Bug 997014 - Part 1: Improve GetSurfaceSnapshot. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 17 Apr 2014 17:28:17 +1200
changeset 198665 54ac1366823a96f3a8aaed009f1ca570e7c4464b
parent 198664 d53bccef7150e32f407ff1e84b26a35f69f01aa4
child 198666 6e72c7a1d9d930fe27ee1c327ef2cf46be6a2f79
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs997014
milestone31.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 997014 - Part 1: Improve GetSurfaceSnapshot. r=roc
content/canvas/public/nsICanvasRenderingContextInternal.h
content/canvas/src/CanvasRenderingContext2D.h
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -9,18 +9,18 @@
 #include "nsISupports.h"
 #include "nsIInputStream.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "GraphicsFilter.h"
 #include "mozilla/RefPtr.h"
 
 #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
-{ 0x9a6a5bdf, 0x1261, 0x4057, \
-  { 0x85, 0xcc, 0xaf, 0x97, 0x6c, 0x36, 0x99, 0xa9 } }
+{ 0xf74397d9, 0x25d9, 0x43ed, \
+  { 0xb4, 0x6a, 0xf5, 0x4e, 0xa1, 0x17, 0xae, 0x6e } }
 
 class gfxContext;
 class gfxASurface;
 class nsDisplayListBuilder;
 
 namespace mozilla {
 namespace layers {
 class CanvasLayer;
@@ -85,17 +85,20 @@ public:
                             nsIInputStream **aStream) = 0;
 
   // If this canvas context can be represented with a simple Thebes surface,
   // return the surface.  Otherwise returns an error.
   NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0;
   
   // This gets an Azure SourceSurface for the canvas, this will be a snapshot
   // of the canvas at the time it was called.
-  virtual mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() = 0;
+  // If aPremultAlpha is provided, then it assumed the callee can handle
+  // un-premultiplied surfaces, and *aPremultAlpha will be set to false
+  // if one is returned.
+  virtual mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) = 0;
 
   // If this context is opaque, the backing store of the canvas should
   // be created as opaque; all compositing operators should assume the
   // dst alpha is always 1.0.  If this is never called, the context
   // defaults to false (not opaque).
   NS_IMETHOD SetIsOpaque(bool isOpaque) = 0;
   virtual bool GetIsOpaque() = 0;
 
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -460,18 +460,24 @@ public:
   NS_IMETHOD Render(gfxContext *ctx,
                     GraphicsFilter aFilter,
                     uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
   NS_IMETHOD GetInputStream(const char* aMimeType,
                             const char16_t* aEncoderOptions,
                             nsIInputStream **aStream) MOZ_OVERRIDE;
   NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE;
 
-  mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() MOZ_OVERRIDE
-  { EnsureTarget(); return mTarget->Snapshot(); }
+  mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) MOZ_OVERRIDE
+  {
+    EnsureTarget();
+    if (aPremultAlpha) {
+      *aPremultAlpha = true;
+    }
+    return mTarget->Snapshot();
+  }
 
   NS_IMETHOD SetIsOpaque(bool isOpaque) MOZ_OVERRIDE;
   bool GetIsOpaque() MOZ_OVERRIDE { return mOpaque; }
   NS_IMETHOD Reset() MOZ_OVERRIDE;
   already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                CanvasLayer *aOldLayer,
                                                LayerManager *aManager) MOZ_OVERRIDE;
   virtual bool ShouldForceInactiveLayer(LayerManager *aManager) MOZ_OVERRIDE;
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1371,19 +1371,66 @@ WebGLContext::ForceRestoreContext()
 {
     mContextStatus = ContextLostAwaitingRestore;
 }
 
 void
 WebGLContext::MakeContextCurrent() const { gl->MakeCurrent(); }
 
 mozilla::TemporaryRef<mozilla::gfx::SourceSurface>
-WebGLContext::GetSurfaceSnapshot()
+WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
 {
-  return nullptr;
+    if (!gl)
+        return nullptr;
+
+    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
+                                                         gfxImageFormat::ARGB32);
+    if (surf->CairoStatus() != 0) {
+        return nullptr;
+    }
+
+    gl->MakeCurrent();
+    ReadScreenIntoImageSurface(gl, surf);
+
+    if (aPremultAlpha) {
+        *aPremultAlpha = true;
+    }
+    bool srcPremultAlpha = mOptions.premultipliedAlpha;
+    if (!srcPremultAlpha) {
+        if (aPremultAlpha) {
+            *aPremultAlpha = false;
+        } else {
+            gfxUtils::PremultiplyImageSurface(surf);
+            surf->MarkDirty();
+        }
+    }
+
+    RefPtr<DrawTarget> dt =
+        Factory::CreateDrawTarget(BackendType::CAIRO,
+                                  IntSize(mWidth, mHeight),
+                                  SurfaceFormat::B8G8R8A8);
+
+    if (!dt) {
+        return nullptr;
+    }
+
+    RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surf);
+
+    Matrix m;
+    m.Translate(0.0, mHeight);
+    m.Scale(1.0, -1.0);
+    dt->SetTransform(m);
+
+    dt->DrawSurface(source,
+                    Rect(0, 0, mWidth, mHeight),
+                    Rect(0, 0, mWidth, mHeight),
+                    DrawSurfaceOptions(),
+                    DrawOptions(1.0f, CompositionOp::OP_SOURCE));
+
+    return dt->Snapshot();
 }
 
 //
 // XPCOM goop
 //
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -168,17 +168,17 @@ public:
     NS_IMETHOD Render(gfxContext *ctx,
                       GraphicsFilter f,
                       uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
     virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const char16_t* aEncoderOptions,
                               nsIInputStream **aStream) MOZ_OVERRIDE;
     NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE;
-    mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() MOZ_OVERRIDE;
+    mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha) MOZ_OVERRIDE;
 
     NS_IMETHOD SetIsOpaque(bool b) MOZ_OVERRIDE { return NS_OK; };
     bool GetIsOpaque() MOZ_OVERRIDE { return false; }
     NS_IMETHOD SetContextOptions(JSContext* aCx,
                                  JS::Handle<JS::Value> aOptions) MOZ_OVERRIDE;
 
     NS_IMETHOD SetIsIPC(bool b) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Redraw(const gfxRect&) { return NS_ERROR_NOT_IMPLEMENTED; }