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