From bcbf465f2cf1336bc998eb9e548b2328d63226c8 Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Wed, 18 Jan 2023 19:03:33 -0600 Subject: [PATCH 1/9] Extend timeout of table test --- spec/dom-to-image-more.spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/dom-to-image-more.spec.js b/spec/dom-to-image-more.spec.js index ef836527..69b784d4 100644 --- a/spec/dom-to-image-more.spec.js +++ b/spec/dom-to-image-more.spec.js @@ -18,6 +18,7 @@ describe('regression', function () { it('should render to svg', function (done) { + this.timeout(5000); loadTestPage( 'small/dom-node.html', 'small/style.css', @@ -131,6 +132,7 @@ }); it('should render nested svg with broken namespace', function (done) { + this.timeout(5000); loadTestPage( 'svg-ns/dom-node.html', 'svg-ns/style.css', @@ -531,6 +533,7 @@ }); it('should honor zero-padding table elements', function (done) { + this.timeout(5000); loadTestPage( 'padding/dom-node.html', 'padding/style.css', From 5f6d26482ce60632cb0a6e1045b3a8a3e96f0613 Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Wed, 18 Jan 2023 19:39:24 -0600 Subject: [PATCH 2/9] Mirror the cloned-element's DOM fragment hierarchy This ensures that browser-stylesheets that have parent tag based rules work correctly. This is evident when doing (for example) a bare `TD` before, the default style was defaulted to be `padding: opx`, but when the `TD` is actually created as a child of the normal hierarchy (e.g. `TABLE`, `TBODY`, `TR`, `TD`) then the defaulted padding is `padding: 1px`. Refactored a bit for clarity Resolves #106 and thus also Resolves #95 --- src/dom-to-image-more.js | 144 ++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 38 deletions(-) diff --git a/src/dom-to-image-more.js b/src/dom-to-image-more.js index 9709904c..10e02990 100644 --- a/src/dom-to-image-more.js +++ b/src/dom-to-image-more.js @@ -329,6 +329,7 @@ copyFont(sourceComputedStyles, targetElement.style); // here we re-assign the font props. } else { copyUserComputedStyleFast( + sourceElement, sourceComputedStyles, parentComputedStyles, targetElement @@ -981,11 +982,12 @@ } function copyUserComputedStyleFast( + sourceElement, sourceComputedStyles, parentComputedStyles, targetElement ) { - const defaultStyle = getDefaultStyle(targetElement.tagName); + const defaultStyle = getDefaultStyle(sourceElement); const targetStyle = targetElement.style; util.asArray(sourceComputedStyles).forEach(function (name) { @@ -1010,45 +1012,111 @@ let removeDefaultStylesTimeoutId = null; let tagNameDefaultStyles = {}; - function getDefaultStyle(tagName) { - if (tagNameDefaultStyles[tagName]) { - return tagNameDefaultStyles[tagName]; + const ascentStoppers = [ + // these come from https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements + 'ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'DETAILS', 'DIALOG', 'DD', 'DIV', 'DL', 'DT', 'FIELDSET', + 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', 'HGROUP', + 'HR', 'LI', 'MAIN', 'NAV', 'OL', 'P', 'PRE', 'SECTION', 'SVG', 'TABLE', 'UL', + // these are ultimate stoppers in case something drastic changes in how the DOM works + 'BODY', 'HEAD', 'HTML' + ]; + + function getDefaultStyle(sourceElement) { + const tagHierarchy = computeTagHierarchy(sourceElement); + const tagKey = tagHierarchy.join('>'); // it's like CSS + if (tagNameDefaultStyles[tagKey]) { + return tagNameDefaultStyles[tagKey]; } - if (!sandbox) { - // Create a hidden sandbox