html2canvas-pro 2.2.4 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/html2canvas-pro.cjs +11221 -0
  2. package/dist/html2canvas-pro.cjs.map +1 -0
  3. package/dist/html2canvas-pro.esm.js +2812 -2587
  4. package/dist/html2canvas-pro.esm.js.map +1 -1
  5. package/dist/html2canvas-pro.js +2812 -2587
  6. package/dist/html2canvas-pro.js.map +1 -1
  7. package/dist/html2canvas-pro.min.js +4 -5
  8. package/dist/lib/core/abort-helper.js +20 -0
  9. package/dist/lib/core/background-parser.js +41 -0
  10. package/dist/lib/core/cache-storage.js +63 -7
  11. package/dist/lib/core/config-assembler.js +88 -0
  12. package/dist/lib/core/lru-map.js +66 -0
  13. package/dist/lib/core/render-element.js +24 -103
  14. package/dist/lib/css/property-descriptors/background-position.js +1 -11
  15. package/dist/lib/css/property-descriptors/background-size.js +3 -1
  16. package/dist/lib/css/syntax/token-constants.js +214 -0
  17. package/dist/lib/css/syntax/token-singletons.js +36 -0
  18. package/dist/lib/css/syntax/token-types.js +10 -0
  19. package/dist/lib/css/syntax/tokenizer.js +175 -307
  20. package/dist/lib/css/types/length-percentage.js +63 -3
  21. package/dist/lib/dom/document-cloner.js +23 -22
  22. package/dist/lib/dom/node-parser.js +1 -21
  23. package/dist/lib/dom/slot-cloner.js +8 -8
  24. package/dist/lib/render/background.js +4 -1
  25. package/dist/lib/render/canvas/background-renderer.js +27 -39
  26. package/dist/lib/render/canvas/canvas-renderer.js +3 -3
  27. package/dist/lib/render/canvas/effects-renderer.js +94 -32
  28. package/dist/lib/render/canvas/text-renderer.js +94 -32
  29. package/dist/lib/render/stacking-context.js +12 -6
  30. package/dist/types/core/abort-helper.d.ts +12 -0
  31. package/dist/types/core/background-parser.d.ts +16 -0
  32. package/dist/types/core/cache-storage.d.ts +25 -0
  33. package/dist/types/core/config-assembler.d.ts +28 -0
  34. package/dist/types/core/lru-map.d.ts +37 -0
  35. package/dist/types/css/syntax/token-constants.d.ts +74 -0
  36. package/dist/types/css/syntax/token-singletons.d.ts +22 -0
  37. package/dist/types/css/syntax/token-types.d.ts +72 -0
  38. package/dist/types/css/syntax/tokenizer.d.ts +6 -73
  39. package/dist/types/css/types/length-percentage.d.ts +42 -1
  40. package/dist/types/dom/document-cloner.d.ts +5 -0
  41. package/dist/types/dom/node-parser.d.ts +0 -2
  42. package/dist/types/render/canvas/background-renderer.d.ts +0 -10
  43. package/dist/types/render/canvas/effects-renderer.d.ts +42 -17
  44. package/dist/types/render/canvas/text-renderer.d.ts +15 -2
  45. package/dist/types/render/stacking-context.d.ts +26 -1
  46. package/package.json +5 -7
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Generic LRU (Least-Recently-Used) wrapper over a native `Map`.
3
+ *
4
+ * Both the CSS parse cache and the background pattern cache implement the
5
+ * same LRU eviction pattern using Map's insertion-order guarantee. This
6
+ * tiny utility centralises that logic so it can be reused without
7
+ * duplication.
8
+ *
9
+ * Usage:
10
+ * ```ts
11
+ * const cache = new LRUMap<string, CanvasPattern>(50);
12
+ * const entry = cache.get(key); // promotes if found, returns undefined otherwise
13
+ * cache.set(key, value); // evicts oldest entry when at capacity
14
+ * ```
15
+ */
16
+ export declare class LRUMap<K, V> {
17
+ private readonly maxSize;
18
+ private readonly _map;
19
+ constructor(maxSize: number);
20
+ /**
21
+ * Get a value by key.
22
+ * On cache hit the entry is promoted to the end of the Map (most-recently-used).
23
+ * Returns `undefined` on miss.
24
+ */
25
+ get(key: K): V | undefined;
26
+ /**
27
+ * Insert or update a key-value pair.
28
+ * If the key already exists it is moved to MRU position. If the map is
29
+ * at capacity the least-recently-used entry (oldest insertion order) is
30
+ * evicted before inserting.
31
+ */
32
+ set(key: K, value: V): void;
33
+ /** Current number of entries. */
34
+ get size(): number;
35
+ /** Remove all entries. */
36
+ clear(): void;
37
+ }
@@ -0,0 +1,74 @@
1
+ declare const LINE_FEED = 10;
2
+ declare const SOLIDUS = 47;
3
+ declare const REVERSE_SOLIDUS = 92;
4
+ declare const CHARACTER_TABULATION = 9;
5
+ declare const SPACE = 32;
6
+ declare const QUOTATION_MARK = 34;
7
+ declare const EQUALS_SIGN = 61;
8
+ declare const NUMBER_SIGN = 35;
9
+ declare const DOLLAR_SIGN = 36;
10
+ declare const PERCENTAGE_SIGN = 37;
11
+ declare const APOSTROPHE = 39;
12
+ declare const LEFT_PARENTHESIS = 40;
13
+ declare const RIGHT_PARENTHESIS = 41;
14
+ declare const LOW_LINE = 95;
15
+ declare const HYPHEN_MINUS = 45;
16
+ declare const EXCLAMATION_MARK = 33;
17
+ declare const LESS_THAN_SIGN = 60;
18
+ declare const GREATER_THAN_SIGN = 62;
19
+ declare const COMMERCIAL_AT = 64;
20
+ declare const LEFT_SQUARE_BRACKET = 91;
21
+ declare const RIGHT_SQUARE_BRACKET = 93;
22
+ declare const CIRCUMFLEX_ACCENT = 61;
23
+ declare const LEFT_CURLY_BRACKET = 123;
24
+ declare const QUESTION_MARK = 63;
25
+ declare const RIGHT_CURLY_BRACKET = 125;
26
+ declare const VERTICAL_LINE = 124;
27
+ declare const TILDE = 126;
28
+ declare const CONTROL = 128;
29
+ declare const REPLACEMENT_CHARACTER = 65533;
30
+ declare const ASTERISK = 42;
31
+ declare const PLUS_SIGN = 43;
32
+ declare const COMMA = 44;
33
+ declare const COLON = 58;
34
+ declare const SEMICOLON = 59;
35
+ declare const FULL_STOP = 46;
36
+ declare const NULL = 0;
37
+ declare const BACKSPACE = 8;
38
+ declare const LINE_TABULATION = 11;
39
+ declare const SHIFT_OUT = 14;
40
+ declare const INFORMATION_SEPARATOR_ONE = 31;
41
+ declare const DELETE = 127;
42
+ declare const EOF = -1;
43
+ declare const ZERO = 48;
44
+ declare const a = 97;
45
+ declare const e = 101;
46
+ declare const f = 102;
47
+ declare const u = 117;
48
+ declare const z = 122;
49
+ declare const A = 65;
50
+ declare const E = 69;
51
+ declare const F = 70;
52
+ declare const U = 85;
53
+ declare const Z = 90;
54
+ /** Re-exported code-point constants used by the Tokenizer class internally. */
55
+ export { LINE_FEED, SOLIDUS, REVERSE_SOLIDUS, CHARACTER_TABULATION, SPACE, QUOTATION_MARK, EQUALS_SIGN, NUMBER_SIGN, DOLLAR_SIGN, PERCENTAGE_SIGN, APOSTROPHE, LEFT_PARENTHESIS, RIGHT_PARENTHESIS, LOW_LINE, HYPHEN_MINUS, EXCLAMATION_MARK, LESS_THAN_SIGN, GREATER_THAN_SIGN, COMMERCIAL_AT, LEFT_SQUARE_BRACKET, RIGHT_SQUARE_BRACKET, CIRCUMFLEX_ACCENT, LEFT_CURLY_BRACKET, QUESTION_MARK, RIGHT_CURLY_BRACKET, VERTICAL_LINE, TILDE, CONTROL, REPLACEMENT_CHARACTER, ASTERISK, PLUS_SIGN, COMMA, COLON, SEMICOLON, FULL_STOP, NULL, BACKSPACE, LINE_TABULATION, SHIFT_OUT, INFORMATION_SEPARATOR_ONE, DELETE, EOF, ZERO, a, e, f, u, z, A, E, F, U, Z };
56
+ declare const isDigit: (codePoint: number) => boolean;
57
+ declare const isSurrogateCodePoint: (codePoint: number) => boolean;
58
+ declare const isHex: (codePoint: number) => boolean;
59
+ declare const isLowerCaseLetter: (codePoint: number) => boolean;
60
+ declare const isUpperCaseLetter: (codePoint: number) => boolean;
61
+ declare const isLetter: (codePoint: number) => boolean;
62
+ declare const isNonASCIICodePoint: (codePoint: number) => boolean;
63
+ declare const isWhiteSpace: (codePoint: number) => boolean;
64
+ declare const isNameStartCodePoint: (codePoint: number) => boolean;
65
+ declare const isNameCodePoint: (codePoint: number) => boolean;
66
+ declare const isNonPrintableCodePoint: (codePoint: number) => boolean;
67
+ declare const isValidEscape: (c1: number, c2: number) => boolean;
68
+ declare const isIdentifierStart: (c1: number, c2: number, c3: number) => boolean;
69
+ declare const isNumberStart: (c1: number, c2: number, c3: number) => boolean;
70
+ /** Re-exported character-classification predicates. */
71
+ export { isDigit, isSurrogateCodePoint, isHex, isLowerCaseLetter, isUpperCaseLetter, isLetter, isNonASCIICodePoint, isWhiteSpace, isNameStartCodePoint, isNameCodePoint, isNonPrintableCodePoint, isValidEscape, isIdentifierStart, isNumberStart };
72
+ declare const stringToNumber: (codePoints: number[]) => number;
73
+ /** Re-exported helper: converts an array of code points to a JS number. */
74
+ export { stringToNumber };
@@ -0,0 +1,22 @@
1
+ import type { Token } from './token-types';
2
+ export declare const LEFT_PARENTHESIS_TOKEN: Token;
3
+ export declare const RIGHT_PARENTHESIS_TOKEN: Token;
4
+ export declare const COMMA_TOKEN: Token;
5
+ export declare const SUFFIX_MATCH_TOKEN: Token;
6
+ export declare const PREFIX_MATCH_TOKEN: Token;
7
+ export declare const COLUMN_TOKEN: Token;
8
+ export declare const DASH_MATCH_TOKEN: Token;
9
+ export declare const INCLUDE_MATCH_TOKEN: Token;
10
+ export declare const LEFT_CURLY_BRACKET_TOKEN: Token;
11
+ export declare const RIGHT_CURLY_BRACKET_TOKEN: Token;
12
+ export declare const SUBSTRING_MATCH_TOKEN: Token;
13
+ export declare const BAD_URL_TOKEN: Token;
14
+ export declare const BAD_STRING_TOKEN: Token;
15
+ export declare const CDO_TOKEN: Token;
16
+ export declare const CDC_TOKEN: Token;
17
+ export declare const COLON_TOKEN: Token;
18
+ export declare const SEMICOLON_TOKEN: Token;
19
+ export declare const LEFT_SQUARE_BRACKET_TOKEN: Token;
20
+ export declare const RIGHT_SQUARE_BRACKET_TOKEN: Token;
21
+ export declare const WHITESPACE_TOKEN: Token;
22
+ export declare const EOF_TOKEN: Token;
@@ -0,0 +1,72 @@
1
+ export declare const enum TokenType {
2
+ STRING_TOKEN = 0,
3
+ BAD_STRING_TOKEN = 1,
4
+ LEFT_PARENTHESIS_TOKEN = 2,
5
+ RIGHT_PARENTHESIS_TOKEN = 3,
6
+ COMMA_TOKEN = 4,
7
+ HASH_TOKEN = 5,
8
+ DELIM_TOKEN = 6,
9
+ AT_KEYWORD_TOKEN = 7,
10
+ PREFIX_MATCH_TOKEN = 8,
11
+ DASH_MATCH_TOKEN = 9,
12
+ INCLUDE_MATCH_TOKEN = 10,
13
+ LEFT_CURLY_BRACKET_TOKEN = 11,
14
+ RIGHT_CURLY_BRACKET_TOKEN = 12,
15
+ SUFFIX_MATCH_TOKEN = 13,
16
+ SUBSTRING_MATCH_TOKEN = 14,
17
+ DIMENSION_TOKEN = 15,
18
+ PERCENTAGE_TOKEN = 16,
19
+ NUMBER_TOKEN = 17,
20
+ FUNCTION = 18,
21
+ FUNCTION_TOKEN = 19,
22
+ IDENT_TOKEN = 20,
23
+ COLUMN_TOKEN = 21,
24
+ URL_TOKEN = 22,
25
+ BAD_URL_TOKEN = 23,
26
+ CDC_TOKEN = 24,
27
+ CDO_TOKEN = 25,
28
+ COLON_TOKEN = 26,
29
+ SEMICOLON_TOKEN = 27,
30
+ LEFT_SQUARE_BRACKET_TOKEN = 28,
31
+ RIGHT_SQUARE_BRACKET_TOKEN = 29,
32
+ UNICODE_RANGE_TOKEN = 30,
33
+ WHITESPACE_TOKEN = 31,
34
+ EOF_TOKEN = 32
35
+ }
36
+ interface IToken {
37
+ type: TokenType;
38
+ }
39
+ export interface Token extends IToken {
40
+ type: TokenType.BAD_URL_TOKEN | TokenType.BAD_STRING_TOKEN | TokenType.LEFT_PARENTHESIS_TOKEN | TokenType.RIGHT_PARENTHESIS_TOKEN | TokenType.COMMA_TOKEN | TokenType.SUBSTRING_MATCH_TOKEN | TokenType.PREFIX_MATCH_TOKEN | TokenType.SUFFIX_MATCH_TOKEN | TokenType.COLON_TOKEN | TokenType.SEMICOLON_TOKEN | TokenType.LEFT_SQUARE_BRACKET_TOKEN | TokenType.RIGHT_SQUARE_BRACKET_TOKEN | TokenType.LEFT_CURLY_BRACKET_TOKEN | TokenType.RIGHT_CURLY_BRACKET_TOKEN | TokenType.DASH_MATCH_TOKEN | TokenType.INCLUDE_MATCH_TOKEN | TokenType.COLUMN_TOKEN | TokenType.WHITESPACE_TOKEN | TokenType.CDC_TOKEN | TokenType.CDO_TOKEN | TokenType.EOF_TOKEN;
41
+ }
42
+ export interface StringValueToken extends IToken {
43
+ type: TokenType.STRING_TOKEN | TokenType.DELIM_TOKEN | TokenType.FUNCTION_TOKEN | TokenType.IDENT_TOKEN | TokenType.URL_TOKEN | TokenType.AT_KEYWORD_TOKEN;
44
+ value: string;
45
+ }
46
+ export interface HashToken extends IToken {
47
+ type: TokenType.HASH_TOKEN;
48
+ flags: number;
49
+ value: string;
50
+ }
51
+ export interface NumberValueToken extends IToken {
52
+ type: TokenType.PERCENTAGE_TOKEN | TokenType.NUMBER_TOKEN;
53
+ flags: number;
54
+ number: number;
55
+ }
56
+ export interface DimensionToken extends IToken {
57
+ type: TokenType.DIMENSION_TOKEN;
58
+ flags: number;
59
+ unit: string;
60
+ number: number;
61
+ }
62
+ export interface UnicodeRangeToken extends IToken {
63
+ type: TokenType.UNICODE_RANGE_TOKEN;
64
+ start: number;
65
+ end: number;
66
+ }
67
+ export type CSSToken = Token | StringValueToken | NumberValueToken | DimensionToken | UnicodeRangeToken | HashToken;
68
+ export declare const FLAG_UNRESTRICTED: number;
69
+ export declare const FLAG_ID: number;
70
+ export declare const FLAG_INTEGER: number;
71
+ export declare const FLAG_NUMBER: number;
72
+ export {};
@@ -1,75 +1,9 @@
1
- export declare const enum TokenType {
2
- STRING_TOKEN = 0,
3
- BAD_STRING_TOKEN = 1,
4
- LEFT_PARENTHESIS_TOKEN = 2,
5
- RIGHT_PARENTHESIS_TOKEN = 3,
6
- COMMA_TOKEN = 4,
7
- HASH_TOKEN = 5,
8
- DELIM_TOKEN = 6,
9
- AT_KEYWORD_TOKEN = 7,
10
- PREFIX_MATCH_TOKEN = 8,
11
- DASH_MATCH_TOKEN = 9,
12
- INCLUDE_MATCH_TOKEN = 10,
13
- LEFT_CURLY_BRACKET_TOKEN = 11,
14
- RIGHT_CURLY_BRACKET_TOKEN = 12,
15
- SUFFIX_MATCH_TOKEN = 13,
16
- SUBSTRING_MATCH_TOKEN = 14,
17
- DIMENSION_TOKEN = 15,
18
- PERCENTAGE_TOKEN = 16,
19
- NUMBER_TOKEN = 17,
20
- FUNCTION = 18,
21
- FUNCTION_TOKEN = 19,
22
- IDENT_TOKEN = 20,
23
- COLUMN_TOKEN = 21,
24
- URL_TOKEN = 22,
25
- BAD_URL_TOKEN = 23,
26
- CDC_TOKEN = 24,
27
- CDO_TOKEN = 25,
28
- COLON_TOKEN = 26,
29
- SEMICOLON_TOKEN = 27,
30
- LEFT_SQUARE_BRACKET_TOKEN = 28,
31
- RIGHT_SQUARE_BRACKET_TOKEN = 29,
32
- UNICODE_RANGE_TOKEN = 30,
33
- WHITESPACE_TOKEN = 31,
34
- EOF_TOKEN = 32
35
- }
36
- interface IToken {
37
- type: TokenType;
38
- }
39
- export interface Token extends IToken {
40
- type: TokenType.BAD_URL_TOKEN | TokenType.BAD_STRING_TOKEN | TokenType.LEFT_PARENTHESIS_TOKEN | TokenType.RIGHT_PARENTHESIS_TOKEN | TokenType.COMMA_TOKEN | TokenType.SUBSTRING_MATCH_TOKEN | TokenType.PREFIX_MATCH_TOKEN | TokenType.SUFFIX_MATCH_TOKEN | TokenType.COLON_TOKEN | TokenType.SEMICOLON_TOKEN | TokenType.LEFT_SQUARE_BRACKET_TOKEN | TokenType.RIGHT_SQUARE_BRACKET_TOKEN | TokenType.LEFT_CURLY_BRACKET_TOKEN | TokenType.RIGHT_CURLY_BRACKET_TOKEN | TokenType.DASH_MATCH_TOKEN | TokenType.INCLUDE_MATCH_TOKEN | TokenType.COLUMN_TOKEN | TokenType.WHITESPACE_TOKEN | TokenType.CDC_TOKEN | TokenType.CDO_TOKEN | TokenType.EOF_TOKEN;
41
- }
42
- export interface StringValueToken extends IToken {
43
- type: TokenType.STRING_TOKEN | TokenType.DELIM_TOKEN | TokenType.FUNCTION_TOKEN | TokenType.IDENT_TOKEN | TokenType.URL_TOKEN | TokenType.AT_KEYWORD_TOKEN;
44
- value: string;
45
- }
46
- export interface HashToken extends IToken {
47
- type: TokenType.HASH_TOKEN;
48
- flags: number;
49
- value: string;
50
- }
51
- export interface NumberValueToken extends IToken {
52
- type: TokenType.PERCENTAGE_TOKEN | TokenType.NUMBER_TOKEN;
53
- flags: number;
54
- number: number;
55
- }
56
- export interface DimensionToken extends IToken {
57
- type: TokenType.DIMENSION_TOKEN;
58
- flags: number;
59
- unit: string;
60
- number: number;
61
- }
62
- export interface UnicodeRangeToken extends IToken {
63
- type: TokenType.UNICODE_RANGE_TOKEN;
64
- start: number;
65
- end: number;
66
- }
67
- export type CSSToken = Token | StringValueToken | NumberValueToken | DimensionToken | UnicodeRangeToken | HashToken;
68
- export declare const FLAG_UNRESTRICTED: number;
69
- export declare const FLAG_ID: number;
70
- export declare const FLAG_INTEGER: number;
71
- export declare const FLAG_NUMBER: number;
72
- export declare const EOF_TOKEN: Token;
1
+ import type { CSSToken } from './token-types';
2
+ export { TokenType } from './token-types';
3
+ export type { Token, StringValueToken, HashToken, NumberValueToken, DimensionToken, UnicodeRangeToken, CSSToken } from './token-types';
4
+ export { FLAG_UNRESTRICTED, FLAG_ID, FLAG_INTEGER, FLAG_NUMBER } from './token-types';
5
+ export { isDigit, isHex, isWhiteSpace, isNameCodePoint, isValidEscape, isIdentifierStart, isNameStartCodePoint, isNumberStart } from './token-constants';
6
+ export { COMMA_TOKEN, COLON_TOKEN, SEMICOLON_TOKEN, LEFT_PARENTHESIS_TOKEN, RIGHT_PARENTHESIS_TOKEN, LEFT_CURLY_BRACKET_TOKEN, RIGHT_CURLY_BRACKET_TOKEN, LEFT_SQUARE_BRACKET_TOKEN, RIGHT_SQUARE_BRACKET_TOKEN, WHITESPACE_TOKEN, EOF_TOKEN, BAD_URL_TOKEN, BAD_STRING_TOKEN, CDC_TOKEN, CDO_TOKEN, PREFIX_MATCH_TOKEN, SUFFIX_MATCH_TOKEN, SUBSTRING_MATCH_TOKEN, DASH_MATCH_TOKEN, INCLUDE_MATCH_TOKEN, COLUMN_TOKEN } from './token-singletons';
73
7
  export declare class Tokenizer {
74
8
  private static _pool;
75
9
  private static readonly MAX_POOL_SIZE;
@@ -96,4 +30,3 @@ export declare class Tokenizer {
96
30
  private consumeEscapedCodePoint;
97
31
  private consumeName;
98
32
  }
99
- export {};
@@ -1,12 +1,53 @@
1
- import { DimensionToken, NumberValueToken } from '../syntax/tokenizer';
1
+ import { DimensionToken, NumberValueToken, TokenType } from '../syntax/tokenizer';
2
2
  import { CSSValue, CSSFunction } from '../syntax/parser';
3
+ /**
4
+ * Internal token representing a calc() expression that has both a percentage
5
+ * component and a pixel offset. Created at parse time and resolved at render
6
+ * time once the container size is known.
7
+ *
8
+ * Extends NumberValueToken so it is structurally assignable wherever
9
+ * LengthPercentage (DimensionToken | NumberValueToken) is expected,
10
+ * avoiding widespread type changes.
11
+ */
12
+ export interface CalcWithPercentage extends NumberValueToken {
13
+ type: TokenType.NUMBER_TOKEN;
14
+ /** The percentage coefficient (extracted from the calc expression). */
15
+ _calcPercentage: number;
16
+ /** The pixel offset (extracted from the calc expression). */
17
+ _calcPixelOffset: number;
18
+ }
3
19
  export type LengthPercentage = DimensionToken | NumberValueToken;
4
20
  export type LengthPercentageTuple = [LengthPercentage] | [LengthPercentage, LengthPercentage];
5
21
  export declare const isLengthPercentage: (token: CSSValue) => token is LengthPercentage;
22
+ /**
23
+ * Check if a token is a CalcWithPercentage deferred token.
24
+ * Accepts CSSValue (structural duck-type check) for use in type guards.
25
+ */
26
+ export declare const isCalcWithPercentage: (token: CSSValue) => token is CalcWithPercentage;
6
27
  /**
7
28
  * Check if a token is a calc() function
8
29
  */
9
30
  export declare const isCalcFunction: (token: CSSValue) => token is CSSFunction;
31
+ /**
32
+ * Parse a calc() token and produce a LengthPercentage.
33
+ *
34
+ * Uses two-point evaluation to extract the percentage coefficient and pixel
35
+ * offset from a calc() expression so it can be resolved later at render time
36
+ * when the container size is known.
37
+ *
38
+ * evaluate(0) → pixelOffset
39
+ * evaluate(100) → percentage + pixelOffset → percentage = evaluate(100) - pixelOffset
40
+ *
41
+ * If the expression has no percentage component, returns a plain NUMBER_TOKEN
42
+ * for backwards compatibility.
43
+ */
44
+ export declare const parseCalcForLengthPercentage: (calcToken: CSSFunction) => LengthPercentage | null;
45
+ /**
46
+ * Convenience helper for parsing an optional calc() or length-percentage value.
47
+ * Used by property descriptors that accept both calc() and regular length-percentage tokens.
48
+ * Returns null if the value is neither a calc() function nor a length-percentage token.
49
+ */
50
+ export declare const parseOptionalCalcOrLength: (value: CSSValue) => LengthPercentage | null;
10
51
  /**
11
52
  * Evaluate a calc() expression and convert to LengthPercentage token
12
53
  * Supports basic arithmetic: +, -, *, /
@@ -49,4 +49,9 @@ declare enum PseudoElementType {
49
49
  AFTER = 1
50
50
  }
51
51
  export declare const copyCSSStyles: <T extends HTMLElement | SVGElement>(style: CSSStyleDeclaration, target: T) => T;
52
+ /**
53
+ * Serialise a document type declaration to an HTML string.
54
+ * @internal – exported for testing only, not part of the public API.
55
+ */
56
+ export declare const serializeDoctype: (doctype?: DocumentType | null) => string;
52
57
  export {};
@@ -1,5 +1,3 @@
1
1
  import { ElementContainer } from './element-container';
2
2
  import { Context } from '../core/context';
3
- import { isBodyElement, isCanvasElement, isCustomElement, isElementNode, isHTMLElement, isHTMLElementNode, isIFrameElement, isImageElement, isInputElement, isLIElement, isOLElement, isScriptElement, isSelectElement, isSlotElement, isStyleElement, isSVGElement, isSVGElementNode, isTextareaElement, isTextNode, isVideoElement } from './node-type-guards';
4
- export { isBodyElement, isCanvasElement, isCustomElement, isElementNode, isHTMLElement, isHTMLElementNode, isIFrameElement, isImageElement, isInputElement, isLIElement, isOLElement, isScriptElement, isSelectElement, isSlotElement, isStyleElement, isSVGElement, isSVGElementNode, isTextareaElement, isTextNode, isVideoElement };
5
3
  export declare const parseTree: (context: Context, element: HTMLElement) => ElementContainer;
@@ -38,12 +38,8 @@ export declare class BackgroundRenderer {
38
38
  * CanvasPatterns are tied to the rendering context and must not be
39
39
  * shared across different render passes. This cache lives for the
40
40
  * duration of one html2canvas() call.
41
- *
42
- * Also reused for linear-gradient and repeating-linear-gradient
43
- * pattern canvases to avoid redundant offscreen canvas allocation.
44
41
  */
45
42
  private readonly patternCache;
46
- private static readonly PATTERN_CACHE_MAX;
47
43
  constructor(deps: BackgroundRendererDependencies);
48
44
  /**
49
45
  * Render background images for a container
@@ -95,10 +91,4 @@ export declare class BackgroundRenderer {
95
91
  * @param paths - Array of path points
96
92
  */
97
93
  private path;
98
- /**
99
- * LRU-aware get: returns value and promotes the entry to end of Map.
100
- */
101
- private lruGet;
102
- /** LRU-aware set for CanvasPattern caches. Evicts oldest entry on overflow. */
103
- private lruSet;
104
94
  }
@@ -6,6 +6,8 @@
6
6
  * - Transform effects (matrix transformations)
7
7
  * - Clip effects (overflow / border-radius clipping via Path[])
8
8
  * - Clip-path effects (CSS clip-path shapes: inset, circle, ellipse, polygon, path)
9
+ * - Blend effects (mix-blend-mode)
10
+ * - Filter effects (CSS filter functions)
9
11
  */
10
12
  import { IElementEffect } from '../effects';
11
13
  import { Path } from '../path';
@@ -26,40 +28,63 @@ export interface EffectsPathCallback {
26
28
  *
27
29
  * Manages rendering effects stack including opacity, transforms, and clipping.
28
30
  * Extracted from CanvasRenderer to improve code organization and maintainability.
31
+ *
32
+ * ## Save/restore optimisation
33
+ *
34
+ * Canvas `save()` / `restore()` snapshot and restore the entire canvas state
35
+ * (transform matrix, clip region, compositing mode, filter, shadow, …) which
36
+ * is relatively expensive. The old implementation called `save()` / `restore()`
37
+ * for every single effect unconditionally.
38
+ *
39
+ * This implementation does a **batch pre-scan** before applying effects:
40
+ *
41
+ * | Effect type | Modifies | Reversible? | Needs save? |
42
+ * |--------------------|----------------------|---------------|-------------|
43
+ * | TransformEffect | transform matrix | ❌ irreversible | **YES** |
44
+ * | ClipEffect | clip region | ❌ cumulative | **YES** |
45
+ * | ClipPathEffect | clip region | ❌ cumulative | **YES** |
46
+ * | OpacityEffect | globalAlpha | ✅ scalar | NO |
47
+ * | BlendEffect | globalCompositeOp | ✅ scalar | NO |
48
+ * | FilterEffect | filter + shadow | ✅ string+vec | NO |
49
+ *
50
+ * When the batch contains *only* lightweight effects (opacity / blend / filter)
51
+ * we skip `save()` entirely and manually reset properties on pop.
52
+ *
53
+ * When the batch contains at least one heavyweight effect (transform / clip /
54
+ * clip-path) we call `save()` **once** before the first heavyweight effect and
55
+ * `restore()` **once** when that effect is popped.
29
56
  */
30
57
  export declare class EffectsRenderer {
31
58
  private readonly ctx;
32
59
  private readonly pathCallback;
33
60
  private readonly activeEffects;
61
+ /** Whether a canvas state save was performed for the current batch. */
62
+ private didSave;
63
+ /** Index (0-based, from start of activeEffects array) of the last
64
+ * heavyweight effect in the batch — the one whose pop triggers
65
+ * restore(). Set to -1 when no save was performed. */
66
+ private saveAtDepth;
34
67
  constructor(deps: EffectsRendererDependencies, pathCallback: EffectsPathCallback);
35
68
  /**
36
- * Apply multiple effects
37
- * Clears existing effects and applies new ones
38
- *
39
- * @param effects - Array of effects to apply
69
+ * Apply multiple effects.
70
+ * Clears existing effects and applies new ones.
40
71
  */
41
72
  applyEffects(effects: IElementEffect[]): void;
42
73
  /**
43
- * Apply a single effect
44
- *
45
- * @param effect - Effect to apply
74
+ * Apply a single effect (called internally by applyEffects).
46
75
  */
47
- applyEffect(effect: IElementEffect): void;
76
+ private applyEffect;
48
77
  /**
49
- * Remove the most recent effect
50
- * Restores the canvas state before the effect was applied
78
+ * Remove the most recent effect.
79
+ * Restores canvas state if needed.
51
80
  */
52
- popEffect(): void;
81
+ private popEffect;
53
82
  /**
54
- * Get the current number of active effects
55
- *
56
- * @returns Number of active effects
83
+ * Get the current number of active effects.
57
84
  */
58
85
  getActiveEffectCount(): number;
59
86
  /**
60
- * Check if there are any active effects
61
- *
62
- * @returns True if there are active effects
87
+ * Check if there are any active effects.
63
88
  */
64
89
  hasActiveEffects(): boolean;
65
90
  }
@@ -10,18 +10,18 @@
10
10
  * - Paint order (fill/stroke)
11
11
  * - Font styles
12
12
  */
13
- import { Context } from '../../core/context';
14
13
  import { TextContainer } from '../../dom/text-container';
15
14
  import { CSSParsedDeclaration } from '../../css';
16
15
  import { Bounds } from '../../css/layout/bounds';
17
16
  import { TextBounds } from '../../css/layout/text';
18
17
  import { WRITING_MODE } from '../../css/property-descriptors/writing-mode';
18
+ import { FontMetrics } from '../font-metrics';
19
19
  /**
20
20
  * Dependencies required for TextRenderer
21
21
  */
22
22
  export interface TextRendererDependencies {
23
23
  ctx: CanvasRenderingContext2D;
24
- context: Context;
24
+ fontMetrics: FontMetrics;
25
25
  options: {
26
26
  scale: number;
27
27
  };
@@ -35,9 +35,22 @@ export declare const hasCJKCharacters: (text: string) => boolean;
35
35
  */
36
36
  export declare class TextRenderer {
37
37
  private readonly ctx;
38
+ private readonly fontMetrics;
38
39
  private readonly options;
39
40
  private readonly decorationRenderer;
41
+ /**
42
+ * Per-render glyph width cache. Keyed by glyph + font string,
43
+ * avoids redundant `measureText` calls when letter-spacing is non-zero.
44
+ * Cleared at the start of each renderTextNode call.
45
+ */
46
+ private glyphWidthCache;
40
47
  constructor(deps: TextRendererDependencies);
48
+ /**
49
+ * Returns the cached width for a glyph+font pair, measuring via
50
+ * measureText if not yet cached. Only used when letterSpacing !== 0
51
+ * (the `canRenderWholeText` fast path handles the zero-spacing case).
52
+ */
53
+ private cachedMeasureText;
41
54
  /**
42
55
  * Iterate grapheme clusters one-by-one, applying correct letter-spacing and
43
56
  * per-script baseline for each character.
@@ -1,6 +1,8 @@
1
1
  import { ElementContainer } from '../dom/element-container';
2
2
  import { BoundCurves } from './bound-curves';
3
- import { EffectTarget, IElementEffect } from './effects';
3
+ import { ClipPathEffect, EffectTarget, IElementEffect } from './effects';
4
+ import { Bounds } from '../css/layout/bounds';
5
+ import { ClipPathValue, ShapeRadius } from '../css/property-descriptors/clip-path';
4
6
  export declare class StackingContext {
5
7
  element: ElementPaint;
6
8
  negativeZIndex: StackingContext[];
@@ -21,4 +23,27 @@ export declare class ElementPaint {
21
23
  constructor(container: ElementContainer, parent: ElementPaint | null);
22
24
  getEffects(target: EffectTarget): IElementEffect[];
23
25
  }
26
+ /** @internal – exported for testing only. */
27
+ export declare const hasOverflowClip: (styles: ElementContainer["styles"]) => boolean;
28
+ /**
29
+ * Resolve a `closest-side` or `farthest-side` shape-radius keyword to pixels
30
+ * for a single axis. Used by both `circle()` (per-axis) and `ellipse()`.
31
+ *
32
+ * @param r - The ShapeRadius (keyword or length-percentage).
33
+ * @param center - Absolute center coordinate on this axis (cx or cy).
34
+ * @param start - Absolute start of the reference box on this axis.
35
+ * @param end - Absolute end of the reference box on this axis.
36
+ * @param dimRef - Reference dimension for resolving a length-percentage value.
37
+ * @internal – exported for testing only.
38
+ */
39
+ export declare const resolveAxisRadius: (r: ShapeRadius, center: number, start: number, end: number, dimRef: number) => number;
40
+ /**
41
+ * Convert a parsed ClipPathValue + element bounds into a ClipPathEffect whose
42
+ * `applyClip` callback draws the clip shape directly onto the canvas context.
43
+ *
44
+ * All coordinates are computed in page-absolute space at construction time so
45
+ * the callback itself is allocation-free and executes synchronously.
46
+ * @internal – exported for testing only.
47
+ */
48
+ export declare const buildClipPathEffect: (clipPath: ClipPathValue, bounds: Bounds) => ClipPathEffect | null;
24
49
  export declare const parseStackingContexts: (container: ElementContainer) => StackingContext;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "html2canvas-pro",
3
3
  "description": "Screenshots with JavaScript. Next generation!",
4
4
  "type": "module",
5
- "main": "dist/html2canvas-pro.js",
5
+ "main": "dist/html2canvas-pro.cjs",
6
6
  "module": "dist/html2canvas-pro.esm.js",
7
7
  "typings": "dist/types/index.d.ts",
8
8
  "browser": "dist/html2canvas-pro.esm.js",
@@ -15,11 +15,11 @@
15
15
  ".": {
16
16
  "types": "./dist/types/index.d.ts",
17
17
  "import": "./dist/html2canvas-pro.esm.js",
18
- "require": "./dist/html2canvas-pro.js",
18
+ "require": "./dist/html2canvas-pro.cjs",
19
19
  "default": "./dist/html2canvas-pro.esm.js"
20
20
  }
21
21
  },
22
- "version": "2.2.4",
22
+ "version": "2.3.1",
23
23
  "author": {
24
24
  "name": "yorickshan",
25
25
  "email": "yorickshan@gmail.com",
@@ -87,14 +87,13 @@
87
87
  "puppeteer": "^24.34.0",
88
88
  "replace-in-file": "^8.4.0",
89
89
  "rimraf": "^6.0.1",
90
- "rolldown": "^1.1.2",
90
+ "rolldown": "^1.2.0",
91
91
  "serve-index": "^1.9.1",
92
92
  "slash": "5.1.0",
93
93
  "ts-node": "^10.9.2",
94
94
  "tsx": "^4.22.3",
95
95
  "typedoc": "^0.28.19",
96
96
  "typescript": "^5.5.4",
97
- "uglify-js": "^3.13.10",
98
97
  "vitepress": "^1.6.4",
99
98
  "vitest": "^3.2.6",
100
99
  "yargs": "^18.0.0"
@@ -111,9 +110,8 @@
111
110
  },
112
111
  "scripts": {
113
112
  "prebuild": "rimraf dist/ && rimraf build/ && mkdir -p dist && mkdir -p build",
114
- "build": "tsc --module commonjs -p tsconfig.build.json && rolldown -c rolldown.config.ts && pnpm build:create-reftest-list && rolldown -c tests/rolldown.testrunner.config.ts && pnpm build:minify",
113
+ "build": "tsc --module commonjs -p tsconfig.build.json && rolldown -c rolldown.config.ts && pnpm build:create-reftest-list && rolldown -c tests/rolldown.testrunner.config.ts",
115
114
  "build:testrunner": "rolldown -c tests/rolldown.testrunner.config.ts",
116
- "build:minify": "uglifyjs --compress --comments /^!/ -o dist/html2canvas-pro.min.js --mangle -- dist/html2canvas-pro.js",
117
115
  "build:reftest-result-list": "tsx scripts/create-reftest-result-list.ts",
118
116
  "build:create-reftest-list": "tsx scripts/create-reftest-list.ts tests/reftests/ignore.txt build/reftests.js",
119
117
  "release": "sh scripts/version-upgrade.sh",