@remotion/web-renderer 4.0.396 → 4.0.397
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/compose.js +11 -5
- package/dist/create-scaffold.js +10 -3
- package/dist/drawing/border-radius.js +9 -32
- package/dist/drawing/calculate-transforms.d.ts +9 -3
- package/dist/drawing/calculate-transforms.js +31 -9
- package/dist/drawing/clamp-rect-to-parent-bounds.d.ts +4 -0
- package/dist/drawing/clamp-rect-to-parent-bounds.js +11 -0
- package/dist/drawing/do-rects-intersect.d.ts +1 -0
- package/dist/drawing/do-rects-intersect.js +6 -0
- package/dist/drawing/draw-box-shadow.d.ts +18 -0
- package/dist/drawing/draw-box-shadow.js +103 -0
- package/dist/drawing/draw-element.d.ts +4 -1
- package/dist/drawing/draw-element.js +37 -6
- package/dist/drawing/draw-outline.js +9 -32
- package/dist/drawing/draw-rounded.d.ts +9 -0
- package/dist/drawing/draw-rounded.js +34 -0
- package/dist/drawing/get-pretransform-rect.js +5 -0
- package/dist/drawing/handle-3d-transform.d.ts +9 -8
- package/dist/drawing/handle-3d-transform.js +11 -25
- package/dist/drawing/handle-mask.d.ts +8 -0
- package/dist/drawing/handle-mask.js +19 -0
- package/dist/drawing/mask-image.d.ts +3 -0
- package/dist/drawing/mask-image.js +14 -0
- package/dist/drawing/parse-linear-gradient.d.ts +14 -0
- package/dist/drawing/parse-linear-gradient.js +260 -0
- package/dist/drawing/precompose.d.ts +11 -0
- package/dist/drawing/precompose.js +13 -0
- package/dist/drawing/process-node.d.ts +4 -3
- package/dist/drawing/process-node.js +89 -14
- package/dist/drawing/round-to-expand-rect.d.ts +1 -0
- package/dist/drawing/round-to-expand-rect.js +7 -0
- package/dist/drawing/text/draw-text.d.ts +5 -1
- package/dist/drawing/text/draw-text.js +10 -5
- package/dist/drawing/text/find-line-breaks.text.d.ts +1 -1
- package/dist/drawing/text/find-line-breaks.text.js +2 -2
- package/dist/drawing/text/handle-text-node.d.ts +2 -1
- package/dist/drawing/text/handle-text-node.js +3 -2
- package/dist/drawing/transform-in-3d.d.ts +3 -1
- package/dist/drawing/transform-in-3d.js +30 -28
- package/dist/drawing/transform.d.ts +2 -1
- package/dist/drawing/transform.js +6 -2
- package/dist/esm/index.mjs +788 -211
- package/dist/get-biggest-bounding-client-rect.js +19 -4
- package/dist/internal-state.d.ts +2 -2
- package/dist/internal-state.js +7 -7
- package/dist/render-media-on-web.d.ts +1 -0
- package/dist/render-media-on-web.js +22 -14
- package/package.json +6 -6
package/dist/esm/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
StreamTarget,
|
|
7
7
|
VideoSampleSource
|
|
8
8
|
} from "mediabunny";
|
|
9
|
-
import { Internals as
|
|
9
|
+
import { Internals as Internals7 } from "remotion";
|
|
10
10
|
|
|
11
11
|
// src/add-sample.ts
|
|
12
12
|
import { AudioSample, VideoSample } from "mediabunny";
|
|
@@ -231,16 +231,22 @@ async function createScaffold({
|
|
|
231
231
|
throw new Error("@remotion/web-renderer requires React 18 or higher");
|
|
232
232
|
}
|
|
233
233
|
const div = document.createElement("div");
|
|
234
|
+
div.style.position = "fixed";
|
|
234
235
|
div.style.display = "flex";
|
|
236
|
+
div.style.flexDirection = "column";
|
|
235
237
|
div.style.backgroundColor = "transparent";
|
|
236
|
-
div.style.position = "fixed";
|
|
237
238
|
div.style.width = `${width}px`;
|
|
238
239
|
div.style.height = `${height}px`;
|
|
239
240
|
div.style.zIndex = "-9999";
|
|
240
241
|
div.style.top = "0";
|
|
241
|
-
div.style.visibility = "hidden";
|
|
242
242
|
div.style.left = "0";
|
|
243
|
+
div.style.right = "0";
|
|
244
|
+
div.style.bottom = "0";
|
|
245
|
+
div.style.visibility = "hidden";
|
|
243
246
|
div.style.pointerEvents = "none";
|
|
247
|
+
const scaffoldClassName = `remotion-scaffold-${Math.random().toString(36).substring(2, 15)}`;
|
|
248
|
+
div.className = scaffoldClassName;
|
|
249
|
+
const cleanupCSS = Internals2.CSSUtils.injectCSS(Internals2.CSSUtils.makeDefaultPreviewCSS(`.${scaffoldClassName}`, "white"));
|
|
244
250
|
document.body.appendChild(div);
|
|
245
251
|
const { promise, resolve, reject } = withResolvers();
|
|
246
252
|
const root = ReactDOM.createRoot(div, {
|
|
@@ -336,6 +342,7 @@ async function createScaffold({
|
|
|
336
342
|
cleanupScaffold: () => {
|
|
337
343
|
root.unmount();
|
|
338
344
|
div.remove();
|
|
345
|
+
cleanupCSS();
|
|
339
346
|
},
|
|
340
347
|
timeUpdater,
|
|
341
348
|
collectAssets
|
|
@@ -384,17 +391,17 @@ var getDefaultAudioEncodingConfig = async () => {
|
|
|
384
391
|
|
|
385
392
|
// src/internal-state.ts
|
|
386
393
|
var makeInternalState = () => {
|
|
387
|
-
let
|
|
388
|
-
let
|
|
394
|
+
let drawnPrecomposedPixels = 0;
|
|
395
|
+
let precomposedTextures = 0;
|
|
389
396
|
return {
|
|
390
|
-
getDrawn3dPixels: () =>
|
|
391
|
-
|
|
392
|
-
|
|
397
|
+
getDrawn3dPixels: () => drawnPrecomposedPixels,
|
|
398
|
+
getPrecomposedTiles: () => precomposedTextures,
|
|
399
|
+
addPrecompose: ({
|
|
393
400
|
canvasWidth,
|
|
394
401
|
canvasHeight
|
|
395
402
|
}) => {
|
|
396
|
-
|
|
397
|
-
|
|
403
|
+
drawnPrecomposedPixels += canvasWidth * canvasHeight;
|
|
404
|
+
precomposedTextures++;
|
|
398
405
|
}
|
|
399
406
|
};
|
|
400
407
|
};
|
|
@@ -600,6 +607,9 @@ var drawDomElement = (node) => {
|
|
|
600
607
|
return domDrawFn;
|
|
601
608
|
};
|
|
602
609
|
|
|
610
|
+
// src/drawing/process-node.ts
|
|
611
|
+
import { Internals as Internals5 } from "remotion";
|
|
612
|
+
|
|
603
613
|
// src/drawing/has-transform.ts
|
|
604
614
|
var hasTransformCssValue = (style) => {
|
|
605
615
|
return style.transform !== "none" && style.transform !== "";
|
|
@@ -614,6 +624,239 @@ var hasAnyTransformCssValue = (style) => {
|
|
|
614
624
|
return hasTransformCssValue(style) || hasRotateCssValue(style) || hasScaleCssValue(style);
|
|
615
625
|
};
|
|
616
626
|
|
|
627
|
+
// src/drawing/parse-linear-gradient.ts
|
|
628
|
+
import { NoReactInternals as NoReactInternals2 } from "remotion/no-react";
|
|
629
|
+
var isValidColor = (color) => {
|
|
630
|
+
try {
|
|
631
|
+
const result = NoReactInternals2.processColor(color);
|
|
632
|
+
return result !== null && result !== undefined;
|
|
633
|
+
} catch {
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
var parseDirection = (directionStr) => {
|
|
638
|
+
const trimmed = directionStr.trim().toLowerCase();
|
|
639
|
+
if (trimmed.startsWith("to ")) {
|
|
640
|
+
const direction = trimmed.substring(3).trim();
|
|
641
|
+
switch (direction) {
|
|
642
|
+
case "top":
|
|
643
|
+
return 0;
|
|
644
|
+
case "right":
|
|
645
|
+
return 90;
|
|
646
|
+
case "bottom":
|
|
647
|
+
return 180;
|
|
648
|
+
case "left":
|
|
649
|
+
return 270;
|
|
650
|
+
case "top right":
|
|
651
|
+
case "right top":
|
|
652
|
+
return 45;
|
|
653
|
+
case "bottom right":
|
|
654
|
+
case "right bottom":
|
|
655
|
+
return 135;
|
|
656
|
+
case "bottom left":
|
|
657
|
+
case "left bottom":
|
|
658
|
+
return 225;
|
|
659
|
+
case "top left":
|
|
660
|
+
case "left top":
|
|
661
|
+
return 315;
|
|
662
|
+
default:
|
|
663
|
+
return 180;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
const angleMatch = trimmed.match(/^(-?\d+\.?\d*)(deg|rad|grad|turn)$/);
|
|
667
|
+
if (angleMatch) {
|
|
668
|
+
const value = parseFloat(angleMatch[1]);
|
|
669
|
+
const unit = angleMatch[2];
|
|
670
|
+
switch (unit) {
|
|
671
|
+
case "deg":
|
|
672
|
+
return value;
|
|
673
|
+
case "rad":
|
|
674
|
+
return value * 180 / Math.PI;
|
|
675
|
+
case "grad":
|
|
676
|
+
return value * 360 / 400;
|
|
677
|
+
case "turn":
|
|
678
|
+
return value * 360;
|
|
679
|
+
default:
|
|
680
|
+
return value;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return 180;
|
|
684
|
+
};
|
|
685
|
+
var parseColorStops = (colorStopsStr) => {
|
|
686
|
+
const parts = colorStopsStr.split(/,(?![^(]*\))/);
|
|
687
|
+
const stops = [];
|
|
688
|
+
for (const part of parts) {
|
|
689
|
+
const trimmed = part.trim();
|
|
690
|
+
if (!trimmed)
|
|
691
|
+
continue;
|
|
692
|
+
const colorMatch = trimmed.match(/(rgba?\([^)]+\)|hsla?\([^)]+\)|#[0-9a-f]{3,8}|[a-z]+)/i);
|
|
693
|
+
if (!colorMatch) {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
const colorStr = colorMatch[0];
|
|
697
|
+
if (!isValidColor(colorStr)) {
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
const remaining = trimmed.substring(colorMatch.index + colorStr.length).trim();
|
|
701
|
+
const normalizedColor = colorStr;
|
|
702
|
+
let position = null;
|
|
703
|
+
if (remaining) {
|
|
704
|
+
const posMatch = remaining.match(/(-?\d+\.?\d*)(%|px)?/);
|
|
705
|
+
if (posMatch) {
|
|
706
|
+
const value = parseFloat(posMatch[1]);
|
|
707
|
+
const unit = posMatch[2];
|
|
708
|
+
if (unit === "%") {
|
|
709
|
+
position = value / 100;
|
|
710
|
+
} else if (unit === "px") {
|
|
711
|
+
position = null;
|
|
712
|
+
} else {
|
|
713
|
+
position = value / 100;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
stops.push({
|
|
718
|
+
color: normalizedColor,
|
|
719
|
+
position: position !== null ? position : -1
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
if (stops.length === 0) {
|
|
723
|
+
return null;
|
|
724
|
+
}
|
|
725
|
+
let lastExplicitIndex = -1;
|
|
726
|
+
let lastExplicitPosition = 0;
|
|
727
|
+
for (let i = 0;i < stops.length; i++) {
|
|
728
|
+
if (stops[i].position !== -1) {
|
|
729
|
+
if (lastExplicitIndex >= 0) {
|
|
730
|
+
const numImplicit = i - lastExplicitIndex - 1;
|
|
731
|
+
if (numImplicit > 0) {
|
|
732
|
+
const step = (stops[i].position - lastExplicitPosition) / (numImplicit + 1);
|
|
733
|
+
for (let j = lastExplicitIndex + 1;j < i; j++) {
|
|
734
|
+
stops[j].position = lastExplicitPosition + step * (j - lastExplicitIndex);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
} else {
|
|
738
|
+
const numImplicit = i;
|
|
739
|
+
if (numImplicit > 0) {
|
|
740
|
+
const step = stops[i].position / (numImplicit + 1);
|
|
741
|
+
for (let j = 0;j < i; j++) {
|
|
742
|
+
stops[j].position = step * (j + 1);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
lastExplicitIndex = i;
|
|
747
|
+
lastExplicitPosition = stops[i].position;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (stops.every((s) => s.position === -1)) {
|
|
751
|
+
if (stops.length === 1) {
|
|
752
|
+
stops[0].position = 0.5;
|
|
753
|
+
} else {
|
|
754
|
+
for (let i = 0;i < stops.length; i++) {
|
|
755
|
+
stops[i].position = i / (stops.length - 1);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
} else if (lastExplicitIndex < stops.length - 1) {
|
|
759
|
+
const numImplicit = stops.length - 1 - lastExplicitIndex;
|
|
760
|
+
const step = (1 - lastExplicitPosition) / (numImplicit + 1);
|
|
761
|
+
for (let i = lastExplicitIndex + 1;i < stops.length; i++) {
|
|
762
|
+
stops[i].position = lastExplicitPosition + step * (i - lastExplicitIndex);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
for (const stop of stops) {
|
|
766
|
+
stop.position = Math.max(0, Math.min(1, stop.position));
|
|
767
|
+
}
|
|
768
|
+
return stops;
|
|
769
|
+
};
|
|
770
|
+
var extractGradientContent = (backgroundImage) => {
|
|
771
|
+
const prefix = "linear-gradient(";
|
|
772
|
+
const startIndex = backgroundImage.toLowerCase().indexOf(prefix);
|
|
773
|
+
if (startIndex === -1) {
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
let depth = 0;
|
|
777
|
+
const contentStart = startIndex + prefix.length;
|
|
778
|
+
for (let i = contentStart;i < backgroundImage.length; i++) {
|
|
779
|
+
const char = backgroundImage[i];
|
|
780
|
+
if (char === "(") {
|
|
781
|
+
depth++;
|
|
782
|
+
} else if (char === ")") {
|
|
783
|
+
if (depth === 0) {
|
|
784
|
+
return backgroundImage.substring(contentStart, i).trim();
|
|
785
|
+
}
|
|
786
|
+
depth--;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return null;
|
|
790
|
+
};
|
|
791
|
+
var parseLinearGradient = (backgroundImage) => {
|
|
792
|
+
if (!backgroundImage || backgroundImage === "none") {
|
|
793
|
+
return null;
|
|
794
|
+
}
|
|
795
|
+
const content = extractGradientContent(backgroundImage);
|
|
796
|
+
if (!content) {
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
const parts = content.split(/,(?![^(]*\))/);
|
|
800
|
+
let angle = 180;
|
|
801
|
+
let colorStopsStart = 0;
|
|
802
|
+
if (parts.length > 0) {
|
|
803
|
+
const firstPart = parts[0].trim();
|
|
804
|
+
const isDirection = firstPart.startsWith("to ") || /^-?\d+\.?\d*(deg|rad|grad|turn)$/.test(firstPart);
|
|
805
|
+
if (isDirection) {
|
|
806
|
+
angle = parseDirection(firstPart);
|
|
807
|
+
colorStopsStart = 1;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
const colorStopsStr = parts.slice(colorStopsStart).join(",");
|
|
811
|
+
const colorStops = parseColorStops(colorStopsStr);
|
|
812
|
+
if (!colorStops || colorStops.length === 0) {
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
return {
|
|
816
|
+
angle,
|
|
817
|
+
colorStops
|
|
818
|
+
};
|
|
819
|
+
};
|
|
820
|
+
var createCanvasGradient = ({
|
|
821
|
+
ctx,
|
|
822
|
+
rect,
|
|
823
|
+
gradientInfo
|
|
824
|
+
}) => {
|
|
825
|
+
const angleRad = (gradientInfo.angle - 90) * Math.PI / 180;
|
|
826
|
+
const centerX = rect.left + rect.width / 2;
|
|
827
|
+
const centerY = rect.top + rect.height / 2;
|
|
828
|
+
const cos = Math.cos(angleRad);
|
|
829
|
+
const sin = Math.sin(angleRad);
|
|
830
|
+
const halfWidth = rect.width / 2;
|
|
831
|
+
const halfHeight = rect.height / 2;
|
|
832
|
+
let length = Math.abs(cos) * halfWidth + Math.abs(sin) * halfHeight;
|
|
833
|
+
if (!Number.isFinite(length) || length === 0) {
|
|
834
|
+
length = Math.sqrt(halfWidth ** 2 + halfHeight ** 2);
|
|
835
|
+
}
|
|
836
|
+
const x0 = centerX - cos * length;
|
|
837
|
+
const y0 = centerY - sin * length;
|
|
838
|
+
const x1 = centerX + cos * length;
|
|
839
|
+
const y1 = centerY + sin * length;
|
|
840
|
+
const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
|
|
841
|
+
for (const stop of gradientInfo.colorStops) {
|
|
842
|
+
gradient.addColorStop(stop.position, stop.color);
|
|
843
|
+
}
|
|
844
|
+
return gradient;
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
// src/drawing/mask-image.ts
|
|
848
|
+
var getMaskImageValue = (computedStyle) => {
|
|
849
|
+
const { maskImage, webkitMaskImage } = computedStyle;
|
|
850
|
+
const value = maskImage || webkitMaskImage;
|
|
851
|
+
if (!value || value === "none") {
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
return value;
|
|
855
|
+
};
|
|
856
|
+
var parseMaskImage = (maskImageValue) => {
|
|
857
|
+
return parseLinearGradient(maskImageValue);
|
|
858
|
+
};
|
|
859
|
+
|
|
617
860
|
// src/drawing/parse-transform-origin.ts
|
|
618
861
|
var parseTransformOrigin = (transformOrigin) => {
|
|
619
862
|
if (transformOrigin.trim() === "") {
|
|
@@ -633,30 +876,39 @@ var getInternalTransformOrigin = (transform) => {
|
|
|
633
876
|
};
|
|
634
877
|
return origin;
|
|
635
878
|
};
|
|
636
|
-
var getGlobalTransformOrigin = ({
|
|
637
|
-
transform,
|
|
638
|
-
offsetLeft,
|
|
639
|
-
offsetTop
|
|
640
|
-
}) => {
|
|
879
|
+
var getGlobalTransformOrigin = ({ transform }) => {
|
|
641
880
|
const { x: originX, y: originY } = getInternalTransformOrigin(transform);
|
|
642
881
|
return {
|
|
643
|
-
x: originX + transform.boundingClientRect.left
|
|
644
|
-
y: originY + transform.boundingClientRect.top
|
|
882
|
+
x: originX + transform.boundingClientRect.left,
|
|
883
|
+
y: originY + transform.boundingClientRect.top
|
|
645
884
|
};
|
|
646
885
|
};
|
|
647
886
|
var calculateTransforms = ({
|
|
648
887
|
element,
|
|
649
|
-
|
|
650
|
-
offsetTop
|
|
888
|
+
rootElement
|
|
651
889
|
}) => {
|
|
652
890
|
let parent = element;
|
|
653
891
|
const transforms = [];
|
|
654
892
|
const toReset = [];
|
|
893
|
+
let opacity = 1;
|
|
655
894
|
let elementComputedStyle = null;
|
|
895
|
+
let maskImageInfo = null;
|
|
656
896
|
while (parent) {
|
|
657
897
|
const computedStyle = getComputedStyle(parent);
|
|
658
898
|
if (parent === element) {
|
|
659
899
|
elementComputedStyle = computedStyle;
|
|
900
|
+
opacity = parseFloat(computedStyle.opacity);
|
|
901
|
+
const maskImageValue = getMaskImageValue(computedStyle);
|
|
902
|
+
maskImageInfo = maskImageValue ? parseMaskImage(maskImageValue) : null;
|
|
903
|
+
const originalMaskImage = parent.style.maskImage;
|
|
904
|
+
const originalWebkitMaskImage = parent.style.webkitMaskImage;
|
|
905
|
+
parent.style.maskImage = "none";
|
|
906
|
+
parent.style.webkitMaskImage = "none";
|
|
907
|
+
const parentRef = parent;
|
|
908
|
+
toReset.push(() => {
|
|
909
|
+
parentRef.style.maskImage = originalMaskImage;
|
|
910
|
+
parentRef.style.webkitMaskImage = originalWebkitMaskImage;
|
|
911
|
+
});
|
|
660
912
|
}
|
|
661
913
|
if (hasAnyTransformCssValue(computedStyle) || parent === element) {
|
|
662
914
|
const toParse = hasTransformCssValue(computedStyle) ? computedStyle.transform : undefined;
|
|
@@ -686,6 +938,9 @@ var calculateTransforms = ({
|
|
|
686
938
|
parentRef.style.rotate = rotate;
|
|
687
939
|
});
|
|
688
940
|
}
|
|
941
|
+
if (parent === rootElement) {
|
|
942
|
+
break;
|
|
943
|
+
}
|
|
689
944
|
parent = parent.parentElement;
|
|
690
945
|
}
|
|
691
946
|
for (const transform of transforms) {
|
|
@@ -697,9 +952,7 @@ var calculateTransforms = ({
|
|
|
697
952
|
for (const transform of transforms.slice().reverse()) {
|
|
698
953
|
for (const matrix of transform.matrices) {
|
|
699
954
|
const globalTransformOrigin = getGlobalTransformOrigin({
|
|
700
|
-
transform
|
|
701
|
-
offsetLeft,
|
|
702
|
-
offsetTop
|
|
955
|
+
transform
|
|
703
956
|
});
|
|
704
957
|
const transformMatrix = new DOMMatrix().translate(globalTransformOrigin.x, globalTransformOrigin.y).multiply(matrix).translate(-globalTransformOrigin.x, -globalTransformOrigin.y);
|
|
705
958
|
totalMatrix.multiplySelf(transformMatrix);
|
|
@@ -708,6 +961,8 @@ var calculateTransforms = ({
|
|
|
708
961
|
if (!elementComputedStyle) {
|
|
709
962
|
throw new Error("Element computed style not found");
|
|
710
963
|
}
|
|
964
|
+
const needs3DTransformViaWebGL = !totalMatrix.is2D;
|
|
965
|
+
const needsMaskImage = maskImageInfo !== null;
|
|
711
966
|
return {
|
|
712
967
|
dimensions,
|
|
713
968
|
totalMatrix,
|
|
@@ -718,10 +973,85 @@ var calculateTransforms = ({
|
|
|
718
973
|
},
|
|
719
974
|
nativeTransformOrigin,
|
|
720
975
|
computedStyle: elementComputedStyle,
|
|
721
|
-
opacity
|
|
976
|
+
opacity,
|
|
977
|
+
maskImageInfo,
|
|
978
|
+
precompositing: {
|
|
979
|
+
needs3DTransformViaWebGL,
|
|
980
|
+
needsMaskImage: maskImageInfo,
|
|
981
|
+
needsPrecompositing: Boolean(needs3DTransformViaWebGL || needsMaskImage)
|
|
982
|
+
}
|
|
722
983
|
};
|
|
723
984
|
};
|
|
724
985
|
|
|
986
|
+
// src/drawing/round-to-expand-rect.ts
|
|
987
|
+
var roundToExpandRect = (rect) => {
|
|
988
|
+
const left = Math.floor(rect.left);
|
|
989
|
+
const top = Math.floor(rect.top);
|
|
990
|
+
const right = Math.ceil(rect.right);
|
|
991
|
+
const bottom = Math.ceil(rect.bottom);
|
|
992
|
+
return new DOMRect(left, top, right - left, bottom - top);
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
// src/drawing/clamp-rect-to-parent-bounds.ts
|
|
996
|
+
var getNarrowerRect = ({
|
|
997
|
+
firstRect,
|
|
998
|
+
secondRect
|
|
999
|
+
}) => {
|
|
1000
|
+
const left = Math.max(firstRect.left, secondRect.left);
|
|
1001
|
+
const top = Math.max(firstRect.top, secondRect.top);
|
|
1002
|
+
const bottom = Math.min(firstRect.bottom, secondRect.bottom);
|
|
1003
|
+
const right = Math.min(firstRect.right, secondRect.right);
|
|
1004
|
+
return new DOMRect(left, top, right - left, bottom - top);
|
|
1005
|
+
};
|
|
1006
|
+
var getWiderRectAndExpand = ({
|
|
1007
|
+
firstRect,
|
|
1008
|
+
secondRect
|
|
1009
|
+
}) => {
|
|
1010
|
+
if (firstRect === null) {
|
|
1011
|
+
return roundToExpandRect(secondRect);
|
|
1012
|
+
}
|
|
1013
|
+
const left = Math.min(firstRect.left, secondRect.left);
|
|
1014
|
+
const top = Math.min(firstRect.top, secondRect.top);
|
|
1015
|
+
const bottom = Math.max(firstRect.bottom, secondRect.bottom);
|
|
1016
|
+
const right = Math.max(firstRect.right, secondRect.right);
|
|
1017
|
+
return roundToExpandRect(new DOMRect(left, top, right - left, bottom - top));
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
// src/drawing/do-rects-intersect.ts
|
|
1021
|
+
function doRectsIntersect(rect1, rect2) {
|
|
1022
|
+
return !(rect1.right <= rect2.left || rect1.left >= rect2.right || rect1.bottom <= rect2.top || rect1.top >= rect2.bottom);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// src/drawing/draw-rounded.ts
|
|
1026
|
+
var drawRoundedRectPath = ({
|
|
1027
|
+
ctx,
|
|
1028
|
+
x,
|
|
1029
|
+
y,
|
|
1030
|
+
width,
|
|
1031
|
+
height,
|
|
1032
|
+
borderRadius
|
|
1033
|
+
}) => {
|
|
1034
|
+
ctx.beginPath();
|
|
1035
|
+
ctx.moveTo(x + borderRadius.topLeft.horizontal, y);
|
|
1036
|
+
ctx.lineTo(x + width - borderRadius.topRight.horizontal, y);
|
|
1037
|
+
if (borderRadius.topRight.horizontal > 0 || borderRadius.topRight.vertical > 0) {
|
|
1038
|
+
ctx.ellipse(x + width - borderRadius.topRight.horizontal, y + borderRadius.topRight.vertical, borderRadius.topRight.horizontal, borderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
|
|
1039
|
+
}
|
|
1040
|
+
ctx.lineTo(x + width, y + height - borderRadius.bottomRight.vertical);
|
|
1041
|
+
if (borderRadius.bottomRight.horizontal > 0 || borderRadius.bottomRight.vertical > 0) {
|
|
1042
|
+
ctx.ellipse(x + width - borderRadius.bottomRight.horizontal, y + height - borderRadius.bottomRight.vertical, borderRadius.bottomRight.horizontal, borderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
|
|
1043
|
+
}
|
|
1044
|
+
ctx.lineTo(x + borderRadius.bottomLeft.horizontal, y + height);
|
|
1045
|
+
if (borderRadius.bottomLeft.horizontal > 0 || borderRadius.bottomLeft.vertical > 0) {
|
|
1046
|
+
ctx.ellipse(x + borderRadius.bottomLeft.horizontal, y + height - borderRadius.bottomLeft.vertical, borderRadius.bottomLeft.horizontal, borderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
|
|
1047
|
+
}
|
|
1048
|
+
ctx.lineTo(x, y + borderRadius.topLeft.vertical);
|
|
1049
|
+
if (borderRadius.topLeft.horizontal > 0 || borderRadius.topLeft.vertical > 0) {
|
|
1050
|
+
ctx.ellipse(x + borderRadius.topLeft.horizontal, y + borderRadius.topLeft.vertical, borderRadius.topLeft.horizontal, borderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
|
|
1051
|
+
}
|
|
1052
|
+
ctx.closePath();
|
|
1053
|
+
};
|
|
1054
|
+
|
|
725
1055
|
// src/drawing/border-radius.ts
|
|
726
1056
|
function parseValue({
|
|
727
1057
|
value,
|
|
@@ -831,25 +1161,14 @@ function setBorderRadius({
|
|
|
831
1161
|
return () => {};
|
|
832
1162
|
}
|
|
833
1163
|
ctx.save();
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
ctx.ellipse(rect.left + rect.width - borderRadius.bottomRight.horizontal, rect.top + rect.height - borderRadius.bottomRight.vertical, borderRadius.bottomRight.horizontal, borderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
|
|
843
|
-
}
|
|
844
|
-
ctx.lineTo(rect.left + borderRadius.bottomLeft.horizontal, rect.top + rect.height);
|
|
845
|
-
if (borderRadius.bottomLeft.horizontal > 0 || borderRadius.bottomLeft.vertical > 0) {
|
|
846
|
-
ctx.ellipse(rect.left + borderRadius.bottomLeft.horizontal, rect.top + rect.height - borderRadius.bottomLeft.vertical, borderRadius.bottomLeft.horizontal, borderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
|
|
847
|
-
}
|
|
848
|
-
ctx.lineTo(rect.left, rect.top + borderRadius.topLeft.vertical);
|
|
849
|
-
if (borderRadius.topLeft.horizontal > 0 || borderRadius.topLeft.vertical > 0) {
|
|
850
|
-
ctx.ellipse(rect.left + borderRadius.topLeft.horizontal, rect.top + borderRadius.topLeft.vertical, borderRadius.topLeft.horizontal, borderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
|
|
851
|
-
}
|
|
852
|
-
ctx.closePath();
|
|
1164
|
+
drawRoundedRectPath({
|
|
1165
|
+
ctx,
|
|
1166
|
+
x: rect.left,
|
|
1167
|
+
y: rect.top,
|
|
1168
|
+
width: rect.width,
|
|
1169
|
+
height: rect.height,
|
|
1170
|
+
borderRadius
|
|
1171
|
+
});
|
|
853
1172
|
ctx.clip();
|
|
854
1173
|
return () => {
|
|
855
1174
|
ctx.restore();
|
|
@@ -1193,6 +1512,107 @@ var drawBorder = ({
|
|
|
1193
1512
|
ctx.setLineDash(originalLineDash);
|
|
1194
1513
|
};
|
|
1195
1514
|
|
|
1515
|
+
// src/drawing/draw-box-shadow.ts
|
|
1516
|
+
import { Internals as Internals4 } from "remotion";
|
|
1517
|
+
var parseBoxShadow = (boxShadowValue) => {
|
|
1518
|
+
if (!boxShadowValue || boxShadowValue === "none") {
|
|
1519
|
+
return [];
|
|
1520
|
+
}
|
|
1521
|
+
const shadows = [];
|
|
1522
|
+
const shadowStrings = boxShadowValue.split(/,(?![^(]*\))/);
|
|
1523
|
+
for (const shadowStr of shadowStrings) {
|
|
1524
|
+
const trimmed = shadowStr.trim();
|
|
1525
|
+
if (!trimmed || trimmed === "none") {
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
const shadow = {
|
|
1529
|
+
offsetX: 0,
|
|
1530
|
+
offsetY: 0,
|
|
1531
|
+
blurRadius: 0,
|
|
1532
|
+
color: "rgba(0, 0, 0, 0.5)",
|
|
1533
|
+
inset: false
|
|
1534
|
+
};
|
|
1535
|
+
shadow.inset = /\binset\b/i.test(trimmed);
|
|
1536
|
+
let remaining = trimmed.replace(/\binset\b/gi, "").trim();
|
|
1537
|
+
const colorMatch = remaining.match(/(rgba?\([^)]+\)|hsla?\([^)]+\)|#[0-9a-f]{3,8}|[a-z]+)/i);
|
|
1538
|
+
if (colorMatch) {
|
|
1539
|
+
shadow.color = colorMatch[0];
|
|
1540
|
+
remaining = remaining.replace(colorMatch[0], "").trim();
|
|
1541
|
+
}
|
|
1542
|
+
const numbers = remaining.match(/[+-]?\d*\.?\d+(?:px|em|rem|%)?/gi) || [];
|
|
1543
|
+
const values = numbers.map((n) => parseFloat(n) || 0);
|
|
1544
|
+
if (values.length >= 2) {
|
|
1545
|
+
shadow.offsetX = values[0];
|
|
1546
|
+
shadow.offsetY = values[1];
|
|
1547
|
+
if (values.length >= 3) {
|
|
1548
|
+
shadow.blurRadius = Math.max(0, values[2]);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
shadows.push(shadow);
|
|
1552
|
+
}
|
|
1553
|
+
return shadows;
|
|
1554
|
+
};
|
|
1555
|
+
var setBoxShadow = ({
|
|
1556
|
+
ctx,
|
|
1557
|
+
rect,
|
|
1558
|
+
borderRadius,
|
|
1559
|
+
computedStyle,
|
|
1560
|
+
logLevel
|
|
1561
|
+
}) => {
|
|
1562
|
+
const shadows = parseBoxShadow(computedStyle.boxShadow);
|
|
1563
|
+
if (shadows.length === 0) {
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
for (let i = shadows.length - 1;i >= 0; i--) {
|
|
1567
|
+
const shadow = shadows[i];
|
|
1568
|
+
const newLeft = rect.left + Math.min(shadow.offsetX, 0) - shadow.blurRadius;
|
|
1569
|
+
const newRight = rect.right + Math.max(shadow.offsetX, 0) + shadow.blurRadius;
|
|
1570
|
+
const newTop = rect.top + Math.min(shadow.offsetY, 0) - shadow.blurRadius;
|
|
1571
|
+
const newBottom = rect.bottom + Math.max(shadow.offsetY, 0) + shadow.blurRadius;
|
|
1572
|
+
const newRect = new DOMRect(newLeft, newTop, newRight - newLeft, newBottom - newTop);
|
|
1573
|
+
const leftOffset = rect.left - newLeft;
|
|
1574
|
+
const topOffset = rect.top - newTop;
|
|
1575
|
+
const newCanvas = new OffscreenCanvas(newRect.width, newRect.height);
|
|
1576
|
+
const newCtx = newCanvas.getContext("2d");
|
|
1577
|
+
if (!newCtx) {
|
|
1578
|
+
throw new Error("Failed to get context");
|
|
1579
|
+
}
|
|
1580
|
+
if (shadow.inset) {
|
|
1581
|
+
Internals4.Log.warn({
|
|
1582
|
+
logLevel,
|
|
1583
|
+
tag: "@remotion/web-renderer"
|
|
1584
|
+
}, 'Detected "box-shadow" with "inset". This is not yet supported in @remotion/web-renderer');
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
newCtx.shadowBlur = shadow.blurRadius;
|
|
1588
|
+
newCtx.shadowColor = shadow.color;
|
|
1589
|
+
newCtx.shadowOffsetX = shadow.offsetX;
|
|
1590
|
+
newCtx.shadowOffsetY = shadow.offsetY;
|
|
1591
|
+
newCtx.fillStyle = "black";
|
|
1592
|
+
drawRoundedRectPath({
|
|
1593
|
+
ctx: newCtx,
|
|
1594
|
+
x: leftOffset,
|
|
1595
|
+
y: topOffset,
|
|
1596
|
+
width: rect.width,
|
|
1597
|
+
height: rect.height,
|
|
1598
|
+
borderRadius
|
|
1599
|
+
});
|
|
1600
|
+
newCtx.fill();
|
|
1601
|
+
newCtx.shadowColor = "transparent";
|
|
1602
|
+
newCtx.globalCompositeOperation = "destination-out";
|
|
1603
|
+
drawRoundedRectPath({
|
|
1604
|
+
ctx: newCtx,
|
|
1605
|
+
x: leftOffset,
|
|
1606
|
+
y: topOffset,
|
|
1607
|
+
width: rect.width,
|
|
1608
|
+
height: rect.height,
|
|
1609
|
+
borderRadius
|
|
1610
|
+
});
|
|
1611
|
+
newCtx.fill();
|
|
1612
|
+
ctx.drawImage(newCanvas, rect.left - leftOffset, rect.top - topOffset);
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
|
|
1196
1616
|
// src/drawing/draw-outline.ts
|
|
1197
1617
|
var parseOutlineWidth = (value) => {
|
|
1198
1618
|
return parseFloat(value) || 0;
|
|
@@ -1225,7 +1645,6 @@ var drawOutline = ({
|
|
|
1225
1645
|
const originalStrokeStyle = ctx.strokeStyle;
|
|
1226
1646
|
const originalLineWidth = ctx.lineWidth;
|
|
1227
1647
|
const originalLineDash = ctx.getLineDash();
|
|
1228
|
-
ctx.beginPath();
|
|
1229
1648
|
ctx.strokeStyle = outlineColor;
|
|
1230
1649
|
ctx.lineWidth = outlineWidth;
|
|
1231
1650
|
ctx.setLineDash(getLineDashPattern2(outlineStyle, outlineWidth));
|
|
@@ -1253,24 +1672,14 @@ var drawOutline = ({
|
|
|
1253
1672
|
vertical: borderRadius.bottomLeft.vertical === 0 ? 0 : Math.max(0, borderRadius.bottomLeft.vertical + offset)
|
|
1254
1673
|
}
|
|
1255
1674
|
};
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
}
|
|
1265
|
-
ctx.lineTo(outlineX + adjustedBorderRadius.bottomLeft.horizontal, outlineY + outlineH);
|
|
1266
|
-
if (adjustedBorderRadius.bottomLeft.horizontal > 0 || adjustedBorderRadius.bottomLeft.vertical > 0) {
|
|
1267
|
-
ctx.ellipse(outlineX + adjustedBorderRadius.bottomLeft.horizontal, outlineY + outlineH - adjustedBorderRadius.bottomLeft.vertical, adjustedBorderRadius.bottomLeft.horizontal, adjustedBorderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
|
|
1268
|
-
}
|
|
1269
|
-
ctx.lineTo(outlineX, outlineY + adjustedBorderRadius.topLeft.vertical);
|
|
1270
|
-
if (adjustedBorderRadius.topLeft.horizontal > 0 || adjustedBorderRadius.topLeft.vertical > 0) {
|
|
1271
|
-
ctx.ellipse(outlineX + adjustedBorderRadius.topLeft.horizontal, outlineY + adjustedBorderRadius.topLeft.vertical, adjustedBorderRadius.topLeft.horizontal, adjustedBorderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
|
|
1272
|
-
}
|
|
1273
|
-
ctx.closePath();
|
|
1675
|
+
drawRoundedRectPath({
|
|
1676
|
+
ctx,
|
|
1677
|
+
x: outlineX,
|
|
1678
|
+
y: outlineY,
|
|
1679
|
+
width: outlineW,
|
|
1680
|
+
height: outlineH,
|
|
1681
|
+
borderRadius: adjustedBorderRadius
|
|
1682
|
+
});
|
|
1274
1683
|
ctx.stroke();
|
|
1275
1684
|
ctx.strokeStyle = originalStrokeStyle;
|
|
1276
1685
|
ctx.lineWidth = originalLineWidth;
|
|
@@ -1310,9 +1719,11 @@ var setOverflowHidden = ({
|
|
|
1310
1719
|
// src/drawing/transform.ts
|
|
1311
1720
|
var setTransform = ({
|
|
1312
1721
|
ctx,
|
|
1313
|
-
transform
|
|
1722
|
+
transform,
|
|
1723
|
+
parentRect
|
|
1314
1724
|
}) => {
|
|
1315
|
-
|
|
1725
|
+
const offsetMatrix = new DOMMatrix().translate(-parentRect.x, -parentRect.y).multiply(transform).translate(parentRect.x, parentRect.y);
|
|
1726
|
+
ctx.setTransform(offsetMatrix);
|
|
1316
1727
|
return () => {
|
|
1317
1728
|
ctx.setTransform(new DOMMatrix);
|
|
1318
1729
|
};
|
|
@@ -1325,9 +1736,12 @@ var drawElement = async ({
|
|
|
1325
1736
|
context,
|
|
1326
1737
|
draw,
|
|
1327
1738
|
opacity,
|
|
1328
|
-
totalMatrix
|
|
1739
|
+
totalMatrix,
|
|
1740
|
+
parentRect,
|
|
1741
|
+
logLevel
|
|
1329
1742
|
}) => {
|
|
1330
1743
|
const background = computedStyle.backgroundColor;
|
|
1744
|
+
const { backgroundImage } = computedStyle;
|
|
1331
1745
|
const borderRadius = parseBorderRadius({
|
|
1332
1746
|
borderRadius: computedStyle.borderRadius,
|
|
1333
1747
|
width: rect.width,
|
|
@@ -1335,19 +1749,43 @@ var drawElement = async ({
|
|
|
1335
1749
|
});
|
|
1336
1750
|
const finishTransform = setTransform({
|
|
1337
1751
|
ctx: context,
|
|
1338
|
-
transform: totalMatrix
|
|
1752
|
+
transform: totalMatrix,
|
|
1753
|
+
parentRect
|
|
1339
1754
|
});
|
|
1340
|
-
const
|
|
1755
|
+
const finishOpacity = setOpacity({
|
|
1341
1756
|
ctx: context,
|
|
1757
|
+
opacity
|
|
1758
|
+
});
|
|
1759
|
+
setBoxShadow({
|
|
1760
|
+
ctx: context,
|
|
1761
|
+
computedStyle,
|
|
1342
1762
|
rect,
|
|
1343
1763
|
borderRadius,
|
|
1344
|
-
|
|
1764
|
+
logLevel
|
|
1345
1765
|
});
|
|
1346
|
-
const
|
|
1766
|
+
const finishBorderRadius = setBorderRadius({
|
|
1347
1767
|
ctx: context,
|
|
1348
|
-
|
|
1768
|
+
rect,
|
|
1769
|
+
borderRadius,
|
|
1770
|
+
forceClipEvenWhenZero: false
|
|
1349
1771
|
});
|
|
1350
|
-
|
|
1772
|
+
let gradientDrawn = false;
|
|
1773
|
+
if (backgroundImage && backgroundImage !== "none") {
|
|
1774
|
+
const gradientInfo = parseLinearGradient(backgroundImage);
|
|
1775
|
+
if (gradientInfo) {
|
|
1776
|
+
const gradient = createCanvasGradient({
|
|
1777
|
+
ctx: context,
|
|
1778
|
+
rect,
|
|
1779
|
+
gradientInfo
|
|
1780
|
+
});
|
|
1781
|
+
const originalFillStyle = context.fillStyle;
|
|
1782
|
+
context.fillStyle = gradient;
|
|
1783
|
+
context.fillRect(rect.left, rect.top, rect.width, rect.height);
|
|
1784
|
+
context.fillStyle = originalFillStyle;
|
|
1785
|
+
gradientDrawn = true;
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
if (!gradientDrawn && background && background !== "transparent" && !(background.startsWith("rgba") && (background.endsWith(", 0)") || background.endsWith(",0")))) {
|
|
1351
1789
|
const originalFillStyle = context.fillStyle;
|
|
1352
1790
|
context.fillStyle = background;
|
|
1353
1791
|
context.fillRect(rect.left, rect.top, rect.width, rect.height);
|
|
@@ -1382,9 +1820,6 @@ var drawElement = async ({
|
|
|
1382
1820
|
};
|
|
1383
1821
|
};
|
|
1384
1822
|
|
|
1385
|
-
// src/drawing/handle-3d-transform.ts
|
|
1386
|
-
import { Internals as Internals4 } from "remotion";
|
|
1387
|
-
|
|
1388
1823
|
// src/walk-tree.ts
|
|
1389
1824
|
function skipToNextNonDescendant(treeWalker) {
|
|
1390
1825
|
if (treeWalker.nextSibling()) {
|
|
@@ -1410,10 +1845,23 @@ var getBiggestBoundingClientRect = (element) => {
|
|
|
1410
1845
|
const outlineWidth = parseOutlineWidth(computedStyle.outlineWidth);
|
|
1411
1846
|
const outlineOffset = parseOutlineOffset(computedStyle.outlineOffset);
|
|
1412
1847
|
const rect = treeWalker.currentNode.getBoundingClientRect();
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1848
|
+
const shadows = parseBoxShadow(computedStyle.boxShadow);
|
|
1849
|
+
let shadowLeft = 0;
|
|
1850
|
+
let shadowRight = 0;
|
|
1851
|
+
let shadowTop = 0;
|
|
1852
|
+
let shadowBottom = 0;
|
|
1853
|
+
for (const shadow of shadows) {
|
|
1854
|
+
if (!shadow.inset) {
|
|
1855
|
+
shadowLeft = Math.max(shadowLeft, Math.abs(Math.min(shadow.offsetX, 0)) + shadow.blurRadius);
|
|
1856
|
+
shadowRight = Math.max(shadowRight, Math.max(shadow.offsetX, 0) + shadow.blurRadius);
|
|
1857
|
+
shadowTop = Math.max(shadowTop, Math.abs(Math.min(shadow.offsetY, 0)) + shadow.blurRadius);
|
|
1858
|
+
shadowBottom = Math.max(shadowBottom, Math.max(shadow.offsetY, 0) + shadow.blurRadius);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
mostLeft = Math.min(mostLeft, rect.left - outlineOffset - outlineWidth - shadowLeft);
|
|
1862
|
+
mostTop = Math.min(mostTop, rect.top - outlineOffset - outlineWidth - shadowTop);
|
|
1863
|
+
mostRight = Math.max(mostRight, rect.right + outlineOffset + outlineWidth + shadowRight);
|
|
1864
|
+
mostBottom = Math.max(mostBottom, rect.bottom + outlineOffset + outlineWidth + shadowBottom);
|
|
1417
1865
|
if (computedStyle.overflow === "hidden") {
|
|
1418
1866
|
if (!skipToNextNonDescendant(treeWalker)) {
|
|
1419
1867
|
break;
|
|
@@ -1426,18 +1874,6 @@ var getBiggestBoundingClientRect = (element) => {
|
|
|
1426
1874
|
return new DOMRect(mostLeft, mostTop, mostRight - mostLeft, mostBottom - mostTop);
|
|
1427
1875
|
};
|
|
1428
1876
|
|
|
1429
|
-
// src/drawing/clamp-rect-to-parent-bounds.ts
|
|
1430
|
-
var getNarrowerRect = ({
|
|
1431
|
-
firstRect,
|
|
1432
|
-
secondRect
|
|
1433
|
-
}) => {
|
|
1434
|
-
const left = Math.max(firstRect.left, secondRect.left);
|
|
1435
|
-
const top = Math.max(firstRect.top, secondRect.top);
|
|
1436
|
-
const bottom = Math.min(firstRect.bottom, secondRect.bottom);
|
|
1437
|
-
const right = Math.min(firstRect.right, secondRect.right);
|
|
1438
|
-
return new DOMRect(left, top, right - left, bottom - top);
|
|
1439
|
-
};
|
|
1440
|
-
|
|
1441
1877
|
// src/drawing/get-pretransform-rect.ts
|
|
1442
1878
|
function getPreTransformRect(targetRect, matrix) {
|
|
1443
1879
|
const origin = new DOMPoint(0, 0).matrixTransform(matrix);
|
|
@@ -1454,6 +1890,10 @@ function getPreTransformRect(targetRect, matrix) {
|
|
|
1454
1890
|
origin.y
|
|
1455
1891
|
]);
|
|
1456
1892
|
const inverse2D = effective2D.inverse();
|
|
1893
|
+
const wasNotInvertible = isNaN(inverse2D.m11);
|
|
1894
|
+
if (wasNotInvertible) {
|
|
1895
|
+
return new DOMRect(0, 0, 0, 0);
|
|
1896
|
+
}
|
|
1457
1897
|
const corners = [
|
|
1458
1898
|
new DOMPoint(targetRect.x, targetRect.y),
|
|
1459
1899
|
new DOMPoint(targetRect.x + targetRect.width, targetRect.y),
|
|
@@ -1466,26 +1906,6 @@ function getPreTransformRect(targetRect, matrix) {
|
|
|
1466
1906
|
return new DOMRect(Math.min(...xs), Math.min(...ys), Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));
|
|
1467
1907
|
}
|
|
1468
1908
|
|
|
1469
|
-
// src/drawing/transform-rect-with-matrix.ts
|
|
1470
|
-
function transformDOMRect({
|
|
1471
|
-
rect,
|
|
1472
|
-
matrix
|
|
1473
|
-
}) {
|
|
1474
|
-
const topLeft = new DOMPointReadOnly(rect.left, rect.top);
|
|
1475
|
-
const topRight = new DOMPointReadOnly(rect.right, rect.top);
|
|
1476
|
-
const bottomLeft = new DOMPointReadOnly(rect.left, rect.bottom);
|
|
1477
|
-
const bottomRight = new DOMPointReadOnly(rect.right, rect.bottom);
|
|
1478
|
-
const transformedTopLeft = topLeft.matrixTransform(matrix);
|
|
1479
|
-
const transformedTopRight = topRight.matrixTransform(matrix);
|
|
1480
|
-
const transformedBottomLeft = bottomLeft.matrixTransform(matrix);
|
|
1481
|
-
const transformedBottomRight = bottomRight.matrixTransform(matrix);
|
|
1482
|
-
const minX = Math.min(transformedTopLeft.x / transformedTopLeft.w, transformedTopRight.x / transformedTopRight.w, transformedBottomLeft.x / transformedBottomLeft.w, transformedBottomRight.x / transformedBottomRight.w);
|
|
1483
|
-
const maxX = Math.max(transformedTopLeft.x / transformedTopLeft.w, transformedTopRight.x / transformedTopRight.w, transformedBottomLeft.x / transformedBottomLeft.w, transformedBottomRight.x / transformedBottomRight.w);
|
|
1484
|
-
const minY = Math.min(transformedTopLeft.y / transformedTopLeft.w, transformedTopRight.y / transformedTopRight.w, transformedBottomLeft.y / transformedBottomLeft.w, transformedBottomRight.y / transformedBottomRight.w);
|
|
1485
|
-
const maxY = Math.max(transformedTopLeft.y / transformedTopLeft.w, transformedTopRight.y / transformedTopRight.w, transformedBottomLeft.y / transformedBottomLeft.w, transformedBottomRight.y / transformedBottomRight.w);
|
|
1486
|
-
return new DOMRect(minX, minY, maxX - minX, maxY - minY);
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
1909
|
// src/drawing/transform-in-3d.ts
|
|
1490
1910
|
function compileShader(shaderGl, source, type) {
|
|
1491
1911
|
const shader = shaderGl.createShader(type);
|
|
@@ -1501,24 +1921,14 @@ function compileShader(shaderGl, source, type) {
|
|
|
1501
1921
|
}
|
|
1502
1922
|
return shader;
|
|
1503
1923
|
}
|
|
1504
|
-
var helperCanvas = null;
|
|
1505
1924
|
var createHelperCanvas = ({
|
|
1506
1925
|
canvasWidth,
|
|
1507
1926
|
canvasHeight
|
|
1508
1927
|
}) => {
|
|
1509
|
-
if (helperCanvas && helperCanvas.canvas.width >= canvasWidth && helperCanvas.canvas.height >= canvasHeight) {
|
|
1510
|
-
helperCanvas.gl.clearColor(0, 0, 0, 0);
|
|
1511
|
-
helperCanvas.gl.clear(helperCanvas.gl.COLOR_BUFFER_BIT);
|
|
1512
|
-
return helperCanvas;
|
|
1513
|
-
}
|
|
1514
|
-
if (helperCanvas) {
|
|
1515
|
-
helperCanvas.gl.deleteProgram(helperCanvas.program);
|
|
1516
|
-
helperCanvas.gl.deleteShader(helperCanvas.vertexShader);
|
|
1517
|
-
helperCanvas.gl.deleteShader(helperCanvas.fragmentShader);
|
|
1518
|
-
helperCanvas = null;
|
|
1519
|
-
}
|
|
1520
1928
|
const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
|
|
1521
|
-
const gl = canvas.getContext("webgl"
|
|
1929
|
+
const gl = canvas.getContext("webgl", {
|
|
1930
|
+
premultipliedAlpha: true
|
|
1931
|
+
});
|
|
1522
1932
|
if (!gl) {
|
|
1523
1933
|
throw new Error("WebGL not supported");
|
|
1524
1934
|
}
|
|
@@ -1557,21 +1967,17 @@ var createHelperCanvas = ({
|
|
|
1557
1967
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
1558
1968
|
gl.enable(gl.BLEND);
|
|
1559
1969
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
1560
|
-
|
|
1561
|
-
return helperCanvas;
|
|
1970
|
+
return { canvas, gl, program, vertexShader, fragmentShader };
|
|
1562
1971
|
};
|
|
1563
1972
|
var transformIn3d = ({
|
|
1564
1973
|
matrix,
|
|
1565
1974
|
sourceCanvas,
|
|
1566
|
-
untransformedRect
|
|
1975
|
+
untransformedRect,
|
|
1976
|
+
rectAfterTransforms
|
|
1567
1977
|
}) => {
|
|
1568
|
-
const rectAfterTransforms = transformDOMRect({
|
|
1569
|
-
rect: untransformedRect,
|
|
1570
|
-
matrix
|
|
1571
|
-
});
|
|
1572
1978
|
const { canvas, gl, program } = createHelperCanvas({
|
|
1573
|
-
canvasWidth:
|
|
1574
|
-
canvasHeight:
|
|
1979
|
+
canvasWidth: rectAfterTransforms.width,
|
|
1980
|
+
canvasHeight: rectAfterTransforms.height
|
|
1575
1981
|
});
|
|
1576
1982
|
const vertexBuffer = gl.createBuffer();
|
|
1577
1983
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
@@ -1614,7 +2020,10 @@ var transformIn3d = ({
|
|
|
1614
2020
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
1615
2021
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
1616
2022
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
2023
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
1617
2024
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, sourceCanvas);
|
|
2025
|
+
gl.enable(gl.BLEND);
|
|
2026
|
+
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
1618
2027
|
const transformMatrix = matrix.toFloat32Array();
|
|
1619
2028
|
const zScale = 1e9;
|
|
1620
2029
|
const projectionMatrix = new Float32Array([
|
|
@@ -1642,19 +2051,31 @@ var transformIn3d = ({
|
|
|
1642
2051
|
gl.uniformMatrix4fv(uProjection, false, projectionMatrix);
|
|
1643
2052
|
gl.uniform1i(uTexture, 0);
|
|
1644
2053
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
2054
|
+
gl.disableVertexAttribArray(aPosition);
|
|
2055
|
+
gl.disableVertexAttribArray(aTexCoord);
|
|
1645
2056
|
gl.deleteTexture(texture);
|
|
1646
2057
|
gl.deleteBuffer(vertexBuffer);
|
|
1647
|
-
|
|
2058
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2059
|
+
gl.deleteTexture(texture);
|
|
2060
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
2061
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
2062
|
+
return {
|
|
2063
|
+
canvas,
|
|
2064
|
+
rect: rectAfterTransforms,
|
|
2065
|
+
cleanup: () => {
|
|
2066
|
+
const loseContext = gl.getExtension("WEBGL_lose_context");
|
|
2067
|
+
if (loseContext) {
|
|
2068
|
+
loseContext.loseContext();
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
1648
2072
|
};
|
|
1649
2073
|
|
|
1650
2074
|
// src/drawing/handle-3d-transform.ts
|
|
1651
|
-
var
|
|
2075
|
+
var getPrecomposeRectFor3DTransform = ({
|
|
1652
2076
|
element,
|
|
1653
|
-
matrix,
|
|
1654
2077
|
parentRect,
|
|
1655
|
-
|
|
1656
|
-
logLevel,
|
|
1657
|
-
internalState
|
|
2078
|
+
matrix
|
|
1658
2079
|
}) => {
|
|
1659
2080
|
const unclampedBiggestBoundingClientRect = getBiggestBoundingClientRect(element);
|
|
1660
2081
|
const biggestPossiblePretransformRect = getPreTransformRect(parentRect, matrix);
|
|
@@ -1662,33 +2083,93 @@ var handle3dTransform = async ({
|
|
|
1662
2083
|
firstRect: unclampedBiggestBoundingClientRect,
|
|
1663
2084
|
secondRect: biggestPossiblePretransformRect
|
|
1664
2085
|
});
|
|
1665
|
-
|
|
1666
|
-
|
|
2086
|
+
return preTransformRect;
|
|
2087
|
+
};
|
|
2088
|
+
var handle3dTransform = ({
|
|
2089
|
+
matrix,
|
|
2090
|
+
precomposeRect,
|
|
2091
|
+
tempCanvas,
|
|
2092
|
+
rectAfterTransforms
|
|
2093
|
+
}) => {
|
|
2094
|
+
const {
|
|
2095
|
+
canvas: transformed,
|
|
2096
|
+
rect: transformedRect,
|
|
2097
|
+
cleanup
|
|
2098
|
+
} = transformIn3d({
|
|
2099
|
+
untransformedRect: precomposeRect,
|
|
2100
|
+
matrix,
|
|
2101
|
+
sourceCanvas: tempCanvas,
|
|
2102
|
+
rectAfterTransforms
|
|
2103
|
+
});
|
|
2104
|
+
if (transformedRect.width <= 0 || transformedRect.height <= 0) {
|
|
2105
|
+
return null;
|
|
2106
|
+
}
|
|
2107
|
+
return [transformed, cleanup];
|
|
2108
|
+
};
|
|
2109
|
+
|
|
2110
|
+
// src/drawing/handle-mask.ts
|
|
2111
|
+
var getPrecomposeRectForMask = (element) => {
|
|
2112
|
+
const boundingRect = getBiggestBoundingClientRect(element);
|
|
2113
|
+
return boundingRect;
|
|
2114
|
+
};
|
|
2115
|
+
var handleMask = ({
|
|
2116
|
+
gradientInfo,
|
|
2117
|
+
rect,
|
|
2118
|
+
precomposeRect,
|
|
2119
|
+
tempContext
|
|
2120
|
+
}) => {
|
|
2121
|
+
const rectOffsetX = rect.left - precomposeRect.left;
|
|
2122
|
+
const rectOffsetY = rect.top - precomposeRect.top;
|
|
2123
|
+
const rectToFill = new DOMRect(rectOffsetX, rectOffsetY, rect.width, rect.height);
|
|
2124
|
+
const gradient = createCanvasGradient({
|
|
2125
|
+
ctx: tempContext,
|
|
2126
|
+
rect: rectToFill,
|
|
2127
|
+
gradientInfo
|
|
2128
|
+
});
|
|
2129
|
+
tempContext.globalCompositeOperation = "destination-in";
|
|
2130
|
+
tempContext.fillStyle = gradient;
|
|
2131
|
+
tempContext.fillRect(rectToFill.left, rectToFill.top, rectToFill.width, rectToFill.height);
|
|
2132
|
+
};
|
|
2133
|
+
|
|
2134
|
+
// src/drawing/precompose.ts
|
|
2135
|
+
var precomposeDOMElement = async ({
|
|
2136
|
+
boundingRect,
|
|
2137
|
+
element,
|
|
2138
|
+
logLevel,
|
|
2139
|
+
internalState
|
|
2140
|
+
}) => {
|
|
2141
|
+
const tempCanvas = new OffscreenCanvas(boundingRect.width, boundingRect.height);
|
|
2142
|
+
const tempContext = tempCanvas.getContext("2d");
|
|
1667
2143
|
await compose({
|
|
1668
2144
|
element,
|
|
1669
|
-
context:
|
|
2145
|
+
context: tempContext,
|
|
1670
2146
|
logLevel,
|
|
1671
|
-
parentRect:
|
|
2147
|
+
parentRect: boundingRect,
|
|
1672
2148
|
internalState
|
|
1673
2149
|
});
|
|
1674
|
-
|
|
1675
|
-
const { canvas: transformed, rect: transformedRect } = transformIn3d({
|
|
1676
|
-
untransformedRect: preTransformRect,
|
|
1677
|
-
matrix,
|
|
1678
|
-
sourceCanvas: tempCanvas
|
|
1679
|
-
});
|
|
1680
|
-
context.drawImage(transformed, transformedRect.x, transformedRect.y);
|
|
1681
|
-
const afterDraw = Date.now();
|
|
1682
|
-
Internals4.Log.trace({
|
|
1683
|
-
logLevel,
|
|
1684
|
-
tag: "@remotion/web-renderer"
|
|
1685
|
-
}, `Transforming element in 3D - canvas size: ${transformedRect.width}x${transformedRect.height} - compose: ${afterCompose - start}ms - draw: ${afterDraw - afterCompose}ms`);
|
|
1686
|
-
internalState.add3DTransform({
|
|
1687
|
-
canvasWidth: Math.ceil(transformedRect.width),
|
|
1688
|
-
canvasHeight: Math.ceil(transformedRect.height)
|
|
1689
|
-
});
|
|
2150
|
+
return { tempCanvas, tempContext };
|
|
1690
2151
|
};
|
|
1691
2152
|
|
|
2153
|
+
// src/drawing/transform-rect-with-matrix.ts
|
|
2154
|
+
function transformDOMRect({
|
|
2155
|
+
rect,
|
|
2156
|
+
matrix
|
|
2157
|
+
}) {
|
|
2158
|
+
const topLeft = new DOMPointReadOnly(rect.left, rect.top);
|
|
2159
|
+
const topRight = new DOMPointReadOnly(rect.right, rect.top);
|
|
2160
|
+
const bottomLeft = new DOMPointReadOnly(rect.left, rect.bottom);
|
|
2161
|
+
const bottomRight = new DOMPointReadOnly(rect.right, rect.bottom);
|
|
2162
|
+
const transformedTopLeft = topLeft.matrixTransform(matrix);
|
|
2163
|
+
const transformedTopRight = topRight.matrixTransform(matrix);
|
|
2164
|
+
const transformedBottomLeft = bottomLeft.matrixTransform(matrix);
|
|
2165
|
+
const transformedBottomRight = bottomRight.matrixTransform(matrix);
|
|
2166
|
+
const minX = Math.min(transformedTopLeft.x / transformedTopLeft.w, transformedTopRight.x / transformedTopRight.w, transformedBottomLeft.x / transformedBottomLeft.w, transformedBottomRight.x / transformedBottomRight.w);
|
|
2167
|
+
const maxX = Math.max(transformedTopLeft.x / transformedTopLeft.w, transformedTopRight.x / transformedTopRight.w, transformedBottomLeft.x / transformedBottomLeft.w, transformedBottomRight.x / transformedBottomRight.w);
|
|
2168
|
+
const minY = Math.min(transformedTopLeft.y / transformedTopLeft.w, transformedTopRight.y / transformedTopRight.w, transformedBottomLeft.y / transformedBottomLeft.w, transformedBottomRight.y / transformedBottomRight.w);
|
|
2169
|
+
const maxY = Math.max(transformedTopLeft.y / transformedTopLeft.w, transformedTopRight.y / transformedTopRight.w, transformedBottomLeft.y / transformedBottomLeft.w, transformedBottomRight.y / transformedBottomRight.w);
|
|
2170
|
+
return new DOMRect(minX, minY, maxX - minX, maxY - minY);
|
|
2171
|
+
}
|
|
2172
|
+
|
|
1692
2173
|
// src/drawing/process-node.ts
|
|
1693
2174
|
var processNode = async ({
|
|
1694
2175
|
element,
|
|
@@ -1696,48 +2177,124 @@ var processNode = async ({
|
|
|
1696
2177
|
draw,
|
|
1697
2178
|
logLevel,
|
|
1698
2179
|
parentRect,
|
|
1699
|
-
internalState
|
|
2180
|
+
internalState,
|
|
2181
|
+
rootElement
|
|
1700
2182
|
}) => {
|
|
1701
|
-
const
|
|
2183
|
+
const {
|
|
2184
|
+
totalMatrix,
|
|
2185
|
+
reset,
|
|
2186
|
+
dimensions,
|
|
2187
|
+
opacity,
|
|
2188
|
+
computedStyle,
|
|
2189
|
+
precompositing
|
|
2190
|
+
} = calculateTransforms({
|
|
1702
2191
|
element,
|
|
1703
|
-
|
|
1704
|
-
offsetTop: parentRect.y
|
|
2192
|
+
rootElement
|
|
1705
2193
|
});
|
|
1706
|
-
const { totalMatrix, reset, dimensions, opacity, computedStyle } = transforms;
|
|
1707
2194
|
if (opacity === 0) {
|
|
1708
2195
|
reset();
|
|
1709
|
-
return { type: "
|
|
2196
|
+
return { type: "skip-children" };
|
|
1710
2197
|
}
|
|
1711
2198
|
if (dimensions.width <= 0 || dimensions.height <= 0) {
|
|
1712
2199
|
reset();
|
|
1713
|
-
return { type: "continue", cleanupAfterChildren:
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
|
|
2200
|
+
return { type: "continue", cleanupAfterChildren: null };
|
|
2201
|
+
}
|
|
2202
|
+
const rect = new DOMRect(dimensions.left - parentRect.x, dimensions.top - parentRect.y, dimensions.width, dimensions.height);
|
|
2203
|
+
if (precompositing.needsPrecompositing) {
|
|
2204
|
+
const start = Date.now();
|
|
2205
|
+
let precomposeRect = null;
|
|
2206
|
+
if (precompositing.needsMaskImage) {
|
|
2207
|
+
precomposeRect = getWiderRectAndExpand({
|
|
2208
|
+
firstRect: precomposeRect,
|
|
2209
|
+
secondRect: getPrecomposeRectForMask(element)
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
if (precompositing.needs3DTransformViaWebGL) {
|
|
2213
|
+
precomposeRect = getWiderRectAndExpand({
|
|
2214
|
+
firstRect: precomposeRect,
|
|
2215
|
+
secondRect: getPrecomposeRectFor3DTransform({
|
|
2216
|
+
element,
|
|
2217
|
+
parentRect,
|
|
2218
|
+
matrix: totalMatrix
|
|
2219
|
+
})
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
if (!precomposeRect) {
|
|
2223
|
+
throw new Error("Precompose rect not found");
|
|
2224
|
+
}
|
|
2225
|
+
if (precomposeRect.width <= 0 || precomposeRect.height <= 0) {
|
|
2226
|
+
return { type: "continue", cleanupAfterChildren: null };
|
|
2227
|
+
}
|
|
2228
|
+
if (!doRectsIntersect(precomposeRect, parentRect)) {
|
|
2229
|
+
return { type: "continue", cleanupAfterChildren: null };
|
|
2230
|
+
}
|
|
2231
|
+
const { tempCanvas, tempContext } = await precomposeDOMElement({
|
|
2232
|
+
boundingRect: precomposeRect,
|
|
1717
2233
|
element,
|
|
1718
|
-
matrix: totalMatrix,
|
|
1719
|
-
parentRect,
|
|
1720
|
-
context,
|
|
1721
2234
|
logLevel,
|
|
1722
2235
|
internalState
|
|
1723
2236
|
});
|
|
2237
|
+
let drawable = tempCanvas;
|
|
2238
|
+
let cleanupWebGL = () => {};
|
|
2239
|
+
const rectAfterTransforms = roundToExpandRect(transformDOMRect({
|
|
2240
|
+
rect: precomposeRect,
|
|
2241
|
+
matrix: totalMatrix
|
|
2242
|
+
}));
|
|
2243
|
+
if (precompositing.needsMaskImage) {
|
|
2244
|
+
handleMask({
|
|
2245
|
+
gradientInfo: precompositing.needsMaskImage,
|
|
2246
|
+
rect,
|
|
2247
|
+
precomposeRect,
|
|
2248
|
+
tempContext
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
if (precompositing.needs3DTransformViaWebGL) {
|
|
2252
|
+
const t = handle3dTransform({
|
|
2253
|
+
matrix: totalMatrix,
|
|
2254
|
+
precomposeRect,
|
|
2255
|
+
tempCanvas: drawable,
|
|
2256
|
+
rectAfterTransforms
|
|
2257
|
+
});
|
|
2258
|
+
if (t) {
|
|
2259
|
+
const [transformed, cleanup] = t;
|
|
2260
|
+
drawable = transformed;
|
|
2261
|
+
cleanupWebGL = cleanup;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
const previousTransform = context.getTransform();
|
|
2265
|
+
if (drawable) {
|
|
2266
|
+
context.setTransform(new DOMMatrix);
|
|
2267
|
+
context.drawImage(drawable, rectAfterTransforms.left - parentRect.x, rectAfterTransforms.top - parentRect.y, rectAfterTransforms.width, rectAfterTransforms.height);
|
|
2268
|
+
context.setTransform(previousTransform);
|
|
2269
|
+
Internals5.Log.trace({
|
|
2270
|
+
logLevel,
|
|
2271
|
+
tag: "@remotion/web-renderer"
|
|
2272
|
+
}, `Transforming element in 3D - canvas size: ${precomposeRect.width}x${precomposeRect.height} - compose: ${Date.now() - start}ms`);
|
|
2273
|
+
internalState.addPrecompose({
|
|
2274
|
+
canvasWidth: precomposeRect.width,
|
|
2275
|
+
canvasHeight: precomposeRect.height
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
1724
2278
|
reset();
|
|
2279
|
+
cleanupWebGL();
|
|
1725
2280
|
return { type: "skip-children" };
|
|
1726
2281
|
}
|
|
1727
2282
|
const { cleanupAfterChildren } = await drawElement({
|
|
1728
|
-
rect
|
|
2283
|
+
rect,
|
|
1729
2284
|
computedStyle,
|
|
1730
2285
|
context,
|
|
1731
2286
|
draw,
|
|
1732
2287
|
opacity,
|
|
1733
|
-
totalMatrix
|
|
2288
|
+
totalMatrix,
|
|
2289
|
+
parentRect,
|
|
2290
|
+
logLevel
|
|
1734
2291
|
});
|
|
1735
2292
|
reset();
|
|
1736
2293
|
return { type: "continue", cleanupAfterChildren };
|
|
1737
2294
|
};
|
|
1738
2295
|
|
|
1739
2296
|
// src/drawing/text/draw-text.ts
|
|
1740
|
-
import { Internals as
|
|
2297
|
+
import { Internals as Internals6 } from "remotion";
|
|
1741
2298
|
|
|
1742
2299
|
// src/drawing/text/apply-text-transform.ts
|
|
1743
2300
|
var applyTextTransform = (text, transform) => {
|
|
@@ -1827,7 +2384,7 @@ function findLineBreaks(span, rtl) {
|
|
|
1827
2384
|
const shouldCollapse = !computedStyle.whiteSpaceCollapse.includes("preserve");
|
|
1828
2385
|
lines.push({
|
|
1829
2386
|
text: shouldCollapse ? currentLine.trim() : currentLine,
|
|
1830
|
-
|
|
2387
|
+
height: currentHeight - previousRect.height,
|
|
1831
2388
|
offsetHorizontal
|
|
1832
2389
|
});
|
|
1833
2390
|
currentLine = wordsToAdd;
|
|
@@ -1843,7 +2400,7 @@ function findLineBreaks(span, rtl) {
|
|
|
1843
2400
|
const offsetHorizontal = rtl ? lastRect.right - originalRect.right : lastRect.left - originalRect.left;
|
|
1844
2401
|
lines.push({
|
|
1845
2402
|
text: currentLine,
|
|
1846
|
-
|
|
2403
|
+
height: rect.height - lines.reduce((acc, curr) => acc + curr.height, 0),
|
|
1847
2404
|
offsetHorizontal
|
|
1848
2405
|
});
|
|
1849
2406
|
}
|
|
@@ -1852,7 +2409,10 @@ function findLineBreaks(span, rtl) {
|
|
|
1852
2409
|
}
|
|
1853
2410
|
|
|
1854
2411
|
// src/drawing/text/draw-text.ts
|
|
1855
|
-
var drawText = (
|
|
2412
|
+
var drawText = ({
|
|
2413
|
+
span,
|
|
2414
|
+
logLevel
|
|
2415
|
+
}) => {
|
|
1856
2416
|
const drawFn = ({ dimensions: rect, computedStyle, contextToDraw }) => {
|
|
1857
2417
|
const {
|
|
1858
2418
|
fontFamily,
|
|
@@ -1866,8 +2426,8 @@ var drawText = (span) => {
|
|
|
1866
2426
|
} = computedStyle;
|
|
1867
2427
|
const isVertical = writingMode !== "horizontal-tb";
|
|
1868
2428
|
if (isVertical) {
|
|
1869
|
-
|
|
1870
|
-
logLevel
|
|
2429
|
+
Internals6.Log.warn({
|
|
2430
|
+
logLevel,
|
|
1871
2431
|
tag: "@remotion/web-renderer"
|
|
1872
2432
|
}, 'Detected "writing-mode" CSS property. Vertical text is not yet supported in @remotion/web-renderer');
|
|
1873
2433
|
return;
|
|
@@ -1887,10 +2447,14 @@ var drawText = (span) => {
|
|
|
1887
2447
|
const xPosition = isRTL ? rect.right : rect.left;
|
|
1888
2448
|
const lines = findLineBreaks(span, isRTL);
|
|
1889
2449
|
let offsetTop = 0;
|
|
1890
|
-
const
|
|
2450
|
+
const measurements = contextToDraw.measureText(lines[0].text);
|
|
2451
|
+
const { fontBoundingBoxDescent, fontBoundingBoxAscent } = measurements;
|
|
2452
|
+
const fontHeight = fontBoundingBoxAscent + fontBoundingBoxDescent;
|
|
1891
2453
|
for (const line of lines) {
|
|
1892
|
-
|
|
1893
|
-
|
|
2454
|
+
const leading = line.height - fontHeight;
|
|
2455
|
+
const halfLeading = leading / 2;
|
|
2456
|
+
contextToDraw.fillText(line.text, xPosition + line.offsetHorizontal, rect.top + halfLeading + fontBoundingBoxAscent + offsetTop);
|
|
2457
|
+
offsetTop += line.height;
|
|
1894
2458
|
}
|
|
1895
2459
|
span.textContent = originalText;
|
|
1896
2460
|
contextToDraw.restore();
|
|
@@ -1904,7 +2468,8 @@ var handleTextNode = async ({
|
|
|
1904
2468
|
context,
|
|
1905
2469
|
logLevel,
|
|
1906
2470
|
parentRect,
|
|
1907
|
-
internalState
|
|
2471
|
+
internalState,
|
|
2472
|
+
rootElement
|
|
1908
2473
|
}) => {
|
|
1909
2474
|
const span = document.createElement("span");
|
|
1910
2475
|
const parent = node.parentNode;
|
|
@@ -1916,10 +2481,11 @@ var handleTextNode = async ({
|
|
|
1916
2481
|
const value = await processNode({
|
|
1917
2482
|
context,
|
|
1918
2483
|
element: span,
|
|
1919
|
-
draw: drawText(span),
|
|
2484
|
+
draw: drawText({ span, logLevel }),
|
|
1920
2485
|
logLevel,
|
|
1921
2486
|
parentRect,
|
|
1922
|
-
internalState
|
|
2487
|
+
internalState,
|
|
2488
|
+
rootElement
|
|
1923
2489
|
});
|
|
1924
2490
|
parent.insertBefore(node, span);
|
|
1925
2491
|
parent.removeChild(span);
|
|
@@ -1932,7 +2498,8 @@ var walkOverNode = ({
|
|
|
1932
2498
|
context,
|
|
1933
2499
|
logLevel,
|
|
1934
2500
|
parentRect,
|
|
1935
|
-
internalState
|
|
2501
|
+
internalState,
|
|
2502
|
+
rootElement
|
|
1936
2503
|
}) => {
|
|
1937
2504
|
if (node instanceof HTMLElement || node instanceof SVGElement) {
|
|
1938
2505
|
return processNode({
|
|
@@ -1941,7 +2508,8 @@ var walkOverNode = ({
|
|
|
1941
2508
|
draw: drawDomElement(node),
|
|
1942
2509
|
logLevel,
|
|
1943
2510
|
parentRect,
|
|
1944
|
-
internalState
|
|
2511
|
+
internalState,
|
|
2512
|
+
rootElement
|
|
1945
2513
|
});
|
|
1946
2514
|
}
|
|
1947
2515
|
if (node instanceof Text) {
|
|
@@ -1950,7 +2518,8 @@ var walkOverNode = ({
|
|
|
1950
2518
|
context,
|
|
1951
2519
|
logLevel,
|
|
1952
2520
|
parentRect,
|
|
1953
|
-
internalState
|
|
2521
|
+
internalState,
|
|
2522
|
+
rootElement
|
|
1954
2523
|
});
|
|
1955
2524
|
}
|
|
1956
2525
|
throw new Error("Unknown node type");
|
|
@@ -1988,17 +2557,20 @@ var compose = async ({
|
|
|
1988
2557
|
context,
|
|
1989
2558
|
logLevel,
|
|
1990
2559
|
parentRect,
|
|
1991
|
-
internalState
|
|
2560
|
+
internalState,
|
|
2561
|
+
rootElement: element
|
|
1992
2562
|
});
|
|
1993
2563
|
if (val.type === "skip-children") {
|
|
1994
2564
|
if (!skipToNextNonDescendant(treeWalker)) {
|
|
1995
2565
|
break;
|
|
1996
2566
|
}
|
|
1997
2567
|
} else {
|
|
1998
|
-
cleanupAfterChildren
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2568
|
+
if (val.cleanupAfterChildren) {
|
|
2569
|
+
cleanupAfterChildren.unshift({
|
|
2570
|
+
element: treeWalker.currentNode,
|
|
2571
|
+
cleanupFn: val.cleanupAfterChildren
|
|
2572
|
+
});
|
|
2573
|
+
}
|
|
2002
2574
|
if (!treeWalker.nextNode()) {
|
|
2003
2575
|
break;
|
|
2004
2576
|
}
|
|
@@ -2215,7 +2787,8 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2215
2787
|
onArtifact,
|
|
2216
2788
|
onFrame,
|
|
2217
2789
|
outputTarget: userDesiredOutputTarget,
|
|
2218
|
-
licenseKey
|
|
2790
|
+
licenseKey,
|
|
2791
|
+
muted
|
|
2219
2792
|
}) => {
|
|
2220
2793
|
const outputTarget = userDesiredOutputTarget === null ? await canUseWebFsWriter() ? "web-fs" : "arraybuffer" : userDesiredOutputTarget;
|
|
2221
2794
|
if (outputTarget === "web-fs") {
|
|
@@ -2226,7 +2799,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2226
2799
|
if (codec && !format.getSupportedCodecs().includes(codecToMediabunnyCodec(codec))) {
|
|
2227
2800
|
return Promise.reject(new Error(`Codec ${codec} is not supported for container ${container}`));
|
|
2228
2801
|
}
|
|
2229
|
-
const resolved = await
|
|
2802
|
+
const resolved = await Internals7.resolveVideoConfig({
|
|
2230
2803
|
calculateMetadata: composition.calculateMetadata ?? null,
|
|
2231
2804
|
signal: signal ?? new AbortController().signal,
|
|
2232
2805
|
defaultProps: composition.defaultProps ?? {},
|
|
@@ -2253,7 +2826,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2253
2826
|
logLevel,
|
|
2254
2827
|
mediaCacheSizeInBytes,
|
|
2255
2828
|
schema: schema ?? null,
|
|
2256
|
-
audioEnabled:
|
|
2829
|
+
audioEnabled: !muted,
|
|
2257
2830
|
videoEnabled: true,
|
|
2258
2831
|
initialFrame: 0,
|
|
2259
2832
|
defaultCodec: resolved.defaultCodec,
|
|
@@ -2302,15 +2875,18 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2302
2875
|
videoSampleSource.close();
|
|
2303
2876
|
});
|
|
2304
2877
|
output.addVideoTrack(videoSampleSource);
|
|
2305
|
-
|
|
2306
|
-
if (!
|
|
2307
|
-
|
|
2878
|
+
let audioSampleSource = null;
|
|
2879
|
+
if (!muted) {
|
|
2880
|
+
const defaultAudioEncodingConfig = await getDefaultAudioEncodingConfig();
|
|
2881
|
+
if (!defaultAudioEncodingConfig) {
|
|
2882
|
+
return Promise.reject(new Error("No default audio encoding config found"));
|
|
2883
|
+
}
|
|
2884
|
+
audioSampleSource = new AudioSampleSource(defaultAudioEncodingConfig);
|
|
2885
|
+
cleanupFns.push(() => {
|
|
2886
|
+
audioSampleSource?.close();
|
|
2887
|
+
});
|
|
2888
|
+
output.addAudioTrack(audioSampleSource);
|
|
2308
2889
|
}
|
|
2309
|
-
const audioSampleSource = new AudioSampleSource(defaultAudioEncodingConfig);
|
|
2310
|
-
cleanupFns.push(() => {
|
|
2311
|
-
audioSampleSource.close();
|
|
2312
|
-
});
|
|
2313
|
-
output.addAudioTrack(audioSampleSource);
|
|
2314
2890
|
await output.start();
|
|
2315
2891
|
if (signal?.aborted) {
|
|
2316
2892
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
@@ -2356,7 +2932,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2356
2932
|
if (signal?.aborted) {
|
|
2357
2933
|
throw new Error("renderMediaOnWeb() was cancelled");
|
|
2358
2934
|
}
|
|
2359
|
-
const audio = onlyInlineAudio({ assets, fps: resolved.fps, frame });
|
|
2935
|
+
const audio = muted ? null : onlyInlineAudio({ assets, fps: resolved.fps, frame });
|
|
2360
2936
|
const timestamp = Math.round((frame - realFrameRange[0]) / resolved.fps * 1e6);
|
|
2361
2937
|
const videoFrame = new VideoFrame(imageData, {
|
|
2362
2938
|
timestamp
|
|
@@ -2379,7 +2955,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2379
2955
|
}
|
|
2380
2956
|
await Promise.all([
|
|
2381
2957
|
addVideoSampleAndCloseFrame(frameToEncode, videoSampleSource),
|
|
2382
|
-
audio ? addAudioSample(audio, audioSampleSource) : Promise.resolve()
|
|
2958
|
+
audio && audioSampleSource ? addAudioSample(audio, audioSampleSource) : Promise.resolve()
|
|
2383
2959
|
]);
|
|
2384
2960
|
progress.encodedFrames++;
|
|
2385
2961
|
throttledOnProgress?.({ ...progress });
|
|
@@ -2389,7 +2965,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2389
2965
|
}
|
|
2390
2966
|
onProgress?.({ ...progress });
|
|
2391
2967
|
videoSampleSource.close();
|
|
2392
|
-
audioSampleSource
|
|
2968
|
+
audioSampleSource?.close();
|
|
2393
2969
|
await output.finalize();
|
|
2394
2970
|
const mimeType = getMimeType(container);
|
|
2395
2971
|
if (webFsTarget) {
|
|
@@ -2424,7 +3000,7 @@ var internalRenderMediaOnWeb = async ({
|
|
|
2424
3000
|
licenseKey: licenseKey ?? null,
|
|
2425
3001
|
apiName: "renderMediaOnWeb"
|
|
2426
3002
|
}).catch((err2) => {
|
|
2427
|
-
|
|
3003
|
+
Internals7.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
|
|
2428
3004
|
});
|
|
2429
3005
|
throw err;
|
|
2430
3006
|
} finally {
|
|
@@ -2452,13 +3028,14 @@ var renderMediaOnWeb = (options) => {
|
|
|
2452
3028
|
onArtifact: options.onArtifact ?? null,
|
|
2453
3029
|
onFrame: options.onFrame ?? null,
|
|
2454
3030
|
outputTarget: options.outputTarget ?? null,
|
|
2455
|
-
licenseKey: options.licenseKey ?? undefined
|
|
3031
|
+
licenseKey: options.licenseKey ?? undefined,
|
|
3032
|
+
muted: options.muted ?? false
|
|
2456
3033
|
}));
|
|
2457
3034
|
return onlyOneRenderAtATimeQueue.ref;
|
|
2458
3035
|
};
|
|
2459
3036
|
// src/render-still-on-web.tsx
|
|
2460
3037
|
import {
|
|
2461
|
-
Internals as
|
|
3038
|
+
Internals as Internals8
|
|
2462
3039
|
} from "remotion";
|
|
2463
3040
|
async function internalRenderStillOnWeb({
|
|
2464
3041
|
frame,
|
|
@@ -2473,7 +3050,7 @@ async function internalRenderStillOnWeb({
|
|
|
2473
3050
|
onArtifact,
|
|
2474
3051
|
licenseKey
|
|
2475
3052
|
}) {
|
|
2476
|
-
const resolved = await
|
|
3053
|
+
const resolved = await Internals8.resolveVideoConfig({
|
|
2477
3054
|
calculateMetadata: composition.calculateMetadata ?? null,
|
|
2478
3055
|
signal: signal ?? new AbortController().signal,
|
|
2479
3056
|
defaultProps: composition.defaultProps ?? {},
|
|
@@ -2544,7 +3121,7 @@ async function internalRenderStillOnWeb({
|
|
|
2544
3121
|
licenseKey: licenseKey ?? null,
|
|
2545
3122
|
apiName: "renderStillOnWeb"
|
|
2546
3123
|
}).catch((err2) => {
|
|
2547
|
-
|
|
3124
|
+
Internals8.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
|
|
2548
3125
|
});
|
|
2549
3126
|
throw err;
|
|
2550
3127
|
} finally {
|