tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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