Bug 1274919 - Part 2: Start decoding suspended video when mouse begins hovering tab. r?cpearce draft
authorDan Glastonbury <dglastonbury@mozilla.com>
Mon, 23 May 2016 14:20:23 +1000
changeset 370571 fd85d3450c3310c5e32cd3fddf85089a034accd2
parent 370570 d59d44f895b9c538b98fda44fe906f44c7232081
child 521790 5d143c52e6fcbee7dbbee097d131aa063c296b92
push id19106
push userbmo:dglastonbury@mozilla.com
push dateWed, 25 May 2016 01:25:27 +0000
reviewerscpearce
bugs1274919
milestone49.0a1
Bug 1274919 - Part 2: Start decoding suspended video when mouse begins hovering tab. r?cpearce MozReview-Commit-ID: 80SGYdE1atj
dom/base/nsGlobalWindow.cpp
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4039,17 +4039,21 @@ nsPIDOMWindowOuter::SetTabHovered(bool a
 #endif
 
   if (mTabHovered == aHovered) {
     return;
   }
 
   mTabHovered = aHovered;
 
-  // TODO: Notify media elements to become ready (exit suspend/dormant, spin
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(ToSupports(this), "tab-hover",
+                         mTabHovered ? MOZ_UTF16("true") : MOZ_UTF16("false"));
+  }
 }
 
 bool
 nsPIDOMWindowInner::GetAudioCaptured() const
 {
   MOZ_ASSERT(IsInnerWindow());
   return mAudioCaptured;
 }
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4576,43 +4576,88 @@ void HTMLMediaElement::AddRemoveSelfRefe
       mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING));
 
   if (needSelfReference != mHasSelfReference) {
     mHasSelfReference = needSelfReference;
     if (needSelfReference) {
       // The observer service will hold a strong reference to us. This
       // will do to keep us alive. We need to know about shutdown so that
       // we can release our self-reference.
-      nsContentUtils::RegisterShutdownObserver(this);
+      RegisterObservers();
     } else {
       // Dispatch Release asynchronously so that we don't destroy this object
       // inside a call stack of method calls on this object
       nsCOMPtr<nsIRunnable> event =
         NewRunnableMethod(this, &HTMLMediaElement::DoRemoveSelfReference);
       NS_DispatchToMainThread(event);
     }
   }
 
   UpdateAudioChannelPlayingState();
 }
 
 void HTMLMediaElement::DoRemoveSelfReference()
 {
   // We don't need the shutdown observer anymore. Unregistering releases
   // its reference to us, which we were using as our self-reference.
+  UnregisterObservers();
+}
+
+void HTMLMediaElement::RegisterObservers()
+{
+  nsContentUtils::RegisterShutdownObserver(this);
+
+  // Register interest in tab-hover. This is used to notify decoders to wake up
+  // from suspended state.
+  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
+  if (observerService) {
+    observerService->AddObserver(this, "tab-hover", false);
+  }
+}
+
+void HTMLMediaElement::UnregisterObservers()
+{
   nsContentUtils::UnregisterShutdownObserver(this);
+
+  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
+  if (observerService) {
+    observerService->RemoveObserver(this, "tab-hover");
+  }
 }
 
 nsresult HTMLMediaElement::Observe(nsISupports* aSubject,
-                                   const char* aTopic, const char16_t* aData)
+                                   const char* aTopic,
+                                   const char16_t* aData)
 {
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
     mShuttingDown = true;
     AddRemoveSelfReference();
-  }
+  } else if (strcmp(aTopic, "tab-hover") == 0) {
+    nsIDocument* doc = OwnerDoc();
+    if (!doc) {
+      return NS_OK;
+    }
+
+    nsPIDOMWindowOuter* owningWindow = doc->GetWindow();
+    nsCOMPtr<nsPIDOMWindowOuter> sourceWindow = do_QueryInterface(aSubject);
+    if (!owningWindow || owningWindow != sourceWindow) {
+      return NS_OK;
+    }
+
+    nsAutoString value(aData);
+    bool tabHovered = value.EqualsASCII("true");
+
+    // Tell the decoder that it needs to wake up.
+    // TODO: At the moment this is done via tell the decoder that it has
+    // become visible. This may need to change.
+    if (mDecoder && !IsBeingDestroyed()) {
+      mDecoder->NotifyOwnerActivityChanged(tabHovered || !IsHidden());
+    }
+  }
+
   return NS_OK;
 }
 
 bool
 HTMLMediaElement::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eCONTENT | eMEDIA));
 }
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -981,16 +981,19 @@ protected:
    */
   void AddRemoveSelfReference();
 
   /**
    * Called asynchronously to release a self-reference to this element.
    */
   void DoRemoveSelfReference();
 
+  void RegisterObservers();
+  void UnregisterObservers();
+
   /**
    * Possible values of the 'preload' attribute.
    */
   enum PreloadAttrValue {
     PRELOAD_ATTR_EMPTY,    // set to ""
     PRELOAD_ATTR_NONE,     // set to "none"
     PRELOAD_ATTR_METADATA, // set to "metadata"
     PRELOAD_ATTR_AUTO      // set to "auto"