Source/WebCore/ChangeLog

 12021-08-17 Martin Robinson <mrobinson@webkit.org>
 2
 3 position: sticky with display: inline-block
 4 https://bugs.webkit.org/show_bug.cgi?id=224415
 5 <rdar://problem/76811968>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Improve sticky positioning applied to inline items. The first improvement is to
 10 skip anonymous RenderBlock parents of inline display items when looking for the
 11 containing block used to calculate sticky constraints. These anonymous parents
 12 are not the containing block that constrains the movement of these kind of stickily
 13 positioned items. Instead look for containing block for the anonymous parent,
 14 which does limit the scroll boundaries of inline stickily position items.
 15
 16 Previously, when converting the frame rect from the coordinate space of the stickily
 17 positioned item to that of the scrolling container, the code used to apply the offset
 18 from the containing block to the scrolling ancestor directly to the frame rect. That
 19 doesn't work when the containing block that determines sticky constraints is not the
 20 direct containing block of the stickily positioned items (as it is for inlines).
 21
 22 Instead, the code now just maps the frame rect directly from the item parent to
 23 the scrolling ancestor. This simplifies things a bit and allows it to work with
 24 inline stickily positioned items.
 25
 26 Finally, this change adds comments to make it clearer what this method is doing.
 27
 28 No new tests. This is covered by existing WPT tests. Specifically the following
 29 tests are now passing:
 30 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-hyperlink.html
 31 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-nested-table.html
 32 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-table-parts.html
 33 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-table-th-bottom.html
 34 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-nested-thead-th.html
 35
 36 * css/CSSComputedStyleDeclaration.cpp:
 37 (WebCore::positionOffsetValue): enclosingClippingBoxForStickyPosition now returns a pair
 38 to avoid passing in a pointer. Only look at the first part of the pair here.
 39 * rendering/RenderBoxModelObject.cpp:
 40 (WebCore::RenderBoxModelObject::computeStickyPositionConstraints const): Modified this method
 41 to return a pair in order to avoid dealing with input parameters. This allows simplifying this
 42 method, making the code a bit simpler.
 43 (WebCore::RenderBoxModelObject::enclosingClippingBoxForStickyPosition const): Deleted.
 44 (WebCore::RenderBoxModelObject::computeStickyPositionConstraints const): Make two changes
 45 to this method to improve sticky positioning for inline elements. The first change is
 46 to be a bit better about finding the appropriate containing block for calculating sticky
 47 constraints. The second is to more resiliently move from coordinate systems. In addition,
 48 improve the comments for this method to make it clearer what is happening at each step.
 49 * rendering/RenderBoxModelObject.h: Updated method declaration.
 50
1512021-08-17 Jer Noble <jer.noble@apple.com>
252
353 LayoutTests imported/w3c/web-platform-tests/html/canvas/element/imagebitmap/createImageBitmap-* are flakey

Source/WebCore/css/CSSComputedStyleDeclaration.cpp

@@static RefPtr<CSSValue> positionOffsetValue(const RenderStyle& style, CSSPropert
399399 }
400400 LayoutUnit containingBlockSize;
401401 if (box.isStickilyPositioned()) {
402  auto& enclosingClippingBox = box.enclosingClippingBoxForStickyPosition();
 402 auto& enclosingClippingBox = box.enclosingClippingBoxForStickyPosition().first;
403403 if (isVerticalProperty == enclosingClippingBox.isHorizontalWritingMode())
404404 containingBlockSize = enclosingClippingBox.contentLogicalHeight();
405405 else

Source/WebCore/rendering/RenderBoxModelObject.cpp

@@LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L
440440 return referencePoint;
441441}
442442
443 const RenderBox& RenderBoxModelObject::enclosingClippingBoxForStickyPosition(const RenderLayer** enclosingClippingLayer) const
 443std::pair<const RenderBox&, const RenderLayer*> RenderBoxModelObject::enclosingClippingBoxForStickyPosition() const
