| 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 |