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