Bug 1239864 (part 1) - Add new, nicer rect-iterators for nsRegion and nsIntRegion. r=roc.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 14 Jan 2016 18:36:11 -0800
changeset 304796 dbfd0199b5c78985881f84221a1a06491bf2e46c
parent 304795 d57e965c2f567a8a2fbb5c227a5a48e8e67ef83a
child 304797 17073770898507418ace502f1f25cadaff037c3e
push id9214
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:25:21 +0000
treeherdermozilla-aurora@8849dd1a4a79 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1239864
milestone47.0a1
Bug 1239864 (part 1) - Add new, nicer rect-iterators for nsRegion and nsIntRegion. r=roc. This requires renaming the existing nsIntRegion::RectIterator as nsIntRegion::OldRectIterator to make way for the new nsIntRegion::RectIterator. This doesn't require many knock-on changes because most existing uses of that type use the nsIntRegionRectIterator typedef.
gfx/ipc/GfxMessageUtils.h
gfx/layers/LayersLogging.h
gfx/layers/basic/BasicCompositor.cpp
gfx/layers/ipc/CompositorChild.cpp
gfx/src/nsRegion.h
widget/PuppetWidget.cpp
widget/cocoa/VibrancyManager.mm
widget/cocoa/nsChildView.mm
widget/nsBaseWidget.cpp
widget/nsShmImage.cpp
widget/uikit/nsWindow.mm
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -388,17 +388,17 @@ struct RegionParamTraits
     return false;
   }
 };
 
 template<class Units>
 struct ParamTraits<mozilla::gfx::IntRegionTyped<Units>>
   : RegionParamTraits<mozilla::gfx::IntRegionTyped<Units>,
                       mozilla::gfx::IntRectTyped<Units>,
