Skip to content

Commit

Permalink
revise matches-css implementation as per #1930 and uBlockOrigin/uAsse…
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhill committed Dec 1, 2016
1 parent a6d402a commit 98d2bba
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 33 deletions.
65 changes: 34 additions & 31 deletions src/js/contentscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ var jobQueue = [
{ t: 'css-csel', _0: [] } // to manually hide (not incremental)
];

var reParserEx = /:(?:matches-css|has|style|xpath)\(.+?\)$/;
var reParserEx = /:(?:has|matches-css|matches-css-before|matches-css-after|style|xpath)\(.+?\)$/;

var allExceptions = createSet(),
allSelectors = createSet(),
Expand Down Expand Up @@ -201,48 +201,45 @@ var runHasJob = function(job, fn) {
}
};

var csspropDictFromString = function(s) {
var aa = s.split(/;\s+|;$/),
i = aa.length,
dict = Object.create(null),
prop, pos;
while ( i-- ) {
prop = aa[i].trim();
if ( prop === '' ) { continue; }
pos = prop.indexOf(':');
if ( pos === -1 ) { continue; }
dict[prop.slice(0, pos).trim()] = prop.slice(pos + 1).trim();
// '/' = ascii 0x2F */

var parseMatchesCSSJob = function(raw) {
var prop = raw.trim();
if ( prop === '' ) { return null; }
var pos = prop.indexOf(':'),
v = pos !== -1 ? prop.slice(pos + 1).trim() : '',
vlen = v.length;
if (
vlen > 1 &&
v.charCodeAt(0) === 0x2F &&
v.charCodeAt(vlen-1) === 0x2F
) {
try { v = new RegExp(v.slice(1, -1)); } catch(ex) { return null; }
}
return dict;
return { k: prop.slice(0, pos).trim(), v: v };
};

var runMatchesCSSJob = function(job, fn) {
if ( job._2 === undefined ) {
if ( job._0.indexOf(':after', job._0.length - 6) !== -1 ) {
job._0 = job._0.slice(0, -6);
job._2 = ':after';
} else {
job._2 = null;
}
}
var nodes = document.querySelectorAll(job._0),
i = nodes.length;
if ( i === 0 ) { return; }
if ( typeof job._1 === 'string' ) {
job._1 = csspropDictFromString(job._1);
job._1 = parseMatchesCSSJob(job._1);
}
var node, match, style;
if ( job._1 === null ) { return; }
var k = job._1.k,
v = job._1.v,
node, style, match;
while ( i-- ) {
node = nodes[i];
style = window.getComputedStyle(node, job._2);
match = undefined;
for ( var prop in job._1 ) {
match = style[prop] === job._1[prop];
if ( match === false ) {
break;
}
if ( style === null ) { continue; } /* FF */
if ( v instanceof RegExp ) {
match = v.test(style[k]);
} else {
match = style[k] === v;
}
if ( match === true ) {
if ( match ) {
fn(node, job);
}
}
Expand Down Expand Up @@ -332,7 +329,13 @@ var domFilterer = {
if ( sel1.lastIndexOf(':has', 0) === 0 ) {
this.jobQueue.push({ t: 'has-hide', raw: s, _0: sel0, _1: sel1.slice(5, -1) });
} else if ( sel1.lastIndexOf(':matches-css', 0) === 0 ) {
this.jobQueue.push({ t: 'matches-css-hide', raw: s, _0: sel0, _1: sel1.slice(13, -1) });
if ( sel1.lastIndexOf(':matches-css-before', 0) === 0 ) {
this.jobQueue.push({ t: 'matches-css-hide', raw: s, _0: sel0, _1: sel1.slice(20, -1), _2: ':before' });
} else if ( sel1.lastIndexOf(':matches-css-after', 0) === 0 ) {
this.jobQueue.push({ t: 'matches-css-hide', raw: s, _0: sel0, _1: sel1.slice(19, -1), _2: ':after' });
} else {
this.jobQueue.push({ t: 'matches-css-hide', raw: s, _0: sel0, _1: sel1.slice(13, -1), _2: null });
}
} else if ( sel1.lastIndexOf(':style', 0) === 0 ) {
this.job1._0.push(sel0 + ' { ' + sel1.slice(7, -1) + ' }');
this.job1._1 = undefined;
Expand Down
4 changes: 2 additions & 2 deletions src/js/cosmetic-filtering.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ var FilterParser = function() {
this.hostnames = [];
this.invalid = false;
this.cosmetic = true;
this.reNeedHostname = /^(?:script:contains|script:inject|.+?:has|.+?:matches-css|:xpath)\(.+?\)$/;
this.reNeedHostname = /^(?:script:contains|script:inject|.+?:has|.+?:matches-css(?:-before|-after)?|:xpath)\(.+?\)$/;
};

/******************************************************************************/
Expand Down Expand Up @@ -721,7 +721,7 @@ FilterContainer.prototype.isValidSelector = (function() {
}

var reHasSelector = /^(.+?):has\((.+?)\)$/,
reMatchesCSSSelector = /^(.+?):matches-css\((.+?)\)$/,
reMatchesCSSSelector = /^(.+?):matches-css(?:-before|-after)?\((.+?)\)$/,
reXpathSelector = /^:xpath\((.+?)\)$/,
reStyleSelector = /^(.+?):style\((.+?)\)$/,
reStyleBad = /url\([^)]+\)/,
Expand Down

0 comments on commit 98d2bba

Please sign in to comment.