Bug 1009214 part 1 - [css-grid] Don't wrap placeholders in an anonymous grid item. r=dholbert

This commit is contained in:
Mats Palmgren 2015-05-05 21:53:22 +00:00
parent 1d9dc5cf18
commit 16cb7dcfbc
3 changed files with 80 additions and 27 deletions

View File

@ -9579,7 +9579,7 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
FCItemIterator iter(aItems);
do {
// Advance iter past children that don't want to be wrapped
if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState)) {
if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, containerType)) {
// Hit the end of the items without finding any remaining children that
// need to be wrapped. We're finished!
return;
@ -9601,7 +9601,8 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
FCItemIterator afterWhitespaceIter(iter);
bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
bool nextChildNeedsAnonItem =
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState);
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState,
containerType);
if (!nextChildNeedsAnonItem) {
// There's nothing after the whitespace that we need to wrap, so we
@ -9615,7 +9616,7 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
// we jump back to the beginning of the loop to skip over that child
// (and anything else non-wrappable after it)
MOZ_ASSERT(!iter.IsDone() &&
!iter.item().NeedsAnonFlexOrGridItem(aState),
!iter.item().NeedsAnonFlexOrGridItem(aState, containerType),
"hitEnd and/or nextChildNeedsAnonItem lied");
continue;
}
@ -9625,7 +9626,7 @@ nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
// anonymous flex/grid item. Now we see how many children after it also want
// to be wrapped in an anonymous flex/grid item.
FCItemIterator endIter(iter); // iterator to find the end of the group
endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState);
endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, containerType);
NS_ASSERTION(iter != endIter,
"Should've had at least one wrappable child to seek past");
@ -11831,8 +11832,9 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// 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).
nsIAtom* containerType = aFrame->GetType();
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
iter.item().NeedsAnonFlexOrGridItem(aState)) {
iter.item().NeedsAnonFlexOrGridItem(aState, containerType)) {
RecreateFramesForContent(aFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr);
return true;
@ -11844,7 +11846,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// Jump to the last entry in the list
iter.SetToEnd();
iter.Prev();
if (iter.item().NeedsAnonFlexOrGridItem(aState)) {
if (iter.item().NeedsAnonFlexOrGridItem(aState, containerType)) {
RecreateFramesForContent(aFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr);
return true;
@ -11869,10 +11871,11 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
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.SkipItemsThatNeedAnonFlexOrGridItem(aState)) {
nsIFrame* containerFrame = aFrame->GetParent();
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState,
containerFrame->GetType())) {
// We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out.
nsIFrame* containerFrame = aFrame->GetParent();
RecreateFramesForContent(containerFrame->GetContent(), true,
REMOVE_FOR_RECONSTRUCTION, nullptr);
return true;
@ -12324,14 +12327,17 @@ Iterator::SkipItemsNotWantingParentType(ParentType aParentType)
bool
nsCSSFrameConstructor::FrameConstructionItem::
NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState)
NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
nsIAtom* aContainerType)
{
if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
// This will be an inline non-replaced box.
return true;
}
if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
// Bug 874718: Flex containers still wrap placeholders; Grid containers don't.
if (aContainerType == nsGkAtoms::flexContainerFrame &&
!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
aState.GetGeometricParent(mStyleContext->StyleDisplay(), nullptr)) {
// We're abspos or fixedpos, which means we'll spawn a placeholder which
// we'll need to wrap in an anonymous flex item. So, we just treat
@ -12346,10 +12352,11 @@ nsCSSFrameConstructor::FrameConstructionItem::
inline bool
nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState)
const nsFrameConstructorState& aState,
nsIAtom* aContainerType)
{
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (item().NeedsAnonFlexOrGridItem(aState)) {
while (item().NeedsAnonFlexOrGridItem(aState, aContainerType)) {
Next();
if (IsDone()) {
return true;
@ -12361,10 +12368,11 @@ Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
inline bool
nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState)
const nsFrameConstructorState& aState,
nsIAtom* aContainerType)
{
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (!(item().NeedsAnonFlexOrGridItem(aState))) {
while (!(item().NeedsAnonFlexOrGridItem(aState, aContainerType))) {
Next();
if (IsDone()) {
return true;

View File

@ -931,13 +931,13 @@ private:
// Return whether the iterator is done after doing that.
// The iterator must not be done when this is called.
inline bool SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState);
const nsFrameConstructorState& aState, nsIAtom* aContainerType);
// Skip to the first frame that is a non-replaced inline or is
// positioned. Return whether the iterator is done after doing that.
// The iterator must not be done when this is called.
inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState);
const nsFrameConstructorState& aState, nsIAtom* aContainerType);
// 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
@ -1074,7 +1074,8 @@ private:
// Indicates whether (when in a flex or grid container) this item needs
// to be wrapped in an anonymous block.
bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState);
bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState,
nsIAtom* aContainerType);
// Don't call this unless the frametree really depends on the answer!
// Especially so for generated content, where we don't want to reframe

View File

