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