Bug 1059026 - Replace imgFrame::mOffset and imgFrame::mSize with imgFrame::mFrameRect. r=edwin
authorSeth Fowler <mark.seth.fowler@gmail.com>
Thu, 26 May 2016 22:19:38 -0700
changeset 340277 d452f7cdc61e607a53c996798a14d93ab9d30378
parent 340276 46935fd55a7ff9218c16b7b03d5e90d7f8168014
child 340278 1bc7102718a99bc960054cbad9f178df932234c8
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1059026
milestone49.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 1059026 - Replace imgFrame::mOffset and imgFrame::mSize with imgFrame::mFrameRect. r=edwin
image/imgFrame.cpp
image/imgFrame.h
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -181,18 +181,17 @@ imgFrame::InitForDecoder(const nsIntSize
   // warn for properties related to bad content.
   if (!AllowedImageAndFrameDimensions(aImageSize, aRect)) {
     NS_WARNING("Should have legal image size");
     mAborted = true;
     return NS_ERROR_FAILURE;
   }
 
   mImageSize = aImageSize;
-  mOffset.MoveTo(aRect.x, aRect.y);
-  mSize.SizeTo(aRect.width, aRect.height);
+  mFrameRect = aRect;
 
   mFormat = aFormat;
   mPaletteDepth = aPaletteDepth;
   mNonPremult = aNonPremult;
 
   if (aPaletteDepth != 0) {
     // We're creating for a paletted image.
     if (aPaletteDepth > 8) {
@@ -200,36 +199,35 @@ imgFrame::InitForDecoder(const nsIntSize
       NS_ERROR("This Depth is not supported");
       mAborted = true;
       return NS_ERROR_FAILURE;
     }
 
     // Use the fallible allocator here. Paletted images always use 1 byte per
     // pixel, so calculating the amount of memory we need is straightforward.
     mPalettedImageData =
-      static_cast<uint8_t*>(malloc(PaletteDataLength() +
-                                   (mSize.width * mSize.height)));
+      static_cast<uint8_t*>(malloc(PaletteDataLength() + mFrameRect.Area()));
     if (!mPalettedImageData) {
       NS_WARNING("malloc for paletted image data should succeed");
     }
     NS_ENSURE_TRUE(mPalettedImageData, NS_ERROR_OUT_OF_MEMORY);
   } else {
     MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitForDecoder() twice?");
 
-    mVBuf = AllocateBufferForImage(mSize, mFormat);
+    mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
     if (!mVBuf) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
     if (mVBuf->OnHeap()) {
-      int32_t stride = VolatileSurfaceStride(mSize, mFormat);
+      int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
       VolatileBufferPtr<uint8_t> ptr(mVBuf);
-      memset(ptr, 0, stride * mSize.height);
+      memset(ptr, 0, stride * mFrameRect.height);
     }
-    mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
+    mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
 
     if (!mImageSurface) {
       NS_WARNING("Failed to create VolatileDataSourceSurface");
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
@@ -247,73 +245,71 @@ imgFrame::InitWithDrawable(gfxDrawable* 
   // warn for properties related to bad content.
   if (!AllowedImageSize(aSize.width, aSize.height)) {
     NS_WARNING("Should have legal image size");
     mAborted = true;
     return NS_ERROR_FAILURE;
   }
 
   mImageSize = aSize;
-  mOffset.MoveTo(0, 0);
-  mSize.SizeTo(aSize.width, aSize.height);
+  mFrameRect = IntRect(IntPoint(0, 0), aSize);
 
   mFormat = aFormat;
   mPaletteDepth = 0;
 
   RefPtr<DrawTarget> target;
 
   bool canUseDataSurface =
     gfxPlatform::GetPlatform()->CanRenderContentToDataSurface();
 
   if (canUseDataSurface) {
     // It's safe to use data surfaces for content on this platform, so we can
     // get away with using volatile buffers.
     MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitWithDrawable() twice?");
 
-    mVBuf = AllocateBufferForImage(mSize, mFormat);
+    mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
     if (!mVBuf) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    int32_t stride = VolatileSurfaceStride(mSize, mFormat);
+    int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
     VolatileBufferPtr<uint8_t> ptr(mVBuf);
     if (!ptr) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
     if (mVBuf->OnHeap()) {
-      memset(ptr, 0, stride * mSize.height);
+      memset(ptr, 0, stride * mFrameRect.height);
     }
-    mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
+    mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
 
     target = gfxPlatform::GetPlatform()->
-      CreateDrawTargetForData(ptr, mSize, stride, mFormat);
+      CreateDrawTargetForData(ptr, mFrameRect.Size(), stride, mFormat);
   } else {
     // We can't use data surfaces for content, so we'll create an offscreen
     // surface instead.  This means if someone later calls RawAccessRef(), we
     // may have to do an expensive readback, but we warned callers about that in
     // the documentation for this method.
     MOZ_ASSERT(!mOptSurface, "Called imgFrame::InitWithDrawable() twice?");
 
     target = gfxPlatform::GetPlatform()->
-      CreateOffscreenContentDrawTarget(mSize, mFormat);
+      CreateOffscreenContentDrawTarget(mFrameRect.Size(), mFormat);
   }
 
   if (!target || !target->IsValid()) {
     mAborted = true;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // Draw using the drawable the caller provided.
-  nsIntRect imageRect(0, 0, mSize.width, mSize.height);
   RefPtr<gfxContext> ctx = gfxContext::ForDrawTarget(target);
-  MOZ_ASSERT(ctx); // already checked the draw target above
-  gfxUtils::DrawPixelSnapped(ctx, aDrawable, mSize,
-                             ImageRegion::Create(ThebesRect(imageRect)),
+  MOZ_ASSERT(ctx);  // Already checked the draw target above.
+  gfxUtils::DrawPixelSnapped(ctx, aDrawable, mFrameRect.Size(),
+                             ImageRegion::Create(ThebesRect(mFrameRect)),
                              mFormat, aFilter, aImageFlags);
 
   if (canUseDataSurface && !mImageSurface) {
     NS_WARNING("Failed to create VolatileDataSourceSurface");
     mAborted = true;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
@@ -360,20 +356,20 @@ imgFrame::Optimize()
   // Cairo doesn't support non-premult single-colors.
   if (mNonPremult) {
     return NS_OK;
   }
 
   /* Figure out if the entire image is a constant color */
 
   if (gfxPrefs::ImageSingleColorOptimizationEnabled() &&
-      mImageSurface->Stride() == mSize.width * 4) {
+      mImageSurface->Stride() == mFrameRect.width * 4) {
     uint32_t* imgData = (uint32_t*) ((uint8_t*) mVBufPtr);
     uint32_t firstPixel = * (uint32_t*) imgData;
-    uint32_t pixelCount = mSize.width * mSize.height + 1;
+    uint32_t pixelCount = mFrameRect.Area() + 1;
 
     while (--pixelCount && *imgData++ == firstPixel)
       ;
 
     if (pixelCount == 0) {
       // all pixels were the same
       if (mFormat == SurfaceFormat::B8G8R8A8 ||
           mFormat == SurfaceFormat::B8G8R8X8) {
@@ -402,45 +398,45 @@ imgFrame::Optimize()
 
 #ifdef ANDROID
   SurfaceFormat optFormat = gfxPlatform::GetPlatform()
     ->Optimal2DFormatForContent(gfxContentType::COLOR);
 
   if (mFormat != SurfaceFormat::B8G8R8A8 &&
       optFormat == SurfaceFormat::R5G6B5_UINT16) {
     RefPtr<VolatileBuffer> buf =
-      AllocateBufferForImage(mSize, optFormat);
+      AllocateBufferForImage(mFrameRect.Size(), optFormat);
     if (!buf) {
       return NS_OK;
     }
 
     RefPtr<DataSourceSurface> surf =
-      CreateLockedSurface(buf, mSize, optFormat);
+      CreateLockedSurface(buf, mFrameRect.Size(), optFormat);
     if (!surf) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     DataSourceSurface::MappedSurface mapping;
     if (!surf->Map(DataSourceSurface::MapType::WRITE, &mapping)) {
       gfxCriticalError() << "imgFrame::Optimize failed to map surface";
       return NS_ERROR_FAILURE;
     }
 
     RefPtr<DrawTarget> target =
       Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                        mapping.mData,
-                                       mSize,
+                                       mFrameRect.Size(),
                                        mapping.mStride,
                                        optFormat);
 
     if (!target) {
       gfxWarning() << "imgFrame::Optimize failed in CreateDrawTargetForData";
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    Rect rect(0, 0, mSize.width, mSize.height);
+    Rect rect(0, 0, mFrameRect.width, mFrameRect.height);
     target->DrawSurface(mImageSurface, rect, rect);
     target->Flush();
     surf->Unmap();
 
     mImageSurface = surf;
     mVBuf = buf;
     mFormat = optFormat;
   }
@@ -541,17 +537,17 @@ imgFrame::SurfaceForDrawing(bool        
                              target->GetFormat());
   }
 
   // Not tiling, and we have a surface, so we can account for
   // padding and/or a partial decode just by twiddling parameters.
   gfxPoint paddingTopLeft(aPadding.left, aPadding.top);
   aRegion = aRegion.Intersect(available) - paddingTopLeft;
   aContext->Multiply(gfxMatrix::Translation(paddingTopLeft));
-  aImageRect = gfxRect(0, 0, mSize.width, mSize.height);
+  aImageRect = gfxRect(0, 0, mFrameRect.width, mFrameRect.height);
 
   IntSize availableSize(mDecoded.width, mDecoded.height);
   return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, availableSize),
                            mFormat);
 }
 
 bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
                     Filter aFilter, uint32_t aImageFlags)
@@ -563,20 +559,20 @@ bool imgFrame::Draw(gfxContext* aContext
   NS_ASSERTION(!aRegion.Rect().IsEmpty(), "Drawing empty region!");
   NS_ASSERTION(!aRegion.IsRestricted() ||
                !aRegion.Rect().Intersect(aRegion.Restriction()).IsEmpty(),
                "We must be allowed to sample *some* source pixels!");
   NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!");
 
   MonitorAutoLock lock(mMonitor);
 
-  nsIntMargin padding(mOffset.y,
-                      mImageSize.width - (mOffset.x + mSize.width),
-                      mImageSize.height - (mOffset.y + mSize.height),
-                      mOffset.x);
+  nsIntMargin padding(mFrameRect.y,
+                      mImageSize.width - mFrameRect.XMost(),
+                      mImageSize.height - mFrameRect.YMost(),
+                      mFrameRect.x);
 
   bool doPadding = padding != nsIntMargin(0,0,0,0);
   bool doPartialDecode = !AreAllPixelsWritten();
 
   if (mSinglePixel && !doPadding && !doPartialDecode) {
     if (mSinglePixelColor.a == 0.0) {
       return true;
     }
@@ -625,20 +621,19 @@ imgFrame::ImageUpdated(const nsIntRect& 
 
 nsresult
 imgFrame::ImageUpdatedInternal(const nsIntRect& aUpdateRect)
 {
   mMonitor.AssertCurrentThreadOwns();
 
   mDecoded.UnionRect(mDecoded, aUpdateRect);
 
-  // clamp to bounds, in case someone sends a bogus updateRect (I'm looking at
-  // you, gif decoder)
-  nsIntRect boundsRect(mOffset, mSize);
-  mDecoded.IntersectRect(mDecoded, boundsRect);
+  // Clamp to the frame rect to ensure that decoder bugs don't result in a
+  // decoded rect that extends outside the bounds of the frame rect.
+  mDecoded.IntersectRect(mDecoded, mFrameRect);
 
   return NS_OK;
 }
 
 void
 imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
                  DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */,
                  int32_t aRawTimeout /* = 0 */,
@@ -656,42 +651,36 @@ imgFrame::Finish(Opacity aFrameOpacity /
   mBlendMethod = aBlendMethod;
   ImageUpdatedInternal(GetRect());
   mFinished = true;
 
   // The image is now complete, wake up anyone who's waiting.
   mMonitor.NotifyAll();
 }
 
-nsIntRect
-imgFrame::GetRect() const
-{
-  return gfx::IntRect(mOffset, mSize);
-}
-
 uint32_t
 imgFrame::GetImageBytesPerRow() const
 {
   mMonitor.AssertCurrentThreadOwns();
 
   if (mVBuf) {
-    return mSize.width * BytesPerPixel(mFormat);
+    return mFrameRect.width * BytesPerPixel(mFormat);
   }
 
   if (mPaletteDepth) {
-    return mSize.width;
+    return mFrameRect.width;
   }
 
   return 0;
 }
 
 uint32_t
 imgFrame::GetImageDataLength() const
 {
-  return GetImageBytesPerRow() * mSize.height;
+  return GetImageBytesPerRow() * mFrameRect.height;
 }
 
 void
 imgFrame::GetImageData(uint8_t** aData, uint32_t* aLength) const
 {
   MonitorAutoLock lock(mMonitor);
   GetImageDataInternal(aData, aLength);
 }
@@ -837,17 +826,17 @@ imgFrame::UnlockImageData()
       return NS_OK;
     }
 
     // If we're using a surface format with alpha but the image has no alpha,
     // change the format. This doesn't change the underlying data at all, but
     // allows DrawTargets to avoid blending when drawing known opaque images.
     if (mHasNoAlpha && mFormat == SurfaceFormat::B8G8R8A8 && mImageSurface) {
       mFormat = SurfaceFormat::B8G8R8X8;
-      mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
+      mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
     }
 
     // Convert the data surface to a GPU surface or a single color if possible.
     // This will also release mImageSurface if possible.
     Optimize();
 
     // Allow the OS to release our data surface.
     mVBufPtr = nullptr;
@@ -910,17 +899,17 @@ imgFrame::GetSurfaceInternal()
     return nullptr;
   }
 
   VolatileBufferPtr<char> buf(mVBuf);
   if (buf.WasBufferPurged()) {
     return nullptr;
   }
 
-  return CreateLockedSurface(mVBuf, mSize, mFormat);
+  return CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
 }
 
 AnimationData
 imgFrame::GetAnimationData() const
 {
   MonitorAutoLock lock(mMonitor);
   MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
 
@@ -978,18 +967,17 @@ imgFrame::WaitUntilFinished() const
     mMonitor.Wait();
   }
 }
 
 bool
 imgFrame::AreAllPixelsWritten() const
 {
   mMonitor.AssertCurrentThreadOwns();
-  return mDecoded.IsEqualInterior(nsIntRect(mOffset.x, mOffset.y,
-                                            mSize.width, mSize.height));
+  return mDecoded.IsEqualInterior(mFrameRect);
 }
 
 bool imgFrame::GetCompositingFailed() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mCompositingFailed;
 }
 
--- a/image/imgFrame.h
+++ b/image/imgFrame.h
@@ -78,16 +78,18 @@ struct AnimationData
 };
 
 class imgFrame
 {
   typedef gfx::Color Color;
   typedef gfx::DataSourceSurface DataSourceSurface;
   typedef gfx::DrawTarget DrawTarget;
   typedef gfx::Filter Filter;
+  typedef gfx::IntPoint IntPoint;
+  typedef gfx::IntRect IntRect;
   typedef gfx::IntSize IntSize;
   typedef gfx::SourceSurface SourceSurface;
   typedef gfx::SurfaceFormat SurfaceFormat;
 
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
 
@@ -207,19 +209,19 @@ public:
    * Returns the number of bytes per pixel this imgFrame requires.  This is a
    * worst-case value that does not take into account the effects of format
    * changes caused by Optimize(), since an imgFrame is not optimized throughout
    * its lifetime.
    */
   uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
 
   IntSize GetImageSize() const { return mImageSize; }
-  nsIntRect GetRect() const;
-  IntSize GetSize() const { return mSize; }
-  bool NeedsPadding() const { return mOffset != nsIntPoint(0, 0); }
+  IntRect GetRect() const { return mFrameRect; }
+  IntSize GetSize() const { return mFrameRect.Size(); }
+  bool NeedsPadding() const { return mFrameRect.TopLeft() != IntPoint(0, 0); }
   void GetImageData(uint8_t** aData, uint32_t* length) const;
   uint8_t* GetImageData() const;
 
   bool GetIsPaletted() const;
   void GetPaletteData(uint32_t** aPalette, uint32_t* length) const;
   uint32_t* GetPaletteData() const;
   uint8_t GetPaletteDepth() const { return mPaletteDepth; }
 
@@ -315,18 +317,17 @@ private: // data
   bool mOptimizable;
 
 
   //////////////////////////////////////////////////////////////////////////////
   // Effectively const data, only mutated in the Init methods.
   //////////////////////////////////////////////////////////////////////////////
 
   IntSize      mImageSize;
-  IntSize      mSize;
-  nsIntPoint   mOffset;
+  IntRect      mFrameRect;
 
   // The palette and image data for images that are paletted, since Cairo
   // doesn't support these images.
   // The paletted data comes first, then the image data itself.
   // Total length is PaletteDataLength() + GetImageDataLength().
   uint8_t*     mPalettedImageData;
   uint8_t      mPaletteDepth;