html2canvas-pro 2.1.0 → 2.2.0
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.
- package/dist/html2canvas-pro.esm.js +10226 -10526
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +10869 -11171
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +8 -8
- package/dist/lib/config.js +0 -22
- package/dist/lib/core/cache-storage.js +3 -40
- package/dist/lib/core/constants.js +25 -0
- package/dist/lib/core/context.js +1 -0
- package/dist/lib/core/features.js +3 -2
- package/dist/lib/core/validator.js +3 -3
- package/dist/lib/css/grouped/background-styles.js +36 -0
- package/dist/lib/css/grouped/border-styles.js +75 -0
- package/dist/lib/css/grouped/font-styles.js +93 -0
- package/dist/lib/css/grouped/layout-styles.js +127 -0
- package/dist/lib/css/index.js +74 -46
- package/dist/lib/css/layout/text.js +7 -6
- package/dist/lib/css/property-descriptors/background-blend-mode.js +41 -0
- package/dist/lib/css/property-descriptors/border-image-repeat.js +42 -0
- package/dist/lib/css/property-descriptors/border-image-slice.js +45 -0
- package/dist/lib/css/property-descriptors/border-image-source.js +21 -0
- package/dist/lib/css/property-descriptors/border-radius.js +1 -1
- package/dist/lib/css/property-descriptors/box-decoration-break.js +18 -0
- package/dist/lib/css/property-descriptors/counter-increment.js +17 -12
- package/dist/lib/css/property-descriptors/counter-reset.js +4 -12
- package/dist/lib/css/property-descriptors/filter.js +76 -0
- package/dist/lib/css/property-descriptors/font-variant-ligatures.js +34 -0
- package/dist/lib/css/property-descriptors/object-fit.js +1 -1
- package/dist/lib/css/property-descriptors/object-position.js +42 -0
- package/dist/lib/css/property-descriptors/visibility.js +1 -1
- package/dist/lib/css/property-descriptors/zoom.js +18 -0
- package/dist/lib/css/syntax/parser.js +0 -1
- package/dist/lib/css/types/color.js +5 -1
- package/dist/lib/css/types/functions/repeating-linear-gradient.js +9 -0
- package/dist/lib/css/types/image.js +12 -2
- package/dist/lib/css/types/length-percentage.js +6 -2
- package/dist/lib/css/types/safe-eval.js +80 -0
- package/dist/lib/dom/document-cloner.js +23 -163
- package/dist/lib/dom/slot-cloner.js +176 -0
- package/dist/lib/index.js +1 -17
- package/dist/lib/render/canvas/background-renderer.js +169 -30
- package/dist/lib/render/canvas/border-image-renderer.js +153 -0
- package/dist/lib/render/canvas/canvas-renderer.js +39 -190
- package/dist/lib/render/canvas/content-renderer.js +202 -0
- package/dist/lib/render/canvas/effects-renderer.js +3 -0
- package/dist/lib/render/canvas/foreignobject-renderer.js +5 -1
- package/dist/lib/render/canvas/text/text-decoration-renderer.js +99 -0
- package/dist/lib/render/canvas/text-renderer.js +100 -224
- package/dist/lib/render/effects.js +38 -3
- package/dist/lib/render/object-fit.js +19 -15
- package/dist/lib/render/stacking-context.js +11 -0
- package/dist/types/config.d.ts +0 -10
- package/dist/types/core/cache-storage.d.ts +0 -24
- package/dist/types/core/constants.d.ts +22 -0
- package/dist/types/core/context.d.ts +3 -0
- package/dist/types/core/performance-monitor.d.ts +4 -4
- package/dist/types/core/validator.d.ts +6 -8
- package/dist/types/css/grouped/background-styles.d.ts +16 -0
- package/dist/types/css/grouped/border-styles.d.ts +31 -0
- package/dist/types/css/grouped/font-styles.d.ts +35 -0
- package/dist/types/css/grouped/layout-styles.d.ts +46 -0
- package/dist/types/css/index.d.ts +30 -0
- package/dist/types/css/property-descriptors/background-blend-mode.d.ts +23 -0
- package/dist/types/css/property-descriptors/border-image-repeat.d.ts +12 -0
- package/dist/types/css/property-descriptors/border-image-slice.d.ts +10 -0
- package/dist/types/css/property-descriptors/border-image-source.d.ts +4 -0
- package/dist/types/css/property-descriptors/box-decoration-break.d.ts +6 -0
- package/dist/types/css/property-descriptors/counter-increment.d.ts +3 -0
- package/dist/types/css/property-descriptors/filter.d.ts +3 -0
- package/dist/types/css/property-descriptors/font-variant-ligatures.d.ts +14 -0
- package/dist/types/css/property-descriptors/object-position.d.ts +4 -0
- package/dist/types/css/property-descriptors/zoom.d.ts +3 -0
- package/dist/types/css/types/functions/repeating-linear-gradient.d.ts +4 -0
- package/dist/types/css/types/image.d.ts +4 -2
- package/dist/types/css/types/safe-eval.d.ts +8 -0
- package/dist/types/dom/document-cloner.d.ts +3 -44
- package/dist/types/dom/slot-cloner.d.ts +66 -0
- package/dist/types/index.d.ts +3 -7
- package/dist/types/options.d.ts +11 -0
- package/dist/types/render/canvas/background-renderer.d.ts +23 -0
- package/dist/types/render/canvas/border-image-renderer.d.ts +18 -0
- package/dist/types/render/canvas/canvas-renderer.d.ts +1 -0
- package/dist/types/render/canvas/content-renderer.d.ts +44 -0
- package/dist/types/render/canvas/text/text-decoration-renderer.d.ts +18 -0
- package/dist/types/render/canvas/text-renderer.d.ts +12 -1
- package/dist/types/render/effects.d.ts +12 -2
- package/dist/types/render/object-fit.d.ts +2 -1
- package/dist/types/render/renderer-interface.d.ts +11 -9
- package/package.json +7 -20
- package/dist/lib/dom/replaced-elements/pseudo-elements.js +0 -0
- package/dist/lib/invariant.js +0 -9
- package/dist/types/dom/replaced-elements/pseudo-elements.d.ts +0 -0
- package/dist/types/invariant.d.ts +0 -1
- package/src/__tests__/index.ts +0 -99
- package/src/config.ts +0 -107
- package/src/core/__mocks__/cache-storage.ts +0 -1
- package/src/core/__mocks__/context.ts +0 -19
- package/src/core/__mocks__/features.ts +0 -8
- package/src/core/__mocks__/logger.ts +0 -17
- package/src/core/__tests__/cache-storage.test.ts +0 -205
- package/src/core/__tests__/cache-storage.ts +0 -278
- package/src/core/__tests__/logger.ts +0 -29
- package/src/core/__tests__/validator.ts +0 -359
- package/src/core/bitwise.ts +0 -1
- package/src/core/cache-storage.ts +0 -315
- package/src/core/context.ts +0 -31
- package/src/core/debugger.ts +0 -32
- package/src/core/features.ts +0 -222
- package/src/core/logger.ts +0 -64
- package/src/core/origin-checker.ts +0 -57
- package/src/core/performance-monitor.ts +0 -241
- package/src/core/render-element.ts +0 -272
- package/src/core/util.ts +0 -1
- package/src/core/validator.ts +0 -593
- package/src/css/index.ts +0 -427
- package/src/css/layout/__mocks__/bounds.ts +0 -6
- package/src/css/layout/bounds.ts +0 -79
- package/src/css/layout/text.ts +0 -161
- package/src/css/property-descriptor.ts +0 -49
- package/src/css/property-descriptors/__tests__/background-tests.ts +0 -65
- package/src/css/property-descriptors/__tests__/clip-path.test.ts +0 -280
- package/src/css/property-descriptors/__tests__/font-family.ts +0 -25
- package/src/css/property-descriptors/__tests__/image-rendering-integration.test.ts +0 -153
- package/src/css/property-descriptors/__tests__/image-rendering-performance.test.ts +0 -175
- package/src/css/property-descriptors/__tests__/image-rendering.test.ts +0 -72
- package/src/css/property-descriptors/__tests__/paint-order.ts +0 -87
- package/src/css/property-descriptors/__tests__/text-shadow.ts +0 -94
- package/src/css/property-descriptors/__tests__/transform-tests.ts +0 -18
- package/src/css/property-descriptors/background-clip.ts +0 -30
- package/src/css/property-descriptors/background-color.ts +0 -9
- package/src/css/property-descriptors/background-image.ts +0 -27
- package/src/css/property-descriptors/background-origin.ts +0 -31
- package/src/css/property-descriptors/background-position.ts +0 -38
- package/src/css/property-descriptors/background-repeat.ts +0 -44
- package/src/css/property-descriptors/background-size.ts +0 -27
- package/src/css/property-descriptors/border-color.ts +0 -13
- package/src/css/property-descriptors/border-radius.ts +0 -19
- package/src/css/property-descriptors/border-style.ts +0 -34
- package/src/css/property-descriptors/border-width.ts +0 -20
- package/src/css/property-descriptors/box-shadow.ts +0 -60
- package/src/css/property-descriptors/clip-path.ts +0 -271
- package/src/css/property-descriptors/color.ts +0 -9
- package/src/css/property-descriptors/content.ts +0 -26
- package/src/css/property-descriptors/counter-increment.ts +0 -43
- package/src/css/property-descriptors/counter-reset.ts +0 -36
- package/src/css/property-descriptors/direction.ts +0 -23
- package/src/css/property-descriptors/display.ts +0 -117
- package/src/css/property-descriptors/duration.ts +0 -14
- package/src/css/property-descriptors/float.ts +0 -29
- package/src/css/property-descriptors/font-family.ts +0 -38
- package/src/css/property-descriptors/font-size.ts +0 -9
- package/src/css/property-descriptors/font-style.ts +0 -25
- package/src/css/property-descriptors/font-variant.ts +0 -12
- package/src/css/property-descriptors/font-weight.ts +0 -26
- package/src/css/property-descriptors/image-rendering.ts +0 -33
- package/src/css/property-descriptors/letter-spacing.ts +0 -25
- package/src/css/property-descriptors/line-break.ts +0 -22
- package/src/css/property-descriptors/line-height.ts +0 -22
- package/src/css/property-descriptors/list-style-image.ts +0 -19
- package/src/css/property-descriptors/list-style-position.ts +0 -22
- package/src/css/property-descriptors/list-style-type.ts +0 -179
- package/src/css/property-descriptors/margin.ts +0 -13
- package/src/css/property-descriptors/mix-blend-mode.ts +0 -35
- package/src/css/property-descriptors/object-fit.ts +0 -39
- package/src/css/property-descriptors/opacity.ts +0 -15
- package/src/css/property-descriptors/overflow-wrap.ts +0 -22
- package/src/css/property-descriptors/overflow.ts +0 -34
- package/src/css/property-descriptors/padding.ts +0 -14
- package/src/css/property-descriptors/paint-order.ts +0 -42
- package/src/css/property-descriptors/position.ts +0 -30
- package/src/css/property-descriptors/quotes.ts +0 -57
- package/src/css/property-descriptors/rotate.ts +0 -34
- package/src/css/property-descriptors/text-align.ts +0 -26
- package/src/css/property-descriptors/text-decoration-color.ts +0 -9
- package/src/css/property-descriptors/text-decoration-line.ts +0 -38
- package/src/css/property-descriptors/text-decoration-style.ts +0 -32
- package/src/css/property-descriptors/text-decoration-thickness.ts +0 -30
- package/src/css/property-descriptors/text-overflow.ts +0 -23
- package/src/css/property-descriptors/text-shadow.ts +0 -52
- package/src/css/property-descriptors/text-transform.ts +0 -27
- package/src/css/property-descriptors/text-underline-offset.ts +0 -27
- package/src/css/property-descriptors/transform-origin.ts +0 -29
- package/src/css/property-descriptors/transform.ts +0 -74
- package/src/css/property-descriptors/visibility.ts +0 -25
- package/src/css/property-descriptors/webkit-line-clamp.ts +0 -30
- package/src/css/property-descriptors/webkit-text-stroke-color.ts +0 -8
- package/src/css/property-descriptors/webkit-text-stroke-width.ts +0 -15
- package/src/css/property-descriptors/word-break.ts +0 -25
- package/src/css/property-descriptors/writing-mode.ts +0 -37
- package/src/css/property-descriptors/z-index.ts +0 -27
- package/src/css/syntax/__tests__/tokernizer-tests.ts +0 -29
- package/src/css/syntax/parser.ts +0 -188
- package/src/css/syntax/tokenizer.ts +0 -822
- package/src/css/type-descriptor.ts +0 -7
- package/src/css/types/__tests__/color-tests.ts +0 -147
- package/src/css/types/__tests__/image-tests.ts +0 -239
- package/src/css/types/angle.ts +0 -86
- package/src/css/types/color-math.ts +0 -22
- package/src/css/types/color-spaces/a98.ts +0 -86
- package/src/css/types/color-spaces/p3.ts +0 -92
- package/src/css/types/color-spaces/pro-photo.ts +0 -87
- package/src/css/types/color-spaces/rec2020.ts +0 -90
- package/src/css/types/color-spaces/srgb.ts +0 -87
- package/src/css/types/color-utilities.ts +0 -452
- package/src/css/types/color.ts +0 -485
- package/src/css/types/functions/-prefix-linear-gradient.ts +0 -35
- package/src/css/types/functions/-prefix-radial-gradient.ts +0 -106
- package/src/css/types/functions/-webkit-gradient.ts +0 -69
- package/src/css/types/functions/__tests__/radial-gradient.ts +0 -69
- package/src/css/types/functions/counter.ts +0 -511
- package/src/css/types/functions/gradient.ts +0 -206
- package/src/css/types/functions/linear-gradient.ts +0 -28
- package/src/css/types/functions/radial-gradient.ts +0 -101
- package/src/css/types/image.ts +0 -120
- package/src/css/types/index.ts +0 -1
- package/src/css/types/length-percentage.ts +0 -137
- package/src/css/types/length.ts +0 -7
- package/src/css/types/time.ts +0 -20
- package/src/dom/__mocks__/document-cloner.ts +0 -22
- package/src/dom/__tests__/dom-normalizer.test.ts +0 -133
- package/src/dom/__tests__/element-container.test.ts +0 -129
- package/src/dom/document-cloner.ts +0 -929
- package/src/dom/dom-normalizer.ts +0 -133
- package/src/dom/element-container.ts +0 -75
- package/src/dom/elements/li-element-container.ts +0 -10
- package/src/dom/elements/ol-element-container.ts +0 -12
- package/src/dom/elements/select-element-container.ts +0 -10
- package/src/dom/elements/textarea-element-container.ts +0 -9
- package/src/dom/node-parser.ts +0 -177
- package/src/dom/node-type-guards.ts +0 -70
- package/src/dom/replaced-elements/canvas-element-container.ts +0 -15
- package/src/dom/replaced-elements/iframe-element-container.ts +0 -55
- package/src/dom/replaced-elements/image-element-container.ts +0 -16
- package/src/dom/replaced-elements/index.ts +0 -5
- package/src/dom/replaced-elements/input-element-container.ts +0 -105
- package/src/dom/replaced-elements/pseudo-elements.ts +0 -0
- package/src/dom/replaced-elements/svg-element-container.ts +0 -23
- package/src/dom/text-container.ts +0 -42
- package/src/global.d.ts +0 -19
- package/src/index.ts +0 -82
- package/src/invariant.ts +0 -5
- package/src/options.ts +0 -55
- package/src/render/__tests__/object-fit.test.ts +0 -85
- package/src/render/background.ts +0 -298
- package/src/render/bezier-curve.ts +0 -47
- package/src/render/border.ts +0 -165
- package/src/render/bound-curves.ts +0 -388
- package/src/render/box-sizing.ts +0 -31
- package/src/render/canvas/__tests__/background-renderer.test.ts +0 -72
- package/src/render/canvas/__tests__/border-renderer.test.ts +0 -24
- package/src/render/canvas/__tests__/effects-renderer.test.ts +0 -32
- package/src/render/canvas/__tests__/text-renderer.test.ts +0 -471
- package/src/render/canvas/background-renderer.ts +0 -271
- package/src/render/canvas/border-renderer.ts +0 -224
- package/src/render/canvas/canvas-path.ts +0 -31
- package/src/render/canvas/canvas-renderer.ts +0 -641
- package/src/render/canvas/effects-renderer.ts +0 -130
- package/src/render/canvas/foreignobject-renderer.ts +0 -53
- package/src/render/canvas/text-renderer.ts +0 -700
- package/src/render/effects.ts +0 -75
- package/src/render/font-metrics.ts +0 -72
- package/src/render/object-fit.ts +0 -100
- package/src/render/path.ts +0 -37
- package/src/render/renderer-interface.ts +0 -28
- package/src/render/stacking-context.ts +0 -386
- package/src/render/vector.ts +0 -19
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Background Renderer
|
|
3
|
-
*
|
|
4
|
-
* Handles rendering of element backgrounds including:
|
|
5
|
-
* - Background colors
|
|
6
|
-
* - Background images (URL)
|
|
7
|
-
* - Linear gradients
|
|
8
|
-
* - Radial gradients
|
|
9
|
-
* - Background patterns and repeats
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { Context } from '../../core/context';
|
|
13
|
-
import { ElementContainer } from '../../dom/element-container';
|
|
14
|
-
import { Path } from '../path';
|
|
15
|
-
import {
|
|
16
|
-
CSSImageType,
|
|
17
|
-
CSSLinearGradientImage,
|
|
18
|
-
CSSRadialGradientImage,
|
|
19
|
-
CSSURLImage,
|
|
20
|
-
isLinearGradient,
|
|
21
|
-
isRadialGradient
|
|
22
|
-
} from '../../css/types/image';
|
|
23
|
-
import { calculateBackgroundRendering } from '../background';
|
|
24
|
-
import { calculateGradientDirection, calculateRadius, processColorStops } from '../../css/types/functions/gradient';
|
|
25
|
-
import { FIFTY_PERCENT, getAbsoluteValue } from '../../css/types/length-percentage';
|
|
26
|
-
import { asString } from '../../css/types/color-utilities';
|
|
27
|
-
import { IMAGE_RENDERING } from '../../css/property-descriptors/image-rendering';
|
|
28
|
-
import { createCanvasPath } from './canvas-path';
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Dependencies required for BackgroundRenderer
|
|
32
|
-
*/
|
|
33
|
-
export interface BackgroundRendererDependencies {
|
|
34
|
-
ctx: CanvasRenderingContext2D;
|
|
35
|
-
context: Context;
|
|
36
|
-
canvas: HTMLCanvasElement;
|
|
37
|
-
options: {
|
|
38
|
-
width: number;
|
|
39
|
-
height: number;
|
|
40
|
-
scale: number;
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Background Renderer
|
|
46
|
-
*
|
|
47
|
-
* Specialized renderer for element backgrounds.
|
|
48
|
-
* Extracted from CanvasRenderer to improve code organization and maintainability.
|
|
49
|
-
*/
|
|
50
|
-
export class BackgroundRenderer {
|
|
51
|
-
private readonly ctx: CanvasRenderingContext2D;
|
|
52
|
-
private readonly context: Context;
|
|
53
|
-
private readonly canvas: HTMLCanvasElement;
|
|
54
|
-
|
|
55
|
-
constructor(deps: BackgroundRendererDependencies) {
|
|
56
|
-
this.ctx = deps.ctx;
|
|
57
|
-
this.context = deps.context;
|
|
58
|
-
this.canvas = deps.canvas;
|
|
59
|
-
// Options stored in deps but not needed as instance property
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Render background images for a container
|
|
64
|
-
* Supports URL images, linear gradients, and radial gradients
|
|
65
|
-
*
|
|
66
|
-
* @param container - Element container with background styles
|
|
67
|
-
*/
|
|
68
|
-
async renderBackgroundImage(container: ElementContainer): Promise<void> {
|
|
69
|
-
let index = container.styles.backgroundImage.length - 1;
|
|
70
|
-
for (const backgroundImage of container.styles.backgroundImage.slice(0).reverse()) {
|
|
71
|
-
if (backgroundImage.type === CSSImageType.URL) {
|
|
72
|
-
await this.renderBackgroundURLImage(container, backgroundImage as CSSURLImage, index);
|
|
73
|
-
} else if (isLinearGradient(backgroundImage)) {
|
|
74
|
-
this.renderLinearGradient(container, backgroundImage, index);
|
|
75
|
-
} else if (isRadialGradient(backgroundImage)) {
|
|
76
|
-
this.renderRadialGradient(container, backgroundImage, index);
|
|
77
|
-
}
|
|
78
|
-
index--;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Render a URL-based background image
|
|
84
|
-
*/
|
|
85
|
-
private async renderBackgroundURLImage(
|
|
86
|
-
container: ElementContainer,
|
|
87
|
-
backgroundImage: CSSURLImage,
|
|
88
|
-
index: number
|
|
89
|
-
): Promise<void> {
|
|
90
|
-
let image;
|
|
91
|
-
const url = backgroundImage.url;
|
|
92
|
-
try {
|
|
93
|
-
image = await this.context.cache.match(url);
|
|
94
|
-
} catch (e) {
|
|
95
|
-
this.context.logger.error(`Error loading background-image ${url}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (image) {
|
|
99
|
-
const imageWidth = isNaN(image.width) || image.width === 0 ? 1 : image.width;
|
|
100
|
-
const imageHeight = isNaN(image.height) || image.height === 0 ? 1 : image.height;
|
|
101
|
-
const [path, x, y, width, height] = calculateBackgroundRendering(container, index, [
|
|
102
|
-
imageWidth,
|
|
103
|
-
imageHeight,
|
|
104
|
-
imageWidth / imageHeight
|
|
105
|
-
]);
|
|
106
|
-
const pattern = this.ctx.createPattern(
|
|
107
|
-
this.resizeImage(image as HTMLImageElement, width, height, container.styles.imageRendering),
|
|
108
|
-
'repeat'
|
|
109
|
-
) as CanvasPattern;
|
|
110
|
-
this.renderRepeat(path, pattern, x, y);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Render a linear gradient background
|
|
116
|
-
*/
|
|
117
|
-
private renderLinearGradient(
|
|
118
|
-
container: ElementContainer,
|
|
119
|
-
backgroundImage: CSSLinearGradientImage,
|
|
120
|
-
index: number
|
|
121
|
-
): void {
|
|
122
|
-
const [path, x, y, width, height] = calculateBackgroundRendering(container, index, [null, null, null]);
|
|
123
|
-
const [lineLength, x0, x1, y0, y1] = calculateGradientDirection(backgroundImage.angle, width, height);
|
|
124
|
-
|
|
125
|
-
const ownerDocument = this.canvas.ownerDocument ?? document;
|
|
126
|
-
const canvas = ownerDocument.createElement('canvas');
|
|
127
|
-
canvas.width = width;
|
|
128
|
-
canvas.height = height;
|
|
129
|
-
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
|
130
|
-
const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
|
|
131
|
-
|
|
132
|
-
processColorStops(backgroundImage.stops, lineLength || 1).forEach((colorStop) =>
|
|
133
|
-
gradient.addColorStop(colorStop.stop, asString(colorStop.color))
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
ctx.fillStyle = gradient;
|
|
137
|
-
ctx.fillRect(0, 0, width, height);
|
|
138
|
-
if (width > 0 && height > 0) {
|
|
139
|
-
const pattern = this.ctx.createPattern(canvas, 'repeat') as CanvasPattern;
|
|
140
|
-
this.renderRepeat(path, pattern, x, y);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Render a radial gradient background
|
|
146
|
-
*/
|
|
147
|
-
private renderRadialGradient(
|
|
148
|
-
container: ElementContainer,
|
|
149
|
-
backgroundImage: CSSRadialGradientImage,
|
|
150
|
-
index: number
|
|
151
|
-
): void {
|
|
152
|
-
const [path, left, top, width, height] = calculateBackgroundRendering(container, index, [null, null, null]);
|
|
153
|
-
const position = backgroundImage.position.length === 0 ? [FIFTY_PERCENT] : backgroundImage.position;
|
|
154
|
-
const x = getAbsoluteValue(position[0], width);
|
|
155
|
-
const y = getAbsoluteValue(position[position.length - 1], height);
|
|
156
|
-
|
|
157
|
-
let [rx, ry] = calculateRadius(backgroundImage, x, y, width, height);
|
|
158
|
-
// Handle edge case where radial gradient size is 0
|
|
159
|
-
// Use a minimum value of 0.01 to ensure gradient is still rendered
|
|
160
|
-
if (rx === 0 || ry === 0) {
|
|
161
|
-
rx = Math.max(rx, 0.01);
|
|
162
|
-
ry = Math.max(ry, 0.01);
|
|
163
|
-
}
|
|
164
|
-
if (rx > 0 && ry > 0) {
|
|
165
|
-
const radialGradient = this.ctx.createRadialGradient(left + x, top + y, 0, left + x, top + y, rx);
|
|
166
|
-
|
|
167
|
-
processColorStops(backgroundImage.stops, rx * 2).forEach((colorStop) =>
|
|
168
|
-
radialGradient.addColorStop(colorStop.stop, asString(colorStop.color))
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
this.path(path);
|
|
172
|
-
this.ctx.fillStyle = radialGradient;
|
|
173
|
-
if (rx !== ry) {
|
|
174
|
-
// transforms for elliptical radial gradient
|
|
175
|
-
const midX = container.bounds.left + 0.5 * container.bounds.width;
|
|
176
|
-
const midY = container.bounds.top + 0.5 * container.bounds.height;
|
|
177
|
-
const f = ry / rx;
|
|
178
|
-
const invF = 1 / f;
|
|
179
|
-
|
|
180
|
-
this.ctx.save();
|
|
181
|
-
this.ctx.translate(midX, midY);
|
|
182
|
-
this.ctx.transform(1, 0, 0, f, 0, 0);
|
|
183
|
-
this.ctx.translate(-midX, -midY);
|
|
184
|
-
|
|
185
|
-
this.ctx.fillRect(left, invF * (top - midY) + midY, width, height * invF);
|
|
186
|
-
this.ctx.restore();
|
|
187
|
-
} else {
|
|
188
|
-
this.ctx.fill();
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Render a repeating pattern with offset
|
|
195
|
-
*
|
|
196
|
-
* @param path - Path to fill
|
|
197
|
-
* @param pattern - Canvas pattern or gradient
|
|
198
|
-
* @param offsetX - X offset for pattern
|
|
199
|
-
* @param offsetY - Y offset for pattern
|
|
200
|
-
*/
|
|
201
|
-
private renderRepeat(
|
|
202
|
-
path: Path[],
|
|
203
|
-
pattern: CanvasPattern | CanvasGradient,
|
|
204
|
-
offsetX: number,
|
|
205
|
-
offsetY: number
|
|
206
|
-
): void {
|
|
207
|
-
this.path(path);
|
|
208
|
-
this.ctx.fillStyle = pattern;
|
|
209
|
-
this.ctx.translate(offsetX, offsetY);
|
|
210
|
-
this.ctx.fill();
|
|
211
|
-
this.ctx.translate(-offsetX, -offsetY);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Resize an image to target dimensions
|
|
216
|
-
*
|
|
217
|
-
* @param image - Source image
|
|
218
|
-
* @param width - Target width
|
|
219
|
-
* @param height - Target height
|
|
220
|
-
* @param imageRendering - CSS image-rendering property value
|
|
221
|
-
* @returns Resized canvas or original image
|
|
222
|
-
*/
|
|
223
|
-
private resizeImage(
|
|
224
|
-
image: HTMLImageElement,
|
|
225
|
-
width: number,
|
|
226
|
-
height: number,
|
|
227
|
-
imageRendering: IMAGE_RENDERING
|
|
228
|
-
): HTMLCanvasElement | HTMLImageElement {
|
|
229
|
-
// https://github.com/niklasvh/html2canvas/pull/2911
|
|
230
|
-
// if (image.width === width && image.height === height) {
|
|
231
|
-
// return image;
|
|
232
|
-
// }
|
|
233
|
-
|
|
234
|
-
const ownerDocument = this.canvas.ownerDocument ?? document;
|
|
235
|
-
const canvas = ownerDocument.createElement('canvas');
|
|
236
|
-
canvas.width = Math.max(1, width);
|
|
237
|
-
canvas.height = Math.max(1, height);
|
|
238
|
-
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
|
239
|
-
|
|
240
|
-
// Apply image smoothing based on CSS image-rendering property
|
|
241
|
-
if (imageRendering === IMAGE_RENDERING.PIXELATED || imageRendering === IMAGE_RENDERING.CRISP_EDGES) {
|
|
242
|
-
this.context.logger.debug(`Disabling image smoothing for background image due to CSS image-rendering`);
|
|
243
|
-
ctx.imageSmoothingEnabled = false;
|
|
244
|
-
} else if (imageRendering === IMAGE_RENDERING.SMOOTH) {
|
|
245
|
-
this.context.logger.debug(
|
|
246
|
-
`Enabling image smoothing for background image due to CSS image-rendering: smooth`
|
|
247
|
-
);
|
|
248
|
-
ctx.imageSmoothingEnabled = true;
|
|
249
|
-
} else {
|
|
250
|
-
// AUTO: inherit from main renderer context
|
|
251
|
-
ctx.imageSmoothingEnabled = this.ctx.imageSmoothingEnabled;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Inherit quality setting
|
|
255
|
-
if (this.ctx.imageSmoothingQuality) {
|
|
256
|
-
ctx.imageSmoothingQuality = this.ctx.imageSmoothingQuality;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height);
|
|
260
|
-
return canvas;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Create a canvas path from path array
|
|
265
|
-
*
|
|
266
|
-
* @param paths - Array of path points
|
|
267
|
-
*/
|
|
268
|
-
private path(paths: Path[]): void {
|
|
269
|
-
createCanvasPath(this.ctx, paths);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Border Renderer
|
|
3
|
-
*
|
|
4
|
-
* Handles rendering of element borders including:
|
|
5
|
-
* - Solid borders
|
|
6
|
-
* - Double borders
|
|
7
|
-
* - Dashed borders
|
|
8
|
-
* - Dotted borders
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { Color } from '../../css/types/color';
|
|
12
|
-
import { asString } from '../../css/types/color-utilities';
|
|
13
|
-
import { BoundCurves } from '../bound-curves';
|
|
14
|
-
import { BORDER_STYLE } from '../../css/property-descriptors/border-style';
|
|
15
|
-
import {
|
|
16
|
-
parsePathForBorder,
|
|
17
|
-
parsePathForBorderDoubleInner,
|
|
18
|
-
parsePathForBorderDoubleOuter,
|
|
19
|
-
parsePathForBorderStroke
|
|
20
|
-
} from '../border';
|
|
21
|
-
import { isBezierCurve, BezierCurve } from '../bezier-curve';
|
|
22
|
-
import { Vector } from '../vector';
|
|
23
|
-
import { Path } from '../path';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Dependencies required for BorderRenderer
|
|
27
|
-
*/
|
|
28
|
-
export interface BorderRendererDependencies {
|
|
29
|
-
ctx: CanvasRenderingContext2D;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Path creation callbacks
|
|
34
|
-
* The main CanvasRenderer retains path() and formatPath() methods,
|
|
35
|
-
* so we inject them as callbacks to avoid duplication
|
|
36
|
-
*/
|
|
37
|
-
export interface PathCallbacks {
|
|
38
|
-
path(paths: Path[]): void;
|
|
39
|
-
formatPath(paths: Path[]): void;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Border Renderer
|
|
44
|
-
*
|
|
45
|
-
* Specialized renderer for element borders.
|
|
46
|
-
* Extracted from CanvasRenderer to improve code organization and maintainability.
|
|
47
|
-
*/
|
|
48
|
-
export class BorderRenderer {
|
|
49
|
-
private readonly ctx: CanvasRenderingContext2D;
|
|
50
|
-
private pathCallbacks: PathCallbacks;
|
|
51
|
-
|
|
52
|
-
constructor(deps: BorderRendererDependencies, pathCallbacks: PathCallbacks) {
|
|
53
|
-
this.ctx = deps.ctx;
|
|
54
|
-
this.pathCallbacks = pathCallbacks;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Render a solid border
|
|
59
|
-
*
|
|
60
|
-
* @param color - Border color
|
|
61
|
-
* @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
|
|
62
|
-
* @param curvePoints - Border curve points
|
|
63
|
-
*/
|
|
64
|
-
async renderSolidBorder(color: Color, side: number, curvePoints: BoundCurves): Promise<void> {
|
|
65
|
-
this.pathCallbacks.path(parsePathForBorder(curvePoints, side));
|
|
66
|
-
this.ctx.fillStyle = asString(color);
|
|
67
|
-
this.ctx.fill();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Render a double border
|
|
72
|
-
* Falls back to solid border if width is too small
|
|
73
|
-
*
|
|
74
|
-
* @param color - Border color
|
|
75
|
-
* @param width - Border width
|
|
76
|
-
* @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
|
|
77
|
-
* @param curvePoints - Border curve points
|
|
78
|
-
*/
|
|
79
|
-
async renderDoubleBorder(color: Color, width: number, side: number, curvePoints: BoundCurves): Promise<void> {
|
|
80
|
-
if (width < 3) {
|
|
81
|
-
await this.renderSolidBorder(color, side, curvePoints);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const outerPaths = parsePathForBorderDoubleOuter(curvePoints, side);
|
|
86
|
-
this.pathCallbacks.path(outerPaths);
|
|
87
|
-
this.ctx.fillStyle = asString(color);
|
|
88
|
-
this.ctx.fill();
|
|
89
|
-
const innerPaths = parsePathForBorderDoubleInner(curvePoints, side);
|
|
90
|
-
this.pathCallbacks.path(innerPaths);
|
|
91
|
-
this.ctx.fill();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Render a dashed or dotted border
|
|
96
|
-
*
|
|
97
|
-
* @param color - Border color
|
|
98
|
-
* @param width - Border width
|
|
99
|
-
* @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
|
|
100
|
-
* @param curvePoints - Border curve points
|
|
101
|
-
* @param style - Border style (DASHED or DOTTED)
|
|
102
|
-
*/
|
|
103
|
-
async renderDashedDottedBorder(
|
|
104
|
-
color: Color,
|
|
105
|
-
width: number,
|
|
106
|
-
side: number,
|
|
107
|
-
curvePoints: BoundCurves,
|
|
108
|
-
style: BORDER_STYLE
|
|
109
|
-
): Promise<void> {
|
|
110
|
-
this.ctx.save();
|
|
111
|
-
|
|
112
|
-
const strokePaths = parsePathForBorderStroke(curvePoints, side);
|
|
113
|
-
const boxPaths = parsePathForBorder(curvePoints, side);
|
|
114
|
-
|
|
115
|
-
if (style === BORDER_STYLE.DASHED) {
|
|
116
|
-
this.pathCallbacks.path(boxPaths);
|
|
117
|
-
this.ctx.clip();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Extract start and end coordinates
|
|
121
|
-
let startX, startY, endX, endY;
|
|
122
|
-
if (isBezierCurve(boxPaths[0])) {
|
|
123
|
-
startX = (boxPaths[0] as BezierCurve).start.x;
|
|
124
|
-
startY = (boxPaths[0] as BezierCurve).start.y;
|
|
125
|
-
} else {
|
|
126
|
-
startX = (boxPaths[0] as Vector).x;
|
|
127
|
-
startY = (boxPaths[0] as Vector).y;
|
|
128
|
-
}
|
|
129
|
-
if (isBezierCurve(boxPaths[1])) {
|
|
130
|
-
endX = (boxPaths[1] as BezierCurve).end.x;
|
|
131
|
-
endY = (boxPaths[1] as BezierCurve).end.y;
|
|
132
|
-
} else {
|
|
133
|
-
endX = (boxPaths[1] as Vector).x;
|
|
134
|
-
endY = (boxPaths[1] as Vector).y;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Calculate border length
|
|
138
|
-
let length;
|
|
139
|
-
if (side === 0 || side === 2) {
|
|
140
|
-
length = Math.abs(startX - endX);
|
|
141
|
-
} else {
|
|
142
|
-
length = Math.abs(startY - endY);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
this.ctx.beginPath();
|
|
146
|
-
if (style === BORDER_STYLE.DOTTED) {
|
|
147
|
-
this.pathCallbacks.formatPath(strokePaths);
|
|
148
|
-
} else {
|
|
149
|
-
this.pathCallbacks.formatPath(boxPaths.slice(0, 2));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Calculate dash and space lengths
|
|
153
|
-
let dashLength = width < 3 ? width * 3 : width * 2;
|
|
154
|
-
let spaceLength = width < 3 ? width * 2 : width;
|
|
155
|
-
if (style === BORDER_STYLE.DOTTED) {
|
|
156
|
-
dashLength = width;
|
|
157
|
-
spaceLength = width;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Adjust dash pattern for border length
|
|
161
|
-
let useLineDash = true;
|
|
162
|
-
if (length <= dashLength * 2) {
|
|
163
|
-
useLineDash = false;
|
|
164
|
-
} else if (length <= dashLength * 2 + spaceLength) {
|
|
165
|
-
const multiplier = length / (2 * dashLength + spaceLength);
|
|
166
|
-
dashLength *= multiplier;
|
|
167
|
-
spaceLength *= multiplier;
|
|
168
|
-
} else {
|
|
169
|
-
const numberOfDashes = Math.floor((length + spaceLength) / (dashLength + spaceLength));
|
|
170
|
-
const minSpace = (length - numberOfDashes * dashLength) / (numberOfDashes - 1);
|
|
171
|
-
const maxSpace = (length - (numberOfDashes + 1) * dashLength) / numberOfDashes;
|
|
172
|
-
spaceLength =
|
|
173
|
-
maxSpace <= 0 || Math.abs(spaceLength - minSpace) < Math.abs(spaceLength - maxSpace)
|
|
174
|
-
? minSpace
|
|
175
|
-
: maxSpace;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Apply line dash pattern
|
|
179
|
-
if (useLineDash) {
|
|
180
|
-
if (style === BORDER_STYLE.DOTTED) {
|
|
181
|
-
this.ctx.setLineDash([0, dashLength + spaceLength]);
|
|
182
|
-
} else {
|
|
183
|
-
this.ctx.setLineDash([dashLength, spaceLength]);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Set line style and stroke
|
|
188
|
-
if (style === BORDER_STYLE.DOTTED) {
|
|
189
|
-
this.ctx.lineCap = 'round';
|
|
190
|
-
this.ctx.lineWidth = width;
|
|
191
|
-
} else {
|
|
192
|
-
this.ctx.lineWidth = width * 2 + 1.1;
|
|
193
|
-
}
|
|
194
|
-
this.ctx.strokeStyle = asString(color);
|
|
195
|
-
this.ctx.stroke();
|
|
196
|
-
this.ctx.setLineDash([]);
|
|
197
|
-
|
|
198
|
-
// Fill dashed round edge gaps
|
|
199
|
-
if (style === BORDER_STYLE.DASHED) {
|
|
200
|
-
if (isBezierCurve(boxPaths[0])) {
|
|
201
|
-
const path1 = boxPaths[3] as BezierCurve;
|
|
202
|
-
const path2 = boxPaths[0] as BezierCurve;
|
|
203
|
-
this.ctx.beginPath();
|
|
204
|
-
this.pathCallbacks.formatPath([
|
|
205
|
-
new Vector(path1.end.x, path1.end.y),
|
|
206
|
-
new Vector(path2.start.x, path2.start.y)
|
|
207
|
-
]);
|
|
208
|
-
this.ctx.stroke();
|
|
209
|
-
}
|
|
210
|
-
if (isBezierCurve(boxPaths[1])) {
|
|
211
|
-
const path1 = boxPaths[1] as BezierCurve;
|
|
212
|
-
const path2 = boxPaths[2] as BezierCurve;
|
|
213
|
-
this.ctx.beginPath();
|
|
214
|
-
this.pathCallbacks.formatPath([
|
|
215
|
-
new Vector(path1.end.x, path1.end.y),
|
|
216
|
-
new Vector(path2.start.x, path2.start.y)
|
|
217
|
-
]);
|
|
218
|
-
this.ctx.stroke();
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
this.ctx.restore();
|
|
223
|
-
}
|
|
224
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { isBezierCurve } from '../bezier-curve';
|
|
2
|
-
import { Path } from '../path';
|
|
3
|
-
import { Vector } from '../vector';
|
|
4
|
-
|
|
5
|
-
export const formatCanvasPath = (ctx: CanvasRenderingContext2D, paths: Path[]): void => {
|
|
6
|
-
paths.forEach((point, index) => {
|
|
7
|
-
const start: Vector = isBezierCurve(point) ? point.start : point;
|
|
8
|
-
if (index === 0) {
|
|
9
|
-
ctx.moveTo(start.x, start.y);
|
|
10
|
-
} else {
|
|
11
|
-
ctx.lineTo(start.x, start.y);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (isBezierCurve(point)) {
|
|
15
|
-
ctx.bezierCurveTo(
|
|
16
|
-
point.startControl.x,
|
|
17
|
-
point.startControl.y,
|
|
18
|
-
point.endControl.x,
|
|
19
|
-
point.endControl.y,
|
|
20
|
-
point.end.x,
|
|
21
|
-
point.end.y
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const createCanvasPath = (ctx: CanvasRenderingContext2D, paths: Path[]): void => {
|
|
28
|
-
ctx.beginPath();
|
|
29
|
-
formatCanvasPath(ctx, paths);
|
|
30
|
-
ctx.closePath();
|
|
31
|
-
};
|