diff options
Diffstat (limited to 'data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js')
-rw-r--r-- | data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js | 444 |
1 files changed, 0 insertions, 444 deletions
diff --git a/data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js b/data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js deleted file mode 100644 index fc6d314..0000000 --- a/data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js +++ /dev/null @@ -1,444 +0,0 @@ -/* - * This file is part of Adblock Plus <https://adblockplus.org/>, - * Copyright (C) 2006-2017 eyeo GmbH - * - * Adblock Plus is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. - * - * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * @fileOverview Stores Adblock Plus data to be attached to a window. - */ -let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); - -let {port} = require("messaging"); -let {Utils} = require("utils"); -let {Flasher} = require("child/flasher"); - -let nodeData = new WeakMap(); -let windowStats = new WeakMap(); -let windowData = new WeakMap(); -let requestEntryMaxId = 0; - -/** - * Active RequestNotifier instances by their ID - * @type Map.<number,RequestNotifier> - */ -let notifiers = new Map(); - -port.on("startWindowScan", onStartScan); -port.on("shutdownNotifier", onNotifierShutdown); -port.on("flashNodes", onFlashNodes); -port.on("retrieveNodeSize", onRetrieveNodeSize); -port.on("storeNodesForEntries", onStoreNodes); -port.on("retrieveWindowStats", onRetrieveWindowStats); -port.on("storeWindowData", onStoreWindowData); -port.on("retrieveWindowData", onRetrieveWindowData); - -function onStartScan({notifierID, outerWindowID}) -{ - let window = Services.wm.getOuterWindowWithId(outerWindowID); - if (window) - new RequestNotifier(window, notifierID); -} - -function onNotifierShutdown(notifierID) -{ - let notifier = notifiers.get(notifierID); - if (notifier) - notifier.shutdown(); -} - -function onFlashNodes({notifierID, requests, scrollToItem}) -{ - let notifier = notifiers.get(notifierID); - if (notifier) - notifier.flashNodes(requests, scrollToItem); -} - -function onRetrieveNodeSize({notifierID, requests}) -{ - let notifier = notifiers.get(notifierID); - if (notifier) - return notifier.retrieveNodeSize(requests); -} - -function onStoreNodes({notifierID, requests}) -{ - let notifier = notifiers.get(notifierID); - if (notifier) - return notifier.storeNodesForEntries(requests); -} - -function onRetrieveWindowStats(outerWindowID) -{ - let window = Services.wm.getOuterWindowWithId(outerWindowID); - if (window) - return RequestNotifier.getWindowStatistics(window); -} - -function onStoreWindowData({outerWindowID, data}) -{ - let window = Services.wm.getOuterWindowWithId(outerWindowID); - if (window) - windowData.set(window.document, data); -}; - -function onRetrieveWindowData(outerWindowID) -{ - let window = Services.wm.getOuterWindowWithId(outerWindowID); - if (window) - return windowData.get(window.document) || null; -}; - -/** - * Creates a notifier object for a particular window. After creation the window - * will first be scanned for previously saved requests. Once that scan is - * complete only new requests for this window will be reported. - * @param {Window} window window to attach the notifier to - * @param {Integer} notifierID Parent notifier ID to be messaged - */ -function RequestNotifier(window, notifierID) -{ - this.window = window; - this.id = notifierID; - notifiers.set(this.id, this); - this.nodes = new Map(); - this.startScan(window); -} -exports.RequestNotifier = RequestNotifier; - -RequestNotifier.prototype = -{ - /** - * Parent notifier ID to be messaged - * @type Integer - */ - id: null, - - /** - * The window this notifier is associated with. - * @type Window - */ - window: null, - - /** - * Nodes associated with a particular request ID. - * @type Map.<number,Node> - */ - nodes: null, - - /** - * Shuts down the notifier once it is no longer used. The listener - * will no longer be called after that. - */ - shutdown: function() - { - delete this.window; - delete this.nodes; - this.stopFlashing(); - notifiers.delete(this.id); - }, - - /** - * Notifies the parent about a new request. - * @param {Node} node DOM node that the request is associated with - * @param {Object} entry - */ - notifyListener: function(node, entry) - { - if (this.nodes) - this.nodes.set(entry.id, node); - port.emit("foundNodeData", { - notifierID: this.id, - data: entry - }); - }, - - onComplete: function() - { - port.emit("scanComplete", this.id); - }, - - /** - * Number of currently posted scan events (will be 0 when the scan finishes - * running). - */ - eventsPosted: 0, - - /** - * Starts the initial scan of the window (will recurse into frames). - * @param {Window} wnd the window to be scanned - */ - startScan: function(wnd) - { - let doc = wnd.document; - let walker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, null, false); - - let process = function() - { - // Don't do anything if the notifier was shut down already. - if (!this.window) - return; - - let node = walker.currentNode; - let data = nodeData.get(node); - if (typeof data != "undefined") - for (let k in data) - this.notifyListener(node, data[k]); - - if (walker.nextNode()) - Utils.runAsync(process); - else - { - // Done with the current window, start the scan for its frames - for (let i = 0; i < wnd.frames.length; i++) - this.startScan(wnd.frames[i]); - - this.eventsPosted--; - if (!this.eventsPosted) - { - this.scanComplete = true; - this.onComplete(); - } - } - }.bind(this); - - // Process each node in a separate event to allow other events to process - this.eventsPosted++; - Utils.runAsync(process); - }, - - /** - * Makes the nodes associated with the given requests blink. - * @param {number[]} requests list of request IDs that were previously - * reported by this notifier. - * @param {boolean} scrollToItem if true, scroll to first node - */ - flashNodes: function(requests, scrollToItem) - { - this.stopFlashing(); - - let nodes = []; - for (let id of requests) - { - if (!this.nodes.has(id)) - continue; - - let node = this.nodes.get(id); - if (Cu.isDeadWrapper(node)) - this.nodes.delete(node); - else if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) - nodes.push(node); - } - if (nodes.length) - this.flasher = new Flasher(nodes, scrollToItem); - }, - - /** - * Stops flashing nodes after a previous flashNodes() call. - */ - stopFlashing: function() - { - if (this.flasher) - this.flasher.stop(); - this.flasher = null; - }, - - /** - * Attempts to calculate the size of the nodes associated with the requests. - * @param {number[]} requests list of request IDs that were previously - * reported by this notifier. - * @return {number[]|null} either an array containing width and height or - * null if the size could not be calculated. - */ - retrieveNodeSize: function(requests) - { - function getNodeSize(node) - { - if (node instanceof Ci.nsIDOMHTMLImageElement && (node.naturalWidth || node.naturalHeight)) - return [node.naturalWidth, node.naturalHeight]; - else if (node instanceof Ci.nsIDOMHTMLElement && (node.offsetWidth || node.offsetHeight)) - return [node.offsetWidth, node.offsetHeight]; - else - return null; - } - - let size = null; - for (let id of requests) - { - if (!this.nodes.has(id)) - continue; - - let node = this.nodes.get(id); - if (Cu.isDeadWrapper(node)) - this.nodes.delete(node); - else - { - size = getNodeSize(node); - if (size) - break; - } - } - return size; - }, - - /** - * Stores the nodes associated with the requests and generates a unique ID - * for them that can be used with Policy.refilterNodes(). - * @param {number[]} requests list of request IDs that were previously - * reported by this notifier. - * @return {string} unique identifiers associated with the nodes. - */ - storeNodesForEntries: function(requests) - { - let nodes = []; - for (let id of requests) - { - if (!this.nodes.has(id)) - continue; - - let node = this.nodes.get(id); - if (Cu.isDeadWrapper(node)) - this.nodes.delete(node); - else - nodes.push(node); - } - - let {storeNodes} = require("child/contentPolicy"); - return storeNodes(nodes); - } -}; - -/** - * Attaches request data to a DOM node. - * @param {Node} node node to attach data to - * @param {Window} topWnd top-level window the node belongs to - * @param {Object} hitData - * @param {String} hitData.contentType request type, e.g. "IMAGE" - * @param {String} hitData.docDomain domain of the document that initiated the request - * @param {Boolean} hitData.thirdParty will be true if a third-party server has been requested - * @param {String} hitData.location the address that has been requested - * @param {String} hitData.filter filter applied to the request or null if none - * @param {String} hitData.filterType type of filter applied to the request - */ -RequestNotifier.addNodeData = function(node, topWnd, {contentType, docDomain, thirdParty, location, filter, filterType}) -{ - let entry = { - id: ++requestEntryMaxId, - type: contentType, - docDomain, thirdParty, location, filter - }; - - let existingData = nodeData.get(node); - if (typeof existingData == "undefined") - { - existingData = {}; - nodeData.set(node, existingData); - } - - // Add this request to the node data - existingData[contentType + " " + location] = entry; - - // Update window statistics - if (!windowStats.has(topWnd.document)) - { - windowStats.set(topWnd.document, { - items: 0, - hidden: 0, - blocked: 0, - whitelisted: 0, - filters: {} - }); - } - - let stats = windowStats.get(topWnd.document); - if (filterType != "elemhide" && filterType != "elemhideexception" && filterType != "elemhideemulation") - stats.items++; - if (filter) - { - if (filterType == "blocking") - stats.blocked++; - else if (filterType == "whitelist" || filterType == "elemhideexception") - stats.whitelisted++; - else if (filterType == "elemhide" || filterType == "elemhideemulation") - stats.hidden++; - - if (filter in stats.filters) - stats.filters[filter]++; - else - stats.filters[filter] = 1; - } - - // Notify listeners - for (let notifier of notifiers.values()) - if (!notifier.window || notifier.window == topWnd) - notifier.notifyListener(node, entry); -} - -/** - * Retrieves the statistics for a window. - * @return {Object} Object with the properties items, blocked, whitelisted, hidden, filters containing statistics for the window (might be null) - */ -RequestNotifier.getWindowStatistics = function(/**Window*/ wnd) -{ - if (windowStats.has(wnd.document)) - return windowStats.get(wnd.document); - else - return null; -} - -/** - * Retrieves the request data associated with a DOM node. - * @param {Node} node - * @param {Boolean} noParent if missing or false, the search will extend to the parent nodes until one is found that has data associated with it - * @param {Integer} [type] request type to be looking for - * @param {String} [location] request location to be looking for - * @result {[Node, Object]} - * @static - */ -RequestNotifier.getDataForNode = function(node, noParent, type, location) -{ - while (node) - { - let data = nodeData.get(node); - if (typeof data != "undefined") - { - let entry = null; - // Look for matching entry - for (let k in data) - { - if ((!entry || entry.id < data[k].id) && - (typeof type == "undefined" || data[k].type == type) && - (typeof location == "undefined" || data[k].location == location)) - { - entry = data[k]; - } - } - if (entry) - return [node, entry]; - } - - // If we don't have any match on this node then maybe its parent will do - if ((typeof noParent != "boolean" || !noParent) && - node.parentNode instanceof Ci.nsIDOMElement) - { - node = node.parentNode; - } - else - { - node = null; - } - } - - return null; -}; |