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