Bug 1023336, part 2 - Use the new BufferSizeFromStrideAndHeight helper where appropriate in Moz2D code. r=Bas, a=sylvestre
authorJonathan Watt <jwatt@jwatt.org>
Wed, 02 Jul 2014 11:41:15 +0100
changeset 207564 a6e69640a00bd186337531fd4d6b2c6e0d60fa04
parent 207563 072b0d1c3098e447a9f09009e424c7a92475f215
child 207565 4220f0159e89d8cbcfecbe4f15d9ebba1fd89fdd
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, sylvestre
bugs1023336
milestone32.0a2
Bug 1023336, part 2 - Use the new BufferSizeFromStrideAndHeight helper where appropriate in Moz2D code. r=Bas, a=sylvestre
gfx/2d/Blur.cpp
gfx/2d/DataSurfaceHelpers.cpp
gfx/2d/DrawTargetCG.cpp
gfx/2d/ImageScaling.cpp
gfx/2d/SourceSurfaceCG.cpp
gfx/2d/SourceSurfaceRawData.cpp
--- a/gfx/2d/Blur.cpp
+++ b/gfx/2d/Blur.cpp
@@ -1,24 +1,25 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/gfx/Blur.h"
+#include "Blur.h"
 
 #include <algorithm>
 #include <math.h>
 #include <string.h>
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Constants.h"
 
 #include "2D.h"
+#include "DataSurfaceHelpers.h"
 #include "Tools.h"
 
 using namespace std;
 
 namespace mozilla {
 namespace gfx {
 
 /**
@@ -378,19 +379,19 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& a
   }
 
   CheckedInt<int32_t> stride = RoundUpToMultipleOf4(mRect.width);
   if (stride.isValid()) {
     mStride = stride.value();
 
     // We need to leave room for an additional 3 bytes for a potential overrun
     // in our blurring code.
-    CheckedInt<int32_t> size = CheckedInt<int32_t>(mStride) * mRect.height + 3;
-    if (size.isValid()) {
-      mSurfaceAllocationSize = size.value();
+    size_t size = BufferSizeFromStrideAndHeight(mStride, mRect.height, 3);
+    if (size != 0) {
+      mSurfaceAllocationSize = size;
     }
   }
 }
 
 AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
                            int32_t aStride,
                            float aSigmaX,
                            float aSigmaY)
@@ -398,19 +399,19 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& a
           int32_t(aRect.width), int32_t(aRect.height)),
     mSpreadRadius(),
     mBlurRadius(CalculateBlurRadius(Point(aSigmaX, aSigmaY))),
     mStride(aStride),
     mSurfaceAllocationSize(-1)
 {
   IntRect intRect;
   if (aRect.ToIntRect(&intRect)) {
-    CheckedInt<int32_t> minDataSize = CheckedInt<int32_t>(intRect.width)*intRect.height;
-    if (minDataSize.isValid()) {
-      mSurfaceAllocationSize = minDataSize.value();
+    size_t minDataSize = BufferSizeFromStrideAndHeight(intRect.width, intRect.height);
+    if (minDataSize != 0) {
+      mSurfaceAllocationSize = minDataSize;
     }
   }
 }
 
 
 AlphaBoxBlur::~AlphaBoxBlur()
 {
 }
@@ -523,17 +524,23 @@ AlphaBoxBlur::Blur(uint8_t* aData)
         memcpy(aData, tmpData, szB);
       }
       delete [] tmpData;
     } else {
       size_t integralImageStride = GetAlignedStride<16>(integralImageSize.width * 4);
 
       // We need to leave room for an additional 12 bytes for a maximum overrun
       // of 3 pixels in the blurring code.
-      AlignedArray<uint32_t> integralImage((integralImageStride / 4) * integralImageSize.height + 12);
+      size_t bufLen = BufferSizeFromStrideAndHeight(integralImageStride, integralImageSize.height, 12);
+      if (bufLen == 0) {
+        return;
+      }
+      // bufLen is a byte count, but here we want a multiple of 32-bit ints, so
+      // we divide by 4.
+      AlignedArray<uint32_t> integralImage((bufLen / 4) + ((bufLen % 4) ? 1 : 0));
 
       if (!integralImage) {
         return;
       }
 #ifdef USE_SSE2
       if (Factory::HasSSE2()) {
         BoxBlur_SSE2(aData, horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0],
                      verticalLobes[0][1], integralImage, integralImageStride);
--- a/gfx/2d/DataSurfaceHelpers.cpp
+++ b/gfx/2d/DataSurfaceHelpers.cpp
@@ -33,16 +33,18 @@ ConvertBGRXToBGRA(uint8_t* aData, const 
 }
 
 void
 CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize,
                              int32_t aSrcStride, int32_t aBytesPerPixel)
 {
   MOZ_ASSERT(aBytesPerPixel > 0,
              "Negative stride for aDst not currently supported");
+  MOZ_ASSERT(BufferSizeFromStrideAndHeight(aSrcStride, aSrcSize.height) > 0,
+             "How did we end up with a surface with such a big buffer?");
 
   int packedStride = aSrcSize.width * aBytesPerPixel;
 
   if (aSrcStride == packedStride) {
     // aSrc is already packed, so we can copy with a single memcpy.
     memcpy(aDst, aSrc, packedStride * aSrcSize.height);
   } else {
     // memcpy one row at a time.
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -1,23 +1,26 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "BorrowedContext.h"
+#include "DataSurfaceHelpers.h"
 #include "DrawTargetCG.h"
+#include "Logging.h"
 #include "SourceSurfaceCG.h"
 #include "Rect.h"
 #include "ScaledFontMac.h"
 #include "Tools.h"
 #include <vector>
 #include <algorithm>
 #include "MacIOSurface.h"
 #include "FilterNodeSoftware.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/Types.h" // for decltype
 #include "mozilla/FloatingPoint.h"
 
 using namespace std;
 
 //CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
 
 // A private API that Cairo has been using for a long time
 CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
@@ -1294,31 +1297,40 @@ DrawTargetCG::Init(BackendType aType,
                    SurfaceFormat aFormat)
 {
   // XXX: we should come up with some consistent semantics for dealing
   // with zero area drawtargets
   if (aSize.width <= 0 || aSize.height <= 0 ||
       // 32767 is the maximum size supported by cairo
       // we clamp to that to make it easier to interoperate
       aSize.width > 32767 || aSize.height > 32767) {
+    gfxWarning() << "Failed to Init() DrawTargetCG because of bad size.";
     mColorSpace = nullptr;
     mCg = nullptr;
     return false;
   }
 
   //XXX: handle SurfaceFormat
 
   //XXX: we'd be better off reusing the Colorspace across draw targets
   mColorSpace = CGColorSpaceCreateDeviceRGB();
 
   if (aData == nullptr && aType != BackendType::COREGRAPHICS_ACCELERATED) {
     // XXX: Currently, Init implicitly clears, that can often be a waste of time
-    mData.Realloc(aStride * aSize.height);
+    size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height);
+    if (bufLen == 0) {
+      mColorSpace = nullptr;
+      mCg = nullptr;
+      return false;
+    }
+    static_assert(sizeof(decltype(mData[0])) == 1,
+                  "mData.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen");
+    mData.Realloc(/* actually an object count */ bufLen);
     aData = static_cast<unsigned char*>(mData);
-    memset(aData, 0, aStride * aSize.height);
+    memset(aData, 0, bufLen);
   }
 
   mSize = aSize;
 
   if (aType == BackendType::COREGRAPHICS_ACCELERATED) {
     RefPtr<MacIOSurface> ioSurface = MacIOSurface::CreateIOSurface(aSize.width, aSize.height);
     mCg = ioSurface->CreateIOSurfaceContext();
     // If we don't have the symbol for 'CreateIOSurfaceContext' mCg will be null
--- a/gfx/2d/ImageScaling.cpp
+++ b/gfx/2d/ImageScaling.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageScaling.h"
 #include "2D.h"
+#include "DataSurfaceHelpers.h"
 
 #include <math.h>
 #include <algorithm>
 
 using namespace std;
 
 namespace mozilla {
 namespace gfx {
@@ -72,17 +73,23 @@ ImageHalfScaler::ScaleForSize(const IntS
   mStride = internalSurfSize.width * 4;
   if (mStride % 16) {
     mStride += 16 - (mStride % 16);
   }
 
   delete [] mDataStorage;
   // Allocate 15 bytes extra to make sure we can get 16 byte alignment. We
   // should add tools for this, see bug 751696.
-  mDataStorage = new uint8_t[internalSurfSize.height * mStride + 15];
+  size_t bufLen = BufferSizeFromStrideAndHeight(mStride, internalSurfSize.height, 15);
+  if (bufLen == 0) {
+    mSize.SizeTo(0, 0);
+    mDataStorage = nullptr;
+    return;
+  }
+  mDataStorage = new uint8_t[bufLen];
 
   if (uintptr_t(mDataStorage) % 16) {
     // Our storage does not start at a 16-byte boundary. Make sure mData does!
     mData = (uint8_t*)(uintptr_t(mDataStorage) +
       (16 - (uintptr_t(mDataStorage) % 16)));
   } else {
     mData = mDataStorage;
   }
--- a/gfx/2d/SourceSurfaceCG.cpp
+++ b/gfx/2d/SourceSurfaceCG.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceSurfaceCG.h"
 #include "DrawTargetCG.h"
 #include "DataSourceSurfaceWrapper.h"
+#include "DataSurfaceHelpers.h"
+#include "mozilla/Types.h" // for decltype
 
 #include "MacIOSurface.h"
 #include "Tools.h"
 
 namespace mozilla {
 namespace gfx {
 
 
@@ -85,19 +87,23 @@ CreateCGImage(void *aInfo,
       bitsPerComponent = 8;
       bitsPerPixel = 8;
       break;
 
     default:
       MOZ_CRASH();
   }
 
+  size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height);
+  if (bufLen == 0) {
+    return nullptr;
+  }
   CGDataProviderRef dataProvider = CGDataProviderCreateWithData(aInfo,
                                                                 aData,
-                                                                aSize.height * aStride,
+                                                                bufLen,
                                                                 releaseCallback);
 
   CGImageRef image;
   if (aFormat == SurfaceFormat::A8) {
     CGFloat decode[] = {1.0, 0.0};
     image = CGImageMaskCreate (aSize.width, aSize.height,
                                bitsPerComponent,
                                bitsPerPixel,
@@ -127,20 +133,26 @@ CreateCGImage(void *aInfo,
 bool
 SourceSurfaceCG::InitFromData(unsigned char *aData,
                                const IntSize &aSize,
                                int32_t aStride,
                                SurfaceFormat aFormat)
 {
   assert(aSize.width >= 0 && aSize.height >= 0);
 
-  void *data = malloc(aStride * aSize.height);
+  size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height);
+  if (bufLen == 0) {
+    mImage = nullptr;
+    return false;
+  }
+
+  void *data = malloc(bufLen);
   // Copy all the data except the stride padding on the very last
   // row since we can't guarantee that is readable.
-  memcpy(data, aData, aStride * (aSize.height - 1) + (aSize.width * BytesPerPixel(aFormat)));
+  memcpy(data, aData, bufLen - aStride + (aSize.width * BytesPerPixel(aFormat)));
 
   mFormat = aFormat;
   mImage = CreateCGImage(data, data, aSize, aStride, aFormat);
 
   return mImage != nullptr;
 }
 
 DataSourceSurfaceCG::~DataSourceSurfaceCG()
@@ -164,18 +176,24 @@ DataSourceSurfaceCG::InitFromData(unsign
                                const IntSize &aSize,
                                int32_t aStride,
                                SurfaceFormat aFormat)
 {
   if (aSize.width <= 0 || aSize.height <= 0) {
     return false;
   }
 
-  void *data = malloc(aStride * aSize.height);
-  memcpy(data, aData, aStride * (aSize.height - 1) + (aSize.width * BytesPerPixel(aFormat)));
+  size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height);
+  if (bufLen == 0) {
+    mImage = nullptr;
+    return false;
+  }
+
+  void *data = malloc(bufLen);
+  memcpy(data, aData, bufLen - aStride + (aSize.width * BytesPerPixel(aFormat)));
 
   mFormat = aFormat;
   mImage = CreateCGImage(data, data, aSize, aStride, aFormat);
 
   if (!mImage) {
     free(data);
     return false;
   }
@@ -297,23 +315,31 @@ SourceSurfaceCGBitmapContext::GetSize() 
 void
 SourceSurfaceCGBitmapContext::DrawTargetWillChange()
 {
   if (mDrawTarget) {
     // This will break the weak reference we hold to mCg
     size_t stride = CGBitmapContextGetBytesPerRow(mCg);
     size_t height = CGBitmapContextGetHeight(mCg);
 
-    mDataHolder.Realloc(stride * height);
-    mData = mDataHolder;
+    size_t bufLen = BufferSizeFromStrideAndHeight(stride, height);
+    if (bufLen == 0) {
+      mDataHolder.Dealloc();
+      mData = nullptr;
+    } else {
+      static_assert(sizeof(decltype(mDataHolder[0])) == 1,
+                    "mDataHolder.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen");
+      mDataHolder.Realloc(/* actually an object count */ bufLen);
+      mData = mDataHolder;
 
-    // copy out the data from the CGBitmapContext
-    // we'll maintain ownership of mData until
-    // we transfer it to mImage
-    memcpy(mData, CGBitmapContextGetData(mCg), stride*height);
+      // copy out the data from the CGBitmapContext
+      // we'll maintain ownership of mData until
+      // we transfer it to mImage
+      memcpy(mData, CGBitmapContextGetData(mCg), bufLen);
+    }
 
     // drop the current image for the data associated with the CGBitmapContext
     if (mImage)
       CGImageRelease(mImage);
     mImage = nullptr;
 
     mCg = nullptr;
     mDrawTarget = nullptr;
--- a/gfx/2d/SourceSurfaceRawData.cpp
+++ b/gfx/2d/SourceSurfaceRawData.cpp
@@ -1,15 +1,18 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceSurfaceRawData.h"
+
+#include "DataSurfaceHelpers.h"
 #include "Logging.h"
+#include "mozilla/Types.h" // for decltype
 
 namespace mozilla {
 namespace gfx {
 
 bool
 SourceSurfaceRawData::InitWrappingData(uint8_t *aData,
                                        const IntSize &aSize,
                                        int32_t aStride,
@@ -24,31 +27,49 @@ SourceSurfaceRawData::InitWrappingData(u
 
   return true;
 }
 
 bool
 SourceSurfaceAlignedRawData::Init(const IntSize &aSize,
                                   SurfaceFormat aFormat)
 {
+  mFormat = aFormat;
   mStride = GetAlignedStride<16>(aSize.width * BytesPerPixel(aFormat));
-  mArray.Realloc(mStride * aSize.height);
-  mSize = aSize;
-  mFormat = aFormat;
+
+  size_t bufLen = BufferSizeFromStrideAndHeight(mStride, aSize.height);
+  if (bufLen > 0) {
+    static_assert(sizeof(decltype(mArray[0])) == 1,
+                  "mArray.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen");
+    mArray.Realloc(/* actually an object count */ bufLen);
+    mSize = aSize;
+  } else {
+    mArray.Dealloc();
+    mSize.SizeTo(0, 0);
+  }
 
   return mArray != nullptr;
 }
 
 bool
 SourceSurfaceAlignedRawData::InitWithStride(const IntSize &aSize,
                                             SurfaceFormat aFormat,
                                             int32_t aStride)
 {
+  mFormat = aFormat;
   mStride = aStride;
-  mArray.Realloc(mStride * aSize.height);
-  mSize = aSize;
-  mFormat = aFormat;
+
+  size_t bufLen = BufferSizeFromStrideAndHeight(mStride, aSize.height);
+  if (bufLen > 0) {
+    static_assert(sizeof(decltype(mArray[0])) == 1,
+                  "mArray.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen");
+    mArray.Realloc(/* actually an object count */ bufLen);
+    mSize = aSize;
+  } else {
+    mArray.Dealloc();
+    mSize.SizeTo(0, 0);
+  }
 
   return mArray != nullptr;
 }
 
 }
 }