- add sources.
[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 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 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>()));
46 }
47
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;
62 }
63
64 }  // namespace
65
66 FaviconService::FaviconService(HistoryService* history_service)
67     : history_service_(history_service) {
68 }
69
70 // static
71 void FaviconService::FaviconResultsCallbackRunner(
72     const FaviconResultsCallback& callback,
73     const std::vector<chrome::FaviconBitmapResult>* results) {
74   callback.Run(*results);
75 }
76
77 CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
78     const GURL& icon_url,
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);
92   } else {
93     return RunWithEmptyResultAsync(callback_runner, tracker);
94   }
95 }
96
97 CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
98     const GURL& icon_url,
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);
108
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);
114
115     return history_service_->GetFavicons(
116         icon_urls, icon_type, desired_size_in_dip, desired_scale_factors,
117         callback_runner, tracker);
118   } else {
119     return RunWithEmptyResultAsync(callback_runner, tracker);
120   }
121 }
122
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);
135   } else {
136     return RunWithEmptyResultAsync(callback, tracker);
137   }
138 }
139
140 CancelableTaskTracker::TaskId FaviconService::UpdateFaviconMappingsAndFetch(
141     const GURL& page_url,
142     const std::vector<GURL>& icon_urls,
143     int icon_types,
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);
151   } else {
152     return RunWithEmptyResultAsync(callback, tracker);
153   }
154 }
155
156 CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL(
157     const FaviconForURLParams& params,
158     const FaviconImageCallback& callback,
159     CancelableTaskTracker* tracker) {
160   return GetFaviconForURLImpl(
161       params,
162       FaviconUtil::GetFaviconScaleFactors(),
163       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
164            base::Unretained(this),
165            callback,
166            params.desired_size_in_dip),
167       tracker);
168 }
169
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(
178       params,
179       desired_scale_factors,
180       Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
181            base::Unretained(this),
182            callback,
183            params.desired_size_in_dip,
184            desired_scale_factor),
185       tracker);
186 }
187
188 CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForURL(
189     Profile* profile,
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);
207   }
208   return RunWithEmptyResultAsync(favicon_results_callback, tracker);
209 }
210
211 CancelableTaskTracker::TaskId FaviconService::GetFaviconForURL(
212     const FaviconForURLParams& params,
213     const FaviconResultsCallback& callback,
214     CancelableTaskTracker* tracker) {
215   return GetFaviconForURLImpl(params,
216                               FaviconUtil::GetFaviconScaleFactors(),
217                               callback,
218                               tracker);
219 }
220
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);
233
234   if (history_service_) {
235     return history_service_->GetFaviconForID(
236         favicon_id, desired_size_in_dip, desired_scale_factor,
237         callback_runner, tracker);
238   } else {
239     return RunWithEmptyResultAsync(callback_runner, tracker);
240   }
241 }
242
243 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
244   if (history_service_)
245     history_service_->SetFaviconsOutOfDateForPage(page_url);
246 }
247
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);
252 }
253
254 void FaviconService::SetImportedFavicons(
255     const std::vector<ImportedFaviconUsage>& favicon_usage) {
256   if (history_service_)
257     history_service_->SetImportedFavicons(favicon_usage);
258 }
259
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,
268                                    pixel_size);
269   }
270 }
271
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_)
277     return;
278
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(),
287                                           false,
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;
295
296       favicon_bitmap_data.push_back(bitmap_data_element);
297     }
298   }
299
300   history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data);
301 }
302
303 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
304   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
305   missing_favicon_urls_.insert(url_hash);
306 }
307
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();
311 }
312
313 void FaviconService::ClearUnableToDownloadFavicons() {
314   missing_favicon_urls_.clear();
315 }
316
317 FaviconService::~FaviconService() {}
318
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,
330                                                params.icon_types,
331                                                params.desired_size_in_dip,
332                                                desired_scale_factors,
333                                                callback,
334                                                tracker);
335   }
336   return RunWithEmptyResultAsync(callback, tracker);
337 }
338
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);
349
350   image_result.icon_url = image_result.image.IsEmpty() ?
351       GURL() : favicon_bitmap_results[0].icon_url;
352   callback.Run(image_result);
353 }
354
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());
362     return;
363   }
364
365   DCHECK_EQ(1u, favicon_bitmap_results.size());
366   chrome::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0];
367
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);
373     return;
374   }
375
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);
384     return;
385   }
386
387   // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
388   // convert back.
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);
393
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());
398     return;
399   }
400
401   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
402       &resized_bitmap_data);
403   callback.Run(bitmap_result);
404 }