Bug 1766413 [wpt PR 33787] - Fix some cases of "ref test" to be "reftest", a=testonly
[gecko.git] / image / ISurfaceProvider.h
blob03ab713238acdced6eac146beed3c101884bb976
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/. */
6 /**
7 * An interface for objects which can either store a surface or dynamically
8 * generate one, and various implementations.
9 */
11 #ifndef mozilla_image_ISurfaceProvider_h
12 #define mozilla_image_ISurfaceProvider_h
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"
22 #include "imgFrame.h"
23 #include "SurfaceCache.h"
25 namespace mozilla {
26 namespace image {
28 class CachedSurface;
29 class DrawableSurface;
31 /**
32 * An interface for objects which can either store a surface or dynamically
33 * generate one.
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
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; }
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; }
49 /// @return a drawable reference to a surface.
50 DrawableSurface Surface();
52 /// @return true if DrawableRef() will return a completely decoded surface.
53 virtual bool IsFinished() const = 0;
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(); }
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;
67 typedef imgFrame::AddSizeOfCbData AddSizeOfCbData;
68 typedef imgFrame::AddSizeOfCb AddSizeOfCb;
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;
80 ref->AddSizeOfExcludingThis(aMallocSizeOf, aCallback);
83 virtual void Reset() {}
84 virtual void Advance(size_t aFrame) {}
85 virtual bool MayAdvance() const { return false; }
86 virtual void MarkMayAdvance() {}
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; }
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");
105 virtual ~ISurfaceProvider() {}
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;
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;
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;
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;
129 private:
130 friend class CachedSurface;
131 friend class DrawableSurface;
133 const ImageKey mImageKey;
134 const SurfaceKey mSurfaceKey;
135 AvailabilityState mAvailability;
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.
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.
148 class MOZ_STACK_CLASS DrawableSurface final {
149 public:
150 DrawableSurface() : mHaveSurface(false) {}
152 explicit DrawableSurface(NotNull<ISurfaceProvider*> aProvider)
153 : mProvider(aProvider), mHaveSurface(true) {}
155 DrawableSurface(DrawableSurface&& aOther)
156 : mDrawableRef(std::move(aOther.mDrawableRef)),
157 mProvider(std::move(aOther.mProvider)),
158 mHaveSurface(aOther.mHaveSurface) {
159 aOther.mHaveSurface = false;
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;
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.
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.
183 nsresult Seek(size_t aFrame) {
184 MOZ_ASSERT(mHaveSurface, "Trying to seek an empty DrawableSurface?");
186 if (!mProvider) {
187 MOZ_ASSERT_UNREACHABLE("Trying to seek a static DrawableSurface?");
188 return NS_ERROR_FAILURE;
191 mDrawableRef = mProvider->DrawableRef(aFrame);
193 return mDrawableRef ? NS_OK : NS_ERROR_FAILURE;
196 already_AddRefed<imgFrame> GetFrame(size_t aFrame) {
197 MOZ_ASSERT(mHaveSurface, "Trying to get on an empty DrawableSurface?");
199 if (!mProvider) {
200 MOZ_ASSERT_UNREACHABLE("Trying to get on a static DrawableSurface?");
201 return nullptr;
204 return mProvider->GetFrame(aFrame);
207 void Reset() {
208 if (!mProvider) {
209 MOZ_ASSERT_UNREACHABLE("Trying to reset a static DrawableSurface?");
210 return;
213 mProvider->Reset();
216 void Advance(size_t aFrame) {
217 if (!mProvider) {
218 MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
219 return;
222 mProvider->Advance(aFrame);
225 bool MayAdvance() const {
226 if (!mProvider) {
227 MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
228 return false;
231 return mProvider->MayAdvance();
234 void MarkMayAdvance() {
235 if (!mProvider) {
236 MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
237 return;
240 mProvider->MarkMayAdvance();
243 bool IsFullyDecoded() const {
244 if (!mProvider) {
245 MOZ_ASSERT_UNREACHABLE(
246 "Trying to check decoding state of a static DrawableSurface?");
247 return false;
250 return mProvider->IsFullyDecoded();
253 void TakeProvider(WebRenderImageProvider** aOutProvider) {
254 mProvider.forget(aOutProvider);
257 explicit operator bool() const { return mHaveSurface; }
258 imgFrame* operator->() { return DrawableRef().get(); }
260 private:
261 DrawableSurface(const DrawableSurface& aOther) = delete;
262 DrawableSurface& operator=(const DrawableSurface& aOther) = delete;
264 DrawableFrameRef& DrawableRef() {
265 MOZ_ASSERT(mHaveSurface);
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);
276 MOZ_ASSERT(mDrawableRef);
277 return mDrawableRef;
280 DrawableFrameRef mDrawableRef;
281 RefPtr<ISurfaceProvider> mProvider;
282 bool mHaveSurface;
285 // Surface() is implemented here so that DrawableSurface's definition is
286 // visible.
287 inline DrawableSurface ISurfaceProvider::Surface() {
288 return DrawableSurface(WrapNotNull(this));
292 * An ISurfaceProvider that stores a single surface.
294 class SimpleSurfaceProvider final : public ISurfaceProvider {
295 public:
296 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SimpleSurfaceProvider, override)
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());
306 bool IsFinished() const override { return mSurface->IsFinished(); }
308 size_t LogicalSizeInBytes() const override {
309 gfx::IntSize size = mSurface->GetSize();
310 return size.width * size.height * mSurface->GetBytesPerPixel();
313 nsresult UpdateKey(layers::RenderRootStateManager* aManager,
314 wr::IpcResourceUpdateQueue& aResources,
315 wr::ImageKey& aKey) override;
317 protected:
318 DrawableFrameRef DrawableRef(size_t aFrame) override {
319 MOZ_ASSERT(aFrame == 0,
320 "Requesting an animation frame from a SimpleSurfaceProvider?");
321 return mSurface->DrawableRef();
324 bool IsLocked() const override { return bool(mLockRef); }
326 void SetLocked(bool aLocked) override {
327 if (aLocked == IsLocked()) {
328 return; // Nothing changed.
331 // If we're locked, hold a DrawableFrameRef to |mSurface|, which will keep
332 // any volatile buffer it owns in memory.
333 mLockRef = aLocked ? mSurface->DrawableRef() : DrawableFrameRef();
336 private:
337 virtual ~SimpleSurfaceProvider() {}
339 NotNull<RefPtr<imgFrame>> mSurface;
340 DrawableFrameRef mLockRef;
343 } // namespace image
344 } // namespace mozilla
346 #endif // mozilla_image_ISurfaceProvider_h