Skip to content

Commit cad87d8

Browse files
committed
Cannot rely on auto-positioned absolutely positioned descendants being marked for layout
https://bugs.webkit.org/show_bug.cgi?id=276350 <rdar://problem/131806062> Reviewed by Antti Koivisto. This is a relatively inexpensive way to determine whether a statically positioned (in the inline direction) out-of-flow box needs its position adjusted due to parent border box move (e.g. margin changes). (ideally, the parent would signal to this out-of-flow box that a positional adjustment is required, which would then be picked up here during the out-of-flow box's layout) Test: fast/block/positioning/abspos-auto-left-fixed-top-change-parent-margin-left.html * LayoutTests/fast/block/positioning/abspos-auto-left-fixed-top-change-parent-margin-left-expected.html: Added. * LayoutTests/fast/block/positioning/abspos-auto-left-fixed-top-change-parent-margin-left.html: Added. * Source/WebCore/rendering/PositionedLayoutConstraints.h: * Source/WebCore/rendering/RenderBlock.cpp: (WebCore::RenderBlock::layoutOutOfFlowBox): Canonical link: https://commits.webkit.org/305229@main
1 parent 394eb73 commit cad87d8

File tree

4 files changed

+32
-3
lines changed

4 files changed

+32
-3
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<!DOCTYPE html>
2+
<p>There should be no red on this page.</p>
3+
<div style="margin-left:200px; width:200px; height:200px; background:green;"></div>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<p>There should be no red on this page.</p>
3+
<div style="position:relative;">
4+
<div id="elm" style="width:200px; height:200px; background:red;">
5+
<div style="position:absolute; top:0; width:200px; height:200px; background:green;"></div>
6+
</div>
7+
</div>
8+
<script>
9+
document.body.offsetTop;
10+
document.getElementById("elm").style.marginLeft = "200px";
11+
</script>

Source/WebCore/rendering/PositionedLayoutConstraints.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class PositionedLayoutConstraints {
9191
void fixupLogicalLeftPosition(RenderBox::LogicalExtentComputedValues&) const;
9292
void adjustLogicalTopWithLogicalHeightIfNeeded(RenderBox::LogicalExtentComputedValues&) const;
9393

94+
LayoutUnit computedInlineStaticDistance() const;
95+
9496
private:
9597
bool containingCoordsAreFlipped() const;
9698

@@ -104,7 +106,6 @@ class PositionedLayoutConstraints {
104106
bool needsGridAreaAdjustmentBeforeStaticPositioning() const;
105107
std::optional<LayoutUnit> remainingSpaceForStaticAlignment(LayoutUnit itemSize) const;
106108
void computeStaticPosition();
107-
LayoutUnit computedInlineStaticDistance() const;
108109
LayoutUnit computedBlockStaticDistance() const;
109110

110111
CheckedRef<const RenderBox> m_renderer;

Source/WebCore/rendering/RenderBlock.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,11 +815,25 @@ void RenderBlock::layoutOutOfFlowBox(RenderBox& outOfFlowBox, RelayoutChildren r
815815
return;
816816
}
817817

818+
auto& outOfFlowBoxStyle = outOfFlowBox.style();
818819
// When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
819820
// non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
820821
// objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
821822
// positioned explicitly) this should not incur a performance penalty.
822-
if (relayoutChildren == RelayoutChildren::Yes || (outOfFlowBox.style().hasStaticBlockPosition(isHorizontalWritingMode()) && outOfFlowBox.parent() != this))
823+
auto needsLayout = [&] {
824+
if (relayoutChildren == RelayoutChildren::Yes)
825+
return true;
826+
if (outOfFlowBox.parent() == this)
827+
return false;
828+
if (outOfFlowBoxStyle.hasStaticBlockPosition(isHorizontalWritingMode()))
829+
return true;
830+
if (outOfFlowBoxStyle.hasStaticInlinePosition(isHorizontalWritingMode())) {
831+
// FIXME: We could just set the logical left on this out-of-flow box since the box itself does not really need layout (we are just moving an out-of-flow renderer here).
832+
return outOfFlowBox.logicalLeft() != PositionedLayoutConstraints { outOfFlowBox, LogicalBoxAxis::Inline }.computedInlineStaticDistance();
833+
}
834+
return false;
835+
};
836+
if (needsLayout())
823837
outOfFlowBox.setChildNeedsLayout(MarkOnlyThis);
824838

825839
// If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
@@ -831,7 +845,7 @@ void RenderBlock::layoutOutOfFlowBox(RenderBox& outOfFlowBox, RelayoutChildren r
831845
// We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width
832846
// and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
833847
if (outOfFlowBox.needsOutOfFlowMovementLayoutOnly() && outOfFlowBox.tryLayoutDoingOutOfFlowMovementOnly()) {
834-
if (Style::AnchorPositionEvaluator::isAnchorPositioned(outOfFlowBox.style()))
848+
if (Style::AnchorPositionEvaluator::isAnchorPositioned(outOfFlowBoxStyle))
835849
Style::AnchorPositionEvaluator::captureScrollSnapshots(outOfFlowBox);
836850
outOfFlowBox.clearNeedsLayout();
837851
}

0 commit comments

Comments
 (0)