@remotion/web-renderer 4.0.391 → 4.0.392
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/border-radius.d.ts +31 -0
- package/dist/border-radius.js +152 -0
- package/dist/calculate-transforms.d.ts +11 -0
- package/dist/calculate-transforms.js +91 -0
- package/dist/composable.d.ts +4 -0
- package/dist/composable.js +1 -0
- package/dist/compose-canvas.d.ts +1 -0
- package/dist/compose-canvas.js +36 -0
- package/dist/compose-svg.d.ts +1 -0
- package/dist/compose-svg.js +34 -0
- package/dist/drawing/calculate-transforms.js +27 -8
- package/dist/drawing/compose-canvas.d.ts +1 -0
- package/dist/drawing/compose-canvas.js +36 -0
- package/dist/drawing/compose-svg.d.ts +1 -0
- package/dist/drawing/compose-svg.js +34 -0
- package/dist/drawing/compose.d.ts +5 -0
- package/dist/drawing/compose.js +6 -0
- package/dist/drawing/draw-element-to-canvas.js +40 -47
- package/dist/drawing/draw-element.d.ts +8 -0
- package/dist/drawing/draw-element.js +50 -0
- package/dist/drawing/get-computed-style-cache.d.ts +0 -0
- package/dist/drawing/get-computed-style-cache.js +1 -0
- package/dist/drawing/text/draw-text.d.ts +1 -0
- package/dist/drawing/text/draw-text.js +57 -0
- package/dist/drawing/text/handle-text-node.js +0 -12
- package/dist/drawing/transform-in-3d.d.ts +8 -0
- package/dist/drawing/transform-in-3d.js +125 -0
- package/dist/esm/index.mjs +301 -103
- package/dist/find-canvas-elements.d.ts +1 -0
- package/dist/find-canvas-elements.js +13 -0
- package/dist/find-capturable-elements.d.ts +2 -0
- package/dist/find-capturable-elements.js +26 -0
- package/dist/opacity.d.ts +4 -0
- package/dist/opacity.js +7 -0
- package/dist/parse-transform-origin.d.ts +4 -0
- package/dist/parse-transform-origin.js +7 -0
- package/dist/transform.d.ts +4 -0
- package/dist/transform.js +6 -0
- package/package.json +5 -5
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { parseBorderRadius, setBorderRadius } from './border-radius';
|
|
2
|
+
import { drawBorder } from './draw-border';
|
|
3
|
+
import { setOpacity } from './opacity';
|
|
4
|
+
import { setTransform } from './transform';
|
|
5
|
+
export const drawElement = async ({ dimensions, computedStyle, context, draw, opacity, totalMatrix, }) => {
|
|
6
|
+
const background = computedStyle.backgroundColor;
|
|
7
|
+
const borderRadius = parseBorderRadius({
|
|
8
|
+
borderRadius: computedStyle.borderRadius,
|
|
9
|
+
width: dimensions.width,
|
|
10
|
+
height: dimensions.height,
|
|
11
|
+
});
|
|
12
|
+
const finishTransform = setTransform({
|
|
13
|
+
ctx: context,
|
|
14
|
+
transform: totalMatrix,
|
|
15
|
+
});
|
|
16
|
+
const finishBorderRadius = setBorderRadius({
|
|
17
|
+
ctx: context,
|
|
18
|
+
x: dimensions.left,
|
|
19
|
+
y: dimensions.top,
|
|
20
|
+
width: dimensions.width,
|
|
21
|
+
height: dimensions.height,
|
|
22
|
+
borderRadius,
|
|
23
|
+
});
|
|
24
|
+
const finishOpacity = setOpacity({
|
|
25
|
+
ctx: context,
|
|
26
|
+
opacity,
|
|
27
|
+
});
|
|
28
|
+
if (background &&
|
|
29
|
+
background !== 'transparent' &&
|
|
30
|
+
!(background.startsWith('rgba') &&
|
|
31
|
+
(background.endsWith(', 0)') || background.endsWith(',0')))) {
|
|
32
|
+
const originalFillStyle = context.fillStyle;
|
|
33
|
+
context.fillStyle = background;
|
|
34
|
+
context.fillRect(dimensions.left, dimensions.top, dimensions.width, dimensions.height);
|
|
35
|
+
context.fillStyle = originalFillStyle;
|
|
36
|
+
}
|
|
37
|
+
await draw(dimensions, computedStyle);
|
|
38
|
+
drawBorder({
|
|
39
|
+
ctx: context,
|
|
40
|
+
x: dimensions.left,
|
|
41
|
+
y: dimensions.top,
|
|
42
|
+
width: dimensions.width,
|
|
43
|
+
height: dimensions.height,
|
|
44
|
+
borderRadius,
|
|
45
|
+
computedStyle,
|
|
46
|
+
});
|
|
47
|
+
finishOpacity();
|
|
48
|
+
finishBorderRadius();
|
|
49
|
+
finishTransform();
|
|
50
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const drawTextToCanvas: (parentElement: HTMLElement, context: OffscreenCanvasRenderingContext2D) => Promise<void>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { withResolvers } from '../../with-resolvers';
|
|
2
|
+
export const drawTextToCanvas = async (parentElement, context) => {
|
|
3
|
+
const clientRect = parentElement.getBoundingClientRect();
|
|
4
|
+
const computedStyle = getComputedStyle(parentElement);
|
|
5
|
+
const clonedNode = parentElement.cloneNode(true);
|
|
6
|
+
for (let i = 0; i < computedStyle.length; i++) {
|
|
7
|
+
const propertyName = computedStyle[i];
|
|
8
|
+
const value = computedStyle.getPropertyValue(propertyName);
|
|
9
|
+
if (propertyName === 'margin-top' ||
|
|
10
|
+
propertyName === 'margin-bottom' ||
|
|
11
|
+
propertyName === 'margin-left' ||
|
|
12
|
+
propertyName === 'margin-right' ||
|
|
13
|
+
propertyName === 'margin') {
|
|
14
|
+
// @ts-expect-error - propertyName is a valid CSS property
|
|
15
|
+
clonedNode.style[propertyName] = '0px';
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
// @ts-expect-error - propertyName is a valid CSS property
|
|
19
|
+
clonedNode.style[propertyName] = value;
|
|
20
|
+
}
|
|
21
|
+
// Create an SVG that contains the cloned node via a foreignObject
|
|
22
|
+
const svgNS = 'http://www.w3.org/2000/svg';
|
|
23
|
+
const svg = document.createElementNS(svgNS, 'svg');
|
|
24
|
+
svg.setAttribute('width', `${clientRect.width}`);
|
|
25
|
+
svg.setAttribute('height', `${clientRect.height}`);
|
|
26
|
+
const foreignObject = document.createElementNS(svgNS, 'foreignObject');
|
|
27
|
+
foreignObject.setAttribute('x', '0');
|
|
28
|
+
foreignObject.setAttribute('y', '0');
|
|
29
|
+
foreignObject.setAttribute('width', `${clientRect.width}`);
|
|
30
|
+
foreignObject.setAttribute('height', `${clientRect.height}`);
|
|
31
|
+
// The cloned node must be in XHTML namespace to render properly
|
|
32
|
+
const xhtmlNS = 'http://www.w3.org/1999/xhtml';
|
|
33
|
+
const wrappedDiv = document.createElementNS(xhtmlNS, 'div');
|
|
34
|
+
wrappedDiv.style.width = `${clientRect.width}px`;
|
|
35
|
+
wrappedDiv.style.height = `${clientRect.height}px`;
|
|
36
|
+
wrappedDiv.appendChild(clonedNode);
|
|
37
|
+
foreignObject.appendChild(wrappedDiv);
|
|
38
|
+
svg.appendChild(foreignObject);
|
|
39
|
+
// Convert SVG to data URL
|
|
40
|
+
const serializer = new XMLSerializer();
|
|
41
|
+
const svgString = serializer.serializeToString(svg);
|
|
42
|
+
const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
|
|
43
|
+
const { promise, resolve, reject } = withResolvers();
|
|
44
|
+
// Create image and draw when loaded
|
|
45
|
+
const img = new window.Image();
|
|
46
|
+
img.onload = function () {
|
|
47
|
+
resolve(img);
|
|
48
|
+
};
|
|
49
|
+
img.onerror = function (err) {
|
|
50
|
+
// We may want to add robust error handling here
|
|
51
|
+
reject(err);
|
|
52
|
+
};
|
|
53
|
+
img.src = svgDataUrl;
|
|
54
|
+
await promise;
|
|
55
|
+
console.log(clientRect);
|
|
56
|
+
context.drawImage(img, clientRect.left, clientRect.top, clientRect.width, clientRect.height);
|
|
57
|
+
};
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
// Supported:
|
|
2
|
-
// - fontFamily
|
|
3
|
-
// - fontSize
|
|
4
|
-
// - fontWeight
|
|
5
|
-
// - color
|
|
6
|
-
// - lineHeight
|
|
7
|
-
// - direction
|
|
8
|
-
// - letterSpacing
|
|
9
|
-
// - textTransform
|
|
10
|
-
// Not supported:
|
|
11
|
-
// - writingMode
|
|
12
|
-
// - textDecoration
|
|
13
1
|
import { Internals } from 'remotion';
|
|
14
2
|
import { drawElementToCanvas } from '../draw-element-to-canvas';
|
|
15
3
|
import { findLineBreaks } from './find-line-breaks.text';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const transformIn3d: ({ canvasWidth, canvasHeight, matrix, sourceCanvas, offsetLeft, offsetTop, }: {
|
|
2
|
+
canvasWidth: number;
|
|
3
|
+
canvasHeight: number;
|
|
4
|
+
offsetLeft: number;
|
|
5
|
+
offsetTop: number;
|
|
6
|
+
matrix: DOMMatrix;
|
|
7
|
+
sourceCanvas: HTMLCanvasElement | OffscreenCanvas;
|
|
8
|
+
}) => OffscreenCanvas;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
function compileShader(shaderGl, source, type) {
|
|
2
|
+
const shader = shaderGl.createShader(type);
|
|
3
|
+
if (!shader) {
|
|
4
|
+
throw new Error('Could not create shader');
|
|
5
|
+
}
|
|
6
|
+
shaderGl.shaderSource(shader, source);
|
|
7
|
+
shaderGl.compileShader(shader);
|
|
8
|
+
if (!shaderGl.getShaderParameter(shader, shaderGl.COMPILE_STATUS)) {
|
|
9
|
+
const log = shaderGl.getShaderInfoLog(shader);
|
|
10
|
+
shaderGl.deleteShader(shader);
|
|
11
|
+
throw new Error('Shader compile error: ' + log);
|
|
12
|
+
}
|
|
13
|
+
return shader;
|
|
14
|
+
}
|
|
15
|
+
export const transformIn3d = ({ canvasWidth, canvasHeight, matrix, sourceCanvas, offsetLeft, offsetTop, }) => {
|
|
16
|
+
const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
|
|
17
|
+
const gl = canvas.getContext('webgl');
|
|
18
|
+
if (!gl) {
|
|
19
|
+
throw new Error('WebGL not supported');
|
|
20
|
+
}
|
|
21
|
+
// Vertex shader - now includes texture coordinates
|
|
22
|
+
const vsSource = `
|
|
23
|
+
attribute vec2 aPosition;
|
|
24
|
+
attribute vec2 aTexCoord;
|
|
25
|
+
uniform mat4 uTransform;
|
|
26
|
+
uniform mat4 uProjection;
|
|
27
|
+
varying vec2 vTexCoord;
|
|
28
|
+
|
|
29
|
+
void main() {
|
|
30
|
+
gl_Position = uProjection * uTransform * vec4(aPosition, 0.0, 1.0);
|
|
31
|
+
vTexCoord = aTexCoord;
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
// Fragment shader - now samples from texture
|
|
35
|
+
const fsSource = `
|
|
36
|
+
precision mediump float;
|
|
37
|
+
uniform sampler2D uTexture;
|
|
38
|
+
varying vec2 vTexCoord;
|
|
39
|
+
|
|
40
|
+
void main() {
|
|
41
|
+
gl_FragColor = texture2D(uTexture, vTexCoord);
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
// Create program
|
|
45
|
+
const vertexShader = compileShader(gl, vsSource, gl.VERTEX_SHADER);
|
|
46
|
+
const fragmentShader = compileShader(gl, fsSource, gl.FRAGMENT_SHADER);
|
|
47
|
+
const program = gl.createProgram();
|
|
48
|
+
gl.attachShader(program, vertexShader);
|
|
49
|
+
gl.attachShader(program, fragmentShader);
|
|
50
|
+
gl.linkProgram(program);
|
|
51
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
52
|
+
throw new Error('Program link error: ' + gl.getProgramInfoLog(program));
|
|
53
|
+
}
|
|
54
|
+
gl.useProgram(program);
|
|
55
|
+
// Create a quad (two triangles) with texture coordinates
|
|
56
|
+
// prettier-ignore
|
|
57
|
+
const vertices = new Float32Array([
|
|
58
|
+
// Position (x, y) + TexCoord (u, v)
|
|
59
|
+
// First:
|
|
60
|
+
offsetLeft, offsetTop, 0, 0, // bottom-left
|
|
61
|
+
canvasWidth + offsetLeft, offsetTop, 1, 0, // bottom-right
|
|
62
|
+
offsetLeft, canvasHeight + offsetTop, 0, 1, // top-left
|
|
63
|
+
// Second:
|
|
64
|
+
offsetLeft, canvasHeight + offsetTop, 0, 1, // top-left
|
|
65
|
+
canvasWidth + offsetLeft, offsetTop, 1, 0, // bottom-right
|
|
66
|
+
canvasWidth + offsetLeft, canvasHeight + offsetTop, 1, 1, // top-right
|
|
67
|
+
]);
|
|
68
|
+
const vertexBuffer = gl.createBuffer();
|
|
69
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
70
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
71
|
+
const aPosition = gl.getAttribLocation(program, 'aPosition');
|
|
72
|
+
const aTexCoord = gl.getAttribLocation(program, 'aTexCoord');
|
|
73
|
+
// Position attribute (2 floats, stride 4 floats, offset 0)
|
|
74
|
+
gl.enableVertexAttribArray(aPosition);
|
|
75
|
+
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 4 * 4, 0);
|
|
76
|
+
// Texture coordinate attribute (2 floats, stride 4 floats, offset 2)
|
|
77
|
+
gl.enableVertexAttribArray(aTexCoord);
|
|
78
|
+
gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, 4 * 4, 2 * 4);
|
|
79
|
+
// Create and configure texture
|
|
80
|
+
const texture = gl.createTexture();
|
|
81
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
82
|
+
// Set texture parameters
|
|
83
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
84
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
85
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
86
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
87
|
+
// Upload the source canvas as a texture
|
|
88
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, sourceCanvas);
|
|
89
|
+
// The transform matrix
|
|
90
|
+
const transformMatrix = matrix.toFloat32Array();
|
|
91
|
+
const zScale = 1000000000; // By default infinite in chrome
|
|
92
|
+
// Create orthographic projection matrix for pixel coordinates
|
|
93
|
+
const projectionMatrix = new Float32Array([
|
|
94
|
+
2 / canvasWidth,
|
|
95
|
+
0,
|
|
96
|
+
0,
|
|
97
|
+
0,
|
|
98
|
+
0,
|
|
99
|
+
-2 / canvasHeight,
|
|
100
|
+
0,
|
|
101
|
+
0,
|
|
102
|
+
0,
|
|
103
|
+
0,
|
|
104
|
+
-2 / zScale,
|
|
105
|
+
0,
|
|
106
|
+
-1,
|
|
107
|
+
1,
|
|
108
|
+
0,
|
|
109
|
+
1,
|
|
110
|
+
]);
|
|
111
|
+
const uTransform = gl.getUniformLocation(program, 'uTransform');
|
|
112
|
+
const uProjection = gl.getUniformLocation(program, 'uProjection');
|
|
113
|
+
const uTexture = gl.getUniformLocation(program, 'uTexture');
|
|
114
|
+
gl.uniformMatrix4fv(uTransform, false, transformMatrix);
|
|
115
|
+
gl.uniformMatrix4fv(uProjection, false, projectionMatrix);
|
|
116
|
+
gl.uniform1i(uTexture, 0); // Use texture unit 0
|
|
117
|
+
// Clear and draw
|
|
118
|
+
gl.clearColor(0, 0, 0, 0); // Transparent background
|
|
119
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
120
|
+
// Enable blending for transparency
|
|
121
|
+
gl.enable(gl.BLEND);
|
|
122
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
123
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
124
|
+
return canvas;
|
|
125
|
+
};
|
package/dist/esm/index.mjs
CHANGED
|
@@ -8664,6 +8664,110 @@ var getQualityForWebRendererQuality = (quality) => {
|
|
|
8664
8664
|
}
|
|
8665
8665
|
};
|
|
8666
8666
|
|
|
8667
|
+
// src/drawing/parse-transform-origin.ts
|
|
8668
|
+
var parseTransformOrigin = (transformOrigin) => {
|
|
8669
|
+
if (transformOrigin.trim() === "") {
|
|
8670
|
+
return null;
|
|
8671
|
+
}
|
|
8672
|
+
const [x, y] = transformOrigin.split(" ");
|
|
8673
|
+
return { x: parseFloat(x), y: parseFloat(y) };
|
|
8674
|
+
};
|
|
8675
|
+
|
|
8676
|
+
// src/drawing/calculate-transforms.ts
|
|
8677
|
+
var getInternalTransformOrigin = (transform) => {
|
|
8678
|
+
const centerX = transform.boundingClientRect.width / 2;
|
|
8679
|
+
const centerY = transform.boundingClientRect.height / 2;
|
|
8680
|
+
const origin = parseTransformOrigin(transform.transformOrigin) ?? {
|
|
8681
|
+
x: centerX,
|
|
8682
|
+
y: centerY
|
|
8683
|
+
};
|
|
8684
|
+
return origin;
|
|
8685
|
+
};
|
|
8686
|
+
var getGlobalTransformOrigin = (transform) => {
|
|
8687
|
+
const { x: originX, y: originY } = getInternalTransformOrigin(transform);
|
|
8688
|
+
return {
|
|
8689
|
+
x: originX + transform.boundingClientRect.left,
|
|
8690
|
+
y: originY + transform.boundingClientRect.top
|
|
8691
|
+
};
|
|
8692
|
+
};
|
|
8693
|
+
var calculateTransforms = (element) => {
|
|
8694
|
+
let parent = element;
|
|
8695
|
+
const transforms = [];
|
|
8696
|
+
const toReset = [];
|
|
8697
|
+
let opacity = 1;
|
|
8698
|
+
let elementComputedStyle = null;
|
|
8699
|
+
while (parent) {
|
|
8700
|
+
const computedStyle = getComputedStyle(parent);
|
|
8701
|
+
const parentOpacity = computedStyle.opacity;
|
|
8702
|
+
if (parentOpacity && parentOpacity !== "") {
|
|
8703
|
+
opacity *= parseFloat(parentOpacity);
|
|
8704
|
+
}
|
|
8705
|
+
if (parent === element) {
|
|
8706
|
+
elementComputedStyle = computedStyle;
|
|
8707
|
+
}
|
|
8708
|
+
if (computedStyle.transform && computedStyle.transform !== "none" || parent === element) {
|
|
8709
|
+
const toParse = computedStyle.transform === "none" || computedStyle.transform === "" ? undefined : computedStyle.transform;
|
|
8710
|
+
const matrix = new DOMMatrix(toParse);
|
|
8711
|
+
const { transform, scale, rotate } = parent.style;
|
|
8712
|
+
const additionalMatrices = [];
|
|
8713
|
+
if (rotate !== "") {
|
|
8714
|
+
additionalMatrices.push(new DOMMatrix(`rotate(${rotate})`));
|
|
8715
|
+
}
|
|
8716
|
+
if (scale !== "") {
|
|
8717
|
+
additionalMatrices.push(new DOMMatrix(`scale(${scale})`));
|
|
8718
|
+
}
|
|
8719
|
+
additionalMatrices.push(matrix);
|
|
8720
|
+
parent.style.transform = "none";
|
|
8721
|
+
parent.style.scale = "none";
|
|
8722
|
+
parent.style.rotate = "none";
|
|
8723
|
+
transforms.push({
|
|
8724
|
+
rect: parent,
|
|
8725
|
+
transformOrigin: computedStyle.transformOrigin,
|
|
8726
|
+
boundingClientRect: null,
|
|
8727
|
+
matrices: additionalMatrices
|
|
8728
|
+
});
|
|
8729
|
+
const parentRef = parent;
|
|
8730
|
+
toReset.push(() => {
|
|
8731
|
+
parentRef.style.transform = transform;
|
|
8732
|
+
parentRef.style.scale = scale;
|
|
8733
|
+
parentRef.style.rotate = rotate;
|
|
8734
|
+
});
|
|
8735
|
+
}
|
|
8736
|
+
parent = parent.parentElement;
|
|
8737
|
+
}
|
|
8738
|
+
for (const transform of transforms) {
|
|
8739
|
+
transform.boundingClientRect = transform.rect.getBoundingClientRect();
|
|
8740
|
+
}
|
|
8741
|
+
const dimensions = transforms[0].boundingClientRect;
|
|
8742
|
+
const nativeTransformOrigin = getInternalTransformOrigin(transforms[0]);
|
|
8743
|
+
const totalMatrix = new DOMMatrix;
|
|
8744
|
+
for (const transform of transforms.slice().reverse()) {
|
|
8745
|
+
if (!transform.boundingClientRect) {
|
|
8746
|
+
throw new Error("Bounding client rect not found");
|
|
8747
|
+
}
|
|
8748
|
+
for (const matrix of transform.matrices) {
|
|
8749
|
+
const globalTransformOrigin = getGlobalTransformOrigin(transform);
|
|
8750
|
+
const transformMatrix = new DOMMatrix().translate(globalTransformOrigin.x, globalTransformOrigin.y).multiply(matrix).translate(-globalTransformOrigin.x, -globalTransformOrigin.y);
|
|
8751
|
+
totalMatrix.multiplySelf(transformMatrix);
|
|
8752
|
+
}
|
|
8753
|
+
}
|
|
8754
|
+
if (!elementComputedStyle) {
|
|
8755
|
+
throw new Error("Element computed style not found");
|
|
8756
|
+
}
|
|
8757
|
+
return {
|
|
8758
|
+
dimensions,
|
|
8759
|
+
totalMatrix,
|
|
8760
|
+
reset: () => {
|
|
8761
|
+
for (const reset of toReset) {
|
|
8762
|
+
reset();
|
|
8763
|
+
}
|
|
8764
|
+
},
|
|
8765
|
+
nativeTransformOrigin,
|
|
8766
|
+
opacity,
|
|
8767
|
+
computedStyle: elementComputedStyle
|
|
8768
|
+
};
|
|
8769
|
+
};
|
|
8770
|
+
|
|
8667
8771
|
// src/drawing/border-radius.ts
|
|
8668
8772
|
function parseValue({
|
|
8669
8773
|
value,
|
|
@@ -8800,96 +8904,6 @@ function setBorderRadius({
|
|
|
8800
8904
|
};
|
|
8801
8905
|
}
|
|
8802
8906
|
|
|
8803
|
-
// src/drawing/parse-transform-origin.ts
|
|
8804
|
-
var parseTransformOrigin = (transformOrigin) => {
|
|
8805
|
-
if (transformOrigin.trim() === "") {
|
|
8806
|
-
return null;
|
|
8807
|
-
}
|
|
8808
|
-
const [x, y] = transformOrigin.split(" ");
|
|
8809
|
-
return { x: parseFloat(x), y: parseFloat(y) };
|
|
8810
|
-
};
|
|
8811
|
-
|
|
8812
|
-
// src/drawing/calculate-transforms.ts
|
|
8813
|
-
var getInternalTransformOrigin = (transform) => {
|
|
8814
|
-
const centerX = transform.boundingClientRect.width / 2;
|
|
8815
|
-
const centerY = transform.boundingClientRect.height / 2;
|
|
8816
|
-
const origin = parseTransformOrigin(transform.transformOrigin) ?? {
|
|
8817
|
-
x: centerX,
|
|
8818
|
-
y: centerY
|
|
8819
|
-
};
|
|
8820
|
-
return origin;
|
|
8821
|
-
};
|
|
8822
|
-
var getGlobalTransformOrigin = (transform) => {
|
|
8823
|
-
const { x: originX, y: originY } = getInternalTransformOrigin(transform);
|
|
8824
|
-
return {
|
|
8825
|
-
x: originX + transform.boundingClientRect.left,
|
|
8826
|
-
y: originY + transform.boundingClientRect.top
|
|
8827
|
-
};
|
|
8828
|
-
};
|
|
8829
|
-
var calculateTransforms = (element) => {
|
|
8830
|
-
let parent = element;
|
|
8831
|
-
const transforms = [];
|
|
8832
|
-
const toReset = [];
|
|
8833
|
-
let opacity = 1;
|
|
8834
|
-
let elementComputedStyle = null;
|
|
8835
|
-
while (parent) {
|
|
8836
|
-
const computedStyle = getComputedStyle(parent);
|
|
8837
|
-
const parentOpacity = computedStyle.opacity;
|
|
8838
|
-
if (parentOpacity && parentOpacity !== "") {
|
|
8839
|
-
opacity *= parseFloat(parentOpacity);
|
|
8840
|
-
}
|
|
8841
|
-
if (parent === element) {
|
|
8842
|
-
elementComputedStyle = computedStyle;
|
|
8843
|
-
}
|
|
8844
|
-
if (computedStyle.transform && computedStyle.transform !== "none" || parent === element) {
|
|
8845
|
-
const toParse = computedStyle.transform === "none" || computedStyle.transform === "" ? undefined : computedStyle.transform;
|
|
8846
|
-
const matrix = new DOMMatrix(toParse);
|
|
8847
|
-
const { transform } = parent.style;
|
|
8848
|
-
parent.style.transform = "none";
|
|
8849
|
-
transforms.push({
|
|
8850
|
-
matrix,
|
|
8851
|
-
rect: parent,
|
|
8852
|
-
transformOrigin: computedStyle.transformOrigin,
|
|
8853
|
-
boundingClientRect: null
|
|
8854
|
-
});
|
|
8855
|
-
const parentRef = parent;
|
|
8856
|
-
toReset.push(() => {
|
|
8857
|
-
parentRef.style.transform = transform;
|
|
8858
|
-
});
|
|
8859
|
-
}
|
|
8860
|
-
parent = parent.parentElement;
|
|
8861
|
-
}
|
|
8862
|
-
for (const transform of transforms) {
|
|
8863
|
-
transform.boundingClientRect = transform.rect.getBoundingClientRect();
|
|
8864
|
-
}
|
|
8865
|
-
const dimensions = transforms[0].boundingClientRect;
|
|
8866
|
-
const nativeTransformOrigin = getInternalTransformOrigin(transforms[0]);
|
|
8867
|
-
const totalMatrix = new DOMMatrix;
|
|
8868
|
-
for (const transform of transforms.slice().reverse()) {
|
|
8869
|
-
if (!transform.boundingClientRect) {
|
|
8870
|
-
throw new Error("Bounding client rect not found");
|
|
8871
|
-
}
|
|
8872
|
-
const globalTransformOrigin = getGlobalTransformOrigin(transform);
|
|
8873
|
-
const transformMatrix = new DOMMatrix().translate(globalTransformOrigin.x, globalTransformOrigin.y).multiply(transform.matrix).translate(-globalTransformOrigin.x, -globalTransformOrigin.y);
|
|
8874
|
-
totalMatrix.multiplySelf(transformMatrix);
|
|
8875
|
-
}
|
|
8876
|
-
if (!elementComputedStyle) {
|
|
8877
|
-
throw new Error("Element computed style not found");
|
|
8878
|
-
}
|
|
8879
|
-
return {
|
|
8880
|
-
dimensions,
|
|
8881
|
-
totalMatrix,
|
|
8882
|
-
reset: () => {
|
|
8883
|
-
for (const reset of toReset) {
|
|
8884
|
-
reset();
|
|
8885
|
-
}
|
|
8886
|
-
},
|
|
8887
|
-
nativeTransformOrigin,
|
|
8888
|
-
opacity,
|
|
8889
|
-
computedStyle: elementComputedStyle
|
|
8890
|
-
};
|
|
8891
|
-
};
|
|
8892
|
-
|
|
8893
8907
|
// src/drawing/draw-border.ts
|
|
8894
8908
|
var drawBorder = ({
|
|
8895
8909
|
ctx,
|
|
@@ -9000,21 +9014,15 @@ var setTransform = ({
|
|
|
9000
9014
|
};
|
|
9001
9015
|
};
|
|
9002
9016
|
|
|
9003
|
-
// src/drawing/draw-element
|
|
9004
|
-
var
|
|
9005
|
-
|
|
9017
|
+
// src/drawing/draw-element.ts
|
|
9018
|
+
var drawElement = async ({
|
|
9019
|
+
dimensions,
|
|
9020
|
+
computedStyle,
|
|
9006
9021
|
context,
|
|
9007
|
-
draw
|
|
9022
|
+
draw,
|
|
9023
|
+
opacity,
|
|
9024
|
+
totalMatrix
|
|
9008
9025
|
}) => {
|
|
9009
|
-
const { totalMatrix, reset, dimensions, opacity, computedStyle } = calculateTransforms(element);
|
|
9010
|
-
if (opacity === 0) {
|
|
9011
|
-
reset();
|
|
9012
|
-
return;
|
|
9013
|
-
}
|
|
9014
|
-
if (dimensions.width <= 0 || dimensions.height <= 0) {
|
|
9015
|
-
reset();
|
|
9016
|
-
return;
|
|
9017
|
-
}
|
|
9018
9026
|
const background = computedStyle.backgroundColor;
|
|
9019
9027
|
const borderRadius = parseBorderRadius({
|
|
9020
9028
|
borderRadius: computedStyle.borderRadius,
|
|
@@ -9056,6 +9064,196 @@ var drawElementToCanvas = async ({
|
|
|
9056
9064
|
finishOpacity();
|
|
9057
9065
|
finishBorderRadius();
|
|
9058
9066
|
finishTransform();
|
|
9067
|
+
};
|
|
9068
|
+
|
|
9069
|
+
// src/drawing/transform-in-3d.ts
|
|
9070
|
+
function compileShader(shaderGl, source, type) {
|
|
9071
|
+
const shader = shaderGl.createShader(type);
|
|
9072
|
+
if (!shader) {
|
|
9073
|
+
throw new Error("Could not create shader");
|
|
9074
|
+
}
|
|
9075
|
+
shaderGl.shaderSource(shader, source);
|
|
9076
|
+
shaderGl.compileShader(shader);
|
|
9077
|
+
if (!shaderGl.getShaderParameter(shader, shaderGl.COMPILE_STATUS)) {
|
|
9078
|
+
const log = shaderGl.getShaderInfoLog(shader);
|
|
9079
|
+
shaderGl.deleteShader(shader);
|
|
9080
|
+
throw new Error("Shader compile error: " + log);
|
|
9081
|
+
}
|
|
9082
|
+
return shader;
|
|
9083
|
+
}
|
|
9084
|
+
var transformIn3d = ({
|
|
9085
|
+
canvasWidth,
|
|
9086
|
+
canvasHeight,
|
|
9087
|
+
matrix,
|
|
9088
|
+
sourceCanvas,
|
|
9089
|
+
offsetLeft,
|
|
9090
|
+
offsetTop
|
|
9091
|
+
}) => {
|
|
9092
|
+
const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
|
|
9093
|
+
const gl = canvas.getContext("webgl");
|
|
9094
|
+
if (!gl) {
|
|
9095
|
+
throw new Error("WebGL not supported");
|
|
9096
|
+
}
|
|
9097
|
+
const vsSource = `
|
|
9098
|
+
attribute vec2 aPosition;
|
|
9099
|
+
attribute vec2 aTexCoord;
|
|
9100
|
+
uniform mat4 uTransform;
|
|
9101
|
+
uniform mat4 uProjection;
|
|
9102
|
+
varying vec2 vTexCoord;
|
|
9103
|
+
|
|
9104
|
+
void main() {
|
|
9105
|
+
gl_Position = uProjection * uTransform * vec4(aPosition, 0.0, 1.0);
|
|
9106
|
+
vTexCoord = aTexCoord;
|
|
9107
|
+
}
|
|
9108
|
+
`;
|
|
9109
|
+
const fsSource = `
|
|
9110
|
+
precision mediump float;
|
|
9111
|
+
uniform sampler2D uTexture;
|
|
9112
|
+
varying vec2 vTexCoord;
|
|
9113
|
+
|
|
9114
|
+
void main() {
|
|
9115
|
+
gl_FragColor = texture2D(uTexture, vTexCoord);
|
|
9116
|
+
}
|
|
9117
|
+
`;
|
|
9118
|
+
const vertexShader = compileShader(gl, vsSource, gl.VERTEX_SHADER);
|
|
9119
|
+
const fragmentShader = compileShader(gl, fsSource, gl.FRAGMENT_SHADER);
|
|
9120
|
+
const program = gl.createProgram();
|
|
9121
|
+
gl.attachShader(program, vertexShader);
|
|
9122
|
+
gl.attachShader(program, fragmentShader);
|
|
9123
|
+
gl.linkProgram(program);
|
|
9124
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
9125
|
+
throw new Error("Program link error: " + gl.getProgramInfoLog(program));
|
|
9126
|
+
}
|
|
9127
|
+
gl.useProgram(program);
|
|
9128
|
+
const vertices = new Float32Array([
|
|
9129
|
+
offsetLeft,
|
|
9130
|
+
offsetTop,
|
|
9131
|
+
0,
|
|
9132
|
+
0,
|
|
9133
|
+
canvasWidth + offsetLeft,
|
|
9134
|
+
offsetTop,
|
|
9135
|
+
1,
|
|
9136
|
+
0,
|
|
9137
|
+
offsetLeft,
|
|
9138
|
+
canvasHeight + offsetTop,
|
|
9139
|
+
0,
|
|
9140
|
+
1,
|
|
9141
|
+
offsetLeft,
|
|
9142
|
+
canvasHeight + offsetTop,
|
|
9143
|
+
0,
|
|
9144
|
+
1,
|
|
9145
|
+
canvasWidth + offsetLeft,
|
|
9146
|
+
offsetTop,
|
|
9147
|
+
1,
|
|
9148
|
+
0,
|
|
9149
|
+
canvasWidth + offsetLeft,
|
|
9150
|
+
canvasHeight + offsetTop,
|
|
9151
|
+
1,
|
|
9152
|
+
1
|
|
9153
|
+
]);
|
|
9154
|
+
const vertexBuffer = gl.createBuffer();
|
|
9155
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
9156
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
9157
|
+
const aPosition = gl.getAttribLocation(program, "aPosition");
|
|
9158
|
+
const aTexCoord = gl.getAttribLocation(program, "aTexCoord");
|
|
9159
|
+
gl.enableVertexAttribArray(aPosition);
|
|
9160
|
+
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 4 * 4, 0);
|
|
9161
|
+
gl.enableVertexAttribArray(aTexCoord);
|
|
9162
|
+
gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, 4 * 4, 2 * 4);
|
|
9163
|
+
const texture = gl.createTexture();
|
|
9164
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
9165
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
9166
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
9167
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
9168
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
9169
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, sourceCanvas);
|
|
9170
|
+
const transformMatrix = matrix.toFloat32Array();
|
|
9171
|
+
const zScale = 1e9;
|
|
9172
|
+
const projectionMatrix = new Float32Array([
|
|
9173
|
+
2 / canvasWidth,
|
|
9174
|
+
0,
|
|
9175
|
+
0,
|
|
9176
|
+
0,
|
|
9177
|
+
0,
|
|
9178
|
+
-2 / canvasHeight,
|
|
9179
|
+
0,
|
|
9180
|
+
0,
|
|
9181
|
+
0,
|
|
9182
|
+
0,
|
|
9183
|
+
-2 / zScale,
|
|
9184
|
+
0,
|
|
9185
|
+
-1,
|
|
9186
|
+
1,
|
|
9187
|
+
0,
|
|
9188
|
+
1
|
|
9189
|
+
]);
|
|
9190
|
+
const uTransform = gl.getUniformLocation(program, "uTransform");
|
|
9191
|
+
const uProjection = gl.getUniformLocation(program, "uProjection");
|
|
9192
|
+
const uTexture = gl.getUniformLocation(program, "uTexture");
|
|
9193
|
+
gl.uniformMatrix4fv(uTransform, false, transformMatrix);
|
|
9194
|
+
gl.uniformMatrix4fv(uProjection, false, projectionMatrix);
|
|
9195
|
+
gl.uniform1i(uTexture, 0);
|
|
9196
|
+
gl.clearColor(0, 0, 0, 0);
|
|
9197
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
9198
|
+
gl.enable(gl.BLEND);
|
|
9199
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
9200
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
9201
|
+
return canvas;
|
|
9202
|
+
};
|
|
9203
|
+
|
|
9204
|
+
// src/drawing/draw-element-to-canvas.ts
|
|
9205
|
+
var drawElementToCanvas = async ({
|
|
9206
|
+
element,
|
|
9207
|
+
context,
|
|
9208
|
+
draw
|
|
9209
|
+
}) => {
|
|
9210
|
+
const { totalMatrix, reset, dimensions, opacity, computedStyle } = calculateTransforms(element);
|
|
9211
|
+
if (opacity === 0) {
|
|
9212
|
+
reset();
|
|
9213
|
+
return;
|
|
9214
|
+
}
|
|
9215
|
+
if (dimensions.width <= 0 || dimensions.height <= 0) {
|
|
9216
|
+
reset();
|
|
9217
|
+
return;
|
|
9218
|
+
}
|
|
9219
|
+
if (!totalMatrix.is2D) {
|
|
9220
|
+
const offsetLeft = Math.min(dimensions.left, 0);
|
|
9221
|
+
const offsetTop = Math.min(dimensions.top, 0);
|
|
9222
|
+
const tempCanvasWidth = Math.max(dimensions.width, dimensions.right);
|
|
9223
|
+
const tempCanvasHeight = Math.max(dimensions.height, dimensions.bottom);
|
|
9224
|
+
const tempCanvas = new OffscreenCanvas(tempCanvasWidth, tempCanvasHeight);
|
|
9225
|
+
const context2 = tempCanvas.getContext("2d");
|
|
9226
|
+
if (!context2) {
|
|
9227
|
+
throw new Error("Could not get context");
|
|
9228
|
+
}
|
|
9229
|
+
const adjustedDimensions = new DOMRect(dimensions.left - offsetLeft, dimensions.top - offsetTop, dimensions.width, dimensions.height);
|
|
9230
|
+
await drawElement({
|
|
9231
|
+
dimensions: adjustedDimensions,
|
|
9232
|
+
computedStyle,
|
|
9233
|
+
context: context2,
|
|
9234
|
+
draw,
|
|
9235
|
+
opacity,
|
|
9236
|
+
totalMatrix: new DOMMatrix
|
|
9237
|
+
});
|
|
9238
|
+
const transformed = transformIn3d({
|
|
9239
|
+
canvasWidth: tempCanvasWidth,
|
|
9240
|
+
canvasHeight: tempCanvasHeight,
|
|
9241
|
+
matrix: totalMatrix,
|
|
9242
|
+
sourceCanvas: tempCanvas,
|
|
9243
|
+
offsetLeft,
|
|
9244
|
+
offsetTop
|
|
9245
|
+
});
|
|
9246
|
+
context.drawImage(transformed, 0, 0);
|
|
9247
|
+
} else {
|
|
9248
|
+
await drawElement({
|
|
9249
|
+
dimensions,
|
|
9250
|
+
computedStyle,
|
|
9251
|
+
context,
|
|
9252
|
+
draw,
|
|
9253
|
+
opacity,
|
|
9254
|
+
totalMatrix
|
|
9255
|
+
});
|
|
9256
|
+
}
|
|
9059
9257
|
reset();
|
|
9060
9258
|
};
|
|
9061
9259
|
|