Bug 1282038 - Allow allowfullscreen for rewritten YouTube Flash embeds. r=qdot,jst, a=lizzard
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Fri, 24 Jun 2016 19:12:53 +0900
changeset 341868 c0a5d404e9872311da2d213ee9ae49b9e4d74971
parent 341867 7c544c41ae8f5cae773b84bab1aca58a11c25469
child 341869 7051fecb8b5138f526492e87131ab7e0f40db0f1
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot, jst, lizzard
bugs1282038
milestone49.0a2
Bug 1282038 - Allow allowfullscreen for rewritten YouTube Flash embeds. r=qdot,jst, a=lizzard MozReview-Commit-ID: I8y0gMA5BxE
docshell/base/nsDocShell.cpp
dom/base/nsObjectLoadingContent.cpp
dom/base/nsObjectLoadingContent.h
dom/base/test/file_youtube_flash_embed.html
dom/base/test/mochitest.ini
dom/base/test/test_youtube_flash_embed.html
testing/mochitest/embed/Xm5i5kbIXzc
testing/mochitest/embed/Xm5i5kbIXzc^headers^
testing/mochitest/moz.build
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -80,16 +80,17 @@
 #include "nsIScrollObserver.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIChannel.h"
 #include "IHistory.h"
 #include "nsViewSourceHandler.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsICookieService.h"
 #include "nsIConsoleReportCollector.h"
+#include "nsObjectLoadingContent.h"
 
 // we want to explore making the document own the load group
 // so we can associate the document URI with the load group.
 // until this point, we have an evil hack:
 #include "nsIHttpChannelInternal.h"
 #include "nsPILoadGroupInternal.h"
 
 // Local Includes
@@ -2514,25 +2515,45 @@ nsDocShell::GetFullscreenAllowed(bool* a
   nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
   if (!win) {
     return NS_OK;
   }
   nsCOMPtr<Element> frameElement = win->GetFrameElementInternal();
   if (frameElement && !frameElement->IsXULElement()) {
     // We do not allow document inside any containing element other
     // than iframe to enter fullscreen.
-    if (!frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
-      return NS_OK;
-    }
-    // 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)) {
+    if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
+      // 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;
+      }
+    } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
+      // Respect allowfullscreen only if this is a rewritten YouTube embed.
+      nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
+        do_QueryInterface(frameElement);
+      if (!objectLoadingContent) {
+        return NS_OK;
+      }
+      nsObjectLoadingContent* olc =
+        static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
+      if (!olc->IsRewrittenYoutubeEmbed()) {
+        return NS_OK;
+      }
+      // We don't have to check prefixed attributes because Flash does not
+      // support them.
+      if (!frameElement->HasAttr(kNameSpaceID_None,
+                                 nsGkAtoms::allowfullscreen)) {
+        return NS_OK;
+      }
+    } else {
+      // neither iframe nor embed
       return NS_OK;
     }
     nsIDocument* doc = frameElement->GetUncomposedDoc();
     if (!doc || !doc->FullscreenEnabledInternal()) {
       return NS_OK;
     }
   }
 
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -716,17 +716,18 @@ nsObjectLoadingContent::nsObjectLoadingC
   , mRunID(0)
   , mHasRunID(false)
   , mChannelLoaded(false)
   , mInstantiating(false)
   , mNetworkCreated(true)
   , mActivated(false)
   , mIsStopping(false)
   , mIsLoading(false)
-  , mScriptRequested(false) {}
+  , mScriptRequested(false)
+  , mRewrittenYoutubeEmbed(false) {}
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   // Should have been unbound from the tree at this point, and
   // CheckPluginStopEvent keeps us alive
   if (mFrameLoader) {
     NS_NOTREACHED("Should not be tearing down frame loaders at this point");
     mFrameLoader->Destroy();
@@ -1838,29 +1839,31 @@ nsObjectLoadingContent::UpdateObjectPara
     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, uriStr);
   } else if (thisContent->NodeInfo()->Equals(nsGkAtoms::embed)) {
     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, uriStr);
   } else {
     // Applet tags should always have a java MIME type at this point
     NS_NOTREACHED("Unrecognized plugin-loading tag");
   }
 
+  mRewrittenYoutubeEmbed = false;
   // Note that the baseURI changing could affect the newURI, even if uriStr did
   // not change.
   if (!uriStr.IsEmpty()) {
     rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(newURI),
                                                    uriStr,
                                                    thisContent->OwnerDoc(),
                                                    newBaseURI);
     nsCOMPtr<nsIURI> rewrittenURI;
     MaybeRewriteYoutubeEmbed(newURI,
                              newBaseURI,
                              getter_AddRefs(rewrittenURI));
     if (rewrittenURI) {
       newURI = rewrittenURI;
+      mRewrittenYoutubeEmbed = true;
       newMime = NS_LITERAL_CSTRING("text/html");
     }
 
     if (NS_SUCCEEDED(rv)) {
       NS_TryToSetImmutable(newURI);
     } else {
       stateInvalid = true;
     }
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -245,16 +245,21 @@ class nsObjectLoadingContent : public ns
       if (NS_FAILED(rv)) {
         aRv.Throw(rv);
         return 0;
       }
 
       return runID;
     }
 
