Add WasShown/WasHidden to RenderFrameObserver.

BUG=304341

Review URL: https://codereview.chromium.org/298283003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273375 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 552962dd..65bd5a0 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -19,6 +19,7 @@
 #include "content/browser/renderer_host/input/input_router.h"
 #include "content/browser/renderer_host/input/timeout_monitor.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/common/desktop_notification_messages.h"
 #include "content/common/frame_messages.h"
 #include "content/common/input_messages.h"
@@ -488,6 +489,10 @@
   frame_tree_node()->navigator()->DidNavigate(this, validated_params);
 }
 
+RenderWidgetHostImpl* RenderFrameHostImpl::GetRenderWidgetHost() {
+  return static_cast<RenderWidgetHostImpl*>(render_view_host_);
+}
+
 int RenderFrameHostImpl::GetEnabledBindings() {
   return render_view_host_->GetEnabledBindings();
 }
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 835f6e7..ab32d9f 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -39,6 +39,7 @@
 class RenderFrameProxyHost;
 class RenderProcessHost;
 class RenderViewHostImpl;
+class RenderWidgetHostImpl;
 struct ContextMenuParams;
 struct GlobalRequestID;
 struct Referrer;
@@ -80,6 +81,9 @@
   RenderViewHostImpl* render_view_host() { return render_view_host_; }
   RenderFrameHostDelegate* delegate() { return delegate_; }
   FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
+  // TODO(nasko): The RenderWidgetHost will be owned by RenderFrameHost in
+  // the future, so update this accessor to return the right pointer.
+  RenderWidgetHostImpl* GetRenderWidgetHost();
 
   // This function is called when this is a swapped out RenderFrameHost that
   // lives in the same process as the parent frame. The
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 5c3be86..1bcf3fc 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -216,6 +216,14 @@
   NavigateFrameToURL(root->child_at(0), http_url);
   EXPECT_EQ(http_url, observer.navigation_url());
   EXPECT_TRUE(observer.navigation_succeeded());
+  {
+    // There should be only one RenderWidgetHost when there are no
+    // cross-process iframes.
+    std::set<RenderWidgetHostImpl*> widgets_set =
+        static_cast<WebContentsImpl*>(shell()->web_contents())
+            ->GetRenderWidgetHostsInTree();
+    EXPECT_EQ(1U, widgets_set.size());
+  }
 
   // These must stay in scope with replace_host.
   GURL::Replacements replace_host;
@@ -238,6 +246,14 @@
   EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
   EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
   EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
+  {
+    // There should be now two RenderWidgetHosts, one for each process
+    // rendering a frame.
+    std::set<RenderWidgetHostImpl*> widgets_set =
+        static_cast<WebContentsImpl*>(shell()->web_contents())
+            ->GetRenderWidgetHostsInTree();
+    EXPECT_EQ(2U, widgets_set.size());
+  }
 
   // Load another cross-site page into the same iframe.
   cross_site_url = test_server()->GetURL("files/title3.html");
@@ -262,6 +278,12 @@
   EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
             child->current_frame_host()->GetProcess());
   EXPECT_NE(rph, child->current_frame_host()->GetProcess());
+  {
+    std::set<RenderWidgetHostImpl*> widgets_set =
+        static_cast<WebContentsImpl*>(shell()->web_contents())
+            ->GetRenderWidgetHostsInTree();
+    EXPECT_EQ(2U, widgets_set.size());
+  }
 }
 
 // Crash a subframe and ensures its children are cleared from the FrameTree.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 1256f58c..6ed02ce 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -217,6 +217,11 @@
   rfh->Send(message_copy);
 }
 
+void AddRenderWidgetHostToSet(std::set<RenderWidgetHostImpl*>* set,
+                              RenderFrameHost* rfh) {
+  set->insert(static_cast<RenderFrameHostImpl*>(rfh)->GetRenderWidgetHost());
+}
+
 }  // namespace
 
 WebContents* WebContents::Create(const WebContents::CreateParams& params) {
@@ -938,12 +943,18 @@
 
 void WebContentsImpl::WasShown() {
   controller_.SetActive(true);
-  RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
-  if (rwhv) {
-    rwhv->Show();
+
+  std::set<RenderWidgetHostImpl*> widgets = GetRenderWidgetHostsInTree();
+  for (std::set<RenderWidgetHostImpl*>::iterator iter = widgets.begin();
+       iter != widgets.end();
+       iter++) {
+    RenderWidgetHostView* rwhv = (*iter)->GetView();
+    if (rwhv) {
+      rwhv->Show();
 #if defined(OS_MACOSX)
-    rwhv->SetActive(true);
+      rwhv->SetActive(true);
 #endif
+    }
   }
 
   last_active_time_ = base::TimeTicks::Now();
@@ -971,9 +982,14 @@
     // removes the |GetRenderViewHost()|; then when we actually destroy the
     // window, OnWindowPosChanged() notices and calls WasHidden() (which
     // calls us).
-    RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
-    if (rwhv)
-      rwhv->Hide();
+    std::set<RenderWidgetHostImpl*> widgets = GetRenderWidgetHostsInTree();
+    for (std::set<RenderWidgetHostImpl*>::iterator iter = widgets.begin();
+         iter != widgets.end();
+         iter++) {
+      RenderWidgetHostView* rwhv = (*iter)->GetView();
+      if (rwhv)
+        rwhv->Hide();
+    }
   }
 
   FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden());
@@ -1129,6 +1145,12 @@
   observers_.RemoveObserver(observer);
 }
 
