favicon_service.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 26using base::Bind; 27 28namespace { 29 30void 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. 41base::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. 51base::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(). 69std::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 80FaviconService::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 89void FaviconService::FaviconResultsCallbackRunner( 90 const favicon_base::FaviconResultsCallback& callback, 91 const std::vector<favicon_base::FaviconRawBitmapResult>* results) { 92 callback.Run(*results); 93} 94 95base::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 115base::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 139base::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 158base::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 173base::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 192base::CancelableTaskTracker::TaskId 193FaviconService::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 221base::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 235base::CancelableTaskTracker::TaskId 236FaviconService::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 255base::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 275void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) { 276 if (history_service_) 277 history_service_->SetFaviconsOutOfDateForPage(page_url); 278} 279 280void 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 286void FaviconService::SetImportedFavicons( 287 const std::vector<ImportedFaviconUsage>& favicon_usage) { 288 if (history_service_) 289 history_service_->SetImportedFavicons(favicon_usage); 290} 291 292void 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 304void 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<favicon_base::FaviconRawBitmapData> favicon_bitmap_data; 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 scale. 318 if (std::find(favicon_scales.begin(), 319 favicon_scales.end(), 320 image_reps[i].scale()) == favicon_scales.end()) { 321 continue; 322 } 323 324 scoped_refptr<base::RefCountedBytes> bitmap_data( 325 new base::RefCountedBytes()); 326 if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps[i].sk_bitmap(), 327 false, 328 &bitmap_data->data())) { 329 gfx::Size pixel_size(image_reps[i].pixel_width(), 330 image_reps[i].pixel_height()); 331 favicon_base::FaviconRawBitmapData bitmap_data_element; 332 bitmap_data_element.bitmap_data = bitmap_data; 333 bitmap_data_element.pixel_size = pixel_size; 334 bitmap_data_element.icon_url = icon_url; 335 336 favicon_bitmap_data.push_back(bitmap_data_element); 337 } 338 } 339 history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data); 340} 341 342void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) { 343 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); 344 missing_favicon_urls_.insert(url_hash); 345} 346 347bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const { 348 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); 349 return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end(); 350} 351 352void FaviconService::ClearUnableToDownloadFavicons() { 353 missing_favicon_urls_.clear(); 354} 355 356FaviconService::~FaviconService() {} 357 358base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl( 359 const GURL& page_url, 360 int icon_types, 361 const std::vector<int>& desired_sizes_in_pixel, 362 const favicon_base::FaviconResultsCallback& callback, 363 base::CancelableTaskTracker* tracker) { 364 if (page_url.SchemeIs(content::kChromeUIScheme) || 365 page_url.SchemeIs(extensions::kExtensionScheme)) { 366 return GetFaviconForChromeURL( 367 profile_, page_url, desired_sizes_in_pixel, callback, tracker); 368 } 369 if (history_service_) { 370 return history_service_->GetFaviconsForURL(page_url, 371 icon_types, 372 desired_sizes_in_pixel, 373 callback, 374 tracker); 375 } 376 return RunWithEmptyResultAsync(callback, tracker); 377} 378 379void FaviconService::RunFaviconImageCallbackWithBitmapResults( 380 const favicon_base::FaviconImageCallback& callback, 381 int desired_size_in_dip, 382 const std::vector<favicon_base::FaviconRawBitmapResult>& 383 favicon_bitmap_results) { 384 favicon_base::FaviconImageResult image_result; 385 image_result.image = favicon_base::SelectFaviconFramesFromPNGs( 386 favicon_bitmap_results, 387 favicon_base::GetFaviconScales(), 388 desired_size_in_dip); 389 favicon_base::SetFaviconColorSpace(&image_result.image); 390 391 image_result.icon_url = image_result.image.IsEmpty() ? 392 GURL() : favicon_bitmap_results[0].icon_url; 393 callback.Run(image_result); 394} 395 396void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults( 397 const favicon_base::FaviconRawBitmapCallback& callback, 398 int desired_size_in_pixel, 399 const std::vector<favicon_base::FaviconRawBitmapResult>& 400 favicon_bitmap_results) { 401 if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) { 402 callback.Run(favicon_base::FaviconRawBitmapResult()); 403 return; 404 } 405 406 favicon_base::FaviconRawBitmapResult bitmap_result = 407 favicon_bitmap_results[0]; 408 409 // If the desired size is 0, SelectFaviconFrames() will return the largest 410 // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap 411 // data for a single bitmap, return it and avoid an unnecessary decode. 412 if (desired_size_in_pixel == 0) { 413 callback.Run(bitmap_result); 414 return; 415 } 416 417 // If history bitmap is already desired pixel size, return early. 418 if (bitmap_result.pixel_size.width() == desired_size_in_pixel && 419 bitmap_result.pixel_size.height() == desired_size_in_pixel) { 420 callback.Run(bitmap_result); 421 return; 422 } 423 424 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then 425 // convert back. 426 std::vector<float> desired_favicon_scales; 427 desired_favicon_scales.push_back(1.0f); 428 gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs( 429 favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel); 430 431 std::vector<unsigned char> resized_bitmap_data; 432 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false, 433 &resized_bitmap_data)) { 434 callback.Run(favicon_base::FaviconRawBitmapResult()); 435 return; 436 } 437 438 bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector( 439 &resized_bitmap_data); 440 callback.Run(bitmap_result); 441} 442