+    bool IsRewrittenYoutubeEmbed() const
+    {
+      return mRewrittenYoutubeEmbed;
+    }
+
   protected:
     /**
      * Begins loading the object when called
      *
      * Attributes of |this| QI'd to nsIContent will be inspected, depending on
      * the node type. This function currently assumes it is a <applet>,
      * <object>, or <embed> tag.
      *
@@ -620,17 +625,17 @@ class nsObjectLoadingContent : public ns
 
 
     // Type of the currently-loaded content.
     ObjectType                  mType           : 8;
     // The type of fallback content we're showing (see ObjectState())
     FallbackType                mFallbackType : 8;
 
     uint32_t                    mRunID;
-    bool                        mHasRunID;
+    bool                        mHasRunID : 1;
 
     // If true, we have opened a channel as the listener and it has reached
     // OnStartRequest. Does not get set for channels that are passed directly to
     // the plugin listener.
     bool                        mChannelLoaded    : 1;
 
     // Whether we are about to call instantiate on our frame. If we aren't,
     // SetFrame needs to asynchronously call Instantiate.
@@ -650,16 +655,22 @@ class nsObjectLoadingContent : public ns
 
     // Protects LoadObject from re-entry
     bool                        mIsLoading : 1;
 
     // For plugin stand-in types (click-to-play) tracks
     // whether content js has tried to access the plugin script object.
     bool                        mScriptRequested : 1;
 
+    // True if object represents an object/embed tag pointing to a flash embed
+    // for a youtube video. When possible (see IsRewritableYoutubeEmbed function
+    // comments for details), we change these to try to load HTML5 versions of
+    // videos.
+    bool                        mRewrittenYoutubeEmbed : 1;
+
     nsWeakFrame                 mPrintFrame;
 
     RefPtr<nsPluginInstanceOwner> mInstanceOwner;
     nsTArray<mozilla::dom::MozPluginParameter> mCachedAttributes;
     nsTArray<mozilla::dom::MozPluginParameter> mCachedParameters;
 };
 
 #endif
copy from dom/base/test/test_youtube_flash_embed.html
copy to dom/base/test/file_youtube_flash_embed.html
--- a/dom/base/test/test_youtube_flash_embed.html
+++ b/dom/base/test/file_youtube_flash_embed.html
@@ -1,44 +1,65 @@
 <!DOCTYPE HTML>
 <html>
   <!--
        https://bugzilla.mozilla.org/show_bug.cgi?id=1240471
      -->
   <head>
     <meta charset="utf-8">
     <title>Test for Bug 1240471</title>
-    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="application/javascript">
-     SimpleTest.waitForExplicitFinish();
+     let SimpleTest = {
+       finish: function() {
+         parent.postMessage(JSON.stringify({fn: "finish"}), "*");
+       }
+     };
+     ["ok", "is", "info"].forEach(fn => {
+       self[fn] = function (...args) {
+         parent.postMessage(JSON.stringify({fn: fn, args: args}), "*");
+       }
+     });
      "use strict";
-     function onLoad () {
+     function onLoad() {
        let youtube_changed_url_query = "https://mochitest.youtube.com/embed/Xm5i5kbIXzc?start=10&end=20";
 
-       function testEmbed(embed, expected_url) {
-         ok (embed, "Embed node exists");
+       function testEmbed(embed, expected_url, expected_fullscreen) {
+         ok (!!embed, "Embed node exists");
+         // getSVGDocument will return HTMLDocument if the content is HTML
+         let doc = embed.getSVGDocument();
+         // doc must be unprivileged because privileged doc will always be
+         // allowed to use fullscreen.
+         is (doc.fullscreenEnabled, expected_fullscreen,
+             "fullscreen should be " + (expected_fullscreen ? "enabled" : "disabled"));
          embed = SpecialPowers.wrap(embed);
          is (embed.srcURI.spec, expected_url, "Should have src uri of " + expected_url);
        }
        info("Running youtube rewrite query test");
-       testEmbed(document.getElementById("testembed-correct"), youtube_changed_url_query);
-       testEmbed(document.getElementById("testembed-wrong"), youtube_changed_url_query);
-       testEmbed(document.getElementById("testembed-whywouldyouevendothat"), youtube_changed_url_query);
+       testEmbed(document.getElementById("testembed-correct"), youtube_changed_url_query, false);
+       testEmbed(document.getElementById("testembed-correct-fs"), youtube_changed_url_query, true);
+       testEmbed(document.getElementById("testembed-wrong"), youtube_changed_url_query, false);
+       testEmbed(document.getElementById("testembed-whywouldyouevendothat"), youtube_changed_url_query, true);
        SimpleTest.finish();
      }
     </script>
   </head>
   <body onload="onLoad()">
     <embed id="testembed-correct"
            src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
            type="application/x-shockwave-flash"
            allowscriptaccess="always"></embed>
+    <embed id="testembed-correct-fs"
+           src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
+           type="application/x-shockwave-flash"
+           allowfullscreen
+           allowscriptaccess="always"></embed>
     <embed id="testembed-wrong"
            src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10&end=20"
            type="application/x-shockwave-flash"
            allowscriptaccess="always"></embed>
     <embed id="testembed-whywouldyouevendothat"
            src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10?end=20"
            type="application/x-shockwave-flash"
+           allowfullscreen
            allowscriptaccess="always"></embed>
   </body>
 </html>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -217,16 +217,17 @@ support-files =
   file_xhtmlserializer_1_sibling_body.xhtml
   file_xhtmlserializer_1_sibling_body_only_body.xhtml
   file_xhtmlserializer_1_wrap.xhtml
   file_xhtmlserializer_2.xhtml
   file_xhtmlserializer_2_basic.xhtml
   file_xhtmlserializer_2_enthtml.xhtml
   file_xhtmlserializer_2_entw3c.xhtml
   file_xhtmlserializer_2_latin1.xhtml
+  file_youtube_flash_embed.html
   fileapi_chromeScript.js
   fileutils.js
   forRemoval.resource
   forRemoval.resource^headers^
   formReset.html
   invalid_accesscontrol.resource
   invalid_accesscontrol.resource^headers^
   mutationobserver_dialog.html
--- a/dom/base/test/test_youtube_flash_embed.html
+++ b/dom/base/test/test_youtube_flash_embed.html
@@ -5,40 +5,28 @@
      -->
   <head>
     <meta charset="utf-8">
     <title>Test for Bug 1240471</title>
     <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="application/javascript">
      SimpleTest.waitForExplicitFinish();
-     "use strict";
-     function onLoad () {
-       let youtube_changed_url_query = "https://mochitest.youtube.com/embed/Xm5i5kbIXzc?start=10&end=20";
-
-       function testEmbed(embed, expected_url) {
-         ok (embed, "Embed node exists");
-         embed = SpecialPowers.wrap(embed);
-         is (embed.srcURI.spec, expected_url, "Should have src uri of " + expected_url);
+     let path = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/file_youtube_flash_embed.html';
+     onmessage = function(e) {
+       let msg = JSON.parse(e.data);
+       if (msg.fn == "finish") {
+         SimpleTest.finish();
+         return;
        }
-       info("Running youtube rewrite query test");
-       testEmbed(document.getElementById("testembed-correct"), youtube_changed_url_query);
-       testEmbed(document.getElementById("testembed-wrong"), youtube_changed_url_query);
-       testEmbed(document.getElementById("testembed-whywouldyouevendothat"), youtube_changed_url_query);
-       SimpleTest.finish();
+       self[msg.fn].apply(null, msg.args);
+     }
+     function onLoad() {
+       // The test file must be loaded into youtube.com domain
+       // because it needs unprivileged access to fullscreenEnabled.
+       ifr.src = "https://mochitest.youtube.com" + path;
      }
     </script>
   </head>
   <body onload="onLoad()">
-    <embed id="testembed-correct"
-           src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
-           type="application/x-shockwave-flash"
-           allowscriptaccess="always"></embed>
-    <embed id="testembed-wrong"
-           src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10&end=20"
-           type="application/x-shockwave-flash"
-           allowscriptaccess="always"></embed>
-    <embed id="testembed-whywouldyouevendothat"
-           src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10?end=20"
-           type="application/x-shockwave-flash"
-           allowscriptaccess="always"></embed>
+    <iframe id="ifr" allowfullscreen></iframe>
   </body>
 </html>
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/embed/Xm5i5kbIXzc^headers^
@@ -0,0 +1,2 @@
+HTTP 200 OK
+Content-Type: text/html
--- a/testing/mochitest/moz.build
+++ b/testing/mochitest/moz.build
@@ -66,16 +66,21 @@ TEST_HARNESS_FILES.testing.mochitest += 
     'runtests.py',
     'runtestsb2g.py',
     'runtestsremote.py',
     'server.js',
     'start_b2g.js',
     'start_desktop.js',
 ]
 
+TEST_HARNESS_FILES.testing.mochitest.embed += [
+    'embed/Xm5i5kbIXzc',
+    'embed/Xm5i5kbIXzc^headers^',
+]
+
 TEST_HARNESS_FILES.testing.mochitest.pywebsocket += [
     'pywebsocket/standalone.py',
 ]
 
 TEST_HARNESS_FILES.testing.mochitest.pywebsocket.mod_pywebsocket += [
     'pywebsocket/mod_pywebsocket/__init__.py',
     'pywebsocket/mod_pywebsocket/_stream_base.py',
     'pywebsocket/mod_pywebsocket/_stream_hixie75.py',