@weasel-js/font 1.10.1 → 1.11.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.
@@ -0,0 +1,161 @@
1
+ // src/faceMetrics.ts
2
+ var finite = (n) => typeof n === "number" && Number.isFinite(n);
3
+ var USE_TYPO_METRICS = 1 << 7;
4
+ function verticalMetricsFromTables(t) {
5
+ const upem = t.unitsPerEm;
6
+ if (!finite(upem) || upem <= 0) return void 0;
7
+ const os2 = t.os2;
8
+ const pair = (a, d, down) => finite(a) && finite(d) && a + (down ? d : -d) > 0 ? { ascent: a / upem, descent: (down ? d : -d) / upem } : void 0;
9
+ const typo = pair(os2?.sTypoAscender, os2?.sTypoDescender, false);
10
+ const hhea = pair(t.hhea?.ascender, t.hhea?.descender, false);
11
+ const win = pair(os2?.usWinAscent, os2?.usWinDescent, true);
12
+ const useTypo = finite(os2?.fsSelection) && (os2.fsSelection & USE_TYPO_METRICS) !== 0;
13
+ return (useTypo ? typo : void 0) ?? hhea ?? typo ?? win;
14
+ }
15
+ function faceMetricsFromTables(t) {
16
+ const upem = t.unitsPerEm;
17
+ if (!finite(upem) || upem <= 0) return void 0;
18
+ const out = {};
19
+ const rule = (position, thickness) => finite(position) && finite(thickness) && thickness > 0 ? { offset: -position / upem, thickness: thickness / upem } : void 0;
20
+ const script = (size, shift) => finite(size) && finite(shift) && size > 0 ? { size: size / upem, shift: shift / upem } : void 0;
21
+ const underline = rule(t.post?.underlinePosition, t.post?.underlineThickness);
22
+ const strikethrough = rule(t.os2?.yStrikeoutPosition, t.os2?.yStrikeoutSize);
23
+ const superscript = script(t.os2?.ySuperscriptYSize, t.os2?.ySuperscriptYOffset);
24
+ const sub = t.os2?.ySubscriptYOffset;
25
+ const subscript = script(t.os2?.ySubscriptYSize, finite(sub) ? -sub : sub);
26
+ const vertical = verticalMetricsFromTables(t);
27
+ if (vertical) {
28
+ out.ascent = vertical.ascent;
29
+ out.descent = vertical.descent;
30
+ }
31
+ if (underline) out.underline = underline;
32
+ if (strikethrough) out.strikethrough = strikethrough;
33
+ if (superscript) out.superscript = superscript;
34
+ if (subscript) out.subscript = subscript;
35
+ const xHeight = t.os2?.sxHeight;
36
+ const capHeight = t.os2?.sCapHeight;
37
+ if (finite(xHeight) && xHeight > 0) out.xHeight = xHeight / upem;
38
+ if (finite(capHeight) && capHeight > 0) out.capHeight = capHeight / upem;
39
+ return Object.keys(out).length > 0 ? out : void 0;
40
+ }
41
+ function parseFaceMetrics(raw) {
42
+ if (raw === void 0) return void 0;
43
+ if (typeof raw !== "object" || raw === null) throw new Error("parseBmFont: faceMetrics must be an object");
44
+ const r = raw;
45
+ const out = {};
46
+ if (r.ascent !== void 0 || r.descent !== void 0) {
47
+ if (!finite(r.ascent) || !finite(r.descent) || r.ascent + r.descent <= 0) {
48
+ throw new Error("parseBmFont: malformed faceMetrics.ascent/descent");
49
+ }
50
+ out.ascent = r.ascent;
51
+ out.descent = r.descent;
52
+ }
53
+ const pair = (key, a, b, positive) => {
54
+ const v = r[key];
55
+ if (v === void 0) return;
56
+ const e = v;
57
+ if (typeof e !== "object" || e === null || !finite(e[a]) || !finite(e[b]) || e[positive] <= 0) {
58
+ throw new Error(`parseBmFont: malformed faceMetrics.${key}`);
59
+ }
60
+ out[key] = { [a]: e[a], [b]: e[b] };
61
+ };
62
+ pair("underline", "offset", "thickness", "thickness");
63
+ pair("strikethrough", "offset", "thickness", "thickness");
64
+ pair("superscript", "size", "shift", "size");
65
+ pair("subscript", "size", "shift", "size");
66
+ for (const key of ["xHeight", "capHeight"]) {
67
+ const v = r[key];
68
+ if (v === void 0) continue;
69
+ if (!finite(v) || v <= 0) throw new Error(`parseBmFont: malformed faceMetrics.${key}`);
70
+ out[key] = v;
71
+ }
72
+ return Object.keys(out).length > 0 ? out : void 0;
73
+ }
74
+ function faceMetricsOf(result) {
75
+ return result.outlineFace?.faceMetrics ?? result.entry?.font.faceMetrics;
76
+ }
77
+
78
+ // src/FontAtlas.ts
79
+ var FIXTURE_FONT = {
80
+ info: { face: "Inter", size: 32 },
81
+ common: { lineHeight: 38, base: 29, scaleW: 512, scaleH: 512 },
82
+ chars: [
83
+ { id: 65, x: 0, y: 0, width: 22, height: 28, xoffset: 1, yoffset: 4, xadvance: 23, page: 0 },
84
+ { id: 66, x: 24, y: 0, width: 20, height: 28, xoffset: 2, yoffset: 4, xadvance: 22, page: 0 }
85
+ ],
86
+ kernings: [
87
+ { first: 65, second: 66, amount: -1 }
88
+ ]
89
+ };
90
+ function parseBmFont(raw) {
91
+ if (typeof raw !== "object" || raw === null) throw new Error("parseBmFont: expected object");
92
+ const r = raw;
93
+ if (!r.info || typeof r.info !== "object") throw new Error("parseBmFont: missing info");
94
+ if (!r.common || typeof r.common !== "object") throw new Error("parseBmFont: missing common");
95
+ if (!Array.isArray(r.chars)) throw new Error("parseBmFont: chars must be an array");
96
+ const info = r.info;
97
+ const common = r.common;
98
+ const positive = [
99
+ ["info.size", info.size],
100
+ ["common.scaleW", common.scaleW],
101
+ ["common.scaleH", common.scaleH]
102
+ ];
103
+ for (const [name, value] of positive) {
104
+ if (typeof value !== "number" || !(value > 0) || !Number.isFinite(value)) {
105
+ throw new Error(`parseBmFont: ${name} must be a positive number`);
106
+ }
107
+ }
108
+ if (typeof common.base !== "number" || !Number.isFinite(common.base)) {
109
+ throw new Error("parseBmFont: common.base must be a number");
110
+ }
111
+ const chars = r.chars;
112
+ const kernings = Array.isArray(r.kernings) ? r.kernings : [];
113
+ const charMap = /* @__PURE__ */ new Map();
114
+ for (const ch of chars) charMap.set(ch.id, ch);
115
+ const kerningMap = /* @__PURE__ */ new Map();
116
+ for (const k of kernings) {
117
+ let inner = kerningMap.get(k.first);
118
+ if (!inner) {
119
+ inner = /* @__PURE__ */ new Map();
120
+ kerningMap.set(k.first, inner);
121
+ }
122
+ inner.set(k.second, k.amount);
123
+ }
124
+ const faceMetrics = parseFaceMetrics(r.faceMetrics);
125
+ const range = r.distanceField?.distanceRange;
126
+ return {
127
+ info,
128
+ common,
129
+ chars,
130
+ kernings,
131
+ charMap,
132
+ kerningMap,
133
+ ...faceMetrics ? { faceMetrics } : {},
134
+ ...typeof range === "number" && range > 0 ? { distanceRange: range } : {}
135
+ };
136
+ }
137
+
138
+ // src/cssFamily.ts
139
+ function cssFamilyName(family) {
140
+ if (/[,"']/.test(family)) return family;
141
+ return GENERIC_FAMILIES.has(family.trim().toLowerCase()) ? family.trim() : JSON.stringify(family);
142
+ }
143
+ var GENERIC_FAMILIES = /* @__PURE__ */ new Set([
144
+ "serif",
145
+ "sans-serif",
146
+ "monospace",
147
+ "cursive",
148
+ "fantasy",
149
+ "system-ui",
150
+ "ui-serif",
151
+ "ui-sans-serif",
152
+ "ui-monospace",
153
+ "ui-rounded",
154
+ "math",
155
+ "emoji",
156
+ "fangsong"
157
+ ]);
158
+
159
+ export { FIXTURE_FONT, cssFamilyName, faceMetricsFromTables, faceMetricsOf, parseBmFont, verticalMetricsFromTables };
160
+ //# sourceMappingURL=chunk-XQPRAGHF.js.map
161
+ //# sourceMappingURL=chunk-XQPRAGHF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/faceMetrics.ts","../src/FontAtlas.ts","../src/cssFamily.ts"],"names":[],"mappings":";AAoEA,IAAM,MAAA,GAAS,CAAC,CAAA,KAA4B,OAAO,MAAM,QAAA,IAAY,MAAA,CAAO,SAAS,CAAC,CAAA;AAGtF,IAAM,mBAAmB,CAAA,IAAK,CAAA;AAevB,SAAS,0BAA0B,CAAA,EAAsE;AAC9G,EAAA,MAAM,OAAO,CAAA,CAAE,UAAA;AACf,EAAA,IAAI,CAAC,MAAA,CAAO,IAAI,CAAA,IAAK,IAAA,IAAQ,GAAG,OAAO,MAAA;AACvC,EAAA,MAAM,MAAM,CAAA,CAAE,GAAA;AACd,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,EAAY,CAAA,EAAY,IAAA,KACpC,MAAA,CAAO,CAAC,CAAA,IAAK,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA,IAAK,IAAA,GAAO,CAAA,GAAI,CAAC,CAAA,CAAA,GAAK,CAAA,GAC5C,EAAE,MAAA,EAAQ,CAAA,GAAI,IAAA,EAAM,OAAA,EAAA,CAAU,IAAA,GAAO,CAAA,GAAI,CAAC,CAAA,IAAK,IAAA,EAAK,GACpD,MAAA;AACN,EAAA,MAAM,OAAO,IAAA,CAAK,GAAA,EAAK,aAAA,EAAe,GAAA,EAAK,gBAAgB,KAAK,CAAA;AAChE,EAAA,MAAM,IAAA,GAAO,KAAK,CAAA,CAAE,IAAA,EAAM,UAAU,CAAA,CAAE,IAAA,EAAM,WAAW,KAAK,CAAA;AAC5D,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA,EAAK,WAAA,EAAa,GAAA,EAAK,cAAc,IAAI,CAAA;AAC1D,EAAA,MAAM,UAAU,MAAA,CAAO,GAAA,EAAK,WAAW,CAAA,IAAA,CAAM,GAAA,CAAI,cAAc,gBAAA,MAAsB,CAAA;AACrF,EAAA,OAAA,CAAQ,OAAA,GAAU,IAAA,GAAO,MAAA,KAAc,IAAA,IAAQ,IAAA,IAAQ,GAAA;AACzD;AAWO,SAAS,sBAAsB,CAAA,EAA8C;AAClF,EAAA,MAAM,OAAO,CAAA,CAAE,UAAA;AACf,EAAA,IAAI,CAAC,MAAA,CAAO,IAAI,CAAA,IAAK,IAAA,IAAQ,GAAG,OAAO,MAAA;AACvC,EAAA,MAAM,MAKF,EAAC;AACL,EAAA,MAAM,IAAA,GAAO,CAAC,QAAA,EAAmB,SAAA,KAC/B,OAAO,QAAQ,CAAA,IAAK,OAAO,SAAS,CAAA,IAAK,YAAY,CAAA,GACjD,EAAE,QAAQ,CAAC,QAAA,GAAW,MAAM,SAAA,EAAW,SAAA,GAAY,MAAK,GACxD,MAAA;AACN,EAAA,MAAM,SAAS,CAAC,IAAA,EAAe,UAC7B,MAAA,CAAO,IAAI,KAAK,MAAA,CAAO,KAAK,KAAK,IAAA,GAAO,CAAA,GACpC,EAAE,IAAA,EAAM,IAAA,GAAO,MAAM,KAAA,EAAO,KAAA,GAAQ,MAAK,GACzC,MAAA;AACN,EAAA,MAAM,YAAY,IAAA,CAAK,CAAA,CAAE,MAAM,iBAAA,EAAmB,CAAA,CAAE,MAAM,kBAAkB,CAAA;AAC5E,EAAA,MAAM,gBAAgB,IAAA,CAAK,CAAA,CAAE,KAAK,kBAAA,EAAoB,CAAA,CAAE,KAAK,cAAc,CAAA;AAC3E,EAAA,MAAM,cAAc,MAAA,CAAO,CAAA,CAAE,KAAK,iBAAA,EAAmB,CAAA,CAAE,KAAK,mBAAmB,CAAA;AAC/E,EAAA,MAAM,GAAA,GAAM,EAAE,GAAA,EAAK,iBAAA;AACnB,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,CAAA,CAAE,GAAA,EAAK,eAAA,EAAiB,OAAO,GAAG,CAAA,GAAI,CAAC,GAAA,GAAM,GAAG,CAAA;AACzE,EAAA,MAAM,QAAA,GAAW,0BAA0B,CAAC,CAAA;AAC5C,EAAA,IAAI,QAAA,EAAU;AAAE,IAAA,GAAA,CAAI,SAAS,QAAA,CAAS,MAAA;AAAQ,IAAA,GAAA,CAAI,UAAU,QAAA,CAAS,OAAA;AAAA,EAAS;AAC9E,EAAA,IAAI,SAAA,MAAe,SAAA,GAAY,SAAA;AAC/B,EAAA,IAAI,aAAA,MAAmB,aAAA,GAAgB,aAAA;AACvC,EAAA,IAAI,WAAA,MAAiB,WAAA,GAAc,WAAA;AACnC,EAAA,IAAI,SAAA,MAAe,SAAA,GAAY,SAAA;AAC/B,EAAA,MAAM,OAAA,GAAU,EAAE,GAAA,EAAK,QAAA;AACvB,EAAA,MAAM,SAAA,GAAY,EAAE,GAAA,EAAK,UAAA;AACzB,EAAA,IAAI,OAAO,OAAO,CAAA,IAAK,UAAU,CAAA,EAAG,GAAA,CAAI,UAAU,OAAA,GAAU,IAAA;AAC5D,EAAA,IAAI,OAAO,SAAS,CAAA,IAAK,YAAY,CAAA,EAAG,GAAA,CAAI,YAAY,SAAA,GAAY,IAAA;AACpE,EAAA,OAAO,OAAO,IAAA,CAAK,GAAG,CAAA,CAAE,MAAA,GAAS,IAAI,GAAA,GAAM,MAAA;AAC7C;AAMO,SAAS,iBAAiB,GAAA,EAAuC;AACtE,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,MAAA;AAC9B,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,GAAA,KAAQ,MAAM,MAAM,IAAI,MAAM,4CAA4C,CAAA;AACzG,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,MAAM,MAAoE,EAAC;AAC3E,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,MAAA,IAAa,CAAA,CAAE,YAAY,MAAA,EAAW;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,CAAA,CAAE,MAAM,KAAK,CAAC,MAAA,CAAO,CAAA,CAAE,OAAO,CAAA,IAAK,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,WAAW,CAAA,EAAG;AACxE,MAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,IACrE;AACA,IAAA,GAAA,CAAI,SAAS,CAAA,CAAE,MAAA;AACf,IAAA,GAAA,CAAI,UAAU,CAAA,CAAE,OAAA;AAAA,EAClB;AACA,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,EAAa,CAAA,EAAW,GAAW,QAAA,KAA2B;AAC1E,IAAA,MAAM,CAAA,GAAI,EAAE,GAAG,CAAA;AACf,IAAA,IAAI,MAAM,MAAA,EAAW;AACrB,IAAA,MAAM,CAAA,GAAI,CAAA;AACV,IAAA,IAAI,OAAO,MAAM,QAAA,IAAY,CAAA,KAAM,QAAQ,CAAC,MAAA,CAAO,EAAE,CAAC,CAAC,KAAK,CAAC,MAAA,CAAO,EAAE,CAAC,CAAC,KAAM,CAAA,CAAE,QAAQ,KAAgB,CAAA,EAAG;AACzG,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,GAAG,CAAA,CAAE,CAAA;AAAA,IAC7D;AACA,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,EAAE,CAAC,CAAC,GAAG,CAAA,CAAE,CAAC,CAAA,EAAG,CAAC,CAAC,GAAG,CAAA,CAAE,CAAC,CAAA,EAAE;AAAA,EACpC,CAAA;AACA,EAAA,IAAA,CAAK,WAAA,EAAa,QAAA,EAAU,WAAA,EAAa,WAAW,CAAA;AACpD,EAAA,IAAA,CAAK,eAAA,EAAiB,QAAA,EAAU,WAAA,EAAa,WAAW,CAAA;AACxD,EAAA,IAAA,CAAK,aAAA,EAAe,MAAA,EAAQ,OAAA,EAAS,MAAM,CAAA;AAC3C,EAAA,IAAA,CAAK,WAAA,EAAa,MAAA,EAAQ,OAAA,EAAS,MAAM,CAAA;AACzC,EAAA,KAAA,MAAW,GAAA,IAAO,CAAC,SAAA,EAAW,WAAW,CAAA,EAAY;AACnD,IAAA,MAAM,CAAA,GAAI,EAAE,GAAG,CAAA;AACf,IAAA,IAAI,MAAM,MAAA,EAAW;AACrB,IAAA,IAAI,CAAC,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,GAAG,CAAA,CAAE,CAAA;AACrF,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,CAAA;AAAA,EACb;AACA,EAAA,OAAO,OAAO,IAAA,CAAK,GAAG,CAAA,CAAE,MAAA,GAAS,IAAK,GAAA,GAAsB,MAAA;AAC9D;AAOO,SAAS,cAAc,MAAA,EAGF;AAC1B,EAAA,OAAO,MAAA,CAAO,WAAA,EAAa,WAAA,IAAe,MAAA,CAAO,OAAO,IAAA,CAAK,WAAA;AAC/D;;;AC5HO,IAAM,YAAA,GAAe;AAAA,EAC1B,IAAA,EAAM,EAAE,IAAA,EAAM,OAAA,EAAS,MAAM,EAAA,EAAG;AAAA,EAChC,MAAA,EAAQ,EAAE,UAAA,EAAY,EAAA,EAAI,MAAM,EAAA,EAAI,MAAA,EAAQ,GAAA,EAAK,MAAA,EAAQ,GAAA,EAAI;AAAA,EAC7D,KAAA,EAAO;AAAA,IACL,EAAE,EAAA,EAAI,EAAA,EAAI,GAAG,CAAA,EAAI,CAAA,EAAG,GAAG,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,SAAS,CAAA,EAAG,OAAA,EAAS,GAAG,QAAA,EAAU,EAAA,EAAI,MAAM,CAAA,EAAE;AAAA,IAC5F,EAAE,EAAA,EAAI,EAAA,EAAI,GAAG,EAAA,EAAI,CAAA,EAAG,GAAG,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,SAAS,CAAA,EAAG,OAAA,EAAS,GAAG,QAAA,EAAU,EAAA,EAAI,MAAM,CAAA;AAAE,GAC9F;AAAA,EACA,QAAA,EAAU;AAAA,IACR,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,QAAQ,EAAA;AAAG;AAExC;AAIO,SAAS,YAAY,GAAA,EAAsB;AAChD,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,GAAA,KAAQ,MAAM,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAC3F,EAAA,MAAM,CAAA,GAAI,GAAA;AAEV,EAAA,IAAI,CAAC,CAAA,CAAE,IAAA,IAAQ,OAAO,CAAA,CAAE,SAAS,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,2BAA2B,CAAA;AACtF,EAAA,IAAI,CAAC,CAAA,CAAE,MAAA,IAAU,OAAO,CAAA,CAAE,WAAW,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,6BAA6B,CAAA;AAC5F,EAAA,IAAI,CAAC,MAAM,OAAA,CAAQ,CAAA,CAAE,KAAK,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,qCAAqC,CAAA;AAElF,EAAA,MAAM,OAAO,CAAA,CAAE,IAAA;AACf,EAAA,MAAM,SAAS,CAAA,CAAE,MAAA;AAEjB,EAAA,MAAM,QAAA,GAAqC;AAAA,IACzC,CAAC,WAAA,EAAa,IAAA,CAAK,IAAI,CAAA;AAAA,IAAG,CAAC,eAAA,EAAiB,MAAA,CAAO,MAAM,CAAA;AAAA,IAAG,CAAC,eAAA,EAAiB,MAAA,CAAO,MAAM;AAAA,GAC7F;AACA,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,CAAA,IAAK,QAAA,EAAU;AACpC,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,EAAE,KAAA,GAAQ,MAAM,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AACxE,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,aAAA,EAAgB,IAAI,CAAA,0BAAA,CAA4B,CAAA;AAAA,IAClE;AAAA,EACF;AACA,EAAA,IAAI,OAAO,OAAO,IAAA,KAAS,QAAA,IAAY,CAAC,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA,EAAG;AACpE,IAAA,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAAA,EAC7D;AACA,EAAA,MAAM,QAAQ,CAAA,CAAE,KAAA;AAChB,EAAA,MAAM,QAAA,GAA4B,MAAM,OAAA,CAAQ,CAAA,CAAE,QAAQ,CAAA,GACrD,CAAA,CAAE,WACH,EAAC;AAEL,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAwB;AAC5C,EAAA,KAAA,MAAW,MAAM,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,EAAA,CAAG,IAAI,EAAE,CAAA;AAE7C,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAiC;AACxD,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,IAAI,KAAA,GAAQ,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,KAAK,CAAA;AAClC,IAAA,IAAI,CAAC,KAAA,EAAO;AAAE,MAAA,KAAA,uBAAY,GAAA,EAAI;AAAG,MAAA,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,KAAA,EAAO,KAAK,CAAA;AAAA,IAAG;AACjE,IAAA,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,CAAA,CAAE,MAAM,CAAA;AAAA,EAC9B;AAEA,EAAA,MAAM,WAAA,GAAc,gBAAA,CAAiB,CAAA,CAAE,WAAW,CAAA;AAClD,EAAA,MAAM,KAAA,GAAS,EAAE,aAAA,EAA2D,aAAA;AAC5E,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IAAM,MAAA;AAAA,IAAQ,KAAA;AAAA,IAAO,QAAA;AAAA,IAAU,OAAA;AAAA,IAAS,UAAA;AAAA,IACxC,GAAI,WAAA,GAAc,EAAE,WAAA,KAAgB,EAAC;AAAA,IACrC,GAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,GAAQ,IAAI,EAAE,aAAA,EAAe,KAAA,EAAM,GAAI;AAAC,GAC3E;AACF;;;ACtHO,SAAS,cAAc,MAAA,EAAwB;AACpD,EAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,EAAG,OAAO,MAAA;AACjC,EAAA,OAAO,gBAAA,CAAiB,GAAA,CAAI,MAAA,CAAO,IAAA,EAAK,CAAE,WAAA,EAAa,CAAA,GAAI,MAAA,CAAO,IAAA,EAAK,GAAI,IAAA,CAAK,UAAU,MAAM,CAAA;AAClG;AAEA,IAAM,gBAAA,uBAA4C,GAAA,CAAI;AAAA,EACpD,OAAA;AAAA,EAAS,YAAA;AAAA,EAAc,WAAA;AAAA,EAAa,SAAA;AAAA,EAAW,SAAA;AAAA,EAAW,WAAA;AAAA,EAC1D,UAAA;AAAA,EAAY,eAAA;AAAA,EAAiB,cAAA;AAAA,EAAgB,YAAA;AAAA,EAAc,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS;AAC9E,CAAC,CAAA","file":"chunk-XQPRAGHF.js","sourcesContent":["/**\n * The line, decoration and script metrics a font states for itself, in the\n * kit's units: em fractions, with a rule's `offset` measured *down* from the\n * baseline to its top edge (y grows down) and a script's `shift` positive\n * for a rise.\n *\n * Both glyph tiers derive the record through {@link faceMetricsFromTables},\n * so one font yields one set of numbers whichever tier serves a run.\n */\n\n/** One rule: the top edge's distance below the baseline, and its weight. */\nexport interface FaceRuleMetrics {\n readonly offset: number;\n readonly thickness: number;\n}\n\n/** One script preset: `size` scales the inherited font size, `shift` raises\n * (positive) or lowers (negative) the baseline, in inherited ems. */\nexport interface FaceScriptMetrics {\n readonly size: number;\n readonly shift: number;\n}\n\n/** What a face says about its line, rules, scripts and letter heights.\n * Every field is optional: a font may carry some of these tables and not\n * others. */\nexport interface FaceMetrics {\n /** Baseline to the top of the face's line box, in ems — the ascent a\n * browser sets this face with. See {@link verticalMetricsFromTables}. */\n readonly ascent?: number;\n /** Baseline to the bottom of the face's line box, in ems, positive\n * downward. Present exactly when `ascent` is. */\n readonly descent?: number;\n readonly underline?: FaceRuleMetrics;\n readonly strikethrough?: FaceRuleMetrics;\n readonly superscript?: FaceScriptMetrics;\n readonly subscript?: FaceScriptMetrics;\n /** Height of a flat lowercase letter above the baseline, in ems\n * (`OS/2.sxHeight`). */\n readonly xHeight?: number;\n /** Height of a flat capital above the baseline, in ems\n * (`OS/2.sCapHeight`). */\n readonly capHeight?: number;\n}\n\n/** The table fields {@link faceMetricsFromTables} reads, in font units, as\n * the OpenType `post` and `OS/2` tables state them. */\nexport interface FaceMetricTables {\n unitsPerEm: number;\n hhea?: { ascender?: number; descender?: number };\n post?: { underlinePosition?: number; underlineThickness?: number };\n os2?: {\n fsSelection?: number;\n sTypoAscender?: number;\n sTypoDescender?: number;\n usWinAscent?: number;\n usWinDescent?: number;\n yStrikeoutPosition?: number;\n yStrikeoutSize?: number;\n ySuperscriptYSize?: number;\n ySuperscriptYOffset?: number;\n ySubscriptYSize?: number;\n ySubscriptYOffset?: number;\n sxHeight?: number;\n sCapHeight?: number;\n };\n}\n\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n);\n\n/** `OS/2.fsSelection` bit 7: the font asks to be set by its typo metrics. */\nconst USE_TYPO_METRICS = 1 << 7;\n\n/**\n * The ascent and descent a browser sets this face with, in ems, descent\n * positive downward.\n *\n * The OpenType rule: `OS/2` `sTypoAscender`/`sTypoDescender` when the font\n * sets `USE_TYPO_METRICS`, otherwise `hhea`. Firefox, and every engine on\n * Linux, follow it; Chromium and WebKit on macOS read `hhea` even when the\n * flag is set, and the DOM edit overlay's measured baseline correction\n * absorbs the difference there.\n *\n * Falls back to the typo pair, then the win pair, when `hhea` is absent or\n * zero.\n */\nexport function verticalMetricsFromTables(t: FaceMetricTables): { ascent: number; descent: number } | undefined {\n const upem = t.unitsPerEm;\n if (!finite(upem) || upem <= 0) return undefined;\n const os2 = t.os2;\n const pair = (a: unknown, d: unknown, down: boolean) =>\n finite(a) && finite(d) && a + (down ? d : -d) > 0\n ? { ascent: a / upem, descent: (down ? d : -d) / upem }\n : undefined;\n const typo = pair(os2?.sTypoAscender, os2?.sTypoDescender, false);\n const hhea = pair(t.hhea?.ascender, t.hhea?.descender, false);\n const win = pair(os2?.usWinAscent, os2?.usWinDescent, true);\n const useTypo = finite(os2?.fsSelection) && (os2.fsSelection & USE_TYPO_METRICS) !== 0;\n return (useTypo ? typo : undefined) ?? hhea ?? typo ?? win;\n}\n\n/**\n * Convert raw table values to {@link FaceMetrics}.\n *\n * `post.underlinePosition` and `OS/2.yStrikeoutPosition` are the rule's top\n * edge, positive above the baseline. `ySubscriptYOffset` is positive\n * *downward*, unlike its superscript twin. A zero weight or size is a font\n * that left the field blank, so that entry is dropped and the caller's\n * default applies.\n */\nexport function faceMetricsFromTables(t: FaceMetricTables): FaceMetrics | undefined {\n const upem = t.unitsPerEm;\n if (!finite(upem) || upem <= 0) return undefined;\n const out: {\n ascent?: number; descent?: number;\n underline?: FaceRuleMetrics; strikethrough?: FaceRuleMetrics;\n superscript?: FaceScriptMetrics; subscript?: FaceScriptMetrics;\n xHeight?: number; capHeight?: number;\n } = {};\n const rule = (position: unknown, thickness: unknown): FaceRuleMetrics | undefined =>\n finite(position) && finite(thickness) && thickness > 0\n ? { offset: -position / upem, thickness: thickness / upem }\n : undefined;\n const script = (size: unknown, shift: unknown): FaceScriptMetrics | undefined =>\n finite(size) && finite(shift) && size > 0\n ? { size: size / upem, shift: shift / upem }\n : undefined;\n const underline = rule(t.post?.underlinePosition, t.post?.underlineThickness);\n const strikethrough = rule(t.os2?.yStrikeoutPosition, t.os2?.yStrikeoutSize);\n const superscript = script(t.os2?.ySuperscriptYSize, t.os2?.ySuperscriptYOffset);\n const sub = t.os2?.ySubscriptYOffset;\n const subscript = script(t.os2?.ySubscriptYSize, finite(sub) ? -sub : sub);\n const vertical = verticalMetricsFromTables(t);\n if (vertical) { out.ascent = vertical.ascent; out.descent = vertical.descent; }\n if (underline) out.underline = underline;\n if (strikethrough) out.strikethrough = strikethrough;\n if (superscript) out.superscript = superscript;\n if (subscript) out.subscript = subscript;\n const xHeight = t.os2?.sxHeight;\n const capHeight = t.os2?.sCapHeight;\n if (finite(xHeight) && xHeight > 0) out.xHeight = xHeight / upem;\n if (finite(capHeight) && capHeight > 0) out.capHeight = capHeight / upem;\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Validate an atlas JSON's `faceMetrics` block. Absent is fine. Present and\n * malformed throws, naming the entry.\n */\nexport function parseFaceMetrics(raw: unknown): FaceMetrics | undefined {\n if (raw === undefined) return undefined;\n if (typeof raw !== 'object' || raw === null) throw new Error('parseBmFont: faceMetrics must be an object');\n const r = raw as Record<string, unknown>;\n const out: Record<string, FaceRuleMetrics | FaceScriptMetrics | number> = {};\n if (r.ascent !== undefined || r.descent !== undefined) {\n if (!finite(r.ascent) || !finite(r.descent) || r.ascent + r.descent <= 0) {\n throw new Error('parseBmFont: malformed faceMetrics.ascent/descent');\n }\n out.ascent = r.ascent;\n out.descent = r.descent;\n }\n const pair = (key: string, a: string, b: string, positive: string): void => {\n const v = r[key];\n if (v === undefined) return;\n const e = v as Record<string, unknown> | null;\n if (typeof e !== 'object' || e === null || !finite(e[a]) || !finite(e[b]) || (e[positive] as number) <= 0) {\n throw new Error(`parseBmFont: malformed faceMetrics.${key}`);\n }\n out[key] = { [a]: e[a], [b]: e[b] } as unknown as FaceRuleMetrics | FaceScriptMetrics;\n };\n pair('underline', 'offset', 'thickness', 'thickness');\n pair('strikethrough', 'offset', 'thickness', 'thickness');\n pair('superscript', 'size', 'shift', 'size');\n pair('subscript', 'size', 'shift', 'size');\n for (const key of ['xHeight', 'capHeight'] as const) {\n const v = r[key];\n if (v === undefined) continue;\n if (!finite(v) || v <= 0) throw new Error(`parseBmFont: malformed faceMetrics.${key}`);\n out[key] = v;\n }\n return Object.keys(out).length > 0 ? (out as FaceMetrics) : undefined;\n}\n\n/**\n * The face metrics behind a resolved run — the outline face's on the outline\n * tier, the atlas's on the atlas tier. The canvas tier has none, so callers\n * fall back to their defaults.\n */\nexport function faceMetricsOf(result: {\n readonly entry: { readonly font: { readonly faceMetrics?: FaceMetrics } } | null;\n readonly outlineFace?: { readonly faceMetrics?: FaceMetrics };\n}): FaceMetrics | undefined {\n return result.outlineFace?.faceMetrics ?? result.entry?.font.faceMetrics;\n}\n","/**\n * BmFont JSON types and parser for the MSDF atlas format produced by\n * msdf-bmfont-xml. The parser builds accelerator maps (charMap, kerningMap)\n * for O(1) glyph and kerning lookup during layout.\n */\n\nimport { parseFaceMetrics, type FaceMetrics } from './faceMetrics';\n\n/** The face an atlas was generated from, and the size in pixels it was generated at. */\nexport interface BmFontInfo {\n face: string;\n size: number;\n}\n\n/** Font-wide vertical metrics and the atlas page dimensions, in pixels. */\nexport interface BmFontCommon {\n lineHeight: number;\n base: number;\n scaleW: number;\n scaleH: number;\n}\n\n/** One glyph: where it sits in the atlas page (`x`/`y`/`width`/`height`),\n * where to draw it relative to the pen (`xoffset`/`yoffset`), and how far the\n * pen then advances. */\nexport interface BmFontChar {\n id: number;\n x: number;\n y: number;\n width: number;\n height: number;\n xoffset: number;\n yoffset: number;\n xadvance: number;\n page: number;\n /** Set on a glyph whose atlas rect holds its own colors, on a page of the\n * dynamic tier's color set: an emoji. It is painted as it is, untinted. */\n color?: true;\n}\n\n/** A kerning pair: `amount` px to add to the advance when `second` follows\n * `first`. Codepoints, not glyph indices. */\nexport interface BmFontKerning {\n first: number;\n second: number;\n amount: number;\n}\n\n/** A parsed MSDF atlas: the BmFont record plus the `charMap` / `kerningMap`\n * accelerators layout reads per glyph. */\nexport interface BmFont {\n info: BmFontInfo;\n common: BmFontCommon;\n chars: BmFontChar[];\n kernings: BmFontKerning[];\n charMap: Map<number, BmFontChar>;\n kerningMap: Map<number, Map<number, number>>;\n /** The font's own decoration and script metrics, when the bake recorded\n * them. Not part of the BMFont format: `gen-font` adds it as a top-level\n * `faceMetrics` block, and an atlas without one leaves layout on its\n * defaults. */\n faceMetrics?: FaceMetrics;\n /** Atlas texels over which the distance field runs from 0 to 1, edge at\n * 0.5 — msdf-bmfont-xml's `distanceField.distanceRange`. Absent when the\n * file does not record it. */\n distanceRange?: number;\n}\n\n/** Two-glyph fixture for unit tests. */\nexport const FIXTURE_FONT = {\n info: { face: 'Inter', size: 32 },\n common: { lineHeight: 38, base: 29, scaleW: 512, scaleH: 512 },\n chars: [\n { id: 65, x: 0, y: 0, width: 22, height: 28, xoffset: 1, yoffset: 4, xadvance: 23, page: 0 },\n { id: 66, x: 24, y: 0, width: 20, height: 28, xoffset: 2, yoffset: 4, xadvance: 22, page: 0 },\n ],\n kernings: [\n { first: 65, second: 66, amount: -1 },\n ],\n};\n\n/** Validate a BmFont JSON document and build its lookup maps. Throws with the\n * missing or malformed field named. */\nexport function parseBmFont(raw: unknown): BmFont {\n if (typeof raw !== 'object' || raw === null) throw new Error('parseBmFont: expected object');\n const r = raw as Record<string, unknown>;\n\n if (!r.info || typeof r.info !== 'object') throw new Error('parseBmFont: missing info');\n if (!r.common || typeof r.common !== 'object') throw new Error('parseBmFont: missing common');\n if (!Array.isArray(r.chars)) throw new Error('parseBmFont: chars must be an array');\n\n const info = r.info as BmFontInfo;\n const common = r.common as BmFontCommon;\n // Every advance and quad divides by these, so a bad one is NaN geometry.\n const positive: Array<[string, unknown]> = [\n ['info.size', info.size], ['common.scaleW', common.scaleW], ['common.scaleH', common.scaleH],\n ];\n for (const [name, value] of positive) {\n if (typeof value !== 'number' || !(value > 0) || !Number.isFinite(value)) {\n throw new Error(`parseBmFont: ${name} must be a positive number`);\n }\n }\n if (typeof common.base !== 'number' || !Number.isFinite(common.base)) {\n throw new Error('parseBmFont: common.base must be a number');\n }\n const chars = r.chars as BmFontChar[];\n const kernings: BmFontKerning[] = Array.isArray(r.kernings)\n ? (r.kernings as BmFontKerning[])\n : [];\n\n const charMap = new Map<number, BmFontChar>();\n for (const ch of chars) charMap.set(ch.id, ch);\n\n const kerningMap = new Map<number, Map<number, number>>();\n for (const k of kernings) {\n let inner = kerningMap.get(k.first);\n if (!inner) { inner = new Map(); kerningMap.set(k.first, inner); }\n inner.set(k.second, k.amount);\n }\n\n const faceMetrics = parseFaceMetrics(r.faceMetrics);\n const range = (r.distanceField as { distanceRange?: unknown } | undefined)?.distanceRange;\n return {\n info, common, chars, kernings, charMap, kerningMap,\n ...(faceMetrics ? { faceMetrics } : {}),\n ...(typeof range === 'number' && range > 0 ? { distanceRange: range } : {}),\n };\n}\n","/**\n * `family` as it must appear in a CSS `font` shorthand or `font-family`.\n *\n * A generic keyword has to stay bare: quoted, `\"sans-serif\"` names a font\n * called sans-serif, which no machine has, and the browser falls back to its\n * default serif. A single named family is quoted so a name like `Font 3D`\n * still parses. Anything already holding a comma or a quote is a CSS family\n * list the caller wrote, and passes through as written.\n */\nexport function cssFamilyName(family: string): string {\n if (/[,\"']/.test(family)) return family;\n return GENERIC_FAMILIES.has(family.trim().toLowerCase()) ? family.trim() : JSON.stringify(family);\n}\n\nconst GENERIC_FAMILIES: ReadonlySet<string> = new Set([\n 'serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui',\n 'ui-serif', 'ui-sans-serif', 'ui-monospace', 'ui-rounded', 'math', 'emoji', 'fangsong',\n]);\n"]}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * The line, decoration and script metrics a font states for itself, in the
3
+ * kit's units: em fractions, with a rule's `offset` measured *down* from the
4
+ * baseline to its top edge (y grows down) and a script's `shift` positive
5
+ * for a rise.
6
+ *
7
+ * Both glyph tiers derive the record through {@link faceMetricsFromTables},
8
+ * so one font yields one set of numbers whichever tier serves a run.
9
+ */
10
+ /** One rule: the top edge's distance below the baseline, and its weight. */
11
+ interface FaceRuleMetrics {
12
+ readonly offset: number;
13
+ readonly thickness: number;
14
+ }
15
+ /** One script preset: `size` scales the inherited font size, `shift` raises
16
+ * (positive) or lowers (negative) the baseline, in inherited ems. */
17
+ interface FaceScriptMetrics {
18
+ readonly size: number;
19
+ readonly shift: number;
20
+ }
21
+ /** What a face says about its line, rules, scripts and letter heights.
22
+ * Every field is optional: a font may carry some of these tables and not
23
+ * others. */
24
+ interface FaceMetrics {
25
+ /** Baseline to the top of the face's line box, in ems — the ascent a
26
+ * browser sets this face with. See {@link verticalMetricsFromTables}. */
27
+ readonly ascent?: number;
28
+ /** Baseline to the bottom of the face's line box, in ems, positive
29
+ * downward. Present exactly when `ascent` is. */
30
+ readonly descent?: number;
31
+ readonly underline?: FaceRuleMetrics;
32
+ readonly strikethrough?: FaceRuleMetrics;
33
+ readonly superscript?: FaceScriptMetrics;
34
+ readonly subscript?: FaceScriptMetrics;
35
+ /** Height of a flat lowercase letter above the baseline, in ems
36
+ * (`OS/2.sxHeight`). */
37
+ readonly xHeight?: number;
38
+ /** Height of a flat capital above the baseline, in ems
39
+ * (`OS/2.sCapHeight`). */
40
+ readonly capHeight?: number;
41
+ }
42
+ /** The table fields {@link faceMetricsFromTables} reads, in font units, as
43
+ * the OpenType `post` and `OS/2` tables state them. */
44
+ interface FaceMetricTables {
45
+ unitsPerEm: number;
46
+ hhea?: {
47
+ ascender?: number;
48
+ descender?: number;
49
+ };
50
+ post?: {
51
+ underlinePosition?: number;
52
+ underlineThickness?: number;
53
+ };
54
+ os2?: {
55
+ fsSelection?: number;
56
+ sTypoAscender?: number;
57
+ sTypoDescender?: number;
58
+ usWinAscent?: number;
59
+ usWinDescent?: number;
60
+ yStrikeoutPosition?: number;
61
+ yStrikeoutSize?: number;
62
+ ySuperscriptYSize?: number;
63
+ ySuperscriptYOffset?: number;
64
+ ySubscriptYSize?: number;
65
+ ySubscriptYOffset?: number;
66
+ sxHeight?: number;
67
+ sCapHeight?: number;
68
+ };
69
+ }
70
+ /**
71
+ * The ascent and descent a browser sets this face with, in ems, descent
72
+ * positive downward.
73
+ *
74
+ * The OpenType rule: `OS/2` `sTypoAscender`/`sTypoDescender` when the font
75
+ * sets `USE_TYPO_METRICS`, otherwise `hhea`. Firefox, and every engine on
76
+ * Linux, follow it; Chromium and WebKit on macOS read `hhea` even when the
77
+ * flag is set, and the DOM edit overlay's measured baseline correction
78
+ * absorbs the difference there.
79
+ *
80
+ * Falls back to the typo pair, then the win pair, when `hhea` is absent or
81
+ * zero.
82
+ */
83
+ declare function verticalMetricsFromTables(t: FaceMetricTables): {
84
+ ascent: number;
85
+ descent: number;
86
+ } | undefined;
87
+ /**
88
+ * Convert raw table values to {@link FaceMetrics}.
89
+ *
90
+ * `post.underlinePosition` and `OS/2.yStrikeoutPosition` are the rule's top
91
+ * edge, positive above the baseline. `ySubscriptYOffset` is positive
92
+ * *downward*, unlike its superscript twin. A zero weight or size is a font
93
+ * that left the field blank, so that entry is dropped and the caller's
94
+ * default applies.
95
+ */
96
+ declare function faceMetricsFromTables(t: FaceMetricTables): FaceMetrics | undefined;
97
+ /**
98
+ * The face metrics behind a resolved run — the outline face's on the outline
99
+ * tier, the atlas's on the atlas tier. The canvas tier has none, so callers
100
+ * fall back to their defaults.
101
+ */
102
+ declare function faceMetricsOf(result: {
103
+ readonly entry: {
104
+ readonly font: {
105
+ readonly faceMetrics?: FaceMetrics;
106
+ };
107
+ } | null;
108
+ readonly outlineFace?: {
109
+ readonly faceMetrics?: FaceMetrics;
110
+ };
111
+ }): FaceMetrics | undefined;
112
+
113
+ /**
114
+ * BmFont JSON types and parser for the MSDF atlas format produced by
115
+ * msdf-bmfont-xml. The parser builds accelerator maps (charMap, kerningMap)
116
+ * for O(1) glyph and kerning lookup during layout.
117
+ */
118
+
119
+ /** The face an atlas was generated from, and the size in pixels it was generated at. */
120
+ interface BmFontInfo {
121
+ face: string;
122
+ size: number;
123
+ }
124
+ /** Font-wide vertical metrics and the atlas page dimensions, in pixels. */
125
+ interface BmFontCommon {
126
+ lineHeight: number;
127
+ base: number;
128
+ scaleW: number;
129
+ scaleH: number;
130
+ }
131
+ /** One glyph: where it sits in the atlas page (`x`/`y`/`width`/`height`),
132
+ * where to draw it relative to the pen (`xoffset`/`yoffset`), and how far the
133
+ * pen then advances. */
134
+ interface BmFontChar {
135
+ id: number;
136
+ x: number;
137
+ y: number;
138
+ width: number;
139
+ height: number;
140
+ xoffset: number;
141
+ yoffset: number;
142
+ xadvance: number;
143
+ page: number;
144
+ /** Set on a glyph whose atlas rect holds its own colors, on a page of the
145
+ * dynamic tier's color set: an emoji. It is painted as it is, untinted. */
146
+ color?: true;
147
+ }
148
+ /** A kerning pair: `amount` px to add to the advance when `second` follows
149
+ * `first`. Codepoints, not glyph indices. */
150
+ interface BmFontKerning {
151
+ first: number;
152
+ second: number;
153
+ amount: number;
154
+ }
155
+ /** A parsed MSDF atlas: the BmFont record plus the `charMap` / `kerningMap`
156
+ * accelerators layout reads per glyph. */
157
+ interface BmFont {
158
+ info: BmFontInfo;
159
+ common: BmFontCommon;
160
+ chars: BmFontChar[];
161
+ kernings: BmFontKerning[];
162
+ charMap: Map<number, BmFontChar>;
163
+ kerningMap: Map<number, Map<number, number>>;
164
+ /** The font's own decoration and script metrics, when the bake recorded
165
+ * them. Not part of the BMFont format: `gen-font` adds it as a top-level
166
+ * `faceMetrics` block, and an atlas without one leaves layout on its
167
+ * defaults. */
168
+ faceMetrics?: FaceMetrics;
169
+ /** Atlas texels over which the distance field runs from 0 to 1, edge at
170
+ * 0.5 — msdf-bmfont-xml's `distanceField.distanceRange`. Absent when the
171
+ * file does not record it. */
172
+ distanceRange?: number;
173
+ }
174
+ /** Two-glyph fixture for unit tests. */
175
+ declare const FIXTURE_FONT: {
176
+ info: {
177
+ face: string;
178
+ size: number;
179
+ };
180
+ common: {
181
+ lineHeight: number;
182
+ base: number;
183
+ scaleW: number;
184
+ scaleH: number;
185
+ };
186
+ chars: {
187
+ id: number;
188
+ x: number;
189
+ y: number;
190
+ width: number;
191
+ height: number;
192
+ xoffset: number;
193
+ yoffset: number;
194
+ xadvance: number;
195
+ page: number;
196
+ }[];
197
+ kernings: {
198
+ first: number;
199
+ second: number;
200
+ amount: number;
201
+ }[];
202
+ };
203
+ /** Validate a BmFont JSON document and build its lookup maps. Throws with the
204
+ * missing or malformed field named. */
205
+ declare function parseBmFont(raw: unknown): BmFont;
206
+
207
+ /**
208
+ * The style axis of a font variant, one declaration for the whole stack.
209
+ *
210
+ * Written inline as `'normal' | 'italic'` in half a dozen places before this,
211
+ * across the font/text package line — identical value sets, so nothing could
212
+ * drift until someone added `'oblique'`, and then it would have drifted
213
+ * silently in every place that had not been found.
214
+ */
215
+ type FontStyle = 'normal' | 'italic';
216
+
217
+ export { type BmFontChar as B, type FontStyle as F, type BmFont as a, type BmFontCommon as b, type BmFontInfo as c, type BmFontKerning as d, FIXTURE_FONT as e, type FaceMetricTables as f, type FaceMetrics as g, type FaceRuleMetrics as h, type FaceScriptMetrics as i, faceMetricsFromTables as j, faceMetricsOf as k, parseBmFont as p, verticalMetricsFromTables as v };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,45 @@
1
- import { R as ResolveResult, B as BmFont, a as BmFontChar, F as FontStyle } from './test-seams-BvULFsbo.js';
2
- export { b as BmFontCommon, c as BmFontInfo, d as BmFontKerning, C as CanvasFontEntry, D as DynamicFace, e as FIXTURE_FONT, f as FaceMetricTables, g as FaceMetrics, h as FaceRuleMetrics, i as FaceScriptMetrics, j as FontEntry, k as FontFallbackPolicy, l as FontFamilyFaces, m as FontRequest, n as FontVariant, G as GlyphTextureSink, O as OutlineFace, o as OutlineFaceInfo, p as OutlineFontOptions, q as OutlineParser, r as OutlineSource, s as OutlineStatus, t as OutlineVariant, u as RegisterFontOptions, v as RegisteredFont, T as TexSource, w as colorPageTextureId, x as cssFontFamily, y as cssFontFamilyLoading, z as dynamicPageTextureId, A as ensureFontTexture, E as faceMetricsFor, H as faceMetricsFromTables, I as faceMetricsOf, J as fontOutlineRegistry, K as fontPending, L as fontRegistry, M as getDefaultFontFamily, N as getFont, P as getFontFallbackPolicy, Q as glyphOutline, S as hasFontOutlines, U as isCanvasFont, V as listCanvasFonts, W as listFontOutlines, X as listFontWeights, Y as listFonts, Z as loadFontOutlines, _ as markAllFontsNotUploaded, $ as outlineMetrics, a0 as outlineStatus, a1 as parseBmFont, a2 as refreshCanvasFont, a3 as registerCanvasFont, a4 as registerFont, a5 as registerFontOutlines, a6 as resolveFontVariant, a7 as resolveGlyphFallback, a8 as setDefaultFontFamily, a9 as setFontFallbackPolicy, aa as syncColorPageTexture, ab as syncDynamicPageTexture, ac as textureCacheKey, ad as unregisterCanvasFont, ae as unregisterFontOutlines, af as verticalMetricsFromTables, ag as warmFonts } from './test-seams-BvULFsbo.js';
1
+ import { B as BmFontChar, a as BmFont, F as FontStyle } from './fontStyle-D1y21YZ9.js';
2
+ export { b as BmFontCommon, c as BmFontInfo, d as BmFontKerning, e as FIXTURE_FONT, f as FaceMetricTables, g as FaceMetrics, h as FaceRuleMetrics, i as FaceScriptMetrics, j as faceMetricsFromTables, k as faceMetricsOf, p as parseBmFont, v as verticalMetricsFromTables } from './fontStyle-D1y21YZ9.js';
3
+ import { R as ResolveResult } from './test-seams-DvdFz4GW.js';
4
+ export { C as CanvasFontEntry, P as DYNAMIC_PAGE_SIZE, D as DynamicFace, F as FontEntry, a as FontFallbackPolicy, b as FontFamilyFaces, c as FontRequest, d as FontVariant, G as GlyphTextureSink, O as OutlineFace, e as OutlineFaceInfo, f as OutlineFontOptions, g as OutlineParser, h as OutlineSource, i as OutlineStatus, j as OutlineVariant, k as RegisterFontOptions, l as RegisteredFont, T as TexSource, m as colorPageTextureId, n as cssFontFamily, o as cssFontFamilyLoading, p as dynamicPageTextureId, q as ensureFontTexture, r as faceMetricsFor, s as fontOutlineRegistry, t as fontPending, u as fontRegistry, v as getDefaultFontFamily, w as getFont, x as getFontFallbackPolicy, y as glyphOutline, z as hasFontOutlines, A as isCanvasFont, B as listCanvasFonts, E as listFontOutlines, H as listFontWeights, I as listFonts, J as loadFontOutlines, K as markAllFontsNotUploaded, L as outlineMetrics, M as outlineStatus, N as refreshCanvasFont, Q as registerCanvasFont, S as registerFont, U as registerFontOutlines, V as resolveFontVariant, W as resolveGlyphFallback, X as setDefaultFontFamily, Y as setFontFallbackPolicy, Z as sharpColorPageTextureId, _ as syncColorPageTexture, $ as syncDynamicPageTexture, a0 as syncSharpColorPageTexture, a1 as textureCacheKey, a2 as unregisterCanvasFont, a3 as unregisterFontOutlines, a4 as warmFonts } from './test-seams-DvdFz4GW.js';
5
+ export { cssFamilyName } from './metrics.js';
3
6
  import '@weasel-js/registry';
4
7
 
8
+ /**
9
+ * Color glyphs baked again larger. A color glyph is a bitmap baked at
10
+ * `BAKE_SIZE`, so it blurs when drawn much bigger than that; this re-rasters
11
+ * it at `BAKE_SIZE × 2^level` onto pages of its own, the way a vector image
12
+ * re-rasterizes in power-of-two steps. One emoji at the largest level takes
13
+ * the room of sixty at the base size, so these pages fill and empty without
14
+ * taking the base bakes with them.
15
+ */
16
+
17
+ /** The largest level baked: `BAKE_SIZE × 2^3`, 384px. */
18
+ declare const MAX_SHARP_LEVEL = 3;
19
+ /** A color glyph baked at `BAKE_SIZE × 2^level`. */
20
+ interface SharperColorGlyph {
21
+ level: number;
22
+ /**
23
+ * Its rect on sharp color page `glyph.page` (`sharpColorPageTextureId`), in
24
+ * that bake's texels. Its `xoffset` and `yoffset` are in the base bake's px,
25
+ * as the base record's are, so both place from the same pen; it covers
26
+ * `width / 2^level` of them.
27
+ */
28
+ glyph: BmFontChar;
29
+ }
30
+ /**
31
+ * A bake of `char`, a base color bake, sharper than it for drawing at `scale`
32
+ * device pixels to one of its texels: the power of two at or above `scale`,
33
+ * up to {@link MAX_SHARP_LEVEL}. Asks for that bake if it has not been, and
34
+ * until it lands serves the sharpest level that has. Null when the base bake
35
+ * is the sharpest there is.
36
+ */
37
+ declare function sharperColorGlyph(char: BmFontChar, scale: number): SharperColorGlyph | null;
38
+
5
39
  /**
6
40
  * Baking measured glyphs into the dynamic atlas's pages: a few a frame, the
7
- * rest on later ticks, and every page emptied whole when one set fills.
41
+ * rest on later ticks, and every page emptied whole when the field or color
42
+ * set fills. The sharp color set, larger bakes of color glyphs, empties alone.
8
43
  */
9
44
 
10
45
  /** How many glyphs the dynamic atlas will rasterize synchronously before
@@ -51,17 +86,6 @@ declare function subscribeGlyphReady(cb: () => void): () => void;
51
86
  */
52
87
  declare function faceGeneration(): number;
53
88
 
54
- /**
55
- * `family` as it must appear in a CSS `font` shorthand or `font-family`.
56
- *
57
- * A generic keyword has to stay bare: quoted, `"sans-serif"` names a font
58
- * called sans-serif, which no machine has, and the browser falls back to its
59
- * default serif. A single named family is quoted so a name like `Font 3D`
60
- * still parses. Anything already holding a comma or a quote is a CSS family
61
- * list the caller wrote, and passes through as written.
62
- */
63
- declare function cssFamilyName(family: string): string;
64
-
65
89
  /**
66
90
  * One shape for the advances, kerning and baseline of whichever tier resolved
67
91
  * a face. A baked atlas and the canvas tier measure in their bake-size pixels
@@ -253,5 +277,19 @@ declare const GLYPH_COVERAGE_GLSL = "\nfloat median(float r, float g, float b) {
253
277
  * atlas that is not registered.
254
278
  */
255
279
  declare function glyphFieldScale(source: 'atlas' | 'canvas', family: string, weight: number, style: FontStyle): readonly [number, number] | undefined;
280
+ /**
281
+ * How far the field threshold drops for a glyph faked bold from a lighter
282
+ * face. Tuned on Inter: it thickens strokes about a pixel at 16px without
283
+ * breaking glyph topology.
284
+ */
285
+ declare const SYNTH_BOLD_AMOUNT = 0.08;
286
+ /**
287
+ * How far synthetic bold moves each edge of a glyph outward, in em, for the
288
+ * atlas that serves it: `SYNTH_BOLD_AMOUNT` of the field's span, which is
289
+ * `distanceRange` texels in a baked MSDF atlas and `SDF_RADIUS` in a runtime
290
+ * canvas page, over the atlas's texels per em. `undefined` for an atlas that
291
+ * is not registered.
292
+ */
293
+ declare function syntheticBoldGrowth(source: 'atlas' | 'canvas', family: string, weight: number, style: FontStyle): number | undefined;
256
294
 
257
- export { BmFont, BmFontChar, DEFAULT_BAKE_BUDGET, FontStyle, GLYPH_COVERAGE_GLSL, GLYPH_MODE_MSDF, GLYPH_MODE_R8, type GlyphMetrics, type LocalFontOutlinesOptions, type LocalFontOutlinesResult, ResolveResult, type ResolvedGlyph, canQueryLocalFonts, cssFamilyName, enableLocalFontOutlines, faceGeneration, glyphFieldScale, glyphGeneration, glyphIn, metricsOf, parseFontStyle, resetBakeBudget, resolveColorCluster, resolveGlyph, subscribeGlyphReady, warnNoMetrics };
295
+ export { BmFont, BmFontChar, DEFAULT_BAKE_BUDGET, FontStyle, GLYPH_COVERAGE_GLSL, GLYPH_MODE_MSDF, GLYPH_MODE_R8, type GlyphMetrics, type LocalFontOutlinesOptions, type LocalFontOutlinesResult, MAX_SHARP_LEVEL, ResolveResult, type ResolvedGlyph, SYNTH_BOLD_AMOUNT, type SharperColorGlyph, canQueryLocalFonts, enableLocalFontOutlines, faceGeneration, glyphFieldScale, glyphGeneration, glyphIn, metricsOf, parseFontStyle, resetBakeBudget, resolveColorCluster, resolveGlyph, sharperColorGlyph, subscribeGlyphReady, syntheticBoldGrowth, warnNoMetrics };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
- import { fontPending, fallbackWarningClaimed, claimFallbackWarning, resolveGlyphFallback, registerFontOutlines, createOpenTypeParser, getFont, PAGE_SIZE, SDF_RADIUS } from './chunk-NM6K6M4Y.js';
2
- export { DEFAULT_BAKE_BUDGET, FIXTURE_FONT, colorPageTextureId, cssFamilyName, cssFontFamily, cssFontFamilyLoading, dynamicPageTextureId, ensureFontTexture, faceGeneration, faceMetricsFor, faceMetricsFromTables, faceMetricsOf, fontOutlineRegistry, fontPending, fontRegistry, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFontWeights, listFonts, loadFontOutlines, markAllFontsNotUploaded, outlineMetrics, outlineStatus, parseBmFont, refreshCanvasFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, subscribeGlyphReady, syncColorPageTexture, syncDynamicPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines, verticalMetricsFromTables, warmFonts } from './chunk-NM6K6M4Y.js';
1
+ import { fontPending, fallbackWarningClaimed, claimFallbackWarning, resolveGlyphFallback, registerFontOutlines, createOpenTypeParser, getFont, SDF_RADIUS, BAKE_SIZE, PAGE_SIZE } from './chunk-RECWJ5LR.js';
2
+ export { DEFAULT_BAKE_BUDGET, PAGE_SIZE as DYNAMIC_PAGE_SIZE, MAX_SHARP_LEVEL, colorPageTextureId, cssFontFamily, cssFontFamilyLoading, dynamicPageTextureId, ensureFontTexture, faceGeneration, faceMetricsFor, fontOutlineRegistry, fontPending, fontRegistry, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFontWeights, listFonts, loadFontOutlines, markAllFontsNotUploaded, outlineMetrics, outlineStatus, refreshCanvasFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, sharpColorPageTextureId, sharperColorGlyph, subscribeGlyphReady, syncColorPageTexture, syncDynamicPageTexture, syncSharpColorPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines, warmFonts } from './chunk-RECWJ5LR.js';
3
+ export { FIXTURE_FONT, cssFamilyName, faceMetricsFromTables, faceMetricsOf, parseBmFont, verticalMetricsFromTables } from './chunk-XQPRAGHF.js';
3
4
 
4
5
  // src/defaultIgnorable.ts
5
6
  var RANGES = [
@@ -249,7 +250,14 @@ function glyphFieldScale(source, family, weight, style) {
249
250
  const range = font.distanceRange ?? DEFAULT_MSDF_RANGE;
250
251
  return [font.common.scaleW / range, font.common.scaleH / range];
251
252
  }
253
+ var SYNTH_BOLD_AMOUNT = 0.08;
254
+ function syntheticBoldGrowth(source, family, weight, style) {
255
+ if (source === "canvas") return SYNTH_BOLD_AMOUNT * SDF_RADIUS / BAKE_SIZE;
256
+ const font = getFont(family, weight, style)?.font;
257
+ if (!font) return void 0;
258
+ return SYNTH_BOLD_AMOUNT * (font.distanceRange ?? DEFAULT_MSDF_RANGE) / font.info.size;
259
+ }
252
260
 
253
- export { GLYPH_COVERAGE_GLSL, GLYPH_MODE_MSDF, GLYPH_MODE_R8, canQueryLocalFonts, enableLocalFontOutlines, glyphFieldScale, glyphIn, metricsOf, parseFontStyle, resolveColorCluster, resolveGlyph, warnNoMetrics };
261
+ export { GLYPH_COVERAGE_GLSL, GLYPH_MODE_MSDF, GLYPH_MODE_R8, SYNTH_BOLD_AMOUNT, canQueryLocalFonts, enableLocalFontOutlines, glyphFieldScale, glyphIn, metricsOf, parseFontStyle, resolveColorCluster, resolveGlyph, syntheticBoldGrowth, warnNoMetrics };
254
262
  //# sourceMappingURL=index.js.map
255
263
  //# sourceMappingURL=index.js.map