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, &current_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