Home | History | Annotate | Download | only in browser
      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