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