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"
12 #include "ImageContainer.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"
29 struct RecordingSourceSurfaceUserData
{
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
);
48 userData
->recorder
->AddPendingDeletion([userData
]() -> void {
49 userData
->recorder
->RecordSourceSurfaceDestruction(userData
->refPtr
);
54 static bool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate
* aRecorder
,
55 SourceSurface
* aSurface
,
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.
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
);
75 class SourceSurfaceRecording
: public SourceSurface
{
77 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording
, override
)
79 SourceSurfaceRecording(IntSize aSize
, SurfaceFormat aFormat
,
80 DrawEventRecorderPrivate
* aRecorder
,
81 SourceSurface
* aOriginalSurface
= nullptr)
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();
106 already_AddRefed
<SourceSurface
> ExtractSubrect(const IntRect
& aRect
) override
;
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
{
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
{
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
)),
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
,
214 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
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
) {
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
,
243 RecordEventSelf(RecordedLink(aLocalDest
, aURI
, aRect
));
246 void DrawTargetRecording::Destination(const char* aDestination
,
247 const Point
& aPoint
) {
250 RecordEventSelf(RecordedDestination(aDestination
, aPoint
));
253 void DrawTargetRecording::FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
254 const DrawOptions
& aOptions
) {
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
) {
267 EnsurePatternDependenciesStored(aPattern
);
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
) {
279 EnsurePatternDependenciesStored(aPattern
);
282 RecordedStrokeLine(aBegin
, aEnd
, aPattern
, aStrokeOptions
, aOptions
));
285 void DrawTargetRecording::Fill(const Path
* aPath
, const Pattern
& aPattern
,
286 const DrawOptions
& aOptions
) {
293 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
294 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
295 auto circle
= path
->AsCircle();
297 EnsurePatternDependenciesStored(aPattern
);
298 RecordEventSelf(RecordedFillCircle(circle
.value(), aPattern
, aOptions
));
303 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
304 EnsurePatternDependenciesStored(aPattern
);
305 RecordEventSelf(RecordedFill(pathRecording
, aPattern
, aOptions
));
308 struct RecordingFontUserData
{
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
);
325 void DrawTargetRecording::DrawGlyphs(ScaledFont
* aFont
,
326 const GlyphBuffer
& aBuffer
,
327 const Pattern
& aPattern
,
328 const DrawOptions
& aOptions
,
329 const StrokeOptions
* aStrokeOptions
) {
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
348 RecordedFontDescriptor
fontDesc(unscaledFont
);
349 if (fontDesc
.IsValid()) {
350 RecordEventSkipFlushTransform(fontDesc
);
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
));
364 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
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
));
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
) {
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
) {
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
) {
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
));
445 auto line
= path
->AsLine();
447 EnsurePatternDependenciesStored(aPattern
);
448 RecordEventSelf(RecordedStrokeLine(line
->origin
, line
->destination
,
449 aPattern
, aStrokeOptions
, aOptions
));
454 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
455 EnsurePatternDependenciesStored(aPattern
);
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
) {
467 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
468 EnsurePatternDependenciesStored(aPattern
);
470 RecordEventSelf(RecordedDrawShadow(pathRecording
, aPattern
, aShadow
, aOptions
,
474 void DrawTargetRecording::MarkChanged() {
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
)) {
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
) {
530 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurface");
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
) {
543 mRecorder
->StoreImageRecording(aImageOfSurfaceDescriptor
,
544 "DrawSurfaceDescriptor");
546 RecordEventSelf(RecordedDrawSurfaceDescriptor(aDesc
, aDest
, aSource
,
547 aSurfOptions
, aOptions
));
550 void DrawTargetRecording::DrawDependentSurface(uint64_t aId
,
554 mRecorder
->AddDependentSurface(aId
);
555 RecordEventSelf(RecordedDrawDependentSurface(aId
, aDest
));
558 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface
* aSurface
,
560 const ShadowOptions
& aShadow
,
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
) {
582 MOZ_ASSERT(mRecorder
->HasStoredObject(aNode
));
584 RecordEventSelf(RecordedDrawFilter(aNode
, aSourceRect
, aDestPoint
, aOptions
));
587 already_AddRefed
<FilterNode
> DrawTargetRecording::CreateFilter(
589 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(mRecorder
);
591 RecordEventSelfSkipFlushTransform(RecordedFilterNodeCreation(retNode
, aType
));
593 return retNode
.forget();
596 void DrawTargetRecording::ClearRect(const Rect
& aRect
) {
599 RecordEventSelf(RecordedClearRect(aRect
));
602 void DrawTargetRecording::CopySurface(SourceSurface
* aSurface
,
603 const IntRect
& aSourceRect
,
604 const IntPoint
& aDestination
) {
611 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "CopySurface");
613 RecordEventSelf(RecordedCopySurface(aSurface
, aSourceRect
, aDestination
));
616 void DrawTargetRecording::PushClip(const Path
* aPath
) {
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();
627 PushClipRect(rect
.value());
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());
648 void DrawTargetRecording::PushLayer(bool aOpaque
, Float aOpacity
,
649 SourceSurface
* aMask
,
650 const Matrix
& aMaskTransform
,
651 const IntRect
& aBounds
,
652 bool aCopyBackground
) {
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
) {
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() {
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
,
698 SurfaceFormat aFormat
) const {
699 RefPtr
<SourceSurface
> surface
= CreateDataSourceSurfaceWithStrideFromData(
700 aSize
, aFormat
, aStride
, aData
, aStride
);
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())));
716 RefPtr
<SourceSurface
> strongRef(userData
->optimizedSurface
);
718 return do_AddRef(strongRef
);
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())));
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 {
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
))) {
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
)) {
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.
794 "Content-process DrawTargetRecording can't create requested similar "
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
);
811 RecordedCreateClippedDrawTarget(similarDT
.get(), aBounds
, aFormat
));
812 similarDT
->mTransform
= similarDT
->mRecordedTransform
= mTransform
;
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
),
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
833 "Content-process DrawTargetRecording can't create requested clipped "
836 return similarDT
.forget();
839 already_AddRefed
<PathBuilder
> DrawTargetRecording::CreatePathBuilder(
840 FillRule aFillRule
) const {
841 return MakeAndAddRef
<PathBuilderRecording
>(mFinalDT
->GetBackendType(),
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
) {
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
) {
871 DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA
);
872 RecordEventSelfSkipFlushTransform(
873 RecordedSetPermitSubpixelAA(aPermitSubpixelAA
));
876 already_AddRefed
<PathRecording
> DrawTargetRecording::EnsurePathStored(
878 RefPtr
<PathRecording
> pathRecording
;
879 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
881 const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
882 if (!mRecorder
->TryAddStoredObject(pathRecording
)) {
883 // Path is already stored.
884 return pathRecording
.forget();
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
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.
930 case PatternType::LINEAR_GRADIENT
: {
932 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
,
933 mRecorder
->HasStoredObject(
934 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
));
937 case PatternType::RADIAL_GRADIENT
: {
939 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
,
940 mRecorder
->HasStoredObject(
941 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
));
944 case PatternType::CONIC_GRADIENT
: {
946 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
,
947 mRecorder
->HasStoredObject(
948 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
));
951 case PatternType::SURFACE
: {
952 const SurfacePattern
* pat
= static_cast<const SurfacePattern
*>(&aPattern
);
953 EnsureSurfaceStoredRecording(mRecorder
, pat
->mSurface
,
954 "EnsurePatternDependenciesStored");
961 } // namespace mozilla