Bug 641019 - "Crash on video with odd widths and 16-bit displays" [r=tterribe a=stuart]
authorTimothy B. Terriberry <tterribe>
Tue, 15 Mar 2011 15:01:00 -0700
changeset 63416 7d92741097d9e26bb13d8e054a10662ef582fc9c
parent 63415 1604da0cfed4bcd00ab926e04056be53ce8ba369
child 63417 5a6de9619cd26669a0c2e6ab303854278bd0f626
push idunknown
push userunknown
push dateunknown
reviewerstterribe, stuart
bugs641019
milestone2.0b13pre
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 641019 - "Crash on video with odd widths and 16-bit displays" [r=tterribe a=stuart]
gfx/layers/basic/BasicImages.cpp
gfx/thebes/gfxASurface.cpp
gfx/thebes/gfxASurface.h
gfx/ycbcr/convert.patch
gfx/ycbcr/yuv_convert.cpp
--- a/gfx/layers/basic/BasicImages.cpp
+++ b/gfx/layers/basic/BasicImages.cpp
@@ -124,16 +124,17 @@ public:
 
   void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
   gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
 
 protected:
   nsAutoArrayPtr<PRUint8>              mBuffer;
   nsCountedRef<nsMainThreadSurfaceRef> mSurface;
   gfxIntSize                           mScaleHint;
+  PRInt32                              mStride;
   gfxImageFormat                       mOffscreenFormat;
 };
 
 void
 BasicPlanarYCbCrImage::SetData(const Data& aData)
 {
   // Do some sanity checks to prevent integer overflow
   if (aData.mYSize.width > 16384 || aData.mYSize.height > 16384) {
@@ -153,18 +154,18 @@ BasicPlanarYCbCrImage::SetData(const Dat
     } else {
       // yuv2rgb16 function not yet available for non-NEON
       format = gfxASurface::ImageFormatRGB24;
     }
   }
   gfxIntSize size(prescale ? mScaleHint.width : aData.mPicSize.width,
                   prescale ? mScaleHint.height : aData.mPicSize.height);
 
-  int bpp = gfxASurface::BytePerPixelFromFormat(format);
-  mBuffer = new PRUint8[size.width * size.height * bpp];
+  mStride = gfxASurface::FormatStrideForWidth(format, size.width);
+  mBuffer = new PRUint8[size.height * mStride];
   if (!mBuffer) {
     // out of memory
     return;
   }
 
   gfx::YUVType type = gfx::YV12;
   if (aData.mYSize.width == aData.mCbCrSize.width &&
       aData.mYSize.height == aData.mCbCrSize.height) {
@@ -190,17 +191,17 @@ BasicPlanarYCbCrImage::SetData(const Dat
                              aData.mCrChannel,
                              mBuffer,
                              aData.mPicSize.width,
                              aData.mPicSize.height,
                              size.width,
                              size.height,
                              aData.mYStride,
                              aData.mCbCrStride,
-                             size.width*bpp,
+                             mStride,
                              type,
                              gfx::ROTATE_0,
                              gfx::FILTER_BILINEAR);
     } else {
        NS_ERROR("Fail, ScaleYCbCrToRGB format not supported\n");
     }
   } else { // no prescale
     if (format == gfxASurface::ImageFormatRGB16_565) {
@@ -210,30 +211,30 @@ BasicPlanarYCbCrImage::SetData(const Dat
                                 aData.mCrChannel,
                                 mBuffer,
                                 aData.mPicX,
                                 aData.mPicY,
                                 aData.mPicSize.width,
                                 aData.mPicSize.height,
                                 aData.mYStride,
                                 aData.mCbCrStride,
-                                aData.mPicSize.width*bpp,
+                                mStride,
                                 type);
     } else { // format != gfxASurface::ImageFormatRGB16_565
       gfx::ConvertYCbCrToRGB32(aData.mYChannel,
                                aData.mCbChannel,
                                aData.mCrChannel,
                                mBuffer,
                                aData.mPicX,
                                aData.mPicY,
                                aData.mPicSize.width,
                                aData.mPicSize.height,
                                aData.mYStride,
                                aData.mCbCrStride,
-                               aData.mPicSize.width*bpp,
+                               mStride,
                                type);
     }
   }
   SetOffscreenFormat(format);
   mSize = size;
 }
 
 static cairo_user_data_key_t imageSurfaceDataKey;
