diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 060e230a4613..f3d747ba175f 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -3513,6 +3513,19 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt const nsStyleDisplay* display = styleContext->StyleDisplay(); nsIContent* const content = aItem.mContent; + // Get the parent of the content and check if it is a XBL children element. + // Push the children element as an ancestor here because it does + // not have a frame and would not otherwise be pushed as an ancestor. It is + // necessary to do so in order to correctly handle style resolution on + // descendants. + nsIContent* parent = content->GetParent(); + bool pushInsertionPoint = aState.mTreeMatchContext.mAncestorFilter.HasFilter() && + parent && parent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL); + TreeMatchContext::AutoAncestorPusher + insertionPointPusher(pushInsertionPoint, + aState.mTreeMatchContext, + parent && parent->IsElement() ? parent->AsElement() : nullptr); + // Push the content as a style ancestor now, so we don't have to do // it in our various full-constructor functions. In particular, // since a number of full-constructor functions don't actually call @@ -9945,6 +9958,20 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState, FlattenedChildIterator iter(aContent); for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { + // Get the parent of the content and check if it is a XBL children element + // (if the content is a children element then parent != aContent because the + // FlattenedChildIterator will transitively iterate through + // for default content). Push the children element as an ancestor here because + // it does not have a frame and would not otherwise be pushed as an ancestor. + nsIContent* parent = child->GetParent(); + MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children."); + MOZ_ASSERT(parent->IsElement()); + bool pushInsertionPoint = parent != aContent && + aState.mTreeMatchContext.mAncestorFilter.HasFilter(); + TreeMatchContext::AutoAncestorPusher + ancestorPusher(pushInsertionPoint, aState.mTreeMatchContext, + parent->AsElement()); + // Frame construction item construction should not post // restyles, so removing restyle flags here is safe. if (child->IsElement()) { @@ -11204,6 +11231,20 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState, FlattenedChildIterator iter(parentContent); for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) { + // Get the parent of the content and check if it is a XBL children element + // (if the content is a children element then contentParent != parentContent because the + // FlattenedChildIterator will transitively iterate through + // for default content). Push the children element as an ancestor here because + // it does not have a frame and would not otherwise be pushed as an ancestor. + nsIContent* contentParent = content->GetParent(); + MOZ_ASSERT(contentParent, "Parent must be non-null because we are iterating children."); + MOZ_ASSERT(contentParent->IsElement()); + bool pushInsertionPoint = contentParent != parentContent && + aState.mTreeMatchContext.mAncestorFilter.HasFilter(); + TreeMatchContext::AutoAncestorPusher + insertionPointPusher(pushInsertionPoint, aState.mTreeMatchContext, + contentParent->AsElement()); + // Manually check for comments/PIs, since we don't have a frame to pass to // AddFrameConstructionItems. We know our parent is a non-replaced inline, // so there is no need to do the NeedFrameFor check. diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp index e62f7e4fd5b3..fbc021f23b4d 100644 --- a/layout/base/nsFrameManager.cpp +++ b/layout/base/nsFrameManager.cpp @@ -1369,6 +1369,18 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext, NS_ASSERTION(!undisplayed->mStyle->GetPseudo(), "Shouldn't have random pseudo style contexts in the " "undisplayed map"); + + // Get the parent of the undisplayed content and check if it is a XBL + // children element. Push the children element as an ancestor here because it does + // not have a frame and would not otherwise be pushed as an ancestor. + nsIContent* parent = undisplayed->mContent->GetParent(); + bool pushInsertionPoint = parent && + parent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL); + TreeMatchContext::AutoAncestorPusher + insertionPointPusher(pushInsertionPoint, + aTreeMatchContext, + parent && parent->IsElement() ? parent->AsElement() : nullptr); + nsRestyleHint thisChildHint = childRestyleHint; RestyleTracker::RestyleData undisplayedRestyleData; if (aRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(), @@ -1524,6 +1536,19 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext, for (; !childFrames.AtEnd(); childFrames.Next()) { nsIFrame* child = childFrames.get(); if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { + // Get the parent of the child frame's content and check if it is a XBL + // children element. Push the children element as an ancestor here because it does + // not have a frame and would not otherwise be pushed as an ancestor. + + // Check if the frame has a content because |child| may be a nsPageFrame that does + // not have a content. + nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr; + bool pushInsertionPoint = parent && + parent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL); + TreeMatchContext::AutoAncestorPusher + insertionPointPusher(pushInsertionPoint, aTreeMatchContext, + parent && parent->IsElement() ? parent->AsElement() : nullptr); + // only do frames that are in flow if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder // get out of flow frame and recur there diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index c3b88263f04b..140b19af8f84 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -3395,14 +3395,6 @@ TreeMatchContext::InitAncestors(Element *aElement) break; } - if (parent->AsElement()->NodeInfo()->Equals(nsGkAtoms::children, - kNameSpaceID_XBL)) { - parent = parent->GetParentNode(); - if (!parent->IsElement()) { - break; - } - } - cur = parent->AsElement(); } while (true); @@ -3471,17 +3463,6 @@ AncestorFilter::AssertHasAllAncestors(Element *aElement) const { nsINode* cur = aElement->GetParentNode(); while (cur && cur->IsElement()) { - // We build our ancestor tree from the top-down. However, because - // elements don't have frames and don't directly - // participate in the style tree, they never get pushed as ancestors. - // Skip them on the way up as we do on the way down (see also - // mozilla::dom::ExplicitChildIterator). - if (cur->AsElement()->NodeInfo()->Equals(nsGkAtoms::children, - kNameSpaceID_XBL)) { - cur = cur->GetParentNode(); - continue; - } - MOZ_ASSERT(mElements.Contains(cur)); cur = cur->GetParentNode(); }