Update configs. IGNORE BROKEN CHANGESETS CLOSED TREE NO BUG a=release ba=release
[gecko.git] / gfx / 2d / DrawTargetRecording.cpp
blob2a1a1ca389cb949c74d4fcafb8a5050c6e5b3c0b
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/. */
7 #include "DrawTargetRecording.h"
8 #include "DrawTargetSkia.h"
9 #include "PathRecording.h"
10 #include <stdio.h>
12 #include "ImageContainer.h"
13 #include "Logging.h"
14 #include "Tools.h"
15 #include "Filters.h"
16 #include "mozilla/gfx/DataSurfaceHelpers.h"
17 #include "mozilla/layers/CanvasDrawEventRecorder.h"
18 #include "mozilla/layers/RecordedCanvasEventImpl.h"
19 #include "mozilla/layers/SourceSurfaceSharedData.h"
20 #include "mozilla/layers/TextureRecorded.h"
21 #include "mozilla/UniquePtr.h"
22 #include "nsXULAppAPI.h" // for XRE_IsContentProcess()
23 #include "RecordingTypes.h"
24 #include "RecordedEventImpl.h"
26 namespace mozilla {
27 namespace gfx {
29 struct RecordingSourceSurfaceUserData {
30 void* refPtr;
31 RefPtr<DrawEventRecorderPrivate> recorder;
33 // The optimized surface holds a reference to our surface, for GetDataSurface
34 // calls, so we must hold a weak reference to avoid circular dependency.
35 ThreadSafeWeakPtr<SourceSurface> optimizedSurface;
38 static void RecordingSourceSurfaceUserDataFunc(void* aUserData) {
39 RecordingSourceSurfaceUserData* userData =
40 static_cast<RecordingSourceSurfaceUserData*>(aUserData);
42 if (NS_IsMainThread()) {
43 userData->recorder->RecordSourceSurfaceDestruction(userData->refPtr);
44 delete userData;
45 return;
48 userData->recorder->AddPendingDeletion([userData]() -> void {
49 userData->recorder->RecordSourceSurfaceDestruction(userData->refPtr);
50 delete userData;
51 });
54 static bool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate* aRecorder,
55 SourceSurface* aSurface,
56 const char* reason) {
57 // It's important that TryAddStoredObject is called first because that will
58 // run any pending processing required by recorded objects that have been
59 // deleted off the main thread.
60 if (!aRecorder->TryAddStoredObject(aSurface)) {
61 // Surface is already stored.
62 return false;
64 aRecorder->StoreSourceSurfaceRecording(aSurface, reason);
65 aRecorder->AddSourceSurface(aSurface);
67 RecordingSourceSurfaceUserData* userData = new RecordingSourceSurfaceUserData;
68 userData->refPtr = aSurface;
69 userData->recorder = aRecorder;
70 aSurface->AddUserData(reinterpret_cast<UserDataKey*>(aRecorder), userData,
71 &RecordingSourceSurfaceUserDataFunc);
72 return true;
75 class SourceSurfaceRecording : public SourceSurface {
76 public:
77 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording, override)
79 SourceSurfaceRecording(IntSize aSize, SurfaceFormat aFormat,
80 DrawEventRecorderPrivate* aRecorder,
81 SourceSurface* aOriginalSurface = nullptr)
82 : mSize(aSize),
83 mFormat(aFormat),
84 mRecorder(aRecorder),
85 mOriginalSurface(aOriginalSurface) {
86 mRecorder->AddStoredObject(this);
89 ~SourceSurfaceRecording() {
90 mRecorder->RemoveStoredObject(this);
91 mRecorder->RecordEvent(
92 RecordedSourceSurfaceDestruction(ReferencePtr(this)));
95 SurfaceType GetType() const override { return SurfaceType::RECORDING; }
96 IntSize GetSize() const override { return mSize; }
97 SurfaceFormat GetFormat() const override { return mFormat; }
98 already_AddRefed<DataSourceSurface> GetDataSurface() override {
99 if (mOriginalSurface) {
100 return mOriginalSurface->GetDataSurface();
103 return nullptr;
106 already_AddRefed<SourceSurface> ExtractSubrect(const IntRect& aRect) override;
108 IntSize mSize;
109 SurfaceFormat mFormat;
110 RefPtr<DrawEventRecorderPrivate> mRecorder;
111 // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call
112 // we need GetDataSurface to work, so we hold the original surface we
113 // optimized to return its GetDataSurface.
114 RefPtr<SourceSurface> mOriginalSurface;
117 class GradientStopsRecording : public GradientStops {
118 public:
119 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording, override)
121 explicit GradientStopsRecording(DrawEventRecorderPrivate* aRecorder)
122 : mRecorder(aRecorder) {
123 mRecorder->AddStoredObject(this);
126 virtual ~GradientStopsRecording() {
127 mRecorder->RemoveStoredObject(this);
128 mRecorder->RecordEvent(
129 RecordedGradientStopsDestruction(ReferencePtr(this)));
132 BackendType GetBackendType() const override { return BackendType::RECORDING; }
134 RefPtr<DrawEventRecorderPrivate> mRecorder;
137 class FilterNodeRecording : public FilterNode {
138 public:
139 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording, override)
140 using FilterNode::SetAttribute;
142 explicit FilterNodeRecording(DrawEventRecorderPrivate* aRecorder)
143 : mRecorder(aRecorder) {
144 mRecorder->AddStoredObject(this);
147 virtual ~FilterNodeRecording() {
148 mRecorder->RemoveStoredObject(this);
149 mRecorder->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this)));
152 void SetInput(uint32_t aIndex, SourceSurface* aSurface) override {
153 EnsureSurfaceStoredRecording(mRecorder, aSurface, "SetInput");
155 mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aSurface));
157 void SetInput(uint32_t aIndex, FilterNode* aFilter) override {
158 MOZ_ASSERT(mRecorder->HasStoredObject(aFilter));
160 mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aFilter));
163 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
164 void SetAttribute(uint32_t aIndex, type aValue) override { \
165 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \
166 this, aIndex, aValue, \
167 RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
170 FORWARD_SET_ATTRIBUTE(bool, BOOL);
171 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32);
172 FORWARD_SET_ATTRIBUTE(Float, FLOAT);
173 FORWARD_SET_ATTRIBUTE(const Size&, SIZE);
174 FORWARD_SET_ATTRIBUTE(const IntSize&, INTSIZE);
175 FORWARD_SET_ATTRIBUTE(const IntPoint&, INTPOINT);
176 FORWARD_SET_ATTRIBUTE(const Rect&, RECT);
177 FORWARD_SET_ATTRIBUTE(const IntRect&, INTRECT);
178 FORWARD_SET_ATTRIBUTE(const Point&, POINT);
179 FORWARD_SET_ATTRIBUTE(const Matrix&, MATRIX);
180 FORWARD_SET_ATTRIBUTE(const Matrix5x4&, MATRIX5X4);
181 FORWARD_SET_ATTRIBUTE(const Point3D&, POINT3D);
182 FORWARD_SET_ATTRIBUTE(const DeviceColor&, COLOR);
184 #undef FORWARD_SET_ATTRIBUTE
186 void SetAttribute(uint32_t aIndex, const Float* aFloat,
187 uint32_t aSize) override {
188 mRecorder->RecordEvent(
189 RecordedFilterNodeSetAttribute(this, aIndex, aFloat, aSize));
192 FilterBackend GetBackendType() override { return FILTER_BACKEND_RECORDING; }
194 RefPtr<DrawEventRecorderPrivate> mRecorder;
197 DrawTargetRecording::DrawTargetRecording(
198 layers::CanvasDrawEventRecorder* aRecorder,
199 const layers::RemoteTextureOwnerId& aTextureOwnerId, DrawTarget* aDT,
200 const IntSize& aSize)
201 : mRecorder(static_cast<DrawEventRecorderPrivate*>(aRecorder)),
202 mFinalDT(aDT),
203 mRect(IntPoint(0, 0), aSize) {
204 RecordEventSkipFlushTransform(layers::RecordedCanvasDrawTargetCreation(
205 this, aTextureOwnerId, mFinalDT->GetBackendType(), aSize,
206 mFinalDT->GetFormat()));
207 mFormat = mFinalDT->GetFormat();
208 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat));
211 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder* aRecorder,
212 DrawTarget* aDT, IntRect aRect,
213 bool aHasData)
214 : mRecorder(static_cast<DrawEventRecorderPrivate*>(aRecorder)),
215 mFinalDT(aDT),
216 mRect(aRect) {
217 MOZ_DIAGNOSTIC_ASSERT(aRecorder->GetRecorderType() != RecorderType::CANVAS);
218 RefPtr<SourceSurface> snapshot = aHasData ? mFinalDT->Snapshot() : nullptr;
219 RecordEventSkipFlushTransform(
220 RecordedDrawTargetCreation(this, mFinalDT->GetBackendType(), mRect,
221 mFinalDT->GetFormat(), aHasData, snapshot));
222 mFormat = mFinalDT->GetFormat();
223 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat));
226 DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording* aDT,
227 IntRect aRect, SurfaceFormat aFormat)
228 : mRecorder(aDT->mRecorder), mFinalDT(aDT->mFinalDT), mRect(aRect) {
229 mFormat = aFormat;
230 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat));
233 DrawTargetRecording::~DrawTargetRecording() {
234 RecordEventSkipFlushTransform(
235 RecordedDrawTargetDestruction(ReferencePtr(this)));
236 mRecorder->ClearDrawTarget(this);
239 void DrawTargetRecording::Link(const char* aLocalDest, const char* aURI,
240 const Rect& aRect) {
241 MarkChanged();
243 RecordEventSelf(RecordedLink(aLocalDest, aURI, aRect));
246 void DrawTargetRecording::Destination(const char* aDestination,
247 const Point& aPoint) {
248 MarkChanged();
250 RecordEventSelf(RecordedDestination(aDestination, aPoint));
253 void DrawTargetRecording::FillRect(const Rect& aRect, const Pattern& aPattern,
254 const DrawOptions& aOptions) {
255 MarkChanged();
257 EnsurePatternDependenciesStored(aPattern);
259 RecordEventSelf(RecordedFillRect(aRect, aPattern, aOptions));
262 void DrawTargetRecording::StrokeRect(const Rect& aRect, const Pattern& aPattern,
263 const StrokeOptions& aStrokeOptions,
264 const DrawOptions& aOptions) {
265 MarkChanged();
267 EnsurePatternDependenciesStored(aPattern);
269 RecordEventSelf(
270 RecordedStrokeRect(aRect, aPattern, aStrokeOptions, aOptions));
273 void DrawTargetRecording::StrokeLine(const Point& aBegin, const Point& aEnd,
274 const Pattern& aPattern,
275 const StrokeOptions& aStrokeOptions,
276 const DrawOptions& aOptions) {
277 MarkChanged();
279 EnsurePatternDependenciesStored(aPattern);
281 RecordEventSelf(
282 RecordedStrokeLine(aBegin, aEnd, aPattern, aStrokeOptions, aOptions));
285 void DrawTargetRecording::Fill(const Path* aPath, const Pattern& aPattern,
286 const DrawOptions& aOptions) {
287 if (!aPath) {
288 return;
291 MarkChanged();
293 if (aPath->GetBackendType() == BackendType::RECORDING) {
294 const PathRecording* path = static_cast<const PathRecording*>(aPath);
295 auto circle = path->AsCircle();
296 if (circle) {
297 EnsurePatternDependenciesStored(aPattern);
298 RecordEventSelf(RecordedFillCircle(circle.value(), aPattern, aOptions));
299 return;
303 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
304 EnsurePatternDependenciesStored(aPattern);
305 RecordEventSelf(RecordedFill(pathRecording, aPattern, aOptions));
308 struct RecordingFontUserData {
309 void* refPtr;
310 void* unscaledFont;
311 RefPtr<DrawEventRecorderPrivate> recorder;
314 static void RecordingFontUserDataDestroyFunc(void* aUserData) {
315 RecordingFontUserData* userData =
316 static_cast<RecordingFontUserData*>(aUserData);
318 userData->recorder->RecordEvent(
319 RecordedScaledFontDestruction(ReferencePtr(userData->refPtr)));
320 userData->recorder->RemoveScaledFont((ScaledFont*)userData->refPtr);
321 userData->recorder->DecrementUnscaledFontRefCount(userData->unscaledFont);
322 delete userData;
325 void DrawTargetRecording::DrawGlyphs(ScaledFont* aFont,
326 const GlyphBuffer& aBuffer,
327 const Pattern& aPattern,
328 const DrawOptions& aOptions,
329 const StrokeOptions* aStrokeOptions) {
330 if (!aFont) {
331 return;
334 MarkChanged();
336 EnsurePatternDependenciesStored(aPattern);
338 UserDataKey* userDataKey = reinterpret_cast<UserDataKey*>(mRecorder.get());
339 if (mRecorder->WantsExternalFonts()) {
340 mRecorder->AddScaledFont(aFont);
341 } else if (!aFont->GetUserData(userDataKey)) {
342 UnscaledFont* unscaledFont = aFont->GetUnscaledFont();
343 if (mRecorder->IncrementUnscaledFontRefCount(unscaledFont) == 0) {
344 // Prefer sending the description, if we can create one. This ensures
345 // we don't record the data of system fonts which saves time and can
346 // prevent duplicate copies from accumulating in the OS cache during
347 // playback.
348 RecordedFontDescriptor fontDesc(unscaledFont);
349 if (fontDesc.IsValid()) {
350 RecordEventSkipFlushTransform(fontDesc);
351 } else {
352 RecordedFontData fontData(unscaledFont);
353 RecordedFontDetails fontDetails;
354 if (fontData.GetFontDetails(fontDetails)) {
355 // Try to serialise the whole font, just in case this is a web font
356 // that is not present on the system.
357 if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) {
358 RecordEventSkipFlushTransform(fontData);
359 mRecorder->AddStoredFontData(fontDetails.fontDataKey);
361 RecordEventSkipFlushTransform(
362 RecordedUnscaledFontCreation(unscaledFont, fontDetails));
363 } else {
364 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
365 "UnscaledFont";
369 RecordEventSkipFlushTransform(
370 RecordedScaledFontCreation(aFont, unscaledFont));
371 RecordingFontUserData* userData = new RecordingFontUserData;
372 userData->refPtr = aFont;
373 userData->unscaledFont = unscaledFont;
374 userData->recorder = mRecorder;
375 aFont->AddUserData(userDataKey, userData,
376 &RecordingFontUserDataDestroyFunc);
377 userData->recorder->AddScaledFont(aFont);
380 if (aStrokeOptions) {
381 RecordEventSelf(RecordedStrokeGlyphs(aFont, aPattern, *aStrokeOptions,
382 aOptions, aBuffer.mGlyphs,
383 aBuffer.mNumGlyphs));
384 } else {
385 RecordEventSelf(RecordedFillGlyphs(aFont, aPattern, aOptions,
386 aBuffer.mGlyphs, aBuffer.mNumGlyphs));
390 void DrawTargetRecording::FillGlyphs(ScaledFont* aFont,
391 const GlyphBuffer& aBuffer,
392 const Pattern& aPattern,
393 const DrawOptions& aOptions) {
394 DrawGlyphs(aFont, aBuffer, aPattern, aOptions);
397 void DrawTargetRecording::StrokeGlyphs(ScaledFont* aFont,
398 const GlyphBuffer& aBuffer,
399 const Pattern& aPattern,
400 const StrokeOptions& aStrokeOptions,
401 const DrawOptions& aOptions) {
402 DrawGlyphs(aFont, aBuffer, aPattern, aOptions, &aStrokeOptions);
405 void DrawTargetRecording::Mask(const Pattern& aSource, const Pattern& aMask,
406 const DrawOptions& aOptions) {
407 MarkChanged();
409 EnsurePatternDependenciesStored(aSource);
410 EnsurePatternDependenciesStored(aMask);
412 RecordEventSelf(RecordedMask(aSource, aMask, aOptions));
415 void DrawTargetRecording::MaskSurface(const Pattern& aSource,
416 SourceSurface* aMask, Point aOffset,
417 const DrawOptions& aOptions) {
418 if (!aMask) {
419 return;
422 MarkChanged();
424 EnsurePatternDependenciesStored(aSource);
425 EnsureSurfaceStoredRecording(mRecorder, aMask, "MaskSurface");
427 RecordEventSelf(RecordedMaskSurface(aSource, aMask, aOffset, aOptions));
430 void DrawTargetRecording::Stroke(const Path* aPath, const Pattern& aPattern,
431 const StrokeOptions& aStrokeOptions,
432 const DrawOptions& aOptions) {
433 MarkChanged();
435 if (aPath->GetBackendType() == BackendType::RECORDING) {
436 const PathRecording* path = static_cast<const PathRecording*>(aPath);
437 auto circle = path->AsCircle();
438 if (circle && circle->closed) {
439 EnsurePatternDependenciesStored(aPattern);
440 RecordEventSelf(RecordedStrokeCircle(circle.value(), aPattern,
441 aStrokeOptions, aOptions));
442 return;
445 auto line = path->AsLine();
446 if (line) {
447 EnsurePatternDependenciesStored(aPattern);
448 RecordEventSelf(RecordedStrokeLine(line->origin, line->destination,
449 aPattern, aStrokeOptions, aOptions));
450 return;
454 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
455 EnsurePatternDependenciesStored(aPattern);
457 RecordEventSelf(
458 RecordedStroke(pathRecording, aPattern, aStrokeOptions, aOptions));
461 void DrawTargetRecording::DrawShadow(const Path* aPath, const Pattern& aPattern,
462 const ShadowOptions& aShadow,
463 const DrawOptions& aOptions,
464 const StrokeOptions* aStrokeOptions) {
465 MarkChanged();
467 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
468 EnsurePatternDependenciesStored(aPattern);
470 RecordEventSelf(RecordedDrawShadow(pathRecording, aPattern, aShadow, aOptions,
471 aStrokeOptions));
474 void DrawTargetRecording::MarkChanged() {
475 if (mTextureData) {
476 mTextureData->DrawTargetWillChange();
480 already_AddRefed<SourceSurface> DrawTargetRecording::Snapshot() {
481 RefPtr<SourceSurface> retSurf =
482 new SourceSurfaceRecording(mRect.Size(), mFormat, mRecorder);
484 RecordEventSelfSkipFlushTransform(RecordedSnapshot(ReferencePtr(retSurf)));
486 return retSurf.forget();
489 already_AddRefed<SourceSurface> DrawTargetRecording::IntoLuminanceSource(
490 LuminanceType aLuminanceType, float aOpacity) {
491 RefPtr<SourceSurface> retSurf =
492 new SourceSurfaceRecording(mRect.Size(), SurfaceFormat::A8, mRecorder);
494 RecordEventSelfSkipFlushTransform(
495 RecordedIntoLuminanceSource(retSurf, aLuminanceType, aOpacity));
497 return retSurf.forget();
500 already_AddRefed<SourceSurface> SourceSurfaceRecording::ExtractSubrect(
501 const IntRect& aRect) {
502 if (aRect.IsEmpty() || !GetRect().Contains(aRect)) {
503 return nullptr;
506 RefPtr<SourceSurface> subSurf =
507 new SourceSurfaceRecording(aRect.Size(), mFormat, mRecorder);
508 mRecorder->RecordEvent(RecordedExtractSubrect(subSurf, this, aRect));
509 return subSurf.forget();
512 void DrawTargetRecording::Flush() {
513 RecordEventSelfSkipFlushTransform(RecordedFlush());
516 void DrawTargetRecording::DetachAllSnapshots() {
517 RecordEventSelfSkipFlushTransform(RecordedDetachAllSnapshots());
520 void DrawTargetRecording::DrawSurface(SourceSurface* aSurface,
521 const Rect& aDest, const Rect& aSource,
522 const DrawSurfaceOptions& aSurfOptions,
523 const DrawOptions& aOptions) {
524 if (!aSurface) {
525 return;
528 MarkChanged();
530 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurface");
532 RecordEventSelf(
533 RecordedDrawSurface(aSurface, aDest, aSource, aSurfOptions, aOptions));
536 void DrawTargetRecording::DrawSurfaceDescriptor(
537 const layers::SurfaceDescriptor& aDesc,
538 const RefPtr<layers::Image>& aImageOfSurfaceDescriptor, const Rect& aDest,
539 const Rect& aSource, const DrawSurfaceOptions& aSurfOptions,
540 const DrawOptions& aOptions) {
541 MarkChanged();
543 mRecorder->StoreImageRecording(aImageOfSurfaceDescriptor,
544 "DrawSurfaceDescriptor");
546 RecordEventSelf(RecordedDrawSurfaceDescriptor(aDesc, aDest, aSource,
547 aSurfOptions, aOptions));
550 void DrawTargetRecording::DrawDependentSurface(uint64_t aId,
551 const Rect& aDest) {
552 MarkChanged();
554 mRecorder->AddDependentSurface(aId);
555 RecordEventSelf(RecordedDrawDependentSurface(aId, aDest));
558 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface* aSurface,
559 const Point& aDest,
560 const ShadowOptions& aShadow,
561 CompositionOp aOp) {
562 if (!aSurface) {
563 return;
566 MarkChanged();
568 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurfaceWithShadow");
570 RecordEventSelf(RecordedDrawSurfaceWithShadow(aSurface, aDest, aShadow, aOp));
573 void DrawTargetRecording::DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
574 const Point& aDestPoint,
575 const DrawOptions& aOptions) {
576 if (!aNode) {
577 return;
580 MarkChanged();
582 MOZ_ASSERT(mRecorder->HasStoredObject(aNode));
584 RecordEventSelf(RecordedDrawFilter(aNode, aSourceRect, aDestPoint, aOptions));
587 already_AddRefed<FilterNode> DrawTargetRecording::CreateFilter(
588 FilterType aType) {
589 RefPtr<FilterNode> retNode = new FilterNodeRecording(mRecorder);
591 RecordEventSelfSkipFlushTransform(RecordedFilterNodeCreation(retNode, aType));
593 return retNode.forget();
596 void DrawTargetRecording::ClearRect(const Rect& aRect) {
597 MarkChanged();
599 RecordEventSelf(RecordedClearRect(aRect));
602 void DrawTargetRecording::CopySurface(SourceSurface* aSurface,
603 const IntRect& aSourceRect,
604 const IntPoint& aDestination) {
605 if (!aSurface) {
606 return;
609 MarkChanged();
611 EnsureSurfaceStoredRecording(mRecorder, aSurface, "CopySurface");
613 RecordEventSelf(RecordedCopySurface(aSurface, aSourceRect, aDestination));
616 void DrawTargetRecording::PushClip(const Path* aPath) {
617 if (!aPath) {
618 return;
621 // The canvas doesn't have a clipRect API so we always end up in the generic
622 // path. The D2D backend doesn't have a good way of specializing rectangular
623 // clips so we take advantage of the fact that aPath is usually backed by a
624 // SkiaPath which implements AsRect() and specialize it here.
625 auto rect = aPath->AsRect();
626 if (rect.isSome()) {
627 PushClipRect(rect.value());
628 return;
631 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
632 RecordEventSelf(RecordedPushClip(ReferencePtr(pathRecording)));
635 void DrawTargetRecording::PushClipRect(const Rect& aRect) {
636 RecordEventSelf(RecordedPushClipRect(aRect));
639 void DrawTargetRecording::PopClip() {
640 RecordEventSelfSkipFlushTransform(RecordedPopClip());
643 bool DrawTargetRecording::RemoveAllClips() {
644 RecordEventSelfSkipFlushTransform(RecordedRemoveAllClips());
645 return true;
648 void DrawTargetRecording::PushLayer(bool aOpaque, Float aOpacity,
649 SourceSurface* aMask,
650 const Matrix& aMaskTransform,
651 const IntRect& aBounds,
652 bool aCopyBackground) {
653 if (aMask) {
654 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer");
657 RecordEventSelf(RecordedPushLayer(aOpaque, aOpacity, aMask, aMaskTransform,
658 aBounds, aCopyBackground));
660 PushedLayer layer(GetPermitSubpixelAA());
661 mPushedLayers.push_back(layer);
662 DrawTarget::SetPermitSubpixelAA(aOpaque);
665 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque, Float aOpacity,
666 SourceSurface* aMask,
667 const Matrix& aMaskTransform,
668 const IntRect& aBounds,
669 bool aCopyBackground,
670 CompositionOp aCompositionOp) {
671 if (aMask) {
672 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer");
675 RecordEventSelf(RecordedPushLayerWithBlend(aOpaque, aOpacity, aMask,
676 aMaskTransform, aBounds,
677 aCopyBackground, aCompositionOp));
679 PushedLayer layer(GetPermitSubpixelAA());
680 mPushedLayers.push_back(layer);
681 DrawTarget::SetPermitSubpixelAA(aOpaque);
684 void DrawTargetRecording::PopLayer() {
685 MarkChanged();
687 RecordEventSelfSkipFlushTransform(RecordedPopLayer());
689 const PushedLayer& layer = mPushedLayers.back();
690 DrawTarget::SetPermitSubpixelAA(layer.mOldPermitSubpixelAA);
691 mPushedLayers.pop_back();
694 already_AddRefed<SourceSurface>
695 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData,
696 const IntSize& aSize,
697 int32_t aStride,
698 SurfaceFormat aFormat) const {
699 RefPtr<SourceSurface> surface = CreateDataSourceSurfaceWithStrideFromData(
700 aSize, aFormat, aStride, aData, aStride);
701 if (!surface) {
702 return nullptr;
705 return OptimizeSourceSurface(surface);
708 already_AddRefed<SourceSurface> DrawTargetRecording::OptimizeSourceSurface(
709 SourceSurface* aSurface) const {
710 // See if we have a previously optimized surface available. We have to do this
711 // check before the SurfaceType::RECORDING below, because aSurface might be a
712 // SurfaceType::RECORDING from another recorder we have previously optimized.
713 auto* userData = static_cast<RecordingSourceSurfaceUserData*>(
714 aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get())));
715 if (userData) {
716 RefPtr<SourceSurface> strongRef(userData->optimizedSurface);
717 if (strongRef) {
718 return do_AddRef(strongRef);
720 } else {
721 if (!EnsureSurfaceStoredRecording(mRecorder, aSurface,
722 "OptimizeSourceSurface")) {
723 // Surface was already stored, but doesn't have UserData so must be one
724 // of our recording surfaces.
725 MOZ_ASSERT(aSurface->GetType() == SurfaceType::RECORDING);
726 return do_AddRef(aSurface);
729 userData = static_cast<RecordingSourceSurfaceUserData*>(
730 aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get())));
731 MOZ_ASSERT(userData,
732 "User data should always have been set by "
733 "EnsureSurfaceStoredRecording.");
736 RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording(
737 aSurface->GetSize(), aSurface->GetFormat(), mRecorder, aSurface);
738 RecordEventSelfSkipFlushTransform(
739 RecordedOptimizeSourceSurface(aSurface, retSurf));
740 userData->optimizedSurface = retSurf;
742 return retSurf.forget();
745 already_AddRefed<SourceSurface>
746 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
747 const NativeSurface& aSurface) const {
748 MOZ_ASSERT(false);
749 return nullptr;
752 already_AddRefed<DrawTarget>
753 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
754 const IntSize& aSize, SurfaceFormat aFormat) const {
755 if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) {
756 // If the requested similar draw target is too big, then we should try to
757 // rasterize on the content side to avoid duplicating the effort when a
758 // blob image gets tiled. If we fail somehow to produce it, we can fall
759 // back to recording.
760 constexpr int32_t kRasterThreshold = 256 * 256 * 4;
761 int32_t stride = aSize.width * BytesPerPixel(aFormat);
762 int32_t surfaceBytes = aSize.height * stride;
763 if (surfaceBytes >= kRasterThreshold) {
764 auto surface = MakeRefPtr<SourceSurfaceSharedData>();
765 if (surface->Init(aSize, stride, aFormat)) {
766 auto dt = MakeRefPtr<DrawTargetSkia>();
767 if (dt->Init(std::move(surface))) {
768 return dt.forget();
769 } else {
770 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
776 return CreateSimilarDrawTarget(aSize, aFormat);
779 already_AddRefed<DrawTarget> DrawTargetRecording::CreateSimilarDrawTarget(
780 const IntSize& aSize, SurfaceFormat aFormat) const {
781 RefPtr<DrawTargetRecording> similarDT;
782 if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) {
783 similarDT =
784 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize), aFormat);
785 similarDT->SetOptimizeTransform(mOptimizeTransform);
786 RecordEventSelfSkipFlushTransform(
787 RecordedCreateSimilarDrawTarget(similarDT.get(), aSize, aFormat));
788 } else if (XRE_IsContentProcess()) {
789 // Crash any content process that calls this function with arguments that
790 // would fail to create a similar draw target. We do this to root out bad
791 // callers. We don't want to crash any important processes though so for
792 // for those we'll just gracefully return nullptr.
793 MOZ_CRASH(
794 "Content-process DrawTargetRecording can't create requested similar "
795 "drawtarget");
797 return similarDT.forget();
800 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
801 const IntSize& aSize, SurfaceFormat aFormat) const {
802 return mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat);
805 RefPtr<DrawTarget> DrawTargetRecording::CreateClippedDrawTarget(
806 const Rect& aBounds, SurfaceFormat aFormat) {
807 RefPtr<DrawTargetRecording> similarDT =
808 new DrawTargetRecording(this, mRect, aFormat);
809 similarDT->SetOptimizeTransform(mOptimizeTransform);
810 RecordEventSelf(
811 RecordedCreateClippedDrawTarget(similarDT.get(), aBounds, aFormat));
812 similarDT->mTransform = similarDT->mRecordedTransform = mTransform;
813 return similarDT;
816 already_AddRefed<DrawTarget>
817 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
818 const IntSize& aMaxSize, SurfaceFormat aFormat, FilterNode* aFilter,
819 FilterNode* aSource, const Rect& aSourceRect, const Point& aDestPoint) {
820 RefPtr<DrawTargetRecording> similarDT;
821 if (mFinalDT->CanCreateSimilarDrawTarget(aMaxSize, aFormat)) {
822 similarDT = new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize),
823 aFormat);
824 similarDT->SetOptimizeTransform(mOptimizeTransform);
825 // RecordedCreateDrawTargetForFilter::PlayEvent uses the transform, despite
826 // the fact that the underlying DrawTarget does not.
827 RecordEventSelf(RecordedCreateDrawTargetForFilter(similarDT.get(), aMaxSize,
828 aFormat, aFilter, aSource,
829 aSourceRect, aDestPoint));
830 } else if (XRE_IsContentProcess()) {
831 // See CreateSimilarDrawTarget
832 MOZ_CRASH(
833 "Content-process DrawTargetRecording can't create requested clipped "
834 "drawtarget");
836 return similarDT.forget();
839 already_AddRefed<PathBuilder> DrawTargetRecording::CreatePathBuilder(
840 FillRule aFillRule) const {
841 return MakeAndAddRef<PathBuilderRecording>(mFinalDT->GetBackendType(),
842 aFillRule);
845 already_AddRefed<GradientStops> DrawTargetRecording::CreateGradientStops(
846 GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode) const {
847 RefPtr<GradientStops> retStops = new GradientStopsRecording(mRecorder);
849 RecordEventSelfSkipFlushTransform(
850 RecordedGradientStopsCreation(retStops, aStops, aNumStops, aExtendMode));
852 return retStops.forget();
855 void DrawTargetRecording::SetTransform(const Matrix& aTransform) {
856 DrawTarget::SetTransform(aTransform);
857 if (!mOptimizeTransform) {
858 FlushTransform();
862 void DrawTargetRecording::RecordTransform(const Matrix& aTransform) const {
863 RecordEventSelfSkipFlushTransform(RecordedSetTransform(aTransform));
864 mRecordedTransform = aTransform;
867 void DrawTargetRecording::SetPermitSubpixelAA(bool aPermitSubpixelAA) {
868 if (aPermitSubpixelAA == mPermitSubpixelAA) {
869 return;
871 DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA);
872 RecordEventSelfSkipFlushTransform(
873 RecordedSetPermitSubpixelAA(aPermitSubpixelAA));
876 already_AddRefed<PathRecording> DrawTargetRecording::EnsurePathStored(
877 const Path* aPath) {
878 RefPtr<PathRecording> pathRecording;
879 if (aPath->GetBackendType() == BackendType::RECORDING) {
880 pathRecording =
881 const_cast<PathRecording*>(static_cast<const PathRecording*>(aPath));
882 if (!mRecorder->TryAddStoredObject(pathRecording)) {
883 // Path is already stored.
884 return pathRecording.forget();
886 } else {
887 MOZ_ASSERT(!mRecorder->HasStoredObject(aPath));
888 FillRule fillRule = aPath->GetFillRule();
889 RefPtr<PathBuilderRecording> builderRecording =
890 new PathBuilderRecording(mFinalDT->GetBackendType(), fillRule);
891 aPath->StreamToSink(builderRecording);
892 pathRecording = builderRecording->Finish().downcast<PathRecording>();
893 mRecorder->AddStoredObject(pathRecording);
896 // It's important that AddStoredObject or TryAddStoredObject is called before
897 // this because that will run any pending processing required by recorded
898 // objects that have been deleted off the main thread.
899 RecordEventSelfSkipFlushTransform(RecordedPathCreation(pathRecording.get()));
900 pathRecording->mStoredRecorders.push_back(mRecorder);
902 return pathRecording.forget();
905 // This should only be called on the 'root' DrawTargetRecording.
906 // Calling it on a child DrawTargetRecordings will cause confusion.
907 void DrawTargetRecording::FlushItem(const IntRect& aBounds) {
908 mRecorder->FlushItem(aBounds);
909 // Reinitialize the recorder (FlushItem will write a new recording header)
910 // Tell the new recording about our draw target
911 // This code should match what happens in the DrawTargetRecording constructor.
912 MOZ_DIAGNOSTIC_ASSERT(mRecorder->GetRecorderType() ==
913 RecorderType::WEBRENDER);
914 RecordEventSkipFlushTransform(
915 RecordedDrawTargetCreation(this, mFinalDT->GetBackendType(), mRect,
916 mFinalDT->GetFormat(), false, nullptr));
917 // RecordedDrawTargetCreation can actually reuse the base DrawTarget for the
918 // recording, but we cannot conclude that from here, so force the transform
919 // to be recorded.
920 RecordTransform(mTransform);
921 mTransformDirty = false;
924 void DrawTargetRecording::EnsurePatternDependenciesStored(
925 const Pattern& aPattern) {
926 switch (aPattern.GetType()) {
927 case PatternType::COLOR:
928 // No dependencies here.
929 return;
930 case PatternType::LINEAR_GRADIENT: {
931 MOZ_ASSERT_IF(
932 static_cast<const LinearGradientPattern*>(&aPattern)->mStops,
933 mRecorder->HasStoredObject(
934 static_cast<const LinearGradientPattern*>(&aPattern)->mStops));
935 return;
937 case PatternType::RADIAL_GRADIENT: {
938 MOZ_ASSERT_IF(
939 static_cast<const RadialGradientPattern*>(&aPattern)->mStops,
940 mRecorder->HasStoredObject(
941 static_cast<const RadialGradientPattern*>(&aPattern)->mStops));
942 return;
944 case PatternType::CONIC_GRADIENT: {
945 MOZ_ASSERT_IF(
946 static_cast<const ConicGradientPattern*>(&aPattern)->mStops,
947 mRecorder->HasStoredObject(
948 static_cast<const ConicGradientPattern*>(&aPattern)->mStops));
949 return;
951 case PatternType::SURFACE: {
952 const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aPattern);
953 EnsureSurfaceStoredRecording(mRecorder, pat->mSurface,
954 "EnsurePatternDependenciesStored");
955 return;
960 } // namespace gfx
961 } // namespace mozilla