Bug 1270648 part 4 - Make fullscreen enabled flag not be affected after document is loaded. r?smaug draft
authorXidorn Quan <me@upsuper.org>
Mon, 16 May 2016 10:12:56 +1000
changeset 367718 69f0f4754620ec47fcb050818d16d95a237f3f0b
parent 367717 9030af8d17e288251956d1837f7a96f10d56c31e
child 367719 8dfd78925fe882360ae966f151d241914b5f86bb
push id18336
push userxquan@mozilla.com
push dateTue, 17 May 2016 09:32:49 +0000
reviewerssmaug
bugs1270648
milestone49.0a1
Bug 1270648 part 4 - Make fullscreen enabled flag not be affected after document is loaded. r?smaug MozReview-Commit-ID: L2dMAUr63qv
docshell/base/nsDocShell.cpp
dom/base/ImportManager.cpp
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/xul/XULDocument.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html.ini
testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2516,16 +2516,20 @@ nsDocShell::GetFullscreenAllowed(bool* a
     // If any ancestor iframe does not have allowfullscreen attribute
     // set, then fullscreen is not allowed.
     if (!frameElement->HasAttr(kNameSpaceID_None,
                                nsGkAtoms::allowfullscreen) &&
         !frameElement->HasAttr(kNameSpaceID_None,
                                nsGkAtoms::mozallowfullscreen)) {
       return NS_OK;
     }
+    nsIDocument* doc = frameElement->GetUncomposedDoc();
+    if (!doc || !doc->FullscreenEnabledInternal()) {
+      return NS_OK;
+    }
   }
 
   // If we have no parent then we're the root docshell; no ancestor of the
   // original docshell doesn't have a allowfullscreen attribute, so
   // report fullscreen as allowed.
   RefPtr<nsDocShell> parent = GetParentDocshell();
   if (!parent) {
     *aFullscreenAllowed = true;
--- a/dom/base/ImportManager.cpp
+++ b/dom/base/ImportManager.cpp
@@ -591,18 +591,20 @@ ImportLoader::OnStartRequest(nsIRequest*
                                   DocumentFlavorHTML);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_ABORT_ERR);
 
   // The imported document must know which master document it belongs to.
   mDocument = do_QueryInterface(importDoc);
   nsCOMPtr<nsIDocument> master = mImportParent->MasterDocument();
   mDocument->SetMasterDocument(master);
 
-  // We want to inherit the sandbox flags from the master document.
+  // We want to inherit the sandbox flags and fullscreen enabled flag
+  // from the master document.
   mDocument->SetSandboxFlags(master->GetSandboxFlags());
+  mDocument->SetFullscreenEnabled(master->FullscreenEnabledInternal());
 
   // We have to connect the blank document we created with the channel we opened,
   // and create its own LoadGroup for it.
   nsCOMPtr<nsIStreamListener> listener;
   nsCOMPtr<nsILoadGroup> loadGroup;
   channel->GetLoadGroup(getter_AddRefs(loadGroup));
   nsCOMPtr<nsILoadGroup> newLoadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
   NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1447,16 +1447,17 @@ nsIDocument::nsIDocument()
     // unless we get a window, and in that case the docshell value will get
     // &&-ed in, this is safe.
     mAllowDNSPrefetch(true),
     mIsBeingUsedAsImage(false),
     mHasLinksToUpdate(false),
     mFontFaceSetDirty(true),
     mGetUserFontSetCalled(false),
     mPostedFlushUserFontSet(false),
