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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_
27 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_
28 
29 #include <memory>
30 #include <utility>
31 
32 #include "base/macros.h"
33 #include "base/memory/memory_pressure_listener.h"
34 #include "base/memory/ptr_util.h"
35 #include "cc/paint/paint_image_generator.h"
36 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
37 #include "third_party/blink/renderer/platform/graphics/skia/sk_size_hash.h"
38 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
39 #include "third_party/blink/renderer/platform/platform_export.h"
40 #include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h"
41 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
42 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
43 #include "third_party/blink/renderer/platform/wtf/vector.h"
44 #include "third_party/skia/include/core/SkSize.h"
45 #include "third_party/skia/include/core/SkTypes.h"
46 
47 namespace blink {
48 
49 // Decoder cache entry is identified by:
50 // 1. Pointer to ImageFrameGenerator.
51 // 2. Size of the image.
52 // 3. ImageDecoder::AlphaOption
53 struct DecoderCacheKey {
54   const blink::ImageFrameGenerator* gen_;
55   SkISize size_;
56   blink::ImageDecoder::AlphaOption alpha_option_;
57   cc::PaintImage::GeneratorClientId client_id_;
58 
DecoderCacheKeyDecoderCacheKey59   DecoderCacheKey()
60       : gen_(nullptr),
61         size_(SkISize::Make(0, 0)),
62         alpha_option_(static_cast<blink::ImageDecoder::AlphaOption>(0)),
63         client_id_(cc::PaintImage::kDefaultGeneratorClientId) {}
64 };
65 
66 static inline bool operator==(const DecoderCacheKey& a,
67                               const DecoderCacheKey& b) {
68   return a.gen_ == b.gen_ && a.size_ == b.size_ &&
69          a.alpha_option_ == b.alpha_option_ && a.client_id_ == b.client_id_;
70 }
71 
72 static inline bool operator!=(const DecoderCacheKey& a,
73                               const DecoderCacheKey& b) {
74   return !(a == b);
75 }
76 
77 // Base class for all cache entries.
78 class CacheEntry : public DoublyLinkedListNode<CacheEntry> {
79   USING_FAST_MALLOC(CacheEntry);
80   friend class WTF::DoublyLinkedListNode<CacheEntry>;
81 
82  public:
83   enum CacheType {
84     kTypeDecoder,
85   };
86 
CacheEntry(const ImageFrameGenerator * generator,int use_count)87   CacheEntry(const ImageFrameGenerator* generator, int use_count)
88       : generator_(generator),
89         use_count_(use_count),
90         prev_(nullptr),
91         next_(nullptr) {}
92 
~CacheEntry()93   virtual ~CacheEntry() { DCHECK(!use_count_); }
94 
Generator()95   const ImageFrameGenerator* Generator() const { return generator_; }
UseCount()96   int UseCount() const { return use_count_; }
IncrementUseCount()97   void IncrementUseCount() { ++use_count_; }
DecrementUseCount()98   void DecrementUseCount() {
99     --use_count_;
100     DCHECK_GE(use_count_, 0);
101   }
102 
103   // FIXME: getSafeSize() returns the size in bytes truncated to a 32-bit
104   // integer. Find a way to get the size in 64-bits.
105   virtual size_t MemoryUsageInBytes() const = 0;
106   virtual CacheType GetType() const = 0;
107 
108  protected:
109   const ImageFrameGenerator* generator_;
110   int use_count_;
111 
112  private:
113   CacheEntry* prev_;
114   CacheEntry* next_;
115 
116   DISALLOW_COPY_AND_ASSIGN(CacheEntry);
117 };
118 
119 class DecoderCacheEntry final : public CacheEntry {
120  public:
DecoderCacheEntry(const ImageFrameGenerator * generator,int count,std::unique_ptr<ImageDecoder> decoder,cc::PaintImage::GeneratorClientId client_id)121   DecoderCacheEntry(const ImageFrameGenerator* generator,
122                     int count,
123                     std::unique_ptr<ImageDecoder> decoder,
124                     cc::PaintImage::GeneratorClientId client_id)
125       : CacheEntry(generator, count),
126         cached_decoder_(std::move(decoder)),
127         size_(SkISize::Make(cached_decoder_->DecodedSize().Width(),
128                             cached_decoder_->DecodedSize().Height())),
129         alpha_option_(cached_decoder_->GetAlphaOption()),
130         client_id_(client_id) {}
131 
MemoryUsageInBytes()132   size_t MemoryUsageInBytes() const override {
133     return size_.width() * size_.height() * 4;
134   }
GetType()135   CacheType GetType() const override { return kTypeDecoder; }
136 
MakeCacheKey(const ImageFrameGenerator * generator,const SkISize & size,ImageDecoder::AlphaOption alpha_option,cc::PaintImage::GeneratorClientId client_id)137   static DecoderCacheKey MakeCacheKey(
138       const ImageFrameGenerator* generator,
139       const SkISize& size,
140       ImageDecoder::AlphaOption alpha_option,
141       cc::PaintImage::GeneratorClientId client_id) {
142     DecoderCacheKey key;
143     key.gen_ = generator;
144     key.size_ = size;
145     key.alpha_option_ = alpha_option;
146     key.client_id_ = client_id;
147     return key;
148   }
MakeCacheKey(const ImageFrameGenerator * generator,const ImageDecoder * decoder,cc::PaintImage::GeneratorClientId client_id)149   static DecoderCacheKey MakeCacheKey(
150       const ImageFrameGenerator* generator,
151       const ImageDecoder* decoder,
152       cc::PaintImage::GeneratorClientId client_id) {
153     return MakeCacheKey(generator,
154                         SkISize::Make(decoder->DecodedSize().Width(),
155                                       decoder->DecodedSize().Height()),
156                         decoder->GetAlphaOption(), client_id);
157   }
CacheKey()158   DecoderCacheKey CacheKey() const {
159     return MakeCacheKey(generator_, size_, alpha_option_, client_id_);
160   }
CachedDecoder()161   ImageDecoder* CachedDecoder() const { return cached_decoder_.get(); }
162 
163  private:
164   std::unique_ptr<ImageDecoder> cached_decoder_;
165   SkISize size_;
166   ImageDecoder::AlphaOption alpha_option_;
167   cc::PaintImage::GeneratorClientId client_id_;
168 };
169 
170 }  // namespace blink
171 
172 namespace WTF {
173 
174 template <>
175 struct DefaultHash<blink::DecoderCacheKey> {
176   STATIC_ONLY(DefaultHash);
177   struct Hash {
178     STATIC_ONLY(Hash);
179     static unsigned GetHash(const blink::DecoderCacheKey& p) {
180       auto first =
181           HashInts(DefaultHash<blink::ImageFrameGenerator*>::Hash::GetHash(
182                        const_cast<blink::ImageFrameGenerator*>(p.gen_)),
183                    DefaultHash<SkISize>::Hash::GetHash(p.size_));
184       auto second = HashInts(DefaultHash<uint8_t>::Hash::GetHash(
185                                  static_cast<uint8_t>(p.alpha_option_)),
186                              p.client_id_);
187       return HashInts(first, second);
188     }
189     static bool Equal(const blink::DecoderCacheKey& a,
190                       const blink::DecoderCacheKey& b) {
191       return a.gen_ == b.gen_ && a.size_ == b.size_ &&
192              a.alpha_option_ == b.alpha_option_ && a.client_id_ == b.client_id_;
193     }
194     static const bool safe_to_compare_to_empty_or_deleted = true;
195   };
196 };
197 
198 template <>
199 struct HashTraits<blink::DecoderCacheKey>
200     : GenericHashTraits<blink::DecoderCacheKey> {
201   STATIC_ONLY(HashTraits);
202   static const bool kEmptyValueIsZero = true;
203   static blink::DecoderCacheKey EmptyValue() {
204     return blink::DecoderCacheEntry::MakeCacheKey(
205         nullptr, SkISize::Make(0, 0),
206         static_cast<blink::ImageDecoder::AlphaOption>(0),
207         cc::PaintImage::kDefaultGeneratorClientId);
208   }
209   static void ConstructDeletedValue(blink::DecoderCacheKey& slot, bool) {
210     slot = blink::DecoderCacheEntry::MakeCacheKey(
211         nullptr, SkISize::Make(-1, -1),
212         static_cast<blink::ImageDecoder::AlphaOption>(0),
213         cc::PaintImage::kDefaultGeneratorClientId);
214   }
215   static bool IsDeletedValue(const blink::DecoderCacheKey& value) {
216     return value.size_ == SkISize::Make(-1, -1);
217   }
218 };
219 
220 }  // namespace WTF
221 
222 namespace blink {
223 
224 // FUNCTION
225 //
226 // ImageDecodingStore is a class used to manage cached decoder objects.
227 //
228 // EXTERNAL OBJECTS
229 //
230 // ImageDecoder
231 //   A decoder object. It is used to decode raw data into bitmap images.
232 //
233 // ImageFrameGenerator
234 //   This is a direct user of this cache. Responsible for generating bitmap
235 //   images using an ImageDecoder. It contains encoded image data and is used
236 //   to represent one image file. It is used to index image and decoder
237 //   objects in the cache.
238 //
239 // THREAD SAFETY
240 //
241 // All public methods can be used on any thread.
242 
243 class PLATFORM_EXPORT ImageDecodingStore final {
244   USING_FAST_MALLOC(ImageDecodingStore);
245 
246  public:
247   ImageDecodingStore();
248   ~ImageDecodingStore();
249 
250   static ImageDecodingStore& Instance();
251 
252   // Accesses a cached decoder object. A decoder is indexed by origin
253   // (ImageFrameGenerator) and scaled size. Returns true if the cached object
254   // is found.
255   bool LockDecoder(const ImageFrameGenerator*,
256                    const SkISize& scaled_size,
257                    ImageDecoder::AlphaOption,
258                    cc::PaintImage::GeneratorClientId client_id,
259                    ImageDecoder**);
260   void UnlockDecoder(const ImageFrameGenerator*,
261                      cc::PaintImage::GeneratorClientId client_id,
262                      const ImageDecoder*);
263   void InsertDecoder(const ImageFrameGenerator*,
264                      cc::PaintImage::GeneratorClientId client_id,
265                      std::unique_ptr<ImageDecoder>);
266   void RemoveDecoder(const ImageFrameGenerator*,
267                      cc::PaintImage::GeneratorClientId client_id,
268                      const ImageDecoder*);
269 
270   // Remove all cache entries indexed by ImageFrameGenerator.
271   void RemoveCacheIndexedByGenerator(const ImageFrameGenerator*);
272 
273   void Clear();
274   void SetCacheLimitInBytes(size_t);
275   size_t MemoryUsageInBytes();
276   int CacheEntries();
277   int DecoderCacheEntries();
278 
279  private:
280   void Prune();
281 
282   // Called by the memory pressure listener when the memory pressure rises.
283   void OnMemoryPressure(
284       base::MemoryPressureListener::MemoryPressureLevel level);
285 
286   // These helper methods are called while m_mutex is locked.
287   template <class T, class U, class V>
288   void InsertCacheInternal(std::unique_ptr<T> cache_entry,
289                            U* cache_map,
290                            V* identifier_map);
291 
292   // Helper method to remove a cache entry. Ownership is transferred to
293   // deletionList. Use of Vector<> is handy when removing multiple entries.
294   template <class T, class U, class V>
295   void RemoveFromCacheInternal(
296       const T* cache_entry,
297       U* cache_map,
298       V* identifier_map,
299       Vector<std::unique_ptr<CacheEntry>>* deletion_list);
300 
301   // Helper method to remove a cache entry. Uses the templated version base on
302   // the type of cache entry.
303   void RemoveFromCacheInternal(
304       const CacheEntry*,
305       Vector<std::unique_ptr<CacheEntry>>* deletion_list);
306 
307   // Helper method to remove all cache entries associated with an
308   // ImageFrameGenerator. Ownership of the cache entries is transferred to
309   // |deletionList|.
310   template <class U, class V>
311   void RemoveCacheIndexedByGeneratorInternal(
312       U* cache_map,
313       V* identifier_map,
314       const ImageFrameGenerator*,
315       Vector<std::unique_ptr<CacheEntry>>* deletion_list);
316 
317   // Helper method to remove cache entry pointers from the LRU list.
318   void RemoveFromCacheListInternal(
319       const Vector<std::unique_ptr<CacheEntry>>& deletion_list);
320 
321   // A doubly linked list that maintains usage history of cache entries.
322   // This is used for eviction of old entries.
323   // Head of this list is the least recently used cache entry.
324   // Tail of this list is the most recently used cache entry.
325   DoublyLinkedList<CacheEntry> ordered_cache_list_ GUARDED_BY(mutex_);
326 
327   // A lookup table for all decoder cache objects. Owns all decoder cache
328   // objects.
329   typedef HashMap<DecoderCacheKey, std::unique_ptr<DecoderCacheEntry>>
330       DecoderCacheMap;
331   DecoderCacheMap decoder_cache_map_ GUARDED_BY(mutex_);
332 
333   // A lookup table to map ImageFrameGenerator to all associated
334   // decoder cache keys.
335   typedef HashSet<DecoderCacheKey> DecoderCacheKeySet;
336   typedef HashMap<const ImageFrameGenerator*, DecoderCacheKeySet>
337       DecoderCacheKeyMap;
338   DecoderCacheKeyMap decoder_cache_key_map_ GUARDED_BY(mutex_);
339 
340   size_t heap_limit_in_bytes_ GUARDED_BY(mutex_);
341   size_t heap_memory_usage_in_bytes_ GUARDED_BY(mutex_);
342 
343   // A listener to global memory pressure events.
344   base::MemoryPressureListener memory_pressure_listener_;
345 
346   // Also protects:
347   // - the CacheEntry in |decoder_cache_map_|.
348   // - calls to underlying skBitmap's LockPixels()/UnlockPixels() as they are
349   //   not threadsafe.
350   Mutex mutex_;
351 
352   DISALLOW_COPY_AND_ASSIGN(ImageDecodingStore);
353 };
354 
355 }  // namespace blink
356 
357 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_IMAGE_DECODING_STORE_H_
358