Move Sad Tab implementation out of the TabContentsViews.

BUG=103258
TEST=no change in sad tab behavior

Review URL: http://codereview.chromium.org/8477042

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110086 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/automation/automation_tab_helper.cc b/chrome/browser/automation/automation_tab_helper.cc
index 3e4945a0..30d203b 100644
--- a/chrome/browser/automation/automation_tab_helper.cc
+++ b/chrome/browser/automation/automation_tab_helper.cc
@@ -87,7 +87,7 @@
   }
 }
 
-void AutomationTabHelper::RenderViewGone() {
+void AutomationTabHelper::RenderViewGone(base::TerminationStatus status) {
   OnTabOrRenderViewDestroyed(tab_contents());
 }
 
diff --git a/chrome/browser/automation/automation_tab_helper.h b/chrome/browser/automation/automation_tab_helper.h
index a8ddef7e..ae764ba 100644
--- a/chrome/browser/automation/automation_tab_helper.h
+++ b/chrome/browser/automation/automation_tab_helper.h
@@ -106,11 +106,11 @@
       const std::string& error_msg);
 
   // TabContentsObserver implementation.
-  virtual void DidStartLoading();
-  virtual void DidStopLoading();
-  virtual void RenderViewGone();
-  virtual void TabContentsDestroyed(TabContents* tab_contents);
-  virtual bool OnMessageReceived(const IPC::Message& message);
+  virtual void DidStartLoading() OVERRIDE;
+  virtual void DidStopLoading() OVERRIDE;
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
+  virtual void TabContentsDestroyed(TabContents* tab_contents) OVERRIDE;
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
   void OnWillPerformClientRedirect(int64 frame_id, double delay_seconds);
   void OnDidCompleteOrCancelClientRedirect(int64 frame_id);
diff --git a/chrome/browser/infobars/infobar_tab_helper.cc b/chrome/browser/infobars/infobar_tab_helper.cc
index ac10be64..000bfb4 100644
--- a/chrome/browser/infobars/infobar_tab_helper.cc
+++ b/chrome/browser/infobars/infobar_tab_helper.cc
@@ -155,7 +155,7 @@
       InsecureContentInfoBarDelegate::RUN));
 }
 
-void InfoBarTabHelper::RenderViewGone() {
+void InfoBarTabHelper::RenderViewGone(base::TerminationStatus status) {
   RemoveAllInfoBars(true);
 }
 
diff --git a/chrome/browser/infobars/infobar_tab_helper.h b/chrome/browser/infobars/infobar_tab_helper.h
index d1332f07..f614a8b 100644
--- a/chrome/browser/infobars/infobar_tab_helper.h
+++ b/chrome/browser/infobars/infobar_tab_helper.h
@@ -50,7 +50,7 @@
   void set_infobars_enabled(bool value) { infobars_enabled_ = value; }
 
   // TabContentsObserver overrides:
-  virtual void RenderViewGone() OVERRIDE;
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
   // content::NotificationObserver overrides:
diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc
index ee586cc..e476972 100644
--- a/chrome/browser/notifications/balloon_host.cc
+++ b/chrome/browser/notifications/balloon_host.cc
@@ -93,7 +93,7 @@
       content::NotificationService::NoDetails());
 }
 
-void BalloonHost::RenderViewGone() {
+void BalloonHost::RenderViewGone(base::TerminationStatus status) {
   CloseContents(tab_contents_.get());
 }
 
diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h
index 7dfd875..257fba8 100644
--- a/chrome/browser/notifications/balloon_host.h
+++ b/chrome/browser/notifications/balloon_host.h
@@ -68,7 +68,7 @@
   // TabContentsObserver implementation:
   virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
   virtual void RenderViewReady() OVERRIDE;
-  virtual void RenderViewGone() OVERRIDE;
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
   // Message handlers
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index be115b1..9891dc9 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -161,7 +161,7 @@
       MessageLoopForUI::current()->Quit();
   }
 
-  virtual void RenderViewGone() OVERRIDE {
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE {
     // On quit, it's possible to end up here when render processes are closed
     // before the PrerenderManager is destroyed.  As a result, it's possible to
     // get either FINAL_STATUS_APP_TERMINATING or FINAL_STATUS_RENDERER_CRASHED
@@ -175,7 +175,7 @@
       expected_final_status_ = FINAL_STATUS_RENDERER_CRASHED;
     }
 
-    PrerenderContents::RenderViewGone();
+    PrerenderContents::RenderViewGone(status);
   }
 
   virtual bool AddAliasURL(const GURL& url) OVERRIDE {
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index c4b67322..02bb75b 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -523,7 +523,7 @@
   Destroy(FINAL_STATUS_JS_OUT_OF_MEMORY);
 }
 
-void PrerenderContents::RenderViewGone() {
+void PrerenderContents::RenderViewGone(base::TerminationStatus status) {
   Destroy(FINAL_STATUS_RENDERER_CRASHED);
 }
 
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index 3c26e30..37010cc 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -145,7 +145,7 @@
       const GURL& validated_url,
       bool is_error_page,
       RenderViewHost* render_view_host) OVERRIDE;
-  virtual void RenderViewGone() OVERRIDE;
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
 
   // content::NotificationObserver
   virtual void Observe(int type,
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index 6d4ddcd..c24affa 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -135,7 +135,7 @@
   TerminatePrintJob(true);
 }
 
