Bug 1331322 - Add a flag to indicate that a node is native anonymous content. r=bholley
authorBobby Holley <bobbyholley@gmail.com>
Fri, 20 Jan 2017 18:28:46 -0800
changeset 343319 dd44bee444c5f2258ad485dcb438f2ac2aefb05c
parent 343318 25419350a53769301628e02a08c98c98abb39266
child 343320 4c84e0a380ecab34ff9ae9a1208441ee28514e69
push id31377
push usercbook@mozilla.com
push dateFri, 17 Feb 2017 11:41:48 +0000
treeherdermozilla-central@975ce5d8f7d8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1331322
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1331322 - Add a flag to indicate that a node is native anonymous content. r=bholley
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;