@unmade/text-renderer 1.1.1 → 1.2.0
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/README.md +184 -0
- package/dist/{__vite-browser-external-CijFC1_R.js → __vite-browser-external-oLchLuMx.js} +1 -1
- package/dist/baselines/index.d.ts +19 -0
- package/dist/ce-adapter/index.cjs +1 -1
- package/dist/ce-adapter/index.js +1 -1
- package/dist/fitting/index.d.ts +86 -0
- package/dist/helpers/bbox.d.ts +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1004 -327
- package/dist/node/baselines/index.d.ts +19 -0
- package/dist/node/fitting/index.d.ts +86 -0
- package/dist/node/helpers/bbox.d.ts +2 -1
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +239 -123
- package/dist/node/rendering/index.d.ts +2 -2
- package/dist/node/types.d.ts +3 -0
- package/dist/rendering/index.d.ts +2 -2
- package/dist/{chunk-3b4jIN3o.js → rolldown-runtime-DtPi1Y-2.js} +2 -2
- package/dist/types.d.ts +3 -0
- package/dist/worker/baselines/index.d.ts +19 -0
- package/dist/worker/fitting/index.d.ts +86 -0
- package/dist/worker/helpers/bbox.d.ts +2 -1
- package/dist/worker/index.d.ts +1 -0
- package/dist/worker/index.js +2665 -2323
- package/dist/worker/rendering/index.d.ts +2 -2
- package/dist/worker/types.d.ts +3 -0
- package/package.json +12 -5
- package/dist/helpers/matrix.d.ts +0 -8
- package/dist/node/helpers/matrix.d.ts +0 -8
- package/dist/worker/helpers/matrix.d.ts +0 -8
package/dist/node/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Blob as e, Buffer as t, Face as n, Feature as r, Font as i, shape as a } from "harfbuzzjs";
|
|
2
|
-
import
|
|
2
|
+
import o from "@thednp/dommatrix";
|
|
3
3
|
import { DOMParser as s } from "linkedom";
|
|
4
4
|
import "node:path";
|
|
5
|
-
import c from "
|
|
5
|
+
import { svgPathProperties as c } from "svg-path-properties";
|
|
6
6
|
//#region src/loading/createLoadedFont.ts
|
|
7
7
|
function l(e) {
|
|
8
8
|
let t = Infinity, n = Infinity, r = -Infinity, i = -Infinity, a = 0, o = 0;
|
|
@@ -237,18 +237,18 @@ var x = async (t, r = !1) => {
|
|
|
237
237
|
let a = f.get(t);
|
|
238
238
|
if (a) {
|
|
239
239
|
if (r && !a.svgGlyphs) {
|
|
240
|
-
let r =
|
|
241
|
-
a.svgGlyphs =
|
|
240
|
+
let r = await b(t), o = new e(r), s = new n(o), c = new i(s), l = s.referenceTable("SVG ");
|
|
241
|
+
a.svgGlyphs = l ? await _(l, c, s.upem) : /* @__PURE__ */ new Map();
|
|
242
242
|
}
|
|
243
243
|
return a;
|
|
244
244
|
}
|
|
245
|
-
let o =
|
|
245
|
+
let o = await b(t), s = new e(o), c = new n(s), l = new i(c), u = c.getName(1, "en") ?? "", p;
|
|
246
246
|
if (r) {
|
|
247
|
-
let e =
|
|
248
|
-
|
|
247
|
+
let e = c.referenceTable("SVG ");
|
|
248
|
+
p = e ? await _(e, l, c.upem) : /* @__PURE__ */ new Map();
|
|
249
249
|
}
|
|
250
|
-
let
|
|
251
|
-
return f.set(t,
|
|
250
|
+
let m = d(c, l, u, p);
|
|
251
|
+
return f.set(t, m), m;
|
|
252
252
|
}, S = .03125, C = 1.1, w = .2, T = {
|
|
253
253
|
outlineWidth: S,
|
|
254
254
|
letterSpacing: 0,
|
|
@@ -267,36 +267,44 @@ var x = async (t, r = !1) => {
|
|
|
267
267
|
return `${this.x} ${this.y}`;
|
|
268
268
|
}
|
|
269
269
|
};
|
|
270
|
-
function
|
|
270
|
+
function ee(e, t, n = new E(0, 0)) {
|
|
271
271
|
let r = e.X - n.X, i = e.Y - n.Y, a = t / 180 * Math.PI, o = Math.cos(a), s = Math.sin(a), c = r * o - i * s, l = r * s + i * o;
|
|
272
272
|
return new E(c + n.X, l + n.Y);
|
|
273
273
|
}
|
|
274
274
|
//#endregion
|
|
275
275
|
//#region src/baselines/index.ts
|
|
276
|
-
var
|
|
276
|
+
var D = (e) => e === void 0 || e === "flat" ? { type: "flat" } : e === "curved" ? { type: "curved" } : e, O = (e) => {
|
|
277
277
|
if (!e || !e.trim()) throw Error("Custom baseline path must be a non-empty SVG path string");
|
|
278
278
|
if (!e.trim().startsWith("M")) throw Error("Custom baseline path must start with an M (moveto) command");
|
|
279
|
-
},
|
|
279
|
+
}, k = ({ boxDimensions: e, totalTextHeight: t, baseline: n, lineHeight: r, verticalAlignment: i = "centre", lineNumber: a = 0 }) => {
|
|
280
280
|
let { width: o, height: s } = e, c = r - n, l = n;
|
|
281
281
|
switch (i) {
|
|
282
282
|
case "centre":
|
|
283
283
|
l = (s - t) / 2 + r - c;
|
|
284
284
|
break;
|
|
285
|
-
case "bottom":
|
|
286
|
-
l = s - t + r - c;
|
|
287
|
-
break;
|
|
285
|
+
case "bottom": l = s - t + r - c;
|
|
288
286
|
}
|
|
289
287
|
return l += r * C * a, `M 0 ${l} L ${o} ${l}`;
|
|
290
|
-
},
|
|
291
|
-
let {
|
|
292
|
-
|
|
288
|
+
}, A = ({ boxDimensions: e, baseline: t, textHeight: n, verticalAlignment: r }) => {
|
|
289
|
+
let { height: i } = e, a = n * w, o = n + a, s = t + (r === "top" ? 0 : i / 2 - o / 2), c = s + a;
|
|
290
|
+
return r !== "top" && (c > i || s - n < 0) ? A({
|
|
293
291
|
boxDimensions: e,
|
|
294
292
|
baseline: t,
|
|
295
293
|
textHeight: n,
|
|
296
294
|
verticalAlignment: "top"
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
|
|
295
|
+
}) : {
|
|
296
|
+
curveTop: s,
|
|
297
|
+
curveBottom: c,
|
|
298
|
+
curveXInset: n / 4
|
|
299
|
+
};
|
|
300
|
+
}, j = ({ boxDimensions: e, baseline: t, textHeight: n, verticalAlignment: r }) => {
|
|
301
|
+
let { width: i } = e, { curveTop: a, curveBottom: o, curveXInset: s } = A({
|
|
302
|
+
boxDimensions: e,
|
|
303
|
+
baseline: t,
|
|
304
|
+
textHeight: n,
|
|
305
|
+
verticalAlignment: r
|
|
306
|
+
}), c = new E(s, o), l = new E(i / 2, a), u = new E(i - s, o), d = i * .2, f = new E(d, a), p = new E(i - d, a);
|
|
307
|
+
return `${`M ${c.toSVGString()}`} ${`Q ${f.toSVGString()} ${l.toSVGString()}`} ${`Q ${p.toSVGString()} ${u.toSVGString()}`}`;
|
|
300
308
|
}, M = (e) => {
|
|
301
309
|
for (let t of [
|
|
302
310
|
"I",
|
|
@@ -324,11 +332,11 @@ var O = (e) => e === void 0 || e === "flat" ? { type: "flat" } : e === "curved"
|
|
|
324
332
|
height: s.y2 - s.y1 + c,
|
|
325
333
|
baseline: s.y1 * -1 + c / 2
|
|
326
334
|
};
|
|
327
|
-
}, I = s,
|
|
328
|
-
|
|
335
|
+
}, I = s, te = o, ne = new I().parseFromString("<svg></svg>", "image/svg+xml");
|
|
336
|
+
ne.readyState = "complete";
|
|
329
337
|
//#endregion
|
|
330
338
|
//#region ../svg-helpers/dist/colours/named-colours.mjs
|
|
331
|
-
var
|
|
339
|
+
var re = {
|
|
332
340
|
aliceblue: "#f0f8ff",
|
|
333
341
|
antiquewhite: "#faebd7",
|
|
334
342
|
aqua: "#00ffff",
|
|
@@ -477,13 +485,13 @@ var ne = {
|
|
|
477
485
|
whitesmoke: "#f5f5f5",
|
|
478
486
|
yellow: "#ffff00",
|
|
479
487
|
yellowgreen: "#9acd32"
|
|
480
|
-
},
|
|
488
|
+
}, ie = (e) => {
|
|
481
489
|
let t = Array.from(e), n = !1;
|
|
482
490
|
return t[0] === "#" && (t.shift(), n = !0), t.length === 3 && (t = t.map((e) => `${e}${e}`)), `${n ? "#" : ""}${t.join("").toLowerCase()}`;
|
|
483
491
|
}, L = (e) => Math.max(0, Math.min(255, Math.round(typeof e == "string" ? Number.parseInt(e, 10) : e))).toString(16).padStart(2, "0"), R = (...e) => {
|
|
484
492
|
let [t, n, r] = Array.isArray(e[0]) ? e[0] : e;
|
|
485
493
|
return `#${L(t)}${L(n)}${L(r)}`;
|
|
486
|
-
},
|
|
494
|
+
}, ae = (e, t, n) => {
|
|
487
495
|
if (t === 0) {
|
|
488
496
|
let e = Math.round(n * 255);
|
|
489
497
|
return [
|
|
@@ -498,9 +506,9 @@ var ne = {
|
|
|
498
506
|
Math.round((c + o) * 255),
|
|
499
507
|
Math.round((l + o) * 255)
|
|
500
508
|
];
|
|
501
|
-
},
|
|
509
|
+
}, oe = (e) => /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.test(e), z = (e) => {
|
|
502
510
|
let t = e.trim().toLowerCase();
|
|
503
|
-
if (t.startsWith("#") || /^[0-9a-f]{3}([0-9a-f]{3})?$/.test(t)) return
|
|
511
|
+
if (t.startsWith("#") || /^[0-9a-f]{3}([0-9a-f]{3})?$/.test(t)) return oe(t) ? ie(t) : void 0;
|
|
504
512
|
if (t.startsWith("rgb")) {
|
|
505
513
|
let e = t.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*[\d.]+\s*)?\)/);
|
|
506
514
|
return e ? R(Number.parseInt(e[1], 10), Number.parseInt(e[2], 10), Number.parseInt(e[3], 10)) : void 0;
|
|
@@ -508,10 +516,10 @@ var ne = {
|
|
|
508
516
|
if (t.startsWith("hsl")) {
|
|
509
517
|
let e = t.match(/hsla?\(\s*(\d+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*(?:,\s*[\d.]+\s*)?\)/);
|
|
510
518
|
if (!e) return;
|
|
511
|
-
let [n, r, i] =
|
|
519
|
+
let [n, r, i] = ae(Number.parseInt(e[1], 10), Number.parseFloat(e[2]) / 100, Number.parseFloat(e[3]) / 100);
|
|
512
520
|
return R(n, r, i);
|
|
513
521
|
}
|
|
514
|
-
let n =
|
|
522
|
+
let n = re[t];
|
|
515
523
|
if (n) return n;
|
|
516
524
|
}, B = {
|
|
517
525
|
svg: "svg",
|
|
@@ -527,7 +535,7 @@ var ne = {
|
|
|
527
535
|
}, V = {
|
|
528
536
|
fill: "fill",
|
|
529
537
|
stroke: "stroke"
|
|
530
|
-
},
|
|
538
|
+
}, se = {
|
|
531
539
|
tiling: [
|
|
532
540
|
B.circle,
|
|
533
541
|
B.ellipse,
|
|
@@ -553,69 +561,69 @@ var ne = {
|
|
|
553
561
|
`[${V.fill}]`,
|
|
554
562
|
`[${V.stroke}]`
|
|
555
563
|
]
|
|
556
|
-
},
|
|
564
|
+
}, ce = (e) => Array.from(e.querySelectorAll(se.tiling.map((e) => `*:not(clipPath) > ${e}`).join(", "))), le = (e) => {
|
|
557
565
|
let t = e.getAttribute(V.stroke);
|
|
558
566
|
return t === "none" || !t ? !1 : t;
|
|
559
|
-
},
|
|
567
|
+
}, H = (e) => {
|
|
560
568
|
if (!(e === "none" || e === "transparent" || e.startsWith("url("))) return z(e);
|
|
561
|
-
},
|
|
562
|
-
let t =
|
|
563
|
-
let n = t.getAttribute("stop-color"), r = t.getAttribute(V.fill) || "#000", i =
|
|
569
|
+
}, ue = (e) => {
|
|
570
|
+
let t = ce(e).reduce((e, t) => {
|
|
571
|
+
let n = t.getAttribute("stop-color"), r = t.getAttribute(V.fill) || "#000", i = le(t);
|
|
564
572
|
if (r && !n) {
|
|
565
|
-
let t =
|
|
573
|
+
let t = H(r);
|
|
566
574
|
t && e.add(t);
|
|
567
575
|
}
|
|
568
576
|
if (n) {
|
|
569
|
-
let t =
|
|
577
|
+
let t = H(n);
|
|
570
578
|
t && e.add(t);
|
|
571
579
|
}
|
|
572
580
|
if (i) {
|
|
573
|
-
let t =
|
|
581
|
+
let t = H(i);
|
|
574
582
|
t && e.add(t);
|
|
575
583
|
}
|
|
576
584
|
return e;
|
|
577
585
|
}, /* @__PURE__ */ new Set());
|
|
578
586
|
return Array.from(t);
|
|
579
|
-
},
|
|
587
|
+
}, de = (e) => {
|
|
580
588
|
let t = new I().parseFromString(e, "image/svg+xml").querySelector("svg");
|
|
581
|
-
return t ?
|
|
589
|
+
return t ? ue(t) : [];
|
|
582
590
|
};
|
|
583
591
|
//#endregion
|
|
584
592
|
//#region src/glyph/svg-glyph-converter.ts
|
|
585
|
-
function
|
|
593
|
+
function U(e) {
|
|
586
594
|
let t = e.trim(), n = t.startsWith("<svg") || t.startsWith("<?xml"), r = n ? t : `<svg>${t}</svg>`;
|
|
587
595
|
return {
|
|
588
596
|
doc: new I().parseFromString(r, "image/svg+xml"),
|
|
589
597
|
wasWrapped: !n
|
|
590
598
|
};
|
|
591
599
|
}
|
|
592
|
-
function
|
|
600
|
+
function W(e, t) {
|
|
593
601
|
let n = e.querySelector("svg");
|
|
594
602
|
return n ? t ? n.innerHTML : n.outerHTML : "";
|
|
595
603
|
}
|
|
596
|
-
function
|
|
604
|
+
function fe(e) {
|
|
597
605
|
let { svgGlyphs: t } = e;
|
|
598
606
|
if (!t || t.size === 0) return [];
|
|
599
607
|
let n = /* @__PURE__ */ new Set();
|
|
600
|
-
for (let [, e] of t) for (let t of
|
|
608
|
+
for (let [, e] of t) for (let t of de(e.svg)) n.add(t);
|
|
601
609
|
return Array.from(n);
|
|
602
610
|
}
|
|
603
|
-
function
|
|
611
|
+
function pe(e) {
|
|
604
612
|
return !!e && e !== "none" && e !== "transparent" && !e.startsWith("url(");
|
|
605
613
|
}
|
|
606
|
-
function
|
|
614
|
+
function me(e) {
|
|
607
615
|
let t = new I().parseFromString(e, "image/svg+xml").querySelector("svg");
|
|
608
616
|
return t ? t.innerHTML.trim() : "";
|
|
609
617
|
}
|
|
610
|
-
var
|
|
618
|
+
var he = [
|
|
611
619
|
"fill",
|
|
612
620
|
"stroke",
|
|
613
621
|
"clip-path",
|
|
614
622
|
"mask",
|
|
615
623
|
"filter"
|
|
616
624
|
];
|
|
617
|
-
function
|
|
618
|
-
let { doc: n, wasWrapped: r } =
|
|
625
|
+
function ge(e, t) {
|
|
626
|
+
let { doc: n, wasWrapped: r } = U(e), i = /* @__PURE__ */ new Map();
|
|
619
627
|
for (let e of n.querySelectorAll("[id]")) {
|
|
620
628
|
let n = e.getAttribute("id");
|
|
621
629
|
if (!n) continue;
|
|
@@ -623,7 +631,7 @@ function fe(e, t) {
|
|
|
623
631
|
i.set(n, r), e.setAttribute("id", r);
|
|
624
632
|
}
|
|
625
633
|
if (i.size === 0) return e;
|
|
626
|
-
for (let e of
|
|
634
|
+
for (let e of he) for (let t of n.querySelectorAll(`[${e}]`)) {
|
|
627
635
|
let n = t.getAttribute(e);
|
|
628
636
|
if (n) {
|
|
629
637
|
let r = n.replace(/url\(#([^)]+)\)/g, (e, t) => {
|
|
@@ -640,13 +648,13 @@ function fe(e, t) {
|
|
|
640
648
|
a && e.setAttribute(t, `#${a}`);
|
|
641
649
|
}
|
|
642
650
|
}
|
|
643
|
-
return
|
|
651
|
+
return W(n, r);
|
|
644
652
|
}
|
|
645
|
-
var
|
|
653
|
+
var _e = [
|
|
646
654
|
"fill",
|
|
647
655
|
"stroke",
|
|
648
656
|
"stop-color"
|
|
649
|
-
],
|
|
657
|
+
], ve = [
|
|
650
658
|
"path",
|
|
651
659
|
"rect",
|
|
652
660
|
"circle",
|
|
@@ -655,109 +663,95 @@ var pe = [
|
|
|
655
663
|
"polyline",
|
|
656
664
|
"text"
|
|
657
665
|
];
|
|
658
|
-
function
|
|
659
|
-
let { doc: n, wasWrapped: r } =
|
|
666
|
+
function ye(e, t) {
|
|
667
|
+
let { doc: n, wasWrapped: r } = U(e), i = {};
|
|
660
668
|
for (let [e, n] of Object.entries(t)) i[z(e) ?? e.toLowerCase()] = n;
|
|
661
|
-
for (let e of
|
|
669
|
+
for (let e of _e) for (let t of n.querySelectorAll(`[${e}]`)) {
|
|
662
670
|
let n = t.getAttribute(e);
|
|
663
|
-
if (!n || !
|
|
671
|
+
if (!n || !pe(n)) continue;
|
|
664
672
|
let r = z(n), a = r ? i[r] : void 0;
|
|
665
673
|
a && t.setAttribute(e, a.hex);
|
|
666
674
|
}
|
|
667
675
|
let a = i["#000000"];
|
|
668
676
|
if (a) {
|
|
669
|
-
let e =
|
|
677
|
+
let e = ve.map((e) => `${e}:not([fill])`).join(", ");
|
|
670
678
|
for (let t of n.querySelectorAll(e)) t.setAttribute("fill", a.hex);
|
|
671
679
|
}
|
|
672
|
-
return
|
|
680
|
+
return W(n, r);
|
|
673
681
|
}
|
|
674
682
|
//#endregion
|
|
675
|
-
//#region src/helpers/matrix.ts
|
|
676
|
-
var ge = (e = [
|
|
677
|
-
1,
|
|
678
|
-
0,
|
|
679
|
-
0,
|
|
680
|
-
1,
|
|
681
|
-
0,
|
|
682
|
-
0
|
|
683
|
-
]) => {
|
|
684
|
-
let t = new ee(`matrix(${e.join(",")})`);
|
|
685
|
-
if (!t) throw Error("Your browser does not support matrices");
|
|
686
|
-
return t;
|
|
687
|
-
};
|
|
688
|
-
//#endregion
|
|
689
683
|
//#region src/helpers/xml.ts
|
|
690
|
-
function
|
|
684
|
+
function be(e) {
|
|
691
685
|
return e.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
692
686
|
}
|
|
693
687
|
//#endregion
|
|
694
688
|
//#region src/rendering/index.ts
|
|
695
|
-
var
|
|
696
|
-
let { outlineWidth:
|
|
689
|
+
var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontSize: r, spacing: i = T, horizontalAlignment: a = "centre", colourMap: o }) => {
|
|
690
|
+
let { outlineWidth: s, letterSpacing: l, letterSpacingOutline: u } = i, d = new c(t), f = s ? r * s * 2 : 0, p = d.getTotalLength(), m = e.getPaths(n, 0, 0, r, { drawSVG: !1 }), h = e.getPath(n, 0, 0, r, { drawSVG: !1 }).getBoundingBox(), g = h.x1 - f / 2, _ = h.x2 + f / 2 - g, v = s > 0 ? u : l, y = v ? v * r : 0;
|
|
697
691
|
a === "distributed" && (y = n.length === 1 ? 0 : (p - _) / (n.length - 1));
|
|
698
692
|
let b = y * (n.length - 1), x = _ + b, S = 0 - g;
|
|
699
693
|
a === "centre" ? S = (p - x) / 2 - g : a === "right" && (S = p - _ - g - b);
|
|
700
694
|
let C = [];
|
|
701
695
|
for (let t = 0; t < m.length; t++) {
|
|
702
|
-
let i = m[t], a = i.getBoundingBox(),
|
|
696
|
+
let i = m[t], a = i.getBoundingBox(), s = e.charToGlyph(n[t]), { advanceWidth: c } = s;
|
|
703
697
|
if (!c) throw Error(`No advance width for character: ${n[t]} in font ${e.names.fontFamily}`);
|
|
704
|
-
let { x1: l, x2: u } =
|
|
698
|
+
let { x1: l, x2: u } = s.getBoundingBox(), f = G(c, r, e.unitsPerEm), h = G(u - l, r, e.unitsPerEm), g = S + a.x1;
|
|
705
699
|
if (t > 0 && (g += y * t), g + h > p) throw Error(`TOO_WIDE: character "${n[t]}" at index ${t} exceeds baseline path length (${Math.round(g + h)} > ${Math.round(p)})`);
|
|
706
|
-
let _ = g + f / 2, v = d.getTangentAtLength(_), b = Math.atan2(v.y, v.x) * 180 / Math.PI, x = d.getPointAtLength(g), w = x.x, T = x.y,
|
|
707
|
-
|
|
708
|
-
let
|
|
700
|
+
let _ = g + f / 2, v = d.getTangentAtLength(_), b = Math.atan2(v.y, v.x) * 180 / Math.PI, x = d.getPointAtLength(g), w = x.x, T = x.y, D = a.x2 - a.x1, O = new E(a.x1 + D / 2, 0), k = ee(new E(a.x1, 0), b, O), A = w - k.X, j = T - k.Y, M = new te();
|
|
701
|
+
M = M.translate(A, j);
|
|
702
|
+
let N;
|
|
709
703
|
if (b) {
|
|
710
|
-
let e = a.x1 +
|
|
711
|
-
|
|
712
|
-
} else
|
|
713
|
-
let
|
|
714
|
-
|
|
715
|
-
let
|
|
704
|
+
let e = a.x1 + D / 2;
|
|
705
|
+
M = M.translate(e, 0), M = M.rotate(b), M = M.translate(-e, 0), N = `translate(${A} ${j}) translate(${e} 0) rotate(${b}) translate(${-e} 0)`;
|
|
706
|
+
} else N = `translate(${A} ${j})`;
|
|
707
|
+
let P = i.toPathData(2);
|
|
708
|
+
P.length && !P.endsWith("Z") && (P += "Z", P = P.replace(/M/g, "ZM"), P = P.substring(1));
|
|
709
|
+
let F;
|
|
716
710
|
if (e.svgGlyphs) {
|
|
717
|
-
let n = e.svgGlyphs.get(
|
|
711
|
+
let n = e.svgGlyphs.get(s.index);
|
|
718
712
|
if (n) {
|
|
719
|
-
let e =
|
|
720
|
-
e =
|
|
713
|
+
let e = me(n.svg);
|
|
714
|
+
e = ge(e, `g${s.index}-${t}`), o && (e = ye(e, o)), F = {
|
|
721
715
|
content: e,
|
|
722
716
|
viewBox: n.viewbox,
|
|
723
717
|
x: a.x1,
|
|
724
718
|
y: a.y1,
|
|
725
719
|
width: a.x2 - a.x1,
|
|
726
720
|
height: a.y2 - a.y1,
|
|
727
|
-
glyphIndex:
|
|
721
|
+
glyphIndex: s.index
|
|
728
722
|
};
|
|
729
723
|
}
|
|
730
724
|
}
|
|
731
725
|
C.push({
|
|
732
726
|
path: i,
|
|
733
|
-
matrix:
|
|
727
|
+
matrix: M,
|
|
734
728
|
attributes: {
|
|
735
|
-
d:
|
|
736
|
-
"data-character":
|
|
737
|
-
transform:
|
|
729
|
+
d: P,
|
|
730
|
+
"data-character": be(n[t]),
|
|
731
|
+
transform: N
|
|
738
732
|
},
|
|
739
733
|
glyphData: {
|
|
740
|
-
index:
|
|
734
|
+
index: s.index,
|
|
741
735
|
bbox: a
|
|
742
736
|
},
|
|
743
|
-
...
|
|
737
|
+
...F ? { svgGlyph: F } : {}
|
|
744
738
|
});
|
|
745
739
|
}
|
|
746
740
|
return C;
|
|
747
|
-
},
|
|
741
|
+
}, K = { hex: "#FFFFFF" }, q = (e, t) => {
|
|
748
742
|
let n = `data-${e}-colour-url`, r = [`${e}="${t.hex}"`];
|
|
749
743
|
return t.reference && r.push(`${n}="${t.reference}"`), r.join(" ");
|
|
750
|
-
},
|
|
744
|
+
}, J = (e, t) => {
|
|
751
745
|
let { attributes: n, svgGlyph: r } = e;
|
|
752
|
-
return r ? `<g transform="${n.transform}" data-character="${n["data-character"]}"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="${r.viewBox}" width="${r.width}" height="${r.height}" x="${r.x}" y="${r.y}" data-glyph-index="${r.glyphIndex}">${r.content}</svg></g>` : `<path d="${n.d}" ${
|
|
753
|
-
},
|
|
746
|
+
return r ? `<g transform="${n.transform}" data-character="${n["data-character"]}"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="${r.viewBox}" width="${r.width}" height="${r.height}" x="${r.x}" y="${r.y}" data-glyph-index="${r.glyphIndex}">${r.content}</svg></g>` : `<path d="${n.d}" ${q("fill", t)} transform="${n.transform}" data-character="${n["data-character"]}"/>`;
|
|
747
|
+
}, Se = ({ boxDimensions: e, paths: t, spacing: n = T, fontSize: r = 0, fillColour: i = K, strokeColour: a = K }) => {
|
|
754
748
|
let { width: o, height: s } = e, { outlineWidth: c } = n, l = c > 0 && r > 0, u;
|
|
755
749
|
if (l) {
|
|
756
750
|
let e = r * c * 2;
|
|
757
|
-
u = `${t.filter((e) => !e.svgGlyph).map(({ attributes: t }) => `<path d="${t.d}" ${
|
|
758
|
-
} else u = t.map((e) =>
|
|
751
|
+
u = `${t.filter((e) => !e.svgGlyph).map(({ attributes: t }) => `<path d="${t.d}" ${q("fill", a)} ${q("stroke", a)} stroke-width="${e}" stroke-linejoin="round" transform="${t.transform}" data-character="${t["data-character"]}"/>`).join("\n ")}\n ${t.map((e) => J(e, i)).join("\n ")}`;
|
|
752
|
+
} else u = t.map((e) => J(e, i)).join("\n ");
|
|
759
753
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${o}" height="${s}" viewBox="0 0 ${o} ${s}">${u ? `\n ${u}\n` : ""}</svg>`;
|
|
760
|
-
},
|
|
754
|
+
}, Y = (e) => {
|
|
761
755
|
let { text: t, font: n, physicalSize: r, fontSize: i, boxDimensions: a, spacing: o = T, verticalAlignment: s = "centre", baseline: c = "flat", horizontalAlignment: l = "left", fillColour: u = { hex: "#FFFFFF" }, strokeColour: d = { hex: "#FFFFFF" }, colourMap: f } = e, { width: p, height: m, physicalWidth: h, physicalHeight: g } = a;
|
|
762
756
|
if (p <= 0 || m <= 0) throw Error(`boxDimensions width and height must be positive (got ${p}x${m})`);
|
|
763
757
|
if (h <= 0 || g <= 0) throw Error(`boxDimensions physicalWidth and physicalHeight must be positive (got ${h}x${g})`);
|
|
@@ -767,7 +761,7 @@ var J = (e, t, n) => e / n * t, Y = ({ font: e, baselinePath: t, text: n, fontSi
|
|
|
767
761
|
boxDimensions: a,
|
|
768
762
|
physicalSize: r,
|
|
769
763
|
spacing: o
|
|
770
|
-
}), v =
|
|
764
|
+
}), v = D(c), y = t.split("\n").filter((e) => e.length > 0);
|
|
771
765
|
y.length || (y = [""]), (v.type === "curved" || v.type === "custom") && (y = [y.join("")]);
|
|
772
766
|
let b = y.map((e) => F({
|
|
773
767
|
font: n,
|
|
@@ -779,7 +773,7 @@ var J = (e, t, n) => e / n * t, Y = ({ font: e, baselinePath: t, text: n, fontSi
|
|
|
779
773
|
let t;
|
|
780
774
|
switch (v.type) {
|
|
781
775
|
case "custom":
|
|
782
|
-
|
|
776
|
+
O(v.path), t = v.path;
|
|
783
777
|
break;
|
|
784
778
|
case "curved": {
|
|
785
779
|
let e = F({
|
|
@@ -796,18 +790,16 @@ var J = (e, t, n) => e / n * t, Y = ({ font: e, baselinePath: t, text: n, fontSi
|
|
|
796
790
|
});
|
|
797
791
|
break;
|
|
798
792
|
}
|
|
799
|
-
case "flat":
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
});
|
|
808
|
-
break;
|
|
793
|
+
case "flat": t = k({
|
|
794
|
+
boxDimensions: a,
|
|
795
|
+
totalTextHeight: w,
|
|
796
|
+
baseline: x,
|
|
797
|
+
lineHeight: S,
|
|
798
|
+
verticalAlignment: s,
|
|
799
|
+
lineNumber: e
|
|
800
|
+
});
|
|
809
801
|
}
|
|
810
|
-
let r =
|
|
802
|
+
let r = xe({
|
|
811
803
|
font: n,
|
|
812
804
|
baselinePath: t,
|
|
813
805
|
text: y[e],
|
|
@@ -818,7 +810,7 @@ var J = (e, t, n) => e / n * t, Y = ({ font: e, baselinePath: t, text: n, fontSi
|
|
|
818
810
|
});
|
|
819
811
|
E.push(...r);
|
|
820
812
|
}
|
|
821
|
-
return
|
|
813
|
+
return Se({
|
|
822
814
|
boxDimensions: a,
|
|
823
815
|
paths: E,
|
|
824
816
|
spacing: o,
|
|
@@ -826,15 +818,139 @@ var J = (e, t, n) => e / n * t, Y = ({ font: e, baselinePath: t, text: n, fontSi
|
|
|
826
818
|
fillColour: u,
|
|
827
819
|
strokeColour: d
|
|
828
820
|
});
|
|
829
|
-
},
|
|
821
|
+
}, X = 100, Ce = (e) => {
|
|
822
|
+
let t = e.split("\n").filter((e) => e.length > 0);
|
|
823
|
+
return t.length ? t : [""];
|
|
824
|
+
}, we = (e) => e.split("\n").filter((e) => e.length > 0).join(""), Te = (e, t, n, r, i, a) => {
|
|
825
|
+
let o = F({
|
|
826
|
+
font: e,
|
|
827
|
+
text: M(e),
|
|
828
|
+
fontSize: n,
|
|
829
|
+
spacing: r
|
|
830
|
+
}), s = {
|
|
831
|
+
boxDimensions: i,
|
|
832
|
+
baseline: o.baseline,
|
|
833
|
+
textHeight: o.height,
|
|
834
|
+
verticalAlignment: a
|
|
835
|
+
}, l = new c(j(s)).getTotalLength(), { curveTop: u, curveBottom: d } = A(s), f = F({
|
|
836
|
+
font: e,
|
|
837
|
+
text: t,
|
|
838
|
+
fontSize: n,
|
|
839
|
+
spacing: r
|
|
840
|
+
}), p = u - f.baseline, m = d + (f.height - f.baseline);
|
|
841
|
+
return {
|
|
842
|
+
width: f.width <= l,
|
|
843
|
+
height: p >= 0 && m <= i.height
|
|
844
|
+
};
|
|
845
|
+
}, Z = (e) => e.width && e.height, Q = (e) => e.width ? "height" : "width", Ee = .01, De = 60, Oe = ({ font: e, text: t, boxDimensions: n, spacing: r, verticalAlignment: i, minFontSize: a, maxFontSize: o }) => {
|
|
846
|
+
let s = we(t);
|
|
847
|
+
if (!s.length) return {
|
|
848
|
+
fontSize: o,
|
|
849
|
+
fits: !0,
|
|
850
|
+
boundBy: "requestedSize"
|
|
851
|
+
};
|
|
852
|
+
let c = (t) => Te(e, s, t, r, n, i), l = c(a);
|
|
853
|
+
if (!Z(l)) return {
|
|
854
|
+
fontSize: a,
|
|
855
|
+
fits: !1,
|
|
856
|
+
boundBy: Q(l)
|
|
857
|
+
};
|
|
858
|
+
if (Z(c(o))) return {
|
|
859
|
+
fontSize: o,
|
|
860
|
+
fits: !0,
|
|
861
|
+
boundBy: "requestedSize"
|
|
862
|
+
};
|
|
863
|
+
let u = a, d = o, f = 0;
|
|
864
|
+
for (; d - u > Ee && f < De;) {
|
|
865
|
+
let e = (u + d) / 2;
|
|
866
|
+
Z(c(e)) ? u = e : d = e, f++;
|
|
867
|
+
}
|
|
868
|
+
return {
|
|
869
|
+
fontSize: u,
|
|
870
|
+
fits: !0,
|
|
871
|
+
boundBy: Q(c(d))
|
|
872
|
+
};
|
|
873
|
+
}, $ = (e) => {
|
|
874
|
+
let { font: t, text: n, boxDimensions: r, size: i, spacing: a = T, baseline: o = "flat", verticalAlignment: s = "centre" } = e, l = i.mode === "fitToBox" ? i.maxFontSize : i.mode === "fontSize" ? i.fontSize : P({
|
|
875
|
+
font: t,
|
|
876
|
+
boxDimensions: r,
|
|
877
|
+
physicalSize: i.physicalSize,
|
|
878
|
+
spacing: a
|
|
879
|
+
});
|
|
880
|
+
if (!n.length) return {
|
|
881
|
+
fontSize: l,
|
|
882
|
+
fits: !0,
|
|
883
|
+
boundBy: "requestedSize"
|
|
884
|
+
};
|
|
885
|
+
let u = D(o);
|
|
886
|
+
if (u.type === "curved") return Oe({
|
|
887
|
+
font: t,
|
|
888
|
+
text: n,
|
|
889
|
+
boxDimensions: r,
|
|
890
|
+
spacing: a,
|
|
891
|
+
verticalAlignment: s,
|
|
892
|
+
minFontSize: i.mode === "fitToBox" ? i.minFontSize : l,
|
|
893
|
+
maxFontSize: l
|
|
894
|
+
});
|
|
895
|
+
let d = Ce(n);
|
|
896
|
+
u.type === "custom" && (d = [d.join("")]);
|
|
897
|
+
let f = d.map((e) => F({
|
|
898
|
+
font: t,
|
|
899
|
+
text: e,
|
|
900
|
+
fontSize: X,
|
|
901
|
+
spacing: a
|
|
902
|
+
})), p = Math.max(...f.map((e) => e.baseline)) + Math.max(...f.map((e) => e.height - e.baseline)), m = d.length === 1 ? p : p + p * (d.length - 1) * C, h = Math.max(...f.map((e) => e.width)), g = (u.type === "custom" ? new c(u.path).getTotalLength() : r.width) / h, _ = r.height / m, v = g <= _ ? "width" : "height", y = X * Math.min(g, _);
|
|
903
|
+
return i.mode === "fitToBox" ? y < i.minFontSize ? {
|
|
904
|
+
fontSize: i.minFontSize,
|
|
905
|
+
fits: !1,
|
|
906
|
+
boundBy: v
|
|
907
|
+
} : y > i.maxFontSize ? {
|
|
908
|
+
fontSize: i.maxFontSize,
|
|
909
|
+
fits: !0,
|
|
910
|
+
boundBy: "requestedSize"
|
|
911
|
+
} : {
|
|
912
|
+
fontSize: y,
|
|
913
|
+
fits: !0,
|
|
914
|
+
boundBy: v
|
|
915
|
+
} : l <= y ? {
|
|
916
|
+
fontSize: l,
|
|
917
|
+
fits: !0,
|
|
918
|
+
boundBy: "requestedSize"
|
|
919
|
+
} : {
|
|
920
|
+
fontSize: l,
|
|
921
|
+
fits: !1,
|
|
922
|
+
boundBy: v
|
|
923
|
+
};
|
|
924
|
+
}, ke = (e) => {
|
|
925
|
+
let t = e.text, n = t, r = 0, i = 0;
|
|
926
|
+
for (;;) {
|
|
927
|
+
let a = $({
|
|
928
|
+
...e,
|
|
929
|
+
text: n
|
|
930
|
+
});
|
|
931
|
+
if (a.fits) return {
|
|
932
|
+
...a,
|
|
933
|
+
text: n,
|
|
934
|
+
truncated: n !== t,
|
|
935
|
+
linesDropped: r,
|
|
936
|
+
charactersRemoved: i
|
|
937
|
+
};
|
|
938
|
+
let o = n.split("\n");
|
|
939
|
+
if (o.length > 1) n = o.slice(0, -1).join("\n"), r += 1;
|
|
940
|
+
else {
|
|
941
|
+
let e = n.slice(0, -1).trim();
|
|
942
|
+
i += n.length - e.length, n = e;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}, Ae = async (e) => {
|
|
830
946
|
let { fontUrl: t, fontSizeFallback: n, ...r } = e, i = await x(t, !!r.colourMap);
|
|
831
947
|
try {
|
|
832
|
-
return
|
|
948
|
+
return Y({
|
|
833
949
|
...r,
|
|
834
950
|
font: i
|
|
835
951
|
});
|
|
836
952
|
} catch (e) {
|
|
837
|
-
if (n != null && e instanceof Error && e.message.startsWith("TOO_WIDE")) return
|
|
953
|
+
if (n != null && e instanceof Error && e.message.startsWith("TOO_WIDE")) return Y({
|
|
838
954
|
...r,
|
|
839
955
|
font: i,
|
|
840
956
|
fontSize: n
|
|
@@ -843,4 +959,4 @@ var J = (e, t, n) => e / n * t, Y = ({ font: e, baselinePath: t, text: n, fontSi
|
|
|
843
959
|
}
|
|
844
960
|
};
|
|
845
961
|
//#endregion
|
|
846
|
-
export { S as DEFAULT_OUTLINE_FACTOR, T as DEFAULT_SPACING, C as LINE_HEIGHT, j as generateCurvedBaseline,
|
|
962
|
+
export { S as DEFAULT_OUTLINE_FACTOR, T as DEFAULT_SPACING, C as LINE_HEIGHT, ke as fitAndTruncateTextToBox, j as generateCurvedBaseline, k as generateFlatBaseline, p as getFontCache, fe as getFontColours, P as getFontSizeFromPhysicalSize, $ as getFontSizeToFitBox, Ae as getRenderedText, F as getTextMetricsAtFontSize, x as loadFont, D as normaliseBaselineOption, Y as renderText, O as validateCustomBaselinePath };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LoadedFont } from '../loading';
|
|
2
|
-
import { ColourMap, GlyphFill, HorizontalTextAlignmentValues, TextSpacing } from '../types';
|
|
2
|
+
import { ColourMap, GlyphFill, HorizontalTextAlignmentValues, PlatformMatrix, TextSpacing } from '../types';
|
|
3
3
|
export interface SvgGlyphEntry {
|
|
4
4
|
content: string;
|
|
5
5
|
viewBox: string;
|
|
@@ -16,7 +16,7 @@ export interface PathEntry {
|
|
|
16
16
|
transform: string;
|
|
17
17
|
};
|
|
18
18
|
path: unknown;
|
|
19
|
-
matrix:
|
|
19
|
+
matrix: PlatformMatrix;
|
|
20
20
|
glyphData: {
|
|
21
21
|
index: number;
|
|
22
22
|
bbox: {
|
package/dist/node/types.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { DOMMatrix } from '@unmade/platform';
|
|
1
2
|
import { LoadedFont } from './loading';
|
|
3
|
+
/** The platform's matrix, which is not the same shape as the DOM's DOMMatrix. */
|
|
4
|
+
export type PlatformMatrix = InstanceType<typeof DOMMatrix>;
|
|
2
5
|
export type MeasurementUnits = 'mm' | 'in';
|
|
3
6
|
export type BoxDimensions = {
|
|
4
7
|
width: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LoadedFont } from '../loading';
|
|
2
|
-
import { ColourMap, GlyphFill, HorizontalTextAlignmentValues, TextSpacing } from '../types';
|
|
2
|
+
import { ColourMap, GlyphFill, HorizontalTextAlignmentValues, PlatformMatrix, TextSpacing } from '../types';
|
|
3
3
|
export interface SvgGlyphEntry {
|
|
4
4
|
content: string;
|
|
5
5
|
viewBox: string;
|
|
@@ -16,7 +16,7 @@ export interface PathEntry {
|
|
|
16
16
|
transform: string;
|
|
17
17
|
};
|
|
18
18
|
path: unknown;
|
|
19
|
-
matrix:
|
|
19
|
+
matrix: PlatformMatrix;
|
|
20
20
|
glyphData: {
|
|
21
21
|
index: number;
|
|
22
22
|
bbox: {
|