tor-browser

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

DrawEventRecorder.h (10976B)


      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 #ifndef MOZILLA_GFX_DRAWEVENTRECORDER_H_
      8 #define MOZILLA_GFX_DRAWEVENTRECORDER_H_
      9 
     10 #include "2D.h"
     11 #include "DrawEventRecorderTypes.h"
     12 #include "RecordedEvent.h"
     13 #include "RecordingTypes.h"
     14 
     15 #include <deque>
     16 #include <functional>
     17 #include <vector>
     18 
     19 #include "ImageContainer.h"
     20 #include "mozilla/DataMutex.h"
     21 #include "mozilla/ThreadSafeWeakPtr.h"
     22 #include "nsTHashMap.h"
     23 #include "nsTHashSet.h"
     24 #include "nsISupportsImpl.h"
     25 
     26 namespace mozilla {
     27 namespace layers {
     28 class CanvasChild;
     29 }  // namespace layers
     30 
     31 namespace gfx {
     32 
     33 class DrawTargetRecording;
     34 class PathRecording;
     35 class RecordedEvent;
     36 
     37 class DrawEventRecorderPrivate : public DrawEventRecorder {
     38 public:
     39  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPrivate, override)
     40 
     41  DrawEventRecorderPrivate();
     42  virtual ~DrawEventRecorderPrivate();
     43  RecorderType GetRecorderType() const override {
     44    return RecorderType::PRIVATE;
     45  }
     46  bool Finish() override {
     47    ClearResources();
     48    return true;
     49  }
     50  virtual void FlushItem(IntRect) {}
     51  virtual void DetachResources() {
     52    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
     53 
     54    nsTHashSet<ScaledFont*> fonts = std::move(mStoredFonts);
     55    for (const auto& font : fonts) {
     56      font->RemoveUserData(reinterpret_cast<UserDataKey*>(this));
     57    }
     58 
     59    // SourceSurfaces can be deleted off the main thread, so we use
     60    // ThreadSafeWeakPtrs to allow for this. RemoveUserData is thread safe.
     61    nsTHashMap<void*, ThreadSafeWeakPtr<SourceSurface>> surfaces =
     62        std::move(mStoredSurfaces);
     63    for (const auto& entry : surfaces) {
     64      RefPtr<SourceSurface> strongRef(entry.GetData());
     65      if (strongRef) {
     66        strongRef->RemoveUserData(reinterpret_cast<UserDataKey*>(this));
     67      }
     68    }
     69 
     70    // Now that we've detached we can't get any more pending deletions, so
     71    // processing now should mean we include all clean up operations.
     72    ProcessPendingDeletions();
     73  }
     74 
     75  void ClearResources() {
     76    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
     77    mStoredObjects.Clear();
     78    mStoredFontData.Clear();
     79    mScaledFonts.clear();
     80    mCurrentDT = nullptr;
     81  }
     82 
     83  template <class S>
     84  void WriteHeader(S& aStream) {
     85    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
     86    WriteElement(aStream, kMagicInt);
     87    WriteElement(aStream, kMajorRevision);
     88    WriteElement(aStream, kMinorRevision);
     89  }
     90 
     91  virtual void RecordEvent(const RecordedEvent& aEvent) = 0;
     92 
     93  void RecordEvent(const DrawTargetRecording* aDT,
     94                   const RecordedEvent& aEvent) {
     95    ReferencePtr dt = aDT;
     96    if (mCurrentDT != dt) {
     97      SetDrawTarget(dt);
     98    }
     99    RecordEvent(aEvent);
    100  }
    101 
    102  void SetDrawTarget(ReferencePtr aDT);
    103 
    104  void ClearDrawTarget(const DrawTargetRecording* aDT) {
    105    ReferencePtr dt = aDT;
    106    if (mCurrentDT == dt) {
    107      mCurrentDT = nullptr;
    108    }
    109  }
    110 
    111  void AddStoredObject(const ReferencePtr aObject) {
    112    ProcessPendingDeletions();
    113    mStoredObjects.Insert(aObject);
    114  }
    115 
    116  /**
    117   * This is a combination of HasStoredObject and AddStoredObject, so that we
    118   * only have to call ProcessPendingDeletions once, which involves locking.
    119   * @param aObject the object to store if not already stored
    120   * @return true if the object was not already stored, false if it was
    121   */
    122  bool TryAddStoredObject(const ReferencePtr aObject) {
    123    ProcessPendingDeletions();
    124    return mStoredObjects.EnsureInserted(aObject);
    125  }
    126 
    127  virtual void AddPendingDeletion(std::function<void()>&& aPendingDeletion) {
    128    auto lockedPendingDeletions = mPendingDeletions.Lock();
    129    lockedPendingDeletions->emplace_back(std::move(aPendingDeletion));
    130  }
    131 
    132  void RemoveStoredObject(const ReferencePtr aObject) {
    133    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    134    mStoredObjects.Remove(aObject);
    135  }
    136 
    137  /**
    138   * @param aUnscaledFont the UnscaledFont to increment the reference count for
    139   * @return the previous reference count
    140   */
    141  int32_t IncrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont) {
    142    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    143    int32_t& count = mUnscaledFontRefs.LookupOrInsert(aUnscaledFont, 0);
    144    return count++;
    145  }
    146 
    147  /**
    148   * Decrements the reference count for aUnscaledFont and, if count is now zero,
    149   * records its destruction.
    150   * @param aUnscaledFont the UnscaledFont to decrement the reference count for
    151   */
    152  void DecrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont);
    153 
    154  void AddScaledFont(ScaledFont* aFont) {
    155    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    156    if (mStoredFonts.EnsureInserted(aFont) && WantsExternalFonts()) {
    157      mScaledFonts.push_back(aFont);
    158    }
    159  }
    160 
    161  void RemoveScaledFont(ScaledFont* aFont) { mStoredFonts.Remove(aFont); }
    162 
    163  void AddSourceSurface(SourceSurface* aSurface) {
    164    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    165    mStoredSurfaces.InsertOrUpdate(aSurface, aSurface);
    166  }
    167 
    168  void RemoveSourceSurface(SourceSurface* aSurface) {
    169    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    170    mStoredSurfaces.Remove(aSurface);
    171  }
    172 
    173 #if defined(DEBUG)
    174  // Only used within debug assertions.
    175  bool HasStoredObject(const ReferencePtr aObject) {
    176    ProcessPendingDeletions();
    177    return mStoredObjects.Contains(aObject);
    178  }
    179 #endif
    180 
    181  void AddStoredFontData(const uint64_t aFontDataKey) {
    182    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    183    mStoredFontData.Insert(aFontDataKey);
    184  }
    185 
    186  bool HasStoredFontData(const uint64_t aFontDataKey) {
    187    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    188    return mStoredFontData.Contains(aFontDataKey);
    189  }
    190 
    191  bool WantsExternalFonts() const { return mExternalFonts; }
    192 
    193  virtual void StoreSourceSurfaceRecording(SourceSurface* aSurface,
    194                                           const char* aReason);
    195 
    196  virtual void StoreImageRecording(
    197      const RefPtr<layers::Image>& aImageOfSurfaceDescriptor,
    198      const char* aReasony) {
    199    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    200  }
    201 
    202  /**
    203   * Used when a source surface is destroyed, aSurface is a void* instead of a
    204   * SourceSurface* because this is called during the SourceSurface destructor,
    205   * so it is partially destructed and should not be accessed.
    206   * @param aSurface the surface whose destruction is being recorded
    207   */
    208  void RecordSourceSurfaceDestruction(void* aSurface);
    209 
    210  virtual void AddDependentSurface(uint64_t aDependencyId) {
    211    MOZ_CRASH("GFX: AddDependentSurface");
    212  }
    213 
    214  struct ExternalSurfaceEntry {
    215    RefPtr<SourceSurface> mSurface;
    216    int64_t mEventCount = -1;
    217  };
    218 
    219  using ExternalSurfacesHolder =
    220      DrawEventRecorderPrivate_ExternalSurfacesHolder;
    221 
    222  void TakeExternalSurfaces(ExternalSurfacesHolder& aSurfaces) {
    223    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    224    aSurfaces = std::move(mExternalSurfaces);
    225  }
    226 
    227  struct ExternalImageEntry {
    228    RefPtr<layers::Image> mImage;
    229    int64_t mEventCount = -1;
    230  };
    231 
    232  using ExternalImagesHolder = std::deque<ExternalImageEntry>;
    233 
    234  virtual already_AddRefed<layers::CanvasChild> GetCanvasChild() const {
    235    return nullptr;
    236  }
    237 
    238 protected:
    239  NS_DECL_OWNINGTHREAD
    240 
    241  void StoreExternalSurfaceRecording(SourceSurface* aSurface, uint64_t aKey);
    242 
    243  void StoreExternalImageRecording(
    244      const RefPtr<layers::Image>& aImageOfSurfaceDescriptor);
    245 
    246  void ProcessPendingDeletions() {
    247    NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
    248 
    249    PendingDeletionsVector pendingDeletions;
    250    {
    251      auto lockedPendingDeletions = mPendingDeletions.Lock();
    252      pendingDeletions.swap(*lockedPendingDeletions);
    253    }
    254    for (const auto& pendingDeletion : pendingDeletions) {
    255      pendingDeletion();
    256    }
    257  }
    258 
    259  virtual void Flush() = 0;
    260 
    261  nsTHashSet<const void*> mStoredObjects;
    262 
    263  using PendingDeletionsVector = std::vector<std::function<void()>>;
    264  DataMutex<PendingDeletionsVector> mPendingDeletions{
    265      "DrawEventRecorderPrivate::mPendingDeletions"};
    266 
    267  // It's difficult to track the lifetimes of UnscaledFonts directly, so we
    268  // instead track the number of recorded ScaledFonts that hold a reference to
    269  // an Unscaled font and use that as a proxy to the real lifetime. An
    270  // UnscaledFonts lifetime could be longer than this, but we only use the
    271  // ScaledFonts directly and if another uses an UnscaledFont we have destroyed
    272  // on the translation side, it will be recreated.
    273  nsTHashMap<const void*, int32_t> mUnscaledFontRefs;
    274 
    275  nsTHashSet<uint64_t> mStoredFontData;
    276  nsTHashSet<ScaledFont*> mStoredFonts;
    277  std::vector<RefPtr<ScaledFont>> mScaledFonts;
    278 
    279  // SourceSurfaces can get deleted off the main thread, so we hold a map of the
    280  // raw pointer to a ThreadSafeWeakPtr to protect against this.
    281  nsTHashMap<void*, ThreadSafeWeakPtr<SourceSurface>> mStoredSurfaces;
    282 
    283  ReferencePtr mCurrentDT;
    284  ExternalSurfacesHolder mExternalSurfaces;
    285  ExternalImagesHolder mExternalImages;
    286  bool mExternalFonts;
    287 };
    288 
    289 typedef std::function<void(MemStream& aStream,
    290                           std::vector<RefPtr<ScaledFont>>& aScaledFonts)>
    291    SerializeResourcesFn;
    292 
    293 // WARNING: This should not be used in its existing state because
    294 // it is likely to OOM because of large continguous allocations.
    295 class DrawEventRecorderMemory : public DrawEventRecorderPrivate {
    296 public:
    297  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory, override)
    298 
    299  /**
    300   * Constructs a DrawEventRecorder that stores the recording in memory.
    301   */
    302  DrawEventRecorderMemory();
    303  explicit DrawEventRecorderMemory(const SerializeResourcesFn& aSerialize);
    304 
    305  RecorderType GetRecorderType() const override { return RecorderType::MEMORY; }
    306 
    307  void RecordEvent(const RecordedEvent& aEvent) override;
    308 
    309  void AddDependentSurface(uint64_t aDependencyId) override;
    310 
    311  nsTHashSet<uint64_t>&& TakeDependentSurfaces();
    312 
    313  /**
    314   * @return the current size of the recording (in chars).
    315   */
    316  size_t RecordingSize();
    317 
    318  /**
    319   * Wipes the internal recording buffer, but the recorder does NOT forget which
    320   * objects it has recorded. This can be used so that a recording can be copied
    321   * and processed in chunks, releasing memory as it goes.
    322   */
    323  void WipeRecording();
    324  bool Finish() override;
    325  void FlushItem(IntRect) override;
    326 
    327  MemStream mOutputStream;
    328  /* The index stream is of the form:
    329   * ItemIndex { size_t dataEnd; size_t extraDataEnd; }
    330   * It gets concatenated to the end of mOutputStream in Finish()
    331   * The last size_t in the stream is offset of the begining of the
    332   * index.
    333   */
    334  MemStream mIndex;
    335 
    336 protected:
    337  virtual ~DrawEventRecorderMemory() = default;
    338 
    339 private:
    340  SerializeResourcesFn mSerializeCallback;
    341  nsTHashSet<uint64_t> mDependentSurfaces;
    342 
    343  void Flush() override;
    344 };
    345 
    346 }  // namespace gfx
    347 }  // namespace mozilla
    348 
    349 #endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */