Bug 1869043 add a main thread record of track audio outputs r=padenot
[gecko.git] / gfx / 2d / DrawTargetRecording.cpp
blob744257bc9936bf3d0552bd5b2af4319a7990c5ed
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)));
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) {
267 if (!aPath) {
268 return;
271 if (aPath->GetBackendType() == BackendType::RECORDING) {
272 const PathRecording* path = static_cast<const PathRecording*>(aPath);
273 auto circle = path->AsCircle();
274 if (circle) {
275 EnsurePatternDependenciesStored(aPattern);
276 mRecorder->RecordEvent(
277 RecordedFillCircle(this, circle.value(), aPattern, aOptions));
278 return;
282 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
283 EnsurePatternDependenciesStored(aPattern);
285 mRecorder->RecordEvent(RecordedFill(this, pathRecording, aPattern, aOptions));
288 struct RecordingFontUserData {
289 void* refPtr;
290 void* unscaledFont;
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);
302 delete userData;
305 void DrawTargetRecording::FillGlyphs(ScaledFont* aFont,
306 const GlyphBuffer& aBuffer,
307 const Pattern& aPattern,
308 const DrawOptions& aOptions) {
309 if (!aFont) {
310 return;
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
324 // playback.
325 RecordedFontDescriptor fontDesc(unscaledFont);
326 if (fontDesc.IsValid()) {
327 mRecorder->RecordEvent(fontDesc);
328 } else {
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));
340 } else {
341 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
342 "UnscaledFont";
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) {
371 if (!aMask) {
372 return;
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));
392 return;
395 auto line = path->AsLine();
396 if (line) {
397 EnsurePatternDependenciesStored(aPattern);
398 mRecorder->RecordEvent(RecordedStrokeLine(this, line->origin,
399 line->destination, aPattern,
400 aStrokeOptions, aOptions));
401 return;
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) {
455 if (!aSurface) {
456 return;
459 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurface");
461 mRecorder->RecordEvent(RecordedDrawSurface(this, aSurface, aDest, aSource,
462 aSurfOptions, aOptions));
465 void DrawTargetRecording::DrawDependentSurface(uint64_t aId,
466 const Rect& aDest) {
467 mRecorder->AddDependentSurface(aId);
468 mRecorder->RecordEvent(RecordedDrawDependentSurface(this, aId, aDest));
471 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface* aSurface,
472 const Point& aDest,
473 const ShadowOptions& aShadow,
474 CompositionOp aOp) {
475 if (!aSurface) {
476 return;
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) {
488 if (!aNode) {
489 return;
492 MOZ_ASSERT(mRecorder->HasStoredObject(aNode));
494 mRecorder->RecordEvent(
495 RecordedDrawFilter(this, aNode, aSourceRect, aDestPoint, aOptions));
498 already_AddRefed<FilterNode> DrawTargetRecording::CreateFilter(
499 FilterType aType) {
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) {
514 if (!aSurface) {
515 return;
518 EnsureSurfaceStoredRecording(mRecorder, aSurface, "CopySurface");
520 mRecorder->RecordEvent(
521 RecordedCopySurface(this, aSurface, aSourceRect, aDestination));
524 void DrawTargetRecording::PushClip(const Path* aPath) {
525 if (!aPath) {
526 return;
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();
534 if (rect.isSome()) {
535 PushClipRect(rect.value());
536 return;
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) {
557 if (aMask) {
558 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer");
561 mRecorder->RecordEvent(RecordedPushLayer(this, aOpaque, aOpacity, aMask,
562 aMaskTransform, aBounds,
563 aCopyBackground));
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) {
572 if (aMask) {
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,
588 int32_t aStride,
589 SurfaceFormat aFormat) const {
590 RefPtr<SourceSurface> surface = CreateDataSourceSurfaceWithStrideFromData(
591 aSize, aFormat, aStride, aData, aStride);
592 if (!surface) {
593 return nullptr;
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())));
606 if (userData) {
607 RefPtr<SourceSurface> strongRef(userData->optimizedSurface);
608 if (strongRef) {
609 return do_AddRef(strongRef);
611 } else {
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())));
622 MOZ_ASSERT(userData,
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 {
639 MOZ_ASSERT(false);
640 return nullptr;
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))) {
660 return dt.forget();
661 } else {
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)) {
675 similarDT =
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.
684 MOZ_CRASH(
685 "Content-process DrawTargetRecording can't create requested similar "
686 "drawtarget");
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);
703 return similarDT;
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),
713 aFormat);
714 mRecorder->RecordEvent(RecordedCreateDrawTargetForFilter(
715 this, similarDT.get(), aMaxSize, aFormat, aFilter, aSource, aSourceRect,
716 aDestPoint));
717 } else if (XRE_IsContentProcess()) {
718 // See CreateSimilarDrawTarget
719 MOZ_CRASH(
720 "Content-process DrawTargetRecording can't create requested clipped "
721 "drawtarget");
723 return similarDT.forget();
726 already_AddRefed<PathBuilder> DrawTargetRecording::CreatePathBuilder(
727 FillRule aFillRule) const {
728 return MakeAndAddRef<PathBuilderRecording>(mFinalDT->GetBackendType(),
729 aFillRule);
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(
748 const Path* aPath) {
749 RefPtr<PathRecording> pathRecording;
750 if (aPath->GetBackendType() == BackendType::RECORDING) {
751 pathRecording =
752 const_cast<PathRecording*>(static_cast<const PathRecording*>(aPath));
753 if (!mRecorder->TryAddStoredObject(pathRecording)) {
754 // Path is already stored.
755 return pathRecording.forget();
757 } else {
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.
796 return;
797 case PatternType::LINEAR_GRADIENT: {
798 MOZ_ASSERT_IF(
799 static_cast<const LinearGradientPattern*>(&aPattern)->mStops,
800 mRecorder->HasStoredObject(
801 static_cast<const LinearGradientPattern*>(&aPattern)->mStops));
802 return;
804 case PatternType::RADIAL_GRADIENT: {
805 MOZ_ASSERT_IF(
806 static_cast<const RadialGradientPattern*>(&aPattern)->mStops,
807 mRecorder->HasStoredObject(
808 static_cast<const RadialGradientPattern*>(&aPattern)->mStops));
809 return;
811 case PatternType::CONIC_GRADIENT: {
812 MOZ_ASSERT_IF(
813 static_cast<const ConicGradientPattern*>(&aPattern)->mStops,
814 mRecorder->HasStoredObject(
815 static_cast<const ConicGradientPattern*>(&aPattern)->mStops));
816 return;
818 case PatternType::SURFACE: {
819 const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aPattern);
820 EnsureSurfaceStoredRecording(mRecorder, pat->mSurface,
821 "EnsurePatternDependenciesStored");
822 return;
827 } // namespace gfx
828 } // namespace mozilla