Skip to content

Instantly share code, notes, and snippets.

@evilpie
Last active August 29, 2015 14:14
Show Gist options
  • Save evilpie/11c26923c67622a6c27f to your computer and use it in GitHub Desktop.
Save evilpie/11c26923c67622a6c27f to your computer and use it in GitHub Desktop.
# HG changeset patch
# Parent c6ae2f78d271f4bd87d8f0efb6086a8a624f0e4b
diff --git a/lib/contentPolicy.js b/lib/contentPolicy.js
--- a/lib/contentPolicy.js
+++ b/lib/contentPolicy.js
@@ -129,73 +129,92 @@ let Policy = exports.Policy =
Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetService.USER_SHEET);
onShutdown.add(function()
{
Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService.USER_SHEET);
})
},
/**
+ * Checks whether a window or its parent is whitelisted or has a valid site-key.
+ * @param wnd {nsIDOMWindow}
+ */
+ shouldNeverBlockWindow: function(wnd)
+ {
+ let topWnd = wnd.top;
+ if (!topWnd || !topWnd.location || !topWnd.location.href)
+ return true;
+
+ let uri = wnd.document.documentURIObject;
+ if (!uri)
+ return true;
+
+ if (!Policy.isBlockableScheme(uri.scheme))
+ return true;
+
+ let [sitekey, sitekeyWnd] = getSitekey(wnd);
+ let testWnd = wnd;
+ let testSitekey = sitekey;
+ let testSitekeyWnd = sitekeyWnd;
+ let parentWndLocation = getWindowLocation(testWnd);
+
+ while (true)
+ {
+ let testWndLocation = parentWndLocation;
+ parentWndLocation = (testWnd == testWnd.parent ? testWndLocation : getWindowLocation(testWnd.parent));
+ match = Policy.isWhitelisted(testWndLocation, parentWndLocation, testSitekey);
+
+ if (match instanceof WhitelistFilter)
+ {
+ FilterStorage.increaseHitCount(match, wnd);
+ RequestNotifier.addNodeData(testWnd.document, topWnd, Policy.type.DOCUMENT, getHostname(parentWndLocation), false, testWndLocation, match);
+ return true;
+ }
+
+ if (testWnd.parent == testWnd)
+ break;
+
+ if (testWnd == testSitekeyWnd)
+ [testSitekey, testSitekeyWnd] = getSitekey(testWnd.parent);
+ testWnd = testWnd.parent;
+ }
+
+ return false;
+ },
+
+ /**
* Checks whether a node should be blocked, hides it if necessary
* @param wnd {nsIDOMWindow}
* @param node {nsIDOMElement}
* @param contentType {String}
* @param location {nsIURI}
* @param collapse {Boolean} true to force hiding of the node
* @return {Boolean} false if the node should be blocked
*/
processNode: function(wnd, node, contentType, location, collapse)
{
- let topWnd = wnd.top;
- if (!topWnd || !topWnd.location || !topWnd.location.href)
+ if (!wnd || Policy.shouldNeverBlockWindow(wnd))
return true;
+ let topWnd = wnd.top;
let originWindow = Utils.getOriginWindow(wnd);
let wndLocation = originWindow.location.href;
let docDomain = getHostname(wndLocation);
- let match = null;
- let [sitekey, sitekeyWnd] = getSitekey(wnd);
- if (!match && Prefs.enabled)
- {
- let testWnd = wnd;
- let testSitekey = sitekey;
- let testSitekeyWnd = sitekeyWnd;
- let parentWndLocation = getWindowLocation(testWnd);
- while (true)
- {
- let testWndLocation = parentWndLocation;
- parentWndLocation = (testWnd == testWnd.parent ? testWndLocation : getWindowLocation(testWnd.parent));
- match = Policy.isWhitelisted(testWndLocation, parentWndLocation, testSitekey);
-
- if (match instanceof WhitelistFilter)
- {
- FilterStorage.increaseHitCount(match, wnd);
- RequestNotifier.addNodeData(testWnd.document, topWnd, Policy.type.DOCUMENT, getHostname(parentWndLocation), false, testWndLocation, match);
- return true;
- }
-
- if (testWnd.parent == testWnd)
- break;
-
- if (testWnd == testSitekeyWnd)
- [testSitekey, testSitekeyWnd] = getSitekey(testWnd.parent);
- testWnd = testWnd.parent;
- }
- }
// Data loaded by plugins should be attached to the document
if (contentType == Policy.type.OBJECT_SUBREQUEST && node instanceof Ci.nsIDOMElement)
node = node.ownerDocument;
// Fix type for objects misrepresented as frames or images
if (contentType != Policy.type.OBJECT && (node instanceof Ci.nsIDOMHTMLObjectElement || node instanceof Ci.nsIDOMHTMLEmbedElement))
contentType = Policy.type.OBJECT;
let locationText = location.spec;
- if (!match && contentType == Policy.type.ELEMHIDE)
+ let match = null;
+ if (contentType == Policy.type.ELEMHIDE)
{
let testWnd = wnd;
let parentWndLocation = getWindowLocation(testWnd);
while (true)
{
let testWndLocation = parentWndLocation;
parentWndLocation = (testWnd == testWnd.parent ? testWndLocation : getWindowLocation(testWnd.parent));
let parentDocDomain = getHostname(parentWndLocation);
@@ -225,17 +244,17 @@ let Policy = exports.Policy =
{
FilterStorage.increaseHitCount(exception, wnd);
RequestNotifier.addNodeData(node, topWnd, contentType, docDomain, false, locationText, exception);
return true;
}
}
let thirdParty = (contentType == Policy.type.ELEMHIDE ? false : isThirdParty(location, docDomain));
-
+ let [sitekey, sitekeyWnd] = getSitekey(wnd);
if (!match && Prefs.enabled)
{
match = defaultMatcher.matchesAny(locationText, Policy.typeDescr[contentType] || "", docDomain, thirdParty, sitekey);
if (match instanceof BlockingFilter && node.ownerDocument && !(contentType in Policy.nonVisual))
{
let prefCollapse = (match.collapse != null ? match.collapse : !Prefs.fastcollapse);
if (collapse || prefCollapse)
schedulePostProcess(node);
diff --git a/lib/elemHide.js b/lib/elemHide.js
--- a/lib/elemHide.js
+++ b/lib/elemHide.js
@@ -22,16 +22,17 @@
Cu.import("resource://gre/modules/Services.jsm");
let {Utils} = require("utils");
let {IO} = require("io");
let {Prefs} = require("prefs");
let {ElemHideException} = require("filterClasses");
let {FilterNotifier} = require("filterNotifier");
let {AboutHandler} = require("elemHideHitRegistration");
+let Poliy = null;
/**
* Lookup table, filters by their associated key
* @type Object
*/
let filterByKey = Object.create(null);
/**
@@ -54,21 +55,35 @@ let exceptions = Object.create(null);
/**
* Currently applied stylesheet URL
* @type nsIURI
*/
let styleURL = null;
/**
+ * Global stylesheet that should be loaded into content windows.
+ * @type nsIStyleSheet
+ */
+let styleSheet = null;
+
+/**
+ * Use the new way of injecting styles per window that exists since Firefox 33.
+ * @type boolean
+ */
+let usePreloading = ('preloadSheet' in Utils.styleService); // XXX Disable when e10s is on
+
+/**
* Element hiding component
* @class
*/
let ElemHide = exports.ElemHide =
{
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
+
/**
* Indicates whether filters have been added or removed since the last apply() call.
* @type Boolean
*/
isDirty: false,
/**
* Inidicates whether the element hiding stylesheet is currently applied.
@@ -76,31 +91,64 @@ let ElemHide = exports.ElemHide =
*/
applied: false,
/**
* Called on module startup.
*/
init: function()
{
+ if (usePreloading) {
+ // Avoid dependency issue.
+ Policy = require("contentPolicy").Policy;
+
+ Services.obs.addObserver(this, "content-document-global-created", true);
+ }
+
Prefs.addListener(function(name)
{
if (name == "enabled")
ElemHide.apply();
});
onShutdown.add(function()
{
ElemHide.unapply();
+
+ if (usePreloading)
+ Services.obs.removeObserver(this, "content-document-global-created");
});
let styleFile = IO.resolveFilePath(Prefs.data_directory);
styleFile.append("elemhide.css");
styleURL = Services.io.newFileURI(styleFile).QueryInterface(Ci.nsIFileURL);
},
+ observe: function (subject, topic, data, additional)
+ {
+ if (topic != "content-document-global-created")
+ return;
+
+ if (!Prefs.enabled || Policy.shouldNeverBlockWindow(subject))
+ return;
+
+ if (styleSheet)
+ {
+ try
+ {
+ let utils = subject.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ utils.addSheet(styleSheet, Ci.nsIStyleSheetService.USER_SHEET);
+ }
+ catch (e)
+ {
+ Cu.reportError(e);
+ }
+ }
+ },
+
/**
* Removes all known filters
*/
clear: function()
{
filterByKey = Object.create(null);
keyByFilter = Object.create(null);
knownExceptions = Object.create(null);
@@ -214,17 +262,21 @@ let ElemHide = exports.ElemHide =
if (!ElemHide.isDirty || !Prefs.enabled)
{
// Nothing changed, looks like we merely got enabled/disabled
if (Prefs.enabled && !ElemHide.applied)
{
try
{
- Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET);
+ if (!usePreloading)
+ Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET);
+ else
+ styleSheet = Utils.styleService.preloadSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET);
+
ElemHide.applied = true;
}
catch (e)
{
Cu.reportError(e);
}
}
else if (!Prefs.enabled && ElemHide.applied)
@@ -339,36 +391,28 @@ let ElemHide = exports.ElemHide =
* Unapplies current stylesheet URL
*/
unapply: function()
{
if (ElemHide.applied)
{
try
{
- Utils.styleService.unregisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET);
+ if (!usePreloading)
+ Utils.styleService.unregisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET);
}
catch (e)
{
Cu.reportError(e);
}
ElemHide.applied = false;
}
},
/**
- * Retrieves the currently applied stylesheet URL
- * @type String
- */
- get styleURL()
- {
- return ElemHide.applied ? styleURL.spec : null;
- },
-
- /**
* Retrieves an element hiding filter by the corresponding protocol key
*/
getFilterByKey: function(/**String*/ key) /**Filter*/
{
return (key in filterByKey ? filterByKey[key] : null);
},
/**
# HG changeset patch
# Parent f3da596345f4c3c1e0906ddb3eb1a3d99a8dd3fa
diff --git a/lib/elemHide.js b/lib/elemHide.js
--- a/lib/elemHide.js
+++ b/lib/elemHide.js
@@ -412,17 +412,21 @@ let ElemHide = exports.ElemHide =
{
// Only allow unqualified rules on a few protocols to prevent them from blocking chrome
yield '@-moz-document url-prefix("http://"),url-prefix("https://"),'
+ 'url-prefix("mailbox://"),url-prefix("imap://"),'
+ 'url-prefix("news://"),url-prefix("snews://"){';
}
for (let selector in list)
- yield selector.replace(/[^\x01-\x7F]/g, escapeChar) + "{" + cssTemplate.replace("%ID%", list[selector]) + "}";
+ yield selector.replace(/[^\x01-\x7F]/g, escapeChar) + ","
+
+ yield ".dummmydummydummy"
+ yield "{ display: none; }";
+
yield '}';
}
},
/**
* Unapplies current stylesheet URL
*/
unapply: function()
# HG changeset patch
# Parent cc45a3b6e343740bcc34288878562f2c2d7793ea
diff --git a/lib/elemHide.js b/lib/elemHide.js
--- a/lib/elemHide.js
+++ b/lib/elemHide.js
@@ -124,16 +124,48 @@ let ElemHide = exports.ElemHide =
observe: function (subject, topic, data, additional)
{
if (topic != "content-document-global-created")
return;
if (!Prefs.enabled || Policy.shouldNeverBlockWindow(subject))
return;
+ let domain = null;
+ let filters = null;
+ try
+ {
+ domain = subject.document.documentURIObject.host;
+ if (domain)
+ filters = ElemHide.getFiltersWithKeyForDomain(domain, true);
+ } catch (e) {}
+
+ if (filters)
+ {
+ let list = Object.create(null);
+ for (let {key, filter} of filters)
+ list[key] = filter;
+
+ let css = "";
+ for (let line in this._generateCSSContent(list, false))
+ css += line + "\n";
+
+ let uri = Services.io.newURI("data:text/css;base64," + btoa(css), null, null);
+ try
+ {
+ let utils = subject.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ utils.loadSheet(uri, Ci.nsIStyleSheetService.USER_SHEET);
+ }
+ catch (e)
+ {
+ Cu.reportError(e);
+ }
+ }
+
if (styleSheet)
{
try
{
let utils = subject.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
utils.addSheet(styleSheet, Ci.nsIStyleSheetService.USER_SHEET);
}
@@ -282,17 +314,17 @@ let ElemHide = exports.ElemHide =
else if (!Prefs.enabled && ElemHide.applied)
{
ElemHide.unapply();
}
return;
}
- IO.writeToFile(styleURL.file, this._generateCSSContent(), function(e)
+ IO.writeToFile(styleURL.file, this._generateCSSContent(filterByKey, usePreloading), function(e)
{
this._applying = false;
// _generateCSSContent is throwing NS_ERROR_NOT_AVAILABLE to indicate that
// there are no filters. If that exception is passed through XPCOM we will
// see a proper exception here, otherwise a number.
let noFilters = (e == Cr.NS_ERROR_NOT_AVAILABLE || (e && e.result == Cr.NS_ERROR_NOT_AVAILABLE));
if (noFilters)
@@ -329,26 +361,29 @@ let ElemHide = exports.ElemHide =
FilterNotifier.triggerListeners("elemhideupdate");
}
}.bind(this));
this._applying = true;
},
- _generateCSSContent: function()
+ _generateCSSContent: function(filters, onlyGlobal)
{
// Grouping selectors by domains
let domains = Object.create(null);
let hasFilters = false;
- for (let key in filterByKey)
+ for (let key in filters)
{
- let filter = filterByKey[key];
+ let filter = filters[key];
let domain = filter.selectorDomain || "";
+ if (onlyGlobal && domain)
+ continue;
+
let list;
if (domain in domains)
list = domains[domain];
else
{
list = Object.create(null);
domains[domain] = list;
}
@@ -427,10 +462,27 @@ let ElemHide = exports.ElemHide =
let filter = filterByKey[key];
if (specificOnly && (!filter.domains || filter.domains[""]))
continue;
if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain))
result.push(filter.selector);
}
return result;
+ },
+
+ getFiltersWithKeyForDomain: function(/**String*/ domain)
+ {
+ let result = [];
+ for (let key in filterByKey)
+ {
+ let filter = filterByKey[key];
+
+ if (!filter.domains)
+ continue
+
+ if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain))
+ result.push({key, filter});
+ }
+ return result;
}
+
};
diff --git a/lib/elemHideHitRegistration.js b/lib/elemHideHitRegistration.js
--- a/lib/elemHideHitRegistration.js
+++ b/lib/elemHideHitRegistration.js
@@ -134,16 +134,18 @@ HitRegistrationChannel.prototype = {
let filter = ElemHide.getFilterByKey(this.key);
if (filter)
{
let wnd = Utils.getRequestWindow(this);
if (wnd && wnd.document && !Policy.processNode(wnd, wnd.document, Policy.type.ELEMHIDE, filter))
data = "<bindings xmlns='http://www.mozilla.org/xbl'/>";
}
+ dump("filter: " + filter + " data: " + data + "\n");
+
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
stream.setData(data, data.length);
return stream;
},
isPending: function()
{
return false;
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment