@remotion/web-renderer 4.0.394 → 4.0.396

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/border-radius.d.ts +31 -0
  2. package/dist/border-radius.js +152 -0
  3. package/dist/calculate-transforms.d.ts +2 -0
  4. package/dist/calculate-transforms.js +17 -0
  5. package/dist/composable.d.ts +2 -8
  6. package/dist/compose-canvas.js +28 -4
  7. package/dist/compose.d.ts +6 -3
  8. package/dist/compose.js +41 -12
  9. package/dist/drawing/border-radius.d.ts +3 -5
  10. package/dist/drawing/border-radius.js +12 -11
  11. package/dist/drawing/calculate-transforms.d.ts +6 -2
  12. package/dist/drawing/calculate-transforms.js +19 -22
  13. package/dist/drawing/canvas-offset-from-rect.d.ts +8 -0
  14. package/dist/drawing/canvas-offset-from-rect.js +12 -0
  15. package/dist/drawing/clamp-rect-to-parent-bounds.d.ts +4 -0
  16. package/dist/drawing/clamp-rect-to-parent-bounds.js +7 -0
  17. package/dist/drawing/compose-canvas.d.ts +1 -0
  18. package/dist/drawing/compose-canvas.js +36 -0
  19. package/dist/drawing/compose-svg.d.ts +1 -0
  20. package/dist/drawing/compose-svg.js +34 -0
  21. package/dist/drawing/compose.d.ts +5 -0
  22. package/dist/drawing/compose.js +6 -0
  23. package/dist/drawing/draw-border.d.ts +2 -5
  24. package/dist/drawing/draw-border.js +307 -55
  25. package/dist/drawing/draw-element-to-canvas.d.ts +4 -1
  26. package/dist/drawing/draw-element-to-canvas.js +9 -26
  27. package/dist/drawing/draw-element.d.ts +5 -3
  28. package/dist/drawing/draw-element.js +29 -14
  29. package/dist/drawing/draw-outline.d.ts +9 -0
  30. package/dist/drawing/draw-outline.js +116 -0
  31. package/dist/drawing/get-bounding-box-including-shadow.d.ts +1 -0
  32. package/dist/drawing/get-bounding-box-including-shadow.js +6 -0
  33. package/dist/drawing/get-computed-style-cache.d.ts +0 -0
  34. package/dist/drawing/get-computed-style-cache.js +1 -0
  35. package/dist/drawing/get-pretransform-rect.d.ts +1 -0
  36. package/dist/drawing/get-pretransform-rect.js +31 -0
  37. package/dist/drawing/handle-3d-transform.d.ts +10 -0
  38. package/dist/drawing/handle-3d-transform.js +39 -0
  39. package/dist/drawing/has-transform.d.ts +4 -0
  40. package/dist/drawing/has-transform.js +14 -0
  41. package/dist/drawing/overflow.d.ts +7 -0
  42. package/dist/drawing/overflow.js +12 -0
  43. package/dist/drawing/process-node.d.ts +17 -0
  44. package/dist/drawing/process-node.js +41 -0
  45. package/dist/drawing/text/draw-text.js +6 -8
  46. package/dist/drawing/text/handle-text-node.d.ts +8 -5
  47. package/dist/drawing/text/handle-text-node.js +6 -5
  48. package/dist/drawing/transform-in-3d.d.ts +7 -7
  49. package/dist/drawing/transform-in-3d.js +27 -13
  50. package/dist/drawing/transform-rect-with-matrix.d.ts +4 -0
  51. package/dist/drawing/transform-rect-with-matrix.js +19 -0
  52. package/dist/drawing/turn-svg-into-drawable.js +7 -0
  53. package/dist/esm/index.mjs +897 -205
  54. package/dist/find-canvas-elements.d.ts +1 -0
  55. package/dist/find-canvas-elements.js +13 -0
  56. package/dist/find-capturable-elements.d.ts +1 -1
  57. package/dist/find-capturable-elements.js +20 -22
  58. package/dist/get-biggest-bounding-client-rect.js +18 -5
  59. package/dist/internal-state.d.ts +9 -0
  60. package/dist/internal-state.js +12 -0
  61. package/dist/opacity.d.ts +4 -0
  62. package/dist/opacity.js +7 -0
  63. package/dist/render-media-on-web.d.ts +3 -0
  64. package/dist/render-media-on-web.js +38 -15
  65. package/dist/render-still-on-web.d.ts +6 -1
  66. package/dist/render-still-on-web.js +29 -8
  67. package/dist/send-telemetry-event.js +1 -1
  68. package/dist/take-screenshot.d.ts +8 -2
  69. package/dist/take-screenshot.js +16 -4
  70. package/dist/transform.d.ts +4 -0
  71. package/dist/transform.js +6 -0
  72. package/package.json +7 -6
@@ -6,7 +6,7 @@ import {
6
6
  StreamTarget,
7
7
  VideoSampleSource
8
8
  } from "mediabunny";
9
- import { Internals as Internals4 } from "remotion";
9
+ import { Internals as Internals6 } from "remotion";
10
10
 
11
11
  // src/add-sample.ts
12
12
  import { AudioSample, VideoSample } from "mediabunny";
@@ -382,6 +382,23 @@ var getDefaultAudioEncodingConfig = async () => {
382
382
  return null;
383
383
  };
384
384
 
385
+ // src/internal-state.ts
386
+ var makeInternalState = () => {
387
+ let drawn3dPixels = 0;
388
+ let drawn3dTextures = 0;
389
+ return {
390
+ getDrawn3dPixels: () => drawn3dPixels,
391
+ getDrawn3dTextures: () => drawn3dTextures,
392
+ add3DTransform: ({
393
+ canvasWidth,
394
+ canvasHeight
395
+ }) => {
396
+ drawn3dPixels += canvasWidth * canvasHeight;
397
+ drawn3dTextures++;
398
+ }
399
+ };
400
+ };
401
+
385
402
  // src/mediabunny-mappings.ts
386
403
  import {
387
404
  Mp4OutputFormat,
@@ -460,20 +477,95 @@ var onlyOneRenderAtATimeQueue = {
460
477
  ref: Promise.resolve()
461
478
  };
462
479
 
480
+ // ../licensing/dist/esm/index.mjs
481
+ var HOST = "https://www.remotion.pro";
482
+ var registerUsageEvent = async ({
483
+ apiKey,
484
+ host,
485
+ succeeded,
486
+ event
487
+ }) => {
488
+ const abortController = new AbortController;
489
+ const timeout = setTimeout(() => {
490
+ abortController.abort();
491
+ }, 1e4);
492
+ try {
493
+ const res = await fetch(`${HOST}/api/track/register-usage-point`, {
494
+ method: "POST",
495
+ body: JSON.stringify({
496
+ event,
497
+ apiKey,
498
+ host,
499
+ succeeded
500
+ }),
501
+ headers: {
502
+ "Content-Type": "application/json"
503
+ },
504
+ signal: abortController.signal
505
+ });
506
+ clearTimeout(timeout);
507
+ const json = await res.json();
508
+ if (json.success) {
509
+ return {
510
+ billable: json.billable,
511
+ classification: json.classification
512
+ };
513
+ }
514
+ if (!res.ok) {
515
+ throw new Error(json.error);
516
+ }
517
+ const read = await res.json();
518
+ return read;
519
+ } catch (err) {
520
+ clearTimeout(timeout);
521
+ if (err instanceof Error && err.name === "AbortError") {
522
+ throw new Error("Request timed out after 10 seconds");
523
+ }
524
+ throw err;
525
+ }
526
+ };
527
+
528
+ // src/send-telemetry-event.ts
529
+ import { Internals as Internals3 } from "remotion";
530
+ var sendUsageEvent = async ({
531
+ licenseKey,
532
+ succeeded,
533
+ apiName
534
+ }) => {
535
+ const host = typeof window === "undefined" ? null : typeof window.location === "undefined" ? null : window.location.origin ?? null;
536
+ if (host === null) {
537
+ return;
538
+ }
539
+ if (licenseKey === null) {
540
+ Internals3.Log.warn({ logLevel: "warn", tag: "web-renderer" }, `Pass "licenseKey" to ${apiName}(). If you qualify for the free license (https://remotion.dev/license), pass "free-license" instead.`);
541
+ }
542
+ await registerUsageEvent({
543
+ apiKey: licenseKey === "free-license" ? null : licenseKey,
544
+ event: "webcodec-conversion",
545
+ host,
546
+ succeeded
547
+ });
548
+ };
549
+
463
550
  // src/drawing/turn-svg-into-drawable.ts
464
551
  var turnSvgIntoDrawable = (svg) => {
552
+ const { fill, color } = getComputedStyle(svg);
465
553
  const originalTransform = svg.style.transform;
466
554
  const originalTransformOrigin = svg.style.transformOrigin;
467
555
  const originalMarginLeft = svg.style.marginLeft;
468
556
  const originalMarginRight = svg.style.marginRight;
469
557
  const originalMarginTop = svg.style.marginTop;
470
558
  const originalMarginBottom = svg.style.marginBottom;
559
+ const originalFill = svg.style.fill;
560
+ const originalColor = svg.style.color;
471
561
  svg.style.transform = "none";
472
562
  svg.style.transformOrigin = "";
473
563
  svg.style.marginLeft = "0";
474
564
  svg.style.marginRight = "0";
475
565
  svg.style.marginTop = "0";
476
566
  svg.style.marginBottom = "0";
567
+ svg.style.fill = fill;
568
+ svg.style.color = color;
477
569
  const svgData = new XMLSerializer().serializeToString(svg);
478
570
  svg.style.marginLeft = originalMarginLeft;
479
571
  svg.style.marginRight = originalMarginRight;
@@ -481,6 +573,8 @@ var turnSvgIntoDrawable = (svg) => {
481
573
  svg.style.marginBottom = originalMarginBottom;
482
574
  svg.style.transform = originalTransform;
483
575
  svg.style.transformOrigin = originalTransformOrigin;
576
+ svg.style.fill = originalFill;
577
+ svg.style.color = originalColor;
484
578
  return new Promise((resolve, reject) => {
485
579
  const image = new Image;
486
580
  const url = `data:image/svg+xml;base64,${btoa(svgData)}`;
@@ -506,6 +600,20 @@ var drawDomElement = (node) => {
506
600
  return domDrawFn;
507
601
  };
508
602
 
603
+ // src/drawing/has-transform.ts
604
+ var hasTransformCssValue = (style) => {
605
+ return style.transform !== "none" && style.transform !== "";
606
+ };
607
+ var hasRotateCssValue = (style) => {
608
+ return style.rotate !== "none" && style.rotate !== "";
609
+ };
610
+ var hasScaleCssValue = (style) => {
611
+ return style.scale !== "none" && style.scale !== "";
612
+ };
613
+ var hasAnyTransformCssValue = (style) => {
614
+ return hasTransformCssValue(style) || hasRotateCssValue(style) || hasScaleCssValue(style);
615
+ };
616
+
509
617
  // src/drawing/parse-transform-origin.ts
510
618
  var parseTransformOrigin = (transformOrigin) => {
511
619
  if (transformOrigin.trim() === "") {
@@ -525,30 +633,33 @@ var getInternalTransformOrigin = (transform) => {
525
633
  };
526
634
  return origin;
527
635
  };
528
- var getGlobalTransformOrigin = (transform) => {
636
+ var getGlobalTransformOrigin = ({
637
+ transform,
638
+ offsetLeft,
639
+ offsetTop
640
+ }) => {
529
641
  const { x: originX, y: originY } = getInternalTransformOrigin(transform);
530
642
  return {
531
- x: originX + transform.boundingClientRect.left,
532
- y: originY + transform.boundingClientRect.top
643
+ x: originX + transform.boundingClientRect.left - offsetLeft,
644
+ y: originY + transform.boundingClientRect.top - offsetTop
533
645
  };
534
646
  };
535
- var calculateTransforms = (element) => {
647
+ var calculateTransforms = ({
648
+ element,
649
+ offsetLeft,
650
+ offsetTop
651
+ }) => {
536
652
  let parent = element;
537
653
  const transforms = [];
538
654
  const toReset = [];
539
- let opacity = 1;
540
655
  let elementComputedStyle = null;
541
656
  while (parent) {
542
657
  const computedStyle = getComputedStyle(parent);
543
- const parentOpacity = computedStyle.opacity;
544
- if (parentOpacity && parentOpacity !== "") {
545
- opacity *= parseFloat(parentOpacity);
546
- }
547
658
  if (parent === element) {
548
659
  elementComputedStyle = computedStyle;
549
660
  }
550
- if (computedStyle.transform && computedStyle.transform !== "none" || parent === element) {
551
- const toParse = computedStyle.transform === "none" || computedStyle.transform === "" ? undefined : computedStyle.transform;
661
+ if (hasAnyTransformCssValue(computedStyle) || parent === element) {
662
+ const toParse = hasTransformCssValue(computedStyle) ? computedStyle.transform : undefined;
552
663
  const matrix = new DOMMatrix(toParse);
553
664
  const { transform, scale, rotate } = parent.style;
554
665
  const additionalMatrices = [];
@@ -563,7 +674,7 @@ var calculateTransforms = (element) => {
563
674
  parent.style.scale = "none";
564
675
  parent.style.rotate = "none";
565
676
  transforms.push({
566
- rect: parent,
677
+ element: parent,
567
678
  transformOrigin: computedStyle.transformOrigin,
568
679
  boundingClientRect: null,
569
680
  matrices: additionalMatrices
@@ -578,17 +689,18 @@ var calculateTransforms = (element) => {
578
689
  parent = parent.parentElement;
579
690
  }
580
691
  for (const transform of transforms) {
581
- transform.boundingClientRect = transform.rect.getBoundingClientRect();
692
+ transform.boundingClientRect = transform.element.getBoundingClientRect();
582
693
  }
583
694
  const dimensions = transforms[0].boundingClientRect;
584
695
  const nativeTransformOrigin = getInternalTransformOrigin(transforms[0]);
585
696
  const totalMatrix = new DOMMatrix;
586
697
  for (const transform of transforms.slice().reverse()) {
587
- if (!transform.boundingClientRect) {
588
- throw new Error("Bounding client rect not found");
589
- }
590
698
  for (const matrix of transform.matrices) {
591
- const globalTransformOrigin = getGlobalTransformOrigin(transform);
699
+ const globalTransformOrigin = getGlobalTransformOrigin({
700
+ transform,
701
+ offsetLeft,
702
+ offsetTop
703
+ });
592
704
  const transformMatrix = new DOMMatrix().translate(globalTransformOrigin.x, globalTransformOrigin.y).multiply(matrix).translate(-globalTransformOrigin.x, -globalTransformOrigin.y);
593
705
  totalMatrix.multiplySelf(transformMatrix);
594
706
  }
@@ -605,8 +717,8 @@ var calculateTransforms = (element) => {
605
717
  }
606
718
  },
607
719
  nativeTransformOrigin,
608
- opacity,
609
- computedStyle: elementComputedStyle
720
+ computedStyle: elementComputedStyle,
721
+ opacity: elementComputedStyle.opacity && elementComputedStyle.opacity !== "" ? parseFloat(elementComputedStyle.opacity) : 1
610
722
  };
611
723
  };
612
724
 
@@ -711,33 +823,31 @@ function parseBorderRadius({
711
823
  }
712
824
  function setBorderRadius({
713
825
  ctx,
714
- x,
715
- y,
716
- width,
717
- height,
718
- borderRadius
826
+ rect,
827
+ borderRadius,
828
+ forceClipEvenWhenZero = false
719
829
  }) {
720
- if (borderRadius.topLeft.horizontal === 0 && borderRadius.topLeft.vertical === 0 && borderRadius.topRight.horizontal === 0 && borderRadius.topRight.vertical === 0 && borderRadius.bottomRight.horizontal === 0 && borderRadius.bottomRight.vertical === 0 && borderRadius.bottomLeft.horizontal === 0 && borderRadius.bottomLeft.vertical === 0) {
830
+ if (borderRadius.topLeft.horizontal === 0 && borderRadius.topLeft.vertical === 0 && borderRadius.topRight.horizontal === 0 && borderRadius.topRight.vertical === 0 && borderRadius.bottomRight.horizontal === 0 && borderRadius.bottomRight.vertical === 0 && borderRadius.bottomLeft.horizontal === 0 && borderRadius.bottomLeft.vertical === 0 && !forceClipEvenWhenZero) {
721
831
  return () => {};
722
832
  }
723
833
  ctx.save();
724
834
  ctx.beginPath();
725
- ctx.moveTo(x + borderRadius.topLeft.horizontal, y);
726
- ctx.lineTo(x + width - borderRadius.topRight.horizontal, y);
835
+ ctx.moveTo(rect.left + borderRadius.topLeft.horizontal, rect.top);
836
+ ctx.lineTo(rect.left + rect.width - borderRadius.topRight.horizontal, rect.top);
727
837
  if (borderRadius.topRight.horizontal > 0 || borderRadius.topRight.vertical > 0) {
728
- ctx.ellipse(x + width - borderRadius.topRight.horizontal, y + borderRadius.topRight.vertical, borderRadius.topRight.horizontal, borderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
838
+ ctx.ellipse(rect.left + rect.width - borderRadius.topRight.horizontal, rect.top + borderRadius.topRight.vertical, borderRadius.topRight.horizontal, borderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
729
839
  }
730
- ctx.lineTo(x + width, y + height - borderRadius.bottomRight.vertical);
840
+ ctx.lineTo(rect.left + rect.width, rect.top + rect.height - borderRadius.bottomRight.vertical);
731
841
  if (borderRadius.bottomRight.horizontal > 0 || borderRadius.bottomRight.vertical > 0) {
732
- ctx.ellipse(x + width - borderRadius.bottomRight.horizontal, y + height - borderRadius.bottomRight.vertical, borderRadius.bottomRight.horizontal, borderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
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);
733
843
  }
734
- ctx.lineTo(x + borderRadius.bottomLeft.horizontal, y + height);
844
+ ctx.lineTo(rect.left + borderRadius.bottomLeft.horizontal, rect.top + rect.height);
735
845
  if (borderRadius.bottomLeft.horizontal > 0 || borderRadius.bottomLeft.vertical > 0) {
736
- ctx.ellipse(x + borderRadius.bottomLeft.horizontal, y + height - borderRadius.bottomLeft.vertical, borderRadius.bottomLeft.horizontal, borderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
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);
737
847
  }
738
- ctx.lineTo(x, y + borderRadius.topLeft.vertical);
848
+ ctx.lineTo(rect.left, rect.top + borderRadius.topLeft.vertical);
739
849
  if (borderRadius.topLeft.horizontal > 0 || borderRadius.topLeft.vertical > 0) {
740
- ctx.ellipse(x + borderRadius.topLeft.horizontal, y + borderRadius.topLeft.vertical, borderRadius.topLeft.horizontal, borderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
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);
741
851
  }
742
852
  ctx.closePath();
743
853
  ctx.clip();
@@ -747,86 +857,420 @@ function setBorderRadius({
747
857
  }
748
858
 
749
859
  // src/drawing/draw-border.ts
750
- var drawBorder = ({
860
+ var parseBorderWidth = (value) => {
861
+ return parseFloat(value) || 0;
862
+ };
863
+ var getBorderSideProperties = (computedStyle) => {
864
+ return {
865
+ top: {
866
+ width: parseBorderWidth(computedStyle.borderTopWidth),
867
+ color: computedStyle.borderTopColor || computedStyle.borderColor || "black",
868
+ style: computedStyle.borderTopStyle || computedStyle.borderStyle || "solid"
869
+ },
870
+ right: {
871
+ width: parseBorderWidth(computedStyle.borderRightWidth),
872
+ color: computedStyle.borderRightColor || computedStyle.borderColor || "black",
873
+ style: computedStyle.borderRightStyle || computedStyle.borderStyle || "solid"
874
+ },
875
+ bottom: {
876
+ width: parseBorderWidth(computedStyle.borderBottomWidth),
877
+ color: computedStyle.borderBottomColor || computedStyle.borderColor || "black",
878
+ style: computedStyle.borderBottomStyle || computedStyle.borderStyle || "solid"
879
+ },
880
+ left: {
881
+ width: parseBorderWidth(computedStyle.borderLeftWidth),
882
+ color: computedStyle.borderLeftColor || computedStyle.borderColor || "black",
883
+ style: computedStyle.borderLeftStyle || computedStyle.borderStyle || "solid"
884
+ }
885
+ };
886
+ };
887
+ var getLineDashPattern = (style, width) => {
888
+ if (style === "dashed") {
889
+ return [width * 2, width];
890
+ }
891
+ if (style === "dotted") {
892
+ return [width, width];
893
+ }
894
+ return [];
895
+ };
896
+ var drawBorderSide = ({
897
+ ctx,
898
+ side,
899
+ x,
900
+ y,
901
+ width,
902
+ height,
903
+ borderRadius,
904
+ borderProperties
905
+ }) => {
906
+ const { width: borderWidth, color, style } = borderProperties;
907
+ if (borderWidth <= 0 || style === "none" || style === "hidden") {
908
+ return;
909
+ }
910
+ ctx.beginPath();
911
+ ctx.strokeStyle = color;
912
+ ctx.lineWidth = borderWidth;
913
+ ctx.setLineDash(getLineDashPattern(style, borderWidth));
914
+ const halfWidth = borderWidth / 2;
915
+ if (side === "top") {
916
+ const startX = x + borderRadius.topLeft.horizontal;
917
+ const startY = y + halfWidth;
918
+ const endX = x + width - borderRadius.topRight.horizontal;
919
+ const endY = y + halfWidth;
920
+ ctx.moveTo(startX, startY);
921
+ ctx.lineTo(endX, endY);
922
+ } else if (side === "right") {
923
+ const startX = x + width - halfWidth;
924
+ const startY = y + borderRadius.topRight.vertical;
925
+ const endX = x + width - halfWidth;
926
+ const endY = y + height - borderRadius.bottomRight.vertical;
927
+ ctx.moveTo(startX, startY);
928
+ ctx.lineTo(endX, endY);
929
+ } else if (side === "bottom") {
930
+ const startX = x + borderRadius.bottomLeft.horizontal;
931
+ const startY = y + height - halfWidth;
932
+ const endX = x + width - borderRadius.bottomRight.horizontal;
933
+ const endY = y + height - halfWidth;
934
+ ctx.moveTo(startX, startY);
935
+ ctx.lineTo(endX, endY);
936
+ } else if (side === "left") {
937
+ const startX = x + halfWidth;
938
+ const startY = y + borderRadius.topLeft.vertical;
939
+ const endX = x + halfWidth;
940
+ const endY = y + height - borderRadius.bottomLeft.vertical;
941
+ ctx.moveTo(startX, startY);
942
+ ctx.lineTo(endX, endY);
943
+ }
944
+ ctx.stroke();
945
+ };
946
+ var drawCorner = ({
751
947
  ctx,
948
+ corner,
752
949
  x,
753
950
  y,
754
951
  width,
755
952
  height,
756
953
  borderRadius,
954
+ topBorder,
955
+ rightBorder,
956
+ bottomBorder,
957
+ leftBorder
958
+ }) => {
959
+ const radius = borderRadius[corner];
960
+ if (radius.horizontal <= 0 && radius.vertical <= 0) {
961
+ return;
962
+ }
963
+ let border1;
964
+ let border2;
965
+ let centerX;
966
+ let centerY;
967
+ let startAngle;
968
+ let endAngle;
969
+ if (corner === "topLeft") {
970
+ border1 = leftBorder;
971
+ border2 = topBorder;
972
+ centerX = x + radius.horizontal;
973
+ centerY = y + radius.vertical;
974
+ startAngle = Math.PI;
975
+ endAngle = Math.PI * 3 / 2;
976
+ } else if (corner === "topRight") {
977
+ border1 = topBorder;
978
+ border2 = rightBorder;
979
+ centerX = x + width - radius.horizontal;
980
+ centerY = y + radius.vertical;
981
+ startAngle = -Math.PI / 2;
982
+ endAngle = 0;
983
+ } else if (corner === "bottomRight") {
984
+ border1 = rightBorder;
985
+ border2 = bottomBorder;
986
+ centerX = x + width - radius.horizontal;
987
+ centerY = y + height - radius.vertical;
988
+ startAngle = 0;
989
+ endAngle = Math.PI / 2;
990
+ } else {
991
+ border1 = bottomBorder;
992
+ border2 = leftBorder;
993
+ centerX = x + radius.horizontal;
994
+ centerY = y + height - radius.vertical;
995
+ startAngle = Math.PI / 2;
996
+ endAngle = Math.PI;
997
+ }
998
+ const avgWidth = (border1.width + border2.width) / 2;
999
+ const useColor = border1.width >= border2.width ? border1.color : border2.color;
1000
+ const useStyle = border1.width >= border2.width ? border1.style : border2.style;
1001
+ if (avgWidth > 0 && useStyle !== "none" && useStyle !== "hidden") {
1002
+ ctx.beginPath();
1003
+ ctx.strokeStyle = useColor;
1004
+ ctx.lineWidth = avgWidth;
1005
+ ctx.setLineDash(getLineDashPattern(useStyle, avgWidth));
1006
+ const adjustedRadiusH = Math.max(0, radius.horizontal - avgWidth / 2);
1007
+ const adjustedRadiusV = Math.max(0, radius.vertical - avgWidth / 2);
1008
+ ctx.ellipse(centerX, centerY, adjustedRadiusH, adjustedRadiusV, 0, startAngle, endAngle);
1009
+ ctx.stroke();
1010
+ }
1011
+ };
1012
+ var drawUniformBorder = ({
1013
+ ctx,
1014
+ x,
1015
+ y,
1016
+ width,
1017
+ height,
1018
+ borderRadius,
1019
+ borderWidth,
1020
+ borderColor,
1021
+ borderStyle
1022
+ }) => {
1023
+ ctx.beginPath();
1024
+ ctx.strokeStyle = borderColor;
1025
+ ctx.lineWidth = borderWidth;
1026
+ ctx.setLineDash(getLineDashPattern(borderStyle, borderWidth));
1027
+ const halfWidth = borderWidth / 2;
1028
+ const borderX = x + halfWidth;
1029
+ const borderY = y + halfWidth;
1030
+ const borderW = width - borderWidth;
1031
+ const borderH = height - borderWidth;
1032
+ const adjustedBorderRadius = {
1033
+ topLeft: {
1034
+ horizontal: Math.max(0, borderRadius.topLeft.horizontal - halfWidth),
1035
+ vertical: Math.max(0, borderRadius.topLeft.vertical - halfWidth)
1036
+ },
1037
+ topRight: {
1038
+ horizontal: Math.max(0, borderRadius.topRight.horizontal - halfWidth),
1039
+ vertical: Math.max(0, borderRadius.topRight.vertical - halfWidth)
1040
+ },
1041
+ bottomRight: {
1042
+ horizontal: Math.max(0, borderRadius.bottomRight.horizontal - halfWidth),
1043
+ vertical: Math.max(0, borderRadius.bottomRight.vertical - halfWidth)
1044
+ },
1045
+ bottomLeft: {
1046
+ horizontal: Math.max(0, borderRadius.bottomLeft.horizontal - halfWidth),
1047
+ vertical: Math.max(0, borderRadius.bottomLeft.vertical - halfWidth)
1048
+ }
1049
+ };
1050
+ ctx.moveTo(borderX + adjustedBorderRadius.topLeft.horizontal, borderY);
1051
+ ctx.lineTo(borderX + borderW - adjustedBorderRadius.topRight.horizontal, borderY);
1052
+ if (adjustedBorderRadius.topRight.horizontal > 0 || adjustedBorderRadius.topRight.vertical > 0) {
1053
+ ctx.ellipse(borderX + borderW - adjustedBorderRadius.topRight.horizontal, borderY + adjustedBorderRadius.topRight.vertical, adjustedBorderRadius.topRight.horizontal, adjustedBorderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
1054
+ }
1055
+ ctx.lineTo(borderX + borderW, borderY + borderH - adjustedBorderRadius.bottomRight.vertical);
1056
+ if (adjustedBorderRadius.bottomRight.horizontal > 0 || adjustedBorderRadius.bottomRight.vertical > 0) {
1057
+ ctx.ellipse(borderX + borderW - adjustedBorderRadius.bottomRight.horizontal, borderY + borderH - adjustedBorderRadius.bottomRight.vertical, adjustedBorderRadius.bottomRight.horizontal, adjustedBorderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
1058
+ }
1059
+ ctx.lineTo(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderH);
1060
+ if (adjustedBorderRadius.bottomLeft.horizontal > 0 || adjustedBorderRadius.bottomLeft.vertical > 0) {
1061
+ ctx.ellipse(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderH - adjustedBorderRadius.bottomLeft.vertical, adjustedBorderRadius.bottomLeft.horizontal, adjustedBorderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
1062
+ }
1063
+ ctx.lineTo(borderX, borderY + adjustedBorderRadius.topLeft.vertical);
1064
+ if (adjustedBorderRadius.topLeft.horizontal > 0 || adjustedBorderRadius.topLeft.vertical > 0) {
1065
+ ctx.ellipse(borderX + adjustedBorderRadius.topLeft.horizontal, borderY + adjustedBorderRadius.topLeft.vertical, adjustedBorderRadius.topLeft.horizontal, adjustedBorderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
1066
+ }
1067
+ ctx.closePath();
1068
+ ctx.stroke();
1069
+ };
1070
+ var drawBorder = ({
1071
+ ctx,
1072
+ rect,
1073
+ borderRadius,
757
1074
  computedStyle
758
1075
  }) => {
759
- const {
760
- borderStyle,
761
- borderColor,
762
- borderWidth: computedBorderWidth
763
- } = computedStyle;
764
- const borderWidths = computedBorderWidth.split(/\s+/).map((w) => parseFloat(w));
765
- const borderTop = borderWidths[0] || 0;
766
- const borderRight = borderWidths[1] || borderTop;
767
- const borderBottom = borderWidths[2] || borderTop;
768
- const borderLeft = borderWidths[3] || borderRight;
769
- const hasBorder = borderStyle && borderStyle !== "none" && borderStyle !== "hidden" && (borderTop > 0 || borderRight > 0 || borderBottom > 0 || borderLeft > 0);
1076
+ const borders = getBorderSideProperties(computedStyle);
1077
+ const hasBorder = borders.top.width > 0 || borders.right.width > 0 || borders.bottom.width > 0 || borders.left.width > 0;
770
1078
  if (!hasBorder) {
771
1079
  return;
772
1080
  }
773
1081
  const originalStrokeStyle = ctx.strokeStyle;
774
1082
  const originalLineWidth = ctx.lineWidth;
775
1083
  const originalLineDash = ctx.getLineDash();
776
- ctx.strokeStyle = borderColor;
777
- if (borderStyle === "dashed") {
778
- const max = Math.max(borderTop, borderRight, borderBottom, borderLeft);
779
- ctx.setLineDash([max * 2, max]);
780
- } else if (borderStyle === "dotted") {
781
- ctx.setLineDash([
782
- Math.max(borderTop, borderRight, borderBottom, borderLeft)
783
- ]);
1084
+ const allSidesEqual = borders.top.width === borders.right.width && borders.top.width === borders.bottom.width && borders.top.width === borders.left.width && borders.top.color === borders.right.color && borders.top.color === borders.bottom.color && borders.top.color === borders.left.color && borders.top.style === borders.right.style && borders.top.style === borders.bottom.style && borders.top.style === borders.left.style && borders.top.width > 0;
1085
+ if (allSidesEqual) {
1086
+ drawUniformBorder({
1087
+ ctx,
1088
+ x: rect.left,
1089
+ y: rect.top,
1090
+ width: rect.width,
1091
+ height: rect.height,
1092
+ borderRadius,
1093
+ borderWidth: borders.top.width,
1094
+ borderColor: borders.top.color,
1095
+ borderStyle: borders.top.style
1096
+ });
784
1097
  } else {
785
- ctx.setLineDash([]);
1098
+ drawCorner({
1099
+ ctx,
1100
+ corner: "topLeft",
1101
+ x: rect.left,
1102
+ y: rect.top,
1103
+ width: rect.width,
1104
+ height: rect.height,
1105
+ borderRadius,
1106
+ topBorder: borders.top,
1107
+ rightBorder: borders.right,
1108
+ bottomBorder: borders.bottom,
1109
+ leftBorder: borders.left
1110
+ });
1111
+ drawCorner({
1112
+ ctx,
1113
+ corner: "topRight",
1114
+ x: rect.left,
1115
+ y: rect.top,
1116
+ width: rect.width,
1117
+ height: rect.height,
1118
+ borderRadius,
1119
+ topBorder: borders.top,
1120
+ rightBorder: borders.right,
1121
+ bottomBorder: borders.bottom,
1122
+ leftBorder: borders.left
1123
+ });
1124
+ drawCorner({
1125
+ ctx,
1126
+ corner: "bottomRight",
1127
+ x: rect.left,
1128
+ y: rect.top,
1129
+ width: rect.width,
1130
+ height: rect.height,
1131
+ borderRadius,
1132
+ topBorder: borders.top,
1133
+ rightBorder: borders.right,
1134
+ bottomBorder: borders.bottom,
1135
+ leftBorder: borders.left
1136
+ });
1137
+ drawCorner({
1138
+ ctx,
1139
+ corner: "bottomLeft",
1140
+ x: rect.left,
1141
+ y: rect.top,
1142
+ width: rect.width,
1143
+ height: rect.height,
1144
+ borderRadius,
1145
+ topBorder: borders.top,
1146
+ rightBorder: borders.right,
1147
+ bottomBorder: borders.bottom,
1148
+ leftBorder: borders.left
1149
+ });
1150
+ drawBorderSide({
1151
+ ctx,
1152
+ side: "top",
1153
+ x: rect.left,
1154
+ y: rect.top,
1155
+ width: rect.width,
1156
+ height: rect.height,
1157
+ borderRadius,
1158
+ borderProperties: borders.top
1159
+ });
1160
+ drawBorderSide({
1161
+ ctx,
1162
+ side: "right",
1163
+ x: rect.left,
1164
+ y: rect.top,
1165
+ width: rect.width,
1166
+ height: rect.height,
1167
+ borderRadius,
1168
+ borderProperties: borders.right
1169
+ });
1170
+ drawBorderSide({
1171
+ ctx,
1172
+ side: "bottom",
1173
+ x: rect.left,
1174
+ y: rect.top,
1175
+ width: rect.width,
1176
+ height: rect.height,
1177
+ borderRadius,
1178
+ borderProperties: borders.bottom
1179
+ });
1180
+ drawBorderSide({
1181
+ ctx,
1182
+ side: "left",
1183
+ x: rect.left,
1184
+ y: rect.top,
1185
+ width: rect.width,
1186
+ height: rect.height,
1187
+ borderRadius,
1188
+ borderProperties: borders.left
1189
+ });
1190
+ }
1191
+ ctx.strokeStyle = originalStrokeStyle;
1192
+ ctx.lineWidth = originalLineWidth;
1193
+ ctx.setLineDash(originalLineDash);
1194
+ };
1195
+
1196
+ // src/drawing/draw-outline.ts
1197
+ var parseOutlineWidth = (value) => {
1198
+ return parseFloat(value) || 0;
1199
+ };
1200
+ var parseOutlineOffset = (value) => {
1201
+ return parseFloat(value) || 0;
1202
+ };
1203
+ var getLineDashPattern2 = (style, width) => {
1204
+ if (style === "dashed") {
1205
+ return [width * 2, width];
1206
+ }
1207
+ if (style === "dotted") {
1208
+ return [width, width];
1209
+ }
1210
+ return [];
1211
+ };
1212
+ var drawOutline = ({
1213
+ ctx,
1214
+ rect,
1215
+ borderRadius,
1216
+ computedStyle
1217
+ }) => {
1218
+ const outlineWidth = parseOutlineWidth(computedStyle.outlineWidth);
1219
+ const { outlineStyle } = computedStyle;
1220
+ const outlineColor = computedStyle.outlineColor || "black";
1221
+ const outlineOffset = parseOutlineOffset(computedStyle.outlineOffset);
1222
+ if (outlineWidth <= 0 || outlineStyle === "none" || outlineStyle === "hidden") {
1223
+ return;
786
1224
  }
787
- const maxBorderWidth = Math.max(borderTop, borderRight, borderBottom, borderLeft);
1225
+ const originalStrokeStyle = ctx.strokeStyle;
1226
+ const originalLineWidth = ctx.lineWidth;
1227
+ const originalLineDash = ctx.getLineDash();
788
1228
  ctx.beginPath();
789
- const borderX = x + maxBorderWidth / 2;
790
- const borderY = y + maxBorderWidth / 2;
791
- const borderWidth = width - maxBorderWidth;
792
- const borderHeight = height - maxBorderWidth;
1229
+ ctx.strokeStyle = outlineColor;
1230
+ ctx.lineWidth = outlineWidth;
1231
+ ctx.setLineDash(getLineDashPattern2(outlineStyle, outlineWidth));
1232
+ const halfWidth = outlineWidth / 2;
1233
+ const offset = outlineOffset + halfWidth;
1234
+ const outlineX = rect.left - offset;
1235
+ const outlineY = rect.top - offset;
1236
+ const outlineW = rect.width + offset * 2;
1237
+ const outlineH = rect.height + offset * 2;
793
1238
  const adjustedBorderRadius = {
794
1239
  topLeft: {
795
- horizontal: Math.max(0, borderRadius.topLeft.horizontal - maxBorderWidth / 2),
796
- vertical: Math.max(0, borderRadius.topLeft.vertical - maxBorderWidth / 2)
1240
+ horizontal: borderRadius.topLeft.horizontal === 0 ? 0 : Math.max(0, borderRadius.topLeft.horizontal + offset),
1241
+ vertical: borderRadius.topLeft.vertical === 0 ? 0 : Math.max(0, borderRadius.topLeft.vertical + offset)
797
1242
  },
798
1243
  topRight: {
799
- horizontal: Math.max(0, borderRadius.topRight.horizontal - maxBorderWidth / 2),
800
- vertical: Math.max(0, borderRadius.topRight.vertical - maxBorderWidth / 2)
1244
+ horizontal: borderRadius.topRight.horizontal === 0 ? 0 : Math.max(0, borderRadius.topRight.horizontal + offset),
1245
+ vertical: borderRadius.topRight.vertical === 0 ? 0 : Math.max(0, borderRadius.topRight.vertical + offset)
801
1246
  },
802
1247
  bottomRight: {
803
- horizontal: Math.max(0, borderRadius.bottomRight.horizontal - maxBorderWidth / 2),
804
- vertical: Math.max(0, borderRadius.bottomRight.vertical - maxBorderWidth / 2)
1248
+ horizontal: borderRadius.bottomRight.horizontal === 0 ? 0 : Math.max(0, borderRadius.bottomRight.horizontal + offset),
1249
+ vertical: borderRadius.bottomRight.vertical === 0 ? 0 : Math.max(0, borderRadius.bottomRight.vertical + offset)
805
1250
  },
806
1251
  bottomLeft: {
807
- horizontal: Math.max(0, borderRadius.bottomLeft.horizontal - maxBorderWidth / 2),
808
- vertical: Math.max(0, borderRadius.bottomLeft.vertical - maxBorderWidth / 2)
1252
+ horizontal: borderRadius.bottomLeft.horizontal === 0 ? 0 : Math.max(0, borderRadius.bottomLeft.horizontal + offset),
1253
+ vertical: borderRadius.bottomLeft.vertical === 0 ? 0 : Math.max(0, borderRadius.bottomLeft.vertical + offset)
809
1254
  }
810
1255
  };
811
- ctx.moveTo(borderX + adjustedBorderRadius.topLeft.horizontal, borderY);
812
- ctx.lineTo(borderX + borderWidth - adjustedBorderRadius.topRight.horizontal, borderY);
1256
+ ctx.moveTo(outlineX + adjustedBorderRadius.topLeft.horizontal, outlineY);
1257
+ ctx.lineTo(outlineX + outlineW - adjustedBorderRadius.topRight.horizontal, outlineY);
813
1258
  if (adjustedBorderRadius.topRight.horizontal > 0 || adjustedBorderRadius.topRight.vertical > 0) {
814
- ctx.ellipse(borderX + borderWidth - adjustedBorderRadius.topRight.horizontal, borderY + adjustedBorderRadius.topRight.vertical, adjustedBorderRadius.topRight.horizontal, adjustedBorderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
1259
+ ctx.ellipse(outlineX + outlineW - adjustedBorderRadius.topRight.horizontal, outlineY + adjustedBorderRadius.topRight.vertical, adjustedBorderRadius.topRight.horizontal, adjustedBorderRadius.topRight.vertical, 0, -Math.PI / 2, 0);
815
1260
  }
816
- ctx.lineTo(borderX + borderWidth, borderY + borderHeight - adjustedBorderRadius.bottomRight.vertical);
1261
+ ctx.lineTo(outlineX + outlineW, outlineY + outlineH - adjustedBorderRadius.bottomRight.vertical);
817
1262
  if (adjustedBorderRadius.bottomRight.horizontal > 0 || adjustedBorderRadius.bottomRight.vertical > 0) {
818
- ctx.ellipse(borderX + borderWidth - adjustedBorderRadius.bottomRight.horizontal, borderY + borderHeight - adjustedBorderRadius.bottomRight.vertical, adjustedBorderRadius.bottomRight.horizontal, adjustedBorderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
1263
+ ctx.ellipse(outlineX + outlineW - adjustedBorderRadius.bottomRight.horizontal, outlineY + outlineH - adjustedBorderRadius.bottomRight.vertical, adjustedBorderRadius.bottomRight.horizontal, adjustedBorderRadius.bottomRight.vertical, 0, 0, Math.PI / 2);
819
1264
  }
820
- ctx.lineTo(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderHeight);
1265
+ ctx.lineTo(outlineX + adjustedBorderRadius.bottomLeft.horizontal, outlineY + outlineH);
821
1266
  if (adjustedBorderRadius.bottomLeft.horizontal > 0 || adjustedBorderRadius.bottomLeft.vertical > 0) {
822
- ctx.ellipse(borderX + adjustedBorderRadius.bottomLeft.horizontal, borderY + borderHeight - adjustedBorderRadius.bottomLeft.vertical, adjustedBorderRadius.bottomLeft.horizontal, adjustedBorderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
1267
+ ctx.ellipse(outlineX + adjustedBorderRadius.bottomLeft.horizontal, outlineY + outlineH - adjustedBorderRadius.bottomLeft.vertical, adjustedBorderRadius.bottomLeft.horizontal, adjustedBorderRadius.bottomLeft.vertical, 0, Math.PI / 2, Math.PI);
823
1268
  }
824
- ctx.lineTo(borderX, borderY + adjustedBorderRadius.topLeft.vertical);
1269
+ ctx.lineTo(outlineX, outlineY + adjustedBorderRadius.topLeft.vertical);
825
1270
  if (adjustedBorderRadius.topLeft.horizontal > 0 || adjustedBorderRadius.topLeft.vertical > 0) {
826
- ctx.ellipse(borderX + adjustedBorderRadius.topLeft.horizontal, borderY + adjustedBorderRadius.topLeft.vertical, adjustedBorderRadius.topLeft.horizontal, adjustedBorderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
1271
+ ctx.ellipse(outlineX + adjustedBorderRadius.topLeft.horizontal, outlineY + adjustedBorderRadius.topLeft.vertical, adjustedBorderRadius.topLeft.horizontal, adjustedBorderRadius.topLeft.vertical, 0, Math.PI, Math.PI * 3 / 2);
827
1272
  }
828
1273
  ctx.closePath();
829
- ctx.lineWidth = maxBorderWidth;
830
1274
  ctx.stroke();
831
1275
  ctx.strokeStyle = originalStrokeStyle;
832
1276
  ctx.lineWidth = originalLineWidth;
@@ -845,6 +1289,24 @@ var setOpacity = ({
845
1289
  };
846
1290
  };
847
1291
 
1292
+ // src/drawing/overflow.ts
1293
+ var setOverflowHidden = ({
1294
+ ctx,
1295
+ rect,
1296
+ borderRadius,
1297
+ overflowHidden
1298
+ }) => {
1299
+ if (!overflowHidden) {
1300
+ return () => {};
1301
+ }
1302
+ return setBorderRadius({
1303
+ ctx,
1304
+ rect,
1305
+ borderRadius,
1306
+ forceClipEvenWhenZero: true
1307
+ });
1308
+ };
1309
+
848
1310
  // src/drawing/transform.ts
849
1311
  var setTransform = ({
850
1312
  ctx,
@@ -858,7 +1320,7 @@ var setTransform = ({
858
1320
 
859
1321
  // src/drawing/draw-element.ts
860
1322
  var drawElement = async ({
861
- dimensions,
1323
+ rect,
862
1324
  computedStyle,
863
1325
  context,
864
1326
  draw,
@@ -868,8 +1330,8 @@ var drawElement = async ({
868
1330
  const background = computedStyle.backgroundColor;
869
1331
  const borderRadius = parseBorderRadius({
870
1332
  borderRadius: computedStyle.borderRadius,
871
- width: dimensions.width,
872
- height: dimensions.height
1333
+ width: rect.width,
1334
+ height: rect.height
873
1335
  });
874
1336
  const finishTransform = setTransform({
875
1337
  ctx: context,
@@ -877,11 +1339,9 @@ var drawElement = async ({
877
1339
  });
878
1340
  const finishBorderRadius = setBorderRadius({
879
1341
  ctx: context,
880
- x: dimensions.left,
881
- y: dimensions.top,
882
- width: dimensions.width,
883
- height: dimensions.height,
884
- borderRadius
1342
+ rect,
1343
+ borderRadius,
1344
+ forceClipEvenWhenZero: false
885
1345
  });
886
1346
  const finishOpacity = setOpacity({
887
1347
  ctx: context,
@@ -890,24 +1350,142 @@ var drawElement = async ({
890
1350
  if (background && background !== "transparent" && !(background.startsWith("rgba") && (background.endsWith(", 0)") || background.endsWith(",0")))) {
891
1351
  const originalFillStyle = context.fillStyle;
892
1352
  context.fillStyle = background;
893
- context.fillRect(dimensions.left, dimensions.top, dimensions.width, dimensions.height);
1353
+ context.fillRect(rect.left, rect.top, rect.width, rect.height);
894
1354
  context.fillStyle = originalFillStyle;
895
1355
  }
896
- await draw({ dimensions, computedStyle, contextToDraw: context });
1356
+ await draw({ dimensions: rect, computedStyle, contextToDraw: context });
897
1357
  drawBorder({
898
1358
  ctx: context,
899
- x: dimensions.left,
900
- y: dimensions.top,
901
- width: dimensions.width,
902
- height: dimensions.height,
1359
+ rect,
903
1360
  borderRadius,
904
1361
  computedStyle
905
1362
  });
906
- finishOpacity();
907
1363
  finishBorderRadius();
1364
+ drawOutline({
1365
+ ctx: context,
1366
+ rect,
1367
+ borderRadius,
1368
+ computedStyle
1369
+ });
1370
+ const finishOverflowHidden = setOverflowHidden({
1371
+ ctx: context,
1372
+ rect,
1373
+ borderRadius,
1374
+ overflowHidden: computedStyle.overflow === "hidden"
1375
+ });
908
1376
  finishTransform();
1377
+ return {
1378
+ cleanupAfterChildren: () => {
1379
+ finishOpacity();
1380
+ finishOverflowHidden();
1381
+ }
1382
+ };
909
1383
  };
910
1384
 
1385
+ // src/drawing/handle-3d-transform.ts
1386
+ import { Internals as Internals4 } from "remotion";
1387
+
1388
+ // src/walk-tree.ts
1389
+ function skipToNextNonDescendant(treeWalker) {
1390
+ if (treeWalker.nextSibling()) {
1391
+ return true;
1392
+ }
1393
+ while (treeWalker.parentNode()) {
1394
+ if (treeWalker.nextSibling()) {
1395
+ return true;
1396
+ }
1397
+ }
1398
+ return false;
1399
+ }
1400
+
1401
+ // src/get-biggest-bounding-client-rect.ts
1402
+ var getBiggestBoundingClientRect = (element) => {
1403
+ const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
1404
+ let mostLeft = Infinity;
1405
+ let mostTop = Infinity;
1406
+ let mostRight = -Infinity;
1407
+ let mostBottom = -Infinity;
1408
+ while (true) {
1409
+ const computedStyle = getComputedStyle(treeWalker.currentNode);
1410
+ const outlineWidth = parseOutlineWidth(computedStyle.outlineWidth);
1411
+ const outlineOffset = parseOutlineOffset(computedStyle.outlineOffset);
1412
+ const rect = treeWalker.currentNode.getBoundingClientRect();
1413
+ mostLeft = Math.min(mostLeft, rect.left - outlineOffset - outlineWidth);
1414
+ mostTop = Math.min(mostTop, rect.top - outlineOffset - outlineWidth);
1415
+ mostRight = Math.max(mostRight, rect.right + outlineOffset + outlineWidth);
1416
+ mostBottom = Math.max(mostBottom, rect.bottom + outlineOffset + outlineWidth);
1417
+ if (computedStyle.overflow === "hidden") {
1418
+ if (!skipToNextNonDescendant(treeWalker)) {
1419
+ break;
1420
+ }
1421
+ }
1422
+ if (!treeWalker.nextNode()) {
1423
+ break;
1424
+ }
1425
+ }
1426
+ return new DOMRect(mostLeft, mostTop, mostRight - mostLeft, mostBottom - mostTop);
1427
+ };
1428
+
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
+ // src/drawing/get-pretransform-rect.ts
1442
+ function getPreTransformRect(targetRect, matrix) {
1443
+ const origin = new DOMPoint(0, 0).matrixTransform(matrix);
1444
+ const unitX = new DOMPoint(1, 0).matrixTransform(matrix);
1445
+ const unitY = new DOMPoint(0, 1).matrixTransform(matrix);
1446
+ const basisX = { x: unitX.x - origin.x, y: unitX.y - origin.y };
1447
+ const basisY = { x: unitY.x - origin.x, y: unitY.y - origin.y };
1448
+ const effective2D = new DOMMatrix([
1449
+ basisX.x,
1450
+ basisX.y,
1451
+ basisY.x,
1452
+ basisY.y,
1453
+ origin.x,
1454
+ origin.y
1455
+ ]);
1456
+ const inverse2D = effective2D.inverse();
1457
+ const corners = [
1458
+ new DOMPoint(targetRect.x, targetRect.y),
1459
+ new DOMPoint(targetRect.x + targetRect.width, targetRect.y),
1460
+ new DOMPoint(targetRect.x + targetRect.width, targetRect.y + targetRect.height),
1461
+ new DOMPoint(targetRect.x, targetRect.y + targetRect.height)
1462
+ ];
1463
+ const transformedCorners = corners.map((c) => c.matrixTransform(inverse2D));
1464
+ const xs = transformedCorners.map((p) => p.x);
1465
+ const ys = transformedCorners.map((p) => p.y);
1466
+ return new DOMRect(Math.min(...xs), Math.min(...ys), Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));
1467
+ }
1468
+
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
+
911
1489
  // src/drawing/transform-in-3d.ts
912
1490
  function compileShader(shaderGl, source, type) {
913
1491
  const shader = shaderGl.createShader(type);
@@ -933,6 +1511,12 @@ var createHelperCanvas = ({
933
1511
  helperCanvas.gl.clear(helperCanvas.gl.COLOR_BUFFER_BIT);
934
1512
  return helperCanvas;
935
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
+ }
936
1520
  const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
937
1521
  const gl = canvas.getContext("webgl");
938
1522
  if (!gl) {
@@ -973,43 +1557,47 @@ var createHelperCanvas = ({
973
1557
  gl.clear(gl.COLOR_BUFFER_BIT);
974
1558
  gl.enable(gl.BLEND);
975
1559
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
976
- helperCanvas = { canvas, gl, program };
1560
+ helperCanvas = { canvas, gl, program, vertexShader, fragmentShader };
977
1561
  return helperCanvas;
978
1562
  };
979
1563
  var transformIn3d = ({
980
- canvasWidth,
981
- canvasHeight,
982
1564
  matrix,
983
1565
  sourceCanvas,
984
- offsetLeft,
985
- offsetTop
1566
+ untransformedRect
986
1567
  }) => {
987
- const { canvas, gl, program } = createHelperCanvas({ canvasWidth, canvasHeight });
1568
+ const rectAfterTransforms = transformDOMRect({
1569
+ rect: untransformedRect,
1570
+ matrix
1571
+ });
1572
+ const { canvas, gl, program } = createHelperCanvas({
1573
+ canvasWidth: Math.ceil(rectAfterTransforms.width),
1574
+ canvasHeight: Math.ceil(rectAfterTransforms.height)
1575
+ });
988
1576
  const vertexBuffer = gl.createBuffer();
989
1577
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
990
1578
  const vertices = new Float32Array([
991
- offsetLeft,
992
- offsetTop,
1579
+ untransformedRect.x,
1580
+ untransformedRect.y,
993
1581
  0,
994
1582
  0,
995
- canvasWidth + offsetLeft,
996
- offsetTop,
1583
+ untransformedRect.x + untransformedRect.width,
1584
+ untransformedRect.y,
997
1585
  1,
998
1586
  0,
999
- offsetLeft,
1000
- canvasHeight + offsetTop,
1587
+ untransformedRect.x,
1588
+ untransformedRect.y + untransformedRect.height,
1001
1589
  0,
1002
1590
  1,
1003
- offsetLeft,
1004
- canvasHeight + offsetTop,
1591
+ untransformedRect.x,
1592
+ untransformedRect.y + untransformedRect.height,
1005
1593
  0,
1006
1594
  1,
1007
- canvasWidth + offsetLeft,
1008
- offsetTop,
1595
+ untransformedRect.x + untransformedRect.width,
1596
+ untransformedRect.y,
1009
1597
  1,
1010
1598
  0,
1011
- canvasWidth + offsetLeft,
1012
- canvasHeight + offsetTop,
1599
+ untransformedRect.x + untransformedRect.width,
1600
+ untransformedRect.y + untransformedRect.height,
1013
1601
  1,
1014
1602
  1
1015
1603
  ]);
@@ -1042,8 +1630,8 @@ var transformIn3d = ({
1042
1630
  0,
1043
1631
  -2 / zScale,
1044
1632
  0,
1045
- -1,
1046
- 1,
1633
+ -1 + 2 * -rectAfterTransforms.x / canvas.width,
1634
+ 1 - 2 * -rectAfterTransforms.y / canvas.height,
1047
1635
  0,
1048
1636
  1
1049
1637
  ]);
@@ -1056,56 +1644,88 @@ var transformIn3d = ({
1056
1644
  gl.drawArrays(gl.TRIANGLES, 0, 6);
1057
1645
  gl.deleteTexture(texture);
1058
1646
  gl.deleteBuffer(vertexBuffer);
1059
- return canvas;
1647
+ return { canvas, rect: rectAfterTransforms };
1648
+ };
1649
+
1650
+ // src/drawing/handle-3d-transform.ts
1651
+ var handle3dTransform = async ({
1652
+ element,
1653
+ matrix,
1654
+ parentRect,
1655
+ context,
1656
+ logLevel,
1657
+ internalState
1658
+ }) => {
1659
+ const unclampedBiggestBoundingClientRect = getBiggestBoundingClientRect(element);
1660
+ const biggestPossiblePretransformRect = getPreTransformRect(parentRect, matrix);
1661
+ const preTransformRect = getNarrowerRect({
1662
+ firstRect: unclampedBiggestBoundingClientRect,
1663
+ secondRect: biggestPossiblePretransformRect
1664
+ });
1665
+ const start = Date.now();
1666
+ const tempCanvas = new OffscreenCanvas(Math.ceil(preTransformRect.width), Math.ceil(preTransformRect.height));
1667
+ await compose({
1668
+ element,
1669
+ context: tempCanvas.getContext("2d"),
1670
+ logLevel,
1671
+ parentRect: preTransformRect,
1672
+ internalState
1673
+ });
1674
+ const afterCompose = Date.now();
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
+ });
1060
1690
  };
1061
1691
 
1062
- // src/drawing/draw-element-to-canvas.ts
1063
- var drawElementToCanvas = async ({
1692
+ // src/drawing/process-node.ts
1693
+ var processNode = async ({
1064
1694
  element,
1065
1695
  context,
1066
1696
  draw,
1067
- offsetLeft,
1068
- offsetTop
1697
+ logLevel,
1698
+ parentRect,
1699
+ internalState
1069
1700
  }) => {
1070
- const { totalMatrix, reset, dimensions, opacity, computedStyle } = calculateTransforms(element);
1701
+ const transforms = calculateTransforms({
1702
+ element,
1703
+ offsetLeft: parentRect.x,
1704
+ offsetTop: parentRect.y
1705
+ });
1706
+ const { totalMatrix, reset, dimensions, opacity, computedStyle } = transforms;
1071
1707
  if (opacity === 0) {
1072
1708
  reset();
1073
- return "continue";
1709
+ return { type: "continue", cleanupAfterChildren: () => {} };
1074
1710
  }
1075
1711
  if (dimensions.width <= 0 || dimensions.height <= 0) {
1076
1712
  reset();
1077
- return "continue";
1713
+ return { type: "continue", cleanupAfterChildren: () => {} };
1078
1714
  }
1079
1715
  if (!totalMatrix.is2D) {
1080
- const canvasOffsetLeft = Math.min(dimensions.left, 0);
1081
- const canvasOffsetTop = Math.min(dimensions.top, 0);
1082
- const tempCanvasWidth = Math.max(dimensions.width, dimensions.right);
1083
- const tempCanvasHeight = Math.max(dimensions.height, dimensions.bottom);
1084
- const tempCanvas = new OffscreenCanvas(tempCanvasWidth, tempCanvasHeight);
1085
- const context2 = tempCanvas.getContext("2d");
1086
- if (!context2) {
1087
- throw new Error("Could not get context");
1088
- }
1089
- await compose({
1716
+ await handle3dTransform({
1090
1717
  element,
1091
- context: context2,
1092
- offsetLeft: canvasOffsetLeft,
1093
- offsetTop: canvasOffsetTop
1094
- });
1095
- const transformed = transformIn3d({
1096
- canvasWidth: tempCanvasWidth,
1097
- canvasHeight: tempCanvasHeight,
1098
1718
  matrix: totalMatrix,
1099
- sourceCanvas: tempCanvas,
1100
- offsetLeft: canvasOffsetLeft,
1101
- offsetTop: canvasOffsetTop
1719
+ parentRect,
1720
+ context,
1721
+ logLevel,
1722
+ internalState
1102
1723
  });
1103
- context.drawImage(transformed, 0, 0);
1104
1724
  reset();
1105
- return "skip-children";
1725
+ return { type: "skip-children" };
1106
1726
  }
1107
- await drawElement({
1108
- dimensions: new DOMRect(dimensions.left - offsetLeft, dimensions.top - offsetTop, dimensions.width, dimensions.height),
1727
+ const { cleanupAfterChildren } = await drawElement({
1728
+ rect: new DOMRect(dimensions.left - parentRect.x, dimensions.top - parentRect.y, dimensions.width, dimensions.height),
1109
1729
  computedStyle,
1110
1730
  context,
1111
1731
  draw,
@@ -1113,11 +1733,11 @@ var drawElementToCanvas = async ({
1113
1733
  totalMatrix
1114
1734
  });
1115
1735
  reset();
1116
- return "continue";
1736
+ return { type: "continue", cleanupAfterChildren };
1117
1737
  };
1118
1738
 
1119
1739
  // src/drawing/text/draw-text.ts
1120
- import { Internals as Internals3 } from "remotion";
1740
+ import { Internals as Internals5 } from "remotion";
1121
1741
 
1122
1742
  // src/drawing/text/apply-text-transform.ts
1123
1743
  var applyTextTransform = (text, transform) => {
@@ -1239,7 +1859,6 @@ var drawText = (span) => {
1239
1859
  fontSize,
1240
1860
  fontWeight,
1241
1861
  color,
1242
- lineHeight,
1243
1862
  direction,
1244
1863
  writingMode,
1245
1864
  letterSpacing,
@@ -1247,22 +1866,20 @@ var drawText = (span) => {
1247
1866
  } = computedStyle;
1248
1867
  const isVertical = writingMode !== "horizontal-tb";
1249
1868
  if (isVertical) {
1250
- Internals3.Log.warn({
1869
+ Internals5.Log.warn({
1251
1870
  logLevel: "warn",
1252
1871
  tag: "@remotion/web-renderer"
1253
1872
  }, 'Detected "writing-mode" CSS property. Vertical text is not yet supported in @remotion/web-renderer');
1254
1873
  return;
1255
1874
  }
1256
1875
  contextToDraw.save();
1257
- contextToDraw.font = `${fontWeight} ${fontSize} ${fontFamily}`;
1876
+ const fontSizePx = parseFloat(fontSize);
1877
+ contextToDraw.font = `${fontWeight} ${fontSizePx}px ${fontFamily}`;
1258
1878
  contextToDraw.fillStyle = color;
1259
1879
  contextToDraw.letterSpacing = letterSpacing;
1260
- const fontSizePx = parseFloat(fontSize);
1261
- const lineHeightPx = lineHeight === "normal" ? 1.2 * fontSizePx : parseFloat(lineHeight);
1262
- const baselineOffset = (lineHeightPx - fontSizePx) / 2;
1263
1880
  const isRTL = direction === "rtl";
1264
1881
  contextToDraw.textAlign = isRTL ? "right" : "left";
1265
- contextToDraw.textBaseline = "top";
1882
+ contextToDraw.textBaseline = "alphabetic";
1266
1883
  const originalText = span.textContent;
1267
1884
  const collapsedText = getCollapsedText(span);
1268
1885
  const transformedText = applyTextTransform(collapsedText, textTransform);
@@ -1270,8 +1887,9 @@ var drawText = (span) => {
1270
1887
  const xPosition = isRTL ? rect.right : rect.left;
1271
1888
  const lines = findLineBreaks(span, isRTL);
1272
1889
  let offsetTop = 0;
1890
+ const { fontBoundingBoxAscent } = contextToDraw.measureText(lines[0].text);
1273
1891
  for (const line of lines) {
1274
- contextToDraw.fillText(line.text, xPosition + line.offsetHorizontal, rect.top + baselineOffset + offsetTop);
1892
+ contextToDraw.fillText(line.text, xPosition + line.offsetHorizontal, rect.top + offsetTop + fontBoundingBoxAscent);
1275
1893
  offsetTop += line.offsetTop;
1276
1894
  }
1277
1895
  span.textContent = originalText;
@@ -1284,8 +1902,9 @@ var drawText = (span) => {
1284
1902
  var handleTextNode = async ({
1285
1903
  node,
1286
1904
  context,
1287
- offsetLeft,
1288
- offsetTop
1905
+ logLevel,
1906
+ parentRect,
1907
+ internalState
1289
1908
  }) => {
1290
1909
  const span = document.createElement("span");
1291
1910
  const parent = node.parentNode;
@@ -1294,58 +1913,56 @@ var handleTextNode = async ({
1294
1913
  }
1295
1914
  parent.insertBefore(span, node);
1296
1915
  span.appendChild(node);
1297
- const value = await drawElementToCanvas({
1916
+ const value = await processNode({
1298
1917
  context,
1299
1918
  element: span,
1300
1919
  draw: drawText(span),
1301
- offsetLeft,
1302
- offsetTop
1920
+ logLevel,
1921
+ parentRect,
1922
+ internalState
1303
1923
  });
1304
1924
  parent.insertBefore(node, span);
1305
1925
  parent.removeChild(span);
1306
1926
  return value;
1307
1927
  };
1308
1928
 
1309
- // src/walk-tree.ts
1310
- function skipToNextNonDescendant(treeWalker) {
1311
- if (treeWalker.nextSibling()) {
1312
- return true;
1313
- }
1314
- while (treeWalker.parentNode()) {
1315
- if (treeWalker.nextSibling()) {
1316
- return true;
1317
- }
1318
- }
1319
- return false;
1320
- }
1321
-
1322
1929
  // src/compose.ts
1323
1930
  var walkOverNode = ({
1324
1931
  node,
1325
1932
  context,
1326
- offsetLeft,
1327
- offsetTop
1933
+ logLevel,
1934
+ parentRect,
1935
+ internalState
1328
1936
  }) => {
1329
1937
  if (node instanceof HTMLElement || node instanceof SVGElement) {
1330
- return drawElementToCanvas({
1938
+ return processNode({
1331
1939
  element: node,
1332
1940
  context,
1333
1941
  draw: drawDomElement(node),
1334
- offsetLeft,
1335
- offsetTop
1942
+ logLevel,
1943
+ parentRect,
1944
+ internalState
1336
1945
  });
1337
1946
  }
1338
1947
  if (node instanceof Text) {
1339
- return handleTextNode({ node, context, offsetLeft, offsetTop });
1948
+ return handleTextNode({
1949
+ node,
1950
+ context,
1951
+ logLevel,
1952
+ parentRect,
1953
+ internalState
1954
+ });
1340
1955
  }
1341
1956
  throw new Error("Unknown node type");
1342
1957
  };
1343
1958
  var compose = async ({
1344
1959
  element,
1345
1960
  context,
1346
- offsetLeft,
1347
- offsetTop
1961
+ logLevel,
1962
+ parentRect,
1963
+ internalState
1348
1964
  }) => {
1965
+ const cleanupAfterChildren = [];
1349
1966
  const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, (node) => {
1350
1967
  if (node instanceof Element) {
1351
1968
  if (node.parentElement instanceof SVGSVGElement) {
@@ -1357,43 +1974,78 @@ var compose = async ({
1357
1974
  return NodeFilter.FILTER_ACCEPT;
1358
1975
  });
1359
1976
  while (true) {
1977
+ for (let i = 0;i < cleanupAfterChildren.length; ) {
1978
+ const cleanup = cleanupAfterChildren[i];
1979
+ if (!(cleanup.element === treeWalker.currentNode || cleanup.element.contains(treeWalker.currentNode))) {
1980
+ cleanup.cleanupFn();
1981
+ cleanupAfterChildren.splice(i, 1);
1982
+ } else {
1983
+ i++;
1984
+ }
1985
+ }
1360
1986
  const val = await walkOverNode({
1361
1987
  node: treeWalker.currentNode,
1362
1988
  context,
1363
- offsetLeft,
1364
- offsetTop
1989
+ logLevel,
1990
+ parentRect,
1991
+ internalState
1365
1992
  });
1366
- if (val === "skip-children") {
1993
+ if (val.type === "skip-children") {
1367
1994
  if (!skipToNextNonDescendant(treeWalker)) {
1368
1995
  break;
1369
1996
  }
1370
- } else if (!treeWalker.nextNode()) {
1371
- break;
1997
+ } else {
1998
+ cleanupAfterChildren.push({
1999
+ element: treeWalker.currentNode,
2000
+ cleanupFn: val.cleanupAfterChildren
2001
+ });
2002
+ if (!treeWalker.nextNode()) {
2003
+ break;
2004
+ }
1372
2005
  }
1373
2006
  }
2007
+ for (const cleanup of cleanupAfterChildren) {
2008
+ cleanup.cleanupFn();
2009
+ }
1374
2010
  };
1375
2011
 
1376
2012
  // src/take-screenshot.ts
1377
2013
  var createFrame = async ({
1378
2014
  div,
1379
2015
  width,
1380
- height
2016
+ height,
2017
+ logLevel,
2018
+ internalState
1381
2019
  }) => {
1382
2020
  const canvas = new OffscreenCanvas(width, height);
1383
2021
  const context = canvas.getContext("2d");
1384
2022
  if (!context) {
1385
2023
  throw new Error("Could not get context");
1386
2024
  }
1387
- await compose({ element: div, context, offsetLeft: 0, offsetTop: 0 });
2025
+ await compose({
2026
+ element: div,
2027
+ context,
2028
+ logLevel,
2029
+ parentRect: new DOMRect(0, 0, width, height),
2030
+ internalState
2031
+ });
1388
2032
  return canvas;
1389
2033
  };
1390
2034
  var takeScreenshot = async ({
1391
2035
  div,
1392
2036
  width,
1393
2037
  height,
1394
- imageFormat
2038
+ imageFormat,
2039
+ logLevel,
2040
+ internalState
1395
2041
  }) => {
1396
- const frame = await createFrame({ div, width, height });
2042
+ const frame = await createFrame({
2043
+ div,
2044
+ width,
2045
+ height,
2046
+ logLevel,
2047
+ internalState
2048
+ });
1397
2049
  const imageData = await frame.convertToBlob({
1398
2050
  type: `image/${imageFormat}`
1399
2051
  });
@@ -1562,7 +2214,8 @@ var internalRenderMediaOnWeb = async ({
1562
2214
  transparent,
1563
2215
  onArtifact,
1564
2216
  onFrame,
1565
- outputTarget: userDesiredOutputTarget
2217
+ outputTarget: userDesiredOutputTarget,
2218
+ licenseKey
1566
2219
  }) => {
1567
2220
  const outputTarget = userDesiredOutputTarget === null ? await canUseWebFsWriter() ? "web-fs" : "arraybuffer" : userDesiredOutputTarget;
1568
2221
  if (outputTarget === "web-fs") {
@@ -1573,7 +2226,7 @@ var internalRenderMediaOnWeb = async ({
1573
2226
  if (codec && !format.getSupportedCodecs().includes(codecToMediabunnyCodec(codec))) {
1574
2227
  return Promise.reject(new Error(`Codec ${codec} is not supported for container ${container}`));
1575
2228
  }
1576
- const resolved = await Internals4.resolveVideoConfig({
2229
+ const resolved = await Internals6.resolveVideoConfig({
1577
2230
  calculateMetadata: composition.calculateMetadata ?? null,
1578
2231
  signal: signal ?? new AbortController().signal,
1579
2232
  defaultProps: composition.defaultProps ?? {},
@@ -1606,6 +2259,7 @@ var internalRenderMediaOnWeb = async ({
1606
2259
  defaultCodec: resolved.defaultCodec,
1607
2260
  defaultOutName: resolved.defaultOutName
1608
2261
  });
2262
+ const internalState = makeInternalState();
1609
2263
  const artifactsHandler = handleArtifacts();
1610
2264
  cleanupFns.push(() => {
1611
2265
  cleanupScaffold();
@@ -1683,7 +2337,9 @@ var internalRenderMediaOnWeb = async ({
1683
2337
  const imageData = await createFrame({
1684
2338
  div,
1685
2339
  width: resolved.width,
1686
- height: resolved.height
2340
+ height: resolved.height,
2341
+ logLevel,
2342
+ internalState
1687
2343
  });
1688
2344
  if (signal?.aborted) {
1689
2345
  throw new Error("renderMediaOnWeb() was cancelled");
@@ -1741,20 +2397,36 @@ var internalRenderMediaOnWeb = async ({
1741
2397
  return {
1742
2398
  getBlob: () => {
1743
2399
  return webFsTarget.getBlob();
1744
- }
2400
+ },
2401
+ internalState
1745
2402
  };
1746
2403
  }
1747
2404
  if (!(target instanceof BufferTarget)) {
1748
2405
  throw new Error("Expected target to be a BufferTarget");
1749
2406
  }
2407
+ sendUsageEvent({
2408
+ licenseKey: licenseKey ?? null,
2409
+ succeeded: true,
2410
+ apiName: "renderMediaOnWeb"
2411
+ });
1750
2412
  return {
1751
2413
  getBlob: () => {
1752
2414
  if (!target.buffer) {
1753
2415
  throw new Error("The resulting buffer is empty");
1754
2416
  }
1755
2417
  return Promise.resolve(new Blob([target.buffer], { type: mimeType }));
1756
- }
2418
+ },
2419
+ internalState
1757
2420
  };
2421
+ } catch (err) {
2422
+ sendUsageEvent({
2423
+ succeeded: false,
2424
+ licenseKey: licenseKey ?? null,
2425
+ apiName: "renderMediaOnWeb"
2426
+ }).catch((err2) => {
2427
+ Internals6.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
2428
+ });
2429
+ throw err;
1758
2430
  } finally {
1759
2431
  cleanupFns.forEach((fn) => fn());
1760
2432
  }
@@ -1765,7 +2437,7 @@ var renderMediaOnWeb = (options) => {
1765
2437
  onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref.catch(() => Promise.resolve()).then(() => internalRenderMediaOnWeb({
1766
2438
  ...options,
1767
2439
  delayRenderTimeoutInMilliseconds: options.delayRenderTimeoutInMilliseconds ?? 30000,
1768
- logLevel: options.logLevel ?? "info",
2440
+ logLevel: options.logLevel ?? window.remotion_logLevel ?? "info",
1769
2441
  schema: options.schema ?? undefined,
1770
2442
  mediaCacheSizeInBytes: options.mediaCacheSizeInBytes ?? null,
1771
2443
  codec,
@@ -1779,13 +2451,14 @@ var renderMediaOnWeb = (options) => {
1779
2451
  transparent: options.transparent ?? false,
1780
2452
  onArtifact: options.onArtifact ?? null,
1781
2453
  onFrame: options.onFrame ?? null,
1782
- outputTarget: options.outputTarget ?? null
2454
+ outputTarget: options.outputTarget ?? null,
2455
+ licenseKey: options.licenseKey ?? undefined
1783
2456
  }));
1784
2457
  return onlyOneRenderAtATimeQueue.ref;
1785
2458
  };
1786
2459
  // src/render-still-on-web.tsx
1787
2460
  import {
1788
- Internals as Internals5
2461
+ Internals as Internals7
1789
2462
  } from "remotion";
1790
2463
  async function internalRenderStillOnWeb({
1791
2464
  frame,
@@ -1797,9 +2470,10 @@ async function internalRenderStillOnWeb({
1797
2470
  mediaCacheSizeInBytes,
1798
2471
  composition,
1799
2472
  signal,
1800
- onArtifact
2473
+ onArtifact,
2474
+ licenseKey
1801
2475
  }) {
1802
- const resolved = await Internals5.resolveVideoConfig({
2476
+ const resolved = await Internals7.resolveVideoConfig({
1803
2477
  calculateMetadata: composition.calculateMetadata ?? null,
1804
2478
  signal: signal ?? new AbortController().signal,
1805
2479
  defaultProps: composition.defaultProps ?? {},
@@ -1813,6 +2487,7 @@ async function internalRenderStillOnWeb({
1813
2487
  if (signal?.aborted) {
1814
2488
  return Promise.reject(new Error("renderStillOnWeb() was cancelled"));
1815
2489
  }
2490
+ const internalState = makeInternalState();
1816
2491
  const { delayRenderScope, div, cleanupScaffold, collectAssets } = await createScaffold({
1817
2492
  width: resolved.width,
1818
2493
  height: resolved.height,
@@ -1849,13 +2524,29 @@ async function internalRenderStillOnWeb({
1849
2524
  div,
1850
2525
  width: resolved.width,
1851
2526
  height: resolved.height,
1852
- imageFormat
2527
+ imageFormat,
2528
+ logLevel,
2529
+ internalState
1853
2530
  });
1854
2531
  const assets = collectAssets.current.collectAssets();
1855
2532
  if (onArtifact) {
1856
2533
  await artifactsHandler.handle({ imageData, frame, assets, onArtifact });
1857
2534
  }
1858
- return imageData;
2535
+ sendUsageEvent({
2536
+ licenseKey: licenseKey ?? null,
2537
+ succeeded: true,
2538
+ apiName: "renderStillOnWeb"
2539
+ });
2540
+ return { blob: imageData, internalState };
2541
+ } catch (err) {
2542
+ sendUsageEvent({
2543
+ succeeded: false,
2544
+ licenseKey: licenseKey ?? null,
2545
+ apiName: "renderStillOnWeb"
2546
+ }).catch((err2) => {
2547
+ Internals7.Log.error({ logLevel: "error", tag: "web-renderer" }, "Failed to send usage event", err2);
2548
+ });
2549
+ throw err;
1859
2550
  } finally {
1860
2551
  cleanupScaffold();
1861
2552
  }
@@ -1864,11 +2555,12 @@ var renderStillOnWeb = (options) => {
1864
2555
  onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref.catch(() => Promise.resolve()).then(() => internalRenderStillOnWeb({
1865
2556
  ...options,
1866
2557
  delayRenderTimeoutInMilliseconds: options.delayRenderTimeoutInMilliseconds ?? 30000,
1867
- logLevel: options.logLevel ?? "info",
2558
+ logLevel: options.logLevel ?? window.remotion_logLevel ?? "info",
1868
2559
  schema: options.schema ?? undefined,
1869
2560
  mediaCacheSizeInBytes: options.mediaCacheSizeInBytes ?? null,
1870
2561
  signal: options.signal ?? null,
1871
- onArtifact: options.onArtifact ?? null
2562
+ onArtifact: options.onArtifact ?? null,
2563
+ licenseKey: options.licenseKey ?? undefined
1872
2564
  }));
1873
2565
  return onlyOneRenderAtATimeQueue.ref;
1874
2566
  };