| 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 <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 got_favicon_from_history_(false), | 191 got_favicon_from_history_(false), |
| 192 initial_history_result_expired_or_incomplete_(false), | 192 initial_history_result_expired_or_incomplete_(false), |
| 193 redownload_icons_(false), | 193 redownload_icons_(false), |
| 194 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)), | 194 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)), |
| 195 download_largest_icon_( | 195 download_largest_icon_( |
| 196 handler_type == FaviconDriverObserver::NON_TOUCH_LARGEST || | 196 handler_type == FaviconDriverObserver::NON_TOUCH_LARGEST || |
| 197 handler_type == FaviconDriverObserver::TOUCH_LARGEST), | 197 handler_type == FaviconDriverObserver::TOUCH_LARGEST), |
| 198 notification_icon_type_(favicon_base::INVALID_ICON), | 198 notification_icon_type_(favicon_base::INVALID_ICON), |
| 199 service_(service), | 199 service_(service), |
| 200 delegate_(delegate), | 200 delegate_(delegate), |
| 201 num_download_requests_(0), | 201 num_image_download_requests_(0), |
| 202 current_candidate_index_(0u) { | 202 current_candidate_index_(0u) { |
| 203 DCHECK(delegate_); | 203 DCHECK(delegate_); |
| 204 } | 204 } |
| 205 | 205 |
| 206 FaviconHandler::~FaviconHandler() { | 206 FaviconHandler::~FaviconHandler() { |
| 207 } | 207 } |
| 208 | 208 |
| 209 // static | 209 // static |
| 210 int FaviconHandler::GetIconTypesFromHandlerType( | 210 int FaviconHandler::GetIconTypesFromHandlerType( |
| 211 FaviconDriverObserver::NotificationIconType handler_type) { | 211 FaviconDriverObserver::NotificationIconType handler_type) { |
| 212 switch (handler_type) { | 212 switch (handler_type) { |
| 213 case FaviconDriverObserver::NON_TOUCH_16_DIP: | 213 case FaviconDriverObserver::NON_TOUCH_16_DIP: |
| 214 case FaviconDriverObserver::NON_TOUCH_LARGEST: | 214 case FaviconDriverObserver::NON_TOUCH_LARGEST: |
| 215 return favicon_base::FAVICON; | 215 return favicon_base::FAVICON; |
| 216 case FaviconDriverObserver::TOUCH_LARGEST: | 216 case FaviconDriverObserver::TOUCH_LARGEST: |
| 217 return favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON; | 217 return favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON; |
| 218 } | 218 } |
| 219 return 0; | 219 return 0; |
| 220 } | 220 } |
| 221 | 221 |
| 222 void FaviconHandler::FetchFavicon(const GURL& url) { | 222 void FaviconHandler::FetchFavicon(const GURL& url) { |
| 223 cancelable_task_tracker_for_page_url_.TryCancelAll(); | 223 cancelable_task_tracker_for_page_url_.TryCancelAll(); |
| 224 cancelable_task_tracker_for_candidates_.TryCancelAll(); | 224 cancelable_task_tracker_for_candidates_.TryCancelAll(); |
| 225 | 225 |
| 226 url_ = url; | 226 url_ = url; |
| 227 | 227 |
| 228 initial_history_result_expired_or_incomplete_ = false; | 228 initial_history_result_expired_or_incomplete_ = false; |
| 229 redownload_icons_ = false; | 229 redownload_icons_ = false; |
| 230 got_favicon_from_history_ = false; | 230 got_favicon_from_history_ = false; |
| 231 download_request_.Cancel(); | 231 image_download_request_.Cancel(); |
| 232 candidates_.clear(); | 232 candidates_.clear(); |
| 233 notification_icon_url_ = GURL(); | 233 notification_icon_url_ = GURL(); |
| 234 notification_icon_type_ = favicon_base::INVALID_ICON; | 234 notification_icon_type_ = favicon_base::INVALID_ICON; |
| 235 num_download_requests_ = 0; | 235 num_image_download_requests_ = 0; |
| 236 current_candidate_index_ = 0u; | 236 current_candidate_index_ = 0u; |
| 237 best_favicon_ = DownloadedFavicon(); | 237 best_favicon_ = DownloadedFavicon(); |
| 238 | 238 |
| 239 // Request the favicon from the history service. In parallel to this the | 239 // Request the favicon from the history service. In parallel to this the |
| 240 // renderer is going to notify us (well WebContents) when the favicon url is | 240 // renderer is going to notify us (well WebContents) when the favicon url is |
| 241 // available. | 241 // available. |
| 242 service_->GetFaviconForPageURL( | 242 service_->GetFaviconForPageURL( |
| 243 url_, icon_types_, preferred_icon_size(), | 243 url_, icon_types_, preferred_icon_size(), |
| 244 base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, | 244 base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, |
| 245 base::Unretained(this)), | 245 base::Unretained(this)), |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace); | 307 favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace); |
| 308 | 308 |
| 309 delegate_->OnFaviconUpdated(url_, handler_type_, icon_url, | 309 delegate_->OnFaviconUpdated(url_, handler_type_, icon_url, |
| 310 icon_url != notification_icon_url_, | 310 icon_url != notification_icon_url_, |
| 311 image_with_adjusted_colorspace); | 311 image_with_adjusted_colorspace); |
| 312 | 312 |
| 313 notification_icon_url_ = icon_url; | 313 notification_icon_url_ = icon_url; |
| 314 notification_icon_type_ = icon_type; | 314 notification_icon_type_ = icon_type; |
| 315 } | 315 } |
| 316 | 316 |
| 317 void FaviconHandler::OnUpdateFaviconURL( | 317 void FaviconHandler::OnUpdateCandidates( |
| 318 const GURL& page_url, | 318 const GURL& page_url, |
| 319 const std::vector<FaviconURL>& candidates) { | 319 const std::vector<FaviconURL>& candidates) { |
| 320 if (page_url != url_) | 320 if (page_url != url_) |
| 321 return; | 321 return; |
| 322 | 322 |
| 323 std::vector<FaviconCandidate> sorted_candidates; | 323 std::vector<FaviconCandidate> sorted_candidates; |
| 324 const std::vector<int> desired_pixel_sizes = | 324 const std::vector<int> desired_pixel_sizes = |
| 325 GetDesiredPixelSizes(handler_type_); | 325 GetDesiredPixelSizes(handler_type_); |
| 326 for (const FaviconURL& candidate : candidates) { | 326 for (const FaviconURL& candidate : candidates) { |
| 327 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) { | 327 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) { |
| 328 sorted_candidates.push_back( | 328 sorted_candidates.push_back( |
| 329 FaviconCandidate::FromFaviconURL(candidate, desired_pixel_sizes)); | 329 FaviconCandidate::FromFaviconURL(candidate, desired_pixel_sizes)); |
| 330 } | 330 } |
| 331 } | 331 } |
| 332 | 332 |
| 333 std::stable_sort(sorted_candidates.begin(), sorted_candidates.end(), | 333 std::stable_sort(sorted_candidates.begin(), sorted_candidates.end(), |
| 334 &FaviconCandidate::CompareScore); | 334 &FaviconCandidate::CompareScore); |
| 335 | 335 |
| 336 if (candidates_.size() == sorted_candidates.size() && | 336 if (candidates_.size() == sorted_candidates.size() && |
| 337 std::equal(sorted_candidates.begin(), sorted_candidates.end(), | 337 std::equal(sorted_candidates.begin(), sorted_candidates.end(), |
| 338 candidates_.begin())) { | 338 candidates_.begin())) { |
| 339 return; | 339 return; |
| 340 } | 340 } |
| 341 | 341 |
| 342 cancelable_task_tracker_for_candidates_.TryCancelAll(); | 342 cancelable_task_tracker_for_candidates_.TryCancelAll(); |
| 343 download_request_.Cancel(); | 343 image_download_request_.Cancel(); |
| 344 candidates_ = std::move(sorted_candidates); | 344 candidates_ = std::move(sorted_candidates); |
| 345 num_download_requests_ = 0; | 345 num_image_download_requests_ = 0; |
| 346 current_candidate_index_ = 0u; | 346 current_candidate_index_ = 0u; |
| 347 best_favicon_ = DownloadedFavicon(); | 347 best_favicon_ = DownloadedFavicon(); |
| 348 | 348 |
| 349 // TODO(davemoore) Should clear on empty url. Currently we ignore it. | 349 // TODO(davemoore) Should clear on empty url. Currently we ignore it. |
| 350 // This appears to be what FF does as well. | 350 // This appears to be what FF does as well. |
| 351 if (current_candidate() && got_favicon_from_history_) | 351 if (current_candidate() && got_favicon_from_history_) |
| 352 OnGotInitialHistoryDataAndIconURLCandidates(); | 352 OnGotInitialHistoryDataAndIconURLCandidates(); |
| 353 } | 353 } |
| 354 | 354 |
| 355 // static | 355 // static |
| (...skipping 24 matching lines...) Expand all Loading... |
| 380 } | 380 } |
| 381 | 381 |
| 382 void FaviconHandler::OnDidDownloadFavicon( | 382 void FaviconHandler::OnDidDownloadFavicon( |
| 383 favicon_base::IconType icon_type, | 383 favicon_base::IconType icon_type, |
| 384 int id, | 384 int id, |
| 385 int http_status_code, | 385 int http_status_code, |
| 386 const GURL& image_url, | 386 const GURL& image_url, |
| 387 const std::vector<SkBitmap>& bitmaps, | 387 const std::vector<SkBitmap>& bitmaps, |
| 388 const std::vector<gfx::Size>& original_bitmap_sizes) { | 388 const std::vector<gfx::Size>& original_bitmap_sizes) { |
| 389 // Mark download as finished. | 389 // Mark download as finished. |
| 390 download_request_.Cancel(); | 390 image_download_request_.Cancel(); |
| 391 | 391 |
| 392 if (bitmaps.empty() && http_status_code == 404) { | 392 if (bitmaps.empty() && http_status_code == 404) { |
| 393 DVLOG(1) << "Failed to Download Favicon:" << image_url; | 393 DVLOG(1) << "Failed to Download Favicon:" << image_url; |
| 394 RecordDownloadOutcome(DownloadOutcome::FAILED); | 394 RecordDownloadOutcome(DownloadOutcome::FAILED); |
| 395 service_->UnableToDownloadFavicon(image_url); | 395 service_->UnableToDownloadFavicon(image_url); |
| 396 } | 396 } |
| 397 | 397 |
| 398 bool request_next_icon = true; | 398 bool request_next_icon = true; |
| 399 if (!bitmaps.empty()) { | 399 if (!bitmaps.empty()) { |
| 400 RecordDownloadOutcome(DownloadOutcome::SUCCEEDED); | 400 RecordDownloadOutcome(DownloadOutcome::SUCCEEDED); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 426 request_next_icon = !UpdateFaviconCandidate(downloaded_favicon); | 426 request_next_icon = !UpdateFaviconCandidate(downloaded_favicon); |
| 427 } | 427 } |
| 428 } | 428 } |
| 429 | 429 |
| 430 if (request_next_icon && current_candidate_index_ + 1 < candidates_.size()) { | 430 if (request_next_icon && current_candidate_index_ + 1 < candidates_.size()) { |
| 431 // Process the next candidate. | 431 // Process the next candidate. |
| 432 ++current_candidate_index_; | 432 ++current_candidate_index_; |
| 433 DownloadCurrentCandidateOrAskFaviconService(); | 433 DownloadCurrentCandidateOrAskFaviconService(); |
| 434 } else { | 434 } else { |
| 435 // OnDidDownloadFavicon() can only be called after requesting a download, so | 435 // OnDidDownloadFavicon() can only be called after requesting a download, so |
| 436 // |num_download_requests_| can never be 0. | 436 // |num_image_download_requests_| can never be 0. |
| 437 RecordDownloadAttemptsForHandlerType(handler_type_, num_download_requests_); | 437 RecordDownloadAttemptsForHandlerType(handler_type_, |
| 438 num_image_download_requests_); |
| 438 // We have either found the ideal candidate or run out of candidates. | 439 // We have either found the ideal candidate or run out of candidates. |
| 439 if (best_favicon_.candidate.icon_type != favicon_base::INVALID_ICON) { | 440 if (best_favicon_.candidate.icon_type != favicon_base::INVALID_ICON) { |
| 440 // No more icons to request, set the favicon from the candidate. | 441 // No more icons to request, set the favicon from the candidate. |
| 441 SetFavicon(best_favicon_.candidate.icon_url, best_favicon_.image, | 442 SetFavicon(best_favicon_.candidate.icon_url, best_favicon_.image, |
| 442 best_favicon_.candidate.icon_type); | 443 best_favicon_.candidate.icon_type); |
| 443 } | 444 } |
| 444 // Clear download related state. | 445 // Clear download related state. |
| 445 current_candidate_index_ = candidates_.size(); | 446 current_candidate_index_ = candidates_.size(); |
| 446 num_download_requests_ = 0; | 447 num_image_download_requests_ = 0; |
| 447 best_favicon_ = DownloadedFavicon(); | 448 best_favicon_ = DownloadedFavicon(); |
| 448 } | 449 } |
| 449 } | 450 } |
| 450 | 451 |
| 451 const std::vector<GURL> FaviconHandler::GetIconURLs() const { | 452 const std::vector<GURL> FaviconHandler::GetIconURLs() const { |
| 452 std::vector<GURL> icon_urls; | 453 std::vector<GURL> icon_urls; |
| 453 for (const FaviconCandidate& candidate : candidates_) | 454 for (const FaviconCandidate& candidate : candidates_) |
| 454 icon_urls.push_back(candidate.icon_url); | 455 icon_urls.push_back(candidate.icon_url); |
| 455 return icon_urls; | 456 return icon_urls; |
| 456 } | 457 } |
| 457 | 458 |
| 458 bool FaviconHandler::HasPendingTasksForTest() { | 459 bool FaviconHandler::HasPendingTasksForTest() { |
| 459 return !download_request_.IsCancelled() || | 460 return !image_download_request_.IsCancelled() || |
| 460 cancelable_task_tracker_for_page_url_.HasTrackedTasks() || | 461 cancelable_task_tracker_for_page_url_.HasTrackedTasks() || |
| 461 cancelable_task_tracker_for_candidates_.HasTrackedTasks(); | 462 cancelable_task_tracker_for_candidates_.HasTrackedTasks(); |
| 462 } | 463 } |
| 463 | 464 |
| 464 bool FaviconHandler::ShouldSaveFavicon() { | 465 bool FaviconHandler::ShouldSaveFavicon() { |
| 465 if (!delegate_->IsOffTheRecord()) | 466 if (!delegate_->IsOffTheRecord()) |
| 466 return true; | 467 return true; |
| 467 | 468 |
| 468 // Always save favicon if the page is bookmarked. | 469 // Always save favicon if the page is bookmarked. |
| 469 return delegate_->IsBookmarked(url_); | 470 return delegate_->IsBookmarked(url_); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 495 if (current_candidate()) | 496 if (current_candidate()) |
| 496 OnGotInitialHistoryDataAndIconURLCandidates(); | 497 OnGotInitialHistoryDataAndIconURLCandidates(); |
| 497 } | 498 } |
| 498 | 499 |
| 499 void FaviconHandler::DownloadCurrentCandidateOrAskFaviconService() { | 500 void FaviconHandler::DownloadCurrentCandidateOrAskFaviconService() { |
| 500 GURL icon_url = current_candidate()->icon_url; | 501 GURL icon_url = current_candidate()->icon_url; |
| 501 favicon_base::IconType icon_type = current_candidate()->icon_type; | 502 favicon_base::IconType icon_type = current_candidate()->icon_type; |
| 502 | 503 |
| 503 if (redownload_icons_) { | 504 if (redownload_icons_) { |
| 504 // We have the mapping, but the favicon is out of date. Download it now. | 505 // We have the mapping, but the favicon is out of date. Download it now. |
| 505 ScheduleDownload(icon_url, icon_type); | 506 ScheduleImageDownload(icon_url, icon_type); |
| 506 } else { | 507 } else { |
| 507 // We don't know the favicon, but we may have previously downloaded the | 508 // We don't know the favicon, but we may have previously downloaded the |
| 508 // favicon for another page that shares the same favicon. Ask for the | 509 // favicon for another page that shares the same favicon. Ask for the |
| 509 // favicon given the favicon URL. | 510 // favicon given the favicon URL. |
| 510 if (delegate_->IsOffTheRecord()) { | 511 if (delegate_->IsOffTheRecord()) { |
| 511 service_->GetFavicon( | 512 service_->GetFavicon( |
| 512 icon_url, icon_type, preferred_icon_size(), | 513 icon_url, icon_type, preferred_icon_size(), |
| 513 base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)), | 514 base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)), |
| 514 &cancelable_task_tracker_for_candidates_); | 515 &cancelable_task_tracker_for_candidates_); |
| 515 } else { | 516 } else { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 535 | 536 |
| 536 if (has_valid_result) { | 537 if (has_valid_result) { |
| 537 // There is a valid favicon. Notify any observers. It is useful to notify | 538 // There is a valid favicon. Notify any observers. It is useful to notify |
| 538 // the observers even if the favicon is expired or incomplete (incorrect | 539 // the observers even if the favicon is expired or incomplete (incorrect |
| 539 // size) because temporarily showing the user an expired favicon or | 540 // size) because temporarily showing the user an expired favicon or |
| 540 // streched favicon is preferable to showing the user the default favicon. | 541 // streched favicon is preferable to showing the user the default favicon. |
| 541 NotifyFaviconUpdated(favicon_bitmap_results); | 542 NotifyFaviconUpdated(favicon_bitmap_results); |
| 542 } | 543 } |
| 543 | 544 |
| 544 if (has_expired_or_incomplete_result) { | 545 if (has_expired_or_incomplete_result) { |
| 545 ScheduleDownload(current_candidate()->icon_url, | 546 ScheduleImageDownload(current_candidate()->icon_url, |
| 546 current_candidate()->icon_type); | 547 current_candidate()->icon_type); |
| 547 } else if (num_download_requests_ > 0) { | 548 } else if (num_image_download_requests_ > 0) { |
| 548 RecordDownloadAttemptsForHandlerType(handler_type_, num_download_requests_); | 549 RecordDownloadAttemptsForHandlerType(handler_type_, |
| 550 num_image_download_requests_); |
| 549 } | 551 } |
| 550 } | 552 } |
| 551 | 553 |
| 552 void FaviconHandler::ScheduleDownload(const GURL& image_url, | 554 void FaviconHandler::ScheduleImageDownload(const GURL& image_url, |
| 553 favicon_base::IconType icon_type) { | 555 favicon_base::IconType icon_type) { |
| 554 DCHECK(image_url.is_valid()); | 556 DCHECK(image_url.is_valid()); |
| 555 // Note that CancelableCallback starts cancelled. | 557 // Note that CancelableCallback starts cancelled. |
| 556 DCHECK(download_request_.IsCancelled()) << "More than one ongoing download"; | 558 DCHECK(image_download_request_.IsCancelled()) |
| 559 << "More than one ongoing download"; |
| 557 if (service_->WasUnableToDownloadFavicon(image_url)) { | 560 if (service_->WasUnableToDownloadFavicon(image_url)) { |
| 558 DVLOG(1) << "Skip Failed FavIcon: " << image_url; | 561 DVLOG(1) << "Skip Failed FavIcon: " << image_url; |
| 559 RecordDownloadOutcome(DownloadOutcome::SKIPPED); | 562 RecordDownloadOutcome(DownloadOutcome::SKIPPED); |
| 560 OnDidDownloadFavicon(icon_type, 0, 0, image_url, std::vector<SkBitmap>(), | 563 OnDidDownloadFavicon(icon_type, 0, 0, image_url, std::vector<SkBitmap>(), |
| 561 std::vector<gfx::Size>()); | 564 std::vector<gfx::Size>()); |
| 562 return; | 565 return; |
| 563 } | 566 } |
| 564 ++num_download_requests_; | 567 ++num_image_download_requests_; |
| 565 download_request_.Reset(base::Bind(&FaviconHandler::OnDidDownloadFavicon, | 568 image_download_request_.Reset( |
| 566 base::Unretained(this), icon_type)); | 569 base::Bind(&FaviconHandler::OnDidDownloadFavicon, base::Unretained(this), |
| 570 icon_type)); |
| 567 // A max bitmap size is specified to avoid receiving huge bitmaps in | 571 // A max bitmap size is specified to avoid receiving huge bitmaps in |
| 568 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload() | 572 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload() |
| 569 // for more details about the max bitmap size. | 573 // for more details about the max bitmap size. |
| 570 const int download_id = | 574 const int download_id = |
| 571 delegate_->DownloadImage(image_url, GetMaximalIconSize(handler_type_), | 575 delegate_->DownloadImage(image_url, GetMaximalIconSize(handler_type_), |
| 572 download_request_.callback()); | 576 image_download_request_.callback()); |
| 573 DCHECK_NE(download_id, 0); | 577 DCHECK_NE(download_id, 0); |
| 574 } | 578 } |
| 575 | 579 |
| 576 } // namespace favicon | 580 } // namespace favicon |
| OLD | NEW |