diff options
Diffstat (limited to 'layout/base/nsCSSFrameConstructor.cpp')
-rw-r--r-- | layout/base/nsCSSFrameConstructor.cpp | 1576 |
1 files changed, 676 insertions, 900 deletions
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 37cd3e45ee..fc458b5ebf 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -43,6 +43,7 @@ #include "nsContainerFrame.h" #include "nsNameSpaceManager.h" #include "nsIComboboxControlFrame.h" +#include "nsComboboxControlFrame.h" #include "nsIListControlFrame.h" #include "nsIDOMCharacterData.h" #include "nsPlaceholderFrame.h" @@ -691,10 +692,9 @@ nsAbsoluteItems::nsAbsoluteItems(nsContainerFrame* aContainingBlock) void nsAbsoluteItems::AddChild(nsIFrame* aChild) { - NS_ASSERTION(aChild->PresContext()->FrameManager()-> - GetPlaceholderFrameFor(aChild), - "Child without placeholder being added to nsAbsoluteItems?"); aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW); + NS_ASSERTION(aChild->GetPlaceholderFrame(), + "Child without placeholder being added to nsAbsoluteItems?"); nsFrameItems::AddChild(aChild); } @@ -1831,11 +1831,7 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat aPseudoElement == CSSPseudoElementType::after, "unexpected aPseudoElement"); - // XXXbz is this ever true? - if (!aParentContent->IsElement()) { - NS_ERROR("Bogus generated content parent"); - return; - } + MOZ_ASSERT(aParentContent->IsElement()); StyleSetHandle styleSet = mPresShell->StyleSet(); @@ -1863,7 +1859,15 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget()); if (NS_FAILED(rv)) return; + + // Cleared when the pseudo is unbound from the tree, so no need to store a + // strong reference, nor a destructor. + nsIAtom* property = isBefore + ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty; + aParentContent->SetProperty(property, container.get()); + container->SetIsNativeAnonymousRoot(); + container->SetPseudoElementType(aPseudoElement); // If the parent is in a shadow tree, make sure we don't // bind with a document because shadow roots and its descendants @@ -3027,14 +3031,12 @@ nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell, placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow); - // The placeholder frame has a pointer back to the out-of-flow frame + // Associate the placeholder/out-of-flow with each other. placeholderFrame->SetOutOfFlowFrame(aFrame); + aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame); aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW); - // Add mapping from absolutely positioned frame to its placeholder frame - aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame); - return placeholderFrame; } @@ -3075,7 +3077,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState, // The drop-down list's frame is created explicitly. The combobox frame shares its content // with the drop-down list. nsFrameState flags = NS_BLOCK_FLOAT_MGR; - nsContainerFrame* comboboxFrame = + nsComboboxControlFrame* comboboxFrame = NS_NewComboboxControlFrame(mPresShell, styleContext, flags); // Save the history state so we don't restore during construction @@ -3090,10 +3092,6 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState, aState.AddChild(comboboxFrame, aFrameItems, content, styleContext, aParentFrame); - nsIComboboxControlFrame* comboBox = do_QueryFrame(comboboxFrame); - NS_ASSERTION(comboBox, "NS_NewComboboxControlFrame returned frame that " - "doesn't implement nsIComboboxControlFrame"); - // Resolve pseudo element style for the dropdown list RefPtr<nsStyleContext> listStyle; listStyle = mPresShell->StyleSet()-> @@ -3108,7 +3106,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState, listControlFrame->SetComboboxFrame(comboboxFrame); } // Notify combobox that it should use the listbox as it's popup - comboBox->SetDropDown(listFrame); + comboboxFrame->SetDropDown(listFrame); NS_ASSERTION(!listFrame->IsAbsPosContainingBlock(), "Ended up with positioned dropdown list somehow."); @@ -3129,10 +3127,29 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState, // Create display and button frames from the combobox's anonymous content. // The anonymous content is appended to existing anonymous content for this // element (the scrollbars). - nsFrameItems childItems; - CreateAnonymousFrames(aState, content, comboboxFrame, - aItem.mPendingBinding, childItems); + + // nsComboboxControlFrame needs special frame creation behavior for its first + // piece of anonymous content, which means that we can't take the normal + // ProcessChildren path. + AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems; + DebugOnly<nsresult> rv = GetAnonymousContent(content, comboboxFrame, newAnonymousItems); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + MOZ_ASSERT(newAnonymousItems.Length() == 2); + + // Manually create a frame for the special NAC. + MOZ_ASSERT(newAnonymousItems[0].mContent == comboboxFrame->GetDisplayNode()); + newAnonymousItems.RemoveElementAt(0); + nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode(); + MOZ_ASSERT(customFrame); + customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT); + childItems.AddChild(customFrame); + + // The other piece of NAC can take the normal path. + FrameConstructionItemList fcItems; + AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems, + fcItems); + ConstructFramesFromItemList(aState, fcItems, comboboxFrame, childItems); comboboxFrame->SetInitialChildList(kPrincipalList, childItems); @@ -3172,7 +3189,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState, * But the select tag should really be fixed to use GFX scrollbars that can * be create with BuildScrollFrame. */ -nsresult +void nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState, nsContainerFrame* scrollFrame, nsContainerFrame* scrolledFrame, @@ -3218,7 +3235,6 @@ nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState, // Set the scrolled frame's initial child lists scrolledFrame->SetInitialChildList(kPrincipalList, childItems); - return NS_OK; } nsIFrame* @@ -3805,7 +3821,7 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt // AutoDisplayContentsAncestorPusher above.) TreeMatchContext::AutoAncestorPusher insertionPointPusher(aState.mTreeMatchContext); - if (adcp.IsEmpty() && parent && nsContentUtils::IsContentInsertionPoint(parent)) { + if (adcp.IsEmpty() && parent && parent->IsActiveChildrenElement()) { if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { insertionPointPusher.PushAncestorAndStyleScope(parent); } else { @@ -4094,70 +4110,6 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt } } -// after the node has been constructed and initialized create any -// anonymous content a node needs. -nsresult -nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState, - nsIContent* aParent, - nsContainerFrame* aParentFrame, - PendingBinding* aPendingBinding, - nsFrameItems& aChildItems) -{ - AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> newAnonymousItems; - nsresult rv = GetAnonymousContent(aParent, aParentFrame, newAnonymousItems); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t count = newAnonymousItems.Length(); - if (count == 0) { - return NS_OK; - } - - nsFrameConstructorState::PendingBindingAutoPusher pusher(aState, - aPendingBinding); - TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext); - if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { - ancestorPusher.PushAncestorAndStyleScope(aParent->AsElement()); - } else { - ancestorPusher.PushStyleScope(aParent->AsElement()); - } - - nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame); - NS_ASSERTION(creator, - "How can that happen if we have nodes to construct frames for?"); - - InsertionPoint insertion(aParentFrame, aParent); - for (uint32_t i=0; i < count; i++) { - nsIContent* content = newAnonymousItems[i].mContent; - NS_ASSERTION(content, "null anonymous content?"); - NS_ASSERTION(!newAnonymousItems[i].mStyleContext, "Unexpected style context"); - NS_ASSERTION(newAnonymousItems[i].mChildren.IsEmpty(), - "This method is not currently used with frames that implement " - "nsIAnonymousContentCreator::CreateAnonymousContent to " - "output a list where the items have their own children"); - - nsIFrame* newFrame = creator->CreateFrameFor(content); - if (newFrame) { - NS_ASSERTION(content->GetPrimaryFrame(), - "Content must have a primary frame now"); - newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT); - aChildItems.AddChild(newFrame); - } else { - FrameConstructionItemList items; - { - // Skip parent display based style-fixup during our - // AddFrameConstructionItems() call: - TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper - parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext); - - AddFrameConstructionItems(aState, content, true, insertion, items); - } - ConstructFramesFromItemList(aState, items, aParentFrame, aChildItems); - } - } - - return NS_OK; -} - static void SetFlagsOnSubtree(nsIContent *aNode, uintptr_t aFlagsToSet) { @@ -4209,6 +4161,13 @@ ConnectAnonymousTreeDescendants(nsIContent* aParent, } } +void SetNativeAnonymousBitOnDescendants(nsIContent *aRoot) +{ + for (nsIContent* curr = aRoot; curr; curr = curr->GetNextNode(aRoot)) { + curr->SetFlags(NODE_IS_NATIVE_ANONYMOUS); + } +} + nsresult nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent, nsIFrame* aParentFrame, @@ -4230,16 +4189,32 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent, nsIContent* content = aContent[i].mContent; NS_ASSERTION(content, "null anonymous content?"); - // least-surprise CSS binding until we do the SVG specified - // cascading rules for <svg:use> - bug 265894 - if (aParentFrame->GetType() == nsGkAtoms::svgUseFrame) { + ConnectAnonymousTreeDescendants(content, aContent[i].mChildren); + + nsIAtom* parentFrameType = aParentFrame->GetType(); + if (parentFrameType == nsGkAtoms::svgUseFrame) { + // least-surprise CSS binding until we do the SVG specified + // cascading rules for <svg:use> - bug 265894 content->SetFlags(NODE_IS_ANONYMOUS_ROOT); } else { content->SetIsNativeAnonymousRoot(); + // Don't mark descendants of the custom content container + // as native anonymous. When canvas custom content is initially + // created and appended to the custom content container, in + // nsIDocument::InsertAnonymousContent, it is not considered native + // anonymous content. But if we end up reframing the root element, + // we will re-create the nsCanvasFrame, and we would end up in here, + // marking it as NAC. Existing uses of canvas custom content would + // break if it becomes NAC (since each element starts inheriting + // styles from its closest non-NAC ancestor, rather than from its + // parent). + if (!(parentFrameType == nsGkAtoms::canvasFrame && + content == static_cast<nsCanvasFrame*>(aParentFrame) + ->GetCustomContentContainer())) { + SetNativeAnonymousBitOnDescendants(content); + } } - ConnectAnonymousTreeDescendants(content, aContent[i].mChildren); - bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE); // If the parent is in a shadow tree, make sure we don't @@ -4264,11 +4239,9 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent, } if (ServoStyleSet* styleSet = mPresShell->StyleSet()->GetAsServo()) { - // Eagerly compute styles for the anonymous content tree, but only do so - // if the content doesn't have an explicit style context (if it does, we - // don't need the normal computed values). + // Eagerly compute styles for the anonymous content tree. for (auto& info : aContent) { - if (!info.mStyleContext) { + if (info.mContent->IsElement()) { styleSet->StyleNewSubtree(info.mContent); } } @@ -4574,11 +4547,25 @@ nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState, // if there are any anonymous children for the scroll frame, create // frames for them. - // Pass a null pending binding: we don't care how constructors for any of - // this anonymous content order with anything else. It's never been - // consistent anyway. - CreateAnonymousFrames(aState, aContent, gfxScrollFrame, nullptr, - anonymousItems); + // + // We can't take the normal ProcessChildren path, because the NAC needs to + // be parented to the scrollframe, and everything else needs to be parented + // to the scrolledframe. + AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC; + DebugOnly<nsresult> rv = GetAnonymousContent(aContent, gfxScrollFrame, scrollNAC); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + if (scrollNAC.Length() > 0) { + TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext); + if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { + ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement()); + } else { + ancestorPusher.PushStyleScope(aContent->AsElement()); + } + + FrameConstructionItemList items; + AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items); + ConstructFramesFromItemList(aState, items, gfxScrollFrame, anonymousItems); + } aNewFrame = gfxScrollFrame; @@ -5033,22 +5020,46 @@ nsCSSFrameConstructor::ResolveStyleContext(const InsertionPoint& aInsertion, already_AddRefed<nsStyleContext> nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext, nsIContent* aContent, - nsFrameConstructorState* aState) + nsFrameConstructorState* aState, + Element* aOriginatingElementOrNull) { StyleSetHandle styleSet = mPresShell->StyleSet(); aContent->OwnerDoc()->FlushPendingLinkUpdates(); RefPtr<nsStyleContext> result; if (aContent->IsElement()) { - if (aState) { - result = styleSet->ResolveStyleFor(aContent->AsElement(), - aParentStyleContext, - aState->mTreeMatchContext); + auto pseudoType = aContent->AsElement()->GetPseudoElementType(); + if (pseudoType == CSSPseudoElementType::NotPseudo) { + MOZ_ASSERT(!aOriginatingElementOrNull); + if (aState) { + result = styleSet->ResolveStyleFor(aContent->AsElement(), + aParentStyleContext, + aState->mTreeMatchContext); + } else { + result = styleSet->ResolveStyleFor(aContent->AsElement(), + aParentStyleContext); + } } else { - result = styleSet->ResolveStyleFor(aContent->AsElement(), - aParentStyleContext); + MOZ_ASSERT(aContent->IsInNativeAnonymousSubtree()); + if (!aOriginatingElementOrNull) { + // For pseudo-implementing NAC created by JS using the ChromeOnly + // document.createElement(..., { pseudo: ... }) API, we find the + // originating element by lookup the tree until we find a non-NAC + // ancestor. (These are the correct semantics for C++-generated pseudo- + // implementing NAC as well, but for those cases we already have a + // correct originating element passed in.) + MOZ_ASSERT(nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)); + aOriginatingElementOrNull = + nsContentUtils::GetClosestNonNativeAnonymousAncestor(aContent->AsElement()); + } + MOZ_ASSERT(aOriginatingElementOrNull); + result = styleSet->ResolvePseudoElementStyle(aOriginatingElementOrNull, + pseudoType, + aParentStyleContext, + aContent->AsElement()); } } else { + MOZ_ASSERT(!aOriginatingElementOrNull); NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT), "shouldn't waste time creating style contexts for " "comments and processing instructions"); @@ -6065,9 +6076,10 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState static void AddGenConPseudoToFrame(nsIFrame* aOwnerFrame, nsIContent* aContent) { - NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aOwnerFrame), - "property should only be set on first continuation/ib-sibling"); + // FIXME(emilio): Remove this property, and use the frame of the generated + // content itself to tear the content down? It should be quite simpler. + aOwnerFrame = nsLayoutUtils::FirstContinuationOrIBSplitSibling(aOwnerFrame); nsIFrame::ContentArray* value = aOwnerFrame->GetProperty(nsIFrame::GenConProperty()); if (!value) { @@ -6198,16 +6210,16 @@ IsRootBoxFrame(nsIFrame *aFrame) return (aFrame->GetType() == nsGkAtoms::rootFrame); } -nsresult +void nsCSSFrameConstructor::ReconstructDocElementHierarchy() { Element* rootElement = mDocument->GetRootElement(); if (!rootElement) { /* nothing to do */ - return NS_OK; + return; } - return RecreateFramesForContent(rootElement, false, REMOVE_FOR_RECONSTRUCTION, - nullptr); + RecreateFramesForContent(rootElement, InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); } nsContainerFrame* @@ -6312,129 +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. - if (aParentFrame->GetGenConPseudos() || - 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(); } @@ -6457,7 +6364,7 @@ GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling) * appending flowed frames to a parent's principal child list. It handles the * case where the parent is the trailing inline of an {ib} split. */ -nsresult +void nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aState, nsContainerFrame* aParentFrame, nsFrameItems& aFrameList, @@ -6542,13 +6449,11 @@ nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aStat return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings, aParentFrame, true); } - - return NS_OK; + return; } // Insert the frames after our aPrevSibling InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList); - return NS_OK; } #define UNSET_DISPLAY static_cast<StyleDisplay>(255) @@ -6650,111 +6555,147 @@ nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling, return true; } +// FIXME(emilio): If we ever kill IsValidSibling() we can simplify this quite a +// bit (no need to pass aTargetContent or aTargetContentDisplay, and the +// adjust() calls can be responsibility of the caller). +template<nsCSSFrameConstructor::SiblingDirection aDirection> nsIFrame* -nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent, - nsIContent* aTargetContent, - StyleDisplay& aTargetContentDisplay, - nsContainerFrame* aParentFrame, - bool aPrevSibling) -{ - nsIFrame* sibling = aContent->GetPrimaryFrame(); - if (!sibling && GetDisplayContentsStyleFor(aContent)) { - // A display:contents node - check if it has a ::before / ::after frame... - sibling = aPrevSibling ? - nsLayoutUtils::GetAfterFrameForContent(aParentFrame, aContent) : - nsLayoutUtils::GetBeforeFrameForContent(aParentFrame, aContent); - if (!sibling) { - // ... then recurse into children ... - const bool forward = !aPrevSibling; - FlattenedChildIterator iter(aContent, forward); - sibling = aPrevSibling ? - FindPreviousSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame) : - FindNextSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame); - } - if (!sibling) { - // ... then ::after / ::before on the opposite end. - sibling = aPrevSibling ? - nsLayoutUtils::GetBeforeFrameForContent(aParentFrame, aContent) : - nsLayoutUtils::GetAfterFrameForContent(aParentFrame, aContent); - } - if (!sibling) { - return nullptr; +nsCSSFrameConstructor::FindSiblingInternal( + FlattenedChildIterator aIter, + nsIContent* aTargetContent, + StyleDisplay& aTargetContentDisplay) +{ + auto adjust = [&](nsIFrame* aPotentialSiblingFrame) -> nsIFrame* { + return AdjustSiblingFrame( + aPotentialSiblingFrame, aTargetContent, aTargetContentDisplay, + aDirection); + }; + + auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* { + return aDirection == SiblingDirection::Forward + ? aIter.GetNextChild() : aIter.GetPreviousChild(); + }; + + auto getNearPseudo = [](const nsIContent* aContent) -> nsIFrame* { + return aDirection == SiblingDirection::Forward + ? nsLayoutUtils::GetBeforeFrame(aContent) + : nsLayoutUtils::GetAfterFrame(aContent); + }; + + auto getFarPseudo = [](const nsIContent* aContent) -> nsIFrame* { + return aDirection == SiblingDirection::Forward + ? nsLayoutUtils::GetAfterFrame(aContent) + : nsLayoutUtils::GetBeforeFrame(aContent); + }; + + while (nsIContent* sibling = nextDomSibling(aIter)) { + if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) { + // XXX the GetContent() == sibling check is needed due to bug 135040. + // Remove it once that's fixed. + if (primaryFrame->GetContent() == sibling) { + if (nsIFrame* frame = adjust(primaryFrame)) { + return frame; + } + } + } + + if (GetDisplayContentsStyleFor(sibling)) { + if (nsIFrame* frame = adjust(getNearPseudo(sibling))) { + return frame; + } + + const bool startFromBeginning = aDirection == SiblingDirection::Forward; + FlattenedChildIterator iter(sibling, startFromBeginning); + nsIFrame* sibling = FindSiblingInternal<aDirection>( + iter, aTargetContent, aTargetContentDisplay); + if (sibling) { + return sibling; + } } - } else if (!sibling || sibling->GetContent() != aContent) { - // XXX the GetContent() != aContent check is needed due to bug 135040. - // Remove it once that's fixed. - return nullptr; } - // If the frame is out-of-flow, GetPrimaryFrame() will have returned the - // out-of-flow frame; we want the placeholder. - if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - nsIFrame* placeholderFrame = GetPlaceholderFrameFor(sibling); - NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame"); - sibling = placeholderFrame; + return adjust(getFarPseudo(aIter.Parent())); +} + +nsIFrame* +nsCSSFrameConstructor::AdjustSiblingFrame( + nsIFrame* aSibling, + nsIContent* aTargetContent, + mozilla::StyleDisplay& aTargetContentDisplay, + SiblingDirection aDirection) +{ + if (!aSibling) { + return nullptr; } - // The frame we have now should never be a continuation - NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?"); + if (aSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { + aSibling = aSibling->GetPlaceholderFrame(); + MOZ_ASSERT(aSibling); + } - if (aPrevSibling) { - // The frame may be a ib-split frame (a split inline frame that - // contains a block). Get the last part of that split. - if (IsFramePartOfIBSplit(sibling)) { - sibling = GetLastIBSplitSibling(sibling, true); + MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?"); + if (aDirection == SiblingDirection::Backward) { + // The frame may be a ib-split frame (a split inline frame that contains a + // block). Get the last part of that split. + if (IsFramePartOfIBSplit(aSibling)) { + aSibling = GetLastIBSplitSibling(aSibling, true); } // The frame may have a continuation. If so, we want the last // non-overflow-container continuation as our previous sibling. - sibling = sibling->GetTailContinuation(); + aSibling = aSibling->GetTailContinuation(); } - if (aTargetContent && - !IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) { - sibling = nullptr; + if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) { + return nullptr; } - return sibling; + return aSibling; } nsIFrame* -nsCSSFrameConstructor::FindPreviousSibling(FlattenedChildIterator aIter, - nsIContent* aTargetContent, - StyleDisplay& aTargetContentDisplay, - nsContainerFrame* aParentFrame) +nsCSSFrameConstructor::FindPreviousSibling(const FlattenedChildIterator& aIter, + StyleDisplay& aTargetContentDisplay) { - // Note: not all content objects are associated with a frame (e.g., if it's - // `display: none') so keep looking until we find a previous frame. - while (nsIContent* sibling = aIter.GetPreviousChild()) { - MOZ_ASSERT(sibling != aTargetContent); - nsIFrame* prevSibling = - FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay, - aParentFrame, true); - if (prevSibling) { - // Found a previous sibling, we're done! - return prevSibling; - } - } + return FindSibling<SiblingDirection::Backward>(aIter, aTargetContentDisplay); +} - return nullptr; +nsIFrame* +nsCSSFrameConstructor::FindNextSibling(const FlattenedChildIterator& aIter, + StyleDisplay& aTargetContentDisplay) +{ + return FindSibling<SiblingDirection::Forward>(aIter, aTargetContentDisplay); } +template<nsCSSFrameConstructor::SiblingDirection aDirection> nsIFrame* -nsCSSFrameConstructor::FindNextSibling(FlattenedChildIterator aIter, - nsIContent* aTargetContent, - StyleDisplay& aTargetContentDisplay, - nsContainerFrame* aParentFrame) +nsCSSFrameConstructor::FindSibling(const FlattenedChildIterator& aIter, + StyleDisplay& aTargetContentDisplay) { - while (nsIContent* sibling = aIter.GetNextChild()) { - MOZ_ASSERT(sibling != aTargetContent); - nsIFrame* nextSibling = - FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay, - aParentFrame, false); + nsIContent* targetContent = aIter.Get(); + nsIFrame* sibling = + FindSiblingInternal<aDirection>(aIter, targetContent, aTargetContentDisplay); + if (sibling) { + return sibling; + } + + // Our siblings (if any) do not have a frame to guide us. The frame for the + // target content should be inserted whereever a frame for the container would + // be inserted. This is needed when inserting into display: contents nodes. + const nsIContent* current = aIter.Parent(); + while (GetDisplayContentsStyleFor(current)) { + const nsIContent* parent = current->GetFlattenedTreeParent(); + MOZ_ASSERT(parent, "No display: contents on the root"); - if (nextSibling) { - // We found a next sibling, we're done! - return nextSibling; + FlattenedChildIterator iter(parent); + iter.Seek(current); + sibling = FindSiblingInternal<aDirection>( + iter, targetContent, aTargetContentDisplay); + if (sibling) { + return sibling; } + + current = parent; } return nullptr; @@ -6820,8 +6761,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion, // Note that FindPreviousSibling is passed the iterator by value, so that // the later usage of the iterator starts from the same place. StyleDisplay childDisplay = UNSET_DISPLAY; - nsIFrame* prevSibling = - FindPreviousSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame); + nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay); // Now, find the geometric parent so that we can handle // continuations properly. Use the prev sibling if we have it; @@ -6834,48 +6774,20 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion, iter.Seek(aEndSkipChild); iter.GetPreviousChild(); } - nsIFrame* nextSibling = - FindNextSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame); - if (GetDisplayContentsStyleFor(aInsertion->mContainer)) { - if (!nextSibling) { - // Our siblings (if any) does not have a frame to guide us. - // The frame for aChild should be inserted whereever a frame for - // the container would be inserted. This is needed when inserting - // into nested display:contents nodes. - nsIContent* child = aInsertion->mContainer; - nsIContent* parent = child->GetParent(); - aInsertion->mParentFrame = - ::GetAdjustedParentFrame(aInsertion->mParentFrame, - aInsertion->mParentFrame->GetType(), - parent); - InsertionPoint fakeInsertion(aInsertion->mParentFrame, parent); - nsIFrame* result = GetInsertionPrevSibling(&fakeInsertion, child, aIsAppend, - aIsRangeInsertSafe, nullptr, nullptr); - MOZ_ASSERT(aInsertion->mParentFrame->GetContent() == - fakeInsertion.mParentFrame->GetContent()); - // fakeInsertion.mParentFrame may now be a continuation of the frame - // we started with in the ctor above. - aInsertion->mParentFrame = fakeInsertion.mParentFrame; - return result; - } - - prevSibling = nextSibling->GetPrevSibling(); - } - - if (nextSibling) { + if (nsIFrame* nextSibling = FindNextSibling(iter, childDisplay)) { aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame(); } else { // No previous or next sibling, so treat this like an appended frame. *aIsAppend = true; if (IsFramePartOfIBSplit(aInsertion->mParentFrame)) { // Since we're appending, we'll walk to the last anonymous frame - // that was created for the broken inline frame. But don't walk - // to the trailing inline if it's empty; stop at the block. + // that was created for the broken inline frame. We can walk to the + // trailing inline, since we know this is a real append, and not an + // insert (that would've been handled by `FindNextSibling`). aInsertion->mParentFrame = - GetLastIBSplitSibling(aInsertion->mParentFrame, false); + GetLastIBSplitSibling(aInsertion->mParentFrame, true); } - // Get continuation that parents the last child. This MUST be done - // before the AdjustAppendParentForAfterContent call. + // Get continuation that parents the last child. aInsertion->mParentFrame = nsLayoutUtils::LastContinuationWithChild(aInsertion->mParentFrame); // Deal with fieldsets @@ -6883,12 +6795,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion, ::GetAdjustedParentFrame(aInsertion->mParentFrame, aInsertion->mParentFrame->GetType(), aChild); - nsIFrame* appendAfterFrame; - aInsertion->mParentFrame = - ::AdjustAppendParentForAfterContent(this, aInsertion->mContainer, - aInsertion->mParentFrame, - aChild, &appendAfterFrame); - prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, appendAfterFrame); + prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, nullptr); } } @@ -7004,7 +6911,8 @@ nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent, } NS_ASSERTION(!aContent->GetPrimaryFrame(), "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"); - ContentInserted(aParentContent, aContent, nullptr, false); + const bool allowLazyConstruction = true; + ContentInserted(aParentContent, aContent, nullptr, allowLazyConstruction); } // For inserts aChild should be valid, for appends it should be null. @@ -7014,11 +6922,8 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, nsIContent* aContainer, nsIContent* aChild) { - // XXXmats no lazy frames for display:contents direct descendants yet - // (Mozilla bug 979782). if (mPresShell->GetPresContext()->IsChrome() || !aContainer || - aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXULElement() || - GetDisplayContentsStyleFor(aContainer)) { + aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXULElement()) { return false; } @@ -7054,8 +6959,7 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, // hit a node with a leaf frame. // // Also, it's fine if one of the nodes without primary frame is a display: - // contents node except if it's the direct ancestor of the children we're - // recreating frames for. + // contents node. bool noPrimaryFrame = false; bool needsFrameBitSet = false; #endif @@ -7287,8 +7191,9 @@ nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame, cur = cur->GetNextSibling()) { if (IsSpecialFramesetChild(cur)) { // Just reframe the parent, since framesets are weird like that. - RecreateFramesForContent(aParentFrame->GetContent(), false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aParentFrame->GetContent(), + InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); return true; } } @@ -7296,7 +7201,7 @@ nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame, return false; } -nsresult +void nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, nsIContent* aFirstNewContent, bool aAllowLazyConstruction) @@ -7339,8 +7244,8 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, if (tag == nsGkAtoms::treechildren || tag == nsGkAtoms::treeitem || tag == nsGkAtoms::treerow) - return NS_OK; + return; } #endif // MOZ_XUL @@ -7353,21 +7258,21 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, //XXXsmaug This is super unefficient! nsIContent* bindingParent = aContainer->GetBindingParent(); LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(bindingParent, false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(bindingParent, InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } // See comment in ContentRangeInserted for why this is necessary. if (!GetContentInsertionFrameFor(aContainer) && !aContainer->IsActiveChildrenElement()) { - return NS_OK; + return; } if (aAllowLazyConstruction && MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) { - return NS_OK; + return; } LAYOUT_PHASE_TEMP_EXIT(); @@ -7377,13 +7282,13 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, nsContainerFrame*& parentFrame = insertion.mParentFrame; LAYOUT_PHASE_TEMP_REENTER(); if (!parentFrame) { - return NS_OK; + return; } LAYOUT_PHASE_TEMP_EXIT(); if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) { LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; + return; } LAYOUT_PHASE_TEMP_REENTER(); @@ -7391,21 +7296,22 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, // Nothing to do here; we shouldn't be constructing kids of leaves // Clear lazy bits so we don't try to construct again. ClearLazyBits(aFirstNewContent, nullptr); - return NS_OK; + return; } if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) { LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(parentFrame->GetContent(), + InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + 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) { @@ -7431,38 +7337,79 @@ 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; - 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); + } - // Create some new frames - nsFrameConstructorState state(mPresShell, - GetAbsoluteContainingBlock(parentFrame, FIXED_POS), - GetAbsoluteContainingBlock(parentFrame, ABS_POS), - GetFloatContainingBlock(parentFrame)); - state.mTreeMatchContext.InitAncestors(aContainer->AsElement()); + 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; + } - // See if the containing block has :first-letter style applied. - bool haveFirstLetterStyle = false, haveFirstLineStyle = false; - nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock; - if (containingBlock) { - haveFirstLetterStyle = HasFirstLetterStyle(containingBlock); - haveFirstLineStyle = - ShouldHaveFirstLineStyle(containingBlock->GetContent(), - containingBlock->StyleContext()); + // 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(nextSibling); // Before we get going, remove the current letter frames - RemoveLetterFrames(state.mPresShell, containingBlock); + RemoveLetterFrames(mPresShell, containingBlock); + + // 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); + } + } } + // Create some new frames + nsFrameConstructorState state(mPresShell, + GetAbsoluteContainingBlock(parentFrame, FIXED_POS), + GetAbsoluteContainingBlock(parentFrame, ABS_POS), + containingBlock); + state.mTreeMatchContext.InitAncestors(aContainer->AsElement()); + 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 && @@ -7487,7 +7434,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. @@ -7497,7 +7444,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, if (WipeContainingBlock(state, containingBlock, parentFrame, items, true, prevSibling)) { LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; + return; } LAYOUT_PHASE_TEMP_REENTER(); @@ -7510,8 +7457,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. @@ -7584,7 +7534,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, } #endif - return NS_OK; + return; } #ifdef MOZ_XUL @@ -7627,17 +7577,17 @@ bool NotifyListBoxBody(nsPresContext* aPresContext, } #endif // MOZ_XUL -nsresult +void nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, nsIContent* aChild, nsILayoutHistoryState* aFrameState, bool aAllowLazyConstruction) { - return ContentRangeInserted(aContainer, - aChild, - aChild->GetNextSibling(), - aFrameState, - aAllowLazyConstruction); + ContentRangeInserted(aContainer, + aChild, + aChild->GetNextSibling(), + aFrameState, + aAllowLazyConstruction); } // ContentRangeInserted handles creating frames for a range of nodes that @@ -7658,7 +7608,7 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, // in the caption list, while skipping any nodes in the range being inserted // (because when we treat the caption frames the other nodes have had their // frames constructed but not yet inserted into the frame tree). -nsresult +void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, nsIContent* aStartChild, nsIContent* aEndChild, @@ -7715,7 +7665,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, // The insert case in NotifyListBoxBody // doesn't use "old next sibling". aStartChild, nullptr, nullptr, CONTENT_INSERTED)) { - return NS_OK; + return; } } else { // We don't handle a range insert to a listbox parent, issue single @@ -7724,7 +7674,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, IssueSingleInsertNofications(aContainer, aStartChild, aEndChild, aAllowLazyConstruction); LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; + return; } } #endif // MOZ_XUL @@ -7739,7 +7689,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, if (aStartChild != docElement) { // Not the root element; just bail out - return NS_OK; + return; } NS_PRECONDITION(nullptr == mRootElementFrame, @@ -7776,7 +7726,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, } #endif - return NS_OK; + return; } if (aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE) && @@ -7789,10 +7739,10 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, //XXXsmaug This is super unefficient! nsIContent* bindingParent = aContainer->GetBindingParent(); LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(bindingParent, false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(bindingParent, InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } // Put 'parentFrame' inside a scope so we don't confuse it with @@ -7803,7 +7753,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, // a parent. While its uncommon to change the structure of the default content itself, a label, // for example, can be reframed by having its value attribute set or removed. if (!parentFrame && !aContainer->IsActiveChildrenElement()) { - return NS_OK; + return; } // Otherwise, we've got parent content. Find its frame. @@ -7812,7 +7762,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, if (aAllowLazyConstruction && MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) { - return NS_OK; + return; } } @@ -7832,7 +7782,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, } if (!insertion.mParentFrame) { - return NS_OK; + return; } bool isAppend, isRangeInsertSafe; @@ -7846,16 +7796,14 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, IssueSingleInsertNofications(aContainer, aStartChild, aEndChild, aAllowLazyConstruction); LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; + return; } - nsIContent* container = insertion.mParentFrame->GetContent(); - nsIAtom* frameType = insertion.mParentFrame->GetType(); LAYOUT_PHASE_TEMP_EXIT(); if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild, aEndChild)) { LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; + return; } LAYOUT_PHASE_TEMP_REENTER(); @@ -7872,10 +7820,11 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, // and if so, proceed. But we'd have to extend nsFieldSetFrame // to locate this legend in the inserted frames and extract it. LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(insertion.mParentFrame->GetContent(), false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(insertion.mParentFrame->GetContent(), + InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } // We should only get here with details when doing a single insertion because @@ -7887,26 +7836,27 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, // expensive to recreate the entire details frame, but it's the simplest way // to handle the insertion. LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = - RecreateFramesForContent(insertion.mParentFrame->GetContent(), false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(insertion.mParentFrame->GetContent(), + InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } // Don't construct kids of leaves if (insertion.mParentFrame->IsLeaf()) { // Clear lazy bits so we don't try to construct again. ClearLazyBits(aStartChild, aEndChild); - return NS_OK; + return; } if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) { LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(insertion.mParentFrame->GetContent(), false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(insertion.mParentFrame->GetContent(), + InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } nsFrameConstructorState state(mPresShell, @@ -7956,7 +7906,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, // the placeholder frame. if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { nsPlaceholderFrame* placeholderFrame = - GetPlaceholderFrameFor(insertion.mParentFrame); + insertion.mParentFrame->GetPlaceholderFrame(); NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?"); insertion.mParentFrame = placeholderFrame->GetParent(); } else { @@ -7983,30 +7933,13 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, IssueSingleInsertNofications(aContainer, aStartChild, aEndChild, aAllowLazyConstruction); LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; + return; } - container = insertion.mParentFrame->GetContent(); frameType = insertion.mParentFrame->GetType(); } } - if (!prevSibling) { - // We're inserting the new frames as the first child. See if the - // parent has a :before pseudo-element - nsIFrame* firstChild = insertion.mParentFrame->PrincipalChildList().FirstChild(); - - if (firstChild && - nsLayoutUtils::IsGeneratedContentFor(container, firstChild, - nsCSSPseudoElements::before)) { - // Insert the new frames after the last continuation of the :before - prevSibling = firstChild->GetTailContinuation(); - insertion.mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame(); - // Don't change isAppend here; we'll can call AppendFrames as needed, and - // the change to our prevSibling doesn't affect that. - } - } - FrameConstructionItemList items; ParentType parentType = GetParentType(frameType); FlattenedChildIterator iter(aContainer); @@ -8051,7 +7984,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items, isAppend, prevSibling)) { LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; + return; } LAYOUT_PHASE_TEMP_REENTER(); @@ -8075,65 +8008,11 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, } } - // If the parent of our current prevSibling is different from the frame we'll - // actually use as the parent, then the calculated insertion point is now - // invalid and as it is unknown where to insert correctly we append instead - // (bug 341858). - // This can affect our prevSibling and isAppend, but should not have any - // effect on the WipeContainingBlock above, since this should only happen - // when neither parent is a ib-split frame and should not affect whitespace - // handling inside table-related frames (and in fact, can only happen when - // one of the parents is a table wrapper and one is an inner table or when the - // parent is a fieldset or fieldset content frame). So it won't affect the - // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo - // handling will only be affected by us maybe thinking we're not inserting - // at the beginning, whereas we really are. That would have made us reframe - // unnecessarily, but that's ok. - // XXXbz we should push our frame construction item code up higher, so we - // know what our items are by the time we start figuring out previous - // siblings - if (prevSibling && frameItems.NotEmpty() && - frameItems.FirstChild()->GetParent() != prevSibling->GetParent()) { -#ifdef DEBUG - nsIFrame* frame1 = frameItems.FirstChild()->GetParent(); - nsIFrame* frame2 = prevSibling->GetParent(); - NS_ASSERTION(!IsFramePartOfIBSplit(frame1) && - !IsFramePartOfIBSplit(frame2), - "Neither should be ib-split"); - NS_ASSERTION((frame1->GetType() == nsGkAtoms::tableFrame && - frame2->GetType() == nsGkAtoms::tableWrapperFrame) || - (frame1->GetType() == nsGkAtoms::tableWrapperFrame && - frame2->GetType() == nsGkAtoms::tableFrame) || - frame1->GetType() == nsGkAtoms::fieldSetFrame || - (frame1->GetParent() && - frame1->GetParent()->GetType() == nsGkAtoms::fieldSetFrame), - "Unexpected frame types"); -#endif - isAppend = true; - nsIFrame* appendAfterFrame; - insertion.mParentFrame = - ::AdjustAppendParentForAfterContent(this, container, - frameItems.FirstChild()->GetParent(), - aStartChild, &appendAfterFrame); - prevSibling = ::FindAppendPrevSibling(insertion.mParentFrame, appendAfterFrame); - } - - if (haveFirstLineStyle && insertion.mParentFrame == containingBlock) { + if (haveFirstLineStyle && insertion.mParentFrame == containingBlock && isAppend) { // It's possible that the new frame goes into a first-line // frame. Look at it and see... - if (isAppend) { - // Use append logic when appending - AppendFirstLineFrames(state, containingBlock->GetContent(), - containingBlock, frameItems); - } - else { - // Use more complicated insert logic when inserting - // XXXbz this method is a no-op, so it's easy for the args being passed - // here to make no sense without anyone noticing... If it ever stops - // being a no-op, vet them carefully! - InsertFirstLineFrames(state, container, containingBlock, &insertion.mParentFrame, - prevSibling, frameItems); - } + AppendFirstLineFrames(state, containingBlock->GetContent(), + containingBlock, frameItems); } // We might have captions; put them into the caption list of the @@ -8216,32 +8095,35 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, #endif #ifdef ACCESSIBILITY - nsAccessibilityService* accService = nsIPresShell::AccService(); - if (accService) { + if (nsAccessibilityService* accService = nsIPresShell::AccService()) { accService->ContentRangeInserted(mPresShell, aContainer, aStartChild, aEndChild); } #endif - return NS_OK; + return; } -nsresult -nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, - nsIContent* aChild, - nsIContent* aOldNextSibling, - RemoveFlags aFlags, - bool* aDidReconstruct, - nsIContent** aDestroyedFramesFor) -{ +void +nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, + nsIContent* aChild, + nsIContent* aOldNextSibling, + RemoveFlags aFlags, + bool* aDidReconstruct) +{ + MOZ_ASSERT(aChild); + MOZ_ASSERT(aDidReconstruct); AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); NS_PRECONDITION(mUpdateCount != 0, "Should be in an update while destroying frames"); *aDidReconstruct = false; - if (aDestroyedFramesFor) { - *aDestroyedFramesFor = aChild; - } + + // Only recreate sync if we're already in frame construction, that is, + // recreate async for XBL DOM changes, and normal content removals. + const InsertionKind insertionKind = (aFlags == REMOVE_FOR_RECONSTRUCTION) + ? InsertionKind::Sync + : InsertionKind::Async; nsPresContext* presContext = mPresShell->GetPresContext(); MOZ_ASSERT(presContext, "Our presShell should have a valid presContext"); @@ -8274,7 +8156,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, } #endif - nsresult rv = NS_OK; nsIFrame* childFrame = aChild->GetPrimaryFrame(); if (!childFrame || childFrame->GetContent() != aChild) { // XXXbz the GetContent() != aChild check is needed due to bug 135040. @@ -8284,37 +8165,33 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, MOZ_ASSERT(!childFrame || !GetDisplayContentsStyleFor(aChild), "display:contents nodes shouldn't have a frame"); if (!childFrame && GetDisplayContentsStyleFor(aChild)) { - nsIFrame* ancestorFrame = nullptr; - nsIContent* ancestor = aContainer; - for (; ancestor; ancestor = ancestor->GetParent()) { - ancestorFrame = ancestor->GetPrimaryFrame(); - if (ancestorFrame) { - break; - } + nsIContent* ancestor = aChild->GetFlattenedTreeParent(); + MOZ_ASSERT(ancestor, "display: contents on the root?"); + while (!ancestor->GetPrimaryFrame()) { + ancestor = ancestor->GetFlattenedTreeParent(); + MOZ_ASSERT(ancestor, "we can't have a display: contents subtree root!"); } - if (ancestorFrame) { - nsIFrame* contentInsertion = ancestorFrame->GetContentInsertionFrame(); - if (ancestorFrame->GetGenConPseudos() || - (contentInsertion && contentInsertion->GetGenConPseudos())) { - *aDidReconstruct = true; - LAYOUT_PHASE_TEMP_EXIT(); - // XXXmats Can we recreate frames only for the ::after/::before content? - // XXX Perhaps even only those that belong to the aChild sub-tree? - RecreateFramesForContent(ancestor, false, aFlags, aDestroyedFramesFor); - LAYOUT_PHASE_TEMP_REENTER(); - return NS_OK; - } + + nsIFrame* ancestorFrame = ancestor->GetPrimaryFrame(); + if (ancestorFrame->GetProperty(nsIFrame::GenConProperty())) { + *aDidReconstruct = true; + + // XXXmats Can we recreate frames only for the ::after/::before content? + // XXX Perhaps even only those that belong to the aChild sub-tree? + LAYOUT_PHASE_TEMP_EXIT(); + RecreateFramesForContent(ancestor, insertionKind, aFlags); + LAYOUT_PHASE_TEMP_REENTER(); + return; } FlattenedChildIterator iter(aChild); for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) { if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) { LAYOUT_PHASE_TEMP_EXIT(); - rv = ContentRemoved(aChild, c, nullptr, aFlags, aDidReconstruct, aDestroyedFramesFor); + ContentRemoved(aChild, c, nullptr, aFlags, aDidReconstruct); LAYOUT_PHASE_TEMP_REENTER(); - NS_ENSURE_SUCCESS(rv, rv); if (aFlags != REMOVE_DESTROY_FRAMES && *aDidReconstruct) { - return rv; + return; } } } @@ -8327,7 +8204,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, if (aFlags == REMOVE_DESTROY_FRAMES) { CaptureStateForFramesOf(aChild, mTempFrameTreeState); } - return NS_OK; + return; } #endif // MOZ_XUL @@ -8365,10 +8242,9 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, nsIContent* bindingParent = aContainer->GetBindingParent(); *aDidReconstruct = true; LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(bindingParent, false, - aFlags, aDestroyedFramesFor); + RecreateFramesForContent(bindingParent, insertionKind, aFlags); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } if (aFlags == REMOVE_DESTROY_FRAMES) { @@ -8380,15 +8256,11 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // See whether we need to remove more than just childFrame LAYOUT_PHASE_TEMP_EXIT(); - nsIContent* container; - if (MaybeRecreateContainerForFrameRemoval(childFrame, aFlags, &rv, &container)) { - LAYOUT_PHASE_TEMP_REENTER(); - MOZ_ASSERT(container); + if (MaybeRecreateContainerForFrameRemoval( + childFrame, insertionKind, aFlags)) { *aDidReconstruct = true; - if (aDestroyedFramesFor) { - *aDestroyedFramesFor = container; - } - return rv; + LAYOUT_PHASE_TEMP_REENTER(); + return; } LAYOUT_PHASE_TEMP_REENTER(); @@ -8401,10 +8273,10 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // Just reframe the parent, since framesets are weird like that. *aDidReconstruct = true; LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false, - aFlags, aDestroyedFramesFor); + RecreateFramesForContent(parentFrame->GetContent(), insertionKind, + aFlags); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } // If we're a child of MathML, then we should reframe the MathML content. @@ -8415,10 +8287,9 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) { *aDidReconstruct = true; LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(possibleMathMLAncestor->GetContent(), - false, aFlags, aDestroyedFramesFor); + RecreateFramesForContent(parentFrame->GetContent(), insertionKind, aFlags); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } // Undo XUL wrapping if it's no longer needed. @@ -8432,15 +8303,14 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) { *aDidReconstruct = true; LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(grandparentFrame->GetContent(), true, - aFlags, aDestroyedFramesFor); + RecreateFramesForContent(grandparentFrame->GetContent(), insertionKind, + aFlags); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } #ifdef ACCESSIBILITY - nsAccessibilityService* accService = nsIPresShell::AccService(); - if (accService) { + if (nsAccessibilityService* accService = nsIPresShell::AccService()) { accService->ContentRemoved(mPresShell, aChild); } #endif @@ -8449,7 +8319,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // :first-letter style applies. nsIFrame* inflowChild = childFrame; if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - inflowChild = GetPlaceholderFrameFor(childFrame); + inflowChild = childFrame->GetPlaceholderFrame(); NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?"); } nsContainerFrame* containingBlock = @@ -8479,7 +8349,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // XXXbz the GetContent() != aChild check is needed due to bug 135040. // Remove it once that's fixed. ClearUndisplayedContentIn(aChild, aContainer); - return NS_OK; + return; } parentFrame = childFrame->GetParent(); parentType = parentFrame->GetType(); @@ -8505,7 +8375,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // Notify the parent frame that it should delete the frame if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - childFrame = GetPlaceholderFrameFor(childFrame); + childFrame = childFrame->GetPlaceholderFrame(); NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow."); parentFrame = childFrame->GetParent(); } @@ -8543,6 +8413,9 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // and hence it's adjacent to a block end. // If aOldNextSibling is null, then the text node before the node being // removed is the last node, and we don't need to worry about it. + // + // FIXME(emilio): This should probably use the lazy frame construction + // bits if possible instead of reframing it in place. if (aOldNextSibling) { nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling(); if (prevSibling && prevSibling->GetPreviousSibling()) { @@ -8569,7 +8442,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, #endif } - return rv; + return; } /** @@ -8631,12 +8504,11 @@ nsCSSFrameConstructor::EnsureFrameForTextNode(nsGenericDOMDataNode* aContent) return aContent->GetPrimaryFrame(); } -nsresult +void nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent, CharacterDataChangeInfo* aInfo) { AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); - nsresult rv = NS_OK; if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) && !aContent->TextIsOnlyWhitespace()) || @@ -8648,10 +8520,10 @@ nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent, "Bit should never be set on generated content"); #endif LAYOUT_PHASE_TEMP_EXIT(); - nsresult rv = RecreateFramesForContent(aContent, false, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aContent, InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); LAYOUT_PHASE_TEMP_REENTER(); - return rv; + return; } // Find the child frame @@ -8699,8 +8571,6 @@ nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent, RecoverLetterFrames(block); } } - - return rv; } void @@ -9149,7 +9019,7 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame) // are within fixed frames, because that would cause duplicates on the new // page - bug 389619) for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) { - nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed); + nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame(); if (prevPlaceholder && nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) { // We want to use the same style as the primary style frame for @@ -9314,7 +9184,8 @@ nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement) } } - RecreateFramesForContent(aElement, false, REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aElement, InsertionKind::Sync, + REMOVE_FOR_RECONSTRUCTION); return nullptr; } @@ -9357,19 +9228,16 @@ FindPreviousNonWhitespaceSibling(nsIFrame* aFrame) } bool -nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, - RemoveFlags aFlags, - nsresult* aResult, - nsIContent** aDestroyedFramesFor) +nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval( + nsIFrame* aFrame, + InsertionKind aInsertionKind, + RemoveFlags aFlags) { NS_PRECONDITION(aFrame, "Must have a frame"); NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root"); - NS_PRECONDITION(aResult, "Null out param?"); NS_PRECONDITION(aFrame == aFrame->FirstContinuation(), "aFrame not the result of GetPrimaryFrame()?"); - *aDestroyedFramesFor = nullptr; - if (IsFramePartOfIBSplit(aFrame)) { // The removal functions can't handle removal of an {ib} split directly; we // need to rebuild the containing block. @@ -9382,44 +9250,44 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, } #endif - *aResult = ReframeContainingBlock(aFrame, aFlags, aDestroyedFramesFor); + ReframeContainingBlock(aFrame, aInsertionKind, aFlags); return true; } nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame(); if (insertionFrame && insertionFrame->GetType() == nsGkAtoms::legendFrame && aFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame) { - // When we remove the legend for a fieldset, we should reframe - // the fieldset to ensure another legend is used, if there is one - *aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(), false, - aFlags, aDestroyedFramesFor); + RecreateFramesForContent(aFrame->GetParent()->GetContent(), aInsertionKind, + aFlags); return true; } - if (insertionFrame && - aFrame->GetParent()->GetType() == nsGkAtoms::detailsFrame) { + nsIFrame* inFlowFrame = + (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ? + aFrame->GetPlaceholderFrame() : aFrame; + MOZ_ASSERT(inFlowFrame, "How did that happen?"); + MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(), + "placeholder for primary frame has previous continuations?"); + nsIFrame* parent = inFlowFrame->GetParent(); + + if (parent && parent->GetType() == nsGkAtoms::detailsFrame) { HTMLSummaryElement* summary = - HTMLSummaryElement::FromContent(insertionFrame->GetContent()); + HTMLSummaryElement::FromContent(aFrame->GetContent()); + DetailsFrame* detailsFrame = static_cast<DetailsFrame*>(parent); - if (summary && summary->IsMainSummary()) { + // Unlike adding summary element cases, we need to check children of the + // parent details frame since at this moment the summary element has been + // already removed from the parent details element's child list. + if (summary && detailsFrame->HasMainSummaryFrame(aFrame)) { // When removing a summary, we should reframe the parent details frame to // ensure that another summary is used or the default summary is // generated. - *aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(), - false, REMOVE_FOR_RECONSTRUCTION, - aDestroyedFramesFor); + RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags); return true; } } // Now check for possibly needing to reconstruct due to a pseudo parent - nsIFrame* inFlowFrame = - (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ? - GetPlaceholderFrameFor(aFrame) : aFrame; - MOZ_ASSERT(inFlowFrame, "How did that happen?"); - MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(), - "placeholder for primary frame has previous continuations?"); - nsIFrame* parent = inFlowFrame->GetParent(); // For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame // need to be checked here, since all other types of parent will be catched // by "Check ruby containers" section below. @@ -9437,10 +9305,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, // Similar if we're a table-caption. (inFlowFrame->IsTableCaption() && parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) { - // We're the first or last frame in the pseudo. Need to reframe. - // Good enough to recreate frames for |parent|'s content - *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags, - aDestroyedFramesFor); + RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags); return true; } } @@ -9469,8 +9334,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, #endif // Good enough to recreate frames for aFrame's parent's content; even if // aFrame's parent is a pseudo, that'll be the right content node. - *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags, - aDestroyedFramesFor); + RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags); return true; } } @@ -9486,8 +9350,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, // frames may be constructed or destroyed accordingly. // 2. The type of the first child of a ruby frame determines // whether a pseudo ruby base container should exist. - *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags, - aDestroyedFramesFor); + RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags); return true; } @@ -9510,8 +9373,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, } #endif // DEBUG // Recreate frames for the flex container (the removed frame's parent) - *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags, - aDestroyedFramesFor); + RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags); return true; } @@ -9529,8 +9391,8 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, } #endif // DEBUG // Recreate frames for the flex container (the removed frame's grandparent) - *aResult = RecreateFramesForContent(parent->GetParent()->GetContent(), true, - aFlags, aDestroyedFramesFor); + RecreateFramesForContent(parent->GetParent()->GetContent(), aInsertionKind, + aFlags); return true; } @@ -9538,7 +9400,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, if (aFrame->GetType() == nsGkAtoms::popupSetFrame) { nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell); if (rootBox && rootBox->GetPopupSetFrame() == aFrame) { - *aResult = ReconstructDocElementHierarchy(); + ReconstructDocElementHierarchy(); return true; } } @@ -9550,8 +9412,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, !inFlowFrame->GetNextSibling() && ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) || (parent->GetNextContinuation() && !parent->GetNextInFlow()))) { - *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags, - aDestroyedFramesFor); + RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags); return true; } @@ -9587,24 +9448,26 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, } #endif - *aResult = ReframeContainingBlock(parent, aFlags, aDestroyedFramesFor); + ReframeContainingBlock(parent, aInsertionKind, aFlags); return true; } -nsresult -nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent, - bool aAsyncInsert, - RemoveFlags aFlags, - nsIContent** aDestroyedFramesFor) +void +nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent, + InsertionKind aInsertionKind, + RemoveFlags aFlags) { - NS_PRECONDITION(!aAsyncInsert || aContent->IsElement(), - "Can only insert elements async"); + MOZ_ASSERT(aInsertionKind != InsertionKind::Async || aContent->IsElement()); + MOZ_ASSERT(aContent); + // If there is no document, we don't want to recreate frames for it. (You // shouldn't generally be giving this method content without a document // anyway). // Rebuilding the frame tree can have bad effects, especially if it's the // frame tree for chrome (see bug 157322). - NS_ENSURE_TRUE(aContent->GetComposedDoc(), NS_ERROR_FAILURE); + if (NS_WARN_IF(!aContent->GetComposedDoc())) { + return; + } // Is the frame ib-split? If so, we need to reframe the containing // block *here*, rather than trying to remove and re-insert the @@ -9630,8 +9493,8 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent, if (frame) { nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame); if (nonGeneratedAncestor->GetContent() != aContent) { - return RecreateFramesForContent(nonGeneratedAncestor->GetContent(), aAsyncInsert, - aFlags, aDestroyedFramesFor); + return RecreateFramesForContent(nonGeneratedAncestor->GetContent(), + aInsertionKind, aFlags); } if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) { @@ -9651,8 +9514,8 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent, if (ancestor->GetType() != nsGkAtoms::svgUseFrame) { NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(), "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?"); - return RecreateFramesForContent(ancestor->GetContent(), aAsyncInsert, - aFlags, aDestroyedFramesFor); + return RecreateFramesForContent(ancestor->GetContent(), aInsertionKind, + aFlags); } } @@ -9663,20 +9526,13 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent, // with native anonymous content from the editor. if (parent && parent->IsLeaf() && parentContent && parentContent != aContent) { - return RecreateFramesForContent(parentContent, aAsyncInsert, aFlags, - aDestroyedFramesFor); + return RecreateFramesForContent(parentContent, aInsertionKind, aFlags); } } - nsresult rv = NS_OK; - nsIContent* container; - if (frame && MaybeRecreateContainerForFrameRemoval(frame, aFlags, &rv, - &container)) { - MOZ_ASSERT(container); - if (aDestroyedFramesFor) { - *aDestroyedFramesFor = container; - } - return rv; + if (frame && + MaybeRecreateContainerForFrameRemoval(frame, aInsertionKind, aFlags)) { + return; } nsINode* containerNode = aContent->GetParentNode(); @@ -9688,47 +9544,44 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent, // Need the nsIContent parent, which might be null here, since we need to // pass it to ContentInserted and ContentRemoved. + // + // FIXME(emilio): Do we need a strong ref here? nsCOMPtr<nsIContent> container = aContent->GetParent(); // Remove the frames associated with the content object. bool didReconstruct; nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ? nullptr : aContent->GetNextSibling(); - const bool reconstruct = aFlags != REMOVE_DESTROY_FRAMES; - RemoveFlags flags = reconstruct ? REMOVE_FOR_RECONSTRUCTION : aFlags; - rv = ContentRemoved(container, aContent, nextSibling, flags, - &didReconstruct, aDestroyedFramesFor); - if (NS_FAILED(rv)) { - return rv; - } - if (reconstruct && !didReconstruct) { - // Now, recreate the frames associated with this content object. If - // ContentRemoved triggered reconstruction, then we don't need to do this - // because the frames will already have been built. - if (aAsyncInsert) { + ContentRemoved(container, aContent, nextSibling, aFlags, &didReconstruct); + if (!didReconstruct) { + if (aInsertionKind == InsertionKind::Async) { // XXXmats doesn't frame state need to be restored in this case too? - RestyleManager()->PostRestyleEvent( - aContent->AsElement(), nsRestyleHint(0), nsChangeHint_ReconstructFrame); + RestyleManager()->PostRestyleEvent(aContent->AsElement(), + nsRestyleHint(0), + nsChangeHint_ReconstructFrame); } else { - rv = ContentInserted(container, aContent, mTempFrameTreeState, false); + // Now, recreate the frames associated with this content object. If + // ContentRemoved triggered reconstruction, then we don't need to do this + // because the frames will already have been built. + ContentInserted(container, aContent, mTempFrameTreeState, false); } } } - - return rv; } void -nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent, - nsIContent** aDestroyedFramesFor) +nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent, + bool* aDidReconstruct) { MOZ_ASSERT(aContent && aContent->GetParentNode()); - bool didReconstruct; nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ? nullptr : aContent->GetNextSibling(); - ContentRemoved(aContent->GetParent(), aContent, nextSibling, - REMOVE_DESTROY_FRAMES, &didReconstruct, aDestroyedFramesFor); + ContentRemoved(aContent->GetParent(), + aContent, + nextSibling, + REMOVE_DESTROY_FRAMES, + aDidReconstruct); } ////////////////////////////////////////////////////////////////////// @@ -10660,13 +10513,6 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent( { for (uint32_t i = 0; i < aAnonymousItems.Length(); ++i) { nsIContent* content = aAnonymousItems[i].mContent; -#ifdef DEBUG - nsIAnonymousContentCreator* creator = do_QueryFrame(aFrame); - NS_ASSERTION(!creator || !creator->CreateFrameFor(content), - "If you need to use CreateFrameFor, you need to call " - "CreateAnonymousFrames manually and not follow the standard " - "ProcessChildren() codepath for this frame"); -#endif // Gecko-styled nodes should have no pending restyle flags. MOZ_ASSERT_IF(!content->IsStyledByServo(), !content->IsElement() || @@ -10684,24 +10530,111 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent( RefPtr<nsStyleContext> styleContext; TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext); - if (aAnonymousItems[i].mStyleContext) { - // If we have an explicit style context, that means that the anonymous - // content creator had its own plan for the style, and doesn't need the - // computed style obtained by cascading this content as a normal node. - // This happens when a native anonymous node is used to implement a - // pseudo-element. Allowing Servo to traverse these nodes would be wasted - // work, so assert that we didn't do that. - MOZ_ASSERT_IF(content->IsStyledByServo(), !content->HasServoData()); - styleContext = aAnonymousItems[i].mStyleContext.forget(); - } else { - // If we don't have an explicit style context, that means we need the - // ordinary computed values. Make sure we eagerly cascaded them when the - // anonymous nodes were created. - MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(), - content->HasServoData()); - styleContext = ResolveStyleContext(aFrame, content, &aState); + + // Make sure we eagerly performed the servo cascade when the anonymous + // nodes were created. + MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(), + content->AsElement()->HasServoData()); + + // Determine whether this NAC is pseudo-implementing. + nsIAtom* pseudo = nullptr; + if (content->IsElement()) { + auto pseudoType = content->AsElement()->GetPseudoElementType(); + if (pseudoType != CSSPseudoElementType::NotPseudo) { + pseudo = nsCSSPseudoElements::GetPseudoAtom(pseudoType); + } + } + + // Determine the appropriate parent style for this NAC, and if the NAC + // implements a pseudo-element, the appropriate originating element + // (that is to say, the element to the left of the ::pseudo-element in + // the selector). This is all rather tricky, and merits some discussion. + // + // First, it's important to note that author stylesheets generally do not + // apply to elements in native-anonymous subtrees. The exceptions to + // this are web-exposed pseudo-elements, where authors can style the + // pseudo-implementing NAC if the originating element is not itself in a NAC + // subtree. + // + // For this reason, it's very important that we avoid using a style parent + // that is inside a NAC subtree together with an originating element that + // is not inside a NAC subtree, since that would allow authors to + // explicitly inherit styles from internal elements, potentially making + // the NAC hierarchy observable. To ensure this, and generally simplify + // things, we always set the originating element to the style parent. + // + // As a consequence of the above, all web-exposed pseudo-elements (which, + // by definition, must have a content-accessible originating element) must + // also inherit style from that same content-accessible element. To avoid + // unintuitive behavior differences between NAC elements that do and don't + // correspond to web-exposed pseudo-elements, we follow this protocol for + // all NAC, pseudo-implementing or not. + // + // However, things get tricky with the <video> element, where we have a + // bunch of XBL-generated anonymous content descending from a native- + // anonymous XULElement. The XBL elements inherit style from their + // flattened tree parent, because that's how XBL works. But then we need + // to figure out what to do when one of those anonymous XBL elements + // (like an <input> element) generates its own (possibly pseudo-element- + // implementing) NAC. + // + // In this case, we inherit style from the XBL-generated NAC-creating + // element, rather than the <video> element. There are a number of good + // reasons for this. First, inheriting from the great-grandparent while + // the parent inherits from the grandparent would be bizarre at best. + // Second, exposing pseudo-elements from elements within our particular + // XBL implementation would allow content styles to (un)intentionally + // alter the video controls, which would be very bad. Third, our UA + // stylesheets have selectors like: + // + // input[type=range][orient=horizontal]::-moz-range-track + // + // and we need to make sure that the originating element is the <input>, + // not the <video>, because that's where the |orient| attribute lives. + // + // The upshot of all of this is that, to find the style parent (and + // originating element, if applicable), we walk up our parent chain to the + // first element that is not itself NAC (distinct from whether it happens + // to be in a NAC subtree). + // + // The one exception to all of this is scrollbar content, which we parent + // directly to the scrollframe. This is because the special-snowflake + // construction of scroll frames doesn't result in the placeholder frame + // being constructed until later, which means that GetInFlowParent() doesn't + // work right in the case of out-of-flow scrollframes. + // + // To implement all this, we need to pass the correct parent style context + // here because SetPrimaryFrame() may not have been called on the content + // yet and thus ResolveStyleContext can't find it otherwise. + // + // We don't need to worry about display:contents here, because such + // elements don't get a frame and thus can't generate NAC. But we do need + // to worry about anonymous boxes, which CorrectStyleParentFrame handles + // for us. + nsIFrame* inheritFrame = aFrame; + if (!content->IsNativeScrollbarContent()) { + while (inheritFrame->GetContent()->IsNativeAnonymous()) { + inheritFrame = inheritFrame->GetInFlowParent(); + } } + nsIFrame* styleParentFrame = + nsFrame::CorrectStyleParentFrame(inheritFrame, pseudo); + // The only way we can not have a style parent now is if inheritFrame is the + // canvas frame and we're the NAC parent for all the things added via + // nsIDocument::InsertAnonymousContent. + MOZ_ASSERT_IF(!styleParentFrame, + inheritFrame->GetType() == nsGkAtoms::canvasFrame); + // And that anonymous div has no pseudo. + MOZ_ASSERT_IF(!styleParentFrame, !pseudo); + + Element* originating = + pseudo ? styleParentFrame->GetContent()->AsElement() : nullptr; + nsStyleContext* parentStyle = + styleParentFrame ? styleParentFrame->StyleContext() : nullptr; + styleContext = + ResolveStyleContext(parentStyle, content, &aState, originating); + nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr; if (!aAnonymousItems[i].mChildren.IsEmpty()) { anonChildren = &aAnonymousItems[i].mChildren; @@ -11028,151 +10961,6 @@ nsCSSFrameConstructor::AppendFirstLineFrames( lineFrame, aFrameItems); } -// Special routine to handle inserting a new frame into a block -// frame's child list. Takes care of placing the new frame into the -// right place when first-line style is present. -nsresult -nsCSSFrameConstructor::InsertFirstLineFrames( - nsFrameConstructorState& aState, - nsIContent* aContent, - nsIFrame* aBlockFrame, - nsContainerFrame** aParentFrame, - nsIFrame* aPrevSibling, - nsFrameItems& aFrameItems) -{ - nsresult rv = NS_OK; - // XXXbz If you make this method actually do something, check to - // make sure that the caller is passing what you expect. In - // particular, which content is aContent? And audit the rest of - // this code too; it makes bogus assumptions and may not build. -#if 0 - nsIFrame* parentFrame = *aParentFrame; - nsIFrame* newFrame = aFrameItems.childList; - bool isInline = IsInlineOutside(newFrame); - - if (!aPrevSibling) { - // Insertion will become the first frame. Two cases: we either - // already have a first-line frame or we don't. - nsIFrame* firstBlockKid = aBlockFrame->PrincipalChildList().FirstChild(); - if (firstBlockKid->GetType() == nsGkAtoms::lineFrame) { - // We already have a first-line frame - nsIFrame* lineFrame = firstBlockKid; - - if (isInline) { - // Easy case: the new inline frame will go into the lineFrame. - ReparentFrame(this, lineFrame, newFrame); - InsertFrames(lineFrame, kPrincipalList, nullptr, newFrame); - - // Since the frame is going into the lineFrame, don't let it - // go into the block too. - aFrameItems.childList = nullptr; - aFrameItems.lastChild = nullptr; - } - else { - // Harder case: We are about to insert a block level element - // before the first-line frame. - // XXX need a method to steal away frames from the line-frame - } - } - else { - // We do not have a first-line frame - if (isInline) { - // We now need a first-line frame to contain the inline frame. - nsIFrame* lineFrame = NS_NewFirstLineFrame(firstLineStyle); - - if (NS_SUCCEEDED(rv)) { - // Lookup first-line style context - nsStyleContext* parentStyle = - nsFrame::CorrectStyleParentFrame(aBlockFrame, - nsCSSPseudoElements::firstLine)-> - StyleContext(); - RefPtr<nsStyleContext> firstLineStyle = - GetFirstLineStyle(aContent, parentStyle); - - // Initialize the line frame - InitAndRestoreFrame(aState, aContent, aBlockFrame, lineFrame); - - // Make sure the caller inserts the lineFrame into the - // blocks list of children. - aFrameItems.childList = lineFrame; - aFrameItems.lastChild = lineFrame; - - // Give the inline frames to the lineFrame <b>after</b> - // reparenting them - NS_ASSERTION(lineFrame->StyleContext() == firstLineStyle, - "Bogus style context on line frame"); - ReparentFrame(aPresContext, lineFrame, newFrame); - lineFrame->SetInitialChildList(kPrincipalList, newFrame); - } - } - else { - // Easy case: the regular insertion logic can insert the new - // frame because it's a block frame. - } - } - } - else { - // Insertion will not be the first frame. - nsIFrame* prevSiblingParent = aPrevSibling->GetParent(); - if (prevSiblingParent == aBlockFrame) { - // Easy case: The prev-siblings parent is the block - // frame. Therefore the prev-sibling is not currently in a - // line-frame. Therefore the new frame which is going after it, - // regardless of type, is not going into a line-frame. - } - else { - // If the prevSiblingParent is not the block-frame then it must - // be a line-frame (if it were a letter-frame, that logic would - // already have adjusted the prev-sibling to be the - // letter-frame). - if (isInline) { - // Easy case: the insertion can go where the caller thinks it - // should go (which is into prevSiblingParent). - } - else { - // Block elements don't end up in line-frames, therefore - // change the insertion point to aBlockFrame. However, there - // might be more inline elements following aPrevSibling that - // need to be pulled out of the line-frame and become children - // of the block. - nsIFrame* nextSibling = aPrevSibling->GetNextSibling(); - nsIFrame* nextLineFrame = prevSiblingParent->GetNextInFlow(); - if (nextSibling || nextLineFrame) { - // Oy. We have work to do. Create a list of the new frames - // that are going into the block by stripping them away from - // the line-frame(s). - if (nextSibling) { - nsLineFrame* lineFrame = (nsLineFrame*) prevSiblingParent; - nsFrameList tail = lineFrame->StealFramesAfter(aPrevSibling); - // XXX do something with 'tail' - } - - nsLineFrame* nextLineFrame = (nsLineFrame*) lineFrame; - for (;;) { - nextLineFrame = nextLineFrame->GetNextInFlow(); - if (!nextLineFrame) { - break; - } - nsIFrame* kids = nextLineFrame->PrincipalChildList().FirstChild(); - } - } - else { - // We got lucky: aPrevSibling was the last inline frame in - // the line-frame. - ReparentFrame(this, aBlockFrame, newFrame); - InsertFrames(aBlockFrame, kPrincipalList, - prevSiblingParent, newFrame); - aFrameItems.childList = nullptr; - aFrameItems.lastChild = nullptr; - } - } - } - } - -#endif - return rv; -} - //---------------------------------------------------------------------- // First-letter support @@ -11494,7 +11282,7 @@ FindFirstLetterFrame(nsIFrame* aFrame, nsIFrame::ChildListID aListID) return nullptr; } -nsresult +void nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames( nsIPresShell* aPresShell, nsIFrame* aBlockFrame) @@ -11506,7 +11294,7 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames( floatFrame = ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList); if (!floatFrame) { - return NS_OK; + return; } } @@ -11514,19 +11302,19 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames( // destroyed when we destroy the letter frame). nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild(); if (!textFrame) { - return NS_OK; + return; } // Discover the placeholder frame for the letter frame - nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrameFor(floatFrame); + nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame(); if (!placeholderFrame) { // Somethings really wrong - return NS_OK; + return; } nsContainerFrame* parentFrame = placeholderFrame->GetParent(); if (!parentFrame) { // Somethings really wrong - return NS_OK; + return; } // Create a new text frame with the right style context that maps @@ -11535,7 +11323,7 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames( nsStyleContext* parentSC = parentFrame->StyleContext(); nsIContent* textContent = textFrame->GetContent(); if (!textContent) { - return NS_OK; + return; } RefPtr<nsStyleContext> newSC = aPresShell->StyleSet()-> ResolveStyleForText(textContent, parentSC); @@ -11580,11 +11368,9 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames( if (offsetsNeedFixing) { prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING); } - - return NS_OK; } -nsresult +void nsCSSFrameConstructor::RemoveFirstLetterFrames(nsIPresShell* aPresShell, nsContainerFrame* aFrame, nsContainerFrame* aBlockFrame, @@ -11657,11 +11443,9 @@ nsCSSFrameConstructor::RemoveFirstLetterFrames(nsIPresShell* aPresShell, prevSibling = kid; kid = kid->GetNextSibling(); } - - return NS_OK; } -nsresult +void nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell, nsContainerFrame* aBlockFrame) { @@ -11670,20 +11454,16 @@ nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell, nsContainerFrame* continuation = aBlockFrame; bool stopLooking = false; - nsresult rv; do { - rv = RemoveFloatingFirstLetterFrames(aPresShell, continuation); - if (NS_SUCCEEDED(rv)) { - rv = RemoveFirstLetterFrames(aPresShell, - continuation, aBlockFrame, &stopLooking); - } + RemoveFloatingFirstLetterFrames(aPresShell, continuation); + RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame, + &stopLooking); if (stopLooking) { break; } continuation = static_cast<nsContainerFrame*>(continuation->GetNextContinuation()); } while (continuation); - return rv; } // Fixup the letter frame situation for the given block @@ -11726,7 +11506,7 @@ nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame) // listbox Widget Routines -nsresult +void nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame, nsIFrame* aPrevFrame, nsIContent* aChild, @@ -11734,8 +11514,6 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame, bool aIsAppend) { #ifdef MOZ_XUL - nsresult rv = NS_OK; - // Construct a new frame if (nullptr != aParentFrame) { nsFrameItems frameItems; @@ -11756,7 +11534,7 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame, if (StyleDisplay::None == display->mDisplay) { *aNewFrame = nullptr; - return NS_OK; + return; } BeginUpdate(); @@ -11775,9 +11553,9 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame, if (newFrame) { // Notify the parent frame if (aIsAppend) - rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems); + ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems); else - rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems); + ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems); } EndUpdate(); @@ -11792,10 +11570,6 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame, } #endif } - - return rv; -#else - return NS_ERROR_FAILURE; #endif } @@ -12218,8 +11992,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, if (aFrame->IsXULBoxFrame() && !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) && aItems.AnyItemsNeedBlockParent()) { - RecreateFramesForContent(aFrame->GetContent(), true, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async, + REMOVE_FOR_RECONSTRUCTION); return true; } @@ -12238,8 +12012,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, const bool isWebkitBox = IsFlexContainerForLegacyBox(aFrame, frameType); if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) && iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) { - RecreateFramesForContent(aFrame->GetContent(), true, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async, + REMOVE_FOR_RECONSTRUCTION); return true; } @@ -12250,8 +12024,9 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, iter.SetToEnd(); iter.Prev(); if (iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) { - RecreateFramesForContent(aFrame->GetContent(), true, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aFrame->GetContent(), + InsertionKind::Async, + REMOVE_FOR_RECONSTRUCTION); return true; } } @@ -12281,8 +12056,9 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, isWebkitBox)) { // We hit something that _doesn't_ need an anonymous flex item! // Rebuild the flex container to bust it out. - RecreateFramesForContent(containerFrame->GetContent(), true, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(containerFrame->GetContent(), + InsertionKind::Async, + REMOVE_FOR_RECONSTRUCTION); return true; } @@ -12306,8 +12082,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, // We want to optimize it better, and avoid reframing as much as // possible. But given the cases above, and the fact that a ruby // usually won't be very large, it should be fine to reframe it. - RecreateFramesForContent(aFrame->GetContent(), true, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async, + REMOVE_FOR_RECONSTRUCTION); return true; } @@ -12473,8 +12249,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, if (!aItems.AllWantParentType(parentType)) { // Reframing aFrame->GetContent() is good enough, since the content of // table pseudo-frames is the ancestor content. - RecreateFramesForContent(aFrame->GetContent(), true, - REMOVE_FOR_RECONSTRUCTION, nullptr); + RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async, + REMOVE_FOR_RECONSTRUCTION); return true; } } @@ -12562,15 +12338,15 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, static_cast<void*>(blockContent)); } #endif - RecreateFramesForContent(blockContent, true, REMOVE_FOR_RECONSTRUCTION, - nullptr); + RecreateFramesForContent(blockContent, InsertionKind::Async, + REMOVE_FOR_RECONSTRUCTION); return true; } -nsresult -nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame, - RemoveFlags aFlags, - nsIContent** aDestroyedFramesFor) +void +nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame, + InsertionKind aInsertionKind, + RemoveFlags aFlags) { #ifdef DEBUG @@ -12590,7 +12366,7 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame, // don't ReframeContainingBlock, this will result in a crash // if we remove a tree that's in reflow - see bug 121368 for testcase NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!"); - return NS_OK; + return; } // Get the first "normal" ancestor of the target frame. @@ -12606,23 +12382,25 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame, // so GetFloatContainingBlock(aFrame) has been removed // And get the containingBlock's content - nsCOMPtr<nsIContent> blockContent = containingBlock->GetContent(); - if (blockContent) { + if (nsIContent* blockContent = containingBlock->GetContent()) { #ifdef DEBUG if (gNoisyContentUpdates) { printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent)); } #endif - return RecreateFramesForContent(blockContent, true, aFlags, aDestroyedFramesFor); + RecreateFramesForContent(blockContent->AsElement(), aInsertionKind, + REMOVE_FOR_RECONSTRUCTION); + return; } } // If we get here, we're screwed! - return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(), - true, aFlags, nullptr); + RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(), + aInsertionKind, + REMOVE_FOR_RECONSTRUCTION); } -nsresult +void nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame) { { @@ -12656,8 +12434,6 @@ nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame) // call XBL constructors after the frames are created mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue(); - - return NS_OK; } ////////////////////////////////////////////////////////// |