• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #ifndef ImageDecodingStore_h
27 #define ImageDecodingStore_h
28 
29 #include "SkSize.h"
30 #include "SkTypes.h"
31 #include "platform/PlatformExport.h"
32 #include "platform/graphics/DiscardablePixelRef.h"
33 #include "platform/graphics/ScaledImageFragment.h"
34 #include "platform/graphics/skia/SkSizeHash.h"
35 #include "platform/image-decoders/ImageDecoder.h"
36 
37 #include "wtf/DoublyLinkedList.h"
38 #include "wtf/HashSet.h"
39 #include "wtf/OwnPtr.h"
40 #include "wtf/PassOwnPtr.h"
41 #include "wtf/ThreadingPrimitives.h"
42 #include "wtf/Vector.h"
43 
44 namespace WebCore {
45 
46 class ImageFrameGenerator;
47 class SharedBuffer;
48 
49 // FUNCTION
50 //
51 // ImageDecodingStore is a class used to manage image cache objects. There are two
52 // types of cache objects stored:
53 //
54 // 1. Image objects
55 //    Each image object belongs to one frame decoded and/or resampled from an image
56 //    file. The image object can be complete or partial. Complete means the image
57 //    is fully decoded and will not mutate in future decoding passes. It can have
58 //    multiple concurrent users. A partial image object has only one user.
59 //
60 // 2. Decoder objects
61 //    A decoder object contains an image decoder. This allows decoding to resume
62 //    from previous states. There can be one user per one decoder object at any
63 //    time.
64 //
65 // EXTERNAL OBJECTS
66 //
67 // ScaledImageFragment
68 //   A cached image object. Contains the bitmap and information about the bitmap
69 //   image.
70 //
71 // ImageDecoder
72 //   A decoder object. It is used to decode raw data into bitmap images.
73 //
74 // ImageFrameGenerator
75 //   This is a direct user of this cache. Responsible for generating bitmap images
76 //   using an ImageDecoder. It contains encoded image data and is used to represent
77 //   one image file. It is used to index image and decoder objects in the cache.
78 //
79 // LazyDecodingPixelRef
80 //   A read only user of this cache.
81 //
82 // THREAD SAFETY
83 //
84 // All public methods can be used on any thread.
85 
86 class PLATFORM_EXPORT ImageDecodingStore {
87 public:
create()88     static PassOwnPtr<ImageDecodingStore> create() { return adoptPtr(new ImageDecodingStore); }
89     ~ImageDecodingStore();
90 
91     static ImageDecodingStore* instance();
92 
93     // Why do we need this?
94     // ImageDecodingStore is used in two code paths:
95     // 1. Android uses this to cache both images and decoders.
96     // 2. Skia discardable memory path has its own cache. We still want cache
97     //    decoders but not images because Skia will take care of it.
98     // Because of the two use cases we want to just disable image caching.
99     //
100     // FIXME: It is weird to have this behavior. We want to remove image
101     // caching from this class once the transition to Skia discardable memory
102     // is complete.
103     static void setImageCachingEnabled(bool);
104 
105     // Access a complete cached image object. A complete cached image object is
106     // indexed by the origin (ImageFrameGenerator), scaled size and frame index
107     // within the image file.
108     // Return true if the cache object is found.
109     // Return false if the cache object cannot be found or it is incomplete.
110     bool lockCache(const ImageFrameGenerator*, const SkISize& scaledSize, size_t index, const ScaledImageFragment**);
111     void unlockCache(const ImageFrameGenerator*, const ScaledImageFragment*);
112     const ScaledImageFragment* insertAndLockCache(const ImageFrameGenerator*, PassOwnPtr<ScaledImageFragment>);
113 
114     // Access a cached decoder object. A decoder is indexed by origin (ImageFrameGenerator)
115     // and scaled size. Return true if the cached object is found.
116     bool lockDecoder(const ImageFrameGenerator*, const SkISize& scaledSize, ImageDecoder**);
117     void unlockDecoder(const ImageFrameGenerator*, const ImageDecoder*);
118     void insertDecoder(const ImageFrameGenerator*, PassOwnPtr<ImageDecoder>, bool isDiscardable);
119     void removeDecoder(const ImageFrameGenerator*, const ImageDecoder*);
120 
121     // Locks the cache for safety, but does not attempt to lock the object we're checking for.
122     bool isCached(const ImageFrameGenerator*, const SkISize& scaledSize, size_t index);
123 
124     // Remove all cache entries indexed by ImageFrameGenerator.
125     void removeCacheIndexedByGenerator(const ImageFrameGenerator*);
126 
127     void clear();
128     void setCacheLimitInBytes(size_t);
129     size_t memoryUsageInBytes();
130     int cacheEntries();
131     int imageCacheEntries();
132     int decoderCacheEntries();
133 
134 private:
135     // Image cache entry is identified by:
136     // 1. Pointer to ImageFrameGenerator.
137     // 2. Size of the image.
138     // 3. LocalFrame index.
139     // 4. LocalFrame generation. Increments on each progressive decode.
140     //
141     // The use of generation ID is to allow multiple versions of an image frame
142     // be stored in the cache. Each generation comes from a progressive decode.
143     //
144     // Decoder entries are identified by (1) and (2) only.
145     typedef std::pair<const ImageFrameGenerator*, SkISize> DecoderCacheKey;
146     typedef std::pair<size_t, size_t> IndexAndGeneration;
147     typedef std::pair<DecoderCacheKey, IndexAndGeneration> ImageCacheKey;
148 
149     // Base class for all cache entries.
150     class CacheEntry : public DoublyLinkedListNode<CacheEntry> {
151         friend class WTF::DoublyLinkedListNode<CacheEntry>;
152     public:
153         enum CacheType {
154             TypeImage,
155             TypeDecoder,
156         };
157 
CacheEntry(const ImageFrameGenerator * generator,int useCount,bool isDiscardable)158         CacheEntry(const ImageFrameGenerator* generator, int useCount, bool isDiscardable)
159             : m_generator(generator)
160             , m_useCount(useCount)
161             , m_isDiscardable(isDiscardable)
162             , m_prev(0)
163             , m_next(0)
164         {
165         }
166 
~CacheEntry()167         virtual ~CacheEntry()
168         {
169             ASSERT(!m_useCount);
170         }
171 
generator()172         const ImageFrameGenerator* generator() const { return m_generator; }
useCount()173         int useCount() const { return m_useCount; }
incrementUseCount()174         void incrementUseCount() { ++m_useCount; }
decrementUseCount()175         void decrementUseCount() { --m_useCount; ASSERT(m_useCount >= 0); }
isDiscardable()176         bool isDiscardable() const { return m_isDiscardable; }
177 
178         // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer.
179         //        Find a way to get the size in 64-bits.
180         virtual size_t memoryUsageInBytes() const = 0;
181         virtual CacheType type() const = 0;
182 
183     protected:
184         const ImageFrameGenerator* m_generator;
185         int m_useCount;
186         bool m_isDiscardable;
187 
188     private:
189         CacheEntry* m_prev;
190         CacheEntry* m_next;
191     };
192 
193     class ImageCacheEntry FINAL : public CacheEntry {
194     public:
createAndUse(const ImageFrameGenerator * generator,PassOwnPtr<ScaledImageFragment> image)195         static PassOwnPtr<ImageCacheEntry> createAndUse(const ImageFrameGenerator* generator, PassOwnPtr<ScaledImageFragment> image)
196         {
197             return adoptPtr(new ImageCacheEntry(generator, 1, image));
198         }
199 
ImageCacheEntry(const ImageFrameGenerator * generator,int count,PassOwnPtr<ScaledImageFragment> image)200         ImageCacheEntry(const ImageFrameGenerator* generator, int count, PassOwnPtr<ScaledImageFragment> image)
201             : CacheEntry(generator, count, DiscardablePixelRef::isDiscardable(image->bitmap().pixelRef()))
202             , m_cachedImage(image)
203         {
204         }
205 
206         // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer.
207         //        Find a way to get the size in 64-bits.
memoryUsageInBytes()208         virtual size_t memoryUsageInBytes() const OVERRIDE { return cachedImage()->bitmap().getSafeSize(); }
type()209         virtual CacheType type() const OVERRIDE { return TypeImage; }
210 
makeCacheKey(const ImageFrameGenerator * generator,const SkISize & size,size_t index,size_t generation)211         static ImageCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size, size_t index, size_t generation)
212         {
213             return std::make_pair(std::make_pair(generator, size), std::make_pair(index, generation));
214         }
cacheKey()215         ImageCacheKey cacheKey() const { return makeCacheKey(m_generator, m_cachedImage->scaledSize(), m_cachedImage->index(), m_cachedImage->generation()); }
cachedImage()216         const ScaledImageFragment* cachedImage() const { return m_cachedImage.get(); }
cachedImage()217         ScaledImageFragment* cachedImage() { return m_cachedImage.get(); }
218 
219     private:
220         OwnPtr<ScaledImageFragment> m_cachedImage;
221     };
222 
223     class DecoderCacheEntry FINAL : public CacheEntry {
224     public:
create(const ImageFrameGenerator * generator,PassOwnPtr<ImageDecoder> decoder,bool isDiscardable)225         static PassOwnPtr<DecoderCacheEntry> create(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder, bool isDiscardable)
226         {
227             return adoptPtr(new DecoderCacheEntry(generator, 0, decoder, isDiscardable));
228         }
229 
DecoderCacheEntry(const ImageFrameGenerator * generator,int count,PassOwnPtr<ImageDecoder> decoder,bool isDiscardable)230         DecoderCacheEntry(const ImageFrameGenerator* generator, int count, PassOwnPtr<ImageDecoder> decoder, bool isDiscardable)
231             : CacheEntry(generator, count, isDiscardable)
232             , m_cachedDecoder(decoder)
233             , m_size(SkISize::Make(m_cachedDecoder->decodedSize().width(), m_cachedDecoder->decodedSize().height()))
234         {
235         }
236 
memoryUsageInBytes()237         virtual size_t memoryUsageInBytes() const OVERRIDE { return m_size.width() * m_size.height() * 4; }
type()238         virtual CacheType type() const OVERRIDE { return TypeDecoder; }
239 
makeCacheKey(const ImageFrameGenerator * generator,const SkISize & size)240         static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size)
241         {
242             return std::make_pair(generator, size);
243         }
makeCacheKey(const ImageFrameGenerator * generator,const ImageDecoder * decoder)244         static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const ImageDecoder* decoder)
245         {
246             return std::make_pair(generator, SkISize::Make(decoder->decodedSize().width(), decoder->decodedSize().height()));
247         }
cacheKey()248         DecoderCacheKey cacheKey() const { return makeCacheKey(m_generator, m_size); }
cachedDecoder()249         ImageDecoder* cachedDecoder() const { return m_cachedDecoder.get(); }
250 
251     private:
252         OwnPtr<ImageDecoder> m_cachedDecoder;
253         SkISize m_size;
254     };
255 
256     ImageDecodingStore();
257 
258     void prune();
259 
260     // These helper methods are called while m_mutex is locked.
261 
262     // Find and lock a cache entry, and return true on success.
263     // Memory of the cache entry can be discarded, in which case it is saved in
264     // deletionList.
265     bool lockCacheEntryInternal(ImageCacheEntry*, const ScaledImageFragment**, Vector<OwnPtr<CacheEntry> >* deletionList);
266 
267     template<class T, class U, class V> void insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheMap, V* identifierMap);
268 
269     // Helper method to remove a cache entry. Ownership is transferred to
270     // deletionList. Use of Vector<> is handy when removing multiple entries.
271     template<class T, class U, class V> void removeFromCacheInternal(const T* cacheEntry, U* cacheMap, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList);
272 
273     // Helper method to remove a cache entry. Uses the templated version base on
274     // the type of cache entry.
275     void removeFromCacheInternal(const CacheEntry*, Vector<OwnPtr<CacheEntry> >* deletionList);
276 
277     // Helper method to remove all cache entries associated with a ImageFraneGenerator.
278     // Ownership of cache entries is transferred to deletionList.
279     template<class U, class V> void removeCacheIndexedByGeneratorInternal(U* cacheMap, V* identifierMap, const ImageFrameGenerator*, Vector<OwnPtr<CacheEntry> >* deletionList);
280 
281     // Helper method to remove cache entry pointers from the LRU list.
282     void removeFromCacheListInternal(const Vector<OwnPtr<CacheEntry> >& deletionList);
283 
284     // A doubly linked list that maintains usage history of cache entries.
285     // This is used for eviction of old entries.
286     // Head of this list is the least recently used cache entry.
287     // Tail of this list is the most recently used cache entry.
288     DoublyLinkedList<CacheEntry> m_orderedCacheList;
289 
290     // A lookup table for all image cache objects. Owns all image cache objects.
291     typedef HashMap<ImageCacheKey, OwnPtr<ImageCacheEntry> > ImageCacheMap;
292     ImageCacheMap m_imageCacheMap;
293 
294     // A lookup table for all decoder cache objects. Owns all decoder cache objects.
295     typedef HashMap<DecoderCacheKey, OwnPtr<DecoderCacheEntry> > DecoderCacheMap;
296     DecoderCacheMap m_decoderCacheMap;
297 
298     // A lookup table to map ImageFrameGenerator to all associated image
299     // cache keys.
300     typedef HashSet<ImageCacheKey> ImageCacheKeySet;
301     typedef HashMap<const ImageFrameGenerator*, ImageCacheKeySet> ImageCacheKeyMap;
302     ImageCacheKeyMap m_imageCacheKeyMap;
303 
304     // A lookup table to map ImageFrameGenerator to all associated
305     // decoder cache keys.
306     typedef HashSet<DecoderCacheKey> DecoderCacheKeySet;
307     typedef HashMap<const ImageFrameGenerator*, DecoderCacheKeySet> DecoderCacheKeyMap;
308     DecoderCacheKeyMap m_decoderCacheKeyMap;
309 
310     size_t m_heapLimitInBytes;
311     size_t m_heapMemoryUsageInBytes;
312     size_t m_discardableMemoryUsageInBytes;
313 
314     // Protect concurrent access to these members:
315     //   m_orderedCacheList
316     //   m_imageCacheMap, m_decoderCacheMap and all CacheEntrys stored in it
317     //   m_imageCacheKeyMap
318     //   m_decoderCacheKeyMap
319     //   m_heapLimitInBytes
320     //   m_heapMemoryUsageInBytes
321     //   m_discardableMemoryUsageInBytes
322     // This mutex also protects calls to underlying skBitmap's
323     // lockPixels()/unlockPixels() as they are not threadsafe.
324     Mutex m_mutex;
325 };
326 
327 } // namespace WebCore
328 
329 #endif
330