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/SourceSurfaceSharedData.h"
17 #include "mozilla/UniquePtr.h"
18 #include "nsXULAppAPI.h" // for XRE_IsContentProcess()
19 #include "RecordingTypes.h"
20 #include "RecordedEventImpl.h"
25 struct RecordingSourceSurfaceUserData
{
27 RefPtr
<DrawEventRecorderPrivate
> recorder
;
29 // The optimized surface holds a reference to our surface, for GetDataSurface
30 // calls, so we must hold a weak reference to avoid circular dependency.
31 ThreadSafeWeakPtr
<SourceSurface
> optimizedSurface
;
34 static void RecordingSourceSurfaceUserDataFunc(void* aUserData
) {
35 RecordingSourceSurfaceUserData
* userData
=
36 static_cast<RecordingSourceSurfaceUserData
*>(aUserData
);
38 if (NS_IsMainThread()) {
39 userData
->recorder
->RecordSourceSurfaceDestruction(userData
->refPtr
);
44 userData
->recorder
->AddPendingDeletion([userData
]() -> void {
45 userData
->recorder
->RecordSourceSurfaceDestruction(userData
->refPtr
);
50 static bool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate
* aRecorder
,
51 SourceSurface
* aSurface
,
53 // It's important that TryAddStoredObject is called first because that will
54 // run any pending processing required by recorded objects that have been
55 // deleted off the main thread.
56 if (!aRecorder
->TryAddStoredObject(aSurface
)) {
57 // Surface is already stored.
60 aRecorder
->StoreSourceSurfaceRecording(aSurface
, reason
);
61 aRecorder
->AddSourceSurface(aSurface
);
63 RecordingSourceSurfaceUserData
* userData
= new RecordingSourceSurfaceUserData
;
64 userData
->refPtr
= aSurface
;
65 userData
->recorder
= aRecorder
;
66 aSurface
->AddUserData(reinterpret_cast<UserDataKey
*>(aRecorder
), userData
,
67 &RecordingSourceSurfaceUserDataFunc
);
71 class SourceSurfaceRecording
: public SourceSurface
{
73 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording
, override
)
75 SourceSurfaceRecording(IntSize aSize
, SurfaceFormat aFormat
,
76 DrawEventRecorderPrivate
* aRecorder
,
77 SourceSurface
* aOriginalSurface
= nullptr)
81 mOriginalSurface(aOriginalSurface
) {
82 mRecorder
->AddStoredObject(this);
85 ~SourceSurfaceRecording() {
86 mRecorder
->RemoveStoredObject(this);
87 mRecorder
->RecordEvent(
88 RecordedSourceSurfaceDestruction(ReferencePtr(this)));
91 SurfaceType
GetType() const override
{ return SurfaceType::RECORDING
; }
92 IntSize
GetSize() const override
{ return mSize
; }
93 SurfaceFormat
GetFormat() const override
{ return mFormat
; }
94 already_AddRefed
<DataSourceSurface
> GetDataSurface() override
{
95 if (mOriginalSurface
) {
96 return mOriginalSurface
->GetDataSurface();
103 SurfaceFormat mFormat
;
104 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
105 // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call
106 // we need GetDataSurface to work, so we hold the original surface we
107 // optimized to return its GetDataSurface.
108 RefPtr
<SourceSurface
> mOriginalSurface
;
111 class GradientStopsRecording
: public GradientStops
{
113 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording
, override
)
115 explicit GradientStopsRecording(DrawEventRecorderPrivate
* aRecorder
)
116 : mRecorder(aRecorder
) {
117 mRecorder
->AddStoredObject(this);
120 virtual ~GradientStopsRecording() {
121 mRecorder
->RemoveStoredObject(this);
122 mRecorder
->RecordEvent(
123 RecordedGradientStopsDestruction(ReferencePtr(this)));
126 BackendType
GetBackendType() const override
{ return BackendType::RECORDING
; }
128 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
131 class FilterNodeRecording
: public FilterNode
{
133 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording
, override
)
134 using FilterNode::SetAttribute
;
136 explicit FilterNodeRecording(DrawEventRecorderPrivate
* aRecorder
)
137 : mRecorder(aRecorder
) {
138 mRecorder
->AddStoredObject(this);
141 virtual ~FilterNodeRecording() {
142 mRecorder
->RemoveStoredObject(this);
143 mRecorder
->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this)));
146 void SetInput(uint32_t aIndex
, SourceSurface
* aSurface
) override
{
147 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "SetInput");
149 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aSurface
));
151 void SetInput(uint32_t aIndex
, FilterNode
* aFilter
) override
{
152 MOZ_ASSERT(mRecorder
->HasStoredObject(aFilter
));
154 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aFilter
));
157 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
158 void SetAttribute(uint32_t aIndex, type aValue) override { \
159 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \
160 this, aIndex, aValue, \
161 RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
164 FORWARD_SET_ATTRIBUTE(bool, BOOL
);
165 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32
);
166 FORWARD_SET_ATTRIBUTE(Float
, FLOAT
);
167 FORWARD_SET_ATTRIBUTE(const Size
&, SIZE
);
168 FORWARD_SET_ATTRIBUTE(const IntSize
&, INTSIZE
);
169 FORWARD_SET_ATTRIBUTE(const IntPoint
&, INTPOINT
);
170 FORWARD_SET_ATTRIBUTE(const Rect
&, RECT
);
171 FORWARD_SET_ATTRIBUTE(const IntRect
&, INTRECT
);
172 FORWARD_SET_ATTRIBUTE(const Point
&, POINT
);
173 FORWARD_SET_ATTRIBUTE(const Matrix
&, MATRIX
);
174 FORWARD_SET_ATTRIBUTE(const Matrix5x4
&, MATRIX5X4
);
175 FORWARD_SET_ATTRIBUTE(const Point3D
&, POINT3D
);
176 FORWARD_SET_ATTRIBUTE(const DeviceColor
&, COLOR
);
178 #undef FORWARD_SET_ATTRIBUTE
180 void SetAttribute(uint32_t aIndex
, const Float
* aFloat
,
181 uint32_t aSize
) override
{
182 mRecorder
->RecordEvent(
183 RecordedFilterNodeSetAttribute(this, aIndex
, aFloat
, aSize
));
186 FilterBackend
GetBackendType() override
{ return FILTER_BACKEND_RECORDING
; }
188 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
191 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder
* aRecorder
,
192 DrawTarget
* aDT
, IntRect aRect
,
194 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
197 RefPtr
<SourceSurface
> snapshot
= aHasData
? mFinalDT
->Snapshot() : nullptr;
198 mRecorder
->RecordEvent(
199 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
200 mFinalDT
->GetFormat(), aHasData
, snapshot
));
201 mFormat
= mFinalDT
->GetFormat();
204 DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording
* aDT
,
205 IntRect aRect
, SurfaceFormat aFormat
)
206 : mRecorder(aDT
->mRecorder
), mFinalDT(aDT
->mFinalDT
), mRect(aRect
) {
210 DrawTargetRecording::~DrawTargetRecording() {
211 mRecorder
->RecordEvent(RecordedDrawTargetDestruction(ReferencePtr(this)));
214 void DrawTargetRecording::Link(const char* aDestination
, const Rect
& aRect
) {
215 mRecorder
->RecordEvent(RecordedLink(this, aDestination
, aRect
));
218 void DrawTargetRecording::Destination(const char* aDestination
,
219 const Point
& aPoint
) {
220 mRecorder
->RecordEvent(RecordedDestination(this, aDestination
, aPoint
));
223 void DrawTargetRecording::FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
224 const DrawOptions
& aOptions
) {
225 EnsurePatternDependenciesStored(aPattern
);
227 mRecorder
->RecordEvent(RecordedFillRect(this, aRect
, aPattern
, aOptions
));
230 void DrawTargetRecording::StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
231 const StrokeOptions
& aStrokeOptions
,
232 const DrawOptions
& aOptions
) {
233 EnsurePatternDependenciesStored(aPattern
);
235 mRecorder
->RecordEvent(
236 RecordedStrokeRect(this, aRect
, aPattern
, aStrokeOptions
, aOptions
));
239 void DrawTargetRecording::StrokeLine(const Point
& aBegin
, const Point
& aEnd
,
240 const Pattern
& aPattern
,
241 const StrokeOptions
& aStrokeOptions
,
242 const DrawOptions
& aOptions
) {
243 EnsurePatternDependenciesStored(aPattern
);
245 mRecorder
->RecordEvent(RecordedStrokeLine(this, aBegin
, aEnd
, aPattern
,
246 aStrokeOptions
, aOptions
));
249 void DrawTargetRecording::Fill(const Path
* aPath
, const Pattern
& aPattern
,
250 const DrawOptions
& aOptions
) {
255 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
256 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
257 auto circle
= path
->AsCircle();
259 EnsurePatternDependenciesStored(aPattern
);
260 mRecorder
->RecordEvent(
261 RecordedFillCircle(this, circle
.value(), aPattern
, aOptions
));
266 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
267 EnsurePatternDependenciesStored(aPattern
);
269 mRecorder
->RecordEvent(RecordedFill(this, pathRecording
, aPattern
, aOptions
));
272 struct RecordingFontUserData
{
275 RefPtr
<DrawEventRecorderPrivate
> recorder
;
278 static void RecordingFontUserDataDestroyFunc(void* aUserData
) {
279 RecordingFontUserData
* userData
=
280 static_cast<RecordingFontUserData
*>(aUserData
);
282 userData
->recorder
->RecordEvent(
283 RecordedScaledFontDestruction(ReferencePtr(userData
->refPtr
)));
284 userData
->recorder
->RemoveScaledFont((ScaledFont
*)userData
->refPtr
);
285 userData
->recorder
->DecrementUnscaledFontRefCount(userData
->unscaledFont
);
289 void DrawTargetRecording::FillGlyphs(ScaledFont
* aFont
,
290 const GlyphBuffer
& aBuffer
,
291 const Pattern
& aPattern
,
292 const DrawOptions
& aOptions
) {
297 EnsurePatternDependenciesStored(aPattern
);
299 UserDataKey
* userDataKey
= reinterpret_cast<UserDataKey
*>(mRecorder
.get());
300 if (mRecorder
->WantsExternalFonts()) {
301 mRecorder
->AddScaledFont(aFont
);
302 } else if (!aFont
->GetUserData(userDataKey
)) {
303 UnscaledFont
* unscaledFont
= aFont
->GetUnscaledFont();
304 if (mRecorder
->IncrementUnscaledFontRefCount(unscaledFont
) == 0) {
305 // Prefer sending the description, if we can create one. This ensures
306 // we don't record the data of system fonts which saves time and can
307 // prevent duplicate copies from accumulating in the OS cache during
309 RecordedFontDescriptor
fontDesc(unscaledFont
);
310 if (fontDesc
.IsValid()) {
311 mRecorder
->RecordEvent(fontDesc
);
313 RecordedFontData
fontData(unscaledFont
);
314 RecordedFontDetails fontDetails
;
315 if (fontData
.GetFontDetails(fontDetails
)) {
316 // Try to serialise the whole font, just in case this is a web font
317 // that is not present on the system.
318 if (!mRecorder
->HasStoredFontData(fontDetails
.fontDataKey
)) {
319 mRecorder
->RecordEvent(fontData
);
320 mRecorder
->AddStoredFontData(fontDetails
.fontDataKey
);
322 mRecorder
->RecordEvent(
323 RecordedUnscaledFontCreation(unscaledFont
, fontDetails
));
325 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
330 mRecorder
->RecordEvent(RecordedScaledFontCreation(aFont
, unscaledFont
));
331 RecordingFontUserData
* userData
= new RecordingFontUserData
;
332 userData
->refPtr
= aFont
;
333 userData
->unscaledFont
= unscaledFont
;
334 userData
->recorder
= mRecorder
;
335 aFont
->AddUserData(userDataKey
, userData
,
336 &RecordingFontUserDataDestroyFunc
);
337 userData
->recorder
->AddScaledFont(aFont
);
340 mRecorder
->RecordEvent(RecordedFillGlyphs(
341 this, aFont
, aPattern
, aOptions
, aBuffer
.mGlyphs
, aBuffer
.mNumGlyphs
));
344 void DrawTargetRecording::Mask(const Pattern
& aSource
, const Pattern
& aMask
,
345 const DrawOptions
& aOptions
) {
346 EnsurePatternDependenciesStored(aSource
);
347 EnsurePatternDependenciesStored(aMask
);
349 mRecorder
->RecordEvent(RecordedMask(this, aSource
, aMask
, aOptions
));
352 void DrawTargetRecording::MaskSurface(const Pattern
& aSource
,
353 SourceSurface
* aMask
, Point aOffset
,
354 const DrawOptions
& aOptions
) {
359 EnsurePatternDependenciesStored(aSource
);
360 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "MaskSurface");
362 mRecorder
->RecordEvent(
363 RecordedMaskSurface(this, aSource
, aMask
, aOffset
, aOptions
));
366 void DrawTargetRecording::Stroke(const Path
* aPath
, const Pattern
& aPattern
,
367 const StrokeOptions
& aStrokeOptions
,
368 const DrawOptions
& aOptions
) {
369 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
370 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
371 auto circle
= path
->AsCircle();
372 if (circle
&& circle
->closed
) {
373 EnsurePatternDependenciesStored(aPattern
);
374 mRecorder
->RecordEvent(RecordedStrokeCircle(
375 this, circle
.value(), aPattern
, aStrokeOptions
, aOptions
));
379 auto line
= path
->AsLine();
381 EnsurePatternDependenciesStored(aPattern
);
382 mRecorder
->RecordEvent(RecordedStrokeLine(this, line
->origin
,
383 line
->destination
, aPattern
,
384 aStrokeOptions
, aOptions
));
389 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
390 EnsurePatternDependenciesStored(aPattern
);
392 mRecorder
->RecordEvent(
393 RecordedStroke(this, pathRecording
, aPattern
, aStrokeOptions
, aOptions
));
396 void DrawTargetRecording::DrawShadow(const Path
* aPath
, const Pattern
& aPattern
,
397 const ShadowOptions
& aShadow
,
398 const DrawOptions
& aOptions
,
399 const StrokeOptions
* aStrokeOptions
) {
400 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
401 EnsurePatternDependenciesStored(aPattern
);
403 mRecorder
->RecordEvent(RecordedDrawShadow(this, pathRecording
, aPattern
,
404 aShadow
, aOptions
, aStrokeOptions
));
407 already_AddRefed
<SourceSurface
> DrawTargetRecording::Snapshot() {
408 RefPtr
<SourceSurface
> retSurf
=
409 new SourceSurfaceRecording(mRect
.Size(), mFormat
, mRecorder
);
411 mRecorder
->RecordEvent(RecordedSnapshot(retSurf
, this));
413 return retSurf
.forget();
416 already_AddRefed
<SourceSurface
> DrawTargetRecording::IntoLuminanceSource(
417 LuminanceType aLuminanceType
, float aOpacity
) {
418 RefPtr
<SourceSurface
> retSurf
=
419 new SourceSurfaceRecording(mRect
.Size(), SurfaceFormat::A8
, mRecorder
);
421 mRecorder
->RecordEvent(
422 RecordedIntoLuminanceSource(retSurf
, this, aLuminanceType
, aOpacity
));
424 return retSurf
.forget();
427 void DrawTargetRecording::Flush() {
428 mRecorder
->RecordEvent(RecordedFlush(this));
431 void DrawTargetRecording::DetachAllSnapshots() {
432 mRecorder
->RecordEvent(RecordedDetachAllSnapshots(this));
435 void DrawTargetRecording::DrawSurface(SourceSurface
* aSurface
,
436 const Rect
& aDest
, const Rect
& aSource
,
437 const DrawSurfaceOptions
& aSurfOptions
,
438 const DrawOptions
& aOptions
) {
443 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurface");
445 mRecorder
->RecordEvent(RecordedDrawSurface(this, aSurface
, aDest
, aSource
,
446 aSurfOptions
, aOptions
));
449 void DrawTargetRecording::DrawDependentSurface(uint64_t aId
,
451 mRecorder
->AddDependentSurface(aId
);
452 mRecorder
->RecordEvent(RecordedDrawDependentSurface(this, aId
, aDest
));
455 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface
* aSurface
,
457 const ShadowOptions
& aShadow
,
463 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurfaceWithShadow");
465 mRecorder
->RecordEvent(
466 RecordedDrawSurfaceWithShadow(this, aSurface
, aDest
, aShadow
, aOp
));
469 void DrawTargetRecording::DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
470 const Point
& aDestPoint
,
471 const DrawOptions
& aOptions
) {
476 MOZ_ASSERT(mRecorder
->HasStoredObject(aNode
));
478 mRecorder
->RecordEvent(
479 RecordedDrawFilter(this, aNode
, aSourceRect
, aDestPoint
, aOptions
));
482 already_AddRefed
<FilterNode
> DrawTargetRecording::CreateFilter(
484 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(mRecorder
);
486 mRecorder
->RecordEvent(RecordedFilterNodeCreation(retNode
, aType
));
488 return retNode
.forget();
491 void DrawTargetRecording::ClearRect(const Rect
& aRect
) {
492 mRecorder
->RecordEvent(RecordedClearRect(this, aRect
));
495 void DrawTargetRecording::CopySurface(SourceSurface
* aSurface
,
496 const IntRect
& aSourceRect
,
497 const IntPoint
& aDestination
) {
502 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "CopySurface");
504 mRecorder
->RecordEvent(
505 RecordedCopySurface(this, aSurface
, aSourceRect
, aDestination
));
508 void DrawTargetRecording::PushClip(const Path
* aPath
) {
513 // The canvas doesn't have a clipRect API so we always end up in the generic
514 // path. The D2D backend doesn't have a good way of specializing rectangular
515 // clips so we take advantage of the fact that aPath is usually backed by a
516 // SkiaPath which implements AsRect() and specialize it here.
517 auto rect
= aPath
->AsRect();
519 PushClipRect(rect
.value());
523 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
525 mRecorder
->RecordEvent(RecordedPushClip(this, pathRecording
));
528 void DrawTargetRecording::PushClipRect(const Rect
& aRect
) {
529 mRecorder
->RecordEvent(RecordedPushClipRect(this, aRect
));
532 void DrawTargetRecording::PopClip() {
533 mRecorder
->RecordEvent(RecordedPopClip(static_cast<DrawTarget
*>(this)));
536 void DrawTargetRecording::PushLayer(bool aOpaque
, Float aOpacity
,
537 SourceSurface
* aMask
,
538 const Matrix
& aMaskTransform
,
539 const IntRect
& aBounds
,
540 bool aCopyBackground
) {
542 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
545 mRecorder
->RecordEvent(RecordedPushLayer(this, aOpaque
, aOpacity
, aMask
,
546 aMaskTransform
, aBounds
,
550 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque
, Float aOpacity
,
551 SourceSurface
* aMask
,
552 const Matrix
& aMaskTransform
,
553 const IntRect
& aBounds
,
554 bool aCopyBackground
,
555 CompositionOp aCompositionOp
) {
557 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
560 mRecorder
->RecordEvent(
561 RecordedPushLayerWithBlend(this, aOpaque
, aOpacity
, aMask
, aMaskTransform
,
562 aBounds
, aCopyBackground
, aCompositionOp
));
565 void DrawTargetRecording::PopLayer() {
566 mRecorder
->RecordEvent(RecordedPopLayer(static_cast<DrawTarget
*>(this)));
569 already_AddRefed
<SourceSurface
>
570 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData
,
571 const IntSize
& aSize
,
573 SurfaceFormat aFormat
) const {
574 RefPtr
<SourceSurface
> surface
= CreateDataSourceSurfaceWithStrideFromData(
575 aSize
, aFormat
, aStride
, aData
, aStride
);
580 return OptimizeSourceSurface(surface
);
583 already_AddRefed
<SourceSurface
> DrawTargetRecording::OptimizeSourceSurface(
584 SourceSurface
* aSurface
) const {
585 // See if we have a previously optimized surface available. We have to do this
586 // check before the SurfaceType::RECORDING below, because aSurface might be a
587 // SurfaceType::RECORDING from another recorder we have previously optimized.
588 auto* userData
= static_cast<RecordingSourceSurfaceUserData
*>(
589 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
591 RefPtr
<SourceSurface
> strongRef(userData
->optimizedSurface
);
593 return do_AddRef(strongRef
);
596 if (!EnsureSurfaceStoredRecording(mRecorder
, aSurface
,
597 "OptimizeSourceSurface")) {
598 // Surface was already stored, but doesn't have UserData so must be one
599 // of our recording surfaces.
600 MOZ_ASSERT(aSurface
->GetType() == SurfaceType::RECORDING
);
601 return do_AddRef(aSurface
);
604 userData
= static_cast<RecordingSourceSurfaceUserData
*>(
605 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
607 "User data should always have been set by "
608 "EnsureSurfaceStoredRecording.");
611 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(
612 aSurface
->GetSize(), aSurface
->GetFormat(), mRecorder
, aSurface
);
613 mRecorder
->RecordEvent(
614 RecordedOptimizeSourceSurface(aSurface
, this, retSurf
));
615 userData
->optimizedSurface
= retSurf
;
617 return retSurf
.forget();
620 already_AddRefed
<SourceSurface
>
621 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
622 const NativeSurface
& aSurface
) const {
627 already_AddRefed
<DrawTarget
>
628 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
629 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
630 RefPtr
<DrawTarget
> similarDT
;
631 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
632 // If the requested similar draw target is too big, then we should try to
633 // rasterize on the content side to avoid duplicating the effort when a
634 // blob image gets tiled. If we fail somehow to produce it, we can fall
635 // back to recording.
636 constexpr int32_t kRasterThreshold
= 256 * 256 * 4;
637 int32_t stride
= aSize
.width
* BytesPerPixel(aFormat
);
638 int32_t surfaceBytes
= aSize
.height
* stride
;
639 if (surfaceBytes
>= kRasterThreshold
) {
640 auto surface
= MakeRefPtr
<SourceSurfaceSharedData
>();
641 if (surface
->Init(aSize
, stride
, aFormat
)) {
642 auto dt
= MakeRefPtr
<DrawTargetSkia
>();
643 if (dt
->Init(std::move(surface
))) {
646 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
652 return CreateSimilarDrawTarget(aSize
, aFormat
);
655 already_AddRefed
<DrawTarget
> DrawTargetRecording::CreateSimilarDrawTarget(
656 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
657 RefPtr
<DrawTarget
> similarDT
;
658 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
660 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize
), aFormat
);
661 mRecorder
->RecordEvent(
662 RecordedCreateSimilarDrawTarget(similarDT
.get(), aSize
, aFormat
));
663 } else if (XRE_IsContentProcess()) {
664 // Crash any content process that calls this function with arguments that
665 // would fail to create a similar draw target. We do this to root out bad
666 // callers. We don't want to crash any important processes though so for
667 // for those we'll just gracefully return nullptr.
669 "Content-process DrawTargetRecording can't create requested similar "
672 return similarDT
.forget();
675 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
676 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
677 return mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
);
680 RefPtr
<DrawTarget
> DrawTargetRecording::CreateClippedDrawTarget(
681 const Rect
& aBounds
, SurfaceFormat aFormat
) {
682 RefPtr
<DrawTarget
> similarDT
;
683 similarDT
= new DrawTargetRecording(this, mRect
, aFormat
);
684 mRecorder
->RecordEvent(
685 RecordedCreateClippedDrawTarget(this, similarDT
.get(), aBounds
, aFormat
));
686 similarDT
->SetTransform(mTransform
);
690 already_AddRefed
<DrawTarget
>
691 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
692 const IntSize
& aMaxSize
, SurfaceFormat aFormat
, FilterNode
* aFilter
,
693 FilterNode
* aSource
, const Rect
& aSourceRect
, const Point
& aDestPoint
) {
694 RefPtr
<DrawTarget
> similarDT
;
695 if (mFinalDT
->CanCreateSimilarDrawTarget(aMaxSize
, aFormat
)) {
696 similarDT
= new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize
),
698 mRecorder
->RecordEvent(RecordedCreateDrawTargetForFilter(
699 this, similarDT
.get(), aMaxSize
, aFormat
, aFilter
, aSource
, aSourceRect
,
701 } else if (XRE_IsContentProcess()) {
702 // See CreateSimilarDrawTarget
704 "Content-process DrawTargetRecording can't create requested clipped "
707 return similarDT
.forget();
710 already_AddRefed
<PathBuilder
> DrawTargetRecording::CreatePathBuilder(
711 FillRule aFillRule
) const {
712 return MakeAndAddRef
<PathBuilderRecording
>(mFinalDT
->GetBackendType(),
716 already_AddRefed
<GradientStops
> DrawTargetRecording::CreateGradientStops(
717 GradientStop
* aStops
, uint32_t aNumStops
, ExtendMode aExtendMode
) const {
718 RefPtr
<GradientStops
> retStops
= new GradientStopsRecording(mRecorder
);
720 mRecorder
->RecordEvent(
721 RecordedGradientStopsCreation(retStops
, aStops
, aNumStops
, aExtendMode
));
723 return retStops
.forget();
726 void DrawTargetRecording::SetTransform(const Matrix
& aTransform
) {
727 mRecorder
->RecordEvent(RecordedSetTransform(this, aTransform
));
728 DrawTarget::SetTransform(aTransform
);
731 already_AddRefed
<PathRecording
> DrawTargetRecording::EnsurePathStored(
733 RefPtr
<PathRecording
> pathRecording
;
734 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
736 const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
737 if (!mRecorder
->TryAddStoredObject(pathRecording
)) {
738 // Path is already stored.
739 return pathRecording
.forget();
742 MOZ_ASSERT(!mRecorder
->HasStoredObject(aPath
));
743 FillRule fillRule
= aPath
->GetFillRule();
744 RefPtr
<PathBuilderRecording
> builderRecording
=
745 new PathBuilderRecording(mFinalDT
->GetBackendType(), fillRule
);
746 aPath
->StreamToSink(builderRecording
);
747 pathRecording
= builderRecording
->Finish().downcast
<PathRecording
>();
748 mRecorder
->AddStoredObject(pathRecording
);
751 // It's important that AddStoredObject or TryAddStoredObject is called before
752 // this because that will run any pending processing required by recorded
753 // objects that have been deleted off the main thread.
754 mRecorder
->RecordEvent(RecordedPathCreation(pathRecording
.get()));
755 pathRecording
->mStoredRecorders
.push_back(mRecorder
);
757 return pathRecording
.forget();
760 // This should only be called on the 'root' DrawTargetRecording.
761 // Calling it on a child DrawTargetRecordings will cause confusion.
762 void DrawTargetRecording::FlushItem(const IntRect
& aBounds
) {
763 mRecorder
->FlushItem(aBounds
);
764 // Reinitialize the recorder (FlushItem will write a new recording header)
765 // Tell the new recording about our draw target
766 // This code should match what happens in the DrawTargetRecording constructor.
767 mRecorder
->RecordEvent(
768 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
769 mFinalDT
->GetFormat(), false, nullptr));
770 // Add the current transform to the new recording
771 mRecorder
->RecordEvent(
772 RecordedSetTransform(this, DrawTarget::GetTransform()));
775 void DrawTargetRecording::EnsurePatternDependenciesStored(
776 const Pattern
& aPattern
) {
777 switch (aPattern
.GetType()) {
778 case PatternType::COLOR
:
779 // No dependencies here.
781 case PatternType::LINEAR_GRADIENT
: {
783 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
,
784 mRecorder
->HasStoredObject(
785 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
));
788 case PatternType::RADIAL_GRADIENT
: {
790 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
,
791 mRecorder
->HasStoredObject(
792 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
));
795 case PatternType::CONIC_GRADIENT
: {
797 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
,
798 mRecorder
->HasStoredObject(
799 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
));
802 case PatternType::SURFACE
: {
803 const SurfacePattern
* pat
= static_cast<const SurfacePattern
*>(&aPattern
);
804 EnsureSurfaceStoredRecording(mRecorder
, pat
->mSurface
,
805 "EnsurePatternDependenciesStored");
812 } // namespace mozilla