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,63 @@ |
} |
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)) |
Sebastian Noack
2018/09/18 15:33:24
Since splitSelectors() is only called from one cod
Manish Jethani
2018/09/18 15:50:02
I tried this and it seems to actually perform slig
Sebastian Noack
2018/09/18 16:41:45
V8 optimizes functions regardless of size, however
Manish Jethani
2018/09/18 17:24:07
There is a specific optimization in TurboFan calle
Sebastian Noack
2018/09/18 17:40:54
This appears rather odd to me. On which version of
Manish Jethani
2018/09/18 17:47:46
I did it on Chrome 71 (Canary). It's not going to
Manish Jethani
2018/09/18 19:51:57
Alright, here we go.
The alternative version of t
Sebastian Noack
2018/09/18 21:21:03
I think the main target for any benchmark should a
Manish Jethani
2018/09/19 09:39:00
A lot of the best programmers would disagree that
Manish Jethani
2018/09/19 10:18:33
Since I was modifying the `createStyleSheet` funct
Manish Jethani
2018/09/19 10:29:08
Also: https://arstechnica.com/information-technolo
Sebastian Noack
2018/09/19 11:05:53
I'm obviously not trying to argue that functions s
Manish Jethani
2018/09/19 13:14:41
If they are logically separate (as in, the program
Jon Sonesen
2018/09/19 16:36:26
FWIW I would say that Manish is right about contex
|
+ 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) |
+{ |
+ let styleSheet = ""; |
+ |
+ for (let rule of createRules(selectors)) |
+ styleSheet += rule + "\n"; |
+ |
+ return styleSheet; |
+} |
+ |
+exports.createStyleSheet = createStyleSheet; |