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
@@ -1,315 +0,0 @@
1
- import { FEATURES } from './features';
2
- import { Context } from './context';
3
-
4
- /**
5
- * CacheStorage (Deprecated static methods)
6
- *
7
- * @deprecated The static methods of CacheStorage are deprecated.
8
- * Use OriginChecker class instead for instance-based origin checking.
9
- *
10
- * For backward compatibility, these methods remain but should not be used in new code.
11
- */
12
- export class CacheStorage {
13
- private static _link?: HTMLAnchorElement;
14
- private static _origin = 'about:blank';
15
-
16
- /**
17
- * @deprecated Use OriginChecker.getOrigin() instead
18
- */
19
- static getOrigin(url: string): string {
20
- const link = CacheStorage._link;
21
- if (!link) {
22
- return 'about:blank';
23
- }
24
-
25
- link.href = url;
26
- link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/
27
- return link.protocol + link.hostname + link.port;
28
- }
29
-
30
- /**
31
- * @deprecated Use OriginChecker.isSameOrigin() instead
32
- */
33
- static isSameOrigin(src: string): boolean {
34
- return CacheStorage.getOrigin(src) === CacheStorage._origin;
35
- }
36
-
37
- /**
38
- * @deprecated No longer needed. OriginChecker is created per Context.
39
- */
40
- static setContext(window: Window): void {
41
- CacheStorage._link = window.document.createElement('a');
42
- CacheStorage._origin = CacheStorage.getOrigin(window.location.href);
43
- }
44
- }
45
-
46
- export interface ResourceOptions {
47
- imageTimeout: number;
48
- useCORS: boolean;
49
- allowTaint: boolean;
50
- proxy?: string;
51
- customIsSameOrigin?: (this: void, src: string, oldFn: (src: string) => boolean) => boolean | Promise<boolean>;
52
- maxCacheSize?: number; // Maximum cache size (default: 100, max: 10000)
53
- }
54
-
55
- interface CacheEntry {
56
- value: Promise<HTMLImageElement | HTMLCanvasElement | undefined>;
57
- }
58
-
59
- export class Cache {
60
- private readonly _cache: Map<string, CacheEntry> = new Map();
61
- private readonly maxSize: number;
62
- private readonly _pendingOperations: Map<string, Promise<void>> = new Map();
63
-
64
- constructor(
65
- private readonly context: Context,
66
- private readonly _options: ResourceOptions
67
- ) {
68
- // Default cache size: 100 items
69
- this.maxSize = _options.maxCacheSize ?? 100;
70
-
71
- if (this.maxSize < 1) {
72
- throw new Error('Cache maxSize must be at least 1');
73
- }
74
-
75
- if (this.maxSize > 10000) {
76
- this.context.logger.warn(
77
- `Cache maxSize ${this.maxSize} is very large and may cause memory issues. ` +
78
- `Consider using a smaller value (recommended: 100-1000).`
79
- );
80
- }
81
- }
82
-
83
- addImage(src: string): Promise<void> {
84
- // Wait for any pending operations on this key
85
- const pending = this._pendingOperations.get(src);
86
- if (pending) {
87
- return pending;
88
- }
89
-
90
- if (this.has(src)) {
91
- // Move to end for LRU ordering
92
- const entry = this._cache.get(src)!;
93
- this._cache.delete(src);
94
- this._cache.set(src, entry);
95
- return Promise.resolve();
96
- }
97
-
98
- if (isBlobImage(src) || isRenderable(src)) {
99
- // Create a pending operation to ensure atomicity
100
- const operation = this._addImageInternal(src);
101
- this._pendingOperations.set(src, operation);
102
- operation.finally(() => {
103
- this._pendingOperations.delete(src);
104
- });
105
-
106
- return operation;
107
- }
108
-
109
- return Promise.resolve();
110
- }
111
-
112
- private async _addImageInternal(src: string): Promise<void> {
113
- const timeoutMs = this._options.imageTimeout ?? 15000;
114
- const imageWithTimeout = this.withTimeout(
115
- this.loadImage(src),
116
- timeoutMs,
117
- `Timed out (${timeoutMs}ms) loading image`
118
- );
119
-
120
- // Handle errors to prevent unhandled rejections
121
- imageWithTimeout.catch((error) => {
122
- this.context.logger.error(
123
- `Failed to load image ${src}: ${error instanceof Error ? error.message : 'Unknown error'}`
124
- );
125
- });
126
-
127
- // Store the promise with timeout in cache
128
- this.set(src, imageWithTimeout);
129
- }
130
-
131
- private withTimeout<T>(promise: Promise<T>, timeoutMs: number, message: string): Promise<T> {
132
- if (timeoutMs <= 0) {
133
- return promise;
134
- }
135
-
136
- let timeoutId: ReturnType<typeof setTimeout> | undefined;
137
- const timeout = new Promise<never>((_, reject) => {
138
- timeoutId = setTimeout(() => reject(new Error(message)), timeoutMs);
139
- });
140
-
141
- return Promise.race([promise, timeout]).finally(() => {
142
- if (timeoutId !== undefined) {
143
- clearTimeout(timeoutId);
144
- }
145
- });
146
- }
147
-
148
- match(src: string): Promise<HTMLImageElement | HTMLCanvasElement | undefined> | undefined {
149
- const entry = this._cache.get(src);
150
- if (entry) {
151
- // Move to end for LRU ordering (O(1))
152
- this._cache.delete(src);
153
- this._cache.set(src, entry);
154
- return entry.value;
155
- }
156
- return undefined;
157
- }
158
-
159
- /**
160
- * Set a value in cache with LRU eviction (O(1) via Map insertion order).
161
- * Map preserves insertion order; delete+set on access moves items to the end.
162
- * The first key in Map.keys() is always the least recently used.
163
- */
164
- private set(key: string, value: Promise<HTMLImageElement | HTMLCanvasElement | undefined>): void {
165
- if (this._cache.has(key)) {
166
- // Update existing entry: move to end of Map
167
- this._cache.delete(key);
168
- } else if (this._cache.size >= this.maxSize) {
169
- // Evict LRU (first key = least recently used) — O(1)
170
- const lruKey = this._cache.keys().next().value;
171
- if (lruKey !== undefined) {
172
- this._cache.delete(lruKey);
173
- this.context.logger.debug(`Cache: Evicted LRU entry: ${lruKey}`);
174
- }
175
- }
176
-
177
- this._cache.set(key, { value });
178
- }
179
-
180
- /**
181
- * Get cache size
182
- */
183
- size(): number {
184
- return this._cache.size;
185
- }
186
-
187
- /**
188
- * Get max cache size
189
- */
190
- getMaxSize(): number {
191
- return this.maxSize;
192
- }
193
-
194
- /**
195
- * Clear all cache entries
196
- */
197
- clear(): void {
198
- this._cache.clear();
199
- }
200
-
201
- private async loadImage(key: string): Promise<HTMLImageElement | undefined> {
202
- const originChecker = this.context.originChecker;
203
- const defaultIsSameOrigin = (src: string) => originChecker.isSameOrigin(src);
204
-
205
- const isSameOrigin: boolean =
206
- typeof this._options.customIsSameOrigin === 'function'
207
- ? await this._options.customIsSameOrigin(key, defaultIsSameOrigin)
208
- : defaultIsSameOrigin(key);
209
- const useCORS =
210
- !isInlineImage(key) && this._options.useCORS === true && FEATURES.SUPPORT_CORS_IMAGES && !isSameOrigin;
211
- const useProxy =
212
- !isInlineImage(key) &&
213
- !isSameOrigin &&
214
- !isBlobImage(key) &&
215
- typeof this._options.proxy === 'string' &&
216
- FEATURES.SUPPORT_CORS_XHR &&
217
- !useCORS;
218
- if (
219
- !isSameOrigin &&
220
- this._options.allowTaint === false &&
221
- !isInlineImage(key) &&
222
- !isBlobImage(key) &&
223
- !useProxy &&
224
- !useCORS
225
- ) {
226
- return;
227
- }
228
-
229
- let src = key;
230
- if (useProxy) {
231
- src = await this.proxy(src);
232
- }
233
-
234
- this.context.logger.debug(`Added image ${key.substring(0, 256)}`);
235
-
236
- return await new Promise((resolve, reject) => {
237
- const img = new Image();
238
- img.onload = () => resolve(img);
239
- img.onerror = reject;
240
- //ios safari 10.3 taints canvas with data urls unless crossOrigin is set to anonymous
241
- if (isInlineBase64Image(src) || useCORS) {
242
- img.crossOrigin = 'anonymous';
243
- }
244
- img.src = src;
245
- if (img.complete === true) {
246
- // Inline XML images may fail to parse, throwing an Error later on
247
- setTimeout(() => resolve(img), 500);
248
- }
249
- });
250
- }
251
-
252
- private has(key: string): boolean {
253
- return this._cache.has(key);
254
- }
255
-
256
- keys(): Promise<string[]> {
257
- return Promise.resolve(Array.from(this._cache.keys()));
258
- }
259
-
260
- private proxy(src: string): Promise<string> {
261
- const proxy = this._options.proxy;
262
-
263
- if (!proxy) {
264
- throw new Error('No proxy defined');
265
- }
266
-
267
- const key = src.substring(0, 256);
268
-
269
- return new Promise((resolve, reject) => {
270
- const responseType = FEATURES.SUPPORT_RESPONSE_TYPE ? 'blob' : 'text';
271
- const xhr = new XMLHttpRequest();
272
- xhr.onload = () => {
273
- if (xhr.status === 200) {
274
- if (responseType === 'text') {
275
- resolve(xhr.response);
276
- } else {
277
- const reader = new FileReader();
278
- reader.addEventListener('load', () => resolve(reader.result as string), false);
279
- reader.addEventListener('error', (e) => reject(e), false);
280
- reader.readAsDataURL(xhr.response);
281
- }
282
- } else {
283
- reject(`Failed to proxy resource ${key} with status code ${xhr.status}`);
284
- }
285
- };
286
-
287
- xhr.onerror = reject;
288
- const queryString = proxy.indexOf('?') > -1 ? '&' : '?';
289
- xhr.open('GET', `${proxy}${queryString}url=${encodeURIComponent(src)}&responseType=${responseType}`);
290
-
291
- if (responseType !== 'text' && xhr instanceof XMLHttpRequest) {
292
- xhr.responseType = responseType;
293
- }
294
-
295
- if (this._options.imageTimeout) {
296
- const timeout = this._options.imageTimeout;
297
- xhr.timeout = timeout;
298
- xhr.ontimeout = () => reject(`Timed out (${timeout}ms) proxying ${key}`);
299
- }
300
-
301
- xhr.send();
302
- });
303
- }
304
- }
305
-
306
- const INLINE_SVG = /^data:image\/svg\+xml/i;
307
- const INLINE_BASE64 = /^data:image\/.*;base64,/i;
308
- const INLINE_IMG = /^data:image\/.*/i;
309
-
310
- const isRenderable = (src: string): boolean => FEATURES.SUPPORT_SVG_DRAWING || !isSVG(src);
311
- const isInlineImage = (src: string): boolean => INLINE_IMG.test(src);
312
- const isInlineBase64Image = (src: string): boolean => INLINE_BASE64.test(src);
313
- const isBlobImage = (src: string): boolean => src.substr(0, 4) === 'blob';
314
-
315
- const isSVG = (src: string): boolean => src.substr(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);
@@ -1,31 +0,0 @@
1
- import { Logger } from './logger';
2
- import { Cache, ResourceOptions } from './cache-storage';
3
- import { Bounds } from '../css/layout/bounds';
4
- import { OriginChecker } from './origin-checker';
5
- import { Html2CanvasConfig } from '../config';
6
-
7
- export type ContextOptions = {
8
- logging: boolean;
9
- cache?: Cache;
10
- } & ResourceOptions;
11
-
12
- export class Context {
13
- private readonly instanceName = `#${Context.instanceCount++}`;
14
- readonly logger: Logger;
15
- readonly cache: Cache;
16
- readonly originChecker: OriginChecker;
17
- readonly config: Html2CanvasConfig;
18
-
19
- private static instanceCount = 1;
20
-
21
- constructor(
22
- options: ContextOptions,
23
- public windowBounds: Bounds,
24
- config: Html2CanvasConfig
25
- ) {
26
- this.config = config;
27
- this.logger = new Logger({ id: this.instanceName, enabled: options.logging });
28
- this.originChecker = new OriginChecker(config.window);
29
- this.cache = options.cache ?? config.cache ?? new Cache(this, options);
30
- }
31
- }
@@ -1,32 +0,0 @@
1
- const elementDebuggerAttribute = 'data-html2canvas-debug';
2
- export const enum DebuggerType {
3
- NONE,
4
- ALL,
5
- CLONE,
6
- PARSE,
7
- RENDER
8
- }
9
-
10
- const getElementDebugType = (element: Element): DebuggerType => {
11
- if (typeof element.getAttribute !== 'function') {
12
- return DebuggerType.NONE;
13
- }
14
- const attribute = element.getAttribute(elementDebuggerAttribute);
15
- switch (attribute) {
16
- case 'all':
17
- return DebuggerType.ALL;
18
- case 'clone':
19
- return DebuggerType.CLONE;
20
- case 'parse':
21
- return DebuggerType.PARSE;
22
- case 'render':
23
- return DebuggerType.RENDER;
24
- default:
25
- return DebuggerType.NONE;
26
- }
27
- };
28
-
29
- export const isDebugging = (element: Element, type: Omit<DebuggerType, DebuggerType.NONE>): boolean => {
30
- const elementType = getElementDebugType(element);
31
- return elementType === DebuggerType.ALL || type === elementType;
32
- };
@@ -1,222 +0,0 @@
1
- import { fromCodePoint, toCodePoints } from 'css-line-break';
2
-
3
- const testRangeBounds = (document: Document) => {
4
- const TEST_HEIGHT = 123;
5
-
6
- if (document.createRange) {
7
- const range = document.createRange();
8
- if (range.getBoundingClientRect) {
9
- const testElement = document.createElement('boundtest');
10
- testElement.style.height = `${TEST_HEIGHT}px`;
11
- testElement.style.display = 'block';
12
- document.body.appendChild(testElement);
13
-
14
- range.selectNode(testElement);
15
- const rangeBounds = range.getBoundingClientRect();
16
- const rangeHeight = Math.round(rangeBounds.height);
17
- document.body.removeChild(testElement);
18
- if (rangeHeight === TEST_HEIGHT) {
19
- return true;
20
- }
21
- }
22
- }
23
-
24
- return false;
25
- };
26
-
27
- const testIOSLineBreak = (document: Document) => {
28
- const testElement = document.createElement('boundtest');
29
- testElement.style.width = '50px';
30
- testElement.style.display = 'block';
31
- testElement.style.fontSize = '12px';
32
- testElement.style.letterSpacing = '0px';
33
- testElement.style.wordSpacing = '0px';
34
- document.body.appendChild(testElement);
35
- const range = document.createRange();
36
-
37
- testElement.innerHTML = typeof ''.repeat === 'function' ? '&#128104;'.repeat(10) : '';
38
-
39
- const node = testElement.firstChild as Text;
40
-
41
- const textList = toCodePoints(node.data).map((i) => fromCodePoint(i));
42
- let offset = 0;
43
- let prev: DOMRect = {} as DOMRect;
44
-
45
- // ios 13 does not handle range getBoundingClientRect line changes correctly #2177
46
- const supports = textList.every((text, i) => {
47
- range.setStart(node, offset);
48
- range.setEnd(node, offset + text.length);
49
- const rect = range.getBoundingClientRect();
50
-
51
- offset += text.length;
52
- const boundAhead = rect.x > prev.x || rect.y > prev.y;
53
-
54
- prev = rect;
55
- if (i === 0) {
56
- return true;
57
- }
58
-
59
- return boundAhead;
60
- });
61
-
62
- document.body.removeChild(testElement);
63
- return supports;
64
- };
65
-
66
- const testCORS = (): boolean => typeof new Image().crossOrigin !== 'undefined';
67
-
68
- const testResponseType = (): boolean => typeof new XMLHttpRequest().responseType === 'string';
69
-
70
- const testSVG = (document: Document): boolean => {
71
- const img = new Image();
72
- const canvas = document.createElement('canvas');
73
- const ctx = canvas.getContext('2d');
74
- if (!ctx) {
75
- return false;
76
- }
77
-
78
- img.src = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>`;
79
-
80
- try {
81
- ctx.drawImage(img, 0, 0);
82
- canvas.toDataURL();
83
- } catch (e) {
84
- return false;
85
- }
86
- return true;
87
- };
88
-
89
- const isGreenPixel = (data: Uint8ClampedArray): boolean =>
90
- data[0] === 0 && data[1] === 255 && data[2] === 0 && data[3] === 255;
91
-
92
- const testForeignObject = (document: Document): Promise<boolean> => {
93
- const canvas = document.createElement('canvas');
94
- const size = 100;
95
- canvas.width = size;
96
- canvas.height = size;
97
- const ctx = canvas.getContext('2d');
98
- if (!ctx) {
99
- return Promise.reject(false);
100
- }
101
- ctx.fillStyle = 'rgb(0, 255, 0)';
102
- ctx.fillRect(0, 0, size, size);
103
-
104
- const img = new Image();
105
- const greenImageSrc = canvas.toDataURL();
106
- img.src = greenImageSrc;
107
- const svg = createForeignObjectSVG(size, size, 0, 0, img);
108
- ctx.fillStyle = 'red';
109
- ctx.fillRect(0, 0, size, size);
110
-
111
- return loadSerializedSVG(svg)
112
- .then((img: HTMLImageElement) => {
113
- ctx.drawImage(img, 0, 0);
114
- const data = ctx.getImageData(0, 0, size, size).data;
115
- ctx.fillStyle = 'red';
116
- ctx.fillRect(0, 0, size, size);
117
-
118
- const node = document.createElement('div');
119
- node.style.backgroundImage = `url(${greenImageSrc})`;
120
- node.style.height = `${size}px`;
121
- // Firefox 55 does not render inline <img /> tags
122
- return isGreenPixel(data)
123
- ? loadSerializedSVG(createForeignObjectSVG(size, size, 0, 0, node))
124
- : Promise.reject(false);
125
- })
126
- .then((img: HTMLImageElement) => {
127
- ctx.drawImage(img, 0, 0);
128
- // Edge does not render background-images
129
- return isGreenPixel(ctx.getImageData(0, 0, size, size).data);
130
- })
131
- .catch(() => false);
132
- };
133
-
134
- export const createForeignObjectSVG = (
135
- width: number,
136
- height: number,
137
- x: number,
138
- y: number,
139
- node: Node
140
- ): SVGForeignObjectElement => {
141
- const xmlns = 'http://www.w3.org/2000/svg';
142
- const svg = document.createElementNS(xmlns, 'svg');
143
- const foreignObject = document.createElementNS(xmlns, 'foreignObject');
144
- svg.setAttributeNS(null, 'width', width.toString());
145
- svg.setAttributeNS(null, 'height', height.toString());
146
-
147
- foreignObject.setAttributeNS(null, 'width', '100%');
148
- foreignObject.setAttributeNS(null, 'height', '100%');
149
- foreignObject.setAttributeNS(null, 'x', x.toString());
150
- foreignObject.setAttributeNS(null, 'y', y.toString());
151
- foreignObject.setAttributeNS(null, 'externalResourcesRequired', 'true');
152
- svg.appendChild(foreignObject);
153
-
154
- foreignObject.appendChild(node);
155
-
156
- return svg;
157
- };
158
-
159
- export const loadSerializedSVG = (svg: Node): Promise<HTMLImageElement> => {
160
- return new Promise((resolve, reject) => {
161
- const img = new Image();
162
- img.onload = () => resolve(img);
163
- img.onerror = reject;
164
-
165
- img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(new XMLSerializer().serializeToString(svg))}`;
166
- });
167
- };
168
-
169
- export const FEATURES = {
170
- get SUPPORT_RANGE_BOUNDS(): boolean {
171
- 'use strict';
172
- const value = testRangeBounds(document);
173
- Object.defineProperty(FEATURES, 'SUPPORT_RANGE_BOUNDS', { value });
174
- return value;
175
- },
176
- get SUPPORT_WORD_BREAKING(): boolean {
177
- 'use strict';
178
- const value = FEATURES.SUPPORT_RANGE_BOUNDS && testIOSLineBreak(document);
179
- Object.defineProperty(FEATURES, 'SUPPORT_WORD_BREAKING', { value });
180
- return value;
181
- },
182
- get SUPPORT_SVG_DRAWING(): boolean {
183
- 'use strict';
184
- const value = testSVG(document);
185
- Object.defineProperty(FEATURES, 'SUPPORT_SVG_DRAWING', { value });
186
- return value;
187
- },
188
- get SUPPORT_FOREIGNOBJECT_DRAWING(): Promise<boolean> {
189
- 'use strict';
190
- const value =
191
- typeof Array.from === 'function' && typeof window.fetch === 'function'
192
- ? testForeignObject(document)
193
- : Promise.resolve(false);
194
- Object.defineProperty(FEATURES, 'SUPPORT_FOREIGNOBJECT_DRAWING', { value });
195
- return value;
196
- },
197
- get SUPPORT_CORS_IMAGES(): boolean {
198
- 'use strict';
199
- const value = testCORS();
200
- Object.defineProperty(FEATURES, 'SUPPORT_CORS_IMAGES', { value });
201
- return value;
202
- },
203
- get SUPPORT_RESPONSE_TYPE(): boolean {
204
- 'use strict';
205
- const value = testResponseType();
206
- Object.defineProperty(FEATURES, 'SUPPORT_RESPONSE_TYPE', { value });
207
- return value;
208
- },
209
- get SUPPORT_CORS_XHR(): boolean {
210
- 'use strict';
211
- const value = 'withCredentials' in new XMLHttpRequest();
212
- Object.defineProperty(FEATURES, 'SUPPORT_CORS_XHR', { value });
213
- return value;
214
- },
215
- get SUPPORT_NATIVE_TEXT_SEGMENTATION(): boolean {
216
- 'use strict';
217
-
218
- const value = !!(typeof Intl !== 'undefined' && (Intl as any).Segmenter);
219
- Object.defineProperty(FEATURES, 'SUPPORT_NATIVE_TEXT_SEGMENTATION', { value });
220
- return value;
221
- }
222
- };
@@ -1,64 +0,0 @@
1
- export interface LoggerOptions {
2
- id: string;
3
- enabled: boolean;
4
- }
5
-
6
- export class Logger {
7
- static instances: { [key: string]: Logger } = {};
8
-
9
- private readonly id: string;
10
- private readonly enabled: boolean;
11
- private readonly start: number;
12
-
13
- constructor({ id, enabled }: LoggerOptions) {
14
- this.id = id;
15
- this.enabled = enabled;
16
- this.start = Date.now();
17
- }
18
-
19
- debug(...args: unknown[]): void {
20
- if (this.enabled) {
21
- // eslint-disable-next-line no-console
22
- if (typeof window !== 'undefined' && window.console && typeof console.debug === 'function') {
23
- // eslint-disable-next-line no-console
24
- console.debug(this.id, `${this.getTime()}ms`, ...args);
25
- } else {
26
- this.info(...args);
27
- }
28
- }
29
- }
30
-
31
- getTime(): number {
32
- return Date.now() - this.start;
33
- }
34
-
35
- info(...args: unknown[]): void {
36
- if (this.enabled) {
37
- // eslint-disable-next-line no-console
38
- if (typeof window !== 'undefined' && window.console && typeof console.info === 'function') {
39
- // eslint-disable-next-line no-console
40
- console.info(this.id, `${this.getTime()}ms`, ...args);
41
- }
42
- }
43
- }
44
-
45
- warn(...args: unknown[]): void {
46
- if (this.enabled) {
47
- if (typeof window !== 'undefined' && window.console && typeof console.warn === 'function') {
48
- console.warn(this.id, `${this.getTime()}ms`, ...args);
49
- } else {
50
- this.info(...args);
51
- }
52
- }
53
- }
54
-
55
- error(...args: unknown[]): void {
56
- if (this.enabled) {
57
- if (typeof window !== 'undefined' && window.console && typeof console.error === 'function') {
58
- console.error(this.id, `${this.getTime()}ms`, ...args);
59
- } else {
60
- this.info(...args);
61
- }
62
- }
63
- }
64
- }