-
Notifications
You must be signed in to change notification settings - Fork 222
Description
Simulating pseudo-class selectors hover/active/focus/target (see https://github.com/cburgmer/rasterizeHTML.js/wiki/API#optional-parameters) will result in the following error on Chrome, if the option executeJs is set to true:
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'cssRules')
at documentUtil.js:89:60
at Array.forEach (<anonymous>)
at replaceSimpleSelectorsBy (documentUtil.js:80:52)
at Object.module.lowercaseCssTypeSelectors (documentUtil.js:131:9)
at Object.module.rewriteTagNameSelectorsToLowerCase (documentHelper.js:68:22)
at Object.module.getSvgForDocument (document2svg.js:107:24)
at document2svg.js:122:31
Example of problematic invocation:
rasterizeHTML.drawHTML(
html,
{
executeJs: true,
active: ".bgimage", // remove this to circumvent the error
}
);Analysis:
- When
executeJsis set to true, we load the document to be rendered into a sandboxed iframe, so that the JavaScript is executed automatically by the browser. - We then extract the new document from the iframe and pass this on.
- The iframe has been added to the current window's document, to force the browser to evaluate the code. We now clean it up once the previous step is done.
- Eventually when we get to the pseudo-class handling code, we inspect all cssRules of style elements (
styleElement.sheet.cssRules), and rewrite the selectors to fake a hover/active/focus/target event. - Then we serialise the changed cssRules back into text/css and update the style's textContent (
styleElement.textContent), as we need to serialize the whole (X)HTML document at the end before embedding in the SVG.
In newer Chromes now step 5 seems to reset the sheet property of the changed style elements. As we will access this property repeatedly (minimum once later to handle XHTML's lowercase tag names, and hence the need for tag name selectors to be lowercase), we fail and run into the above problem. (If we apply multiple fake pseudo-class activations, the stack trace looks slightly different.)
When exectuteJs is set to false, we do not use an iframe and this does not seem to trigger the issue.
We can circumvent the problem by not immediately removing the temporary iframe from step 3, but keeping it until we are done with the document exposed by it. It seems that removing the iframe from an active parent document, will not update the sheet property if a style's textContent is changed.
Here is a minimal test case to reproduce the browser issue: https://jsfiddle.net/cburgmer/zyLeu8w5/12/. Whether this is standard conformant or not is not clear to me.