@remotion/web-renderer 4.0.395 → 4.0.396

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 (71) 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 +2 -0
  4. package/dist/calculate-transforms.js +17 -0
  5. package/dist/composable.d.ts +2 -8
  6. package/dist/compose-canvas.js +28 -4
  7. package/dist/compose.d.ts +4 -3
  8. package/dist/compose.js +39 -12
  9. package/dist/drawing/border-radius.d.ts +3 -5
  10. package/dist/drawing/border-radius.js +12 -11
  11. package/dist/drawing/calculate-transforms.d.ts +6 -2
  12. package/dist/drawing/calculate-transforms.js +19 -22
  13. package/dist/drawing/canvas-offset-from-rect.d.ts +8 -0
  14. package/dist/drawing/canvas-offset-from-rect.js +12 -0
  15. package/dist/drawing/clamp-rect-to-parent-bounds.d.ts +4 -0
  16. package/dist/drawing/clamp-rect-to-parent-bounds.js +7 -0
  17. package/dist/drawing/compose-canvas.d.ts +1 -0
  18. package/dist/drawing/compose-canvas.js +36 -0
  19. package/dist/drawing/compose-svg.d.ts +1 -0
  20. package/dist/drawing/compose-svg.js +34 -0
  21. package/dist/drawing/compose.d.ts +5 -0
  22. package/dist/drawing/compose.js +6 -0
  23. package/dist/drawing/draw-border.d.ts +2 -5
  24. package/dist/drawing/draw-border.js +37 -37
  25. package/dist/drawing/draw-element-to-canvas.d.ts +2 -1
  26. package/dist/drawing/draw-element-to-canvas.js +8 -36
  27. package/dist/drawing/draw-element.d.ts +5 -3
  28. package/dist/drawing/draw-element.js +29 -14
  29. package/dist/drawing/draw-outline.d.ts +9 -0
  30. package/dist/drawing/draw-outline.js +116 -0
  31. package/dist/drawing/get-bounding-box-including-shadow.d.ts +1 -0
  32. package/dist/drawing/get-bounding-box-including-shadow.js +6 -0
  33. package/dist/drawing/get-computed-style-cache.d.ts +0 -0
  34. package/dist/drawing/get-computed-style-cache.js +1 -0
  35. package/dist/drawing/get-pretransform-rect.d.ts +1 -0
  36. package/dist/drawing/get-pretransform-rect.js +31 -0
  37. package/dist/drawing/handle-3d-transform.d.ts +10 -0
  38. package/dist/drawing/handle-3d-transform.js +39 -0
  39. package/dist/drawing/has-transform.d.ts +4 -0
  40. package/dist/drawing/has-transform.js +14 -0
  41. package/dist/drawing/overflow.d.ts +7 -0
  42. package/dist/drawing/overflow.js +12 -0
  43. package/dist/drawing/process-node.d.ts +17 -0
  44. package/dist/drawing/process-node.js +41 -0
  45. package/dist/drawing/text/handle-text-node.d.ts +6 -5
  46. package/dist/drawing/text/handle-text-node.js +5 -5
  47. package/dist/drawing/transform-in-3d.d.ts +7 -7
  48. package/dist/drawing/transform-in-3d.js +20 -12
  49. package/dist/drawing/transform-rect-with-matrix.d.ts +4 -0
  50. package/dist/drawing/transform-rect-with-matrix.js +19 -0
  51. package/dist/esm/index.mjs +501 -218
  52. package/dist/find-canvas-elements.d.ts +1 -0
  53. package/dist/find-canvas-elements.js +13 -0
  54. package/dist/find-capturable-elements.d.ts +1 -1
  55. package/dist/find-capturable-elements.js +20 -22
  56. package/dist/get-biggest-bounding-client-rect.js +14 -4
  57. package/dist/internal-state.d.ts +9 -0
  58. package/dist/internal-state.js +12 -0
  59. package/dist/opacity.d.ts +4 -0
  60. package/dist/opacity.js +7 -0
  61. package/dist/render-media-on-web.d.ts +2 -0
  62. package/dist/render-media-on-web.js +5 -0
  63. package/dist/render-still-on-web.d.ts +5 -1
  64. package/dist/render-still-on-web.js +4 -1
  65. package/dist/take-screenshot.d.ts +5 -2
  66. package/dist/take-screenshot.js +16 -4
  67. package/dist/transform.d.ts +4 -0
  68. package/dist/transform.js +6 -0
  69. package/package.json +6 -6
  70. package/dist/drawing/text/get-base-height.d.ts +0 -1
  71. package/dist/drawing/text/get-base-height.js +0 -13
