Home | History | Annotate | Download | only in chromium
      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