@weasel-js/font 1.2.0 → 1.3.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.
@@ -475,6 +475,291 @@ function _resetDynamicFontsForTests() {
475
475
  rasterizer = null;
476
476
  }
477
477
 
478
+ // src/outline/OutlineFace.ts
479
+ var OUTLINE_PRECISION = 5;
480
+
481
+ // src/outline/sfnt.ts
482
+ var SFNT_HEADER_BYTES = 12;
483
+ var TABLE_RECORD_BYTES = 16;
484
+ function tagAt(view, offset) {
485
+ return String.fromCharCode(
486
+ view.getUint8(offset),
487
+ view.getUint8(offset + 1),
488
+ view.getUint8(offset + 2),
489
+ view.getUint8(offset + 3)
490
+ );
491
+ }
492
+ function isFontCollection(bytes) {
493
+ if (bytes.byteLength < 4) return false;
494
+ return tagAt(new DataView(bytes), 0) === "ttcf";
495
+ }
496
+ var FONT_SIGNATURES = /* @__PURE__ */ new Set([
497
+ "\0\0\0",
498
+ "true",
499
+ "typ1",
500
+ "OTTO",
501
+ "ttcf",
502
+ "wOFF",
503
+ "wOF2"
504
+ ]);
505
+ var RESOURCE_HEADER_BYTES = 16;
506
+ function isDataForkFont(bytes) {
507
+ if (bytes.byteLength < RESOURCE_HEADER_BYTES) return false;
508
+ const view = new DataView(bytes);
509
+ if (FONT_SIGNATURES.has(tagAt(view, 0))) return false;
510
+ const dataOffset = view.getUint32(0);
511
+ const mapOffset = view.getUint32(4);
512
+ const dataLength = view.getUint32(8);
513
+ const mapLength = view.getUint32(12);
514
+ return dataOffset >= RESOURCE_HEADER_BYTES && dataOffset + dataLength === mapOffset && mapOffset + mapLength <= bytes.byteLength;
515
+ }
516
+ function readTableDirectory(view, dirOffset) {
517
+ const numTables = view.getUint16(dirOffset + 4);
518
+ const records = [];
519
+ for (let i = 0; i < numTables; i++) {
520
+ const at = dirOffset + SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;
521
+ records.push({
522
+ tag: tagAt(view, at),
523
+ checksum: view.getUint32(at + 4),
524
+ offset: view.getUint32(at + 8),
525
+ length: view.getUint32(at + 12)
526
+ });
527
+ }
528
+ return records;
529
+ }
530
+ function postScriptNameAt(view, records) {
531
+ const name = records.find((r) => r.tag === "name");
532
+ if (!name) return null;
533
+ const base = name.offset;
534
+ const count = view.getUint16(base + 2);
535
+ const stringOffset = view.getUint16(base + 4);
536
+ for (let i = 0; i < count; i++) {
537
+ const rec = base + 6 + i * 12;
538
+ if (view.getUint16(rec + 6) !== 6) continue;
539
+ const length = view.getUint16(rec + 8);
540
+ const offset = view.getUint16(rec + 10);
541
+ let out = "";
542
+ for (let b = 0; b < length; b++) {
543
+ const code = view.getUint8(base + stringOffset + offset + b);
544
+ if (code !== 0) out += String.fromCharCode(code);
545
+ }
546
+ if (out.length > 0) return out;
547
+ }
548
+ return null;
549
+ }
550
+ function extractFont(source, view, dirOffset) {
551
+ const records = readTableDirectory(view, dirOffset);
552
+ const padded = (n) => n + 3 & -4;
553
+ let total = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;
554
+ for (const r of records) total += padded(r.length);
555
+ const out = new ArrayBuffer(total);
556
+ const dst = new DataView(out);
557
+ const dstBytes = new Uint8Array(out);
558
+ const srcBytes = new Uint8Array(source);
559
+ dst.setUint32(0, view.getUint32(dirOffset));
560
+ dst.setUint16(4, records.length);
561
+ const entrySelector = Math.floor(Math.log2(records.length));
562
+ const searchRange = 2 ** entrySelector * 16;
563
+ dst.setUint16(6, searchRange);
564
+ dst.setUint16(8, entrySelector);
565
+ dst.setUint16(10, records.length * 16 - searchRange);
566
+ let cursor = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;
567
+ records.forEach((r, i) => {
568
+ const at = SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;
569
+ for (let b = 0; b < 4; b++) dst.setUint8(at + b, r.tag.charCodeAt(b));
570
+ dst.setUint32(at + 4, r.checksum);
571
+ dst.setUint32(at + 8, cursor);
572
+ dst.setUint32(at + 12, r.length);
573
+ dstBytes.set(srcBytes.subarray(r.offset, r.offset + r.length), cursor);
574
+ cursor += padded(r.length);
575
+ });
576
+ return out;
577
+ }
578
+ function sfntFromCollection(bytes, postScriptName) {
579
+ if (isDataForkFont(bytes)) {
580
+ throw new Error(
581
+ "Datafork TrueType (.dfont) is not supported \u2014 the outline tier reads sfnt tables and a .dfont holds them inside a Macintosh resource map."
582
+ );
583
+ }
584
+ if (!isFontCollection(bytes)) return { bytes, matched: true };
585
+ const view = new DataView(bytes);
586
+ const numFonts = view.getUint32(8);
587
+ if (numFonts === 0) throw new Error("font collection contains no fonts");
588
+ const offsets = [];
589
+ for (let i = 0; i < numFonts; i++) offsets.push(view.getUint32(12 + i * 4));
590
+ if (postScriptName) {
591
+ for (const dirOffset of offsets) {
592
+ const records = readTableDirectory(view, dirOffset);
593
+ if (postScriptNameAt(view, records) === postScriptName) {
594
+ return { bytes: extractFont(bytes, view, dirOffset), matched: true };
595
+ }
596
+ }
597
+ }
598
+ return { bytes: extractFont(bytes, view, offsets[0]), matched: !postScriptName };
599
+ }
600
+
601
+ // src/outline/opentypeParser.ts
602
+ var modulePromise = null;
603
+ function loadOpenType() {
604
+ modulePromise ??= import('opentype.js');
605
+ return modulePromise;
606
+ }
607
+ function parserOf(ns) {
608
+ const interop = ns;
609
+ return interop.default?.parse ?? ns.parse;
610
+ }
611
+ function faceFor(font) {
612
+ const upem = font.unitsPerEm;
613
+ return {
614
+ unitsPerEm: upem,
615
+ ascender: font.ascender / upem,
616
+ advanceOf(cp) {
617
+ const index = font.charToGlyphIndex(String.fromCodePoint(cp));
618
+ if (!index) return null;
619
+ return (font.glyphs.get(index).advanceWidth ?? 0) / upem;
620
+ },
621
+ kernOf(left, right) {
622
+ const l = font.charToGlyphIndex(String.fromCodePoint(left));
623
+ const r = font.charToGlyphIndex(String.fromCodePoint(right));
624
+ if (!l || !r) return 0;
625
+ return font.getKerningValue(font.glyphs.get(l), font.glyphs.get(r)) / upem;
626
+ },
627
+ glyphD(cp) {
628
+ const index = font.charToGlyphIndex(String.fromCodePoint(cp));
629
+ if (!index) return null;
630
+ const d = font.glyphs.get(index).getPath(0, 0, 1).toPathData(OUTLINE_PRECISION);
631
+ return d.length > 0 ? d : null;
632
+ }
633
+ };
634
+ }
635
+ function createOpenTypeParser(postScriptName) {
636
+ return async (bytes) => {
637
+ const parse = parserOf(await loadOpenType());
638
+ const { bytes: single } = sfntFromCollection(bytes, postScriptName);
639
+ return faceFor(parse(single));
640
+ };
641
+ }
642
+ var openTypeParser = createOpenTypeParser();
643
+
644
+ // src/outline/outlineRegistry.ts
645
+ var slots = /* @__PURE__ */ new Map();
646
+ function slotKey(family, weight, style) {
647
+ return `${family}|${weight}|${style}`;
648
+ }
649
+ function normalize(v) {
650
+ return { weight: v.weight ?? 400, style: v.style ?? "normal" };
651
+ }
652
+ function registerFontOutlines(family, variant, source, opts = {}) {
653
+ const { weight, style } = normalize(variant);
654
+ slots.set(slotKey(family, weight, style), {
655
+ family,
656
+ weight,
657
+ style,
658
+ source,
659
+ parser: opts.parser ?? openTypeParser,
660
+ status: "idle",
661
+ face: null,
662
+ glyphs: /* @__PURE__ */ new Map()
663
+ });
664
+ notifyGlyphReady();
665
+ }
666
+ function unregisterFontOutlines(family, variant = {}) {
667
+ const { weight, style } = normalize(variant);
668
+ if (slots.delete(slotKey(family, weight, style))) notifyGlyphReady();
669
+ }
670
+ function hasFontOutlines(family, weight = 400, style = "normal") {
671
+ return slots.has(slotKey(family, weight, style));
672
+ }
673
+ function outlineStatus(family, weight = 400, style = "normal") {
674
+ return slots.get(slotKey(family, weight, style))?.status ?? null;
675
+ }
676
+ function listFontOutlines() {
677
+ return [...slots.values()].map(({ family, weight, style, status }) => ({ family, weight, style, status })).sort((a, b) => a.family.localeCompare(b.family) || a.weight - b.weight || a.style.localeCompare(b.style));
678
+ }
679
+ function closeContours(d) {
680
+ let out = "";
681
+ let start = 0;
682
+ for (let i = 1; i < d.length; i++) {
683
+ const c = d[i];
684
+ if (c !== "M" && c !== "m") continue;
685
+ out += closeOne(d.slice(start, i));
686
+ start = i;
687
+ }
688
+ return out + closeOne(d.slice(start));
689
+ }
690
+ function closeOne(contour) {
691
+ const trimmed = contour.trimEnd();
692
+ if (trimmed.length === 0) return "";
693
+ const last = trimmed[trimmed.length - 1];
694
+ return last === "Z" || last === "z" ? trimmed : `${trimmed}Z`;
695
+ }
696
+ function glyphOutline(family, weight, style, cp) {
697
+ const slot = slots.get(slotKey(family, weight, style));
698
+ if (!slot) return null;
699
+ if (slot.status === "idle") {
700
+ void beginLoad(slot);
701
+ return null;
702
+ }
703
+ if (slot.status !== "ready") return null;
704
+ const cached = slot.glyphs.get(cp);
705
+ if (cached !== void 0) return cached;
706
+ let d = null;
707
+ try {
708
+ const raw = slot.face.glyphD(cp);
709
+ d = raw === null ? null : closeContours(raw);
710
+ } catch (err) {
711
+ warnOnce(
712
+ `glyph|${slotKey(family, weight, style)}`,
713
+ `weasel: outline face "${family}" (${weight}/${style}) could not produce a glyph for U+${cp.toString(16).toUpperCase().padStart(4, "0")} \u2014 ${err instanceof Error ? err.message : String(err)}. Falling back to the SDF tier.`
714
+ );
715
+ }
716
+ slot.glyphs.set(cp, d);
717
+ return d;
718
+ }
719
+ function outlineMetrics(family, weight, style) {
720
+ const slot = slots.get(slotKey(family, weight, style));
721
+ if (!slot) return null;
722
+ if (slot.status === "idle") {
723
+ void beginLoad(slot);
724
+ return null;
725
+ }
726
+ return slot.status === "ready" ? slot.face : null;
727
+ }
728
+ async function beginLoad(slot) {
729
+ slot.status = "loading";
730
+ try {
731
+ slot.face = await slot.parser(await readSource(slot.source));
732
+ slot.status = "ready";
733
+ notifyGlyphReady();
734
+ } catch (err) {
735
+ slot.status = "failed";
736
+ warnOnce(
737
+ `load|${slotKey(slot.family, slot.weight, slot.style)}`,
738
+ `weasel registerFontOutlines("${slot.family}" ${slot.weight}/${slot.style}): ${err instanceof Error ? err.message : String(err)}. Large text in this face keeps rendering from the SDF tier.`
739
+ );
740
+ }
741
+ }
742
+ async function readSource(source) {
743
+ const resolved = typeof source === "function" ? await source() : source;
744
+ if (typeof resolved === "string") {
745
+ const res = await fetch(resolved);
746
+ if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${resolved}`);
747
+ return res.arrayBuffer();
748
+ }
749
+ if (resolved instanceof ArrayBuffer) return resolved;
750
+ return resolved.arrayBuffer();
751
+ }
752
+ var warned = /* @__PURE__ */ new Set();
753
+ function warnOnce(key, message) {
754
+ if (warned.has(key)) return;
755
+ warned.add(key);
756
+ console.warn(message);
757
+ }
758
+ function _resetFontOutlinesForTests() {
759
+ slots = /* @__PURE__ */ new Map();
760
+ warned.clear();
761
+ }
762
+
478
763
  // src/registerFont.ts
479
764
  var registry = /* @__PURE__ */ new Map();
480
765
  function variantKey(weight, style) {
@@ -553,10 +838,20 @@ function missResolveResult(family, weight, style, suppressWarn = false) {
553
838
  if (isExplicitCanvasFont(family)) {
554
839
  return {
555
840
  entry: null,
556
- dynamicFace: getDynamicFace(family, weight, style),
841
+ dynamicFace: getDynamicFace(family, weight, style),
842
+ resolved: { family, weight, style },
843
+ synthetic: { bold: false, italic: false },
844
+ source: "canvas"
845
+ };
846
+ }
847
+ const face = outlineMetrics(family, weight, style === "italic" ? "italic" : "normal");
848
+ if (face) {
849
+ return {
850
+ entry: null,
851
+ outlineFace: face,
557
852
  resolved: { family, weight, style },
558
853
  synthetic: { bold: false, italic: false },
559
- source: "canvas"
854
+ source: "outline"
560
855
  };
561
856
  }
562
857
  const policy2 = getFontFallbackPolicy();
@@ -745,264 +1040,6 @@ function resolveFontVariantInternal(family, weight, style, suppressWarn) {
745
1040
  return missResolveResult(family, weight, style, suppressWarn);
746
1041
  }
747
1042
 
748
- // src/outline/OutlineFace.ts
749
- var OUTLINE_PRECISION = 5;
750
-
751
- // src/outline/sfnt.ts
752
- var SFNT_HEADER_BYTES = 12;
753
- var TABLE_RECORD_BYTES = 16;
754
- function tagAt(view, offset) {
755
- return String.fromCharCode(
756
- view.getUint8(offset),
757
- view.getUint8(offset + 1),
758
- view.getUint8(offset + 2),
759
- view.getUint8(offset + 3)
760
- );
761
- }
762
- function isFontCollection(bytes) {
763
- if (bytes.byteLength < 4) return false;
764
- return tagAt(new DataView(bytes), 0) === "ttcf";
765
- }
766
- var FONT_SIGNATURES = /* @__PURE__ */ new Set([
767
- "\0\0\0",
768
- "true",
769
- "typ1",
770
- "OTTO",
771
- "ttcf",
772
- "wOFF",
773
- "wOF2"
774
- ]);
775
- var RESOURCE_HEADER_BYTES = 16;
776
- function isDataForkFont(bytes) {
777
- if (bytes.byteLength < RESOURCE_HEADER_BYTES) return false;
778
- const view = new DataView(bytes);
779
- if (FONT_SIGNATURES.has(tagAt(view, 0))) return false;
780
- const dataOffset = view.getUint32(0);
781
- const mapOffset = view.getUint32(4);
782
- const dataLength = view.getUint32(8);
783
- const mapLength = view.getUint32(12);
784
- return dataOffset >= RESOURCE_HEADER_BYTES && dataOffset + dataLength === mapOffset && mapOffset + mapLength <= bytes.byteLength;
785
- }
786
- function readTableDirectory(view, dirOffset) {
787
- const numTables = view.getUint16(dirOffset + 4);
788
- const records = [];
789
- for (let i = 0; i < numTables; i++) {
790
- const at = dirOffset + SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;
791
- records.push({
792
- tag: tagAt(view, at),
793
- checksum: view.getUint32(at + 4),
794
- offset: view.getUint32(at + 8),
795
- length: view.getUint32(at + 12)
796
- });
797
- }
798
- return records;
799
- }
800
- function postScriptNameAt(view, records) {
801
- const name = records.find((r) => r.tag === "name");
802
- if (!name) return null;
803
- const base = name.offset;
804
- const count = view.getUint16(base + 2);
805
- const stringOffset = view.getUint16(base + 4);
806
- for (let i = 0; i < count; i++) {
807
- const rec = base + 6 + i * 12;
808
- if (view.getUint16(rec + 6) !== 6) continue;
809
- const length = view.getUint16(rec + 8);
810
- const offset = view.getUint16(rec + 10);
811
- let out = "";
812
- for (let b = 0; b < length; b++) {
813
- const code = view.getUint8(base + stringOffset + offset + b);
814
- if (code !== 0) out += String.fromCharCode(code);
815
- }
816
- if (out.length > 0) return out;
817
- }
818
- return null;
819
- }
820
- function extractFont(source, view, dirOffset) {
821
- const records = readTableDirectory(view, dirOffset);
822
- const padded = (n) => n + 3 & -4;
823
- let total = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;
824
- for (const r of records) total += padded(r.length);
825
- const out = new ArrayBuffer(total);
826
- const dst = new DataView(out);
827
- const dstBytes = new Uint8Array(out);
828
- const srcBytes = new Uint8Array(source);
829
- dst.setUint32(0, view.getUint32(dirOffset));
830
- dst.setUint16(4, records.length);
831
- const entrySelector = Math.floor(Math.log2(records.length));
832
- const searchRange = 2 ** entrySelector * 16;
833
- dst.setUint16(6, searchRange);
834
- dst.setUint16(8, entrySelector);
835
- dst.setUint16(10, records.length * 16 - searchRange);
836
- let cursor = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;
837
- records.forEach((r, i) => {
838
- const at = SFNT_HEADER_BYTES + i * TABLE_RECORD_BYTES;
839
- for (let b = 0; b < 4; b++) dst.setUint8(at + b, r.tag.charCodeAt(b));
840
- dst.setUint32(at + 4, r.checksum);
841
- dst.setUint32(at + 8, cursor);
842
- dst.setUint32(at + 12, r.length);
843
- dstBytes.set(srcBytes.subarray(r.offset, r.offset + r.length), cursor);
844
- cursor += padded(r.length);
845
- });
846
- return out;
847
- }
848
- function sfntFromCollection(bytes, postScriptName) {
849
- if (isDataForkFont(bytes)) {
850
- throw new Error(
851
- "Datafork TrueType (.dfont) is not supported \u2014 the outline tier reads sfnt tables and a .dfont holds them inside a Macintosh resource map."
852
- );
853
- }
854
- if (!isFontCollection(bytes)) return { bytes, matched: true };
855
- const view = new DataView(bytes);
856
- const numFonts = view.getUint32(8);
857
- if (numFonts === 0) throw new Error("font collection contains no fonts");
858
- const offsets = [];
859
- for (let i = 0; i < numFonts; i++) offsets.push(view.getUint32(12 + i * 4));
860
- if (postScriptName) {
861
- for (const dirOffset of offsets) {
862
- const records = readTableDirectory(view, dirOffset);
863
- if (postScriptNameAt(view, records) === postScriptName) {
864
- return { bytes: extractFont(bytes, view, dirOffset), matched: true };
865
- }
866
- }
867
- }
868
- return { bytes: extractFont(bytes, view, offsets[0]), matched: !postScriptName };
869
- }
870
-
871
- // src/outline/opentypeParser.ts
872
- var modulePromise = null;
873
- function loadOpenType() {
874
- modulePromise ??= import('opentype.js');
875
- return modulePromise;
876
- }
877
- function faceFor(font) {
878
- return {
879
- unitsPerEm: font.unitsPerEm,
880
- glyphD(cp) {
881
- const index = font.charToGlyphIndex(String.fromCodePoint(cp));
882
- if (!index) return null;
883
- const d = font.glyphs.get(index).getPath(0, 0, 1).toPathData(OUTLINE_PRECISION);
884
- return d.length > 0 ? d : null;
885
- }
886
- };
887
- }
888
- function createOpenTypeParser(postScriptName) {
889
- return async (bytes) => {
890
- const opentype = await loadOpenType();
891
- const { bytes: single } = sfntFromCollection(bytes, postScriptName);
892
- return faceFor(opentype.parse(single));
893
- };
894
- }
895
- var openTypeParser = createOpenTypeParser();
896
-
897
- // src/outline/outlineRegistry.ts
898
- var slots = /* @__PURE__ */ new Map();
899
- function slotKey(family, weight, style) {
900
- return `${family}|${weight}|${style}`;
901
- }
902
- function normalize(v) {
903
- return { weight: v.weight ?? 400, style: v.style ?? "normal" };
904
- }
905
- function registerFontOutlines(family, variant, source, opts = {}) {
906
- const { weight, style } = normalize(variant);
907
- slots.set(slotKey(family, weight, style), {
908
- family,
909
- weight,
910
- style,
911
- source,
912
- parser: opts.parser ?? openTypeParser,
913
- status: "idle",
914
- face: null,
915
- glyphs: /* @__PURE__ */ new Map()
916
- });
917
- }
918
- function unregisterFontOutlines(family, variant = {}) {
919
- const { weight, style } = normalize(variant);
920
- slots.delete(slotKey(family, weight, style));
921
- }
922
- function hasFontOutlines(family, weight = 400, style = "normal") {
923
- return slots.has(slotKey(family, weight, style));
924
- }
925
- function outlineStatus(family, weight = 400, style = "normal") {
926
- return slots.get(slotKey(family, weight, style))?.status ?? null;
927
- }
928
- function listFontOutlines() {
929
- return [...slots.values()].map(({ family, weight, style, status }) => ({ family, weight, style, status })).sort((a, b) => a.family.localeCompare(b.family) || a.weight - b.weight || a.style.localeCompare(b.style));
930
- }
931
- function closeContours(d) {
932
- let out = "";
933
- let start = 0;
934
- for (let i = 1; i < d.length; i++) {
935
- const c = d[i];
936
- if (c !== "M" && c !== "m") continue;
937
- out += closeOne(d.slice(start, i));
938
- start = i;
939
- }
940
- return out + closeOne(d.slice(start));
941
- }
942
- function closeOne(contour) {
943
- const trimmed = contour.trimEnd();
944
- if (trimmed.length === 0) return "";
945
- const last = trimmed[trimmed.length - 1];
946
- return last === "Z" || last === "z" ? trimmed : `${trimmed}Z`;
947
- }
948
- function glyphOutline(family, weight, style, cp) {
949
- const slot = slots.get(slotKey(family, weight, style));
950
- if (!slot) return null;
951
- if (slot.status === "idle") {
952
- void beginLoad(slot);
953
- return null;
954
- }
955
- if (slot.status !== "ready") return null;
956
- const cached = slot.glyphs.get(cp);
957
- if (cached !== void 0) return cached;
958
- let d = null;
959
- try {
960
- const raw = slot.face.glyphD(cp);
961
- d = raw === null ? null : closeContours(raw);
962
- } catch (err) {
963
- warnOnce(
964
- `glyph|${slotKey(family, weight, style)}`,
965
- `weasel: outline face "${family}" (${weight}/${style}) could not produce a glyph for U+${cp.toString(16).toUpperCase().padStart(4, "0")} \u2014 ${err instanceof Error ? err.message : String(err)}. Falling back to the SDF tier.`
966
- );
967
- }
968
- slot.glyphs.set(cp, d);
969
- return d;
970
- }
971
- async function beginLoad(slot) {
972
- slot.status = "loading";
973
- try {
974
- slot.face = await slot.parser(await readSource(slot.source));
975
- slot.status = "ready";
976
- notifyGlyphReady();
977
- } catch (err) {
978
- slot.status = "failed";
979
- warnOnce(
980
- `load|${slotKey(slot.family, slot.weight, slot.style)}`,
981
- `weasel registerFontOutlines("${slot.family}" ${slot.weight}/${slot.style}): ${err instanceof Error ? err.message : String(err)}. Large text in this face keeps rendering from the SDF tier.`
982
- );
983
- }
984
- }
985
- async function readSource(source) {
986
- const resolved = typeof source === "function" ? await source() : source;
987
- if (typeof resolved === "string") {
988
- const res = await fetch(resolved);
989
- if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${resolved}`);
990
- return res.arrayBuffer();
991
- }
992
- if (resolved instanceof ArrayBuffer) return resolved;
993
- return resolved.arrayBuffer();
994
- }
995
- var warned = /* @__PURE__ */ new Set();
996
- function warnOnce(key, message) {
997
- if (warned.has(key)) return;
998
- warned.add(key);
999
- console.warn(message);
1000
- }
1001
- function _resetFontOutlinesForTests() {
1002
- slots = /* @__PURE__ */ new Map();
1003
- warned.clear();
1004
- }
1005
-
1006
- export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, __setGlyphRasterizerForTests, _getPagesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests, createOpenTypeParser, dynamicPageTextureId, ensureFontTexture, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFonts, markAllFontsNotUploaded, outlineStatus, parseBmFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines };
1007
- //# sourceMappingURL=chunk-3RSTZDXH.js.map
1008
- //# sourceMappingURL=chunk-3RSTZDXH.js.map
1043
+ export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, __setGlyphRasterizerForTests, _getPagesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests, createOpenTypeParser, dynamicPageTextureId, ensureFontTexture, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFonts, markAllFontsNotUploaded, outlineMetrics, outlineStatus, parseBmFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines };
1044
+ //# sourceMappingURL=chunk-NRVRDX3F.js.map
1045
+ //# sourceMappingURL=chunk-NRVRDX3F.js.map