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 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 CancelableTaskTracker::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 
     79 bool 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 
     95 bool 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 
    137 IconManager::CacheKey::CacheKey(const IconGroupID& group,
    138                                 IconLoader::IconSize size)
    139     : group(group),
    140       size(size) {
    141 }
    142 
    143 bool IconManager::CacheKey::operator<(const CacheKey &other) const {
    144   if (group != other.group)
    145     return group < other.group;
    146   return size < other.size;
    147 }
    148