Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / favicon / favicon_service.cc
blob6b1d9f8ed91a39ab88e9d9345bbdb721d705aa29
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"
7 #include "base/hash.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"
24 using base::Bind;
26 namespace {
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())
33 return;
34 callback.Run(results);
37 // Helper to run callback with empty results if we cannot get the history
38 // service.
39 CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
40 const FaviconService::FaviconResultsCallback& callback,
41 CancelableTaskTracker* tracker) {
42 return tracker->PostTask(
43 base::MessageLoopProxy::current().get(),
44 FROM_HERE,
45 Bind(callback, std::vector<chrome::FaviconBitmapResult>()));
48 // Return the TaskId to retreive the favicon from chrome specific URL.
49 CancelableTaskTracker::TaskId GetFaviconForChromeURL(
50 Profile* profile,
51 const GURL& page_url,
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);
61 return id;
64 } // namespace
66 FaviconService::FaviconService(Profile* profile)
67 : history_service_(HistoryServiceFactory::GetForProfile(
68 profile, Profile::EXPLICIT_ACCESS)),
69 profile_(profile) {
72 // static
73 void FaviconService::FaviconResultsCallbackRunner(
74 const FaviconResultsCallback& callback,
75 const std::vector<chrome::FaviconBitmapResult>* results) {
76 callback.Run(*results);
79 CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
80 const GURL& icon_url,
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);
94 } else {
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);
120 } else {
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);
137 } else {
138 return RunWithEmptyResultAsync(callback, tracker);
142 CancelableTaskTracker::TaskId FaviconService::UpdateFaviconMappingsAndFetch(
143 const GURL& page_url,
144 const std::vector<GURL>& icon_urls,
145 int icon_types,
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);
153 } else {
154 return RunWithEmptyResultAsync(callback, tracker);
158 CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL(
159 const FaviconForURLParams& params,
160 const FaviconImageCallback& callback,
161 CancelableTaskTracker* tracker) {
162 return GetFaviconForURLImpl(
163 params,
164 FaviconUtil::GetFaviconScaleFactors(),
165 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
166 base::Unretained(this),
167 callback,
168 params.desired_size_in_dip),
169 tracker);
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(
180 params,
181 desired_scale_factors,
182 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
183 base::Unretained(this),
184 callback,
185 params.desired_size_in_dip,
186 desired_scale_factor),
187 tracker);
190 CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForURL(
191 Profile* profile,
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(),
219 callback,
220 tracker);
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);
240 } else {
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,
270 pixel_size);
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_)
279 return;
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(),
289 false,
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,
332 params.icon_types,
333 params.desired_size_in_dip,
334 desired_scale_factors,
335 callback,
336 tracker);
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());
364 return;
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);
375 return;
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);
386 return;
389 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
390 // convert back.
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());
400 return;
403 bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
404 &resized_bitmap_data);
405 callback.Run(bitmap_result);