@weasel-js/core 1.0.0 → 1.0.2
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/CHANGELOG.md +604 -0
- package/dist/{chunk-D2C6K6FO.js → chunk-PI56ORHE.js} +2162 -1491
- package/dist/chunk-PI56ORHE.js.map +1 -0
- package/dist/{chunk-DCIU3SRK.js → chunk-W2WB4352.js} +79 -151
- package/dist/chunk-W2WB4352.js.map +1 -0
- package/dist/clipboard.d.ts +2 -2
- package/dist/clipboard.js +0 -1
- package/dist/clone.d.ts +2 -2
- package/dist/clone.js +0 -1
- package/dist/{geometry-DVeZ2i-c.d.ts → geometry-CnISZ11w.d.ts} +1 -1
- package/dist/{grid-XcFQVS0f.d.ts → grid-CBiLBnyc.d.ts} +2 -2
- package/dist/index.d.ts +202 -54
- package/dist/index.js +2 -3
- package/dist/insert.d.ts +3 -3
- package/dist/insert.js +0 -1
- package/dist/insert.js.map +1 -1
- package/dist/move.d.ts +5 -5
- package/dist/move.js +0 -1
- package/dist/move.js.map +1 -1
- package/dist/{options-wAvCnOZd.d.ts → options-DoOvx50U.d.ts} +1 -1
- package/dist/patterns-builtin.js +0 -1
- package/dist/{pointSnapToGrid-BuDZWBrL.d.ts → pointSnapToGrid-Bj4r_lEQ.d.ts} +3 -3
- package/dist/{index-ChM3ZJ2v.d.ts → registry-BQL4oyTg.d.ts} +140 -349
- package/dist/renderer.d.ts +63 -8
- package/dist/renderer.js +2 -3
- package/dist/resize.d.ts +5 -5
- package/dist/resize.js +0 -1
- package/dist/routing.d.ts +105 -6
- package/dist/routing.js +1 -2
- package/dist/{types-B_-khFM0.d.ts → types-Ch0Goo-j.d.ts} +12 -0
- package/dist/{types-BhJJ2OCM.d.ts → types-Ct4n0Z38.d.ts} +1 -1
- package/dist/{types-BJ8_cyT7.d.ts → types-Dtxe7jTS.d.ts} +20 -1
- package/dist/{types-DUpI7Apc.d.ts → types-Kh_osAq9.d.ts} +8 -1
- package/package.json +6 -6
- package/dist/chunk-D2C6K6FO.js.map +0 -1
- package/dist/chunk-DCIU3SRK.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -9
- package/dist/chunk-PZ5AY32C.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionDisabledReason,
|
|
1
|
+
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-W2WB4352.js';
|
|
2
2
|
import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-UB6A6L77.js';
|
|
3
3
|
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-Z3KNFTTS.js';
|
|
4
4
|
import { AUTO_POSE_DESCRIPTOR, RECT_POSE_DESCRIPTOR, resolveUnit, pathPoseDescriptor, polygonFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, strokeHitTest, withinPxRadius, boundsOfPath, PATH_M, PATH_L, PATH_Z, PATH_Q, PATH_C, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, PathBuilder, pointInPath, transformPath, translatePath, pxExtent, remapRotatedLeaf, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-6SHZHXXR.js';
|
|
@@ -13,13 +13,13 @@ import earcut from 'earcut';
|
|
|
13
13
|
import { applyToPoint, rotateAboutPoint, boxToBox, pointInPolygon, segmentsCross } from '@weasel-js/geom';
|
|
14
14
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
15
15
|
import polygonClipping from 'polygon-clipping';
|
|
16
|
-
import { matchSpec, mimeMatchesGlob } from '@weasel-js/gestures';
|
|
16
|
+
import { matchSpec, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec, mimeMatchesGlob } from '@weasel-js/gestures';
|
|
17
17
|
import { NORMAL, IMPLICIT_TAGS } from '@weasel-js/modes';
|
|
18
18
|
import { createHistory } from '@weasel-js/history';
|
|
19
19
|
export * from '@weasel-js/history';
|
|
20
20
|
|
|
21
21
|
// src/version.ts
|
|
22
|
-
var VERSION = "1.0.
|
|
22
|
+
var VERSION = "1.0.2" ;
|
|
23
23
|
|
|
24
24
|
// src/features/grid/roundToCell.ts
|
|
25
25
|
function roundToCell(value, cellSize) {
|
|
@@ -399,6 +399,8 @@ var GLMeshCache = class {
|
|
|
399
399
|
gl;
|
|
400
400
|
aPositionLoc;
|
|
401
401
|
map = /* @__PURE__ */ new WeakMap();
|
|
402
|
+
/** Meshes this context has drawn at least once; see `uploadRecurring`. */
|
|
403
|
+
seen = /* @__PURE__ */ new WeakSet();
|
|
402
404
|
finalizer;
|
|
403
405
|
pendingDeletes = [];
|
|
404
406
|
/** Transient resources allocated this frame; freed at end of render(). */
|
|
@@ -423,6 +425,19 @@ var GLMeshCache = class {
|
|
|
423
425
|
this.transientThisFrame.push({ vao: handle.vao, vbo, ibo });
|
|
424
426
|
return handle;
|
|
425
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Upload a Mesh that may or may not recur across frames. Its first sight in
|
|
430
|
+
* *this* context takes `uploadTransient`; every later one takes the
|
|
431
|
+
* persistent handle. One transient upload to find out is cheaper than
|
|
432
|
+
* stranding a persistent VAO on a mesh that never returns, whose release
|
|
433
|
+
* would wait on GC. The transient upload does not populate the persistent
|
|
434
|
+
* map, so steady-state reuse begins on the third frame.
|
|
435
|
+
*/
|
|
436
|
+
uploadRecurring(mesh) {
|
|
437
|
+
if (this.seen.has(mesh)) return this.handleFor(mesh);
|
|
438
|
+
this.seen.add(mesh);
|
|
439
|
+
return this.uploadTransient(mesh);
|
|
440
|
+
}
|
|
426
441
|
/**
|
|
427
442
|
* Free all transient resources allocated since the last call. Called by
|
|
428
443
|
* the renderer at the end of each `render()`. Safe under context loss.
|
|
@@ -1532,1269 +1547,1269 @@ function getMesh(path) {
|
|
|
1532
1547
|
cache.set(path, mesh);
|
|
1533
1548
|
return mesh;
|
|
1534
1549
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
}
|
|
1541
|
-
function extractRect(p) {
|
|
1542
|
-
const { x, y, width: w, height: h } = p;
|
|
1543
|
-
return {
|
|
1544
|
-
points: [x, y, x + w, y, x + w, y + h, x, y + h],
|
|
1545
|
-
closed: true,
|
|
1546
|
-
anchorA: new Uint32Array([0, 1, 2, 3]),
|
|
1547
|
-
anchorB: new Uint32Array([0, 1, 2, 3]),
|
|
1548
|
-
anchorT: new Float32Array([0, 0, 0, 0])
|
|
1549
|
-
};
|
|
1550
|
+
var UNDERLINE_OFFSET = 0.1;
|
|
1551
|
+
var STRIKETHROUGH_OFFSET = -0.3;
|
|
1552
|
+
var DECORATION_THICKNESS = 0.05;
|
|
1553
|
+
function fillKey(p) {
|
|
1554
|
+
if ("color" in p) return `s:${p.color}:${p.opacity ?? 1}`;
|
|
1555
|
+
return `nx:${Math.random()}`;
|
|
1550
1556
|
}
|
|
1551
|
-
function
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
let anchorCounter = 0;
|
|
1556
|
-
let pts = null;
|
|
1557
|
-
let aA = null;
|
|
1558
|
-
let aB = null;
|
|
1559
|
-
let aT = null;
|
|
1560
|
-
let current = null;
|
|
1561
|
-
let coordIdx = 0;
|
|
1562
|
-
let prevX = 0;
|
|
1563
|
-
let prevY = 0;
|
|
1564
|
-
let prevAnchor = -1;
|
|
1565
|
-
const beginContour = () => {
|
|
1566
|
-
pts = [];
|
|
1567
|
-
aA = [];
|
|
1568
|
-
aB = [];
|
|
1569
|
-
aT = [];
|
|
1570
|
-
const next = { points: pts, closed: false };
|
|
1571
|
-
out.push(next);
|
|
1572
|
-
return next;
|
|
1573
|
-
};
|
|
1574
|
-
const dropDuplicateClosingPoint = () => {
|
|
1575
|
-
if (!pts || !aA || !aB || !aT) return;
|
|
1576
|
-
const n = pts.length / 2;
|
|
1577
|
-
if (n < 2) return;
|
|
1578
|
-
if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;
|
|
1579
|
-
pts.length -= 2;
|
|
1580
|
-
aA.length -= 1;
|
|
1581
|
-
aB.length -= 1;
|
|
1582
|
-
aT.length -= 1;
|
|
1583
|
-
};
|
|
1584
|
-
const commit = (target) => {
|
|
1585
|
-
if (!pts || !aA || !aB || !aT) return;
|
|
1586
|
-
target.anchorA = new Uint32Array(aA);
|
|
1587
|
-
target.anchorB = new Uint32Array(aB);
|
|
1588
|
-
target.anchorT = new Float32Array(aT);
|
|
1589
|
-
};
|
|
1590
|
-
for (let cmdIdx = 0; cmdIdx < commands.length; cmdIdx++) {
|
|
1591
|
-
const cmd = commands[cmdIdx];
|
|
1592
|
-
switch (cmd) {
|
|
1593
|
-
case PATH_M: {
|
|
1594
|
-
if (current) commit(current);
|
|
1595
|
-
current = beginContour();
|
|
1596
|
-
prevX = coords[coordIdx];
|
|
1597
|
-
prevY = coords[coordIdx + 1];
|
|
1598
|
-
pts.push(prevX, prevY);
|
|
1599
|
-
aA.push(anchorCounter);
|
|
1600
|
-
aB.push(anchorCounter);
|
|
1601
|
-
aT.push(0);
|
|
1602
|
-
prevAnchor = anchorCounter;
|
|
1603
|
-
anchorCounter++;
|
|
1604
|
-
coordIdx += 2;
|
|
1605
|
-
break;
|
|
1606
|
-
}
|
|
1607
|
-
case PATH_L: {
|
|
1608
|
-
prevX = coords[coordIdx];
|
|
1609
|
-
prevY = coords[coordIdx + 1];
|
|
1610
|
-
pts.push(prevX, prevY);
|
|
1611
|
-
aA.push(anchorCounter);
|
|
1612
|
-
aB.push(anchorCounter);
|
|
1613
|
-
aT.push(0);
|
|
1614
|
-
prevAnchor = anchorCounter;
|
|
1615
|
-
anchorCounter++;
|
|
1616
|
-
coordIdx += 2;
|
|
1617
|
-
break;
|
|
1618
|
-
}
|
|
1619
|
-
case PATH_Q: {
|
|
1620
|
-
const cx = coords[coordIdx], cy = coords[coordIdx + 1];
|
|
1621
|
-
const ex = coords[coordIdx + 2], ey = coords[coordIdx + 3];
|
|
1622
|
-
const targetAnchor = anchorCounter;
|
|
1623
|
-
const segStart = pts.length / 2;
|
|
1624
|
-
const arcAccum = [];
|
|
1625
|
-
const total = flattenQuadraticWithArcLen(prevX, prevY, cx, cy, ex, ey, tolerance, pts, arcAccum);
|
|
1626
|
-
for (let k = 0; k < arcAccum.length; k++) {
|
|
1627
|
-
aA.push(prevAnchor);
|
|
1628
|
-
aB.push(targetAnchor);
|
|
1629
|
-
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
1630
|
-
}
|
|
1631
|
-
const lastIdx = segStart + arcAccum.length - 1;
|
|
1632
|
-
aA[lastIdx] = targetAnchor;
|
|
1633
|
-
aB[lastIdx] = targetAnchor;
|
|
1634
|
-
aT[lastIdx] = 0;
|
|
1635
|
-
prevX = ex;
|
|
1636
|
-
prevY = ey;
|
|
1637
|
-
prevAnchor = targetAnchor;
|
|
1638
|
-
anchorCounter++;
|
|
1639
|
-
coordIdx += 4;
|
|
1640
|
-
break;
|
|
1641
|
-
}
|
|
1642
|
-
case PATH_C: {
|
|
1643
|
-
const c1x = coords[coordIdx], c1y = coords[coordIdx + 1];
|
|
1644
|
-
const c2x = coords[coordIdx + 2], c2y = coords[coordIdx + 3];
|
|
1645
|
-
const ex = coords[coordIdx + 4], ey = coords[coordIdx + 5];
|
|
1646
|
-
const targetAnchor = anchorCounter;
|
|
1647
|
-
const segStart = pts.length / 2;
|
|
1648
|
-
const arcAccum = [];
|
|
1649
|
-
const total = flattenCubicWithArcLen(prevX, prevY, c1x, c1y, c2x, c2y, ex, ey, tolerance, pts, arcAccum);
|
|
1650
|
-
for (let k = 0; k < arcAccum.length; k++) {
|
|
1651
|
-
aA.push(prevAnchor);
|
|
1652
|
-
aB.push(targetAnchor);
|
|
1653
|
-
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
1654
|
-
}
|
|
1655
|
-
const lastIdx = segStart + arcAccum.length - 1;
|
|
1656
|
-
aA[lastIdx] = targetAnchor;
|
|
1657
|
-
aB[lastIdx] = targetAnchor;
|
|
1658
|
-
aT[lastIdx] = 0;
|
|
1659
|
-
prevX = ex;
|
|
1660
|
-
prevY = ey;
|
|
1661
|
-
prevAnchor = targetAnchor;
|
|
1662
|
-
anchorCounter++;
|
|
1663
|
-
coordIdx += 6;
|
|
1664
|
-
break;
|
|
1665
|
-
}
|
|
1666
|
-
case PATH_Z: {
|
|
1667
|
-
if (current) {
|
|
1668
|
-
current.closed = true;
|
|
1669
|
-
dropDuplicateClosingPoint();
|
|
1670
|
-
}
|
|
1671
|
-
break;
|
|
1672
|
-
}
|
|
1673
|
-
default:
|
|
1674
|
-
throw new Error(`extractPolylines: unknown command code ${cmd}`);
|
|
1675
|
-
}
|
|
1557
|
+
function sameFill(a, b) {
|
|
1558
|
+
if (a === b) return true;
|
|
1559
|
+
if ("color" in a && "color" in b) {
|
|
1560
|
+
return a.color === b.color && (a.opacity ?? 1) === (b.opacity ?? 1);
|
|
1676
1561
|
}
|
|
1677
|
-
|
|
1678
|
-
return out;
|
|
1562
|
+
return false;
|
|
1679
1563
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
const
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1564
|
+
function strokeKey(s) {
|
|
1565
|
+
if (!s) return "-";
|
|
1566
|
+
return [
|
|
1567
|
+
fillKey(s.paint),
|
|
1568
|
+
s.width ?? 1,
|
|
1569
|
+
s.join ?? "miter",
|
|
1570
|
+
s.cap ?? "butt",
|
|
1571
|
+
s.miterLimit ?? "",
|
|
1572
|
+
s.align ?? "center",
|
|
1573
|
+
(s.dash ?? []).join(",")
|
|
1574
|
+
].join(":");
|
|
1575
|
+
}
|
|
1576
|
+
function groupKey(family, weight, style, synthetic, fill, stroke, source, page) {
|
|
1577
|
+
return `${family}|${weight}|${style}|${synthetic.bold ? 1 : 0}${synthetic.italic ? 1 : 0}|${fillKey(fill)}|${strokeKey(stroke)}|${source}|${page}`;
|
|
1578
|
+
}
|
|
1579
|
+
function getOrCreateGroup(ctx, run, resolved, page, sourceOverride) {
|
|
1580
|
+
const atlasFamily = resolved.resolved.family;
|
|
1581
|
+
const resolvedWeight = resolved.resolved.weight;
|
|
1582
|
+
const resolvedStyle = resolved.resolved.style;
|
|
1583
|
+
const source = sourceOverride ?? resolved.source;
|
|
1584
|
+
const key = groupKey(
|
|
1585
|
+
atlasFamily,
|
|
1586
|
+
resolvedWeight,
|
|
1587
|
+
resolvedStyle,
|
|
1588
|
+
resolved.synthetic,
|
|
1589
|
+
run.fill,
|
|
1590
|
+
source === "outline" ? run.stroke : void 0,
|
|
1591
|
+
source,
|
|
1592
|
+
page
|
|
1593
|
+
);
|
|
1594
|
+
let g = ctx.groups.get(key);
|
|
1595
|
+
if (!g) {
|
|
1596
|
+
g = {
|
|
1597
|
+
family: atlasFamily,
|
|
1598
|
+
weight: resolvedWeight,
|
|
1599
|
+
style: resolvedStyle,
|
|
1600
|
+
synthetic: { ...resolved.synthetic },
|
|
1601
|
+
source,
|
|
1602
|
+
page,
|
|
1603
|
+
fill: run.fill,
|
|
1604
|
+
// Only the outline tier can paint it, and carrying it on an SDF group
|
|
1605
|
+
// would be a promise the renderer cannot keep.
|
|
1606
|
+
...source === "outline" && run.stroke !== void 0 ? { stroke: run.stroke } : {},
|
|
1607
|
+
quads: [],
|
|
1608
|
+
glyphs: []
|
|
1706
1609
|
};
|
|
1610
|
+
ctx.groups.set(key, g);
|
|
1707
1611
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
const
|
|
1714
|
-
const
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
const subs = dash.length > 0 ? splitForDash(pl, dash) : [pl];
|
|
1720
|
-
for (const sub2 of subs) {
|
|
1721
|
-
expandPolyline(sub2, width, join, cap, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT);
|
|
1612
|
+
return g;
|
|
1613
|
+
}
|
|
1614
|
+
function resolveGlyph(run, font, resolved, cp) {
|
|
1615
|
+
const direct = font.charMap.get(cp);
|
|
1616
|
+
if (direct) return { glyph: direct, font, resolved };
|
|
1617
|
+
const fallback = resolveGlyphFallback(run.fontFamily, run.fontWeight, run.fontStyle);
|
|
1618
|
+
const face = fallback?.dynamicFace;
|
|
1619
|
+
if (fallback && face) {
|
|
1620
|
+
const glyph = face.requestGlyph(cp);
|
|
1621
|
+
if (glyph.xadvance > 0 || glyph.width > 0) {
|
|
1622
|
+
return { glyph, font: face.font, resolved: fallback };
|
|
1722
1623
|
}
|
|
1723
1624
|
}
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
indices: new Uint32Array(idx),
|
|
1727
|
-
anchorA: new Uint32Array(anchorA),
|
|
1728
|
-
anchorB: new Uint32Array(anchorB),
|
|
1729
|
-
anchorT: new Float32Array(anchorT)
|
|
1730
|
-
};
|
|
1625
|
+
warnMissingGlyphOnce(resolved.resolved.family, cp);
|
|
1626
|
+
return null;
|
|
1731
1627
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
const
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
const
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1628
|
+
var warnedMissingGlyphs = /* @__PURE__ */ new Set();
|
|
1629
|
+
function warnMissingGlyphOnce(family, cp) {
|
|
1630
|
+
const key = `${family}|${cp}`;
|
|
1631
|
+
if (warnedMissingGlyphs.has(key)) return;
|
|
1632
|
+
warnedMissingGlyphs.add(key);
|
|
1633
|
+
const ch = String.fromCodePoint(cp);
|
|
1634
|
+
console.warn(
|
|
1635
|
+
`weasel layoutRuns: no glyph for U+${cp.toString(16).toUpperCase().padStart(4, "0")} (${JSON.stringify(ch)}) in "${family}", and the dynamic tier could not rasterize it \u2014 skipping the character. Bake it into the atlas, or call registerCanvasFont("${family}") to serve missing codepoints from installed fonts.`
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
function layoutRuns(runs, opts) {
|
|
1639
|
+
const ctx = { groups: /* @__PURE__ */ new Map() };
|
|
1640
|
+
const entries = [];
|
|
1641
|
+
let prevCp;
|
|
1642
|
+
let prevFont;
|
|
1643
|
+
let prevFontSize;
|
|
1644
|
+
for (const run of runs) {
|
|
1645
|
+
const resolved = resolveFontVariant(run.fontFamily, run.fontWeight, run.fontStyle);
|
|
1646
|
+
const font = resolved.entry?.font ?? resolved.dynamicFace?.font;
|
|
1647
|
+
if (!font) {
|
|
1648
|
+
prevCp = void 0;
|
|
1649
|
+
prevFont = void 0;
|
|
1650
|
+
prevFontSize = void 0;
|
|
1651
|
+
continue;
|
|
1751
1652
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1653
|
+
const scale2 = run.fontSize / font.info.size;
|
|
1654
|
+
const tracking = run.letterSpacing;
|
|
1655
|
+
for (const ch of [...run.text]) {
|
|
1656
|
+
const cp = ch.codePointAt(0);
|
|
1657
|
+
const isNewline = cp === 10;
|
|
1658
|
+
const isSpace = cp === 32;
|
|
1659
|
+
if (isNewline) {
|
|
1660
|
+
entries.push({
|
|
1661
|
+
run,
|
|
1662
|
+
font,
|
|
1663
|
+
glyph: { id: cp, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
|
|
1664
|
+
// A newline consumes no advance, so it takes no tracking either.
|
|
1665
|
+
cp,
|
|
1666
|
+
advance: 0,
|
|
1667
|
+
tracking: 0,
|
|
1668
|
+
kerningBefore: 0,
|
|
1669
|
+
isSpace: false,
|
|
1670
|
+
isNewline: true,
|
|
1671
|
+
resolved,
|
|
1672
|
+
fontSize: run.fontSize
|
|
1673
|
+
});
|
|
1674
|
+
prevCp = void 0;
|
|
1675
|
+
prevFont = void 0;
|
|
1676
|
+
prevFontSize = void 0;
|
|
1677
|
+
continue;
|
|
1678
|
+
}
|
|
1679
|
+
if (isSpace) {
|
|
1680
|
+
const spaceGlyph = resolved.dynamicFace ? resolved.dynamicFace.requestGlyph(32) : font.charMap.get(32);
|
|
1681
|
+
const advance = spaceGlyph ? spaceGlyph.xadvance * scale2 : run.fontSize * 0.25;
|
|
1682
|
+
let kerningBefore2 = 0;
|
|
1683
|
+
if (prevCp !== void 0 && prevFont !== void 0 && prevFontSize !== void 0) {
|
|
1684
|
+
const kAtlas = prevFont.kerningMap.get(prevCp)?.get(cp) ?? 0;
|
|
1685
|
+
kerningBefore2 = kAtlas * (prevFontSize / prevFont.info.size);
|
|
1686
|
+
}
|
|
1687
|
+
entries.push({
|
|
1688
|
+
run,
|
|
1689
|
+
font,
|
|
1690
|
+
glyph: spaceGlyph ?? { id: 32, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
|
|
1691
|
+
cp,
|
|
1692
|
+
advance,
|
|
1693
|
+
tracking,
|
|
1694
|
+
kerningBefore: kerningBefore2,
|
|
1695
|
+
isSpace: true,
|
|
1696
|
+
isNewline: false,
|
|
1697
|
+
resolved,
|
|
1698
|
+
fontSize: run.fontSize
|
|
1699
|
+
});
|
|
1700
|
+
prevCp = cp;
|
|
1701
|
+
prevFont = font;
|
|
1702
|
+
prevFontSize = run.fontSize;
|
|
1703
|
+
continue;
|
|
1704
|
+
}
|
|
1705
|
+
const hit = resolved.dynamicFace ? { glyph: resolved.dynamicFace.requestGlyph(cp), font, resolved } : resolveGlyph(run, font, resolved, cp);
|
|
1706
|
+
if (!hit) {
|
|
1707
|
+
prevCp = cp;
|
|
1708
|
+
prevFont = font;
|
|
1709
|
+
prevFontSize = run.fontSize;
|
|
1710
|
+
continue;
|
|
1711
|
+
}
|
|
1712
|
+
const glyphFont = hit.font;
|
|
1713
|
+
const glyphScale = run.fontSize / glyphFont.info.size;
|
|
1714
|
+
let kerningBefore = 0;
|
|
1715
|
+
if (prevCp !== void 0 && prevFont !== void 0 && prevFontSize !== void 0) {
|
|
1716
|
+
const kAtlas = prevFont.kerningMap.get(prevCp)?.get(cp) ?? 0;
|
|
1717
|
+
kerningBefore = kAtlas * (prevFontSize / prevFont.info.size);
|
|
1718
|
+
}
|
|
1719
|
+
entries.push({
|
|
1720
|
+
run,
|
|
1721
|
+
font: glyphFont,
|
|
1722
|
+
glyph: hit.glyph,
|
|
1723
|
+
cp,
|
|
1724
|
+
advance: hit.glyph.xadvance * glyphScale,
|
|
1725
|
+
tracking,
|
|
1726
|
+
kerningBefore,
|
|
1727
|
+
isSpace,
|
|
1728
|
+
isNewline: false,
|
|
1729
|
+
resolved: hit.resolved,
|
|
1730
|
+
fontSize: run.fontSize
|
|
1731
|
+
});
|
|
1732
|
+
prevCp = cp;
|
|
1733
|
+
prevFont = glyphFont;
|
|
1734
|
+
prevFontSize = run.fontSize;
|
|
1764
1735
|
}
|
|
1765
1736
|
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
const endSrc = s === segs.length - 1 && pl.closed && closerSrcIdx >= 0 ? 0 : startSrc + 1;
|
|
1772
|
-
const base = verts.length / 2;
|
|
1773
|
-
segBaseIdx.push(base);
|
|
1774
|
-
const nxA = seg.nxUnit * seg.halfA, nyA = seg.nyUnit * seg.halfA;
|
|
1775
|
-
const nxB = seg.nxUnit * seg.halfB, nyB = seg.nyUnit * seg.halfB;
|
|
1776
|
-
verts.push(seg.ax + nxA, seg.ay + nyA);
|
|
1777
|
-
anchorA.push(plA[startSrc]);
|
|
1778
|
-
anchorB.push(plB[startSrc]);
|
|
1779
|
-
anchorT.push(plT[startSrc]);
|
|
1780
|
-
verts.push(seg.ax - nxA, seg.ay - nyA);
|
|
1781
|
-
anchorA.push(plA[startSrc]);
|
|
1782
|
-
anchorB.push(plB[startSrc]);
|
|
1783
|
-
anchorT.push(plT[startSrc]);
|
|
1784
|
-
verts.push(seg.bx + nxB, seg.by + nyB);
|
|
1785
|
-
anchorA.push(plA[endSrc]);
|
|
1786
|
-
anchorB.push(plB[endSrc]);
|
|
1787
|
-
anchorT.push(plT[endSrc]);
|
|
1788
|
-
verts.push(seg.bx - nxB, seg.by - nyB);
|
|
1789
|
-
anchorA.push(plA[endSrc]);
|
|
1790
|
-
anchorB.push(plB[endSrc]);
|
|
1791
|
-
anchorT.push(plT[endSrc]);
|
|
1792
|
-
idx.push(base, base + 1, base + 2, base + 1, base + 3, base + 2);
|
|
1793
|
-
}
|
|
1794
|
-
const joinCount = pl.closed ? segs.length : segs.length - 1;
|
|
1795
|
-
for (let j = 0; j < joinCount; j++) {
|
|
1796
|
-
emitJoin(segs, segBaseIdx, j, join, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT, segSrcIdx, plA, plB, plT);
|
|
1797
|
-
}
|
|
1798
|
-
if (!pl.closed && cap !== "butt") {
|
|
1799
|
-
const first = segs[0];
|
|
1800
|
-
const firstBase = segBaseIdx[0];
|
|
1801
|
-
emitCap(first, firstBase + 0, firstBase + 1, false, first.halfA, cap, verts, idx, anchorA, anchorB, anchorT, plA[0], plB[0], plT[0]);
|
|
1802
|
-
const last = segs[segs.length - 1];
|
|
1803
|
-
const lastBase = segBaseIdx[segs.length - 1];
|
|
1804
|
-
const lastSrc = segSrcIdx[segs.length - 1] + 1;
|
|
1805
|
-
emitCap(last, lastBase + 2, lastBase + 3, true, last.halfB, cap, verts, idx, anchorA, anchorB, anchorT, plA[lastSrc], plB[lastSrc], plT[lastSrc]);
|
|
1737
|
+
const lines = [];
|
|
1738
|
+
let cur = { entries: [], width: 0, height: 0 };
|
|
1739
|
+
function commitLine() {
|
|
1740
|
+
lines.push(cur);
|
|
1741
|
+
cur = { entries: [], width: 0, height: 0 };
|
|
1806
1742
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
};
|
|
1819
|
-
for (let i = 0; i < ptCount; i++) {
|
|
1820
|
-
const a = aA[i], b = aB[i], t = aT[i];
|
|
1821
|
-
if (a === b) {
|
|
1822
|
-
widths[i] = read(a);
|
|
1823
|
-
} else {
|
|
1824
|
-
const wa = read(a);
|
|
1825
|
-
const wb = read(b);
|
|
1826
|
-
widths[i] = wa + (wb - wa) * t;
|
|
1743
|
+
let i = 0;
|
|
1744
|
+
while (i < entries.length) {
|
|
1745
|
+
const e = entries[i];
|
|
1746
|
+
if (e.isNewline) {
|
|
1747
|
+
if (cur.entries.length === 0) {
|
|
1748
|
+
cur.height = Math.max(cur.height, e.fontSize * opts.lineHeight);
|
|
1749
|
+
cur.blank = e;
|
|
1750
|
+
}
|
|
1751
|
+
commitLine();
|
|
1752
|
+
i++;
|
|
1753
|
+
continue;
|
|
1827
1754
|
}
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
const cx = atEnd ? seg.bx : seg.ax;
|
|
1837
|
-
const cy = atEnd ? seg.by : seg.ay;
|
|
1838
|
-
const nx = seg.nxUnit * half;
|
|
1839
|
-
const ny = seg.nyUnit * half;
|
|
1840
|
-
if (cap === "square") {
|
|
1841
|
-
const ox = cx + dx * half;
|
|
1842
|
-
const oy = cy + dy * half;
|
|
1843
|
-
const lOut = verts.length / 2;
|
|
1844
|
-
verts.push(ox + nx, oy + ny);
|
|
1845
|
-
anchorA.push(endA);
|
|
1846
|
-
anchorB.push(endB);
|
|
1847
|
-
anchorT.push(endT);
|
|
1848
|
-
const rOut = verts.length / 2;
|
|
1849
|
-
verts.push(ox - nx, oy - ny);
|
|
1850
|
-
anchorA.push(endA);
|
|
1851
|
-
anchorB.push(endB);
|
|
1852
|
-
anchorT.push(endT);
|
|
1853
|
-
if (atEnd) {
|
|
1854
|
-
idx.push(leftIdx, lOut, rOut, leftIdx, rOut, rightIdx);
|
|
1855
|
-
} else {
|
|
1856
|
-
idx.push(leftIdx, rOut, lOut, leftIdx, rightIdx, rOut);
|
|
1755
|
+
if (e.isSpace) {
|
|
1756
|
+
if (cur.entries.length > 0) {
|
|
1757
|
+
cur.entries.push(e);
|
|
1758
|
+
cur.width += e.kerningBefore + e.advance + e.tracking;
|
|
1759
|
+
cur.height = Math.max(cur.height, e.fontSize * opts.lineHeight);
|
|
1760
|
+
}
|
|
1761
|
+
i++;
|
|
1762
|
+
continue;
|
|
1857
1763
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
anchorB.push(endB);
|
|
1865
|
-
anchorT.push(endT);
|
|
1866
|
-
const startAngle = Math.atan2(ny, nx);
|
|
1867
|
-
const sweep = atEnd ? -Math.PI : Math.PI;
|
|
1868
|
-
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_CAP_STEP_RAD));
|
|
1869
|
-
const stepAngle = sweep / steps;
|
|
1870
|
-
let prevIdx = leftIdx;
|
|
1871
|
-
for (let i = 1; i < steps; i++) {
|
|
1872
|
-
const ang = startAngle + i * stepAngle;
|
|
1873
|
-
const fx = cx + Math.cos(ang) * half;
|
|
1874
|
-
const fy = cy + Math.sin(ang) * half;
|
|
1875
|
-
const newIdx = verts.length / 2;
|
|
1876
|
-
verts.push(fx, fy);
|
|
1877
|
-
anchorA.push(endA);
|
|
1878
|
-
anchorB.push(endB);
|
|
1879
|
-
anchorT.push(endT);
|
|
1880
|
-
if (atEnd) idx.push(prevIdx, newIdx, pivotIdx);
|
|
1881
|
-
else idx.push(prevIdx, pivotIdx, newIdx);
|
|
1882
|
-
prevIdx = newIdx;
|
|
1764
|
+
let j = i;
|
|
1765
|
+
let wordWidth = 0;
|
|
1766
|
+
while (j < entries.length && !entries[j].isSpace && !entries[j].isNewline) {
|
|
1767
|
+
const w = entries[j];
|
|
1768
|
+
wordWidth += w.kerningBefore + w.advance + w.tracking;
|
|
1769
|
+
j++;
|
|
1883
1770
|
}
|
|
1884
|
-
if (
|
|
1885
|
-
|
|
1771
|
+
if (Number.isFinite(opts.maxWidth) && cur.width + wordWidth > opts.maxWidth && cur.entries.length > 0) {
|
|
1772
|
+
commitLine();
|
|
1773
|
+
}
|
|
1774
|
+
for (let k = i; k < j; k++) {
|
|
1775
|
+
const w = entries[k];
|
|
1776
|
+
const kerningBefore = cur.entries.length === 0 ? 0 : w.kerningBefore;
|
|
1777
|
+
cur.entries.push({ ...w, kerningBefore });
|
|
1778
|
+
cur.width += kerningBefore + w.advance + w.tracking;
|
|
1779
|
+
cur.height = Math.max(cur.height, w.fontSize * opts.lineHeight);
|
|
1780
|
+
}
|
|
1781
|
+
i = j;
|
|
1886
1782
|
}
|
|
1887
|
-
|
|
1888
|
-
function
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
let
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
anchorA: new Uint32Array(curA),
|
|
1906
|
-
anchorB: new Uint32Array(curB),
|
|
1907
|
-
anchorT: new Float32Array(curT)
|
|
1908
|
-
});
|
|
1783
|
+
if (cur.entries.length > 0) commitLine();
|
|
1784
|
+
function outlineFor(e) {
|
|
1785
|
+
const min = opts.outlineMinSize;
|
|
1786
|
+
if (min === void 0 || e.fontSize < min) return null;
|
|
1787
|
+
if (e.resolved.synthetic.bold) return null;
|
|
1788
|
+
const r = e.resolved.resolved;
|
|
1789
|
+
return glyphOutline(r.family, r.weight, r.style, e.cp);
|
|
1790
|
+
}
|
|
1791
|
+
const decorations = [];
|
|
1792
|
+
let span = null;
|
|
1793
|
+
function flushSpan() {
|
|
1794
|
+
const s = span;
|
|
1795
|
+
span = null;
|
|
1796
|
+
if (!s || s.x1 <= s.x0) return;
|
|
1797
|
+
const thickness = s.fontSize * DECORATION_THICKNESS;
|
|
1798
|
+
if (s.underline) {
|
|
1799
|
+
const y0 = s.baselineY + s.fontSize * UNDERLINE_OFFSET;
|
|
1800
|
+
decorations.push({ kind: "underline", x0: s.x0, y0, x1: s.x1, y1: y0 + thickness, fill: s.fill });
|
|
1909
1801
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
const
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
prevX = cx;
|
|
1941
|
-
prevY = cy;
|
|
1942
|
-
traveled = segFullLen;
|
|
1943
|
-
segLen = 0;
|
|
1944
|
-
if (dashRemaining <= 1e-9) {
|
|
1945
|
-
flushAndAdvance();
|
|
1946
|
-
if (onPhase) {
|
|
1947
|
-
curPts = [prevX, prevY];
|
|
1948
|
-
curA = [endA];
|
|
1949
|
-
curB = [endB];
|
|
1950
|
-
curT = [endT];
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
} else {
|
|
1954
|
-
const tConsume = dashRemaining / segLen;
|
|
1955
|
-
const ix = prevX + segDx * tConsume;
|
|
1956
|
-
const iy = prevY + segDy * tConsume;
|
|
1957
|
-
traveled += dashRemaining;
|
|
1958
|
-
const frac = traveled / segFullLen;
|
|
1959
|
-
let mA, mB, mT;
|
|
1960
|
-
if (startA === endA && startB === endB) {
|
|
1961
|
-
mA = startA;
|
|
1962
|
-
mB = startB;
|
|
1963
|
-
mT = startT + (endT - startT) * frac;
|
|
1802
|
+
if (s.strikethrough) {
|
|
1803
|
+
const y0 = s.baselineY + s.fontSize * STRIKETHROUGH_OFFSET;
|
|
1804
|
+
decorations.push({ kind: "strikethrough", x0: s.x0, y0, x1: s.x1, y1: y0 + thickness, fill: s.fill });
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
const lineBoxes = [];
|
|
1808
|
+
let penY = 0;
|
|
1809
|
+
let maxLineWidth = 0;
|
|
1810
|
+
const finiteWidth = Number.isFinite(opts.maxWidth) ? opts.maxWidth : 0;
|
|
1811
|
+
for (const line of lines) {
|
|
1812
|
+
const alignShift = (() => {
|
|
1813
|
+
if (opts.align === "left") return 0;
|
|
1814
|
+
if (!Number.isFinite(opts.maxWidth)) {
|
|
1815
|
+
return opts.align === "center" ? -line.width / 2 : -line.width;
|
|
1816
|
+
}
|
|
1817
|
+
const slack = finiteWidth - line.width;
|
|
1818
|
+
return opts.align === "center" ? slack / 2 : slack;
|
|
1819
|
+
})();
|
|
1820
|
+
const lineX0 = alignShift;
|
|
1821
|
+
const baselineSource = line.entries[0] ?? line.blank;
|
|
1822
|
+
const lineBaselineY = baselineSource ? penY + baselineSource.font.common.base * (baselineSource.fontSize / baselineSource.font.info.size) : penY;
|
|
1823
|
+
let penX = lineX0;
|
|
1824
|
+
for (const e of line.entries) {
|
|
1825
|
+
penX += e.kerningBefore;
|
|
1826
|
+
const step = e.advance + e.tracking;
|
|
1827
|
+
const scale2 = e.fontSize / e.font.info.size;
|
|
1828
|
+
const baselineY = penY + e.font.common.base * scale2;
|
|
1829
|
+
if (e.run.underline || e.run.strikethrough) {
|
|
1830
|
+
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)) {
|
|
1831
|
+
span.x1 = penX + step;
|
|
1964
1832
|
} else {
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
if (onPhase && curPts) {
|
|
1976
|
-
curPts.push(ix, iy);
|
|
1977
|
-
curA.push(mA);
|
|
1978
|
-
curB.push(mB);
|
|
1979
|
-
curT.push(mT);
|
|
1980
|
-
}
|
|
1981
|
-
prevX = ix;
|
|
1982
|
-
prevY = iy;
|
|
1983
|
-
segDx = cx - prevX;
|
|
1984
|
-
segDy = cy - prevY;
|
|
1985
|
-
segLen = Math.hypot(segDx, segDy);
|
|
1986
|
-
flushAndAdvance();
|
|
1987
|
-
if (onPhase) {
|
|
1988
|
-
curPts = [prevX, prevY];
|
|
1989
|
-
curA = [mA];
|
|
1990
|
-
curB = [mB];
|
|
1991
|
-
curT = [mT];
|
|
1833
|
+
flushSpan();
|
|
1834
|
+
span = {
|
|
1835
|
+
underline: e.run.underline,
|
|
1836
|
+
strikethrough: e.run.strikethrough,
|
|
1837
|
+
fill: e.run.fill,
|
|
1838
|
+
fontSize: e.fontSize,
|
|
1839
|
+
baselineY,
|
|
1840
|
+
x0: penX,
|
|
1841
|
+
x1: penX + step
|
|
1842
|
+
};
|
|
1992
1843
|
}
|
|
1844
|
+
} else {
|
|
1845
|
+
flushSpan();
|
|
1846
|
+
}
|
|
1847
|
+
const outlineD = outlineFor(e);
|
|
1848
|
+
if (outlineD !== null) {
|
|
1849
|
+
const group2 = getOrCreateGroup(ctx, e.run, e.resolved, 0, "outline");
|
|
1850
|
+
group2.glyphs.push({
|
|
1851
|
+
d: outlineD,
|
|
1852
|
+
key: `${e.resolved.resolved.family}|${e.resolved.resolved.weight}|${e.resolved.resolved.style}|${e.cp}`,
|
|
1853
|
+
x: penX,
|
|
1854
|
+
baselineY,
|
|
1855
|
+
// Em space is unit-scale, so world units per em is just the size.
|
|
1856
|
+
scale: e.fontSize
|
|
1857
|
+
});
|
|
1858
|
+
penX += step;
|
|
1859
|
+
continue;
|
|
1860
|
+
}
|
|
1861
|
+
if (e.advance === 0 || e.glyph.width === 0 || e.glyph.page < 0) {
|
|
1862
|
+
penX += step;
|
|
1863
|
+
continue;
|
|
1993
1864
|
}
|
|
1865
|
+
const group = getOrCreateGroup(ctx, e.run, e.resolved, e.glyph.page);
|
|
1866
|
+
const atlasW = e.font.common.scaleW;
|
|
1867
|
+
const atlasH = e.font.common.scaleH;
|
|
1868
|
+
const qx0 = penX + e.glyph.xoffset * scale2;
|
|
1869
|
+
const qy0 = penY + e.glyph.yoffset * scale2;
|
|
1870
|
+
const qx1 = qx0 + e.glyph.width * scale2;
|
|
1871
|
+
const qy1 = qy0 + e.glyph.height * scale2;
|
|
1872
|
+
const u0 = e.glyph.x / atlasW;
|
|
1873
|
+
const v0 = e.glyph.y / atlasH;
|
|
1874
|
+
const u1 = (e.glyph.x + e.glyph.width) / atlasW;
|
|
1875
|
+
const v1 = (e.glyph.y + e.glyph.height) / atlasH;
|
|
1876
|
+
group.quads.push({ x0: qx0, y0: qy0, x1: qx1, y1: qy1, u0, v0, u1, v1, baselineY });
|
|
1877
|
+
penX += step;
|
|
1994
1878
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
anchorT: new Float32Array(curT)
|
|
1879
|
+
flushSpan();
|
|
1880
|
+
lineBoxes.push({
|
|
1881
|
+
x0: lineX0,
|
|
1882
|
+
y0: penY,
|
|
1883
|
+
x1: lineX0 + line.width,
|
|
1884
|
+
y1: penY + line.height,
|
|
1885
|
+
baselineY: lineBaselineY
|
|
2003
1886
|
});
|
|
1887
|
+
maxLineWidth = Math.max(maxLineWidth, line.width);
|
|
1888
|
+
penY += line.height;
|
|
2004
1889
|
}
|
|
2005
|
-
return out;
|
|
2006
|
-
}
|
|
2007
|
-
function makeSeg(ax, ay, bx, by, halfA, halfB) {
|
|
2008
|
-
const dx = bx - ax, dy = by - ay;
|
|
2009
|
-
const len = Math.hypot(dx, dy);
|
|
2010
|
-
if (len === 0) return null;
|
|
2011
1890
|
return {
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
nxUnit: -dy / len,
|
|
2017
|
-
nyUnit: dx / len,
|
|
2018
|
-
halfA,
|
|
2019
|
-
halfB,
|
|
2020
|
-
len
|
|
1891
|
+
groups: [...ctx.groups.values()],
|
|
1892
|
+
decorations,
|
|
1893
|
+
lines: lineBoxes,
|
|
1894
|
+
bounds: { width: maxLineWidth, height: penY }
|
|
2021
1895
|
};
|
|
2022
1896
|
}
|
|
2023
|
-
var
|
|
2024
|
-
var
|
|
2025
|
-
function
|
|
2026
|
-
|
|
2027
|
-
const
|
|
2028
|
-
const
|
|
2029
|
-
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
const cross = adx * bdy - ady * bdx;
|
|
2033
|
-
if (cross === 0) return;
|
|
2034
|
-
const onPositive = cross > 0;
|
|
2035
|
-
const aOuterEnd = onPositive ? aBase + 3 : aBase + 2;
|
|
2036
|
-
const bOuterStart = onPositive ? bBase + 1 : bBase + 0;
|
|
2037
|
-
const nextSeg = (j + 1) % segs.length;
|
|
2038
|
-
const cornerSrc = segSrcIdx[nextSeg];
|
|
2039
|
-
const cornerA = plA[cornerSrc];
|
|
2040
|
-
const cornerB = plB[cornerSrc];
|
|
2041
|
-
const cornerT = plT[cornerSrc];
|
|
2042
|
-
const halfAtCorner = a.halfB;
|
|
2043
|
-
const taperA = Math.max(a.halfA, a.halfB) / Math.max(1e-9, Math.min(a.halfA, a.halfB));
|
|
2044
|
-
const taperB = Math.max(b.halfA, b.halfB) / Math.max(1e-9, Math.min(b.halfA, b.halfB));
|
|
2045
|
-
const forceBevelForVarying = taperA > varyingThreshold || taperB > varyingThreshold;
|
|
2046
|
-
if (join === "bevel" || forceBevelForVarying) {
|
|
2047
|
-
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2048
|
-
return;
|
|
2049
|
-
}
|
|
2050
|
-
if (join === "miter") {
|
|
2051
|
-
const aOX = verts[aOuterEnd * 2], aOY = verts[aOuterEnd * 2 + 1];
|
|
2052
|
-
const bOX = verts[bOuterStart * 2], bOY = verts[bOuterStart * 2 + 1];
|
|
2053
|
-
const apex = lineLineIntersect(aOX, aOY, adx, ady, bOX, bOY, -bdx, -bdy);
|
|
2054
|
-
if (!apex) {
|
|
2055
|
-
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2056
|
-
return;
|
|
2057
|
-
}
|
|
2058
|
-
const miterLen = Math.hypot(apex[0] - a.bx, apex[1] - a.by);
|
|
2059
|
-
if (miterLen > miterLimit * halfAtCorner) {
|
|
2060
|
-
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2061
|
-
return;
|
|
2062
|
-
}
|
|
2063
|
-
const apexIdx = verts.length / 2;
|
|
2064
|
-
verts.push(apex[0], apex[1]);
|
|
2065
|
-
anchorA.push(cornerA);
|
|
2066
|
-
anchorB.push(cornerB);
|
|
2067
|
-
anchorT.push(cornerT);
|
|
2068
|
-
const jIdx = verts.length / 2;
|
|
2069
|
-
verts.push(a.bx, a.by);
|
|
2070
|
-
anchorA.push(cornerA);
|
|
2071
|
-
anchorB.push(cornerB);
|
|
2072
|
-
anchorT.push(cornerT);
|
|
2073
|
-
if (onPositive) {
|
|
2074
|
-
idx.push(aOuterEnd, apexIdx, bOuterStart);
|
|
2075
|
-
idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
2076
|
-
} else {
|
|
2077
|
-
idx.push(aOuterEnd, bOuterStart, apexIdx);
|
|
2078
|
-
idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
2079
|
-
}
|
|
2080
|
-
return;
|
|
2081
|
-
}
|
|
2082
|
-
if (join === "round") {
|
|
2083
|
-
emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2084
|
-
return;
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
var ROUND_STEP_RAD = 10 * Math.PI / 180;
|
|
2088
|
-
function emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
2089
|
-
const cx = a.bx, cy = a.by;
|
|
2090
|
-
const pivotIdx = verts.length / 2;
|
|
2091
|
-
verts.push(cx, cy);
|
|
2092
|
-
anchorA.push(cornerA);
|
|
2093
|
-
anchorB.push(cornerB);
|
|
2094
|
-
anchorT.push(cornerT);
|
|
2095
|
-
const startX = verts[aOuterEnd * 2] - cx;
|
|
2096
|
-
const startY = verts[aOuterEnd * 2 + 1] - cy;
|
|
2097
|
-
const endX = verts[bOuterStart * 2] - cx;
|
|
2098
|
-
const endY = verts[bOuterStart * 2 + 1] - cy;
|
|
2099
|
-
const r = Math.hypot(startX, startY);
|
|
2100
|
-
const startAngle = Math.atan2(startY, startX);
|
|
2101
|
-
const endAngle = Math.atan2(endY, endX);
|
|
2102
|
-
let sweep = endAngle - startAngle;
|
|
2103
|
-
if (onPositive && sweep < 0) sweep += 2 * Math.PI;
|
|
2104
|
-
else if (!onPositive && sweep > 0) sweep -= 2 * Math.PI;
|
|
2105
|
-
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_STEP_RAD));
|
|
2106
|
-
const stepAngle = sweep / steps;
|
|
2107
|
-
let prevIdx = aOuterEnd;
|
|
2108
|
-
for (let i = 1; i < steps; i++) {
|
|
2109
|
-
const ang = startAngle + i * stepAngle;
|
|
2110
|
-
const fx = cx + Math.cos(ang) * r;
|
|
2111
|
-
const fy = cy + Math.sin(ang) * r;
|
|
2112
|
-
const newIdx = verts.length / 2;
|
|
2113
|
-
verts.push(fx, fy);
|
|
2114
|
-
anchorA.push(cornerA);
|
|
2115
|
-
anchorB.push(cornerB);
|
|
2116
|
-
anchorT.push(cornerT);
|
|
2117
|
-
if (onPositive) idx.push(prevIdx, pivotIdx, newIdx);
|
|
2118
|
-
else idx.push(prevIdx, newIdx, pivotIdx);
|
|
2119
|
-
prevIdx = newIdx;
|
|
2120
|
-
}
|
|
2121
|
-
if (onPositive) idx.push(prevIdx, pivotIdx, bOuterStart);
|
|
2122
|
-
else idx.push(prevIdx, bOuterStart, pivotIdx);
|
|
2123
|
-
}
|
|
2124
|
-
function emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
2125
|
-
const jIdx = verts.length / 2;
|
|
2126
|
-
verts.push(a.bx, a.by);
|
|
2127
|
-
anchorA.push(cornerA);
|
|
2128
|
-
anchorB.push(cornerB);
|
|
2129
|
-
anchorT.push(cornerT);
|
|
2130
|
-
if (onPositive) idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
2131
|
-
else idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
2132
|
-
}
|
|
2133
|
-
function lineLineIntersect(apx, apy, adx, ady, bpx, bpy, bdx, bdy) {
|
|
2134
|
-
const denom = adx * bdy - ady * bdx;
|
|
2135
|
-
if (Math.abs(denom) < 1e-9) return null;
|
|
2136
|
-
const t = ((bpx - apx) * bdy - (bpy - apy) * bdx) / denom;
|
|
2137
|
-
return [apx + t * adx, apy + t * ady];
|
|
1897
|
+
var LAYOUT_CACHE_VARIANT_LIMIT = 8;
|
|
1898
|
+
var cache2 = /* @__PURE__ */ new WeakMap();
|
|
1899
|
+
function outlineBucket(runs, min) {
|
|
1900
|
+
if (min === void 0) return -1;
|
|
1901
|
+
const sizes = /* @__PURE__ */ new Set();
|
|
1902
|
+
for (const r of runs) sizes.add(r.fontSize);
|
|
1903
|
+
let n = 0;
|
|
1904
|
+
for (const size of sizes) if (size >= min) n++;
|
|
1905
|
+
return n;
|
|
2138
1906
|
}
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
var DECORATION_THICKNESS = 0.05;
|
|
2142
|
-
function fillKey(p) {
|
|
2143
|
-
if ("color" in p) return `s:${p.color}:${p.opacity ?? 1}`;
|
|
2144
|
-
return `nx:${Math.random()}`;
|
|
1907
|
+
function variantKey(runs, opts) {
|
|
1908
|
+
return `${opts.maxWidth}|${opts.lineHeight}|${opts.align}|${outlineBucket(runs, opts.outlineMinSize)}`;
|
|
2145
1909
|
}
|
|
2146
|
-
function
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
1910
|
+
function cachedLayoutRuns(runs, opts) {
|
|
1911
|
+
const fonts = glyphGeneration();
|
|
1912
|
+
let entry = cache2.get(runs);
|
|
1913
|
+
if (entry === void 0) {
|
|
1914
|
+
entry = { generation: fonts, byVariant: /* @__PURE__ */ new Map() };
|
|
1915
|
+
cache2.set(runs, entry);
|
|
1916
|
+
} else if (entry.generation !== fonts) {
|
|
1917
|
+
entry.generation = fonts;
|
|
1918
|
+
entry.byVariant.clear();
|
|
2150
1919
|
}
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
s.join ?? "miter",
|
|
2159
|
-
s.cap ?? "butt",
|
|
2160
|
-
s.miterLimit ?? "",
|
|
2161
|
-
s.align ?? "center",
|
|
2162
|
-
(s.dash ?? []).join(",")
|
|
2163
|
-
].join(":");
|
|
1920
|
+
const key = variantKey(runs, opts);
|
|
1921
|
+
const hit = entry.byVariant.get(key);
|
|
1922
|
+
if (hit !== void 0) return hit;
|
|
1923
|
+
const laid = layoutRuns(runs, opts);
|
|
1924
|
+
if (entry.byVariant.size >= LAYOUT_CACHE_VARIANT_LIMIT) entry.byVariant.clear();
|
|
1925
|
+
entry.byVariant.set(key, laid);
|
|
1926
|
+
return laid;
|
|
2164
1927
|
}
|
|
2165
|
-
|
|
2166
|
-
|
|
1928
|
+
|
|
1929
|
+
// src/features/text/verticalAlign.ts
|
|
1930
|
+
function verticalAlignOffset(align, boxHeight, textHeight) {
|
|
1931
|
+
if (align === void 0 || align === "top" || boxHeight === void 0) return 0;
|
|
1932
|
+
const slack = boxHeight - textHeight;
|
|
1933
|
+
return align === "center" ? slack / 2 : slack;
|
|
2167
1934
|
}
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
const
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
g = {
|
|
2186
|
-
family: atlasFamily,
|
|
2187
|
-
weight: resolvedWeight,
|
|
2188
|
-
style: resolvedStyle,
|
|
2189
|
-
synthetic: { ...resolved.synthetic },
|
|
2190
|
-
source,
|
|
2191
|
-
page,
|
|
2192
|
-
fill: run.fill,
|
|
2193
|
-
// Only the outline tier can paint it, and carrying it on an SDF group
|
|
2194
|
-
// would be a promise the renderer cannot keep.
|
|
2195
|
-
...source === "outline" && run.stroke !== void 0 ? { stroke: run.stroke } : {},
|
|
2196
|
-
quads: [],
|
|
2197
|
-
glyphs: []
|
|
2198
|
-
};
|
|
2199
|
-
ctx.groups.set(key, g);
|
|
1935
|
+
|
|
1936
|
+
// src/features/paths/pathFromD.ts
|
|
1937
|
+
var NUM_RE = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
|
|
1938
|
+
function tokenize(d) {
|
|
1939
|
+
const out = [];
|
|
1940
|
+
let i = 0;
|
|
1941
|
+
while (i < d.length) {
|
|
1942
|
+
const ch = d[i];
|
|
1943
|
+
if (/[A-Za-z]/.test(ch)) {
|
|
1944
|
+
let j = i + 1;
|
|
1945
|
+
while (j < d.length && !/[A-Za-z]/.test(d[j])) j++;
|
|
1946
|
+
const argSlice = d.slice(i + 1, j);
|
|
1947
|
+
out.push({ cmd: ch, args: readNumbers(argSlice) });
|
|
1948
|
+
i = j;
|
|
1949
|
+
} else {
|
|
1950
|
+
i++;
|
|
1951
|
+
}
|
|
2200
1952
|
}
|
|
2201
|
-
return
|
|
1953
|
+
return out;
|
|
2202
1954
|
}
|
|
2203
|
-
function
|
|
2204
|
-
const
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
if (glyph.xadvance > 0 || glyph.width > 0) {
|
|
2211
|
-
return { glyph, font: face.font, resolved: fallback };
|
|
2212
|
-
}
|
|
1955
|
+
function readNumbers(s) {
|
|
1956
|
+
const out = [];
|
|
1957
|
+
let m;
|
|
1958
|
+
NUM_RE.lastIndex = 0;
|
|
1959
|
+
while ((m = NUM_RE.exec(s)) !== null) {
|
|
1960
|
+
const n = Number(m[0]);
|
|
1961
|
+
if (Number.isFinite(n)) out.push(n);
|
|
2213
1962
|
}
|
|
2214
|
-
|
|
2215
|
-
return null;
|
|
1963
|
+
return out;
|
|
2216
1964
|
}
|
|
2217
|
-
var
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
1965
|
+
var ARG_COUNTS = {
|
|
1966
|
+
M: 2,
|
|
1967
|
+
L: 2,
|
|
1968
|
+
H: 1,
|
|
1969
|
+
V: 1,
|
|
1970
|
+
C: 6,
|
|
1971
|
+
S: 4,
|
|
1972
|
+
Q: 4,
|
|
1973
|
+
T: 2,
|
|
1974
|
+
A: 7,
|
|
1975
|
+
Z: 0
|
|
1976
|
+
};
|
|
1977
|
+
function pathFromD(d, onWarn) {
|
|
1978
|
+
const tokens = tokenize(d);
|
|
1979
|
+
const b = new PathBuilder();
|
|
1980
|
+
const st = {
|
|
1981
|
+
x: 0,
|
|
1982
|
+
y: 0,
|
|
1983
|
+
startX: 0,
|
|
1984
|
+
startY: 0,
|
|
1985
|
+
lastCubicCtrl: null,
|
|
1986
|
+
lastQuadCtrl: null
|
|
1987
|
+
};
|
|
1988
|
+
for (const { cmd, args } of tokens) {
|
|
1989
|
+
const upper = cmd.toUpperCase();
|
|
1990
|
+
const relative = cmd !== upper;
|
|
1991
|
+
const argCount = ARG_COUNTS[upper];
|
|
1992
|
+
if (argCount === void 0) {
|
|
1993
|
+
onWarn?.(`unknown path command: ${cmd}`);
|
|
2240
1994
|
continue;
|
|
2241
1995
|
}
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
if (isNewline) {
|
|
2249
|
-
entries.push({
|
|
2250
|
-
run,
|
|
2251
|
-
font,
|
|
2252
|
-
glyph: { id: cp, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
|
|
2253
|
-
// A newline consumes no advance, so it takes no tracking either.
|
|
2254
|
-
cp,
|
|
2255
|
-
advance: 0,
|
|
2256
|
-
tracking: 0,
|
|
2257
|
-
kerningBefore: 0,
|
|
2258
|
-
isSpace: false,
|
|
2259
|
-
isNewline: true,
|
|
2260
|
-
resolved,
|
|
2261
|
-
fontSize: run.fontSize
|
|
2262
|
-
});
|
|
2263
|
-
prevCp = void 0;
|
|
2264
|
-
prevFont = void 0;
|
|
2265
|
-
prevFontSize = void 0;
|
|
2266
|
-
continue;
|
|
2267
|
-
}
|
|
2268
|
-
if (isSpace) {
|
|
2269
|
-
const spaceGlyph = resolved.dynamicFace ? resolved.dynamicFace.requestGlyph(32) : font.charMap.get(32);
|
|
2270
|
-
const advance = spaceGlyph ? spaceGlyph.xadvance * scale2 : run.fontSize * 0.25;
|
|
2271
|
-
let kerningBefore2 = 0;
|
|
2272
|
-
if (prevCp !== void 0 && prevFont !== void 0 && prevFontSize !== void 0) {
|
|
2273
|
-
const kAtlas = prevFont.kerningMap.get(prevCp)?.get(cp) ?? 0;
|
|
2274
|
-
kerningBefore2 = kAtlas * (prevFontSize / prevFont.info.size);
|
|
2275
|
-
}
|
|
2276
|
-
entries.push({
|
|
2277
|
-
run,
|
|
2278
|
-
font,
|
|
2279
|
-
glyph: spaceGlyph ?? { id: 32, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
|
|
2280
|
-
cp,
|
|
2281
|
-
advance,
|
|
2282
|
-
tracking,
|
|
2283
|
-
kerningBefore: kerningBefore2,
|
|
2284
|
-
isSpace: true,
|
|
2285
|
-
isNewline: false,
|
|
2286
|
-
resolved,
|
|
2287
|
-
fontSize: run.fontSize
|
|
2288
|
-
});
|
|
2289
|
-
prevCp = cp;
|
|
2290
|
-
prevFont = font;
|
|
2291
|
-
prevFontSize = run.fontSize;
|
|
2292
|
-
continue;
|
|
2293
|
-
}
|
|
2294
|
-
const hit = resolved.dynamicFace ? { glyph: resolved.dynamicFace.requestGlyph(cp), font, resolved } : resolveGlyph(run, font, resolved, cp);
|
|
2295
|
-
if (!hit) {
|
|
2296
|
-
prevCp = cp;
|
|
2297
|
-
prevFont = font;
|
|
2298
|
-
prevFontSize = run.fontSize;
|
|
2299
|
-
continue;
|
|
2300
|
-
}
|
|
2301
|
-
const glyphFont = hit.font;
|
|
2302
|
-
const glyphScale = run.fontSize / glyphFont.info.size;
|
|
2303
|
-
let kerningBefore = 0;
|
|
2304
|
-
if (prevCp !== void 0 && prevFont !== void 0 && prevFontSize !== void 0) {
|
|
2305
|
-
const kAtlas = prevFont.kerningMap.get(prevCp)?.get(cp) ?? 0;
|
|
2306
|
-
kerningBefore = kAtlas * (prevFontSize / prevFont.info.size);
|
|
2307
|
-
}
|
|
2308
|
-
entries.push({
|
|
2309
|
-
run,
|
|
2310
|
-
font: glyphFont,
|
|
2311
|
-
glyph: hit.glyph,
|
|
2312
|
-
cp,
|
|
2313
|
-
advance: hit.glyph.xadvance * glyphScale,
|
|
2314
|
-
tracking,
|
|
2315
|
-
kerningBefore,
|
|
2316
|
-
isSpace,
|
|
2317
|
-
isNewline: false,
|
|
2318
|
-
resolved: hit.resolved,
|
|
2319
|
-
fontSize: run.fontSize
|
|
2320
|
-
});
|
|
2321
|
-
prevCp = cp;
|
|
2322
|
-
prevFont = glyphFont;
|
|
2323
|
-
prevFontSize = run.fontSize;
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
|
-
const lines = [];
|
|
2327
|
-
let cur = { entries: [], width: 0, height: 0 };
|
|
2328
|
-
function commitLine() {
|
|
2329
|
-
lines.push(cur);
|
|
2330
|
-
cur = { entries: [], width: 0, height: 0 };
|
|
2331
|
-
}
|
|
2332
|
-
let i = 0;
|
|
2333
|
-
while (i < entries.length) {
|
|
2334
|
-
const e = entries[i];
|
|
2335
|
-
if (e.isNewline) {
|
|
2336
|
-
if (cur.entries.length === 0) {
|
|
2337
|
-
cur.height = Math.max(cur.height, e.fontSize * opts.lineHeight);
|
|
2338
|
-
cur.blank = e;
|
|
2339
|
-
}
|
|
2340
|
-
commitLine();
|
|
2341
|
-
i++;
|
|
1996
|
+
if (upper === "Z") {
|
|
1997
|
+
b.close();
|
|
1998
|
+
st.x = st.startX;
|
|
1999
|
+
st.y = st.startY;
|
|
2000
|
+
st.lastCubicCtrl = null;
|
|
2001
|
+
st.lastQuadCtrl = null;
|
|
2342
2002
|
continue;
|
|
2343
2003
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
}
|
|
2350
|
-
i++;
|
|
2351
|
-
continue;
|
|
2004
|
+
const groups = argCount === 0 ? 1 : Math.floor(args.length / argCount);
|
|
2005
|
+
for (let g = 0; g < groups; g++) {
|
|
2006
|
+
const a = args.slice(g * argCount, (g + 1) * argCount);
|
|
2007
|
+
const effectiveUpper = upper === "M" && g > 0 ? "L" : upper;
|
|
2008
|
+
runCommand(effectiveUpper, relative, a, st, b);
|
|
2352
2009
|
}
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2010
|
+
}
|
|
2011
|
+
return b.build();
|
|
2012
|
+
}
|
|
2013
|
+
function runCommand(upper, relative, a, st, b) {
|
|
2014
|
+
const rx = relative ? st.x : 0;
|
|
2015
|
+
const ry = relative ? st.y : 0;
|
|
2016
|
+
switch (upper) {
|
|
2017
|
+
case "M": {
|
|
2018
|
+
const x = a[0] + rx;
|
|
2019
|
+
const y = a[1] + ry;
|
|
2020
|
+
b.moveTo(x, y);
|
|
2021
|
+
st.x = x;
|
|
2022
|
+
st.y = y;
|
|
2023
|
+
st.startX = x;
|
|
2024
|
+
st.startY = y;
|
|
2025
|
+
st.lastCubicCtrl = null;
|
|
2026
|
+
st.lastQuadCtrl = null;
|
|
2027
|
+
return;
|
|
2359
2028
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2029
|
+
case "L": {
|
|
2030
|
+
const x = a[0] + rx;
|
|
2031
|
+
const y = a[1] + ry;
|
|
2032
|
+
b.lineTo(x, y);
|
|
2033
|
+
st.x = x;
|
|
2034
|
+
st.y = y;
|
|
2035
|
+
st.lastCubicCtrl = null;
|
|
2036
|
+
st.lastQuadCtrl = null;
|
|
2037
|
+
return;
|
|
2362
2038
|
}
|
|
2363
|
-
|
|
2364
|
-
const
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2039
|
+
case "H": {
|
|
2040
|
+
const x = a[0] + (relative ? st.x : 0);
|
|
2041
|
+
b.lineTo(x, st.y);
|
|
2042
|
+
st.x = x;
|
|
2043
|
+
st.lastCubicCtrl = null;
|
|
2044
|
+
st.lastQuadCtrl = null;
|
|
2045
|
+
return;
|
|
2369
2046
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
const r = e.resolved.resolved;
|
|
2378
|
-
return glyphOutline(r.family, r.weight, r.style, e.cp);
|
|
2379
|
-
}
|
|
2380
|
-
const decorations = [];
|
|
2381
|
-
let span = null;
|
|
2382
|
-
function flushSpan() {
|
|
2383
|
-
const s = span;
|
|
2384
|
-
span = null;
|
|
2385
|
-
if (!s || s.x1 <= s.x0) return;
|
|
2386
|
-
const thickness = s.fontSize * DECORATION_THICKNESS;
|
|
2387
|
-
if (s.underline) {
|
|
2388
|
-
const y0 = s.baselineY + s.fontSize * UNDERLINE_OFFSET;
|
|
2389
|
-
decorations.push({ kind: "underline", x0: s.x0, y0, x1: s.x1, y1: y0 + thickness, fill: s.fill });
|
|
2047
|
+
case "V": {
|
|
2048
|
+
const y = a[0] + (relative ? st.y : 0);
|
|
2049
|
+
b.lineTo(st.x, y);
|
|
2050
|
+
st.y = y;
|
|
2051
|
+
st.lastCubicCtrl = null;
|
|
2052
|
+
st.lastQuadCtrl = null;
|
|
2053
|
+
return;
|
|
2390
2054
|
}
|
|
2391
|
-
|
|
2392
|
-
const
|
|
2393
|
-
|
|
2055
|
+
case "C": {
|
|
2056
|
+
const x1 = a[0] + rx, y1 = a[1] + ry;
|
|
2057
|
+
const x2 = a[2] + rx, y2 = a[3] + ry;
|
|
2058
|
+
const x = a[4] + rx, y = a[5] + ry;
|
|
2059
|
+
b.curveTo(x1, y1, x2, y2, x, y);
|
|
2060
|
+
st.x = x;
|
|
2061
|
+
st.y = y;
|
|
2062
|
+
st.lastCubicCtrl = { x: x2, y: y2 };
|
|
2063
|
+
st.lastQuadCtrl = null;
|
|
2064
|
+
return;
|
|
2394
2065
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2066
|
+
case "S": {
|
|
2067
|
+
const ref = st.lastCubicCtrl ?? { x: st.x, y: st.y };
|
|
2068
|
+
const x1 = 2 * st.x - ref.x;
|
|
2069
|
+
const y1 = 2 * st.y - ref.y;
|
|
2070
|
+
const x2 = a[0] + rx, y2 = a[1] + ry;
|
|
2071
|
+
const x = a[2] + rx, y = a[3] + ry;
|
|
2072
|
+
b.curveTo(x1, y1, x2, y2, x, y);
|
|
2073
|
+
st.x = x;
|
|
2074
|
+
st.y = y;
|
|
2075
|
+
st.lastCubicCtrl = { x: x2, y: y2 };
|
|
2076
|
+
st.lastQuadCtrl = null;
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
case "Q": {
|
|
2080
|
+
const x1 = a[0] + rx, y1 = a[1] + ry;
|
|
2081
|
+
const x = a[2] + rx, y = a[3] + ry;
|
|
2082
|
+
b.quadTo(x1, y1, x, y);
|
|
2083
|
+
st.x = x;
|
|
2084
|
+
st.y = y;
|
|
2085
|
+
st.lastQuadCtrl = { x: x1, y: y1 };
|
|
2086
|
+
st.lastCubicCtrl = null;
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
case "T": {
|
|
2090
|
+
const ref = st.lastQuadCtrl ?? { x: st.x, y: st.y };
|
|
2091
|
+
const x1 = 2 * st.x - ref.x;
|
|
2092
|
+
const y1 = 2 * st.y - ref.y;
|
|
2093
|
+
const x = a[0] + rx, y = a[1] + ry;
|
|
2094
|
+
b.quadTo(x1, y1, x, y);
|
|
2095
|
+
st.x = x;
|
|
2096
|
+
st.y = y;
|
|
2097
|
+
st.lastQuadCtrl = { x: x1, y: y1 };
|
|
2098
|
+
st.lastCubicCtrl = null;
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
case "A": {
|
|
2102
|
+
const rxA = Math.abs(a[0]);
|
|
2103
|
+
const ryA = Math.abs(a[1]);
|
|
2104
|
+
const xRot = a[2];
|
|
2105
|
+
const largeArc = a[3] !== 0;
|
|
2106
|
+
const sweep = a[4] !== 0;
|
|
2107
|
+
const ex = a[5] + rx;
|
|
2108
|
+
const ey = a[6] + ry;
|
|
2109
|
+
arcToCubics(st.x, st.y, ex, ey, rxA, ryA, xRot, largeArc, sweep, b);
|
|
2110
|
+
st.x = ex;
|
|
2111
|
+
st.y = ey;
|
|
2112
|
+
st.lastCubicCtrl = null;
|
|
2113
|
+
st.lastQuadCtrl = null;
|
|
2114
|
+
return;
|
|
2115
|
+
}
|
|
2116
|
+
default:
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep, b) {
|
|
2121
|
+
if (x1 === x2 && y1 === y2) return;
|
|
2122
|
+
if (rx === 0 || ry === 0) {
|
|
2123
|
+
b.lineTo(x2, y2);
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2126
|
+
const phi = xAxisRotationDeg * Math.PI / 180;
|
|
2127
|
+
const cosPhi = Math.cos(phi);
|
|
2128
|
+
const sinPhi = Math.sin(phi);
|
|
2129
|
+
const dx = (x1 - x2) / 2;
|
|
2130
|
+
const dy = (y1 - y2) / 2;
|
|
2131
|
+
const x1p = cosPhi * dx + sinPhi * dy;
|
|
2132
|
+
const y1p = -sinPhi * dx + cosPhi * dy;
|
|
2133
|
+
let rxs = rx * rx;
|
|
2134
|
+
let rys = ry * ry;
|
|
2135
|
+
const x1ps = x1p * x1p;
|
|
2136
|
+
const y1ps = y1p * y1p;
|
|
2137
|
+
const lambda = x1ps / rxs + y1ps / rys;
|
|
2138
|
+
let rxFixed = rx;
|
|
2139
|
+
let ryFixed = ry;
|
|
2140
|
+
if (lambda > 1) {
|
|
2141
|
+
const sqrtLambda = Math.sqrt(lambda);
|
|
2142
|
+
rxFixed = sqrtLambda * rx;
|
|
2143
|
+
ryFixed = sqrtLambda * ry;
|
|
2144
|
+
rxs = rxFixed * rxFixed;
|
|
2145
|
+
rys = ryFixed * ryFixed;
|
|
2146
|
+
}
|
|
2147
|
+
const sign = largeArc === sweep ? -1 : 1;
|
|
2148
|
+
const num = rxs * rys - rxs * y1ps - rys * x1ps;
|
|
2149
|
+
const den = rxs * y1ps + rys * x1ps;
|
|
2150
|
+
const factor = sign * Math.sqrt(Math.max(0, num / den));
|
|
2151
|
+
const cxp = factor * (rxFixed * y1p) / ryFixed;
|
|
2152
|
+
const cyp = factor * -(ryFixed * x1p) / rxFixed;
|
|
2153
|
+
const cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2;
|
|
2154
|
+
const cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2;
|
|
2155
|
+
const angle = (ux, uy, vx, vy) => {
|
|
2156
|
+
const dot = ux * vx + uy * vy;
|
|
2157
|
+
const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
|
|
2158
|
+
let a = Math.acos(Math.max(-1, Math.min(1, dot / len)));
|
|
2159
|
+
if (ux * vy - uy * vx < 0) a = -a;
|
|
2160
|
+
return a;
|
|
2161
|
+
};
|
|
2162
|
+
const theta1 = angle(1, 0, (x1p - cxp) / rxFixed, (y1p - cyp) / ryFixed);
|
|
2163
|
+
let dTheta = angle(
|
|
2164
|
+
(x1p - cxp) / rxFixed,
|
|
2165
|
+
(y1p - cyp) / ryFixed,
|
|
2166
|
+
(-x1p - cxp) / rxFixed,
|
|
2167
|
+
(-y1p - cyp) / ryFixed
|
|
2168
|
+
);
|
|
2169
|
+
if (!sweep && dTheta > 0) dTheta -= 2 * Math.PI;
|
|
2170
|
+
else if (sweep && dTheta < 0) dTheta += 2 * Math.PI;
|
|
2171
|
+
const segCount = Math.max(1, Math.ceil(Math.abs(dTheta) / (Math.PI / 2)));
|
|
2172
|
+
const segAngle = dTheta / segCount;
|
|
2173
|
+
const t = 4 / 3 * Math.tan(segAngle / 4);
|
|
2174
|
+
let prevX = x1;
|
|
2175
|
+
let prevY = y1;
|
|
2176
|
+
let prevDx = -Math.sin(theta1) * rxFixed;
|
|
2177
|
+
let prevDy = Math.cos(theta1) * ryFixed;
|
|
2178
|
+
for (let i = 1; i <= segCount; i++) {
|
|
2179
|
+
const theta = theta1 + i * segAngle;
|
|
2180
|
+
const cosT = Math.cos(theta);
|
|
2181
|
+
const sinT = Math.sin(theta);
|
|
2182
|
+
const px = cosPhi * (cosT * rxFixed) - sinPhi * (sinT * ryFixed) + cx;
|
|
2183
|
+
const py = sinPhi * (cosT * rxFixed) + cosPhi * (sinT * ryFixed) + cy;
|
|
2184
|
+
const dxNew = -sinT * rxFixed;
|
|
2185
|
+
const dyNew = cosT * ryFixed;
|
|
2186
|
+
const c1x = prevX + cosPhi * (t * prevDx) - sinPhi * (t * prevDy);
|
|
2187
|
+
const c1y = prevY + sinPhi * (t * prevDx) + cosPhi * (t * prevDy);
|
|
2188
|
+
const c2x = px - cosPhi * (t * dxNew) + sinPhi * (t * dyNew);
|
|
2189
|
+
const c2y = py - sinPhi * (t * dxNew) - cosPhi * (t * dyNew);
|
|
2190
|
+
b.curveTo(c1x, c1y, c2x, c2y, px, py);
|
|
2191
|
+
prevX = px;
|
|
2192
|
+
prevY = py;
|
|
2193
|
+
prevDx = dxNew;
|
|
2194
|
+
prevDy = dyNew;
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
// src/renderer/cache/outlineMeshCache.ts
|
|
2199
|
+
var OUTLINE_FLATTEN_TOLERANCE = 1 / 4096;
|
|
2200
|
+
var OUTLINE_MESH_CACHE_LIMIT = 2048;
|
|
2201
|
+
var cache3 = /* @__PURE__ */ new Map();
|
|
2202
|
+
function outlineMesh(key, d) {
|
|
2203
|
+
const cached = cache3.get(key);
|
|
2204
|
+
if (cached !== void 0) return cached;
|
|
2205
|
+
if (cache3.size >= OUTLINE_MESH_CACHE_LIMIT) cache3 = /* @__PURE__ */ new Map();
|
|
2206
|
+
const mesh = tessellate(pathFromD(d), { flattenTolerance: OUTLINE_FLATTEN_TOLERANCE });
|
|
2207
|
+
cache3.set(key, mesh);
|
|
2208
|
+
return mesh;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
// src/features/paths/tessellate/polyline.ts
|
|
2212
|
+
function extractPolylines(path, opts = {}) {
|
|
2213
|
+
if (path.kind === "rect") return [extractRect(path)];
|
|
2214
|
+
return extractPolygon(path, opts);
|
|
2215
|
+
}
|
|
2216
|
+
function extractRect(p) {
|
|
2217
|
+
const { x, y, width: w, height: h } = p;
|
|
2218
|
+
return {
|
|
2219
|
+
points: [x, y, x + w, y, x + w, y + h, x, y + h],
|
|
2220
|
+
closed: true,
|
|
2221
|
+
anchorA: new Uint32Array([0, 1, 2, 3]),
|
|
2222
|
+
anchorB: new Uint32Array([0, 1, 2, 3]),
|
|
2223
|
+
anchorT: new Float32Array([0, 0, 0, 0])
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
function extractPolygon(p, opts) {
|
|
2227
|
+
const tolerance = opts.flattenTolerance ?? DEFAULT_FLATTEN_TOLERANCE;
|
|
2228
|
+
const { commands, coords } = p;
|
|
2229
|
+
const out = [];
|
|
2230
|
+
let anchorCounter = 0;
|
|
2231
|
+
let pts = null;
|
|
2232
|
+
let aA = null;
|
|
2233
|
+
let aB = null;
|
|
2234
|
+
let aT = null;
|
|
2235
|
+
let current = null;
|
|
2236
|
+
let coordIdx = 0;
|
|
2237
|
+
let prevX = 0;
|
|
2238
|
+
let prevY = 0;
|
|
2239
|
+
let prevAnchor = -1;
|
|
2240
|
+
const beginContour = () => {
|
|
2241
|
+
pts = [];
|
|
2242
|
+
aA = [];
|
|
2243
|
+
aB = [];
|
|
2244
|
+
aT = [];
|
|
2245
|
+
const next = { points: pts, closed: false };
|
|
2246
|
+
out.push(next);
|
|
2247
|
+
return next;
|
|
2248
|
+
};
|
|
2249
|
+
const dropDuplicateClosingPoint = () => {
|
|
2250
|
+
if (!pts || !aA || !aB || !aT) return;
|
|
2251
|
+
const n = pts.length / 2;
|
|
2252
|
+
if (n < 2) return;
|
|
2253
|
+
if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;
|
|
2254
|
+
pts.length -= 2;
|
|
2255
|
+
aA.length -= 1;
|
|
2256
|
+
aB.length -= 1;
|
|
2257
|
+
aT.length -= 1;
|
|
2258
|
+
};
|
|
2259
|
+
const commit = (target) => {
|
|
2260
|
+
if (!pts || !aA || !aB || !aT) return;
|
|
2261
|
+
target.anchorA = new Uint32Array(aA);
|
|
2262
|
+
target.anchorB = new Uint32Array(aB);
|
|
2263
|
+
target.anchorT = new Float32Array(aT);
|
|
2264
|
+
};
|
|
2265
|
+
for (let cmdIdx = 0; cmdIdx < commands.length; cmdIdx++) {
|
|
2266
|
+
const cmd = commands[cmdIdx];
|
|
2267
|
+
switch (cmd) {
|
|
2268
|
+
case PATH_M: {
|
|
2269
|
+
if (current) commit(current);
|
|
2270
|
+
current = beginContour();
|
|
2271
|
+
prevX = coords[coordIdx];
|
|
2272
|
+
prevY = coords[coordIdx + 1];
|
|
2273
|
+
pts.push(prevX, prevY);
|
|
2274
|
+
aA.push(anchorCounter);
|
|
2275
|
+
aB.push(anchorCounter);
|
|
2276
|
+
aT.push(0);
|
|
2277
|
+
prevAnchor = anchorCounter;
|
|
2278
|
+
anchorCounter++;
|
|
2279
|
+
coordIdx += 2;
|
|
2280
|
+
break;
|
|
2405
2281
|
}
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
x0: penX,
|
|
2430
|
-
x1: penX + step
|
|
2431
|
-
};
|
|
2282
|
+
case PATH_L: {
|
|
2283
|
+
prevX = coords[coordIdx];
|
|
2284
|
+
prevY = coords[coordIdx + 1];
|
|
2285
|
+
pts.push(prevX, prevY);
|
|
2286
|
+
aA.push(anchorCounter);
|
|
2287
|
+
aB.push(anchorCounter);
|
|
2288
|
+
aT.push(0);
|
|
2289
|
+
prevAnchor = anchorCounter;
|
|
2290
|
+
anchorCounter++;
|
|
2291
|
+
coordIdx += 2;
|
|
2292
|
+
break;
|
|
2293
|
+
}
|
|
2294
|
+
case PATH_Q: {
|
|
2295
|
+
const cx = coords[coordIdx], cy = coords[coordIdx + 1];
|
|
2296
|
+
const ex = coords[coordIdx + 2], ey = coords[coordIdx + 3];
|
|
2297
|
+
const targetAnchor = anchorCounter;
|
|
2298
|
+
const segStart = pts.length / 2;
|
|
2299
|
+
const arcAccum = [];
|
|
2300
|
+
const total = flattenQuadraticWithArcLen(prevX, prevY, cx, cy, ex, ey, tolerance, pts, arcAccum);
|
|
2301
|
+
for (let k = 0; k < arcAccum.length; k++) {
|
|
2302
|
+
aA.push(prevAnchor);
|
|
2303
|
+
aB.push(targetAnchor);
|
|
2304
|
+
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
2432
2305
|
}
|
|
2433
|
-
|
|
2434
|
-
|
|
2306
|
+
const lastIdx = segStart + arcAccum.length - 1;
|
|
2307
|
+
aA[lastIdx] = targetAnchor;
|
|
2308
|
+
aB[lastIdx] = targetAnchor;
|
|
2309
|
+
aT[lastIdx] = 0;
|
|
2310
|
+
prevX = ex;
|
|
2311
|
+
prevY = ey;
|
|
2312
|
+
prevAnchor = targetAnchor;
|
|
2313
|
+
anchorCounter++;
|
|
2314
|
+
coordIdx += 4;
|
|
2315
|
+
break;
|
|
2435
2316
|
}
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
const
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2317
|
+
case PATH_C: {
|
|
2318
|
+
const c1x = coords[coordIdx], c1y = coords[coordIdx + 1];
|
|
2319
|
+
const c2x = coords[coordIdx + 2], c2y = coords[coordIdx + 3];
|
|
2320
|
+
const ex = coords[coordIdx + 4], ey = coords[coordIdx + 5];
|
|
2321
|
+
const targetAnchor = anchorCounter;
|
|
2322
|
+
const segStart = pts.length / 2;
|
|
2323
|
+
const arcAccum = [];
|
|
2324
|
+
const total = flattenCubicWithArcLen(prevX, prevY, c1x, c1y, c2x, c2y, ex, ey, tolerance, pts, arcAccum);
|
|
2325
|
+
for (let k = 0; k < arcAccum.length; k++) {
|
|
2326
|
+
aA.push(prevAnchor);
|
|
2327
|
+
aB.push(targetAnchor);
|
|
2328
|
+
aT.push(total > 0 ? arcAccum[k] / total : 0);
|
|
2329
|
+
}
|
|
2330
|
+
const lastIdx = segStart + arcAccum.length - 1;
|
|
2331
|
+
aA[lastIdx] = targetAnchor;
|
|
2332
|
+
aB[lastIdx] = targetAnchor;
|
|
2333
|
+
aT[lastIdx] = 0;
|
|
2334
|
+
prevX = ex;
|
|
2335
|
+
prevY = ey;
|
|
2336
|
+
prevAnchor = targetAnchor;
|
|
2337
|
+
anchorCounter++;
|
|
2338
|
+
coordIdx += 6;
|
|
2339
|
+
break;
|
|
2449
2340
|
}
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2341
|
+
case PATH_Z: {
|
|
2342
|
+
if (current) {
|
|
2343
|
+
current.closed = true;
|
|
2344
|
+
dropDuplicateClosingPoint();
|
|
2345
|
+
}
|
|
2346
|
+
break;
|
|
2453
2347
|
}
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2348
|
+
default:
|
|
2349
|
+
throw new Error(`extractPolylines: unknown command code ${cmd}`);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
if (current) commit(current);
|
|
2353
|
+
return out;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
// src/features/paths/tessellate/stroke.ts
|
|
2357
|
+
var EMPTY_MESH = {
|
|
2358
|
+
vertices: new Float32Array(0),
|
|
2359
|
+
indices: new Uint32Array(0),
|
|
2360
|
+
anchorA: new Uint32Array(0),
|
|
2361
|
+
anchorB: new Uint32Array(0),
|
|
2362
|
+
anchorT: new Float32Array(0)
|
|
2363
|
+
};
|
|
2364
|
+
function tessellateStroke(path, stroke, opts = {}) {
|
|
2365
|
+
const width = stroke.width ?? 1;
|
|
2366
|
+
if (width <= 0) return EMPTY_MESH;
|
|
2367
|
+
const join = stroke.join ?? "miter";
|
|
2368
|
+
const cap = stroke.cap ?? "butt";
|
|
2369
|
+
const align = stroke.align ?? "center";
|
|
2370
|
+
const miterLimit = stroke.miterLimit ?? DEFAULT_MITER_LIMIT;
|
|
2371
|
+
const varyingThreshold = stroke.varyingWidthJoinThreshold ?? DEFAULT_VARYING_WIDTH_JOIN_THRESHOLD;
|
|
2372
|
+
let workingPath = path;
|
|
2373
|
+
if (path.kind === "rect" && align !== "center") {
|
|
2374
|
+
const aligned = alignedStrokeRect(path, align, width);
|
|
2375
|
+
workingPath = {
|
|
2376
|
+
kind: "rect",
|
|
2377
|
+
x: aligned.x,
|
|
2378
|
+
y: aligned.y,
|
|
2379
|
+
width: aligned.width,
|
|
2380
|
+
height: aligned.height
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
const polylines = extractPolylines(workingPath, opts);
|
|
2384
|
+
if (stroke.vertexWidths && stroke.vertexWidths.length > 0) {
|
|
2385
|
+
for (const pl of polylines) populatePolylineWidths(pl, stroke.vertexWidths, width);
|
|
2386
|
+
}
|
|
2387
|
+
const dash = stroke.dash ?? [];
|
|
2388
|
+
const verts = [];
|
|
2389
|
+
const idx = [];
|
|
2390
|
+
const anchorA = [];
|
|
2391
|
+
const anchorB = [];
|
|
2392
|
+
const anchorT = [];
|
|
2393
|
+
for (const pl of polylines) {
|
|
2394
|
+
const subs = dash.length > 0 ? splitForDash(pl, dash) : [pl];
|
|
2395
|
+
for (const sub2 of subs) {
|
|
2396
|
+
expandPolyline(sub2, width, join, cap, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT);
|
|
2467
2397
|
}
|
|
2468
|
-
flushSpan();
|
|
2469
|
-
lineBoxes.push({
|
|
2470
|
-
x0: lineX0,
|
|
2471
|
-
y0: penY,
|
|
2472
|
-
x1: lineX0 + line.width,
|
|
2473
|
-
y1: penY + line.height,
|
|
2474
|
-
baselineY: lineBaselineY
|
|
2475
|
-
});
|
|
2476
|
-
maxLineWidth = Math.max(maxLineWidth, line.width);
|
|
2477
|
-
penY += line.height;
|
|
2478
2398
|
}
|
|
2479
2399
|
return {
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2400
|
+
vertices: new Float32Array(verts),
|
|
2401
|
+
indices: new Uint32Array(idx),
|
|
2402
|
+
anchorA: new Uint32Array(anchorA),
|
|
2403
|
+
anchorB: new Uint32Array(anchorB),
|
|
2404
|
+
anchorT: new Float32Array(anchorT)
|
|
2484
2405
|
};
|
|
2485
2406
|
}
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
const
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
entry.generation = fonts;
|
|
2507
|
-
entry.byVariant.clear();
|
|
2407
|
+
function expandPolyline(pl, width, join, cap, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT) {
|
|
2408
|
+
const half = width / 2;
|
|
2409
|
+
const pts = pl.points;
|
|
2410
|
+
const ptCount = pts.length / 2;
|
|
2411
|
+
const segCount = ptCount - 1;
|
|
2412
|
+
if (segCount < 1) return;
|
|
2413
|
+
const plA = pl.anchorA ?? new Uint32Array(ptCount);
|
|
2414
|
+
const plB = pl.anchorB ?? new Uint32Array(ptCount);
|
|
2415
|
+
const plT = pl.anchorT ?? new Float32Array(ptCount);
|
|
2416
|
+
const plHalf = pl.widths ? pl.widths.map((w) => w / 2) : null;
|
|
2417
|
+
const segs = [];
|
|
2418
|
+
const segSrcIdx = [];
|
|
2419
|
+
for (let s = 0; s < segCount; s++) {
|
|
2420
|
+
const ha = plHalf ? plHalf[s] : half;
|
|
2421
|
+
const hb = plHalf ? plHalf[s + 1] : half;
|
|
2422
|
+
const seg = makeSeg(pts[s * 2], pts[s * 2 + 1], pts[(s + 1) * 2], pts[(s + 1) * 2 + 1], ha, hb);
|
|
2423
|
+
if (seg) {
|
|
2424
|
+
segs.push(seg);
|
|
2425
|
+
segSrcIdx.push(s);
|
|
2426
|
+
}
|
|
2508
2427
|
}
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
if (align === void 0 || align === "top" || boxHeight === void 0) return 0;
|
|
2521
|
-
const slack = boxHeight - textHeight;
|
|
2522
|
-
return align === "center" ? slack / 2 : slack;
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
|
-
// src/features/paths/pathFromD.ts
|
|
2526
|
-
var NUM_RE = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
|
|
2527
|
-
function tokenize(d) {
|
|
2528
|
-
const out = [];
|
|
2529
|
-
let i = 0;
|
|
2530
|
-
while (i < d.length) {
|
|
2531
|
-
const ch = d[i];
|
|
2532
|
-
if (/[A-Za-z]/.test(ch)) {
|
|
2533
|
-
let j = i + 1;
|
|
2534
|
-
while (j < d.length && !/[A-Za-z]/.test(d[j])) j++;
|
|
2535
|
-
const argSlice = d.slice(i + 1, j);
|
|
2536
|
-
out.push({ cmd: ch, args: readNumbers(argSlice) });
|
|
2537
|
-
i = j;
|
|
2538
|
-
} else {
|
|
2539
|
-
i++;
|
|
2428
|
+
let closerSrcIdx = -1;
|
|
2429
|
+
if (pl.closed && segs.length >= 1) {
|
|
2430
|
+
const last = segs[segs.length - 1];
|
|
2431
|
+
const first = segs[0];
|
|
2432
|
+
const haCloser = plHalf ? plHalf[ptCount - 1] : half;
|
|
2433
|
+
const hbCloser = plHalf ? plHalf[0] : half;
|
|
2434
|
+
const closer = makeSeg(last.bx, last.by, first.ax, first.ay, haCloser, hbCloser);
|
|
2435
|
+
if (closer) {
|
|
2436
|
+
segs.push(closer);
|
|
2437
|
+
closerSrcIdx = ptCount - 1;
|
|
2438
|
+
segSrcIdx.push(closerSrcIdx);
|
|
2540
2439
|
}
|
|
2541
2440
|
}
|
|
2542
|
-
return
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2441
|
+
if (segs.length === 0) return;
|
|
2442
|
+
const segBaseIdx = [];
|
|
2443
|
+
for (let s = 0; s < segs.length; s++) {
|
|
2444
|
+
const seg = segs[s];
|
|
2445
|
+
const startSrc = segSrcIdx[s];
|
|
2446
|
+
const endSrc = s === segs.length - 1 && pl.closed && closerSrcIdx >= 0 ? 0 : startSrc + 1;
|
|
2447
|
+
const base = verts.length / 2;
|
|
2448
|
+
segBaseIdx.push(base);
|
|
2449
|
+
const nxA = seg.nxUnit * seg.halfA, nyA = seg.nyUnit * seg.halfA;
|
|
2450
|
+
const nxB = seg.nxUnit * seg.halfB, nyB = seg.nyUnit * seg.halfB;
|
|
2451
|
+
verts.push(seg.ax + nxA, seg.ay + nyA);
|
|
2452
|
+
anchorA.push(plA[startSrc]);
|
|
2453
|
+
anchorB.push(plB[startSrc]);
|
|
2454
|
+
anchorT.push(plT[startSrc]);
|
|
2455
|
+
verts.push(seg.ax - nxA, seg.ay - nyA);
|
|
2456
|
+
anchorA.push(plA[startSrc]);
|
|
2457
|
+
anchorB.push(plB[startSrc]);
|
|
2458
|
+
anchorT.push(plT[startSrc]);
|
|
2459
|
+
verts.push(seg.bx + nxB, seg.by + nyB);
|
|
2460
|
+
anchorA.push(plA[endSrc]);
|
|
2461
|
+
anchorB.push(plB[endSrc]);
|
|
2462
|
+
anchorT.push(plT[endSrc]);
|
|
2463
|
+
verts.push(seg.bx - nxB, seg.by - nyB);
|
|
2464
|
+
anchorA.push(plA[endSrc]);
|
|
2465
|
+
anchorB.push(plB[endSrc]);
|
|
2466
|
+
anchorT.push(plT[endSrc]);
|
|
2467
|
+
idx.push(base, base + 1, base + 2, base + 1, base + 3, base + 2);
|
|
2468
|
+
}
|
|
2469
|
+
const joinCount = pl.closed ? segs.length : segs.length - 1;
|
|
2470
|
+
for (let j = 0; j < joinCount; j++) {
|
|
2471
|
+
emitJoin(segs, segBaseIdx, j, join, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT, segSrcIdx, plA, plB, plT);
|
|
2472
|
+
}
|
|
2473
|
+
if (!pl.closed && cap !== "butt") {
|
|
2474
|
+
const first = segs[0];
|
|
2475
|
+
const firstBase = segBaseIdx[0];
|
|
2476
|
+
emitCap(first, firstBase + 0, firstBase + 1, false, first.halfA, cap, verts, idx, anchorA, anchorB, anchorT, plA[0], plB[0], plT[0]);
|
|
2477
|
+
const last = segs[segs.length - 1];
|
|
2478
|
+
const lastBase = segBaseIdx[segs.length - 1];
|
|
2479
|
+
const lastSrc = segSrcIdx[segs.length - 1] + 1;
|
|
2480
|
+
emitCap(last, lastBase + 2, lastBase + 3, true, last.halfB, cap, verts, idx, anchorA, anchorB, anchorT, plA[lastSrc], plB[lastSrc], plT[lastSrc]);
|
|
2551
2481
|
}
|
|
2552
|
-
return out;
|
|
2553
2482
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
Z: 0
|
|
2565
|
-
};
|
|
2566
|
-
function pathFromD(d, onWarn) {
|
|
2567
|
-
const tokens = tokenize(d);
|
|
2568
|
-
const b = new PathBuilder();
|
|
2569
|
-
const st = {
|
|
2570
|
-
x: 0,
|
|
2571
|
-
y: 0,
|
|
2572
|
-
startX: 0,
|
|
2573
|
-
startY: 0,
|
|
2574
|
-
lastCubicCtrl: null,
|
|
2575
|
-
lastQuadCtrl: null
|
|
2483
|
+
function populatePolylineWidths(pl, vertexWidths, fallbackWidth) {
|
|
2484
|
+
const ptCount = pl.points.length / 2;
|
|
2485
|
+
if (ptCount === 0) return;
|
|
2486
|
+
const aA = pl.anchorA ?? new Uint32Array(ptCount);
|
|
2487
|
+
const aB = pl.anchorB ?? new Uint32Array(ptCount);
|
|
2488
|
+
const aT = pl.anchorT ?? new Float32Array(ptCount);
|
|
2489
|
+
const widths = new Float32Array(ptCount);
|
|
2490
|
+
const read = (i) => {
|
|
2491
|
+
const v = vertexWidths[i];
|
|
2492
|
+
return typeof v === "number" && isFinite(v) && v > 0 ? v : fallbackWidth;
|
|
2576
2493
|
};
|
|
2577
|
-
for (
|
|
2578
|
-
const
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
if (upper === "Z") {
|
|
2586
|
-
b.close();
|
|
2587
|
-
st.x = st.startX;
|
|
2588
|
-
st.y = st.startY;
|
|
2589
|
-
st.lastCubicCtrl = null;
|
|
2590
|
-
st.lastQuadCtrl = null;
|
|
2591
|
-
continue;
|
|
2592
|
-
}
|
|
2593
|
-
const groups = argCount === 0 ? 1 : Math.floor(args.length / argCount);
|
|
2594
|
-
for (let g = 0; g < groups; g++) {
|
|
2595
|
-
const a = args.slice(g * argCount, (g + 1) * argCount);
|
|
2596
|
-
const effectiveUpper = upper === "M" && g > 0 ? "L" : upper;
|
|
2597
|
-
runCommand(effectiveUpper, relative, a, st, b);
|
|
2494
|
+
for (let i = 0; i < ptCount; i++) {
|
|
2495
|
+
const a = aA[i], b = aB[i], t = aT[i];
|
|
2496
|
+
if (a === b) {
|
|
2497
|
+
widths[i] = read(a);
|
|
2498
|
+
} else {
|
|
2499
|
+
const wa = read(a);
|
|
2500
|
+
const wb = read(b);
|
|
2501
|
+
widths[i] = wa + (wb - wa) * t;
|
|
2598
2502
|
}
|
|
2599
2503
|
}
|
|
2600
|
-
|
|
2504
|
+
pl.widths = widths;
|
|
2601
2505
|
}
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
const
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
case "H": {
|
|
2629
|
-
const x = a[0] + (relative ? st.x : 0);
|
|
2630
|
-
b.lineTo(x, st.y);
|
|
2631
|
-
st.x = x;
|
|
2632
|
-
st.lastCubicCtrl = null;
|
|
2633
|
-
st.lastQuadCtrl = null;
|
|
2634
|
-
return;
|
|
2635
|
-
}
|
|
2636
|
-
case "V": {
|
|
2637
|
-
const y = a[0] + (relative ? st.y : 0);
|
|
2638
|
-
b.lineTo(st.x, y);
|
|
2639
|
-
st.y = y;
|
|
2640
|
-
st.lastCubicCtrl = null;
|
|
2641
|
-
st.lastQuadCtrl = null;
|
|
2642
|
-
return;
|
|
2506
|
+
var ROUND_CAP_STEP_RAD = 10 * Math.PI / 180;
|
|
2507
|
+
function emitCap(seg, leftIdx, rightIdx, atEnd, half, cap, verts, idx, anchorA, anchorB, anchorT, endA, endB, endT) {
|
|
2508
|
+
const sign = atEnd ? 1 : -1;
|
|
2509
|
+
const dx = (seg.bx - seg.ax) / seg.len * sign;
|
|
2510
|
+
const dy = (seg.by - seg.ay) / seg.len * sign;
|
|
2511
|
+
const cx = atEnd ? seg.bx : seg.ax;
|
|
2512
|
+
const cy = atEnd ? seg.by : seg.ay;
|
|
2513
|
+
const nx = seg.nxUnit * half;
|
|
2514
|
+
const ny = seg.nyUnit * half;
|
|
2515
|
+
if (cap === "square") {
|
|
2516
|
+
const ox = cx + dx * half;
|
|
2517
|
+
const oy = cy + dy * half;
|
|
2518
|
+
const lOut = verts.length / 2;
|
|
2519
|
+
verts.push(ox + nx, oy + ny);
|
|
2520
|
+
anchorA.push(endA);
|
|
2521
|
+
anchorB.push(endB);
|
|
2522
|
+
anchorT.push(endT);
|
|
2523
|
+
const rOut = verts.length / 2;
|
|
2524
|
+
verts.push(ox - nx, oy - ny);
|
|
2525
|
+
anchorA.push(endA);
|
|
2526
|
+
anchorB.push(endB);
|
|
2527
|
+
anchorT.push(endT);
|
|
2528
|
+
if (atEnd) {
|
|
2529
|
+
idx.push(leftIdx, lOut, rOut, leftIdx, rOut, rightIdx);
|
|
2530
|
+
} else {
|
|
2531
|
+
idx.push(leftIdx, rOut, lOut, leftIdx, rightIdx, rOut);
|
|
2643
2532
|
}
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2533
|
+
return;
|
|
2534
|
+
}
|
|
2535
|
+
if (cap === "round") {
|
|
2536
|
+
const pivotIdx = verts.length / 2;
|
|
2537
|
+
verts.push(cx, cy);
|
|
2538
|
+
anchorA.push(endA);
|
|
2539
|
+
anchorB.push(endB);
|
|
2540
|
+
anchorT.push(endT);
|
|
2541
|
+
const startAngle = Math.atan2(ny, nx);
|
|
2542
|
+
const sweep = atEnd ? -Math.PI : Math.PI;
|
|
2543
|
+
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_CAP_STEP_RAD));
|
|
2544
|
+
const stepAngle = sweep / steps;
|
|
2545
|
+
let prevIdx = leftIdx;
|
|
2546
|
+
for (let i = 1; i < steps; i++) {
|
|
2547
|
+
const ang = startAngle + i * stepAngle;
|
|
2548
|
+
const fx = cx + Math.cos(ang) * half;
|
|
2549
|
+
const fy = cy + Math.sin(ang) * half;
|
|
2550
|
+
const newIdx = verts.length / 2;
|
|
2551
|
+
verts.push(fx, fy);
|
|
2552
|
+
anchorA.push(endA);
|
|
2553
|
+
anchorB.push(endB);
|
|
2554
|
+
anchorT.push(endT);
|
|
2555
|
+
if (atEnd) idx.push(prevIdx, newIdx, pivotIdx);
|
|
2556
|
+
else idx.push(prevIdx, pivotIdx, newIdx);
|
|
2557
|
+
prevIdx = newIdx;
|
|
2654
2558
|
}
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2559
|
+
if (atEnd) idx.push(prevIdx, rightIdx, pivotIdx);
|
|
2560
|
+
else idx.push(prevIdx, pivotIdx, rightIdx);
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
function splitForDash(pl, dash) {
|
|
2564
|
+
const out = [];
|
|
2565
|
+
const plA = pl.anchorA ?? new Uint32Array(pl.points.length / 2);
|
|
2566
|
+
const plB = pl.anchorB ?? new Uint32Array(pl.points.length / 2);
|
|
2567
|
+
const plT = pl.anchorT ?? new Float32Array(pl.points.length / 2);
|
|
2568
|
+
let dashIdx = 0;
|
|
2569
|
+
let dashRemaining = dash[0];
|
|
2570
|
+
let onPhase = true;
|
|
2571
|
+
let curPts = onPhase ? [pl.points[0], pl.points[1]] : null;
|
|
2572
|
+
let curA = onPhase ? [plA[0]] : null;
|
|
2573
|
+
let curB = onPhase ? [plB[0]] : null;
|
|
2574
|
+
let curT = onPhase ? [plT[0]] : null;
|
|
2575
|
+
const flushAndAdvance = () => {
|
|
2576
|
+
if (curPts && curPts.length >= 4) {
|
|
2577
|
+
out.push({
|
|
2578
|
+
points: curPts,
|
|
2579
|
+
closed: false,
|
|
2580
|
+
anchorA: new Uint32Array(curA),
|
|
2581
|
+
anchorB: new Uint32Array(curB),
|
|
2582
|
+
anchorT: new Float32Array(curT)
|
|
2583
|
+
});
|
|
2667
2584
|
}
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2585
|
+
curPts = null;
|
|
2586
|
+
curA = null;
|
|
2587
|
+
curB = null;
|
|
2588
|
+
curT = null;
|
|
2589
|
+
dashIdx = (dashIdx + 1) % dash.length;
|
|
2590
|
+
dashRemaining = dash[dashIdx];
|
|
2591
|
+
onPhase = !onPhase;
|
|
2592
|
+
};
|
|
2593
|
+
let prevX = pl.points[0], prevY = pl.points[1];
|
|
2594
|
+
const ptCount = pl.points.length / 2;
|
|
2595
|
+
const segCount = pl.closed ? ptCount : ptCount - 1;
|
|
2596
|
+
for (let i = 0; i < segCount; i++) {
|
|
2597
|
+
const nextIdx = (i + 1) % ptCount;
|
|
2598
|
+
const cx = pl.points[nextIdx * 2], cy = pl.points[nextIdx * 2 + 1];
|
|
2599
|
+
const startA = plA[i], startB = plB[i], startT = plT[i];
|
|
2600
|
+
const endA = plA[nextIdx], endB = plB[nextIdx], endT = plT[nextIdx];
|
|
2601
|
+
const segFullDx = cx - prevX, segFullDy = cy - prevY;
|
|
2602
|
+
const segFullLen = Math.hypot(segFullDx, segFullDy);
|
|
2603
|
+
let segDx = segFullDx, segDy = segFullDy;
|
|
2604
|
+
let segLen = segFullLen;
|
|
2605
|
+
let traveled = 0;
|
|
2606
|
+
while (segLen > 1e-9) {
|
|
2607
|
+
if (segLen <= dashRemaining) {
|
|
2608
|
+
if (onPhase && curPts) {
|
|
2609
|
+
curPts.push(cx, cy);
|
|
2610
|
+
curA.push(endA);
|
|
2611
|
+
curB.push(endB);
|
|
2612
|
+
curT.push(endT);
|
|
2613
|
+
}
|
|
2614
|
+
dashRemaining -= segLen;
|
|
2615
|
+
prevX = cx;
|
|
2616
|
+
prevY = cy;
|
|
2617
|
+
traveled = segFullLen;
|
|
2618
|
+
segLen = 0;
|
|
2619
|
+
if (dashRemaining <= 1e-9) {
|
|
2620
|
+
flushAndAdvance();
|
|
2621
|
+
if (onPhase) {
|
|
2622
|
+
curPts = [prevX, prevY];
|
|
2623
|
+
curA = [endA];
|
|
2624
|
+
curB = [endB];
|
|
2625
|
+
curT = [endT];
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
} else {
|
|
2629
|
+
const tConsume = dashRemaining / segLen;
|
|
2630
|
+
const ix = prevX + segDx * tConsume;
|
|
2631
|
+
const iy = prevY + segDy * tConsume;
|
|
2632
|
+
traveled += dashRemaining;
|
|
2633
|
+
const frac = traveled / segFullLen;
|
|
2634
|
+
let mA, mB, mT;
|
|
2635
|
+
if (startA === endA && startB === endB) {
|
|
2636
|
+
mA = startA;
|
|
2637
|
+
mB = startB;
|
|
2638
|
+
mT = startT + (endT - startT) * frac;
|
|
2639
|
+
} else {
|
|
2640
|
+
if (frac < 0.5) {
|
|
2641
|
+
mA = startA;
|
|
2642
|
+
mB = startB;
|
|
2643
|
+
mT = startT;
|
|
2644
|
+
} else {
|
|
2645
|
+
mA = endA;
|
|
2646
|
+
mB = endB;
|
|
2647
|
+
mT = endT;
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
if (onPhase && curPts) {
|
|
2651
|
+
curPts.push(ix, iy);
|
|
2652
|
+
curA.push(mA);
|
|
2653
|
+
curB.push(mB);
|
|
2654
|
+
curT.push(mT);
|
|
2655
|
+
}
|
|
2656
|
+
prevX = ix;
|
|
2657
|
+
prevY = iy;
|
|
2658
|
+
segDx = cx - prevX;
|
|
2659
|
+
segDy = cy - prevY;
|
|
2660
|
+
segLen = Math.hypot(segDx, segDy);
|
|
2661
|
+
flushAndAdvance();
|
|
2662
|
+
if (onPhase) {
|
|
2663
|
+
curPts = [prevX, prevY];
|
|
2664
|
+
curA = [mA];
|
|
2665
|
+
curB = [mB];
|
|
2666
|
+
curT = [mT];
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2677
2669
|
}
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2670
|
+
}
|
|
2671
|
+
if (curPts && curPts.length >= 4) {
|
|
2672
|
+
out.push({
|
|
2673
|
+
points: curPts,
|
|
2674
|
+
closed: false,
|
|
2675
|
+
anchorA: new Uint32Array(curA),
|
|
2676
|
+
anchorB: new Uint32Array(curB),
|
|
2677
|
+
anchorT: new Float32Array(curT)
|
|
2678
|
+
});
|
|
2679
|
+
}
|
|
2680
|
+
return out;
|
|
2681
|
+
}
|
|
2682
|
+
function makeSeg(ax, ay, bx, by, halfA, halfB) {
|
|
2683
|
+
const dx = bx - ax, dy = by - ay;
|
|
2684
|
+
const len = Math.hypot(dx, dy);
|
|
2685
|
+
if (len === 0) return null;
|
|
2686
|
+
return {
|
|
2687
|
+
ax,
|
|
2688
|
+
ay,
|
|
2689
|
+
bx,
|
|
2690
|
+
by,
|
|
2691
|
+
nxUnit: -dy / len,
|
|
2692
|
+
nyUnit: dx / len,
|
|
2693
|
+
halfA,
|
|
2694
|
+
halfB,
|
|
2695
|
+
len
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
var DEFAULT_MITER_LIMIT = 10;
|
|
2699
|
+
var DEFAULT_VARYING_WIDTH_JOIN_THRESHOLD = 1.5;
|
|
2700
|
+
function emitJoin(segs, segBaseIdx, j, join, miterLimit, varyingThreshold, verts, idx, anchorA, anchorB, anchorT, segSrcIdx, plA, plB, plT) {
|
|
2701
|
+
const a = segs[j];
|
|
2702
|
+
const b = segs[(j + 1) % segs.length];
|
|
2703
|
+
const aBase = segBaseIdx[j];
|
|
2704
|
+
const bBase = segBaseIdx[(j + 1) % segs.length];
|
|
2705
|
+
const adx = a.bx - a.ax, ady = a.by - a.ay;
|
|
2706
|
+
const bdx = b.bx - b.ax, bdy = b.by - b.ay;
|
|
2707
|
+
const cross = adx * bdy - ady * bdx;
|
|
2708
|
+
if (cross === 0) return;
|
|
2709
|
+
const onPositive = cross > 0;
|
|
2710
|
+
const aOuterEnd = onPositive ? aBase + 3 : aBase + 2;
|
|
2711
|
+
const bOuterStart = onPositive ? bBase + 1 : bBase + 0;
|
|
2712
|
+
const nextSeg = (j + 1) % segs.length;
|
|
2713
|
+
const cornerSrc = segSrcIdx[nextSeg];
|
|
2714
|
+
const cornerA = plA[cornerSrc];
|
|
2715
|
+
const cornerB = plB[cornerSrc];
|
|
2716
|
+
const cornerT = plT[cornerSrc];
|
|
2717
|
+
const halfAtCorner = a.halfB;
|
|
2718
|
+
const taperA = Math.max(a.halfA, a.halfB) / Math.max(1e-9, Math.min(a.halfA, a.halfB));
|
|
2719
|
+
const taperB = Math.max(b.halfA, b.halfB) / Math.max(1e-9, Math.min(b.halfA, b.halfB));
|
|
2720
|
+
const forceBevelForVarying = taperA > varyingThreshold || taperB > varyingThreshold;
|
|
2721
|
+
if (join === "bevel" || forceBevelForVarying) {
|
|
2722
|
+
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
if (join === "miter") {
|
|
2726
|
+
const aOX = verts[aOuterEnd * 2], aOY = verts[aOuterEnd * 2 + 1];
|
|
2727
|
+
const bOX = verts[bOuterStart * 2], bOY = verts[bOuterStart * 2 + 1];
|
|
2728
|
+
const apex = lineLineIntersect(aOX, aOY, adx, ady, bOX, bOY, -bdx, -bdy);
|
|
2729
|
+
if (!apex) {
|
|
2730
|
+
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2688
2731
|
return;
|
|
2689
2732
|
}
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
const xRot = a[2];
|
|
2694
|
-
const largeArc = a[3] !== 0;
|
|
2695
|
-
const sweep = a[4] !== 0;
|
|
2696
|
-
const ex = a[5] + rx;
|
|
2697
|
-
const ey = a[6] + ry;
|
|
2698
|
-
arcToCubics(st.x, st.y, ex, ey, rxA, ryA, xRot, largeArc, sweep, b);
|
|
2699
|
-
st.x = ex;
|
|
2700
|
-
st.y = ey;
|
|
2701
|
-
st.lastCubicCtrl = null;
|
|
2702
|
-
st.lastQuadCtrl = null;
|
|
2733
|
+
const miterLen = Math.hypot(apex[0] - a.bx, apex[1] - a.by);
|
|
2734
|
+
if (miterLen > miterLimit * halfAtCorner) {
|
|
2735
|
+
emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2703
2736
|
return;
|
|
2704
2737
|
}
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2738
|
+
const apexIdx = verts.length / 2;
|
|
2739
|
+
verts.push(apex[0], apex[1]);
|
|
2740
|
+
anchorA.push(cornerA);
|
|
2741
|
+
anchorB.push(cornerB);
|
|
2742
|
+
anchorT.push(cornerT);
|
|
2743
|
+
const jIdx = verts.length / 2;
|
|
2744
|
+
verts.push(a.bx, a.by);
|
|
2745
|
+
anchorA.push(cornerA);
|
|
2746
|
+
anchorB.push(cornerB);
|
|
2747
|
+
anchorT.push(cornerT);
|
|
2748
|
+
if (onPositive) {
|
|
2749
|
+
idx.push(aOuterEnd, apexIdx, bOuterStart);
|
|
2750
|
+
idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
2751
|
+
} else {
|
|
2752
|
+
idx.push(aOuterEnd, bOuterStart, apexIdx);
|
|
2753
|
+
idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
2754
|
+
}
|
|
2713
2755
|
return;
|
|
2714
2756
|
}
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
const dx = (x1 - x2) / 2;
|
|
2719
|
-
const dy = (y1 - y2) / 2;
|
|
2720
|
-
const x1p = cosPhi * dx + sinPhi * dy;
|
|
2721
|
-
const y1p = -sinPhi * dx + cosPhi * dy;
|
|
2722
|
-
let rxs = rx * rx;
|
|
2723
|
-
let rys = ry * ry;
|
|
2724
|
-
const x1ps = x1p * x1p;
|
|
2725
|
-
const y1ps = y1p * y1p;
|
|
2726
|
-
const lambda = x1ps / rxs + y1ps / rys;
|
|
2727
|
-
let rxFixed = rx;
|
|
2728
|
-
let ryFixed = ry;
|
|
2729
|
-
if (lambda > 1) {
|
|
2730
|
-
const sqrtLambda = Math.sqrt(lambda);
|
|
2731
|
-
rxFixed = sqrtLambda * rx;
|
|
2732
|
-
ryFixed = sqrtLambda * ry;
|
|
2733
|
-
rxs = rxFixed * rxFixed;
|
|
2734
|
-
rys = ryFixed * ryFixed;
|
|
2757
|
+
if (join === "round") {
|
|
2758
|
+
emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT);
|
|
2759
|
+
return;
|
|
2735
2760
|
}
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
const
|
|
2740
|
-
const
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
const
|
|
2752
|
-
let
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
const sinT = Math.sin(theta);
|
|
2771
|
-
const px = cosPhi * (cosT * rxFixed) - sinPhi * (sinT * ryFixed) + cx;
|
|
2772
|
-
const py = sinPhi * (cosT * rxFixed) + cosPhi * (sinT * ryFixed) + cy;
|
|
2773
|
-
const dxNew = -sinT * rxFixed;
|
|
2774
|
-
const dyNew = cosT * ryFixed;
|
|
2775
|
-
const c1x = prevX + cosPhi * (t * prevDx) - sinPhi * (t * prevDy);
|
|
2776
|
-
const c1y = prevY + sinPhi * (t * prevDx) + cosPhi * (t * prevDy);
|
|
2777
|
-
const c2x = px - cosPhi * (t * dxNew) + sinPhi * (t * dyNew);
|
|
2778
|
-
const c2y = py - sinPhi * (t * dxNew) - cosPhi * (t * dyNew);
|
|
2779
|
-
b.curveTo(c1x, c1y, c2x, c2y, px, py);
|
|
2780
|
-
prevX = px;
|
|
2781
|
-
prevY = py;
|
|
2782
|
-
prevDx = dxNew;
|
|
2783
|
-
prevDy = dyNew;
|
|
2761
|
+
}
|
|
2762
|
+
var ROUND_STEP_RAD = 10 * Math.PI / 180;
|
|
2763
|
+
function emitRoundJoin(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
2764
|
+
const cx = a.bx, cy = a.by;
|
|
2765
|
+
const pivotIdx = verts.length / 2;
|
|
2766
|
+
verts.push(cx, cy);
|
|
2767
|
+
anchorA.push(cornerA);
|
|
2768
|
+
anchorB.push(cornerB);
|
|
2769
|
+
anchorT.push(cornerT);
|
|
2770
|
+
const startX = verts[aOuterEnd * 2] - cx;
|
|
2771
|
+
const startY = verts[aOuterEnd * 2 + 1] - cy;
|
|
2772
|
+
const endX = verts[bOuterStart * 2] - cx;
|
|
2773
|
+
const endY = verts[bOuterStart * 2 + 1] - cy;
|
|
2774
|
+
const r = Math.hypot(startX, startY);
|
|
2775
|
+
const startAngle = Math.atan2(startY, startX);
|
|
2776
|
+
const endAngle = Math.atan2(endY, endX);
|
|
2777
|
+
let sweep = endAngle - startAngle;
|
|
2778
|
+
if (onPositive && sweep < 0) sweep += 2 * Math.PI;
|
|
2779
|
+
else if (!onPositive && sweep > 0) sweep -= 2 * Math.PI;
|
|
2780
|
+
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / ROUND_STEP_RAD));
|
|
2781
|
+
const stepAngle = sweep / steps;
|
|
2782
|
+
let prevIdx = aOuterEnd;
|
|
2783
|
+
for (let i = 1; i < steps; i++) {
|
|
2784
|
+
const ang = startAngle + i * stepAngle;
|
|
2785
|
+
const fx = cx + Math.cos(ang) * r;
|
|
2786
|
+
const fy = cy + Math.sin(ang) * r;
|
|
2787
|
+
const newIdx = verts.length / 2;
|
|
2788
|
+
verts.push(fx, fy);
|
|
2789
|
+
anchorA.push(cornerA);
|
|
2790
|
+
anchorB.push(cornerB);
|
|
2791
|
+
anchorT.push(cornerT);
|
|
2792
|
+
if (onPositive) idx.push(prevIdx, pivotIdx, newIdx);
|
|
2793
|
+
else idx.push(prevIdx, newIdx, pivotIdx);
|
|
2794
|
+
prevIdx = newIdx;
|
|
2784
2795
|
}
|
|
2796
|
+
if (onPositive) idx.push(prevIdx, pivotIdx, bOuterStart);
|
|
2797
|
+
else idx.push(prevIdx, bOuterStart, pivotIdx);
|
|
2785
2798
|
}
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
return
|
|
2799
|
+
function emitBevel(a, aOuterEnd, bOuterStart, onPositive, verts, idx, anchorA, anchorB, anchorT, cornerA, cornerB, cornerT) {
|
|
2800
|
+
const jIdx = verts.length / 2;
|
|
2801
|
+
verts.push(a.bx, a.by);
|
|
2802
|
+
anchorA.push(cornerA);
|
|
2803
|
+
anchorB.push(cornerB);
|
|
2804
|
+
anchorT.push(cornerT);
|
|
2805
|
+
if (onPositive) idx.push(aOuterEnd, jIdx, bOuterStart);
|
|
2806
|
+
else idx.push(aOuterEnd, bOuterStart, jIdx);
|
|
2807
|
+
}
|
|
2808
|
+
function lineLineIntersect(apx, apy, adx, ady, bpx, bpy, bdx, bdy) {
|
|
2809
|
+
const denom = adx * bdy - ady * bdx;
|
|
2810
|
+
if (Math.abs(denom) < 1e-9) return null;
|
|
2811
|
+
const t = ((bpx - apx) * bdy - (bpy - apy) * bdx) / denom;
|
|
2812
|
+
return [apx + t * adx, apy + t * ady];
|
|
2798
2813
|
}
|
|
2799
2814
|
|
|
2800
2815
|
// src/renderer/cache/outlineStrokeMeshCache.ts
|
|
@@ -2827,26 +2842,299 @@ function outlineStrokeMesh(glyphKey, d, emWidth, stroke) {
|
|
|
2827
2842
|
return mesh.indices.length === 0 ? null : mesh;
|
|
2828
2843
|
}
|
|
2829
2844
|
|
|
2845
|
+
// src/renderer/cache/strokeMeshCache.ts
|
|
2846
|
+
var STROKE_CONFIGS_PER_PATH = 8;
|
|
2847
|
+
var cache5 = /* @__PURE__ */ new WeakMap();
|
|
2848
|
+
function configKey(stroke, flattenTolerance) {
|
|
2849
|
+
return [
|
|
2850
|
+
stroke.width ?? 1,
|
|
2851
|
+
stroke.cap ?? "butt",
|
|
2852
|
+
stroke.join ?? "miter",
|
|
2853
|
+
stroke.miterLimit ?? "",
|
|
2854
|
+
stroke.align ?? "center",
|
|
2855
|
+
(stroke.dash ?? []).join(","),
|
|
2856
|
+
stroke.varyingWidthJoinThreshold ?? "",
|
|
2857
|
+
flattenTolerance ?? ""
|
|
2858
|
+
].join("|");
|
|
2859
|
+
}
|
|
2860
|
+
function strokeMesh(path, stroke, flattenTolerance) {
|
|
2861
|
+
let byConfig = cache5.get(path);
|
|
2862
|
+
if (byConfig === void 0) {
|
|
2863
|
+
byConfig = /* @__PURE__ */ new Map();
|
|
2864
|
+
cache5.set(path, byConfig);
|
|
2865
|
+
}
|
|
2866
|
+
const key = configKey(stroke, flattenTolerance);
|
|
2867
|
+
const entry = byConfig.get(key);
|
|
2868
|
+
if (entry !== void 0 && entry.vertexWidths === stroke.vertexWidths) {
|
|
2869
|
+
return entry.mesh;
|
|
2870
|
+
}
|
|
2871
|
+
const mesh = tessellateStroke(path, stroke, { flattenTolerance });
|
|
2872
|
+
if (entry === void 0 && byConfig.size >= STROKE_CONFIGS_PER_PATH) byConfig.clear();
|
|
2873
|
+
byConfig.set(key, { mesh, vertexWidths: stroke.vertexWidths });
|
|
2874
|
+
return mesh;
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
// src/renderer/solidBatch.ts
|
|
2878
|
+
var MAX_VERTICES_PER_BATCH = 32768;
|
|
2879
|
+
var FLOATS_PER_VERTEX = 6;
|
|
2880
|
+
var INITIAL_VERTICES = 256;
|
|
2881
|
+
var INITIAL_INDICES = 384;
|
|
2882
|
+
var SolidBatch = class {
|
|
2883
|
+
gl;
|
|
2884
|
+
vao;
|
|
2885
|
+
vbo;
|
|
2886
|
+
ibo;
|
|
2887
|
+
verts = new Float32Array(INITIAL_VERTICES * FLOATS_PER_VERTEX);
|
|
2888
|
+
idx = new Uint32Array(INITIAL_INDICES);
|
|
2889
|
+
nVerts = 0;
|
|
2890
|
+
nIdx = 0;
|
|
2891
|
+
/** What the GPU buffers are currently sized for. */
|
|
2892
|
+
vboVerts = 0;
|
|
2893
|
+
iboIdx = 0;
|
|
2894
|
+
constructor(gl, prog) {
|
|
2895
|
+
const aPos = prog.attribute("a_position");
|
|
2896
|
+
const aColor = prog.attribute("a_vertexColor");
|
|
2897
|
+
if (aPos === void 0 || aColor === void 0) {
|
|
2898
|
+
throw new Error("SolidBatch: vertex-color program is missing a_position / a_vertexColor");
|
|
2899
|
+
}
|
|
2900
|
+
const vao = gl.createVertexArray();
|
|
2901
|
+
const vbo = gl.createBuffer();
|
|
2902
|
+
const ibo = gl.createBuffer();
|
|
2903
|
+
if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
|
|
2904
|
+
this.gl = gl;
|
|
2905
|
+
this.vao = vao;
|
|
2906
|
+
this.vbo = vbo;
|
|
2907
|
+
this.ibo = ibo;
|
|
2908
|
+
const stride = FLOATS_PER_VERTEX * 4;
|
|
2909
|
+
gl.bindVertexArray(vao);
|
|
2910
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
2911
|
+
gl.enableVertexAttribArray(aPos);
|
|
2912
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, stride, 0);
|
|
2913
|
+
gl.enableVertexAttribArray(aColor);
|
|
2914
|
+
gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, stride, 8);
|
|
2915
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
2916
|
+
gl.bindVertexArray(null);
|
|
2917
|
+
this.growGpu(INITIAL_VERTICES, INITIAL_INDICES);
|
|
2918
|
+
}
|
|
2919
|
+
get length() {
|
|
2920
|
+
return this.nIdx;
|
|
2921
|
+
}
|
|
2922
|
+
/** Whether staging `vertices` more would put the run past the per-flush cap. */
|
|
2923
|
+
wouldOverflow(vertices) {
|
|
2924
|
+
return this.nVerts + vertices > MAX_VERTICES_PER_BATCH;
|
|
2925
|
+
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Append one rect's four corners through `m`, all carrying `rgba` (straight
|
|
2928
|
+
* alpha). An affine maps a rect to a parallelogram, so two triangles still
|
|
2929
|
+
* cover it and the batch draws at `u_model` identity.
|
|
2930
|
+
*/
|
|
2931
|
+
pushRect(x, y, w, h, m, r, g, b, a) {
|
|
2932
|
+
this.reserve(4, 6);
|
|
2933
|
+
const v = this.verts;
|
|
2934
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
2935
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
2936
|
+
const x1 = x + w;
|
|
2937
|
+
const y1 = y + h;
|
|
2938
|
+
const ax = ma * x + mc * y + mtx, ay = mb * x + md * y + mty;
|
|
2939
|
+
const bx = ma * x1 + mc * y + mtx, by = mb * x1 + md * y + mty;
|
|
2940
|
+
const cx = ma * x1 + mc * y1 + mtx, cy = mb * x1 + md * y1 + mty;
|
|
2941
|
+
const dx = ma * x + mc * y1 + mtx, dy = mb * x + md * y1 + mty;
|
|
2942
|
+
v[i++] = ax;
|
|
2943
|
+
v[i++] = ay;
|
|
2944
|
+
v[i++] = r;
|
|
2945
|
+
v[i++] = g;
|
|
2946
|
+
v[i++] = b;
|
|
2947
|
+
v[i++] = a;
|
|
2948
|
+
v[i++] = bx;
|
|
2949
|
+
v[i++] = by;
|
|
2950
|
+
v[i++] = r;
|
|
2951
|
+
v[i++] = g;
|
|
2952
|
+
v[i++] = b;
|
|
2953
|
+
v[i++] = a;
|
|
2954
|
+
v[i++] = cx;
|
|
2955
|
+
v[i++] = cy;
|
|
2956
|
+
v[i++] = r;
|
|
2957
|
+
v[i++] = g;
|
|
2958
|
+
v[i++] = b;
|
|
2959
|
+
v[i++] = a;
|
|
2960
|
+
v[i++] = dx;
|
|
2961
|
+
v[i++] = dy;
|
|
2962
|
+
v[i++] = r;
|
|
2963
|
+
v[i++] = g;
|
|
2964
|
+
v[i++] = b;
|
|
2965
|
+
v[i++] = a;
|
|
2966
|
+
const base = this.nVerts;
|
|
2967
|
+
let j = this.nIdx;
|
|
2968
|
+
this.idx[j++] = base;
|
|
2969
|
+
this.idx[j++] = base + 1;
|
|
2970
|
+
this.idx[j++] = base + 2;
|
|
2971
|
+
this.idx[j++] = base;
|
|
2972
|
+
this.idx[j++] = base + 2;
|
|
2973
|
+
this.idx[j++] = base + 3;
|
|
2974
|
+
this.nVerts += 4;
|
|
2975
|
+
this.nIdx += 6;
|
|
2976
|
+
}
|
|
2977
|
+
/**
|
|
2978
|
+
* Append a tessellated mesh through `m`, all vertices carrying `rgba`. The
|
|
2979
|
+
* mesh's own indices are rebased onto the staged vertices, which is why the
|
|
2980
|
+
* index buffer is uploaded per flush rather than written once.
|
|
2981
|
+
*/
|
|
2982
|
+
pushMesh(mesh, m, r, g, b, a) {
|
|
2983
|
+
const src = mesh.vertices;
|
|
2984
|
+
const srcIdx = mesh.indices;
|
|
2985
|
+
const n = src.length >> 1;
|
|
2986
|
+
this.reserve(n, srcIdx.length);
|
|
2987
|
+
const v = this.verts;
|
|
2988
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
2989
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
2990
|
+
for (let k = 0; k < n; k++) {
|
|
2991
|
+
const x = src[k * 2];
|
|
2992
|
+
const y = src[k * 2 + 1];
|
|
2993
|
+
v[i++] = ma * x + mc * y + mtx;
|
|
2994
|
+
v[i++] = mb * x + md * y + mty;
|
|
2995
|
+
v[i++] = r;
|
|
2996
|
+
v[i++] = g;
|
|
2997
|
+
v[i++] = b;
|
|
2998
|
+
v[i++] = a;
|
|
2999
|
+
}
|
|
3000
|
+
const base = this.nVerts;
|
|
3001
|
+
const out = this.idx;
|
|
3002
|
+
let j = this.nIdx;
|
|
3003
|
+
for (let k = 0; k < srcIdx.length; k++) out[j++] = base + srcIdx[k];
|
|
3004
|
+
this.nVerts += n;
|
|
3005
|
+
this.nIdx += srcIdx.length;
|
|
3006
|
+
}
|
|
3007
|
+
/** Upload the staged geometry and bind the batch VAO. Returns the index
|
|
3008
|
+
* count for the caller's `drawElements`. */
|
|
3009
|
+
uploadAndBind() {
|
|
3010
|
+
const gl = this.gl;
|
|
3011
|
+
if (this.nVerts > this.vboVerts || this.nIdx > this.iboIdx) {
|
|
3012
|
+
this.growGpu(this.nVerts, this.nIdx);
|
|
3013
|
+
}
|
|
3014
|
+
gl.bindVertexArray(this.vao);
|
|
3015
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
|
|
3016
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nVerts * FLOATS_PER_VERTEX);
|
|
3017
|
+
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, this.idx, 0, this.nIdx);
|
|
3018
|
+
return this.nIdx;
|
|
3019
|
+
}
|
|
3020
|
+
reset() {
|
|
3021
|
+
this.nVerts = 0;
|
|
3022
|
+
this.nIdx = 0;
|
|
3023
|
+
}
|
|
3024
|
+
dispose() {
|
|
3025
|
+
const gl = this.gl;
|
|
3026
|
+
gl.deleteBuffer(this.vbo);
|
|
3027
|
+
gl.deleteBuffer(this.ibo);
|
|
3028
|
+
gl.deleteVertexArray(this.vao);
|
|
3029
|
+
}
|
|
3030
|
+
/** Grow the CPU arrays so `vertices` / `indices` more fit. */
|
|
3031
|
+
reserve(vertices, indices) {
|
|
3032
|
+
const needVerts = (this.nVerts + vertices) * FLOATS_PER_VERTEX;
|
|
3033
|
+
if (needVerts > this.verts.length) {
|
|
3034
|
+
let len = this.verts.length;
|
|
3035
|
+
while (len < needVerts) len *= 2;
|
|
3036
|
+
const grown = new Float32Array(len);
|
|
3037
|
+
grown.set(this.verts);
|
|
3038
|
+
this.verts = grown;
|
|
3039
|
+
}
|
|
3040
|
+
const needIdx = this.nIdx + indices;
|
|
3041
|
+
if (needIdx > this.idx.length) {
|
|
3042
|
+
let len = this.idx.length;
|
|
3043
|
+
while (len < needIdx) len *= 2;
|
|
3044
|
+
const grown = new Uint32Array(len);
|
|
3045
|
+
grown.set(this.idx);
|
|
3046
|
+
this.idx = grown;
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
/** Size both GPU buffers for at least what is staged, doubling to amortize. */
|
|
3050
|
+
growGpu(vertices, indices) {
|
|
3051
|
+
const gl = this.gl;
|
|
3052
|
+
if (vertices > this.vboVerts) {
|
|
3053
|
+
let capacity = Math.max(this.vboVerts, INITIAL_VERTICES);
|
|
3054
|
+
while (capacity < vertices) capacity *= 2;
|
|
3055
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
|
|
3056
|
+
gl.bufferData(gl.ARRAY_BUFFER, capacity * FLOATS_PER_VERTEX * 4, gl.DYNAMIC_DRAW);
|
|
3057
|
+
this.vboVerts = capacity;
|
|
3058
|
+
}
|
|
3059
|
+
if (indices > this.iboIdx) {
|
|
3060
|
+
let capacity = Math.max(this.iboIdx, INITIAL_INDICES);
|
|
3061
|
+
while (capacity < indices) capacity *= 2;
|
|
3062
|
+
gl.bindVertexArray(this.vao);
|
|
3063
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ibo);
|
|
3064
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, capacity * 4, gl.DYNAMIC_DRAW);
|
|
3065
|
+
gl.bindVertexArray(null);
|
|
3066
|
+
this.iboIdx = capacity;
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
};
|
|
3070
|
+
|
|
2830
3071
|
// src/renderer/draw.ts
|
|
2831
|
-
|
|
3072
|
+
var FRAME_UPLOADS = /* @__PURE__ */ new WeakMap();
|
|
3073
|
+
var FRAME_PROJ = /* @__PURE__ */ new WeakMap();
|
|
3074
|
+
function uploadedFor(ctx, prog) {
|
|
3075
|
+
let byProgram = FRAME_UPLOADS.get(ctx);
|
|
3076
|
+
if (!byProgram) {
|
|
3077
|
+
byProgram = /* @__PURE__ */ new WeakMap();
|
|
3078
|
+
FRAME_UPLOADS.set(ctx, byProgram);
|
|
3079
|
+
}
|
|
3080
|
+
let uploaded = byProgram.get(prog);
|
|
3081
|
+
if (!uploaded) {
|
|
3082
|
+
uploaded = {};
|
|
3083
|
+
byProgram.set(prog, uploaded);
|
|
3084
|
+
}
|
|
3085
|
+
return uploaded;
|
|
3086
|
+
}
|
|
3087
|
+
function sameValues(prev, next) {
|
|
3088
|
+
if (prev === void 0 || prev.length !== next.length) return false;
|
|
3089
|
+
for (let i = 0; i < prev.length; i++) if (prev[i] !== next[i]) return false;
|
|
3090
|
+
return true;
|
|
3091
|
+
}
|
|
3092
|
+
var BATCH_MODEL = mat3.identity();
|
|
3093
|
+
function projFor(ctx) {
|
|
3094
|
+
let proj = FRAME_PROJ.get(ctx);
|
|
3095
|
+
if (!proj) {
|
|
3096
|
+
proj = mat3.screenToClip(ctx.widthCss, ctx.heightCss);
|
|
3097
|
+
FRAME_PROJ.set(ctx, proj);
|
|
3098
|
+
}
|
|
3099
|
+
return proj;
|
|
3100
|
+
}
|
|
3101
|
+
var COLOR_MATRIX_SCRATCH = new Float32Array(16);
|
|
3102
|
+
function setColorMatrixUniforms(ctx, prog, cm = ctx.state.colorMatrix) {
|
|
2832
3103
|
const gl = ctx.gl;
|
|
2833
|
-
const
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2836
|
-
for (let
|
|
2837
|
-
|
|
3104
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
3105
|
+
const mLoc = prog.uniform("u_colorMatrix");
|
|
3106
|
+
if (mLoc !== void 0) {
|
|
3107
|
+
for (let row = 0; row < 4; row++) {
|
|
3108
|
+
for (let col = 0; col < 4; col++) {
|
|
3109
|
+
COLOR_MATRIX_SCRATCH[col * 4 + row] = cm[row * 5 + col];
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
if (!sameValues(uploaded.colorMatrix, COLOR_MATRIX_SCRATCH)) {
|
|
3113
|
+
gl.uniformMatrix4fv(mLoc, false, COLOR_MATRIX_SCRATCH);
|
|
3114
|
+
uploaded.colorMatrix = Float32Array.from(COLOR_MATRIX_SCRATCH);
|
|
2838
3115
|
}
|
|
2839
3116
|
}
|
|
2840
|
-
const mLoc = prog.uniform("u_colorMatrix");
|
|
2841
3117
|
const bLoc = prog.uniform("u_colorBias");
|
|
2842
|
-
if (
|
|
2843
|
-
|
|
3118
|
+
if (bLoc !== void 0) {
|
|
3119
|
+
const bias = [cm[4], cm[9], cm[14], cm[19]];
|
|
3120
|
+
if (!sameValues(uploaded.colorBias, bias)) {
|
|
3121
|
+
gl.uniform4f(bLoc, bias[0], bias[1], bias[2], bias[3]);
|
|
3122
|
+
uploaded.colorBias = Float32Array.from(bias);
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
2844
3125
|
}
|
|
2845
|
-
function
|
|
3126
|
+
function fillMesh(ctx, path) {
|
|
2846
3127
|
if (ctx.flattenTolerance !== void 0) {
|
|
2847
|
-
return
|
|
3128
|
+
return tessellate(path, { flattenTolerance: ctx.flattenTolerance });
|
|
2848
3129
|
}
|
|
2849
|
-
return
|
|
3130
|
+
return getMesh(path);
|
|
3131
|
+
}
|
|
3132
|
+
function meshHandle(ctx, mesh) {
|
|
3133
|
+
if (ctx.flattenTolerance !== void 0) return ctx.meshCache.uploadTransient(mesh);
|
|
3134
|
+
return ctx.meshCache.handleFor(mesh);
|
|
3135
|
+
}
|
|
3136
|
+
function fillMeshHandle(ctx, path) {
|
|
3137
|
+
return meshHandle(ctx, fillMesh(ctx, path));
|
|
2850
3138
|
}
|
|
2851
3139
|
function dispatch(ctx, cmd) {
|
|
2852
3140
|
switch (cmd.kind) {
|
|
@@ -2855,10 +3143,13 @@ function dispatch(ctx, cmd) {
|
|
|
2855
3143
|
case "path":
|
|
2856
3144
|
return drawPath(ctx, cmd);
|
|
2857
3145
|
case "text":
|
|
3146
|
+
flushSolids(ctx);
|
|
2858
3147
|
return drawText(ctx, cmd);
|
|
2859
3148
|
case "image":
|
|
3149
|
+
flushSolids(ctx);
|
|
2860
3150
|
return drawImage(ctx, cmd);
|
|
2861
3151
|
case "shader":
|
|
3152
|
+
flushSolids(ctx);
|
|
2862
3153
|
return drawShader(ctx, cmd);
|
|
2863
3154
|
}
|
|
2864
3155
|
}
|
|
@@ -2998,40 +3289,106 @@ function drawGroup(ctx, cmd) {
|
|
|
2998
3289
|
ctx.state.pop();
|
|
2999
3290
|
}
|
|
3000
3291
|
function drawPath(ctx, cmd) {
|
|
3001
|
-
if (
|
|
3002
|
-
if (cmd.
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3292
|
+
if (cmd.fill) drawPathFill(ctx, cmd);
|
|
3293
|
+
if (cmd.stroke) drawPathStroke(ctx, cmd);
|
|
3294
|
+
}
|
|
3295
|
+
function drawPathFill(ctx, cmd) {
|
|
3296
|
+
const fill = cmd.fill;
|
|
3297
|
+
const isSolid = fill.fill === void 0 || fill.fill === "solid";
|
|
3298
|
+
const hasVColors = !!(cmd.vertexColors && cmd.vertexColors.length > 0);
|
|
3299
|
+
const solid = fill;
|
|
3300
|
+
if (isSolid && !hasVColors && cmd.path.kind === "rect") {
|
|
3301
|
+
pushRect(ctx, cmd.path, solid);
|
|
3302
|
+
return;
|
|
3303
|
+
}
|
|
3304
|
+
const mesh = fillMesh(ctx, cmd.path);
|
|
3305
|
+
if (tryStageSolid(ctx, mesh, isSolid && !hasVColors ? solid : void 0)) return;
|
|
3306
|
+
const handle = meshHandle(ctx, mesh);
|
|
3307
|
+
if (isSolid && hasVColors) {
|
|
3308
|
+
drawPathFillVColor(ctx, cmd, solid, handle);
|
|
3309
|
+
} else if (handle.requiresStencil) {
|
|
3310
|
+
drawPathFillStencil(ctx, fill, handle);
|
|
3311
|
+
} else {
|
|
3312
|
+
drawPathFillByKind(ctx, fill, handle);
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
function isIdentityColorMatrix(cm) {
|
|
3316
|
+
return cm === IDENTITY_COLOR_MATRIX || sameValues(IDENTITY_COLOR_MATRIX, cm);
|
|
3317
|
+
}
|
|
3318
|
+
function stagedStateIsLive(ctx, staged) {
|
|
3319
|
+
if (staged.clipDepth !== ctx.clipDepth) return false;
|
|
3320
|
+
if (!staged.foldsAlpha && staged.alpha !== ctx.state.alpha) return false;
|
|
3321
|
+
const colorMatrix = ctx.state.colorMatrix;
|
|
3322
|
+
return staged.colorMatrix === colorMatrix || sameValues(staged.colorMatrix, colorMatrix);
|
|
3323
|
+
}
|
|
3324
|
+
var MAX_BATCHED_MESH_VERTICES = 256;
|
|
3325
|
+
function canBatchMesh(mesh) {
|
|
3326
|
+
return !mesh.requiresStencil && mesh.vertices.length >> 1 <= MAX_BATCHED_MESH_VERTICES;
|
|
3327
|
+
}
|
|
3328
|
+
function stageSolid(ctx, vertices) {
|
|
3329
|
+
if (ctx.solidState !== void 0 && !stagedStateIsLive(ctx, ctx.solidState)) flushSolids(ctx);
|
|
3330
|
+
if (ctx.solidBatch.wouldOverflow(vertices)) flushSolids(ctx);
|
|
3331
|
+
if (ctx.solidState === void 0) {
|
|
3332
|
+
const colorMatrix = ctx.state.colorMatrix;
|
|
3333
|
+
const foldsAlpha = isIdentityColorMatrix(colorMatrix);
|
|
3334
|
+
ctx.solidState = {
|
|
3335
|
+
alpha: foldsAlpha ? 1 : ctx.state.alpha,
|
|
3336
|
+
colorMatrix,
|
|
3337
|
+
clipDepth: ctx.clipDepth,
|
|
3338
|
+
foldsAlpha
|
|
3339
|
+
};
|
|
3016
3340
|
}
|
|
3017
|
-
|
|
3018
|
-
|
|
3341
|
+
return ctx.solidState;
|
|
3342
|
+
}
|
|
3343
|
+
function stagedColor(ctx, staged, paint) {
|
|
3344
|
+
const [r, g, b, a] = resolveColor(paint.color);
|
|
3345
|
+
return [r, g, b, a * (paint.opacity ?? 1) * (staged.foldsAlpha ? ctx.state.alpha : 1)];
|
|
3346
|
+
}
|
|
3347
|
+
function pushRect(ctx, rect, fill) {
|
|
3348
|
+
const staged = stageSolid(ctx, 4);
|
|
3349
|
+
const [r, g, b, a] = stagedColor(ctx, staged, fill);
|
|
3350
|
+
ctx.solidBatch.pushRect(
|
|
3351
|
+
rect.x,
|
|
3352
|
+
rect.y,
|
|
3353
|
+
rect.width,
|
|
3354
|
+
rect.height,
|
|
3355
|
+
ctx.state.transform,
|
|
3356
|
+
r,
|
|
3357
|
+
g,
|
|
3358
|
+
b,
|
|
3359
|
+
a
|
|
3360
|
+
);
|
|
3361
|
+
}
|
|
3362
|
+
function pushMesh(ctx, mesh, paint) {
|
|
3363
|
+
const staged = stageSolid(ctx, mesh.vertices.length >> 1);
|
|
3364
|
+
const [r, g, b, a] = stagedColor(ctx, staged, paint);
|
|
3365
|
+
ctx.solidBatch.pushMesh(mesh, ctx.state.transform, r, g, b, a);
|
|
3366
|
+
}
|
|
3367
|
+
function tryStageSolid(ctx, mesh, paint) {
|
|
3368
|
+
if (paint !== void 0 && canBatchMesh(mesh)) {
|
|
3369
|
+
pushMesh(ctx, mesh, paint);
|
|
3370
|
+
return true;
|
|
3019
3371
|
}
|
|
3372
|
+
flushSolids(ctx);
|
|
3373
|
+
return false;
|
|
3020
3374
|
}
|
|
3021
|
-
function
|
|
3375
|
+
function flushSolids(ctx) {
|
|
3376
|
+
const batch = ctx.solidBatch;
|
|
3377
|
+
const staged = ctx.solidState;
|
|
3378
|
+
if (batch.length === 0 || staged === void 0) return;
|
|
3022
3379
|
const gl = ctx.gl;
|
|
3023
|
-
const
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
gl.
|
|
3028
|
-
gl.
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
applyClipTest(ctx);
|
|
3033
|
-
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
|
|
3380
|
+
const prog = ctx.pathFillVColor;
|
|
3381
|
+
gl.useProgram(prog.handle);
|
|
3382
|
+
const indexCount = batch.uploadAndBind();
|
|
3383
|
+
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
3384
|
+
gl.uniform4f(prog.uniform("u_color"), 1, 1, 1, 1);
|
|
3385
|
+
gl.uniform1f(prog.uniform("u_alpha"), staged.alpha);
|
|
3386
|
+
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
3387
|
+
applyClipTest(ctx, staged.clipDepth);
|
|
3388
|
+
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
|
3034
3389
|
gl.bindVertexArray(null);
|
|
3390
|
+
batch.reset();
|
|
3391
|
+
ctx.solidState = void 0;
|
|
3035
3392
|
}
|
|
3036
3393
|
function expandAnchorColors(perAnchor, handle) {
|
|
3037
3394
|
const aA = handle.anchorA;
|
|
@@ -3076,11 +3433,18 @@ function drawPathFillVColor(ctx, cmd, fill, handle) {
|
|
|
3076
3433
|
gl.bindVertexArray(null);
|
|
3077
3434
|
gl.deleteBuffer(colorVbo);
|
|
3078
3435
|
}
|
|
3079
|
-
function setProjAndModel(ctx, prog) {
|
|
3436
|
+
function setProjAndModel(ctx, prog, model = ctx.state.transform) {
|
|
3080
3437
|
const gl = ctx.gl;
|
|
3081
|
-
const
|
|
3082
|
-
|
|
3083
|
-
|
|
3438
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
3439
|
+
const proj = projFor(ctx);
|
|
3440
|
+
if (!sameValues(uploaded.proj, proj)) {
|
|
3441
|
+
gl.uniformMatrix3fv(prog.uniform("u_proj"), false, proj);
|
|
3442
|
+
uploaded.proj = Float32Array.from(proj);
|
|
3443
|
+
}
|
|
3444
|
+
if (!sameValues(uploaded.model, model)) {
|
|
3445
|
+
gl.uniformMatrix3fv(prog.uniform("u_model"), false, model);
|
|
3446
|
+
uploaded.model = Float32Array.from(model);
|
|
3447
|
+
}
|
|
3084
3448
|
}
|
|
3085
3449
|
function setSolidPaintUniforms(ctx, prog, color, opacity) {
|
|
3086
3450
|
const gl = ctx.gl;
|
|
@@ -3187,9 +3551,8 @@ function drawPathFillGradient(ctx, fill, handle) {
|
|
|
3187
3551
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
3188
3552
|
gl.bindVertexArray(null);
|
|
3189
3553
|
}
|
|
3190
|
-
function applyClipTest(ctx) {
|
|
3554
|
+
function applyClipTest(ctx, depth = ctx.clipDepth) {
|
|
3191
3555
|
const gl = ctx.gl;
|
|
3192
|
-
const depth = ctx.clipDepth;
|
|
3193
3556
|
if (depth === 0) {
|
|
3194
3557
|
gl.disable(gl.STENCIL_TEST);
|
|
3195
3558
|
return;
|
|
@@ -3212,6 +3575,7 @@ function rasterizePathToStencil(ctx, path) {
|
|
|
3212
3575
|
gl.bindVertexArray(null);
|
|
3213
3576
|
}
|
|
3214
3577
|
function pushClip(ctx, path, newDepth) {
|
|
3578
|
+
flushSolids(ctx);
|
|
3215
3579
|
const gl = ctx.gl;
|
|
3216
3580
|
const ancestors = ancestorMask(newDepth - 1);
|
|
3217
3581
|
const newBit = 1 << newDepth;
|
|
@@ -3226,6 +3590,7 @@ function pushClip(ctx, path, newDepth) {
|
|
|
3226
3590
|
gl.stencilMask(255);
|
|
3227
3591
|
}
|
|
3228
3592
|
function popClip(ctx, path, oldDepth) {
|
|
3593
|
+
flushSolids(ctx);
|
|
3229
3594
|
const gl = ctx.gl;
|
|
3230
3595
|
gl.enable(gl.STENCIL_TEST);
|
|
3231
3596
|
const oldBit = 1 << oldDepth + 1;
|
|
@@ -3273,6 +3638,7 @@ function drawPathStroke(ctx, cmd) {
|
|
|
3273
3638
|
}
|
|
3274
3639
|
const align = stroke.align ?? "center";
|
|
3275
3640
|
if (cmd.path.kind === "polygon" && align !== "center") {
|
|
3641
|
+
flushSolids(ctx);
|
|
3276
3642
|
drawPathStrokeStenciled(ctx, cmd, align);
|
|
3277
3643
|
return;
|
|
3278
3644
|
}
|
|
@@ -3281,11 +3647,13 @@ function drawPathStroke(ctx, cmd) {
|
|
|
3281
3647
|
function drawPathStrokeUnclipped(ctx, cmd) {
|
|
3282
3648
|
const stroke = cmd.stroke;
|
|
3283
3649
|
const solid = stroke.paint;
|
|
3284
|
-
const mesh =
|
|
3650
|
+
const mesh = strokeMesh(cmd.path, stroke, ctx.flattenTolerance);
|
|
3285
3651
|
if (mesh.indices.length === 0) return;
|
|
3286
|
-
const
|
|
3652
|
+
const hasVColors = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
3653
|
+
if (tryStageSolid(ctx, mesh, hasVColors ? void 0 : solid)) return;
|
|
3654
|
+
const handle = hasVColors ? ctx.meshCache.uploadTransient(mesh) : ctx.meshCache.uploadRecurring(mesh);
|
|
3287
3655
|
const gl = ctx.gl;
|
|
3288
|
-
if (
|
|
3656
|
+
if (hasVColors) {
|
|
3289
3657
|
const prog = ctx.pathFillVColor;
|
|
3290
3658
|
gl.useProgram(prog.handle);
|
|
3291
3659
|
gl.bindVertexArray(handle.vao);
|
|
@@ -3316,16 +3684,30 @@ function drawPathStrokeUnclipped(ctx, cmd) {
|
|
|
3316
3684
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
3317
3685
|
gl.bindVertexArray(null);
|
|
3318
3686
|
}
|
|
3687
|
+
var DOUBLED_VERTEX_WIDTHS = /* @__PURE__ */ new WeakMap();
|
|
3688
|
+
function doubledVertexWidths(widths) {
|
|
3689
|
+
let doubled = DOUBLED_VERTEX_WIDTHS.get(widths);
|
|
3690
|
+
if (doubled === void 0) {
|
|
3691
|
+
doubled = widths.map((w) => w * 2);
|
|
3692
|
+
DOUBLED_VERTEX_WIDTHS.set(widths, doubled);
|
|
3693
|
+
}
|
|
3694
|
+
return doubled;
|
|
3695
|
+
}
|
|
3319
3696
|
function drawPathStrokeStenciled(ctx, cmd, align) {
|
|
3320
3697
|
const stroke = cmd.stroke;
|
|
3321
3698
|
const solid = stroke.paint;
|
|
3322
|
-
const widerStroke = {
|
|
3699
|
+
const widerStroke = {
|
|
3700
|
+
...stroke,
|
|
3701
|
+
width: (stroke.width ?? 1) * 2,
|
|
3702
|
+
...stroke.vertexWidths ? { vertexWidths: doubledVertexWidths(stroke.vertexWidths) } : {},
|
|
3703
|
+
align: "center"
|
|
3704
|
+
};
|
|
3705
|
+
const useVColor = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
3323
3706
|
const fillHandle = fillMeshHandle(ctx, cmd.path);
|
|
3324
|
-
const ribbonMesh =
|
|
3707
|
+
const ribbonMesh = strokeMesh(cmd.path, widerStroke, ctx.flattenTolerance);
|
|
3325
3708
|
if (ribbonMesh.indices.length === 0) return;
|
|
3326
|
-
const ribbonHandle = ctx.meshCache.uploadTransient(ribbonMesh);
|
|
3709
|
+
const ribbonHandle = useVColor ? ctx.meshCache.uploadTransient(ribbonMesh) : ctx.meshCache.uploadRecurring(ribbonMesh);
|
|
3327
3710
|
const gl = ctx.gl;
|
|
3328
|
-
const useVColor = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
3329
3711
|
const prog = useVColor ? ctx.pathFillVColor : ctx.pathFill;
|
|
3330
3712
|
gl.useProgram(prog.handle);
|
|
3331
3713
|
setProjAndModel(ctx, prog);
|
|
@@ -3361,11 +3743,11 @@ function drawPathStrokeStenciled(ctx, cmd, align) {
|
|
|
3361
3743
|
}
|
|
3362
3744
|
}
|
|
3363
3745
|
gl.drawElements(gl.TRIANGLES, ribbonHandle.indexCount, gl.UNSIGNED_INT, 0);
|
|
3364
|
-
if (colorVbo) gl.deleteBuffer(colorVbo);
|
|
3365
3746
|
gl.stencilMask(1);
|
|
3366
3747
|
gl.clear(gl.STENCIL_BUFFER_BIT);
|
|
3367
3748
|
gl.disable(gl.STENCIL_TEST);
|
|
3368
3749
|
gl.bindVertexArray(null);
|
|
3750
|
+
if (colorVbo) gl.deleteBuffer(colorVbo);
|
|
3369
3751
|
}
|
|
3370
3752
|
var OUTLINE_MIN_SCREEN_PX = 48;
|
|
3371
3753
|
function modelScale(m) {
|
|
@@ -3380,20 +3762,17 @@ function drawText(ctx, cmd) {
|
|
|
3380
3762
|
const maxWidth = cmd.maxWidth ?? Infinity;
|
|
3381
3763
|
const minScreen = ctx.textOutlineMinScreenSize ?? OUTLINE_MIN_SCREEN_PX;
|
|
3382
3764
|
const outlineMinSize = Number.isFinite(minScreen) ? minScreen / modelScale(ctx.state.transform) : void 0;
|
|
3383
|
-
const laid = cachedLayoutRuns(
|
|
3384
|
-
cmd.runs,
|
|
3385
|
-
{ maxWidth, lineHeight, align, outlineMinSize },
|
|
3386
|
-
{ x: cmd.x, y: cmd.y }
|
|
3387
|
-
);
|
|
3765
|
+
const laid = cachedLayoutRuns(cmd.runs, { maxWidth, lineHeight, align, outlineMinSize });
|
|
3388
3766
|
if (laid.groups.length === 0 && laid.decorations.length === 0) return;
|
|
3389
|
-
const
|
|
3767
|
+
const dx = cmd.x;
|
|
3768
|
+
const dy = cmd.y + verticalAlignOffset(cmd.verticalAlign, cmd.height, laid.bounds.height);
|
|
3390
3769
|
const gl = ctx.gl;
|
|
3391
3770
|
applyClipTest(ctx);
|
|
3392
3771
|
const preparedPrograms = /* @__PURE__ */ new Set();
|
|
3393
3772
|
let currentProg = null;
|
|
3394
3773
|
for (const group of laid.groups) {
|
|
3395
3774
|
if (group.source === "outline") {
|
|
3396
|
-
drawTextOutlineGroup(ctx, group, dy);
|
|
3775
|
+
drawTextOutlineGroup(ctx, group, dx, dy);
|
|
3397
3776
|
currentProg = null;
|
|
3398
3777
|
continue;
|
|
3399
3778
|
}
|
|
@@ -3408,31 +3787,31 @@ function drawText(ctx, cmd) {
|
|
|
3408
3787
|
setColorMatrixUniforms(ctx, prog);
|
|
3409
3788
|
gl.uniform1f(prog.uniform("u_alpha"), ctx.state.alpha);
|
|
3410
3789
|
}
|
|
3411
|
-
drawTextGroup(ctx, group, prog, dy);
|
|
3790
|
+
drawTextGroup(ctx, group, prog, dx, dy);
|
|
3412
3791
|
}
|
|
3413
|
-
drawTextDecorations(ctx, laid.decorations, dy);
|
|
3792
|
+
drawTextDecorations(ctx, laid.decorations, dx, dy);
|
|
3414
3793
|
}
|
|
3415
3794
|
var SYNTHETIC_ITALIC_RADIANS = 0.2094;
|
|
3416
|
-
function drawTextOutlineGroup(ctx, group, dy) {
|
|
3417
|
-
const mesh = outlineGroupMesh(group, dy);
|
|
3795
|
+
function drawTextOutlineGroup(ctx, group, dx, dy) {
|
|
3796
|
+
const mesh = outlineGroupMesh(group, dx, dy);
|
|
3418
3797
|
if (mesh) drawPathFillByKind(ctx, group.fill, ctx.meshCache.uploadTransient(mesh));
|
|
3419
3798
|
if (!group.stroke) return;
|
|
3420
|
-
const
|
|
3421
|
-
if (
|
|
3422
|
-
drawPathFillByKind(ctx, group.stroke.paint, ctx.meshCache.uploadTransient(
|
|
3799
|
+
const ribbon = outlineGroupStrokeMesh(group, dx, dy);
|
|
3800
|
+
if (ribbon) {
|
|
3801
|
+
drawPathFillByKind(ctx, group.stroke.paint, ctx.meshCache.uploadTransient(ribbon));
|
|
3423
3802
|
}
|
|
3424
3803
|
}
|
|
3425
|
-
function outlineGroupMesh(group, dy) {
|
|
3426
|
-
return mergeGlyphMeshes(group, dy, (glyph) => outlineMesh(glyph.key, glyph.d));
|
|
3804
|
+
function outlineGroupMesh(group, dx, dy) {
|
|
3805
|
+
return mergeGlyphMeshes(group, dx, dy, (glyph) => outlineMesh(glyph.key, glyph.d));
|
|
3427
3806
|
}
|
|
3428
|
-
function outlineGroupStrokeMesh(group, dy) {
|
|
3807
|
+
function outlineGroupStrokeMesh(group, dx, dy) {
|
|
3429
3808
|
const stroke = group.stroke;
|
|
3430
3809
|
if (!stroke) return null;
|
|
3431
3810
|
const width = stroke.width ?? 1;
|
|
3432
3811
|
if (!(width > 0)) return null;
|
|
3433
|
-
return mergeGlyphMeshes(group, dy, (glyph) => glyph.scale > 0 ? outlineStrokeMesh(glyph.key, glyph.d, quantizeEmWidth(width / glyph.scale), stroke) : null);
|
|
3812
|
+
return mergeGlyphMeshes(group, dx, dy, (glyph) => glyph.scale > 0 ? outlineStrokeMesh(glyph.key, glyph.d, quantizeEmWidth(width / glyph.scale), stroke) : null);
|
|
3434
3813
|
}
|
|
3435
|
-
function mergeGlyphMeshes(group, dy, meshFor) {
|
|
3814
|
+
function mergeGlyphMeshes(group, dx, dy, meshFor) {
|
|
3436
3815
|
const parts = [];
|
|
3437
3816
|
let vertexFloats = 0;
|
|
3438
3817
|
let indexCount = 0;
|
|
@@ -3455,7 +3834,7 @@ function mergeGlyphMeshes(group, dy, meshFor) {
|
|
|
3455
3834
|
for (let k = 0; k < mesh.vertices.length; k += 2) {
|
|
3456
3835
|
const ex = mesh.vertices[k];
|
|
3457
3836
|
const ey = mesh.vertices[k + 1];
|
|
3458
|
-
vertices[vi++] = x + (ex - ey * shear) * scale2;
|
|
3837
|
+
vertices[vi++] = x + dx + (ex - ey * shear) * scale2;
|
|
3459
3838
|
vertices[vi++] = baselineY + dy + ey * scale2;
|
|
3460
3839
|
}
|
|
3461
3840
|
for (let k = 0; k < mesh.indices.length; k++) indices[ii++] = base + mesh.indices[k];
|
|
@@ -3463,7 +3842,7 @@ function mergeGlyphMeshes(group, dy, meshFor) {
|
|
|
3463
3842
|
}
|
|
3464
3843
|
return { vertices, indices };
|
|
3465
3844
|
}
|
|
3466
|
-
function drawTextDecorations(ctx, decorations, dy) {
|
|
3845
|
+
function drawTextDecorations(ctx, decorations, dx, dy) {
|
|
3467
3846
|
if (decorations.length === 0) return;
|
|
3468
3847
|
const batches = /* @__PURE__ */ new Map();
|
|
3469
3848
|
for (const d of decorations) {
|
|
@@ -3486,14 +3865,15 @@ function drawTextDecorations(ctx, decorations, dy) {
|
|
|
3486
3865
|
const vertices = new Float32Array(rects.length * 4 * 2);
|
|
3487
3866
|
let vi = 0;
|
|
3488
3867
|
for (const d of rects) {
|
|
3868
|
+
const dx0 = d.x0 + dx, dx1 = d.x1 + dx;
|
|
3489
3869
|
const dy0 = d.y0 + dy, dy1 = d.y1 + dy;
|
|
3490
|
-
vertices[vi++] =
|
|
3870
|
+
vertices[vi++] = dx0;
|
|
3491
3871
|
vertices[vi++] = dy0;
|
|
3492
|
-
vertices[vi++] =
|
|
3872
|
+
vertices[vi++] = dx1;
|
|
3493
3873
|
vertices[vi++] = dy0;
|
|
3494
|
-
vertices[vi++] =
|
|
3874
|
+
vertices[vi++] = dx0;
|
|
3495
3875
|
vertices[vi++] = dy1;
|
|
3496
|
-
vertices[vi++] =
|
|
3876
|
+
vertices[vi++] = dx1;
|
|
3497
3877
|
vertices[vi++] = dy1;
|
|
3498
3878
|
}
|
|
3499
3879
|
const indices = new Uint32Array(rects.length * 6);
|
|
@@ -3532,7 +3912,7 @@ function drawTextDecorations(ctx, decorations, dy) {
|
|
|
3532
3912
|
gl.deleteBuffer(ibo);
|
|
3533
3913
|
}
|
|
3534
3914
|
}
|
|
3535
|
-
function drawTextGroup(ctx, group, prog, dy) {
|
|
3915
|
+
function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
3536
3916
|
if (group.source === "canvas") {
|
|
3537
3917
|
if (!syncDynamicPageTexture(ctx.textureCache, group.page)) return;
|
|
3538
3918
|
} else {
|
|
@@ -3543,23 +3923,24 @@ function drawTextGroup(ctx, group, prog, dy) {
|
|
|
3543
3923
|
const vertices = new Float32Array(group.quads.length * 4 * 5);
|
|
3544
3924
|
let vi = 0;
|
|
3545
3925
|
for (const q of group.quads) {
|
|
3926
|
+
const x0 = q.x0 + dx, x1 = q.x1 + dx;
|
|
3546
3927
|
const y0 = q.y0 + dy, y1 = q.y1 + dy, by = q.baselineY + dy;
|
|
3547
|
-
vertices[vi++] =
|
|
3928
|
+
vertices[vi++] = x0;
|
|
3548
3929
|
vertices[vi++] = y0;
|
|
3549
3930
|
vertices[vi++] = q.u0;
|
|
3550
3931
|
vertices[vi++] = q.v0;
|
|
3551
3932
|
vertices[vi++] = by;
|
|
3552
|
-
vertices[vi++] =
|
|
3933
|
+
vertices[vi++] = x1;
|
|
3553
3934
|
vertices[vi++] = y0;
|
|
3554
3935
|
vertices[vi++] = q.u1;
|
|
3555
3936
|
vertices[vi++] = q.v0;
|
|
3556
3937
|
vertices[vi++] = by;
|
|
3557
|
-
vertices[vi++] =
|
|
3938
|
+
vertices[vi++] = x0;
|
|
3558
3939
|
vertices[vi++] = y1;
|
|
3559
3940
|
vertices[vi++] = q.u0;
|
|
3560
3941
|
vertices[vi++] = q.v1;
|
|
3561
3942
|
vertices[vi++] = by;
|
|
3562
|
-
vertices[vi++] =
|
|
3943
|
+
vertices[vi++] = x1;
|
|
3563
3944
|
vertices[vi++] = y1;
|
|
3564
3945
|
vertices[vi++] = q.u1;
|
|
3565
3946
|
vertices[vi++] = q.v1;
|
|
@@ -3757,16 +4138,28 @@ function registerProgram(id, vert, frag) {
|
|
|
3757
4138
|
}
|
|
3758
4139
|
|
|
3759
4140
|
// src/renderer/WeaselRenderer.ts
|
|
4141
|
+
var UNIFORM_QUALIFIER = /^(?:lowp|mediump|highp|precise|invariant|centroid|flat|smooth|noperspective)$/;
|
|
3760
4142
|
function extractUniformNames(glsl) {
|
|
3761
|
-
const
|
|
3762
|
-
const reArray = /\buniform\s+\S+\s+(\w+)\s*\[\s*(\d+)\s*\]\s*;/g;
|
|
4143
|
+
const re = /\buniform\s+([^;{]+);/g;
|
|
3763
4144
|
const names = [];
|
|
3764
4145
|
let m;
|
|
3765
|
-
while ((m =
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
4146
|
+
while ((m = re.exec(glsl)) !== null) {
|
|
4147
|
+
const words = m[1].trim().split(/\s+/);
|
|
4148
|
+
let i = 0;
|
|
4149
|
+
while (i < words.length && UNIFORM_QUALIFIER.test(words[i])) i++;
|
|
4150
|
+
i++;
|
|
4151
|
+
const declarators = words.slice(i).join(" ");
|
|
4152
|
+
if (!declarators) continue;
|
|
4153
|
+
for (const raw of declarators.split(",")) {
|
|
4154
|
+
const d = raw.trim();
|
|
4155
|
+
const arr = /^(\w+)\s*\[\s*(\d+)\s*\]$/.exec(d);
|
|
4156
|
+
if (arr) {
|
|
4157
|
+
const size = parseInt(arr[2], 10);
|
|
4158
|
+
for (let k = 0; k < size; k++) names.push(`${arr[1]}[${k}]`);
|
|
4159
|
+
} else if (/^\w+$/.test(d)) {
|
|
4160
|
+
names.push(d);
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
3770
4163
|
}
|
|
3771
4164
|
return names;
|
|
3772
4165
|
}
|
|
@@ -3786,10 +4179,7 @@ var WeaselRenderer = class {
|
|
|
3786
4179
|
programRegistry = /* @__PURE__ */ new Map();
|
|
3787
4180
|
quadVbo = null;
|
|
3788
4181
|
quadIbo = null;
|
|
3789
|
-
|
|
3790
|
-
rectVao = null;
|
|
3791
|
-
rectVbo = null;
|
|
3792
|
-
rectIbo = null;
|
|
4182
|
+
solidBatch;
|
|
3793
4183
|
groupState = new GroupState();
|
|
3794
4184
|
widthCss;
|
|
3795
4185
|
heightCss;
|
|
@@ -3864,31 +4254,7 @@ var WeaselRenderer = class {
|
|
|
3864
4254
|
this.imageCache = new GLImageCache(this.gl, this.imageMinification);
|
|
3865
4255
|
this.gradRampCache = new GradientRampCache(this.gl);
|
|
3866
4256
|
this.uploadQuadGeometry();
|
|
3867
|
-
this.
|
|
3868
|
-
}
|
|
3869
|
-
/** Allocate the shared rect VAO + dynamic VBO (4 verts × 2 floats) + static
|
|
3870
|
-
* IBO (6 indices). drawRectFast bufferSubData's the 4 corner coords each
|
|
3871
|
-
* draw, avoiding per-rect buffer allocation in animated demos. */
|
|
3872
|
-
uploadRectGeometry(aPositionLoc) {
|
|
3873
|
-
const gl = this.gl;
|
|
3874
|
-
this.rectVao = gl.createVertexArray();
|
|
3875
|
-
this.rectVbo = gl.createBuffer();
|
|
3876
|
-
this.rectIbo = gl.createBuffer();
|
|
3877
|
-
if (!this.rectVao || !this.rectVbo || !this.rectIbo) {
|
|
3878
|
-
throw new Error("WeaselRenderer: failed to create rect-fast geometry");
|
|
3879
|
-
}
|
|
3880
|
-
gl.bindVertexArray(this.rectVao);
|
|
3881
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.rectVbo);
|
|
3882
|
-
gl.bufferData(gl.ARRAY_BUFFER, 8 * 4, gl.DYNAMIC_DRAW);
|
|
3883
|
-
gl.enableVertexAttribArray(aPositionLoc);
|
|
3884
|
-
gl.vertexAttribPointer(aPositionLoc, 2, gl.FLOAT, false, 0, 0);
|
|
3885
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.rectIbo);
|
|
3886
|
-
gl.bufferData(
|
|
3887
|
-
gl.ELEMENT_ARRAY_BUFFER,
|
|
3888
|
-
new Uint32Array([0, 1, 2, 0, 2, 3]),
|
|
3889
|
-
gl.STATIC_DRAW
|
|
3890
|
-
);
|
|
3891
|
-
gl.bindVertexArray(null);
|
|
4257
|
+
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
3892
4258
|
}
|
|
3893
4259
|
uploadQuadGeometry() {
|
|
3894
4260
|
const gl = this.gl;
|
|
@@ -3976,7 +4342,7 @@ var WeaselRenderer = class {
|
|
|
3976
4342
|
this.gradRampCache = new GradientRampCache(this.gl);
|
|
3977
4343
|
markAllFontsNotUploaded();
|
|
3978
4344
|
this.uploadQuadGeometry();
|
|
3979
|
-
this.
|
|
4345
|
+
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
3980
4346
|
for (const id of this.programRegistry.keys()) {
|
|
3981
4347
|
const src = getProgramSource(id);
|
|
3982
4348
|
if (!src) continue;
|
|
@@ -4036,9 +4402,7 @@ var WeaselRenderer = class {
|
|
|
4036
4402
|
this.gradRampCache.free();
|
|
4037
4403
|
if (this.quadVbo) gl.deleteBuffer(this.quadVbo);
|
|
4038
4404
|
if (this.quadIbo) gl.deleteBuffer(this.quadIbo);
|
|
4039
|
-
|
|
4040
|
-
if (this.rectIbo) gl.deleteBuffer(this.rectIbo);
|
|
4041
|
-
if (this.rectVao) gl.deleteVertexArray(this.rectVao);
|
|
4405
|
+
this.solidBatch.dispose();
|
|
4042
4406
|
}
|
|
4043
4407
|
/**
|
|
4044
4408
|
* Draw one frame.
|
|
@@ -4071,8 +4435,7 @@ var WeaselRenderer = class {
|
|
|
4071
4435
|
programRegistry: this.programRegistry,
|
|
4072
4436
|
quadVbo: this.quadVbo,
|
|
4073
4437
|
quadIbo: this.quadIbo,
|
|
4074
|
-
|
|
4075
|
-
rectVbo: this.rectVbo,
|
|
4438
|
+
solidBatch: this.solidBatch,
|
|
4076
4439
|
state: this.groupState,
|
|
4077
4440
|
widthCss: this.widthCss,
|
|
4078
4441
|
heightCss: this.heightCss,
|
|
@@ -4082,6 +4445,7 @@ var WeaselRenderer = class {
|
|
|
4082
4445
|
viewMatrix
|
|
4083
4446
|
};
|
|
4084
4447
|
for (const cmd of commands) dispatch(ctx, cmd);
|
|
4448
|
+
flushSolids(ctx);
|
|
4085
4449
|
this.meshCache.freeTransient();
|
|
4086
4450
|
}
|
|
4087
4451
|
resize(dims) {
|
|
@@ -4111,6 +4475,10 @@ var WeaselRenderer = class {
|
|
|
4111
4475
|
return this.pathFillVColor;
|
|
4112
4476
|
}
|
|
4113
4477
|
/** @internal */
|
|
4478
|
+
_solidBatch() {
|
|
4479
|
+
return this.solidBatch;
|
|
4480
|
+
}
|
|
4481
|
+
/** @internal */
|
|
4114
4482
|
_textSdf() {
|
|
4115
4483
|
return this.textSdf;
|
|
4116
4484
|
}
|
|
@@ -4320,6 +4688,14 @@ function createViewportLayer(opts) {
|
|
|
4320
4688
|
id,
|
|
4321
4689
|
label,
|
|
4322
4690
|
space: "screen",
|
|
4691
|
+
reproject(outer, dims, screen) {
|
|
4692
|
+
const b = bounds(outer, dims);
|
|
4693
|
+
if (screen.x < b.x || screen.x >= b.x + b.w || screen.y < b.y || screen.y >= b.y + b.h) return null;
|
|
4694
|
+
return {
|
|
4695
|
+
x: (screen.x - b.x) / view.scale.x + view.x,
|
|
4696
|
+
y: (screen.y - b.y) / view.scale.y + view.y
|
|
4697
|
+
};
|
|
4698
|
+
},
|
|
4323
4699
|
draw: (data, outerView, dims) => {
|
|
4324
4700
|
const b = bounds(outerView, dims);
|
|
4325
4701
|
const children = [];
|
|
@@ -4346,6 +4722,14 @@ function createViewportLayer(opts) {
|
|
|
4346
4722
|
}
|
|
4347
4723
|
};
|
|
4348
4724
|
}
|
|
4725
|
+
function viewportsAt(layers, outer, dims, screen) {
|
|
4726
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
4727
|
+
const layer = layers[i];
|
|
4728
|
+
const point = layer.reproject(outer, dims, screen);
|
|
4729
|
+
if (point) return { layer, point };
|
|
4730
|
+
}
|
|
4731
|
+
return null;
|
|
4732
|
+
}
|
|
4349
4733
|
|
|
4350
4734
|
// src/features/parallax/deriveParallaxView.ts
|
|
4351
4735
|
function asXY(v) {
|
|
@@ -5380,12 +5764,7 @@ function moveGestureAdapter(scene) {
|
|
|
5380
5764
|
return {
|
|
5381
5765
|
getNode: (id) => scene.get(asNodeId(id)),
|
|
5382
5766
|
getNodes: () => {
|
|
5383
|
-
|
|
5384
|
-
for (const id of scene.renderOrder()) {
|
|
5385
|
-
const n = scene.get(id);
|
|
5386
|
-
if (n) out.push(n);
|
|
5387
|
-
}
|
|
5388
|
-
return out;
|
|
5767
|
+
return [...scene.renderOrderNodes()];
|
|
5389
5768
|
},
|
|
5390
5769
|
getPose: (id) => scene.get(asNodeId(id)).pose,
|
|
5391
5770
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
@@ -5484,6 +5863,12 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
5484
5863
|
if (layout2.contains) return layout2.contains(cPose, draggedCenter);
|
|
5485
5864
|
return draggedCenter.x >= aabb.x && draggedCenter.x < aabb.x + aabb.width && draggedCenter.y >= aabb.y && draggedCenter.y < aabb.y + aabb.height;
|
|
5486
5865
|
};
|
|
5866
|
+
const draggedArg = {
|
|
5867
|
+
id: draggedId,
|
|
5868
|
+
originPose: startWorld,
|
|
5869
|
+
pose: draggedWorld,
|
|
5870
|
+
sourceContainerId
|
|
5871
|
+
};
|
|
5487
5872
|
const consider = (id, zPath) => {
|
|
5488
5873
|
if (id === draggedId) return;
|
|
5489
5874
|
const layout2 = layoutDep.getLayout(id);
|
|
@@ -5493,6 +5878,7 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
5493
5878
|
const worldPose = composeWorldPose(poseAdapter, id, pc.compose);
|
|
5494
5879
|
const worldAABB = boundsOf2(worldPose);
|
|
5495
5880
|
if (!testInside(worldPose, worldAABB, layout2)) return;
|
|
5881
|
+
if (layout2.acceptsDrop && !layout2.acceptsDrop({ id, bounds: worldAABB }, draggedArg)) return;
|
|
5496
5882
|
candidates.push({
|
|
5497
5883
|
id,
|
|
5498
5884
|
bounds: worldAABB,
|
|
@@ -5541,20 +5927,16 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
5541
5927
|
id: cid,
|
|
5542
5928
|
pose: composeWorldPose(poseAdapter, cid, pc.compose)
|
|
5543
5929
|
}));
|
|
5544
|
-
const draggedArg = {
|
|
5545
|
-
id: draggedId,
|
|
5546
|
-
originPose: startWorld,
|
|
5547
|
-
pose: draggedWorld,
|
|
5548
|
-
sourceContainerId
|
|
5549
|
-
};
|
|
5550
5930
|
const targets = layout.getDropTargets(container, children, draggedArg);
|
|
5551
5931
|
const target = layout.snap.pickTarget(targets, { x: moveCtx.drag.current.x, y: moveCtx.drag.current.y });
|
|
5552
5932
|
if (!target) return;
|
|
5933
|
+
const reflowIds = /* @__PURE__ */ new Set();
|
|
5553
5934
|
for (const [cid, pose] of layout.reflowPoses(container, children, draggedArg, target)) {
|
|
5554
5935
|
if (asNodeId(cid) === draggedId) continue;
|
|
5555
5936
|
const parent = scene.get(asNodeId(cid))?.parent ?? null;
|
|
5556
5937
|
const local = rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose);
|
|
5557
5938
|
scratch.previews.set(asNodeId(cid), local);
|
|
5939
|
+
reflowIds.add(asNodeId(cid));
|
|
5558
5940
|
}
|
|
5559
5941
|
const sourceReflow = /* @__PURE__ */ new Map();
|
|
5560
5942
|
if (sourceContainerId && sourceContainerId !== dest.id) {
|
|
@@ -5577,10 +5959,11 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
5577
5959
|
sourceReflow.set(cid, pose);
|
|
5578
5960
|
const parent = scene.get(asNodeId(cid))?.parent ?? null;
|
|
5579
5961
|
scratch.previews.set(asNodeId(cid), rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose));
|
|
5962
|
+
reflowIds.add(asNodeId(cid));
|
|
5580
5963
|
}
|
|
5581
5964
|
}
|
|
5582
5965
|
}
|
|
5583
|
-
scratch.layoutPass = { layout, container, children, target, sourceReflow };
|
|
5966
|
+
scratch.layoutPass = { layout, container, children, target, sourceReflow, reflowIds };
|
|
5584
5967
|
}
|
|
5585
5968
|
function scenePoseAdapter(scene) {
|
|
5586
5969
|
return {
|
|
@@ -5888,7 +6271,8 @@ var moveAction = {
|
|
|
5888
6271
|
scratch.previews.clear();
|
|
5889
6272
|
},
|
|
5890
6273
|
previewIds: () => scratch.previews.keys(),
|
|
5891
|
-
previewPose: (id) => scratch.previews.get(id) ?? null
|
|
6274
|
+
previewPose: (id) => scratch.previews.get(id) ?? null,
|
|
6275
|
+
previewOpaqueIds: () => scratch.layoutPass?.reflowIds ?? null
|
|
5892
6276
|
};
|
|
5893
6277
|
}
|
|
5894
6278
|
},
|
|
@@ -6001,12 +6385,7 @@ function defaultCommitAdapter(scene) {
|
|
|
6001
6385
|
return {
|
|
6002
6386
|
getNode: (id) => scene.get(asNodeId(id)),
|
|
6003
6387
|
getNodes: () => {
|
|
6004
|
-
|
|
6005
|
-
for (const id of scene.renderOrder()) {
|
|
6006
|
-
const n = scene.get(id);
|
|
6007
|
-
if (n) out.push(n);
|
|
6008
|
-
}
|
|
6009
|
-
return out;
|
|
6388
|
+
return [...scene.renderOrderNodes()];
|
|
6010
6389
|
},
|
|
6011
6390
|
getPose: (id) => scene.get(asNodeId(id)).pose,
|
|
6012
6391
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
@@ -6662,7 +7041,8 @@ var KIT_INSERT_KINDS = /* @__PURE__ */ new Set([
|
|
|
6662
7041
|
"line",
|
|
6663
7042
|
"polygon",
|
|
6664
7043
|
"star",
|
|
6665
|
-
"pencil"
|
|
7044
|
+
"pencil",
|
|
7045
|
+
"image"
|
|
6666
7046
|
]);
|
|
6667
7047
|
var liveInsertScratch = null;
|
|
6668
7048
|
function effectiveOriginMode(paramsOrigin, altHeld) {
|
|
@@ -7791,7 +8171,7 @@ var pinchZoomAction = {
|
|
|
7791
8171
|
const multiTouch = ctx.multiTouch;
|
|
7792
8172
|
if (!multiTouch) return {};
|
|
7793
8173
|
const startSpread = multiTouch.spread > 0 ? multiTouch.spread : 1;
|
|
7794
|
-
const scratch = { view, startSpread };
|
|
8174
|
+
const scratch = { view, startSpread, centroid: multiTouch.centroid };
|
|
7795
8175
|
return {
|
|
7796
8176
|
kind: "pinch",
|
|
7797
8177
|
onMove(moveCtx) {
|
|
@@ -7801,8 +8181,15 @@ var pinchZoomAction = {
|
|
|
7801
8181
|
if (currentSpread <= 0 || scratch.startSpread <= 0) return;
|
|
7802
8182
|
const factor = currentSpread / scratch.startSpread;
|
|
7803
8183
|
scratch.startSpread = currentSpread;
|
|
8184
|
+
const prev = scratch.centroid;
|
|
8185
|
+
scratch.centroid = centroid;
|
|
7804
8186
|
const current = scratch.view.get();
|
|
7805
|
-
|
|
8187
|
+
const zoomed = zoomAt(current, prev, factor);
|
|
8188
|
+
scratch.view.set({
|
|
8189
|
+
scale: zoomed.scale,
|
|
8190
|
+
x: zoomed.x - (centroid.x - prev.x) / zoomed.scale.x,
|
|
8191
|
+
y: zoomed.y - (centroid.y - prev.y) / zoomed.scale.y
|
|
8192
|
+
});
|
|
7806
8193
|
}
|
|
7807
8194
|
// onEnd: nothing to do — zoom was applied each frame.
|
|
7808
8195
|
};
|
|
@@ -8286,10 +8673,12 @@ function normalizeNegativeExtent(pose) {
|
|
|
8286
8673
|
}
|
|
8287
8674
|
|
|
8288
8675
|
// src/interactions/actions/defaults/flip.ts
|
|
8289
|
-
function flipSelection(selection, scene, axis, applyOps, geometryProjection) {
|
|
8676
|
+
function flipSelection(selection, scene, axis, pivot, applyOps, geometryProjection) {
|
|
8290
8677
|
const ids = selection.get();
|
|
8291
8678
|
if (ids.length === 0) return;
|
|
8292
8679
|
const geom = AUTO_POSE_DESCRIPTOR;
|
|
8680
|
+
const nodes = ids.map((id) => scene.get(id)).filter((n) => n != null);
|
|
8681
|
+
const unionPivot = pivot === "union" ? unionBounds(nodes.map((n) => geom.getBounds(n.pose))) : null;
|
|
8293
8682
|
const ops = [];
|
|
8294
8683
|
for (const id of ids) {
|
|
8295
8684
|
const node = scene.get(id);
|
|
@@ -8297,10 +8686,10 @@ function flipSelection(selection, scene, axis, applyOps, geometryProjection) {
|
|
|
8297
8686
|
ops.push(createTransformOp({
|
|
8298
8687
|
id,
|
|
8299
8688
|
from: node.pose,
|
|
8300
|
-
to: flipPoseViaDescriptor(node.pose, axis, geom),
|
|
8689
|
+
to: unionPivot ? flipPoseAboutBounds(node.pose, axis, geom, unionPivot) : flipPoseViaDescriptor(node.pose, axis, geom),
|
|
8301
8690
|
label: "Flip"
|
|
8302
8691
|
}));
|
|
8303
|
-
const g = geom.getBounds(node.pose);
|
|
8692
|
+
const g = unionPivot ?? geom.getBounds(node.pose);
|
|
8304
8693
|
const cx = g.x + g.width / 2;
|
|
8305
8694
|
const cy = g.y + g.height / 2;
|
|
8306
8695
|
const m = axis === "x" ? [-1, 0, 0, 1, 2 * cx, 0] : [1, 0, 0, -1, 0, 2 * cy];
|
|
@@ -8329,12 +8718,13 @@ var flipAction = {
|
|
|
8329
8718
|
timing: "immediate",
|
|
8330
8719
|
run: (deps, params) => {
|
|
8331
8720
|
const axis = params?.axis ?? "x";
|
|
8721
|
+
const pivot = params?.pivot ?? "each";
|
|
8332
8722
|
const selection = deps.selection;
|
|
8333
8723
|
const scene = deps.scene;
|
|
8334
8724
|
const applyOps = deps.applyOps;
|
|
8335
8725
|
const geometryProjection = deps.geometryProjection;
|
|
8336
8726
|
if (!selection || !scene) return;
|
|
8337
|
-
flipSelection(selection, scene, axis, applyOps, geometryProjection);
|
|
8727
|
+
flipSelection(selection, scene, axis, pivot, applyOps, geometryProjection);
|
|
8338
8728
|
}
|
|
8339
8729
|
},
|
|
8340
8730
|
enabled: requiresSelection
|
|
@@ -10283,6 +10673,12 @@ var DEFAULT_DEBUG_THEME = {
|
|
|
10283
10673
|
fpsText: "#e0e0e0",
|
|
10284
10674
|
fpsTextBg: "rgba(0, 0, 0, 0.6)"
|
|
10285
10675
|
};
|
|
10676
|
+
var DEFAULT_DEBUG_STROKES = {
|
|
10677
|
+
hitbox: { width: 1, dash: [2, 2] },
|
|
10678
|
+
bounds: { width: 1 },
|
|
10679
|
+
handle: { width: 1 },
|
|
10680
|
+
snap: { width: 1 }
|
|
10681
|
+
};
|
|
10286
10682
|
|
|
10287
10683
|
// src/debug/createDebugOverlayLayer.ts
|
|
10288
10684
|
function createDebugOverlayLayer({
|
|
@@ -10290,6 +10686,7 @@ function createDebugOverlayLayer({
|
|
|
10290
10686
|
config
|
|
10291
10687
|
}) {
|
|
10292
10688
|
const theme = { ...DEFAULT_DEBUG_THEME, ...config.theme ?? {} };
|
|
10689
|
+
const strokes = { ...DEFAULT_DEBUG_STROKES, ...config.strokes ?? {} };
|
|
10293
10690
|
const fpsHistory = [];
|
|
10294
10691
|
const FPS_WINDOW = 60;
|
|
10295
10692
|
return {
|
|
@@ -10301,11 +10698,11 @@ function createDebugOverlayLayer({
|
|
|
10301
10698
|
const s = sink.snapshot();
|
|
10302
10699
|
const t = viewToTransform(view);
|
|
10303
10700
|
const out = [];
|
|
10304
|
-
if (config.hitboxes) emitHitboxes(out, s, view, t, theme);
|
|
10305
|
-
if (config.bounds) emitBounds(out, s, view, t, theme);
|
|
10306
|
-
if (config.handles) emitHandles(out, s, t, theme);
|
|
10701
|
+
if (config.hitboxes) emitHitboxes(out, s, view, t, theme, strokes);
|
|
10702
|
+
if (config.bounds) emitBounds(out, s, view, t, theme, strokes);
|
|
10703
|
+
if (config.handles) emitHandles(out, s, t, theme, strokes);
|
|
10307
10704
|
if (config.origins) emitOrigins(out, s, t, theme);
|
|
10308
|
-
if (config.snap) emitSnap(out, s, t, theme);
|
|
10705
|
+
if (config.snap) emitSnap(out, s, t, theme, strokes);
|
|
10309
10706
|
if (config.ids) emitIds(out, s, t, theme);
|
|
10310
10707
|
if (config.layers) emitLayersPanel(out, s, dims, theme);
|
|
10311
10708
|
if (config.fps) {
|
|
@@ -10338,9 +10735,16 @@ function approxCircleScreen(cx, cy, r, segments = 24) {
|
|
|
10338
10735
|
function rectPath2(x, y, w, h) {
|
|
10339
10736
|
return { kind: "rect", x, y, width: w, height: h };
|
|
10340
10737
|
}
|
|
10341
|
-
function
|
|
10738
|
+
function strokeOf(s, color) {
|
|
10739
|
+
return {
|
|
10740
|
+
paint: { fill: "solid", color },
|
|
10741
|
+
width: s.width,
|
|
10742
|
+
...s.dash && s.dash.length > 0 ? { dash: [...s.dash] } : {}
|
|
10743
|
+
};
|
|
10744
|
+
}
|
|
10745
|
+
function emitHitboxes(out, s, view, t, theme, strokes) {
|
|
10342
10746
|
const fill = { fill: "solid", color: theme.hitboxFill };
|
|
10343
|
-
const stroke =
|
|
10747
|
+
const stroke = strokeOf(strokes.hitbox, theme.hitboxStroke);
|
|
10344
10748
|
for (const h of s.hitboxes) {
|
|
10345
10749
|
if (h.shape.kind === "rect") {
|
|
10346
10750
|
const [sx, sy] = worldToScreen(h.shape.x, h.shape.y, t);
|
|
@@ -10354,8 +10758,8 @@ function emitHitboxes(out, s, view, t, theme) {
|
|
|
10354
10758
|
}
|
|
10355
10759
|
}
|
|
10356
10760
|
}
|
|
10357
|
-
function emitBounds(out, s, view, t, theme) {
|
|
10358
|
-
const stroke =
|
|
10761
|
+
function emitBounds(out, s, view, t, theme, strokes) {
|
|
10762
|
+
const stroke = strokeOf(strokes.bounds, theme.bounds);
|
|
10359
10763
|
for (const b of s.bounds) {
|
|
10360
10764
|
const [sx, sy] = worldToScreen(b.bounds.x, b.bounds.y, t);
|
|
10361
10765
|
const sw = b.bounds.width * view.scale.x;
|
|
@@ -10363,8 +10767,8 @@ function emitBounds(out, s, view, t, theme) {
|
|
|
10363
10767
|
out.push({ kind: "path", path: rectPath2(sx, sy, sw, sh), stroke });
|
|
10364
10768
|
}
|
|
10365
10769
|
}
|
|
10366
|
-
function emitHandles(out, s, t, theme) {
|
|
10367
|
-
const stroke =
|
|
10770
|
+
function emitHandles(out, s, t, theme, strokes) {
|
|
10771
|
+
const stroke = strokeOf(strokes.handle, theme.handle);
|
|
10368
10772
|
for (const h of s.handles) {
|
|
10369
10773
|
const [cx, cy] = worldToScreen(h.position.x, h.position.y, t);
|
|
10370
10774
|
const horiz = {
|
|
@@ -10390,14 +10794,14 @@ function emitOrigins(out, s, t, theme) {
|
|
|
10390
10794
|
out.push({ kind: "path", path: approxCircleScreen(cx, cy, 3), fill });
|
|
10391
10795
|
}
|
|
10392
10796
|
}
|
|
10393
|
-
function emitSnap(out, s, t, theme) {
|
|
10797
|
+
function emitSnap(out, s, t, theme, strokes) {
|
|
10394
10798
|
const color = theme.snap;
|
|
10395
10799
|
for (const c of s.snap) {
|
|
10396
10800
|
const [cx, cy] = worldToScreen(c.point.x, c.point.y, t);
|
|
10397
10801
|
const cmd = {
|
|
10398
10802
|
kind: "path",
|
|
10399
10803
|
path: approxCircleScreen(cx, cy, 4),
|
|
10400
|
-
...c.accepted ? { fill: { fill: "solid", color } } : { stroke:
|
|
10804
|
+
...c.accepted ? { fill: { fill: "solid", color } } : { stroke: strokeOf(strokes.snap, color) }
|
|
10401
10805
|
};
|
|
10402
10806
|
out.push(cmd);
|
|
10403
10807
|
}
|
|
@@ -10706,18 +11110,39 @@ function modsCount(mods) {
|
|
|
10706
11110
|
}
|
|
10707
11111
|
function targetRank(target) {
|
|
10708
11112
|
if (target === void 0) return 0;
|
|
10709
|
-
|
|
10710
|
-
if (
|
|
10711
|
-
|
|
10712
|
-
|
|
11113
|
+
const form = parseTargetSpec(target);
|
|
11114
|
+
if (form === null) return 1;
|
|
11115
|
+
switch (form.form) {
|
|
11116
|
+
case "kind":
|
|
11117
|
+
return form.requireSelected ? 3 : 2;
|
|
11118
|
+
case "affordance":
|
|
11119
|
+
return 2;
|
|
11120
|
+
case "body":
|
|
11121
|
+
return 1;
|
|
11122
|
+
case "predicate":
|
|
11123
|
+
return 1;
|
|
11124
|
+
default: {
|
|
11125
|
+
return 1;
|
|
11126
|
+
}
|
|
11127
|
+
}
|
|
10713
11128
|
}
|
|
10714
11129
|
function targetConsultsAffordance(specTarget) {
|
|
10715
11130
|
if (specTarget === void 0) return false;
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
11131
|
+
const form = parseTargetSpec(specTarget);
|
|
11132
|
+
if (form === null) return false;
|
|
11133
|
+
switch (form.form) {
|
|
11134
|
+
case "predicate":
|
|
11135
|
+
return form.kindOf.readsAffordance !== false;
|
|
11136
|
+
case "affordance":
|
|
11137
|
+
return true;
|
|
11138
|
+
case "body":
|
|
11139
|
+
return false;
|
|
11140
|
+
case "kind":
|
|
11141
|
+
return false;
|
|
11142
|
+
default: {
|
|
11143
|
+
return false;
|
|
11144
|
+
}
|
|
10719
11145
|
}
|
|
10720
|
-
return typeof specTarget === "string" && specTarget.startsWith("affordance:");
|
|
10721
11146
|
}
|
|
10722
11147
|
function specTargetOf(spec) {
|
|
10723
11148
|
return "target" in spec ? spec.target : void 0;
|
|
@@ -10759,11 +11184,22 @@ function reportDeadClaim(owner, warn) {
|
|
|
10759
11184
|
`[weasel] exclusive claim by "${key}" matched no binding: no \`affordance:\` or \`kindOf\` target resolved against it, so the press was dropped.`
|
|
10760
11185
|
);
|
|
10761
11186
|
}
|
|
11187
|
+
function phaseRank(spec) {
|
|
11188
|
+
if (spec === void 0) return 0;
|
|
11189
|
+
const atoms = typeof spec === "string" ? [{ channel: "&", phase: spec }] : spec;
|
|
11190
|
+
if (atoms.length === 0) return 0;
|
|
11191
|
+
let min = 2;
|
|
11192
|
+
for (const a of atoms) {
|
|
11193
|
+
const rank = (a.channel === "*" ? 0 : 1) + (a.phase === "*" ? 0 : 1);
|
|
11194
|
+
if (rank < min) min = rank;
|
|
11195
|
+
}
|
|
11196
|
+
return min;
|
|
11197
|
+
}
|
|
10762
11198
|
function specificity(spec) {
|
|
10763
|
-
const t = targetRank(
|
|
11199
|
+
const t = targetRank(specTargetOf(spec));
|
|
10764
11200
|
const mods = "mods" in spec ? spec.mods : void 0;
|
|
10765
11201
|
const m = modsCount(mods);
|
|
10766
|
-
const p = "phase" in spec
|
|
11202
|
+
const p = phaseRank("phase" in spec ? spec.phase : void 0);
|
|
10767
11203
|
const typed = (spec.kind === "drop" || spec.kind === "paste") && spec.types !== void 0 && spec.types.length > 0 ? 2 : 1;
|
|
10768
11204
|
return [t, m, p, typed];
|
|
10769
11205
|
}
|
|
@@ -12423,8 +12859,7 @@ function useGestureDispatcher(opts) {
|
|
|
12423
12859
|
if (!cd) return;
|
|
12424
12860
|
const items = itemsFromClipboardData(cd);
|
|
12425
12861
|
if (items.length === 0) return;
|
|
12426
|
-
|
|
12427
|
-
dispatch2({
|
|
12862
|
+
const result = dispatch2({
|
|
12428
12863
|
kind: "paste",
|
|
12429
12864
|
items,
|
|
12430
12865
|
// ClipboardEvent carries no modifier state.
|
|
@@ -12433,6 +12868,7 @@ function useGestureDispatcher(opts) {
|
|
|
12433
12868
|
metaKey: false,
|
|
12434
12869
|
shiftKey: false
|
|
12435
12870
|
});
|
|
12871
|
+
if (result === "handled") e.preventDefault();
|
|
12436
12872
|
};
|
|
12437
12873
|
if (keyboard) {
|
|
12438
12874
|
window.addEventListener("keydown", onKeyDown);
|
|
@@ -12776,6 +13212,52 @@ function useViewAnimation(setView) {
|
|
|
12776
13212
|
);
|
|
12777
13213
|
return { animateTo, animateToBounds, cancel };
|
|
12778
13214
|
}
|
|
13215
|
+
function validateId(id, kind) {
|
|
13216
|
+
if (id.length === 0) {
|
|
13217
|
+
throw new Error(`weasel: ${kind} id may not be empty`);
|
|
13218
|
+
}
|
|
13219
|
+
if (RESERVED_ID_PREFIXES.has(id[0])) {
|
|
13220
|
+
throw new Error(
|
|
13221
|
+
`weasel: ${kind} id "${id}" starts with reserved sigil "${id[0]}" (reserved set: ${[...RESERVED_ID_PREFIXES].join(" ")})`
|
|
13222
|
+
);
|
|
13223
|
+
}
|
|
13224
|
+
if (RESERVED_ID_NAMES.has(id)) {
|
|
13225
|
+
throw new Error(
|
|
13226
|
+
`weasel: ${kind} id "${id}" collides with a reserved phase keyword (reserved: ${[...RESERVED_ID_NAMES].join(", ")})`
|
|
13227
|
+
);
|
|
13228
|
+
}
|
|
13229
|
+
}
|
|
13230
|
+
function defineTool(def) {
|
|
13231
|
+
validateId(def.id, "tool");
|
|
13232
|
+
const resolveCursor = (ctx) => {
|
|
13233
|
+
if (def.cursor == null) return "";
|
|
13234
|
+
return typeof def.cursor === "function" ? def.cursor(ctx) : def.cursor;
|
|
13235
|
+
};
|
|
13236
|
+
return {
|
|
13237
|
+
id: def.id,
|
|
13238
|
+
eligibility: {
|
|
13239
|
+
focus: true,
|
|
13240
|
+
capabilities: def.capabilities,
|
|
13241
|
+
...def.hotkey ? { offhand: def.hotkey } : {}
|
|
13242
|
+
},
|
|
13243
|
+
actions: def.actions,
|
|
13244
|
+
def,
|
|
13245
|
+
presentation: def.presentation,
|
|
13246
|
+
keybinding: def.keybinding,
|
|
13247
|
+
onActivate: def.onActivate,
|
|
13248
|
+
onDeactivate: def.onDeactivate,
|
|
13249
|
+
initScratch: def.initScratch ?? (() => null),
|
|
13250
|
+
cursor: resolveCursor,
|
|
13251
|
+
bindings: def.bindings,
|
|
13252
|
+
overlay: def.overlay,
|
|
13253
|
+
overlayPosition: def.overlayPosition
|
|
13254
|
+
};
|
|
13255
|
+
}
|
|
13256
|
+
|
|
13257
|
+
// src/tools/defineViewportTool.ts
|
|
13258
|
+
function defineViewportTool(def) {
|
|
13259
|
+
return defineTool(def);
|
|
13260
|
+
}
|
|
12779
13261
|
|
|
12780
13262
|
// src/interactions/actions/defaults/toolOffhand.ts
|
|
12781
13263
|
var TOOL_OFFHAND_ID = "tool.offhand";
|
|
@@ -12870,17 +13352,19 @@ function useContributions(opts) {
|
|
|
12870
13352
|
const { ordered, state } = snapshot();
|
|
12871
13353
|
return scopeBindings(ordered, state);
|
|
12872
13354
|
}, [snapshot]);
|
|
12873
|
-
const overlays = useCallback(() => {
|
|
13355
|
+
const overlays = useCallback((position = "top") => {
|
|
12874
13356
|
const { ordered, state } = snapshot();
|
|
12875
13357
|
const active = [];
|
|
12876
13358
|
const hotkey = [];
|
|
12877
13359
|
const ambient = [];
|
|
12878
13360
|
for (const entry of ordered) {
|
|
12879
13361
|
if (!entry.overlay) continue;
|
|
13362
|
+
if ((entry.overlayPosition ?? "top") !== position) continue;
|
|
13363
|
+
const layers = Array.isArray(entry.overlay) ? entry.overlay : [entry.overlay];
|
|
12880
13364
|
const scope = liveScope(entry.id, entry.eligibility ?? {}, state);
|
|
12881
|
-
if (scope === "active") active.push(
|
|
12882
|
-
else if (scope === "hotkey") hotkey.push(
|
|
12883
|
-
else if (scope === "ambient") ambient.push(
|
|
13365
|
+
if (scope === "active") active.push(...layers);
|
|
13366
|
+
else if (scope === "hotkey") hotkey.push(...layers);
|
|
13367
|
+
else if (scope === "ambient") ambient.push(...layers);
|
|
12884
13368
|
}
|
|
12885
13369
|
return [...active, ...hotkey, ...ambient];
|
|
12886
13370
|
}, [snapshot]);
|
|
@@ -13633,21 +14117,18 @@ function textLineBoxes(pose, opts = {}) {
|
|
|
13633
14117
|
const style = resolveTextStyle(pose.style);
|
|
13634
14118
|
const source = pose.runs && pose.runs.length > 0 ? pose.runs : pose.text;
|
|
13635
14119
|
const runs = resolveRuns(toRuns(source), style);
|
|
13636
|
-
const laid = layoutRuns(
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
{ x: pose.x, y: pose.y }
|
|
13644
|
-
);
|
|
13645
|
-
const dy = verticalAlignOffset(pose.verticalAlign, pose.height, laid.bounds.height);
|
|
14120
|
+
const laid = layoutRuns(runs, {
|
|
14121
|
+
maxWidth: opts.maxWidth ?? pose.width,
|
|
14122
|
+
lineHeight: style.lineHeight,
|
|
14123
|
+
align: style.align
|
|
14124
|
+
});
|
|
14125
|
+
const dx = pose.x;
|
|
14126
|
+
const dy = pose.y + verticalAlignOffset(pose.verticalAlign, pose.height, laid.bounds.height);
|
|
13646
14127
|
const out = [];
|
|
13647
14128
|
for (const line of laid.lines) {
|
|
13648
14129
|
if (!opts.includeEmpty && line.x1 <= line.x0) continue;
|
|
13649
14130
|
out.push({
|
|
13650
|
-
x: line.x0 - padding,
|
|
14131
|
+
x: line.x0 + dx - padding,
|
|
13651
14132
|
y: line.y0 + dy - padding,
|
|
13652
14133
|
width: line.x1 - line.x0 + padding * 2,
|
|
13653
14134
|
height: line.y1 - line.y0 + padding * 2
|
|
@@ -13710,7 +14191,7 @@ function isBoundsGradient(fill) {
|
|
|
13710
14191
|
}
|
|
13711
14192
|
|
|
13712
14193
|
// src/features/patterns/resolveSpec.ts
|
|
13713
|
-
var
|
|
14194
|
+
var cache6 = /* @__PURE__ */ new Map();
|
|
13714
14195
|
function specKey(spec) {
|
|
13715
14196
|
const keys = Object.keys(spec).sort();
|
|
13716
14197
|
const bag = spec;
|
|
@@ -13718,10 +14199,10 @@ function specKey(spec) {
|
|
|
13718
14199
|
}
|
|
13719
14200
|
function resolvePatternSpec(spec) {
|
|
13720
14201
|
const key = specKey(spec);
|
|
13721
|
-
const hit =
|
|
14202
|
+
const hit = cache6.get(key);
|
|
13722
14203
|
if (hit !== void 0) return hit;
|
|
13723
14204
|
const built = buildTile(spec);
|
|
13724
|
-
|
|
14205
|
+
cache6.set(key, built);
|
|
13725
14206
|
return built;
|
|
13726
14207
|
}
|
|
13727
14208
|
function buildTile(spec) {
|
|
@@ -13757,7 +14238,7 @@ function resolveFillPattern(fill) {
|
|
|
13757
14238
|
}
|
|
13758
14239
|
|
|
13759
14240
|
// src/features/images/imageCache.ts
|
|
13760
|
-
var
|
|
14241
|
+
var cache7 = /* @__PURE__ */ new Map();
|
|
13761
14242
|
var subscribers = /* @__PURE__ */ new Set();
|
|
13762
14243
|
var defaultLoader = async (src) => {
|
|
13763
14244
|
if (typeof Image === "undefined" || typeof createImageBitmap === "undefined") {
|
|
@@ -13775,28 +14256,28 @@ function notify() {
|
|
|
13775
14256
|
}
|
|
13776
14257
|
function startLoad(src) {
|
|
13777
14258
|
const entry = { status: "loading" };
|
|
13778
|
-
|
|
14259
|
+
cache7.set(src, entry);
|
|
13779
14260
|
loader(src).then(
|
|
13780
14261
|
(bitmap) => {
|
|
13781
|
-
if (
|
|
13782
|
-
|
|
14262
|
+
if (cache7.get(src) !== entry) return;
|
|
14263
|
+
cache7.set(src, { status: "ready", bitmap });
|
|
13783
14264
|
notify();
|
|
13784
14265
|
},
|
|
13785
14266
|
() => {
|
|
13786
|
-
if (
|
|
13787
|
-
|
|
14267
|
+
if (cache7.get(src) !== entry) return;
|
|
14268
|
+
cache7.set(src, { status: "error" });
|
|
13788
14269
|
notify();
|
|
13789
14270
|
}
|
|
13790
14271
|
);
|
|
13791
14272
|
}
|
|
13792
14273
|
function getImageBitmap(src) {
|
|
13793
|
-
const entry =
|
|
14274
|
+
const entry = cache7.get(src);
|
|
13794
14275
|
if (entry) return entry.bitmap;
|
|
13795
14276
|
startLoad(src);
|
|
13796
14277
|
return void 0;
|
|
13797
14278
|
}
|
|
13798
14279
|
function imageStatus(src) {
|
|
13799
|
-
return
|
|
14280
|
+
return cache7.get(src)?.status ?? "idle";
|
|
13800
14281
|
}
|
|
13801
14282
|
function subscribeImageReady(cb) {
|
|
13802
14283
|
subscribers.add(cb);
|
|
@@ -14163,6 +14644,7 @@ registerBuiltInShapePainters();
|
|
|
14163
14644
|
function pickTopMostHit(ids, adapter) {
|
|
14164
14645
|
if (ids.length === 0) return null;
|
|
14165
14646
|
if (ids.length === 1) return ids[0];
|
|
14647
|
+
let candidates = ids;
|
|
14166
14648
|
const getParent = adapter?.getParent;
|
|
14167
14649
|
if (typeof getParent === "function") {
|
|
14168
14650
|
const set = new Set(ids);
|
|
@@ -14177,15 +14659,40 @@ function pickTopMostHit(ids, adapter) {
|
|
|
14177
14659
|
}
|
|
14178
14660
|
if (dropped.size > 0) {
|
|
14179
14661
|
const filtered = ids.filter((id) => !dropped.has(id));
|
|
14180
|
-
if (filtered.length ===
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14662
|
+
if (filtered.length === 1) return filtered[0];
|
|
14663
|
+
if (filtered.length > 1) candidates = filtered;
|
|
14664
|
+
}
|
|
14665
|
+
}
|
|
14666
|
+
return pickHighestZ(candidates, adapter);
|
|
14667
|
+
}
|
|
14668
|
+
function pickHighestZ(ids, adapter) {
|
|
14669
|
+
const compareZ = adapter?.compareZ;
|
|
14670
|
+
if (typeof compareZ === "function") {
|
|
14671
|
+
let best = ids[0];
|
|
14672
|
+
for (let i = 1; i < ids.length; i++) {
|
|
14673
|
+
if (compareZ(ids[i], best) >= 0) best = ids[i];
|
|
14674
|
+
}
|
|
14675
|
+
return best;
|
|
14676
|
+
}
|
|
14677
|
+
const getZIndex = adapter?.getZIndex;
|
|
14678
|
+
if (typeof getZIndex === "function") {
|
|
14679
|
+
let best = ids[0];
|
|
14680
|
+
let bestZ = zOf(getZIndex, best);
|
|
14681
|
+
for (let i = 1; i < ids.length; i++) {
|
|
14682
|
+
const z = zOf(getZIndex, ids[i]);
|
|
14683
|
+
if (z >= bestZ) {
|
|
14684
|
+
best = ids[i];
|
|
14685
|
+
bestZ = z;
|
|
14184
14686
|
}
|
|
14185
14687
|
}
|
|
14688
|
+
return best;
|
|
14186
14689
|
}
|
|
14187
14690
|
return ids[ids.length - 1];
|
|
14188
14691
|
}
|
|
14692
|
+
function zOf(getZIndex, id) {
|
|
14693
|
+
const z = getZIndex(id);
|
|
14694
|
+
return typeof z === "number" && Number.isFinite(z) ? z : -Infinity;
|
|
14695
|
+
}
|
|
14189
14696
|
|
|
14190
14697
|
// src/core/selection/selectionTarget.ts
|
|
14191
14698
|
var MULTI_RESIZE_TARGET_ID = "__weasel:multi-selection";
|
|
@@ -14590,9 +15097,19 @@ function composeAffordanceLayer(id, label, affordances) {
|
|
|
14590
15097
|
},
|
|
14591
15098
|
// The walk itself lives in `hitAffordanceRegions` so this layer and
|
|
14592
15099
|
// `buildAffordanceAt` share one implementation rather than two that can
|
|
14593
|
-
// drift. This wrapper
|
|
14594
|
-
// binding
|
|
14595
|
-
hitTest: (wx, wy, state, view, _dims, isVisible) =>
|
|
15100
|
+
// drift. This wrapper lifts the region's declared cursor and claim onto
|
|
15101
|
+
// the binding, the way `buildAffordanceAt` lifts them onto `AffordanceHit`.
|
|
15102
|
+
hitTest: (wx, wy, state, view, _dims, isVisible) => {
|
|
15103
|
+
const hit = hitAffordanceRegions(affordances, wx, wy, state, view, isVisible);
|
|
15104
|
+
if (!hit) return null;
|
|
15105
|
+
const { cursor, strength, claimedKinds } = hit.region;
|
|
15106
|
+
return {
|
|
15107
|
+
...hit.binding,
|
|
15108
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
15109
|
+
...strength !== void 0 ? { strength } : {},
|
|
15110
|
+
...claimedKinds !== void 0 ? { claimedKinds } : {}
|
|
15111
|
+
};
|
|
15112
|
+
}
|
|
14596
15113
|
};
|
|
14597
15114
|
}
|
|
14598
15115
|
function asChromeState(data) {
|
|
@@ -15375,7 +15892,7 @@ function useEllipseTool() {
|
|
|
15375
15892
|
);
|
|
15376
15893
|
}
|
|
15377
15894
|
function useImageTool(options) {
|
|
15378
|
-
const { src, label = "Image" } = options;
|
|
15895
|
+
const { src, label = "Image", preview = "bitmap" } = options;
|
|
15379
15896
|
return useMemo(
|
|
15380
15897
|
() => defineTool({
|
|
15381
15898
|
id: "image",
|
|
@@ -15394,11 +15911,11 @@ function useImageTool(options) {
|
|
|
15394
15911
|
{
|
|
15395
15912
|
spec: { kind: "drag" },
|
|
15396
15913
|
actionId: "insert",
|
|
15397
|
-
opts: { params: { kind: "image", src } }
|
|
15914
|
+
opts: { params: { kind: "image", src, preview } }
|
|
15398
15915
|
}
|
|
15399
15916
|
]
|
|
15400
15917
|
}),
|
|
15401
|
-
[src, label]
|
|
15918
|
+
[src, label, preview]
|
|
15402
15919
|
);
|
|
15403
15920
|
}
|
|
15404
15921
|
function useEyedropperTool(opts) {
|
|
@@ -15865,6 +16382,19 @@ function composeOrderedLayers(layersMap, standardLayers, sceneLayers) {
|
|
|
15865
16382
|
}
|
|
15866
16383
|
return out;
|
|
15867
16384
|
}
|
|
16385
|
+
function placeToolOverlays(ordered, selectionOverlay, overlays) {
|
|
16386
|
+
const before = overlays("before-selection");
|
|
16387
|
+
const after = overlays("after-selection");
|
|
16388
|
+
const at = selectionOverlay ? ordered.indexOf(selectionOverlay) : -1;
|
|
16389
|
+
if (at >= 0) {
|
|
16390
|
+
ordered.splice(at + 1, 0, ...after);
|
|
16391
|
+
ordered.splice(at, 0, ...before);
|
|
16392
|
+
} else {
|
|
16393
|
+
ordered.push(...before, ...after);
|
|
16394
|
+
}
|
|
16395
|
+
ordered.push(...overlays("top"));
|
|
16396
|
+
return ordered;
|
|
16397
|
+
}
|
|
15868
16398
|
|
|
15869
16399
|
// src/canvas/toolPreview.ts
|
|
15870
16400
|
function* toolsInPriorityOrder(tools) {
|
|
@@ -16630,6 +17160,15 @@ function wrapWithPoseRotation(cmds, pose) {
|
|
|
16630
17160
|
children: cmds
|
|
16631
17161
|
}];
|
|
16632
17162
|
}
|
|
17163
|
+
|
|
17164
|
+
// src/canvas/wrapNodeOutput.ts
|
|
17165
|
+
function wrapNodeOutput(cmds, pose, alpha) {
|
|
17166
|
+
const rotated = wrapWithPoseRotation(cmds, pose);
|
|
17167
|
+
if (alpha !== 1 && rotated.length > 0) {
|
|
17168
|
+
return [{ kind: "group", alpha, children: rotated }];
|
|
17169
|
+
}
|
|
17170
|
+
return rotated;
|
|
17171
|
+
}
|
|
16633
17172
|
function CursorCoordsHud({ canvasRef, viewRef, offset }) {
|
|
16634
17173
|
const [state, setState] = useState({
|
|
16635
17174
|
client: { x: 0, y: 0 },
|
|
@@ -16881,12 +17420,7 @@ function buildSceneLayer(cfg, adapter, debugSink, boundsOfFn, hideIds, slot) {
|
|
|
16881
17420
|
const oy = pose.y ?? (b ? b.y : 0);
|
|
16882
17421
|
debugSink.recordOrigin(obj.id, { x: ox, y: oy });
|
|
16883
17422
|
}
|
|
16884
|
-
|
|
16885
|
-
const alpha = cfg.alphaFor ? cfg.alphaFor(obj.id) : 1;
|
|
16886
|
-
if (alpha !== 1 && rotated.length > 0) {
|
|
16887
|
-
return [{ kind: "group", alpha, children: rotated }];
|
|
16888
|
-
}
|
|
16889
|
-
return rotated;
|
|
17423
|
+
return wrapNodeOutput(cmds, pose, cfg.alphaFor ? cfg.alphaFor(obj.id) : 1);
|
|
16890
17424
|
};
|
|
16891
17425
|
const hierarchicalAdapter = cfg.toPose ? {
|
|
16892
17426
|
...a,
|
|
@@ -16910,13 +17444,8 @@ function buildSceneLayer(cfg, adapter, debugSink, boundsOfFn, hideIds, slot) {
|
|
|
16910
17444
|
const pose = toPose(obj);
|
|
16911
17445
|
if (drawOne) {
|
|
16912
17446
|
const cmds = drawOne(obj, pose, view);
|
|
16913
|
-
const
|
|
16914
|
-
const
|
|
16915
|
-
if (alpha !== 1 && rotated.length > 0) {
|
|
16916
|
-
children.push({ kind: "group", alpha, children: rotated });
|
|
16917
|
-
} else {
|
|
16918
|
-
for (const cmd of rotated) children.push(cmd);
|
|
16919
|
-
}
|
|
17447
|
+
const wrapped = wrapNodeOutput(cmds, pose, cfg.alphaFor ? cfg.alphaFor(obj.id) : 1);
|
|
17448
|
+
for (const cmd of wrapped) children.push(cmd);
|
|
16920
17449
|
}
|
|
16921
17450
|
if (debugSink) {
|
|
16922
17451
|
const b = boundsOfFn ? boundsOfFn(obj.id) : null;
|
|
@@ -17412,7 +17941,7 @@ function CanvasInner(props, ref) {
|
|
|
17412
17941
|
const out = composeOrderedLayers(effectiveLayersMap, standardLayers, sceneLayers);
|
|
17413
17942
|
if (decorationLayer) out.push(decorationLayer);
|
|
17414
17943
|
if (tools) {
|
|
17415
|
-
out.
|
|
17944
|
+
placeToolOverlays(out, standardLayers.selectionOverlay, tools.getActiveOverlays);
|
|
17416
17945
|
}
|
|
17417
17946
|
return out;
|
|
17418
17947
|
}, [layersMap, adapter, selectedIds, effectiveBoundsOf, multiActive2, debugSink, tools, backgroundLayer, decorationLayer]);
|
|
@@ -17630,6 +18159,7 @@ function createScene(options) {
|
|
|
17630
18159
|
return i;
|
|
17631
18160
|
}
|
|
17632
18161
|
function rebuildLayerIndex() {
|
|
18162
|
+
invalidateOrder();
|
|
17633
18163
|
state.layerIndex.clear();
|
|
17634
18164
|
for (let i = 0; i < state.layers.length; i++) {
|
|
17635
18165
|
state.layerIndex.set(state.layers[i].id, i);
|
|
@@ -17655,6 +18185,7 @@ function createScene(options) {
|
|
|
17655
18185
|
const idx = sibs.indexOf(id);
|
|
17656
18186
|
if (idx < 0) throw new Error(`Scene: node "${id}" not found in its parent's children`);
|
|
17657
18187
|
sibs.splice(idx, 1);
|
|
18188
|
+
invalidateOrder();
|
|
17658
18189
|
return { parent: node.parent, index: idx };
|
|
17659
18190
|
}
|
|
17660
18191
|
function attach(id, parent, index) {
|
|
@@ -17663,6 +18194,7 @@ function createScene(options) {
|
|
|
17663
18194
|
sibs.splice(i, 0, id);
|
|
17664
18195
|
const node = requireNode(id);
|
|
17665
18196
|
node.parent = parent;
|
|
18197
|
+
invalidateOrder();
|
|
17666
18198
|
}
|
|
17667
18199
|
function descendants(id, out) {
|
|
17668
18200
|
const n = state.nodes.get(id);
|
|
@@ -17742,9 +18274,11 @@ function createScene(options) {
|
|
|
17742
18274
|
apply: (p) => {
|
|
17743
18275
|
requireLayerIndex(p.to);
|
|
17744
18276
|
requireNode(p.id).layer = p.to;
|
|
18277
|
+
invalidateOrder();
|
|
17745
18278
|
},
|
|
17746
18279
|
revert: (p) => {
|
|
17747
18280
|
requireNode(p.id).layer = p.from;
|
|
18281
|
+
invalidateOrder();
|
|
17748
18282
|
}
|
|
17749
18283
|
});
|
|
17750
18284
|
registerKitOp("kit:move", {
|
|
@@ -17883,21 +18417,98 @@ function createScene(options) {
|
|
|
17883
18417
|
registered.set(k, h);
|
|
17884
18418
|
}
|
|
17885
18419
|
}
|
|
17886
|
-
function
|
|
17887
|
-
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
|
|
17896
|
-
|
|
17897
|
-
|
|
18420
|
+
function renderOrderInternal() {
|
|
18421
|
+
return state.layers.length === 1 ? renderOrderFlat() : renderOrderBucketed();
|
|
18422
|
+
}
|
|
18423
|
+
function renderOrderNodesInternal() {
|
|
18424
|
+
return state.layers.length === 1 ? renderOrderNodesFlat() : renderOrderNodesBucketed();
|
|
18425
|
+
}
|
|
18426
|
+
let structureGeneration = 0;
|
|
18427
|
+
let orderCache = { gen: 0 };
|
|
18428
|
+
function invalidateOrder() {
|
|
18429
|
+
structureGeneration++;
|
|
18430
|
+
}
|
|
18431
|
+
function currentOrderCache() {
|
|
18432
|
+
if (orderCache.gen !== structureGeneration) {
|
|
18433
|
+
orderCache = { gen: structureGeneration };
|
|
18434
|
+
}
|
|
18435
|
+
return orderCache;
|
|
18436
|
+
}
|
|
18437
|
+
function renderOrderFlat() {
|
|
18438
|
+
const only = state.layers[0].id;
|
|
18439
|
+
const out = [];
|
|
18440
|
+
const stack = [...state.roots].reverse();
|
|
18441
|
+
while (stack.length > 0) {
|
|
18442
|
+
const id = stack.pop();
|
|
18443
|
+
const node = state.nodes.get(id);
|
|
18444
|
+
if (!node) continue;
|
|
18445
|
+
if (node.layer === only) out.push(id);
|
|
18446
|
+
if (node.kind === "container") {
|
|
18447
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18448
|
+
stack.push(node.children[i]);
|
|
17898
18449
|
}
|
|
17899
18450
|
}
|
|
17900
18451
|
}
|
|
18452
|
+
return out;
|
|
18453
|
+
}
|
|
18454
|
+
function renderOrderNodesFlat() {
|
|
18455
|
+
const only = state.layers[0].id;
|
|
18456
|
+
const out = [];
|
|
18457
|
+
const stack = [...state.roots].reverse();
|
|
18458
|
+
while (stack.length > 0) {
|
|
18459
|
+
const id = stack.pop();
|
|
18460
|
+
const node = state.nodes.get(id);
|
|
18461
|
+
if (!node) continue;
|
|
18462
|
+
if (node.layer === only) out.push(node);
|
|
18463
|
+
if (node.kind === "container") {
|
|
18464
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18465
|
+
stack.push(node.children[i]);
|
|
18466
|
+
}
|
|
18467
|
+
}
|
|
18468
|
+
}
|
|
18469
|
+
return out;
|
|
18470
|
+
}
|
|
18471
|
+
function renderOrderBucketed() {
|
|
18472
|
+
const buckets = state.layers.map(() => []);
|
|
18473
|
+
const stack = [...state.roots].reverse();
|
|
18474
|
+
while (stack.length > 0) {
|
|
18475
|
+
const id = stack.pop();
|
|
18476
|
+
const node = state.nodes.get(id);
|
|
18477
|
+
if (!node) continue;
|
|
18478
|
+
const bucket = buckets[state.layerIndex.get(node.layer) ?? -1];
|
|
18479
|
+
if (bucket) bucket.push(id);
|
|
18480
|
+
if (node.kind === "container") {
|
|
18481
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18482
|
+
stack.push(node.children[i]);
|
|
18483
|
+
}
|
|
18484
|
+
}
|
|
18485
|
+
}
|
|
18486
|
+
const out = [];
|
|
18487
|
+
for (const bucket of buckets) {
|
|
18488
|
+
for (const id of bucket) out.push(id);
|
|
18489
|
+
}
|
|
18490
|
+
return out;
|
|
18491
|
+
}
|
|
18492
|
+
function renderOrderNodesBucketed() {
|
|
18493
|
+
const buckets = state.layers.map(() => []);
|
|
18494
|
+
const stack = [...state.roots].reverse();
|
|
18495
|
+
while (stack.length > 0) {
|
|
18496
|
+
const id = stack.pop();
|
|
18497
|
+
const node = state.nodes.get(id);
|
|
18498
|
+
if (!node) continue;
|
|
18499
|
+
const bucket = buckets[state.layerIndex.get(node.layer) ?? -1];
|
|
18500
|
+
if (bucket) bucket.push(node);
|
|
18501
|
+
if (node.kind === "container") {
|
|
18502
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18503
|
+
stack.push(node.children[i]);
|
|
18504
|
+
}
|
|
18505
|
+
}
|
|
18506
|
+
}
|
|
18507
|
+
const out = [];
|
|
18508
|
+
for (const bucket of buckets) {
|
|
18509
|
+
for (const node of bucket) out.push(node);
|
|
18510
|
+
}
|
|
18511
|
+
return out;
|
|
17901
18512
|
}
|
|
17902
18513
|
const scene = {
|
|
17903
18514
|
get nodes() {
|
|
@@ -17926,7 +18537,12 @@ function createScene(options) {
|
|
|
17926
18537
|
return out;
|
|
17927
18538
|
},
|
|
17928
18539
|
renderOrder() {
|
|
17929
|
-
|
|
18540
|
+
const c = currentOrderCache();
|
|
18541
|
+
return c.ids ??= renderOrderInternal();
|
|
18542
|
+
},
|
|
18543
|
+
renderOrderNodes() {
|
|
18544
|
+
const c = currentOrderCache();
|
|
18545
|
+
return c.nodes ??= renderOrderNodesInternal();
|
|
17930
18546
|
},
|
|
17931
18547
|
add(spec) {
|
|
17932
18548
|
const id = spec.id ?? generateId();
|
|
@@ -18234,9 +18850,8 @@ function createScene(options) {
|
|
|
18234
18850
|
},
|
|
18235
18851
|
toJSON() {
|
|
18236
18852
|
const nodes = [];
|
|
18237
|
-
for (const
|
|
18238
|
-
const
|
|
18239
|
-
if (!n) continue;
|
|
18853
|
+
for (const n of renderOrderNodesInternal()) {
|
|
18854
|
+
const id = n.id;
|
|
18240
18855
|
const out = {
|
|
18241
18856
|
id,
|
|
18242
18857
|
kind: n.kind,
|
|
@@ -18270,6 +18885,7 @@ function createScene(options) {
|
|
|
18270
18885
|
state.roots.length = 0;
|
|
18271
18886
|
state.layers.length = 0;
|
|
18272
18887
|
state.layerIndex.clear();
|
|
18888
|
+
invalidateOrder();
|
|
18273
18889
|
for (let i = 0; i < json.systemLayers.length; i++) {
|
|
18274
18890
|
const spec = json.systemLayers[i];
|
|
18275
18891
|
if (state.layerIndex.has(spec.id)) {
|
|
@@ -18567,9 +19183,8 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
18567
19183
|
getNodes() {
|
|
18568
19184
|
const visible = visibleLayers();
|
|
18569
19185
|
const out = [];
|
|
18570
|
-
for (const
|
|
18571
|
-
|
|
18572
|
-
if (n && visible.has(n.layer)) out.push(n);
|
|
19186
|
+
for (const n of scene.renderOrderNodes()) {
|
|
19187
|
+
if (visible.has(n.layer)) out.push(n);
|
|
18573
19188
|
}
|
|
18574
19189
|
return out;
|
|
18575
19190
|
},
|
|
@@ -18909,9 +19524,7 @@ function useSceneSelectTool(args) {
|
|
|
18909
19524
|
// path descriptor for a tighter test.
|
|
18910
19525
|
hitTestArea: (rect) => {
|
|
18911
19526
|
const hits = [];
|
|
18912
|
-
for (const
|
|
18913
|
-
const n = scene.get(nid);
|
|
18914
|
-
if (!n) continue;
|
|
19527
|
+
for (const n of scene.renderOrderNodes()) {
|
|
18915
19528
|
if (isPathLike(n.pose) && pathPoseDescriptor.intersectsRect) {
|
|
18916
19529
|
if (pathPoseDescriptor.intersectsRect(n.pose, rect)) hits.push(n.id);
|
|
18917
19530
|
continue;
|
|
@@ -18949,9 +19562,8 @@ function useSceneSelectTool(args) {
|
|
|
18949
19562
|
}
|
|
18950
19563
|
const tolerance = pickTolerancePx / meanScale(getView?.()?.scale ?? { x: 1, y: 1 });
|
|
18951
19564
|
const out = [];
|
|
18952
|
-
for (const
|
|
18953
|
-
|
|
18954
|
-
if (!n || !poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
|
|
19565
|
+
for (const n of scene.renderOrderNodes()) {
|
|
19566
|
+
if (!poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
|
|
18955
19567
|
if (shapePicking && !shapeCoversPoint(n, n.pose, wx, wy, { tolerance })) continue;
|
|
18956
19568
|
out.push(n.id);
|
|
18957
19569
|
}
|
|
@@ -18996,6 +19608,7 @@ function useSceneSelectTool(args) {
|
|
|
18996
19608
|
boundsOf: wiredBoundsOf
|
|
18997
19609
|
};
|
|
18998
19610
|
}
|
|
19611
|
+
var GHOST_ALPHA = 0.85;
|
|
18999
19612
|
function usePreviewGhostLayer(args) {
|
|
19000
19613
|
const { scene, tools, sceneSlot, dispatcher } = args;
|
|
19001
19614
|
const sceneRef = useRef(scene);
|
|
@@ -19082,15 +19695,26 @@ function usePreviewGhostLayer(args) {
|
|
|
19082
19695
|
}
|
|
19083
19696
|
return [group];
|
|
19084
19697
|
};
|
|
19698
|
+
const opaqueSet = /* @__PURE__ */ new Set();
|
|
19699
|
+
for (const source of sources) {
|
|
19700
|
+
const ids = source.previewOpaqueIds?.();
|
|
19701
|
+
if (!ids) continue;
|
|
19702
|
+
for (const id of ids) opaqueSet.add(id);
|
|
19703
|
+
}
|
|
19085
19704
|
const children = [];
|
|
19705
|
+
const opaque = [];
|
|
19086
19706
|
for (const id of idSet) {
|
|
19087
19707
|
const node = sc.get(asNodeId(id));
|
|
19088
19708
|
const parent = node?.parent;
|
|
19089
19709
|
if (parent != null && idSet.has(parent)) continue;
|
|
19090
|
-
|
|
19710
|
+
const sink = opaqueSet.has(id) ? opaque : children;
|
|
19711
|
+
for (const cmd of buildSubtree(id)) sink.push(cmd);
|
|
19091
19712
|
}
|
|
19092
|
-
if (children.length === 0) return [];
|
|
19093
|
-
|
|
19713
|
+
if (children.length === 0 && opaque.length === 0) return [];
|
|
19714
|
+
const out = [];
|
|
19715
|
+
if (opaque.length > 0) out.push({ kind: "group", children: opaque });
|
|
19716
|
+
if (children.length > 0) out.push({ kind: "group", alpha: GHOST_ALPHA, children });
|
|
19717
|
+
return out;
|
|
19094
19718
|
}
|
|
19095
19719
|
}), []);
|
|
19096
19720
|
}
|
|
@@ -19100,6 +19724,7 @@ var DEFAULT_STYLE = {
|
|
|
19100
19724
|
dash: [3, 3],
|
|
19101
19725
|
lineWidth: 1
|
|
19102
19726
|
};
|
|
19727
|
+
var PREVIEW_CONTENT_OPACITY = 0.85;
|
|
19103
19728
|
function useDispatcherOverlayLayer(args) {
|
|
19104
19729
|
const { dispatcher, style } = args;
|
|
19105
19730
|
const dispatcherRef = useRef(dispatcher);
|
|
@@ -19162,6 +19787,26 @@ function useDispatcherOverlayLayer(args) {
|
|
|
19162
19787
|
pathCmd = rectPath(sx, sy, b.width * view.scale.x, b.height * view.scale.y);
|
|
19163
19788
|
break;
|
|
19164
19789
|
}
|
|
19790
|
+
case "image": {
|
|
19791
|
+
const e = ov.extras;
|
|
19792
|
+
const [sx, sy] = worldToScreen(b.x, b.y, t);
|
|
19793
|
+
const sw = b.width * view.scale.x;
|
|
19794
|
+
const sh = b.height * view.scale.y;
|
|
19795
|
+
const bmp = e.preview === "outline" || !e.src ? void 0 : getImageBitmap(e.src);
|
|
19796
|
+
if (bmp) {
|
|
19797
|
+
out.push({
|
|
19798
|
+
kind: "image",
|
|
19799
|
+
image: bmp,
|
|
19800
|
+
x: sx,
|
|
19801
|
+
y: sy,
|
|
19802
|
+
w: sw,
|
|
19803
|
+
h: sh,
|
|
19804
|
+
opacity: PREVIEW_CONTENT_OPACITY
|
|
19805
|
+
});
|
|
19806
|
+
}
|
|
19807
|
+
pathCmd = rectPath(sx, sy, sw, sh);
|
|
19808
|
+
break;
|
|
19809
|
+
}
|
|
19165
19810
|
case "ellipse": {
|
|
19166
19811
|
const [sx, sy] = worldToScreen(b.x, b.y, t);
|
|
19167
19812
|
pathCmd = ellipsePath({
|
|
@@ -19220,7 +19865,7 @@ function useDispatcherOverlayLayer(args) {
|
|
|
19220
19865
|
const cmd = {
|
|
19221
19866
|
kind: "path",
|
|
19222
19867
|
path: pathCmd,
|
|
19223
|
-
fill: ov.shape === "line" || ov.shape === "pencil" ? void 0 : { color: cfg.fill },
|
|
19868
|
+
fill: ov.shape === "line" || ov.shape === "pencil" || ov.shape === "image" ? void 0 : { color: cfg.fill },
|
|
19224
19869
|
stroke: { paint: { color: cfg.stroke }, width: cfg.lineWidth, dash: cfg.dash }
|
|
19225
19870
|
};
|
|
19226
19871
|
out.push(cmd);
|
|
@@ -19933,9 +20578,6 @@ function buildClassifyTarget(getSelection, pickBest, kindOfNode) {
|
|
|
19933
20578
|
function w2s3(wx, wy, view) {
|
|
19934
20579
|
return [(wx - view.x) * view.scale.x, (wy - view.y) * view.scale.y];
|
|
19935
20580
|
}
|
|
19936
|
-
function r2s(radiusWorld, view) {
|
|
19937
|
-
return radiusWorld * meanScale(view.scale);
|
|
19938
|
-
}
|
|
19939
20581
|
var SLOP_FILL = "rgba(255, 80, 140, 0.18)";
|
|
19940
20582
|
var SLOP_STROKE = "rgba(255, 80, 140, 0.55)";
|
|
19941
20583
|
function createSlopsDebugLayer(opts) {
|
|
@@ -19946,7 +20588,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
19946
20588
|
draw: (_data, view) => {
|
|
19947
20589
|
const out = [];
|
|
19948
20590
|
const sel = opts.selectionRef.current?.current ?? [];
|
|
19949
|
-
const r =
|
|
20591
|
+
const r = HANDLE_HIT_RADIUS;
|
|
19950
20592
|
for (const id of sel) {
|
|
19951
20593
|
const b = opts.boundsOf(id);
|
|
19952
20594
|
if (!b) continue;
|
|
@@ -19983,6 +20625,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
19983
20625
|
}
|
|
19984
20626
|
const editingId = opts.getEditingId();
|
|
19985
20627
|
if (editingId) {
|
|
20628
|
+
const anchorR = ANCHOR_HIT_RADIUS;
|
|
19986
20629
|
const pose = opts.getPose(editingId);
|
|
19987
20630
|
if (pose && pose.kind === "polygon") {
|
|
19988
20631
|
const anchors = enumerateAnchors(pose);
|
|
@@ -19990,7 +20633,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
19990
20633
|
const [sx, sy] = w2s3(a.x, a.y, view);
|
|
19991
20634
|
out.push({
|
|
19992
20635
|
kind: "path",
|
|
19993
|
-
path: circlePath(sx, sy,
|
|
20636
|
+
path: circlePath(sx, sy, anchorR),
|
|
19994
20637
|
fill: { fill: "solid", color: SLOP_FILL },
|
|
19995
20638
|
stroke: { paint: { fill: "solid", color: SLOP_STROKE }, width: 1 }
|
|
19996
20639
|
});
|
|
@@ -19998,7 +20641,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
19998
20641
|
const [csx, csy] = w2s3(a.controlIn.x, a.controlIn.y, view);
|
|
19999
20642
|
out.push({
|
|
20000
20643
|
kind: "path",
|
|
20001
|
-
path: circlePath(csx, csy,
|
|
20644
|
+
path: circlePath(csx, csy, anchorR),
|
|
20002
20645
|
fill: { fill: "solid", color: SLOP_FILL },
|
|
20003
20646
|
stroke: { paint: { fill: "solid", color: SLOP_STROKE }, width: 1 }
|
|
20004
20647
|
});
|
|
@@ -20007,7 +20650,7 @@ function createSlopsDebugLayer(opts) {
|
|
|
20007
20650
|
const [csx, csy] = w2s3(a.controlOut.x, a.controlOut.y, view);
|
|
20008
20651
|
out.push({
|
|
20009
20652
|
kind: "path",
|
|
20010
|
-
path: circlePath(csx, csy,
|
|
20653
|
+
path: circlePath(csx, csy, anchorR),
|
|
20011
20654
|
fill: { fill: "solid", color: SLOP_FILL },
|
|
20012
20655
|
stroke: { paint: { fill: "solid", color: SLOP_STROKE }, width: 1 }
|
|
20013
20656
|
});
|
|
@@ -20089,30 +20732,41 @@ function DepRegistryProviderIfRoot({ children }) {
|
|
|
20089
20732
|
function hitTestArea(scene, bounds) {
|
|
20090
20733
|
const { x, y, width: w, height: h } = bounds;
|
|
20091
20734
|
const area = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
20092
|
-
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h });
|
|
20735
|
+
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
|
|
20093
20736
|
}
|
|
20094
|
-
function hitTestAreaPolygon(scene, area, areaBounds) {
|
|
20737
|
+
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
|
|
20095
20738
|
const ab = areaBounds ?? boundsOf(area);
|
|
20096
20739
|
if (!ab) return [];
|
|
20097
20740
|
const hits = [];
|
|
20098
|
-
|
|
20099
|
-
|
|
20100
|
-
|
|
20741
|
+
const order = scene.renderOrderNodes();
|
|
20742
|
+
for (let i = 0; i < order.length; i++) {
|
|
20743
|
+
const node = order[i];
|
|
20744
|
+
if (node.kind === "container") continue;
|
|
20101
20745
|
const pose = node.pose;
|
|
20102
|
-
const
|
|
20746
|
+
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
20747
|
+
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
|
|
20103
20748
|
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
20104
20749
|
continue;
|
|
20105
20750
|
}
|
|
20106
20751
|
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) {
|
|
20107
20752
|
continue;
|
|
20108
20753
|
}
|
|
20109
|
-
if (
|
|
20110
|
-
hits.push(id);
|
|
20754
|
+
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) {
|
|
20755
|
+
hits.push(node.id);
|
|
20111
20756
|
continue;
|
|
20112
20757
|
}
|
|
20113
|
-
if (
|
|
20114
|
-
|
|
20758
|
+
if (silhouette) {
|
|
20759
|
+
if (silhouetteOverlapsArea(pose.coords, area)) {
|
|
20760
|
+
hits.push(node.id);
|
|
20761
|
+
}
|
|
20762
|
+
continue;
|
|
20763
|
+
}
|
|
20764
|
+
const drawn = findShapeSilhouette(node, pose);
|
|
20765
|
+
if (drawn?.kind === "polygon") {
|
|
20766
|
+
if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
|
|
20767
|
+
continue;
|
|
20115
20768
|
}
|
|
20769
|
+
hits.push(node.id);
|
|
20116
20770
|
}
|
|
20117
20771
|
return hits;
|
|
20118
20772
|
}
|
|
@@ -22345,14 +22999,25 @@ var inferredNodeProperties = inferredNodeRouting.map((e) => ({
|
|
|
22345
22999
|
|
|
22346
23000
|
// src/canvas/sceneViewRender.ts
|
|
22347
23001
|
var RENDERER_CACHE = /* @__PURE__ */ new WeakMap();
|
|
22348
|
-
function
|
|
22349
|
-
|
|
22350
|
-
|
|
22351
|
-
|
|
22352
|
-
|
|
22353
|
-
|
|
22354
|
-
|
|
22355
|
-
|
|
23002
|
+
function sceneAsHierarchy(scene) {
|
|
23003
|
+
return {
|
|
23004
|
+
getLayers: () => scene.layers.map((l) => ({ id: l.id, visible: l.visible })),
|
|
23005
|
+
getNode: (id) => scene.get(id),
|
|
23006
|
+
getChildren: (parentId) => {
|
|
23007
|
+
if (parentId === null) return scene.roots;
|
|
23008
|
+
const node = scene.get(parentId);
|
|
23009
|
+
return node && node.kind === "container" ? node.children : [];
|
|
23010
|
+
},
|
|
23011
|
+
getPose: (id) => scene.get(id).pose
|
|
23012
|
+
};
|
|
23013
|
+
}
|
|
23014
|
+
function buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor) {
|
|
23015
|
+
const wrappedDrawOne = (node, pose, v) => wrapNodeOutput(drawOne(node, pose, v), pose, alphaFor ? alphaFor(node.id) : 1);
|
|
23016
|
+
const children = buildSceneTree(
|
|
23017
|
+
sceneAsHierarchy(scene),
|
|
23018
|
+
wrappedDrawOne,
|
|
23019
|
+
view
|
|
23020
|
+
);
|
|
22356
23021
|
if (extraCommands && extraCommands.length > 0) {
|
|
22357
23022
|
for (const cmd of extraCommands) children.push(cmd);
|
|
22358
23023
|
}
|
|
@@ -22363,7 +23028,7 @@ function buildSceneViewCommands(scene, view, drawOne, extraCommands) {
|
|
|
22363
23028
|
}];
|
|
22364
23029
|
}
|
|
22365
23030
|
function renderSceneToCanvas(args) {
|
|
22366
|
-
const { canvas, scene, view, width, height, drawOne, extraCommands } = args;
|
|
23031
|
+
const { canvas, scene, view, width, height, drawOne, extraCommands, alphaFor } = args;
|
|
22367
23032
|
const dpr = args.dpr ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1);
|
|
22368
23033
|
let entry = RENDERER_CACHE.get(canvas);
|
|
22369
23034
|
if (!entry) {
|
|
@@ -22391,11 +23056,11 @@ function renderSceneToCanvas(args) {
|
|
|
22391
23056
|
entry.height = height;
|
|
22392
23057
|
entry.dpr = dpr;
|
|
22393
23058
|
}
|
|
22394
|
-
const commands = buildSceneViewCommands(scene, view, drawOne, extraCommands);
|
|
23059
|
+
const commands = buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor);
|
|
22395
23060
|
entry.renderer.render(commands, viewToMat3(view));
|
|
22396
23061
|
}
|
|
22397
23062
|
function SceneViewCanvasInner(props) {
|
|
22398
|
-
const { scene, view, width, height, drawOne, extraCommands, className, canvasRef } = props;
|
|
23063
|
+
const { scene, view, width, height, drawOne, extraCommands, alphaFor, className, canvasRef } = props;
|
|
22399
23064
|
useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);
|
|
22400
23065
|
const localRef = useRef(null);
|
|
22401
23066
|
const setCanvasRef = (el) => {
|
|
@@ -22416,7 +23081,8 @@ function SceneViewCanvasInner(props) {
|
|
|
22416
23081
|
width,
|
|
22417
23082
|
height,
|
|
22418
23083
|
drawOne,
|
|
22419
|
-
extraCommands
|
|
23084
|
+
extraCommands,
|
|
23085
|
+
alphaFor
|
|
22420
23086
|
});
|
|
22421
23087
|
});
|
|
22422
23088
|
return /* @__PURE__ */ jsx(
|
|
@@ -22515,6 +23181,7 @@ function MinimapCanvasInner(props) {
|
|
|
22515
23181
|
width,
|
|
22516
23182
|
height,
|
|
22517
23183
|
drawOne,
|
|
23184
|
+
alphaFor,
|
|
22518
23185
|
fit = "scene",
|
|
22519
23186
|
poseBounds,
|
|
22520
23187
|
indicatorStyle,
|
|
@@ -22626,6 +23293,7 @@ function MinimapCanvasInner(props) {
|
|
|
22626
23293
|
height,
|
|
22627
23294
|
drawOne,
|
|
22628
23295
|
extraCommands,
|
|
23296
|
+
alphaFor,
|
|
22629
23297
|
className,
|
|
22630
23298
|
canvasRef: setCanvasRef
|
|
22631
23299
|
}
|
|
@@ -22667,7 +23335,7 @@ function planPixelRender(args) {
|
|
|
22667
23335
|
fill: { fill: "solid", color: args.background }
|
|
22668
23336
|
});
|
|
22669
23337
|
}
|
|
22670
|
-
commands.push(...buildSceneViewCommands(args.scene, view, drawOne));
|
|
23338
|
+
commands.push(...buildSceneViewCommands(args.scene, view, drawOne, void 0, args.alphaFor));
|
|
22671
23339
|
return { width, height, view, commands };
|
|
22672
23340
|
}
|
|
22673
23341
|
function defaultCreateCanvas(width, height) {
|
|
@@ -23019,15 +23687,11 @@ function measureText(ctx, text, maxWidth, style) {
|
|
|
23019
23687
|
function measureTextBounds(text, style, opts) {
|
|
23020
23688
|
const resolved = resolveTextStyle(style);
|
|
23021
23689
|
const runs = resolveRuns([{ text }], resolved);
|
|
23022
|
-
const { bounds } = layoutRuns(
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
align: resolved.align
|
|
23028
|
-
},
|
|
23029
|
-
{ x: 0, y: 0 }
|
|
23030
|
-
);
|
|
23690
|
+
const { bounds } = layoutRuns(runs, {
|
|
23691
|
+
maxWidth: opts?.maxWidth ?? Infinity,
|
|
23692
|
+
lineHeight: opts?.lineHeight ?? resolved.lineHeight,
|
|
23693
|
+
align: resolved.align
|
|
23694
|
+
});
|
|
23031
23695
|
return bounds;
|
|
23032
23696
|
}
|
|
23033
23697
|
|
|
@@ -23929,6 +24593,14 @@ function useSceneTextEdit(scene, container, options = {}) {
|
|
|
23929
24593
|
const setter = optsRef.current.setRuns;
|
|
23930
24594
|
const data = setter ? setter(node.data, runs) : { ...node.data, runs };
|
|
23931
24595
|
sceneRef.current.update(nid, { data });
|
|
24596
|
+
},
|
|
24597
|
+
setStyle: (id, style) => {
|
|
24598
|
+
const nid = asNodeId(id);
|
|
24599
|
+
const node = sceneRef.current.get(nid);
|
|
24600
|
+
if (!node) return;
|
|
24601
|
+
const setter = optsRef.current.setStyle;
|
|
24602
|
+
const data = setter ? setter(node.data, style) : { ...node.data, style };
|
|
24603
|
+
sceneRef.current.update(nid, { data });
|
|
23932
24604
|
}
|
|
23933
24605
|
});
|
|
23934
24606
|
const onDoubleClick = useCallback((e) => {
|
|
@@ -23940,10 +24612,9 @@ function useSceneTextEdit(scene, container, options = {}) {
|
|
|
23940
24612
|
const cy = view ? canvasY / view.scale.y + view.y : canvasY;
|
|
23941
24613
|
const readText = (data) => optsRef.current.getText ? optsRef.current.getText(data) : data.text ?? "";
|
|
23942
24614
|
const readStyle = (data) => optsRef.current.getStyle ? optsRef.current.getStyle(data) : data.style;
|
|
23943
|
-
const order =
|
|
24615
|
+
const order = sceneRef.current.renderOrderNodes();
|
|
23944
24616
|
for (let i = order.length - 1; i >= 0; i--) {
|
|
23945
|
-
const node =
|
|
23946
|
-
if (!node) continue;
|
|
24617
|
+
const node = order[i];
|
|
23947
24618
|
const text = readText(node.data);
|
|
23948
24619
|
const pose = {
|
|
23949
24620
|
x: node.pose.x,
|
|
@@ -27638,6 +28309,6 @@ function mergeContributions(...bundles) {
|
|
|
27638
28309
|
return out;
|
|
27639
28310
|
}
|
|
27640
28311
|
|
|
27641
|
-
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyHitExistingGate, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, bezierCubic, bezierQuadratic, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView2 as computeFitView, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMarkdownRenderer, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewportLayer, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic2 as easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, fontString, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getNodeShapes, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, isEditableTarget2 as isEditableTarget, isPatternSpec, lassoSelectAction, layoutMarkdown, lerpColorArray, lerpOklab, lerpOklch, linear, liveScope, makeViewportZoomAction, markdownToRuns, mat3, matchAlignment, matchesKeyBinding, meanScale, measureText, measureTextBounds, measuredWidth, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerNodeShape, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolvePatternSpec, resolveRuns, resolveTextStyle, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, runsToMarkdown, runsToPlainText, sampleGradientStops, sceneFromJSON, sceneNodeClientRect, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textLineBoxes, tileGrid, toHex8, toRuns, translatePoseViaDescriptor, translateRectPose, tweenPose, tweenVertexColors, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewTween, useZoom, verticalAlignOffset, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
27642
|
-
//# sourceMappingURL=chunk-
|
|
27643
|
-
//# sourceMappingURL=chunk-
|
|
28312
|
+
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyHitExistingGate, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, bezierCubic, bezierQuadratic, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView2 as computeFitView, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMarkdownRenderer, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewportLayer, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic2 as easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, fontString, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getNodeShapes, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, isEditableTarget2 as isEditableTarget, isPatternSpec, lassoSelectAction, layoutMarkdown, lerpColorArray, lerpOklab, lerpOklch, linear, liveScope, makeViewportZoomAction, markdownToRuns, mat3, matchAlignment, matchesKeyBinding, meanScale, measureText, measureTextBounds, measuredWidth, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerNodeShape, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolvePatternSpec, resolveRuns, resolveTextStyle, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, runsToMarkdown, runsToPlainText, sampleGradientStops, sceneFromJSON, sceneNodeClientRect, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textLineBoxes, tileGrid, toHex8, toRuns, translatePoseViaDescriptor, translateRectPose, tweenPose, tweenVertexColors, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewTween, useZoom, verticalAlignOffset, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, viewportsAt, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
28313
|
+
//# sourceMappingURL=chunk-PI56ORHE.js.map
|
|
28314
|
+
//# sourceMappingURL=chunk-PI56ORHE.js.map
|