| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/favicon/core/favicon_service.h" | 5 #include "components/favicon/core/favicon_service.h" |
| 6 | 6 |
| 7 #include <stddef.h> | |
| 8 #include <cmath> | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "base/hash.h" | |
| 12 #include "base/single_thread_task_runner.h" | |
| 13 #include "base/threading/thread_task_runner_handle.h" | |
| 14 #include "base/trace_event/trace_event.h" | |
| 15 #include "components/favicon/core/favicon_client.h" | |
| 16 #include "components/favicon_base/favicon_util.h" | |
| 17 #include "components/favicon_base/select_favicon_frames.h" | |
| 18 #include "components/history/core/browser/history_service.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 #include "url/gurl.h" | |
| 24 | |
| 25 namespace favicon { | 7 namespace favicon { |
| 26 namespace { | |
| 27 | |
| 28 // Helper to run callback with empty results if we cannot get the history | |
| 29 // service. | |
| 30 base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync( | |
| 31 const favicon_base::FaviconResultsCallback& callback, | |
| 32 base::CancelableTaskTracker* tracker) { | |
| 33 scoped_refptr<base::SingleThreadTaskRunner> thread_runner( | |
| 34 base::ThreadTaskRunnerHandle::Get()); | |
| 35 return tracker->PostTask( | |
| 36 thread_runner.get(), FROM_HERE, | |
| 37 base::Bind(callback, | |
| 38 std::vector<favicon_base::FaviconRawBitmapResult>())); | |
| 39 } | |
| 40 | |
| 41 // Returns a vector of pixel edge sizes from |size_in_dip| and | |
| 42 // favicon_base::GetFaviconScales(). | |
| 43 std::vector<int> GetPixelSizesForFaviconScales(int size_in_dip) { | |
| 44 std::vector<float> scales = favicon_base::GetFaviconScales(); | |
| 45 std::vector<int> sizes_in_pixel; | |
| 46 for (size_t i = 0; i < scales.size(); ++i) { | |
| 47 sizes_in_pixel.push_back(std::ceil(size_in_dip * scales[i])); | |
| 48 } | |
| 49 return sizes_in_pixel; | |
| 50 } | |
| 51 | |
| 52 } // namespace | |
| 53 | |
| 54 FaviconService::FaviconService(std::unique_ptr<FaviconClient> favicon_client, | |
| 55 history::HistoryService* history_service) | |
| 56 : favicon_client_(std::move(favicon_client)), | |
| 57 history_service_(history_service) {} | |
| 58 | |
| 59 FaviconService::~FaviconService() { | |
| 60 } | |
| 61 | 8 |
| 62 // static | 9 // static |
| 63 void FaviconService::FaviconResultsCallbackRunner( | 10 void FaviconService::FaviconResultsCallbackRunner( |
| 64 const favicon_base::FaviconResultsCallback& callback, | 11 const favicon_base::FaviconResultsCallback& callback, |
| 65 const std::vector<favicon_base::FaviconRawBitmapResult>* results) { | 12 const std::vector<favicon_base::FaviconRawBitmapResult>* results) { |
| 66 callback.Run(*results); | 13 callback.Run(*results); |
| 67 } | 14 } |
| 68 | 15 |
| 69 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage( | |
| 70 const GURL& icon_url, | |
| 71 const favicon_base::FaviconImageCallback& callback, | |
| 72 base::CancelableTaskTracker* tracker) { | |
| 73 TRACE_EVENT0("browser", "FaviconService::GetFaviconImage"); | |
| 74 favicon_base::FaviconResultsCallback callback_runner = | |
| 75 base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults, | |
| 76 base::Unretained(this), callback, gfx::kFaviconSize); | |
| 77 if (history_service_) { | |
| 78 std::vector<GURL> icon_urls; | |
| 79 icon_urls.push_back(icon_url); | |
| 80 return history_service_->GetFavicons( | |
| 81 icon_urls, | |
| 82 favicon_base::FAVICON, | |
| 83 GetPixelSizesForFaviconScales(gfx::kFaviconSize), | |
| 84 callback_runner, | |
| 85 tracker); | |
| 86 } | |
| 87 return RunWithEmptyResultAsync(callback_runner, tracker); | |
| 88 } | |
| 89 | |
| 90 base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon( | |
| 91 const GURL& icon_url, | |
| 92 favicon_base::IconType icon_type, | |
| 93 int desired_size_in_pixel, | |
| 94 const favicon_base::FaviconRawBitmapCallback& callback, | |
| 95 base::CancelableTaskTracker* tracker) { | |
| 96 TRACE_EVENT0("browser", "FaviconService::GetRawFavicon"); | |
| 97 favicon_base::FaviconResultsCallback callback_runner = | |
| 98 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
| 99 base::Unretained(this), callback, desired_size_in_pixel); | |
| 100 | |
| 101 if (history_service_) { | |
| 102 std::vector<GURL> icon_urls; | |
| 103 icon_urls.push_back(icon_url); | |
| 104 std::vector<int> desired_sizes_in_pixel; | |
| 105 desired_sizes_in_pixel.push_back(desired_size_in_pixel); | |
| 106 | |
| 107 return history_service_->GetFavicons( | |
| 108 icon_urls, icon_type, desired_sizes_in_pixel, callback_runner, tracker); | |
| 109 } | |
| 110 return RunWithEmptyResultAsync(callback_runner, tracker); | |
| 111 } | |
| 112 | |
| 113 base::CancelableTaskTracker::TaskId FaviconService::GetFavicon( | |
| 114 const GURL& icon_url, | |
| 115 favicon_base::IconType icon_type, | |
| 116 int desired_size_in_dip, | |
| 117 const favicon_base::FaviconResultsCallback& callback, | |
| 118 base::CancelableTaskTracker* tracker) { | |
| 119 TRACE_EVENT0("browser", "FaviconService::GetFavicon"); | |
| 120 if (history_service_) { | |
| 121 std::vector<GURL> icon_urls; | |
| 122 icon_urls.push_back(icon_url); | |
| 123 return history_service_->GetFavicons( | |
| 124 icon_urls, | |
| 125 icon_type, | |
| 126 GetPixelSizesForFaviconScales(desired_size_in_dip), | |
| 127 callback, | |
| 128 tracker); | |
| 129 } | |
| 130 return RunWithEmptyResultAsync(callback, tracker); | |
| 131 } | |
| 132 | |
| 133 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL( | |
| 134 const GURL& page_url, | |
| 135 const favicon_base::FaviconImageCallback& callback, | |
| 136 base::CancelableTaskTracker* tracker) { | |
| 137 TRACE_EVENT0("browser", "FaviconService::GetFaviconImageForPageURL"); | |
| 138 return GetFaviconForPageURLImpl( | |
| 139 page_url, favicon_base::FAVICON, | |
| 140 GetPixelSizesForFaviconScales(gfx::kFaviconSize), | |
| 141 base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults, | |
| 142 base::Unretained(this), callback, gfx::kFaviconSize), | |
| 143 tracker); | |
| 144 } | |
| 145 | |
| 146 base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL( | |
| 147 const GURL& page_url, | |
| 148 int icon_types, | |
| 149 int desired_size_in_pixel, | |
| 150 const favicon_base::FaviconRawBitmapCallback& callback, | |
| 151 base::CancelableTaskTracker* tracker) { | |
| 152 TRACE_EVENT0("browser", "FaviconService::GetRawFaviconForPageURL"); | |
| 153 std::vector<int> desired_sizes_in_pixel; | |
| 154 desired_sizes_in_pixel.push_back(desired_size_in_pixel); | |
| 155 return GetFaviconForPageURLImpl( | |
| 156 page_url, icon_types, desired_sizes_in_pixel, | |
| 157 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
| 158 base::Unretained(this), callback, desired_size_in_pixel), | |
| 159 tracker); | |
| 160 } | |
| 161 | |
| 162 base::CancelableTaskTracker::TaskId | |
| 163 FaviconService::GetLargestRawFaviconForPageURL( | |
| 164 const GURL& page_url, | |
| 165 const std::vector<int>& icon_types, | |
| 166 int minimum_size_in_pixels, | |
| 167 const favicon_base::FaviconRawBitmapCallback& callback, | |
| 168 base::CancelableTaskTracker* tracker) { | |
| 169 TRACE_EVENT0("browser", "FaviconService::GetLargestRawFaviconForPageURL"); | |
| 170 favicon_base::FaviconResultsCallback favicon_results_callback = | |
| 171 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
| 172 base::Unretained(this), callback, 0); | |
| 173 if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) { | |
| 174 std::vector<int> desired_sizes_in_pixel; | |
| 175 desired_sizes_in_pixel.push_back(0); | |
| 176 return favicon_client_->GetFaviconForNativeApplicationURL( | |
| 177 page_url, desired_sizes_in_pixel, favicon_results_callback, tracker); | |
| 178 } | |
| 179 if (history_service_) { | |
| 180 return history_service_->GetLargestFaviconForURL(page_url, icon_types, | |
| 181 minimum_size_in_pixels, callback, tracker); | |
| 182 } | |
| 183 return RunWithEmptyResultAsync(favicon_results_callback, tracker); | |
| 184 } | |
| 185 | |
| 186 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL( | |
| 187 const GURL& page_url, | |
| 188 int icon_types, | |
| 189 int desired_size_in_dip, | |
| 190 const favicon_base::FaviconResultsCallback& callback, | |
| 191 base::CancelableTaskTracker* tracker) { | |
| 192 TRACE_EVENT0("browser", "FaviconService::GetFaviconForPageURL"); | |
| 193 return GetFaviconForPageURLImpl( | |
| 194 page_url, | |
| 195 icon_types, | |
| 196 GetPixelSizesForFaviconScales(desired_size_in_dip), | |
| 197 callback, | |
| 198 tracker); | |
| 199 } | |
| 200 | |
| 201 base::CancelableTaskTracker::TaskId | |
| 202 FaviconService::UpdateFaviconMappingsAndFetch( | |
| 203 const GURL& page_url, | |
| 204 const std::vector<GURL>& icon_urls, | |
| 205 int icon_types, | |
| 206 int desired_size_in_dip, | |
| 207 const favicon_base::FaviconResultsCallback& callback, | |
| 208 base::CancelableTaskTracker* tracker) { | |
| 209 if (history_service_) { | |
| 210 return history_service_->UpdateFaviconMappingsAndFetch( | |
| 211 page_url, | |
| 212 icon_urls, | |
| 213 icon_types, | |
| 214 GetPixelSizesForFaviconScales(desired_size_in_dip), | |
| 215 callback, | |
| 216 tracker); | |
| 217 } | |
| 218 return RunWithEmptyResultAsync(callback, tracker); | |
| 219 } | |
| 220 | |
| 221 base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID( | |
| 222 favicon_base::FaviconID favicon_id, | |
| 223 const favicon_base::FaviconRawBitmapCallback& callback, | |
| 224 base::CancelableTaskTracker* tracker) { | |
| 225 TRACE_EVENT0("browser", "FaviconService::GetLargestRawFaviconForID"); | |
| 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 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
| 231 base::Unretained(this), callback, desired_size); | |
| 232 | |
| 233 if (history_service_) { | |
| 234 return history_service_->GetFaviconForID( | |
| 235 favicon_id, desired_size, callback_runner, tracker); | |
| 236 } | |
| 237 return RunWithEmptyResultAsync(callback_runner, tracker); | |
| 238 } | |
| 239 | |
| 240 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) { | |
| 241 if (history_service_) | |
| 242 history_service_->SetFaviconsOutOfDateForPage(page_url); | |
| 243 } | |
| 244 | |
| 245 void FaviconService::SetImportedFavicons( | |
| 246 const favicon_base::FaviconUsageDataList& favicon_usage) { | |
| 247 if (history_service_) | |
| 248 history_service_->SetImportedFavicons(favicon_usage); | |
| 249 } | |
| 250 | |
| 251 void FaviconService::MergeFavicon( | |
| 252 const GURL& page_url, | |
| 253 const GURL& icon_url, | |
| 254 favicon_base::IconType icon_type, | |
| 255 scoped_refptr<base::RefCountedMemory> bitmap_data, | |
| 256 const gfx::Size& pixel_size) { | |
| 257 if (history_service_) { | |
| 258 history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data, | |
| 259 pixel_size); | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 void FaviconService::SetFavicons(const GURL& page_url, | |
| 264 const GURL& icon_url, | |
| 265 favicon_base::IconType icon_type, | |
| 266 const gfx::Image& image) { | |
| 267 if (!history_service_) | |
| 268 return; | |
| 269 | |
| 270 gfx::ImageSkia image_skia = image.AsImageSkia(); | |
| 271 image_skia.EnsureRepsForSupportedScales(); | |
| 272 const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps(); | |
| 273 std::vector<SkBitmap> bitmaps; | |
| 274 const std::vector<float> favicon_scales = favicon_base::GetFaviconScales(); | |
| 275 for (size_t i = 0; i < image_reps.size(); ++i) { | |
| 276 // Don't save if the scale isn't one of supported favicon scales. | |
| 277 if (std::find(favicon_scales.begin(), | |
| 278 favicon_scales.end(), | |
| 279 image_reps[i].scale()) == favicon_scales.end()) { | |
| 280 continue; | |
| 281 } | |
| 282 bitmaps.push_back(image_reps[i].sk_bitmap()); | |
| 283 } | |
| 284 history_service_->SetFavicons(page_url, icon_type, icon_url, bitmaps); | |
| 285 } | |
| 286 | |
| 287 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) { | |
| 288 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); | |
| 289 missing_favicon_urls_.insert(url_hash); | |
| 290 } | |
| 291 | |
| 292 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const { | |
| 293 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); | |
| 294 return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end(); | |
| 295 } | |
| 296 | |
| 297 void FaviconService::ClearUnableToDownloadFavicons() { | |
| 298 missing_favicon_urls_.clear(); | |
| 299 } | |
| 300 | |
| 301 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl( | |
| 302 const GURL& page_url, | |
| 303 int icon_types, | |
| 304 const std::vector<int>& desired_sizes_in_pixel, | |
| 305 const favicon_base::FaviconResultsCallback& callback, | |
| 306 base::CancelableTaskTracker* tracker) { | |
| 307 if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) { | |
| 308 return favicon_client_->GetFaviconForNativeApplicationURL( | |
| 309 page_url, desired_sizes_in_pixel, callback, tracker); | |
| 310 } | |
| 311 if (history_service_) { | |
| 312 return history_service_->GetFaviconsForURL(page_url, | |
| 313 icon_types, | |
| 314 desired_sizes_in_pixel, | |
| 315 callback, | |
| 316 tracker); | |
| 317 } | |
| 318 return RunWithEmptyResultAsync(callback, tracker); | |
| 319 } | |
| 320 | |
| 321 void FaviconService::RunFaviconImageCallbackWithBitmapResults( | |
| 322 const favicon_base::FaviconImageCallback& callback, | |
| 323 int desired_size_in_dip, | |
| 324 const std::vector<favicon_base::FaviconRawBitmapResult>& | |
| 325 favicon_bitmap_results) { | |
| 326 TRACE_EVENT0("browser", | |
| 327 "FaviconService::RunFaviconImageCallbackWithBitmapResults"); | |
| 328 favicon_base::FaviconImageResult image_result; | |
| 329 image_result.image = favicon_base::SelectFaviconFramesFromPNGs( | |
| 330 favicon_bitmap_results, | |
| 331 favicon_base::GetFaviconScales(), | |
| 332 desired_size_in_dip); | |
| 333 favicon_base::SetFaviconColorSpace(&image_result.image); | |
| 334 | |
| 335 image_result.icon_url = image_result.image.IsEmpty() ? | |
| 336 GURL() : favicon_bitmap_results[0].icon_url; | |
| 337 callback.Run(image_result); | |
| 338 } | |
| 339 | |
| 340 void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults( | |
| 341 const favicon_base::FaviconRawBitmapCallback& callback, | |
| 342 int desired_size_in_pixel, | |
| 343 const std::vector<favicon_base::FaviconRawBitmapResult>& | |
| 344 favicon_bitmap_results) { | |
| 345 TRACE_EVENT0("browser", | |
| 346 "FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults"); | |
| 347 callback.Run( | |
| 348 ResizeFaviconBitmapResult(favicon_bitmap_results, desired_size_in_pixel)); | |
| 349 } | |
| 350 | |
| 351 } // namespace favicon | 16 } // namespace favicon |
| OLD | NEW |