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
12 #include "SurfaceStream.h" // for SurfaceStream
13 #include "gfxPattern.h" // for gfxPattern, etc
14 #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
15 #include "gfxRect.h" // for gfxRect
16 #include "gfxUtils.h" // for gfxUtils
17 #include "gfx2DGlue.h" // for thebes --> moz2d transition
18 #include "mozilla/gfx/BaseSize.h" // for BaseSize
19 #include "mozilla/gfx/Tools.h"
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
29 using namespace mozilla::gfx
;
30 using namespace mozilla::gl
;
32 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager
* aLayerManager
, void *aImplData
) :
33 CanvasLayer(aLayerManager
, aImplData
)
35 , mIsAlphaPremultiplied(true)
37 MOZ_COUNT_CTOR(CopyableCanvasLayer
);
40 CopyableCanvasLayer::~CopyableCanvasLayer()
42 MOZ_COUNT_DTOR(CopyableCanvasLayer
);
46 CopyableCanvasLayer::Initialize(const Data
& aData
)
48 NS_ASSERTION(mSurface
== nullptr, "BasicCanvasLayer::Initialize called twice!");
50 if (aData
.mGLContext
) {
51 mGLContext
= aData
.mGLContext
;
52 mStream
= aData
.mStream
;
53 mIsAlphaPremultiplied
= aData
.mIsGLAlphaPremult
;
55 MOZ_ASSERT(mGLContext
->IsOffscreen(), "canvas gl context isn't offscreen");
57 // [Basic Layers, non-OMTC] WebGL layer init.
58 // `GLScreenBuffer::Morph`ing is only needed in BasicShadowableCanvasLayer.
59 } else if (aData
.mDrawTarget
) {
60 mDrawTarget
= aData
.mDrawTarget
;
61 mSurface
= mDrawTarget
->Snapshot();
64 NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
67 mBounds
.SetRect(0, 0, aData
.mSize
.width
, aData
.mSize
.height
);
71 CopyableCanvasLayer::IsDataValid(const Data
& aData
)
73 return mGLContext
== aData
.mGLContext
&& mStream
== aData
.mStream
;
77 CopyableCanvasLayer::UpdateTarget(DrawTarget
* aDestTarget
)
85 mSurface
= mDrawTarget
->Snapshot();
88 if (!mGLContext
&& aDestTarget
) {
89 NS_ASSERTION(mSurface
, "Must have surface to draw!");
91 aDestTarget
->CopySurface(mSurface
,
92 IntRect(0, 0, mBounds
.width
, mBounds
.height
),
100 SharedSurface
* sharedSurf
= nullptr;
102 sharedSurf
= mStream
->SwapConsumer();
104 sharedSurf
= mGLContext
->RequestFrame();
108 NS_WARNING("Null frame received.");
112 IntSize
readSize(sharedSurf
->mSize
);
113 SurfaceFormat format
= (GetContentFlags() & CONTENT_OPAQUE
)
114 ? SurfaceFormat::B8G8R8X8
115 : SurfaceFormat::B8G8R8A8
;
116 bool needsPremult
= sharedSurf
->mHasAlpha
&& !mIsAlphaPremultiplied
;
118 // Try to read back directly into aDestTarget's output buffer
123 SurfaceFormat destFormat
;
124 if (aDestTarget
->LockBits(&destData
, &destSize
, &destStride
, &destFormat
)) {
125 if (destSize
== readSize
&& destFormat
== format
) {
126 RefPtr
<DataSourceSurface
> data
=
127 Factory::CreateWrappingDataSourceSurface(destData
, destStride
, destSize
, destFormat
);
128 mGLContext
->Screen()->Readback(sharedSurf
, data
);
130 gfxUtils::PremultiplyDataSurface(data
, data
);
132 aDestTarget
->ReleaseBits(destData
);
135 aDestTarget
->ReleaseBits(destData
);
139 RefPtr
<SourceSurface
> resultSurf
;
140 if (sharedSurf
->mType
== SharedSurfaceType::Basic
&& !needsPremult
) {
141 SharedSurface_Basic
* sharedSurf_Basic
= SharedSurface_Basic::Cast(sharedSurf
);
142 resultSurf
= sharedSurf_Basic
->GetData();
144 RefPtr
<DataSourceSurface
> data
= GetTempSurface(readSize
, format
);
145 // There will already be a warning from inside of GetTempSurface, but
146 // it doesn't hurt to complain:
147 if (NS_WARN_IF(!data
)) {
151 // Readback handles Flush/MarkDirty.
152 mGLContext
->Screen()->Readback(sharedSurf
, data
);
154 gfxUtils::PremultiplyDataSurface(data
, data
);
158 MOZ_ASSERT(resultSurf
);
161 aDestTarget
->CopySurface(resultSurf
,
162 IntRect(0, 0, readSize
.width
, readSize
.height
),
165 // If !aDestSurface then we will end up painting using mSurface, so
166 // stick our surface into mSurface, so that the Paint() path is the same.
167 mSurface
= resultSurf
;
173 CopyableCanvasLayer::GetTempSurface(const IntSize
& aSize
,
174 const SurfaceFormat aFormat
)
176 if (!mCachedTempSurface
||
177 aSize
!= mCachedTempSurface
->GetSize() ||
178 aFormat
!= mCachedTempSurface
->GetFormat())
180 // Create a surface aligned to 8 bytes since that's the highest alignment WebGL can handle.
181 uint32_t stride
= GetAlignedStride
<8>(aSize
.width
* BytesPerPixel(aFormat
));
182 mCachedTempSurface
= Factory::CreateDataSourceSurfaceWithStride(aSize
, aFormat
, stride
);
185 return mCachedTempSurface
;
189 CopyableCanvasLayer::DiscardTempSurface()
191 mCachedTempSurface
= nullptr;