+std::set<RenderWidgetHostImpl*> WebContentsImpl::GetRenderWidgetHostsInTree() {
+  std::set<RenderWidgetHostImpl*> set;
+  ForEachFrame(base::Bind(&AddRenderWidgetHostToSet, base::Unretained(&set)));
+  return set;
+}
+
 void WebContentsImpl::Activate() {
   if (delegate_)
     delegate_->ActivateContents(this);
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index d65036d..c8a0355b 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -644,6 +644,7 @@
   FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles);
   FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate);
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest, PageDoesBackAndReload);
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, CrossSiteIframe);
 
   // So InterstitialPageImpl can access SetIsLoading.
   friend class InterstitialPageImpl;
@@ -674,6 +675,10 @@
   // watching |web_contents|. No-op if there is no such observer.
   void RemoveDestructionObserver(WebContentsImpl* web_contents);
 
+  // Traverses all the RenderFrameHosts in the FrameTree and creates a set
+  // all the unique RenderWidgetHosts.
+  std::set<RenderWidgetHostImpl*> GetRenderWidgetHostsInTree();
+
   // Callback function when showing JavaScript dialogs.  Takes in a routing ID
   // pair to identify the RenderFrameHost that opened the dialog, because it's
   // possible for the RenderFrameHost to be deleted by the time this is called.
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
index 63c73a5..ac836bb 100644
--- a/content/public/renderer/render_frame_observer.h
+++ b/content/public/renderer/render_frame_observer.h
@@ -39,6 +39,10 @@
   // Called when a load is explicitly stopped by the user or browser.
   virtual void OnStop() {}
 
+  // Called when the RenderFrame visiblity is changed.
+  virtual void WasHidden() {}
+  virtual void WasShown() {}
+
   // These match the Blink API notifications
   virtual void DidCommitProvisionalLoad(bool is_new_navigation) {}
   virtual void DidStartProvisionalLoad() {}
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index a1bf793..7be5f6e 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -416,6 +416,8 @@
       g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this));
   CHECK(result.second) << "Inserting a duplicate item.";
 
+  render_view_->RegisterRenderFrame(this);
+
 #if defined(OS_ANDROID)
   new JavaBridgeDispatcher(this);
 #endif
@@ -428,10 +430,13 @@
 RenderFrameImpl::~RenderFrameImpl() {
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone());
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct());
+
 #if defined(VIDEO_HOLE)
   if (media_player_manager_)
     render_view_->UnregisterVideoHoleFrame(this);
 #endif  // defined(VIDEO_HOLE)
+
+  render_view_->UnregisterRenderFrame(this);
   g_routing_id_frame_map.Get().erase(routing_id_);
   RenderThread::Get()->RemoveRoute(routing_id_);
 }
@@ -2887,6 +2892,14 @@
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnStop());
 }
 
+void RenderFrameImpl::WasHidden() {
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasHidden());
+}
+
+void RenderFrameImpl::WasShown() {
+  FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown());
+}
+
 // Tell the embedding application that the URL of the active page has changed.
 void RenderFrameImpl::UpdateURL(blink::WebFrame* frame) {
   DCHECK(!frame_ || frame_ == frame);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 166f8194..e122028 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -131,6 +131,10 @@
   // Notification from RenderView.
   virtual void OnStop();
 
+  // Notifications from RenderWidget.
+  void WasHidden();
+  void WasShown();
+
   // Start/Stop loading notifications.
   // TODO(nasko): Those are page-level methods at this time and come from
   // WebViewClient. We should move them to be WebFrameClient calls and put
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 5428b542..646b94b 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -768,6 +768,8 @@
   TRACE_EVENT0("renderer", "RenderWidget::OnWasHidden");
   // Go into a mode where we stop generating paint and scrolling events.
   SetHidden(true);
+  FOR_EACH_OBSERVER(RenderFrameImpl, render_frames_,
+                    WasHidden());
 }
 
 void RenderWidget::OnWasShown(bool needs_repainting) {
@@ -778,6 +780,8 @@
 
   // See OnWasHidden
   SetHidden(false);
+  FOR_EACH_OBSERVER(RenderFrameImpl, render_frames_,
+                    WasShown());
 
   if (!needs_repainting)
     return;
@@ -2124,6 +2128,14 @@
   swapped_out_frames_.RemoveObserver(frame);
 }
 
+void RenderWidget::RegisterRenderFrame(RenderFrameImpl* frame) {
+  render_frames_.AddObserver(frame);
+}
+
+void RenderWidget::UnregisterRenderFrame(RenderFrameImpl* frame) {
+  render_frames_.RemoveObserver(frame);
+}
+
 #if defined(VIDEO_HOLE)
 void RenderWidget::RegisterVideoHoleFrame(RenderFrameImpl* frame) {
   video_hole_frames_.AddObserver(frame);
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 43811c38..fac71786 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -113,6 +113,11 @@
   void RegisterSwappedOutChildFrame(RenderFrameImpl* frame);
   void UnregisterSwappedOutChildFrame(RenderFrameImpl* frame);
 
+  // Functions to track all RenderFrame objects associated with this
+  // RenderWidget.
+  void RegisterRenderFrame(RenderFrameImpl* frame);
+  void UnregisterRenderFrame(RenderFrameImpl* frame);
+
 #if defined(VIDEO_HOLE)
   void RegisterVideoHoleFrame(RenderFrameImpl* frame);
   void UnregisterVideoHoleFrame(RenderFrameImpl* frame);
@@ -720,6 +725,11 @@
   ObserverList<RenderFrameImpl> video_hole_frames_;
 #endif  // defined(VIDEO_HOLE)
 
+  // A list of RenderFrames associated with this RenderWidget. Notifications
+  // are sent to each frame in the list for events such as changing
+  // visibility state for example.
+  ObserverList<RenderFrameImpl> render_frames_;
+
   ui::MenuSourceType context_menu_source_type_;
   gfx::Point touch_editing_context_menu_location_;