Bug 1274919 - part3 : only send msg if someone is waiting for it. draft
authorAlastor Wu <alwu@mozilla.com>
Thu, 20 Jul 2017 15:11:25 +0800
changeset 611999 6e261b2a4560fb7cbef6436f94cc373ca690b24f
parent 611975 7601e43eb7f77e32f7eb49af3f191a761997d029
child 612000 7d0f9d7ac56d9769ad01ab710527188c410d0ca5
push id69356
push useralwu@mozilla.com
push dateThu, 20 Jul 2017 07:11:52 +0000
bugs1274919
milestone56.0a1
Bug 1274919 - part3 : only send msg if someone is waiting for it. 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
@@ -154,34 +154,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();
@@ -189,32 +249,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;