summaryrefslogtreecommitdiffstats
path: root/layout/base/nsCSSFrameConstructor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/nsCSSFrameConstructor.cpp')
-rw-r--r--layout/base/nsCSSFrameConstructor.cpp1576
1 files changed, 676 insertions, 900 deletions
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 37cd3e45e..fc458b5eb 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;
}
//////////////////////////////////////////////////////////