@@ -256,20 +257,18 @@ BasicPlanarYCbCrImage::GetAsSurface()
 
   if (!mBuffer) {
     return nsnull;
   }
 
   gfxASurface::gfxImageFormat format = GetOffscreenFormat();
 
   nsRefPtr<gfxImageSurface> imgSurface =
-      new gfxImageSurface(mBuffer, mSize,
-                          mSize.width * gfxASurface::BytePerPixelFromFormat(format),
-                          format);
-  if (!imgSurface) {
+      new gfxImageSurface(mBuffer, mSize, mStride, format);
+  if (!imgSurface || imgSurface->CairoStatus() != 0) {
     return nsnull;
   }
 
   // Pass ownership of the buffer to the surface
   imgSurface->SetData(&imageSurfaceDataKey, mBuffer.forget(), DestroyBuffer);
 
   nsRefPtr<gfxASurface> result = imgSurface.get();
 #if defined(XP_MACOSX)
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -368,16 +368,23 @@ gfxASurface::CheckSurfaceSize(const gfxI
     // reject images with sides bigger than limit
     if (limit &&
         (sz.width > limit || sz.height > limit))
         return PR_FALSE;
 
     return PR_TRUE;
 }
 
+/* static */
+PRInt32
+gfxASurface::FormatStrideForWidth(gfxImageFormat format, PRInt32 width)
+{
+    return cairo_format_stride_for_width((cairo_format_t)format, (int)width);
+}
+
 nsresult
 gfxASurface::BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName)
 {
     return NS_OK;
 }
 
 nsresult
 gfxASurface::EndPrinting()
--- a/gfx/thebes/gfxASurface.h
+++ b/gfx/thebes/gfxASurface.h
@@ -165,16 +165,21 @@ public:
     int CairoStatus();
 
     /* Make sure that the given dimensions don't overflow a 32-bit signed int
      * using 4 bytes per pixel; optionally, make sure that either dimension
      * doesn't exceed the given limit.
      */
     static PRBool CheckSurfaceSize(const gfxIntSize& sz, PRInt32 limit = 0);
 
+    /* Provide a stride value that will respect all alignment requirements of
+     * the accelerated image-rendering code.
+     */
+    static PRInt32 FormatStrideForWidth(gfxImageFormat format, PRInt32 width);
+
     /* Return the default set of context flags for this surface; these are
      * hints to the context about any special rendering considerations.  See
      * gfxContext::SetFlag for documentation.
      */
     virtual PRInt32 GetDefaultContextFlags() const { return 0; }
 
     static gfxContentType ContentFromFormat(gfxImageFormat format);
     static gfxImageFormat FormatFromContent(gfxContentType format);
--- a/gfx/ycbcr/convert.patch
+++ b/gfx/ycbcr/convert.patch
@@ -63,17 +63,17 @@ diff --git a/gfx/ycbcr/yuv_convert.cpp b
 +                                  int pic_height,
 +                                  int y_pitch,
 +                                  int uv_pitch,
 +                                  int rgb_pitch,
 +                                  YUVType yuv_type)
 +{
 +#ifdef HAVE_YCBCR_TO_RGB565
 +  for (int i = 0; i < pic_height; i++) {
-+    yv12_to_rgb565_neon((uint16*)rgb_buf + pic_width * i,
++    yv12_to_rgb565_neon((uint16*)(rgb_buf + rgb_pitch * i),
 +                         y_buf + y_pitch * i,
 +                         u_buf + uv_pitch * (i / 2),
 +                         v_buf + uv_pitch * (i / 2),
 +                         pic_width,
 +                         0);
 +  }
 +#endif
 +}
--- a/gfx/ycbcr/yuv_convert.cpp
+++ b/gfx/ycbcr/yuv_convert.cpp
@@ -47,17 +47,17 @@ NS_GFX_(void) ConvertYCbCrToRGB565(const
                                   int pic_height,
                                   int y_pitch,
                                   int uv_pitch,
                                   int rgb_pitch,
                                   YUVType yuv_type)
 {
 #ifdef HAVE_YCBCR_TO_RGB565
   for (int i = 0; i < pic_height; i++) {
-    yv12_to_rgb565_neon((uint16*)rgb_buf + pic_width * i,
+    yv12_to_rgb565_neon((uint16*)(rgb_buf + rgb_pitch * i),
                          y_buf + y_pitch * i,
                          u_buf + uv_pitch * (i / 2),
                          v_buf + uv_pitch * (i / 2),
                          pic_width,
                          0);
   }
 #endif
 }