• 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 <cmath>
8 
9 #include "base/hash.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "chrome/browser/history/history_backend.h"
12 #include "chrome/browser/history/history_service.h"
13 #include "chrome/browser/history/history_service_factory.h"
14 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
15 #include "chrome/common/importer/imported_favicon_usage.h"
16 #include "chrome/common/url_constants.h"
17 #include "components/favicon_base/favicon_types.h"
18 #include "components/favicon_base/favicon_util.h"
19 #include "components/favicon_base/select_favicon_frames.h"
20 #include "extensions/common/constants.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/gfx/codec/png_codec.h"
23 #include "ui/gfx/favicon_size.h"
24 #include "ui/gfx/image/image_skia.h"
25 
26 using base::Bind;
27 
28 namespace {
29 
CancelOrRunFaviconResultsCallback(const base::CancelableTaskTracker::IsCanceledCallback & is_canceled,const favicon_base::FaviconResultsCallback & callback,const std::vector<favicon_base::FaviconRawBitmapResult> & results)30 void CancelOrRunFaviconResultsCallback(
31     const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
32     const favicon_base::FaviconResultsCallback& callback,
33     const std::vector<favicon_base::FaviconRawBitmapResult>& results) {
34   if (is_canceled.Run())
35     return;
36   callback.Run(results);
37 }
38 
39 // Helper to run callback with empty results if we cannot get the history
40 // service.
RunWithEmptyResultAsync(const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)41 base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
42     const favicon_base::FaviconResultsCallback& callback,
43     base::CancelableTaskTracker* tracker) {
44   return tracker->PostTask(
45       base::MessageLoopProxy::current().get(),
46       FROM_HERE,
47       Bind(callback, std::vector<favicon_base::FaviconRawBitmapResult>()));
48 }
49 
50 // Return the TaskId to retreive the favicon from chrome specific URL.
GetFaviconForChromeURL(Profile * profile,const GURL & page_url,const std::vector<int> & desired_sizes_in_pixel,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)51 base::CancelableTaskTracker::TaskId GetFaviconForChromeURL(
52     Profile* profile,
53     const GURL& page_url,
54     const std::vector<int>& desired_sizes_in_pixel,
55     const favicon_base::FaviconResultsCallback& callback,
56     base::CancelableTaskTracker* tracker) {
57   base::CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
58   base::CancelableTaskTracker::TaskId id =
59       tracker->NewTrackedTaskId(&is_canceled_cb);
60   favicon_base::FaviconResultsCallback cancelable_cb =
61       Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback);
62   ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(
63       profile, page_url, desired_sizes_in_pixel, cancelable_cb);
64   return id;
65 }
66 
67 // Returns a vector of pixel edge sizes from |size_in_dip| and
68 // favicon_base::GetFaviconScales().
GetPixelSizesForFaviconScales(int size_in_dip)69 std::vector<int> GetPixelSizesForFaviconScales(int size_in_dip) {
70   std::vector<float> scales = favicon_base::GetFaviconScales();
71   std::vector<int> sizes_in_pixel;
72   for (size_t i = 0; i < scales.size(); ++i) {
73     sizes_in_pixel.push_back(std::ceil(size_in_dip * scales[i]));
74   }
75   return sizes_in_pixel;
76 }
77 
78 }  // namespace
79 
FaviconService(Profile * profile,FaviconClient * favicon_client)80 FaviconService::FaviconService(Profile* profile, FaviconClient* favicon_client)
81     : history_service_(
82           HistoryServiceFactory::GetForProfile(profile,
83                                                Profile::EXPLICIT_ACCESS)),
84       profile_(profile),
85       favicon_client_(favicon_client) {
86 }
87 
88 // static
FaviconResultsCallbackRunner(const favicon_base::FaviconResultsCallback & callback,const std::vector<favicon_base::FaviconRawBitmapResult> * results)89 void FaviconService::FaviconResultsCallbackRunner(
90     const favicon_base::FaviconResultsCallback& callback,
91     const std::vector<favicon_base::FaviconRawBitmapResult>* results) {
92   callback.Run(*results);
93 }
94 
GetFaviconImage(const GURL & icon_url,const favicon_base::FaviconImageCallback & callback,base::CancelableTaskTracker * tracker)95 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
96     const GURL& icon_url,
97     const favicon_base::FaviconImageCallback& callback,
98     base::CancelableTaskTracker* tracker) {
99   favicon_base::FaviconResultsCallback callback_runner =
100       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
101            base::Unretained(this), callback, gfx::kFaviconSize);
102   if (history_service_) {
103     std::vector<GURL> icon_urls;
104     icon_urls.push_back(icon_url);
105     return history_service_->GetFavicons(
106         icon_urls,
107         favicon_base::FAVICON,
108         GetPixelSizesForFaviconScales(gfx::kFaviconSize),
109         callback_runner,
110         tracker);
111   }
112   return RunWithEmptyResultAsync(callback_runner, tracker);
113 }
114 
GetRawFavicon(const GURL & icon_url,favicon_base::IconType icon_type,int desired_size_in_pixel,const favicon_base::FaviconRawBitmapCallback & callback,base::CancelableTaskTracker * tracker)115 base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
116     const GURL& icon_url,
117     favicon_base::IconType icon_type,
118     int desired_size_in_pixel,
119     const favicon_base::FaviconRawBitmapCallback& callback,
120     base::CancelableTaskTracker* tracker) {
121   favicon_base::FaviconResultsCallback callback_runner =
122       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
123            base::Unretained(this),
124            callback,
125            desired_size_in_pixel);
126 
127   if (history_service_) {
128     std::vector<GURL> icon_urls;
129     icon_urls.push_back(icon_url);
130     std::vector<int> desired_sizes_in_pixel;
131     desired_sizes_in_pixel.push_back(desired_size_in_pixel);
132 
133     return history_service_->GetFavicons(
134         icon_urls, icon_type, desired_sizes_in_pixel, callback_runner, tracker);
135   }
136   return RunWithEmptyResultAsync(callback_runner, tracker);
137 }
138 
GetFavicon(const GURL & icon_url,favicon_base::IconType icon_type,int desired_size_in_dip,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)139 base::CancelableTaskTracker::TaskId FaviconService::GetFavicon(
140     const GURL& icon_url,
141     favicon_base::IconType icon_type,
142     int desired_size_in_dip,
143     const favicon_base::FaviconResultsCallback& callback,
144     base::CancelableTaskTracker* tracker) {
145   if (history_service_) {
146     std::vector<GURL> icon_urls;
147     icon_urls.push_back(icon_url);
148     return history_service_->GetFavicons(
149         icon_urls,
150         icon_type,
151         GetPixelSizesForFaviconScales(desired_size_in_dip),
152         callback,
153         tracker);
154   }
155   return RunWithEmptyResultAsync(callback, tracker);
156 }
157 
GetFaviconImageForPageURL(const GURL & page_url,const favicon_base::FaviconImageCallback & callback,base::CancelableTaskTracker * tracker)158 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL(
159     const GURL& page_url,
160     const favicon_base::FaviconImageCallback& callback,
161     base::CancelableTaskTracker* tracker) {
162   return GetFaviconForPageURLImpl(
163       page_url,
164       favicon_base::FAVICON,
165       GetPixelSizesForFaviconScales(gfx::kFaviconSize),
166       Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
167            base::Unretained(this),
168            callback,
169            gfx::kFaviconSize),
170       tracker);
171 }
172 
GetRawFaviconForPageURL(const GURL & page_url,int icon_types,int desired_size_in_pixel,const favicon_base::FaviconRawBitmapCallback & callback,base::CancelableTaskTracker * tracker)173 base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL(
174     const GURL& page_url,
175     int icon_types,
176     int desired_size_in_pixel,
177     const favicon_base::FaviconRawBitmapCallback& callback,
178     base::CancelableTaskTracker* tracker) {
179   std::vector<int> desired_sizes_in_pixel;
180   desired_sizes_in_pixel.push_back(desired_size_in_pixel);
181   return GetFaviconForPageURLImpl(
182       page_url,
183       icon_types,
184       desired_sizes_in_pixel,
185       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
186            base::Unretained(this),
187            callback,
188            desired_size_in_pixel),
189       tracker);
190 }
191 
192 base::CancelableTaskTracker::TaskId
GetLargestRawFaviconForPageURL(const GURL & page_url,const std::vector<int> & icon_types,int minimum_size_in_pixels,const favicon_base::FaviconRawBitmapCallback & callback,base::CancelableTaskTracker * tracker)193 FaviconService::GetLargestRawFaviconForPageURL(
194     const GURL& page_url,
195     const std::vector<int>& icon_types,
196     int minimum_size_in_pixels,
197     const favicon_base::FaviconRawBitmapCallback& callback,
198     base::CancelableTaskTracker* tracker) {
199   favicon_base::FaviconResultsCallback favicon_results_callback =
200       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
201            base::Unretained(this),
202            callback,
203            0);
204   if (page_url.SchemeIs(content::kChromeUIScheme) ||
205       page_url.SchemeIs(extensions::kExtensionScheme)) {
206     std::vector<int> desired_sizes_in_pixel;
207     desired_sizes_in_pixel.push_back(0);
208     return GetFaviconForChromeURL(profile_,
209                                   page_url,
210                                   desired_sizes_in_pixel,
211                                   favicon_results_callback,
212                                   tracker);
213   }
214   if (history_service_) {
215     return history_service_->GetLargestFaviconForURL(page_url, icon_types,
216         minimum_size_in_pixels, callback, tracker);
217   }
218   return RunWithEmptyResultAsync(favicon_results_callback, tracker);
219 }
220 
GetFaviconForPageURL(const GURL & page_url,int icon_types,int desired_size_in_dip,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)221 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL(
222     const GURL& page_url,
223     int icon_types,
224     int desired_size_in_dip,
225     const favicon_base::FaviconResultsCallback& callback,
226     base::CancelableTaskTracker* tracker) {
227   return GetFaviconForPageURLImpl(
228       page_url,
229       icon_types,
230       GetPixelSizesForFaviconScales(desired_size_in_dip),
231       callback,
232       tracker);
233 }
234 
235 base::CancelableTaskTracker::TaskId
UpdateFaviconMappingsAndFetch(const GURL & page_url,const std::vector<GURL> & icon_urls,int icon_types,int desired_size_in_dip,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)236 FaviconService::UpdateFaviconMappingsAndFetch(
237     const GURL& page_url,
238     const std::vector<GURL>& icon_urls,
239     int icon_types,
240     int desired_size_in_dip,
241     const favicon_base::FaviconResultsCallback& callback,
242     base::CancelableTaskTracker* tracker) {
243   if (history_service_) {
244     return history_service_->UpdateFaviconMappingsAndFetch(
245         page_url,
246         icon_urls,
247         icon_types,
248         GetPixelSizesForFaviconScales(desired_size_in_dip),
249         callback,
250         tracker);
251   }
252   return RunWithEmptyResultAsync(callback, tracker);
253 }
254 
GetLargestRawFaviconForID(favicon_base::FaviconID favicon_id,const favicon_base::FaviconRawBitmapCallback & callback,base::CancelableTaskTracker * tracker)255 base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
256     favicon_base::FaviconID favicon_id,
257     const favicon_base::FaviconRawBitmapCallback& callback,
258     base::CancelableTaskTracker* tracker) {
259   // Use 0 as |desired_size| to get the largest bitmap for |favicon_id| without
260   // any resizing.
261   int desired_size = 0;
262   favicon_base::FaviconResultsCallback callback_runner =
263       Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
264            base::Unretained(this),
265            callback,
266            desired_size);
267 
268   if (history_service_) {
269     return history_service_->GetFaviconForID(
270         favicon_id, desired_size, callback_runner, tracker);
271   }
272   return RunWithEmptyResultAsync(callback_runner, tracker);
273 }
274 
SetFaviconOutOfDateForPage(const GURL & page_url)275 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
276   if (history_service_)
277     history_service_->SetFaviconsOutOfDateForPage(page_url);
278 }
279 
CloneFavicon(const GURL & old_page_url,const GURL & new_page_url)280 void FaviconService::CloneFavicon(const GURL& old_page_url,
281                                   const GURL& new_page_url) {
282   if (history_service_)
283     history_service_->CloneFavicons(old_page_url, new_page_url);
284 }
285 
SetImportedFavicons(const std::vector<ImportedFaviconUsage> & favicon_usage)286 void FaviconService::SetImportedFavicons(
287     const std::vector<ImportedFaviconUsage>& favicon_usage) {
288   if (history_service_)
289     history_service_->SetImportedFavicons(favicon_usage);
290 }
291 
MergeFavicon(const GURL & page_url,const GURL & icon_url,favicon_base::IconType icon_type,scoped_refptr<base::RefCountedMemory> bitmap_data,const gfx::Size & pixel_size)292 void FaviconService::MergeFavicon(
293     const GURL& page_url,
294     const GURL& icon_url,
295     favicon_base::IconType icon_type,
296     scoped_refptr<base::RefCountedMemory> bitmap_data,
297     const gfx::Size& pixel_size) {
298   if (history_service_) {
299     history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
300                                    pixel_size);
301   }
302 }
303 
SetFavicons(const GURL & page_url,const GURL & icon_url,favicon_base::IconType icon_type,const gfx::Image & image)304 void FaviconService::SetFavicons(const GURL& page_url,
305                                  const GURL& icon_url,
306                                  favicon_base::IconType icon_type,
307                                  const gfx::Image& image) {
308   if (!history_service_)
309     return;
310 
311   gfx::ImageSkia image_skia = image.AsImageSkia();
312   image_skia.EnsureRepsForSupportedScales();
313   const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
314   std::vector<SkBitmap> bitmaps;
315   const std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
316   for (size_t i = 0; i < image_reps.size(); ++i) {
317     // Don't save if the scale isn't one of supported favicon scales.
318     if (std::find(favicon_scales.begin(),
319                   favicon_scales.end(),
320                   image_reps[i].scale()) == favicon_scales.end()) {
321       continue;
322     }
323     bitmaps.push_back(image_reps[i].sk_bitmap());
324   }
325   history_service_->SetFavicons(page_url, icon_type, icon_url, bitmaps);
326 }
327 
UnableToDownloadFavicon(const GURL & icon_url)328 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
329   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
330   missing_favicon_urls_.insert(url_hash);
331 }
332 
WasUnableToDownloadFavicon(const GURL & icon_url) const333 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
334   MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
335   return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
336 }
337 
ClearUnableToDownloadFavicons()338 void FaviconService::ClearUnableToDownloadFavicons() {
339   missing_favicon_urls_.clear();
340 }
341 
~FaviconService()342 FaviconService::~FaviconService() {}
343 
GetFaviconForPageURLImpl(const GURL & page_url,int icon_types,const std::vector<int> & desired_sizes_in_pixel,const favicon_base::FaviconResultsCallback & callback,base::CancelableTaskTracker * tracker)344 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl(
345     const GURL& page_url,
346     int icon_types,
347     const std::vector<int>& desired_sizes_in_pixel,
348     const favicon_base::FaviconResultsCallback& callback,
349     base::CancelableTaskTracker* tracker) {
350   if (page_url.SchemeIs(content::kChromeUIScheme) ||
351       page_url.SchemeIs(extensions::kExtensionScheme)) {
352     return GetFaviconForChromeURL(
353         profile_, page_url, desired_sizes_in_pixel, callback, tracker);
354   }
355   if (history_service_) {
356     return history_service_->GetFaviconsForURL(page_url,
357                                                icon_types,
358                                                desired_sizes_in_pixel,
359                                                callback,
360                                                tracker);
361   }
362   return RunWithEmptyResultAsync(callback, tracker);
363 }
364 
RunFaviconImageCallbackWithBitmapResults(const favicon_base::FaviconImageCallback & callback,int desired_size_in_dip,const std::vector<favicon_base::FaviconRawBitmapResult> & favicon_bitmap_results)365 void FaviconService::RunFaviconImageCallbackWithBitmapResults(
366     const favicon_base::FaviconImageCallback& callback,
367     int desired_size_in_dip,
368     const std::vector<favicon_base::FaviconRawBitmapResult>&
369         favicon_bitmap_results) {
370   favicon_base::FaviconImageResult image_result;
371   image_result.image = favicon_base::SelectFaviconFramesFromPNGs(
372       favicon_bitmap_results,
373       favicon_base::GetFaviconScales(),
374       desired_size_in_dip);
375   favicon_base::SetFaviconColorSpace(&image_result.image);
376 
377   image_result.icon_url = image_result.image.IsEmpty() ?
378       GURL() : favicon_bitmap_results[0].icon_url;
379   callback.Run(image_result);
380 }
381 
RunFaviconRawBitmapCallbackWithBitmapResults(const favicon_base::FaviconRawBitmapCallback & callback,int desired_size_in_pixel,const std::vector<favicon_base::FaviconRawBitmapResult> & favicon_bitmap_results)382 void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults(
383     const favicon_base::FaviconRawBitmapCallback& callback,
384     int desired_size_in_pixel,
385     const std::vector<favicon_base::FaviconRawBitmapResult>&
386         favicon_bitmap_results) {
387   if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
388     callback.Run(favicon_base::FaviconRawBitmapResult());
389     return;
390   }
391 
392   favicon_base::FaviconRawBitmapResult bitmap_result =
393       favicon_bitmap_results[0];
394 
395   // If the desired size is 0, SelectFaviconFrames() will return the largest
396   // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
397   // data for a single bitmap, return it and avoid an unnecessary decode.
398   if (desired_size_in_pixel == 0) {
399     callback.Run(bitmap_result);
400     return;
401   }
402 
403   // If history bitmap is already desired pixel size, return early.
404   if (bitmap_result.pixel_size.width() == desired_size_in_pixel &&
405       bitmap_result.pixel_size.height() == desired_size_in_pixel) {
406     callback.Run(bitmap_result);
407     return;
408   }
409 
410   // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
411   // convert back.
412   std::vector<float> desired_favicon_scales;
413   desired_favicon_scales.push_back(1.0f);
414   gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
415       favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel);
416 
417   std::vector<unsigned char> resized_bitmap_data;
418   if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
419                                          &resized_bitmap_data)) {
420     callback.Run(favicon_base::FaviconRawBitmapResult());
421     return;
422   }
423 
424   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
425       &resized_bitmap_data);
426   callback.Run(bitmap_result);
427 }
428