зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1622935 Part 2 - Move nsGridContainerFrame's NormalizeChildLists() and related helpers to nsContainerFrame. r=mats
Also, add relevant bits to be able to use them in the flex container. Differential Revision: https://phabricator.services.mozilla.com/D73166
This commit is contained in:
Родитель
06f54ceeb6
Коммит
b510e66915
|
@ -1602,6 +1602,212 @@ bool nsContainerFrame::PushIncompleteChildren(
|
|||
return true;
|
||||
}
|
||||
|
||||
void nsContainerFrame::NormalizeChildLists() {
|
||||
MOZ_ASSERT(IsFlexOrGridContainer(),
|
||||
"Only Flex / Grid containers can call this!");
|
||||
|
||||
// Note: the following description uses grid container as an example. Flex
|
||||
// container is similar.
|
||||
//
|
||||
// First we gather child frames we should include in our reflow/placement,
|
||||
// i.e. overflowed children from our prev-in-flow, and pushed first-in-flow
|
||||
// children (that might now fit). It's important to note that these children
|
||||
// can be in arbitrary order vis-a-vis the current children in our lists.
|
||||
// E.g. grid items in the document order: A, B, C may be placed in the rows
|
||||
// 3, 2, 1. Assume each row goes in a separate grid container fragment,
|
||||
// and we reflow the second fragment. Now if C (in fragment 1) overflows,
|
||||
// we can't just prepend it to our mFrames like we usually do because that
|
||||
// would violate the document order invariant that other code depends on.
|
||||
// Similarly if we pull up child A (from fragment 3) we can't just append
|
||||
// that for the same reason. Instead, we must sort these children into
|
||||
// our child lists. (The sorting is trivial given that both lists are
|
||||
// already fully sorted individually - it's just a merge.)
|
||||
//
|
||||
// The invariants that we maintain are that each grid container child list
|
||||
// is sorted in the normal document order at all times, but that children
|
||||
// in different grid container continuations may be in arbitrary order.
|
||||
|
||||
const auto didPushItemsBit = IsFlexContainerFrame()
|
||||
? NS_STATE_FLEX_DID_PUSH_ITEMS
|
||||
: NS_STATE_GRID_DID_PUSH_ITEMS;
|
||||
const auto hasChildNifBit = IsFlexContainerFrame()
|
||||
? NS_STATE_FLEX_HAS_CHILD_NIFS
|
||||
: NS_STATE_GRID_HAS_CHILD_NIFS;
|
||||
|
||||
auto* prevInFlow = static_cast<nsContainerFrame*>(GetPrevInFlow());
|
||||
// Merge overflow frames from our prev-in-flow into our principal child list.
|
||||
if (prevInFlow) {
|
||||
AutoFrameListPtr overflow(PresContext(), prevInFlow->StealOverflowFrames());
|
||||
if (overflow) {
|
||||
ReparentFrames(*overflow, prevInFlow, this);
|
||||
MergeSortedFrameLists(mFrames, *overflow, GetContent());
|
||||
|
||||
// Move trailing next-in-flows into our overflow list.
|
||||
nsFrameList continuations;
|
||||
for (nsIFrame* f = mFrames.FirstChild(); f;) {
|
||||
nsIFrame* next = f->GetNextSibling();
|
||||
nsIFrame* pif = f->GetPrevInFlow();
|
||||
if (pif && pif->GetParent() == this) {
|
||||
mFrames.RemoveFrame(f);
|
||||
continuations.AppendFrame(nullptr, f);
|
||||
}
|
||||
f = next;
|
||||
}
|
||||
MergeSortedOverflow(continuations);
|
||||
|
||||
// Move trailing OC next-in-flows into our excess overflow containers
|
||||
// list.
|
||||
nsFrameList* overflowContainers =
|
||||
GetPropTableFrames(OverflowContainersProperty());
|
||||
if (overflowContainers) {
|
||||
nsFrameList moveToEOC;
|
||||
for (nsIFrame* f = overflowContainers->FirstChild(); f;) {
|
||||
nsIFrame* next = f->GetNextSibling();
|
||||
nsIFrame* pif = f->GetPrevInFlow();
|
||||
if (pif && pif->GetParent() == this) {
|
||||
overflowContainers->RemoveFrame(f);
|
||||
moveToEOC.AppendFrame(nullptr, f);
|
||||
}
|
||||
f = next;
|
||||
}
|
||||
if (overflowContainers->IsEmpty()) {
|
||||
RemoveProperty(OverflowContainersProperty());
|
||||
}
|
||||
MergeSortedExcessOverflowContainers(moveToEOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge our own overflow frames into our principal child list,
|
||||
// except those that are a next-in-flow for one of our items.
|
||||
DebugOnly<bool> foundOwnPushedChild = false;
|
||||
{
|
||||
nsFrameList* ourOverflow = GetOverflowFrames();
|
||||
if (ourOverflow) {
|
||||
nsFrameList items;
|
||||
for (nsIFrame* f = ourOverflow->FirstChild(); f;) {
|
||||
nsIFrame* next = f->GetNextSibling();
|
||||
nsIFrame* pif = f->GetPrevInFlow();
|
||||
if (!pif || pif->GetParent() != this) {
|
||||
MOZ_ASSERT(f->GetParent() == this);
|
||||
ourOverflow->RemoveFrame(f);
|
||||
items.AppendFrame(nullptr, f);
|
||||
if (!pif) {
|
||||
foundOwnPushedChild = true;
|
||||
}
|
||||
}
|
||||
f = next;
|
||||
}
|
||||
MergeSortedFrameLists(mFrames, items, GetContent());
|
||||
if (ourOverflow->IsEmpty()) {
|
||||
DestroyOverflowList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Push any child next-in-flows in our principal list to OverflowList.
|
||||
if (HasAnyStateBits(hasChildNifBit)) {
|
||||
nsFrameList framesToPush;
|
||||
nsIFrame* firstChild = mFrames.FirstChild();
|
||||
// Note that we potentially modify our mFrames list as we go.
|
||||
for (auto* child = firstChild; child; child = child->GetNextSibling()) {
|
||||
if (auto* childNIF = child->GetNextInFlow()) {
|
||||
if (childNIF->GetParent() == this) {
|
||||
for (auto* c = child->GetNextSibling(); c; c = c->GetNextSibling()) {
|
||||
if (c == childNIF) {
|
||||
// child's next-in-flow is in our principal child list, push it.
|
||||
mFrames.RemoveFrame(childNIF);
|
||||
framesToPush.AppendFrame(nullptr, childNIF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!framesToPush.IsEmpty()) {
|
||||
MergeSortedOverflow(framesToPush);
|
||||
}
|
||||
RemoveStateBits(hasChildNifBit);
|
||||
}
|
||||
|
||||
// Pull up any first-in-flow children we might have pushed.
|
||||
if (HasAnyStateBits(didPushItemsBit)) {
|
||||
RemoveStateBits(didPushItemsBit);
|
||||
nsFrameList items;
|
||||
auto* nif = static_cast<nsContainerFrame*>(GetNextInFlow());
|
||||
auto* firstNIF = nif;
|
||||
DebugOnly<bool> nifNeedPushedItem = false;
|
||||
while (nif) {
|
||||
nsFrameList nifItems;
|
||||
for (nsIFrame* nifChild = nif->GetChildList(kPrincipalList).FirstChild();
|
||||
nifChild;) {
|
||||
nsIFrame* next = nifChild->GetNextSibling();
|
||||
if (!nifChild->GetPrevInFlow()) {
|
||||
nif->StealFrame(nifChild);
|
||||
ReparentFrame(nifChild, nif, this);
|
||||
nifItems.AppendFrame(nullptr, nifChild);
|
||||
nifNeedPushedItem = false;
|
||||
}
|
||||
nifChild = next;
|
||||
}
|
||||
MergeSortedFrameLists(items, nifItems, GetContent());
|
||||
|
||||
if (!nif->HasAnyStateBits(didPushItemsBit)) {
|
||||
MOZ_ASSERT(!nifNeedPushedItem || mDidPushItemsBitMayLie,
|
||||
"The state bit stored in didPushItemsBit lied!");
|
||||
break;
|
||||
}
|
||||
nifNeedPushedItem = true;
|
||||
|
||||
for (nsIFrame* nifChild = nif->GetChildList(kOverflowList).FirstChild();
|
||||
nifChild;) {
|
||||
nsIFrame* next = nifChild->GetNextSibling();
|
||||
if (!nifChild->GetPrevInFlow()) {
|
||||
nif->StealFrame(nifChild);
|
||||
ReparentFrame(nifChild, nif, this);
|
||||
nifItems.AppendFrame(nullptr, nifChild);
|
||||
nifNeedPushedItem = false;
|
||||
}
|
||||
nifChild = next;
|
||||
}
|
||||
MergeSortedFrameLists(items, nifItems, GetContent());
|
||||
|
||||
nif->RemoveStateBits(didPushItemsBit);
|
||||
nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow());
|
||||
MOZ_ASSERT(nif || !nifNeedPushedItem || mDidPushItemsBitMayLie,
|
||||
"The state bit stored in didPushItemsBit lied!");
|
||||
}
|
||||
|
||||
if (!items.IsEmpty()) {
|
||||
// Pull up the first next-in-flow of the pulled up items too, unless its
|
||||
// parent is our nif (to avoid leaving a hole there).
|
||||
nsFrameList childNIFs;
|
||||
nsFrameList childOCNIFs;
|
||||
for (auto* child : items) {
|
||||
auto* childNIF = child->GetNextInFlow();
|
||||
if (childNIF && childNIF->GetParent() != firstNIF) {
|
||||
auto* parent = childNIF->GetParent();
|
||||
parent->StealFrame(childNIF);
|
||||
ReparentFrame(childNIF, parent, firstNIF);
|
||||
if ((childNIF->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
|
||||
childOCNIFs.AppendFrame(nullptr, childNIF);
|
||||
} else {
|
||||
childNIFs.AppendFrame(nullptr, childNIF);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Merge items' NIFs into our NIF's respective overflow child lists.
|
||||
firstNIF->MergeSortedOverflow(childNIFs);
|
||||
firstNIF->MergeSortedExcessOverflowContainers(childOCNIFs);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
foundOwnPushedChild || !items.IsEmpty() || mDidPushItemsBitMayLie,
|
||||
"The state bit stored in didPushItemsBit lied!");
|
||||
MergeSortedFrameLists(mFrames, items, GetContent());
|
||||
}
|
||||
}
|
||||
|
||||
bool nsContainerFrame::MoveOverflowToChildList() {
|
||||
bool result = false;
|
||||
|
||||
|
@ -2204,6 +2410,76 @@ void nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild) {
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Debugging
|
||||
|
||||
#ifdef DEBUG
|
||||
void nsContainerFrame::SanityCheckChildListsBeforeReflow() const {
|
||||
MOZ_ASSERT(IsFlexOrGridContainer(),
|
||||
"Only Flex / Grid containers can call this!");
|
||||
|
||||
const auto didPushItemsBit = IsFlexContainerFrame()
|
||||
? NS_STATE_FLEX_DID_PUSH_ITEMS
|
||||
: NS_STATE_GRID_DID_PUSH_ITEMS;
|
||||
ChildListIDs absLists = {kAbsoluteList, kFixedList, kOverflowContainersList,
|
||||
kExcessOverflowContainersList};
|
||||
ChildListIDs itemLists = {kPrincipalList, kOverflowList};
|
||||
for (const nsIFrame* f = this; f; f = f->GetNextInFlow()) {
|
||||
MOZ_ASSERT(!f->HasAnyStateBits(didPushItemsBit),
|
||||
"At start of reflow, we should've pulled items back from all "
|
||||
"NIFs and cleared the state bit stored in didPushItemsBit in "
|
||||
"the process.");
|
||||
for (nsIFrame::ChildListIterator childLists(f); !childLists.IsDone();
|
||||
childLists.Next()) {
|
||||
if (!itemLists.contains(childLists.CurrentID())) {
|
||||
MOZ_ASSERT(absLists.contains(childLists.CurrentID()) ||
|
||||
childLists.CurrentID() == kBackdropList,
|
||||
"unexpected non-empty child list");
|
||||
continue;
|
||||
}
|
||||
for (auto* child : childLists.CurrentList()) {
|
||||
MOZ_ASSERT(f == this || child->GetPrevInFlow(),
|
||||
"all pushed items must be pulled up before reflow");
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we have a prev-in-flow, each of its children's next-in-flow
|
||||
// should be one of our children or be null.
|
||||
const auto* pif = static_cast<nsContainerFrame*>(GetPrevInFlow());
|
||||
if (pif) {
|
||||
const nsFrameList* oc = GetPropTableFrames(OverflowContainersProperty());
|
||||
const nsFrameList* eoc =
|
||||
GetPropTableFrames(ExcessOverflowContainersProperty());
|
||||
const nsFrameList* pifEOC =
|
||||
pif->GetPropTableFrames(ExcessOverflowContainersProperty());
|
||||
for (const nsIFrame* child : pif->GetChildList(kPrincipalList)) {
|
||||
const nsIFrame* childNIF = child->GetNextInFlow();
|
||||
MOZ_ASSERT(!childNIF || mFrames.ContainsFrame(childNIF) ||
|
||||
(pifEOC && pifEOC->ContainsFrame(childNIF)) ||
|
||||
(oc && oc->ContainsFrame(childNIF)) ||
|
||||
(eoc && eoc->ContainsFrame(childNIF)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsContainerFrame::SetDidPushItemsBitIfNeeded(ChildListID aListID,
|
||||
nsIFrame* aOldFrame) {
|
||||
MOZ_ASSERT(IsFlexOrGridContainer(),
|
||||
"Only Flex / Grid containers can call this!");
|
||||
|
||||
// Note that kPrincipalList doesn't mean aOldFrame must be on that list.
|
||||
// It can also be on kOverflowList, in which case it might be a pushed
|
||||
// item, and if it's the only pushed item our DID_PUSH_ITEMS bit will lie.
|
||||
if (aListID == kPrincipalList && !aOldFrame->GetPrevInFlow()) {
|
||||
// Since the bit may lie, set the mDidPushItemsBitMayLie value to true for
|
||||
// ourself and for all our prev-in-flows.
|
||||
nsContainerFrame* frameThatMayLie = this;
|
||||
do {
|
||||
frameThatMayLie->mDidPushItemsBitMayLie = true;
|
||||
frameThatMayLie =
|
||||
static_cast<nsContainerFrame*>(frameThatMayLie->GetPrevInFlow());
|
||||
} while (frameThatMayLie);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
void nsContainerFrame::List(FILE* out, const char* aPrefix,
|
||||
ListFlags aFlags) const {
|
||||
|
|
|
@ -648,6 +648,19 @@ class nsContainerFrame : public nsSplittableFrame {
|
|||
const FrameHashtable& aIncompleteItems,
|
||||
const FrameHashtable& aOverflowIncompleteItems);
|
||||
|
||||
/**
|
||||
* Prepare our child lists so that they are ready to reflow by the following
|
||||
* operations:
|
||||
*
|
||||
* - Merge overflow list from our prev-in-flow into our principal child list.
|
||||
* - Merge our own overflow list into our principal child list,
|
||||
* - Push any child's next-in-flows in our principal child list to our
|
||||
* overflow list.
|
||||
* - Pull up any first-in-flow child we might have pushed from our
|
||||
* next-in-flows.
|
||||
*/
|
||||
void NormalizeChildLists();
|
||||
|
||||
/**
|
||||
* Reparent floats whose placeholders are inline descendants of aFrame from
|
||||
* whatever block they're currently parented by to aOurBlock.
|
||||
|
@ -726,6 +739,22 @@ class nsContainerFrame : public nsSplittableFrame {
|
|||
|
||||
// ==========================================================================
|
||||
|
||||
#ifdef DEBUG
|
||||
// A helper for flex / grid container to sanity check child lists before
|
||||
// reflow. Intended to be called after calling NormalizeChildLists().
|
||||
void SanityCheckChildListsBeforeReflow() const;
|
||||
|
||||
// A helper to set mDidPushItemsBitMayLie if needed. Intended to be called
|
||||
// only in flex / grid container's RemoveFrame.
|
||||
void SetDidPushItemsBitIfNeeded(ChildListID aListID, nsIFrame* aOldFrame);
|
||||
|
||||
// A flag for flex / grid containers. If true, NS_STATE_GRID_DID_PUSH_ITEMS or
|
||||
// NS_STATE_FLEX_DID_PUSH_ITEMS may be set even though all pushed frames may
|
||||
// have been removed. This is used to suppress an assertion in case
|
||||
// RemoveFrame removed all associated child frames.
|
||||
bool mDidPushItemsBitMayLie{false};
|
||||
#endif
|
||||
|
||||
nsFrameList mFrames;
|
||||
};
|
||||
|
||||
|
|
|
@ -352,6 +352,15 @@ FRAME_STATE_BIT(FlexContainer, 23, NS_STATE_FLEX_SYNTHESIZE_BASELINE)
|
|||
// -webkit-line-ellipsis marker.
|
||||
FRAME_STATE_BIT(FlexContainer, 24, NS_STATE_FLEX_HAS_LINE_CLAMP_ELLIPSIS)
|
||||
|
||||
// True iff some first-in-flow in-flow children were pushed.
|
||||
// Note that those child frames may have been removed without this bit
|
||||
// being updated for performance reasons, so code shouldn't depend on
|
||||
// actually finding any pushed items when this bit is set.
|
||||
FRAME_STATE_BIT(FlexContainer, 25, NS_STATE_FLEX_DID_PUSH_ITEMS)
|
||||
|
||||
// We've merged some OverflowList children since last reflow.
|
||||
FRAME_STATE_BIT(FlexContainer, 26, NS_STATE_FLEX_HAS_CHILD_NIFS)
|
||||
|
||||
// == Frame state bits that apply to grid container frames ====================
|
||||
|
||||
FRAME_STATE_GROUP(GridContainer, nsGridContainerFrame)
|
||||
|
|
|
@ -8412,199 +8412,6 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aState,
|
|||
return bSize;
|
||||
}
|
||||
|
||||
void nsGridContainerFrame::NormalizeChildLists() {
|
||||
// First we gather child frames we should include in our reflow/placement,
|
||||
// i.e. overflowed children from our prev-in-flow, and pushed first-in-flow
|
||||
// children (that might now fit). It's important to note that these children
|
||||
// can be in arbitrary order vis-a-vis the current children in our lists.
|
||||
// E.g. grid items in the document order: A, B, C may be placed in the rows
|
||||
// 3, 2, 1. Assume each row goes in a separate grid container fragment,
|
||||
// and we reflow the second fragment. Now if C (in fragment 1) overflows,
|
||||
// we can't just prepend it to our mFrames like we usually do because that
|
||||
// would violate the document order invariant that other code depends on.
|
||||
// Similarly if we pull up child A (from fragment 3) we can't just append
|
||||
// that for the same reason. Instead, we must sort these children into
|
||||
// our child lists. (The sorting is trivial given that both lists are
|
||||
// already fully sorted individually - it's just a merge.)
|
||||
//
|
||||
// The invariants that we maintain are that each grid container child list
|
||||
// is sorted in the normal document order at all times, but that children
|
||||
// in different grid container continuations may be in arbitrary order.
|
||||
|
||||
auto prevInFlow = static_cast<nsGridContainerFrame*>(GetPrevInFlow());
|
||||
// Merge overflow frames from our prev-in-flow into our principal child list.
|
||||
if (prevInFlow) {
|
||||
AutoFrameListPtr overflow(PresContext(), prevInFlow->StealOverflowFrames());
|
||||
if (overflow) {
|
||||
ReparentFrames(*overflow, prevInFlow, this);
|
||||
MergeSortedFrameLists(mFrames, *overflow, GetContent());
|
||||
|
||||
// Move trailing next-in-flows into our overflow list.
|
||||
nsFrameList continuations;
|
||||
for (nsIFrame* f = mFrames.FirstChild(); f;) {
|
||||
nsIFrame* next = f->GetNextSibling();
|
||||
nsIFrame* pif = f->GetPrevInFlow();
|
||||
if (pif && pif->GetParent() == this) {
|
||||
mFrames.RemoveFrame(f);
|
||||
continuations.AppendFrame(nullptr, f);
|
||||
}
|
||||
f = next;
|
||||
}
|
||||
MergeSortedOverflow(continuations);
|
||||
|
||||
// Move trailing OC next-in-flows into our excess overflow containers
|
||||
// list.
|
||||
nsFrameList* overflowContainers =
|
||||
GetPropTableFrames(OverflowContainersProperty());
|
||||
if (overflowContainers) {
|
||||
nsFrameList moveToEOC;
|
||||
for (nsIFrame* f = overflowContainers->FirstChild(); f;) {
|
||||
nsIFrame* next = f->GetNextSibling();
|
||||
nsIFrame* pif = f->GetPrevInFlow();
|
||||
if (pif && pif->GetParent() == this) {
|
||||
overflowContainers->RemoveFrame(f);
|
||||
moveToEOC.AppendFrame(nullptr, f);
|
||||
}
|
||||
f = next;
|
||||
}
|
||||
if (overflowContainers->IsEmpty()) {
|
||||
RemoveProperty(OverflowContainersProperty());
|
||||
}
|
||||
MergeSortedExcessOverflowContainers(moveToEOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge our own overflow frames into our principal child list,
|
||||
// except those that are a next-in-flow for one of our items.
|
||||
DebugOnly<bool> foundOwnPushedChild = false;
|
||||
{
|
||||
nsFrameList* ourOverflow = GetOverflowFrames();
|
||||
if (ourOverflow) {
|
||||
nsFrameList items;
|
||||
for (nsIFrame* f = ourOverflow->FirstChild(); f;) {
|
||||
nsIFrame* next = f->GetNextSibling();
|
||||
nsIFrame* pif = f->GetPrevInFlow();
|
||||
if (!pif || pif->GetParent() != this) {
|
||||
MOZ_ASSERT(f->GetParent() == this);
|
||||
ourOverflow->RemoveFrame(f);
|
||||
items.AppendFrame(nullptr, f);
|
||||
if (!pif) {
|
||||
foundOwnPushedChild = true;
|
||||
}
|
||||
}
|
||||
f = next;
|
||||
}
|
||||
MergeSortedFrameLists(mFrames, items, GetContent());
|
||||
if (ourOverflow->IsEmpty()) {
|
||||
DestroyOverflowList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Push any child next-in-flows in our principal list to OverflowList.
|
||||
if (HasAnyStateBits(NS_STATE_GRID_HAS_CHILD_NIFS)) {
|
||||
nsFrameList framesToPush;
|
||||
nsIFrame* firstChild = mFrames.FirstChild();
|
||||
// Note that we potentially modify our mFrames list as we go.
|
||||
for (auto child = firstChild; child; child = child->GetNextSibling()) {
|
||||
if (auto* childNIF = child->GetNextInFlow()) {
|
||||
if (childNIF->GetParent() == this) {
|
||||
for (auto c = child->GetNextSibling(); c; c = c->GetNextSibling()) {
|
||||
if (c == childNIF) {
|
||||
// child's next-in-flow is in our principal child list, push it.
|
||||
mFrames.RemoveFrame(childNIF);
|
||||
framesToPush.AppendFrame(nullptr, childNIF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!framesToPush.IsEmpty()) {
|
||||
MergeSortedOverflow(framesToPush);
|
||||
}
|
||||
RemoveStateBits(NS_STATE_GRID_HAS_CHILD_NIFS);
|
||||
}
|
||||
|
||||
// Pull up any first-in-flow children we might have pushed.
|
||||
if (HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS)) {
|
||||
RemoveStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
|
||||
nsFrameList items;
|
||||
auto nif = static_cast<nsGridContainerFrame*>(GetNextInFlow());
|
||||
auto firstNIF = nif;
|
||||
DebugOnly<bool> nifNeedPushedItem = false;
|
||||
while (nif) {
|
||||
nsFrameList nifItems;
|
||||
for (nsIFrame* nifChild = nif->GetChildList(kPrincipalList).FirstChild();
|
||||
nifChild;) {
|
||||
nsIFrame* next = nifChild->GetNextSibling();
|
||||
if (!nifChild->GetPrevInFlow()) {
|
||||
nif->StealFrame(nifChild);
|
||||
ReparentFrame(nifChild, nif, this);
|
||||
nifItems.AppendFrame(nullptr, nifChild);
|
||||
nifNeedPushedItem = false;
|
||||
}
|
||||
nifChild = next;
|
||||
}
|
||||
MergeSortedFrameLists(items, nifItems, GetContent());
|
||||
|
||||
if (!nif->HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS)) {
|
||||
MOZ_ASSERT(!nifNeedPushedItem || mDidPushItemsBitMayLie,
|
||||
"NS_STATE_GRID_DID_PUSH_ITEMS lied");
|
||||
break;
|
||||
}
|
||||
nifNeedPushedItem = true;
|
||||
|
||||
for (nsIFrame* nifChild = nif->GetChildList(kOverflowList).FirstChild();
|
||||
nifChild;) {
|
||||
nsIFrame* next = nifChild->GetNextSibling();
|
||||
if (!nifChild->GetPrevInFlow()) {
|
||||
nif->StealFrame(nifChild);
|
||||
ReparentFrame(nifChild, nif, this);
|
||||
nifItems.AppendFrame(nullptr, nifChild);
|
||||
nifNeedPushedItem = false;
|
||||
}
|
||||
nifChild = next;
|
||||
}
|
||||
MergeSortedFrameLists(items, nifItems, GetContent());
|
||||
|
||||
nif->RemoveStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
|
||||
nif = static_cast<nsGridContainerFrame*>(nif->GetNextInFlow());
|
||||
MOZ_ASSERT(nif || !nifNeedPushedItem || mDidPushItemsBitMayLie,
|
||||
"NS_STATE_GRID_DID_PUSH_ITEMS lied");
|
||||
}
|
||||
|
||||
if (!items.IsEmpty()) {
|
||||
// Pull up the first next-in-flow of the pulled up items too, unless its
|
||||
// parent is our nif (to avoid leaving a hole there).
|
||||
nsFrameList childNIFs;
|
||||
nsFrameList childOCNIFs;
|
||||
for (auto child : items) {
|
||||
auto childNIF = child->GetNextInFlow();
|
||||
if (childNIF && childNIF->GetParent() != firstNIF) {
|
||||
auto parent = childNIF->GetParent();
|
||||
parent->StealFrame(childNIF);
|
||||
ReparentFrame(childNIF, parent, firstNIF);
|
||||
if ((childNIF->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
|
||||
childOCNIFs.AppendFrame(nullptr, childNIF);
|
||||
} else {
|
||||
childNIFs.AppendFrame(nullptr, childNIF);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Merge items' NIFs into our NIF's respective overflow child lists.
|
||||
firstNIF->MergeSortedOverflow(childNIFs);
|
||||
firstNIF->MergeSortedExcessOverflowContainers(childOCNIFs);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
foundOwnPushedChild || !items.IsEmpty() || mDidPushItemsBitMayLie,
|
||||
"NS_STATE_GRID_DID_PUSH_ITEMS lied");
|
||||
MergeSortedFrameLists(mFrames, items, GetContent());
|
||||
}
|
||||
}
|
||||
|
||||
void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
|
@ -8622,7 +8429,7 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
#ifdef DEBUG
|
||||
mDidPushItemsBitMayLie = false;
|
||||
SanityCheckGridItemsBeforeReflow();
|
||||
SanityCheckChildListsBeforeReflow();
|
||||
#endif // DEBUG
|
||||
|
||||
for (auto& perAxisBaseline : mBaseline) {
|
||||
|
@ -9489,20 +9296,7 @@ void nsGridContainerFrame::RemoveFrame(ChildListID aListID,
|
|||
supportedLists += kBackdropList;
|
||||
MOZ_ASSERT(supportedLists.contains(aListID), "unexpected child list");
|
||||
|
||||
// Note that kPrincipalList doesn't mean aOldFrame must be on that list.
|
||||
// It can also be on kOverflowList, in which case it might be a pushed
|
||||
// item, and if it's the only pushed item our DID_PUSH_ITEMS bit will lie.
|
||||
if (aListID == kPrincipalList && !aOldFrame->GetPrevInFlow()) {
|
||||
// Since the bit may lie, set the mDidPushItemsBitMayLie value to true for
|
||||
// ourself and for all our contiguous previous-in-flow
|
||||
// nsGridContainerFrames.
|
||||
nsGridContainerFrame* frameThatMayLie = this;
|
||||
do {
|
||||
frameThatMayLie->mDidPushItemsBitMayLie = true;
|
||||
frameThatMayLie =
|
||||
static_cast<nsGridContainerFrame*>(frameThatMayLie->GetPrevInFlow());
|
||||
} while (frameThatMayLie);
|
||||
}
|
||||
SetDidPushItemsBitIfNeeded(aListID, aOldFrame);
|
||||
#endif
|
||||
|
||||
nsContainerFrame::RemoveFrame(aListID, aOldFrame);
|
||||
|
@ -9805,47 +9599,6 @@ void nsGridContainerFrame::SetInitialChildList(ChildListID aListID,
|
|||
return nsContainerFrame::SetInitialChildList(aListID, aChildList);
|
||||
}
|
||||
|
||||
void nsGridContainerFrame::SanityCheckGridItemsBeforeReflow() const {
|
||||
ChildListIDs absLists = {kAbsoluteList, kFixedList, kOverflowContainersList,
|
||||
kExcessOverflowContainersList};
|
||||
ChildListIDs itemLists = {kPrincipalList, kOverflowList};
|
||||
for (const nsIFrame* f = this; f; f = f->GetNextInFlow()) {
|
||||
MOZ_ASSERT(!f->HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS),
|
||||
"At start of reflow, we should've pulled items back from all "
|
||||
"NIFs and cleared NS_STATE_GRID_DID_PUSH_ITEMS in the process");
|
||||
for (nsIFrame::ChildListIterator childLists(f); !childLists.IsDone();
|
||||
childLists.Next()) {
|
||||
if (!itemLists.contains(childLists.CurrentID())) {
|
||||
MOZ_ASSERT(absLists.contains(childLists.CurrentID()) ||
|
||||
childLists.CurrentID() == kBackdropList,
|
||||
"unexpected non-empty child list");
|
||||
continue;
|
||||
}
|
||||
for (auto child : childLists.CurrentList()) {
|
||||
MOZ_ASSERT(f == this || child->GetPrevInFlow(),
|
||||
"all pushed items must be pulled up before reflow");
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we have a prev-in-flow, each of its children's next-in-flow
|
||||
// should be one of our children or be null.
|
||||
const auto pif = static_cast<nsGridContainerFrame*>(GetPrevInFlow());
|
||||
if (pif) {
|
||||
const nsFrameList* oc = GetPropTableFrames(OverflowContainersProperty());
|
||||
const nsFrameList* eoc =
|
||||
GetPropTableFrames(ExcessOverflowContainersProperty());
|
||||
const nsFrameList* pifEOC =
|
||||
pif->GetPropTableFrames(ExcessOverflowContainersProperty());
|
||||
for (const nsIFrame* child : pif->GetChildList(kPrincipalList)) {
|
||||
const nsIFrame* childNIF = child->GetNextInFlow();
|
||||
MOZ_ASSERT(!childNIF || mFrames.ContainsFrame(childNIF) ||
|
||||
(pifEOC && pifEOC->ContainsFrame(childNIF)) ||
|
||||
(oc && oc->ContainsFrame(childNIF)) ||
|
||||
(eoc && eoc->ContainsFrame(childNIF)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsGridContainerFrame::TrackSize::DumpStateBits(StateBits aState) {
|
||||
printf("min:");
|
||||
if (aState & eAutoMinSizing) {
|
||||
|
|
|
@ -360,8 +360,6 @@ class nsGridContainerFrame final : public nsContainerFrame {
|
|||
const mozilla::StyleOwnedSlice<mozilla::StyleCustomIdent>;
|
||||
void AddImplicitNamedAreas(mozilla::Span<LineNameList>);
|
||||
|
||||
void NormalizeChildLists();
|
||||
|
||||
/**
|
||||
* Reflow and place our children.
|
||||
* @return the consumed size of all of this grid container's continuations
|
||||
|
@ -448,10 +446,6 @@ class nsGridContainerFrame final : public nsContainerFrame {
|
|||
LineRange GridArea::*aMinor, uint32_t aFragmentStartTrack,
|
||||
uint32_t aFirstExcludedTrack);
|
||||
|
||||
#ifdef DEBUG
|
||||
void SanityCheckGridItemsBeforeReflow() const;
|
||||
#endif // DEBUG
|
||||
|
||||
/**
|
||||
* Update our NS_STATE_GRID_IS_COL/ROW_SUBGRID bits and related subgrid state
|
||||
* on our entire continuation chain based on the current style.
|
||||
|
@ -554,13 +548,6 @@ class nsGridContainerFrame final : public nsContainerFrame {
|
|||
|
||||
// Our baselines, one per BaselineSharingGroup per axis.
|
||||
PerLogicalAxis<PerBaseline<nscoord>> mBaseline;
|
||||
|
||||
#ifdef DEBUG
|
||||
// If true, NS_STATE_GRID_DID_PUSH_ITEMS may be set even though all pushed
|
||||
// frames may have been removed. This is used to suppress an assertion
|
||||
// in case RemoveFrame removed all associated child frames.
|
||||
bool mDidPushItemsBitMayLie{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* nsGridContainerFrame_h___ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче