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/file_util.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/stl_util-inl.h"
10#include "third_party/skia/include/core/SkBitmap.h"
11#include "third_party/skia/include/core/SkCanvas.h"
12
13struct IconManager::ClientRequest {
14  scoped_refptr<IconRequest> request;
15  IconGroupID group;
16  IconLoader::IconSize size;
17};
18
19IconManager::IconManager() {
20}
21
22IconManager::~IconManager() {
23  STLDeleteValues(&icon_cache_);
24}
25
26gfx::Image* IconManager::LookupIcon(const FilePath& file_name,
27                                    IconLoader::IconSize size) {
28  IconGroupID group = GetGroupIDFromFilepath(file_name);
29  IconMap::iterator it = icon_cache_.find(CacheKey(group, size));
30  if (it != icon_cache_.end())
31    return it->second;
32
33  return NULL;
34}
35
36IconManager::Handle IconManager::LoadIcon(
37    const FilePath& file_name,
38    IconLoader::IconSize size,
39    CancelableRequestConsumerBase* consumer,
40    IconRequestCallback* callback) {
41  IconGroupID group = GetGroupIDFromFilepath(file_name);
42  IconRequest* request = new IconRequest(callback);
43  AddRequest(request, consumer);
44
45  IconLoader* loader = new IconLoader(group, size, this);
46  loader->AddRef();
47  loader->Start();
48  ClientRequest client_request = { request, group, size };
49  requests_[loader] = client_request;
50  return request->handle();
51}
52
53// IconLoader::Delegate implementation -----------------------------------------
54
55bool IconManager::OnImageLoaded(IconLoader* source, gfx::Image* result) {
56  ClientRequests::iterator rit = requests_.find(source);
57  // Balances the AddRef() in LoadIcon().
58  source->Release();
59
60  // Look up our client state.
61  if (rit == requests_.end()) {
62    NOTREACHED();
63    return false;  // Return false to indicate result should be deleted.
64  }
65
66  ClientRequest client_request = rit->second;
67  if (client_request.request->canceled()) {
68    requests_.erase(rit);
69    return false;  // Return false to indicate result should be deleted.
70  }
71
72  // Cache the bitmap. Watch out: |result| or the cached bitmap may be NULL to
73  // indicate a current or past failure.
74  CacheKey key(client_request.group, client_request.size);
75  IconMap::iterator it = icon_cache_.find(key);
76  if (it != icon_cache_.end() && result && it->second) {
77    it->second->SwapRepresentations(result);
78    delete result;
79    result = it->second;
80  } else {
81    icon_cache_[key] = result;
82  }
83
84  // Inform our client that the request has completed.
85  IconRequest* icon_request = client_request.request;
86  icon_request->ForwardResult(IconRequest::TupleType(icon_request->handle(),
87                                                     result));
88  requests_.erase(rit);
89
90  return true;  // Indicates we took ownership of result.
91}
92
93IconManager::CacheKey::CacheKey(const IconGroupID& group,
94                                IconLoader::IconSize size)
95    : group(group),
96      size(size) {
97}
98
99bool IconManager::CacheKey::operator<(const CacheKey &other) const {
100  if (group != other.group)
101    return group < other.group;
102  return size < other.size;
103}
104