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"
15 #include "mozilla/gfx/DataSurfaceHelpers.h"
16 #include "mozilla/layers/CanvasDrawEventRecorder.h"
17 #include "mozilla/layers/RecordedCanvasEventImpl.h"
18 #include "mozilla/layers/SourceSurfaceSharedData.h"
19 #include "mozilla/UniquePtr.h"
20 #include "nsXULAppAPI.h" // for XRE_IsContentProcess()
21 #include "RecordingTypes.h"
22 #include "RecordedEventImpl.h"
27 struct RecordingSourceSurfaceUserData
{
29 RefPtr
<DrawEventRecorderPrivate
> recorder
;
31 // The optimized surface holds a reference to our surface, for GetDataSurface
32 // calls, so we must hold a weak reference to avoid circular dependency.
33 ThreadSafeWeakPtr
<SourceSurface
> optimizedSurface
;
36 static void RecordingSourceSurfaceUserDataFunc(void* aUserData
) {
37 RecordingSourceSurfaceUserData
* userData
=
38 static_cast<RecordingSourceSurfaceUserData
*>(aUserData
);
40 if (NS_IsMainThread()) {
41 userData
->recorder
->RecordSourceSurfaceDestruction(userData
->refPtr
);
46 userData
->recorder
->AddPendingDeletion([userData
]() -> void {
47 userData
->recorder
->RecordSourceSurfaceDestruction(userData
->refPtr
);
52 static bool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate
* aRecorder
,
53 SourceSurface
* aSurface
,
55 // It's important that TryAddStoredObject is called first because that will
56 // run any pending processing required by recorded objects that have been
57 // deleted off the main thread.
58 if (!aRecorder
->TryAddStoredObject(aSurface
)) {
59 // Surface is already stored.
62 aRecorder
->StoreSourceSurfaceRecording(aSurface
, reason
);
63 aRecorder
->AddSourceSurface(aSurface
);
65 RecordingSourceSurfaceUserData
* userData
= new RecordingSourceSurfaceUserData
;
66 userData
->refPtr
= aSurface
;
67 userData
->recorder
= aRecorder
;
68 aSurface
->AddUserData(reinterpret_cast<UserDataKey
*>(aRecorder
), userData
,
69 &RecordingSourceSurfaceUserDataFunc
);
73 class SourceSurfaceRecording
: public SourceSurface
{
75 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording
, override
)
77 SourceSurfaceRecording(IntSize aSize
, SurfaceFormat aFormat
,
78 DrawEventRecorderPrivate
* aRecorder
,
79 SourceSurface
* aOriginalSurface
= nullptr)
83 mOriginalSurface(aOriginalSurface
) {
84 mRecorder
->AddStoredObject(this);
87 ~SourceSurfaceRecording() {
88 mRecorder
->RemoveStoredObject(this);
89 mRecorder
->RecordEvent(
90 RecordedSourceSurfaceDestruction(ReferencePtr(this)));
93 SurfaceType
GetType() const override
{ return SurfaceType::RECORDING
; }
94 IntSize
GetSize() const override
{ return mSize
; }
95 SurfaceFormat
GetFormat() const override
{ return mFormat
; }
96 already_AddRefed
<DataSourceSurface
> GetDataSurface() override
{
97 if (mOriginalSurface
) {
98 return mOriginalSurface
->GetDataSurface();
104 already_AddRefed
<SourceSurface
> ExtractSubrect(const IntRect
& aRect
) override
;
107 SurfaceFormat mFormat
;
108 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
109 // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call
110 // we need GetDataSurface to work, so we hold the original surface we
111 // optimized to return its GetDataSurface.
112 RefPtr
<SourceSurface
> mOriginalSurface
;
115 class GradientStopsRecording
: public GradientStops
{
117 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording
, override
)
119 explicit GradientStopsRecording(DrawEventRecorderPrivate
* aRecorder
)
120 : mRecorder(aRecorder
) {
121 mRecorder
->AddStoredObject(this);
124 virtual ~GradientStopsRecording() {
125 mRecorder
->RemoveStoredObject(this);
126 mRecorder
->RecordEvent(
127 RecordedGradientStopsDestruction(ReferencePtr(this)));
130 BackendType
GetBackendType() const override
{ return BackendType::RECORDING
; }
132 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
135 class FilterNodeRecording
: public FilterNode
{
137 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording
, override
)
138 using FilterNode::SetAttribute
;
140 explicit FilterNodeRecording(DrawEventRecorderPrivate
* aRecorder
)
141 : mRecorder(aRecorder
) {
142 mRecorder
->AddStoredObject(this);
145 virtual ~FilterNodeRecording() {
146 mRecorder
->RemoveStoredObject(this);
147 mRecorder
->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this)));
150 void SetInput(uint32_t aIndex
, SourceSurface
* aSurface
) override
{
151 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "SetInput");
153 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aSurface
));
155 void SetInput(uint32_t aIndex
, FilterNode
* aFilter
) override
{
156 MOZ_ASSERT(mRecorder
->HasStoredObject(aFilter
));
158 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aFilter
));
161 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
162 void SetAttribute(uint32_t aIndex, type aValue) override { \
163 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \
164 this, aIndex, aValue, \
165 RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
168 FORWARD_SET_ATTRIBUTE(bool, BOOL
);
169 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32
);
170 FORWARD_SET_ATTRIBUTE(Float
, FLOAT
);
171 FORWARD_SET_ATTRIBUTE(const Size
&, SIZE
);
172 FORWARD_SET_ATTRIBUTE(const IntSize
&, INTSIZE
);
173 FORWARD_SET_ATTRIBUTE(const IntPoint
&, INTPOINT
);
174 FORWARD_SET_ATTRIBUTE(const Rect
&, RECT
);
175 FORWARD_SET_ATTRIBUTE(const IntRect
&, INTRECT
);
176 FORWARD_SET_ATTRIBUTE(const Point
&, POINT
);
177 FORWARD_SET_ATTRIBUTE(const Matrix
&, MATRIX
);
178 FORWARD_SET_ATTRIBUTE(const Matrix5x4
&, MATRIX5X4
);
179 FORWARD_SET_ATTRIBUTE(const Point3D
&, POINT3D
);
180 FORWARD_SET_ATTRIBUTE(const DeviceColor
&, COLOR
);
182 #undef FORWARD_SET_ATTRIBUTE
184 void SetAttribute(uint32_t aIndex
, const Float
* aFloat
,
185 uint32_t aSize
) override
{
186 mRecorder
->RecordEvent(
187 RecordedFilterNodeSetAttribute(this, aIndex
, aFloat
, aSize
));
190 FilterBackend
GetBackendType() override
{ return FILTER_BACKEND_RECORDING
; }
192 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
195 DrawTargetRecording::DrawTargetRecording(
196 layers::CanvasDrawEventRecorder
* aRecorder
, int64_t aTextureId
,
197 const layers::RemoteTextureOwnerId
& aTextureOwnerId
, DrawTarget
* aDT
,
198 const IntSize
& aSize
)
199 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
201 mRect(IntPoint(0, 0), aSize
) {
202 mRecorder
->RecordEvent(layers::RecordedCanvasDrawTargetCreation(
203 this, aTextureId
, aTextureOwnerId
, mFinalDT
->GetBackendType(), aSize
,
204 mFinalDT
->GetFormat()));
205 mFormat
= mFinalDT
->GetFormat();
206 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat
));
209 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder
* aRecorder
,
210 DrawTarget
* aDT
, IntRect aRect
,
212 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
215 MOZ_DIAGNOSTIC_ASSERT(aRecorder
->GetRecorderType() != RecorderType::CANVAS
);
216 RefPtr
<SourceSurface
> snapshot
= aHasData
? mFinalDT
->Snapshot() : nullptr;
217 mRecorder
->RecordEvent(
218 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
219 mFinalDT
->GetFormat(), aHasData
, snapshot
));
220 mFormat
= mFinalDT
->GetFormat();
221 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat
));
224 DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording
* aDT
,
225 IntRect aRect
, SurfaceFormat aFormat
)
226 : mRecorder(aDT
->mRecorder
), mFinalDT(aDT
->mFinalDT
), mRect(aRect
) {
228 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat
));
231 DrawTargetRecording::~DrawTargetRecording() {
232 mRecorder
->RecordEvent(RecordedDrawTargetDestruction(ReferencePtr(this)));
233 mRecorder
->ClearDrawTarget(this);
236 void DrawTargetRecording::Link(const char* aDestination
, const Rect
& aRect
) {
239 mRecorder
->RecordEvent(this, RecordedLink(aDestination
, aRect
));
242 void DrawTargetRecording::Destination(const char* aDestination
,
243 const Point
& aPoint
) {
246 mRecorder
->RecordEvent(this, RecordedDestination(aDestination
, aPoint
));
249 void DrawTargetRecording::FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
250 const DrawOptions
& aOptions
) {
253 EnsurePatternDependenciesStored(aPattern
);
255 mRecorder
->RecordEvent(this, RecordedFillRect(aRect
, aPattern
, aOptions
));
258 void DrawTargetRecording::StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
259 const StrokeOptions
& aStrokeOptions
,
260 const DrawOptions
& aOptions
) {
263 EnsurePatternDependenciesStored(aPattern
);
265 mRecorder
->RecordEvent(
266 this, RecordedStrokeRect(aRect
, aPattern
, aStrokeOptions
, aOptions
));
269 void DrawTargetRecording::StrokeLine(const Point
& aBegin
, const Point
& aEnd
,
270 const Pattern
& aPattern
,
271 const StrokeOptions
& aStrokeOptions
,
272 const DrawOptions
& aOptions
) {
275 EnsurePatternDependenciesStored(aPattern
);
277 mRecorder
->RecordEvent(this, RecordedStrokeLine(aBegin
, aEnd
, aPattern
,
278 aStrokeOptions
, aOptions
));
281 void DrawTargetRecording::Fill(const Path
* aPath
, const Pattern
& aPattern
,
282 const DrawOptions
& aOptions
) {
289 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
290 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
291 auto circle
= path
->AsCircle();
293 EnsurePatternDependenciesStored(aPattern
);
294 mRecorder
->RecordEvent(
295 this, RecordedFillCircle(circle
.value(), aPattern
, aOptions
));
300 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
301 EnsurePatternDependenciesStored(aPattern
);
303 mRecorder
->RecordEvent(this, 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 mRecorder
->RecordEvent(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 mRecorder
->RecordEvent(fontData
);
357 mRecorder
->AddStoredFontData(fontDetails
.fontDataKey
);
359 mRecorder
->RecordEvent(
360 RecordedUnscaledFontCreation(unscaledFont
, fontDetails
));
362 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
367 mRecorder
->RecordEvent(RecordedScaledFontCreation(aFont
, unscaledFont
));
368 RecordingFontUserData
* userData
= new RecordingFontUserData
;
369 userData
->refPtr
= aFont
;
370 userData
->unscaledFont
= unscaledFont
;
371 userData
->recorder
= mRecorder
;
372 aFont
->AddUserData(userDataKey
, userData
,
373 &RecordingFontUserDataDestroyFunc
);
374 userData
->recorder
->AddScaledFont(aFont
);
377 if (aStrokeOptions
) {
378 mRecorder
->RecordEvent(
379 this, RecordedStrokeGlyphs(aFont
, aPattern
, *aStrokeOptions
, aOptions
,
380 aBuffer
.mGlyphs
, aBuffer
.mNumGlyphs
));
382 mRecorder
->RecordEvent(
383 this, RecordedFillGlyphs(aFont
, aPattern
, aOptions
, aBuffer
.mGlyphs
,
384 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 mRecorder
->RecordEvent(this, 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 mRecorder
->RecordEvent(
426 this, RecordedMaskSurface(aSource
, aMask
, aOffset
, aOptions
));
429 void DrawTargetRecording::Stroke(const Path
* aPath
, const Pattern
& aPattern
,
430 const StrokeOptions
& aStrokeOptions
,
431 const DrawOptions
& aOptions
) {
434 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
435 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
436 auto circle
= path
->AsCircle();
437 if (circle
&& circle
->closed
) {
438 EnsurePatternDependenciesStored(aPattern
);
439 mRecorder
->RecordEvent(
440 this, RecordedStrokeCircle(circle
.value(), aPattern
, aStrokeOptions
,
445 auto line
= path
->AsLine();
447 EnsurePatternDependenciesStored(aPattern
);
448 mRecorder
->RecordEvent(
449 this, RecordedStrokeLine(line
->origin
, line
->destination
, aPattern
,
450 aStrokeOptions
, aOptions
));
455 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
456 EnsurePatternDependenciesStored(aPattern
);
458 mRecorder
->RecordEvent(
459 this, RecordedStroke(pathRecording
, aPattern
, aStrokeOptions
, aOptions
));
462 void DrawTargetRecording::DrawShadow(const Path
* aPath
, const Pattern
& aPattern
,
463 const ShadowOptions
& aShadow
,
464 const DrawOptions
& aOptions
,
465 const StrokeOptions
* aStrokeOptions
) {
468 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
469 EnsurePatternDependenciesStored(aPattern
);
471 mRecorder
->RecordEvent(
472 this, RecordedDrawShadow(pathRecording
, aPattern
, aShadow
, aOptions
,
476 void DrawTargetRecording::MarkChanged() { mIsDirty
= true; }
478 already_AddRefed
<SourceSurface
> DrawTargetRecording::Snapshot() {
479 RefPtr
<SourceSurface
> retSurf
=
480 new SourceSurfaceRecording(mRect
.Size(), mFormat
, mRecorder
);
482 mRecorder
->RecordEvent(this, RecordedSnapshot(ReferencePtr(retSurf
)));
484 return retSurf
.forget();
487 already_AddRefed
<SourceSurface
> DrawTargetRecording::IntoLuminanceSource(
488 LuminanceType aLuminanceType
, float aOpacity
) {
489 RefPtr
<SourceSurface
> retSurf
=
490 new SourceSurfaceRecording(mRect
.Size(), SurfaceFormat::A8
, mRecorder
);
492 mRecorder
->RecordEvent(
493 this, RecordedIntoLuminanceSource(retSurf
, aLuminanceType
, aOpacity
));
495 return retSurf
.forget();
498 already_AddRefed
<SourceSurface
> SourceSurfaceRecording::ExtractSubrect(
499 const IntRect
& aRect
) {
500 if (aRect
.IsEmpty() || !GetRect().Contains(aRect
)) {
504 RefPtr
<SourceSurface
> subSurf
=
505 new SourceSurfaceRecording(aRect
.Size(), mFormat
, mRecorder
);
506 mRecorder
->RecordEvent(RecordedExtractSubrect(subSurf
, this, aRect
));
507 return subSurf
.forget();
510 void DrawTargetRecording::Flush() {
511 mRecorder
->RecordEvent(this, RecordedFlush());
514 void DrawTargetRecording::DetachAllSnapshots() {
515 mRecorder
->RecordEvent(this, RecordedDetachAllSnapshots());
518 void DrawTargetRecording::DrawSurface(SourceSurface
* aSurface
,
519 const Rect
& aDest
, const Rect
& aSource
,
520 const DrawSurfaceOptions
& aSurfOptions
,
521 const DrawOptions
& aOptions
) {
528 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurface");
530 mRecorder
->RecordEvent(this, RecordedDrawSurface(aSurface
, aDest
, aSource
,
531 aSurfOptions
, aOptions
));
534 void DrawTargetRecording::DrawDependentSurface(uint64_t aId
,
538 mRecorder
->AddDependentSurface(aId
);
539 mRecorder
->RecordEvent(this, RecordedDrawDependentSurface(aId
, aDest
));
542 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface
* aSurface
,
544 const ShadowOptions
& aShadow
,
552 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurfaceWithShadow");
554 mRecorder
->RecordEvent(
555 this, RecordedDrawSurfaceWithShadow(aSurface
, aDest
, aShadow
, aOp
));
558 void DrawTargetRecording::DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
559 const Point
& aDestPoint
,
560 const DrawOptions
& aOptions
) {
567 MOZ_ASSERT(mRecorder
->HasStoredObject(aNode
));
569 mRecorder
->RecordEvent(
570 this, RecordedDrawFilter(aNode
, aSourceRect
, aDestPoint
, aOptions
));
573 already_AddRefed
<FilterNode
> DrawTargetRecording::CreateFilter(
575 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(mRecorder
);
577 mRecorder
->RecordEvent(this, RecordedFilterNodeCreation(retNode
, aType
));
579 return retNode
.forget();
582 void DrawTargetRecording::ClearRect(const Rect
& aRect
) {
585 mRecorder
->RecordEvent(this, RecordedClearRect(aRect
));
588 void DrawTargetRecording::CopySurface(SourceSurface
* aSurface
,
589 const IntRect
& aSourceRect
,
590 const IntPoint
& aDestination
) {
597 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "CopySurface");
599 mRecorder
->RecordEvent(
600 this, RecordedCopySurface(aSurface
, aSourceRect
, aDestination
));
603 void DrawTargetRecording::PushClip(const Path
* aPath
) {
608 // The canvas doesn't have a clipRect API so we always end up in the generic
609 // path. The D2D backend doesn't have a good way of specializing rectangular
610 // clips so we take advantage of the fact that aPath is usually backed by a
611 // SkiaPath which implements AsRect() and specialize it here.
612 auto rect
= aPath
->AsRect();
614 PushClipRect(rect
.value());
618 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
620 mRecorder
->RecordEvent(this, RecordedPushClip(ReferencePtr(pathRecording
)));
623 void DrawTargetRecording::PushClipRect(const Rect
& aRect
) {
624 mRecorder
->RecordEvent(this, RecordedPushClipRect(aRect
));
627 void DrawTargetRecording::PopClip() {
628 mRecorder
->RecordEvent(this, RecordedPopClip());
631 void DrawTargetRecording::PushLayer(bool aOpaque
, Float aOpacity
,
632 SourceSurface
* aMask
,
633 const Matrix
& aMaskTransform
,
634 const IntRect
& aBounds
,
635 bool aCopyBackground
) {
637 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
640 mRecorder
->RecordEvent(
641 this, RecordedPushLayer(aOpaque
, aOpacity
, aMask
, aMaskTransform
, aBounds
,
644 PushedLayer
layer(GetPermitSubpixelAA());
645 mPushedLayers
.push_back(layer
);
646 DrawTarget::SetPermitSubpixelAA(aOpaque
);
649 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque
, Float aOpacity
,
650 SourceSurface
* aMask
,
651 const Matrix
& aMaskTransform
,
652 const IntRect
& aBounds
,
653 bool aCopyBackground
,
654 CompositionOp aCompositionOp
) {
656 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
659 mRecorder
->RecordEvent(this, RecordedPushLayerWithBlend(
660 aOpaque
, aOpacity
, aMask
, aMaskTransform
,
661 aBounds
, aCopyBackground
, aCompositionOp
));
663 PushedLayer
layer(GetPermitSubpixelAA());
664 mPushedLayers
.push_back(layer
);
665 DrawTarget::SetPermitSubpixelAA(aOpaque
);
668 void DrawTargetRecording::PopLayer() {
671 mRecorder
->RecordEvent(this, RecordedPopLayer());
673 const PushedLayer
& layer
= mPushedLayers
.back();
674 DrawTarget::SetPermitSubpixelAA(layer
.mOldPermitSubpixelAA
);
675 mPushedLayers
.pop_back();
678 already_AddRefed
<SourceSurface
>
679 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData
,
680 const IntSize
& aSize
,
682 SurfaceFormat aFormat
) const {
683 RefPtr
<SourceSurface
> surface
= CreateDataSourceSurfaceWithStrideFromData(
684 aSize
, aFormat
, aStride
, aData
, aStride
);
689 return OptimizeSourceSurface(surface
);
692 already_AddRefed
<SourceSurface
> DrawTargetRecording::OptimizeSourceSurface(
693 SourceSurface
* aSurface
) const {
694 // See if we have a previously optimized surface available. We have to do this
695 // check before the SurfaceType::RECORDING below, because aSurface might be a
696 // SurfaceType::RECORDING from another recorder we have previously optimized.
697 auto* userData
= static_cast<RecordingSourceSurfaceUserData
*>(
698 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
700 RefPtr
<SourceSurface
> strongRef(userData
->optimizedSurface
);
702 return do_AddRef(strongRef
);
705 if (!EnsureSurfaceStoredRecording(mRecorder
, aSurface
,
706 "OptimizeSourceSurface")) {
707 // Surface was already stored, but doesn't have UserData so must be one
708 // of our recording surfaces.
709 MOZ_ASSERT(aSurface
->GetType() == SurfaceType::RECORDING
);
710 return do_AddRef(aSurface
);
713 userData
= static_cast<RecordingSourceSurfaceUserData
*>(
714 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
716 "User data should always have been set by "
717 "EnsureSurfaceStoredRecording.");
720 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(
721 aSurface
->GetSize(), aSurface
->GetFormat(), mRecorder
, aSurface
);
722 mRecorder
->RecordEvent(const_cast<DrawTargetRecording
*>(this),
723 RecordedOptimizeSourceSurface(aSurface
, retSurf
));
724 userData
->optimizedSurface
= retSurf
;
726 return retSurf
.forget();
729 already_AddRefed
<SourceSurface
>
730 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
731 const NativeSurface
& aSurface
) const {
736 already_AddRefed
<DrawTarget
>
737 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
738 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
739 RefPtr
<DrawTarget
> similarDT
;
740 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
741 // If the requested similar draw target is too big, then we should try to
742 // rasterize on the content side to avoid duplicating the effort when a
743 // blob image gets tiled. If we fail somehow to produce it, we can fall
744 // back to recording.
745 constexpr int32_t kRasterThreshold
= 256 * 256 * 4;
746 int32_t stride
= aSize
.width
* BytesPerPixel(aFormat
);
747 int32_t surfaceBytes
= aSize
.height
* stride
;
748 if (surfaceBytes
>= kRasterThreshold
) {
749 auto surface
= MakeRefPtr
<SourceSurfaceSharedData
>();
750 if (surface
->Init(aSize
, stride
, aFormat
)) {
751 auto dt
= MakeRefPtr
<DrawTargetSkia
>();
752 if (dt
->Init(std::move(surface
))) {
755 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
761 return CreateSimilarDrawTarget(aSize
, aFormat
);
764 already_AddRefed
<DrawTarget
> DrawTargetRecording::CreateSimilarDrawTarget(
765 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
766 RefPtr
<DrawTarget
> similarDT
;
767 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
769 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize
), aFormat
);
770 mRecorder
->RecordEvent(
771 const_cast<DrawTargetRecording
*>(this),
772 RecordedCreateSimilarDrawTarget(similarDT
.get(), aSize
, aFormat
));
773 } else if (XRE_IsContentProcess()) {
774 // Crash any content process that calls this function with arguments that
775 // would fail to create a similar draw target. We do this to root out bad
776 // callers. We don't want to crash any important processes though so for
777 // for those we'll just gracefully return nullptr.
779 "Content-process DrawTargetRecording can't create requested similar "
782 return similarDT
.forget();
785 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
786 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
787 return mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
);
790 RefPtr
<DrawTarget
> DrawTargetRecording::CreateClippedDrawTarget(
791 const Rect
& aBounds
, SurfaceFormat aFormat
) {
792 RefPtr
<DrawTarget
> similarDT
;
793 similarDT
= new DrawTargetRecording(this, mRect
, aFormat
);
794 mRecorder
->RecordEvent(
795 this, RecordedCreateClippedDrawTarget(similarDT
.get(), aBounds
, aFormat
));
796 similarDT
->SetTransform(mTransform
);
800 already_AddRefed
<DrawTarget
>
801 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
802 const IntSize
& aMaxSize
, SurfaceFormat aFormat
, FilterNode
* aFilter
,
803 FilterNode
* aSource
, const Rect
& aSourceRect
, const Point
& aDestPoint
) {
804 RefPtr
<DrawTarget
> similarDT
;
805 if (mFinalDT
->CanCreateSimilarDrawTarget(aMaxSize
, aFormat
)) {
806 similarDT
= new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize
),
808 mRecorder
->RecordEvent(
809 this, RecordedCreateDrawTargetForFilter(similarDT
.get(), aMaxSize
,
810 aFormat
, aFilter
, aSource
,
811 aSourceRect
, aDestPoint
));
812 } else if (XRE_IsContentProcess()) {
813 // See CreateSimilarDrawTarget
815 "Content-process DrawTargetRecording can't create requested clipped "
818 return similarDT
.forget();
821 already_AddRefed
<PathBuilder
> DrawTargetRecording::CreatePathBuilder(
822 FillRule aFillRule
) const {
823 return MakeAndAddRef
<PathBuilderRecording
>(mFinalDT
->GetBackendType(),
827 already_AddRefed
<GradientStops
> DrawTargetRecording::CreateGradientStops(
828 GradientStop
* aStops
, uint32_t aNumStops
, ExtendMode aExtendMode
) const {
829 RefPtr
<GradientStops
> retStops
= new GradientStopsRecording(mRecorder
);
831 mRecorder
->RecordEvent(
832 const_cast<DrawTargetRecording
*>(this),
833 RecordedGradientStopsCreation(retStops
, aStops
, aNumStops
, aExtendMode
));
835 return retStops
.forget();
838 void DrawTargetRecording::SetTransform(const Matrix
& aTransform
) {
839 if (mTransform
.ExactlyEquals(aTransform
)) {
842 DrawTarget::SetTransform(aTransform
);
843 mRecorder
->RecordEvent(this, RecordedSetTransform(aTransform
));
846 void DrawTargetRecording::SetPermitSubpixelAA(bool aPermitSubpixelAA
) {
847 if (aPermitSubpixelAA
== mPermitSubpixelAA
) {
850 DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA
);
851 mRecorder
->RecordEvent(this, RecordedSetPermitSubpixelAA(aPermitSubpixelAA
));
854 already_AddRefed
<PathRecording
> DrawTargetRecording::EnsurePathStored(
856 RefPtr
<PathRecording
> pathRecording
;
857 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
859 const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
860 if (!mRecorder
->TryAddStoredObject(pathRecording
)) {
861 // Path is already stored.
862 return pathRecording
.forget();
865 MOZ_ASSERT(!mRecorder
->HasStoredObject(aPath
));
866 FillRule fillRule
= aPath
->GetFillRule();
867 RefPtr
<PathBuilderRecording
> builderRecording
=
868 new PathBuilderRecording(mFinalDT
->GetBackendType(), fillRule
);
869 aPath
->StreamToSink(builderRecording
);
870 pathRecording
= builderRecording
->Finish().downcast
<PathRecording
>();
871 mRecorder
->AddStoredObject(pathRecording
);
874 // It's important that AddStoredObject or TryAddStoredObject is called before
875 // this because that will run any pending processing required by recorded
876 // objects that have been deleted off the main thread.
877 mRecorder
->RecordEvent(this, RecordedPathCreation(pathRecording
.get()));
878 pathRecording
->mStoredRecorders
.push_back(mRecorder
);
880 return pathRecording
.forget();
883 // This should only be called on the 'root' DrawTargetRecording.
884 // Calling it on a child DrawTargetRecordings will cause confusion.
885 void DrawTargetRecording::FlushItem(const IntRect
& aBounds
) {
886 mRecorder
->FlushItem(aBounds
);
887 // Reinitialize the recorder (FlushItem will write a new recording header)
888 // Tell the new recording about our draw target
889 // This code should match what happens in the DrawTargetRecording constructor.
890 MOZ_DIAGNOSTIC_ASSERT(mRecorder
->GetRecorderType() != RecorderType::CANVAS
);
891 mRecorder
->RecordEvent(
892 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
893 mFinalDT
->GetFormat(), false, nullptr));
894 // Add the current transform to the new recording
895 mRecorder
->RecordEvent(this,
896 RecordedSetTransform(DrawTarget::GetTransform()));
899 void DrawTargetRecording::EnsurePatternDependenciesStored(
900 const Pattern
& aPattern
) {
901 switch (aPattern
.GetType()) {
902 case PatternType::COLOR
:
903 // No dependencies here.
905 case PatternType::LINEAR_GRADIENT
: {
907 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
,
908 mRecorder
->HasStoredObject(
909 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
));
912 case PatternType::RADIAL_GRADIENT
: {
914 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
,
915 mRecorder
->HasStoredObject(
916 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
));
919 case PatternType::CONIC_GRADIENT
: {
921 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
,
922 mRecorder
->HasStoredObject(
923 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
));
926 case PatternType::SURFACE
: {
927 const SurfacePattern
* pat
= static_cast<const SurfacePattern
*>(&aPattern
);
928 EnsureSurfaceStoredRecording(mRecorder
, pat
->mSurface
,
929 "EnsurePatternDependenciesStored");
936 } // namespace mozilla