Bug 1331322 - Add a flag to indicate that a node is native anonymous content. r=bz draft
authorBobby Holley <bobbyholley@gmail.com>
Fri, 20 Jan 2017 18:28:46 -0800
changeset 485064 bc5a4ef8416f7fa6c9067bad1485bf025c268d5d
parent 485063 c8b2bd32c3a8009782a54068d2f59aee7a87ffbe
child 485065 a905853cc85bf6d41a61c0163193b869a8b864dd
push id45616
push userbmo:bobbyholley@gmail.com
push dateThu, 16 Feb 2017 01:57:04 +0000
reviewersbz
bugs1331322
milestone54.0a1
Bug 1331322 - Add a flag to indicate that a node is native anonymous content. r=bz
dom/base/nsIContent.h
dom/base/nsINode.h
layout/base/nsCSSFrameConstructor.cpp
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -189,17 +189,17 @@ public:
 
   /**
    * Makes this content anonymous
    * @see nsIAnonymousContentCreator
    */
   void SetIsNativeAnonymousRoot()
   {
     SetFlags(NODE_IS_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
-             NODE_IS_NATIVE_ANONYMOUS_ROOT);
+             NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_NATIVE_ANONYMOUS);
   }
 
   /**
    * Returns |this| if it is not chrome-only/native anonymous, otherwise
    * first non chrome-only/native anonymous ancestor.
    */
   virtual nsIContent* FindFirstNonChromeOnlyAccessContent() const;
 
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -122,18 +122,38 @@ enum {
   // in the document and therefore should get bindings attached.
   NODE_FORCE_XBL_BINDINGS =               NODE_FLAG_BIT(5),
 
   // Whether a binding manager may have a pointer to this
   NODE_MAY_BE_IN_BINDING_MNGR =           NODE_FLAG_BIT(6),
 
   NODE_IS_EDITABLE =                      NODE_FLAG_BIT(7),
 
-  // Bit that will soon be used for other things.
-  THIS_BIT_BELONGS_TO_BHOLLEY =           NODE_FLAG_BIT(8),
+  // This node was created by layout as native anonymous content. This
+  // generally corresponds to things created by nsIAnonymousContentCreator,
+  // though there are exceptions (svg:use content does not have this flag
+  // set, and any non-nsIAnonymousContentCreator callers of
+  // SetIsNativeAnonymousRoot also get this flag).
+  //
+  // One very important aspect here is that this node is not transitive over
+  // the subtree (if you want that, use NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE).
+  // If Gecko code somewhere attaches children to a node with this bit set,
+  // the children will not have the bit themselves unless the calling code sets
+  // it explicitly. This means that XBL content bound to NAC doesn't get this
+  // bit, nor do nodes inserted by editor.
+  //
+  // For now, this bit exists primarily to control style inheritance behavior,
+  // since the nodes for which we set it are often used to implement pseudo-
+  // elements, which need to inherit style from a script-visible element.
+  //
+  // A more general principle for this bit might be this: If the node is entirely
+  // a detail of layout, is not script-observable in any way, and other engines
+  // might accomplish the same task with a nodeless layout frame, then the node
+  // should have this bit set.
+  NODE_IS_NATIVE_ANONYMOUS =              NODE_FLAG_BIT(8),
 
   // Whether the node participates in a shadow tree.
   NODE_IS_IN_SHADOW_TREE =                NODE_FLAG_BIT(9),
 
   // Node has an :empty or :-moz-only-whitespace selector
   NODE_HAS_EMPTY_SELECTOR =               NODE_FLAG_BIT(10),
 
   // A child of the node has a selector such that any insertion,
@@ -1166,16 +1186,25 @@ public:
 #ifdef MOZILLA_INTERNAL_API
     return IsEditableInternal();
 #else
     return IsEditableExternal();
 #endif
   }
 
   /**
+   * Returns true if |this| is native anonymous (i.e. created by
+   * nsIAnonymousContentCreator);
+   */
+  bool IsNativeAnonymous() const
+  {
+    return HasFlag(NODE_IS_NATIVE_ANONYMOUS);
+  }
+
+  /**
    * Returns true if |this| or any of its ancestors is native anonymous.
    */
   bool IsInNativeAnonymousSubtree() const
   {
 #ifdef DEBUG
     if (HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE)) {
       return true;
     }
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -4182,16 +4182,23 @@ ConnectAnonymousTreeDescendants(nsIConte
     NS_ASSERTION(content, "null anonymous content?");
 
     ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
 
     aParent->AppendChildTo(content, false);
   }
 }
 
+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,
                                            nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
 {
   nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
   if (!creator)
     return NS_OK;
@@ -4203,25 +4210,26 @@ nsCSSFrameConstructor::GetAnonymousConte
   }
 
   uint32_t count = aContent.Length();
   for (uint32_t i=0; i < count; i++) {
     // get our child's content and set its parent to our content
     nsIContent* content = aContent[i].mContent;
     NS_ASSERTION(content, "null anonymous content?");
 
+    ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
+
     // least-surprise CSS binding until we do the SVG specified
     // cascading rules for <svg:use> - bug 265894
     if (aParentFrame->GetType() == nsGkAtoms::svgUseFrame) {
       content->SetFlags(NODE_IS_ANONYMOUS_ROOT);
     } else {
       content->SetIsNativeAnonymousRoot();
-    }
-
-    ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
+      SetNativeAnonymousBitOnDescendants(content);
+    }
 
     bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
 
     // If the parent is in a shadow tree, make sure we don't
     // bind with a document because shadow roots and its descendants
     // are not in document.
     nsIDocument* bindDocument =
       aParent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;