+    mFullscreenEnabled(false),
     mPartID(0),
     mDidFireDOMContentLoaded(true),
     mHasScrollLinkedEffect(false),
     mUserHasInteracted(false)
 {
   SetInDocument();
 
   PR_INIT_CLIST(&mDOMMediaQueryLists);
@@ -2574,23 +2575,25 @@ nsDocument::StartDocumentLoad(const char
     bool isSrcdocChannel;
     inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
     if (isSrcdocChannel) {
       mIsSrcdocDocument = true;
     }
   }
 
   // If this document is being loaded by a docshell, copy its sandbox flags
-  // to the document. These are immutable after being set here.
+  // to the document, and store the fullscreen enabled flag. These are
+  // immutable after being set here.
   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aContainer);
 
   if (docShell) {
     nsresult rv = docShell->GetSandboxFlags(&mSandboxFlags);
     NS_ENSURE_SUCCESS(rv, rv);
     WarnIfSandboxIneffective(docShell, mSandboxFlags, GetChannel());
+    mFullscreenEnabled = docShell->GetFullscreenAllowed();
   }
 
   // The CSP directive upgrade-insecure-requests not only applies to the
   // toplevel document, but also to nested documents. Let's propagate that
   // flag from the parent to the nested document.
   nsCOMPtr<nsIDocShellTreeItem> treeItem = this->GetDocShell();
   if (treeItem) {
     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
@@ -11729,24 +11732,19 @@ GetFullscreenError(nsIDocument* aDoc, bo
     // in a Runnable, so don't use GetMozFullScreenEnabled() from a
     // Runnable!
     return nullptr;
   }
 
   if (!nsContentUtils::IsFullScreenApiEnabled()) {
     return "FullscreenDeniedDisabled";
   }
-
-  // Ensure that all containing elements are <iframe> and have
-  // allowfullscreen attribute set.
-  nsCOMPtr<nsIDocShell> docShell(aDoc->GetDocShell());
-  if (!docShell || !docShell->GetFullscreenAllowed()) {
+  if (!aDoc->FullscreenEnabledInternal()) {
     return "FullscreenDeniedContainerNotAllowed";
   }
-
   return nullptr;
 }
 
 bool
 nsDocument::FullscreenElementReadyCheck(Element* aElement,
                                         bool aWasCallerChrome)
 {
   NS_ASSERTION(aElement,
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2560,16 +2560,21 @@ public:
   // Not const because all the full-screen goop is not const
   virtual bool FullscreenEnabled() = 0;
   virtual Element* GetFullscreenElement() = 0;
   bool Fullscreen()
   {
     return !!GetFullscreenElement();
   }
   void ExitFullscreen();
+  bool FullscreenEnabledInternal() const { return mFullscreenEnabled; }
+  void SetFullscreenEnabled(bool aEnabled)
+  {
+    mFullscreenEnabled = aEnabled;
+  }
   Element* GetMozPointerLockElement();
   void MozExitPointerLock()
   {
     UnlockPointer(this);
   }
   bool Hidden() const
   {
     return mVisibilityState != mozilla::dom::VisibilityState::Visible;
@@ -3019,16 +3024,20 @@ protected:
   bool mFontFaceSetDirty : 1;
 
   // Has GetUserFontSet() been called?
   bool mGetUserFontSetCalled : 1;
 
   // Do we currently have an event posted to call FlushUserFontSet?
   bool mPostedFlushUserFontSet : 1;
 
+  // Whether fullscreen is enabled for this document. This corresponds
+  // to the "fullscreen enabled flag" in the HTML spec.
+  bool mFullscreenEnabled : 1;
+
   enum Type {
     eUnknown, // should never be used
     eHTML,
     eXHTML,
     eGenericXML,
     eSVG,
     eXUL
   };
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -377,16 +377,17 @@ XULDocument::StartDocumentLoad(const cha
             }
         }
     }
     // NOTE: If this ever starts calling nsDocument::StartDocumentLoad
     // we'll possibly need to reset our content type afterwards.
     mStillWalking = true;
     mMayStartLayout = false;
     mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
+    mFullscreenEnabled = true;
 
     mChannel = aChannel;
 
     // Get the URI.  Note that this should match nsDocShell::OnLoadingSite
     nsresult rv =
         NS_GetFinalChannelURI(aChannel, getter_AddRefs(mDocumentURI));
     NS_ENSURE_SUCCESS(rv, rv);
     
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -35338,16 +35338,22 @@
           }
         ],
         "html/semantics/document-metadata/the-base-element/base_srcdoc.html": [
           {
             "path": "html/semantics/document-metadata/the-base-element/base_srcdoc.html",
             "url": "/html/semantics/document-metadata/the-base-element/base_srcdoc.html"
           }
         ],
