summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-08 22:57:50 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-08 22:57:50 +0000
commitccdaf3daedf362860baf698902f18d1e6f0089b7 (patch)
tree2be41f7cf39d63d49375bef762fb9b11a4e57002
parenta4df4160d29cbaee030d87fce1edaf9c9ba0f2e7 (diff)
downloadchromium_src-ccdaf3daedf362860baf698902f18d1e6f0089b7.zip
chromium_src-ccdaf3daedf362860baf698902f18d1e6f0089b7.tar.gz
chromium_src-ccdaf3daedf362860baf698902f18d1e6f0089b7.tar.bz2
Merge 68646 - Makes instant run before unload listeners.
BUG=64694 TEST=none Review URL: http://codereview.chromium.org/5610005 TBR=sky@chromium.org Review URL: http://codereview.chromium.org/5581010 git-svn-id: svn://svn.chromium.org/chrome/branches/597/src@68657 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/instant/instant_browsertest.cc1
-rw-r--r--chrome/browser/instant/instant_unload_handler.cc135
-rw-r--r--chrome/browser/instant/instant_unload_handler.h48
-rw-r--r--chrome/browser/sessions/session_id.h3
-rw-r--r--chrome/browser/tab_contents/navigation_controller.cc6
-rw-r--r--chrome/browser/tab_contents/navigation_controller.h2
-rw-r--r--chrome/browser/tab_contents/navigation_controller_unittest.cc12
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc9
-rw-r--r--chrome/browser/tab_contents/tab_contents.h6
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.cc3
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.h3
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc12
-rw-r--r--chrome/browser/tabs/tab_strip_model.h8
-rw-r--r--chrome/browser/tabs/tab_strip_model_unittest.cc4
-rw-r--r--chrome/browser/ui/browser.cc25
-rw-r--r--chrome/browser/ui/browser.h2
-rw-r--r--chrome/chrome_browser.gypi2
17 files changed, 244 insertions, 37 deletions
diff --git a/chrome/browser/instant/instant_browsertest.cc b/chrome/browser/instant/instant_browsertest.cc
index 02d25ad..f9a0d7e 100644
--- a/chrome/browser/instant/instant_browsertest.cc
+++ b/chrome/browser/instant/instant_browsertest.cc
@@ -22,7 +22,6 @@
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
-
class InstantTest : public InProcessBrowserTest {
public:
InstantTest()
diff --git a/chrome/browser/instant/instant_unload_handler.cc b/chrome/browser/instant/instant_unload_handler.cc
new file mode 100644
index 0000000..811bde2
--- /dev/null
+++ b/chrome/browser/instant/instant_unload_handler.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/instant/instant_unload_handler.h"
+
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+
+// TabContentsDelegate implementation. This owns the TabContents supplied to the
+// constructor.
+class InstantUnloadHandler::TabContentsDelegateImpl
+ : public TabContentsDelegate {
+ public:
+ TabContentsDelegateImpl(InstantUnloadHandler* handler,
+ TabContentsWrapper* tab_contents,
+ int index)
+ : handler_(handler),
+ tab_contents_(tab_contents),
+ index_(index) {
+ tab_contents->tab_contents()->set_delegate(this);
+ }
+
+ ~TabContentsDelegateImpl() {
+ }
+
+ // Releases ownership of the TabContentsWrapper to the caller.
+ TabContentsWrapper* ReleaseTab() {
+ TabContentsWrapper* tab = tab_contents_.release();
+ tab->tab_contents()->set_delegate(NULL);
+ return tab;
+ }
+
+ // See description above field.
+ int index() const { return index_; }
+
+ // TabContentsDelegate overrides:
+ virtual void WillRunBeforeUnloadConfirm() {
+ handler_->Activate(this);
+ }
+
+ virtual bool ShouldSuppressDialogs() {
+ return true; // Return true so dialogs are suppressed.
+ }
+
+ virtual void CloseContents(TabContents* source) {
+ handler_->Destroy(this);
+ }
+
+ // All of the following are overriden to do nothing (they are pure
+ // virtual). When we're attemping to close the tab, none of this matters.
+ virtual void OpenURLFromTab(TabContents* source,
+ const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {}
+ virtual void NavigationStateChanged(const TabContents* source,
+ unsigned changed_flags) {}
+ virtual void AddNewContents(TabContents* source,
+ TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {}
+ virtual void ActivateContents(TabContents* contents) {}
+ virtual void DeactivateContents(TabContents* contents) {}
+ virtual void LoadingStateChanged(TabContents* source) {}
+ virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
+ virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
+ virtual void URLStarredChanged(TabContents* source, bool starred) {}
+ virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
+
+ private:
+ InstantUnloadHandler* handler_;
+ scoped_ptr<TabContentsWrapper> tab_contents_;
+
+ // The index |tab_contents_| was originally at. If we add the tab back we add
+ // it at this index.
+ const int index_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl);
+};
+
+InstantUnloadHandler::InstantUnloadHandler(Browser* browser)
+ : browser_(browser) {
+}
+
+InstantUnloadHandler::~InstantUnloadHandler() {
+}
+
+void InstantUnloadHandler::RunUnloadListenersOrDestroy(TabContentsWrapper* tab,
+ int index) {
+ if (!tab->tab_contents()->NeedToFireBeforeUnload()) {
+ // Tab doesn't have any before unload listeners and can be safely deleted.
+ delete tab;
+ return;
+ }
+
+ // Tab has before unload listener. Install a delegate and fire the before
+ // unload listener.
+ TabContentsDelegateImpl* delegate =
+ new TabContentsDelegateImpl(this, tab, index);
+ delegates_.push_back(delegate);
+ // TODO: decide if we really want false here. false is used for tab closes,
+ // and is needed so that the tab correctly closes but it doesn't really match
+ // what's logically happening.
+ tab->tab_contents()->render_view_host()->FirePageBeforeUnload(false);
+}
+
+void InstantUnloadHandler::Activate(TabContentsDelegateImpl* delegate) {
+ // Take ownership of the TabContents from the delegate.
+ TabContentsWrapper* tab = delegate->ReleaseTab();
+ browser::NavigateParams params(browser_, tab);
+ params.disposition = NEW_FOREGROUND_TAB;
+ params.tabstrip_index = delegate->index();
+
+ // Remove (and delete) the delegate.
+ ScopedVector<TabContentsDelegateImpl>::iterator i =
+ std::find(delegates_.begin(), delegates_.end(), delegate);
+ DCHECK(i != delegates_.end());
+ delegates_.erase(i);
+ delegate = NULL;
+
+ // Add the tab back in.
+ browser::Navigate(&params);
+}
+
+void InstantUnloadHandler::Destroy(TabContentsDelegateImpl* delegate) {
+ ScopedVector<TabContentsDelegateImpl>::iterator i =
+ std::find(delegates_.begin(), delegates_.end(), delegate);
+ DCHECK(i != delegates_.end());
+ delegates_.erase(i);
+}
diff --git a/chrome/browser/instant/instant_unload_handler.h b/chrome/browser/instant/instant_unload_handler.h
new file mode 100644
index 0000000..21800d0
--- /dev/null
+++ b/chrome/browser/instant/instant_unload_handler.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_INSTANT_INSTANT_UNLOAD_HANDLER_H_
+#define CHROME_BROWSER_INSTANT_INSTANT_UNLOAD_HANDLER_H_
+#pragma once
+
+#include "base/scoped_vector.h"
+
+class Browser;
+class TabContentsWrapper;
+
+// InstantUnloadHandler makes sure the before unload and unload handler is run
+// when using instant. When the user commits the instant preview the existing
+// TabContentsWrapper is passed to |RunUnloadListenersOrDestroy|. If the tab has
+// no before unload or unload listener the tab is deleted, otherwise the before
+// unload and unload listener is executed. If the before unload listener shows a
+// dialog the tab is added back to the tabstrip at its original location next to
+// the instant page.
+class InstantUnloadHandler {
+ public:
+ explicit InstantUnloadHandler(Browser* browser);
+ ~InstantUnloadHandler();
+
+ // See class description for details on what this does.
+ void RunUnloadListenersOrDestroy(TabContentsWrapper* tab_contents, int index);
+
+ private:
+ class TabContentsDelegateImpl;
+
+ // Invoked if the tab is to be shown. This happens if the before unload
+ // listener returns a string.
+ void Activate(TabContentsDelegateImpl* delegate);
+
+ // Destroys the old tab. This is invoked if script tries to close the page.
+ void Destroy(TabContentsDelegateImpl* delegate);
+
+ // TODO(sky): browser really needs to wait to close until there are no more
+ // tabs managed by InstantUnloadHandler.
+ Browser* browser_;
+
+ ScopedVector<TabContentsDelegateImpl> delegates_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstantUnloadHandler);
+};
+
+#endif // CHROME_BROWSER_INSTANT_INSTANT_UNLOAD_HANDLER_H_
diff --git a/chrome/browser/sessions/session_id.h b/chrome/browser/sessions/session_id.h
index 3036386..91f6d6f 100644
--- a/chrome/browser/sessions/session_id.h
+++ b/chrome/browser/sessions/session_id.h
@@ -28,9 +28,6 @@ class SessionID {
explicit SessionID(id_type id) : id_(id) {}
- // Resets the ID to 0.
- void clear() { id_ = 0; }
-
// Resets the id. This is used when restoring a session
void set_id(id_type id) { id_ = id; }
diff --git a/chrome/browser/tab_contents/navigation_controller.cc b/chrome/browser/tab_contents/navigation_controller.cc
index 918a9b4..fac26a3 100644
--- a/chrome/browser/tab_contents/navigation_controller.cc
+++ b/chrome/browser/tab_contents/navigation_controller.cc
@@ -980,8 +980,10 @@ void NavigationController::CopyStateFromAndPrune(NavigationController* source) {
// Take over the session id from source.
session_id_ = source->session_id_;
- // Reset source's session id as we're taking it over.
- source->session_id_.clear();
+ // Reset source's session id as we're taking it over. We give it a new id in
+ // case source is added later on, which can happen with instant enabled if the
+ // tab has a before unload handler.
+ source->session_id_ = SessionID();
}
void NavigationController::PruneAllButActive() {
diff --git a/chrome/browser/tab_contents/navigation_controller.h b/chrome/browser/tab_contents/navigation_controller.h
index f9c284e..d86b587 100644
--- a/chrome/browser/tab_contents/navigation_controller.h
+++ b/chrome/browser/tab_contents/navigation_controller.h
@@ -372,8 +372,6 @@ class NavigationController {
// this: E F *G* (last must be active or pending)
// result: A B *G*
// This ignores the transient index of the source and honors that of 'this'.
- // This should only be used when you are going to destroy |source| right after
- // invoking this.
void CopyStateFromAndPrune(NavigationController* source);
// Removes all the entries except the active entry. If there is a new pending
diff --git a/chrome/browser/tab_contents/navigation_controller_unittest.cc b/chrome/browser/tab_contents/navigation_controller_unittest.cc
index 81010a9..b8cfcb5 100644
--- a/chrome/browser/tab_contents/navigation_controller_unittest.cc
+++ b/chrome/browser/tab_contents/navigation_controller_unittest.cc
@@ -1740,9 +1740,9 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->url());
// The session id of the new tab should be that of the old, and the old should
- // be set to 0.
+ // get a new id.
EXPECT_EQ(id.id(), other_controller.session_id().id());
- EXPECT_EQ(0, controller().session_id().id());
+ EXPECT_NE(id.id(), controller().session_id().id());
}
// Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
@@ -1770,9 +1770,9 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
// The session id of the new tab should be that of the old, and the old should
- // be set to 0.
+ // get a new id.
EXPECT_EQ(id.id(), other_controller.session_id().id());
- EXPECT_EQ(0, controller().session_id().id());
+ EXPECT_NE(id.id(), controller().session_id().id());
}
// Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
@@ -1807,9 +1807,9 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
EXPECT_EQ(url3, other_controller.pending_entry()->url());
// The session id of the new tab should be that of the old, and the old should
- // be set to 0.
+ // be get a new id.
EXPECT_EQ(id.id(), other_controller.session_id().id());
- EXPECT_EQ(0, controller().session_id().id());
+ EXPECT_NE(id.id(), controller().session_id().id());
}
// Tests that navigations initiated from the page (with the history object)
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 816c56d..53e295f 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -849,6 +849,13 @@ void TabContents::HideContents() {
WasHidden();
}
+bool TabContents::NeedToFireBeforeUnload() {
+ // TODO(creis): Should we fire even for interstitial pages?
+ return notify_disconnection() &&
+ !showing_interstitial_page() &&
+ !render_view_host()->SuddenTerminationAllowed();
+}
+
void TabContents::OpenURL(const GURL& url, const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition) {
@@ -2792,6 +2799,8 @@ void TabContents::RunJavaScriptMessage(
void TabContents::RunBeforeUnloadConfirm(const std::wstring& message,
IPC::Message* reply_msg) {
+ if (delegate())
+ delegate()->WillRunBeforeUnloadConfirm();
if (delegate() && delegate()->ShouldSuppressDialogs()) {
render_view_host()->JavaScriptMessageBoxClosed(reply_msg, true,
std::wstring());
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index e213cac..345bca2 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -345,6 +345,12 @@ class TabContents : public PageNavigator,
virtual void ShowContents();
virtual void HideContents();
+ // Returns true if the before unload and unload listeners need to be
+ // fired. The value of this changes over time. For example, if true and the
+ // before unload listener is executed and allows the user to exit, then this
+ // returns false.
+ bool NeedToFireBeforeUnload();
+
#ifdef UNIT_TEST
// Expose the render manager for testing.
RenderViewHostManager* render_manager() { return &render_manager_; }
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.cc b/chrome/browser/tab_contents/tab_contents_delegate.cc
index 4b0e54b..21c13ff 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.cc
+++ b/chrome/browser/tab_contents/tab_contents_delegate.cc
@@ -49,6 +49,9 @@ void TabContentsDelegate::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
gfx::NativeWindow parent_window) {
}
+void TabContentsDelegate::WillRunBeforeUnloadConfirm() {
+}
+
bool TabContentsDelegate::ShouldSuppressDialogs() {
return false;
}
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h
index b3cbf72..6a59741 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.h
+++ b/chrome/browser/tab_contents/tab_contents_delegate.h
@@ -158,6 +158,9 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
gfx::NativeWindow parent_window);
+ // Invoked prior to showing before unload handler confirmation dialog.
+ virtual void WillRunBeforeUnloadConfirm();
+
// Returns true if javascript dialogs and unload alerts are suppressed.
// Default is false.
virtual bool ShouldSuppressDialogs();
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index 1a9ac8f..98316e9 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -165,26 +165,28 @@ void TabStripModel::InsertTabContentsAt(int index,
ChangeSelectedContentsFrom(selected_contents, index, false);
}
-void TabStripModel::ReplaceTabContentsAt(int index,
- TabContentsWrapper* new_contents) {
+TabContentsWrapper* TabStripModel::ReplaceTabContentsAt(
+ int index,
+ TabContentsWrapper* new_contents) {
// TODO: this should reset group/opener of any tabs that point at
// old_contents.
DCHECK(ContainsIndex(index));
- scoped_ptr<TabContentsWrapper> old_contents(GetContentsAt(index));
+ TabContentsWrapper* old_contents = GetContentsAt(index);
contents_data_[index]->contents = new_contents;
FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
- TabReplacedAt(old_contents.get(), new_contents, index));
+ TabReplacedAt(old_contents, new_contents, index));
// When the selected tab contents is replaced send out selected notification
// too. We do this as nearly all observers need to treat a replace of the
// selected contents as selection changing.
if (selected_index_ == index) {
FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
- TabSelectedAt(old_contents.get(), new_contents,
+ TabSelectedAt(old_contents, new_contents,
selected_index_, false));
}
+ return old_contents;
}
void TabStripModel::ReplaceNavigationControllerAt(
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index 2aae16e..7a3c8d9 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -195,9 +195,11 @@ class TabStripModel : public NotificationObserver {
void ReplaceNavigationControllerAt(int index,
TabContentsWrapper* contents);
- // Replaces the tab contents at |index| with |new_contents|. This deletes the
- // TabContents currently at |index|.
- void ReplaceTabContentsAt(int index, TabContentsWrapper* new_contents);
+ // Replaces the tab contents at |index| with |new_contents|. The
+ // TabContentsWrapper that was at |index| is returned and ownership returns
+ // to the caller.
+ TabContentsWrapper* ReplaceTabContentsAt(int index,
+ TabContentsWrapper* new_contents);
// Detaches the TabContents at the specified index from this strip. The
// TabContents is not destroyed, just removed from display. The caller is
diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc
index 576085d..ff461f6 100644
--- a/chrome/browser/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/tabs/tab_strip_model_unittest.cc
@@ -1846,7 +1846,7 @@ TEST_F(TabStripModelTest, ReplaceSendsSelected) {
strip.AddObserver(&tabstrip_observer);
TabContentsWrapper* new_contents = CreateTabContents();
- strip.ReplaceTabContentsAt(0, new_contents);
+ delete strip.ReplaceTabContentsAt(0, new_contents);
ASSERT_EQ(2, tabstrip_observer.GetStateCount());
@@ -1870,7 +1870,7 @@ TEST_F(TabStripModelTest, ReplaceSendsSelected) {
// And replace it.
new_contents = CreateTabContents();
- strip.ReplaceTabContentsAt(1, new_contents);
+ delete strip.ReplaceTabContentsAt(1, new_contents);
ASSERT_EQ(1, tabstrip_observer.GetStateCount());
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index e91f4c7..e0d9e1d 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -60,6 +60,7 @@
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/instant/instant_controller.h"
+#include "chrome/browser/instant/instant_unload_handler.h"
#include "chrome/browser/location_bar.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/browser_url_util.h"
@@ -183,13 +184,6 @@ const float kPopupMaxWidthFactor = 0.5;
const float kPopupMaxHeightFactor = 0.6;
#endif
-// Returns true if the specified TabContents has unload listeners registered.
-bool TabHasUnloadListener(TabContents* contents) {
- return contents->notify_disconnection() &&
- !contents->showing_interstitial_page() &&
- !contents->render_view_host()->SuddenTerminationAllowed();
-}
-
} // namespace
extern bool g_log_bug53991;
@@ -820,7 +814,7 @@ bool Browser::ShouldCloseWindow() {
for (int i = 0; i < tab_count(); ++i) {
TabContents* contents = GetTabContentsAt(i);
- if (TabHasUnloadListener(contents))
+ if (contents->NeedToFireBeforeUnload())
tabs_needing_before_unload_fired_.insert(contents);
}
@@ -2034,11 +2028,11 @@ bool Browser::RunUnloadEventsHelper(TabContents* contents) {
// handler we can fire even if the TabContents has an unload listener.
// One case where we hit this is in a tab that has an infinite loop
// before load.
- if (TabHasUnloadListener(contents)) {
+ if (contents->NeedToFireBeforeUnload()) {
// If the page has unload listeners, then we tell the renderer to fire
// them. Once they have fired, we'll get a message back saying whether
// to proceed closing the page or not, which sends us back to this method
- // with the HasUnloadListener bit cleared.
+ // with the NeedToFireBeforeUnload bit cleared.
contents->render_view_host()->FirePageBeforeUnload(false);
return true;
}
@@ -3313,7 +3307,8 @@ void Browser::Observe(NotificationType type,
if (!InstantController::IsEnabled(profile())) {
if (instant()) {
instant()->DestroyPreviewContents();
- instant_.reset(NULL);
+ instant_.reset();
+ instant_unload_handler_.reset();
}
} else {
CreateInstantIfNecessary();
@@ -3373,8 +3368,11 @@ void Browser::CommitInstant(TabContentsWrapper* preview_contents) {
preview_contents->controller().CopyStateFromAndPrune(
&tab_contents->controller());
// TabStripModel takes ownership of preview_contents.
- tab_handler_->GetTabStripModel()->ReplaceTabContentsAt(
- index, preview_contents);
+ TabContentsWrapper* old_contents =
+ tab_handler_->GetTabStripModel()->ReplaceTabContentsAt(
+ index, preview_contents);
+ // InstantUnloadHandler takes ownership of old_contents.
+ instant_unload_handler_->RunUnloadListenersOrDestroy(old_contents, index);
}
void Browser::SetSuggestedText(const string16& text) {
@@ -4141,5 +4139,6 @@ void Browser::CreateInstantIfNecessary() {
if (type() == TYPE_NORMAL && InstantController::IsEnabled(profile()) &&
!profile()->IsOffTheRecord()) {
instant_.reset(new InstantController(profile_, this));
+ instant_unload_handler_.reset(new InstantUnloadHandler(this));
}
}
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index faa316c..8dcc28f 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -40,6 +40,7 @@ class BrowserWindow;
class Extension;
class FindBarController;
class InstantController;
+class InstantUnloadHandler;
class PrefService;
class Profile;
class SessionStorageNamespace;
@@ -1109,6 +1110,7 @@ class Browser : public TabHandlerDelegate,
TabRestoreService* tab_restore_service_;
scoped_ptr<InstantController> instant_;
+ scoped_ptr<InstantUnloadHandler> instant_unload_handler_;
DISALLOW_COPY_AND_ASSIGN(Browser);
};
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 8b40050..550367e 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2161,6 +2161,8 @@
'browser/instant/instant_loader_delegate.h',
'browser/instant/instant_loader_manager.cc',
'browser/instant/instant_loader_manager.h',
+ 'browser/instant/instant_unload_handler.cc',
+ 'browser/instant/instant_unload_handler.h',
'browser/instant/promo_counter.cc',
'browser/instant/promo_counter.h',
'browser/intranet_redirect_detector.cc',