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