backout 29799f914cab, Bug 917642 - [Helix] Please update the helix blobs
[gecko.git] / gfx / layers / CopyableCanvasLayer.cpp
blob6fd66f367792d40835b0ed02d94606953a3ad438
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "BasicLayersImpl.h" // for FillWithMask, etc
7 #include "CopyableCanvasLayer.h"
8 #include "GLContext.h" // for GLContext
9 #include "GLScreenBuffer.h" // for GLScreenBuffer
10 #include "SharedSurface.h" // for SharedSurface
11 #include "SharedSurfaceGL.h" // for SharedSurface_GL, etc
12 #include "SurfaceTypes.h" // for APITypeT, APITypeT::OpenGL, etc
13 #include "gfxImageSurface.h" // for gfxImageSurface
14 #include "gfxMatrix.h" // for gfxMatrix
15 #include "gfxPattern.h" // for gfxPattern, etc
16 #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
17 #include "gfxRect.h" // for gfxRect
18 #include "gfxUtils.h" // for gfxUtils
19 #include "mozilla/gfx/BaseSize.h" // for BaseSize
20 #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
21 #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
22 #include "nsRect.h" // for nsIntRect
23 #include "nsSize.h" // for nsIntSize
25 using namespace mozilla::gfx;
26 using namespace mozilla::gl;
28 namespace mozilla {
29 namespace layers {
31 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
32 CanvasLayer(aLayerManager, aImplData)
34 MOZ_COUNT_CTOR(CopyableCanvasLayer);
35 mForceReadback = Preferences::GetBool("webgl.force-layers-readback", false);
38 CopyableCanvasLayer::~CopyableCanvasLayer()
40 MOZ_COUNT_DTOR(CopyableCanvasLayer);
43 void
44 CopyableCanvasLayer::Initialize(const Data& aData)
46 NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!");
48 if (aData.mSurface) {
49 mSurface = aData.mSurface;
50 NS_ASSERTION(!aData.mGLContext, "CanvasLayer can't have both surface and GLContext");
51 mNeedsYFlip = false;
52 } else if (aData.mGLContext) {
53 mGLContext = aData.mGLContext;
54 mIsGLAlphaPremult = aData.mIsGLAlphaPremult;
55 mNeedsYFlip = true;
56 MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
58 // [Basic Layers, non-OMTC] WebGL layer init.
59 // `GLScreenBuffer::Morph`ing is only needed in BasicShadowableCanvasLayer.
60 } else if (aData.mDrawTarget) {
61 mDrawTarget = aData.mDrawTarget;
62 mSurface =
63 gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget);
64 mNeedsYFlip = false;
65 } else {
66 NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
69 mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
72 void
73 CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
75 if (!IsDirty())
76 return;
77 Painted();
79 if (mDrawTarget) {
80 mDrawTarget->Flush();
81 mSurface =
82 gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget);
85 if (!mGLContext && aDestSurface) {
86 nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface);
87 tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
88 CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer);
89 return;
92 if (mGLContext) {
93 nsRefPtr<gfxImageSurface> readSurf;
94 nsRefPtr<gfxASurface> resultSurf;
96 SharedSurface* sharedSurf = mGLContext->RequestFrame();
97 if (!sharedSurf) {
98 NS_WARNING("Null frame received.");
99 return;
102 gfxIntSize readSize(sharedSurf->Size());
103 gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
104 ? gfxImageFormatRGB24
105 : gfxImageFormatARGB32;
107 if (aDestSurface) {
108 resultSurf = aDestSurface;
109 } else {
110 resultSurf = GetTempSurface(readSize, format);
112 MOZ_ASSERT(resultSurf);
113 if (resultSurf->CairoStatus() != 0) {
114 MOZ_ASSERT(false, "Bad resultSurf->CairoStatus().");
115 return;
118 MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL);
119 SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf);
121 if (surfGL->Type() == SharedSurfaceType::Basic) {
122 SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
123 readSurf = sharedSurf_Basic->GetData();
124 } else {
125 if (resultSurf->GetSize() != readSize ||
126 !(readSurf = resultSurf->GetAsImageSurface()) ||
127 readSurf->Format() != format)
129 readSurf = GetTempSurface(readSize, format);
132 // Readback handles Flush/MarkDirty.
133 mGLContext->Screen()->Readback(surfGL, readSurf);
135 MOZ_ASSERT(readSurf);
137 bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
138 if (needsPremult) {
139 readSurf->Flush();
140 gfxUtils::PremultiplyImageSurface(readSurf);
141 readSurf->MarkDirty();
144 if (readSurf != resultSurf) {
145 readSurf->Flush();
146 nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
147 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
148 ctx->SetSource(readSurf);
149 ctx->Paint();
152 // If !aDestSurface then we will end up painting using mSurface, so
153 // stick our surface into mSurface, so that the Paint() path is the same.
154 if (!aDestSurface) {
155 mSurface = resultSurf;
160 void
161 CopyableCanvasLayer::PaintWithOpacity(gfxContext* aContext,
162 float aOpacity,
163 Layer* aMaskLayer,
164 gfxContext::GraphicsOperator aOperator)
166 if (!mSurface) {
167 NS_WARNING("No valid surface to draw!");
168 return;
171 nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
173 pat->SetFilter(mFilter);
174 pat->SetExtend(gfxPattern::EXTEND_PAD);
176 gfxMatrix m;
177 if (mNeedsYFlip) {
178 m = aContext->CurrentMatrix();
179 aContext->Translate(gfxPoint(0.0, mBounds.height));
180 aContext->Scale(1.0, -1.0);
183 // If content opaque, then save off current operator and set to source.
184 // This ensures that alpha is not applied even if the source surface
185 // has an alpha channel
186 gfxContext::GraphicsOperator savedOp;
187 if (GetContentFlags() & CONTENT_OPAQUE) {
188 savedOp = aContext->CurrentOperator();
189 aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
192 AutoSetOperator setOperator(aContext, aOperator);
193 aContext->NewPath();
194 // No need to snap here; our transform is already set up to snap our rect
195 aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height));
196 aContext->SetPattern(pat);
198 FillWithMask(aContext, aOpacity, aMaskLayer);
199 // Restore surface operator
200 if (GetContentFlags() & CONTENT_OPAQUE) {
201 aContext->SetOperator(savedOp);
204 if (mNeedsYFlip) {
205 aContext->SetMatrix(m);
209 gfxImageSurface*
210 CopyableCanvasLayer::GetTempSurface(const gfxIntSize& aSize, const gfxImageFormat aFormat)
212 if (!mCachedTempSurface ||
213 aSize.width != mCachedSize.width ||
214 aSize.height != mCachedSize.height ||
215 aFormat != mCachedFormat)
217 mCachedTempSurface = new gfxImageSurface(aSize, aFormat);
218 mCachedSize = aSize;
219 mCachedFormat = aFormat;
222 MOZ_ASSERT(mCachedTempSurface->Stride() == mCachedTempSurface->Width() * 4);
223 return mCachedTempSurface;
226 void
227 CopyableCanvasLayer::DiscardTempSurface()
229 mCachedTempSurface = nullptr;