summaryrefslogtreecommitdiffstats
path: root/layout/base
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base')
-rw-r--r--layout/base/nsCSSFrameConstructor.cpp217
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.