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)));
230 void DrawTargetRecording::Link(const char* aDestination
, const Rect
& aRect
) {
231 mRecorder
->RecordEvent(RecordedLink(this, aDestination
, aRect
));
234 void DrawTargetRecording::Destination(const char* aDestination
,
235 const Point
& aPoint
) {
236 mRecorder
->RecordEvent(RecordedDestination(this, aDestination
, aPoint
));
239 void DrawTargetRecording::FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
240 const DrawOptions
& aOptions
) {
241 EnsurePatternDependenciesStored(aPattern
);
243 mRecorder
->RecordEvent(RecordedFillRect(this, aRect
, aPattern
, aOptions
));
246 void DrawTargetRecording::StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
247 const StrokeOptions
& aStrokeOptions
,
248 const DrawOptions
& aOptions
) {
249 EnsurePatternDependenciesStored(aPattern
);
251 mRecorder
->RecordEvent(
252 RecordedStrokeRect(this, aRect
, aPattern
, aStrokeOptions
, aOptions
));
255 void DrawTargetRecording::StrokeLine(const Point
& aBegin
, const Point
& aEnd
,
256 const Pattern
& aPattern
,
257 const StrokeOptions
& aStrokeOptions
,
258 const DrawOptions
& aOptions
) {
259 EnsurePatternDependenciesStored(aPattern
);
261 mRecorder
->RecordEvent(RecordedStrokeLine(this, aBegin
, aEnd
, aPattern
,
262 aStrokeOptions
, aOptions
));
265 void DrawTargetRecording::Fill(const Path
* aPath
, const Pattern
& aPattern
,
266 const DrawOptions
& aOptions
) {
271 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
272 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
273 auto circle
= path
->AsCircle();
275 EnsurePatternDependenciesStored(aPattern
);
276 mRecorder
->RecordEvent(
277 RecordedFillCircle(this, circle
.value(), aPattern
, aOptions
));
282 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
283 EnsurePatternDependenciesStored(aPattern
);
285 mRecorder
->RecordEvent(RecordedFill(this, pathRecording
, aPattern
, aOptions
));
288 struct RecordingFontUserData
{
291 RefPtr
<DrawEventRecorderPrivate
> recorder
;
294 static void RecordingFontUserDataDestroyFunc(void* aUserData
) {
295 RecordingFontUserData
* userData
=
296 static_cast<RecordingFontUserData
*>(aUserData
);
298 userData
->recorder
->RecordEvent(
299 RecordedScaledFontDestruction(ReferencePtr(userData
->refPtr
)));
300 userData
->recorder
->RemoveScaledFont((ScaledFont
*)userData
->refPtr
);
301 userData
->recorder
->DecrementUnscaledFontRefCount(userData
->unscaledFont
);
305 void DrawTargetRecording::FillGlyphs(ScaledFont
* aFont
,
306 const GlyphBuffer
& aBuffer
,
307 const Pattern
& aPattern
,
308 const DrawOptions
& aOptions
) {
313 EnsurePatternDependenciesStored(aPattern
);
315 UserDataKey
* userDataKey
= reinterpret_cast<UserDataKey
*>(mRecorder
.get());
316 if (mRecorder
->WantsExternalFonts()) {
317 mRecorder
->AddScaledFont(aFont
);
318 } else if (!aFont
->GetUserData(userDataKey
)) {
319 UnscaledFont
* unscaledFont
= aFont
->GetUnscaledFont();
320 if (mRecorder
->IncrementUnscaledFontRefCount(unscaledFont
) == 0) {
321 // Prefer sending the description, if we can create one. This ensures
322 // we don't record the data of system fonts which saves time and can
323 // prevent duplicate copies from accumulating in the OS cache during
325 RecordedFontDescriptor
fontDesc(unscaledFont
);
326 if (fontDesc
.IsValid()) {
327 mRecorder
->RecordEvent(fontDesc
);
329 RecordedFontData
fontData(unscaledFont
);
330 RecordedFontDetails fontDetails
;
331 if (fontData
.GetFontDetails(fontDetails
)) {
332 // Try to serialise the whole font, just in case this is a web font
333 // that is not present on the system.
334 if (!mRecorder
->HasStoredFontData(fontDetails
.fontDataKey
)) {
335 mRecorder
->RecordEvent(fontData
);
336 mRecorder
->AddStoredFontData(fontDetails
.fontDataKey
);
338 mRecorder
->RecordEvent(
339 RecordedUnscaledFontCreation(unscaledFont
, fontDetails
));
341 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
346 mRecorder
->RecordEvent(RecordedScaledFontCreation(aFont
, unscaledFont
));
347 RecordingFontUserData
* userData
= new RecordingFontUserData
;
348 userData
->refPtr
= aFont
;
349 userData
->unscaledFont
= unscaledFont
;
350 userData
->recorder
= mRecorder
;
351 aFont
->AddUserData(userDataKey
, userData
,
352 &RecordingFontUserDataDestroyFunc
);
353 userData
->recorder
->AddScaledFont(aFont
);
356 mRecorder
->RecordEvent(RecordedFillGlyphs(
357 this, aFont
, aPattern
, aOptions
, aBuffer
.mGlyphs
, aBuffer
.mNumGlyphs
));
360 void DrawTargetRecording::Mask(const Pattern
& aSource
, const Pattern
& aMask
,
361 const DrawOptions
& aOptions
) {
362 EnsurePatternDependenciesStored(aSource
);
363 EnsurePatternDependenciesStored(aMask
);
365 mRecorder
->RecordEvent(RecordedMask(this, aSource
, aMask
, aOptions
));
368 void DrawTargetRecording::MaskSurface(const Pattern
& aSource
,
369 SourceSurface
* aMask
, Point aOffset
,
370 const DrawOptions
& aOptions
) {
375 EnsurePatternDependenciesStored(aSource
);
376 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "MaskSurface");
378 mRecorder
->RecordEvent(
379 RecordedMaskSurface(this, aSource
, aMask
, aOffset
, aOptions
));
382 void DrawTargetRecording::Stroke(const Path
* aPath
, const Pattern
& aPattern
,
383 const StrokeOptions
& aStrokeOptions
,
384 const DrawOptions
& aOptions
) {
385 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
386 const PathRecording
* path
= static_cast<const PathRecording
*>(aPath
);
387 auto circle
= path
->AsCircle();
388 if (circle
&& circle
->closed
) {
389 EnsurePatternDependenciesStored(aPattern
);
390 mRecorder
->RecordEvent(RecordedStrokeCircle(
391 this, circle
.value(), aPattern
, aStrokeOptions
, aOptions
));
395 auto line
= path
->AsLine();
397 EnsurePatternDependenciesStored(aPattern
);
398 mRecorder
->RecordEvent(RecordedStrokeLine(this, line
->origin
,
399 line
->destination
, aPattern
,
400 aStrokeOptions
, aOptions
));
405 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
406 EnsurePatternDependenciesStored(aPattern
);
408 mRecorder
->RecordEvent(
409 RecordedStroke(this, pathRecording
, aPattern
, aStrokeOptions
, aOptions
));
412 void DrawTargetRecording::DrawShadow(const Path
* aPath
, const Pattern
& aPattern
,
413 const ShadowOptions
& aShadow
,
414 const DrawOptions
& aOptions
,
415 const StrokeOptions
* aStrokeOptions
) {
416 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
417 EnsurePatternDependenciesStored(aPattern
);
419 mRecorder
->RecordEvent(RecordedDrawShadow(this, pathRecording
, aPattern
,
420 aShadow
, aOptions
, aStrokeOptions
));
423 already_AddRefed
<SourceSurface
> DrawTargetRecording::Snapshot() {
424 RefPtr
<SourceSurface
> retSurf
=
425 new SourceSurfaceRecording(mRect
.Size(), mFormat
, mRecorder
);
427 mRecorder
->RecordEvent(RecordedSnapshot(retSurf
, this));
429 return retSurf
.forget();
432 already_AddRefed
<SourceSurface
> DrawTargetRecording::IntoLuminanceSource(
433 LuminanceType aLuminanceType
, float aOpacity
) {
434 RefPtr
<SourceSurface
> retSurf
=
435 new SourceSurfaceRecording(mRect
.Size(), SurfaceFormat::A8
, mRecorder
);
437 mRecorder
->RecordEvent(
438 RecordedIntoLuminanceSource(retSurf
, this, aLuminanceType
, aOpacity
));
440 return retSurf
.forget();
443 void DrawTargetRecording::Flush() {
444 mRecorder
->RecordEvent(RecordedFlush(this));
447 void DrawTargetRecording::DetachAllSnapshots() {
448 mRecorder
->RecordEvent(RecordedDetachAllSnapshots(this));
451 void DrawTargetRecording::DrawSurface(SourceSurface
* aSurface
,
452 const Rect
& aDest
, const Rect
& aSource
,
453 const DrawSurfaceOptions
& aSurfOptions
,
454 const DrawOptions
& aOptions
) {
459 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurface");
461 mRecorder
->RecordEvent(RecordedDrawSurface(this, aSurface
, aDest
, aSource
,
462 aSurfOptions
, aOptions
));
465 void DrawTargetRecording::DrawDependentSurface(uint64_t aId
,
467 mRecorder
->AddDependentSurface(aId
);
468 mRecorder
->RecordEvent(RecordedDrawDependentSurface(this, aId
, aDest
));
471 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface
* aSurface
,
473 const ShadowOptions
& aShadow
,
479 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurfaceWithShadow");
481 mRecorder
->RecordEvent(
482 RecordedDrawSurfaceWithShadow(this, aSurface
, aDest
, aShadow
, aOp
));
485 void DrawTargetRecording::DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
486 const Point
& aDestPoint
,
487 const DrawOptions
& aOptions
) {
492 MOZ_ASSERT(mRecorder
->HasStoredObject(aNode
));
494 mRecorder
->RecordEvent(
495 RecordedDrawFilter(this, aNode
, aSourceRect
, aDestPoint
, aOptions
));
498 already_AddRefed
<FilterNode
> DrawTargetRecording::CreateFilter(
500 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(mRecorder
);
502 mRecorder
->RecordEvent(RecordedFilterNodeCreation(this, retNode
, aType
));
504 return retNode
.forget();
507 void DrawTargetRecording::ClearRect(const Rect
& aRect
) {
508 mRecorder
->RecordEvent(RecordedClearRect(this, aRect
));
511 void DrawTargetRecording::CopySurface(SourceSurface
* aSurface
,
512 const IntRect
& aSourceRect
,
513 const IntPoint
& aDestination
) {
518 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "CopySurface");
520 mRecorder
->RecordEvent(
521 RecordedCopySurface(this, aSurface
, aSourceRect
, aDestination
));
524 void DrawTargetRecording::PushClip(const Path
* aPath
) {
529 // The canvas doesn't have a clipRect API so we always end up in the generic
530 // path. The D2D backend doesn't have a good way of specializing rectangular
531 // clips so we take advantage of the fact that aPath is usually backed by a
532 // SkiaPath which implements AsRect() and specialize it here.
533 auto rect
= aPath
->AsRect();
535 PushClipRect(rect
.value());
539 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
541 mRecorder
->RecordEvent(RecordedPushClip(this, pathRecording
));
544 void DrawTargetRecording::PushClipRect(const Rect
& aRect
) {
545 mRecorder
->RecordEvent(RecordedPushClipRect(this, aRect
));
548 void DrawTargetRecording::PopClip() {
549 mRecorder
->RecordEvent(RecordedPopClip(static_cast<DrawTarget
*>(this)));
552 void DrawTargetRecording::PushLayer(bool aOpaque
, Float aOpacity
,
553 SourceSurface
* aMask
,
554 const Matrix
& aMaskTransform
,
555 const IntRect
& aBounds
,
556 bool aCopyBackground
) {
558 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
561 mRecorder
->RecordEvent(RecordedPushLayer(this, aOpaque
, aOpacity
, aMask
,
562 aMaskTransform
, aBounds
,
566 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque
, Float aOpacity
,
567 SourceSurface
* aMask
,
568 const Matrix
& aMaskTransform
,
569 const IntRect
& aBounds
,
570 bool aCopyBackground
,
571 CompositionOp aCompositionOp
) {
573 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
576 mRecorder
->RecordEvent(
577 RecordedPushLayerWithBlend(this, aOpaque
, aOpacity
, aMask
, aMaskTransform
,
578 aBounds
, aCopyBackground
, aCompositionOp
));
581 void DrawTargetRecording::PopLayer() {
582 mRecorder
->RecordEvent(RecordedPopLayer(static_cast<DrawTarget
*>(this)));
585 already_AddRefed
<SourceSurface
>
586 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData
,
587 const IntSize
& aSize
,
589 SurfaceFormat aFormat
) const {
590 RefPtr
<SourceSurface
> surface
= CreateDataSourceSurfaceWithStrideFromData(
591 aSize
, aFormat
, aStride
, aData
, aStride
);
596 return OptimizeSourceSurface(surface
);
599 already_AddRefed
<SourceSurface
> DrawTargetRecording::OptimizeSourceSurface(
600 SourceSurface
* aSurface
) const {
601 // See if we have a previously optimized surface available. We have to do this
602 // check before the SurfaceType::RECORDING below, because aSurface might be a
603 // SurfaceType::RECORDING from another recorder we have previously optimized.
604 auto* userData
= static_cast<RecordingSourceSurfaceUserData
*>(
605 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
607 RefPtr
<SourceSurface
> strongRef(userData
->optimizedSurface
);
609 return do_AddRef(strongRef
);
612 if (!EnsureSurfaceStoredRecording(mRecorder
, aSurface
,
613 "OptimizeSourceSurface")) {
614 // Surface was already stored, but doesn't have UserData so must be one
615 // of our recording surfaces.
616 MOZ_ASSERT(aSurface
->GetType() == SurfaceType::RECORDING
);
617 return do_AddRef(aSurface
);
620 userData
= static_cast<RecordingSourceSurfaceUserData
*>(
621 aSurface
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get())));
623 "User data should always have been set by "
624 "EnsureSurfaceStoredRecording.");
627 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(
628 aSurface
->GetSize(), aSurface
->GetFormat(), mRecorder
, aSurface
);
629 mRecorder
->RecordEvent(
630 RecordedOptimizeSourceSurface(aSurface
, this, retSurf
));
631 userData
->optimizedSurface
= retSurf
;
633 return retSurf
.forget();
636 already_AddRefed
<SourceSurface
>
637 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
638 const NativeSurface
& aSurface
) const {
643 already_AddRefed
<DrawTarget
>
644 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
645 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
646 RefPtr
<DrawTarget
> similarDT
;
647 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
648 // If the requested similar draw target is too big, then we should try to
649 // rasterize on the content side to avoid duplicating the effort when a
650 // blob image gets tiled. If we fail somehow to produce it, we can fall
651 // back to recording.
652 constexpr int32_t kRasterThreshold
= 256 * 256 * 4;
653 int32_t stride
= aSize
.width
* BytesPerPixel(aFormat
);
654 int32_t surfaceBytes
= aSize
.height
* stride
;
655 if (surfaceBytes
>= kRasterThreshold
) {
656 auto surface
= MakeRefPtr
<SourceSurfaceSharedData
>();
657 if (surface
->Init(aSize
, stride
, aFormat
)) {
658 auto dt
= MakeRefPtr
<DrawTargetSkia
>();
659 if (dt
->Init(std::move(surface
))) {
662 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
668 return CreateSimilarDrawTarget(aSize
, aFormat
);
671 already_AddRefed
<DrawTarget
> DrawTargetRecording::CreateSimilarDrawTarget(
672 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
673 RefPtr
<DrawTarget
> similarDT
;
674 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
676 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize
), aFormat
);
677 mRecorder
->RecordEvent(
678 RecordedCreateSimilarDrawTarget(this, similarDT
.get(), aSize
, aFormat
));
679 } else if (XRE_IsContentProcess()) {
680 // Crash any content process that calls this function with arguments that
681 // would fail to create a similar draw target. We do this to root out bad
682 // callers. We don't want to crash any important processes though so for
683 // for those we'll just gracefully return nullptr.
685 "Content-process DrawTargetRecording can't create requested similar "
688 return similarDT
.forget();
691 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
692 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
693 return mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
);
696 RefPtr
<DrawTarget
> DrawTargetRecording::CreateClippedDrawTarget(
697 const Rect
& aBounds
, SurfaceFormat aFormat
) {
698 RefPtr
<DrawTarget
> similarDT
;
699 similarDT
= new DrawTargetRecording(this, mRect
, aFormat
);
700 mRecorder
->RecordEvent(
701 RecordedCreateClippedDrawTarget(this, similarDT
.get(), aBounds
, aFormat
));
702 similarDT
->SetTransform(mTransform
);
706 already_AddRefed
<DrawTarget
>
707 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
708 const IntSize
& aMaxSize
, SurfaceFormat aFormat
, FilterNode
* aFilter
,
709 FilterNode
* aSource
, const Rect
& aSourceRect
, const Point
& aDestPoint
) {
710 RefPtr
<DrawTarget
> similarDT
;
711 if (mFinalDT
->CanCreateSimilarDrawTarget(aMaxSize
, aFormat
)) {
712 similarDT
= new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize
),
714 mRecorder
->RecordEvent(RecordedCreateDrawTargetForFilter(
715 this, similarDT
.get(), aMaxSize
, aFormat
, aFilter
, aSource
, aSourceRect
,
717 } else if (XRE_IsContentProcess()) {
718 // See CreateSimilarDrawTarget
720 "Content-process DrawTargetRecording can't create requested clipped "
723 return similarDT
.forget();
726 already_AddRefed
<PathBuilder
> DrawTargetRecording::CreatePathBuilder(
727 FillRule aFillRule
) const {
728 return MakeAndAddRef
<PathBuilderRecording
>(mFinalDT
->GetBackendType(),
732 already_AddRefed
<GradientStops
> DrawTargetRecording::CreateGradientStops(
733 GradientStop
* aStops
, uint32_t aNumStops
, ExtendMode aExtendMode
) const {
734 RefPtr
<GradientStops
> retStops
= new GradientStopsRecording(mRecorder
);
736 mRecorder
->RecordEvent(RecordedGradientStopsCreation(this, retStops
, aStops
,
737 aNumStops
, aExtendMode
));
739 return retStops
.forget();
742 void DrawTargetRecording::SetTransform(const Matrix
& aTransform
) {
743 mRecorder
->RecordEvent(RecordedSetTransform(this, aTransform
));
744 DrawTarget::SetTransform(aTransform
);
747 already_AddRefed
<PathRecording
> DrawTargetRecording::EnsurePathStored(
749 RefPtr
<PathRecording
> pathRecording
;
750 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
752 const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
753 if (!mRecorder
->TryAddStoredObject(pathRecording
)) {
754 // Path is already stored.
755 return pathRecording
.forget();
758 MOZ_ASSERT(!mRecorder
->HasStoredObject(aPath
));
759 FillRule fillRule
= aPath
->GetFillRule();
760 RefPtr
<PathBuilderRecording
> builderRecording
=
761 new PathBuilderRecording(mFinalDT
->GetBackendType(), fillRule
);
762 aPath
->StreamToSink(builderRecording
);
763 pathRecording
= builderRecording
->Finish().downcast
<PathRecording
>();
764 mRecorder
->AddStoredObject(pathRecording
);
767 // It's important that AddStoredObject or TryAddStoredObject is called before
768 // this because that will run any pending processing required by recorded
769 // objects that have been deleted off the main thread.
770 mRecorder
->RecordEvent(RecordedPathCreation(this, pathRecording
.get()));
771 pathRecording
->mStoredRecorders
.push_back(mRecorder
);
773 return pathRecording
.forget();
776 // This should only be called on the 'root' DrawTargetRecording.
777 // Calling it on a child DrawTargetRecordings will cause confusion.
778 void DrawTargetRecording::FlushItem(const IntRect
& aBounds
) {
779 mRecorder
->FlushItem(aBounds
);
780 // Reinitialize the recorder (FlushItem will write a new recording header)
781 // Tell the new recording about our draw target
782 // This code should match what happens in the DrawTargetRecording constructor.
783 mRecorder
->RecordEvent(
784 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
785 mFinalDT
->GetFormat(), false, nullptr));
786 // Add the current transform to the new recording
787 mRecorder
->RecordEvent(
788 RecordedSetTransform(this, DrawTarget::GetTransform()));
791 void DrawTargetRecording::EnsurePatternDependenciesStored(
792 const Pattern
& aPattern
) {
793 switch (aPattern
.GetType()) {
794 case PatternType::COLOR
:
795 // No dependencies here.
797 case PatternType::LINEAR_GRADIENT
: {
799 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
,
800 mRecorder
->HasStoredObject(
801 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
));
804 case PatternType::RADIAL_GRADIENT
: {
806 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
,
807 mRecorder
->HasStoredObject(
808 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
));
811 case PatternType::CONIC_GRADIENT
: {
813 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
,
814 mRecorder
->HasStoredObject(
815 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
));
818 case PatternType::SURFACE
: {
819 const SurfacePattern
* pat
= static_cast<const SurfacePattern
*>(&aPattern
);
820 EnsureSurfaceStoredRecording(mRecorder
, pat
->mSurface
,
821 "EnsurePatternDependenciesStored");
828 } // namespace mozilla