[Pkg-mozext-commits] [greasemonkey] 23/43: Move all the observer / runner logic back into the frame script.

David Prévot taffit at moszumanska.debian.org
Sun Feb 22 21:56:11 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository greasemonkey.

commit 6298013ea7f16c940d4613b45d4528bd5e69bc34
Author: Anthony Lieuallen <arantius at gmail.com>
Date:   Wed Nov 19 16:44:42 2014 -0500

    Move all the observer / runner logic back into the frame script.
    
    Based on: http://bugzil.la/1048164#c32
    Because the logic before this only worked with E10S on, failed with it off.
    
    Refs #2004
---
 content/framescript.js               | 264 +++++++++++++++++++++++++++++++++--
 modules/contentObserver.js           | 259 ----------------------------------
 modules/util/messageManagerForWin.js |  27 ----
 3 files changed, 252 insertions(+), 298 deletions(-)

diff --git a/content/framescript.js b/content/framescript.js
index 059ed0a..d35d133 100644
--- a/content/framescript.js
+++ b/content/framescript.js
@@ -5,16 +5,256 @@ var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 
-// For every *content* frame/process, make sure the content observer is running.
-var rti = docShell.QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem;
-if (rti.itemType == Ci.nsIDocShellTreeItem.typeContent) {
-  Cu.import('resource://greasemonkey/contentObserver.js');
-
-  addEventListener("pagehide", contentObserver.pagehide.bind(contentObserver));
-  addEventListener("pageshow", contentObserver.pageshow.bind(contentObserver));
-
-  addMessageListener("greasemonkey:inject-script",
-      contentObserver.runDelayedScript.bind(contentObserver));
-  addMessageListener("greasemonkey:menu-command-clicked",
-      contentObserver.runMenuCommand.bind(contentObserver));
+Cu.import('resource://gre/modules/Services.jsm');
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+Cu.import('resource://greasemonkey/GM_setClipboard.js');
+Cu.import('resource://greasemonkey/ipcscript.js');
+Cu.import('resource://greasemonkey/miscapis.js');
+Cu.import('resource://greasemonkey/sandbox.js');
+Cu.import('resource://greasemonkey/util.js');
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+var gScope = this;
+var gScriptRunners = {};
+var gStripUserPassRegexp = new RegExp('(://)([^:/]+)(:[^@/]+)?@');
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+function ScriptRunner(aWindow, aUrl) {
+  this.menuCommands = [];
+  this.window = aWindow;
+  this.windowId = GM_util.windowId(this.window);
+  this.url = aUrl;
 }
+
+ScriptRunner.prototype.injectScripts = function(aScripts) {
+  try {
+    this.window.QueryInterface(Ci.nsIDOMChromeWindow);
+    // Never ever inject scripts into a chrome context window.
+    return;
+  } catch(e) {
+    // Ignore, it's good if we can't QI to a chrome window.
+  }
+
+  var winIsTop = this.windowIsTop(this.window);
+
+  for (var i = 0, script = null; script = aScripts[i]; i++) {
+    if (script.noframes && !winIsTop) continue;
+    var sandbox = createSandbox(script, this, gScope);
+    runScriptInSandbox(script, sandbox);
+  }
+};
+
+ScriptRunner.prototype.openInTab = function(aUrl, aInBackground) {
+  var response = sendSyncMessage('greasemonkey:open-in-tab', {
+    inBackground: aInBackground,
+    url: aUrl
+  });
+  return response ? response[0] : null;
+};
+
+
+ScriptRunner.prototype.registeredMenuCommand = function(aCommand) {
+  var length = this.menuCommands.push(aCommand);
+
+  sendAsyncMessage('greasemonkey:menu-command-registered', {
+    accessKey: aCommand.accessKey,
+    frozen: aCommand.frozen,
+    index: length - 1,
+    name: aCommand.name,
+    windowId: aCommand.contentWindowId
+  });
+};
+
+ScriptRunner.prototype.windowIsTop = function(aContentWin) {
+  try {
+    aContentWin.QueryInterface(Ci.nsIDOMWindow);
+    if (aContentWin.frameElement) return false;
+  } catch (e) {
+    var url = 'unknown';
+    try {
+      url = aContentWin.location.href;
+    } catch (e) { }
+    // Ignore non-DOM-windows.
+    dump('Could not QI this.window to nsIDOMWindow at\n' + url + ' ?!\n');
+  }
+  return true;
+};
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+function ContentObserver() {
+}
+
+
+ContentObserver.prototype.QueryInterface = XPCOMUtils.generateQI([
+    Ci.nsIObserver]);
+
+
+ContentObserver.prototype.createScriptFromObject = function(aObject) {
+  var script = Object.create(IPCScript.prototype);
+  // TODO: better way for this? Object.create needs property descriptors.
+  for (var key in aObject) {
+    script[key] = aObject[key];
+  }
+  return script;
+};
+
+
+ContentObserver.prototype.contentLoad = function(aEvent) {
+  var contentWin = aEvent.target.defaultView;
+
+  // Now that we've seen any first load event, stop listening for any more.
+  contentWin.removeEventListener('DOMContentLoaded', gContentLoad, true);
+  contentWin.removeEventListener('load', gContentLoad, true);
+
+  this.runScripts('document-end', contentWin);
+};
+
+
+ContentObserver.prototype.observe = function(aSubject, aTopic, aData) {
+  if (!GM_util.getEnabled()) return;
+
+  switch (aTopic) {
+    case 'document-element-inserted':
+      if (!GM_util.getEnabled()) return;
+
+      var doc = aSubject;
+      var win = doc && doc.defaultView;
+      if (!doc || !win) return;
+      if (win.top !== content) return;
+
+      var url = doc.documentURI;
+      if (!GM_util.isGreasemonkeyable(url)) return;
+
+      // Listen for whichever kind of load event arrives first.
+      win.addEventListener('DOMContentLoaded', gContentLoad, true);
+      win.addEventListener('load', gContentLoad, true);
+
+      this.runScripts('document-start', win);
+      break;
+    default:
+      dump('Content frame observed unknown topic: ' + aTopic + '\n');
+  }
+};
+
+
+ContentObserver.prototype.pagehide = function(aEvent) {
+  var contentWin = aEvent.target.defaultView;
+  var windowId = GM_util.windowId(contentWin);
+
+  if (!windowId || !gScriptRunners[windowId]) return;
+
+  // Small optimization: only send a notification if there's a menu command
+  // for this window.
+  if (!gScriptRunners[windowId].menuCommands.length) return;
+
+  if (aEvent.persisted) {
+    sendAsyncMessage('greasemonkey:toggle-menu-commands', {
+      frozen: true,
+      windowId: windowId
+    });
+  } else {
+    sendAsyncMessage('greasemonkey:clear-menu-commands', {
+      windowId: windowId
+    });
+  }
+};
+
+
+ContentObserver.prototype.pageshow = function(aEvent) {
+  var contentWin = aEvent.target.defaultView;
+  var windowId = GM_util.windowId(contentWin);
+
+  if (!windowId || !gScriptRunners[windowId]) return;
+
+  if (!gScriptRunners[windowId].menuCommands.length) return;
+
+  sendAsyncMessage('greasemonkey:toggle-menu-commands', {
+    frozen: false,
+    windowId: windowId
+  });
+};
+
+
+ContentObserver.prototype.runDelayedScript = function(aMessage) {
+  var windowId = aMessage.data.windowId;
+  var scriptRunner = gScriptRunners[windowId];
+  if (!scriptRunner) return;
+
+  var script = this.createScriptFromObject(aMessage.data.script);
+  scriptRunner.injectScripts([script]);
+};
+
+
+ContentObserver.prototype.runMenuCommand = function(aMessage) {
+  var windowId = aMessage.data.windowId;
+  if (!gScriptRunners[windowId]) return;
+
+  var index = aMessage.data.index;
+  var command = gScriptRunners[windowId].menuCommands[index];
+  if (!command || !command.commandFunc) return;
+
+  // Ensure |this| is set to the sandbox object inside the command function.
+  command.commandFunc.call(null);
+};
+
+
+ContentObserver.prototype.runScripts = function(aRunWhen, aContentWin) {
+  // See #1970
+  // When content does (e.g.) history.replacestate() in an inline script,
+  // the location.href changes between document-start and document-end time.
+  // But the content can call replacestate() much later, too.  The only way to
+  // be consistent is to ignore it.  Luckily, the  document.documentURI does
+  // _not_ change, so always use it when deciding whether to run scripts.
+  var url = aContentWin.document.documentURI;
+  // But ( #1631 ) ignore user/pass in the URL.
+  url = url.replace(gStripUserPassRegexp, '$1');
+
+  if (!GM_util.isGreasemonkeyable(url)) return;
+
+  var scriptRunner = gScriptRunners[windowId];
+  var windowId = GM_util.windowId(aContentWin);
+  if (!scriptRunner) {
+    scriptRunner = new ScriptRunner(aContentWin, url);
+    gScriptRunners[windowId] = scriptRunner;
+  } else if (scriptRunner.window !== aContentWin) {
+    // Sanity check, shouldn't be necessary.
+    // TODO: remove
+    dump('Script runner window changed for ' + url + ' at ' + aRunWhen + '\n');
+    scriptRunner.window = aContentWin;
+  }
+
+  var response = sendSyncMessage(
+    'greasemonkey:scripts-for-url', {
+      'url': url,
+      'when': aRunWhen,
+      'windowId': windowId
+    });
+  if (!response || !response[0]) return;
+
+  var scripts = response[0].map(this.createScriptFromObject);
+  scriptRunner.injectScripts(scripts);
+};
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+// Create a singleton object within this frame, attach observer/listeners to it.
+var contentObserver = new ContentObserver();
+
+// This global function reference can easily be both attached as an event
+// listener, and then removed again.
+var gContentLoad = contentObserver.contentLoad.bind(contentObserver);
+
+addEventListener('pagehide', contentObserver.pagehide.bind(contentObserver));
+addEventListener('pageshow', contentObserver.pageshow.bind(contentObserver));
+addMessageListener('greasemonkey:inject-script',
+    contentObserver.runDelayedScript.bind(contentObserver));
+addMessageListener('greasemonkey:menu-command-clicked',
+    contentObserver.runMenuCommand.bind(contentObserver));
+Services.obs.addObserver(contentObserver, 'document-element-inserted', false);
+addEventListener('unload', function() {
+  Services.obs.removeObserver(contentObserver, 'document-element-inserted');
+}, false);
diff --git a/modules/contentObserver.js b/modules/contentObserver.js
deleted file mode 100644
index ab32e88..0000000
--- a/modules/contentObserver.js
+++ /dev/null
@@ -1,259 +0,0 @@
-var EXPORTED_SYMBOLS = ['contentObserver'];
-
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-Cu.import('resource://greasemonkey/GM_setClipboard.js');
-Cu.import("resource://greasemonkey/ipcscript.js");
-Cu.import("resource://greasemonkey/miscapis.js");
-Cu.import("resource://greasemonkey/sandbox.js");
-Cu.import('resource://greasemonkey/util.js');
-
-// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-
-var gScriptRunners = {};
-var gStripUserPassRegexp = new RegExp('(://)([^:/]+)(:[^@/]+)?@');
-
-// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-
-function ScriptRunner(aWindow, aUrl) {
-  this.menuCommands = [];
-  this.window = aWindow;
-  this.windowId = GM_util.windowId(this.window);
-  this.url = aUrl;
-}
-
-ScriptRunner.prototype.injectScripts = function(aScripts, aMessageManager) {
-  try {
-    this.window.QueryInterface(Ci.nsIDOMChromeWindow);
-    // Never ever inject scripts into a chrome context window.
-    return;
-  } catch(e) {
-    // Ignore, it's good if we can't QI to a chrome window.
-  }
-
-  var winIsTop = this.windowIsTop(this.window);
-
-  for (var i = 0, script = null; script = aScripts[i]; i++) {
-    if (script.noframes && !winIsTop) continue;
-    var sandbox = createSandbox(script, this, aMessageManager);
-    runScriptInSandbox(script, sandbox);
-  }
-};
-
-ScriptRunner.prototype.openInTab = function(aUrl, aInBackground) {
-  var mm = GM_util.messageManagerForWin(this.window);
-  var response = mm.sendSyncMessage('greasemonkey:open-in-tab', {
-    inBackground: aInBackground,
-    url: aUrl
-  });
-
-  return response ? response[0] : null;
-};
-
-
-ScriptRunner.prototype.registeredMenuCommand = function(aCommand) {
-  var length = this.menuCommands.push(aCommand);
-
-  var mm = GM_util.messageManagerForWin(this.window);
-  mm.sendAsyncMessage("greasemonkey:menu-command-registered", {
-    accessKey: aCommand.accessKey,
-    frozen: aCommand.frozen,
-    index: length - 1,
-    name: aCommand.name,
-    windowId: aCommand.contentWindowId
-  });
-};
-
-ScriptRunner.prototype.windowIsTop = function(aContentWin) {
-  try {
-    aContentWin.QueryInterface(Ci.nsIDOMWindow);
-    if (aContentWin.frameElement) return false;
-  } catch (e) {
-    var url = 'unknown';
-    try {
-      url = aContentWin.location.href;
-    } catch (e) { }
-    // Ignore non-DOM-windows.
-    dump('Could not QI this.window to nsIDOMWindow at\n' + url + ' ?!\n');
-  }
-  return true;
-};
-
-// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-
-function ContentObserver() {
-}
-
-
-ContentObserver.prototype.QueryInterface = XPCOMUtils.generateQI([
-    Ci.nsIObserver]);
-
-
-ContentObserver.prototype.createScriptFromObject = function(aObject) {
-  var script = Object.create(IPCScript.prototype);
-  // TODO: better way for this? Object.create needs property descriptors.
-  for (var key in aObject) {
-    script[key] = aObject[key];
-  }
-  return script;
-};
-
-
-ContentObserver.prototype.contentLoad = function(aEvent) {
-  var contentWin = aEvent.target.defaultView;
-
-  // Now that we've seen any first load event, stop listening for any more.
-  contentWin.removeEventListener("DOMContentLoaded", gContentLoad, true);
-  contentWin.removeEventListener("load", gContentLoad, true);
-
-  this.runScripts('document-end', contentWin);
-};
-
-
-ContentObserver.prototype.observe = function(aSubject, aTopic, aData) {
-  if (!GM_util.getEnabled()) return;
-
-  switch (aTopic) {
-    case 'document-element-inserted':
-      if (!GM_util.getEnabled()) return;
-
-      var doc = aSubject;
-      var url = doc.documentURI;
-      if (!GM_util.isGreasemonkeyable(url)) return;
-
-      var win = doc && doc.defaultView;
-      if (!doc || !win) break;
-
-      // Listen for whichever kind of load event arrives first.
-      win.addEventListener("DOMContentLoaded", gContentLoad, true);
-      win.addEventListener("load", gContentLoad, true);
-
-      this.runScripts('document-start', win);
-      break;
-    default:
-      dump("received unknown topic: " + aTopic + "\n");
-  }
-};
-
-
-ContentObserver.prototype.pagehide = function(aEvent) {
-  var contentWin = aEvent.target.defaultView;
-  var windowId = GM_util.windowId(contentWin);
-
-  if (!windowId || !gScriptRunners[windowId]) return;
-
-  // Small optimization: only send a notification if there's a menu command
-  // for this window.
-  if (!gScriptRunners[windowId].menuCommands.length) return;
-
-  var mm = GM_util.messageManagerForWin(contentWin);
-  if (aEvent.persisted) {
-    mm.sendAsyncMessage("greasemonkey:toggle-menu-commands", {
-      frozen: true,
-      windowId: windowId
-    });
-  } else {
-    mm.sendAsyncMessage("greasemonkey:clear-menu-commands", {
-      windowId: windowId
-    });
-  }
-};
-
-
-ContentObserver.prototype.pageshow = function(aEvent) {
-  var contentWin = aEvent.target.defaultView;
-  var windowId = GM_util.windowId(contentWin);
-
-  if (!windowId || !gScriptRunners[windowId]) return;
-
-  if (!gScriptRunners[windowId].menuCommands.length) return;
-
-  var mm = GM_util.messageManagerForWin(contentWin);
-  mm.sendAsyncMessage("greasemonkey:toggle-menu-commands", {
-    frozen: false,
-    windowId: windowId
-  });
-};
-
-
-ContentObserver.prototype.runDelayedScript = function(aMessage) {
-  var windowId = aMessage.data.windowId;
-  var scriptRunner = gScriptRunners[windowId];
-  if (!scriptRunner) return;
-
-  var script = this.createScriptFromObject(aMessage.data.script);
-  scriptRunner.injectScripts(
-      [script],
-      GM_util.messageManagerForWin(scriptRunner.window));
-};
-
-
-ContentObserver.prototype.runMenuCommand = function(aMessage) {
-  var windowId = aMessage.data.windowId;
-  if (!gScriptRunners[windowId]) return;
-
-  var index = aMessage.data.index;
-  var command = gScriptRunners[windowId].menuCommands[index];
-  if (!command || !command.commandFunc) return;
-
-  // Ensure |this| is set to the sandbox object inside the command function.
-  command.commandFunc.call(null);
-};
-
-
-ContentObserver.prototype.runScripts = function(aRunWhen, aContentWin) {
-  // See #1970
-  // When content does (e.g.) history.replacestate() in an inline script,
-  // the location.href changes between document-start and document-end time.
-  // But the content can call replacestate() much later, too.  The only way to
-  // be consistent is to ignore it.  Luckily, the  document.documentURI does
-  // _not_ change, so always use it when deciding whether to run scripts.
-  var url = aContentWin.document.documentURI;
-  // But ( #1631 ) ignore user/pass in the URL.
-  url = url.replace(gStripUserPassRegexp, '$1');
-
-  if (!GM_util.isGreasemonkeyable(url)) return;
-
-  var scriptRunner = gScriptRunners[windowId];
-  var windowId = GM_util.windowId(aContentWin);
-  if (!scriptRunner) {
-    scriptRunner = new ScriptRunner(aContentWin, url);
-    gScriptRunners[windowId] = scriptRunner;
-  } else if (scriptRunner.window !== aContentWin) {
-    // Sanity check, shouldn't be necessary.
-    // TODO: remove
-    dump("Script runner window changed for " + url + " at " + aRunWhen + "\n");
-    scriptRunner.window = aContentWin;
-  }
-
-  var mm = GM_util.messageManagerForWin(aContentWin);
-  var response = mm.sendSyncMessage(
-    'greasemonkey:scripts-for-url', {
-      'url': url,
-      'when': aRunWhen,
-      'windowId': windowId
-    });
-  if (!response || !response[0]) return;
-
-  var scripts = response[0].map(this.createScriptFromObject);
-  scriptRunner.injectScripts(
-      scripts, GM_util.messageManagerForWin(aContentWin));
-};
-
-// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
-
-// Since observers are process-global, create this observer singleton in the
-// process-global JSM scope.
-var contentObserver = new ContentObserver();
-Services.obs.addObserver(contentObserver, 'document-element-inserted', false);
-
-// This single global function reference can easily be both attached as
-// an event listener, and then removed again.
-var gContentLoad = contentObserver.contentLoad.bind(contentObserver);
diff --git a/modules/util/messageManagerForWin.js b/modules/util/messageManagerForWin.js
deleted file mode 100644
index 7d2f523..0000000
--- a/modules/util/messageManagerForWin.js
+++ /dev/null
@@ -1,27 +0,0 @@
-var EXPORTED_SYMBOLS = ['messageManagerForWin'];
-
-var Ci = Components.interfaces;
-
-function messageManagerForWin(aContentWin) {
-  try {
-    // This crazy incantation works only when E10S is ENabled.
-    return aContentWin.QueryInterface(Ci.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIWebNavigation)
-        .QueryInterface(Ci.nsIDocShellTreeItem)
-        .rootTreeItem
-        .QueryInterface(Ci.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIContentFrameMessageManager);
-  } catch (e) {
-    // While this one works when E10S is DISabled.
-    try {
-      return aContentWin.QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(Ci.nsIWebNavigation)
-          .QueryInterface(Ci.nsIDocShell)
-          .QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(Ci.nsIContentFrameMessageManager);
-    } catch (e) {
-      dump('Could not get message manager round 2:\n'+e+'\n\n');
-      return null;
-    }
-  }
-};

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/greasemonkey.git



More information about the Pkg-mozext-commits mailing list