Bug 1347758 - part1 : window should know whehter there is any alive media component and decide to resume the tab or not. draft
authorAlastor Wu <alwu@mozilla.com>
Fri, 24 Mar 2017 14:43:26 +0800
changeset 504484 c8a4cd52480f7b7b895284cdfa0f2146560eedd8
parent 504149 01d1dedf400d4be413b1a0d48090dca7acf29637
child 504485 763e82a4003a646e35d0f6592cdadba1ad878283
push id50804
push useralwu@mozilla.com
push dateFri, 24 Mar 2017 09:03:46 +0000
bugs1347758
milestone55.0a1
Bug 1347758 - part1 : window should know whehter there is any alive media component and decide to resume the tab or not. We should let window decide whether resume the media component, not document. Because we might have media component which is not in DOM tree, but we still want to play it. Window should be resumed when all following conditions are true, (1) the tab is in the foreground (2) there is any alive media component (MediaElement/WebAudio/PlugIn...) (3) the window is blocked (nsISuspendedTypes::SUSPENDED_BLOCK) MozReview-Commit-ID: JXw5MA4FCxF
dom/base/nsDocument.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsIDocument.h
dom/base/nsPIDOMWindow.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1322,17 +1322,16 @@ nsIDocument::nsIDocument()
     mHasHadDefaultView(false),
     mStyleSheetChangeEventsEnabled(false),
     mIsSrcdocDocument(false),
     mDidDocumentOpen(false),
     mHasDisplayDocument(false),
     mFontFaceSetDirty(true),
     mGetUserFontSetCalled(false),
     mPostedFlushUserFontSet(false),
-    mEverInForeground(false),
     mCompatMode(eCompatibility_FullStandards),
     mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
     mStyleBackendType(StyleBackendType::None),
 #ifdef MOZILLA_INTERNAL_API
     mVisibilityState(dom::VisibilityState::Hidden),
 #else
     mDummy(0),
 #endif
@@ -1421,18 +1420,16 @@ nsDocument::nsDocument(const char* aCont
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
 
   // Start out mLastStyleSheetSet as null, per spec
   SetDOMStringToNull(mLastStyleSheetSet);
 
   // void state used to differentiate an empty source from an unselected source
   mPreloadPictureFoundSource.SetIsVoid(true);
-
-  mEverInForeground = false;
 }
 
 void
 nsDocument::ClearAllBoxObjects()
 {
   if (mBoxObjectTable) {
     for (auto iter = mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
       nsPIBoxObject* boxObject = iter.UserData();
@@ -12207,29 +12204,20 @@ nsDocument::PostVisibilityUpdateEvent()
   nsCOMPtr<nsIRunnable> event =
     NewRunnableMethod(this, &nsDocument::UpdateVisibilityState);
   Dispatch("nsDocument::UpdateVisibilityState", TaskCategory::Other, event.forget());
 }
 
 void
 nsDocument::MaybeActiveMediaComponents()
 {
-  if (mEverInForeground) {
-    return;
-  }
-
   if (!mWindow) {
     return;
   }
 
-  if (mMediaContent.IsEmpty()) {
-    return;
-  }
-
-  mEverInForeground = true;
   GetWindow()->MaybeActiveMediaComponents();
 }
 
 NS_IMETHODIMP
 nsDocument::GetHidden(bool* aHidden)
 {
   *aHidden = Hidden();
   return NS_OK;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -984,17 +984,18 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMW
   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), mIsRootOuterWindow(false), mInnerWindow(nullptr),
   mOuterWindow(aOuterWindow),
   // Make sure no actual window ends up with mWindowID == 0
   mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
   mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false),
-  mLargeAllocStatus(LargeAllocStatus::NONE)
+  mLargeAllocStatus(LargeAllocStatus::NONE),
+  mShouldResumeOnFirstActiveMediaComponent(false)
 {
   if (aOuterWindow) {
     mTimeoutManager =
       MakeUnique<mozilla::dom::TimeoutManager>(*nsGlobalWindow::Cast(AsInner()));
   }
 }
 
 template<class T>
@@ -4343,49 +4344,53 @@ bool
 nsPIDOMWindowInner::IsRunningTimeout()
 {
   return TimeoutManager().IsRunningTimeout();
 }
 
 void
 nsPIDOMWindowOuter::NotifyCreatedNewMediaComponent()
 {
-  if (mMediaSuspend != nsISuspendedTypes::SUSPENDED_BLOCK) {
-    return;
-  }
+  // We would only active media component when there is any alive one.
+  mShouldResumeOnFirstActiveMediaComponent = true;
 
   // If the document is already on the foreground but the suspend state is still
   // suspend-block, that means the media component was created after calling
   // MaybeActiveMediaComponents, so the window's suspend state doesn't be
   // changed yet. Therefore, we need to call it again, because the state is only
   // changed after there exists alive media within the window.
   MaybeActiveMediaComponents();
 }
 
 void
 nsPIDOMWindowOuter::MaybeActiveMediaComponents()
 {
   if (IsInnerWindow()) {
     return mOuterWindow->MaybeActiveMediaComponents();
   }
 
+  // Resume the media when the tab was blocked and the tab already has
+  // alive media components.
+  if (!mShouldResumeOnFirstActiveMediaComponent ||
+      mMediaSuspend != nsISuspendedTypes::SUSPENDED_BLOCK) {
+    return;
+  }
+
   nsCOMPtr<nsPIDOMWindowInner> inner = GetCurrentInnerWindow();
   if (!inner) {
     return;
   }
 
+  // If the document is not visible, don't need to resume it.
   nsCOMPtr<nsIDocument> doc = inner->GetExtantDoc();
-  if (!doc) {
-    return;
-  }
-
-  if (!doc->Hidden() &&
-      mMediaSuspend == nsISuspendedTypes::SUSPENDED_BLOCK) {
-    SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
-  }
+  if (!doc || doc->Hidden()) {
+    return;
+  }
+
+  SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
 }
 
 SuspendTypes
 nsPIDOMWindowOuter::GetMediaSuspend() const
 {
   if (IsInnerWindow()) {
     return mOuterWindow->GetMediaSuspend();
   }
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3181,19 +3181,16 @@ 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;
-
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState
   ReadyState mReadyState;
 
   // Whether this document has (or will have, once we have a pres shell) a
   // Gecko- or Servo-backed style system.
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -732,16 +732,20 @@ protected:
 
   uint32_t mMarkedCCGeneration;
 
   // Let the service workers plumbing know that some feature are enabled while
   // testing.
   bool mServiceWorkersTestingEnabled;
 
   mozilla::dom::LargeAllocStatus mLargeAllocStatus; // Outer window only
+
+  // When there is any created alive media component, we can consider to resume
+  // the media content in the window.
+  bool mShouldResumeOnFirstActiveMediaComponent;
 };
 
 #define NS_PIDOMWINDOWINNER_IID \
 { 0x775dabc9, 0x8f43, 0x4277, \
   { 0x9a, 0xdb, 0xf1, 0x99, 0x0d, 0x77, 0xcf, 0xfb } }
 
 #define NS_PIDOMWINDOWOUTER_IID \
   { 0x769693d4, 0xb009, 0x4fe2, \