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

Side by Side Diff: lib/elemHide.js

Issue 29935564: Issue 7452 - Do not cache element hiding filter objects by default Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Created Nov. 3, 2018, 7:54 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/filterListener.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 /** 20 /**
21 * @fileOverview Element hiding implementation. 21 * @fileOverview Element hiding implementation.
22 */ 22 */
23 23
24 const {Filter} = require("./filterClasses");
24 const {ElemHideExceptions} = require("./elemHideExceptions"); 25 const {ElemHideExceptions} = require("./elemHideExceptions");
25 const {filterNotifier} = require("./filterNotifier"); 26 const {filterNotifier} = require("./filterNotifier");
26 27
27 /** 28 /**
28 * The maximum number of selectors in a CSS rule. This is used by 29 * The maximum number of selectors in a CSS rule. This is used by
29 * <code>{@link createStyleSheet}</code> to split up a long list of selectors 30 * <code>{@link createStyleSheet}</code> to split up a long list of selectors
30 * into multiple rules. 31 * into multiple rules.
31 * @const {number} 32 * @const {number}
32 * @default 33 * @default
33 */ 34 */
34 const selectorGroupSize = 1024; 35 const selectorGroupSize = 1024;
35 36
36 /** 37 /**
37 * Lookup table, active flag, by filter by domain. 38 * Lookup table, active flag, by filter by domain.
Manish Jethani 2018/11/03 20:01:25 Throughout this file, "filter" now means filter te
hub 2018/11/22 15:59:33 I'd update the comment to say `by filter text`
Manish Jethani 2018/11/23 02:03:33 Done.
38 * (Only contains filters that aren't unconditionally matched for all domains.) 39 * (Only contains filters that aren't unconditionally matched for all domains.)
39 * @type {Map.<string,Map.<Filter,boolean>>} 40 * @type {Map.<string,Map.<string,boolean>>}
40 */ 41 */
41 let filtersByDomain = new Map(); 42 let filtersByDomain = new Map();
42 43
43 /** 44 /**
44 * Lookup table, filter by selector. (Only used for selectors that are 45 * Lookup table, filter by selector. (Only used for selectors that are
45 * unconditionally matched for all domains.) 46 * unconditionally matched for all domains.)
46 * @type {Map.<string,Filter>} 47 * @type {Map.<string,string>}
47 */ 48 */
48 let filterBySelector = new Map(); 49 let filterBySelector = new Map();
49 50
50 /** 51 /**
51 * This array caches the keys of filterBySelector table (selectors 52 * This array caches the keys of filterBySelector table (selectors
52 * which unconditionally apply on all domains). It will be null if the 53 * which unconditionally apply on all domains). It will be null if the
53 * cache needs to be rebuilt. 54 * cache needs to be rebuilt.
54 * @type {?string[]} 55 * @type {?string[]}
55 */ 56 */
56 let unconditionalSelectors = null; 57 let unconditionalSelectors = null;
(...skipping 16 matching lines...) Expand all
73 74
74 /** 75 /**
75 * Map to be used instead when a filter has a blank domains property. 76 * Map to be used instead when a filter has a blank domains property.
76 * @type {Map.<string,boolean>} 77 * @type {Map.<string,boolean>}
77 * @const 78 * @const
78 */ 79 */
79 let defaultDomains = new Map([["", true]]); 80 let defaultDomains = new Map([["", true]]);
80 81
81 /** 82 /**
82 * Set containing known element hiding filters 83 * Set containing known element hiding filters
83 * @type {Set.<ElemHideFilter>} 84 * @type {Set.<string>}
84 */ 85 */
85 let knownFilters = new Set(); 86 let knownFilters = new Set();
86 87
87 /** 88 /**
88 * All domains known to occur in exceptions 89 * All domains known to occur in exceptions
89 * @type {Set.<string>} 90 * @type {Set.<string>}
90 */ 91 */
91 let knownExceptionDomains = new Set(); 92 let knownExceptionDomains = new Set();
92 93
93 /** 94 /**
(...skipping 23 matching lines...) Expand all
117 { 118 {
118 for (let [domain, isIncluded] of domains || defaultDomains) 119 for (let [domain, isIncluded] of domains || defaultDomains)
119 { 120 {
120 // There's no need to note that a filter is generically disabled. 121 // There's no need to note that a filter is generically disabled.
121 if (!isIncluded && domain == "") 122 if (!isIncluded && domain == "")
122 continue; 123 continue;
123 124
124 let filters = filtersByDomain.get(domain); 125 let filters = filtersByDomain.get(domain);
125 if (!filters) 126 if (!filters)
126 filtersByDomain.set(domain, filters = new Map()); 127 filtersByDomain.set(domain, filters = new Map());
127 filters.set(filter, isIncluded); 128 filters.set(filter.text, isIncluded ? filter.selector : null);
Manish Jethani 2018/11/03 20:01:25 Instead of true/false, we now keep the selector or
128 } 129 }
129 } 130 }
130 131
131 /** 132 /**
132 * Returns a list of selectors that apply on each website unconditionally. 133 * Returns a list of selectors that apply on each website unconditionally.
133 * @returns {string[]} 134 * @returns {string[]}
134 */ 135 */
135 function getUnconditionalSelectors() 136 function getUnconditionalSelectors()
136 { 137 {
137 if (!unconditionalSelectors) 138 if (!unconditionalSelectors)
(...skipping 22 matching lines...) Expand all
160 // This code is a performance hot-spot, which is why we've made certain 161 // This code is a performance hot-spot, which is why we've made certain
161 // micro-optimisations. Please be careful before making changes. 162 // micro-optimisations. Please be careful before making changes.
162 while (true) 163 while (true)
163 { 164 {
164 if (specificOnly && currentDomain == "") 165 if (specificOnly && currentDomain == "")
165 break; 166 break;
166 167
167 let filters = filtersByDomain.get(currentDomain); 168 let filters = filtersByDomain.get(currentDomain);
168 if (filters) 169 if (filters)
169 { 170 {
170 for (let [filter, isIncluded] of filters) 171 for (let [text, selector] of filters)
171 { 172 {
172 if (!isIncluded) 173 if (selector == null)
173 { 174 {
174 excluded.add(filter); 175 excluded.add(text);
175 } 176 }
176 else 177 else if ((excluded.size == 0 || !excluded.has(text)) &&
178 !ElemHideExceptions.getException(selector, domain))
177 { 179 {
178 let {selector} = filter; 180 selectors.push(selector);
179 if ((excluded.size == 0 || !excluded.has(filter)) &&
180 !ElemHideExceptions.getException(selector, domain))
181 {
182 selectors.push(selector);
183 }
184 } 181 }
185 } 182 }
186 } 183 }
187 184
188 if (currentDomain == "") 185 if (currentDomain == "")
189 break; 186 break;
190 187
191 let nextDot = currentDomain.indexOf("."); 188 let nextDot = currentDomain.indexOf(".");
192 currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); 189 currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1);
193 } 190 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 if (domain != "") 233 if (domain != "")
237 knownExceptionDomains.add(domain); 234 knownExceptionDomains.add(domain);
238 } 235 }
239 } 236 }
240 237
241 // If this is the first exception for a previously unconditionally applied 238 // If this is the first exception for a previously unconditionally applied
242 // element hiding selector we need to take care to update the lookups. 239 // element hiding selector we need to take care to update the lookups.
243 let unconditionalFilterForSelector = filterBySelector.get(selector); 240 let unconditionalFilterForSelector = filterBySelector.get(selector);
244 if (unconditionalFilterForSelector) 241 if (unconditionalFilterForSelector)
245 { 242 {
246 addToFiltersByDomain(unconditionalFilterForSelector); 243 addToFiltersByDomain(Filter.fromText(unconditionalFilterForSelector));
Manish Jethani 2018/11/03 20:01:25 This is the one time where we have to get the filt
247 filterBySelector.delete(selector); 244 filterBySelector.delete(selector);
248 unconditionalSelectors = null; 245 unconditionalSelectors = null;
249 defaultStyleSheet = null; 246 defaultStyleSheet = null;
250 } 247 }
251 }); 248 });
252 249
253 /** 250 /**
254 * Container for element hiding filters 251 * Container for element hiding filters
255 * @class 252 * @class
256 */ 253 */
(...skipping 16 matching lines...) Expand all
273 270
274 filterNotifier.emit("elemhideupdate"); 271 filterNotifier.emit("elemhideupdate");
275 }, 272 },
276 273
277 /** 274 /**
278 * Add a new element hiding filter 275 * Add a new element hiding filter
279 * @param {ElemHideFilter} filter 276 * @param {ElemHideFilter} filter
280 */ 277 */
281 add(filter) 278 add(filter)
282 { 279 {
283 if (knownFilters.has(filter)) 280 if (knownFilters.has(filter.text))
284 return; 281 return;
285 282
286 commonStyleSheet = null; 283 commonStyleSheet = null;
287 284
288 let {domains, selector} = filter; 285 let {domains, selector} = filter;
289 286
290 if (!(domains || ElemHideExceptions.hasExceptions(selector))) 287 if (!(domains || ElemHideExceptions.hasExceptions(selector)))
291 { 288 {
292 // The new filter's selector is unconditionally applied to all domains 289 // The new filter's selector is unconditionally applied to all domains
293 filterBySelector.set(selector, filter); 290 filterBySelector.set(selector, filter.text);
294 unconditionalSelectors = null; 291 unconditionalSelectors = null;
295 defaultStyleSheet = null; 292 defaultStyleSheet = null;
296 } 293 }
297 else 294 else
298 { 295 {
299 // The new filter's selector only applies to some domains 296 // The new filter's selector only applies to some domains
300 addToFiltersByDomain(filter, domains); 297 addToFiltersByDomain(filter, domains);
301 } 298 }
302 299
303 knownFilters.add(filter); 300 knownFilters.add(filter.text);
304 filterNotifier.emit("elemhideupdate"); 301 filterNotifier.emit("elemhideupdate");
305 }, 302 },
306 303
307 /** 304 /**
308 * Removes an element hiding filter 305 * Removes an element hiding filter
309 * @param {ElemHideFilter} filter 306 * @param {ElemHideFilter} filter
310 */ 307 */
311 remove(filter) 308 remove(filter)
312 { 309 {
313 if (!knownFilters.has(filter)) 310 if (!knownFilters.has(filter.text))
314 return; 311 return;
315 312
316 commonStyleSheet = null; 313 commonStyleSheet = null;
317 314
318 let {selector} = filter; 315 let {selector} = filter;
319 316
320 // Unconditially applied element hiding filters 317 // Unconditially applied element hiding filters
321 if (filterBySelector.get(selector) == filter) 318 if (filterBySelector.get(selector) == filter.text)
322 { 319 {
323 filterBySelector.delete(selector); 320 filterBySelector.delete(selector);
324 unconditionalSelectors = null; 321 unconditionalSelectors = null;
325 defaultStyleSheet = null; 322 defaultStyleSheet = null;
326 } 323 }
327 // Conditionally applied element hiding filters 324 // Conditionally applied element hiding filters
328 else 325 else
329 { 326 {
330 let domains = filter.domains || defaultDomains; 327 let domains = filter.domains || defaultDomains;
331 for (let domain of domains.keys()) 328 for (let domain of domains.keys())
332 { 329 {
333 let filters = filtersByDomain.get(domain); 330 let filters = filtersByDomain.get(domain);
334 if (filters) 331 if (filters)
335 { 332 {
336 filters.delete(filter); 333 filters.delete(filter.text);
337 334
338 if (filters.size == 0) 335 if (filters.size == 0)
339 filtersByDomain.delete(domain); 336 filtersByDomain.delete(domain);
340 } 337 }
341 } 338 }
342 } 339 }
343 340
344 knownFilters.delete(filter); 341 knownFilters.delete(filter.text);
345 filterNotifier.emit("elemhideupdate"); 342 filterNotifier.emit("elemhideupdate");
346 }, 343 },
347 344
348 /** 345 /**
349 * @typedef {object} ElemHideStyleSheet 346 * @typedef {object} ElemHideStyleSheet
350 * @property {string} code CSS code. 347 * @property {string} code CSS code.
351 * @property {Array.<string>} selectors List of selectors. 348 * @property {Array.<string>} selectors List of selectors.
352 */ 349 */
353 350
354 /** 351 /**
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 { 476 {
480 let styleSheet = ""; 477 let styleSheet = "";
481 478
482 for (let selectorGroup of splitSelectors(selectors)) 479 for (let selectorGroup of splitSelectors(selectors))
483 styleSheet += createRule(selectorGroup); 480 styleSheet += createRule(selectorGroup);
484 481
485 return styleSheet; 482 return styleSheet;
486 } 483 }
487 484
488 exports.createStyleSheet = createStyleSheet; 485 exports.createStyleSheet = createStyleSheet;
OLDNEW
« no previous file with comments | « no previous file | test/filterListener.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld