Bug 1321284 - Part 2: Add nsINode::GetFlattenedTreeParentNodeForStyle. r=bholley
MozReview-Commit-ID: AmDyeE21N8g
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -396,16 +396,17 @@ public:
inline bool HasDirAuto() const {
return (!HasFixedDir() &&
(HasValidDir() || IsHTMLElement(nsGkAtoms::bdi)));
}
Directionality GetComputedDirectionality() const;
inline Element* GetFlattenedTreeParentElement() const;
+ inline Element* GetFlattenedTreeParentElementForStyle() const;
bool HasDirtyDescendantsForServo() const
{
MOZ_ASSERT(IsStyledByServo());
return HasFlag(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
void SetHasDirtyDescendantsForServo() {
--- a/dom/base/ElementInlines.h
+++ b/dom/base/ElementInlines.h
@@ -32,16 +32,27 @@ Element::GetFlattenedTreeParentElement()
nsINode* parentNode = GetFlattenedTreeParentNode();
if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
return parentNode->AsElement();
}
return nullptr;
}
+inline Element*
+Element::GetFlattenedTreeParentElementForStyle() const
+{
+ nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
+ if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
+ return parentNode->AsElement();
+ }
+
+ return nullptr;
+}
+
inline void
Element::NoteDirtyDescendantsForServo()
{
Element* curr = this;
while (curr && !curr->HasDirtyDescendantsForServo()) {
curr->SetHasDirtyDescendantsForServo();
curr = curr->GetFlattenedTreeParentElement();
}
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -147,25 +147,64 @@ nsIContent::FindFirstNonChromeOnlyAccess
// non-const. (Then again, so does GetChildAt(0)->GetParent().)
return const_cast<nsIContent*>(content);
}
}
return nullptr;
}
nsINode*
-nsIContent::GetFlattenedTreeParentNodeInternal() const
+nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
{
nsINode* parentNode = GetParentNode();
if (!parentNode || !parentNode->IsContent()) {
MOZ_ASSERT(!parentNode || parentNode == OwnerDoc());
return parentNode;
}
nsIContent* parent = parentNode->AsContent();
+ if (aType == eForStyle &&
+ IsRootOfNativeAnonymousSubtree() &&
+ OwnerDoc()->GetRootElement() == parent) {
+ // When getting the flattened tree parent for style, we return null
+ // for any "document level" native anonymous content subtree root.
+ // This is NAC generated by an ancestor frame of the document element's
+ // primary frame, and includes scrollbar elements created by the root
+ // scroll frame, and the "custom content container" and accessible caret
+ // generated by the nsCanvasFrame. We distinguish document level NAC
+ // from NAC generated by the root element's primary frame below.
+ nsIFrame* parentFrame = parent->GetPrimaryFrame();
+ if (!parentFrame) {
+ // If the root element has no primary frame, it means it can't have
+ // generated any NAC itself. Thus any NAC we have here must have
+ // been generated by an ancestor frame.
+ //
+ // If we are in here, then either the root element is display:none, or
+ // we are in the middle of constructing the root of the frame tree and
+ // we are trying to eagerly restyle document level NAC in
+ // nsCSSFrameConstructor::GetAnonymousContent before the root
+ // element's frame has been constructed.
+ return nullptr;
+ }
+ nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame);
+ if (!creator) {
+ // If the root element does have a frame, but does not implement
+ // nsIAnonymousContentCreator, then this must be document level NAC.
+ return nullptr;
+ }
+ AutoTArray<nsIContent*, 8> elements;
+ creator->AppendAnonymousContentTo(elements, 0);
+ if (!elements.Contains(this)) {
+ // If the root element does have a frame, and also does implement
+ // nsIAnonymousContentCreator, but didn't create this node, then
+ // it must be document level NAC.
+ return nullptr;
+ }
+ }
+
if (parent && nsContentUtils::HasDistributedChildren(parent) &&
nsContentUtils::IsInSameAnonymousTree(parent, this)) {
// This node is distributed to insertion points, thus we
// need to consult the destination insertion points list to
// figure out where this node was inserted in the flattened tree.
// It may be the case that |parent| distributes its children
// but the child does not match any insertion points, thus
// the flattened tree parent is nullptr.
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -726,20 +726,19 @@ public:
virtual void SetXBLInsertionParent(nsIContent* aContent) = 0;
/**
* Same as GetFlattenedTreeParentNode, but returns null if the parent is
* non-nsIContent.
*/
inline nsIContent *GetFlattenedTreeParent() const;
- /**
- * Helper method, which we leave public so that it's accessible from nsINode.
- */
- nsINode *GetFlattenedTreeParentNodeInternal() const;
+ // Helper method, which we leave public so that it's accessible from nsINode.
+ enum FlattenedParentType { eNotForStyle, eForStyle };
+ nsINode* GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const;
/**
* Gets the custom element data used by web components custom element.
* Custom element data is created at the first attempt to enqueue a callback.
*
* @return The custom element data or null if none.
*/
virtual mozilla::dom::CustomElementData *GetCustomElementData() const = 0;
--- a/dom/base/nsIContentInlines.h
+++ b/dom/base/nsIContentInlines.h
@@ -28,44 +28,63 @@ inline mozilla::dom::ShadowRoot* nsICont
{
if (!IsElement()) {
return nullptr;
}
return AsElement()->FastGetShadowRoot();
}
-inline nsINode* nsINode::GetFlattenedTreeParentNode() const
+template<nsIContent::FlattenedParentType Type>
+static inline nsINode*
+GetFlattenedTreeParentNode(const nsINode* aNode)
{
- nsINode* parent = GetParentNode();
-
+ nsINode* parent = aNode->GetParentNode();
// Try to short-circuit past the complicated and not-exactly-fast logic for
// computing the flattened parent.
//
- // There are three cases where we need might something other than parentNode:
+ // There are four cases where we need might something other than parentNode:
// (1) The node is an explicit child of an XBL-bound element, re-bound
// to an XBL insertion point.
// (2) The node is a top-level element in a shadow tree, whose flattened
// parent is the host element (as opposed to the actual parent which
// is the shadow root).
// (3) The node is an explicit child of an element with a shadow root,
// re-bound to an insertion point.
- bool needSlowCall = HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
- IsInShadowTree() ||
- (parent && parent->IsContent() &&
- parent->AsContent()->GetShadowRoot());
+ // (4) We want the flattened parent for style, and the node is the root
+ // of a native anonymous content subtree parented to the document's
+ // root element.
+ bool needSlowCall = aNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
+ aNode->IsInShadowTree() ||
+ (parent &&
+ parent->IsContent() &&
+ parent->AsContent()->GetShadowRoot()) ||
+ (Type == nsIContent::eForStyle &&
+ aNode->IsContent() &&
+ aNode->AsContent()->IsRootOfNativeAnonymousSubtree() &&
+ aNode->OwnerDoc()->GetRootElement() == parent);
if (MOZ_UNLIKELY(needSlowCall)) {
- MOZ_ASSERT(IsContent());
- return AsContent()->GetFlattenedTreeParentNodeInternal();
+ MOZ_ASSERT(aNode->IsContent());
+ return aNode->AsContent()->GetFlattenedTreeParentNodeInternal(Type);
}
+ return parent;
+}
- return parent;
+inline nsINode*
+nsINode::GetFlattenedTreeParentNode() const
+{
+ return ::GetFlattenedTreeParentNode<nsIContent::eNotForStyle>(this);
}
inline nsIContent*
nsIContent::GetFlattenedTreeParent() const
{
nsINode* parent = GetFlattenedTreeParentNode();
return (parent && parent->IsContent()) ? parent->AsContent() : nullptr;
}
+inline nsINode*
+nsINode::GetFlattenedTreeParentNodeForStyle() const
+{
+ return ::GetFlattenedTreeParentNode<nsIContent::eForStyle>(this);
+}
#endif // nsIContentInlines_h
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -914,16 +914,24 @@ public:
* into an insertion point, or if the node is a direct child of a
* shadow root.
*
* @return the flattened tree parent
*/
inline nsINode* GetFlattenedTreeParentNode() const;
/**
+ * Like GetFlattenedTreeParentNode, but returns null for any native
+ * anonymous content that was generated for ancestor frames of the
+ * root element's primary frame, such as scrollbar elements created
+ * by the root scroll frame.
+ */
+ inline nsINode* GetFlattenedTreeParentNodeForStyle() const;
+
+ /**
* Get the parent nsINode for this node if it is an Element.
* @return the parent node
*/
mozilla::dom::Element* GetParentElement() const
{
return mParent && mParent->IsElement() ? mParent->AsElement() : nullptr;
}