diff --git a/platform/firefox/frameModule.js b/platform/firefox/frameModule.js index c773a5160..8a73cb05f 100644 --- a/platform/firefox/frameModule.js +++ b/platform/firefox/frameModule.js @@ -471,30 +471,18 @@ var contentObserver = { /******************************************************************************/ -const locationChangedMessageName = hostName + ':locationChanged'; - -var LocationChangeListener = function(docShell) { - if ( !docShell ) { +var LocationChangeListener = function(docShell, webProgress) { + var mm = docShell.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + if ( !mm || typeof mm.sendAsyncMessage !== 'function' ) { return; } - - var requestor = docShell.QueryInterface(Ci.nsIInterfaceRequestor); - var ds = requestor.getInterface(Ci.nsIWebProgress); - if ( !ds ) { - return; - } - var mm = requestor.getInterface(Ci.nsIContentFrameMessageManager); - if ( !mm ) { - return; - } - if ( typeof mm.sendAsyncMessage !== 'function' ) { - return; - } - this.docShell = ds; this.messageManager = mm; - ds.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION); + webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION); }; +LocationChangeListener.prototype.messageName = hostName + ':locationChanged'; + LocationChangeListener.prototype.QueryInterface = XPCOMUtils.generateQI([ 'nsIWebProgressListener', 'nsISupportsWeakReference' @@ -504,7 +492,7 @@ LocationChangeListener.prototype.onLocationChange = function(webProgress, reques if ( !webProgress.isTopLevel ) { return; } - this.messageManager.sendAsyncMessage(locationChangedMessageName, { + this.messageManager.sendAsyncMessage(this.messageName, { url: location.asciiSpec, flags: flags }); diff --git a/platform/firefox/frameScript.js b/platform/firefox/frameScript.js index b1a908fde..05e5ceff7 100644 --- a/platform/firefox/frameScript.js +++ b/platform/firefox/frameScript.js @@ -1,7 +1,7 @@ /******************************************************************************* - µBlock - a browser extension to block requests. - Copyright (C) 2014 The µBlock authors + uBlock Origin - a browser extension to block requests. + Copyright (C) 2014-2016 The uBlock Origin authors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,68 +23,44 @@ // https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Frame_script_environment -(function(context) { +(function() { -'use strict'; + 'use strict'; -/******************************************************************************/ - -let {contentObserver, LocationChangeListener} = Components.utils.import( - Components.stack.filename.replace('Script', 'Module'), - null -); - -// https://github.com/gorhill/uBlock/issues/1444 -// Apparently the same context is used for all extensions, hence we must use -// scoped variables to ensure no collision. -let locationChangeListener; - -let injectContentScripts = function(win) { - if ( !win || !win.document ) { + if ( !this.docShell ) { return; } - contentObserver.observe(win.document); + let {LocationChangeListener} = Components.utils.import( + Components.stack.filename.replace('Script', 'Module'), + null + ); - if ( win.frames && win.frames.length ) { - let i = win.frames.length; - while ( i-- ) { - injectContentScripts(win.frames[i]); + // https://github.com/gorhill/uBlock/issues/1444 + // Apparently the same context is used for all extensions, hence we must + // use scoped variables to ensure no collision. + let locationChangeListener; + + // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Progress_Listeners + // "Note that the browser uses a weak reference to your listener object, + // "so make sure to keep an external reference to your object to ensure + // "that it stays in memory." + // This listener below allows us to keep `locationChangeListener` alive + // until we no longer need it. + let shutdown = function(ev) { + if ( ev.target === this ) { + this.removeEventListener('unload', shutdown); } + }; + this.addEventListener('unload', shutdown); + + let webProgress = this.docShell + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebProgress); + if ( webProgress && webProgress.isTopLevel ) { + locationChangeListener = new LocationChangeListener(this.docShell, webProgress); } -}; -let onLoadCompleted = function() { - context.removeMessageListener('ublock0-load-completed', onLoadCompleted); - injectContentScripts(context.content); -}; -context.addMessageListener('ublock0-load-completed', onLoadCompleted); - -let shutdown = function(ev) { - if ( ev.target !== context ) { - return; - } - context.removeMessageListener('ublock0-load-completed', onLoadCompleted); - context.removeEventListener('unload', shutdown); - locationChangeListener = null; - LocationChangeListener = null; - contentObserver = null; -}; -context.addEventListener('unload', shutdown); - -if ( context.docShell ) { - let Ci = Components.interfaces; - let wp = context.docShell.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebProgress); - let dw = wp.DOMWindow; - - if ( dw === dw.top ) { - locationChangeListener = new LocationChangeListener(context.docShell); - } -} - -/******************************************************************************/ - -})(this); +}).call(this); /******************************************************************************/ diff --git a/platform/firefox/frameScript0.js b/platform/firefox/frameScript0.js new file mode 100644 index 000000000..38acce2ec --- /dev/null +++ b/platform/firefox/frameScript0.js @@ -0,0 +1,58 @@ +/******************************************************************************* + + uBlock Origin - a browser extension to block requests. + Copyright (C) 2014-2016 The uBlock Origin authors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +/******************************************************************************/ + +// https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Frame_script_environment + +(function(context) { + + 'use strict'; + + if ( !context.content ) { + return; + } + + let {contentObserver} = Components.utils.import( + Components.stack.filename.replace('Script0', 'Module'), + null + ); + + let injectContentScripts = function(win) { + if ( !win || !win.document ) { + return; + } + + contentObserver.observe(win.document); + + if ( win.frames && win.frames.length ) { + let i = win.frames.length; + while ( i-- ) { + injectContentScripts(win.frames[i]); + } + } + }; + + injectContentScripts(context.content); + +})(this); + +/******************************************************************************/ diff --git a/platform/firefox/vapi-background.js b/platform/firefox/vapi-background.js index 39d8e867f..72c187fc6 100644 --- a/platform/firefox/vapi-background.js +++ b/platform/firefox/vapi-background.js @@ -20,7 +20,7 @@ */ /* jshint esnext: true, bitwise: false */ -/* global self, Components, punycode, µBlock */ +/* global punycode */ // For background page @@ -3367,16 +3367,21 @@ vAPI.lastError = function() { // the web pages before uBlock was ready. vAPI.onLoadAllCompleted = function() { + // TODO: vAPI shouldn't know about uBlock. Just like in uMatrix, uBlock + // should collect on its side all the opened tabs whenever it is ready. var µb = µBlock; var tabId; for ( var browser of tabWatcher.browsers() ) { tabId = tabWatcher.tabIdFromTarget(browser); µb.tabContextManager.commit(tabId, browser.currentURI.asciiSpec); µb.bindTabToPageStats(tabId); - browser.messageManager.sendAsyncMessage( - location.host + '-load-completed' - ); } + // Inject special frame script, which sole purpose is to inject + // content scripts into *already* opened tabs. This allows to unclutter + // the main frame script. + vAPI.messaging + .globalMessageManager + .loadFrameScript(vAPI.getURL('frameScript0.js'), false); }; /******************************************************************************/