| Index: chrome/browser/sessions/persistent_tab_restore_service.cc
|
| diff --git a/chrome/browser/sessions/tab_restore_service.cc b/chrome/browser/sessions/persistent_tab_restore_service.cc
|
| similarity index 50%
|
| copy from chrome/browser/sessions/tab_restore_service.cc
|
| copy to chrome/browser/sessions/persistent_tab_restore_service.cc
|
| index 4003edb3ad7f707fa978dfab25a33896f38fcf50..357964762037202a6fc537b139a07e5fac6c50fa 100644
|
| --- a/chrome/browser/sessions/tab_restore_service.cc
|
| +++ b/chrome/browser/sessions/persistent_tab_restore_service.cc
|
| @@ -2,69 +2,85 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "chrome/browser/sessions/tab_restore_service.h"
|
| +#include "chrome/browser/sessions/persistent_tab_restore_service.h"
|
|
|
| -#include <algorithm>
|
| -#include <iterator>
|
| -#include <map>
|
| +#include <cstring> // memcpy
|
| +#include <vector>
|
|
|
| +#include "base/basictypes.h"
|
| #include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/callback.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/file_path.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/ref_counted.h"
|
| #include "base/memory/scoped_vector.h"
|
| -#include "base/metrics/histogram.h"
|
| #include "base/stl_util.h"
|
| -#include "chrome/browser/extensions/extension_service.h"
|
| -#include "chrome/browser/extensions/tab_helper.h"
|
| +#include "base/time.h"
|
| +#include "chrome/browser/common/cancelable_request.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/sessions/base_session_service.h"
|
| #include "chrome/browser/sessions/session_command.h"
|
| #include "chrome/browser/sessions/session_service.h"
|
| #include "chrome/browser/sessions/session_service_factory.h"
|
| -#include "chrome/browser/sessions/session_types.h"
|
| -#include "chrome/browser/sessions/tab_restore_service_delegate.h"
|
| -#include "chrome/browser/sessions/tab_restore_service_observer.h"
|
| -#include "chrome/browser/ui/tab_contents/tab_contents.h"
|
| -#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
|
| -#include "chrome/common/extensions/extension.h"
|
| -#include "chrome/common/extensions/extension_constants.h"
|
| -#include "chrome/common/url_constants.h"
|
| -#include "content/public/browser/navigation_controller.h"
|
| -#include "content/public/browser/navigation_entry.h"
|
| -#include "content/public/browser/web_contents.h"
|
| +#include "chrome/browser/sessions/tab_restore_service_factory.h"
|
| +#include "content/public/browser/session_storage_namespace.h"
|
|
|
| -using base::Time;
|
| -using content::NavigationController;
|
| -using content::NavigationEntry;
|
| -using content::WebContents;
|
| +namespace {
|
| +
|
| +// Only written if the tab is pinned.
|
| +typedef bool PinnedStatePayload;
|
| +
|
| +typedef int32 RestoredEntryPayload;
|
|
|
| -// TimeFactory-----------------------------------------------------------------
|
| +typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry;
|
|
|
| -TabRestoreService::TimeFactory::~TimeFactory() {}
|
| +// Payload used for the start of a tab close. This is the old struct that is
|
| +// used for backwards compat when it comes to reading the session files.
|
| +struct SelectedNavigationInTabPayload {
|
| + SessionID::id_type id;
|
| + int32 index;
|
| +};
|
|
|
| -// Entry ----------------------------------------------------------------------
|
| +// Payload used for the start of a window close. This is the old struct that is
|
| +// used for backwards compat when it comes to reading the session files. This
|
| +// struct must be POD, because we memset the contents.
|
| +struct WindowPayload {
|
| + SessionID::id_type window_id;
|
| + int32 selected_tab_index;
|
| + int32 num_tabs;
|
| +};
|
|
|
| -// ID of the next Entry.
|
| -static SessionID::id_type next_entry_id = 1;
|
| +// Payload used for the start of a window close. This struct must be POD,
|
| +// because we memset the contents.
|
| +struct WindowPayload2 : WindowPayload {
|
| + int64 timestamp;
|
| +};
|
|
|
| -TabRestoreService::Entry::Entry()
|
| - : id(next_entry_id++),
|
| - type(TAB),
|
| - from_last_session(false) {}
|
| +// Payload used for the start of a tab close.
|
| +struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload {
|
| + int64 timestamp;
|
| +};
|
|
|
| -TabRestoreService::Entry::Entry(Type type)
|
| - : id(next_entry_id++),
|
| - type(type),
|
| - from_last_session(false) {}
|
| +// Used to indicate what has loaded.
|
| +enum LoadState {
|
| + // Indicates we haven't loaded anything.
|
| + NOT_LOADED = 1 << 0,
|
|
|
| -TabRestoreService::Entry::~Entry() {}
|
| + // Indicates we've asked for the last sessions and tabs but haven't gotten the
|
| + // result back yet.
|
| + LOADING = 1 << 2,
|
|
|
| -// TabRestoreService ----------------------------------------------------------
|
| + // Indicates we finished loading the last tabs (but not necessarily the last
|
| + // session).
|
| + LOADED_LAST_TABS = 1 << 3,
|
|
|
| -// static
|
| -const size_t TabRestoreService::kMaxEntries = 25;
|
| + // Indicates we finished loading the last session (but not necessarily the
|
| + // last tabs).
|
| + LOADED_LAST_SESSION = 1 << 4
|
| +};
|
|
|
| -// Identifier for commands written to file.
|
| -// The ordering in the file is as follows:
|
| +// Identifier for commands written to file. The ordering in the file is as
|
| +// follows:
|
| // . When the user closes a tab a command of type
|
| // kCommandSelectedNavigationInTab is written identifying the tab and
|
| // the selected index, then a kCommandPinnedState command if the tab was
|
| @@ -77,212 +93,206 @@ const size_t TabRestoreService::kMaxEntries = 25;
|
| // described).
|
| // . When the user restores an entry a command of type kCommandRestoredEntry
|
| // is written.
|
| -static const SessionCommand::id_type kCommandUpdateTabNavigation = 1;
|
| -static const SessionCommand::id_type kCommandRestoredEntry = 2;
|
| -static const SessionCommand::id_type kCommandWindow = 3;
|
| -static const SessionCommand::id_type kCommandSelectedNavigationInTab = 4;
|
| -static const SessionCommand::id_type kCommandPinnedState = 5;
|
| -static const SessionCommand::id_type kCommandSetExtensionAppID = 6;
|
| -static const SessionCommand::id_type kCommandSetWindowAppName = 7;
|
| -static const SessionCommand::id_type kCommandSetTabUserAgentOverride = 8;
|
| +const SessionCommand::id_type kCommandUpdateTabNavigation = 1;
|
| +const SessionCommand::id_type kCommandRestoredEntry = 2;
|
| +const SessionCommand::id_type kCommandWindow = 3;
|
| +const SessionCommand::id_type kCommandSelectedNavigationInTab = 4;
|
| +const SessionCommand::id_type kCommandPinnedState = 5;
|
| +const SessionCommand::id_type kCommandSetExtensionAppID = 6;
|
| +const SessionCommand::id_type kCommandSetWindowAppName = 7;
|
| +const SessionCommand::id_type kCommandSetTabUserAgentOverride = 8;
|
|
|
| // Number of entries (not commands) before we clobber the file and write
|
| // everything.
|
| -static const int kEntriesPerReset = 40;
|
| +const int kEntriesPerReset = 40;
|
|
|
| -namespace {
|
| +const size_t kMaxEntries = TabRestoreServiceHelper::kMaxEntries;
|
|
|
| -// Payload structures.
|
| +} // namespace
|
|
|
| -typedef int32 RestoredEntryPayload;
|
| +// PersistentTabRestoreService::Delegate ---------------------------------------
|
| +
|
| +// Implements the link between the tab restore service and the session backend.
|
| +class PersistentTabRestoreService::Delegate
|
| + : public BaseSessionService,
|
| + public TabRestoreServiceHelper::Observer {
|
| + public:
|
| + explicit Delegate(Profile* profile);
|
| +
|
| + virtual ~Delegate();
|
| +
|
| + // BaseSessionService:
|
| + virtual void Save() OVERRIDE;
|
| +
|
| + // TabRestoreServiceHelper::Observer:
|
| + virtual void OnClearEntries() OVERRIDE;
|
| + virtual void OnRestoreEntryById(
|
| + SessionID::id_type id,
|
| + Entries::const_iterator entry_iterator) OVERRIDE;
|
| + virtual void OnAddEntry() OVERRIDE;
|
| +
|
| + void set_tab_restore_service_helper(
|
| + TabRestoreServiceHelper* tab_restore_service_helper) {
|
| + tab_restore_service_helper_ = tab_restore_service_helper;
|
| + }
|
|
|
| -// Payload used for the start of a window close. This is the old struct that is
|
| -// used for backwards compat when it comes to reading the session files. This
|
| -// struct must be POD, because we memset the contents.
|
| -struct WindowPayload {
|
| - SessionID::id_type window_id;
|
| - int32 selected_tab_index;
|
| - int32 num_tabs;
|
| -};
|
| + void LoadTabsFromLastSession();
|
| +
|
| + bool IsLoaded() const;
|
|
|
| -// Payload used for the start of a tab close. This is the old struct that is
|
| -// used for backwards compat when it comes to reading the session files.
|
| -struct SelectedNavigationInTabPayload {
|
| - SessionID::id_type id;
|
| - int32 index;
|
| -};
|
| + // Creates and add entries to |entries| for each of the windows in |windows|.
|
| + static void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows,
|
| + std::vector<Entry*>* entries);
|
|
|
| -// Payload used for the start of a window close. This struct must be POD,
|
| -// because we memset the contents.
|
| -struct WindowPayload2 : WindowPayload {
|
| - int64 timestamp;
|
| -};
|
| + void Shutdown();
|
|
|
| -// Payload used for the start of a tab close.
|
| -struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload {
|
| - int64 timestamp;
|
| -};
|
| + // Schedules the commands for a window close.
|
| + void ScheduleCommandsForWindow(const Window& window);
|
|
|
| -// Only written if the tab is pinned.
|
| -typedef bool PinnedStatePayload;
|
| + // Schedules the commands for a tab close. |selected_index| gives the index of
|
| + // the selected navigation.
|
| + void ScheduleCommandsForTab(const Tab& tab, int selected_index);
|
|
|
| -typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry;
|
| + // Creates a window close command.
|
| + static SessionCommand* CreateWindowCommand(SessionID::id_type id,
|
| + int selected_tab_index,
|
| + int num_tabs,
|
| + base::Time timestamp);
|
|
|
| -// If |id_to_entry| contains an entry for |id| the corresponding entry is
|
| -// deleted and removed from both |id_to_entry| and |entries|. This is used
|
| -// when creating entries from the backend file.
|
| -void RemoveEntryByID(SessionID::id_type id,
|
| - IDToEntry* id_to_entry,
|
| - std::vector<TabRestoreService::Entry*>* entries) {
|
| - // Look for the entry in the map. If it is present, erase it from both
|
| - // collections and return.
|
| - IDToEntry::iterator i = id_to_entry->find(id);
|
| - if (i != id_to_entry->end()) {
|
| - entries->erase(std::find(entries->begin(), entries->end(), i->second));
|
| - delete i->second;
|
| - id_to_entry->erase(i);
|
| - return;
|
| - }
|
| + // Creates a tab close command.
|
| + static SessionCommand* CreateSelectedNavigationInTabCommand(
|
| + SessionID::id_type tab_id,
|
| + int32 index,
|
| + base::Time timestamp);
|
|
|
| - // Otherwise, loop over all items in the map and see if any of the Windows
|
| - // have Tabs with the |id|.
|
| - for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end();
|
| - ++i) {
|
| - if (i->second->type == TabRestoreService::WINDOW) {
|
| - TabRestoreService::Window* window =
|
| - static_cast<TabRestoreService::Window*>(i->second);
|
| - std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin();
|
| - for ( ; j != window->tabs.end(); ++j) {
|
| - // If the ID matches one of this window's tabs, remove it from the list.
|
| - if ((*j).id == id) {
|
| - window->tabs.erase(j);
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -}
|
| + // Creates a restore command.
|
| + static SessionCommand* CreateRestoredEntryCommand(
|
| + SessionID::id_type entry_id);
|
|
|
| -void RecordAppLaunch(Profile* profile, const TabRestoreService::Tab& tab) {
|
| - GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url();
|
| - DCHECK(profile->GetExtensionService());
|
| - if (!profile->GetExtensionService()->IsInstalledApp(url))
|
| - return;
|
| + // Returns the index to persist as the selected index. This is the same as
|
| + // |tab.current_navigation_index| unless the entry at
|
| + // |tab.current_navigation_index| shouldn't be persisted. Returns -1 if no
|
| + // valid navigation to persist.
|
| + int GetSelectedNavigationIndexToPersist(const Tab& tab);
|
|
|
| - AppLauncherHandler::RecordAppLaunchType(
|
| - extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED);
|
| -}
|
| + // Invoked when we've loaded the session commands that identify the previously
|
| + // closed tabs. This creates entries, adds them to staging_entries_, and
|
| + // invokes LoadState.
|
| + void OnGotLastSessionCommands(
|
| + Handle handle,
|
| + scoped_refptr<InternalGetCommandsRequest> request);
|
|
|
| -} // namespace
|
| + // Populates |loaded_entries| with Entries from |request|.
|
| + void CreateEntriesFromCommands(
|
| + scoped_refptr<InternalGetCommandsRequest> request,
|
| + std::vector<Entry*>* loaded_entries);
|
|
|
| -TabRestoreService::Tab::Tab()
|
| - : Entry(TAB),
|
| - current_navigation_index(-1),
|
| - browser_id(0),
|
| - tabstrip_index(-1),
|
| - pinned(false) {
|
| -}
|
| + // Validates all entries in |entries|, deleting any with no navigations. This
|
| + // also deletes any entries beyond the max number of entries we can hold.
|
| + static void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries);
|
|
|
| -TabRestoreService::Tab::~Tab() {
|
| -}
|
| + // Callback from SessionService when we've received the windows from the
|
| + // previous session. This creates and add entries to |staging_entries_| and
|
| + // invokes LoadStateChanged. |ignored_active_window| is ignored because we
|
| + // don't need to restore activation.
|
| + void OnGotPreviousSession(Handle handle,
|
| + std::vector<SessionWindow*>* windows,
|
| + SessionID::id_type ignored_active_window);
|
|
|
| -TabRestoreService::Window::Window() : Entry(WINDOW), selected_tab_index(-1) {
|
| -}
|
| + // Converts a SessionWindow into a Window, returning true on success. We use 0
|
| + // as the timestamp here since we do not know when the window/tab was closed.
|
| + static bool ConvertSessionWindowToWindow(SessionWindow* session_window,
|
| + Window* window);
|
|
|
| -TabRestoreService::Window::~Window() {
|
| -}
|
| + // Invoked when previous tabs or session is loaded. If both have finished
|
| + // loading the entries in |staging_entries_| are added to entries and
|
| + // observers are notified.
|
| + void LoadStateChanged();
|
| +
|
| + // If |id_to_entry| contains an entry for |id| the corresponding entry is
|
| + // deleted and removed from both |id_to_entry| and |entries|. This is used
|
| + // when creating entries from the backend file.
|
| + void RemoveEntryByID(SessionID::id_type id,
|
| + IDToEntry* id_to_entry,
|
| + std::vector<TabRestoreService::Entry*>* entries);
|
| +
|
| + private:
|
| + TabRestoreServiceHelper* tab_restore_service_helper_;
|
|
|
| -TabRestoreService::TabRestoreService(Profile* profile,
|
| - TabRestoreService::TimeFactory* time_factory)
|
| + // The number of entries to write.
|
| + int entries_to_write_;
|
| +
|
| + // Number of entries we've written.
|
| + int entries_written_;
|
| +
|
| + // Whether we've loaded the last session.
|
| + int load_state_;
|
| +
|
| + // Results from previously closed tabs/sessions is first added here. When the
|
| + // results from both us and the session restore service have finished loading
|
| + // LoadStateChanged is invoked, which adds these entries to entries_.
|
| + std::vector<Entry*> staging_entries_;
|
| +
|
| + // Used when loading previous tabs/session.
|
| + CancelableRequestConsumer load_consumer_;
|
| +
|
| + // Used when loading open tabs/session when recovering from a crash.
|
| + CancelableRequestConsumer crash_consumer_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Delegate);
|
| +};
|
| +
|
| +PersistentTabRestoreService::Delegate::Delegate(Profile* profile)
|
| : BaseSessionService(BaseSessionService::TAB_RESTORE, profile,
|
| FilePath()),
|
| - load_state_(NOT_LOADED),
|
| - restoring_(false),
|
| + tab_restore_service_helper_(NULL),
|
| entries_to_write_(0),
|
| entries_written_(0),
|
| - time_factory_(time_factory) {
|
| + load_state_(NOT_LOADED) {
|
| }
|
|
|
| -TabRestoreService::~TabRestoreService() {
|
| - FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
|
| - TabRestoreServiceDestroyed(this));
|
| - STLDeleteElements(&entries_);
|
| +PersistentTabRestoreService::Delegate::~Delegate() {
|
| STLDeleteElements(&staging_entries_);
|
| - time_factory_ = NULL;
|
| -}
|
| -
|
| -void TabRestoreService::AddObserver(TabRestoreServiceObserver* observer) {
|
| - observer_list_.AddObserver(observer);
|
| -}
|
| -
|
| -void TabRestoreService::RemoveObserver(TabRestoreServiceObserver* observer) {
|
| - observer_list_.RemoveObserver(observer);
|
| -}
|
| -
|
| -void TabRestoreService::CreateHistoricalTab(content::WebContents* contents,
|
| - int index) {
|
| - if (restoring_)
|
| - return;
|
| -
|
| - TabRestoreServiceDelegate* delegate =
|
| - TabRestoreServiceDelegate::FindDelegateForWebContents(contents);
|
| - if (closing_delegates_.find(delegate) != closing_delegates_.end())
|
| - return;
|
| -
|
| - scoped_ptr<Tab> local_tab(new Tab());
|
| - PopulateTab(local_tab.get(), index, delegate, &contents->GetController());
|
| - if (local_tab->navigations.empty())
|
| - return;
|
| -
|
| - AddEntry(local_tab.release(), true, true);
|
| }
|
|
|
| -void TabRestoreService::BrowserClosing(TabRestoreServiceDelegate* delegate) {
|
| - closing_delegates_.insert(delegate);
|
| -
|
| - scoped_ptr<Window> window(new Window());
|
| - window->selected_tab_index = delegate->GetSelectedIndex();
|
| - window->timestamp = TimeNow();
|
| - window->app_name = delegate->GetAppName();
|
| -
|
| - // Don't use std::vector::resize() because it will push copies of an empty tab
|
| - // into the vector, which will give all tabs in a window the same ID.
|
| - for (int i = 0; i < delegate->GetTabCount(); ++i) {
|
| - window->tabs.push_back(Tab());
|
| +void PersistentTabRestoreService::Delegate::Save() {
|
| + const Entries& entries = tab_restore_service_helper_->entries();
|
| + int to_write_count = std::min(entries_to_write_,
|
| + static_cast<int>(entries.size()));
|
| + entries_to_write_ = 0;
|
| + if (entries_written_ + to_write_count > kEntriesPerReset) {
|
| + to_write_count = entries.size();
|
| + set_pending_reset(true);
|
| }
|
| - size_t entry_index = 0;
|
| - for (int tab_index = 0; tab_index < delegate->GetTabCount(); ++tab_index) {
|
| - PopulateTab(&(window->tabs[entry_index]),
|
| - tab_index,
|
| - delegate,
|
| - &delegate->GetWebContentsAt(tab_index)->GetController());
|
| - if (window->tabs[entry_index].navigations.empty()) {
|
| - window->tabs.erase(window->tabs.begin() + entry_index);
|
| - } else {
|
| - window->tabs[entry_index].browser_id = delegate->GetSessionID().id();
|
| - entry_index++;
|
| + if (to_write_count) {
|
| + // Write the to_write_count most recently added entries out. The most
|
| + // recently added entry is at the front, so we use a reverse iterator to
|
| + // write in the order the entries were added.
|
| + Entries::const_reverse_iterator i = entries.rbegin();
|
| + DCHECK(static_cast<size_t>(to_write_count) <= entries.size());
|
| + std::advance(i, entries.size() - static_cast<int>(to_write_count));
|
| + for (; i != entries.rend(); ++i) {
|
| + Entry* entry = *i;
|
| + if (entry->type == TAB) {
|
| + Tab* tab = static_cast<Tab*>(entry);
|
| + int selected_index = GetSelectedNavigationIndexToPersist(*tab);
|
| + if (selected_index != -1)
|
| + ScheduleCommandsForTab(*tab, selected_index);
|
| + } else {
|
| + ScheduleCommandsForWindow(*static_cast<Window*>(entry));
|
| + }
|
| + entries_written_++;
|
| }
|
| }
|
| - if (window->tabs.size() == 1 && window->app_name.empty()) {
|
| - // Short-circuit creating a Window if only 1 tab was present. This fixes
|
| - // http://crbug.com/56744. Copy the Tab because it's owned by an object on
|
| - // the stack.
|
| - AddEntry(new Tab(window->tabs[0]), true, true);
|
| - } else if (!window->tabs.empty()) {
|
| - window->selected_tab_index =
|
| - std::min(static_cast<int>(window->tabs.size() - 1),
|
| - window->selected_tab_index);
|
| - AddEntry(window.release(), true, true);
|
| - }
|
| -}
|
| -
|
| -void TabRestoreService::BrowserClosed(TabRestoreServiceDelegate* delegate) {
|
| - closing_delegates_.erase(delegate);
|
| + if (pending_reset())
|
| + entries_written_ = 0;
|
| + BaseSessionService::Save();
|
| }
|
|
|
| -void TabRestoreService::ClearEntries() {
|
| +void PersistentTabRestoreService::Delegate::OnClearEntries() {
|
| // Mark all the tabs as closed so that we don't attempt to restore them.
|
| - for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i)
|
| + const Entries& entries = tab_restore_service_helper_->entries();
|
| + for (Entries::const_iterator i = entries.begin(); i != entries.end(); ++i)
|
| ScheduleCommand(CreateRestoredEntryCommand((*i)->id));
|
|
|
| entries_to_write_ = 0;
|
| @@ -293,153 +303,31 @@ void TabRestoreService::ClearEntries() {
|
| // Schedule a command, otherwise if there are no pending commands Save does
|
| // nothing.
|
| ScheduleCommand(CreateRestoredEntryCommand(1));
|
| -
|
| - STLDeleteElements(&entries_);
|
| - NotifyTabsChanged();
|
| -}
|
| -
|
| -const TabRestoreService::Entries& TabRestoreService::entries() const {
|
| - return entries_;
|
| -}
|
| -
|
| -void TabRestoreService::RestoreMostRecentEntry(
|
| - TabRestoreServiceDelegate* delegate) {
|
| - if (entries_.empty())
|
| - return;
|
| -
|
| - RestoreEntryById(delegate, entries_.front()->id, UNKNOWN);
|
| }
|
|
|
| -TabRestoreService::Tab* TabRestoreService::RemoveTabEntryById(
|
| - SessionID::id_type id) {
|
| - Entries::iterator i = GetEntryIteratorById(id);
|
| - if (i == entries_.end())
|
| - return NULL;
|
| -
|
| - Entry* entry = *i;
|
| - if (entry->type != TAB)
|
| - return NULL;
|
| -
|
| - Tab* tab = static_cast<Tab*>(entry);
|
| - entries_.erase(i);
|
| - return tab;
|
| -}
|
| -
|
| -void TabRestoreService::RestoreEntryById(TabRestoreServiceDelegate* delegate,
|
| - SessionID::id_type id,
|
| - WindowOpenDisposition disposition) {
|
| - Entries::iterator i = GetEntryIteratorById(id);
|
| - if (i == entries_.end()) {
|
| - // Don't hoark here, we allow an invalid id.
|
| - return;
|
| - }
|
| -
|
| +void PersistentTabRestoreService::Delegate::OnRestoreEntryById(
|
| + SessionID::id_type id,
|
| + Entries::const_iterator entry_iterator) {
|
| size_t index = 0;
|
| - for (Entries::iterator j = entries_.begin(); j != i && j != entries_.end();
|
| + const Entries& entries = tab_restore_service_helper_->entries();
|
| + for (Entries::const_iterator j = entries.begin();
|
| + j != entry_iterator && j != entries.end();
|
| ++j, ++index) {}
|
| if (static_cast<int>(index) < entries_to_write_)
|
| entries_to_write_--;
|
|
|
| ScheduleCommand(CreateRestoredEntryCommand(id));
|
| +}
|
|
|
| - restoring_ = true;
|
| - Entry* entry = *i;
|
| -
|
| - // If the entry's ID does not match the ID that is being restored, then the
|
| - // entry is a window from which a single tab will be restored.
|
| - bool restoring_tab_in_window = entry->id != id;
|
| -
|
| - if (!restoring_tab_in_window) {
|
| - entries_.erase(i);
|
| - i = entries_.end();
|
| - }
|
| -
|
| - // |delegate| will be NULL in cases where one isn't already available (eg,
|
| - // when invoked on Mac OS X with no windows open). In this case, create a
|
| - // new browser into which we restore the tabs.
|
| - if (entry->type == TAB) {
|
| - Tab* tab = static_cast<Tab*>(entry);
|
| - delegate = RestoreTab(*tab, delegate, disposition);
|
| - delegate->ShowBrowserWindow();
|
| - } else if (entry->type == WINDOW) {
|
| - TabRestoreServiceDelegate* current_delegate = delegate;
|
| - Window* window = static_cast<Window*>(entry);
|
| -
|
| - // When restoring a window, either the entire window can be restored, or a
|
| - // single tab within it. If the entry's ID matches the one to restore, then
|
| - // the entire window will be restored.
|
| - if (!restoring_tab_in_window) {
|
| - delegate = TabRestoreServiceDelegate::Create(profile(), window->app_name);
|
| - for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) {
|
| - const Tab& tab = window->tabs[tab_i];
|
| - WebContents* restored_tab =
|
| - delegate->AddRestoredTab(tab.navigations, delegate->GetTabCount(),
|
| - tab.current_navigation_index,
|
| - tab.extension_app_id,
|
| - static_cast<int>(tab_i) ==
|
| - window->selected_tab_index,
|
| - tab.pinned, tab.from_last_session,
|
| - tab.session_storage_namespace,
|
| - tab.user_agent_override);
|
| - if (restored_tab) {
|
| - restored_tab->GetController().LoadIfNecessary();
|
| - RecordAppLaunch(profile(), tab);
|
| - }
|
| - }
|
| - // All the window's tabs had the same former browser_id.
|
| - if (window->tabs[0].has_browser()) {
|
| - UpdateTabBrowserIDs(window->tabs[0].browser_id,
|
| - delegate->GetSessionID().id());
|
| - }
|
| - } else {
|
| - // Restore a single tab from the window. Find the tab that matches the ID
|
| - // in the window and restore it.
|
| - for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
|
| - tab_i != window->tabs.end(); ++tab_i) {
|
| - const Tab& tab = *tab_i;
|
| - if (tab.id == id) {
|
| - delegate = RestoreTab(tab, delegate, disposition);
|
| - window->tabs.erase(tab_i);
|
| - // If restoring the tab leaves the window with nothing else, delete it
|
| - // as well.
|
| - if (!window->tabs.size()) {
|
| - entries_.erase(i);
|
| - delete entry;
|
| - } else {
|
| - // Update the browser ID of the rest of the tabs in the window so if
|
| - // any one is restored, it goes into the same window as the tab
|
| - // being restored now.
|
| - UpdateTabBrowserIDs(tab.browser_id,
|
| - delegate->GetSessionID().id());
|
| - for (std::vector<Tab>::iterator tab_j = window->tabs.begin();
|
| - tab_j != window->tabs.end(); ++tab_j) {
|
| - (*tab_j).browser_id = delegate->GetSessionID().id();
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - delegate->ShowBrowserWindow();
|
| -
|
| - if (disposition == CURRENT_TAB && current_delegate &&
|
| - current_delegate->GetActiveWebContents()) {
|
| - current_delegate->CloseTab();
|
| - }
|
| - } else {
|
| - NOTREACHED();
|
| - }
|
| -
|
| - if (!restoring_tab_in_window) {
|
| - delete entry;
|
| - }
|
| -
|
| - restoring_ = false;
|
| - NotifyTabsChanged();
|
| +void PersistentTabRestoreService::Delegate::OnAddEntry() {
|
| + // Start the save timer, when it fires we'll generate the commands.
|
| + StartSaveTimer();
|
| + entries_to_write_++;
|
| }
|
|
|
| -void TabRestoreService::LoadTabsFromLastSession() {
|
| - if (load_state_ != NOT_LOADED || entries_.size() == kMaxEntries)
|
| +void PersistentTabRestoreService::Delegate::LoadTabsFromLastSession() {
|
| + if (load_state_ != NOT_LOADED ||
|
| + tab_restore_service_helper_->entries().size() == kMaxEntries)
|
| return;
|
|
|
| #if !defined(ENABLE_SESSION_SERVICE)
|
| @@ -461,8 +349,7 @@ void TabRestoreService::LoadTabsFromLastSession() {
|
| // saved them).
|
| session_service->GetLastSession(
|
| &crash_consumer_,
|
| - base::Bind(&TabRestoreService::OnGotPreviousSession,
|
| - base::Unretained(this)));
|
| + base::Bind(&Delegate::OnGotPreviousSession, base::Unretained(this)));
|
| } else {
|
| load_state_ |= LOADED_LAST_SESSION;
|
| }
|
| @@ -473,165 +360,33 @@ void TabRestoreService::LoadTabsFromLastSession() {
|
| // crash (the call to GetLastSession above requests those).
|
| ScheduleGetLastSessionCommands(
|
| new InternalGetCommandsRequest(
|
| - base::Bind(&TabRestoreService::OnGotLastSessionCommands,
|
| + base::Bind(&Delegate::OnGotLastSessionCommands,
|
| base::Unretained(this))),
|
| &load_consumer_);
|
| }
|
|
|
| -bool TabRestoreService::IsLoaded() const {
|
| +bool PersistentTabRestoreService::Delegate::IsLoaded() const {
|
| return !(load_state_ & (NOT_LOADED | LOADING));
|
| }
|
|
|
| -void TabRestoreService::Shutdown() {
|
| - if (backend())
|
| - Save();
|
| -}
|
| -
|
| -void TabRestoreService::Save() {
|
| - int to_write_count = std::min(entries_to_write_,
|
| - static_cast<int>(entries_.size()));
|
| - entries_to_write_ = 0;
|
| - if (entries_written_ + to_write_count > kEntriesPerReset) {
|
| - to_write_count = entries_.size();
|
| - set_pending_reset(true);
|
| - }
|
| - if (to_write_count) {
|
| - // Write the to_write_count most recently added entries out. The most
|
| - // recently added entry is at the front, so we use a reverse iterator to
|
| - // write in the order the entries were added.
|
| - Entries::reverse_iterator i = entries_.rbegin();
|
| - DCHECK(static_cast<size_t>(to_write_count) <= entries_.size());
|
| - std::advance(i, entries_.size() - static_cast<int>(to_write_count));
|
| - for (; i != entries_.rend(); ++i) {
|
| - Entry* entry = *i;
|
| - if (entry->type == TAB) {
|
| - Tab* tab = static_cast<Tab*>(entry);
|
| - int selected_index = GetSelectedNavigationIndexToPersist(*tab);
|
| - if (selected_index != -1)
|
| - ScheduleCommandsForTab(*tab, selected_index);
|
| - } else {
|
| - ScheduleCommandsForWindow(*static_cast<Window*>(entry));
|
| - }
|
| - entries_written_++;
|
| - }
|
| - }
|
| - if (pending_reset())
|
| - entries_written_ = 0;
|
| - BaseSessionService::Save();
|
| -}
|
| -
|
| -void TabRestoreService::PopulateTab(Tab* tab,
|
| - int index,
|
| - TabRestoreServiceDelegate* delegate,
|
| - NavigationController* controller) {
|
| - const int pending_index = controller->GetPendingEntryIndex();
|
| - int entry_count = controller->GetEntryCount();
|
| - if (entry_count == 0 && pending_index == 0)
|
| - entry_count++;
|
| - tab->navigations.resize(static_cast<int>(entry_count));
|
| - for (int i = 0; i < entry_count; ++i) {
|
| - NavigationEntry* entry = (i == pending_index) ?
|
| - controller->GetPendingEntry() : controller->GetEntryAtIndex(i);
|
| - tab->navigations[i] =
|
| - TabNavigation::FromNavigationEntry(i, *entry);
|
| - }
|
| - tab->timestamp = TimeNow();
|
| - tab->current_navigation_index = controller->GetCurrentEntryIndex();
|
| - if (tab->current_navigation_index == -1 && entry_count > 0)
|
| - tab->current_navigation_index = 0;
|
| - tab->tabstrip_index = index;
|
| -
|
| - TabContents* tab_contents =
|
| - TabContents::FromWebContents(controller->GetWebContents());
|
| - // tab_contents is NULL in some browser tests.
|
| - if (tab_contents) {
|
| - const extensions::Extension* extension =
|
| - extensions::TabHelper::FromWebContents(controller->GetWebContents())->
|
| - extension_app();
|
| - if (extension)
|
| - tab->extension_app_id = extension->id();
|
| - }
|
| -
|
| - tab->user_agent_override =
|
| - controller->GetWebContents()->GetUserAgentOverride();
|
| -
|
| - // TODO(ajwong): This does not correctly handle storage for isolated apps.
|
| - tab->session_storage_namespace =
|
| - controller->GetDefaultSessionStorageNamespace();
|
| -
|
| - // Delegate may be NULL during unit tests.
|
| - if (delegate) {
|
| - tab->browser_id = delegate->GetSessionID().id();
|
| - tab->pinned = delegate->IsTabPinned(tab->tabstrip_index);
|
| - }
|
| -}
|
| -
|
| -void TabRestoreService::NotifyTabsChanged() {
|
| - FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
|
| - TabRestoreServiceChanged(this));
|
| -}
|
| -
|
| -void TabRestoreService::AddEntry(Entry* entry, bool notify, bool to_front) {
|
| - if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) {
|
| - delete entry;
|
| - return;
|
| - }
|
| -
|
| - if (to_front)
|
| - entries_.push_front(entry);
|
| - else
|
| - entries_.push_back(entry);
|
| -
|
| - PruneEntries();
|
| -
|
| - if (notify)
|
| - NotifyTabsChanged();
|
| -
|
| - // Start the save timer, when it fires we'll generate the commands.
|
| - StartSaveTimer();
|
| - entries_to_write_++;
|
| -}
|
| -
|
| -void TabRestoreService::PruneEntries() {
|
| - Entries new_entries;
|
| -
|
| - for (TabRestoreService::Entries::const_iterator iter = entries_.begin();
|
| - iter != entries_.end(); ++iter) {
|
| - TabRestoreService::Entry* entry = *iter;
|
| -
|
| - if (FilterEntry(entry) &&
|
| - new_entries.size() < kMaxEntries) {
|
| - new_entries.push_back(entry);
|
| - } else {
|
| - delete entry;
|
| - }
|
| +// static
|
| +void PersistentTabRestoreService::Delegate::CreateEntriesFromWindows(
|
| + std::vector<SessionWindow*>* windows,
|
| + std::vector<Entry*>* entries) {
|
| + for (size_t i = 0; i < windows->size(); ++i) {
|
| + scoped_ptr<Window> window(new Window());
|
| + if (ConvertSessionWindowToWindow((*windows)[i], window.get()))
|
| + entries->push_back(window.release());
|
| }
|
| -
|
| - entries_ = new_entries;
|
| }
|
|
|
| -TabRestoreService::Entries::iterator TabRestoreService::GetEntryIteratorById(
|
| - SessionID::id_type id) {
|
| - for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
|
| - if ((*i)->id == id)
|
| - return i;
|
| -
|
| - // For Window entries, see if the ID matches a tab. If so, report the window
|
| - // as the Entry.
|
| - if ((*i)->type == WINDOW) {
|
| - std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs;
|
| - for (std::vector<Tab>::iterator j = tabs.begin();
|
| - j != tabs.end(); ++j) {
|
| - if ((*j).id == id) {
|
| - return i;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return entries_.end();
|
| +void PersistentTabRestoreService::Delegate::Shutdown() {
|
| + if (backend())
|
| + Save();
|
| }
|
|
|
| -void TabRestoreService::ScheduleCommandsForWindow(const Window& window) {
|
| +void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow(
|
| + const Window& window) {
|
| DCHECK(!window.tabs.empty());
|
| int selected_tab = window.selected_tab_index;
|
| int valid_tab_count = 0;
|
| @@ -666,8 +421,9 @@ void TabRestoreService::ScheduleCommandsForWindow(const Window& window) {
|
| }
|
| }
|
|
|
| -void TabRestoreService::ScheduleCommandsForTab(const Tab& tab,
|
| - int selected_index) {
|
| +void PersistentTabRestoreService::Delegate::ScheduleCommandsForTab(
|
| + const Tab& tab,
|
| + int selected_index) {
|
| const std::vector<TabNavigation>& navigations = tab.navigations;
|
| int max_index = static_cast<int>(navigations.size());
|
|
|
| @@ -719,10 +475,12 @@ void TabRestoreService::ScheduleCommandsForTab(const Tab& tab,
|
| }
|
| }
|
|
|
| -SessionCommand* TabRestoreService::CreateWindowCommand(SessionID::id_type id,
|
| - int selected_tab_index,
|
| - int num_tabs,
|
| - Time timestamp) {
|
| +// static
|
| +SessionCommand* PersistentTabRestoreService::Delegate::CreateWindowCommand(
|
| + SessionID::id_type id,
|
| + int selected_tab_index,
|
| + int num_tabs,
|
| + base::Time timestamp) {
|
| WindowPayload2 payload;
|
| // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of
|
| // uninitialized memory in the struct.
|
| @@ -738,10 +496,12 @@ SessionCommand* TabRestoreService::CreateWindowCommand(SessionID::id_type id,
|
| return command;
|
| }
|
|
|
| -SessionCommand* TabRestoreService::CreateSelectedNavigationInTabCommand(
|
| +// static
|
| +SessionCommand*
|
| +PersistentTabRestoreService::Delegate::CreateSelectedNavigationInTabCommand(
|
| SessionID::id_type tab_id,
|
| int32 index,
|
| - Time timestamp) {
|
| + base::Time timestamp) {
|
| SelectedNavigationInTabPayload2 payload;
|
| payload.id = tab_id;
|
| payload.index = index;
|
| @@ -752,7 +512,9 @@ SessionCommand* TabRestoreService::CreateSelectedNavigationInTabCommand(
|
| return command;
|
| }
|
|
|
| -SessionCommand* TabRestoreService::CreateRestoredEntryCommand(
|
| +// static
|
| +SessionCommand*
|
| +PersistentTabRestoreService::Delegate::CreateRestoredEntryCommand(
|
| SessionID::id_type entry_id) {
|
| RestoredEntryPayload payload = entry_id;
|
| SessionCommand* command =
|
| @@ -761,7 +523,8 @@ SessionCommand* TabRestoreService::CreateRestoredEntryCommand(
|
| return command;
|
| }
|
|
|
| -int TabRestoreService::GetSelectedNavigationIndexToPersist(const Tab& tab) {
|
| +int PersistentTabRestoreService::Delegate::GetSelectedNavigationIndexToPersist(
|
| + const Tab& tab) {
|
| const std::vector<TabNavigation>& navigations = tab.navigations;
|
| int selected_index = tab.current_navigation_index;
|
| int max_index = static_cast<int>(navigations.size());
|
| @@ -786,7 +549,7 @@ int TabRestoreService::GetSelectedNavigationIndexToPersist(const Tab& tab) {
|
| return (selected_index == max_index) ? -1 : selected_index;
|
| }
|
|
|
| -void TabRestoreService::OnGotLastSessionCommands(
|
| +void PersistentTabRestoreService::Delegate::OnGotLastSessionCommands(
|
| Handle handle,
|
| scoped_refptr<InternalGetCommandsRequest> request) {
|
| std::vector<Entry*> entries;
|
| @@ -798,10 +561,11 @@ void TabRestoreService::OnGotLastSessionCommands(
|
| LoadStateChanged();
|
| }
|
|
|
| -void TabRestoreService::CreateEntriesFromCommands(
|
| +void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
|
| scoped_refptr<InternalGetCommandsRequest> request,
|
| std::vector<Entry*>* loaded_entries) {
|
| - if (request->canceled() || entries_.size() == kMaxEntries)
|
| + if (request->canceled() ||
|
| + tab_restore_service_helper_->entries().size() == kMaxEntries)
|
| return;
|
|
|
| std::vector<SessionCommand*>& commands = request->commands;
|
| @@ -869,7 +633,8 @@ void TabRestoreService::CreateEntriesFromCommands(
|
|
|
| current_window = new Window();
|
| current_window->selected_tab_index = payload.selected_tab_index;
|
| - current_window->timestamp = Time::FromInternalValue(payload.timestamp);
|
| + current_window->timestamp =
|
| + base::Time::FromInternalValue(payload.timestamp);
|
| entries.push_back(current_window);
|
| id_to_entry[payload.window_id] = current_window;
|
| break;
|
| @@ -902,7 +667,8 @@ void TabRestoreService::CreateEntriesFromCommands(
|
| RemoveEntryByID(payload.id, &id_to_entry, &(entries.get()));
|
| current_tab = new Tab();
|
| id_to_entry[payload.id] = current_tab;
|
| - current_tab->timestamp = Time::FromInternalValue(payload.timestamp);
|
| + current_tab->timestamp =
|
| + base::Time::FromInternalValue(payload.timestamp);
|
| entries.push_back(current_tab);
|
| }
|
| current_tab->current_navigation_index = payload.index;
|
| @@ -992,143 +758,8 @@ void TabRestoreService::CreateEntriesFromCommands(
|
| loaded_entries->swap(entries.get());
|
| }
|
|
|
| -TabRestoreServiceDelegate* TabRestoreService::RestoreTab(
|
| - const Tab& tab,
|
| - TabRestoreServiceDelegate* delegate,
|
| - WindowOpenDisposition disposition) {
|
| - if (disposition == CURRENT_TAB && delegate) {
|
| - delegate->ReplaceRestoredTab(tab.navigations,
|
| - tab.current_navigation_index,
|
| - tab.from_last_session,
|
| - tab.extension_app_id,
|
| - tab.session_storage_namespace,
|
| - tab.user_agent_override);
|
| - } else {
|
| - // We only respsect the tab's original browser if there's no disposition.
|
| - if (disposition == UNKNOWN && tab.has_browser())
|
| - delegate = TabRestoreServiceDelegate::FindDelegateWithID(tab.browser_id);
|
| -
|
| - int tab_index = -1;
|
| -
|
| - // |delegate| will be NULL in cases where one isn't already available (eg,
|
| - // when invoked on Mac OS X with no windows open). In this case, create a
|
| - // new browser into which we restore the tabs.
|
| - if (delegate && disposition != NEW_WINDOW) {
|
| - tab_index = tab.tabstrip_index;
|
| - } else {
|
| - delegate = TabRestoreServiceDelegate::Create(profile(), std::string());
|
| - if (tab.has_browser())
|
| - UpdateTabBrowserIDs(tab.browser_id, delegate->GetSessionID().id());
|
| - }
|
| -
|
| - // Place the tab at the end if the tab index is no longer valid or
|
| - // we were passed a specific disposition.
|
| - if (tab_index < 0 || tab_index > delegate->GetTabCount() ||
|
| - disposition != UNKNOWN) {
|
| - tab_index = delegate->GetTabCount();
|
| - }
|
| -
|
| - WebContents* web_contents = delegate->AddRestoredTab(
|
| - tab.navigations,
|
| - tab_index,
|
| - tab.current_navigation_index,
|
| - tab.extension_app_id,
|
| - disposition != NEW_BACKGROUND_TAB,
|
| - tab.pinned,
|
| - tab.from_last_session,
|
| - tab.session_storage_namespace,
|
| - tab.user_agent_override);
|
| - web_contents->GetController().LoadIfNecessary();
|
| - }
|
| - RecordAppLaunch(profile(), tab);
|
| - return delegate;
|
| -}
|
| -
|
| -
|
| -bool TabRestoreService::ValidateTab(Tab* tab) {
|
| - if (tab->navigations.empty())
|
| - return false;
|
| -
|
| - tab->current_navigation_index =
|
| - std::max(0, std::min(tab->current_navigation_index,
|
| - static_cast<int>(tab->navigations.size()) - 1));
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool TabRestoreService::ValidateWindow(Window* window) {
|
| - window->selected_tab_index =
|
| - std::max(0, std::min(window->selected_tab_index,
|
| - static_cast<int>(window->tabs.size() - 1)));
|
| -
|
| - int i = 0;
|
| - for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
|
| - tab_i != window->tabs.end();) {
|
| - if (!ValidateTab(&(*tab_i))) {
|
| - tab_i = window->tabs.erase(tab_i);
|
| - if (i < window->selected_tab_index)
|
| - window->selected_tab_index--;
|
| - else if (i == window->selected_tab_index)
|
| - window->selected_tab_index = 0;
|
| - } else {
|
| - ++tab_i;
|
| - ++i;
|
| - }
|
| - }
|
| -
|
| - if (window->tabs.empty())
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool TabRestoreService::ValidateEntry(Entry* entry) {
|
| - if (entry->type == TAB)
|
| - return ValidateTab(static_cast<Tab*>(entry));
|
| -
|
| - if (entry->type == WINDOW)
|
| - return ValidateWindow(static_cast<Window*>(entry));
|
| -
|
| - NOTREACHED();
|
| - return false;
|
| -}
|
| -
|
| -bool TabRestoreService::IsTabInteresting(const Tab* tab) {
|
| - if (tab->navigations.empty())
|
| - return false;
|
| -
|
| - if (tab->navigations.size() > 1)
|
| - return true;
|
| -
|
| - return tab->pinned ||
|
| - tab->navigations.at(0).virtual_url() !=
|
| - GURL(chrome::kChromeUINewTabURL);
|
| -}
|
| -
|
| -bool TabRestoreService::IsWindowInteresting(const Window* window) {
|
| - if (window->tabs.empty())
|
| - return false;
|
| -
|
| - if (window->tabs.size() > 1)
|
| - return true;
|
| -
|
| - return IsTabInteresting(&window->tabs[0]);
|
| -}
|
| -
|
| -bool TabRestoreService::FilterEntry(Entry* entry) {
|
| - if (!ValidateEntry(entry))
|
| - return false;
|
| -
|
| - if (entry->type == TAB)
|
| - return IsTabInteresting(static_cast<Tab*>(entry));
|
| - else if (entry->type == WINDOW)
|
| - return IsWindowInteresting(static_cast<Window*>(entry));
|
| -
|
| - NOTREACHED();
|
| - return false;
|
| -}
|
| -
|
| -void TabRestoreService::ValidateAndDeleteEmptyEntries(
|
| +// static
|
| +void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries(
|
| std::vector<Entry*>* entries) {
|
| std::vector<Entry*> valid_entries;
|
| std::vector<Entry*> invalid_entries;
|
| @@ -1136,7 +767,7 @@ void TabRestoreService::ValidateAndDeleteEmptyEntries(
|
| // Iterate from the back so that we keep the most recently closed entries.
|
| for (std::vector<Entry*>::reverse_iterator i = entries->rbegin();
|
| i != entries->rend(); ++i) {
|
| - if (ValidateEntry(*i))
|
| + if (TabRestoreServiceHelper::ValidateEntry(*i))
|
| valid_entries.push_back(*i);
|
| else
|
| invalid_entries.push_back(*i);
|
| @@ -1148,19 +779,7 @@ void TabRestoreService::ValidateAndDeleteEmptyEntries(
|
| STLDeleteElements(&invalid_entries);
|
| }
|
|
|
| -void TabRestoreService::UpdateTabBrowserIDs(SessionID::id_type old_id,
|
| - SessionID::id_type new_id) {
|
| - for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
|
| - Entry* entry = *i;
|
| - if (entry->type == TAB) {
|
| - Tab* tab = static_cast<Tab*>(entry);
|
| - if (tab->browser_id == old_id)
|
| - tab->browser_id = new_id;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void TabRestoreService::OnGotPreviousSession(
|
| +void PersistentTabRestoreService::Delegate::OnGotPreviousSession(
|
| Handle handle,
|
| std::vector<SessionWindow*>* windows,
|
| SessionID::id_type ignored_active_window) {
|
| @@ -1173,17 +792,7 @@ void TabRestoreService::OnGotPreviousSession(
|
| LoadStateChanged();
|
| }
|
|
|
| -void TabRestoreService::CreateEntriesFromWindows(
|
| - std::vector<SessionWindow*>* windows,
|
| - std::vector<Entry*>* entries) {
|
| - for (size_t i = 0; i < windows->size(); ++i) {
|
| - scoped_ptr<Window> window(new Window());
|
| - if (ConvertSessionWindowToWindow((*windows)[i], window.get()))
|
| - entries->push_back(window.release());
|
| - }
|
| -}
|
| -
|
| -bool TabRestoreService::ConvertSessionWindowToWindow(
|
| +bool PersistentTabRestoreService::Delegate::ConvertSessionWindowToWindow(
|
| SessionWindow* session_window,
|
| Window* window) {
|
| for (size_t i = 0; i < session_window->tabs.size(); ++i) {
|
| @@ -1195,7 +804,7 @@ bool TabRestoreService::ConvertSessionWindowToWindow(
|
| tab.current_navigation_index =
|
| session_window->tabs[i]->current_navigation_index;
|
| tab.extension_app_id = session_window->tabs[i]->extension_app_id;
|
| - tab.timestamp = Time();
|
| + tab.timestamp = base::Time();
|
| }
|
| }
|
| if (window->tabs.empty())
|
| @@ -1204,11 +813,11 @@ bool TabRestoreService::ConvertSessionWindowToWindow(
|
| window->selected_tab_index =
|
| std::min(session_window->selected_tab_index,
|
| static_cast<int>(window->tabs.size() - 1));
|
| - window->timestamp = Time();
|
| + window->timestamp = base::Time();
|
| return true;
|
| }
|
|
|
| -void TabRestoreService::LoadStateChanged() {
|
| +void PersistentTabRestoreService::Delegate::LoadStateChanged() {
|
| if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) !=
|
| (LOADED_LAST_TABS | LOADED_LAST_SESSION)) {
|
| // Still waiting on previous session or previous tabs.
|
| @@ -1218,30 +827,31 @@ void TabRestoreService::LoadStateChanged() {
|
| // We're done loading.
|
| load_state_ ^= LOADING;
|
|
|
| - if (staging_entries_.empty() || entries_.size() >= kMaxEntries) {
|
| + const Entries& entries = tab_restore_service_helper_->entries();
|
| + if (staging_entries_.empty() || entries.size() >= kMaxEntries) {
|
| STLDeleteElements(&staging_entries_);
|
| return;
|
| }
|
|
|
| - if (staging_entries_.size() + entries_.size() > kMaxEntries) {
|
| + if (staging_entries_.size() + entries.size() > kMaxEntries) {
|
| // If we add all the staged entries we'll end up with more than
|
| - // kMaxEntries. Delete entries such that we only end up with
|
| - // at most kMaxEntries.
|
| - int surplus = kMaxEntries - entries_.size();
|
| + // kMaxEntries. Delete entries such that we only end up with at most
|
| + // kMaxEntries.
|
| + int surplus = kMaxEntries - entries.size();
|
| CHECK_LE(0, surplus);
|
| CHECK_GE(static_cast<int>(staging_entries_.size()), surplus);
|
| STLDeleteContainerPointers(
|
| - staging_entries_.begin() + (kMaxEntries - entries_.size()),
|
| + staging_entries_.begin() + (kMaxEntries - entries.size()),
|
| staging_entries_.end());
|
| staging_entries_.erase(
|
| - staging_entries_.begin() + (kMaxEntries - entries_.size()),
|
| + staging_entries_.begin() + (kMaxEntries - entries.size()),
|
| staging_entries_.end());
|
| }
|
|
|
| // And add them.
|
| for (size_t i = 0; i < staging_entries_.size(); ++i) {
|
| staging_entries_[i]->from_last_session = true;
|
| - AddEntry(staging_entries_[i], false, false);
|
| + tab_restore_service_helper_->AddEntry(staging_entries_[i], false, false);
|
| }
|
|
|
| // AddEntry takes ownership of the entry, need to clear out entries so that
|
| @@ -1253,10 +863,133 @@ void TabRestoreService::LoadStateChanged() {
|
| // the front, not the end and we just added the entries to the end).
|
| entries_to_write_ = staging_entries_.size();
|
|
|
| - PruneEntries();
|
| - NotifyTabsChanged();
|
| + tab_restore_service_helper_->PruneEntries();
|
| + tab_restore_service_helper_->NotifyTabsChanged();
|
| +}
|
| +
|
| +void PersistentTabRestoreService::Delegate::RemoveEntryByID(
|
| + SessionID::id_type id,
|
| + IDToEntry* id_to_entry,
|
| + std::vector<TabRestoreService::Entry*>* entries) {
|
| + // Look for the entry in the map. If it is present, erase it from both
|
| + // collections and return.
|
| + IDToEntry::iterator i = id_to_entry->find(id);
|
| + if (i != id_to_entry->end()) {
|
| + entries->erase(std::find(entries->begin(), entries->end(), i->second));
|
| + delete i->second;
|
| + id_to_entry->erase(i);
|
| + return;
|
| + }
|
| +
|
| + // Otherwise, loop over all items in the map and see if any of the Windows
|
| + // have Tabs with the |id|.
|
| + for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end();
|
| + ++i) {
|
| + if (i->second->type == TabRestoreService::WINDOW) {
|
| + TabRestoreService::Window* window =
|
| + static_cast<TabRestoreService::Window*>(i->second);
|
| + std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin();
|
| + for ( ; j != window->tabs.end(); ++j) {
|
| + // If the ID matches one of this window's tabs, remove it from the
|
| + // list.
|
| + if ((*j).id == id) {
|
| + window->tabs.erase(j);
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +// PersistentTabRestoreService -------------------------------------------------
|
| +
|
| +PersistentTabRestoreService::PersistentTabRestoreService(
|
| + Profile* profile,
|
| + TimeFactory* time_factory)
|
| + : delegate_(new Delegate(profile)),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(
|
| + helper_(this, delegate_.get(), profile, time_factory)) {
|
| + delegate_->set_tab_restore_service_helper(&helper_);
|
| +}
|
| +
|
| +PersistentTabRestoreService::~PersistentTabRestoreService() {}
|
| +
|
| +void PersistentTabRestoreService::AddObserver(
|
| + TabRestoreServiceObserver* observer) {
|
| + helper_.AddObserver(observer);
|
| +}
|
| +
|
| +void PersistentTabRestoreService::RemoveObserver(
|
| + TabRestoreServiceObserver* observer) {
|
| + helper_.RemoveObserver(observer);
|
| +}
|
| +
|
| +void PersistentTabRestoreService::CreateHistoricalTab(
|
| + content::WebContents* contents,
|
| + int index) {
|
| + helper_.CreateHistoricalTab(contents, index);
|
| +}
|
| +
|
| +void PersistentTabRestoreService::BrowserClosing(
|
| + TabRestoreServiceDelegate* delegate) {
|
| + helper_.BrowserClosing(delegate);
|
| +}
|
| +
|
| +void PersistentTabRestoreService::BrowserClosed(
|
| + TabRestoreServiceDelegate* delegate) {
|
| + helper_.BrowserClosed(delegate);
|
| +}
|
| +
|
| +void PersistentTabRestoreService::ClearEntries() {
|
| + helper_.ClearEntries();
|
| +}
|
| +
|
| +const TabRestoreService::Entries& PersistentTabRestoreService::entries() const {
|
| + return helper_.entries();
|
| +}
|
| +
|
| +void PersistentTabRestoreService::RestoreMostRecentEntry(
|
| + TabRestoreServiceDelegate* delegate) {
|
| + helper_.RestoreMostRecentEntry(delegate);
|
| +}
|
| +
|
| +TabRestoreService::Tab* PersistentTabRestoreService::RemoveTabEntryById(
|
| + SessionID::id_type id) {
|
| + return helper_.RemoveTabEntryById(id);
|
| +}
|
| +
|
| +void PersistentTabRestoreService::RestoreEntryById(
|
| + TabRestoreServiceDelegate* delegate,
|
| + SessionID::id_type id,
|
| + WindowOpenDisposition disposition) {
|
| + helper_.RestoreEntryById(delegate, id, disposition);
|
| +}
|
| +
|
| +bool PersistentTabRestoreService::IsLoaded() const {
|
| + return delegate_->IsLoaded();
|
| +}
|
| +
|
| +void PersistentTabRestoreService::DeleteLastSession() {
|
| + return delegate_->DeleteLastSession();
|
| +}
|
| +
|
| +void PersistentTabRestoreService::Shutdown() {
|
| + return delegate_->Shutdown();
|
| +}
|
| +
|
| +void PersistentTabRestoreService::LoadTabsFromLastSession() {
|
| + delegate_->LoadTabsFromLastSession();
|
| +}
|
| +
|
| +TabRestoreService::Entries* PersistentTabRestoreService::mutable_entries() {
|
| + return &helper_.entries_;
|
| +}
|
| +
|
| +void PersistentTabRestoreService::PruneEntries() {
|
| + helper_.PruneEntries();
|
| }
|
|
|
| -Time TabRestoreService::TimeNow() const {
|
| - return time_factory_ ? time_factory_->TimeNow() : Time::Now();
|
| +ProfileKeyedService* TabRestoreServiceFactory::BuildServiceInstanceFor(
|
| + Profile* profile) const {
|
| + return new PersistentTabRestoreService(profile, NULL);
|
| }
|
|
|