-void PrintViewManager::RenderViewGone() {
+void PrintViewManager::RenderViewGone(base::TerminationStatus status) {
   if (!print_job_.get())
     return;
 
diff --git a/chrome/browser/printing/print_view_manager.h b/chrome/browser/printing/print_view_manager.h
index d75e3d8..1702461 100644
--- a/chrome/browser/printing/print_view_manager.h
+++ b/chrome/browser/printing/print_view_manager.h
@@ -80,10 +80,10 @@
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
   // Terminates or cancels the print job if one was pending.
-  virtual void RenderViewGone();
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
 
   // Cancels the print job.
-  virtual void StopNavigation();
+  virtual void StopNavigation() OVERRIDE;
 
  private:
   // IPC Message handlers.
diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc
index b52f39b..19d04f3 100644
--- a/chrome/browser/tab_contents/background_contents.cc
+++ b/chrome/browser/tab_contents/background_contents.cc
@@ -94,7 +94,7 @@
       content::Details<BackgroundContents>(this));
 }
 
-void BackgroundContents::RenderViewGone() {
+void BackgroundContents::RenderViewGone(base::TerminationStatus status) {
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED,
       content::Source<Profile>(profile_),
@@ -103,7 +103,7 @@
   // Our RenderView went away, so we should go away also, so killing the process
   // via the TaskManager doesn't permanently leave a BackgroundContents hanging
   // around the system, blocking future instances from being created
-  // (http://crbug.com/65189).
+  // <http://crbug.com/65189>.
   delete this;
 }
 
diff --git a/chrome/browser/tab_contents/background_contents.h b/chrome/browser/tab_contents/background_contents.h
index e92f5173..fc3a4435 100644
--- a/chrome/browser/tab_contents/background_contents.h
+++ b/chrome/browser/tab_contents/background_contents.h
@@ -51,7 +51,7 @@
   virtual void DidNavigateMainFramePostCommit(TabContents* tab) OVERRIDE;
 
   // TabContentsObserver implementation:
-  virtual void RenderViewGone() OVERRIDE;
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
 
   // content::NotificationObserver
   virtual void Observe(int type,
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
index 4284f640..d297b99f 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
@@ -13,11 +13,9 @@
 #include "base/string_util.h"
 #include "base/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/tab_contents/render_view_context_menu_gtk.h"
 #include "chrome/browser/tab_contents/web_drag_bookmark_handler_gtk.h"
 #include "chrome/browser/ui/gtk/constrained_window_gtk.h"
-#include "chrome/browser/ui/gtk/sad_tab_gtk.h"
 #include "content/browser/renderer_host/render_view_host.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_widget_host_view_gtk.h"
@@ -26,8 +24,6 @@
 #include "content/browser/tab_contents/tab_contents_delegate.h"
 #include "content/browser/tab_contents/web_drag_dest_gtk.h"
 #include "content/browser/tab_contents/web_drag_source_gtk.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "ui/base/gtk/gtk_expanded_container.h"
 #include "ui/base/gtk/gtk_floating_container.h"
 #include "ui/gfx/point.h"
@@ -81,7 +77,8 @@
     : tab_contents_(tab_contents),
       floating_(gtk_floating_container_new()),
       expanded_(gtk_expanded_container_new()),
-      constrained_window_(NULL) {
+      constrained_window_(NULL),
+      overlaid_view_(NULL) {
   gtk_widget_set_name(expanded_, "chrome-tab-contents-view");
   g_signal_connect(expanded_, "size-allocate",
                    G_CALLBACK(OnSizeAllocateThunk), this);
@@ -93,8 +90,6 @@
   gtk_container_add(GTK_CONTAINER(floating_.get()), expanded_);
   gtk_widget_show(expanded_);
   gtk_widget_show(floating_.get());
-  registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_CONNECTED,
-                 content::Source<TabContents>(tab_contents));
   drag_source_.reset(new content::WebDragSourceGtk(tab_contents));
 }
 
@@ -198,20 +193,6 @@
 
 void TabContentsViewGtk::OnTabCrashed(base::TerminationStatus status,
                                       int error_code) {
-  // Only show the sad tab if we're not in browser shutdown, so that TabContents
-  // objects that are not in a browser (e.g., HTML dialogs) and thus are
-  // visible do not flash a sad tab page.
-  if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
-    return;
-
-  if (tab_contents_ != NULL && !sad_tab_.get()) {
-    sad_tab_.reset(new SadTabGtk(
-        tab_contents_,
-        status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ?
-        SadTabGtk::KILLED : SadTabGtk::CRASHED));
-    InsertIntoContentArea(sad_tab_->widget());
-    gtk_widget_show(sad_tab_->widget());
-  }
 }
 
 void TabContentsViewGtk::SizeContents(const gfx::Size& size) {
@@ -279,6 +260,19 @@
   out->SetRect(x, y, w, h);
 }
 
+void TabContentsViewGtk::InstallOverlayView(gfx::NativeView view) {
+  DCHECK(!overlaid_view_);
+  overlaid_view_ = view;
+  InsertIntoContentArea(view);
+  gtk_widget_show(view);
+}
+
+void TabContentsViewGtk::RemoveOverlayView() {
+  DCHECK(overlaid_view_);
+  gtk_container_remove(GTK_CONTAINER(expanded_), overlaid_view_);
+  overlaid_view_ = NULL;
+}
+
 void TabContentsViewGtk::SetFocusedWidget(GtkWidget* widget) {
   focus_store_.SetWidget(widget);
 }
@@ -301,24 +295,6 @@
   }
 }
 
