@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.
- package/dist/border-radius.d.ts +31 -0
- package/dist/border-radius.js +152 -0
- package/dist/calculate-transforms.d.ts +2 -0
- package/dist/calculate-transforms.js +17 -0
- package/dist/composable.d.ts +2 -8
- package/dist/compose-canvas.js +28 -4
- package/dist/compose.d.ts +4 -3
- package/dist/compose.js +39 -12
- package/dist/drawing/border-radius.d.ts +3 -5
- package/dist/drawing/border-radius.js +12 -11
- package/dist/drawing/calculate-transforms.d.ts +6 -2
- package/dist/drawing/calculate-transforms.js +19 -22
- package/dist/drawing/canvas-offset-from-rect.d.ts +8 -0
- package/dist/drawing/canvas-offset-from-rect.js +12 -0
- package/dist/drawing/clamp-rect-to-parent-bounds.d.ts +4 -0
- package/dist/drawing/clamp-rect-to-parent-bounds.js +7 -0
- 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-border.d.ts +2 -5
- package/dist/drawing/draw-border.js +37 -37
- package/dist/drawing/draw-element-to-canvas.d.ts +2 -1
- package/dist/drawing/draw-element-to-canvas.js +8 -36
- package/dist/drawing/draw-element.d.ts +5 -3
- package/dist/drawing/draw-element.js +29 -14
- package/dist/drawing/draw-outline.d.ts +9 -0
- package/dist/drawing/draw-outline.js +116 -0
- package/dist/drawing/get-bounding-box-including-shadow.d.ts +1 -0
- package/dist/drawing/get-bounding-box-including-shadow.js +6 -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/get-pretransform-rect.d.ts +1 -0
- package/dist/drawing/get-pretransform-rect.js +31 -0
- package/dist/drawing/handle-3d-transform.d.ts +10 -0
- package/dist/drawing/handle-3d-transform.js +39 -0
- package/dist/drawing/has-transform.d.ts +4 -0
- package/dist/drawing/has-transform.js +14 -0
- package/dist/drawing/overflow.d.ts +7 -0
- package/dist/drawing/overflow.js +12 -0
- package/dist/drawing/process-node.d.ts +17 -0
- package/dist/drawing/process-node.js +41 -0
- package/dist/drawing/text/handle-text-node.d.ts +6 -5
- package/dist/drawing/text/handle-text-node.js +5 -5
- package/dist/drawing/transform-in-3d.d.ts +7 -7
- package/dist/drawing/transform-in-3d.js +20 -12
- package/dist/drawing/transform-rect-with-matrix.d.ts +4 -0
- package/dist/drawing/transform-rect-with-matrix.js +19 -0
- package/dist/esm/index.mjs +501 -218
- package/dist/find-canvas-elements.d.ts +1 -0
- package/dist/find-canvas-elements.js +13 -0
- package/dist/find-capturable-elements.d.ts +1 -1
- package/dist/find-capturable-elements.js +20 -22
- package/dist/get-biggest-bounding-client-rect.js +14 -4
- package/dist/internal-state.d.ts +9 -0
- package/dist/internal-state.js +12 -0
- package/dist/opacity.d.ts +4 -0
- package/dist/opacity.js +7 -0
- package/dist/render-media-on-web.d.ts +2 -0
- package/dist/render-media-on-web.js +5 -0
- package/dist/render-still-on-web.d.ts +5 -1
- package/dist/render-still-on-web.js +4 -1
- package/dist/take-screenshot.d.ts +5 -2
- package/dist/take-screenshot.js +16 -4
- package/dist/transform.d.ts +4 -0
- package/dist/transform.js +6 -0
- package/package.json +6 -6
- package/dist/drawing/text/get-base-height.d.ts +0 -1
- 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
|
+
};
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { BorderRadiusCorners } from './border-radius';
|
|
2
|
-
export declare const drawBorder: ({ ctx,
|
|
2
|
+
export declare const drawBorder: ({ ctx, rect, borderRadius, computedStyle, }: {
|
|
3
3
|
ctx: OffscreenCanvasRenderingContext2D;
|
|
4
|
-
|
|
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,
|
|
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 {
|
|
7
|
-
export const drawElementToCanvas = async ({ element, context, draw, offsetLeft, offsetTop, logLevel, }) => {
|
|
8
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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: ({
|
|
3
|
-
|
|
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<
|
|
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 ({
|
|
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:
|
|
10
|
-
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
+
};
|