From cd0d7258c3a93f2989d5d9ec0244ba2763ea2d23 Mon Sep 17 00:00:00 2001 From: Niklas von Hertzen Date: Sat, 14 Aug 2021 15:01:41 +0800 Subject: [PATCH] feat: add support for data-html2canvas-debug property for debugging (#2658) --- src/core/debugger.ts | 29 ++++++++++++++++++++++++++++ src/dom/document-cloner.ts | 4 ++++ src/dom/element-container.ts | 20 ++++++++++++------- src/render/canvas/canvas-renderer.ts | 9 ++++++++- 4 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 src/core/debugger.ts diff --git a/src/core/debugger.ts b/src/core/debugger.ts new file mode 100644 index 0000000..4d4f127 --- /dev/null +++ b/src/core/debugger.ts @@ -0,0 +1,29 @@ +const elementDebuggerAttribute = 'data-html2canvas-debug'; +export const enum DebuggerType { + NONE, + ALL, + CLONE, + PARSE, + RENDER +} + +const getElementDebugType = (element: Element): DebuggerType => { + const attribute = element.getAttribute(elementDebuggerAttribute); + switch (attribute) { + case 'all': + return DebuggerType.ALL; + case 'clone': + return DebuggerType.CLONE; + case 'parse': + return DebuggerType.PARSE; + case 'render': + return DebuggerType.RENDER; + default: + return DebuggerType.NONE; + } +}; + +export const isDebugging = (element: Element, type: Omit): boolean => { + const elementType = getElementDebugType(element); + return elementType === DebuggerType.ALL || type === elementType; +}; diff --git a/src/dom/document-cloner.ts b/src/dom/document-cloner.ts index 0bb7b18..e6c2588 100644 --- a/src/dom/document-cloner.ts +++ b/src/dom/document-cloner.ts @@ -20,6 +20,7 @@ import {LIST_STYLE_TYPE, listStyleType} from '../css/property-descriptors/list-s import {CSSParsedCounterDeclaration, CSSParsedPseudoDeclaration} from '../css/index'; import {getQuote} from '../css/property-descriptors/quotes'; import {Context} from '../core/context'; +import {DebuggerType, isDebugging} from '../core/debugger'; export interface CloneOptions { ignoreElements?: (element: Element) => boolean; @@ -136,6 +137,9 @@ export class DocumentCloner { } createElementClone(node: T): HTMLElement | SVGElement { + if (isDebugging(node, DebuggerType.CLONE)) { + debugger; + } if (isCanvasElement(node)) { return this.createCanvasClone(node); } diff --git a/src/dom/element-container.ts b/src/dom/element-container.ts index d284287..01f5018 100644 --- a/src/dom/element-container.ts +++ b/src/dom/element-container.ts @@ -3,24 +3,27 @@ import {TextContainer} from './text-container'; import {Bounds, parseBounds} from '../css/layout/bounds'; import {isHTMLElementNode} from './node-parser'; import {Context} from '../core/context'; +import {DebuggerType, isDebugging} from '../core/debugger'; export const enum FLAGS { CREATES_STACKING_CONTEXT = 1 << 1, CREATES_REAL_STACKING_CONTEXT = 1 << 2, - IS_LIST_OWNER = 1 << 3 + IS_LIST_OWNER = 1 << 3, + DEBUG_RENDER = 1 << 4 } export class ElementContainer { readonly styles: CSSParsedDeclaration; - readonly textNodes: TextContainer[]; - readonly elements: ElementContainer[]; + readonly textNodes: TextContainer[] = []; + readonly elements: ElementContainer[] = []; bounds: Bounds; - flags: number; + flags = 0; constructor(protected readonly context: Context, element: Element) { + if (isDebugging(element, DebuggerType.PARSE)) { + debugger; + } this.styles = new CSSParsedDeclaration(context, window.getComputedStyle(element, null)); - this.textNodes = []; - this.elements = []; if (isHTMLElementNode(element)) { if (this.styles.animationDuration.some((duration) => duration > 0)) { @@ -37,6 +40,9 @@ export class ElementContainer { } this.bounds = parseBounds(this.context, element); - this.flags = 0; + + if (isDebugging(element, DebuggerType.RENDER)) { + this.flags |= FLAGS.DEBUG_RENDER; + } } } diff --git a/src/render/canvas/canvas-renderer.ts b/src/render/canvas/canvas-renderer.ts index ccbd5a3..8ecedb5 100644 --- a/src/render/canvas/canvas-renderer.ts +++ b/src/render/canvas/canvas-renderer.ts @@ -1,6 +1,6 @@ import {ElementPaint, parseStackingContexts, StackingContext} from '../stacking-context'; import {asString, Color, isTransparent} from '../../css/types/color'; -import {ElementContainer} from '../../dom/element-container'; +import {ElementContainer, FLAGS} from '../../dom/element-container'; import {BORDER_STYLE} from '../../css/property-descriptors/border-style'; import {CSSParsedDeclaration} from '../../css/index'; import {TextContainer} from '../../dom/text-container'; @@ -135,6 +135,10 @@ export class CanvasRenderer extends Renderer { } async renderNode(paint: ElementPaint): Promise { + if (contains(paint.container.flags, FLAGS.DEBUG_RENDER)) { + debugger; + } + if (paint.container.styles.isVisible()) { await this.renderNodeBackgroundAndBorders(paint); await this.renderNodeContent(paint); @@ -468,6 +472,9 @@ export class CanvasRenderer extends Renderer { } async renderStackContent(stack: StackingContext): Promise { + if (contains(stack.element.container.flags, FLAGS.DEBUG_RENDER)) { + debugger; + } // https://www.w3.org/TR/css-position-3/#painting-order // 1. the background and borders of the element forming the stacking context. await this.renderNodeBackgroundAndBorders(stack.element);