commit e68d92a91aac8905aae22bb4a5d66f551448a8e6
parent 0d2014ac189f66307d9627b0f24b166b9066decd
Author: David Shin <dshin@mozilla.com>
Date: Thu, 18 Dec 2025 22:12:10 +0000
Bug 2004596: Move grid absolute reflow after grid area is added to overflow. r=layout-reviewers,layout-anchor-positioning-reviewers,emilio
Adjusted ordering:
1. In-flow reflow
2. Overflow adjustment using grid-area + grid item margin rects from step 1
3. Abspos reflow, using overflow area from step 2 as scrollable containing
block if the abspos element in question has a default anchor.
Differential Revision: https://phabricator.services.mozilla.com/D277051
Diffstat:
2 files changed, 74 insertions(+), 60 deletions(-)
diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp
@@ -9299,46 +9299,55 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aGridRI,
aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
aStatus.MergeCompletionStatusFrom(ocStatus);
+ return bSize;
+}
+
+void nsGridContainerFrame::ReflowAbsoluteChildren(GridReflowInput& aGridRI,
+ const LogicalRect& aContentArea,
+ nscoord aContentBSize,
+ ReflowOutput& aDesiredSize,
+ nsReflowStatus& aStatus) {
+ WritingMode wm = aGridRI.mReflowInput->GetWritingMode();
auto* absoluteContainer = GetAbsoluteContainingBlock();
// We have prepared the absolute frames when initializing GridReflowInput.
- if (absoluteContainer && absoluteContainer->HasAbsoluteFrames()) {
- // 'gridOrigin' is the origin of the grid (the start of the first track),
- // with respect to the grid container's padding-box (CB).
- LogicalMargin pad(aGridRI.mReflowInput->ComputedLogicalPadding(wm));
- const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm));
- const LogicalRect gridCB(wm, 0, 0,
- aContentArea.ISize(wm) + pad.IStartEnd(wm),
- bSize + pad.BStartEnd(wm));
- const nsSize gridCBPhysicalSize = gridCB.Size(wm).GetPhysicalSize(wm);
- size_t i = 0;
- for (nsIFrame* child : absoluteContainer->GetChildList()) {
- MOZ_ASSERT(i < aGridRI.mAbsPosItems.Length());
- MOZ_ASSERT(aGridRI.mAbsPosItems[i].mFrame == child);
- GridArea& area = aGridRI.mAbsPosItems[i].mArea;
- LogicalRect itemCB =
- aGridRI.ContainingBlockForAbsPos(area, gridOrigin, gridCB);
- // AbsoluteContainingBlock::Reflow uses physical coordinates.
- nsRect* cb = child->GetProperty(GridItemContainingBlockRect());
- if (!cb) {
- cb = new nsRect;
- child->SetProperty(GridItemContainingBlockRect(), cb);
- }
- *cb = itemCB.GetPhysicalRect(wm, gridCBPhysicalSize);
- ++i;
- }
- const auto border = aGridRI.mReflowInput->ComputedPhysicalBorder();
- const nsPoint borderShift{border.left, border.top};
- const nsRect paddingRect(borderShift, gridCBPhysicalSize);
- // XXX: To optimize the performance, set the flags only when the CB width
- // or height actually changes.
- AbsPosReflowFlags flags{
- AbsPosReflowFlag::AllowFragmentation, AbsPosReflowFlag::CBWidthChanged,
- AbsPosReflowFlag::CBHeightChanged, AbsPosReflowFlag::IsGridContainerCB};
- absoluteContainer->Reflow(this, PresContext(), *aGridRI.mReflowInput,
- aStatus, paddingRect, flags,
- &aDesiredSize.mOverflowAreas);
+ if (!absoluteContainer || !absoluteContainer->HasAbsoluteFrames()) {
+ return;
}
- return bSize;
+ // 'gridOrigin' is the origin of the grid (the start of the first track),
+ // with respect to the grid container's padding-box (CB).
+ LogicalMargin pad(aGridRI.mReflowInput->ComputedLogicalPadding(wm));
+ const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm));
+ const LogicalRect gridCB(wm, 0, 0,
+ aContentArea.ISize(wm) + pad.IStartEnd(wm),
+ aContentBSize + pad.BStartEnd(wm));
+ const nsSize gridCBPhysicalSize = gridCB.Size(wm).GetPhysicalSize(wm);
+ size_t i = 0;
+ for (nsIFrame* child : absoluteContainer->GetChildList()) {
+ MOZ_ASSERT(i < aGridRI.mAbsPosItems.Length());
+ MOZ_ASSERT(aGridRI.mAbsPosItems[i].mFrame == child);
+ GridArea& area = aGridRI.mAbsPosItems[i].mArea;
+ LogicalRect itemCB =
+ aGridRI.ContainingBlockForAbsPos(area, gridOrigin, gridCB);
+ // AbsoluteContainingBlock::Reflow uses physical coordinates.
+ nsRect* cb = child->GetProperty(GridItemContainingBlockRect());
+ if (!cb) {
+ cb = new nsRect;
+ child->SetProperty(GridItemContainingBlockRect(), cb);
+ }
+ *cb = itemCB.GetPhysicalRect(wm, gridCBPhysicalSize);
+ ++i;
+ }
+ const auto border = aGridRI.mReflowInput->ComputedPhysicalBorder();
+ const nsPoint borderShift{border.left, border.top};
+ const nsRect paddingRect(borderShift, gridCBPhysicalSize);
+ // XXX: To optimize the performance, set the flags only when the CB width
+ // or height actually changes.
+ AbsPosReflowFlags flags{
+ AbsPosReflowFlag::AllowFragmentation, AbsPosReflowFlag::CBWidthChanged,
+ AbsPosReflowFlag::CBHeightChanged, AbsPosReflowFlag::IsGridContainerCB};
+ absoluteContainer->Reflow(this, PresContext(), *aGridRI.mReflowInput,
+ aStatus, paddingRect, flags,
+ &aDesiredSize.mOverflowAreas);
}
nscoord nsGridContainerFrame::ComputeBSizeForResolvingRowSizes(
@@ -9603,29 +9612,6 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
contentBSize =
ReflowChildren(gridRI, contentArea, containerSize, aDesiredSize, aStatus);
- contentBSize = std::max(contentBSize - consumedBSize, 0);
-
- // Skip our block-end border if we're INCOMPLETE.
- if (!aStatus.IsComplete() && !gridRI.mSkipSides.BEnd() &&
- StyleBorder()->mBoxDecorationBreak != StyleBoxDecorationBreak::Clone) {
- bp.BEnd(wm) = nscoord(0);
- }
-
- LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
- contentBSize + bp.BStartEnd(wm));
- aDesiredSize.SetSize(wm, desiredSize);
- nsRect frameRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height());
- aDesiredSize.mOverflowAreas.UnionAllWith(frameRect);
-
- if (repositionChildren) {
- nsPoint physicalDelta(aDesiredSize.Width() - bp.LeftRight(wm), 0);
- for (const auto& item : gridRI.mGridItems) {
- auto* child = item.mFrame;
- child->MovePositionBy(physicalDelta);
- ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
- }
- }
-
if (Style()->GetPseudoType() == PseudoStyleType::scrolledContent) {
// Per spec, the grid area is included in a grid container's scrollable
// overflow region [1], as well as the padding on the end-edge sides that
@@ -9672,6 +9658,29 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
}
aDesiredSize.mOverflowAreas.UnionAllWith(gridItemMarginBoxBounds);
}
+ ReflowAbsoluteChildren(gridRI, contentArea, contentBSize, aDesiredSize, aStatus);
+ contentBSize = std::max(contentBSize - consumedBSize, 0);
+
+ // Skip our block-end border if we're INCOMPLETE.
+ if (!aStatus.IsComplete() && !gridRI.mSkipSides.BEnd() &&
+ StyleBorder()->mBoxDecorationBreak != StyleBoxDecorationBreak::Clone) {
+ bp.BEnd(wm) = nscoord(0);
+ }
+
+ LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
+ contentBSize + bp.BStartEnd(wm));
+ aDesiredSize.SetSize(wm, desiredSize);
+ nsRect frameRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height());
+ aDesiredSize.mOverflowAreas.UnionAllWith(frameRect);
+
+ if (repositionChildren) {
+ nsPoint physicalDelta(aDesiredSize.Width() - bp.LeftRight(wm), 0);
+ for (const auto& item : gridRI.mGridItems) {
+ auto* child = item.mFrame;
+ child->MovePositionBy(physicalDelta);
+ ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
+ }
+ }
// TODO: fix align-tracks alignment in fragments
if ((IsRowMasonry() && !prevInFlow) || IsColMasonry()) {
diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h
@@ -398,6 +398,11 @@ class nsGridContainerFrame final : public nsContainerFrame,
const LogicalRect& aContentArea,
const nsSize& aContainerSize,
ReflowOutput& aDesiredSize, nsReflowStatus& aStatus);
+ void ReflowAbsoluteChildren(GridReflowInput& aGridRI,
+ const LogicalRect& aContentArea,
+ nscoord aContentBSize,
+ ReflowOutput& aDesiredSize,
+ nsReflowStatus& aStatus);
/**
* Helper to implement IntrinsicISize().