revise matches-css implementation as per #1930 and https://github.com/uBlockOrigin/uAssets/issues/212

This commit is contained in:
gorhill 2016-12-01 11:55:05 -05:00
parent a6d402aefe
commit 98d2bbada7
2 changed files with 36 additions and 33 deletions

View file

@ -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(),
@ -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);
}
}
@ -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;

View file

@ -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)\(.+?\)$/;
};
/******************************************************************************/
@ -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\([^)]+\)/,