Bumping manifests a=b2g-bump
[gecko.git] / gfx / layers / CopyableCanvasLayer.cpp
blob19e2ea770d57a72bac57cec0928a8248f9f3afa7
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
24 #include "gfxUtils.h"
26 namespace mozilla {
27 namespace layers {
29 using namespace mozilla::gfx;
30 using namespace mozilla::gl;
32 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
33 CanvasLayer(aLayerManager, aImplData)
34 , mStream(nullptr)
35 , mIsAlphaPremultiplied(true)
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 mStream = aData.mStream;
53 mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
54 mNeedsYFlip = true;
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();
62 mNeedsYFlip = false;
63 } else {
64 NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
67 mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
70 bool
71 CopyableCanvasLayer::IsDataValid(const Data& aData)
73 return mGLContext == aData.mGLContext && mStream == aData.mStream;
76 void
77 CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
79 if (!IsDirty())
80 return;
81 Painted();
83 if (mDrawTarget) {
84 mDrawTarget->Flush();
85 mSurface = mDrawTarget->Snapshot();
88 if (!mGLContext && aDestTarget) {
89 NS_ASSERTION(mSurface, "Must have surface to draw!");
90 if (mSurface) {
91 aDestTarget->CopySurface(mSurface,
92 IntRect(0, 0, mBounds.width, mBounds.height),
93 IntPoint(0, 0));
94 mSurface = nullptr;
96 return;
99 if (mGLContext) {
100 SharedSurface* sharedSurf = nullptr;
101 if (mStream) {
102 sharedSurf = mStream->SwapConsumer();
103 } else {
104 sharedSurf = mGLContext->RequestFrame();
107 if (!sharedSurf) {
108 NS_WARNING("Null frame received.");
109 return;
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
119 if (aDestTarget) {
120 uint8_t* destData;
121 IntSize destSize;
122 int32_t destStride;
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);
129 if (needsPremult) {
130 gfxUtils::PremultiplyDataSurface(data, data);
132 aDestTarget->ReleaseBits(destData);
133 return;
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();
143 } else {
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)) {
148 return;
151 // Readback handles Flush/MarkDirty.
152 mGLContext->Screen()->Readback(sharedSurf, data);
153 if (needsPremult) {
154 gfxUtils::PremultiplyDataSurface(data, data);
156 resultSurf = data;
158 MOZ_ASSERT(resultSurf);
160 if (aDestTarget) {
161 aDestTarget->CopySurface(resultSurf,
162 IntRect(0, 0, readSize.width, readSize.height),
163 IntPoint(0, 0));
164 } else {
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;
172 DataSourceSurface*
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;
188 void
189 CopyableCanvasLayer::DiscardTempSurface()
191 mCachedTempSurface = nullptr;