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 281823 dbfd0199b5c78985881f84221a1a06491bf2e46c
parent 281822 d57e965c2f567a8a2fbb5c227a5a48e8e67ef83a
child 281824 17073770898507418ace502f1f25cadaff037c3e
push id29948
push usercbook@mozilla.com
push dateWed, 27 Jan 2016 11:00:24 +0000
treeherdermozilla-central@211a4c710fb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1239864
milestone47.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 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();