@openpresentation/opf-render 0.13.0 → 0.14.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/README.md +107 -77
- package/dist/chart-options.js +26 -21
- package/dist/charts.js +204 -117
- package/dist/deck-runtime.js +21 -34
- package/dist/element.d.ts +11 -6
- package/dist/element.js +28 -18
- package/dist/export-browser.d.ts +7 -1
- package/dist/export-browser.js +7 -6
- package/dist/font-compatibility.js +4 -4
- package/dist/font-registry.js +324 -0
- package/dist/fonts-browser.d.ts +25 -3
- package/dist/fonts-browser.js +54 -3
- package/dist/fonts-node.d.ts +32 -16
- package/dist/fonts-node.js +110 -50
- package/dist/fonts.d.ts +48 -27
- package/dist/fonts.js +7 -320
- package/dist/index.d.ts +36 -16
- package/dist/lazy-font-list.js +1 -1
- package/dist/lazy-fonts.js +7 -7
- package/dist/pdf-fonts.js +1 -1
- package/dist/player.d.ts +4 -4
- package/dist/player.js +5 -5
- package/dist/preview-fonts.d.ts +4 -4
- package/dist/preview-fonts.js +6 -5
- package/dist/raster.js +24 -9
- package/dist/script-font-pack.js +19 -26
- package/dist/script-fonts.js +6 -17
- package/dist/svg.d.ts +30 -14
- package/dist/svg.js +286 -266
- package/dist/symbol-fonts.js +22 -55
- package/package.json +3 -3
- package/dist/font-policy.js +0 -2734
- package/dist/symbol-encodings.js +0 -7
package/dist/fonts-node.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
|
-
import { createFontRegistry, OPFFontError } from "./
|
|
6
|
+
import { createFontRegistry, OPFFontError } from "./font-registry.js";
|
|
7
7
|
import { BUNDLED_FONT_MANIFEST } from "./font-manifest.js";
|
|
8
8
|
import { lazyFontList } from "./lazy-font-list.js";
|
|
9
9
|
export { BUNDLED_FONT_MANIFEST } from "./font-manifest.js";
|
|
@@ -106,7 +106,7 @@ async function withScripts(loaded, scripts, {presentation, onDiagnostic, renderO
|
|
|
106
106
|
async function completeFallback(registry, presentation, loaded, onDiagnostic, renderOptions) {
|
|
107
107
|
const selection = loaded.selection;
|
|
108
108
|
if (!selection) return;
|
|
109
|
-
const seen = new Set([...selection.packages, ...selection.notInstalled]);
|
|
109
|
+
const seen = new Set([...(loaded.packages ?? []), ...selection.packages, ...selection.notInstalled]);
|
|
110
110
|
for (;;) {
|
|
111
111
|
const analysis = analyzePresentationScripts(presentation, undefined, renderOptions), covers = character => registry.scriptFacesCover(character);
|
|
112
112
|
const next = nextFallbackPackage(analysis, {covers, loaded: seen});
|
|
@@ -124,6 +124,7 @@ async function completeFallback(registry, presentation, loaded, onDiagnostic, re
|
|
|
124
124
|
}
|
|
125
125
|
registry.addFaces(embedUsed(extra.entries));
|
|
126
126
|
loaded.fontFiles.push(...extra.fontFiles);
|
|
127
|
+
loaded.packages?.push(next.name);
|
|
127
128
|
selection.packages.push(next.name);
|
|
128
129
|
}
|
|
129
130
|
}
|
|
@@ -152,63 +153,122 @@ async function withFaces(loaded, faces) {
|
|
|
152
153
|
return {...loaded, entries:[...own.entries, ...loaded.entries], fontFiles:[...own.fontFiles, ...loaded.fontFiles]};
|
|
153
154
|
}
|
|
154
155
|
|
|
155
|
-
/**
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Build the registry of a pack: `base` (the bundled Roboto faces), `office` (the metric and visual substitutes for the Office
|
|
158
|
+
* families plus the open families font schemes select, FF-31, optionally alongside the base) or `none` (only the caller's
|
|
159
|
+
* `faces`). Returns the live registry and what was loaded (`entries`, `fontFiles`, `packages`, `selection`), which `ensure` extends.
|
|
160
|
+
*/
|
|
161
|
+
async function buildRegistry(pack, {scripts, faces, presentation, onDiagnostic, renderOptions, ...options}) {
|
|
162
|
+
let loaded, registryOptions = options;
|
|
163
|
+
if (pack === "office") {
|
|
164
|
+
const {entries, fontFiles, packages} = await loadPack("office");
|
|
165
|
+
for (const [include, name] of [[options.includeOpenFonts, "open"], [options.includeBaseFonts, "base"]]) {
|
|
166
|
+
if (include === false) continue;
|
|
167
|
+
const extra = await loadPack(name);
|
|
168
|
+
fontFiles.push(...extra.fontFiles);
|
|
169
|
+
entries.push(...extra.entries);
|
|
170
|
+
packages.push(...extra.packages);
|
|
171
|
+
}
|
|
172
|
+
// Noto Sans (regular, bold, italic, bold italic) is the default Latin, Cyrillic and Greek fallback face
|
|
173
|
+
// (glyph fallback), so Georgia with Russian text previews without the scripts option. It is embedded in an
|
|
174
|
+
// SVG only when the slide's text draws it (embed "used"); raster output reads it from fontFiles. Unless the
|
|
175
|
+
// caller asked for it with scripts it is fallback-only, so no other family's preview changes. "auto" counts as asking for it when the
|
|
176
|
+
// presentation itself selects Latn (a Sylfaen scheme: Noto Sans is its designated replacement, which a fallback-only face never is), as
|
|
177
|
+
// an explicit list does; a presentation that does not select Latn keeps it fallback-only.
|
|
178
|
+
const requested = scripts === "auto" && presentation !== null && typeof presentation === "object" ? scriptFontPackages(autoScriptSelection(presentation, renderOptions).scripts).map(pkg => pkg.name)
|
|
179
|
+
: scripts === undefined || scripts === "auto" || (Array.isArray(scripts) && !scripts.length) ? [] : scriptFontPackages(scripts).map(pkg => pkg.name);
|
|
180
|
+
const fallback = await loadPackages(scriptFontPackages(["Latn"]).filter(pkg => !requested.includes(pkg.name)), undefined, {fallbackOnly:true});
|
|
181
|
+
fontFiles.push(...fallback.fontFiles);
|
|
182
|
+
entries.push(...fallback.entries);
|
|
183
|
+
packages.push(...fallback.packages);
|
|
184
|
+
loaded = await withFaces(await withScripts({entries, fontFiles, packages}, scripts, {presentation, onDiagnostic, renderOptions}), faces);
|
|
185
|
+
// A package that is the renamed successor of a family answers to the old name through a built-in alias.
|
|
186
|
+
const aliases = options.includeOpenFonts === false ? options.aliases : {...renamedAliases(), ...options.aliases};
|
|
187
|
+
registryOptions = {substitutionPolicy:"metric", ...options, ...(aliases ? {aliases} : {})};
|
|
188
|
+
} else {
|
|
189
|
+
loaded = await withFaces(await withScripts(pack === "none" ? {entries:[], fontFiles:[], packages:[]} : await loadPack("base"), scripts, {presentation, onDiagnostic, renderOptions}), faces);
|
|
190
|
+
}
|
|
191
|
+
loaded.packages ??= [];
|
|
192
|
+
const registry = Object.assign(createFontRegistry(loaded.entries, registryOptions), {fontFiles: loaded.fontFiles, ...(loaded.selection ? {scriptSelection: loaded.selection} : {})});
|
|
159
193
|
registry.lazyFonts = lazyOf(registry);
|
|
160
|
-
await completeFallback(registry, presentation,
|
|
161
|
-
return registry;
|
|
194
|
+
await completeFallback(registry, presentation, loaded, onDiagnostic, renderOptions);
|
|
195
|
+
return {registry, loaded};
|
|
162
196
|
}
|
|
163
197
|
|
|
164
|
-
/**
|
|
165
|
-
*
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Load the faces a text needs that this handle does not hold yet: what `scripts: "auto"` does at load, run again for another
|
|
200
|
+
* presentation (an edit that adds a script, another deck on the same handle). Cheap when nothing is needed. A package that is not
|
|
201
|
+
* installed, or a script no pinned font serves, is reported once through `onDiagnostic`. Resolves with the script packages this
|
|
202
|
+
* call added (`scripts`; `lazy` is always empty here: Node loads every vendored face with its pack) and the drawn CJK
|
|
203
|
+
* characters no loaded face covers.
|
|
204
|
+
*/
|
|
205
|
+
async function ensureFonts(registry, loaded, presentation, {onDiagnostic, renderOptions} = {}) {
|
|
206
|
+
if (presentation === null || typeof presentation !== "object") throw new OPFFontError("invalid-font-scripts", "ensure needs the presentation whose text decides the scripts.");
|
|
207
|
+
const selection = (loaded.selection ??= {detected: [], scripts: [], unavailable: [], packages: [], notInstalled: []});
|
|
208
|
+
registry.scriptSelection = selection;
|
|
209
|
+
const before = loaded.packages.length;
|
|
210
|
+
const wanted = scriptSelectionOf(analyzePresentationScripts(presentation, undefined, renderOptions));
|
|
211
|
+
const held = new Set([...loaded.packages, ...selection.notInstalled]);
|
|
212
|
+
const skipped = [];
|
|
213
|
+
const extra = await loadPackages(scriptFontPackages(wanted.scripts).filter(pkg => !held.has(pkg.name)), skipped);
|
|
214
|
+
if (extra.entries.length) registry.addFaces(embedUsed(extra.entries));
|
|
215
|
+
loaded.fontFiles.push(...extra.fontFiles);
|
|
216
|
+
loaded.packages.push(...extra.packages);
|
|
217
|
+
selection.packages.push(...extra.packages);
|
|
218
|
+
for (const item of skipped) {
|
|
219
|
+
selection.notInstalled.push(item.package);
|
|
220
|
+
onDiagnostic?.({code: "script-font-not-installed", package: item.package, scripts: item.scripts, message: `Install ${item.package}@${item.version} to preview ${item.scripts.join(", ")} text with its designated open font.`});
|
|
221
|
+
}
|
|
222
|
+
for (const script of wanted.unavailable) if (!selection.unavailable.includes(script)) {
|
|
223
|
+
selection.unavailable.push(script);
|
|
224
|
+
onDiagnostic?.({code: "script-font-unavailable", script, message: `No pinned open font serves script '${script}'; that text uses the design font.`});
|
|
174
225
|
}
|
|
175
|
-
// Noto Sans (regular, bold, italic, bold italic) is the default Latin, Cyrillic and Greek fallback face
|
|
176
|
-
// (glyph fallback), so Georgia with Russian text previews without the scripts option. It is embedded in an
|
|
177
|
-
// SVG only when the slide's text draws it (embed "used"); raster output reads it from fontFiles. Unless the
|
|
178
|
-
// caller asked for it with scripts it is fallback-only, so no other family's preview changes. "auto" counts as asking for it when the
|
|
179
|
-
// presentation itself selects Latn (a Sylfaen scheme: Noto Sans is its designated replacement, which a fallback-only face never is), as
|
|
180
|
-
// an explicit list does; a presentation that does not select Latn keeps it fallback-only.
|
|
181
|
-
const requested = scripts === "auto" && presentation !== null && typeof presentation === "object" ? scriptFontPackages(autoScriptSelection(presentation, renderOptions).scripts).map(pkg => pkg.name)
|
|
182
|
-
: scripts === undefined || scripts === "auto" || (Array.isArray(scripts) && !scripts.length) ? [] : scriptFontPackages(scripts).map(pkg => pkg.name);
|
|
183
|
-
const fallback = await loadPackages(scriptFontPackages(["Latn"]).filter(pkg => !requested.includes(pkg.name)), undefined, {fallbackOnly:true});
|
|
184
|
-
fontFiles.push(...fallback.fontFiles);
|
|
185
|
-
entries.push(...fallback.entries);
|
|
186
|
-
packages.push(...fallback.packages);
|
|
187
|
-
const loaded = await withFaces(await withScripts({entries, fontFiles, packages}, scripts, {presentation, onDiagnostic, renderOptions}), faces);
|
|
188
|
-
const aliases = options.includeOpenFonts === false ? options.aliases : {...renamedAliases(), ...options.aliases};
|
|
189
|
-
const registry = Object.assign(createFontRegistry(loaded.entries,{substitutionPolicy:"metric",...options,...(aliases?{aliases}:{})}),{fontFiles:loaded.fontFiles, ...(loaded.selection ? {scriptSelection: loaded.selection} : {})});
|
|
190
|
-
registry.lazyFonts = lazyOf(registry);
|
|
191
226
|
await completeFallback(registry, presentation, loaded, onDiagnostic, renderOptions);
|
|
192
|
-
return
|
|
227
|
+
return {scripts: loaded.packages.slice(before), lazy: [], uncovered: selection.uncovered ? [...selection.uncovered] : []};
|
|
193
228
|
}
|
|
194
229
|
|
|
195
|
-
/**
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
230
|
+
/**
|
|
231
|
+
* The fonts handle: one set of verified font inputs for layout, SVG, editor, PPTX and Node raster export. Pass it as `{ fonts }` to
|
|
232
|
+
* `renderSvg`, `renderSlideSvg`, `svgToPng`, `svgToPdf`, core `paginate` and `validate`, and `toPptx`.
|
|
233
|
+
*
|
|
234
|
+
* Bundled, openly licensed faces only: no system font discovery and no network requests. `pack`: `base` (default, Roboto),
|
|
235
|
+
* `office` (the Office substitutes and the open families) or `none` (only the `faces` you supply). Everything else
|
|
236
|
+
* (`substitutionPolicy`, `aliases`, `fallbackFamily`, `themeFonts`, `strictGlyphs`, `includeBaseFonts`, `includeOpenFonts`,
|
|
237
|
+
* `faces`, `scripts`, `presentation`, `onDiagnostic`, `renderOptions`) goes to the registry. `embedScriptFonts` embeds the large script
|
|
238
|
+
* faces in standalone SVG (default false: raster output reads them from `fontFiles`).
|
|
239
|
+
*/
|
|
240
|
+
export async function loadFonts({pack = "base", embedScriptFonts = false, ...options} = {}) {
|
|
241
|
+
if (pack !== "base" && pack !== "office" && pack !== "none") throw new OPFFontError("invalid-font-pack", "Choose the base, office or none font pack.", {pack});
|
|
242
|
+
const {registry, loaded} = await buildRegistry(pack, options);
|
|
243
|
+
// Script faces are large (CJK faces are 5-10 MB each). Raster output reads them from fontFiles; embed them in standalone SVG only
|
|
244
|
+
// on request. The default Noto Sans fallback is always offered (embed "used"), so an SVG carries it exactly when its text draws it.
|
|
245
|
+
const selectEmbedded = () => registry.selectEmbeddedFonts(face => embedScriptFonts || !face.scripts || face.fallbackOnly);
|
|
246
|
+
// The embedded list is base64 of every face: computed on first use, and again after `ensure` added faces.
|
|
247
|
+
let embeddedFonts, fontFiles = [...registry.fontFiles];
|
|
248
|
+
const refresh = () => { embeddedFonts = undefined; fontFiles = [...registry.fontFiles]; };
|
|
203
249
|
return {
|
|
250
|
+
textMeasurement: registry.textMeasurement,
|
|
251
|
+
get embeddedFonts() { return (embeddedFonts ??= selectEmbedded()); },
|
|
252
|
+
get fontFiles() { return fontFiles; },
|
|
253
|
+
useBundledFonts: false,
|
|
254
|
+
loadSystemFonts: false,
|
|
204
255
|
registry,
|
|
205
|
-
manifest:BUNDLED_FONT_MANIFEST,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
256
|
+
manifest: BUNDLED_FONT_MANIFEST,
|
|
257
|
+
get substitutions() { return registry.substitutions; },
|
|
258
|
+
/** Load the script faces the presentation's text needs (see `ensureFonts`); `embeddedFonts` and `fontFiles` then include them. */
|
|
259
|
+
async ensure(presentation, callOptions = {}) {
|
|
260
|
+
const result = await ensureFonts(registry, loaded, presentation, {onDiagnostic: callOptions.onDiagnostic ?? options.onDiagnostic, renderOptions: {...options.renderOptions, ...callOptions.renderOptions}});
|
|
261
|
+
refresh();
|
|
262
|
+
return result;
|
|
263
|
+
},
|
|
264
|
+
/** Synchronous: the script packages the presentation needs that are not loaded yet. Empty means `ensure` loads nothing. */
|
|
265
|
+
pending(presentation, renderOptions) {
|
|
266
|
+
const held = new Set([...loaded.packages, ...(loaded.selection?.notInstalled ?? [])]);
|
|
267
|
+
const analysis = analyzePresentationScripts(presentation, undefined, {...options.renderOptions, ...renderOptions});
|
|
268
|
+
const primary = scriptFontPackages(scriptSelectionOf(analysis).scripts).map(pkg => pkg.name).filter(name => !held.has(name));
|
|
269
|
+
if (primary.length) return primary;
|
|
270
|
+
const next = nextFallbackPackage(analysis, {covers: character => registry.scriptFacesCover(character), loaded: held});
|
|
271
|
+
return next ? [next.name] : [];
|
|
212
272
|
},
|
|
213
273
|
};
|
|
214
274
|
}
|
package/dist/fonts.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import type { TextMeasurement, TextStyle } from "@openpresentation/opf/composition";
|
|
1
|
+
import type { TextMeasurement, TextStyle, ScriptRole } from "@openpresentation/opf/composition";
|
|
2
|
+
import type { FontPolicyEntry } from "@openpresentation/opf/font-policy";
|
|
3
|
+
import type { LazyFont } from "./fonts-node.js";
|
|
4
|
+
// Core owns these: the font policy table and lookup, the symbol-font code rules and the script slot of a script. They are core's own
|
|
5
|
+
// exports (the same objects), not copies.
|
|
6
|
+
export { FONT_POLICY, fontPolicyFor } from "@openpresentation/opf/font-policy";
|
|
7
|
+
export type { FontPolicyEntry } from "@openpresentation/opf/font-policy";
|
|
8
|
+
export { isSymbolEncodedFamily, mapSymbolText, symbolCodeOf } from "@openpresentation/opf/symbol-font-encodings";
|
|
9
|
+
export { scriptFontRole } from "@openpresentation/opf/composition";
|
|
10
|
+
export type { ScriptRole } from "@openpresentation/opf/composition";
|
|
2
11
|
export interface FontFaceInput { data: Uint8Array; family?: string; weight?: number; italic?: boolean; postscriptName?: string; license?: string; /** Serves glyph fallback and requests by its own family only; never a replacement for another family. */ fallbackOnly?: boolean; /** "used" embeds the face in an SVG only when the slide's text names its family (the open pack, FF-31). Default "always". */ embed?: "always" | "used"; /** ISO 15924 scripts a designated script replacement face serves (FF-19). */ scripts?: string[] }
|
|
3
12
|
export interface EmbeddedFont { family: string; weight: number; italic?: boolean; dataUrl: string; license?: string; embed?: "used" }
|
|
4
13
|
export type FontCompatibility = "exact" | "metric" | "visual" | "generic";
|
|
@@ -17,18 +26,6 @@ export interface FontResolution {
|
|
|
17
26
|
measured?:FontReplacementMeasurement;
|
|
18
27
|
licenseClass?:FontPolicyEntry['licenseClass']; availability?:FontPolicyEntry['availability'];
|
|
19
28
|
}
|
|
20
|
-
/** One OPF font policy row (snapshot of opf spec/reference/font-policy.json, decisions applied). */
|
|
21
|
-
export interface FontPolicyEntry {
|
|
22
|
-
family:string; licenseClass:"open"|"proprietary-standard"|"proprietary-nonstandard"; license:string;
|
|
23
|
-
availability:("windows"|"windows-optional"|"macos"|"office"|"office-cloud")[]; embeddableByOpf:boolean;
|
|
24
|
-
replacement:{family:string; compatibility:"metric"|"visual"; decision?:string; metricModeFallback?:true; weight?:number; measured:FontReplacementMeasurement|null; source?:string}|null;
|
|
25
|
-
alternates?:string[];
|
|
26
|
-
}
|
|
27
|
-
export declare const FONT_POLICY: readonly Readonly<FontPolicyEntry>[];
|
|
28
|
-
export declare const FONT_POLICY_SOURCE: Readonly<{version:number; path:string; sha256:string}>;
|
|
29
|
-
/** Provisional owner decisions applied to the snapshot (owner may revise). */
|
|
30
|
-
export declare const FONT_POLICY_DECISIONS: Readonly<Record<string, unknown>>;
|
|
31
|
-
export declare function fontPolicyFor(family:string): Readonly<FontPolicyEntry>|undefined;
|
|
32
29
|
export interface FontRegistryOptions {
|
|
33
30
|
aliases?: Record<string,string>; fallbackFamily?: string; strictGlyphs?: boolean;
|
|
34
31
|
substitutionPolicy?: "none" | "metric" | "visual";
|
|
@@ -36,6 +33,42 @@ export interface FontRegistryOptions {
|
|
|
36
33
|
}
|
|
37
34
|
export declare const FONT_COMPATIBILITY: readonly Readonly<{requestedFamily:string;substitutes:readonly string[];compatibility:"metric"|"visual";weights?:readonly number[];weight?:number;source?:string;measured?:FontReplacementMeasurement;decision?:string;metricModeFallback?:true;licenseClass?:FontPolicyEntry['licenseClass'];note:string}>[];
|
|
38
35
|
export declare const EXPERIMENTAL_FONT_CANDIDATES: readonly Readonly<{requestedFamily:string;substitute:string;source:string;note:string}>[];
|
|
36
|
+
/**
|
|
37
|
+
* What the deck-level functions read from their `fonts` option: `renderSvg`, `renderSlideSvg` and `<opf-deck>` take the measurement and
|
|
38
|
+
* the faces to embed; `svgToPng` and `svgToPdf` (Node) take the font files; core `paginate`, `validate` and `resolveSlideContext` take the
|
|
39
|
+
* measurement. The object `loadFonts()` returns is a `FontsHandle`, which extends this; any object with these fields works.
|
|
40
|
+
*/
|
|
41
|
+
export interface RenderFonts {
|
|
42
|
+
/** Measures text with the real faces. Without it layout uses core's portable estimate. */
|
|
43
|
+
textMeasurement?: TextMeasurement;
|
|
44
|
+
/** Faces `renderSvg` writes into each SVG as @font-face data; a face flagged `embed: "used"` only when a slide draws its family. */
|
|
45
|
+
embeddedFonts?: readonly EmbeddedFont[];
|
|
46
|
+
/** Font files the Node raster and PDF conversions draw with. */
|
|
47
|
+
fontFiles?: readonly string[];
|
|
48
|
+
/** Whether a conversion adds the bundled base faces to `fontFiles`. Default true; a handle that already holds them says false. */
|
|
49
|
+
useBundledFonts?: boolean;
|
|
50
|
+
/** Whether the raster conversion loads system fonts. Default false (the output never depends on the machine). */
|
|
51
|
+
loadSystemFonts?: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** What `fonts.ensure(presentation)` loaded: the script packages and vendored faces that were missing, and drawn CJK characters no face covers. */
|
|
54
|
+
export interface EnsureResult { scripts: string[]; lazy: LazyFont[]; uncovered: string[] }
|
|
55
|
+
/** The fonts handle `loadFonts()` returns from `/fonts-node` and `/fonts-browser`: pass it as `{ fonts }` to every deck-level function. */
|
|
56
|
+
export interface FontsHandle extends RenderFonts {
|
|
57
|
+
readonly textMeasurement: FontRegistry["textMeasurement"];
|
|
58
|
+
readonly embeddedFonts: EmbeddedFont[];
|
|
59
|
+
/** The face registry behind the handle (shaping, resolution, lazy and script loading). */
|
|
60
|
+
readonly registry: FontRegistry;
|
|
61
|
+
/** The pinned manifest of the bundled font packages. */
|
|
62
|
+
readonly manifest: { readonly version: number; readonly packages: readonly object[] };
|
|
63
|
+
/** The substitutions made so far (a requested family drawn with another face), as `registry.substitutions`. */
|
|
64
|
+
readonly substitutions: FontResolution[];
|
|
65
|
+
/** Load the script (and, in a browser, vendored) faces the presentation's text needs. Cheap when nothing is missing. */
|
|
66
|
+
ensure(presentation: unknown, options?: object): Promise<EnsureResult>;
|
|
67
|
+
/** Synchronous: the files and script packages `ensure` would load. Empty means a render can start now. */
|
|
68
|
+
pending(presentation: unknown, renderOptions?: object): string[];
|
|
69
|
+
/** Remove the faces this handle added to the document (a browser handle). */
|
|
70
|
+
dispose?(): void;
|
|
71
|
+
}
|
|
39
72
|
export interface FaceDescription { family:string; weight:number; italic:boolean; scripts?:string[] }
|
|
40
73
|
export interface FontRegistry {
|
|
41
74
|
textMeasurement: TextMeasurement & {outlineBounds: NonNullable<TextMeasurement['outlineBounds']>; resolveFont(style: TextStyle): FontResolution};
|
|
@@ -46,6 +79,8 @@ export interface FontRegistry {
|
|
|
46
79
|
selectEmbeddedFonts(predicate: (face: FaceDescription) => boolean): EmbeddedFont[];
|
|
47
80
|
/** Parsed face metadata in entry order, without encoding font bytes. */
|
|
48
81
|
describeFaces(): FaceDescription[];
|
|
82
|
+
/** Every face as `{ family, data }`, the bytes the registry measures with. */
|
|
83
|
+
exportFaces(): { family: string; data: Uint8Array }[];
|
|
49
84
|
readonly substitutions: FontResolution[];
|
|
50
85
|
/** True when a loaded script-pack face has a glyph for the character. */
|
|
51
86
|
scriptFacesCover(character: string): boolean;
|
|
@@ -53,10 +88,7 @@ export interface FontRegistry {
|
|
|
53
88
|
addFaces(entries: FontFaceInput[]): { family: string; weight: number; italic: boolean; scripts?: string[] }[];
|
|
54
89
|
}
|
|
55
90
|
export declare class OPFFontError extends Error { code:string; details:Record<string,unknown>; constructor(code:string,message:string,details?:Record<string,unknown>) }
|
|
56
|
-
export declare function createFontRegistry(entries: FontFaceInput[], options?: FontRegistryOptions): FontRegistry;
|
|
57
91
|
|
|
58
|
-
/** OOXML script slot. */
|
|
59
|
-
export type ScriptRole = "latin" | "eastAsian" | "complexScript";
|
|
60
92
|
export interface ScriptFontSlots { latin: string; eastAsian: string; complexScript: string }
|
|
61
93
|
/** Core `resolveScriptFonts` output, or the same shape. `serif` prefers serif replacements. */
|
|
62
94
|
export interface ScriptFontProfile {
|
|
@@ -81,7 +113,6 @@ export interface ScriptFonts {
|
|
|
81
113
|
export declare const SCRIPT_FONT_FAMILIES: Readonly<Record<string, Readonly<{ sans?: string; serif?: string }>>>;
|
|
82
114
|
export declare const SCRIPT_FONT_REPLACEMENTS: readonly Readonly<{requestedFamily:string;script:string;substitutes:readonly string[];compatibility:"visual";note:string}>[];
|
|
83
115
|
export declare function scriptOfCharacter(character: string): string;
|
|
84
|
-
export declare function scriptFontRole(script: string): ScriptRole;
|
|
85
116
|
export declare function itemizeScripts(text: string, profile?: ScriptFontProfile): ScriptRun[];
|
|
86
117
|
/** Script keys in the strings of a JSON value. The profile's own script counts unless `includeLanguage` is false; `ignoreKeys` are not visited. */
|
|
87
118
|
export declare function detectScripts(value: unknown, profile?: ScriptFontProfile, options?: { includeLanguage?: boolean; ignoreKeys?: readonly string[] }): string[];
|
|
@@ -107,17 +138,7 @@ export declare const SYMBOL_PLACEHOLDER: string;
|
|
|
107
138
|
export declare const SYMBOL_PREVIEW_FACES: Readonly<Record<SymbolFontFamily, readonly string[]>>;
|
|
108
139
|
/** Every open face a symbol preview may draw with. */
|
|
109
140
|
export declare const SYMBOL_FACE_FAMILIES: readonly string[];
|
|
110
|
-
/** Per family: the verified font version and, for codes 0x20..0xFF in order, `[unicode, advance, reason?]` (hex code points joined with '+', font units). */
|
|
111
|
-
export declare const SYMBOL_ENCODINGS: readonly Readonly<{ family: SymbolFontFamily; version: string; unitsPerEm: number; mapped: number; codes: readonly (readonly [string | null, number | null, string?])[] }>[];
|
|
112
|
-
/** Which core table (spec/reference/symbol-font-encodings.json) the snapshot came from. */
|
|
113
|
-
export declare const SYMBOL_ENCODINGS_SOURCE: Readonly<{ version: number; path: string; sha256: string }>;
|
|
114
|
-
export declare function isSymbolEncodedFamily(family: string): boolean;
|
|
115
|
-
export declare function symbolEncodingFor(family: string): (typeof SYMBOL_ENCODINGS)[number] | undefined;
|
|
116
141
|
export declare function symbolPreviewFaces(family: string): readonly string[];
|
|
117
|
-
/** The symbol code (0x20..0xFF) of one character: a private-use U+F0xx, an ASCII or Latin-1 character, or a Windows-1252 character at 0x80..0x9F; null for anything else. */
|
|
118
|
-
export declare function symbolCodeOf(character: string): number | null;
|
|
119
|
-
/** Normalise text in a symbol-encoded family: per character its code (null when not a code), the Unicode equivalent to draw (or null with a reason) and the verified font's advance in em. */
|
|
120
|
-
export declare function mapSymbolText(family: string, text: string): { source: string; code: number | null; unicode: string | null; advance: number | null; reason?: string }[];
|
|
121
142
|
/** Wrap a measurement so pagination, the renderer and the editor itemize script runs identically. */
|
|
122
143
|
export declare function createScriptTextMeasurement(measurement: TextMeasurement, profile: ScriptFontProfile, options?: ScriptFontsOptions): TextMeasurement;
|
|
123
144
|
export declare function openTypeLanguage(tag: string | undefined): string | undefined;
|