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