@remotion/studio 4.0.468 → 4.0.470

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 (134) hide show
  1. package/dist/Studio.js +1 -1
  2. package/dist/api/save-render-output.js +3 -12
  3. package/dist/components/AudioWaveform.d.ts +1 -0
  4. package/dist/components/AudioWaveform.js +41 -23
  5. package/dist/components/CompositionSelectorItem.js +1 -1
  6. package/dist/components/ContextMenu.d.ts +1 -0
  7. package/dist/components/ContextMenu.js +8 -3
  8. package/dist/components/EditorContent.js +5 -4
  9. package/dist/components/EditorGuides/Guide.js +1 -1
  10. package/dist/components/ExpandedTracksProvider.js +3 -8
  11. package/dist/components/Menu/MenuItem.d.ts +1 -1
  12. package/dist/components/Menu/MenuItem.js +2 -2
  13. package/dist/components/Menu/MenuSubItem.js +5 -5
  14. package/dist/components/MenuBuildIndicator.js +0 -1
  15. package/dist/components/NewComposition/InputDragger.js +1 -0
  16. package/dist/components/Preview.js +4 -1
  17. package/dist/components/PreviewToolbar.js +2 -4
  18. package/dist/components/SelectedOutlineOverlay.d.ts +18 -0
  19. package/dist/components/SelectedOutlineOverlay.js +645 -0
  20. package/dist/components/Timeline/Timeline.js +18 -3
  21. package/dist/components/Timeline/TimelineDeleteKeybindings.d.ts +2 -0
  22. package/dist/components/Timeline/TimelineDeleteKeybindings.js +86 -0
  23. package/dist/components/Timeline/TimelineDragHandler.js +19 -244
  24. package/dist/components/Timeline/{TimelineEffectGroupRow.d.ts → TimelineEffectItem.d.ts} +1 -1
  25. package/dist/components/Timeline/{TimelineEffectGroupRow.js → TimelineEffectItem.js} +61 -35
  26. package/dist/components/Timeline/{TimelineEffectFieldRow.d.ts → TimelineEffectPropItem.d.ts} +4 -1
  27. package/dist/components/Timeline/{TimelineEffectFieldRow.js → TimelineEffectPropItem.js} +100 -16
  28. package/dist/components/Timeline/TimelineExpandArrowButton.js +5 -1
  29. package/dist/components/Timeline/TimelineExpandedKeyframeRow.d.ts +11 -0
  30. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +55 -0
  31. package/dist/components/Timeline/TimelineExpandedRow.d.ts +1 -0
  32. package/dist/components/Timeline/TimelineExpandedRow.js +29 -11
  33. package/dist/components/Timeline/TimelineExpandedSection.d.ts +1 -0
  34. package/dist/components/Timeline/TimelineExpandedSection.js +4 -4
  35. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.d.ts +1 -1
  36. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +9 -120
  37. package/dist/components/Timeline/TimelineFieldLabel.d.ts +6 -0
  38. package/dist/components/Timeline/TimelineFieldLabel.js +30 -0
  39. package/dist/components/Timeline/TimelineInOutDragHandler.d.ts +2 -0
  40. package/dist/components/Timeline/TimelineInOutDragHandler.js +324 -0
  41. package/dist/components/Timeline/TimelineInOutPointer.js +3 -1
  42. package/dist/components/Timeline/TimelineInOutPointerHandle.d.ts +1 -0
  43. package/dist/components/Timeline/TimelineInOutPointerHandle.js +5 -4
  44. package/dist/components/Timeline/TimelineItemStack.d.ts +5 -0
  45. package/dist/components/Timeline/TimelineItemStack.js +82 -0
  46. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +17 -0
  47. package/dist/components/Timeline/TimelineKeyframeControls.js +217 -0
  48. package/dist/components/Timeline/TimelineKeyframeDiamond.d.ts +7 -0
  49. package/dist/components/Timeline/TimelineKeyframeDiamond.js +88 -0
  50. package/dist/components/Timeline/TimelineKeyframedValue.d.ts +8 -0
  51. package/dist/components/Timeline/TimelineKeyframedValue.js +36 -0
  52. package/dist/components/Timeline/TimelineLayerEye.js +1 -0
  53. package/dist/components/Timeline/TimelineList.js +3 -11
  54. package/dist/components/Timeline/TimelineMediaInfo.d.ts +13 -1
  55. package/dist/components/Timeline/TimelineMediaInfo.js +33 -80
  56. package/dist/components/Timeline/TimelineRowChrome.d.ts +10 -1
  57. package/dist/components/Timeline/TimelineRowChrome.js +64 -6
  58. package/dist/components/Timeline/TimelineSchemaField.js +7 -2
  59. package/dist/components/Timeline/TimelineSelection.d.ts +85 -0
  60. package/dist/components/Timeline/TimelineSelection.js +417 -0
  61. package/dist/components/Timeline/TimelineSequence.d.ts +2 -0
  62. package/dist/components/Timeline/TimelineSequence.js +18 -6
  63. package/dist/components/Timeline/TimelineSequenceFrame.js +1 -0
  64. package/dist/components/Timeline/{TimelineListItem.d.ts → TimelineSequenceItem.d.ts} +2 -2
  65. package/dist/components/Timeline/{TimelineListItem.js → TimelineSequenceItem.js} +148 -63
  66. package/dist/components/Timeline/TimelineSequenceName.d.ts +7 -0
  67. package/dist/components/Timeline/TimelineSequenceName.js +50 -0
  68. package/dist/components/Timeline/{TimelineFieldRow.d.ts → TimelineSequencePropItem.d.ts} +5 -3
  69. package/dist/components/Timeline/TimelineSequencePropItem.js +183 -0
  70. package/dist/components/Timeline/TimelineTimeIndicators.js +0 -1
  71. package/dist/components/Timeline/TimelineTrack.d.ts +5 -0
  72. package/dist/components/Timeline/TimelineTrack.js +66 -0
  73. package/dist/components/Timeline/TimelineTracks.js +2 -16
  74. package/dist/components/Timeline/TimelineTranslateField.js +14 -22
  75. package/dist/components/Timeline/TimelineUvCoordinateField.d.ts +11 -0
  76. package/dist/components/Timeline/TimelineUvCoordinateField.js +126 -0
  77. package/dist/components/Timeline/TimelineVideoInfo.js +11 -12
  78. package/dist/components/Timeline/call-add-keyframe.d.ts +23 -0
  79. package/dist/components/Timeline/call-add-keyframe.js +54 -0
  80. package/dist/components/Timeline/call-delete-keyframe.d.ts +21 -0
  81. package/dist/components/Timeline/call-delete-keyframe.js +50 -0
  82. package/dist/components/Timeline/delete-selected-keyframe.d.ts +11 -0
  83. package/dist/components/Timeline/delete-selected-keyframe.js +51 -0
  84. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +17 -0
  85. package/dist/components/Timeline/delete-selected-timeline-item.js +183 -0
  86. package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +13 -0
  87. package/dist/components/Timeline/duplicate-selected-timeline-item.js +66 -0
  88. package/dist/components/Timeline/find-track-for-node-path-info.d.ts +7 -0
  89. package/dist/components/Timeline/find-track-for-node-path-info.js +13 -0
  90. package/dist/components/Timeline/get-keyframe-navigation.d.ts +9 -0
  91. package/dist/components/Timeline/get-keyframe-navigation.js +26 -0
  92. package/dist/components/Timeline/get-node-keyframes.d.ts +11 -0
  93. package/dist/components/Timeline/get-node-keyframes.js +23 -0
  94. package/dist/components/Timeline/get-timeline-keyframes.js +6 -8
  95. package/dist/components/Timeline/parse-keyframe-field-from-node-path.d.ts +8 -0
  96. package/dist/components/Timeline/parse-keyframe-field-from-node-path.js +26 -0
  97. package/dist/components/Timeline/save-sequence-prop.d.ts +14 -2
  98. package/dist/components/Timeline/save-sequence-prop.js +42 -7
  99. package/dist/components/Timeline/timeline-field-row-layout.d.ts +1 -0
  100. package/dist/components/Timeline/timeline-field-row-layout.js +11 -1
  101. package/dist/components/Timeline/timeline-row-layout.d.ts +1 -0
  102. package/dist/components/Timeline/timeline-row-layout.js +2 -1
  103. package/dist/components/Timeline/timeline-translate-utils.d.ts +2 -0
  104. package/dist/components/Timeline/timeline-translate-utils.js +20 -0
  105. package/dist/components/Timeline/use-expanded-track-keyframe-rows.d.ts +17 -0
  106. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +52 -0
  107. package/dist/components/Timeline/use-open-sequence-in-editor.d.ts +6 -0
  108. package/dist/components/Timeline/use-open-sequence-in-editor.js +31 -0
  109. package/dist/components/composition-menu-items.js +32 -1
  110. package/dist/error-overlay/remotion-overlay/OpenInEditor.js +0 -1
  111. package/dist/esm/{chunk-8q828zk7.js → chunk-dny42qnq.js} +10566 -6221
  112. package/dist/esm/internals.mjs +10566 -6221
  113. package/dist/esm/previewEntry.mjs +10548 -6203
  114. package/dist/esm/renderEntry.mjs +3 -1
  115. package/dist/helpers/colors.d.ts +1 -1
  116. package/dist/helpers/colors.js +1 -1
  117. package/dist/helpers/format-file-location.d.ts +9 -0
  118. package/dist/helpers/format-file-location.js +27 -0
  119. package/dist/helpers/get-box-quads-polyfill-internals.d.ts +82 -0
  120. package/dist/helpers/get-box-quads-polyfill-internals.js +2395 -0
  121. package/dist/helpers/get-box-quads-ponyfill.d.ts +10 -0
  122. package/dist/helpers/get-box-quads-ponyfill.js +23 -0
  123. package/dist/helpers/open-in-editor.d.ts +1 -1
  124. package/dist/helpers/open-in-editor.js +11 -26
  125. package/dist/helpers/timeline-layout.d.ts +8 -7
  126. package/dist/helpers/timeline-layout.js +9 -8
  127. package/dist/helpers/timeline-node-path-key.d.ts +2 -0
  128. package/dist/helpers/timeline-node-path-key.js +10 -0
  129. package/dist/helpers/use-menu-structure.js +8 -16
  130. package/dist/renderEntry.js +2 -2
  131. package/package.json +10 -10
  132. package/dist/components/Timeline/TimelineFieldRow.js +0 -113
  133. package/dist/components/Timeline/TimelineStack/index.d.ts +0 -8
  134. package/dist/components/Timeline/TimelineStack/index.js +0 -119
@@ -0,0 +1,2395 @@
1
+ "use strict";
2
+ /* eslint-disable */
3
+ /*
4
+ * Geometry helpers adapted from getBoxQuadsPolyfill
5
+ * https://github.com/jogibear9988/getBoxQuadsPolyfill (MIT)
6
+ *
7
+ * Used as a Remotion ponyfill only — does not patch globals.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.addPolyfill = addPolyfill;
11
+ exports.patchAdoptNode = patchAdoptNode;
12
+ exports.convertQuadFromNode = convertQuadFromNode;
13
+ exports.convertRectFromNode = convertRectFromNode;
14
+ exports.convertPointFromNode = convertPointFromNode;
15
+ exports.clearCache = clearCache;
16
+ exports.useCache = useCache;
17
+ exports.getBoxQuads = getBoxQuads;
18
+ exports.getElementSize = getElementSize;
19
+ exports.getResultingTransformationBetweenElementAndAllAncestors = getResultingTransformationBetweenElementAndAllAncestors;
20
+ exports.getElementCombinedTransform = getElementCombinedTransform;
21
+ //todo:
22
+ //transform-box (SVGs) https://developer.mozilla.org/en-US/docs/Web/CSS/transform-box
23
+ // =============================================================================
24
+ // PERFORMANCE FIXES APPLIED (14 total):
25
+ //
26
+ // FIX 1 – getElementCombinedTransform: check parent perspective inside fast-path
27
+ // so identity elements return immediately on non-3D pages.
28
+ // FIX 2 – getResultingTransformationBetweenElementAndAllAncestors: guard initial
29
+ // self-transform multiply with isIdentity check.
30
+ // FIX 3 – All translate matrix calls: skip new DOMMatrix().translateSelf(0,0)
31
+ // when both offsets are zero (hot loop, flat layouts).
32
+ // FIX 4 – getElementOffsetsInContainer/HTMLElement: defer getCachedComputedStyle
33
+ // until inside the `includeScroll` branch where it's actually needed.
34
+ // FIX 5 – getResultingTransformationBetweenElementAndAllAncestors: guard
35
+ // projectTo2D calls with !is2D check to skip style reads on 2D pages.
36
+ // FIX 6 – getResultingTransformationBetweenElementAndAllAncestors: cache the
37
+ // result on the early-return (ancestor found) path, not just fallthrough.
38
+ // FIX 7 – getBoxQuads: reuse the Range already created for the multi-fragment
39
+ // text check; pass clientRects/boundingRect into getElementSize to
40
+ // avoid creating a second Range for Text nodes.
41
+ // FIX 8 – getBoxQuads: split the per-point `!o` branch out of the loop into
42
+ // two separate loops to eliminate the branch test on every iteration.
43
+ // FIX 9 – getBoxQuads: hoist parseFloat calls for box offsets (margin/padding/
44
+ // content) so values are computed once, not 4x inside the loop.
45
+ // FIX 10 – getElementCombinedTransform: check hasTransform first (most common
46
+ // non-identity case) so cheaper checks fire before heavier ones.
47
+ // FIX 11 – getElementCombinedTransform: skip transform-origin wrap/unwrap when
48
+ // origin is (0, 0, 0), saving two DOMMatrix allocations.
49
+ // FIX 12 – getResultingTransformationBetweenElementAndAllAncestors: reuse
50
+ // getElementCombinedTransform result across loop iterations (carry
51
+ // parent transform forward instead of recomputing next iteration).
52
+ // FIX 13 – Repeated cross-realm instanceof checks: cache constructors from the
53
+ // node's window at function entry to avoid repeated property lookups.
54
+ // (Applied in getElementSize and getBoxQuads hot paths.)
55
+ // FIX 14 – transformPointBox: parse style values once per call, not once per
56
+ // property access (avoids repeated parseFloat on shared string props).
57
+ // =============================================================================
58
+ /**
59
+ * @param {globalThis} windowObj?
60
+ * @param {boolean=} force
61
+ */
62
+ function addPolyfill(windowObj = window, force = false) {
63
+ var _a;
64
+ (_a = windowObj.__getBoxQuadsPolyfillFns) !== null && _a !== void 0 ? _a : (windowObj.__getBoxQuadsPolyfillFns = {});
65
+ windowObj.__getBoxQuadsPolyfillFns.getBoxQuads = getBoxQuads;
66
+ windowObj.__getBoxQuadsPolyfillFns.convertQuadFromNode = convertQuadFromNode;
67
+ windowObj.__getBoxQuadsPolyfillFns.convertRectFromNode = convertRectFromNode;
68
+ windowObj.__getBoxQuadsPolyfillFns.convertPointFromNode =
69
+ convertPointFromNode;
70
+ if (force || !windowObj.Node.prototype.getBoxQuads) {
71
+ //@ts-ignore
72
+ windowObj.Node.prototype.getBoxQuads = function (options) {
73
+ return windowObj.__getBoxQuadsPolyfillFns.getBoxQuads(this, options);
74
+ };
75
+ }
76
+ if (force || !windowObj.Node.prototype.convertQuadFromNode) {
77
+ //@ts-ignore
78
+ windowObj.Node.prototype.convertQuadFromNode = function (quad, from, options) {
79
+ return windowObj.__getBoxQuadsPolyfillFns.convertQuadFromNode(this, quad, from, options);
80
+ };
81
+ }
82
+ if (force || !windowObj.Node.prototype.convertRectFromNode) {
83
+ //@ts-ignore
84
+ windowObj.Node.prototype.convertRectFromNode = function (rect, from, options) {
85
+ return windowObj.__getBoxQuadsPolyfillFns.convertRectFromNode(this, rect, from, options);
86
+ };
87
+ }
88
+ if (force || !windowObj.Node.prototype.convertPointFromNode) {
89
+ //@ts-ignore
90
+ windowObj.Node.prototype.convertPointFromNode = function (point, from, options) {
91
+ return windowObj.__getBoxQuadsPolyfillFns.convertPointFromNode(this, point, from, options);
92
+ };
93
+ }
94
+ }
95
+ /**
96
+ * @param {globalThis} windowObj?
97
+ */
98
+ function patchAdoptNode(windowObj = window) {
99
+ if (!windowObj.Node.prototype.getBoxQuads) {
100
+ //@ts-ignore
101
+ windowObj.Node.prototype.getBoxQuads = function (options) {
102
+ return getBoxQuads(this, options);
103
+ };
104
+ }
105
+ if (!windowObj.Node.prototype.convertQuadFromNode) {
106
+ //@ts-ignore
107
+ windowObj.Node.prototype.convertQuadFromNode = function (quad, from, options) {
108
+ return convertQuadFromNode(this, quad, from, options);
109
+ };
110
+ }
111
+ if (!windowObj.Node.prototype.convertRectFromNode) {
112
+ //@ts-ignore
113
+ windowObj.Node.prototype.convertRectFromNode = function (rect, from, options) {
114
+ return convertRectFromNode(this, rect, from, options);
115
+ };
116
+ }
117
+ if (!windowObj.Node.prototype.convertPointFromNode) {
118
+ //@ts-ignore
119
+ windowObj.Node.prototype.convertPointFromNode = function (point, from, options) {
120
+ return convertPointFromNode(this, point, from, options);
121
+ };
122
+ }
123
+ }
124
+ /**
125
+ * @param {Node} node
126
+ * @param {DOMQuadInit} quad
127
+ * @param {Element} from
128
+ * @param {{fromBox?: 'margin'|'border'|'padding'|'content', toBox?: 'margin'|'border'|'padding'|'content', iframes?: HTMLIFrameElement[]}=} options
129
+ * @returns {DOMQuad}
130
+ */
131
+ function convertQuadFromNode(node, quad, from, options) {
132
+ var _a, _b;
133
+ const ancestor = ((_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).document.body;
134
+ const m1 = getResultingTransformationBetweenElementAndAllAncestors(from, ancestor, options === null || options === void 0 ? void 0 : options.iframes, true);
135
+ const m2 = getResultingTransformationBetweenElementAndAllAncestors(node, ancestor, options === null || options === void 0 ? void 0 : options.iframes, true).inverse();
136
+ if ((options === null || options === void 0 ? void 0 : options.fromBox) && (options === null || options === void 0 ? void 0 : options.fromBox) !== 'border') {
137
+ const fromStyle = getCachedComputedStyle(from);
138
+ quad = new DOMQuad(transformPointBox(quad.p1, options.fromBox, fromStyle, -1), transformPointBox(quad.p2, options.fromBox, fromStyle, -1), transformPointBox(quad.p3, options.fromBox, fromStyle, -1), transformPointBox(quad.p4, options.fromBox, fromStyle, -1));
139
+ }
140
+ let res = new DOMQuad(m2.transformPoint(m1.transformPoint(quad.p1)), m2.transformPoint(m1.transformPoint(quad.p2)), m2.transformPoint(m1.transformPoint(quad.p3)), m2.transformPoint(m1.transformPoint(quad.p4)));
141
+ if ((options === null || options === void 0 ? void 0 : options.toBox) &&
142
+ (options === null || options === void 0 ? void 0 : options.toBox) !== 'border' &&
143
+ (node instanceof Element ||
144
+ node instanceof ((_b = node.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).Element)) {
145
+ const nodeStyle = getCachedComputedStyle(node);
146
+ res = new DOMQuad(transformPointBox(res.p1, options.toBox, nodeStyle, -1), transformPointBox(res.p2, options.toBox, nodeStyle, -1), transformPointBox(res.p3, options.toBox, nodeStyle, -1), transformPointBox(res.p4, options.toBox, nodeStyle, -1));
147
+ }
148
+ return res;
149
+ }
150
+ /**
151
+ * @param {Node} node
152
+ * @param {{x: number, y: number, width: number, height: number}} rect
153
+ * @param {Element} from
154
+ * @param {{fromBox?: 'margin'|'border'|'padding'|'content', toBox?: 'margin'|'border'|'padding'|'content', iframes?: HTMLIFrameElement[]}=} options
155
+ * @returns {DOMQuad}
156
+ */
157
+ function convertRectFromNode(node, rect, from, options) {
158
+ var _a, _b;
159
+ const ancestor = ((_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).document.body
160
+ .parentElement;
161
+ const m1 = getResultingTransformationBetweenElementAndAllAncestors(from, ancestor, options === null || options === void 0 ? void 0 : options.iframes, true);
162
+ const m2 = getResultingTransformationBetweenElementAndAllAncestors(node, ancestor, options === null || options === void 0 ? void 0 : options.iframes, true).inverse();
163
+ if ((options === null || options === void 0 ? void 0 : options.fromBox) && (options === null || options === void 0 ? void 0 : options.fromBox) !== 'border') {
164
+ const p = transformPointBox(new DOMPoint(rect.x, rect.y), options.fromBox, getCachedComputedStyle(from), 1);
165
+ rect = new DOMRect(p.x, p.y, rect.width, rect.height);
166
+ }
167
+ let res = new DOMQuad(m2.transformPoint(m1.transformPoint(new DOMPoint(rect.x, rect.y))), m2.transformPoint(m1.transformPoint(new DOMPoint(rect.x + rect.width, rect.y))), m2.transformPoint(m1.transformPoint(new DOMPoint(rect.x + rect.width, rect.y + rect.height))), m2.transformPoint(m1.transformPoint(new DOMPoint(rect.x, rect.y + rect.height))));
168
+ if ((options === null || options === void 0 ? void 0 : options.toBox) &&
169
+ (options === null || options === void 0 ? void 0 : options.toBox) !== 'border' &&
170
+ (node instanceof Element ||
171
+ node instanceof ((_b = node.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).Element)) {
172
+ const nodeStyle = getCachedComputedStyle(node);
173
+ res = new DOMQuad(transformPointBox(res.p1, options.toBox, nodeStyle, -1), transformPointBox(res.p2, options.toBox, nodeStyle, -1), transformPointBox(res.p3, options.toBox, nodeStyle, -1), transformPointBox(res.p4, options.toBox, nodeStyle, -1));
174
+ }
175
+ return res;
176
+ }
177
+ /**
178
+ * @param {Node} node
179
+ * @param {DOMPointInit} point
180
+ * @param {Element} from
181
+ * @param {{fromBox?: 'margin'|'border'|'padding'|'content', toBox?: 'margin'|'border'|'padding'|'content', iframes?: HTMLIFrameElement[]}=} options
182
+ * @returns {DOMPoint}
183
+ */
184
+ function convertPointFromNode(node, point, from, options) {
185
+ var _a, _b;
186
+ const ancestor = ((_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).document.body
187
+ .parentElement;
188
+ const m1 = getResultingTransformationBetweenElementAndAllAncestors(from, ancestor, options === null || options === void 0 ? void 0 : options.iframes, true);
189
+ const m2 = getResultingTransformationBetweenElementAndAllAncestors(node, ancestor, options === null || options === void 0 ? void 0 : options.iframes, true).inverse();
190
+ if ((options === null || options === void 0 ? void 0 : options.fromBox) && (options === null || options === void 0 ? void 0 : options.fromBox) !== 'border') {
191
+ point = transformPointBox(point, options.fromBox, getCachedComputedStyle(from), 1);
192
+ }
193
+ let res = m2.transformPoint(m1.transformPoint(point));
194
+ if ((options === null || options === void 0 ? void 0 : options.toBox) &&
195
+ (options === null || options === void 0 ? void 0 : options.toBox) !== 'border' &&
196
+ (node instanceof Element ||
197
+ node instanceof ((_b = node.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).Element)) {
198
+ res = transformPointBox(res, options.toBox, getCachedComputedStyle(node), -1);
199
+ }
200
+ return res;
201
+ }
202
+ /**
203
+ * @param {DOMPointInit} point
204
+ * @param {'margin'|'border'|'padding'|'content'} box
205
+ * @param {CSSStyleDeclaration} style
206
+ * @param {number} operator
207
+ * @returns {DOMPoint}
208
+ *
209
+ * FIX 14: Parse each style value once and reuse, rather than calling parseFloat
210
+ * multiple times on the same property (e.g. borderLeftWidth used twice in 'content').
211
+ */
212
+ function transformPointBox(point, box, style, operator) {
213
+ if (box === 'margin') {
214
+ const mLeft = parseFloat(style.marginLeft);
215
+ const mTop = parseFloat(style.marginTop);
216
+ return new DOMPoint(point.x - operator * mLeft, point.y - operator * mTop);
217
+ }
218
+ else if (box === 'padding') {
219
+ const bLeft = parseFloat(style.borderLeftWidth);
220
+ const bTop = parseFloat(style.borderTopWidth);
221
+ return new DOMPoint(point.x + operator * bLeft, point.y + operator * bTop);
222
+ }
223
+ else if (box === 'content') {
224
+ const bLeft = parseFloat(style.borderLeftWidth);
225
+ const bTop = parseFloat(style.borderTopWidth);
226
+ const pLeft = parseFloat(style.paddingLeft);
227
+ const pTop = parseFloat(style.paddingTop);
228
+ return new DOMPoint(point.x + operator * (bLeft + pLeft), point.y + operator * (bTop + pTop));
229
+ }
230
+ //@ts-ignore
231
+ return point;
232
+ }
233
+ /** @type { WeakMap<Node, number> } */
234
+ let hash;
235
+ /** @type { Map<string, DOMQuad[]> } */
236
+ let boxQuadsCache;
237
+ /** @type { Map<string, DOMMatrix> } */
238
+ let transformCache;
239
+ /** @type { WeakMap<Node, CSSStyleDeclaration> } */
240
+ let computedStyleCache;
241
+ let hashId = 0;
242
+ function clearCache() {
243
+ boxQuadsCache.clear();
244
+ transformCache.clear();
245
+ computedStyleCache = new WeakMap();
246
+ }
247
+ function useCache() {
248
+ hash = new WeakMap();
249
+ boxQuadsCache = new Map();
250
+ transformCache = new Map();
251
+ computedStyleCache = new WeakMap();
252
+ }
253
+ /**
254
+ * @param {Element} element
255
+ * @returns {CSSStyleDeclaration}
256
+ */
257
+ function getCachedComputedStyle(element) {
258
+ var _a, _b;
259
+ if (!computedStyleCache) {
260
+ return ((_a = element.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).getComputedStyle(element);
261
+ }
262
+ let style = computedStyleCache.get(element);
263
+ if (!style) {
264
+ style = ((_b = element.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).getComputedStyle(element);
265
+ computedStyleCache.set(element, style);
266
+ }
267
+ return style;
268
+ }
269
+ /**
270
+ * @param {Node} node
271
+ * @returns {boolean}
272
+ */
273
+ function isElementNode(node) {
274
+ return !!node && node.nodeType === Node.ELEMENT_NODE;
275
+ }
276
+ /**
277
+ * @param {Node} element
278
+ * @returns {number}
279
+ */
280
+ function getElementZoom(element) {
281
+ if (!isElementNode(element)) {
282
+ return 1;
283
+ }
284
+ /** @type {Element} */
285
+ // @ts-ignore
286
+ const actualElement = element;
287
+ const zoom = getCachedComputedStyle(actualElement).zoom;
288
+ if (!zoom || zoom === 'normal') {
289
+ return 1;
290
+ }
291
+ if (zoom.endsWith('%')) {
292
+ const percentage = parseFloat(zoom);
293
+ return Number.isFinite(percentage) && percentage > 0 ? percentage / 100 : 1;
294
+ }
295
+ const value = parseFloat(zoom);
296
+ return Number.isFinite(value) && value > 0 ? value : 1;
297
+ }
298
+ /**
299
+ * `zoom` scales the element's internal coordinate space while also shifting the
300
+ * element within its parent from the top-center anchor in the default writing-mode.
301
+ * For descendant coordinates we keep the scale in the matrix pipeline and apply
302
+ * the parent-position shift separately in the layout translation step.
303
+ * @param {Node} element
304
+ * @returns {DOMMatrix}
305
+ */
306
+ function getElementZoomScaleTransform(element) {
307
+ if (!isElementNode(element)) {
308
+ return new DOMMatrix();
309
+ }
310
+ const zoom = getElementZoom(element);
311
+ if (zoom === 1) {
312
+ return new DOMMatrix();
313
+ }
314
+ return new DOMMatrix().scaleSelf(zoom);
315
+ }
316
+ /**
317
+ * @param {Node} element
318
+ * @param {HTMLIFrameElement[]=} iframes
319
+ * @param {boolean=} includeZoom
320
+ * @returns {DOMMatrix}
321
+ */
322
+ function getElementTransformWithZoom(element, iframes, includeZoom = true) {
323
+ const transform = getElementCombinedTransform(element, iframes);
324
+ if (!includeZoom || !isElementNode(element)) {
325
+ return transform;
326
+ }
327
+ const zoomTransform = getElementZoomScaleTransform(element);
328
+ if (zoomTransform.isIdentity) {
329
+ return transform;
330
+ }
331
+ // `zoom` scales transform translations as well as the element's local axes,
332
+ // so it needs to wrap the transform matrix instead of being appended to it.
333
+ return zoomTransform.multiply(transform);
334
+ }
335
+ /**
336
+ * @param {Node} node
337
+ * @param {{box?: 'margin'|'border'|'padding'|'content', relativeTo?: Element, iframes?: HTMLIFrameElement[]}=} options
338
+ * @returns {DOMQuad[]}
339
+ */
340
+ function getBoxQuads(node, options) {
341
+ var _a, _b, _c, _d, _e, _f;
342
+ const defaultRelativeTo = (_a = node.ownerDocument.documentElement) !== null && _a !== void 0 ? _a : node.ownerDocument.body;
343
+ const relativeTo = (_b = options === null || options === void 0 ? void 0 : options.relativeTo) !== null && _b !== void 0 ? _b : defaultRelativeTo;
344
+ const viewportRoot = (_c = node.ownerDocument.documentElement) !== null && _c !== void 0 ? _c : node.ownerDocument.body;
345
+ const resolveFixedThroughViewport = relativeTo !== viewportRoot &&
346
+ shouldResolveFixedPositionThroughViewport(node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes);
347
+ let key;
348
+ if (boxQuadsCache) {
349
+ let i1 = hash.get(node);
350
+ if (i1 === undefined)
351
+ hash.set(node, (i1 = hashId++));
352
+ let i2 = hash.get(relativeTo);
353
+ if (i2 === undefined)
354
+ hash.set(relativeTo, (i2 = hashId++));
355
+ key = i1 + '_' + i2 + '_' + ((_d = options === null || options === void 0 ? void 0 : options.box) !== null && _d !== void 0 ? _d : 'border');
356
+ const q = boxQuadsCache.get(key);
357
+ if (q)
358
+ return q;
359
+ }
360
+ /** @type {DOMMatrix} */
361
+ let originalElementAndAllParentsMultipliedMatrix = getResultingTransformationBetweenElementAndAllAncestors(node, resolveFixedThroughViewport ? viewportRoot : relativeTo, options === null || options === void 0 ? void 0 : options.iframes);
362
+ // FIX 13: Cache cross-realm constructors once per call.
363
+ const win = (_e = node.ownerDocument.defaultView) !== null && _e !== void 0 ? _e : window;
364
+ const _Text = win.Text;
365
+ const _SVGGraphicsElement = win.SVGGraphicsElement;
366
+ const _SVGSVGElement = win.SVGSVGElement;
367
+ // For text nodes, check for multiple fragments (multi-column layout, line-wrapping).
368
+ // getClientRects() returns one rect per line-box fragment; getBoundingClientRect()
369
+ // only returns the union AABB, so without this we'd always get one quad.
370
+ if (node instanceof Text || node instanceof _Text) {
371
+ const canUseViewportTextRects = originalElementAndAllParentsMultipliedMatrix.is2D &&
372
+ Math.abs(originalElementAndAllParentsMultipliedMatrix.b) < 1e-10 &&
373
+ Math.abs(originalElementAndAllParentsMultipliedMatrix.c) < 1e-10;
374
+ // FIX 7: Create the Range once here and reuse it for both the multi-fragment
375
+ // check and the single-fragment size fallback, avoiding a second Range
376
+ // allocation inside getElementSize for Text nodes.
377
+ const range = node.ownerDocument.createRange();
378
+ range.selectNodeContents(node);
379
+ const clientRects = range.getClientRects();
380
+ const viewportRoot = (_f = node.ownerDocument.documentElement) !== null && _f !== void 0 ? _f : node.ownerDocument.body;
381
+ const viewportRootRect = viewportRoot === null || viewportRoot === void 0 ? void 0 : viewportRoot.getBoundingClientRect();
382
+ const convertViewportRectToRelativeQuad = (rect) => {
383
+ var _a, _b;
384
+ if (relativeTo === viewportRoot) {
385
+ return new DOMQuad(new DOMPoint(rect.x, rect.y), new DOMPoint(rect.x + rect.width, rect.y), new DOMPoint(rect.x + rect.width, rect.y + rect.height), new DOMPoint(rect.x, rect.y + rect.height));
386
+ }
387
+ const rectInViewportRoot = new DOMRect(rect.x - ((_a = viewportRootRect === null || viewportRootRect === void 0 ? void 0 : viewportRootRect.x) !== null && _a !== void 0 ? _a : 0), rect.y - ((_b = viewportRootRect === null || viewportRootRect === void 0 ? void 0 : viewportRootRect.y) !== null && _b !== void 0 ? _b : 0), rect.width, rect.height);
388
+ return convertRectFromNode(relativeTo, rectInViewportRoot, viewportRoot, {
389
+ iframes: options === null || options === void 0 ? void 0 : options.iframes,
390
+ });
391
+ };
392
+ if (clientRects.length > 1) {
393
+ if (canUseViewportTextRects) {
394
+ const quads = [];
395
+ for (const cr of clientRects) {
396
+ if (cr.width < 1 && cr.height < 1)
397
+ continue;
398
+ quads.push(convertViewportRectToRelativeQuad(cr));
399
+ }
400
+ if (quads.length > 0) {
401
+ if (boxQuadsCache)
402
+ boxQuadsCache.set(key, quads);
403
+ return quads;
404
+ }
405
+ }
406
+ // Work via the parent element so rotation is handled correctly.
407
+ // Each fragment's viewport rect (from getClientRects) is an AABB;
408
+ // its center equals the actual geometric center regardless of rotation.
409
+ // We convert that center to parent-local space, recover the fragment's
410
+ // local dimensions via the 2x2 AABB system, then apply the parent's
411
+ // accumulated matrix to build proper (rotated) quads in relativeTo-space.
412
+ const parent = getParentElementIncludingSlots(node, options === null || options === void 0 ? void 0 : options.iframes);
413
+ const M_parent = getResultingTransformationBetweenElementAndAllAncestors(parent, resolveFixedThroughViewport ? viewportRoot : relativeTo, options === null || options === void 0 ? void 0 : options.iframes);
414
+ const parentCss = getElementCombinedTransform(parent, options === null || options === void 0 ? void 0 : options.iframes);
415
+ const pr = parent.getBoundingClientRect();
416
+ const pa = parentCss.a, pb = parentCss.b, pc = parentCss.c, pd = parentCss.d;
417
+ // AABB center of the transformed parent equals its geometric center.
418
+ // geometric_center_screen = screen(0,0) + L * (pw/2, ph/2)
419
+ // => screen(0,0) = AABB_center - L * (pw/2, ph/2)
420
+ //@ts-ignore
421
+ const pw = parent.offsetWidth;
422
+ //@ts-ignore
423
+ const ph = parent.offsetHeight;
424
+ const parentOriginX = pr.x + pr.width / 2 - ((pa * pw) / 2 + (pc * ph) / 2);
425
+ const parentOriginY = pr.y + pr.height / 2 - ((pb * pw) / 2 + (pd * ph) / 2);
426
+ const linearDet = pa * pd - pb * pc;
427
+ const absA = Math.abs(pa), absB = Math.abs(pb);
428
+ const absDet = absA * absA - absB * absB;
429
+ const quads = [];
430
+ for (const cr of clientRects) {
431
+ if (cr.width < 1 && cr.height < 1)
432
+ continue;
433
+ // Fragment AABB center -> parent-local center via inverse CSS transform
434
+ const dx = cr.x + cr.width / 2 - parentOriginX;
435
+ const dy = cr.y + cr.height / 2 - parentOriginY;
436
+ let lcx, lcy;
437
+ if (Math.abs(linearDet) > 1e-10) {
438
+ lcx = (pd * dx - pc * dy) / linearDet;
439
+ lcy = (pa * dy - pb * dx) / linearDet;
440
+ }
441
+ else {
442
+ lcx = dx;
443
+ lcy = dy;
444
+ }
445
+ // Fragment dimensions in parent-local via 2x2 AABB system
446
+ let tw, th;
447
+ if (Math.abs(absDet) > 1e-6) {
448
+ tw = Math.max(0, (absA * cr.width - absB * cr.height) / absDet);
449
+ th = Math.max(0, (absA * cr.height - absB * cr.width) / absDet);
450
+ }
451
+ else {
452
+ // Singular (~45 deg): use CSS line-height as th
453
+ const cs = getCachedComputedStyle(parent);
454
+ th = Math.max(0, parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2 || 16);
455
+ const denom = Math.max(absA, absB);
456
+ tw =
457
+ denom > 1e-6
458
+ ? Math.max(0, (cr.width - th * absB) / denom)
459
+ : cr.width;
460
+ }
461
+ // Fragment top-left in parent-local, then transform all 4 corners via M_parent
462
+ const lx = lcx - tw / 2, ly = lcy - th / 2;
463
+ const quad = new DOMQuad(M_parent.transformPoint(new DOMPoint(lx, ly)), M_parent.transformPoint(new DOMPoint(lx + tw, ly)), M_parent.transformPoint(new DOMPoint(lx + tw, ly + th)), M_parent.transformPoint(new DOMPoint(lx, ly + th)));
464
+ quads.push(finishQuadRelativeToTarget(quad, node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes, resolveFixedThroughViewport, options === null || options === void 0 ? void 0 : options.box));
465
+ }
466
+ if (quads.length > 0) {
467
+ if (boxQuadsCache)
468
+ boxQuadsCache.set(key, quads);
469
+ return quads;
470
+ }
471
+ }
472
+ // FIX 7 (continued): Single-fragment text — reuse the already-fetched
473
+ // bounding rect so getElementSize doesn't create a second Range.
474
+ const textBoundingRect = range.getBoundingClientRect();
475
+ if (canUseViewportTextRects) {
476
+ const tQuad = [convertViewportRectToRelativeQuad(textBoundingRect)];
477
+ if (boxQuadsCache)
478
+ boxQuadsCache.set(key, tQuad);
479
+ return tQuad;
480
+ }
481
+ const { width: tw, height: th } = _getTextNodeSize(originalElementAndAllParentsMultipliedMatrix, textBoundingRect, node);
482
+ const is2Dt = originalElementAndAllParentsMultipliedMatrix.is2D;
483
+ const tCorners = [
484
+ new DOMPoint(0, 0),
485
+ new DOMPoint(tw, 0),
486
+ new DOMPoint(tw, th),
487
+ new DOMPoint(0, th),
488
+ ];
489
+ /** @type {[DOMPoint,DOMPoint,DOMPoint,DOMPoint]} */
490
+ //@ts-ignore
491
+ const tPoints = Array(4);
492
+ if (is2Dt) {
493
+ for (let i = 0; i < 4; i++)
494
+ tPoints[i] = tCorners[i].matrixTransform(originalElementAndAllParentsMultipliedMatrix);
495
+ }
496
+ else {
497
+ for (let i = 0; i < 4; i++) {
498
+ tPoints[i] = projectPoint(tCorners[i], originalElementAndAllParentsMultipliedMatrix).matrixTransform(originalElementAndAllParentsMultipliedMatrix);
499
+ tPoints[i] = as2DPoint(tPoints[i]);
500
+ }
501
+ }
502
+ const tQuad = [
503
+ finishQuadRelativeToTarget(new DOMQuad(tPoints[0], tPoints[1], tPoints[2], tPoints[3]), node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes, resolveFixedThroughViewport, options === null || options === void 0 ? void 0 : options.box),
504
+ ];
505
+ if (boxQuadsCache)
506
+ boxQuadsCache.set(key, tQuad);
507
+ return tQuad;
508
+ }
509
+ if ((node instanceof SVGGraphicsElement ||
510
+ node instanceof _SVGGraphicsElement) &&
511
+ !(node instanceof SVGSVGElement || node instanceof _SVGSVGElement)) {
512
+ const bbox = node.getBBox();
513
+ const visualBox = getSvgVisualBox(node, bbox);
514
+ const x0 = visualBox.x - bbox.x;
515
+ const y0 = visualBox.y - bbox.y;
516
+ const x1 = x0 + visualBox.width;
517
+ const y1 = y0 + visualBox.height;
518
+ const screenPts = [
519
+ new DOMPoint(visualBox.x, visualBox.y),
520
+ new DOMPoint(visualBox.x + visualBox.width, visualBox.y),
521
+ new DOMPoint(visualBox.x + visualBox.width, visualBox.y + visualBox.height),
522
+ new DOMPoint(visualBox.x, visualBox.y + visualBox.height),
523
+ ];
524
+ const pts = [
525
+ new DOMPoint(x0, y0),
526
+ new DOMPoint(x1, y0),
527
+ new DOMPoint(x1, y1),
528
+ new DOMPoint(x0, y1),
529
+ ];
530
+ const screenCtm = !hasTransformedHtmlAncestor(node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes)
531
+ ? node.getScreenCTM()
532
+ : null;
533
+ if (screenCtm) {
534
+ const screenQuad = new DOMQuad(screenPts[0].matrixTransform(screenCtm), screenPts[1].matrixTransform(screenCtm), screenPts[2].matrixTransform(screenCtm), screenPts[3].matrixTransform(screenCtm));
535
+ const svgQuad = [
536
+ convertViewportQuadToRelativeNode(screenQuad, node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes),
537
+ ];
538
+ if (boxQuadsCache)
539
+ boxQuadsCache.set(key, svgQuad);
540
+ return svgQuad;
541
+ }
542
+ /** @type {[DOMPoint,DOMPoint,DOMPoint,DOMPoint]} */
543
+ //@ts-ignore
544
+ const points = Array(4);
545
+ if (originalElementAndAllParentsMultipliedMatrix.is2D) {
546
+ for (let i = 0; i < 4; i++)
547
+ points[i] = pts[i].matrixTransform(originalElementAndAllParentsMultipliedMatrix);
548
+ }
549
+ else {
550
+ for (let i = 0; i < 4; i++) {
551
+ points[i] = projectPoint(pts[i], originalElementAndAllParentsMultipliedMatrix).matrixTransform(originalElementAndAllParentsMultipliedMatrix);
552
+ points[i] = as2DPoint(points[i]);
553
+ }
554
+ }
555
+ const svgQuad = [
556
+ finishQuadRelativeToTarget(new DOMQuad(points[0], points[1], points[2], points[3]), node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes, resolveFixedThroughViewport, options === null || options === void 0 ? void 0 : options.box),
557
+ ];
558
+ if (boxQuadsCache)
559
+ boxQuadsCache.set(key, svgQuad);
560
+ return svgQuad;
561
+ }
562
+ if (node instanceof win.Element &&
563
+ relativeTo === node.ownerDocument.documentElement &&
564
+ (!(options === null || options === void 0 ? void 0 : options.box) || options.box === 'border') &&
565
+ originalElementAndAllParentsMultipliedMatrix.is2D &&
566
+ Math.abs(originalElementAndAllParentsMultipliedMatrix.b) < 1e-10 &&
567
+ Math.abs(originalElementAndAllParentsMultipliedMatrix.c) < 1e-10) {
568
+ const rect = node.getBoundingClientRect();
569
+ const viewportQuad = [
570
+ new DOMQuad(new DOMPoint(rect.x, rect.y), new DOMPoint(rect.x + rect.width, rect.y), new DOMPoint(rect.x + rect.width, rect.y + rect.height), new DOMPoint(rect.x, rect.y + rect.height)),
571
+ ];
572
+ if (boxQuadsCache)
573
+ boxQuadsCache.set(key, viewportQuad);
574
+ return viewportQuad;
575
+ }
576
+ let { width, height } = getElementSize(node, originalElementAndAllParentsMultipliedMatrix);
577
+ // FIX 13: cache cross-realm Element constructor.
578
+ const _Element = win.Element;
579
+ const is2D = originalElementAndAllParentsMultipliedMatrix.is2D;
580
+ // FIX 8 + FIX 9: Split the `!o` branch out of the point loop into two
581
+ // separate code paths. In the box-offset path, parse style values once
582
+ // (FIX 9) and use them directly, eliminating 4x redundant parseFloat calls.
583
+ if (node instanceof Element || node instanceof _Element) {
584
+ const box = options === null || options === void 0 ? void 0 : options.box;
585
+ if (box === 'margin' || box === 'padding' || box === 'content') {
586
+ const cs = getCachedComputedStyle(node);
587
+ let x0, y0, x1, y1, x2, y2, x3, y3;
588
+ if (box === 'margin') {
589
+ const mL = parseFloat(cs.marginLeft);
590
+ const mT = parseFloat(cs.marginTop);
591
+ const mR = parseFloat(cs.marginRight);
592
+ const mB = parseFloat(cs.marginBottom);
593
+ x0 = -mL;
594
+ y0 = -mT;
595
+ x1 = width + mR;
596
+ y1 = -mT;
597
+ x2 = width + mR;
598
+ y2 = height + mB;
599
+ x3 = -mL;
600
+ y3 = height + mB;
601
+ }
602
+ else if (box === 'padding') {
603
+ const bL = parseFloat(cs.borderLeftWidth);
604
+ const bT = parseFloat(cs.borderTopWidth);
605
+ const bR = parseFloat(cs.borderRightWidth);
606
+ const bB = parseFloat(cs.borderBottomWidth);
607
+ x0 = bL;
608
+ y0 = bT;
609
+ x1 = width - bR;
610
+ y1 = bT;
611
+ x2 = width - bR;
612
+ y2 = height - bB;
613
+ x3 = bL;
614
+ y3 = height - bB;
615
+ }
616
+ else {
617
+ // content
618
+ const bL = parseFloat(cs.borderLeftWidth);
619
+ const bT = parseFloat(cs.borderTopWidth);
620
+ const bR = parseFloat(cs.borderRightWidth);
621
+ const bB = parseFloat(cs.borderBottomWidth);
622
+ const pL = parseFloat(cs.paddingLeft);
623
+ const pT = parseFloat(cs.paddingTop);
624
+ const pR = parseFloat(cs.paddingRight);
625
+ const pB = parseFloat(cs.paddingBottom);
626
+ x0 = bL + pL;
627
+ y0 = bT + pT;
628
+ x1 = width - bR - pR;
629
+ y1 = bT + pT;
630
+ x2 = width - bR - pR;
631
+ y2 = height - bB - pB;
632
+ x3 = bL + pL;
633
+ y3 = height - bB - pB;
634
+ }
635
+ const pts = [
636
+ new DOMPoint(x0, y0),
637
+ new DOMPoint(x1, y1),
638
+ new DOMPoint(x2, y2),
639
+ new DOMPoint(x3, y3),
640
+ ];
641
+ /** @type {[DOMPoint,DOMPoint,DOMPoint,DOMPoint]} */
642
+ //@ts-ignore
643
+ const points = Array(4);
644
+ if (is2D) {
645
+ for (let i = 0; i < 4; i++)
646
+ points[i] = pts[i].matrixTransform(originalElementAndAllParentsMultipliedMatrix);
647
+ }
648
+ else {
649
+ for (let i = 0; i < 4; i++) {
650
+ points[i] = projectPoint(pts[i], originalElementAndAllParentsMultipliedMatrix).matrixTransform(originalElementAndAllParentsMultipliedMatrix);
651
+ points[i] = as2DPoint(points[i]);
652
+ }
653
+ }
654
+ const quad = [
655
+ finishQuadRelativeToTarget(new DOMQuad(points[0], points[1], points[2], points[3]), node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes, resolveFixedThroughViewport, options === null || options === void 0 ? void 0 : options.box),
656
+ ];
657
+ if (boxQuadsCache)
658
+ boxQuadsCache.set(key, quad);
659
+ return quad;
660
+ }
661
+ }
662
+ // FIX 8: No-offset path — plain loop, no `!o` branch test per iteration.
663
+ const corners = [
664
+ new DOMPoint(0, 0),
665
+ new DOMPoint(width, 0),
666
+ new DOMPoint(width, height),
667
+ new DOMPoint(0, height),
668
+ ];
669
+ /** @type {[DOMPoint,DOMPoint,DOMPoint,DOMPoint]} */
670
+ //@ts-ignore
671
+ const points = Array(4);
672
+ if (is2D) {
673
+ for (let i = 0; i < 4; i++)
674
+ points[i] = corners[i].matrixTransform(originalElementAndAllParentsMultipliedMatrix);
675
+ }
676
+ else {
677
+ for (let i = 0; i < 4; i++) {
678
+ points[i] = projectPoint(corners[i], originalElementAndAllParentsMultipliedMatrix).matrixTransform(originalElementAndAllParentsMultipliedMatrix);
679
+ points[i] = as2DPoint(points[i]);
680
+ }
681
+ }
682
+ const quad = [
683
+ finishQuadRelativeToTarget(new DOMQuad(points[0], points[1], points[2], points[3]), node, relativeTo, options === null || options === void 0 ? void 0 : options.iframes, resolveFixedThroughViewport, options === null || options === void 0 ? void 0 : options.box),
684
+ ];
685
+ if (boxQuadsCache)
686
+ boxQuadsCache.set(key, quad);
687
+ return quad;
688
+ }
689
+ function finishQuadRelativeToTarget(quad, node, relativeTo, iframes, resolveFixedThroughViewport, box) {
690
+ if (resolveFixedThroughViewport) {
691
+ quad = alignViewportBorderQuadToRenderedBox(quad, node, box);
692
+ return convertViewportQuadToRelativeNode(quad, node, relativeTo, iframes);
693
+ }
694
+ return toViewportRelativeDocumentElementQuad(quad, node, relativeTo, iframes);
695
+ }
696
+ function alignViewportBorderQuadToRenderedBox(quad, node, box) {
697
+ var _a;
698
+ if (box && box !== 'border') {
699
+ return quad;
700
+ }
701
+ const win = (_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
702
+ if (!(node instanceof win.Element)) {
703
+ return quad;
704
+ }
705
+ const rect = node.getBoundingClientRect();
706
+ const left = Math.min(quad.p1.x, quad.p2.x, quad.p3.x, quad.p4.x);
707
+ const top = Math.min(quad.p1.y, quad.p2.y, quad.p3.y, quad.p4.y);
708
+ const dx = rect.left - left;
709
+ const dy = rect.top - top;
710
+ if (Math.abs(dx) < 1e-10 && Math.abs(dy) < 1e-10) {
711
+ return quad;
712
+ }
713
+ const translate = (point) => new DOMPoint(point.x + dx, point.y + dy, point.z, point.w);
714
+ return new DOMQuad(translate(quad.p1), translate(quad.p2), translate(quad.p3), translate(quad.p4));
715
+ }
716
+ function convertViewportQuadToRelativeNode(quad, node, relativeTo, iframes) {
717
+ var _a, _b;
718
+ const viewportRoot = (_a = node.ownerDocument.documentElement) !== null && _a !== void 0 ? _a : node.ownerDocument.body;
719
+ if (relativeTo === viewportRoot) {
720
+ return quad;
721
+ }
722
+ const win = (_b = node.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window;
723
+ if (relativeTo instanceof win.SVGElement) {
724
+ const relativeScreenCtm = relativeTo.getScreenCTM();
725
+ if (relativeScreenCtm) {
726
+ const inverse = relativeScreenCtm.inverse();
727
+ return new DOMQuad(quad.p1.matrixTransform(inverse), quad.p2.matrixTransform(inverse), quad.p3.matrixTransform(inverse), quad.p4.matrixTransform(inverse));
728
+ }
729
+ }
730
+ if (relativeTo.ownerDocument === node.ownerDocument &&
731
+ relativeTo instanceof win.HTMLElement) {
732
+ const htmlQuad = convertViewportQuadToHtmlElement(quad, relativeTo, iframes);
733
+ if (htmlQuad) {
734
+ return htmlQuad;
735
+ }
736
+ }
737
+ if (relativeTo === node.ownerDocument.body) {
738
+ const relativeRect = relativeTo.getBoundingClientRect();
739
+ const scrollLeft = relativeTo.scrollLeft || 0;
740
+ const scrollTop = relativeTo.scrollTop || 0;
741
+ return new DOMQuad(new DOMPoint(quad.p1.x - relativeRect.x + scrollLeft, quad.p1.y - relativeRect.y + scrollTop), new DOMPoint(quad.p2.x - relativeRect.x + scrollLeft, quad.p2.y - relativeRect.y + scrollTop), new DOMPoint(quad.p3.x - relativeRect.x + scrollLeft, quad.p3.y - relativeRect.y + scrollTop), new DOMPoint(quad.p4.x - relativeRect.x + scrollLeft, quad.p4.y - relativeRect.y + scrollTop));
742
+ }
743
+ return convertQuadFromNode(relativeTo, quad, viewportRoot, { iframes });
744
+ }
745
+ function convertViewportQuadToHtmlElement(quad, relativeTo, iframes) {
746
+ const scale = getPositiveAxisAlignedViewportScale(relativeTo, iframes);
747
+ if (!scale) {
748
+ return null;
749
+ }
750
+ const relativeRect = relativeTo.getBoundingClientRect();
751
+ const scaleX = scale.x;
752
+ const scaleY = scale.y;
753
+ if (!Number.isFinite(scaleX) ||
754
+ !Number.isFinite(scaleY) ||
755
+ Math.abs(scaleX) < 1e-10 ||
756
+ Math.abs(scaleY) < 1e-10) {
757
+ return null;
758
+ }
759
+ const scrollLeft = relativeTo.scrollLeft || 0;
760
+ const scrollTop = relativeTo.scrollTop || 0;
761
+ const convertPoint = (point) => new DOMPoint((point.x - relativeRect.x) / scaleX + scrollLeft, (point.y - relativeRect.y) / scaleY + scrollTop);
762
+ return new DOMQuad(convertPoint(quad.p1), convertPoint(quad.p2), convertPoint(quad.p3), convertPoint(quad.p4));
763
+ }
764
+ function getPositiveAxisAlignedViewportScale(element, iframes) {
765
+ var _a;
766
+ const win = (_a = element.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
767
+ const scale = { x: 1, y: 1 };
768
+ let current = element;
769
+ while (current && current !== element.ownerDocument.documentElement) {
770
+ if (current instanceof win.Element) {
771
+ const style = getCachedComputedStyle(current);
772
+ const transformScale = getPositiveAxisAlignedTransformScale(style);
773
+ if (!transformScale) {
774
+ return null;
775
+ }
776
+ const zoom = getElementZoom(current);
777
+ scale.x *= transformScale.x * zoom;
778
+ scale.y *= transformScale.y * zoom;
779
+ }
780
+ current = getParentElementIncludingSlots(current, iframes);
781
+ }
782
+ return scale;
783
+ }
784
+ function getPositiveAxisAlignedTransformScale(style) {
785
+ if (style.perspective && style.perspective !== 'none') {
786
+ return null;
787
+ }
788
+ if (style.rotate &&
789
+ style.rotate !== 'none' &&
790
+ !isZeroAngleValue(style.rotate)) {
791
+ return null;
792
+ }
793
+ const individualScale = parsePositiveScaleValue(style.scale);
794
+ if (!individualScale) {
795
+ return null;
796
+ }
797
+ const transform = style.transform;
798
+ if (!transform || transform === 'none') {
799
+ return individualScale;
800
+ }
801
+ if (transform.startsWith('matrix3d(')) {
802
+ const values = parseCssMatrixValues(transform);
803
+ if ((values === null || values === void 0 ? void 0 : values.length) === 16 &&
804
+ values[0] > 0 &&
805
+ values[5] > 0 &&
806
+ Math.abs(values[1]) < 1e-10 &&
807
+ Math.abs(values[4]) < 1e-10 &&
808
+ Math.abs(values[3]) < 1e-10 &&
809
+ Math.abs(values[7]) < 1e-10 &&
810
+ Math.abs(values[11]) < 1e-10) {
811
+ return {
812
+ x: individualScale.x * values[0],
813
+ y: individualScale.y * values[5],
814
+ };
815
+ }
816
+ return null;
817
+ }
818
+ if (transform.startsWith('matrix(')) {
819
+ const values = parseCssMatrixValues(transform);
820
+ if ((values === null || values === void 0 ? void 0 : values.length) === 6 &&
821
+ values[0] > 0 &&
822
+ values[3] > 0 &&
823
+ Math.abs(values[1]) < 1e-10 &&
824
+ Math.abs(values[2]) < 1e-10) {
825
+ return {
826
+ x: individualScale.x * values[0],
827
+ y: individualScale.y * values[3],
828
+ };
829
+ }
830
+ return null;
831
+ }
832
+ return null;
833
+ }
834
+ function parsePositiveScaleValue(value) {
835
+ var _a;
836
+ if (!value || value === 'none') {
837
+ return { x: 1, y: 1 };
838
+ }
839
+ const parts = value
840
+ .split(/\s+/)
841
+ .map((part) => parseFloat(part))
842
+ .filter(Number.isFinite);
843
+ if (parts.length === 0 ||
844
+ parts[0] <= 0 ||
845
+ (parts[1] != null && parts[1] <= 0)) {
846
+ return null;
847
+ }
848
+ return { x: parts[0], y: (_a = parts[1]) !== null && _a !== void 0 ? _a : parts[0] };
849
+ }
850
+ function parseCssMatrixValues(transform) {
851
+ const start = transform.indexOf('(');
852
+ const end = transform.lastIndexOf(')');
853
+ if (start < 0 || end <= start) {
854
+ return null;
855
+ }
856
+ const values = transform
857
+ .slice(start + 1, end)
858
+ .split(',')
859
+ .map((value) => parseFloat(value.trim()));
860
+ return values.every(Number.isFinite) ? values : null;
861
+ }
862
+ function isZeroAngleValue(value) {
863
+ const matches = value.match(/-?\d*\.?\d+(?:e[-+]?\d+)?/gi);
864
+ if (!(matches === null || matches === void 0 ? void 0 : matches.length)) {
865
+ return false;
866
+ }
867
+ const angle = parseFloat(matches[matches.length - 1]);
868
+ return Number.isFinite(angle) && Math.abs(angle) < 1e-10;
869
+ }
870
+ function hasTransformedHtmlAncestor(node, relativeTo, iframes) {
871
+ var _a;
872
+ const win = (_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
873
+ let element = getParentElementIncludingSlots(node, iframes);
874
+ while (element &&
875
+ element !== relativeTo &&
876
+ element !== node.ownerDocument.documentElement) {
877
+ if (element instanceof win.HTMLElement) {
878
+ const css = getCachedComputedStyle(element);
879
+ if (transformProperties.some((value) => css[value] ? css[value] !== 'none' : false)) {
880
+ return true;
881
+ }
882
+ }
883
+ element = getParentElementIncludingSlots(element, iframes);
884
+ }
885
+ return false;
886
+ }
887
+ function toViewportRelativeDocumentElementQuad(quad, node, relativeTo, iframes) {
888
+ var _a, _b, _c, _d, _e;
889
+ if (relativeTo !== node.ownerDocument.documentElement) {
890
+ return quad;
891
+ }
892
+ if (isViewportFixedAnchoredNode(node, iframes)) {
893
+ return quad;
894
+ }
895
+ const win = (_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
896
+ const scrollX = (_c = (_b = win.scrollX) !== null && _b !== void 0 ? _b : node.ownerDocument.documentElement.scrollLeft) !== null && _c !== void 0 ? _c : 0;
897
+ const scrollY = (_e = (_d = win.scrollY) !== null && _d !== void 0 ? _d : node.ownerDocument.documentElement.scrollTop) !== null && _e !== void 0 ? _e : 0;
898
+ if (scrollX === 0 && scrollY === 0) {
899
+ return quad;
900
+ }
901
+ return new DOMQuad(new DOMPoint(quad.p1.x - scrollX, quad.p1.y - scrollY), new DOMPoint(quad.p2.x - scrollX, quad.p2.y - scrollY), new DOMPoint(quad.p3.x - scrollX, quad.p3.y - scrollY), new DOMPoint(quad.p4.x - scrollX, quad.p4.y - scrollY));
902
+ }
903
+ function isViewportFixedAnchoredNode(node, iframes) {
904
+ var _a;
905
+ const win = (_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
906
+ let element = null;
907
+ if (node instanceof win.Text) {
908
+ element = getParentElementIncludingSlots(node, iframes);
909
+ }
910
+ else if (node instanceof win.Element) {
911
+ element = node;
912
+ }
913
+ while (element && element !== node.ownerDocument.documentElement) {
914
+ const cs = getCachedComputedStyle(element);
915
+ if (cs.position === 'fixed') {
916
+ return getNearestFixedContainingBlock(element, iframes) == null;
917
+ }
918
+ element = getParentElementIncludingSlots(element, iframes);
919
+ }
920
+ return false;
921
+ }
922
+ function shouldResolveFixedPositionThroughViewport(node, relativeTo, iframes) {
923
+ var _a;
924
+ const win = (_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
925
+ let element = null;
926
+ if (node instanceof win.Text) {
927
+ element = getParentElementIncludingSlots(node, iframes);
928
+ }
929
+ else if (node instanceof win.Element) {
930
+ element = node;
931
+ }
932
+ while (element && element !== node.ownerDocument.documentElement) {
933
+ const cs = getCachedComputedStyle(element);
934
+ if (cs.position === 'fixed') {
935
+ const fixedContainer = getNearestFixedContainingBlock(element, iframes);
936
+ return (fixedContainer == null ||
937
+ (fixedContainer !== relativeTo &&
938
+ !isFlatTreeInclusiveAncestor(relativeTo, fixedContainer)));
939
+ }
940
+ if (element === relativeTo) {
941
+ break;
942
+ }
943
+ element = getParentElementIncludingSlots(element, iframes);
944
+ }
945
+ return false;
946
+ }
947
+ /**
948
+ * Compute width/height for a Text node given an already-fetched bounding rect.
949
+ * Extracted from getElementSize so getBoxQuads (FIX 7) can reuse the Range it
950
+ * already created, avoiding a second Range allocation.
951
+ * @param {DOMMatrix} matrix
952
+ * @param {DOMRect} targetRect
953
+ * @param {Text} node
954
+ */
955
+ function _getTextNodeSize(matrix, targetRect, node) {
956
+ var _a, _b;
957
+ const absA = Math.abs((_a = matrix === null || matrix === void 0 ? void 0 : matrix.a) !== null && _a !== void 0 ? _a : 1);
958
+ const absB = Math.abs((_b = matrix === null || matrix === void 0 ? void 0 : matrix.b) !== null && _b !== void 0 ? _b : 0);
959
+ const det = absA * absA - absB * absB; // cos(2*angle)*scale^2
960
+ let width, height;
961
+ if (Math.abs(det) > 1e-6) {
962
+ width = Math.max(0, (absA * targetRect.width - absB * targetRect.height) / det);
963
+ height = Math.max(0, (absA * targetRect.height - absB * targetRect.width) / det);
964
+ }
965
+ else {
966
+ // Singular (~45 deg rotation): use CSS line-height as the known height
967
+ const parentEl = node.parentElement;
968
+ let lineH = 16;
969
+ if (parentEl) {
970
+ const cs = getCachedComputedStyle(parentEl);
971
+ lineH = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2 || 16;
972
+ }
973
+ height = Math.max(0, lineH);
974
+ const denom = Math.max(absA, absB);
975
+ width =
976
+ denom > 1e-6
977
+ ? Math.max(0, (targetRect.width - height * absB) / denom)
978
+ : targetRect.width;
979
+ }
980
+ return { width, height };
981
+ }
982
+ //todo: https://drafts.csswg.org/css-transforms-2/#accumulated-3d-transformation-matrix-computation
983
+ // also good for writing a spec
984
+ // Find a value for z that will transform to 0. (from firefox matrix.h)
985
+ // or chromium https://github.com/chromium/chromium/blob/main/ui/gfx/geometry/transform.cc#L849
986
+ /**
987
+ * @param {DOMPoint} point
988
+ */
989
+ function projectPoint(point, m) {
990
+ const z = -(point.x * m.m13 + point.y * m.m23 + m.m43) / m.m33;
991
+ return new DOMPoint(point.x, point.y, z, 1);
992
+ }
993
+ /**
994
+ * convert a DOM-Point to 2D
995
+ * @param {DOMPoint} point
996
+ */
997
+ function as2DPoint(point) {
998
+ return new DOMPoint(point.x / point.w, point.y / point.w);
999
+ }
1000
+ /**
1001
+ * @param {Node} node
1002
+ * @param {DOMMatrix=} matrix
1003
+ */
1004
+ function getElementSize(node, matrix) {
1005
+ var _a, _b, _c;
1006
+ let width = 0;
1007
+ let height = 0;
1008
+ // FIX 13: Cache cross-realm constructors once.
1009
+ const win = (_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
1010
+ if (node instanceof HTMLElement || node instanceof win.HTMLElement) {
1011
+ width = node.offsetWidth;
1012
+ height = node.offsetHeight;
1013
+ }
1014
+ else if (node instanceof SVGSVGElement ||
1015
+ node instanceof win.SVGSVGElement) {
1016
+ width = node.width.baseVal.value;
1017
+ height = node.height.baseVal.value;
1018
+ }
1019
+ else if (node instanceof SVGGraphicsElement ||
1020
+ node instanceof win.SVGGraphicsElement) {
1021
+ const bbox = node.getBBox();
1022
+ width = bbox.width;
1023
+ height = bbox.height;
1024
+ }
1025
+ else if (node instanceof MathMLElement ||
1026
+ node instanceof win.MathMLElement) {
1027
+ const bbox = node.getBoundingClientRect();
1028
+ width = bbox.width / ((_b = matrix === null || matrix === void 0 ? void 0 : matrix.a) !== null && _b !== void 0 ? _b : 1);
1029
+ height = bbox.height / ((_c = matrix === null || matrix === void 0 ? void 0 : matrix.d) !== null && _c !== void 0 ? _c : 1);
1030
+ }
1031
+ else if (node instanceof Text || node instanceof win.Text) {
1032
+ // Note: getBoxQuads passes an already-fetched rect via _getTextNodeSize to
1033
+ // avoid this Range creation. This path serves external callers of getElementSize.
1034
+ const range = node.ownerDocument.createRange();
1035
+ range.selectNodeContents(node);
1036
+ const targetRect = range.getBoundingClientRect();
1037
+ const result = _getTextNodeSize(matrix, targetRect, node);
1038
+ width = result.width;
1039
+ height = result.height;
1040
+ }
1041
+ return { width, height };
1042
+ }
1043
+ function getSvgVisualBox(node, bbox) {
1044
+ const svgStyle = getCachedComputedStyle(node);
1045
+ const strokeWidth = svgStyle.stroke !== 'none' ? parseFloat(svgStyle.strokeWidth) || 0 : 0;
1046
+ if (strokeWidth <= 0) {
1047
+ return bbox;
1048
+ }
1049
+ const strokeInflation = getSvgStrokeInflation(node, bbox, strokeWidth);
1050
+ return new DOMRect(bbox.x - strokeInflation.left, bbox.y - strokeInflation.top, bbox.width + strokeInflation.left + strokeInflation.right, bbox.height + strokeInflation.top + strokeInflation.bottom);
1051
+ }
1052
+ function getSvgStrokeInflation(node, bbox, strokeWidth) {
1053
+ var _a;
1054
+ const halfStrokeWidth = strokeWidth / 2;
1055
+ if (node instanceof SVGLineElement ||
1056
+ node instanceof ((_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).SVGLineElement) {
1057
+ const x1 = node.x1.baseVal.value;
1058
+ const y1 = node.y1.baseVal.value;
1059
+ const x2 = node.x2.baseVal.value;
1060
+ const y2 = node.y2.baseVal.value;
1061
+ const dx = x2 - x1;
1062
+ const dy = y2 - y1;
1063
+ const length = Math.hypot(dx, dy);
1064
+ if (length > 1e-10) {
1065
+ let inflateX = (halfStrokeWidth * Math.abs(dy)) / length;
1066
+ let inflateY = (halfStrokeWidth * Math.abs(dx)) / length;
1067
+ const lineCap = getCachedComputedStyle(node).strokeLinecap;
1068
+ if (lineCap === 'round' || lineCap === 'square') {
1069
+ inflateX += (halfStrokeWidth * Math.abs(dx)) / length;
1070
+ inflateY += (halfStrokeWidth * Math.abs(dy)) / length;
1071
+ }
1072
+ return { left: inflateX, right: inflateX, top: inflateY, bottom: inflateY };
1073
+ }
1074
+ }
1075
+ const genericInflation = strokeWidth * 2;
1076
+ return {
1077
+ left: genericInflation,
1078
+ right: genericInflation,
1079
+ top: genericInflation,
1080
+ bottom: genericInflation,
1081
+ };
1082
+ }
1083
+ /**
1084
+ * @param {Node} node
1085
+ * @param {boolean} includeScroll
1086
+ * @param {HTMLIFrameElement[]} iframes
1087
+ */
1088
+ function getElementOffsetsInContainer(node, includeScroll, iframes) {
1089
+ var _a, _b, _c, _d, _e, _f;
1090
+ if (node instanceof HTMLElement ||
1091
+ node instanceof ((_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).HTMLElement) {
1092
+ // When <html> appears inside a shadow DOM canvas the browser reflects
1093
+ // body's top margin into html.offsetTop (but not offsetLeft), causing
1094
+ // a Y-only shift in the transform walk. The html element has no real
1095
+ // layout offset relative to its shadow-host container, so return 0,0.
1096
+ if (node instanceof HTMLHtmlElement ||
1097
+ node instanceof ((_b = node.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).HTMLHtmlElement) {
1098
+ return new DOMPoint(0, 0);
1099
+ }
1100
+ const cs = getCachedComputedStyle(node);
1101
+ if (cs.position === 'fixed') {
1102
+ const fixedContainer = getNearestFixedContainingBlock(node, iframes);
1103
+ if (!fixedContainer) {
1104
+ const left = cs.left && cs.left !== 'auto' ? parseFloat(cs.left) : node.offsetLeft;
1105
+ const top = cs.top && cs.top !== 'auto' ? parseFloat(cs.top) : node.offsetTop;
1106
+ return new DOMPoint(left, top);
1107
+ }
1108
+ const m = getResultingTransformationBetweenElementAndAllAncestors(fixedContainer, node.ownerDocument.body, iframes, true).inverse();
1109
+ const r1 = node.getBoundingClientRect();
1110
+ const r1t = m.transformPoint(r1);
1111
+ const r2 = fixedContainer.getBoundingClientRect();
1112
+ const r2t = m.transformPoint(r2);
1113
+ return new DOMPoint(r1t.x - r2t.x, r1t.y - r2t.y);
1114
+ }
1115
+ // FIX 4: Only call getCachedComputedStyle when includeScroll is true —
1116
+ // cs is unused in the plain offsetLeft/offsetTop path.
1117
+ if (includeScroll) {
1118
+ return new DOMPoint(node.offsetLeft - (node.scrollLeft - parseFloat(cs.borderLeftWidth)), node.offsetTop - (node.scrollTop - parseFloat(cs.borderTopWidth)));
1119
+ }
1120
+ else {
1121
+ return new DOMPoint(node.offsetLeft, node.offsetTop);
1122
+ }
1123
+ }
1124
+ else if (node instanceof Text ||
1125
+ node instanceof ((_c = node.ownerDocument.defaultView) !== null && _c !== void 0 ? _c : window).Text) {
1126
+ const range = node.ownerDocument.createRange();
1127
+ range.selectNodeContents(node);
1128
+ const r1 = range.getBoundingClientRect();
1129
+ /** @type {HTMLElement} */
1130
+ //@ts-ignore
1131
+ const parent = getParentElementIncludingSlots(node, iframes);
1132
+ const r2 = parent.getBoundingClientRect();
1133
+ // Get the parent's CSS transform so we can work in local space even when rotated.
1134
+ const pt = getElementCombinedTransform(parent, iframes);
1135
+ const pa = pt.a, pb = pt.b, pc = pt.c, pd = pt.d;
1136
+ // AABB center of the transformed parent equals its geometric center.
1137
+ // geometric_center_screen = screen(0,0) + L * (pw/2, ph/2)
1138
+ // => screen(0,0) = AABB_center - L * (pw/2, ph/2)
1139
+ const pw = parent.offsetWidth;
1140
+ const ph = parent.offsetHeight;
1141
+ const parentOriginX = r2.x + r2.width / 2 - ((pa * pw) / 2 + (pc * ph) / 2);
1142
+ const parentOriginY = r2.y + r2.height / 2 - ((pb * pw) / 2 + (pd * ph) / 2);
1143
+ // Delta from parent origin to text AABB center in screen space
1144
+ const dx = r1.x + r1.width / 2 - parentOriginX;
1145
+ const dy = r1.y + r1.height / 2 - parentOriginY;
1146
+ // Apply inverse of CSS transform linear part: local_center = L^-1 * screen_delta
1147
+ const transformDet = pa * pd - pb * pc;
1148
+ let localCenterX, localCenterY;
1149
+ if (Math.abs(transformDet) > 1e-10) {
1150
+ localCenterX = (pd * dx - pc * dy) / transformDet;
1151
+ localCenterY = (pa * dy - pb * dx) / transformDet;
1152
+ }
1153
+ else {
1154
+ localCenterX = dx;
1155
+ localCenterY = dy;
1156
+ }
1157
+ // Recover tw and th in local space from the AABB using the 2x2 system:
1158
+ // aabb_w = tw*|cos| + th*|sin|, aabb_h = tw*|sin| + th*|cos|
1159
+ const absA = Math.abs(pa), absB = Math.abs(pb);
1160
+ const absDet = absA * absA - absB * absB;
1161
+ let tw, th;
1162
+ if (Math.abs(absDet) > 1e-6) {
1163
+ tw = Math.max(0, (absA * r1.width - absB * r1.height) / absDet);
1164
+ th = Math.max(0, (absA * r1.height - absB * r1.width) / absDet);
1165
+ }
1166
+ else {
1167
+ // Singular (~45 deg): use CSS line-height as th
1168
+ const cs = getCachedComputedStyle(parent);
1169
+ th = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2 || 16;
1170
+ th = Math.max(0, th);
1171
+ const denom = Math.max(absA, absB);
1172
+ tw =
1173
+ denom > 1e-6 ? Math.max(0, (r1.width - th * absB) / denom) : r1.width;
1174
+ }
1175
+ // local origin = center minus half-dimensions
1176
+ return new DOMPoint(localCenterX - tw / 2, localCenterY - th / 2);
1177
+ }
1178
+ else if (node instanceof Element ||
1179
+ node instanceof ((_d = node.ownerDocument.defaultView) !== null && _d !== void 0 ? _d : window).Element) {
1180
+ if ((node instanceof SVGGraphicsElement ||
1181
+ node instanceof
1182
+ ((_e = node.ownerDocument.defaultView) !== null && _e !== void 0 ? _e : window).SVGGraphicsElement) &&
1183
+ !(node instanceof SVGSVGElement ||
1184
+ node instanceof ((_f = node.ownerDocument.defaultView) !== null && _f !== void 0 ? _f : window).SVGSVGElement)) {
1185
+ const bb = node.getBBox();
1186
+ return new DOMPoint(bb.x, bb.y);
1187
+ }
1188
+ const cs = getCachedComputedStyle(node);
1189
+ if (cs.position === 'absolute') {
1190
+ return new DOMPoint(parseFloat(cs.left), parseFloat(cs.top));
1191
+ }
1192
+ const par = getParentElementIncludingSlots(node, iframes);
1193
+ const m = getResultingTransformationBetweenElementAndAllAncestors(par, document.body, iframes, true).inverse();
1194
+ const r1 = node.getBoundingClientRect();
1195
+ const r1t = m.transformPoint(r1);
1196
+ const r2 = par.getBoundingClientRect();
1197
+ const r2t = m.transformPoint(r2);
1198
+ return new DOMPoint(r1t.x - r2t.x, r1t.y - r2t.y);
1199
+ }
1200
+ }
1201
+ /**
1202
+ * @param {Node} node
1203
+ * @param {Element} ancestor
1204
+ * @param {HTMLIFrameElement[]} iframes
1205
+ * @param {boolean=} excludeSelfZoom
1206
+ */
1207
+ function getResultingTransformationBetweenElementAndAllAncestors(node, ancestor, iframes, excludeSelfZoom = false) {
1208
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1209
+ let key;
1210
+ if (transformCache) {
1211
+ let i1 = hash.get(node);
1212
+ if (i1 === undefined)
1213
+ hash.set(node, (i1 = hashId++));
1214
+ let i2 = hash.get(ancestor);
1215
+ if (i2 === undefined)
1216
+ hash.set(ancestor, (i2 = hashId++));
1217
+ key = i1 + '_' + i2 + '_' + (excludeSelfZoom ? 'no-self-zoom' : 'full');
1218
+ const q = transformCache.get(key);
1219
+ if (q)
1220
+ return q;
1221
+ }
1222
+ /** @type {Element } */
1223
+ //@ts-ignore
1224
+ let actualElement = node;
1225
+ /** @type {DOMMatrix } */
1226
+ let parentElementMatrix;
1227
+ // FIX 12: Compute self-transform once; we'll carry parent transforms forward
1228
+ // each iteration instead of recomputing them.
1229
+ const useOwnSvgCtm = (actualElement instanceof SVGGraphicsElement ||
1230
+ actualElement instanceof
1231
+ ((_a = actualElement.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window)
1232
+ .SVGGraphicsElement) &&
1233
+ !(actualElement instanceof SVGSVGElement ||
1234
+ actualElement instanceof
1235
+ ((_b = actualElement.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).SVGSVGElement);
1236
+ // SVGGraphicsElement.getCTM() already includes the element's local SVG/CSS transform.
1237
+ // Starting with getElementTransformWithZoom here would double-apply self rotate/scale.
1238
+ let currentElementTransform = useOwnSvgCtm
1239
+ ? new DOMMatrix()
1240
+ : getElementTransformWithZoom(actualElement, iframes, !excludeSelfZoom);
1241
+ /** @type {DOMMatrix } */
1242
+ // FIX 2: Only use a non-identity starting matrix when the element itself has
1243
+ // a CSS transform. Most plain elements have identity, avoiding a multiply.
1244
+ let originalElementAndAllParentsMultipliedMatrix = currentElementTransform.isIdentity
1245
+ ? new DOMMatrix()
1246
+ : currentElementTransform;
1247
+ let perspectiveParentElement = getParentElementIncludingSlots(actualElement, iframes);
1248
+ if (perspectiveParentElement) {
1249
+ // FIX 5: Guard transformStyle read behind is2D — on a standard 2D page
1250
+ // the matrix is always 2D here so we skip the style read entirely.
1251
+ if (!originalElementAndAllParentsMultipliedMatrix.is2D) {
1252
+ const s = getCachedComputedStyle(perspectiveParentElement);
1253
+ if (s.transformStyle !== 'preserve-3d') {
1254
+ projectTo2D(originalElementAndAllParentsMultipliedMatrix);
1255
+ }
1256
+ }
1257
+ }
1258
+ let lastOffsetParent = null;
1259
+ while (actualElement != ancestor && actualElement != null) {
1260
+ let parentElement = getParentElementIncludingSlots(actualElement, iframes);
1261
+ if (actualElement instanceof HTMLElement ||
1262
+ actualElement instanceof
1263
+ ((_c = actualElement.ownerDocument.defaultView) !== null && _c !== void 0 ? _c : window).HTMLElement) {
1264
+ const fixedStyle = getCachedComputedStyle(actualElement);
1265
+ if (fixedStyle.position === 'fixed') {
1266
+ const fixedContainer = getNearestFixedContainingBlock(actualElement, iframes);
1267
+ parentElement = fixedContainer !== null && fixedContainer !== void 0 ? fixedContainer : ancestor;
1268
+ }
1269
+ }
1270
+ if (actualElement.assignedSlot != null) {
1271
+ if (actualElement.nodeType === Node.ELEMENT_NODE) {
1272
+ const slotOffsetParent = offsetParentPolyfill(actualElement);
1273
+ const shouldApplySlottedOffset = lastOffsetParent !== slotOffsetParent &&
1274
+ (lastOffsetParent === null ||
1275
+ actualElement === lastOffsetParent ||
1276
+ !isFlatTreeInclusiveAncestor(lastOffsetParent, actualElement));
1277
+ if (shouldApplySlottedOffset) {
1278
+ const l = offsetTopLeftPolyfill(actualElement, 'offsetLeft');
1279
+ const t = offsetTopLeftPolyfill(actualElement, 'offsetTop');
1280
+ // FIX 3: Skip zero-translation matrix allocations.
1281
+ if (l !== 0 || t !== 0) {
1282
+ const mvMat = new DOMMatrix().translateSelf(l, t);
1283
+ originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
1284
+ }
1285
+ lastOffsetParent = slotOffsetParent;
1286
+ }
1287
+ if (lastOffsetParent === null)
1288
+ lastOffsetParent = slotOffsetParent;
1289
+ }
1290
+ else if (actualElement.nodeType === Node.TEXT_NODE) {
1291
+ const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
1292
+ // FIX 3
1293
+ if (offsets.x !== 0 || offsets.y !== 0) {
1294
+ const mvMat = new DOMMatrix().translateSelf(offsets.x, offsets.y);
1295
+ originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
1296
+ }
1297
+ }
1298
+ /*
1299
+ following code should be used instead of above to fix:
1300
+ but it does not work with:
1301
+ <div>
1302
+ <visu-tag-root-canvas id="outer-tag-root-canvas" tag-root="SRM.RBG01">
1303
+ <template shadowrootmode="open">
1304
+ <div id="rootObj" style="height:100%;width:100%;position:absolute;top:400px;">
1305
+ <slot></slot>
1306
+ </div>
1307
+ </template>
1308
+ <div class="wrapper" id="aaaaabb" style="height:50px;width:50px;"></div>
1309
+ </visu-tag-root-canvas>
1310
+ </div>
1311
+ */
1312
+ /*
1313
+ const l = offsetTopLeftPolyfill(actualElement, 'offsetLeft');
1314
+ const t = offsetTopLeftPolyfill(actualElement, 'offsetTop');
1315
+ const mvMat = new DOMMatrix().translateSelf(l, t);
1316
+ originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
1317
+ */
1318
+ }
1319
+ else {
1320
+ if (!(actualElement instanceof SVGSVGElement) &&
1321
+ !(actualElement instanceof
1322
+ ((_d = actualElement.ownerDocument.defaultView) !== null && _d !== void 0 ? _d : window).SVGSVGElement) &&
1323
+ (actualElement instanceof SVGGraphicsElement ||
1324
+ actualElement instanceof
1325
+ ((_e = actualElement.ownerDocument.defaultView) !== null && _e !== void 0 ? _e : window)
1326
+ .SVGGraphicsElement)) {
1327
+ const ctm = actualElement.getCTM();
1328
+ const bb = actualElement.getBBox();
1329
+ // FIX 3
1330
+ if (bb.x !== 0 || bb.y !== 0) {
1331
+ const mvMat = new DOMMatrix().translateSelf(bb.x, bb.y);
1332
+ originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
1333
+ }
1334
+ originalElementAndAllParentsMultipliedMatrix = new DOMMatrix([
1335
+ ctm.a,
1336
+ ctm.b,
1337
+ ctm.c,
1338
+ ctm.d,
1339
+ ctm.e,
1340
+ ctm.f,
1341
+ ]).multiplySelf(originalElementAndAllParentsMultipliedMatrix);
1342
+ parentElement = actualElement.ownerSVGElement;
1343
+ }
1344
+ else if (actualElement instanceof HTMLElement ||
1345
+ actualElement instanceof
1346
+ ((_f = actualElement.ownerDocument.defaultView) !== null && _f !== void 0 ? _f : window).HTMLElement) {
1347
+ const actualStyle = getCachedComputedStyle(actualElement);
1348
+ const isFixedSelf = actualStyle.position === 'fixed' && actualElement === node;
1349
+ if ((isFixedSelf || lastOffsetParent !== actualElement.offsetParent) &&
1350
+ !(actualElement instanceof HTMLSlotElement ||
1351
+ actualElement instanceof
1352
+ ((_g = actualElement.ownerDocument.defaultView) !== null && _g !== void 0 ? _g : window)
1353
+ .HTMLSlotElement) &&
1354
+ (lastOffsetParent === null ||
1355
+ actualElement === lastOffsetParent ||
1356
+ !isFlatTreeInclusiveAncestor(lastOffsetParent, actualElement))) {
1357
+ const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
1358
+ const zoom = getElementZoom(actualElement);
1359
+ lastOffsetParent = actualElement.offsetParent;
1360
+ // FIX 3
1361
+ if (offsets.x !== 0 || offsets.y !== 0) {
1362
+ const mvMat = new DOMMatrix().translateSelf(offsets.x * zoom, offsets.y * zoom);
1363
+ originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
1364
+ }
1365
+ }
1366
+ }
1367
+ else {
1368
+ const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
1369
+ lastOffsetParent = null;
1370
+ // FIX 3
1371
+ if (offsets.x !== 0 || offsets.y !== 0) {
1372
+ const mvMat = new DOMMatrix().translateSelf(offsets.x, offsets.y);
1373
+ originalElementAndAllParentsMultipliedMatrix = mvMat.multiplySelf(originalElementAndAllParentsMultipliedMatrix);
1374
+ }
1375
+ }
1376
+ }
1377
+ if (parentElement) {
1378
+ if (parentElement === ancestor) {
1379
+ // The ancestor's own transform is excluded from the returned matrix,
1380
+ // so avoid computing it on the hot return path.
1381
+ if (lastOffsetParent !== null &&
1382
+ (parentElement instanceof HTMLElement ||
1383
+ parentElement instanceof
1384
+ ((_h = parentElement.ownerDocument.defaultView) !== null && _h !== void 0 ? _h : window)
1385
+ .HTMLElement) &&
1386
+ parentElement.offsetParent === lastOffsetParent) {
1387
+ const ancOff = getElementOffsetsInContainer(parentElement, false, iframes);
1388
+ // FIX 3
1389
+ if (ancOff.x !== 0 || ancOff.y !== 0) {
1390
+ originalElementAndAllParentsMultipliedMatrix = new DOMMatrix()
1391
+ .translate(-ancOff.x, -ancOff.y)
1392
+ .multiply(originalElementAndAllParentsMultipliedMatrix);
1393
+ }
1394
+ }
1395
+ // FIX 15: Do NOT subtract the scroll of documentElement (the viewport/window
1396
+ // scroll). The offsetLeft/offsetTop walk already yields document-absolute
1397
+ // coordinates; subtracting documentElement.scrollTop would wrongly
1398
+ // shift positions to viewport-space when the page is scrolled.
1399
+ // Only subtract scroll for a non-root ancestor that is itself a
1400
+ // scroll container (e.g. an overflow:scroll div used as relativeTo).
1401
+ const isViewportScrollContainer = parentElement === parentElement.ownerDocument.documentElement;
1402
+ if (!isViewportScrollContainer &&
1403
+ (parentElement.scrollTop || parentElement.scrollLeft))
1404
+ originalElementAndAllParentsMultipliedMatrix = new DOMMatrix()
1405
+ .translate(-parentElement.scrollLeft, -parentElement.scrollTop)
1406
+ .multiply(originalElementAndAllParentsMultipliedMatrix);
1407
+ const ancestorZoom = getElementZoomScaleTransform(parentElement);
1408
+ if (!ancestorZoom.isIdentity)
1409
+ originalElementAndAllParentsMultipliedMatrix = ancestorZoom.multiply(originalElementAndAllParentsMultipliedMatrix);
1410
+ // FIX 6: Cache result on the early-return path. Originally, the
1411
+ // cache.set() only ran after the while-loop (the null/root
1412
+ // fallthrough), so the most common case — element IS a
1413
+ // descendant of ancestor — was NEVER cached.
1414
+ if (transformCache)
1415
+ transformCache.set(key, originalElementAndAllParentsMultipliedMatrix);
1416
+ return originalElementAndAllParentsMultipliedMatrix;
1417
+ }
1418
+ // FIX 12: parentElementMatrix computed here; in the next iteration this
1419
+ // becomes the element's own transform, so we can reuse it without
1420
+ // calling getElementCombinedTransform again.
1421
+ parentElementMatrix = getElementTransformWithZoom(parentElement, iframes);
1422
+ if (!parentElementMatrix.isIdentity)
1423
+ originalElementAndAllParentsMultipliedMatrix =
1424
+ parentElementMatrix.multiply(originalElementAndAllParentsMultipliedMatrix);
1425
+ perspectiveParentElement = getParentElementIncludingSlots(parentElement, iframes);
1426
+ if (perspectiveParentElement) {
1427
+ // FIX 5: Skip transformStyle read when matrix is already 2D.
1428
+ if (!originalElementAndAllParentsMultipliedMatrix.is2D) {
1429
+ const s = getCachedComputedStyle(perspectiveParentElement);
1430
+ if (s.transformStyle !== 'preserve-3d') {
1431
+ projectTo2D(originalElementAndAllParentsMultipliedMatrix);
1432
+ }
1433
+ }
1434
+ }
1435
+ }
1436
+ actualElement = parentElement;
1437
+ }
1438
+ if (transformCache) {
1439
+ transformCache.set(key, originalElementAndAllParentsMultipliedMatrix);
1440
+ }
1441
+ return originalElementAndAllParentsMultipliedMatrix;
1442
+ }
1443
+ /*
1444
+ getResultingTransformationBetweenElementAndAllAncestors -> but with extra layout matrix (does not work yet....)
1445
+
1446
+ export function getResultingTransformationBetweenElementAndAllAncestors(node, ancestor, iframes) {
1447
+ let key;
1448
+ if (transformCache) {
1449
+ let i1 = hash.get(node);
1450
+ if (i1 === undefined)
1451
+ hash.set(node, i1 = hashId++);
1452
+ let i2 = hash.get(ancestor);
1453
+ if (i2 === undefined)
1454
+ hash.set(ancestor, i2 = hashId++);
1455
+ key = i1 + '_' + i2;
1456
+ const q = transformCache.get(key);
1457
+ if (q)
1458
+ return q;
1459
+ }
1460
+
1461
+ // NEW - two matrices instead of one
1462
+ let layoutMatrix = new DOMMatrix();
1463
+
1464
+ let actualElement = node;
1465
+
1466
+ let transformMatrix = getElementCombinedTransform(actualElement, iframes); //.multiplySelf(transformMatrix);
1467
+
1468
+
1469
+ const perspectiveParent = getParentElementIncludingSlots(actualElement, iframes);
1470
+ if (perspectiveParent) {
1471
+ const s = getCachedComputedStyle(perspectiveParent);
1472
+ if (s.transformStyle !== "preserve-3d")
1473
+ projectTo2D(transformMatrix);
1474
+ }
1475
+
1476
+
1477
+ let lastOffsetParent = null;
1478
+
1479
+ while (actualElement !== ancestor && actualElement != null) {
1480
+
1481
+ const parentElement = getParentElementIncludingSlots(actualElement, iframes);
1482
+
1483
+ // ------------------------
1484
+ // LAYOUT MATRIX (offsets)
1485
+ // ------------------------
1486
+
1487
+ if (actualElement.assignedSlot != null) {
1488
+
1489
+ const l = offsetTopLeftPolyfill(actualElement, "offsetLeft");
1490
+ const t = offsetTopLeftPolyfill(actualElement, "offsetTop");
1491
+ layoutMatrix = new DOMMatrix().translateSelf(l, t).multiplySelf(layoutMatrix);
1492
+
1493
+ } else {
1494
+
1495
+ if (actualElement instanceof HTMLElement ||
1496
+ actualElement instanceof (actualElement.ownerDocument.defaultView ?? window).HTMLElement) {
1497
+
1498
+ if (lastOffsetParent !== actualElement.offsetParent &&
1499
+ !(actualElement instanceof HTMLSlotElement)) {
1500
+
1501
+ const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
1502
+ lastOffsetParent = actualElement.offsetParent;
1503
+
1504
+ layoutMatrix = new DOMMatrix().translateSelf(offsets.x, offsets.y).multiplySelf(layoutMatrix);
1505
+ }
1506
+
1507
+ } else {
1508
+
1509
+ const offsets = getElementOffsetsInContainer(actualElement, actualElement !== node, iframes);
1510
+ lastOffsetParent = null;
1511
+
1512
+ layoutMatrix = new DOMMatrix().translateSelf(offsets.x, offsets.y).multiplySelf(layoutMatrix);
1513
+ }
1514
+ }
1515
+
1516
+ // ------------------------
1517
+ // TRANSFORM MATRIX (CSS)
1518
+ // ------------------------
1519
+
1520
+ if (parentElement) {
1521
+
1522
+ // NEW - only affects transform pipeline
1523
+ const parentTransform = getElementCombinedTransform(parentElement, iframes);
1524
+ transformMatrix = parentTransform.multiply(transformMatrix);
1525
+
1526
+ // flattening boundary
1527
+ const perspectiveParent = getParentElementIncludingSlots(parentElement, iframes);
1528
+ if (perspectiveParent) {
1529
+ const s = getCachedComputedStyle(perspectiveParent);
1530
+ if (s.transformStyle !== "preserve-3d")
1531
+ projectTo2D(transformMatrix);
1532
+ }
1533
+
1534
+ // ------------------------
1535
+ // EXIT CONDITION
1536
+ // ------------------------
1537
+
1538
+ if (parentElement === ancestor) {
1539
+
1540
+ // NEW - scroll offsets belong to layout
1541
+ if (parentElement.scrollTop || parentElement.scrollLeft) {
1542
+ layoutMatrix = new DOMMatrix()
1543
+ .translate(-parentElement.scrollLeft, -parentElement.scrollTop)
1544
+ .multiply(layoutMatrix);
1545
+ }
1546
+
1547
+ const result = layoutMatrix.multiply(transformMatrix);
1548
+
1549
+ if (transformCache)
1550
+ transformCache.set(key, result);
1551
+
1552
+ return result;
1553
+ }
1554
+ }
1555
+
1556
+ actualElement = parentElement;
1557
+ }
1558
+
1559
+ const result = layoutMatrix.multiply(transformMatrix);
1560
+
1561
+ if (transformCache)
1562
+ transformCache.set(key, result);
1563
+
1564
+ return result;
1565
+ }
1566
+ */
1567
+ /**
1568
+ * @param {Node} node
1569
+ * @param {HTMLIFrameElement[]} iframes
1570
+ * @returns {Element}
1571
+ */
1572
+ function getParentElementIncludingSlots(node, iframes) {
1573
+ var _a, _b, _c;
1574
+ if ((node instanceof Element ||
1575
+ node instanceof ((_a = node.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).Element) &&
1576
+ node.assignedSlot)
1577
+ return node.assignedSlot;
1578
+ if (node.parentElement == null) {
1579
+ if (node.parentNode instanceof ShadowRoot ||
1580
+ node.parentNode instanceof
1581
+ ((_b = node.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).ShadowRoot) {
1582
+ return node.parentNode.host;
1583
+ }
1584
+ }
1585
+ if (node instanceof HTMLHtmlElement ||
1586
+ node instanceof ((_c = node.ownerDocument.defaultView) !== null && _c !== void 0 ? _c : window).HTMLHtmlElement) {
1587
+ if (iframes) {
1588
+ for (const f of iframes)
1589
+ if ((f === null || f === void 0 ? void 0 : f.contentDocument) == node.ownerDocument)
1590
+ return f;
1591
+ }
1592
+ }
1593
+ return node.parentElement;
1594
+ }
1595
+ /**
1596
+ * @param {Node} element
1597
+ * @param {HTMLIFrameElement[]=} iframes
1598
+ */
1599
+ function getElementCombinedTransform(element, iframes) {
1600
+ var _a;
1601
+ var _b;
1602
+ if (element instanceof Text ||
1603
+ element instanceof ((_b = element.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window).Text)
1604
+ return new DOMMatrix();
1605
+ /** @type {Element} */
1606
+ // @ts-ignore
1607
+ const actualElement = element;
1608
+ //https://www.w3.org/TR/css-transforms-2/#ctm
1609
+ let s = getCachedComputedStyle(actualElement);
1610
+ // FIX 10: Check hasTransform first — it's the most common non-identity case.
1611
+ // Reordering so the most frequent hit is evaluated first.
1612
+ const hasTransform = s.transform !== 'none' && !!s.transform;
1613
+ const hasTranslate = s.translate !== 'none' && !!s.translate;
1614
+ const hasRotate = s.rotate !== 'none' && !!s.rotate;
1615
+ const hasScale = s.scale !== 'none' && !!s.scale;
1616
+ const hasOffsetPath = !!s.offsetPath && s.offsetPath !== 'none';
1617
+ if (!hasTransform &&
1618
+ !hasTranslate &&
1619
+ !hasRotate &&
1620
+ !hasScale &&
1621
+ !hasOffsetPath) {
1622
+ // FIX 1: Check parent perspective right here in the fast-path, so identity
1623
+ // elements on non-3D pages return a new DOMMatrix() immediately
1624
+ // without calling getElementPerspectiveTransform at all.
1625
+ const parent = getParentElementIncludingSlots(actualElement, iframes);
1626
+ if (!parent)
1627
+ return new DOMMatrix();
1628
+ const ps = getCachedComputedStyle(parent);
1629
+ if (!ps.perspective || ps.perspective === 'none')
1630
+ return new DOMMatrix();
1631
+ // Parent has a perspective — fall through to compute it properly.
1632
+ //@ts-ignore
1633
+ const pt = getElementPerspectiveTransform(actualElement, iframes);
1634
+ return pt != null ? pt : new DOMMatrix();
1635
+ }
1636
+ let m = new DOMMatrix();
1637
+ const origin = s.transformOrigin.split(' ');
1638
+ const originX = parseFloat(origin[0]);
1639
+ const originY = parseFloat(origin[1]);
1640
+ const originZ = origin[2] ? parseFloat(origin[2]) : 0;
1641
+ // FIX 11: Skip the origin wrap/unwrap entirely when origin is (0,0,0).
1642
+ // Saves two DOMMatrix allocations and two multiply calls per element.
1643
+ const hasNonZeroOrigin = originX !== 0 || originY !== 0 || originZ !== 0;
1644
+ const mOri = hasNonZeroOrigin
1645
+ ? new DOMMatrix().translateSelf(originX, originY, originZ)
1646
+ : null;
1647
+ if (hasTranslate) {
1648
+ let tr = s.translate;
1649
+ if (tr.includes('%')) {
1650
+ const v = tr.split(' ');
1651
+ const r = actualElement.getBoundingClientRect();
1652
+ if (v[0].endsWith('%'))
1653
+ v[0] = (parseFloat(v[0]) * r.width) / 100 + 'px';
1654
+ if ((_a = v[1]) === null || _a === void 0 ? void 0 : _a.endsWith('%'))
1655
+ v[1] = (parseFloat(v[1]) * r.height) / 100 + 'px';
1656
+ tr = v.join(',');
1657
+ }
1658
+ m.multiplySelf(new DOMMatrix('translate(' + tr.replaceAll(' ', ',') + ')'));
1659
+ }
1660
+ if (hasRotate) {
1661
+ m.multiplySelf(new DOMMatrix('rotate(' + s.rotate.replaceAll(' ', ',') + ')'));
1662
+ }
1663
+ if (hasScale) {
1664
+ m.multiplySelf(new DOMMatrix('scale(' + s.scale.replaceAll(' ', ',') + ')'));
1665
+ }
1666
+ if (hasOffsetPath) {
1667
+ m.multiplySelf(computeOffsetTransformMatrix(element));
1668
+ }
1669
+ if (hasTransform) {
1670
+ m.multiplySelf(new DOMMatrix(s.transform));
1671
+ }
1672
+ // FIX 11 (continued): Only wrap with origin if non-zero.
1673
+ if (hasNonZeroOrigin) {
1674
+ m = mOri.multiply(m.multiplySelf(mOri.inverse()));
1675
+ }
1676
+ //@ts-ignore
1677
+ const pt = getElementPerspectiveTransform(element, iframes);
1678
+ if (pt != null) {
1679
+ m = pt.multiplySelf(m);
1680
+ }
1681
+ return m;
1682
+ }
1683
+ /**
1684
+ * project a DOM-Matrix to 2D (from firefox matrix.h)
1685
+ * @param {DOMMatrix} m
1686
+ */
1687
+ function projectTo2D(m) {
1688
+ m.m31 = 0.0;
1689
+ m.m32 = 0.0;
1690
+ m.m13 = 0.0;
1691
+ m.m23 = 0.0;
1692
+ m.m33 = 1.0;
1693
+ m.m43 = 0.0;
1694
+ m.m34 = 0.0;
1695
+ // Some matrices, such as those derived from perspective transforms,
1696
+ // can modify _44 from 1, while leaving the rest of the fourth column
1697
+ // (_14, _24) at 0. In this case, after resetting the third row and
1698
+ // third column above, the value of _44 functions only to scale the
1699
+ // coordinate transform divide by W. The matrix can be converted to
1700
+ // a true 2D matrix by normalizing out the scaling effect of _44 on
1701
+ // the remaining components ahead of time.
1702
+ if (m.m14 == 0.0 && m.m24 == 0.0 && m.m44 != 1.0 && m.m44 != 0.0) {
1703
+ const scale = 1.0 / m.m44;
1704
+ m.m11 *= scale;
1705
+ m.m12 *= scale;
1706
+ m.m21 *= scale;
1707
+ m.m22 *= scale;
1708
+ m.m41 *= scale;
1709
+ m.m42 *= scale;
1710
+ m.m44 = 1.0;
1711
+ }
1712
+ }
1713
+ /**
1714
+ * @param {HTMLElement} element
1715
+ * @param {HTMLIFrameElement[]} iframes
1716
+ */
1717
+ function getElementPerspectiveTransform(element, iframes) {
1718
+ /** @type { Element } */
1719
+ //@ts-ignore
1720
+ const perspectiveNode = getParentElementIncludingSlots(element, iframes);
1721
+ if (perspectiveNode) {
1722
+ //https://drafts.csswg.org/css-transforms-2/#perspective-matrix-computation
1723
+ let s = getCachedComputedStyle(perspectiveNode);
1724
+ if (s.perspective !== 'none') {
1725
+ let m = new DOMMatrix();
1726
+ let p = parseFloat(s.perspective);
1727
+ m.m34 = -1.0 / p;
1728
+ //https://drafts.csswg.org/css-transforms-2/#PerspectiveDefined
1729
+ if (s.perspectiveOrigin) {
1730
+ const origin = s.perspectiveOrigin.split(' ');
1731
+ const originX = parseFloat(origin[0]) - element.offsetLeft;
1732
+ const originY = parseFloat(origin[1]) - element.offsetTop;
1733
+ const mOri = new DOMMatrix().translateSelf(originX, originY);
1734
+ const mOriInv = new DOMMatrix().translateSelf(-originX, -originY);
1735
+ return mOri.multiplySelf(m.multiplySelf(mOriInv));
1736
+ }
1737
+ }
1738
+ }
1739
+ return null;
1740
+ }
1741
+ function computeOffsetTransformMatrix(elem) {
1742
+ var _a;
1743
+ const cs = getCachedComputedStyle(elem);
1744
+ const offsetPath = cs.offsetPath; // e.g. "path('M0,0 ...')"
1745
+ const offsetDistance = cs.offsetDistance; // e.g. "50%"
1746
+ const offsetRotate = cs.offsetRotate; // e.g. "auto", "45deg", "auto 30deg"
1747
+ const offsetAnchor = cs.offsetAnchor;
1748
+ const transformOrigin = cs.transformOrigin;
1749
+ // Parse offset-distance (px or %)
1750
+ let distance = parseOffsetDistance(offsetDistance);
1751
+ // Compute position & tangent on path (in containing block coordinates)
1752
+ let { x, y, angle } = computeOffsetPathPoint(elem, offsetPath, distance);
1753
+ // Subtract the element's flow position within its containing block.
1754
+ // The offset-path positions the element absolutely within the containing block,
1755
+ // but the walk already adds offsetLeft/offsetTop (flow position). To avoid
1756
+ // double-counting, make the offset relative to the flow position.
1757
+ const parent = elem.parentElement;
1758
+ if (parent instanceof HTMLElement ||
1759
+ parent instanceof ((_a = parent.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window).HTMLElement) {
1760
+ if (elem.offsetParent === parent) {
1761
+ // Containing block = parent = offsetParent
1762
+ x -= elem.offsetLeft;
1763
+ y -= elem.offsetTop;
1764
+ }
1765
+ else if (elem.offsetParent === parent.offsetParent) {
1766
+ // Both share the same offsetParent
1767
+ x -= elem.offsetLeft - parent.offsetLeft;
1768
+ y -= elem.offsetTop - parent.offsetTop;
1769
+ }
1770
+ }
1771
+ // Handle offset-rotate
1772
+ let rotateFinal = 0;
1773
+ if (offsetRotate.startsWith('auto')) {
1774
+ let parts = offsetRotate.split(/\s+/);
1775
+ let extra = parts.length === 2 ? parseFloat(parts[1]) : 0;
1776
+ rotateFinal = angle + extra;
1777
+ }
1778
+ else {
1779
+ rotateFinal = parseFloat(offsetRotate);
1780
+ }
1781
+ const anchor = parseOffsetAnchor(offsetAnchor, transformOrigin, elem);
1782
+ const anchorMatrix = new DOMMatrix().translateSelf(-anchor.x, -anchor.y);
1783
+ let m = anchorMatrix.translate(x, y);
1784
+ m.multiplySelf(anchorMatrix.invertSelf());
1785
+ m.rotateSelf(rotateFinal);
1786
+ m.translateSelf(-anchor.x, -anchor.y);
1787
+ return m;
1788
+ }
1789
+ function parseOffsetAnchor(str, transformOrigin, elem) {
1790
+ const width = elem.offsetWidth;
1791
+ const height = elem.offsetHeight;
1792
+ if (!str || str === 'auto') {
1793
+ str = transformOrigin;
1794
+ }
1795
+ const parts = str.split(/\s+/);
1796
+ if (parts.length === 1) {
1797
+ // 1-value syntax = x only, y = center
1798
+ const x = parsePosition(parts[0], width);
1799
+ return { x, y: height / 2 };
1800
+ }
1801
+ const x = parsePosition(parts[0], width);
1802
+ const y = parsePosition(parts[1], height);
1803
+ return { x, y };
1804
+ }
1805
+ function parsePosition(part, size) {
1806
+ part = part.trim();
1807
+ if (part.endsWith('%')) {
1808
+ return (parseFloat(part) / 100) * size;
1809
+ }
1810
+ if (part.endsWith('px')) {
1811
+ return parseFloat(part);
1812
+ }
1813
+ // keywords
1814
+ switch (part) {
1815
+ case 'left':
1816
+ return 0;
1817
+ case 'top':
1818
+ return 0;
1819
+ case 'center':
1820
+ return size / 2;
1821
+ case 'right':
1822
+ return size;
1823
+ case 'bottom':
1824
+ return size;
1825
+ }
1826
+ return parseFloat(part);
1827
+ }
1828
+ function parseOffsetDistance(str) {
1829
+ str = str.trim();
1830
+ if (str.endsWith('%')) {
1831
+ return parseFloat(str) / 100; // normalized (0..1)
1832
+ }
1833
+ return parseFloat(str); // px value if pathLength = 1
1834
+ }
1835
+ function parseAngle(str) {
1836
+ if (!str)
1837
+ return 0;
1838
+ str = str.trim();
1839
+ if (str.endsWith('deg'))
1840
+ return parseFloat(str);
1841
+ if (str.endsWith('rad'))
1842
+ return parseFloat(str) * (180 / Math.PI);
1843
+ if (str.endsWith('grad'))
1844
+ return parseFloat(str) * 0.9;
1845
+ return parseFloat(str);
1846
+ }
1847
+ function computeOffsetPathPoint(elem, offsetPath, distNorm) {
1848
+ if (!offsetPath || offsetPath === 'none') {
1849
+ return { x: 0, y: 0, angle: 0 };
1850
+ }
1851
+ const value = offsetPath.trim();
1852
+ let m = value.match(/path\(["'](.+)["']\)/);
1853
+ if (m)
1854
+ return computePathType(m[1], distNorm);
1855
+ if (value.startsWith('circle('))
1856
+ return computeCircle(value, distNorm);
1857
+ if (value.startsWith('ellipse('))
1858
+ return computeEllipse(value, distNorm);
1859
+ if (value.startsWith('inset('))
1860
+ return computeInset(value, elem, distNorm);
1861
+ if (value.startsWith('rect('))
1862
+ return computeRect(value, distNorm);
1863
+ if (value.startsWith('xywh('))
1864
+ return computeXYWH(value, distNorm);
1865
+ if (value.startsWith('ray('))
1866
+ return computeRay(value, distNorm);
1867
+ if (value.startsWith('polygon('))
1868
+ return computePolygon(value, distNorm);
1869
+ console.warn('Unsupported offset-path:', offsetPath);
1870
+ return { x: 0, y: 0, angle: 0 };
1871
+ }
1872
+ function computePathType(pathData, distNorm) {
1873
+ let svgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1874
+ svgPath.setAttribute('d', pathData);
1875
+ const total = svgPath.getTotalLength();
1876
+ const dist = distNorm <= 1 ? distNorm * total : distNorm;
1877
+ const p1 = svgPath.getPointAtLength(dist);
1878
+ const p2 = svgPath.getPointAtLength(Math.min(total, dist + 0.01));
1879
+ let angle = (Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180) / Math.PI;
1880
+ return { x: p1.x, y: p1.y, angle };
1881
+ }
1882
+ function computeRay(str, t) {
1883
+ let m = str.match(/ray\(([^)]+)\)/);
1884
+ let inside = m[1].trim();
1885
+ // Split on "at" (optional)
1886
+ let [beforeAt, atPart] = inside.split('at').map((s) => s && s.trim());
1887
+ // angle
1888
+ let parts = beforeAt.split(/\s+/);
1889
+ let angleDeg = parseAngle(parts[0]);
1890
+ let angleRad = (angleDeg * Math.PI) / 180;
1891
+ // point of origin
1892
+ let ox = 0, oy = 0;
1893
+ if (atPart) {
1894
+ const pos = atPart.split(/\s+/);
1895
+ ox = parseFloat(pos[0]);
1896
+ oy = parseFloat(pos[1]);
1897
+ }
1898
+ // Ray: infinite line; offset-distance is distance along ray
1899
+ let dist = t <= 1 ? t : t; // percentage normalized already
1900
+ let x = ox + Math.cos(angleRad) * dist;
1901
+ let y = oy + Math.sin(angleRad) * dist;
1902
+ // tangent is ray direction
1903
+ return { x, y, angle: angleDeg };
1904
+ }
1905
+ function computeCircle(str, t) {
1906
+ let m = str.match(/circle\(([^)]+)\)/);
1907
+ let inner = m[1];
1908
+ let [radiusPart, atPart] = inner.split('at').map((s) => s.trim());
1909
+ let r = parseFloat(radiusPart);
1910
+ let [cx, cy] = atPart.split(/\s+/).map(parseFloat);
1911
+ let angleRad = t * 2 * Math.PI;
1912
+ let x = cx + Math.cos(angleRad) * r;
1913
+ let y = cy + Math.sin(angleRad) * r;
1914
+ let tangentAngleDeg = (angleRad * 180) / Math.PI + 90;
1915
+ return { x, y, angle: tangentAngleDeg };
1916
+ }
1917
+ function computeEllipse(str, t) {
1918
+ let m = str.match(/ellipse\(([^)]+)\)/);
1919
+ let parts = m[1].split('at');
1920
+ let radii = parts[0].trim().split(/\s+/).map(parseFloat);
1921
+ let center = parts[1].trim().split(/\s+/).map(parseFloat);
1922
+ let rx = radii[0];
1923
+ let ry = radii[1];
1924
+ let cx = center[0];
1925
+ let cy = center[1];
1926
+ let angleRad = t * 2 * Math.PI;
1927
+ let x = cx + Math.cos(angleRad) * rx;
1928
+ let y = cy + Math.sin(angleRad) * ry;
1929
+ // tangent direction derivative
1930
+ let dx = -Math.sin(angleRad) * rx;
1931
+ let dy = Math.cos(angleRad) * ry;
1932
+ let tangentAngleDeg = (Math.atan2(dy, dx) * 180) / Math.PI;
1933
+ return { x, y, angle: tangentAngleDeg };
1934
+ }
1935
+ function computeRect(str, t) {
1936
+ let m = str.match(/rect\(([^)]+)\)/);
1937
+ let nums = m[1].split(/\s+/).map((s) => parseFloat(s));
1938
+ let top = nums[0], right = nums[1], bottom = nums[2], left = nums[3];
1939
+ return rectPath(top, left, right, bottom, t);
1940
+ }
1941
+ function computeXYWH(str, t) {
1942
+ let m = str.match(/xywh\(([^)]+)\)/);
1943
+ let nums = m[1].split(/\s+/).map(parseFloat);
1944
+ let left = nums[0];
1945
+ let top = nums[1];
1946
+ let width = nums[2];
1947
+ let height = nums[3];
1948
+ return rectPath(top, left, left + width, top + height, t);
1949
+ }
1950
+ function computePolygon(str, t) {
1951
+ let m = str.match(/polygon\(([^)]+)\)/);
1952
+ let pairs = m[1].split(',').map((p) => p.trim().split(/\s+/).map(parseFloat));
1953
+ // Build cumulative lengths
1954
+ let pts = pairs;
1955
+ let lengths = [0];
1956
+ for (let i = 1; i < pts.length; i++) {
1957
+ let dx = pts[i][0] - pts[i - 1][0];
1958
+ let dy = pts[i][1] - pts[i - 1][1];
1959
+ lengths.push(Math.hypot(dx, dy) + lengths[i - 1]);
1960
+ }
1961
+ // close polygon
1962
+ let dx = pts[0][0] - pts[pts.length - 1][0];
1963
+ let dy = pts[0][1] - pts[pts.length - 1][1];
1964
+ lengths.push(Math.hypot(dx, dy) + lengths[lengths.length - 1]);
1965
+ let total = lengths[lengths.length - 1];
1966
+ let target = t * total;
1967
+ // find segment
1968
+ let i = lengths.findIndex((len) => len >= target);
1969
+ if (i <= 0)
1970
+ i = 1;
1971
+ let prevLen = lengths[i - 1];
1972
+ let nextLen = lengths[i];
1973
+ let segT = (target - prevLen) / (nextLen - prevLen);
1974
+ // segment points
1975
+ let a = pts[(i - 1) % pts.length];
1976
+ let b = pts[i % pts.length];
1977
+ let x = a[0] + (b[0] - a[0]) * segT;
1978
+ let y = a[1] + (b[1] - a[1]) * segT;
1979
+ let angle = (Math.atan2(b[1] - a[1], b[0] - a[0]) * 180) / Math.PI;
1980
+ return { x, y, angle };
1981
+ }
1982
+ function rectPath(top, left, right, bottom, t) {
1983
+ let w = right - left;
1984
+ let h = bottom - top;
1985
+ let perimeter = 2 * (w + h);
1986
+ let dist = t * perimeter;
1987
+ // go around edges
1988
+ if (dist < w) {
1989
+ // top edge
1990
+ let x = left + dist;
1991
+ return { x, y: top, angle: 0 };
1992
+ }
1993
+ dist -= w;
1994
+ if (dist < h) {
1995
+ // right edge
1996
+ let y = top + dist;
1997
+ return { x: right, y, angle: 90 };
1998
+ }
1999
+ dist -= h;
2000
+ if (dist < w) {
2001
+ // bottom edge
2002
+ let x = right - dist;
2003
+ return { x, y: bottom, angle: 180 };
2004
+ }
2005
+ dist -= w;
2006
+ // left edge
2007
+ let y = bottom - dist;
2008
+ return { x: left, y, angle: 270 };
2009
+ }
2010
+ // normalized inset uses calc
2011
+ function tokenizeCalc(input) {
2012
+ let tokens = [];
2013
+ let i = 0;
2014
+ while (i < input.length) {
2015
+ let ch = input[i];
2016
+ if (/\s/.test(ch)) {
2017
+ i++;
2018
+ continue;
2019
+ }
2020
+ // operators & parentheses
2021
+ if ('+-*/()'.includes(ch)) {
2022
+ tokens.push({ type: ch, value: ch });
2023
+ i++;
2024
+ continue;
2025
+ }
2026
+ // numbers or dimensions or %
2027
+ if (/[0-9.]/.test(ch)) {
2028
+ let start = i;
2029
+ while (/[0-9.]/.test(input[i]))
2030
+ i++;
2031
+ let num = input.slice(start, i);
2032
+ if (input[i] === '%') {
2033
+ i++;
2034
+ tokens.push({ type: 'percentage', value: parseFloat(num) });
2035
+ continue;
2036
+ }
2037
+ // only px supported
2038
+ if (input.slice(i, i + 2) === 'px') {
2039
+ i += 2;
2040
+ tokens.push({ type: 'dimension', value: parseFloat(num), unit: 'px' });
2041
+ continue;
2042
+ }
2043
+ // plain number
2044
+ tokens.push({ type: 'number', value: parseFloat(num) });
2045
+ continue;
2046
+ }
2047
+ // function name (calc)
2048
+ if (/[a-zA-Z]/.test(ch)) {
2049
+ let start = i;
2050
+ while (/[a-zA-Z]/.test(input[i]))
2051
+ i++;
2052
+ let name = input.slice(start, i);
2053
+ if (name === 'calc' && input[i] === '(') {
2054
+ tokens.push({ type: 'func', value: 'calc' });
2055
+ continue;
2056
+ }
2057
+ throw new Error('Unsupported function: ' + name);
2058
+ }
2059
+ throw new Error('Unexpected character in calc(): ' + ch);
2060
+ }
2061
+ return tokens;
2062
+ }
2063
+ // normalized inset uses calc
2064
+ function parseCalc(tokens) {
2065
+ let i = 0;
2066
+ function peek() {
2067
+ return tokens[i];
2068
+ }
2069
+ function consume() {
2070
+ return tokens[i++];
2071
+ }
2072
+ function parseExpression() {
2073
+ let node = parseTerm();
2074
+ while (peek() && (peek().type === '+' || peek().type === '-')) {
2075
+ let op = consume().type;
2076
+ let right = parseTerm();
2077
+ node = { type: 'binary', op, left: node, right };
2078
+ }
2079
+ return node;
2080
+ }
2081
+ function parseTerm() {
2082
+ let node = parseFactor();
2083
+ while (peek() && (peek().type === '*' || peek().type === '/')) {
2084
+ let op = consume().type;
2085
+ let right = parseFactor();
2086
+ node = { type: 'binary', op, left: node, right };
2087
+ }
2088
+ return node;
2089
+ }
2090
+ function parseFactor() {
2091
+ let t = peek();
2092
+ if (!t)
2093
+ throw 'Unexpected end in calc()';
2094
+ if (t.type === 'number') {
2095
+ consume();
2096
+ return { type: 'number', value: t.value };
2097
+ }
2098
+ if (t.type === 'dimension') {
2099
+ consume();
2100
+ return { type: 'dimension', value: t.value, unit: t.unit };
2101
+ }
2102
+ if (t.type === 'percentage') {
2103
+ consume();
2104
+ return { type: 'percentage', value: t.value };
2105
+ }
2106
+ if (t.type === 'func') {
2107
+ consume(); // "calc"
2108
+ if (peek().type !== '(')
2109
+ throw "Expected '(' after calc";
2110
+ consume();
2111
+ let node = parseExpression();
2112
+ if (!peek() || peek().type !== ')')
2113
+ throw "Expected ')'";
2114
+ consume();
2115
+ return node;
2116
+ }
2117
+ if (t.type === '(') {
2118
+ consume();
2119
+ let node = parseExpression();
2120
+ if (!peek() || peek().type !== ')')
2121
+ throw "Expected ')'";
2122
+ consume();
2123
+ return node;
2124
+ }
2125
+ throw new Error('Unexpected calc token ' + JSON.stringify(t));
2126
+ }
2127
+ let ast = parseExpression();
2128
+ if (i !== tokens.length)
2129
+ throw 'Extra tokens after calc';
2130
+ return ast;
2131
+ }
2132
+ // normalized inset uses calc
2133
+ function evalCalc(ast, env) {
2134
+ switch (ast.type) {
2135
+ case 'number':
2136
+ return ast.value;
2137
+ case 'dimension':
2138
+ return ast.value; // px only -> already a number
2139
+ case 'percentage':
2140
+ return env.percentBase * (ast.value / 100);
2141
+ case 'binary': {
2142
+ let l = evalCalc(ast.left, env);
2143
+ let r = evalCalc(ast.right, env);
2144
+ switch (ast.op) {
2145
+ case '+':
2146
+ return l + r;
2147
+ case '-':
2148
+ return l - r;
2149
+ case '*':
2150
+ return l * r;
2151
+ case '/':
2152
+ return l / r;
2153
+ }
2154
+ }
2155
+ }
2156
+ throw 'Invalid AST node ' + ast.type;
2157
+ }
2158
+ function resolveLength(expr, element, useHeight = false) {
2159
+ expr = expr.trim();
2160
+ // Fast path: pure px
2161
+ if (/^[0-9.]+px$/.test(expr))
2162
+ return parseFloat(expr);
2163
+ let base = useHeight ? element.offsetHeight : element.offsetWidth;
2164
+ // Pure %
2165
+ if (/^[0-9.]+%$/.test(expr)) {
2166
+ let p = parseFloat(expr);
2167
+ return base * (p / 100);
2168
+ }
2169
+ // calc(...) or mixed values
2170
+ const ast = parseCalc(tokenizeCalc(expr));
2171
+ return evalCalc(ast, {
2172
+ percentBase: base,
2173
+ });
2174
+ }
2175
+ function parseInsetArgs(str) {
2176
+ let inside = str
2177
+ .trim()
2178
+ .replace(/^inset\s*\(/, '')
2179
+ .replace(/\)\s*$/, '');
2180
+ let args = [];
2181
+ let current = '';
2182
+ let depth = 0;
2183
+ for (let i = 0; i < inside.length; i++) {
2184
+ let ch = inside[i];
2185
+ if (ch === '(') {
2186
+ depth++;
2187
+ current += ch;
2188
+ }
2189
+ else if (ch === ')') {
2190
+ depth--;
2191
+ current += ch;
2192
+ }
2193
+ else if (/\s/.test(ch) && depth === 0) {
2194
+ if (current.trim() !== '') {
2195
+ args.push(current.trim());
2196
+ current = '';
2197
+ }
2198
+ }
2199
+ else {
2200
+ current += ch;
2201
+ }
2202
+ }
2203
+ if (current.trim() !== '') {
2204
+ args.push(current.trim());
2205
+ }
2206
+ return args;
2207
+ }
2208
+ /**
2209
+ *
2210
+ * @param {string} str
2211
+ * @param {HTMLElement} element
2212
+ * @param {number} progress
2213
+ * @returns
2214
+ */
2215
+ function computeInset(str, element, progress) {
2216
+ const args = parseInsetArgs(str);
2217
+ if (args.length !== 4)
2218
+ throw new Error('inset() must have 4 arguments');
2219
+ const topPx = resolveLength(args[0], element, true);
2220
+ const rightPx = resolveLength(args[1], element, false);
2221
+ const bottomPx = resolveLength(args[2], element, true);
2222
+ const leftPx = resolveLength(args[3], element, false);
2223
+ const w = element.offsetWidth;
2224
+ const h = element.offsetHeight;
2225
+ // Actual rectangle coordinates
2226
+ const x1 = leftPx;
2227
+ const y1 = topPx;
2228
+ const x2 = w - rightPx;
2229
+ const y2 = h - bottomPx;
2230
+ // Rectangle perimeter
2231
+ const P = 2 * (x2 - x1 + (y2 - y1));
2232
+ let d = P * progress;
2233
+ // Walk the rectangle clockwise, return point
2234
+ // Top edge: (x1 -> x2, y1)
2235
+ let len = x2 - x1;
2236
+ if (d <= len)
2237
+ return { x: x1 + d, y: y1, angle: 0 };
2238
+ d -= len;
2239
+ // Right edge: (x2, y1 -> y2)
2240
+ len = y2 - y1;
2241
+ if (d <= len)
2242
+ return { x: x2, y: y1 + d, angle: 90 };
2243
+ d -= len;
2244
+ // Bottom edge: (x2 -> x1, y2)
2245
+ len = x2 - x1;
2246
+ if (d <= len)
2247
+ return { x: x2 - d, y: y2, angle: 180 };
2248
+ d -= len;
2249
+ // Left edge: (x1, y2 -> y1)
2250
+ return { x: x1, y: y2 - d, angle: 270 };
2251
+ }
2252
+ //Code from: https://github.com/floating-ui/floating-ui/blob/master/packages/utils/src/dom.ts
2253
+ const transformProperties = [
2254
+ 'transform',
2255
+ 'translate',
2256
+ 'scale',
2257
+ 'rotate',
2258
+ 'perspective',
2259
+ ];
2260
+ const willChangeValues = [
2261
+ 'transform',
2262
+ 'translate',
2263
+ 'scale',
2264
+ 'rotate',
2265
+ 'perspective',
2266
+ 'filter',
2267
+ ];
2268
+ const containValues = ['paint', 'layout', 'strict', 'content'];
2269
+ function isElement(value) {
2270
+ var _a, _b;
2271
+ const elType = (_b = (_a = value === null || value === void 0 ? void 0 : value.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) === null || _b === void 0 ? void 0 : _b.Element;
2272
+ return (value instanceof Element || (elType != null && value instanceof elType));
2273
+ }
2274
+ /**
2275
+ *
2276
+ * @param {CSSStyleDeclaration} css
2277
+ * @returns {boolean}
2278
+ */
2279
+ function isContainingBlock(css) {
2280
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
2281
+ // https://drafts.csswg.org/css-transforms-2/#individual-transforms
2282
+ return (transformProperties.some((value) => css[value] ? css[value] !== 'none' : false) ||
2283
+ (css.containerType ? css.containerType !== 'normal' : false) ||
2284
+ (css.backdropFilter ? css.backdropFilter !== 'none' : false) ||
2285
+ (css.filter ? css.filter !== 'none' : false) ||
2286
+ willChangeValues.some((value) => (css.willChange || '').includes(value)) ||
2287
+ containValues.some((value) => (css.contain || '').includes(value)));
2288
+ }
2289
+ //Code from: https://github.com/jcfranco/composed-offset-position/blob/main/src/index.ts
2290
+ function flatTreeParent(element) {
2291
+ if (element.assignedSlot)
2292
+ return element.assignedSlot;
2293
+ if (element.parentNode instanceof ShadowRoot)
2294
+ return element.parentNode.host;
2295
+ return element.parentNode;
2296
+ }
2297
+ function isFlatTreeInclusiveAncestor(ancestor, node) {
2298
+ for (let current = node; current; current = flatTreeParent(current)) {
2299
+ if (current === ancestor)
2300
+ return true;
2301
+ }
2302
+ return false;
2303
+ }
2304
+ function ancestorTreeScopes(element) {
2305
+ var _a, _b, _c;
2306
+ var _d, _e;
2307
+ const scopes = new Set();
2308
+ let currentScope = element.getRootNode();
2309
+ const shadowRootCtor = (_d = (_b = (_a = element.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) === null || _b === void 0 ? void 0 : _b.ShadowRoot) !== null && _d !== void 0 ? _d : ShadowRoot;
2310
+ while (currentScope) {
2311
+ scopes.add(currentScope);
2312
+ if (currentScope instanceof shadowRootCtor) {
2313
+ currentScope = (_e = (_c = currentScope.host) === null || _c === void 0 ? void 0 : _c.getRootNode()) !== null && _e !== void 0 ? _e : null;
2314
+ }
2315
+ else {
2316
+ currentScope = currentScope.parentNode
2317
+ ? currentScope.parentNode.getRootNode()
2318
+ : null;
2319
+ }
2320
+ }
2321
+ return scopes;
2322
+ }
2323
+ function offsetParentPolyfill(element) {
2324
+ // Do an initial walk to check for display:none ancestors.
2325
+ for (let ancestor = element; ancestor; ancestor = flatTreeParent(ancestor)) {
2326
+ if (!(ancestor instanceof Element))
2327
+ continue;
2328
+ if (getCachedComputedStyle(ancestor).display === 'none')
2329
+ return null;
2330
+ }
2331
+ for (let ancestor = flatTreeParent(element); ancestor; ancestor = flatTreeParent(ancestor)) {
2332
+ if (!(ancestor instanceof Element))
2333
+ continue;
2334
+ const style = getCachedComputedStyle(ancestor);
2335
+ if (style.display === 'contents')
2336
+ continue;
2337
+ if (style.position !== 'static' || isContainingBlock(style))
2338
+ return ancestor;
2339
+ if (ancestor.tagName === 'BODY')
2340
+ return ancestor;
2341
+ }
2342
+ return null;
2343
+ }
2344
+ /**
2345
+ *
2346
+ * @param {*} element
2347
+ * @param {'offsetTop' | 'offsetLeft'} offsetTopOrLeft
2348
+ * @returns
2349
+ */
2350
+ function offsetTopLeftPolyfill(element, offsetTopOrLeft) {
2351
+ let value = element[offsetTopOrLeft];
2352
+ let nextOffsetParent = offsetParentPolyfill(element);
2353
+ const scopes = ancestorTreeScopes(element);
2354
+ while (nextOffsetParent && !scopes.has(nextOffsetParent.getRootNode())) {
2355
+ value -= nextOffsetParent[offsetTopOrLeft];
2356
+ nextOffsetParent = offsetParentPolyfill(nextOffsetParent);
2357
+ }
2358
+ return value;
2359
+ }
2360
+ /**
2361
+ * @param {Element} element
2362
+ * @returns {boolean}
2363
+ */
2364
+ function createsFixedContainingBlock(element) {
2365
+ const cs = getCachedComputedStyle(element);
2366
+ if ((cs.transform && cs.transform !== 'none') ||
2367
+ (cs.perspective && cs.perspective !== 'none') ||
2368
+ (cs.filter && cs.filter !== 'none') ||
2369
+ (cs.backdropFilter && cs.backdropFilter !== 'none')) {
2370
+ return true;
2371
+ }
2372
+ const contain = cs.contain || '';
2373
+ if (contain.includes('paint') ||
2374
+ contain.includes('layout') ||
2375
+ contain.includes('strict') ||
2376
+ contain.includes('content')) {
2377
+ return true;
2378
+ }
2379
+ const willChange = cs.willChange || '';
2380
+ return /transform|perspective|filter|backdrop-filter/.test(willChange);
2381
+ }
2382
+ /**
2383
+ * @param {HTMLElement} element
2384
+ * @param {HTMLIFrameElement[]=} iframes
2385
+ * @returns {Element | null}
2386
+ */
2387
+ function getNearestFixedContainingBlock(element, iframes) {
2388
+ let parent = getParentElementIncludingSlots(element, iframes);
2389
+ while (parent) {
2390
+ if (createsFixedContainingBlock(parent))
2391
+ return parent;
2392
+ parent = getParentElementIncludingSlots(parent, iframes);
2393
+ }
2394
+ return null;
2395
+ }