Bug 666041 patch 2.5: Add nsCSSFrameConstructor code for detecting when a flex container needs to have its frames rebuilt. r=bz

This commit is contained in:
Daniel Holbert 2012-06-26 15:11:53 -07:00
parent 348d6c9a3d
commit a445dcdc59

View File

@ -329,6 +329,16 @@ static PRInt32 FFWC_recursions=0;
static PRInt32 FFWC_nextInFlows=0;
#endif
#ifdef MOZ_FLEXBOX
// Returns true if aFrame is an anonymous flex item
static inline bool
IsAnonymousFlexItem(const nsIFrame* aFrame)
{
const nsIAtom* pseudoType = aFrame->GetStyleContext()->GetPseudo();
return pseudoType == nsCSSAnonBoxes::anonymousFlexItem;
}
#endif // MOZ_FLEXBOX
static inline nsIFrame*
GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
{
@ -8984,6 +8994,55 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
return true;
}
#ifdef MOZ_FLEXBOX
// Might need to reconstruct things if the removed frame's nextSibling is an
// anonymous flex item. The removed frame might've been what divided two
// runs of inline content into two anonymous flex items, which would now
// need to be merged.
// NOTE: It's fine that we've advanced nextSibling past whitespace (up above);
// we're only interested in anonymous flex items here, and those can never
// be adjacent to whitespace, since they absorb contiguous runs of inline
// non-replaced content (including whitespace).
if (nextSibling && IsAnonymousFlexItem(nextSibling)) {
NS_ABORT_IF_FALSE(parent->GetType() == nsGkAtoms::flexContainerFrame,
"anonymous flex items should only exist as children "
"of flex container frames");
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, aFrame);
printf(" has an anonymous flex item as its next sibling\n");
}
#endif // DEBUG
// Recreate frames for the flex container (the removed frame's parent)
*aResult = RecreateFramesForContent(parent->GetContent(), true);
return true;
}
// Might need to reconstruct things if the removed frame's nextSibling is
// null and its parent is an anonymous flex item. (This might be the last
// remaining child of that anonymous flex item, which can then go away.)
if (!nextSibling && IsAnonymousFlexItem(parent)) {
NS_ABORT_IF_FALSE(parent->GetParent() &&
parent->GetParent()->GetType() == nsGkAtoms::flexContainerFrame,
"anonymous flex items should only exist as children "
"of flex container frames");
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, aFrame);
printf(" has an anonymous flex item as its parent\n");
}
#endif // DEBUG
// Recreate frames for the flex container (the removed frame's grandparent)
*aResult = RecreateFramesForContent(parent->GetParent()->GetContent(),
true);
return true;
}
#endif // MOZ_FLEXBOX
#ifdef MOZ_XUL
if (aFrame->GetType() == nsGkAtoms::popupSetFrame) {
nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
@ -11132,7 +11191,67 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
// Situation #2 is a case when table pseudo-frames don't work out right
#ifdef MOZ_FLEXBOX
// Situation #2 is a flex container frame into which we're inserting new
// inline non-replaced children, adjacent to an existing anonymous flex item.
if (aFrame->GetType() == nsGkAtoms::flexContainerFrame) {
FCItemIterator iter(aItems);
// Check if we're adding to-be-wrapped content right *after* an existing
// anonymous flex item (which would need to absorb this content).
if (aPrevSibling && IsAnonymousFlexItem(aPrevSibling) &&
iter.item().NeedsAnonFlexItem(aState)) {
RecreateFramesForContent(aFrame->GetContent(), true);
return true;
}
// Check if we're adding to-be-wrapped content right *before* an existing
// anonymous flex item (which would need to absorb this content).
if (nextSibling && IsAnonymousFlexItem(nextSibling)) {
// Jump to the last entry in the list
iter.SetToEnd();
iter.Prev();
if (iter.item().NeedsAnonFlexItem(aState)) {
RecreateFramesForContent(aFrame->GetContent(), true);
return true;
}
}
}
// Situation #3 is an anonymous flex item that's getting new children who
// don't want to be wrapped.
if (IsAnonymousFlexItem(aFrame)) {
nsIFrame* flexContainerFrame = aFrame->GetParent();
NS_ABORT_IF_FALSE(flexContainerFrame &&
flexContainerFrame->GetType() == nsGkAtoms::flexContainerFrame,
"anonymous flex items should only exist as children "
"of flex container frames");
// We need to push a null float containing block to be sure that
// "NeedsAnonFlexItem" will know we're not honoring floats for this
// inserted content. (In particular, this is necessary in order for
// NeedsAnonFlexItem's "GetGeometricParent" call to return the correct
// result.) We're not honoring floats on this content because it has the
// _flex container_ as its parent in the content tree.
nsFrameConstructorSaveState floatSaveState;
aState.PushFloatContainingBlock(nsnull, floatSaveState);
FCItemIterator iter(aItems);
// Skip over things that _do_ need an anonymous flex item, because
// they're perfectly happy to go here -- they won't cause a reframe.
if (!iter.SkipItemsThatNeedAnonFlexItem(aState)) {
// We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out.
RecreateFramesForContent(flexContainerFrame->GetContent(), true);
return true;
}
// If we get here, then everything in |aItems| needs to be wrapped in
// an anonymous flex item. That's where it's already going - good!
}
#endif // MOZ_FLEXBOX
// Situation #4 is a case when table pseudo-frames don't work out right
ParentType parentType = GetParentType(aFrame);
// If all the kids want a parent of the type that aFrame is, then we're all
// set to go. Indeed, there won't be any table pseudo-frames created between