ISurfaceProvider.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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. * An interface for objects which can either store a surface or dynamically
  7. * generate one, and various implementations.
  8. */
  9. #ifndef mozilla_image_ISurfaceProvider_h
  10. #define mozilla_image_ISurfaceProvider_h
  11. #include "mozilla/Attributes.h"
  12. #include "mozilla/Maybe.h"
  13. #include "mozilla/MemoryReporting.h"
  14. #include "mozilla/NotNull.h"
  15. #include "mozilla/TimeStamp.h"
  16. #include "mozilla/Variant.h"
  17. #include "mozilla/gfx/2D.h"
  18. #include "imgFrame.h"
  19. #include "SurfaceCache.h"
  20. namespace mozilla {
  21. namespace image {
  22. class CachedSurface;
  23. class DrawableSurface;
  24. /**
  25. * An interface for objects which can either store a surface or dynamically
  26. * generate one.
  27. */
  28. class ISurfaceProvider
  29. {
  30. public:
  31. // Subclasses may or may not be XPCOM classes, so we just require that they
  32. // implement AddRef and Release.
  33. NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
  34. NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
  35. /// @return key data used for identifying which image this ISurfaceProvider is
  36. /// associated with in the surface cache.
  37. ImageKey GetImageKey() const { return mImageKey; }
  38. /// @return key data used to uniquely identify this ISurfaceProvider's cache
  39. /// entry in the surface cache.
  40. const SurfaceKey& GetSurfaceKey() const { return mSurfaceKey; }
  41. /// @return a (potentially lazily computed) drawable reference to a surface.
  42. virtual DrawableSurface Surface();
  43. /// @return true if DrawableRef() will return a completely decoded surface.
  44. virtual bool IsFinished() const = 0;
  45. /// @return the number of bytes of memory this ISurfaceProvider is expected to
  46. /// require. Optimizations may result in lower real memory usage. Trivial
  47. /// overhead is ignored. Because this value is used in bookkeeping, it's
  48. /// important that it be constant over the lifetime of this object.
  49. virtual size_t LogicalSizeInBytes() const = 0;
  50. /// @return the actual number of bytes of memory this ISurfaceProvider is
  51. /// using. May vary over the lifetime of the ISurfaceProvider. The default
  52. /// implementation is appropriate for static ISurfaceProviders.
  53. virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
  54. size_t& aHeapSizeOut,
  55. size_t& aNonHeapSizeOut)
  56. {
  57. DrawableFrameRef ref = DrawableRef(/* aFrame = */ 0);
  58. if (!ref) {
  59. return;
  60. }
  61. ref->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, aNonHeapSizeOut);
  62. }
  63. /// @return the availability state of this ISurfaceProvider, which indicates
  64. /// whether DrawableRef() could successfully return a surface. Should only be
  65. /// called from SurfaceCache code as it relies on SurfaceCache for
  66. /// synchronization.
  67. AvailabilityState& Availability() { return mAvailability; }
  68. const AvailabilityState& Availability() const { return mAvailability; }
  69. protected:
  70. ISurfaceProvider(const ImageKey aImageKey,
  71. const SurfaceKey& aSurfaceKey,
  72. AvailabilityState aAvailability)
  73. : mImageKey(aImageKey)
  74. , mSurfaceKey(aSurfaceKey)
  75. , mAvailability(aAvailability)
  76. {
  77. MOZ_ASSERT(aImageKey, "Must have a valid image key");
  78. }
  79. virtual ~ISurfaceProvider() { }
  80. /// @return an eagerly computed drawable reference to a surface. For
  81. /// dynamically generated animation surfaces, @aFrame specifies the 0-based
  82. /// index of the desired frame.
  83. virtual DrawableFrameRef DrawableRef(size_t aFrame) = 0;
  84. /// @return true if this ISurfaceProvider is locked. (@see SetLocked())
  85. /// Should only be called from SurfaceCache code as it relies on SurfaceCache
  86. /// for synchronization.
  87. virtual bool IsLocked() const = 0;
  88. /// If @aLocked is true, hint that this ISurfaceProvider is in use and it
  89. /// should avoid releasing its resources. Should only be called from
  90. /// SurfaceCache code as it relies on SurfaceCache for synchronization.
  91. virtual void SetLocked(bool aLocked) = 0;
  92. private:
  93. friend class CachedSurface;
  94. friend class DrawableSurface;
  95. const ImageKey mImageKey;
  96. const SurfaceKey mSurfaceKey;
  97. AvailabilityState mAvailability;
  98. };
  99. /**
  100. * A reference to a surface (stored in an imgFrame) that holds the surface in
  101. * memory, guaranteeing that it can be drawn. If you have a DrawableSurface
  102. * |surf| and |if (surf)| returns true, then calls to |surf->Draw()| and
  103. * |surf->GetSourceSurface()| are guaranteed to succeed.
  104. *
  105. * Note that the surface may be computed lazily, so a DrawableSurface should not
  106. * be dereferenced (i.e., operator->() should not be called) until you're
  107. * sure that you want to draw it.
  108. */
  109. class MOZ_STACK_CLASS DrawableSurface final
  110. {
  111. public:
  112. DrawableSurface() : mHaveSurface(false) { }
  113. explicit DrawableSurface(DrawableFrameRef&& aDrawableRef)
  114. : mDrawableRef(Move(aDrawableRef))
  115. , mHaveSurface(bool(mDrawableRef))
  116. { }
  117. explicit DrawableSurface(NotNull<ISurfaceProvider*> aProvider)
  118. : mProvider(aProvider)
  119. , mHaveSurface(true)
  120. { }
  121. DrawableSurface(DrawableSurface&& aOther)
  122. : mDrawableRef(Move(aOther.mDrawableRef))
  123. , mProvider(Move(aOther.mProvider))
  124. , mHaveSurface(aOther.mHaveSurface)
  125. {
  126. aOther.mHaveSurface = false;
  127. }
  128. DrawableSurface& operator=(DrawableSurface&& aOther)
  129. {
  130. MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
  131. mDrawableRef = Move(aOther.mDrawableRef);
  132. mProvider = Move(aOther.mProvider);
  133. mHaveSurface = aOther.mHaveSurface;
  134. aOther.mHaveSurface = false;
  135. return *this;
  136. }
  137. /**
  138. * If this DrawableSurface is dynamically generated from an animation, attempt
  139. * to seek to frame @aFrame, where @aFrame is a 0-based index into the frames
  140. * of the animation. Otherwise, nothing will blow up at runtime, but we assert
  141. * in debug builds, since calling this in an unexpected situation probably
  142. * indicates a bug.
  143. *
  144. * @return a successful result if we could obtain frame @aFrame. Note that
  145. * |mHaveSurface| being true means that we're guaranteed to have *some* frame,
  146. * so the caller can dereference this DrawableSurface even if Seek() fails,
  147. * but while nothing will blow up, the frame won't be the one they expect.
  148. */
  149. nsresult Seek(size_t aFrame)
  150. {
  151. MOZ_ASSERT(mHaveSurface, "Trying to seek an empty DrawableSurface?");
  152. if (!mProvider) {
  153. MOZ_ASSERT_UNREACHABLE("Trying to seek a static DrawableSurface?");
  154. return NS_ERROR_FAILURE;
  155. }
  156. mDrawableRef = mProvider->DrawableRef(aFrame);
  157. return mDrawableRef ? NS_OK : NS_ERROR_FAILURE;
  158. }
  159. explicit operator bool() const { return mHaveSurface; }
  160. imgFrame* operator->() { return DrawableRef().get(); }
  161. private:
  162. DrawableSurface(const DrawableSurface& aOther) = delete;
  163. DrawableSurface& operator=(const DrawableSurface& aOther) = delete;
  164. DrawableFrameRef& DrawableRef()
  165. {
  166. MOZ_ASSERT(mHaveSurface);
  167. // If we weren't created with a DrawableFrameRef directly, we should've been
  168. // created with an ISurfaceProvider which can give us one. Note that if
  169. // Seek() has been called, we'll already have a DrawableFrameRef, so we
  170. // won't need to get one here.
  171. if (!mDrawableRef) {
  172. MOZ_ASSERT(mProvider);
  173. mDrawableRef = mProvider->DrawableRef(/* aFrame = */ 0);
  174. }
  175. MOZ_ASSERT(mDrawableRef);
  176. return mDrawableRef;
  177. }
  178. DrawableFrameRef mDrawableRef;
  179. RefPtr<ISurfaceProvider> mProvider;
  180. bool mHaveSurface;
  181. };
  182. // Surface() is implemented here so that DrawableSurface's definition is
  183. // visible. This default implementation eagerly obtains a DrawableFrameRef for
  184. // the first frame and is intended for static ISurfaceProviders.
  185. inline DrawableSurface
  186. ISurfaceProvider::Surface()
  187. {
  188. return DrawableSurface(DrawableRef(/* aFrame = */ 0));
  189. }
  190. /**
  191. * An ISurfaceProvider that stores a single surface.
  192. */
  193. class SimpleSurfaceProvider final : public ISurfaceProvider
  194. {
  195. public:
  196. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SimpleSurfaceProvider, override)
  197. SimpleSurfaceProvider(const ImageKey aImageKey,
  198. const SurfaceKey& aSurfaceKey,
  199. NotNull<imgFrame*> aSurface)
  200. : ISurfaceProvider(aImageKey, aSurfaceKey,
  201. AvailabilityState::StartAvailable())
  202. , mSurface(aSurface)
  203. {
  204. MOZ_ASSERT(aSurfaceKey.Size() == mSurface->GetSize());
  205. }
  206. bool IsFinished() const override { return mSurface->IsFinished(); }
  207. size_t LogicalSizeInBytes() const override
  208. {
  209. gfx::IntSize size = mSurface->GetSize();
  210. return size.width * size.height * mSurface->GetBytesPerPixel();
  211. }
  212. protected:
  213. DrawableFrameRef DrawableRef(size_t aFrame) override
  214. {
  215. MOZ_ASSERT(aFrame == 0,
  216. "Requesting an animation frame from a SimpleSurfaceProvider?");
  217. return mSurface->DrawableRef();
  218. }
  219. bool IsLocked() const override { return bool(mLockRef); }
  220. void SetLocked(bool aLocked) override
  221. {
  222. if (aLocked == IsLocked()) {
  223. return; // Nothing changed.
  224. }
  225. // If we're locked, hold a DrawableFrameRef to |mSurface|, which will keep
  226. // any volatile buffer it owns in memory.
  227. mLockRef = aLocked ? mSurface->DrawableRef()
  228. : DrawableFrameRef();
  229. }
  230. private:
  231. virtual ~SimpleSurfaceProvider() { }
  232. NotNull<RefPtr<imgFrame>> mSurface;
  233. DrawableFrameRef mLockRef;
  234. };
  235. } // namespace image
  236. } // namespace mozilla
  237. #endif // mozilla_image_ISurfaceProvider_h