@navaramap/font 0.0.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.
- package/LICENSE +8 -0
- package/README.md +3 -0
- package/dist/index.d.ts +556 -0
- package/dist/index.js +3517 -0
- package/dist/index.umd.cjs +1 -0
- package/package.json +51 -0
- package/src/FontManager.test.ts +2087 -0
- package/src/FontManager.ts +1064 -0
- package/src/FontWorkerClient.ts +183 -0
- package/src/LRUMap.test.ts +124 -0
- package/src/LRUMap.ts +57 -0
- package/src/cssFontFamily.test.ts +230 -0
- package/src/cssFontFamily.ts +286 -0
- package/src/fontWorker.ts +255 -0
- package/src/index.ts +28 -0
- package/src/types.ts +150 -0
- package/src/vite-env.d.ts +1 -0
package/LICENSE
ADDED
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
import { ConcurrencyManager } from '@navaramap/worker';
|
|
2
|
+
import { DataTexture } from 'three';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pixel range over which a quality's atlas distance field ramps from
|
|
6
|
+
* "outside" to "inside" (i.e. the value covered by `d - 0.5` in the shader).
|
|
7
|
+
* Converts an outline-thickness expressed in pixels into a delta on the
|
|
8
|
+
* sampled distance value.
|
|
9
|
+
*
|
|
10
|
+
* SDF: `SDF_RADIUS` (35) in `crates/navara_wasm_font_worker/src/atlas.rs`.
|
|
11
|
+
* MSDF: `MSDF_RANGE_PX` (8) in `crates/navara_wasm_font_worker/src/msdf.rs`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const atlasRangePx: (highQuality: boolean) => number;
|
|
14
|
+
|
|
15
|
+
declare type BatchPrepareTextResult = {
|
|
16
|
+
results: {
|
|
17
|
+
text: string;
|
|
18
|
+
shapeResult: ShapeTextResult | null;
|
|
19
|
+
}[];
|
|
20
|
+
/** Snapshot of the SDF atlas, if any glyphs were added during the batch. */
|
|
21
|
+
atlas: FontAtlasData | null;
|
|
22
|
+
/** Snapshot of the COLRv1 color atlas (RGBA), if any color glyphs were added during the batch. */
|
|
23
|
+
colorAtlas: FontAtlasData | null;
|
|
24
|
+
/** The atlas key used for this batch (family name or font URL). */
|
|
25
|
+
atlasKey: string;
|
|
26
|
+
/** True if any glyph was evicted during this batch. The reused rects mean
|
|
27
|
+
* cached shape results for this atlas may be stale, so the FontManager bumps
|
|
28
|
+
* the atlas generation to force a re-shape on next use. Optional only so
|
|
29
|
+
* callers needn't construct it (the worker always sends it). */
|
|
30
|
+
evicted?: boolean;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Pixel size at which COLRv1 color glyphs are rasterized into the color atlas.
|
|
35
|
+
* Must match `COLOR_GLYPH_PX_SIZE` in `crates/navara_wasm_font_worker/src/color_raster.rs`.
|
|
36
|
+
*/
|
|
37
|
+
export declare const COLOR_GLYPH_PX_SIZE = 64;
|
|
38
|
+
|
|
39
|
+
/** Create an RGBA color atlas DataTexture for COLRv1 glyphs.
|
|
40
|
+
* Pixel data is unpremultiplied sRGB; three.js linearizes on sample. */
|
|
41
|
+
export declare function createColorAtlasTexture(data: Uint8Array, width: number, height: number): DataTexture;
|
|
42
|
+
|
|
43
|
+
/** Create an SDF/MSDF distance-field atlas DataTexture.
|
|
44
|
+
*
|
|
45
|
+
* `channels`: 1 → R8 SDF (sampled as `.r`); 4 → RGBA8 MTSDF (three MSDF
|
|
46
|
+
* channels + true SDF in alpha, sampled as `median(.rgb)`). RGB8 isn't
|
|
47
|
+
* supported because three.js dropped `RGBFormat` in r137. */
|
|
48
|
+
export declare function createSdfAtlasTexture(data: Uint8Array, width: number, height: number, channels: number): DataTexture;
|
|
49
|
+
|
|
50
|
+
/** Filters selecting which `@font-face` blocks of a stylesheet to include. */
|
|
51
|
+
export declare type CssFontFaceFilter = {
|
|
52
|
+
/**
|
|
53
|
+
* Only include blocks whose `font-family` matches one of these names
|
|
54
|
+
* (quotes stripped, case-insensitive). Useful when a stylesheet declares
|
|
55
|
+
* several families and only some should become faces.
|
|
56
|
+
*
|
|
57
|
+
* When given as an array, it also sets face priority: faces are ordered by
|
|
58
|
+
* their family's position in the array (stable within a family). This
|
|
59
|
+
* matters for stylesheets like the Google Fonts CSS API that sort
|
|
60
|
+
* `@font-face` blocks alphabetically regardless of request order — face
|
|
61
|
+
* order decides which face wins for codepoints covered by several faces,
|
|
62
|
+
* and `faces[0]` is the fallback for uncovered codepoints.
|
|
63
|
+
*/
|
|
64
|
+
fontFamily?: string | string[];
|
|
65
|
+
/** Only include blocks whose `font-weight` matches, e.g. `800` or `"100 900"`. */
|
|
66
|
+
fontWeight?: string | number;
|
|
67
|
+
/** Only include blocks whose `font-style` matches, e.g. `"normal"` or `"italic"`. */
|
|
68
|
+
fontStyle?: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export declare type FetchCssFontFamilyOptions = CssFontFaceFilter & {
|
|
72
|
+
/** Extra `fetch` options (e.g. credentials for a private font host). */
|
|
73
|
+
requestInit?: RequestInit;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Fetch one or more stylesheets and build a {@link FontFamily} from their
|
|
78
|
+
* `@font-face` rules — see {@link parseFontFamilyFromCss}. Only the CSS is
|
|
79
|
+
* downloaded here; font files stay lazily fetched per face as text needs
|
|
80
|
+
* them.
|
|
81
|
+
*
|
|
82
|
+
* Works directly with the Google Fonts CSS API, which declares one
|
|
83
|
+
* `@font-face` per script subset with `unicode-range` (CJK families are
|
|
84
|
+
* split into ~100 lazily-loaded slices):
|
|
85
|
+
*
|
|
86
|
+
* ```ts
|
|
87
|
+
* const family = await fetchFontFamilyFromCss(
|
|
88
|
+
* "labels",
|
|
89
|
+
* "https://fonts.googleapis.com/css2?family=Archivo:wght@800&family=Noto+Sans+JP:wght@800",
|
|
90
|
+
* );
|
|
91
|
+
* view.addFontFamily(family);
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* When passing multiple URLs, face priority follows URL order, then block
|
|
95
|
+
* order within each stylesheet.
|
|
96
|
+
*
|
|
97
|
+
* @param family Family name to register the faces under.
|
|
98
|
+
* @param cssUrl Stylesheet URL(s) to fetch.
|
|
99
|
+
* @param options Optional block filters and fetch options.
|
|
100
|
+
*/
|
|
101
|
+
export declare function fetchFontFamilyFromCss(family: string, cssUrl: string | string[], options?: FetchCssFontFamilyOptions): Promise<FontFamily>;
|
|
102
|
+
|
|
103
|
+
/** SDF/MSDF atlas texture data.
|
|
104
|
+
*
|
|
105
|
+
* `channels` selects the GPU texture format:
|
|
106
|
+
* - 1 → R8 (single-channel SDF, sampled as `.r`).
|
|
107
|
+
* - 4 → RGBA8. Either MTSDF (three MSDF channels + true SDF in alpha,
|
|
108
|
+
* sampled as `median(.rgb)` in the fragment shader) or the COLRv1 color
|
|
109
|
+
* atlas — distinguished by which atlas slot the data was placed in, not
|
|
110
|
+
* by `channels`.
|
|
111
|
+
*
|
|
112
|
+
* 3-channel MSDF (RGB8) isn't used: three.js dropped `RGBFormat` in r137,
|
|
113
|
+
* and the worker emits MTSDF (4 channels) for the high-quality path.
|
|
114
|
+
*/
|
|
115
|
+
export declare type FontAtlasData = {
|
|
116
|
+
data: Uint8Array;
|
|
117
|
+
width: number;
|
|
118
|
+
height: number;
|
|
119
|
+
channels: number;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
declare type FontFace_2 = {
|
|
123
|
+
unicodeRanges: UnicodeRange[];
|
|
124
|
+
url: string;
|
|
125
|
+
};
|
|
126
|
+
export { FontFace_2 as FontFace }
|
|
127
|
+
|
|
128
|
+
export declare type FontFamily = {
|
|
129
|
+
family: string;
|
|
130
|
+
faces: FontFace_2[];
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Manages font loading, text shaping, and SDF atlas access.
|
|
135
|
+
*
|
|
136
|
+
* Delegates heavy computation (shaping, SDF rasterization, atlas packing)
|
|
137
|
+
* to a dedicated Web Worker via FontWorkerClient. GPU texture management
|
|
138
|
+
* (DataTexture creation/update) stays on the main thread.
|
|
139
|
+
*/
|
|
140
|
+
export declare class FontManager {
|
|
141
|
+
private _workerUrl;
|
|
142
|
+
private _client;
|
|
143
|
+
private _clientPromise;
|
|
144
|
+
private _concurrencyManager;
|
|
145
|
+
/** Worker cache budget, delivered when the (lazy) client is created. */
|
|
146
|
+
private _fontBudgetBytes;
|
|
147
|
+
/** Tracks in-flight fetch promises to avoid duplicate requests. */
|
|
148
|
+
private _pending;
|
|
149
|
+
/** Tracks fonts that have been successfully loaded. */
|
|
150
|
+
private _loaded;
|
|
151
|
+
/** Cache shaped text results to avoid redundant worker calls (LRU-evicted). */
|
|
152
|
+
private _shapeCache;
|
|
153
|
+
/** Cache atlas data per font to avoid redundant copies. */
|
|
154
|
+
private _atlasCache;
|
|
155
|
+
/** Cache color atlas data per font (COLRv1 RGBA). */
|
|
156
|
+
private _colorAtlasCache;
|
|
157
|
+
/** Tracks whether the atlas cache is stale (new glyphs may have been rasterized). */
|
|
158
|
+
private _atlasDirty;
|
|
159
|
+
/** Tracks whether the color atlas cache is stale. */
|
|
160
|
+
private _colorAtlasDirty;
|
|
161
|
+
/** Shared GPU texture per font — all meshes using the same font share one DataTexture. */
|
|
162
|
+
private _textureCache;
|
|
163
|
+
/** Shared color atlas texture per atlas key (RGBA). */
|
|
164
|
+
private _colorTextureCache;
|
|
165
|
+
/** Tracks in-flight prepareText promises to deduplicate. */
|
|
166
|
+
private _preparePending;
|
|
167
|
+
/** Microtask batch queue: per-font list of texts awaiting worker dispatch. */
|
|
168
|
+
private _batchQueue;
|
|
169
|
+
/** Whether a microtask flush is already scheduled. */
|
|
170
|
+
private _batchScheduled;
|
|
171
|
+
private _refCount;
|
|
172
|
+
/** Registered font families, keyed by family name. */
|
|
173
|
+
private _families;
|
|
174
|
+
/** Real cmap coverage per font file URL, reported by the worker when the
|
|
175
|
+
* file is first loaded. Declared face ranges can differ from what the
|
|
176
|
+
* file contains (e.g. shared per-subset boilerplate in Google Fonts CSS
|
|
177
|
+
* claims codepoints the file lacks, which would shape as tofu), so
|
|
178
|
+
* registered faces pointing at the URL get their `unicodeRanges` replaced
|
|
179
|
+
* with these — once per file, never per shaped text. */
|
|
180
|
+
private _cmapRanges;
|
|
181
|
+
/** Maps font URL → atlas key (family name or URL for standalone fonts). */
|
|
182
|
+
private _atlasKeys;
|
|
183
|
+
/** Per-atlas generation counter. Bumped when the worker reports it evicted
|
|
184
|
+
* glyphs from an atlas; cached shape results carry the generation they were
|
|
185
|
+
* built under, so any from before the eviction are re-shaped on next use.
|
|
186
|
+
* Visible labels are *normally* unaffected — their glyphs are pinned and not
|
|
187
|
+
* evicted — but a large burst can evict a still-in-flight glyph before its
|
|
188
|
+
* retain lands; `onAtlasEvicted` lets consumers rebuild such stale meshes. */
|
|
189
|
+
private _atlasGeneration;
|
|
190
|
+
/** Eviction listeners keyed by resolved atlas key. Notified (coalesced on a
|
|
191
|
+
* microtask) after an eviction bumps an atlas's generation, so visible
|
|
192
|
+
* consumers can rebuild meshes whose baked metrics may now be stale. */
|
|
193
|
+
private _evictListeners;
|
|
194
|
+
/** Atlas keys with an eviction awaiting notification, plus its schedule flag. */
|
|
195
|
+
private _pendingEvictNotify;
|
|
196
|
+
private _evictNotifyScheduled;
|
|
197
|
+
/** Pending visible-label refcount increments per atlas key (one entry per
|
|
198
|
+
* occurrence), flushed to the worker on a microtask. */
|
|
199
|
+
private _retainQueue;
|
|
200
|
+
/** Pending visible-label refcount decrements per atlas key. */
|
|
201
|
+
private _releaseQueue;
|
|
202
|
+
/** Whether a retain/release flush is already scheduled. */
|
|
203
|
+
private _refFlushScheduled;
|
|
204
|
+
constructor(workerUrl: string | URL);
|
|
205
|
+
setConcurrencyManager(concurrencyManager: ConcurrencyManager): void;
|
|
206
|
+
/**
|
|
207
|
+
* Register a font family with multiple faces.
|
|
208
|
+
* No font files are loaded until text is prepared.
|
|
209
|
+
*/
|
|
210
|
+
registerFontFamily(family: FontFamily): void;
|
|
211
|
+
/**
|
|
212
|
+
* Remove a registered font family. No font resources are unloaded here —
|
|
213
|
+
* each mesh that used this family tracks its loaded face URLs and unloads
|
|
214
|
+
* them individually on dispose.
|
|
215
|
+
*/
|
|
216
|
+
unregisterFontFamily(familyName: string): void;
|
|
217
|
+
/** Check whether a font identifier is a registered family name. */
|
|
218
|
+
isFamily(fontIdentifier: string): boolean;
|
|
219
|
+
/**
|
|
220
|
+
* Split `text` into runs of consecutive characters that map to the same face.
|
|
221
|
+
* Each character picks the first face whose unicode ranges contain it,
|
|
222
|
+
* falling back to face 0. Spaces stick to the current run to avoid breaking
|
|
223
|
+
* up whitespace.
|
|
224
|
+
*/
|
|
225
|
+
private _segmentTextByFace;
|
|
226
|
+
/** First face whose unicode ranges contain `codepoint`, or face 0. */
|
|
227
|
+
private _findFaceForCodepoint;
|
|
228
|
+
/** Replace the unicode ranges of every registered face pointing at
|
|
229
|
+
* `rawUrl` with the font file's real cmap coverage (see `_cmapRanges`). */
|
|
230
|
+
private _applyCmapRanges;
|
|
231
|
+
private _ensureClient;
|
|
232
|
+
/**
|
|
233
|
+
* Sets the worker-side cache budget (font data + atlas pixels). Must be
|
|
234
|
+
* called before the first font loads — the worker is created lazily and
|
|
235
|
+
* the budget is delivered with its init message.
|
|
236
|
+
*/
|
|
237
|
+
setMemoryBudget(bytes: number | undefined): void;
|
|
238
|
+
/**
|
|
239
|
+
* Snapshot of the font worker's memory usage, or `undefined` while no
|
|
240
|
+
* worker has been spawned (no fonts in use = zero cost).
|
|
241
|
+
*/
|
|
242
|
+
memoryStats(): Promise<FontWorkerMemoryStats | undefined>;
|
|
243
|
+
/**
|
|
244
|
+
* Load a font from a URL. Fetches the font file and sends it to the worker.
|
|
245
|
+
* Returns immediately if the font is already loaded. Deduplicates concurrent requests.
|
|
246
|
+
*
|
|
247
|
+
* `atlasKey`: optional shared atlas identifier (e.g. font family name).
|
|
248
|
+
* `highQuality`: which atlas raster path to use. Two materials referencing the
|
|
249
|
+
* same `url` but different `highQuality` values produce two independent
|
|
250
|
+
* (font, atlas) entries — both live side-by-side. The browser HTTP cache
|
|
251
|
+
* makes the second fetch effectively free.
|
|
252
|
+
*/
|
|
253
|
+
loadFont(url: string, highQuality: boolean, atlasKey?: string): Promise<void>;
|
|
254
|
+
unloadFont(url: string, highQuality: boolean): Promise<void>;
|
|
255
|
+
/**
|
|
256
|
+
* Prepare text for rendering: shapes text and updates atlas in the worker.
|
|
257
|
+
* Must be called (and awaited) before shapeText() will return data for this text.
|
|
258
|
+
* Accepts either a font URL or a registered font family name.
|
|
259
|
+
*
|
|
260
|
+
* For font families, face URLs are loaded lazily — only the faces whose
|
|
261
|
+
* unicode ranges cover `text` are fetched. Pass a caller-owned `loadedFaces`
|
|
262
|
+
* Set to track which URLs were loaded; the caller must call unloadFont() for
|
|
263
|
+
* each URL in the set on dispose. Passing the same set across multiple calls
|
|
264
|
+
* ensures each face URL is loaded exactly once per caller.
|
|
265
|
+
*
|
|
266
|
+
* For standalone font URLs the font must already be loaded via loadFont().
|
|
267
|
+
*/
|
|
268
|
+
prepareText(fontIdentifier: string, text: string, highQuality: boolean, loadedFaces?: Set<string>): Promise<void>;
|
|
269
|
+
/**
|
|
270
|
+
* Check if text has been prepared (sync).
|
|
271
|
+
* Accepts either a font URL or a registered font family name.
|
|
272
|
+
*/
|
|
273
|
+
isTextPrepared(fontIdentifier: string, text: string, highQuality: boolean): boolean;
|
|
274
|
+
/**
|
|
275
|
+
* Get shaped text from cache. Returns undefined if not yet prepared.
|
|
276
|
+
* Call prepareText() first.
|
|
277
|
+
* Accepts either a font URL or a registered font family name.
|
|
278
|
+
*/
|
|
279
|
+
shapeText(fontIdentifier: string, text: string, highQuality: boolean): ShapeTextResult | undefined;
|
|
280
|
+
/** Prepare text for a single standalone font (non-family path). */
|
|
281
|
+
private _prepareSingleFontText;
|
|
282
|
+
/** Prepare text for a font family: segment, shape per-face, stitch. */
|
|
283
|
+
private _prepareFamilyText;
|
|
284
|
+
/** Combine shaped results from multiple face segments into one result.
|
|
285
|
+
*
|
|
286
|
+
* All glyph advances/offsets and bearing values are normalized to the first
|
|
287
|
+
* segment's unitsPerEm so the consumer can apply a single scale factor.
|
|
288
|
+
*/
|
|
289
|
+
private _stitchSegments;
|
|
290
|
+
/**
|
|
291
|
+
* Get the SDF atlas data for a loaded font from cache.
|
|
292
|
+
* Accepts either a font URL or a registered font family name.
|
|
293
|
+
* For families, the atlas is shared across all faces.
|
|
294
|
+
*/
|
|
295
|
+
getAtlas(fontIdentifier: string, highQuality: boolean): FontAtlasData | undefined;
|
|
296
|
+
/**
|
|
297
|
+
* Shared GPU DataTexture for a font's atlas. Returns the same instance
|
|
298
|
+
* across callers and updates it in-place when the atlas grows. Accepts a
|
|
299
|
+
* font URL or a family name.
|
|
300
|
+
*/
|
|
301
|
+
getAtlasTexture(fontIdentifier: string, highQuality: boolean): DataTexture | null;
|
|
302
|
+
/** Color atlas data for a loaded COLRv1 font. `undefined` for monochrome. */
|
|
303
|
+
getColorAtlas(fontIdentifier: string, highQuality: boolean): FontAtlasData | undefined;
|
|
304
|
+
/**
|
|
305
|
+
* Shared GPU DataTexture for a font's COLRv1 color atlas. `null` when no
|
|
306
|
+
* color glyphs have been rasterized under this key.
|
|
307
|
+
*/
|
|
308
|
+
getColorAtlasTexture(fontIdentifier: string, highQuality: boolean): DataTexture | null;
|
|
309
|
+
/** Shared "get cached texture, create or refresh from atlas data" path.
|
|
310
|
+
* When the atlas grew, dispose() releases the GL handle so three.js
|
|
311
|
+
* reallocates at the new size on the next render instead of overflowing
|
|
312
|
+
* texSubImage2D. The DataTexture instance is preserved so existing meshes
|
|
313
|
+
* keep their refs. */
|
|
314
|
+
private _getOrUpdateTexture;
|
|
315
|
+
dispose(): void;
|
|
316
|
+
private _cacheKey;
|
|
317
|
+
/** Current generation of an atlas. Bumped whenever the atlas evicts glyphs;
|
|
318
|
+
* cached shape results stamped with an older generation are treated as
|
|
319
|
+
* stale (their metrics may point at reused rects) and re-shaped on next use. */
|
|
320
|
+
private _currentGen;
|
|
321
|
+
/** Whether `text` has a cached shape result that is still current for its
|
|
322
|
+
* atlas. A result from before the atlas last evicted is treated as not
|
|
323
|
+
* prepared, forcing a re-shape that re-rasterizes any evicted glyphs. */
|
|
324
|
+
private _isPreparedFresh;
|
|
325
|
+
/**
|
|
326
|
+
* Subscribe to evictions on the atlas backing `(fontIdentifier, highQuality)`.
|
|
327
|
+
* The listener fires (coalesced on a microtask) after the worker reports that
|
|
328
|
+
* atlas evicted glyphs — the cue for a visible consumer to rebuild any mesh
|
|
329
|
+
* whose baked atlas rects may now be stale. Returns an unsubscribe function.
|
|
330
|
+
*/
|
|
331
|
+
onAtlasEvicted(fontIdentifier: string, highQuality: boolean, listener: () => void): () => void;
|
|
332
|
+
/** Queue an eviction notification for `atlasKey`, coalescing a burst of
|
|
333
|
+
* per-batch evictions into a single microtask-deferred fan-out. */
|
|
334
|
+
private _scheduleEvictNotify;
|
|
335
|
+
private _flushEvictNotify;
|
|
336
|
+
/**
|
|
337
|
+
* Add one visible-label reference to each glyph (composite keys) so the
|
|
338
|
+
* worker keeps them in the atlas while on screen. Call when a label using
|
|
339
|
+
* these glyphs becomes visible; balance with {@link releaseGlyphs}.
|
|
340
|
+
*/
|
|
341
|
+
retainGlyphs(fontIdentifier: string, highQuality: boolean, keys: bigint[]): void;
|
|
342
|
+
/** Drop one visible-label reference from each glyph. Call when a label hides
|
|
343
|
+
* or is disposed. */
|
|
344
|
+
releaseGlyphs(fontIdentifier: string, highQuality: boolean, keys: bigint[]): void;
|
|
345
|
+
private _enqueueRef;
|
|
346
|
+
/** Send queued refcount changes to the worker. Retains are sent before
|
|
347
|
+
* releases so a glyph hidden and re-shown in the same tick never momentarily
|
|
348
|
+
* drops to zero. */
|
|
349
|
+
private _flushRefs;
|
|
350
|
+
/** Resolve a (font identifier, quality) pair to its qualified atlas key.
|
|
351
|
+
* Family names get a quality suffix and become their own atlas key; font
|
|
352
|
+
* URLs are looked up via `_atlasKeys` (already-qualified keys). */
|
|
353
|
+
private _resolveAtlasKey;
|
|
354
|
+
/** Fetch + worker-load a font for a single (url, quality) combination.
|
|
355
|
+
*
|
|
356
|
+
* `rawUrl` is the network URL (no `#q=...` fragment). `qUrl` and
|
|
357
|
+
* `qAtlasKey` are the qualified identifiers the worker will use as
|
|
358
|
+
* FontEntry / atlas keys. The worker side treats `qUrl` as opaque, so the
|
|
359
|
+
* same `rawUrl` can be loaded twice (once per quality) without collision.
|
|
360
|
+
*/
|
|
361
|
+
private _fetchAndLoad;
|
|
362
|
+
private _flushBatch;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Main-thread client that communicates with the dedicated font Web Worker.
|
|
367
|
+
* Uses a request/response protocol with incrementing message IDs.
|
|
368
|
+
*/
|
|
369
|
+
export declare class FontWorkerClient {
|
|
370
|
+
private _worker;
|
|
371
|
+
private _concurrencyManager;
|
|
372
|
+
private _nextId;
|
|
373
|
+
private _pending;
|
|
374
|
+
private _ready;
|
|
375
|
+
constructor(workerUrl: string | URL, concurrencyManager: ConcurrencyManager, options?: FontWorkerClientOptions);
|
|
376
|
+
/** Wait for the WASM module to be initialized in the worker. */
|
|
377
|
+
ready(): Promise<void>;
|
|
378
|
+
/** Load a font file into the worker's FontCache. Transfers the ArrayBuffer.
|
|
379
|
+
* `atlasKey`: optional shared atlas identifier (e.g. font family name).
|
|
380
|
+
* When provided, all fonts loaded with the same key share a single atlas.
|
|
381
|
+
* `highQuality`: whether to use the high-quality atlas raster path. The Rust side creates the
|
|
382
|
+
* atlas with this mode on the first load; subsequent loads under the same
|
|
383
|
+
* `atlasKey` are expected to reuse the same quality (the TS layer
|
|
384
|
+
* guarantees this by including the highQuality flag in both `url` and `atlasKey`).
|
|
385
|
+
*
|
|
386
|
+
* On success, `cmapRanges` holds the font's real cmap coverage as
|
|
387
|
+
* flattened `[from, to, ...]` inclusive codepoint ranges (empty when the
|
|
388
|
+
* face has no parsable unicode cmap — treat as unknown). */
|
|
389
|
+
loadFont(url: string, data: ArrayBuffer, atlasKey: string | undefined, highQuality: boolean): Promise<{
|
|
390
|
+
ok: boolean;
|
|
391
|
+
cmapRanges: Uint32Array | null;
|
|
392
|
+
}>;
|
|
393
|
+
unloadFont(url: string): Promise<{
|
|
394
|
+
ok: boolean;
|
|
395
|
+
}>;
|
|
396
|
+
/** Add one visible-label reference to each glyph (composite keys) under
|
|
397
|
+
* `atlasKey`. Fire-and-forget; the worker replies so `_pending` is cleared.
|
|
398
|
+
* Transfers the key buffer — the caller discards it after this call. */
|
|
399
|
+
retainGlyphs(atlasKey: string, keys: BigUint64Array): void;
|
|
400
|
+
/** Drop one visible-label reference from each glyph under `atlasKey`. */
|
|
401
|
+
releaseGlyphs(atlasKey: string, keys: BigUint64Array): void;
|
|
402
|
+
/** Shape multiple texts in one worker round-trip. */
|
|
403
|
+
prepareTextBatch(fontUrl: string, texts: string[]): Promise<BatchPrepareTextResult>;
|
|
404
|
+
/** Snapshot of the worker's WASM heap and font-cache memory usage. */
|
|
405
|
+
getMemoryStats(): Promise<FontWorkerMemoryStats>;
|
|
406
|
+
dispose(): void;
|
|
407
|
+
private _send;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
declare type FontWorkerClientOptions = {
|
|
411
|
+
/** Memory budget for the worker's font caches (font data + atlas pixels).
|
|
412
|
+
* Caps further atlas growth; the WASM heap itself never shrinks. */
|
|
413
|
+
fontBudgetBytes?: number;
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
/** Snapshot of the font worker's WASM heap and font-cache memory usage. */
|
|
417
|
+
export declare type FontWorkerMemoryStats = {
|
|
418
|
+
/** Total WASM linear memory of the font worker (never shrinks). */
|
|
419
|
+
heapBytes: number;
|
|
420
|
+
fontCount: number;
|
|
421
|
+
atlasCount: number;
|
|
422
|
+
glyphCount: number;
|
|
423
|
+
/** Raw font file bytes held by the cache. */
|
|
424
|
+
fontBytes: number;
|
|
425
|
+
/** Monochrome (SDF/MSDF) atlas pixel bytes. */
|
|
426
|
+
atlasBytes: number;
|
|
427
|
+
/** COLRv1 color atlas pixel bytes. */
|
|
428
|
+
colorAtlasBytes: number;
|
|
429
|
+
/** Configured cache budget; undefined when unlimited. */
|
|
430
|
+
budgetBytes?: number;
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Per-glyph character class used for line breaking during layout.
|
|
435
|
+
* Must match the `CHAR_CLASS_*` constants in
|
|
436
|
+
* `crates/navara_wasm_font_worker/src/shaping.rs`.
|
|
437
|
+
*/
|
|
438
|
+
export declare const GlyphCharClass: {
|
|
439
|
+
readonly Normal: 0;
|
|
440
|
+
/** Breakable whitespace: a line may wrap here, dropping the glyph. */
|
|
441
|
+
readonly Whitespace: 1;
|
|
442
|
+
/** Synthetic hard-break marker (zero advance, no atlas entry). */
|
|
443
|
+
readonly Newline: 2;
|
|
444
|
+
/** CJK-style character: a line may break after this glyph. */
|
|
445
|
+
readonly Ideographic: 3;
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
/** Glyph metrics from either the SDF or the color atlas. */
|
|
449
|
+
export declare type GlyphMetrics = {
|
|
450
|
+
glyphId: number;
|
|
451
|
+
/** Unique font index within the atlas (distinguishes glyphs from different fonts). */
|
|
452
|
+
fontIndex: number;
|
|
453
|
+
/** Pre-computed composite key (font_index, glyph_id) from WASM. */
|
|
454
|
+
compositeKey: bigint;
|
|
455
|
+
atlasX: number;
|
|
456
|
+
atlasY: number;
|
|
457
|
+
atlasW: number;
|
|
458
|
+
atlasH: number;
|
|
459
|
+
bearingX: number;
|
|
460
|
+
bearingY: number;
|
|
461
|
+
/** True when this glyph lives in the COLRv1 color atlas (RGBA) rather than the SDF atlas (R8). */
|
|
462
|
+
isColor: boolean;
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* A Map with a maximum capacity that evicts the least-recently used entries.
|
|
467
|
+
*
|
|
468
|
+
* Both `get` and `set` refresh the entry's position, making it the most recent.
|
|
469
|
+
* When the map exceeds `maxSize`, the least-recently used entries are evicted.
|
|
470
|
+
*/
|
|
471
|
+
export declare class LRUMap<K, V> {
|
|
472
|
+
private _map;
|
|
473
|
+
private _maxSize;
|
|
474
|
+
constructor(maxSize: number);
|
|
475
|
+
get size(): number;
|
|
476
|
+
has(key: K): boolean;
|
|
477
|
+
get(key: K): V | undefined;
|
|
478
|
+
set(key: K, value: V): void;
|
|
479
|
+
delete(key: K): boolean;
|
|
480
|
+
clear(): void;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export declare type ParseCssFontFamilyOptions = CssFontFaceFilter & {
|
|
484
|
+
/** Base URL used to resolve relative `src: url(...)` references. */
|
|
485
|
+
baseUrl?: string;
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Parse a CSS `unicode-range` descriptor value (e.g. `"U+0-7F, U+131, U+4??"`)
|
|
490
|
+
* into inclusive codepoint ranges. Supports single codepoints (`U+26`),
|
|
491
|
+
* intervals (`U+0102-0103`) and wildcards (`U+4??`).
|
|
492
|
+
*/
|
|
493
|
+
export declare function parseCssUnicodeRange(value: string): UnicodeRange[];
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Build a {@link FontFamily} from CSS `@font-face` rules, so faces and their
|
|
497
|
+
* unicode ranges don't have to be written by hand. Each `@font-face` block
|
|
498
|
+
* becomes one face: its `src` URL and its `unicode-range` (faces stay
|
|
499
|
+
* lazily downloaded — a face is only fetched once text actually needs a
|
|
500
|
+
* codepoint in its ranges). Blocks without a `unicode-range` cover all
|
|
501
|
+
* codepoints.
|
|
502
|
+
*
|
|
503
|
+
* Face priority follows CSS semantics: later `@font-face` rules take
|
|
504
|
+
* precedence when their unicode-ranges overlap, so faces come out in
|
|
505
|
+
* reverse stylesheet order (use the `fontFamily` array to order families
|
|
506
|
+
* explicitly). The resulting first face doubles as the fallback for
|
|
507
|
+
* codepoints no face covers — same semantics as a hand-written
|
|
508
|
+
* {@link FontFamily}.
|
|
509
|
+
*
|
|
510
|
+
* @param family Family name to register the faces under.
|
|
511
|
+
* @param cssText Stylesheet text containing `@font-face` rules.
|
|
512
|
+
* @param options Optional block filters and a `baseUrl` for relative URLs.
|
|
513
|
+
*/
|
|
514
|
+
export declare function parseFontFamilyFromCss(family: string, cssText: string, options?: ParseCssFontFamilyOptions): FontFamily;
|
|
515
|
+
|
|
516
|
+
/** A single shaped glyph with positioning info. */
|
|
517
|
+
export declare type ShapedGlyph = {
|
|
518
|
+
glyphId: number;
|
|
519
|
+
/** Unique font index within the atlas (distinguishes glyphs from different fonts). */
|
|
520
|
+
fontIndex: number;
|
|
521
|
+
/** Pre-computed composite key (font_index, glyph_id) from WASM. */
|
|
522
|
+
compositeKey: bigint;
|
|
523
|
+
xAdvance: number;
|
|
524
|
+
yAdvance: number;
|
|
525
|
+
xOffset: number;
|
|
526
|
+
yOffset: number;
|
|
527
|
+
/** One of `GlyphCharClass` (line-break info). */
|
|
528
|
+
charClass: number;
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
/** Result from shaping text: glyph positions + atlas metrics. */
|
|
532
|
+
export declare type ShapeTextResult = {
|
|
533
|
+
glyphs: ShapedGlyph[];
|
|
534
|
+
metrics: GlyphMetrics[];
|
|
535
|
+
/** Font units per em (needed for converting font-unit to pixel space) */
|
|
536
|
+
unitsPerEm: number;
|
|
537
|
+
/** Ascender in font units (hhea), for multi-line layout. */
|
|
538
|
+
ascender: number;
|
|
539
|
+
/** Descender in font units (hhea, negative below baseline). */
|
|
540
|
+
descender: number;
|
|
541
|
+
/** Extra line gap in font units (hhea). */
|
|
542
|
+
lineGap: number;
|
|
543
|
+
/** FontManager-internal: the atlas generation these metrics were built
|
|
544
|
+
* under. When the atlas evicts glyphs its generation bumps, marking older
|
|
545
|
+
* cached results stale so they are re-shaped on next use. Unset on results
|
|
546
|
+
* fresh from the worker; the FontManager stamps it when caching. */
|
|
547
|
+
_generation?: number;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
/** Inclusive codepoint range covered by a font face. */
|
|
551
|
+
export declare type UnicodeRange = {
|
|
552
|
+
from: number;
|
|
553
|
+
to: number;
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
export { }
|