OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/favicon/core/favicon_service.h" | 5 #include "components/favicon/core/favicon_service.h" |
6 | 6 |
7 #include <stddef.h> | |
8 #include <cmath> | |
9 #include <utility> | |
10 | |
11 #include "base/hash.h" | |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/threading/thread_task_runner_handle.h" | |
14 #include "base/trace_event/trace_event.h" | |
15 #include "components/favicon/core/favicon_client.h" | |
16 #include "components/favicon_base/favicon_util.h" | |
17 #include "components/favicon_base/select_favicon_frames.h" | |
18 #include "components/history/core/browser/history_service.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 #include "url/gurl.h" | |
24 | |
25 namespace favicon { | 7 namespace favicon { |
26 namespace { | |
27 | |
28 // Helper to run callback with empty results if we cannot get the history | |
29 // service. | |
30 base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync( | |
31 const favicon_base::FaviconResultsCallback& callback, | |
32 base::CancelableTaskTracker* tracker) { | |
33 scoped_refptr<base::SingleThreadTaskRunner> thread_runner( | |
34 base::ThreadTaskRunnerHandle::Get()); | |
35 return tracker->PostTask( | |
36 thread_runner.get(), FROM_HERE, | |
37 base::Bind(callback, | |
38 std::vector<favicon_base::FaviconRawBitmapResult>())); | |
39 } | |
40 | |
41 // Returns a vector of pixel edge sizes from |size_in_dip| and | |
42 // favicon_base::GetFaviconScales(). | |
43 std::vector<int> GetPixelSizesForFaviconScales(int size_in_dip) { | |
44 std::vector<float> scales = favicon_base::GetFaviconScales(); | |
45 std::vector<int> sizes_in_pixel; | |
46 for (size_t i = 0; i < scales.size(); ++i) { | |
47 sizes_in_pixel.push_back(std::ceil(size_in_dip * scales[i])); | |
48 } | |
49 return sizes_in_pixel; | |
50 } | |
51 | |
52 } // namespace | |
53 | |
54 FaviconService::FaviconService(std::unique_ptr<FaviconClient> favicon_client, | |
55 history::HistoryService* history_service) | |
56 : favicon_client_(std::move(favicon_client)), | |
57 history_service_(history_service) {} | |
58 | |
59 FaviconService::~FaviconService() { | |
60 } | |
61 | 8 |
62 // static | 9 // static |
63 void FaviconService::FaviconResultsCallbackRunner( | 10 void FaviconService::FaviconResultsCallbackRunner( |
64 const favicon_base::FaviconResultsCallback& callback, | 11 const favicon_base::FaviconResultsCallback& callback, |
65 const std::vector<favicon_base::FaviconRawBitmapResult>* results) { | 12 const std::vector<favicon_base::FaviconRawBitmapResult>* results) { |
66 callback.Run(*results); | 13 callback.Run(*results); |
67 } | 14 } |
68 | 15 |
69 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage( | |
70 const GURL& icon_url, | |
71 const favicon_base::FaviconImageCallback& callback, | |
72 base::CancelableTaskTracker* tracker) { | |
73 TRACE_EVENT0("browser", "FaviconService::GetFaviconImage"); | |
74 favicon_base::FaviconResultsCallback callback_runner = | |
75 base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults, | |
76 base::Unretained(this), callback, gfx::kFaviconSize); | |
77 if (history_service_) { | |
78 std::vector<GURL> icon_urls; | |
79 icon_urls.push_back(icon_url); | |
80 return history_service_->GetFavicons( | |
81 icon_urls, | |
82 favicon_base::FAVICON, | |
83 GetPixelSizesForFaviconScales(gfx::kFaviconSize), | |
84 callback_runner, | |
85 tracker); | |
86 } | |
87 return RunWithEmptyResultAsync(callback_runner, tracker); | |
88 } | |
89 | |
90 base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon( | |
91 const GURL& icon_url, | |
92 favicon_base::IconType icon_type, | |
93 int desired_size_in_pixel, | |
94 const favicon_base::FaviconRawBitmapCallback& callback, | |
95 base::CancelableTaskTracker* tracker) { | |
96 TRACE_EVENT0("browser", "FaviconService::GetRawFavicon"); | |
97 favicon_base::FaviconResultsCallback callback_runner = | |
98 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
99 base::Unretained(this), callback, desired_size_in_pixel); | |
100 | |
101 if (history_service_) { | |
102 std::vector<GURL> icon_urls; | |
103 icon_urls.push_back(icon_url); | |
104 std::vector<int> desired_sizes_in_pixel; | |
105 desired_sizes_in_pixel.push_back(desired_size_in_pixel); | |
106 | |
107 return history_service_->GetFavicons( | |
108 icon_urls, icon_type, desired_sizes_in_pixel, callback_runner, tracker); | |
109 } | |
110 return RunWithEmptyResultAsync(callback_runner, tracker); | |
111 } | |
112 | |
113 base::CancelableTaskTracker::TaskId FaviconService::GetFavicon( | |
114 const GURL& icon_url, | |
115 favicon_base::IconType icon_type, | |
116 int desired_size_in_dip, | |
117 const favicon_base::FaviconResultsCallback& callback, | |
118 base::CancelableTaskTracker* tracker) { | |
119 TRACE_EVENT0("browser", "FaviconService::GetFavicon"); | |
120 if (history_service_) { | |
121 std::vector<GURL> icon_urls; | |
122 icon_urls.push_back(icon_url); | |
123 return history_service_->GetFavicons( | |
124 icon_urls, | |
125 icon_type, | |
126 GetPixelSizesForFaviconScales(desired_size_in_dip), | |
127 callback, | |
128 tracker); | |
129 } | |
130 return RunWithEmptyResultAsync(callback, tracker); | |
131 } | |
132 | |
133 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL( | |
134 const GURL& page_url, | |
135 const favicon_base::FaviconImageCallback& callback, | |
136 base::CancelableTaskTracker* tracker) { | |
137 TRACE_EVENT0("browser", "FaviconService::GetFaviconImageForPageURL"); | |
138 return GetFaviconForPageURLImpl( | |
139 page_url, favicon_base::FAVICON, | |
140 GetPixelSizesForFaviconScales(gfx::kFaviconSize), | |
141 base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults, | |
142 base::Unretained(this), callback, gfx::kFaviconSize), | |
143 tracker); | |
144 } | |
145 | |
146 base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL( | |
147 const GURL& page_url, | |
148 int icon_types, | |
149 int desired_size_in_pixel, | |
150 const favicon_base::FaviconRawBitmapCallback& callback, | |
151 base::CancelableTaskTracker* tracker) { | |
152 TRACE_EVENT0("browser", "FaviconService::GetRawFaviconForPageURL"); | |
153 std::vector<int> desired_sizes_in_pixel; | |
154 desired_sizes_in_pixel.push_back(desired_size_in_pixel); | |
155 return GetFaviconForPageURLImpl( | |
156 page_url, icon_types, desired_sizes_in_pixel, | |
157 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
158 base::Unretained(this), callback, desired_size_in_pixel), | |
159 tracker); | |
160 } | |
161 | |
162 base::CancelableTaskTracker::TaskId | |
163 FaviconService::GetLargestRawFaviconForPageURL( | |
164 const GURL& page_url, | |
165 const std::vector<int>& icon_types, | |
166 int minimum_size_in_pixels, | |
167 const favicon_base::FaviconRawBitmapCallback& callback, | |
168 base::CancelableTaskTracker* tracker) { | |
169 TRACE_EVENT0("browser", "FaviconService::GetLargestRawFaviconForPageURL"); | |
170 favicon_base::FaviconResultsCallback favicon_results_callback = | |
171 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
172 base::Unretained(this), callback, 0); | |
173 if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) { | |
174 std::vector<int> desired_sizes_in_pixel; | |
175 desired_sizes_in_pixel.push_back(0); | |
176 return favicon_client_->GetFaviconForNativeApplicationURL( | |
177 page_url, desired_sizes_in_pixel, favicon_results_callback, tracker); | |
178 } | |
179 if (history_service_) { | |
180 return history_service_->GetLargestFaviconForURL(page_url, icon_types, | |
181 minimum_size_in_pixels, callback, tracker); | |
182 } | |
183 return RunWithEmptyResultAsync(favicon_results_callback, tracker); | |
184 } | |
185 | |
186 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL( | |
187 const GURL& page_url, | |
188 int icon_types, | |
189 int desired_size_in_dip, | |
190 const favicon_base::FaviconResultsCallback& callback, | |
191 base::CancelableTaskTracker* tracker) { | |
192 TRACE_EVENT0("browser", "FaviconService::GetFaviconForPageURL"); | |
193 return GetFaviconForPageURLImpl( | |
194 page_url, | |
195 icon_types, | |
196 GetPixelSizesForFaviconScales(desired_size_in_dip), | |
197 callback, | |
198 tracker); | |
199 } | |
200 | |
201 base::CancelableTaskTracker::TaskId | |
202 FaviconService::UpdateFaviconMappingsAndFetch( | |
203 const GURL& page_url, | |
204 const std::vector<GURL>& icon_urls, | |
205 int icon_types, | |
206 int desired_size_in_dip, | |
207 const favicon_base::FaviconResultsCallback& callback, | |
208 base::CancelableTaskTracker* tracker) { | |
209 if (history_service_) { | |
210 return history_service_->UpdateFaviconMappingsAndFetch( | |
211 page_url, | |
212 icon_urls, | |
213 icon_types, | |
214 GetPixelSizesForFaviconScales(desired_size_in_dip), | |
215 callback, | |
216 tracker); | |
217 } | |
218 return RunWithEmptyResultAsync(callback, tracker); | |
219 } | |
220 | |
221 base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID( | |
222 favicon_base::FaviconID favicon_id, | |
223 const favicon_base::FaviconRawBitmapCallback& callback, | |
224 base::CancelableTaskTracker* tracker) { | |
225 TRACE_EVENT0("browser", "FaviconService::GetLargestRawFaviconForID"); | |
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 base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults, | |
231 base::Unretained(this), callback, desired_size); | |
232 | |
233 if (history_service_) { | |
234 return history_service_->GetFaviconForID( | |
235 favicon_id, desired_size, callback_runner, tracker); | |
236 } | |
237 return RunWithEmptyResultAsync(callback_runner, tracker); | |
238 } | |
239 | |
240 void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) { | |
241 if (history_service_) | |
242 history_service_->SetFaviconsOutOfDateForPage(page_url); | |
243 } | |
244 | |
245 void FaviconService::SetImportedFavicons( | |
246 const favicon_base::FaviconUsageDataList& favicon_usage) { | |
247 if (history_service_) | |
248 history_service_->SetImportedFavicons(favicon_usage); | |
249 } | |
250 | |
251 void FaviconService::MergeFavicon( | |
252 const GURL& page_url, | |
253 const GURL& icon_url, | |
254 favicon_base::IconType icon_type, | |
255 scoped_refptr<base::RefCountedMemory> bitmap_data, | |
256 const gfx::Size& pixel_size) { | |
257 if (history_service_) { | |
258 history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data, | |
259 pixel_size); | |
260 } | |
261 } | |
262 | |
263 void FaviconService::SetFavicons(const GURL& page_url, | |
264 const GURL& icon_url, | |
265 favicon_base::IconType icon_type, | |
266 const gfx::Image& image) { | |
267 if (!history_service_) | |
268 return; | |
269 | |
270 gfx::ImageSkia image_skia = image.AsImageSkia(); | |
271 image_skia.EnsureRepsForSupportedScales(); | |
272 const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps(); | |
273 std::vector<SkBitmap> bitmaps; | |
274 const std::vector<float> favicon_scales = favicon_base::GetFaviconScales(); | |
275 for (size_t i = 0; i < image_reps.size(); ++i) { | |
276 // Don't save if the scale isn't one of supported favicon scales. | |
277 if (std::find(favicon_scales.begin(), | |
278 favicon_scales.end(), | |
279 image_reps[i].scale()) == favicon_scales.end()) { | |
280 continue; | |
281 } | |
282 bitmaps.push_back(image_reps[i].sk_bitmap()); | |
283 } | |
284 history_service_->SetFavicons(page_url, icon_type, icon_url, bitmaps); | |
285 } | |
286 | |
287 void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) { | |
288 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); | |
289 missing_favicon_urls_.insert(url_hash); | |
290 } | |
291 | |
292 bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const { | |
293 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); | |
294 return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end(); | |
295 } | |
296 | |
297 void FaviconService::ClearUnableToDownloadFavicons() { | |
298 missing_favicon_urls_.clear(); | |
299 } | |
300 | |
301 base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl( | |
302 const GURL& page_url, | |
303 int icon_types, | |
304 const std::vector<int>& desired_sizes_in_pixel, | |
305 const favicon_base::FaviconResultsCallback& callback, | |
306 base::CancelableTaskTracker* tracker) { | |
307 if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) { | |
308 return favicon_client_->GetFaviconForNativeApplicationURL( | |
309 page_url, desired_sizes_in_pixel, callback, tracker); | |
310 } | |
311 if (history_service_) { | |
312 return history_service_->GetFaviconsForURL(page_url, | |
313 icon_types, | |
314 desired_sizes_in_pixel, | |
315 callback, | |
316 tracker); | |
317 } | |
318 return RunWithEmptyResultAsync(callback, tracker); | |
319 } | |
320 | |
321 void FaviconService::RunFaviconImageCallbackWithBitmapResults( | |
322 const favicon_base::FaviconImageCallback& callback, | |
323 int desired_size_in_dip, | |
324 const std::vector<favicon_base::FaviconRawBitmapResult>& | |
325 favicon_bitmap_results) { | |
326 TRACE_EVENT0("browser", | |
327 "FaviconService::RunFaviconImageCallbackWithBitmapResults"); | |
328 favicon_base::FaviconImageResult image_result; | |
329 image_result.image = favicon_base::SelectFaviconFramesFromPNGs( | |
330 favicon_bitmap_results, | |
331 favicon_base::GetFaviconScales(), | |
332 desired_size_in_dip); | |
333 favicon_base::SetFaviconColorSpace(&image_result.image); | |
334 | |
335 image_result.icon_url = image_result.image.IsEmpty() ? | |
336 GURL() : favicon_bitmap_results[0].icon_url; | |
337 callback.Run(image_result); | |
338 } | |
339 | |
340 void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults( | |
341 const favicon_base::FaviconRawBitmapCallback& callback, | |
342 int desired_size_in_pixel, | |
343 const std::vector<favicon_base::FaviconRawBitmapResult>& | |
344 favicon_bitmap_results) { | |
345 TRACE_EVENT0("browser", | |
346 "FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults"); | |
347 callback.Run( | |
348 ResizeFaviconBitmapResult(favicon_bitmap_results, desired_size_in_pixel)); | |
349 } | |
350 | |
351 } // namespace favicon | 16 } // namespace favicon |
OLD | NEW |