Bug 1067576 - Make console.log work in frame scripts (r=Mossop)
authorBill McCloskey <wmccloskey@mozilla.com>
Tue, 07 Oct 2014 11:46:25 -0700
changeset 209232 c5e310d17e58610b6f1b1b13779a98a1ccc1acb4
parent 209231 e5c5d33293aa89bcae840849adba3438d57810c5
child 209233 09bd9d93d3e2574abdc5db3f608737a309eb8d59
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersMossop
bugs1067576
milestone35.0a1
Bug 1067576 - Make console.log work in frame scripts (r=Mossop)
browser/installer/package-manifest.in
toolkit/components/moz.build
toolkit/components/processsingleton/ContentProcessSingleton.js
toolkit/components/processsingleton/MainProcessSingleton.js
toolkit/components/processsingleton/ProcessSingleton.manifest
toolkit/components/processsingleton/moz.build
toolkit/content/browser-content.js
toolkit/content/widgets/browser.xml
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -439,16 +439,19 @@
 @BINPATH@/components/nsUpdateService.js
 @BINPATH@/components/nsUpdateServiceStub.js
 #endif
 @BINPATH@/components/nsUpdateTimerManager.manifest
 @BINPATH@/components/nsUpdateTimerManager.js
 @BINPATH@/components/addoncompat.manifest
 @BINPATH@/components/multiprocessShims.js
 @BINPATH@/components/pluginGlue.manifest
