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 "core/platform/graphics/chromium/DiscardablePixelRef.h" 32 #include "core/platform/graphics/chromium/ScaledImageFragment.h" 33 #include "core/platform/graphics/chromium/SkSizeHash.h" 34 #include "core/platform/image-decoders/ImageDecoder.h" 35 36 #include "wtf/DoublyLinkedList.h" 37 #include "wtf/HashSet.h" 38 #include "wtf/OwnPtr.h" 39 #include "wtf/PassOwnPtr.h" 40 #include "wtf/ThreadingPrimitives.h" 41 #include "wtf/Vector.h" 42 43 namespace WebCore { 44 45 class ImageFrameGenerator; 46 class SharedBuffer; 47 48 // FUNCTION 49 // 50 // ImageDecodingStore is a class used to manage image cache objects. There are two 51 // types of cache objects stored: 52 // 53 // 1. Image objects 54 // Each image object belongs to one frame decoded and/or resampled from an image 55 // file. The image object can be complete or partial. Complete means the image 56 // is fully decoded and will not mutate in future decoding passes. It can have 57 // multiple concurrent users. A partial image object has only one user. 58 // 59 // 2. Decoder objects 60 // A decoder object contains an image decoder. This allows decoding to resume 61 // from previous states. There can be one user per one decoder object at any 62 // time. 63 // 64 // EXTERNAL OBJECTS 65 // 66 // ScaledImageFragment 67 // A cached image object. Contains the bitmap and information about the bitmap 68 // image. 69 // 70 // ImageDecoder 71 // A decoder object. It is used to decode raw data into bitmap images. 72 // 73 // ImageFrameGenerator 74 // This is a direct user of this cache. Responsible for generating bitmap images 75 // using an ImageDecoder. It contains encoded image data and is used to represent 76 // one image file. It is used to index image and decoder objects in the cache. 77 // 78 // LazyDecodingPixelRef 79 // A read only user of this cache. 80 // 81 // THREAD SAFETY 82 // 83 // All public methods can be used on any thread. 84 85 class ImageDecodingStore { 86 public: 87 static PassOwnPtr<ImageDecodingStore> create() { return adoptPtr(new ImageDecodingStore); } 88 ~ImageDecodingStore(); 89 90 static ImageDecodingStore* instance(); 91 static void initializeOnce(); 92 static void shutdown(); 93 94 // Access a complete cached image object. A complete cached image object is 95 // indexed by the origin (ImageFrameGenerator), scaled size and frame index 96 // within the image file. 97 // Return true if the cache object is found. 98 // Return false if the cache object cannot be found or it is incomplete. 99 bool lockCache(const ImageFrameGenerator*, const SkISize& scaledSize, size_t index, const ScaledImageFragment**); 100 void unlockCache(const ImageFrameGenerator*, const ScaledImageFragment*); 101 const ScaledImageFragment* insertAndLockCache(const ImageFrameGenerator*, PassOwnPtr<ScaledImageFragment>); 102 103 // Access a cached decoder object. A decoder is indexed by origin (ImageFrameGenerator) 104 // and scaled size. Return true if the cached object is found. 105 bool lockDecoder(const ImageFrameGenerator*, const SkISize& scaledSize, ImageDecoder**); 106 void unlockDecoder(const ImageFrameGenerator*, const ImageDecoder*); 107 void insertDecoder(const ImageFrameGenerator*, PassOwnPtr<ImageDecoder>, bool isDiscardable); 108 void removeDecoder(const ImageFrameGenerator*, const ImageDecoder*); 109 110 // Locks the cache for safety, but does not attempt to lock the object we're checking for. 111 bool isCached(const ImageFrameGenerator*, const SkISize& scaledSize, size_t index); 112 113 // Remove all cache entries indexed by ImageFrameGenerator. 114 void removeCacheIndexedByGenerator(const ImageFrameGenerator*); 115 116 void clear(); 117 void setCacheLimitInBytes(size_t); 118 size_t memoryUsageInBytes(); 119 unsigned cacheEntries(); 120 unsigned imageCacheEntries(); 121 unsigned decoderCacheEntries(); 122 123 private: 124 // Image cache entry is identified by: 125 // 1. Pointer to ImageFrameGenerator. 126 // 2. Size of the image. 127 // 3. Frame index. 128 // 4. Frame generation. Increments on each progressive decode. 129 // 130 // The use of generation ID is to allow multiple versions of an image frame 131 // be stored in the cache. Each generation comes from a progressive decode. 132 // 133 // Decoder entries are identified by (1) and (2) only. 134 typedef std::pair<const ImageFrameGenerator*, SkISize> DecoderCacheKey; 135 typedef std::pair<size_t, size_t> IndexAndGeneration; 136 typedef std::pair<DecoderCacheKey, IndexAndGeneration> ImageCacheKey; 137 138 // Base class for all cache entries. 139 class CacheEntry : public DoublyLinkedListNode<CacheEntry> { 140 friend class WTF::DoublyLinkedListNode<CacheEntry>; 141 public: 142 enum CacheType { 143 TypeImage, 144 TypeDecoder, 145 }; 146 147 CacheEntry(const ImageFrameGenerator* generator, int useCount, bool isDiscardable) 148 : m_generator(generator) 149 , m_useCount(useCount) 150 , m_isDiscardable(isDiscardable) 151 , m_prev(0) 152 , m_next(0) 153 { 154 } 155 156 virtual ~CacheEntry() 157 { 158 ASSERT(!m_useCount); 159 } 160 161 const ImageFrameGenerator* generator() const { return m_generator; } 162 int useCount() const { return m_useCount; } 163 void incrementUseCount() { ++m_useCount; } 164 void decrementUseCount() { --m_useCount; ASSERT(m_useCount >= 0); } 165 bool isDiscardable() const { return m_isDiscardable; } 166 167 // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer. 168 // Find a way to get the size in 64-bits. 169 virtual size_t memoryUsageInBytes() const = 0; 170 virtual CacheType type() const = 0; 171 172 protected: 173 const ImageFrameGenerator* m_generator; 174 int m_useCount; 175 bool m_isDiscardable; 176 177 private: 178 CacheEntry* m_prev; 179 CacheEntry* m_next; 180 }; 181 182 class ImageCacheEntry : public CacheEntry { 183 public: 184 static PassOwnPtr<ImageCacheEntry> createAndUse(const ImageFrameGenerator* generator, PassOwnPtr<ScaledImageFragment> image) 185 { 186 return adoptPtr(new ImageCacheEntry(generator, 1, image)); 187 } 188 189 ImageCacheEntry(const ImageFrameGenerator* generator, int count, PassOwnPtr<ScaledImageFragment> image) 190 : CacheEntry(generator, count, DiscardablePixelRef::isDiscardable(image->bitmap().pixelRef())) 191 , m_cachedImage(image) 192 { 193 } 194 195 // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer. 196 // Find a way to get the size in 64-bits. 197 virtual size_t memoryUsageInBytes() const { return cachedImage()->bitmap().getSafeSize(); } 198 virtual CacheType type() const { return TypeImage; } 199 200 static ImageCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size, size_t index, size_t generation) 201 { 202 return std::make_pair(std::make_pair(generator, size), std::make_pair(index, generation)); 203 } 204 ImageCacheKey cacheKey() const { return makeCacheKey(m_generator, m_cachedImage->scaledSize(), m_cachedImage->index(), m_cachedImage->generation()); } 205 const ScaledImageFragment* cachedImage() const { return m_cachedImage.get(); } 206 ScaledImageFragment* cachedImage() { return m_cachedImage.get(); } 207 208 private: 209 OwnPtr<ScaledImageFragment> m_cachedImage; 210 }; 211 212 class DecoderCacheEntry : public CacheEntry { 213 public: 214 static PassOwnPtr<DecoderCacheEntry> create(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder, bool isDiscardable) 215 { 216 return adoptPtr(new DecoderCacheEntry(generator, 0, decoder, isDiscardable)); 217 } 218 219 DecoderCacheEntry(const ImageFrameGenerator* generator, int count, PassOwnPtr<ImageDecoder> decoder, bool isDiscardable) 220 : CacheEntry(generator, count, isDiscardable) 221 , m_cachedDecoder(decoder) 222 , m_size(SkISize::Make(m_cachedDecoder->size().width(), m_cachedDecoder->size().height())) 223 { 224 } 225 226 virtual size_t memoryUsageInBytes() const { return m_size.width() * m_size.height() * 4; } 227 virtual CacheType type() const { return TypeDecoder; } 228 229 static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size) 230 { 231 return std::make_pair(generator, size); 232 } 233 static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const ImageDecoder* decoder) 234 { 235 return std::make_pair(generator, SkISize::Make(decoder->size().width(), decoder->size().height())); 236 } 237 DecoderCacheKey cacheKey() const { return makeCacheKey(m_generator, m_size); } 238 ImageDecoder* cachedDecoder() const { return m_cachedDecoder.get(); } 239 240 private: 241 OwnPtr<ImageDecoder> m_cachedDecoder; 242 SkISize m_size; 243 }; 244 245 ImageDecodingStore(); 246 247 void prune(); 248 249 // These helper methods are called while m_mutex is locked. 250 251 // Find and lock a cache entry, and return true on success. 252 // Memory of the cache entry can be discarded, in which case it is saved in 253 // deletionList. 254 bool lockCacheEntryInternal(ImageCacheEntry*, const ScaledImageFragment**, Vector<OwnPtr<CacheEntry> >* deletionList); 255 256 template<class T, class U, class V> void insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheMap, V* identifierMap); 257 258 // Helper method to remove a cache entry. Ownership is transferred to 259 // deletionList. Use of Vector<> is handy when removing multiple entries. 260 template<class T, class U, class V> void removeFromCacheInternal(const T* cacheEntry, U* cacheMap, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList); 261 262 // Helper method to remove a cache entry. Uses the templated version base on 263 // the type of cache entry. 264 void removeFromCacheInternal(const CacheEntry*, Vector<OwnPtr<CacheEntry> >* deletionList); 265 266 // Helper method to remove all cache entries associated with a ImageFraneGenerator. 267 // Ownership of cache entries is transferred to deletionList. 268 template<class U, class V> void removeCacheIndexedByGeneratorInternal(U* cacheMap, V* identifierMap, const ImageFrameGenerator*, Vector<OwnPtr<CacheEntry> >* deletionList); 269 270 // Helper method to remove cache entry pointers from the LRU list. 271 void removeFromCacheListInternal(const Vector<OwnPtr<CacheEntry> >& deletionList); 272 273 void incrementMemoryUsage(size_t size) { m_memoryUsageInBytes += size; } 274 void decrementMemoryUsage(size_t size) 275 { 276 ASSERT(m_memoryUsageInBytes >= size); 277 m_memoryUsageInBytes -= size; 278 } 279 280 // A doubly linked list that maintains usage history of cache entries. 281 // This is used for eviction of old entries. 282 // Head of this list is the least recently used cache entry. 283 // Tail of this list is the most recently used cache entry. 284 DoublyLinkedList<CacheEntry> m_orderedCacheList; 285 286 // A lookup table for all image cache objects. Owns all image cache objects. 287 typedef HashMap<ImageCacheKey, OwnPtr<ImageCacheEntry> > ImageCacheMap; 288 ImageCacheMap m_imageCacheMap; 289 290 // A lookup table for all decoder cache objects. Owns all decoder cache objects. 291 typedef HashMap<DecoderCacheKey, OwnPtr<DecoderCacheEntry> > DecoderCacheMap; 292 DecoderCacheMap m_decoderCacheMap; 293 294 // A lookup table to map ImageFrameGenerator to all associated image 295 // cache keys. 296 typedef HashSet<ImageCacheKey> ImageCacheKeySet; 297 typedef HashMap<const ImageFrameGenerator*, ImageCacheKeySet> ImageCacheKeyMap; 298 ImageCacheKeyMap m_imageCacheKeyMap; 299 300 // A lookup table to map ImageFrameGenerator to all associated 301 // decoder cache keys. 302 typedef HashSet<DecoderCacheKey> DecoderCacheKeySet; 303 typedef HashMap<const ImageFrameGenerator*, DecoderCacheKeySet> DecoderCacheKeyMap; 304 DecoderCacheKeyMap m_decoderCacheKeyMap; 305 306 size_t m_cacheLimitInBytes; 307 size_t m_memoryUsageInBytes; 308 309 // Protect concurrent access to these members: 310 // m_orderedCacheList 311 // m_imageCacheMap, m_decoderCacheMap and all CacheEntrys stored in it 312 // m_imageCacheKeyMap 313 // m_decoderCacheKeyMap 314 // m_cacheLimitInBytes 315 // m_memoryUsageInBytes 316 // This mutex also protects calls to underlying skBitmap's 317 // lockPixels()/unlockPixels() as they are not threadsafe. 318 Mutex m_mutex; 319 }; 320 321 } // namespace WebCore 322 323 #endif 324