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 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 } | 228 } |
229 return 0; | 229 return 0; |
230 } | 230 } |
231 | 231 |
232 void FaviconHandler::FetchFavicon(const GURL& url) { | 232 void FaviconHandler::FetchFavicon(const GURL& url) { |
233 cancelable_task_tracker_.TryCancelAll(); | 233 cancelable_task_tracker_.TryCancelAll(); |
234 | 234 |
235 url_ = url; | 235 url_ = url; |
236 | 236 |
237 favicon_expired_or_incomplete_ = got_favicon_from_history_ = false; | 237 favicon_expired_or_incomplete_ = got_favicon_from_history_ = false; |
| 238 download_requests_.clear(); |
238 image_urls_.clear(); | 239 image_urls_.clear(); |
| 240 history_results_.clear(); |
| 241 best_favicon_candidate_ = FaviconCandidate(); |
239 | 242 |
240 // Request the favicon from the history service. In parallel to this the | 243 // Request the favicon from the history service. In parallel to this the |
241 // renderer is going to notify us (well WebContents) when the favicon url is | 244 // renderer is going to notify us (well WebContents) when the favicon url is |
242 // available. | 245 // available. |
243 GetFaviconForURLFromFaviconService( | 246 GetFaviconForURLFromFaviconService( |
244 url_, icon_types_, | 247 url_, icon_types_, |
245 base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, | 248 base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, |
246 base::Unretained(this)), | 249 base::Unretained(this)), |
247 &cancelable_task_tracker_); | 250 &cancelable_task_tracker_); |
248 } | 251 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 return exact_match; | 294 return exact_match; |
292 } | 295 } |
293 | 296 |
294 void FaviconHandler::SetFavicon(const GURL& url, | 297 void FaviconHandler::SetFavicon(const GURL& url, |
295 const GURL& icon_url, | 298 const GURL& icon_url, |
296 const gfx::Image& image, | 299 const gfx::Image& image, |
297 favicon_base::IconType icon_type) { | 300 favicon_base::IconType icon_type) { |
298 if (ShouldSaveFavicon(url)) | 301 if (ShouldSaveFavicon(url)) |
299 SetHistoryFavicons(url, icon_url, icon_type, image); | 302 SetHistoryFavicons(url, icon_url, icon_type, image); |
300 | 303 |
301 if (!UrlMatches(url, url_) || PageChangedSinceFaviconWasRequested()) | 304 NotifyFaviconAvailable(icon_url, image); |
302 return; | |
303 | |
304 NotifyFaviconAvailable( | |
305 icon_url, | |
306 image, | |
307 icon_type == favicon_base::FAVICON && !download_largest_icon_); | |
308 } | 305 } |
309 | 306 |
310 void FaviconHandler::NotifyFaviconAvailable( | 307 void FaviconHandler::NotifyFaviconAvailable( |
311 const std::vector<favicon_base::FaviconRawBitmapResult>& | 308 const std::vector<favicon_base::FaviconRawBitmapResult>& |
312 favicon_bitmap_results, | 309 favicon_bitmap_results) { |
313 bool is_active_favicon) { | |
314 gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs( | 310 gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs( |
315 favicon_bitmap_results, | 311 favicon_bitmap_results, |
316 favicon_base::GetFaviconScales(), | 312 favicon_base::GetFaviconScales(), |
317 preferred_icon_size()); | 313 preferred_icon_size()); |
318 // The history service sends back results for a single icon URL, so it does | 314 // The history service sends back results for a single icon URL, so it does |
319 // not matter which result we get the |icon_url| from. | 315 // not matter which result we get the |icon_url| from. |
320 const GURL icon_url = favicon_bitmap_results.empty() ? | 316 const GURL icon_url = favicon_bitmap_results.empty() ? |
321 GURL() : favicon_bitmap_results[0].icon_url; | 317 GURL() : favicon_bitmap_results[0].icon_url; |
322 NotifyFaviconAvailable(icon_url, resized_image, is_active_favicon); | 318 NotifyFaviconAvailable(icon_url, resized_image); |
323 } | 319 } |
324 | 320 |
325 void FaviconHandler::NotifyFaviconAvailable(const GURL& icon_url, | 321 void FaviconHandler::NotifyFaviconAvailable(const GURL& icon_url, |
326 const gfx::Image& image, | 322 const gfx::Image& image) { |
327 bool is_active_favicon) { | |
328 gfx::Image image_with_adjusted_colorspace = image; | 323 gfx::Image image_with_adjusted_colorspace = image; |
329 favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace); | 324 favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace); |
330 | 325 |
| 326 bool is_active_favicon = |
| 327 (handler_type_ == FAVICON && !download_largest_icon_); |
| 328 |
331 driver_->OnFaviconAvailable( | 329 driver_->OnFaviconAvailable( |
332 image_with_adjusted_colorspace, icon_url, is_active_favicon); | 330 image_with_adjusted_colorspace, icon_url, is_active_favicon); |
333 } | 331 } |
334 | 332 |
335 void FaviconHandler::OnUpdateFaviconURL( | 333 void FaviconHandler::OnUpdateFaviconURL( |
336 const std::vector<FaviconURL>& candidates) { | 334 const std::vector<FaviconURL>& candidates) { |
| 335 download_requests_.clear(); |
337 image_urls_.clear(); | 336 image_urls_.clear(); |
338 best_favicon_candidate_ = FaviconCandidate(); | 337 best_favicon_candidate_ = FaviconCandidate(); |
| 338 |
339 for (const FaviconURL& candidate : candidates) { | 339 for (const FaviconURL& candidate : candidates) { |
340 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) | 340 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) |
341 image_urls_.push_back(candidate); | 341 image_urls_.push_back(candidate); |
342 } | 342 } |
343 | 343 |
344 if (download_largest_icon_) | 344 if (download_largest_icon_) |
345 SortAndPruneImageUrls(); | 345 SortAndPruneImageUrls(); |
346 | 346 |
347 // TODO(davemoore) Should clear on empty url. Currently we ignore it. | 347 // TODO(davemoore) Should clear on empty url. Currently we ignore it. |
348 // This appears to be what FF does as well. | 348 // This appears to be what FF does as well. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 DownloadRequests::iterator i = download_requests_.find(id); | 386 DownloadRequests::iterator i = download_requests_.find(id); |
387 if (i == download_requests_.end()) { | 387 if (i == download_requests_.end()) { |
388 // Currently WebContents notifies us of ANY downloads so that it is | 388 // Currently WebContents notifies us of ANY downloads so that it is |
389 // possible to get here. | 389 // possible to get here. |
390 return; | 390 return; |
391 } | 391 } |
392 | 392 |
393 DownloadRequest download_request = i->second; | 393 DownloadRequest download_request = i->second; |
394 download_requests_.erase(i); | 394 download_requests_.erase(i); |
395 | 395 |
396 if (current_candidate() && | 396 if (PageChangedSinceFaviconWasRequested() || |
397 DoUrlAndIconMatch(*current_candidate(), | 397 !current_candidate() || |
398 image_url, | 398 !DoUrlAndIconMatch(*current_candidate(), |
399 download_request.icon_type)) { | 399 image_url, |
400 bool request_next_icon = true; | 400 download_request.icon_type)) { |
| 401 return; |
| 402 } |
| 403 |
| 404 bool request_next_icon = true; |
| 405 if (!bitmaps.empty()) { |
401 float score = 0.0f; | 406 float score = 0.0f; |
402 gfx::ImageSkia image_skia; | 407 gfx::ImageSkia image_skia; |
403 if (download_largest_icon_ && !bitmaps.empty()) { | 408 if (download_largest_icon_) { |
404 int index = -1; | 409 int index = -1; |
405 // Use the largest bitmap if FaviconURL doesn't have sizes attribute. | 410 // Use the largest bitmap if FaviconURL doesn't have sizes attribute. |
406 if (current_candidate()->icon_sizes.empty()) { | 411 if (current_candidate()->icon_sizes.empty()) { |
407 index = GetLargestSizeIndex(original_bitmap_sizes); | 412 index = GetLargestSizeIndex(original_bitmap_sizes); |
408 } else { | 413 } else { |
409 index = GetIndexBySize(original_bitmap_sizes, | 414 index = GetIndexBySize(original_bitmap_sizes, |
410 current_candidate()->icon_sizes[0]); | 415 current_candidate()->icon_sizes[0]); |
411 // Find largest bitmap if there is no one exactly matched. | 416 // Find largest bitmap if there is no one exactly matched. |
412 if (index == -1) | 417 if (index == -1) |
413 index = GetLargestSizeIndex(original_bitmap_sizes); | 418 index = GetLargestSizeIndex(original_bitmap_sizes); |
414 } | 419 } |
415 image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1)); | 420 image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1)); |
416 } else { | 421 } else { |
417 image_skia = CreateFaviconImageSkia(bitmaps, | 422 image_skia = CreateFaviconImageSkia(bitmaps, |
418 original_bitmap_sizes, | 423 original_bitmap_sizes, |
419 preferred_icon_size(), | 424 preferred_icon_size(), |
420 &score); | 425 &score); |
421 } | 426 } |
422 | 427 |
423 if (!image_skia.isNull()) { | 428 if (!image_skia.isNull()) { |
424 gfx::Image image(image_skia); | 429 gfx::Image image(image_skia); |
425 // The downloaded icon is still valid when there is no FaviconURL update | 430 // The downloaded icon is still valid when there is no FaviconURL update |
426 // during the downloading. | 431 // during the downloading. |
427 if (!bitmaps.empty()) { | 432 request_next_icon = !UpdateFaviconCandidate( |
428 request_next_icon = !UpdateFaviconCandidate( | 433 download_request.url, image_url, image, score, |
429 download_request.url, image_url, image, score, | 434 download_request.icon_type); |
430 download_request.icon_type); | |
431 } | |
432 } | 435 } |
433 if (request_next_icon && !PageChangedSinceFaviconWasRequested() && | 436 } |
434 image_urls_.size() > 1) { | 437 |
435 // Remove the first member of image_urls_ and process the remaining. | 438 if (request_next_icon && image_urls_.size() > 1) { |
436 image_urls_.erase(image_urls_.begin()); | 439 // Remove the first member of image_urls_ and process the remaining. |
437 ProcessCurrentUrl(); | 440 image_urls_.erase(image_urls_.begin()); |
438 } else if (best_favicon_candidate_.icon_type != | 441 ProcessCurrentUrl(); |
439 favicon_base::INVALID_ICON) { | 442 } else if (best_favicon_candidate_.icon_type != favicon_base::INVALID_ICON) { |
440 // No more icons to request, set the favicon from the candidate. | 443 // No more icons to request, set the favicon from the candidate. |
441 SetFavicon(best_favicon_candidate_.url, | 444 SetFavicon(best_favicon_candidate_.url, |
442 best_favicon_candidate_.image_url, | 445 best_favicon_candidate_.image_url, |
443 best_favicon_candidate_.image, | 446 best_favicon_candidate_.image, |
444 best_favicon_candidate_.icon_type); | 447 best_favicon_candidate_.icon_type); |
445 // Reset candidate. | 448 // Reset candidate. |
446 image_urls_.clear(); | 449 image_urls_.clear(); |
447 download_requests_.clear(); | 450 download_requests_.clear(); |
448 best_favicon_candidate_ = FaviconCandidate(); | 451 best_favicon_candidate_ = FaviconCandidate(); |
449 } | |
450 } | 452 } |
451 } | 453 } |
452 | 454 |
453 bool FaviconHandler::HasPendingTasksForTest() { | 455 bool FaviconHandler::HasPendingTasksForTest() { |
454 return !download_requests_.empty() || | 456 return !download_requests_.empty() || |
455 cancelable_task_tracker_.HasTrackedTasks(); | 457 cancelable_task_tracker_.HasTrackedTasks(); |
456 } | 458 } |
457 | 459 |
458 bool FaviconHandler::PageChangedSinceFaviconWasRequested() { | 460 bool FaviconHandler::PageChangedSinceFaviconWasRequested() { |
459 if (UrlMatches(driver_->GetActiveURL(), url_) && url_.is_valid()) { | 461 if (UrlMatches(driver_->GetActiveURL(), url_) && url_.is_valid()) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 | 564 |
563 if (has_results && handler_type_ == FAVICON && | 565 if (has_results && handler_type_ == FAVICON && |
564 !download_largest_icon_ && !driver_->GetActiveFaviconValidity() && | 566 !download_largest_icon_ && !driver_->GetActiveFaviconValidity() && |
565 (!current_candidate() || | 567 (!current_candidate() || |
566 DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) { | 568 DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) { |
567 if (has_valid_result) { | 569 if (has_valid_result) { |
568 // The db knows the favicon (although it may be out of date) and the entry | 570 // The db knows the favicon (although it may be out of date) and the entry |
569 // doesn't have an icon. Set the favicon now, and if the favicon turns out | 571 // doesn't have an icon. Set the favicon now, and if the favicon turns out |
570 // to be expired (or the wrong url) we'll fetch later on. This way the | 572 // to be expired (or the wrong url) we'll fetch later on. This way the |
571 // user doesn't see a flash of the default favicon. | 573 // user doesn't see a flash of the default favicon. |
572 NotifyFaviconAvailable(favicon_bitmap_results, true); | 574 NotifyFaviconAvailable(favicon_bitmap_results); |
573 } else { | 575 } else { |
574 // If |favicon_bitmap_results| does not have any valid results, treat the | 576 // If |favicon_bitmap_results| does not have any valid results, treat the |
575 // favicon as if it's expired. | 577 // favicon as if it's expired. |
576 // TODO(pkotwicz): Do something better. | 578 // TODO(pkotwicz): Do something better. |
577 favicon_expired_or_incomplete_ = true; | 579 favicon_expired_or_incomplete_ = true; |
578 } | 580 } |
579 } | 581 } |
580 if (has_results && !favicon_expired_or_incomplete_) { | 582 if (has_results && !favicon_expired_or_incomplete_) { |
581 if (current_candidate() && | 583 if (current_candidate() && |
582 !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)) { | 584 !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)) { |
583 // Mapping in the database is wrong. DownloadFavIconOrAskHistory will | 585 // Mapping in the database is wrong. DownloadFavIconOrAskHistory will |
584 // update the mapping for this url and download the favicon if we don't | 586 // update the mapping for this url and download the favicon if we don't |
585 // already have it. | 587 // already have it. |
586 DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(), | 588 DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(), |
587 current_candidate()->icon_url, | 589 current_candidate()->icon_url, |
588 current_candidate()->icon_type); | 590 current_candidate()->icon_type); |
589 } | 591 } |
590 } else if (current_candidate()) { | 592 } else if (current_candidate()) { |
591 // We know the official url for the favicon, but either don't have the | 593 // We know the official url for the favicon, but either don't have the |
592 // favicon or it's expired. Continue on to DownloadFaviconOrAskHistory to | 594 // favicon or it's expired. Continue on to DownloadFaviconOrAskHistory to |
593 // either download or check history again. | 595 // either download or check history again. |
594 DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(), | 596 DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(), |
595 current_candidate()->icon_url, | 597 current_candidate()->icon_url, |
596 current_candidate()->icon_type); | 598 current_candidate()->icon_type); |
597 } | 599 } |
598 // else we haven't got the icon url. When we get it we'll ask the | 600 // else we haven't got the icon url. When we get it we'll ask the |
599 // renderer to download the icon. | 601 // renderer to download the icon. |
600 | 602 |
601 if (has_valid_result && (handler_type_ != FAVICON || download_largest_icon_)) | 603 if (has_valid_result && (handler_type_ != FAVICON || download_largest_icon_)) |
602 NotifyFaviconAvailable(favicon_bitmap_results, false); | 604 NotifyFaviconAvailable(favicon_bitmap_results); |
603 } | 605 } |
604 | 606 |
605 void FaviconHandler::DownloadFaviconOrAskFaviconService( | 607 void FaviconHandler::DownloadFaviconOrAskFaviconService( |
606 const GURL& page_url, | 608 const GURL& page_url, |
607 const GURL& icon_url, | 609 const GURL& icon_url, |
608 favicon_base::IconType icon_type) { | 610 favicon_base::IconType icon_type) { |
609 if (favicon_expired_or_incomplete_) { | 611 if (favicon_expired_or_incomplete_) { |
610 // We have the mapping, but the favicon is out of date. Download it now. | 612 // We have the mapping, but the favicon is out of date. Download it now. |
611 ScheduleDownload(page_url, icon_url, icon_type); | 613 ScheduleDownload(page_url, icon_url, icon_type); |
612 } else { | 614 } else { |
(...skipping 27 matching lines...) Expand all Loading... |
640 bool has_results = !favicon_bitmap_results.empty(); | 642 bool has_results = !favicon_bitmap_results.empty(); |
641 bool has_expired_or_incomplete_result = HasExpiredOrIncompleteResult( | 643 bool has_expired_or_incomplete_result = HasExpiredOrIncompleteResult( |
642 preferred_icon_size(), favicon_bitmap_results); | 644 preferred_icon_size(), favicon_bitmap_results); |
643 bool has_valid_result = HasValidResult(favicon_bitmap_results); | 645 bool has_valid_result = HasValidResult(favicon_bitmap_results); |
644 | 646 |
645 if (has_results && handler_type_ == FAVICON && !download_largest_icon_) { | 647 if (has_results && handler_type_ == FAVICON && !download_largest_icon_) { |
646 if (has_valid_result) { | 648 if (has_valid_result) { |
647 // There is a favicon, set it now. If expired we'll download the current | 649 // There is a favicon, set it now. If expired we'll download the current |
648 // one again, but at least the user will get some icon instead of the | 650 // one again, but at least the user will get some icon instead of the |
649 // default and most likely the current one is fine anyway. | 651 // default and most likely the current one is fine anyway. |
650 NotifyFaviconAvailable(favicon_bitmap_results, true); | 652 NotifyFaviconAvailable(favicon_bitmap_results); |
651 } | 653 } |
652 if (has_expired_or_incomplete_result) { | 654 if (has_expired_or_incomplete_result) { |
653 // The favicon is out of date. Request the current one. | 655 // The favicon is out of date. Request the current one. |
654 ScheduleDownload(driver_->GetActiveURL(), | 656 ScheduleDownload(driver_->GetActiveURL(), |
655 driver_->GetActiveFaviconURL(), | 657 driver_->GetActiveFaviconURL(), |
656 favicon_base::FAVICON); | 658 favicon_base::FAVICON); |
657 } | 659 } |
658 } else if (current_candidate() && | 660 } else if (current_candidate() && |
659 (!has_results || has_expired_or_incomplete_result || | 661 (!has_results || has_expired_or_incomplete_result || |
660 !(DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)))) { | 662 !(DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)))) { |
661 // We don't know the favicon, it is out of date or its type is not same as | 663 // We don't know the favicon, it is out of date or its type is not same as |
662 // one got from page. Request the current one. | 664 // one got from page. Request the current one. |
663 ScheduleDownload(driver_->GetActiveURL(), | 665 ScheduleDownload(driver_->GetActiveURL(), |
664 current_candidate()->icon_url, | 666 current_candidate()->icon_url, |
665 current_candidate()->icon_type); | 667 current_candidate()->icon_type); |
666 } | 668 } |
667 history_results_ = favicon_bitmap_results; | 669 history_results_ = favicon_bitmap_results; |
668 | 670 |
669 if (has_valid_result && | 671 if (has_valid_result && |
670 (handler_type_ != FAVICON || download_largest_icon_)) { | 672 (handler_type_ != FAVICON || download_largest_icon_)) { |
671 NotifyFaviconAvailable(favicon_bitmap_results, false); | 673 NotifyFaviconAvailable(favicon_bitmap_results); |
672 } | 674 } |
673 } | 675 } |
674 | 676 |
675 int FaviconHandler::ScheduleDownload(const GURL& url, | 677 void FaviconHandler::ScheduleDownload(const GURL& url, |
676 const GURL& image_url, | 678 const GURL& image_url, |
677 favicon_base::IconType icon_type) { | 679 favicon_base::IconType icon_type) { |
678 // A max bitmap size is specified to avoid receiving huge bitmaps in | 680 // A max bitmap size is specified to avoid receiving huge bitmaps in |
679 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload() | 681 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload() |
680 // for more details about the max bitmap size. | 682 // for more details about the max bitmap size. |
681 const int download_id = DownloadFavicon(image_url, | 683 const int download_id = DownloadFavicon(image_url, |
682 GetMaximalIconSize(icon_type)); | 684 GetMaximalIconSize(icon_type)); |
683 if (download_id) { | 685 if (download_id) { |
684 // Download ids should be unique. | 686 // Download ids should be unique. |
685 DCHECK(download_requests_.find(download_id) == download_requests_.end()); | 687 DCHECK(download_requests_.find(download_id) == download_requests_.end()); |
686 download_requests_[download_id] = | 688 download_requests_[download_id] = |
687 DownloadRequest(url, image_url, icon_type); | 689 DownloadRequest(url, image_url, icon_type); |
688 } | 690 } |
689 | |
690 return download_id; | |
691 } | 691 } |
692 | 692 |
693 void FaviconHandler::SortAndPruneImageUrls() { | 693 void FaviconHandler::SortAndPruneImageUrls() { |
694 // Not using const-reference since the loop mutates FaviconURL::icon_sizes. | 694 // Not using const-reference since the loop mutates FaviconURL::icon_sizes. |
695 for (FaviconURL& image_url : image_urls_) { | 695 for (FaviconURL& image_url : image_urls_) { |
696 if (image_url.icon_sizes.empty()) | 696 if (image_url.icon_sizes.empty()) |
697 continue; | 697 continue; |
698 | 698 |
699 gfx::Size largest = | 699 gfx::Size largest = |
700 image_url.icon_sizes[GetLargestSizeIndex(image_url.icon_sizes)]; | 700 image_url.icon_sizes[GetLargestSizeIndex(image_url.icon_sizes)]; |
701 image_url.icon_sizes.clear(); | 701 image_url.icon_sizes.clear(); |
702 image_url.icon_sizes.push_back(largest); | 702 image_url.icon_sizes.push_back(largest); |
703 } | 703 } |
704 std::stable_sort(image_urls_.begin(), image_urls_.end(), | 704 std::stable_sort(image_urls_.begin(), image_urls_.end(), |
705 CompareIconSize); | 705 CompareIconSize); |
706 } | 706 } |
707 | 707 |
708 } // namespace favicon | 708 } // namespace favicon |
OLD | NEW |