mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 1000376 - part 2, Implement frame construction part for anonymous grid items (reusing the anon flex item code). r=dholbert
This commit is contained in:
parent
b998e12bb7
commit
8e16a78e6c
@ -302,14 +302,38 @@ static int32_t FFWC_recursions=0;
|
||||
static int32_t FFWC_nextInFlows=0;
|
||||
#endif
|
||||
|
||||
// Returns true if aFrame is an anonymous flex item
|
||||
// Returns true if aFrame is an anonymous flex/grid item.
|
||||
static inline bool
|
||||
IsAnonymousFlexItem(const nsIFrame* aFrame)
|
||||
IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
|
||||
{
|
||||
const nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
|
||||
return pseudoType == nsCSSAnonBoxes::anonymousFlexItem;
|
||||
return pseudoType == nsCSSAnonBoxes::anonymousFlexItem ||
|
||||
pseudoType == nsCSSAnonBoxes::anonymousGridItem;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static void
|
||||
AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
|
||||
const nsIFrame* aParent)
|
||||
{
|
||||
MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
|
||||
"expected an anonymous flex or grid item child frame");
|
||||
MOZ_ASSERT(aParent, "expected a parent frame");
|
||||
const nsIAtom* pseudoType = aChild->StyleContext()->GetPseudo();
|
||||
if (pseudoType == nsCSSAnonBoxes::anonymousFlexItem) {
|
||||
MOZ_ASSERT(aParent->GetType() == nsGkAtoms::flexContainerFrame,
|
||||
"anonymous flex items should only exist as children "
|
||||
"of flex container frames");
|
||||
} else {
|
||||
MOZ_ASSERT(aParent->GetType() == nsGkAtoms::gridContainerFrame,
|
||||
"anonymous grid items should only exist as children "
|
||||
"of grid container frames");
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define AssertAnonymousFlexOrGridItemParent(x, y) do { /* nothing */ } while(0)
|
||||
#endif
|
||||
|
||||
static inline nsIFrame*
|
||||
GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
|
||||
{
|
||||
@ -8541,10 +8565,8 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
|
||||
// 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");
|
||||
if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
|
||||
AssertAnonymousFlexOrGridItemParent(nextSibling, parent);
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
|
||||
@ -8561,11 +8583,8 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
|
||||
// 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");
|
||||
if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
|
||||
AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
|
||||
@ -8875,20 +8894,24 @@ nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
|
||||
};
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::CreateNeededAnonFlexItems(
|
||||
nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
|
||||
nsFrameConstructorState& aState,
|
||||
FrameConstructionItemList& aItems,
|
||||
nsIFrame* aParentFrame)
|
||||
{
|
||||
if (aItems.IsEmpty() ||
|
||||
aParentFrame->GetType() != nsGkAtoms::flexContainerFrame) {
|
||||
if (aItems.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
nsIAtom* containerType = aParentFrame->GetType();
|
||||
if (containerType != nsGkAtoms::flexContainerFrame &&
|
||||
containerType != nsGkAtoms::gridContainerFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
FCItemIterator iter(aItems);
|
||||
do {
|
||||
// Advance iter past children that don't want to be wrapped
|
||||
if (iter.SkipItemsThatDontNeedAnonFlexItem(aState)) {
|
||||
if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState)) {
|
||||
// Hit the end of the items without finding any remaining children that
|
||||
// need to be wrapped. We're finished!
|
||||
return;
|
||||
@ -8897,22 +8920,22 @@ nsCSSFrameConstructor::CreateNeededAnonFlexItems(
|
||||
// If our next potentially-wrappable child is whitespace, then see if
|
||||
// there's anything wrappable immediately after it. If not, we just drop
|
||||
// the whitespace and move on. (We're not supposed to create any anonymous
|
||||
// flex items that _only_ contain whitespace).
|
||||
// flex/grid items that _only_ contain whitespace).
|
||||
// (BUT if this is generated content, then we don't give whitespace nodes
|
||||
// any special treatment, because they're probably not really whitespace --
|
||||
// they're just temporarily empty, waiting for their generated text.)
|
||||
// XXXdholbert If this node's generated text will *actually end up being
|
||||
// entirely whitespace*, then we technically should still skip over it, per
|
||||
// the flexbox spec. I'm not bothering with that at this point, since it's
|
||||
// a pretty extreme edge case.
|
||||
// the CSS grid & flexbox specs. I'm not bothering with that at this point,
|
||||
// since it's a pretty extreme edge case.
|
||||
if (!aParentFrame->IsGeneratedContentFrame() &&
|
||||
iter.item().IsWhitespace(aState)) {
|
||||
FCItemIterator afterWhitespaceIter(iter);
|
||||
bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
|
||||
bool nextChildNeedsAnonFlexItem =
|
||||
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexItem(aState);
|
||||
bool nextChildNeedsAnonItem =
|
||||
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState);
|
||||
|
||||
if (!nextChildNeedsAnonFlexItem) {
|
||||
if (!nextChildNeedsAnonItem) {
|
||||
// There's nothing after the whitespace that we need to wrap, so we
|
||||
// just drop this run of whitespace.
|
||||
iter.DeleteItemsTo(afterWhitespaceIter);
|
||||
@ -8924,24 +8947,25 @@ nsCSSFrameConstructor::CreateNeededAnonFlexItems(
|
||||
// we jump back to the beginning of the loop to skip over that child
|
||||
// (and anything else non-wrappable after it)
|
||||
NS_ABORT_IF_FALSE(!iter.IsDone() &&
|
||||
!iter.item().NeedsAnonFlexItem(aState),
|
||||
"hitEnd and/or nextChildNeedsAnonFlexItem lied");
|
||||
!iter.item().NeedsAnonFlexOrGridItem(aState),
|
||||
"hitEnd and/or nextChildNeedsAnonItem lied");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Now |iter| points to the first child that needs to be wrapped in an
|
||||
// anonymous flex item. Now we see how many children after it also want
|
||||
// to be wrapped in an anonymous flex item.
|
||||
// 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.SkipItemsThatNeedAnonFlexItem(aState);
|
||||
endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState);
|
||||
|
||||
NS_ASSERTION(iter != endIter,
|
||||
"Should've had at least one wrappable child to seek past");
|
||||
|
||||
// Now, we create the anonymous flex item to contain the children
|
||||
// Now, we create the anonymous flex or grid item to contain the children
|
||||
// between |iter| and |endIter|.
|
||||
nsIAtom* pseudoType = nsCSSAnonBoxes::anonymousFlexItem;
|
||||
nsIAtom* pseudoType = containerType == nsGkAtoms::flexContainerFrame ?
|
||||
nsCSSAnonBoxes::anonymousFlexItem : nsCSSAnonBoxes::anonymousGridItem;
|
||||
nsStyleContext* parentStyle = aParentFrame->StyleContext();
|
||||
nsIContent* parentContent = aParentFrame->GetContent();
|
||||
already_AddRefed<nsStyleContext> wrapperStyle =
|
||||
@ -8968,11 +8992,11 @@ nsCSSFrameConstructor::CreateNeededAnonFlexItems(
|
||||
newItem->mIsBlock = !newItem->mIsAllInline;
|
||||
|
||||
NS_ABORT_IF_FALSE(!newItem->mIsAllInline && newItem->mIsBlock,
|
||||
"expecting anonymous flex items to be block-level "
|
||||
"expecting anonymous flex/grid items to be block-level "
|
||||
"(this will make a difference when we encounter "
|
||||
"'flex-align: baseline')");
|
||||
"'align-items: baseline')");
|
||||
|
||||
// Anonymous flex items induce line boundaries around their
|
||||
// Anonymous flex and grid items induce line boundaries around their
|
||||
// contents.
|
||||
newItem->mChildItems.SetLineBoundaryAtStart(true);
|
||||
newItem->mChildItems.SetLineBoundaryAtEnd(true);
|
||||
@ -9205,7 +9229,7 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta
|
||||
nsFrameItems& aFrameItems)
|
||||
{
|
||||
CreateNeededTablePseudos(aState, aItems, aParentFrame);
|
||||
CreateNeededAnonFlexItems(aState, aItems, aParentFrame);
|
||||
CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
|
||||
|
||||
aItems.SetTriedConstructingFrames();
|
||||
for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
|
||||
@ -10785,56 +10809,53 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
|
||||
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)) {
|
||||
// anonymous flex or grid item (which would need to absorb this content).
|
||||
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
|
||||
iter.item().NeedsAnonFlexOrGridItem(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)) {
|
||||
// anonymous flex or grid item (which would need to absorb this content).
|
||||
if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
|
||||
// Jump to the last entry in the list
|
||||
iter.SetToEnd();
|
||||
iter.Prev();
|
||||
if (iter.item().NeedsAnonFlexItem(aState)) {
|
||||
if (iter.item().NeedsAnonFlexOrGridItem(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");
|
||||
// Situation #3 is an anonymous flex or grid item that's getting new children
|
||||
// who don't want to be wrapped.
|
||||
if (IsAnonymousFlexOrGridItem(aFrame)) {
|
||||
AssertAnonymousFlexOrGridItemParent(aFrame, aFrame->GetParent());
|
||||
|
||||
// We need to push a null float containing block to be sure that
|
||||
// "NeedsAnonFlexItem" will know we're not honoring floats for this
|
||||
// "NeedsAnonFlexOrGridItem" 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.
|
||||
// its "GetGeometricParent" call to return the correct result.)
|
||||
// We're not honoring floats on this content because it has the
|
||||
// _flex/grid container_ as its parent in the content tree.
|
||||
nsFrameConstructorSaveState floatSaveState;
|
||||
aState.PushFloatContainingBlock(nullptr, 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)) {
|
||||
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState)) {
|
||||
// We hit something that _doesn't_ need an anonymous flex item!
|
||||
// Rebuild the flex container to bust it out.
|
||||
RecreateFramesForContent(flexContainerFrame->GetContent(), true);
|
||||
nsIFrame* containerFrame = aFrame->GetParent();
|
||||
RecreateFramesForContent(containerFrame->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!
|
||||
// an anonymous flex or grid item. That's where it's already going - good!
|
||||
}
|
||||
|
||||
// Situation #4 is a case when table pseudo-frames don't work out right
|
||||
@ -11239,7 +11260,7 @@ Iterator::SkipItemsWantingParentType(ParentType aParentType)
|
||||
|
||||
bool
|
||||
nsCSSFrameConstructor::FrameConstructionItem::
|
||||
NeedsAnonFlexItem(const nsFrameConstructorState& aState)
|
||||
NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState)
|
||||
{
|
||||
if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
|
||||
// This will be an inline non-replaced box.
|
||||
@ -11260,11 +11281,11 @@ nsCSSFrameConstructor::FrameConstructionItem::
|
||||
|
||||
inline bool
|
||||
nsCSSFrameConstructor::FrameConstructionItemList::
|
||||
Iterator::SkipItemsThatNeedAnonFlexItem(
|
||||
Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
|
||||
const nsFrameConstructorState& aState)
|
||||
{
|
||||
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
|
||||
while (item().NeedsAnonFlexItem(aState)) {
|
||||
while (item().NeedsAnonFlexOrGridItem(aState)) {
|
||||
Next();
|
||||
if (IsDone()) {
|
||||
return true;
|
||||
@ -11275,11 +11296,11 @@ Iterator::SkipItemsThatNeedAnonFlexItem(
|
||||
|
||||
inline bool
|
||||
nsCSSFrameConstructor::FrameConstructionItemList::
|
||||
Iterator::SkipItemsThatDontNeedAnonFlexItem(
|
||||
Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
|
||||
const nsFrameConstructorState& aState)
|
||||
{
|
||||
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
|
||||
while (!(item().NeedsAnonFlexItem(aState))) {
|
||||
while (!(item().NeedsAnonFlexOrGridItem(aState))) {
|
||||
Next();
|
||||
if (IsDone()) {
|
||||
return true;
|
||||
|
@ -791,13 +791,13 @@ private:
|
||||
// Skip over non-replaced inline frames and positioned frames.
|
||||
// Return whether the iterator is done after doing that.
|
||||
// The iterator must not be done when this is called.
|
||||
inline bool SkipItemsThatNeedAnonFlexItem(
|
||||
inline bool SkipItemsThatNeedAnonFlexOrGridItem(
|
||||
const nsFrameConstructorState& aState);
|
||||
|
||||
// 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 SkipItemsThatDontNeedAnonFlexItem(
|
||||
inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
|
||||
const nsFrameConstructorState& aState);
|
||||
|
||||
// Skip over whitespace. Return whether the iterator is done after doing
|
||||
@ -928,9 +928,9 @@ private:
|
||||
return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
|
||||
}
|
||||
|
||||
// Indicates whether (when in a flexbox container) this item needs to be
|
||||
// wrapped in an anonymous block.
|
||||
bool NeedsAnonFlexItem(const nsFrameConstructorState& aState);
|
||||
// Indicates whether (when in a flex or grid container) this item needs
|
||||
// to be wrapped in an anonymous block.
|
||||
bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState);
|
||||
|
||||
// Don't call this unless the frametree really depends on the answer!
|
||||
// Especially so for generated content, where we don't want to reframe
|
||||
@ -1020,14 +1020,15 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to create the anonymous flex items that we need.
|
||||
* If aParentFrame is not a nsFlexContainerFrame then this method is a NOP.
|
||||
* Function to create the anonymous flex or grid items that we need.
|
||||
* If aParentFrame is not a nsFlexContainerFrame or nsGridContainerFrame then
|
||||
* this method is a NOP.
|
||||
* @param aItems the child frame construction items before pseudo creation
|
||||
* @param aParentFrame the parent frame
|
||||
*/
|
||||
void CreateNeededAnonFlexItems(nsFrameConstructorState& aState,
|
||||
FrameConstructionItemList& aItems,
|
||||
nsIFrame* aParentFrame);
|
||||
void CreateNeededAnonFlexOrGridItems(nsFrameConstructorState& aState,
|
||||
FrameConstructionItemList& aItems,
|
||||
nsIFrame* aParentFrame);
|
||||
|
||||
/**
|
||||
* Function to create the table pseudo items we need.
|
||||
|
Loading…
Reference in New Issue
Block a user