Bug 1262053 - part1 : unblock window's media when the page was first visited. draft
authorDan Glastonbury <dglastonbury@mozilla.com>
Tue, 16 Aug 2016 14:42:42 +0800
changeset 401064 9fe28ab1998d08a857a22fdacae714bc033887c3
parent 400825 054d4856cea6150a6638e5daf7913713281af97d
child 401065 10feed05b99de7390faedeed999cdce82a5c7451
push id26351
push useralwu@mozilla.com
push dateTue, 16 Aug 2016 06:57:30 +0000
bugs1262053
milestone51.0a1
Bug 1262053 - part1 : unblock window's media when the page was first visited. MozReview-Commit-ID: sXhv0QJEYc
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsGlobalWindow.cpp
dom/base/nsIDocument.h
modules/libpref/init/all.js
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1465,16 +1465,18 @@ nsDocument::nsDocument(const char* aCont
   // void state used to differentiate an empty source from an unselected source
   mPreloadPictureFoundSource.SetIsVoid(true);
 
   if (!sProcessingStack) {
     sProcessingStack.emplace();
     // Add the base queue sentinel to the processing stack.
     sProcessingStack->AppendElement((CustomElementData*) nullptr);
   }
+
+  mEverInForeground = false;
 }
 
 void
 nsDocument::ClearAllBoxObjects()
 {
   if (mBoxObjectTable) {
     for (auto iter = mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
       nsPIBoxObject* boxObject = iter.UserData();
@@ -12562,16 +12564,20 @@ nsDocument::UpdateVisibilityState()
                                          /* cancelable = */ false);
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("mozvisibilitychange"),
                                          /* bubbles = */ true,
                                          /* cancelable = */ false);
 
     EnumerateActivityObservers(NotifyActivityChanged, nullptr);
   }
+
+  if (mVisibilityState == dom::VisibilityState::Visible) {
+    MaybeActiveMediaComponents();
+  }
 }
 
 VisibilityState
 nsDocument::GetVisibilityState() const
 {
   // We have to check a few pieces of information here:
   // 1)  Are we in bfcache (!IsVisible())?  If so, nothing else matters.
   // 2)  Do we have an outer window?  If not, we're hidden.  Note that we don't
@@ -12597,16 +12603,33 @@ nsDocument::GetVisibilityState() const
 /* virtual */ void
 nsDocument::PostVisibilityUpdateEvent()
 {
   nsCOMPtr<nsIRunnable> event =
     NewRunnableMethod(this, &nsDocument::UpdateVisibilityState);
   NS_DispatchToMainThread(event);
 }
 
+void
+nsDocument::MaybeActiveMediaComponents()
+{
+  if (mEverInForeground) {
+    return;
+  }
+
+  if (!mWindow) {
+    return;
+  }
+
+  mEverInForeground = true;
+  if (GetWindow()->GetMediaSuspend() == nsISuspendedTypes::SUSPENDED_BLOCK) {
+    GetWindow()->SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
+  }
+}
+
 NS_IMETHODIMP
 nsDocument::GetMozHidden(bool* aHidden)
 {
   *aHidden = MozHidden();
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1204,16 +1204,20 @@ public:
   mozilla::dom::Promise* GetOrientationPendingPromise() const override;
 
   // This method may fire a DOM event; if it does so it will happen
   // synchronously.
   void UpdateVisibilityState();
   // Posts an event to call UpdateVisibilityState
   virtual void PostVisibilityUpdateEvent() override;
 
+  // Since we wouldn't automatically play media from non-visited page, we need
+  // to notify window when the page was first visited.
+  void MaybeActiveMediaComponents();
+
   virtual void DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const override;
   // DocAddSizeOfIncludingThis is inherited from nsIDocument.
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   virtual void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
                                         Element* aCustomElement,
                                         mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -613,17 +613,18 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMW
   mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
   mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
   mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
   mMayHaveMouseEnterLeaveEventListener(false),
   mMayHavePointerEnterLeaveEventListener(false),
   mInnerObjectsFreed(false),
   mIsModalContentWindow(false),
   mIsActive(false), mIsBackground(false),
-  mMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED),
+  mMediaSuspend(Preferences::GetBool("media.block-autoplay-until-in-foreground", true) ?
+    nsISuspendedTypes::SUSPENDED_BLOCK : nsISuspendedTypes::NONE_SUSPENDED),
   mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false),
   mDesktopModeViewport(false), mInnerWindow(nullptr),
   mOuterWindow(aOuterWindow),
   // Make sure no actual window ends up with mWindowID == 0
   mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
   mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false)
  {}
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3064,16 +3064,19 @@ protected:
   bool mFontFaceSetDirty : 1;
 
   // Has GetUserFontSet() been called?
   bool mGetUserFontSetCalled : 1;
 
   // Do we currently have an event posted to call FlushUserFontSet?
   bool mPostedFlushUserFontSet : 1;
 
+  // True is document has ever been in a foreground window.
+  bool mEverInForeground : 1;
+
   enum Type {
     eUnknown, // should never be used
     eHTML,
     eXHTML,
     eGenericXML,
     eSVG,
     eXUL
   };
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5498,16 +5498,17 @@ pref("media.seekToNextFrame.enabled", tr
 pref("osfile.reset_worker_delay", 30000);
 #endif
 
 #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
 pref("dom.webkitBlink.dirPicker.enabled", true);
 pref("dom.webkitBlink.filesystem.enabled", true);
 #endif
 
+pref("media.block-autoplay-until-in-foreground", true);
 #ifdef MOZ_STYLO
 // Is the Servo-backed style system enabled?
 pref("layout.css.servo.enabled", true);
 #endif
 
 #ifdef NIGHTLY_BUILD
 pref("dom.html_fragment_serialisation.appendLF", true);
 #else