Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / ImageDecodingStore.cpp
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 #include "config.h"
27 #include "platform/graphics/ImageDecodingStore.h"
28
29 #include "platform/TraceEvent.h"
30 #include "wtf/Threading.h"
31
32 namespace blink {
33
34 namespace {
35
36 static const size_t defaultMaxTotalSizeOfHeapEntries = 32 * 1024 * 1024;
37
38 } // namespace
39
40 ImageDecodingStore::ImageDecodingStore()
41     : m_heapLimitInBytes(defaultMaxTotalSizeOfHeapEntries)
42     , m_heapMemoryUsageInBytes(0)
43 {
44 }
45
46 ImageDecodingStore::~ImageDecodingStore()
47 {
48 #if ENABLE(ASSERT)
49     setCacheLimitInBytes(0);
50     ASSERT(!m_decoderCacheMap.size());
51     ASSERT(!m_orderedCacheList.size());
52     ASSERT(!m_decoderCacheKeyMap.size());
53 #endif
54 }
55
56 ImageDecodingStore* ImageDecodingStore::instance()
57 {
58     AtomicallyInitializedStatic(ImageDecodingStore*, store = ImageDecodingStore::create().leakPtr());
59     return store;
60 }
61
62 bool ImageDecodingStore::lockDecoder(const ImageFrameGenerator* generator, const SkISize& scaledSize, ImageDecoder** decoder)
63 {
64     ASSERT(decoder);
65
66     MutexLocker lock(m_mutex);
67     DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, scaledSize));
68     if (iter == m_decoderCacheMap.end())
69         return false;
70
71     DecoderCacheEntry* cacheEntry = iter->value.get();
72
73     // There can only be one user of a decoder at a time.
74     ASSERT(!cacheEntry->useCount());
75     cacheEntry->incrementUseCount();
76     *decoder = cacheEntry->cachedDecoder();
77     return true;
78 }
79
80 void ImageDecodingStore::unlockDecoder(const ImageFrameGenerator* generator, const ImageDecoder* decoder)
81 {
82     MutexLocker lock(m_mutex);
83     DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, decoder));
84     ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end());
85
86     CacheEntry* cacheEntry = iter->value.get();
87     cacheEntry->decrementUseCount();
88
89     // Put the entry to the end of list.
90     m_orderedCacheList.remove(cacheEntry);
91     m_orderedCacheList.append(cacheEntry);
92 }
93
94 void ImageDecodingStore::insertDecoder(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder)
95 {
96     // Prune old cache entries to give space for the new one.
97     prune();
98
99     OwnPtr<DecoderCacheEntry> newCacheEntry = DecoderCacheEntry::create(generator, decoder);
100
101     MutexLocker lock(m_mutex);
102     ASSERT(!m_decoderCacheMap.contains(newCacheEntry->cacheKey()));
103     insertCacheInternal(newCacheEntry.release(), &m_decoderCacheMap, &m_decoderCacheKeyMap);
104 }
105
106 void ImageDecodingStore::removeDecoder(const ImageFrameGenerator* generator, const ImageDecoder* decoder)
107 {
108     Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
109     {
110         MutexLocker lock(m_mutex);
111         DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::makeCacheKey(generator, decoder));
112         ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end());
113
114         CacheEntry* cacheEntry = iter->value.get();
115         ASSERT(cacheEntry->useCount());
116         cacheEntry->decrementUseCount();
117
118         // Delete only one decoder cache entry. Ownership of the cache entry
119         // is transfered to cacheEntriesToDelete such that object can be deleted
120         // outside of the lock.
121         removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
122
123         // Remove from LRU list.
124         removeFromCacheListInternal(cacheEntriesToDelete);
125     }
126 }
127
128 void ImageDecodingStore::removeCacheIndexedByGenerator(const ImageFrameGenerator* generator)
129 {
130     Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
131     {
132         MutexLocker lock(m_mutex);
133
134         // Remove image cache objects and decoder cache objects associated
135         // with a ImageFrameGenerator.
136         removeCacheIndexedByGeneratorInternal(&m_decoderCacheMap, &m_decoderCacheKeyMap, generator, &cacheEntriesToDelete);
137
138         // Remove from LRU list as well.
139         removeFromCacheListInternal(cacheEntriesToDelete);
140     }
141 }
142
143 void ImageDecodingStore::clear()
144 {
145     size_t cacheLimitInBytes;
146     {
147         MutexLocker lock(m_mutex);
148         cacheLimitInBytes = m_heapLimitInBytes;
149         m_heapLimitInBytes = 0;
150     }
151
152     prune();
153
154     {
155         MutexLocker lock(m_mutex);
156         m_heapLimitInBytes = cacheLimitInBytes;
157     }
158 }
159
160 void ImageDecodingStore::setCacheLimitInBytes(size_t cacheLimit)
161 {
162     {
163         MutexLocker lock(m_mutex);
164         m_heapLimitInBytes = cacheLimit;
165     }
166     prune();
167 }
168
169 size_t ImageDecodingStore::memoryUsageInBytes()
170 {
171     MutexLocker lock(m_mutex);
172     return m_heapMemoryUsageInBytes;
173 }
174
175 int ImageDecodingStore::cacheEntries()
176 {
177     MutexLocker lock(m_mutex);
178     return m_decoderCacheMap.size();
179 }
180
181 int ImageDecodingStore::decoderCacheEntries()
182 {
183     MutexLocker lock(m_mutex);
184     return m_decoderCacheMap.size();
185 }
186
187 void ImageDecodingStore::prune()
188 {
189     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStore::prune");
190
191     Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
192     {
193         MutexLocker lock(m_mutex);
194
195         // Head of the list is the least recently used entry.
196         const CacheEntry* cacheEntry = m_orderedCacheList.head();
197
198         // Walk the list of cache entries starting from the least recently used
199         // and then keep them for deletion later.
200         while (cacheEntry) {
201             const bool isPruneNeeded = m_heapMemoryUsageInBytes > m_heapLimitInBytes || !m_heapLimitInBytes;
202             if (!isPruneNeeded)
203                 break;
204
205             // Cache is not used; Remove it.
206             if (!cacheEntry->useCount())
207                 removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
208             cacheEntry = cacheEntry->next();
209         }
210
211         // Remove from cache list as well.
212         removeFromCacheListInternal(cacheEntriesToDelete);
213     }
214 }
215
216 template<class T, class U, class V>
217 void ImageDecodingStore::insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheMap, V* identifierMap)
218 {
219     const size_t cacheEntryBytes = cacheEntry->memoryUsageInBytes();
220     m_heapMemoryUsageInBytes += cacheEntryBytes;
221
222     // m_orderedCacheList is used to support LRU operations to reorder cache
223     // entries quickly.
224     m_orderedCacheList.append(cacheEntry.get());
225
226     typename U::KeyType key = cacheEntry->cacheKey();
227     typename V::AddResult result = identifierMap->add(cacheEntry->generator(), typename V::MappedType());
228     result.storedValue->value.add(key);
229     cacheMap->add(key, cacheEntry);
230
231     TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes);
232     TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap.size());
233 }
234
235 template<class T, class U, class V>
236 void ImageDecodingStore::removeFromCacheInternal(const T* cacheEntry, U* cacheMap, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList)
237 {
238     const size_t cacheEntryBytes = cacheEntry->memoryUsageInBytes();
239     ASSERT(m_heapMemoryUsageInBytes >= cacheEntryBytes);
240     m_heapMemoryUsageInBytes -= cacheEntryBytes;
241
242     // Remove entry from identifier map.
243     typename V::iterator iter = identifierMap->find(cacheEntry->generator());
244     ASSERT(iter != identifierMap->end());
245     iter->value.remove(cacheEntry->cacheKey());
246     if (!iter->value.size())
247         identifierMap->remove(iter);
248
249     // Remove entry from cache map.
250     deletionList->append(cacheMap->take(cacheEntry->cacheKey()));
251
252     TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreHeapMemoryUsageBytes", m_heapMemoryUsageInBytes);
253     TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink.image_decoding"), "ImageDecodingStoreNumOfDecoders", m_decoderCacheMap.size());
254 }
255
256 void ImageDecodingStore::removeFromCacheInternal(const CacheEntry* cacheEntry, Vector<OwnPtr<CacheEntry> >* deletionList)
257 {
258     if (cacheEntry->type() == CacheEntry::TypeDecoder) {
259         removeFromCacheInternal(static_cast<const DecoderCacheEntry*>(cacheEntry), &m_decoderCacheMap, &m_decoderCacheKeyMap, deletionList);
260     } else {
261         ASSERT(false);
262     }
263 }
264
265 template<class U, class V>
266 void ImageDecodingStore::removeCacheIndexedByGeneratorInternal(U* cacheMap, V* identifierMap, const ImageFrameGenerator* generator, Vector<OwnPtr<CacheEntry> >* deletionList)
267 {
268     typename V::iterator iter = identifierMap->find(generator);
269     if (iter == identifierMap->end())
270         return;
271
272     // Get all cache identifiers associated with generator.
273     Vector<typename U::KeyType> cacheIdentifierList;
274     copyToVector(iter->value, cacheIdentifierList);
275
276     // For each cache identifier find the corresponding CacheEntry and remove it.
277     for (size_t i = 0; i < cacheIdentifierList.size(); ++i) {
278         ASSERT(cacheMap->contains(cacheIdentifierList[i]));
279         const typename U::MappedType::PtrType cacheEntry = cacheMap->get(cacheIdentifierList[i]);
280         ASSERT(!cacheEntry->useCount());
281         removeFromCacheInternal(cacheEntry, cacheMap, identifierMap, deletionList);
282     }
283 }
284
285 void ImageDecodingStore::removeFromCacheListInternal(const Vector<OwnPtr<CacheEntry> >& deletionList)
286 {
287     for (size_t i = 0; i < deletionList.size(); ++i)
288         m_orderedCacheList.remove(deletionList[i].get());
289 }
290
291 } // namespace blink