Bumping manifests a=b2g-bump
[gecko.git] / gfx / layers / CopyableCanvasLayer.cpp
blob3889920faac0c19989ff590663a03e840ebbfaa4
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 "gfxPattern.h" // for gfxPattern, etc
13 #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
14 #include "gfxRect.h" // for gfxRect
15 #include "gfxUtils.h" // for gfxUtils
16 #include "gfx2DGlue.h" // for thebes --> moz2d transition
17 #include "mozilla/gfx/BaseSize.h" // for BaseSize
18 #include "mozilla/gfx/Tools.h"
19 #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
20 #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
21 #include "nsRect.h" // for nsIntRect
22 #include "nsSize.h" // for nsIntSize
23 #include "gfxUtils.h"
25 namespace mozilla {
26 namespace layers {
28 using namespace mozilla::gfx;
29 using namespace mozilla::gl;
31 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
32 CanvasLayer(aLayerManager, aImplData)
33 , mGLFrontbuffer(nullptr)
34 , mIsAlphaPremultiplied(true)
35 , mOriginPos(gl::OriginPos::TopLeft)
37 MOZ_COUNT_CTOR(CopyableCanvasLayer);
40 CopyableCanvasLayer::~CopyableCanvasLayer()
42 MOZ_COUNT_DTOR(CopyableCanvasLayer);
45 void
46 CopyableCanvasLayer::Initialize(const Data& aData)
48 NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!");
50 if (aData.mGLContext) {
51 mGLContext = aData.mGLContext;
52 mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
53 mOriginPos = gl::OriginPos::BottomLeft;
55 MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
57 if (aData.mFrontbufferGLTex) {
58 gfx::IntSize size(aData.mSize.width, aData.mSize.height);
59 mGLFrontbuffer = SharedSurface_GLTexture::Create(aData.mGLContext,
60 nullptr,
61 aData.mGLContext->GetGLFormats(),
62 size, aData.mHasAlpha,
63 aData.mFrontbufferGLTex);
65 } else if (aData.mDrawTarget) {
66 mDrawTarget = aData.mDrawTarget;
67 mSurface = mDrawTarget->Snapshot();
68 } else {
69 MOZ_CRASH("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
72 mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
75 bool
76 CopyableCanvasLayer::IsDataValid(const Data& aData)
78 return mGLContext == aData.mGLContext;
81 void
82 CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
84 if (mDrawTarget) {
85 mDrawTarget->Flush();
86 mSurface = mDrawTarget->Snapshot();
89 if (!mGLContext && aDestTarget) {
90 NS_ASSERTION(mSurface, "Must have surface to draw!");
91 if (mSurface) {
92 aDestTarget->CopySurface(mSurface,
93 IntRect(0, 0, mBounds.width, mBounds.height),
94 IntPoint(0, 0));
95 mSurface = nullptr;
97 return;
100 if (mDrawTarget) {
101 return;
104 MOZ_ASSERT(mGLContext);
106 SharedSurface* frontbuffer = nullptr;
107 if (mGLFrontbuffer) {
108 frontbuffer = mGLFrontbuffer.get();
109 } else {
110 GLScreenBuffer* screen = mGLContext->Screen();
111 ShSurfHandle* front = screen->Front();
112 if (front) {
113 frontbuffer = front->Surf();
117 if (!frontbuffer) {
118 NS_WARNING("Null frame received.");
119 return;
122 IntSize readSize(frontbuffer->mSize);
123 SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE)
124 ? SurfaceFormat::B8G8R8X8
125 : SurfaceFormat::B8G8R8A8;
126 bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
128 // Try to read back directly into aDestTarget's output buffer
129 if (aDestTarget) {
130 uint8_t* destData;
131 IntSize destSize;
132 int32_t destStride;
133 SurfaceFormat destFormat;
134 if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
135 if (destSize == readSize && destFormat == format) {
136 RefPtr<DataSourceSurface> data =
137 Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
138 mGLContext->Screen()->Readback(frontbuffer, data);
139 if (needsPremult) {
140 gfxUtils::PremultiplyDataSurface(data, data);
142 aDestTarget->ReleaseBits(destData);
143 return;
145 aDestTarget->ReleaseBits(destData);
149 RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
150 // There will already be a warning from inside of GetTempSurface, but
151 // it doesn't hurt to complain:
152 if (NS_WARN_IF(!resultSurf)) {
153 return;
156 // Readback handles Flush/MarkDirty.
157 mGLContext->Screen()->Readback(frontbuffer, resultSurf);
158 if (needsPremult) {
159 gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
161 MOZ_ASSERT(resultSurf);
163 if (aDestTarget) {
164 aDestTarget->CopySurface(resultSurf,
165 IntRect(0, 0, readSize.width, readSize.height),
166 IntPoint(0, 0));
167 } else {
168 // If !aDestSurface then we will end up painting using mSurface, so
169 // stick our surface into mSurface, so that the Paint() path is the same.
170 mSurface = resultSurf;
174 DataSourceSurface*
175 CopyableCanvasLayer::GetTempSurface(const IntSize& aSize,
176 const SurfaceFormat aFormat)
178 if (!mCachedTempSurface ||
179 aSize != mCachedTempSurface->GetSize() ||
180 aFormat != mCachedTempSurface->GetFormat())
182 // Create a surface aligned to 8 bytes since that's the highest alignment WebGL can handle.
183 uint32_t stride = GetAlignedStride<8>(aSize.width * BytesPerPixel(aFormat));
184 mCachedTempSurface = Factory::CreateDataSourceSurfaceWithStride(aSize, aFormat, stride);
187 return mCachedTempSurface;
190 void
191 CopyableCanvasLayer::DiscardTempSurface()
193 mCachedTempSurface = nullptr;