Bug 1549751 - Part 1: Add nsDisplayList::Iterator r=mattwoodrow
authorMiko Mynttinen <mikokm@gmail.com>
Wed, 08 May 2019 14:11:40 +0000
changeset 531886 61e59c0325ddeba0bfe6a3624a60d0e7150ac632
parent 531885 1c914f89d39582a35e96e22542cd4fd99e2dc663
child 531887 69a48ceb1ecb6c0857a5a258d653be3b0a7b93b6
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1549751
milestone68.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 1549751 - Part 1: Add nsDisplayList::Iterator r=mattwoodrow Differential Revision: https://phabricator.services.mozilla.com/D30224
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1533,17 +1533,17 @@ void nsDisplayListBuilder::EnterPresShel
   if (state->mCaretFrame) {
     MarkFrameForDisplay(state->mCaretFrame, aReferenceFrame);
   }
 }
 
 // A non-blank paint is a paint that does not just contain the canvas
 // background.
 static bool DisplayListIsNonBlank(nsDisplayList* aList) {
-  for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) {
+  for (nsDisplayItem* i : *aList) {
     switch (i->GetType()) {
       case DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO:
       case DisplayItemType::TYPE_CANVAS_BACKGROUND_COLOR:
       case DisplayItemType::TYPE_CANVAS_BACKGROUND_IMAGE:
         continue;
       case DisplayItemType::TYPE_SOLID_COLOR:
       case DisplayItemType::TYPE_BACKGROUND:
       case DisplayItemType::TYPE_BACKGROUND_COLOR:
@@ -1561,17 +1561,17 @@ static bool DisplayListIsNonBlank(nsDisp
 // A contentful paint is a paint that does contains DOM content (text,
 // images, non-blank canvases, SVG): "First Contentful Paint entry
 // contains a DOMHighResTimeStamp reporting the time when the browser
 // first rendered any text, image (including background images),
 // non-white canvas or SVG. This excludes any content of iframes, but
 // includes text with pending webfonts. This is the first time users
 // could start consuming page content."
 static bool DisplayListIsContentful(nsDisplayList* aList) {
-  for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) {
+  for (nsDisplayItem* i : *aList) {
     DisplayItemType type = i->GetType();
     nsDisplayList* children = i->GetChildren();
 
     switch (type) {
       case DisplayItemType::TYPE_SUBDOCUMENT:  // iframes are ignored
         break;
       // CANVASes check if they may have been modified (as a stand-in
       // actually tracking all modifications)
@@ -2421,44 +2421,44 @@ static void MoveListTo(nsDisplayList* aL
   nsDisplayItem* item;
   while ((item = aList->RemoveBottom()) != nullptr) {
     aElements->AppendElement(item);
   }
 }
 
 nsRect nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
   nsRect bounds;
-  for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
+  for (nsDisplayItem* i : *this) {
     bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder));
   }
   return bounds;
 }
 
 nsRect nsDisplayList::GetClippedBoundsWithRespectToASR(
     nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR,
     nsRect* aBuildingRect) const {
   nsRect bounds;
-  for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
+  for (nsDisplayItem* i : *this) {
     nsRect r = i->GetClippedBounds(aBuilder);
     if (aASR != i->GetActiveScrolledRoot() && !r.IsEmpty()) {
       if (Maybe<nsRect> clip = i->GetClipWithRespectToASR(aBuilder, aASR)) {
         r = clip.ref();
       }
     }
     if (aBuildingRect) {
       aBuildingRect->UnionRect(*aBuildingRect, i->GetBuildingRect());
     }
     bounds.UnionRect(bounds, r);
   }
   return bounds;
 }
 
 nsRect nsDisplayList::GetBuildingRect() const {
   nsRect result;
-  for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
+  for (nsDisplayItem* i : *this) {
     result.UnionRect(result, i->GetBuildingRect());
   }
   return result;
 }
 
 bool nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
                                              nsRegion* aVisibleRegion) {
   AUTO_PROFILER_LABEL("nsDisplayList::ComputeVisibilityForRoot", GRAPHICS);
@@ -3008,31 +3008,31 @@ static void FlushFramesArray(nsTArray<Fr
 
 void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                             nsDisplayItem::HitTestState* aState,
                             nsTArray<nsIFrame*>* aOutFrames) const {
   nsDisplayItem* item;
 
   if (aState->mInPreserves3D) {
     // Collect leaves of the current 3D rendering context.
-    for (item = GetBottom(); item; item = item->GetAbove()) {
+    for (nsDisplayItem* item : *this) {
       auto itemType = item->GetType();
       if (itemType != DisplayItemType::TYPE_TRANSFORM ||
           !static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
         item->HitTest(aBuilder, aRect, aState, aOutFrames);
       } else {
         // One of leaves in the current 3D rendering context.
         aState->mItemBuffer.AppendElement(item);
       }
     }
     return;
   }
 
   int32_t itemBufferStart = aState->mItemBuffer.Length();
-  for (item = GetBottom(); item; item = item->GetAbove()) {
+  for (nsDisplayItem* item : *this) {
     aState->mItemBuffer.AppendElement(item);
   }
 
   AutoTArray<FramesWithDepth, 16> temp;
   for (int32_t i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart;
        --i) {
     // Pop element off the end of the buffer. We want to shorten the buffer
     // so that recursive calls to HitTest have more buffer space.
@@ -5820,17 +5820,17 @@ void nsDisplayWrapList::Paint(nsDisplayL
  * PaintedLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
  * and they all have the expected animated geometry root.
  */
 static LayerState RequiredLayerStateForChildren(
     nsDisplayListBuilder* aBuilder, LayerManager* aManager,
     const ContainerLayerParameters& aParameters, const nsDisplayList& aList,
     AnimatedGeometryRoot* aExpectedAnimatedGeometryRootForChildren) {
   LayerState result = LAYER_INACTIVE;
-  for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
+  for (nsDisplayItem* i : aList) {
     if (result == LAYER_INACTIVE &&
         i->GetAnimatedGeometryRoot() !=
             aExpectedAnimatedGeometryRootForChildren) {
       result = LAYER_ACTIVE;
     }
 
     LayerState state = i->GetLayerState(aBuilder, aManager, aParameters);
     if (state == LAYER_ACTIVE &&
@@ -6060,17 +6060,17 @@ static const size_t kOpacityMaxListSize 
 static bool CollectItemsWithOpacity(nsDisplayList* aList,
                                     nsTArray<nsDisplayItem*>& aArray) {
   if (aList->Count() > kOpacityMaxListSize) {
     // Exit early, since |aList| will likely contain more than
     // |kOpacityMaxChildCount| items.
     return false;
   }
 
-  for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
+  for (nsDisplayItem* i : *aList) {
     const DisplayItemType type = i->GetType();
 
     // Descend only into wraplists.
     if (type == DisplayItemType::TYPE_WRAP_LIST) {
       // The current display item has children, process them first.
       if (!CollectItemsWithOpacity(i->GetChildren(), aArray)) {
         return false;
       }
@@ -8415,17 +8415,17 @@ void nsDisplayTransform::ComputeBounds(n
    * The bounds are transformed with the accumulated transformation matrix up to
    * the 3D context root coordinate space.
    */
   nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
   accTransform.Accumulate(GetTransform().GetMatrix());
 
   // Do not dive into another 3D context.
   if (!IsLeafOf3DContext()) {
-    for (nsDisplayItem* i = GetChildren()->GetBottom(); i; i = i->GetAbove()) {
+    for (nsDisplayItem* i : *GetChildren()) {
       i->DoUpdateBoundsPreserves3D(aBuilder);
     }
   }
 
   /* The child transforms that extend 3D context further will have empty bounds,
    * so the untransformed bounds here is the bounds of all the non-preserve-3d
    * content under this transform.
    */
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3175,16 +3175,51 @@ class nsDisplayItem : public nsDisplayIt
  */
 class nsDisplayList {
  public:
   typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::PaintedLayer PaintedLayer;
 
+  template <typename T>
+  class Iterator {
+   public:
+    Iterator() : mItem(nullptr) {}
+    ~Iterator() = default;
+    Iterator(const Iterator& aOther) = default;
+    Iterator& operator=(const Iterator& aOther) = default;
+
+    explicit Iterator(const nsDisplayList* aList) : mItem(aList->GetBottom()) {}
+    explicit Iterator(const nsDisplayItem* aItem) : mItem(aItem) {}
+
+    Iterator& operator++() {
+      mItem = mItem ? mItem->GetAbove() : mItem;
+      return *this;
+    }
+
+    bool operator==(const Iterator& aOther) const {
+      return mItem == aOther.mItem;
+    }
+
+    bool operator!=(const Iterator& aOther) const {
+      return !operator==(aOther);
+    }
+
+    T* operator*() { return mItem; }
+
+   private:
+    T* mItem;
+  };
+
+  using DisplayItemIterator = Iterator<nsDisplayItem>;
+
+  DisplayItemIterator begin() const { return DisplayItemIterator(this); }
+  DisplayItemIterator end() const { return DisplayItemIterator(); }
+
   /**
    * Create an empty list.
    */
   nsDisplayList()
       : mLength(0), mIsOpaque(false), mForceTransparentSurface(false) {
     mTop = &mSentinel;
     mSentinel.mAbove = nullptr;
   }
@@ -3486,28 +3521,28 @@ class nsDisplayList {
       nsRect* aBuildingRect = nullptr) const;
 
   /**
    * Returns the opaque region of this display list.
    */
   nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder) {
     nsRegion result;
     bool snap;
-    for (nsDisplayItem* item = GetBottom(); item; item = item->GetAbove()) {
+    for (nsDisplayItem* item : *this) {
       result.OrWith(item->GetOpaqueRegion(aBuilder, &snap));
     }
     return result;
   }
 
   /**
    * Returns the bounds of the area that needs component alpha.
    */
   nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const {
     nsRect bounds;
-    for (nsDisplayItem* item = GetBottom(); item; item = item->GetAbove()) {
+    for (nsDisplayItem* item : *this) {
       bounds.UnionRect(bounds, item->GetComponentAlphaBounds(aBuilder));
     }
     return bounds;
   }
 
   /**
    * Find the topmost display item that returns a non-null frame, and return
    * the frame.