Fix scroll restoration when exiting fullscreen mode.

There's two problems in Chrome/Blink that cause the existing scroll restoration
not to work on desktop platforms:

In Blink, when entering fullscreen mode, FullscreenController saves the current
scroll offset so that it can restore it later. However, this was done in
FullscreenController::didEnterFullScreen, which is called only after WebViewImpl
is resized, meaning that the scroll offset may already be wiped out.

In Chrome, we explicitly send a WasResized message to ensure that the renderer
is notified of the fullscreen change in cases where toggling fullscreen doesn't
actually change the renderer's size (e.g. going from tab fullscreen to browser
fullscreen). However, this means that the renderer gets two separate resize
events for the fullscreen toggle: one that toggles fullscreen and another for
the size change. Thus, Blink tries to restore the scroll offset before the
renderer is resized which might then clamp that scroll offset.

For the first issue, I've moved the scroll offset saving logic into
FullscreenController::enterFullScreenForElement which is called before sending
the request IPC to the browser.

For the second issue, I added a will_cause_resize parameter to
WebContents::ExitFullscreen that tells the method whether exiting fullscreen will
potentially cause a window resize. Based on this, WebContents can choose to
explicitly send the WasResized only in cases where it will not occur otherwise.
This ensures the Resize message includes both the fullscreen state change and
size change in one message.

BUG=142427
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_site_isolation

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

Cr-Commit-Position: refs/heads/master@{#372146}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 3eaba069..4ff0a3a 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1682,11 +1682,13 @@
     delegate_->EnterFullscreenModeForTab(this, origin);
 
   FOR_EACH_OBSERVER(WebContentsObserver, observers_,
-                    DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab(
-                        GetRenderViewHost()->GetWidget())));
+                    DidToggleFullscreenModeForTab(
+                        IsFullscreenForCurrentTab(
+                            GetRenderViewHost()->GetWidget()),
+                        false));
 }
 
-void WebContentsImpl::ExitFullscreenMode() {
+void WebContentsImpl::ExitFullscreenMode(bool will_cause_resize) {
   // This method is being called to leave renderer-initiated fullscreen mode.
   // Make sure any existing fullscreen widget is shut down first.
   RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
@@ -1704,20 +1706,26 @@
   if (delegate_)
     delegate_->ExitFullscreenModeForTab(this);
 
-  // Ensure web contents exit fullscreen state by sending a resize message,
-  // which includes the fullscreen state. This is required for the situation
-  // of the browser moving the view into a fullscreen state "browser fullscreen"
-  // and then the contents entering "tab fullscreen". Exiting the contents
-  // "tab fullscreen" then won't have the side effect of the view resizing,
-  // hence the explicit call here is required.
-  if (RenderWidgetHostView* rwh_view = GetRenderWidgetHostView()) {
-    if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost())
-      render_widget_host->WasResized();
+  // The fullscreen state is communicated to the renderer through a resize
+  // message. If the change in fullscreen state doesn't cause a view resize
+  // then we must ensure web contents exit the fullscreen state by explicitly
+  // sending a resize message. This is required for the situation of the browser
+  // moving the view into a "browser fullscreen" state and then the contents
+  // entering "tab fullscreen". Exiting the contents "tab fullscreen" then won't
+  // have the side effect of the view resizing, hence the explicit call here is
+  // required.
+  if (!will_cause_resize) {
+    if (RenderWidgetHostView* rwhv = GetRenderWidgetHostView()) {
+        if (RenderWidgetHost* render_widget_host = rwhv->GetRenderWidgetHost())
+          render_widget_host->WasResized();
+    }
   }
 
   FOR_EACH_OBSERVER(WebContentsObserver, observers_,
-                    DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab(
-                        GetRenderViewHost()->GetWidget())));
+                    DidToggleFullscreenModeForTab(
+                        IsFullscreenForCurrentTab(
+                            GetRenderViewHost()->GetWidget()),
+                        will_cause_resize));
 }
 
 bool WebContentsImpl::IsFullscreenForCurrentTab(
@@ -2882,10 +2890,10 @@
   manifest_manager_host_->HasManifest(GetMainFrame(), callback);
 }
 
-void WebContentsImpl::ExitFullscreen() {
+void WebContentsImpl::ExitFullscreen(bool will_cause_resize) {
   // Clean up related state and initiate the fullscreen exit.
   GetRenderViewHost()->GetWidget()->RejectMouseLockOrUnlockIfNecessary();
-  ExitFullscreenMode();
+  ExitFullscreenMode(will_cause_resize);
 }
 
 void WebContentsImpl::ResumeLoadingCreatedWebContents() {
@@ -3068,7 +3076,7 @@
     return;
   }
   if (IsFullscreenForCurrentTab(GetRenderViewHost()->GetWidget()))
-    ExitFullscreen();
+    ExitFullscreen(false);
   DCHECK(!IsFullscreenForCurrentTab(GetRenderViewHost()->GetWidget()));
 }
 
@@ -3940,7 +3948,7 @@
   // Ensure fullscreen mode is exited in the |delegate_| since a crashed
   // renderer may not have made a clean exit.
   if (IsFullscreenForCurrentTab(GetRenderViewHost()->GetWidget()))
-    ExitFullscreenMode();
+    ExitFullscreenMode(false);
 
   // Cancel any visible dialogs so they are not left dangling over the sad tab.
   CancelActiveAndPendingDialogs();