Bug 1236400 part 2: Extend NeedsAnonFlexOrGridItem() & related code to wrap all inline-level -webkit-box children in an anonymous flex item. r=mats

MozReview-Commit-ID: LK4VW0xSI5m
This commit is contained in:
Daniel Holbert
2016-03-24 09:55:11 -07:00
parent 22b6cb5f0f
commit ff3a1cedde
2 changed files with 57 additions and 17 deletions

View File

@@ -341,6 +341,15 @@ IsFlexOrGridContainer(const nsIFrame* aFrame)
t == nsGkAtoms::gridContainerFrame; t == nsGkAtoms::gridContainerFrame;
} }
// Returns true if aFrame has "display: -webkit-{inline-}box"
static inline bool
IsWebkitBox(const nsIFrame* aFrame)
{
auto containerDisplay = aFrame->StyleDisplay()->mDisplay;
return containerDisplay == NS_STYLE_DISPLAY_WEBKIT_BOX ||
containerDisplay == NS_STYLE_DISPLAY_WEBKIT_INLINE_BOX;
}
#if DEBUG #if DEBUG
static void static void
AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild, AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
@@ -9752,10 +9761,13 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
} }
nsIAtom* containerType = aParentFrame->GetType(); nsIAtom* containerType = aParentFrame->GetType();
const bool isWebkitBox = IsWebkitBox(aParentFrame);
FCItemIterator iter(aItems); FCItemIterator iter(aItems);
do { do {
// Advance iter past children that don't want to be wrapped // Advance iter past children that don't want to be wrapped
if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, containerType)) { if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, containerType,
isWebkitBox)) {
// Hit the end of the items without finding any remaining children that // Hit the end of the items without finding any remaining children that
// need to be wrapped. We're finished! // need to be wrapped. We're finished!
return; return;
@@ -9777,8 +9789,10 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
FCItemIterator afterWhitespaceIter(iter); FCItemIterator afterWhitespaceIter(iter);
bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState); bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
bool nextChildNeedsAnonItem = bool nextChildNeedsAnonItem =
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState, !hitEnd &&
containerType); afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState,
containerType,
isWebkitBox);
if (!nextChildNeedsAnonItem) { if (!nextChildNeedsAnonItem) {
// There's nothing after the whitespace that we need to wrap, so we // There's nothing after the whitespace that we need to wrap, so we
@@ -9792,7 +9806,8 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
// we jump back to the beginning of the loop to skip over that child // we jump back to the beginning of the loop to skip over that child
// (and anything else non-wrappable after it) // (and anything else non-wrappable after it)
MOZ_ASSERT(!iter.IsDone() && MOZ_ASSERT(!iter.IsDone() &&
!iter.item().NeedsAnonFlexOrGridItem(aState, containerType), !iter.item().NeedsAnonFlexOrGridItem(aState, containerType,
isWebkitBox),
"hitEnd and/or nextChildNeedsAnonItem lied"); "hitEnd and/or nextChildNeedsAnonItem lied");
continue; continue;
} }
@@ -9802,7 +9817,8 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
// anonymous flex/grid item. Now we see how many children after it also want // anonymous flex/grid item. Now we see how many children after it also want
// to be wrapped in an anonymous flex/grid item. // to be wrapped in an anonymous flex/grid item.
FCItemIterator endIter(iter); // iterator to find the end of the group FCItemIterator endIter(iter); // iterator to find the end of the group
endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, containerType); endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, containerType,
isWebkitBox);
NS_ASSERTION(iter != endIter, NS_ASSERTION(iter != endIter,
"Should've had at least one wrappable child to seek past"); "Should've had at least one wrappable child to seek past");
@@ -12042,8 +12058,10 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// Check if we're adding to-be-wrapped content right *after* an existing // Check if we're adding to-be-wrapped content right *after* an existing
// anonymous flex or grid item (which would need to absorb this content). // anonymous flex or grid item (which would need to absorb this content).
nsIAtom* containerType = aFrame->GetType(); nsIAtom* containerType = aFrame->GetType();
bool isWebkitBox = IsWebkitBox(aFrame);
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) && if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
iter.item().NeedsAnonFlexOrGridItem(aState, containerType)) { iter.item().NeedsAnonFlexOrGridItem(aState, containerType,
isWebkitBox)) {
RecreateFramesForContent(aFrame->GetContent(), true, RecreateFramesForContent(aFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr); REMOVE_FOR_RECONSTRUCTION, nullptr);
return true; return true;
@@ -12055,7 +12073,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// Jump to the last entry in the list // Jump to the last entry in the list
iter.SetToEnd(); iter.SetToEnd();
iter.Prev(); iter.Prev();
if (iter.item().NeedsAnonFlexOrGridItem(aState, containerType)) { if (iter.item().NeedsAnonFlexOrGridItem(aState, containerType,
isWebkitBox)) {
RecreateFramesForContent(aFrame->GetContent(), true, RecreateFramesForContent(aFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr); REMOVE_FOR_RECONSTRUCTION, nullptr);
return true; return true;
@@ -12082,7 +12101,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// they're perfectly happy to go here -- they won't cause a reframe. // they're perfectly happy to go here -- they won't cause a reframe.
nsIFrame* containerFrame = aFrame->GetParent(); nsIFrame* containerFrame = aFrame->GetParent();
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState,
containerFrame->GetType())) { containerFrame->GetType(),
IsWebkitBox(containerFrame))) {
// We hit something that _doesn't_ need an anonymous flex item! // We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out. // Rebuild the flex container to bust it out.
RecreateFramesForContent(containerFrame->GetContent(), true, RecreateFramesForContent(containerFrame->GetContent(), true,
@@ -12534,10 +12554,14 @@ Iterator::SkipItemsNotWantingParentType(ParentType aParentType)
return false; return false;
} }
// Note: we implement -webkit-box & -webkit-inline-box using
// nsFlexContainerFrame, but we use different rules for what gets wrapped in an
// anonymous flex item.
bool bool
nsCSSFrameConstructor::FrameConstructionItem:: nsCSSFrameConstructor::FrameConstructionItem::
NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState, NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
nsIAtom* aContainerType) nsIAtom* aContainerType,
bool aIsWebkitBox)
{ {
if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) { if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
// This will be an inline non-replaced box. // This will be an inline non-replaced box.
@@ -12555,6 +12579,12 @@ nsCSSFrameConstructor::FrameConstructionItem::
return true; return true;
} }
if (aIsWebkitBox &&
mStyleContext->StyleDisplay()->IsInlineOutsideStyle()) {
// In a -webkit-box, all inline-level content gets wrapped in an anon item.
return true;
}
return false; return false;
} }
@@ -12562,10 +12592,12 @@ inline bool
nsCSSFrameConstructor::FrameConstructionItemList:: nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatNeedAnonFlexOrGridItem( Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState, const nsFrameConstructorState& aState,
nsIAtom* aContainerType) nsIAtom* aContainerType,
bool aIsWebkitBox)
{ {
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet"); NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (item().NeedsAnonFlexOrGridItem(aState, aContainerType)) { while (item().NeedsAnonFlexOrGridItem(aState, aContainerType,
aIsWebkitBox)) {
Next(); Next();
if (IsDone()) { if (IsDone()) {
return true; return true;
@@ -12578,10 +12610,12 @@ inline bool
nsCSSFrameConstructor::FrameConstructionItemList:: nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem( Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState, const nsFrameConstructorState& aState,
nsIAtom* aContainerType) nsIAtom* aContainerType,
bool aIsWebkitBox)
{ {
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet"); NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (!(item().NeedsAnonFlexOrGridItem(aState, aContainerType))) { while (!(item().NeedsAnonFlexOrGridItem(aState, aContainerType,
aIsWebkitBox))) {
Next(); Next();
if (IsDone()) { if (IsDone()) {
return true; return true;

View File

@@ -925,13 +925,15 @@ private:
// Return whether the iterator is done after doing that. // Return whether the iterator is done after doing that.
// The iterator must not be done when this is called. // The iterator must not be done when this is called.
inline bool SkipItemsThatNeedAnonFlexOrGridItem( inline bool SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState, nsIAtom* aContainerType); const nsFrameConstructorState& aState, nsIAtom* aContainerType,
bool aIsWebkitBox);
// Skip to the first frame that is a non-replaced inline or is // Skip to the first frame that is a non-replaced inline or is
// positioned. Return whether the iterator is done after doing that. // positioned. Return whether the iterator is done after doing that.
// The iterator must not be done when this is called. // The iterator must not be done when this is called.
inline bool SkipItemsThatDontNeedAnonFlexOrGridItem( inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState, nsIAtom* aContainerType); const nsFrameConstructorState& aState, nsIAtom* aContainerType,
bool aIsWebkitBox);
// Skip over all items that do not want a ruby parent. Return whether // Skip over all items that do not want a ruby parent. Return whether
// the iterator is done after doing that. The iterator must not be done // the iterator is done after doing that. The iterator must not be done
@@ -1067,9 +1069,13 @@ private:
} }
// Indicates whether (when in a flex or grid container) this item needs // Indicates whether (when in a flex or grid container) this item needs
// to be wrapped in an anonymous block. // to be wrapped in an anonymous block. (Note that we implement
// -webkit-box/-webkit-inline-box using our standard flexbox frame class,
// but we use different rules for what gets wrapped. The aIsWebkitBox
// parameter here tells us whether to use those different rules.)
bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState, bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
nsIAtom* aContainerType); nsIAtom* aContainerType,
bool aIsWebkitBox);
// Don't call this unless the frametree really depends on the answer! // Don't call this unless the frametree really depends on the answer!
// Especially so for generated content, where we don't want to reframe // Especially so for generated content, where we don't want to reframe