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();
105 SurfaceFormat mFormat
;
106 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
107 // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call
108 // we need GetDataSurface to work, so we hold the original surface we
109 // optimized to return its GetDataSurface.
110 RefPtr
<SourceSurface
> mOriginalSurface
;
113 class GradientStopsRecording
: public GradientStops
{
115 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording
, override
)
117 explicit GradientStopsRecording(DrawEventRecorderPrivate
* aRecorder
)
118 : mRecorder(aRecorder
) {
119 mRecorder
->AddStoredObject(this);
122 virtual ~GradientStopsRecording() {
123 mRecorder
->RemoveStoredObject(this);
124 mRecorder
->RecordEvent(
125 RecordedGradientStopsDestruction(ReferencePtr(this)));
128 BackendType
GetBackendType() const override
{ return BackendType::RECORDING
; }
130 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
133 class FilterNodeRecording
: public FilterNode
{
135 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording
, override
)
136 using FilterNode::SetAttribute
;
138 explicit FilterNodeRecording(DrawEventRecorderPrivate
* aRecorder
)
139 : mRecorder(aRecorder
) {
140 mRecorder
->AddStoredObject(this);
143 virtual ~FilterNodeRecording() {
144 mRecorder
->RemoveStoredObject(this);
145 mRecorder
->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this)));
148 void SetInput(uint32_t aIndex
, SourceSurface
* aSurface
) override
{
149 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "SetInput");
151 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aSurface
));
153 void SetInput(uint32_t aIndex
, FilterNode
* aFilter
) override
{
154 MOZ_ASSERT(mRecorder
->HasStoredObject(aFilter
));
156 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aFilter
));
159 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
160 void SetAttribute(uint32_t aIndex, type aValue) override { \
161 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \
162 this, aIndex, aValue, \
163 RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
166 FORWARD_SET_ATTRIBUTE(bool, BOOL
);
167 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32
);
168 FORWARD_SET_ATTRIBUTE(Float
, FLOAT
);
169 FORWARD_SET_ATTRIBUTE(const Size
&, SIZE
);
170 FORWARD_SET_ATTRIBUTE(const IntSize
&, INTSIZE
);
171 FORWARD_SET_ATTRIBUTE(const IntPoint
&, INTPOINT
);
172 FORWARD_SET_ATTRIBUTE(const Rect
&, RECT
);
173 FORWARD_SET_ATTRIBUTE(const IntRect
&, INTRECT
);
174 FORWARD_SET_ATTRIBUTE(const Point
&, POINT
);
175 FORWARD_SET_ATTRIBUTE(const Matrix
&, MATRIX
);
176 FORWARD_SET_ATTRIBUTE(const Matrix5x4
&, MATRIX5X4
);
177 FORWARD_SET_ATTRIBUTE(const Point3D
&, POINT3D
);
178 FORWARD_SET_ATTRIBUTE(const DeviceColor
&, COLOR
);
180 #undef FORWARD_SET_ATTRIBUTE
182 void SetAttribute(uint32_t aIndex
, const Float
* aFloat
,
183 uint32_t aSize
) override
{
184 mRecorder
->RecordEvent(
185 RecordedFilterNodeSetAttribute(this, aIndex
, aFloat
, aSize
));
188 FilterBackend
GetBackendType() override
{ return FILTER_BACKEND_RECORDING
; }
190 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
193 DrawTargetRecording::DrawTargetRecording(
194 layers::CanvasDrawEventRecorder
* aRecorder
, int64_t aTextureId
,
195 const layers::RemoteTextureOwnerId
& aTextureOwnerId
, DrawTarget
* aDT
,
196 const IntSize
& aSize
)
197 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
199 mRect(IntPoint(0, 0), aSize
) {
200 mRecorder
->RecordEvent(layers::RecordedCanvasDrawTargetCreation(
201 this, aTextureId
, aTextureOwnerId
, mFinalDT
->GetBackendType(), aSize
,
202 mFinalDT
->GetFormat()));
203 mFormat
= mFinalDT
->GetFormat();
206 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder
* aRecorder
,
207 DrawTarget
* aDT
, IntRect aRect
,
209 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
212 MOZ_DIAGNOSTIC_ASSERT(aRecorder
->GetRecorderType() != RecorderType::CANVAS
);
213 RefPtr
<SourceSurface
> snapshot
= aHasData
? mFinalDT
->Snapshot() : nullptr;
214 mRecorder
->RecordEvent(
215 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
216 mFinalDT
->GetFormat(), aHasData
, snapshot
));
217 mFormat
= mFinalDT
->GetFormat();
220 DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording
* aDT
,
221 IntRect aRect
, SurfaceFormat aFormat
)
222 : mRecorder(aDT
->mRecorder
), mFinalDT(aDT
->mFinalDT
), mRect(aRect
) {
226 DrawTargetRecording::~DrawTargetRecording() {
227 mRecorder
->RecordEvent(RecordedDrawTargetDestruction(ReferencePtr(this)));
228 mRecorder
->ClearDrawTarget(this);
231 void DrawTargetRecording::Link(const char* aDestination
, const Rect
& aRect
) {
232 mRecorder
->RecordEvent(this, RecordedLink(aDestination
, aRect
));
235 void DrawTargetRecording::Destination(const char* aDestination
,
236 const Point
& aPoint
) {
237 mRecorder
->RecordEvent(this, RecordedDestination(aDestination
, aPoint
));
240 void DrawTargetRecording::FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
241 const DrawOptions
& aOptions
) {
242 EnsurePatternDependenciesStored(aPattern
);
244 mRecorder
->RecordEvent(this, RecordedFillRect(aRect
, aPattern
, aOptions
));
247 void DrawTargetRecording::StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
248 const StrokeOptions
& aStrokeOptions
,
249 const DrawOptions
& aOptions
) {
250 EnsurePatternDependenciesStored(aPattern
);
252 mRecorder
->RecordEvent(
253 this, RecordedStrokeRect(aRect
, aPattern
, aStrokeOptions
, aOptions
));
256 void DrawTargetRecording::StrokeLine(const Point
& aBegin
, const Point
& aEnd
,
257 const Pattern
& aPattern
,
258 const StrokeOptions
& aStrokeOptions
,
259 const DrawOptions
& aOptions
) {
260 EnsurePatternDependenciesStored(aPattern
);
262 mRecorder
->RecordEvent(this, RecordedStrokeLine(aBegin
, aEnd
, aPattern
,
263 aStrokeOptions
, aOptions
));
266 void DrawTargetRecording::Fill(const Path
* aPath
, const Pattern
& aPattern
,
267 const DrawOptions
& aOptions
) {
272 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
273 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
274 auto circle
= path
->AsCircle();
276 EnsurePatternDependenciesStored(aPattern
);
277 mRecorder
->RecordEvent(
278 this, RecordedFillCircle(circle
.value(), aPattern
, aOptions
));
283 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
284 EnsurePatternDependenciesStored(aPattern
);
286 mRecorder
->RecordEvent(this, RecordedFill(pathRecording
, aPattern
, aOptions
));
289 struct RecordingFontUserData
{
292 RefPtr
<DrawEventRecorderPrivate
> recorder
;
295 static void RecordingFontUserDataDestroyFunc(void* aUserData
) {
296 RecordingFontUserData
* userData
=
297 static_cast<RecordingFontUserData
*>(aUserData
);
299 userData
->recorder
->RecordEvent(
300 RecordedScaledFontDestruction(ReferencePtr(userData
->refPtr
)));
301 userData
->recorder
->RemoveScaledFont((ScaledFont
*)userData
->refPtr
);
302 userData
->recorder
->DecrementUnscaledFontRefCount(userData
->unscaledFont
);
306 void DrawTargetRecording::FillGlyphs(ScaledFont
* aFont
,
307 const GlyphBuffer
& aBuffer
,
308 const Pattern
& aPattern
,
309 const DrawOptions
& aOptions
) {
314 EnsurePatternDependenciesStored(aPattern
);
316 UserDataKey
* userDataKey
= reinterpret_cast<UserDataKey
*>(mRecorder
.get());
317 if (mRecorder
->WantsExternalFonts()) {
318 mRecorder
->AddScaledFont(aFont
);
319 } else if (!aFont
->GetUserData(userDataKey
)) {
320 UnscaledFont
* unscaledFont
= aFont
->GetUnscaledFont();
321 if (mRecorder
->IncrementUnscaledFontRefCount(unscaledFont
) == 0) {
322 // Prefer sending the description, if we can create one. This ensures
323 // we don't record the data of system fonts which saves time and can
324 // prevent duplicate copies from accumulating in the OS cache during
326 RecordedFontDescriptor
fontDesc(unscaledFont
);
327 if (fontDesc
.IsValid()) {
328 mRecorder
->RecordEvent(fontDesc
);
330 RecordedFontData
fontData(unscaledFont
);
331 RecordedFontDetails fontDetails
;
332 if (fontData
.GetFontDetails(fontDetails
)) {
333 // Try to serialise the whole font, just in case this is a web font
334 // that is not present on the system.
335 if (!mRecorder
->HasStoredFontData(fontDetails
.fontDataKey
)) {
336 mRecorder
->RecordEvent(fontData
);
337 mRecorder
->AddStoredFontData(fontDetails
.fontDataKey
);
339 mRecorder
->RecordEvent(
340 RecordedUnscaledFontCreation(unscaledFont
, fontDetails
));
342 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
347 mRecorder
->RecordEvent(RecordedScaledFontCreation(aFont
, unscaledFont
));
348 RecordingFontUserData
* userData
= new RecordingFontUserData
;
349 userData
->refPtr
= aFont
;
350 userData
->unscaledFont
= unscaledFont
;
351 userData
->recorder
= mRecorder
;
352 aFont
->AddUserData(userDataKey
, userData
,
353 &RecordingFontUserDataDestroyFunc
);
354 userData
->recorder
->AddScaledFont(aFont
);
357 mRecorder
->RecordEvent(
358 this, RecordedFillGlyphs(aFont
, aPattern
, aOptions
, aBuffer
.mGlyphs
,
359 aBuffer
.mNumGlyphs
));
362 void DrawTargetRecording::Mask(const Pattern
& aSource
, const Pattern
& aMask
,
363 const DrawOptions
& aOptions
) {
364 EnsurePatternDependenciesStored(aSource
);
365 EnsurePatternDependenciesStored(aMask
);
367 mRecorder
->RecordEvent(this, RecordedMask(aSource
, aMask
, aOptions
));
370 void DrawTargetRecording::MaskSurface(const Pattern
& aSource
,
371 SourceSurface
* aMask
, Point aOffset
,
372 const DrawOptions
& aOptions
) {
377 EnsurePatternDependenciesStored(aSource
);
378 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "MaskSurface");
380 mRecorder
->RecordEvent(
381 this, RecordedMaskSurface(aSource
, aMask
, aOffset
, aOptions
));
384 void DrawTargetRecording::Stroke(const Path
* aPath
, const Pattern
& aPattern
,
385 const StrokeOptions
& aStrokeOptions
,
386 const DrawOptions
& aOptions
) {
387 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
388 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
389 auto circle
= path
->AsCircle();
390 if (circle
&& circle
->closed
) {
391 EnsurePatternDependenciesStored(aPattern
);
392 mRecorder
->RecordEvent(
393 this, RecordedStrokeCircle(circle
.value(), aPattern
, aStrokeOptions
,
398 auto line
= path
->AsLine();
400 EnsurePatternDependenciesStored(aPattern
);
401 mRecorder
->RecordEvent(
402 this, RecordedStrokeLine(line
->origin
, line
->destination
, aPattern
,
403 aStrokeOptions
, aOptions
));
408 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
409 EnsurePatternDependenciesStored(aPattern
);
411 mRecorder
->RecordEvent(
412 this, RecordedStroke(pathRecording
, aPattern
, aStrokeOptions
, aOptions
));
415 void DrawTargetRecording::DrawShadow(const Path
* aPath
, const Pattern
& aPattern
,
416 const ShadowOptions
& aShadow
,
417 const DrawOptions
& aOptions
,
418 const StrokeOptions
* aStrokeOptions
) {
419 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
420 EnsurePatternDependenciesStored(aPattern
);
422 mRecorder
->RecordEvent(
423 this, RecordedDrawShadow(pathRecording
, aPattern
, aShadow
, aOptions
,
427 already_AddRefed
<SourceSurface
> DrawTargetRecording::Snapshot() {
428 RefPtr
<SourceSurface
> retSurf
=
429 new SourceSurfaceRecording(mRect
.Size(), mFormat
, mRecorder
);
431 mRecorder
->RecordEvent(this, RecordedSnapshot(ReferencePtr(retSurf
)));
433 return retSurf
.forget();
436 already_AddRefed
<SourceSurface
> DrawTargetRecording::IntoLuminanceSource(
437 LuminanceType aLuminanceType
, float aOpacity
) {
438 RefPtr
<SourceSurface
> retSurf
=
439 new SourceSurfaceRecording(mRect
.Size(), SurfaceFormat::A8
, mRecorder
);
441 mRecorder
->RecordEvent(
442 this, RecordedIntoLuminanceSource(retSurf
, aLuminanceType
, aOpacity
));
444 return retSurf
.forget();
447 void DrawTargetRecording::Flush() {
448 mRecorder
->RecordEvent(this, RecordedFlush());
451 void DrawTargetRecording::DetachAllSnapshots() {
452 mRecorder
->RecordEvent(this, RecordedDetachAllSnapshots());
455 void DrawTargetRecording::DrawSurface(SourceSurface
* aSurface
,
456 const Rect
& aDest
, const Rect
& aSource
,
457 const DrawSurfaceOptions
& aSurfOptions
,
458 const DrawOptions
& aOptions
) {
463 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurface");
465 mRecorder
->RecordEvent(this, RecordedDrawSurface(aSurface
, aDest
, aSource
,
466 aSurfOptions
, aOptions
));
469 void DrawTargetRecording::DrawDependentSurface(uint64_t aId
,
471 mRecorder
->AddDependentSurface(aId
);
472 mRecorder
->RecordEvent(this, RecordedDrawDependentSurface(aId
, aDest
));
475 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface
* aSurface
,
477 const ShadowOptions
& aShadow
,
483 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurfaceWithShadow");
485 mRecorder
->RecordEvent(
486 this, RecordedDrawSurfaceWithShadow(aSurface
, aDest
, aShadow
, aOp
));
489 void DrawTargetRecording::DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
490 const Point
& aDestPoint
,
491 const DrawOptions
& aOptions
) {
496 MOZ_ASSERT(mRecorder
->HasStoredObject(aNode
));
498 mRecorder
->RecordEvent(
499 this, RecordedDrawFilter(aNode
, aSourceRect
, aDestPoint
, aOptions
));
502 already_AddRefed
<FilterNode
> DrawTargetRecording::CreateFilter(
504 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(mRecorder
);
506 mRecorder
->RecordEvent(this, RecordedFilterNodeCreation(retNode
, aType
));
508 return retNode
.forget();
511 void DrawTargetRecording::ClearRect(const Rect
& aRect
) {
512 mRecorder
->RecordEvent(this, RecordedClearRect(aRect
));
515 void DrawTargetRecording::CopySurface(SourceSurface
* aSurface
,
516 const IntRect
& aSourceRect
,
517 const IntPoint
& aDestination
) {
522 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "CopySurface");
524 mRecorder
->RecordEvent(
525 this, RecordedCopySurface(aSurface
, aSourceRect
, aDestination
));
528 void DrawTargetRecording::PushClip(const Path
* aPath
) {
533 // The canvas doesn't have a clipRect API so we always end up in the generic
534 // path. The D2D backend doesn't have a good way of specializing rectangular
535 // clips so we take advantage of the fact that aPath is usually backed by a
536 // SkiaPath which implements AsRect() and specialize it here.
537 auto rect
= aPath
->AsRect();
539 PushClipRect(rect
.value());
543 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
545 mRecorder
->RecordEvent(this, RecordedPushClip(ReferencePtr(pathRecording
)));
548 void DrawTargetRecording::PushClipRect(const Rect
& aRect
) {
549 mRecorder
->RecordEvent(this, RecordedPushClipRect(aRect
));
552 void DrawTargetRecording::PopClip() {
553 mRecorder
->RecordEvent(this, RecordedPopClip());
556 void DrawTargetRecording::PushLayer(bool aOpaque
, Float aOpacity
,
557 SourceSurface
* aMask
,
558 const Matrix
& aMaskTransform
,
559 const IntRect
& aBounds
,
560 bool aCopyBackground
) {
562 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
565 mRecorder
->RecordEvent(
566 this, RecordedPushLayer(aOpaque
, aOpacity
, aMask
, aMaskTransform
, aBounds
,
570 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque
, Float aOpacity
,
571 SourceSurface
* aMask
,
572 const Matrix
& aMaskTransform
,
573 const IntRect
& aBounds
,
574 bool aCopyBackground
,
575 CompositionOp aCompositionOp
) {
577 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
580 mRecorder
->RecordEvent(this, RecordedPushLayerWithBlend(
581 aOpaque
, aOpacity
, aMask
, aMaskTransform
,
582 aBounds
, aCopyBackground
, aCompositionOp
));
585 void DrawTargetRecording::PopLayer() {
586 mRecorder
->RecordEvent(this, RecordedPopLayer());
589 already_AddRefed
<SourceSurface
>
590 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData
,
591 const IntSize
& aSize
,
593 SurfaceFormat aFormat
) const {
594 RefPtr
<SourceSurface
> surface
= CreateDataSourceSurfaceWithStrideFromData(
595 aSize
, aFormat
, aStride
, aData
, aStride
);
600 return OptimizeSourceSurface(surface
);
603 already_AddRefed
<SourceSurface
> DrawTargetRecording::OptimizeSourceSurface(
604 SourceSurface
* aSurface
) const {
605 // See if we have a previously optimized surface available. We have to do this
606 // check before the SurfaceType::RECORDING below, because aSurface might be a
607 // SurfaceType::RECORDING from another recorder we have previously optimized.
608 auto* userData
= static_cast<RecordingSourceSurfaceUserData
*>(
609 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
611 RefPtr
<SourceSurface
> strongRef(userData
->optimizedSurface
);
613 return do_AddRef(strongRef
);
616 if (!EnsureSurfaceStoredRecording(mRecorder
, aSurface
,
617 "OptimizeSourceSurface")) {
618 // Surface was already stored, but doesn't have UserData so must be one
619 // of our recording surfaces.
620 MOZ_ASSERT(aSurface
->GetType() == SurfaceType::RECORDING
);
621 return do_AddRef(aSurface
);
624 userData
= static_cast<RecordingSourceSurfaceUserData
*>(
625 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
627 "User data should always have been set by "
628 "EnsureSurfaceStoredRecording.");
631 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(
632 aSurface
->GetSize(), aSurface
->GetFormat(), mRecorder
, aSurface
);
633 mRecorder
->RecordEvent(const_cast<DrawTargetRecording
*>(this),
634 RecordedOptimizeSourceSurface(aSurface
, retSurf
));
635 userData
->optimizedSurface
= retSurf
;
637 return retSurf
.forget();
640 already_AddRefed
<SourceSurface
>
641 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
642 const NativeSurface
& aSurface
) const {
647 already_AddRefed
<DrawTarget
>
648 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
649 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
650 RefPtr
<DrawTarget
> similarDT
;
651 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
652 // If the requested similar draw target is too big, then we should try to
653 // rasterize on the content side to avoid duplicating the effort when a
654 // blob image gets tiled. If we fail somehow to produce it, we can fall
655 // back to recording.
656 constexpr int32_t kRasterThreshold
= 256 * 256 * 4;
657 int32_t stride
= aSize
.width
* BytesPerPixel(aFormat
);
658 int32_t surfaceBytes
= aSize
.height
* stride
;
659 if (surfaceBytes
>= kRasterThreshold
) {
660 auto surface
= MakeRefPtr
<SourceSurfaceSharedData
>();
661 if (surface
->Init(aSize
, stride
, aFormat
)) {
662 auto dt
= MakeRefPtr
<DrawTargetSkia
>();
663 if (dt
->Init(std::move(surface
))) {
666 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
672 return CreateSimilarDrawTarget(aSize
, aFormat
);
675 already_AddRefed
<DrawTarget
> DrawTargetRecording::CreateSimilarDrawTarget(
676 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
677 RefPtr
<DrawTarget
> similarDT
;
678 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
680 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize
), aFormat
);
681 mRecorder
->RecordEvent(
682 const_cast<DrawTargetRecording
*>(this),
683 RecordedCreateSimilarDrawTarget(similarDT
.get(), aSize
, aFormat
));
684 } else if (XRE_IsContentProcess()) {
685 // Crash any content process that calls this function with arguments that
686 // would fail to create a similar draw target. We do this to root out bad
687 // callers. We don't want to crash any important processes though so for
688 // for those we'll just gracefully return nullptr.
690 "Content-process DrawTargetRecording can't create requested similar "
693 return similarDT
.forget();
696 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
697 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
698 return mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
);
701 RefPtr
<DrawTarget
> DrawTargetRecording::CreateClippedDrawTarget(
702 const Rect
& aBounds
, SurfaceFormat aFormat
) {
703 RefPtr
<DrawTarget
> similarDT
;
704 similarDT
= new DrawTargetRecording(this, mRect
, aFormat
);
705 mRecorder
->RecordEvent(
706 this, RecordedCreateClippedDrawTarget(similarDT
.get(), aBounds
, aFormat
));
707 similarDT
->SetTransform(mTransform
);
711 already_AddRefed
<DrawTarget
>
712 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
713 const IntSize
& aMaxSize
, SurfaceFormat aFormat
, FilterNode
* aFilter
,
714 FilterNode
* aSource
, const Rect
& aSourceRect
, const Point
& aDestPoint
) {
715 RefPtr
<DrawTarget
> similarDT
;
716 if (mFinalDT
->CanCreateSimilarDrawTarget(aMaxSize
, aFormat
)) {
717 similarDT
= new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize
),
719 mRecorder
->RecordEvent(
720 this, RecordedCreateDrawTargetForFilter(similarDT
.get(), aMaxSize
,
721 aFormat
, aFilter
, aSource
,
722 aSourceRect
, aDestPoint
));
723 } else if (XRE_IsContentProcess()) {
724 // See CreateSimilarDrawTarget
726 "Content-process DrawTargetRecording can't create requested clipped "
729 return similarDT
.forget();
732 already_AddRefed
<PathBuilder
> DrawTargetRecording::CreatePathBuilder(
733 FillRule aFillRule
) const {
734 return MakeAndAddRef
<PathBuilderRecording
>(mFinalDT
->GetBackendType(),
738 already_AddRefed
<GradientStops
> DrawTargetRecording::CreateGradientStops(
739 GradientStop
* aStops
, uint32_t aNumStops
, ExtendMode aExtendMode
) const {
740 RefPtr
<GradientStops
> retStops
= new GradientStopsRecording(mRecorder
);
742 mRecorder
->RecordEvent(
743 const_cast<DrawTargetRecording
*>(this),
744 RecordedGradientStopsCreation(retStops
, aStops
, aNumStops
, aExtendMode
));
746 return retStops
.forget();
749 void DrawTargetRecording::SetTransform(const Matrix
& aTransform
) {
750 if (mTransform
.ExactlyEquals(aTransform
)) {
753 DrawTarget::SetTransform(aTransform
);
754 mRecorder
->RecordEvent(this, RecordedSetTransform(aTransform
));
757 already_AddRefed
<PathRecording
> DrawTargetRecording::EnsurePathStored(
759 RefPtr
<PathRecording
> pathRecording
;
760 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
762 const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
763 if (!mRecorder
->TryAddStoredObject(pathRecording
)) {
764 // Path is already stored.
765 return pathRecording
.forget();
768 MOZ_ASSERT(!mRecorder
->HasStoredObject(aPath
));
769 FillRule fillRule
= aPath
->GetFillRule();
770 RefPtr
<PathBuilderRecording
> builderRecording
=
771 new PathBuilderRecording(mFinalDT
->GetBackendType(), fillRule
);
772 aPath
->StreamToSink(builderRecording
);
773 pathRecording
= builderRecording
->Finish().downcast
<PathRecording
>();
774 mRecorder
->AddStoredObject(pathRecording
);
777 // It's important that AddStoredObject or TryAddStoredObject is called before
778 // this because that will run any pending processing required by recorded
779 // objects that have been deleted off the main thread.
780 mRecorder
->RecordEvent(this, RecordedPathCreation(pathRecording
.get()));
781 pathRecording
->mStoredRecorders
.push_back(mRecorder
);
783 return pathRecording
.forget();
786 // This should only be called on the 'root' DrawTargetRecording.
787 // Calling it on a child DrawTargetRecordings will cause confusion.
788 void DrawTargetRecording::FlushItem(const IntRect
& aBounds
) {
789 mRecorder
->FlushItem(aBounds
);
790 // Reinitialize the recorder (FlushItem will write a new recording header)
791 // Tell the new recording about our draw target
792 // This code should match what happens in the DrawTargetRecording constructor.
793 MOZ_DIAGNOSTIC_ASSERT(mRecorder
->GetRecorderType() != RecorderType::CANVAS
);
794 mRecorder
->RecordEvent(
795 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
796 mFinalDT
->GetFormat(), false, nullptr));
797 // Add the current transform to the new recording
798 mRecorder
->RecordEvent(this,
799 RecordedSetTransform(DrawTarget::GetTransform()));
802 void DrawTargetRecording::EnsurePatternDependenciesStored(
803 const Pattern
& aPattern
) {
804 switch (aPattern
.GetType()) {
805 case PatternType::COLOR
:
806 // No dependencies here.
808 case PatternType::LINEAR_GRADIENT
: {
810 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
,
811 mRecorder
->HasStoredObject(
812 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
));
815 case PatternType::RADIAL_GRADIENT
: {
817 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
,
818 mRecorder
->HasStoredObject(
819 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
));
822 case PatternType::CONIC_GRADIENT
: {
824 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
,
825 mRecorder
->HasStoredObject(
826 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
));
829 case PatternType::SURFACE
: {
830 const SurfacePattern
* pat
= static_cast<const SurfacePattern
*>(&aPattern
);
831 EnsureSurfaceStoredRecording(mRecorder
, pat
->mSurface
,
832 "EnsurePatternDependenciesStored");
839 } // namespace mozilla