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/UniquePtr.h"
21 #include "nsXULAppAPI.h" // for XRE_IsContentProcess()
22 #include "RecordingTypes.h"
23 #include "RecordedEventImpl.h"
28 struct RecordingSourceSurfaceUserData
{
30 RefPtr
<DrawEventRecorderPrivate
> recorder
;
32 // The optimized surface holds a reference to our surface, for GetDataSurface
33 // calls, so we must hold a weak reference to avoid circular dependency.
34 ThreadSafeWeakPtr
<SourceSurface
> optimizedSurface
;
37 static void RecordingSourceSurfaceUserDataFunc(void* aUserData
) {
38 RecordingSourceSurfaceUserData
* userData
=
39 static_cast<RecordingSourceSurfaceUserData
*>(aUserData
);
41 if (NS_IsMainThread()) {
42 userData
->recorder
->RecordSourceSurfaceDestruction(userData
->refPtr
);
47 userData
->recorder
->AddPendingDeletion([userData
]() -> void {
48 userData
->recorder
->RecordSourceSurfaceDestruction(userData
->refPtr
);
53 static bool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate
* aRecorder
,
54 SourceSurface
* aSurface
,
56 // It's important that TryAddStoredObject is called first because that will
57 // run any pending processing required by recorded objects that have been
58 // deleted off the main thread.
59 if (!aRecorder
->TryAddStoredObject(aSurface
)) {
60 // Surface is already stored.
63 aRecorder
->StoreSourceSurfaceRecording(aSurface
, reason
);
64 aRecorder
->AddSourceSurface(aSurface
);
66 RecordingSourceSurfaceUserData
* userData
= new RecordingSourceSurfaceUserData
;
67 userData
->refPtr
= aSurface
;
68 userData
->recorder
= aRecorder
;
69 aSurface
->AddUserData(reinterpret_cast<UserDataKey
*>(aRecorder
), userData
,
70 &RecordingSourceSurfaceUserDataFunc
);
74 class SourceSurfaceRecording
: public SourceSurface
{
76 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording
, override
)
78 SourceSurfaceRecording(IntSize aSize
, SurfaceFormat aFormat
,
79 DrawEventRecorderPrivate
* aRecorder
,
80 SourceSurface
* aOriginalSurface
= nullptr)
84 mOriginalSurface(aOriginalSurface
) {
85 mRecorder
->AddStoredObject(this);
88 ~SourceSurfaceRecording() {
89 mRecorder
->RemoveStoredObject(this);
90 mRecorder
->RecordEvent(
91 RecordedSourceSurfaceDestruction(ReferencePtr(this)));
94 SurfaceType
GetType() const override
{ return SurfaceType::RECORDING
; }
95 IntSize
GetSize() const override
{ return mSize
; }
96 SurfaceFormat
GetFormat() const override
{ return mFormat
; }
97 already_AddRefed
<DataSourceSurface
> GetDataSurface() override
{
98 if (mOriginalSurface
) {
99 return mOriginalSurface
->GetDataSurface();
105 already_AddRefed
<SourceSurface
> ExtractSubrect(const IntRect
& aRect
) override
;
108 SurfaceFormat mFormat
;
109 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
110 // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call
111 // we need GetDataSurface to work, so we hold the original surface we
112 // optimized to return its GetDataSurface.
113 RefPtr
<SourceSurface
> mOriginalSurface
;
116 class GradientStopsRecording
: public GradientStops
{
118 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording
, override
)
120 explicit GradientStopsRecording(DrawEventRecorderPrivate
* aRecorder
)
121 : mRecorder(aRecorder
) {
122 mRecorder
->AddStoredObject(this);
125 virtual ~GradientStopsRecording() {
126 mRecorder
->RemoveStoredObject(this);
127 mRecorder
->RecordEvent(
128 RecordedGradientStopsDestruction(ReferencePtr(this)));
131 BackendType
GetBackendType() const override
{ return BackendType::RECORDING
; }
133 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
136 class FilterNodeRecording
: public FilterNode
{
138 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording
, override
)
139 using FilterNode::SetAttribute
;
141 explicit FilterNodeRecording(DrawEventRecorderPrivate
* aRecorder
)
142 : mRecorder(aRecorder
) {
143 mRecorder
->AddStoredObject(this);
146 virtual ~FilterNodeRecording() {
147 mRecorder
->RemoveStoredObject(this);
148 mRecorder
->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this)));
151 void SetInput(uint32_t aIndex
, SourceSurface
* aSurface
) override
{
152 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "SetInput");
154 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aSurface
));
156 void SetInput(uint32_t aIndex
, FilterNode
* aFilter
) override
{
157 MOZ_ASSERT(mRecorder
->HasStoredObject(aFilter
));
159 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aFilter
));
162 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
163 void SetAttribute(uint32_t aIndex, type aValue) override { \
164 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \
165 this, aIndex, aValue, \
166 RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
169 FORWARD_SET_ATTRIBUTE(bool, BOOL
);
170 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32
);
171 FORWARD_SET_ATTRIBUTE(Float
, FLOAT
);
172 FORWARD_SET_ATTRIBUTE(const Size
&, SIZE
);
173 FORWARD_SET_ATTRIBUTE(const IntSize
&, INTSIZE
);
174 FORWARD_SET_ATTRIBUTE(const IntPoint
&, INTPOINT
);
175 FORWARD_SET_ATTRIBUTE(const Rect
&, RECT
);
176 FORWARD_SET_ATTRIBUTE(const IntRect
&, INTRECT
);
177 FORWARD_SET_ATTRIBUTE(const Point
&, POINT
);
178 FORWARD_SET_ATTRIBUTE(const Matrix
&, MATRIX
);
179 FORWARD_SET_ATTRIBUTE(const Matrix5x4
&, MATRIX5X4
);
180 FORWARD_SET_ATTRIBUTE(const Point3D
&, POINT3D
);
181 FORWARD_SET_ATTRIBUTE(const DeviceColor
&, COLOR
);
183 #undef FORWARD_SET_ATTRIBUTE
185 void SetAttribute(uint32_t aIndex
, const Float
* aFloat
,
186 uint32_t aSize
) override
{
187 mRecorder
->RecordEvent(
188 RecordedFilterNodeSetAttribute(this, aIndex
, aFloat
, aSize
));
191 FilterBackend
GetBackendType() override
{ return FILTER_BACKEND_RECORDING
; }
193 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
196 DrawTargetRecording::DrawTargetRecording(
197 layers::CanvasDrawEventRecorder
* aRecorder
, int64_t aTextureId
,
198 const layers::RemoteTextureOwnerId
& aTextureOwnerId
, DrawTarget
* aDT
,
199 const IntSize
& aSize
)
200 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
202 mRect(IntPoint(0, 0), aSize
) {
203 RecordEventSkipFlushTransform(layers::RecordedCanvasDrawTargetCreation(
204 this, aTextureId
, aTextureOwnerId
, mFinalDT
->GetBackendType(), aSize
,
205 mFinalDT
->GetFormat()));
206 mFormat
= mFinalDT
->GetFormat();
207 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat
));
210 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder
* aRecorder
,
211 DrawTarget
* aDT
, IntRect aRect
,
213 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
216 MOZ_DIAGNOSTIC_ASSERT(aRecorder
->GetRecorderType() != RecorderType::CANVAS
);
217 RefPtr
<SourceSurface
> snapshot
= aHasData
? mFinalDT
->Snapshot() : nullptr;
218 RecordEventSkipFlushTransform(
219 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
220 mFinalDT
->GetFormat(), aHasData
, snapshot
));
221 mFormat
= mFinalDT
->GetFormat();
222 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat
));
225 DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording
* aDT
,
226 IntRect aRect
, SurfaceFormat aFormat
)
227 : mRecorder(aDT
->mRecorder
), mFinalDT(aDT
->mFinalDT
), mRect(aRect
) {
229 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat
));
232 DrawTargetRecording::~DrawTargetRecording() {
233 RecordEventSkipFlushTransform(
234 RecordedDrawTargetDestruction(ReferencePtr(this)));
235 mRecorder
->ClearDrawTarget(this);
238 void DrawTargetRecording::Link(const char* aDestination
, const Rect
& aRect
) {
241 RecordEventSelf(RecordedLink(aDestination
, aRect
));
244 void DrawTargetRecording::Destination(const char* aDestination
,
245 const Point
& aPoint
) {
248 RecordEventSelf(RecordedDestination(aDestination
, aPoint
));
251 void DrawTargetRecording::FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
252 const DrawOptions
& aOptions
) {
255 EnsurePatternDependenciesStored(aPattern
);
257 RecordEventSelf(RecordedFillRect(aRect
, aPattern
, aOptions
));
260 void DrawTargetRecording::StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
261 const StrokeOptions
& aStrokeOptions
,
262 const DrawOptions
& aOptions
) {
265 EnsurePatternDependenciesStored(aPattern
);
268 RecordedStrokeRect(aRect
, aPattern
, aStrokeOptions
, aOptions
));
271 void DrawTargetRecording::StrokeLine(const Point
& aBegin
, const Point
& aEnd
,
272 const Pattern
& aPattern
,
273 const StrokeOptions
& aStrokeOptions
,
274 const DrawOptions
& aOptions
) {
277 EnsurePatternDependenciesStored(aPattern
);
280 RecordedStrokeLine(aBegin
, aEnd
, aPattern
, aStrokeOptions
, aOptions
));
283 void DrawTargetRecording::Fill(const Path
* aPath
, const Pattern
& aPattern
,
284 const DrawOptions
& aOptions
) {
291 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
292 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
293 auto circle
= path
->AsCircle();
295 EnsurePatternDependenciesStored(aPattern
);
296 RecordEventSelf(RecordedFillCircle(circle
.value(), aPattern
, aOptions
));
301 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
302 EnsurePatternDependenciesStored(aPattern
);
303 RecordEventSelf(RecordedFill(pathRecording
, aPattern
, aOptions
));
306 struct RecordingFontUserData
{
309 RefPtr
<DrawEventRecorderPrivate
> recorder
;
312 static void RecordingFontUserDataDestroyFunc(void* aUserData
) {
313 RecordingFontUserData
* userData
=
314 static_cast<RecordingFontUserData
*>(aUserData
);
316 userData
->recorder
->RecordEvent(
317 RecordedScaledFontDestruction(ReferencePtr(userData
->refPtr
)));
318 userData
->recorder
->RemoveScaledFont((ScaledFont
*)userData
->refPtr
);
319 userData
->recorder
->DecrementUnscaledFontRefCount(userData
->unscaledFont
);
323 void DrawTargetRecording::DrawGlyphs(ScaledFont
* aFont
,
324 const GlyphBuffer
& aBuffer
,
325 const Pattern
& aPattern
,
326 const DrawOptions
& aOptions
,
327 const StrokeOptions
* aStrokeOptions
) {
334 EnsurePatternDependenciesStored(aPattern
);
336 UserDataKey
* userDataKey
= reinterpret_cast<UserDataKey
*>(mRecorder
.get());
337 if (mRecorder
->WantsExternalFonts()) {
338 mRecorder
->AddScaledFont(aFont
);
339 } else if (!aFont
->GetUserData(userDataKey
)) {
340 UnscaledFont
* unscaledFont
= aFont
->GetUnscaledFont();
341 if (mRecorder
->IncrementUnscaledFontRefCount(unscaledFont
) == 0) {
342 // Prefer sending the description, if we can create one. This ensures
343 // we don't record the data of system fonts which saves time and can
344 // prevent duplicate copies from accumulating in the OS cache during
346 RecordedFontDescriptor
fontDesc(unscaledFont
);
347 if (fontDesc
.IsValid()) {
348 RecordEventSkipFlushTransform(fontDesc
);
350 RecordedFontData
fontData(unscaledFont
);
351 RecordedFontDetails fontDetails
;
352 if (fontData
.GetFontDetails(fontDetails
)) {
353 // Try to serialise the whole font, just in case this is a web font
354 // that is not present on the system.
355 if (!mRecorder
->HasStoredFontData(fontDetails
.fontDataKey
)) {
356 RecordEventSkipFlushTransform(fontData
);
357 mRecorder
->AddStoredFontData(fontDetails
.fontDataKey
);
359 RecordEventSkipFlushTransform(
360 RecordedUnscaledFontCreation(unscaledFont
, fontDetails
));
362 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
367 RecordEventSkipFlushTransform(
368 RecordedScaledFontCreation(aFont
, unscaledFont
));
369 RecordingFontUserData
* userData
= new RecordingFontUserData
;
370 userData
->refPtr
= aFont
;
371 userData
->unscaledFont
= unscaledFont
;
372 userData
->recorder
= mRecorder
;
373 aFont
->AddUserData(userDataKey
, userData
,
374 &RecordingFontUserDataDestroyFunc
);
375 userData
->recorder
->AddScaledFont(aFont
);
378 if (aStrokeOptions
) {
379 RecordEventSelf(RecordedStrokeGlyphs(aFont
, aPattern
, *aStrokeOptions
,
380 aOptions
, aBuffer
.mGlyphs
,
381 aBuffer
.mNumGlyphs
));
383 RecordEventSelf(RecordedFillGlyphs(aFont
, aPattern
, aOptions
,
384 aBuffer
.mGlyphs
, aBuffer
.mNumGlyphs
));
388 void DrawTargetRecording::FillGlyphs(ScaledFont
* aFont
,
389 const GlyphBuffer
& aBuffer
,
390 const Pattern
& aPattern
,
391 const DrawOptions
& aOptions
) {
392 DrawGlyphs(aFont
, aBuffer
, aPattern
, aOptions
);
395 void DrawTargetRecording::StrokeGlyphs(ScaledFont
* aFont
,
396 const GlyphBuffer
& aBuffer
,
397 const Pattern
& aPattern
,
398 const StrokeOptions
& aStrokeOptions
,
399 const DrawOptions
& aOptions
) {
400 DrawGlyphs(aFont
, aBuffer
, aPattern
, aOptions
, &aStrokeOptions
);
403 void DrawTargetRecording::Mask(const Pattern
& aSource
, const Pattern
& aMask
,
404 const DrawOptions
& aOptions
) {
407 EnsurePatternDependenciesStored(aSource
);
408 EnsurePatternDependenciesStored(aMask
);
410 RecordEventSelf(RecordedMask(aSource
, aMask
, aOptions
));
413 void DrawTargetRecording::MaskSurface(const Pattern
& aSource
,
414 SourceSurface
* aMask
, Point aOffset
,
415 const DrawOptions
& aOptions
) {
422 EnsurePatternDependenciesStored(aSource
);
423 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "MaskSurface");
425 RecordEventSelf(RecordedMaskSurface(aSource
, aMask
, aOffset
, aOptions
));
428 void DrawTargetRecording::Stroke(const Path
* aPath
, const Pattern
& aPattern
,
429 const StrokeOptions
& aStrokeOptions
,
430 const DrawOptions
& aOptions
) {
433 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
434 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
435 auto circle
= path
->AsCircle();
436 if (circle
&& circle
->closed
) {
437 EnsurePatternDependenciesStored(aPattern
);
438 RecordEventSelf(RecordedStrokeCircle(circle
.value(), aPattern
,
439 aStrokeOptions
, aOptions
));
443 auto line
= path
->AsLine();
445 EnsurePatternDependenciesStored(aPattern
);
446 RecordEventSelf(RecordedStrokeLine(line
->origin
, line
->destination
,
447 aPattern
, aStrokeOptions
, aOptions
));
452 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
453 EnsurePatternDependenciesStored(aPattern
);
456 RecordedStroke(pathRecording
, aPattern
, aStrokeOptions
, aOptions
));
459 void DrawTargetRecording::DrawShadow(const Path
* aPath
, const Pattern
& aPattern
,
460 const ShadowOptions
& aShadow
,
461 const DrawOptions
& aOptions
,
462 const StrokeOptions
* aStrokeOptions
) {
465 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
466 EnsurePatternDependenciesStored(aPattern
);
468 RecordEventSelf(RecordedDrawShadow(pathRecording
, aPattern
, aShadow
, aOptions
,
472 void DrawTargetRecording::MarkChanged() { mIsDirty
= true; }
474 already_AddRefed
<SourceSurface
> DrawTargetRecording::Snapshot() {
475 RefPtr
<SourceSurface
> retSurf
=
476 new SourceSurfaceRecording(mRect
.Size(), mFormat
, mRecorder
);
478 RecordEventSelfSkipFlushTransform(RecordedSnapshot(ReferencePtr(retSurf
)));
480 return retSurf
.forget();
483 already_AddRefed
<SourceSurface
> DrawTargetRecording::IntoLuminanceSource(
484 LuminanceType aLuminanceType
, float aOpacity
) {
485 RefPtr
<SourceSurface
> retSurf
=
486 new SourceSurfaceRecording(mRect
.Size(), SurfaceFormat::A8
, mRecorder
);
488 RecordEventSelfSkipFlushTransform(
489 RecordedIntoLuminanceSource(retSurf
, aLuminanceType
, aOpacity
));
491 return retSurf
.forget();
494 already_AddRefed
<SourceSurface
> SourceSurfaceRecording::ExtractSubrect(
495 const IntRect
& aRect
) {
496 if (aRect
.IsEmpty() || !GetRect().Contains(aRect
)) {
500 RefPtr
<SourceSurface
> subSurf
=
501 new SourceSurfaceRecording(aRect
.Size(), mFormat
, mRecorder
);
502 mRecorder
->RecordEvent(RecordedExtractSubrect(subSurf
, this, aRect
));
503 return subSurf
.forget();
506 void DrawTargetRecording::Flush() {
507 RecordEventSelfSkipFlushTransform(RecordedFlush());
510 void DrawTargetRecording::DetachAllSnapshots() {
511 RecordEventSelfSkipFlushTransform(RecordedDetachAllSnapshots());
514 void DrawTargetRecording::DrawSurface(SourceSurface
* aSurface
,
515 const Rect
& aDest
, const Rect
& aSource
,
516 const DrawSurfaceOptions
& aSurfOptions
,
517 const DrawOptions
& aOptions
) {
524 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurface");
527 RecordedDrawSurface(aSurface
, aDest
, aSource
, aSurfOptions
, aOptions
));
530 void DrawTargetRecording::DrawSurfaceDescriptor(
531 const layers::SurfaceDescriptor
& aDesc
,
532 const RefPtr
<layers::Image
>& aImageOfSurfaceDescriptor
, const Rect
& aDest
,
533 const Rect
& aSource
, const DrawSurfaceOptions
& aSurfOptions
,
534 const DrawOptions
& aOptions
) {
537 mRecorder
->StoreImageRecording(aImageOfSurfaceDescriptor
,
538 "DrawSurfaceDescriptor");
540 RecordEventSelf(RecordedDrawSurfaceDescriptor(aDesc
, aDest
, aSource
,
541 aSurfOptions
, aOptions
));
544 void DrawTargetRecording::DrawDependentSurface(uint64_t aId
,
548 mRecorder
->AddDependentSurface(aId
);
549 RecordEventSelf(RecordedDrawDependentSurface(aId
, aDest
));
552 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface
* aSurface
,
554 const ShadowOptions
& aShadow
,
562 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurfaceWithShadow");
564 RecordEventSelf(RecordedDrawSurfaceWithShadow(aSurface
, aDest
, aShadow
, aOp
));
567 void DrawTargetRecording::DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
568 const Point
& aDestPoint
,
569 const DrawOptions
& aOptions
) {
576 MOZ_ASSERT(mRecorder
->HasStoredObject(aNode
));
578 RecordEventSelf(RecordedDrawFilter(aNode
, aSourceRect
, aDestPoint
, aOptions
));
581 already_AddRefed
<FilterNode
> DrawTargetRecording::CreateFilter(
583 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(mRecorder
);
585 RecordEventSelfSkipFlushTransform(RecordedFilterNodeCreation(retNode
, aType
));
587 return retNode
.forget();
590 void DrawTargetRecording::ClearRect(const Rect
& aRect
) {
593 RecordEventSelf(RecordedClearRect(aRect
));
596 void DrawTargetRecording::CopySurface(SourceSurface
* aSurface
,
597 const IntRect
& aSourceRect
,
598 const IntPoint
& aDestination
) {
605 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "CopySurface");
607 RecordEventSelf(RecordedCopySurface(aSurface
, aSourceRect
, aDestination
));
610 void DrawTargetRecording::PushClip(const Path
* aPath
) {
615 // The canvas doesn't have a clipRect API so we always end up in the generic
616 // path. The D2D backend doesn't have a good way of specializing rectangular
617 // clips so we take advantage of the fact that aPath is usually backed by a
618 // SkiaPath which implements AsRect() and specialize it here.
619 auto rect
= aPath
->AsRect();
621 PushClipRect(rect
.value());
625 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
626 RecordEventSelf(RecordedPushClip(ReferencePtr(pathRecording
)));
629 void DrawTargetRecording::PushClipRect(const Rect
& aRect
) {
630 RecordEventSelf(RecordedPushClipRect(aRect
));
633 void DrawTargetRecording::PopClip() {
634 RecordEventSelfSkipFlushTransform(RecordedPopClip());
637 void DrawTargetRecording::PushLayer(bool aOpaque
, Float aOpacity
,
638 SourceSurface
* aMask
,
639 const Matrix
& aMaskTransform
,
640 const IntRect
& aBounds
,
641 bool aCopyBackground
) {
643 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
646 RecordEventSelf(RecordedPushLayer(aOpaque
, aOpacity
, aMask
, aMaskTransform
,
647 aBounds
, aCopyBackground
));
649 PushedLayer
layer(GetPermitSubpixelAA());
650 mPushedLayers
.push_back(layer
);
651 DrawTarget::SetPermitSubpixelAA(aOpaque
);
654 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque
, Float aOpacity
,
655 SourceSurface
* aMask
,
656 const Matrix
& aMaskTransform
,
657 const IntRect
& aBounds
,
658 bool aCopyBackground
,
659 CompositionOp aCompositionOp
) {
661 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
664 RecordEventSelf(RecordedPushLayerWithBlend(aOpaque
, aOpacity
, aMask
,
665 aMaskTransform
, aBounds
,
666 aCopyBackground
, aCompositionOp
));
668 PushedLayer
layer(GetPermitSubpixelAA());
669 mPushedLayers
.push_back(layer
);
670 DrawTarget::SetPermitSubpixelAA(aOpaque
);
673 void DrawTargetRecording::PopLayer() {
676 RecordEventSelfSkipFlushTransform(RecordedPopLayer());
678 const PushedLayer
& layer
= mPushedLayers
.back();
679 DrawTarget::SetPermitSubpixelAA(layer
.mOldPermitSubpixelAA
);
680 mPushedLayers
.pop_back();
683 already_AddRefed
<SourceSurface
>
684 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData
,
685 const IntSize
& aSize
,
687 SurfaceFormat aFormat
) const {
688 RefPtr
<SourceSurface
> surface
= CreateDataSourceSurfaceWithStrideFromData(
689 aSize
, aFormat
, aStride
, aData
, aStride
);
694 return OptimizeSourceSurface(surface
);
697 already_AddRefed
<SourceSurface
> DrawTargetRecording::OptimizeSourceSurface(
698 SourceSurface
* aSurface
) const {
699 // See if we have a previously optimized surface available. We have to do this
700 // check before the SurfaceType::RECORDING below, because aSurface might be a
701 // SurfaceType::RECORDING from another recorder we have previously optimized.
702 auto* userData
= static_cast<RecordingSourceSurfaceUserData
*>(
703 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
705 RefPtr
<SourceSurface
> strongRef(userData
->optimizedSurface
);
707 return do_AddRef(strongRef
);
710 if (!EnsureSurfaceStoredRecording(mRecorder
, aSurface
,
711 "OptimizeSourceSurface")) {
712 // Surface was already stored, but doesn't have UserData so must be one
713 // of our recording surfaces.
714 MOZ_ASSERT(aSurface
->GetType() == SurfaceType::RECORDING
);
715 return do_AddRef(aSurface
);
718 userData
= static_cast<RecordingSourceSurfaceUserData
*>(
719 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
721 "User data should always have been set by "
722 "EnsureSurfaceStoredRecording.");
725 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(
726 aSurface
->GetSize(), aSurface
->GetFormat(), mRecorder
, aSurface
);
727 RecordEventSelfSkipFlushTransform(
728 RecordedOptimizeSourceSurface(aSurface
, retSurf
));
729 userData
->optimizedSurface
= retSurf
;
731 return retSurf
.forget();
734 already_AddRefed
<SourceSurface
>
735 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
736 const NativeSurface
& aSurface
) const {
741 already_AddRefed
<DrawTarget
>
742 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
743 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
744 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
745 // If the requested similar draw target is too big, then we should try to
746 // rasterize on the content side to avoid duplicating the effort when a
747 // blob image gets tiled. If we fail somehow to produce it, we can fall
748 // back to recording.
749 constexpr int32_t kRasterThreshold
= 256 * 256 * 4;
750 int32_t stride
= aSize
.width
* BytesPerPixel(aFormat
);
751 int32_t surfaceBytes
= aSize
.height
* stride
;
752 if (surfaceBytes
>= kRasterThreshold
) {
753 auto surface
= MakeRefPtr
<SourceSurfaceSharedData
>();
754 if (surface
->Init(aSize
, stride
, aFormat
)) {
755 auto dt
= MakeRefPtr
<DrawTargetSkia
>();
756 if (dt
->Init(std::move(surface
))) {
759 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
765 return CreateSimilarDrawTarget(aSize
, aFormat
);
768 already_AddRefed
<DrawTarget
> DrawTargetRecording::CreateSimilarDrawTarget(
769 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
770 RefPtr
<DrawTargetRecording
> similarDT
;
771 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
773 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize
), aFormat
);
774 similarDT
->SetOptimizeTransform(mOptimizeTransform
);
775 RecordEventSelfSkipFlushTransform(
776 RecordedCreateSimilarDrawTarget(similarDT
.get(), aSize
, aFormat
));
777 } else if (XRE_IsContentProcess()) {
778 // Crash any content process that calls this function with arguments that
779 // would fail to create a similar draw target. We do this to root out bad
780 // callers. We don't want to crash any important processes though so for
781 // for those we'll just gracefully return nullptr.
783 "Content-process DrawTargetRecording can't create requested similar "
786 return similarDT
.forget();
789 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
790 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
791 return mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
);
794 RefPtr
<DrawTarget
> DrawTargetRecording::CreateClippedDrawTarget(
795 const Rect
& aBounds
, SurfaceFormat aFormat
) {
796 RefPtr
<DrawTargetRecording
> similarDT
=
797 new DrawTargetRecording(this, mRect
, aFormat
);
798 similarDT
->SetOptimizeTransform(mOptimizeTransform
);
800 RecordedCreateClippedDrawTarget(similarDT
.get(), aBounds
, aFormat
));
801 similarDT
->mTransform
= similarDT
->mRecordedTransform
= mTransform
;
805 already_AddRefed
<DrawTarget
>
806 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
807 const IntSize
& aMaxSize
, SurfaceFormat aFormat
, FilterNode
* aFilter
,
808 FilterNode
* aSource
, const Rect
& aSourceRect
, const Point
& aDestPoint
) {
809 RefPtr
<DrawTargetRecording
> similarDT
;
810 if (mFinalDT
->CanCreateSimilarDrawTarget(aMaxSize
, aFormat
)) {
811 similarDT
= new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize
),
813 similarDT
->SetOptimizeTransform(mOptimizeTransform
);
814 // RecordedCreateDrawTargetForFilter::PlayEvent uses the transform, despite
815 // the fact that the underlying DrawTarget does not.
816 RecordEventSelf(RecordedCreateDrawTargetForFilter(similarDT
.get(), aMaxSize
,
817 aFormat
, aFilter
, aSource
,
818 aSourceRect
, aDestPoint
));
819 } else if (XRE_IsContentProcess()) {
820 // See CreateSimilarDrawTarget
822 "Content-process DrawTargetRecording can't create requested clipped "
825 return similarDT
.forget();
828 already_AddRefed
<PathBuilder
> DrawTargetRecording::CreatePathBuilder(
829 FillRule aFillRule
) const {
830 return MakeAndAddRef
<PathBuilderRecording
>(mFinalDT
->GetBackendType(),
834 already_AddRefed
<GradientStops
> DrawTargetRecording::CreateGradientStops(
835 GradientStop
* aStops
, uint32_t aNumStops
, ExtendMode aExtendMode
) const {
836 RefPtr
<GradientStops
> retStops
= new GradientStopsRecording(mRecorder
);
838 RecordEventSelfSkipFlushTransform(
839 RecordedGradientStopsCreation(retStops
, aStops
, aNumStops
, aExtendMode
));
841 return retStops
.forget();
844 void DrawTargetRecording::SetTransform(const Matrix
& aTransform
) {
845 DrawTarget::SetTransform(aTransform
);
846 if (!mOptimizeTransform
) {
851 void DrawTargetRecording::RecordTransform(const Matrix
& aTransform
) const {
852 RecordEventSelfSkipFlushTransform(RecordedSetTransform(aTransform
));
853 mRecordedTransform
= aTransform
;
856 void DrawTargetRecording::SetPermitSubpixelAA(bool aPermitSubpixelAA
) {
857 if (aPermitSubpixelAA
== mPermitSubpixelAA
) {
860 DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA
);
861 RecordEventSelfSkipFlushTransform(
862 RecordedSetPermitSubpixelAA(aPermitSubpixelAA
));
865 already_AddRefed
<PathRecording
> DrawTargetRecording::EnsurePathStored(
867 RefPtr
<PathRecording
> pathRecording
;
868 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
870 const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
871 if (!mRecorder
->TryAddStoredObject(pathRecording
)) {
872 // Path is already stored.
873 return pathRecording
.forget();
876 MOZ_ASSERT(!mRecorder
->HasStoredObject(aPath
));
877 FillRule fillRule
= aPath
->GetFillRule();
878 RefPtr
<PathBuilderRecording
> builderRecording
=
879 new PathBuilderRecording(mFinalDT
->GetBackendType(), fillRule
);
880 aPath
->StreamToSink(builderRecording
);
881 pathRecording
= builderRecording
->Finish().downcast
<PathRecording
>();
882 mRecorder
->AddStoredObject(pathRecording
);
885 // It's important that AddStoredObject or TryAddStoredObject is called before
886 // this because that will run any pending processing required by recorded
887 // objects that have been deleted off the main thread.
888 RecordEventSelfSkipFlushTransform(RecordedPathCreation(pathRecording
.get()));
889 pathRecording
->mStoredRecorders
.push_back(mRecorder
);
891 return pathRecording
.forget();
894 // This should only be called on the 'root' DrawTargetRecording.
895 // Calling it on a child DrawTargetRecordings will cause confusion.
896 void DrawTargetRecording::FlushItem(const IntRect
& aBounds
) {
897 mRecorder
->FlushItem(aBounds
);
898 // Reinitialize the recorder (FlushItem will write a new recording header)
899 // Tell the new recording about our draw target
900 // This code should match what happens in the DrawTargetRecording constructor.
901 MOZ_DIAGNOSTIC_ASSERT(mRecorder
->GetRecorderType() ==
902 RecorderType::WEBRENDER
);
903 RecordEventSkipFlushTransform(
904 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
905 mFinalDT
->GetFormat(), false, nullptr));
906 // RecordedDrawTargetCreation can actually reuse the base DrawTarget for the
907 // recording, but we cannot conclude that from here, so force the transform
909 RecordTransform(mTransform
);
910 mTransformDirty
= false;
913 void DrawTargetRecording::EnsurePatternDependenciesStored(
914 const Pattern
& aPattern
) {
915 switch (aPattern
.GetType()) {
916 case PatternType::COLOR
:
917 // No dependencies here.
919 case PatternType::LINEAR_GRADIENT
: {
921 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
,
922 mRecorder
->HasStoredObject(
923 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
));
926 case PatternType::RADIAL_GRADIENT
: {
928 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
,
929 mRecorder
->HasStoredObject(
930 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
));
933 case PatternType::CONIC_GRADIENT
: {
935 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
,
936 mRecorder
->HasStoredObject(
937 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
));
940 case PatternType::SURFACE
: {
941 const SurfacePattern
* pat
= static_cast<const SurfacePattern
*>(&aPattern
);
942 EnsureSurfaceStoredRecording(mRecorder
, pat
->mSurface
,
943 "EnsurePatternDependenciesStored");
950 } // namespace mozilla