De-duplicate visibility handling code in WebContentsImpl

This is a cleanup in prepration for performing the changes laid out in
crbug.com/995131#c24

Bug: 995131
Change-Id: I177069c21782ccd38231c483da5469bc47932158
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1891119
Commit-Queue: Collin Baker <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Cr-Commit-Position: refs/heads/master@{#711576}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7b3bb6a..dafbbbc 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1456,28 +1456,8 @@
     OnPreferredSizeChanged(preferred_size_);
   }
 
-  if (GetVisibility() != Visibility::VISIBLE && !was_captured) {
-    // TODO: Share code with WasShown().
-    SendPageMessage(new PageMsg_WasShown(MSG_ROUTING_NONE));
-
-    if (auto* view = GetRenderWidgetHostView()) {
-      view->Show();
-#if defined(OS_MACOSX)
-      view->SetActive(true);
-#endif
-    }
-
-    if (!ShowingInterstitialPage())
-      SetVisibilityForChildViews(true);
-
-    for (FrameTreeNode* node : frame_tree_.Nodes()) {
-      RenderFrameProxyHost* parent = node->render_manager()->GetProxyToParent();
-      if (!parent)
-        continue;
-
-      parent->cross_process_frame_connector()->DelegateWasShown();
-    }
-  }
+  if (!was_captured)
+    UpdateVisibilityAndNotifyPageAndView(GetVisibility());
 }
 
 void WebContentsImpl::DecrementCapturerCount() {
@@ -1493,13 +1473,7 @@
     const gfx::Size old_size = preferred_size_for_capture_;
     preferred_size_for_capture_ = gfx::Size();
     OnPreferredSizeChanged(old_size);
-
-    if (visibility_ == Visibility::HIDDEN) {
-      DVLOG(1) << "Executing delayed WasHidden().";
-      WasHidden();
-    } else if (visibility_ == Visibility::OCCLUDED) {
-      WasOccluded();
-    }
+    UpdateVisibilityAndNotifyPageAndView(GetVisibility());
   }
 }
 
