@weasel-js/font 1.9.2 → 1.9.4

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.
@@ -97,6 +97,19 @@ function parseBmFont(raw) {
97
97
  if (!Array.isArray(r.chars)) throw new Error("parseBmFont: chars must be an array");
98
98
  const info = r.info;
99
99
  const common = r.common;
100
+ const positive = [
101
+ ["info.size", info.size],
102
+ ["common.scaleW", common.scaleW],
103
+ ["common.scaleH", common.scaleH]
104
+ ];
105
+ for (const [name, value] of positive) {
106
+ if (typeof value !== "number" || !(value > 0) || !Number.isFinite(value)) {
107
+ throw new Error(`parseBmFont: ${name} must be a positive number`);
108
+ }
109
+ }
110
+ if (typeof common.base !== "number" || !Number.isFinite(common.base)) {
111
+ throw new Error("parseBmFont: common.base must be a number");
112
+ }
100
113
  const chars = r.chars;
101
114
  const kernings = Array.isArray(r.kernings) ? r.kernings : [];
102
115
  const charMap = /* @__PURE__ */ new Map();
@@ -178,6 +191,27 @@ function _resetFallbackForTests() {
178
191
  warnedFallbacks.clear();
179
192
  }
180
193
 
194
+ // src/cssFamily.ts
195
+ function cssFamilyName(family) {
196
+ if (/[,"']/.test(family)) return family;
197
+ return GENERIC_FAMILIES.has(family.trim().toLowerCase()) ? family.trim() : JSON.stringify(family);
198
+ }
199
+ var GENERIC_FAMILIES = /* @__PURE__ */ new Set([
200
+ "serif",
201
+ "sans-serif",
202
+ "monospace",
203
+ "cursive",
204
+ "fantasy",
205
+ "system-ui",
206
+ "ui-serif",
207
+ "ui-sans-serif",
208
+ "ui-monospace",
209
+ "ui-rounded",
210
+ "math",
211
+ "emoji",
212
+ "fangsong"
213
+ ]);
214
+
181
215
  // src/dynamic/shelfPack.ts
182
216
  var ShelfPacker = class {
183
217
  constructor(pageSize, maxPages) {
@@ -299,7 +333,7 @@ var BAKE_SIZE = 48;
299
333
  var PAD = 8;
300
334
  var METRICS_SIZE = 1e3;
301
335
  function cssFontString(weight, style, family, size = BAKE_SIZE) {
302
- return `${style === "italic" ? "italic " : ""}${weight} ${size}px ${JSON.stringify(family)}`;
336
+ return `${style === "italic" ? "italic " : ""}${weight} ${size}px ${cssFamilyName(family)}`;
303
337
  }
304
338
  function createCanvasRasterizer() {
305
339
  let canvas;
@@ -580,9 +614,7 @@ function _resetDynamicFontsForTests() {
580
614
  // src/outline/OutlineFace.ts
581
615
  var OUTLINE_PRECISION = 5;
582
616
 
583
- // src/outline/sfnt.ts
584
- var SFNT_HEADER_BYTES = 12;
585
- var TABLE_RECORD_BYTES = 16;
617
+ // src/outline/tag.ts
586
618
  function tagAt(view, offset) {
587
619
  return String.fromCharCode(
588
620
  view.getUint8(offset),
@@ -591,10 +623,11 @@ function tagAt(view, offset) {
591
623
  view.getUint8(offset + 3)
592
624
  );
593
625
  }
594
- function isFontCollection(bytes) {
595
- if (bytes.byteLength < 4) return false;
596
- return tagAt(new DataView(bytes), 0) === "ttcf";
597
- }
626
+
627
+ // src/outline/dataFork.ts
628
+ var RESOURCE_HEADER_BYTES = 16;
629
+ var TYPE_ENTRY_BYTES = 8;
630
+ var REFERENCE_BYTES = 12;
598
631
  var FONT_SIGNATURES = /* @__PURE__ */ new Set([
599
632
  "\0\0\0",
600
633
  "true",
@@ -604,7 +637,6 @@ var FONT_SIGNATURES = /* @__PURE__ */ new Set([
604
637
  "wOFF",
605
638
  "wOF2"
606
639
  ]);
607
- var RESOURCE_HEADER_BYTES = 16;
608
640
  function isDataForkFont(bytes) {
609
641
  if (bytes.byteLength < RESOURCE_HEADER_BYTES) return false;
610
642
  const view = new DataView(bytes);
@@ -615,6 +647,46 @@ function isDataForkFont(bytes) {
615
647
  const mapLength = view.getUint32(12);
616
648
  return dataOffset >= RESOURCE_HEADER_BYTES && dataOffset + dataLength === mapOffset && mapOffset + mapLength <= bytes.byteLength;
617
649
  }
650
+ var truncated = () => new Error("Datafork TrueType (.dfont) is truncated: a resource runs past the end of its segment.");
651
+ function sfntResources(bytes) {
652
+ const view = new DataView(bytes);
653
+ const dataOffset = view.getUint32(0);
654
+ const mapOffset = view.getUint32(4);
655
+ const dataLength = view.getUint32(8);
656
+ const mapEnd = mapOffset + view.getUint32(12);
657
+ const inMap = (at, count) => at >= mapOffset && at + count <= mapEnd;
658
+ if (!inMap(mapOffset + 24, 2)) return [];
659
+ const typeList = mapOffset + view.getUint16(mapOffset + 24);
660
+ if (!inMap(typeList, 2)) return [];
661
+ const typeCount = view.getUint16(typeList) + 1 & 65535;
662
+ const out = [];
663
+ for (let t = 0; t < typeCount; t++) {
664
+ const entry = typeList + 2 + t * TYPE_ENTRY_BYTES;
665
+ if (!inMap(entry, TYPE_ENTRY_BYTES)) throw truncated();
666
+ if (tagAt(view, entry) !== "sfnt") continue;
667
+ const count = view.getUint16(entry + 4) + 1;
668
+ const references = typeList + view.getUint16(entry + 6);
669
+ for (let i = 0; i < count; i++) {
670
+ const ref = references + i * REFERENCE_BYTES;
671
+ if (!inMap(ref, REFERENCE_BYTES)) throw truncated();
672
+ const offset = view.getUint32(ref + 4) & 16777215;
673
+ if (offset + 4 > dataLength) throw truncated();
674
+ const start = dataOffset + offset + 4;
675
+ const length = view.getUint32(start - 4);
676
+ if (offset + 4 + length > dataLength) throw truncated();
677
+ out.push(bytes.slice(start, start + length));
678
+ }
679
+ }
680
+ return out;
681
+ }
682
+
683
+ // src/outline/sfnt.ts
684
+ var SFNT_HEADER_BYTES = 12;
685
+ var TABLE_RECORD_BYTES = 16;
686
+ function isFontCollection(bytes) {
687
+ if (bytes.byteLength < 4) return false;
688
+ return tagAt(new DataView(bytes), 0) === "ttcf";
689
+ }
618
690
  function readTableDirectory(view, dirOffset) {
619
691
  const numTables = view.getUint16(dirOffset + 4);
620
692
  const records = [];
@@ -653,7 +725,12 @@ function extractFont(source, view, dirOffset) {
653
725
  const records = readTableDirectory(view, dirOffset);
654
726
  const padded = (n) => n + 3 & -4;
655
727
  let total = SFNT_HEADER_BYTES + records.length * TABLE_RECORD_BYTES;
656
- for (const r of records) total += padded(r.length);
728
+ for (const r of records) {
729
+ if (r.offset + r.length > source.byteLength) {
730
+ throw new Error(`font collection is truncated: table "${r.tag}" runs past the end of the file`);
731
+ }
732
+ total += padded(r.length);
733
+ }
657
734
  const out = new ArrayBuffer(total);
658
735
  const dst = new DataView(out);
659
736
  const dstBytes = new Uint8Array(out);
@@ -679,9 +756,13 @@ function extractFont(source, view, dirOffset) {
679
756
  }
680
757
  function sfntFromCollection(bytes, postScriptName) {
681
758
  if (isDataForkFont(bytes)) {
682
- throw new Error(
683
- "Datafork TrueType (.dfont) is not supported \u2014 the outline tier reads sfnt tables and a .dfont holds them inside a Macintosh resource map."
684
- );
759
+ const fonts = sfntResources(bytes);
760
+ if (fonts.length === 0) throw new Error("Datafork TrueType (.dfont) holds no sfnt resource.");
761
+ const named = postScriptName ? fonts.find((font) => {
762
+ const view2 = new DataView(font);
763
+ return postScriptNameAt(view2, readTableDirectory(view2, 0)) === postScriptName;
764
+ }) : void 0;
765
+ return { bytes: named ?? fonts[0], matched: named !== void 0 || !postScriptName };
685
766
  }
686
767
  if (!isFontCollection(bytes)) return { bytes, matched: true };
687
768
  const view = new DataView(bytes);
@@ -1280,6 +1361,7 @@ function missResolveResult(family, weight, style, suppressWarn = false) {
1280
1361
  source: "outline"
1281
1362
  };
1282
1363
  }
1364
+ if (fontPending(family, weight, style)) return pendingMiss(family, weight, style);
1283
1365
  const policy2 = getFontFallbackPolicy();
1284
1366
  if (policy2 === "canvas") {
1285
1367
  autoEnrollCanvasFont(family);
@@ -1525,7 +1607,7 @@ function cssFontFamily(family, variant = {}) {
1525
1607
  if (!priv) return family;
1526
1608
  const name = nameFor(priv.target);
1527
1609
  for (const v of priv.variants) ensureFace(name, v.family, v.weight, v.style);
1528
- return `${JSON.stringify(name)}, ${family}`;
1610
+ return `${JSON.stringify(name)}, ${cssFamilyName(family)}`;
1529
1611
  }
1530
1612
  function cssFontFamilyLoading(family, variant = {}) {
1531
1613
  const priv = privateFamily(family, variant);
@@ -1584,6 +1666,6 @@ function _resetDomFacesForTests() {
1584
1666
  warned2.clear();
1585
1667
  }
1586
1668
 
1587
- export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, PAGE_SIZE, SDF_RADIUS, __setGlyphRasterizerForTests, _getPagesForTests, _resetDomFacesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests, createOpenTypeParser, cssFontFamily, cssFontFamilyLoading, dynamicPageTextureId, ensureFontTexture, faceMetricsFor, faceMetricsFromTables, faceMetricsOf, fontOutlineRegistry, fontPending, fontRegistry, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFontWeights, listFonts, loadFontOutlines, markAllFontsNotUploaded, outlineMetrics, outlineStatus, parseBmFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines, verticalMetricsFromTables, warmFonts };
1588
- //# sourceMappingURL=chunk-RYN4NYX4.js.map
1589
- //# sourceMappingURL=chunk-RYN4NYX4.js.map
1669
+ export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, PAGE_SIZE, SDF_RADIUS, __setGlyphRasterizerForTests, _getPagesForTests, _resetDomFacesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests, createOpenTypeParser, cssFamilyName, cssFontFamily, cssFontFamilyLoading, dynamicPageTextureId, ensureFontTexture, faceMetricsFor, faceMetricsFromTables, faceMetricsOf, fontOutlineRegistry, fontPending, fontRegistry, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFontWeights, listFonts, loadFontOutlines, markAllFontsNotUploaded, outlineMetrics, outlineStatus, parseBmFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines, verticalMetricsFromTables, warmFonts };
1670
+ //# sourceMappingURL=chunk-ERSHQYJL.js.map
1671
+ //# sourceMappingURL=chunk-ERSHQYJL.js.map