@weasel-js/font 1.7.0 → 1.7.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.
- package/dist/{chunk-CDPTPB26.js → chunk-RYN4NYX4.js} +570 -25
- package/dist/chunk-RYN4NYX4.js.map +1 -0
- package/dist/index.d.ts +33 -18
- package/dist/index.js +19 -6
- package/dist/index.js.map +1 -1
- package/dist/{test-seams-D1ex7UxJ.d.ts → test-seams-Df2Zqwk8.d.ts} +356 -90
- package/dist/test-seams.d.ts +1 -1
- package/dist/test-seams.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-CDPTPB26.js.map +0 -1
|
@@ -1,5 +1,82 @@
|
|
|
1
1
|
import { createReflectable } from '@weasel-js/registry';
|
|
2
2
|
|
|
3
|
+
// src/faceMetrics.ts
|
|
4
|
+
var finite = (n) => typeof n === "number" && Number.isFinite(n);
|
|
5
|
+
var USE_TYPO_METRICS = 1 << 7;
|
|
6
|
+
function verticalMetricsFromTables(t) {
|
|
7
|
+
const upem = t.unitsPerEm;
|
|
8
|
+
if (!finite(upem) || upem <= 0) return void 0;
|
|
9
|
+
const os2 = t.os2;
|
|
10
|
+
const pair = (a, d, down) => finite(a) && finite(d) && a + (down ? d : -d) > 0 ? { ascent: a / upem, descent: (down ? d : -d) / upem } : void 0;
|
|
11
|
+
const typo = pair(os2?.sTypoAscender, os2?.sTypoDescender, false);
|
|
12
|
+
const hhea = pair(t.hhea?.ascender, t.hhea?.descender, false);
|
|
13
|
+
const win = pair(os2?.usWinAscent, os2?.usWinDescent, true);
|
|
14
|
+
const useTypo = finite(os2?.fsSelection) && (os2.fsSelection & USE_TYPO_METRICS) !== 0;
|
|
15
|
+
return (useTypo ? typo : void 0) ?? hhea ?? typo ?? win;
|
|
16
|
+
}
|
|
17
|
+
function faceMetricsFromTables(t) {
|
|
18
|
+
const upem = t.unitsPerEm;
|
|
19
|
+
if (!finite(upem) || upem <= 0) return void 0;
|
|
20
|
+
const out = {};
|
|
21
|
+
const rule = (position, thickness) => finite(position) && finite(thickness) && thickness > 0 ? { offset: -position / upem, thickness: thickness / upem } : void 0;
|
|
22
|
+
const script = (size, shift) => finite(size) && finite(shift) && size > 0 ? { size: size / upem, shift: shift / upem } : void 0;
|
|
23
|
+
const underline = rule(t.post?.underlinePosition, t.post?.underlineThickness);
|
|
24
|
+
const strikethrough = rule(t.os2?.yStrikeoutPosition, t.os2?.yStrikeoutSize);
|
|
25
|
+
const superscript = script(t.os2?.ySuperscriptYSize, t.os2?.ySuperscriptYOffset);
|
|
26
|
+
const sub = t.os2?.ySubscriptYOffset;
|
|
27
|
+
const subscript = script(t.os2?.ySubscriptYSize, finite(sub) ? -sub : sub);
|
|
28
|
+
const vertical = verticalMetricsFromTables(t);
|
|
29
|
+
if (vertical) {
|
|
30
|
+
out.ascent = vertical.ascent;
|
|
31
|
+
out.descent = vertical.descent;
|
|
32
|
+
}
|
|
33
|
+
if (underline) out.underline = underline;
|
|
34
|
+
if (strikethrough) out.strikethrough = strikethrough;
|
|
35
|
+
if (superscript) out.superscript = superscript;
|
|
36
|
+
if (subscript) out.subscript = subscript;
|
|
37
|
+
const xHeight = t.os2?.sxHeight;
|
|
38
|
+
const capHeight = t.os2?.sCapHeight;
|
|
39
|
+
if (finite(xHeight) && xHeight > 0) out.xHeight = xHeight / upem;
|
|
40
|
+
if (finite(capHeight) && capHeight > 0) out.capHeight = capHeight / upem;
|
|
41
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
42
|
+
}
|
|
43
|
+
function parseFaceMetrics(raw) {
|
|
44
|
+
if (raw === void 0) return void 0;
|
|
45
|
+
if (typeof raw !== "object" || raw === null) throw new Error("parseBmFont: faceMetrics must be an object");
|
|
46
|
+
const r = raw;
|
|
47
|
+
const out = {};
|
|
48
|
+
if (r.ascent !== void 0 || r.descent !== void 0) {
|
|
49
|
+
if (!finite(r.ascent) || !finite(r.descent) || r.ascent + r.descent <= 0) {
|
|
50
|
+
throw new Error("parseBmFont: malformed faceMetrics.ascent/descent");
|
|
51
|
+
}
|
|
52
|
+
out.ascent = r.ascent;
|
|
53
|
+
out.descent = r.descent;
|
|
54
|
+
}
|
|
55
|
+
const pair = (key, a, b, positive) => {
|
|
56
|
+
const v = r[key];
|
|
57
|
+
if (v === void 0) return;
|
|
58
|
+
const e = v;
|
|
59
|
+
if (typeof e !== "object" || e === null || !finite(e[a]) || !finite(e[b]) || e[positive] <= 0) {
|
|
60
|
+
throw new Error(`parseBmFont: malformed faceMetrics.${key}`);
|
|
61
|
+
}
|
|
62
|
+
out[key] = { [a]: e[a], [b]: e[b] };
|
|
63
|
+
};
|
|
64
|
+
pair("underline", "offset", "thickness", "thickness");
|
|
65
|
+
pair("strikethrough", "offset", "thickness", "thickness");
|
|
66
|
+
pair("superscript", "size", "shift", "size");
|
|
67
|
+
pair("subscript", "size", "shift", "size");
|
|
68
|
+
for (const key of ["xHeight", "capHeight"]) {
|
|
69
|
+
const v = r[key];
|
|
70
|
+
if (v === void 0) continue;
|
|
71
|
+
if (!finite(v) || v <= 0) throw new Error(`parseBmFont: malformed faceMetrics.${key}`);
|
|
72
|
+
out[key] = v;
|
|
73
|
+
}
|
|
74
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
75
|
+
}
|
|
76
|
+
function faceMetricsOf(result) {
|
|
77
|
+
return result.outlineFace?.faceMetrics ?? result.entry?.font.faceMetrics;
|
|
78
|
+
}
|
|
79
|
+
|
|
3
80
|
// src/FontAtlas.ts
|
|
4
81
|
var FIXTURE_FONT = {
|
|
5
82
|
info: { face: "Inter", size: 32 },
|
|
@@ -33,7 +110,18 @@ function parseBmFont(raw) {
|
|
|
33
110
|
}
|
|
34
111
|
inner.set(k.second, k.amount);
|
|
35
112
|
}
|
|
36
|
-
|
|
113
|
+
const faceMetrics = parseFaceMetrics(r.faceMetrics);
|
|
114
|
+
const range = r.distanceField?.distanceRange;
|
|
115
|
+
return {
|
|
116
|
+
info,
|
|
117
|
+
common,
|
|
118
|
+
chars,
|
|
119
|
+
kernings,
|
|
120
|
+
charMap,
|
|
121
|
+
kerningMap,
|
|
122
|
+
...faceMetrics ? { faceMetrics } : {},
|
|
123
|
+
...typeof range === "number" && range > 0 ? { distanceRange: range } : {}
|
|
124
|
+
};
|
|
37
125
|
}
|
|
38
126
|
|
|
39
127
|
// src/glyphReady.ts
|
|
@@ -60,13 +148,17 @@ function _clearGlyphReadySubscribers() {
|
|
|
60
148
|
var policy = "substitute";
|
|
61
149
|
var defaultFamily = null;
|
|
62
150
|
function setFontFallbackPolicy(next) {
|
|
151
|
+
if (next === policy) return;
|
|
63
152
|
policy = next;
|
|
153
|
+
notifyGlyphReady();
|
|
64
154
|
}
|
|
65
155
|
function getFontFallbackPolicy() {
|
|
66
156
|
return policy;
|
|
67
157
|
}
|
|
68
158
|
function setDefaultFontFamily(family) {
|
|
159
|
+
if (family === defaultFamily) return;
|
|
69
160
|
defaultFamily = family;
|
|
161
|
+
notifyGlyphReady();
|
|
70
162
|
}
|
|
71
163
|
function getDefaultFontFamily() {
|
|
72
164
|
return defaultFamily;
|
|
@@ -205,8 +297,9 @@ function alphaToSdf(alpha, width, height, radius, cutoff) {
|
|
|
205
297
|
// src/dynamic/glyphRasterizer.ts
|
|
206
298
|
var BAKE_SIZE = 48;
|
|
207
299
|
var PAD = 8;
|
|
208
|
-
|
|
209
|
-
|
|
300
|
+
var METRICS_SIZE = 1e3;
|
|
301
|
+
function cssFontString(weight, style, family, size = BAKE_SIZE) {
|
|
302
|
+
return `${style === "italic" ? "italic " : ""}${weight} ${size}px ${JSON.stringify(family)}`;
|
|
210
303
|
}
|
|
211
304
|
function createCanvasRasterizer() {
|
|
212
305
|
let canvas;
|
|
@@ -221,18 +314,19 @@ function createCanvasRasterizer() {
|
|
|
221
314
|
}
|
|
222
315
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
223
316
|
if (!ctx) throw new Error("weasel DynamicGlyphAtlas: 2D context unavailable");
|
|
224
|
-
function setFont(family, weight, style) {
|
|
225
|
-
ctx.font = cssFontString(weight, style, family);
|
|
317
|
+
function setFont(family, weight, style, size = BAKE_SIZE) {
|
|
318
|
+
ctx.font = cssFontString(weight, style, family, size);
|
|
226
319
|
ctx.textBaseline = "alphabetic";
|
|
227
320
|
ctx.textAlign = "left";
|
|
228
321
|
}
|
|
229
322
|
return {
|
|
230
323
|
faceMetrics(family, weight, style) {
|
|
231
|
-
setFont(family, weight, style);
|
|
324
|
+
setFont(family, weight, style, METRICS_SIZE);
|
|
232
325
|
const m = ctx.measureText("Hg");
|
|
326
|
+
const k = BAKE_SIZE / METRICS_SIZE;
|
|
233
327
|
return {
|
|
234
|
-
ascent: m.fontBoundingBoxAscent ??
|
|
235
|
-
descent: m.fontBoundingBoxDescent ??
|
|
328
|
+
ascent: (m.fontBoundingBoxAscent ?? METRICS_SIZE * 0.8) * k,
|
|
329
|
+
descent: (m.fontBoundingBoxDescent ?? METRICS_SIZE * 0.2) * k
|
|
236
330
|
};
|
|
237
331
|
},
|
|
238
332
|
rasterize(family, weight, style, codepoint) {
|
|
@@ -294,8 +388,10 @@ function getRasterizer() {
|
|
|
294
388
|
return rasterizer;
|
|
295
389
|
}
|
|
296
390
|
function registerCanvasFont(family) {
|
|
391
|
+
if (isExplicitCanvasFont(family)) return;
|
|
297
392
|
canvasFamilies.add(family);
|
|
298
393
|
autoEnrolledFamilies.delete(family);
|
|
394
|
+
notifyGlyphReady();
|
|
299
395
|
}
|
|
300
396
|
function isCanvasFont(family) {
|
|
301
397
|
if (!canvasFamilies.has(family)) return false;
|
|
@@ -318,11 +414,13 @@ function isExplicitCanvasFont(family) {
|
|
|
318
414
|
return canvasFamilies.has(family) && !autoEnrolledFamilies.has(family);
|
|
319
415
|
}
|
|
320
416
|
function unregisterCanvasFont(family) {
|
|
417
|
+
if (!canvasFamilies.has(family)) return;
|
|
321
418
|
canvasFamilies.delete(family);
|
|
322
419
|
autoEnrolledFamilies.delete(family);
|
|
323
420
|
for (const key of [...faces.keys()]) {
|
|
324
421
|
if (faces.get(key).family === family) faces.delete(key);
|
|
325
422
|
}
|
|
423
|
+
notifyGlyphReady();
|
|
326
424
|
}
|
|
327
425
|
function getDynamicFace(family, weight, style) {
|
|
328
426
|
const key = `${family}|${weight}|${style}`;
|
|
@@ -343,7 +441,9 @@ function getDynamicFace(family, weight, style) {
|
|
|
343
441
|
kernings: [],
|
|
344
442
|
// no kerning in v1 (measured-pair kerning is future work)
|
|
345
443
|
charMap: /* @__PURE__ */ new Map(),
|
|
346
|
-
kerningMap: /* @__PURE__ */ new Map()
|
|
444
|
+
kerningMap: /* @__PURE__ */ new Map(),
|
|
445
|
+
// Unrounded, unlike `common`: layout places the baseline from these.
|
|
446
|
+
faceMetrics: { ascent: metrics.ascent / BAKE_SIZE, descent: metrics.descent / BAKE_SIZE }
|
|
347
447
|
};
|
|
348
448
|
const face = {
|
|
349
449
|
family,
|
|
@@ -600,6 +700,163 @@ function sfntFromCollection(bytes, postScriptName) {
|
|
|
600
700
|
return { bytes: extractFont(bytes, view, offsets[0]), matched: !postScriptName };
|
|
601
701
|
}
|
|
602
702
|
|
|
703
|
+
// src/outline/gposKerning.ts
|
|
704
|
+
function gposPairKerning(bytes) {
|
|
705
|
+
const v = new DataView(bytes);
|
|
706
|
+
const version = v.byteLength >= 12 ? tag(v, 0) : "";
|
|
707
|
+
if (version !== "\0\0\0" && version !== "true" && version !== "OTTO") return null;
|
|
708
|
+
const gpos = tableOffset(v, "GPOS");
|
|
709
|
+
if (gpos === null) return null;
|
|
710
|
+
const featureList = gpos + v.getUint16(gpos + 6);
|
|
711
|
+
const lookupList = gpos + v.getUint16(gpos + 8);
|
|
712
|
+
const lookupIndexes = /* @__PURE__ */ new Set();
|
|
713
|
+
const featureCount = v.getUint16(featureList);
|
|
714
|
+
for (let i = 0; i < featureCount; i++) {
|
|
715
|
+
const rec = featureList + 2 + i * 6;
|
|
716
|
+
if (tag(v, rec) !== "kern") continue;
|
|
717
|
+
const feature = featureList + v.getUint16(rec + 4);
|
|
718
|
+
const count = v.getUint16(feature + 2);
|
|
719
|
+
for (let j = 0; j < count; j++) lookupIndexes.add(v.getUint16(feature + 4 + j * 2));
|
|
720
|
+
}
|
|
721
|
+
if (lookupIndexes.size === 0) return null;
|
|
722
|
+
const lookups = [];
|
|
723
|
+
for (const index of [...lookupIndexes].sort((a, b) => a - b)) {
|
|
724
|
+
const lookup = lookupList + v.getUint16(lookupList + 2 + index * 2);
|
|
725
|
+
const type = v.getUint16(lookup);
|
|
726
|
+
const subtables = [];
|
|
727
|
+
const count = v.getUint16(lookup + 4);
|
|
728
|
+
for (let j = 0; j < count; j++) {
|
|
729
|
+
let sub = lookup + v.getUint16(lookup + 6 + j * 2);
|
|
730
|
+
let subType = type;
|
|
731
|
+
if (type === 9) {
|
|
732
|
+
subType = v.getUint16(sub + 2);
|
|
733
|
+
sub += v.getUint32(sub + 4);
|
|
734
|
+
}
|
|
735
|
+
if (subType === 2) subtables.push(sub);
|
|
736
|
+
}
|
|
737
|
+
if (subtables.length > 0) lookups.push(subtables);
|
|
738
|
+
}
|
|
739
|
+
const memo = /* @__PURE__ */ new Map();
|
|
740
|
+
return (left, right) => {
|
|
741
|
+
const key = left * 65536 + right;
|
|
742
|
+
const hit = memo.get(key);
|
|
743
|
+
if (hit !== void 0) return hit;
|
|
744
|
+
let total = 0;
|
|
745
|
+
for (const subtables of lookups) {
|
|
746
|
+
for (const sub of subtables) {
|
|
747
|
+
const value = pairValue(v, sub, left, right);
|
|
748
|
+
if (value !== null) {
|
|
749
|
+
total += value;
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
memo.set(key, total);
|
|
755
|
+
return total;
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
function tag(v, at) {
|
|
759
|
+
return String.fromCharCode(v.getUint8(at), v.getUint8(at + 1), v.getUint8(at + 2), v.getUint8(at + 3));
|
|
760
|
+
}
|
|
761
|
+
function tableOffset(v, name) {
|
|
762
|
+
const count = v.getUint16(4);
|
|
763
|
+
for (let i = 0; i < count; i++) {
|
|
764
|
+
const rec = 12 + i * 16;
|
|
765
|
+
if (tag(v, rec) === name) return v.getUint32(rec + 8);
|
|
766
|
+
}
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
function valueSize(format) {
|
|
770
|
+
let n = 0;
|
|
771
|
+
for (let f = format; f; f >>= 1) n += f & 1;
|
|
772
|
+
return n * 2;
|
|
773
|
+
}
|
|
774
|
+
function xAdvance(v, at, format) {
|
|
775
|
+
if (!(format & 4)) return 0;
|
|
776
|
+
return v.getInt16(at + (format & 1 ? 2 : 0) + (format & 2 ? 2 : 0));
|
|
777
|
+
}
|
|
778
|
+
function pairValue(v, sub, left, right) {
|
|
779
|
+
const format = v.getUint16(sub);
|
|
780
|
+
const covIndex = coverageIndex(v, sub + v.getUint16(sub + 2), left);
|
|
781
|
+
if (covIndex < 0) return null;
|
|
782
|
+
const vf1 = v.getUint16(sub + 4);
|
|
783
|
+
const vf2 = v.getUint16(sub + 6);
|
|
784
|
+
const recordSize = 2 + valueSize(vf1) + valueSize(vf2);
|
|
785
|
+
if (format === 1) {
|
|
786
|
+
const pairSet = sub + v.getUint16(sub + 10 + covIndex * 2);
|
|
787
|
+
let lo = 0;
|
|
788
|
+
let hi = v.getUint16(pairSet) - 1;
|
|
789
|
+
while (lo <= hi) {
|
|
790
|
+
const mid = lo + hi >> 1;
|
|
791
|
+
const rec = pairSet + 2 + mid * recordSize;
|
|
792
|
+
const second = v.getUint16(rec);
|
|
793
|
+
if (second === right) return xAdvance(v, rec + 2, vf1);
|
|
794
|
+
if (second < right) lo = mid + 1;
|
|
795
|
+
else hi = mid - 1;
|
|
796
|
+
}
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
if (format === 2) {
|
|
800
|
+
const class1 = classOf(v, sub + v.getUint16(sub + 8), left);
|
|
801
|
+
const class2 = classOf(v, sub + v.getUint16(sub + 10), right);
|
|
802
|
+
const class1Count = v.getUint16(sub + 12);
|
|
803
|
+
const class2Count = v.getUint16(sub + 14);
|
|
804
|
+
if (class1 >= class1Count || class2 >= class2Count) return null;
|
|
805
|
+
const rec = sub + 16 + (class1 * class2Count + class2) * (recordSize - 2);
|
|
806
|
+
return xAdvance(v, rec, vf1);
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
function coverageIndex(v, cov, glyph) {
|
|
811
|
+
const format = v.getUint16(cov);
|
|
812
|
+
const count = v.getUint16(cov + 2);
|
|
813
|
+
let lo = 0;
|
|
814
|
+
let hi = count - 1;
|
|
815
|
+
if (format === 1) {
|
|
816
|
+
while (lo <= hi) {
|
|
817
|
+
const mid = lo + hi >> 1;
|
|
818
|
+
const g = v.getUint16(cov + 4 + mid * 2);
|
|
819
|
+
if (g === glyph) return mid;
|
|
820
|
+
if (g < glyph) lo = mid + 1;
|
|
821
|
+
else hi = mid - 1;
|
|
822
|
+
}
|
|
823
|
+
return -1;
|
|
824
|
+
}
|
|
825
|
+
if (format === 2) {
|
|
826
|
+
while (lo <= hi) {
|
|
827
|
+
const mid = lo + hi >> 1;
|
|
828
|
+
const rec = cov + 4 + mid * 6;
|
|
829
|
+
const start = v.getUint16(rec);
|
|
830
|
+
const end = v.getUint16(rec + 2);
|
|
831
|
+
if (glyph < start) hi = mid - 1;
|
|
832
|
+
else if (glyph > end) lo = mid + 1;
|
|
833
|
+
else return v.getUint16(rec + 4) + glyph - start;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return -1;
|
|
837
|
+
}
|
|
838
|
+
function classOf(v, def, glyph) {
|
|
839
|
+
const format = v.getUint16(def);
|
|
840
|
+
if (format === 1) {
|
|
841
|
+
const start = v.getUint16(def + 2);
|
|
842
|
+
const count = v.getUint16(def + 4);
|
|
843
|
+
const i = glyph - start;
|
|
844
|
+
return i >= 0 && i < count ? v.getUint16(def + 6 + i * 2) : 0;
|
|
845
|
+
}
|
|
846
|
+
if (format === 2) {
|
|
847
|
+
let lo = 0;
|
|
848
|
+
let hi = v.getUint16(def + 2) - 1;
|
|
849
|
+
while (lo <= hi) {
|
|
850
|
+
const mid = lo + hi >> 1;
|
|
851
|
+
const rec = def + 4 + mid * 6;
|
|
852
|
+
if (glyph < v.getUint16(rec)) hi = mid - 1;
|
|
853
|
+
else if (glyph > v.getUint16(rec + 2)) lo = mid + 1;
|
|
854
|
+
else return v.getUint16(rec + 4);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return 0;
|
|
858
|
+
}
|
|
859
|
+
|
|
603
860
|
// src/outline/opentypeParser.ts
|
|
604
861
|
var modulePromise = null;
|
|
605
862
|
function loadOpenType() {
|
|
@@ -610,11 +867,14 @@ function parserOf(ns) {
|
|
|
610
867
|
const interop = ns;
|
|
611
868
|
return interop.default?.parse ?? ns.parse;
|
|
612
869
|
}
|
|
613
|
-
function faceFor(font) {
|
|
870
|
+
function faceFor(font, gpos) {
|
|
614
871
|
const upem = font.unitsPerEm;
|
|
872
|
+
const { hhea, post, os2 } = font.tables;
|
|
873
|
+
const faceMetrics = faceMetricsFromTables({ unitsPerEm: upem, hhea, post, os2 });
|
|
615
874
|
return {
|
|
616
875
|
unitsPerEm: upem,
|
|
617
|
-
ascender: font.ascender / upem,
|
|
876
|
+
ascender: faceMetrics?.ascent ?? font.ascender / upem,
|
|
877
|
+
...faceMetrics ? { faceMetrics } : {},
|
|
618
878
|
advanceOf(cp) {
|
|
619
879
|
const index = font.charToGlyphIndex(String.fromCodePoint(cp));
|
|
620
880
|
if (!index) return null;
|
|
@@ -624,6 +884,7 @@ function faceFor(font) {
|
|
|
624
884
|
const l = font.charToGlyphIndex(String.fromCodePoint(left));
|
|
625
885
|
const r = font.charToGlyphIndex(String.fromCodePoint(right));
|
|
626
886
|
if (!l || !r) return 0;
|
|
887
|
+
if (gpos) return gpos(l, r) / upem;
|
|
627
888
|
return font.getKerningValue(font.glyphs.get(l), font.glyphs.get(r)) / upem;
|
|
628
889
|
},
|
|
629
890
|
glyphD(cp) {
|
|
@@ -638,7 +899,7 @@ function createOpenTypeParser(postScriptName) {
|
|
|
638
899
|
return async (bytes) => {
|
|
639
900
|
const parse = parserOf(await loadOpenType());
|
|
640
901
|
const { bytes: single } = sfntFromCollection(bytes, postScriptName);
|
|
641
|
-
return faceFor(parse(single));
|
|
902
|
+
return faceFor(parse(single), gposPairKerning(single));
|
|
642
903
|
};
|
|
643
904
|
}
|
|
644
905
|
var openTypeParser = createOpenTypeParser();
|
|
@@ -659,12 +920,15 @@ function registerFontOutlines(family, variant, source, opts = {}) {
|
|
|
659
920
|
weight,
|
|
660
921
|
style,
|
|
661
922
|
source,
|
|
923
|
+
cssSrc: opts.cssSrc,
|
|
662
924
|
parser: opts.parser ?? openTypeParser,
|
|
663
925
|
status: "idle",
|
|
664
926
|
face: null,
|
|
665
|
-
glyphs: /* @__PURE__ */ new Map()
|
|
927
|
+
glyphs: /* @__PURE__ */ new Map(),
|
|
928
|
+
load: null
|
|
666
929
|
});
|
|
667
930
|
notifyGlyphReady();
|
|
931
|
+
if (source instanceof ArrayBuffer) announceBytes(slots.get(slotKey(family, weight, style)), source);
|
|
668
932
|
}
|
|
669
933
|
function unregisterFontOutlines(family, variant = {}) {
|
|
670
934
|
const { weight, style } = normalize(variant);
|
|
@@ -728,23 +992,57 @@ function outlineMetrics(family, weight, style) {
|
|
|
728
992
|
}
|
|
729
993
|
return slot.status === "ready" ? slot.face : null;
|
|
730
994
|
}
|
|
731
|
-
async function
|
|
995
|
+
async function loadFontOutlines(family, variant = {}) {
|
|
996
|
+
const { weight, style } = normalize(variant);
|
|
997
|
+
const slot = slots.get(slotKey(family, weight, style));
|
|
998
|
+
if (!slot) return null;
|
|
999
|
+
await beginLoad(slot);
|
|
1000
|
+
return slot.status;
|
|
1001
|
+
}
|
|
1002
|
+
function beginLoad(slot) {
|
|
1003
|
+
slot.load ??= runLoad(slot);
|
|
1004
|
+
return slot.load;
|
|
1005
|
+
}
|
|
1006
|
+
async function runLoad(slot) {
|
|
732
1007
|
slot.status = "loading";
|
|
733
1008
|
slots.bump();
|
|
734
1009
|
try {
|
|
735
|
-
|
|
1010
|
+
const bytes = await readSource(slot.source);
|
|
1011
|
+
announceBytes(slot, bytes);
|
|
1012
|
+
slot.face = await slot.parser(bytes);
|
|
736
1013
|
slot.status = "ready";
|
|
737
1014
|
slots.bump();
|
|
738
1015
|
notifyGlyphReady();
|
|
739
1016
|
} catch (err) {
|
|
740
1017
|
slot.status = "failed";
|
|
741
1018
|
slots.bump();
|
|
1019
|
+
notifyGlyphReady();
|
|
742
1020
|
warnOnce(
|
|
743
1021
|
`load|${slotKey(slot.family, slot.weight, slot.style)}`,
|
|
744
1022
|
`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.`
|
|
745
1023
|
);
|
|
746
1024
|
}
|
|
747
1025
|
}
|
|
1026
|
+
function outlineCssSource(family, weight, style) {
|
|
1027
|
+
const slot = slots.get(slotKey(family, weight, style));
|
|
1028
|
+
if (!slot) return null;
|
|
1029
|
+
if (slot.cssSrc !== void 0) return { registration: slot, src: slot.cssSrc };
|
|
1030
|
+
if (typeof slot.source === "string") {
|
|
1031
|
+
return { registration: slot, url: `url(${JSON.stringify(slot.source)})` };
|
|
1032
|
+
}
|
|
1033
|
+
const source = slot.source;
|
|
1034
|
+
return { registration: slot, bytes: () => readSource(source) };
|
|
1035
|
+
}
|
|
1036
|
+
var bytesListener = null;
|
|
1037
|
+
function onOutlineBytes(listener) {
|
|
1038
|
+
bytesListener = listener;
|
|
1039
|
+
}
|
|
1040
|
+
function announceBytes(slot, bytes) {
|
|
1041
|
+
try {
|
|
1042
|
+
bytesListener?.(slot, bytes);
|
|
1043
|
+
} catch {
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
748
1046
|
async function readSource(source) {
|
|
749
1047
|
const resolved = typeof source === "function" ? await source() : source;
|
|
750
1048
|
if (typeof resolved === "string") {
|
|
@@ -776,17 +1074,33 @@ function normalizeVariant(v) {
|
|
|
776
1074
|
style: v.style ?? "normal"
|
|
777
1075
|
};
|
|
778
1076
|
}
|
|
1077
|
+
var inFlight = /* @__PURE__ */ new Map();
|
|
1078
|
+
var loads = /* @__PURE__ */ new Map();
|
|
1079
|
+
var declared = /* @__PURE__ */ new Map();
|
|
1080
|
+
var registeredFamilies = /* @__PURE__ */ new Set();
|
|
779
1081
|
function _resetFontRegistryForTests() {
|
|
780
1082
|
registry.clear();
|
|
1083
|
+
inFlight.clear();
|
|
1084
|
+
loads.clear();
|
|
1085
|
+
declared.clear();
|
|
1086
|
+
registeredFamilies.clear();
|
|
781
1087
|
_clearFallbackWarnings();
|
|
782
1088
|
}
|
|
783
1089
|
function getFont(family, weight = 400, style = "normal") {
|
|
784
1090
|
return registry.get(family)?.get(variantKey(weight, style)) ?? null;
|
|
785
1091
|
}
|
|
1092
|
+
function faceMetricsFor(family, weight = 400, style = "normal") {
|
|
1093
|
+
return getFont(family, weight, style)?.font.faceMetrics ?? outlineMetrics(family, weight, style === "italic" ? "italic" : "normal")?.faceMetrics;
|
|
1094
|
+
}
|
|
786
1095
|
function listFonts() {
|
|
787
1096
|
const out = [];
|
|
788
|
-
for (const
|
|
789
|
-
const
|
|
1097
|
+
for (const family of registeredFamilies) {
|
|
1098
|
+
const keys = /* @__PURE__ */ new Set([
|
|
1099
|
+
...registry.get(family)?.keys() ?? [],
|
|
1100
|
+
...declared.get(family)?.keys() ?? []
|
|
1101
|
+
]);
|
|
1102
|
+
if (keys.size === 0) continue;
|
|
1103
|
+
const variants = [...keys].map((key) => {
|
|
790
1104
|
const [w, s] = key.split("|");
|
|
791
1105
|
return { weight: Number(w), style: s };
|
|
792
1106
|
}).sort((a, b) => a.weight - b.weight || a.style.localeCompare(b.style));
|
|
@@ -794,10 +1108,60 @@ function listFonts() {
|
|
|
794
1108
|
}
|
|
795
1109
|
return out;
|
|
796
1110
|
}
|
|
797
|
-
|
|
1111
|
+
function listFontWeights(family) {
|
|
1112
|
+
const weights = /* @__PURE__ */ new Set();
|
|
1113
|
+
for (const key of registry.get(family)?.keys() ?? []) weights.add(Number(key.split("|")[0]));
|
|
1114
|
+
for (const key of declared.get(family)?.keys() ?? []) weights.add(Number(key.split("|")[0]));
|
|
1115
|
+
for (const face of listFontOutlines()) {
|
|
1116
|
+
if (face.family === family && face.status !== "failed") weights.add(face.weight);
|
|
1117
|
+
}
|
|
1118
|
+
return [...weights].sort((a, b) => a - b);
|
|
1119
|
+
}
|
|
1120
|
+
function registerFont(family, variant, metricsUrl, atlasUrl, opts = {}) {
|
|
798
1121
|
const { weight, style } = normalizeVariant(variant);
|
|
799
1122
|
const key = variantKey(weight, style);
|
|
800
|
-
|
|
1123
|
+
registeredFamilies.add(family);
|
|
1124
|
+
if (registry.get(family)?.has(key)) return Promise.resolve();
|
|
1125
|
+
if (!opts.lazy) return loadVariant(family, key, metricsUrl, atlasUrl);
|
|
1126
|
+
const running = loads.get(`${family}|${key}`);
|
|
1127
|
+
if (running) return running;
|
|
1128
|
+
const existing = declared.get(family)?.get(key);
|
|
1129
|
+
if (existing) return existing.promise;
|
|
1130
|
+
let settle2;
|
|
1131
|
+
const promise = new Promise((resolve, reject) => {
|
|
1132
|
+
settle2 = (load) => {
|
|
1133
|
+
load.then(resolve, reject);
|
|
1134
|
+
};
|
|
1135
|
+
});
|
|
1136
|
+
const variants = declared.get(family) ?? /* @__PURE__ */ new Map();
|
|
1137
|
+
declared.set(family, variants.set(key, { metricsUrl, atlasUrl, promise, settle: settle2 }));
|
|
1138
|
+
notifyGlyphReady();
|
|
1139
|
+
return promise;
|
|
1140
|
+
}
|
|
1141
|
+
function loadVariant(family, key, metricsUrl, atlasUrl) {
|
|
1142
|
+
const id = `${family}|${key}`;
|
|
1143
|
+
const running = loads.get(id);
|
|
1144
|
+
if (running) return running;
|
|
1145
|
+
const load = fetchVariant(family, key, metricsUrl, atlasUrl);
|
|
1146
|
+
loads.set(id, load);
|
|
1147
|
+
const settleLoad = () => {
|
|
1148
|
+
if (loads.get(id) === load) loads.delete(id);
|
|
1149
|
+
};
|
|
1150
|
+
load.then(settleLoad, settleLoad);
|
|
1151
|
+
const pendingLazy = declared.get(family)?.get(key);
|
|
1152
|
+
if (pendingLazy) {
|
|
1153
|
+
const variants = declared.get(family);
|
|
1154
|
+
variants.delete(key);
|
|
1155
|
+
if (variants.size === 0) declared.delete(family);
|
|
1156
|
+
pendingLazy.settle(load);
|
|
1157
|
+
}
|
|
1158
|
+
return load;
|
|
1159
|
+
}
|
|
1160
|
+
async function fetchVariant(family, key, metricsUrl, atlasUrl) {
|
|
1161
|
+
const [weight, style] = key.split("|");
|
|
1162
|
+
const token = {};
|
|
1163
|
+
const tokens = inFlight.get(family) ?? /* @__PURE__ */ new Set();
|
|
1164
|
+
inFlight.set(family, tokens.add(token));
|
|
801
1165
|
try {
|
|
802
1166
|
const [metricsRes, atlasRes] = await Promise.all([
|
|
803
1167
|
fetch(metricsUrl),
|
|
@@ -816,13 +1180,75 @@ async function registerFont(family, variant, metricsUrl, atlasUrl) {
|
|
|
816
1180
|
const font = parseBmFont(rawJson);
|
|
817
1181
|
const bitmap = await createImageBitmap(blob);
|
|
818
1182
|
registry.set(family, new Map(registry.get(family)).set(key, { font, bitmap }));
|
|
1183
|
+
settle(family, token);
|
|
819
1184
|
notifyGlyphReady();
|
|
820
1185
|
} catch (err) {
|
|
1186
|
+
settle(family, token);
|
|
1187
|
+
notifyGlyphReady();
|
|
821
1188
|
throw new Error(
|
|
822
1189
|
`weasel registerFont("${family}" ${weight}/${style}): ${err instanceof Error ? err.message : String(err)}`
|
|
823
1190
|
);
|
|
824
1191
|
}
|
|
825
1192
|
}
|
|
1193
|
+
function wakeDeclared(family, weight, style) {
|
|
1194
|
+
const variants = declared.get(family);
|
|
1195
|
+
if (!variants) return;
|
|
1196
|
+
const exact = variantKey(weight, style);
|
|
1197
|
+
const keys = variants.has(exact) ? [exact] : [...variants.keys()];
|
|
1198
|
+
for (const key of keys) {
|
|
1199
|
+
const { metricsUrl, atlasUrl } = variants.get(key);
|
|
1200
|
+
loadVariant(family, key, metricsUrl, atlasUrl).catch(() => {
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
function warmFonts(fonts) {
|
|
1205
|
+
const pending2 = [];
|
|
1206
|
+
for (const font of fonts ?? [...registeredFamilies]) {
|
|
1207
|
+
if (typeof font !== "string") {
|
|
1208
|
+
const { weight, style } = normalizeVariant(font);
|
|
1209
|
+
pending2.push(...variantLoads(font.family, weight, style));
|
|
1210
|
+
continue;
|
|
1211
|
+
}
|
|
1212
|
+
if (!registeredFamilies.has(font)) {
|
|
1213
|
+
return Promise.reject(new Error(`weasel warmFonts: "${font}" was never registered.`));
|
|
1214
|
+
}
|
|
1215
|
+
for (const [key, { metricsUrl, atlasUrl }] of [...declared.get(font) ?? []]) {
|
|
1216
|
+
loadVariant(font, key, metricsUrl, atlasUrl);
|
|
1217
|
+
}
|
|
1218
|
+
pending2.push(...familyLoads(font));
|
|
1219
|
+
}
|
|
1220
|
+
return Promise.all(pending2).then(() => void 0);
|
|
1221
|
+
}
|
|
1222
|
+
function familyLoads(family) {
|
|
1223
|
+
return [...loads].filter(([id]) => id.startsWith(`${family}|`)).map(([, load]) => load);
|
|
1224
|
+
}
|
|
1225
|
+
function variantLoads(family, weight, style) {
|
|
1226
|
+
const out = [];
|
|
1227
|
+
const outlines = hasFontOutlines(family, weight, style);
|
|
1228
|
+
if (outlines) out.push(loadFontOutlines(family, { weight, style }));
|
|
1229
|
+
const key = variantKey(weight, style);
|
|
1230
|
+
if (registry.get(family)?.has(key)) return out;
|
|
1231
|
+
wakeDeclared(family, weight, style);
|
|
1232
|
+
const exact = loads.get(`${family}|${key}`);
|
|
1233
|
+
if (exact) return [...out, exact];
|
|
1234
|
+
if (registry.has(family) || atlasPending(family)) return [...out, ...familyLoads(family)];
|
|
1235
|
+
if (outlines || isExplicitCanvasFont(family) || getFontFallbackPolicy() !== "substitute") return out;
|
|
1236
|
+
const fallback = getDefaultFontFamily() ?? firstRegisteredFamily();
|
|
1237
|
+
return fallback !== null && fallback !== family ? [...out, ...variantLoads(fallback, weight, style)] : out;
|
|
1238
|
+
}
|
|
1239
|
+
function atlasPending(family) {
|
|
1240
|
+
return inFlight.has(family) || declared.has(family);
|
|
1241
|
+
}
|
|
1242
|
+
function settle(family, token) {
|
|
1243
|
+
const tokens = inFlight.get(family);
|
|
1244
|
+
if (!tokens?.delete(token)) return;
|
|
1245
|
+
if (tokens.size === 0) inFlight.delete(family);
|
|
1246
|
+
}
|
|
1247
|
+
function fontPending(family, weight = 400, style = "normal") {
|
|
1248
|
+
if (atlasPending(family)) return true;
|
|
1249
|
+
const outline = outlineStatus(family, weight, style === "italic" ? "italic" : "normal");
|
|
1250
|
+
return outline === "idle" || outline === "loading";
|
|
1251
|
+
}
|
|
826
1252
|
function ensureFontTexture(family, weight, style, textureCache) {
|
|
827
1253
|
const entry = getFont(family, weight, style);
|
|
828
1254
|
if (!entry) return false;
|
|
@@ -868,12 +1294,13 @@ function missResolveResult(family, weight, style, suppressWarn = false) {
|
|
|
868
1294
|
if (policy2 === "substitute") {
|
|
869
1295
|
const fallback = getDefaultFontFamily() ?? firstRegisteredFamily();
|
|
870
1296
|
if (fallback !== null && fallback !== family) {
|
|
871
|
-
if (registry.has(fallback) || isCanvasFont(fallback)) {
|
|
1297
|
+
if (registry.has(fallback) || isCanvasFont(fallback) || atlasPending(fallback)) {
|
|
872
1298
|
const result = resolveFontVariantInternal(fallback, weight, style, true);
|
|
873
1299
|
if (result.entry !== null || result.dynamicFace !== void 0) {
|
|
874
1300
|
if (!suppressWarn) warnMissingFamilyOnce(family, weight, style, fallback);
|
|
875
1301
|
return { ...result, substituted: { requested: family, resolved: fallback } };
|
|
876
1302
|
}
|
|
1303
|
+
if (atlasPending(fallback)) return pendingMiss(family, weight, style);
|
|
877
1304
|
}
|
|
878
1305
|
if (!suppressWarn) warnUnusableDefaultOnce(family, weight, style, fallback);
|
|
879
1306
|
} else if (fallback === family && !suppressWarn) {
|
|
@@ -892,7 +1319,18 @@ function missResolveResult(family, weight, style, suppressWarn = false) {
|
|
|
892
1319
|
};
|
|
893
1320
|
}
|
|
894
1321
|
function firstRegisteredFamily() {
|
|
895
|
-
|
|
1322
|
+
for (const family of registeredFamilies) {
|
|
1323
|
+
if (registry.has(family) || atlasPending(family)) return family;
|
|
1324
|
+
}
|
|
1325
|
+
return null;
|
|
1326
|
+
}
|
|
1327
|
+
function pendingMiss(family, weight, style) {
|
|
1328
|
+
return {
|
|
1329
|
+
entry: null,
|
|
1330
|
+
resolved: { family, weight, style },
|
|
1331
|
+
synthetic: { bold: false, italic: false },
|
|
1332
|
+
source: "atlas"
|
|
1333
|
+
};
|
|
896
1334
|
}
|
|
897
1335
|
function warnMissingFamilyOnce(family, weight, style, resolved) {
|
|
898
1336
|
if (!claimFallbackWarning(`substituted|${family}|${weight}|${style}`)) return;
|
|
@@ -945,11 +1383,17 @@ function resolveGlyphFallback(family, weight, style) {
|
|
|
945
1383
|
}
|
|
946
1384
|
}
|
|
947
1385
|
function resolveFontVariantInternal(family, weight, style, suppressWarn) {
|
|
1386
|
+
wakeDeclared(family, weight, style);
|
|
1387
|
+
const exactKey = variantKey(weight, style);
|
|
1388
|
+
if (loads.has(`${family}|${exactKey}`) && !registry.get(family)?.has(exactKey)) {
|
|
1389
|
+
return pendingMiss(family, weight, style);
|
|
1390
|
+
}
|
|
948
1391
|
const familyMap = registry.get(family);
|
|
949
1392
|
if (!familyMap || familyMap.size === 0) {
|
|
1393
|
+
if (atlasPending(family)) return pendingMiss(family, weight, style);
|
|
950
1394
|
return missResolveResult(family, weight, style, suppressWarn);
|
|
951
1395
|
}
|
|
952
|
-
const exact = familyMap.get(
|
|
1396
|
+
const exact = familyMap.get(exactKey);
|
|
953
1397
|
if (exact) {
|
|
954
1398
|
return {
|
|
955
1399
|
entry: exact,
|
|
@@ -1039,6 +1483,107 @@ function resolveFontVariantInternal(family, weight, style, suppressWarn) {
|
|
|
1039
1483
|
return missResolveResult(family, weight, style, suppressWarn);
|
|
1040
1484
|
}
|
|
1041
1485
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1486
|
+
// src/domFace.ts
|
|
1487
|
+
var names = /* @__PURE__ */ new Map();
|
|
1488
|
+
var faces2 = /* @__PURE__ */ new Map();
|
|
1489
|
+
var warned2 = /* @__PURE__ */ new Set();
|
|
1490
|
+
function domFonts() {
|
|
1491
|
+
return typeof FontFace !== "undefined" && typeof document !== "undefined" && !!document.fonts;
|
|
1492
|
+
}
|
|
1493
|
+
function nameFor(family) {
|
|
1494
|
+
let name = names.get(family);
|
|
1495
|
+
if (!name) {
|
|
1496
|
+
name = `weasel-face-${names.size}`;
|
|
1497
|
+
names.set(family, name);
|
|
1498
|
+
}
|
|
1499
|
+
return name;
|
|
1500
|
+
}
|
|
1501
|
+
onOutlineBytes((registration, bytes) => {
|
|
1502
|
+
if (!domFonts()) return;
|
|
1503
|
+
const { family, weight, style } = registration;
|
|
1504
|
+
ensureFace(nameFor(family), family, weight, style, bytes);
|
|
1505
|
+
});
|
|
1506
|
+
function privateFamily(family, variant) {
|
|
1507
|
+
if (!domFonts()) return null;
|
|
1508
|
+
const resolved = resolveFontVariant(family, variant.weight ?? 400, variant.style ?? "normal");
|
|
1509
|
+
if (resolved.source === "canvas") return null;
|
|
1510
|
+
const target = resolved.resolved.family;
|
|
1511
|
+
const variants = listFontOutlines().filter((f) => f.family === target && f.status !== "failed");
|
|
1512
|
+
if (variants.length === 0) {
|
|
1513
|
+
if (resolved.entry && !warned2.has(target)) {
|
|
1514
|
+
warned2.add(target);
|
|
1515
|
+
console.warn(
|
|
1516
|
+
`weasel: "${target}" draws from a baked atlas with no font file registered, so DOM text in it (the text edit overlay) uses the browser's own "${family}" and will not match the canvas. Register the file the atlas was baked from: registerFontOutlines("${target}", \u2026).`
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
return null;
|
|
1520
|
+
}
|
|
1521
|
+
return { target, variants };
|
|
1522
|
+
}
|
|
1523
|
+
function cssFontFamily(family, variant = {}) {
|
|
1524
|
+
const priv = privateFamily(family, variant);
|
|
1525
|
+
if (!priv) return family;
|
|
1526
|
+
const name = nameFor(priv.target);
|
|
1527
|
+
for (const v of priv.variants) ensureFace(name, v.family, v.weight, v.style);
|
|
1528
|
+
return `${JSON.stringify(name)}, ${family}`;
|
|
1529
|
+
}
|
|
1530
|
+
function cssFontFamilyLoading(family, variant = {}) {
|
|
1531
|
+
const priv = privateFamily(family, variant);
|
|
1532
|
+
if (!priv) return null;
|
|
1533
|
+
const name = nameFor(priv.target);
|
|
1534
|
+
for (const v of priv.variants) ensureFace(name, v.family, v.weight, v.style);
|
|
1535
|
+
const weight = variant.weight ?? 400;
|
|
1536
|
+
const style = variant.style ?? "normal";
|
|
1537
|
+
const exact = priv.variants.filter((v) => v.weight === weight && v.style === style);
|
|
1538
|
+
const pending2 = (exact.length > 0 ? exact : priv.variants).map((v) => faces2.get(`${v.family}|${v.weight}|${v.style}`)).filter((l) => l !== void 0 && !l.settled).map((l) => l.done);
|
|
1539
|
+
return pending2.length === 0 ? null : Promise.all(pending2).then(() => {
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
function ensureFace(name, family, weight, style, bytes) {
|
|
1543
|
+
const key = `${family}|${weight}|${style}`;
|
|
1544
|
+
const css = outlineCssSource(family, weight, style);
|
|
1545
|
+
if (!css) return;
|
|
1546
|
+
const have = faces2.get(key);
|
|
1547
|
+
if (have?.from === css.registration) return;
|
|
1548
|
+
if (have?.face) document.fonts.delete(have.face);
|
|
1549
|
+
let settle2;
|
|
1550
|
+
const entry = {
|
|
1551
|
+
from: css.registration,
|
|
1552
|
+
face: null,
|
|
1553
|
+
settled: false,
|
|
1554
|
+
done: new Promise((r) => {
|
|
1555
|
+
settle2 = r;
|
|
1556
|
+
})
|
|
1557
|
+
};
|
|
1558
|
+
const finish = () => {
|
|
1559
|
+
entry.settled = true;
|
|
1560
|
+
settle2();
|
|
1561
|
+
};
|
|
1562
|
+
faces2.set(key, entry);
|
|
1563
|
+
const descriptors = { weight: String(weight), style, display: "swap" };
|
|
1564
|
+
const add = (face) => {
|
|
1565
|
+
if (faces2.get(key) !== entry) return finish();
|
|
1566
|
+
entry.face = face;
|
|
1567
|
+
document.fonts.add(face);
|
|
1568
|
+
face.load().then(finish, () => {
|
|
1569
|
+
finish();
|
|
1570
|
+
console.warn(`weasel: could not load "${family}" (${weight}/${style}) for DOM text; the text edit overlay falls back to the browser's own face.`);
|
|
1571
|
+
});
|
|
1572
|
+
};
|
|
1573
|
+
if ("src" in css) add(new FontFace(name, css.src, descriptors));
|
|
1574
|
+
else if (bytes !== void 0) add(new FontFace(name, bytes, descriptors));
|
|
1575
|
+
else if ("url" in css) add(new FontFace(name, css.url, descriptors));
|
|
1576
|
+
else css.bytes().then((buf) => add(new FontFace(name, buf, descriptors)), finish);
|
|
1577
|
+
}
|
|
1578
|
+
function _resetDomFacesForTests() {
|
|
1579
|
+
if (typeof document !== "undefined" && document.fonts) {
|
|
1580
|
+
for (const { face } of faces2.values()) if (face) document.fonts.delete(face);
|
|
1581
|
+
}
|
|
1582
|
+
names.clear();
|
|
1583
|
+
faces2.clear();
|
|
1584
|
+
warned2.clear();
|
|
1585
|
+
}
|
|
1586
|
+
|
|
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
|