@unmade/text-renderer 1.2.0 → 1.3.1

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.
@@ -1,7 +1,7 @@
1
1
  import { Blob as e, Buffer as t, Face as n, Feature as r, Font as i, shape as a } from "harfbuzzjs";
2
2
  import o from "@thednp/dommatrix";
3
- import { DOMParser as s } from "linkedom";
4
3
  import "node:path";
4
+ import { DOMParser as s } from "linkedom";
5
5
  import { svgPathProperties as c } from "svg-path-properties";
6
6
  //#region src/loading/createLoadedFont.ts
7
7
  function l(e) {
@@ -305,7 +305,87 @@ var D = (e) => e === void 0 || e === "flat" ? { type: "flat" } : e === "curved"
305
305
  verticalAlignment: r
306
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
307
  return `${`M ${c.toSVGString()}`} ${`Q ${f.toSVGString()} ${l.toSVGString()}`} ${`Q ${p.toSVGString()} ${u.toSVGString()}`}`;
308
- }, M = (e) => {
308
+ }, M = class e {
309
+ constructor(e = 0, t = 0, n = 0, r = 1) {
310
+ this.x = e, this.y = t, this.z = n, this.w = r;
311
+ }
312
+ static fromPoint(t) {
313
+ return new e(t.x, t.y, t.z === void 0 ? 0 : t.z, t.w === void 0 ? 1 : t.w);
314
+ }
315
+ matrixTransform(t) {
316
+ return t.is2D && this.z === 0 && this.w === 1 ? new e(this.x * t.a + this.y * t.c + t.e, this.x * t.b + this.y * t.d + t.f, 0, 1) : new e(this.x * t.m11 + this.y * t.m21 + this.z * t.m31 + this.w * t.m41, this.x * t.m12 + this.y * t.m22 + this.z * t.m32 + this.w * t.m42, this.x * t.m13 + this.y * t.m23 + this.z * t.m33 + this.w * t.m43, this.x * t.m14 + this.y * t.m24 + this.z * t.m34 + this.w * t.m44);
317
+ }
318
+ toJSON() {
319
+ return {
320
+ x: this.x,
321
+ y: this.y,
322
+ z: this.z,
323
+ w: this.w
324
+ };
325
+ }
326
+ }, N = s, te = o, P = new N().parseFromString("<svg></svg>", "image/svg+xml");
327
+ P.readyState = "complete";
328
+ //#endregion
329
+ //#region src/helpers/bbox.ts
330
+ var F = class {
331
+ get x3() {
332
+ return this._x3 || this.x1;
333
+ }
334
+ get y3() {
335
+ return this._y3 || this.y2;
336
+ }
337
+ get x4() {
338
+ return this._x4 || this.x2;
339
+ }
340
+ get y4() {
341
+ return this._y4 || this.y1;
342
+ }
343
+ constructor(e, t, n, r, i, a, o, s) {
344
+ this.x1 = e, this.y1 = t, this.x2 = n, this.y2 = r, this._x3 = i, this._y3 = a, this._x4 = o, this._y4 = s, this.corners = [
345
+ new M(this.x1, this.y1),
346
+ new M(this.x2, this.y2),
347
+ new M(this.x3, this.y3),
348
+ new M(this.x4, this.y4)
349
+ ];
350
+ }
351
+ transform(e) {
352
+ this.corners = this.corners.map((t) => t.matrixTransform(e)), this.x1 = this.corners[0].x, this.y1 = this.corners[0].y, this.x2 = this.corners[1].x, this.y2 = this.corners[1].y, this._x3 = this.corners[2].x, this._y3 = this.corners[2].y, this._x4 = this.corners[3].x, this._y4 = this.corners[3].y;
353
+ }
354
+ toPointsArray() {
355
+ return this.corners.map((e) => [e.x, e.y]);
356
+ }
357
+ getBBox() {
358
+ let e = Math.min(this.x1, this.x2, this.x3, this.x4), t = Math.min(this.y1, this.y2, this.y3, this.y4), n = Math.max(this.x1, this.x2, this.x3, this.x4) - e, r = Math.max(this.y1, this.y2, this.y3, this.y4) - t;
359
+ return new I(e, t, e + n, t + r);
360
+ }
361
+ }, I = class extends F {
362
+ get x() {
363
+ return this.x1;
364
+ }
365
+ get y() {
366
+ return this.y1;
367
+ }
368
+ get width() {
369
+ return this.x2 - this.x1;
370
+ }
371
+ get height() {
372
+ return this.y2 - this.y1;
373
+ }
374
+ add(e) {
375
+ this.x1 = Math.min(this.x1, e.x1, e.x2, e.x3, e.x4), this.y1 = Math.min(this.y1, e.y1, e.y2, e.y3, e.y4), this.x2 = Math.max(this.x2, e.x1, e.x2, e.x3, e.x4), this.y2 = Math.max(this.y2, e.y1, e.y2, e.y3, e.y4);
376
+ }
377
+ addPoint(e, t) {
378
+ this.x1 = Math.min(this.x1, e), this.y1 = Math.min(this.y1, t), this.x2 = Math.max(this.x2, e), this.y2 = Math.max(this.y2, t);
379
+ }
380
+ serialize() {
381
+ return {
382
+ x: this.x,
383
+ y: this.y,
384
+ width: this.width,
385
+ height: this.height
386
+ };
387
+ }
388
+ }, L = (e) => {
309
389
  for (let t of [
310
390
  "I",
311
391
  "l",
@@ -315,28 +395,24 @@ var D = (e) => e === void 0 || e === "flat" ? { type: "flat" } : e === "curved"
315
395
  if (n && n.name !== ".notdef") return t;
316
396
  }
317
397
  return console.error("No standard character found for fixed height calculation. Using \"I\" as default."), "I";
318
- }, N = 100, P = ({ font: e, boxDimensions: t, physicalSize: n, spacing: r = T }) => {
398
+ }, R = 100, z = ({ font: e, boxDimensions: t, physicalSize: n, spacing: r = T }) => {
319
399
  let i = n;
320
400
  if (i[1] !== t.physicalUnits) throw Error(`Mismatched units between physicalFontSize (${i[1]}) and boxDimensions (${t.physicalUnits})`);
321
- let { outlineWidth: a } = r, o = M(e), s = e.getPath(o, 0, 0, N).getBoundingBox(), c = s.y2 - s.y1;
401
+ let { outlineWidth: a } = r, o = L(e), s = e.getPath(o, 0, 0, R).getBoundingBox(), c = s.y2 - s.y1;
322
402
  if (a > 0) {
323
- let e = N * a;
403
+ let e = R * a;
324
404
  c += e * 2;
325
405
  }
326
406
  let l = c / t.height * t.physicalHeight;
327
- return N * (i[0] / l);
328
- }, F = ({ font: e, text: t, fontSize: n, spacing: r = T }) => {
407
+ return R * (i[0] / l);
408
+ }, B = ({ font: e, text: t, fontSize: n, spacing: r = T }) => {
329
409
  let { outlineWidth: i, letterSpacing: a, letterSpacingOutline: o } = r, s = e.getPath(t, 0, 0, n).getBoundingBox(), c = i ? n * i * 2 : 0, l = i > 0 ? o : a, u = t.length > 1 ? l * n * (t.length - 1) : 0;
330
410
  return {
331
411
  width: s.x2 - s.x1 + c + u,
332
412
  height: s.y2 - s.y1 + c,
333
413
  baseline: s.y1 * -1 + c / 2
334
414
  };
335
- }, I = s, te = o, ne = new I().parseFromString("<svg></svg>", "image/svg+xml");
336
- ne.readyState = "complete";
337
- //#endregion
338
- //#region ../svg-helpers/dist/colours/named-colours.mjs
339
- var re = {
415
+ }, ne = {
340
416
  aliceblue: "#f0f8ff",
341
417
  antiquewhite: "#faebd7",
342
418
  aqua: "#00ffff",
@@ -485,13 +561,13 @@ var re = {
485
561
  whitesmoke: "#f5f5f5",
486
562
  yellow: "#ffff00",
487
563
  yellowgreen: "#9acd32"
488
- }, ie = (e) => {
564
+ }, re = (e) => {
489
565
  let t = Array.from(e), n = !1;
490
566
  return t[0] === "#" && (t.shift(), n = !0), t.length === 3 && (t = t.map((e) => `${e}${e}`)), `${n ? "#" : ""}${t.join("").toLowerCase()}`;
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) => {
567
+ }, V = (e) => Math.max(0, Math.min(255, Math.round(typeof e == "string" ? Number.parseInt(e, 10) : e))).toString(16).padStart(2, "0"), H = (...e) => {
492
568
  let [t, n, r] = Array.isArray(e[0]) ? e[0] : e;
493
- return `#${L(t)}${L(n)}${L(r)}`;
494
- }, ae = (e, t, n) => {
569
+ return `#${V(t)}${V(n)}${V(r)}`;
570
+ }, ie = (e, t, n) => {
495
571
  if (t === 0) {
496
572
  let e = Math.round(n * 255);
497
573
  return [
@@ -506,22 +582,22 @@ var re = {
506
582
  Math.round((c + o) * 255),
507
583
  Math.round((l + o) * 255)
508
584
  ];
509
- }, oe = (e) => /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.test(e), z = (e) => {
585
+ }, ae = (e) => /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.test(e), U = (e) => {
510
586
  let t = e.trim().toLowerCase();
511
- if (t.startsWith("#") || /^[0-9a-f]{3}([0-9a-f]{3})?$/.test(t)) return oe(t) ? ie(t) : void 0;
587
+ if (t.startsWith("#") || /^[0-9a-f]{3}([0-9a-f]{3})?$/.test(t)) return ae(t) ? re(t) : void 0;
512
588
  if (t.startsWith("rgb")) {
513
589
  let e = t.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*[\d.]+\s*)?\)/);
514
- return e ? R(Number.parseInt(e[1], 10), Number.parseInt(e[2], 10), Number.parseInt(e[3], 10)) : void 0;
590
+ return e ? H(Number.parseInt(e[1], 10), Number.parseInt(e[2], 10), Number.parseInt(e[3], 10)) : void 0;
515
591
  }
516
592
  if (t.startsWith("hsl")) {
517
593
  let e = t.match(/hsla?\(\s*(\d+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*(?:,\s*[\d.]+\s*)?\)/);
518
594
  if (!e) return;
519
- let [n, r, i] = ae(Number.parseInt(e[1], 10), Number.parseFloat(e[2]) / 100, Number.parseFloat(e[3]) / 100);
520
- return R(n, r, i);
595
+ let [n, r, i] = ie(Number.parseInt(e[1], 10), Number.parseFloat(e[2]) / 100, Number.parseFloat(e[3]) / 100);
596
+ return H(n, r, i);
521
597
  }
522
- let n = re[t];
598
+ let n = ne[t];
523
599
  if (n) return n;
524
- }, B = {
600
+ }, W = {
525
601
  svg: "svg",
526
602
  circle: "circle",
527
603
  desc: "desc",
@@ -532,98 +608,98 @@ var re = {
532
608
  polygon: "polygon",
533
609
  polyline: "polyline",
534
610
  stop: "stop"
535
- }, V = {
611
+ }, G = {
536
612
  fill: "fill",
537
613
  stroke: "stroke"
538
- }, se = {
614
+ }, oe = {
539
615
  tiling: [
540
- B.circle,
541
- B.ellipse,
542
- B.rect,
543
- B.line,
544
- B.path,
545
- B.polygon,
546
- B.polyline,
547
- B.stop,
548
- `[${V.fill}]`,
549
- `[${V.stroke}]`
616
+ W.circle,
617
+ W.ellipse,
618
+ W.rect,
619
+ W.line,
620
+ W.path,
621
+ W.polygon,
622
+ W.polyline,
623
+ W.stop,
624
+ `[${G.fill}]`,
625
+ `[${G.stroke}]`
550
626
  ],
551
627
  nonTiling: [
552
- B.circle,
553
- B.desc,
554
- B.ellipse,
555
- B.rect,
556
- B.line,
557
- B.path,
558
- B.polygon,
559
- B.polyline,
560
- B.stop,
561
- `[${V.fill}]`,
562
- `[${V.stroke}]`
628
+ W.circle,
629
+ W.desc,
630
+ W.ellipse,
631
+ W.rect,
632
+ W.line,
633
+ W.path,
634
+ W.polygon,
635
+ W.polyline,
636
+ W.stop,
637
+ `[${G.fill}]`,
638
+ `[${G.stroke}]`
563
639
  ]
564
- }, ce = (e) => Array.from(e.querySelectorAll(se.tiling.map((e) => `*:not(clipPath) > ${e}`).join(", "))), le = (e) => {
565
- let t = e.getAttribute(V.stroke);
640
+ }, se = (e) => Array.from(e.querySelectorAll(oe.tiling.map((e) => `*:not(clipPath) > ${e}`).join(", "))), ce = (e) => {
641
+ let t = e.getAttribute(G.stroke);
566
642
  return t === "none" || !t ? !1 : t;
567
- }, H = (e) => {
568
- if (!(e === "none" || e === "transparent" || e.startsWith("url("))) return z(e);
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);
643
+ }, K = (e) => {
644
+ if (!(e === "none" || e === "transparent" || e.startsWith("url("))) return U(e);
645
+ }, le = (e) => {
646
+ let t = se(e).reduce((e, t) => {
647
+ let n = t.getAttribute("stop-color"), r = t.getAttribute(G.fill) || "#000", i = ce(t);
572
648
  if (r && !n) {
573
- let t = H(r);
649
+ let t = K(r);
574
650
  t && e.add(t);
575
651
  }
576
652
  if (n) {
577
- let t = H(n);
653
+ let t = K(n);
578
654
  t && e.add(t);
579
655
  }
580
656
  if (i) {
581
- let t = H(i);
657
+ let t = K(i);
582
658
  t && e.add(t);
583
659
  }
584
660
  return e;
585
661
  }, /* @__PURE__ */ new Set());
586
662
  return Array.from(t);
587
- }, de = (e) => {
588
- let t = new I().parseFromString(e, "image/svg+xml").querySelector("svg");
589
- return t ? ue(t) : [];
663
+ }, ue = (e) => {
664
+ let t = new N().parseFromString(e, "image/svg+xml").querySelector("svg");
665
+ return t ? le(t) : [];
590
666
  };
591
667
  //#endregion
592
668
  //#region src/glyph/svg-glyph-converter.ts
593
- function U(e) {
669
+ function q(e) {
594
670
  let t = e.trim(), n = t.startsWith("<svg") || t.startsWith("<?xml"), r = n ? t : `<svg>${t}</svg>`;
595
671
  return {
596
- doc: new I().parseFromString(r, "image/svg+xml"),
672
+ doc: new N().parseFromString(r, "image/svg+xml"),
597
673
  wasWrapped: !n
598
674
  };
599
675
  }
600
- function W(e, t) {
676
+ function J(e, t) {
601
677
  let n = e.querySelector("svg");
602
678
  return n ? t ? n.innerHTML : n.outerHTML : "";
603
679
  }
604
- function fe(e) {
680
+ function de(e) {
605
681
  let { svgGlyphs: t } = e;
606
682
  if (!t || t.size === 0) return [];
607
683
  let n = /* @__PURE__ */ new Set();
608
- for (let [, e] of t) for (let t of de(e.svg)) n.add(t);
684
+ for (let [, e] of t) for (let t of ue(e.svg)) n.add(t);
609
685
  return Array.from(n);
610
686
  }
611
- function pe(e) {
687
+ function fe(e) {
612
688
  return !!e && e !== "none" && e !== "transparent" && !e.startsWith("url(");
613
689
  }
614
- function me(e) {
615
- let t = new I().parseFromString(e, "image/svg+xml").querySelector("svg");
690
+ function pe(e) {
691
+ let t = new N().parseFromString(e, "image/svg+xml").querySelector("svg");
616
692
  return t ? t.innerHTML.trim() : "";
617
693
  }
618
- var he = [
694
+ var me = [
619
695
  "fill",
620
696
  "stroke",
621
697
  "clip-path",
622
698
  "mask",
623
699
  "filter"
624
700
  ];
625
- function ge(e, t) {
626
- let { doc: n, wasWrapped: r } = U(e), i = /* @__PURE__ */ new Map();
701
+ function he(e, t) {
702
+ let { doc: n, wasWrapped: r } = q(e), i = /* @__PURE__ */ new Map();
627
703
  for (let e of n.querySelectorAll("[id]")) {
628
704
  let n = e.getAttribute("id");
629
705
  if (!n) continue;
@@ -631,7 +707,7 @@ function ge(e, t) {
631
707
  i.set(n, r), e.setAttribute("id", r);
632
708
  }
633
709
  if (i.size === 0) return e;
634
- for (let e of he) for (let t of n.querySelectorAll(`[${e}]`)) {
710
+ for (let e of me) for (let t of n.querySelectorAll(`[${e}]`)) {
635
711
  let n = t.getAttribute(e);
636
712
  if (n) {
637
713
  let r = n.replace(/url\(#([^)]+)\)/g, (e, t) => {
@@ -648,13 +724,13 @@ function ge(e, t) {
648
724
  a && e.setAttribute(t, `#${a}`);
649
725
  }
650
726
  }
651
- return W(n, r);
727
+ return J(n, r);
652
728
  }
653
- var _e = [
729
+ var ge = [
654
730
  "fill",
655
731
  "stroke",
656
732
  "stop-color"
657
- ], ve = [
733
+ ], _e = [
658
734
  "path",
659
735
  "rect",
660
736
  "circle",
@@ -663,30 +739,30 @@ var _e = [
663
739
  "polyline",
664
740
  "text"
665
741
  ];
666
- function ye(e, t) {
667
- let { doc: n, wasWrapped: r } = U(e), i = {};
668
- for (let [e, n] of Object.entries(t)) i[z(e) ?? e.toLowerCase()] = n;
669
- for (let e of _e) for (let t of n.querySelectorAll(`[${e}]`)) {
742
+ function ve(e, t) {
743
+ let { doc: n, wasWrapped: r } = q(e), i = {};
744
+ for (let [e, n] of Object.entries(t)) i[U(e) ?? e.toLowerCase()] = n;
745
+ for (let e of ge) for (let t of n.querySelectorAll(`[${e}]`)) {
670
746
  let n = t.getAttribute(e);
671
- if (!n || !pe(n)) continue;
672
- let r = z(n), a = r ? i[r] : void 0;
747
+ if (!n || !fe(n)) continue;
748
+ let r = U(n), a = r ? i[r] : void 0;
673
749
  a && t.setAttribute(e, a.hex);
674
750
  }
675
751
  let a = i["#000000"];
676
752
  if (a) {
677
- let e = ve.map((e) => `${e}:not([fill])`).join(", ");
753
+ let e = _e.map((e) => `${e}:not([fill])`).join(", ");
678
754
  for (let t of n.querySelectorAll(e)) t.setAttribute("fill", a.hex);
679
755
  }
680
- return W(n, r);
756
+ return J(n, r);
681
757
  }
682
758
  //#endregion
683
759
  //#region src/helpers/xml.ts
684
- function be(e) {
760
+ function ye(e) {
685
761
  return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&apos;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
686
762
  }
687
763
  //#endregion
688
764
  //#region src/rendering/index.ts
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 }) => {
765
+ var Y = (e, t, n) => e / n * t, be = ({ font: e, baselinePath: t, text: n, fontSize: r, spacing: i = T, horizontalAlignment: a = "centre", colourMap: o }) => {
690
766
  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;
691
767
  a === "distributed" && (y = n.length === 1 ? 0 : (p - _) / (n.length - 1));
692
768
  let b = y * (n.length - 1), x = _ + b, S = 0 - g;
@@ -695,7 +771,7 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
695
771
  for (let t = 0; t < m.length; t++) {
696
772
  let i = m[t], a = i.getBoundingBox(), s = e.charToGlyph(n[t]), { advanceWidth: c } = s;
697
773
  if (!c) throw Error(`No advance width for character: ${n[t]} in font ${e.names.fontFamily}`);
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;
774
+ let { x1: l, x2: u } = s.getBoundingBox(), f = Y(c, r, e.unitsPerEm), h = Y(u - l, r, e.unitsPerEm), g = S + a.x1;
699
775
  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)})`);
700
776
  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
777
  M = M.translate(A, j);
@@ -710,8 +786,8 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
710
786
  if (e.svgGlyphs) {
711
787
  let n = e.svgGlyphs.get(s.index);
712
788
  if (n) {
713
- let e = me(n.svg);
714
- e = ge(e, `g${s.index}-${t}`), o && (e = ye(e, o)), F = {
789
+ let e = pe(n.svg);
790
+ e = he(e, `g${s.index}-${t}`), o && (e = ve(e, o)), F = {
715
791
  content: e,
716
792
  viewBox: n.viewbox,
717
793
  x: a.x1,
@@ -727,7 +803,7 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
727
803
  matrix: M,
728
804
  attributes: {
729
805
  d: P,
730
- "data-character": be(n[t]),
806
+ "data-character": ye(n[t]),
731
807
  transform: N
732
808
  },
733
809
  glyphData: {
@@ -738,93 +814,146 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
738
814
  });
739
815
  }
740
816
  return C;
741
- }, K = { hex: "#FFFFFF" }, q = (e, t) => {
742
- let n = `data-${e}-colour-url`, r = [`${e}="${t.hex}"`];
743
- return t.reference && r.push(`${n}="${t.reference}"`), r.join(" ");
744
- }, J = (e, t) => {
745
- let { attributes: n, svgGlyph: r } = e;
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 }) => {
748
- let { width: o, height: s } = e, { outlineWidth: c } = n, l = c > 0 && r > 0, u;
749
- if (l) {
750
- let e = r * c * 2;
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 ");
753
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${o}" height="${s}" viewBox="0 0 ${o} ${s}">${u ? `\n ${u}\n` : ""}</svg>`;
754
- }, Y = (e) => {
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;
756
- if (p <= 0 || m <= 0) throw Error(`boxDimensions width and height must be positive (got ${p}x${m})`);
757
- if (h <= 0 || g <= 0) throw Error(`boxDimensions physicalWidth and physicalHeight must be positive (got ${h}x${g})`);
758
- if (r[0] <= 0) throw Error(`physicalSize height must be positive (got ${r[0]})`);
759
- let _ = i ?? P({
760
- font: n,
761
- boxDimensions: a,
762
- physicalSize: r,
817
+ }, X = (e) => {
818
+ let { font: t, text: n, boxDimensions: r, physicalSize: i, fontSize: a, spacing: o = T, baseline: s = "flat", horizontalAlignment: c = "left", verticalAlignment: l = "centre", colourMap: u } = e, { width: d, height: f, physicalWidth: p, physicalHeight: m } = r;
819
+ if (d <= 0 || f <= 0) throw Error(`boxDimensions width and height must be positive (got ${d}x${f})`);
820
+ if (p <= 0 || m <= 0) throw Error(`boxDimensions physicalWidth and physicalHeight must be positive (got ${p}x${m})`);
821
+ if (i[0] <= 0) throw Error(`physicalSize height must be positive (got ${i[0]})`);
822
+ let h = a ?? z({
823
+ font: t,
824
+ boxDimensions: r,
825
+ physicalSize: i,
763
826
  spacing: o
764
- }), v = D(c), y = t.split("\n").filter((e) => e.length > 0);
765
- y.length || (y = [""]), (v.type === "curved" || v.type === "custom") && (y = [y.join("")]);
766
- let b = y.map((e) => F({
767
- font: n,
827
+ }), g = D(s), _ = n.split("\n").filter((e) => e.length > 0);
828
+ _.length || (_ = [""]), (g.type === "curved" || g.type === "custom") && (_ = [_.join("")]);
829
+ let v = _.map((e) => B({
830
+ font: t,
768
831
  text: e,
769
- fontSize: _,
832
+ fontSize: h,
770
833
  spacing: o
771
- })), x = Math.max(...b.map((e) => e.baseline)), S = x + Math.max(...b.map((e) => e.height - e.baseline)), w = y.length === 1 ? S : S + S * (y.length - 1) * C, E = [];
772
- for (let e = 0; e < y.length; e++) {
773
- let t;
774
- switch (v.type) {
834
+ })), y = Math.max(...v.map((e) => e.baseline)), b = y + Math.max(...v.map((e) => e.height - e.baseline)), x = _.length === 1 ? b : b + b * (_.length - 1) * C, S = [];
835
+ for (let e = 0; e < _.length; e++) {
836
+ let n;
837
+ switch (g.type) {
775
838
  case "custom":
776
- O(v.path), t = v.path;
839
+ O(g.path), n = g.path;
777
840
  break;
778
841
  case "curved": {
779
- let e = F({
780
- font: n,
781
- text: M(n),
782
- fontSize: _,
842
+ let e = B({
843
+ font: t,
844
+ text: L(t),
845
+ fontSize: h,
783
846
  spacing: o
784
847
  });
785
- t = j({
786
- boxDimensions: a,
848
+ n = j({
849
+ boxDimensions: r,
787
850
  baseline: e.baseline,
788
851
  textHeight: e.height,
789
- verticalAlignment: s
852
+ verticalAlignment: l
790
853
  });
791
854
  break;
792
855
  }
793
- case "flat": t = k({
794
- boxDimensions: a,
795
- totalTextHeight: w,
796
- baseline: x,
797
- lineHeight: S,
798
- verticalAlignment: s,
856
+ case "flat": n = k({
857
+ boxDimensions: r,
858
+ totalTextHeight: x,
859
+ baseline: y,
860
+ lineHeight: b,
861
+ verticalAlignment: l,
799
862
  lineNumber: e
800
863
  });
801
864
  }
802
- let r = xe({
803
- font: n,
804
- baselinePath: t,
805
- text: y[e],
806
- fontSize: _,
865
+ S.push(...be({
866
+ font: t,
867
+ baselinePath: n,
868
+ text: _[e],
869
+ fontSize: h,
807
870
  spacing: o,
808
- horizontalAlignment: l,
809
- colourMap: f
810
- });
811
- E.push(...r);
871
+ horizontalAlignment: c,
872
+ colourMap: u
873
+ }));
874
+ }
875
+ return {
876
+ fontSize: h,
877
+ lines: _,
878
+ paths: S,
879
+ spacing: o,
880
+ tallestHeight: b,
881
+ totalHeight: x,
882
+ maxBaseline: y
883
+ };
884
+ }, xe = (e) => {
885
+ let { font: t, boxDimensions: n, spacing: r = T } = e, { fontSize: i, paths: a, lines: o } = X(e), s = null;
886
+ for (let e of a) {
887
+ let { x1: t, y1: n, x2: r, y2: i } = e.glyphData.bbox, a = new I(t, n, r, i);
888
+ a.transform(e.matrix), s ? s.add(a) : s = a.getBBox();
889
+ }
890
+ if (s && r.outlineWidth > 0) {
891
+ let e = i * r.outlineWidth;
892
+ s = new I(s.x1 - e, s.y1 - e, s.x2 + e, s.y2 + e);
812
893
  }
813
- return Se({
814
- boxDimensions: a,
815
- paths: E,
894
+ let c = s ?? new I(0, 0, 0, 0), l = (e) => e / n.width * n.physicalWidth, u = (e) => e / n.height * n.physicalHeight, d = B({
895
+ font: t,
896
+ text: L(t),
897
+ fontSize: i,
898
+ spacing: r
899
+ });
900
+ return {
901
+ fontSize: i,
902
+ bbox: {
903
+ x: c.x,
904
+ y: c.y,
905
+ width: c.width,
906
+ height: c.height
907
+ },
908
+ physicalWidth: l(c.width),
909
+ physicalHeight: u(c.height),
910
+ physicalUnits: n.physicalUnits,
911
+ physicalCapHeight: u(d.height),
912
+ lines: o.map((e) => {
913
+ let n = B({
914
+ font: t,
915
+ text: e,
916
+ fontSize: i,
917
+ spacing: r
918
+ });
919
+ return {
920
+ text: e,
921
+ width: n.width,
922
+ height: n.height,
923
+ baseline: n.baseline
924
+ };
925
+ })
926
+ };
927
+ }, Se = { hex: "#FFFFFF" }, Z = (e, t) => {
928
+ let n = `data-${e}-colour-url`, r = [`${e}="${t.hex}"`];
929
+ return t.reference && r.push(`${n}="${t.reference}"`), r.join(" ");
930
+ }, Ce = (e, t) => {
931
+ let { attributes: n, svgGlyph: r } = e;
932
+ 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}" ${Z("fill", t)} transform="${n.transform}" data-character="${n["data-character"]}"/>`;
933
+ }, we = ({ boxDimensions: e, paths: t, spacing: n = T, fontSize: r = 0, fillColour: i = Se, strokeColour: a = Se }) => {
934
+ let { width: o, height: s } = e, { outlineWidth: c } = n, l = c > 0 && r > 0, u;
935
+ if (l) {
936
+ let e = r * c * 2;
937
+ u = `${t.filter((e) => !e.svgGlyph).map(({ attributes: t }) => `<path d="${t.d}" ${Z("fill", a)} ${Z("stroke", a)} stroke-width="${e}" stroke-linejoin="round" transform="${t.transform}" data-character="${t["data-character"]}"/>`).join("\n ")}\n ${t.map((e) => Ce(e, i)).join("\n ")}`;
938
+ } else u = t.map((e) => Ce(e, i)).join("\n ");
939
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${o}" height="${s}" viewBox="0 0 ${o} ${s}">${u ? `\n ${u}\n` : ""}</svg>`;
940
+ }, Q = (e) => {
941
+ let { boxDimensions: t, fillColour: n = { hex: "#FFFFFF" }, strokeColour: r = { hex: "#FFFFFF" } } = e, { fontSize: i, paths: a, spacing: o } = X(e);
942
+ return we({
943
+ boxDimensions: t,
944
+ paths: a,
816
945
  spacing: o,
817
- fontSize: _,
818
- fillColour: u,
819
- strokeColour: d
946
+ fontSize: i,
947
+ fillColour: n,
948
+ strokeColour: r
820
949
  });
821
- }, X = 100, Ce = (e) => {
950
+ }, Te = 100, Ee = (e) => {
822
951
  let t = e.split("\n").filter((e) => e.length > 0);
823
952
  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({
953
+ }, De = (e) => e.split("\n").filter((e) => e.length > 0).join(""), Oe = (e, t, n, r, i, a) => {
954
+ let o = B({
826
955
  font: e,
827
- text: M(e),
956
+ text: L(e),
828
957
  fontSize: n,
829
958
  spacing: r
830
959
  }), s = {
@@ -832,7 +961,7 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
832
961
  baseline: o.baseline,
833
962
  textHeight: o.height,
834
963
  verticalAlignment: a
835
- }, l = new c(j(s)).getTotalLength(), { curveTop: u, curveBottom: d } = A(s), f = F({
964
+ }, l = new c(j(s)).getTotalLength(), { curveTop: u, curveBottom: d } = A(s), f = B({
836
965
  font: e,
837
966
  text: t,
838
967
  fontSize: n,
@@ -842,36 +971,36 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
842
971
  width: f.width <= l,
843
972
  height: p >= 0 && m <= i.height
844
973
  };
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);
974
+ }, $ = (e) => e.width && e.height, ke = (e) => e.width ? "height" : "width", Ae = .01, je = 60, Me = ({ font: e, text: t, boxDimensions: n, spacing: r, verticalAlignment: i, minFontSize: a, maxFontSize: o }) => {
975
+ let s = De(t);
847
976
  if (!s.length) return {
848
977
  fontSize: o,
849
978
  fits: !0,
850
979
  boundBy: "requestedSize"
851
980
  };
852
- let c = (t) => Te(e, s, t, r, n, i), l = c(a);
853
- if (!Z(l)) return {
981
+ let c = (t) => Oe(e, s, t, r, n, i), l = c(a);
982
+ if (!$(l)) return {
854
983
  fontSize: a,
855
984
  fits: !1,
856
- boundBy: Q(l)
985
+ boundBy: ke(l)
857
986
  };
858
- if (Z(c(o))) return {
987
+ if ($(c(o))) return {
859
988
  fontSize: o,
860
989
  fits: !0,
861
990
  boundBy: "requestedSize"
862
991
  };
863
992
  let u = a, d = o, f = 0;
864
- for (; d - u > Ee && f < De;) {
993
+ for (; d - u > Ae && f < je;) {
865
994
  let e = (u + d) / 2;
866
- Z(c(e)) ? u = e : d = e, f++;
995
+ $(c(e)) ? u = e : d = e, f++;
867
996
  }
868
997
  return {
869
998
  fontSize: u,
870
999
  fits: !0,
871
- boundBy: Q(c(d))
1000
+ boundBy: ke(c(d))
872
1001
  };
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({
1002
+ }, Ne = (e) => {
1003
+ 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 : z({
875
1004
  font: t,
876
1005
  boxDimensions: r,
877
1006
  physicalSize: i.physicalSize,
@@ -883,7 +1012,7 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
883
1012
  boundBy: "requestedSize"
884
1013
  };
885
1014
  let u = D(o);
886
- if (u.type === "curved") return Oe({
1015
+ if (u.type === "curved") return Me({
887
1016
  font: t,
888
1017
  text: n,
889
1018
  boxDimensions: r,
@@ -892,14 +1021,14 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
892
1021
  minFontSize: i.mode === "fitToBox" ? i.minFontSize : l,
893
1022
  maxFontSize: l
894
1023
  });
895
- let d = Ce(n);
1024
+ let d = Ee(n);
896
1025
  u.type === "custom" && (d = [d.join("")]);
897
- let f = d.map((e) => F({
1026
+ let f = d.map((e) => B({
898
1027
  font: t,
899
1028
  text: e,
900
- fontSize: X,
1029
+ fontSize: Te,
901
1030
  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, _);
1031
+ })), 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 = Te * Math.min(g, _);
903
1032
  return i.mode === "fitToBox" ? y < i.minFontSize ? {
904
1033
  fontSize: i.minFontSize,
905
1034
  fits: !1,
@@ -921,10 +1050,10 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
921
1050
  fits: !1,
922
1051
  boundBy: v
923
1052
  };
924
- }, ke = (e) => {
1053
+ }, Pe = (e) => {
925
1054
  let t = e.text, n = t, r = 0, i = 0;
926
1055
  for (;;) {
927
- let a = $({
1056
+ let a = Ne({
928
1057
  ...e,
929
1058
  text: n
930
1059
  });
@@ -942,15 +1071,15 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
942
1071
  i += n.length - e.length, n = e;
943
1072
  }
944
1073
  }
945
- }, Ae = async (e) => {
1074
+ }, Fe = async (e) => {
946
1075
  let { fontUrl: t, fontSizeFallback: n, ...r } = e, i = await x(t, !!r.colourMap);
947
1076
  try {
948
- return Y({
1077
+ return Q({
949
1078
  ...r,
950
1079
  font: i
951
1080
  });
952
1081
  } catch (e) {
953
- if (n != null && e instanceof Error && e.message.startsWith("TOO_WIDE")) return Y({
1082
+ if (n != null && e instanceof Error && e.message.startsWith("TOO_WIDE")) return Q({
954
1083
  ...r,
955
1084
  font: i,
956
1085
  fontSize: n
@@ -959,4 +1088,4 @@ var G = (e, t, n) => e / n * t, xe = ({ font: e, baselinePath: t, text: n, fontS
959
1088
  }
960
1089
  };
961
1090
  //#endregion
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 };
1091
+ export { S as DEFAULT_OUTLINE_FACTOR, T as DEFAULT_SPACING, C as LINE_HEIGHT, Pe as fitAndTruncateTextToBox, j as generateCurvedBaseline, k as generateFlatBaseline, p as getFontCache, de as getFontColours, z as getFontSizeFromPhysicalSize, Ne as getFontSizeToFitBox, Fe as getRenderedText, B as getTextMetricsAtFontSize, X as layoutText, x as loadFont, xe as measureText, D as normaliseBaselineOption, Q as renderText, O as validateCustomBaselinePath };