Bug 686742 - Move YUV conversion code into gfxUtil functions. r=derf
authorOleg Romashin <romaxa@gmail.com>
Tue, 27 Sep 2011 15:19:24 -0700
changeset 78217 2a443d5f2944f2537c20304f45b0d614759a6e23
parent 78216 482cba26ee79172237cf82c0450e0e886b47d2ae
child 78218 261bb33e9c53c477279633b488812feb20d72d7c
push idunknown
push userunknown
push dateunknown
reviewersderf
bugs686742
milestone10.0a1
Bug 686742 - Move YUV conversion code into gfxUtil functions. r=derf
gfx/layers/ImageLayers.h
gfx/layers/basic/BasicImages.cpp
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -37,21 +37,22 @@
 
 #ifndef GFX_IMAGELAYER_H
 #define GFX_IMAGELAYER_H
 
 #include "Layers.h"
 
 #include "gfxPattern.h"
 #include "nsThreadUtils.h"
-#include "nsCoreAnimationSupport.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/mozalloc.h"
 
+class nsIOSurface;
+
 namespace mozilla {
 namespace layers {
 
 enum StereoMode {
   STEREO_MODE_MONO,
   STEREO_MODE_LEFT_RIGHT,
   STEREO_MODE_RIGHT_LEFT,
   STEREO_MODE_BOTTOM_TOP,
--- a/gfx/layers/basic/BasicImages.cpp
+++ b/gfx/layers/basic/BasicImages.cpp
@@ -42,18 +42,17 @@
 #include "gfxImageSurface.h"
 
 #ifdef XP_MACOSX
 #include "gfxQuartzImageSurface.h"
 #endif
 
 #include "cairo.h"
 
-#include "yuv_convert.h"
-#include "ycbcr_to_rgb565.h"
+#include "gfxUtils.h"
 
 #include "gfxPlatform.h"
 
 using mozilla::ReentrantMonitor;
 
 namespace mozilla {
 namespace layers {
 
@@ -151,137 +150,29 @@ BasicPlanarYCbCrImage::SetData(const Dat
     return;
   }
   
   if (mDelayedConversion) {
     mBuffer = CopyData(mData, mSize, mBufferSize, aData);
     return;
   }
   
-  gfx::YUVType type = 
-    gfx::TypeFromSize(aData.mYSize.width,
-                      aData.mYSize.height,
-                      aData.mCbCrSize.width,
-                      aData.mCbCrSize.height);
-
   gfxASurface::gfxImageFormat format = GetOffscreenFormat();
 
-  // 'prescale' is true if the scaling is to be done as part of the
-  // YCbCr to RGB conversion rather than on the RGB data when rendered.
-  PRBool prescale = mScaleHint.width > 0 && mScaleHint.height > 0 &&
-                    mScaleHint != aData.mPicSize;
-  if (format == gfxASurface::ImageFormatRGB16_565) {
-#if defined(HAVE_YCBCR_TO_RGB565)
-    if (prescale &&
-        !gfx::IsScaleYCbCrToRGB565Fast(aData.mPicX,
-                                       aData.mPicY,
-                                       aData.mPicSize.width,
-                                       aData.mPicSize.height,
-                                       mScaleHint.width,
-                                       mScaleHint.height,
-                                       type,
-                                       gfx::FILTER_BILINEAR) &&
-        gfx::IsConvertYCbCrToRGB565Fast(aData.mPicX,
-                                        aData.mPicY,
-                                        aData.mPicSize.width,
-                                        aData.mPicSize.height,
-                                        type)) {
-      prescale = PR_FALSE;
-    }
-#else
-    // yuv2rgb16 function not available
-    format = gfxASurface::ImageFormatRGB24;
-#endif
-  }
-  else if (format != gfxASurface::ImageFormatRGB24) {
-    // No other formats are currently supported.
-    format = gfxASurface::ImageFormatRGB24;
-  }
-  if (format == gfxASurface::ImageFormatRGB24) {
-    /* ScaleYCbCrToRGB32 does not support a picture offset, nor 4:4:4 data.
-       See bugs 639415 and 640073. */
-    if (aData.mPicX != 0 || aData.mPicY != 0 || type == gfx::YV24)
-      prescale = PR_FALSE;
-  }
-
-  gfxIntSize size(prescale ? mScaleHint.width : aData.mPicSize.width,
-                  prescale ? mScaleHint.height : aData.mPicSize.height);
+  gfxIntSize size(mScaleHint);
+  gfxUtils::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
 
   mStride = gfxASurface::FormatStrideForWidth(format, size.width);
   mBuffer = AllocateBuffer(size.height * mStride);
   if (!mBuffer) {
     // out of memory
     return;
   }
 
-  // Convert from YCbCr to RGB now, scaling the image if needed.
-  if (size != aData.mPicSize) {
-#if defined(HAVE_YCBCR_TO_RGB565)
-    if (format == gfxASurface::ImageFormatRGB16_565) {
-      gfx::ScaleYCbCrToRGB565(aData.mYChannel,
-                              aData.mCbChannel,
-                              aData.mCrChannel,
-                              mBuffer,
-                              aData.mPicX,
-                              aData.mPicY,
-                              aData.mPicSize.width,
-                              aData.mPicSize.height,
-                              size.width,
-                              size.height,
-                              aData.mYStride,
-                              aData.mCbCrStride,
-                              mStride,
-                              type,
-                              gfx::FILTER_BILINEAR);
-    } else
-#endif
-      gfx::ScaleYCbCrToRGB32(aData.mYChannel,
-                             aData.mCbChannel,
-                             aData.mCrChannel,
-                             mBuffer,
-                             aData.mPicSize.width,
-                             aData.mPicSize.height,
-                             size.width,
-                             size.height,
-                             aData.mYStride,
-                             aData.mCbCrStride,
-                             mStride,
-                             type,
-                             gfx::ROTATE_0,
-                             gfx::FILTER_BILINEAR);
-  } else { // no prescale
-#if defined(HAVE_YCBCR_TO_RGB565)
-    if (format == gfxASurface::ImageFormatRGB16_565) {
-      gfx::ConvertYCbCrToRGB565(aData.mYChannel,
-                                aData.mCbChannel,
-                                aData.mCrChannel,
-                                mBuffer,
-                                aData.mPicX,
-                                aData.mPicY,
-                                aData.mPicSize.width,
-                                aData.mPicSize.height,
-                                aData.mYStride,
-                                aData.mCbCrStride,
-                                mStride,
-                                type);
-    } else // format != gfxASurface::ImageFormatRGB16_565
-#endif
-      gfx::ConvertYCbCrToRGB32(aData.mYChannel,
-                               aData.mCbChannel,
-                               aData.mCrChannel,
-                               mBuffer,
-                               aData.mPicX,
-                               aData.mPicY,
-                               aData.mPicSize.width,
-                               aData.mPicSize.height,
-                               aData.mYStride,
-                               aData.mCbCrStride,
-                               mStride,
-                               type);
-  }
+  gfxUtils::ConvertYCbCrToRGB(aData, format, size, mBuffer, mStride);
   SetOffscreenFormat(format);
   mSize = size;
 }
 
 static cairo_user_data_key_t imageSurfaceDataKey;
 
 static void
 DestroyBuffer(void* aBuffer)
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -35,21 +35,26 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxUtils.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxDrawable.h"
 #include "nsRegion.h"
+#include "yuv_convert.h"
+#include "ycbcr_to_rgb565.h"
 
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
 
+using namespace mozilla;
+using namespace mozilla::layers;
+
 static PRUint8 sUnpremultiplyTable[256*256];
 static PRUint8 sPremultiplyTable[256*256];
 static PRBool sTablesInitialized = PR_FALSE;
 
 static const PRUint8 PremultiplyValue(PRUint8 a, PRUint8 v) {
     return sPremultiplyTable[a*256+v];
 }
 
@@ -512,8 +517,141 @@ gfxUtils::PathFromRegionSnapped(gfxConte
 PRBool
 gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut)
 {
   *aOut = nsIntRect(PRInt32(aIn.X()), PRInt32(aIn.Y()),
   PRInt32(aIn.Width()), PRInt32(aIn.Height()));
   return gfxRect(aOut->x, aOut->y, aOut->width, aOut->height).IsEqualEdges(aIn);
 }
 
+void
+gfxUtils::GetYCbCrToRGBDestFormatAndSize(const PlanarYCbCrImage::Data& aData,
+                                         gfxASurface::gfxImageFormat& aSuggestedFormat,
+                                         gfxIntSize& aSuggestedSize)
+{
+  gfx::YUVType yuvtype =
+    gfx::TypeFromSize(aData.mYSize.width,
+                      aData.mYSize.height,
+                      aData.mCbCrSize.width,
+                      aData.mCbCrSize.height);
+
+  // 'prescale' is true if the scaling is to be done as part of the
+  // YCbCr to RGB conversion rather than on the RGB data when rendered.
+  PRBool prescale = aSuggestedSize.width > 0 && aSuggestedSize.height > 0 &&
+                    aSuggestedSize != aData.mPicSize;
+
+  if (aSuggestedFormat == gfxASurface::ImageFormatRGB16_565) {
+#if defined(HAVE_YCBCR_TO_RGB565)
+    if (prescale &&
+        !gfx::IsScaleYCbCrToRGB565Fast(aData.mPicX,
+                                       aData.mPicY,
+                                       aData.mPicSize.width,
+                                       aData.mPicSize.height,
+                                       aSuggestedSize.width,
+                                       aSuggestedSize.height,
+                                       yuvtype,
+                                       gfx::FILTER_BILINEAR) &&
+        gfx::IsConvertYCbCrToRGB565Fast(aData.mPicX,
+                                        aData.mPicY,
+                                        aData.mPicSize.width,
+                                        aData.mPicSize.height,
+                                        yuvtype)) {
+      prescale = PR_FALSE;
+    }
+#else
+    // yuv2rgb16 function not available
+    aSuggestedFormat = gfxASurface::ImageFormatRGB24;
+#endif
+  }
+  else if (aSuggestedFormat != gfxASurface::ImageFormatRGB24) {
+    // No other formats are currently supported.
+    aSuggestedFormat = gfxASurface::ImageFormatRGB24;
+  }
+  if (aSuggestedFormat == gfxASurface::ImageFormatRGB24) {
+    /* ScaleYCbCrToRGB32 does not support a picture offset, nor 4:4:4 data.
+       See bugs 639415 and 640073. */
+    if (aData.mPicX != 0 || aData.mPicY != 0 || yuvtype == gfx::YV24)
+      prescale = PR_FALSE;
+  }
+  if (!prescale) {
+    aSuggestedSize = aData.mPicSize;
+  }
+}
+
+void
+gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrImage::Data& aData,
+                            const gfxASurface::gfxImageFormat& aDestFormat,
+                            const gfxIntSize& aDestSize,
+                            unsigned char* aDestBuffer,
+                            PRInt32 aStride)
+{
+  gfx::YUVType yuvtype =
+    gfx::TypeFromSize(aData.mYSize.width,
+                      aData.mYSize.height,
+                      aData.mCbCrSize.width,
+                      aData.mCbCrSize.height);
+
+  // Convert from YCbCr to RGB now, scaling the image if needed.
+  if (aDestSize != aData.mPicSize) {
+#if defined(HAVE_YCBCR_TO_RGB565)
+    if (aDestFormat == gfxASurface::ImageFormatRGB16_565) {
+      gfx::ScaleYCbCrToRGB565(aData.mYChannel,
+                              aData.mCbChannel,
+                              aData.mCrChannel,
+                              aDestBuffer,
+                              aData.mPicX,
+                              aData.mPicY,
+                              aData.mPicSize.width,
+                              aData.mPicSize.height,
+                              aDestSize.width,
+                              aDestSize.height,
+                              aData.mYStride,
+                              aData.mCbCrStride,
+                              aStride,
+                              yuvtype,
+                              gfx::FILTER_BILINEAR);
+    } else
+#endif
+      gfx::ScaleYCbCrToRGB32(aData.mYChannel,
+                             aData.mCbChannel,
+                             aData.mCrChannel,
+                             aDestBuffer,
+                             aData.mPicSize.width,
+                             aData.mPicSize.height,
+                             aDestSize.width,
+                             aDestSize.height,
+                             aData.mYStride,
+                             aData.mCbCrStride,
+                             aStride,
+                             yuvtype,
+                             gfx::ROTATE_0,
+                             gfx::FILTER_BILINEAR);
+  } else { // no prescale
+#if defined(HAVE_YCBCR_TO_RGB565)
+    if (aDestFormat == gfxASurface::ImageFormatRGB16_565) {
+      gfx::ConvertYCbCrToRGB565(aData.mYChannel,
+                                aData.mCbChannel,
+                                aData.mCrChannel,
+                                aDestBuffer,
+                                aData.mPicX,
+                                aData.mPicY,
+                                aData.mPicSize.width,
+                                aData.mPicSize.height,
+                                aData.mYStride,
+                                aData.mCbCrStride,
+                                aStride,
+                                yuvtype);
+    } else // aDestFormat != gfxASurface::ImageFormatRGB16_565
+#endif
+      gfx::ConvertYCbCrToRGB32(aData.mYChannel,
+                               aData.mCbChannel,
+                               aData.mCrChannel,
+                               aDestBuffer,
+                               aData.mPicX,
+                               aData.mPicY,
+                               aData.mPicSize.width,
+                               aData.mPicSize.height,
+                               aData.mYStride,
+                               aData.mCbCrStride,
+                               aStride,
+                               yuvtype);
+  }
+}
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_UTILS_H
 #define GFX_UTILS_H
 
 #include "gfxTypes.h"
 #include "gfxPattern.h"
 #include "gfxImageSurface.h"
+#include "ImageLayers.h"
 
 class gfxDrawable;
 class nsIntRegion;
 struct nsIntRect;
 
 class THEBES_API gfxUtils {
 public:
     /*
@@ -118,11 +119,37 @@ public:
     */
     static PRBool GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut);
 
     /**
      * Return the smallest power of kScaleResolution (2) greater than or equal to
      * aVal.
      */
     static gfxFloat ClampToScaleFactor(gfxFloat aVal);
+
+    /**
+     * Helper function for ConvertYCbCrToRGB that finds the
+     * RGB buffer size and format for given YCbCrImage.
+     * @param aSuggestedFormat will be set to ImageFormatRGB24
+     *   if the desired format is not supported.
+     * @param aSuggestedSize will be set to the picture size from aData
+     *   if either the suggested size was {0,0}
+     *   or simultaneous scaling and conversion is not supported.
+     */
+    static void
+    GetYCbCrToRGBDestFormatAndSize(const mozilla::layers::PlanarYCbCrImage::Data& aData,
+                                   gfxASurface::gfxImageFormat& aSuggestedFormat,
+                                   gfxIntSize& aSuggestedSize);
+
+    /**
+     * Convert YCbCrImage into RGB aDestBuffer
+     * Format and Size parameters must have
+     *   been passed to GetYCbCrToRGBDestFormatAndSize
+     */
+    static void
+    ConvertYCbCrToRGB(const mozilla::layers::PlanarYCbCrImage::Data& aData,
+                      const gfxASurface::gfxImageFormat& aDestFormat,
+                      const gfxIntSize& aDestSize,
+                      unsigned char* aDestBuffer,
+                      PRInt32 aStride);
 };
 
 #endif