diff options
Diffstat (limited to 'layout/base')
-rw-r--r-- | layout/base/nsCSSFrameConstructor.cpp | 217 |
1 files changed, 70 insertions, 147 deletions
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 37d1a2cff..f69ffe603 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -6324,131 +6324,24 @@ nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame) } /** - * This function will check whether aContainer has :after generated content. - * If so, appending to it should actually insert. The return value is the - * parent to use for newly-appended content. *aAfterFrame points to the :after - * frame before which appended content should go, if there is one. - */ -static nsContainerFrame* -AdjustAppendParentForAfterContent(nsFrameManager* aFrameManager, - nsIContent* aContainer, - nsContainerFrame* aParentFrame, - nsIContent* aChild, - nsIFrame** aAfterFrame) -{ - // If the parent frame has any pseudo-elements or aContainer is a - // display:contents node then we need to walk through the child - // frames to find the first one that is either a ::after frame for an - // ancestor of aChild or a frame that is for a node later in the - // document than aChild and return that in aAfterFrame. - nsIFrame* afterBeforeOwnerFrame = - nsLayoutUtils::FirstContinuationOrIBSplitSibling(aParentFrame); - if (afterBeforeOwnerFrame->GetProperty(nsIFrame::GenConProperty()) || - nsLayoutUtils::HasPseudoStyle(aContainer, aParentFrame->StyleContext(), - CSSPseudoElementType::after, - aParentFrame->PresContext()) || - aFrameManager->GetDisplayContentsStyleFor(aContainer)) { - nsIFrame* afterFrame = nullptr; - nsContainerFrame* parent = - static_cast<nsContainerFrame*>(aParentFrame->LastContinuation()); - bool done = false; - while (!done && parent) { - // Ensure that all normal flow children are on the principal child list. - parent->DrainSelfOverflowList(); - - nsIFrame* child = parent->GetChildList(nsIFrame::kPrincipalList).LastChild(); - if (child && child->IsPseudoFrame(aContainer) && - !child->IsGeneratedContentFrame()) { - // Drill down into non-generated pseudo frames of aContainer. - nsContainerFrame* childAsContainer = do_QueryFrame(child); - if (childAsContainer) { - parent = nsLayoutUtils::LastContinuationWithChild(childAsContainer); - continue; - } - } - - for (; child; child = child->GetPrevSibling()) { - nsIContent* c = child->GetContent(); - if (child->IsGeneratedContentFrame()) { - nsIContent* p = c->GetParent(); - if (c->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter) { - if (!nsContentUtils::ContentIsDescendantOf(aChild, p) && - p != aContainer && - nsContentUtils::PositionIsBefore(p, aChild)) { - // ::after generated content for content earlier in the doc and not - // for an ancestor. "p != aContainer" may seem redundant but it - // checks if the ::after belongs to the XBL insertion point we're - // inserting aChild into (in which case ContentIsDescendantOf is - // false even though p == aContainer). - // See layout/reftests/bugs/482592-1a.xhtml for an example of that. - done = true; - break; - } - } else if (nsContentUtils::PositionIsBefore(p, aChild)) { - // Non-::after generated content for content earlier in the doc. - done = true; - break; - } - } else if (nsContentUtils::PositionIsBefore(c, aChild)) { - // Content is before aChild. - done = true; - break; - } - afterFrame = child; - } - - parent = static_cast<nsContainerFrame*>(parent->GetPrevContinuation()); - } - if (afterFrame) { - *aAfterFrame = afterFrame; - return afterFrame->GetParent(); - } - } - - *aAfterFrame = nullptr; - - if (IsFramePartOfIBSplit(aParentFrame)) { - // We might be in a situation where the last part of the {ib} split was - // empty. Since we have no ::after pseudo-element, we do in fact want to be - // appending to that last part, so advance to it if needed. Note that here - // aParentFrame is the result of a GetLastIBSplitSibling call, so must be - // either the last or next to last ib-split sibling. - nsContainerFrame* trailingInline = GetIBSplitSibling(aParentFrame); - if (trailingInline) { - aParentFrame = trailingInline; - } - - // Always make sure to look at the last continuation of the frame - // for the {ib} case, even if that continuation is empty. We - // don't do this for the non-ib-split-frame case, since in the - // other cases appending to the last nonempty continuation is fine - // and in fact not doing that can confuse code that doesn't know - // to pull kids from continuations other than its next one. - aParentFrame = - static_cast<nsContainerFrame*>(aParentFrame->LastContinuation()); - } - - return aParentFrame; -} - -/** * This function will get the previous sibling to use for an append operation. - * it takes a parent frame (must not be null) and its :after frame (may be - * null). + * + * It takes a parent frame (must not be null) and the next insertion sibling, if + * the parent content is display: contents or has ::after content (may be null). */ static nsIFrame* -FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame) +FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aNextSibling) { - if (aAfterFrame) { - NS_ASSERTION(aAfterFrame->GetParent() == aParentFrame, "Wrong parent"); - NS_ASSERTION(aAfterFrame->GetPrevSibling() || - aParentFrame->PrincipalChildList().FirstChild() == aAfterFrame, - ":after frame must be on the principal child list here"); - return aAfterFrame->GetPrevSibling(); - } - aParentFrame->DrainSelfOverflowList(); + if (aNextSibling) { + MOZ_ASSERT(aNextSibling->GetParent() == aParentFrame, "Wrong parent"); + MOZ_ASSERT(aNextSibling->GetPrevSibling() || + aParentFrame->PrincipalChildList().FirstChild() == aNextSibling, + "next sibling must be on the principal child list here"); + return aNextSibling->GetPrevSibling(); + } + return aParentFrame->GetChildList(kPrincipalList).LastChild(); } @@ -7417,7 +7310,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, // If the frame we are manipulating is a ib-split frame (that is, one // that's been created as a result of a block-in-inline situation) then we // need to append to the last ib-split sibling, not to the frame itself. - bool parentIBSplit = IsFramePartOfIBSplit(parentFrame); + const bool parentIBSplit = IsFramePartOfIBSplit(parentFrame); if (parentIBSplit) { #ifdef DEBUG if (gNoisyContentUpdates) { @@ -7443,36 +7336,63 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, parentFrame->GetType() != nsGkAtoms::detailsFrame, "Parent frame should not be fieldset or details!"); - // Deal with possible :after generated content on the parent - nsIFrame* parentAfterFrame; - nsContainerFrame* preAdjustedParentFrame = parentFrame; - parentFrame = - ::AdjustAppendParentForAfterContent(this, insertion.mContainer, parentFrame, - aFirstNewContent, &parentAfterFrame); + // Deal with possible :after generated content on the parent, or display: + // contents. + nsIFrame* nextSibling = nullptr; + if (GetDisplayContentsStyleFor(insertion.mContainer) || + nsLayoutUtils::GetAfterFrame(insertion.mContainer)) { + FlattenedChildIterator iter(insertion.mContainer); + iter.Seek(insertion.mContainer->GetLastChild()); + StyleDisplay unused = UNSET_DISPLAY; + nextSibling = FindNextSibling(iter, unused); + } - // See if the containing block has :first-letter style applied. - bool haveFirstLetterStyle = false, haveFirstLineStyle = false; - nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame); - if (containingBlock) { - haveFirstLetterStyle = HasFirstLetterStyle(containingBlock); - haveFirstLineStyle = - ShouldHaveFirstLineStyle(containingBlock->GetContent(), - containingBlock->StyleContext()); + if (nextSibling) { + parentFrame = nextSibling->GetParent()->GetContentInsertionFrame(); + } else if (parentIBSplit) { + // We might be in a situation where the last part of the {ib} split was + // empty. Since we have no ::after pseudo-element, we do in fact want to be + // appending to that last part, so advance to it if needed. Note that here + // aParentFrame is the result of a GetLastIBSplitSibling call, so must be + // either the last or next to last ib-split sibling. + if (nsContainerFrame* trailingInline = GetIBSplitSibling(parentFrame)) { + parentFrame = trailingInline; + } + + // Always make sure to look at the last continuation of the frame + // for the {ib} case, even if that continuation is empty. We + // don't do this for the non-ib-split-frame case, since in the + // other cases appending to the last nonempty continuation is fine + // and in fact not doing that can confuse code that doesn't know + // to pull kids from continuations other than its next one. + parentFrame = + static_cast<nsContainerFrame*>(parentFrame->LastContinuation()); } + nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame); + + // See if the containing block has :first-letter style applied. + const bool haveFirstLetterStyle = + containingBlock && HasFirstLetterStyle(containingBlock); + + const bool haveFirstLineStyle = + containingBlock && + ShouldHaveFirstLineStyle(containingBlock->GetContent(), + containingBlock->StyleContext()); + if (haveFirstLetterStyle) { - nsWeakFrame wf(parentAfterFrame); + nsWeakFrame wf(nextSibling); // Before we get going, remove the current letter frames RemoveLetterFrames(mPresShell, containingBlock); - if (parentAfterFrame && !wf) { - // Ouch, parentAfterFrame was a letter frame and we just deleted it! - // Retry AdjustAppendParentForAfterContent; fortunately this is rare. - parentFrame = - ::AdjustAppendParentForAfterContent(this, insertion.mContainer, - preAdjustedParentFrame, - aFirstNewContent, &parentAfterFrame); - if (parentFrame != preAdjustedParentFrame) { + // Reget nextSibling, since we may have killed it. + if (nextSibling && !wf) { + FlattenedChildIterator iter(insertion.mContainer); + iter.Seek(insertion.mContainer->GetLastChild()); + StyleDisplay unused = UNSET_DISPLAY; + nextSibling = FindNextSibling(iter, unused); + if (nextSibling) { + parentFrame = nextSibling->GetParent()->GetContentInsertionFrame(); containingBlock = GetFloatContainingBlock(parentFrame); } } @@ -7488,7 +7408,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, nsIAtom* frameType = parentFrame->GetType(); FlattenedChildIterator iter(aContainer); - bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild()); + const bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild(); FrameConstructionItemList items; if (aFirstNewContent->GetPreviousSibling() && GetParentType(frameType) == eTypeBlock && @@ -7513,7 +7433,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, AddFrameConstructionItems(state, child, false, insertion, items); } - nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, parentAfterFrame); + nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, nextSibling); // Perform special check for diddling around with the frames in // a ib-split inline frame. @@ -7536,8 +7456,11 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, !prevSibling->IsInlineOutside() || prevSibling->GetType() == nsGkAtoms::brFrame); // :after content can't be <br> so no need to check it - items.SetLineBoundaryAtEnd(!parentAfterFrame || - !parentAfterFrame->IsInlineOutside()); + // + // FIXME(emilio): A display: contents sibling could! Write a test-case and + // fix. + items.SetLineBoundaryAtEnd( + !nextSibling || !nextSibling->IsInlineOutside()); } // To suppress whitespace-only text frames, we have to verify that // our container's DOM child list matches its flattened tree child list. |