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