Bug 1800563: Inhibit out-of-flow grid containers from being subgrids. r=TYLin

This patch does two things:

1. Extends ShouldInhibitSubgridDueToIFC to return true for out-of-flow frames,
   per spec (which makes us pass the WPT independent-formatting-context.html).
   Spec reference: https://drafts.csswg.org/css-grid-2/#subgrid-listing
   "...if the grid container [the one that's styled to be a subgrid] is
   otherwise forced to establish an independent formatting context (for
   example, due to layout containment or absolute positioning), the used value
   is the initial value, 'none', and the grid container is not a subgrid."

2. Removes some newly-dead code from ComputeSelfSubgridMasonryBits that
   provided some special handling for out-of-flow subgrids (which are now
   impossible to create, as of this change); and also remove
   WillHaveAtLeastOneTrackInAxis() whose last caller I'm removing here.

3. Renames a variable 'gridParent' to 'parentGrid' to match the spec
   terminology at https://drafts.csswg.org/css-grid-2/#parent-grid

Differential Revision: https://phabricator.services.mozilla.com/D193731
This commit is contained in:
Daniel Holbert 2023-12-20 02:03:04 +00:00
parent 5f7834499a
commit b99412ee25
3 changed files with 18 additions and 64 deletions

View file

@ -9315,28 +9315,29 @@ nsFrameState nsGridContainerFrame::ComputeSelfSubgridMasonryBits() const {
return bits; return bits;
} }
// Skip our scroll frame and such if we have it. // Skip over our scroll frame and such if we have it, to find our "parent
// This will store the outermost frame that shares our content node: // grid", if we have one.
const nsIFrame* outerFrame = this;
// ...and this will store that frame's parent: // After this loop, 'parent' will represent the parent of the outermost frame
// that shares our content node. (Normally this is just our parent frame, but
// if we're e.g. a scrolled frame, then this will be the parent of our
// wrapper-scrollable-frame.) If 'parent' turns out to be a grid container,
// then it's our "parent grid", and we could potentially be a subgrid of it.
auto* parent = GetParent(); auto* parent = GetParent();
while (parent && parent->GetContent() == GetContent()) { while (parent && parent->GetContent() == GetContent()) {
// If we find our containing frame has 'contain:layout/paint' we can't be // If we find our containing frame (e.g. our scroll frame) can't be a
// subgrid, for the same reasons as above. This can happen when this frame // subgrid, then we can't be a subgrid, for the same reasons as above. This
// is itself a grid item. // can happen when this frame is itself a grid item with "overflow:scroll"
// or similar.
if (ShouldInhibitSubgridDueToIFC(parent)) { if (ShouldInhibitSubgridDueToIFC(parent)) {
return bits; return bits;
} }
outerFrame = parent;
parent = parent->GetParent(); parent = parent->GetParent();
} }
const nsGridContainerFrame* gridParent = do_QueryFrame(parent); const nsGridContainerFrame* parentGrid = do_QueryFrame(parent);
if (gridParent) { if (parentGrid) {
bool isOrthogonal = bool isOrthogonal =
GetWritingMode().IsOrthogonalTo(parent->GetWritingMode()); GetWritingMode().IsOrthogonalTo(parent->GetWritingMode());
// NOTE: our NS_FRAME_OUT_OF_FLOW isn't set yet so we check our style.
bool isOutOfFlow =
outerFrame->StyleDisplay()->IsAbsolutelyPositionedStyle();
bool isColSubgrid = pos->mGridTemplateColumns.IsSubgrid(); bool isColSubgrid = pos->mGridTemplateColumns.IsSubgrid();
// Subgridding a parent masonry axis makes us use masonry layout too, // Subgridding a parent masonry axis makes us use masonry layout too,
// unless our other axis is a masonry axis. // unless our other axis is a masonry axis.
@ -9348,15 +9349,6 @@ nsFrameState nsGridContainerFrame::ComputeSelfSubgridMasonryBits() const {
bits |= NS_STATE_GRID_IS_COL_MASONRY; bits |= NS_STATE_GRID_IS_COL_MASONRY;
} }
} }
// OOF subgrids don't create tracks in the parent, so we need to check that
// it has one anyway. Otherwise we refuse to subgrid that axis since we
// can't place grid items inside a subgrid without at least one track.
if (isColSubgrid && isOutOfFlow) {
auto parentAxis = isOrthogonal ? eLogicalAxisBlock : eLogicalAxisInline;
if (!gridParent->WillHaveAtLeastOneTrackInAxis(parentAxis)) {
isColSubgrid = false;
}
}
if (isColSubgrid) { if (isColSubgrid) {
bits |= NS_STATE_GRID_IS_COL_SUBGRID; bits |= NS_STATE_GRID_IS_COL_SUBGRID;
} }
@ -9370,12 +9362,6 @@ nsFrameState nsGridContainerFrame::ComputeSelfSubgridMasonryBits() const {
bits |= NS_STATE_GRID_IS_ROW_MASONRY; bits |= NS_STATE_GRID_IS_ROW_MASONRY;
} }
} }
if (isRowSubgrid && isOutOfFlow) {
auto parentAxis = isOrthogonal ? eLogicalAxisInline : eLogicalAxisBlock;
if (!gridParent->WillHaveAtLeastOneTrackInAxis(parentAxis)) {
isRowSubgrid = false;
}
}
if (isRowSubgrid) { if (isRowSubgrid) {
bits |= NS_STATE_GRID_IS_ROW_SUBGRID; bits |= NS_STATE_GRID_IS_ROW_SUBGRID;
} }
@ -9383,35 +9369,6 @@ nsFrameState nsGridContainerFrame::ComputeSelfSubgridMasonryBits() const {
return bits; return bits;
} }
bool nsGridContainerFrame::WillHaveAtLeastOneTrackInAxis(
LogicalAxis aAxis) const {
if (IsSubgrid(aAxis)) {
// This is enforced by refusing to be a subgrid unless our parent has
// at least one track in aAxis by ComputeSelfSubgridMasonryBits above.
return true;
}
if (IsMasonry(aAxis)) {
return false;
}
const auto* pos = StylePosition();
const auto& gridTemplate = aAxis == eLogicalAxisBlock
? pos->mGridTemplateRows
: pos->mGridTemplateColumns;
if (gridTemplate.IsTrackList()) {
return true;
}
for (nsIFrame* child : PrincipalChildList()) {
if (!child->IsPlaceholderFrame()) {
// A grid item triggers at least one implicit track in each axis.
return true;
}
}
if (!pos->mGridTemplateAreas.IsNone()) {
return true;
}
return false;
}
void nsGridContainerFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, void nsGridContainerFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) { nsIFrame* aPrevInFlow) {
nsContainerFrame::Init(aContent, aParent, aPrevInFlow); nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
@ -9965,10 +9922,12 @@ bool nsGridContainerFrame::ShouldInhibitSubgridDueToIFC(
const nsIFrame* aFrame) { const nsIFrame* aFrame) {
// Just checking for things that make us establish an independent formatting // Just checking for things that make us establish an independent formatting
// context (IFC) and hence prevent us from being a subgrid: // context (IFC) and hence prevent us from being a subgrid:
// * Out-of-flow (e.g. abspos) frames also establish an IFC. Note, our
// NS_FRAME_OUT_OF_FLOW bit potentially isn't set yet, so we check our style.
// * contain:layout and contain:paint each make us establish an IFC. // * contain:layout and contain:paint each make us establish an IFC.
// XXXdholbert We should also check whether we're out-of-flow (bug 1800563).
const auto* display = aFrame->StyleDisplay(); const auto* display = aFrame->StyleDisplay();
return display->IsContainLayout() || display->IsContainPaint(); return display->IsAbsolutelyPositionedStyle() || display->IsContainLayout() ||
display->IsContainPaint();
} }
nsGridContainerFrame* nsGridContainerFrame::GetGridContainerFrame( nsGridContainerFrame* nsGridContainerFrame::GetGridContainerFrame(

View file

@ -453,9 +453,6 @@ class nsGridContainerFrame final : public nsContainerFrame,
*/ */
nsFrameState ComputeSelfSubgridMasonryBits() const; nsFrameState ComputeSelfSubgridMasonryBits() const;
/** Helper for ComputeSelfSubgridMasonryBits(). */
bool WillHaveAtLeastOneTrackInAxis(LogicalAxis aAxis) const;
private: private:
// Helpers for ReflowChildren // Helpers for ReflowChildren
struct Fragmentainer { struct Fragmentainer {

View file

@ -1,2 +0,0 @@
[independent-formatting-context.html]
expected: FAIL