/src/mozilla-central/gfx/2d/DrawTargetCapture.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 "DrawTargetCapture.h" |
8 | | #include "DrawCommand.h" |
9 | | #include "DrawCommands.h" |
10 | | #include "gfxPlatform.h" |
11 | | #include "SourceSurfaceCapture.h" |
12 | | #include "FilterNodeCapture.h" |
13 | | |
14 | | namespace mozilla { |
15 | | namespace gfx { |
16 | | |
17 | | |
18 | | DrawTargetCaptureImpl::~DrawTargetCaptureImpl() |
19 | 0 | { |
20 | 0 | if (mSnapshot && !mSnapshot->hasOneRef()) { |
21 | 0 | mSnapshot->DrawTargetWillDestroy(); |
22 | 0 | mSnapshot = nullptr; |
23 | 0 | } |
24 | 0 | } |
25 | | |
26 | | DrawTargetCaptureImpl::DrawTargetCaptureImpl(gfx::DrawTarget* aTarget, size_t aFlushBytes) |
27 | | : mSnapshot(nullptr), |
28 | | mStride(0), |
29 | | mSurfaceAllocationSize(0), |
30 | | mFlushBytes(aFlushBytes) |
31 | 0 | { |
32 | 0 | mSize = aTarget->GetSize(); |
33 | 0 | mFormat = aTarget->GetFormat(); |
34 | 0 | SetPermitSubpixelAA(aTarget->GetPermitSubpixelAA()); |
35 | 0 |
|
36 | 0 | mRefDT = aTarget; |
37 | 0 | } |
38 | | |
39 | | DrawTargetCaptureImpl::DrawTargetCaptureImpl(BackendType aBackend, |
40 | | const IntSize& aSize, |
41 | | SurfaceFormat aFormat) |
42 | | : mSize(aSize), |
43 | | mSnapshot(nullptr), |
44 | | mStride(0), |
45 | | mSurfaceAllocationSize(0), |
46 | | mFlushBytes(0) |
47 | 0 | { |
48 | 0 | RefPtr<DrawTarget> screenRefDT = |
49 | 0 | gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); |
50 | 0 |
|
51 | 0 | mFormat = aFormat; |
52 | 0 | SetPermitSubpixelAA(IsOpaque(mFormat)); |
53 | 0 | if (aBackend == screenRefDT->GetBackendType()) { |
54 | 0 | mRefDT = screenRefDT; |
55 | 0 | } else { |
56 | 0 | // This situation can happen if a blur operation decides to |
57 | 0 | // use an unaccelerated path even if the system backend is |
58 | 0 | // Direct2D. |
59 | 0 | // |
60 | 0 | // We don't really want to encounter the reverse scenario: |
61 | 0 | // we shouldn't pick an accelerated backend if the system |
62 | 0 | // backend is skia. |
63 | 0 | if (aBackend == BackendType::DIRECT2D1_1) { |
64 | 0 | gfxWarning() << "Creating a RefDT in DrawTargetCapture."; |
65 | 0 | } |
66 | 0 |
|
67 | 0 | // Create a 1x1 size ref dt to create assets |
68 | 0 | // If we have to snapshot, we'll just create the real DT |
69 | 0 | IntSize size(1, 1); |
70 | 0 | mRefDT = Factory::CreateDrawTarget(aBackend, size, mFormat); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | bool |
75 | | DrawTargetCaptureImpl::Init(const IntSize& aSize, DrawTarget* aRefDT) |
76 | 0 | { |
77 | 0 | if (!aRefDT) { |
78 | 0 | return false; |
79 | 0 | } |
80 | 0 | |
81 | 0 | mRefDT = aRefDT; |
82 | 0 |
|
83 | 0 | mSize = aSize; |
84 | 0 | mFormat = aRefDT->GetFormat(); |
85 | 0 | SetPermitSubpixelAA(IsOpaque(mFormat)); |
86 | 0 | return true; |
87 | 0 | } |
88 | | |
89 | | void |
90 | | DrawTargetCaptureImpl::InitForData(int32_t aStride, size_t aSurfaceAllocationSize) |
91 | 0 | { |
92 | 0 | MOZ_ASSERT(!mFlushBytes); |
93 | 0 | mStride = aStride; |
94 | 0 | mSurfaceAllocationSize = aSurfaceAllocationSize; |
95 | 0 | } |
96 | | |
97 | | already_AddRefed<SourceSurface> |
98 | | DrawTargetCaptureImpl::Snapshot() |
99 | 0 | { |
100 | 0 | if (!mSnapshot) { |
101 | 0 | mSnapshot = new SourceSurfaceCapture(this); |
102 | 0 | } |
103 | 0 |
|
104 | 0 | RefPtr<SourceSurface> surface = mSnapshot; |
105 | 0 | return surface.forget(); |
106 | 0 | } |
107 | | |
108 | | already_AddRefed<SourceSurface> |
109 | | DrawTargetCaptureImpl::IntoLuminanceSource(LuminanceType aLuminanceType, |
110 | | float aOpacity) |
111 | 0 | { |
112 | 0 | RefPtr<SourceSurface> surface = new SourceSurfaceCapture(this, aLuminanceType, aOpacity); |
113 | 0 | return surface.forget(); |
114 | 0 | } |
115 | | |
116 | | already_AddRefed<SourceSurface> |
117 | | DrawTargetCaptureImpl::OptimizeSourceSurface(SourceSurface *aSurface) const |
118 | 0 | { |
119 | 0 | // If the surface is a recording, make sure it gets resolved on the paint thread. |
120 | 0 | if (aSurface->GetType() == SurfaceType::CAPTURE) { |
121 | 0 | RefPtr<SourceSurface> surface = aSurface; |
122 | 0 | return surface.forget(); |
123 | 0 | } |
124 | 0 | return mRefDT->OptimizeSourceSurface(aSurface); |
125 | 0 | } |
126 | | |
127 | | void |
128 | | DrawTargetCaptureImpl::DetachAllSnapshots() |
129 | 0 | { |
130 | 0 | MarkChanged(); |
131 | 0 | } |
132 | | |
133 | 0 | #define AppendCommand(arg) new (AppendToCommandList<arg>()) arg |
134 | 0 | #define ReuseOrAppendCommand(arg) new (ReuseOrAppendToCommandList<arg>()) arg |
135 | | |
136 | | void |
137 | | DrawTargetCaptureImpl::SetPermitSubpixelAA(bool aPermitSubpixelAA) |
138 | 0 | { |
139 | 0 | // Save memory by eliminating state changes with no effect |
140 | 0 | if (mPermitSubpixelAA == aPermitSubpixelAA) { |
141 | 0 | return; |
142 | 0 | } |
143 | 0 | |
144 | 0 | ReuseOrAppendCommand(SetPermitSubpixelAACommand)(aPermitSubpixelAA); |
145 | 0 |
|
146 | 0 | // Have to update mPermitSubpixelAA for this DT |
147 | 0 | // because some code paths query the current setting |
148 | 0 | // to determine subpixel AA eligibility. |
149 | 0 | DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA); |
150 | 0 | } |
151 | | |
152 | | void |
153 | | DrawTargetCaptureImpl::DrawSurface(SourceSurface *aSurface, |
154 | | const Rect &aDest, |
155 | | const Rect &aSource, |
156 | | const DrawSurfaceOptions &aSurfOptions, |
157 | | const DrawOptions &aOptions) |
158 | 0 | { |
159 | 0 | aSurface->GuaranteePersistance(); |
160 | 0 | AppendCommand(DrawSurfaceCommand)(aSurface, aDest, aSource, aSurfOptions, aOptions); |
161 | 0 | } |
162 | | |
163 | | void |
164 | | DrawTargetCaptureImpl::DrawSurfaceWithShadow(SourceSurface *aSurface, |
165 | | const Point &aDest, |
166 | | const Color &aColor, |
167 | | const Point &aOffset, |
168 | | Float aSigma, |
169 | | CompositionOp aOperator) |
170 | 0 | { |
171 | 0 | aSurface->GuaranteePersistance(); |
172 | 0 | AppendCommand(DrawSurfaceWithShadowCommand)(aSurface, aDest, aColor, aOffset, aSigma, aOperator); |
173 | 0 | } |
174 | | |
175 | | void |
176 | | DrawTargetCaptureImpl::DrawFilter(FilterNode *aNode, |
177 | | const Rect &aSourceRect, |
178 | | const Point &aDestPoint, |
179 | | const DrawOptions &aOptions) |
180 | 0 | { |
181 | 0 | // @todo XXX - this won't work properly long term yet due to filternodes not |
182 | 0 | // being immutable. |
183 | 0 | AppendCommand(DrawFilterCommand)(aNode, aSourceRect, aDestPoint, aOptions); |
184 | 0 | } |
185 | | |
186 | | void |
187 | | DrawTargetCaptureImpl::ClearRect(const Rect &aRect) |
188 | 0 | { |
189 | 0 | AppendCommand(ClearRectCommand)(aRect); |
190 | 0 | } |
191 | | |
192 | | void |
193 | | DrawTargetCaptureImpl::MaskSurface(const Pattern &aSource, |
194 | | SourceSurface *aMask, |
195 | | Point aOffset, |
196 | | const DrawOptions &aOptions) |
197 | 0 | { |
198 | 0 | aMask->GuaranteePersistance(); |
199 | 0 | AppendCommand(MaskSurfaceCommand)(aSource, aMask, aOffset, aOptions); |
200 | 0 | } |
201 | | |
202 | | void |
203 | | DrawTargetCaptureImpl::CopySurface(SourceSurface* aSurface, |
204 | | const IntRect& aSourceRect, |
205 | | const IntPoint& aDestination) |
206 | 0 | { |
207 | 0 | aSurface->GuaranteePersistance(); |
208 | 0 | AppendCommand(CopySurfaceCommand)(aSurface, aSourceRect, aDestination); |
209 | 0 | } |
210 | | |
211 | | void |
212 | | DrawTargetCaptureImpl::CopyRect(const IntRect &aSourceRect, |
213 | | const IntPoint &aDestination) |
214 | 0 | { |
215 | 0 | AppendCommand(CopyRectCommand)(aSourceRect, aDestination); |
216 | 0 | } |
217 | | |
218 | | void |
219 | | DrawTargetCaptureImpl::FillRect(const Rect& aRect, |
220 | | const Pattern& aPattern, |
221 | | const DrawOptions& aOptions) |
222 | 0 | { |
223 | 0 | AppendCommand(FillRectCommand)(aRect, aPattern, aOptions); |
224 | 0 | } |
225 | | |
226 | | void |
227 | | DrawTargetCaptureImpl::StrokeRect(const Rect& aRect, |
228 | | const Pattern& aPattern, |
229 | | const StrokeOptions& aStrokeOptions, |
230 | | const DrawOptions& aOptions) |
231 | 0 | { |
232 | 0 | AppendCommand(StrokeRectCommand)(aRect, aPattern, aStrokeOptions, aOptions); |
233 | 0 | } |
234 | | |
235 | | void |
236 | | DrawTargetCaptureImpl::StrokeLine(const Point& aStart, |
237 | | const Point& aEnd, |
238 | | const Pattern& aPattern, |
239 | | const StrokeOptions& aStrokeOptions, |
240 | | const DrawOptions& aOptions) |
241 | 0 | { |
242 | 0 | AppendCommand(StrokeLineCommand)(aStart, aEnd, aPattern, aStrokeOptions, aOptions); |
243 | 0 | } |
244 | | |
245 | | void |
246 | | DrawTargetCaptureImpl::Stroke(const Path* aPath, |
247 | | const Pattern& aPattern, |
248 | | const StrokeOptions& aStrokeOptions, |
249 | | const DrawOptions& aOptions) |
250 | 0 | { |
251 | 0 | AppendCommand(StrokeCommand)(aPath, aPattern, aStrokeOptions, aOptions); |
252 | 0 | } |
253 | | |
254 | | void |
255 | | DrawTargetCaptureImpl::Fill(const Path* aPath, |
256 | | const Pattern& aPattern, |
257 | | const DrawOptions& aOptions) |
258 | 0 | { |
259 | 0 | AppendCommand(FillCommand)(aPath, aPattern, aOptions); |
260 | 0 | } |
261 | | |
262 | | void |
263 | | DrawTargetCaptureImpl::FillGlyphs(ScaledFont* aFont, |
264 | | const GlyphBuffer& aBuffer, |
265 | | const Pattern& aPattern, |
266 | | const DrawOptions& aOptions) |
267 | 0 | { |
268 | 0 | AppendCommand(FillGlyphsCommand)(aFont, aBuffer, aPattern, aOptions); |
269 | 0 | } |
270 | | |
271 | | void DrawTargetCaptureImpl::StrokeGlyphs(ScaledFont* aFont, |
272 | | const GlyphBuffer& aBuffer, |
273 | | const Pattern& aPattern, |
274 | | const StrokeOptions& aStrokeOptions, |
275 | | const DrawOptions& aOptions) |
276 | 0 | { |
277 | 0 | AppendCommand(StrokeGlyphsCommand)(aFont, aBuffer, aPattern, aStrokeOptions, aOptions); |
278 | 0 | } |
279 | | |
280 | | void |
281 | | DrawTargetCaptureImpl::Mask(const Pattern &aSource, |
282 | | const Pattern &aMask, |
283 | | const DrawOptions &aOptions) |
284 | 0 | { |
285 | 0 | AppendCommand(MaskCommand)(aSource, aMask, aOptions); |
286 | 0 | } |
287 | | |
288 | | void |
289 | | DrawTargetCaptureImpl::PushClip(const Path* aPath) |
290 | 0 | { |
291 | 0 | AppendCommand(PushClipCommand)(aPath); |
292 | 0 | } |
293 | | |
294 | | void |
295 | | DrawTargetCaptureImpl::PushClipRect(const Rect& aRect) |
296 | 0 | { |
297 | 0 | AppendCommand(PushClipRectCommand)(aRect); |
298 | 0 | } |
299 | | |
300 | | void |
301 | | DrawTargetCaptureImpl::PushLayer(bool aOpaque, |
302 | | Float aOpacity, |
303 | | SourceSurface* aMask, |
304 | | const Matrix& aMaskTransform, |
305 | | const IntRect& aBounds, |
306 | | bool aCopyBackground) |
307 | 0 | { |
308 | 0 | // Have to update mPermitSubpixelAA for this DT |
309 | 0 | // because some code paths query the current setting |
310 | 0 | // to determine subpixel AA eligibility. |
311 | 0 | PushedLayer layer(GetPermitSubpixelAA()); |
312 | 0 | mPushedLayers.push_back(layer); |
313 | 0 | DrawTarget::SetPermitSubpixelAA(aOpaque); |
314 | 0 |
|
315 | 0 | if (aMask) { |
316 | 0 | aMask->GuaranteePersistance(); |
317 | 0 | } |
318 | 0 |
|
319 | 0 | AppendCommand(PushLayerCommand)(aOpaque, |
320 | 0 | aOpacity, |
321 | 0 | aMask, |
322 | 0 | aMaskTransform, |
323 | 0 | aBounds, |
324 | 0 | aCopyBackground); |
325 | 0 | } |
326 | | |
327 | | void |
328 | | DrawTargetCaptureImpl::PopLayer() |
329 | 0 | { |
330 | 0 | MOZ_ASSERT(mPushedLayers.size()); |
331 | 0 | DrawTarget::SetPermitSubpixelAA(mPushedLayers.back().mOldPermitSubpixelAA); |
332 | 0 | mPushedLayers.pop_back(); |
333 | 0 |
|
334 | 0 | AppendCommand(PopLayerCommand)(); |
335 | 0 | } |
336 | | |
337 | | void |
338 | | DrawTargetCaptureImpl::PopClip() |
339 | 0 | { |
340 | 0 | AppendCommand(PopClipCommand)(); |
341 | 0 | } |
342 | | |
343 | | void |
344 | | DrawTargetCaptureImpl::SetTransform(const Matrix& aTransform) |
345 | 0 | { |
346 | 0 | // Save memory by eliminating state changes with no effect |
347 | 0 | if (mTransform.ExactlyEquals(aTransform)) { |
348 | 0 | return; |
349 | 0 | } |
350 | 0 | |
351 | 0 | ReuseOrAppendCommand(SetTransformCommand)(aTransform); |
352 | 0 |
|
353 | 0 | // Have to update the transform for this DT |
354 | 0 | // because some code paths query the current transform |
355 | 0 | // to render specific things. |
356 | 0 | DrawTarget::SetTransform(aTransform); |
357 | 0 | } |
358 | | |
359 | | void |
360 | | DrawTargetCaptureImpl::Blur(const AlphaBoxBlur& aBlur) |
361 | 0 | { |
362 | 0 | // gfxAlphaBoxBlur should not use this if it takes the accelerated path. |
363 | 0 | MOZ_ASSERT(GetBackendType() == BackendType::SKIA); |
364 | 0 |
|
365 | 0 | AppendCommand(BlurCommand)(aBlur); |
366 | 0 | } |
367 | | |
368 | | void |
369 | | DrawTargetCaptureImpl::PadEdges(const IntRegion& aRegion) |
370 | 0 | { |
371 | 0 | AppendCommand(PadEdgesCommand)(aRegion); |
372 | 0 | } |
373 | | |
374 | | void |
375 | | DrawTargetCaptureImpl::ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform) |
376 | 0 | { |
377 | 0 | for (CaptureCommandList::iterator iter(mCommands); !iter.Done(); iter.Next()) { |
378 | 0 | DrawingCommand* cmd = iter.Get(); |
379 | 0 | cmd->ExecuteOnDT(aDT, &aTransform); |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | | void |
384 | | DrawTargetCaptureImpl::MarkChanged() |
385 | 0 | { |
386 | 0 | if (!mSnapshot) { |
387 | 0 | return; |
388 | 0 | } |
389 | 0 | |
390 | 0 | if (mSnapshot->hasOneRef()) { |
391 | 0 | mSnapshot = nullptr; |
392 | 0 | return; |
393 | 0 | } |
394 | 0 | |
395 | 0 | mSnapshot->DrawTargetWillChange(); |
396 | 0 | mSnapshot = nullptr; |
397 | 0 | } |
398 | | |
399 | | already_AddRefed<DrawTarget> |
400 | | DrawTargetCaptureImpl::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const |
401 | 0 | { |
402 | 0 | return MakeAndAddRef<DrawTargetCaptureImpl>(GetBackendType(), aSize, aFormat); |
403 | 0 | } |
404 | | |
405 | | RefPtr<DrawTarget> |
406 | | DrawTargetCaptureImpl::CreateSimilarRasterTarget(const IntSize& aSize, SurfaceFormat aFormat) const |
407 | 0 | { |
408 | 0 | MOZ_ASSERT(!mRefDT->IsCaptureDT()); |
409 | 0 | return mRefDT->CreateSimilarDrawTarget(aSize, aFormat); |
410 | 0 | } |
411 | | |
412 | | already_AddRefed<FilterNode> |
413 | | DrawTargetCaptureImpl::CreateFilter(FilterType aType) |
414 | 0 | { |
415 | 0 | if (mRefDT->GetBackendType() == BackendType::DIRECT2D1_1) { |
416 | 0 | return MakeRefPtr<FilterNodeCapture>(aType).forget(); |
417 | 0 | } else { |
418 | 0 | return mRefDT->CreateFilter(aType); |
419 | 0 | } |
420 | 0 | } |
421 | | |
422 | | bool |
423 | | DrawTargetCaptureImpl::IsEmpty() const |
424 | 0 | { |
425 | 0 | return mCommands.IsEmpty(); |
426 | 0 | } |
427 | | |
428 | | void |
429 | | DrawTargetCaptureImpl::Dump() |
430 | 0 | { |
431 | 0 | TreeLog output; |
432 | 0 | output << "DrawTargetCapture(" << (void*)(this) << ")\n"; |
433 | 0 | TreeAutoIndent indent(output); |
434 | 0 | mCommands.Log(output); |
435 | 0 | output << "\n"; |
436 | 0 | } |
437 | | |
438 | | } // namespace gfx |
439 | | } // namespace mozilla |