Chromium Code Reviews| 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 "chrome/browser/sessions/tab_restore_service.h" | 5 #include "chrome/browser/sessions/persistent_tab_restore_service.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <cstring> // memcpy |
| 8 #include <iterator> | 8 #include <vector> |
| 9 #include <map> | |
| 10 | 9 |
| 10 #include "base/basictypes.h" | |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/bind_helpers.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/callback.h" | 13 #include "base/file_path.h" |
| 14 #include "base/logging.h" | |
| 15 #include "base/memory/ref_counted.h" | |
| 14 #include "base/memory/scoped_vector.h" | 16 #include "base/memory/scoped_vector.h" |
| 15 #include "base/metrics/histogram.h" | |
| 16 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 17 #include "chrome/browser/extensions/extension_service.h" | 18 #include "base/time.h" |
| 18 #include "chrome/browser/extensions/tab_helper.h" | 19 #include "chrome/browser/common/cancelable_request.h" |
| 19 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 21 #include "chrome/browser/sessions/base_session_service.h" | |
| 20 #include "chrome/browser/sessions/session_command.h" | 22 #include "chrome/browser/sessions/session_command.h" |
| 21 #include "chrome/browser/sessions/session_service.h" | 23 #include "chrome/browser/sessions/session_service.h" |
| 22 #include "chrome/browser/sessions/session_service_factory.h" | 24 #include "chrome/browser/sessions/session_service_factory.h" |
| 23 #include "chrome/browser/sessions/session_types.h" | 25 #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| 24 #include "chrome/browser/sessions/tab_restore_service_delegate.h" | 26 #include "content/public/browser/session_storage_namespace.h" |
| 25 #include "chrome/browser/sessions/tab_restore_service_observer.h" | |
| 26 #include "chrome/browser/ui/tab_contents/tab_contents.h" | |
| 27 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" | |
| 28 #include "chrome/common/extensions/extension.h" | |
| 29 #include "chrome/common/extensions/extension_constants.h" | |
| 30 #include "chrome/common/url_constants.h" | |
| 31 #include "content/public/browser/navigation_controller.h" | |
| 32 #include "content/public/browser/navigation_entry.h" | |
| 33 #include "content/public/browser/web_contents.h" | |
| 34 | 27 |
| 35 using base::Time; | 28 namespace { |
| 36 using content::NavigationController; | |
| 37 using content::NavigationEntry; | |
| 38 using content::WebContents; | |
| 39 | 29 |
| 40 // TimeFactory----------------------------------------------------------------- | 30 // Only written if the tab is pinned. |
| 31 typedef bool PinnedStatePayload; | |
| 41 | 32 |
| 42 TabRestoreService::TimeFactory::~TimeFactory() {} | 33 typedef int32 RestoredEntryPayload; |
| 43 | 34 |
| 44 // Entry ---------------------------------------------------------------------- | 35 typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry; |
| 45 | 36 |
| 46 // ID of the next Entry. | 37 // Payload used for the start of a tab close. This is the old struct that is |
| 47 static SessionID::id_type next_entry_id = 1; | 38 // used for backwards compat when it comes to reading the session files. |
| 39 struct SelectedNavigationInTabPayload { | |
| 40 SessionID::id_type id; | |
| 41 int32 index; | |
| 42 }; | |
| 48 | 43 |
| 49 TabRestoreService::Entry::Entry() | 44 // Payload used for the start of a window close. This is the old struct that is |
| 50 : id(next_entry_id++), | 45 // used for backwards compat when it comes to reading the session files. This |
| 51 type(TAB), | 46 // struct must be POD, because we memset the contents. |
| 52 from_last_session(false) {} | 47 struct WindowPayload { |
| 48 SessionID::id_type window_id; | |
| 49 int32 selected_tab_index; | |
| 50 int32 num_tabs; | |
| 51 }; | |
| 53 | 52 |
| 54 TabRestoreService::Entry::Entry(Type type) | 53 // Payload used for the start of a window close. This struct must be POD, |
| 55 : id(next_entry_id++), | 54 // because we memset the contents. |
| 56 type(type), | 55 struct WindowPayload2 : WindowPayload { |
| 57 from_last_session(false) {} | 56 int64 timestamp; |
| 57 }; | |
| 58 | 58 |
| 59 TabRestoreService::Entry::~Entry() {} | 59 // Payload used for the start of a tab close. |
| 60 struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload { | |
| 61 int64 timestamp; | |
| 62 }; | |
| 60 | 63 |
| 61 // TabRestoreService ---------------------------------------------------------- | 64 // Used to indicate what has loaded. |
| 65 enum LoadState { | |
| 66 // Indicates we haven't loaded anything. | |
| 67 NOT_LOADED = 1 << 0, | |
| 62 | 68 |
| 63 // static | 69 // Indicates we've asked for the last sessions and tabs but haven't gotten the |
| 64 const size_t TabRestoreService::kMaxEntries = 25; | 70 // result back yet. |
| 71 LOADING = 1 << 2, | |
| 65 | 72 |
| 66 // Identifier for commands written to file. | 73 // Indicates we finished loading the last tabs (but not necessarily the last |
| 67 // The ordering in the file is as follows: | 74 // session). |
| 75 LOADED_LAST_TABS = 1 << 3, | |
| 76 | |
| 77 // Indicates we finished loading the last session (but not necessarily the | |
| 78 // last tabs). | |
| 79 LOADED_LAST_SESSION = 1 << 4 | |
| 80 }; | |
| 81 | |
| 82 // Identifier for commands written to file. The ordering in the file is as | |
| 83 // follows: | |
| 68 // . When the user closes a tab a command of type | 84 // . When the user closes a tab a command of type |
| 69 // kCommandSelectedNavigationInTab is written identifying the tab and | 85 // kCommandSelectedNavigationInTab is written identifying the tab and |
| 70 // the selected index, then a kCommandPinnedState command if the tab was | 86 // the selected index, then a kCommandPinnedState command if the tab was |
| 71 // pinned and kCommandSetExtensionAppID if the tab has an app id and | 87 // pinned and kCommandSetExtensionAppID if the tab has an app id and |
| 72 // the user agent override if it was using one. This is | 88 // the user agent override if it was using one. This is |
| 73 // followed by any number of kCommandUpdateTabNavigation commands (1 per | 89 // followed by any number of kCommandUpdateTabNavigation commands (1 per |
| 74 // navigation entry). | 90 // navigation entry). |
| 75 // . When the user closes a window a kCommandSelectedNavigationInTab command | 91 // . When the user closes a window a kCommandSelectedNavigationInTab command |
| 76 // is written out and followed by n tab closed sequences (as previoulsy | 92 // is written out and followed by n tab closed sequences (as previoulsy |
| 77 // described). | 93 // described). |
| 78 // . When the user restores an entry a command of type kCommandRestoredEntry | 94 // . When the user restores an entry a command of type kCommandRestoredEntry |
| 79 // is written. | 95 // is written. |
| 80 static const SessionCommand::id_type kCommandUpdateTabNavigation = 1; | 96 const SessionCommand::id_type kCommandUpdateTabNavigation = 1; |
| 81 static const SessionCommand::id_type kCommandRestoredEntry = 2; | 97 const SessionCommand::id_type kCommandRestoredEntry = 2; |
| 82 static const SessionCommand::id_type kCommandWindow = 3; | 98 const SessionCommand::id_type kCommandWindow = 3; |
| 83 static const SessionCommand::id_type kCommandSelectedNavigationInTab = 4; | 99 const SessionCommand::id_type kCommandSelectedNavigationInTab = 4; |
| 84 static const SessionCommand::id_type kCommandPinnedState = 5; | 100 const SessionCommand::id_type kCommandPinnedState = 5; |
| 85 static const SessionCommand::id_type kCommandSetExtensionAppID = 6; | 101 const SessionCommand::id_type kCommandSetExtensionAppID = 6; |
| 86 static const SessionCommand::id_type kCommandSetWindowAppName = 7; | 102 const SessionCommand::id_type kCommandSetWindowAppName = 7; |
| 87 static const SessionCommand::id_type kCommandSetTabUserAgentOverride = 8; | 103 const SessionCommand::id_type kCommandSetTabUserAgentOverride = 8; |
| 88 | 104 |
| 89 // Number of entries (not commands) before we clobber the file and write | 105 // Number of entries (not commands) before we clobber the file and write |
| 90 // everything. | 106 // everything. |
| 91 static const int kEntriesPerReset = 40; | 107 const int kEntriesPerReset = 40; |
| 92 | 108 |
| 93 namespace { | 109 const size_t kMaxEntries = TabRestoreServiceHelper::kMaxEntries; |
| 94 | 110 |
| 95 // Payload structures. | 111 } // namespace |
| 96 | 112 |
| 97 typedef int32 RestoredEntryPayload; | 113 // PersistentTabRestoreService::Delegate --------------------------------------- |
| 98 | 114 |
| 99 // Payload used for the start of a window close. This is the old struct that is | 115 class PersistentTabRestoreService::Delegate |
|
sky
2012/10/25 00:45:44
Add description.
Philippe
2012/10/25 15:37:07
Done. Let me know if you think we can add more det
| |
| 100 // used for backwards compat when it comes to reading the session files. This | 116 : public BaseSessionService, |
| 101 // struct must be POD, because we memset the contents. | 117 public TabRestoreServiceHelper::Observer { |
| 102 struct WindowPayload { | 118 public: |
| 103 SessionID::id_type window_id; | 119 explicit Delegate(Profile* profile); |
| 104 int32 selected_tab_index; | 120 |
| 105 int32 num_tabs; | 121 virtual ~Delegate(); |
| 122 | |
| 123 // BaseSessionService: | |
| 124 virtual void Save() OVERRIDE; | |
| 125 | |
| 126 // TabRestoreServiceHelper::Observer: | |
| 127 virtual void OnClearEntries() OVERRIDE; | |
| 128 virtual void OnRestoreEntryById( | |
| 129 SessionID::id_type id, | |
| 130 Entries::const_iterator entry_iterator) OVERRIDE; | |
| 131 virtual void OnAddEntry() OVERRIDE; | |
| 132 | |
| 133 void set_tab_restore_service_helper( | |
| 134 TabRestoreServiceHelper* tab_restore_service_helper) { | |
| 135 tab_restore_service_helper_ = tab_restore_service_helper; | |
| 136 } | |
| 137 | |
| 138 void LoadTabsFromLastSession(); | |
| 139 | |
| 140 bool IsLoaded() const; | |
| 141 | |
| 142 // Creates and add entries to |entries| for each of the windows in |windows|. | |
| 143 static void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows, | |
| 144 std::vector<Entry*>* entries); | |
| 145 | |
| 146 void Shutdown(); | |
| 147 | |
| 148 // Schedules the commands for a window close. | |
| 149 void ScheduleCommandsForWindow(const Window& window); | |
| 150 | |
| 151 // Schedules the commands for a tab close. |selected_index| gives the index of | |
| 152 // the selected navigation. | |
| 153 void ScheduleCommandsForTab(const Tab& tab, int selected_index); | |
| 154 | |
| 155 // Creates a window close command. | |
| 156 static SessionCommand* CreateWindowCommand(SessionID::id_type id, | |
| 157 int selected_tab_index, | |
| 158 int num_tabs, | |
| 159 base::Time timestamp); | |
| 160 | |
| 161 // Creates a tab close command. | |
| 162 static SessionCommand* CreateSelectedNavigationInTabCommand( | |
| 163 SessionID::id_type tab_id, | |
| 164 int32 index, | |
| 165 base::Time timestamp); | |
| 166 | |
| 167 // Creates a restore command. | |
| 168 static SessionCommand* CreateRestoredEntryCommand( | |
| 169 SessionID::id_type entry_id); | |
| 170 | |
| 171 // Returns the index to persist as the selected index. This is the same as | |
| 172 // |tab.current_navigation_index| unless the entry at | |
| 173 // |tab.current_navigation_index| shouldn't be persisted. Returns -1 if no | |
| 174 // valid navigation to persist. | |
| 175 int GetSelectedNavigationIndexToPersist(const Tab& tab); | |
| 176 | |
| 177 // Invoked when we've loaded the session commands that identify the previously | |
| 178 // closed tabs. This creates entries, adds them to staging_entries_, and | |
| 179 // invokes LoadState. | |
| 180 void OnGotLastSessionCommands( | |
| 181 Handle handle, | |
| 182 scoped_refptr<InternalGetCommandsRequest> request); | |
| 183 | |
| 184 // Populates |loaded_entries| with Entries from |request|. | |
| 185 void CreateEntriesFromCommands( | |
| 186 scoped_refptr<InternalGetCommandsRequest> request, | |
| 187 std::vector<Entry*>* loaded_entries); | |
| 188 | |
| 189 // Validates all entries in |entries|, deleting any with no navigations. This | |
| 190 // also deletes any entries beyond the max number of entries we can hold. | |
| 191 static void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries); | |
| 192 | |
| 193 // Callback from SessionService when we've received the windows from the | |
| 194 // previous session. This creates and add entries to |staging_entries_| and | |
| 195 // invokes LoadStateChanged. |ignored_active_window| is ignored because we | |
| 196 // don't need to restore activation. | |
| 197 void OnGotPreviousSession(Handle handle, | |
| 198 std::vector<SessionWindow*>* windows, | |
| 199 SessionID::id_type ignored_active_window); | |
| 200 | |
| 201 // Converts a SessionWindow into a Window, returning true on success. We use 0 | |
| 202 // as the timestamp here since we do not know when the window/tab was closed. | |
| 203 static bool ConvertSessionWindowToWindow(SessionWindow* session_window, | |
| 204 Window* window); | |
| 205 | |
| 206 // Invoked when previous tabs or session is loaded. If both have finished | |
| 207 // loading the entries in |staging_entries_| are added to entries and | |
| 208 // observers are notified. | |
| 209 void LoadStateChanged(); | |
| 210 | |
| 211 // If |id_to_entry| contains an entry for |id| the corresponding entry is | |
| 212 // deleted and removed from both |id_to_entry| and |entries|. This is used | |
| 213 // when creating entries from the backend file. | |
| 214 void RemoveEntryByID(SessionID::id_type id, | |
| 215 IDToEntry* id_to_entry, | |
| 216 std::vector<TabRestoreService::Entry*>* entries); | |
| 217 | |
| 218 private: | |
| 219 TabRestoreServiceHelper* tab_restore_service_helper_; | |
| 220 | |
| 221 // The number of entries to write. | |
| 222 int entries_to_write_; | |
| 223 | |
| 224 // Number of entries we've written. | |
| 225 int entries_written_; | |
| 226 | |
| 227 // Whether we've loaded the last session. | |
| 228 int load_state_; | |
| 229 | |
| 230 // Results from previously closed tabs/sessions is first added here. When the | |
| 231 // results from both us and the session restore service have finished loading | |
| 232 // LoadStateChanged is invoked, which adds these entries to entries_. | |
| 233 std::vector<Entry*> staging_entries_; | |
| 234 | |
| 235 // Used when loading previous tabs/session. | |
| 236 CancelableRequestConsumer load_consumer_; | |
| 237 | |
| 238 // Used when loading open tabs/session when recovering from a crash. | |
| 239 CancelableRequestConsumer crash_consumer_; | |
| 240 | |
| 241 DISALLOW_COPY_AND_ASSIGN(Delegate); | |
| 106 }; | 242 }; |
| 107 | 243 |
| 108 // Payload used for the start of a tab close. This is the old struct that is | 244 PersistentTabRestoreService::Delegate::Delegate(Profile* profile) |
| 109 // used for backwards compat when it comes to reading the session files. | 245 : BaseSessionService(BaseSessionService::TAB_RESTORE, profile, |
| 110 struct SelectedNavigationInTabPayload { | 246 FilePath()), |
| 111 SessionID::id_type id; | 247 tab_restore_service_helper_(NULL), |
| 112 int32 index; | 248 entries_to_write_(0), |
| 113 }; | 249 entries_written_(0), |
| 114 | 250 load_state_(NOT_LOADED) { |
| 115 // Payload used for the start of a window close. This struct must be POD, | 251 } |
| 116 // because we memset the contents. | 252 |
| 117 struct WindowPayload2 : WindowPayload { | 253 PersistentTabRestoreService::Delegate::~Delegate() { |
| 118 int64 timestamp; | 254 STLDeleteElements(&staging_entries_); |
| 119 }; | 255 } |
| 120 | 256 |
| 121 // Payload used for the start of a tab close. | 257 void PersistentTabRestoreService::Delegate::Save() { |
| 122 struct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload { | 258 const Entries& entries = tab_restore_service_helper_->entries(); |
| 123 int64 timestamp; | 259 int to_write_count = std::min(entries_to_write_, |
| 124 }; | 260 static_cast<int>(entries.size())); |
| 125 | 261 entries_to_write_ = 0; |
| 126 // Only written if the tab is pinned. | 262 if (entries_written_ + to_write_count > kEntriesPerReset) { |
| 127 typedef bool PinnedStatePayload; | 263 to_write_count = entries.size(); |
| 128 | 264 set_pending_reset(true); |
| 129 typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry; | |
| 130 | |
| 131 // If |id_to_entry| contains an entry for |id| the corresponding entry is | |
| 132 // deleted and removed from both |id_to_entry| and |entries|. This is used | |
| 133 // when creating entries from the backend file. | |
| 134 void RemoveEntryByID(SessionID::id_type id, | |
| 135 IDToEntry* id_to_entry, | |
| 136 std::vector<TabRestoreService::Entry*>* entries) { | |
| 137 // Look for the entry in the map. If it is present, erase it from both | |
| 138 // collections and return. | |
| 139 IDToEntry::iterator i = id_to_entry->find(id); | |
| 140 if (i != id_to_entry->end()) { | |
| 141 entries->erase(std::find(entries->begin(), entries->end(), i->second)); | |
| 142 delete i->second; | |
| 143 id_to_entry->erase(i); | |
| 144 return; | |
| 145 } | 265 } |
| 146 | 266 if (to_write_count) { |
| 147 // Otherwise, loop over all items in the map and see if any of the Windows | 267 // Write the to_write_count most recently added entries out. The most |
| 148 // have Tabs with the |id|. | 268 // recently added entry is at the front, so we use a reverse iterator to |
| 149 for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end(); | 269 // write in the order the entries were added. |
| 150 ++i) { | 270 Entries::const_reverse_iterator i = entries.rbegin(); |
| 151 if (i->second->type == TabRestoreService::WINDOW) { | 271 DCHECK(static_cast<size_t>(to_write_count) <= entries.size()); |
| 152 TabRestoreService::Window* window = | 272 std::advance(i, entries.size() - static_cast<int>(to_write_count)); |
| 153 static_cast<TabRestoreService::Window*>(i->second); | 273 for (; i != entries.rend(); ++i) { |
| 154 std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin(); | 274 Entry* entry = *i; |
| 155 for ( ; j != window->tabs.end(); ++j) { | 275 if (entry->type == TAB) { |
| 156 // If the ID matches one of this window's tabs, remove it from the list. | 276 Tab* tab = static_cast<Tab*>(entry); |
| 157 if ((*j).id == id) { | 277 int selected_index = GetSelectedNavigationIndexToPersist(*tab); |
| 158 window->tabs.erase(j); | 278 if (selected_index != -1) |
| 159 return; | 279 ScheduleCommandsForTab(*tab, selected_index); |
| 160 } | 280 } else { |
| 281 ScheduleCommandsForWindow(*static_cast<Window*>(entry)); | |
| 161 } | 282 } |
| 283 entries_written_++; | |
| 162 } | 284 } |
| 163 } | 285 } |
| 286 if (pending_reset()) | |
| 287 entries_written_ = 0; | |
| 288 BaseSessionService::Save(); | |
| 164 } | 289 } |
| 165 | 290 |
| 166 void RecordAppLaunch(Profile* profile, const TabRestoreService::Tab& tab) { | 291 void PersistentTabRestoreService::Delegate::OnClearEntries() { |
| 167 GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url(); | |
| 168 DCHECK(profile->GetExtensionService()); | |
| 169 if (!profile->GetExtensionService()->IsInstalledApp(url)) | |
| 170 return; | |
| 171 | |
| 172 AppLauncherHandler::RecordAppLaunchType( | |
| 173 extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED); | |
| 174 } | |
| 175 | |
| 176 } // namespace | |
| 177 | |
| 178 TabRestoreService::Tab::Tab() | |
| 179 : Entry(TAB), | |
| 180 current_navigation_index(-1), | |
| 181 browser_id(0), | |
| 182 tabstrip_index(-1), | |
| 183 pinned(false) { | |
| 184 } | |
| 185 | |
| 186 TabRestoreService::Tab::~Tab() { | |
| 187 } | |
| 188 | |
| 189 TabRestoreService::Window::Window() : Entry(WINDOW), selected_tab_index(-1) { | |
| 190 } | |
| 191 | |
| 192 TabRestoreService::Window::~Window() { | |
| 193 } | |
| 194 | |
| 195 TabRestoreService::TabRestoreService(Profile* profile, | |
| 196 TabRestoreService::TimeFactory* time_factory) | |
| 197 : BaseSessionService(BaseSessionService::TAB_RESTORE, profile, | |
| 198 FilePath()), | |
| 199 load_state_(NOT_LOADED), | |
| 200 restoring_(false), | |
| 201 entries_to_write_(0), | |
| 202 entries_written_(0), | |
| 203 time_factory_(time_factory) { | |
| 204 } | |
| 205 | |
| 206 TabRestoreService::~TabRestoreService() { | |
| 207 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, | |
| 208 TabRestoreServiceDestroyed(this)); | |
| 209 STLDeleteElements(&entries_); | |
| 210 STLDeleteElements(&staging_entries_); | |
| 211 time_factory_ = NULL; | |
| 212 } | |
| 213 | |
| 214 void TabRestoreService::AddObserver(TabRestoreServiceObserver* observer) { | |
| 215 observer_list_.AddObserver(observer); | |
| 216 } | |
| 217 | |
| 218 void TabRestoreService::RemoveObserver(TabRestoreServiceObserver* observer) { | |
| 219 observer_list_.RemoveObserver(observer); | |
| 220 } | |
| 221 | |
| 222 void TabRestoreService::CreateHistoricalTab(content::WebContents* contents, | |
| 223 int index) { | |
| 224 if (restoring_) | |
| 225 return; | |
| 226 | |
| 227 TabRestoreServiceDelegate* delegate = | |
| 228 TabRestoreServiceDelegate::FindDelegateForWebContents(contents); | |
| 229 if (closing_delegates_.find(delegate) != closing_delegates_.end()) | |
| 230 return; | |
| 231 | |
| 232 scoped_ptr<Tab> local_tab(new Tab()); | |
| 233 PopulateTab(local_tab.get(), index, delegate, &contents->GetController()); | |
| 234 if (local_tab->navigations.empty()) | |
| 235 return; | |
| 236 | |
| 237 AddEntry(local_tab.release(), true, true); | |
| 238 } | |
| 239 | |
| 240 void TabRestoreService::BrowserClosing(TabRestoreServiceDelegate* delegate) { | |
| 241 closing_delegates_.insert(delegate); | |
| 242 | |
| 243 scoped_ptr<Window> window(new Window()); | |
| 244 window->selected_tab_index = delegate->GetSelectedIndex(); | |
| 245 window->timestamp = TimeNow(); | |
| 246 window->app_name = delegate->GetAppName(); | |
| 247 | |
| 248 // Don't use std::vector::resize() because it will push copies of an empty tab | |
| 249 // into the vector, which will give all tabs in a window the same ID. | |
| 250 for (int i = 0; i < delegate->GetTabCount(); ++i) { | |
| 251 window->tabs.push_back(Tab()); | |
| 252 } | |
| 253 size_t entry_index = 0; | |
| 254 for (int tab_index = 0; tab_index < delegate->GetTabCount(); ++tab_index) { | |
| 255 PopulateTab(&(window->tabs[entry_index]), | |
| 256 tab_index, | |
| 257 delegate, | |
| 258 &delegate->GetWebContentsAt(tab_index)->GetController()); | |
| 259 if (window->tabs[entry_index].navigations.empty()) { | |
| 260 window->tabs.erase(window->tabs.begin() + entry_index); | |
| 261 } else { | |
| 262 window->tabs[entry_index].browser_id = delegate->GetSessionID().id(); | |
| 263 entry_index++; | |
| 264 } | |
| 265 } | |
| 266 if (window->tabs.size() == 1 && window->app_name.empty()) { | |
| 267 // Short-circuit creating a Window if only 1 tab was present. This fixes | |
| 268 // http://crbug.com/56744. Copy the Tab because it's owned by an object on | |
| 269 // the stack. | |
| 270 AddEntry(new Tab(window->tabs[0]), true, true); | |
| 271 } else if (!window->tabs.empty()) { | |
| 272 window->selected_tab_index = | |
| 273 std::min(static_cast<int>(window->tabs.size() - 1), | |
| 274 window->selected_tab_index); | |
| 275 AddEntry(window.release(), true, true); | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 void TabRestoreService::BrowserClosed(TabRestoreServiceDelegate* delegate) { | |
| 280 closing_delegates_.erase(delegate); | |
| 281 } | |
| 282 | |
| 283 void TabRestoreService::ClearEntries() { | |
| 284 // Mark all the tabs as closed so that we don't attempt to restore them. | 292 // Mark all the tabs as closed so that we don't attempt to restore them. |
| 285 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) | 293 const Entries& entries = tab_restore_service_helper_->entries(); |
| 294 for (Entries::const_iterator i = entries.begin(); i != entries.end(); ++i) | |
| 286 ScheduleCommand(CreateRestoredEntryCommand((*i)->id)); | 295 ScheduleCommand(CreateRestoredEntryCommand((*i)->id)); |
| 287 | 296 |
| 288 entries_to_write_ = 0; | 297 entries_to_write_ = 0; |
| 289 | 298 |
| 290 // Schedule a pending reset so that we nuke the file on next write. | 299 // Schedule a pending reset so that we nuke the file on next write. |
| 291 set_pending_reset(true); | 300 set_pending_reset(true); |
| 292 | 301 |
| 293 // Schedule a command, otherwise if there are no pending commands Save does | 302 // Schedule a command, otherwise if there are no pending commands Save does |
| 294 // nothing. | 303 // nothing. |
| 295 ScheduleCommand(CreateRestoredEntryCommand(1)); | 304 ScheduleCommand(CreateRestoredEntryCommand(1)); |
| 296 | |
| 297 STLDeleteElements(&entries_); | |
| 298 NotifyTabsChanged(); | |
| 299 } | 305 } |
| 300 | 306 |
| 301 const TabRestoreService::Entries& TabRestoreService::entries() const { | 307 void PersistentTabRestoreService::Delegate::OnRestoreEntryById( |
| 302 return entries_; | 308 SessionID::id_type id, |
| 303 } | 309 Entries::const_iterator entry_iterator) { |
| 304 | |
| 305 void TabRestoreService::RestoreMostRecentEntry( | |
| 306 TabRestoreServiceDelegate* delegate) { | |
| 307 if (entries_.empty()) | |
| 308 return; | |
| 309 | |
| 310 RestoreEntryById(delegate, entries_.front()->id, UNKNOWN); | |
| 311 } | |
| 312 | |
| 313 TabRestoreService::Tab* TabRestoreService::RemoveTabEntryById( | |
| 314 SessionID::id_type id) { | |
| 315 Entries::iterator i = GetEntryIteratorById(id); | |
| 316 if (i == entries_.end()) | |
| 317 return NULL; | |
| 318 | |
| 319 Entry* entry = *i; | |
| 320 if (entry->type != TAB) | |
| 321 return NULL; | |
| 322 | |
| 323 Tab* tab = static_cast<Tab*>(entry); | |
| 324 entries_.erase(i); | |
| 325 return tab; | |
| 326 } | |
| 327 | |
| 328 void TabRestoreService::RestoreEntryById(TabRestoreServiceDelegate* delegate, | |
| 329 SessionID::id_type id, | |
| 330 WindowOpenDisposition disposition) { | |
| 331 Entries::iterator i = GetEntryIteratorById(id); | |
| 332 if (i == entries_.end()) { | |
| 333 // Don't hoark here, we allow an invalid id. | |
| 334 return; | |
| 335 } | |
| 336 | |
| 337 size_t index = 0; | 310 size_t index = 0; |
| 338 for (Entries::iterator j = entries_.begin(); j != i && j != entries_.end(); | 311 const Entries& entries = tab_restore_service_helper_->entries(); |
| 312 for (Entries::const_iterator j = entries.begin(); | |
| 313 j != entry_iterator && j != entries.end(); | |
| 339 ++j, ++index) {} | 314 ++j, ++index) {} |
| 340 if (static_cast<int>(index) < entries_to_write_) | 315 if (static_cast<int>(index) < entries_to_write_) |
| 341 entries_to_write_--; | 316 entries_to_write_--; |
| 342 | 317 |
| 343 ScheduleCommand(CreateRestoredEntryCommand(id)); | 318 ScheduleCommand(CreateRestoredEntryCommand(id)); |
| 344 | |
| 345 restoring_ = true; | |
| 346 Entry* entry = *i; | |
| 347 | |
| 348 // If the entry's ID does not match the ID that is being restored, then the | |
| 349 // entry is a window from which a single tab will be restored. | |
| 350 bool restoring_tab_in_window = entry->id != id; | |
| 351 | |
| 352 if (!restoring_tab_in_window) { | |
| 353 entries_.erase(i); | |
| 354 i = entries_.end(); | |
| 355 } | |
| 356 | |
| 357 // |delegate| will be NULL in cases where one isn't already available (eg, | |
| 358 // when invoked on Mac OS X with no windows open). In this case, create a | |
| 359 // new browser into which we restore the tabs. | |
| 360 if (entry->type == TAB) { | |
| 361 Tab* tab = static_cast<Tab*>(entry); | |
| 362 delegate = RestoreTab(*tab, delegate, disposition); | |
| 363 delegate->ShowBrowserWindow(); | |
| 364 } else if (entry->type == WINDOW) { | |
| 365 TabRestoreServiceDelegate* current_delegate = delegate; | |
| 366 Window* window = static_cast<Window*>(entry); | |
| 367 | |
| 368 // When restoring a window, either the entire window can be restored, or a | |
| 369 // single tab within it. If the entry's ID matches the one to restore, then | |
| 370 // the entire window will be restored. | |
| 371 if (!restoring_tab_in_window) { | |
| 372 delegate = TabRestoreServiceDelegate::Create(profile(), window->app_name); | |
| 373 for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { | |
| 374 const Tab& tab = window->tabs[tab_i]; | |
| 375 WebContents* restored_tab = | |
| 376 delegate->AddRestoredTab(tab.navigations, delegate->GetTabCount(), | |
| 377 tab.current_navigation_index, | |
| 378 tab.extension_app_id, | |
| 379 static_cast<int>(tab_i) == | |
| 380 window->selected_tab_index, | |
| 381 tab.pinned, tab.from_last_session, | |
| 382 tab.session_storage_namespace, | |
| 383 tab.user_agent_override); | |
| 384 if (restored_tab) { | |
| 385 restored_tab->GetController().LoadIfNecessary(); | |
| 386 RecordAppLaunch(profile(), tab); | |
| 387 } | |
| 388 } | |
| 389 // All the window's tabs had the same former browser_id. | |
| 390 if (window->tabs[0].has_browser()) { | |
| 391 UpdateTabBrowserIDs(window->tabs[0].browser_id, | |
| 392 delegate->GetSessionID().id()); | |
| 393 } | |
| 394 } else { | |
| 395 // Restore a single tab from the window. Find the tab that matches the ID | |
| 396 // in the window and restore it. | |
| 397 for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); | |
| 398 tab_i != window->tabs.end(); ++tab_i) { | |
| 399 const Tab& tab = *tab_i; | |
| 400 if (tab.id == id) { | |
| 401 delegate = RestoreTab(tab, delegate, disposition); | |
| 402 window->tabs.erase(tab_i); | |
| 403 // If restoring the tab leaves the window with nothing else, delete it | |
| 404 // as well. | |
| 405 if (!window->tabs.size()) { | |
| 406 entries_.erase(i); | |
| 407 delete entry; | |
| 408 } else { | |
| 409 // Update the browser ID of the rest of the tabs in the window so if | |
| 410 // any one is restored, it goes into the same window as the tab | |
| 411 // being restored now. | |
| 412 UpdateTabBrowserIDs(tab.browser_id, | |
| 413 delegate->GetSessionID().id()); | |
| 414 for (std::vector<Tab>::iterator tab_j = window->tabs.begin(); | |
| 415 tab_j != window->tabs.end(); ++tab_j) { | |
| 416 (*tab_j).browser_id = delegate->GetSessionID().id(); | |
| 417 } | |
| 418 } | |
| 419 break; | |
| 420 } | |
| 421 } | |
| 422 } | |
| 423 delegate->ShowBrowserWindow(); | |
| 424 | |
| 425 if (disposition == CURRENT_TAB && current_delegate && | |
| 426 current_delegate->GetActiveWebContents()) { | |
| 427 current_delegate->CloseTab(); | |
| 428 } | |
| 429 } else { | |
| 430 NOTREACHED(); | |
| 431 } | |
| 432 | |
| 433 if (!restoring_tab_in_window) { | |
| 434 delete entry; | |
| 435 } | |
| 436 | |
| 437 restoring_ = false; | |
| 438 NotifyTabsChanged(); | |
| 439 } | 319 } |
| 440 | 320 |
| 441 void TabRestoreService::LoadTabsFromLastSession() { | 321 void PersistentTabRestoreService::Delegate::OnAddEntry() { |
| 442 if (load_state_ != NOT_LOADED || entries_.size() == kMaxEntries) | 322 // Start the save timer, when it fires we'll generate the commands. |
| 323 StartSaveTimer(); | |
| 324 entries_to_write_++; | |
| 325 } | |
| 326 | |
| 327 void PersistentTabRestoreService::Delegate::LoadTabsFromLastSession() { | |
| 328 if (load_state_ != NOT_LOADED || | |
| 329 tab_restore_service_helper_->entries().size() == kMaxEntries) | |
| 443 return; | 330 return; |
| 444 | 331 |
| 445 #if !defined(ENABLE_SESSION_SERVICE) | 332 #if !defined(ENABLE_SESSION_SERVICE) |
| 446 // If sessions are not stored in the SessionService, default to | 333 // If sessions are not stored in the SessionService, default to |
| 447 // |LOADED_LAST_SESSION| state. | 334 // |LOADED_LAST_SESSION| state. |
| 448 load_state_ = LOADING | LOADED_LAST_SESSION; | 335 load_state_ = LOADING | LOADED_LAST_SESSION; |
| 449 #else | 336 #else |
| 450 load_state_ = LOADING; | 337 load_state_ = LOADING; |
| 451 | 338 |
| 452 SessionService* session_service = | 339 SessionService* session_service = |
| 453 SessionServiceFactory::GetForProfile(profile()); | 340 SessionServiceFactory::GetForProfile(profile()); |
| 454 Profile::ExitType exit_type = profile()->GetLastSessionExitType(); | 341 Profile::ExitType exit_type = profile()->GetLastSessionExitType(); |
| 455 if (!profile()->restored_last_session() && session_service && | 342 if (!profile()->restored_last_session() && session_service && |
| 456 (exit_type == Profile::EXIT_CRASHED || | 343 (exit_type == Profile::EXIT_CRASHED || |
| 457 exit_type == Profile::EXIT_SESSION_ENDED)) { | 344 exit_type == Profile::EXIT_SESSION_ENDED)) { |
| 458 // The previous session crashed and wasn't restored, or was a forced | 345 // The previous session crashed and wasn't restored, or was a forced |
| 459 // shutdown. Both of which won't have notified us of the browser close so | 346 // shutdown. Both of which won't have notified us of the browser close so |
| 460 // that we need to load the windows from session service (which will have | 347 // that we need to load the windows from session service (which will have |
| 461 // saved them). | 348 // saved them). |
| 462 session_service->GetLastSession( | 349 session_service->GetLastSession( |
| 463 &crash_consumer_, | 350 &crash_consumer_, |
| 464 base::Bind(&TabRestoreService::OnGotPreviousSession, | 351 base::Bind(&Delegate::OnGotPreviousSession, base::Unretained(this))); |
| 465 base::Unretained(this))); | |
| 466 } else { | 352 } else { |
| 467 load_state_ |= LOADED_LAST_SESSION; | 353 load_state_ |= LOADED_LAST_SESSION; |
| 468 } | 354 } |
| 469 #endif | 355 #endif |
| 470 | 356 |
| 471 // Request the tabs closed in the last session. If the last session crashed, | 357 // Request the tabs closed in the last session. If the last session crashed, |
| 472 // this won't contain the tabs/window that were open at the point of the | 358 // this won't contain the tabs/window that were open at the point of the |
| 473 // crash (the call to GetLastSession above requests those). | 359 // crash (the call to GetLastSession above requests those). |
| 474 ScheduleGetLastSessionCommands( | 360 ScheduleGetLastSessionCommands( |
| 475 new InternalGetCommandsRequest( | 361 new InternalGetCommandsRequest( |
| 476 base::Bind(&TabRestoreService::OnGotLastSessionCommands, | 362 base::Bind(&Delegate::OnGotLastSessionCommands, |
| 477 base::Unretained(this))), | 363 base::Unretained(this))), |
| 478 &load_consumer_); | 364 &load_consumer_); |
| 479 } | 365 } |
| 480 | 366 |
| 481 bool TabRestoreService::IsLoaded() const { | 367 bool PersistentTabRestoreService::Delegate::IsLoaded() const { |
| 482 return !(load_state_ & (NOT_LOADED | LOADING)); | 368 return !(load_state_ & (NOT_LOADED | LOADING)); |
| 483 } | 369 } |
| 484 | 370 |
| 485 void TabRestoreService::Shutdown() { | 371 // static |
| 372 void PersistentTabRestoreService::Delegate::CreateEntriesFromWindows( | |
| 373 std::vector<SessionWindow*>* windows, | |
| 374 std::vector<Entry*>* entries) { | |
| 375 for (size_t i = 0; i < windows->size(); ++i) { | |
| 376 scoped_ptr<Window> window(new Window()); | |
| 377 if (ConvertSessionWindowToWindow((*windows)[i], window.get())) | |
| 378 entries->push_back(window.release()); | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 void PersistentTabRestoreService::Delegate::Shutdown() { | |
| 486 if (backend()) | 383 if (backend()) |
| 487 Save(); | 384 Save(); |
| 488 } | 385 } |
| 489 | 386 |
| 490 void TabRestoreService::Save() { | 387 void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow( |
| 491 int to_write_count = std::min(entries_to_write_, | 388 const Window& window) { |
| 492 static_cast<int>(entries_.size())); | |
| 493 entries_to_write_ = 0; | |
| 494 if (entries_written_ + to_write_count > kEntriesPerReset) { | |
| 495 to_write_count = entries_.size(); | |
| 496 set_pending_reset(true); | |
| 497 } | |
| 498 if (to_write_count) { | |
| 499 // Write the to_write_count most recently added entries out. The most | |
| 500 // recently added entry is at the front, so we use a reverse iterator to | |
| 501 // write in the order the entries were added. | |
| 502 Entries::reverse_iterator i = entries_.rbegin(); | |
| 503 DCHECK(static_cast<size_t>(to_write_count) <= entries_.size()); | |
| 504 std::advance(i, entries_.size() - static_cast<int>(to_write_count)); | |
| 505 for (; i != entries_.rend(); ++i) { | |
| 506 Entry* entry = *i; | |
| 507 if (entry->type == TAB) { | |
| 508 Tab* tab = static_cast<Tab*>(entry); | |
| 509 int selected_index = GetSelectedNavigationIndexToPersist(*tab); | |
| 510 if (selected_index != -1) | |
| 511 ScheduleCommandsForTab(*tab, selected_index); | |
| 512 } else { | |
| 513 ScheduleCommandsForWindow(*static_cast<Window*>(entry)); | |
| 514 } | |
| 515 entries_written_++; | |
| 516 } | |
| 517 } | |
| 518 if (pending_reset()) | |
| 519 entries_written_ = 0; | |
| 520 BaseSessionService::Save(); | |
| 521 } | |
| 522 | |
| 523 void TabRestoreService::PopulateTab(Tab* tab, | |
| 524 int index, | |
| 525 TabRestoreServiceDelegate* delegate, | |
| 526 NavigationController* controller) { | |
| 527 const int pending_index = controller->GetPendingEntryIndex(); | |
| 528 int entry_count = controller->GetEntryCount(); | |
| 529 if (entry_count == 0 && pending_index == 0) | |
| 530 entry_count++; | |
| 531 tab->navigations.resize(static_cast<int>(entry_count)); | |
| 532 for (int i = 0; i < entry_count; ++i) { | |
| 533 NavigationEntry* entry = (i == pending_index) ? | |
| 534 controller->GetPendingEntry() : controller->GetEntryAtIndex(i); | |
| 535 tab->navigations[i] = | |
| 536 TabNavigation::FromNavigationEntry(i, *entry); | |
| 537 } | |
| 538 tab->timestamp = TimeNow(); | |
| 539 tab->current_navigation_index = controller->GetCurrentEntryIndex(); | |
| 540 if (tab->current_navigation_index == -1 && entry_count > 0) | |
| 541 tab->current_navigation_index = 0; | |
| 542 tab->tabstrip_index = index; | |
| 543 | |
| 544 TabContents* tab_contents = | |
| 545 TabContents::FromWebContents(controller->GetWebContents()); | |
| 546 // tab_contents is NULL in some browser tests. | |
| 547 if (tab_contents) { | |
| 548 const extensions::Extension* extension = | |
| 549 extensions::TabHelper::FromWebContents(controller->GetWebContents())-> | |
| 550 extension_app(); | |
| 551 if (extension) | |
| 552 tab->extension_app_id = extension->id(); | |
| 553 } | |
| 554 | |
| 555 tab->user_agent_override = | |
| 556 controller->GetWebContents()->GetUserAgentOverride(); | |
| 557 | |
| 558 // TODO(ajwong): This does not correctly handle storage for isolated apps. | |
| 559 tab->session_storage_namespace = | |
| 560 controller->GetDefaultSessionStorageNamespace(); | |
| 561 | |
| 562 // Delegate may be NULL during unit tests. | |
| 563 if (delegate) { | |
| 564 tab->browser_id = delegate->GetSessionID().id(); | |
| 565 tab->pinned = delegate->IsTabPinned(tab->tabstrip_index); | |
| 566 } | |
| 567 } | |
| 568 | |
| 569 void TabRestoreService::NotifyTabsChanged() { | |
| 570 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, | |
| 571 TabRestoreServiceChanged(this)); | |
| 572 } | |
| 573 | |
| 574 void TabRestoreService::AddEntry(Entry* entry, bool notify, bool to_front) { | |
| 575 if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) { | |
| 576 delete entry; | |
| 577 return; | |
| 578 } | |
| 579 | |
| 580 if (to_front) | |
| 581 entries_.push_front(entry); | |
| 582 else | |
| 583 entries_.push_back(entry); | |
| 584 | |
| 585 PruneEntries(); | |
| 586 | |
| 587 if (notify) | |
| 588 NotifyTabsChanged(); | |
| 589 | |
| 590 // Start the save timer, when it fires we'll generate the commands. | |
| 591 StartSaveTimer(); | |
| 592 entries_to_write_++; | |
| 593 } | |
| 594 | |
| 595 void TabRestoreService::PruneEntries() { | |
| 596 Entries new_entries; | |
| 597 | |
| 598 for (TabRestoreService::Entries::const_iterator iter = entries_.begin(); | |
| 599 iter != entries_.end(); ++iter) { | |
| 600 TabRestoreService::Entry* entry = *iter; | |
| 601 | |
| 602 if (FilterEntry(entry) && | |
| 603 new_entries.size() < kMaxEntries) { | |
| 604 new_entries.push_back(entry); | |
| 605 } else { | |
| 606 delete entry; | |
| 607 } | |
| 608 } | |
| 609 | |
| 610 entries_ = new_entries; | |
| 611 } | |
| 612 | |
| 613 TabRestoreService::Entries::iterator TabRestoreService::GetEntryIteratorById( | |
| 614 SessionID::id_type id) { | |
| 615 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { | |
| 616 if ((*i)->id == id) | |
| 617 return i; | |
| 618 | |
| 619 // For Window entries, see if the ID matches a tab. If so, report the window | |
| 620 // as the Entry. | |
| 621 if ((*i)->type == WINDOW) { | |
| 622 std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs; | |
| 623 for (std::vector<Tab>::iterator j = tabs.begin(); | |
| 624 j != tabs.end(); ++j) { | |
| 625 if ((*j).id == id) { | |
| 626 return i; | |
| 627 } | |
| 628 } | |
| 629 } | |
| 630 } | |
| 631 return entries_.end(); | |
| 632 } | |
| 633 | |
| 634 void TabRestoreService::ScheduleCommandsForWindow(const Window& window) { | |
| 635 DCHECK(!window.tabs.empty()); | 389 DCHECK(!window.tabs.empty()); |
| 636 int selected_tab = window.selected_tab_index; | 390 int selected_tab = window.selected_tab_index; |
| 637 int valid_tab_count = 0; | 391 int valid_tab_count = 0; |
| 638 int real_selected_tab = selected_tab; | 392 int real_selected_tab = selected_tab; |
| 639 for (size_t i = 0; i < window.tabs.size(); ++i) { | 393 for (size_t i = 0; i < window.tabs.size(); ++i) { |
| 640 if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) { | 394 if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) { |
| 641 valid_tab_count++; | 395 valid_tab_count++; |
| 642 } else if (static_cast<int>(i) < selected_tab) { | 396 } else if (static_cast<int>(i) < selected_tab) { |
| 643 real_selected_tab--; | 397 real_selected_tab--; |
| 644 } | 398 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 659 window.app_name)); | 413 window.app_name)); |
| 660 } | 414 } |
| 661 | 415 |
| 662 for (size_t i = 0; i < window.tabs.size(); ++i) { | 416 for (size_t i = 0; i < window.tabs.size(); ++i) { |
| 663 int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]); | 417 int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]); |
| 664 if (selected_index != -1) | 418 if (selected_index != -1) |
| 665 ScheduleCommandsForTab(window.tabs[i], selected_index); | 419 ScheduleCommandsForTab(window.tabs[i], selected_index); |
| 666 } | 420 } |
| 667 } | 421 } |
| 668 | 422 |
| 669 void TabRestoreService::ScheduleCommandsForTab(const Tab& tab, | 423 void PersistentTabRestoreService::Delegate::ScheduleCommandsForTab( |
| 670 int selected_index) { | 424 const Tab& tab, |
| 425 int selected_index) { | |
| 671 const std::vector<TabNavigation>& navigations = tab.navigations; | 426 const std::vector<TabNavigation>& navigations = tab.navigations; |
| 672 int max_index = static_cast<int>(navigations.size()); | 427 int max_index = static_cast<int>(navigations.size()); |
| 673 | 428 |
| 674 // Determine the first navigation we'll persist. | 429 // Determine the first navigation we'll persist. |
| 675 int valid_count_before_selected = 0; | 430 int valid_count_before_selected = 0; |
| 676 int first_index_to_persist = selected_index; | 431 int first_index_to_persist = selected_index; |
| 677 for (int i = selected_index - 1; i >= 0 && | 432 for (int i = selected_index - 1; i >= 0 && |
| 678 valid_count_before_selected < max_persist_navigation_count; --i) { | 433 valid_count_before_selected < max_persist_navigation_count; --i) { |
| 679 if (ShouldTrackEntry(navigations[i].virtual_url())) { | 434 if (ShouldTrackEntry(navigations[i].virtual_url())) { |
| 680 first_index_to_persist = i; | 435 first_index_to_persist = i; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 712 for (int i = first_index_to_persist, wrote_count = 0; | 467 for (int i = first_index_to_persist, wrote_count = 0; |
| 713 i < max_index && wrote_count < 2 * max_persist_navigation_count; ++i) { | 468 i < max_index && wrote_count < 2 * max_persist_navigation_count; ++i) { |
| 714 if (ShouldTrackEntry(navigations[i].virtual_url())) { | 469 if (ShouldTrackEntry(navigations[i].virtual_url())) { |
| 715 ScheduleCommand( | 470 ScheduleCommand( |
| 716 CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation, tab.id, | 471 CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation, tab.id, |
| 717 navigations[i])); | 472 navigations[i])); |
| 718 } | 473 } |
| 719 } | 474 } |
| 720 } | 475 } |
| 721 | 476 |
| 722 SessionCommand* TabRestoreService::CreateWindowCommand(SessionID::id_type id, | 477 // static |
| 723 int selected_tab_index, | 478 SessionCommand* PersistentTabRestoreService::Delegate::CreateWindowCommand( |
| 724 int num_tabs, | 479 SessionID::id_type id, |
| 725 Time timestamp) { | 480 int selected_tab_index, |
| 481 int num_tabs, | |
| 482 base::Time timestamp) { | |
| 726 WindowPayload2 payload; | 483 WindowPayload2 payload; |
| 727 // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of | 484 // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of |
| 728 // uninitialized memory in the struct. | 485 // uninitialized memory in the struct. |
| 729 memset(&payload, 0, sizeof(payload)); | 486 memset(&payload, 0, sizeof(payload)); |
| 730 payload.window_id = id; | 487 payload.window_id = id; |
| 731 payload.selected_tab_index = selected_tab_index; | 488 payload.selected_tab_index = selected_tab_index; |
| 732 payload.num_tabs = num_tabs; | 489 payload.num_tabs = num_tabs; |
| 733 payload.timestamp = timestamp.ToInternalValue(); | 490 payload.timestamp = timestamp.ToInternalValue(); |
| 734 | 491 |
| 735 SessionCommand* command = | 492 SessionCommand* command = |
| 736 new SessionCommand(kCommandWindow, sizeof(payload)); | 493 new SessionCommand(kCommandWindow, sizeof(payload)); |
| 737 memcpy(command->contents(), &payload, sizeof(payload)); | 494 memcpy(command->contents(), &payload, sizeof(payload)); |
| 738 return command; | 495 return command; |
| 739 } | 496 } |
| 740 | 497 |
| 741 SessionCommand* TabRestoreService::CreateSelectedNavigationInTabCommand( | 498 // static |
| 499 SessionCommand* | |
| 500 PersistentTabRestoreService::Delegate::CreateSelectedNavigationInTabCommand( | |
| 742 SessionID::id_type tab_id, | 501 SessionID::id_type tab_id, |
| 743 int32 index, | 502 int32 index, |
| 744 Time timestamp) { | 503 base::Time timestamp) { |
| 745 SelectedNavigationInTabPayload2 payload; | 504 SelectedNavigationInTabPayload2 payload; |
| 746 payload.id = tab_id; | 505 payload.id = tab_id; |
| 747 payload.index = index; | 506 payload.index = index; |
| 748 payload.timestamp = timestamp.ToInternalValue(); | 507 payload.timestamp = timestamp.ToInternalValue(); |
| 749 SessionCommand* command = | 508 SessionCommand* command = |
| 750 new SessionCommand(kCommandSelectedNavigationInTab, sizeof(payload)); | 509 new SessionCommand(kCommandSelectedNavigationInTab, sizeof(payload)); |
| 751 memcpy(command->contents(), &payload, sizeof(payload)); | 510 memcpy(command->contents(), &payload, sizeof(payload)); |
| 752 return command; | 511 return command; |
| 753 } | 512 } |
| 754 | 513 |
| 755 SessionCommand* TabRestoreService::CreateRestoredEntryCommand( | 514 // static |
| 515 SessionCommand* | |
| 516 PersistentTabRestoreService::Delegate::CreateRestoredEntryCommand( | |
| 756 SessionID::id_type entry_id) { | 517 SessionID::id_type entry_id) { |
| 757 RestoredEntryPayload payload = entry_id; | 518 RestoredEntryPayload payload = entry_id; |
| 758 SessionCommand* command = | 519 SessionCommand* command = |
| 759 new SessionCommand(kCommandRestoredEntry, sizeof(payload)); | 520 new SessionCommand(kCommandRestoredEntry, sizeof(payload)); |
| 760 memcpy(command->contents(), &payload, sizeof(payload)); | 521 memcpy(command->contents(), &payload, sizeof(payload)); |
| 761 return command; | 522 return command; |
| 762 } | 523 } |
| 763 | 524 |
| 764 int TabRestoreService::GetSelectedNavigationIndexToPersist(const Tab& tab) { | 525 int PersistentTabRestoreService::Delegate::GetSelectedNavigationIndexToPersist( |
| 526 const Tab& tab) { | |
| 765 const std::vector<TabNavigation>& navigations = tab.navigations; | 527 const std::vector<TabNavigation>& navigations = tab.navigations; |
| 766 int selected_index = tab.current_navigation_index; | 528 int selected_index = tab.current_navigation_index; |
| 767 int max_index = static_cast<int>(navigations.size()); | 529 int max_index = static_cast<int>(navigations.size()); |
| 768 | 530 |
| 769 // Find the first navigation to persist. We won't persist the selected | 531 // Find the first navigation to persist. We won't persist the selected |
| 770 // navigation if ShouldTrackEntry returns false. | 532 // navigation if ShouldTrackEntry returns false. |
| 771 while (selected_index >= 0 && | 533 while (selected_index >= 0 && |
| 772 !ShouldTrackEntry(navigations[selected_index].virtual_url())) { | 534 !ShouldTrackEntry(navigations[selected_index].virtual_url())) { |
| 773 selected_index--; | 535 selected_index--; |
| 774 } | 536 } |
| 775 | 537 |
| 776 if (selected_index != -1) | 538 if (selected_index != -1) |
| 777 return selected_index; | 539 return selected_index; |
| 778 | 540 |
| 779 // Couldn't find a navigation to persist going back, go forward. | 541 // Couldn't find a navigation to persist going back, go forward. |
| 780 selected_index = tab.current_navigation_index + 1; | 542 selected_index = tab.current_navigation_index + 1; |
| 781 while (selected_index < max_index && | 543 while (selected_index < max_index && |
| 782 !ShouldTrackEntry(navigations[selected_index].virtual_url())) { | 544 !ShouldTrackEntry(navigations[selected_index].virtual_url())) { |
| 783 selected_index++; | 545 selected_index++; |
| 784 } | 546 } |
| 785 | 547 |
| 786 return (selected_index == max_index) ? -1 : selected_index; | 548 return (selected_index == max_index) ? -1 : selected_index; |
| 787 } | 549 } |
| 788 | 550 |
| 789 void TabRestoreService::OnGotLastSessionCommands( | 551 void PersistentTabRestoreService::Delegate::OnGotLastSessionCommands( |
| 790 Handle handle, | 552 Handle handle, |
| 791 scoped_refptr<InternalGetCommandsRequest> request) { | 553 scoped_refptr<InternalGetCommandsRequest> request) { |
| 792 std::vector<Entry*> entries; | 554 std::vector<Entry*> entries; |
| 793 CreateEntriesFromCommands(request, &entries); | 555 CreateEntriesFromCommands(request, &entries); |
| 794 // Closed tabs always go to the end. | 556 // Closed tabs always go to the end. |
| 795 staging_entries_.insert(staging_entries_.end(), entries.begin(), | 557 staging_entries_.insert(staging_entries_.end(), entries.begin(), |
| 796 entries.end()); | 558 entries.end()); |
| 797 load_state_ |= LOADED_LAST_TABS; | 559 load_state_ |= LOADED_LAST_TABS; |
| 798 LoadStateChanged(); | 560 LoadStateChanged(); |
| 799 } | 561 } |
| 800 | 562 |
| 801 void TabRestoreService::CreateEntriesFromCommands( | 563 void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands( |
| 802 scoped_refptr<InternalGetCommandsRequest> request, | 564 scoped_refptr<InternalGetCommandsRequest> request, |
| 803 std::vector<Entry*>* loaded_entries) { | 565 std::vector<Entry*>* loaded_entries) { |
| 804 if (request->canceled() || entries_.size() == kMaxEntries) | 566 if (request->canceled() || |
| 567 tab_restore_service_helper_->entries().size() == kMaxEntries) | |
| 805 return; | 568 return; |
| 806 | 569 |
| 807 std::vector<SessionCommand*>& commands = request->commands; | 570 std::vector<SessionCommand*>& commands = request->commands; |
| 808 // Iterate through the commands populating entries and id_to_entry. | 571 // Iterate through the commands populating entries and id_to_entry. |
| 809 ScopedVector<Entry> entries; | 572 ScopedVector<Entry> entries; |
| 810 IDToEntry id_to_entry; | 573 IDToEntry id_to_entry; |
| 811 // If non-null we're processing the navigations of this tab. | 574 // If non-null we're processing the navigations of this tab. |
| 812 Tab* current_tab = NULL; | 575 Tab* current_tab = NULL; |
| 813 // If non-null we're processing the tabs of this window. | 576 // If non-null we're processing the tabs of this window. |
| 814 Window* current_window = NULL; | 577 Window* current_window = NULL; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 862 pending_window_tabs = payload.num_tabs; | 625 pending_window_tabs = payload.num_tabs; |
| 863 if (pending_window_tabs <= 0) { | 626 if (pending_window_tabs <= 0) { |
| 864 // Should always have at least 1 tab. Likely indicates corruption. | 627 // Should always have at least 1 tab. Likely indicates corruption. |
| 865 return; | 628 return; |
| 866 } | 629 } |
| 867 | 630 |
| 868 RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get())); | 631 RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get())); |
| 869 | 632 |
| 870 current_window = new Window(); | 633 current_window = new Window(); |
| 871 current_window->selected_tab_index = payload.selected_tab_index; | 634 current_window->selected_tab_index = payload.selected_tab_index; |
| 872 current_window->timestamp = Time::FromInternalValue(payload.timestamp); | 635 current_window->timestamp = |
| 636 base::Time::FromInternalValue(payload.timestamp); | |
| 873 entries.push_back(current_window); | 637 entries.push_back(current_window); |
| 874 id_to_entry[payload.window_id] = current_window; | 638 id_to_entry[payload.window_id] = current_window; |
| 875 break; | 639 break; |
| 876 } | 640 } |
| 877 | 641 |
| 878 case kCommandSelectedNavigationInTab: { | 642 case kCommandSelectedNavigationInTab: { |
| 879 SelectedNavigationInTabPayload2 payload; | 643 SelectedNavigationInTabPayload2 payload; |
| 880 if (!command.GetPayload(&payload, sizeof(payload))) { | 644 if (!command.GetPayload(&payload, sizeof(payload))) { |
| 881 SelectedNavigationInTabPayload old_payload; | 645 SelectedNavigationInTabPayload old_payload; |
| 882 if (!command.GetPayload(&old_payload, sizeof(old_payload))) | 646 if (!command.GetPayload(&old_payload, sizeof(old_payload))) |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 895 return; | 659 return; |
| 896 } | 660 } |
| 897 current_window->tabs.resize(current_window->tabs.size() + 1); | 661 current_window->tabs.resize(current_window->tabs.size() + 1); |
| 898 current_tab = &(current_window->tabs.back()); | 662 current_tab = &(current_window->tabs.back()); |
| 899 if (--pending_window_tabs == 0) | 663 if (--pending_window_tabs == 0) |
| 900 current_window = NULL; | 664 current_window = NULL; |
| 901 } else { | 665 } else { |
| 902 RemoveEntryByID(payload.id, &id_to_entry, &(entries.get())); | 666 RemoveEntryByID(payload.id, &id_to_entry, &(entries.get())); |
| 903 current_tab = new Tab(); | 667 current_tab = new Tab(); |
| 904 id_to_entry[payload.id] = current_tab; | 668 id_to_entry[payload.id] = current_tab; |
| 905 current_tab->timestamp = Time::FromInternalValue(payload.timestamp); | 669 current_tab->timestamp = |
| 670 base::Time::FromInternalValue(payload.timestamp); | |
| 906 entries.push_back(current_tab); | 671 entries.push_back(current_tab); |
| 907 } | 672 } |
| 908 current_tab->current_navigation_index = payload.index; | 673 current_tab->current_navigation_index = payload.index; |
| 909 break; | 674 break; |
| 910 } | 675 } |
| 911 | 676 |
| 912 case kCommandUpdateTabNavigation: { | 677 case kCommandUpdateTabNavigation: { |
| 913 if (!current_tab) { | 678 if (!current_tab) { |
| 914 // Should be in a tab when we get this. | 679 // Should be in a tab when we get this. |
| 915 return; | 680 return; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 985 return; | 750 return; |
| 986 } | 751 } |
| 987 } | 752 } |
| 988 | 753 |
| 989 // If there was corruption some of the entries won't be valid. | 754 // If there was corruption some of the entries won't be valid. |
| 990 ValidateAndDeleteEmptyEntries(&(entries.get())); | 755 ValidateAndDeleteEmptyEntries(&(entries.get())); |
| 991 | 756 |
| 992 loaded_entries->swap(entries.get()); | 757 loaded_entries->swap(entries.get()); |
| 993 } | 758 } |
| 994 | 759 |
| 995 TabRestoreServiceDelegate* TabRestoreService::RestoreTab( | 760 // static |
| 996 const Tab& tab, | 761 void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries( |
| 997 TabRestoreServiceDelegate* delegate, | |
| 998 WindowOpenDisposition disposition) { | |
| 999 if (disposition == CURRENT_TAB && delegate) { | |
| 1000 delegate->ReplaceRestoredTab(tab.navigations, | |
| 1001 tab.current_navigation_index, | |
| 1002 tab.from_last_session, | |
| 1003 tab.extension_app_id, | |
| 1004 tab.session_storage_namespace, | |
| 1005 tab.user_agent_override); | |
| 1006 } else { | |
| 1007 // We only respsect the tab's original browser if there's no disposition. | |
| 1008 if (disposition == UNKNOWN && tab.has_browser()) | |
| 1009 delegate = TabRestoreServiceDelegate::FindDelegateWithID(tab.browser_id); | |
| 1010 | |
| 1011 int tab_index = -1; | |
| 1012 | |
| 1013 // |delegate| will be NULL in cases where one isn't already available (eg, | |
| 1014 // when invoked on Mac OS X with no windows open). In this case, create a | |
| 1015 // new browser into which we restore the tabs. | |
| 1016 if (delegate && disposition != NEW_WINDOW) { | |
| 1017 tab_index = tab.tabstrip_index; | |
| 1018 } else { | |
| 1019 delegate = TabRestoreServiceDelegate::Create(profile(), std::string()); | |
| 1020 if (tab.has_browser()) | |
| 1021 UpdateTabBrowserIDs(tab.browser_id, delegate->GetSessionID().id()); | |
| 1022 } | |
| 1023 | |
| 1024 // Place the tab at the end if the tab index is no longer valid or | |
| 1025 // we were passed a specific disposition. | |
| 1026 if (tab_index < 0 || tab_index > delegate->GetTabCount() || | |
| 1027 disposition != UNKNOWN) { | |
| 1028 tab_index = delegate->GetTabCount(); | |
| 1029 } | |
| 1030 | |
| 1031 WebContents* web_contents = delegate->AddRestoredTab( | |
| 1032 tab.navigations, | |
| 1033 tab_index, | |
| 1034 tab.current_navigation_index, | |
| 1035 tab.extension_app_id, | |
| 1036 disposition != NEW_BACKGROUND_TAB, | |
| 1037 tab.pinned, | |
| 1038 tab.from_last_session, | |
| 1039 tab.session_storage_namespace, | |
| 1040 tab.user_agent_override); | |
| 1041 web_contents->GetController().LoadIfNecessary(); | |
| 1042 } | |
| 1043 RecordAppLaunch(profile(), tab); | |
| 1044 return delegate; | |
| 1045 } | |
| 1046 | |
| 1047 | |
| 1048 bool TabRestoreService::ValidateTab(Tab* tab) { | |
| 1049 if (tab->navigations.empty()) | |
| 1050 return false; | |
| 1051 | |
| 1052 tab->current_navigation_index = | |
| 1053 std::max(0, std::min(tab->current_navigation_index, | |
| 1054 static_cast<int>(tab->navigations.size()) - 1)); | |
| 1055 | |
| 1056 return true; | |
| 1057 } | |
| 1058 | |
| 1059 bool TabRestoreService::ValidateWindow(Window* window) { | |
| 1060 window->selected_tab_index = | |
| 1061 std::max(0, std::min(window->selected_tab_index, | |
| 1062 static_cast<int>(window->tabs.size() - 1))); | |
| 1063 | |
| 1064 int i = 0; | |
| 1065 for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); | |
| 1066 tab_i != window->tabs.end();) { | |
| 1067 if (!ValidateTab(&(*tab_i))) { | |
| 1068 tab_i = window->tabs.erase(tab_i); | |
| 1069 if (i < window->selected_tab_index) | |
| 1070 window->selected_tab_index--; | |
| 1071 else if (i == window->selected_tab_index) | |
| 1072 window->selected_tab_index = 0; | |
| 1073 } else { | |
| 1074 ++tab_i; | |
| 1075 ++i; | |
| 1076 } | |
| 1077 } | |
| 1078 | |
| 1079 if (window->tabs.empty()) | |
| 1080 return false; | |
| 1081 | |
| 1082 return true; | |
| 1083 } | |
| 1084 | |
| 1085 bool TabRestoreService::ValidateEntry(Entry* entry) { | |
| 1086 if (entry->type == TAB) | |
| 1087 return ValidateTab(static_cast<Tab*>(entry)); | |
| 1088 | |
| 1089 if (entry->type == WINDOW) | |
| 1090 return ValidateWindow(static_cast<Window*>(entry)); | |
| 1091 | |
| 1092 NOTREACHED(); | |
| 1093 return false; | |
| 1094 } | |
| 1095 | |
| 1096 bool TabRestoreService::IsTabInteresting(const Tab* tab) { | |
| 1097 if (tab->navigations.empty()) | |
| 1098 return false; | |
| 1099 | |
| 1100 if (tab->navigations.size() > 1) | |
| 1101 return true; | |
| 1102 | |
| 1103 return tab->pinned || | |
| 1104 tab->navigations.at(0).virtual_url() != | |
| 1105 GURL(chrome::kChromeUINewTabURL); | |
| 1106 } | |
| 1107 | |
| 1108 bool TabRestoreService::IsWindowInteresting(const Window* window) { | |
| 1109 if (window->tabs.empty()) | |
| 1110 return false; | |
| 1111 | |
| 1112 if (window->tabs.size() > 1) | |
| 1113 return true; | |
| 1114 | |
| 1115 return IsTabInteresting(&window->tabs[0]); | |
| 1116 } | |
| 1117 | |
| 1118 bool TabRestoreService::FilterEntry(Entry* entry) { | |
| 1119 if (!ValidateEntry(entry)) | |
| 1120 return false; | |
| 1121 | |
| 1122 if (entry->type == TAB) | |
| 1123 return IsTabInteresting(static_cast<Tab*>(entry)); | |
| 1124 else if (entry->type == WINDOW) | |
| 1125 return IsWindowInteresting(static_cast<Window*>(entry)); | |
| 1126 | |
| 1127 NOTREACHED(); | |
| 1128 return false; | |
| 1129 } | |
| 1130 | |
| 1131 void TabRestoreService::ValidateAndDeleteEmptyEntries( | |
| 1132 std::vector<Entry*>* entries) { | 762 std::vector<Entry*>* entries) { |
| 1133 std::vector<Entry*> valid_entries; | 763 std::vector<Entry*> valid_entries; |
| 1134 std::vector<Entry*> invalid_entries; | 764 std::vector<Entry*> invalid_entries; |
| 1135 | 765 |
| 1136 // Iterate from the back so that we keep the most recently closed entries. | 766 // Iterate from the back so that we keep the most recently closed entries. |
| 1137 for (std::vector<Entry*>::reverse_iterator i = entries->rbegin(); | 767 for (std::vector<Entry*>::reverse_iterator i = entries->rbegin(); |
| 1138 i != entries->rend(); ++i) { | 768 i != entries->rend(); ++i) { |
| 1139 if (ValidateEntry(*i)) | 769 if (TabRestoreServiceHelper::ValidateEntry(*i)) |
| 1140 valid_entries.push_back(*i); | 770 valid_entries.push_back(*i); |
| 1141 else | 771 else |
| 1142 invalid_entries.push_back(*i); | 772 invalid_entries.push_back(*i); |
| 1143 } | 773 } |
| 1144 // NOTE: at this point the entries are ordered with newest at the front. | 774 // NOTE: at this point the entries are ordered with newest at the front. |
| 1145 entries->swap(valid_entries); | 775 entries->swap(valid_entries); |
| 1146 | 776 |
| 1147 // Delete the remaining entries. | 777 // Delete the remaining entries. |
| 1148 STLDeleteElements(&invalid_entries); | 778 STLDeleteElements(&invalid_entries); |
| 1149 } | 779 } |
| 1150 | 780 |
| 1151 void TabRestoreService::UpdateTabBrowserIDs(SessionID::id_type old_id, | 781 void PersistentTabRestoreService::Delegate::OnGotPreviousSession( |
| 1152 SessionID::id_type new_id) { | |
| 1153 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { | |
| 1154 Entry* entry = *i; | |
| 1155 if (entry->type == TAB) { | |
| 1156 Tab* tab = static_cast<Tab*>(entry); | |
| 1157 if (tab->browser_id == old_id) | |
| 1158 tab->browser_id = new_id; | |
| 1159 } | |
| 1160 } | |
| 1161 } | |
| 1162 | |
| 1163 void TabRestoreService::OnGotPreviousSession( | |
| 1164 Handle handle, | 782 Handle handle, |
| 1165 std::vector<SessionWindow*>* windows, | 783 std::vector<SessionWindow*>* windows, |
| 1166 SessionID::id_type ignored_active_window) { | 784 SessionID::id_type ignored_active_window) { |
| 1167 std::vector<Entry*> entries; | 785 std::vector<Entry*> entries; |
| 1168 CreateEntriesFromWindows(windows, &entries); | 786 CreateEntriesFromWindows(windows, &entries); |
| 1169 // Previous session tabs go first. | 787 // Previous session tabs go first. |
| 1170 staging_entries_.insert(staging_entries_.begin(), entries.begin(), | 788 staging_entries_.insert(staging_entries_.begin(), entries.begin(), |
| 1171 entries.end()); | 789 entries.end()); |
| 1172 load_state_ |= LOADED_LAST_SESSION; | 790 load_state_ |= LOADED_LAST_SESSION; |
| 1173 LoadStateChanged(); | 791 LoadStateChanged(); |
| 1174 } | 792 } |
| 1175 | 793 |
| 1176 void TabRestoreService::CreateEntriesFromWindows( | 794 bool PersistentTabRestoreService::Delegate::ConvertSessionWindowToWindow( |
| 1177 std::vector<SessionWindow*>* windows, | |
| 1178 std::vector<Entry*>* entries) { | |
| 1179 for (size_t i = 0; i < windows->size(); ++i) { | |
| 1180 scoped_ptr<Window> window(new Window()); | |
| 1181 if (ConvertSessionWindowToWindow((*windows)[i], window.get())) | |
| 1182 entries->push_back(window.release()); | |
| 1183 } | |
| 1184 } | |
| 1185 | |
| 1186 bool TabRestoreService::ConvertSessionWindowToWindow( | |
| 1187 SessionWindow* session_window, | 795 SessionWindow* session_window, |
| 1188 Window* window) { | 796 Window* window) { |
| 1189 for (size_t i = 0; i < session_window->tabs.size(); ++i) { | 797 for (size_t i = 0; i < session_window->tabs.size(); ++i) { |
| 1190 if (!session_window->tabs[i]->navigations.empty()) { | 798 if (!session_window->tabs[i]->navigations.empty()) { |
| 1191 window->tabs.resize(window->tabs.size() + 1); | 799 window->tabs.resize(window->tabs.size() + 1); |
| 1192 Tab& tab = window->tabs.back(); | 800 Tab& tab = window->tabs.back(); |
| 1193 tab.pinned = session_window->tabs[i]->pinned; | 801 tab.pinned = session_window->tabs[i]->pinned; |
| 1194 tab.navigations.swap(session_window->tabs[i]->navigations); | 802 tab.navigations.swap(session_window->tabs[i]->navigations); |
| 1195 tab.current_navigation_index = | 803 tab.current_navigation_index = |
| 1196 session_window->tabs[i]->current_navigation_index; | 804 session_window->tabs[i]->current_navigation_index; |
| 1197 tab.extension_app_id = session_window->tabs[i]->extension_app_id; | 805 tab.extension_app_id = session_window->tabs[i]->extension_app_id; |
| 1198 tab.timestamp = Time(); | 806 tab.timestamp = base::Time(); |
| 1199 } | 807 } |
| 1200 } | 808 } |
| 1201 if (window->tabs.empty()) | 809 if (window->tabs.empty()) |
| 1202 return false; | 810 return false; |
| 1203 | 811 |
| 1204 window->selected_tab_index = | 812 window->selected_tab_index = |
| 1205 std::min(session_window->selected_tab_index, | 813 std::min(session_window->selected_tab_index, |
| 1206 static_cast<int>(window->tabs.size() - 1)); | 814 static_cast<int>(window->tabs.size() - 1)); |
| 1207 window->timestamp = Time(); | 815 window->timestamp = base::Time(); |
| 1208 return true; | 816 return true; |
| 1209 } | 817 } |
| 1210 | 818 |
| 1211 void TabRestoreService::LoadStateChanged() { | 819 void PersistentTabRestoreService::Delegate::LoadStateChanged() { |
| 1212 if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) != | 820 if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) != |
| 1213 (LOADED_LAST_TABS | LOADED_LAST_SESSION)) { | 821 (LOADED_LAST_TABS | LOADED_LAST_SESSION)) { |
| 1214 // Still waiting on previous session or previous tabs. | 822 // Still waiting on previous session or previous tabs. |
| 1215 return; | 823 return; |
| 1216 } | 824 } |
| 1217 | 825 |
| 1218 // We're done loading. | 826 // We're done loading. |
| 1219 load_state_ ^= LOADING; | 827 load_state_ ^= LOADING; |
| 1220 | 828 |
| 1221 if (staging_entries_.empty() || entries_.size() >= kMaxEntries) { | 829 const Entries& entries = tab_restore_service_helper_->entries(); |
| 830 if (staging_entries_.empty() || entries.size() >= kMaxEntries) { | |
| 1222 STLDeleteElements(&staging_entries_); | 831 STLDeleteElements(&staging_entries_); |
| 1223 return; | 832 return; |
| 1224 } | 833 } |
| 1225 | 834 |
| 1226 if (staging_entries_.size() + entries_.size() > kMaxEntries) { | 835 if (staging_entries_.size() + entries.size() > kMaxEntries) { |
| 1227 // If we add all the staged entries we'll end up with more than | 836 // If we add all the staged entries we'll end up with more than |
| 1228 // kMaxEntries. Delete entries such that we only end up with | 837 // kMaxEntries. Delete entries such that we only end up with at most |
| 1229 // at most kMaxEntries. | 838 // kMaxEntries. |
| 1230 int surplus = kMaxEntries - entries_.size(); | 839 int surplus = kMaxEntries - entries.size(); |
| 1231 CHECK_LE(0, surplus); | 840 CHECK_LE(0, surplus); |
| 1232 CHECK_GE(static_cast<int>(staging_entries_.size()), surplus); | 841 CHECK_GE(static_cast<int>(staging_entries_.size()), surplus); |
| 1233 STLDeleteContainerPointers( | 842 STLDeleteContainerPointers( |
| 1234 staging_entries_.begin() + (kMaxEntries - entries_.size()), | 843 staging_entries_.begin() + (kMaxEntries - entries.size()), |
| 1235 staging_entries_.end()); | 844 staging_entries_.end()); |
| 1236 staging_entries_.erase( | 845 staging_entries_.erase( |
| 1237 staging_entries_.begin() + (kMaxEntries - entries_.size()), | 846 staging_entries_.begin() + (kMaxEntries - entries.size()), |
| 1238 staging_entries_.end()); | 847 staging_entries_.end()); |
| 1239 } | 848 } |
| 1240 | 849 |
| 1241 // And add them. | 850 // And add them. |
| 1242 for (size_t i = 0; i < staging_entries_.size(); ++i) { | 851 for (size_t i = 0; i < staging_entries_.size(); ++i) { |
| 1243 staging_entries_[i]->from_last_session = true; | 852 staging_entries_[i]->from_last_session = true; |
| 1244 AddEntry(staging_entries_[i], false, false); | 853 tab_restore_service_helper_->AddEntry(staging_entries_[i], false, false); |
| 1245 } | 854 } |
| 1246 | 855 |
| 1247 // AddEntry takes ownership of the entry, need to clear out entries so that | 856 // AddEntry takes ownership of the entry, need to clear out entries so that |
| 1248 // it doesn't delete them. | 857 // it doesn't delete them. |
| 1249 staging_entries_.clear(); | 858 staging_entries_.clear(); |
| 1250 | 859 |
| 1251 // Make it so we rewrite all the tabs. We need to do this otherwise we won't | 860 // Make it so we rewrite all the tabs. We need to do this otherwise we won't |
| 1252 // correctly write out the entries when Save is invoked (Save starts from | 861 // correctly write out the entries when Save is invoked (Save starts from |
| 1253 // the front, not the end and we just added the entries to the end). | 862 // the front, not the end and we just added the entries to the end). |
| 1254 entries_to_write_ = staging_entries_.size(); | 863 entries_to_write_ = staging_entries_.size(); |
| 1255 | 864 |
| 1256 PruneEntries(); | 865 tab_restore_service_helper_->PruneEntries(); |
| 1257 NotifyTabsChanged(); | 866 tab_restore_service_helper_->NotifyTabsChanged(); |
| 1258 } | 867 } |
| 1259 | 868 |
| 1260 Time TabRestoreService::TimeNow() const { | 869 void PersistentTabRestoreService::Delegate::RemoveEntryByID( |
| 1261 return time_factory_ ? time_factory_->TimeNow() : Time::Now(); | 870 SessionID::id_type id, |
| 871 IDToEntry* id_to_entry, | |
| 872 std::vector<TabRestoreService::Entry*>* entries) { | |
| 873 // Look for the entry in the map. If it is present, erase it from both | |
| 874 // collections and return. | |
| 875 IDToEntry::iterator i = id_to_entry->find(id); | |
| 876 if (i != id_to_entry->end()) { | |
| 877 entries->erase(std::find(entries->begin(), entries->end(), i->second)); | |
| 878 delete i->second; | |
| 879 id_to_entry->erase(i); | |
| 880 return; | |
| 881 } | |
| 882 | |
| 883 // Otherwise, loop over all items in the map and see if any of the Windows | |
| 884 // have Tabs with the |id|. | |
| 885 for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end(); | |
| 886 ++i) { | |
| 887 if (i->second->type == TabRestoreService::WINDOW) { | |
| 888 TabRestoreService::Window* window = | |
| 889 static_cast<TabRestoreService::Window*>(i->second); | |
| 890 std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin(); | |
| 891 for ( ; j != window->tabs.end(); ++j) { | |
| 892 // If the ID matches one of this window's tabs, remove it from the | |
| 893 // list. | |
| 894 if ((*j).id == id) { | |
| 895 window->tabs.erase(j); | |
| 896 return; | |
| 897 } | |
| 898 } | |
| 899 } | |
| 900 } | |
| 1262 } | 901 } |
| 902 | |
| 903 // PersistentTabRestoreService ------------------------------------------------- | |
| 904 | |
| 905 PersistentTabRestoreService::PersistentTabRestoreService( | |
| 906 Profile* profile, | |
| 907 TimeFactory* time_factory) | |
| 908 : delegate_(new Delegate(profile)), | |
| 909 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 910 helper_(this, delegate_.get(), profile, time_factory)) { | |
| 911 delegate_->set_tab_restore_service_helper(&helper_); | |
| 912 } | |
| 913 | |
| 914 PersistentTabRestoreService::~PersistentTabRestoreService() {} | |
| 915 | |
| 916 void PersistentTabRestoreService::AddObserver( | |
| 917 TabRestoreServiceObserver* observer) { | |
| 918 helper_.AddObserver(observer); | |
| 919 } | |
| 920 | |
| 921 void PersistentTabRestoreService::RemoveObserver( | |
| 922 TabRestoreServiceObserver* observer) { | |
| 923 helper_.RemoveObserver(observer); | |
| 924 } | |
| 925 | |
| 926 void PersistentTabRestoreService::CreateHistoricalTab( | |
| 927 content::WebContents* contents, | |
| 928 int index) { | |
| 929 helper_.CreateHistoricalTab(contents, index); | |
| 930 } | |
| 931 | |
| 932 void PersistentTabRestoreService::BrowserClosing( | |
| 933 TabRestoreServiceDelegate* delegate) { | |
| 934 helper_.BrowserClosing(delegate); | |
| 935 } | |
| 936 | |
| 937 void PersistentTabRestoreService::BrowserClosed( | |
| 938 TabRestoreServiceDelegate* delegate) { | |
| 939 helper_.BrowserClosed(delegate); | |
| 940 } | |
| 941 | |
| 942 void PersistentTabRestoreService::ClearEntries() { | |
| 943 helper_.ClearEntries(); | |
| 944 } | |
| 945 | |
| 946 const TabRestoreService::Entries& PersistentTabRestoreService::entries() const { | |
| 947 return helper_.entries(); | |
| 948 } | |
| 949 | |
| 950 void PersistentTabRestoreService::RestoreMostRecentEntry( | |
| 951 TabRestoreServiceDelegate* delegate) { | |
| 952 helper_.RestoreMostRecentEntry(delegate); | |
| 953 } | |
| 954 | |
| 955 TabRestoreService::Tab* PersistentTabRestoreService::RemoveTabEntryById( | |
| 956 SessionID::id_type id) { | |
| 957 return helper_.RemoveTabEntryById(id); | |
| 958 } | |
| 959 | |
| 960 void PersistentTabRestoreService::RestoreEntryById( | |
| 961 TabRestoreServiceDelegate* delegate, | |
| 962 SessionID::id_type id, | |
| 963 WindowOpenDisposition disposition) { | |
| 964 helper_.RestoreEntryById(delegate, id, disposition); | |
| 965 } | |
| 966 | |
| 967 bool PersistentTabRestoreService::IsLoaded() const { | |
| 968 return delegate_->IsLoaded(); | |
| 969 } | |
| 970 | |
| 971 void PersistentTabRestoreService::DeleteLastSession() { | |
| 972 return delegate_->DeleteLastSession(); | |
| 973 } | |
| 974 | |
| 975 void PersistentTabRestoreService::Shutdown() { | |
| 976 return delegate_->Shutdown(); | |
| 977 } | |
| 978 | |
| 979 void PersistentTabRestoreService::LoadTabsFromLastSession() { | |
| 980 delegate_->LoadTabsFromLastSession(); | |
| 981 } | |
| 982 | |
| 983 TabRestoreService::Entries* PersistentTabRestoreService::mutable_entries() { | |
| 984 return &helper_.entries_; | |
| 985 } | |
| 986 | |
| 987 void PersistentTabRestoreService::PruneEntries() { | |
| 988 helper_.PruneEntries(); | |
| 989 } | |
| 990 | |
| 991 ProfileKeyedService* TabRestoreServiceFactory::BuildServiceInstanceFor( | |
| 992 Profile* profile) const { | |
| 993 return new PersistentTabRestoreService(profile, NULL); | |
| 994 } | |
| OLD | NEW |