| Index: chrome/browser/instant/instant_unload_handler.cc | 
| diff --git a/chrome/browser/instant/instant_unload_handler.cc b/chrome/browser/instant/instant_unload_handler.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..811bde25e2e06d5dc43a96ee0ac211a4bcfff56f | 
| --- /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(¶ms); | 
| +} | 
| + | 
| +void InstantUnloadHandler::Destroy(TabContentsDelegateImpl* delegate) { | 
| +  ScopedVector<TabContentsDelegateImpl>::iterator i = | 
| +      std::find(delegates_.begin(), delegates_.end(), delegate); | 
| +  DCHECK(i != delegates_.end()); | 
| +  delegates_.erase(i); | 
| +} | 
|  |