gorhill 2017-10-23 12:21:37 -04:00
parent 6e18829f02
commit a76f5b15ac
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
5 changed files with 143 additions and 119 deletions

View File

@ -91,8 +91,6 @@ vAPI.DOMFilterer = function() {
this.commitTimer = new vAPI.SafeAnimationFrame(this.commitNow.bind(this));
this.domIsReady = document.readyState !== 'loading';
this.listeners = [];
this.hideNodeAttr = vAPI.randomToken();
this.hideNodeStylesheet = false;
this.excludedNodeSet = new WeakSet();
this.addedNodes = new Set();
this.removedNodes = false;
@ -119,8 +117,6 @@ vAPI.DOMFilterer = function() {
};
vAPI.DOMFilterer.prototype = {
reHideStyle: /^display:none!important;$/,
// https://www.w3.org/community/webed/wiki/CSS/Selectors#Combinators
reCSSCombinators: /[ >+~]/,
@ -136,27 +132,27 @@ vAPI.DOMFilterer.prototype = {
// Filterset changed.
if ( this.addedSpecificSimpleHide.length !== 0 ) {
console.time('specific simple filterset changed');
console.log('added %d specific simple selectors', this.addedSpecificSimpleHide.length);
//console.time('specific simple filterset changed');
//console.log('added %d specific simple selectors', this.addedSpecificSimpleHide.length);
nodes = document.querySelectorAll(this.addedSpecificSimpleHide.join(','));
for ( node of nodes ) {
this.hideNode(node);
}
this.addedSpecificSimpleHide = [];
this.specificSimpleHideAggregated = undefined;
console.timeEnd('specific simple filterset changed');
//console.timeEnd('specific simple filterset changed');
}
if ( this.addedSpecificComplexHide.length !== 0 ) {
console.time('specific complex filterset changed');
console.log('added %d specific complex selectors', this.addedSpecificComplexHide.length);
//console.time('specific complex filterset changed');
//console.log('added %d specific complex selectors', this.addedSpecificComplexHide.length);
nodes = document.querySelectorAll(this.addedSpecificComplexHide.join(','));
for ( node of nodes ) {
this.hideNode(node);
}
this.addedSpecificComplexHide = [];
this.specificComplexHideAggregated = undefined;
console.timeEnd('specific complex filterset changed');
//console.timeEnd('specific complex filterset changed');
}
// DOM layout changed.
@ -168,10 +164,10 @@ vAPI.DOMFilterer.prototype = {
return;
}
console.log('%d nodes added', this.addedNodes.size);
//console.log('%d nodes added', this.addedNodes.size);
if ( this.specificSimpleHide.size !== 0 && domNodesAdded ) {
console.time('dom layout changed/specific simple selectors');
//console.time('dom layout changed/specific simple selectors');
if ( this.specificSimpleHideAggregated === undefined ) {
this.specificSimpleHideAggregated =
Array.from(this.specificSimpleHide).join(',\n');
@ -185,11 +181,11 @@ vAPI.DOMFilterer.prototype = {
this.hideNode(node);
}
}
console.timeEnd('dom layout changed/specific simple selectors');
//console.timeEnd('dom layout changed/specific simple selectors');
}
if ( this.specificComplexHide.size !== 0 && domLayoutChanged ) {
console.time('dom layout changed/specific complex selectors');
//console.time('dom layout changed/specific complex selectors');
if ( this.specificComplexHideAggregated === undefined ) {
this.specificComplexHideAggregated =
Array.from(this.specificComplexHide).join(',\n');
@ -198,7 +194,7 @@ vAPI.DOMFilterer.prototype = {
for ( node of nodes ) {
this.hideNode(node);
}
console.timeEnd('dom layout changed/specific complex selectors');
//console.timeEnd('dom layout changed/specific complex selectors');
}
this.addedNodes.clear();
@ -228,7 +224,7 @@ vAPI.DOMFilterer.prototype = {
this.commit();
this.triggerListeners('declarative', selectorsStr);
if ( this.reHideStyle.test(declarations) === false ) {
if ( declarations !== 'display:none!important;' ) {
this.specificOthers.push({
selectors: selectorsStr,
declarations: declarations
@ -381,8 +377,8 @@ vAPI.DOMFilterer.prototype = {
new vAPI.SafeAnimationFrame(this.hideNodeBatchProcess.bind(this));
this.hiddenNodeObserver =
new MutationObserver(this.hideNodeObserverHandler.bind(this));
if ( this.hideNodeStylesheet === false ) {
this.hideNodeStylesheet = true;
if ( this.hideNodeStyleSheetInjected === false ) {
this.hideNodeStyleSheetInjected = true;
vAPI.userStylesheet.add(
'[' + this.hideNodeAttr + ']\n{display:none!important;}'
);
@ -400,7 +396,9 @@ vAPI.DOMFilterer.prototype = {
hideNode: function(node) {
if ( this.excludedNodeSet.has(node) ) { return; }
if ( this.hideNodeAttr === undefined ) { return; }
if ( this.hiddenNodeset.has(node) ) { return; }
node.hidden = true;
this.hiddenNodeset.add(node);
if ( this.hideNodeExpando === undefined ) { this.hideNodeInit(); }
node.setAttribute(this.hideNodeAttr, '');
@ -416,6 +414,7 @@ vAPI.DOMFilterer.prototype = {
unhideNode: function(node) {
if ( this.hiddenNodeset.has(node) === false ) { return; }
node.hidden = false;
node.removeAttribute(this.hideNodeAttr);
this.hiddenNodesetToProcess.delete(node);
if ( this.hideNodeExpando === undefined ) { return; }
@ -430,6 +429,7 @@ vAPI.DOMFilterer.prototype = {
},
showNode: function(node) {
node.hidden = false;
var attr = node[this.hideNodeExpando];
if ( attr === false ) {
node.removeAttribute('style');
@ -439,6 +439,7 @@ vAPI.DOMFilterer.prototype = {
},
unshowNode: function(node) {
node.hidden = true;
this.hiddenNodesetToProcess.add(node);
},

View File

@ -61,8 +61,6 @@ vAPI.DOMFilterer = function() {
this.disabled = false;
this.listeners = [];
this.filterset = new Set();
this.hideNodeId = vAPI.randomToken();
this.hideNodeStylesheet = false;
this.excludedNodeSet = new WeakSet();
this.addedCSSRules = new Set();
@ -123,7 +121,6 @@ vAPI.DOMFilterer.prototype = {
selectors: selectorsStr,
declarations,
lazy: details.lazy === true,
internal: details.internal === true,
injected: details.injected === true
};
this.addedCSSRules.add(entry);
@ -167,19 +164,20 @@ vAPI.DOMFilterer.prototype = {
hideNode: function(node) {
if ( this.excludedNodeSet.has(node) ) { return; }
node.setAttribute(this.hideNodeId, '');
if ( this.hideNodeStylesheet === false ) {
this.hideNodeStylesheet = true;
if ( this.hideNodeAttr === undefined ) { return; }
node.setAttribute(this.hideNodeAttr, '');
if ( this.hideNodeStyleSheetInjected === false ) {
this.hideNodeStyleSheetInjected = true;
this.addCSSRule(
'[' + this.hideNodeId + ']',
'display:none!important;',
{ internal: true }
'[' + this.hideNodeAttr + ']',
'display:none!important;'
);
}
},
unhideNode: function(node) {
node.removeAttribute(this.hideNodeId);
if ( this.hideNodeAttr === undefined ) { return; }
node.removeAttribute(this.hideNodeAttr);
},
toggle: function(state) {
@ -204,7 +202,12 @@ vAPI.DOMFilterer.prototype = {
if ( all === false && entry.internal ) { continue; }
selectors.push(entry.selectors);
}
return selectors.join(',\n');
var out = selectors.join(',\n');
if ( !all && this.hideNodeAttr !== undefined ) {
out = out.replace('[' + this.hideNodeAttr + ']', '')
.replace(/^,\n|\n,|,\n$/, '');
}
return out;
},
getFilteredElementCount: function() {

View File

@ -156,7 +156,7 @@ vAPI.domWatcher = (function() {
safeObserverHandlerTimer;
var safeObserverHandler = function() {
console.time('dom watcher/safe observer handler');
//console.time('dom watcher/safe observer handler');
safeObserverHandlerTimer.clear();
var i = addedNodeLists.length,
j = addedNodes.length,
@ -184,7 +184,7 @@ vAPI.domWatcher = (function() {
}
}
removedNodeLists.length = 0;
console.timeEnd('dom watcher/safe observer handler');
//console.timeEnd('dom watcher/safe observer handler');
if ( addedNodes.length === 0 && removedNodes === false ) { return; }
for ( var listener of getListenerIterator() ) {
listener.onDOMChanged(addedNodes, removedNodes);
@ -196,7 +196,7 @@ vAPI.domWatcher = (function() {
// https://github.com/chrisaljoudi/uBlock/issues/205
// Do not handle added node directly from within mutation observer.
var observerHandler = function(mutations) {
console.time('dom watcher/observer handler');
//console.time('dom watcher/observer handler');
var nodeList, mutation,
i = mutations.length;
while ( i-- ) {
@ -214,7 +214,7 @@ vAPI.domWatcher = (function() {
if ( addedNodeLists.length !== 0 || removedNodes ) {
safeObserverHandlerTimer.start();
}
console.timeEnd('dom watcher/observer handler');
//console.timeEnd('dom watcher/observer handler');
};
var startMutationObserver = function() {
@ -557,7 +557,7 @@ vAPI.DOMFilterer = (function() {
entry, nodes, i, node;
if ( this.addedSelectors.size !== 0 ) {
console.time('procedural filterset changed');
//console.time('procedural filterset changed');
for ( entry of this.addedSelectors ) {
nodes = entry[1].exec();
i = nodes.length;
@ -568,11 +568,11 @@ vAPI.DOMFilterer = (function() {
}
}
this.addedSelectors.clear();
console.timeEnd('procedural filterset changed');
//console.timeEnd('procedural filterset changed');
return;
}
console.time('dom layout changed/procedural selectors');
//console.time('dom layout changed/procedural selectors');
this.addedNodes = this.removedNodes = false;
@ -608,7 +608,7 @@ vAPI.DOMFilterer = (function() {
this.currentResultset = afterResultset;
console.timeEnd('dom layout changed/procedural selectors');
//console.timeEnd('dom layout changed/procedural selectors');
},
createProceduralFilter: function(o) {
@ -617,7 +617,7 @@ vAPI.DOMFilterer = (function() {
onDOMCreated: function() {
this.domIsReady = true;
this.domFilterer.commit();
this.domFilterer.commitNow();
},
onDOMChanged: function(addedNodes, removedNodes) {
@ -634,6 +634,8 @@ vAPI.DOMFilterer = (function() {
DOMFiltererBase.call(this);
this.exceptions = [];
this.proceduralFilterer = new DOMProceduralFilterer(this);
this.hideNodeAttr = undefined;
this.hideNodeStyleSheetInjected = false;
// May or may not exist: cache locally since this may be called often.
this.baseOnDOMChanged = DOMFiltererBase.prototype.onDOMChanged;
@ -1084,7 +1086,7 @@ vAPI.domSurveyor = (function() {
// http://jsperf.com/enumerate-classes/6
var surveyPhase1 = function() {
console.time('dom surveyor/surveying');
//console.time('dom surveyor/surveying');
surveyTimer.clear();
var t0 = window.performance.now();
var rews = reWhitespace,
@ -1145,7 +1147,7 @@ vAPI.domSurveyor = (function() {
} else {
surveyPhase3(null);
}
console.timeEnd('dom surveyor/surveying');
//console.timeEnd('dom surveyor/surveying');
};
var reWhitespace = /\s/;
@ -1164,16 +1166,16 @@ vAPI.domSurveyor = (function() {
}
return;
}
console.time('dom surveyor/dom layout created');
//console.time('dom surveyor/dom layout created');
domFilterer = vAPI.domFilterer;
addChunk(pendingIdNodes, document.querySelectorAll('[id]'));
addChunk(pendingClassNodes, document.querySelectorAll('[class]'));
surveyTimer.start();
console.timeEnd('dom surveyor/dom layout created');
//console.timeEnd('dom surveyor/dom layout created');
},
onDOMChanged: function(addedNodes) {
if ( addedNodes.length === 0 ) { return; }
console.time('dom surveyor/dom layout changed');
//console.time('dom surveyor/dom layout changed');
var idNodes = [], iid = 0,
classNodes = [], iclass = 0;
var i = addedNodes.length,
@ -1199,7 +1201,7 @@ vAPI.domSurveyor = (function() {
addChunk(pendingClassNodes, classNodes);
surveyTimer.start(1);
}
console.timeEnd('dom surveyor/dom layout changed');
//console.timeEnd('dom surveyor/dom layout changed');
}
};
@ -1274,8 +1276,6 @@ vAPI.domSurveyor = (function() {
return;
}
var injected = cfeDetails.rulesInjected === true;
if ( response.noCosmeticFiltering ) {
vAPI.domFilterer = null;
vAPI.domSurveyor = null;
@ -1285,27 +1285,34 @@ vAPI.domSurveyor = (function() {
vAPI.domSurveyor = null;
}
domFilterer.exceptions = cfeDetails.exceptionFilters;
domFilterer.hideNodeAttr = cfeDetails.hideNodeAttr;
domFilterer.hideNodeStyleSheetInjected =
cfeDetails.hideNodeStyleSheetInjected === true;
domFilterer.addCSSRule(
cfeDetails.declarativeFilters,
'display:none!important;',
{ injected: injected }
'display:none!important;'
);
domFilterer.addCSSRule(
cfeDetails.highGenericHideSimple,
'display:none!important;',
{ type: 'simple', lazy: true, injected: injected }
{ type: 'simple', lazy: true }
);
domFilterer.addCSSRule(
cfeDetails.highGenericHideComplex,
'display:none!important;',
{ type: 'complex', lazy: true, injected: injected }
{ type: 'complex', lazy: true }
);
domFilterer.addCSSRule(
cfeDetails.injectedHideFilters,
'display:none!important;',
{ injected: true }
);
domFilterer.addProceduralSelectors(cfeDetails.proceduralFilters);
}
if ( cfeDetails.netFilters.length !== 0 && injected !== true ) {
if ( cfeDetails.networkFilters.length !== 0 ) {
vAPI.userStylesheet.add(
cfeDetails.netFilters + '\n{display:none!important;}');
cfeDetails.networkFilters + '\n{display:none!important;}');
}
vAPI.userStylesheet.apply();

View File

@ -1887,11 +1887,63 @@ FilterContainer.prototype.pruneSelectorCacheAsync = function() {
/******************************************************************************/
FilterContainer.prototype.randomAlphaToken = function() {
return String.fromCharCode(Date.now() % 26 + 97) +
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
};
/******************************************************************************/
FilterContainer.prototype.injectRules = function(target, data) {
if (
target instanceof Object === false ||
target.tab instanceof Object === false ||
typeof target.frameId !== 'number'
) {
return;
}
var details = {
code: '',
cssOrigin: 'user',
frameId: target.frameId,
runAt: 'document_start'
};
var injectedHideFilters = [];
if ( data.declarativeFilters.length !== 0 ) {
injectedHideFilters.push(data.declarativeFilters.join(',\n'));
data.declarativeFilters = [];
}
if ( data.proceduralFilters.length !== 0 ) {
injectedHideFilters.push('[' + data.hideNodeAttr + ']');
data.hideNodeStyleSheetInjected = true;
}
if ( data.highGenericHideSimple.length !== 0 ) {
injectedHideFilters.push(data.highGenericHideSimple);
data.highGenericHideSimple = '';
}
if ( data.highGenericHideComplex.length !== 0 ) {
injectedHideFilters.push(data.highGenericHideComplex);
data.highGenericHideComplex = '';
}
data.injectedHideFilters = injectedHideFilters.join(',\n');
if ( data.injectedHideFilters.length !== 0 ) {
details.code = data.injectedHideFilters + '\n{display:none!important;}';
vAPI.insertCSS(target.tab.id, details);
}
if ( data.networkFilters.length !== 0 ) {
details.code = data.networkFilters + '\n{display:none!important;}';
vAPI.insertCSS(target.tab.id, details);
data.networkFilters = '';
}
};
/******************************************************************************/
FilterContainer.prototype.retrieveGenericSelectors = function(request) {
if ( this.acceptedCount === 0 ) { return; }
if ( !request.ids && !request.classes ) { return; }
console.time('cosmeticFilteringEngine.retrieveGenericSelectors');
//console.time('cosmeticFilteringEngine.retrieveGenericSelectors');
var simpleSelectors = this.setRegister0,
complexSelectors = this.setRegister1;
@ -1959,33 +2011,13 @@ FilterContainer.prototype.retrieveGenericSelectors = function(request) {
this.setRegister0.clear();
this.setRegister1.clear();
console.timeEnd('cosmeticFilteringEngine.retrieveGenericSelectors');
//console.timeEnd('cosmeticFilteringEngine.retrieveGenericSelectors');
return out;
};
/******************************************************************************/
FilterContainer.prototype.injectHideRules = function(
tabId,
frameId,
selectors,
runAt
) {
var details = {
code: '',
cssOrigin: 'user',
frameId: frameId,
runAt: runAt
};
for ( var selector of selectors ) {
details.code = selector + '\n{display:none!important;}';
vAPI.insertCSS(tabId, details);
}
};
/******************************************************************************/
FilterContainer.prototype.retrieveDomainSelectors = function(
request,
sender,
@ -1993,7 +2025,7 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
) {
if ( !request.locationURL ) { return; }
console.time('cosmeticFilteringEngine.retrieveDomainSelectors');
//console.time('cosmeticFilteringEngine.retrieveDomainSelectors');
// TODO: consider using MRUCache to quickly lookup all the previously
// looked-up data.
@ -2015,15 +2047,17 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
ready: this.frozen,
domain: domain,
entity: entity,
noDOMSurveying: this.hasGenericHide === false,
declarativeFilters: [],
exceptionFilters: [],
hideNodeAttr: this.randomAlphaToken(),
hideNodeStyleSheetInjected: false,
highGenericSimple: '',
highGenericComplex: '',
netFilters: '',
injectedHideFilters: '',
networkFilters: '',
noDOMSurveying: this.hasGenericHide === false,
proceduralFilters: [],
scripts: undefined,
rulesInjected: false
scripts: undefined
};
if ( options.noCosmeticFiltering !== true ) {
@ -2041,30 +2075,23 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
if ( (bucket = this.specificFilters.get('!' + domainHash)) ) {
bucket.retrieve(hostname, exceptionSet);
}
if ( (bucket = this.proceduralFilters.get('!' + domainHash)) ) {
bucket.retrieve(hostname, exceptionSet);
}
// Specific entity-based exception cosmetic filters.
if ( entityHash !== undefined ) {
if ( (bucket = this.specificFilters.get('!' + entityHash)) ) {
bucket.retrieve(entity, exceptionSet);
}
if ( (bucket = this.proceduralFilters.get('!' + entityHash)) ) {
bucket.retrieve(entity, exceptionSet);
}
}
// Special bucket for those filters without a valid
// domain name as per PSL.
if ( (bucket = this.specificFilters.get('!' + this.noDomainHash)) ) {
bucket.retrieve(hostname, exceptionSet);
}
// Specific exception procedural cosmetic filters.
if ( (bucket = this.proceduralFilters.get('!' + domainHash)) ) {
bucket.retrieve(hostname, exceptionSet);
}
// Specific entity-based exception procedural cosmetic filters.
if ( entityHash !== undefined ) {
if ( (bucket = this.proceduralFilters.get('!' + entityHash)) ) {
bucket.retrieve(entity, exceptionSet);
}
}
// Special bucket for those filters without a valid
// domain name as per PSL.
if ( (bucket = this.proceduralFilters.get('!' + this.noDomainHash)) ) {
bucket.retrieve(hostname, exceptionSet);
}
@ -2162,33 +2189,19 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
r.scripts = this.retrieveUserScripts(domain, hostname);
if ( cacheEntry ) {
var netFilters = [];
cacheEntry.retrieve('net', netFilters);
r.netFilters = netFilters.join(',\n');
var networkFilters = [];
cacheEntry.retrieve('net', networkFilters);
r.networkFilters = networkFilters.join(',\n');
}
if (
this.supportsUserStylesheets &&
sender instanceof Object &&
sender.tab instanceof Object &&
typeof sender.frameId === 'number'
) {
this.injectHideRules(
sender.tab.id,
sender.frameId,
[ r.declarativeFilters.join(',\n'), r.netFilters ],
'document_start'
);
this.injectHideRules(
sender.tab.id,
sender.frameId,
[ r.highGenericHideSimple, r.highGenericHideComplex ],
'document_end'
);
r.rulesInjected = true;
// https://github.com/gorhill/uBlock/issues/3160
// If user stylesheets are supported in the current process, inject the
// cosmetic filter now.
if ( this.supportsUserStylesheets ) {
this.injectRules(sender, r);
}
console.timeEnd('cosmeticFilteringEngine.retrieveDomainSelectors');
//console.timeEnd('cosmeticFilteringEngine.retrieveDomainSelectors');
return r;
};

View File

@ -119,7 +119,7 @@ ProceduralJob.prototype.lookup = function(out) {
};
var jobQueueTimer = new vAPI.SafeAnimationFrame(function processJobQueue() {
console.time('dom logger/scanning for matches');
//console.time('dom logger/scanning for matches');
jobQueueTimer.clear();
var toLog = [],
t0 = Date.now(),
@ -145,13 +145,13 @@ var jobQueueTimer = new vAPI.SafeAnimationFrame(function processJobQueue() {
if ( jobQueue.length !== 0 ) {
jobQueueTimer.start(100);
}
console.timeEnd('dom logger/scanning for matches');
//console.timeEnd('dom logger/scanning for matches');
});
var handlers = {
onFiltersetChanged: function(type, selectors) {
console.time('dom logger/filterset changed');
//console.time('dom logger/filterset changed');
var selector,
sanitized;
if ( type === 'declarative' ) {
@ -189,7 +189,7 @@ var handlers = {
if ( jobQueue.length !== 0 ) {
jobQueueTimer.start(1);
}
console.timeEnd('dom logger/filterset changed');
//console.timeEnd('dom logger/filterset changed');
},
onDOMCreated: function() {