icon_manager.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/icon_manager.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/task_runner.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkCanvas.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RunCallbackIfNotCanceled( 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CancelableTaskTracker::IsCanceledCallback& is_canceled, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IconManager::IconRequestCallback& callback, 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Image* image) { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_canceled.Run()) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback.Run(image); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct IconManager::ClientRequest { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IconRequestCallback callback; 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::FilePath file_path; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IconLoader::IconSize size; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IconManager::IconManager() { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)IconManager::~IconManager() { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STLDeleteValues(&icon_cache_); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Image* IconManager::LookupIconFromFilepath(const base::FilePath& file_name, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 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 49gfx::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 58CancelableTaskTracker::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 79bool 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 95bool 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 137IconManager::CacheKey::CacheKey(const IconGroupID& group, 138 IconLoader::IconSize size) 139 : group(group), 140 size(size) { 141} 142 143bool IconManager::CacheKey::operator<(const CacheKey &other) const { 144 if (group != other.group) 145 return group < other.group; 146 return size < other.size; 147} 148