• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CancelOrRunFaviconResultsCallback(const CancelableTaskTracker::IsCanceledCallback & is_canceled,const FaviconService::FaviconResultsCallback & callback,const std::vector<chrome::FaviconBitmapResult> & results)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.
RunWithEmptyResultAsync(const FaviconService::FaviconResultsCallback & callback,CancelableTaskTracker * tracker)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.
GetFaviconForChromeURL(Profile * profile,const GURL & page_url,const std::vector<ui::ScaleFactor> & desired_scale_factors,const FaviconService::FaviconResultsCallback & callback,CancelableTaskTracker * tracker)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 
FaviconService(Profile * profile)66 FaviconService::FaviconService(Profile* profile)
67     : history_service_(HistoryServiceFactory::GetForProfile(
68           profile, Profile::EXPLICIT_ACCESS)),
69       profile_(profile) {
70 }
71 
72 // static
FaviconResultsCallbackRunner(const FaviconResultsCallback & callback,const std::vector<chrome::FaviconBitmapResult> * results)73 void FaviconService::FaviconResultsCallbackRunner(
74     const FaviconResultsCallback& callback,
75     const std::vector<chrome::FaviconBitmapResult>* results) {
76   callback.Run(*results);
77 }
78 
GetFaviconImage(const GURL & icon_url,chrome::IconType icon_type,int desired_size_in_dip,const FaviconImageCallback & callback,CancelableTaskTracker * tracker)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);
96   }
97 }
98 
GetRawFavicon(const GURL & icon_url,chrome::IconType icon_type,int desired_size_in_dip,ui::ScaleFactor desired_scale_factor,const FaviconRawCallback & callback,CancelableTaskTracker * 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);
110 
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);
116 
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);
122   }
123 }
124 
GetFavicon(const GURL & icon_url,chrome::IconType icon_type,int desired_size_in_dip,const FaviconResultsCallback & callback,CancelableTaskTracker * 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);
139   }
140 }
141 
UpdateFaviconMappingsAndFetch(const GURL & page_url,const std::vector<GURL> & icon_urls,int icon_types,int desired_size_in_dip,const FaviconResultsCallback & callback,CancelableTaskTracker * 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);
155   }
156 }
157 
GetFaviconImageForURL(const FaviconForURLParams & params,const FaviconImageCallback & callback,CancelableTaskTracker * 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);
170 }
171 
GetRawFaviconForURL(const FaviconForURLParams & params,ui::ScaleFactor desired_scale_factor,const FaviconRawCallback & callback,CancelableTaskTracker * 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);
188 }
189 
GetLargestRawFaviconForURL(Profile * profile,const GURL & page_url,const std::vector<int> & icon_types,int minimum_size_in_pixels,const FaviconRawCallback & callback,CancelableTaskTracker * 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);
209   }
210   return RunWithEmptyResultAsync(favicon_results_callback, tracker);
211 }
212 
GetFaviconForURL(const FaviconForURLParams & params,const FaviconResultsCallback & callback,CancelableTaskTracker * 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);
221 }
222 
GetLargestRawFaviconForID(chrome::FaviconID favicon_id,const FaviconRawCallback & callback,CancelableTaskTracker * 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);
235 
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);
242   }
243 }
244 
SetFaviconOutOfDateForPage(const GURL & page_url)245 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
246   if (history_service_)
247     history_service_->SetFaviconsOutOfDateForPage(page_url);
248 }
249 
CloneFavicon(const GURL & old_page_url,const GURL & new_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);
254 }
255 
SetImportedFavicons(const std::vector<ImportedFaviconUsage> & favicon_usage)256 void FaviconService::SetImportedFavicons(
257     const std::vector<ImportedFaviconUsage>& favicon_usage) {
258   if (history_service_)
259     history_service_->SetImportedFavicons(favicon_usage);
260 }
261 
MergeFavicon(const GURL & page_url,const GURL & icon_url,chrome::IconType icon_type,scoped_refptr<base::RefCountedMemory> bitmap_data,const gfx::Size & pixel_size)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);
271   }
272 }
273 
SetFavicons(const GURL & page_url,const GURL & icon_url,chrome::IconType icon_type,const gfx::Image & image)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;
280 
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;
297 
298       favicon_bitmap_data.push_back(bitmap_data_element);
299     }
300   }
301 
302   history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data);
303 }
304 
UnableToDownloadFavicon(const GURL & icon_url)305 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
306   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
307   missing_favicon_urls_.insert(url_hash);
308 }
309 
WasUnableToDownloadFavicon(const GURL & icon_url) const310 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();
313 }
314 
ClearUnableToDownloadFavicons()315 void FaviconService::ClearUnableToDownloadFavicons() {
316   missing_favicon_urls_.clear();
317 }
318 
~FaviconService()319 FaviconService::~FaviconService() {}
320 
GetFaviconForURLImpl(const FaviconForURLParams & params,const std::vector<ui::ScaleFactor> & desired_scale_factors,const FaviconResultsCallback & callback,CancelableTaskTracker * tracker)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);
337   }
338   return RunWithEmptyResultAsync(callback, tracker);
339 }
340 
RunFaviconImageCallbackWithBitmapResults(const FaviconImageCallback & callback,int desired_size_in_dip,const std::vector<chrome::FaviconBitmapResult> & favicon_bitmap_results)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);
351 
352   image_result.icon_url = image_result.image.IsEmpty() ?
353       GURL() : favicon_bitmap_results[0].icon_url;
354   callback.Run(image_result);
355 }
356 
RunFaviconRawCallbackWithBitmapResults(const FaviconRawCallback & callback,int desired_size_in_dip,ui::ScaleFactor desired_scale_factor,const std::vector<chrome::FaviconBitmapResult> & favicon_bitmap_results)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;
365   }
366 
367   DCHECK_EQ(1u, favicon_bitmap_results.size());
368   chrome::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0];
369 
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;
376   }
377 
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;
387   }
388 
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);
395 
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;
401   }
402 
403   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
404       &resized_bitmap_data);
405   callback.Run(bitmap_result);
406 }
407