Bug 1334749. Avoid creating a temporary cairo surface, just to copy its data to a skia surface, in putImageData. r=lsalzman
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 30 Jan 2017 15:45:23 -0500
changeset 331682 0c3de6069e8efdce7edf84231fcc5a4b09368885
parent 331681 3b7d96464366abd6b5a8c45cfec0444510d2f602
child 331683 1064fae59e5d7ca5bf208e3253b2f411181b608f
push id86334
push userbzbarsky@mozilla.com
push dateMon, 30 Jan 2017 20:45:57 +0000
treeherdermozilla-inbound@0c3de6069e8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1334749
milestone54.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 1334749. Avoid creating a temporary cairo surface, just to copy its data to a skia surface, in putImageData. r=lsalzman
dom/canvas/CanvasRenderingContext2D.cpp
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -45,17 +45,16 @@
 #include "nsContentUtils.h"
 
 #include "nsTArray.h"
 
 #include "ImageEncoder.h"
 #include "ImageRegion.h"
 
 #include "gfxContext.h"
-#include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxFont.h"
 #include "gfxBlur.h"
 #include "gfxPrefs.h"
 #include "gfxUtils.h"
 
 #include "nsFrameLoader.h"
 #include "nsBidi.h"
@@ -5805,38 +5804,48 @@ CanvasRenderingContext2D::PutImageData_e
 
   uint32_t len = aW * aH * 4;
   if (dataLen != len) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   uint32_t copyWidth = dirtyRect.Width();
   uint32_t copyHeight = dirtyRect.Height();
-  RefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(gfx::IntSize(copyWidth, copyHeight),
-                                                          SurfaceFormat::A8R8G8B8_UINT32,
-                                                          false);
-  if (!imgsurf || imgsurf->CairoStatus()) {
+  RefPtr<DataSourceSurface> sourceSurface =
+    gfx::Factory::CreateDataSourceSurface(gfx::IntSize(copyWidth, copyHeight),
+                                          SurfaceFormat::B8G8R8A8,
+                                          false);
+  // In certain scenarios, requesting larger than 8k image fails.  Bug 803568
+  // covers the details of how to run into it, but the full detailed
+  // investigation hasn't been done to determine the underlying cause.  We
+  // will just handle the failure to allocate the surface to avoid a crash.
+  if (!sourceSurface) {
     return NS_ERROR_FAILURE;
   }
 
+  uint8_t *dstLine = sourceSurface->GetData();
+  if (!dstLine) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  int32_t dstStride = sourceSurface->Stride();
+
   uint32_t copyX = dirtyRect.x - aX;
   uint32_t copyY = dirtyRect.y - aY;
-  //uint8_t *src = aArray->Data();
-  uint8_t *dst = imgsurf->Data();
   uint8_t* srcLine = aArray->Data() + copyY * (aW * 4) + copyX * 4;
   // For opaque canvases, we must still premultiply the RGB components, but write the alpha as opaque.
   uint8_t alphaMask = mOpaque ? 255 : 0;
 #if 0
   printf("PutImageData_explicit: dirty x=%d y=%d w=%d h=%d copy x=%d y=%d w=%d h=%d ext x=%d y=%d w=%d h=%d\n",
        dirtyRect.x, dirtyRect.y, copyWidth, copyHeight,
        copyX, copyY, copyWidth, copyHeight,
        x, y, w, h);
 #endif
   for (uint32_t j = 0; j < copyHeight; j++) {
     uint8_t *src = srcLine;
+    uint8_t *dst = dstLine;
     for (uint32_t i = 0; i < copyWidth; i++) {
       uint8_t r = *src++;
       uint8_t g = *src++;
       uint8_t b = *src++;
       uint8_t a = *src++;
 
       // Convert to premultiplied color (losslessly if the input came from getImageData)
 #if MOZ_LITTLE_ENDIAN
@@ -5847,39 +5856,32 @@ CanvasRenderingContext2D::PutImageData_e
 #else
       *dst++ = a | alphaMask;
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b];
 #endif
     }
     srcLine += aW * 4;
+    // Note that dstLine + dstStride might not be the same as "dst" here,
+    // depending the width we asked for and the width the underlying machinery
+    // decided to actually allocate (e.g. to give each row nice alignment).
+    dstLine += dstStride;
   }
 
   // The canvas spec says that the current path, transformation matrix, shadow attributes,
   // global alpha, the clipping region, and global composition operator must not affect the
   // getImageData() and putImageData() methods.
   const gfx::Rect putRect(dirtyRect);
   EnsureTarget(&putRect);
 
   if (!IsTargetValid()) {
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<SourceSurface> sourceSurface =
-    mTarget->CreateSourceSurfaceFromData(imgsurf->Data(), IntSize(copyWidth, copyHeight), imgsurf->Stride(), SurfaceFormat::B8G8R8A8);
-
-  // In certain scenarios, requesting larger than 8k image fails.  Bug 803568
-  // covers the details of how to run into it, but the full detailed
-  // investigation hasn't been done to determine the underlying cause.  We
-  // will just handle the failure to allocate the surface to avoid a crash.
-  if (!sourceSurface) {
-    return NS_ERROR_FAILURE;
-  }
-
   mTarget->CopySurface(sourceSurface,
                        IntRect(0, 0,
                                dirtyRect.width, dirtyRect.height),
                        IntPoint(dirtyRect.x, dirtyRect.y));
 
   Redraw(gfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
 
   return NS_OK;