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

Delta Between Two Patch Sets: lib/content/elemHideEmulation.js

Issue 29760699: Issue 6619 - Qualify CSS selectors in document style sheet correctly (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Created April 24, 2018, 7:14 p.m.
Right Patch Set: Reinclude test/common.js Created May 15, 2018, 5:18 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 | « lib/common.js ('k') | test/common.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 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 } 170 }
171 return all ? subtree.querySelectorAll(selector) : 171 return all ? subtree.querySelectorAll(selector) :
172 subtree.querySelector(selector); 172 subtree.querySelector(selector);
173 } 173 }
174 174
175 function scopedQuerySelectorAll(subtree, selector) 175 function scopedQuerySelectorAll(subtree, selector)
176 { 176 {
177 return scopedQuerySelector(subtree, selector, true); 177 return scopedQuerySelector(subtree, selector, true);
178 } 178 }
179 179
180 const regexpRegexp = /^\/(.*)\/([im]*)$/; 180 const regexpRegexp = /^\/(.*)\/([imu]*)$/;
181 181
182 /** 182 /**
183 * Make a regular expression from a text argument. If it can be parsed as a 183 * Make a regular expression from a text argument. If it can be parsed as a
184 * regular expression, parse it and the flags. 184 * regular expression, parse it and the flags.
185 * @param {string} text the text argument. 185 * @param {string} text the text argument.
186 * @return {?RegExp} a RegExp object or null in case of error. 186 * @return {?RegExp} a RegExp object or null in case of error.
187 */ 187 */
188 function makeRegExpParameter(text) 188 function makeRegExpParameter(text)
189 { 189 {
190 let [, pattern, flags] = 190 let [, pattern, flags] =
(...skipping 27 matching lines...) Expand all
218 // Just in case the getSelectors() generator above had to run some heavy 218 // Just in case the getSelectors() generator above had to run some heavy
219 // document.querySelectorAll() call which didn't produce any results, make 219 // document.querySelectorAll() call which didn't produce any results, make
220 // sure there is at least one point where execution can pause. 220 // sure there is at least one point where execution can pause.
221 yield null; 221 yield null;
222 } 222 }
223 223
224 function PlainSelector(selector) 224 function PlainSelector(selector)
225 { 225 {
226 this._selector = selector; 226 this._selector = selector;
227 this.maybeDependsOnAttributes = /[#.]|\[.+\]/.test(selector); 227 this.maybeDependsOnAttributes = /[#.]|\[.+\]/.test(selector);
228 this.dependsOnDOM = this.maybeDependsOnAttributes;
228 } 229 }
229 230
230 PlainSelector.prototype = { 231 PlainSelector.prototype = {
231 /** 232 /**
232 * Generator function returning a pair of selector 233 * Generator function returning a pair of selector
233 * string and subtree. 234 * string and subtree.
234 * @param {string} prefix the prefix for the selector. 235 * @param {string} prefix the prefix for the selector.
235 * @param {Node} subtree the subtree we work on. 236 * @param {Node} subtree the subtree we work on.
236 * @param {StringifiedStyle[]} styles the stringified style objects. 237 * @param {StringifiedStyle[]} styles the stringified style objects.
237 */ 238 */
238 *getSelectors(prefix, subtree, styles) 239 *getSelectors(prefix, subtree, styles)
239 { 240 {
240 yield [prefix + this._selector, subtree]; 241 yield [prefix + this._selector, subtree];
241 } 242 }
242 }; 243 };
243 244
244 const incompletePrefixRegexp = /[\s>+~]$/; 245 const incompletePrefixRegexp = /[\s>+~]$/;
245 246
246 function HasSelector(selectors) 247 function HasSelector(selectors)
247 { 248 {
248 this._innerSelectors = selectors; 249 this._innerSelectors = selectors;
249 } 250 }
250 251
251 HasSelector.prototype = { 252 HasSelector.prototype = {
252 requiresHiding: true,
253 dependsOnDOM: true, 253 dependsOnDOM: true,
254 254
255 get dependsOnStyles() 255 get dependsOnStyles()
256 { 256 {
257 return this._innerSelectors.some(selector => selector.dependsOnStyles); 257 return this._innerSelectors.some(selector => selector.dependsOnStyles);
258 }, 258 },
259 259
260 get dependsOnCharacterData() 260 get dependsOnCharacterData()
261 { 261 {
262 return this._innerSelectors.some( 262 return this._innerSelectors.some(
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 } 305 }
306 } 306 }
307 }; 307 };
308 308
309 function ContainsSelector(textContent) 309 function ContainsSelector(textContent)
310 { 310 {
311 this._regexp = makeRegExpParameter(textContent); 311 this._regexp = makeRegExpParameter(textContent);
312 } 312 }
313 313
314 ContainsSelector.prototype = { 314 ContainsSelector.prototype = {
315 requiresHiding: true,
316 dependsOnDOM: true, 315 dependsOnDOM: true,
317 dependsOnCharacterData: true, 316 dependsOnCharacterData: true,
318 317
319 *getSelectors(prefix, subtree, styles) 318 *getSelectors(prefix, subtree, styles)
320 { 319 {
321 for (let element of this.getElements(prefix, subtree, styles)) 320 for (let element of this.getElements(prefix, subtree, styles))
322 yield [makeSelector(element), subtree]; 321 yield [makeSelector(element), subtree];
323 }, 322 },
324 323
325 *getElements(prefix, subtree, styles) 324 *getElements(prefix, subtree, styles)
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 regexpString = propertyExpression.slice(1, -1) 362 regexpString = propertyExpression.slice(1, -1)
364 .replace("\\7B ", "{").replace("\\7D ", "}"); 363 .replace("\\7B ", "{").replace("\\7D ", "}");
365 } 364 }
366 else 365 else
367 regexpString = filterToRegExp(propertyExpression); 366 regexpString = filterToRegExp(propertyExpression);
368 367
369 this._regexp = new RegExp(regexpString, "i"); 368 this._regexp = new RegExp(regexpString, "i");
370 } 369 }
371 370
372 PropsSelector.prototype = { 371 PropsSelector.prototype = {
373 preferHideWithSelector: true,
374 dependsOnStyles: true, 372 dependsOnStyles: true,
375 373
376 *findPropsSelectors(styles, prefix, regexp) 374 *findPropsSelectors(styles, prefix, regexp)
377 { 375 {
378 for (let style of styles) 376 for (let style of styles)
379 if (regexp.test(style.style)) 377 if (regexp.test(style.style))
380 for (let subSelector of style.subSelectors) 378 for (let subSelector of style.subSelectors)
381 { 379 {
382 if (subSelector.startsWith("*") && 380 if (subSelector.startsWith("*") &&
383 !incompletePrefixRegexp.test(prefix)) 381 !incompletePrefixRegexp.test(prefix))
(...skipping 14 matching lines...) Expand all
398 } 396 }
399 }; 397 };
400 398
401 function Pattern(selectors, text) 399 function Pattern(selectors, text)
402 { 400 {
403 this.selectors = selectors; 401 this.selectors = selectors;
404 this.text = text; 402 this.text = text;
405 } 403 }
406 404
407 Pattern.prototype = { 405 Pattern.prototype = {
408 isSelectorHidingOnlyPattern()
409 {
410 return getCachedPropertyValue(
411 this, "_selectorHidingOnlyPattern",
412 () => this.selectors.some(selector => selector.preferHideWithSelector) &&
413 !this.selectors.some(selector => selector.requiresHiding)
414 );
415 },
416
417 get dependsOnStyles() 406 get dependsOnStyles()
418 { 407 {
419 return getCachedPropertyValue( 408 return getCachedPropertyValue(
420 this, "_dependsOnStyles", 409 this, "_dependsOnStyles",
421 () => this.selectors.some(selector => selector.dependsOnStyles) 410 () => this.selectors.some(selector => selector.dependsOnStyles)
422 ); 411 );
423 }, 412 },
424 413
425 get dependsOnDOM() 414 get dependsOnDOM()
426 { 415 {
(...skipping 30 matching lines...) Expand all
457 }, 446 },
458 447
459 get dependsOnCharacterData() 448 get dependsOnCharacterData()
460 { 449 {
461 // Observe changes to character data only if there's a contains selector in 450 // Observe changes to character data only if there's a contains selector in
462 // one of the patterns. 451 // one of the patterns.
463 return getCachedPropertyValue( 452 return getCachedPropertyValue(
464 this, "_dependsOnCharacterData", 453 this, "_dependsOnCharacterData",
465 () => this.selectors.some(selector => selector.dependsOnCharacterData) 454 () => this.selectors.some(selector => selector.dependsOnCharacterData)
466 ); 455 );
456 },
457
458 matchesMutationTypes(mutationTypes)
459 {
460 let mutationTypeMatchMap = getCachedPropertyValue(
461 this, "_mutationTypeMatchMap",
462 () => new Map([
463 // All types of DOM-dependent patterns are affected by mutations of
464 // type "childList".
465 ["childList", true],
466 ["attributes", this.maybeDependsOnAttributes],
467 ["characterData", this.dependsOnCharacterData]
468 ])
469 );
470
471 for (let mutationType of mutationTypes)
472 {
473 if (mutationTypeMatchMap.get(mutationType))
474 return true;
475 }
476
477 return false;
467 } 478 }
468 }; 479 };
480
481 function extractMutationTypes(mutations)
482 {
483 let types = new Set();
484
485 for (let mutation of mutations)
486 {
487 types.add(mutation.type);
488
489 // There are only 3 types of mutations: "attributes", "characterData", and
490 // "childList".
491 if (types.size == 3)
492 break;
493 }
494
495 return types;
496 }
469 497
470 function filterPatterns(patterns, {stylesheets, mutations}) 498 function filterPatterns(patterns, {stylesheets, mutations})
471 { 499 {
472 if (!stylesheets && !mutations) 500 if (!stylesheets && !mutations)
473 return patterns.slice(); 501 return patterns.slice();
474 502
503 let mutationTypes = mutations ? extractMutationTypes(mutations) : null;
504
475 return patterns.filter( 505 return patterns.filter(
476 pattern => (stylesheets && pattern.dependsOnStyles) || 506 pattern => (stylesheets && pattern.dependsOnStyles) ||
477 (mutations && pattern.dependsOnDOM) 507 (mutations && pattern.dependsOnDOM &&
508 pattern.matchesMutationTypes(mutationTypes))
478 ); 509 );
479 } 510 }
480 511
481 function shouldObserveAttributes(patterns) 512 function shouldObserveAttributes(patterns)
482 { 513 {
483 return patterns.some(pattern => pattern.maybeDependsOnAttributes); 514 return patterns.some(pattern => pattern.maybeDependsOnAttributes);
484 } 515 }
485 516
486 function shouldObserveCharacterData(patterns) 517 function shouldObserveCharacterData(patterns)
487 { 518 {
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 701
671 pattern = patterns.shift(); 702 pattern = patterns.shift();
672 703
673 generator = evaluate(pattern.selectors, 0, "", 704 generator = evaluate(pattern.selectors, 0, "",
674 this.document, cssStyles); 705 this.document, cssStyles);
675 } 706 }
676 for (let selector of generator) 707 for (let selector of generator)
677 { 708 {
678 if (selector != null) 709 if (selector != null)
679 { 710 {
680 if (!this.useInlineStyles || 711 if (!this.useInlineStyles)
681 pattern.isSelectorHidingOnlyPattern())
682 { 712 {
683 selectors.push(selector); 713 selectors.push(selector);
684 selectorFilters.push(pattern.text); 714 selectorFilters.push(pattern.text);
685 } 715 }
686 else 716 else
687 { 717 {
688 for (let element of this.document.querySelectorAll(selector)) 718 for (let element of this.document.querySelectorAll(selector))
689 { 719 {
690 elements.push(element); 720 elements.push(element);
691 elementFilters.push(pattern.text); 721 elementFilters.push(pattern.text);
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 characterData: shouldObserveCharacterData(this.patterns), 866 characterData: shouldObserveCharacterData(this.patterns),
837 subtree: true 867 subtree: true
838 } 868 }
839 ); 869 );
840 this.document.addEventListener("load", this.onLoad.bind(this), true); 870 this.document.addEventListener("load", this.onLoad.bind(this), true);
841 } 871 }
842 } 872 }
843 }; 873 };
844 874
845 exports.ElemHideEmulation = ElemHideEmulation; 875 exports.ElemHideEmulation = ElemHideEmulation;
LEFTRIGHT

Powered by Google App Engine
This is Rietveld