@@ -0,0 +1,34 @@
1
+ export const turnSvgIntoDrawable = (svg) => {
2
+ const originalTransform = svg.style.transform;
3
+ const originalTransformOrigin = svg.style.transformOrigin;
4
+ const originalMarginLeft = svg.style.marginLeft;
5
+ const originalMarginRight = svg.style.marginRight;
6
+ const originalMarginTop = svg.style.marginTop;
7
+ const originalMarginBottom = svg.style.marginBottom;
8
+ svg.style.transform = 'none';
9
+ svg.style.transformOrigin = '';
10
+ // Margins were already included in the positioning calculation,
11
+ // so we need to remove them to avoid double counting.
12
+ svg.style.marginLeft = '0';
13
+ svg.style.marginRight = '0';
14
+ svg.style.marginTop = '0';
15
+ svg.style.marginBottom = '0';
16
+ const svgData = new XMLSerializer().serializeToString(svg);
17
+ svg.style.marginLeft = originalMarginLeft;
18
+ svg.style.marginRight = originalMarginRight;
19
+ svg.style.marginTop = originalMarginTop;
20
+ svg.style.marginBottom = originalMarginBottom;
21
+ svg.style.transform = originalTransform;
22
+ svg.style.transformOrigin = originalTransformOrigin;
23
+ return new Promise((resolve, reject) => {
24
+ const image = new Image();
25
+ const url = `data:image/svg+xml;base64,${btoa(svgData)}`;
26
+ image.onload = function () {
27
+ resolve(image);
28
+ };
29
+ image.onerror = () => {
30
+ reject(new Error('Failed to convert SVG to image'));
31
+ };
32
+ image.src = url;
33
+ });
34
+ };
@@ -0,0 +1,5 @@
1
+ import type { Composable } from '../composable';
2
+ export declare const compose: ({ composables, context, }: {
3
+ composables: Composable[];
4
+ context: OffscreenCanvasRenderingContext2D;
5
+ }) => Promise<void>;
@@ -0,0 +1,6 @@
1
+ import { drawElementToCanvas } from './draw-element-to-canvas';
2
+ export const compose = async ({ composables, context, }) => {
3
+ for (const composable of composables) {
4
+ await drawElementToCanvas(composable.element, context);
5
+ }
6
+ };
@@ -1,10 +1,7 @@
1
1
  import type { BorderRadiusCorners } from './border-radius';
2
- export declare const drawBorder: ({ ctx, x, y, width, height, borderRadius, computedStyle, }: {
2
+ export declare const drawBorder: ({ ctx, rect, borderRadius, computedStyle, }: {
3
3
  ctx: OffscreenCanvasRenderingContext2D;
4
- x: number;
5
- y: number;
6
- width: number;
7
- height: number;
4
+ rect: DOMRect;
8
5
  borderRadius: BorderRadiusCorners;
9
6
  computedStyle: CSSStyleDeclaration;
10
7
  }) => void;
@@ -211,7 +211,7 @@ const drawUniformBorder = ({ ctx, x, y, width, height, borderRadius, borderWidth
211
211
  ctx.closePath();
212
212
  ctx.stroke();
213
213
  };
214
- export const drawBorder = ({ ctx, x, y, width, height, borderRadius, computedStyle, }) => {
214
+ export const drawBorder = ({ ctx, rect, borderRadius, computedStyle, }) => {
215
215
  const borders = getBorderSideProperties(computedStyle);
216
216
  // Check if we have any visible border
217
217
  const hasBorder = borders.top.width > 0 ||
@@ -240,10 +240,10 @@ export const drawBorder = ({ ctx, x, y, width, height, borderRadius, computedSty
240
240
  // Draw as a single continuous border for continuous dashing
241
241
  drawUniformBorder({
242
242
  ctx,
243
- x,
244
- y,
245
- width,
246
- height,
243
+ x: rect.left,
244
+ y: rect.top,
245
+ width: rect.width,
246
+ height: rect.height,
247
247
  borderRadius,
248
248
  borderWidth: borders.top.width,
249
249
  borderColor: borders.top.color,
@@ -255,10 +255,10 @@ export const drawBorder = ({ ctx, x, y, width, height, borderRadius, computedSty
255
255
  drawCorner({
256
256
  ctx,
257
257
  corner: 'topLeft',
258
- x,
259
- y,
260
- width,
261
- height,
258
+ x: rect.left,
259
+ y: rect.top,
260
+ width: rect.width,
261
+ height: rect.height,
262
262
  borderRadius,
263
263
  topBorder: borders.top,
264
264
  rightBorder: borders.right,
@@ -268,10 +268,10 @@ export const drawBorder = ({ ctx, x, y, width, height, borderRadius, computedSty
268
268
  drawCorner({
269
269
  ctx,
270
270
  corner: 'topRight',
271
- x,
272
- y,
273
- width,
274
- height,
271
+ x: rect.left,
272
+ y: rect.top,
273
+ width: rect.width,
274
+ height: rect.height,
275
275
  borderRadius,
276
276
  topBorder: borders.top,
277
277
  rightBorder: borders.right,
@@ -281,10 +281,10 @@ export const drawBorder = ({ ctx, x, y, width, height, borderRadius, computedSty
281
281
  drawCorner({
282
282
  ctx,
283
283
  corner: 'bottomRight',
284
- x,
285
- y,
286
- width,
287
- height,
284
+ x: rect.left,
285
+ y: rect.top,
286
+ width: rect.width,
287
+ height: rect.height,
288
288
  borderRadius,
289
289
  topBorder: borders.top,
290
290
  rightBorder: borders.right,
@@ -294,10 +294,10 @@ export const drawBorder = ({ ctx, x, y, width, height, borderRadius, computedSty
294
294
  drawCorner({
295
295
  ctx,
296
296
  corner: 'bottomLeft',
297
- x,
298
- y,
299
- width,
300
- height,
297
+ x: rect.left,
298
+ y: rect.top,
299
+ width: rect.width,
300
+ height: rect.height,
301
301
  borderRadius,
302
302
  topBorder: borders.top,
303
303
  rightBorder: borders.right,
@@ -308,40 +308,40 @@ export const drawBorder = ({ ctx, x, y, width, height, borderRadius, computedSty
308
308
  drawBorderSide({
309
309
  ctx,
310
310
  side: 'top',
311
- x,
312
- y,
313
- width,
314
- height,
311
+ x: rect.left,
312
+ y: rect.top,
313
+ width: rect.width,
314
+ height: rect.height,
315
315
  borderRadius,
316
316
  borderProperties: borders.top,
317
317
  });
318
318
  drawBorderSide({
319
319
  ctx,
320
320
  side: 'right',
321
- x,
322
- y,
323
- width,
324
- height,
321
+ x: rect.left,
322
+ y: rect.top,
323
+ width: rect.width,
324
+ height: rect.height,
325
325
  borderRadius,
326
326
  borderProperties: borders.right,
327
327
  });
328
328
  drawBorderSide({
329
329
  ctx,
330
330
  side: 'bottom',
331
- x,
332
- y,
333
- width,
334
- height,
331
+ x: rect.left,
332
+ y: rect.top,
333
+ width: rect.width,
334
+ height: rect.height,
335
335
  borderRadius,
336
336
  borderProperties: borders.bottom,
337
337
  });
338
338
  drawBorderSide({
339
339
  ctx,
340
340
  side: 'left',
341
- x,
342
- y,
343
- width,
344
- height,
341
+ x: rect.left,
342
+ y: rect.top,
343
+ width: rect.width,
344
+ height: rect.height,
345
345
  borderRadius,
346
346
  borderProperties: borders.left,
347
347
  });
@@ -1,11 +1,12 @@
1
1
  import type { LogLevel } from 'remotion';
2
2
  import type { DrawFn } from './drawn-fn';
3
3
  export type DrawElementToCanvasReturnValue = 'continue' | 'skip-children';
4
- export declare const drawElementToCanvas: ({ element, context, draw, offsetLeft, offsetTop, logLevel, }: {
4
+ export declare const drawElementToCanvas: ({ element, context, draw, offsetLeft, offsetTop, logLevel, parentRect, }: {
5
5
  element: HTMLElement | SVGElement;
6
6
  context: OffscreenCanvasRenderingContext2D;
7
7
  draw: DrawFn;
8
8
  offsetLeft: number;
9
9
  offsetTop: number;
10
10
  logLevel: LogLevel;
11
+ parentRect: DOMRect;
11
12
  }) => Promise<DrawElementToCanvasReturnValue>;
@@ -1,11 +1,9 @@
1
- import { Internals } from 'remotion';
2
- import { compose } from '../compose';
3
- import { getBiggestBoundingClientRect } from '../get-biggest-bounding-client-rect';
4
1
  import { calculateTransforms } from './calculate-transforms';
5
2
  import { drawElement } from './draw-element';
6
- import { transformIn3d } from './transform-in-3d';
7
- export const drawElementToCanvas = async ({ element, context, draw, offsetLeft, offsetTop, logLevel, }) => {
8
- const { totalMatrix, reset, dimensions, opacity, computedStyle } = calculateTransforms(element);
3
+ import { handle3dTransform } from './handle-3d-transform';
4
+ export const drawElementToCanvas = async ({ element, context, draw, offsetLeft, offsetTop, logLevel, parentRect, }) => {
5
+ const transforms = calculateTransforms({ element, offsetLeft, offsetTop });
6
+ const { totalMatrix, reset, dimensions, opacity, computedStyle } = transforms;
9
7
  if (opacity === 0) {
10
8
  reset();
11
9
  return 'continue';
@@ -15,40 +13,14 @@ export const drawElementToCanvas = async ({ element, context, draw, offsetLeft,
15
13
  return 'continue';
16
14
  }
17
15
  if (!totalMatrix.is2D) {
18
- const biggestBoundingClientRect = getBiggestBoundingClientRect(element);
19
- const canvasOffsetLeft = Math.min(biggestBoundingClientRect.left, 0);
20
- const canvasOffsetTop = Math.min(biggestBoundingClientRect.top, 0);
21
- const tempCanvasWidth = Math.max(biggestBoundingClientRect.width, biggestBoundingClientRect.right);
22
- const tempCanvasHeight = Math.max(biggestBoundingClientRect.height, biggestBoundingClientRect.bottom);
23
- const start = Date.now();
24
- const tempCanvas = new OffscreenCanvas(tempCanvasWidth, tempCanvasHeight);
25
- const context2 = tempCanvas.getContext('2d');
26
- if (!context2) {
27
- throw new Error('Could not get context');
28
- }
29
- await compose({
16
+ await handle3dTransform({
30
17
  element,
31
- context: context2,
32
- offsetLeft: canvasOffsetLeft,
33
- offsetTop: canvasOffsetTop,
18
+ totalMatrix,
19
+ parentRect,
20
+ context,
34
21
  logLevel,
35
22
  });
36
- const afterCompose = Date.now();
37
- const transformed = transformIn3d({
38
- canvasWidth: tempCanvasWidth,
39
- canvasHeight: tempCanvasHeight,
40
- matrix: totalMatrix,
41
- sourceCanvas: tempCanvas,
42
- offsetLeft: canvasOffsetLeft,
43
- offsetTop: canvasOffsetTop,
44
- });
45
- context.drawImage(transformed, 0, 0);
46
- const afterDraw = Date.now();
47
23
  reset();
48
- Internals.Log.trace({
49
- logLevel,
50
- tag: '@remotion/web-renderer',
51
- }, `Transforming element in 3D - canvas size: ${tempCanvasWidth}x${tempCanvasHeight} - compose: ${afterCompose - start}ms - draw: ${afterDraw - afterCompose}ms`);
52
24
  return 'skip-children';
53
25
  }
54
26
  await drawElement({
@@ -1,9 +1,11 @@
1
1
  import type { DrawFn } from './drawn-fn';
2
- export declare const drawElement: ({ dimensions, computedStyle, context, draw, opacity, totalMatrix, }: {
3
- dimensions: DOMRect;
2
+ export declare const drawElement: ({ rect, computedStyle, context, draw, opacity, totalMatrix, }: {
3
+ rect: DOMRect;
4
4
  computedStyle: CSSStyleDeclaration;
5
5
  context: OffscreenCanvasRenderingContext2D;
6
6
  opacity: number;
7
7
  totalMatrix: DOMMatrix;
8
8
  draw: DrawFn;
9
- }) => Promise<void>;
9
+ }) => Promise<{
10
+ cleanupAfterChildren: () => void;
11
+ }>;
@@ -1,13 +1,15 @@
1
1
  import { parseBorderRadius, setBorderRadius } from './border-radius';
2
2
  import { drawBorder } from './draw-border';
3
+ import { drawOutline } from './draw-outline';
3
4
  import { setOpacity } from './opacity';
5
+ import { setOverflowHidden } from './overflow';
4
6
  import { setTransform } from './transform';
5
- export const drawElement = async ({ dimensions, computedStyle, context, draw, opacity, totalMatrix, }) => {
7
+ export const drawElement = async ({ rect, computedStyle, context, draw, opacity, totalMatrix, }) => {
6
8
  const background = computedStyle.backgroundColor;
7
9
  const borderRadius = parseBorderRadius({
8
10
  borderRadius: computedStyle.borderRadius,
9
- width: dimensions.width,
10
- height: dimensions.height,
11
+ width: rect.width,
12
+ height: rect.height,
11
13
  });
12
14
  const finishTransform = setTransform({
13
15
  ctx: context,
@@ -15,11 +17,9 @@ export const drawElement = async ({ dimensions, computedStyle, context, draw, op
15
17
  });
16
18
  const finishBorderRadius = setBorderRadius({
17
19
  ctx: context,
18
- x: dimensions.left,
19
- y: dimensions.top,
20
- width: dimensions.width,
21
- height: dimensions.height,
20
+ rect,
22
21
  borderRadius,
22
+ forceClipEvenWhenZero: false,
23
23
  });
24
24
  const finishOpacity = setOpacity({
25
25
  ctx: context,
@@ -31,20 +31,35 @@ export const drawElement = async ({ dimensions, computedStyle, context, draw, op
31
31
  (background.endsWith(', 0)') || background.endsWith(',0')))) {
32
32
  const originalFillStyle = context.fillStyle;
33
33
  context.fillStyle = background;
34
- context.fillRect(dimensions.left, dimensions.top, dimensions.width, dimensions.height);
34
+ context.fillRect(rect.left, rect.top, rect.width, rect.height);
35
35
  context.fillStyle = originalFillStyle;
36
36
  }
37
- await draw({ dimensions, computedStyle, contextToDraw: context });
37
+ await draw({ dimensions: rect, computedStyle, contextToDraw: context });
38
38
  drawBorder({
39
39
  ctx: context,
40
- x: dimensions.left,
41
- y: dimensions.top,
42
- width: dimensions.width,
43
- height: dimensions.height,
40
+ rect,
44
41
  borderRadius,
45
42
  computedStyle,
46
43
  });
47
- finishOpacity();
48
44
  finishBorderRadius();
45
+ // Drawing outline ignores overflow: hidden, finishing it and starting a new one for the outline
46
+ drawOutline({
47
+ ctx: context,
48
+ rect,
49
+ borderRadius,
50
+ computedStyle,
51
+ });
52
+ const finishOverflowHidden = setOverflowHidden({
53
+ ctx: context,
54
+ rect,
55
+ borderRadius,
56
+ overflowHidden: computedStyle.overflow === 'hidden',
57
+ });
49
58
  finishTransform();
59
+ return {
60
+ cleanupAfterChildren: () => {
61
+ finishOpacity();
62
+ finishOverflowHidden();
63
+ },
64
+ };
50
65
  };
@@ -0,0 +1,9 @@
1
+ import type { BorderRadiusCorners } from './border-radius';
2
+ export declare const parseOutlineWidth: (value: string) => number;
3
+ export declare const parseOutlineOffset: (value: string) => number;
4
+ export declare const drawOutline: ({ ctx, rect, borderRadius, computedStyle, }: {
5
+ ctx: OffscreenCanvasRenderingContext2D;
6
+ rect: DOMRect;
7
+ borderRadius: BorderRadiusCorners;
8
+ computedStyle: CSSStyleDeclaration;
9
+ }) => void;
@@ -0,0 +1,116 @@
1
+ export const parseOutlineWidth = (value) => {
2
+ return parseFloat(value) || 0;
3
+ };
4
+ export const parseOutlineOffset = (value) => {
5
+ return parseFloat(value) || 0;
6
+ };
7
+ const getLineDashPattern = (style, width) => {
8
+ if (style === 'dashed') {
9
+ return [width * 2, width];
10
+ }
11
+ if (style === 'dotted') {
12
+ return [width, width];
13
+ }
14
+ return [];
15
+ };
16
+ export const drawOutline = ({ ctx, rect, borderRadius, computedStyle, }) => {
17
+ const outlineWidth = parseOutlineWidth(computedStyle.outlineWidth);
18
+ const { outlineStyle } = computedStyle;
19
+ const outlineColor = computedStyle.outlineColor || 'black';
20
+ const outlineOffset = parseOutlineOffset(computedStyle.outlineOffset);
21
+ // Check if we have a visible outline
22
+ if (outlineWidth <= 0 ||
23
+ outlineStyle === 'none' ||
24
+ outlineStyle === 'hidden') {
25
+ return;
26
+ }
27
+ // Save original canvas state
28
+ const originalStrokeStyle = ctx.strokeStyle;
29
+ const originalLineWidth = ctx.lineWidth;
30
+ const originalLineDash = ctx.getLineDash();
31
+ ctx.beginPath();
32
+ ctx.strokeStyle = outlineColor;
33
+ ctx.lineWidth = outlineWidth;
34
+ ctx.setLineDash(getLineDashPattern(outlineStyle, outlineWidth));
35
+ // Calculate outline position
36
+ // Outline is drawn outside the border edge, offset by outlineOffset
37
+ const halfWidth = outlineWidth / 2;
38
+ const offset = outlineOffset + halfWidth;
39
+ const outlineX = rect.left - offset;
40
+ const outlineY = rect.top - offset;
41
+ const outlineW = rect.width + offset * 2;
42
+ const outlineH = rect.height + offset * 2;
43
+ // Adjust border radius for the outline offset
44
+ // When outline-offset is positive, we need to expand the radius
45
+ // When outline-offset is negative, we need to shrink the radius
46
+ const adjustedBorderRadius = {
47
+ topLeft: {
48
+ horizontal: borderRadius.topLeft.horizontal === 0
49
+ ? 0
50
+ : Math.max(0, borderRadius.topLeft.horizontal + offset),
51
+ vertical: borderRadius.topLeft.vertical === 0
52
+ ? 0
53
+ : Math.max(0, borderRadius.topLeft.vertical + offset),
54
+ },
55
+ topRight: {
56
+ horizontal: borderRadius.topRight.horizontal === 0
57
+ ? 0
58
+ : Math.max(0, borderRadius.topRight.horizontal + offset),
59
+ vertical: borderRadius.topRight.vertical === 0
60
+ ? 0
61
+ : Math.max(0, borderRadius.topRight.vertical + offset),
62
+ },
63
+ bottomRight: {
64
+ horizontal: borderRadius.bottomRight.horizontal === 0
65
+ ? 0
66
+ : Math.max(0, borderRadius.bottomRight.horizontal + offset),
67
+ vertical: borderRadius.bottomRight.vertical === 0
68
+ ? 0
69
+ : Math.max(0, borderRadius.bottomRight.vertical + offset),
70
+ },
71
+ bottomLeft: {
72
+ horizontal: borderRadius.bottomLeft.horizontal === 0
73
+ ? 0
74
+ : Math.max(0, borderRadius.bottomLeft.horizontal + offset),
75
+ vertical: borderRadius.bottomLeft.vertical === 0
76
+ ? 0
77
+ : Math.max(0, borderRadius.bottomLeft.vertical + offset),
78
+ },
79
+ };
80
+ // Draw continuous path with border radius
81
+ ctx.moveTo(outlineX + adjustedBorderRadius.topLeft.horizontal, outlineY);
82
+ // Top edge
83
+ ctx.lineTo(outlineX + outlineW - adjustedBorderRadius.topRight.horizontal, outlineY);
84
+ // Top-right corner
85
+ if (adjustedBorderRadius.topRight.horizontal > 0 ||
86
+ adjustedBorderRadius.topRight.vertical > 0) {
87
+ ctx.ellipse(outlineX + outlineW - adjustedBorderRadius.topRight.horizontal, outlineY + adjustedBorderRadius.topRight.vertical, adjustedBorderRadius.topRight.horizontal, adjustedBorderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
88
+ }
89
+ // Right edge
90
+ ctx.lineTo(outlineX + outlineW, outlineY + outlineH - adjustedBorderRadius.bottomRight.vertical);
91
+ // Bottom-right corner
92
+ if (adjustedBorderRadius.bottomRight.horizontal > 0 ||
93
+ adjustedBorderRadius.bottomRight.vertical > 0) {
94
+ ctx.ellipse(outlineX + outlineW - adjustedBorderRadius.bottomRight.horizontal, outlineY + outlineH - adjustedBorderRadius.bottomRight.vertical, adjustedBorderRadius.bottomRight.horizontal, adjustedBorderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
95
+ }
96
+ // Bottom edge
97
+ ctx.lineTo(outlineX + adjustedBorderRadius.bottomLeft.horizontal, outlineY + outlineH);
98
+ // Bottom-left corner
99
+ if (adjustedBorderRadius.bottomLeft.horizontal > 0 ||
100
+ adjustedBorderRadius.bottomLeft.vertical > 0) {
101
+ ctx.ellipse(outlineX + adjustedBorderRadius.bottomLeft.horizontal, outlineY + outlineH - adjustedBorderRadius.bottomLeft.vertical, adjustedBorderRadius.bottomLeft.horizontal, adjustedBorderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
102
+ }
103
+ // Left edge
104
+ ctx.lineTo(outlineX, outlineY + adjustedBorderRadius.topLeft.vertical);
105
+ // Top-left corner
106
+ if (adjustedBorderRadius.topLeft.horizontal > 0 ||
107
+ adjustedBorderRadius.topLeft.vertical > 0) {
108
+ ctx.ellipse(outlineX + adjustedBorderRadius.topLeft.horizontal, outlineY + adjustedBorderRadius.topLeft.vertical, adjustedBorderRadius.topLeft.horizontal, adjustedBorderRadius.topLeft.vertical, 0, Math.PI, (Math.PI * 3) / 2);
109
+ }
110
+ ctx.closePath();
111
+ ctx.stroke();
112
+ // Restore original canvas state
113
+ ctx.strokeStyle = originalStrokeStyle;
114
+ ctx.lineWidth = originalLineWidth;
115
+ ctx.setLineDash(originalLineDash);
116
+ };
@@ -0,0 +1 @@
1
+ export declare const getBoundingBoxIncludingOutline: (element: Element) => DOMRect;
@@ -0,0 +1,6 @@
1
+ export const getBoundingBoxIncludingOutline = (element) => {
2
+ var _a, _b, _c, _d, _e;
3
+ const rect = element.getBoundingClientRect();
4
+ const shadow = (_a = element.shadowRoot) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
5
+ return new DOMRect(Math.min(rect.left, (_b = shadow === null || shadow === void 0 ? void 0 : shadow.left) !== null && _b !== void 0 ? _b : 0), Math.min(rect.top, (_c = shadow === null || shadow === void 0 ? void 0 : shadow.top) !== null && _c !== void 0 ? _c : 0), Math.max(rect.right, (_d = shadow === null || shadow === void 0 ? void 0 : shadow.right) !== null && _d !== void 0 ? _d : 0), Math.max(rect.bottom, (_e = shadow === null || shadow === void 0 ? void 0 : shadow.bottom) !== null && _e !== void 0 ? _e : 0));
6
+ };
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ export declare function getPreTransformRect(targetRect: DOMRect, matrix: DOMMatrix): DOMRect;
@@ -0,0 +1,31 @@
1
+ export function getPreTransformRect(targetRect, matrix) {
2
+ // 1. Determine the effective 2D transformation by transforming basis vectors
3
+ const origin = new DOMPoint(0, 0).matrixTransform(matrix);
4
+ const unitX = new DOMPoint(1, 0).matrixTransform(matrix);
5
+ const unitY = new DOMPoint(0, 1).matrixTransform(matrix);
6
+ // 2. Compute the 2D basis vectors after transformation
7
+ const basisX = { x: unitX.x - origin.x, y: unitX.y - origin.y };
8
+ const basisY = { x: unitY.x - origin.x, y: unitY.y - origin.y };
9
+ // 3. Build the effective 2D matrix and invert it
10
+ const effective2D = new DOMMatrix([
11
+ basisX.x,
12
+ basisX.y, // a, b (first column)
13
+ basisY.x,
14
+ basisY.y, // c, d (second column)
15
+ origin.x,
16
+ origin.y, // e, f (translation)
17
+ ]);
18
+ const inverse2D = effective2D.inverse();
19
+ // 4. Transform target rect corners using the 2D inverse
20
+ const corners = [
21
+ new DOMPoint(targetRect.x, targetRect.y),
22
+ new DOMPoint(targetRect.x + targetRect.width, targetRect.y),
23
+ new DOMPoint(targetRect.x + targetRect.width, targetRect.y + targetRect.height),
24
+ new DOMPoint(targetRect.x, targetRect.y + targetRect.height),
25
+ ];
26
+ const transformedCorners = corners.map((c) => c.matrixTransform(inverse2D));
27
+ // 5. Compute bounding box
28
+ const xs = transformedCorners.map((p) => p.x);
29
+ const ys = transformedCorners.map((p) => p.y);
30
+ return new DOMRect(Math.min(...xs), Math.min(...ys), Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));
31
+ }
@@ -0,0 +1,10 @@
1
+ import type { LogLevel } from 'remotion';
2
+ import type { InternalState } from '../internal-state';
3
+ export declare const handle3dTransform: ({ element, matrix, parentRect, context, logLevel, internalState, }: {
4
+ element: HTMLElement | SVGElement;
5
+ matrix: DOMMatrix;
6
+ parentRect: DOMRect;
7
+ context: OffscreenCanvasRenderingContext2D;
8
+ logLevel: LogLevel;
9
+ internalState: InternalState;
10
+ }) => Promise<void>;
@@ -0,0 +1,39 @@
1
+ import { Internals } from 'remotion';
2
+ import { compose } from '../compose';
3
+ import { getBiggestBoundingClientRect } from '../get-biggest-bounding-client-rect';
4
+ import { getNarrowerRect } from './clamp-rect-to-parent-bounds';
5
+ import { getPreTransformRect } from './get-pretransform-rect';
6
+ import { transformIn3d } from './transform-in-3d';
7
+ export const handle3dTransform = async ({ element, matrix, parentRect, context, logLevel, internalState, }) => {
8
+ const unclampedBiggestBoundingClientRect = getBiggestBoundingClientRect(element);
9
+ const biggestPossiblePretransformRect = getPreTransformRect(parentRect, matrix);
10
+ const preTransformRect = getNarrowerRect({
11
+ firstRect: unclampedBiggestBoundingClientRect,
12
+ secondRect: biggestPossiblePretransformRect,
13
+ });
14
+ const start = Date.now();
15
+ const tempCanvas = new OffscreenCanvas(Math.ceil(preTransformRect.width), Math.ceil(preTransformRect.height));
16
+ await compose({
17
+ element,
18
+ context: tempCanvas.getContext('2d'),
19
+ logLevel,
20
+ parentRect: preTransformRect,
21
+ internalState,
22
+ });
23
+ const afterCompose = Date.now();
24
+ const { canvas: transformed, rect: transformedRect } = transformIn3d({
25
+ untransformedRect: preTransformRect,
26
+ matrix,
27
+ sourceCanvas: tempCanvas,
28
+ });
29
+ context.drawImage(transformed, transformedRect.x, transformedRect.y);
30
+ const afterDraw = Date.now();
31
+ Internals.Log.trace({
32
+ logLevel,
33
+ tag: '@remotion/web-renderer',
34
+ }, `Transforming element in 3D - canvas size: ${transformedRect.width}x${transformedRect.height} - compose: ${afterCompose - start}ms - draw: ${afterDraw - afterCompose}ms`);
35
+ internalState.add3DTransform({
36
+ canvasWidth: Math.ceil(transformedRect.width),
37
+ canvasHeight: Math.ceil(transformedRect.height),
38
+ });
39
+ };
@@ -0,0 +1,4 @@
1
+ export declare const hasTransformCssValue: (style: CSSStyleDeclaration) => boolean;
2
+ export declare const hasRotateCssValue: (style: CSSStyleDeclaration) => boolean;
3
+ export declare const hasScaleCssValue: (style: CSSStyleDeclaration) => boolean;
4
+ export declare const hasAnyTransformCssValue: (style: CSSStyleDeclaration) => boolean;
@@ -0,0 +1,14 @@
1
+ export const hasTransformCssValue = (style) => {
2
+ return style.transform !== 'none' && style.transform !== '';
3
+ };
4
+ export const hasRotateCssValue = (style) => {
5
+ return style.rotate !== 'none' && style.rotate !== '';
6
+ };
7
+ export const hasScaleCssValue = (style) => {
8
+ return style.scale !== 'none' && style.scale !== '';
9
+ };
10
+ export const hasAnyTransformCssValue = (style) => {
11
+ return (hasTransformCssValue(style) ||
12
+ hasRotateCssValue(style) ||
13
+ hasScaleCssValue(style));
14
+ };
@@ -0,0 +1,7 @@
1
+ import type { BorderRadiusCorners } from './border-radius';
2
+ export declare const setOverflowHidden: ({ ctx, rect, borderRadius, overflowHidden, }: {
3
+ ctx: OffscreenCanvasRenderingContext2D;
4
+ rect: DOMRect;
5
+ borderRadius: BorderRadiusCorners;
6
+ overflowHidden: boolean;
7
+ }) => () => void;
@@ -0,0 +1,12 @@
1
+ import { setBorderRadius } from './border-radius';
2
+ export const setOverflowHidden = ({ ctx, rect, borderRadius, overflowHidden, }) => {
3
+ if (!overflowHidden) {
4
+ return () => { };
5
+ }
6
+ return setBorderRadius({
7
+ ctx,
8
+ rect,
9
+ borderRadius,
10
+ forceClipEvenWhenZero: true,
11
+ });
12
+ };