Bug 1321284 - Part 1: Make StyleChildrenIterator skip NAC generated by root element primary frame ancestors. r=bholley draft
authorCameron McCormack <cam@mcc.id.au>
Thu, 01 Dec 2016 11:34:57 +0800
changeset 447232 7c5a533ada4eaa9839ca0497426f2c9c2a2d6c0b
parent 447231 6e9571d8b6a3033f33bca1c1655d13e2f9364474
child 447233 7e0d8f40ce513283f7262dca332fddc1e92ff810
push id38025
push userbmo:cam@mcc.id.au
push dateSat, 03 Dec 2016 06:57:28 +0000
reviewersbholley
bugs1321284
milestone53.0a1
Bug 1321284 - Part 1: Make StyleChildrenIterator skip NAC generated by root element primary frame ancestors. r=bholley MozReview-Commit-ID: HICYWQgkE77
dom/base/ChildIterator.cpp
dom/base/ChildIterator.h
dom/base/nsIContent.h
layout/generic/nsIAnonymousContentCreator.h
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -378,17 +378,20 @@ AllChildrenIterator::Seek(nsIContent* aC
 
 void
 AllChildrenIterator::AppendNativeAnonymousChildren()
 {
   AppendNativeAnonymousChildrenFromFrame(mOriginalContent->GetPrimaryFrame());
 
   // The root scroll frame is not the primary frame of the root element.
   // Detect and handle this case.
-  if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
+  //
+  // XXXheycam This probably needs to find the nsCanvasFrame's NAC too.
+  if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
+      mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
     nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
     nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
     if (scrollFrame) {
       AppendNativeAnonymousChildrenFromFrame(scrollFrame);
     }
   }
 }
 
@@ -580,22 +583,16 @@ StyleChildrenIterator::IsNeeded(const El
   }
 
   // If the node has native anonymous content, return true.
   nsIAnonymousContentCreator* ac = do_QueryFrame(aElement->GetPrimaryFrame());
   if (ac) {
     return true;
   }
 
-  // The root element has a scroll frame that is not the primary frame, so we
-  // need to do special checking for that case.
-  if (aElement == aElement->OwnerDoc()->GetRootElement()) {
-    return true;
-  }
-
   return false;
 }
 
 
 nsIContent*
 StyleChildrenIterator::GetNextChild()
 {
   while (nsIContent* child = AllChildrenIterator::GetNextChild()) {
--- a/dom/base/ChildIterator.h
+++ b/dom/base/ChildIterator.h
@@ -251,28 +251,32 @@ private:
   // there's no easy way to do that.
   nsMutationGuard mMutationGuard;
 #endif
 };
 
 /**
  * StyleChildrenIterator traverses the children of the element from the
  * perspective of the style system, particularly the children we need to traverse
- * during restyle. This is identical to AllChildrenIterator with eAllChildren,
- * _except_ that we detect and skip any native anonymous children that are used
- * to implement pseudo-elements (since the style system needs to cascade those
- * using different algorithms).
+ * during restyle. This is identical to AllChildrenIterator with
+ * (eAllChildren | eSkipDocumentLevelNativeAnonymousContent), _except_ that we
+ * detect and skip any native anonymous children that are used to implement
+ * pseudo-elements (since the style system needs to cascade those using
+ * different algorithms).
  *
  * Note: it assumes that no mutation of the DOM or frame tree takes place during
  * iteration, and will break horribly if that is not true.
  */
-class StyleChildrenIterator : private AllChildrenIterator {
+class StyleChildrenIterator : private AllChildrenIterator
+{
 public:
   explicit StyleChildrenIterator(const nsIContent* aContent)
-    : AllChildrenIterator(aContent, nsIContent::eAllChildren)
+    : AllChildrenIterator(aContent,
+                          nsIContent::eAllChildren |
+                          nsIContent::eSkipDocumentLevelNativeAnonymousContent)
   {
     MOZ_COUNT_CTOR(StyleChildrenIterator);
   }
   ~StyleChildrenIterator() { MOZ_COUNT_DTOR(StyleChildrenIterator); }
 
   nsIContent* GetNextChild();
 
   // Returns true if we cannot find all the children we need to style by
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -140,17 +140,24 @@ public:
      *   4. :after generated node
      */
     eAllButXBL = 1,
 
     /**
      * Skip native anonymous content created for placeholder of HTML input,
      * used in conjunction with eAllChildren or eAllButXBL.
      */
-    eSkipPlaceholderContent = 2
+    eSkipPlaceholderContent = 2,
+
+    /**
+     * Skip native anonymous content created by ancestor frames of the root
+     * element's primary frame, such as scrollbar elements created by the root
+     * scroll frame.
+     */
+    eSkipDocumentLevelNativeAnonymousContent = 4,
   };
 
   /**
    * Return either the XBL explicit children of the node or the XBL flattened
    * tree children of the node, depending on the filter, as well as
    * native anonymous children.
    *
    * @note calling this method with eAllButXBL will return children that are
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -61,17 +61,19 @@ public:
    *       that.
    */
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements)=0;
 
   /**
    * Appends "native" anonymous children created by CreateAnonymousContent()
    * to the given content list depending on the filter.
    *
-   * @see nsIContent::GetChildren for set of values used for filter.
+   * @see nsIContent::GetChildren for set of values used for filter.  Currently,
+   *   eSkipPlaceholderContent is the only flag that any implementation of
+   *   this method heeds.
    */
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) = 0;
 
   /**
    * Implementations can override this method to create special frames for the
    * anonymous content returned from CreateAnonymousContent.
    * By default this method returns nullptr, which means the default frame