Backed out changeset 28c56a4f3af6 (bug 1874810) for causing Moz2DImageRenderer relate...
[gecko.git] / gfx / 2d / DrawTargetRecording.cpp
blob6e7a3dc54b688096eb7079b984dca6598a30332c
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"
10 #include <stdio.h>
12 #include "Logging.h"
13 #include "Tools.h"
14 #include "Filters.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"
24 namespace mozilla {
25 namespace gfx {
27 struct RecordingSourceSurfaceUserData {
28 void* refPtr;
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);
42 delete userData;
43 return;
46 userData->recorder->AddPendingDeletion([userData]() -> void {
47 userData->recorder->RecordSourceSurfaceDestruction(userData->refPtr);
48 delete userData;
49 });
52 static bool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate* aRecorder,
53 SourceSurface* aSurface,
54 const char* reason) {
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.
60 return false;
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);
70 return true;
73 class SourceSurfaceRecording : public SourceSurface {
74 public:
75 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording, override)
77 SourceSurfaceRecording(IntSize aSize, SurfaceFormat aFormat,
78 DrawEventRecorderPrivate* aRecorder,
79 SourceSurface* aOriginalSurface = nullptr)
80 : mSize(aSize),
81 mFormat(aFormat),
82 mRecorder(aRecorder),
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();
101 return nullptr;
104 IntSize mSize;
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 {
114 public:
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 {
134 public:
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)),
198 mFinalDT(aDT),
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,
208 bool aHasData)
209 : mRecorder(static_cast<DrawEventRecorderPrivate*>(aRecorder)),
210 mFinalDT(aDT),
211 mRect(aRect) {
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) {
223 mFormat = aFormat;
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) {
268 if (!aPath) {
269 return;
272 if (aPath->GetBackendType() == BackendType::RECORDING) {
273 const PathRecording* path = static_cast<const PathRecording*>(aPath);
274 auto circle = path->AsCircle();
275 if (circle) {
276 EnsurePatternDependenciesStored(aPattern);
277 mRecorder->RecordEvent(
278 this, RecordedFillCircle(circle.value(), aPattern, aOptions));
279 return;
283 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
284 EnsurePatternDependenciesStored(aPattern);
286 mRecorder->RecordEvent(this, RecordedFill(pathRecording, aPattern, aOptions));
289 struct RecordingFontUserData {
290 void* refPtr;
291 void* unscaledFont;
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);
303 delete userData;
306 void DrawTargetRecording::FillGlyphs(ScaledFont* aFont,
307 const GlyphBuffer& aBuffer,
308 const Pattern& aPattern,
309 const DrawOptions& aOptions) {
310 if (!aFont) {
311 return;
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
325 // playback.
326 RecordedFontDescriptor fontDesc(unscaledFont);
327 if (fontDesc.IsValid()) {
328 mRecorder->RecordEvent(fontDesc);
329 } else {
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));
341 } else {
342 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
343 "UnscaledFont";
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) {
373 if (!aMask) {
374 return;
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,
394 aOptions));
395 return;
398 auto line = path->AsLine();
399 if (line) {
400 EnsurePatternDependenciesStored(aPattern);
401 mRecorder->RecordEvent(
402 this, RecordedStrokeLine(line->origin, line->destination, aPattern,
403 aStrokeOptions, aOptions));
404 return;
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,
424 aStrokeOptions));
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) {
459 if (!aSurface) {
460 return;
463 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurface");
465 mRecorder->RecordEvent(this, RecordedDrawSurface(aSurface, aDest, aSource,
466 aSurfOptions, aOptions));
469 void DrawTargetRecording::DrawDependentSurface(uint64_t aId,
470 const Rect& aDest) {
471 mRecorder->AddDependentSurface(aId);
472 mRecorder->RecordEvent(this, RecordedDrawDependentSurface(aId, aDest));
475 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface* aSurface,
476 const Point& aDest,
477 const ShadowOptions& aShadow,
478 CompositionOp aOp) {
479 if (!aSurface) {
480 return;
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) {
492 if (!aNode) {
493 return;
496 MOZ_ASSERT(mRecorder->HasStoredObject(aNode));
498 mRecorder->RecordEvent(
499 this, RecordedDrawFilter(aNode, aSourceRect, aDestPoint, aOptions));
502 already_AddRefed<FilterNode> DrawTargetRecording::CreateFilter(
503 FilterType aType) {
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) {
518 if (!aSurface) {
519 return;
522 EnsureSurfaceStoredRecording(mRecorder, aSurface, "CopySurface");
524 mRecorder->RecordEvent(
525 this, RecordedCopySurface(aSurface, aSourceRect, aDestination));
528 void DrawTargetRecording::PushClip(const Path* aPath) {
529 if (!aPath) {
530 return;
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();
538 if (rect.isSome()) {
539 PushClipRect(rect.value());
540 return;
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) {
561 if (aMask) {
562 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer");
565 mRecorder->RecordEvent(
566 this, RecordedPushLayer(aOpaque, aOpacity, aMask, aMaskTransform, aBounds,
567 aCopyBackground));
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) {
576 if (aMask) {
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,
592 int32_t aStride,
593 SurfaceFormat aFormat) const {
594 RefPtr<SourceSurface> surface = CreateDataSourceSurfaceWithStrideFromData(
595 aSize, aFormat, aStride, aData, aStride);
596 if (!surface) {
597 return nullptr;
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())));
610 if (userData) {
611 RefPtr<SourceSurface> strongRef(userData->optimizedSurface);
612 if (strongRef) {
613 return do_AddRef(strongRef);
615 } else {
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())));
626 MOZ_ASSERT(userData,
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 {
643 MOZ_ASSERT(false);
644 return nullptr;
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))) {
664 return dt.forget();
665 } else {
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)) {
679 similarDT =
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.
689 MOZ_CRASH(
690 "Content-process DrawTargetRecording can't create requested similar "
691 "drawtarget");
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);
708 return similarDT;
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),
718 aFormat);
719 mRecorder->RecordEvent(
720 this, RecordedCreateDrawTargetForFilter(similarDT.get(), aMaxSize,
721 aFormat, aFilter, aSource,
722 aSourceRect, aDestPoint));
723 } else if (XRE_IsContentProcess()) {
724 // See CreateSimilarDrawTarget
725 MOZ_CRASH(
726 "Content-process DrawTargetRecording can't create requested clipped "
727 "drawtarget");
729 return similarDT.forget();
732 already_AddRefed<PathBuilder> DrawTargetRecording::CreatePathBuilder(
733 FillRule aFillRule) const {
734 return MakeAndAddRef<PathBuilderRecording>(mFinalDT->GetBackendType(),
735 aFillRule);
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)) {
751 return;
753 DrawTarget::SetTransform(aTransform);
754 mRecorder->RecordEvent(this, RecordedSetTransform(aTransform));
757 already_AddRefed<PathRecording> DrawTargetRecording::EnsurePathStored(
758 const Path* aPath) {
759 RefPtr<PathRecording> pathRecording;
760 if (aPath->GetBackendType() == BackendType::RECORDING) {
761 pathRecording =
762 const_cast<PathRecording*>(static_cast<const PathRecording*>(aPath));
763 if (!mRecorder->TryAddStoredObject(pathRecording)) {
764 // Path is already stored.
765 return pathRecording.forget();
767 } else {
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.
807 return;
808 case PatternType::LINEAR_GRADIENT: {
809 MOZ_ASSERT_IF(
810 static_cast<const LinearGradientPattern*>(&aPattern)->mStops,
811 mRecorder->HasStoredObject(
812 static_cast<const LinearGradientPattern*>(&aPattern)->mStops));
813 return;
815 case PatternType::RADIAL_GRADIENT: {
816 MOZ_ASSERT_IF(
817 static_cast<const RadialGradientPattern*>(&aPattern)->mStops,
818 mRecorder->HasStoredObject(
819 static_cast<const RadialGradientPattern*>(&aPattern)->mStops));
820 return;
822 case PatternType::CONIC_GRADIENT: {
823 MOZ_ASSERT_IF(
824 static_cast<const ConicGradientPattern*>(&aPattern)->mStops,
825 mRecorder->HasStoredObject(
826 static_cast<const ConicGradientPattern*>(&aPattern)->mStops));
827 return;
829 case PatternType::SURFACE: {
830 const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aPattern);
831 EnsureSurfaceStoredRecording(mRecorder, pat->mSurface,
832 "EnsurePatternDependenciesStored");
833 return;
838 } // namespace gfx
839 } // namespace mozilla