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/history/select_favicon_frames.h"
14 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
15 #include "chrome/common/favicon/favicon_types.h"
16 #include "chrome/common/importer/imported_favicon_usage.h"
17 #include "chrome/common/url_constants.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 CancelableTaskTracker::IsCanceledCallback
& is_canceled
,
30 const FaviconService::FaviconResultsCallback
& callback
,
31 const std::vector
<chrome::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 CancelableTaskTracker::TaskId
RunWithEmptyResultAsync(
40 const FaviconService::FaviconResultsCallback
& callback
,
41 CancelableTaskTracker
* tracker
) {
42 return tracker
->PostTask(
43 base::MessageLoopProxy::current().get(),
45 Bind(callback
, std::vector
<chrome::FaviconBitmapResult
>()));
48 // Return the TaskId to retreive the favicon from chrome specific URL.
49 CancelableTaskTracker::TaskId
GetFaviconForChromeURL(
52 const std::vector
<ui::ScaleFactor
>& desired_scale_factors
,
53 const FaviconService::FaviconResultsCallback
& callback
,
54 CancelableTaskTracker
* tracker
) {
55 CancelableTaskTracker::IsCanceledCallback is_canceled_cb
;
56 CancelableTaskTracker::TaskId id
= tracker
->NewTrackedTaskId(&is_canceled_cb
);
57 FaviconService::FaviconResultsCallback cancelable_cb
=
58 Bind(&CancelOrRunFaviconResultsCallback
, is_canceled_cb
, callback
);
59 ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(profile
,
60 page_url
, desired_scale_factors
, cancelable_cb
);
66 FaviconService::FaviconService(Profile
* profile
)
67 : history_service_(HistoryServiceFactory::GetForProfile(
68 profile
, Profile::EXPLICIT_ACCESS
)),
73 void FaviconService::FaviconResultsCallbackRunner(
74 const FaviconResultsCallback
& callback
,
75 const std::vector
<chrome::FaviconBitmapResult
>* results
) {
76 callback
.Run(*results
);
79 CancelableTaskTracker::TaskId
FaviconService::GetFaviconImage(
81 chrome::IconType icon_type
,
82 int desired_size_in_dip
,
83 const FaviconImageCallback
& callback
,
84 CancelableTaskTracker
* tracker
) {
85 FaviconResultsCallback callback_runner
=
86 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults
,
87 base::Unretained(this), callback
, desired_size_in_dip
);
88 if (history_service_
) {
89 std::vector
<GURL
> icon_urls
;
90 icon_urls
.push_back(icon_url
);
91 return history_service_
->GetFavicons(
92 icon_urls
, icon_type
, desired_size_in_dip
,
93 FaviconUtil::GetFaviconScaleFactors(), callback_runner
, tracker
);
95 return RunWithEmptyResultAsync(callback_runner
, tracker
);
99 CancelableTaskTracker::TaskId
FaviconService::GetRawFavicon(
100 const GURL
& icon_url
,
101 chrome::IconType icon_type
,
102 int desired_size_in_dip
,
103 ui::ScaleFactor desired_scale_factor
,
104 const FaviconRawCallback
& callback
,
105 CancelableTaskTracker
* tracker
) {
106 FaviconResultsCallback callback_runner
=
107 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
108 base::Unretained(this),
109 callback
, desired_size_in_dip
, desired_scale_factor
);
111 if (history_service_
) {
112 std::vector
<GURL
> icon_urls
;
113 icon_urls
.push_back(icon_url
);
114 std::vector
<ui::ScaleFactor
> desired_scale_factors
;
115 desired_scale_factors
.push_back(desired_scale_factor
);
117 return history_service_
->GetFavicons(
118 icon_urls
, icon_type
, desired_size_in_dip
, desired_scale_factors
,
119 callback_runner
, tracker
);
121 return RunWithEmptyResultAsync(callback_runner
, tracker
);
125 CancelableTaskTracker::TaskId
FaviconService::GetFavicon(
126 const GURL
& icon_url
,
127 chrome::IconType icon_type
,
128 int desired_size_in_dip
,
129 const FaviconResultsCallback
& callback
,
130 CancelableTaskTracker
* tracker
) {
131 if (history_service_
) {
132 std::vector
<GURL
> icon_urls
;
133 icon_urls
.push_back(icon_url
);
134 return history_service_
->GetFavicons(
135 icon_urls
, icon_type
, desired_size_in_dip
,
136 FaviconUtil::GetFaviconScaleFactors(), callback
, tracker
);
138 return RunWithEmptyResultAsync(callback
, tracker
);
142 CancelableTaskTracker::TaskId
FaviconService::UpdateFaviconMappingsAndFetch(
143 const GURL
& page_url
,
144 const std::vector
<GURL
>& icon_urls
,
146 int desired_size_in_dip
,
147 const FaviconResultsCallback
& callback
,
148 CancelableTaskTracker
* tracker
) {
149 if (history_service_
) {
150 return history_service_
->UpdateFaviconMappingsAndFetch(
151 page_url
, icon_urls
, icon_types
, desired_size_in_dip
,
152 FaviconUtil::GetFaviconScaleFactors(), callback
, tracker
);
154 return RunWithEmptyResultAsync(callback
, tracker
);
158 CancelableTaskTracker::TaskId
FaviconService::GetFaviconImageForURL(
159 const FaviconForURLParams
& params
,
160 const FaviconImageCallback
& callback
,
161 CancelableTaskTracker
* tracker
) {
162 return GetFaviconForURLImpl(
164 FaviconUtil::GetFaviconScaleFactors(),
165 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults
,
166 base::Unretained(this),
168 params
.desired_size_in_dip
),
172 CancelableTaskTracker::TaskId
FaviconService::GetRawFaviconForURL(
173 const FaviconForURLParams
& params
,
174 ui::ScaleFactor desired_scale_factor
,
175 const FaviconRawCallback
& callback
,
176 CancelableTaskTracker
* tracker
) {
177 std::vector
<ui::ScaleFactor
> desired_scale_factors
;
178 desired_scale_factors
.push_back(desired_scale_factor
);
179 return GetFaviconForURLImpl(
181 desired_scale_factors
,
182 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
183 base::Unretained(this),
185 params
.desired_size_in_dip
,
186 desired_scale_factor
),
190 CancelableTaskTracker::TaskId
FaviconService::GetLargestRawFaviconForURL(
192 const GURL
& page_url
,
193 const std::vector
<int>& icon_types
,
194 int minimum_size_in_pixels
,
195 const FaviconRawCallback
& callback
,
196 CancelableTaskTracker
* tracker
) {
197 FaviconResultsCallback favicon_results_callback
=
198 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
199 base::Unretained(this), callback
, 0, ui::ScaleFactor());
200 if (page_url
.SchemeIs(chrome::kChromeUIScheme
) ||
201 page_url
.SchemeIs(extensions::kExtensionScheme
)) {
202 std::vector
<ui::ScaleFactor
> scale_factor
;
203 scale_factor
.push_back(ui::SCALE_FACTOR_100P
);
204 return GetFaviconForChromeURL(profile
, page_url
, scale_factor
,
205 favicon_results_callback
, tracker
);
206 } else if (history_service_
) {
207 return history_service_
->GetLargestFaviconForURL(page_url
, icon_types
,
208 minimum_size_in_pixels
, callback
, tracker
);
210 return RunWithEmptyResultAsync(favicon_results_callback
, tracker
);
213 CancelableTaskTracker::TaskId
FaviconService::GetFaviconForURL(
214 const FaviconForURLParams
& params
,
215 const FaviconResultsCallback
& callback
,
216 CancelableTaskTracker
* tracker
) {
217 return GetFaviconForURLImpl(params
,
218 FaviconUtil::GetFaviconScaleFactors(),
223 CancelableTaskTracker::TaskId
FaviconService::GetLargestRawFaviconForID(
224 chrome::FaviconID favicon_id
,
225 const FaviconRawCallback
& callback
,
226 CancelableTaskTracker
* tracker
) {
227 // Use 0 as |desired_size_in_dip| to get the largest bitmap for |favicon_id|
228 // without any resizing.
229 int desired_size_in_dip
= 0;
230 ui::ScaleFactor desired_scale_factor
= ui::SCALE_FACTOR_100P
;
231 FaviconResultsCallback callback_runner
=
232 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults
,
233 base::Unretained(this),
234 callback
, desired_size_in_dip
, desired_scale_factor
);
236 if (history_service_
) {
237 return history_service_
->GetFaviconForID(
238 favicon_id
, desired_size_in_dip
, desired_scale_factor
,
239 callback_runner
, tracker
);
241 return RunWithEmptyResultAsync(callback_runner
, tracker
);
245 void FaviconService::SetFaviconOutOfDateForPage(const GURL
& page_url
) {
246 if (history_service_
)
247 history_service_
->SetFaviconsOutOfDateForPage(page_url
);
250 void FaviconService::CloneFavicon(const GURL
& old_page_url
,
251 const GURL
& new_page_url
) {
252 if (history_service_
)
253 history_service_
->CloneFavicons(old_page_url
, new_page_url
);
256 void FaviconService::SetImportedFavicons(
257 const std::vector
<ImportedFaviconUsage
>& favicon_usage
) {
258 if (history_service_
)
259 history_service_
->SetImportedFavicons(favicon_usage
);
262 void FaviconService::MergeFavicon(
263 const GURL
& page_url
,
264 const GURL
& icon_url
,
265 chrome::IconType icon_type
,
266 scoped_refptr
<base::RefCountedMemory
> bitmap_data
,
267 const gfx::Size
& pixel_size
) {
268 if (history_service_
) {
269 history_service_
->MergeFavicon(page_url
, icon_url
, icon_type
, bitmap_data
,
274 void FaviconService::SetFavicons(const GURL
& page_url
,
275 const GURL
& icon_url
,
276 chrome::IconType icon_type
,
277 const gfx::Image
& image
) {
278 if (!history_service_
)
281 gfx::ImageSkia image_skia
= image
.AsImageSkia();
282 image_skia
.EnsureRepsForSupportedScales();
283 const std::vector
<gfx::ImageSkiaRep
>& image_reps
= image_skia
.image_reps();
284 std::vector
<chrome::FaviconBitmapData
> favicon_bitmap_data
;
285 for (size_t i
= 0; i
< image_reps
.size(); ++i
) {
286 scoped_refptr
<base::RefCountedBytes
> bitmap_data(
287 new base::RefCountedBytes());
288 if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps
[i
].sk_bitmap(),
290 &bitmap_data
->data())) {
291 gfx::Size
pixel_size(image_reps
[i
].pixel_width(),
292 image_reps
[i
].pixel_height());
293 chrome::FaviconBitmapData bitmap_data_element
;
294 bitmap_data_element
.bitmap_data
= bitmap_data
;
295 bitmap_data_element
.pixel_size
= pixel_size
;
296 bitmap_data_element
.icon_url
= icon_url
;
298 favicon_bitmap_data
.push_back(bitmap_data_element
);
302 history_service_
->SetFavicons(page_url
, icon_type
, favicon_bitmap_data
);
305 void FaviconService::UnableToDownloadFavicon(const GURL
& icon_url
) {
306 MissingFaviconURLHash url_hash
= base::Hash(icon_url
.spec());
307 missing_favicon_urls_
.insert(url_hash
);
310 bool FaviconService::WasUnableToDownloadFavicon(const GURL
& icon_url
) const {
311 MissingFaviconURLHash url_hash
= base::Hash(icon_url
.spec());
312 return missing_favicon_urls_
.find(url_hash
) != missing_favicon_urls_
.end();
315 void FaviconService::ClearUnableToDownloadFavicons() {
316 missing_favicon_urls_
.clear();
319 FaviconService::~FaviconService() {}
321 CancelableTaskTracker::TaskId
FaviconService::GetFaviconForURLImpl(
322 const FaviconForURLParams
& params
,
323 const std::vector
<ui::ScaleFactor
>& desired_scale_factors
,
324 const FaviconResultsCallback
& callback
,
325 CancelableTaskTracker
* tracker
) {
326 if (params
.page_url
.SchemeIs(chrome::kChromeUIScheme
) ||
327 params
.page_url
.SchemeIs(extensions::kExtensionScheme
)) {
328 return GetFaviconForChromeURL(profile_
, params
.page_url
,
329 desired_scale_factors
, callback
, tracker
);
330 } else if (history_service_
) {
331 return history_service_
->GetFaviconsForURL(params
.page_url
,
333 params
.desired_size_in_dip
,
334 desired_scale_factors
,
338 return RunWithEmptyResultAsync(callback
, tracker
);
341 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
342 const FaviconImageCallback
& callback
,
343 int desired_size_in_dip
,
344 const std::vector
<chrome::FaviconBitmapResult
>& favicon_bitmap_results
) {
345 chrome::FaviconImageResult image_result
;
346 image_result
.image
= FaviconUtil::SelectFaviconFramesFromPNGs(
347 favicon_bitmap_results
,
348 FaviconUtil::GetFaviconScaleFactors(),
349 desired_size_in_dip
);
350 FaviconUtil::SetFaviconColorSpace(&image_result
.image
);
352 image_result
.icon_url
= image_result
.image
.IsEmpty() ?
353 GURL() : favicon_bitmap_results
[0].icon_url
;
354 callback
.Run(image_result
);
357 void FaviconService::RunFaviconRawCallbackWithBitmapResults(
358 const FaviconRawCallback
& callback
,
359 int desired_size_in_dip
,
360 ui::ScaleFactor desired_scale_factor
,
361 const std::vector
<chrome::FaviconBitmapResult
>& favicon_bitmap_results
) {
362 if (favicon_bitmap_results
.empty() || !favicon_bitmap_results
[0].is_valid()) {
363 callback
.Run(chrome::FaviconBitmapResult());
367 DCHECK_EQ(1u, favicon_bitmap_results
.size());
368 chrome::FaviconBitmapResult bitmap_result
= favicon_bitmap_results
[0];
370 // If the desired size is 0, SelectFaviconFrames() will return the largest
371 // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
372 // data for a single bitmap, return it and avoid an unnecessary decode.
373 if (desired_size_in_dip
== 0) {
374 callback
.Run(bitmap_result
);
378 // If history bitmap is already desired pixel size, return early.
379 float desired_scale
= ui::GetImageScale(desired_scale_factor
);
380 int desired_edge_width_in_pixel
= static_cast<int>(
381 desired_size_in_dip
* desired_scale
+ 0.5f
);
382 gfx::Size
desired_size_in_pixel(desired_edge_width_in_pixel
,
383 desired_edge_width_in_pixel
);
384 if (bitmap_result
.pixel_size
== desired_size_in_pixel
) {
385 callback
.Run(bitmap_result
);
389 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
391 std::vector
<ui::ScaleFactor
> desired_scale_factors
;
392 desired_scale_factors
.push_back(desired_scale_factor
);
393 gfx::Image resized_image
= FaviconUtil::SelectFaviconFramesFromPNGs(
394 favicon_bitmap_results
, desired_scale_factors
, desired_size_in_dip
);
396 std::vector
<unsigned char> resized_bitmap_data
;
397 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image
.AsBitmap(), false,
398 &resized_bitmap_data
)) {
399 callback
.Run(chrome::FaviconBitmapResult());
403 bitmap_result
.bitmap_data
= base::RefCountedBytes::TakeVector(
404 &resized_bitmap_data
);
405 callback
.Run(bitmap_result
);