cosmetic filtering: stop surveying and/or filtering after too many consecutive misses

This commit is contained in:
gorhill 2016-07-12 13:29:30 -04:00
parent 58beeaacc1
commit 9e7fbb857b
2 changed files with 67 additions and 25 deletions

View File

@ -121,6 +121,7 @@ var reParserEx = /^(.*?(:has\(.+?\)|:xpath\(.+?\))?)(:style\(.+?\))?$/;
var allExceptions = Object.create(null);
var allSelectors = Object.create(null);
var stagedNodes = [];
// Complex selectors, due to their nature may need to be "de-committed". A
// Set() is used to implement this functionality.
@ -143,6 +144,7 @@ var cosmeticFiltersActivated = function() {
/******************************************************************************/
var domFilterer = {
commitMissCount: 0,
disabledId: vAPI.randomToken(),
enabled: true,
hiddenId: vAPI.randomToken(),
@ -202,7 +204,6 @@ var domFilterer = {
return this;
}
if ( sel1.lastIndexOf(':xpath',0) === 0 ) {
if ( sel0 !== sel1 ) { return this; }
this.jobQueue.push({ t: 'xpath-hide', raw: s, _0: sel1.slice(7, -1) });
return this;
}
@ -267,14 +268,9 @@ var domFilterer = {
}
},
commit: function(stagedNodes) {
var beforeHiddenNodeCount = this.hiddenNodeCount;
if ( stagedNodes === undefined ) {
stagedNodes = [ document.documentElement ];
}
var styleText = '', i, n;
commit_: function() {
var beforeHiddenNodeCount = this.hiddenNodeCount,
styleText = '', i, n;
// Stock job 0 = css rules/hide
if ( this.job0._0.length ) {
@ -305,6 +301,7 @@ var domFilterer = {
this.runSimpleSelectorJob(this.job2, stagedNodes[i], hideNode);
}
}
stagedNodes = [];
// Complex selectors: non-incremental.
complexSelectorsOldResultSet = complexSelectorsCurrentResultSet;
@ -323,6 +320,13 @@ var domFilterer = {
this.runJob(this.jobQueue[i], complexHideNode);
}
var commitHit = this.hiddenNodeCount !== beforeHiddenNodeCount;
if ( commitHit ) {
this.commitMissCount = 0;
} else {
this.commitMissCount += 1;
}
// Un-hide nodes previously hidden.
i = complexSelectorsOldResultSet.size;
if ( i !== 0 ) {
@ -334,10 +338,7 @@ var domFilterer = {
}
// If DOM nodes have been affected, lazily notify core process.
if (
this.hiddenNodeCount !== beforeHiddenNodeCount &&
cosmeticFiltersActivatedTimer === null
) {
if ( commitHit && cosmeticFiltersActivatedTimer === null ) {
cosmeticFiltersActivatedTimer = vAPI.setTimeout(
cosmeticFiltersActivated,
503
@ -345,20 +346,35 @@ var domFilterer = {
}
},
commit: function(nodes) {
if ( stagedNodes.length === 0 ) {
window.requestAnimationFrame(this.commit_.bind(this));
}
if ( nodes === undefined ) {
stagedNodes = [ document.documentElement ];
} else if ( stagedNodes[0] !== document.documentElement ) {
stagedNodes = stagedNodes.concat(nodes);
}
},
hideNode: function(node) {
if ( node[this.hiddenId] ) {
if ( node[this.hiddenId] !== undefined ) {
return;
}
node.setAttribute(this.hiddenId, '');
node[this.hiddenId] = true;
this.hiddenNodeCount += 1;
node.hidden = true;
// TODO: conditionally make use of `display: none !important;` style.
// - is node.style.display !== ''?
// - if yes, is node.hasAttribute('style') true?
// - if yes: node.setAttribute('style', node.getAttribute('style') +
// ';display: none !important'
// - remember this was done
node[this.hiddenId] = null;
var style = window.getComputedStyle(node),
display = style.getPropertyValue('display');
if ( display !== '' && display !== 'none' ) {
var styleAttr = node.getAttribute('style') || '';
node[this.hiddenId] = node.hasAttribute('style') && styleAttr;
if ( styleAttr !== '' ) {
styleAttr += '; ';
}
node.setAttribute('style', styleAttr + 'display: none !important;');
}
if ( shadowId === undefined ) {
return;
}
@ -452,6 +468,12 @@ var domFilterer = {
showNode: function(node) {
node.hidden = false;
var styleAttr = node[this.hiddenId];
if ( styleAttr === false ) {
node.removeAttribute('style');
} else if ( typeof styleAttr === 'string' ) {
node.setAttribute('style', node[this.hiddenId]);
}
var shadow = node.shadowRoot;
if ( shadow && shadow[shadowId] ) {
if ( shadow.firstElementChild !== null ) {
@ -470,7 +492,7 @@ var domFilterer = {
},
unhideNode: function(node) {
if ( node[this.hiddenId] ) {
if ( node[this.hiddenId] !== undefined ) {
this.hiddenNodeCount--;
}
node.removeAttribute(this.hiddenId);
@ -487,6 +509,12 @@ var domFilterer = {
unshowNode: function(node) {
node.hidden = true;
var styleAttr = node[this.hiddenId];
if ( styleAttr === false ) {
node.setAttribute('style', 'display: none !important;');
} else if ( typeof styleAttr === 'string' ) {
node.setAttribute('style', node[this.hiddenId] + '; display: none !important;');
}
var shadow = node.shadowRoot;
if ( shadow && shadow[shadowId] && shadow.firstElementChild !== null ) {
shadow.removeChild(shadow.firstElementChild);
@ -921,9 +949,10 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
return;
}
var queriedSelectors = Object.create(null),
var cosmeticSurveyingMissCount = 0,
highGenerics = null,
lowGenericSelectors = [];
lowGenericSelectors = [],
queriedSelectors = Object.create(null);
// Handle main process' response.
@ -974,6 +1003,16 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
);
}
// Shutdown surveyor if too many consecutive empty resultsets.
if ( domFilterer.job0._0.length === 0 ) {
cosmeticSurveyingMissCount += 1;
if ( cosmeticSurveyingMissCount > 255 ) {
domSurveyor = undefined;
}
} else {
cosmeticSurveyingMissCount = 0;
}
domFilterer.commit(contextNodes);
contextNodes = [];
@ -1280,6 +1319,9 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
} else {
domFilterer.commit(contextNodes);
contextNodes = [];
if ( domFilterer.commitMissCount > 255 ) {
domLayoutObserver.disconnect();
}
}
}

View File

@ -49,7 +49,7 @@ var isBadRegex = function(s) {
return false;
};
var cosmeticSurveyingMissCountMax = parseInt(vAPI.localStorage.getItem('cosmeticSurveyingMissCountMax'), 10) || 10;
var cosmeticSurveyingMissCountMax = parseInt(vAPI.localStorage.getItem('cosmeticSurveyingMissCountMax'), 10) || 15;
/******************************************************************************/
/*