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

Delta Between Two Patch Sets: lib/elemHide.js

Issue 29893618: Issue 6957 - Return common style sheet for unknown domains (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Created Sept. 27, 2018, 9:18 p.m.
Right Patch Set: Slightly refactored Created Sept. 28, 2018, 3:50 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 | no next file » | 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) 101 while (domain && !filtersByDomain.has(domain) &&
102 return ""; 102 !knownExceptionDomains.has(domain))
103 103 {
104 if (domain[domain.length - 1] == ".")
105 domain = domain.replace(/\.+$/, "");
106
107 domain = domain.toLowerCase();
108
109 while (domain)
110 {
111 if (knownDomains.has(domain) || ElemHideExceptions.isKnownDomain(domain))
112 break;
113
114 let index = domain.indexOf("."); 104 let index = domain.indexOf(".");
115 domain = index == -1 ? "" : domain.substring(index + 1); 105 domain = index == -1 ? "" : domain.substring(index + 1);
116 } 106 }
117 107
118 return domain; 108 return domain;
119 } 109 }
120 110
121 /** 111 /**
122 * Adds a filter to the lookup table of filters by domain. 112 * Adds a filter to the lookup table of filters by domain.
123 * @param {Filter} filter 113 * @param {Filter} filter
124 */ 114 */
125 function addToFiltersByDomain(filter) 115 function addToFiltersByDomain(filter)
126 { 116 {
127 let domains = filter.domains || defaultDomains; 117 let domains = filter.domains || defaultDomains;
128 for (let [domain, isIncluded] of domains) 118 for (let [domain, isIncluded] of domains)
129 { 119 {
130 // 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.
131 if (domain == "") 121 if (!isIncluded && domain == "")
132 { 122 continue;
133 if (!isIncluded)
134 continue;
135 }
136 else
137 {
138 // Note: Once a domain is known it never becomes unknown, even when all
139 // the filters containing that domain are removed. This is a best-case
140 // optimization.
141 knownDomains.add(domain);
142 }
143 123
144 let filters = filtersByDomain.get(domain); 124 let filters = filtersByDomain.get(domain);
145 if (!filters) 125 if (!filters)
146 filtersByDomain.set(domain, filters = new Map()); 126 filtersByDomain.set(domain, filters = new Map());
147 filters.set(filter, isIncluded); 127 filters.set(filter, isIncluded);
148 } 128 }
149 } 129 }
150 130
151 /** 131 /**
152 * Returns a list of selectors that apply on each website unconditionally. 132 * Returns a list of selectors that apply on each website unconditionally.
153 * @returns {string[]} 133 * @returns {string[]}
154 */ 134 */
155 function getUnconditionalSelectors() 135 function getUnconditionalSelectors()
156 { 136 {
157 if (!unconditionalSelectors) 137 if (!unconditionalSelectors)
158 unconditionalSelectors = [...filterBySelector.keys()]; 138 unconditionalSelectors = [...filterBySelector.keys()];
159 139
160 return unconditionalSelectors; 140 return unconditionalSelectors;
161 } 141 }
162 142
163 /** 143 /**
164 * 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
165 * of filters that do not apply unconditionally on all domains. 145 * of filters that do not apply unconditionally on all domains.
166 * 146 *
167 * @param {string} domain The domain. 147 * @param {string} domain The domain.
168 * @param {boolean} [specificOnly=false] Whether selectors from generic filters 148 * @param {boolean} specificOnly Whether selectors from generic filters should
169 * should be included. 149 * be included.
170 * 150 *
171 * @returns {Array.<string>} The list of selectors. 151 * @returns {Array.<string>} The list of selectors.
172 */ 152 */
173 function getConditionalSelectorsForDomain(domain, specificOnly = false) 153 function getConditionalSelectors(domain, specificOnly)
174 { 154 {
175 let selectors = []; 155 let selectors = [];
176 156
177 let excluded = new Set(); 157 let excluded = new Set();
178 let currentDomain = domain; 158 let currentDomain = domain;
179 159
180 // 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
181 // micro-optimisations. Please be careful before making changes. 161 // micro-optimisations. Please be careful before making changes.
182 while (true) 162 while (true)
183 { 163 {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 */ 201 */
222 function getDefaultStyleSheet() 202 function getDefaultStyleSheet()
223 { 203 {
224 if (!defaultStyleSheet) 204 if (!defaultStyleSheet)
225 defaultStyleSheet = createStyleSheet(getUnconditionalSelectors()); 205 defaultStyleSheet = createStyleSheet(getUnconditionalSelectors());
226 206
227 return defaultStyleSheet; 207 return defaultStyleSheet;
228 } 208 }
229 209
230 /** 210 /**
231 * Returns the default style sheet that applies on all unknown domains. 211 * Returns the common style sheet that applies on all unknown domains.
232 * @returns {string} 212 * @returns {string}
233 */ 213 */
234 function getCommonStyleSheet() 214 function getCommonStyleSheet()
235 { 215 {
236 if (!commonStyleSheet) 216 if (!commonStyleSheet)
217 {
237 commonStyleSheet = getDefaultStyleSheet() + 218 commonStyleSheet = getDefaultStyleSheet() +
238 createStyleSheet(getConditionalSelectorsForDomain("")); 219 createStyleSheet(getConditionalSelectors("", false));
220 }
239 221
240 return commonStyleSheet; 222 return commonStyleSheet;
241 } 223 }
242 224
243 ElemHideExceptions.on("added", ({selector}) => 225 ElemHideExceptions.on("added", ({domains, selector}) =>
244 { 226 {
245 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 }
246 240
247 // If this is the first exception for a previously unconditionally applied 241 // If this is the first exception for a previously unconditionally applied
248 // 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.
249 let unconditionalFilterForSelector = filterBySelector.get(selector); 243 let unconditionalFilterForSelector = filterBySelector.get(selector);
250 if (unconditionalFilterForSelector) 244 if (unconditionalFilterForSelector)
251 { 245 {
252 addToFiltersByDomain(unconditionalFilterForSelector); 246 addToFiltersByDomain(unconditionalFilterForSelector);
253 filterBySelector.delete(selector); 247 filterBySelector.delete(selector);
254 unconditionalSelectors = null; 248 unconditionalSelectors = null;
255 defaultStyleSheet = null; 249 defaultStyleSheet = null;
256 } 250 }
257 }); 251 });
258 252
259 /** 253 /**
260 * Container for element hiding filters 254 * Container for element hiding filters
261 * @class 255 * @class
262 */ 256 */
263 exports.ElemHide = { 257 exports.ElemHide = {
264 /** 258 /**
265 * Removes all known filters 259 * Removes all known filters
266 */ 260 */
267 clear() 261 clear()
268 { 262 {
269 commonStyleSheet = null; 263 commonStyleSheet = null;
270 264
271 for (let collection of [filtersByDomain, filterBySelector, knownDomains, 265 for (let collection of [filtersByDomain, filterBySelector, knownFilters,
272 knownFilters]) 266 knownExceptionDomains])
267 {
273 collection.clear(); 268 collection.clear();
269 }
274 270
275 unconditionalSelectors = null; 271 unconditionalSelectors = null;
276 defaultStyleSheet = null; 272 defaultStyleSheet = null;
277 273
278 filterNotifier.emit("elemhideupdate"); 274 filterNotifier.emit("elemhideupdate");
279 }, 275 },
280 276
281 /** 277 /**
282 * Add a new element hiding filter 278 * Add a new element hiding filter
283 * @param {ElemHideFilter} filter 279 * @param {ElemHideFilter} filter
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 * 357 *
362 * @param {string} domain The domain. 358 * @param {string} domain The domain.
363 * @param {boolean} [specificOnly=false] Whether selectors from generic 359 * @param {boolean} [specificOnly=false] Whether selectors from generic
364 * filters should be included. 360 * filters should be included.
365 * 361 *
366 * @returns {ElemHideStyleSheet} An object containing the CSS code and the 362 * @returns {ElemHideStyleSheet} An object containing the CSS code and the
367 * list of selectors. 363 * list of selectors.
368 */ 364 */
369 generateStyleSheetForDomain(domain, specificOnly = false) 365 generateStyleSheetForDomain(domain, specificOnly = false)
370 { 366 {
371 let knownSuffix = getKnownSuffix(domain); 367 let code = null;
372 368 let selectors = null;
373 let selectors = getConditionalSelectorsForDomain(knownSuffix, specificOnly); 369
374 let code = specificOnly ? createStyleSheet(selectors) : 370 if (domain[domain.length - 1] == ".")
375 knownSuffix == "" ? getCommonStyleSheet() : 371 domain = domain.replace(/\.+$/, "");
376 (getDefaultStyleSheet() + createStyleSheet(selectors)); 372
377 373 domain = domain.toLowerCase();
378 if (!specificOnly) 374
375 if (specificOnly)
376 {
377 selectors = getConditionalSelectors(domain, true);
378 code = createStyleSheet(selectors);
379 }
380 else
381 {
382 let knownSuffix = getKnownSuffix(domain);
383
384 selectors = getConditionalSelectors(knownSuffix, false);
385 code = knownSuffix == "" ? getCommonStyleSheet() :
386 (getDefaultStyleSheet() + createStyleSheet(selectors));
387
379 selectors = getUnconditionalSelectors().concat(selectors); 388 selectors = getUnconditionalSelectors().concat(selectors);
389 }
380 390
381 return {code, selectors}; 391 return {code, selectors};
382 } 392 }
383 }; 393 };
384 394
385 /** 395 /**
386 * Splits a list of selectors into groups determined by the value of 396 * Splits a list of selectors into groups determined by the value of
387 * <code>{@link selectorGroupSize}</code>. 397 * <code>{@link selectorGroupSize}</code>.
388 * 398 *
389 * @param {Array.<string>} selectors 399 * @param {Array.<string>} selectors
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 { 443 {
434 let styleSheet = ""; 444 let styleSheet = "";
435 445
436 for (let selectorGroup of splitSelectors(selectors)) 446 for (let selectorGroup of splitSelectors(selectors))
437 styleSheet += createRule(selectorGroup); 447 styleSheet += createRule(selectorGroup);
438 448
439 return styleSheet; 449 return styleSheet;
440 } 450 }
441 451
442 exports.createStyleSheet = createStyleSheet; 452 exports.createStyleSheet = createStyleSheet;
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld