Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / image / src / SurfaceCache.h
blob050e5f5195ed033ed47ef1d5cfa7aa38b1b5d242
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 * SurfaceCache is a service for caching temporary surfaces and decoded image
8 * data in imagelib.
9 */
11 #ifndef MOZILLA_IMAGELIB_SURFACECACHE_H_
12 #define MOZILLA_IMAGELIB_SURFACECACHE_H_
14 #include "mozilla/Maybe.h" // for Maybe
15 #include "mozilla/MemoryReporting.h" // for MallocSizeOf
16 #include "mozilla/HashFunctions.h" // for HashGeneric and AddToHash
17 #include "gfx2DGlue.h" // for gfxMemoryLocation
18 #include "gfxPoint.h" // for gfxSize
19 #include "nsCOMPtr.h" // for already_AddRefed
20 #include "mozilla/gfx/Point.h" // for mozilla::gfx::IntSize
21 #include "mozilla/gfx/2D.h" // for SourceSurface
22 #include "SVGImageContext.h" // for SVGImageContext
24 namespace mozilla {
25 namespace image {
27 class DrawableFrameRef;
28 class Image;
29 class imgFrame;
32 * ImageKey contains the information we need to look up all cached surfaces for
33 * a particular image.
35 typedef Image* ImageKey;
38 * SurfaceKey contains the information we need to look up a specific cached
39 * surface. Together with an ImageKey, this uniquely identifies the surface.
41 * Callers should construct a SurfaceKey using the appropriate helper function
42 * for their image type - either RasterSurfaceKey or VectorSurfaceKey.
44 class SurfaceKey
46 typedef gfx::IntSize IntSize;
48 public:
49 bool operator==(const SurfaceKey& aOther) const
51 return aOther.mSize == mSize &&
52 aOther.mSVGContext == mSVGContext &&
53 aOther.mAnimationTime == mAnimationTime &&
54 aOther.mFlags == mFlags;
57 uint32_t Hash() const
59 uint32_t hash = HashGeneric(mSize.width, mSize.height);
60 hash = AddToHash(hash, mSVGContext.map(HashSIC).valueOr(0));
61 hash = AddToHash(hash, mAnimationTime, mFlags);
62 return hash;
65 IntSize Size() const { return mSize; }
66 Maybe<SVGImageContext> SVGContext() const { return mSVGContext; }
67 float AnimationTime() const { return mAnimationTime; }
68 uint32_t Flags() const { return mFlags; }
70 SurfaceKey WithNewFlags(uint32_t aFlags) const
72 return SurfaceKey(mSize, mSVGContext, mAnimationTime, aFlags);
75 private:
76 SurfaceKey(const IntSize& aSize,
77 const Maybe<SVGImageContext>& aSVGContext,
78 const float aAnimationTime,
79 const uint32_t aFlags)
80 : mSize(aSize)
81 , mSVGContext(aSVGContext)
82 , mAnimationTime(aAnimationTime)
83 , mFlags(aFlags)
84 { }
86 static uint32_t HashSIC(const SVGImageContext& aSIC) {
87 return aSIC.Hash();
90 friend SurfaceKey RasterSurfaceKey(const IntSize&, uint32_t, uint32_t);
91 friend SurfaceKey VectorSurfaceKey(const IntSize&,
92 const Maybe<SVGImageContext>&,
93 float);
95 IntSize mSize;
96 Maybe<SVGImageContext> mSVGContext;
97 float mAnimationTime;
98 uint32_t mFlags;
101 inline SurfaceKey
102 RasterSurfaceKey(const gfx::IntSize& aSize,
103 uint32_t aFlags,
104 uint32_t aFrameNum)
106 return SurfaceKey(aSize, Nothing(), float(aFrameNum), aFlags);
109 inline SurfaceKey
110 VectorSurfaceKey(const gfx::IntSize& aSize,
111 const Maybe<SVGImageContext>& aSVGContext,
112 float aAnimationTime)
114 // We don't care about aFlags for VectorImage because none of the flags we
115 // have right now influence VectorImage's rendering. If we add a new flag that
116 // *does* affect how a VectorImage renders, we'll have to change this.
117 return SurfaceKey(aSize, aSVGContext, aAnimationTime, 0);
120 enum class Lifetime : uint8_t {
121 Transient,
122 Persistent
125 enum class InsertOutcome : uint8_t {
126 SUCCESS, // Success (but see Insert documentation).
127 FAILURE, // Couldn't insert (e.g., for capacity reasons).
128 FAILURE_ALREADY_PRESENT // A surface with the same key is already present.
132 * SurfaceCache is an imagelib-global service that allows caching of temporary
133 * surfaces. Surfaces normally expire from the cache automatically if they go
134 * too long without being accessed.
136 * SurfaceCache does not hold surfaces directly; instead, it holds imgFrame
137 * objects, which hold surfaces but also layer on additional features specific
138 * to imagelib's needs like animation, padding support, and transparent support
139 * for volatile buffers.
141 * Sometime it's useful to temporarily prevent surfaces from expiring from the
142 * cache. This is most often because losing the data could harm the user
143 * experience (for example, we often don't want to allow surfaces that are
144 * currently visible to expire) or because it's not possible to rematerialize
145 * the surface. SurfaceCache supports this through the use of image locking and
146 * surface lifetimes; see the comments for Insert() and LockImage() for more
147 * details.
149 * Any image which stores surfaces in the SurfaceCache *must* ensure that it
150 * calls RemoveImage() before it is destroyed. See the comments for
151 * RemoveImage() for more details.
153 struct SurfaceCache
155 typedef gfx::IntSize IntSize;
158 * Initialize static data. Called during imagelib module initialization.
160 static void Initialize();
163 * Release static data. Called during imagelib module shutdown.
165 static void Shutdown();
168 * Look up the imgFrame containing a surface in the cache and returns a
169 * drawable reference to that imgFrame.
171 * If the image associated with the surface is locked, then the surface will
172 * be locked before it is returned.
174 * If the imgFrame was found in the cache, but had stored its surface in a
175 * volatile buffer which was discarded by the OS, then it is automatically
176 * removed from the cache and an empty DrawableFrameRef is returned. Note that
177 * this will never happen to persistent surfaces associated with a locked
178 * image; the cache keeps a strong reference to such surfaces internally.
180 * @param aImageKey Key data identifying which image the surface belongs to.
181 * @param aSurfaceKey Key data which uniquely identifies the requested surface.
182 * @param aAlternateFlags If not Nothing(), a different set of flags than the
183 * ones specified in @aSurfaceKey which are also
184 * acceptable to the caller. This is more efficient
185 * than calling Lookup() twice, which requires taking a
186 * lock each time.
188 * @return a DrawableFrameRef to the imgFrame wrapping the requested surface,
189 * or an empty DrawableFrameRef if not found.
191 static DrawableFrameRef Lookup(const ImageKey aImageKey,
192 const SurfaceKey& aSurfaceKey,
193 const Maybe<uint32_t>& aAlternateFlags
194 = Nothing());
197 * Looks up the best matching surface in the cache and returns a drawable
198 * reference to the imgFrame containing it.
200 * Returned surfaces may vary from the requested surface only in terms of
201 * size, unless @aAlternateFlags is specified.
203 * If the image associated with the surface is locked, then the surface will
204 * be locked before it is returned.
206 * @param aImageKey Key data identifying which image the surface belongs to.
207 * @param aSurfaceKey Key data which identifies the ideal surface to return.
208 * @param aAlternateFlags If not Nothing(), a different set of flags than the
209 * ones specified in @aSurfaceKey which are also
210 * acceptable to the caller. This is much more
211 * efficient than calling LookupBestMatch() twice.
213 * @return a DrawableFrameRef to the imgFrame wrapping a surface similar to
214 * the requested surface, or an empty DrawableFrameRef if not found.
216 static DrawableFrameRef LookupBestMatch(const ImageKey aImageKey,
217 const SurfaceKey& aSurfaceKey,
218 const Maybe<uint32_t>& aAlternateFlags
219 = Nothing());
222 * Insert a surface into the cache. If a surface with the same ImageKey and
223 * SurfaceKey is already in the cache, Insert returns FAILURE_ALREADY_PRESENT.
225 * Each surface in the cache has a lifetime, either Transient or Persistent.
226 * Transient surfaces can expire from the cache at any time. Persistent
227 * surfaces, on the other hand, will never expire as long as they remain
228 * locked, but if they become unlocked, can expire just like transient
229 * surfaces. When it is first inserted, a persistent surface is locked if its
230 * associated image is locked. When that image is later unlocked, the surface
231 * becomes unlocked too. To become locked again at that point, two things must
232 * happen: the image must become locked again (via LockImage()), and the
233 * surface must be touched again (via one of the Lookup() functions).
235 * All of this means that a very particular procedure has to be followed for
236 * surfaces which cannot be rematerialized. First, they must be inserted
237 * with a persistent lifetime *after* the image is locked with LockImage(); if
238 * you use the other order, the surfaces might expire before LockImage() gets
239 * called or before the surface is touched again by Lookup(). Second, the
240 * image they are associated with must never be unlocked.
242 * If a surface cannot be rematerialized, it may be important to know whether
243 * it was inserted into the cache successfully. Insert() returns FAILURE if it
244 * failed to insert the surface, which could happen because of capacity
245 * reasons, or because it was already freed by the OS. If you aren't inserting
246 * a surface with persistent lifetime, or if the surface isn't associated with
247 * a locked image, checking for SUCCESS or FAILURE is useless: the surface
248 * might expire immediately after being inserted, even though Insert()
249 * returned SUCCESS. Thus, many callers do not need to check the result of
250 * Insert() at all.
252 * @param aTarget The new surface (wrapped in an imgFrame) to insert into
253 * the cache.
254 * @param aImageKey Key data identifying which image the surface belongs to.
255 * @param aSurfaceKey Key data which uniquely identifies the requested surface.
256 * @param aLifetime Whether this is a transient surface that can always be
257 * allowed to expire, or a persistent surface that
258 * shouldn't expire if the image is locked.
259 * @return SUCCESS if the surface was inserted successfully. (But see above
260 * for more information about when you should check this.)
261 * FAILURE if the surface could not be inserted, e.g. for capacity
262 * reasons. (But see above for more information about when you
263 * should check this.)
264 * FAILURE_ALREADY_PRESENT if a surface with the same ImageKey and
265 * SurfaceKey already exists in the cache.
267 static InsertOutcome Insert(imgFrame* aSurface,
268 const ImageKey aImageKey,
269 const SurfaceKey& aSurfaceKey,
270 Lifetime aLifetime);
273 * Checks if a surface of a given size could possibly be stored in the cache.
274 * If CanHold() returns false, Insert() will always fail to insert the
275 * surface, but the inverse is not true: Insert() may take more information
276 * into account than just image size when deciding whether to cache the
277 * surface, so Insert() may still fail even if CanHold() returns true.
279 * Use CanHold() to avoid the need to create a temporary surface when we know
280 * for sure the cache can't hold it.
282 * @param aSize The dimensions of a surface in pixels.
283 * @param aBytesPerPixel How many bytes each pixel of the surface requires.
284 * Defaults to 4, which is appropriate for RGBA or RGBX
285 * images.
287 * @return false if the surface cache can't hold a surface of that size.
289 static bool CanHold(const IntSize& aSize, uint32_t aBytesPerPixel = 4);
290 static bool CanHold(size_t aSize);
293 * Locks an image. Any of the image's persistent surfaces which are either
294 * inserted or accessed while the image is locked will not expire.
296 * Locking an image does not automatically lock that image's existing
297 * surfaces. A call to LockImage() guarantees that persistent surfaces which
298 * are inserted afterward will not expire before the next call to
299 * UnlockImage() or UnlockSurfaces() for that image. Surfaces that are
300 * accessed via Lookup() or LookupBestMatch() after a LockImage() call will
301 * also not expire until the next UnlockImage() or UnlockSurfaces() call for
302 * that image. Any other surfaces owned by the image may expire at any time,
303 * whether they are persistent or transient.
305 * Regardless of locking, any of an image's surfaces may be removed using
306 * RemoveSurface(), and all of an image's surfaces are removed by
307 * RemoveImage(), whether the image is locked or not.
309 * It's safe to call LockImage() on an image that's already locked; this has
310 * no effect.
312 * You must always unlock any image you lock. You may do this explicitly by
313 * calling UnlockImage(), or implicitly by calling RemoveImage(). Since you're
314 * required to call RemoveImage() when you destroy an image, this doesn't
315 * impose any additional requirements, but it's preferable to call
316 * UnlockImage() earlier if it's possible.
318 * @param aImageKey The image to lock.
320 static void LockImage(const ImageKey aImageKey);
323 * Unlocks an image, allowing any of its surfaces to expire at any time.
325 * It's OK to call UnlockImage() on an image that's already unlocked; this has
326 * no effect.
328 * @param aImageKey The image to unlock.
330 static void UnlockImage(const ImageKey aImageKey);
333 * Unlocks the existing surfaces of an image, allowing them to expire at any
334 * time.
336 * This does not unlock the image itself, so accessing the surfaces via
337 * Lookup() or LookupBestMatch() will lock them again, and prevent them from
338 * expiring.
340 * This is intended to be used in situations where it's no longer clear that
341 * all of the persistent surfaces owned by an image are needed. Calling
342 * UnlockSurfaces() and then taking some action that will cause Lookup() to
343 * touch any surfaces that are still useful will permit the remaining surfaces
344 * to expire from the cache.
346 * If the image is unlocked, this has no effect.
348 * @param aImageKey The image which should have its existing surfaces
349 * unlocked.
351 static void UnlockSurfaces(const ImageKey aImageKey);
354 * Removes a surface from the cache, if it's present. If it's not present,
355 * RemoveSurface() has no effect.
357 * Use this function to remove individual surfaces that have become invalid.
358 * Prefer RemoveImage() or DiscardAll() when they're applicable, as they have
359 * much better performance than calling this function repeatedly.
361 * @param aImageKey Key data identifying which image the surface belongs to.
362 * @param aSurfaceKey Key data which uniquely identifies the requested surface.
364 static void RemoveSurface(const ImageKey aImageKey,
365 const SurfaceKey& aSurfaceKey);
368 * Removes all cached surfaces associated with the given image from the cache.
369 * If the image is locked, it is automatically unlocked.
371 * This MUST be called, at a minimum, when an Image which could be storing
372 * surfaces in the surface cache is destroyed. If another image were allocated
373 * at the same address it could result in subtle, difficult-to-reproduce bugs.
375 * @param aImageKey The image which should be removed from the cache.
377 static void RemoveImage(const ImageKey aImageKey);
380 * Evicts all evictable surfaces from the cache.
382 * All surfaces are evictable except for persistent surfaces associated with
383 * locked images. Non-evictable surfaces can only be removed by
384 * RemoveSurface() or RemoveImage().
386 static void DiscardAll();
389 * Computes the size of the surfaces stored for the given image at the given
390 * memory location.
392 * This is intended for use with memory reporting.
394 * @param aImageKey The image to report memory usage for.
395 * @param aLocation The location (heap, nonheap, etc.) of the memory to
396 * report on.
397 * @param aMallocSizeOf A fallback malloc memory reporting function. This
398 * should be null unless we're reporting on in-process
399 * heap memory.
401 static size_t SizeOfSurfaces(const ImageKey aImageKey,
402 gfxMemoryLocation aLocation,
403 MallocSizeOf aMallocSizeOf);
405 private:
406 virtual ~SurfaceCache() = 0; // Forbid instantiation.
409 } // namespace image
410 } // namespace mozilla
412 #endif // MOZILLA_IMAGELIB_SURFACECACHE_H_