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"
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"
25 // Helper to run callback with empty results if we cannot get the history
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
,
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
;
51 FaviconService::FaviconService(FaviconClient
* favicon_client
,
52 history::HistoryService
* history_service
)
53 : history_service_(history_service
), favicon_client_(favicon_client
) {
56 FaviconService::~FaviconService() {
60 void FaviconService::FaviconResultsCallbackRunner(
61 const favicon_base::FaviconResultsCallback
& callback
,
62 const std::vector
<favicon_base::FaviconRawBitmapResult
>* results
) {
63 callback
.Run(*results
);
66 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconImage(
68 const favicon_base::FaviconImageCallback
& callback
,
69 base::CancelableTaskTracker
* tracker
) {
70 favicon_base::FaviconResultsCallback callback_runner
=
71 base::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(
78 favicon_base::FAVICON
,
79 GetPixelSizesForFaviconScales(gfx::kFaviconSize
),
83 return RunWithEmptyResultAsync(callback_runner
, tracker
);
86 base::CancelableTaskTracker::TaskId
FaviconService::GetRawFavicon(
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 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults
,
94 base::Unretained(this), callback
, desired_size_in_pixel
);
96 if (history_service_
) {
97 std::vector
<GURL
> icon_urls
;
98 icon_urls
.push_back(icon_url
);
99 std::vector
<int> desired_sizes_in_pixel
;
100 desired_sizes_in_pixel
.push_back(desired_size_in_pixel
);
102 return history_service_
->GetFavicons(
103 icon_urls
, icon_type
, desired_sizes_in_pixel
, callback_runner
, tracker
);
105 return RunWithEmptyResultAsync(callback_runner
, tracker
);
108 base::CancelableTaskTracker::TaskId
FaviconService::GetFavicon(
109 const GURL
& icon_url
,
110 favicon_base::IconType icon_type
,
111 int desired_size_in_dip
,
112 const favicon_base::FaviconResultsCallback
& callback
,
113 base::CancelableTaskTracker
* tracker
) {
114 if (history_service_
) {
115 std::vector
<GURL
> icon_urls
;
116 icon_urls
.push_back(icon_url
);
117 return history_service_
->GetFavicons(
120 GetPixelSizesForFaviconScales(desired_size_in_dip
),
124 return RunWithEmptyResultAsync(callback
, tracker
);
127 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconImageForPageURL(
128 const GURL
& page_url
,
129 const favicon_base::FaviconImageCallback
& callback
,
130 base::CancelableTaskTracker
* tracker
) {
131 return GetFaviconForPageURLImpl(
132 page_url
, favicon_base::FAVICON
,
133 GetPixelSizesForFaviconScales(gfx::kFaviconSize
),
134 base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults
,
135 base::Unretained(this), callback
, gfx::kFaviconSize
),
139 base::CancelableTaskTracker::TaskId
FaviconService::GetRawFaviconForPageURL(
140 const GURL
& page_url
,
142 int desired_size_in_pixel
,
143 const favicon_base::FaviconRawBitmapCallback
& callback
,
144 base::CancelableTaskTracker
* tracker
) {
145 std::vector
<int> desired_sizes_in_pixel
;
146 desired_sizes_in_pixel
.push_back(desired_size_in_pixel
);
147 return GetFaviconForPageURLImpl(
148 page_url
, icon_types
, desired_sizes_in_pixel
,
149 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults
,
150 base::Unretained(this), callback
, desired_size_in_pixel
),
154 base::CancelableTaskTracker::TaskId
155 FaviconService::GetLargestRawFaviconForPageURL(
156 const GURL
& page_url
,
157 const std::vector
<int>& icon_types
,
158 int minimum_size_in_pixels
,
159 const favicon_base::FaviconRawBitmapCallback
& callback
,
160 base::CancelableTaskTracker
* tracker
) {
161 favicon_base::FaviconResultsCallback favicon_results_callback
=
162 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults
,
163 base::Unretained(this), callback
, 0);
164 if (favicon_client_
&& favicon_client_
->IsNativeApplicationURL(page_url
)) {
165 std::vector
<int> desired_sizes_in_pixel
;
166 desired_sizes_in_pixel
.push_back(0);
167 return favicon_client_
->GetFaviconForNativeApplicationURL(
168 page_url
, desired_sizes_in_pixel
, favicon_results_callback
, tracker
);
170 if (history_service_
) {
171 return history_service_
->GetLargestFaviconForURL(page_url
, icon_types
,
172 minimum_size_in_pixels
, callback
, tracker
);
174 return RunWithEmptyResultAsync(favicon_results_callback
, tracker
);
177 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconForPageURL(
178 const GURL
& page_url
,
180 int desired_size_in_dip
,
181 const favicon_base::FaviconResultsCallback
& callback
,
182 base::CancelableTaskTracker
* tracker
) {
183 return GetFaviconForPageURLImpl(
186 GetPixelSizesForFaviconScales(desired_size_in_dip
),
191 base::CancelableTaskTracker::TaskId
192 FaviconService::UpdateFaviconMappingsAndFetch(
193 const GURL
& page_url
,
194 const std::vector
<GURL
>& icon_urls
,
196 int desired_size_in_dip
,
197 const favicon_base::FaviconResultsCallback
& callback
,
198 base::CancelableTaskTracker
* tracker
) {
199 if (history_service_
) {
200 return history_service_
->UpdateFaviconMappingsAndFetch(
204 GetPixelSizesForFaviconScales(desired_size_in_dip
),
208 return RunWithEmptyResultAsync(callback
, tracker
);
211 base::CancelableTaskTracker::TaskId
FaviconService::GetLargestRawFaviconForID(
212 favicon_base::FaviconID favicon_id
,
213 const favicon_base::FaviconRawBitmapCallback
& callback
,
214 base::CancelableTaskTracker
* tracker
) {
215 // Use 0 as |desired_size| to get the largest bitmap for |favicon_id| without
217 int desired_size
= 0;
218 favicon_base::FaviconResultsCallback callback_runner
=
219 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults
,
220 base::Unretained(this), callback
, desired_size
);
222 if (history_service_
) {
223 return history_service_
->GetFaviconForID(
224 favicon_id
, desired_size
, callback_runner
, tracker
);
226 return RunWithEmptyResultAsync(callback_runner
, tracker
);
229 void FaviconService::SetFaviconOutOfDateForPage(const GURL
& page_url
) {
230 if (history_service_
)
231 history_service_
->SetFaviconsOutOfDateForPage(page_url
);
234 void FaviconService::CloneFavicon(const GURL
& old_page_url
,
235 const GURL
& new_page_url
) {
236 if (history_service_
)
237 history_service_
->CloneFavicons(old_page_url
, new_page_url
);
240 void FaviconService::SetImportedFavicons(
241 const favicon_base::FaviconUsageDataList
& favicon_usage
) {
242 if (history_service_
)
243 history_service_
->SetImportedFavicons(favicon_usage
);
246 void FaviconService::MergeFavicon(
247 const GURL
& page_url
,
248 const GURL
& icon_url
,
249 favicon_base::IconType icon_type
,
250 scoped_refptr
<base::RefCountedMemory
> bitmap_data
,
251 const gfx::Size
& pixel_size
) {
252 if (history_service_
) {
253 history_service_
->MergeFavicon(page_url
, icon_url
, icon_type
, bitmap_data
,
258 void FaviconService::SetFavicons(const GURL
& page_url
,
259 const GURL
& icon_url
,
260 favicon_base::IconType icon_type
,
261 const gfx::Image
& image
) {
262 if (!history_service_
)
265 gfx::ImageSkia image_skia
= image
.AsImageSkia();
266 image_skia
.EnsureRepsForSupportedScales();
267 const std::vector
<gfx::ImageSkiaRep
>& image_reps
= image_skia
.image_reps();
268 std::vector
<SkBitmap
> bitmaps
;
269 const std::vector
<float> favicon_scales
= favicon_base::GetFaviconScales();
270 for (size_t i
= 0; i
< image_reps
.size(); ++i
) {
271 // Don't save if the scale isn't one of supported favicon scales.
272 if (std::find(favicon_scales
.begin(),
273 favicon_scales
.end(),
274 image_reps
[i
].scale()) == favicon_scales
.end()) {
277 bitmaps
.push_back(image_reps
[i
].sk_bitmap());
279 history_service_
->SetFavicons(page_url
, icon_type
, icon_url
, bitmaps
);
282 void FaviconService::UnableToDownloadFavicon(const GURL
& icon_url
) {
283 MissingFaviconURLHash url_hash
= base::Hash(icon_url
.spec());
284 missing_favicon_urls_
.insert(url_hash
);
287 bool FaviconService::WasUnableToDownloadFavicon(const GURL
& icon_url
) const {
288 MissingFaviconURLHash url_hash
= base::Hash(icon_url
.spec());
289 return missing_favicon_urls_
.find(url_hash
) != missing_favicon_urls_
.end();
292 void FaviconService::ClearUnableToDownloadFavicons() {
293 missing_favicon_urls_
.clear();
296 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconForPageURLImpl(
297 const GURL
& page_url
,
299 const std::vector
<int>& desired_sizes_in_pixel
,
300 const favicon_base::FaviconResultsCallback
& callback
,
301 base::CancelableTaskTracker
* tracker
) {
302 if (favicon_client_
&& favicon_client_
->IsNativeApplicationURL(page_url
)) {
303 return favicon_client_
->GetFaviconForNativeApplicationURL(
304 page_url
, desired_sizes_in_pixel
, callback
, tracker
);
306 if (history_service_
) {
307 return history_service_
->GetFaviconsForURL(page_url
,
309 desired_sizes_in_pixel
,
313 return RunWithEmptyResultAsync(callback
, tracker
);
316 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
317 const favicon_base::FaviconImageCallback
& callback
,
318 int desired_size_in_dip
,
319 const std::vector
<favicon_base::FaviconRawBitmapResult
>&
320 favicon_bitmap_results
) {
321 favicon_base::FaviconImageResult image_result
;
322 image_result
.image
= favicon_base::SelectFaviconFramesFromPNGs(
323 favicon_bitmap_results
,
324 favicon_base::GetFaviconScales(),
325 desired_size_in_dip
);
326 favicon_base::SetFaviconColorSpace(&image_result
.image
);
328 image_result
.icon_url
= image_result
.image
.IsEmpty() ?
329 GURL() : favicon_bitmap_results
[0].icon_url
;
330 callback
.Run(image_result
);
333 void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults(
334 const favicon_base::FaviconRawBitmapCallback
& callback
,
335 int desired_size_in_pixel
,
336 const std::vector
<favicon_base::FaviconRawBitmapResult
>&
337 favicon_bitmap_results
) {
338 if (favicon_bitmap_results
.empty() || !favicon_bitmap_results
[0].is_valid()) {
339 callback
.Run(favicon_base::FaviconRawBitmapResult());
343 favicon_base::FaviconRawBitmapResult bitmap_result
=
344 favicon_bitmap_results
[0];
346 // If the desired size is 0, SelectFaviconFrames() will return the largest
347 // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
348 // data for a single bitmap, return it and avoid an unnecessary decode.
349 if (desired_size_in_pixel
== 0) {
350 callback
.Run(bitmap_result
);
354 // If history bitmap is already desired pixel size, return early.
355 if (bitmap_result
.pixel_size
.width() == desired_size_in_pixel
&&
356 bitmap_result
.pixel_size
.height() == desired_size_in_pixel
) {
357 callback
.Run(bitmap_result
);
361 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
363 std::vector
<float> desired_favicon_scales
;
364 desired_favicon_scales
.push_back(1.0f
);
365 gfx::Image resized_image
= favicon_base::SelectFaviconFramesFromPNGs(
366 favicon_bitmap_results
, desired_favicon_scales
, desired_size_in_pixel
);
368 std::vector
<unsigned char> resized_bitmap_data
;
369 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image
.AsBitmap(), false,
370 &resized_bitmap_data
)) {
371 callback
.Run(favicon_base::FaviconRawBitmapResult());
375 bitmap_result
.bitmap_data
= base::RefCountedBytes::TakeVector(
376 &resized_bitmap_data
);
377 callback
.Run(bitmap_result
);
380 } // namespace favicon