| Index: lib/cssInjection.js |
| =================================================================== |
| --- a/lib/cssInjection.js |
| +++ b/lib/cssInjection.js |
| @@ -21,21 +21,28 @@ |
| const {RegExpFilter} = require("filterClasses"); |
| const {ElemHide} = require("elemHide"); |
| const {ElemHideEmulation} = require("elemHideEmulation"); |
| const {checkWhitelisted} = require("whitelisting"); |
| const {extractHostFromFrame} = require("url"); |
| const {port} = require("messaging"); |
| const devtools = require("devtools"); |
| +const info = require("info"); |
| -const userStyleSheetsSupported = "extensionTypes" in browser && |
| - "CSSOrigin" in browser.extensionTypes; |
| +// Chromium's support for tabs.removeCSS is still a work in progress and the |
| +// API is likely to be different from Firefox's; for now we just don't use it |
| +// at all, even if it's available. |
| +// See https://crbug.com/608854 |
| +const styleSheetRemovalSupported = info.platform == "gecko"; |
| + |
| const selectorGroupSize = 1024; |
| +let userStyleSheetsSupported = true; |
| + |
| function* splitSelectors(selectors) |
| { |
| // Chromium's Blink engine supports only up to 8,192 simple selectors, and |
| // even fewer compound selectors, in a rule. The exact number of selectors |
| // that would work depends on their sizes (e.g. "#foo .bar" has a size of 2). |
| // Since we don't know the sizes of the selectors here, we simply split them |
| // into groups of 1,024, based on the reasonable assumption that the average |
| // selector won't have a size greater than 8. The alternative would be to |
| @@ -56,27 +63,39 @@ |
| function createStyleSheet(selectors) |
| { |
| return Array.from(createRules(selectors)).join("\n"); |
| } |
| function addStyleSheet(tabId, frameId, styleSheet) |
| { |
| - browser.tabs.insertCSS(tabId, { |
| - code: styleSheet, |
| - cssOrigin: "user", |
| - frameId, |
| - matchAboutBlank: true, |
| - runAt: "document_start" |
| - }); |
| + try |
| + { |
| + browser.tabs.insertCSS(tabId, { |
| + code: styleSheet, |
| + cssOrigin: "user", |
| + frameId, |
| + matchAboutBlank: true, |
| + runAt: "document_start" |
| + }); |
| + } |
| + catch (error) |
| + { |
| + userStyleSheetsSupported = false; |
| + } |
| + |
| + return userStyleSheetsSupported; |
| } |
| function removeStyleSheet(tabId, frameId, styleSheet) |
| { |
| + if (!styleSheetRemovalSupported) |
| + return; |
| + |
| browser.tabs.removeCSS(tabId, { |
| code: styleSheet, |
| cssOrigin: "user", |
| frameId, |
| matchAboutBlank: true |
| }); |
| } |
| @@ -94,26 +113,27 @@ |
| // Ideally we would compare the old and new style sheets and skip this code |
| // if they're the same, but the old style sheet can be a leftover from a |
| // previous instance of the frame. We must add the new style sheet |
| // regardless. |
| // Add the new style sheet first to keep previously hidden elements from |
| // reappearing momentarily. |
| - if (styleSheet) |
| - addStyleSheet(tabId, frameId, styleSheet); |
| + if (styleSheet && !addStyleSheet(tabId, frameId, styleSheet)) |
| + return false; |
| // Sometimes the old and new style sheets can be exactly the same. In such a |
| // case, do not remove the "old" style sheet, because it is in fact the new |
| // style sheet now. |
| if (oldStyleSheet && oldStyleSheet != styleSheet) |
| removeStyleSheet(tabId, frameId, oldStyleSheet); |
| frame.injectedStyleSheets.set(groupName, styleSheet); |
| + return true; |
| } |
| port.on("elemhide.getSelectors", (message, sender) => |
| { |
| let selectors = []; |
| let emulatedPatterns = []; |
| let trace = devtools && devtools.hasPanel(sender.page); |
| let inline = !userStyleSheetsSupported; |
| @@ -130,23 +150,33 @@ |
| hostname, |
| specificOnly ? ElemHide.SPECIFIC_ONLY : ElemHide.ALL_MATCHING |
| ); |
| for (let filter of ElemHideEmulation.getRulesForDomain(hostname)) |
| emulatedPatterns.push({selector: filter.selector, text: filter.text}); |
| } |
| - if (!inline) |
| - updateFrameStyles(sender.page.id, sender.frame.id, selectors, "standard"); |
| + if (!inline && !updateFrameStyles(sender.page.id, sender.frame.id, |
| + selectors, "standard")) |
| + { |
| + inline = true; |
| + } |
| let response = {trace, inline, emulatedPatterns}; |
| if (trace || inline) |
| response.selectors = selectors; |
| + // If we can't remove user style sheets using tabs.removeCSS, we'll only keep |
| + // adding them, which could cause problems with emulation filters as |
| + // described in issue #5864. Instead, we can just ask the content script to |
| + // add styles for emulation filters inline. |
| + if (!styleSheetRemovalSupported) |
| + response.inlineEmulated = true; |
| + |
| return response; |
| }); |
| port.on("elemhide.injectSelectors", (message, sender) => |
| { |
| updateFrameStyles(sender.page.id, sender.frame.id, message.selectors, |
| message.groupName); |
| }); |