@ -34,11 +34,14 @@ class nsGridContainerFrame::GridItemCSSOrderIterator
{
public:
enum OrderState { eUnknownOrder, eKnownOrdered, eKnownUnordered };
enum ChildFilter { eSkipPlaceholders, eIncludeAll };
GridItemCSSOrderIterator(nsIFrame* aGridContainer,
nsIFrame::ChildListID aListID,
ChildFilter aFilter = eSkipPlaceholders,
OrderState aState = eUnknownOrder)
: mChildren(aGridContainer->GetChildList(aListID))
, mArrayIndex(0)
, mSkipPlaceholders(aFilter == eSkipPlaceholders)
#ifdef DEBUG
, mGridContainer(aGridContainer)
, mListID(aListID)
@ -69,6 +72,10 @@ public:
// XXX replace this with nsTArray::StableSort when bug 1147091 is fixed.
std::stable_sort(mArray->begin(), mArray->end(), IsCSSOrderLessThan);
}
if (mSkipPlaceholders) {
SkipPlaceholders();
}
}
nsIFrame* operator*() const
@ -80,6 +87,28 @@ public:
return (*mArray)[mArrayIndex];
}
/**
* Skip over placeholder children.
*/
void SkipPlaceholders()
{
if (mEnumerator) {
for (; !mEnumerator->AtEnd(); mEnumerator->Next()) {
nsIFrame* child = mEnumerator->get();
if (child->GetType() != nsGkAtoms::placeholderFrame) {
return;
}
}
} else {
for (; mArrayIndex < mArray->Length(); ++mArrayIndex) {
nsIFrame* child = (*mArray)[mArrayIndex];
if (child->GetType() != nsGkAtoms::placeholderFrame) {
return;
}
}
}
}
bool AtEnd() const
{
MOZ_ASSERT(mEnumerator || mArrayIndex <= mArray->Length());
@ -100,9 +129,12 @@ public:
MOZ_ASSERT(mArrayIndex < mArray->Length(), "iterating past end");
++mArrayIndex;
}
if (mSkipPlaceholders) {
SkipPlaceholders();
}
}
void Reset()
void Reset(ChildFilter aFilter = eSkipPlaceholders)
{
if (mEnumerator) {
mEnumerator.reset();
@ -110,6 +142,10 @@ public:
} else {
mArrayIndex = 0;
}
mSkipPlaceholders = aFilter == eSkipPlaceholders;
if (mSkipPlaceholders) {
SkipPlaceholders();
}
}
bool ItemsAreAlreadyInOrder() const { return mEnumerator.isSome(); }
@ -124,6 +160,8 @@ private:
// Used if child list is *not* in ascending 'order'.
Maybe<nsTArray<nsIFrame*>> mArray;
size_t mArrayIndex;
// Skip placeholder children in the iteration?
bool mSkipPlaceholders;
#ifdef DEBUG
nsIFrame* mGridContainer;
nsIFrame::ChildListID mListID;
@ -1213,13 +1251,19 @@ nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator& aIter,
nsPresContext* pc = PresContext();
for (; !aIter.AtEnd(); aIter.Next()) {
nsIFrame* child = *aIter;
GridArea* area = GetGridAreaForChild(child);
MOZ_ASSERT(area && area->IsDefinite());
LogicalRect cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
cb += gridOrigin;
const bool isGridItem = child->GetType() != nsGkAtoms::placeholderFrame;
LogicalRect cb(wm);
if (MOZ_LIKELY(isGridItem)) {
GridArea* area = GetGridAreaForChild(child);
MOZ_ASSERT(area && area->IsDefinite());
cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
cb += gridOrigin;
} else {
cb = aContentArea;
}
nsHTMLReflowState childRS(pc, aReflowState, child, cb.Size(wm));
const LogicalMargin margin = childRS.ComputedLogicalMargin();
if (childRS.ComputedBSize() == NS_AUTOHEIGHT) {
if (childRS.ComputedBSize() == NS_AUTOHEIGHT && MOZ_LIKELY(isGridItem)) {
// XXX the start of an align-self:stretch impl. Needs min-/max-bsize
// clamping though, and check the prop value is actually 'stretch'!
LogicalMargin bp = childRS.ComputedLogicalBorderPadding();
@ -1331,7 +1375,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
computedISize, bSize);
normalFlowIter.Reset();
normalFlowIter.Reset(GridItemCSSOrderIterator::eIncludeAll);
ReflowChildren(normalFlowIter, contentArea, colSizes, rowSizes, aDesiredSize,
aReflowState, aStatus);
@ -1368,7 +1412,8 @@ nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
typedef GridItemCSSOrderIterator::OrderState OrderState;
OrderState order = mIsNormalFlowInCSSOrder ? OrderState::eKnownOrdered
: OrderState::eKnownUnordered;
GridItemCSSOrderIterator iter(this, kPrincipalList, order);
GridItemCSSOrderIterator iter(this, kPrincipalList,
GridItemCSSOrderIterator::eIncludeAll, order);
for (; !iter.AtEnd(); iter.Next()) {
nsIFrame* child = *iter;
BuildDisplayListForChild(aBuilder, child, aDirtyRect, childLists,
@ -1438,8 +1483,7 @@ FrameWantsToBeInAnonymousGridItem(nsIFrame* aFrame)
{
// Note: This needs to match the logic in
// nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem()
return (aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
nsGkAtoms::placeholderFrame == aFrame->GetType());
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
}
// Debugging method, to let us assert that our anonymous grid items are