Update configs. IGNORE BROKEN CHANGESETS CLOSED TREE NO BUG a=release ba=release
[gecko.git] / gfx / 2d / DrawTargetRecording.cpp
blobcdabb80ecdec1bf4da0685fb8f6e99179821f399
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 "ImageContainer.h"
13 #include "Logging.h"
14 #include "Tools.h"
15 #include "Filters.h"
16 #include "mozilla/gfx/DataSurfaceHelpers.h"
17 #include "mozilla/layers/CanvasDrawEventRecorder.h"
18 #include "mozilla/layers/RecordedCanvasEventImpl.h"
19 #include "mozilla/layers/SourceSurfaceSharedData.h"
20 #include "mozilla/UniquePtr.h"
21 #include "nsXULAppAPI.h" // for XRE_IsContentProcess()
22 #include "RecordingTypes.h"
23 #include "RecordedEventImpl.h"
25 namespace mozilla {
26 namespace gfx {
28 struct RecordingSourceSurfaceUserData {
29 void* refPtr;
30 RefPtr<DrawEventRecorderPrivate> recorder;
32 // The optimized surface holds a reference to our surface, for GetDataSurface
33 // calls, so we must hold a weak reference to avoid circular dependency.
34 ThreadSafeWeakPtr<SourceSurface> optimizedSurface;
37 static void RecordingSourceSurfaceUserDataFunc(void* aUserData) {
38 RecordingSourceSurfaceUserData* userData =
39 static_cast<RecordingSourceSurfaceUserData*>(aUserData);
41 if (NS_IsMainThread()) {
42 userData->recorder->RecordSourceSurfaceDestruction(userData->refPtr);
43 delete userData;
44 return;
47 userData->recorder->AddPendingDeletion([userData]() -> void {
48 userData->recorder->RecordSourceSurfaceDestruction(userData->refPtr);
49 delete userData;
50 });
53 static bool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate* aRecorder,
54 SourceSurface* aSurface,
55 const char* reason) {
56 // It's important that TryAddStoredObject is called first because that will
57 // run any pending processing required by recorded objects that have been
58 // deleted off the main thread.
59 if (!aRecorder->TryAddStoredObject(aSurface)) {
60 // Surface is already stored.
61 return false;
63 aRecorder->StoreSourceSurfaceRecording(aSurface, reason);
64 aRecorder->AddSourceSurface(aSurface);
66 RecordingSourceSurfaceUserData* userData = new RecordingSourceSurfaceUserData;
67 userData->refPtr = aSurface;
68 userData->recorder = aRecorder;
69 aSurface->AddUserData(reinterpret_cast<UserDataKey*>(aRecorder), userData,
70 &RecordingSourceSurfaceUserDataFunc);
71 return true;
74 class SourceSurfaceRecording : public SourceSurface {
75 public:
76 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording, override)
78 SourceSurfaceRecording(IntSize aSize, SurfaceFormat aFormat,
79 DrawEventRecorderPrivate* aRecorder,
80 SourceSurface* aOriginalSurface = nullptr)
81 : mSize(aSize),
82 mFormat(aFormat),
83 mRecorder(aRecorder),
84 mOriginalSurface(aOriginalSurface) {
85 mRecorder->AddStoredObject(this);
88 ~SourceSurfaceRecording() {
89 mRecorder->RemoveStoredObject(this);
90 mRecorder->RecordEvent(
91 RecordedSourceSurfaceDestruction(ReferencePtr(this)));
94 SurfaceType GetType() const override { return SurfaceType::RECORDING; }
95 IntSize GetSize() const override { return mSize; }
96 SurfaceFormat GetFormat() const override { return mFormat; }
97 already_AddRefed<DataSourceSurface> GetDataSurface() override {
98 if (mOriginalSurface) {
99 return mOriginalSurface->GetDataSurface();
102 return nullptr;
105 already_AddRefed<SourceSurface> ExtractSubrect(const IntRect& aRect) override;
107 IntSize mSize;
108 SurfaceFormat mFormat;
109 RefPtr<DrawEventRecorderPrivate> mRecorder;
110 // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call
111 // we need GetDataSurface to work, so we hold the original surface we
112 // optimized to return its GetDataSurface.
113 RefPtr<SourceSurface> mOriginalSurface;
116 class GradientStopsRecording : public GradientStops {
117 public:
118 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording, override)
120 explicit GradientStopsRecording(DrawEventRecorderPrivate* aRecorder)
121 : mRecorder(aRecorder) {
122 mRecorder->AddStoredObject(this);
125 virtual ~GradientStopsRecording() {
126 mRecorder->RemoveStoredObject(this);
127 mRecorder->RecordEvent(
128 RecordedGradientStopsDestruction(ReferencePtr(this)));
131 BackendType GetBackendType() const override { return BackendType::RECORDING; }
133 RefPtr<DrawEventRecorderPrivate> mRecorder;
136 class FilterNodeRecording : public FilterNode {
137 public:
138 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording, override)
139 using FilterNode::SetAttribute;
141 explicit FilterNodeRecording(DrawEventRecorderPrivate* aRecorder)
142 : mRecorder(aRecorder) {
143 mRecorder->AddStoredObject(this);
146 virtual ~FilterNodeRecording() {
147 mRecorder->RemoveStoredObject(this);
148 mRecorder->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this)));
151 void SetInput(uint32_t aIndex, SourceSurface* aSurface) override {
152 EnsureSurfaceStoredRecording(mRecorder, aSurface, "SetInput");
154 mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aSurface));
156 void SetInput(uint32_t aIndex, FilterNode* aFilter) override {
157 MOZ_ASSERT(mRecorder->HasStoredObject(aFilter));
159 mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aFilter));
162 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
163 void SetAttribute(uint32_t aIndex, type aValue) override { \
164 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \
165 this, aIndex, aValue, \
166 RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
169 FORWARD_SET_ATTRIBUTE(bool, BOOL);
170 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32);
171 FORWARD_SET_ATTRIBUTE(Float, FLOAT);
172 FORWARD_SET_ATTRIBUTE(const Size&, SIZE);
173 FORWARD_SET_ATTRIBUTE(const IntSize&, INTSIZE);
174 FORWARD_SET_ATTRIBUTE(const IntPoint&, INTPOINT);
175 FORWARD_SET_ATTRIBUTE(const Rect&, RECT);
176 FORWARD_SET_ATTRIBUTE(const IntRect&, INTRECT);
177 FORWARD_SET_ATTRIBUTE(const Point&, POINT);
178 FORWARD_SET_ATTRIBUTE(const Matrix&, MATRIX);
179 FORWARD_SET_ATTRIBUTE(const Matrix5x4&, MATRIX5X4);
180 FORWARD_SET_ATTRIBUTE(const Point3D&, POINT3D);
181 FORWARD_SET_ATTRIBUTE(const DeviceColor&, COLOR);
183 #undef FORWARD_SET_ATTRIBUTE
185 void SetAttribute(uint32_t aIndex, const Float* aFloat,
186 uint32_t aSize) override {
187 mRecorder->RecordEvent(
188 RecordedFilterNodeSetAttribute(this, aIndex, aFloat, aSize));
191 FilterBackend GetBackendType() override { return FILTER_BACKEND_RECORDING; }
193 RefPtr<DrawEventRecorderPrivate> mRecorder;
196 DrawTargetRecording::DrawTargetRecording(
197 layers::CanvasDrawEventRecorder* aRecorder, int64_t aTextureId,
198 const layers::RemoteTextureOwnerId& aTextureOwnerId, DrawTarget* aDT,
199 const IntSize& aSize)
200 : mRecorder(static_cast<DrawEventRecorderPrivate*>(aRecorder)),
201 mFinalDT(aDT),
202 mRect(IntPoint(0, 0), aSize) {
203 RecordEventSkipFlushTransform(layers::RecordedCanvasDrawTargetCreation(
204 this, aTextureId, aTextureOwnerId, mFinalDT->GetBackendType(), aSize,
205 mFinalDT->GetFormat()));
206 mFormat = mFinalDT->GetFormat();
207 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat));
210 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder* aRecorder,
211 DrawTarget* aDT, IntRect aRect,
212 bool aHasData)
213 : mRecorder(static_cast<DrawEventRecorderPrivate*>(aRecorder)),
214 mFinalDT(aDT),
215 mRect(aRect) {
216 MOZ_DIAGNOSTIC_ASSERT(aRecorder->GetRecorderType() != RecorderType::CANVAS);
217 RefPtr<SourceSurface> snapshot = aHasData ? mFinalDT->Snapshot() : nullptr;
218 RecordEventSkipFlushTransform(
219 RecordedDrawTargetCreation(this, mFinalDT->GetBackendType(), mRect,
220 mFinalDT->GetFormat(), aHasData, snapshot));
221 mFormat = mFinalDT->GetFormat();
222 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat));
225 DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording* aDT,
226 IntRect aRect, SurfaceFormat aFormat)
227 : mRecorder(aDT->mRecorder), mFinalDT(aDT->mFinalDT), mRect(aRect) {
228 mFormat = aFormat;
229 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat));
232 DrawTargetRecording::~DrawTargetRecording() {
233 RecordEventSkipFlushTransform(
234 RecordedDrawTargetDestruction(ReferencePtr(this)));
235 mRecorder->ClearDrawTarget(this);
238 void DrawTargetRecording::Link(const char* aDestination, const Rect& aRect) {
239 MarkChanged();
241 RecordEventSelf(RecordedLink(aDestination, aRect));
244 void DrawTargetRecording::Destination(const char* aDestination,
245 const Point& aPoint) {
246 MarkChanged();
248 RecordEventSelf(RecordedDestination(aDestination, aPoint));
251 void DrawTargetRecording::FillRect(const Rect& aRect, const Pattern& aPattern,
252 const DrawOptions& aOptions) {
253 MarkChanged();
255 EnsurePatternDependenciesStored(aPattern);
257 RecordEventSelf(RecordedFillRect(aRect, aPattern, aOptions));
260 void DrawTargetRecording::StrokeRect(const Rect& aRect, const Pattern& aPattern,
261 const StrokeOptions& aStrokeOptions,
262 const DrawOptions& aOptions) {
263 MarkChanged();
265 EnsurePatternDependenciesStored(aPattern);
267 RecordEventSelf(
268 RecordedStrokeRect(aRect, aPattern, aStrokeOptions, aOptions));
271 void DrawTargetRecording::StrokeLine(const Point& aBegin, const Point& aEnd,
272 const Pattern& aPattern,
273 const StrokeOptions& aStrokeOptions,
274 const DrawOptions& aOptions) {
275 MarkChanged();
277 EnsurePatternDependenciesStored(aPattern);
279 RecordEventSelf(
280 RecordedStrokeLine(aBegin, aEnd, aPattern, aStrokeOptions, aOptions));
283 void DrawTargetRecording::Fill(const Path* aPath, const Pattern& aPattern,
284 const DrawOptions& aOptions) {
285 if (!aPath) {
286 return;
289 MarkChanged();
291 if (aPath->GetBackendType() == BackendType::RECORDING) {
292 const PathRecording* path = static_cast<const PathRecording*>(aPath);
293 auto circle = path->AsCircle();
294 if (circle) {
295 EnsurePatternDependenciesStored(aPattern);
296 RecordEventSelf(RecordedFillCircle(circle.value(), aPattern, aOptions));
297 return;
301 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
302 EnsurePatternDependenciesStored(aPattern);
303 RecordEventSelf(RecordedFill(pathRecording, aPattern, aOptions));
306 struct RecordingFontUserData {
307 void* refPtr;
308 void* unscaledFont;
309 RefPtr<DrawEventRecorderPrivate> recorder;
312 static void RecordingFontUserDataDestroyFunc(void* aUserData) {
313 RecordingFontUserData* userData =
314 static_cast<RecordingFontUserData*>(aUserData);
316 userData->recorder->RecordEvent(
317 RecordedScaledFontDestruction(ReferencePtr(userData->refPtr)));
318 userData->recorder->RemoveScaledFont((ScaledFont*)userData->refPtr);
319 userData->recorder->DecrementUnscaledFontRefCount(userData->unscaledFont);
320 delete userData;
323 void DrawTargetRecording::DrawGlyphs(ScaledFont* aFont,
324 const GlyphBuffer& aBuffer,
325 const Pattern& aPattern,
326 const DrawOptions& aOptions,
327 const StrokeOptions* aStrokeOptions) {
328 if (!aFont) {
329 return;
332 MarkChanged();
334 EnsurePatternDependenciesStored(aPattern);
336 UserDataKey* userDataKey = reinterpret_cast<UserDataKey*>(mRecorder.get());
337 if (mRecorder->WantsExternalFonts()) {
338 mRecorder->AddScaledFont(aFont);
339 } else if (!aFont->GetUserData(userDataKey)) {
340 UnscaledFont* unscaledFont = aFont->GetUnscaledFont();
341 if (mRecorder->IncrementUnscaledFontRefCount(unscaledFont) == 0) {
342 // Prefer sending the description, if we can create one. This ensures
343 // we don't record the data of system fonts which saves time and can
344 // prevent duplicate copies from accumulating in the OS cache during
345 // playback.
346 RecordedFontDescriptor fontDesc(unscaledFont);
347 if (fontDesc.IsValid()) {
348 RecordEventSkipFlushTransform(fontDesc);
349 } else {
350 RecordedFontData fontData(unscaledFont);
351 RecordedFontDetails fontDetails;
352 if (fontData.GetFontDetails(fontDetails)) {
353 // Try to serialise the whole font, just in case this is a web font
354 // that is not present on the system.
355 if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) {
356 RecordEventSkipFlushTransform(fontData);
357 mRecorder->AddStoredFontData(fontDetails.fontDataKey);
359 RecordEventSkipFlushTransform(
360 RecordedUnscaledFontCreation(unscaledFont, fontDetails));
361 } else {
362 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise "
363 "UnscaledFont";
367 RecordEventSkipFlushTransform(
368 RecordedScaledFontCreation(aFont, unscaledFont));
369 RecordingFontUserData* userData = new RecordingFontUserData;
370 userData->refPtr = aFont;
371 userData->unscaledFont = unscaledFont;
372 userData->recorder = mRecorder;
373 aFont->AddUserData(userDataKey, userData,
374 &RecordingFontUserDataDestroyFunc);
375 userData->recorder->AddScaledFont(aFont);
378 if (aStrokeOptions) {
379 RecordEventSelf(RecordedStrokeGlyphs(aFont, aPattern, *aStrokeOptions,
380 aOptions, aBuffer.mGlyphs,
381 aBuffer.mNumGlyphs));
382 } else {
383 RecordEventSelf(RecordedFillGlyphs(aFont, aPattern, aOptions,
384 aBuffer.mGlyphs, aBuffer.mNumGlyphs));
388 void DrawTargetRecording::FillGlyphs(ScaledFont* aFont,
389 const GlyphBuffer& aBuffer,
390 const Pattern& aPattern,
391 const DrawOptions& aOptions) {
392 DrawGlyphs(aFont, aBuffer, aPattern, aOptions);
395 void DrawTargetRecording::StrokeGlyphs(ScaledFont* aFont,
396 const GlyphBuffer& aBuffer,
397 const Pattern& aPattern,
398 const StrokeOptions& aStrokeOptions,
399 const DrawOptions& aOptions) {
400 DrawGlyphs(aFont, aBuffer, aPattern, aOptions, &aStrokeOptions);
403 void DrawTargetRecording::Mask(const Pattern& aSource, const Pattern& aMask,
404 const DrawOptions& aOptions) {
405 MarkChanged();
407 EnsurePatternDependenciesStored(aSource);
408 EnsurePatternDependenciesStored(aMask);
410 RecordEventSelf(RecordedMask(aSource, aMask, aOptions));
413 void DrawTargetRecording::MaskSurface(const Pattern& aSource,
414 SourceSurface* aMask, Point aOffset,
415 const DrawOptions& aOptions) {
416 if (!aMask) {
417 return;
420 MarkChanged();
422 EnsurePatternDependenciesStored(aSource);
423 EnsureSurfaceStoredRecording(mRecorder, aMask, "MaskSurface");
425 RecordEventSelf(RecordedMaskSurface(aSource, aMask, aOffset, aOptions));
428 void DrawTargetRecording::Stroke(const Path* aPath, const Pattern& aPattern,
429 const StrokeOptions& aStrokeOptions,
430 const DrawOptions& aOptions) {
431 MarkChanged();
433 if (aPath->GetBackendType() == BackendType::RECORDING) {
434 const PathRecording* path = static_cast<const PathRecording*>(aPath);
435 auto circle = path->AsCircle();
436 if (circle && circle->closed) {
437 EnsurePatternDependenciesStored(aPattern);
438 RecordEventSelf(RecordedStrokeCircle(circle.value(), aPattern,
439 aStrokeOptions, aOptions));
440 return;
443 auto line = path->AsLine();
444 if (line) {
445 EnsurePatternDependenciesStored(aPattern);
446 RecordEventSelf(RecordedStrokeLine(line->origin, line->destination,
447 aPattern, aStrokeOptions, aOptions));
448 return;
452 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
453 EnsurePatternDependenciesStored(aPattern);
455 RecordEventSelf(
456 RecordedStroke(pathRecording, aPattern, aStrokeOptions, aOptions));
459 void DrawTargetRecording::DrawShadow(const Path* aPath, const Pattern& aPattern,
460 const ShadowOptions& aShadow,
461 const DrawOptions& aOptions,
462 const StrokeOptions* aStrokeOptions) {
463 MarkChanged();
465 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
466 EnsurePatternDependenciesStored(aPattern);
468 RecordEventSelf(RecordedDrawShadow(pathRecording, aPattern, aShadow, aOptions,
469 aStrokeOptions));
472 void DrawTargetRecording::MarkChanged() { mIsDirty = true; }
474 already_AddRefed<SourceSurface> DrawTargetRecording::Snapshot() {
475 RefPtr<SourceSurface> retSurf =
476 new SourceSurfaceRecording(mRect.Size(), mFormat, mRecorder);
478 RecordEventSelfSkipFlushTransform(RecordedSnapshot(ReferencePtr(retSurf)));
480 return retSurf.forget();
483 already_AddRefed<SourceSurface> DrawTargetRecording::IntoLuminanceSource(
484 LuminanceType aLuminanceType, float aOpacity) {
485 RefPtr<SourceSurface> retSurf =
486 new SourceSurfaceRecording(mRect.Size(), SurfaceFormat::A8, mRecorder);
488 RecordEventSelfSkipFlushTransform(
489 RecordedIntoLuminanceSource(retSurf, aLuminanceType, aOpacity));
491 return retSurf.forget();
494 already_AddRefed<SourceSurface> SourceSurfaceRecording::ExtractSubrect(
495 const IntRect& aRect) {
496 if (aRect.IsEmpty() || !GetRect().Contains(aRect)) {
497 return nullptr;
500 RefPtr<SourceSurface> subSurf =
501 new SourceSurfaceRecording(aRect.Size(), mFormat, mRecorder);
502 mRecorder->RecordEvent(RecordedExtractSubrect(subSurf, this, aRect));
503 return subSurf.forget();
506 void DrawTargetRecording::Flush() {
507 RecordEventSelfSkipFlushTransform(RecordedFlush());
510 void DrawTargetRecording::DetachAllSnapshots() {
511 RecordEventSelfSkipFlushTransform(RecordedDetachAllSnapshots());
514 void DrawTargetRecording::DrawSurface(SourceSurface* aSurface,
515 const Rect& aDest, const Rect& aSource,
516 const DrawSurfaceOptions& aSurfOptions,
517 const DrawOptions& aOptions) {
518 if (!aSurface) {
519 return;
522 MarkChanged();
524 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurface");
526 RecordEventSelf(
527 RecordedDrawSurface(aSurface, aDest, aSource, aSurfOptions, aOptions));
530 void DrawTargetRecording::DrawSurfaceDescriptor(
531 const layers::SurfaceDescriptor& aDesc,
532 const RefPtr<layers::Image>& aImageOfSurfaceDescriptor, const Rect& aDest,
533 const Rect& aSource, const DrawSurfaceOptions& aSurfOptions,
534 const DrawOptions& aOptions) {
535 MarkChanged();
537 mRecorder->StoreImageRecording(aImageOfSurfaceDescriptor,
538 "DrawSurfaceDescriptor");
540 RecordEventSelf(RecordedDrawSurfaceDescriptor(aDesc, aDest, aSource,
541 aSurfOptions, aOptions));
544 void DrawTargetRecording::DrawDependentSurface(uint64_t aId,
545 const Rect& aDest) {
546 MarkChanged();
548 mRecorder->AddDependentSurface(aId);
549 RecordEventSelf(RecordedDrawDependentSurface(aId, aDest));
552 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface* aSurface,
553 const Point& aDest,
554 const ShadowOptions& aShadow,
555 CompositionOp aOp) {
556 if (!aSurface) {
557 return;
560 MarkChanged();
562 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurfaceWithShadow");
564 RecordEventSelf(RecordedDrawSurfaceWithShadow(aSurface, aDest, aShadow, aOp));
567 void DrawTargetRecording::DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
568 const Point& aDestPoint,
569 const DrawOptions& aOptions) {
570 if (!aNode) {
571 return;
574 MarkChanged();
576 MOZ_ASSERT(mRecorder->HasStoredObject(aNode));
578 RecordEventSelf(RecordedDrawFilter(aNode, aSourceRect, aDestPoint, aOptions));
581 already_AddRefed<FilterNode> DrawTargetRecording::CreateFilter(
582 FilterType aType) {
583 RefPtr<FilterNode> retNode = new FilterNodeRecording(mRecorder);
585 RecordEventSelfSkipFlushTransform(RecordedFilterNodeCreation(retNode, aType));
587 return retNode.forget();
590 void DrawTargetRecording::ClearRect(const Rect& aRect) {
591 MarkChanged();
593 RecordEventSelf(RecordedClearRect(aRect));
596 void DrawTargetRecording::CopySurface(SourceSurface* aSurface,
597 const IntRect& aSourceRect,
598 const IntPoint& aDestination) {
599 if (!aSurface) {
600 return;
603 MarkChanged();
605 EnsureSurfaceStoredRecording(mRecorder, aSurface, "CopySurface");
607 RecordEventSelf(RecordedCopySurface(aSurface, aSourceRect, aDestination));
610 void DrawTargetRecording::PushClip(const Path* aPath) {
611 if (!aPath) {
612 return;
615 // The canvas doesn't have a clipRect API so we always end up in the generic
616 // path. The D2D backend doesn't have a good way of specializing rectangular
617 // clips so we take advantage of the fact that aPath is usually backed by a
618 // SkiaPath which implements AsRect() and specialize it here.
619 auto rect = aPath->AsRect();
620 if (rect.isSome()) {
621 PushClipRect(rect.value());
622 return;
625 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
626 RecordEventSelf(RecordedPushClip(ReferencePtr(pathRecording)));
629 void DrawTargetRecording::PushClipRect(const Rect& aRect) {
630 RecordEventSelf(RecordedPushClipRect(aRect));
633 void DrawTargetRecording::PopClip() {
634 RecordEventSelfSkipFlushTransform(RecordedPopClip());
637 void DrawTargetRecording::PushLayer(bool aOpaque, Float aOpacity,
638 SourceSurface* aMask,
639 const Matrix& aMaskTransform,
640 const IntRect& aBounds,
641 bool aCopyBackground) {
642 if (aMask) {
643 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer");
646 RecordEventSelf(RecordedPushLayer(aOpaque, aOpacity, aMask, aMaskTransform,
647 aBounds, aCopyBackground));
649 PushedLayer layer(GetPermitSubpixelAA());
650 mPushedLayers.push_back(layer);
651 DrawTarget::SetPermitSubpixelAA(aOpaque);
654 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque, Float aOpacity,
655 SourceSurface* aMask,
656 const Matrix& aMaskTransform,
657 const IntRect& aBounds,
658 bool aCopyBackground,
659 CompositionOp aCompositionOp) {
660 if (aMask) {
661 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer");
664 RecordEventSelf(RecordedPushLayerWithBlend(aOpaque, aOpacity, aMask,
665 aMaskTransform, aBounds,
666 aCopyBackground, aCompositionOp));
668 PushedLayer layer(GetPermitSubpixelAA());
669 mPushedLayers.push_back(layer);
670 DrawTarget::SetPermitSubpixelAA(aOpaque);
673 void DrawTargetRecording::PopLayer() {
674 MarkChanged();
676 RecordEventSelfSkipFlushTransform(RecordedPopLayer());
678 const PushedLayer& layer = mPushedLayers.back();
679 DrawTarget::SetPermitSubpixelAA(layer.mOldPermitSubpixelAA);
680 mPushedLayers.pop_back();
683 already_AddRefed<SourceSurface>
684 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData,
685 const IntSize& aSize,
686 int32_t aStride,
687 SurfaceFormat aFormat) const {
688 RefPtr<SourceSurface> surface = CreateDataSourceSurfaceWithStrideFromData(
689 aSize, aFormat, aStride, aData, aStride);
690 if (!surface) {
691 return nullptr;
694 return OptimizeSourceSurface(surface);
697 already_AddRefed<SourceSurface> DrawTargetRecording::OptimizeSourceSurface(
698 SourceSurface* aSurface) const {
699 // See if we have a previously optimized surface available. We have to do this
700 // check before the SurfaceType::RECORDING below, because aSurface might be a
701 // SurfaceType::RECORDING from another recorder we have previously optimized.
702 auto* userData = static_cast<RecordingSourceSurfaceUserData*>(
703 aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get())));
704 if (userData) {
705 RefPtr<SourceSurface> strongRef(userData->optimizedSurface);
706 if (strongRef) {
707 return do_AddRef(strongRef);
709 } else {
710 if (!EnsureSurfaceStoredRecording(mRecorder, aSurface,
711 "OptimizeSourceSurface")) {
712 // Surface was already stored, but doesn't have UserData so must be one
713 // of our recording surfaces.
714 MOZ_ASSERT(aSurface->GetType() == SurfaceType::RECORDING);
715 return do_AddRef(aSurface);
718 userData = static_cast<RecordingSourceSurfaceUserData*>(
719 aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get())));
720 MOZ_ASSERT(userData,
721 "User data should always have been set by "
722 "EnsureSurfaceStoredRecording.");
725 RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording(
726 aSurface->GetSize(), aSurface->GetFormat(), mRecorder, aSurface);
727 RecordEventSelfSkipFlushTransform(
728 RecordedOptimizeSourceSurface(aSurface, retSurf));
729 userData->optimizedSurface = retSurf;
731 return retSurf.forget();
734 already_AddRefed<SourceSurface>
735 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(
736 const NativeSurface& aSurface) const {
737 MOZ_ASSERT(false);
738 return nullptr;
741 already_AddRefed<DrawTarget>
742 DrawTargetRecording::CreateSimilarDrawTargetWithBacking(
743 const IntSize& aSize, SurfaceFormat aFormat) const {
744 if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) {
745 // If the requested similar draw target is too big, then we should try to
746 // rasterize on the content side to avoid duplicating the effort when a
747 // blob image gets tiled. If we fail somehow to produce it, we can fall
748 // back to recording.
749 constexpr int32_t kRasterThreshold = 256 * 256 * 4;
750 int32_t stride = aSize.width * BytesPerPixel(aFormat);
751 int32_t surfaceBytes = aSize.height * stride;
752 if (surfaceBytes >= kRasterThreshold) {
753 auto surface = MakeRefPtr<SourceSurfaceSharedData>();
754 if (surface->Init(aSize, stride, aFormat)) {
755 auto dt = MakeRefPtr<DrawTargetSkia>();
756 if (dt->Init(std::move(surface))) {
757 return dt.forget();
758 } else {
759 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
765 return CreateSimilarDrawTarget(aSize, aFormat);
768 already_AddRefed<DrawTarget> DrawTargetRecording::CreateSimilarDrawTarget(
769 const IntSize& aSize, SurfaceFormat aFormat) const {
770 RefPtr<DrawTargetRecording> similarDT;
771 if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) {
772 similarDT =
773 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize), aFormat);
774 similarDT->SetOptimizeTransform(mOptimizeTransform);
775 RecordEventSelfSkipFlushTransform(
776 RecordedCreateSimilarDrawTarget(similarDT.get(), aSize, aFormat));
777 } else if (XRE_IsContentProcess()) {
778 // Crash any content process that calls this function with arguments that
779 // would fail to create a similar draw target. We do this to root out bad
780 // callers. We don't want to crash any important processes though so for
781 // for those we'll just gracefully return nullptr.
782 MOZ_CRASH(
783 "Content-process DrawTargetRecording can't create requested similar "
784 "drawtarget");
786 return similarDT.forget();
789 bool DrawTargetRecording::CanCreateSimilarDrawTarget(
790 const IntSize& aSize, SurfaceFormat aFormat) const {
791 return mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat);
794 RefPtr<DrawTarget> DrawTargetRecording::CreateClippedDrawTarget(
795 const Rect& aBounds, SurfaceFormat aFormat) {
796 RefPtr<DrawTargetRecording> similarDT =
797 new DrawTargetRecording(this, mRect, aFormat);
798 similarDT->SetOptimizeTransform(mOptimizeTransform);
799 RecordEventSelf(
800 RecordedCreateClippedDrawTarget(similarDT.get(), aBounds, aFormat));
801 similarDT->mTransform = similarDT->mRecordedTransform = mTransform;
802 return similarDT;
805 already_AddRefed<DrawTarget>
806 DrawTargetRecording::CreateSimilarDrawTargetForFilter(
807 const IntSize& aMaxSize, SurfaceFormat aFormat, FilterNode* aFilter,
808 FilterNode* aSource, const Rect& aSourceRect, const Point& aDestPoint) {
809 RefPtr<DrawTargetRecording> similarDT;
810 if (mFinalDT->CanCreateSimilarDrawTarget(aMaxSize, aFormat)) {
811 similarDT = new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize),
812 aFormat);
813 similarDT->SetOptimizeTransform(mOptimizeTransform);
814 // RecordedCreateDrawTargetForFilter::PlayEvent uses the transform, despite
815 // the fact that the underlying DrawTarget does not.
816 RecordEventSelf(RecordedCreateDrawTargetForFilter(similarDT.get(), aMaxSize,
817 aFormat, aFilter, aSource,
818 aSourceRect, aDestPoint));
819 } else if (XRE_IsContentProcess()) {
820 // See CreateSimilarDrawTarget
821 MOZ_CRASH(
822 "Content-process DrawTargetRecording can't create requested clipped "
823 "drawtarget");
825 return similarDT.forget();
828 already_AddRefed<PathBuilder> DrawTargetRecording::CreatePathBuilder(
829 FillRule aFillRule) const {
830 return MakeAndAddRef<PathBuilderRecording>(mFinalDT->GetBackendType(),
831 aFillRule);
834 already_AddRefed<GradientStops> DrawTargetRecording::CreateGradientStops(
835 GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode) const {
836 RefPtr<GradientStops> retStops = new GradientStopsRecording(mRecorder);
838 RecordEventSelfSkipFlushTransform(
839 RecordedGradientStopsCreation(retStops, aStops, aNumStops, aExtendMode));
841 return retStops.forget();
844 void DrawTargetRecording::SetTransform(const Matrix& aTransform) {
845 DrawTarget::SetTransform(aTransform);
846 if (!mOptimizeTransform) {
847 FlushTransform();
851 void DrawTargetRecording::RecordTransform(const Matrix& aTransform) const {
852 RecordEventSelfSkipFlushTransform(RecordedSetTransform(aTransform));
853 mRecordedTransform = aTransform;
856 void DrawTargetRecording::SetPermitSubpixelAA(bool aPermitSubpixelAA) {
857 if (aPermitSubpixelAA == mPermitSubpixelAA) {
858 return;
860 DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA);
861 RecordEventSelfSkipFlushTransform(
862 RecordedSetPermitSubpixelAA(aPermitSubpixelAA));
865 already_AddRefed<PathRecording> DrawTargetRecording::EnsurePathStored(
866 const Path* aPath) {
867 RefPtr<PathRecording> pathRecording;
868 if (aPath->GetBackendType() == BackendType::RECORDING) {
869 pathRecording =
870 const_cast<PathRecording*>(static_cast<const PathRecording*>(aPath));
871 if (!mRecorder->TryAddStoredObject(pathRecording)) {
872 // Path is already stored.
873 return pathRecording.forget();
875 } else {
876 MOZ_ASSERT(!mRecorder->HasStoredObject(aPath));
877 FillRule fillRule = aPath->GetFillRule();
878 RefPtr<PathBuilderRecording> builderRecording =
879 new PathBuilderRecording(mFinalDT->GetBackendType(), fillRule);
880 aPath->StreamToSink(builderRecording);
881 pathRecording = builderRecording->Finish().downcast<PathRecording>();
882 mRecorder->AddStoredObject(pathRecording);
885 // It's important that AddStoredObject or TryAddStoredObject is called before
886 // this because that will run any pending processing required by recorded
887 // objects that have been deleted off the main thread.
888 RecordEventSelfSkipFlushTransform(RecordedPathCreation(pathRecording.get()));
889 pathRecording->mStoredRecorders.push_back(mRecorder);
891 return pathRecording.forget();
894 // This should only be called on the 'root' DrawTargetRecording.
895 // Calling it on a child DrawTargetRecordings will cause confusion.
896 void DrawTargetRecording::FlushItem(const IntRect& aBounds) {
897 mRecorder->FlushItem(aBounds);
898 // Reinitialize the recorder (FlushItem will write a new recording header)
899 // Tell the new recording about our draw target
900 // This code should match what happens in the DrawTargetRecording constructor.
901 MOZ_DIAGNOSTIC_ASSERT(mRecorder->GetRecorderType() ==
902 RecorderType::WEBRENDER);
903 RecordEventSkipFlushTransform(
904 RecordedDrawTargetCreation(this, mFinalDT->GetBackendType(), mRect,
905 mFinalDT->GetFormat(), false, nullptr));
906 // RecordedDrawTargetCreation can actually reuse the base DrawTarget for the
907 // recording, but we cannot conclude that from here, so force the transform
908 // to be recorded.
909 RecordTransform(mTransform);
910 mTransformDirty = false;
913 void DrawTargetRecording::EnsurePatternDependenciesStored(
914 const Pattern& aPattern) {
915 switch (aPattern.GetType()) {
916 case PatternType::COLOR:
917 // No dependencies here.
918 return;
919 case PatternType::LINEAR_GRADIENT: {
920 MOZ_ASSERT_IF(
921 static_cast<const LinearGradientPattern*>(&aPattern)->mStops,
922 mRecorder->HasStoredObject(
923 static_cast<const LinearGradientPattern*>(&aPattern)->mStops));
924 return;
926 case PatternType::RADIAL_GRADIENT: {
927 MOZ_ASSERT_IF(
928 static_cast<const RadialGradientPattern*>(&aPattern)->mStops,
929 mRecorder->HasStoredObject(
930 static_cast<const RadialGradientPattern*>(&aPattern)->mStops));
931 return;
933 case PatternType::CONIC_GRADIENT: {
934 MOZ_ASSERT_IF(
935 static_cast<const ConicGradientPattern*>(&aPattern)->mStops,
936 mRecorder->HasStoredObject(
937 static_cast<const ConicGradientPattern*>(&aPattern)->mStops));
938 return;
940 case PatternType::SURFACE: {
941 const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aPattern);
942 EnsureSurfaceStoredRecording(mRecorder, pat->mSurface,
943 "EnsurePatternDependenciesStored");
944 return;
949 } // namespace gfx
950 } // namespace mozilla