1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/icon_manager.h" 6 7 #include "base/bind.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/stl_util.h" 10 #include "base/task_runner.h" 11 #include "third_party/skia/include/core/SkBitmap.h" 12 #include "third_party/skia/include/core/SkCanvas.h" 13 14 namespace { 15 16 void RunCallbackIfNotCanceled( 17 const CancelableTaskTracker::IsCanceledCallback& is_canceled, 18 const IconManager::IconRequestCallback& callback, 19 gfx::Image* image) { 20 if (is_canceled.Run()) 21 return; 22 callback.Run(image); 23 } 24 25 } // namespace 26 27 struct IconManager::ClientRequest { 28 IconRequestCallback callback; 29 base::FilePath file_path; 30 IconLoader::IconSize size; 31 }; 32 33 IconManager::IconManager() { 34 } 35 36 IconManager::~IconManager() { 37 STLDeleteValues(&icon_cache_); 38 } 39 40 gfx::Image* IconManager::LookupIconFromFilepath(const base::FilePath& file_name, 41 IconLoader::IconSize size) { 42 GroupMap::iterator it = group_cache_.find(file_name); 43 if (it != group_cache_.end()) 44 return LookupIconFromGroup(it->second, size); 45 46 return NULL; 47 } 48 49 gfx::Image* IconManager::LookupIconFromGroup(const IconGroupID& group, 50 IconLoader::IconSize size) { 51 IconMap::iterator it = icon_cache_.find(CacheKey(group, size)); 52 if (it != icon_cache_.end()) 53 return it->second; 54 55 return NULL; 56 } 57 58 CancelableTaskTracker::TaskId IconManager::LoadIcon( 59 const base::FilePath& file_name, 60 IconLoader::IconSize size, 61 const IconRequestCallback& callback, 62 CancelableTaskTracker* tracker) { 63 IconLoader* loader = new IconLoader(file_name, size, this); 64 loader->AddRef(); 65 loader->Start(); 66 67 CancelableTaskTracker::IsCanceledCallback is_canceled; 68 CancelableTaskTracker::TaskId id = tracker->NewTrackedTaskId(&is_canceled); 69 IconRequestCallback callback_runner = base::Bind( 70 &RunCallbackIfNotCanceled, is_canceled, callback); 71 72 ClientRequest client_request = { callback_runner, file_name, size }; 73 requests_[loader] = client_request; 74 return id; 75 } 76 77 // IconLoader::Delegate implementation ----------------------------------------- 78 79 bool IconManager::OnGroupLoaded(IconLoader* loader, 80 const IconGroupID& group) { 81 ClientRequests::iterator rit = requests_.find(loader); 82 if (rit == requests_.end()) { 83 NOTREACHED(); 84 return false; 85 } 86 87 gfx::Image* result = LookupIconFromGroup(group, rit->second.size); 88 if (!result) { 89 return false; 90 } 91 92 return OnImageLoaded(loader, result, group); 93 } 94 95 bool IconManager::OnImageLoaded( 96 IconLoader* loader, gfx::Image* result, const IconGroupID& group) { 97 ClientRequests::iterator rit = requests_.find(loader); 98 99 // Balances the AddRef() in LoadIcon(). 100 loader->Release(); 101 102 // Look up our client state. 103 if (rit == requests_.end()) { 104 NOTREACHED(); 105 return false; // Return false to indicate result should be deleted. 106 } 107 108 const ClientRequest& client_request = rit->second; 109 110 // Cache the bitmap. Watch out: |result| may be NULL to indicate a current 111 // failure. We assume that if we have an entry in |icon_cache_| 112 // it must not be NULL. 113 CacheKey key(group, client_request.size); 114 IconMap::iterator it = icon_cache_.find(key); 115 if (it != icon_cache_.end()) { 116 if (!result) { 117 delete it->second; 118 icon_cache_.erase(it); 119 } else if (result != it->second) { 120 it->second->SwapRepresentations(result); 121 delete result; 122 result = it->second; 123 } 124 } else if (result) { 125 icon_cache_[key] = result; 126 } 127 128 group_cache_[client_request.file_path] = group; 129 130 // Inform our client that the request has completed. 131 client_request.callback.Run(result); 132 requests_.erase(rit); 133 134 return true; // Indicates we took ownership of result. 135 } 136 137 IconManager::CacheKey::CacheKey(const IconGroupID& group, 138 IconLoader::IconSize size) 139 : group(group), 140 size(size) { 141 } 142 143 bool IconManager::CacheKey::operator<(const CacheKey &other) const { 144 if (group != other.group) 145 return group < other.group; 146 return size < other.size; 147 } 148