15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_helper.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <iterator>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_types.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_delegate.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_observer.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_controller.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/session_storage_namespace.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/web_contents.h"
22558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(ENABLE_EXTENSIONS)
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/extensions/tab_helper.h"
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/extensions/extension_constants.h"
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/extension_registry.h"
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/extension.h"
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/extension_set.h"
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationController;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationEntry;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecordAppLaunch(Profile* profile, const TabRestoreService::Tab& tab) {
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url();
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const extensions::Extension* extension =
42a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      extensions::ExtensionRegistry::Get(profile)
43a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          ->enabled_extensions().GetAppByURL(url);
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CoreAppLauncherHandler::RecordAppLaunchType(
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->GetType());
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // defined(ENABLE_EXTENSIONS)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabRestoreServiceHelper::Observer -------------------------------------------
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreServiceHelper::Observer::~Observer() {}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::Observer::OnClearEntries() {}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::Observer::OnRestoreEntryById(
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type id,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Entries::const_iterator entry_iterator) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::Observer::OnAddEntry() {}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabRestoreServiceHelper -----------------------------------------------------
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreServiceHelper::TabRestoreServiceHelper(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreService* tab_restore_service,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Observer* observer,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreService::TimeFactory* time_factory)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : tab_restore_service_(tab_restore_service),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observer_(observer),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(profile),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      restoring_(false),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      time_factory_(time_factory) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(tab_restore_service_);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreServiceHelper::~TabRestoreServiceHelper() {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    TabRestoreServiceDestroyed(tab_restore_service_));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&entries_);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::AddObserver(
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceObserver* observer) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_list_.AddObserver(observer);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::RemoveObserver(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceObserver* observer) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_list_.RemoveObserver(observer);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::CreateHistoricalTab(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WebContents* contents,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (restoring_)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabRestoreServiceDelegate* delegate =
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TabRestoreServiceDelegate::FindDelegateForWebContents(contents);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (closing_delegates_.find(delegate) != closing_delegates_.end())
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Tab> local_tab(new Tab());
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PopulateTab(local_tab.get(), index, delegate, &contents->GetController());
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (local_tab->navigations.empty())
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddEntry(local_tab.release(), true, true);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::BrowserClosing(
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* delegate) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  closing_delegates_.insert(delegate);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Window> window(new Window());
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->selected_tab_index = delegate->GetSelectedIndex();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->timestamp = TimeNow();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->app_name = delegate->GetAppName();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't use std::vector::resize() because it will push copies of an empty tab
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // into the vector, which will give all tabs in a window the same ID.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < delegate->GetTabCount(); ++i) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window->tabs.push_back(Tab());
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t entry_index = 0;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int tab_index = 0; tab_index < delegate->GetTabCount(); ++tab_index) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PopulateTab(&(window->tabs[entry_index]),
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                tab_index,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                delegate,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                &delegate->GetWebContentsAt(tab_index)->GetController());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (window->tabs[entry_index].navigations.empty()) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window->tabs.erase(window->tabs.begin() + entry_index);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window->tabs[entry_index].browser_id = delegate->GetSessionID().id();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entry_index++;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window->tabs.size() == 1 && window->app_name.empty()) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Short-circuit creating a Window if only 1 tab was present. This fixes
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://crbug.com/56744. Copy the Tab because it's owned by an object on
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the stack.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddEntry(new Tab(window->tabs[0]), true, true);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!window->tabs.empty()) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window->selected_tab_index =
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::min(static_cast<int>(window->tabs.size() - 1),
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 window->selected_tab_index);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddEntry(window.release(), true, true);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::BrowserClosed(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* delegate) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  closing_delegates_.erase(delegate);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::ClearEntries() {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnClearEntries();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&entries_);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyTabsChanged();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const TabRestoreService::Entries& TabRestoreServiceHelper::entries() const {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return entries_;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochstd::vector<content::WebContents*>
1753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochTabRestoreServiceHelper::RestoreMostRecentEntry(
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TabRestoreServiceDelegate* delegate,
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::HostDesktopType host_desktop_type) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entries_.empty())
1793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return std::vector<WebContents*>();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return RestoreEntryById(delegate, entries_.front()->id, host_desktop_type,
1823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      UNKNOWN);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreService::Tab* TabRestoreServiceHelper::RemoveTabEntryById(
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type id) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Entries::iterator i = GetEntryIteratorById(id);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i == entries_.end())
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Entry* entry = *i;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry->type != TabRestoreService::TAB)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tab* tab = static_cast<Tab*>(entry);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.erase(i);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return tab;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochstd::vector<content::WebContents*> TabRestoreServiceHelper::RestoreEntryById(
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* delegate,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SessionID::id_type id,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::HostDesktopType host_desktop_type,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WindowOpenDisposition disposition) {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Entries::iterator entry_iterator = GetEntryIteratorById(id);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry_iterator == entries_.end())
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Don't hoark here, we allow an invalid id.
2083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return std::vector<WebContents*>();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnRestoreEntryById(id, entry_iterator);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  restoring_ = true;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Entry* entry = *entry_iterator;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the entry's ID does not match the ID that is being restored, then the
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // entry is a window from which a single tab will be restored.
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool restoring_tab_in_window = entry->id != id;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!restoring_tab_in_window) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries_.erase(entry_iterator);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry_iterator = entries_.end();
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |delegate| will be NULL in cases where one isn't already available (eg,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when invoked on Mac OS X with no windows open). In this case, create a
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // new browser into which we restore the tabs.
2273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  std::vector<WebContents*> web_contents;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry->type == TabRestoreService::TAB) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tab* tab = static_cast<Tab*>(entry);
2303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    WebContents* restored_tab = NULL;
2313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    delegate = RestoreTab(*tab, delegate, host_desktop_type, disposition,
2323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        &restored_tab);
2333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    web_contents.push_back(restored_tab);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate->ShowBrowserWindow();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (entry->type == TabRestoreService::WINDOW) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* current_delegate = delegate;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Window* window = static_cast<Window*>(entry);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When restoring a window, either the entire window can be restored, or a
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // single tab within it. If the entry's ID matches the one to restore, then
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the entire window will be restored.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!restoring_tab_in_window) {
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate = TabRestoreServiceDelegate::Create(profile_, host_desktop_type,
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                   window->app_name);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const Tab& tab = window->tabs[tab_i];
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        WebContents* restored_tab = delegate->AddRestoredTab(
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            tab.navigations,
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            delegate->GetTabCount(),
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            tab.current_navigation_index,
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            tab.extension_app_id,
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            static_cast<int>(tab_i) == window->selected_tab_index,
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            tab.pinned,
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            tab.from_last_session,
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            tab.session_storage_namespace.get(),
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            tab.user_agent_override);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (restored_tab) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          restored_tab->GetController().LoadIfNecessary();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RecordAppLaunch(profile_, tab);
2603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          web_contents.push_back(restored_tab);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // All the window's tabs had the same former browser_id.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (window->tabs[0].has_browser()) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateTabBrowserIDs(window->tabs[0].browser_id,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            delegate->GetSessionID().id());
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Restore a single tab from the window. Find the tab that matches the ID
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // in the window and restore it.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           tab_i != window->tabs.end(); ++tab_i) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const Tab& tab = *tab_i;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (tab.id == id) {
2753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          WebContents* restored_tab = NULL;
2763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          delegate = RestoreTab(tab, delegate, host_desktop_type, disposition,
2773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch              &restored_tab);
2783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          web_contents.push_back(restored_tab);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window->tabs.erase(tab_i);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // If restoring the tab leaves the window with nothing else, delete it
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // as well.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!window->tabs.size()) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            entries_.erase(entry_iterator);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            delete entry;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Update the browser ID of the rest of the tabs in the window so if
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // any one is restored, it goes into the same window as the tab
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // being restored now.
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            UpdateTabBrowserIDs(tab.browser_id,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                delegate->GetSessionID().id());
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for (std::vector<Tab>::iterator tab_j = window->tabs.begin();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 tab_j != window->tabs.end(); ++tab_j) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (*tab_j).browser_id = delegate->GetSessionID().id();
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate->ShowBrowserWindow();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (disposition == CURRENT_TAB && current_delegate &&
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_delegate->GetActiveWebContents()) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_delegate->CloseTab();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!restoring_tab_in_window) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete entry;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  restoring_ = false;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyTabsChanged();
3163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return web_contents;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::NotifyTabsChanged() {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    TabRestoreServiceChanged(tab_restore_service_));
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
324a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void TabRestoreServiceHelper::NotifyLoaded() {
325a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
326a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                    TabRestoreServiceLoaded(tab_restore_service_));
327a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
328a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::AddEntry(Entry* entry,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       bool notify,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       bool to_front) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete entry;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_front)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries_.push_front(entry);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entries_.push_back(entry);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PruneEntries();
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (notify)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyTabsChanged();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnAddEntry();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::PruneEntries() {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Entries new_entries;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (TabRestoreService::Entries::const_iterator iter = entries_.begin();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != entries_.end(); ++iter) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreService::Entry* entry = *iter;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FilterEntry(entry) &&
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_entries.size() < kMaxEntries) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_entries.push_back(entry);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete entry;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_ = new_entries;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreService::Entries::iterator
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreServiceHelper::GetEntryIteratorById(SessionID::id_type id) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->id == id)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For Window entries, see if the ID matches a tab. If so, report the window
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // as the Entry.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->type == TabRestoreService::WINDOW) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::vector<Tab>::iterator j = tabs.begin();
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           j != tabs.end(); ++j) {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ((*j).id == id) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return i;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return entries_.end();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabRestoreServiceHelper::ValidateEntry(Entry* entry) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry->type == TabRestoreService::TAB)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ValidateTab(static_cast<Tab*>(entry));
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry->type == TabRestoreService::WINDOW)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ValidateWindow(static_cast<Window*>(entry));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::PopulateTab(
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tab* tab,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* delegate,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NavigationController* controller) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int pending_index = controller->GetPendingEntryIndex();
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int entry_count = controller->GetEntryCount();
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry_count == 0 && pending_index == 0)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry_count++;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab->navigations.resize(static_cast<int>(entry_count));
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < entry_count; ++i) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NavigationEntry* entry = (i == pending_index) ?
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        controller->GetPendingEntry() : controller->GetEntryAtIndex(i);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab->navigations[i] =
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        sessions::SerializedNavigationEntry::FromNavigationEntry(i, *entry);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab->timestamp = TimeNow();
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab->current_navigation_index = controller->GetCurrentEntryIndex();
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tab->current_navigation_index == -1 && entry_count > 0)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab->current_navigation_index = 0;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab->tabstrip_index = index;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(ENABLE_EXTENSIONS)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extensions::TabHelper* extensions_tab_helper =
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::TabHelper::FromWebContents(controller->GetWebContents());
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // extensions_tab_helper is NULL in some browser tests.
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extensions_tab_helper) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const extensions::Extension* extension =
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions_tab_helper->extension_app();
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extension)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab->extension_app_id = extension->id();
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
434116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab->user_agent_override =
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      controller->GetWebContents()->GetUserAgentOverride();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
439ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // TODO(ajwong): This does not correctly handle storage for isolated apps.
440ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  tab->session_storage_namespace =
441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      controller->GetDefaultSessionStorageNamespace();
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delegate may be NULL during unit tests.
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate) {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab->browser_id = delegate->GetSessionID().id();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab->pinned = delegate->IsTabPinned(tab->tabstrip_index);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabRestoreServiceDelegate* TabRestoreServiceHelper::RestoreTab(
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Tab& tab,
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreServiceDelegate* delegate,
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::HostDesktopType host_desktop_type,
4543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    WindowOpenDisposition disposition,
4553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    WebContents** contents) {
4563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  WebContents* web_contents;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (disposition == CURRENT_TAB && delegate) {
4583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    web_contents = delegate->ReplaceRestoredTab(
4593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        tab.navigations,
4603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        tab.current_navigation_index,
4613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        tab.from_last_session,
4623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        tab.extension_app_id,
4633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        tab.session_storage_namespace.get(),
4643240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        tab.user_agent_override);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only respsect the tab's original browser if there's no disposition.
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (disposition == UNKNOWN && tab.has_browser()) {
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate = TabRestoreServiceDelegate::FindDelegateWithID(
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     tab.browser_id, host_desktop_type);
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int tab_index = -1;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |delegate| will be NULL in cases where one isn't already available (eg,
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // when invoked on Mac OS X with no windows open). In this case, create a
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new browser into which we restore the tabs.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate && disposition != NEW_WINDOW) {
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index = tab.tabstrip_index;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate = TabRestoreServiceDelegate::Create(profile_, host_desktop_type,
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                   std::string());
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (tab.has_browser())
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdateTabBrowserIDs(tab.browser_id, delegate->GetSessionID().id());
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Place the tab at the end if the tab index is no longer valid or
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we were passed a specific disposition.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tab_index < 0 || tab_index > delegate->GetTabCount() ||
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        disposition != UNKNOWN) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index = delegate->GetTabCount();
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    web_contents = delegate->AddRestoredTab(tab.navigations,
4943240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            tab_index,
4953240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            tab.current_navigation_index,
4963240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            tab.extension_app_id,
4973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            disposition != NEW_BACKGROUND_TAB,
4983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            tab.pinned,
4993240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            tab.from_last_session,
5003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            tab.session_storage_namespace.get(),
5013240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                                            tab.user_agent_override);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_contents->GetController().LoadIfNecessary();
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordAppLaunch(profile_, tab);
5053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (contents)
5063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    *contents = web_contents;
5073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delegate;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabRestoreServiceHelper::ValidateTab(Tab* tab) {
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tab->navigations.empty())
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab->current_navigation_index =
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(0, std::min(tab->current_navigation_index,
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           static_cast<int>(tab->navigations.size()) - 1));
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabRestoreServiceHelper::ValidateWindow(Window* window) {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window->selected_tab_index =
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(0, std::min(window->selected_tab_index,
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           static_cast<int>(window->tabs.size() - 1)));
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i = 0;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       tab_i != window->tabs.end();) {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ValidateTab(&(*tab_i))) {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_i = window->tabs.erase(tab_i);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i < window->selected_tab_index)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        window->selected_tab_index--;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else if (i == window->selected_tab_index)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        window->selected_tab_index = 0;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++tab_i;
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window->tabs.empty())
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabRestoreServiceHelper::IsTabInteresting(const Tab* tab) {
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tab->navigations.empty())
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tab->navigations.size() > 1)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return tab->pinned ||
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab->navigations.at(0).virtual_url() !=
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GURL(chrome::kChromeUINewTabURL);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabRestoreServiceHelper::IsWindowInteresting(const Window* window) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window->tabs.empty())
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window->tabs.size() > 1)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsTabInteresting(&window->tabs[0]);
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabRestoreServiceHelper::FilterEntry(Entry* entry) {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ValidateEntry(entry))
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry->type == TabRestoreService::TAB)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return IsTabInteresting(static_cast<Tab*>(entry));
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (entry->type == TabRestoreService::WINDOW)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return IsWindowInteresting(static_cast<Window*>(entry));
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabRestoreServiceHelper::UpdateTabBrowserIDs(SessionID::id_type old_id,
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  SessionID::id_type new_id) {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Entry* entry = *i;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->type == TabRestoreService::TAB) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Tab* tab = static_cast<Tab*>(entry);
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (tab->browser_id == old_id)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tab->browser_id = new_id;
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Time TabRestoreServiceHelper::TimeNow() const {
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return time_factory_ ? time_factory_->TimeNow() : base::Time::Now();
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
599