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