+@BINPATH@/components/ProcessSingleton.manifest
+@BINPATH@/components/MainProcessSingleton.js
+@BINPATH@/components/ContentProcessSingleton.js
 @BINPATH@/browser/components/nsSessionStore.manifest
 @BINPATH@/browser/components/nsSessionStartup.js
 @BINPATH@/browser/components/nsSessionStore.js
 @BINPATH@/components/nsURLFormatter.manifest
 @BINPATH@/components/nsURLFormatter.js
 @BINPATH@/browser/components/@DLL_PREFIX@browsercomps@DLL_SUFFIX@
 @BINPATH@/components/txEXSLTRegExFunctions.manifest
 @BINPATH@/components/txEXSLTRegExFunctions.js
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -31,16 +31,17 @@ DIRS += [
     'jsdownloads',
     'mediasniffer',
     'microformats',
     'osfile',
     'parentalcontrols',
     'passwordmgr',
     'perf',
     'places',
+    'processsingleton',
     'promiseworker',
     'prompts',
     'protobuf',
     'reflect',
     'sqlite',
     'startup',
     'statusfilter',
     'telemetry',
new file mode 100644
--- /dev/null
+++ b/toolkit/components/processsingleton/ContentProcessSingleton.js
@@ -0,0 +1,64 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
+                                   "@mozilla.org/childprocessmessagemanager;1",
+                                   "nsIMessageSender");
+
+function ContentProcessSingleton() {}
+ContentProcessSingleton.prototype = {
+  classID: Components.ID("{ca2a8470-45c7-11e4-916c-0800200c9a66}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference]),
+
+  observe: function(subject, topic, data) {
+    switch (topic) {
+    case "app-startup": {
+      Services.obs.addObserver(this, "console-api-log-event", false);
+      Services.obs.addObserver(this, "xpcom-shutdown", false);
+      break;
+    }
+    case "console-api-log-event": {
+      let consoleMsg = subject.wrappedJSObject;
+
+      let msgData = {
+        level: consoleMsg.level,
+        filename: consoleMsg.filename,
+        lineNumber: consoleMsg.lineNumber,
+        functionName: consoleMsg.functionName,
+        timeStamp: consoleMsg.timeStamp,
+        arguments: [],
+      };
+
+      // We can't send objects over the message manager, so we sanitize
+      // them out.
+      for (let arg of consoleMsg.arguments) {
+        if ((typeof arg == "object" || typeof arg == "function") && arg !== null) {
+          msgData.arguments.push("<unavailable>");
+        } else {
+          msgData.arguments.push(arg);
+        }
+      }
+
+      cpmm.sendAsyncMessage("Console:Log", msgData);
+      break;
+    }
+
+    case "xpcom-shutdown":
+      Services.obs.removeObserver(this, "console-api-log-event");
+      Services.obs.removeObserver(this, "xpcom-shutdown");
+      break;
+    }
+  },
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentProcessSingleton]);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/processsingleton/MainProcessSingleton.js
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
+                                   "@mozilla.org/parentprocessmessagemanager;1",
+                                   "nsIMessageListenerManager");
+
+XPCOMUtils.defineLazyServiceGetter(this, "globalmm",
+                                   "@mozilla.org/globalmessagemanager;1",
+                                   "nsIMessageBroadcaster");
+
+function MainProcessSingleton() {}
+MainProcessSingleton.prototype = {
+  classID: Components.ID("{0636a680-45cb-11e4-916c-0800200c9a66}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference]),
+
+  receiveMessage: function(message) {
+    let logMsg = message.data;
+    logMsg.wrappedJSObject = logMsg;
+    Services.obs.notifyObservers(logMsg, "console-api-log-event", null);
+  },
+
+  observe: function(subject, topic, data) {
+    switch (topic) {
+    case "app-startup": {
+      Services.obs.addObserver(this, "xpcom-shutdown", false);
+
+      // Load this script early so that console.* is initialized
+      // before other frame scripts.
+      globalmm.loadFrameScript("chrome://global/content/browser-content.js", true);
+      ppmm.addMessageListener("Console:Log", this);
+      break;
+    }
+
+    case "xpcom-shutdown":
+      ppmm.removeMessageListener("Console:Log", this);
+      break;
+    }
+  },
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MainProcessSingleton]);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/processsingleton/ProcessSingleton.manifest
@@ -0,0 +1,7 @@
+component {0636a680-45cb-11e4-916c-0800200c9a66} MainProcessSingleton.js process=main
+contract @mozilla.org/main-process-singleton;1 {0636a680-45cb-11e4-916c-0800200c9a66} process=main
+category app-startup MainProcessSingleton service,@mozilla.org/main-process-singleton;1 process=main
+
+component {ca2a8470-45c7-11e4-916c-0800200c9a66} ContentProcessSingleton.js process=content
+contract @mozilla.org/content-process-singleton;1 {ca2a8470-45c7-11e4-916c-0800200c9a66} process=content
+category app-startup ContentProcessSingleton service,@mozilla.org/content-process-singleton;1 process=content
new file mode 100644
--- /dev/null
+++ b/toolkit/components/processsingleton/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXTRA_COMPONENTS += [
+    'ContentProcessSingleton.js',
+    'MainProcessSingleton.js',
+    'ProcessSingleton.manifest',
+]
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -343,9 +343,13 @@ let PopupBlocking = {
     }
   },
 
   updateBlockedPopups: function(freshPopup) {
     sendAsyncMessage("PopupBlocking:UpdateBlockedPopups",
                      {blockedPopups: this.popupData, freshPopup: freshPopup});
   },
 };
-PopupBlocking.init();
\ No newline at end of file
+PopupBlocking.init();
+
+// Set up console.* for frame scripts.
+let Console = Components.utils.import("resource://gre/modules/devtools/Console.jsm", {});
+this.console = new Console.ConsoleAPI();
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -785,17 +785,16 @@
             this.addEventListener("pageshow", this.onPageShow, true);
             this.addEventListener("pagehide", this.onPageHide, true);
           }
 
           if (this.messageManager) {
             this.messageManager.addMessageListener("PopupBlocking:UpdateBlockedPopups", this);
             this.messageManager.addMessageListener("Autoscroll:Start", this);
             this.messageManager.addMessageListener("Autoscroll:Cancel", this);
-            this.messageManager.loadFrameScript("chrome://global/content/browser-content.js", true);
           }
         ]]>
       </constructor>
 
       <destructor>
         <![CDATA[
           this.destroy();
         ]]>