Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(574)

Side by Side Diff: Source/core/platform/graphics/ImageDecodingStore.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "core/platform/graphics/ImageDecodingStore.h"
28
29 #include "platform/TraceEvent.h"
30
31 namespace WebCore {
32
33 namespace {
34
35 // 32MB memory limit for cache.
36 static const size_t defaultCacheLimitInBytes = 32768 * 1024;
37 static ImageDecodingStore* s_instance = 0;
38
39 static void setInstance(ImageDecodingStore* imageDecodingStore)
40 {
41 delete s_instance;
42 s_instance = imageDecodingStore;
43 }
44
45 } // namespace
46
47 ImageDecodingStore::ImageDecodingStore()
48 : m_cacheLimitInBytes(defaultCacheLimitInBytes)
49 , m_memoryUsageInBytes(0)
50 {
51 }
52
53 ImageDecodingStore::~ImageDecodingStore()
54 {
55 #ifndef NDEBUG
56 setCacheLimitInBytes(0);
57 ASSERT(!m_imageCacheMap.size());
58 ASSERT(!m_decoderCacheMap.size());
59 ASSERT(!m_orderedCacheList.size());
60 ASSERT(!m_imageCacheKeyMap.size());
61 ASSERT(!m_decoderCacheKeyMap.size());
62 #endif
63 }
64
65 ImageDecodingStore* ImageDecodingStore::instance()
66 {
67 return s_instance;
68 }
69
70 void ImageDecodingStore::initializeOnce()
71 {
72 setInstance(ImageDecodingStore::create().leakPtr());
73 }
74
75 void ImageDecodingStore::shutdown()
76 {
77 setInstance(0);
78 }
79
80 bool ImageDecodingStore::lockCache(const ImageFrameGenerator* generator, const S kISize& scaledSize, size_t index, const ScaledImageFragment** cachedImage)
81 {
82 ASSERT(cachedImage);
83
84 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
85 {
86 MutexLocker lock(m_mutex);
87 // Public access is restricted to complete images only.
88 ImageCacheMap::iterator iter = m_imageCacheMap.find(ImageCacheEntry::mak eCacheKey(generator, scaledSize, index, ScaledImageFragment::CompleteImage));
89 if (iter == m_imageCacheMap.end())
90 return false;
91 return lockCacheEntryInternal(iter->value.get(), cachedImage, &cacheEntr iesToDelete);
92 }
93 }
94
95 void ImageDecodingStore::unlockCache(const ImageFrameGenerator* generator, const ScaledImageFragment* cachedImage)
96 {
97 MutexLocker lock(m_mutex);
98 cachedImage->bitmap().unlockPixels();
99 ImageCacheMap::iterator iter = m_imageCacheMap.find(ImageCacheEntry::makeCac heKey(generator, cachedImage->scaledSize(), cachedImage->index(), cachedImage->g eneration()));
100 ASSERT_WITH_SECURITY_IMPLICATION(iter != m_imageCacheMap.end());
101
102 CacheEntry* cacheEntry = iter->value.get();
103 cacheEntry->decrementUseCount();
104
105 // Put the entry to the end of list.
106 m_orderedCacheList.remove(cacheEntry);
107 m_orderedCacheList.append(cacheEntry);
108 }
109
110 const ScaledImageFragment* ImageDecodingStore::insertAndLockCache(const ImageFra meGenerator* generator, PassOwnPtr<ScaledImageFragment> image)
111 {
112 // Prune old cache entries to give space for the new one.
113 prune();
114
115 ScaledImageFragment* newImage = image.get();
116 OwnPtr<ImageCacheEntry> newCacheEntry = ImageCacheEntry::createAndUse(genera tor, image);
117 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
118 {
119 MutexLocker lock(m_mutex);
120
121 ImageCacheMap::iterator iter = m_imageCacheMap.find(newCacheEntry->cache Key());
122
123 // It is rare but possible that the key of a new cache entry is found.
124 // This happens if the generation ID of the image object wraps around.
125 // In this case we will try to return the existing cached object and
126 // discard the new cache object.
127 if (iter != m_imageCacheMap.end()) {
128 const ScaledImageFragment* oldImage;
129 if (lockCacheEntryInternal(iter->value.get(), &oldImage, &cacheEntri esToDelete)) {
130 newCacheEntry->decrementUseCount();
131 return oldImage;
132 }
133 }
134
135 // The new image is not locked yet so do it here.
136 newImage->bitmap().lockPixels();
137 insertCacheInternal(newCacheEntry.release(), &m_imageCacheMap, &m_imageC acheKeyMap);
138 }
139 return newImage;
140 }
141
142 bool ImageDecodingStore::lockDecoder(const ImageFrameGenerator* generator, const SkISize& scaledSize, ImageDecoder** decoder)
143 {
144 ASSERT(decoder);
145
146 MutexLocker lock(m_mutex);
147 DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::m akeCacheKey(generator, scaledSize));
148 if (iter == m_decoderCacheMap.end())
149 return false;
150
151 DecoderCacheEntry* cacheEntry = iter->value.get();
152
153 // There can only be one user of a decoder at a time.
154 ASSERT(!cacheEntry->useCount());
155 cacheEntry->incrementUseCount();
156 *decoder = cacheEntry->cachedDecoder();
157 return true;
158 }
159
160 void ImageDecodingStore::unlockDecoder(const ImageFrameGenerator* generator, con st ImageDecoder* decoder)
161 {
162 MutexLocker lock(m_mutex);
163 DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntry::m akeCacheKey(generator, decoder));
164 ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end());
165
166 CacheEntry* cacheEntry = iter->value.get();
167 cacheEntry->decrementUseCount();
168
169 // Put the entry to the end of list.
170 m_orderedCacheList.remove(cacheEntry);
171 m_orderedCacheList.append(cacheEntry);
172 }
173
174 void ImageDecodingStore::insertDecoder(const ImageFrameGenerator* generator, Pas sOwnPtr<ImageDecoder> decoder, bool isDiscardable)
175 {
176 // Prune old cache entries to give space for the new one.
177 prune();
178
179 OwnPtr<DecoderCacheEntry> newCacheEntry = DecoderCacheEntry::create(generato r, decoder, isDiscardable);
180
181 MutexLocker lock(m_mutex);
182 ASSERT(!m_decoderCacheMap.contains(newCacheEntry->cacheKey()));
183 insertCacheInternal(newCacheEntry.release(), &m_decoderCacheMap, &m_decoderC acheKeyMap);
184 }
185
186 void ImageDecodingStore::removeDecoder(const ImageFrameGenerator* generator, con st ImageDecoder* decoder)
187 {
188 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
189 {
190 MutexLocker lock(m_mutex);
191 DecoderCacheMap::iterator iter = m_decoderCacheMap.find(DecoderCacheEntr y::makeCacheKey(generator, decoder));
192 ASSERT_WITH_SECURITY_IMPLICATION(iter != m_decoderCacheMap.end());
193
194 CacheEntry* cacheEntry = iter->value.get();
195 ASSERT(cacheEntry->useCount());
196 cacheEntry->decrementUseCount();
197
198 // Delete only one decoder cache entry. Ownership of the cache entry
199 // is transfered to cacheEntriesToDelete such that object can be deleted
200 // outside of the lock.
201 removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
202
203 // Remove from LRU list.
204 removeFromCacheListInternal(cacheEntriesToDelete);
205 }
206 }
207
208 bool ImageDecodingStore::isCached(const ImageFrameGenerator* generator, const Sk ISize& scaledSize, size_t index)
209 {
210 MutexLocker lock(m_mutex);
211 ImageCacheMap::iterator iter = m_imageCacheMap.find(ImageCacheEntry::makeCac heKey(generator, scaledSize, index, ScaledImageFragment::CompleteImage));
212 if (iter == m_imageCacheMap.end())
213 return false;
214 return true;
215 }
216
217 void ImageDecodingStore::removeCacheIndexedByGenerator(const ImageFrameGenerator * generator)
218 {
219 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
220 {
221 MutexLocker lock(m_mutex);
222
223 // Remove image cache objects and decoder cache objects associated
224 // with a ImageFrameGenerator.
225 removeCacheIndexedByGeneratorInternal(&m_imageCacheMap, &m_imageCacheKey Map, generator, &cacheEntriesToDelete);
226 removeCacheIndexedByGeneratorInternal(&m_decoderCacheMap, &m_decoderCach eKeyMap, generator, &cacheEntriesToDelete);
227
228 // Remove from LRU list as well.
229 removeFromCacheListInternal(cacheEntriesToDelete);
230 }
231 }
232
233 void ImageDecodingStore::clear()
234 {
235 size_t cacheLimitInBytes;
236 {
237 MutexLocker lock(m_mutex);
238 cacheLimitInBytes = m_cacheLimitInBytes;
239 m_cacheLimitInBytes = 0;
240 }
241
242 prune();
243
244 {
245 MutexLocker lock(m_mutex);
246 m_cacheLimitInBytes = cacheLimitInBytes;
247 }
248 }
249
250 void ImageDecodingStore::setCacheLimitInBytes(size_t cacheLimit)
251 {
252 {
253 MutexLocker lock(m_mutex);
254 m_cacheLimitInBytes = cacheLimit;
255 }
256 prune();
257 }
258
259 size_t ImageDecodingStore::memoryUsageInBytes()
260 {
261 MutexLocker lock(m_mutex);
262 return m_memoryUsageInBytes;
263 }
264
265 int ImageDecodingStore::cacheEntries()
266 {
267 MutexLocker lock(m_mutex);
268 return m_imageCacheMap.size() + m_decoderCacheMap.size();
269 }
270
271 int ImageDecodingStore::imageCacheEntries()
272 {
273 MutexLocker lock(m_mutex);
274 return m_imageCacheMap.size();
275 }
276
277 int ImageDecodingStore::decoderCacheEntries()
278 {
279 MutexLocker lock(m_mutex);
280 return m_decoderCacheMap.size();
281 }
282
283 void ImageDecodingStore::prune()
284 {
285 TRACE_EVENT0("webkit", "ImageDecodingStore::prune");
286
287 Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
288 {
289 MutexLocker lock(m_mutex);
290
291 // Head of the list is the least recently used entry.
292 const CacheEntry* cacheEntry = m_orderedCacheList.head();
293
294 // Walk the list of cache entries starting from the least recently used
295 // and then keep them for deletion later.
296 while (cacheEntry && (m_memoryUsageInBytes > m_cacheLimitInBytes || !m_c acheLimitInBytes)) {
297 // Cache is not used; Remove it.
298 if (!cacheEntry->useCount())
299 removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
300 cacheEntry = cacheEntry->next();
301 }
302
303 // Remove from cache list as well.
304 removeFromCacheListInternal(cacheEntriesToDelete);
305 }
306 }
307
308 bool ImageDecodingStore::lockCacheEntryInternal(ImageCacheEntry* cacheEntry, con st ScaledImageFragment** cachedImage, Vector<OwnPtr<CacheEntry> >* deletionList)
309 {
310 ScaledImageFragment* image = cacheEntry->cachedImage();
311
312 image->bitmap().lockPixels();
313
314 // Memory for this image entry might be discarded already.
315 // In this case remove the entry.
316 if (!image->bitmap().getPixels()) {
317 image->bitmap().unlockPixels();
318 removeFromCacheInternal(cacheEntry, &m_imageCacheMap, &m_imageCacheKeyMa p, deletionList);
319 removeFromCacheListInternal(*deletionList);
320 return false;
321 }
322 cacheEntry->incrementUseCount();
323 *cachedImage = image;
324 return true;
325 }
326
327 template<class T, class U, class V>
328 void ImageDecodingStore::insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheM ap, V* identifierMap)
329 {
330 // Usage of discardable memory is not counted because we want to use more
331 // than the cache limit allows. Cache limit only applies to non-discardable
332 // objects.
333 if (!cacheEntry->isDiscardable())
334 incrementMemoryUsage(cacheEntry->memoryUsageInBytes());
335
336 // m_orderedCacheList is used to support LRU operations to reorder cache
337 // entries quickly.
338 m_orderedCacheList.append(cacheEntry.get());
339
340 typename U::KeyType key = cacheEntry->cacheKey();
341 typename V::AddResult result = identifierMap->add(cacheEntry->generator(), t ypename V::MappedType());
342 result.iterator->value.add(key);
343 cacheMap->add(key, cacheEntry);
344
345 TRACE_COUNTER1("webkit", "ImageDecodingStoreMemoryUsageBytes", m_memoryUsage InBytes);
346 TRACE_COUNTER1("webkit", "ImageDecodingStoreNumOfImages", m_imageCacheMap.si ze());
347 TRACE_COUNTER1("webkit", "ImageDecodingStoreNumOfDecoders", m_decoderCacheMa p.size());
348 }
349
350 template<class T, class U, class V>
351 void ImageDecodingStore::removeFromCacheInternal(const T* cacheEntry, U* cacheMa p, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList)
352 {
353 if (!cacheEntry->isDiscardable())
354 decrementMemoryUsage(cacheEntry->memoryUsageInBytes());
355
356 // Remove entry from identifier map.
357 typename V::iterator iter = identifierMap->find(cacheEntry->generator());
358 ASSERT(iter != identifierMap->end());
359 iter->value.remove(cacheEntry->cacheKey());
360 if (!iter->value.size())
361 identifierMap->remove(iter);
362
363 // Remove entry from cache map.
364 deletionList->append(cacheMap->take(cacheEntry->cacheKey()));
365
366 TRACE_COUNTER1("webkit", "ImageDecodingStoreMemoryUsageBytes", m_memoryUsage InBytes);
367 TRACE_COUNTER1("webkit", "ImageDecodingStoreNumOfImages", m_imageCacheMap.si ze());
368 TRACE_COUNTER1("webkit", "ImageDecodingStoreNumOfDecoders", m_decoderCacheMa p.size());
369 }
370
371 void ImageDecodingStore::removeFromCacheInternal(const CacheEntry* cacheEntry, V ector<OwnPtr<CacheEntry> >* deletionList)
372 {
373 if (cacheEntry->type() == CacheEntry::TypeImage) {
374 removeFromCacheInternal(static_cast<const ImageCacheEntry*>(cacheEntry), &m_imageCacheMap, &m_imageCacheKeyMap, deletionList);
375 } else if (cacheEntry->type() == CacheEntry::TypeDecoder) {
376 removeFromCacheInternal(static_cast<const DecoderCacheEntry*>(cacheEntry ), &m_decoderCacheMap, &m_decoderCacheKeyMap, deletionList);
377 } else {
378 ASSERT(false);
379 }
380 }
381
382 template<class U, class V>
383 void ImageDecodingStore::removeCacheIndexedByGeneratorInternal(U* cacheMap, V* i dentifierMap, const ImageFrameGenerator* generator, Vector<OwnPtr<CacheEntry> >* deletionList)
384 {
385 typename V::iterator iter = identifierMap->find(generator);
386 if (iter == identifierMap->end())
387 return;
388
389 // Get all cache identifiers associated with generator.
390 Vector<typename U::KeyType> cacheIdentifierList;
391 copyToVector(iter->value, cacheIdentifierList);
392
393 // For each cache identifier find the corresponding CacheEntry and remove it .
394 for (size_t i = 0; i < cacheIdentifierList.size(); ++i) {
395 ASSERT(cacheMap->contains(cacheIdentifierList[i]));
396 const typename U::MappedType::PtrType cacheEntry = cacheMap->get(cacheId entifierList[i]);
397 ASSERT(!cacheEntry->useCount());
398 removeFromCacheInternal(cacheEntry, cacheMap, identifierMap, deletionLis t);
399 }
400 }
401
402 void ImageDecodingStore::removeFromCacheListInternal(const Vector<OwnPtr<CacheEn try> >& deletionList)
403 {
404 for (size_t i = 0; i < deletionList.size(); ++i)
405 m_orderedCacheList.remove(deletionList[i].get());
406 }
407
408 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/ImageDecodingStore.h ('k') | Source/core/platform/graphics/ImageDecodingStoreTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698