diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/2d/SourceSurfaceCapture.cpp | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/gfx/2d/SourceSurfaceCapture.cpp b/gfx/2d/SourceSurfaceCapture.cpp new file mode 100644 index 0000000000..227c0ddf34 --- /dev/null +++ b/gfx/2d/SourceSurfaceCapture.cpp @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SourceSurfaceCapture.h" +#include "DrawCommand.h" +#include "DrawTargetCapture.h" +#include "MainThreadUtils.h" +#include "mozilla/gfx/Logging.h" + +namespace mozilla { +namespace gfx { + +SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner) + : mOwner(aOwner), + mHasCommandList(false), + mShouldResolveToLuminance{false}, + mLuminanceType{LuminanceType::LUMINANCE}, + mOpacity{1.0f}, + mLock("SourceSurfaceCapture.mLock") { + mSize = mOwner->GetSize(); + mFormat = mOwner->GetFormat(); + mRefDT = mOwner->mRefDT; + mStride = mOwner->mStride; + mSurfaceAllocationSize = mOwner->mSurfaceAllocationSize; +} + +SourceSurfaceCapture::SourceSurfaceCapture( + DrawTargetCaptureImpl* aOwner, + LuminanceType aLuminanceType /* = LuminanceType::LINEARRGB */, + Float aOpacity /* = 1.0f */) + : mOwner{aOwner}, + mHasCommandList{false}, + mShouldResolveToLuminance{true}, + mLuminanceType{aLuminanceType}, + mOpacity{aOpacity}, + mLock{"SourceSurfaceCapture.mLock"} { + mSize = mOwner->GetSize(); + mFormat = mOwner->GetFormat(); + mRefDT = mOwner->mRefDT; + mStride = mOwner->mStride; + mSurfaceAllocationSize = mOwner->mSurfaceAllocationSize; + + // In this case our DrawTarget will not track us, so copy its drawing + // commands. + DrawTargetWillChange(); +} + +SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner, + SourceSurface* aSurfToOptimize) + : mOwner{aOwner}, + mHasCommandList{false}, + mShouldResolveToLuminance{false}, + mLuminanceType{LuminanceType::LUMINANCE}, + mOpacity{1.0f}, + mLock{"SourceSurfaceCapture.mLock"}, + mSurfToOptimize(aSurfToOptimize) { + mSize = aSurfToOptimize->GetSize(); + mFormat = aSurfToOptimize->GetFormat(); + mRefDT = mOwner->mRefDT; +} + +SourceSurfaceCapture::~SourceSurfaceCapture() = default; + +void SourceSurfaceCapture::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf, + SizeOfInfo& aInfo) const { + MutexAutoLock lock(mLock); + aInfo.AddType(SurfaceType::CAPTURE); + if (mSurfToOptimize) { + mSurfToOptimize->SizeOfExcludingThis(aMallocSizeOf, aInfo); + return; + } + if (mResolved) { + mResolved->SizeOfExcludingThis(aMallocSizeOf, aInfo); + return; + } + if (mHasCommandList) { + aInfo.mHeapBytes += mCommands.BufferCapacity(); + return; + } +} + +bool SourceSurfaceCapture::IsValid() const { + // We must either be able to source a command list, or we must have a cached + // and rasterized surface. + MutexAutoLock lock(mLock); + + if (mSurfToOptimize) { + // We were given a surface, but we haven't tried to optimize it yet + // with the reference draw target. + return mSurfToOptimize->IsValid(); + } + if (mResolved) { + // We were given a surface, and we already optimized it with the + // reference draw target. + return mResolved->IsValid(); + } + + // We have no underlying surface, so it must be a set of drawing commands. + return mOwner || mHasCommandList; +} + +RefPtr<SourceSurface> SourceSurfaceCapture::Resolve(BackendType aBackendType) { + MutexAutoLock lock(mLock); + + if (mSurfToOptimize) { + mResolved = mRefDT->OptimizeSourceSurface(mSurfToOptimize); + mSurfToOptimize = nullptr; + } + + if (mResolved || (!mOwner && !mHasCommandList)) { + // We are already resolved, or there is no way we can rasterize + // anything, we don't have a source DrawTarget and we don't have + // a command list. Return whatever our cached surface is. + return mResolved; + } + + BackendType backendType = aBackendType; + if (backendType == BackendType::NONE) { + backendType = mRefDT->GetBackendType(); + } + + // Note: SurfaceType is not 1:1 with BackendType, so we can't easily decide + // that they match. Instead we just cache the first thing to be requested. + // We ensured no mResolved existed before. + mResolved = ResolveImpl(backendType); + + return mResolved; +} + +RefPtr<SourceSurface> SourceSurfaceCapture::ResolveImpl( + BackendType aBackendType) { + RefPtr<DrawTarget> dt; + uint8_t* data = nullptr; + if (!mSurfaceAllocationSize) { + if (aBackendType == mRefDT->GetBackendType()) { + dt = mRefDT->CreateSimilarDrawTarget(mSize, mFormat); + } else { + dt = Factory::CreateDrawTarget(aBackendType, mSize, mFormat); + } + } else { + data = static_cast<uint8_t*>(calloc(1, mSurfaceAllocationSize)); + if (!data) { + return nullptr; + } + BackendType type = Factory::DoesBackendSupportDataDrawtarget(aBackendType) + ? aBackendType + : BackendType::SKIA; + dt = Factory::CreateDrawTargetForData(type, data, mSize, mStride, mFormat); + if (!dt || !dt->IsValid()) { + free(data); + return nullptr; + } + } + + if (!dt || !dt->IsValid()) { + // Make sure we haven't allocated and aren't leaking something, the code + // right anove here should have guaranteed that. + MOZ_ASSERT(!data); + return nullptr; + } + + // If we're still attached to a DrawTarget, use its command list rather than + // our own (which will be empty). + CaptureCommandList& commands = + mHasCommandList ? mCommands : mOwner->mCommands; + for (CaptureCommandList::iterator iter(commands); !iter.Done(); iter.Next()) { + DrawingCommand* cmd = iter.Get(); + cmd->ExecuteOnDT(dt, nullptr); + } + + RefPtr<SourceSurface> surf; + if (!mShouldResolveToLuminance) { + surf = dt->Snapshot(); + } else { + surf = dt->IntoLuminanceSource(mLuminanceType, mOpacity); + } + + if (data) { + surf->AddUserData(reinterpret_cast<UserDataKey*>(dt.get()), data, free); + } + + return surf; +} + +already_AddRefed<DataSourceSurface> SourceSurfaceCapture::GetDataSurface() { + RefPtr<SourceSurface> surface = Resolve(); + if (!surface) { + return nullptr; + } + return surface->GetDataSurface(); +} + +void SourceSurfaceCapture::DrawTargetWillDestroy() { + MutexAutoLock lock(mLock); + + // The source DrawTarget is going away, so we can just steal its commands. + mCommands = std::move(mOwner->mCommands); + mHasCommandList = true; + mOwner = nullptr; +} + +void SourceSurfaceCapture::DrawTargetWillChange() { + MutexAutoLock lock(mLock); + + for (CaptureCommandList::iterator iter(mOwner->mCommands); !iter.Done(); + iter.Next()) { + DrawingCommand* cmd = iter.Get(); + cmd->CloneInto(&mCommands); + } + + mHasCommandList = true; + mOwner = nullptr; +} + +} // namespace gfx +} // namespace mozilla |