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 base::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 base::CancelableTaskTracker::TaskId IconManager::LoadIcon( 59 const base::FilePath& file_name, 60 IconLoader::IconSize size, 61 const IconRequestCallback& callback, 62 base::CancelableTaskTracker* tracker) { 63 IconLoader* loader = new IconLoader(file_name, size, this); 64 loader->AddRef(); 65 loader->Start(); 66 67 base::CancelableTaskTracker::IsCanceledCallback is_canceled; 68 base::CancelableTaskTracker::TaskId id = 69 tracker->NewTrackedTaskId(&is_canceled); 70 IconRequestCallback callback_runner = base::Bind( 71 &RunCallbackIfNotCanceled, is_canceled, callback); 72 73 ClientRequest client_request = { callback_runner, file_name, size }; 74 requests_[loader] = client_request; 75 return id; 76 } 77 78 // IconLoader::Delegate implementation ----------------------------------------- 79 80 bool IconManager::OnGroupLoaded(IconLoader* loader, 81 const IconGroupID& group) { 82 ClientRequests::iterator rit = requests_.find(loader); 83 if (rit == requests_.end()) { 84 NOTREACHED(); 85 return false; 86 } 87 88 gfx::Image* result = LookupIconFromGroup(group, rit->second.size); 89 if (!result) { 90 return false; 91 } 92 93 return OnImageLoaded(loader, result, group); 94 } 95 96 bool IconManager::OnImageLoaded( 97 IconLoader* loader, gfx::Image* result, const IconGroupID& group) { 98 ClientRequests::iterator rit = requests_.find(loader); 99 100 // Balances the AddRef() in LoadIcon(). 101 loader->Release(); 102 103 // Look up our client state. 104 if (rit == requests_.end()) { 105 NOTREACHED(); 106 return false; // Return false to indicate result should be deleted. 107 } 108 109 const ClientRequest& client_request = rit->second; 110 111 // Cache the bitmap. Watch out: |result| may be NULL to indicate a current 112 // failure. We assume that if we have an entry in |icon_cache_| 113 // it must not be NULL. 114 CacheKey key(group, client_request.size); 115 IconMap::iterator it = icon_cache_.find(key); 116 if (it != icon_cache_.end()) { 117 if (!result) { 118 delete it->second; 119 icon_cache_.erase(it); 120 } else if (result != it->second) { 121 it->second->SwapRepresentations(result); 122 delete result; 123 result = it->second; 124 } 125 } else if (result) { 126 icon_cache_[key] = result; 127 } 128 129 group_cache_[client_request.file_path] = group; 130 131 // Inform our client that the request has completed. 132 client_request.callback.Run(result); 133 requests_.erase(rit); 134 135 return true; // Indicates we took ownership of result. 136 } 137 138 IconManager::CacheKey::CacheKey(const IconGroupID& group, 139 IconLoader::IconSize size) 140 : group(group), 141 size(size) { 142 } 143 144 bool IconManager::CacheKey::operator<(const CacheKey &other) const { 145 if (group != other.group) 146 return group < other.group; 147 return size < other.size; 148 } 149