Bug 533840 - Don't start playback when removed from a document and autoplaying. r=padenot,cpearce
authorBastien Scanu <bastien42@gmail.com>
Fri, 07 Jun 2013 13:46:45 +0200
changeset 136496 a4f84868850fbc05e526bc2a61c2974f033d0186
parent 136495 8710fcb40a3219a9b9d5646a110b3e50413bcbab
child 136497 b1dba904d5c8a48cd1c8fa31fb217e992a844726
child 137907 cc7af847469ce89ebdb343e2a2f68b4591d8f8d5
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerspadenot, cpearce
bugs533840
milestone25.0a1
Bug 533840 - Don't start playback when removed from a document and autoplaying. r=padenot,cpearce
content/html/content/public/HTMLMediaElement.h
content/html/content/src/HTMLMediaElement.cpp
content/media/test/Makefile.in
content/media/test/test_paused_after_removed.html
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -1114,16 +1114,19 @@ protected:
   bool mDownloadSuspendedByCache;
 
   // Audio Channel Type.
   AudioChannelType mAudioChannelType;
 
   // Is this media element playing?
   bool mPlayingThroughTheAudioChannel;
 
+  // Has this element been in a document?
+  bool mWasInDocument;
+
   // An agent used to join audio channel service.
   nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
 
   // List of our attached text track objects.
   nsRefPtr<TextTrackList> mTextTracks;
 };
 
 } // namespace dom
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1902,17 +1902,18 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mHasSelfReference(false),
     mShuttingDown(false),
     mSuspendedForPreloadNone(false),
     mMediaSecurityVerified(false),
     mCORSMode(CORS_NONE),
     mHasAudio(false),
     mDownloadSuspendedByCache(false),
     mAudioChannelType(AUDIO_CHANNEL_NORMAL),
-    mPlayingThroughTheAudioChannel(false)
+    mPlayingThroughTheAudioChannel(false),
+    mWasInDocument(false)
 {
 #ifdef PR_LOGGING
   if (!gMediaElementLog) {
     gMediaElementLog = PR_NewLogModule("nsMediaElement");
   }
   if (!gMediaElementEventsLog) {
     gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
   }
@@ -2323,32 +2324,35 @@ nsresult HTMLMediaElement::BindToTree(ns
   if (aDocument) {
     mAutoplayEnabled =
       IsAutoplayEnabled() && (!aDocument || !aDocument->IsStaticDocument()) &&
       !IsEditable();
     // The preload action depends on the value of the autoplay attribute.
     // It's value may have changed, so update it.
     UpdatePreloadAction();
 
+    mWasInDocument = true;
+
     if (aDocument->HasAudioAvailableListeners()) {
       // The document already has listeners for the "MozAudioAvailable"
       // event, so the decoder must be notified so it initiates
       // "MozAudioAvailable" event dispatch.
       NotifyAudioAvailableListener();
     }
   }
 
   return rv;
 }
 
 void HTMLMediaElement::UnbindFromTree(bool aDeep,
                                       bool aNullParent)
 {
-  if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY)
+  if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
     Pause();
+  }
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 }
 
 /* static */
 CanPlayStatus
 HTMLMediaElement::GetCanPlay(const nsAString& aType)
 {
   nsContentTypeParser parser(aType);
@@ -3037,17 +3041,20 @@ void HTMLMediaElement::ChangeReadyState(
   }
 }
 
 bool HTMLMediaElement::CanActivateAutoplay()
 {
   // For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
   // this element itself might be blocking the stream from making progress by
   // being paused.
+  // If we were in a document, but we have been removed, we should not start the
+  // playback.
   return !mPausedForInactiveDocumentOrChannel &&
+         mWasInDocument && IsInDoc() &&
          mAutoplaying &&
          mPaused &&
          (mDownloadSuspendedByCache ||
           (mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
           (mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
          HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
          mAutoplayEnabled &&
          !IsEditable();
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -130,16 +130,17 @@ MOCHITEST_FILES = \
 		test_seekLies.html \
 		test_media_sniffer.html \
 		contentType.sjs \
 		test_streams_srcObject.html \
 		test_reset_src.html \
 		test_streams_autoplay.html \
 		test_streams_gc.html \
 		test_streams_tracks.html \
+		test_paused_after_removed.html \
 		$(filter disabled-for-intermittent-failures--bug-608634, test_error_in_video_document.html) \
 		test_texttrack.html \
 		test_timeupdate_small_files.html \
 		test_unseekable.html \
 		test_webvtt_disabled.html \
 		$(NULL)
 
 # Disabled on Windows for frequent intermittent failures
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_paused_after_removed.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=533840
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 533840</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=533840">Mozilla Bug 533840</a>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+  /* Test for Bug 533840 */
+
+var manager = new MediaTestManager;
+
+function onloadstart(event) {
+  var video = event.target;
+  video.parentNode.removeChild(video);
+  ok(video.paused, "Media should be paused.");
+  // wait a bit to check we won't receive the a "play" event.
+  setTimeout(function() {
+    video.removeEventListener("loadstart", onloadstart);
+    video.src = "";
+    manager.finished(video.token);
+  }, 3000);
+}
+
+function onplay(event) {
+  ok(false, "Should not receive a play event.");
+}
+
+function startTest(test, token) {
+  var video = document.createElement('video');
+  video.token = token;
+  manager.started(token);
+  video.src = test.name;
+  video.preload = "auto";
+  video.autoplay = true;
+  video.addEventListener("loadstart", onloadstart);
+  video.addEventListener("play", onplay);
+  SimpleTest.waitForExplicitFinish();
+  document.body.appendChild(video);
+}
+
+manager.runTests(gProgressTests, startTest);
+</script>
+</pre>
+</body>
+</html>
+