Bug 1863402 - Simplify top layer fixed list set-up and back out bug 1799036. r=dholbert

The top layer fixed list CB and the regular fixed list CB are always the
same (the viewport frame). We're currently using two different
AbsoluteFrameList for these, but that's wrong. Make sure to use the same
AbsoluteFrameList. This makes sure that placeholders for the fixed list
are properly ordered.

Revert bug 1799036 (for now at least), since this also fixes that issue
in a better, less breaking way.

While at it, also insert the top layer abspos list after the
non-top-layer one. This is needed so that a non-top-layer abspos element
and a top layer abspos element are laid out in the right order.

We don't need to share a list for those tho, because all top-layer
abspos items are also abspos containers themselves, so a non-top-layer
descendant of a top layer item can't escape the top layer chain. This
fixes a couple non-fatal asserts.

Differential Revision: https://phabricator.services.mozilla.com/D192908
This commit is contained in:
Emilio Cobos Álvarez
2023-11-09 11:29:59 +00:00
parent a522cc6926
commit c1820e53c4
8 changed files with 113 additions and 117 deletions

View File

@@ -582,19 +582,17 @@ class MOZ_STACK_CLASS nsFrameConstructorSaveState {
// Pointer to struct whose data we save/restore.
AbsoluteFrameList* mList = nullptr;
// The saved pointer to the fixed list.
AbsoluteFrameList* mSavedFixedList = nullptr;
// Copy of original frame list. This can be the original absolute list or a
// float list. If we're saving the abs-pos state for a transformed element,
// i.e. when mSavedFixedPosIsAbsPos is true, this is the original fixed list.
// float list.
AbsoluteFrameList mSavedList;
// The name of the child list in which our frames would belong.
mozilla::FrameChildListID mChildListID = FrameChildListID::Principal;
nsFrameConstructorState* mState = nullptr;
// Only used when saving an absolute list. See the description of
// nsFrameConstructorState::mFixedPosIsAbsPos for its meaning.
bool mSavedFixedPosIsAbsPos = false;
friend class nsFrameConstructorState;
};
@@ -607,35 +605,54 @@ class MOZ_STACK_CLASS nsFrameConstructorState {
nsCSSFrameConstructor* mFrameConstructor;
// Containing block information for out-of-flow frames.
AbsoluteFrameList mFixedList;
AbsoluteFrameList mAbsoluteList;
//
// Floats are easy. Whatever is our float CB.
//
// Regular abspos elements are easy too. Its containing block can be the
// nearest abspos element, or the ICB (the canvas frame).
//
// Top layer abspos elements are always children of the ICB, but we can get
// away with having two different lists (mAbsoluteList and
// mTopLayerAbsoluteList), because because top layer frames cause
// non-top-layer frames to be contained inside (so any descendants of a top
// layer abspos can never share containing block with it, unless they're also
// in the top layer).
//
// Regular fixed elements however are trickier. Fixed elements can be
// contained in one of three lists:
//
// * mAbsoluteList, if our abspos cb is also a fixpos cb (e.g., is
// transformed or has a filter).
//
// * mAncestorFixedList, if the fixpos cb is an ancestor element other than
// the viewport frame, (so, a transformed / filtered
// ancestor).
//
// * mRealFixedList, which is also the fixed list used for the top layer
// fixed items, which is the fixed list of the viewport
// frame.
//
// It is important that mRealFixedList is shared between regular and top layer
// fixpos elements, since no-top-layer descendants of top layer fixed elements
// could share ICB and vice versa, so without that there would be no guarantee
// of layout ordering between them.
AbsoluteFrameList mFloatedList;
// The containing block of a frame in the top layer is defined by the
// spec: fixed-positioned frames are children of the viewport frame,
// and absolutely-positioned frames are children of the initial
// containing block. They would not be caught by any other containing
// block, e.g. frames with transform or filter.
AbsoluteFrameList mTopLayerFixedList;
AbsoluteFrameList mAbsoluteList;
AbsoluteFrameList mTopLayerAbsoluteList;
AbsoluteFrameList mAncestorFixedList;
AbsoluteFrameList mRealFixedList;
// Never null, always pointing to one of the lists documented above.
AbsoluteFrameList* mFixedList;
// What `page: auto` resolves to. This is the used page-name of the parent
// frame. Updated by AutoFrameConstructionPageName.
const nsAtom* mAutoPageNameValue;
const nsAtom* mAutoPageNameValue = nullptr;
nsCOMPtr<nsILayoutHistoryState> mFrameState;
// These bits will be added to the state bits of any frame we construct
// using this state.
nsFrameState mAdditionalStateBits;
// When working with transform / filter properties, we want to hook the
// abs-pos and fixed-pos lists together, since such elements are fixed-pos
// containing blocks.
//
// Similarly when restricting absolute positioning (for e.g. mathml).
//
// This flag determines whether or not we want to wire the fixed-pos and
// abs-pos lists together.
bool mFixedPosIsAbsPos;
nsFrameState mAdditionalStateBits{0};
// If false (which is the default) then call SetPrimaryFrame() as needed
// during frame construction. If true, don't make any SetPrimaryFrame()
@@ -753,12 +770,8 @@ class MOZ_STACK_CLASS nsFrameConstructorState {
* we'll hand back the abs-pos list. Callers should use this function if they
* want to get the list acting as the fixed-pos item parent.
*/
AbsoluteFrameList& GetFixedList() {
return mFixedPosIsAbsPos ? mAbsoluteList : mFixedList;
}
const AbsoluteFrameList& GetFixedList() const {
return mFixedPosIsAbsPos ? mAbsoluteList : mFixedList;
}
AbsoluteFrameList& GetFixedList() { return *mFixedList; }
const AbsoluteFrameList& GetFixedList() const { return *mFixedList; }
protected:
friend class nsFrameConstructorSaveState;
@@ -794,24 +807,26 @@ nsFrameConstructorState::nsFrameConstructorState(
: mPresContext(aPresShell->GetPresContext()),
mPresShell(aPresShell),
mFrameConstructor(aPresShell->FrameConstructor()),
mFixedList(aFixedContainingBlock),
mAbsoluteList(aAbsoluteContainingBlock),
mFloatedList(aFloatContainingBlock),
mTopLayerFixedList(
static_cast<nsContainerFrame*>(mFrameConstructor->GetRootFrame())),
mAbsoluteList(aAbsoluteContainingBlock),
mTopLayerAbsoluteList(mFrameConstructor->GetCanvasFrame()),
// Will be set by AutoFrameConstructionPageName
mAutoPageNameValue(nullptr),
mAncestorFixedList(aFixedContainingBlock),
mRealFixedList(
static_cast<nsContainerFrame*>(mFrameConstructor->GetRootFrame())),
// See PushAbsoluteContaningBlock below
mFrameState(aHistoryState),
mAdditionalStateBits(nsFrameState(0)),
// If the fixed-pos containing block is equal to the abs-pos containing
// block, use the abs-pos containing block's abs-pos list for fixed-pos
// frames.
mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
mCreatingExtraFrames(false),
mHasRenderedLegend(false) {
MOZ_COUNT_CTOR(nsFrameConstructorState);
mFixedList = [&] {
if (aFixedContainingBlock == aAbsoluteContainingBlock) {
return &mAbsoluteList;
}
if (aAbsoluteContainingBlock == mRealFixedList.mContainingBlock) {
return &mRealFixedList;
}
return &mAncestorFixedList;
}();
}
nsFrameConstructorState::nsFrameConstructorState(
@@ -832,11 +847,11 @@ nsFrameConstructorState::~nsFrameConstructorState() {
}
void nsFrameConstructorState::ProcessFrameInsertionsForAllLists() {
ProcessFrameInsertions(mTopLayerFixedList, FrameChildListID::Fixed);
ProcessFrameInsertions(mTopLayerAbsoluteList, FrameChildListID::Absolute);
ProcessFrameInsertions(mFloatedList, FrameChildListID::Float);
ProcessFrameInsertions(mAbsoluteList, FrameChildListID::Absolute);
ProcessFrameInsertions(mFixedList, FrameChildListID::Fixed);
ProcessFrameInsertions(mTopLayerAbsoluteList, FrameChildListID::Absolute);
ProcessFrameInsertions(*mFixedList, FrameChildListID::Fixed);
ProcessFrameInsertions(mRealFixedList, FrameChildListID::Fixed);
}
void nsFrameConstructorState::PushAbsoluteContainingBlock(
@@ -847,26 +862,29 @@ void nsFrameConstructorState::PushAbsoluteContainingBlock(
aSaveState.mList = &mAbsoluteList;
aSaveState.mChildListID = FrameChildListID::Absolute;
aSaveState.mState = this;
aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
if (mFixedPosIsAbsPos) {
// Since we're going to replace mAbsoluteList, we need to save it into
// mFixedList now (and save the current value of mFixedList).
aSaveState.mSavedList = std::move(mFixedList);
mFixedList = std::move(mAbsoluteList);
} else {
// Otherwise, we just save mAbsoluteList.
aSaveState.mSavedList = std::move(mAbsoluteList);
}
aSaveState.mSavedList = std::move(mAbsoluteList);
aSaveState.mSavedFixedList = mFixedList;
mAbsoluteList = AbsoluteFrameList(aNewAbsoluteContainingBlock);
/* See if we're wiring the fixed-pos and abs-pos lists together. This happens
* if we're a transformed/filtered/etc element, or if we force a null abspos
* containing block (for mathml for example).
*/
mFixedPosIsAbsPos =
!aPositionedFrame || aPositionedFrame->IsFixedPosContainingBlock();
mFixedList = [&] {
if (!aPositionedFrame || aPositionedFrame->IsFixedPosContainingBlock()) {
// See if we need to treat abspos and fixedpos the same. This happens if
// we're a transformed/filtered/etc element, or if we force a null abspos
// containing block (for mathml for example).
return &mAbsoluteList;
}
if (aPositionedFrame->StyleDisplay()->mTopLayer == StyleTopLayer::Top) {
// If our new CB is in the top layer, and isn't a fixed CB itself, we also
// escape the usual containment.
return &mRealFixedList;
}
if (mFixedList == &mAbsoluteList) {
// If we were pointing to our old absolute list, keep pointing to it.
return &aSaveState.mSavedList;
}
// Otherwise keep pointing to the current thing (another ancestor's
// absolute list, or the real fixed list, doesn't matter).
return mFixedList;
}();
if (aNewAbsoluteContainingBlock) {
aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
@@ -947,8 +965,8 @@ nsContainerFrame* nsFrameConstructorState::GetGeometricParent(
MOZ_ASSERT(aStyleDisplay.IsAbsolutelyPositionedStyle(),
"Top layer items should always be absolutely positioned");
if (aStyleDisplay.mPosition == StylePositionProperty::Fixed) {
MOZ_ASSERT(mTopLayerFixedList.mContainingBlock, "No root frame?");
return mTopLayerFixedList.mContainingBlock;
MOZ_ASSERT(mRealFixedList.mContainingBlock, "No root frame?");
return mRealFixedList.mContainingBlock;
}
MOZ_ASSERT(aStyleDisplay.mPosition == StylePositionProperty::Absolute);
MOZ_ASSERT(mTopLayerAbsoluteList.mContainingBlock);
@@ -961,8 +979,8 @@ nsContainerFrame* nsFrameConstructorState::GetGeometricParent(
}
if (aStyleDisplay.mPosition == StylePositionProperty::Fixed &&
GetFixedList().mContainingBlock) {
return GetFixedList().mContainingBlock;
mFixedList->mContainingBlock) {
return mFixedList->mContainingBlock;
}
return aContentParentFrame;
@@ -1047,7 +1065,7 @@ AbsoluteFrameList* nsFrameConstructorState::GetOutOfFlowFrameList(
*aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
if (disp->mPosition == StylePositionProperty::Fixed) {
*aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
return &mTopLayerFixedList;
return &mRealFixedList;
}
*aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
return &mTopLayerAbsoluteList;
@@ -1058,7 +1076,7 @@ AbsoluteFrameList* nsFrameConstructorState::GetOutOfFlowFrameList(
}
if (disp->mPosition == StylePositionProperty::Fixed) {
*aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
return &GetFixedList();
return mFixedList;
}
}
return nullptr;
@@ -1157,15 +1175,23 @@ void nsFrameConstructorState::AddChild(
// function's `AutoTArray`s into its callers' stack frames, so disable inlining.
MOZ_NEVER_INLINE void nsFrameConstructorState::ProcessFrameInsertions(
AbsoluteFrameList& aFrameList, FrameChildListID aChildListID) {
#define NS_NONXUL_LIST_TEST \
(&aFrameList == &mFloatedList && aChildListID == FrameChildListID::Float) || \
((&aFrameList == &mAbsoluteList || \
&aFrameList == &mTopLayerAbsoluteList) && \
aChildListID == FrameChildListID::Absolute) || \
((&aFrameList == &mFixedList || &aFrameList == &mTopLayerFixedList) && \
aChildListID == FrameChildListID::Fixed)
MOZ_ASSERT(NS_NONXUL_LIST_TEST,
"Unexpected aFrameList/aChildListID combination");
MOZ_ASSERT(&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList ||
&aFrameList == &mTopLayerAbsoluteList ||
&aFrameList == &mAncestorFixedList || &aFrameList == mFixedList ||
&aFrameList == &mRealFixedList);
MOZ_ASSERT_IF(&aFrameList == &mFloatedList,
aChildListID == FrameChildListID::Float);
MOZ_ASSERT_IF(&aFrameList == &mAbsoluteList || &aFrameList == mFixedList,
aChildListID == FrameChildListID::Absolute ||
aChildListID == FrameChildListID::Fixed);
MOZ_ASSERT_IF(&aFrameList == &mTopLayerAbsoluteList,
aChildListID == FrameChildListID::Absolute);
MOZ_ASSERT_IF(&aFrameList == mFixedList && &aFrameList != &mAbsoluteList,
aChildListID == FrameChildListID::Fixed);
MOZ_ASSERT_IF(&aFrameList == &mAncestorFixedList,
aChildListID == FrameChildListID::Fixed);
MOZ_ASSERT_IF(&aFrameList == &mRealFixedList,
aChildListID == FrameChildListID::Fixed);
if (aFrameList.IsEmpty()) {
return;
@@ -1290,15 +1316,8 @@ nsFrameConstructorSaveState::~nsFrameConstructorSaveState() {
mState->ProcessFrameInsertions(*mList, mChildListID);
if (mList == &mState->mAbsoluteList) {
mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
// mAbsoluteList was moved to mFixedList, so move mFixedList back
// and repair the old mFixedList now.
if (mSavedFixedPosIsAbsPos) {
mState->mAbsoluteList = std::move(mState->mFixedList);
mState->mFixedList = std::move(mSavedList);
} else {
mState->mAbsoluteList = std::move(mSavedList);
}
mState->mAbsoluteList = std::move(mSavedList);
mState->mFixedList = mSavedFixedList;
} else {
mState->mFloatedList = std::move(mSavedList);
}
@@ -5578,8 +5597,10 @@ nsContainerFrame* nsCSSFrameConstructor::GetAbsoluteContainingBlock(
// the correct containing block (the scrolledframe) in that case.
// If we're looking for a fixed-pos containing block and the frame is
// not transformed, skip it.
if (!frame->IsAbsPosContainingBlock() ||
(aType == FIXED_POS && !frame->IsFixedPosContainingBlock())) {
if (!frame->IsAbsPosContainingBlock()) {
continue;
}
if (aType == FIXED_POS && !frame->IsFixedPosContainingBlock()) {
continue;
}
nsIFrame* absPosCBCandidate = frame;