-                      typename mozilla::gfx::IntRegionTyped<Units>::RectIterator>
+                      typename mozilla::gfx::IntRegionTyped<Units>::OldRectIterator>
 {};
 
 template<>
 struct ParamTraits<mozilla::gfx::IntSize>
 {
   typedef mozilla::gfx::IntSize paramType;
 
   static void Write(Message* msg, const paramType& param)
--- a/gfx/layers/LayersLogging.h
+++ b/gfx/layers/LayersLogging.h
@@ -97,17 +97,17 @@ template <typename units>
 void
 AppendToString(std::stringstream& aStream, const mozilla::gfx::IntRegionTyped<units>& r,
                const char* pfx="", const char* sfx="")
 {
   typedef mozilla::gfx::IntRegionTyped<units> RegionType;
 
   aStream << pfx;
 
-  typename RegionType::RectIterator it(r);
+  typename RegionType::OldRectIterator it(r);
   aStream << "< ";
   while (const typename RegionType::RectType* sr = it.Next()) {
     AppendToString(aStream, *sr);
     aStream << "; ";
   }
   aStream << ">";
 
   aStream << sfx;
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -621,17 +621,17 @@ BasicCompositor::EndFrame()
   RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
   RefPtr<DrawTarget> dest(mTarget ? mTarget : mDrawTarget);
 
   nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint();
 
   // The source DrawTarget is clipped to the invalidation region, so we have
   // to copy the individual rectangles in the region or else we'll draw blank
   // pixels.
-  LayoutDeviceIntRegion::RectIterator iter(mInvalidRegion);
+  LayoutDeviceIntRegion::OldRectIterator iter(mInvalidRegion);
   for (const LayoutDeviceIntRect *r = iter.Next(); r; r = iter.Next()) {
     dest->CopySurface(source,
                       IntRect(r->x - mInvalidRect.x, r->y - mInvalidRect.y, r->width, r->height),
                       IntPoint(r->x - offset.x, r->y - offset.y));
   }
   if (!mTarget) {
     mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
   }
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -229,17 +229,17 @@ static void CalculatePluginClip(const La
   region.MoveBy(-aContentOffset.x, -aContentOffset.y);
   contentVisibleRegion.AndWith(region);
   if (contentVisibleRegion.IsEmpty()) {
     aPluginIsVisible = false;
     return;
   }
   // shift to plugin widget origin
   contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y);
-  LayoutDeviceIntRegion::RectIterator iter(contentVisibleRegion);
+  LayoutDeviceIntRegion::OldRectIterator iter(contentVisibleRegion);
   for (const LayoutDeviceIntRect* rgnRect = iter.Next(); rgnRect; rgnRect = iter.Next()) {
     aResult.AppendElement(*rgnRect);
     aVisibleBounds.UnionRect(aVisibleBounds, *rgnRect);
   }
 }
 #endif
 
 bool
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -346,16 +346,55 @@ public:
    * visitFn has a side parameter that can be TOP,BOTTOM,LEFT,RIGHT
    * and specifies which kind of edge is being visited. x1, y1, x2, y2
    * are the coordinates of the line. (x1 == x2) || (y1 == y2)
    */
   typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
   void VisitEdges(visitFn, void *closure);
 
   nsCString ToString() const;
+
+  class RectIterator
+  {
+    int mCurrent;               // Index of the current entry
+    int mLimit;                 // Index one past the final entry.
+    mutable nsRect mTmp;        // The most recently gotten rectangle.
+    pixman_box32_t *mBoxes;
+
+  public:
+    explicit RectIterator(const nsRegion& aRegion)
+    {
+      mCurrent = 0;
+      mBoxes = pixman_region32_rectangles(aRegion.Impl(), &mLimit);
+      // Work around pixman bug. Sometimes pixman creates regions with 1 rect
+      // that's empty.
+      if (mLimit == 1 && nsRegion::BoxToRect(mBoxes[0]).IsEmpty()) {
+        mLimit = 0;
+      }
+    }
+
+    bool Done() const { return mCurrent == mLimit; }
+
+    const nsRect& Get() const
+    {
+      MOZ_ASSERT(!Done());
+      mTmp = nsRegion::BoxToRect(mBoxes[mCurrent]);
+      NS_ASSERTION(!mTmp.IsEmpty(), "Shouldn't return empty rect");
+      return mTmp;
+    }
+
+    void Next()
+    {
+      MOZ_ASSERT(!Done());
+      mCurrent++;
+    }
+  };
+
+  RectIterator RectIter() const { return RectIterator(*this); }
+
 private:
   pixman_region32_t mImpl;
 
 #ifndef MOZ_TREE_PIXMAN
   // For compatibility with pixman versions older than 0.25.2.
   static inline void
   pixman_region32_clear(pixman_region32_t *region)
   {
@@ -696,17 +735,17 @@ public:
     return mImpl.IsEqual (aRegion.mImpl);
   }
   uint32_t GetNumRects () const { return mImpl.GetNumRects (); }
   Rect GetBounds () const { return FromRect (mImpl.GetBounds ()); }
   uint64_t Area () const { return mImpl.Area(); }
   nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const
   {
     nsRegion result;
-    RectIterator rgnIter(*this);
+    OldRectIterator rgnIter(*this);
     const Rect* currentRect;
     while ((currentRect = rgnIter.Next())) {
       nsRect appRect = ::ToAppUnits(*currentRect, aAppUnitsPerPixel);
       result.Or(result, appRect);
     }
     return result;
   }
   Rect GetLargestRectangle (const Rect& aContainingRect = Rect()) const
@@ -763,23 +802,24 @@ public:
   typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
   void VisitEdges (visitFn visit, void *closure)
   {
     mImpl.VisitEdges (visit, closure);
   }
 
   nsCString ToString() const { return mImpl.ToString(); }
 
-  class RectIterator
+  // XXX: this is going away soon in favour of RectIterator
+  class OldRectIterator
   {
     nsRegionRectIterator mImpl;
     Rect mTmp;
 
   public:
-    explicit RectIterator (const BaseIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
+    explicit OldRectIterator (const BaseIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
 
     const Rect* Next ()
     {
       const nsRect* r = mImpl.Next();
       if (!r)
         return nullptr;
       mTmp = FromRect (*r);
       return &mTmp;
@@ -795,16 +835,39 @@ public:
     }
 
     void Reset ()
     {
       mImpl.Reset ();
     }
   };
 
+  class RectIterator
+  {
+    nsRegion::RectIterator mImpl; // The underlying iterator.
+    mutable Rect mTmp;            // The most recently gotten rectangle.
+
+  public:
+    explicit RectIterator(const BaseIntRegion& aRegion)
+      : mImpl(aRegion.mImpl)
+    {}
+
+    bool Done() const { return mImpl.Done(); }
+
+    const Rect& Get() const
+    {
+      mTmp = FromRect(mImpl.Get());
+      return mTmp;
+    }
+
+    void Next() { mImpl.Next(); }
+  };
+
+  RectIterator RectIter() const { return RectIterator(*this); }
+
 protected:
   // Expose enough to derived classes from them to define conversions
   // between different types of BaseIntRegions.
   explicit BaseIntRegion(const nsRegion& aImpl) : mImpl(aImpl) {}
   const nsRegion& Impl() const { return mImpl; }
 private:
   nsRegion mImpl;
 
@@ -870,11 +933,11 @@ private:
   // This is deliberately private, so calling code uses FromUnknownRegion().
   explicit IntRegionTyped(const nsRegion& aRegion) : Super(aRegion) {}
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 typedef mozilla::gfx::IntRegion nsIntRegion;
-typedef nsIntRegion::RectIterator nsIntRegionRectIterator;
+typedef nsIntRegion::OldRectIterator nsIntRegionRectIterator;
 
 #endif
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -27,17 +27,17 @@ using namespace mozilla::dom;
 using namespace mozilla::hal;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 
 static void
 InvalidateRegion(nsIWidget* aWidget, const LayoutDeviceIntRegion& aRegion)
 {
-  LayoutDeviceIntRegion::RectIterator it(aRegion);
+  LayoutDeviceIntRegion::OldRectIterator it(aRegion);
   while(const LayoutDeviceIntRect* r = it.Next()) {
     aWidget->Invalidate(*r);
   }
 }
 
 /*static*/ already_AddRefed<nsIWidget>
 nsIWidget::CreatePuppetWidget(TabChild* aTabChild)
 {
--- a/widget/cocoa/VibrancyManager.mm
+++ b/widget/cocoa/VibrancyManager.mm
@@ -23,17 +23,17 @@ VibrancyManager::UpdateVibrantRegion(Vib
   // as necessary. We try to update the geometry of existing views if
   // possible, or create new ones or remove old ones if the number of
   // rects in the region has changed.
 
   nsTArray<NSView*> viewsToRecycle;
   vr.effectViews.SwapElements(viewsToRecycle);
   // vr.effectViews is now empty.
 
-  LayoutDeviceIntRegion::RectIterator iter(aRegion);
+  LayoutDeviceIntRegion::OldRectIterator iter(aRegion);
   const LayoutDeviceIntRect* iterRect = nullptr;
   for (size_t i = 0; (iterRect = iter.Next()) || i < viewsToRecycle.Length(); ++i) {
     if (iterRect) {
       NSView* view = nil;
       NSRect rect = mCoordinateConverter.DevPixelsToCocoaPoints(*iterRect);
       if (i < viewsToRecycle.Length()) {
         view = viewsToRecycle[i];
         [view setFrame:rect];
@@ -66,17 +66,17 @@ VibrancyManager::ClearVibrantAreas() con
   }
 }
 
 void
 VibrancyManager::ClearVibrantRegion(const VibrantRegion& aVibrantRegion) const
 {
   [[NSColor clearColor] set];
 
-  LayoutDeviceIntRegion::RectIterator iter(aVibrantRegion.region);
+  LayoutDeviceIntRegion::OldRectIterator iter(aVibrantRegion.region);
   while (const LayoutDeviceIntRect* rect = iter.Next()) {
     NSRectFill(mCoordinateConverter.DevPixelsToCocoaPoints(*rect));
   }
 }
 
 @interface NSView(CurrentFillColor)
 - (NSColor*)_currentFillColor;
 @end
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -3748,17 +3748,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
     gfx::Factory::CreateDrawTargetForCairoCGContext(aContext,
                                                     gfx::IntSize(backingSize.width,
                                                                  backingSize.height));
   MOZ_ASSERT(dt); // see implementation
   dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
   RefPtr<gfxContext> targetContext = new gfxContext(dt);
 
   // Set up the clip region.
-  LayoutDeviceIntRegion::RectIterator iter(region);
+  LayoutDeviceIntRegion::OldRectIterator iter(region);
   targetContext->NewPath();
   for (;;) {
     const LayoutDeviceIntRect* r = iter.Next();
     if (!r)
       break;
     targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
   }
   targetContext->Clip();
@@ -4627,17 +4627,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
   return NSRectToCGRect(inWindowCoords);
 }
 
 static CGSRegionObj
 NewCGSRegionFromRegion(const LayoutDeviceIntRegion& aRegion,
                        CGRect (^aRectConverter)(const LayoutDeviceIntRect&))
 {
   nsTArray<CGRect> rects;
-  LayoutDeviceIntRegion::RectIterator iter(aRegion);
+  LayoutDeviceIntRegion::OldRectIterator iter(aRegion);
   for (;;) {
     const LayoutDeviceIntRect* r = iter.Next();
     if (!r) {
       break;
     }
     rects.AppendElement(aRectConverter(*r));
   }
 
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -753,17 +753,17 @@ nsBaseWidget::RegionFromArray(const nsTA
   return region;
 }
 
 void
 nsBaseWidget::ArrayFromRegion(const LayoutDeviceIntRegion& aRegion,
                               nsTArray<LayoutDeviceIntRect>& aRects)
 {
   const LayoutDeviceIntRect* r;
-  for (LayoutDeviceIntRegion::RectIterator iter(aRegion); (r = iter.Next()); ) {
+  for (LayoutDeviceIntRegion::OldRectIterator iter(aRegion); (r = iter.Next()); ) {
     aRects.AppendElement(*r);
   }
 }
 
 nsresult
 nsBaseWidget::SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
                                   bool aIntersectWithExisting)
 {
--- a/widget/nsShmImage.cpp
+++ b/widget/nsShmImage.cpp
@@ -137,17 +137,17 @@ nsShmImage::CreateDrawTarget()
 void
 nsShmImage::Put(Display* aDisplay, Drawable aWindow,
                 const LayoutDeviceIntRegion& aRegion)
 {
     GC gc = XCreateGC(aDisplay, aWindow, 0, nullptr);
     LayoutDeviceIntRegion bounded;
     bounded.And(aRegion,
                 LayoutDeviceIntRect(0, 0, mImage->width, mImage->height));
-    LayoutDeviceIntRegion::RectIterator iter(bounded);
+    LayoutDeviceIntRegion::OldRectIterator iter(bounded);
     for (const LayoutDeviceIntRect *r = iter.Next(); r; r = iter.Next()) {
         XShmPutImage(aDisplay, aWindow, gc, mImage,
                      r->x, r->y,
                      r->x, r->y,
                      r->width, r->height,
                      False);
     }
 
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -372,17 +372,17 @@ private:
                                                                           backingSize.height));
     dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
     targetContext = new gfxContext(dt);
   } else {
     MOZ_ASSERT_UNREACHABLE("COREGRAPHICS is the only supported backed");
   }
 
   // Set up the clip region.
-  LayoutDeviceIntRegion::RectIterator iter(region);
+  LayoutDeviceIntRegion::OldRectIterator iter(region);
   targetContext->NewPath();
   for (;;) {
     const LayoutDeviceIntRect* r = iter.Next();
     if (!r)
       break;
     targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
   }
   targetContext->Clip();