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