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 // Return the TaskId to retreive the favicon from chrome specific URL.
     49 CancelableTaskTracker::TaskId GetFaviconForChromeURL(
     50     Profile* profile,
     51     const GURL& page_url,
     52     const std::vector<ui::ScaleFactor>& desired_scale_factors,
     53     const FaviconService::FaviconResultsCallback& callback,
     54     CancelableTaskTracker* tracker) {
     55   CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
     56   CancelableTaskTracker::TaskId id = tracker->NewTrackedTaskId(&is_canceled_cb);
     57   FaviconService::FaviconResultsCallback cancelable_cb =
     58       Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback);
     59   ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(profile,
     60       page_url, desired_scale_factors, cancelable_cb);
     61   return id;
     62 }
     63 
     64 }  // namespace
     65 
     66 FaviconService::FaviconService(Profile* profile)
     67     : history_service_(HistoryServiceFactory::GetForProfile(
     68           profile, Profile::EXPLICIT_ACCESS)),
     69       profile_(profile) {
     70 }
     71 
     72 // static
     73 void FaviconService::FaviconResultsCallbackRunner(
     74     const FaviconResultsCallback& callback,
     75     const std::vector<chrome::FaviconBitmapResult>* results) {
     76   callback.Run(*results);
     77 }
     78 
     79 CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
     80     const GURL& icon_url,
     81     chrome::IconType icon_type,
     82     int desired_size_in_dip,
     83     const FaviconImageCallback& callback,
     84     CancelableTaskTracker* tracker) {
     85   FaviconResultsCallback callback_runner =
     86       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
     87            base::Unretained(this), callback, desired_size_in_dip);
     88   if (history_service_) {
     89     std::vector<GURL> icon_urls;
     90     icon_urls.push_back(icon_url);
     91     return history_service_->GetFavicons(
     92         icon_urls, icon_type, desired_size_in_dip,
     93         FaviconUtil::GetFaviconScaleFactors(), callback_runner, tracker);
     94   } else {
     95     return RunWithEmptyResultAsync(callback_runner, tracker);
     96   }
     97 }
     98 
     99 CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
    100     const GURL& icon_url,
    101     chrome::IconType icon_type,
    102     int desired_size_in_dip,
    103     ui::ScaleFactor desired_scale_factor,
    104     const FaviconRawCallback& callback,
    105     CancelableTaskTracker* tracker) {
    106   FaviconResultsCallback callback_runner =
    107       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
    108            base::Unretained(this),
    109            callback, desired_size_in_dip, desired_scale_factor);
    110 
    111   if (history_service_) {
    112     std::vector<GURL> icon_urls;
    113     icon_urls.push_back(icon_url);
    114     std::vector<ui::ScaleFactor> desired_scale_factors;
    115     desired_scale_factors.push_back(desired_scale_factor);
    116 
    117     return history_service_->GetFavicons(
    118         icon_urls, icon_type, desired_size_in_dip, desired_scale_factors,
    119         callback_runner, tracker);
    120   } else {
    121     return RunWithEmptyResultAsync(callback_runner, tracker);
    122   }
    123 }
    124 
    125 CancelableTaskTracker::TaskId FaviconService::GetFavicon(
    126     const GURL& icon_url,
    127     chrome::IconType icon_type,
    128     int desired_size_in_dip,
    129     const FaviconResultsCallback& callback,
    130     CancelableTaskTracker* tracker) {
    131   if (history_service_) {
    132     std::vector<GURL> icon_urls;
    133     icon_urls.push_back(icon_url);
    134     return history_service_->GetFavicons(
    135         icon_urls, icon_type, desired_size_in_dip,
    136         FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
    137   } else {
    138     return RunWithEmptyResultAsync(callback, tracker);
    139   }
    140 }
    141 
    142 CancelableTaskTracker::TaskId FaviconService::UpdateFaviconMappingsAndFetch(
    143     const GURL& page_url,
    144     const std::vector<GURL>& icon_urls,
    145     int icon_types,
    146     int desired_size_in_dip,
    147     const FaviconResultsCallback& callback,
    148     CancelableTaskTracker* tracker) {
    149   if (history_service_) {
    150     return history_service_->UpdateFaviconMappingsAndFetch(
    151         page_url, icon_urls, icon_types, desired_size_in_dip,
    152         FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
    153   } else {
    154     return RunWithEmptyResultAsync(callback, tracker);
    155   }
    156 }
    157 
    158 CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL(
    159     const FaviconForURLParams& params,
    160     const FaviconImageCallback& callback,
    161     CancelableTaskTracker* tracker) {
    162   return GetFaviconForURLImpl(
    163       params,
    164       FaviconUtil::GetFaviconScaleFactors(),
    165       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
    166            base::Unretained(this),
    167            callback,
    168            params.desired_size_in_dip),
    169       tracker);
    170 }
    171 
    172 CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForURL(
    173     const FaviconForURLParams& params,
    174     ui::ScaleFactor desired_scale_factor,
    175     const FaviconRawCallback& callback,
    176     CancelableTaskTracker* tracker) {
    177   std::vector<ui::ScaleFactor> desired_scale_factors;
    178   desired_scale_factors.push_back(desired_scale_factor);
    179   return GetFaviconForURLImpl(
    180       params,
    181       desired_scale_factors,
    182       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
    183            base::Unretained(this),
    184            callback,
    185            params.desired_size_in_dip,
    186            desired_scale_factor),
    187       tracker);
    188 }
    189 
    190 CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForURL(
    191     Profile* profile,
    192     const GURL& page_url,
    193     const std::vector<int>& icon_types,
    194     int minimum_size_in_pixels,
    195     const FaviconRawCallback& callback,
    196     CancelableTaskTracker* tracker) {
    197   FaviconResultsCallback favicon_results_callback =
    198       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
    199            base::Unretained(this), callback, 0, ui::ScaleFactor());
    200   if (page_url.SchemeIs(chrome::kChromeUIScheme) ||
    201       page_url.SchemeIs(extensions::kExtensionScheme)) {
    202     std::vector<ui::ScaleFactor> scale_factor;
    203     scale_factor.push_back(ui::SCALE_FACTOR_100P);
    204     return GetFaviconForChromeURL(profile, page_url, scale_factor,
    205                                   favicon_results_callback, tracker);
    206   } else if (history_service_) {
    207     return history_service_->GetLargestFaviconForURL(page_url, icon_types,
    208         minimum_size_in_pixels, callback, tracker);
    209   }
    210   return RunWithEmptyResultAsync(favicon_results_callback, tracker);
    211 }
    212 
    213 CancelableTaskTracker::TaskId FaviconService::GetFaviconForURL(
    214     const FaviconForURLParams& params,
    215     const FaviconResultsCallback& callback,
    216     CancelableTaskTracker* tracker) {
    217   return GetFaviconForURLImpl(params,
    218                               FaviconUtil::GetFaviconScaleFactors(),
    219                               callback,
    220                               tracker);
    221 }
    222 
    223 CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
    224     chrome::FaviconID favicon_id,
    225     const FaviconRawCallback& callback,
    226     CancelableTaskTracker* tracker) {
    227   // Use 0 as |desired_size_in_dip| to get the largest bitmap for |favicon_id|
    228   // without any resizing.
    229   int desired_size_in_dip = 0;
    230   ui::ScaleFactor desired_scale_factor = ui::SCALE_FACTOR_100P;
    231   FaviconResultsCallback callback_runner =
    232       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
    233            base::Unretained(this),
    234            callback, desired_size_in_dip, desired_scale_factor);
    235 
    236   if (history_service_) {
    237     return history_service_->GetFaviconForID(
    238         favicon_id, desired_size_in_dip, desired_scale_factor,
    239         callback_runner, tracker);
    240   } else {
    241     return RunWithEmptyResultAsync(callback_runner, tracker);
    242   }
    243 }
    244 
    245 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
    246   if (history_service_)
    247     history_service_->SetFaviconsOutOfDateForPage(page_url);
    248 }
    249 
    250 void FaviconService::CloneFavicon(const GURL& old_page_url,
    251                                   const GURL& new_page_url) {
    252   if (history_service_)
    253     history_service_->CloneFavicons(old_page_url, new_page_url);
    254 }
    255 
    256 void FaviconService::SetImportedFavicons(
    257     const std::vector<ImportedFaviconUsage>& favicon_usage) {
    258   if (history_service_)
    259     history_service_->SetImportedFavicons(favicon_usage);
    260 }
    261 
    262 void FaviconService::MergeFavicon(
    263     const GURL& page_url,
    264     const GURL& icon_url,
    265     chrome::IconType icon_type,
    266     scoped_refptr<base::RefCountedMemory> bitmap_data,
    267     const gfx::Size& pixel_size) {
    268   if (history_service_) {
    269     history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
    270                                    pixel_size);
    271   }
    272 }
    273 
    274 void FaviconService::SetFavicons(const GURL& page_url,
    275                                  const GURL& icon_url,
    276                                  chrome::IconType icon_type,
    277                                  const gfx::Image& image) {
    278   if (!history_service_)
    279     return;
    280 
    281   gfx::ImageSkia image_skia = image.AsImageSkia();
    282   image_skia.EnsureRepsForSupportedScales();
    283   const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
    284   std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
    285   for (size_t i = 0; i < image_reps.size(); ++i) {
    286     scoped_refptr<base::RefCountedBytes> bitmap_data(
    287         new base::RefCountedBytes());
    288     if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps[i].sk_bitmap(),
    289                                           false,
    290                                           &bitmap_data->data())) {
    291       gfx::Size pixel_size(image_reps[i].pixel_width(),
    292                            image_reps[i].pixel_height());
    293       chrome::FaviconBitmapData bitmap_data_element;
    294       bitmap_data_element.bitmap_data = bitmap_data;
    295       bitmap_data_element.pixel_size = pixel_size;
    296       bitmap_data_element.icon_url = icon_url;
    297 
    298       favicon_bitmap_data.push_back(bitmap_data_element);
    299     }
    300   }
    301 
    302   history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data);
    303 }
    304 
    305 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
    306   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
    307   missing_favicon_urls_.insert(url_hash);
    308 }
    309 
    310 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
    311   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
    312   return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
    313 }
    314 
    315 void FaviconService::ClearUnableToDownloadFavicons() {
    316   missing_favicon_urls_.clear();
    317 }
    318 
    319 FaviconService::~FaviconService() {}
    320 
    321 CancelableTaskTracker::TaskId FaviconService::GetFaviconForURLImpl(
    322     const FaviconForURLParams& params,
    323     const std::vector<ui::ScaleFactor>& desired_scale_factors,
    324     const FaviconResultsCallback& callback,
    325     CancelableTaskTracker* tracker) {
    326   if (params.page_url.SchemeIs(chrome::kChromeUIScheme) ||
    327       params.page_url.SchemeIs(extensions::kExtensionScheme)) {
    328     return GetFaviconForChromeURL(profile_, params.page_url,
    329                                   desired_scale_factors, callback, tracker);
    330   } else if (history_service_) {
    331     return history_service_->GetFaviconsForURL(params.page_url,
    332                                                params.icon_types,
    333                                                params.desired_size_in_dip,
    334                                                desired_scale_factors,
    335                                                callback,
    336                                                tracker);
    337   }
    338   return RunWithEmptyResultAsync(callback, tracker);
    339 }
    340 
    341 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
    342     const FaviconImageCallback& callback,
    343     int desired_size_in_dip,
    344     const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
    345   chrome::FaviconImageResult image_result;
    346   image_result.image = FaviconUtil::SelectFaviconFramesFromPNGs(
    347       favicon_bitmap_results,
    348       FaviconUtil::GetFaviconScaleFactors(),
    349       desired_size_in_dip);
    350   FaviconUtil::SetFaviconColorSpace(&image_result.image);
    351 
    352   image_result.icon_url = image_result.image.IsEmpty() ?
    353       GURL() : favicon_bitmap_results[0].icon_url;
    354   callback.Run(image_result);
    355 }
    356 
    357 void FaviconService::RunFaviconRawCallbackWithBitmapResults(
    358     const FaviconRawCallback& callback,
    359     int desired_size_in_dip,
    360     ui::ScaleFactor desired_scale_factor,
    361     const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
    362   if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
    363     callback.Run(chrome::FaviconBitmapResult());
    364     return;
    365   }
    366 
    367   DCHECK_EQ(1u, favicon_bitmap_results.size());
    368   chrome::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0];
    369 
    370   // If the desired size is 0, SelectFaviconFrames() will return the largest
    371   // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
    372   // data for a single bitmap, return it and avoid an unnecessary decode.
    373   if (desired_size_in_dip == 0) {
    374     callback.Run(bitmap_result);
    375     return;
    376   }
    377 
    378   // If history bitmap is already desired pixel size, return early.
    379   float desired_scale = ui::GetImageScale(desired_scale_factor);
    380   int desired_edge_width_in_pixel = static_cast<int>(
    381       desired_size_in_dip * desired_scale + 0.5f);
    382   gfx::Size desired_size_in_pixel(desired_edge_width_in_pixel,
    383                                   desired_edge_width_in_pixel);
    384   if (bitmap_result.pixel_size == desired_size_in_pixel) {
    385     callback.Run(bitmap_result);
    386     return;
    387   }
    388 
    389   // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
    390   // convert back.
    391   std::vector<ui::ScaleFactor> desired_scale_factors;
    392   desired_scale_factors.push_back(desired_scale_factor);
    393   gfx::Image resized_image = FaviconUtil::SelectFaviconFramesFromPNGs(
    394       favicon_bitmap_results, desired_scale_factors, desired_size_in_dip);
    395 
    396   std::vector<unsigned char> resized_bitmap_data;
    397   if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
    398                                          &resized_bitmap_data)) {
    399     callback.Run(chrome::FaviconBitmapResult());
    400     return;
    401   }
    402 
    403   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
    404       &resized_bitmap_data);
    405   callback.Run(bitmap_result);
    406 }
    407