444444{
445445 ASSERT(isStickilyPositioned());
446 
447446 RenderLayer* clipLayer = hasLayer() ? layer()->enclosingOverflowClipLayer(ExcludeSelf) : nullptr;
448 
449  if (enclosingClippingLayer)
450  *enclosingClippingLayer = clipLayer;
451 
452  return clipLayer ? downcast<RenderBox>(clipLayer->renderer()) : view();
 447 const RenderBox& box = clipLayer ? downcast<RenderBox>(clipLayer->renderer()) : view();
 448 return { box, clipLayer };
453449}
454450
455451void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& constrainingRect) const
456452{
457453 constraints.setConstrainingRectAtLastLayout(constrainingRect);
458454
 455 // Find the containing block to use for determining the constraining rect. If this is an inline
 456 // with an anonymous block as the parent, don't to use that parent as the containing block. We
 457 // want the size of the actual non-anonymous containing block because anonymous block parents
 458 // are the same size as their content.
459459 RenderBlock* containingBlock = this->containingBlock();
460  const RenderLayer* enclosingClippingLayer = nullptr;
461  auto& enclosingClippingBox = enclosingClippingBoxForStickyPosition(&enclosingClippingLayer);
 460 if (this->isInline() && containingBlock->isAnonymousBlock())
 461 containingBlock = containingBlock->containingBlock();
 462 auto [enclosingClippingBox, enclosingClippingLayer] = enclosingClippingBoxForStickyPosition();
462463
463464 LayoutRect containerContentRect;
464  if (!enclosingClippingLayer || (containingBlock != &enclosingClippingBox))
 465 if (!enclosingClippingLayer || (containingBlock != &enclosingClippingBox)) {
 466 // In this case either the scrolling element is the view or there is another containing block in
 467 // the hierarchy between this stickily positioned item and its scrolling ancestor. In both cases,
 468 // we use the content box rectangle of the containing block, which is what should constrain the
 469 // movement.
465470 containerContentRect = containingBlock->contentBoxRect();
466  else {
 471 } else {
467472 containerContentRect = containingBlock->layoutOverflowRect();
468473 LayoutPoint containerLocation = containerContentRect.location() + LayoutPoint(containingBlock->borderLeft() + containingBlock->paddingLeft(),
469474 containingBlock->borderTop() + containingBlock->paddingTop());

@@void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewpo
498503
499504 // Now compute the sticky box rect, also relative to the scrolling ancestor.
500505 LayoutRect stickyBoxRect = frameRectForStickyPositioning();
501  LayoutRect flippedStickyBoxRect = stickyBoxRect;
502  containingBlock->flipForWritingMode(flippedStickyBoxRect);
503  FloatRect stickyBoxRelativeToScrollingAnecstor = flippedStickyBoxRect;
504506
505  // FIXME: sucks to call localToContainerQuad again, but we can't just offset from the previously computed rect if there are transforms.
506  // Map to the view to avoid including page scale factor.
507  FloatPoint stickyLocationRelativeToScrollingAncestor = flippedStickyBoxRect.location() + containingBlock->localToContainerQuad(FloatRect(FloatPoint(), containingBlock->size()), &enclosingClippingBox).boundingBox().location();
 507 // Ideally, it would be possible to call this->localToContainerQuad to determine the frame
 508 // rectangle in the coordinate system of the scrolling ancestor, but localToContainerQuad
 509 // itself depends on sticky positioning! Instead, start from the parent but first adjusting
 510 // the rectangle for the writing mode of this stickily-positioned element.
 511 //
 512 // FIXME: For now, assume that |this| is not transformed. It would also be nice to not have to
 513 // call localToContainerQuad again since we have already done a similar call to move from
 514 // the containing block to the scrolling ancestor above, but localToContainerQuad takes care
 515 // of a lot of complex situations involving inlines, tables, and transformations.
 516 if (parent()->isBox())
 517 downcast<RenderBox>(parent())->flipForWritingMode(stickyBoxRect);
 518 auto stickyBoxRelativeToScrollingAncestor = parent()->localToContainerQuad(FloatRect(stickyBoxRect), &enclosingClippingBox).boundingBox();
 519
508520 if (enclosingClippingLayer) {
509  stickyLocationRelativeToScrollingAncestor -= FloatSize(enclosingClippingBox.borderLeft() + enclosingClippingBox.paddingLeft(),
510  enclosingClippingBox.borderTop() + enclosingClippingBox.paddingTop());
511  if (&enclosingClippingBox != containingBlock) {
 521 stickyBoxRelativeToScrollingAncestor.move(-FloatSize(enclosingClippingBox.borderLeft() + enclosingClippingBox.paddingLeft(),
 522 enclosingClippingBox.borderTop() + enclosingClippingBox.paddingTop()));
 523
 524 if (&enclosingClippingBox != parent()) {
512525 if (auto* scrollableArea = enclosingClippingLayer->scrollableArea())
513  stickyLocationRelativeToScrollingAncestor += scrollableArea->scrollOffset();
 526 stickyBoxRelativeToScrollingAncestor.moveBy(scrollableArea->scrollOffset());
514527 }
515528 }
516  // FIXME: For now, assume that |this| is not transformed.
517  stickyBoxRelativeToScrollingAnecstor.setLocation(stickyLocationRelativeToScrollingAncestor);
518  constraints.setStickyBoxRect(stickyBoxRelativeToScrollingAnecstor);
 529 constraints.setStickyBoxRect(stickyBoxRelativeToScrollingAncestor);
519530
520531 if (!style().left().isAuto()) {
521532 constraints.setLeftOffset(valueForLength(style().left(), constrainingRect.width()));

Source/WebCore/rendering/RenderBoxModelObject.h

@@public:
116116 LayoutSize relativePositionLogicalOffset() const { return style().isHorizontalWritingMode() ? relativePositionOffset() : relativePositionOffset().transposedSize(); }
117117
118118 FloatRect constrainingRectForStickyPosition() const;
119  const RenderBox& enclosingClippingBoxForStickyPosition(const RenderLayer** enclosingClippingLayer = nullptr) const;
 119 std::pair<const RenderBox&, const RenderLayer*> enclosingClippingBoxForStickyPosition() const;
120120 void computeStickyPositionConstraints(StickyPositionViewportConstraints&, const FloatRect& constrainingRect) const;
121121 LayoutSize stickyPositionOffset() const;
122122 LayoutSize stickyPositionLogicalOffset() const { return style().isHorizontalWritingMode() ? stickyPositionOffset() : stickyPositionOffset().transposedSize(); }

LayoutTests/ChangeLog

 12021-08-17 Martin Robinson <mrobinson@webkit.org>
 2
 3 position: sticky with display: inline-block
 4 https://bugs.webkit.org/show_bug.cgi?id=224415
 5 <rdar://problem/76811968>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 * TestExpectations: Unskip newly passing tests and skip one test which was
 10 a false pass previously.
 11
1122021-08-16 Diego Pino Garcia <dpino@igalia.com>
213
314 [GLIB] Unreviewed test gardening. Update baselines after r277970.

LayoutTests/TestExpectations

@@webkit.org/b/228993 imported/w3c/web-platform-tests/css/css-position/multicol/st
34823482webkit.org/b/228993 imported/w3c/web-platform-tests/css/css-position/multicol/static-position/vrl-ltr-rtl-in-multicol.tentative.html [ ImageOnlyFailure ]
34833483webkit.org/b/228993 imported/w3c/web-platform-tests/css/css-position/multicol/static-position/vrl-rtl-ltr-in-multicol.tentative.html [ ImageOnlyFailure ]
34843484webkit.org/b/228993 imported/w3c/web-platform-tests/css/css-position/multicol/static-position/vrl-rtl-rtl-in-multicol.html [ ImageOnlyFailure ]
3485 webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-hyperlink.html [ ImageOnlyFailure ]
34863485webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-inline.html [ ImageOnlyFailure ]
34873486webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-nested-inline.html [ ImageOnlyFailure ]
3488 webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-nested-table.html [ ImageOnlyFailure ]
34893487webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-rendering.html [ ImageOnlyFailure ]
3490 webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-table-parts.html [ ImageOnlyFailure ]
3491 webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-table-th-bottom.html [ ImageOnlyFailure ]
34923488webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-writing-modes.html [ ImageOnlyFailure ]
34933489webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-large-top-2.tentative.html [ ImageOnlyFailure ]
34943490webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-large-top.tentative.html [ ImageOnlyFailure ]
3495 webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/position-sticky-nested-thead-th.html [ ImageOnlyFailure ]
 3491webkit.org/b/203450 imported/w3c/web-platform-tests/css/css-position/sticky/sticky-after-input.html [ Failure ]
34963492webkit.org/b/203451 imported/w3c/web-platform-tests/css/css-position/static-position/htb-ltr-ltr.html [ ImageOnlyFailure ]
34973493webkit.org/b/203451 imported/w3c/web-platform-tests/css/css-position/static-position/htb-ltr-rtl.tentative.html [ ImageOnlyFailure ]
34983494webkit.org/b/203451 imported/w3c/web-platform-tests/css/css-position/static-position/htb-rtl-ltr.tentative.html [ ImageOnlyFailure ]