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
;
30 static void RecordingSourceSurfaceUserDataFunc(void* aUserData
) {
31 RecordingSourceSurfaceUserData
* userData
=
32 static_cast<RecordingSourceSurfaceUserData
*>(aUserData
);
34 userData
->recorder
->RecordSourceSurfaceDestruction(
35 static_cast<SourceSurface
*>(userData
->refPtr
));
40 static void EnsureSurfaceStoredRecording(DrawEventRecorderPrivate
* aRecorder
,
41 SourceSurface
* aSurface
,
43 if (aRecorder
->HasStoredObject(aSurface
)) {
47 aRecorder
->StoreSourceSurfaceRecording(aSurface
, reason
);
48 aRecorder
->AddStoredObject(aSurface
);
49 aRecorder
->AddSourceSurface(aSurface
);
51 RecordingSourceSurfaceUserData
* userData
= new RecordingSourceSurfaceUserData
;
52 userData
->refPtr
= aSurface
;
53 userData
->recorder
= aRecorder
;
54 aSurface
->AddUserData(reinterpret_cast<UserDataKey
*>(aRecorder
), userData
,
55 &RecordingSourceSurfaceUserDataFunc
);
58 class SourceSurfaceRecording
: public SourceSurface
{
60 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording
, override
)
62 SourceSurfaceRecording(IntSize aSize
, SurfaceFormat aFormat
,
63 DrawEventRecorderPrivate
* aRecorder
,
64 SourceSurface
* aOriginalSurface
= nullptr)
68 mOriginalSurface(aOriginalSurface
) {
69 mRecorder
->AddStoredObject(this);
72 ~SourceSurfaceRecording() {
73 mRecorder
->RemoveStoredObject(this);
74 mRecorder
->RecordEvent(
75 RecordedSourceSurfaceDestruction(ReferencePtr(this)));
78 SurfaceType
GetType() const override
{ return SurfaceType::RECORDING
; }
79 IntSize
GetSize() const override
{ return mSize
; }
80 SurfaceFormat
GetFormat() const override
{ return mFormat
; }
81 already_AddRefed
<DataSourceSurface
> GetDataSurface() override
{
82 if (mOriginalSurface
) {
83 return mOriginalSurface
->GetDataSurface();
90 SurfaceFormat mFormat
;
91 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
92 // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call
93 // we need GetDataSurface to work, so we hold the original surface we
94 // optimized to return its GetDataSurface.
95 RefPtr
<SourceSurface
> mOriginalSurface
;
98 class GradientStopsRecording
: public GradientStops
{
100 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording
, override
)
102 explicit GradientStopsRecording(DrawEventRecorderPrivate
* aRecorder
)
103 : mRecorder(aRecorder
) {
104 mRecorder
->AddStoredObject(this);
107 virtual ~GradientStopsRecording() {
108 mRecorder
->RemoveStoredObject(this);
109 mRecorder
->RecordEvent(
110 RecordedGradientStopsDestruction(ReferencePtr(this)));
113 BackendType
GetBackendType() const override
{ return BackendType::RECORDING
; }
115 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
118 class FilterNodeRecording
: public FilterNode
{
120 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording
, override
)
121 using FilterNode::SetAttribute
;
123 explicit FilterNodeRecording(DrawEventRecorderPrivate
* aRecorder
)
124 : mRecorder(aRecorder
) {
125 mRecorder
->AddStoredObject(this);
128 virtual ~FilterNodeRecording() {
129 mRecorder
->RemoveStoredObject(this);
130 mRecorder
->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this)));
133 void SetInput(uint32_t aIndex
, SourceSurface
* aSurface
) override
{
134 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "SetInput");
136 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aSurface
));
138 void SetInput(uint32_t aIndex
, FilterNode
* aFilter
) override
{
139 MOZ_ASSERT(mRecorder
->HasStoredObject(aFilter
));
141 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aFilter
));
144 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
145 void SetAttribute(uint32_t aIndex, type aValue) override { \
146 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \
147 this, aIndex, aValue, \
148 RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
151 FORWARD_SET_ATTRIBUTE(bool, BOOL
);
152 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32
);
153 FORWARD_SET_ATTRIBUTE(Float
, FLOAT
);
154 FORWARD_SET_ATTRIBUTE(const Size
&, SIZE
);
155 FORWARD_SET_ATTRIBUTE(const IntSize
&, INTSIZE
);
156 FORWARD_SET_ATTRIBUTE(const IntPoint
&, INTPOINT
);
157 FORWARD_SET_ATTRIBUTE(const Rect
&, RECT
);
158 FORWARD_SET_ATTRIBUTE(const IntRect
&, INTRECT
);
159 FORWARD_SET_ATTRIBUTE(const Point
&, POINT
);
160 FORWARD_SET_ATTRIBUTE(const Matrix
&, MATRIX
);
161 FORWARD_SET_ATTRIBUTE(const Matrix5x4
&, MATRIX5X4
);
162 FORWARD_SET_ATTRIBUTE(const Point3D
&, POINT3D
);
163 FORWARD_SET_ATTRIBUTE(const DeviceColor
&, COLOR
);
165 #undef FORWARD_SET_ATTRIBUTE
167 void SetAttribute(uint32_t aIndex
, const Float
* aFloat
,
168 uint32_t aSize
) override
{
169 mRecorder
->RecordEvent(
170 RecordedFilterNodeSetAttribute(this, aIndex
, aFloat
, aSize
));
173 FilterBackend
GetBackendType() override
{ return FILTER_BACKEND_RECORDING
; }
175 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
178 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder
* aRecorder
,
179 DrawTarget
* aDT
, IntRect aRect
,
181 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
)),
184 RefPtr
<SourceSurface
> snapshot
= aHasData
? mFinalDT
->Snapshot() : nullptr;
185 mRecorder
->RecordEvent(
186 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
187 mFinalDT
->GetFormat(), aHasData
, snapshot
));
188 mFormat
= mFinalDT
->GetFormat();
191 DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording
* aDT
,
192 IntRect aRect
, SurfaceFormat aFormat
)
193 : mRecorder(aDT
->mRecorder
), mFinalDT(aDT
->mFinalDT
), mRect(aRect
) {
197 DrawTargetRecording::~DrawTargetRecording() {
198 mRecorder
->RecordEvent(RecordedDrawTargetDestruction(ReferencePtr(this)));
201 void DrawTargetRecording::Link(const char* aDestination
, const Rect
& aRect
) {
202 mRecorder
->RecordEvent(RecordedLink(this, aDestination
, aRect
));
205 void DrawTargetRecording::Destination(const char* aDestination
,
206 const Point
& aPoint
) {
207 mRecorder
->RecordEvent(RecordedDestination(this, aDestination
, aPoint
));
210 void DrawTargetRecording::FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
211 const DrawOptions
& aOptions
) {
212 EnsurePatternDependenciesStored(aPattern
);
214 mRecorder
->RecordEvent(RecordedFillRect(this, aRect
, aPattern
, aOptions
));
217 void DrawTargetRecording::StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
218 const StrokeOptions
& aStrokeOptions
,
219 const DrawOptions
& aOptions
) {
220 EnsurePatternDependenciesStored(aPattern
);
222 mRecorder
->RecordEvent(
223 RecordedStrokeRect(this, aRect
, aPattern
, aStrokeOptions
, aOptions
));
226 void DrawTargetRecording::StrokeLine(const Point
& aBegin
, const Point
& aEnd
,
227 const Pattern
& aPattern
,
228 const StrokeOptions
& aStrokeOptions
,
229 const DrawOptions
& aOptions
) {
230 EnsurePatternDependenciesStored(aPattern
);
232 mRecorder
->RecordEvent(RecordedStrokeLine(this, aBegin
, aEnd
, aPattern
,
233 aStrokeOptions
, aOptions
));
236 void DrawTargetRecording::Fill(const Path
* aPath
, const Pattern
& aPattern
,
237 const DrawOptions
& aOptions
) {
238 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
239 EnsurePatternDependenciesStored(aPattern
);
241 mRecorder
->RecordEvent(RecordedFill(this, pathRecording
, aPattern
, aOptions
));
244 struct RecordingFontUserData
{
247 RefPtr
<DrawEventRecorderPrivate
> recorder
;
250 static void RecordingFontUserDataDestroyFunc(void* aUserData
) {
251 RecordingFontUserData
* userData
=
252 static_cast<RecordingFontUserData
*>(aUserData
);
254 userData
->recorder
->RecordEvent(
255 RecordedScaledFontDestruction(ReferencePtr(userData
->refPtr
)));
256 userData
->recorder
->RemoveScaledFont((ScaledFont
*)userData
->refPtr
);
257 userData
->recorder
->DecrementUnscaledFontRefCount(userData
->unscaledFont
);
261 void DrawTargetRecording::FillGlyphs(ScaledFont
* aFont
,
262 const GlyphBuffer
& aBuffer
,
263 const Pattern
& aPattern
,
264 const DrawOptions
& aOptions
) {
265 EnsurePatternDependenciesStored(aPattern
);
267 UserDataKey
* userDataKey
= reinterpret_cast<UserDataKey
*>(mRecorder
.get());
268 if (mRecorder
->WantsExternalFonts()) {
269 mRecorder
->AddScaledFont(aFont
);
270 } else if (!aFont
->GetUserData(userDataKey
)) {
271 UnscaledFont
* unscaledFont
= aFont
->GetUnscaledFont();
272 if (mRecorder
->IncrementUnscaledFontRefCount(unscaledFont
) == 0) {
273 // Prefer sending the description, if we can create one. This ensures
274 // we don't record the data of system fonts which saves time and can
275 // prevent duplicate copies from accumulating in the OS cache during
277 RecordedFontDescriptor
fontDesc(unscaledFont
);
278 if (fontDesc
.IsValid()) {
279 mRecorder
->RecordEvent(fontDesc
);
281 RecordedFontData
fontData(unscaledFont
);
282 RecordedFontDetails fontDetails
;
283 if (fontData
.GetFontDetails(fontDetails
)) {
284 // Try to serialise the whole font, just in case this is a web font
285 // that is not present on the system.
286 if (!mRecorder
->HasStoredFontData(fontDetails
.fontDataKey
)) {
287 mRecorder
->RecordEvent(fontData
);
288 mRecorder
->AddStoredFontData(fontDetails
.fontDataKey
);
290 mRecorder
->RecordEvent(
291 RecordedUnscaledFontCreation(unscaledFont
, fontDetails
));
293 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
298 mRecorder
->RecordEvent(RecordedScaledFontCreation(aFont
, unscaledFont
));
299 RecordingFontUserData
* userData
= new RecordingFontUserData
;
300 userData
->refPtr
= aFont
;
301 userData
->unscaledFont
= unscaledFont
;
302 userData
->recorder
= mRecorder
;
303 aFont
->AddUserData(userDataKey
, userData
,
304 &RecordingFontUserDataDestroyFunc
);
305 userData
->recorder
->AddScaledFont(aFont
);
308 mRecorder
->RecordEvent(RecordedFillGlyphs(
309 this, aFont
, aPattern
, aOptions
, aBuffer
.mGlyphs
, aBuffer
.mNumGlyphs
));
312 void DrawTargetRecording::Mask(const Pattern
& aSource
, const Pattern
& aMask
,
313 const DrawOptions
& aOptions
) {
314 EnsurePatternDependenciesStored(aSource
);
315 EnsurePatternDependenciesStored(aMask
);
317 mRecorder
->RecordEvent(RecordedMask(this, aSource
, aMask
, aOptions
));
320 void DrawTargetRecording::MaskSurface(const Pattern
& aSource
,
321 SourceSurface
* aMask
, Point aOffset
,
322 const DrawOptions
& aOptions
) {
323 EnsurePatternDependenciesStored(aSource
);
324 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "MaskSurface");
326 mRecorder
->RecordEvent(
327 RecordedMaskSurface(this, aSource
, aMask
, aOffset
, aOptions
));
330 void DrawTargetRecording::Stroke(const Path
* aPath
, const Pattern
& aPattern
,
331 const StrokeOptions
& aStrokeOptions
,
332 const DrawOptions
& aOptions
) {
333 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
334 EnsurePatternDependenciesStored(aPattern
);
336 mRecorder
->RecordEvent(
337 RecordedStroke(this, pathRecording
, aPattern
, aStrokeOptions
, aOptions
));
340 already_AddRefed
<SourceSurface
> DrawTargetRecording::Snapshot() {
341 RefPtr
<SourceSurface
> retSurf
=
342 new SourceSurfaceRecording(mRect
.Size(), mFormat
, mRecorder
);
344 mRecorder
->RecordEvent(RecordedSnapshot(retSurf
, this));
346 return retSurf
.forget();
349 already_AddRefed
<SourceSurface
> DrawTargetRecording::IntoLuminanceSource(
350 LuminanceType aLuminanceType
, float aOpacity
) {
351 RefPtr
<SourceSurface
> retSurf
=
352 new SourceSurfaceRecording(mRect
.Size(), SurfaceFormat::A8
, mRecorder
);
354 mRecorder
->RecordEvent(
355 RecordedIntoLuminanceSource(retSurf
, this, aLuminanceType
, aOpacity
));
357 return retSurf
.forget();
360 void DrawTargetRecording::Flush() {
361 mRecorder
->RecordEvent(RecordedFlush(this));
364 void DrawTargetRecording::DetachAllSnapshots() {
365 mRecorder
->RecordEvent(RecordedDetachAllSnapshots(this));
368 void DrawTargetRecording::DrawSurface(SourceSurface
* aSurface
,
369 const Rect
& aDest
, const Rect
& aSource
,
370 const DrawSurfaceOptions
& aSurfOptions
,
371 const DrawOptions
& aOptions
) {
372 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurface");
374 mRecorder
->RecordEvent(RecordedDrawSurface(this, aSurface
, aDest
, aSource
,
375 aSurfOptions
, aOptions
));
378 void DrawTargetRecording::DrawDependentSurface(uint64_t aId
,
380 mRecorder
->AddDependentSurface(aId
);
381 mRecorder
->RecordEvent(RecordedDrawDependentSurface(this, aId
, aDest
));
384 void DrawTargetRecording::DrawSurfaceWithShadow(
385 SourceSurface
* aSurface
, const Point
& aDest
, const DeviceColor
& aColor
,
386 const Point
& aOffset
, Float aSigma
, CompositionOp aOp
) {
387 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "DrawSurfaceWithShadow");
389 mRecorder
->RecordEvent(RecordedDrawSurfaceWithShadow(
390 this, aSurface
, aDest
, aColor
, aOffset
, aSigma
, aOp
));
393 void DrawTargetRecording::DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
394 const Point
& aDestPoint
,
395 const DrawOptions
& aOptions
) {
396 MOZ_ASSERT(mRecorder
->HasStoredObject(aNode
));
398 mRecorder
->RecordEvent(
399 RecordedDrawFilter(this, aNode
, aSourceRect
, aDestPoint
, aOptions
));
402 already_AddRefed
<FilterNode
> DrawTargetRecording::CreateFilter(
404 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(mRecorder
);
406 mRecorder
->RecordEvent(RecordedFilterNodeCreation(retNode
, aType
));
408 return retNode
.forget();
411 void DrawTargetRecording::ClearRect(const Rect
& aRect
) {
412 mRecorder
->RecordEvent(RecordedClearRect(this, aRect
));
415 void DrawTargetRecording::CopySurface(SourceSurface
* aSurface
,
416 const IntRect
& aSourceRect
,
417 const IntPoint
& aDestination
) {
418 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "CopySurface");
420 mRecorder
->RecordEvent(
421 RecordedCopySurface(this, aSurface
, aSourceRect
, aDestination
));
424 void DrawTargetRecording::PushClip(const Path
* aPath
) {
425 RefPtr
<PathRecording
> pathRecording
= EnsurePathStored(aPath
);
427 mRecorder
->RecordEvent(RecordedPushClip(this, pathRecording
));
430 void DrawTargetRecording::PushClipRect(const Rect
& aRect
) {
431 mRecorder
->RecordEvent(RecordedPushClipRect(this, aRect
));
434 void DrawTargetRecording::PopClip() {
435 mRecorder
->RecordEvent(RecordedPopClip(static_cast<DrawTarget
*>(this)));
438 void DrawTargetRecording::PushLayer(bool aOpaque
, Float aOpacity
,
439 SourceSurface
* aMask
,
440 const Matrix
& aMaskTransform
,
441 const IntRect
& aBounds
,
442 bool aCopyBackground
) {
444 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
447 mRecorder
->RecordEvent(RecordedPushLayer(this, aOpaque
, aOpacity
, aMask
,
448 aMaskTransform
, aBounds
,
452 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque
, Float aOpacity
,
453 SourceSurface
* aMask
,
454 const Matrix
& aMaskTransform
,
455 const IntRect
& aBounds
,
456 bool aCopyBackground
,
457 CompositionOp aCompositionOp
) {
459 EnsureSurfaceStoredRecording(mRecorder
, aMask
, "PushLayer");
462 mRecorder
->RecordEvent(
463 RecordedPushLayerWithBlend(this, aOpaque
, aOpacity
, aMask
, aMaskTransform
,
464 aBounds
, aCopyBackground
, aCompositionOp
));
467 void DrawTargetRecording::PopLayer() {
468 mRecorder
->RecordEvent(RecordedPopLayer(static_cast<DrawTarget
*>(this)));
471 already_AddRefed
<SourceSurface
>
472 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData
,
473 const IntSize
& aSize
,
475 SurfaceFormat aFormat
) const {
476 RefPtr
<SourceSurface
> surface
= CreateDataSourceSurfaceWithStrideFromData(
477 aSize
, aFormat
, aStride
, aData
, aStride
);
482 return OptimizeSourceSurface(surface
);
485 already_AddRefed
<SourceSurface
> DrawTargetRecording::OptimizeSourceSurface(
486 SourceSurface
* aSurface
) const {
487 if (aSurface
->GetType() == SurfaceType::RECORDING
&&
488 static_cast<SourceSurfaceRecording
*>(aSurface
)->mRecorder
== mRecorder
) {
489 // aSurface is already optimized for our recorder.
490 return do_AddRef(aSurface
);
493 EnsureSurfaceStoredRecording(mRecorder
, aSurface
, "OptimizeSourceSurface");
495 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(
496 aSurface
->GetSize(), aSurface
->GetFormat(), mRecorder
, aSurface
);
498 mRecorder
->RecordEvent(
499 RecordedOptimizeSourceSurface(aSurface
, this, retSurf
));
501 return retSurf
.forget();
504 already_AddRefed
<SourceSurface
>
505 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
506 const NativeSurface
& aSurface
) const {
511 already_AddRefed
<DrawTarget
>
512 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
513 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
514 RefPtr
<DrawTarget
> similarDT
;
515 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
516 // If the requested similar draw target is too big, then we should try to
517 // rasterize on the content side to avoid duplicating the effort when a
518 // blob image gets tiled. If we fail somehow to produce it, we can fall
519 // back to recording.
520 constexpr int32_t kRasterThreshold
= 256 * 256 * 4;
521 int32_t stride
= aSize
.width
* BytesPerPixel(aFormat
);
522 int32_t surfaceBytes
= aSize
.height
* stride
;
523 if (surfaceBytes
>= kRasterThreshold
) {
524 auto surface
= MakeRefPtr
<SourceSurfaceSharedData
>();
525 if (surface
->Init(aSize
, stride
, aFormat
)) {
526 auto dt
= MakeRefPtr
<DrawTargetSkia
>();
527 if (dt
->Init(std::move(surface
))) {
530 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
536 return CreateSimilarDrawTarget(aSize
, aFormat
);
539 already_AddRefed
<DrawTarget
> DrawTargetRecording::CreateSimilarDrawTarget(
540 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
541 RefPtr
<DrawTarget
> similarDT
;
542 if (mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
)) {
544 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize
), aFormat
);
545 mRecorder
->RecordEvent(
546 RecordedCreateSimilarDrawTarget(similarDT
.get(), aSize
, aFormat
));
547 } else if (XRE_IsContentProcess()) {
548 // Crash any content process that calls this function with arguments that
549 // would fail to create a similar draw target. We do this to root out bad
550 // callers. We don't want to crash any important processes though so for
551 // for those we'll just gracefully return nullptr.
553 "Content-process DrawTargetRecording can't create requested similar "
556 return similarDT
.forget();
559 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
560 const IntSize
& aSize
, SurfaceFormat aFormat
) const {
561 return mFinalDT
->CanCreateSimilarDrawTarget(aSize
, aFormat
);
564 RefPtr
<DrawTarget
> DrawTargetRecording::CreateClippedDrawTarget(
565 const Rect
& aBounds
, SurfaceFormat aFormat
) {
566 RefPtr
<DrawTarget
> similarDT
;
567 similarDT
= new DrawTargetRecording(this, mRect
, aFormat
);
568 mRecorder
->RecordEvent(
569 RecordedCreateClippedDrawTarget(this, similarDT
.get(), aBounds
, aFormat
));
570 similarDT
->SetTransform(mTransform
);
574 already_AddRefed
<DrawTarget
>
575 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
576 const IntSize
& aMaxSize
, SurfaceFormat aFormat
, FilterNode
* aFilter
,
577 FilterNode
* aSource
, const Rect
& aSourceRect
, const Point
& aDestPoint
) {
578 RefPtr
<DrawTarget
> similarDT
;
579 if (mFinalDT
->CanCreateSimilarDrawTarget(aMaxSize
, aFormat
)) {
580 similarDT
= new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize
),
582 mRecorder
->RecordEvent(RecordedCreateDrawTargetForFilter(
583 this, similarDT
.get(), aMaxSize
, aFormat
, aFilter
, aSource
, aSourceRect
,
585 } else if (XRE_IsContentProcess()) {
586 // See CreateSimilarDrawTarget
588 "Content-process DrawTargetRecording can't create requested clipped "
591 return similarDT
.forget();
594 already_AddRefed
<PathBuilder
> DrawTargetRecording::CreatePathBuilder(
595 FillRule aFillRule
) const {
596 RefPtr
<PathBuilder
> builder
= mFinalDT
->CreatePathBuilder(aFillRule
);
597 return MakeAndAddRef
<PathBuilderRecording
>(builder
, aFillRule
);
600 already_AddRefed
<GradientStops
> DrawTargetRecording::CreateGradientStops(
601 GradientStop
* aStops
, uint32_t aNumStops
, ExtendMode aExtendMode
) const {
602 RefPtr
<GradientStops
> retStops
= new GradientStopsRecording(mRecorder
);
604 mRecorder
->RecordEvent(
605 RecordedGradientStopsCreation(retStops
, aStops
, aNumStops
, aExtendMode
));
607 return retStops
.forget();
610 void DrawTargetRecording::SetTransform(const Matrix
& aTransform
) {
611 mRecorder
->RecordEvent(RecordedSetTransform(this, aTransform
));
612 DrawTarget::SetTransform(aTransform
);
615 already_AddRefed
<PathRecording
> DrawTargetRecording::EnsurePathStored(
617 RefPtr
<PathRecording
> pathRecording
;
618 if (aPath
->GetBackendType() == BackendType::RECORDING
) {
620 const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
621 if (mRecorder
->HasStoredObject(aPath
)) {
622 return pathRecording
.forget();
625 MOZ_ASSERT(!mRecorder
->HasStoredObject(aPath
));
626 FillRule fillRule
= aPath
->GetFillRule();
627 RefPtr
<PathBuilder
> builder
= mFinalDT
->CreatePathBuilder(fillRule
);
628 RefPtr
<PathBuilderRecording
> builderRecording
=
629 new PathBuilderRecording(builder
, fillRule
);
630 aPath
->StreamToSink(builderRecording
);
631 pathRecording
= builderRecording
->Finish().downcast
<PathRecording
>();
634 mRecorder
->RecordEvent(RecordedPathCreation(pathRecording
.get()));
635 mRecorder
->AddStoredObject(pathRecording
);
636 pathRecording
->mStoredRecorders
.push_back(mRecorder
);
638 return pathRecording
.forget();
641 // This should only be called on the 'root' DrawTargetRecording.
642 // Calling it on a child DrawTargetRecordings will cause confusion.
643 void DrawTargetRecording::FlushItem(const IntRect
& aBounds
) {
644 mRecorder
->FlushItem(aBounds
);
645 // Reinitialize the recorder (FlushItem will write a new recording header)
646 // Tell the new recording about our draw target
647 // This code should match what happens in the DrawTargetRecording constructor.
648 mRecorder
->RecordEvent(
649 RecordedDrawTargetCreation(this, mFinalDT
->GetBackendType(), mRect
,
650 mFinalDT
->GetFormat(), false, nullptr));
651 // Add the current transform to the new recording
652 mRecorder
->RecordEvent(
653 RecordedSetTransform(this, DrawTarget::GetTransform()));
656 void DrawTargetRecording::EnsurePatternDependenciesStored(
657 const Pattern
& aPattern
) {
658 switch (aPattern
.GetType()) {
659 case PatternType::COLOR
:
660 // No dependencies here.
662 case PatternType::LINEAR_GRADIENT
: {
664 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
,
665 mRecorder
->HasStoredObject(
666 static_cast<const LinearGradientPattern
*>(&aPattern
)->mStops
));
669 case PatternType::RADIAL_GRADIENT
: {
671 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
,
672 mRecorder
->HasStoredObject(
673 static_cast<const RadialGradientPattern
*>(&aPattern
)->mStops
));
676 case PatternType::CONIC_GRADIENT
: {
678 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
,
679 mRecorder
->HasStoredObject(
680 static_cast<const ConicGradientPattern
*>(&aPattern
)->mStops
));
683 case PatternType::SURFACE
: {
684 const SurfacePattern
* pat
= static_cast<const SurfacePattern
*>(&aPattern
);
685 EnsureSurfaceStoredRecording(mRecorder
, pat
->mSurface
,
686 "EnsurePatternDependenciesStored");
693 } // namespace mozilla