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 "chrome/browser/favicon/favicon_service.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "chrome/browser/favicon/favicon_util.h"
10 #include "chrome/browser/history/history_backend.h"
11 #include "chrome/browser/history/history_service.h"
12 #include "chrome/browser/history/history_service_factory.h"
13 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
14 #include "chrome/common/importer/imported_favicon_usage.h"
15 #include "chrome/common/url_constants.h"
16 #include "components/favicon_base/favicon_types.h"
17 #include "components/favicon_base/select_favicon_frames.h"
18 #include "extensions/common/constants.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"
28 void CancelOrRunFaviconResultsCallback(
29 const base::CancelableTaskTracker::IsCanceledCallback
& is_canceled
,
30 const FaviconService::FaviconResultsCallback
& callback
,
31 const std::vector
<favicon_base::FaviconBitmapResult
>& results
) {
32 if (is_canceled
.Run())
34 callback
.Run(results
);
37 // Helper to run callback with empty results if we cannot get the history
39 base::CancelableTaskTracker::TaskId
RunWithEmptyResultAsync(
40 const FaviconService::FaviconResultsCallback
& callback
,
41 base::CancelableTaskTracker
* tracker
) {
42 return tracker
->PostTask(
43 base::MessageLoopProxy::current().get(),
45 Bind(callback
, std::vector
<favicon_base::FaviconBitmapResult
>()));
48 // Return the TaskId to retreive the favicon from chrome specific URL.
49 base::CancelableTaskTracker::TaskId
GetFaviconForChromeURL(
52 const std::vector
<ui::ScaleFactor
>& desired_scale_factors
,
53 const FaviconService::FaviconResultsCallback
& callback
,
54 base::CancelableTaskTracker
* tracker
) {
55 base::CancelableTaskTracker::IsCanceledCallback is_canceled_cb
;
56 base::CancelableTaskTracker::TaskId id
=
57 tracker
->NewTrackedTaskId(&is_canceled_cb
);
58 FaviconService::FaviconResultsCallback cancelable_cb
=
59 Bind(&CancelOrRunFaviconResultsCallback
, is_canceled_cb
, callback
);
60 ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(profile
,
61 page_url
, desired_scale_factors
, cancelable_cb
);
67 FaviconService::FaviconService(Profile
* profile
)
68 : history_service_(HistoryServiceFactory::GetForProfile(
69 profile
, Profile::EXPLICIT_ACCESS
)),
74 void FaviconService::FaviconResultsCallbackRunner(
75 const FaviconResultsCallback
& callback
,
76 const std::vector
<favicon_base::FaviconBitmapResult
>* results
) {
77 callback
.Run(*results
);
80 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconImage(
82 favicon_base::IconType icon_type
,
83 int desired_size_in_dip
,
84 const FaviconImageCallback
& callback
,
85 base::CancelableTaskTracker
* tracker
) {
86 FaviconResultsCallback callback_runner
=
87 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults
,
88 base::Unretained(this), callback
, desired_size_in_dip
);
89 if (history_service_
) {
90 std::vector
<GURL
> icon_urls
;
91 icon_urls
.push_back(icon_url
);
92 return history_service_
->GetFavicons(
93 icon_urls
, icon_type
, desired_size_in_dip
,
94 FaviconUtil::GetFaviconScaleFactors(), callback_runner
, tracker
);
96 return RunWithEmptyResultAsync(callback_runner
, tracker
);
100 base::CancelableTaskTracker::TaskId
FaviconService::GetRawFavicon(
101 const GURL
& icon_url
,
102 favicon_base::IconType icon_type
,
103 int desired_size_in_dip
,
104 ui::ScaleFactor desired_scale_factor
,
105 const FaviconRawCallback
& callback
,
106 base::CancelableTaskTracker
* tracker
) {
107 FaviconResultsCallback callback_runner
=
108 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
109 base::Unretained(this),
110 callback
, desired_size_in_dip
, desired_scale_factor
);
112 if (history_service_
) {
113 std::vector
<GURL
> icon_urls
;
114 icon_urls
.push_back(icon_url
);
115 std::vector
<ui::ScaleFactor
> desired_scale_factors
;
116 desired_scale_factors
.push_back(desired_scale_factor
);
118 return history_service_
->GetFavicons(
119 icon_urls
, icon_type
, desired_size_in_dip
, desired_scale_factors
,
120 callback_runner
, tracker
);
122 return RunWithEmptyResultAsync(callback_runner
, tracker
);
126 base::CancelableTaskTracker::TaskId
FaviconService::GetFavicon(
127 const GURL
& icon_url
,
128 favicon_base::IconType icon_type
,
129 int desired_size_in_dip
,
130 const FaviconResultsCallback
& callback
,
131 base::CancelableTaskTracker
* tracker
) {
132 if (history_service_
) {
133 std::vector
<GURL
> icon_urls
;
134 icon_urls
.push_back(icon_url
);
135 return history_service_
->GetFavicons(
136 icon_urls
, icon_type
, desired_size_in_dip
,
137 FaviconUtil::GetFaviconScaleFactors(), callback
, tracker
);
139 return RunWithEmptyResultAsync(callback
, tracker
);
143 base::CancelableTaskTracker::TaskId
144 FaviconService::UpdateFaviconMappingsAndFetch(
145 const GURL
& page_url
,
146 const std::vector
<GURL
>& icon_urls
,
148 int desired_size_in_dip
,
149 const FaviconResultsCallback
& callback
,
150 base::CancelableTaskTracker
* tracker
) {
151 if (history_service_
) {
152 return history_service_
->UpdateFaviconMappingsAndFetch(
153 page_url
, icon_urls
, icon_types
, desired_size_in_dip
,
154 FaviconUtil::GetFaviconScaleFactors(), callback
, tracker
);
156 return RunWithEmptyResultAsync(callback
, tracker
);
160 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconImageForURL(
161 const FaviconForURLParams
& params
,
162 const FaviconImageCallback
& callback
,
163 base::CancelableTaskTracker
* tracker
) {
164 return GetFaviconForURLImpl(
166 FaviconUtil::GetFaviconScaleFactors(),
167 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults
,
168 base::Unretained(this),
170 params
.desired_size_in_dip
),
174 base::CancelableTaskTracker::TaskId
FaviconService::GetRawFaviconForURL(
175 const FaviconForURLParams
& params
,
176 ui::ScaleFactor desired_scale_factor
,
177 const FaviconRawCallback
& callback
,
178 base::CancelableTaskTracker
* tracker
) {
179 std::vector
<ui::ScaleFactor
> desired_scale_factors
;
180 desired_scale_factors
.push_back(desired_scale_factor
);
181 return GetFaviconForURLImpl(
183 desired_scale_factors
,
184 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
185 base::Unretained(this),
187 params
.desired_size_in_dip
,
188 desired_scale_factor
),
192 base::CancelableTaskTracker::TaskId
FaviconService::GetLargestRawFaviconForURL(
194 const GURL
& page_url
,
195 const std::vector
<int>& icon_types
,
196 int minimum_size_in_pixels
,
197 const FaviconRawCallback
& callback
,
198 base::CancelableTaskTracker
* tracker
) {
199 FaviconResultsCallback favicon_results_callback
=
200 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
201 base::Unretained(this), callback
, 0, ui::ScaleFactor());
202 if (page_url
.SchemeIs(content::kChromeUIScheme
) ||
203 page_url
.SchemeIs(extensions::kExtensionScheme
)) {
204 std::vector
<ui::ScaleFactor
> scale_factor
;
205 scale_factor
.push_back(ui::SCALE_FACTOR_100P
);
206 return GetFaviconForChromeURL(profile
, page_url
, scale_factor
,
207 favicon_results_callback
, tracker
);
208 } else if (history_service_
) {
209 return history_service_
->GetLargestFaviconForURL(page_url
, icon_types
,
210 minimum_size_in_pixels
, callback
, tracker
);
212 return RunWithEmptyResultAsync(favicon_results_callback
, tracker
);
215 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconForURL(
216 const FaviconForURLParams
& params
,
217 const FaviconResultsCallback
& callback
,
218 base::CancelableTaskTracker
* tracker
) {
219 return GetFaviconForURLImpl(params
,
220 FaviconUtil::GetFaviconScaleFactors(),
225 base::CancelableTaskTracker::TaskId
FaviconService::GetLargestRawFaviconForID(
226 favicon_base::FaviconID favicon_id
,
227 const FaviconRawCallback
& callback
,
228 base::CancelableTaskTracker
* tracker
) {
229 // Use 0 as |desired_size_in_dip| to get the largest bitmap for |favicon_id|
230 // without any resizing.
231 int desired_size_in_dip
= 0;
232 ui::ScaleFactor desired_scale_factor
= ui::SCALE_FACTOR_100P
;
233 FaviconResultsCallback callback_runner
=
234 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
235 base::Unretained(this),
236 callback
, desired_size_in_dip
, desired_scale_factor
);
238 if (history_service_
) {
239 return history_service_
->GetFaviconForID(
240 favicon_id
, desired_size_in_dip
, desired_scale_factor
,
241 callback_runner
, tracker
);
243 return RunWithEmptyResultAsync(callback_runner
, tracker
);
247 void FaviconService::SetFaviconOutOfDateForPage(const GURL
& page_url
) {
248 if (history_service_
)
249 history_service_
->SetFaviconsOutOfDateForPage(page_url
);
252 void FaviconService::CloneFavicon(const GURL
& old_page_url
,
253 const GURL
& new_page_url
) {
254 if (history_service_
)
255 history_service_
->CloneFavicons(old_page_url
, new_page_url
);
258 void FaviconService::SetImportedFavicons(
259 const std::vector
<ImportedFaviconUsage
>& favicon_usage
) {
260 if (history_service_
)
261 history_service_
->SetImportedFavicons(favicon_usage
);
264 void FaviconService::MergeFavicon(
265 const GURL
& page_url
,
266 const GURL
& icon_url
,
267 favicon_base::IconType icon_type
,
268 scoped_refptr
<base::RefCountedMemory
> bitmap_data
,
269 const gfx::Size
& pixel_size
) {
270 if (history_service_
) {
271 history_service_
->MergeFavicon(page_url
, icon_url
, icon_type
, bitmap_data
,
276 void FaviconService::SetFavicons(const GURL
& page_url
,
277 const GURL
& icon_url
,
278 favicon_base::IconType icon_type
,
279 const gfx::Image
& image
) {
280 if (!history_service_
)
283 gfx::ImageSkia image_skia
= image
.AsImageSkia();
284 image_skia
.EnsureRepsForSupportedScales();
285 const std::vector
<gfx::ImageSkiaRep
>& image_reps
= image_skia
.image_reps();
286 std::vector
<favicon_base::FaviconBitmapData
> favicon_bitmap_data
;
287 for (size_t i
= 0; i
< image_reps
.size(); ++i
) {
288 scoped_refptr
<base::RefCountedBytes
> bitmap_data(
289 new base::RefCountedBytes());
290 if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps
[i
].sk_bitmap(),
292 &bitmap_data
->data())) {
293 gfx::Size
pixel_size(image_reps
[i
].pixel_width(),
294 image_reps
[i
].pixel_height());
295 favicon_base::FaviconBitmapData bitmap_data_element
;
296 bitmap_data_element
.bitmap_data
= bitmap_data
;
297 bitmap_data_element
.pixel_size
= pixel_size
;
298 bitmap_data_element
.icon_url
= icon_url
;
300 favicon_bitmap_data
.push_back(bitmap_data_element
);
304 history_service_
->SetFavicons(page_url
, icon_type
, favicon_bitmap_data
);
307 void FaviconService::UnableToDownloadFavicon(const GURL
& icon_url
) {
308 MissingFaviconURLHash url_hash
= base::Hash(icon_url
.spec());
309 missing_favicon_urls_
.insert(url_hash
);
312 bool FaviconService::WasUnableToDownloadFavicon(const GURL
& icon_url
) const {
313 MissingFaviconURLHash url_hash
= base::Hash(icon_url
.spec());
314 return missing_favicon_urls_
.find(url_hash
) != missing_favicon_urls_
.end();
317 void FaviconService::ClearUnableToDownloadFavicons() {
318 missing_favicon_urls_
.clear();
321 FaviconService::~FaviconService() {}
323 base::CancelableTaskTracker::TaskId
FaviconService::GetFaviconForURLImpl(
324 const FaviconForURLParams
& params
,
325 const std::vector
<ui::ScaleFactor
>& desired_scale_factors
,
326 const FaviconResultsCallback
& callback
,
327 base::CancelableTaskTracker
* tracker
) {
328 if (params
.page_url
.SchemeIs(content::kChromeUIScheme
) ||
329 params
.page_url
.SchemeIs(extensions::kExtensionScheme
)) {
330 return GetFaviconForChromeURL(profile_
, params
.page_url
,
331 desired_scale_factors
, callback
, tracker
);
332 } else if (history_service_
) {
333 return history_service_
->GetFaviconsForURL(params
.page_url
,
335 params
.desired_size_in_dip
,
336 desired_scale_factors
,
340 return RunWithEmptyResultAsync(callback
, tracker
);
343 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
344 const FaviconImageCallback
& callback
,
345 int desired_size_in_dip
,
346 const std::vector
<favicon_base::FaviconBitmapResult
>&
347 favicon_bitmap_results
) {
348 favicon_base::FaviconImageResult image_result
;
349 image_result
.image
= FaviconUtil::SelectFaviconFramesFromPNGs(
350 favicon_bitmap_results
,
351 FaviconUtil::GetFaviconScaleFactors(),
352 desired_size_in_dip
);
353 FaviconUtil::SetFaviconColorSpace(&image_result
.image
);
355 image_result
.icon_url
= image_result
.image
.IsEmpty() ?
356 GURL() : favicon_bitmap_results
[0].icon_url
;
357 callback
.Run(image_result
);
360 void FaviconService::RunFaviconRawCallbackWithBitmapResults(
361 const FaviconRawCallback
& callback
,
362 int desired_size_in_dip
,
363 ui::ScaleFactor desired_scale_factor
,
364 const std::vector
<favicon_base::FaviconBitmapResult
>&
365 favicon_bitmap_results
) {
366 if (favicon_bitmap_results
.empty() || !favicon_bitmap_results
[0].is_valid()) {
367 callback
.Run(favicon_base::FaviconBitmapResult());
371 DCHECK_EQ(1u, favicon_bitmap_results
.size());
372 favicon_base::FaviconBitmapResult bitmap_result
= favicon_bitmap_results
[0];
374 // If the desired size is 0, SelectFaviconFrames() will return the largest
375 // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
376 // data for a single bitmap, return it and avoid an unnecessary decode.
377 if (desired_size_in_dip
== 0) {
378 callback
.Run(bitmap_result
);
382 // If history bitmap is already desired pixel size, return early.
383 float desired_scale
= ui::GetImageScale(desired_scale_factor
);
384 int desired_edge_width_in_pixel
= static_cast<int>(
385 desired_size_in_dip
* desired_scale
+ 0.5f
);
386 gfx::Size
desired_size_in_pixel(desired_edge_width_in_pixel
,
387 desired_edge_width_in_pixel
);
388 if (bitmap_result
.pixel_size
== desired_size_in_pixel
) {
389 callback
.Run(bitmap_result
);
393 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
395 std::vector
<ui::ScaleFactor
> desired_scale_factors
;
396 desired_scale_factors
.push_back(desired_scale_factor
);
397 gfx::Image resized_image
= FaviconUtil::SelectFaviconFramesFromPNGs(
398 favicon_bitmap_results
, desired_scale_factors
, desired_size_in_dip
);
400 std::vector
<unsigned char> resized_bitmap_data
;
401 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image
.AsBitmap(), false,
402 &resized_bitmap_data
)) {
403 callback
.Run(favicon_base::FaviconBitmapResult());
407 bitmap_result
.bitmap_data
= base::RefCountedBytes::TakeVector(
408 &resized_bitmap_data
);
409 callback
.Run(bitmap_result
);