html2canvas-pro 2.1.0 → 2.1.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 (186) hide show
  1. package/dist/html2canvas-pro.esm.js +21 -7
  2. package/dist/html2canvas-pro.esm.js.map +1 -1
  3. package/dist/html2canvas-pro.js +21 -7
  4. package/dist/html2canvas-pro.js.map +1 -1
  5. package/dist/html2canvas-pro.min.js +3 -3
  6. package/dist/lib/core/cache-storage.js +2 -2
  7. package/dist/lib/core/features.js +2 -2
  8. package/dist/lib/render/canvas/background-renderer.js +6 -0
  9. package/dist/lib/render/canvas/canvas-renderer.js +5 -1
  10. package/dist/lib/render/canvas/foreignobject-renderer.js +5 -1
  11. package/package.json +3 -11
  12. package/dist/lib/invariant.js +0 -9
  13. package/dist/types/invariant.d.ts +0 -1
  14. package/src/__tests__/index.ts +0 -99
  15. package/src/config.ts +0 -107
  16. package/src/core/__mocks__/cache-storage.ts +0 -1
  17. package/src/core/__mocks__/context.ts +0 -19
  18. package/src/core/__mocks__/features.ts +0 -8
  19. package/src/core/__mocks__/logger.ts +0 -17
  20. package/src/core/__tests__/cache-storage.test.ts +0 -205
  21. package/src/core/__tests__/cache-storage.ts +0 -278
  22. package/src/core/__tests__/logger.ts +0 -29
  23. package/src/core/__tests__/validator.ts +0 -359
  24. package/src/core/bitwise.ts +0 -1
  25. package/src/core/cache-storage.ts +0 -315
  26. package/src/core/context.ts +0 -31
  27. package/src/core/debugger.ts +0 -32
  28. package/src/core/features.ts +0 -222
  29. package/src/core/logger.ts +0 -64
  30. package/src/core/origin-checker.ts +0 -57
  31. package/src/core/performance-monitor.ts +0 -241
  32. package/src/core/render-element.ts +0 -272
  33. package/src/core/util.ts +0 -1
  34. package/src/core/validator.ts +0 -593
  35. package/src/css/index.ts +0 -427
  36. package/src/css/layout/__mocks__/bounds.ts +0 -6
  37. package/src/css/layout/bounds.ts +0 -79
  38. package/src/css/layout/text.ts +0 -161
  39. package/src/css/property-descriptor.ts +0 -49
  40. package/src/css/property-descriptors/__tests__/background-tests.ts +0 -65
  41. package/src/css/property-descriptors/__tests__/clip-path.test.ts +0 -280
  42. package/src/css/property-descriptors/__tests__/font-family.ts +0 -25
  43. package/src/css/property-descriptors/__tests__/image-rendering-integration.test.ts +0 -153
  44. package/src/css/property-descriptors/__tests__/image-rendering-performance.test.ts +0 -175
  45. package/src/css/property-descriptors/__tests__/image-rendering.test.ts +0 -72
  46. package/src/css/property-descriptors/__tests__/paint-order.ts +0 -87
  47. package/src/css/property-descriptors/__tests__/text-shadow.ts +0 -94
  48. package/src/css/property-descriptors/__tests__/transform-tests.ts +0 -18
  49. package/src/css/property-descriptors/background-clip.ts +0 -30
  50. package/src/css/property-descriptors/background-color.ts +0 -9
  51. package/src/css/property-descriptors/background-image.ts +0 -27
  52. package/src/css/property-descriptors/background-origin.ts +0 -31
  53. package/src/css/property-descriptors/background-position.ts +0 -38
  54. package/src/css/property-descriptors/background-repeat.ts +0 -44
  55. package/src/css/property-descriptors/background-size.ts +0 -27
  56. package/src/css/property-descriptors/border-color.ts +0 -13
  57. package/src/css/property-descriptors/border-radius.ts +0 -19
  58. package/src/css/property-descriptors/border-style.ts +0 -34
  59. package/src/css/property-descriptors/border-width.ts +0 -20
  60. package/src/css/property-descriptors/box-shadow.ts +0 -60
  61. package/src/css/property-descriptors/clip-path.ts +0 -271
  62. package/src/css/property-descriptors/color.ts +0 -9
  63. package/src/css/property-descriptors/content.ts +0 -26
  64. package/src/css/property-descriptors/counter-increment.ts +0 -43
  65. package/src/css/property-descriptors/counter-reset.ts +0 -36
  66. package/src/css/property-descriptors/direction.ts +0 -23
  67. package/src/css/property-descriptors/display.ts +0 -117
  68. package/src/css/property-descriptors/duration.ts +0 -14
  69. package/src/css/property-descriptors/float.ts +0 -29
  70. package/src/css/property-descriptors/font-family.ts +0 -38
  71. package/src/css/property-descriptors/font-size.ts +0 -9
  72. package/src/css/property-descriptors/font-style.ts +0 -25
  73. package/src/css/property-descriptors/font-variant.ts +0 -12
  74. package/src/css/property-descriptors/font-weight.ts +0 -26
  75. package/src/css/property-descriptors/image-rendering.ts +0 -33
  76. package/src/css/property-descriptors/letter-spacing.ts +0 -25
  77. package/src/css/property-descriptors/line-break.ts +0 -22
  78. package/src/css/property-descriptors/line-height.ts +0 -22
  79. package/src/css/property-descriptors/list-style-image.ts +0 -19
  80. package/src/css/property-descriptors/list-style-position.ts +0 -22
  81. package/src/css/property-descriptors/list-style-type.ts +0 -179
  82. package/src/css/property-descriptors/margin.ts +0 -13
  83. package/src/css/property-descriptors/mix-blend-mode.ts +0 -35
  84. package/src/css/property-descriptors/object-fit.ts +0 -39
  85. package/src/css/property-descriptors/opacity.ts +0 -15
  86. package/src/css/property-descriptors/overflow-wrap.ts +0 -22
  87. package/src/css/property-descriptors/overflow.ts +0 -34
  88. package/src/css/property-descriptors/padding.ts +0 -14
  89. package/src/css/property-descriptors/paint-order.ts +0 -42
  90. package/src/css/property-descriptors/position.ts +0 -30
  91. package/src/css/property-descriptors/quotes.ts +0 -57
  92. package/src/css/property-descriptors/rotate.ts +0 -34
  93. package/src/css/property-descriptors/text-align.ts +0 -26
  94. package/src/css/property-descriptors/text-decoration-color.ts +0 -9
  95. package/src/css/property-descriptors/text-decoration-line.ts +0 -38
  96. package/src/css/property-descriptors/text-decoration-style.ts +0 -32
  97. package/src/css/property-descriptors/text-decoration-thickness.ts +0 -30
  98. package/src/css/property-descriptors/text-overflow.ts +0 -23
  99. package/src/css/property-descriptors/text-shadow.ts +0 -52
  100. package/src/css/property-descriptors/text-transform.ts +0 -27
  101. package/src/css/property-descriptors/text-underline-offset.ts +0 -27
  102. package/src/css/property-descriptors/transform-origin.ts +0 -29
  103. package/src/css/property-descriptors/transform.ts +0 -74
  104. package/src/css/property-descriptors/visibility.ts +0 -25
  105. package/src/css/property-descriptors/webkit-line-clamp.ts +0 -30
  106. package/src/css/property-descriptors/webkit-text-stroke-color.ts +0 -8
  107. package/src/css/property-descriptors/webkit-text-stroke-width.ts +0 -15
  108. package/src/css/property-descriptors/word-break.ts +0 -25
  109. package/src/css/property-descriptors/writing-mode.ts +0 -37
  110. package/src/css/property-descriptors/z-index.ts +0 -27
  111. package/src/css/syntax/__tests__/tokernizer-tests.ts +0 -29
  112. package/src/css/syntax/parser.ts +0 -188
  113. package/src/css/syntax/tokenizer.ts +0 -822
  114. package/src/css/type-descriptor.ts +0 -7
  115. package/src/css/types/__tests__/color-tests.ts +0 -147
  116. package/src/css/types/__tests__/image-tests.ts +0 -239
  117. package/src/css/types/angle.ts +0 -86
  118. package/src/css/types/color-math.ts +0 -22
  119. package/src/css/types/color-spaces/a98.ts +0 -86
  120. package/src/css/types/color-spaces/p3.ts +0 -92
  121. package/src/css/types/color-spaces/pro-photo.ts +0 -87
  122. package/src/css/types/color-spaces/rec2020.ts +0 -90
  123. package/src/css/types/color-spaces/srgb.ts +0 -87
  124. package/src/css/types/color-utilities.ts +0 -452
  125. package/src/css/types/color.ts +0 -485
  126. package/src/css/types/functions/-prefix-linear-gradient.ts +0 -35
  127. package/src/css/types/functions/-prefix-radial-gradient.ts +0 -106
  128. package/src/css/types/functions/-webkit-gradient.ts +0 -69
  129. package/src/css/types/functions/__tests__/radial-gradient.ts +0 -69
  130. package/src/css/types/functions/counter.ts +0 -511
  131. package/src/css/types/functions/gradient.ts +0 -206
  132. package/src/css/types/functions/linear-gradient.ts +0 -28
  133. package/src/css/types/functions/radial-gradient.ts +0 -101
  134. package/src/css/types/image.ts +0 -120
  135. package/src/css/types/index.ts +0 -1
  136. package/src/css/types/length-percentage.ts +0 -137
  137. package/src/css/types/length.ts +0 -7
  138. package/src/css/types/time.ts +0 -20
  139. package/src/dom/__mocks__/document-cloner.ts +0 -22
  140. package/src/dom/__tests__/dom-normalizer.test.ts +0 -133
  141. package/src/dom/__tests__/element-container.test.ts +0 -129
  142. package/src/dom/document-cloner.ts +0 -929
  143. package/src/dom/dom-normalizer.ts +0 -133
  144. package/src/dom/element-container.ts +0 -75
  145. package/src/dom/elements/li-element-container.ts +0 -10
  146. package/src/dom/elements/ol-element-container.ts +0 -12
  147. package/src/dom/elements/select-element-container.ts +0 -10
  148. package/src/dom/elements/textarea-element-container.ts +0 -9
  149. package/src/dom/node-parser.ts +0 -177
  150. package/src/dom/node-type-guards.ts +0 -70
  151. package/src/dom/replaced-elements/canvas-element-container.ts +0 -15
  152. package/src/dom/replaced-elements/iframe-element-container.ts +0 -55
  153. package/src/dom/replaced-elements/image-element-container.ts +0 -16
  154. package/src/dom/replaced-elements/index.ts +0 -5
  155. package/src/dom/replaced-elements/input-element-container.ts +0 -105
  156. package/src/dom/replaced-elements/pseudo-elements.ts +0 -0
  157. package/src/dom/replaced-elements/svg-element-container.ts +0 -23
  158. package/src/dom/text-container.ts +0 -42
  159. package/src/global.d.ts +0 -19
  160. package/src/index.ts +0 -82
  161. package/src/invariant.ts +0 -5
  162. package/src/options.ts +0 -55
  163. package/src/render/__tests__/object-fit.test.ts +0 -85
  164. package/src/render/background.ts +0 -298
  165. package/src/render/bezier-curve.ts +0 -47
  166. package/src/render/border.ts +0 -165
  167. package/src/render/bound-curves.ts +0 -388
  168. package/src/render/box-sizing.ts +0 -31
  169. package/src/render/canvas/__tests__/background-renderer.test.ts +0 -72
  170. package/src/render/canvas/__tests__/border-renderer.test.ts +0 -24
  171. package/src/render/canvas/__tests__/effects-renderer.test.ts +0 -32
  172. package/src/render/canvas/__tests__/text-renderer.test.ts +0 -471
  173. package/src/render/canvas/background-renderer.ts +0 -271
  174. package/src/render/canvas/border-renderer.ts +0 -224
  175. package/src/render/canvas/canvas-path.ts +0 -31
  176. package/src/render/canvas/canvas-renderer.ts +0 -641
  177. package/src/render/canvas/effects-renderer.ts +0 -130
  178. package/src/render/canvas/foreignobject-renderer.ts +0 -53
  179. package/src/render/canvas/text-renderer.ts +0 -700
  180. package/src/render/effects.ts +0 -75
  181. package/src/render/font-metrics.ts +0 -72
  182. package/src/render/object-fit.ts +0 -100
  183. package/src/render/path.ts +0 -37
  184. package/src/render/renderer-interface.ts +0 -28
  185. package/src/render/stacking-context.ts +0 -386
  186. package/src/render/vector.ts +0 -19
