OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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_handler.h" | 5 #include "components/favicon/core/favicon_handler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 if (!b1.icon_sizes.empty()) | 144 if (!b1.icon_sizes.empty()) |
145 area1 = b1.icon_sizes.front().GetArea(); | 145 area1 = b1.icon_sizes.front().GetArea(); |
146 | 146 |
147 int area2 = 0; | 147 int area2 = 0; |
148 if (!b2.icon_sizes.empty()) | 148 if (!b2.icon_sizes.empty()) |
149 area2 = b2.icon_sizes.front().GetArea(); | 149 area2 = b2.icon_sizes.front().GetArea(); |
150 | 150 |
151 return area1 > area2; | 151 return area1 > area2; |
152 } | 152 } |
153 | 153 |
| 154 // Sorts the entries in |image_urls| by icon size in descending order. |
| 155 // Discards all but the largest size for each FaviconURL. |
| 156 void SortAndPruneImageUrls(std::vector<FaviconURL>* image_urls) { |
| 157 // Not using const-reference since the loop mutates FaviconURL::icon_sizes. |
| 158 for (FaviconURL& image_url : *image_urls) { |
| 159 if (image_url.icon_sizes.empty()) |
| 160 continue; |
| 161 |
| 162 gfx::Size largest = |
| 163 image_url.icon_sizes[GetLargestSizeIndex(image_url.icon_sizes)]; |
| 164 image_url.icon_sizes.clear(); |
| 165 image_url.icon_sizes.push_back(largest); |
| 166 } |
| 167 std::stable_sort(image_urls->begin(), image_urls->end(), CompareIconSize); |
| 168 } |
| 169 |
| 170 // Checks whether two FaviconURLs are equal ignoring the icon sizes. |
| 171 bool FaviconURLsEqualIgnoringSizes(const FaviconURL& u1, const FaviconURL& u2) { |
| 172 return u1.icon_type == u2.icon_type && u1.icon_url == u2.icon_url; |
| 173 } |
| 174 |
154 } // namespace | 175 } // namespace |
155 | 176 |
156 //////////////////////////////////////////////////////////////////////////////// | 177 //////////////////////////////////////////////////////////////////////////////// |
157 | 178 |
158 FaviconHandler::DownloadRequest::DownloadRequest() | 179 FaviconHandler::DownloadRequest::DownloadRequest() |
159 : icon_type(favicon_base::INVALID_ICON) { | 180 : icon_type(favicon_base::INVALID_ICON) { |
160 } | 181 } |
161 | 182 |
162 FaviconHandler::DownloadRequest::~DownloadRequest() { | 183 FaviconHandler::DownloadRequest::~DownloadRequest() { |
163 } | 184 } |
(...skipping 28 matching lines...) Expand all Loading... |
192 FaviconHandler::FaviconHandler(FaviconService* service, | 213 FaviconHandler::FaviconHandler(FaviconService* service, |
193 FaviconDriver* driver, | 214 FaviconDriver* driver, |
194 Type handler_type, | 215 Type handler_type, |
195 bool download_largest_icon) | 216 bool download_largest_icon) |
196 : got_favicon_from_history_(false), | 217 : got_favicon_from_history_(false), |
197 favicon_expired_or_incomplete_(false), | 218 favicon_expired_or_incomplete_(false), |
198 handler_type_(handler_type), | 219 handler_type_(handler_type), |
199 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)), | 220 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)), |
200 download_largest_icon_(download_largest_icon), | 221 download_largest_icon_(download_largest_icon), |
201 service_(service), | 222 service_(service), |
202 driver_(driver) { | 223 driver_(driver), |
| 224 current_candidate_index_(0u) { |
203 DCHECK(driver_); | 225 DCHECK(driver_); |
204 } | 226 } |
205 | 227 |
206 FaviconHandler::~FaviconHandler() { | 228 FaviconHandler::~FaviconHandler() { |
207 } | 229 } |
208 | 230 |
209 // static | 231 // static |
210 int FaviconHandler::GetIconTypesFromHandlerType( | 232 int FaviconHandler::GetIconTypesFromHandlerType( |
211 FaviconHandler::Type handler_type) { | 233 FaviconHandler::Type handler_type) { |
212 switch (handler_type) { | 234 switch (handler_type) { |
(...skipping 10 matching lines...) Expand all Loading... |
223 | 245 |
224 void FaviconHandler::FetchFavicon(const GURL& url) { | 246 void FaviconHandler::FetchFavicon(const GURL& url) { |
225 cancelable_task_tracker_.TryCancelAll(); | 247 cancelable_task_tracker_.TryCancelAll(); |
226 | 248 |
227 url_ = url; | 249 url_ = url; |
228 | 250 |
229 favicon_expired_or_incomplete_ = got_favicon_from_history_ = false; | 251 favicon_expired_or_incomplete_ = got_favicon_from_history_ = false; |
230 download_requests_.clear(); | 252 download_requests_.clear(); |
231 image_urls_.clear(); | 253 image_urls_.clear(); |
232 history_results_.clear(); | 254 history_results_.clear(); |
| 255 current_candidate_index_ = 0u; |
233 best_favicon_candidate_ = FaviconCandidate(); | 256 best_favicon_candidate_ = FaviconCandidate(); |
234 | 257 |
235 // Request the favicon from the history service. In parallel to this the | 258 // Request the favicon from the history service. In parallel to this the |
236 // renderer is going to notify us (well WebContents) when the favicon url is | 259 // renderer is going to notify us (well WebContents) when the favicon url is |
237 // available. | 260 // available. |
238 GetFaviconForURLFromFaviconService( | 261 GetFaviconForURLFromFaviconService( |
239 url_, icon_types_, | 262 url_, icon_types_, |
240 base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, | 263 base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, |
241 base::Unretained(this)), | 264 base::Unretained(this)), |
242 &cancelable_task_tracker_); | 265 &cancelable_task_tracker_); |
(...skipping 16 matching lines...) Expand all Loading... |
259 | 282 |
260 // The size of the downloaded icon may not match the declared size. Stop | 283 // The size of the downloaded icon may not match the declared size. Stop |
261 // downloading if: | 284 // downloading if: |
262 // - current candidate is only candidate. | 285 // - current candidate is only candidate. |
263 // - next candidate doesn't have sizes attributes, in this case, the rest | 286 // - next candidate doesn't have sizes attributes, in this case, the rest |
264 // candidates don't have sizes attribute either, stop downloading now, | 287 // candidates don't have sizes attribute either, stop downloading now, |
265 // otherwise, all favicon without sizes attribute are downloaded. | 288 // otherwise, all favicon without sizes attribute are downloaded. |
266 // - next candidate has sizes attribute and it is not larger than largest, | 289 // - next candidate has sizes attribute and it is not larger than largest, |
267 // - current candidate is maximal one we want. | 290 // - current candidate is maximal one we want. |
268 const int maximal_size = GetMaximalIconSize(icon_type); | 291 const int maximal_size = GetMaximalIconSize(icon_type); |
269 exact_match = image_urls_.size() == 1 || | 292 if (current_candidate_index_ + 1 >= image_urls_.size()) { |
270 image_urls_[1].icon_sizes.empty() || | 293 exact_match = true; |
271 image_urls_[1].icon_sizes[0].GetArea() <= largest.GetArea() || | 294 } else { |
272 (image.Size().width() == maximal_size && | 295 FaviconURL next_image_url = image_urls_[current_candidate_index_ + 1]; |
273 image.Size().height() == maximal_size); | 296 exact_match = next_image_url.icon_sizes.empty() || |
| 297 next_image_url.icon_sizes[0].GetArea() <= largest.GetArea() || |
| 298 (image.Size().width() == maximal_size && |
| 299 image.Size().height() == maximal_size); |
| 300 } |
274 } else { | 301 } else { |
275 exact_match = score == 1 || preferred_icon_size() == 0; | 302 exact_match = score == 1 || preferred_icon_size() == 0; |
276 replace_best_favicon_candidate = | 303 replace_best_favicon_candidate = |
277 exact_match || | 304 exact_match || |
278 best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON || | 305 best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON || |
279 score > best_favicon_candidate_.score; | 306 score > best_favicon_candidate_.score; |
280 } | 307 } |
281 if (replace_best_favicon_candidate) { | 308 if (replace_best_favicon_candidate) { |
282 best_favicon_candidate_ = | 309 best_favicon_candidate_ = |
283 FaviconCandidate(image_url, image, score, icon_type); | 310 FaviconCandidate(image_url, image, score, icon_type); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 driver_->OnFaviconAvailable( | 346 driver_->OnFaviconAvailable( |
320 url_, icon_url, image_with_adjusted_colorspace, is_active_favicon); | 347 url_, icon_url, image_with_adjusted_colorspace, is_active_favicon); |
321 } | 348 } |
322 | 349 |
323 void FaviconHandler::OnUpdateFaviconURL( | 350 void FaviconHandler::OnUpdateFaviconURL( |
324 const GURL& page_url, | 351 const GURL& page_url, |
325 const std::vector<FaviconURL>& candidates) { | 352 const std::vector<FaviconURL>& candidates) { |
326 if (page_url != url_) | 353 if (page_url != url_) |
327 return; | 354 return; |
328 | 355 |
329 download_requests_.clear(); | 356 std::vector<FaviconURL> pruned_candidates; |
330 image_urls_.clear(); | |
331 best_favicon_candidate_ = FaviconCandidate(); | |
332 | |
333 for (const FaviconURL& candidate : candidates) { | 357 for (const FaviconURL& candidate : candidates) { |
334 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) | 358 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) |
335 image_urls_.push_back(candidate); | 359 pruned_candidates.push_back(candidate); |
336 } | 360 } |
337 | 361 |
338 if (download_largest_icon_) | 362 if (download_largest_icon_) |
339 SortAndPruneImageUrls(); | 363 SortAndPruneImageUrls(&pruned_candidates); |
| 364 |
| 365 // Ignore FaviconURL::icon_sizes because FaviconURL::icon_sizes is not stored |
| 366 // in the history database. |
| 367 if (image_urls_.size() == pruned_candidates.size() && |
| 368 std::equal(pruned_candidates.begin(), pruned_candidates.end(), |
| 369 image_urls_.begin(), FaviconURLsEqualIgnoringSizes)) { |
| 370 return; |
| 371 } |
| 372 |
| 373 download_requests_.clear(); |
| 374 image_urls_ = pruned_candidates; |
| 375 current_candidate_index_ = 0u; |
| 376 best_favicon_candidate_ = FaviconCandidate(); |
340 | 377 |
341 // TODO(davemoore) Should clear on empty url. Currently we ignore it. | 378 // TODO(davemoore) Should clear on empty url. Currently we ignore it. |
342 // This appears to be what FF does as well. | 379 // This appears to be what FF does as well. |
343 if (!image_urls_.empty()) | 380 if (current_candidate()) |
344 ProcessCurrentUrl(); | 381 ProcessCurrentUrl(); |
345 } | 382 } |
346 | 383 |
347 void FaviconHandler::ProcessCurrentUrl() { | 384 void FaviconHandler::ProcessCurrentUrl() { |
348 DCHECK(!image_urls_.empty()); | 385 DCHECK(!image_urls_.empty()); |
349 | 386 |
350 // current_candidate() may return NULL if download_largest_icon_ is true and | |
351 // all the sizes are larger than the max. | |
352 if (!current_candidate()) | |
353 return; | |
354 | |
355 if (current_candidate()->icon_type == favicon_base::FAVICON && | 387 if (current_candidate()->icon_type == favicon_base::FAVICON && |
356 !download_largest_icon_) { | 388 !download_largest_icon_) { |
357 if (!favicon_expired_or_incomplete_ && | 389 if (!favicon_expired_or_incomplete_ && |
358 driver_->GetActiveFaviconValidity() && | 390 driver_->GetActiveFaviconValidity() && |
359 DoUrlAndIconMatch(*current_candidate(), | 391 DoUrlAndIconMatch(*current_candidate(), |
360 driver_->GetActiveFaviconURL(), | 392 driver_->GetActiveFaviconURL(), |
361 favicon_base::FAVICON)) | 393 favicon_base::FAVICON)) |
362 return; | 394 return; |
363 } else if (!favicon_expired_or_incomplete_ && got_favicon_from_history_ && | 395 } else if (!favicon_expired_or_incomplete_ && got_favicon_from_history_ && |
364 HasValidResult(history_results_) && | 396 HasValidResult(history_results_) && |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 | 451 |
420 if (!image_skia.isNull()) { | 452 if (!image_skia.isNull()) { |
421 gfx::Image image(image_skia); | 453 gfx::Image image(image_skia); |
422 // The downloaded icon is still valid when there is no FaviconURL update | 454 // The downloaded icon is still valid when there is no FaviconURL update |
423 // during the downloading. | 455 // during the downloading. |
424 request_next_icon = !UpdateFaviconCandidate(image_url, image, score, | 456 request_next_icon = !UpdateFaviconCandidate(image_url, image, score, |
425 download_request.icon_type); | 457 download_request.icon_type); |
426 } | 458 } |
427 } | 459 } |
428 | 460 |
429 if (request_next_icon && image_urls_.size() > 1) { | 461 if (request_next_icon && current_candidate_index_ + 1 < image_urls_.size()) { |
430 // Remove the first member of image_urls_ and process the remaining. | 462 // Process the next candidate. |
431 image_urls_.erase(image_urls_.begin()); | 463 ++current_candidate_index_; |
432 ProcessCurrentUrl(); | 464 ProcessCurrentUrl(); |
433 } else { | 465 } else { |
434 // We have either found the ideal candidate or run out of candidates. | 466 // We have either found the ideal candidate or run out of candidates. |
435 if (best_favicon_candidate_.icon_type != favicon_base::INVALID_ICON) { | 467 if (best_favicon_candidate_.icon_type != favicon_base::INVALID_ICON) { |
436 // No more icons to request, set the favicon from the candidate. | 468 // No more icons to request, set the favicon from the candidate. |
437 SetFavicon(best_favicon_candidate_.image_url, | 469 SetFavicon(best_favicon_candidate_.image_url, |
438 best_favicon_candidate_.image, | 470 best_favicon_candidate_.image, |
439 best_favicon_candidate_.icon_type); | 471 best_favicon_candidate_.icon_type); |
440 } | 472 } |
441 // Clear download related state. | 473 // Clear download related state. |
442 image_urls_.clear(); | |
443 download_requests_.clear(); | 474 download_requests_.clear(); |
| 475 current_candidate_index_ = image_urls_.size(); |
444 best_favicon_candidate_ = FaviconCandidate(); | 476 best_favicon_candidate_ = FaviconCandidate(); |
445 } | 477 } |
446 } | 478 } |
447 | 479 |
448 bool FaviconHandler::HasPendingTasksForTest() { | 480 bool FaviconHandler::HasPendingTasksForTest() { |
449 return !download_requests_.empty() || | 481 return !download_requests_.empty() || |
450 cancelable_task_tracker_.HasTrackedTasks(); | 482 cancelable_task_tracker_.HasTrackedTasks(); |
451 } | 483 } |
452 | 484 |
453 int FaviconHandler::DownloadFavicon(const GURL& image_url, | 485 int FaviconHandler::DownloadFavicon(const GURL& image_url, |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 if (download_id == 0) { | 689 if (download_id == 0) { |
658 // If DownloadFavicon() did not start a download, it returns a download id | 690 // If DownloadFavicon() did not start a download, it returns a download id |
659 // of 0. We still need to call OnDidDownloadFavicon() because the method is | 691 // of 0. We still need to call OnDidDownloadFavicon() because the method is |
660 // responsible for initiating the data request for the next candidate. | 692 // responsible for initiating the data request for the next candidate. |
661 OnDidDownloadFavicon(download_id, image_url, std::vector<SkBitmap>(), | 693 OnDidDownloadFavicon(download_id, image_url, std::vector<SkBitmap>(), |
662 std::vector<gfx::Size>()); | 694 std::vector<gfx::Size>()); |
663 | 695 |
664 } | 696 } |
665 } | 697 } |
666 | 698 |
667 void FaviconHandler::SortAndPruneImageUrls() { | |
668 // Not using const-reference since the loop mutates FaviconURL::icon_sizes. | |
669 for (FaviconURL& image_url : image_urls_) { | |
670 if (image_url.icon_sizes.empty()) | |
671 continue; | |
672 | |
673 gfx::Size largest = | |
674 image_url.icon_sizes[GetLargestSizeIndex(image_url.icon_sizes)]; | |
675 image_url.icon_sizes.clear(); | |
676 image_url.icon_sizes.push_back(largest); | |
677 } | |
678 std::stable_sort(image_urls_.begin(), image_urls_.end(), | |
679 CompareIconSize); | |
680 } | |
681 | |
682 } // namespace favicon | 699 } // namespace favicon |
OLD | NEW |