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 <cmath>
      8 
      9 #include "base/hash.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "chrome/browser/history/history_backend.h"
     12 #include "chrome/browser/history/history_service.h"
     13 #include "chrome/browser/history/history_service_factory.h"
     14 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
     15 #include "chrome/common/importer/imported_favicon_usage.h"
     16 #include "chrome/common/url_constants.h"
     17 #include "components/favicon_base/favicon_types.h"
     18 #include "components/favicon_base/favicon_util.h"
     19 #include "components/favicon_base/select_favicon_frames.h"
     20 #include "extensions/common/constants.h"
     21 #include "third_party/skia/include/core/SkBitmap.h"
     22 #include "ui/gfx/codec/png_codec.h"
     23 #include "ui/gfx/favicon_size.h"
     24 #include "ui/gfx/image/image_skia.h"
     25 
     26 using base::Bind;
     27 
     28 namespace {
     29 
     30 void CancelOrRunFaviconResultsCallback(
     31     const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
     32     const favicon_base::FaviconResultsCallback& callback,
     33     const std::vector<favicon_base::FaviconRawBitmapResult>& results) {
     34   if (is_canceled.Run())
     35     return;
     36   callback.Run(results);
     37 }
     38 
     39 // Helper to run callback with empty results if we cannot get the history
     40 // service.
     41 base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
     42     const favicon_base::FaviconResultsCallback& callback,
     43     base::CancelableTaskTracker* tracker) {
     44   return tracker->PostTask(
     45       base::MessageLoopProxy::current().get(),
     46       FROM_HERE,
     47       Bind(callback, std::vector<favicon_base::FaviconRawBitmapResult>()));
     48 }
     49 
     50 // Return the TaskId to retreive the favicon from chrome specific URL.
     51 base::CancelableTaskTracker::TaskId GetFaviconForChromeURL(
     52     Profile* profile,
     53     const GURL& page_url,
     54     const std::vector<int>& desired_sizes_in_pixel,
     55     const favicon_base::FaviconResultsCallback& callback,
     56     base::CancelableTaskTracker* tracker) {
     57   base::CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
     58   base::CancelableTaskTracker::TaskId id =
     59       tracker->NewTrackedTaskId(&is_canceled_cb);
     60   favicon_base::FaviconResultsCallback cancelable_cb =
     61       Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback);
     62   ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(
     63       profile, page_url, desired_sizes_in_pixel, cancelable_cb);
     64   return id;
     65 }
     66 
     67 // Returns a vector of pixel edge sizes from |size_in_dip| and
     68 // favicon_base::GetFaviconScales().
     69 std::vector<int> GetPixelSizesForFaviconScales(int size_in_dip) {
     70   std::vector<float> scales = favicon_base::GetFaviconScales();
     71   std::vector<int> sizes_in_pixel;
     72   for (size_t i = 0; i < scales.size(); ++i) {
     73     sizes_in_pixel.push_back(std::ceil(size_in_dip * scales[i]));
     74   }
     75   return sizes_in_pixel;
     76 }
     77 
     78 }  // namespace
     79 
     80 FaviconService::FaviconService(Profile* profile, FaviconClient* favicon_client)
     81     : history_service_(
     82           HistoryServiceFactory::GetForProfile(profile,
     83                                                Profile::EXPLICIT_ACCESS)),
     84       profile_(profile),
     85       favicon_client_(favicon_client) {
     86 }
     87 
     88 // static
     89 void FaviconService::FaviconResultsCallbackRunner(
     90     const favicon_base::FaviconResultsCallback& callback,
     91     const std::vector<favicon_base::FaviconRawBitmapResult>* results) {
     92   callback.Run(*results);
     93 }
     94 
     95 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
     96     const GURL& icon_url,
     97     const favicon_base::FaviconImageCallback& callback,
     98     base::CancelableTaskTracker* tracker) {
     99   favicon_base::FaviconResultsCallback callback_runner =
    100       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
    101            base::Unretained(this), callback, gfx::kFaviconSize);
    102   if (history_service_) {
    103     std::vector<GURL> icon_urls;
    104     icon_urls.push_back(icon_url);
    105     return history_service_->GetFavicons(
    106         icon_urls,
    107         favicon_base::FAVICON,
    108         GetPixelSizesForFaviconScales(gfx::kFaviconSize),
    109         callback_runner,
    110         tracker);
    111   }
    112   return RunWithEmptyResultAsync(callback_runner, tracker);
    113 }
    114 
    115 base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
    116     const GURL& icon_url,
    117     favicon_base::IconType icon_type,
    118     int desired_size_in_pixel,
    119     const favicon_base::FaviconRawBitmapCallback& callback,
    120     base::CancelableTaskTracker* tracker) {
    121   favicon_base::FaviconResultsCallback callback_runner =
    122       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
    123            base::Unretained(this),
    124            callback,
    125            desired_size_in_pixel);
    126 
    127   if (history_service_) {
    128     std::vector<GURL> icon_urls;
    129     icon_urls.push_back(icon_url);
    130     std::vector<int> desired_sizes_in_pixel;
    131     desired_sizes_in_pixel.push_back(desired_size_in_pixel);
    132 
    133     return history_service_->GetFavicons(
    134         icon_urls, icon_type, desired_sizes_in_pixel, callback_runner, tracker);
    135   }
    136   return RunWithEmptyResultAsync(callback_runner, tracker);
    137 }
    138 
    139 base::CancelableTaskTracker::TaskId FaviconService::GetFavicon(
    140     const GURL& icon_url,
    141     favicon_base::IconType icon_type,
    142     int desired_size_in_dip,
    143     const favicon_base::FaviconResultsCallback& callback,
    144     base::CancelableTaskTracker* tracker) {
    145   if (history_service_) {
    146     std::vector<GURL> icon_urls;
    147     icon_urls.push_back(icon_url);
    148     return history_service_->GetFavicons(
    149         icon_urls,
    150         icon_type,
    151         GetPixelSizesForFaviconScales(desired_size_in_dip),
    152         callback,
    153         tracker);
    154   }
    155   return RunWithEmptyResultAsync(callback, tracker);
    156 }
    157 
    158 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL(
    159     const GURL& page_url,
    160     const favicon_base::FaviconImageCallback& callback,
    161     base::CancelableTaskTracker* tracker) {
    162   return GetFaviconForPageURLImpl(
    163       page_url,
    164       favicon_base::FAVICON,
    165       GetPixelSizesForFaviconScales(gfx::kFaviconSize),
    166       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
    167            base::Unretained(this),
    168            callback,
    169            gfx::kFaviconSize),
    170       tracker);
    171 }
    172 
    173 base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL(
    174     const GURL& page_url,
    175     int icon_types,
    176     int desired_size_in_pixel,
    177     const favicon_base::FaviconRawBitmapCallback& callback,
    178     base::CancelableTaskTracker* tracker) {
    179   std::vector<int> desired_sizes_in_pixel;
    180   desired_sizes_in_pixel.push_back(desired_size_in_pixel);
    181   return GetFaviconForPageURLImpl(
    182       page_url,
    183       icon_types,
    184       desired_sizes_in_pixel,
    185       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
    186            base::Unretained(this),
    187            callback,
    188            desired_size_in_pixel),
    189       tracker);
    190 }
    191 
    192 base::CancelableTaskTracker::TaskId
    193 FaviconService::GetLargestRawFaviconForPageURL(
    194     const GURL& page_url,
    195     const std::vector<int>& icon_types,
    196     int minimum_size_in_pixels,
    197     const favicon_base::FaviconRawBitmapCallback& callback,
    198     base::CancelableTaskTracker* tracker) {
    199   favicon_base::FaviconResultsCallback favicon_results_callback =
    200       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
    201            base::Unretained(this),
    202            callback,
    203            0);
    204   if (page_url.SchemeIs(content::kChromeUIScheme) ||
    205       page_url.SchemeIs(extensions::kExtensionScheme)) {
    206     std::vector<int> desired_sizes_in_pixel;
    207     desired_sizes_in_pixel.push_back(0);
    208     return GetFaviconForChromeURL(profile_,
    209                                   page_url,
    210                                   desired_sizes_in_pixel,
    211                                   favicon_results_callback,
    212                                   tracker);
    213   }
    214   if (history_service_) {
    215     return history_service_->GetLargestFaviconForURL(page_url, icon_types,
    216         minimum_size_in_pixels, callback, tracker);
    217   }
    218   return RunWithEmptyResultAsync(favicon_results_callback, tracker);
    219 }
    220 
    221 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL(
    222     const GURL& page_url,
    223     int icon_types,
    224     int desired_size_in_dip,
    225     const favicon_base::FaviconResultsCallback& callback,
    226     base::CancelableTaskTracker* tracker) {
    227   return GetFaviconForPageURLImpl(
    228       page_url,
    229       icon_types,
    230       GetPixelSizesForFaviconScales(desired_size_in_dip),
    231       callback,
    232       tracker);
    233 }
    234 
    235 base::CancelableTaskTracker::TaskId
    236 FaviconService::UpdateFaviconMappingsAndFetch(
    237     const GURL& page_url,
    238     const std::vector<GURL>& icon_urls,
    239     int icon_types,
    240     int desired_size_in_dip,
    241     const favicon_base::FaviconResultsCallback& callback,
    242     base::CancelableTaskTracker* tracker) {
    243   if (history_service_) {
    244     return history_service_->UpdateFaviconMappingsAndFetch(
    245         page_url,
    246         icon_urls,
    247         icon_types,
    248         GetPixelSizesForFaviconScales(desired_size_in_dip),
    249         callback,
    250         tracker);
    251   }
    252   return RunWithEmptyResultAsync(callback, tracker);
    253 }
    254 
    255 base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
    256     favicon_base::FaviconID favicon_id,
    257     const favicon_base::FaviconRawBitmapCallback& callback,
    258     base::CancelableTaskTracker* tracker) {
    259   // Use 0 as |desired_size| to get the largest bitmap for |favicon_id| without
    260   // any resizing.
    261   int desired_size = 0;
    262   favicon_base::FaviconResultsCallback callback_runner =
    263       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
    264            base::Unretained(this),
    265            callback,
    266            desired_size);
    267 
    268   if (history_service_) {
    269     return history_service_->GetFaviconForID(
    270         favicon_id, desired_size, callback_runner, tracker);
    271   }
    272   return RunWithEmptyResultAsync(callback_runner, tracker);
    273 }
    274 
    275 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
    276   if (history_service_)
    277     history_service_->SetFaviconsOutOfDateForPage(page_url);
    278 }
    279 
    280 void FaviconService::CloneFavicon(const GURL& old_page_url,
    281                                   const GURL& new_page_url) {
    282   if (history_service_)
    283     history_service_->CloneFavicons(old_page_url, new_page_url);
    284 }
    285 
    286 void FaviconService::SetImportedFavicons(
    287     const std::vector<ImportedFaviconUsage>& favicon_usage) {
    288   if (history_service_)
    289     history_service_->SetImportedFavicons(favicon_usage);
    290 }
    291 
    292 void FaviconService::MergeFavicon(
    293     const GURL& page_url,
    294     const GURL& icon_url,
    295     favicon_base::IconType icon_type,
    296     scoped_refptr<base::RefCountedMemory> bitmap_data,
    297     const gfx::Size& pixel_size) {
    298   if (history_service_) {
    299     history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
    300                                    pixel_size);
    301   }
    302 }
    303 
    304 void FaviconService::SetFavicons(const GURL& page_url,
    305                                  const GURL& icon_url,
    306                                  favicon_base::IconType icon_type,
    307                                  const gfx::Image& image) {
    308   if (!history_service_)
    309     return;
    310 
    311   gfx::ImageSkia image_skia = image.AsImageSkia();
    312   image_skia.EnsureRepsForSupportedScales();
    313   const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
    314   std::vector<SkBitmap> bitmaps;
    315   const std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
    316   for (size_t i = 0; i < image_reps.size(); ++i) {
    317     // Don't save if the scale isn't one of supported favicon scales.
    318     if (std::find(favicon_scales.begin(),
    319                   favicon_scales.end(),
    320                   image_reps[i].scale()) == favicon_scales.end()) {
    321       continue;
    322     }
    323     bitmaps.push_back(image_reps[i].sk_bitmap());
    324   }
    325   history_service_->SetFavicons(page_url, icon_type, icon_url, bitmaps);
    326 }
    327 
    328 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
    329   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
    330   missing_favicon_urls_.insert(url_hash);
    331 }
    332 
    333 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
    334   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
    335   return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
    336 }
    337 
    338 void FaviconService::ClearUnableToDownloadFavicons() {
    339   missing_favicon_urls_.clear();
    340 }
    341 
    342 FaviconService::~FaviconService() {}
    343 
    344 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl(
    345     const GURL& page_url,
    346     int icon_types,
    347     const std::vector<int>& desired_sizes_in_pixel,
    348     const favicon_base::FaviconResultsCallback& callback,
    349     base::CancelableTaskTracker* tracker) {
    350   if (page_url.SchemeIs(content::kChromeUIScheme) ||
    351       page_url.SchemeIs(extensions::kExtensionScheme)) {
    352     return GetFaviconForChromeURL(
    353         profile_, page_url, desired_sizes_in_pixel, callback, tracker);
    354   }
    355   if (history_service_) {
    356     return history_service_->GetFaviconsForURL(page_url,
    357                                                icon_types,
    358                                                desired_sizes_in_pixel,
    359                                                callback,
    360                                                tracker);
    361   }
    362   return RunWithEmptyResultAsync(callback, tracker);
    363 }
    364 
    365 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
    366     const favicon_base::FaviconImageCallback& callback,
    367     int desired_size_in_dip,
    368     const std::vector<favicon_base::FaviconRawBitmapResult>&
    369         favicon_bitmap_results) {
    370   favicon_base::FaviconImageResult image_result;
    371   image_result.image = favicon_base::SelectFaviconFramesFromPNGs(
    372       favicon_bitmap_results,
    373       favicon_base::GetFaviconScales(),
    374       desired_size_in_dip);
    375   favicon_base::SetFaviconColorSpace(&image_result.image);
    376 
    377   image_result.icon_url = image_result.image.IsEmpty() ?
    378       GURL() : favicon_bitmap_results[0].icon_url;
    379   callback.Run(image_result);
    380 }
    381 
    382 void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults(
    383     const favicon_base::FaviconRawBitmapCallback& callback,
    384     int desired_size_in_pixel,
    385     const std::vector<favicon_base::FaviconRawBitmapResult>&
    386         favicon_bitmap_results) {
    387   if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
    388     callback.Run(favicon_base::FaviconRawBitmapResult());
    389     return;
    390   }
    391 
    392   favicon_base::FaviconRawBitmapResult bitmap_result =
    393       favicon_bitmap_results[0];
    394 
    395   // If the desired size is 0, SelectFaviconFrames() will return the largest
    396   // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
    397   // data for a single bitmap, return it and avoid an unnecessary decode.
    398   if (desired_size_in_pixel == 0) {
    399     callback.Run(bitmap_result);
    400     return;
    401   }
    402 
    403   // If history bitmap is already desired pixel size, return early.
    404   if (bitmap_result.pixel_size.width() == desired_size_in_pixel &&
    405       bitmap_result.pixel_size.height() == desired_size_in_pixel) {
    406     callback.Run(bitmap_result);
    407     return;
    408   }
    409 
    410   // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
    411   // convert back.
    412   std::vector<float> desired_favicon_scales;
    413   desired_favicon_scales.push_back(1.0f);
    414   gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
    415       favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel);
    416 
    417   std::vector<unsigned char> resized_bitmap_data;
    418   if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
    419                                          &resized_bitmap_data)) {
    420     callback.Run(favicon_base::FaviconRawBitmapResult());
    421     return;
    422   }
    423 
    424   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
    425       &resized_bitmap_data);
    426   callback.Run(bitmap_result);
    427 }
    428