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