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) 81 : history_service_(HistoryServiceFactory::GetForProfile( 82 profile, Profile::EXPLICIT_ACCESS)), 83 profile_(profile) { 84 } 85 86 // static 87 void FaviconService::FaviconResultsCallbackRunner( 88 const favicon_base::FaviconResultsCallback& callback, 89 const std::vector<favicon_base::FaviconRawBitmapResult>* results) { 90 callback.Run(*results); 91 } 92 93 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage( 94 const GURL& icon_url, 95 favicon_base::IconType icon_type, 96 int desired_size_in_dip, 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, desired_size_in_dip); 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 icon_type, 108 GetPixelSizesForFaviconScales(desired_size_in_dip), 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_dip, 119 float desired_favicon_scale, 120 const favicon_base::FaviconRawBitmapCallback& callback, 121 base::CancelableTaskTracker* tracker) { 122 int desired_size_in_pixel = 123 std::ceil(desired_size_in_dip * desired_favicon_scale); 124 favicon_base::FaviconResultsCallback callback_runner = 125 Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, 126 base::Unretained(this), 127 callback, 128 desired_size_in_pixel); 129 130 if (history_service_) { 131 std::vector<GURL> icon_urls; 132 icon_urls.push_back(icon_url); 133 std::vector<int> desired_sizes_in_pixel; 134 desired_sizes_in_pixel.push_back(desired_size_in_pixel); 135 136 return history_service_->GetFavicons( 137 icon_urls, icon_type, desired_sizes_in_pixel, callback_runner, tracker); 138 } 139 return RunWithEmptyResultAsync(callback_runner, tracker); 140 } 141 142 base::CancelableTaskTracker::TaskId FaviconService::GetFavicon( 143 const GURL& icon_url, 144 favicon_base::IconType icon_type, 145 int desired_size_in_dip, 146 const favicon_base::FaviconResultsCallback& callback, 147 base::CancelableTaskTracker* tracker) { 148 if (history_service_) { 149 std::vector<GURL> icon_urls; 150 icon_urls.push_back(icon_url); 151 return history_service_->GetFavicons( 152 icon_urls, 153 icon_type, 154 GetPixelSizesForFaviconScales(desired_size_in_dip), 155 callback, 156 tracker); 157 } 158 return RunWithEmptyResultAsync(callback, tracker); 159 } 160 161 base::CancelableTaskTracker::TaskId 162 FaviconService::UpdateFaviconMappingsAndFetch( 163 const GURL& page_url, 164 const std::vector<GURL>& icon_urls, 165 int icon_types, 166 int desired_size_in_dip, 167 const favicon_base::FaviconResultsCallback& callback, 168 base::CancelableTaskTracker* tracker) { 169 if (history_service_) { 170 return history_service_->UpdateFaviconMappingsAndFetch( 171 page_url, 172 icon_urls, 173 icon_types, 174 GetPixelSizesForFaviconScales(desired_size_in_dip), 175 callback, 176 tracker); 177 } 178 return RunWithEmptyResultAsync(callback, tracker); 179 } 180 181 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL( 182 const FaviconForPageURLParams& params, 183 const favicon_base::FaviconImageCallback& callback, 184 base::CancelableTaskTracker* tracker) { 185 return GetFaviconForPageURLImpl( 186 params, 187 GetPixelSizesForFaviconScales(params.desired_size_in_dip), 188 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults, 189 base::Unretained(this), 190 callback, 191 params.desired_size_in_dip), 192 tracker); 193 } 194 195 base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL( 196 const FaviconForPageURLParams& params, 197 float desired_favicon_scale, 198 const favicon_base::FaviconRawBitmapCallback& callback, 199 base::CancelableTaskTracker* tracker) { 200 int desired_size_in_pixel = 201 std::ceil(params.desired_size_in_dip * desired_favicon_scale); 202 std::vector<int> desired_sizes_in_pixel; 203 desired_sizes_in_pixel.push_back(desired_size_in_pixel); 204 return GetFaviconForPageURLImpl( 205 params, 206 desired_sizes_in_pixel, 207 Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, 208 base::Unretained(this), 209 callback, 210 desired_size_in_pixel), 211 tracker); 212 } 213 214 base::CancelableTaskTracker::TaskId 215 FaviconService::GetLargestRawFaviconForPageURL( 216 Profile* profile, 217 const GURL& page_url, 218 const std::vector<int>& icon_types, 219 int minimum_size_in_pixels, 220 const favicon_base::FaviconRawBitmapCallback& callback, 221 base::CancelableTaskTracker* tracker) { 222 favicon_base::FaviconResultsCallback favicon_results_callback = 223 Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, 224 base::Unretained(this), 225 callback, 226 0); 227 if (page_url.SchemeIs(content::kChromeUIScheme) || 228 page_url.SchemeIs(extensions::kExtensionScheme)) { 229 std::vector<int> desired_sizes_in_pixel; 230 desired_sizes_in_pixel.push_back(0); 231 return GetFaviconForChromeURL(profile, 232 page_url, 233 desired_sizes_in_pixel, 234 favicon_results_callback, 235 tracker); 236 } 237 if (history_service_) { 238 return history_service_->GetLargestFaviconForURL(page_url, icon_types, 239 minimum_size_in_pixels, callback, tracker); 240 } 241 return RunWithEmptyResultAsync(favicon_results_callback, tracker); 242 } 243 244 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL( 245 const FaviconForPageURLParams& params, 246 const favicon_base::FaviconResultsCallback& callback, 247 base::CancelableTaskTracker* tracker) { 248 return GetFaviconForPageURLImpl( 249 params, 250 GetPixelSizesForFaviconScales(params.desired_size_in_dip), 251 callback, 252 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<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 342 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) { 343 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); 344 missing_favicon_urls_.insert(url_hash); 345 } 346 347 bool 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 352 void FaviconService::ClearUnableToDownloadFavicons() { 353 missing_favicon_urls_.clear(); 354 } 355 356 FaviconService::~FaviconService() {} 357 358 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl( 359 const FaviconForPageURLParams& params, 360 const std::vector<int>& desired_sizes_in_pixel, 361 const favicon_base::FaviconResultsCallback& callback, 362 base::CancelableTaskTracker* tracker) { 363 if (params.page_url.SchemeIs(content::kChromeUIScheme) || 364 params.page_url.SchemeIs(extensions::kExtensionScheme)) { 365 return GetFaviconForChromeURL( 366 profile_, params.page_url, desired_sizes_in_pixel, callback, tracker); 367 } 368 if (history_service_) { 369 return history_service_->GetFaviconsForURL(params.page_url, 370 params.icon_types, 371 desired_sizes_in_pixel, 372 callback, 373 tracker); 374 } 375 return RunWithEmptyResultAsync(callback, tracker); 376 } 377 378 void FaviconService::RunFaviconImageCallbackWithBitmapResults( 379 const favicon_base::FaviconImageCallback& callback, 380 int desired_size_in_dip, 381 const std::vector<favicon_base::FaviconRawBitmapResult>& 382 favicon_bitmap_results) { 383 favicon_base::FaviconImageResult image_result; 384 image_result.image = favicon_base::SelectFaviconFramesFromPNGs( 385 favicon_bitmap_results, 386 favicon_base::GetFaviconScales(), 387 desired_size_in_dip); 388 favicon_base::SetFaviconColorSpace(&image_result.image); 389 390 image_result.icon_url = image_result.image.IsEmpty() ? 391 GURL() : favicon_bitmap_results[0].icon_url; 392 callback.Run(image_result); 393 } 394 395 void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults( 396 const favicon_base::FaviconRawBitmapCallback& callback, 397 int desired_size_in_pixel, 398 const std::vector<favicon_base::FaviconRawBitmapResult>& 399 favicon_bitmap_results) { 400 if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) { 401 callback.Run(favicon_base::FaviconRawBitmapResult()); 402 return; 403 } 404 405 DCHECK_EQ(1u, favicon_bitmap_results.size()); 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