@@ -1694,67 +1668,11 @@
 }
 
 void WebContentsImpl::WasShown() {
-  controller_.SetActive(true);
-
-  // This shows the Page before showing the individual RenderWidgets, as
-  // RenderWidgets will work to produce compositor frames and handle input
-  // as soon as they are shown. But the Page and other classes do not expect to
-  // be producing frames when the Page is hidden. So we make sure the Page is
-  // shown first.
-  SendPageMessage(new PageMsg_WasShown(MSG_ROUTING_NONE));
-
-  if (auto* view = GetRenderWidgetHostView()) {
-    view->Show();
-#if defined(OS_MACOSX)
-    view->SetActive(true);
-#endif
-  }
-
-  if (!ShowingInterstitialPage())
-    SetVisibilityForChildViews(true);
-
-  last_active_time_ = base::TimeTicks::Now();
-  SetVisibility(Visibility::VISIBLE);
-
-  for (FrameTreeNode* node : frame_tree_.Nodes()) {
-    RenderFrameProxyHost* parent = node->render_manager()->GetProxyToParent();
-    if (!parent)
-      continue;
-
-    parent->cross_process_frame_connector()->DelegateWasShown();
-  }
+  UpdateVisibilityAndNotifyPageAndView(Visibility::VISIBLE);
 }
 
 void WebContentsImpl::WasHidden() {
-  // If there are entities capturing screenshots or video (e.g. mirroring),
-  // or in Picture-in-Picture mode, don't activate the "disable rendering"
-  // optimization.
-  if (!IsBeingCaptured() && !HasPictureInPictureVideo()) {
-    // This hides the individual RenderWidgets before hiding the Page, as
-    // RenderWidgets will work to produce compositor frames and handle input
-    // until they are hidden. But the Page and other classes do not expect to
-    // be producing frames when the Page is hidden. So we stop the widgets,
-    // then hide the Page.
-    //
-    // |GetRenderViewHost()| can be NULL if the user middle clicks a link to
-    // open a tab in the background, then closes the tab before selecting it.
-    // This is because closing the tab calls WebContentsImpl::Destroy(), which
-    // removes the |GetRenderViewHost()|; then when we actually destroy the
-    // window, OnWindowPosChanged() notices and calls WasHidden() (which
-    // calls us).
-    if (auto* view = GetRenderWidgetHostView())
-      view->Hide();
-
-    if (!ShowingInterstitialPage())
-      SetVisibilityForChildViews(false);
-  }
-
-  // Inform the renderer that the page was hidden if there are no entities
-  // capturing screenshots or video (e.g. mirroring).
-  if (!IsBeingCaptured())
-    SendPageMessage(new PageMsg_WasHidden(MSG_ROUTING_NONE));
-
-  SetVisibility(Visibility::HIDDEN);
+  UpdateVisibilityAndNotifyPageAndView(Visibility::HIDDEN);
 }
 
 bool WebContentsImpl::HasRecentInteractiveInputEvent() {
@@ -1785,25 +1703,7 @@
 #endif
 
 void WebContentsImpl::WasOccluded() {
-  // If there are entities capturing screenshots or video (e.g. mirroring),
-  // or in Picture-in-Picture mode, don't activate the "disable rendering"
-  // optimization.
-  if (!IsBeingCaptured() && !HasPictureInPictureVideo()) {
-    if (auto* main_view = GetRenderWidgetHostView())
-      main_view->WasOccluded();
-    if (!ShowingInterstitialPage()) {
-      // Occluding child view is treated as hiding the view
-      // (https://crbug.com/903455).
-      SetVisibilityForChildViews(false);
-    }
-  }
-
-  // Inform the renderer that the page was hidden if there are no entities
-  // capturing screenshots or video (e.g. mirroring).
-  if (!IsBeingCaptured())
-    SendPageMessage(new PageMsg_WasHidden(MSG_ROUTING_NONE));
-
-  SetVisibility(Visibility::OCCLUDED);
+  UpdateVisibilityAndNotifyPageAndView(Visibility::OCCLUDED);
 }
 
 Visibility WebContentsImpl::GetVisibility() {
@@ -2618,6 +2518,74 @@
     display_cutout_host_impl_->DidAcquireFullscreen(new_fullscreen_frame);
 }
 
+void WebContentsImpl::UpdateVisibilityAndNotifyPageAndView(
+    Visibility new_visibility) {
+  if (new_visibility == Visibility::VISIBLE)
+    controller_.SetActive(true);
+
+  // Only hide the page if there are no entities capturing screenshots
+  // or video (e.g. mirroring).
+  const bool page_is_visible =
+      new_visibility == Visibility::VISIBLE || IsBeingCaptured();
+  // If there are entities in Picture-in-Picture mode, don't activate
+  // the "disable rendering" optimization.
+  const bool view_is_visible = page_is_visible || HasPictureInPictureVideo();
+
+  // This shows the Page before showing the individual RenderWidgets, as
+  // RenderWidgets will work to produce compositor frames and handle input
+  // as soon as they are shown. But the Page and other classes do not expect to
+  // be producing frames when the Page is hidden. So we make sure the Page is
+  // shown first.
+  if (page_is_visible)
+    SendPageMessage(new PageMsg_WasShown(MSG_ROUTING_NONE));
+
+  // |GetRenderWidgetHostView()| can be null if the user middle clicks a link to
+  // open a tab in the background, then closes the tab before selecting it.
+  // This is because closing the tab calls WebContentsImpl::Destroy(), which
+  // removes the |GetRenderViewHost()|; then when we actually destroy the
+  // window, OnWindowPosChanged() notices and calls WasHidden() (which
+  // calls us).
+  if (auto* view = GetRenderWidgetHostView()) {
+    if (view_is_visible) {
+      view->Show();
+#if defined(OS_MACOSX)
+      view->SetActive(true);
+#endif
+    } else if (new_visibility == Visibility::HIDDEN) {
+      view->Hide();
+    } else {
+      view->WasOccluded();
+    }
+  }
+
+  if (!ShowingInterstitialPage())
+    SetVisibilityForChildViews(view_is_visible);
+
+  // Make sure to call SetVisibilityAndNotifyObservers(VISIBLE) before notifying
+  // the CrossProcessFrameConnector.
+  if (new_visibility == Visibility::VISIBLE) {
+    last_active_time_ = base::TimeTicks::Now();
+    SetVisibilityAndNotifyObservers(new_visibility);
+  }
+
+  if (!page_is_visible) {
+    // Similar to when showing the page, we only hide the page after
+    // hiding the individual RenderWidgets.
+    SendPageMessage(new PageMsg_WasHidden(MSG_ROUTING_NONE));
+  } else {
+    for (FrameTreeNode* node : frame_tree_.Nodes()) {
+      RenderFrameProxyHost* parent = node->render_manager()->GetProxyToParent();
+      if (!parent)
+        continue;
+
+      parent->cross_process_frame_connector()->DelegateWasShown();
+    }
+  }
+
+  if (new_visibility != Visibility::VISIBLE)
+    SetVisibilityAndNotifyObservers(new_visibility);
+}
+
 #if defined(OS_ANDROID)
 void WebContentsImpl::UpdateUserGestureCarryoverInfo() {
   if (delegate_)
@@ -4084,7 +4052,7 @@
   }
 }
 
-void WebContentsImpl::SetVisibility(Visibility visibility) {
+void WebContentsImpl::SetVisibilityAndNotifyObservers(Visibility visibility) {
   const Visibility previous_visibility = visibility_;
   visibility_ = visibility;
 
@@ -7250,12 +7218,7 @@
   if (visibility == visibility_)
     return;
 
-  if (visibility == Visibility::VISIBLE)
-    WasShown();
-  else if (visibility == Visibility::OCCLUDED)
-    WasOccluded();
-  else
-    WasHidden();
+  UpdateVisibilityAndNotifyPageAndView(visibility);
 }
 
 void WebContentsImpl::UpdateOverridingUserAgent() {