Bug 1342883 - part1: When nsDocument receive unload event from nsDocumentViewer, nofity the MediaElements. r=smaug draft
authorbechen@mozilla.com <bechen@mozilla.com>
Mon, 25 Sep 2017 17:12:27 +0800
changeset 669715 70de598d426376345c88b75d94ec0c49b8ccb8bb
parent 666196 c5d8edcea43b1d186f467f5138c825d80705e109
child 669716 f1c31bcddab4d2a11351b8992293e0babea88f18
push id81405
push userbmo:bechen@mozilla.com
push dateMon, 25 Sep 2017 09:12:47 +0000
reviewerssmaug
bugs1342883
milestone57.0a1
Bug 1342883 - part1: When nsDocument receive unload event from nsDocumentViewer, nofity the MediaElements. r=smaug MozReview-Commit-ID: PZZAAjHYgL
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
layout/base/nsDocumentViewer.cpp
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -4913,37 +4913,46 @@ nsDocument::ContainsMSEContent()
 {
   bool containsMSE = false;
   EnumerateActivityObservers(CheckIfContainsMSEContent,
                              static_cast<void*>(&containsMSE));
   return containsMSE;
 }
 
 static void
-NotifyActivityChanged(nsISupports *aSupports, void *aUnused)
+NotifyActivityChanged(nsISupports *aSupports, void *aDocumentUnload)
 {
   nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aSupports));
   if (domMediaElem) {
     nsCOMPtr<nsIContent> content(do_QueryInterface(domMediaElem));
     MOZ_ASSERT(content, "aSupports is not a content");
     HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(content.get());
-    mediaElem->NotifyOwnerDocumentActivityChanged();
+    bool unload = static_cast<bool*>(aDocumentUnload) ?
+                  *static_cast<bool*>(aDocumentUnload) : false;
+    mediaElem->NotifyOwnerDocumentActivityChanged(&unload);
   }
   nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aSupports));
   if (objectLoadingContent) {
     nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
     olc->NotifyOwnerDocumentActivityChanged();
   }
   nsCOMPtr<nsIDocumentActivity> objectDocumentActivity(do_QueryInterface(aSupports));
   if (objectDocumentActivity) {
     objectDocumentActivity->NotifyOwnerDocumentActivityChanged();
   }
 }
 
 void
+nsDocument::NotifyUnloadEvent()
+{
+  bool unload = true;
+  EnumerateActivityObservers(NotifyActivityChanged, (void*)&unload);
+}
+
+void
 nsIDocument::SetContainer(nsDocShell* aContainer)
 {
   if (aContainer) {
     mDocumentContainer = aContainer;
   } else {
     mDocumentContainer = WeakPtr<nsDocShell>();
   }
 
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -656,17 +656,17 @@ public:
   virtual void NotifyIntersectionObservers() override;
 
   virtual void NotifyLayerManagerRecreated() override;
 
   virtual void ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) override;
   virtual void UnscheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) override;
   virtual void ResolveScheduledSVGPresAttrs() override;
   bool IsSynthesized();
-
+  virtual void NotifyUnloadEvent() override;
 private:
   void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
   void SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages);
 
 public:
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE_OVERRIDABLE
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1087,16 +1087,17 @@ public:
    */
   virtual void ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) = 0;
   // Unschedule an element scheduled by ScheduleFrameRequestCallback (e.g. for when it is destroyed)
   virtual void UnscheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) = 0;
 
   // Resolve all SVG pres attrs scheduled in ScheduleSVGForPresAttrEvaluation
   virtual void ResolveScheduledSVGPresAttrs() = 0;
 
+  virtual void NotifyUnloadEvent() {};
 protected:
   virtual Element *GetRootElementInternal() const = 0;
 
   void SetPageUnloadingEventTimeStamp()
   {
     MOZ_ASSERT(!mPageUnloadingEventTimeStamp);
     mPageUnloadingEventTimeStamp = mozilla::TimeStamp::NowLoRes();
   }
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -6337,17 +6337,17 @@ bool HTMLMediaElement::IsBeingDestroyed(
   nsIDocShell* docShell = ownerDoc ? ownerDoc->GetDocShell() : nullptr;
   bool isBeingDestroyed = false;
   if (docShell) {
     docShell->IsBeingDestroyed(&isBeingDestroyed);
   }
   return isBeingDestroyed;
 }
 
-void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
+void HTMLMediaElement::NotifyOwnerDocumentActivityChanged(bool aDocumentUnload)
 {
   bool visible = !IsHidden();
   if (visible) {
     // Visible -> Just pause hidden play time (no-op if already paused).
     HiddenVideoStop();
   } else if (mPlayTime.IsStarted()) {
     // Not visible, play time is running -> Start hidden play time if needed.
     HiddenVideoStart();
@@ -6357,22 +6357,26 @@ void HTMLMediaElement::NotifyOwnerDocume
     NotifyDecoderActivityChanges();
   }
 
   bool pauseElement = ShouldElementBePaused();
   SuspendOrResumeElement(pauseElement, !IsActive());
 
   // If the owning document has become inactive we should shutdown the CDM.
   if (!OwnerDoc()->IsCurrentActiveDocument() && mMediaKeys) {
-      mMediaKeys->Shutdown();
-      mMediaKeys = nullptr;
-      if (mDecoder) {
-        ShutdownDecoder();
-      }
-    }
+    mMediaKeys->Shutdown();
+    mMediaKeys = nullptr;
+    if (mDecoder) {
+      ShutdownDecoder();
+    }
+  }
+
+  if (aDocumentUnload && mDecoder) {
+    ShutdownDecoder();
+  }
 
   AddRemoveSelfReference();
 }
 
 void HTMLMediaElement::AddRemoveSelfReference()
 {
   // XXX we could release earlier here in many situations if we examined
   // which event listeners are attached. Right now we assume there is a
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -232,17 +232,17 @@ public:
   // ImageContainer containing the video data.
   virtual VideoFrameContainer* GetVideoFrameContainer() final override;
   layers::ImageContainer* GetImageContainer();
 
   /**
    * Call this to reevaluate whether we should start/stop due to our owner
    * document being active, inactive, visible or hidden.
    */
-  void NotifyOwnerDocumentActivityChanged();
+  void NotifyOwnerDocumentActivityChanged(bool aDocumentUnload = false);
 
   // From PrincipalChangeObserver<DOMMediaStream>.
   void PrincipalChanged(DOMMediaStream* aStream) override;
 
   void UpdateSrcStreamVideoPrincipal(const PrincipalHandle& aPrincipalHandle);
 
   // Called after the MediaStream we're playing rendered a frame to aContainer
   // with a different principalHandle than the previous frame.
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1423,16 +1423,20 @@ nsDocumentViewer::PageHide(bool aIsUnloa
 
     // Never permit popups from the unload handler, no matter how we get
     // here.
     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
     nsIDocument::PageUnloadingEventTimeStamp timestamp(mDocument);
 
     EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
+    nsIDocument* doc = GetDocument();
+    if (doc) {
+      doc->NotifyUnloadEvent();
+    }
   }
 
 #ifdef MOZ_XUL
   // look for open menupopups and close them after the unload event, in case
   // the unload event listeners open any new popups
   nsContentUtils::HidePopupsInDocument(mDocument);
 #endif