Bug 1274919 - part3 : only send msg if someone is waiting for it. r=jwwang,mikedeboer
authorAlastor Wu <alwu@mozilla.com>
Thu, 20 Jul 2017 15:11:25 +0800
changeset 418822 ec8748c31ef32b251d193324790239f361030ea2
parent 418821 2b788dca1f6081f5abd432b624d078fc8d9464b9
child 418823 04596e7f840bc610c2c01032c644ca1ef58f1257
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwwang, mikedeboer
bugs1274919
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1274919 - part3 : only send msg if someone is waiting for it. r=jwwang,mikedeboer Only send the msg "Browser:UnselectedTabHover" when someone requests for the msg, it can reduce non-necessary communication. MozReview-Commit-ID: 2mBUMB4AMVo
dom/media/MediaDecoder.cpp
toolkit/content/browser-content.js
toolkit/content/widgets/browser.xml
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -155,34 +155,94 @@ class MediaDecoder::BackgroundVideoDecod
     }
 
     void RegisterEvent() {
       MOZ_ASSERT(!mIsRegisteredForEvent);
       nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
       if (observerService) {
         observerService->AddObserver(this, "unselected-tab-hover", false);
         mIsRegisteredForEvent = true;
+        EnableEvent();
       }
     }
 
     void UnregisterEvent() {
       MOZ_ASSERT(mIsRegisteredForEvent);
       nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
       if (observerService) {
         observerService->RemoveObserver(this, "unselected-tab-hover");
         mIsRegisteredForEvent = false;
         mDecoder->mIsBackgroundVideoDecodingAllowed = false;
         mDecoder->UpdateVideoDecodeMode();
+        DisableEvent();
       }
     }
   private:
     ~BackgroundVideoDecodingPermissionObserver() {
       MOZ_ASSERT(!mIsRegisteredForEvent);
     }
 
+    void EnableEvent() const
+    {
+      nsCOMPtr<nsPIDOMWindowOuter> win = GetOwnerWindow();
+      if (!win) {
+        return;
+      }
+      nsContentUtils::DispatchEventOnlyToChrome(
+        GetOwnerDoc(), ToSupports(win),
+        NS_LITERAL_STRING("UnselectedTabHover:Enable"),
+        /* Bubbles */ true,
+        /* Cancelable */ false,
+        /* DefaultAction */ nullptr);
+    }
+
+    void DisableEvent() const
+    {
+      nsCOMPtr<nsPIDOMWindowOuter> win = GetOwnerWindow();
+      if (!win) {
+        return;
+      }
+      nsContentUtils::DispatchEventOnlyToChrome(
+        GetOwnerDoc(), ToSupports(win),
+        NS_LITERAL_STRING("UnselectedTabHover:Disable"),
+        /* Bubbles */ true,
+        /* Cancelable */ false,
+        /* DefaultAction */ nullptr);
+    }
+
+    already_AddRefed<nsPIDOMWindowOuter> GetOwnerWindow() const
+    {
+      nsIDocument* doc = GetOwnerDoc();
+      if (!doc) {
+        return nullptr;
+      }
+
+      nsCOMPtr<nsPIDOMWindowInner> innerWin = doc->GetInnerWindow();
+      if (!innerWin) {
+        return nullptr;
+      }
+
+      nsCOMPtr<nsPIDOMWindowOuter> outerWin = innerWin->GetOuterWindow();
+      if (!outerWin) {
+        return nullptr;
+      }
+
+      nsCOMPtr<nsPIDOMWindowOuter> topWin = outerWin->GetTop();
+      return topWin.forget();
+    }
+
+    nsIDocument* GetOwnerDoc() const
+    {
+      if (!mDecoder->mOwner) {
+        return nullptr;
+      }
+
+      return mDecoder->mOwner->GetDocument();
+    }
+
     bool IsValidEventSender(nsISupports* aSubject) const
     {
       nsCOMPtr<nsPIDOMWindowInner> senderInner(do_QueryInterface(aSubject));
       if (!senderInner) {
         return false;
       }
 
       nsCOMPtr<nsPIDOMWindowOuter> senderOuter = senderInner->GetOuterWindow();
@@ -190,32 +250,21 @@ class MediaDecoder::BackgroundVideoDecod
         return false;
       }
 
       nsCOMPtr<nsPIDOMWindowOuter> senderTop = senderOuter->GetTop();
       if (!senderTop) {
         return false;
       }
 
-      nsIDocument* doc = mDecoder->GetOwner()->GetDocument();
-      if (!doc) {
+      nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
+      if (!ownerTop) {
         return false;
       }
 
-      nsCOMPtr<nsPIDOMWindowInner> ownerInner = doc->GetInnerWindow();
-      if (!ownerInner) {
-        return false;
-      }
-
-      nsCOMPtr<nsPIDOMWindowOuter> ownerOuter = ownerInner->GetOuterWindow();
-      if (!ownerOuter) {
-        return false;
-      }
-
-      nsCOMPtr<nsPIDOMWindowOuter> ownerTop = ownerOuter->GetTop();
       return ownerTop == senderTop;
     }
     // The life cycle of observer would always be shorter than decoder, so we
     // use raw pointer here.
     MediaDecoder* mDecoder;
     bool mIsRegisteredForEvent;
 };
 
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -977,20 +977,16 @@ addMessageListener("WebChannelMessageToC
     } else {
       Cu.reportError("WebChannel message failed. Principal mismatch.");
     }
   } else {
     Cu.reportError("WebChannel message failed. No message data.");
   }
 });
 
