Bug 1204149 - Fix entering DOM fullscreen in fullscreen mode for e10s. r=smaug
authorXidorn Quan <quanxunzhen@gmail.com>
Fri, 18 Sep 2015 09:33:54 +0800
changeset 295783 28082ed69e6639c1248e18550ff076f0c2b2bc42
parent 295782 0573cd4aed27d346c1235ac984a4376fb93d9480
child 295784 982d9a8639898c9060986d8fa582dc4ebef93af2
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1204149
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1204149 - Fix entering DOM fullscreen in fullscreen mode for e10s. r=smaug
browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js
dom/base/nsDocument.cpp
--- a/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js
+++ b/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js
@@ -115,22 +115,41 @@ var gTests = [
     desc: "F11 key",
     affectsFullscreenMode: true,
     exitFunc: function () {
       executeSoon(() => EventUtils.synthesizeKey("VK_F11", {}));
     }
   }
 ];
 
+function checkState(expectedStates, contentStates) {
+  is(contentStates.inDOMFullscreen, expectedStates.inDOMFullscreen,
+     "The DOM fullscreen state of the content should match");
+  // TODO window.fullScreen is not updated as soon as the fullscreen
+  //      state flips in child process, hence checking it could cause
+  //      anonying intermittent failure. As we just want to confirm the
+  //      fullscreen state of the browser window, we can just check the
+  //      that on the chrome window below.
+  // is(contentStates.inFullscreen, expectedStates.inFullscreen,
+  //    "The fullscreen state of the content should match");
+  is(document.mozFullScreen, expectedStates.inDOMFullscreen,
+     "The DOM fullscreen state of the chrome should match");
+  is(window.fullScreen, expectedStates.inFullscreen,
+     "The fullscreen state of the chrome should match");
+}
+
+const kPage = "http://example.org/browser/browser/" +
+              "base/content/test/general/dummy_page.html";
+
 add_task(function* () {
   yield pushPrefs(
     ["full-screen-api.transition-duration.enter", "0 0"],
     ["full-screen-api.transition-duration.leave", "0 0"]);
 
-  let tab = gBrowser.addTab("about:robots");
+  let tab = gBrowser.addTab(kPage);
   let browser = tab.linkedBrowser;
   gBrowser.selectedTab = tab;
   yield waitForDocLoadComplete();
 
   registerCleanupFunction(() => {
     if (browser.contentWindow.fullScreen) {
       BrowserFullScreen();
     }
@@ -143,70 +162,60 @@ add_task(function* () {
   gMessageManager.addMessageListener(
     "Test:FullscreenChanged", captureUnexpectedFullscreenChange);
 
   // Wait for the document being activated, so that
   // fullscreen request won't be denied.
   yield new Promise(resolve => listenOneMessage("Test:Activated", resolve));
 
   for (let test of gTests) {
+    let contentStates;
     info("Testing exit DOM fullscreen via " + test.desc);
 
-    var { inDOMFullscreen, inFullscreen } = yield queryFullscreenState();
-    ok(!inDOMFullscreen, "Shouldn't have been in DOM fullscreen");
-    ok(!inFullscreen, "Shouldn't have been in fullscreen");
+    contentStates = yield queryFullscreenState();
+    checkState({inDOMFullscreen: false, inFullscreen: false}, contentStates);
 
     /* DOM fullscreen without fullscreen mode */
 
-    // Enter DOM fullscreen
+    info("> Enter DOM fullscreen");
     gMessageManager.sendAsyncMessage("Test:RequestFullscreen");
-    var { inDOMFullscreen, inFullscreen } =
-      yield waitForFullscreenChanges(FS_CHANGE_BOTH);
-    ok(inDOMFullscreen, "Should now be in DOM fullscreen");
-    ok(inFullscreen, "Should now be in fullscreen");
+    contentStates = yield waitForFullscreenChanges(FS_CHANGE_BOTH);
+    checkState({inDOMFullscreen: true, inFullscreen: true}, contentStates);
 
-    // Exit DOM fullscreen
+    info("> Exit DOM fullscreen");
     test.exitFunc();
-    var { inDOMFullscreen, inFullscreen } =
-      yield waitForFullscreenChanges(FS_CHANGE_BOTH);
-    ok(!inDOMFullscreen, "Should no longer be in DOM fullscreen");
-    ok(!inFullscreen, "Should no longer be in fullscreen");
+    contentStates = yield waitForFullscreenChanges(FS_CHANGE_BOTH);
+    checkState({inDOMFullscreen: false, inFullscreen: false}, contentStates);
 
     /* DOM fullscreen with fullscreen mode */
 
-    // Enter fullscreen mode
+    info("> Enter fullscreen mode");
     // Need to be asynchronous because sizemodechange event could be
     // dispatched synchronously, which would cause the event listener
     // miss that event and wait infinitely.
     executeSoon(() => BrowserFullScreen());
-    var { inDOMFullscreen, inFullscreen } =
-      yield waitForFullscreenChanges(FS_CHANGE_SIZE);
-    ok(!inDOMFullscreen, "Shouldn't have been in DOM fullscreen");
-    ok(inFullscreen, "Should now be in fullscreen mode");
+    contentStates = yield waitForFullscreenChanges(FS_CHANGE_SIZE);
+    checkState({inDOMFullscreen: false, inFullscreen: true}, contentStates);
 
-    // Enter DOM fullscreen
+    info("> Enter DOM fullscreen in fullscreen mode");
     gMessageManager.sendAsyncMessage("Test:RequestFullscreen");
-    var { inDOMFullscreen, inFullscreen } =
-      yield waitForFullscreenChanges(FS_CHANGE_DOM);
-    ok(inDOMFullscreen, "Should now be in DOM fullscreen");
-    ok(inFullscreen, "Should still be in fullscreen");
+    contentStates = yield waitForFullscreenChanges(FS_CHANGE_DOM);
+    checkState({inDOMFullscreen: true, inFullscreen: true}, contentStates);
 
-    // Exit DOM fullscreen
+    info("> Exit DOM fullscreen in fullscreen mode");
     test.exitFunc();
-    var { inDOMFullscreen, inFullscreen } =
-      yield waitForFullscreenChanges(test.affectsFullscreenMode ?
-                                     FS_CHANGE_BOTH : FS_CHANGE_DOM);
-    ok(!inDOMFullscreen, "Should no longer be in DOM fullscreen");
-    if (test.affectsFullscreenMode) {
-      ok(!inFullscreen, "Should no longer be in fullscreen mode");
-    } else {
-      ok(inFullscreen, "Should still be in fullscreen mode");
-    }
+    contentStates = yield waitForFullscreenChanges(
+      test.affectsFullscreenMode ? FS_CHANGE_BOTH : FS_CHANGE_DOM);
+    checkState({
+      inDOMFullscreen: false,
+      inFullscreen: !test.affectsFullscreenMode
+    }, contentStates);
 
     /* Cleanup */
 
     // Exit fullscreen mode if we are still in
-    if (browser.contentWindow.fullScreen) {
+    if (window.fullScreen) {
+      info("> Cleanup");
       executeSoon(() => BrowserFullScreen());
       yield waitForFullscreenChanges(FS_CHANGE_SIZE);
     }
   }
 });
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -11681,37 +11681,60 @@ GetRootWindow(nsIDocument* aDoc)
   if (!docShell) {
     return nullptr;
   }
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   docShell->GetRootTreeItem(getter_AddRefs(rootItem));
   return rootItem ? rootItem->GetWindow() : nullptr;
 }
 
+static bool
+ShouldApplyFullscreenDirectly(nsIDocument* aDoc,
+                              nsPIDOMWindow* aRootWin)
+{
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    // If we are in the content process, we can apply the fullscreen
+    // state directly only if we have been in DOM fullscreen, because
+    // otherwise we always need to notify the chrome.
+    return nsContentUtils::GetRootDocument(aDoc)->IsFullScreenDoc();
+  } else {
+    // If we are in the chrome process, and the window has not been in
+    // fullscreen, we certainly need to make that fullscreen first.
+    bool fullscreen;
+    NS_WARN_IF(NS_FAILED(aRootWin->GetFullScreen(&fullscreen)));
+    if (!fullscreen) {
+      return false;
+    }
+    // The iterator not being at end indicates there is still some
+    // pending fullscreen request relates to this document. We have to
+    // push the request to the pending queue so requests are handled
+    // in the correct order.
+    PendingFullscreenRequestList::Iterator
+      iter(aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
+    if (!iter.AtEnd()) {
+      return false;
+    }
+    // We have to apply the fullscreen state directly in this case,
+    // because nsGlobalWindow::SetFullscreenInternal() will do nothing
+    // if it is already in fullscreen. If we do not apply the state but
+    // instead add it to the queue and wait for the window as normal,
+    // we would get stuck.
+    return true;
+  }
+}
+
 void
 nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
 {
   nsCOMPtr<nsPIDOMWindow> rootWin = GetRootWindow(this);
   if (!rootWin) {
     return;
   }
 
-  // If we have been in fullscreen, apply the new state directly.
-  // Note that we should check both condition, because if we are in
-  // child process, our window may not report to be in fullscreen.
-  // Also, it is possible that the root window reports that it is in
-  // fullscreen while there exists pending fullscreen request because
-  // of ongoing fullscreen transition. In that case, we shouldn't
-  // apply the state before any previous request.
-  if ((static_cast<nsGlobalWindow*>(rootWin.get())->FullScreen() &&
-       // The iterator being at end at the beginning indicates there is
-       // no pending fullscreen request which relates to this document.
-       PendingFullscreenRequestList::Iterator(
-         this, PendingFullscreenRequestList::eDocumentsWithSameRoot).AtEnd()) ||
-      nsContentUtils::GetRootDocument(this)->IsFullScreenDoc()) {
+  if (ShouldApplyFullscreenDirectly(this, rootWin)) {
     ApplyFullscreen(*aRequest);
     return;
   }
 
   // We don't need to check element ready before this point, because
   // if we called ApplyFullscreen, it would check that for us.
   Element* elem = aRequest->GetElement();
   if (!FullscreenElementReadyCheck(elem, aRequest->mIsCallerChrome)) {