Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / favicon / favicon_service.cc
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.
4
5 #include "chrome/browser/favicon/favicon_service.h"
6
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"
23
24 using base::Bind;
25
26 namespace {
27
28 void CancelOrRunFaviconResultsCallback(
29     const base::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);
35 }
36
37 // Helper to run callback with empty results if we cannot get the history
38 // service.
39 base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
40     const FaviconService::FaviconResultsCallback& callback,
41     base::CancelableTaskTracker* tracker) {
42   return tracker->PostTask(
43       base::MessageLoopProxy::current().get(),
44       FROM_HERE,
45       Bind(callback, std::vector<chrome::FaviconBitmapResult>()));
46 }
47
48 // Return the TaskId to retreive the favicon from chrome specific URL.
49 base::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     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);
62   return id;
63 }
64
65 }  // namespace
66
67 FaviconService::FaviconService(Profile* profile)
68     : history_service_(HistoryServiceFactory::GetForProfile(
69           profile, Profile::EXPLICIT_ACCESS)),
70       profile_(profile) {
71 }
72
73 // static
74 void FaviconService::FaviconResultsCallbackRunner(
75     const FaviconResultsCallback& callback,
76     const std::vector<chrome::FaviconBitmapResult>* results) {
77   callback.Run(*results);
78 }
79
80 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
81     const GURL& icon_url,
82     chrome::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);
95   } else {
96     return RunWithEmptyResultAsync(callback_runner, tracker);
97   }
98 }
99
100 base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
101     const GURL& icon_url,
102     chrome::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);
111
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);
117
118     return history_service_->GetFavicons(
119         icon_urls, icon_type, desired_size_in_dip, desired_scale_factors,
120         callback_runner, tracker);
121   } else {
122     return RunWithEmptyResultAsync(callback_runner, tracker);
123   }
124 }
125
126 base::CancelableTaskTracker::TaskId FaviconService::GetFavicon(
127     const GURL& icon_url,
128     chrome::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);
138   } else {
139     return RunWithEmptyResultAsync(callback, tracker);
140   }
141 }
142
143 base::CancelableTaskTracker::TaskId
144 FaviconService::UpdateFaviconMappingsAndFetch(
145     const GURL& page_url,
146     const std::vector<GURL>& icon_urls,
147     int icon_types,
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);
155   } else {
156     return RunWithEmptyResultAsync(callback, tracker);
157   }
158 }
159
160 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL(
161     const FaviconForURLParams& params,
162     const FaviconImageCallback& callback,
163     base::CancelableTaskTracker* tracker) {
164   return GetFaviconForURLImpl(
165       params,
166       FaviconUtil::GetFaviconScaleFactors(),
167       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
168            base::Unretained(this),
169            callback,
170            params.desired_size_in_dip),
171       tracker);
172 }
173
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(
182       params,
183       desired_scale_factors,
184       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
185            base::Unretained(this),
186            callback,
187            params.desired_size_in_dip,
188            desired_scale_factor),
189       tracker);
190 }
191
192 base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForURL(
193     Profile* profile,
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);
211   }
212   return RunWithEmptyResultAsync(favicon_results_callback, tracker);
213 }
214
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(),
221                               callback,
222                               tracker);
223 }
224
225 base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
226     chrome::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);
237
238   if (history_service_) {
239     return history_service_->GetFaviconForID(
240         favicon_id, desired_size_in_dip, desired_scale_factor,
241         callback_runner, tracker);
242   } else {
243     return RunWithEmptyResultAsync(callback_runner, tracker);
244   }
245 }
246
247 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
248   if (history_service_)
249     history_service_->SetFaviconsOutOfDateForPage(page_url);
250 }
251
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);
256 }
257
258 void FaviconService::SetImportedFavicons(
259     const std::vector<ImportedFaviconUsage>& favicon_usage) {
260   if (history_service_)
261     history_service_->SetImportedFavicons(favicon_usage);
262 }
263
264 void FaviconService::MergeFavicon(
265     const GURL& page_url,
266     const GURL& icon_url,
267     chrome::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,
272                                    pixel_size);
273   }
274 }
275
276 void FaviconService::SetFavicons(const GURL& page_url,
277                                  const GURL& icon_url,
278                                  chrome::IconType icon_type,
279                                  const gfx::Image& image) {
280   if (!history_service_)
281     return;
282
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<chrome::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(),
291                                           false,
292                                           &bitmap_data->data())) {
293       gfx::Size pixel_size(image_reps[i].pixel_width(),
294                            image_reps[i].pixel_height());
295       chrome::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;
299
300       favicon_bitmap_data.push_back(bitmap_data_element);
301     }
302   }
303
304   history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data);
305 }
306
307 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
308   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
309   missing_favicon_urls_.insert(url_hash);
310 }
311
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();
315 }
316
317 void FaviconService::ClearUnableToDownloadFavicons() {
318   missing_favicon_urls_.clear();
319 }
320
321 FaviconService::~FaviconService() {}
322
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,
334                                                params.icon_types,
335                                                params.desired_size_in_dip,
336                                                desired_scale_factors,
337                                                callback,
338                                                tracker);
339   }
340   return RunWithEmptyResultAsync(callback, tracker);
341 }
342
343 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
344     const FaviconImageCallback& callback,
345     int desired_size_in_dip,
346     const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
347   chrome::FaviconImageResult image_result;
348   image_result.image = FaviconUtil::SelectFaviconFramesFromPNGs(
349       favicon_bitmap_results,
350       FaviconUtil::GetFaviconScaleFactors(),
351       desired_size_in_dip);
352   FaviconUtil::SetFaviconColorSpace(&image_result.image);
353
354   image_result.icon_url = image_result.image.IsEmpty() ?
355       GURL() : favicon_bitmap_results[0].icon_url;
356   callback.Run(image_result);
357 }
358
359 void FaviconService::RunFaviconRawCallbackWithBitmapResults(
360     const FaviconRawCallback& callback,
361     int desired_size_in_dip,
362     ui::ScaleFactor desired_scale_factor,
363     const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
364   if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
365     callback.Run(chrome::FaviconBitmapResult());
366     return;
367   }
368
369   DCHECK_EQ(1u, favicon_bitmap_results.size());
370   chrome::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0];
371
372   // If the desired size is 0, SelectFaviconFrames() will return the largest
373   // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
374   // data for a single bitmap, return it and avoid an unnecessary decode.
375   if (desired_size_in_dip == 0) {
376     callback.Run(bitmap_result);
377     return;
378   }
379
380   // If history bitmap is already desired pixel size, return early.
381   float desired_scale = ui::GetImageScale(desired_scale_factor);
382   int desired_edge_width_in_pixel = static_cast<int>(
383       desired_size_in_dip * desired_scale + 0.5f);
384   gfx::Size desired_size_in_pixel(desired_edge_width_in_pixel,
385                                   desired_edge_width_in_pixel);
386   if (bitmap_result.pixel_size == desired_size_in_pixel) {
387     callback.Run(bitmap_result);
388     return;
389   }
390
391   // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
392   // convert back.
393   std::vector<ui::ScaleFactor> desired_scale_factors;
394   desired_scale_factors.push_back(desired_scale_factor);
395   gfx::Image resized_image = FaviconUtil::SelectFaviconFramesFromPNGs(
396       favicon_bitmap_results, desired_scale_factors, desired_size_in_dip);
397
398   std::vector<unsigned char> resized_bitmap_data;
399   if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
400                                          &resized_bitmap_data)) {
401     callback.Run(chrome::FaviconBitmapResult());
402     return;
403   }
404
405   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
406       &resized_bitmap_data);
407   callback.Run(bitmap_result);
408 }