Fix the issue that any tab/window closing hotkey will crash the Pepper Flash Fullscreen.

BUG=149821
TEST=None


Review URL: https://chromiumcodereview.appspot.com/10968037

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158408 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index 4f0243b..29011b53 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -9,6 +9,7 @@
 
 namespace content {
 
+class RenderWidgetHostImpl;
 struct NativeWebKeyboardEvent;
 
 //
@@ -18,6 +19,9 @@
 //  of the RenderWidgetHost.
 class CONTENT_EXPORT RenderWidgetHostDelegate {
  public:
+  // The RenderWidgetHost is going to be deleted.
+  virtual void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) {}
+
   // Callback to give the browser a chance to handle the specified keyboard
   // event before sending it to the renderer.
   // Returns true if the |event| was handled. Otherwise, if the |event| would
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index e5aaac8..62f2892 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -185,6 +185,9 @@
   surface_id_ = 0;
 
   process_->Release(routing_id_);
+
+  if (delegate_)
+    delegate_->RenderWidgetDeleted(this);
 }
 
 // static
@@ -969,10 +972,6 @@
 
     bool is_keyboard_shortcut = false;
     // Only pre-handle the key event if it's not handled by the input method.
-    // A delegate_ of NULL seems impossible but crash reports show that it
-    // can happen (see http://crbug.com/134465). This doesn't seem to happen
-    // with Chrome 22 and later, so checking the delegate_ here can be removed
-    // once Chrome 22 goes to stable..
     if (delegate_ && !key_event.skip_in_browser) {
       // We need to set |suppress_next_char_events_| to true if
       // PreHandleKeyboardEvent() returns true, but |this| may already be
@@ -1849,7 +1848,7 @@
     // We only send unprocessed key event upwards if we are not hidden,
     // because the user has moved away from us and no longer expect any effect
     // of this key event.
-    if (!processed && !is_hidden_ && !front_item.skip_in_browser) {
+    if (delegate_ && !processed && !is_hidden_ && !front_item.skip_in_browser) {
       delegate_->HandleKeyboardEvent(front_item);
 
       // WARNING: This RenderWidgetHostImpl can be deallocated at this point
@@ -2060,4 +2059,8 @@
   OnRenderAutoResized(new_size);
 }
 
+void RenderWidgetHostImpl::DetachDelegate() {
+  delegate_ = NULL;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 4eeaa44a..916bcd58 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -66,6 +66,8 @@
  public:
   // routing_id can be MSG_ROUTING_NONE, in which case the next available
   // routing id is taken from the RenderProcessHost.
+  // If this object outlives |delegate|, DetachDelegate() must be called when
+  // |delegate| goes away.
   RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
                        RenderProcessHost* process,
                        int routing_id);
@@ -419,6 +421,8 @@
   // any previous pending acks that are not relevant upon repaint.
   void ResetSizeAndRepaintPendingFlags();
 
+  void DetachDelegate();
+
  protected:
   virtual RenderWidgetHostImpl* AsRenderWidgetHostImpl() OVERRIDE;
 
@@ -439,10 +443,9 @@
   // when accelerated compositing is enabled.
   gfx::GLSurfaceHandle GetCompositingSurface();
 
-  // "RenderWidgetHostDelegate" ------------------------------------------------
-  // There is no RenderWidgetHostDelegate but the following methods serve the
-  // same purpose. They are overridden by RenderViewHost to send upwards to its
-  // delegate.
+  // ---------------------------------------------------------------------------
+  // The following methods are overridden by RenderViewHost to send upwards to
+  // its delegate.
 
   // Called when a mousewheel event was not processed by the renderer.
   virtual void UnhandledWheelEvent(const WebKit::WebMouseWheelEvent& event) {}
@@ -638,6 +641,7 @@
   void TickActiveSmoothScrollGesture();
 
   // Our delegate, which wants to know mainly about keyboard events.
+  // It will remain non-NULL until DetachDelegate() is called.
   RenderWidgetHostDelegate* delegate_;
 
   // Created during construction but initialized during Init*(). Therefore, it
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index fe9c088..a92e5d3 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -365,6 +365,12 @@
 WebContentsImpl::~WebContentsImpl() {
   is_being_destroyed_ = true;
 
+  for (std::set<RenderWidgetHostImpl*>::iterator iter =
+           created_widgets_.begin(); iter != created_widgets_.end(); ++iter) {
+    (*iter)->DetachDelegate();
+  }
+  created_widgets_.clear();
+
   // Clear out any JavaScript state.
   if (dialog_creator_)
     dialog_creator_->ResetJavaScriptState(this);
@@ -1194,6 +1200,19 @@
     delegate_->LostCapture();
 }
 
+void WebContentsImpl::RenderWidgetDeleted(
+    RenderWidgetHostImpl* render_widget_host) {
+  if (is_being_destroyed_) {
+    // |created_widgets_| might have been destroyed.
+    return;
+  }
+
+  std::set<RenderWidgetHostImpl*>::iterator iter =
+      created_widgets_.find(render_widget_host);
+  if (iter != created_widgets_.end())
+    created_widgets_.erase(iter);
+}
+
 bool WebContentsImpl::PreHandleKeyboardEvent(
     const NativeWebKeyboardEvent& event,
     bool* is_keyboard_shortcut) {
@@ -1356,6 +1375,8 @@
   content::RenderProcessHost* process = GetRenderProcessHost();
   RenderWidgetHostImpl* widget_host =
       new RenderWidgetHostImpl(this, process, route_id);
+  created_widgets_.insert(widget_host);
+
   RenderWidgetHostViewPort* widget_view =
       RenderWidgetHostViewPort::CreateViewForWidget(widget_host);
   if (!is_fullscreen) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 2dcbfd2e..9429df3 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_IMPL_H_
 
 #include <map>
+#include <set>
 #include <string>
 
 #include "base/compiler_specific.h"
@@ -47,6 +48,7 @@
 class RenderViewHost;
 class RenderViewHostDelegateView;
 class RenderViewHostImpl;
+class RenderWidgetHostImpl;
 class SiteInstance;
 class TestWebContents;
 class WebContentsDelegate;
@@ -429,6 +431,8 @@
 
   // RenderWidgetHostDelegate --------------------------------------------------
 
+  virtual void RenderWidgetDeleted(
+      content::RenderWidgetHostImpl* render_widget_host) OVERRIDE;
   virtual bool PreHandleKeyboardEvent(
       const content::NativeWebKeyboardEvent& event,
       bool* is_keyboard_shortcut) OVERRIDE;
@@ -859,6 +863,10 @@
   // to the RVH through which the message was received.
   content::RenderViewHost* message_source_;
 
+  // All live RenderWidgetHostImpls that are created by this object and may
+  // outlive it.
+  std::set<content::RenderWidgetHostImpl*> created_widgets_;
+
   DISALLOW_COPY_AND_ASSIGN(WebContentsImpl);
 };