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
;
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
);
44 CopyableCanvasLayer::Initialize(const Data
& aData
)
46 NS_ASSERTION(mSurface
== nullptr, "BasicCanvasLayer::Initialize called twice!");
49 mSurface
= aData
.mSurface
;
50 NS_ASSERTION(!aData
.mGLContext
, "CanvasLayer can't have both surface and GLContext");
52 } else if (aData
.mGLContext
) {
53 mGLContext
= aData
.mGLContext
;
54 mIsGLAlphaPremult
= aData
.mIsGLAlphaPremult
;
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
;
63 gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget
);
66 NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
69 mBounds
.SetRect(0, 0, aData
.mSize
.width
, aData
.mSize
.height
);
73 CopyableCanvasLayer::UpdateSurface(gfxASurface
* aDestSurface
, Layer
* aMaskLayer
)
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
);
93 nsRefPtr
<gfxImageSurface
> readSurf
;
94 nsRefPtr
<gfxASurface
> resultSurf
;
96 SharedSurface
* sharedSurf
= mGLContext
->RequestFrame();
98 NS_WARNING("Null frame received.");
102 gfxIntSize
readSize(sharedSurf
->Size());
103 gfxImageFormat format
= (GetContentFlags() & CONTENT_OPAQUE
)
104 ? gfxImageFormatRGB24
105 : gfxImageFormatARGB32
;
108 resultSurf
= aDestSurface
;
110 resultSurf
= GetTempSurface(readSize
, format
);
112 MOZ_ASSERT(resultSurf
);
113 if (resultSurf
->CairoStatus() != 0) {
114 MOZ_ASSERT(false, "Bad resultSurf->CairoStatus().");
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();
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
;
140 gfxUtils::PremultiplyImageSurface(readSurf
);
141 readSurf
->MarkDirty();
144 if (readSurf
!= resultSurf
) {
146 nsRefPtr
<gfxContext
> ctx
= new gfxContext(resultSurf
);
147 ctx
->SetOperator(gfxContext::OPERATOR_SOURCE
);
148 ctx
->SetSource(readSurf
);
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.
155 mSurface
= resultSurf
;
161 CopyableCanvasLayer::PaintWithOpacity(gfxContext
* aContext
,
164 gfxContext::GraphicsOperator aOperator
)
167 NS_WARNING("No valid surface to draw!");
171 nsRefPtr
<gfxPattern
> pat
= new gfxPattern(mSurface
);
173 pat
->SetFilter(mFilter
);
174 pat
->SetExtend(gfxPattern::EXTEND_PAD
);
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
);
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
);
205 aContext
->SetMatrix(m
);
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
);
219 mCachedFormat
= aFormat
;
222 MOZ_ASSERT(mCachedTempSurface
->Stride() == mCachedTempSurface
->Width() * 4);
223 return mCachedTempSurface
;
227 CopyableCanvasLayer::DiscardTempSurface()
229 mCachedTempSurface
= nullptr;