@@ -245,5 +245,5 @@ const INLINE_IMG = /^data:image\/.*/i;
245
245
  const isRenderable = (src) => features_1.FEATURES.SUPPORT_SVG_DRAWING || !isSVG(src);
246
246
  const isInlineImage = (src) => INLINE_IMG.test(src);
247
247
  const isInlineBase64Image = (src) => INLINE_BASE64.test(src);
248
- const isBlobImage = (src) => src.substr(0, 4) === 'blob';
249
- const isSVG = (src) => src.substr(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);
248
+ const isBlobImage = (src) => src.substring(0, 4) === 'blob';
249
+ const isSVG = (src) => src.slice(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);
@@ -79,7 +79,7 @@ const testForeignObject = (document) => {
79
79
  canvas.height = size;
80
80
  const ctx = canvas.getContext('2d');
81
81
  if (!ctx) {
82
- return Promise.reject(false);
82
+ return Promise.reject(new Error('Failed to get 2D rendering context'));
83
83
  }
84
84
  ctx.fillStyle = 'rgb(0, 255, 0)';
85
85
  ctx.fillRect(0, 0, size, size);
@@ -101,7 +101,7 @@ const testForeignObject = (document) => {
101
101
  // Firefox 55 does not render inline <img /> tags
102
102
  return isGreenPixel(data)
103
103
  ? (0, exports.loadSerializedSVG)((0, exports.createForeignObjectSVG)(size, size, 0, 0, node))
104
- : Promise.reject(false);
104
+ : Promise.reject(new Error('ForeignObject rendering not supported'));
105
105
  })
106
106
  .then((img) => {
107
107
  ctx.drawImage(img, 0, 0);
@@ -87,6 +87,9 @@ class BackgroundRenderer {
87
87
  canvas.width = width;
88
88
  canvas.height = height;
89
89
  const ctx = canvas.getContext('2d');
90
+ if (!ctx) {
91
+ return;
92
+ }
90
93
  const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
91
94
  (0, gradient_1.processColorStops)(backgroundImage.stops, lineLength || 1).forEach((colorStop) => gradient.addColorStop(colorStop.stop, (0, color_utilities_1.asString)(colorStop.color)));
92
95
  ctx.fillStyle = gradient;
@@ -168,6 +171,9 @@ class BackgroundRenderer {
168
171
  canvas.width = Math.max(1, width);
169
172
  canvas.height = Math.max(1, height);
170
173
  const ctx = canvas.getContext('2d');
174
+ if (!ctx) {
175
+ return image;
176
+ }
171
177
  // Apply image smoothing based on CSS image-rendering property
172
178
  if (imageRendering === image_rendering_1.IMAGE_RENDERING.PIXELATED || imageRendering === image_rendering_1.IMAGE_RENDERING.CRISP_EDGES) {
173
179
  this.context.logger.debug(`Disabling image smoothing for background image due to CSS image-rendering`);
@@ -34,7 +34,11 @@ class CanvasRenderer {
34
34
  this.context = context;
35
35
  this.options = options;
36
36
  this.canvas = options.canvas ? options.canvas : document.createElement('canvas');
37
- this.ctx = this.canvas.getContext('2d');
37
+ const ctx = this.canvas.getContext('2d');
38
+ if (!ctx) {
39
+ throw new Error('Failed to get 2D rendering context from canvas');
40
+ }
41
+ this.ctx = ctx;
38
42
  if (!options.canvas) {
39
43
  this.canvas.width = Math.floor(options.width * options.scale);
40
44
  this.canvas.height = Math.floor(options.height * options.scale);
@@ -8,7 +8,11 @@ class ForeignObjectRenderer {
8
8
  this.context = context;
9
9
  this.options = options;
10
10
  this.canvas = options.canvas ? options.canvas : document.createElement('canvas');
11
- this.ctx = this.canvas.getContext('2d');
11
+ const ctx = this.canvas.getContext('2d');
12
+ if (!ctx) {
13
+ throw new Error('Failed to get 2D rendering context from canvas');
14
+ }
15
+ this.ctx = ctx;
12
16
  this.canvas.width = Math.floor(options.width * options.scale);
13
17
  this.canvas.height = Math.floor(options.height * options.scale);
14
18
  this.canvas.style.width = `${options.width}px`;
package/package.json CHANGED
@@ -9,7 +9,6 @@
9
9
  "sideEffects": false,
10
10
  "files": [
11
11
  "dist/",
12
- "src/",
13
12
  "LICENSE"
14
13
  ],
15
14
  "exports": {
@@ -20,7 +19,7 @@
20
19
  "default": "./dist/html2canvas-pro.esm.js"
21
20
  }
22
21
  },
23
- "version": "2.1.0",
22
+ "version": "2.1.1",
24
23
  "author": {
25
24
  "name": "yorickshan",
26
25
  "email": "yorickshan@gmail.com",
@@ -48,14 +47,11 @@
48
47
  "@rollup/plugin-typescript": "^12.3.0",
49
48
  "@types/chai": "^5.2.3",
50
49
  "@types/express": "^5.0.6",
51
- "@types/filenamify-url": "^2.0.1",
52
- "@types/glob": "^9.0.0",
53
50
  "@types/karma": "^6.3.0",
54
51
  "@types/mocha": "^10.0.7",
55
52
  "@types/node": "^25.0.3",
56
53
  "@types/platform": "^1.3.4",
57
54
  "@types/pngjs": "^6.0.5",
58
- "@types/promise-polyfill": "^6.0.3",
59
55
  "@types/serve-index": "^1.9.4",
60
56
  "@typescript-eslint/eslint-plugin": "^8.50.0",
61
57
  "@typescript-eslint/parser": "^8.50.0",
@@ -65,10 +61,10 @@
65
61
  "body-parser": "^2.2.1",
66
62
  "chai": "6.2.2",
67
63
  "change-case": "^5.4.4",
68
- "conventional-changelog-cli": "^5.0.0",
64
+ "conventional-changelog": "^7.2.1",
65
+ "conventional-changelog-conventionalcommits": "^9.3.1",
69
66
  "cors": "^2.8.5",
70
67
  "cz-conventional-changelog": "^3.3.0",
71
- "es6-promise": "^4.2.8",
72
68
  "eslint": "^9.13.0",
73
69
  "eslint-config-prettier": "^10.1.8",
74
70
  "eslint-plugin-prettier": "^5.5.4",
@@ -76,8 +72,6 @@
76
72
  "filenamify-url": "4.0.0",
77
73
  "glob": "^13.0.0",
78
74
  "husky": "^9.1.7",
79
- "jquery": "^3.5.1",
80
- "js-polyfills": "^0.1.42",
81
75
  "jsdom": "^29.1.1",
82
76
  "karma": "^6.3.2",
83
77
  "karma-chrome-launcher": "^3.1.0",
@@ -101,7 +95,6 @@
101
95
  "rollup-plugin-sourcemaps": "^0.6.3",
102
96
  "serve-index": "^1.9.1",
103
97
  "slash": "5.1.0",
104
- "standard-version": "^9.5.0",
105
98
  "ts-node": "^10.9.2",
106
99
  "tsx": "^4.22.3",
107
100
  "typedoc": "^0.28.19",
@@ -142,7 +135,6 @@
142
135
  "watch:unittest": "vitest",
143
136
  "start": "tsx tests/server --port=8080 --cors=8081",
144
137
  "commitlint": "commitlint --config .commitlintrc.json -e -V",
145
- "tag": "sh scripts/create-tag.sh",
146
138
  "docs:dev": "vitepress dev docs",
147
139
  "docs:build": "vitepress build docs",
148
140
  "docs:preview": "vitepress preview docs",
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.invariant = void 0;
4
- const invariant = (assertion, error) => {
5
- if (!assertion) {
6
- console.error(error);
7
- }
8
- };
9
- exports.invariant = invariant;
@@ -1 +0,0 @@
1
- export declare const invariant: (assertion: boolean, error: string) => void;
@@ -1,99 +0,0 @@
1
- import html2canvas from '../index';
2
-
3
- import { CanvasRenderer } from '../render/canvas/canvas-renderer';
4
- import { DocumentCloner } from '../dom/document-cloner';
5
- import { COLORS } from '../css/types/color';
6
-
7
- vi.mock('../core/logger');
8
- vi.mock('../css/layout/bounds');
9
- vi.mock('../dom/document-cloner');
10
- vi.mock('../dom/node-parser', () => {
11
- return {
12
- isBodyElement: () => false,
13
- isHTMLElement: () => false,
14
- parseTree: vi.fn().mockImplementation(() => {
15
- return { styles: {}, restoreTree: vi.fn() };
16
- })
17
- };
18
- });
19
-
20
- vi.mock('../render/stacking-context');
21
- vi.mock('../render/canvas/canvas-renderer');
22
-
23
- describe('html2canvas', () => {
24
- const element = {
25
- ownerDocument: {
26
- defaultView: {
27
- document: {
28
- createElement: () => ({ href: '' })
29
- },
30
- location: { href: 'http://localhost/' },
31
- pageXOffset: 12,
32
- pageYOffset: 34,
33
- innerWidth: 800,
34
- innerHeight: 600
35
- }
36
- }
37
- } as unknown as HTMLElement;
38
-
39
- it('should render with an element', async () => {
40
- DocumentCloner.destroy = vi.fn().mockReturnValue(true);
41
- await html2canvas(element);
42
- expect(CanvasRenderer).toHaveBeenLastCalledWith(
43
- expect.objectContaining({
44
- cache: expect.any(Object),
45
- logger: expect.any(Object),
46
- windowBounds: expect.objectContaining({ left: 12, top: 34 })
47
- }),
48
- expect.objectContaining({
49
- backgroundColor: 0xffffffff,
50
- scale: 1,
51
- height: 50,
52
- width: 200,
53
- x: 0,
54
- y: 0,
55
- canvas: undefined
56
- })
57
- );
58
- expect(DocumentCloner.destroy).toBeCalled();
59
- });
60
-
61
- it('should have transparent background with backgroundColor: null', async () => {
62
- await html2canvas(element, { backgroundColor: null });
63
- expect(CanvasRenderer).toHaveBeenLastCalledWith(
64
- expect.anything(),
65
- expect.objectContaining({
66
- backgroundColor: COLORS.TRANSPARENT
67
- })
68
- );
69
- });
70
-
71
- it('should use existing canvas when given as option', async () => {
72
- const canvas = {} as HTMLCanvasElement;
73
- await html2canvas(element, { canvas });
74
- expect(CanvasRenderer).toHaveBeenLastCalledWith(
75
- expect.anything(),
76
- expect.objectContaining({
77
- canvas
78
- })
79
- );
80
- });
81
-
82
- it('should not remove cloned window when removeContainer: false', async () => {
83
- DocumentCloner.destroy = vi.fn();
84
- await html2canvas(element, { removeContainer: false });
85
- expect(CanvasRenderer).toHaveBeenLastCalledWith(
86
- expect.anything(),
87
- expect.objectContaining({
88
- backgroundColor: 0xffffffff,
89
- scale: 1,
90
- height: 50,
91
- width: 200,
92
- x: 0,
93
- y: 0,
94
- canvas: undefined
95
- })
96
- );
97
- expect(DocumentCloner.destroy).not.toBeCalled();
98
- });
99
- });
package/src/config.ts DELETED
@@ -1,107 +0,0 @@
1
- import { Cache } from './core/cache-storage';
2
-
3
- /**
4
- * Configuration options for Html2Canvas
5
- *
6
- * This class manages global configuration without using module-level static variables.
7
- * Each html2canvas invocation can have its own configuration instance.
8
- */
9
- export interface ConfigOptions {
10
- /**
11
- * Window object to use for DOM operations
12
- */
13
- window?: Window;
14
-
15
- /**
16
- * CSP nonce for inline styles
17
- * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
18
- */
19
- cspNonce?: string;
20
-
21
- /**
22
- * Cache instance to reuse across multiple calls
23
- * Useful for avoiding redundant image loads
24
- */
25
- cache?: Cache;
26
- }
27
-
28
- /**
29
- * Html2Canvas Configuration
30
- *
31
- * Manages configuration state for html2canvas rendering.
32
- * Eliminates the need for global static variables.
33
- */
34
- export class Html2CanvasConfig {
35
- readonly window: Window;
36
- readonly cspNonce?: string;
37
- readonly cache?: Cache;
38
-
39
- constructor(options: ConfigOptions = {}) {
40
- const resolvedWindow = options.window || (typeof window !== 'undefined' ? window : undefined);
41
-
42
- if (!resolvedWindow) {
43
- throw new Error('Window object is required but not available');
44
- }
45
-
46
- this.window = resolvedWindow;
47
- this.cspNonce = options.cspNonce;
48
- this.cache = options.cache;
49
- }
50
-
51
- /**
52
- * Create configuration from an element
53
- * Extracts window from element's owner document
54
- */
55
- static fromElement(element: HTMLElement, options: Partial<ConfigOptions> = {}): Html2CanvasConfig {
56
- const ownerDocument = element.ownerDocument;
57
-
58
- if (!ownerDocument) {
59
- throw new Error('Element is not attached to a document');
60
- }
61
-
62
- const defaultView = ownerDocument.defaultView;
63
-
64
- if (!defaultView) {
65
- throw new Error('Document is not attached to a window');
66
- }
67
-
68
- return new Html2CanvasConfig({
69
- window: defaultView,
70
- ...options
71
- });
72
- }
73
-
74
- /**
75
- * Clone configuration with override options
76
- */
77
- clone(options: Partial<ConfigOptions> = {}): Html2CanvasConfig {
78
- return new Html2CanvasConfig({
79
- window: options.window || this.window,
80
- cspNonce: options.cspNonce ?? this.cspNonce,
81
- cache: options.cache ?? this.cache
82
- });
83
- }
84
- }
85
-
86
- /**
87
- * Default global configuration (for backward compatibility)
88
- * @deprecated Use Html2CanvasConfig instances instead
89
- */
90
- let _defaultConfig: Html2CanvasConfig | null = null;
91
-
92
- /**
93
- * Set default configuration
94
- * @deprecated Pass configuration directly to html2canvas instead
95
- */
96
- export function setDefaultConfig(config: Html2CanvasConfig): void {
97
- console.warn('[html2canvas-pro] setDefaultConfig is deprecated. Pass configuration to html2canvas directly.');
98
- _defaultConfig = config;
99
- }
100
-
101
- /**
102
- * Get default configuration
103
- * @deprecated Pass configuration directly to html2canvas instead
104
- */
105
- export function getDefaultConfig(): Html2CanvasConfig | null {
106
- return _defaultConfig;
107
- }
@@ -1 +0,0 @@
1
- export class CacheStorage {}
@@ -1,19 +0,0 @@
1
- import { logger, Logger } from './logger';
2
-
3
- export class Context {
4
- readonly logger: Logger = logger;
5
-
6
- readonly _cache: { [key: string]: Promise<any> } = {};
7
-
8
- readonly cache: any;
9
-
10
- constructor() {
11
- this.cache = {
12
- addImage: vi.fn().mockImplementation((src: string): Promise<void> => {
13
- const result = Promise.resolve();
14
- this._cache[src] = result;
15
- return result;
16
- })
17
- };
18
- }
19
- }
@@ -1,8 +0,0 @@
1
- export const FEATURES = {
2
- SUPPORT_RANGE_BOUNDS: true,
3
- SUPPORT_SVG_DRAWING: true,
4
- SUPPORT_FOREIGNOBJECT_DRAWING: true,
5
- SUPPORT_CORS_IMAGES: true,
6
- SUPPORT_RESPONSE_TYPE: true,
7
- SUPPORT_CORS_XHR: true
8
- };
@@ -1,17 +0,0 @@
1
- export class Logger {
2
- debug(): void {}
3
-
4
- static create(): void {}
5
-
6
- static destroy(): void {}
7
-
8
- static getInstance(): Logger {
9
- return logger;
10
- }
11
-
12
- info(): void {}
13
-
14
- error(): void {}
15
- }
16
-
17
- export const logger = new Logger();
@@ -1,205 +0,0 @@
1
- import { strictEqual, ok, deepStrictEqual } from 'assert';
2
- import { Cache, ResourceOptions } from '../cache-storage';
3
- import { Context } from '../context';
4
- import { Bounds } from '../../css/layout/bounds';
5
- import { Html2CanvasConfig } from '../../config';
6
-
7
- describe('Cache LRU', () => {
8
- let context: Context;
9
- let cache: Cache;
10
-
11
- beforeEach(() => {
12
- const mockWindow = {
13
- document: {
14
- createElement: (_name: string) => {
15
- let _href = '';
16
- return {
17
- set href(value: string) {
18
- _href = value;
19
- },
20
- get href() {
21
- return _href;
22
- },
23
- get protocol() {
24
- return 'http:';
25
- },
26
- get hostname() {
27
- return 'localhost';
28
- },
29
- get port() {
30
- return '';
31
- }
32
- };
33
- }
34
- },
35
- location: { href: 'http://localhost/' }
36
- } as unknown as Window;
37
-
38
- const config = new Html2CanvasConfig({ window: mockWindow });
39
- context = new Context(
40
- {
41
- logging: false,
42
- imageTimeout: 15000,
43
- useCORS: false,
44
- allowTaint: false
45
- },
46
- new Bounds(0, 0, 800, 600),
47
- config
48
- );
49
-
50
- const options: ResourceOptions = {
51
- imageTimeout: 15000,
52
- useCORS: false,
53
- allowTaint: false,
54
- maxCacheSize: 3 // Small size for testing
55
- };
56
-
57
- cache = new Cache(context, options);
58
- });
59
-
60
- it('should enforce maximum cache size', () => {
61
- strictEqual(cache.getMaxSize(), 3);
62
- strictEqual(cache.size(), 0);
63
- });
64
-
65
- it('should add images to cache', () => {
66
- const blob1 = 'blob:http://localhost/image1';
67
- const blob2 = 'blob:http://localhost/image2';
68
-
69
- cache.addImage(blob1);
70
- strictEqual(cache.size(), 1);
71
-
72
- cache.addImage(blob2);
73
- strictEqual(cache.size(), 2);
74
- });
75
-
76
- it('should not exceed max cache size', () => {
77
- const blobs = [
78
- 'blob:http://localhost/image1',
79
- 'blob:http://localhost/image2',
80
- 'blob:http://localhost/image3',
81
- 'blob:http://localhost/image4' // This should trigger eviction
82
- ];
83
-
84
- blobs.forEach((blob) => cache.addImage(blob));
85
-
86
- // Should not exceed max size (3)
87
- strictEqual(cache.size(), 3);
88
- });
89
-
90
- it('should evict least recently used entry when full', async () => {
91
- const blob1 = 'blob:http://localhost/image1';
92
- const blob2 = 'blob:http://localhost/image2';
93
- const blob3 = 'blob:http://localhost/image3';
94
- const blob4 = 'blob:http://localhost/image4';
95
-
96
- // Add 3 images (fill cache)
97
- cache.addImage(blob1);
98
- await new Promise((resolve) => setTimeout(resolve, 10));
99
-
100
- cache.addImage(blob2);
101
- await new Promise((resolve) => setTimeout(resolve, 10));
102
-
103
- cache.addImage(blob3);
104
- await new Promise((resolve) => setTimeout(resolve, 10));
105
-
106
- strictEqual(cache.size(), 3);
107
-
108
- // Access blob2 and blob3 (update their access time)
109
- cache.match(blob2);
110
- await new Promise((resolve) => setTimeout(resolve, 10));
111
-
112
- cache.match(blob3);
113
- await new Promise((resolve) => setTimeout(resolve, 10));
114
-
115
- // Add blob4 - should evict blob1 (oldest, never accessed)
116
- cache.addImage(blob4);
117
-
118
- strictEqual(cache.size(), 3);
119
-
120
- // blob1 should be evicted
121
- strictEqual(cache.match(blob1), undefined);
122
-
123
- // blob2, blob3, blob4 should exist
124
- ok(cache.match(blob2) !== undefined);
125
- ok(cache.match(blob3) !== undefined);
126
- ok(cache.match(blob4) !== undefined);
127
- });
128
-
129
- it('should update access time on repeated access', async () => {
130
- const blob1 = 'blob:http://localhost/image1';
131
- const blob2 = 'blob:http://localhost/image2';
132
- const blob3 = 'blob:http://localhost/image3';
133
-
134
- cache.addImage(blob1);
135
- await new Promise((resolve) => setTimeout(resolve, 10));
136
-
137
- cache.addImage(blob2);
138
- await new Promise((resolve) => setTimeout(resolve, 10));
139
-
140
- cache.addImage(blob3);
141
- strictEqual(cache.size(), 3);
142
-
143
- // Access blob1 multiple times (update access time)
144
- cache.match(blob1);
145
- await new Promise((resolve) => setTimeout(resolve, 10));
146
-
147
- cache.addImage(blob1); // Should update access time
148
- await new Promise((resolve) => setTimeout(resolve, 10));
149
-
150
- // Add 4th image - should evict blob2 (oldest unaccessed)
151
- const blob4 = 'blob:http://localhost/image4';
152
- cache.addImage(blob4);
153
-
154
- strictEqual(cache.size(), 3);
155
- strictEqual(cache.match(blob2), undefined); // Evicted
156
- ok(cache.match(blob1) !== undefined); // Still exists
157
- });
158
-
159
- it('should clear all cache entries', () => {
160
- cache.addImage('blob:http://localhost/image1');
161
- cache.addImage('blob:http://localhost/image2');
162
- strictEqual(cache.size(), 2);
163
-
164
- cache.clear();
165
- strictEqual(cache.size(), 0);
166
- });
167
-
168
- it('should return cache keys', async () => {
169
- const blob1 = 'blob:http://localhost/image1';
170
- const blob2 = 'blob:http://localhost/image2';
171
-
172
- cache.addImage(blob1);
173
- cache.addImage(blob2);
174
-
175
- deepStrictEqual(await cache.keys(), [blob1, blob2]);
176
- });
177
-
178
- it('should throw error for invalid max size', () => {
179
- const options: ResourceOptions = {
180
- imageTimeout: 15000,
181
- useCORS: false,
182
- allowTaint: false,
183
- maxCacheSize: 0 // Invalid
184
- };
185
-
186
- try {
187
- new Cache(context, options);
188
- ok(false, 'Should have thrown error');
189
- } catch (error: any) {
190
- ok(error.message.includes('at least 1'));
191
- }
192
- });
193
-
194
- it('should use default max size if not specified', () => {
195
- const options: ResourceOptions = {
196
- imageTimeout: 15000,
197
- useCORS: false,
198
- allowTaint: false
199
- // maxCacheSize not specified
200
- };
201
-
202
- const cacheWithDefault = new Cache(context, options);
203
- strictEqual(cacheWithDefault.getMaxSize(), 100); // Default
204
- });
205
- });