-addMessageListener("Browser:UnselectedTabHover", message => {
-  Services.obs.notifyObservers(content.window, "unselected-tab-hover", message.data.hovered);
-});
-
 var AudioPlaybackListener = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   init() {
     Services.obs.addObserver(this, "audio-playback");
 
     addMessageListener("AudioPlayback", this);
     addEventListener("unload", () => {
@@ -1060,16 +1056,33 @@ var AudioPlaybackListener = {
   receiveMessage(msg) {
     if (msg.name == "AudioPlayback") {
       this.handleMediaControlMessage(msg.data.type);
     }
   },
 };
 AudioPlaybackListener.init();
 
+var UnselectedTabHoverObserver = {
+  init() {
+    addMessageListener("Browser:UnselectedTabHover", this);
+    addEventListener("UnselectedTabHover:Enable", this);
+    addEventListener("UnselectedTabHover:Disable", this);
+  },
+  receiveMessage(message) {
+    Services.obs.notifyObservers(content.window, "unselected-tab-hover",
+                                 message.data.hovered);
+  },
+  handleEvent(event) {
+    sendAsyncMessage("UnselectedTabHover:Toggle",
+                     { enable: event.type == "UnselectedTabHover:Enable" });
+  }
+};
+UnselectedTabHoverObserver.init();
+
 addMessageListener("Browser:PurgeSessionHistory", function BrowserPurgeHistory() {
   let sessionHistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
   if (!sessionHistory) {
     return;
   }
 
   // place the entry at current index at the end of the history list, so it won't get removed
   if (sessionHistory.index < sessionHistory.count - 1) {
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -845,21 +845,30 @@
               let event = document.createEvent("Events");
               event.initEvent("DOMAudioPlaybackBlockStopped", true, false);
               this.dispatchEvent(event);
             }
           ]]>
         </body>
       </method>
 
+      <!--
+        Only send the message "Browser:UnselectedTabHover" when someone requests
+        for the message, which can reduce non-necessary communication.
+      -->
+      <field name="_shouldSendUnselectedTabHover">false</field>
+      <field name="_unselectedTabHoverMessageListenerCount">0</field>
+
       <method name="unselectedTabHover">
         <parameter name="hovered"/>
         <body>
           <![CDATA[
-            // TODO : only dispatch event when someone is waiting for this message
+            if (!this._shouldSendUnselectedTabHover) {
+              return;
+            }
             this.messageManager.sendAsyncMessage("Browser:UnselectedTabHover",
               { hovered });
           ]]>
         </body>
       </method>
 
       <property name="securityUI">
         <getter>
@@ -987,16 +996,17 @@
             this.messageManager.addMessageListener("PopupBlocking:UpdateBlockedPopups", this);
             this.messageManager.addMessageListener("Autoscroll:Start", this);
             this.messageManager.addMessageListener("Autoscroll:Cancel", this);
             this.messageManager.addMessageListener("AudioPlayback:Start", this);
             this.messageManager.addMessageListener("AudioPlayback:Stop", this);
             this.messageManager.addMessageListener("AudioPlayback:ActiveMediaBlockStart", this);
             this.messageManager.addMessageListener("AudioPlayback:ActiveMediaBlockStop", this);
             this.messageManager.addMessageListener("AudioPlayback:MediaBlockStop", this);
+            this.messageManager.addMessageListener("UnselectedTabHover:Toggle", this);
 
             if (this.hasAttribute("selectmenulist")) {
               this.messageManager.addMessageListener("Forms:ShowDropDown", this);
               this.messageManager.addMessageListener("Forms:HideDropDown", this);
             }
 
           }
         ]]>
@@ -1093,16 +1103,21 @@
               this.activeMediaBlockStarted();
               break;
             case "AudioPlayback:ActiveMediaBlockStop":
               this.activeMediaBlockStopped();
               break;
             case "AudioPlayback:MediaBlockStop":
               this.mediaBlockStopped();
               break;
+            case "UnselectedTabHover:Toggle":
+              this._shouldSendUnselectedTabHover = data.enable ?
+                ++this._unselectedTabHoverMessageListenerCount > 0 :
+                --this._unselectedTabHoverMessageListenerCount == 0;
+              break;
             case "Forms:ShowDropDown": {
               if (!this._selectParentHelper) {
                 this._selectParentHelper =
                   Cu.import("resource://gre/modules/SelectParentHelper.jsm", {}).SelectParentHelper;
               }
 
               let menulist = document.getElementById(this.getAttribute("selectmenulist"));
               menulist.menupopup.style.direction = data.direction;