b=478982 Gecko users may need to prevent autoplay for video/audio content in messages r=roc,dolske sr=roc
authorNochum Sossonko <highmind63@gmail.com>
Fri, 20 Feb 2009 17:05:07 +1300
changeset 23466 6d7caf9aa2036ca0df208ce22c98787a31ba0e4b
parent 23465 ece99f1ebc456b75dff72bca5560b35b72d6ecf0
child 23467 9bc41efd929853cca54d785cc0e47880e997f1a5
push id778
push userrocallahan@mozilla.com
push dateThu, 26 Feb 2009 09:56:42 +0000
reviewersroc, dolske, roc
bugs478982
milestone1.9.1b3pre
b=478982 Gecko users may need to prevent autoplay for video/audio content in messages r=roc,dolske sr=roc
content/html/content/public/nsHTMLMediaElement.h
content/html/content/src/nsHTMLMediaElement.cpp
dom/public/idl/html/nsIDOMHTMLMediaElement.idl
modules/libpref/src/init/all.js
toolkit/content/widgets/videocontrols.xml
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -332,16 +332,20 @@ protected:
   // latter case.
   // The 'autoplay' HTML attribute indicates that the video should
   // start playing when loaded. The 'autoplay' attribute of the object
   // is a mirror of the HTML attribute. These are different from this
   // 'mAutoplaying' flag, which indicates whether the current playback
   // is a result of the autoplay attribute.
   PRPackedBool mAutoplaying;
 
+  // Indicates whether |autoplay| will actually autoplay based on the pref 
+  // media.autoplay.enabled
+  PRPackedBool mAutoplayEnabled;
+
   // Playback of the video is paused either due to calling the
   // 'Pause' method, or playback not yet having started.
   PRPackedBool mPaused;
 
   // True if the sound is muted
   PRPackedBool mMuted;
 
   // Flag to indicate if the child elements (eg. <source/>) have been
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -247,16 +247,24 @@ nsMediaLoad::GetNextCandidate()
 
 NS_IMPL_ISUPPORTS0(nsMediaLoad)
 
 // nsIDOMHTMLMediaElement
 NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
 NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
 NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Autoplay, autoplay)
 
+/* readonly attribute nsIDOMHTMLMediaElement mozAutoplayEnabled; */
+NS_IMETHODIMP nsHTMLMediaElement::GetMozAutoplayEnabled(PRBool *aAutoplayEnabled)
+{
+  *aAutoplayEnabled = mAutoplayEnabled;
+
+  return NS_OK;
+}
+
 /* readonly attribute nsIDOMHTMLMediaError error; */
 NS_IMETHODIMP nsHTMLMediaElement::GetError(nsIDOMHTMLMediaError * *aError)
 {
   NS_IF_ADDREF(*aError = mError);
 
   return NS_OK;
 }
 
@@ -614,16 +622,17 @@ nsHTMLMediaElement::nsHTMLMediaElement(n
   : nsGenericHTMLElement(aNodeInfo),
     mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
     mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
     mMutedVolume(0.0),
     mMediaSize(-1,-1),
     mBegun(PR_FALSE),
     mLoadedFirstFrame(PR_FALSE),
     mAutoplaying(PR_TRUE),
+    mAutoplayEnabled(PR_TRUE),
     mPaused(PR_TRUE),
     mMuted(PR_FALSE),
     mIsDoneAddingChildren(!aFromParser),
     mPlayingBeforeSeek(PR_FALSE),
     mWaitingFired(PR_FALSE),
     mIsBindingToTree(PR_FALSE)
 {
 }
@@ -715,21 +724,27 @@ nsresult nsHTMLMediaElement::SetAttr(PRI
         mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
       Load();
     }
   }
 
   return rv;
 }
 
