@weasel-js/labkit 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_dts/{DrawCommand-CitWPxMY.d.ts → DrawCommand-uKHt4Vul.d.ts} +56 -0
- package/dist/_dts/{index-C6Yze7sQ.d.ts → index-CFlDPeZh.d.ts} +30 -1
- package/dist/_dts/{types-Si4Fw-1F.d.ts → types-x92Kfeme.d.ts} +14 -0
- package/dist/_dts/{useExperimentState-CJn2hHzd.d.ts → useExperimentState-vrttakTt.d.ts} +43 -0
- package/dist/canvas/index.d.ts +13 -2
- package/dist/canvas/index.js +2 -2
- package/dist/{chunk-ISEK5LXT.js → chunk-3WPOGKUP.js} +1603 -1670
- package/dist/chunk-3WPOGKUP.js.map +1 -0
- package/dist/{chunk-54IQ2DX7.js → chunk-574LJAV4.js} +3 -3
- package/dist/chunk-574LJAV4.js.map +1 -0
- package/dist/{chunk-VLAHRJOC.js → chunk-5R2ATYPJ.js} +2 -2
- package/dist/{chunk-VLAHRJOC.js.map → chunk-5R2ATYPJ.js.map} +1 -1
- package/dist/{chunk-EXBV7A6X.js → chunk-73PXCRCR.js} +3 -3
- package/dist/chunk-73PXCRCR.js.map +1 -0
- package/dist/{chunk-PWC7AQZM.js → chunk-CPUJ3QXL.js} +2 -2
- package/dist/chunk-CPUJ3QXL.js.map +1 -0
- package/dist/{chunk-NRD3TDNQ.js → chunk-N5KTQKQA.js} +1462 -1487
- package/dist/chunk-N5KTQKQA.js.map +1 -0
- package/dist/{chunk-HXZHVU4G.js → chunk-PMAU3SEE.js} +3 -3
- package/dist/chunk-PMAU3SEE.js.map +1 -0
- package/dist/{chunk-7BKDG73Z.js → chunk-RL2LOLNI.js} +2 -2
- package/dist/chunk-RL2LOLNI.js.map +1 -0
- package/dist/{chunk-2QNYYL3V.js → chunk-SFL7NFKN.js} +2 -2
- package/dist/chunk-SFL7NFKN.js.map +1 -0
- package/dist/{chunk-53XSBIUK.js → chunk-T7OKNJTY.js} +2 -2
- package/dist/chunk-T7OKNJTY.js.map +1 -0
- package/dist/controls/index.d.ts +4 -2
- package/dist/controls/index.js +1 -1
- package/dist/dragdrop/index.d.ts +2 -2
- package/dist/index.d.ts +122 -6
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +6 -3
- package/dist/layers/index.js +1 -1
- package/dist/passthrough/weasel-canvas.d.ts +5 -1
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +514 -36
- package/dist/passthrough/weasel-ui.js +2 -2
- package/dist/primitives/index.d.ts +13 -0
- package/dist/primitives/index.js +2 -2
- package/dist/state/index.d.ts +15 -2
- package/dist/state/index.js +2 -2
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +147 -0
- package/dist/ui/layers/index.d.ts +5 -0
- package/dist/ui/layers/index.js +3 -3
- package/dist/undo/index.d.ts +17 -2
- package/dist/undo/index.js +1 -1
- package/package.json +2 -2
- package/src/canvas/CanvasStack.tsx +4 -0
- package/src/canvas/CanvasStackContext.ts +3 -0
- package/src/canvas/canvasCoords.ts +2 -0
- package/src/canvas/useLayerScheduler.ts +2 -0
- package/src/controls/ControlPanel.tsx +2 -0
- package/src/controls/types.ts +14 -0
- package/src/instrument/capabilityDetector.ts +3 -0
- package/src/instrument/defineInstrument.ts +2 -0
- package/src/instrument/types.ts +29 -0
- package/src/instrument/validateConfigSchema.ts +5 -0
- package/src/lab/Lab.tsx +3 -0
- package/src/lab/LabContext.ts +5 -0
- package/src/lab/LabShell.tsx +4 -0
- package/src/lab/WorkspaceGrid.tsx +2 -0
- package/src/lab/gridDims.ts +2 -0
- package/src/layers/LayerList.tsx +3 -0
- package/src/primitives/FpsMeter.tsx +1 -0
- package/src/primitives/ScaleIndicator.tsx +4 -0
- package/src/primitives/Sidebar.tsx +3 -0
- package/src/primitives/StatusBar.tsx +3 -0
- package/src/primitives/Toolbar.tsx +6 -0
- package/src/state/SingletonExperiment.tsx +1 -0
- package/src/state/adapters.ts +8 -0
- package/src/state/context.tsx +9 -0
- package/src/state/helpers.ts +12 -0
- package/src/state/store.ts +6 -0
- package/src/state/types.ts +17 -0
- package/src/state/useExperimentState.ts +3 -0
- package/src/ui/layers/LayerStack.tsx +5 -0
- package/src/ui/properties/CurveField.tsx +4 -1
- package/src/ui/properties/EffectCard.tsx +12 -0
- package/src/ui/properties/PropertyGroup.tsx +1 -0
- package/src/ui/properties/PropertyPanel.tsx +28 -0
- package/src/undo/eventBus.ts +4 -0
- package/src/undo/undoStack.ts +11 -0
- package/src/workspace/DefaultSidebar.tsx +3 -0
- package/src/workspace/DefaultStatusBar.tsx +3 -0
- package/src/workspace/DefaultToolbar.tsx +3 -0
- package/src/workspace/Workspace.tsx +3 -0
- package/src/workspace/WorkspaceChrome.tsx +4 -0
- package/src/workspace/slotTypes.ts +9 -0
- package/src/workspace/workspaceOps.ts +8 -0
- package/dist/chunk-2QNYYL3V.js.map +0 -1
- package/dist/chunk-53XSBIUK.js.map +0 -1
- package/dist/chunk-54IQ2DX7.js.map +0 -1
- package/dist/chunk-7BKDG73Z.js.map +0 -1
- package/dist/chunk-EXBV7A6X.js.map +0 -1
- package/dist/chunk-HXZHVU4G.js.map +0 -1
- package/dist/chunk-ISEK5LXT.js.map +0 -1
- package/dist/chunk-NRD3TDNQ.js.map +0 -1
- package/dist/chunk-PWC7AQZM.js.map +0 -1
|
@@ -3,12 +3,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
3
3
|
import earcut from 'earcut';
|
|
4
4
|
import polygonClipping from 'polygon-clipping';
|
|
5
5
|
|
|
6
|
-
// ../core/dist/chunk-
|
|
7
|
-
var __defProp = Object.defineProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
6
|
+
// ../core/dist/chunk-TR3HZN34.js
|
|
12
7
|
|
|
13
8
|
// ../gestures/dist/index.js
|
|
14
9
|
var GESTURE_DESCRIPTORS = [
|
|
@@ -22,7 +17,12 @@ var GESTURE_DESCRIPTORS = [
|
|
|
22
17
|
{ name: "keyHeld", hasTarget: false, arg: { name: "key", values: "free" } },
|
|
23
18
|
{ name: "contextMenu", hasTarget: true },
|
|
24
19
|
{ name: "longPress", hasTarget: true },
|
|
25
|
-
{ name: "multiTouchTap", hasTarget: false, arg: { name: "fingers", values: ["2", "3", "4"] } }
|
|
20
|
+
{ name: "multiTouchTap", hasTarget: false, arg: { name: "fingers", values: ["2", "3", "4"] } },
|
|
21
|
+
// The arg is the MIME-glob filter. No default: a spec with no `types`
|
|
22
|
+
// matches any payload, which is what an omitted arg slot means for a
|
|
23
|
+
// `'free'` arg.
|
|
24
|
+
{ name: "drop", hasTarget: false, arg: { name: "types", values: "free" } },
|
|
25
|
+
{ name: "paste", hasTarget: false, arg: { name: "types", values: "free" } }
|
|
26
26
|
];
|
|
27
27
|
var BY_NAME = new Map(
|
|
28
28
|
GESTURE_DESCRIPTORS.map((d) => [d.name, d])
|
|
@@ -50,176 +50,11 @@ var RESERVED_ID_NAMES = /* @__PURE__ */ new Set([
|
|
|
50
50
|
"engaged"
|
|
51
51
|
]);
|
|
52
52
|
var VALID_MOD_NAMES = ["mod", "shift", "alt", "ctrl", "meta"];
|
|
53
|
-
|
|
54
|
-
var ACTIVE_SIGILS = /* @__PURE__ */ new Set(["+", "?"]);
|
|
55
|
-
var MOD_NAME_SET = new Set(VALID_MOD_NAMES);
|
|
56
|
-
function parseRoute(input) {
|
|
57
|
-
const trimmed = input.trim();
|
|
58
|
-
if (!trimmed.startsWith("[")) {
|
|
59
|
-
throw new Error(`invalid route (phase brackets required): ${input}`);
|
|
60
|
-
}
|
|
61
|
-
const closeIdx = trimmed.indexOf("]");
|
|
62
|
-
if (closeIdx < 0) throw new Error(`invalid route (unclosed phase bracket): ${input}`);
|
|
63
|
-
const phaseListRaw = trimmed.slice(1, closeIdx).trim();
|
|
64
|
-
const phases = parsePhaseList(phaseListRaw, input);
|
|
65
|
-
let rest = trimmed.slice(closeIdx + 1).trim();
|
|
66
|
-
const gestureMatch = /^([A-Za-z]+)/.exec(rest);
|
|
67
|
-
if (!gestureMatch) throw new Error(`invalid route (no gesture name): ${input}`);
|
|
68
|
-
const gestureName = gestureMatch[1];
|
|
69
|
-
if (!isKnownGestureName(gestureName)) {
|
|
70
|
-
throw new Error(`invalid route (unknown gesture "${gestureName}"): ${input}`);
|
|
71
|
-
}
|
|
72
|
-
rest = rest.slice(gestureMatch[0].length).trimStart();
|
|
73
|
-
const desc = getGestureDescriptor(gestureName);
|
|
74
|
-
let arg;
|
|
75
|
-
if (rest.startsWith("(")) {
|
|
76
|
-
const closeArg = rest.indexOf(")");
|
|
77
|
-
if (closeArg < 0) throw new Error(`invalid route (unbalanced arg parens): ${input}`);
|
|
78
|
-
const argRaw = rest.slice(1, closeArg);
|
|
79
|
-
if (!desc.arg) throw new Error(`invalid route (${gestureName} has no arg): ${input}`);
|
|
80
|
-
if (argRaw !== "*" && desc.arg.values !== "free" && !desc.arg.values.includes(argRaw)) {
|
|
81
|
-
throw new Error(`invalid route ("${argRaw}" not in ${desc.arg.values.join("|")}): ${input}`);
|
|
82
|
-
}
|
|
83
|
-
arg = argRaw;
|
|
84
|
-
rest = rest.slice(closeArg + 1).trimStart();
|
|
85
|
-
} else if (desc.arg) {
|
|
86
|
-
arg = desc.arg.default ?? "*";
|
|
87
|
-
}
|
|
88
|
-
let target;
|
|
89
|
-
if (rest.startsWith("=>")) {
|
|
90
|
-
if (!desc.hasTarget) throw new Error(`invalid route (${gestureName} has no target): ${input}`);
|
|
91
|
-
rest = rest.slice(2).trimStart();
|
|
92
|
-
const tgtMatch = /^([^\s+?!@#$%^&]+)/.exec(rest);
|
|
93
|
-
if (!tgtMatch) throw new Error(`invalid route (missing target after "=>"): ${input}`);
|
|
94
|
-
target = tgtMatch[1];
|
|
95
|
-
rest = rest.slice(tgtMatch[0].length).trimStart();
|
|
96
|
-
} else if (desc.hasTarget) {
|
|
97
|
-
target = "*";
|
|
98
|
-
}
|
|
99
|
-
const modifiers = {};
|
|
100
|
-
while (rest.length > 0) {
|
|
101
|
-
const ch = rest[0];
|
|
102
|
-
if (RESERVED_SIGILS.has(ch)) {
|
|
103
|
-
throw new Error(`invalid route ("${ch}" is reserved for future use): ${input}`);
|
|
104
|
-
}
|
|
105
|
-
if (!ACTIVE_SIGILS.has(ch)) {
|
|
106
|
-
throw new Error(`invalid route (unexpected "${ch}" at "${rest}"): ${input}`);
|
|
107
|
-
}
|
|
108
|
-
const sigil = ch;
|
|
109
|
-
rest = rest.slice(1);
|
|
110
|
-
const nameMatch = /^([a-z]+)/.exec(rest);
|
|
111
|
-
if (!nameMatch) throw new Error(`invalid route (sigil "${sigil}" without modifier name): ${input}`);
|
|
112
|
-
const name = nameMatch[1];
|
|
113
|
-
if (!MOD_NAME_SET.has(name)) {
|
|
114
|
-
throw new Error(`invalid route (unknown modifier "${name}"): ${input}`);
|
|
115
|
-
}
|
|
116
|
-
if (modifiers[name] !== void 0) {
|
|
117
|
-
throw new Error(`invalid route (duplicate modifier "${name}"): ${input}`);
|
|
118
|
-
}
|
|
119
|
-
modifiers[name] = sigil === "+" ? "required" : "optional";
|
|
120
|
-
rest = rest.slice(nameMatch[0].length).trimStart();
|
|
121
|
-
}
|
|
122
|
-
return { phases, gesture: gestureName, arg, target, modifiers };
|
|
123
|
-
}
|
|
124
|
-
function parsePhaseList(raw, input) {
|
|
125
|
-
if (raw === "") throw new Error(`invalid route (empty phase list): ${input}`);
|
|
126
|
-
const tokens = raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
127
|
-
if (tokens.length === 0) throw new Error(`invalid route (empty phase list): ${input}`);
|
|
128
|
-
return tokens.map((t) => parsePhaseAtom(t, input));
|
|
129
|
-
}
|
|
130
|
-
var VALID_PHASES = /* @__PURE__ */ new Set(["initial", "engaged", "*"]);
|
|
131
|
-
function parsePhaseAtom(raw, input) {
|
|
132
|
-
const parts = raw.split(":");
|
|
133
|
-
if (parts.length > 2) {
|
|
134
|
-
throw new Error(`invalid route (phase atom "${raw}" has multiple ":"): ${input}`);
|
|
135
|
-
}
|
|
136
|
-
if (parts.length === 1) {
|
|
137
|
-
const phase2 = parts[0];
|
|
138
|
-
if (!VALID_PHASES.has(phase2)) {
|
|
139
|
-
throw new Error(`invalid route (unknown phase "${phase2}" in "${raw}"): ${input}`);
|
|
140
|
-
}
|
|
141
|
-
return { channel: "&", phase: phase2 };
|
|
142
|
-
}
|
|
143
|
-
const channel = parts[0];
|
|
144
|
-
const phase = parts[1];
|
|
145
|
-
if (channel === "") {
|
|
146
|
-
throw new Error(`invalid route (empty channel before ":" in "${raw}"): ${input}`);
|
|
147
|
-
}
|
|
148
|
-
if (!VALID_PHASES.has(phase)) {
|
|
149
|
-
throw new Error(`invalid route (unknown phase "${phase}" in "${raw}"): ${input}`);
|
|
150
|
-
}
|
|
151
|
-
if (channel !== "&" && channel !== "*") {
|
|
152
|
-
if (RESERVED_ID_NAMES.has(channel)) {
|
|
153
|
-
throw new Error(`invalid route (channel "${channel}" is a reserved phase keyword): ${input}`);
|
|
154
|
-
}
|
|
155
|
-
if (RESERVED_ID_PREFIXES.has(channel[0])) {
|
|
156
|
-
throw new Error(`invalid route (channel "${channel}" starts with reserved sigil "${channel[0]}"): ${input}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return { channel, phase };
|
|
160
|
-
}
|
|
53
|
+
new Set(VALID_MOD_NAMES);
|
|
161
54
|
function formatPhaseAtom(a) {
|
|
162
55
|
if (a.channel === "&") return a.phase;
|
|
163
56
|
return `${a.channel}:${a.phase}`;
|
|
164
57
|
}
|
|
165
|
-
function collapseShiftPairs(routes) {
|
|
166
|
-
if (routes.length < 2) return [...routes];
|
|
167
|
-
const parsed = routes.map((r) => ({ raw: r, p: parseRoute(r) }));
|
|
168
|
-
const consumed = /* @__PURE__ */ new Set();
|
|
169
|
-
const out = [];
|
|
170
|
-
for (let i = 0; i < parsed.length; i++) {
|
|
171
|
-
if (consumed.has(i)) continue;
|
|
172
|
-
const a = parsed[i];
|
|
173
|
-
let twinIndex = -1;
|
|
174
|
-
for (let j = i + 1; j < parsed.length; j++) {
|
|
175
|
-
if (consumed.has(j)) continue;
|
|
176
|
-
const b = parsed[j];
|
|
177
|
-
if (isShiftTwin(a.p, b.p)) {
|
|
178
|
-
twinIndex = j;
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
if (twinIndex < 0) {
|
|
183
|
-
out.push(a.raw);
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
consumed.add(twinIndex);
|
|
187
|
-
const folded = {
|
|
188
|
-
...a.p,
|
|
189
|
-
modifiers: { ...withoutShift(a.p.modifiers), shift: "optional" }
|
|
190
|
-
};
|
|
191
|
-
out.push(formatRoute(folded));
|
|
192
|
-
}
|
|
193
|
-
return out;
|
|
194
|
-
}
|
|
195
|
-
function isShiftTwin(a, b) {
|
|
196
|
-
if (a.gesture !== b.gesture) return false;
|
|
197
|
-
if (a.arg !== b.arg) return false;
|
|
198
|
-
if (a.target !== b.target) return false;
|
|
199
|
-
if (!samePhases(a.phases, b.phases)) return false;
|
|
200
|
-
const aShift = a.modifiers.shift;
|
|
201
|
-
const bShift = b.modifiers.shift;
|
|
202
|
-
const aHas = aShift === "required";
|
|
203
|
-
const bHas = bShift === "required";
|
|
204
|
-
if (!(aHas !== bHas)) return false;
|
|
205
|
-
if (aShift === "optional" || bShift === "optional") return false;
|
|
206
|
-
for (const name of VALID_MOD_NAMES) {
|
|
207
|
-
if (name === "shift") continue;
|
|
208
|
-
if (a.modifiers[name] !== b.modifiers[name]) return false;
|
|
209
|
-
}
|
|
210
|
-
return true;
|
|
211
|
-
}
|
|
212
|
-
function samePhases(a, b) {
|
|
213
|
-
if (a.length !== b.length) return false;
|
|
214
|
-
for (let i = 0; i < a.length; i++) {
|
|
215
|
-
if (a[i].channel !== b[i].channel || a[i].phase !== b[i].phase) return false;
|
|
216
|
-
}
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
function withoutShift(m) {
|
|
220
|
-
const { shift: _shift, ...rest } = m;
|
|
221
|
-
return rest;
|
|
222
|
-
}
|
|
223
58
|
var MOD_ORDER = ["mod", "shift", "alt", "ctrl", "meta"];
|
|
224
59
|
function formatRoute(r) {
|
|
225
60
|
const desc = getGestureDescriptor(r.gesture);
|
|
@@ -240,122 +75,6 @@ function formatRoute(r) {
|
|
|
240
75
|
return out;
|
|
241
76
|
}
|
|
242
77
|
new Set(VALID_MOD_NAMES);
|
|
243
|
-
var MOD_NAMES = {
|
|
244
|
-
mod: "Mod",
|
|
245
|
-
shift: "Shift",
|
|
246
|
-
alt: "Alt",
|
|
247
|
-
ctrl: "Ctrl",
|
|
248
|
-
meta: "Meta"
|
|
249
|
-
};
|
|
250
|
-
var MOD_ORDER2 = ["mod", "shift", "alt", "ctrl", "meta"];
|
|
251
|
-
var ROUTE_TERMS = {
|
|
252
|
-
idle: "Not in the middle of a drag or other synchronous operation.",
|
|
253
|
-
"mid-gesture": "In the middle of a drag or other synchronous operation."
|
|
254
|
-
};
|
|
255
|
-
var ROUTE_FIELD_DEFINITIONS = {
|
|
256
|
-
phases: "Which lifecycle stage(s) a channel must be in for this route to fire. `initial` = the channel is idle; `engaged` = the channel is mid-gesture. The channel is the binding's own tool (`&`), any tool (`*`), or a named tool id.",
|
|
257
|
-
gesture: "The class of input event that triggers this route \u2014 click, drag, double-tap, keyDown/keyUp, wheel, contextMenu, or multiTouchTap.",
|
|
258
|
-
arg: "Sub-class of the gesture. Direction for wheel (up / down / *), key name for keyDown / keyUp, finger count for multiTouchTap. Other gestures have no arg slot.",
|
|
259
|
-
target: "Which hit-test result the gesture must land on. `*` matches any target; `empty` matches the empty canvas; otherwise the value names a specific hit-target kind.",
|
|
260
|
-
modifiers: "Modifier keys the user must hold (`+key`) or may optionally hold (`?key`) for this route to match. Unlisted modifiers must not be held."
|
|
261
|
-
};
|
|
262
|
-
function term(label) {
|
|
263
|
-
return { kind: "term", label, definition: ROUTE_TERMS[label] };
|
|
264
|
-
}
|
|
265
|
-
function joinAnd(parts) {
|
|
266
|
-
if (parts.length === 0) return "";
|
|
267
|
-
if (parts.length === 1) return parts[0];
|
|
268
|
-
if (parts.length === 2) return `${parts[0]} and ${parts[1]}`;
|
|
269
|
-
return `${parts.slice(0, -1).join(", ")}, and ${parts[parts.length - 1]}`;
|
|
270
|
-
}
|
|
271
|
-
function partitionModifiers(mods2) {
|
|
272
|
-
const required = [];
|
|
273
|
-
const optional = [];
|
|
274
|
-
for (const name of MOD_ORDER2) {
|
|
275
|
-
const req = mods2[name];
|
|
276
|
-
if (req === "required") required.push(MOD_NAMES[name]);
|
|
277
|
-
else if (req === "optional") optional.push(MOD_NAMES[name]);
|
|
278
|
-
}
|
|
279
|
-
return { required, optional };
|
|
280
|
-
}
|
|
281
|
-
function phaseAtomParts({ channel, phase }) {
|
|
282
|
-
const subject = channel === "&" ? "the tool" : channel === "*" ? "any tool" : `the ${channel} tool`;
|
|
283
|
-
if (phase === "initial") return [`${subject} is `, term("idle")];
|
|
284
|
-
if (phase === "engaged") return [`${subject} is `, term("mid-gesture")];
|
|
285
|
-
return [`${subject} is in any phase`];
|
|
286
|
-
}
|
|
287
|
-
function phasesParts(phases) {
|
|
288
|
-
if (phases.length === 1) return phaseAtomParts(phases[0]);
|
|
289
|
-
const out = [];
|
|
290
|
-
phases.forEach((p, i) => {
|
|
291
|
-
if (i > 0) out.push(" or ");
|
|
292
|
-
out.push(...phaseAtomParts(p));
|
|
293
|
-
});
|
|
294
|
-
return out;
|
|
295
|
-
}
|
|
296
|
-
function targetClause(target, hasTarget) {
|
|
297
|
-
if (!hasTarget || target === void 0) return "";
|
|
298
|
-
if (target === "*") return " anywhere";
|
|
299
|
-
if (target === "empty") return " on empty canvas";
|
|
300
|
-
return ` on a ${target}`;
|
|
301
|
-
}
|
|
302
|
-
function actionClause(parsed, required) {
|
|
303
|
-
const desc = getGestureDescriptor(parsed.gesture);
|
|
304
|
-
const modPrefix = required.length > 0 ? `${joinAnd(required)}-` : "";
|
|
305
|
-
const target = targetClause(parsed.target, desc.hasTarget);
|
|
306
|
-
switch (parsed.gesture) {
|
|
307
|
-
case "keyDown":
|
|
308
|
-
case "keyUp":
|
|
309
|
-
case "keyHeld": {
|
|
310
|
-
const verb = parsed.gesture === "keyDown" ? "presses" : parsed.gesture === "keyUp" ? "releases" : "holds";
|
|
311
|
-
const key = parsed.arg ?? "any key";
|
|
312
|
-
return required.length > 0 ? `the user holds ${joinAnd(required)} and ${verb} ${key}` : `the user ${verb} ${key}`;
|
|
313
|
-
}
|
|
314
|
-
case "wheel": {
|
|
315
|
-
const direction = parsed.arg === "up" ? " up" : parsed.arg === "down" ? " down" : "";
|
|
316
|
-
return `the user ${modPrefix}scrolls${direction}`;
|
|
317
|
-
}
|
|
318
|
-
case "multiTouchTap":
|
|
319
|
-
return `the user taps with ${parsed.arg ?? "multiple"} fingers`;
|
|
320
|
-
case "contextMenu":
|
|
321
|
-
return `the user ${modPrefix}opens the context menu${target}`;
|
|
322
|
-
case "longPress":
|
|
323
|
-
return `the user ${modPrefix}presses and holds${target}`;
|
|
324
|
-
case "click":
|
|
325
|
-
return `the user ${modPrefix}clicks${target}`;
|
|
326
|
-
case "pointerDown":
|
|
327
|
-
return `the user ${modPrefix}presses${target}`;
|
|
328
|
-
case "dblTap":
|
|
329
|
-
return `the user ${modPrefix}double-taps${target}`;
|
|
330
|
-
case "drag":
|
|
331
|
-
return `the user ${modPrefix}drags${target}`;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
function describeRouteParts(parsed, opts = {}) {
|
|
335
|
-
const { capitalize = true, period = true } = opts;
|
|
336
|
-
const { required, optional } = partitionModifiers(parsed.modifiers);
|
|
337
|
-
const action = actionClause(parsed, required);
|
|
338
|
-
const optClause = optional.length > 0 ? ` (${joinAnd(optional)} optional)` : "";
|
|
339
|
-
const parts = [];
|
|
340
|
-
const head = `fires when ${action}, while `;
|
|
341
|
-
parts.push(capitalize ? head.charAt(0).toUpperCase() + head.slice(1) : head);
|
|
342
|
-
parts.push(...phasesParts(parsed.phases));
|
|
343
|
-
if (optClause) parts.push(optClause);
|
|
344
|
-
if (period) parts.push(".");
|
|
345
|
-
return mergeAdjacentStrings(parts);
|
|
346
|
-
}
|
|
347
|
-
function describeRoute(parsed, opts = {}) {
|
|
348
|
-
return describeRouteParts(parsed, opts).map((p) => typeof p === "string" ? p : p.label).join("");
|
|
349
|
-
}
|
|
350
|
-
function mergeAdjacentStrings(parts) {
|
|
351
|
-
const out = [];
|
|
352
|
-
for (const p of parts) {
|
|
353
|
-
const last = out[out.length - 1];
|
|
354
|
-
if (typeof p === "string" && typeof last === "string") out[out.length - 1] = last + p;
|
|
355
|
-
else out.push(p);
|
|
356
|
-
}
|
|
357
|
-
return out;
|
|
358
|
-
}
|
|
359
78
|
function canonicalModifiers(mods2) {
|
|
360
79
|
return Object.entries(mods2).sort(([a], [b]) => a.localeCompare(b)).map(([name, req]) => `${name}=${req}`).join("&");
|
|
361
80
|
}
|
|
@@ -568,144 +287,8 @@ function matchSpec(e, spec, isMac, phaseCtx) {
|
|
|
568
287
|
}
|
|
569
288
|
}
|
|
570
289
|
var EMPTY_ENGAGED = /* @__PURE__ */ new Set();
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
GESTURE_DESCRIPTORS: () => GESTURE_DESCRIPTORS,
|
|
574
|
-
PREDICATE_TARGET: () => PREDICATE_TARGET,
|
|
575
|
-
RESERVED_ID_NAMES: () => RESERVED_ID_NAMES,
|
|
576
|
-
RESERVED_ID_PREFIXES: () => RESERVED_ID_PREFIXES,
|
|
577
|
-
ROUTE_FIELD_DEFINITIONS: () => ROUTE_FIELD_DEFINITIONS,
|
|
578
|
-
ROUTE_TERMS: () => ROUTE_TERMS,
|
|
579
|
-
buildRouteRegistry: () => buildRouteRegistry,
|
|
580
|
-
canonicalModifiers: () => canonicalModifiers,
|
|
581
|
-
collapseShiftPairs: () => collapseShiftPairs,
|
|
582
|
-
defineTool: () => defineTool,
|
|
583
|
-
defineViewportTool: () => defineViewportTool,
|
|
584
|
-
describeRoute: () => describeRoute,
|
|
585
|
-
describeRouteParts: () => describeRouteParts,
|
|
586
|
-
findConflicts: () => findConflicts,
|
|
587
|
-
findScopedConflicts: () => findScopedConflicts,
|
|
588
|
-
formatConflict: () => formatConflict,
|
|
589
|
-
formatPhaseAtom: () => formatPhaseAtom,
|
|
590
|
-
formatRoute: () => formatRoute,
|
|
591
|
-
getGestureDescriptor: () => getGestureDescriptor,
|
|
592
|
-
isKnownGestureName: () => isKnownGestureName,
|
|
593
|
-
parseRoute: () => parseRoute,
|
|
594
|
-
reportRouteConflicts: () => reportRouteConflicts
|
|
595
|
-
});
|
|
596
|
-
function validateId(id, kind) {
|
|
597
|
-
if (id.length === 0) {
|
|
598
|
-
throw new Error(`weasel: ${kind} id may not be empty`);
|
|
599
|
-
}
|
|
600
|
-
if (RESERVED_ID_PREFIXES.has(id[0])) {
|
|
601
|
-
throw new Error(
|
|
602
|
-
`weasel: ${kind} id "${id}" starts with reserved sigil "${id[0]}" (reserved set: ${[...RESERVED_ID_PREFIXES].join(" ")})`
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
if (RESERVED_ID_NAMES.has(id)) {
|
|
606
|
-
throw new Error(
|
|
607
|
-
`weasel: ${kind} id "${id}" collides with a reserved phase keyword (reserved: ${[...RESERVED_ID_NAMES].join(", ")})`
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
function defineTool(def) {
|
|
612
|
-
validateId(def.id, "tool");
|
|
613
|
-
const resolveCursor = (ctx) => {
|
|
614
|
-
if (def.cursor == null) return "";
|
|
615
|
-
return typeof def.cursor === "function" ? def.cursor(ctx) : def.cursor;
|
|
616
|
-
};
|
|
617
|
-
return {
|
|
618
|
-
id: def.id,
|
|
619
|
-
eligibility: {
|
|
620
|
-
focus: true,
|
|
621
|
-
capabilities: def.capabilities,
|
|
622
|
-
...def.hotkey ? { offhand: def.hotkey } : {}
|
|
623
|
-
},
|
|
624
|
-
actions: def.actions,
|
|
625
|
-
def,
|
|
626
|
-
presentation: def.presentation,
|
|
627
|
-
keybinding: def.keybinding,
|
|
628
|
-
onActivate: def.onActivate,
|
|
629
|
-
onDeactivate: def.onDeactivate,
|
|
630
|
-
initScratch: def.initScratch ?? (() => null),
|
|
631
|
-
cursor: resolveCursor,
|
|
632
|
-
bindings: def.bindings,
|
|
633
|
-
overlay: def.overlay
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
function defineViewportTool(def) {
|
|
637
|
-
return defineTool(def);
|
|
638
|
-
}
|
|
639
|
-
var PREDICATE_TARGET = "predicate";
|
|
640
|
-
var SPEC_KIND_TO_GESTURE = {
|
|
641
|
-
key: "keyDown",
|
|
642
|
-
"key-held": "keyHeld",
|
|
643
|
-
wheel: "wheel",
|
|
644
|
-
click: "click",
|
|
645
|
-
doubleClick: "dblTap",
|
|
646
|
-
contextMenu: "contextMenu",
|
|
647
|
-
longPress: "longPress",
|
|
648
|
-
drag: "drag",
|
|
649
|
-
pointerDown: "pointerDown",
|
|
650
|
-
multiTouch: void 0,
|
|
651
|
-
multiTouchTap: "multiTouchTap",
|
|
652
|
-
drop: void 0,
|
|
653
|
-
paste: void 0
|
|
654
|
-
};
|
|
655
|
-
function buildRouteRegistry(tools) {
|
|
656
|
-
const out = [];
|
|
657
|
-
for (const tool of tools) {
|
|
658
|
-
for (const binding of tool.bindings ?? []) {
|
|
659
|
-
const entry = entryFor(tool.id, binding.spec, binding.actionId);
|
|
660
|
-
if (entry) out.push(entry);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return out;
|
|
664
|
-
}
|
|
665
|
-
function entryFor(toolId, spec, actionId) {
|
|
666
|
-
const gesture = SPEC_KIND_TO_GESTURE[spec.kind];
|
|
667
|
-
if (!gesture || !isKnownGestureName(gesture)) return null;
|
|
668
|
-
const descriptor = getGestureDescriptor(gesture);
|
|
669
|
-
return {
|
|
670
|
-
toolId,
|
|
671
|
-
actionId,
|
|
672
|
-
gesture,
|
|
673
|
-
phase: phaseOf("phase" in spec ? spec.phase : void 0),
|
|
674
|
-
modifiers: parseModSpec("mods" in spec ? spec.mods : void 0),
|
|
675
|
-
arg: descriptor.arg ? argOf(spec, descriptor.arg.default) : void 0,
|
|
676
|
-
target: descriptor.hasTarget ? targetOf("target" in spec ? spec.target : void 0) : void 0,
|
|
677
|
-
spec
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
function phaseOf(phase) {
|
|
681
|
-
if (phase === void 0 || phase === "*") return "any";
|
|
682
|
-
if (phase === "initial" || phase === "engaged") return phase;
|
|
683
|
-
const distinct = new Set(phase.map((atom) => atom.phase));
|
|
684
|
-
if (distinct.size !== 1) return "any";
|
|
685
|
-
const only = [...distinct][0];
|
|
686
|
-
return only === "initial" || only === "engaged" ? only : "any";
|
|
687
|
-
}
|
|
688
|
-
function parseModSpec(mods) {
|
|
689
|
-
if (!mods) return {};
|
|
690
|
-
const out = {};
|
|
691
|
-
for (const [name, req] of Object.entries(mods)) {
|
|
692
|
-
if (req === true) out[name] = "required";
|
|
693
|
-
else if (req === "optional") out[name] = "optional";
|
|
694
|
-
}
|
|
695
|
-
return out;
|
|
696
|
-
}
|
|
697
|
-
function targetOf(target) {
|
|
698
|
-
if (target === void 0) return void 0;
|
|
699
|
-
return typeof target === "string" ? target : PREDICATE_TARGET;
|
|
700
|
-
}
|
|
701
|
-
function argOf(spec, fallback) {
|
|
702
|
-
if ("key" in spec) {
|
|
703
|
-
return Array.isArray(spec.key) ? spec.key.join("|") : spec.key;
|
|
704
|
-
}
|
|
705
|
-
if ("fingers" in spec) return String(spec.fingers);
|
|
706
|
-
if ("direction" in spec) return spec.direction ?? fallback;
|
|
707
|
-
return fallback;
|
|
708
|
-
}
|
|
290
|
+
|
|
291
|
+
// ../core/dist/chunk-TR3HZN34.js
|
|
709
292
|
var DepRegistryContext = createContext(null);
|
|
710
293
|
function DepRegistryProvider({ children }) {
|
|
711
294
|
const sourcesRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -955,6 +538,77 @@ function ActionsProvider({ children }) {
|
|
|
955
538
|
function useActionsRegistry() {
|
|
956
539
|
return useContext(ActionsContext);
|
|
957
540
|
}
|
|
541
|
+
var PREDICATE_TARGET = "predicate";
|
|
542
|
+
var SPEC_KIND_TO_GESTURE = {
|
|
543
|
+
key: "keyDown",
|
|
544
|
+
"key-held": "keyHeld",
|
|
545
|
+
wheel: "wheel",
|
|
546
|
+
click: "click",
|
|
547
|
+
doubleClick: "dblTap",
|
|
548
|
+
contextMenu: "contextMenu",
|
|
549
|
+
longPress: "longPress",
|
|
550
|
+
drag: "drag",
|
|
551
|
+
pointerDown: "pointerDown",
|
|
552
|
+
multiTouch: void 0,
|
|
553
|
+
multiTouchTap: "multiTouchTap",
|
|
554
|
+
drop: "drop",
|
|
555
|
+
paste: "paste"
|
|
556
|
+
};
|
|
557
|
+
function buildRouteRegistry(tools) {
|
|
558
|
+
const out = [];
|
|
559
|
+
for (const tool of tools) {
|
|
560
|
+
for (const binding of tool.bindings ?? []) {
|
|
561
|
+
const entry = entryFor(tool.id, binding.spec, binding.actionId);
|
|
562
|
+
if (entry) out.push(entry);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return out;
|
|
566
|
+
}
|
|
567
|
+
function entryFor(toolId, spec, actionId) {
|
|
568
|
+
const gesture = SPEC_KIND_TO_GESTURE[spec.kind];
|
|
569
|
+
if (!gesture || !isKnownGestureName(gesture)) return null;
|
|
570
|
+
const descriptor = getGestureDescriptor(gesture);
|
|
571
|
+
return {
|
|
572
|
+
toolId,
|
|
573
|
+
actionId,
|
|
574
|
+
gesture,
|
|
575
|
+
phase: phaseOf("phase" in spec ? spec.phase : void 0),
|
|
576
|
+
modifiers: parseModSpec("mods" in spec ? spec.mods : void 0),
|
|
577
|
+
arg: descriptor.arg ? argOf(spec, descriptor.arg.default) : void 0,
|
|
578
|
+
target: descriptor.hasTarget ? targetOf("target" in spec ? spec.target : void 0) : void 0,
|
|
579
|
+
spec
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
function phaseOf(phase) {
|
|
583
|
+
if (phase === void 0 || phase === "*") return "any";
|
|
584
|
+
if (phase === "initial" || phase === "engaged") return phase;
|
|
585
|
+
const distinct = new Set(phase.map((atom) => atom.phase));
|
|
586
|
+
if (distinct.size !== 1) return "any";
|
|
587
|
+
const only = [...distinct][0];
|
|
588
|
+
return only === "initial" || only === "engaged" ? only : "any";
|
|
589
|
+
}
|
|
590
|
+
function parseModSpec(mods) {
|
|
591
|
+
if (!mods) return {};
|
|
592
|
+
const out = {};
|
|
593
|
+
for (const [name, req] of Object.entries(mods)) {
|
|
594
|
+
if (req === true) out[name] = "required";
|
|
595
|
+
else if (req === "optional") out[name] = "optional";
|
|
596
|
+
}
|
|
597
|
+
return out;
|
|
598
|
+
}
|
|
599
|
+
function targetOf(target) {
|
|
600
|
+
if (target === void 0) return void 0;
|
|
601
|
+
return typeof target === "string" ? target : PREDICATE_TARGET;
|
|
602
|
+
}
|
|
603
|
+
function argOf(spec, fallback) {
|
|
604
|
+
if ("key" in spec) {
|
|
605
|
+
return Array.isArray(spec.key) ? spec.key.join("|") : spec.key;
|
|
606
|
+
}
|
|
607
|
+
if ("fingers" in spec) return String(spec.fingers);
|
|
608
|
+
if ("direction" in spec) return spec.direction ?? fallback;
|
|
609
|
+
if ("types" in spec) return spec.types?.length ? spec.types.join("|") : fallback;
|
|
610
|
+
return fallback;
|
|
611
|
+
}
|
|
958
612
|
function findConflicts(tools) {
|
|
959
613
|
const entries = buildRouteRegistry(tools);
|
|
960
614
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -1045,7 +699,7 @@ function reportRouteConflicts(scopes, warn = (m) => console.warn(m)) {
|
|
|
1045
699
|
return conflicts;
|
|
1046
700
|
}
|
|
1047
701
|
|
|
1048
|
-
// ../geom/dist/chunk-
|
|
702
|
+
// ../geom/dist/chunk-UULRZUHO.js
|
|
1049
703
|
function cubicEvalAt(x0, y0, x1, y1, x2, y2, x3, y3, t) {
|
|
1050
704
|
const u = 1 - t;
|
|
1051
705
|
const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
|
|
@@ -1161,7 +815,7 @@ function transformCoords(coords, m) {
|
|
|
1161
815
|
return out;
|
|
1162
816
|
}
|
|
1163
817
|
|
|
1164
|
-
// ../core/dist/chunk-
|
|
818
|
+
// ../core/dist/chunk-U45SODC2.js
|
|
1165
819
|
function resolveUnit(v, unitSystem) {
|
|
1166
820
|
if (typeof v === "number") return v;
|
|
1167
821
|
if (!unitSystem) {
|
|
@@ -1909,7 +1563,7 @@ function createDeleteOp(args) {
|
|
|
1909
1563
|
}
|
|
1910
1564
|
registerOpFactory("delete", (args) => createDeleteOp(args));
|
|
1911
1565
|
|
|
1912
|
-
// ../core/dist/chunk-
|
|
1566
|
+
// ../core/dist/chunk-3KGMJMOS.js
|
|
1913
1567
|
function createTransformOp(args) {
|
|
1914
1568
|
const { id, from, to, label, coalesceKey = `transform:${id}` } = args;
|
|
1915
1569
|
return {
|
|
@@ -1990,7 +1644,7 @@ function snap(strategy, opts = {}) {
|
|
|
1990
1644
|
};
|
|
1991
1645
|
}
|
|
1992
1646
|
|
|
1993
|
-
// ../core/dist/chunk-
|
|
1647
|
+
// ../core/dist/chunk-3JYFAQIB.js
|
|
1994
1648
|
function lockAspectWithModifier(opts = {}) {
|
|
1995
1649
|
const { key = "shift" } = opts;
|
|
1996
1650
|
return {
|
|
@@ -2186,7 +1840,7 @@ function materializePaste(adapter, snapshot, opts) {
|
|
|
2186
1840
|
return { ops, newIds, created };
|
|
2187
1841
|
}
|
|
2188
1842
|
|
|
2189
|
-
// ../core/dist/chunk-
|
|
1843
|
+
// ../core/dist/chunk-HGF5X6MZ.js
|
|
2190
1844
|
var counter = 0;
|
|
2191
1845
|
var registry = /* @__PURE__ */ new Map();
|
|
2192
1846
|
function getTexture(id) {
|
|
@@ -2344,7 +1998,7 @@ function chunks(params) {
|
|
|
2344
1998
|
return build({ tile: "chunks", ...params });
|
|
2345
1999
|
}
|
|
2346
2000
|
|
|
2347
|
-
// ../font/dist/
|
|
2001
|
+
// ../font/dist/chunk-3RSTZDXH.js
|
|
2348
2002
|
var subscribers = /* @__PURE__ */ new Set();
|
|
2349
2003
|
var generation = 0;
|
|
2350
2004
|
function glyphGeneration() {
|
|
@@ -2687,17 +2341,17 @@ function dynamicPageTextureId(page) {
|
|
|
2687
2341
|
return `weasel-dyn-sdf-page-${page}`;
|
|
2688
2342
|
}
|
|
2689
2343
|
var uploadedVersions = /* @__PURE__ */ new WeakMap();
|
|
2690
|
-
function syncDynamicPageTexture(
|
|
2344
|
+
function syncDynamicPageTexture(cache8, pageIndex) {
|
|
2691
2345
|
const page = pages[pageIndex];
|
|
2692
2346
|
if (!page) return false;
|
|
2693
2347
|
const id = dynamicPageTextureId(pageIndex);
|
|
2694
|
-
let seen = uploadedVersions.get(
|
|
2348
|
+
let seen = uploadedVersions.get(cache8);
|
|
2695
2349
|
if (!seen) {
|
|
2696
2350
|
seen = /* @__PURE__ */ new Map();
|
|
2697
|
-
uploadedVersions.set(
|
|
2351
|
+
uploadedVersions.set(cache8, seen);
|
|
2698
2352
|
}
|
|
2699
|
-
if (!
|
|
2700
|
-
|
|
2353
|
+
if (!cache8.has(id)) {
|
|
2354
|
+
cache8.uploadR8(id, PAGE_SIZE, PAGE_SIZE, page.data);
|
|
2701
2355
|
seen.set(pageIndex, page.version);
|
|
2702
2356
|
return true;
|
|
2703
2357
|
}
|
|
@@ -2710,7 +2364,7 @@ function syncDynamicPageTexture(cache7, pageIndex) {
|
|
|
2710
2364
|
const src = (patch.y + row) * PAGE_SIZE + patch.x;
|
|
2711
2365
|
tight.set(page.data.subarray(src, src + patch.w), row * patch.w);
|
|
2712
2366
|
}
|
|
2713
|
-
|
|
2367
|
+
cache8.subImageR8(id, patch.x, patch.y, patch.w, patch.h, tight);
|
|
2714
2368
|
}
|
|
2715
2369
|
seen.set(pageIndex, page.version);
|
|
2716
2370
|
return true;
|
|
@@ -2988,6 +2642,8 @@ function warnOnce(key, message) {
|
|
|
2988
2642
|
warned.add(key);
|
|
2989
2643
|
console.warn(message);
|
|
2990
2644
|
}
|
|
2645
|
+
|
|
2646
|
+
// ../font/dist/index.js
|
|
2991
2647
|
var TEXT_VERT_SRC = (
|
|
2992
2648
|
/* glsl */
|
|
2993
2649
|
`#version 300 es
|
|
@@ -3084,7 +2740,7 @@ var TEXT_SDF_UNIFORMS = [
|
|
|
3084
2740
|
];
|
|
3085
2741
|
var TEXT_SDF_ATTRIBUTES = ["a_position", "a_uv", "a_baselineY"];
|
|
3086
2742
|
|
|
3087
|
-
// ../modes/dist/chunk-
|
|
2743
|
+
// ../modes/dist/chunk-YAJYQMBG.js
|
|
3088
2744
|
var NORMAL = {
|
|
3089
2745
|
allows: [
|
|
3090
2746
|
"creates-selection",
|
|
@@ -3477,7 +3133,7 @@ function serialToEntry(se, custom, logger) {
|
|
|
3477
3133
|
};
|
|
3478
3134
|
}
|
|
3479
3135
|
|
|
3480
|
-
// ../core/dist/chunk-
|
|
3136
|
+
// ../core/dist/chunk-SMCZRSYB.js
|
|
3481
3137
|
function worldToScreen(worldX, worldY, view) {
|
|
3482
3138
|
return [view.panX + worldX * view.zoom.x, view.panY + worldY * view.zoom.y];
|
|
3483
3139
|
}
|
|
@@ -3791,6 +3447,8 @@ var GLMeshCache = class {
|
|
|
3791
3447
|
gl;
|
|
3792
3448
|
aPositionLoc;
|
|
3793
3449
|
map = /* @__PURE__ */ new WeakMap();
|
|
3450
|
+
/** Meshes this context has drawn at least once; see `uploadRecurring`. */
|
|
3451
|
+
seen = /* @__PURE__ */ new WeakSet();
|
|
3794
3452
|
finalizer;
|
|
3795
3453
|
pendingDeletes = [];
|
|
3796
3454
|
/** Transient resources allocated this frame; freed at end of render(). */
|
|
@@ -3815,6 +3473,19 @@ var GLMeshCache = class {
|
|
|
3815
3473
|
this.transientThisFrame.push({ vao: handle.vao, vbo, ibo });
|
|
3816
3474
|
return handle;
|
|
3817
3475
|
}
|
|
3476
|
+
/**
|
|
3477
|
+
* Upload a Mesh that may or may not recur across frames. Its first sight in
|
|
3478
|
+
* *this* context takes `uploadTransient`; every later one takes the
|
|
3479
|
+
* persistent handle. One transient upload to find out is cheaper than
|
|
3480
|
+
* stranding a persistent VAO on a mesh that never returns, whose release
|
|
3481
|
+
* would wait on GC. The transient upload does not populate the persistent
|
|
3482
|
+
* map, so steady-state reuse begins on the third frame.
|
|
3483
|
+
*/
|
|
3484
|
+
uploadRecurring(mesh) {
|
|
3485
|
+
if (this.seen.has(mesh)) return this.handleFor(mesh);
|
|
3486
|
+
this.seen.add(mesh);
|
|
3487
|
+
return this.uploadTransient(mesh);
|
|
3488
|
+
}
|
|
3818
3489
|
/**
|
|
3819
3490
|
* Free all transient resources allocated since the last call. Called by
|
|
3820
3491
|
* the renderer at the end of each `render()`. Safe under context loss.
|
|
@@ -4881,619 +4552,19 @@ function getMesh(path) {
|
|
|
4881
4552
|
cache.set(path, mesh);
|
|
4882
4553
|
return mesh;
|
|
4883
4554
|
}
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4555
|
+
var UNDERLINE_OFFSET = 0.1;
|
|
4556
|
+
var STRIKETHROUGH_OFFSET = -0.3;
|
|
4557
|
+
var DECORATION_THICKNESS = 0.05;
|
|
4558
|
+
function fillKey(p) {
|
|
4559
|
+
if ("color" in p) return `s:${p.color}:${p.opacity ?? 1}`;
|
|
4560
|
+
return `nx:${Math.random()}`;
|
|
4887
4561
|
}
|
|
4888
|
-
function
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
anchorB: new Uint32Array([0, 1, 2, 3]),
|
|
4895
|
-
anchorT: new Float32Array([0, 0, 0, 0])
|
|
4896
|
-
};
|
|
4897
|
-
}
|
|
4898
|
-
function extractPolygon(p, opts) {
|
|
4899
|
-
const tolerance = opts.flattenTolerance ?? DEFAULT_FLATTEN_TOLERANCE;
|
|
4900
|
-
const { commands, coords } = p;
|
|
4901
|
-
const out = [];
|
|
4902
|
-
let anchorCounter = 0;
|
|
4903
|
-
let pts = null;
|
|
4904
|
-
let aA = null;
|
|
4905
|
-
let aB = null;
|
|
4906
|
-
let aT = null;
|
|
4907
|
-
let current = null;
|
|
4908
|
-
let coordIdx = 0;
|
|
4909
|
-
let prevX = 0;
|
|
4910
|
-
let prevY = 0;
|
|
4911
|
-
let prevAnchor = -1;
|
|
4912
|
-
const beginContour = () => {
|
|
4913
|
-
pts = [];
|
|
4914
|
-
aA = [];
|
|
4915
|
-
aB = [];
|
|
4916
|
-
aT = [];
|
|
4917
|
-
const next = { points: pts, closed: false };
|
|
4918
|
-
out.push(next);
|
|
4919
|
-
return next;
|
|
4920
|
-
};
|
|
4921
|
-
const dropDuplicateClosingPoint = () => {
|
|
4922
|
-
if (!pts || !aA || !aB || !aT) return;
|
|
4923
|
-
const n = pts.length / 2;
|
|
4924
|
-
if (n < 2) return;
|
|
4925
|
-
if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;
|
|
4926
|
-
pts.length -= 2;
|
|
4927
|
-
aA.length -= 1;
|
|
4928
|
-
aB.length -= 1;
|
|
4929
|
-
aT.length -= 1;
|
|
4930
|
-
};
|
|
4931
|
-
const commit = (target) => {
|
|
4932
|
-
if (!pts || !aA || !aB || !aT) return;
|
|
4933
|
-
target.anchorA = new Uint32Array(aA);
|
|
4934
|
-
target.anchorB = new Uint32Array(aB);
|
|
4935
|
-
target.anchorT = new Float32Array(aT);
|
|
4936
|
-
};
|
|
4937
|
-
for (let cmdIdx = 0; cmdIdx < commands.length; cmdIdx++) {
|
|
4938
|
-
const cmd = commands[cmdIdx];
|
|
4939
|
-
switch (cmd) {
|
|
4940
|
-
case PATH_M2: {
|
|
4941
|
-
if (current) commit(current);
|
|
4942
|
-
current = beginContour();
|
|
4943
|
-
prevX = coords[coordIdx];
|
|
4944
|
-
prevY = coords[coordIdx + 1];
|
|
4945
|
-
pts.push(prevX, prevY);
|
|
4946
|
-
aA.push(anchorCounter);
|
|
4947
|
-
aB.push(anchorCounter);
|
|
4948
|
-
aT.push(0);
|
|
4949
|
-
prevAnchor = anchorCounter;
|
|
4950
|
-
anchorCounter++;
|
|
4951
|
-
coordIdx += 2;
|
|
4952
|
-
break;
|
|
4953
|
-
}
|
|
4954
|
-
case PATH_L2: {
|
|
4955
|
-
prevX = coords[coordIdx];
|
|
4956
|
-
prevY = coords[coordIdx + 1];
|
|
4957
|
-
pts.push(prevX, prevY);
|
|
4958
|
-
aA.push(anchorCounter);
|
|
4959
|
-
aB.push(anchorCounter);
|
|
4960
|
-
aT.push(0);
|
|
4961
|
-
prevAnchor = anchorCounter;
|
|
4962
|
-
anchorCounter++;
|
|
4963
|
-
coordIdx += 2;
|
|
4964
|
-
break;
|
|
4965
|
-
}
|
|
4966
|
-
case PATH_Q2: {
|
|
4967
|
-
const cx = coords[coordIdx], cy = coords[coordIdx + 1];
|
|
4968
|
-
const ex = coords[coordIdx + 2], ey = coords[coordIdx + 3];
|
|
4969
|
-
const targetAnchor = anchorCounter;
|
|
4970
|
-
const segStart = pts.length / 2;
|
|
4971
|
-
const arcAccum = [];
|
|
4972
|
-
const total = flattenQuadraticWithArcLen(prevX, prevY, cx, cy, ex, ey, tolerance, pts, arcAccum);
|
|
4973
|
-
for (let k = 0; k < arcAccum.length; k++) {
|
|
4974
|
-
aA.push(prevAnchor);
|
|
4975
|
-
aB.push(targetAnchor);
|
|
4976
|
-
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
4977
|
-
}
|
|
4978
|
-
const lastIdx = segStart + arcAccum.length - 1;
|
|
4979
|
-
aA[lastIdx] = targetAnchor;
|
|
4980
|
-
aB[lastIdx] = targetAnchor;
|
|
4981
|
-
aT[lastIdx] = 0;
|
|
4982
|
-
prevX = ex;
|
|
4983
|
-
prevY = ey;
|
|
4984
|
-
prevAnchor = targetAnchor;
|
|
4985
|
-
anchorCounter++;
|
|
4986
|
-
coordIdx += 4;
|
|
4987
|
-
break;
|
|
4988
|
-
}
|
|
4989
|
-
case PATH_C2: {
|
|
4990
|
-
const c1x = coords[coordIdx], c1y = coords[coordIdx + 1];
|
|
4991
|
-
const c2x = coords[coordIdx + 2], c2y = coords[coordIdx + 3];
|
|
4992
|
-
const ex = coords[coordIdx + 4], ey = coords[coordIdx + 5];
|
|
4993
|
-
const targetAnchor = anchorCounter;
|
|
4994
|
-
const segStart = pts.length / 2;
|
|
4995
|
-
const arcAccum = [];
|
|
4996
|
-
const total = flattenCubicWithArcLen(prevX, prevY, c1x, c1y, c2x, c2y, ex, ey, tolerance, pts, arcAccum);
|
|
4997
|
-
for (let k = 0; k < arcAccum.length; k++) {
|
|
4998
|
-
aA.push(prevAnchor);
|
|
4999
|
-
aB.push(targetAnchor);
|
|
5000
|
-
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
5001
|
-
}
|
|
5002
|
-
const lastIdx = segStart + arcAccum.length - 1;
|
|
5003
|
-
aA[lastIdx] = targetAnchor;
|
|
5004
|
-
aB[lastIdx] = targetAnchor;
|
|
5005
|
-
aT[lastIdx] = 0;
|
|
5006
|
-
prevX = ex;
|
|
5007
|
-
prevY = ey;
|
|
5008
|
-
prevAnchor = targetAnchor;
|
|
5009
|
-
anchorCounter++;
|
|
5010
|
-
coordIdx += 6;
|
|
5011
|
-
break;
|
|
5012
|
-
}
|
|
5013
|
-
case PATH_Z2: {
|
|
5014
|
-
if (current) {
|
|
5015
|
-
current.closed = true;
|
|
5016
|
-
dropDuplicateClosingPoint();
|
|
5017
|
-
}
|
|
5018
|
-
break;
|
|
5019
|
-
}
|
|
5020
|
-
default:
|
|
5021
|
-
throw new Error(`extractPolylines: unknown command code ${cmd}`);
|
|
5022
|
-
}
|
|
5023
|
-
}
|
|
5024
|
-
if (current) commit(current);
|
|
5025
|
-
return out;
|
|
5026
|
-
}
|
|
5027
|
-
var EMPTY_MESH = {
|
|
5028
|
-
vertices: new Float32Array(0),
|
|
5029
|
-
indices: new Uint32Array(0),
|
|
5030
|
-
anchorA: new Uint32Array(0),
|
|
5031
|
-
anchorB: new Uint32Array(0),
|
|
5032
|
-
anchorT: new Float32Array(0)
|
|
5033
|
-
};
|
|
5034
|
-
function tessellateStroke(path, stroke, opts = {}) {
|
|
5035
|
-
const width = stroke.width ?? 1;
|
|
5036
|
-
if (width <= 0) return EMPTY_MESH;
|
|
5037
|
-
const join = stroke.join ?? "miter";
|
|
5038
|
-
const cap = stroke.cap ?? "butt";
|
|
5039
|
-
const align = stroke.align ?? "center";
|
|
5040
|
-
const miterLimit = stroke.miterLimit ?? DEFAULT_MITER_LIMIT;
|
|
5041
|
-
const varyingThreshold = stroke.varyingWidthJoinThreshold ?? DEFAULT_VARYING_WIDTH_JOIN_THRESHOLD;
|
|
5042
|
-
let workingPath = path;
|
|
5043
|
-
if (path.kind === "rect" && align !== "center") {
|
|
5044
|
-
const aligned = alignedStrokeRect(path, align, width);
|
|
5045
|
-
workingPath = {
|
|
5046
|
-
kind: "rect",
|
|
5047
|
-
x: aligned.x,
|
|
5048
|
-
y: aligned.y,
|
|
5049
|
-
width: aligned.width,
|
|
5050
|
-
height: aligned.height
|
|
5051
|
-
};
|
|
5052
|
-
}
|
|
5053
|
-
const polylines = extractPolylines(workingPath, opts);
|
|
5054
|
-
if (stroke.vertexWidths && stroke.vertexWidths.length > 0) {
|
|
5055
|
-
for (const pl of polylines) populatePolylineWidths(pl, stroke.vertexWidths, width);
|
|
5056
|
-
}
|
|
5057
|
-
const dash = stroke.dash ?? [];
|
|
5058
|
-
const verts = [];
|
|
5059
|
-
const idx = [];
|
|
5060
|
-
const anchorA = [];
|
|
5061
|
-
const anchorB = [];
|
|
5062
|
-
const anchorT = [];
|
|
5063
|
-
for (const pl of polylines) {
|
|
5064
|
-
const subs = dash.length > 0 ? splitForDash(pl, dash) : [pl];
|
|
5065
|
-
for (const sub2 of subs) {
|
|
5066
|
-
expandPolyline(sub2, width, join, cap, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT);
|
|
5067
|
-
}
|
|
5068
|
-
}
|
|
5069
|
-
return {
|
|
5070
|
-
vertices: new Float32Array(verts),
|
|
5071
|
-
indices: new Uint32Array(idx),
|
|
5072
|
-
anchorA: new Uint32Array(anchorA),
|
|
5073
|
-
anchorB: new Uint32Array(anchorB),
|
|
5074
|
-
anchorT: new Float32Array(anchorT)
|
|
5075
|
-
};
|
|
5076
|
-
}
|
|
5077
|
-
function expandPolyline(pl, width, join, cap, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT) {
|
|
5078
|
-
const half = width / 2;
|
|
5079
|
-
const pts = pl.points;
|
|
5080
|
-
const ptCount = pts.length / 2;
|
|
5081
|
-
const segCount = ptCount - 1;
|
|
5082
|
-
if (segCount < 1) return;
|
|
5083
|
-
const plA = pl.anchorA ?? new Uint32Array(ptCount);
|
|
5084
|
-
const plB = pl.anchorB ?? new Uint32Array(ptCount);
|
|
5085
|
-
const plT = pl.anchorT ?? new Float32Array(ptCount);
|
|
5086
|
-
const plHalf = pl.widths ? pl.widths.map((w) => w / 2) : null;
|
|
5087
|
-
const segs = [];
|
|
5088
|
-
const segSrcIdx = [];
|
|
5089
|
-
for (let s = 0; s < segCount; s++) {
|
|
5090
|
-
const ha = plHalf ? plHalf[s] : half;
|
|
5091
|
-
const hb = plHalf ? plHalf[s + 1] : half;
|
|
5092
|
-
const seg = makeSeg(pts[s * 2], pts[s * 2 + 1], pts[(s + 1) * 2], pts[(s + 1) * 2 + 1], ha, hb);
|
|
5093
|
-
if (seg) {
|
|
5094
|
-
segs.push(seg);
|
|
5095
|
-
segSrcIdx.push(s);
|
|
5096
|
-
}
|
|
5097
|
-
}
|
|
5098
|
-
let closerSrcIdx = -1;
|
|
5099
|
-
if (pl.closed && segs.length >= 1) {
|
|
5100
|
-
const last = segs[segs.length - 1];
|
|
5101
|
-
const first = segs[0];
|
|
5102
|
-
const haCloser = plHalf ? plHalf[ptCount - 1] : half;
|
|
5103
|
-
const hbCloser = plHalf ? plHalf[0] : half;
|
|
5104
|
-
const closer = makeSeg(last.bx, last.by, first.ax, first.ay, haCloser, hbCloser);
|
|
5105
|
-
if (closer) {
|
|
5106
|
-
segs.push(closer);
|
|
5107
|
-
closerSrcIdx = ptCount - 1;
|
|
5108
|
-
segSrcIdx.push(closerSrcIdx);
|
|
5109
|
-
}
|
|
5110
|
-
}
|
|
5111
|
-
if (segs.length === 0) return;
|
|
5112
|
-
const segBaseIdx = [];
|
|
5113
|
-
for (let s = 0; s < segs.length; s++) {
|
|
5114
|
-
const seg = segs[s];
|
|
5115
|
-
const startSrc = segSrcIdx[s];
|
|
5116
|
-
const endSrc = s === segs.length - 1 && pl.closed && closerSrcIdx >= 0 ? 0 : startSrc + 1;
|
|
5117
|
-
const base = verts.length / 2;
|
|
5118
|
-
segBaseIdx.push(base);
|
|
5119
|
-
const nxA = seg.nxUnit * seg.halfA, nyA = seg.nyUnit * seg.halfA;
|
|
5120
|
-
const nxB = seg.nxUnit * seg.halfB, nyB = seg.nyUnit * seg.halfB;
|
|
5121
|
-
verts.push(seg.ax + nxA, seg.ay + nyA);
|
|
5122
|
-
anchorA.push(plA[startSrc]);
|
|
5123
|
-
anchorB.push(plB[startSrc]);
|
|
5124
|
-
anchorT.push(plT[startSrc]);
|
|
5125
|
-
verts.push(seg.ax - nxA, seg.ay - nyA);
|
|
5126
|
-
anchorA.push(plA[startSrc]);
|
|
5127
|
-
anchorB.push(plB[startSrc]);
|
|
5128
|
-
anchorT.push(plT[startSrc]);
|
|
5129
|
-
verts.push(seg.bx + nxB, seg.by + nyB);
|
|
5130
|
-
anchorA.push(plA[endSrc]);
|
|
5131
|
-
anchorB.push(plB[endSrc]);
|
|
5132
|
-
anchorT.push(plT[endSrc]);
|
|
5133
|
-
verts.push(seg.bx - nxB, seg.by - nyB);
|
|
5134
|
-
anchorA.push(plA[endSrc]);
|
|
5135
|
-
anchorB.push(plB[endSrc]);
|
|
5136
|
-
anchorT.push(plT[endSrc]);
|
|
5137
|
-
idx.push(base, base + 1, base + 2, base + 1, base + 3, base + 2);
|
|
5138
|
-
}
|
|
5139
|
-
const joinCount = pl.closed ? segs.length : segs.length - 1;
|
|
5140
|
-
for (let j = 0; j < joinCount; j++) {
|
|
5141
|
-
emitJoin(segs, segBaseIdx, j, join, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT, segSrcIdx, plA, plB, plT);
|
|
5142
|
-
}
|
|
5143
|
-
if (!pl.closed && cap !== "butt") {
|
|
5144
|
-
const first = segs[0];
|
|
5145
|
-
const firstBase = segBaseIdx[0];
|
|
5146
|
-
emitCap(first, firstBase + 0, firstBase + 1, false, first.halfA, cap, verts, idx, anchorA, anchorB, anchorT, plA[0], plB[0], plT[0]);
|
|
5147
|
-
const last = segs[segs.length - 1];
|
|
5148
|
-
const lastBase = segBaseIdx[segs.length - 1];
|
|
5149
|
-
const lastSrc = segSrcIdx[segs.length - 1] + 1;
|
|
5150
|
-
emitCap(last, lastBase + 2, lastBase + 3, true, last.halfB, cap, verts, idx, anchorA, anchorB, anchorT, plA[lastSrc], plB[lastSrc], plT[lastSrc]);
|
|
5151
|
-
}
|
|
5152
|
-
}
|
|
5153
|
-
function populatePolylineWidths(pl, vertexWidths, fallbackWidth) {
|
|
5154
|
-
const ptCount = pl.points.length / 2;
|
|
5155
|
-
if (ptCount === 0) return;
|
|
5156
|
-
const aA = pl.anchorA ?? new Uint32Array(ptCount);
|
|
5157
|
-
const aB = pl.anchorB ?? new Uint32Array(ptCount);
|
|
5158
|
-
const aT = pl.anchorT ?? new Float32Array(ptCount);
|
|
5159
|
-
const widths = new Float32Array(ptCount);
|
|
5160
|
-
const read2 = (i) => {
|
|
5161
|
-
const v = vertexWidths[i];
|
|
5162
|
-
return typeof v === "number" && isFinite(v) && v > 0 ? v : fallbackWidth;
|
|
5163
|
-
};
|
|
5164
|
-
for (let i = 0; i < ptCount; i++) {
|
|
5165
|
-
const a = aA[i], b = aB[i], t = aT[i];
|
|
5166
|
-
if (a === b) {
|
|
5167
|
-
widths[i] = read2(a);
|
|
5168
|
-
} else {
|
|
5169
|
-
const wa = read2(a);
|
|
5170
|
-
const wb = read2(b);
|
|
5171
|
-
widths[i] = wa + (wb - wa) * t;
|
|
5172
|
-
}
|
|
5173
|
-
}
|
|
5174
|
-
pl.widths = widths;
|
|
5175
|
-
}
|
|
5176
|
-
var ROUND_CAP_STEP_RAD = 10 * Math.PI / 180;
|
|
5177
|
-
function emitCap(seg, leftIdx, rightIdx, atEnd, half, cap, verts, idx, anchorA, anchorB, anchorT, endA, endB, endT) {
|
|
5178
|
-
const sign2 = atEnd ? 1 : -1;
|
|
5179
|
-
const dx = (seg.bx - seg.ax) / seg.len * sign2;
|
|
5180
|
-
const dy = (seg.by - seg.ay) / seg.len * sign2;
|
|
5181
|
-
const cx = atEnd ? seg.bx : seg.ax;
|
|
5182
|
-
const cy = atEnd ? seg.by : seg.ay;
|
|
5183
|
-
const nx = seg.nxUnit * half;
|
|
5184
|
-
const ny = seg.nyUnit * half;
|
|
5185
|
-
if (cap === "square") {
|
|
5186
|
-
const ox = cx + dx * half;
|
|
5187
|
-
const oy = cy + dy * half;
|
|
5188
|
-
const lOut = verts.length / 2;
|
|
5189
|
-
verts.push(ox + nx, oy + ny);
|
|
5190
|
-
anchorA.push(endA);
|
|
5191
|
-
anchorB.push(endB);
|
|
5192
|
-
anchorT.push(endT);
|
|
5193
|
-
const rOut = verts.length / 2;
|
|
5194
|
-
verts.push(ox - nx, oy - ny);
|
|
5195
|
-
anchorA.push(endA);
|
|
5196
|
-
anchorB.push(endB);
|
|
5197
|
-
anchorT.push(endT);
|
|
5198
|
-
if (atEnd) {
|
|
5199
|
-
idx.push(leftIdx, lOut, rOut, leftIdx, rOut, rightIdx);
|
|
5200
|
-
} else {
|
|
5201
|
-
idx.push(leftIdx, rOut, lOut, leftIdx, rightIdx, rOut);
|
|
5202
|
-
}
|
|
5203
|
-
return;
|
|
5204
|
-
}
|
|
5205
|
-
if (cap === "round") {
|
|
5206
|
-
const pivotIdx = verts.length / 2;
|
|
5207
|
-
verts.push(cx, cy);
|
|
5208
|
-
anchorA.push(endA);
|
|
5209
|
-
anchorB.push(endB);
|
|
5210
|
-
anchorT.push(endT);
|
|
5211
|
-
const startAngle = Math.atan2(ny, nx);
|
|
5212
|
-
const sweep = atEnd ? -Math.PI : Math.PI;
|
|
5213
|
-
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_CAP_STEP_RAD));
|
|
5214
|
-
const stepAngle = sweep / steps;
|
|
5215
|
-
let prevIdx = leftIdx;
|
|
5216
|
-
for (let i = 1; i < steps; i++) {
|
|
5217
|
-
const ang = startAngle + i * stepAngle;
|
|
5218
|
-
const fx = cx + Math.cos(ang) * half;
|
|
5219
|
-
const fy = cy + Math.sin(ang) * half;
|
|
5220
|
-
const newIdx = verts.length / 2;
|
|
5221
|
-
verts.push(fx, fy);
|
|
5222
|
-
anchorA.push(endA);
|
|
5223
|
-
anchorB.push(endB);
|
|
5224
|
-
anchorT.push(endT);
|
|
5225
|
-
if (atEnd) idx.push(prevIdx, newIdx, pivotIdx);
|
|
5226
|
-
else idx.push(prevIdx, pivotIdx, newIdx);
|
|
5227
|
-
prevIdx = newIdx;
|
|
5228
|
-
}
|
|
5229
|
-
if (atEnd) idx.push(prevIdx, rightIdx, pivotIdx);
|
|
5230
|
-
else idx.push(prevIdx, pivotIdx, rightIdx);
|
|
5231
|
-
}
|
|
5232
|
-
}
|
|
5233
|
-
function splitForDash(pl, dash) {
|
|
5234
|
-
const out = [];
|
|
5235
|
-
const plA = pl.anchorA ?? new Uint32Array(pl.points.length / 2);
|
|
5236
|
-
const plB = pl.anchorB ?? new Uint32Array(pl.points.length / 2);
|
|
5237
|
-
const plT = pl.anchorT ?? new Float32Array(pl.points.length / 2);
|
|
5238
|
-
let dashIdx = 0;
|
|
5239
|
-
let dashRemaining = dash[0];
|
|
5240
|
-
let onPhase = true;
|
|
5241
|
-
let curPts = onPhase ? [pl.points[0], pl.points[1]] : null;
|
|
5242
|
-
let curA = onPhase ? [plA[0]] : null;
|
|
5243
|
-
let curB = onPhase ? [plB[0]] : null;
|
|
5244
|
-
let curT = onPhase ? [plT[0]] : null;
|
|
5245
|
-
const flushAndAdvance = () => {
|
|
5246
|
-
if (curPts && curPts.length >= 4) {
|
|
5247
|
-
out.push({
|
|
5248
|
-
points: curPts,
|
|
5249
|
-
closed: false,
|
|
5250
|
-
anchorA: new Uint32Array(curA),
|
|
5251
|
-
anchorB: new Uint32Array(curB),
|
|
5252
|
-
anchorT: new Float32Array(curT)
|
|
5253
|
-
});
|
|
5254
|
-
}
|
|
5255
|
-
curPts = null;
|
|
5256
|
-
curA = null;
|
|
5257
|
-
curB = null;
|
|
5258
|
-
curT = null;
|
|
5259
|
-
dashIdx = (dashIdx + 1) % dash.length;
|
|
5260
|
-
dashRemaining = dash[dashIdx];
|
|
5261
|
-
onPhase = !onPhase;
|
|
5262
|
-
};
|
|
5263
|
-
let prevX = pl.points[0], prevY = pl.points[1];
|
|
5264
|
-
const ptCount = pl.points.length / 2;
|
|
5265
|
-
const segCount = pl.closed ? ptCount : ptCount - 1;
|
|
5266
|
-
for (let i = 0; i < segCount; i++) {
|
|
5267
|
-
const nextIdx = (i + 1) % ptCount;
|
|
5268
|
-
const cx = pl.points[nextIdx * 2], cy = pl.points[nextIdx * 2 + 1];
|
|
5269
|
-
const startA = plA[i], startB = plB[i], startT = plT[i];
|
|
5270
|
-
const endA = plA[nextIdx], endB = plB[nextIdx], endT = plT[nextIdx];
|
|
5271
|
-
const segFullDx = cx - prevX, segFullDy = cy - prevY;
|
|
5272
|
-
const segFullLen = Math.hypot(segFullDx, segFullDy);
|
|
5273
|
-
let segDx = segFullDx, segDy = segFullDy;
|
|
5274
|
-
let segLen = segFullLen;
|
|
5275
|
-
let traveled = 0;
|
|
5276
|
-
while (segLen > 1e-9) {
|
|
5277
|
-
if (segLen <= dashRemaining) {
|
|
5278
|
-
if (onPhase && curPts) {
|
|
5279
|
-
curPts.push(cx, cy);
|
|
5280
|
-
curA.push(endA);
|
|
5281
|
-
curB.push(endB);
|
|
5282
|
-
curT.push(endT);
|
|
5283
|
-
}
|
|
5284
|
-
dashRemaining -= segLen;
|
|
5285
|
-
prevX = cx;
|
|
5286
|
-
prevY = cy;
|
|
5287
|
-
traveled = segFullLen;
|
|
5288
|
-
segLen = 0;
|
|
5289
|
-
if (dashRemaining <= 1e-9) {
|
|
5290
|
-
flushAndAdvance();
|
|
5291
|
-
if (onPhase) {
|
|
5292
|
-
curPts = [prevX, prevY];
|
|
5293
|
-
curA = [endA];
|
|
5294
|
-
curB = [endB];
|
|
5295
|
-
curT = [endT];
|
|
5296
|
-
}
|
|
5297
|
-
}
|
|
5298
|
-
} else {
|
|
5299
|
-
const tConsume = dashRemaining / segLen;
|
|
5300
|
-
const ix = prevX + segDx * tConsume;
|
|
5301
|
-
const iy = prevY + segDy * tConsume;
|
|
5302
|
-
traveled += dashRemaining;
|
|
5303
|
-
const frac = traveled / segFullLen;
|
|
5304
|
-
let mA, mB, mT;
|
|
5305
|
-
if (startA === endA && startB === endB) {
|
|
5306
|
-
mA = startA;
|
|
5307
|
-
mB = startB;
|
|
5308
|
-
mT = startT + (endT - startT) * frac;
|
|
5309
|
-
} else {
|
|
5310
|
-
if (frac < 0.5) {
|
|
5311
|
-
mA = startA;
|
|
5312
|
-
mB = startB;
|
|
5313
|
-
mT = startT;
|
|
5314
|
-
} else {
|
|
5315
|
-
mA = endA;
|
|
5316
|
-
mB = endB;
|
|
5317
|
-
mT = endT;
|
|
5318
|
-
}
|
|
5319
|
-
}
|
|
5320
|
-
if (onPhase && curPts) {
|
|
5321
|
-
curPts.push(ix, iy);
|
|
5322
|
-
curA.push(mA);
|
|
5323
|
-
curB.push(mB);
|
|
5324
|
-
curT.push(mT);
|
|
5325
|
-
}
|
|
5326
|
-
prevX = ix;
|
|
5327
|
-
prevY = iy;
|
|
5328
|
-
segDx = cx - prevX;
|
|
5329
|
-
segDy = cy - prevY;
|
|
5330
|
-
segLen = Math.hypot(segDx, segDy);
|
|
5331
|
-
flushAndAdvance();
|
|
5332
|
-
if (onPhase) {
|
|
5333
|
-
curPts = [prevX, prevY];
|
|
5334
|
-
curA = [mA];
|
|
5335
|
-
curB = [mB];
|
|
5336
|
-
curT = [mT];
|
|
5337
|
-
}
|
|
5338
|
-
}
|
|
5339
|
-
}
|
|
5340
|
-
}
|
|
5341
|
-
if (curPts && curPts.length >= 4) {
|
|
5342
|
-
out.push({
|
|
5343
|
-
points: curPts,
|
|
5344
|
-
closed: false,
|
|
5345
|
-
anchorA: new Uint32Array(curA),
|
|
5346
|
-
anchorB: new Uint32Array(curB),
|
|
5347
|
-
anchorT: new Float32Array(curT)
|
|
5348
|
-
});
|
|
5349
|
-
}
|
|
5350
|
-
return out;
|
|
5351
|
-
}
|
|
5352
|
-
function makeSeg(ax, ay, bx, by, halfA, halfB) {
|
|
5353
|
-
const dx = bx - ax, dy = by - ay;
|
|
5354
|
-
const len = Math.hypot(dx, dy);
|
|
5355
|
-
if (len === 0) return null;
|
|
5356
|
-
return {
|
|
5357
|
-
ax,
|
|
5358
|
-
ay,
|
|
5359
|
-
bx,
|
|
5360
|
-
by,
|
|
5361
|
-
nxUnit: -dy / len,
|
|
5362
|
-
nyUnit: dx / len,
|
|
5363
|
-
halfA,
|
|
5364
|
-
halfB,
|
|
5365
|
-
len
|
|
5366
|
-
};
|
|
5367
|
-
}
|
|
5368
|
-
var DEFAULT_MITER_LIMIT = 10;
|
|
5369
|
-
var DEFAULT_VARYING_WIDTH_JOIN_THRESHOLD = 1.5;
|
|
5370
|
-
function emitJoin(segs, segBaseIdx, j, join, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT, segSrcIdx, plA, plB, plT) {
|
|
5371
|
-
const a = segs[j];
|
|
5372
|
-
const b = segs[(j + 1) % segs.length];
|
|
5373
|
-
const aBase = segBaseIdx[j];
|
|
5374
|
-
const bBase = segBaseIdx[(j + 1) % segs.length];
|
|
5375
|
-
const adx = a.bx - a.ax, ady = a.by - a.ay;
|
|
5376
|
-
const bdx = b.bx - b.ax, bdy = b.by - b.ay;
|
|
5377
|
-
const cross = adx * bdy - ady * bdx;
|
|
5378
|
-
if (cross === 0) return;
|
|
5379
|
-
const onPositive = cross > 0;
|
|
5380
|
-
const aOuterEnd = onPositive ? aBase + 3 : aBase + 2;
|
|
5381
|
-
const bOuterStart = onPositive ? bBase + 1 : bBase + 0;
|
|
5382
|
-
const nextSeg = (j + 1) % segs.length;
|
|
5383
|
-
const cornerSrc = segSrcIdx[nextSeg];
|
|
5384
|
-
const cornerA = plA[cornerSrc];
|
|
5385
|
-
const cornerB = plB[cornerSrc];
|
|
5386
|
-
const cornerT = plT[cornerSrc];
|
|
5387
|
-
const halfAtCorner = a.halfB;
|
|
5388
|
-
const taperA = Math.max(a.halfA, a.halfB) / Math.max(1e-9, Math.min(a.halfA, a.halfB));
|
|
5389
|
-
const taperB = Math.max(b.halfA, b.halfB) / Math.max(1e-9, Math.min(b.halfA, b.halfB));
|
|
5390
|
-
const forceBevelForVarying = taperA > varyingThreshold || taperB > varyingThreshold;
|
|
5391
|
-
if (join === "bevel" || forceBevelForVarying) {
|
|
5392
|
-
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
5393
|
-
return;
|
|
5394
|
-
}
|
|
5395
|
-
if (join === "miter") {
|
|
5396
|
-
const aOX = verts[aOuterEnd * 2], aOY = verts[aOuterEnd * 2 + 1];
|
|
5397
|
-
const bOX = verts[bOuterStart * 2], bOY = verts[bOuterStart * 2 + 1];
|
|
5398
|
-
const apex = lineLineIntersect(aOX, aOY, adx, ady, bOX, bOY, -bdx, -bdy);
|
|
5399
|
-
if (!apex) {
|
|
5400
|
-
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
5401
|
-
return;
|
|
5402
|
-
}
|
|
5403
|
-
const miterLen = Math.hypot(apex[0] - a.bx, apex[1] - a.by);
|
|
5404
|
-
if (miterLen > miterLimit * halfAtCorner) {
|
|
5405
|
-
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
5406
|
-
return;
|
|
5407
|
-
}
|
|
5408
|
-
const apexIdx = verts.length / 2;
|
|
5409
|
-
verts.push(apex[0], apex[1]);
|
|
5410
|
-
anchorA.push(cornerA);
|
|
5411
|
-
anchorB.push(cornerB);
|
|
5412
|
-
anchorT.push(cornerT);
|
|
5413
|
-
const jIdx = verts.length / 2;
|
|
5414
|
-
verts.push(a.bx, a.by);
|
|
5415
|
-
anchorA.push(cornerA);
|
|
5416
|
-
anchorB.push(cornerB);
|
|
5417
|
-
anchorT.push(cornerT);
|
|
5418
|
-
if (onPositive) {
|
|
5419
|
-
idx.push(aOuterEnd, apexIdx, bOuterStart);
|
|
5420
|
-
idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
5421
|
-
} else {
|
|
5422
|
-
idx.push(aOuterEnd, bOuterStart, apexIdx);
|
|
5423
|
-
idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
5424
|
-
}
|
|
5425
|
-
return;
|
|
5426
|
-
}
|
|
5427
|
-
if (join === "round") {
|
|
5428
|
-
emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
5429
|
-
return;
|
|
5430
|
-
}
|
|
5431
|
-
}
|
|
5432
|
-
var ROUND_STEP_RAD = 10 * Math.PI / 180;
|
|
5433
|
-
function emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
5434
|
-
const cx = a.bx, cy = a.by;
|
|
5435
|
-
const pivotIdx = verts.length / 2;
|
|
5436
|
-
verts.push(cx, cy);
|
|
5437
|
-
anchorA.push(cornerA);
|
|
5438
|
-
anchorB.push(cornerB);
|
|
5439
|
-
anchorT.push(cornerT);
|
|
5440
|
-
const startX = verts[aOuterEnd * 2] - cx;
|
|
5441
|
-
const startY = verts[aOuterEnd * 2 + 1] - cy;
|
|
5442
|
-
const endX = verts[bOuterStart * 2] - cx;
|
|
5443
|
-
const endY = verts[bOuterStart * 2 + 1] - cy;
|
|
5444
|
-
const r = Math.hypot(startX, startY);
|
|
5445
|
-
const startAngle = Math.atan2(startY, startX);
|
|
5446
|
-
const endAngle = Math.atan2(endY, endX);
|
|
5447
|
-
let sweep = endAngle - startAngle;
|
|
5448
|
-
if (onPositive && sweep < 0) sweep += 2 * Math.PI;
|
|
5449
|
-
else if (!onPositive && sweep > 0) sweep -= 2 * Math.PI;
|
|
5450
|
-
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_STEP_RAD));
|
|
5451
|
-
const stepAngle = sweep / steps;
|
|
5452
|
-
let prevIdx = aOuterEnd;
|
|
5453
|
-
for (let i = 1; i < steps; i++) {
|
|
5454
|
-
const ang = startAngle + i * stepAngle;
|
|
5455
|
-
const fx = cx + Math.cos(ang) * r;
|
|
5456
|
-
const fy = cy + Math.sin(ang) * r;
|
|
5457
|
-
const newIdx = verts.length / 2;
|
|
5458
|
-
verts.push(fx, fy);
|
|
5459
|
-
anchorA.push(cornerA);
|
|
5460
|
-
anchorB.push(cornerB);
|
|
5461
|
-
anchorT.push(cornerT);
|
|
5462
|
-
if (onPositive) idx.push(prevIdx, pivotIdx, newIdx);
|
|
5463
|
-
else idx.push(prevIdx, newIdx, pivotIdx);
|
|
5464
|
-
prevIdx = newIdx;
|
|
5465
|
-
}
|
|
5466
|
-
if (onPositive) idx.push(prevIdx, pivotIdx, bOuterStart);
|
|
5467
|
-
else idx.push(prevIdx, bOuterStart, pivotIdx);
|
|
5468
|
-
}
|
|
5469
|
-
function emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
5470
|
-
const jIdx = verts.length / 2;
|
|
5471
|
-
verts.push(a.bx, a.by);
|
|
5472
|
-
anchorA.push(cornerA);
|
|
5473
|
-
anchorB.push(cornerB);
|
|
5474
|
-
anchorT.push(cornerT);
|
|
5475
|
-
if (onPositive) idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
5476
|
-
else idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
5477
|
-
}
|
|
5478
|
-
function lineLineIntersect(apx, apy, adx, ady, bpx, bpy, bdx, bdy) {
|
|
5479
|
-
const denom = adx * bdy - ady * bdx;
|
|
5480
|
-
if (Math.abs(denom) < 1e-9) return null;
|
|
5481
|
-
const t = ((bpx - apx) * bdy - (bpy - apy) * bdx) / denom;
|
|
5482
|
-
return [apx + t * adx, apy + t * ady];
|
|
5483
|
-
}
|
|
5484
|
-
var UNDERLINE_OFFSET = 0.1;
|
|
5485
|
-
var STRIKETHROUGH_OFFSET = -0.3;
|
|
5486
|
-
var DECORATION_THICKNESS = 0.05;
|
|
5487
|
-
function fillKey(p) {
|
|
5488
|
-
if ("color" in p) return `s:${p.color}:${p.opacity ?? 1}`;
|
|
5489
|
-
return `nx:${Math.random()}`;
|
|
5490
|
-
}
|
|
5491
|
-
function sameFill(a, b) {
|
|
5492
|
-
if (a === b) return true;
|
|
5493
|
-
if ("color" in a && "color" in b) {
|
|
5494
|
-
return a.color === b.color && (a.opacity ?? 1) === (b.opacity ?? 1);
|
|
5495
|
-
}
|
|
5496
|
-
return false;
|
|
4562
|
+
function sameFill(a, b) {
|
|
4563
|
+
if (a === b) return true;
|
|
4564
|
+
if ("color" in a && "color" in b) {
|
|
4565
|
+
return a.color === b.color && (a.opacity ?? 1) === (b.opacity ?? 1);
|
|
4566
|
+
}
|
|
4567
|
+
return false;
|
|
5497
4568
|
}
|
|
5498
4569
|
function strokeKey(s) {
|
|
5499
4570
|
if (!s) return "-";
|
|
@@ -5643,496 +4714,1096 @@ function layoutRuns(runs, opts) {
|
|
|
5643
4714
|
prevFontSize = run.fontSize;
|
|
5644
4715
|
continue;
|
|
5645
4716
|
}
|
|
5646
|
-
const glyphFont = hit.font;
|
|
5647
|
-
const glyphScale = run.fontSize / glyphFont.info.size;
|
|
5648
|
-
let kerningBefore = 0;
|
|
5649
|
-
if (prevCp !== void 0 && prevFont !== void 0 && prevFontSize !== void 0) {
|
|
5650
|
-
const kAtlas = prevFont.kerningMap.get(prevCp)?.get(cp) ?? 0;
|
|
5651
|
-
kerningBefore = kAtlas * (prevFontSize / prevFont.info.size);
|
|
4717
|
+
const glyphFont = hit.font;
|
|
4718
|
+
const glyphScale = run.fontSize / glyphFont.info.size;
|
|
4719
|
+
let kerningBefore = 0;
|
|
4720
|
+
if (prevCp !== void 0 && prevFont !== void 0 && prevFontSize !== void 0) {
|
|
4721
|
+
const kAtlas = prevFont.kerningMap.get(prevCp)?.get(cp) ?? 0;
|
|
4722
|
+
kerningBefore = kAtlas * (prevFontSize / prevFont.info.size);
|
|
4723
|
+
}
|
|
4724
|
+
entries.push({
|
|
4725
|
+
run,
|
|
4726
|
+
font: glyphFont,
|
|
4727
|
+
glyph: hit.glyph,
|
|
4728
|
+
cp,
|
|
4729
|
+
advance: hit.glyph.xadvance * glyphScale,
|
|
4730
|
+
tracking,
|
|
4731
|
+
kerningBefore,
|
|
4732
|
+
isSpace,
|
|
4733
|
+
isNewline: false,
|
|
4734
|
+
resolved: hit.resolved,
|
|
4735
|
+
fontSize: run.fontSize
|
|
4736
|
+
});
|
|
4737
|
+
prevCp = cp;
|
|
4738
|
+
prevFont = glyphFont;
|
|
4739
|
+
prevFontSize = run.fontSize;
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
const lines = [];
|
|
4743
|
+
let cur = { entries: [], width: 0, height: 0 };
|
|
4744
|
+
function commitLine() {
|
|
4745
|
+
lines.push(cur);
|
|
4746
|
+
cur = { entries: [], width: 0, height: 0 };
|
|
4747
|
+
}
|
|
4748
|
+
let i = 0;
|
|
4749
|
+
while (i < entries.length) {
|
|
4750
|
+
const e = entries[i];
|
|
4751
|
+
if (e.isNewline) {
|
|
4752
|
+
if (cur.entries.length === 0) {
|
|
4753
|
+
cur.height = Math.max(cur.height, e.fontSize * opts.lineHeight);
|
|
4754
|
+
cur.blank = e;
|
|
4755
|
+
}
|
|
4756
|
+
commitLine();
|
|
4757
|
+
i++;
|
|
4758
|
+
continue;
|
|
4759
|
+
}
|
|
4760
|
+
if (e.isSpace) {
|
|
4761
|
+
if (cur.entries.length > 0) {
|
|
4762
|
+
cur.entries.push(e);
|
|
4763
|
+
cur.width += e.kerningBefore + e.advance + e.tracking;
|
|
4764
|
+
cur.height = Math.max(cur.height, e.fontSize * opts.lineHeight);
|
|
4765
|
+
}
|
|
4766
|
+
i++;
|
|
4767
|
+
continue;
|
|
4768
|
+
}
|
|
4769
|
+
let j = i;
|
|
4770
|
+
let wordWidth = 0;
|
|
4771
|
+
while (j < entries.length && !entries[j].isSpace && !entries[j].isNewline) {
|
|
4772
|
+
const w = entries[j];
|
|
4773
|
+
wordWidth += w.kerningBefore + w.advance + w.tracking;
|
|
4774
|
+
j++;
|
|
4775
|
+
}
|
|
4776
|
+
if (Number.isFinite(opts.maxWidth) && cur.width + wordWidth > opts.maxWidth && cur.entries.length > 0) {
|
|
4777
|
+
commitLine();
|
|
4778
|
+
}
|
|
4779
|
+
for (let k = i; k < j; k++) {
|
|
4780
|
+
const w = entries[k];
|
|
4781
|
+
const kerningBefore = cur.entries.length === 0 ? 0 : w.kerningBefore;
|
|
4782
|
+
cur.entries.push({ ...w, kerningBefore });
|
|
4783
|
+
cur.width += kerningBefore + w.advance + w.tracking;
|
|
4784
|
+
cur.height = Math.max(cur.height, w.fontSize * opts.lineHeight);
|
|
4785
|
+
}
|
|
4786
|
+
i = j;
|
|
4787
|
+
}
|
|
4788
|
+
if (cur.entries.length > 0) commitLine();
|
|
4789
|
+
function outlineFor(e) {
|
|
4790
|
+
const min = opts.outlineMinSize;
|
|
4791
|
+
if (min === void 0 || e.fontSize < min) return null;
|
|
4792
|
+
if (e.resolved.synthetic.bold) return null;
|
|
4793
|
+
const r = e.resolved.resolved;
|
|
4794
|
+
return glyphOutline(r.family, r.weight, r.style, e.cp);
|
|
4795
|
+
}
|
|
4796
|
+
const decorations = [];
|
|
4797
|
+
let span = null;
|
|
4798
|
+
function flushSpan() {
|
|
4799
|
+
const s = span;
|
|
4800
|
+
span = null;
|
|
4801
|
+
if (!s || s.x1 <= s.x0) return;
|
|
4802
|
+
const thickness = s.fontSize * DECORATION_THICKNESS;
|
|
4803
|
+
if (s.underline) {
|
|
4804
|
+
const y0 = s.baselineY + s.fontSize * UNDERLINE_OFFSET;
|
|
4805
|
+
decorations.push({ kind: "underline", x0: s.x0, y0, x1: s.x1, y1: y0 + thickness, fill: s.fill });
|
|
4806
|
+
}
|
|
4807
|
+
if (s.strikethrough) {
|
|
4808
|
+
const y0 = s.baselineY + s.fontSize * STRIKETHROUGH_OFFSET;
|
|
4809
|
+
decorations.push({ kind: "strikethrough", x0: s.x0, y0, x1: s.x1, y1: y0 + thickness, fill: s.fill });
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
const lineBoxes = [];
|
|
4813
|
+
let penY = 0;
|
|
4814
|
+
let maxLineWidth = 0;
|
|
4815
|
+
const finiteWidth = Number.isFinite(opts.maxWidth) ? opts.maxWidth : 0;
|
|
4816
|
+
for (const line of lines) {
|
|
4817
|
+
const alignShift = (() => {
|
|
4818
|
+
if (opts.align === "left") return 0;
|
|
4819
|
+
if (!Number.isFinite(opts.maxWidth)) {
|
|
4820
|
+
return opts.align === "center" ? -line.width / 2 : -line.width;
|
|
4821
|
+
}
|
|
4822
|
+
const slack = finiteWidth - line.width;
|
|
4823
|
+
return opts.align === "center" ? slack / 2 : slack;
|
|
4824
|
+
})();
|
|
4825
|
+
const lineX0 = alignShift;
|
|
4826
|
+
const baselineSource = line.entries[0] ?? line.blank;
|
|
4827
|
+
const lineBaselineY = baselineSource ? penY + baselineSource.font.common.base * (baselineSource.fontSize / baselineSource.font.info.size) : penY;
|
|
4828
|
+
let penX = lineX0;
|
|
4829
|
+
for (const e of line.entries) {
|
|
4830
|
+
penX += e.kerningBefore;
|
|
4831
|
+
const step = e.advance + e.tracking;
|
|
4832
|
+
const scale2 = e.fontSize / e.font.info.size;
|
|
4833
|
+
const baselineY = penY + e.font.common.base * scale2;
|
|
4834
|
+
if (e.run.underline || e.run.strikethrough) {
|
|
4835
|
+
if (span !== null && span.underline === e.run.underline && span.strikethrough === e.run.strikethrough && span.fontSize === e.fontSize && span.baselineY === baselineY && sameFill(span.fill, e.run.fill)) {
|
|
4836
|
+
span.x1 = penX + step;
|
|
4837
|
+
} else {
|
|
4838
|
+
flushSpan();
|
|
4839
|
+
span = {
|
|
4840
|
+
underline: e.run.underline,
|
|
4841
|
+
strikethrough: e.run.strikethrough,
|
|
4842
|
+
fill: e.run.fill,
|
|
4843
|
+
fontSize: e.fontSize,
|
|
4844
|
+
baselineY,
|
|
4845
|
+
x0: penX,
|
|
4846
|
+
x1: penX + step
|
|
4847
|
+
};
|
|
4848
|
+
}
|
|
4849
|
+
} else {
|
|
4850
|
+
flushSpan();
|
|
4851
|
+
}
|
|
4852
|
+
const outlineD = outlineFor(e);
|
|
4853
|
+
if (outlineD !== null) {
|
|
4854
|
+
const group2 = getOrCreateGroup(ctx, e.run, e.resolved, 0, "outline");
|
|
4855
|
+
group2.glyphs.push({
|
|
4856
|
+
d: outlineD,
|
|
4857
|
+
key: `${e.resolved.resolved.family}|${e.resolved.resolved.weight}|${e.resolved.resolved.style}|${e.cp}`,
|
|
4858
|
+
x: penX,
|
|
4859
|
+
baselineY,
|
|
4860
|
+
// Em space is unit-scale, so world units per em is just the size.
|
|
4861
|
+
scale: e.fontSize
|
|
4862
|
+
});
|
|
4863
|
+
penX += step;
|
|
4864
|
+
continue;
|
|
4865
|
+
}
|
|
4866
|
+
if (e.advance === 0 || e.glyph.width === 0 || e.glyph.page < 0) {
|
|
4867
|
+
penX += step;
|
|
4868
|
+
continue;
|
|
5652
4869
|
}
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
prevCp = cp;
|
|
5667
|
-
prevFont = glyphFont;
|
|
5668
|
-
prevFontSize = run.fontSize;
|
|
4870
|
+
const group = getOrCreateGroup(ctx, e.run, e.resolved, e.glyph.page);
|
|
4871
|
+
const atlasW = e.font.common.scaleW;
|
|
4872
|
+
const atlasH = e.font.common.scaleH;
|
|
4873
|
+
const qx0 = penX + e.glyph.xoffset * scale2;
|
|
4874
|
+
const qy0 = penY + e.glyph.yoffset * scale2;
|
|
4875
|
+
const qx1 = qx0 + e.glyph.width * scale2;
|
|
4876
|
+
const qy1 = qy0 + e.glyph.height * scale2;
|
|
4877
|
+
const u0 = e.glyph.x / atlasW;
|
|
4878
|
+
const v0 = e.glyph.y / atlasH;
|
|
4879
|
+
const u1 = (e.glyph.x + e.glyph.width) / atlasW;
|
|
4880
|
+
const v1 = (e.glyph.y + e.glyph.height) / atlasH;
|
|
4881
|
+
group.quads.push({ x0: qx0, y0: qy0, x1: qx1, y1: qy1, u0, v0, u1, v1, baselineY });
|
|
4882
|
+
penX += step;
|
|
5669
4883
|
}
|
|
4884
|
+
flushSpan();
|
|
4885
|
+
lineBoxes.push({
|
|
4886
|
+
x0: lineX0,
|
|
4887
|
+
y0: penY,
|
|
4888
|
+
x1: lineX0 + line.width,
|
|
4889
|
+
y1: penY + line.height,
|
|
4890
|
+
baselineY: lineBaselineY
|
|
4891
|
+
});
|
|
4892
|
+
maxLineWidth = Math.max(maxLineWidth, line.width);
|
|
4893
|
+
penY += line.height;
|
|
5670
4894
|
}
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
lines
|
|
5675
|
-
|
|
4895
|
+
return {
|
|
4896
|
+
groups: [...ctx.groups.values()],
|
|
4897
|
+
decorations,
|
|
4898
|
+
lines: lineBoxes,
|
|
4899
|
+
bounds: { width: maxLineWidth, height: penY }
|
|
4900
|
+
};
|
|
4901
|
+
}
|
|
4902
|
+
var LAYOUT_CACHE_VARIANT_LIMIT = 8;
|
|
4903
|
+
var cache2 = /* @__PURE__ */ new WeakMap();
|
|
4904
|
+
function outlineBucket(runs, min) {
|
|
4905
|
+
if (min === void 0) return -1;
|
|
4906
|
+
const sizes = /* @__PURE__ */ new Set();
|
|
4907
|
+
for (const r of runs) sizes.add(r.fontSize);
|
|
4908
|
+
let n = 0;
|
|
4909
|
+
for (const size of sizes) if (size >= min) n++;
|
|
4910
|
+
return n;
|
|
4911
|
+
}
|
|
4912
|
+
function variantKey2(runs, opts) {
|
|
4913
|
+
return `${opts.maxWidth}|${opts.lineHeight}|${opts.align}|${outlineBucket(runs, opts.outlineMinSize)}`;
|
|
4914
|
+
}
|
|
4915
|
+
function cachedLayoutRuns(runs, opts) {
|
|
4916
|
+
const fonts = glyphGeneration();
|
|
4917
|
+
let entry = cache2.get(runs);
|
|
4918
|
+
if (entry === void 0) {
|
|
4919
|
+
entry = { generation: fonts, byVariant: /* @__PURE__ */ new Map() };
|
|
4920
|
+
cache2.set(runs, entry);
|
|
4921
|
+
} else if (entry.generation !== fonts) {
|
|
4922
|
+
entry.generation = fonts;
|
|
4923
|
+
entry.byVariant.clear();
|
|
5676
4924
|
}
|
|
4925
|
+
const key = variantKey2(runs, opts);
|
|
4926
|
+
const hit = entry.byVariant.get(key);
|
|
4927
|
+
if (hit !== void 0) return hit;
|
|
4928
|
+
const laid = layoutRuns(runs, opts);
|
|
4929
|
+
if (entry.byVariant.size >= LAYOUT_CACHE_VARIANT_LIMIT) entry.byVariant.clear();
|
|
4930
|
+
entry.byVariant.set(key, laid);
|
|
4931
|
+
return laid;
|
|
4932
|
+
}
|
|
4933
|
+
function verticalAlignOffset(align, boxHeight, textHeight) {
|
|
4934
|
+
if (align === void 0 || align === "top" || boxHeight === void 0) return 0;
|
|
4935
|
+
const slack = boxHeight - textHeight;
|
|
4936
|
+
return align === "center" ? slack / 2 : slack;
|
|
4937
|
+
}
|
|
4938
|
+
var NUM_RE = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
|
|
4939
|
+
function tokenize(d) {
|
|
4940
|
+
const out = [];
|
|
5677
4941
|
let i = 0;
|
|
5678
|
-
while (i <
|
|
5679
|
-
const
|
|
5680
|
-
if (
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
}
|
|
5685
|
-
|
|
4942
|
+
while (i < d.length) {
|
|
4943
|
+
const ch = d[i];
|
|
4944
|
+
if (/[A-Za-z]/.test(ch)) {
|
|
4945
|
+
let j = i + 1;
|
|
4946
|
+
while (j < d.length && !/[A-Za-z]/.test(d[j])) j++;
|
|
4947
|
+
const argSlice = d.slice(i + 1, j);
|
|
4948
|
+
out.push({ cmd: ch, args: readNumbers(argSlice) });
|
|
4949
|
+
i = j;
|
|
4950
|
+
} else {
|
|
5686
4951
|
i++;
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
return out;
|
|
4955
|
+
}
|
|
4956
|
+
function readNumbers(s) {
|
|
4957
|
+
const out = [];
|
|
4958
|
+
let m;
|
|
4959
|
+
NUM_RE.lastIndex = 0;
|
|
4960
|
+
while ((m = NUM_RE.exec(s)) !== null) {
|
|
4961
|
+
const n = Number(m[0]);
|
|
4962
|
+
if (Number.isFinite(n)) out.push(n);
|
|
4963
|
+
}
|
|
4964
|
+
return out;
|
|
4965
|
+
}
|
|
4966
|
+
var ARG_COUNTS = {
|
|
4967
|
+
M: 2,
|
|
4968
|
+
L: 2,
|
|
4969
|
+
H: 1,
|
|
4970
|
+
V: 1,
|
|
4971
|
+
C: 6,
|
|
4972
|
+
S: 4,
|
|
4973
|
+
Q: 4,
|
|
4974
|
+
T: 2,
|
|
4975
|
+
A: 7,
|
|
4976
|
+
Z: 0
|
|
4977
|
+
};
|
|
4978
|
+
function pathFromD(d, onWarn) {
|
|
4979
|
+
const tokens = tokenize(d);
|
|
4980
|
+
const b = new PathBuilder();
|
|
4981
|
+
const st = {
|
|
4982
|
+
x: 0,
|
|
4983
|
+
y: 0,
|
|
4984
|
+
startX: 0,
|
|
4985
|
+
startY: 0,
|
|
4986
|
+
lastCubicCtrl: null,
|
|
4987
|
+
lastQuadCtrl: null
|
|
4988
|
+
};
|
|
4989
|
+
for (const { cmd, args } of tokens) {
|
|
4990
|
+
const upper = cmd.toUpperCase();
|
|
4991
|
+
const relative = cmd !== upper;
|
|
4992
|
+
const argCount = ARG_COUNTS[upper];
|
|
4993
|
+
if (argCount === void 0) {
|
|
5687
4994
|
continue;
|
|
5688
4995
|
}
|
|
5689
|
-
if (
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
i++;
|
|
4996
|
+
if (upper === "Z") {
|
|
4997
|
+
b.close();
|
|
4998
|
+
st.x = st.startX;
|
|
4999
|
+
st.y = st.startY;
|
|
5000
|
+
st.lastCubicCtrl = null;
|
|
5001
|
+
st.lastQuadCtrl = null;
|
|
5696
5002
|
continue;
|
|
5697
5003
|
}
|
|
5698
|
-
|
|
5699
|
-
let
|
|
5700
|
-
|
|
5701
|
-
const
|
|
5702
|
-
|
|
5703
|
-
|
|
5004
|
+
const groups = argCount === 0 ? 1 : Math.floor(args.length / argCount);
|
|
5005
|
+
for (let g = 0; g < groups; g++) {
|
|
5006
|
+
const a = args.slice(g * argCount, (g + 1) * argCount);
|
|
5007
|
+
const effectiveUpper = upper === "M" && g > 0 ? "L" : upper;
|
|
5008
|
+
runCommand(effectiveUpper, relative, a, st, b);
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
5011
|
+
return b.build();
|
|
5012
|
+
}
|
|
5013
|
+
function runCommand(upper, relative, a, st, b) {
|
|
5014
|
+
const rx = relative ? st.x : 0;
|
|
5015
|
+
const ry = relative ? st.y : 0;
|
|
5016
|
+
switch (upper) {
|
|
5017
|
+
case "M": {
|
|
5018
|
+
const x = a[0] + rx;
|
|
5019
|
+
const y = a[1] + ry;
|
|
5020
|
+
b.moveTo(x, y);
|
|
5021
|
+
st.x = x;
|
|
5022
|
+
st.y = y;
|
|
5023
|
+
st.startX = x;
|
|
5024
|
+
st.startY = y;
|
|
5025
|
+
st.lastCubicCtrl = null;
|
|
5026
|
+
st.lastQuadCtrl = null;
|
|
5027
|
+
return;
|
|
5028
|
+
}
|
|
5029
|
+
case "L": {
|
|
5030
|
+
const x = a[0] + rx;
|
|
5031
|
+
const y = a[1] + ry;
|
|
5032
|
+
b.lineTo(x, y);
|
|
5033
|
+
st.x = x;
|
|
5034
|
+
st.y = y;
|
|
5035
|
+
st.lastCubicCtrl = null;
|
|
5036
|
+
st.lastQuadCtrl = null;
|
|
5037
|
+
return;
|
|
5038
|
+
}
|
|
5039
|
+
case "H": {
|
|
5040
|
+
const x = a[0] + (relative ? st.x : 0);
|
|
5041
|
+
b.lineTo(x, st.y);
|
|
5042
|
+
st.x = x;
|
|
5043
|
+
st.lastCubicCtrl = null;
|
|
5044
|
+
st.lastQuadCtrl = null;
|
|
5045
|
+
return;
|
|
5046
|
+
}
|
|
5047
|
+
case "V": {
|
|
5048
|
+
const y = a[0] + (relative ? st.y : 0);
|
|
5049
|
+
b.lineTo(st.x, y);
|
|
5050
|
+
st.y = y;
|
|
5051
|
+
st.lastCubicCtrl = null;
|
|
5052
|
+
st.lastQuadCtrl = null;
|
|
5053
|
+
return;
|
|
5054
|
+
}
|
|
5055
|
+
case "C": {
|
|
5056
|
+
const x1 = a[0] + rx, y1 = a[1] + ry;
|
|
5057
|
+
const x2 = a[2] + rx, y2 = a[3] + ry;
|
|
5058
|
+
const x = a[4] + rx, y = a[5] + ry;
|
|
5059
|
+
b.curveTo(x1, y1, x2, y2, x, y);
|
|
5060
|
+
st.x = x;
|
|
5061
|
+
st.y = y;
|
|
5062
|
+
st.lastCubicCtrl = { x: x2, y: y2 };
|
|
5063
|
+
st.lastQuadCtrl = null;
|
|
5064
|
+
return;
|
|
5065
|
+
}
|
|
5066
|
+
case "S": {
|
|
5067
|
+
const ref = st.lastCubicCtrl ?? { x: st.x, y: st.y };
|
|
5068
|
+
const x1 = 2 * st.x - ref.x;
|
|
5069
|
+
const y1 = 2 * st.y - ref.y;
|
|
5070
|
+
const x2 = a[0] + rx, y2 = a[1] + ry;
|
|
5071
|
+
const x = a[2] + rx, y = a[3] + ry;
|
|
5072
|
+
b.curveTo(x1, y1, x2, y2, x, y);
|
|
5073
|
+
st.x = x;
|
|
5074
|
+
st.y = y;
|
|
5075
|
+
st.lastCubicCtrl = { x: x2, y: y2 };
|
|
5076
|
+
st.lastQuadCtrl = null;
|
|
5077
|
+
return;
|
|
5078
|
+
}
|
|
5079
|
+
case "Q": {
|
|
5080
|
+
const x1 = a[0] + rx, y1 = a[1] + ry;
|
|
5081
|
+
const x = a[2] + rx, y = a[3] + ry;
|
|
5082
|
+
b.quadTo(x1, y1, x, y);
|
|
5083
|
+
st.x = x;
|
|
5084
|
+
st.y = y;
|
|
5085
|
+
st.lastQuadCtrl = { x: x1, y: y1 };
|
|
5086
|
+
st.lastCubicCtrl = null;
|
|
5087
|
+
return;
|
|
5704
5088
|
}
|
|
5705
|
-
|
|
5706
|
-
|
|
5089
|
+
case "T": {
|
|
5090
|
+
const ref = st.lastQuadCtrl ?? { x: st.x, y: st.y };
|
|
5091
|
+
const x1 = 2 * st.x - ref.x;
|
|
5092
|
+
const y1 = 2 * st.y - ref.y;
|
|
5093
|
+
const x = a[0] + rx, y = a[1] + ry;
|
|
5094
|
+
b.quadTo(x1, y1, x, y);
|
|
5095
|
+
st.x = x;
|
|
5096
|
+
st.y = y;
|
|
5097
|
+
st.lastQuadCtrl = { x: x1, y: y1 };
|
|
5098
|
+
st.lastCubicCtrl = null;
|
|
5099
|
+
return;
|
|
5707
5100
|
}
|
|
5708
|
-
|
|
5709
|
-
const
|
|
5710
|
-
const
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5101
|
+
case "A": {
|
|
5102
|
+
const rxA = Math.abs(a[0]);
|
|
5103
|
+
const ryA = Math.abs(a[1]);
|
|
5104
|
+
const xRot = a[2];
|
|
5105
|
+
const largeArc = a[3] !== 0;
|
|
5106
|
+
const sweep = a[4] !== 0;
|
|
5107
|
+
const ex = a[5] + rx;
|
|
5108
|
+
const ey = a[6] + ry;
|
|
5109
|
+
arcToCubics(st.x, st.y, ex, ey, rxA, ryA, xRot, largeArc, sweep, b);
|
|
5110
|
+
st.x = ex;
|
|
5111
|
+
st.y = ey;
|
|
5112
|
+
st.lastCubicCtrl = null;
|
|
5113
|
+
st.lastQuadCtrl = null;
|
|
5114
|
+
return;
|
|
5714
5115
|
}
|
|
5715
|
-
|
|
5116
|
+
default:
|
|
5117
|
+
return;
|
|
5716
5118
|
}
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
return glyphOutline(r.family, r.weight, r.style, e.cp);
|
|
5119
|
+
}
|
|
5120
|
+
function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep, b) {
|
|
5121
|
+
if (x1 === x2 && y1 === y2) return;
|
|
5122
|
+
if (rx === 0 || ry === 0) {
|
|
5123
|
+
b.lineTo(x2, y2);
|
|
5124
|
+
return;
|
|
5724
5125
|
}
|
|
5725
|
-
const
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5126
|
+
const phi = xAxisRotationDeg * Math.PI / 180;
|
|
5127
|
+
const cosPhi = Math.cos(phi);
|
|
5128
|
+
const sinPhi = Math.sin(phi);
|
|
5129
|
+
const dx = (x1 - x2) / 2;
|
|
5130
|
+
const dy = (y1 - y2) / 2;
|
|
5131
|
+
const x1p = cosPhi * dx + sinPhi * dy;
|
|
5132
|
+
const y1p = -sinPhi * dx + cosPhi * dy;
|
|
5133
|
+
let rxs = rx * rx;
|
|
5134
|
+
let rys = ry * ry;
|
|
5135
|
+
const x1ps = x1p * x1p;
|
|
5136
|
+
const y1ps = y1p * y1p;
|
|
5137
|
+
const lambda = x1ps / rxs + y1ps / rys;
|
|
5138
|
+
let rxFixed = rx;
|
|
5139
|
+
let ryFixed = ry;
|
|
5140
|
+
if (lambda > 1) {
|
|
5141
|
+
const sqrtLambda = Math.sqrt(lambda);
|
|
5142
|
+
rxFixed = sqrtLambda * rx;
|
|
5143
|
+
ryFixed = sqrtLambda * ry;
|
|
5144
|
+
rxs = rxFixed * rxFixed;
|
|
5145
|
+
rys = ryFixed * ryFixed;
|
|
5740
5146
|
}
|
|
5741
|
-
const
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
const
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5147
|
+
const sign2 = largeArc === sweep ? -1 : 1;
|
|
5148
|
+
const num = rxs * rys - rxs * y1ps - rys * x1ps;
|
|
5149
|
+
const den = rxs * y1ps + rys * x1ps;
|
|
5150
|
+
const factor = sign2 * Math.sqrt(Math.max(0, num / den));
|
|
5151
|
+
const cxp = factor * (rxFixed * y1p) / ryFixed;
|
|
5152
|
+
const cyp = factor * -(ryFixed * x1p) / rxFixed;
|
|
5153
|
+
const cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2;
|
|
5154
|
+
const cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2;
|
|
5155
|
+
const angle = (ux, uy, vx, vy) => {
|
|
5156
|
+
const dot = ux * vx + uy * vy;
|
|
5157
|
+
const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
|
|
5158
|
+
let a = Math.acos(Math.max(-1, Math.min(1, dot / len)));
|
|
5159
|
+
if (ux * vy - uy * vx < 0) a = -a;
|
|
5160
|
+
return a;
|
|
5161
|
+
};
|
|
5162
|
+
const theta1 = angle(1, 0, (x1p - cxp) / rxFixed, (y1p - cyp) / ryFixed);
|
|
5163
|
+
let dTheta = angle(
|
|
5164
|
+
(x1p - cxp) / rxFixed,
|
|
5165
|
+
(y1p - cyp) / ryFixed,
|
|
5166
|
+
(-x1p - cxp) / rxFixed,
|
|
5167
|
+
(-y1p - cyp) / ryFixed
|
|
5168
|
+
);
|
|
5169
|
+
if (!sweep && dTheta > 0) dTheta -= 2 * Math.PI;
|
|
5170
|
+
else if (sweep && dTheta < 0) dTheta += 2 * Math.PI;
|
|
5171
|
+
const segCount = Math.max(1, Math.ceil(Math.abs(dTheta) / (Math.PI / 2)));
|
|
5172
|
+
const segAngle = dTheta / segCount;
|
|
5173
|
+
const t = 4 / 3 * Math.tan(segAngle / 4);
|
|
5174
|
+
let prevX = x1;
|
|
5175
|
+
let prevY = y1;
|
|
5176
|
+
let prevDx = -Math.sin(theta1) * rxFixed;
|
|
5177
|
+
let prevDy = Math.cos(theta1) * ryFixed;
|
|
5178
|
+
for (let i = 1; i <= segCount; i++) {
|
|
5179
|
+
const theta = theta1 + i * segAngle;
|
|
5180
|
+
const cosT = Math.cos(theta);
|
|
5181
|
+
const sinT = Math.sin(theta);
|
|
5182
|
+
const px = cosPhi * (cosT * rxFixed) - sinPhi * (sinT * ryFixed) + cx;
|
|
5183
|
+
const py = sinPhi * (cosT * rxFixed) + cosPhi * (sinT * ryFixed) + cy;
|
|
5184
|
+
const dxNew = -sinT * rxFixed;
|
|
5185
|
+
const dyNew = cosT * ryFixed;
|
|
5186
|
+
const c1x = prevX + cosPhi * (t * prevDx) - sinPhi * (t * prevDy);
|
|
5187
|
+
const c1y = prevY + sinPhi * (t * prevDx) + cosPhi * (t * prevDy);
|
|
5188
|
+
const c2x = px - cosPhi * (t * dxNew) + sinPhi * (t * dyNew);
|
|
5189
|
+
const c2y = py - sinPhi * (t * dxNew) - cosPhi * (t * dyNew);
|
|
5190
|
+
b.curveTo(c1x, c1y, c2x, c2y, px, py);
|
|
5191
|
+
prevX = px;
|
|
5192
|
+
prevY = py;
|
|
5193
|
+
prevDx = dxNew;
|
|
5194
|
+
prevDy = dyNew;
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
var OUTLINE_FLATTEN_TOLERANCE = 1 / 4096;
|
|
5198
|
+
var OUTLINE_MESH_CACHE_LIMIT = 2048;
|
|
5199
|
+
var cache3 = /* @__PURE__ */ new Map();
|
|
5200
|
+
function outlineMesh(key, d) {
|
|
5201
|
+
const cached2 = cache3.get(key);
|
|
5202
|
+
if (cached2 !== void 0) return cached2;
|
|
5203
|
+
if (cache3.size >= OUTLINE_MESH_CACHE_LIMIT) cache3 = /* @__PURE__ */ new Map();
|
|
5204
|
+
const mesh = tessellate(pathFromD(d), { flattenTolerance: OUTLINE_FLATTEN_TOLERANCE });
|
|
5205
|
+
cache3.set(key, mesh);
|
|
5206
|
+
return mesh;
|
|
5207
|
+
}
|
|
5208
|
+
function extractPolylines(path, opts = {}) {
|
|
5209
|
+
if (path.kind === "rect") return [extractRect(path)];
|
|
5210
|
+
return extractPolygon(path, opts);
|
|
5211
|
+
}
|
|
5212
|
+
function extractRect(p) {
|
|
5213
|
+
const { x, y, width: w, height: h } = p;
|
|
5214
|
+
return {
|
|
5215
|
+
points: [x, y, x + w, y, x + w, y + h, x, y + h],
|
|
5216
|
+
closed: true,
|
|
5217
|
+
anchorA: new Uint32Array([0, 1, 2, 3]),
|
|
5218
|
+
anchorB: new Uint32Array([0, 1, 2, 3]),
|
|
5219
|
+
anchorT: new Float32Array([0, 0, 0, 0])
|
|
5220
|
+
};
|
|
5221
|
+
}
|
|
5222
|
+
function extractPolygon(p, opts) {
|
|
5223
|
+
const tolerance = opts.flattenTolerance ?? DEFAULT_FLATTEN_TOLERANCE;
|
|
5224
|
+
const { commands, coords } = p;
|
|
5225
|
+
const out = [];
|
|
5226
|
+
let anchorCounter = 0;
|
|
5227
|
+
let pts = null;
|
|
5228
|
+
let aA = null;
|
|
5229
|
+
let aB = null;
|
|
5230
|
+
let aT = null;
|
|
5231
|
+
let current = null;
|
|
5232
|
+
let coordIdx = 0;
|
|
5233
|
+
let prevX = 0;
|
|
5234
|
+
let prevY = 0;
|
|
5235
|
+
let prevAnchor = -1;
|
|
5236
|
+
const beginContour = () => {
|
|
5237
|
+
pts = [];
|
|
5238
|
+
aA = [];
|
|
5239
|
+
aB = [];
|
|
5240
|
+
aT = [];
|
|
5241
|
+
const next = { points: pts, closed: false };
|
|
5242
|
+
out.push(next);
|
|
5243
|
+
return next;
|
|
5244
|
+
};
|
|
5245
|
+
const dropDuplicateClosingPoint = () => {
|
|
5246
|
+
if (!pts || !aA || !aB || !aT) return;
|
|
5247
|
+
const n = pts.length / 2;
|
|
5248
|
+
if (n < 2) return;
|
|
5249
|
+
if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;
|
|
5250
|
+
pts.length -= 2;
|
|
5251
|
+
aA.length -= 1;
|
|
5252
|
+
aB.length -= 1;
|
|
5253
|
+
aT.length -= 1;
|
|
5254
|
+
};
|
|
5255
|
+
const commit = (target) => {
|
|
5256
|
+
if (!pts || !aA || !aB || !aT) return;
|
|
5257
|
+
target.anchorA = new Uint32Array(aA);
|
|
5258
|
+
target.anchorB = new Uint32Array(aB);
|
|
5259
|
+
target.anchorT = new Float32Array(aT);
|
|
5260
|
+
};
|
|
5261
|
+
for (let cmdIdx = 0; cmdIdx < commands.length; cmdIdx++) {
|
|
5262
|
+
const cmd = commands[cmdIdx];
|
|
5263
|
+
switch (cmd) {
|
|
5264
|
+
case PATH_M2: {
|
|
5265
|
+
if (current) commit(current);
|
|
5266
|
+
current = beginContour();
|
|
5267
|
+
prevX = coords[coordIdx];
|
|
5268
|
+
prevY = coords[coordIdx + 1];
|
|
5269
|
+
pts.push(prevX, prevY);
|
|
5270
|
+
aA.push(anchorCounter);
|
|
5271
|
+
aB.push(anchorCounter);
|
|
5272
|
+
aT.push(0);
|
|
5273
|
+
prevAnchor = anchorCounter;
|
|
5274
|
+
anchorCounter++;
|
|
5275
|
+
coordIdx += 2;
|
|
5276
|
+
break;
|
|
5277
|
+
}
|
|
5278
|
+
case PATH_L2: {
|
|
5279
|
+
prevX = coords[coordIdx];
|
|
5280
|
+
prevY = coords[coordIdx + 1];
|
|
5281
|
+
pts.push(prevX, prevY);
|
|
5282
|
+
aA.push(anchorCounter);
|
|
5283
|
+
aB.push(anchorCounter);
|
|
5284
|
+
aT.push(0);
|
|
5285
|
+
prevAnchor = anchorCounter;
|
|
5286
|
+
anchorCounter++;
|
|
5287
|
+
coordIdx += 2;
|
|
5288
|
+
break;
|
|
5289
|
+
}
|
|
5290
|
+
case PATH_Q2: {
|
|
5291
|
+
const cx = coords[coordIdx], cy = coords[coordIdx + 1];
|
|
5292
|
+
const ex = coords[coordIdx + 2], ey = coords[coordIdx + 3];
|
|
5293
|
+
const targetAnchor = anchorCounter;
|
|
5294
|
+
const segStart = pts.length / 2;
|
|
5295
|
+
const arcAccum = [];
|
|
5296
|
+
const total = flattenQuadraticWithArcLen(prevX, prevY, cx, cy, ex, ey, tolerance, pts, arcAccum);
|
|
5297
|
+
for (let k = 0; k < arcAccum.length; k++) {
|
|
5298
|
+
aA.push(prevAnchor);
|
|
5299
|
+
aB.push(targetAnchor);
|
|
5300
|
+
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
5777
5301
|
}
|
|
5778
|
-
|
|
5779
|
-
|
|
5302
|
+
const lastIdx = segStart + arcAccum.length - 1;
|
|
5303
|
+
aA[lastIdx] = targetAnchor;
|
|
5304
|
+
aB[lastIdx] = targetAnchor;
|
|
5305
|
+
aT[lastIdx] = 0;
|
|
5306
|
+
prevX = ex;
|
|
5307
|
+
prevY = ey;
|
|
5308
|
+
prevAnchor = targetAnchor;
|
|
5309
|
+
anchorCounter++;
|
|
5310
|
+
coordIdx += 4;
|
|
5311
|
+
break;
|
|
5780
5312
|
}
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
const
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5313
|
+
case PATH_C2: {
|
|
5314
|
+
const c1x = coords[coordIdx], c1y = coords[coordIdx + 1];
|
|
5315
|
+
const c2x = coords[coordIdx + 2], c2y = coords[coordIdx + 3];
|
|
5316
|
+
const ex = coords[coordIdx + 4], ey = coords[coordIdx + 5];
|
|
5317
|
+
const targetAnchor = anchorCounter;
|
|
5318
|
+
const segStart = pts.length / 2;
|
|
5319
|
+
const arcAccum = [];
|
|
5320
|
+
const total = flattenCubicWithArcLen(prevX, prevY, c1x, c1y, c2x, c2y, ex, ey, tolerance, pts, arcAccum);
|
|
5321
|
+
for (let k = 0; k < arcAccum.length; k++) {
|
|
5322
|
+
aA.push(prevAnchor);
|
|
5323
|
+
aB.push(targetAnchor);
|
|
5324
|
+
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
5325
|
+
}
|
|
5326
|
+
const lastIdx = segStart + arcAccum.length - 1;
|
|
5327
|
+
aA[lastIdx] = targetAnchor;
|
|
5328
|
+
aB[lastIdx] = targetAnchor;
|
|
5329
|
+
aT[lastIdx] = 0;
|
|
5330
|
+
prevX = ex;
|
|
5331
|
+
prevY = ey;
|
|
5332
|
+
prevAnchor = targetAnchor;
|
|
5333
|
+
anchorCounter++;
|
|
5334
|
+
coordIdx += 6;
|
|
5335
|
+
break;
|
|
5794
5336
|
}
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5337
|
+
case PATH_Z2: {
|
|
5338
|
+
if (current) {
|
|
5339
|
+
current.closed = true;
|
|
5340
|
+
dropDuplicateClosingPoint();
|
|
5341
|
+
}
|
|
5342
|
+
break;
|
|
5798
5343
|
}
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5344
|
+
default:
|
|
5345
|
+
throw new Error(`extractPolylines: unknown command code ${cmd}`);
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
if (current) commit(current);
|
|
5349
|
+
return out;
|
|
5350
|
+
}
|
|
5351
|
+
var EMPTY_MESH = {
|
|
5352
|
+
vertices: new Float32Array(0),
|
|
5353
|
+
indices: new Uint32Array(0),
|
|
5354
|
+
anchorA: new Uint32Array(0),
|
|
5355
|
+
anchorB: new Uint32Array(0),
|
|
5356
|
+
anchorT: new Float32Array(0)
|
|
5357
|
+
};
|
|
5358
|
+
function tessellateStroke(path, stroke, opts = {}) {
|
|
5359
|
+
const width = stroke.width ?? 1;
|
|
5360
|
+
if (width <= 0) return EMPTY_MESH;
|
|
5361
|
+
const join = stroke.join ?? "miter";
|
|
5362
|
+
const cap = stroke.cap ?? "butt";
|
|
5363
|
+
const align = stroke.align ?? "center";
|
|
5364
|
+
const miterLimit = stroke.miterLimit ?? DEFAULT_MITER_LIMIT;
|
|
5365
|
+
const varyingThreshold = stroke.varyingWidthJoinThreshold ?? DEFAULT_VARYING_WIDTH_JOIN_THRESHOLD;
|
|
5366
|
+
let workingPath = path;
|
|
5367
|
+
if (path.kind === "rect" && align !== "center") {
|
|
5368
|
+
const aligned = alignedStrokeRect(path, align, width);
|
|
5369
|
+
workingPath = {
|
|
5370
|
+
kind: "rect",
|
|
5371
|
+
x: aligned.x,
|
|
5372
|
+
y: aligned.y,
|
|
5373
|
+
width: aligned.width,
|
|
5374
|
+
height: aligned.height
|
|
5375
|
+
};
|
|
5376
|
+
}
|
|
5377
|
+
const polylines = extractPolylines(workingPath, opts);
|
|
5378
|
+
if (stroke.vertexWidths && stroke.vertexWidths.length > 0) {
|
|
5379
|
+
for (const pl of polylines) populatePolylineWidths(pl, stroke.vertexWidths, width);
|
|
5380
|
+
}
|
|
5381
|
+
const dash = stroke.dash ?? [];
|
|
5382
|
+
const verts = [];
|
|
5383
|
+
const idx = [];
|
|
5384
|
+
const anchorA = [];
|
|
5385
|
+
const anchorB = [];
|
|
5386
|
+
const anchorT = [];
|
|
5387
|
+
for (const pl of polylines) {
|
|
5388
|
+
const subs = dash.length > 0 ? splitForDash(pl, dash) : [pl];
|
|
5389
|
+
for (const sub2 of subs) {
|
|
5390
|
+
expandPolyline(sub2, width, join, cap, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT);
|
|
5812
5391
|
}
|
|
5813
|
-
flushSpan();
|
|
5814
|
-
lineBoxes.push({
|
|
5815
|
-
x0: lineX0,
|
|
5816
|
-
y0: penY,
|
|
5817
|
-
x1: lineX0 + line.width,
|
|
5818
|
-
y1: penY + line.height,
|
|
5819
|
-
baselineY: lineBaselineY
|
|
5820
|
-
});
|
|
5821
|
-
maxLineWidth = Math.max(maxLineWidth, line.width);
|
|
5822
|
-
penY += line.height;
|
|
5823
5392
|
}
|
|
5824
5393
|
return {
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5394
|
+
vertices: new Float32Array(verts),
|
|
5395
|
+
indices: new Uint32Array(idx),
|
|
5396
|
+
anchorA: new Uint32Array(anchorA),
|
|
5397
|
+
anchorB: new Uint32Array(anchorB),
|
|
5398
|
+
anchorT: new Float32Array(anchorT)
|
|
5829
5399
|
};
|
|
5830
5400
|
}
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
const
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5401
|
+
function expandPolyline(pl, width, join, cap, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT) {
|
|
5402
|
+
const half = width / 2;
|
|
5403
|
+
const pts = pl.points;
|
|
5404
|
+
const ptCount = pts.length / 2;
|
|
5405
|
+
const segCount = ptCount - 1;
|
|
5406
|
+
if (segCount < 1) return;
|
|
5407
|
+
const plA = pl.anchorA ?? new Uint32Array(ptCount);
|
|
5408
|
+
const plB = pl.anchorB ?? new Uint32Array(ptCount);
|
|
5409
|
+
const plT = pl.anchorT ?? new Float32Array(ptCount);
|
|
5410
|
+
const plHalf = pl.widths ? pl.widths.map((w) => w / 2) : null;
|
|
5411
|
+
const segs = [];
|
|
5412
|
+
const segSrcIdx = [];
|
|
5413
|
+
for (let s = 0; s < segCount; s++) {
|
|
5414
|
+
const ha = plHalf ? plHalf[s] : half;
|
|
5415
|
+
const hb = plHalf ? plHalf[s + 1] : half;
|
|
5416
|
+
const seg = makeSeg(pts[s * 2], pts[s * 2 + 1], pts[(s + 1) * 2], pts[(s + 1) * 2 + 1], ha, hb);
|
|
5417
|
+
if (seg) {
|
|
5418
|
+
segs.push(seg);
|
|
5419
|
+
segSrcIdx.push(s);
|
|
5420
|
+
}
|
|
5421
|
+
}
|
|
5422
|
+
let closerSrcIdx = -1;
|
|
5423
|
+
if (pl.closed && segs.length >= 1) {
|
|
5424
|
+
const last = segs[segs.length - 1];
|
|
5425
|
+
const first = segs[0];
|
|
5426
|
+
const haCloser = plHalf ? plHalf[ptCount - 1] : half;
|
|
5427
|
+
const hbCloser = plHalf ? plHalf[0] : half;
|
|
5428
|
+
const closer = makeSeg(last.bx, last.by, first.ax, first.ay, haCloser, hbCloser);
|
|
5429
|
+
if (closer) {
|
|
5430
|
+
segs.push(closer);
|
|
5431
|
+
closerSrcIdx = ptCount - 1;
|
|
5432
|
+
segSrcIdx.push(closerSrcIdx);
|
|
5433
|
+
}
|
|
5434
|
+
}
|
|
5435
|
+
if (segs.length === 0) return;
|
|
5436
|
+
const segBaseIdx = [];
|
|
5437
|
+
for (let s = 0; s < segs.length; s++) {
|
|
5438
|
+
const seg = segs[s];
|
|
5439
|
+
const startSrc = segSrcIdx[s];
|
|
5440
|
+
const endSrc = s === segs.length - 1 && pl.closed && closerSrcIdx >= 0 ? 0 : startSrc + 1;
|
|
5441
|
+
const base = verts.length / 2;
|
|
5442
|
+
segBaseIdx.push(base);
|
|
5443
|
+
const nxA = seg.nxUnit * seg.halfA, nyA = seg.nyUnit * seg.halfA;
|
|
5444
|
+
const nxB = seg.nxUnit * seg.halfB, nyB = seg.nyUnit * seg.halfB;
|
|
5445
|
+
verts.push(seg.ax + nxA, seg.ay + nyA);
|
|
5446
|
+
anchorA.push(plA[startSrc]);
|
|
5447
|
+
anchorB.push(plB[startSrc]);
|
|
5448
|
+
anchorT.push(plT[startSrc]);
|
|
5449
|
+
verts.push(seg.ax - nxA, seg.ay - nyA);
|
|
5450
|
+
anchorA.push(plA[startSrc]);
|
|
5451
|
+
anchorB.push(plB[startSrc]);
|
|
5452
|
+
anchorT.push(plT[startSrc]);
|
|
5453
|
+
verts.push(seg.bx + nxB, seg.by + nyB);
|
|
5454
|
+
anchorA.push(plA[endSrc]);
|
|
5455
|
+
anchorB.push(plB[endSrc]);
|
|
5456
|
+
anchorT.push(plT[endSrc]);
|
|
5457
|
+
verts.push(seg.bx - nxB, seg.by - nyB);
|
|
5458
|
+
anchorA.push(plA[endSrc]);
|
|
5459
|
+
anchorB.push(plB[endSrc]);
|
|
5460
|
+
anchorT.push(plT[endSrc]);
|
|
5461
|
+
idx.push(base, base + 1, base + 2, base + 1, base + 3, base + 2);
|
|
5462
|
+
}
|
|
5463
|
+
const joinCount = pl.closed ? segs.length : segs.length - 1;
|
|
5464
|
+
for (let j = 0; j < joinCount; j++) {
|
|
5465
|
+
emitJoin(segs, segBaseIdx, j, join, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT, segSrcIdx, plA, plB, plT);
|
|
5466
|
+
}
|
|
5467
|
+
if (!pl.closed && cap !== "butt") {
|
|
5468
|
+
const first = segs[0];
|
|
5469
|
+
const firstBase = segBaseIdx[0];
|
|
5470
|
+
emitCap(first, firstBase + 0, firstBase + 1, false, first.halfA, cap, verts, idx, anchorA, anchorB, anchorT, plA[0], plB[0], plT[0]);
|
|
5471
|
+
const last = segs[segs.length - 1];
|
|
5472
|
+
const lastBase = segBaseIdx[segs.length - 1];
|
|
5473
|
+
const lastSrc = segSrcIdx[segs.length - 1] + 1;
|
|
5474
|
+
emitCap(last, lastBase + 2, lastBase + 3, true, last.halfB, cap, verts, idx, anchorA, anchorB, anchorT, plA[lastSrc], plB[lastSrc], plT[lastSrc]);
|
|
5853
5475
|
}
|
|
5854
|
-
const key = variantKey2(runs, opts);
|
|
5855
|
-
const hit = entry.byVariant.get(key);
|
|
5856
|
-
if (hit !== void 0) return hit;
|
|
5857
|
-
const laid = layoutRuns(runs, opts);
|
|
5858
|
-
if (entry.byVariant.size >= LAYOUT_CACHE_VARIANT_LIMIT) entry.byVariant.clear();
|
|
5859
|
-
entry.byVariant.set(key, laid);
|
|
5860
|
-
return laid;
|
|
5861
|
-
}
|
|
5862
|
-
function verticalAlignOffset(align, boxHeight, textHeight) {
|
|
5863
|
-
if (align === void 0 || align === "top" || boxHeight === void 0) return 0;
|
|
5864
|
-
const slack = boxHeight - textHeight;
|
|
5865
|
-
return align === "center" ? slack / 2 : slack;
|
|
5866
5476
|
}
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5477
|
+
function populatePolylineWidths(pl, vertexWidths, fallbackWidth) {
|
|
5478
|
+
const ptCount = pl.points.length / 2;
|
|
5479
|
+
if (ptCount === 0) return;
|
|
5480
|
+
const aA = pl.anchorA ?? new Uint32Array(ptCount);
|
|
5481
|
+
const aB = pl.anchorB ?? new Uint32Array(ptCount);
|
|
5482
|
+
const aT = pl.anchorT ?? new Float32Array(ptCount);
|
|
5483
|
+
const widths = new Float32Array(ptCount);
|
|
5484
|
+
const read2 = (i) => {
|
|
5485
|
+
const v = vertexWidths[i];
|
|
5486
|
+
return typeof v === "number" && isFinite(v) && v > 0 ? v : fallbackWidth;
|
|
5487
|
+
};
|
|
5488
|
+
for (let i = 0; i < ptCount; i++) {
|
|
5489
|
+
const a = aA[i], b = aB[i], t = aT[i];
|
|
5490
|
+
if (a === b) {
|
|
5491
|
+
widths[i] = read2(a);
|
|
5879
5492
|
} else {
|
|
5880
|
-
|
|
5493
|
+
const wa = read2(a);
|
|
5494
|
+
const wb = read2(b);
|
|
5495
|
+
widths[i] = wa + (wb - wa) * t;
|
|
5881
5496
|
}
|
|
5882
5497
|
}
|
|
5883
|
-
|
|
5498
|
+
pl.widths = widths;
|
|
5884
5499
|
}
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5500
|
+
var ROUND_CAP_STEP_RAD = 10 * Math.PI / 180;
|
|
5501
|
+
function emitCap(seg, leftIdx, rightIdx, atEnd, half, cap, verts, idx, anchorA, anchorB, anchorT, endA, endB, endT) {
|
|
5502
|
+
const sign2 = atEnd ? 1 : -1;
|
|
5503
|
+
const dx = (seg.bx - seg.ax) / seg.len * sign2;
|
|
5504
|
+
const dy = (seg.by - seg.ay) / seg.len * sign2;
|
|
5505
|
+
const cx = atEnd ? seg.bx : seg.ax;
|
|
5506
|
+
const cy = atEnd ? seg.by : seg.ay;
|
|
5507
|
+
const nx = seg.nxUnit * half;
|
|
5508
|
+
const ny = seg.nyUnit * half;
|
|
5509
|
+
if (cap === "square") {
|
|
5510
|
+
const ox = cx + dx * half;
|
|
5511
|
+
const oy = cy + dy * half;
|
|
5512
|
+
const lOut = verts.length / 2;
|
|
5513
|
+
verts.push(ox + nx, oy + ny);
|
|
5514
|
+
anchorA.push(endA);
|
|
5515
|
+
anchorB.push(endB);
|
|
5516
|
+
anchorT.push(endT);
|
|
5517
|
+
const rOut = verts.length / 2;
|
|
5518
|
+
verts.push(ox - nx, oy - ny);
|
|
5519
|
+
anchorA.push(endA);
|
|
5520
|
+
anchorB.push(endB);
|
|
5521
|
+
anchorT.push(endT);
|
|
5522
|
+
if (atEnd) {
|
|
5523
|
+
idx.push(leftIdx, lOut, rOut, leftIdx, rOut, rightIdx);
|
|
5524
|
+
} else {
|
|
5525
|
+
idx.push(leftIdx, rOut, lOut, leftIdx, rightIdx, rOut);
|
|
5526
|
+
}
|
|
5527
|
+
return;
|
|
5892
5528
|
}
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
lastQuadCtrl: null
|
|
5917
|
-
};
|
|
5918
|
-
for (const { cmd, args } of tokens) {
|
|
5919
|
-
const upper = cmd.toUpperCase();
|
|
5920
|
-
const relative = cmd !== upper;
|
|
5921
|
-
const argCount = ARG_COUNTS[upper];
|
|
5922
|
-
if (argCount === void 0) {
|
|
5923
|
-
continue;
|
|
5529
|
+
if (cap === "round") {
|
|
5530
|
+
const pivotIdx = verts.length / 2;
|
|
5531
|
+
verts.push(cx, cy);
|
|
5532
|
+
anchorA.push(endA);
|
|
5533
|
+
anchorB.push(endB);
|
|
5534
|
+
anchorT.push(endT);
|
|
5535
|
+
const startAngle = Math.atan2(ny, nx);
|
|
5536
|
+
const sweep = atEnd ? -Math.PI : Math.PI;
|
|
5537
|
+
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_CAP_STEP_RAD));
|
|
5538
|
+
const stepAngle = sweep / steps;
|
|
5539
|
+
let prevIdx = leftIdx;
|
|
5540
|
+
for (let i = 1; i < steps; i++) {
|
|
5541
|
+
const ang = startAngle + i * stepAngle;
|
|
5542
|
+
const fx = cx + Math.cos(ang) * half;
|
|
5543
|
+
const fy = cy + Math.sin(ang) * half;
|
|
5544
|
+
const newIdx = verts.length / 2;
|
|
5545
|
+
verts.push(fx, fy);
|
|
5546
|
+
anchorA.push(endA);
|
|
5547
|
+
anchorB.push(endB);
|
|
5548
|
+
anchorT.push(endT);
|
|
5549
|
+
if (atEnd) idx.push(prevIdx, newIdx, pivotIdx);
|
|
5550
|
+
else idx.push(prevIdx, pivotIdx, newIdx);
|
|
5551
|
+
prevIdx = newIdx;
|
|
5924
5552
|
}
|
|
5925
|
-
if (
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5553
|
+
if (atEnd) idx.push(prevIdx, rightIdx, pivotIdx);
|
|
5554
|
+
else idx.push(prevIdx, pivotIdx, rightIdx);
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
function splitForDash(pl, dash) {
|
|
5558
|
+
const out = [];
|
|
5559
|
+
const plA = pl.anchorA ?? new Uint32Array(pl.points.length / 2);
|
|
5560
|
+
const plB = pl.anchorB ?? new Uint32Array(pl.points.length / 2);
|
|
5561
|
+
const plT = pl.anchorT ?? new Float32Array(pl.points.length / 2);
|
|
5562
|
+
let dashIdx = 0;
|
|
5563
|
+
let dashRemaining = dash[0];
|
|
5564
|
+
let onPhase = true;
|
|
5565
|
+
let curPts = onPhase ? [pl.points[0], pl.points[1]] : null;
|
|
5566
|
+
let curA = onPhase ? [plA[0]] : null;
|
|
5567
|
+
let curB = onPhase ? [plB[0]] : null;
|
|
5568
|
+
let curT = onPhase ? [plT[0]] : null;
|
|
5569
|
+
const flushAndAdvance = () => {
|
|
5570
|
+
if (curPts && curPts.length >= 4) {
|
|
5571
|
+
out.push({
|
|
5572
|
+
points: curPts,
|
|
5573
|
+
closed: false,
|
|
5574
|
+
anchorA: new Uint32Array(curA),
|
|
5575
|
+
anchorB: new Uint32Array(curB),
|
|
5576
|
+
anchorT: new Float32Array(curT)
|
|
5577
|
+
});
|
|
5932
5578
|
}
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5579
|
+
curPts = null;
|
|
5580
|
+
curA = null;
|
|
5581
|
+
curB = null;
|
|
5582
|
+
curT = null;
|
|
5583
|
+
dashIdx = (dashIdx + 1) % dash.length;
|
|
5584
|
+
dashRemaining = dash[dashIdx];
|
|
5585
|
+
onPhase = !onPhase;
|
|
5586
|
+
};
|
|
5587
|
+
let prevX = pl.points[0], prevY = pl.points[1];
|
|
5588
|
+
const ptCount = pl.points.length / 2;
|
|
5589
|
+
const segCount = pl.closed ? ptCount : ptCount - 1;
|
|
5590
|
+
for (let i = 0; i < segCount; i++) {
|
|
5591
|
+
const nextIdx = (i + 1) % ptCount;
|
|
5592
|
+
const cx = pl.points[nextIdx * 2], cy = pl.points[nextIdx * 2 + 1];
|
|
5593
|
+
const startA = plA[i], startB = plB[i], startT = plT[i];
|
|
5594
|
+
const endA = plA[nextIdx], endB = plB[nextIdx], endT = plT[nextIdx];
|
|
5595
|
+
const segFullDx = cx - prevX, segFullDy = cy - prevY;
|
|
5596
|
+
const segFullLen = Math.hypot(segFullDx, segFullDy);
|
|
5597
|
+
let segDx = segFullDx, segDy = segFullDy;
|
|
5598
|
+
let segLen = segFullLen;
|
|
5599
|
+
let traveled = 0;
|
|
5600
|
+
while (segLen > 1e-9) {
|
|
5601
|
+
if (segLen <= dashRemaining) {
|
|
5602
|
+
if (onPhase && curPts) {
|
|
5603
|
+
curPts.push(cx, cy);
|
|
5604
|
+
curA.push(endA);
|
|
5605
|
+
curB.push(endB);
|
|
5606
|
+
curT.push(endT);
|
|
5607
|
+
}
|
|
5608
|
+
dashRemaining -= segLen;
|
|
5609
|
+
prevX = cx;
|
|
5610
|
+
prevY = cy;
|
|
5611
|
+
traveled = segFullLen;
|
|
5612
|
+
segLen = 0;
|
|
5613
|
+
if (dashRemaining <= 1e-9) {
|
|
5614
|
+
flushAndAdvance();
|
|
5615
|
+
if (onPhase) {
|
|
5616
|
+
curPts = [prevX, prevY];
|
|
5617
|
+
curA = [endA];
|
|
5618
|
+
curB = [endB];
|
|
5619
|
+
curT = [endT];
|
|
5620
|
+
}
|
|
5621
|
+
}
|
|
5622
|
+
} else {
|
|
5623
|
+
const tConsume = dashRemaining / segLen;
|
|
5624
|
+
const ix = prevX + segDx * tConsume;
|
|
5625
|
+
const iy = prevY + segDy * tConsume;
|
|
5626
|
+
traveled += dashRemaining;
|
|
5627
|
+
const frac = traveled / segFullLen;
|
|
5628
|
+
let mA, mB, mT;
|
|
5629
|
+
if (startA === endA && startB === endB) {
|
|
5630
|
+
mA = startA;
|
|
5631
|
+
mB = startB;
|
|
5632
|
+
mT = startT + (endT - startT) * frac;
|
|
5633
|
+
} else {
|
|
5634
|
+
if (frac < 0.5) {
|
|
5635
|
+
mA = startA;
|
|
5636
|
+
mB = startB;
|
|
5637
|
+
mT = startT;
|
|
5638
|
+
} else {
|
|
5639
|
+
mA = endA;
|
|
5640
|
+
mB = endB;
|
|
5641
|
+
mT = endT;
|
|
5642
|
+
}
|
|
5643
|
+
}
|
|
5644
|
+
if (onPhase && curPts) {
|
|
5645
|
+
curPts.push(ix, iy);
|
|
5646
|
+
curA.push(mA);
|
|
5647
|
+
curB.push(mB);
|
|
5648
|
+
curT.push(mT);
|
|
5649
|
+
}
|
|
5650
|
+
prevX = ix;
|
|
5651
|
+
prevY = iy;
|
|
5652
|
+
segDx = cx - prevX;
|
|
5653
|
+
segDy = cy - prevY;
|
|
5654
|
+
segLen = Math.hypot(segDx, segDy);
|
|
5655
|
+
flushAndAdvance();
|
|
5656
|
+
if (onPhase) {
|
|
5657
|
+
curPts = [prevX, prevY];
|
|
5658
|
+
curA = [mA];
|
|
5659
|
+
curB = [mB];
|
|
5660
|
+
curT = [mT];
|
|
5661
|
+
}
|
|
5662
|
+
}
|
|
5938
5663
|
}
|
|
5939
5664
|
}
|
|
5940
|
-
|
|
5665
|
+
if (curPts && curPts.length >= 4) {
|
|
5666
|
+
out.push({
|
|
5667
|
+
points: curPts,
|
|
5668
|
+
closed: false,
|
|
5669
|
+
anchorA: new Uint32Array(curA),
|
|
5670
|
+
anchorB: new Uint32Array(curB),
|
|
5671
|
+
anchorT: new Float32Array(curT)
|
|
5672
|
+
});
|
|
5673
|
+
}
|
|
5674
|
+
return out;
|
|
5941
5675
|
}
|
|
5942
|
-
function
|
|
5943
|
-
const
|
|
5944
|
-
const
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
st.lastCubicCtrl = { x: x2, y: y2 };
|
|
5992
|
-
st.lastQuadCtrl = null;
|
|
5993
|
-
return;
|
|
5994
|
-
}
|
|
5995
|
-
case "S": {
|
|
5996
|
-
const ref = st.lastCubicCtrl ?? { x: st.x, y: st.y };
|
|
5997
|
-
const x1 = 2 * st.x - ref.x;
|
|
5998
|
-
const y1 = 2 * st.y - ref.y;
|
|
5999
|
-
const x2 = a[0] + rx, y2 = a[1] + ry;
|
|
6000
|
-
const x = a[2] + rx, y = a[3] + ry;
|
|
6001
|
-
b.curveTo(x1, y1, x2, y2, x, y);
|
|
6002
|
-
st.x = x;
|
|
6003
|
-
st.y = y;
|
|
6004
|
-
st.lastCubicCtrl = { x: x2, y: y2 };
|
|
6005
|
-
st.lastQuadCtrl = null;
|
|
6006
|
-
return;
|
|
6007
|
-
}
|
|
6008
|
-
case "Q": {
|
|
6009
|
-
const x1 = a[0] + rx, y1 = a[1] + ry;
|
|
6010
|
-
const x = a[2] + rx, y = a[3] + ry;
|
|
6011
|
-
b.quadTo(x1, y1, x, y);
|
|
6012
|
-
st.x = x;
|
|
6013
|
-
st.y = y;
|
|
6014
|
-
st.lastQuadCtrl = { x: x1, y: y1 };
|
|
6015
|
-
st.lastCubicCtrl = null;
|
|
6016
|
-
return;
|
|
6017
|
-
}
|
|
6018
|
-
case "T": {
|
|
6019
|
-
const ref = st.lastQuadCtrl ?? { x: st.x, y: st.y };
|
|
6020
|
-
const x1 = 2 * st.x - ref.x;
|
|
6021
|
-
const y1 = 2 * st.y - ref.y;
|
|
6022
|
-
const x = a[0] + rx, y = a[1] + ry;
|
|
6023
|
-
b.quadTo(x1, y1, x, y);
|
|
6024
|
-
st.x = x;
|
|
6025
|
-
st.y = y;
|
|
6026
|
-
st.lastQuadCtrl = { x: x1, y: y1 };
|
|
6027
|
-
st.lastCubicCtrl = null;
|
|
5676
|
+
function makeSeg(ax, ay, bx, by, halfA, halfB) {
|
|
5677
|
+
const dx = bx - ax, dy = by - ay;
|
|
5678
|
+
const len = Math.hypot(dx, dy);
|
|
5679
|
+
if (len === 0) return null;
|
|
5680
|
+
return {
|
|
5681
|
+
ax,
|
|
5682
|
+
ay,
|
|
5683
|
+
bx,
|
|
5684
|
+
by,
|
|
5685
|
+
nxUnit: -dy / len,
|
|
5686
|
+
nyUnit: dx / len,
|
|
5687
|
+
halfA,
|
|
5688
|
+
halfB,
|
|
5689
|
+
len
|
|
5690
|
+
};
|
|
5691
|
+
}
|
|
5692
|
+
var DEFAULT_MITER_LIMIT = 10;
|
|
5693
|
+
var DEFAULT_VARYING_WIDTH_JOIN_THRESHOLD = 1.5;
|
|
5694
|
+
function emitJoin(segs, segBaseIdx, j, join, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT, segSrcIdx, plA, plB, plT) {
|
|
5695
|
+
const a = segs[j];
|
|
5696
|
+
const b = segs[(j + 1) % segs.length];
|
|
5697
|
+
const aBase = segBaseIdx[j];
|
|
5698
|
+
const bBase = segBaseIdx[(j + 1) % segs.length];
|
|
5699
|
+
const adx = a.bx - a.ax, ady = a.by - a.ay;
|
|
5700
|
+
const bdx = b.bx - b.ax, bdy = b.by - b.ay;
|
|
5701
|
+
const cross = adx * bdy - ady * bdx;
|
|
5702
|
+
if (cross === 0) return;
|
|
5703
|
+
const onPositive = cross > 0;
|
|
5704
|
+
const aOuterEnd = onPositive ? aBase + 3 : aBase + 2;
|
|
5705
|
+
const bOuterStart = onPositive ? bBase + 1 : bBase + 0;
|
|
5706
|
+
const nextSeg = (j + 1) % segs.length;
|
|
5707
|
+
const cornerSrc = segSrcIdx[nextSeg];
|
|
5708
|
+
const cornerA = plA[cornerSrc];
|
|
5709
|
+
const cornerB = plB[cornerSrc];
|
|
5710
|
+
const cornerT = plT[cornerSrc];
|
|
5711
|
+
const halfAtCorner = a.halfB;
|
|
5712
|
+
const taperA = Math.max(a.halfA, a.halfB) / Math.max(1e-9, Math.min(a.halfA, a.halfB));
|
|
5713
|
+
const taperB = Math.max(b.halfA, b.halfB) / Math.max(1e-9, Math.min(b.halfA, b.halfB));
|
|
5714
|
+
const forceBevelForVarying = taperA > varyingThreshold || taperB > varyingThreshold;
|
|
5715
|
+
if (join === "bevel" || forceBevelForVarying) {
|
|
5716
|
+
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
5717
|
+
return;
|
|
5718
|
+
}
|
|
5719
|
+
if (join === "miter") {
|
|
5720
|
+
const aOX = verts[aOuterEnd * 2], aOY = verts[aOuterEnd * 2 + 1];
|
|
5721
|
+
const bOX = verts[bOuterStart * 2], bOY = verts[bOuterStart * 2 + 1];
|
|
5722
|
+
const apex = lineLineIntersect(aOX, aOY, adx, ady, bOX, bOY, -bdx, -bdy);
|
|
5723
|
+
if (!apex) {
|
|
5724
|
+
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
6028
5725
|
return;
|
|
6029
5726
|
}
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
const xRot = a[2];
|
|
6034
|
-
const largeArc = a[3] !== 0;
|
|
6035
|
-
const sweep = a[4] !== 0;
|
|
6036
|
-
const ex = a[5] + rx;
|
|
6037
|
-
const ey = a[6] + ry;
|
|
6038
|
-
arcToCubics(st.x, st.y, ex, ey, rxA, ryA, xRot, largeArc, sweep, b);
|
|
6039
|
-
st.x = ex;
|
|
6040
|
-
st.y = ey;
|
|
6041
|
-
st.lastCubicCtrl = null;
|
|
6042
|
-
st.lastQuadCtrl = null;
|
|
5727
|
+
const miterLen = Math.hypot(apex[0] - a.bx, apex[1] - a.by);
|
|
5728
|
+
if (miterLen > miterLimit * halfAtCorner) {
|
|
5729
|
+
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
6043
5730
|
return;
|
|
6044
5731
|
}
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
let rxFixed = rx;
|
|
6068
|
-
let ryFixed = ry;
|
|
6069
|
-
if (lambda > 1) {
|
|
6070
|
-
const sqrtLambda = Math.sqrt(lambda);
|
|
6071
|
-
rxFixed = sqrtLambda * rx;
|
|
6072
|
-
ryFixed = sqrtLambda * ry;
|
|
6073
|
-
rxs = rxFixed * rxFixed;
|
|
6074
|
-
rys = ryFixed * ryFixed;
|
|
6075
|
-
}
|
|
6076
|
-
const sign2 = largeArc === sweep ? -1 : 1;
|
|
6077
|
-
const num = rxs * rys - rxs * y1ps - rys * x1ps;
|
|
6078
|
-
const den = rxs * y1ps + rys * x1ps;
|
|
6079
|
-
const factor = sign2 * Math.sqrt(Math.max(0, num / den));
|
|
6080
|
-
const cxp = factor * (rxFixed * y1p) / ryFixed;
|
|
6081
|
-
const cyp = factor * -(ryFixed * x1p) / rxFixed;
|
|
6082
|
-
const cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2;
|
|
6083
|
-
const cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2;
|
|
6084
|
-
const angle = (ux, uy, vx, vy) => {
|
|
6085
|
-
const dot = ux * vx + uy * vy;
|
|
6086
|
-
const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
|
|
6087
|
-
let a = Math.acos(Math.max(-1, Math.min(1, dot / len)));
|
|
6088
|
-
if (ux * vy - uy * vx < 0) a = -a;
|
|
6089
|
-
return a;
|
|
6090
|
-
};
|
|
6091
|
-
const theta1 = angle(1, 0, (x1p - cxp) / rxFixed, (y1p - cyp) / ryFixed);
|
|
6092
|
-
let dTheta = angle(
|
|
6093
|
-
(x1p - cxp) / rxFixed,
|
|
6094
|
-
(y1p - cyp) / ryFixed,
|
|
6095
|
-
(-x1p - cxp) / rxFixed,
|
|
6096
|
-
(-y1p - cyp) / ryFixed
|
|
6097
|
-
);
|
|
6098
|
-
if (!sweep && dTheta > 0) dTheta -= 2 * Math.PI;
|
|
6099
|
-
else if (sweep && dTheta < 0) dTheta += 2 * Math.PI;
|
|
6100
|
-
const segCount = Math.max(1, Math.ceil(Math.abs(dTheta) / (Math.PI / 2)));
|
|
6101
|
-
const segAngle = dTheta / segCount;
|
|
6102
|
-
const t = 4 / 3 * Math.tan(segAngle / 4);
|
|
6103
|
-
let prevX = x1;
|
|
6104
|
-
let prevY = y1;
|
|
6105
|
-
let prevDx = -Math.sin(theta1) * rxFixed;
|
|
6106
|
-
let prevDy = Math.cos(theta1) * ryFixed;
|
|
6107
|
-
for (let i = 1; i <= segCount; i++) {
|
|
6108
|
-
const theta = theta1 + i * segAngle;
|
|
6109
|
-
const cosT = Math.cos(theta);
|
|
6110
|
-
const sinT = Math.sin(theta);
|
|
6111
|
-
const px = cosPhi * (cosT * rxFixed) - sinPhi * (sinT * ryFixed) + cx;
|
|
6112
|
-
const py = sinPhi * (cosT * rxFixed) + cosPhi * (sinT * ryFixed) + cy;
|
|
6113
|
-
const dxNew = -sinT * rxFixed;
|
|
6114
|
-
const dyNew = cosT * ryFixed;
|
|
6115
|
-
const c1x = prevX + cosPhi * (t * prevDx) - sinPhi * (t * prevDy);
|
|
6116
|
-
const c1y = prevY + sinPhi * (t * prevDx) + cosPhi * (t * prevDy);
|
|
6117
|
-
const c2x = px - cosPhi * (t * dxNew) + sinPhi * (t * dyNew);
|
|
6118
|
-
const c2y = py - sinPhi * (t * dxNew) - cosPhi * (t * dyNew);
|
|
6119
|
-
b.curveTo(c1x, c1y, c2x, c2y, px, py);
|
|
6120
|
-
prevX = px;
|
|
6121
|
-
prevY = py;
|
|
6122
|
-
prevDx = dxNew;
|
|
6123
|
-
prevDy = dyNew;
|
|
5732
|
+
const apexIdx = verts.length / 2;
|
|
5733
|
+
verts.push(apex[0], apex[1]);
|
|
5734
|
+
anchorA.push(cornerA);
|
|
5735
|
+
anchorB.push(cornerB);
|
|
5736
|
+
anchorT.push(cornerT);
|
|
5737
|
+
const jIdx = verts.length / 2;
|
|
5738
|
+
verts.push(a.bx, a.by);
|
|
5739
|
+
anchorA.push(cornerA);
|
|
5740
|
+
anchorB.push(cornerB);
|
|
5741
|
+
anchorT.push(cornerT);
|
|
5742
|
+
if (onPositive) {
|
|
5743
|
+
idx.push(aOuterEnd, apexIdx, bOuterStart);
|
|
5744
|
+
idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
5745
|
+
} else {
|
|
5746
|
+
idx.push(aOuterEnd, bOuterStart, apexIdx);
|
|
5747
|
+
idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
5748
|
+
}
|
|
5749
|
+
return;
|
|
5750
|
+
}
|
|
5751
|
+
if (join === "round") {
|
|
5752
|
+
emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
5753
|
+
return;
|
|
6124
5754
|
}
|
|
6125
5755
|
}
|
|
6126
|
-
var
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
5756
|
+
var ROUND_STEP_RAD = 10 * Math.PI / 180;
|
|
5757
|
+
function emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
5758
|
+
const cx = a.bx, cy = a.by;
|
|
5759
|
+
const pivotIdx = verts.length / 2;
|
|
5760
|
+
verts.push(cx, cy);
|
|
5761
|
+
anchorA.push(cornerA);
|
|
5762
|
+
anchorB.push(cornerB);
|
|
5763
|
+
anchorT.push(cornerT);
|
|
5764
|
+
const startX = verts[aOuterEnd * 2] - cx;
|
|
5765
|
+
const startY = verts[aOuterEnd * 2 + 1] - cy;
|
|
5766
|
+
const endX = verts[bOuterStart * 2] - cx;
|
|
5767
|
+
const endY = verts[bOuterStart * 2 + 1] - cy;
|
|
5768
|
+
const r = Math.hypot(startX, startY);
|
|
5769
|
+
const startAngle = Math.atan2(startY, startX);
|
|
5770
|
+
const endAngle = Math.atan2(endY, endX);
|
|
5771
|
+
let sweep = endAngle - startAngle;
|
|
5772
|
+
if (onPositive && sweep < 0) sweep += 2 * Math.PI;
|
|
5773
|
+
else if (!onPositive && sweep > 0) sweep -= 2 * Math.PI;
|
|
5774
|
+
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_STEP_RAD));
|
|
5775
|
+
const stepAngle = sweep / steps;
|
|
5776
|
+
let prevIdx = aOuterEnd;
|
|
5777
|
+
for (let i = 1; i < steps; i++) {
|
|
5778
|
+
const ang = startAngle + i * stepAngle;
|
|
5779
|
+
const fx = cx + Math.cos(ang) * r;
|
|
5780
|
+
const fy = cy + Math.sin(ang) * r;
|
|
5781
|
+
const newIdx = verts.length / 2;
|
|
5782
|
+
verts.push(fx, fy);
|
|
5783
|
+
anchorA.push(cornerA);
|
|
5784
|
+
anchorB.push(cornerB);
|
|
5785
|
+
anchorT.push(cornerT);
|
|
5786
|
+
if (onPositive) idx.push(prevIdx, pivotIdx, newIdx);
|
|
5787
|
+
else idx.push(prevIdx, newIdx, pivotIdx);
|
|
5788
|
+
prevIdx = newIdx;
|
|
5789
|
+
}
|
|
5790
|
+
if (onPositive) idx.push(prevIdx, pivotIdx, bOuterStart);
|
|
5791
|
+
else idx.push(prevIdx, bOuterStart, pivotIdx);
|
|
5792
|
+
}
|
|
5793
|
+
function emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
5794
|
+
const jIdx = verts.length / 2;
|
|
5795
|
+
verts.push(a.bx, a.by);
|
|
5796
|
+
anchorA.push(cornerA);
|
|
5797
|
+
anchorB.push(cornerB);
|
|
5798
|
+
anchorT.push(cornerT);
|
|
5799
|
+
if (onPositive) idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
5800
|
+
else idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
5801
|
+
}
|
|
5802
|
+
function lineLineIntersect(apx, apy, adx, ady, bpx, bpy, bdx, bdy) {
|
|
5803
|
+
const denom = adx * bdy - ady * bdx;
|
|
5804
|
+
if (Math.abs(denom) < 1e-9) return null;
|
|
5805
|
+
const t = ((bpx - apx) * bdy - (bpy - apy) * bdx) / denom;
|
|
5806
|
+
return [apx + t * adx, apy + t * ady];
|
|
6136
5807
|
}
|
|
6137
5808
|
var OUTLINE_STROKE_MESH_CACHE_LIMIT = 2048;
|
|
6138
5809
|
var WIDTH_QUANTUM = 1 / 1024;
|
|
@@ -6162,6 +5833,36 @@ function outlineStrokeMesh(glyphKey, d, emWidth, stroke) {
|
|
|
6162
5833
|
cache4.set(key, mesh);
|
|
6163
5834
|
return mesh.indices.length === 0 ? null : mesh;
|
|
6164
5835
|
}
|
|
5836
|
+
var STROKE_CONFIGS_PER_PATH = 8;
|
|
5837
|
+
var cache5 = /* @__PURE__ */ new WeakMap();
|
|
5838
|
+
function configKey(stroke, flattenTolerance) {
|
|
5839
|
+
return [
|
|
5840
|
+
stroke.width ?? 1,
|
|
5841
|
+
stroke.cap ?? "butt",
|
|
5842
|
+
stroke.join ?? "miter",
|
|
5843
|
+
stroke.miterLimit ?? "",
|
|
5844
|
+
stroke.align ?? "center",
|
|
5845
|
+
(stroke.dash ?? []).join(","),
|
|
5846
|
+
stroke.varyingWidthJoinThreshold ?? "",
|
|
5847
|
+
flattenTolerance ?? ""
|
|
5848
|
+
].join("|");
|
|
5849
|
+
}
|
|
5850
|
+
function strokeMesh(path, stroke, flattenTolerance) {
|
|
5851
|
+
let byConfig = cache5.get(path);
|
|
5852
|
+
if (byConfig === void 0) {
|
|
5853
|
+
byConfig = /* @__PURE__ */ new Map();
|
|
5854
|
+
cache5.set(path, byConfig);
|
|
5855
|
+
}
|
|
5856
|
+
const key = configKey(stroke, flattenTolerance);
|
|
5857
|
+
const entry = byConfig.get(key);
|
|
5858
|
+
if (entry !== void 0 && entry.vertexWidths === stroke.vertexWidths) {
|
|
5859
|
+
return entry.mesh;
|
|
5860
|
+
}
|
|
5861
|
+
const mesh = tessellateStroke(path, stroke, { flattenTolerance });
|
|
5862
|
+
if (entry === void 0 && byConfig.size >= STROKE_CONFIGS_PER_PATH) byConfig.clear();
|
|
5863
|
+
byConfig.set(key, { mesh, vertexWidths: stroke.vertexWidths });
|
|
5864
|
+
return mesh;
|
|
5865
|
+
}
|
|
6165
5866
|
var MAX_VERTICES_PER_BATCH = 32768;
|
|
6166
5867
|
var FLOATS_PER_VERTEX = 6;
|
|
6167
5868
|
var INITIAL_VERTICES = 256;
|
|
@@ -6563,44 +6264,40 @@ function drawGroup(ctx, cmd) {
|
|
|
6563
6264
|
"weasel: clip nesting depth exceeded (max 7). You can't nest more than 7 levels of clipped containers in a single draw tree. Flatten the hierarchy or compose poses outside the scene graph."
|
|
6564
6265
|
);
|
|
6565
6266
|
}
|
|
6566
|
-
flushSolids(ctx);
|
|
6567
6267
|
pushClip(ctx, cmd.clip, newDepth);
|
|
6568
6268
|
ctx.clipDepth = newDepth;
|
|
6569
6269
|
}
|
|
6570
6270
|
for (const child of cmd.children) dispatch(ctx, child);
|
|
6571
6271
|
if (cmd.clip) {
|
|
6572
|
-
flushSolids(ctx);
|
|
6573
6272
|
popClip(ctx, cmd.clip, ctx.clipDepth - 1);
|
|
6574
6273
|
ctx.clipDepth -= 1;
|
|
6575
6274
|
}
|
|
6576
6275
|
ctx.state.pop();
|
|
6577
6276
|
}
|
|
6578
6277
|
function drawPath(ctx, cmd) {
|
|
6579
|
-
if (
|
|
6580
|
-
if (cmd.fill) {
|
|
6581
|
-
const batchablePaint = (cmd.fill.fill === void 0 || cmd.fill.fill === "solid") && (!cmd.vertexColors || cmd.vertexColors.length === 0);
|
|
6582
|
-
const solid = cmd.fill;
|
|
6583
|
-
if (batchablePaint && cmd.path.kind === "rect") {
|
|
6584
|
-
pushRect(ctx, cmd.path, solid);
|
|
6585
|
-
} else {
|
|
6586
|
-
const mesh = fillMesh(ctx, cmd.path);
|
|
6587
|
-
if (batchablePaint && canBatchMesh(mesh)) {
|
|
6588
|
-
pushMesh(ctx, mesh, solid);
|
|
6589
|
-
} else {
|
|
6590
|
-
flushSolids(ctx);
|
|
6591
|
-
const handle = meshHandle(ctx, mesh);
|
|
6592
|
-
if (cmd.vertexColors && cmd.vertexColors.length > 0 && (cmd.fill.fill === void 0 || cmd.fill.fill === "solid")) {
|
|
6593
|
-
drawPathFillVColor(ctx, cmd, solid, handle);
|
|
6594
|
-
} else if (handle.requiresStencil) {
|
|
6595
|
-
drawPathFillStencil(ctx, cmd.fill, handle);
|
|
6596
|
-
} else {
|
|
6597
|
-
drawPathFillByKind(ctx, cmd.fill, handle);
|
|
6598
|
-
}
|
|
6599
|
-
}
|
|
6600
|
-
}
|
|
6601
|
-
}
|
|
6278
|
+
if (cmd.fill) drawPathFill(ctx, cmd);
|
|
6602
6279
|
if (cmd.stroke) drawPathStroke(ctx, cmd);
|
|
6603
6280
|
}
|
|
6281
|
+
function drawPathFill(ctx, cmd) {
|
|
6282
|
+
const fill = cmd.fill;
|
|
6283
|
+
const isSolid = fill.fill === void 0 || fill.fill === "solid";
|
|
6284
|
+
const hasVColors = !!(cmd.vertexColors && cmd.vertexColors.length > 0);
|
|
6285
|
+
const solid = fill;
|
|
6286
|
+
if (isSolid && !hasVColors && cmd.path.kind === "rect") {
|
|
6287
|
+
pushRect(ctx, cmd.path, solid);
|
|
6288
|
+
return;
|
|
6289
|
+
}
|
|
6290
|
+
const mesh = fillMesh(ctx, cmd.path);
|
|
6291
|
+
if (tryStageSolid(ctx, mesh, isSolid && !hasVColors ? solid : void 0)) return;
|
|
6292
|
+
const handle = meshHandle(ctx, mesh);
|
|
6293
|
+
if (isSolid && hasVColors) {
|
|
6294
|
+
drawPathFillVColor(ctx, cmd, solid, handle);
|
|
6295
|
+
} else if (handle.requiresStencil) {
|
|
6296
|
+
drawPathFillStencil(ctx, fill, handle);
|
|
6297
|
+
} else {
|
|
6298
|
+
drawPathFillByKind(ctx, fill, handle);
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6604
6301
|
function isIdentityColorMatrix(cm) {
|
|
6605
6302
|
return cm === IDENTITY_COLOR_MATRIX || sameValues(IDENTITY_COLOR_MATRIX, cm);
|
|
6606
6303
|
}
|
|
@@ -6653,6 +6350,14 @@ function pushMesh(ctx, mesh, paint) {
|
|
|
6653
6350
|
const [r, g, b, a] = stagedColor(ctx, staged, paint);
|
|
6654
6351
|
ctx.solidBatch.pushMesh(mesh, ctx.state.transform, r, g, b, a);
|
|
6655
6352
|
}
|
|
6353
|
+
function tryStageSolid(ctx, mesh, paint) {
|
|
6354
|
+
if (paint !== void 0 && canBatchMesh(mesh)) {
|
|
6355
|
+
pushMesh(ctx, mesh, paint);
|
|
6356
|
+
return true;
|
|
6357
|
+
}
|
|
6358
|
+
flushSolids(ctx);
|
|
6359
|
+
return false;
|
|
6360
|
+
}
|
|
6656
6361
|
function flushSolids(ctx) {
|
|
6657
6362
|
const batch = ctx.solidBatch;
|
|
6658
6363
|
const staged = ctx.solidState;
|
|
@@ -6856,6 +6561,7 @@ function rasterizePathToStencil(ctx, path) {
|
|
|
6856
6561
|
gl.bindVertexArray(null);
|
|
6857
6562
|
}
|
|
6858
6563
|
function pushClip(ctx, path, newDepth) {
|
|
6564
|
+
flushSolids(ctx);
|
|
6859
6565
|
const gl = ctx.gl;
|
|
6860
6566
|
const ancestors = ancestorMask(newDepth - 1);
|
|
6861
6567
|
const newBit = 1 << newDepth;
|
|
@@ -6870,6 +6576,7 @@ function pushClip(ctx, path, newDepth) {
|
|
|
6870
6576
|
gl.stencilMask(255);
|
|
6871
6577
|
}
|
|
6872
6578
|
function popClip(ctx, path, oldDepth) {
|
|
6579
|
+
flushSolids(ctx);
|
|
6873
6580
|
const gl = ctx.gl;
|
|
6874
6581
|
gl.enable(gl.STENCIL_TEST);
|
|
6875
6582
|
const oldBit = 1 << oldDepth + 1;
|
|
@@ -6926,17 +6633,13 @@ function drawPathStroke(ctx, cmd) {
|
|
|
6926
6633
|
function drawPathStrokeUnclipped(ctx, cmd) {
|
|
6927
6634
|
const stroke = cmd.stroke;
|
|
6928
6635
|
const solid = stroke.paint;
|
|
6929
|
-
const mesh =
|
|
6636
|
+
const mesh = strokeMesh(cmd.path, stroke, ctx.flattenTolerance);
|
|
6930
6637
|
if (mesh.indices.length === 0) return;
|
|
6931
6638
|
const hasVColors = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
6932
|
-
if (
|
|
6933
|
-
|
|
6934
|
-
return;
|
|
6935
|
-
}
|
|
6936
|
-
flushSolids(ctx);
|
|
6937
|
-
const handle = ctx.meshCache.uploadTransient(mesh);
|
|
6639
|
+
if (tryStageSolid(ctx, mesh, hasVColors ? void 0 : solid)) return;
|
|
6640
|
+
const handle = hasVColors ? ctx.meshCache.uploadTransient(mesh) : ctx.meshCache.uploadRecurring(mesh);
|
|
6938
6641
|
const gl = ctx.gl;
|
|
6939
|
-
if (
|
|
6642
|
+
if (hasVColors) {
|
|
6940
6643
|
const prog = ctx.pathFillVColor;
|
|
6941
6644
|
gl.useProgram(prog.handle);
|
|
6942
6645
|
gl.bindVertexArray(handle.vao);
|
|
@@ -6967,16 +6670,30 @@ function drawPathStrokeUnclipped(ctx, cmd) {
|
|
|
6967
6670
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
6968
6671
|
gl.bindVertexArray(null);
|
|
6969
6672
|
}
|
|
6673
|
+
var DOUBLED_VERTEX_WIDTHS = /* @__PURE__ */ new WeakMap();
|
|
6674
|
+
function doubledVertexWidths(widths) {
|
|
6675
|
+
let doubled = DOUBLED_VERTEX_WIDTHS.get(widths);
|
|
6676
|
+
if (doubled === void 0) {
|
|
6677
|
+
doubled = widths.map((w) => w * 2);
|
|
6678
|
+
DOUBLED_VERTEX_WIDTHS.set(widths, doubled);
|
|
6679
|
+
}
|
|
6680
|
+
return doubled;
|
|
6681
|
+
}
|
|
6970
6682
|
function drawPathStrokeStenciled(ctx, cmd, align) {
|
|
6971
6683
|
const stroke = cmd.stroke;
|
|
6972
6684
|
const solid = stroke.paint;
|
|
6973
|
-
const widerStroke = {
|
|
6685
|
+
const widerStroke = {
|
|
6686
|
+
...stroke,
|
|
6687
|
+
width: (stroke.width ?? 1) * 2,
|
|
6688
|
+
...stroke.vertexWidths ? { vertexWidths: doubledVertexWidths(stroke.vertexWidths) } : {},
|
|
6689
|
+
align: "center"
|
|
6690
|
+
};
|
|
6691
|
+
const useVColor = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
6974
6692
|
const fillHandle = fillMeshHandle(ctx, cmd.path);
|
|
6975
|
-
const ribbonMesh =
|
|
6693
|
+
const ribbonMesh = strokeMesh(cmd.path, widerStroke, ctx.flattenTolerance);
|
|
6976
6694
|
if (ribbonMesh.indices.length === 0) return;
|
|
6977
|
-
const ribbonHandle = ctx.meshCache.uploadTransient(ribbonMesh);
|
|
6695
|
+
const ribbonHandle = useVColor ? ctx.meshCache.uploadTransient(ribbonMesh) : ctx.meshCache.uploadRecurring(ribbonMesh);
|
|
6978
6696
|
const gl = ctx.gl;
|
|
6979
|
-
const useVColor = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
6980
6697
|
const prog = useVColor ? ctx.pathFillVColor : ctx.pathFill;
|
|
6981
6698
|
gl.useProgram(prog.handle);
|
|
6982
6699
|
setProjAndModel(ctx, prog);
|
|
@@ -7012,11 +6729,11 @@ function drawPathStrokeStenciled(ctx, cmd, align) {
|
|
|
7012
6729
|
}
|
|
7013
6730
|
}
|
|
7014
6731
|
gl.drawElements(gl.TRIANGLES, ribbonHandle.indexCount, gl.UNSIGNED_INT, 0);
|
|
7015
|
-
if (colorVbo) gl.deleteBuffer(colorVbo);
|
|
7016
6732
|
gl.stencilMask(1);
|
|
7017
6733
|
gl.clear(gl.STENCIL_BUFFER_BIT);
|
|
7018
6734
|
gl.disable(gl.STENCIL_TEST);
|
|
7019
6735
|
gl.bindVertexArray(null);
|
|
6736
|
+
if (colorVbo) gl.deleteBuffer(colorVbo);
|
|
7020
6737
|
}
|
|
7021
6738
|
var OUTLINE_MIN_SCREEN_PX = 48;
|
|
7022
6739
|
function modelScale(m) {
|
|
@@ -7065,9 +6782,9 @@ function drawTextOutlineGroup(ctx, group, dx, dy) {
|
|
|
7065
6782
|
const mesh = outlineGroupMesh(group, dx, dy);
|
|
7066
6783
|
if (mesh) drawPathFillByKind(ctx, group.fill, ctx.meshCache.uploadTransient(mesh));
|
|
7067
6784
|
if (!group.stroke) return;
|
|
7068
|
-
const
|
|
7069
|
-
if (
|
|
7070
|
-
drawPathFillByKind(ctx, group.stroke.paint, ctx.meshCache.uploadTransient(
|
|
6785
|
+
const ribbon = outlineGroupStrokeMesh(group, dx, dy);
|
|
6786
|
+
if (ribbon) {
|
|
6787
|
+
drawPathFillByKind(ctx, group.stroke.paint, ctx.meshCache.uploadTransient(ribbon));
|
|
7071
6788
|
}
|
|
7072
6789
|
}
|
|
7073
6790
|
function outlineGroupMesh(group, dx, dy) {
|
|
@@ -7273,70 +6990,98 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
|
7273
6990
|
gl.deleteBuffer(vbo);
|
|
7274
6991
|
gl.deleteBuffer(ibo);
|
|
7275
6992
|
}
|
|
6993
|
+
var IMAGE_QUAD_RING_SIZE = 64;
|
|
6994
|
+
var IMAGE_QUAD_RINGS = /* @__PURE__ */ new WeakMap();
|
|
6995
|
+
var IMAGE_QUAD_INDICES = new Uint32Array([0, 1, 2, 1, 3, 2]);
|
|
6996
|
+
var IMAGE_QUAD_STRIDE = 16;
|
|
6997
|
+
function imageQuadRing(gl, prog) {
|
|
6998
|
+
const existing = IMAGE_QUAD_RINGS.get(prog);
|
|
6999
|
+
if (existing) return existing;
|
|
7000
|
+
const aPosLoc = prog.attribute("a_position");
|
|
7001
|
+
const aUvLoc = prog.attribute("a_uv");
|
|
7002
|
+
const ibo = gl.createBuffer();
|
|
7003
|
+
if (!ibo) throw new Error("drawImage: createBuffer (IBO) returned null");
|
|
7004
|
+
const vaos = [];
|
|
7005
|
+
const vbos = [];
|
|
7006
|
+
for (let slot = 0; slot < IMAGE_QUAD_RING_SIZE; slot++) {
|
|
7007
|
+
const vao = gl.createVertexArray();
|
|
7008
|
+
const vbo = gl.createBuffer();
|
|
7009
|
+
if (!vao) throw new Error("drawImage: createVertexArray returned null");
|
|
7010
|
+
if (!vbo) throw new Error("drawImage: createBuffer returned null");
|
|
7011
|
+
gl.bindVertexArray(vao);
|
|
7012
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
7013
|
+
gl.bufferData(gl.ARRAY_BUFFER, 4 * IMAGE_QUAD_STRIDE, gl.DYNAMIC_DRAW);
|
|
7014
|
+
if (aPosLoc !== void 0) {
|
|
7015
|
+
gl.enableVertexAttribArray(aPosLoc);
|
|
7016
|
+
gl.vertexAttribPointer(aPosLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 0);
|
|
7017
|
+
}
|
|
7018
|
+
if (aUvLoc !== void 0) {
|
|
7019
|
+
gl.enableVertexAttribArray(aUvLoc);
|
|
7020
|
+
gl.vertexAttribPointer(aUvLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 8);
|
|
7021
|
+
}
|
|
7022
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
7023
|
+
if (slot === 0) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, IMAGE_QUAD_INDICES, gl.STATIC_DRAW);
|
|
7024
|
+
gl.bindVertexArray(null);
|
|
7025
|
+
vaos.push(vao);
|
|
7026
|
+
vbos.push(vbo);
|
|
7027
|
+
}
|
|
7028
|
+
const ring = { vaos, vbos, ibo, next: 0 };
|
|
7029
|
+
IMAGE_QUAD_RINGS.set(prog, ring);
|
|
7030
|
+
return ring;
|
|
7031
|
+
}
|
|
7032
|
+
function disposeImageQuads(gl, prog) {
|
|
7033
|
+
const ring = IMAGE_QUAD_RINGS.get(prog);
|
|
7034
|
+
if (!ring) return;
|
|
7035
|
+
for (const vao of ring.vaos) gl.deleteVertexArray(vao);
|
|
7036
|
+
for (const vbo of ring.vbos) gl.deleteBuffer(vbo);
|
|
7037
|
+
gl.deleteBuffer(ring.ibo);
|
|
7038
|
+
IMAGE_QUAD_RINGS.delete(prog);
|
|
7039
|
+
}
|
|
7040
|
+
var IMAGE_QUAD_VERTICES = new Float32Array(16);
|
|
7276
7041
|
function drawImage(ctx, cmd) {
|
|
7277
7042
|
ctx.imageCache.upload(cmd.image, cmd.image);
|
|
7278
7043
|
const gl = ctx.gl;
|
|
7279
|
-
|
|
7044
|
+
const prog = ctx.imageFill;
|
|
7045
|
+
gl.useProgram(prog.handle);
|
|
7280
7046
|
const x0 = cmd.x, y0 = cmd.y;
|
|
7281
7047
|
const x1 = cmd.x + cmd.w, y1 = cmd.y + cmd.h;
|
|
7282
|
-
const
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
const
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
gl.
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);
|
|
7308
|
-
const stride = 16;
|
|
7309
|
-
const aPosLoc = ctx.imageFill.attribute("a_position");
|
|
7310
|
-
const aUvLoc = ctx.imageFill.attribute("a_uv");
|
|
7311
|
-
if (aPosLoc !== void 0) {
|
|
7312
|
-
gl.enableVertexAttribArray(aPosLoc);
|
|
7313
|
-
gl.vertexAttribPointer(aPosLoc, 2, gl.FLOAT, false, stride, 0);
|
|
7314
|
-
}
|
|
7315
|
-
if (aUvLoc !== void 0) {
|
|
7316
|
-
gl.enableVertexAttribArray(aUvLoc);
|
|
7317
|
-
gl.vertexAttribPointer(aUvLoc, 2, gl.FLOAT, false, stride, 8);
|
|
7318
|
-
}
|
|
7319
|
-
const ibo = gl.createBuffer();
|
|
7320
|
-
if (!ibo) throw new Error("drawImage: createBuffer (IBO) returned null");
|
|
7321
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
7322
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.DYNAMIC_DRAW);
|
|
7323
|
-
setProjAndModel(ctx, ctx.imageFill);
|
|
7324
|
-
setColorMatrixUniforms(ctx, ctx.imageFill);
|
|
7048
|
+
const v = IMAGE_QUAD_VERTICES;
|
|
7049
|
+
v[0] = x0;
|
|
7050
|
+
v[1] = y0;
|
|
7051
|
+
v[2] = 0;
|
|
7052
|
+
v[3] = 0;
|
|
7053
|
+
v[4] = x1;
|
|
7054
|
+
v[5] = y0;
|
|
7055
|
+
v[6] = 1;
|
|
7056
|
+
v[7] = 0;
|
|
7057
|
+
v[8] = x0;
|
|
7058
|
+
v[9] = y1;
|
|
7059
|
+
v[10] = 0;
|
|
7060
|
+
v[11] = 1;
|
|
7061
|
+
v[12] = x1;
|
|
7062
|
+
v[13] = y1;
|
|
7063
|
+
v[14] = 1;
|
|
7064
|
+
v[15] = 1;
|
|
7065
|
+
const ring = imageQuadRing(gl, prog);
|
|
7066
|
+
const slot = ring.next;
|
|
7067
|
+
ring.next = (slot + 1) % IMAGE_QUAD_RING_SIZE;
|
|
7068
|
+
gl.bindVertexArray(ring.vaos[slot]);
|
|
7069
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, ring.vbos[slot]);
|
|
7070
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, v);
|
|
7071
|
+
setProjAndModel(ctx, prog);
|
|
7072
|
+
setColorMatrixUniforms(ctx, prog);
|
|
7325
7073
|
ctx.imageCache.bind(cmd.image, 0);
|
|
7326
7074
|
gl.texParameteri(
|
|
7327
7075
|
gl.TEXTURE_2D,
|
|
7328
7076
|
gl.TEXTURE_MAG_FILTER,
|
|
7329
7077
|
cmd.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
7330
7078
|
);
|
|
7331
|
-
gl.uniform1i(
|
|
7332
|
-
gl.uniform1f(
|
|
7333
|
-
gl.uniform1f(
|
|
7079
|
+
gl.uniform1i(prog.uniform("u_sampler"), 0);
|
|
7080
|
+
gl.uniform1f(prog.uniform("u_opacity"), cmd.opacity ?? 1);
|
|
7081
|
+
gl.uniform1f(prog.uniform("u_alpha"), ctx.state.alpha);
|
|
7334
7082
|
applyClipTest(ctx);
|
|
7335
7083
|
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
|
|
7336
7084
|
gl.bindVertexArray(null);
|
|
7337
|
-
gl.deleteVertexArray(vao);
|
|
7338
|
-
gl.deleteBuffer(vbo);
|
|
7339
|
-
gl.deleteBuffer(ibo);
|
|
7340
7085
|
}
|
|
7341
7086
|
var CUSTOM_VERT_SRC = (
|
|
7342
7087
|
/* glsl */
|
|
@@ -7393,16 +7138,28 @@ var registry3 = /* @__PURE__ */ new Map();
|
|
|
7393
7138
|
function getProgramSource(id) {
|
|
7394
7139
|
return registry3.get(id) ?? null;
|
|
7395
7140
|
}
|
|
7141
|
+
var UNIFORM_QUALIFIER = /^(?:lowp|mediump|highp|precise|invariant|centroid|flat|smooth|noperspective)$/;
|
|
7396
7142
|
function extractUniformNames(glsl) {
|
|
7397
|
-
const
|
|
7398
|
-
const reArray = /\buniform\s+\S+\s+(\w+)\s*\[\s*(\d+)\s*\]\s*;/g;
|
|
7143
|
+
const re = /\buniform\s+([^;{]+);/g;
|
|
7399
7144
|
const names = [];
|
|
7400
7145
|
let m;
|
|
7401
|
-
while ((m =
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7146
|
+
while ((m = re.exec(glsl)) !== null) {
|
|
7147
|
+
const words = m[1].trim().split(/\s+/);
|
|
7148
|
+
let i = 0;
|
|
7149
|
+
while (i < words.length && UNIFORM_QUALIFIER.test(words[i])) i++;
|
|
7150
|
+
i++;
|
|
7151
|
+
const declarators = words.slice(i).join(" ");
|
|
7152
|
+
if (!declarators) continue;
|
|
7153
|
+
for (const raw of declarators.split(",")) {
|
|
7154
|
+
const d = raw.trim();
|
|
7155
|
+
const arr = /^(\w+)\s*\[\s*(\d+)\s*\]$/.exec(d);
|
|
7156
|
+
if (arr) {
|
|
7157
|
+
const size = parseInt(arr[2], 10);
|
|
7158
|
+
for (let k = 0; k < size; k++) names.push(`${arr[1]}[${k}]`);
|
|
7159
|
+
} else if (/^\w+$/.test(d)) {
|
|
7160
|
+
names.push(d);
|
|
7161
|
+
}
|
|
7162
|
+
}
|
|
7406
7163
|
}
|
|
7407
7164
|
return names;
|
|
7408
7165
|
}
|
|
@@ -7644,6 +7401,7 @@ var WeaselRenderer = class {
|
|
|
7644
7401
|
this.gradRampCache.free();
|
|
7645
7402
|
if (this.quadVbo) gl.deleteBuffer(this.quadVbo);
|
|
7646
7403
|
if (this.quadIbo) gl.deleteBuffer(this.quadIbo);
|
|
7404
|
+
disposeImageQuads(gl, this.imageFill);
|
|
7647
7405
|
this.solidBatch.dispose();
|
|
7648
7406
|
}
|
|
7649
7407
|
/**
|
|
@@ -8178,6 +7936,12 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
8178
7936
|
if (layout2.contains) return layout2.contains(cPose, draggedCenter);
|
|
8179
7937
|
return draggedCenter.x >= aabb.x && draggedCenter.x < aabb.x + aabb.width && draggedCenter.y >= aabb.y && draggedCenter.y < aabb.y + aabb.height;
|
|
8180
7938
|
};
|
|
7939
|
+
const draggedArg = {
|
|
7940
|
+
id: draggedId,
|
|
7941
|
+
originPose: startWorld,
|
|
7942
|
+
pose: draggedWorld,
|
|
7943
|
+
sourceContainerId
|
|
7944
|
+
};
|
|
8181
7945
|
const consider = (id, zPath) => {
|
|
8182
7946
|
if (id === draggedId) return;
|
|
8183
7947
|
const layout2 = layoutDep.getLayout(id);
|
|
@@ -8187,6 +7951,7 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
8187
7951
|
const worldPose = composeWorldPose(poseAdapter, id, pc.compose);
|
|
8188
7952
|
const worldAABB = boundsOf2(worldPose);
|
|
8189
7953
|
if (!testInside(worldPose, worldAABB, layout2)) return;
|
|
7954
|
+
if (layout2.acceptsDrop && !layout2.acceptsDrop({ id, bounds: worldAABB }, draggedArg)) return;
|
|
8190
7955
|
candidates.push({
|
|
8191
7956
|
id,
|
|
8192
7957
|
bounds: worldAABB,
|
|
@@ -8235,20 +8000,16 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
8235
8000
|
id: cid,
|
|
8236
8001
|
pose: composeWorldPose(poseAdapter, cid, pc.compose)
|
|
8237
8002
|
}));
|
|
8238
|
-
const draggedArg = {
|
|
8239
|
-
id: draggedId,
|
|
8240
|
-
originPose: startWorld,
|
|
8241
|
-
pose: draggedWorld,
|
|
8242
|
-
sourceContainerId
|
|
8243
|
-
};
|
|
8244
8003
|
const targets = layout.getDropTargets(container, children, draggedArg);
|
|
8245
8004
|
const target = layout.snap.pickTarget(targets, { x: moveCtx.drag.current.x, y: moveCtx.drag.current.y });
|
|
8246
8005
|
if (!target) return;
|
|
8006
|
+
const reflowIds = /* @__PURE__ */ new Set();
|
|
8247
8007
|
for (const [cid, pose] of layout.reflowPoses(container, children, draggedArg, target)) {
|
|
8248
8008
|
if (asNodeId(cid) === draggedId) continue;
|
|
8249
8009
|
const parent = scene.get(asNodeId(cid))?.parent ?? null;
|
|
8250
8010
|
const local = rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose);
|
|
8251
8011
|
scratch.previews.set(asNodeId(cid), local);
|
|
8012
|
+
reflowIds.add(asNodeId(cid));
|
|
8252
8013
|
}
|
|
8253
8014
|
const sourceReflow = /* @__PURE__ */ new Map();
|
|
8254
8015
|
if (sourceContainerId && sourceContainerId !== dest.id) {
|
|
@@ -8271,10 +8032,11 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
8271
8032
|
sourceReflow.set(cid, pose);
|
|
8272
8033
|
const parent = scene.get(asNodeId(cid))?.parent ?? null;
|
|
8273
8034
|
scratch.previews.set(asNodeId(cid), rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose));
|
|
8035
|
+
reflowIds.add(asNodeId(cid));
|
|
8274
8036
|
}
|
|
8275
8037
|
}
|
|
8276
8038
|
}
|
|
8277
|
-
scratch.layoutPass = { layout, container, children, target, sourceReflow };
|
|
8039
|
+
scratch.layoutPass = { layout, container, children, target, sourceReflow, reflowIds };
|
|
8278
8040
|
}
|
|
8279
8041
|
function scenePoseAdapter(scene) {
|
|
8280
8042
|
return {
|
|
@@ -8582,7 +8344,8 @@ var moveAction = {
|
|
|
8582
8344
|
scratch.previews.clear();
|
|
8583
8345
|
},
|
|
8584
8346
|
previewIds: () => scratch.previews.keys(),
|
|
8585
|
-
previewPose: (id) => scratch.previews.get(id) ?? null
|
|
8347
|
+
previewPose: (id) => scratch.previews.get(id) ?? null,
|
|
8348
|
+
previewOpaqueIds: () => scratch.layoutPass?.reflowIds ?? null
|
|
8586
8349
|
};
|
|
8587
8350
|
}
|
|
8588
8351
|
},
|
|
@@ -9318,7 +9081,8 @@ var KIT_INSERT_KINDS = /* @__PURE__ */ new Set([
|
|
|
9318
9081
|
"line",
|
|
9319
9082
|
"polygon",
|
|
9320
9083
|
"star",
|
|
9321
|
-
"pencil"
|
|
9084
|
+
"pencil",
|
|
9085
|
+
"image"
|
|
9322
9086
|
]);
|
|
9323
9087
|
var liveInsertScratch = null;
|
|
9324
9088
|
function effectiveOriginMode(paramsOrigin, altHeld) {
|
|
@@ -10366,7 +10130,7 @@ var pinchZoomAction = {
|
|
|
10366
10130
|
const multiTouch = ctx.multiTouch;
|
|
10367
10131
|
if (!multiTouch) return {};
|
|
10368
10132
|
const startSpread = multiTouch.spread > 0 ? multiTouch.spread : 1;
|
|
10369
|
-
const scratch = { view, startSpread };
|
|
10133
|
+
const scratch = { view, startSpread, centroid: multiTouch.centroid };
|
|
10370
10134
|
return {
|
|
10371
10135
|
kind: "pinch",
|
|
10372
10136
|
onMove(moveCtx) {
|
|
@@ -10376,8 +10140,15 @@ var pinchZoomAction = {
|
|
|
10376
10140
|
if (currentSpread <= 0 || scratch.startSpread <= 0) return;
|
|
10377
10141
|
const factor = currentSpread / scratch.startSpread;
|
|
10378
10142
|
scratch.startSpread = currentSpread;
|
|
10143
|
+
const prev = scratch.centroid;
|
|
10144
|
+
scratch.centroid = centroid;
|
|
10379
10145
|
const current = scratch.view.get();
|
|
10380
|
-
|
|
10146
|
+
const zoomed = zoomAt(current, prev, factor);
|
|
10147
|
+
scratch.view.set({
|
|
10148
|
+
scale: zoomed.scale,
|
|
10149
|
+
x: zoomed.x - (centroid.x - prev.x) / zoomed.scale.x,
|
|
10150
|
+
y: zoomed.y - (centroid.y - prev.y) / zoomed.scale.y
|
|
10151
|
+
});
|
|
10381
10152
|
}
|
|
10382
10153
|
// onEnd: nothing to do — zoom was applied each frame.
|
|
10383
10154
|
};
|
|
@@ -10837,10 +10608,12 @@ function normalizeNegativeExtent(pose) {
|
|
|
10837
10608
|
if (!mutated) return pose;
|
|
10838
10609
|
return { ...pose, x: nx, y: ny, width: nw, height: nh };
|
|
10839
10610
|
}
|
|
10840
|
-
function flipSelection(selection, scene, axis, applyOps, geometryProjection) {
|
|
10611
|
+
function flipSelection(selection, scene, axis, pivot, applyOps, geometryProjection) {
|
|
10841
10612
|
const ids = selection.get();
|
|
10842
10613
|
if (ids.length === 0) return;
|
|
10843
10614
|
const geom = AUTO_POSE_DESCRIPTOR;
|
|
10615
|
+
const nodes = ids.map((id) => scene.get(id)).filter((n) => n != null);
|
|
10616
|
+
const unionPivot = pivot === "union" ? unionBounds(nodes.map((n) => geom.getBounds(n.pose))) : null;
|
|
10844
10617
|
const ops = [];
|
|
10845
10618
|
for (const id of ids) {
|
|
10846
10619
|
const node = scene.get(id);
|
|
@@ -10848,10 +10621,10 @@ function flipSelection(selection, scene, axis, applyOps, geometryProjection) {
|
|
|
10848
10621
|
ops.push(createTransformOp({
|
|
10849
10622
|
id,
|
|
10850
10623
|
from: node.pose,
|
|
10851
|
-
to: flipPoseViaDescriptor(node.pose, axis, geom),
|
|
10624
|
+
to: unionPivot ? flipPoseAboutBounds(node.pose, axis, geom, unionPivot) : flipPoseViaDescriptor(node.pose, axis, geom),
|
|
10852
10625
|
label: "Flip"
|
|
10853
10626
|
}));
|
|
10854
|
-
const g = geom.getBounds(node.pose);
|
|
10627
|
+
const g = unionPivot ?? geom.getBounds(node.pose);
|
|
10855
10628
|
const cx = g.x + g.width / 2;
|
|
10856
10629
|
const cy = g.y + g.height / 2;
|
|
10857
10630
|
const m = axis === "x" ? [-1, 0, 0, 1, 2 * cx, 0] : [1, 0, 0, -1, 0, 2 * cy];
|
|
@@ -10880,12 +10653,13 @@ var flipAction = {
|
|
|
10880
10653
|
timing: "immediate",
|
|
10881
10654
|
run: (deps, params) => {
|
|
10882
10655
|
const axis = params?.axis ?? "x";
|
|
10656
|
+
const pivot = params?.pivot ?? "each";
|
|
10883
10657
|
const selection = deps.selection;
|
|
10884
10658
|
const scene = deps.scene;
|
|
10885
10659
|
const applyOps = deps.applyOps;
|
|
10886
10660
|
const geometryProjection = deps.geometryProjection;
|
|
10887
10661
|
if (!selection || !scene) return;
|
|
10888
|
-
flipSelection(selection, scene, axis, applyOps, geometryProjection);
|
|
10662
|
+
flipSelection(selection, scene, axis, pivot, applyOps, geometryProjection);
|
|
10889
10663
|
}
|
|
10890
10664
|
},
|
|
10891
10665
|
enabled: requiresSelection
|
|
@@ -12743,11 +12517,18 @@ var DEFAULT_DEBUG_THEME = {
|
|
|
12743
12517
|
fpsText: "#e0e0e0",
|
|
12744
12518
|
fpsTextBg: "rgba(0, 0, 0, 0.6)"
|
|
12745
12519
|
};
|
|
12520
|
+
var DEFAULT_DEBUG_STROKES = {
|
|
12521
|
+
hitbox: { width: 1, dash: [2, 2] },
|
|
12522
|
+
bounds: { width: 1 },
|
|
12523
|
+
handle: { width: 1 },
|
|
12524
|
+
snap: { width: 1 }
|
|
12525
|
+
};
|
|
12746
12526
|
function createDebugOverlayLayer({
|
|
12747
12527
|
sink,
|
|
12748
12528
|
config
|
|
12749
12529
|
}) {
|
|
12750
12530
|
const theme = { ...DEFAULT_DEBUG_THEME, ...config.theme ?? {} };
|
|
12531
|
+
const strokes = { ...DEFAULT_DEBUG_STROKES, ...config.strokes ?? {} };
|
|
12751
12532
|
const fpsHistory = [];
|
|
12752
12533
|
const FPS_WINDOW = 60;
|
|
12753
12534
|
return {
|
|
@@ -12759,11 +12540,11 @@ function createDebugOverlayLayer({
|
|
|
12759
12540
|
const s = sink.snapshot();
|
|
12760
12541
|
const t = viewToTransform(view);
|
|
12761
12542
|
const out = [];
|
|
12762
|
-
if (config.hitboxes) emitHitboxes(out, s, view, t, theme);
|
|
12763
|
-
if (config.bounds) emitBounds(out, s, view, t, theme);
|
|
12764
|
-
if (config.handles) emitHandles(out, s, t, theme);
|
|
12543
|
+
if (config.hitboxes) emitHitboxes(out, s, view, t, theme, strokes);
|
|
12544
|
+
if (config.bounds) emitBounds(out, s, view, t, theme, strokes);
|
|
12545
|
+
if (config.handles) emitHandles(out, s, t, theme, strokes);
|
|
12765
12546
|
if (config.origins) emitOrigins(out, s, t, theme);
|
|
12766
|
-
if (config.snap) emitSnap(out, s, t, theme);
|
|
12547
|
+
if (config.snap) emitSnap(out, s, t, theme, strokes);
|
|
12767
12548
|
if (config.ids) emitIds(out, s, t, theme);
|
|
12768
12549
|
if (config.layers) emitLayersPanel(out, s, dims, theme);
|
|
12769
12550
|
if (config.fps) {
|
|
@@ -12796,9 +12577,16 @@ function approxCircleScreen(cx, cy, r, segments = 24) {
|
|
|
12796
12577
|
function rectPath2(x, y, w, h) {
|
|
12797
12578
|
return { kind: "rect", x, y, width: w, height: h };
|
|
12798
12579
|
}
|
|
12799
|
-
function
|
|
12580
|
+
function strokeOf(s, color) {
|
|
12581
|
+
return {
|
|
12582
|
+
paint: { fill: "solid", color },
|
|
12583
|
+
width: s.width,
|
|
12584
|
+
...s.dash && s.dash.length > 0 ? { dash: [...s.dash] } : {}
|
|
12585
|
+
};
|
|
12586
|
+
}
|
|
12587
|
+
function emitHitboxes(out, s, view, t, theme, strokes) {
|
|
12800
12588
|
const fill = { fill: "solid", color: theme.hitboxFill };
|
|
12801
|
-
const stroke =
|
|
12589
|
+
const stroke = strokeOf(strokes.hitbox, theme.hitboxStroke);
|
|
12802
12590
|
for (const h of s.hitboxes) {
|
|
12803
12591
|
if (h.shape.kind === "rect") {
|
|
12804
12592
|
const [sx, sy] = worldToScreen(h.shape.x, h.shape.y, t);
|
|
@@ -12812,8 +12600,8 @@ function emitHitboxes(out, s, view, t, theme) {
|
|
|
12812
12600
|
}
|
|
12813
12601
|
}
|
|
12814
12602
|
}
|
|
12815
|
-
function emitBounds(out, s, view, t, theme) {
|
|
12816
|
-
const stroke =
|
|
12603
|
+
function emitBounds(out, s, view, t, theme, strokes) {
|
|
12604
|
+
const stroke = strokeOf(strokes.bounds, theme.bounds);
|
|
12817
12605
|
for (const b of s.bounds) {
|
|
12818
12606
|
const [sx, sy] = worldToScreen(b.bounds.x, b.bounds.y, t);
|
|
12819
12607
|
const sw = b.bounds.width * view.scale.x;
|
|
@@ -12821,8 +12609,8 @@ function emitBounds(out, s, view, t, theme) {
|
|
|
12821
12609
|
out.push({ kind: "path", path: rectPath2(sx, sy, sw, sh), stroke });
|
|
12822
12610
|
}
|
|
12823
12611
|
}
|
|
12824
|
-
function emitHandles(out, s, t, theme) {
|
|
12825
|
-
const stroke =
|
|
12612
|
+
function emitHandles(out, s, t, theme, strokes) {
|
|
12613
|
+
const stroke = strokeOf(strokes.handle, theme.handle);
|
|
12826
12614
|
for (const h of s.handles) {
|
|
12827
12615
|
const [cx, cy] = worldToScreen(h.position.x, h.position.y, t);
|
|
12828
12616
|
const horiz = {
|
|
@@ -12848,14 +12636,14 @@ function emitOrigins(out, s, t, theme) {
|
|
|
12848
12636
|
out.push({ kind: "path", path: approxCircleScreen(cx, cy, 3), fill });
|
|
12849
12637
|
}
|
|
12850
12638
|
}
|
|
12851
|
-
function emitSnap(out, s, t, theme) {
|
|
12639
|
+
function emitSnap(out, s, t, theme, strokes) {
|
|
12852
12640
|
const color = theme.snap;
|
|
12853
12641
|
for (const c of s.snap) {
|
|
12854
12642
|
const [cx, cy] = worldToScreen(c.point.x, c.point.y, t);
|
|
12855
12643
|
const cmd = {
|
|
12856
12644
|
kind: "path",
|
|
12857
12645
|
path: approxCircleScreen(cx, cy, 4),
|
|
12858
|
-
...c.accepted ? { fill: { fill: "solid", color } } : { stroke:
|
|
12646
|
+
...c.accepted ? { fill: { fill: "solid", color } } : { stroke: strokeOf(strokes.snap, color) }
|
|
12859
12647
|
};
|
|
12860
12648
|
out.push(cmd);
|
|
12861
12649
|
}
|
|
@@ -13227,11 +13015,22 @@ function reportDeadClaim(owner, warn) {
|
|
|
13227
13015
|
`[weasel] exclusive claim by "${key}" matched no binding: no \`affordance:\` or \`kindOf\` target resolved against it, so the press was dropped.`
|
|
13228
13016
|
);
|
|
13229
13017
|
}
|
|
13018
|
+
function phaseRank(spec) {
|
|
13019
|
+
if (spec === void 0) return 0;
|
|
13020
|
+
const atoms = typeof spec === "string" ? [{ channel: "&", phase: spec }] : spec;
|
|
13021
|
+
if (atoms.length === 0) return 0;
|
|
13022
|
+
let min = 2;
|
|
13023
|
+
for (const a of atoms) {
|
|
13024
|
+
const rank = (a.channel === "*" ? 0 : 1) + (a.phase === "*" ? 0 : 1);
|
|
13025
|
+
if (rank < min) min = rank;
|
|
13026
|
+
}
|
|
13027
|
+
return min;
|
|
13028
|
+
}
|
|
13230
13029
|
function specificity(spec) {
|
|
13231
13030
|
const t = targetRank(specTargetOf(spec));
|
|
13232
13031
|
const mods = "mods" in spec ? spec.mods : void 0;
|
|
13233
13032
|
const m = modsCount(mods);
|
|
13234
|
-
const p = "phase" in spec
|
|
13033
|
+
const p = phaseRank("phase" in spec ? spec.phase : void 0);
|
|
13235
13034
|
const typed = (spec.kind === "drop" || spec.kind === "paste") && spec.types !== void 0 && spec.types.length > 0 ? 2 : 1;
|
|
13236
13035
|
return [t, m, p, typed];
|
|
13237
13036
|
}
|
|
@@ -14831,8 +14630,7 @@ function useGestureDispatcher(opts) {
|
|
|
14831
14630
|
if (!cd) return;
|
|
14832
14631
|
const items = itemsFromClipboardData(cd);
|
|
14833
14632
|
if (items.length === 0) return;
|
|
14834
|
-
|
|
14835
|
-
dispatch2({
|
|
14633
|
+
const result = dispatch2({
|
|
14836
14634
|
kind: "paste",
|
|
14837
14635
|
items,
|
|
14838
14636
|
// ClipboardEvent carries no modifier state.
|
|
@@ -14841,6 +14639,7 @@ function useGestureDispatcher(opts) {
|
|
|
14841
14639
|
metaKey: false,
|
|
14842
14640
|
shiftKey: false
|
|
14843
14641
|
});
|
|
14642
|
+
if (result === "handled") e.preventDefault();
|
|
14844
14643
|
};
|
|
14845
14644
|
if (keyboard) {
|
|
14846
14645
|
window.addEventListener("keydown", onKeyDown);
|
|
@@ -15083,6 +14882,50 @@ function usePinchGesture(canvasRef, onPinch, enabled = true) {
|
|
|
15083
14882
|
};
|
|
15084
14883
|
}, [canvasRef, enabled]);
|
|
15085
14884
|
}
|
|
14885
|
+
function validateId(id, kind) {
|
|
14886
|
+
if (id.length === 0) {
|
|
14887
|
+
throw new Error(`weasel: ${kind} id may not be empty`);
|
|
14888
|
+
}
|
|
14889
|
+
if (RESERVED_ID_PREFIXES.has(id[0])) {
|
|
14890
|
+
throw new Error(
|
|
14891
|
+
`weasel: ${kind} id "${id}" starts with reserved sigil "${id[0]}" (reserved set: ${[...RESERVED_ID_PREFIXES].join(" ")})`
|
|
14892
|
+
);
|
|
14893
|
+
}
|
|
14894
|
+
if (RESERVED_ID_NAMES.has(id)) {
|
|
14895
|
+
throw new Error(
|
|
14896
|
+
`weasel: ${kind} id "${id}" collides with a reserved phase keyword (reserved: ${[...RESERVED_ID_NAMES].join(", ")})`
|
|
14897
|
+
);
|
|
14898
|
+
}
|
|
14899
|
+
}
|
|
14900
|
+
function defineTool(def) {
|
|
14901
|
+
validateId(def.id, "tool");
|
|
14902
|
+
const resolveCursor = (ctx) => {
|
|
14903
|
+
if (def.cursor == null) return "";
|
|
14904
|
+
return typeof def.cursor === "function" ? def.cursor(ctx) : def.cursor;
|
|
14905
|
+
};
|
|
14906
|
+
return {
|
|
14907
|
+
id: def.id,
|
|
14908
|
+
eligibility: {
|
|
14909
|
+
focus: true,
|
|
14910
|
+
capabilities: def.capabilities,
|
|
14911
|
+
...def.hotkey ? { offhand: def.hotkey } : {}
|
|
14912
|
+
},
|
|
14913
|
+
actions: def.actions,
|
|
14914
|
+
def,
|
|
14915
|
+
presentation: def.presentation,
|
|
14916
|
+
keybinding: def.keybinding,
|
|
14917
|
+
onActivate: def.onActivate,
|
|
14918
|
+
onDeactivate: def.onDeactivate,
|
|
14919
|
+
initScratch: def.initScratch ?? (() => null),
|
|
14920
|
+
cursor: resolveCursor,
|
|
14921
|
+
bindings: def.bindings,
|
|
14922
|
+
overlay: def.overlay,
|
|
14923
|
+
overlayPosition: def.overlayPosition
|
|
14924
|
+
};
|
|
14925
|
+
}
|
|
14926
|
+
function defineViewportTool(def) {
|
|
14927
|
+
return defineTool(def);
|
|
14928
|
+
}
|
|
15086
14929
|
var TOOL_OFFHAND_ID = "tool.offhand";
|
|
15087
14930
|
function offhandKeyFor(trigger) {
|
|
15088
14931
|
switch (trigger) {
|
|
@@ -15173,17 +15016,19 @@ function useContributions(opts) {
|
|
|
15173
15016
|
const { ordered, state } = snapshot();
|
|
15174
15017
|
return scopeBindings(ordered, state);
|
|
15175
15018
|
}, [snapshot]);
|
|
15176
|
-
const overlays = useCallback(() => {
|
|
15019
|
+
const overlays = useCallback((position = "top") => {
|
|
15177
15020
|
const { ordered, state } = snapshot();
|
|
15178
15021
|
const active = [];
|
|
15179
15022
|
const hotkey = [];
|
|
15180
15023
|
const ambient = [];
|
|
15181
15024
|
for (const entry of ordered) {
|
|
15182
15025
|
if (!entry.overlay) continue;
|
|
15026
|
+
if ((entry.overlayPosition ?? "top") !== position) continue;
|
|
15027
|
+
const layers = Array.isArray(entry.overlay) ? entry.overlay : [entry.overlay];
|
|
15183
15028
|
const scope = liveScope(entry.id, entry.eligibility ?? {}, state);
|
|
15184
|
-
if (scope === "active") active.push(
|
|
15185
|
-
else if (scope === "hotkey") hotkey.push(
|
|
15186
|
-
else if (scope === "ambient") ambient.push(
|
|
15029
|
+
if (scope === "active") active.push(...layers);
|
|
15030
|
+
else if (scope === "hotkey") hotkey.push(...layers);
|
|
15031
|
+
else if (scope === "ambient") ambient.push(...layers);
|
|
15187
15032
|
}
|
|
15188
15033
|
return [...active, ...hotkey, ...ambient];
|
|
15189
15034
|
}, [snapshot]);
|
|
@@ -15811,7 +15656,7 @@ function isBoundsGradient(fill) {
|
|
|
15811
15656
|
}
|
|
15812
15657
|
return fill.units === "bounds";
|
|
15813
15658
|
}
|
|
15814
|
-
var
|
|
15659
|
+
var cache6 = /* @__PURE__ */ new Map();
|
|
15815
15660
|
function specKey(spec) {
|
|
15816
15661
|
const keys = Object.keys(spec).sort();
|
|
15817
15662
|
const bag = spec;
|
|
@@ -15819,10 +15664,10 @@ function specKey(spec) {
|
|
|
15819
15664
|
}
|
|
15820
15665
|
function resolvePatternSpec(spec) {
|
|
15821
15666
|
const key = specKey(spec);
|
|
15822
|
-
const hit =
|
|
15667
|
+
const hit = cache6.get(key);
|
|
15823
15668
|
if (hit !== void 0) return hit;
|
|
15824
15669
|
const built = buildTile(spec);
|
|
15825
|
-
|
|
15670
|
+
cache6.set(key, built);
|
|
15826
15671
|
return built;
|
|
15827
15672
|
}
|
|
15828
15673
|
function buildTile(spec) {
|
|
@@ -15856,7 +15701,7 @@ function resolveFillPattern(fill) {
|
|
|
15856
15701
|
const handle = resolvePatternSpec(fill.pattern);
|
|
15857
15702
|
return handle ? { ...fill, pattern: handle } : null;
|
|
15858
15703
|
}
|
|
15859
|
-
var
|
|
15704
|
+
var cache7 = /* @__PURE__ */ new Map();
|
|
15860
15705
|
var subscribers2 = /* @__PURE__ */ new Set();
|
|
15861
15706
|
var defaultLoader = async (src) => {
|
|
15862
15707
|
if (typeof Image === "undefined" || typeof createImageBitmap === "undefined") {
|
|
@@ -15874,28 +15719,28 @@ function notify() {
|
|
|
15874
15719
|
}
|
|
15875
15720
|
function startLoad(src) {
|
|
15876
15721
|
const entry = { status: "loading" };
|
|
15877
|
-
|
|
15722
|
+
cache7.set(src, entry);
|
|
15878
15723
|
loader(src).then(
|
|
15879
15724
|
(bitmap) => {
|
|
15880
|
-
if (
|
|
15881
|
-
|
|
15725
|
+
if (cache7.get(src) !== entry) return;
|
|
15726
|
+
cache7.set(src, { status: "ready", bitmap });
|
|
15882
15727
|
notify();
|
|
15883
15728
|
},
|
|
15884
15729
|
() => {
|
|
15885
|
-
if (
|
|
15886
|
-
|
|
15730
|
+
if (cache7.get(src) !== entry) return;
|
|
15731
|
+
cache7.set(src, { status: "error" });
|
|
15887
15732
|
notify();
|
|
15888
15733
|
}
|
|
15889
15734
|
);
|
|
15890
15735
|
}
|
|
15891
15736
|
function getImageBitmap(src) {
|
|
15892
|
-
const entry =
|
|
15737
|
+
const entry = cache7.get(src);
|
|
15893
15738
|
if (entry) return entry.bitmap;
|
|
15894
15739
|
startLoad(src);
|
|
15895
15740
|
return void 0;
|
|
15896
15741
|
}
|
|
15897
15742
|
function imageStatus(src) {
|
|
15898
|
-
return
|
|
15743
|
+
return cache7.get(src)?.status ?? "idle";
|
|
15899
15744
|
}
|
|
15900
15745
|
function subscribeImageReady(cb) {
|
|
15901
15746
|
subscribers2.add(cb);
|
|
@@ -16253,6 +16098,7 @@ registerBuiltInShapePainters();
|
|
|
16253
16098
|
function pickTopMostHit(ids, adapter) {
|
|
16254
16099
|
if (ids.length === 0) return null;
|
|
16255
16100
|
if (ids.length === 1) return ids[0];
|
|
16101
|
+
let candidates = ids;
|
|
16256
16102
|
const getParent = adapter?.getParent;
|
|
16257
16103
|
if (typeof getParent === "function") {
|
|
16258
16104
|
const set = new Set(ids);
|
|
@@ -16267,16 +16113,40 @@ function pickTopMostHit(ids, adapter) {
|
|
|
16267
16113
|
}
|
|
16268
16114
|
if (dropped.size > 0) {
|
|
16269
16115
|
const filtered = ids.filter((id) => !dropped.has(id));
|
|
16270
|
-
if (filtered.length ===
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
|
|
16116
|
+
if (filtered.length === 1) return filtered[0];
|
|
16117
|
+
if (filtered.length > 1) candidates = filtered;
|
|
16118
|
+
}
|
|
16119
|
+
}
|
|
16120
|
+
return pickHighestZ(candidates, adapter);
|
|
16121
|
+
}
|
|
16122
|
+
function pickHighestZ(ids, adapter) {
|
|
16123
|
+
const compareZ = adapter?.compareZ;
|
|
16124
|
+
if (typeof compareZ === "function") {
|
|
16125
|
+
let best = ids[0];
|
|
16126
|
+
for (let i = 1; i < ids.length; i++) {
|
|
16127
|
+
if (compareZ(ids[i], best) >= 0) best = ids[i];
|
|
16128
|
+
}
|
|
16129
|
+
return best;
|
|
16130
|
+
}
|
|
16131
|
+
const getZIndex = adapter?.getZIndex;
|
|
16132
|
+
if (typeof getZIndex === "function") {
|
|
16133
|
+
let best = ids[0];
|
|
16134
|
+
let bestZ = zOf(getZIndex, best);
|
|
16135
|
+
for (let i = 1; i < ids.length; i++) {
|
|
16136
|
+
const z = zOf(getZIndex, ids[i]);
|
|
16137
|
+
if (z >= bestZ) {
|
|
16138
|
+
best = ids[i];
|
|
16139
|
+
bestZ = z;
|
|
16275
16140
|
}
|
|
16276
16141
|
}
|
|
16142
|
+
return best;
|
|
16277
16143
|
}
|
|
16278
16144
|
return ids[ids.length - 1];
|
|
16279
16145
|
}
|
|
16146
|
+
function zOf(getZIndex, id) {
|
|
16147
|
+
const z = getZIndex(id);
|
|
16148
|
+
return typeof z === "number" && Number.isFinite(z) ? z : -Infinity;
|
|
16149
|
+
}
|
|
16280
16150
|
var MULTI_RESIZE_TARGET_ID = "__weasel:multi-selection";
|
|
16281
16151
|
function useSelectTool(adapter, options) {
|
|
16282
16152
|
const poseBoundsFn = options.poseBounds ?? ((p) => p);
|
|
@@ -16673,9 +16543,19 @@ function composeAffordanceLayer(id, label, affordances) {
|
|
|
16673
16543
|
},
|
|
16674
16544
|
// The walk itself lives in `hitAffordanceRegions` so this layer and
|
|
16675
16545
|
// `buildAffordanceAt` share one implementation rather than two that can
|
|
16676
|
-
// drift. This wrapper
|
|
16677
|
-
// binding
|
|
16678
|
-
hitTest: (wx, wy, state, view, _dims, isVisible) =>
|
|
16546
|
+
// drift. This wrapper lifts the region's declared cursor and claim onto
|
|
16547
|
+
// the binding, the way `buildAffordanceAt` lifts them onto `AffordanceHit`.
|
|
16548
|
+
hitTest: (wx, wy, state, view, _dims, isVisible) => {
|
|
16549
|
+
const hit = hitAffordanceRegions(affordances, wx, wy, state, view, isVisible);
|
|
16550
|
+
if (!hit) return null;
|
|
16551
|
+
const { cursor, strength, claimedKinds } = hit.region;
|
|
16552
|
+
return {
|
|
16553
|
+
...hit.binding,
|
|
16554
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
16555
|
+
...strength !== void 0 ? { strength } : {},
|
|
16556
|
+
...claimedKinds !== void 0 ? { claimedKinds } : {}
|
|
16557
|
+
};
|
|
16558
|
+
}
|
|
16679
16559
|
};
|
|
16680
16560
|
}
|
|
16681
16561
|
function asChromeState(data) {
|
|
@@ -17835,6 +17715,19 @@ function composeOrderedLayers(layersMap, standardLayers, sceneLayers) {
|
|
|
17835
17715
|
}
|
|
17836
17716
|
return out;
|
|
17837
17717
|
}
|
|
17718
|
+
function placeToolOverlays(ordered, selectionOverlay, overlays) {
|
|
17719
|
+
const before = overlays("before-selection");
|
|
17720
|
+
const after = overlays("after-selection");
|
|
17721
|
+
const at = selectionOverlay ? ordered.indexOf(selectionOverlay) : -1;
|
|
17722
|
+
if (at >= 0) {
|
|
17723
|
+
ordered.splice(at + 1, 0, ...after);
|
|
17724
|
+
ordered.splice(at, 0, ...before);
|
|
17725
|
+
} else {
|
|
17726
|
+
ordered.push(...before, ...after);
|
|
17727
|
+
}
|
|
17728
|
+
ordered.push(...overlays("top"));
|
|
17729
|
+
return ordered;
|
|
17730
|
+
}
|
|
17838
17731
|
function* toolsInPriorityOrder(tools) {
|
|
17839
17732
|
const seen = /* @__PURE__ */ new Set();
|
|
17840
17733
|
const hotkey = tools.hotkeyEngaged ? tools.registry[tools.hotkeyEngaged] : void 0;
|
|
@@ -19263,7 +19156,7 @@ function CanvasInner(props, ref) {
|
|
|
19263
19156
|
const out = composeOrderedLayers(effectiveLayersMap, standardLayers, sceneLayers);
|
|
19264
19157
|
if (decorationLayer) out.push(decorationLayer);
|
|
19265
19158
|
if (tools) {
|
|
19266
|
-
out.
|
|
19159
|
+
placeToolOverlays(out, standardLayers.selectionOverlay, tools.getActiveOverlays);
|
|
19267
19160
|
}
|
|
19268
19161
|
return out;
|
|
19269
19162
|
}, [layersMap, adapter, selectedIds, effectiveBoundsOf, multiActive2, debugSink, tools, backgroundLayer, decorationLayer]);
|
|
@@ -20893,6 +20786,7 @@ function useSceneSelectTool(args) {
|
|
|
20893
20786
|
boundsOf: wiredBoundsOf
|
|
20894
20787
|
};
|
|
20895
20788
|
}
|
|
20789
|
+
var GHOST_ALPHA = 0.85;
|
|
20896
20790
|
function usePreviewGhostLayer(args) {
|
|
20897
20791
|
const { scene, tools, sceneSlot, dispatcher } = args;
|
|
20898
20792
|
const sceneRef = useRef(scene);
|
|
@@ -20979,15 +20873,26 @@ function usePreviewGhostLayer(args) {
|
|
|
20979
20873
|
}
|
|
20980
20874
|
return [group];
|
|
20981
20875
|
};
|
|
20876
|
+
const opaqueSet = /* @__PURE__ */ new Set();
|
|
20877
|
+
for (const source of sources) {
|
|
20878
|
+
const ids = source.previewOpaqueIds?.();
|
|
20879
|
+
if (!ids) continue;
|
|
20880
|
+
for (const id of ids) opaqueSet.add(id);
|
|
20881
|
+
}
|
|
20982
20882
|
const children = [];
|
|
20883
|
+
const opaque = [];
|
|
20983
20884
|
for (const id of idSet) {
|
|
20984
20885
|
const node = sc.get(asNodeId(id));
|
|
20985
20886
|
const parent = node?.parent;
|
|
20986
20887
|
if (parent != null && idSet.has(parent)) continue;
|
|
20987
|
-
|
|
20888
|
+
const sink = opaqueSet.has(id) ? opaque : children;
|
|
20889
|
+
for (const cmd of buildSubtree(id)) sink.push(cmd);
|
|
20988
20890
|
}
|
|
20989
|
-
if (children.length === 0) return [];
|
|
20990
|
-
|
|
20891
|
+
if (children.length === 0 && opaque.length === 0) return [];
|
|
20892
|
+
const out = [];
|
|
20893
|
+
if (opaque.length > 0) out.push({ kind: "group", children: opaque });
|
|
20894
|
+
if (children.length > 0) out.push({ kind: "group", alpha: GHOST_ALPHA, children });
|
|
20895
|
+
return out;
|
|
20991
20896
|
}
|
|
20992
20897
|
}), []);
|
|
20993
20898
|
}
|
|
@@ -20997,6 +20902,7 @@ var DEFAULT_STYLE = {
|
|
|
20997
20902
|
dash: [3, 3],
|
|
20998
20903
|
lineWidth: 1
|
|
20999
20904
|
};
|
|
20905
|
+
var PREVIEW_CONTENT_OPACITY = 0.85;
|
|
21000
20906
|
function useDispatcherOverlayLayer(args) {
|
|
21001
20907
|
const { dispatcher, style } = args;
|
|
21002
20908
|
const dispatcherRef = useRef(dispatcher);
|
|
@@ -21059,6 +20965,26 @@ function useDispatcherOverlayLayer(args) {
|
|
|
21059
20965
|
pathCmd = rectPath(sx, sy, b.width * view.scale.x, b.height * view.scale.y);
|
|
21060
20966
|
break;
|
|
21061
20967
|
}
|
|
20968
|
+
case "image": {
|
|
20969
|
+
const e = ov.extras;
|
|
20970
|
+
const [sx, sy] = worldToScreen(b.x, b.y, t);
|
|
20971
|
+
const sw = b.width * view.scale.x;
|
|
20972
|
+
const sh = b.height * view.scale.y;
|
|
20973
|
+
const bmp = e.preview === "outline" || !e.src ? void 0 : getImageBitmap(e.src);
|
|
20974
|
+
if (bmp) {
|
|
20975
|
+
out.push({
|
|
20976
|
+
kind: "image",
|
|
20977
|
+
image: bmp,
|
|
20978
|
+
x: sx,
|
|
20979
|
+
y: sy,
|
|
20980
|
+
w: sw,
|
|
20981
|
+
h: sh,
|
|
20982
|
+
opacity: PREVIEW_CONTENT_OPACITY
|
|
20983
|
+
});
|
|
20984
|
+
}
|
|
20985
|
+
pathCmd = rectPath(sx, sy, sw, sh);
|
|
20986
|
+
break;
|
|
20987
|
+
}
|
|
21062
20988
|
case "ellipse": {
|
|
21063
20989
|
const [sx, sy] = worldToScreen(b.x, b.y, t);
|
|
21064
20990
|
pathCmd = ellipsePath({
|
|
@@ -21117,7 +21043,7 @@ function useDispatcherOverlayLayer(args) {
|
|
|
21117
21043
|
const cmd = {
|
|
21118
21044
|
kind: "path",
|
|
21119
21045
|
path: pathCmd,
|
|
21120
|
-
fill: ov.shape === "line" || ov.shape === "pencil" ? void 0 : { color: cfg.fill },
|
|
21046
|
+
fill: ov.shape === "line" || ov.shape === "pencil" || ov.shape === "image" ? void 0 : { color: cfg.fill },
|
|
21121
21047
|
stroke: { paint: { color: cfg.stroke }, width: cfg.lineWidth, dash: cfg.dash }
|
|
21122
21048
|
};
|
|
21123
21049
|
out.push(cmd);
|
|
@@ -21806,9 +21732,6 @@ function buildClassifyTarget(getSelection, pickBest, kindOfNode) {
|
|
|
21806
21732
|
function w2s3(wx, wy, view) {
|
|
21807
21733
|
return [(wx - view.x) * view.scale.x, (wy - view.y) * view.scale.y];
|
|
21808
21734
|
}
|
|
21809
|
-
function r2s(radiusWorld, view) {
|
|
21810
|
-
return radiusWorld * meanScale(view.scale);
|
|
21811
|
-
}
|
|
21812
21735
|
var SLOP_FILL = "rgba(255, 80, 140, 0.18)";
|
|
21813
21736
|
var SLOP_STROKE = "rgba(255, 80, 140, 0.55)";
|
|
21814
21737
|
function createSlopsDebugLayer(opts) {
|
|
@@ -21819,7 +21742,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
21819
21742
|
draw: (_data, view) => {
|
|
21820
21743
|
const out = [];
|
|
21821
21744
|
const sel = opts.selectionRef.current?.current ?? [];
|
|
21822
|
-
const r =
|
|
21745
|
+
const r = HANDLE_HIT_RADIUS;
|
|
21823
21746
|
for (const id of sel) {
|
|
21824
21747
|
const b = opts.boundsOf(id);
|
|
21825
21748
|
if (!b) continue;
|
|
@@ -21856,6 +21779,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
21856
21779
|
}
|
|
21857
21780
|
const editingId = opts.getEditingId();
|
|
21858
21781
|
if (editingId) {
|
|
21782
|
+
const anchorR = ANCHOR_HIT_RADIUS;
|
|
21859
21783
|
const pose = opts.getPose(editingId);
|
|
21860
21784
|
if (pose && pose.kind === "polygon") {
|
|
21861
21785
|
const anchors = enumerateAnchors(pose);
|
|
@@ -21863,7 +21787,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
21863
21787
|
const [sx, sy] = w2s3(a.x, a.y, view);
|
|
21864
21788
|
out.push({
|
|
21865
21789
|
kind: "path",
|
|
21866
|
-
path: circlePath(sx, sy,
|
|
21790
|
+
path: circlePath(sx, sy, anchorR),
|
|
21867
21791
|
fill: { fill: "solid", color: SLOP_FILL },
|
|
21868
21792
|
stroke: { paint: { fill: "solid", color: SLOP_STROKE }, width: 1 }
|
|
21869
21793
|
});
|
|
@@ -21871,7 +21795,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
21871
21795
|
const [csx, csy] = w2s3(a.controlIn.x, a.controlIn.y, view);
|
|
21872
21796
|
out.push({
|
|
21873
21797
|
kind: "path",
|
|
21874
|
-
path: circlePath(csx, csy,
|
|
21798
|
+
path: circlePath(csx, csy, anchorR),
|
|
21875
21799
|
fill: { fill: "solid", color: SLOP_FILL },
|
|
21876
21800
|
stroke: { paint: { fill: "solid", color: SLOP_STROKE }, width: 1 }
|
|
21877
21801
|
});
|
|
@@ -21880,7 +21804,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
21880
21804
|
const [csx, csy] = w2s3(a.controlOut.x, a.controlOut.y, view);
|
|
21881
21805
|
out.push({
|
|
21882
21806
|
kind: "path",
|
|
21883
|
-
path: circlePath(csx, csy,
|
|
21807
|
+
path: circlePath(csx, csy, anchorR),
|
|
21884
21808
|
fill: { fill: "solid", color: SLOP_FILL },
|
|
21885
21809
|
stroke: { paint: { fill: "solid", color: SLOP_STROKE }, width: 1 }
|
|
21886
21810
|
});
|
|
@@ -21958,9 +21882,9 @@ function DepRegistryProviderIfRoot({ children }) {
|
|
|
21958
21882
|
function hitTestArea(scene, bounds) {
|
|
21959
21883
|
const { x, y, width: w, height: h } = bounds;
|
|
21960
21884
|
const area = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
21961
|
-
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h });
|
|
21885
|
+
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
|
|
21962
21886
|
}
|
|
21963
|
-
function hitTestAreaPolygon(scene, area, areaBounds) {
|
|
21887
|
+
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
|
|
21964
21888
|
const ab = areaBounds ?? boundsOf(area);
|
|
21965
21889
|
if (!ab) return [];
|
|
21966
21890
|
const hits = [];
|
|
@@ -21977,13 +21901,22 @@ function hitTestAreaPolygon(scene, area, areaBounds) {
|
|
|
21977
21901
|
if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
|
|
21978
21902
|
continue;
|
|
21979
21903
|
}
|
|
21980
|
-
if (
|
|
21904
|
+
if (areaIsRect && b.x >= ab.x && b.y >= ab.y && b.x + b.width <= ab.x + ab.width && b.y + b.height <= ab.y + ab.height) {
|
|
21981
21905
|
hits.push(node.id);
|
|
21982
21906
|
continue;
|
|
21983
21907
|
}
|
|
21984
|
-
if (
|
|
21985
|
-
|
|
21908
|
+
if (silhouette) {
|
|
21909
|
+
if (silhouetteOverlapsArea(pose.coords, area)) {
|
|
21910
|
+
hits.push(node.id);
|
|
21911
|
+
}
|
|
21912
|
+
continue;
|
|
21913
|
+
}
|
|
21914
|
+
const drawn = findShapeSilhouette(node, pose);
|
|
21915
|
+
if (drawn?.kind === "polygon") {
|
|
21916
|
+
if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
|
|
21917
|
+
continue;
|
|
21986
21918
|
}
|
|
21919
|
+
hits.push(node.id);
|
|
21987
21920
|
}
|
|
21988
21921
|
return hits;
|
|
21989
21922
|
}
|
|
@@ -24573,5 +24506,5 @@ function oklchToOklab(L, C, h) {
|
|
|
24573
24506
|
}
|
|
24574
24507
|
|
|
24575
24508
|
export { FALLBACK_FIT_VIEW, MinimapCanvas, SceneViewCanvas, UnknownIcon, buildSceneViewCommands, computeFitView2, computeIndicatorCommand, eligibleContribution, evaluateEnabled, oklabToSrgbU8, oklchToOklab, renderSceneToCanvas, rgbaToHex, useActionsRegistry, useOptionalDepRegistry };
|
|
24576
|
-
//# sourceMappingURL=chunk-
|
|
24577
|
-
//# sourceMappingURL=chunk-
|
|
24509
|
+
//# sourceMappingURL=chunk-3WPOGKUP.js.map
|
|
24510
|
+
//# sourceMappingURL=chunk-3WPOGKUP.js.map
|