Bug 1815552 - Make positioned table parts deal correctly with switching position without being reframed. r=TYLin,layout-reviewers

While looking at the backout, I noticed table parts relied on reframing
on abspos-container-ness changes in a subtle way, see the test, which
fails with the first patch of this bug applied without these changes.

Make the NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN mean the same for table parts
as for everything else. Instead, keep the registration status on each
relevant frame class individually.

Depends on D169127

Differential Revision: https://phabricator.services.mozilla.com/D170969
This commit is contained in:
Emilio Cobos Álvarez
2023-03-01 19:04:17 +00:00
parent dfca94799c
commit 8f36a9e74c
18 changed files with 198 additions and 167 deletions

View File

@@ -2080,11 +2080,10 @@ nsIFrame* nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
// Process children
nsFrameConstructorSaveState absoluteSaveState;
const nsStyleDisplay* display = outerComputedStyle->StyleDisplay();
// Mark the table frame as an absolute container if needed
newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (display->IsAbsPosContainingBlock(newFrame)) {
if (newFrame->IsAbsPosContainingBlock()) {
aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
}
@@ -2117,21 +2116,14 @@ nsIFrame* nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
return newFrame;
}
static void MakeTablePartAbsoluteContainingBlockIfNeeded(
nsFrameConstructorState& aState, const nsStyleDisplay* aDisplay,
nsFrameConstructorSaveState& aAbsSaveState, nsContainerFrame* aFrame) {
static void MakeTablePartAbsoluteContainingBlock(
nsFrameConstructorState& aState, nsFrameConstructorSaveState& aAbsSaveState,
nsContainerFrame* aFrame) {
// If we're positioned, then we need to become an absolute containing block
// for any absolutely positioned children and register for post-reflow fixup.
//
// Note that usually if a frame type can be an absolute containing block, we
// always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or
// not. However, in this case flag serves the additional purpose of indicating
// that the frame was registered with its table frame. This allows us to avoid
// the overhead of unregistering the frame in most cases.
if (aDisplay->IsAbsPosContainingBlock(aFrame)) {
aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
// for any absolutely positioned children.
aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (aFrame->IsAbsPosContainingBlock()) {
aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
nsTableFrame::RegisterPositionedTablePart(aFrame);
}
}
@@ -2162,8 +2154,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructTableRowOrRowGroup(
InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
nsFrameConstructorSaveState absoluteSaveState;
MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
absoluteSaveState, newFrame);
MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, newFrame);
nsFrameConstructorSaveState floatSaveState;
aState.MaybePushFloatContainingBlock(newFrame, floatSaveState);
@@ -2262,8 +2253,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructTableCell(
InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame);
nsFrameConstructorSaveState absoluteSaveState;
MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay,
absoluteSaveState, newFrame);
MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, newFrame);
nsFrameConstructorSaveState floatSaveState;
aState.MaybePushFloatContainingBlock(cellInnerFrame, floatSaveState);
@@ -2519,7 +2509,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
processChildren = true;
contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (display->IsAbsPosContainingBlock(contentFrame)) {
if (contentFrame->IsAbsPosContainingBlock()) {
state.PushAbsoluteContainingBlock(contentFrame, contentFrame,
absoluteSaveState);
}
@@ -2556,8 +2546,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
state, aDocElement,
state.GetGeometricParent(*display, mDocElementContainingBlock),
mDocElementContainingBlock, computedStyle, &contentFrame, frameList,
display->IsAbsPosContainingBlock(contentFrame) ? contentFrame
: nullptr);
contentFrame->IsAbsPosContainingBlock() ? contentFrame : nullptr);
}
MOZ_ASSERT(frameList.FirstChild());
@@ -3306,7 +3295,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructBlockRubyFrame(
nsFrameConstructorSaveState absoluteSaveState;
blockFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (aStyleDisplay->IsAbsPosContainingBlock(newFrame)) {
if (newFrame->IsAbsPosContainingBlock()) {
aState.PushAbsoluteContainingBlock(blockFrame, blockFrame,
absoluteSaveState);
}
@@ -3839,8 +3828,7 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
// Now figure out whether newFrame or outerFrame should be the
// absolute container.
auto outerDisplay = outerStyle->StyleDisplay();
if (outerDisplay->IsAbsPosContainingBlock(outerFrame)) {
if (outerFrame->IsAbsPosContainingBlock()) {
maybeAbsoluteContainingBlock = outerFrame;
maybeAbsoluteContainingBlockStyleFrame = outerFrame;
innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
@@ -4582,10 +4570,9 @@ nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock(
aState.AddChild(newFrame, aFrameList, content, aParentFrame);
nsFrameList blockList;
ConstructBlock(
aState, content, newFrame, newFrame, scrolledContentStyle, &scrolledFrame,
blockList,
aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr);
ConstructBlock(aState, content, newFrame, newFrame, scrolledContentStyle,
&scrolledFrame, blockList,
newFrame->IsAbsPosContainingBlock() ? newFrame : nullptr);
MOZ_ASSERT(blockList.OnlyChild() == scrolledFrame,
"Scrollframe's frameList should be exactly the scrolled frame!");
@@ -4619,11 +4606,10 @@ nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
nsContainerFrame* newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
newFrame->AddStateBits(flags);
ConstructBlock(
aState, aItem.mContent,
aState.GetGeometricParent(*aDisplay, aParentFrame), aParentFrame,
computedStyle, &newFrame, aFrameList,
aDisplay->IsAbsPosContainingBlock(newFrame) ? newFrame : nullptr);
ConstructBlock(aState, aItem.mContent,
aState.GetGeometricParent(*aDisplay, aParentFrame),
aParentFrame, computedStyle, &newFrame, aFrameList,
newFrame->IsAbsPosContainingBlock() ? newFrame : nullptr);
return newFrame;
}
@@ -7894,9 +7880,8 @@ nsIFrame* nsCSSFrameConstructor::CreateContinuingTableFrame(
headerFooterFrame->Init(headerFooter, newFrame, nullptr);
nsFrameConstructorSaveState absoluteSaveState;
MakeTablePartAbsoluteContainingBlockIfNeeded(
state, headerFooterComputedStyle->StyleDisplay(), absoluteSaveState,
headerFooterFrame);
MakeTablePartAbsoluteContainingBlock(state, absoluteSaveState,
headerFooterFrame);
nsFrameConstructorSaveState floatSaveState;
state.MaybePushFloatContainingBlock(headerFooterFrame, floatSaveState);
@@ -7969,16 +7954,10 @@ nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
} else if (LayoutFrameType::TableRowGroup == frameType) {
newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
newFrame->Init(content, aParentFrame, aFrame);
if (newFrame->HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
nsTableFrame::RegisterPositionedTablePart(newFrame);
}
} else if (LayoutFrameType::TableRow == frameType) {
nsTableRowFrame* rowFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
rowFrame->Init(content, aParentFrame, aFrame);
if (rowFrame->HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
nsTableFrame::RegisterPositionedTablePart(rowFrame);
}
// Create a continuing frame for each table cell frame
nsFrameList newChildList;
@@ -8007,9 +7986,6 @@ nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
cellFrame->Init(content, aParentFrame, aFrame);
if (cellFrame->HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
nsTableFrame::RegisterPositionedTablePart(cellFrame);
}
// Create a continuing area frame
nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();