tor-browser

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

ISurfaceProvider.h (11730B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /**
      7 * An interface for objects which can either store a surface or dynamically
      8 * generate one, and various implementations.
      9 */
     10 
     11 #ifndef mozilla_image_ISurfaceProvider_h
     12 #define mozilla_image_ISurfaceProvider_h
     13 
     14 #include "mozilla/Attributes.h"
     15 #include "mozilla/Maybe.h"
     16 #include "mozilla/MemoryReporting.h"
     17 #include "mozilla/NotNull.h"
     18 #include "mozilla/TimeStamp.h"
     19 #include "mozilla/gfx/2D.h"
     20 #include "mozilla/image/WebRenderImageProvider.h"
     21 
     22 #include "imgFrame.h"
     23 #include "SurfaceCache.h"
     24 
     25 namespace mozilla {
     26 namespace image {
     27 
     28 class CachedSurface;
     29 class DrawableSurface;
     30 
     31 /**
     32 * An interface for objects which can either store a surface or dynamically
     33 * generate one.
     34 */
     35 class ISurfaceProvider : public WebRenderImageProvider {
     36 public:
     37  // Subclasses may or may not be XPCOM classes, so we just require that they
     38  // implement AddRef and Release.
     39  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
     40 
     41  /// @return key data used for identifying which image this ISurfaceProvider is
     42  /// associated with in the surface cache.
     43  ImageKey GetImageKey() const { return mImageKey; }
     44 
     45  /// @return key data used to uniquely identify this ISurfaceProvider's cache
     46  /// entry in the surface cache.
     47  const SurfaceKey& GetSurfaceKey() const { return mSurfaceKey; }
     48 
     49  /// @return a drawable reference to a surface.
     50  DrawableSurface Surface();
     51 
     52  /// @return true if DrawableRef() will return a completely decoded surface.
     53  virtual bool IsFinished() const = 0;
     54 
     55  /// @return true if the underlying decoder is currently fully decoded. For
     56  /// animated images, this means that at least every frame has been decoded
     57  /// at least once. It does not guarantee that all of the frames are present,
     58  /// as the surface provider has the option to discard as it deems necessary.
     59  virtual bool IsFullyDecoded() const { return IsFinished(); }
     60 
     61  /// @return the number of bytes of memory this ISurfaceProvider is expected to
     62  /// require. Optimizations may result in lower real memory usage. Trivial
     63  /// overhead is ignored. Because this value is used in bookkeeping, it's
     64  /// important that it be constant over the lifetime of this object.
     65  virtual size_t LogicalSizeInBytes() const = 0;
     66 
     67  typedef imgFrame::AddSizeOfCbData AddSizeOfCbData;
     68  typedef imgFrame::AddSizeOfCb AddSizeOfCb;
     69 
     70  /// @return the actual number of bytes of memory this ISurfaceProvider is
     71  /// using. May vary over the lifetime of the ISurfaceProvider. The default
     72  /// implementation is appropriate for static ISurfaceProviders.
     73  virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
     74                                      const AddSizeOfCb& aCallback) {
     75    DrawableFrameRef ref = DrawableRef(/* aFrame = */ 0);
     76    if (!ref) {
     77      return;
     78    }
     79 
     80    ref->AddSizeOfExcludingThis(aMallocSizeOf, aCallback);
     81  }
     82 
     83  virtual void Reset() {}
     84  virtual void Advance(size_t aFrame) {}
     85  virtual bool MayAdvance() const { return false; }
     86  virtual void MarkMayAdvance() {}
     87 
     88  /// @return the availability state of this ISurfaceProvider, which indicates
     89  /// whether DrawableRef() could successfully return a surface. Should only be
     90  /// called from SurfaceCache code as it relies on SurfaceCache for
     91  /// synchronization.
     92  AvailabilityState& Availability() { return mAvailability; }
     93  const AvailabilityState& Availability() const { return mAvailability; }
     94 
     95 protected:
     96  ISurfaceProvider(const ImageKey aImageKey, const SurfaceKey& aSurfaceKey,
     97                   AvailabilityState aAvailability)
     98      : WebRenderImageProvider(aImageKey),
     99        mImageKey(aImageKey),
    100        mSurfaceKey(aSurfaceKey),
    101        mAvailability(aAvailability) {
    102    MOZ_ASSERT(aImageKey, "Must have a valid image key");
    103  }
    104 
    105  virtual ~ISurfaceProvider() {}
    106 
    107  /// @return an eagerly computed drawable reference to a surface. For
    108  /// dynamically generated animation surfaces, @aFrame specifies the 0-based
    109  /// index of the desired frame.
    110  virtual DrawableFrameRef DrawableRef(size_t aFrame) = 0;
    111 
    112  /// @return an imgFrame at the 0-based index of the desired frame, as
    113  /// specified by @aFrame. Only applies for animated images.
    114  virtual already_AddRefed<imgFrame> GetFrame(size_t aFrame) {
    115    MOZ_ASSERT_UNREACHABLE("Surface provider does not support direct access!");
    116    return nullptr;
    117  }
    118 
    119  /// @return true if this ISurfaceProvider is locked. (@see SetLocked())
    120  /// Should only be called from SurfaceCache code as it relies on SurfaceCache
    121  /// for synchronization.
    122  virtual bool IsLocked() const = 0;
    123 
    124  /// If @aLocked is true, hint that this ISurfaceProvider is in use and it
    125  /// should avoid releasing its resources. Should only be called from
    126  /// SurfaceCache code as it relies on SurfaceCache for synchronization.
    127  virtual void SetLocked(bool aLocked) = 0;
    128 
    129 private:
    130  friend class CachedSurface;
    131  friend class DrawableSurface;
    132 
    133  const ImageKey mImageKey;
    134  const SurfaceKey mSurfaceKey;
    135  AvailabilityState mAvailability;
    136 };
    137 
    138 /**
    139 * A reference to a surface (stored in an imgFrame) that holds the surface in
    140 * memory, guaranteeing that it can be drawn. If you have a DrawableSurface
    141 * |surf| and |if (surf)| returns true, then calls to |surf->Draw()| and
    142 * |surf->GetSourceSurface()| are guaranteed to succeed.
    143 *
    144 * Note that the surface may be computed lazily, so a DrawableSurface should not
    145 * be dereferenced (i.e., operator->() should not be called) until you're
    146 * sure that you want to draw it.
    147 */
    148 class MOZ_STACK_CLASS DrawableSurface final {
    149 public:
    150  DrawableSurface() : mHaveSurface(false) {}
    151 
    152  explicit DrawableSurface(NotNull<ISurfaceProvider*> aProvider)
    153      : mProvider(aProvider), mHaveSurface(true) {}
    154 
    155  DrawableSurface(DrawableSurface&& aOther)
    156      : mDrawableRef(std::move(aOther.mDrawableRef)),
    157        mProvider(std::move(aOther.mProvider)),
    158        mHaveSurface(aOther.mHaveSurface) {
    159    aOther.mHaveSurface = false;
    160  }
    161 
    162  DrawableSurface& operator=(DrawableSurface&& aOther) {
    163    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
    164    mDrawableRef = std::move(aOther.mDrawableRef);
    165    mProvider = std::move(aOther.mProvider);
    166    mHaveSurface = aOther.mHaveSurface;
    167    aOther.mHaveSurface = false;
    168    return *this;
    169  }
    170 
    171  /**
    172   * If this DrawableSurface is dynamically generated from an animation, attempt
    173   * to seek to frame @aFrame, where @aFrame is a 0-based index into the frames
    174   * of the animation. Otherwise, nothing will blow up at runtime, but we assert
    175   * in debug builds, since calling this in an unexpected situation probably
    176   * indicates a bug.
    177   *
    178   * @return a successful result if we could obtain frame @aFrame. Note that
    179   * |mHaveSurface| being true means that we're guaranteed to have *some* frame,
    180   * so the caller can dereference this DrawableSurface even if Seek() fails,
    181   * but while nothing will blow up, the frame won't be the one they expect.
    182   */
    183  nsresult Seek(size_t aFrame) {
    184    MOZ_ASSERT(mHaveSurface, "Trying to seek an empty DrawableSurface?");
    185 
    186    if (!mProvider) {
    187      MOZ_ASSERT_UNREACHABLE("Trying to seek a static DrawableSurface?");
    188      return NS_ERROR_FAILURE;
    189    }
    190 
    191    mDrawableRef = mProvider->DrawableRef(aFrame);
    192 
    193    return mDrawableRef ? NS_OK : NS_ERROR_FAILURE;
    194  }
    195 
    196  already_AddRefed<imgFrame> GetFrame(size_t aFrame) {
    197    MOZ_ASSERT(mHaveSurface, "Trying to get on an empty DrawableSurface?");
    198 
    199    if (!mProvider) {
    200      MOZ_ASSERT_UNREACHABLE("Trying to get on a static DrawableSurface?");
    201      return nullptr;
    202    }
    203 
    204    return mProvider->GetFrame(aFrame);
    205  }
    206 
    207  void Reset() {
    208    if (!mProvider) {
    209      MOZ_ASSERT_UNREACHABLE("Trying to reset a static DrawableSurface?");
    210      return;
    211    }
    212 
    213    mProvider->Reset();
    214  }
    215 
    216  void Advance(size_t aFrame) {
    217    if (!mProvider) {
    218      MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
    219      return;
    220    }
    221 
    222    mProvider->Advance(aFrame);
    223  }
    224 
    225  bool MayAdvance() const {
    226    if (!mProvider) {
    227      MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
    228      return false;
    229    }
    230 
    231    return mProvider->MayAdvance();
    232  }
    233 
    234  void MarkMayAdvance() {
    235    if (!mProvider) {
    236      MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
    237      return;
    238    }
    239 
    240    mProvider->MarkMayAdvance();
    241  }
    242 
    243  bool IsFullyDecoded() const {
    244    if (!mProvider) {
    245      MOZ_ASSERT_UNREACHABLE(
    246          "Trying to check decoding state of a static DrawableSurface?");
    247      return false;
    248    }
    249 
    250    return mProvider->IsFullyDecoded();
    251  }
    252 
    253  void TakeProvider(WebRenderImageProvider** aOutProvider) {
    254    mProvider.forget(aOutProvider);
    255  }
    256 
    257  explicit operator bool() const { return mHaveSurface; }
    258  imgFrame* operator->() { return DrawableRef().get(); }
    259 
    260 private:
    261  DrawableSurface(const DrawableSurface& aOther) = delete;
    262  DrawableSurface& operator=(const DrawableSurface& aOther) = delete;
    263 
    264  DrawableFrameRef& DrawableRef() {
    265    MOZ_ASSERT(mHaveSurface);
    266 
    267    // If we weren't created with a DrawableFrameRef directly, we should've been
    268    // created with an ISurfaceProvider which can give us one. Note that if
    269    // Seek() has been called, we'll already have a DrawableFrameRef, so we
    270    // won't need to get one here.
    271    if (!mDrawableRef) {
    272      MOZ_ASSERT(mProvider);
    273      mDrawableRef = mProvider->DrawableRef(/* aFrame = */ 0);
    274    }
    275 
    276    MOZ_ASSERT(mDrawableRef);
    277    return mDrawableRef;
    278  }
    279 
    280  DrawableFrameRef mDrawableRef;
    281  RefPtr<ISurfaceProvider> mProvider;
    282  bool mHaveSurface;
    283 };
    284 
    285 // Surface() is implemented here so that DrawableSurface's definition is
    286 // visible.
    287 inline DrawableSurface ISurfaceProvider::Surface() {
    288  return DrawableSurface(WrapNotNull(this));
    289 }
    290 
    291 /**
    292 * An ISurfaceProvider that stores a single surface.
    293 */
    294 class SimpleSurfaceProvider final : public ISurfaceProvider {
    295 public:
    296  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SimpleSurfaceProvider, override)
    297 
    298  SimpleSurfaceProvider(const ImageKey aImageKey, const SurfaceKey& aSurfaceKey,
    299                        NotNull<imgFrame*> aSurface)
    300      : ISurfaceProvider(aImageKey, aSurfaceKey,
    301                         AvailabilityState::StartAvailable()),
    302        mSurface(aSurface) {
    303    MOZ_ASSERT(aSurfaceKey.Size() == mSurface->GetSize());
    304  }
    305 
    306  bool IsFinished() const override { return mSurface->IsFinished(); }
    307 
    308  size_t LogicalSizeInBytes() const override {
    309    gfx::IntSize size = mSurface->GetSize();
    310    return size.width * size.height * mSurface->GetBytesPerPixel();
    311  }
    312 
    313  nsresult UpdateKey(layers::RenderRootStateManager* aManager,
    314                     wr::IpcResourceUpdateQueue& aResources,
    315                     wr::ImageKey& aKey) override;
    316 
    317  void InvalidateSurface() override;
    318 
    319 protected:
    320  DrawableFrameRef DrawableRef(size_t aFrame) override {
    321    MOZ_ASSERT(aFrame == 0,
    322               "Requesting an animation frame from a SimpleSurfaceProvider?");
    323    return mSurface->DrawableRef();
    324  }
    325 
    326  bool IsLocked() const override { return bool(mLockRef); }
    327 
    328  void SetLocked(bool aLocked) override {
    329    if (aLocked == IsLocked()) {
    330      return;  // Nothing changed.
    331    }
    332 
    333    // If we're locked, hold a DrawableFrameRef to |mSurface|, which will keep
    334    // any volatile buffer it owns in memory.
    335    mLockRef = aLocked ? mSurface->DrawableRef() : DrawableFrameRef();
    336  }
    337 
    338 private:
    339  virtual ~SimpleSurfaceProvider() {}
    340 
    341  NotNull<RefPtr<imgFrame>> mSurface;
    342  DrawableFrameRef mLockRef;
    343  bool mDirty = false;
    344 };
    345 
    346 }  // namespace image
    347 }  // namespace mozilla
    348 
    349 #endif  // mozilla_image_ISurfaceProvider_h