+        "html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html": [
+          {
+            "path": "html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html",
+            "url": "/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html"
+          }
+        ],
         "html/semantics/embedded-content/the-iframe-element/iframe-load-event.html": [
           {
             "path": "html/semantics/embedded-content/the-iframe-element/iframe-load-event.html",
             "url": "/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html"
           }
         ],
         "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping.html": [
           {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html.ini
@@ -0,0 +1,3 @@
+[iframe-allow-fullscreen.html.ini]
+  type: testharness
+  prefs: [full-screen-api.unprefix.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Check how allowfullscreen affects fullscreen enabled flag</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#initialise-the-document-object">
+<link rel="help" href="https://fullscreen.spec.whatwg.org/#fullscreen-enabled-flag">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="log"></div>
+<script>
+  async_test(function(t) {
+    var iframe = document.createElement("iframe");
+    iframe.src = "support/blank.htm";
+    var eventWatcher = new EventWatcher(t, iframe, "load");
+    document.body.appendChild(iframe);
+    t.add_cleanup(function() {
+      document.body.removeChild(iframe);
+    });
+
+    assert_true(document.fullscreenEnabled, "Top level document has fullscreen enabled flag set");
+    eventWatcher.wait_for("load").then(t.step_func(function() {
+      assert_false(iframe.contentDocument.fullscreenEnabled, "Document inside iframe without allowfullscreen attribute should not have fullscreen enabled flag set");
+      iframe.setAttribute("allowfullscreen", true);
+      assert_false(iframe.contentDocument.fullscreenEnabled, "Setting allowfullscreen attribute after document load should not affect fullscreen enabled flag");
+      iframe.contentWindow.location.reload();
+      return eventWatcher.wait_for("load");
+    })).then(t.step_func(function() {
+      assert_true(iframe.contentDocument.fullscreenEnabled, "Fullscreen enabled flag should be set when a new document is loaded with allowfullscreen attribute present");
+      iframe.removeAttribute("allowfullscreen");
+      assert_true(iframe.contentDocument.fullscreenEnabled, "Removing allowfullscreen attribute should not affect fullscreen enabled flag");
+      iframe.contentWindow.location.reload();
+      return eventWatcher.wait_for("load");
+    })).then(t.step_func_done(function() {
+      assert_false(iframe.contentDocument.fullscreenEnabled, "Fullscreen enabled flag should be reset when a new document is loaded with allowfullscreen attribute absent");
+    }));
+  }, "iframe-allowfullscreen");
+
+  async_test(function(t) {
+    var iframe = document.createElement("iframe");
+    iframe.src = "support/blank.htm";
+    var eventWatcher = new EventWatcher(t, iframe, "load");
+    document.body.appendChild(iframe);
+    t.add_cleanup(function() {
+      document.body.removeChild(iframe);
+    });
+
+    var newWin;
+    assert_true(document.fullscreenEnabled, "Top level document has fullscreen enabled flag set");
+    eventWatcher.wait_for("load").then(t.step_func(function() {
+      assert_false(iframe.contentDocument.fullscreenEnabled, "Document inside iframe without allowfullscreen attribute should not have fullscreen enabled flag set");
+      newWin = iframe.contentWindow.open("support/blank.htm");
+      t.add_cleanup(function() {
+        newWin.close();
+      });
+      var newWinEventWatcher = new EventWatcher(t, newWin, "load");
+      return newWinEventWatcher.wait_for("load");
+    })).then(t.step_func_done(function() {
+      assert_true(newWin.document.fullscreenEnabled, "Document in the new window is a top level document, thus should has fullscreen enabled flag set");
+    }));
+  }, "iframe-allowfullscreen-dialog");
+</script>