Index: lib/elemHide.js |
=================================================================== |
--- a/lib/elemHide.js |
+++ b/lib/elemHide.js |
@@ -20,16 +20,25 @@ |
/** |
* @fileOverview Element hiding implementation. |
*/ |
const {ElemHideExceptions} = require("./elemHideExceptions"); |
const {filterNotifier} = require("./filterNotifier"); |
/** |
+ * The maximum number of selectors in a CSS rule. This is used by |
+ * <code>{@link createStyleSheet}</code> to split up a long list of selectors |
+ * into multiple rules. |
+ * @const {number} |
+ * @default |
+ */ |
+const selectorGroupSize = 1024; |
+ |
+/** |
* Lookup table, active flag, by filter by domain. |
* (Only contains filters that aren't unconditionally matched for all domains.) |
* @type {Map.<string,Map.<Filter,boolean>>} |
*/ |
let filtersByDomain = new Map(); |
/** |
* Lookup table, filter by selector. (Only used for selectors that are |
@@ -236,8 +245,58 @@ |
} |
if (!specificOnly) |
selectors = getUnconditionalSelectors().concat(selectors); |
return selectors; |
} |
}; |
+ |
+/** |
+ * Splits a list of selectors into groups determined by the value of |
+ * <code>{@link selectorGroupSize}</code>. |
+ * |
+ * @param {Array.<string>} selectors |
+ * @yields {Array.<string>} |
+ */ |
+function* splitSelectors(selectors) |
+{ |
+ // Chromium's Blink engine supports only up to 8,192 simple selectors, and |
+ // even fewer compound selectors, in a rule. The exact number of selectors |
+ // that would work depends on their sizes (e.g. "#foo .bar" has a size of 2). |
+ // Since we don't know the sizes of the selectors here, we simply split them |
+ // into groups of 1,024, based on the reasonable assumption that the average |
+ // selector won't have a size greater than 8. The alternative would be to |
+ // calculate the sizes of the selectors and divide them up accordingly, but |
+ // this approach is more efficient and has worked well in practice. In theory |
+ // this could still lead to some selectors not working on Chromium, but it is |
+ // highly unlikely. |
+ // See issue #6298 and https://crbug.com/804179 |
+ for (let i = 0; i < selectors.length; i += selectorGroupSize) |
+ yield selectors.slice(i, i + selectorGroupSize); |
+} |
+ |
+/** |
+ * Creates element hiding CSS rules for a given list of selectors. Each rule |
+ * contains no more than the maximum number of selectors as determined by the |
+ * value of <code>{@link selectorGroupSize}</code>. |
+ * |
+ * @param {Array.<string>} selectors |
+ * @yields {string} |
+ */ |
+function* createRules(selectors) |
+{ |
+ for (let selectorGroup of splitSelectors(selectors)) |
+ yield selectorGroup.join(", ") + " {display: none !important;}"; |
+} |
+ |
+/** |
+ * Creates an element hiding CSS style sheet from a given list of selectors. |
+ * @param {Array.<string>} selectors |
+ * @returns {string} |
+ */ |
+function createStyleSheet(selectors) |
+{ |
+ return [...createRules(selectors)].join("\n"); |
+} |
+ |
+exports.createStyleSheet = createStyleSheet; |