Roll ANGLE cc54ab3..c5b2ba5
[chromium-blink-merge.git] / components / favicon / core / favicon_service.cc
blob769c3e24b96ab8909290a90d846a3151a1c01f4d
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.
5 #include "components/favicon/core/favicon_service.h"
7 #include <cmath>
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/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"
22 namespace favicon {
23 namespace {
25 // Helper to run callback with empty results if we cannot get the history
26 // service.
27 base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
28 const favicon_base::FaviconResultsCallback& callback,
29 base::CancelableTaskTracker* tracker) {
30 scoped_refptr<base::SingleThreadTaskRunner> thread_runner(
31 base::ThreadTaskRunnerHandle::Get());
32 return tracker->PostTask(
33 thread_runner.get(), FROM_HERE,
34 base::Bind(callback,
35 std::vector<favicon_base::FaviconRawBitmapResult>()));
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]));
46 return sizes_in_pixel;
49 } // namespace
51 FaviconService::FaviconService(scoped_ptr<FaviconClient> favicon_client,
52 history::HistoryService* history_service)
53 : favicon_client_(favicon_client.Pass()),
54 history_service_(history_service) {
57 FaviconService::~FaviconService() {
60 // static
61 void FaviconService::FaviconResultsCallbackRunner(
62 const favicon_base::FaviconResultsCallback& callback,
63 const std::vector<favicon_base::FaviconRawBitmapResult>* results) {
64 callback.Run(*results);
67 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
68 const GURL& icon_url,
69 const favicon_base::FaviconImageCallback& callback,
70 base::CancelableTaskTracker* tracker) {
71 favicon_base::FaviconResultsCallback callback_runner =
72 base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
73 base::Unretained(this), callback, gfx::kFaviconSize);
74 if (history_service_) {
75 std::vector<GURL> icon_urls;
76 icon_urls.push_back(icon_url);
77 return history_service_->GetFavicons(
78 icon_urls,
79 favicon_base::FAVICON,
80 GetPixelSizesForFaviconScales(gfx::kFaviconSize),
81 callback_runner,
82 tracker);
84 return RunWithEmptyResultAsync(callback_runner, tracker);
87 base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
88 const GURL& icon_url,
89 favicon_base::IconType icon_type,
90 int desired_size_in_pixel,
91 const favicon_base::FaviconRawBitmapCallback& callback,
92 base::CancelableTaskTracker* tracker) {
93 favicon_base::FaviconResultsCallback callback_runner =
94 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
95 base::Unretained(this), callback, desired_size_in_pixel);
97 if (history_service_) {
98 std::vector<GURL> icon_urls;
99 icon_urls.push_back(icon_url);
100 std::vector<int> desired_sizes_in_pixel;
101 desired_sizes_in_pixel.push_back(desired_size_in_pixel);
103 return history_service_->GetFavicons(
104 icon_urls, icon_type, desired_sizes_in_pixel, callback_runner, tracker);
106 return RunWithEmptyResultAsync(callback_runner, tracker);
109 base::CancelableTaskTracker::TaskId FaviconService::GetFavicon(
110 const GURL& icon_url,
111 favicon_base::IconType icon_type,
112 int desired_size_in_dip,
113 const favicon_base::FaviconResultsCallback& callback,
114 base::CancelableTaskTracker* tracker) {
115 if (history_service_) {
116 std::vector<GURL> icon_urls;
117 icon_urls.push_back(icon_url);
118 return history_service_->GetFavicons(
119 icon_urls,
120 icon_type,
121 GetPixelSizesForFaviconScales(desired_size_in_dip),
122 callback,
123 tracker);
125 return RunWithEmptyResultAsync(callback, tracker);
128 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL(
129 const GURL& page_url,
130 const favicon_base::FaviconImageCallback& callback,
131 base::CancelableTaskTracker* tracker) {
132 return GetFaviconForPageURLImpl(
133 page_url, favicon_base::FAVICON,
134 GetPixelSizesForFaviconScales(gfx::kFaviconSize),
135 base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
136 base::Unretained(this), callback, gfx::kFaviconSize),
137 tracker);
140 base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL(
141 const GURL& page_url,
142 int icon_types,
143 int desired_size_in_pixel,
144 const favicon_base::FaviconRawBitmapCallback& callback,
145 base::CancelableTaskTracker* tracker) {
146 std::vector<int> desired_sizes_in_pixel;
147 desired_sizes_in_pixel.push_back(desired_size_in_pixel);
148 return GetFaviconForPageURLImpl(
149 page_url, icon_types, desired_sizes_in_pixel,
150 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
151 base::Unretained(this), callback, desired_size_in_pixel),
152 tracker);
155 base::CancelableTaskTracker::TaskId
156 FaviconService::GetLargestRawFaviconForPageURL(
157 const GURL& page_url,
158 const std::vector<int>& icon_types,
159 int minimum_size_in_pixels,
160 const favicon_base::FaviconRawBitmapCallback& callback,
161 base::CancelableTaskTracker* tracker) {
162 favicon_base::FaviconResultsCallback favicon_results_callback =
163 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
164 base::Unretained(this), callback, 0);
165 if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) {
166 std::vector<int> desired_sizes_in_pixel;
167 desired_sizes_in_pixel.push_back(0);
168 return favicon_client_->GetFaviconForNativeApplicationURL(
169 page_url, desired_sizes_in_pixel, favicon_results_callback, tracker);
171 if (history_service_) {
172 return history_service_->GetLargestFaviconForURL(page_url, icon_types,
173 minimum_size_in_pixels, callback, tracker);
175 return RunWithEmptyResultAsync(favicon_results_callback, tracker);
178 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL(
179 const GURL& page_url,
180 int icon_types,
181 int desired_size_in_dip,
182 const favicon_base::FaviconResultsCallback& callback,
183 base::CancelableTaskTracker* tracker) {
184 return GetFaviconForPageURLImpl(
185 page_url,
186 icon_types,
187 GetPixelSizesForFaviconScales(desired_size_in_dip),
188 callback,
189 tracker);
192 base::CancelableTaskTracker::TaskId
193 FaviconService::UpdateFaviconMappingsAndFetch(
194 const GURL& page_url,
195 const std::vector<GURL>& icon_urls,
196 int icon_types,
197 int desired_size_in_dip,
198 const favicon_base::FaviconResultsCallback& callback,
199 base::CancelableTaskTracker* tracker) {
200 if (history_service_) {
201 return history_service_->UpdateFaviconMappingsAndFetch(
202 page_url,
203 icon_urls,
204 icon_types,
205 GetPixelSizesForFaviconScales(desired_size_in_dip),
206 callback,
207 tracker);
209 return RunWithEmptyResultAsync(callback, tracker);
212 base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
213 favicon_base::FaviconID favicon_id,
214 const favicon_base::FaviconRawBitmapCallback& callback,
215 base::CancelableTaskTracker* tracker) {
216 // Use 0 as |desired_size| to get the largest bitmap for |favicon_id| without
217 // any resizing.
218 int desired_size = 0;
219 favicon_base::FaviconResultsCallback callback_runner =
220 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
221 base::Unretained(this), callback, desired_size);
223 if (history_service_) {
224 return history_service_->GetFaviconForID(
225 favicon_id, desired_size, callback_runner, tracker);
227 return RunWithEmptyResultAsync(callback_runner, tracker);
230 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
231 if (history_service_)
232 history_service_->SetFaviconsOutOfDateForPage(page_url);
235 void FaviconService::SetImportedFavicons(
236 const favicon_base::FaviconUsageDataList& favicon_usage) {
237 if (history_service_)
238 history_service_->SetImportedFavicons(favicon_usage);
241 void FaviconService::MergeFavicon(
242 const GURL& page_url,
243 const GURL& icon_url,
244 favicon_base::IconType icon_type,
245 scoped_refptr<base::RefCountedMemory> bitmap_data,
246 const gfx::Size& pixel_size) {
247 if (history_service_) {
248 history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
249 pixel_size);
253 void FaviconService::SetFavicons(const GURL& page_url,
254 const GURL& icon_url,
255 favicon_base::IconType icon_type,
256 const gfx::Image& image) {
257 if (!history_service_)
258 return;
260 gfx::ImageSkia image_skia = image.AsImageSkia();
261 image_skia.EnsureRepsForSupportedScales();
262 const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
263 std::vector<SkBitmap> bitmaps;
264 const std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
265 for (size_t i = 0; i < image_reps.size(); ++i) {
266 // Don't save if the scale isn't one of supported favicon scales.
267 if (std::find(favicon_scales.begin(),
268 favicon_scales.end(),
269 image_reps[i].scale()) == favicon_scales.end()) {
270 continue;
272 bitmaps.push_back(image_reps[i].sk_bitmap());
274 history_service_->SetFavicons(page_url, icon_type, icon_url, bitmaps);
277 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
278 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
279 missing_favicon_urls_.insert(url_hash);
282 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
283 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
284 return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
287 void FaviconService::ClearUnableToDownloadFavicons() {
288 missing_favicon_urls_.clear();
291 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl(
292 const GURL& page_url,
293 int icon_types,
294 const std::vector<int>& desired_sizes_in_pixel,
295 const favicon_base::FaviconResultsCallback& callback,
296 base::CancelableTaskTracker* tracker) {
297 if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) {
298 return favicon_client_->GetFaviconForNativeApplicationURL(
299 page_url, desired_sizes_in_pixel, callback, tracker);
301 if (history_service_) {
302 return history_service_->GetFaviconsForURL(page_url,
303 icon_types,
304 desired_sizes_in_pixel,
305 callback,
306 tracker);
308 return RunWithEmptyResultAsync(callback, tracker);
311 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
312 const favicon_base::FaviconImageCallback& callback,
313 int desired_size_in_dip,
314 const std::vector<favicon_base::FaviconRawBitmapResult>&
315 favicon_bitmap_results) {
316 favicon_base::FaviconImageResult image_result;
317 image_result.image = favicon_base::SelectFaviconFramesFromPNGs(
318 favicon_bitmap_results,
319 favicon_base::GetFaviconScales(),
320 desired_size_in_dip);
321 favicon_base::SetFaviconColorSpace(&image_result.image);
323 image_result.icon_url = image_result.image.IsEmpty() ?
324 GURL() : favicon_bitmap_results[0].icon_url;
325 callback.Run(image_result);
328 void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults(
329 const favicon_base::FaviconRawBitmapCallback& callback,
330 int desired_size_in_pixel,
331 const std::vector<favicon_base::FaviconRawBitmapResult>&
332 favicon_bitmap_results) {
333 if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
334 callback.Run(favicon_base::FaviconRawBitmapResult());
335 return;
338 favicon_base::FaviconRawBitmapResult bitmap_result =
339 favicon_bitmap_results[0];
341 // If the desired size is 0, SelectFaviconFrames() will return the largest
342 // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
343 // data for a single bitmap, return it and avoid an unnecessary decode.
344 if (desired_size_in_pixel == 0) {
345 callback.Run(bitmap_result);
346 return;
349 // If history bitmap is already desired pixel size, return early.
350 if (bitmap_result.pixel_size.width() == desired_size_in_pixel &&
351 bitmap_result.pixel_size.height() == desired_size_in_pixel) {
352 callback.Run(bitmap_result);
353 return;
356 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
357 // convert back.
358 std::vector<float> desired_favicon_scales;
359 desired_favicon_scales.push_back(1.0f);
360 gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
361 favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel);
363 std::vector<unsigned char> resized_bitmap_data;
364 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
365 &resized_bitmap_data)) {
366 callback.Run(favicon_base::FaviconRawBitmapResult());
367 return;
370 bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
371 &resized_bitmap_data);
372 callback.Run(bitmap_result);
375 } // namespace favicon