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(HistoryService* history_service)
67 : history_service_(history_service) {
71 void FaviconService::FaviconResultsCallbackRunner(
72 const FaviconResultsCallback& callback,
73 const std::vector<chrome::FaviconBitmapResult>* results) {
74 callback.Run(*results);
77 CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
79 chrome::IconType icon_type,
80 int desired_size_in_dip,
81 const FaviconImageCallback& callback,
82 CancelableTaskTracker* tracker) {
83 FaviconResultsCallback callback_runner =
84 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
85 base::Unretained(this), callback, desired_size_in_dip);
86 if (history_service_) {
87 std::vector<GURL> icon_urls;
88 icon_urls.push_back(icon_url);
89 return history_service_->GetFavicons(
90 icon_urls, icon_type, desired_size_in_dip,
91 FaviconUtil::GetFaviconScaleFactors(), callback_runner, tracker);
93 return RunWithEmptyResultAsync(callback_runner, tracker);
97 CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
99 chrome::IconType icon_type,
100 int desired_size_in_dip,
101 ui::ScaleFactor desired_scale_factor,
102 const FaviconRawCallback& callback,
103 CancelableTaskTracker* tracker) {
104 FaviconResultsCallback callback_runner =
105 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
106 base::Unretained(this),
107 callback, desired_size_in_dip, desired_scale_factor);
109 if (history_service_) {
110 std::vector<GURL> icon_urls;
111 icon_urls.push_back(icon_url);
112 std::vector<ui::ScaleFactor> desired_scale_factors;
113 desired_scale_factors.push_back(desired_scale_factor);
115 return history_service_->GetFavicons(
116 icon_urls, icon_type, desired_size_in_dip, desired_scale_factors,
117 callback_runner, tracker);
119 return RunWithEmptyResultAsync(callback_runner, tracker);
123 CancelableTaskTracker::TaskId FaviconService::GetFavicon(
124 const GURL& icon_url,
125 chrome::IconType icon_type,
126 int desired_size_in_dip,
127 const FaviconResultsCallback& callback,
128 CancelableTaskTracker* tracker) {
129 if (history_service_) {
130 std::vector<GURL> icon_urls;
131 icon_urls.push_back(icon_url);
132 return history_service_->GetFavicons(
133 icon_urls, icon_type, desired_size_in_dip,
134 FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
136 return RunWithEmptyResultAsync(callback, tracker);
140 CancelableTaskTracker::TaskId FaviconService::UpdateFaviconMappingsAndFetch(
141 const GURL& page_url,
142 const std::vector<GURL>& icon_urls,
144 int desired_size_in_dip,
145 const FaviconResultsCallback& callback,
146 CancelableTaskTracker* tracker) {
147 if (history_service_) {
148 return history_service_->UpdateFaviconMappingsAndFetch(
149 page_url, icon_urls, icon_types, desired_size_in_dip,
150 FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
152 return RunWithEmptyResultAsync(callback, tracker);
156 CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL(
157 const FaviconForURLParams& params,
158 const FaviconImageCallback& callback,
159 CancelableTaskTracker* tracker) {
160 return GetFaviconForURLImpl(
162 FaviconUtil::GetFaviconScaleFactors(),
163 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
164 base::Unretained(this),
166 params.desired_size_in_dip),
170 CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForURL(
171 const FaviconForURLParams& params,
172 ui::ScaleFactor desired_scale_factor,
173 const FaviconRawCallback& callback,
174 CancelableTaskTracker* tracker) {
175 std::vector<ui::ScaleFactor> desired_scale_factors;
176 desired_scale_factors.push_back(desired_scale_factor);
177 return GetFaviconForURLImpl(
179 desired_scale_factors,
180 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
181 base::Unretained(this),
183 params.desired_size_in_dip,
184 desired_scale_factor),
188 CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForURL(
190 const GURL& page_url,
191 const std::vector<int>& icon_types,
192 int minimum_size_in_pixels,
193 const FaviconRawCallback& callback,
194 CancelableTaskTracker* tracker) {
195 FaviconResultsCallback favicon_results_callback =
196 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
197 base::Unretained(this), callback, 0, ui::ScaleFactor());
198 if (page_url.SchemeIs(chrome::kChromeUIScheme) ||
199 page_url.SchemeIs(extensions::kExtensionScheme)) {
200 std::vector<ui::ScaleFactor> scale_factor;
201 scale_factor.push_back(ui::SCALE_FACTOR_100P);
202 return GetFaviconForChromeURL(profile, page_url, scale_factor,
203 favicon_results_callback, tracker);
204 } else if (history_service_) {
205 return history_service_->GetLargestFaviconForURL(page_url, icon_types,
206 minimum_size_in_pixels, callback, tracker);
208 return RunWithEmptyResultAsync(favicon_results_callback, tracker);
211 CancelableTaskTracker::TaskId FaviconService::GetFaviconForURL(
212 const FaviconForURLParams& params,
213 const FaviconResultsCallback& callback,
214 CancelableTaskTracker* tracker) {
215 return GetFaviconForURLImpl(params,
216 FaviconUtil::GetFaviconScaleFactors(),
221 CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
222 chrome::FaviconID favicon_id,
223 const FaviconRawCallback& callback,
224 CancelableTaskTracker* tracker) {
225 // Use 0 as |desired_size_in_dip| to get the largest bitmap for |favicon_id|
226 // without any resizing.
227 int desired_size_in_dip = 0;
228 ui::ScaleFactor desired_scale_factor = ui::SCALE_FACTOR_100P;
229 FaviconResultsCallback callback_runner =
230 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
231 base::Unretained(this),
232 callback, desired_size_in_dip, desired_scale_factor);
234 if (history_service_) {
235 return history_service_->GetFaviconForID(
236 favicon_id, desired_size_in_dip, desired_scale_factor,
237 callback_runner, tracker);
239 return RunWithEmptyResultAsync(callback_runner, tracker);
243 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
244 if (history_service_)
245 history_service_->SetFaviconsOutOfDateForPage(page_url);
248 void FaviconService::CloneFavicon(const GURL& old_page_url,
249 const GURL& new_page_url) {
250 if (history_service_)
251 history_service_->CloneFavicons(old_page_url, new_page_url);
254 void FaviconService::SetImportedFavicons(
255 const std::vector<ImportedFaviconUsage>& favicon_usage) {
256 if (history_service_)
257 history_service_->SetImportedFavicons(favicon_usage);
260 void FaviconService::MergeFavicon(
261 const GURL& page_url,
262 const GURL& icon_url,
263 chrome::IconType icon_type,
264 scoped_refptr<base::RefCountedMemory> bitmap_data,
265 const gfx::Size& pixel_size) {
266 if (history_service_) {
267 history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
272 void FaviconService::SetFavicons(const GURL& page_url,
273 const GURL& icon_url,
274 chrome::IconType icon_type,
275 const gfx::Image& image) {
276 if (!history_service_)
279 gfx::ImageSkia image_skia = image.AsImageSkia();
280 image_skia.EnsureRepsForSupportedScales();
281 const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
282 std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
283 for (size_t i = 0; i < image_reps.size(); ++i) {
284 scoped_refptr<base::RefCountedBytes> bitmap_data(
285 new base::RefCountedBytes());
286 if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps[i].sk_bitmap(),
288 &bitmap_data->data())) {
289 gfx::Size pixel_size(image_reps[i].pixel_width(),
290 image_reps[i].pixel_height());
291 chrome::FaviconBitmapData bitmap_data_element;
292 bitmap_data_element.bitmap_data = bitmap_data;
293 bitmap_data_element.pixel_size = pixel_size;
294 bitmap_data_element.icon_url = icon_url;
296 favicon_bitmap_data.push_back(bitmap_data_element);
300 history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data);
303 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
304 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
305 missing_favicon_urls_.insert(url_hash);
308 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
309 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
310 return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
313 void FaviconService::ClearUnableToDownloadFavicons() {
314 missing_favicon_urls_.clear();
317 FaviconService::~FaviconService() {}
319 CancelableTaskTracker::TaskId FaviconService::GetFaviconForURLImpl(
320 const FaviconForURLParams& params,
321 const std::vector<ui::ScaleFactor>& desired_scale_factors,
322 const FaviconResultsCallback& callback,
323 CancelableTaskTracker* tracker) {
324 if (params.page_url.SchemeIs(chrome::kChromeUIScheme) ||
325 params.page_url.SchemeIs(extensions::kExtensionScheme)) {
326 return GetFaviconForChromeURL(params.profile, params.page_url,
327 desired_scale_factors, callback, tracker);
328 } else if (history_service_) {
329 return history_service_->GetFaviconsForURL(params.page_url,
331 params.desired_size_in_dip,
332 desired_scale_factors,
336 return RunWithEmptyResultAsync(callback, tracker);
339 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
340 const FaviconImageCallback& callback,
341 int desired_size_in_dip,
342 const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
343 chrome::FaviconImageResult image_result;
344 image_result.image = FaviconUtil::SelectFaviconFramesFromPNGs(
345 favicon_bitmap_results,
346 FaviconUtil::GetFaviconScaleFactors(),
347 desired_size_in_dip);
348 FaviconUtil::SetFaviconColorSpace(&image_result.image);
350 image_result.icon_url = image_result.image.IsEmpty() ?
351 GURL() : favicon_bitmap_results[0].icon_url;
352 callback.Run(image_result);
355 void FaviconService::RunFaviconRawCallbackWithBitmapResults(
356 const FaviconRawCallback& callback,
357 int desired_size_in_dip,
358 ui::ScaleFactor desired_scale_factor,
359 const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
360 if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
361 callback.Run(chrome::FaviconBitmapResult());
365 DCHECK_EQ(1u, favicon_bitmap_results.size());
366 chrome::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0];
368 // If the desired size is 0, SelectFaviconFrames() will return the largest
369 // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
370 // data for a single bitmap, return it and avoid an unnecessary decode.
371 if (desired_size_in_dip == 0) {
372 callback.Run(bitmap_result);
376 // If history bitmap is already desired pixel size, return early.
377 float desired_scale = ui::GetImageScale(desired_scale_factor);
378 int desired_edge_width_in_pixel = static_cast<int>(
379 desired_size_in_dip * desired_scale + 0.5f);
380 gfx::Size desired_size_in_pixel(desired_edge_width_in_pixel,
381 desired_edge_width_in_pixel);
382 if (bitmap_result.pixel_size == desired_size_in_pixel) {
383 callback.Run(bitmap_result);
387 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
389 std::vector<ui::ScaleFactor> desired_scale_factors;
390 desired_scale_factors.push_back(desired_scale_factor);
391 gfx::Image resized_image = FaviconUtil::SelectFaviconFramesFromPNGs(
392 favicon_bitmap_results, desired_scale_factors, desired_size_in_dip);
394 std::vector<unsigned char> resized_bitmap_data;
395 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
396 &resized_bitmap_data)) {
397 callback.Run(chrome::FaviconBitmapResult());
401 bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
402 &resized_bitmap_data);
403 callback.Run(bitmap_result);