--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -6468,140 +6468,33 @@ nsCSSFrameConstructor::GetFloatContainin
}
// If we didn't find a containing block, then there just isn't
// one.... return null
return nullptr;
}
/**
- * 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 may have an ::after pseudo or aContainer is a
- // display:contents node or aContainer have display:contents children
- // 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.
- if (nsLayoutUtils::HasPseudoStyle(aContainer, aParentFrame->StyleContext(),
- CSSPseudoElementType::after,
- aParentFrame->PresContext()) ||
- aFrameManager->GetDisplayContentsStyleFor(aContainer) ||
- aFrameManager->GetAllRegisteredDisplayContentsStylesIn(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)
-{
- 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();
- }
-
+FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
+{
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();
}
/**
* This function will get the next sibling for a frame insert operation given
* the parent and previous sibling. aPrevSibling may be null.
*/
static nsIFrame*
@@ -7634,17 +7527,17 @@ nsCSSFrameConstructor::ContentAppended(n
RecreateFramesForContent(parentFrame->GetContent(), aInsertionKind);
LAYOUT_PHASE_TEMP_REENTER();
return;
}
// 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) {
printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
nsFrame::ListTag(stdout, parentFrame);
printf(" is ib-split\n");
}
#endif
@@ -7659,46 +7552,76 @@ nsCSSFrameConstructor::ContentAppended(n
// before the AdjustAppendParentForAfterContent call.
parentFrame = nsLayoutUtils::LastContinuationWithChild(parentFrame);
// We should never get here with fieldsets or details, since they have
// multiple insertion points.
MOZ_ASSERT(!parentFrame->IsFieldSetFrame() && !parentFrame->IsDetailsFrame(),
"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);
+ }
+
+ 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.
- bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
- nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
- if (containingBlock) {
- haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
- haveFirstLineStyle =
- ShouldHaveFirstLineStyle(containingBlock->GetContent(),
- containingBlock->StyleContext());
- }
+ const bool haveFirstLetterStyle =
+ containingBlock && HasFirstLetterStyle(containingBlock);
+
+ const bool haveFirstLineStyle =
+ containingBlock &&
+ ShouldHaveFirstLineStyle(containingBlock->GetContent(),
+ containingBlock->StyleContext());
if (haveFirstLetterStyle) {
- AutoWeakFrame wf(parentAfterFrame);
+ AutoWeakFrame 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.
+ //
+ // FIXME(emilio): This kinda sucks! :(
+ 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);
}
}
}
// Create some new frames
//
// We use the provided tree match context, or create a new one on the fly
@@ -7714,17 +7637,18 @@ nsCSSFrameConstructor::ContentAppended(n
matchContext.ptrOr(aProvidedTreeMatchContext),
GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
GetAbsoluteContainingBlock(parentFrame, ABS_POS),
containingBlock);
LayoutFrameType frameType = parentFrame->Type();
FlattenedChildIterator iter(aContainer);
- bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
+ const bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
+
AutoFrameConstructionItemList items(this);
if (aFirstNewContent->GetPreviousSibling() &&
GetParentType(frameType) == eTypeBlock &&
haveNoXBLChildren) {
// If there's a text node in the normal content list just before the new
// items, and it has no frame, make a frame construction item for it. If it
// doesn't need a frame, ConstructFramesFromItemList below won't give it
// one. No need to do all this if our parent type is not block, though,
@@ -7739,17 +7663,17 @@ nsCSSFrameConstructor::ContentAppended(n
aFirstNewContent->GetPreviousSibling(), items);
}
for (nsIContent* child = aFirstNewContent;
child;
child = child->GetNextSibling()) {
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.
// If we're appending before :after content, then we're not really
// appending, so let WipeContainingBlock know that.
LAYOUT_PHASE_TEMP_EXIT();
if (WipeContainingBlock(state, containingBlock, parentFrame, items,
true, prevSibling)) {
@@ -7762,18 +7686,21 @@ nsCSSFrameConstructor::ContentAppended(n
// where frames can be moved around, determine if the list is for the
// start or end of the block.
if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
!haveFirstLineStyle && !parentIBSplit) {
items.SetLineBoundaryAtStart(!prevSibling ||
!prevSibling->IsInlineOutside() ||
prevSibling->IsBrFrame());
// :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.
items.SetParentHasNoXBLChildren(haveNoXBLChildren);
nsFrameItems frameItems;
ConstructFramesFromItemList(state, items, parentFrame,
ParentIsWrapperAnonBox(parentFrame),