@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.
Files changed (39) hide show
  1. package/dist/border-radius.d.ts +31 -0
  2. package/dist/border-radius.js +152 -0
  3. package/dist/calculate-transforms.d.ts +11 -0
  4. package/dist/calculate-transforms.js +91 -0
  5. package/dist/composable.d.ts +4 -0
  6. package/dist/composable.js +1 -0
  7. package/dist/compose-canvas.d.ts +1 -0
  8. package/dist/compose-canvas.js +36 -0
  9. package/dist/compose-svg.d.ts +1 -0
  10. package/dist/compose-svg.js +34 -0
  11. package/dist/drawing/calculate-transforms.js +27 -8
  12. package/dist/drawing/compose-canvas.d.ts +1 -0
  13. package/dist/drawing/compose-canvas.js +36 -0
  14. package/dist/drawing/compose-svg.d.ts +1 -0
  15. package/dist/drawing/compose-svg.js +34 -0
  16. package/dist/drawing/compose.d.ts +5 -0
  17. package/dist/drawing/compose.js +6 -0
  18. package/dist/drawing/draw-element-to-canvas.js +40 -47
  19. package/dist/drawing/draw-element.d.ts +8 -0
  20. package/dist/drawing/draw-element.js +50 -0
  21. package/dist/drawing/get-computed-style-cache.d.ts +0 -0
  22. package/dist/drawing/get-computed-style-cache.js +1 -0
  23. package/dist/drawing/text/draw-text.d.ts +1 -0
  24. package/dist/drawing/text/draw-text.js +57 -0
  25. package/dist/drawing/text/handle-text-node.js +0 -12
  26. package/dist/drawing/transform-in-3d.d.ts +8 -0
  27. package/dist/drawing/transform-in-3d.js +125 -0
  28. package/dist/esm/index.mjs +301 -103
  29. package/dist/find-canvas-elements.d.ts +1 -0
  30. package/dist/find-canvas-elements.js +13 -0
  31. package/dist/find-capturable-elements.d.ts +2 -0
  32. package/dist/find-capturable-elements.js +26 -0
  33. package/dist/opacity.d.ts +4 -0
  34. package/dist/opacity.js +7 -0
  35. package/dist/parse-transform-origin.d.ts +4 -0
  36. package/dist/parse-transform-origin.js +7 -0
  37. package/dist/transform.d.ts +4 -0
  38. package/dist/transform.js +6 -0
  39. 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
+ };
@@ -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-to-canvas.ts
9004
- var drawElementToCanvas = async ({
9005
- element,
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