1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/tab_restore_service.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <iterator> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <map> 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_vector.h" 13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/metrics/histogram.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h" 15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/extensions/extension_service.h" 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_tab_helper.h" 1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_service.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_command.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sessions/session_types.h" 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sessions/tab_restore_service_delegate.h" 223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/sessions/tab_restore_service_observer.h" 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h" 25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/common/extensions/extension_constants.h" 26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_controller.h" 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_entry.h" 28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time; 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TimeFactory----------------------------------------------------------------- 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::TimeFactory::~TimeFactory() {} 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Entry ---------------------------------------------------------------------- 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ID of the next Entry. 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic SessionID::id_type next_entry_id = 1; 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Entry::Entry() 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : id(next_entry_id++), 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type(TAB), 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch from_last_session(false) {} 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Entry::Entry(Type type) 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : id(next_entry_id++), 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type(type), 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch from_last_session(false) {} 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Entry::~Entry() {} 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabRestoreService ---------------------------------------------------------- 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t TabRestoreService::kMaxEntries = 10; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Identifier for commands written to file. 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The ordering in the file is as follows: 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// . When the user closes a tab a command of type 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// kCommandSelectedNavigationInTab is written identifying the tab and 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the selected index, then a kCommandPinnedState command if the tab was 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// pinned and kCommandSetExtensionAppID if the tab has an app id. This is 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// followed by any number of kCommandUpdateTabNavigation commands (1 per 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// navigation entry). 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// . When the user closes a window a kCommandSelectedNavigationInTab command 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is written out and followed by n tab closed sequences (as previoulsy 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// described). 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// . When the user restores an entry a command of type kCommandRestoredEntry 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is written. 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandUpdateTabNavigation = 1; 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandRestoredEntry = 2; 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandWindow = 3; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSelectedNavigationInTab = 4; 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandPinnedState = 5; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SessionCommand::id_type kCommandSetExtensionAppID = 6; 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Number of entries (not commands) before we clobber the file and write 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// everything. 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kEntriesPerReset = 40; 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Payload structures. 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef int32 RestoredEntryPayload; 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Payload used for the start of a window close. This is the old struct that is 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// used for backwards compat when it comes to reading the session files. This 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// struct must be POD, because we memset the contents. 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct WindowPayload { 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type window_id; 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int32 selected_tab_index; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int32 num_tabs; 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Payload used for the start of a tab close. This is the old struct that is 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// used for backwards compat when it comes to reading the session files. 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct SelectedNavigationInTabPayload { 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type id; 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int32 index; 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Payload used for the start of a window close. This struct must be POD, 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// because we memset the contents. 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct WindowPayload2 : WindowPayload { 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 timestamp; 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Payload used for the start of a tab close. 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct SelectedNavigationInTabPayload2 : SelectedNavigationInTabPayload { 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 timestamp; 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Only written if the tab is pinned. 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef bool PinnedStatePayload; 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry; 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If |id_to_entry| contains an entry for |id| the corresponding entry is 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// deleted and removed from both |id_to_entry| and |entries|. This is used 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// when creating entries from the backend file. 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid RemoveEntryByID(SessionID::id_type id, 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDToEntry* id_to_entry, 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<TabRestoreService::Entry*>* entries) { 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Look for the entry in the map. If it is present, erase it from both 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // collections and return. 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDToEntry::iterator i = id_to_entry->find(id); 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (i != id_to_entry->end()) { 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries->erase(std::find(entries->begin(), entries->end(), i->second)); 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete i->second; 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_to_entry->erase(i); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Otherwise, loop over all items in the map and see if any of the Windows 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have Tabs with the |id|. 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end(); 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i) { 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (i->second->type == TabRestoreService::WINDOW) { 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabRestoreService::Window* window = 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<TabRestoreService::Window*>(i->second); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin(); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for ( ; j != window->tabs.end(); ++j) { 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the ID matches one of this window's tabs, remove it from the list. 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*j).id == id) { 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->tabs.erase(j); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid RecordAppLaunch(Profile* profile, const TabRestoreService::Tab& tab) { 156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url(); 157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK(profile->GetExtensionService()); 158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!profile->GetExtensionService()->IsInstalledApp(url)) 159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return; 160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, 162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED, 163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); 164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Tab::Tab() 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : Entry(TAB), 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_navigation_index(-1), 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_id(0), 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_index(-1), 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pinned(false) { 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Tab::~Tab() { 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Window::Window() : Entry(WINDOW), selected_tab_index(-1) { 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Window::~Window() { 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::TabRestoreService(Profile* profile, 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabRestoreService::TimeFactory* time_factory) 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : BaseSessionService(BaseSessionService::TAB_RESTORE, profile, 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath()), 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_state_(NOT_LOADED), 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch restoring_(false), 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reached_max_(false), 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_to_write_(0), 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_written_(0), 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time_factory_(time_factory) { 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::~TabRestoreService() { 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (backend()) 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Save(); 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, 2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick TabRestoreServiceDestroyed(this)); 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteElements(&entries_); 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteElements(&staging_entries_); 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time_factory_ = NULL; 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TabRestoreService::AddObserver(TabRestoreServiceObserver* observer) { 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observer_list_.AddObserver(observer); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TabRestoreService::RemoveObserver(TabRestoreServiceObserver* observer) { 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observer_list_.RemoveObserver(observer); 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRestoreService::CreateHistoricalTab(NavigationController* tab, 217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int index) { 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (restoring_) 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRestoreServiceDelegate* delegate = 222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRestoreServiceDelegate::FindDelegateForController(tab, NULL); 223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (closing_delegates_.find(delegate) != closing_delegates_.end()) 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Tab> local_tab(new Tab()); 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PopulateTab(local_tab.get(), index, delegate, tab); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (local_tab->navigations.empty()) 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddEntry(local_tab.release(), true, true); 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRestoreService::BrowserClosing(TabRestoreServiceDelegate* delegate) { 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen closing_delegates_.insert(delegate); 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 237731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick scoped_ptr<Window> window(new Window()); 238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen window->selected_tab_index = delegate->GetSelectedIndex(); 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->timestamp = TimeNow(); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't use std::vector::resize() because it will push copies of an empty tab 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // into the vector, which will give all tabs in a window the same ID. 242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (int i = 0; i < delegate->GetTabCount(); ++i) { 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->tabs.push_back(Tab()); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t entry_index = 0; 246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (int tab_index = 0; tab_index < delegate->GetTabCount(); ++tab_index) { 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PopulateTab(&(window->tabs[entry_index]), 248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab_index, 249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate, 250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &delegate->GetTabContentsAt(tab_index)->controller()); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (window->tabs[entry_index].navigations.empty()) { 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->tabs.erase(window->tabs.begin() + entry_index); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen window->tabs[entry_index].browser_id = delegate->GetSessionID().id(); 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry_index++; 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 258731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (window->tabs.size() == 1) { 259731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Short-circuit creating a Window if only 1 tab was present. This fixes 260731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // http://crbug.com/56744. Copy the Tab because it's owned by an object on 261731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // the stack. 262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AddEntry(new Tab(window->tabs[0]), true, true); 263731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (!window->tabs.empty()) { 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->selected_tab_index = 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::min(static_cast<int>(window->tabs.size() - 1), 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->selected_tab_index); 267731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AddEntry(window.release(), true, true); 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRestoreService::BrowserClosed(TabRestoreServiceDelegate* delegate) { 272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen closing_delegates_.erase(delegate); 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::ClearEntries() { 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Mark all the tabs as closed so that we don't attempt to restore them. 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand(CreateRestoredEntryCommand((*i)->id)); 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_to_write_ = 0; 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Schedule a pending reset so that we nuke the file on next write. 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_pending_reset(true); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Schedule a command, otherwise if there are no pending commands Save does 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // nothing. 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand(CreateRestoredEntryCommand(1)); 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteElements(&entries_); 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotifyTabsChanged(); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst TabRestoreService::Entries& TabRestoreService::entries() const { 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return entries_; 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRestoreService::RestoreMostRecentEntry( 298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRestoreServiceDelegate* delegate) { 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entries_.empty()) 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RestoreEntryById(delegate, entries_.front()->id, false); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRestoreService::RestoreEntryById(TabRestoreServiceDelegate* delegate, 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type id, 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool replace_existing_tab) { 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Entries::iterator i = GetEntryIteratorById(id); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (i == entries_.end()) { 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't hoark here, we allow an invalid id. 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t index = 0; 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (Entries::iterator j = entries_.begin(); j != i && j != entries_.end(); 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++j, ++index) {} 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (static_cast<int>(index) < entries_to_write_) 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_to_write_--; 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand(CreateRestoredEntryCommand(id)); 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch restoring_ = true; 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Entry* entry = *i; 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the entry's ID does not match the ID that is being restored, then the 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // entry is a window from which a single tab will be restored. 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool restoring_tab_in_window = entry->id != id; 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!restoring_tab_in_window) { 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_.erase(i); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i = entries_.end(); 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // |delegate| will be NULL in cases where one isn't already available (eg, 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // when invoked on Mac OS X with no windows open). In this case, create a 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // new browser into which we restore the tabs. 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entry->type == TAB) { 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tab* tab = static_cast<Tab*>(entry); 339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate = RestoreTab(*tab, delegate, replace_existing_tab); 340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->ShowBrowserWindow(); 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (entry->type == WINDOW) { 342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRestoreServiceDelegate* current_delegate = delegate; 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Window* window = static_cast<Window*>(entry); 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When restoring a window, either the entire window can be restored, or a 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // single tab within it. If the entry's ID matches the one to restore, then 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the entire window will be restored. 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!restoring_tab_in_window) { 349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate = TabRestoreServiceDelegate::Create(profile()); 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Tab& tab = window->tabs[tab_i]; 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabContents* restored_tab = 353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->AddRestoredTab(tab.navigations, delegate->GetTabCount(), 354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.current_navigation_index, 355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.extension_app_id, 356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (static_cast<int>(tab_i) == 357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen window->selected_tab_index), 358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.pinned, tab.from_last_session, 359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.session_storage_namespace); 360dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (restored_tab) { 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch restored_tab->controller().LoadIfNecessary(); 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RecordAppLaunch(profile(), tab); 363dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // All the window's tabs had the same former browser_id. 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (window->tabs[0].has_browser()) { 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateTabBrowserIDs(window->tabs[0].browser_id, 368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->GetSessionID().id()); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Restore a single tab from the window. Find the tab that matches the ID 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // in the window and restore it. 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_i != window->tabs.end(); ++tab_i) { 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Tab& tab = *tab_i; 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab.id == id) { 377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate = RestoreTab(tab, delegate, replace_existing_tab); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->tabs.erase(tab_i); 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If restoring the tab leaves the window with nothing else, delete it 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as well. 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!window->tabs.size()) { 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_.erase(i); 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete entry; 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update the browser ID of the rest of the tabs in the window so if 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // any one is restored, it goes into the same window as the tab 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // being restored now. 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateTabBrowserIDs(tab.browser_id, 389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->GetSessionID().id()); 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<Tab>::iterator tab_j = window->tabs.begin(); 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_j != window->tabs.end(); ++tab_j) { 392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (*tab_j).browser_id = delegate->GetSessionID().id(); 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->ShowBrowserWindow(); 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (replace_existing_tab && current_delegate && 402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen current_delegate->GetSelectedTabContents()) { 403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen current_delegate->CloseTab(); 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!restoring_tab_in_window) { 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete entry; 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch restoring_ = false; 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotifyTabsChanged(); 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::LoadTabsFromLastSession() { 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (load_state_ != NOT_LOADED || reached_max_) 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_state_ = LOADING; 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!profile()->restored_last_session() && 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !profile()->DidLastSessionExitCleanly() && 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile()->GetSessionService()) { 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The previous session crashed and wasn't restored. Load the tabs/windows 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that were open at the point of crash from the session service. 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile()->GetSessionService()->GetLastSession( 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &load_consumer_, 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewCallback(this, &TabRestoreService::OnGotPreviousSession)); 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_state_ |= LOADED_LAST_SESSION; 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Request the tabs closed in the last session. If the last session crashed, 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this won't contain the tabs/window that were open at the point of the 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // crash (the call to GetLastSession above requests those). 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleGetLastSessionCommands( 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new InternalGetCommandsRequest( 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewCallback(this, &TabRestoreService::OnGotLastSessionCommands)), 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &load_consumer_); 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::Save() { 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int to_write_count = std::min(entries_to_write_, 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(entries_.size())); 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_to_write_ = 0; 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entries_written_ + to_write_count > kEntriesPerReset) { 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch to_write_count = entries_.size(); 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_pending_reset(true); 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (to_write_count) { 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Write the to_write_count most recently added entries out. The most 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // recently added entry is at the front, so we use a reverse iterator to 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // write in the order the entries were added. 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Entries::reverse_iterator i = entries_.rbegin(); 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(static_cast<size_t>(to_write_count) <= entries_.size()); 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::advance(i, entries_.size() - static_cast<int>(to_write_count)); 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; i != entries_.rend(); ++i) { 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Entry* entry = *i; 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entry->type == TAB) { 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tab* tab = static_cast<Tab*>(entry); 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int selected_index = GetSelectedNavigationIndexToPersist(*tab); 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (selected_index != -1) 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommandsForTab(*tab, selected_index); 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommandsForWindow(*static_cast<Window*>(entry)); 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_written_++; 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pending_reset()) 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_written_ = 0; 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BaseSessionService::Save(); 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::PopulateTab(Tab* tab, 478ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int index, 479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRestoreServiceDelegate* delegate, 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NavigationController* controller) { 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int pending_index = controller->pending_entry_index(); 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int entry_count = controller->entry_count(); 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entry_count == 0 && pending_index == 0) 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry_count++; 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->navigations.resize(static_cast<int>(entry_count)); 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < entry_count; ++i) { 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NavigationEntry* entry = (i == pending_index) ? 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller->pending_entry() : controller->GetEntryAtIndex(i); 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->navigations[i].SetFromNavigationEntry(*entry); 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->timestamp = TimeNow(); 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->current_navigation_index = controller->GetCurrentEntryIndex(); 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->current_navigation_index == -1 && entry_count > 0) 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->current_navigation_index = 0; 495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab->tabstrip_index = index; 496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabContentsWrapper* wrapper = 498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabContentsWrapper::GetCurrentWrapperForContents( 499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen controller->tab_contents()); 500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // wrapper is NULL in some browser tests. 501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (wrapper) { 502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const Extension* extension = 503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen wrapper->extension_tab_helper()->extension_app(); 504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (extension) 505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab->extension_app_id = extension->id(); 506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick tab->session_storage_namespace = controller->session_storage_namespace(); 5093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Delegate may be NULL during unit tests. 511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (delegate) { 512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab->browser_id = delegate->GetSessionID().id(); 513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab->pinned = delegate->IsTabPinned(tab->tabstrip_index); 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::NotifyTabsChanged() { 5183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, 5193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick TabRestoreServiceChanged(this)); 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::AddEntry(Entry* entry, bool notify, bool to_front) { 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (to_front) 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_.push_front(entry); 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_.push_back(entry); 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (notify) 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PruneAndNotify(); 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start the save timer, when it fires we'll generate the commands. 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartSaveTimer(); 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_to_write_++; 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::PruneAndNotify() { 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (entries_.size() > kMaxEntries) { 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete entries_.back(); 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_.pop_back(); 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reached_max_ = true; 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotifyTabsChanged(); 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRestoreService::Entries::iterator TabRestoreService::GetEntryIteratorById( 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type id) { 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*i)->id == id) 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return i; 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For Window entries, see if the ID matches a tab. If so, report the window 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as the Entry. 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*i)->type == WINDOW) { 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs; 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<Tab>::iterator j = tabs.begin(); 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch j != tabs.end(); ++j) { 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*j).id == id) { 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return i; 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return entries_.end(); 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::ScheduleCommandsForWindow(const Window& window) { 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!window.tabs.empty()); 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int selected_tab = window.selected_tab_index; 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int valid_tab_count = 0; 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int real_selected_tab = selected_tab; 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < window.tabs.size(); ++i) { 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) { 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_tab_count++; 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (static_cast<int>(i) < selected_tab) { 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch real_selected_tab--; 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (valid_tab_count == 0) 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // No tabs to persist. 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand( 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateWindowCommand(window.id, 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::min(real_selected_tab, valid_tab_count - 1), 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_tab_count, 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window.timestamp)); 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < window.tabs.size(); ++i) { 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]); 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (selected_index != -1) 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommandsForTab(window.tabs[i], selected_index); 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::ScheduleCommandsForTab(const Tab& tab, 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int selected_index) { 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<TabNavigation>& navigations = tab.navigations; 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_index = static_cast<int>(navigations.size()); 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Determine the first navigation we'll persist. 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int valid_count_before_selected = 0; 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int first_index_to_persist = selected_index; 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = selected_index - 1; i >= 0 && 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_count_before_selected < max_persist_navigation_count; --i) { 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ShouldTrackEntry(navigations[i])) { 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch first_index_to_persist = i; 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_count_before_selected++; 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Write the command that identifies the selected tab. 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand( 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateSelectedNavigationInTabCommand(tab.id, 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_count_before_selected, 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab.timestamp)); 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab.pinned) { 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PinnedStatePayload payload = true; 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionCommand* command = 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new SessionCommand(kCommandPinnedState, sizeof(payload)); 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(command->contents(), &payload, sizeof(payload)); 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand(command); 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!tab.extension_app_id.empty()) { 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand( 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateSetTabExtensionAppIDCommand(kCommandSetExtensionAppID, tab.id, 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab.extension_app_id)); 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Then write the navigations. 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = first_index_to_persist, wrote_count = 0; 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i < max_index && wrote_count < 2 * max_persist_navigation_count; ++i) { 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ShouldTrackEntry(navigations[i])) { 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creating a NavigationEntry isn't the most efficient way to go about 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this, but it simplifies the code and makes it less error prone as we 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // add new data to NavigationEntry. 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<NavigationEntry> entry( 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch navigations[i].ToNavigationEntry(wrote_count, profile())); 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleCommand( 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation, tab.id, 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wrote_count++, *entry)); 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* TabRestoreService::CreateWindowCommand(SessionID::id_type id, 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int selected_tab_index, 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int num_tabs, 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time timestamp) { 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WindowPayload2 payload; 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // uninitialized memory in the struct. 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memset(&payload, 0, sizeof(payload)); 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.window_id = id; 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.selected_tab_index = selected_tab_index; 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.num_tabs = num_tabs; 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.timestamp = timestamp.ToInternalValue(); 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionCommand* command = 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new SessionCommand(kCommandWindow, sizeof(payload)); 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(command->contents(), &payload, sizeof(payload)); 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return command; 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* TabRestoreService::CreateSelectedNavigationInTabCommand( 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type tab_id, 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int32 index, 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time timestamp) { 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SelectedNavigationInTabPayload2 payload; 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.id = tab_id; 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.index = index; 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.timestamp = timestamp.ToInternalValue(); 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionCommand* command = 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new SessionCommand(kCommandSelectedNavigationInTab, sizeof(payload)); 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(command->contents(), &payload, sizeof(payload)); 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return command; 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSessionCommand* TabRestoreService::CreateRestoredEntryCommand( 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type entry_id) { 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RestoredEntryPayload payload = entry_id; 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionCommand* command = 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new SessionCommand(kCommandRestoredEntry, sizeof(payload)); 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(command->contents(), &payload, sizeof(payload)); 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return command; 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabRestoreService::GetSelectedNavigationIndexToPersist(const Tab& tab) { 688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<TabNavigation>& navigations = tab.navigations; 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int selected_index = tab.current_navigation_index; 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_index = static_cast<int>(navigations.size()); 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Find the first navigation to persist. We won't persist the selected 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // navigation if ShouldTrackEntry returns false. 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (selected_index >= 0 && 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !ShouldTrackEntry(navigations[selected_index])) { 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_index--; 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (selected_index != -1) 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return selected_index; 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Couldn't find a navigation to persist going back, go forward. 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_index = tab.current_navigation_index + 1; 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (selected_index < max_index && 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !ShouldTrackEntry(navigations[selected_index])) { 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_index++; 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return (selected_index == max_index) ? -1 : selected_index; 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::OnGotLastSessionCommands( 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Handle handle, 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<InternalGetCommandsRequest> request) { 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Entry*> entries; 716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateEntriesFromCommands(request, &entries); 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Closed tabs always go to the end. 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.insert(staging_entries_.end(), entries.begin(), 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries.end()); 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_state_ |= LOADED_LAST_TABS; 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LoadStateChanged(); 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::CreateEntriesFromCommands( 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<InternalGetCommandsRequest> request, 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Entry*>* loaded_entries) { 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (request->canceled() || entries_.size() == kMaxEntries) 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<SessionCommand*>& commands = request->commands; 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Iterate through the commands populating entries and id_to_entry. 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScopedVector<Entry> entries; 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDToEntry id_to_entry; 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If non-null we're processing the navigations of this tab. 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tab* current_tab = NULL; 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If non-null we're processing the tabs of this window. 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Window* current_window = NULL; 738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If > 0, we've gotten a window command but not all the tabs yet. 739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int pending_window_tabs = 0; 740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<SessionCommand*>::const_iterator i = commands.begin(); 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != commands.end(); ++i) { 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SessionCommand& command = *(*i); 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (command.id()) { 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case kCommandRestoredEntry: { 745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pending_window_tabs > 0) { 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Should never receive a restored command while waiting for all the 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tabs in a window. 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab = NULL; 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_window = NULL; 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RestoredEntryPayload payload; 755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!command.GetPayload(&payload, sizeof(payload))) 756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveEntryByID(payload, &id_to_entry, &(entries.get())); 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case kCommandWindow: { 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WindowPayload2 payload; 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pending_window_tabs > 0) { 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Should never receive a window command while waiting for all the 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tabs in a window. 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Try the new payload first 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!command.GetPayload(&payload, sizeof(payload))) { 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // then the old payload 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WindowPayload old_payload; 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!command.GetPayload(&old_payload, sizeof(old_payload))) 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Copy the old payload data to the new payload. 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.window_id = old_payload.window_id; 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.selected_tab_index = old_payload.selected_tab_index; 779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.num_tabs = old_payload.num_tabs; 780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Since we don't have a time use time 0 which is used to mark as an 781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // unknown timestamp. 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.timestamp = 0; 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pending_window_tabs = payload.num_tabs; 786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pending_window_tabs <= 0) { 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Should always have at least 1 tab. Likely indicates corruption. 788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get())); 792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_window = new Window(); 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_window->selected_tab_index = payload.selected_tab_index; 795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_window->timestamp = Time::FromInternalValue(payload.timestamp); 796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries->push_back(current_window); 797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_to_entry[payload.window_id] = current_window; 798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case kCommandSelectedNavigationInTab: { 802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SelectedNavigationInTabPayload2 payload; 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!command.GetPayload(&payload, sizeof(payload))) { 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SelectedNavigationInTabPayload old_payload; 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!command.GetPayload(&old_payload, sizeof(old_payload))) 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.id = old_payload.id; 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.index = old_payload.index; 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Since we don't have a time use time 0 which is used to mark as an 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // unknown timestamp. 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch payload.timestamp = 0; 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pending_window_tabs > 0) { 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!current_window) { 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We should have created a window already. 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_window->tabs.resize(current_window->tabs.size() + 1); 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab = &(current_window->tabs.back()); 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (--pending_window_tabs == 0) 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_window = NULL; 824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveEntryByID(payload.id, &id_to_entry, &(entries.get())); 826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab = new Tab(); 827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_to_entry[payload.id] = current_tab; 828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab->timestamp = Time::FromInternalValue(payload.timestamp); 829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries->push_back(current_tab); 830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab->current_navigation_index = payload.index; 832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case kCommandUpdateTabNavigation: { 836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!current_tab) { 837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Should be in a tab when we get this. 838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab->navigations.resize(current_tab->navigations.size() + 1); 841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type tab_id; 842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!RestoreUpdateTabNavigationCommand( 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch command, ¤t_tab->navigations.back(), &tab_id)) { 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case kCommandPinnedState: { 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!current_tab) { 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Should be in a tab when we get this. 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: payload doesn't matter. kCommandPinnedState is only written if 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tab is pinned. 856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab->pinned = true; 857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case kCommandSetExtensionAppID: { 861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!current_tab) { 862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Should be in a tab when we get this. 863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type tab_id; 866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string extension_app_id; 867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!RestoreSetTabExtensionAppIDCommand(command, &tab_id, 868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &extension_app_id)) { 869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_tab->extension_app_id.swap(extension_app_id); 872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Unknown type, usually indicates corruption of file. Ignore it. 877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there was corruption some of the entries won't be valid. Prune any 882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // entries with no navigations. 883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ValidateAndDeleteEmptyEntries(&(entries.get())); 884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loaded_entries->swap(entries.get()); 886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 888ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTabRestoreServiceDelegate* TabRestoreService::RestoreTab( 889ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const Tab& tab, 890ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRestoreServiceDelegate* delegate, 891ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool replace_existing_tab) { 892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |browser| will be NULL in cases where one isn't already available (eg, 893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // when invoked on Mac OS X with no windows open). In this case, create a 894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // new browser into which we restore the tabs. 895ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (replace_existing_tab && delegate) { 896ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->ReplaceRestoredTab(tab.navigations, 897ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.current_navigation_index, 898ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.from_last_session, 899ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.extension_app_id, 900ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.session_storage_namespace); 901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab.has_browser()) 903ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate = TabRestoreServiceDelegate::FindDelegateWithID(tab.browser_id); 904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_index = -1; 906ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (delegate) { 907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_index = tab.tabstrip_index; 908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 909ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate = TabRestoreServiceDelegate::Create(profile()); 910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab.has_browser()) { 911ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UpdateTabBrowserIDs(tab.browser_id, delegate->GetSessionID().id()); 912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 915ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (tab_index < 0 || tab_index > delegate->GetTabCount()) { 916ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab_index = delegate->GetTabCount(); 917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 919ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->AddRestoredTab(tab.navigations, 920ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab_index, 921ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.current_navigation_index, 922ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.extension_app_id, 923ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen true, tab.pinned, tab.from_last_session, 924ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab.session_storage_namespace); 925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 926ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RecordAppLaunch(profile(), tab); 927ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return delegate; 928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRestoreService::ValidateTab(Tab* tab) { 932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->navigations.empty()) 933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->current_navigation_index = 936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::max(0, std::min(tab->current_navigation_index, 937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(tab->navigations.size()) - 1)); 938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::ValidateAndDeleteEmptyEntries( 942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Entry*>* entries) { 943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Entry*> valid_entries; 944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Entry*> invalid_entries; 945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t max_valid = kMaxEntries - entries_.size(); 947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Iterate from the back so that we keep the most recently closed entries. 948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<Entry*>::reverse_iterator i = entries->rbegin(); 949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != entries->rend(); ++i) { 950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool valid_entry = false; 951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (valid_entries.size() != max_valid) { 952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*i)->type == TAB) { 953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tab* tab = static_cast<Tab*>(*i); 954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ValidateTab(tab)) 955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_entry = true; 956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Window* window = static_cast<Window*>(*i); 958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); 959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_i != window->tabs.end();) { 960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ValidateTab(&(*tab_i))) 961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_i = window->tabs.erase(tab_i); 962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++tab_i; 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!window->tabs.empty()) { 966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->selected_tab_index = 967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::max(0, std::min(window->selected_tab_index, 968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(window->tabs.size() - 1))); 969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_entry = true; 970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (valid_entry) 974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch valid_entries.push_back(*i); 975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch invalid_entries.push_back(*i); 977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: at this point the entries are ordered with newest at the front. 979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries->swap(valid_entries); 980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Delete the remaining entries. 982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteElements(&invalid_entries); 983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::UpdateTabBrowserIDs(SessionID::id_type old_id, 986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionID::id_type new_id) { 987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { 988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Entry* entry = *i; 989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entry->type == TAB) { 990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tab* tab = static_cast<Tab*>(entry); 991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->browser_id == old_id) 992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->browser_id = new_id; 993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::OnGotPreviousSession( 998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Handle handle, 999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<SessionWindow*>* windows) { 1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Entry*> entries; 1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateEntriesFromWindows(windows, &entries); 1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Previous session tabs go first. 1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.insert(staging_entries_.begin(), entries.begin(), 1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries.end()); 1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_state_ |= LOADED_LAST_SESSION; 1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LoadStateChanged(); 1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::CreateEntriesFromWindows( 1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<SessionWindow*>* windows, 1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<Entry*>* entries) { 1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < windows->size(); ++i) { 1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Window> window(new Window()); 1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ConvertSessionWindowToWindow((*windows)[i], window.get())) 1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries->push_back(window.release()); 1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRestoreService::ConvertSessionWindowToWindow( 1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SessionWindow* session_window, 1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Window* window) { 1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < session_window->tabs.size(); ++i) { 1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!session_window->tabs[i]->navigations.empty()) { 1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->tabs.resize(window->tabs.size() + 1); 1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tab& tab = window->tabs.back(); 1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab.pinned = session_window->tabs[i]->pinned; 1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab.navigations.swap(session_window->tabs[i]->navigations); 1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab.current_navigation_index = 1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch session_window->tabs[i]->current_navigation_index; 1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab.extension_app_id = session_window->tabs[i]->extension_app_id; 1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab.timestamp = Time(); 1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (window->tabs.empty()) 1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->selected_tab_index = 1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::min(session_window->selected_tab_index, 1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(window->tabs.size() - 1)); 1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window->timestamp = Time(); 1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRestoreService::LoadStateChanged() { 1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((load_state_ & (LOADED_LAST_TABS | LOADED_LAST_SESSION)) != 1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (LOADED_LAST_TABS | LOADED_LAST_SESSION)) { 1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Still waiting on previous session or previous tabs. 1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We're done loading. 1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_state_ ^= LOADING; 1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (staging_entries_.empty() || reached_max_) { 1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteElements(&staging_entries_); 1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (staging_entries_.size() + entries_.size() > kMaxEntries) { 1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we add all the staged entries we'll end up with more than 1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // kMaxEntries. Delete entries such that we only end up with 1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // at most kMaxEntries. 1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(entries_.size() < kMaxEntries); 1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteContainerPointers( 1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.begin() + (kMaxEntries - entries_.size()), 1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.end()); 1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.erase( 1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.begin() + (kMaxEntries - entries_.size()), 1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.end()); 1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // And add them. 1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < staging_entries_.size(); ++i) { 1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_[i]->from_last_session = true; 1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddEntry(staging_entries_[i], false, false); 1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // AddEntry takes ownership of the entry, need to clear out entries so that 1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // it doesn't delete them. 1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch staging_entries_.clear(); 1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make it so we rewrite all the tabs. We need to do this otherwise we won't 1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // correctly write out the entries when Save is invoked (Save starts from 1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the front, not the end and we just added the entries to the end). 1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries_to_write_ = staging_entries_.size(); 1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PruneAndNotify(); 1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTime TabRestoreService::TimeNow() const { 1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return time_factory_ ? time_factory_->TimeNow() : Time::Now(); 1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1093