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/skia/SkSizeHash.h"
33#include "platform/image-decoders/ImageDecoder.h"
34
35#include "wtf/DoublyLinkedList.h"
36#include "wtf/HashSet.h"
37#include "wtf/OwnPtr.h"
38#include "wtf/PassOwnPtr.h"
39#include "wtf/ThreadingPrimitives.h"
40#include "wtf/Vector.h"
41
42namespace blink {
43
44class ImageFrameGenerator;
45
46// FUNCTION
47//
48// ImageDecodingStore is a class used to manage cached decoder objects.
49//
50// EXTERNAL OBJECTS
51//
52// ImageDecoder
53//   A decoder object. It is used to decode raw data into bitmap images.
54//
55// ImageFrameGenerator
56//   This is a direct user of this cache. Responsible for generating bitmap images
57//   using an ImageDecoder. It contains encoded image data and is used to represent
58//   one image file. It is used to index image and decoder objects in the cache.
59//
60// THREAD SAFETY
61//
62// All public methods can be used on any thread.
63
64class PLATFORM_EXPORT ImageDecodingStore {
65public:
66    static PassOwnPtr<ImageDecodingStore> create() { return adoptPtr(new ImageDecodingStore); }
67    ~ImageDecodingStore();
68
69    static ImageDecodingStore* instance();
70
71    // Access a cached decoder object. A decoder is indexed by origin (ImageFrameGenerator)
72    // and scaled size. Return true if the cached object is found.
73    bool lockDecoder(const ImageFrameGenerator*, const SkISize& scaledSize, ImageDecoder**);
74    void unlockDecoder(const ImageFrameGenerator*, const ImageDecoder*);
75    void insertDecoder(const ImageFrameGenerator*, PassOwnPtr<ImageDecoder>);
76    void removeDecoder(const ImageFrameGenerator*, const ImageDecoder*);
77
78    // Remove all cache entries indexed by ImageFrameGenerator.
79    void removeCacheIndexedByGenerator(const ImageFrameGenerator*);
80
81    void clear();
82    void setCacheLimitInBytes(size_t);
83    size_t memoryUsageInBytes();
84    int cacheEntries();
85    int decoderCacheEntries();
86
87private:
88    // Decoder cache entry is identified by:
89    // 1. Pointer to ImageFrameGenerator.
90    // 2. Size of the image.
91    typedef std::pair<const ImageFrameGenerator*, SkISize> DecoderCacheKey;
92
93    // Base class for all cache entries.
94    class CacheEntry : public DoublyLinkedListNode<CacheEntry> {
95        friend class WTF::DoublyLinkedListNode<CacheEntry>;
96    public:
97        enum CacheType {
98            TypeDecoder,
99        };
100
101        CacheEntry(const ImageFrameGenerator* generator, int useCount)
102            : m_generator(generator)
103            , m_useCount(useCount)
104            , m_prev(0)
105            , m_next(0)
106        {
107        }
108
109        virtual ~CacheEntry()
110        {
111            ASSERT(!m_useCount);
112        }
113
114        const ImageFrameGenerator* generator() const { return m_generator; }
115        int useCount() const { return m_useCount; }
116        void incrementUseCount() { ++m_useCount; }
117        void decrementUseCount() { --m_useCount; ASSERT(m_useCount >= 0); }
118
119        // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer.
120        //        Find a way to get the size in 64-bits.
121        virtual size_t memoryUsageInBytes() const = 0;
122        virtual CacheType type() const = 0;
123
124    protected:
125        const ImageFrameGenerator* m_generator;
126        int m_useCount;
127
128    private:
129        CacheEntry* m_prev;
130        CacheEntry* m_next;
131    };
132
133    class DecoderCacheEntry FINAL : public CacheEntry {
134    public:
135        static PassOwnPtr<DecoderCacheEntry> create(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder)
136        {
137            return adoptPtr(new DecoderCacheEntry(generator, 0, decoder));
138        }
139
140        DecoderCacheEntry(const ImageFrameGenerator* generator, int count, PassOwnPtr<ImageDecoder> decoder)
141            : CacheEntry(generator, count)
142            , m_cachedDecoder(decoder)
143            , m_size(SkISize::Make(m_cachedDecoder->decodedSize().width(), m_cachedDecoder->decodedSize().height()))
144        {
145        }
146
147        virtual size_t memoryUsageInBytes() const OVERRIDE { return m_size.width() * m_size.height() * 4; }
148        virtual CacheType type() const OVERRIDE { return TypeDecoder; }
149
150        static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size)
151        {
152            return std::make_pair(generator, size);
153        }
154        static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const ImageDecoder* decoder)
155        {
156            return std::make_pair(generator, SkISize::Make(decoder->decodedSize().width(), decoder->decodedSize().height()));
157        }
158        DecoderCacheKey cacheKey() const { return makeCacheKey(m_generator, m_size); }
159        ImageDecoder* cachedDecoder() const { return m_cachedDecoder.get(); }
160
161    private:
162        OwnPtr<ImageDecoder> m_cachedDecoder;
163        SkISize m_size;
164    };
165
166    ImageDecodingStore();
167
168    void prune();
169
170    // These helper methods are called while m_mutex is locked.
171    template<class T, class U, class V> void insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheMap, V* identifierMap);
172
173    // Helper method to remove a cache entry. Ownership is transferred to
174    // deletionList. Use of Vector<> is handy when removing multiple entries.
175    template<class T, class U, class V> void removeFromCacheInternal(const T* cacheEntry, U* cacheMap, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList);
176
177    // Helper method to remove a cache entry. Uses the templated version base on
178    // the type of cache entry.
179    void removeFromCacheInternal(const CacheEntry*, Vector<OwnPtr<CacheEntry> >* deletionList);
180
181    // Helper method to remove all cache entries associated with a ImageFraneGenerator.
182    // Ownership of cache entries is transferred to deletionList.
183    template<class U, class V> void removeCacheIndexedByGeneratorInternal(U* cacheMap, V* identifierMap, const ImageFrameGenerator*, Vector<OwnPtr<CacheEntry> >* deletionList);
184
185    // Helper method to remove cache entry pointers from the LRU list.
186    void removeFromCacheListInternal(const Vector<OwnPtr<CacheEntry> >& deletionList);
187
188    // A doubly linked list that maintains usage history of cache entries.
189    // This is used for eviction of old entries.
190    // Head of this list is the least recently used cache entry.
191    // Tail of this list is the most recently used cache entry.
192    DoublyLinkedList<CacheEntry> m_orderedCacheList;
193
194    // A lookup table for all decoder cache objects. Owns all decoder cache objects.
195    typedef HashMap<DecoderCacheKey, OwnPtr<DecoderCacheEntry> > DecoderCacheMap;
196    DecoderCacheMap m_decoderCacheMap;
197
198    // A lookup table to map ImageFrameGenerator to all associated
199    // decoder cache keys.
200    typedef HashSet<DecoderCacheKey> DecoderCacheKeySet;
201    typedef HashMap<const ImageFrameGenerator*, DecoderCacheKeySet> DecoderCacheKeyMap;
202    DecoderCacheKeyMap m_decoderCacheKeyMap;
203
204    size_t m_heapLimitInBytes;
205    size_t m_heapMemoryUsageInBytes;
206
207    // Protect concurrent access to these members:
208    //   m_orderedCacheList
209    //   m_decoderCacheMap and all CacheEntrys stored in it
210    //   m_decoderCacheKeyMap
211    //   m_heapLimitInBytes
212    //   m_heapMemoryUsageInBytes
213    // This mutex also protects calls to underlying skBitmap's
214    // lockPixels()/unlockPixels() as they are not threadsafe.
215    Mutex m_mutex;
216};
217
218} // namespace blink
219
220#endif
221