Bug 1338137 - part1 : ref media content when the media element bind to tree. draft
authorAlastor Wu <alwu@mozilla.com>
Sat, 04 Mar 2017 01:14:24 +0800
changeset 493238 5b9a36bddec939d7f77252ce53ce5b408e1d716a
parent 493227 77d5a39a4677ed8e32a7ed46561c962d807fa7b1
child 493239 b3cd4bcde37258263d7435934ef5eab010727ff5
push id47694
push useralwu@mozilla.com
push dateFri, 03 Mar 2017 17:17:14 +0000
bugs1338137, 1319771
milestone54.0a1
Bug 1338137 - part1 : ref media content when the media element bind to tree. In bug1319771, we found that the tab would become visible unexpectly in short period in some situations. We don't want to resume the tab in this kind of situation, so we check whether there is any alive media component in the tab using IsServiceStarted(). However, since we have lots different ways to create the service, this function is not accurate at all. Therefore, we can add media element directly to the document when it binds to tree so that we can really know whether there is any alive media component. MozReview-Commit-ID: FvZFg91IqgE
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
dom/html/HTMLMediaElement.cpp
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10270,16 +10270,32 @@ nsDocument::AddResponsiveContent(nsICont
 void
 nsDocument::RemoveResponsiveContent(nsIContent* aContent)
 {
   MOZ_ASSERT(aContent);
   mResponsiveContent.RemoveEntry(aContent);
 }
 
 void
+nsDocument::AddMediaContent(nsIContent* aContent)
+{
+  MOZ_ASSERT(aContent);
+  MOZ_ASSERT(aContent->IsHTMLElement(nsGkAtoms::video) ||
+             aContent->IsHTMLElement(nsGkAtoms::audio));
+  mMediaContent.PutEntry(aContent);
+}
+
+void
+nsDocument::RemoveMediaContent(nsIContent* aContent)
+{
+  MOZ_ASSERT(aContent);
+  mMediaContent.RemoveEntry(aContent);
+}
+
+void
 nsDocument::NotifyMediaFeatureValuesChanged()
 {
   for (auto iter = mResponsiveContent.ConstIter(); !iter.Done();
        iter.Next()) {
     nsCOMPtr<nsIContent> content = iter.Get()->GetKey();
     if (content->IsHTMLElement(nsGkAtoms::img)) {
       auto* imageElement = static_cast<HTMLImageElement*>(content.get());
       imageElement->MediaFeatureValuesChanged();
@@ -12070,16 +12086,20 @@ nsDocument::MaybeActiveMediaComponents()
   if (mEverInForeground) {
     return;
   }
 
   if (!mWindow) {
     return;
   }
 
+  if (mMediaContent.IsEmpty()) {
+    return;
+  }
+
   mEverInForeground = true;
   GetWindow()->MaybeActiveMediaComponents();
 }
 
 NS_IMETHODIMP
 nsDocument::GetHidden(bool* aHidden)
 {
   *aHidden = Hidden();
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1006,16 +1006,23 @@ public:
   virtual nsresult AddResponsiveContent(nsIContent* aContent) override;
   // Removes an element from mResponsiveContent when the element is
   // removed from the tree.
   virtual void RemoveResponsiveContent(nsIContent* aContent) override;
   // Notifies any responsive content added by AddResponsiveContent upon media
   // features values changing.
   virtual void NotifyMediaFeatureValuesChanged() override;
 
+  // Adds an element to mMediaContent when the element is added to the tree.
+  virtual void AddMediaContent(nsIContent* aContent) override;
+
+  // Removes an element from mMediaContent when the element is removed from
+  // the tree.
+  virtual void RemoveMediaContent(nsIContent* aContent) override;
+
   virtual nsresult GetStateObject(nsIVariant** aResult) override;
 
   virtual nsDOMNavigationTiming* GetNavigationTiming() const override;
   virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming) override;
 
   virtual Element* FindImageMap(const nsAString& aNormalizedMapName) override;
 
   virtual nsTArray<Element*> GetFullscreenStack() const override;
@@ -1553,16 +1560,19 @@ private:
   // state so we can provide useful assertions to consumers of ForgetLink and
   // AddStyleRelevantLink.
   bool mStyledLinksCleared;
 #endif
 
   // A set of responsive images keyed by address pointer.
   nsTHashtable< nsPtrHashKey<nsIContent> > mResponsiveContent;
 
+  // A set of media elements keyed by address pointer.
+  nsTHashtable<nsPtrHashKey<nsIContent>> mMediaContent;
+
   // Member to store out last-selected stylesheet set.
   nsString mLastStyleSheetSet;
 
   nsTArray<RefPtr<nsFrameLoader> > mInitializableFrameLoaders;
   nsTArray<nsCOMPtr<nsIRunnable> > mFrameLoaderFinalizers;
   RefPtr<nsRunnableMethod<nsDocument> > mFrameLoaderRunner;
 
   nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2428,16 +2428,19 @@ public:
   virtual nsresult AddPlugin(nsIObjectLoadingContent* aPlugin) = 0;
   virtual void RemovePlugin(nsIObjectLoadingContent* aPlugin) = 0;
   virtual void GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins) = 0;
 
   virtual nsresult AddResponsiveContent(nsIContent* aContent) = 0;
   virtual void RemoveResponsiveContent(nsIContent* aContent) = 0;
   virtual void NotifyMediaFeatureValuesChanged() = 0;
 
+  virtual void AddMediaContent(nsIContent* aContent) = 0;
+  virtual void RemoveMediaContent(nsIContent* aContent) = 0;
+
   virtual nsresult GetStateObject(nsIVariant** aResult) = 0;
 
   virtual nsDOMNavigationTiming* GetNavigationTiming() const = 0;
 
   virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming) = 0;
 
   virtual Element* FindImageMap(const nsAString& aNormalizedMapName) = 0;
 
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4274,16 +4274,17 @@ 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();
+    aDocument->AddMediaContent(this);
   }
 
   if (mDecoder) {
     // When the MediaElement is binding to tree, the dormant status is
     // aligned to document's hidden status.
     mDecoder->NotifyOwnerActivityChanged(!IsHidden());
   }
 
@@ -4509,16 +4510,19 @@ HTMLMediaElement::ReportTelemetry()
     }
   }
 }
 
 void HTMLMediaElement::UnbindFromTree(bool aDeep,
                                       bool aNullParent)
 {
   mUnboundFromTree = true;
+  if (OwnerDoc()) {
+    OwnerDoc()->RemoveMediaContent(this);
+  }
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 
   if (mDecoder) {
     MOZ_ASSERT(IsHidden());
     mDecoder->NotifyOwnerActivityChanged(false);
   }