Home | History | Annotate | Download | only in favicon
      1 // Copyright (c) 2012 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/favicon/favicon_service.h"
      6 
      7 #include "base/hash.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "chrome/browser/favicon/favicon_util.h"
     10 #include "chrome/browser/history/history_backend.h"
     11 #include "chrome/browser/history/history_service.h"
     12 #include "chrome/browser/history/history_service_factory.h"
     13 #include "chrome/browser/history/select_favicon_frames.h"
     14 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
     15 #include "chrome/common/favicon/favicon_types.h"
     16 #include "chrome/common/importer/imported_favicon_usage.h"
     17 #include "chrome/common/url_constants.h"
     18 #include "extensions/common/constants.h"
     19 #include "third_party/skia/include/core/SkBitmap.h"
     20 #include "ui/gfx/codec/png_codec.h"
     21 #include "ui/gfx/favicon_size.h"
     22 #include "ui/gfx/image/image_skia.h"
     23 
     24 using base::Bind;
     25 
     26 namespace {
     27 
     28 void CancelOrRunFaviconResultsCallback(
     29     const CancelableTaskTracker::IsCanceledCallback& is_canceled,
     30     const FaviconService::FaviconResultsCallback& callback,
     31     const std::vector<chrome::FaviconBitmapResult>& results) {
     32   if (is_canceled.Run())
     33     return;
     34   callback.Run(results);
     35 }
     36 
     37 // Helper to run callback with empty results if we cannot get the history
     38 // service.
     39 CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
     40     const FaviconService::FaviconResultsCallback& callback,
     41     CancelableTaskTracker* tracker) {
     42   return tracker->PostTask(
     43       base::MessageLoopProxy::current().get(),
     44       FROM_HERE,
     45       Bind(callback, std::vector<chrome::FaviconBitmapResult>()));
     46 }
     47 
     48 }  // namespace
     49 
     50 FaviconService::FaviconService(HistoryService* history_service)
     51     : history_service_(history_service) {
     52 }
     53 
     54 // static
     55 void FaviconService::FaviconResultsCallbackRunner(
     56     const FaviconResultsCallback& callback,
     57     const std::vector<chrome::FaviconBitmapResult>* results) {
     58   callback.Run(*results);
     59 }
     60 
     61 CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
     62     const GURL& icon_url,
     63     chrome::IconType icon_type,
     64     int desired_size_in_dip,
     65     const FaviconImageCallback& callback,
     66     CancelableTaskTracker* tracker) {
     67   FaviconResultsCallback callback_runner =
     68       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
     69            base::Unretained(this), callback, desired_size_in_dip);
     70   if (history_service_) {
     71     std::vector<GURL> icon_urls;
     72     icon_urls.push_back(icon_url);
     73     return history_service_->GetFavicons(
     74         icon_urls, icon_type, desired_size_in_dip,
     75         FaviconUtil::GetFaviconScaleFactors(), callback_runner, tracker);
     76   } else {
     77     return RunWithEmptyResultAsync(callback_runner, tracker);
     78   }
     79 }
     80 
     81 CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
     82     const GURL& icon_url,
     83     chrome::IconType icon_type,
     84     int desired_size_in_dip,
     85     ui::ScaleFactor desired_scale_factor,
     86     const FaviconRawCallback& callback,
     87     CancelableTaskTracker* tracker) {
     88   FaviconResultsCallback callback_runner =
     89       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
     90            base::Unretained(this),
     91            callback, desired_size_in_dip, desired_scale_factor);
     92 
     93   if (history_service_) {
     94     std::vector<GURL> icon_urls;
     95     icon_urls.push_back(icon_url);
     96     std::vector<ui::ScaleFactor> desired_scale_factors;
     97     desired_scale_factors.push_back(desired_scale_factor);
     98 
     99     return history_service_->GetFavicons(
    100         icon_urls, icon_type, desired_size_in_dip, desired_scale_factors,
    101         callback_runner, tracker);
    102   } else {
    103     return RunWithEmptyResultAsync(callback_runner, tracker);
    104   }
    105 }
    106 
    107 CancelableTaskTracker::TaskId FaviconService::GetFavicon(
    108     const GURL& icon_url,
    109     chrome::IconType icon_type,
    110     int desired_size_in_dip,
    111     const FaviconResultsCallback& callback,
    112     CancelableTaskTracker* tracker) {
    113   if (history_service_) {
    114     std::vector<GURL> icon_urls;
    115     icon_urls.push_back(icon_url);
    116     return history_service_->GetFavicons(
    117         icon_urls, icon_type, desired_size_in_dip,
    118         FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
    119   } else {
    120     return RunWithEmptyResultAsync(callback, tracker);
    121   }
    122 }
    123 
    124 CancelableTaskTracker::TaskId FaviconService::UpdateFaviconMappingsAndFetch(
    125     const GURL& page_url,
    126     const std::vector<GURL>& icon_urls,
    127     int icon_types,
    128     int desired_size_in_dip,
    129     const FaviconResultsCallback& callback,
    130     CancelableTaskTracker* tracker) {
    131   if (history_service_) {
    132     return history_service_->UpdateFaviconMappingsAndFetch(
    133         page_url, icon_urls, icon_types, desired_size_in_dip,
    134         FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
    135   } else {
    136     return RunWithEmptyResultAsync(callback, tracker);
    137   }
    138 }
    139 
    140 CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL(
    141     const FaviconForURLParams& params,
    142     const FaviconImageCallback& callback,
    143     CancelableTaskTracker* tracker) {
    144   return GetFaviconForURLImpl(
    145       params,
    146       FaviconUtil::GetFaviconScaleFactors(),
    147       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
    148            base::Unretained(this),
    149            callback,
    150            params.desired_size_in_dip),
    151       tracker);
    152 }
    153 
    154 CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForURL(
    155     const FaviconForURLParams& params,
    156     ui::ScaleFactor desired_scale_factor,
    157     const FaviconRawCallback& callback,
    158     CancelableTaskTracker* tracker) {
    159   std::vector<ui::ScaleFactor> desired_scale_factors;
    160   desired_scale_factors.push_back(desired_scale_factor);
    161   return GetFaviconForURLImpl(
    162       params,
    163       desired_scale_factors,
    164       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
    165            base::Unretained(this),
    166            callback,
    167            params.desired_size_in_dip,
    168            desired_scale_factor),
    169       tracker);
    170 }
    171 
    172 CancelableTaskTracker::TaskId FaviconService::GetFaviconForURL(
    173     const FaviconForURLParams& params,
    174     const FaviconResultsCallback& callback,
    175     CancelableTaskTracker* tracker) {
    176   return GetFaviconForURLImpl(params,
    177                               FaviconUtil::GetFaviconScaleFactors(),
    178                               callback,
    179                               tracker);
    180 }
    181 
    182 CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
    183     chrome::FaviconID favicon_id,
    184     const FaviconRawCallback& callback,
    185     CancelableTaskTracker* tracker) {
    186   // Use 0 as |desired_size_in_dip| to get the largest bitmap for |favicon_id|
    187   // without any resizing.
    188   int desired_size_in_dip = 0;
    189   ui::ScaleFactor desired_scale_factor = ui::SCALE_FACTOR_100P;
    190   FaviconResultsCallback callback_runner =
    191       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
    192            base::Unretained(this),
    193            callback, desired_size_in_dip, desired_scale_factor);
    194 
    195   if (history_service_) {
    196     return history_service_->GetFaviconForID(
    197         favicon_id, desired_size_in_dip, desired_scale_factor,
    198         callback_runner, tracker);
    199   } else {
    200     return RunWithEmptyResultAsync(callback_runner, tracker);
    201   }
    202 }
    203 
    204 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
    205   if (history_service_)
    206     history_service_->SetFaviconsOutOfDateForPage(page_url);
    207 }
    208 
    209 void FaviconService::CloneFavicon(const GURL& old_page_url,
    210                                   const GURL& new_page_url) {
    211   if (history_service_)
    212     history_service_->CloneFavicons(old_page_url, new_page_url);
    213 }
    214 
    215 void FaviconService::SetImportedFavicons(
    216     const std::vector<ImportedFaviconUsage>& favicon_usage) {
    217   if (history_service_)
    218     history_service_->SetImportedFavicons(favicon_usage);
    219 }
    220 
    221 void FaviconService::MergeFavicon(
    222     const GURL& page_url,
    223     const GURL& icon_url,
    224     chrome::IconType icon_type,
    225     scoped_refptr<base::RefCountedMemory> bitmap_data,
    226     const gfx::Size& pixel_size) {
    227   if (history_service_) {
    228     history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
    229                                    pixel_size);
    230   }
    231 }
    232 
    233 void FaviconService::SetFavicons(const GURL& page_url,
    234                                  const GURL& icon_url,
    235                                  chrome::IconType icon_type,
    236                                  const gfx::Image& image) {
    237   if (!history_service_)
    238     return;
    239 
    240   gfx::ImageSkia image_skia = image.AsImageSkia();
    241   image_skia.EnsureRepsForSupportedScaleFactors();
    242   const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
    243   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
    244   for (size_t i = 0; i < image_reps.size(); ++i) {
    245     scoped_refptr<base::RefCountedBytes> bitmap_data(
    246         new base::RefCountedBytes());
    247     if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps[i].sk_bitmap(),
    248                                           false,
    249                                           &bitmap_data->data())) {
    250       gfx::Size pixel_size(image_reps[i].pixel_width(),
    251                            image_reps[i].pixel_height());
    252       chrome::FaviconBitmapData bitmap_data_element;
    253       bitmap_data_element.bitmap_data = bitmap_data;
    254       bitmap_data_element.pixel_size = pixel_size;
    255       bitmap_data_element.icon_url = icon_url;
    256 
    257       favicon_bitmap_data.push_back(bitmap_data_element);
    258     }
    259   }
    260 
    261   history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data);
    262 }
    263 
    264 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
    265   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
    266   missing_favicon_urls_.insert(url_hash);
    267 }
    268 
    269 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
    270   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
    271   return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
    272 }
    273 
    274 void FaviconService::ClearUnableToDownloadFavicons() {
    275   missing_favicon_urls_.clear();
    276 }
    277 
    278 FaviconService::~FaviconService() {}
    279 
    280 CancelableTaskTracker::TaskId FaviconService::GetFaviconForURLImpl(
    281     const FaviconForURLParams& params,
    282     const std::vector<ui::ScaleFactor>& desired_scale_factors,
    283     const FaviconResultsCallback& callback,
    284     CancelableTaskTracker* tracker) {
    285   if (params.page_url.SchemeIs(chrome::kChromeUIScheme) ||
    286       params.page_url.SchemeIs(extensions::kExtensionScheme)) {
    287     CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
    288     CancelableTaskTracker::TaskId id =
    289         tracker->NewTrackedTaskId(&is_canceled_cb);
    290 
    291     FaviconResultsCallback cancelable_cb =
    292         Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback);
    293     ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(
    294         params.profile, params.page_url, desired_scale_factors, cancelable_cb);
    295     return id;
    296   } else if (history_service_) {
    297     return history_service_->GetFaviconsForURL(params.page_url,
    298                                                params.icon_types,
    299                                                params.desired_size_in_dip,
    300                                                desired_scale_factors,
    301                                                callback,
    302                                                tracker);
    303   } else {
    304     return RunWithEmptyResultAsync(callback, tracker);
    305   }
    306 }
    307 
    308 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
    309     const FaviconImageCallback& callback,
    310     int desired_size_in_dip,
    311     const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
    312   chrome::FaviconImageResult image_result;
    313   image_result.image = FaviconUtil::SelectFaviconFramesFromPNGs(
    314       favicon_bitmap_results,
    315       FaviconUtil::GetFaviconScaleFactors(),
    316       desired_size_in_dip);
    317   FaviconUtil::SetFaviconColorSpace(&image_result.image);
    318 
    319   image_result.icon_url = image_result.image.IsEmpty() ?
    320       GURL() : favicon_bitmap_results[0].icon_url;
    321   callback.Run(image_result);
    322 }
    323 
    324 void FaviconService::RunFaviconRawCallbackWithBitmapResults(
    325     const FaviconRawCallback& callback,
    326     int desired_size_in_dip,
    327     ui::ScaleFactor desired_scale_factor,
    328     const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
    329   if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
    330     callback.Run(chrome::FaviconBitmapResult());
    331     return;
    332   }
    333 
    334   DCHECK_EQ(1u, favicon_bitmap_results.size());
    335   chrome::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0];
    336 
    337   // If the desired size is 0, SelectFaviconFrames() will return the largest
    338   // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
    339   // data for a single bitmap, return it and avoid an unnecessary decode.
    340   if (desired_size_in_dip == 0) {
    341     callback.Run(bitmap_result);
    342     return;
    343   }
    344 
    345   // If history bitmap is already desired pixel size, return early.
    346   float desired_scale = ui::GetScaleFactorScale(desired_scale_factor);
    347   int desired_edge_width_in_pixel = static_cast<int>(
    348       desired_size_in_dip * desired_scale + 0.5f);
    349   gfx::Size desired_size_in_pixel(desired_edge_width_in_pixel,
    350                                   desired_edge_width_in_pixel);
    351   if (bitmap_result.pixel_size == desired_size_in_pixel) {
    352     callback.Run(bitmap_result);
    353     return;
    354   }
    355 
    356   // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
    357   // convert back.
    358   std::vector<ui::ScaleFactor> desired_scale_factors;
    359   desired_scale_factors.push_back(desired_scale_factor);
    360   gfx::Image resized_image = FaviconUtil::SelectFaviconFramesFromPNGs(
    361       favicon_bitmap_results, desired_scale_factors, desired_size_in_dip);
    362 
    363   std::vector<unsigned char> resized_bitmap_data;
    364   if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
    365                                          &resized_bitmap_data)) {
    366     callback.Run(chrome::FaviconBitmapResult());
    367     return;
    368   }
    369 
    370   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
    371       &resized_bitmap_data);
    372   callback.Run(bitmap_result);
    373 }
    374