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