1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/CopyableCanvasLayer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,200 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "BasicLayersImpl.h" // for FillWithMask, etc 1.10 +#include "CopyableCanvasLayer.h" 1.11 +#include "GLContext.h" // for GLContext 1.12 +#include "GLScreenBuffer.h" // for GLScreenBuffer 1.13 +#include "SharedSurface.h" // for SharedSurface 1.14 +#include "SharedSurfaceGL.h" // for SharedSurface_GL, etc 1.15 +#include "SurfaceTypes.h" // for APITypeT, APITypeT::OpenGL, etc 1.16 +#include "gfxMatrix.h" // for gfxMatrix 1.17 +#include "gfxPattern.h" // for gfxPattern, etc 1.18 +#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat 1.19 +#include "gfxRect.h" // for gfxRect 1.20 +#include "gfxUtils.h" // for gfxUtils 1.21 +#include "gfx2DGlue.h" // for thebes --> moz2d transition 1.22 +#include "mozilla/gfx/BaseSize.h" // for BaseSize 1.23 +#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc 1.24 +#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc 1.25 +#include "nsRect.h" // for nsIntRect 1.26 +#include "nsSize.h" // for nsIntSize 1.27 +#include "LayerUtils.h" 1.28 + 1.29 +using namespace mozilla::gfx; 1.30 +using namespace mozilla::gl; 1.31 + 1.32 +namespace mozilla { 1.33 +namespace layers { 1.34 + 1.35 +CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) : 1.36 + CanvasLayer(aLayerManager, aImplData) 1.37 + , mStream(nullptr) 1.38 +{ 1.39 + MOZ_COUNT_CTOR(CopyableCanvasLayer); 1.40 +} 1.41 + 1.42 +CopyableCanvasLayer::~CopyableCanvasLayer() 1.43 +{ 1.44 + MOZ_COUNT_DTOR(CopyableCanvasLayer); 1.45 +} 1.46 + 1.47 +void 1.48 +CopyableCanvasLayer::Initialize(const Data& aData) 1.49 +{ 1.50 + NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!"); 1.51 + 1.52 + if (aData.mGLContext) { 1.53 + mGLContext = aData.mGLContext; 1.54 + mStream = aData.mStream; 1.55 + mIsGLAlphaPremult = aData.mIsGLAlphaPremult; 1.56 + mNeedsYFlip = true; 1.57 + MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen"); 1.58 + 1.59 + // [Basic Layers, non-OMTC] WebGL layer init. 1.60 + // `GLScreenBuffer::Morph`ing is only needed in BasicShadowableCanvasLayer. 1.61 + } else if (aData.mDrawTarget) { 1.62 + mDrawTarget = aData.mDrawTarget; 1.63 + mSurface = mDrawTarget->Snapshot(); 1.64 + mNeedsYFlip = false; 1.65 + } else { 1.66 + NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); 1.67 + } 1.68 + 1.69 + mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); 1.70 +} 1.71 + 1.72 +bool 1.73 +CopyableCanvasLayer::IsDataValid(const Data& aData) 1.74 +{ 1.75 + return mGLContext == aData.mGLContext && mStream == aData.mStream; 1.76 +} 1.77 + 1.78 +void 1.79 +CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) 1.80 +{ 1.81 + if (!IsDirty()) 1.82 + return; 1.83 + Painted(); 1.84 + 1.85 + if (mDrawTarget) { 1.86 + mDrawTarget->Flush(); 1.87 + mSurface = mDrawTarget->Snapshot(); 1.88 + } 1.89 + 1.90 + if (!mGLContext && aDestTarget) { 1.91 + NS_ASSERTION(mSurface, "Must have surface to draw!"); 1.92 + if (mSurface) { 1.93 + aDestTarget->CopySurface(mSurface, 1.94 + IntRect(0, 0, mBounds.width, mBounds.height), 1.95 + IntPoint(0, 0)); 1.96 + } 1.97 + return; 1.98 + } 1.99 + 1.100 + if (mGLContext) { 1.101 + RefPtr<DataSourceSurface> readSurf; 1.102 + RefPtr<SourceSurface> resultSurf; 1.103 + 1.104 + SharedSurface_GL* sharedSurf = nullptr; 1.105 + if (mStream) { 1.106 + sharedSurf = SharedSurface_GL::Cast(mStream->SwapConsumer()); 1.107 + } else { 1.108 + sharedSurf = mGLContext->RequestFrame(); 1.109 + } 1.110 + 1.111 + if (!sharedSurf) { 1.112 + NS_WARNING("Null frame received."); 1.113 + return; 1.114 + } 1.115 + 1.116 + IntSize readSize(sharedSurf->Size()); 1.117 + SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE) 1.118 + ? SurfaceFormat::B8G8R8X8 1.119 + : SurfaceFormat::B8G8R8A8; 1.120 + 1.121 + if (aDestTarget) { 1.122 + resultSurf = aDestTarget->Snapshot(); 1.123 + if (!resultSurf) { 1.124 + resultSurf = GetTempSurface(readSize, format); 1.125 + } 1.126 + } else { 1.127 + resultSurf = GetTempSurface(readSize, format); 1.128 + } 1.129 + MOZ_ASSERT(resultSurf); 1.130 + MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL); 1.131 + SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf); 1.132 + 1.133 + if (surfGL->Type() == SharedSurfaceType::Basic) { 1.134 + // sharedSurf_Basic->mData must outlive readSurf. Alas, readSurf may not 1.135 + // leave the scope it was declared in. 1.136 + SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); 1.137 + readSurf = sharedSurf_Basic->GetData(); 1.138 + } else { 1.139 + if (resultSurf->GetSize() != readSize || 1.140 + !(readSurf = resultSurf->GetDataSurface()) || 1.141 + readSurf->GetFormat() != format) 1.142 + { 1.143 + readSurf = GetTempSurface(readSize, format); 1.144 + } 1.145 + 1.146 + // Readback handles Flush/MarkDirty. 1.147 + mGLContext->Screen()->Readback(surfGL, readSurf); 1.148 + } 1.149 + MOZ_ASSERT(readSurf); 1.150 + 1.151 + bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult; 1.152 + if (needsPremult) { 1.153 + PremultiplySurface(readSurf); 1.154 + } 1.155 + 1.156 + if (readSurf != resultSurf) { 1.157 + RefPtr<DataSourceSurface> resultDataSurface = 1.158 + resultSurf->GetDataSurface(); 1.159 + RefPtr<DrawTarget> dt = 1.160 + Factory::CreateDrawTargetForData(BackendType::CAIRO, 1.161 + resultDataSurface->GetData(), 1.162 + resultDataSurface->GetSize(), 1.163 + resultDataSurface->Stride(), 1.164 + resultDataSurface->GetFormat()); 1.165 + IntSize readSize = readSurf->GetSize(); 1.166 + dt->CopySurface(readSurf, 1.167 + IntRect(0, 0, readSize.width, readSize.height), 1.168 + IntPoint(0, 0)); 1.169 + } 1.170 + 1.171 + // If !aDestSurface then we will end up painting using mSurface, so 1.172 + // stick our surface into mSurface, so that the Paint() path is the same. 1.173 + if (!aDestTarget) { 1.174 + mSurface = resultSurf; 1.175 + } 1.176 + } 1.177 +} 1.178 + 1.179 +DataSourceSurface* 1.180 +CopyableCanvasLayer::GetTempSurface(const IntSize& aSize, 1.181 + const SurfaceFormat aFormat) 1.182 +{ 1.183 + if (!mCachedTempSurface || 1.184 + aSize.width != mCachedSize.width || 1.185 + aSize.height != mCachedSize.height || 1.186 + aFormat != mCachedFormat) 1.187 + { 1.188 + mCachedTempSurface = Factory::CreateDataSourceSurface(aSize, aFormat); 1.189 + mCachedSize = aSize; 1.190 + mCachedFormat = aFormat; 1.191 + } 1.192 + 1.193 + return mCachedTempSurface; 1.194 +} 1.195 + 1.196 +void 1.197 +CopyableCanvasLayer::DiscardTempSurface() 1.198 +{ 1.199 + mCachedTempSurface = nullptr; 1.200 +} 1.201 + 1.202 +} 1.203 +}