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(scoped_ptr
<FaviconClient
> favicon_client
,
52 history::HistoryService
* history_service
)
53 : favicon_client_(favicon_client
.Pass()),
54 history_service_(history_service
) {
57 FaviconService::~FaviconService() {
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(
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(
79 favicon_base::FAVICON
,
80 GetPixelSizesForFaviconScales(gfx::kFaviconSize
),
84 return RunWithEmptyResultAsync(callback_runner
, tracker
);
87 base::CancelableTaskTracker::TaskId
FaviconService::GetRawFavicon(
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(
121 GetPixelSizesForFaviconScales(desired_size_in_dip
),
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
),
140 base::CancelableTaskTracker::TaskId
FaviconService::GetRawFaviconForPageURL(
141 const GURL
& page_url
,
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
),
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
,
181 int desired_size_in_dip
,
182 const favicon_base::FaviconResultsCallback
& callback
,
183 base::CancelableTaskTracker
* tracker
) {
184 return GetFaviconForPageURLImpl(
187 GetPixelSizesForFaviconScales(desired_size_in_dip
),
192 base::CancelableTaskTracker::TaskId
193 FaviconService::UpdateFaviconMappingsAndFetch(
194 const GURL
& page_url
,
195 const std::vector
<GURL
>& icon_urls
,
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(
205 GetPixelSizesForFaviconScales(desired_size_in_dip
),
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
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
,
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_
)
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()) {
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
,
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
,
304 desired_sizes_in_pixel
,
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());
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
);
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
);
356 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
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());
370 bitmap_result
.bitmap_data
= base::RefCountedBytes::TakeVector(
371 &resized_bitmap_data
);
372 callback
.Run(bitmap_result
);
375 } // namespace favicon