Bug 1141979 - part10 - hanlde drawing RGB24/BGR24/HSV/Lab onto canvas element; r=jrmuizel
authorKaku Kuo <tkuo@mozilla.com>
Mon, 14 Mar 2016 19:34:52 +0800
changeset 339148 88544efdd4bdce59e1f122af3da5925e9a82fe26
parent 339147 0282afe01d9e849ac3babd31932d05415d43752f
child 339149 3d688790126494b8cfc4ba34d91cdea862f061c4
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1141979
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 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);