Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: lib/elemHide.js

Issue 29893628: Issue 6957 - Skip selector lookup for unknown domains (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Created Sept. 27, 2018, 10:01 p.m.
Right Patch Set: Rebase Created Sept. 28, 2018, 6 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | test/elemHide.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 let commonStyleSheet = null; 72 let commonStyleSheet = null;
73 73
74 /** 74 /**
75 * Map to be used instead when a filter has a blank domains property. 75 * Map to be used instead when a filter has a blank domains property.
76 * @type {Map.<string,boolean>} 76 * @type {Map.<string,boolean>}
77 * @const 77 * @const
78 */ 78 */
79 let defaultDomains = new Map([["", true]]); 79 let defaultDomains = new Map([["", true]]);
80 80
81 /** 81 /**
82 * Set containing all known domains
83 * @type {Set.<string>}
84 */
85 let knownDomains = new Set();
86
87 /**
88 * Set containing known element hiding filters 82 * Set containing known element hiding filters
89 * @type {Set.<ElemHideFilter>} 83 * @type {Set.<ElemHideFilter>}
90 */ 84 */
91 let knownFilters = new Set(); 85 let knownFilters = new Set();
86
87 /**
88 * All domains known to occur in exceptions
89 * @type {Set.<string>}
90 */
91 let knownExceptionDomains = new Set();
92 92
93 /** 93 /**
94 * Returns the suffix of the given domain that is known. If no suffix is known, 94 * Returns the suffix of the given domain that is known. If no suffix is known,
95 * an empty string is returned. 95 * an empty string is returned.
96 * @param {?string} domain 96 * @param {?string} domain
97 * @returns {string} 97 * @returns {string}
98 */ 98 */
99 function getKnownSuffix(domain) 99 function getKnownSuffix(domain)
100 { 100 {
101 if (domain[domain.length - 1] == ".") 101 while (domain && !filtersByDomain.has(domain) &&
102 domain = domain.replace(/\.+$/, ""); 102 !knownExceptionDomains.has(domain))
103 103 {
104 domain = domain.toLowerCase();
105
106 while (domain)
107 {
108 if (knownDomains.has(domain) || ElemHideExceptions.isKnownDomain(domain))
109 break;
110
111 let index = domain.indexOf("."); 104 let index = domain.indexOf(".");
112 domain = index == -1 ? "" : domain.substring(index + 1); 105 domain = index == -1 ? "" : domain.substring(index + 1);
113 } 106 }
114 107
115 return domain; 108 return domain;
116 } 109 }
117 110
118 /** 111 /**
119 * Adds a filter to the lookup table of filters by domain. 112 * Adds a filter to the lookup table of filters by domain.
120 * @param {Filter} filter 113 * @param {Filter} filter
121 */ 114 */
122 function addToFiltersByDomain(filter) 115 function addToFiltersByDomain(filter)
123 { 116 {
124 let domains = filter.domains || defaultDomains; 117 let domains = filter.domains || defaultDomains;
125 for (let [domain, isIncluded] of domains) 118 for (let [domain, isIncluded] of domains)
126 { 119 {
127 // There's no need to note that a filter is generically disabled. 120 // There's no need to note that a filter is generically disabled.
128 if (domain == "") 121 if (!isIncluded && domain == "")
129 { 122 continue;
130 if (!isIncluded)
131 continue;
132 }
133 else
134 {
135 // Note: Once a domain is known it never becomes unknown, even when all
136 // the filters containing that domain are removed. This is a best-case
137 // optimization.
138 knownDomains.add(domain);
139 }
140 123
141 let filters = filtersByDomain.get(domain); 124 let filters = filtersByDomain.get(domain);
142 if (!filters) 125 if (!filters)
143 filtersByDomain.set(domain, filters = new Map()); 126 filtersByDomain.set(domain, filters = new Map());
144 filters.set(filter, isIncluded); 127 filters.set(filter, isIncluded);
145 } 128 }
146 } 129 }
147 130
148 /** 131 /**
149 * Returns a list of selectors that apply on each website unconditionally. 132 * Returns a list of selectors that apply on each website unconditionally.
150 * @returns {string[]} 133 * @returns {string[]}
151 */ 134 */
152 function getUnconditionalSelectors() 135 function getUnconditionalSelectors()
153 { 136 {
154 if (!unconditionalSelectors) 137 if (!unconditionalSelectors)
155 unconditionalSelectors = [...filterBySelector.keys()]; 138 unconditionalSelectors = [...filterBySelector.keys()];
156 139
157 return unconditionalSelectors; 140 return unconditionalSelectors;
158 } 141 }
159 142
160 /** 143 /**
161 * Returns the list of selectors that apply on a given domain from the subset 144 * Returns the list of selectors that apply on a given domain from the subset
162 * of filters that do not apply unconditionally on all domains. 145 * of filters that do not apply unconditionally on all domains.
163 * 146 *
164 * @param {string} domain The domain. 147 * @param {string} domain The domain.
165 * @param {boolean} [specificOnly=false] Whether selectors from generic filters 148 * @param {boolean} specificOnly Whether selectors from generic filters should
166 * should be included. 149 * be included.
167 * 150 *
168 * @returns {Array.<string>} The list of selectors. 151 * @returns {Array.<string>} The list of selectors.
169 */ 152 */
170 function getConditionalSelectorsForDomain(domain, specificOnly = false) 153 function getConditionalSelectors(domain, specificOnly)
171 { 154 {
172 let selectors = []; 155 let selectors = [];
173 156
174 let excluded = new Set(); 157 let excluded = new Set();
175 let currentDomain = domain; 158 let currentDomain = domain;
176 159
177 // This code is a performance hot-spot, which is why we've made certain 160 // This code is a performance hot-spot, which is why we've made certain
178 // micro-optimisations. Please be careful before making changes. 161 // micro-optimisations. Please be careful before making changes.
179 while (true) 162 while (true)
180 { 163 {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 return defaultStyleSheet; 207 return defaultStyleSheet;
225 } 208 }
226 209
227 /** 210 /**
228 * Returns the common style sheet that applies on all unknown domains. 211 * Returns the common style sheet that applies on all unknown domains.
229 * @returns {string} 212 * @returns {string}
230 */ 213 */
231 function getCommonStyleSheet() 214 function getCommonStyleSheet()
232 { 215 {
233 if (!commonStyleSheet) 216 if (!commonStyleSheet)
217 {
234 commonStyleSheet = getDefaultStyleSheet() + 218 commonStyleSheet = getDefaultStyleSheet() +
235 createStyleSheet(getConditionalSelectorsForDomain("")); 219 createStyleSheet(getConditionalSelectors("", false));
220 }
236 221
237 return commonStyleSheet; 222 return commonStyleSheet;
238 } 223 }
239 224
240 ElemHideExceptions.on("added", ({selector}) => 225 ElemHideExceptions.on("added", ({domains, selector}) =>
241 { 226 {
242 commonStyleSheet = null; 227 commonStyleSheet = null;
228
229 if (domains)
230 {
231 for (let domain of domains.keys())
232 {
233 // Note: Once an exception domain is known it never becomes unknown, even
234 // when all the exceptions containing that domain are removed. This is a
235 // best-case optimization.
236 if (domain != "")
237 knownExceptionDomains.add(domain);
238 }
239 }
243 240
244 // If this is the first exception for a previously unconditionally applied 241 // If this is the first exception for a previously unconditionally applied
245 // element hiding selector we need to take care to update the lookups. 242 // element hiding selector we need to take care to update the lookups.
246 let unconditionalFilterForSelector = filterBySelector.get(selector); 243 let unconditionalFilterForSelector = filterBySelector.get(selector);
247 if (unconditionalFilterForSelector) 244 if (unconditionalFilterForSelector)
248 { 245 {
249 addToFiltersByDomain(unconditionalFilterForSelector); 246 addToFiltersByDomain(unconditionalFilterForSelector);
250 filterBySelector.delete(selector); 247 filterBySelector.delete(selector);
251 unconditionalSelectors = null; 248 unconditionalSelectors = null;
252 defaultStyleSheet = null; 249 defaultStyleSheet = null;
253 } 250 }
254 }); 251 });
255 252
256 /** 253 /**
257 * Container for element hiding filters 254 * Container for element hiding filters
258 * @class 255 * @class
259 */ 256 */
260 exports.ElemHide = { 257 exports.ElemHide = {
261 /** 258 /**
262 * Removes all known filters 259 * Removes all known filters
263 */ 260 */
264 clear() 261 clear()
265 { 262 {
266 commonStyleSheet = null; 263 commonStyleSheet = null;
267 264
268 for (let collection of [filtersByDomain, filterBySelector, knownDomains, 265 for (let collection of [filtersByDomain, filterBySelector, knownFilters,
269 knownFilters]) 266 knownExceptionDomains])
267 {
270 collection.clear(); 268 collection.clear();
269 }
271 270
272 unconditionalSelectors = null; 271 unconditionalSelectors = null;
273 defaultStyleSheet = null; 272 defaultStyleSheet = null;
274 273
275 filterNotifier.emit("elemhideupdate"); 274 filterNotifier.emit("elemhideupdate");
276 }, 275 },
277 276
278 /** 277 /**
279 * Add a new element hiding filter 278 * Add a new element hiding filter
280 * @param {ElemHideFilter} filter 279 * @param {ElemHideFilter} filter
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 * @property {Array.<string>} selectors List of selectors. 351 * @property {Array.<string>} selectors List of selectors.
353 */ 352 */
354 353
355 /** 354 /**
356 * Generates a style sheet for a given domain based on the current set of 355 * Generates a style sheet for a given domain based on the current set of
357 * filters. 356 * filters.
358 * 357 *
359 * @param {string} domain The domain. 358 * @param {string} domain The domain.
360 * @param {boolean} [specificOnly=false] Whether selectors from generic 359 * @param {boolean} [specificOnly=false] Whether selectors from generic
361 * filters should be included. 360 * filters should be included.
362 * @param {boolean} [includeSelectors=true] Whether the return value should 361 * @param {boolean} [includeSelectors=false] Whether the return value should
363 * include a separate list of selectors. 362 * include a separate list of selectors.
364 * 363 *
365 * @returns {ElemHideStyleSheet} An object containing the CSS code and the 364 * @returns {ElemHideStyleSheet} An object containing the CSS code and the
366 * list of selectors. 365 * list of selectors.
367 */ 366 */
368 generateStyleSheetForDomain(domain, specificOnly = false, 367 generateStyleSheetForDomain(domain, specificOnly = false,
369 includeSelectors = true) 368 includeSelectors = false)
370 { 369 {
371 let knownSuffix = domain ? getKnownSuffix(domain) : ""; 370 let code = null;
372 371 let selectors = null;
373 let selectors = []; 372
374 if (includeSelectors || knownSuffix != "") 373 if (domain[domain.length - 1] == ".")
375 selectors = getConditionalSelectorsForDomain(knownSuffix, specificOnly); 374 domain = domain.replace(/\.+$/, "");
376 375
377 let code = specificOnly ? createStyleSheet(selectors) : 376 domain = domain.toLowerCase();
378 knownSuffix == "" ? getCommonStyleSheet() : 377
379 (getDefaultStyleSheet() + createStyleSheet(selectors)); 378 if (specificOnly)
380 379 {
381 if (includeSelectors && !specificOnly) 380 selectors = getConditionalSelectors(domain, true);
382 selectors = getUnconditionalSelectors().concat(selectors); 381 code = createStyleSheet(selectors);
382 }
383 else
384 {
385 let knownSuffix = getKnownSuffix(domain);
386
387 if (includeSelectors)
388 {
389 selectors = getConditionalSelectors(knownSuffix, false);
390 code = knownSuffix == "" ? getCommonStyleSheet() :
391 (getDefaultStyleSheet() + createStyleSheet(selectors));
392
393 selectors = getUnconditionalSelectors().concat(selectors);
394 }
395 else
396 {
397 code = knownSuffix == "" ? getCommonStyleSheet() :
398 (getDefaultStyleSheet() +
399 createStyleSheet(getConditionalSelectors(knownSuffix,
400 false)));
401 }
402 }
383 403
384 return {code, selectors: includeSelectors ? selectors : null}; 404 return {code, selectors: includeSelectors ? selectors : null};
385 } 405 }
386 }; 406 };
387 407
388 /** 408 /**
389 * Splits a list of selectors into groups determined by the value of 409 * Splits a list of selectors into groups determined by the value of
390 * <code>{@link selectorGroupSize}</code>. 410 * <code>{@link selectorGroupSize}</code>.
391 * 411 *
392 * @param {Array.<string>} selectors 412 * @param {Array.<string>} selectors
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 { 456 {
437 let styleSheet = ""; 457 let styleSheet = "";
438 458
439 for (let selectorGroup of splitSelectors(selectors)) 459 for (let selectorGroup of splitSelectors(selectors))
440 styleSheet += createRule(selectorGroup); 460 styleSheet += createRule(selectorGroup);
441 461
442 return styleSheet; 462 return styleSheet;
443 } 463 }
444 464
445 exports.createStyleSheet = createStyleSheet; 465 exports.createStyleSheet = createStyleSheet;
LEFTRIGHT
« no previous file | test/elemHide.js » ('j') | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld