@remotion/web-renderer 4.0.398 → 4.0.399

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 (76) hide show
  1. package/dist/calculate-transforms.d.ts +0 -2
  2. package/dist/calculate-transforms.js +0 -17
  3. package/dist/composable.d.ts +8 -2
  4. package/dist/compose-canvas.js +4 -28
  5. package/dist/compose.d.ts +2 -1
  6. package/dist/compose.js +34 -35
  7. package/dist/drawing/border-radius.d.ts +3 -1
  8. package/dist/drawing/border-radius.js +27 -6
  9. package/dist/drawing/calculate-object-fit.d.ts +40 -0
  10. package/dist/drawing/calculate-object-fit.js +208 -0
  11. package/dist/drawing/draw-background.d.ts +13 -0
  12. package/dist/drawing/draw-background.js +62 -0
  13. package/dist/drawing/draw-box-shadow.d.ts +1 -1
  14. package/dist/drawing/draw-box-shadow.js +1 -1
  15. package/dist/drawing/draw-dom-element.js +78 -10
  16. package/dist/drawing/draw-element-to-canvas.d.ts +1 -2
  17. package/dist/drawing/draw-element-to-canvas.js +36 -8
  18. package/dist/drawing/draw-element.d.ts +4 -1
  19. package/dist/drawing/draw-element.js +21 -35
  20. package/dist/drawing/fit-svg-into-its-dimensions.d.ts +12 -0
  21. package/dist/drawing/fit-svg-into-its-dimensions.js +35 -0
  22. package/dist/drawing/get-clipped-background.d.ts +8 -0
  23. package/dist/drawing/get-clipped-background.js +14 -0
  24. package/dist/drawing/get-padding-box.d.ts +1 -0
  25. package/dist/drawing/get-padding-box.js +30 -0
  26. package/dist/drawing/get-pretransform-rect.js +13 -0
  27. package/dist/drawing/go-rects-intersect.d.ts +1 -0
  28. package/dist/drawing/go-rects-intersect.js +6 -0
  29. package/dist/drawing/handle-3d-transform.d.ts +4 -2
  30. package/dist/drawing/handle-3d-transform.js +4 -3
  31. package/dist/drawing/handle-mask.js +2 -0
  32. package/dist/drawing/overflow.d.ts +3 -1
  33. package/dist/drawing/overflow.js +3 -1
  34. package/dist/drawing/parse-linear-gradient.d.ts +3 -1
  35. package/dist/drawing/parse-linear-gradient.js +3 -3
  36. package/dist/drawing/precompose.js +1 -0
  37. package/dist/drawing/process-node.js +5 -6
  38. package/dist/drawing/text/draw-text.d.ts +2 -1
  39. package/dist/drawing/text/draw-text.js +9 -3
  40. package/dist/drawing/text/get-base-height.d.ts +1 -0
  41. package/dist/drawing/text/get-base-height.js +13 -0
  42. package/dist/drawing/text/handle-text-node.d.ts +2 -1
  43. package/dist/drawing/text/handle-text-node.js +2 -2
  44. package/dist/drawing/transform-in-3d.d.ts +3 -2
  45. package/dist/drawing/transform-in-3d.js +106 -87
  46. package/dist/esm/index.mjs +678 -168
  47. package/dist/find-capturable-elements.d.ts +1 -1
  48. package/dist/find-capturable-elements.js +22 -20
  49. package/dist/internal-state.d.ts +19 -0
  50. package/dist/internal-state.js +9 -0
  51. package/dist/render-still-on-web.js +1 -0
  52. package/dist/send-telemetry-event.js +1 -1
  53. package/dist/take-screenshot.js +1 -0
  54. package/dist/tree-walker-cleanup-after-children.d.ts +5 -0
  55. package/dist/tree-walker-cleanup-after-children.js +33 -0
  56. package/package.json +9 -8
  57. package/dist/border-radius.d.ts +0 -31
  58. package/dist/border-radius.js +0 -152
  59. package/dist/drawing/canvas-offset-from-rect.d.ts +0 -8
  60. package/dist/drawing/canvas-offset-from-rect.js +0 -12
  61. package/dist/drawing/compose-canvas.d.ts +0 -1
  62. package/dist/drawing/compose-canvas.js +0 -36
  63. package/dist/drawing/compose-svg.d.ts +0 -1
  64. package/dist/drawing/compose-svg.js +0 -34
  65. package/dist/drawing/compose.d.ts +0 -5
  66. package/dist/drawing/compose.js +0 -6
  67. package/dist/drawing/get-bounding-box-including-shadow.d.ts +0 -1
  68. package/dist/drawing/get-bounding-box-including-shadow.js +0 -6
  69. package/dist/drawing/get-computed-style-cache.d.ts +0 -0
  70. package/dist/drawing/get-computed-style-cache.js +0 -1
  71. package/dist/find-canvas-elements.d.ts +0 -1
  72. package/dist/find-canvas-elements.js +0 -13
  73. package/dist/opacity.d.ts +0 -4
  74. package/dist/opacity.js +0 -7
  75. package/dist/transform.d.ts +0 -4
  76. package/dist/transform.js +0 -6
@@ -393,6 +393,9 @@ var getDefaultAudioEncodingConfig = async () => {
393
393
  var makeInternalState = () => {
394
394
  let drawnPrecomposedPixels = 0;
395
395
  let precomposedTextures = 0;
396
+ const helperCanvasState = {
397
+ current: null
398
+ };
396
399
  return {
397
400
  getDrawn3dPixels: () => drawnPrecomposedPixels,
398
401
  getPrecomposedTiles: () => precomposedTextures,
@@ -402,6 +405,12 @@ var makeInternalState = () => {
402
405
  }) => {
403
406
  drawnPrecomposedPixels += canvasWidth * canvasHeight;
404
407
  precomposedTextures++;
408
+ },
409
+ helperCanvasState,
410
+ cleanup: () => {
411
+ if (helperCanvasState.current) {
412
+ helperCanvasState.current.cleanup();
413
+ }
405
414
  }
406
415
  };
407
416
  };
@@ -485,23 +494,31 @@ var onlyOneRenderAtATimeQueue = {
485
494
  };
486
495
 
487
496
  // ../licensing/dist/esm/index.mjs
497
+ function isNetworkError(error) {
498
+ if (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")) {
499
+ return true;
500
+ }
501
+ return false;
502
+ }
488
503
  var HOST = "https://www.remotion.pro";
489
504
  var registerUsageEvent = async ({
490
- apiKey,
491
505
  host,
492
506
  succeeded,
493
- event
507
+ event,
508
+ ...apiOrLicenseKey
494
509
  }) => {
495
510
  const abortController = new AbortController;
496
511
  const timeout = setTimeout(() => {
497
512
  abortController.abort();
498
513
  }, 1e4);
514
+ const apiKey = "apiKey" in apiOrLicenseKey ? apiOrLicenseKey.apiKey : null;
515
+ const licenseKey = "licenseKey" in apiOrLicenseKey ? apiOrLicenseKey.licenseKey : null;
499
516
  try {
500
517
  const res = await fetch(`${HOST}/api/track/register-usage-point`, {
501
518
  method: "POST",
502
519
  body: JSON.stringify({
503
520
  event,
504
- apiKey,
521
+ apiKey: licenseKey ?? apiKey,
505
522
  host,
506
523
  succeeded
507
524
  }),
@@ -521,9 +538,11 @@ var registerUsageEvent = async ({
521
538
  if (!res.ok) {
522
539
  throw new Error(json.error);
523
540
  }
524
- const read = await res.json();
525
- return read;
541
+ throw new Error("Unexpected response from server");
526
542
  } catch (err) {
543
+ if (isNetworkError(err)) {
544
+ console.log("Failed to send usage event", err);
545
+ }
527
546
  clearTimeout(timeout);
528
547
  if (err instanceof Error && err.name === "AbortError") {
529
548
  throw new Error("Request timed out after 10 seconds");
@@ -547,13 +566,227 @@ var sendUsageEvent = async ({
547
566
  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.`);
548
567
  }
549
568
  await registerUsageEvent({
550
- apiKey: licenseKey === "free-license" ? null : licenseKey,
569
+ licenseKey: licenseKey === "free-license" ? null : licenseKey,
551
570
  event: "webcodec-conversion",
552
571
  host,
553
572
  succeeded
554
573
  });
555
574
  };
556
575
 
576
+ // src/drawing/calculate-object-fit.ts
577
+ var calculateFill = ({
578
+ containerSize,
579
+ intrinsicSize
580
+ }) => {
581
+ return {
582
+ sourceX: 0,
583
+ sourceY: 0,
584
+ sourceWidth: intrinsicSize.width,
585
+ sourceHeight: intrinsicSize.height,
586
+ destX: containerSize.left,
587
+ destY: containerSize.top,
588
+ destWidth: containerSize.width,
589
+ destHeight: containerSize.height
590
+ };
591
+ };
592
+ var calculateContain = ({
593
+ containerSize,
594
+ intrinsicSize
595
+ }) => {
596
+ const containerAspect = containerSize.width / containerSize.height;
597
+ const imageAspect = intrinsicSize.width / intrinsicSize.height;
598
+ let destWidth;
599
+ let destHeight;
600
+ if (imageAspect > containerAspect) {
601
+ destWidth = containerSize.width;
602
+ destHeight = containerSize.width / imageAspect;
603
+ } else {
604
+ destHeight = containerSize.height;
605
+ destWidth = containerSize.height * imageAspect;
606
+ }
607
+ const destX = containerSize.left + (containerSize.width - destWidth) / 2;
608
+ const destY = containerSize.top + (containerSize.height - destHeight) / 2;
609
+ return {
610
+ sourceX: 0,
611
+ sourceY: 0,
612
+ sourceWidth: intrinsicSize.width,
613
+ sourceHeight: intrinsicSize.height,
614
+ destX,
615
+ destY,
616
+ destWidth,
617
+ destHeight
618
+ };
619
+ };
620
+ var calculateCover = ({
621
+ containerSize,
622
+ intrinsicSize
623
+ }) => {
624
+ if (containerSize.height <= 0 || intrinsicSize.height <= 0) {
625
+ return {
626
+ sourceX: 0,
627
+ sourceY: 0,
628
+ sourceWidth: 0,
629
+ sourceHeight: 0,
630
+ destX: containerSize.left,
631
+ destY: containerSize.top,
632
+ destWidth: 0,
633
+ destHeight: 0
634
+ };
635
+ }
636
+ const containerAspect = containerSize.width / containerSize.height;
637
+ const imageAspect = intrinsicSize.width / intrinsicSize.height;
638
+ let sourceX = 0;
639
+ let sourceY = 0;
640
+ let sourceWidth = intrinsicSize.width;
641
+ let sourceHeight = intrinsicSize.height;
642
+ if (imageAspect > containerAspect) {
643
+ sourceWidth = intrinsicSize.height * containerAspect;
644
+ sourceX = (intrinsicSize.width - sourceWidth) / 2;
645
+ } else {
646
+ sourceHeight = intrinsicSize.width / containerAspect;
647
+ sourceY = (intrinsicSize.height - sourceHeight) / 2;
648
+ }
649
+ return {
650
+ sourceX,
651
+ sourceY,
652
+ sourceWidth,
653
+ sourceHeight,
654
+ destX: containerSize.left,
655
+ destY: containerSize.top,
656
+ destWidth: containerSize.width,
657
+ destHeight: containerSize.height
658
+ };
659
+ };
660
+ var calculateNone = ({
661
+ containerSize,
662
+ intrinsicSize
663
+ }) => {
664
+ const centeredX = containerSize.left + (containerSize.width - intrinsicSize.width) / 2;
665
+ const centeredY = containerSize.top + (containerSize.height - intrinsicSize.height) / 2;
666
+ let sourceX = 0;
667
+ let sourceY = 0;
668
+ let sourceWidth = intrinsicSize.width;
669
+ let sourceHeight = intrinsicSize.height;
670
+ let destX = centeredX;
671
+ let destY = centeredY;
672
+ let destWidth = intrinsicSize.width;
673
+ let destHeight = intrinsicSize.height;
674
+ if (destX < containerSize.left) {
675
+ const clipAmount = containerSize.left - destX;
676
+ sourceX = clipAmount;
677
+ sourceWidth -= clipAmount;
678
+ destX = containerSize.left;
679
+ destWidth -= clipAmount;
680
+ }
681
+ if (destY < containerSize.top) {
682
+ const clipAmount = containerSize.top - destY;
683
+ sourceY = clipAmount;
684
+ sourceHeight -= clipAmount;
685
+ destY = containerSize.top;
686
+ destHeight -= clipAmount;
687
+ }
688
+ const containerRight = containerSize.left + containerSize.width;
689
+ if (destX + destWidth > containerRight) {
690
+ const clipAmount = destX + destWidth - containerRight;
691
+ sourceWidth -= clipAmount;
692
+ destWidth -= clipAmount;
693
+ }
694
+ const containerBottom = containerSize.top + containerSize.height;
695
+ if (destY + destHeight > containerBottom) {
696
+ const clipAmount = destY + destHeight - containerBottom;
697
+ sourceHeight -= clipAmount;
698
+ destHeight -= clipAmount;
699
+ }
700
+ return {
701
+ sourceX,
702
+ sourceY,
703
+ sourceWidth,
704
+ sourceHeight,
705
+ destX,
706
+ destY,
707
+ destWidth,
708
+ destHeight
709
+ };
710
+ };
711
+ var calculateObjectFit = ({
712
+ objectFit,
713
+ containerSize,
714
+ intrinsicSize
715
+ }) => {
716
+ switch (objectFit) {
717
+ case "fill":
718
+ return calculateFill({ containerSize, intrinsicSize });
719
+ case "contain":
720
+ return calculateContain({ containerSize, intrinsicSize });
721
+ case "cover":
722
+ return calculateCover({ containerSize, intrinsicSize });
723
+ case "none":
724
+ return calculateNone({ containerSize, intrinsicSize });
725
+ case "scale-down": {
726
+ const containResult = calculateContain({ containerSize, intrinsicSize });
727
+ const noneResult = calculateNone({ containerSize, intrinsicSize });
728
+ const containArea = containResult.destWidth * containResult.destHeight;
729
+ const noneArea = noneResult.destWidth * noneResult.destHeight;
730
+ return containArea < noneArea ? containResult : noneResult;
731
+ }
732
+ default: {
733
+ const exhaustiveCheck = objectFit;
734
+ throw new Error(`Unknown object-fit value: ${exhaustiveCheck}`);
735
+ }
736
+ }
737
+ };
738
+ var parseObjectFit = (value) => {
739
+ if (!value) {
740
+ return "fill";
741
+ }
742
+ const normalized = value.trim().toLowerCase();
743
+ switch (normalized) {
744
+ case "fill":
745
+ case "contain":
746
+ case "cover":
747
+ case "none":
748
+ case "scale-down":
749
+ return normalized;
750
+ default:
751
+ return "fill";
752
+ }
753
+ };
754
+
755
+ // src/drawing/fit-svg-into-its-dimensions.ts
756
+ var fitSvgIntoItsContainer = ({
757
+ containerSize,
758
+ elementSize
759
+ }) => {
760
+ if (Math.round(containerSize.width) === Math.round(elementSize.width) && Math.round(containerSize.height) === Math.round(elementSize.height)) {
761
+ return {
762
+ width: containerSize.width,
763
+ height: containerSize.height,
764
+ top: containerSize.top,
765
+ left: containerSize.left
766
+ };
767
+ }
768
+ if (containerSize.width <= 0 || containerSize.height <= 0) {
769
+ throw new Error(`Container must have positive dimensions, but got ${containerSize.width}x${containerSize.height}`);
770
+ }
771
+ if (elementSize.width <= 0 || elementSize.height <= 0) {
772
+ throw new Error(`Element must have positive dimensions, but got ${elementSize.width}x${elementSize.height}`);
773
+ }
774
+ const heightRatio = containerSize.height / elementSize.height;
775
+ const widthRatio = containerSize.width / elementSize.width;
776
+ const ratio = Math.min(heightRatio, widthRatio);
777
+ const newWidth = elementSize.width * ratio;
778
+ const newHeight = elementSize.height * ratio;
779
+ if (newWidth > containerSize.width + 0.000001 || newHeight > containerSize.height + 0.000001) {
780
+ throw new Error(`Element is too big to fit into the container. Max size: ${containerSize.width}x${containerSize.height}, element size: ${newWidth}x${newHeight}`);
781
+ }
782
+ return {
783
+ width: newWidth,
784
+ height: newHeight,
785
+ top: (containerSize.height - newHeight) / 2 + containerSize.top,
786
+ left: (containerSize.width - newWidth) / 2 + containerSize.left
787
+ };
788
+ };
789
+
557
790
  // src/drawing/turn-svg-into-drawable.ts
558
791
  var turnSvgIntoDrawable = (svg) => {
559
792
  const { fill, color } = getComputedStyle(svg);
@@ -596,13 +829,81 @@ var turnSvgIntoDrawable = (svg) => {
596
829
  };
597
830
 
598
831
  // src/drawing/draw-dom-element.ts
832
+ var getReadableImageError = (err, node) => {
833
+ if (!(err instanceof DOMException)) {
834
+ return null;
835
+ }
836
+ if (err.name === "SecurityError") {
837
+ return new Error(`Could not draw image with src="${node.src}" to canvas: ` + `The image is tainted due to CORS restrictions. ` + `The server hosting this image must respond with the "Access-Control-Allow-Origin" header. ` + `See: https://remotion.dev/docs/client-side-rendering/migration`);
838
+ }
839
+ if (err.name === "InvalidStateError") {
840
+ return new Error(`Could not draw image with src="${node.src}" to canvas: ` + `The image is in a broken state. ` + `This usually means the image failed to load - check that the URL is valid and accessible.`);
841
+ }
842
+ return null;
843
+ };
844
+ var drawSvg = ({
845
+ drawable,
846
+ dimensions,
847
+ contextToDraw
848
+ }) => {
849
+ const fitted = fitSvgIntoItsContainer({
850
+ containerSize: dimensions,
851
+ elementSize: {
852
+ width: drawable.width,
853
+ height: drawable.height
854
+ }
855
+ });
856
+ contextToDraw.drawImage(drawable, fitted.left, fitted.top, fitted.width, fitted.height);
857
+ };
858
+ var drawReplacedElement = ({
859
+ drawable,
860
+ dimensions,
861
+ computedStyle,
862
+ contextToDraw
863
+ }) => {
864
+ const objectFit = parseObjectFit(computedStyle.objectFit);
865
+ const intrinsicSize = drawable instanceof HTMLImageElement ? { width: drawable.naturalWidth, height: drawable.naturalHeight } : { width: drawable.width, height: drawable.height };
866
+ const result = calculateObjectFit({
867
+ objectFit,
868
+ containerSize: {
869
+ width: dimensions.width,
870
+ height: dimensions.height,
871
+ left: dimensions.left,
872
+ top: dimensions.top
873
+ },
874
+ intrinsicSize
875
+ });
876
+ contextToDraw.drawImage(drawable, result.sourceX, result.sourceY, result.sourceWidth, result.sourceHeight, result.destX, result.destY, result.destWidth, result.destHeight);
877
+ };
599
878
  var drawDomElement = (node) => {
600
- const domDrawFn = async ({ dimensions, contextToDraw }) => {
601
- const drawable = await (node instanceof SVGSVGElement ? turnSvgIntoDrawable(node) : node instanceof HTMLImageElement ? node : node instanceof HTMLCanvasElement ? node : null);
602
- if (!drawable) {
879
+ const domDrawFn = async ({
880
+ dimensions,
881
+ contextToDraw,
882
+ computedStyle
883
+ }) => {
884
+ if (node instanceof SVGSVGElement) {
885
+ const drawable = await turnSvgIntoDrawable(node);
886
+ drawSvg({ drawable, dimensions, contextToDraw });
603
887
  return;
604
888
  }
605
- contextToDraw.drawImage(drawable, dimensions.left, dimensions.top, dimensions.width, dimensions.height);
889
+ if (node instanceof HTMLImageElement || node instanceof HTMLCanvasElement) {
890
+ try {
891
+ drawReplacedElement({
892
+ drawable: node,
893
+ dimensions,
894
+ computedStyle,
895
+ contextToDraw
896
+ });
897
+ } catch (err) {
898
+ if (node instanceof HTMLImageElement) {
899
+ const readableError = getReadableImageError(err, node);
900
+ if (readableError) {
901
+ throw readableError;
902
+ }
903
+ }
904
+ throw err;
905
+ }
906
+ }
606
907
  };
607
908
  return domDrawFn;
608
909
  };
@@ -820,11 +1121,13 @@ var parseLinearGradient = (backgroundImage) => {
820
1121
  var createCanvasGradient = ({
821
1122
  ctx,
822
1123
  rect,
823
- gradientInfo
1124
+ gradientInfo,
1125
+ offsetLeft,
1126
+ offsetTop
824
1127
  }) => {
825
1128
  const angleRad = (gradientInfo.angle - 90) * Math.PI / 180;
826
- const centerX = rect.left + rect.width / 2;
827
- const centerY = rect.top + rect.height / 2;
1129
+ const centerX = rect.left - offsetLeft + rect.width / 2;
1130
+ const centerY = rect.top - offsetTop + rect.height / 2;
828
1131
  const cos = Math.cos(angleRad);
829
1132
  const sin = Math.sin(angleRad);
830
1133
  const halfWidth = rect.width / 2;
@@ -1052,6 +1355,38 @@ var drawRoundedRectPath = ({
1052
1355
  ctx.closePath();
1053
1356
  };
1054
1357
 
1358
+ // src/drawing/get-padding-box.ts
1359
+ var getPaddingBox = (rect, computedStyle) => {
1360
+ const borderLeft = parseFloat(computedStyle.borderLeftWidth);
1361
+ const borderRight = parseFloat(computedStyle.borderRightWidth);
1362
+ const borderTop = parseFloat(computedStyle.borderTopWidth);
1363
+ const borderBottom = parseFloat(computedStyle.borderBottomWidth);
1364
+ return new DOMRect(rect.left + borderLeft, rect.top + borderTop, rect.width - borderLeft - borderRight, rect.height - borderTop - borderBottom);
1365
+ };
1366
+ var getContentBox = (rect, computedStyle) => {
1367
+ const paddingBox = getPaddingBox(rect, computedStyle);
1368
+ const paddingLeft = parseFloat(computedStyle.paddingLeft);
1369
+ const paddingRight = parseFloat(computedStyle.paddingRight);
1370
+ const paddingTop = parseFloat(computedStyle.paddingTop);
1371
+ const paddingBottom = parseFloat(computedStyle.paddingBottom);
1372
+ return new DOMRect(paddingBox.left + paddingLeft, paddingBox.top + paddingTop, paddingBox.width - paddingLeft - paddingRight, paddingBox.height - paddingTop - paddingBottom);
1373
+ };
1374
+ var getBoxBasedOnBackgroundClip = (rect, computedStyle, backgroundClip) => {
1375
+ if (!backgroundClip) {
1376
+ return rect;
1377
+ }
1378
+ if (backgroundClip.includes("text")) {
1379
+ return rect;
1380
+ }
1381
+ if (backgroundClip.includes("padding-box")) {
1382
+ return getPaddingBox(rect, computedStyle);
1383
+ }
1384
+ if (backgroundClip.includes("content-box")) {
1385
+ return getContentBox(rect, computedStyle);
1386
+ }
1387
+ return rect;
1388
+ };
1389
+
1055
1390
  // src/drawing/border-radius.ts
1056
1391
  function parseValue({
1057
1392
  value,
@@ -1155,19 +1490,40 @@ function setBorderRadius({
1155
1490
  ctx,
1156
1491
  rect,
1157
1492
  borderRadius,
1158
- forceClipEvenWhenZero = false
1493
+ forceClipEvenWhenZero = false,
1494
+ computedStyle,
1495
+ backgroundClip
1159
1496
  }) {
1160
1497
  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) {
1161
1498
  return () => {};
1162
1499
  }
1163
1500
  ctx.save();
1501
+ const boundingRect = getBoxBasedOnBackgroundClip(rect, computedStyle, backgroundClip);
1502
+ const actualBorderRadius = {
1503
+ topLeft: {
1504
+ horizontal: Math.max(0, borderRadius.topLeft.horizontal - (boundingRect.left - rect.left)),
1505
+ vertical: Math.max(0, borderRadius.topLeft.vertical - (boundingRect.top - rect.top))
1506
+ },
1507
+ topRight: {
1508
+ horizontal: Math.max(0, borderRadius.topRight.horizontal - (rect.right - boundingRect.right)),
1509
+ vertical: Math.max(0, borderRadius.topRight.vertical - (boundingRect.top - rect.top))
1510
+ },
1511
+ bottomRight: {
1512
+ horizontal: Math.max(0, borderRadius.bottomRight.horizontal - (rect.right - boundingRect.right)),
1513
+ vertical: Math.max(0, borderRadius.bottomRight.vertical - (rect.bottom - boundingRect.bottom))
1514
+ },
1515
+ bottomLeft: {
1516
+ horizontal: Math.max(0, borderRadius.bottomLeft.horizontal - (boundingRect.left - rect.left)),
1517
+ vertical: Math.max(0, borderRadius.bottomLeft.vertical - (rect.bottom - boundingRect.bottom))
1518
+ }
1519
+ };
1164
1520
  drawRoundedRectPath({
1165
1521
  ctx,
1166
- x: rect.left,
1167
- y: rect.top,
1168
- width: rect.width,
1169
- height: rect.height,
1170
- borderRadius
1522
+ x: boundingRect.left,
1523
+ y: boundingRect.top,
1524
+ width: boundingRect.width,
1525
+ height: boundingRect.height,
1526
+ borderRadius: actualBorderRadius
1171
1527
  });
1172
1528
  ctx.clip();
1173
1529
  return () => {
@@ -1175,6 +1531,93 @@ function setBorderRadius({
1175
1531
  };
1176
1532
  }
1177
1533
 
1534
+ // src/drawing/get-clipped-background.ts
1535
+ var getClippedBackground = async ({
1536
+ element,
1537
+ boundingRect,
1538
+ logLevel,
1539
+ internalState
1540
+ }) => {
1541
+ const tempCanvas = new OffscreenCanvas(boundingRect.width, boundingRect.height);
1542
+ const tempContext = tempCanvas.getContext("2d");
1543
+ await compose({
1544
+ element,
1545
+ context: tempContext,
1546
+ logLevel,
1547
+ parentRect: boundingRect,
1548
+ internalState,
1549
+ onlyBackgroundClip: true
1550
+ });
1551
+ return tempContext;
1552
+ };
1553
+
1554
+ // src/drawing/draw-background.ts
1555
+ var drawBackground = async ({
1556
+ backgroundImage,
1557
+ context,
1558
+ rect,
1559
+ backgroundColor,
1560
+ backgroundClip,
1561
+ element,
1562
+ logLevel,
1563
+ internalState,
1564
+ computedStyle
1565
+ }) => {
1566
+ let contextToDraw = context;
1567
+ const originalCompositeOperation = context.globalCompositeOperation;
1568
+ let offsetLeft = 0;
1569
+ let offsetTop = 0;
1570
+ const finish = () => {
1571
+ context.globalCompositeOperation = originalCompositeOperation;
1572
+ if (context !== contextToDraw) {
1573
+ context.drawImage(contextToDraw.canvas, offsetLeft, offsetTop, contextToDraw.canvas.width, contextToDraw.canvas.height);
1574
+ }
1575
+ };
1576
+ const boundingRect = getBoxBasedOnBackgroundClip(rect, computedStyle, backgroundClip);
1577
+ if (backgroundClip.includes("text")) {
1578
+ offsetLeft = boundingRect.left;
1579
+ offsetTop = boundingRect.top;
1580
+ const originalBackgroundClip = element.style.backgroundClip;
1581
+ const originalWebkitBackgroundClip = element.style.webkitBackgroundClip;
1582
+ element.style.backgroundClip = "initial";
1583
+ element.style.webkitBackgroundClip = "initial";
1584
+ const drawn = await getClippedBackground({
1585
+ element,
1586
+ boundingRect,
1587
+ logLevel,
1588
+ internalState
1589
+ });
1590
+ element.style.backgroundClip = originalBackgroundClip;
1591
+ element.style.webkitBackgroundClip = originalWebkitBackgroundClip;
1592
+ contextToDraw = drawn;
1593
+ contextToDraw.globalCompositeOperation = "source-in";
1594
+ }
1595
+ if (backgroundImage && backgroundImage !== "none") {
1596
+ const gradientInfo = parseLinearGradient(backgroundImage);
1597
+ if (gradientInfo) {
1598
+ const gradient = createCanvasGradient({
1599
+ ctx: contextToDraw,
1600
+ rect: boundingRect,
1601
+ gradientInfo,
1602
+ offsetLeft,
1603
+ offsetTop
1604
+ });
1605
+ const originalFillStyle = contextToDraw.fillStyle;
1606
+ contextToDraw.fillStyle = gradient;
1607
+ contextToDraw.fillRect(boundingRect.left - offsetLeft, boundingRect.top - offsetTop, boundingRect.width, boundingRect.height);
1608
+ contextToDraw.fillStyle = originalFillStyle;
1609
+ return finish();
1610
+ }
1611
+ }
1612
+ if (backgroundColor && backgroundColor !== "transparent" && !(backgroundColor.startsWith("rgba") && (backgroundColor.endsWith(", 0)") || backgroundColor.endsWith(",0")))) {
1613
+ const originalFillStyle = contextToDraw.fillStyle;
1614
+ contextToDraw.fillStyle = backgroundColor;
1615
+ contextToDraw.fillRect(boundingRect.left - offsetLeft, boundingRect.top - offsetLeft, boundingRect.width, boundingRect.height);
1616
+ contextToDraw.fillStyle = originalFillStyle;
1617
+ }
1618
+ finish();
1619
+ };
1620
+
1178
1621
  // src/drawing/draw-border.ts
1179
1622
  var parseBorderWidth = (value) => {
1180
1623
  return parseFloat(value) || 0;
@@ -1552,7 +1995,7 @@ var parseBoxShadow = (boxShadowValue) => {
1552
1995
  }
1553
1996
  return shadows;
1554
1997
  };
1555
- var setBoxShadow = ({
1998
+ var drawBorderRadius = ({
1556
1999
  ctx,
1557
2000
  rect,
1558
2001
  borderRadius,
@@ -1703,7 +2146,9 @@ var setOverflowHidden = ({
1703
2146
  ctx,
1704
2147
  rect,
1705
2148
  borderRadius,
1706
- overflowHidden
2149
+ overflowHidden,
2150
+ computedStyle,
2151
+ backgroundClip
1707
2152
  }) => {
1708
2153
  if (!overflowHidden) {
1709
2154
  return () => {};
@@ -1712,7 +2157,9 @@ var setOverflowHidden = ({
1712
2157
  ctx,
1713
2158
  rect,
1714
2159
  borderRadius,
1715
- forceClipEvenWhenZero: true
2160
+ forceClipEvenWhenZero: true,
2161
+ computedStyle,
2162
+ backgroundClip
1716
2163
  });
1717
2164
  };
1718
2165
 
@@ -1738,10 +2185,11 @@ var drawElement = async ({
1738
2185
  opacity,
1739
2186
  totalMatrix,
1740
2187
  parentRect,
1741
- logLevel
2188
+ logLevel,
2189
+ element,
2190
+ internalState
1742
2191
  }) => {
1743
- const background = computedStyle.backgroundColor;
1744
- const { backgroundImage } = computedStyle;
2192
+ const { backgroundImage, backgroundColor, backgroundClip } = computedStyle;
1745
2193
  const borderRadius = parseBorderRadius({
1746
2194
  borderRadius: computedStyle.borderRadius,
1747
2195
  width: rect.width,
@@ -1756,7 +2204,7 @@ var drawElement = async ({
1756
2204
  ctx: context,
1757
2205
  opacity
1758
2206
  });
1759
- setBoxShadow({
2207
+ drawBorderRadius({
1760
2208
  ctx: context,
1761
2209
  computedStyle,
1762
2210
  rect,
@@ -1767,38 +2215,29 @@ var drawElement = async ({
1767
2215
  ctx: context,
1768
2216
  rect,
1769
2217
  borderRadius,
1770
- forceClipEvenWhenZero: false
2218
+ forceClipEvenWhenZero: false,
2219
+ computedStyle,
2220
+ backgroundClip
2221
+ });
2222
+ await drawBackground({
2223
+ backgroundImage,
2224
+ context,
2225
+ rect,
2226
+ backgroundColor,
2227
+ backgroundClip,
2228
+ element,
2229
+ logLevel,
2230
+ internalState,
2231
+ computedStyle
1771
2232
  });
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")))) {
1789
- const originalFillStyle = context.fillStyle;
1790
- context.fillStyle = background;
1791
- context.fillRect(rect.left, rect.top, rect.width, rect.height);
1792
- context.fillStyle = originalFillStyle;
1793
- }
1794
2233
  await draw({ dimensions: rect, computedStyle, contextToDraw: context });
2234
+ finishBorderRadius();
1795
2235
  drawBorder({
1796
2236
  ctx: context,
1797
2237
  rect,
1798
2238
  borderRadius,
1799
2239
  computedStyle
1800
2240
  });
1801
- finishBorderRadius();
1802
2241
  drawOutline({
1803
2242
  ctx: context,
1804
2243
  rect,
@@ -1809,7 +2248,9 @@ var drawElement = async ({
1809
2248
  ctx: context,
1810
2249
  rect,
1811
2250
  borderRadius,
1812
- overflowHidden: computedStyle.overflow === "hidden"
2251
+ overflowHidden: computedStyle.overflow === "hidden",
2252
+ computedStyle,
2253
+ backgroundClip
1813
2254
  });
1814
2255
  finishTransform();
1815
2256
  return {
@@ -1875,12 +2316,19 @@ var getBiggestBoundingClientRect = (element) => {
1875
2316
  };
1876
2317
 
1877
2318
  // src/drawing/get-pretransform-rect.ts
2319
+ var MAX_SCALE_FACTOR = 100;
1878
2320
  function getPreTransformRect(targetRect, matrix) {
1879
2321
  const origin = new DOMPoint(0, 0).matrixTransform(matrix);
1880
2322
  const unitX = new DOMPoint(1, 0).matrixTransform(matrix);
1881
2323
  const unitY = new DOMPoint(0, 1).matrixTransform(matrix);
1882
2324
  const basisX = { x: unitX.x - origin.x, y: unitX.y - origin.y };
1883
2325
  const basisY = { x: unitY.x - origin.x, y: unitY.y - origin.y };
2326
+ const scaleX = Math.hypot(basisX.x, basisX.y);
2327
+ const scaleY = Math.hypot(basisY.x, basisY.y);
2328
+ const minScale = Math.min(scaleX, scaleY);
2329
+ if (minScale < 1 / MAX_SCALE_FACTOR) {
2330
+ return new DOMRect(0, 0, 0, 0);
2331
+ }
1884
2332
  const effective2D = new DOMMatrix([
1885
2333
  basisX.x,
1886
2334
  basisX.y,
@@ -1907,6 +2355,27 @@ function getPreTransformRect(targetRect, matrix) {
1907
2355
  }
1908
2356
 
1909
2357
  // src/drawing/transform-in-3d.ts
2358
+ var vsSource = `
2359
+ attribute vec2 aPosition;
2360
+ attribute vec2 aTexCoord;
2361
+ uniform mat4 uTransform;
2362
+ uniform mat4 uProjection;
2363
+ varying vec2 vTexCoord;
2364
+
2365
+ void main() {
2366
+ gl_Position = uProjection * uTransform * vec4(aPosition, 0.0, 1.0);
2367
+ vTexCoord = aTexCoord;
2368
+ }
2369
+ `;
2370
+ var fsSource = `
2371
+ precision mediump float;
2372
+ uniform sampler2D uTexture;
2373
+ varying vec2 vTexCoord;
2374
+
2375
+ void main() {
2376
+ gl_FragColor = texture2D(uTexture, vTexCoord);
2377
+ }
2378
+ `;
1910
2379
  function compileShader(shaderGl, source, type) {
1911
2380
  const shader = shaderGl.createShader(type);
1912
2381
  if (!shader) {
@@ -1923,62 +2392,76 @@ function compileShader(shaderGl, source, type) {
1923
2392
  }
1924
2393
  var createHelperCanvas = ({
1925
2394
  canvasWidth,
1926
- canvasHeight
2395
+ canvasHeight,
2396
+ helperCanvasState
1927
2397
  }) => {
2398
+ if (helperCanvasState.current) {
2399
+ if (helperCanvasState.current.canvas.width !== canvasWidth || helperCanvasState.current.canvas.height !== canvasHeight) {
2400
+ helperCanvasState.current.canvas.width = canvasWidth;
2401
+ helperCanvasState.current.canvas.height = canvasHeight;
2402
+ }
2403
+ helperCanvasState.current.gl.viewport(0, 0, canvasWidth, canvasHeight);
2404
+ helperCanvasState.current.gl.clearColor(0, 0, 0, 0);
2405
+ helperCanvasState.current.gl.clear(helperCanvasState.current.gl.COLOR_BUFFER_BIT);
2406
+ return helperCanvasState.current;
2407
+ }
1928
2408
  const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
1929
2409
  const gl = canvas.getContext("webgl", {
1930
2410
  premultipliedAlpha: true
1931
- });
2411
+ }) ?? undefined;
1932
2412
  if (!gl) {
1933
2413
  throw new Error("WebGL not supported");
1934
2414
  }
1935
- const vsSource = `
1936
- attribute vec2 aPosition;
1937
- attribute vec2 aTexCoord;
1938
- uniform mat4 uTransform;
1939
- uniform mat4 uProjection;
1940
- varying vec2 vTexCoord;
1941
-
1942
- void main() {
1943
- gl_Position = uProjection * uTransform * vec4(aPosition, 0.0, 1.0);
1944
- vTexCoord = aTexCoord;
1945
- }
1946
- `;
1947
- const fsSource = `
1948
- precision mediump float;
1949
- uniform sampler2D uTexture;
1950
- varying vec2 vTexCoord;
1951
-
1952
- void main() {
1953
- gl_FragColor = texture2D(uTexture, vTexCoord);
1954
- }
1955
- `;
1956
2415
  const vertexShader = compileShader(gl, vsSource, gl.VERTEX_SHADER);
1957
2416
  const fragmentShader = compileShader(gl, fsSource, gl.FRAGMENT_SHADER);
1958
2417
  const program = gl.createProgram();
2418
+ if (!program) {
2419
+ throw new Error("Could not create program");
2420
+ }
1959
2421
  gl.attachShader(program, vertexShader);
1960
2422
  gl.attachShader(program, fragmentShader);
1961
2423
  gl.linkProgram(program);
1962
2424
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
1963
2425
  throw new Error("Program link error: " + gl.getProgramInfoLog(program));
1964
2426
  }
1965
- gl.useProgram(program);
1966
- gl.clearColor(0, 0, 0, 0);
1967
- gl.clear(gl.COLOR_BUFFER_BIT);
1968
- gl.enable(gl.BLEND);
1969
- gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
1970
- return { canvas, gl, program, vertexShader, fragmentShader };
2427
+ const locations = {
2428
+ aPosition: gl.getAttribLocation(program, "aPosition"),
2429
+ aTexCoord: gl.getAttribLocation(program, "aTexCoord"),
2430
+ uTransform: gl.getUniformLocation(program, "uTransform"),
2431
+ uProjection: gl.getUniformLocation(program, "uProjection"),
2432
+ uTexture: gl.getUniformLocation(program, "uTexture")
2433
+ };
2434
+ gl.deleteShader(vertexShader);
2435
+ gl.deleteShader(fragmentShader);
2436
+ const cleanup = () => {
2437
+ gl.deleteProgram(program);
2438
+ const loseContext = gl.getExtension("WEBGL_lose_context");
2439
+ if (loseContext) {
2440
+ loseContext.loseContext();
2441
+ }
2442
+ };
2443
+ helperCanvasState.current = { canvas, gl, program, locations, cleanup };
2444
+ return helperCanvasState.current;
1971
2445
  };
1972
2446
  var transformIn3d = ({
1973
2447
  matrix,
1974
2448
  sourceCanvas,
1975
2449
  untransformedRect,
1976
- rectAfterTransforms
2450
+ rectAfterTransforms,
2451
+ internalState
1977
2452
  }) => {
1978
- const { canvas, gl, program } = createHelperCanvas({
2453
+ const { canvas, gl, program, locations } = createHelperCanvas({
1979
2454
  canvasWidth: rectAfterTransforms.width,
1980
- canvasHeight: rectAfterTransforms.height
2455
+ canvasHeight: rectAfterTransforms.height,
2456
+ helperCanvasState: internalState.helperCanvasState
1981
2457
  });
2458
+ gl.useProgram(program);
2459
+ gl.viewport(0, 0, rectAfterTransforms.width, rectAfterTransforms.height);
2460
+ gl.clearColor(0, 0, 0, 0);
2461
+ gl.clear(gl.COLOR_BUFFER_BIT);
2462
+ gl.enable(gl.BLEND);
2463
+ gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
2464
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
1982
2465
  const vertexBuffer = gl.createBuffer();
1983
2466
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
1984
2467
  const vertices = new Float32Array([
@@ -2008,66 +2491,52 @@ var transformIn3d = ({
2008
2491
  1
2009
2492
  ]);
2010
2493
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
2011
- const aPosition = gl.getAttribLocation(program, "aPosition");
2012
- const aTexCoord = gl.getAttribLocation(program, "aTexCoord");
2013
- gl.enableVertexAttribArray(aPosition);
2014
- gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 4 * 4, 0);
2015
- gl.enableVertexAttribArray(aTexCoord);
2016
- gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, 4 * 4, 2 * 4);
2494
+ gl.enableVertexAttribArray(locations.aPosition);
2495
+ gl.vertexAttribPointer(locations.aPosition, 2, gl.FLOAT, false, 4 * 4, 0);
2496
+ gl.enableVertexAttribArray(locations.aTexCoord);
2497
+ gl.vertexAttribPointer(locations.aTexCoord, 2, gl.FLOAT, false, 4 * 4, 2 * 4);
2017
2498
  const texture = gl.createTexture();
2018
2499
  gl.bindTexture(gl.TEXTURE_2D, texture);
2019
2500
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
2020
2501
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
2021
2502
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
2022
2503
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
2023
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
2024
2504
  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);
2027
2505
  const transformMatrix = matrix.toFloat32Array();
2028
2506
  const zScale = 1e9;
2029
2507
  const projectionMatrix = new Float32Array([
2030
- 2 / canvas.width,
2508
+ 2 / rectAfterTransforms.width,
2031
2509
  0,
2032
2510
  0,
2033
2511
  0,
2034
2512
  0,
2035
- -2 / canvas.height,
2513
+ -2 / rectAfterTransforms.height,
2036
2514
  0,
2037
2515
  0,
2038
2516
  0,
2039
2517
  0,
2040
2518
  -2 / zScale,
2041
2519
  0,
2042
- -1 + 2 * -rectAfterTransforms.x / canvas.width,
2043
- 1 - 2 * -rectAfterTransforms.y / canvas.height,
2520
+ -1 + 2 * -rectAfterTransforms.x / rectAfterTransforms.width,
2521
+ 1 - 2 * -rectAfterTransforms.y / rectAfterTransforms.height,
2044
2522
  0,
2045
2523
  1
2046
2524
  ]);
2047
- const uTransform = gl.getUniformLocation(program, "uTransform");
2048
- const uProjection = gl.getUniformLocation(program, "uProjection");
2049
- const uTexture = gl.getUniformLocation(program, "uTexture");
2050
- gl.uniformMatrix4fv(uTransform, false, transformMatrix);
2051
- gl.uniformMatrix4fv(uProjection, false, projectionMatrix);
2052
- gl.uniform1i(uTexture, 0);
2525
+ gl.uniformMatrix4fv(locations.uTransform, false, transformMatrix);
2526
+ gl.uniformMatrix4fv(locations.uProjection, false, projectionMatrix);
2527
+ gl.uniform1i(locations.uTexture, 0);
2053
2528
  gl.drawArrays(gl.TRIANGLES, 0, 6);
2054
- gl.disableVertexAttribArray(aPosition);
2055
- gl.disableVertexAttribArray(aTexCoord);
2529
+ gl.disableVertexAttribArray(locations.aPosition);
2530
+ gl.disableVertexAttribArray(locations.aTexCoord);
2056
2531
  gl.deleteTexture(texture);
2057
2532
  gl.deleteBuffer(vertexBuffer);
2058
2533
  gl.bindTexture(gl.TEXTURE_2D, null);
2059
- gl.deleteTexture(texture);
2534
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
2535
+ gl.disable(gl.BLEND);
2060
2536
  gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
2061
- gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
2062
2537
  return {
2063
2538
  canvas,
2064
- rect: rectAfterTransforms,
2065
- cleanup: () => {
2066
- const loseContext = gl.getExtension("WEBGL_lose_context");
2067
- if (loseContext) {
2068
- loseContext.loseContext();
2069
- }
2070
- }
2539
+ rect: rectAfterTransforms
2071
2540
  };
2072
2541
  };
2073
2542
 
@@ -2089,22 +2558,20 @@ var handle3dTransform = ({
2089
2558
  matrix,
2090
2559
  precomposeRect,
2091
2560
  tempCanvas,
2092
- rectAfterTransforms
2561
+ rectAfterTransforms,
2562
+ internalState
2093
2563
  }) => {
2094
- const {
2095
- canvas: transformed,
2096
- rect: transformedRect,
2097
- cleanup
2098
- } = transformIn3d({
2564
+ const { canvas: transformed, rect: transformedRect } = transformIn3d({
2099
2565
  untransformedRect: precomposeRect,
2100
2566
  matrix,
2101
2567
  sourceCanvas: tempCanvas,
2102
- rectAfterTransforms
2568
+ rectAfterTransforms,
2569
+ internalState
2103
2570
  });
2104
2571
  if (transformedRect.width <= 0 || transformedRect.height <= 0) {
2105
2572
  return null;
2106
2573
  }
2107
- return [transformed, cleanup];
2574
+ return transformed;
2108
2575
  };
2109
2576
 
2110
2577
  // src/drawing/handle-mask.ts
@@ -2124,7 +2591,9 @@ var handleMask = ({
2124
2591
  const gradient = createCanvasGradient({
2125
2592
  ctx: tempContext,
2126
2593
  rect: rectToFill,
2127
- gradientInfo
2594
+ gradientInfo,
2595
+ offsetLeft: 0,
2596
+ offsetTop: 0
2128
2597
  });
2129
2598
  tempContext.globalCompositeOperation = "destination-in";
2130
2599
  tempContext.fillStyle = gradient;
@@ -2145,7 +2614,8 @@ var precomposeDOMElement = async ({
2145
2614
  context: tempContext,
2146
2615
  logLevel,
2147
2616
  parentRect: boundingRect,
2148
- internalState
2617
+ internalState,
2618
+ onlyBackgroundClip: false
2149
2619
  });
2150
2620
  return { tempCanvas, tempContext };
2151
2621
  };
@@ -2235,7 +2705,6 @@ var processNode = async ({
2235
2705
  internalState
2236
2706
  });
2237
2707
  let drawable = tempCanvas;
2238
- let cleanupWebGL = () => {};
2239
2708
  const rectAfterTransforms = roundToExpandRect(transformDOMRect({
2240
2709
  rect: precomposeRect,
2241
2710
  matrix: totalMatrix
@@ -2253,18 +2722,17 @@ var processNode = async ({
2253
2722
  matrix: totalMatrix,
2254
2723
  precomposeRect,
2255
2724
  tempCanvas: drawable,
2256
- rectAfterTransforms
2725
+ rectAfterTransforms,
2726
+ internalState
2257
2727
  });
2258
2728
  if (t) {
2259
- const [transformed, cleanup] = t;
2260
- drawable = transformed;
2261
- cleanupWebGL = cleanup;
2729
+ drawable = t;
2262
2730
  }
2263
2731
  }
2264
2732
  const previousTransform = context.getTransform();
2265
2733
  if (drawable) {
2266
2734
  context.setTransform(new DOMMatrix);
2267
- context.drawImage(drawable, rectAfterTransforms.left - parentRect.x, rectAfterTransforms.top - parentRect.y, rectAfterTransforms.width, rectAfterTransforms.height);
2735
+ context.drawImage(drawable, 0, drawable.height - rectAfterTransforms.height, rectAfterTransforms.width, rectAfterTransforms.height, rectAfterTransforms.left - parentRect.x, rectAfterTransforms.top - parentRect.y, rectAfterTransforms.width, rectAfterTransforms.height);
2268
2736
  context.setTransform(previousTransform);
2269
2737
  Internals5.Log.trace({
2270
2738
  logLevel,
@@ -2276,7 +2744,6 @@ var processNode = async ({
2276
2744
  });
2277
2745
  }
2278
2746
  reset();
2279
- cleanupWebGL();
2280
2747
  return { type: "skip-children" };
2281
2748
  }
2282
2749
  const { cleanupAfterChildren } = await drawElement({
@@ -2287,7 +2754,9 @@ var processNode = async ({
2287
2754
  opacity,
2288
2755
  totalMatrix,
2289
2756
  parentRect,
2290
- logLevel
2757
+ logLevel,
2758
+ element,
2759
+ internalState
2291
2760
  });
2292
2761
  reset();
2293
2762
  return { type: "continue", cleanupAfterChildren };
@@ -2411,18 +2880,19 @@ function findLineBreaks(span, rtl) {
2411
2880
  // src/drawing/text/draw-text.ts
2412
2881
  var drawText = ({
2413
2882
  span,
2414
- logLevel
2883
+ logLevel,
2884
+ onlyBackgroundClip
2415
2885
  }) => {
2416
2886
  const drawFn = ({ dimensions: rect, computedStyle, contextToDraw }) => {
2417
2887
  const {
2418
2888
  fontFamily,
2419
2889
  fontSize,
2420
2890
  fontWeight,
2421
- color,
2422
2891
  direction,
2423
2892
  writingMode,
2424
2893
  letterSpacing,
2425
- textTransform
2894
+ textTransform,
2895
+ webkitTextFillColor
2426
2896
  } = computedStyle;
2427
2897
  const isVertical = writingMode !== "horizontal-tb";
2428
2898
  if (isVertical) {
@@ -2435,7 +2905,7 @@ var drawText = ({
2435
2905
  contextToDraw.save();
2436
2906
  const fontSizePx = parseFloat(fontSize);
2437
2907
  contextToDraw.font = `${fontWeight} ${fontSizePx}px ${fontFamily}`;
2438
- contextToDraw.fillStyle = color;
2908
+ contextToDraw.fillStyle = onlyBackgroundClip ? "black" : webkitTextFillColor;
2439
2909
  contextToDraw.letterSpacing = letterSpacing;
2440
2910
  const isRTL = direction === "rtl";
2441
2911
  contextToDraw.textAlign = isRTL ? "right" : "left";
@@ -2469,7 +2939,8 @@ var handleTextNode = async ({
2469
2939
  logLevel,
2470
2940
  parentRect,
2471
2941
  internalState,
2472
- rootElement
2942
+ rootElement,
2943
+ onlyBackgroundClip
2473
2944
  }) => {
2474
2945
  const span = document.createElement("span");
2475
2946
  const parent = node.parentNode;
@@ -2481,7 +2952,7 @@ var handleTextNode = async ({
2481
2952
  const value = await processNode({
2482
2953
  context,
2483
2954
  element: span,
2484
- draw: drawText({ span, logLevel }),
2955
+ draw: drawText({ span, logLevel, onlyBackgroundClip }),
2485
2956
  logLevel,
2486
2957
  parentRect,
2487
2958
  internalState,
@@ -2492,6 +2963,38 @@ var handleTextNode = async ({
2492
2963
  return value;
2493
2964
  };
2494
2965
 
2966
+ // src/tree-walker-cleanup-after-children.ts
2967
+ var createTreeWalkerCleanupAfterChildren = (treeWalker) => {
2968
+ const cleanupAfterChildren = [];
2969
+ const checkCleanUpAtBeginningOfIteration = () => {
2970
+ for (let i = 0;i < cleanupAfterChildren.length; ) {
2971
+ const cleanup = cleanupAfterChildren[i];
2972
+ if (!(cleanup.element === treeWalker.currentNode || cleanup.element.contains(treeWalker.currentNode))) {
2973
+ cleanup.cleanupFn();
2974
+ cleanupAfterChildren.splice(i, 1);
2975
+ } else {
2976
+ i++;
2977
+ }
2978
+ }
2979
+ };
2980
+ const addCleanup = (element, cleanupFn) => {
2981
+ cleanupAfterChildren.unshift({
2982
+ element,
2983
+ cleanupFn
2984
+ });
2985
+ };
2986
+ const cleanupInTheEndOfTheIteration = () => {
2987
+ for (const cleanup of cleanupAfterChildren) {
2988
+ cleanup.cleanupFn();
2989
+ }
2990
+ };
2991
+ return {
2992
+ checkCleanUpAtBeginningOfIteration,
2993
+ addCleanup,
2994
+ cleanupInTheEndOfTheIteration
2995
+ };
2996
+ };
2997
+
2495
2998
  // src/compose.ts
2496
2999
  var walkOverNode = ({
2497
3000
  node,
@@ -2499,7 +3002,8 @@ var walkOverNode = ({
2499
3002
  logLevel,
2500
3003
  parentRect,
2501
3004
  internalState,
2502
- rootElement
3005
+ rootElement,
3006
+ onlyBackgroundClip
2503
3007
  }) => {
2504
3008
  if (node instanceof HTMLElement || node instanceof SVGElement) {
2505
3009
  return processNode({
@@ -2519,46 +3023,55 @@ var walkOverNode = ({
2519
3023
  logLevel,
2520
3024
  parentRect,
2521
3025
  internalState,
2522
- rootElement
3026
+ rootElement,
3027
+ onlyBackgroundClip
2523
3028
  });
2524
3029
  }
2525
3030
  throw new Error("Unknown node type");
2526
3031
  };
3032
+ var getFilterFunction = (node) => {
3033
+ if (!(node instanceof Element)) {
3034
+ return NodeFilter.FILTER_ACCEPT;
3035
+ }
3036
+ if (node.parentElement instanceof SVGSVGElement) {
3037
+ return NodeFilter.FILTER_REJECT;
3038
+ }
3039
+ const computedStyle = getComputedStyle(node);
3040
+ if (computedStyle.display === "none") {
3041
+ return NodeFilter.FILTER_REJECT;
3042
+ }
3043
+ return NodeFilter.FILTER_ACCEPT;
3044
+ };
2527
3045
  var compose = async ({
2528
3046
  element,
2529
3047
  context,
2530
3048
  logLevel,
2531
3049
  parentRect,
2532
- internalState
3050
+ internalState,
3051
+ onlyBackgroundClip
2533
3052
  }) => {
2534
- const cleanupAfterChildren = [];
2535
- const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, (node) => {
2536
- if (node instanceof Element) {
2537
- if (node.parentElement instanceof SVGSVGElement) {
2538
- return NodeFilter.FILTER_REJECT;
2539
- }
2540
- const computedStyle = getComputedStyle(node);
2541
- return computedStyle.display === "none" ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
3053
+ const treeWalker = document.createTreeWalker(element, onlyBackgroundClip ? NodeFilter.SHOW_TEXT : NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, getFilterFunction);
3054
+ if (onlyBackgroundClip) {
3055
+ treeWalker.nextNode();
3056
+ if (!treeWalker.currentNode) {
3057
+ return;
2542
3058
  }
2543
- return NodeFilter.FILTER_ACCEPT;
2544
- });
3059
+ }
3060
+ const {
3061
+ checkCleanUpAtBeginningOfIteration,
3062
+ addCleanup,
3063
+ cleanupInTheEndOfTheIteration
3064
+ } = createTreeWalkerCleanupAfterChildren(treeWalker);
2545
3065
  while (true) {
2546
- for (let i = 0;i < cleanupAfterChildren.length; ) {
2547
- const cleanup = cleanupAfterChildren[i];
2548
- if (!(cleanup.element === treeWalker.currentNode || cleanup.element.contains(treeWalker.currentNode))) {
2549
- cleanup.cleanupFn();
2550
- cleanupAfterChildren.splice(i, 1);
2551
- } else {
2552
- i++;
2553
- }
2554
- }
3066
+ checkCleanUpAtBeginningOfIteration();
2555
3067
  const val = await walkOverNode({
2556
3068
  node: treeWalker.currentNode,
2557
3069
  context,
2558
3070
  logLevel,
2559
3071
  parentRect,
2560
3072
  internalState,
2561
- rootElement: element
3073
+ rootElement: element,
3074
+ onlyBackgroundClip
2562
3075
  });
2563
3076
  if (val.type === "skip-children") {
2564
3077
  if (!skipToNextNonDescendant(treeWalker)) {
@@ -2566,19 +3079,14 @@ var compose = async ({
2566
3079
  }
2567
3080
  } else {
2568
3081
  if (val.cleanupAfterChildren) {
2569
- cleanupAfterChildren.unshift({
2570
- element: treeWalker.currentNode,
2571
- cleanupFn: val.cleanupAfterChildren
2572
- });
3082
+ addCleanup(treeWalker.currentNode, val.cleanupAfterChildren);
2573
3083
  }
2574
3084
  if (!treeWalker.nextNode()) {
2575
3085
  break;
2576
3086
  }
2577
3087
  }
2578
3088
  }
2579
- for (const cleanup of cleanupAfterChildren) {
2580
- cleanup.cleanupFn();
2581
- }
3089
+ cleanupInTheEndOfTheIteration();
2582
3090
  };
2583
3091
 
2584
3092
  // src/take-screenshot.ts
@@ -2599,7 +3107,8 @@ var createFrame = async ({
2599
3107
  context,
2600
3108
  logLevel,
2601
3109
  parentRect: new DOMRect(0, 0, width, height),
2602
- internalState
3110
+ internalState,
3111
+ onlyBackgroundClip: false
2603
3112
  });
2604
3113
  return canvas;
2605
3114
  };
@@ -3130,6 +3639,7 @@ async function internalRenderStillOnWeb({
3130
3639
  });
3131
3640
  throw err;
3132
3641
  } finally {
3642
+ internalState.cleanup();
3133
3643
  cleanupScaffold();
3134
3644
  }
3135
3645
  }