Bug 1141979 - part10 - hanlde drawing RGB24/BGR24/HSV/Lab onto canvas element; r=jrmuizel draft
authorKaku Kuo <tkuo@mozilla.com>
Mon, 14 Mar 2016 19:34:52 +0800
changeset 373849 dbb63b5c5215c6edf92cc954b2cb3fc79a5d6331
parent 373848 97eebbbbecd48b9071c68f95f2a8d151dd70a1f8
child 373850 555760b434b27bb275065527609a48bfbdfd25b7
push id19853
push usertkuo@mozilla.com
push dateWed, 01 Jun 2016 09:17:41 +0000
reviewersjrmuizel
bugs1141979
milestone49.0a1
Bug 1141979 - part10 - hanlde drawing RGB24/BGR24/HSV/Lab onto canvas element; r=jrmuizel MozReview-Commit-ID: FmiTy6tXNN7
dom/canvas/ImageBitmap.cpp
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/dom/ImageBitmap.h"
 
 #include "mozilla/dom/ImageBitmapBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/gfx/2D.h"
+#include "ImageBitmapColorUtils.h"
 #include "ImageBitmapUtils.h"
 #include "ImageUtils.h"
 #include "imgTools.h"
 #include "libyuv.h"
 
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
@@ -422,16 +423,90 @@ ImageBitmap::Close()
 }
 
 void
 ImageBitmap::SetPictureRect(const IntRect& aRect, ErrorResult& aRv)
 {
   mPictureRect = FixUpNegativeDimension(aRect, aRv);
 }
 
+static already_AddRefed<SourceSurface>
+ConvertColorFormatIfNeeded(RefPtr<SourceSurface> aSurface)
+{
+  const SurfaceFormat srcFormat = aSurface->GetFormat();
+  if (srcFormat == SurfaceFormat::R8G8B8A8 ||
+      srcFormat == SurfaceFormat::B8G8R8A8 ||
+      srcFormat == SurfaceFormat::R8G8B8X8 ||
+      srcFormat == SurfaceFormat::B8G8R8X8 ||
+      srcFormat == SurfaceFormat::A8R8G8B8 ||
+      srcFormat == SurfaceFormat::X8R8G8B8) {
+    return aSurface.forget();
+  }
+
+  if (srcFormat == SurfaceFormat::A8 ||
+      srcFormat == SurfaceFormat::Depth) {
+    return nullptr;
+  }
+
+  const int bytesPerPixel = BytesPerPixel(SurfaceFormat::B8G8R8A8);
+  const IntSize dstSize = aSurface->GetSize();
+  const uint32_t dstStride = dstSize.width * bytesPerPixel;
+
+  RefPtr<DataSourceSurface> dstDataSurface =
+    Factory::CreateDataSourceSurfaceWithStride(dstSize,
+                                               SurfaceFormat::B8G8R8A8,
+                                               dstStride);
+
+  RefPtr<DataSourceSurface> srcDataSurface = aSurface->GetDataSurface();
+  if (NS_WARN_IF(!srcDataSurface)) {
+    return nullptr;
+  }
+
+  DataSourceSurface::ScopedMap srcMap(srcDataSurface, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap dstMap(dstDataSurface, DataSourceSurface::WRITE);
+  if (NS_WARN_IF(!srcMap.IsMapped()) || NS_WARN_IF(!dstMap.IsMapped())) {
+    return nullptr;
+  }
+
+  int rv = 0;
+  if (srcFormat == SurfaceFormat::R8G8B8) {
+    rv = RGB24ToBGRA32(srcMap.GetData(), srcMap.GetStride(),
+                       dstMap.GetData(), dstMap.GetStride(),
+                       dstSize.width, dstSize.height);
+  } else if (srcFormat == SurfaceFormat::B8G8R8) {
+    rv = BGR24ToBGRA32(srcMap.GetData(), srcMap.GetStride(),
+                       dstMap.GetData(), dstMap.GetStride(),
+                       dstSize.width, dstSize.height);
+  } else if (srcFormat == SurfaceFormat::HSV) {
+    rv = HSVToBGRA32((const float*)srcMap.GetData(), srcMap.GetStride(),
+                     dstMap.GetData(), dstMap.GetStride(),
+                     dstSize.width, dstSize.height);
+  } else if (srcFormat == SurfaceFormat::Lab) {
+    rv = LabToBGRA32((const float*)srcMap.GetData(), srcMap.GetStride(),
+                     dstMap.GetData(), dstMap.GetStride(),
+                     dstSize.width, dstSize.height);
+  }
+
+  if (NS_WARN_IF(rv != 0)) {
+    return nullptr;
+  }
+
+  return dstDataSurface.forget();
+}
+
+/*
+ * The functionality of PrepareForDrawTarget method:
+ * (1) Get a SourceSurface from the mData (which is a layers::Image).
+ * (2) Convert the SourceSurface to format B8G8R8A8 if the original format is
+ *     R8G8B8, B8G8R8, HSV or Lab.
+ *     Note: if the original format is A8 or Depth, then return null directly.
+ * (3) Do cropping if the size of SourceSurface does not equal to the
+ *     mPictureRect.
+ * (4) Pre-multiply alpha if needed.
+ */
 already_AddRefed<SourceSurface>
 ImageBitmap::PrepareForDrawTarget(gfx::DrawTarget* aTarget)
 {
   MOZ_ASSERT(aTarget);
 
   if (!mData) {
     return nullptr;
   }
@@ -439,16 +514,24 @@ ImageBitmap::PrepareForDrawTarget(gfx::D
   if (!mSurface) {
     mSurface = mData->GetAsSourceSurface();
 
     if (!mSurface) {
       return nullptr;
     }
   }
 
+  // Check if we need to convert the format.
+  // Convert R8G8B8/B8G8R8/HSV/Lab to B8G8R8A8.
+  // Return null if the original format is A8 or Depth.
+  mSurface = ConvertColorFormatIfNeeded(mSurface);
+  if (NS_WARN_IF(!mSurface)) {
+    return nullptr;
+  }
+
   RefPtr<DrawTarget> target = aTarget;
   IntRect surfRect(0, 0, mSurface->GetSize().width, mSurface->GetSize().height);
 
   // Check if we still need to crop our surface
   if (!mPictureRect.IsEqualEdges(surfRect)) {
 
     IntRect surfPortion = surfRect.Intersect(mPictureRect);