-void TabContentsViewGtk::Observe(int type,
-                                 const content::NotificationSource& source,
-                                 const content::NotificationDetails& details) {
-  switch (type) {
-    case content::NOTIFICATION_TAB_CONTENTS_CONNECTED: {
-      // No need to remove the SadTabGtk's widget from the container since
-      // the new RenderWidgetHostViewGtk instance already removed all the
-      // vbox's children.
-      sad_tab_.reset();
-      break;
-    }
-    default:
-      NOTREACHED() << "Got a notification we didn't register for.";
-      break;
-  }
-}
-
-
 void TabContentsViewGtk::CreateNewWindow(
     int route_id,
     const ViewHostMsg_CreateWindow_Params& params) {
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.h b/chrome/browser/tab_contents/tab_contents_view_gtk.h
index feb56b2..efa4133 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.h
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.h
@@ -14,14 +14,11 @@
 #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
 #include "chrome/browser/ui/gtk/focus_store_gtk.h"
 #include "content/browser/tab_contents/tab_contents_view.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/base/gtk/owned_widget_gtk.h"
 
 class ConstrainedWindowGtk;
 class RenderViewContextMenuGtk;
-class SadTabGtk;
 class WebDragBookmarkHandlerGtk;
 
 namespace content {
@@ -29,8 +26,7 @@
 class WebDragSourceGtk;
 }
 
-class TabContentsViewGtk : public TabContentsView,
-                           public content::NotificationObserver {
+class TabContentsViewGtk : public TabContentsView {
  public:
   // The corresponding TabContents is passed in the constructor, and manages our
   // lifetime. This doesn't need to be the case, but is this way currently
@@ -71,6 +67,8 @@
   virtual bool IsEventTracking() const OVERRIDE;
   virtual void CloseTabAfterEventTracking() OVERRIDE;
   virtual void GetViewBounds(gfx::Rect* out) const OVERRIDE;
+  virtual void InstallOverlayView(gfx::NativeView view) OVERRIDE;
+  virtual void RemoveOverlayView() OVERRIDE;
 
   // Backend implementation of RenderViewHostDelegate::View.
   virtual void CreateNewWindow(
@@ -99,12 +97,6 @@
   virtual void GotFocus();
   virtual void TakeFocus(bool reverse);
 
-  // content::NotificationObserver implementation ------------------------------
-
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details);
-
  private:
   // Insert the given widget into the content area. Should only be used for
   // web pages and the like (including interstitials and sad tab). Note that
@@ -136,7 +128,6 @@
   // Common implementations of some RenderViewHostDelegate::View methods.
   RenderViewHostDelegateViewHelper delegate_view_helper_;
 
-
   // Contains |expanded_| as its GtkBin member.
   ui::OwnedWidgetGtk floating_;
 
@@ -148,11 +139,6 @@
   // between uses so that it won't go out of scope before we're done with it.
   scoped_ptr<RenderViewContextMenuGtk> context_menu_;
 
-  // Used to get notifications about renderers coming and going.
-  content::NotificationRegistrar registrar_;
-
-  scoped_ptr<SadTabGtk> sad_tab_;
-
   FocusStoreGtk focus_store_;
 
   // The UI for the constrained dialog currently displayed. This is owned by
@@ -173,6 +159,10 @@
   // variable because resizing in GTK+ is async.
   gfx::Size requested_size_;
 
+  // The overlaid view. Owned by the caller of |InstallOverlayView|; this is a
+  // weak reference.
+  GtkWidget* overlaid_view_;
+
   DISALLOW_COPY_AND_ASSIGN(TabContentsViewGtk);
 };
 
diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.h b/chrome/browser/tab_contents/tab_contents_view_mac.h
index 670358b..406e221 100644
--- a/chrome/browser/tab_contents/tab_contents_view_mac.h
+++ b/chrome/browser/tab_contents/tab_contents_view_mac.h
@@ -17,8 +17,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
 #include "content/browser/tab_contents/tab_contents_view.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "ui/base/cocoa/base_view.h"
 #include "ui/gfx/size.h"
 
@@ -48,8 +46,7 @@
 
 // Mac-specific implementation of the TabContentsView. It owns an NSView that
 // contains all of the contents of the tab and associated child views.
-class TabContentsViewMac : public TabContentsView,
-                           public content::NotificationObserver {
+class TabContentsViewMac : public TabContentsView {
  public:
   // The corresponding TabContents is passed in the constructor, and manages our
   // lifetime. This doesn't need to be the case, but is this way currently
@@ -80,6 +77,8 @@
   virtual bool IsEventTracking() const OVERRIDE;
   virtual void CloseTabAfterEventTracking() OVERRIDE;
   virtual void GetViewBounds(gfx::Rect* out) const OVERRIDE;
+  virtual void InstallOverlayView(gfx::NativeView view) OVERRIDE;
+  virtual void RemoveOverlayView() OVERRIDE;
 
   // Backend implementation of RenderViewHostDelegate::View.
   virtual void CreateNewWindow(
@@ -108,12 +107,6 @@
   virtual void GotFocus();
   virtual void TakeFocus(bool reverse);
 
-  // content::NotificationObserver implementation ------------------------------
-
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details);
-
   // A helper method for closing the tab in the
   // CloseTabAfterEventTracking() implementation.
   void CloseTab();
@@ -135,19 +128,16 @@
   // focus returns.
   scoped_nsobject<FocusTracker> focus_tracker_;
 
-  // Used to get notifications about renderers coming and going.
-  content::NotificationRegistrar registrar_;
-
-  // Used to render the sad tab. This will be non-NULL only when the sad tab is
-  // visible.
-  scoped_nsobject<SadTabController> sad_tab_;
-
   // The context menu. Callbacks are asynchronous so we need to keep it around.
   scoped_ptr<RenderViewContextMenuMac> context_menu_;
 
   // The page content's intrinsic width.
   int preferred_width_;
 
+  // The overlaid view. Owned by the caller of |InstallOverlayView|; this is a
+  // weak reference.
+  NSView* overlaid_view_;
+
   DISALLOW_COPY_AND_ASSIGN(TabContentsViewMac);
 };
 
diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm
index 6f71e3a..ba507b43 100644
--- a/chrome/browser/tab_contents/tab_contents_view_mac.mm
+++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm
@@ -8,12 +8,10 @@
 
 #include <string>
 
-#include "chrome/browser/browser_shutdown.h"
 #import "chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h"
 #include "chrome/browser/tab_contents/render_view_context_menu_mac.h"
 #include "chrome/browser/tab_contents/web_drag_bookmark_handler_mac.h"
 #import "chrome/browser/ui/cocoa/focus_tracker.h"
-#import "chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h"
 #import "chrome/browser/ui/cocoa/view_id_util.h"
 #include "content/browser/renderer_host/render_view_host.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
@@ -27,9 +25,6 @@
 #import "content/common/chrome_application_mac.h"
 #import "content/common/mac/scoped_sending_event.h"
 #include "content/common/view_messages.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "skia/ext/skia_utils_mac.h"
 #import "third_party/mozilla/NSPasteboard+Utils.h"
 
@@ -71,9 +66,8 @@
 
 TabContentsViewMac::TabContentsViewMac(TabContents* tab_contents)
     : tab_contents_(tab_contents),
-      preferred_width_(0) {
-  registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_CONNECTED,
-                 content::Source<TabContents>(tab_contents));
+      preferred_width_(0),
+      overlaid_view_(nil) {
 }
 
 TabContentsViewMac::~TabContentsViewMac() {
@@ -120,6 +114,8 @@
   NSView* view_view = view->native_view();
   [view_view setFrame:[cocoa_view_.get() bounds]];
   [view_view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+  // Add the new view below all other views; this also keeps it below any
+  // overlay view installed.
   [cocoa_view_.get() addSubview:view_view
                      positioned:NSWindowBelow
                      relativeTo:nil];
@@ -188,21 +184,6 @@
 
 void TabContentsViewMac::OnTabCrashed(base::TerminationStatus /* status */,
                                       int /* error_code */) {
-  // Only show the sad tab if we're not in browser shutdown, so that TabContents
-  // objects that are not in a browser (e.g., HTML dialogs) and thus are
-  // visible do not flash a sad tab page.
-  if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
-    return;
-
-  if (!sad_tab_.get()) {
-    DCHECK(tab_contents_);
-    if (tab_contents_) {
-      SadTabController* sad_tab =
-          [[SadTabController alloc] initWithTabContents:tab_contents_
-                                              superview:cocoa_view_];
-      sad_tab_.reset(sad_tab);
-    }
-  }
 }
 
 void TabContentsViewMac::SizeContents(const gfx::Size& size) {
@@ -397,21 +378,22 @@
   NOTIMPLEMENTED();
 }
 
-void TabContentsViewMac::CloseTab() {
-  tab_contents_->Close(tab_contents_->render_view_host());
+void TabContentsViewMac::InstallOverlayView(gfx::NativeView view) {
+  DCHECK(!overlaid_view_);
+  overlaid_view_ = view;
+  [view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+  [cocoa_view_.get() addSubview:view];
+  [view setFrame:[cocoa_view_.get() bounds]];
 }
 
-void TabContentsViewMac::Observe(int type,
-                                 const content::NotificationSource& source,
-                                 const content::NotificationDetails& details) {
-  switch (type) {
-    case content::NOTIFICATION_TAB_CONTENTS_CONNECTED: {
-      sad_tab_.reset();
-      break;
-    }
-    default:
-      NOTREACHED() << "Got a notification we didn't register for.";
-  }
+void TabContentsViewMac::RemoveOverlayView() {
+  DCHECK(overlaid_view_);
+  [overlaid_view_ removeFromSuperview];
+  overlaid_view_ = nil;
+}
+
+void TabContentsViewMac::CloseTab() {
+  tab_contents_->Close(tab_contents_->render_view_host());
 }
 
 @implementation TabContentsViewCocoa
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 90ba5a4..c3de07b3 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -1746,7 +1746,7 @@
 
 // Handle the openLearnMoreAboutCrashLink: action from SadTabController when
 // "Learn more" link in "Aw snap" page (i.e. crash page or sad tab) is
-// clicked. Decoupling the action from its target makes unitestting possible.
+// clicked. Decoupling the action from its target makes unit testing possible.
 - (void)openLearnMoreAboutCrashLink:(id)sender {
   if ([sender isKindOfClass:[SadTabController class]]) {
     SadTabController* sad_tab = static_cast<SadTabController*>(sender);
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller.mm b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
index c0d162ad..0003ae1 100644
--- a/chrome/browser/ui/cocoa/hung_renderer_controller.mm
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
@@ -46,7 +46,7 @@
 
  protected:
   // TabContentsObserver overrides:
-  virtual void RenderViewGone() OVERRIDE {
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE {
     [controller_ renderViewGone];
   }
   virtual void TabContentsDestroyed(TabContents* tab) OVERRIDE {
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h
index 48a97f6..f91327d 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
 
@@ -6,19 +6,24 @@
 #define CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_SAD_TAB_CONTROLLER_H_
 #pragma once
 
+#include "ui/gfx/native_widget_types.h"
+
+#if defined(__OBJC__)
 #import <Cocoa/Cocoa.h>
+#endif  // __OBJC__
 
 class TabContents;
 
+#if defined(__OBJC__)
+
 // A controller class that manages the SadTabView (aka "Aw Snap" or crash page).
 @interface SadTabController : NSViewController {
  @private
   TabContents* tabContents_;  // Weak reference.
 }
 
-// Designated initializer is initWithTabContents.
-- (id)initWithTabContents:(TabContents*)someTabContents
-                superview:(NSView*)superview;
+// Designated initializer.
+- (id)initWithTabContents:(TabContents*)tabContents;
 
 // This action just calls the NSApp sendAction to get it into the standard
 // Cocoa action processing.
@@ -30,4 +35,16 @@
 
 @end
 
+#else
+
+class SadTabController;
+
+#endif  // __OBJC__
+
+// Functions that may be accessed from non-Objective-C C/C++ code.
+namespace sad_tab_controller_mac {
+SadTabController* CreateSadTabController(TabContents* tab_contents);
+gfx::NativeView GetViewOfSadTabController(SadTabController* sad_tab);
+}
+
 #endif  // CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_SAD_TAB_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.mm
index c01a945..5812a8c 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.mm
@@ -7,17 +7,24 @@
 #include "base/mac/mac_util.h"
 #import "chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h"
 
+namespace sad_tab_controller_mac {
+
+SadTabController* CreateSadTabController(TabContents* tab_contents) {
+  return [[SadTabController alloc] initWithTabContents:tab_contents];
+}
+
+gfx::NativeView GetViewOfSadTabController(SadTabController* sad_tab) {
+  return [sad_tab view];
+}
+
+}  // namespace sad_tab_controller_mac
+
 @implementation SadTabController
 
-- (id)initWithTabContents:(TabContents*)someTabContents
-                superview:(NSView*)superview {
+- (id)initWithTabContents:(TabContents*)tabContents {
   if ((self = [super initWithNibName:@"SadTab"
                               bundle:base::mac::MainAppBundle()])) {
-    tabContents_ = someTabContents;
-
-    NSView* view = [self view];
-    [superview addSubview:view];
-    [view setFrame:[superview bounds]];
+    tabContents_ = tabContents;
   }
 
   return self;
@@ -31,11 +38,6 @@
   }
 }
 
-- (void)dealloc {
-  [[self view] removeFromSuperview];
-  [super dealloc];
-}
-
 - (TabContents*)tabContents {
   return tabContents_;
 }
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm
index 0ddf62f..2694d1d 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm
@@ -52,13 +52,13 @@
 
   // Creates the controller and adds its view to contents, caller has ownership.
   SadTabController* CreateController() {
-    NSView* contentView = [test_window_ contentView];
     SadTabController* controller =
-        [[SadTabController alloc] initWithTabContents:contents()
-                                            superview:contentView];
+        [[SadTabController alloc] initWithTabContents:contents()];
     EXPECT_TRUE(controller);
     NSView* view = [controller view];
     EXPECT_TRUE(view);
+    NSView* contentView = [test_window_ contentView];
+    [contentView addSubview:view];
 
     return controller;
   }
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.mm
index dffe008..b79f400 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.mm
@@ -161,9 +161,9 @@
 }
 
 // Called when someone clicks on the embedded link.
-- (BOOL) textView:(NSTextView*)textView
-    clickedOnLink:(id)link
-          atIndex:(NSUInteger)charIndex {
+- (BOOL)textView:(NSTextView*)textView
+   clickedOnLink:(id)link
+         atIndex:(NSUInteger)charIndex {
   if (controller_)
     [controller_ openLearnMoreAboutCrashLink:nil];
   return YES;
diff --git a/chrome/browser/ui/gtk/hung_renderer_dialog_gtk.cc b/chrome/browser/ui/gtk/hung_renderer_dialog_gtk.cc
index 2fb798a..f00a32b 100644
--- a/chrome/browser/ui/gtk/hung_renderer_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/hung_renderer_dialog_gtk.cc
@@ -49,7 +49,7 @@
     }
 
     // TabContentsObserver overrides:
-    virtual void RenderViewGone() OVERRIDE {
+    virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE {
       dialog_->Hide();
     }
     virtual void TabContentsDestroyed(TabContents* tab) OVERRIDE {
diff --git a/chrome/browser/ui/sad_tab_observer.cc b/chrome/browser/ui/sad_tab_observer.cc
new file mode 100644
index 0000000..51a788a
--- /dev/null
+++ b/chrome/browser/ui/sad_tab_observer.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 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/ui/sad_tab_observer.h"
+
+#include "chrome/browser/browser_shutdown.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/browser/tab_contents/tab_contents_view.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+
+#if defined(OS_MACOSX)
+#include "chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h"
+#elif defined(TOOLKIT_VIEWS)
+#include "chrome/browser/ui/views/sad_tab_view.h"
+#include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
+#elif defined(TOOLKIT_GTK)
+#include "chrome/browser/ui/gtk/sad_tab_gtk.h"
+#endif
+
+SadTabObserver::SadTabObserver(TabContents* tab_contents)
+    : TabContentsObserver(tab_contents) {
+  registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_CONNECTED,
+                 content::Source<TabContents>(tab_contents));
+}
+
+SadTabObserver::~SadTabObserver() {
+}
+
+void SadTabObserver::RenderViewGone(base::TerminationStatus status) {
+  // Only show the sad tab if we're not in browser shutdown, so that TabContents
+  // objects that are not in a browser (e.g., HTML dialogs) and thus are
+  // visible do not flash a sad tab page.
+  if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
+    return;
+
+  if (HasSadTab())
+    return;
+
+  gfx::NativeView view = AcquireSadTab(status);
+  tab_contents()->view()->InstallOverlayView(view);
+}
+
+void SadTabObserver::Observe(int type,
+                             const content::NotificationSource& source,
+                             const content::NotificationDetails& details) {
+  switch (type) {
+    case content::NOTIFICATION_TAB_CONTENTS_CONNECTED:
+      if (HasSadTab()) {
+        tab_contents()->view()->RemoveOverlayView();
+        ReleaseSadTab();
+      }
+      break;
+
+    default:
+      NOTREACHED() << "Got a notification we didn't register for.";
+  }
+}
+
+gfx::NativeView SadTabObserver::AcquireSadTab(base::TerminationStatus status) {
+#if defined(OS_MACOSX)
+  sad_tab_.reset(
+      sad_tab_controller_mac::CreateSadTabController(tab_contents()));
+  return sad_tab_controller_mac::GetViewOfSadTabController(sad_tab_.get());
+#elif defined(TOOLKIT_VIEWS)
+  SadTabView::Kind kind =
+      status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ?
+      SadTabView::KILLED : SadTabView::CRASHED;
+  views::Widget::InitParams sad_tab_params(
+      views::Widget::InitParams::TYPE_CONTROL);
+  // It is not possible to create a widget that has no parent, and later
+  // re-parent it. TODO(avi): This is a cheat. Can this be made cleaner?
+  sad_tab_params.parent_widget =
+      static_cast<TabContentsViewViews*>(tab_contents()->view());
+  sad_tab_params.ownership =
+      views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  sad_tab_.reset(new views::Widget);
+  sad_tab_->Init(sad_tab_params);
+  sad_tab_->SetContentsView(new SadTabView(tab_contents(), kind));
+  return sad_tab_->GetNativeView();
+#elif defined(TOOLKIT_GTK)
+  sad_tab_.reset(new SadTabGtk(
+      tab_contents(),
+      status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED
+          ? SadTabGtk::KILLED
+          : SadTabGtk::CRASHED));
+  return sad_tab_->widget();
+#else
+#error Unknown platform
+#endif
+}
+
+void SadTabObserver::ReleaseSadTab() {
+  sad_tab_.reset();
+}
+
+bool SadTabObserver::HasSadTab() {
+  return sad_tab_.get() != NULL;
+}
diff --git a/chrome/browser/ui/sad_tab_observer.h b/chrome/browser/ui/sad_tab_observer.h
new file mode 100644
index 0000000..ace1044
--- /dev/null
+++ b/chrome/browser/ui/sad_tab_observer.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 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_UI_SAD_TAB_OBSERVER_H_
+#define CHROME_BROWSER_UI_SAD_TAB_OBSERVER_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/tab_contents/tab_contents_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "ui/gfx/native_widget_types.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif
+
+#if defined(OS_MACOSX)
+class SadTabController;
+#elif defined(TOOLKIT_VIEWS)
+namespace views {
+class Widget;
+}
+#elif defined(TOOLKIT_GTK)
+class SadTabGtk;
+#endif
+
+// Per-tab class to manage sad tab views.
+class SadTabObserver : public TabContentsObserver,
+                       public content::NotificationObserver {
+ public:
+  explicit SadTabObserver(TabContents* tab_contents);
+  virtual ~SadTabObserver();
+
+ private:
+  // Platform specific function to get an instance of the sad tab page.
+  gfx::NativeView AcquireSadTab(base::TerminationStatus status);
+
+  // Platform specific function to release the instance of the sad tab page.
+  void ReleaseSadTab();
+
+  // Platform specific function to determine if there is a current sad tab page.
+  bool HasSadTab();
+
+  // Overridden from TabContentsObserver:
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
+
+  // Overridden from content::NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // Used to get notifications about renderers coming and going.
+  content::NotificationRegistrar registrar_;
+
+  // The platform views used to render the sad tab, non-NULL if visible.
+#if defined(OS_MACOSX)
+  class ScopedPtrRelease {
+   public:
+    inline void operator()(void* x) const {
+      base::mac::NSObjectRelease(x);
+    }
+  };
+  scoped_ptr_malloc<SadTabController, ScopedPtrRelease> sad_tab_;
+#elif defined(TOOLKIT_VIEWS)
+  scoped_ptr<views::Widget> sad_tab_;
+#elif defined(TOOLKIT_GTK)
+  scoped_ptr<SadTabGtk> sad_tab_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(SadTabObserver);
+};
+
+#endif  // CHROME_BROWSER_UI_SAD_TAB_OBSERVER_H_
diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
index eb0f3113..b381a036 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
+++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
@@ -47,6 +47,7 @@
 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
 #include "chrome/browser/ui/intents/web_intent_picker_factory_impl.h"
 #include "chrome/browser/ui/intents/web_intent_picker_controller.h"
+#include "chrome/browser/ui/sad_tab_observer.h"
 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -306,6 +307,7 @@
   external_protocol_observer_.reset(new ExternalProtocolObserver(contents));
   plugin_observer_.reset(new PluginObserver(this));
   print_preview_.reset(new printing::PrintPreviewMessageHandler(contents));
+  sad_tab_observer_.reset(new SadTabObserver(contents));
   // Start the in-browser thumbnailing if the feature is enabled.
   if (switches::IsInBrowserThumbnailingEnabled()) {
     thumbnail_generation_observer_.reset(new ThumbnailGenerator);
diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.h b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
index 1592e6c..33ba9a5 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
+++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
@@ -43,6 +43,7 @@
 class PluginObserver;
 class Profile;
 class RestoreTabHelper;
+class SadTabObserver;
 class SearchEngineTabHelper;
 class TabContentsSSLHelper;
 class TabContentsWrapperDelegate;
@@ -324,6 +325,7 @@
   scoped_ptr<ExternalProtocolObserver> external_protocol_observer_;
   scoped_ptr<PluginObserver> plugin_observer_;
   scoped_ptr<printing::PrintPreviewMessageHandler> print_preview_;
+  scoped_ptr<SadTabObserver> sad_tab_observer_;
   scoped_ptr<ThumbnailGenerator> thumbnail_generation_observer_;
 
   // TabContents (MUST BE LAST) ------------------------------------------------
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc
index d397f52..0b75aa6f 100644
--- a/chrome/browser/ui/views/hung_renderer_view.cc
+++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -90,7 +90,7 @@
     }
 
     // TabContentsObserver overrides:
-    virtual void RenderViewGone() OVERRIDE;
+    virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
     virtual void TabContentsDestroyed(TabContents* tab) OVERRIDE;
 
    private:
@@ -212,7 +212,8 @@
       tab_(tab) {
 }
 
-void HungPagesTableModel::TabContentsObserverImpl::RenderViewGone() {
+void HungPagesTableModel::TabContentsObserverImpl::RenderViewGone(
+    base::TerminationStatus status) {
   model_->TabDestroyed(this);
 }
 
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc
index 08d083e..8ec3234 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc
@@ -7,11 +7,9 @@
 #include <vector>
 
 #include "base/time.h"
-#include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/ui/constrained_window.h"
 #include "chrome/browser/ui/constrained_window_tab_helper.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
-#include "chrome/browser/ui/views/sad_tab_view.h"
 #include "chrome/browser/ui/views/tab_contents/native_tab_contents_view.h"
 #include "chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h"
 #include "content/browser/renderer_host/render_process_host.h"
@@ -39,9 +37,9 @@
 TabContentsViewViews::TabContentsViewViews(TabContents* tab_contents)
     : tab_contents_(tab_contents),
       native_tab_contents_view_(NULL),
-      sad_tab_widget_(NULL),
       close_tab_after_drag_ends_(false),
-      focus_manager_(NULL) {
+      focus_manager_(NULL),
+      overlaid_view_(NULL) {
   last_focused_view_storage_id_ =
       views::ViewStorage::GetInstance()->CreateStorageID();
 }
@@ -89,12 +87,6 @@
     return render_widget_host->view();
   }
 
-  // If we were showing sad tab, remove it now.
-  if (sad_tab_widget_) {
-    sad_tab_widget_->Close();
-    sad_tab_widget_ = NULL;
-  }
-
   return native_tab_contents_view_->CreateRenderWidgetHostView(
       render_widget_host);
 }
@@ -130,26 +122,6 @@
 
 void TabContentsViewViews::OnTabCrashed(base::TerminationStatus status,
                                         int /* error_code */) {
-  // Only show the sad tab if we're not in browser shutdown, so that TabContents
-  // objects that are not in a browser (e.g., HTML dialogs) and thus are
-  // visible do not flash a sad tab page.
-  if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
-    return;
-
-  // Note that it's possible to get this message after the window was destroyed.
-  if (GetNativeView()) {
-    SadTabView::Kind kind =
-        status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ?
-        SadTabView::KILLED : SadTabView::CRASHED;
-    views::Widget::InitParams sad_tab_widget_params(
-        views::Widget::InitParams::TYPE_CONTROL);
-    sad_tab_widget_params.parent_widget = this;
-    sad_tab_widget_params.bounds =
-        gfx::Rect(GetClientAreaScreenBounds().size());
-    sad_tab_widget_ = new views::Widget;
-    sad_tab_widget_->Init(sad_tab_widget_params);
-    sad_tab_widget_->SetContentsView(new SadTabView(tab_contents_, kind));
-  }
 }
 
 void TabContentsViewViews::SizeContents(const gfx::Size& size) {
@@ -173,8 +145,8 @@
     return;
   }
 
-  if (tab_contents_->is_crashed() && sad_tab_widget_ != NULL) {
-    sad_tab_widget_->GetContentsView()->RequestFocus();
+  if (overlaid_view_) {
+    overlaid_view_->GetContentsView()->RequestFocus();
     return;
   }
 
@@ -285,6 +257,19 @@
   *out = GetWindowScreenBounds();
 }
 
+void TabContentsViewViews::InstallOverlayView(gfx::NativeView view) {
+  DCHECK(!overlaid_view_);
+  views::Widget::ReparentNativeView(view, GetNativeView());
+  overlaid_view_ = views::Widget::GetWidgetForNativeView(view);
+  overlaid_view_->SetBounds(gfx::Rect(GetClientAreaScreenBounds().size()));
+}
+
+void TabContentsViewViews::RemoveOverlayView() {
+  DCHECK(overlaid_view_);
+  overlaid_view_->Close();
+  overlaid_view_ = NULL;
+}
+
 void TabContentsViewViews::UpdateDragCursor(WebDragOperation operation) {
   native_tab_contents_view_->SetDragCursor(operation);
 }
@@ -385,7 +370,7 @@
 }
 
 bool TabContentsViewViews::IsShowingSadTab() const {
-  return tab_contents_->is_crashed() && sad_tab_widget_;
+  return tab_contents_->is_crashed() && overlaid_view_;
 }
 
 void TabContentsViewViews::OnNativeTabContentsViewShown() {
@@ -472,7 +457,7 @@
 
 void TabContentsViewViews::OnNativeWidgetSizeChanged(
     const gfx::Size& new_size) {
-  if (sad_tab_widget_)
-    sad_tab_widget_->SetBounds(gfx::Rect(new_size));
+  if (overlaid_view_)
+    overlaid_view_->SetBounds(gfx::Rect(new_size));
   views::Widget::OnNativeWidgetSizeChanged(new_size);
 }
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h
index 413d01ef..b11f1d3 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h
@@ -16,7 +16,6 @@
 class ConstrainedWindowGtk;
 class NativeTabContentsView;
 class RenderViewContextMenuViews;
-class SadTabView;
 class SkBitmap;
 struct WebDropData;
 namespace gfx {
@@ -28,8 +27,6 @@
 }
 
 // Views-specific implementation of the TabContentsView.
-// TODO(beng): Remove last remnants of Windows-specificity, and make this
-//             subclass Widget.
 class TabContentsViewViews : public views::Widget,
                              public TabContentsView,
                              public internal::NativeTabContentsViewDelegate {
@@ -75,6 +72,8 @@
   virtual bool IsEventTracking() const;
   virtual void CloseTabAfterEventTracking();
   virtual void GetViewBounds(gfx::Rect* out) const OVERRIDE;
+  virtual void InstallOverlayView(gfx::NativeView view) OVERRIDE;
+  virtual void RemoveOverlayView() OVERRIDE;
 
   // Implementation of RenderViewHostDelegate::View.
   virtual void CreateNewWindow(
@@ -152,11 +151,6 @@
 
   NativeTabContentsView* native_tab_contents_view_;
 
-  // If non-null we're showing a sad tab. SadTabView is hosted in a separate
-  // widget so that TabContentsViewViews does not need to draw, and can be
-  // created without a texture.
-  views::Widget* sad_tab_widget_;
-
   // The id used in the ViewStorage to store the last focused view.
   int last_focused_view_storage_id_;
 
@@ -174,6 +168,10 @@
   // accessible when un-parented.
   mutable const views::FocusManager* focus_manager_;
 
+  // The overlaid view. Owned by the caller of |InstallOverlayView|; this is a
+  // weak reference.
+  views::Widget* overlaid_view_;
+
   DISALLOW_COPY_AND_ASSIGN(TabContentsViewViews);
 };
 
diff --git a/chrome/browser/ui/virtual_keyboard/virtual_keyboard_manager.cc b/chrome/browser/ui/virtual_keyboard/virtual_keyboard_manager.cc
index fe7b26b..0d906277 100644
--- a/chrome/browser/ui/virtual_keyboard/virtual_keyboard_manager.cc
+++ b/chrome/browser/ui/virtual_keyboard/virtual_keyboard_manager.cc
@@ -115,7 +115,7 @@
 
   // Overridden from TabContentsObserver.
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-  virtual void RenderViewGone() OVERRIDE;
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
   void OnRequest(const ExtensionHostMsg_Request_Params& params);
 
   // Overridden from TextInputTypeObserver.
@@ -347,7 +347,7 @@
   return handled;
 }
 
-void KeyboardWidget::RenderViewGone() {
+void KeyboardWidget::RenderViewGone(base::TerminationStatus status) {
   // Reload the keyboard if it crashes.
   dom_view_->LoadURL(keyboard_url_);
   dom_view_->SchedulePaint();
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 178bc21..b1f107a 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3187,6 +3187,8 @@
         'browser/ui/panels/panel_window_controller_cocoa.mm',
         'browser/ui/profile_error_dialog.cc',
         'browser/ui/profile_error_dialog.h',
+        'browser/ui/sad_tab_observer.cc',
+        'browser/ui/sad_tab_observer.h',
         'browser/ui/search_engines/edit_search_engine_controller.cc',
         'browser/ui/search_engines/edit_search_engine_controller.h',
         'browser/ui/search_engines/keyword_editor_controller.cc',