DrawTargetRecording.cpp (36564B)
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/. */ 6 7 #include "DrawTargetRecording.h" 8 #include "DrawTargetSkia.h" 9 #include "PathRecording.h" 10 #include <stdio.h> 11 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/layers/TextureRecorded.h" 21 #include "nsXULAppAPI.h" // for XRE_IsContentProcess() 22 #include "RecordingTypes.h" 23 #include "RecordedEventImpl.h" 24 25 namespace mozilla { 26 namespace gfx { 27 28 struct RecordingSourceSurfaceUserData { 29 void* refPtr; 30 RefPtr<DrawEventRecorderPrivate> recorder; 31 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; 35 }; 36 37 static void RecordingSourceSurfaceUserDataFunc(void* aUserData) { 38 RecordingSourceSurfaceUserData* userData = 39 static_cast<RecordingSourceSurfaceUserData*>(aUserData); 40 41 if (NS_IsMainThread()) { 42 userData->recorder->RecordSourceSurfaceDestruction(userData->refPtr); 43 delete userData; 44 return; 45 } 46 47 userData->recorder->AddPendingDeletion([userData]() -> void { 48 userData->recorder->RecordSourceSurfaceDestruction(userData->refPtr); 49 delete userData; 50 }); 51 } 52 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; 62 } 63 aRecorder->StoreSourceSurfaceRecording(aSurface, reason); 64 aRecorder->AddSourceSurface(aSurface); 65 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; 72 } 73 74 class SourceSurfaceRecording : public SourceSurface { 75 public: 76 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording, override) 77 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); 86 } 87 88 ~SourceSurfaceRecording() { 89 mRecorder->RemoveStoredObject(this); 90 mRecorder->RecordEvent( 91 RecordedSourceSurfaceDestruction(ReferencePtr(this))); 92 } 93 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(); 100 } 101 102 return nullptr; 103 } 104 105 already_AddRefed<SourceSurface> ExtractSubrect(const IntRect& aRect) override; 106 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; 114 }; 115 116 class GradientStopsRecording : public GradientStops { 117 public: 118 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording, override) 119 120 explicit GradientStopsRecording(DrawEventRecorderPrivate* aRecorder) 121 : mRecorder(aRecorder) { 122 mRecorder->AddStoredObject(this); 123 } 124 125 virtual ~GradientStopsRecording() { 126 mRecorder->RemoveStoredObject(this); 127 mRecorder->RecordEvent( 128 RecordedGradientStopsDestruction(ReferencePtr(this))); 129 } 130 131 BackendType GetBackendType() const override { return BackendType::RECORDING; } 132 133 RefPtr<DrawEventRecorderPrivate> mRecorder; 134 }; 135 136 class FilterNodeRecording : public FilterNode { 137 public: 138 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording, override) 139 using FilterNode::SetAttribute; 140 141 explicit FilterNodeRecording(DrawEventRecorderPrivate* aRecorder) 142 : mRecorder(aRecorder) { 143 mRecorder->AddStoredObject(this); 144 } 145 146 virtual ~FilterNodeRecording() { 147 mRecorder->RemoveStoredObject(this); 148 mRecorder->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this))); 149 } 150 151 void SetInput(uint32_t aIndex, SourceSurface* aSurface) override { 152 EnsureSurfaceStoredRecording(mRecorder, aSurface, "SetInput"); 153 154 mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aSurface)); 155 } 156 void SetInput(uint32_t aIndex, FilterNode* aFilter) override { 157 MOZ_ASSERT(mRecorder->HasStoredObject(aFilter)); 158 159 mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aFilter)); 160 } 161 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)); \ 167 } 168 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); 182 183 #undef FORWARD_SET_ATTRIBUTE 184 185 void SetAttribute(uint32_t aIndex, const Float* aFloat, 186 uint32_t aSize) override { 187 mRecorder->RecordEvent( 188 RecordedFilterNodeSetAttribute(this, aIndex, aFloat, aSize)); 189 } 190 191 FilterBackend GetBackendType() override { return FILTER_BACKEND_RECORDING; } 192 193 RefPtr<DrawEventRecorderPrivate> mRecorder; 194 }; 195 196 DrawTargetRecording::DrawTargetRecording( 197 layers::CanvasDrawEventRecorder* aRecorder, 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, aTextureOwnerId, mFinalDT->GetBackendType(), aSize, 205 mFinalDT->GetFormat())); 206 mFormat = mFinalDT->GetFormat(); 207 DrawTarget::SetPermitSubpixelAA(IsOpaque(mFormat)); 208 } 209 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)); 223 } 224 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)); 230 } 231 232 DrawTargetRecording::~DrawTargetRecording() { 233 RecordEventSkipFlushTransform( 234 RecordedDrawTargetDestruction(ReferencePtr(this))); 235 mRecorder->ClearDrawTarget(this); 236 } 237 238 void DrawTargetRecording::Link(const char* aLocalDest, const char* aURI, 239 const Rect& aRect) { 240 MarkChanged(); 241 242 RecordEventSelf(RecordedLink(aLocalDest, aURI, aRect)); 243 } 244 245 void DrawTargetRecording::Destination(const char* aDestination, 246 const Point& aPoint) { 247 MarkChanged(); 248 249 RecordEventSelf(RecordedDestination(aDestination, aPoint)); 250 } 251 252 void DrawTargetRecording::FillRect(const Rect& aRect, const Pattern& aPattern, 253 const DrawOptions& aOptions) { 254 MarkChanged(); 255 256 EnsurePatternDependenciesStored(aPattern); 257 258 RecordEventSelf(RecordedFillRect(aRect, aPattern, aOptions)); 259 } 260 261 void DrawTargetRecording::StrokeRect(const Rect& aRect, const Pattern& aPattern, 262 const StrokeOptions& aStrokeOptions, 263 const DrawOptions& aOptions) { 264 MarkChanged(); 265 266 EnsurePatternDependenciesStored(aPattern); 267 268 RecordEventSelf( 269 RecordedStrokeRect(aRect, aPattern, aStrokeOptions, aOptions)); 270 } 271 272 void DrawTargetRecording::StrokeLine(const Point& aBegin, const Point& aEnd, 273 const Pattern& aPattern, 274 const StrokeOptions& aStrokeOptions, 275 const DrawOptions& aOptions) { 276 MarkChanged(); 277 278 EnsurePatternDependenciesStored(aPattern); 279 280 RecordEventSelf( 281 RecordedStrokeLine(aBegin, aEnd, aPattern, aStrokeOptions, aOptions)); 282 } 283 284 void DrawTargetRecording::Fill(const Path* aPath, const Pattern& aPattern, 285 const DrawOptions& aOptions) { 286 if (!aPath) { 287 return; 288 } 289 290 MarkChanged(); 291 292 if (aPath->GetBackendType() == BackendType::RECORDING) { 293 const PathRecording* path = static_cast<const PathRecording*>(aPath); 294 auto circle = path->AsCircle(); 295 if (circle) { 296 EnsurePatternDependenciesStored(aPattern); 297 RecordEventSelf(RecordedFillCircle(circle.value(), aPattern, aOptions)); 298 return; 299 } 300 } 301 302 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); 303 EnsurePatternDependenciesStored(aPattern); 304 RecordEventSelf(RecordedFill(pathRecording, aPattern, aOptions)); 305 } 306 307 struct RecordingFontUserData { 308 void* refPtr; 309 void* unscaledFont; 310 RefPtr<DrawEventRecorderPrivate> recorder; 311 }; 312 313 static void RecordingFontUserDataDestroyFunc(void* aUserData) { 314 RecordingFontUserData* userData = 315 static_cast<RecordingFontUserData*>(aUserData); 316 317 userData->recorder->RecordEvent( 318 RecordedScaledFontDestruction(ReferencePtr(userData->refPtr))); 319 userData->recorder->RemoveScaledFont((ScaledFont*)userData->refPtr); 320 userData->recorder->DecrementUnscaledFontRefCount(userData->unscaledFont); 321 delete userData; 322 } 323 324 void DrawTargetRecording::DrawGlyphs(ScaledFont* aFont, 325 const GlyphBuffer& aBuffer, 326 const Pattern& aPattern, 327 const DrawOptions& aOptions, 328 const StrokeOptions* aStrokeOptions) { 329 if (!aFont) { 330 return; 331 } 332 333 MarkChanged(); 334 335 EnsurePatternDependenciesStored(aPattern); 336 337 UserDataKey* userDataKey = reinterpret_cast<UserDataKey*>(mRecorder.get()); 338 if (mRecorder->WantsExternalFonts()) { 339 mRecorder->AddScaledFont(aFont); 340 } else if (!aFont->GetUserData(userDataKey)) { 341 UnscaledFont* unscaledFont = aFont->GetUnscaledFont(); 342 if (mRecorder->IncrementUnscaledFontRefCount(unscaledFont) == 0) { 343 // Prefer sending the description, if we can create one. This ensures 344 // we don't record the data of system fonts which saves time and can 345 // prevent duplicate copies from accumulating in the OS cache during 346 // playback. 347 RecordedFontDescriptor fontDesc(unscaledFont); 348 if (fontDesc.IsValid()) { 349 RecordEventSkipFlushTransform(fontDesc); 350 } else { 351 RecordedFontData fontData(unscaledFont); 352 RecordedFontDetails fontDetails; 353 if (fontData.GetFontDetails(fontDetails)) { 354 // Try to serialise the whole font, just in case this is a web font 355 // that is not present on the system. 356 if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) { 357 RecordEventSkipFlushTransform(fontData); 358 mRecorder->AddStoredFontData(fontDetails.fontDataKey); 359 } 360 RecordEventSkipFlushTransform( 361 RecordedUnscaledFontCreation(unscaledFont, fontDetails)); 362 } else { 363 gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise " 364 "UnscaledFont"; 365 } 366 } 367 } 368 RecordEventSkipFlushTransform( 369 RecordedScaledFontCreation(aFont, unscaledFont)); 370 RecordingFontUserData* userData = new RecordingFontUserData; 371 userData->refPtr = aFont; 372 userData->unscaledFont = unscaledFont; 373 userData->recorder = mRecorder; 374 aFont->AddUserData(userDataKey, userData, 375 &RecordingFontUserDataDestroyFunc); 376 userData->recorder->AddScaledFont(aFont); 377 } 378 379 if (aStrokeOptions) { 380 RecordEventSelf(RecordedStrokeGlyphs(aFont, aPattern, *aStrokeOptions, 381 aOptions, aBuffer.mGlyphs, 382 aBuffer.mNumGlyphs)); 383 } else { 384 RecordEventSelf(RecordedFillGlyphs(aFont, aPattern, aOptions, 385 aBuffer.mGlyphs, aBuffer.mNumGlyphs)); 386 } 387 } 388 389 void DrawTargetRecording::FillGlyphs(ScaledFont* aFont, 390 const GlyphBuffer& aBuffer, 391 const Pattern& aPattern, 392 const DrawOptions& aOptions) { 393 DrawGlyphs(aFont, aBuffer, aPattern, aOptions); 394 } 395 396 void DrawTargetRecording::StrokeGlyphs(ScaledFont* aFont, 397 const GlyphBuffer& aBuffer, 398 const Pattern& aPattern, 399 const StrokeOptions& aStrokeOptions, 400 const DrawOptions& aOptions) { 401 DrawGlyphs(aFont, aBuffer, aPattern, aOptions, &aStrokeOptions); 402 } 403 404 void DrawTargetRecording::Mask(const Pattern& aSource, const Pattern& aMask, 405 const DrawOptions& aOptions) { 406 MarkChanged(); 407 408 EnsurePatternDependenciesStored(aSource); 409 EnsurePatternDependenciesStored(aMask); 410 411 RecordEventSelf(RecordedMask(aSource, aMask, aOptions)); 412 } 413 414 void DrawTargetRecording::MaskSurface(const Pattern& aSource, 415 SourceSurface* aMask, Point aOffset, 416 const DrawOptions& aOptions) { 417 if (!aMask) { 418 return; 419 } 420 421 MarkChanged(); 422 423 EnsurePatternDependenciesStored(aSource); 424 EnsureSurfaceStoredRecording(mRecorder, aMask, "MaskSurface"); 425 426 RecordEventSelf(RecordedMaskSurface(aSource, aMask, aOffset, aOptions)); 427 } 428 429 void DrawTargetRecording::Stroke(const Path* aPath, const Pattern& aPattern, 430 const StrokeOptions& aStrokeOptions, 431 const DrawOptions& aOptions) { 432 MarkChanged(); 433 434 if (aPath->GetBackendType() == BackendType::RECORDING) { 435 const PathRecording* path = static_cast<const PathRecording*>(aPath); 436 auto circle = path->AsCircle(); 437 if (circle && circle->closed) { 438 EnsurePatternDependenciesStored(aPattern); 439 RecordEventSelf(RecordedStrokeCircle(circle.value(), aPattern, 440 aStrokeOptions, aOptions)); 441 return; 442 } 443 444 auto line = path->AsLine(); 445 if (line) { 446 EnsurePatternDependenciesStored(aPattern); 447 RecordEventSelf(RecordedStrokeLine(line->origin, line->destination, 448 aPattern, aStrokeOptions, aOptions)); 449 return; 450 } 451 } 452 453 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); 454 EnsurePatternDependenciesStored(aPattern); 455 456 RecordEventSelf( 457 RecordedStroke(pathRecording, aPattern, aStrokeOptions, aOptions)); 458 } 459 460 void DrawTargetRecording::DrawShadow(const Path* aPath, const Pattern& aPattern, 461 const ShadowOptions& aShadow, 462 const DrawOptions& aOptions, 463 const StrokeOptions* aStrokeOptions) { 464 MarkChanged(); 465 466 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); 467 EnsurePatternDependenciesStored(aPattern); 468 469 RecordEventSelf(RecordedDrawShadow(pathRecording, aPattern, aShadow, aOptions, 470 aStrokeOptions)); 471 } 472 473 void DrawTargetRecording::MarkChanged() { 474 if (mTextureData) { 475 mTextureData->DrawTargetWillChange(); 476 } 477 } 478 479 already_AddRefed<SourceSurface> DrawTargetRecording::Snapshot() { 480 RefPtr<SourceSurface> retSurf = 481 new SourceSurfaceRecording(mRect.Size(), mFormat, mRecorder); 482 483 RecordEventSelfSkipFlushTransform(RecordedSnapshot(ReferencePtr(retSurf))); 484 485 return retSurf.forget(); 486 } 487 488 already_AddRefed<SourceSurface> 489 DrawTargetRecording::CreateExternalSourceSurface(const IntSize& aSize, 490 SurfaceFormat aFormat) { 491 RefPtr<SourceSurface> retSurf = 492 new SourceSurfaceRecording(aSize, aFormat, mRecorder); 493 494 return retSurf.forget(); 495 } 496 497 already_AddRefed<SourceSurface> DrawTargetRecording::SnapshotExternalCanvas( 498 nsICanvasRenderingContextInternal* aCanvas, 499 mozilla::ipc::IProtocol* aActor) { 500 if (RefPtr<layers::CanvasChild> canvasChild = mRecorder->GetCanvasChild()) { 501 return canvasChild->SnapshotExternalCanvas(this, aCanvas, aActor); 502 } 503 return nullptr; 504 } 505 506 already_AddRefed<SourceSurface> DrawTargetRecording::IntoLuminanceSource( 507 LuminanceType aLuminanceType, float aOpacity) { 508 RefPtr<SourceSurface> retSurf = 509 new SourceSurfaceRecording(mRect.Size(), SurfaceFormat::A8, mRecorder); 510 511 RecordEventSelfSkipFlushTransform( 512 RecordedIntoLuminanceSource(retSurf, aLuminanceType, aOpacity)); 513 514 return retSurf.forget(); 515 } 516 517 already_AddRefed<SourceSurface> SourceSurfaceRecording::ExtractSubrect( 518 const IntRect& aRect) { 519 if (aRect.IsEmpty() || !GetRect().Contains(aRect)) { 520 return nullptr; 521 } 522 523 RefPtr<SourceSurface> subSurf = 524 new SourceSurfaceRecording(aRect.Size(), mFormat, mRecorder); 525 mRecorder->RecordEvent(RecordedExtractSubrect(subSurf, this, aRect)); 526 return subSurf.forget(); 527 } 528 529 void DrawTargetRecording::Flush() { 530 RecordEventSelfSkipFlushTransform(RecordedFlush()); 531 } 532 533 void DrawTargetRecording::DetachAllSnapshots() { 534 RecordEventSelfSkipFlushTransform(RecordedDetachAllSnapshots()); 535 } 536 537 void DrawTargetRecording::DrawSurface(SourceSurface* aSurface, 538 const Rect& aDest, const Rect& aSource, 539 const DrawSurfaceOptions& aSurfOptions, 540 const DrawOptions& aOptions) { 541 if (!aSurface) { 542 return; 543 } 544 545 MarkChanged(); 546 547 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurface"); 548 549 RecordEventSelf( 550 RecordedDrawSurface(aSurface, aDest, aSource, aSurfOptions, aOptions)); 551 } 552 553 void DrawTargetRecording::DrawSurfaceDescriptor( 554 const layers::SurfaceDescriptor& aDesc, 555 const RefPtr<layers::Image>& aImageOfSurfaceDescriptor, const Rect& aDest, 556 const Rect& aSource, const DrawSurfaceOptions& aSurfOptions, 557 const DrawOptions& aOptions) { 558 MarkChanged(); 559 560 mRecorder->StoreImageRecording(aImageOfSurfaceDescriptor, 561 "DrawSurfaceDescriptor"); 562 563 RecordEventSelf(RecordedDrawSurfaceDescriptor(aDesc, aDest, aSource, 564 aSurfOptions, aOptions)); 565 } 566 567 void DrawTargetRecording::DrawDependentSurface(uint64_t aId, 568 const Rect& aDest) { 569 MarkChanged(); 570 571 mRecorder->AddDependentSurface(aId); 572 RecordEventSelf(RecordedDrawDependentSurface(aId, aDest)); 573 } 574 575 void DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface* aSurface, 576 const Point& aDest, 577 const ShadowOptions& aShadow, 578 CompositionOp aOp) { 579 if (!aSurface) { 580 return; 581 } 582 583 MarkChanged(); 584 585 EnsureSurfaceStoredRecording(mRecorder, aSurface, "DrawSurfaceWithShadow"); 586 587 RecordEventSelf(RecordedDrawSurfaceWithShadow(aSurface, aDest, aShadow, aOp)); 588 } 589 590 void DrawTargetRecording::DrawFilter(FilterNode* aNode, const Rect& aSourceRect, 591 const Point& aDestPoint, 592 const DrawOptions& aOptions) { 593 if (!aNode) { 594 return; 595 } 596 597 MarkChanged(); 598 599 MOZ_ASSERT(mRecorder->HasStoredObject(aNode)); 600 601 RecordEventSelf(RecordedDrawFilter(aNode, aSourceRect, aDestPoint, aOptions)); 602 } 603 604 already_AddRefed<FilterNode> DrawTargetRecording::CreateFilter( 605 FilterType aType) { 606 RefPtr<FilterNode> retNode = new FilterNodeRecording(mRecorder); 607 608 RecordEventSelfSkipFlushTransform(RecordedFilterNodeCreation(retNode, aType)); 609 610 return retNode.forget(); 611 } 612 613 already_AddRefed<FilterNode> DrawTargetRecording::DeferFilterInput( 614 const Path* aPath, const Pattern& aPattern, const IntRect& aSourceRect, 615 const IntPoint& aDestOffset, const DrawOptions& aOptions, 616 const StrokeOptions* aStrokeOptions) { 617 RefPtr<FilterNode> retNode = new FilterNodeRecording(mRecorder); 618 619 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); 620 EnsurePatternDependenciesStored(aPattern); 621 622 RecordEventSelf(RecordedDeferFilterInput(retNode, pathRecording, aPattern, 623 aSourceRect, aDestOffset, aOptions, 624 aStrokeOptions)); 625 626 return retNode.forget(); 627 } 628 629 void DrawTargetRecording::ClearRect(const Rect& aRect) { 630 MarkChanged(); 631 632 RecordEventSelf(RecordedClearRect(aRect)); 633 } 634 635 void DrawTargetRecording::CopySurface(SourceSurface* aSurface, 636 const IntRect& aSourceRect, 637 const IntPoint& aDestination) { 638 if (!aSurface) { 639 return; 640 } 641 642 MarkChanged(); 643 644 EnsureSurfaceStoredRecording(mRecorder, aSurface, "CopySurface"); 645 646 RecordEventSelf(RecordedCopySurface(aSurface, aSourceRect, aDestination)); 647 } 648 649 void DrawTargetRecording::PushClip(const Path* aPath) { 650 if (!aPath) { 651 return; 652 } 653 654 // The canvas doesn't have a clipRect API so we always end up in the generic 655 // path. The D2D backend doesn't have a good way of specializing rectangular 656 // clips so we take advantage of the fact that aPath is usually backed by a 657 // SkiaPath which implements AsRect() and specialize it here. 658 auto rect = aPath->AsRect(); 659 if (rect.isSome()) { 660 PushClipRect(rect.value()); 661 return; 662 } 663 664 RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); 665 RecordEventSelf(RecordedPushClip(ReferencePtr(pathRecording))); 666 } 667 668 void DrawTargetRecording::PushClipRect(const Rect& aRect) { 669 RecordEventSelf(RecordedPushClipRect(aRect)); 670 } 671 672 void DrawTargetRecording::PopClip() { 673 RecordEventSelfSkipFlushTransform(RecordedPopClip()); 674 } 675 676 bool DrawTargetRecording::RemoveAllClips() { 677 RecordEventSelfSkipFlushTransform(RecordedRemoveAllClips()); 678 return true; 679 } 680 681 void DrawTargetRecording::PushLayer(bool aOpaque, Float aOpacity, 682 SourceSurface* aMask, 683 const Matrix& aMaskTransform, 684 const IntRect& aBounds, 685 bool aCopyBackground) { 686 if (aMask) { 687 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer"); 688 } 689 690 RecordEventSelf(RecordedPushLayer(aOpaque, aOpacity, aMask, aMaskTransform, 691 aBounds, aCopyBackground)); 692 693 PushedLayer layer(GetPermitSubpixelAA()); 694 mPushedLayers.push_back(layer); 695 DrawTarget::SetPermitSubpixelAA(aOpaque); 696 } 697 698 void DrawTargetRecording::PushLayerWithBlend(bool aOpaque, Float aOpacity, 699 SourceSurface* aMask, 700 const Matrix& aMaskTransform, 701 const IntRect& aBounds, 702 bool aCopyBackground, 703 CompositionOp aCompositionOp) { 704 if (aMask) { 705 EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer"); 706 } 707 708 RecordEventSelf(RecordedPushLayerWithBlend(aOpaque, aOpacity, aMask, 709 aMaskTransform, aBounds, 710 aCopyBackground, aCompositionOp)); 711 712 PushedLayer layer(GetPermitSubpixelAA()); 713 mPushedLayers.push_back(layer); 714 DrawTarget::SetPermitSubpixelAA(aOpaque); 715 } 716 717 void DrawTargetRecording::PopLayer() { 718 MarkChanged(); 719 720 RecordEventSelfSkipFlushTransform(RecordedPopLayer()); 721 722 const PushedLayer& layer = mPushedLayers.back(); 723 DrawTarget::SetPermitSubpixelAA(layer.mOldPermitSubpixelAA); 724 mPushedLayers.pop_back(); 725 } 726 727 already_AddRefed<SourceSurface> 728 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData, 729 const IntSize& aSize, 730 int32_t aStride, 731 SurfaceFormat aFormat) const { 732 RefPtr<SourceSurface> surface = CreateDataSourceSurfaceWithStrideFromData( 733 aSize, aFormat, aStride, aData, aStride); 734 if (!surface) { 735 return nullptr; 736 } 737 738 return OptimizeSourceSurface(surface); 739 } 740 741 already_AddRefed<SourceSurface> DrawTargetRecording::OptimizeSourceSurface( 742 SourceSurface* aSurface) const { 743 // See if we have a previously optimized surface available. We have to do this 744 // check before the SurfaceType::RECORDING below, because aSurface might be a 745 // SurfaceType::RECORDING from another recorder we have previously optimized. 746 auto* userData = static_cast<RecordingSourceSurfaceUserData*>( 747 aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))); 748 if (userData) { 749 RefPtr<SourceSurface> strongRef(userData->optimizedSurface); 750 if (strongRef) { 751 return do_AddRef(strongRef); 752 } 753 } else { 754 if (!EnsureSurfaceStoredRecording(mRecorder, aSurface, 755 "OptimizeSourceSurface")) { 756 // Surface was already stored, but doesn't have UserData so must be one 757 // of our recording surfaces. 758 MOZ_ASSERT(aSurface->GetType() == SurfaceType::RECORDING); 759 return do_AddRef(aSurface); 760 } 761 762 userData = static_cast<RecordingSourceSurfaceUserData*>( 763 aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))); 764 MOZ_ASSERT(userData, 765 "User data should always have been set by " 766 "EnsureSurfaceStoredRecording."); 767 } 768 769 RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording( 770 aSurface->GetSize(), aSurface->GetFormat(), mRecorder, aSurface); 771 RecordEventSelfSkipFlushTransform( 772 RecordedOptimizeSourceSurface(aSurface, retSurf)); 773 userData->optimizedSurface = retSurf; 774 775 return retSurf.forget(); 776 } 777 778 already_AddRefed<SourceSurface> 779 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface( 780 const NativeSurface& aSurface) const { 781 MOZ_ASSERT(false); 782 return nullptr; 783 } 784 785 already_AddRefed<DrawTarget> 786 DrawTargetRecording::CreateSimilarDrawTargetWithBacking( 787 const IntSize& aSize, SurfaceFormat aFormat) const { 788 if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) { 789 // If the requested similar draw target is too big, then we should try to 790 // rasterize on the content side to avoid duplicating the effort when a 791 // blob image gets tiled. If we fail somehow to produce it, we can fall 792 // back to recording. 793 constexpr int32_t kRasterThreshold = 256 * 256 * 4; 794 int32_t stride = aSize.width * BytesPerPixel(aFormat); 795 int32_t surfaceBytes = aSize.height * stride; 796 if (surfaceBytes >= kRasterThreshold) { 797 auto surface = MakeRefPtr<SourceSurfaceSharedData>(); 798 if (surface->Init(aSize, stride, aFormat)) { 799 auto dt = MakeRefPtr<DrawTargetSkia>(); 800 if (dt->Init(std::move(surface))) { 801 return dt.forget(); 802 } else { 803 MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!"); 804 } 805 } 806 } 807 } 808 809 return CreateSimilarDrawTarget(aSize, aFormat); 810 } 811 812 already_AddRefed<DrawTarget> DrawTargetRecording::CreateSimilarDrawTarget( 813 const IntSize& aSize, SurfaceFormat aFormat) const { 814 RefPtr<DrawTargetRecording> similarDT; 815 if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) { 816 similarDT = 817 new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize), aFormat); 818 similarDT->SetOptimizeTransform(mOptimizeTransform); 819 RecordEventSelfSkipFlushTransform( 820 RecordedCreateSimilarDrawTarget(similarDT.get(), aSize, aFormat)); 821 } else if (XRE_IsContentProcess()) { 822 // Crash any content process that calls this function with arguments that 823 // would fail to create a similar draw target. We do this to root out bad 824 // callers. We don't want to crash any important processes though so for 825 // for those we'll just gracefully return nullptr. 826 MOZ_CRASH( 827 "Content-process DrawTargetRecording can't create requested similar " 828 "drawtarget"); 829 } 830 return similarDT.forget(); 831 } 832 833 bool DrawTargetRecording::CanCreateSimilarDrawTarget( 834 const IntSize& aSize, SurfaceFormat aFormat) const { 835 return mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat); 836 } 837 838 RefPtr<DrawTarget> DrawTargetRecording::CreateClippedDrawTarget( 839 const Rect& aBounds, SurfaceFormat aFormat) { 840 RefPtr<DrawTargetRecording> similarDT = 841 new DrawTargetRecording(this, mRect, aFormat); 842 similarDT->SetOptimizeTransform(mOptimizeTransform); 843 RecordEventSelf( 844 RecordedCreateClippedDrawTarget(similarDT.get(), aBounds, aFormat)); 845 similarDT->mTransform = similarDT->mRecordedTransform = mTransform; 846 return similarDT; 847 } 848 849 already_AddRefed<DrawTarget> 850 DrawTargetRecording::CreateSimilarDrawTargetForFilter( 851 const IntSize& aMaxSize, SurfaceFormat aFormat, FilterNode* aFilter, 852 FilterNode* aSource, const Rect& aSourceRect, const Point& aDestPoint) { 853 RefPtr<DrawTargetRecording> similarDT; 854 if (mFinalDT->CanCreateSimilarDrawTarget(aMaxSize, aFormat)) { 855 similarDT = new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aMaxSize), 856 aFormat); 857 similarDT->SetOptimizeTransform(mOptimizeTransform); 858 // RecordedCreateDrawTargetForFilter::PlayEvent uses the transform, despite 859 // the fact that the underlying DrawTarget does not. 860 RecordEventSelf(RecordedCreateDrawTargetForFilter(similarDT.get(), aMaxSize, 861 aFormat, aFilter, aSource, 862 aSourceRect, aDestPoint)); 863 } else if (XRE_IsContentProcess()) { 864 // See CreateSimilarDrawTarget 865 MOZ_CRASH( 866 "Content-process DrawTargetRecording can't create requested clipped " 867 "drawtarget"); 868 } 869 return similarDT.forget(); 870 } 871 872 already_AddRefed<PathBuilder> DrawTargetRecording::CreatePathBuilder( 873 FillRule aFillRule) const { 874 return MakeAndAddRef<PathBuilderRecording>(mFinalDT->GetBackendType(), 875 aFillRule); 876 } 877 878 already_AddRefed<GradientStops> DrawTargetRecording::CreateGradientStops( 879 GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode) const { 880 RefPtr<GradientStops> retStops = new GradientStopsRecording(mRecorder); 881 882 RecordEventSelfSkipFlushTransform( 883 RecordedGradientStopsCreation(retStops, aStops, aNumStops, aExtendMode)); 884 885 return retStops.forget(); 886 } 887 888 void DrawTargetRecording::SetTransform(const Matrix& aTransform) { 889 DrawTarget::SetTransform(aTransform); 890 if (!mOptimizeTransform) { 891 FlushTransform(); 892 } 893 } 894 895 void DrawTargetRecording::RecordTransform(const Matrix& aTransform) const { 896 RecordEventSelfSkipFlushTransform(RecordedSetTransform(aTransform)); 897 mRecordedTransform = aTransform; 898 } 899 900 void DrawTargetRecording::SetPermitSubpixelAA(bool aPermitSubpixelAA) { 901 if (aPermitSubpixelAA == mPermitSubpixelAA) { 902 return; 903 } 904 DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA); 905 RecordEventSelfSkipFlushTransform( 906 RecordedSetPermitSubpixelAA(aPermitSubpixelAA)); 907 } 908 909 already_AddRefed<PathRecording> DrawTargetRecording::EnsurePathStored( 910 const Path* aPath) { 911 RefPtr<PathRecording> pathRecording; 912 if (aPath->GetBackendType() == BackendType::RECORDING) { 913 pathRecording = 914 const_cast<PathRecording*>(static_cast<const PathRecording*>(aPath)); 915 if (!mRecorder->TryAddStoredObject(pathRecording)) { 916 // Path is already stored. 917 return pathRecording.forget(); 918 } 919 } else { 920 MOZ_ASSERT(!mRecorder->HasStoredObject(aPath)); 921 FillRule fillRule = aPath->GetFillRule(); 922 RefPtr<PathBuilderRecording> builderRecording = 923 new PathBuilderRecording(mFinalDT->GetBackendType(), fillRule); 924 aPath->StreamToSink(builderRecording); 925 pathRecording = builderRecording->Finish().downcast<PathRecording>(); 926 mRecorder->AddStoredObject(pathRecording); 927 } 928 929 // It's important that AddStoredObject or TryAddStoredObject is called before 930 // this because that will run any pending processing required by recorded 931 // objects that have been deleted off the main thread. 932 RecordEventSelfSkipFlushTransform(RecordedPathCreation(pathRecording.get())); 933 pathRecording->mStoredRecorders.push_back(mRecorder); 934 935 return pathRecording.forget(); 936 } 937 938 // This should only be called on the 'root' DrawTargetRecording. 939 // Calling it on a child DrawTargetRecordings will cause confusion. 940 void DrawTargetRecording::FlushItem(const IntRect& aBounds) { 941 mRecorder->FlushItem(aBounds); 942 // Reinitialize the recorder (FlushItem will write a new recording header) 943 // Tell the new recording about our draw target 944 // This code should match what happens in the DrawTargetRecording constructor. 945 MOZ_DIAGNOSTIC_ASSERT(mRecorder->GetRecorderType() == 946 RecorderType::WEBRENDER); 947 RecordEventSkipFlushTransform( 948 RecordedDrawTargetCreation(this, mFinalDT->GetBackendType(), mRect, 949 mFinalDT->GetFormat(), false, nullptr)); 950 // RecordedDrawTargetCreation can actually reuse the base DrawTarget for the 951 // recording, but we cannot conclude that from here, so force the transform 952 // to be recorded. 953 RecordTransform(mTransform); 954 mTransformDirty = false; 955 } 956 957 void DrawTargetRecording::EnsurePatternDependenciesStored( 958 const Pattern& aPattern) { 959 switch (aPattern.GetType()) { 960 case PatternType::COLOR: 961 // No dependencies here. 962 return; 963 case PatternType::LINEAR_GRADIENT: { 964 MOZ_ASSERT_IF( 965 static_cast<const LinearGradientPattern*>(&aPattern)->mStops, 966 mRecorder->HasStoredObject( 967 static_cast<const LinearGradientPattern*>(&aPattern)->mStops)); 968 return; 969 } 970 case PatternType::RADIAL_GRADIENT: { 971 MOZ_ASSERT_IF( 972 static_cast<const RadialGradientPattern*>(&aPattern)->mStops, 973 mRecorder->HasStoredObject( 974 static_cast<const RadialGradientPattern*>(&aPattern)->mStops)); 975 return; 976 } 977 case PatternType::CONIC_GRADIENT: { 978 MOZ_ASSERT_IF( 979 static_cast<const ConicGradientPattern*>(&aPattern)->mStops, 980 mRecorder->HasStoredObject( 981 static_cast<const ConicGradientPattern*>(&aPattern)->mStops)); 982 return; 983 } 984 case PatternType::SURFACE: { 985 const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aPattern); 986 EnsureSurfaceStoredRecording(mRecorder, pat->mSurface, 987 "EnsurePatternDependenciesStored"); 988 return; 989 } 990 } 991 } 992 993 } // namespace gfx 994 } // namespace mozilla