/src/mozilla-central/gfx/2d/SourceSurfaceCapture.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "SourceSurfaceCapture.h" |
8 | | #include "DrawCommand.h" |
9 | | #include "DrawTargetCapture.h" |
10 | | #include "MainThreadUtils.h" |
11 | | #include "mozilla/gfx/Logging.h" |
12 | | |
13 | | namespace mozilla { |
14 | | namespace gfx { |
15 | | |
16 | | SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner) |
17 | | : mOwner(aOwner), |
18 | | mHasCommandList(false), |
19 | | mShouldResolveToLuminance{false}, |
20 | | mLuminanceType{LuminanceType::LUMINANCE}, |
21 | | mOpacity{1.0f}, |
22 | | mLock("SourceSurfaceCapture.mLock") |
23 | 0 | { |
24 | 0 | mSize = mOwner->GetSize(); |
25 | 0 | mFormat = mOwner->GetFormat(); |
26 | 0 | mRefDT = mOwner->mRefDT; |
27 | 0 | mStride = mOwner->mStride; |
28 | 0 | mSurfaceAllocationSize = mOwner->mSurfaceAllocationSize; |
29 | 0 | } |
30 | | |
31 | | SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner, |
32 | | LuminanceType aLuminanceType /* = LuminanceType::LINEARRGB */, |
33 | | Float aOpacity /* = 1.0f */) |
34 | | : mOwner{aOwner} |
35 | | , mHasCommandList{false} |
36 | | , mShouldResolveToLuminance{true} |
37 | | , mLuminanceType{aLuminanceType} |
38 | | , mOpacity{aOpacity} |
39 | | , mLock{"SourceSurfaceCapture.mLock"} |
40 | 0 | { |
41 | 0 | mSize = mOwner->GetSize(); |
42 | 0 | mFormat = mOwner->GetFormat(); |
43 | 0 | mRefDT = mOwner->mRefDT; |
44 | 0 | mStride = mOwner->mStride; |
45 | 0 | mSurfaceAllocationSize = mOwner->mSurfaceAllocationSize; |
46 | 0 |
|
47 | 0 | // In this case our DrawTarget will not track us, so copy its drawing commands. |
48 | 0 | DrawTargetWillChange(); |
49 | 0 | } |
50 | | |
51 | | SourceSurfaceCapture::~SourceSurfaceCapture() |
52 | 0 | { |
53 | 0 | } |
54 | | |
55 | | bool |
56 | | SourceSurfaceCapture::IsValid() const |
57 | 0 | { |
58 | 0 | // We must either be able to source a command list, or we must have a cached |
59 | 0 | // and rasterized surface. |
60 | 0 | MutexAutoLock lock(mLock); |
61 | 0 | return (mOwner || mHasCommandList) || mResolved; |
62 | 0 | } |
63 | | |
64 | | RefPtr<SourceSurface> |
65 | | SourceSurfaceCapture::Resolve(BackendType aBackendType) |
66 | 0 | { |
67 | 0 | MutexAutoLock lock(mLock); |
68 | 0 |
|
69 | 0 | if (!mOwner && !mHasCommandList) { |
70 | 0 | // There is no way we can rasterize anything, we don't have a source |
71 | 0 | // DrawTarget and we don't have a command list. Return whatever our |
72 | 0 | // cached surface is. |
73 | 0 | return mResolved; |
74 | 0 | } |
75 | 0 | |
76 | 0 | BackendType backendType = aBackendType; |
77 | 0 | if (backendType == BackendType::NONE) { |
78 | 0 | backendType = mRefDT->GetBackendType(); |
79 | 0 | } |
80 | 0 |
|
81 | 0 | // If on the paint thread, we require that the owning DrawTarget be detached |
82 | 0 | // from this snapshot. This roughly approximates an assert that nothing can |
83 | 0 | // mutate the snapshot. |
84 | 0 | MOZ_RELEASE_ASSERT(NS_IsMainThread() || !mOwner); |
85 | 0 |
|
86 | 0 | // Note: SurfaceType is not 1:1 with BackendType, so we can't easily decide |
87 | 0 | // that they match. Instead we just cache the first thing to be requested. |
88 | 0 | if (!mResolved) { |
89 | 0 | mResolved = ResolveImpl(backendType); |
90 | 0 | } |
91 | 0 | return mResolved; |
92 | 0 | } |
93 | | |
94 | | RefPtr<SourceSurface> |
95 | | SourceSurfaceCapture::ResolveImpl(BackendType aBackendType) |
96 | 0 | { |
97 | 0 | RefPtr<DrawTarget> dt; |
98 | 0 | uint8_t* data = nullptr; |
99 | 0 | if (!mSurfaceAllocationSize) { |
100 | 0 | if (aBackendType == mRefDT->GetBackendType()) { |
101 | 0 | dt = mRefDT->CreateSimilarDrawTarget(mSize, mFormat); |
102 | 0 | } else { |
103 | 0 | dt = Factory::CreateDrawTarget(aBackendType, mSize, mFormat); |
104 | 0 | } |
105 | 0 | } else { |
106 | 0 | data = static_cast<uint8_t*>(calloc(1, mSurfaceAllocationSize)); |
107 | 0 | if (!data) { |
108 | 0 | return nullptr; |
109 | 0 | } |
110 | 0 | BackendType type = Factory::DoesBackendSupportDataDrawtarget(aBackendType) |
111 | 0 | ? aBackendType |
112 | 0 | : BackendType::SKIA; |
113 | 0 | dt = Factory::CreateDrawTargetForData(type, data, mSize, mStride, mFormat); |
114 | 0 | if (!dt) { |
115 | 0 | free(data); |
116 | 0 | return nullptr; |
117 | 0 | } |
118 | 0 | } |
119 | 0 | |
120 | 0 | if (!dt) { |
121 | 0 | // Make sure we haven't allocated and aren't leaking something, the code right |
122 | 0 | // anove here should have guaranteed that. |
123 | 0 | MOZ_ASSERT(!data); |
124 | 0 | return nullptr; |
125 | 0 | } |
126 | 0 |
|
127 | 0 | // If we're still attached to a DrawTarget, use its command list rather than |
128 | 0 | // our own (which will be empty). |
129 | 0 | CaptureCommandList& commands = mHasCommandList |
130 | 0 | ? mCommands |
131 | 0 | : mOwner->mCommands; |
132 | 0 | for (CaptureCommandList::iterator iter(commands); !iter.Done(); iter.Next()) { |
133 | 0 | DrawingCommand* cmd = iter.Get(); |
134 | 0 | cmd->ExecuteOnDT(dt, nullptr); |
135 | 0 | } |
136 | 0 |
|
137 | 0 | RefPtr<SourceSurface> surf; |
138 | 0 | if (!mShouldResolveToLuminance) { |
139 | 0 | surf = dt->Snapshot(); |
140 | 0 | } else { |
141 | 0 | surf = dt->IntoLuminanceSource(mLuminanceType, mOpacity); |
142 | 0 | } |
143 | 0 |
|
144 | 0 | if (data) { |
145 | 0 | surf->AddUserData(reinterpret_cast<UserDataKey*>(dt.get()), data, free); |
146 | 0 | } |
147 | 0 |
|
148 | 0 | return surf.forget(); |
149 | 0 | } |
150 | | |
151 | | already_AddRefed<DataSourceSurface> |
152 | | SourceSurfaceCapture::GetDataSurface() |
153 | 0 | { |
154 | 0 | RefPtr<SourceSurface> surface = Resolve(); |
155 | 0 | if (!surface) { |
156 | 0 | return nullptr; |
157 | 0 | } |
158 | 0 | return surface->GetDataSurface(); |
159 | 0 | } |
160 | | |
161 | | void |
162 | | SourceSurfaceCapture::DrawTargetWillDestroy() |
163 | 0 | { |
164 | 0 | MutexAutoLock lock(mLock); |
165 | 0 |
|
166 | 0 | // The source DrawTarget is going away, so we can just steal its commands. |
167 | 0 | mCommands = std::move(mOwner->mCommands); |
168 | 0 | mHasCommandList = true; |
169 | 0 | mOwner = nullptr; |
170 | 0 | } |
171 | | |
172 | | void |
173 | | SourceSurfaceCapture::DrawTargetWillChange() |
174 | 0 | { |
175 | 0 | MutexAutoLock lock(mLock); |
176 | 0 |
|
177 | 0 | for (CaptureCommandList::iterator iter(mOwner->mCommands); !iter.Done(); iter.Next()) { |
178 | 0 | DrawingCommand* cmd = iter.Get(); |
179 | 0 | cmd->CloneInto(&mCommands); |
180 | 0 | } |
181 | 0 |
|
182 | 0 | mHasCommandList = true; |
183 | 0 | mOwner = nullptr; |
184 | 0 | } |
185 | | |
186 | | } // namespace gfx |
187 | | } // namespace mozilla |