+static PRBool IsAutoplayEnabled()
+{
+  return nsContentUtils::GetBoolPref("media.autoplay.enabled");
+}
+
 nsresult nsHTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                         nsIContent* aBindingParent,
                                         PRBool aCompileEventHandlers)
 {
   mIsBindingToTree = PR_TRUE;
+  mAutoplayEnabled = IsAutoplayEnabled();
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, 
                                                  aParent, 
                                                  aBindingParent, 
                                                  aCompileEventHandlers);
   if (NS_SUCCEEDED(rv) &&
       mIsDoneAddingChildren &&
       mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
     QueueLoadTask();
@@ -1288,17 +1303,18 @@ void nsHTMLMediaElement::ChangeReadyStat
       if (oldState != mReadyState) {
         LOG(PR_LOG_DEBUG, ("Ready state changed to HAVE_ENOUGH_DATA"));
       }
       if (oldState <= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
         DispatchAsyncSimpleEvent(NS_LITERAL_STRING("canplay"));
       }
       if (mAutoplaying &&
           mPaused &&
-          HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) {
+          HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
+          mAutoplayEnabled) {
         mPaused = PR_FALSE;
         if (mDecoder) {
           mDecoder->Play();
         }
         DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play"));
       }
       LOG(PR_LOG_DEBUG, ("Ready state changed to HAVE_ENOUGH_DATA"));
       if (oldState <= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
--- a/dom/public/idl/html/nsIDOMHTMLMediaElement.idl
+++ b/dom/public/idl/html/nsIDOMHTMLMediaElement.idl
@@ -51,17 +51,17 @@
 
 // undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
 %{C++
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 %}
 
-[scriptable, uuid(c19f04dc-f09a-4b1f-b354-af65a12aa8bc)]
+[scriptable, uuid(debed306-1a49-4af8-b10a-8452978a2db1)]
 interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
 {
   // error state
   readonly attribute nsIDOMHTMLMediaError error;
 
   // network state
            attribute DOMString src;
   readonly attribute DOMString currentSrc;
@@ -82,16 +82,17 @@ interface nsIDOMHTMLMediaElement : nsIDO
   readonly attribute unsigned short readyState;
   readonly attribute boolean seeking;
 
   // playback state
            attribute float currentTime;
   readonly attribute float duration;
   readonly attribute boolean paused;
   readonly attribute boolean ended;
+  readonly attribute boolean mozAutoplayEnabled;
            attribute boolean autoplay;
   void play();
   void pause();
 
   // controls
            attribute boolean controls;
            attribute float volume;
            attribute boolean muted;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -137,16 +137,19 @@ pref("media.enforce_same_site_origin", f
 
 #ifdef MOZ_OGG
 pref("media.ogg.enabled", true);
 #endif
 #ifdef MOZ_WAVE
 pref("media.wave.enabled", true);
 #endif
 
+// Whether to autostart a media element with an |autoplay| attribute
+pref("media.autoplay.enabled", true);
+
 // 0 = Off, 1 = Full, 2 = Tagged Images Only. 
 // See eCMSMode in gfx/thebes/public/gfxPlatform.h
 pref("gfx.color_management.mode", 2);
 pref("gfx.color_management.display_profile", "");
 pref("gfx.color_management.rendering_intent", 0);
 
 pref("gfx.downloadable_fonts.enabled", true);
 
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -267,17 +267,18 @@
                         this.isControlsOrDescendant(event.relatedTarget))
                         return;
 
                     var isMouseOver = (event.type == "mouseover");
 
                     // Suppress fading out the controls until the video has rendered
                     // its first frame. But since autoplay videos start off with no
                     // controls, let them fade-out so the controls don't get stuck on.
-                    if (!this.firstFrameShown && !isMouseOver && !this.video.autoplay)
+                    if (!this.firstFrameShown && !isMouseOver &&
+                        !(this.video.autoplay && this.video.mozAutoplayEnabled))
                         return;
 
                     // If we're already fading towards the desired state (or are
                     // already there), then we don't need to do anything more.
                     var directionChange = (this.fadingIn != isMouseOver);
                     if (!directionChange)
                         return;
 
@@ -398,17 +399,17 @@
             // the controls are broken and we don't want them shown. But if script is
             // enabled, the code here will run and can explicitly unhide the controls.
             //
             // For videos with |autoplay| set, we'll leave the controls initially hidden,
             // so that they don't get in the way of the playing video. Otherwise we'll
             // go ahead and reveal the controls now, so they're an obvious user cue.
             //
             // (Note: the |controls| attribute is already handled via layout/style/html.css)
-            if (!video.autoplay || !this.Utils.dynamicControls) {
+            if (!(video.autoplay && video.mozAutoplayEnabled) || !this.Utils.dynamicControls) {
                 this.Utils.controlBar.style.visibility = "visible";
                 this.Utils.controlBar.style.opacity = 1.0;
                 this.Utils.controlsVisible = true;
                 this.Utils.fadingIn = true;
             }
 
             // Use Utils.handleEvent() callback for all media events.
             video.addEventListener("play",         this.Utils, false);