mirror of https://github.com/gorhill/uBlock.git
new content script code: code review, fine tuning perf
This commit is contained in:
parent
6c513629bf
commit
2d68c8ee6c
|
@ -42,6 +42,8 @@ vAPI.contentscriptInjected = true;
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// The DOM filterer is the heart of uBO's cosmetic filtering.
|
||||||
|
|
||||||
vAPI.domFilterer = {
|
vAPI.domFilterer = {
|
||||||
allExceptions: Object.create(null),
|
allExceptions: Object.create(null),
|
||||||
allSelectors: Object.create(null),
|
allSelectors: Object.create(null),
|
||||||
|
@ -49,6 +51,7 @@ vAPI.domFilterer = {
|
||||||
disabledId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
disabledId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
hiddenId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
hiddenId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
||||||
|
hiddenNodeCount: 0,
|
||||||
matchesProp: 'matches',
|
matchesProp: 'matches',
|
||||||
newSelectors: [],
|
newSelectors: [],
|
||||||
shadowId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
shadowId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
||||||
|
@ -57,15 +60,18 @@ vAPI.domFilterer = {
|
||||||
|
|
||||||
complexGroupSelector: null,
|
complexGroupSelector: null,
|
||||||
complexSelectors: [],
|
complexSelectors: [],
|
||||||
|
complexSelectorsMissCount: 0,
|
||||||
simpleGroupSelector: null,
|
simpleGroupSelector: null,
|
||||||
simpleSelectors: [],
|
simpleSelectors: [],
|
||||||
|
|
||||||
complexHasSelectors: [],
|
complexHasSelectors: [],
|
||||||
|
complexHasSelectorsMissCount: 0,
|
||||||
simpleHasSelectors: [],
|
simpleHasSelectors: [],
|
||||||
|
|
||||||
xpathSelectors: [],
|
|
||||||
xpathExpression: null,
|
xpathExpression: null,
|
||||||
xpathResult: null,
|
xpathResult: null,
|
||||||
|
xpathSelectors: [],
|
||||||
|
xpathSelectorsMissCount: 0,
|
||||||
|
|
||||||
addExceptions: function(aa) {
|
addExceptions: function(aa) {
|
||||||
for ( var i = 0, n = aa.length; i < n; i++ ) {
|
for ( var i = 0, n = aa.length; i < n; i++ ) {
|
||||||
|
@ -79,6 +85,7 @@ vAPI.domFilterer = {
|
||||||
this.simpleHasSelectors.push(entry);
|
this.simpleHasSelectors.push(entry);
|
||||||
} else {
|
} else {
|
||||||
this.complexHasSelectors.push(entry);
|
this.complexHasSelectors.push(entry);
|
||||||
|
this.complexHasSelectorsMissCount = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -105,6 +112,7 @@ vAPI.domFilterer = {
|
||||||
} else {
|
} else {
|
||||||
this.complexSelectors.push(s);
|
this.complexSelectors.push(s);
|
||||||
this.complexGroupSelector = null;
|
this.complexGroupSelector = null;
|
||||||
|
this.complexSelectorsMissCount = 0;
|
||||||
}
|
}
|
||||||
this.newSelectors.push(s);
|
this.newSelectors.push(s);
|
||||||
},
|
},
|
||||||
|
@ -157,11 +165,13 @@ vAPI.domFilterer = {
|
||||||
},
|
},
|
||||||
|
|
||||||
commit: function(newNodes) {
|
commit: function(newNodes) {
|
||||||
|
var beforeHiddenNodeCount = this.hiddenNodeCount;
|
||||||
|
|
||||||
if ( newNodes === undefined ) {
|
if ( newNodes === undefined ) {
|
||||||
newNodes = [ document.documentElement ];
|
newNodes = [ document.documentElement ];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject new selectors as CSS rules in a style tags.
|
// Inject new selectors as CSS rules in a style tag.
|
||||||
if ( this.newSelectors.length ) {
|
if ( this.newSelectors.length ) {
|
||||||
var styleTag = document.createElement('style');
|
var styleTag = document.createElement('style');
|
||||||
styleTag.setAttribute('type', 'text/css');
|
styleTag.setAttribute('type', 'text/css');
|
||||||
|
@ -198,21 +208,26 @@ vAPI.domFilterer = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complex `:has()` selectors.
|
// Complex `:has()` selectors.
|
||||||
i = this.complexHasSelectors.length;
|
if ( this.complexHasSelectorsMissCount < 5 && this.complexHasSelectors.length ) {
|
||||||
while ( i-- ) {
|
this.complexHasSelectorsMissCount += 1;
|
||||||
entry = this.complexHasSelectors[i];
|
i = this.complexHasSelectors.length;
|
||||||
nodes = document.querySelectorAll(entry.a + this.cssNotHiddenId);
|
while ( i-- ) {
|
||||||
j = nodes.length;
|
entry = this.complexHasSelectors[i];
|
||||||
while ( j-- ) {
|
nodes = document.querySelectorAll(entry.a + this.cssNotHiddenId);
|
||||||
node = nodes[j];
|
j = nodes.length;
|
||||||
if ( node.querySelector(entry.b) !== null ) {
|
while ( j-- ) {
|
||||||
this.hideNode(node);
|
node = nodes[j];
|
||||||
|
if ( node.querySelector(entry.b) !== null ) {
|
||||||
|
this.hideNode(node);
|
||||||
|
this.complexHasSelectorsMissCount = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `:xpath()` selectors.
|
// `:xpath()` selectors.
|
||||||
if ( this.xpathSelectors.length ) {
|
if ( this.xpathSelectorsMissCount < 5 && this.xpathSelectors.length ) {
|
||||||
|
this.xpathSelectorsMissCount += 1;
|
||||||
if ( this.xpathExpression === null ) {
|
if ( this.xpathExpression === null ) {
|
||||||
this.xpathExpression = document.createExpression(
|
this.xpathExpression = document.createExpression(
|
||||||
this.xpathSelectors.join(this.xpathNotHiddenId + '|') + this.xpathNotHiddenId,
|
this.xpathSelectors.join(this.xpathNotHiddenId + '|') + this.xpathNotHiddenId,
|
||||||
|
@ -229,6 +244,7 @@ vAPI.domFilterer = {
|
||||||
node = this.xpathResult.snapshotItem(i);
|
node = this.xpathResult.snapshotItem(i);
|
||||||
if ( node.nodeType === 1 ) {
|
if ( node.nodeType === 1 ) {
|
||||||
this.hideNode(node);
|
this.hideNode(node);
|
||||||
|
this.xpathSelectorsMissCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +272,8 @@ vAPI.domFilterer = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complex selectors.
|
// Complex selectors.
|
||||||
if ( this.complexSelectors.length ) {
|
if ( this.complexSelectorsMissCount < 5 && this.complexSelectors.length ) {
|
||||||
|
this.complexSelectorsMissCount += 1;
|
||||||
if ( this.complexGroupSelector === null ) {
|
if ( this.complexGroupSelector === null ) {
|
||||||
this.complexGroupSelector =
|
this.complexGroupSelector =
|
||||||
this.complexSelectors.join(this.cssNotHiddenId + ',') +
|
this.complexSelectors.join(this.cssNotHiddenId + ',') +
|
||||||
|
@ -266,16 +283,26 @@ vAPI.domFilterer = {
|
||||||
i = nodes.length;
|
i = nodes.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
this.hideNode(nodes[i]);
|
this.hideNode(nodes[i]);
|
||||||
|
this.complexSelectorsMissCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset transient state.
|
// Reset transient state.
|
||||||
this.newSelectors.length = 0;
|
this.newSelectors.length = 0;
|
||||||
|
|
||||||
|
// If DOM nodes have been affected, notify core process.
|
||||||
|
if ( this.hiddenNodeCount !== beforeHiddenNodeCount ) {
|
||||||
|
vAPI.messaging.send(
|
||||||
|
'contentscript',
|
||||||
|
{ what: 'cosmeticFiltersActivated' }
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
hideNode: (function() {
|
hideNode: (function() {
|
||||||
if ( document.documentElement.shadowRoot === undefined ) {
|
if ( document.documentElement.shadowRoot === undefined ) {
|
||||||
return function(node) {
|
return function(node) {
|
||||||
|
this.hiddenNodeCount += 1;
|
||||||
node.setAttribute(this.hiddenId, '');
|
node.setAttribute(this.hiddenId, '');
|
||||||
if ( this.enabled ) {
|
if ( this.enabled ) {
|
||||||
node.style.setProperty('display', 'none', 'important');
|
node.style.setProperty('display', 'none', 'important');
|
||||||
|
@ -283,6 +310,7 @@ vAPI.domFilterer = {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return function(node) {
|
return function(node) {
|
||||||
|
this.hiddenNodeCount += 1;
|
||||||
node.setAttribute(this.hiddenId, '');
|
node.setAttribute(this.hiddenId, '');
|
||||||
var shadow = node.shadowRoot;
|
var shadow = node.shadowRoot;
|
||||||
// https://www.chromestatus.com/features/4668884095336448
|
// https://www.chromestatus.com/features/4668884095336448
|
||||||
|
@ -408,9 +436,6 @@ var injectScripts = function(scripts) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var responseHandler = function(details) {
|
var responseHandler = function(details) {
|
||||||
var domFilterer = vAPI.domFilterer;
|
|
||||||
var styleTagCount = domFilterer.styleTags.length;
|
|
||||||
|
|
||||||
if ( details ) {
|
if ( details ) {
|
||||||
if (
|
if (
|
||||||
(vAPI.skipCosmeticFiltering = details.skipCosmeticFiltering) !== true &&
|
(vAPI.skipCosmeticFiltering = details.skipCosmeticFiltering) !== true &&
|
||||||
|
@ -428,12 +453,6 @@ var responseHandler = function(details) {
|
||||||
// the browser to flush this script from memory.
|
// the browser to flush this script from memory.
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is just to inform the background process that cosmetic filters were
|
|
||||||
// actually injected.
|
|
||||||
if ( domFilterer.styleTags.length !== styleTagCount ) {
|
|
||||||
vAPI.messaging.send('contentscript', { what: 'cosmeticFiltersActivated' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/587
|
// https://github.com/chrisaljoudi/uBlock/issues/587
|
||||||
// If no filters were found, maybe the script was injected before uBlock's
|
// If no filters were found, maybe the script was injected before uBlock's
|
||||||
// process was fully initialized. When this happens, pages won't be
|
// process was fully initialized. When this happens, pages won't be
|
||||||
|
@ -1042,17 +1061,16 @@ if ( !vAPI.contentscriptInjected ) {
|
||||||
// Added node lists will be cumulated here before being processed
|
// Added node lists will be cumulated here before being processed
|
||||||
var addedNodeLists = [];
|
var addedNodeLists = [];
|
||||||
var addedNodeListsTimer = null;
|
var addedNodeListsTimer = null;
|
||||||
var addedNodeListsTimerDelay = 10;
|
var addedNodeListsTimerDelay = 25;
|
||||||
var removedNodeListsTimer = null;
|
var removedNodeListsTimer = null;
|
||||||
|
var removedNodeListsTimerDelay = 25;
|
||||||
var collapser = domCollapser;
|
var collapser = domCollapser;
|
||||||
|
|
||||||
// The `cosmeticFiltersActivated` message is required: a new element could
|
|
||||||
// be matching an already injected but otherwise inactive cosmetic filter.
|
|
||||||
// This means the already injected cosmetic filter become active (has an
|
|
||||||
// effect on the document), and thus must be logged if needed.
|
|
||||||
var addedNodesHandler = function() {
|
var addedNodesHandler = function() {
|
||||||
addedNodeListsTimer = null;
|
addedNodeListsTimer = null;
|
||||||
addedNodeListsTimerDelay = Math.min(addedNodeListsTimerDelay*2, 100);
|
if ( addedNodeListsTimerDelay < 100 ) {
|
||||||
|
addedNodeListsTimerDelay *= 2;
|
||||||
|
}
|
||||||
var iNodeList = addedNodeLists.length,
|
var iNodeList = addedNodeLists.length,
|
||||||
nodeList, iNode, node;
|
nodeList, iNode, node;
|
||||||
while ( iNodeList-- ) {
|
while ( iNodeList-- ) {
|
||||||
|
@ -1074,7 +1092,6 @@ if ( !vAPI.contentscriptInjected ) {
|
||||||
if ( contextNodes.length !== 0 ) {
|
if ( contextNodes.length !== 0 ) {
|
||||||
classesAndIdsFromNodeList(selectNodes('[class],[id]'));
|
classesAndIdsFromNodeList(selectNodes('[class],[id]'));
|
||||||
retrieveGenericSelectors();
|
retrieveGenericSelectors();
|
||||||
messaging.send('contentscript', { what: 'cosmeticFiltersActivated' });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1082,6 +1099,11 @@ if ( !vAPI.contentscriptInjected ) {
|
||||||
// This will ensure our style elements will stay in the DOM.
|
// This will ensure our style elements will stay in the DOM.
|
||||||
var removedNodesHandler = function() {
|
var removedNodesHandler = function() {
|
||||||
removedNodeListsTimer = null;
|
removedNodeListsTimer = null;
|
||||||
|
removedNodeListsTimerDelay *= 2;
|
||||||
|
// Stop watching style tags after a while.
|
||||||
|
if ( removedNodeListsTimerDelay > 1000 ) {
|
||||||
|
removedNodeListsTimerDelay = 0;
|
||||||
|
}
|
||||||
domFilterer.checkStyleTags(true);
|
domFilterer.checkStyleTags(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1107,8 +1129,8 @@ if ( !vAPI.contentscriptInjected ) {
|
||||||
if ( addedNodeLists.length !== 0 && addedNodeListsTimer === null ) {
|
if ( addedNodeLists.length !== 0 && addedNodeListsTimer === null ) {
|
||||||
addedNodeListsTimer = vAPI.setTimeout(addedNodesHandler, addedNodeListsTimerDelay);
|
addedNodeListsTimer = vAPI.setTimeout(addedNodesHandler, addedNodeListsTimerDelay);
|
||||||
}
|
}
|
||||||
if ( removedNodeLists && removedNodeListsTimer === null ) {
|
if ( removedNodeListsTimerDelay !== 0 && removedNodeLists && removedNodeListsTimer === null ) {
|
||||||
removedNodeListsTimer = vAPI.setTimeout(removedNodesHandler, 100);
|
removedNodeListsTimer = vAPI.setTimeout(removedNodesHandler, removedNodeListsTimerDelay);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue