OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "chrome/browser/win/jumplist.h" | 5 #include "chrome/browser/win/jumplist.h" |
6 | 6 |
7 #include "base/base_paths.h" | 7 #include "base/base_paths.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 #include "url/gurl.h" | 54 #include "url/gurl.h" |
55 | 55 |
56 namespace { | 56 namespace { |
57 | 57 |
58 // The default maximum number of items to display in JumpList is 10. | 58 // The default maximum number of items to display in JumpList is 10. |
59 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx | 59 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx |
60 // The "Most visited" and "Recently closed" category titles always take 2 slots. | 60 // The "Most visited" and "Recently closed" category titles always take 2 slots. |
61 // For the remaining 8 slots, we allocate 5 slots to "most-visited" items and 3 | 61 // For the remaining 8 slots, we allocate 5 slots to "most-visited" items and 3 |
62 // slots to "recently-closed" items, respectively. | 62 // slots to "recently-closed" items, respectively. |
63 constexpr size_t kMostVisitedItems = 5; | 63 constexpr size_t kMostVisitedItems = 5; |
64 constexpr size_t kRecentlyClosedItems = 3; | 64 constexpr size_t kRecentClosedItems = 3; |
65 | 65 |
66 // The number of updates to skip to alleviate the machine when a previous update | 66 // The number of updates to skip to alleviate the machine when a previous update |
67 // was too slow. | 67 // was too slow. |
68 constexpr int kUpdatesToSkipUnderHeavyLoad = 10; | 68 constexpr int kUpdatesToSkipUnderHeavyLoad = 10; |
69 | 69 |
70 // The delay before updating the JumpList to prevent update storms. | 70 // The delay before updating the JumpList to prevent update storms. |
71 constexpr base::TimeDelta kDelayForJumplistUpdate = | 71 constexpr base::TimeDelta kDelayForJumplistUpdate = |
72 base::TimeDelta::FromMilliseconds(3500); | 72 base::TimeDelta::FromMilliseconds(3500); |
73 | 73 |
74 // The maximum allowed time for JumpListUpdater::BeginUpdate. Updates taking | 74 // The maximum allowed time for JumpListUpdater::BeginUpdate. Updates taking |
75 // longer than this are discarded to prevent bogging down slow machines. | 75 // longer than this are discarded to prevent bogging down slow machines. |
76 constexpr base::TimeDelta kTimeOutForJumplistBeginUpdate = | 76 constexpr base::TimeDelta kTimeOutForBeginUpdate = |
77 base::TimeDelta::FromMilliseconds(500); | 77 base::TimeDelta::FromMilliseconds(500); |
78 | 78 |
79 // The maximum allowed time for updating both "most visited" and "recently | 79 // The maximum allowed time for updating both "most visited" and "recently |
80 // closed" categories via JumpListUpdater::AddCustomCategory. | 80 // closed" categories via JumpListUpdater::AddCustomCategory. |
81 constexpr base::TimeDelta kTimeOutForAddCustomCategory = | 81 constexpr base::TimeDelta kTimeOutForAddCategory = |
82 base::TimeDelta::FromMilliseconds(500); | 82 base::TimeDelta::FromMilliseconds(500); |
83 | 83 |
84 // The maximum allowed time for JumpListUpdater::CommitUpdate. | 84 // The maximum allowed time for JumpListUpdater::CommitUpdate. |
85 constexpr base::TimeDelta kTimeOutForJumplistCommitUpdate = | 85 constexpr base::TimeDelta kTimeOutForCommitUpdate = |
86 base::TimeDelta::FromMilliseconds(1000); | 86 base::TimeDelta::FromMilliseconds(1000); |
87 | 87 |
88 // Appends the common switches to each shell link. | 88 // Appends the common switches to each shell link. |
89 void AppendCommonSwitches(ShellLinkItem* shell_link) { | 89 void AppendCommonSwitches(ShellLinkItem* shell_link) { |
90 const char* kSwitchNames[] = { switches::kUserDataDir }; | 90 const char* kSwitchNames[] = { switches::kUserDataDir }; |
91 const base::CommandLine& command_line = | 91 const base::CommandLine& command_line = |
92 *base::CommandLine::ForCurrentProcess(); | 92 *base::CommandLine::ForCurrentProcess(); |
93 shell_link->GetCommandLine()->CopySwitchesFrom(command_line, | 93 shell_link->GetCommandLine()->CopySwitchesFrom(command_line, |
94 kSwitchNames, | 94 kSwitchNames, |
95 arraysize(kSwitchNames)); | 95 arraysize(kSwitchNames)); |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
369 // * arguments | 369 // * arguments |
370 // The last URL of the tab object. | 370 // The last URL of the tab object. |
371 // * title | 371 // * title |
372 // The title of the last URL. | 372 // The title of the last URL. |
373 // * icon | 373 // * icon |
374 // An empty string. This value is to be updated in OnFaviconDataAvailable(). | 374 // An empty string. This value is to be updated in OnFaviconDataAvailable(). |
375 | 375 |
376 sessions::TabRestoreService* tab_restore_service = | 376 sessions::TabRestoreService* tab_restore_service = |
377 TabRestoreServiceFactory::GetForProfile(profile_); | 377 TabRestoreServiceFactory::GetForProfile(profile_); |
378 | 378 |
379 recently_closed_pages_.clear(); | 379 recent_closed_pages_.clear(); |
380 | 380 |
381 for (const auto& entry : tab_restore_service->entries()) { | 381 for (const auto& entry : tab_restore_service->entries()) { |
382 if (recently_closed_pages_.size() >= kRecentlyClosedItems) | 382 if (recent_closed_pages_.size() >= kRecentClosedItems) |
383 break; | 383 break; |
384 switch (entry->type) { | 384 switch (entry->type) { |
385 case sessions::TabRestoreService::TAB: | 385 case sessions::TabRestoreService::TAB: |
386 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), | 386 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), |
387 kRecentlyClosedItems); | 387 kRecentClosedItems); |
388 break; | 388 break; |
389 case sessions::TabRestoreService::WINDOW: | 389 case sessions::TabRestoreService::WINDOW: |
390 AddWindow( | 390 AddWindow( |
391 static_cast<const sessions::TabRestoreService::Window&>(*entry), | 391 static_cast<const sessions::TabRestoreService::Window&>(*entry), |
392 kRecentlyClosedItems); | 392 kRecentClosedItems); |
393 break; | 393 break; |
394 } | 394 } |
395 } | 395 } |
396 | 396 |
397 recently_closed_should_update_ = true; | 397 recent_closed_should_update_ = true; |
398 | 398 |
399 // Force a TopSite history sync when closing a first tab in one session. | 399 // Force a TopSite history sync when closing a first tab in one session. |
400 if (!has_tab_closed_) { | 400 if (!has_tab_closed_) { |
401 has_tab_closed_ = true; | 401 has_tab_closed_ = true; |
402 scoped_refptr<history::TopSites> top_sites = | 402 scoped_refptr<history::TopSites> top_sites = |
403 TopSitesFactory::GetForProfile(profile_); | 403 TopSitesFactory::GetForProfile(profile_); |
404 if (top_sites) | 404 if (top_sites) |
405 top_sites->SyncWithHistory(); | 405 top_sites->SyncWithHistory(); |
406 } | 406 } |
407 } | 407 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
440 // Send a query that retrieves the first favicon. | 440 // Send a query that retrieves the first favicon. |
441 StartLoadingFavicon(); | 441 StartLoadingFavicon(); |
442 } | 442 } |
443 | 443 |
444 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, | 444 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, |
445 size_t max_items) { | 445 size_t max_items) { |
446 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 446 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
447 | 447 |
448 // This code adds the URL and the title strings of the given tab to the | 448 // This code adds the URL and the title strings of the given tab to the |
449 // JumpList variables. | 449 // JumpList variables. |
450 if (recently_closed_pages_.size() >= max_items) | 450 if (recent_closed_pages_.size() >= max_items) |
451 return false; | 451 return false; |
452 | 452 |
453 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 453 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
454 const sessions::SerializedNavigationEntry& current_navigation = | 454 const sessions::SerializedNavigationEntry& current_navigation = |
455 tab.navigations.at(tab.current_navigation_index); | 455 tab.navigations.at(tab.current_navigation_index); |
456 std::string url = current_navigation.virtual_url().spec(); | 456 std::string url = current_navigation.virtual_url().spec(); |
457 link->GetCommandLine()->AppendArgNative(base::UTF8ToUTF16(url)); | 457 link->GetCommandLine()->AppendArgNative(base::UTF8ToUTF16(url)); |
458 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, | 458 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, |
459 jumplist::kRecentlyClosedCategory); | 459 jumplist::kRecentlyClosedCategory); |
460 link->set_title(current_navigation.title()); | 460 link->set_title(current_navigation.title()); |
461 link->set_url(url); | 461 link->set_url(url); |
462 recently_closed_pages_.push_back(link); | 462 recent_closed_pages_.push_back(link); |
463 if (recently_closed_icons_.find(url) == recently_closed_icons_.end()) | 463 if (recent_closed_icons_.find(url) == recent_closed_icons_.end()) |
464 icon_urls_.emplace_back(std::move(url), std::move(link)); | 464 icon_urls_.emplace_back(std::move(url), std::move(link)); |
465 | 465 |
466 return true; | 466 return true; |
467 } | 467 } |
468 | 468 |
469 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, | 469 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, |
470 size_t max_items) { | 470 size_t max_items) { |
471 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 471 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
472 DCHECK(!window.tabs.empty()); | 472 DCHECK(!window.tabs.empty()); |
473 | 473 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
544 update_in_progress_ = true; | 544 update_in_progress_ = true; |
545 | 545 |
546 base::FilePath profile_dir = profile_->GetPath(); | 546 base::FilePath profile_dir = profile_->GetPath(); |
547 | 547 |
548 // Check if incognito windows (or normal windows) are disabled by policy. | 548 // Check if incognito windows (or normal windows) are disabled by policy. |
549 IncognitoModePrefs::Availability incognito_availability = | 549 IncognitoModePrefs::Availability incognito_availability = |
550 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); | 550 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); |
551 | 551 |
552 // Make local copies of JumpList member variables and use them for an update. | 552 // Make local copies of JumpList member variables and use them for an update. |
553 ShellLinkItemList local_most_visited_pages = most_visited_pages_; | 553 ShellLinkItemList local_most_visited_pages = most_visited_pages_; |
554 ShellLinkItemList local_recently_closed_pages = recently_closed_pages_; | 554 ShellLinkItemList local_recent_closed_pages = recent_closed_pages_; |
555 | |
556 bool most_visited_should_update = most_visited_should_update_; | |
557 bool recently_closed_should_update = recently_closed_should_update_; | |
558 | 555 |
559 auto update_results = base::MakeUnique<UpdateResults>(); | 556 auto update_results = base::MakeUnique<UpdateResults>(); |
grt (UTC plus 2)
2017/06/20 10:29:18
meta comment: this object does more than just carr
chengx
2017/06/20 19:33:59
The two lists above, i.e., *_pages_, are not updat
grt (UTC plus 2)
2017/06/21 10:57:29
So they're in-out params, yes? I can see how they
chengx
2017/06/22 22:45:06
Yes, they're in-out params. I've renamed the enum
| |
560 update_results->most_visited_icons_in_update = most_visited_icons_; | 557 update_results->most_visited_icons = most_visited_icons_; |
561 update_results->recently_closed_icons_in_update = recently_closed_icons_; | 558 update_results->recent_closed_icons = recent_closed_icons_; |
559 update_results->most_visited_icon_assoc = most_visited_icon_assoc_; | |
560 update_results->recent_closed_icon_assoc = recent_closed_icon_assoc_; | |
561 update_results->most_visited_should_update = most_visited_should_update_; | |
562 update_results->recent_closed_should_update = recent_closed_should_update_; | |
562 | 563 |
563 // Parameter evaluation order is unspecified in C++. Ensure the pointer value | 564 // Parameter evaluation order is unspecified in C++. Ensure the pointer value |
564 // is obtained before base::Passed() is called. | 565 // is obtained before base::Passed() is called. |
565 auto* update_results_raw = update_results.get(); | 566 auto* update_results_raw = update_results.get(); |
566 | 567 |
567 // Post a task to update the JumpList, which consists of 1) create new icons, | 568 // Post a task to update the JumpList, which consists of 1) create new icons, |
568 // 2) delete old icons, 3) notify the OS. | 569 // 2) notify the OS, 3) delete old icons. |
569 if (!update_jumplist_task_runner_->PostTaskAndReply( | 570 if (!update_jumplist_task_runner_->PostTaskAndReply( |
570 FROM_HERE, | 571 FROM_HERE, |
571 base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir, | 572 base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir, |
572 local_most_visited_pages, local_recently_closed_pages, | 573 local_most_visited_pages, local_recent_closed_pages, |
573 most_visited_should_update, recently_closed_should_update, | |
574 incognito_availability, update_results_raw), | 574 incognito_availability, update_results_raw), |
575 base::Bind(&JumpList::OnRunUpdateCompletion, | 575 base::Bind(&JumpList::OnRunUpdateCompletion, |
576 weak_ptr_factory_.GetWeakPtr(), | 576 weak_ptr_factory_.GetWeakPtr(), |
577 base::Passed(std::move(update_results))))) { | 577 base::Passed(std::move(update_results))))) { |
578 OnRunUpdateCompletion(base::MakeUnique<UpdateResults>()); | 578 OnRunUpdateCompletion(base::MakeUnique<UpdateResults>()); |
579 } | 579 } |
580 } | 580 } |
581 | 581 |
582 void JumpList::OnRunUpdateCompletion( | 582 void JumpList::OnRunUpdateCompletion( |
583 std::unique_ptr<UpdateResults> update_results) { | 583 std::unique_ptr<UpdateResults> update_results) { |
584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
585 | 585 |
586 // Update JumpList member variables based on the results from the update run | 586 // Update JumpList member variables based on the results from the update run |
587 // just finished. | 587 // just finished. |
588 if (update_results->update_timeout) | 588 if (update_results->update_timeout) |
589 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; | 589 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; |
590 | 590 |
591 if (update_results->update_success) { | 591 if (update_results->update_success) { |
592 most_visited_icons_.swap(update_results->most_visited_icons_in_update); | 592 if (update_results->most_visited_should_update) { |
593 recently_closed_icons_.swap( | 593 most_visited_icons_.swap(update_results->most_visited_icons); |
594 update_results->recently_closed_icons_in_update); | 594 most_visited_icon_assoc_.swap(update_results->most_visited_icon_assoc); |
595 most_visited_should_update_ = false; | 595 most_visited_should_update_ = false; |
596 recently_closed_should_update_ = false; | 596 } |
597 if (update_results->recent_closed_should_update) { | |
598 recent_closed_icons_.swap(update_results->recent_closed_icons); | |
599 recent_closed_icon_assoc_.swap(update_results->recent_closed_icon_assoc); | |
600 recent_closed_should_update_ = false; | |
601 } | |
597 } | 602 } |
598 | 603 |
599 update_in_progress_ = false; | 604 update_in_progress_ = false; |
600 | 605 |
601 // If there is any new notification during the update run just finished, start | 606 // If there is any new notification during the update run just finished, start |
602 // another JumpList update. | 607 // another JumpList update. |
603 // Otherwise, post tasks to delete the JumpListIcons and JumpListIconsOld | 608 // Otherwise, post tasks to delete the JumpListIcons and JumpListIconsOld |
604 // folders as they are no longer needed. Now we have the | 609 // folders as they are no longer needed. Now we have the |
605 // JumpListIcons{MostVisited, RecentClosed} folders instead. | 610 // JumpListIcons{MostVisited, RecentClosed} folders instead. |
606 if (top_sites_has_pending_notification_ || | 611 if (top_sites_has_pending_notification_ || |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
652 pref_change_registrar_.reset(); | 657 pref_change_registrar_.reset(); |
653 } | 658 } |
654 profile_ = nullptr; | 659 profile_ = nullptr; |
655 } | 660 } |
656 | 661 |
657 // static | 662 // static |
658 void JumpList::RunUpdateJumpList( | 663 void JumpList::RunUpdateJumpList( |
659 const base::string16& app_id, | 664 const base::string16& app_id, |
660 const base::FilePath& profile_dir, | 665 const base::FilePath& profile_dir, |
661 const ShellLinkItemList& most_visited_pages, | 666 const ShellLinkItemList& most_visited_pages, |
662 const ShellLinkItemList& recently_closed_pages, | 667 const ShellLinkItemList& recent_closed_pages, |
663 bool most_visited_should_update, | |
664 bool recently_closed_should_update, | |
665 IncognitoModePrefs::Availability incognito_availability, | 668 IncognitoModePrefs::Availability incognito_availability, |
666 UpdateResults* update_results) { | 669 UpdateResults* update_results) { |
667 if (!JumpListUpdater::IsEnabled()) | 670 if (!JumpListUpdater::IsEnabled()) |
668 return; | 671 return; |
669 | 672 |
670 DCHECK(update_results); | 673 DCHECK(update_results); |
671 | 674 |
672 JumpListUpdater jumplist_updater(app_id); | 675 JumpListUpdater jumplist_updater(app_id); |
673 | 676 |
674 base::ElapsedTimer begin_update_timer; | 677 base::ElapsedTimer begin_update_timer; |
675 | 678 |
676 if (!jumplist_updater.BeginUpdate()) | 679 if (!jumplist_updater.BeginUpdate()) |
677 return; | 680 return; |
678 | 681 |
679 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer | 682 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer |
680 // than the maximum allowed time, as it's very likely the following update | 683 // than the maximum allowed time, as it's very likely the following update |
681 // steps will also take a long time. As we've not updated the icons on the | 684 // steps will also take a long time. As we've not updated the icons on the |
682 // disk, discarding this update wont't affect the current JumpList used by OS. | 685 // disk, discarding this update wont't affect the current JumpList used by OS. |
683 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) { | 686 if (begin_update_timer.Elapsed() >= kTimeOutForBeginUpdate) { |
684 update_results->update_timeout = true; | 687 update_results->update_timeout = true; |
685 return; | 688 return; |
686 } | 689 } |
687 | 690 |
688 // Record the desired number of icons created in this JumpList update. | 691 // Record the desired number of icons created in this JumpList update. |
689 int icons_created = 0; | 692 int icons_created = 0; |
690 | 693 |
694 URLIconCache most_visited_icons_next; | |
695 URLIconCache recent_closed_icons_next; | |
696 | |
697 base::FilePath most_visited_icon_dir = GenerateJumplistIconDirName( | |
698 profile_dir, FILE_PATH_LITERAL("MostVisited")); | |
699 base::FilePath recent_closed_icon_dir = GenerateJumplistIconDirName( | |
700 profile_dir, FILE_PATH_LITERAL("RecentClosed")); | |
701 | |
691 // Update the icons for "Most Visisted" category of the JumpList if needed. | 702 // Update the icons for "Most Visisted" category of the JumpList if needed. |
692 if (most_visited_should_update) { | 703 if (update_results->most_visited_should_update) { |
693 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName( | 704 icons_created += SafeCreateIconFiles( |
694 profile_dir, FILE_PATH_LITERAL("MostVisited")); | 705 most_visited_icon_dir, most_visited_pages, kMostVisitedItems, |
695 | 706 &update_results->most_visited_icon_assoc, |
696 icons_created += UpdateIconFiles( | 707 &update_results->most_visited_icons, &most_visited_icons_next); |
697 icon_dir_most_visited, most_visited_pages, kMostVisitedItems, | |
698 &update_results->most_visited_icons_in_update); | |
699 } | 708 } |
700 | 709 |
701 // Update the icons for "Recently Closed" category of the JumpList if needed. | 710 // Update the icons for "Recently Closed" category of the JumpList if needed. |
702 if (recently_closed_should_update) { | 711 if (update_results->recent_closed_should_update) { |
703 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName( | 712 icons_created += SafeCreateIconFiles( |
704 profile_dir, FILE_PATH_LITERAL("RecentClosed")); | 713 recent_closed_icon_dir, recent_closed_pages, kRecentClosedItems, |
705 | 714 &update_results->recent_closed_icon_assoc, |
706 icons_created += UpdateIconFiles( | 715 &update_results->recent_closed_icons, &recent_closed_icons_next); |
707 icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems, | |
708 &update_results->recently_closed_icons_in_update); | |
709 } | 716 } |
710 | 717 |
711 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 718 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
712 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created); | 719 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created); |
713 | 720 |
714 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 721 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
715 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); | 722 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); |
716 | 723 |
717 base::ElapsedTimer add_custom_category_timer; | 724 base::ElapsedTimer add_custom_category_timer; |
718 | 725 |
719 // Update the "Most Visited" category of the JumpList if it exists. | 726 // Update the JumpList categories. This update request is applied into the |
720 // This update request is applied into the JumpList when we commit this | 727 // JumpList when we commit this transaction. |
721 // transaction. | 728 bool add_category_success = |
722 if (!jumplist_updater.AddCustomCategory( | 729 jumplist_updater.AddCustomCategory( |
723 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), | 730 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), |
724 most_visited_pages, kMostVisitedItems)) { | 731 most_visited_pages, kMostVisitedItems) && |
732 jumplist_updater.AddCustomCategory( | |
733 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recent_closed_pages, | |
734 kRecentClosedItems); | |
735 | |
736 // If AddCustomCategory call takes longer than the maximum allowed time, abort | |
737 // the current update and skip the next |kUpdatesToSkipUnderHeavyLoad| | |
738 // updates. | |
739 bool timeout = add_custom_category_timer.Elapsed() >= kTimeOutForAddCategory; | |
740 if (timeout) | |
741 update_results->update_timeout = true; | |
742 | |
743 if (!add_category_success || timeout) { | |
744 DeleteIconFilesUnified(most_visited_icon_dir, recent_closed_icon_dir, | |
745 update_results, JumpListVersion::kNext); | |
725 return; | 746 return; |
726 } | 747 } |
727 | 748 |
728 // Update the "Recently Closed" category of the JumpList. | 749 // Update the "Tasks" category of the JumpList. |
729 if (!jumplist_updater.AddCustomCategory( | 750 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) { |
730 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages, | 751 DeleteIconFilesUnified(most_visited_icon_dir, recent_closed_icon_dir, |
731 kRecentlyClosedItems)) { | 752 update_results, JumpListVersion::kNext); |
732 return; | 753 return; |
733 } | 754 } |
734 | 755 |
735 // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate | |
736 // takes longer than the maximum allowed time, skip the next | |
737 // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished | |
738 // because we've already updated the icons on the disk. If discarding this | |
739 // update from here, some items in the current JumpList may not have icons | |
740 // as they've been delete from the disk. In this case, the background color of | |
741 // the JumpList panel is used instead, which doesn't look nice. | |
742 | |
743 if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) | |
744 update_results->update_timeout = true; | |
745 | |
746 // Update the "Tasks" category of the JumpList. | |
747 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) | |
748 return; | |
749 | |
750 base::ElapsedTimer commit_update_timer; | 756 base::ElapsedTimer commit_update_timer; |
751 | 757 |
752 // Commit this transaction and send the updated JumpList to Windows. | 758 // Commit this transaction and send the updated JumpList to Windows. |
753 if (jumplist_updater.CommitUpdate()) | 759 bool commit_success = jumplist_updater.CommitUpdate(); |
760 | |
761 // If CommitUpdate call takes longer than the maximum allowed time, abort the | |
762 // current update and skip the next |kUpdatesToSkipUnderHeavyLoad| updates. | |
763 if (commit_update_timer.Elapsed() >= kTimeOutForCommitUpdate) | |
764 update_results->update_timeout = true; | |
765 | |
766 if (commit_success) { | |
754 update_results->update_success = true; | 767 update_results->update_success = true; |
768 if (update_results->most_visited_should_update) | |
769 update_results->most_visited_icons.swap(most_visited_icons_next); | |
770 if (update_results->recent_closed_should_update) | |
771 update_results->recent_closed_icons.swap(recent_closed_icons_next); | |
772 } | |
755 | 773 |
756 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) | 774 // Delete the set of icons based on commit status. |
757 update_results->update_timeout = true; | 775 JumpListVersion version = |
776 commit_success ? JumpListVersion::kCurrent : JumpListVersion::kNext; | |
777 | |
778 DeleteIconFilesUnified(most_visited_icon_dir, recent_closed_icon_dir, | |
779 update_results, version); | |
758 } | 780 } |
759 | 781 |
760 // static | 782 // static |
761 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, | 783 int JumpList::SafeCreateIconFiles(const base::FilePath& icon_dir, |
762 const ShellLinkItemList& page_list, | 784 const ShellLinkItemList& page_list, |
763 size_t slot_limit, | 785 size_t slot_limit, |
764 URLIconCache* icon_cache) { | 786 IconAssociation* icon_assoc, |
787 URLIconCache* icon_cur, | |
788 URLIconCache* icon_next) { | |
789 DCHECK(icon_assoc); | |
790 DCHECK(icon_cur); | |
791 DCHECK(icon_next); | |
792 | |
765 int icons_created = 0; | 793 int icons_created = 0; |
766 | 794 |
767 // Clear the JumpList icon folder at |icon_dir| and the cache when | 795 // Clear the JumpList icon folder at |icon_dir| and the caches when |
768 // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently | 796 // 1) |icon_cur| is empty. This happens when "Most visited" or "Recently |
769 // closed" category updates for the 1st time after Chrome is launched. | 797 // closed" category updates for the 1st time after Chrome is launched. |
770 // 2) The number of icons in |icon_dir| has exceeded the limit. | 798 // 2) The number of icons in |icon_dir| has exceeded the limit. |
771 if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) { | 799 if (icon_cur->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) { |
772 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); | 800 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); |
773 icon_cache->clear(); | 801 icon_assoc->clear(); |
802 icon_cur->clear(); | |
803 icon_next->clear(); | |
804 | |
774 // Create new icons only when the directory exists and is empty. | 805 // Create new icons only when the directory exists and is empty. |
775 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) | 806 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) { |
776 icons_created += | 807 icons_created += CreateIconFiles(icon_dir, page_list, slot_limit, |
777 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); | 808 icon_assoc, icon_cur, icon_next); |
809 } | |
778 } else if (base::CreateDirectory(icon_dir)) { | 810 } else if (base::CreateDirectory(icon_dir)) { |
779 icons_created += | 811 icons_created += CreateIconFiles(icon_dir, page_list, slot_limit, |
780 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); | 812 icon_assoc, icon_cur, icon_next); |
781 DeleteIconFiles(icon_dir, icon_cache); | |
782 } | 813 } |
783 | 814 |
784 return icons_created; | 815 return icons_created; |
785 } | 816 } |
786 | 817 |
787 // static | 818 // static |
788 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, | 819 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, |
789 const ShellLinkItemList& item_list, | 820 const ShellLinkItemList& item_list, |
790 size_t max_items, | 821 size_t max_items, |
791 URLIconCache* icon_cache) { | 822 IconAssociation* icon_assoc, |
823 URLIconCache* icon_cur, | |
824 URLIconCache* icon_next) { | |
825 DCHECK(icon_assoc); | |
826 DCHECK(icon_cur); | |
827 DCHECK(icon_next); | |
828 | |
792 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 829 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
793 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); | 830 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); |
794 | 831 |
795 int icons_created = 0; | 832 int icons_created = 0; |
796 | 833 |
834 // Mark all the icons kCurrent as they are used by the current JumpList. | |
835 for (auto iter = icon_assoc->begin(); iter != icon_assoc->end(); ++iter) | |
836 iter->second = JumpListVersion::kCurrent; | |
837 | |
797 // Reuse icons for urls that already present in the current JumpList. | 838 // Reuse icons for urls that already present in the current JumpList. |
798 URLIconCache updated_map; | |
799 for (ShellLinkItemList::const_iterator iter = item_list.begin(); | 839 for (ShellLinkItemList::const_iterator iter = item_list.begin(); |
800 iter != item_list.end() && max_items > 0; ++iter, --max_items) { | 840 iter != item_list.end() && max_items > 0; ++iter, --max_items) { |
801 ShellLinkItem* item = iter->get(); | 841 ShellLinkItem* item = iter->get(); |
802 auto cache_iter = icon_cache->find(item->url()); | 842 auto cache_iter = icon_cur->find(item->url()); |
803 if (cache_iter != icon_cache->end()) { | 843 if (cache_iter != icon_cur->end()) { |
804 item->set_icon(cache_iter->second.value(), 0); | 844 item->set_icon(cache_iter->second.value(), 0); |
805 updated_map[item->url()] = cache_iter->second; | 845 (*icon_next)[item->url()] = cache_iter->second; |
846 (*icon_assoc)[cache_iter->second] = JumpListVersion::kShared; | |
806 } else { | 847 } else { |
807 base::FilePath icon_path; | 848 base::FilePath icon_path; |
808 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { | 849 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { |
809 ++icons_created; | 850 ++icons_created; |
810 item->set_icon(icon_path.value(), 0); | 851 item->set_icon(icon_path.value(), 0); |
811 updated_map[item->url()] = icon_path; | 852 (*icon_next)[item->url()] = icon_path; |
853 (*icon_assoc)[icon_path] = JumpListVersion::kNext; | |
812 } | 854 } |
813 } | 855 } |
814 } | 856 } |
815 icon_cache->swap(updated_map); | |
816 | 857 |
817 return icons_created; | 858 return icons_created; |
818 } | 859 } |
819 | 860 |
820 // static | 861 // static |
862 void JumpList::DeleteIconFilesUnified( | |
863 const base::FilePath& most_visited_icon_dir, | |
864 const base::FilePath& recent_closed_icon_dir, | |
865 UpdateResults* update_results, | |
866 JumpListVersion version) { | |
867 DCHECK(update_results); | |
868 | |
869 if (update_results->most_visited_should_update) { | |
870 DeleteIconFiles(most_visited_icon_dir, | |
871 &update_results->most_visited_icon_assoc, version); | |
872 } | |
873 if (update_results->recent_closed_should_update) { | |
874 DeleteIconFiles(recent_closed_icon_dir, | |
875 &update_results->recent_closed_icon_assoc, version); | |
876 } | |
877 } | |
878 | |
879 // static | |
821 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, | 880 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, |
822 URLIconCache* icon_cache) { | 881 IconAssociation* icon_assoc, |
823 // Put all cached icon file paths into a set. | 882 JumpListVersion version) { |
883 DCHECK(icon_assoc); | |
884 | |
885 IconAssociation icon_assoc_updated; | |
886 | |
887 // Put paths of icon files to keep into a set. | |
824 base::flat_set<base::FilePath> cached_files; | 888 base::flat_set<base::FilePath> cached_files; |
825 cached_files.reserve(icon_cache->size()); | 889 cached_files.reserve(icon_assoc->size()); |
826 | 890 for (const auto& path_version_pair : *icon_assoc) { |
827 for (const auto& url_path_pair : *icon_cache) | 891 if (path_version_pair.second != version) { |
828 cached_files.insert(url_path_pair.second); | 892 cached_files.insert(path_version_pair.first); |
893 icon_assoc_updated[path_version_pair.first] = path_version_pair.second; | |
894 } | |
895 } | |
829 | 896 |
830 DeleteNonCachedFiles(icon_dir, cached_files); | 897 DeleteNonCachedFiles(icon_dir, cached_files); |
898 | |
899 // Keep icon_assoc up-to-date after deleting obsolete icons. | |
900 icon_assoc->swap(icon_assoc_updated); | |
831 } | 901 } |
OLD | NEW |