Skip to main content

webfont_generator/
types.rs

1use std::collections::HashMap;
2
3use serde_json::{Map, Value};
4
5/// What happened to a file, for [`crate::GenerateWebfontsResult::regenerate`]. `name` is the
6/// caller-resolved glyph name (the `rename` callback, if any, is applied by the caller).
7pub enum GlyphChange {
8    /// A new file. `name` overrides the file-stem glyph name when `Some`.
9    Added { name: Option<String> },
10    /// An existing file's contents changed. `name` overrides the glyph name when `Some`.
11    Changed { name: Option<String> },
12    /// The file was deleted.
13    Removed,
14}
15
16/// One entry in the `changes` array passed to the Node binding's `regenerate`. The complete
17/// ordered file list passed alongside it controls final glyph order; this only describes which
18/// files need re-reading, renaming, or removal.
19pub struct GlyphChangeEntry {
20    /// Path of the changed file.
21    pub path: String,
22    /// What happened to the file.
23    pub change_type: String,
24    /// Resolved glyph name (with the caller's `rename` already applied). Optional for `'added'`
25    /// and `'changed'` (defaults to the file stem/current name); ignored for `'removed'`.
26    pub name: Option<String>,
27}
28
29/// Complete ordered input membership for a regeneration operation. The case must match the
30/// result's generation mode. Synchronous methods borrow this value; async methods consume it.
31pub enum RegenerationFiles {
32    /// Single-design font inputs, in the order a fresh generation would use.
33    Single(Vec<String>),
34    /// Complete file sets for every configured variant, each named exactly once. The order of
35    /// these entries does not change configured design order. Paths can be shared between
36    /// designs; each design's file list independently determines its membership and order.
37    Variants(Vec<VariantFileSet>),
38}
39
40/// Complete file set for one configured variant during regeneration.
41pub struct VariantFileSet {
42    /// Existing variant name. Full re-diff requires every configured variant exactly once.
43    pub variant: String,
44    /// Complete ordered file set for this variant.
45    pub files: Vec<String>,
46}
47
48/// Font output format. Used in the `types` and `order` options to control which
49/// formats are generated and the order they appear in the CSS `@font-face`
50/// `src:` descriptor.
51#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
52#[derive(Clone, Copy, PartialEq, Eq, Hash)]
53#[cfg_attr(
54    feature = "cli",
55    derive(serde::Deserialize),
56    serde(rename_all = "lowercase")
57)]
58pub enum FontType {
59    /// SVG font (`.svg`). Legacy format; intermediate representation that all
60    /// other formats are derived from.
61    Svg,
62    /// TrueType font (`.ttf`).
63    Ttf,
64    /// Embedded OpenType (`.eot`). Legacy format for older Internet Explorer.
65    Eot,
66    /// Web Open Font Format 1.0 (`.woff`).
67    Woff,
68    /// Web Open Font Format 2.0 (`.woff2`). Best compression; preferred for
69    /// modern browsers.
70    Woff2,
71}
72
73/// One named SVG design in a multi-variant icon family.
74#[derive(Clone)]
75#[cfg_attr(
76    feature = "cli",
77    derive(serde::Deserialize),
78    serde(rename_all = "camelCase", deny_unknown_fields)
79)]
80pub struct FontVariant {
81    /// User-facing variant name, used to derive CSS modifier classes.
82    pub name: String,
83    /// SVG files that belong to this variant.
84    pub files: Vec<String>,
85    /// Optional explicit CSS weight coordinate in the range 1 through 1000. Automatic weights
86    /// resolve outward from the default in steps of 100, or evenly when an interval is crowded.
87    pub weight: Option<u16>,
88    /// Whether this is the family's default variant. Exactly one variant must set this to `true`.
89    pub default: Option<bool>,
90}
91
92/// Family-wide behavior when a logical glyph is absent from a variant.
93#[derive(Clone, Copy, PartialEq, Eq)]
94#[cfg_attr(
95    feature = "cli",
96    derive(serde::Deserialize),
97    serde(rename_all = "lowercase")
98)]
99pub enum MissingGlyphBehavior {
100    /// Use an empty outline while retaining the logical glyph's advance.
101    Blank,
102    /// Reject generation and report every missing variant/glyph pair.
103    Error,
104    /// Reuse the outline from the named fallback variant, which must contain every logical glyph.
105    Fallback,
106}
107
108/// Family-wide missing-glyph policy for multi-variant generation.
109#[derive(Clone)]
110#[cfg_attr(
111    feature = "cli",
112    derive(serde::Deserialize),
113    serde(rename_all = "camelCase", deny_unknown_fields)
114)]
115pub struct MissingGlyphOptions {
116    /// Missing-glyph behavior. Variant mode defaults to [`MissingGlyphBehavior::Blank`] when this
117    /// object is omitted.
118    pub behavior: MissingGlyphBehavior,
119    /// Fallback variant name. Required only when `behavior` is `fallback`; the named variant must
120    /// contain every logical glyph in the family.
121    pub variant: Option<String>,
122}
123
124impl FontType {
125    /// Returns the CSS `format()` value (e.g., "truetype", "woff2").
126    #[inline]
127    pub fn css_format(self) -> &'static str {
128        match self {
129            FontType::Svg => "svg",
130            FontType::Ttf => "truetype",
131            FontType::Eot => "embedded-opentype",
132            FontType::Woff => "woff",
133            FontType::Woff2 => "woff2",
134        }
135    }
136
137    /// Returns the file extension (e.g., "svg", "ttf", "woff2").
138    #[inline]
139    pub fn as_extension(self) -> &'static str {
140        match self {
141            FontType::Svg => "svg",
142            FontType::Ttf => "ttf",
143            FontType::Eot => "eot",
144            FontType::Woff => "woff",
145            FontType::Woff2 => "woff2",
146        }
147    }
148}
149
150/// SVG-format–specific options for the intermediate SVG font and the per-glyph
151/// path processing that feeds every other format.
152#[derive(Clone, Default)]
153#[cfg_attr(
154    feature = "cli",
155    derive(serde::Deserialize),
156    serde(rename_all = "camelCase", deny_unknown_fields)
157)]
158pub struct SvgFormatOptions {
159    /// SVG-format override of the top-level `centerVertically` option. When set,
160    /// it wins over the top-level value; centers each glyph vertically inside
161    /// the em-square based on its bounding box.
162    pub center_vertically: Option<bool>,
163    /// Value of the SVG font's `id` attribute. Defaults to `fontName` when
164    /// omitted.
165    pub font_id: Option<String>,
166    /// Content embedded inside the generated SVG font's `<metadata>` element.
167    pub metadata: Option<String>,
168    /// SVG-format override of the top-level `optimizeOutput` option. When set,
169    /// it wins over the top-level value; runs an SVG path optimizer over each
170    /// glyph, trading a small amount of build time for smaller output bytes.
171    pub optimize_output: Option<bool>,
172    /// SVG-format override of the top-level `preserveAspectRatio` option. When
173    /// set, it wins over the top-level value; preserves the source viewBox
174    /// aspect ratio when scaling glyphs into the em-square.
175    pub preserve_aspect_ratio: Option<bool>,
176}
177
178/// TTF-format–specific options. Populates fields in the generated TTF `name`
179/// and `head` tables.
180#[derive(Clone)]
181#[cfg_attr(
182    feature = "cli",
183    derive(serde::Deserialize),
184    serde(rename_all = "camelCase", deny_unknown_fields)
185)]
186pub struct TtfFormatOptions {
187    /// Copyright string written to the TTF `name` table (record id 0).
188    pub copyright: Option<String>,
189    /// Description string written to the TTF `name` table (record id 10).
190    pub description: Option<String>,
191    /// Unix timestamp in seconds used for the `created` and `modified` fields
192    /// in the TTF `head` table. Pin to a fixed value to produce byte-stable
193    /// reproducible builds.
194    pub ts: Option<i64>,
195    /// Manufacturer URL written to the TTF `name` table (record id 11).
196    pub url: Option<String>,
197    /// Version string written to the TTF `name` table (record id 5).
198    pub version: Option<String>,
199}
200
201/// WOFF-format–specific options. Affects only WOFF1 output; WOFF2 ignores these.
202#[derive(Clone)]
203#[cfg_attr(
204    feature = "cli",
205    derive(serde::Deserialize),
206    serde(rename_all = "camelCase", deny_unknown_fields)
207)]
208pub struct WoffFormatOptions {
209    /// XML string embedded in the WOFF1 metadata block.
210    pub metadata: Option<String>,
211}
212
213/// WOFF2-format–specific options. Affects only WOFF2 output.
214#[derive(Clone)]
215#[cfg_attr(
216    feature = "cli",
217    derive(serde::Deserialize),
218    serde(rename_all = "camelCase", deny_unknown_fields)
219)]
220pub struct Woff2FormatOptions {
221    /// Brotli compression quality used when encoding WOFF2, from `0` (fastest,
222    /// largest output) to `11` (slowest, smallest output). This tunes compression
223    /// effort only and never changes glyph fidelity — the decompressed font is
224    /// identical at every level. Defaults to `11` for the smallest output; lower it
225    /// (e.g. to `10`) for faster encoding at a marginal size cost. Must be between
226    /// `0` and `11`; other values are rejected.
227    pub compression_quality: Option<u8>,
228}
229
230/// Per-format configuration object. Each field carries options that only apply
231/// to the corresponding output format.
232#[derive(Clone, Default)]
233#[cfg_attr(
234    feature = "cli",
235    derive(serde::Deserialize),
236    serde(rename_all = "camelCase", deny_unknown_fields)
237)]
238pub struct FormatOptions {
239    /// SVG-format options.
240    pub svg: Option<SvgFormatOptions>,
241    /// TTF-format options.
242    pub ttf: Option<TtfFormatOptions>,
243    /// WOFF1-format options.
244    pub woff: Option<WoffFormatOptions>,
245    /// WOFF2-format options.
246    pub woff2: Option<Woff2FormatOptions>,
247}
248
249/// Resolved variant metadata supplied to CSS and HTML template callbacks.
250#[derive(Clone)]
251pub struct TemplateVariant {
252    /// User-provided variant name.
253    pub name: String,
254    /// Resolved CSS weight coordinate.
255    pub weight: u32,
256    /// Whether this is the family's default design.
257    pub default: bool,
258    /// Unescaped modifier class for use in HTML.
259    pub class_name: String,
260    /// CSS-escaped modifier class identifier, without a leading dot.
261    pub selector: String,
262}
263
264/// Fields supplied to a `cssContext` callback. Additional keys from
265/// user-supplied `templateOptions` are merged into the same object at runtime,
266/// so the JS-side type widens this with an open-ended index signature.
267#[derive(Clone)]
268pub struct CssContext {
269    /// Name of the generated font, mirroring the `fontName` option.
270    pub font_name: String,
271    /// Pre-rendered value for the CSS `@font-face` `src:` descriptor — a
272    /// comma-separated list of `url(...) format(...)` entries derived from the
273    /// configured `types`, `order`, and `cssFontsUrl`.
274    pub src: String,
275    /// Map from glyph name to its assigned codepoint as a hex-encoded string
276    /// (e.g. `"add" -> "f101"`), suitable for use inside CSS `content`
277    /// declarations like `content: "\f101"`.
278    pub codepoints: HashMap<String, String>,
279    /// Ordered resolved variants; absent in ordinary mode unless supplied by template options.
280    /// The mode-independent Node declaration is unknown because ordinary template data is arbitrary.
281    pub variants: Option<Vec<TemplateVariant>>,
282    /// Modifier class prefix, supplied in variant mode.
283    pub variant_class_prefix: Option<String>,
284    /// Resolved default weight, supplied in variant mode.
285    pub default_weight: Option<u32>,
286    /// Resolved font style, supplied in variant mode.
287    pub font_style: Option<String>,
288}
289
290/// Fields supplied to an `htmlContext` callback. Additional keys
291/// from user-supplied `templateOptions` are merged into the same object at
292/// runtime, so the JS-side type widens this with an open-ended index signature.
293#[derive(Clone)]
294pub struct HtmlContext {
295    /// Name of the generated font, mirroring the `fontName` option.
296    pub font_name: String,
297    /// Glyph names in declaration order, after any `rename` callback has been
298    /// applied. Useful for iterating over icons in a preview template.
299    pub names: Vec<String>,
300    /// Pre-rendered CSS (the same string the engine writes to the `.css`
301    /// output) so HTML templates can embed it inline for self-contained
302    /// previews without an external stylesheet reference.
303    pub styles: String,
304    /// Map from glyph name to its assigned codepoint as a numeric value
305    /// (e.g. `"add" -> 0xF101`). Use the CSS context's hex form if you need a
306    /// string for embedding into CSS `content` declarations.
307    pub codepoints: HashMap<String, u32>,
308    /// Ordered resolved variants; absent in ordinary mode unless supplied by template options.
309    /// The mode-independent Node declaration is unknown because ordinary template data is arbitrary.
310    pub variants: Option<Vec<TemplateVariant>>,
311    /// Modifier class prefix, supplied in variant mode.
312    pub variant_class_prefix: Option<String>,
313    /// Resolved default weight, supplied in variant mode.
314    pub default_weight: Option<u32>,
315    /// Resolved font style, supplied in variant mode.
316    pub font_style: Option<String>,
317}
318
319/// Top-level options controlling webfont generation. `dest` and exactly one source, ordinary
320/// `files` or `variants`, are required. Every other field has a sensible default.
321/// With the `cli` feature, options deserialize from camelCase JSON with unknown fields rejected.
322#[derive(Clone, Default)]
323#[cfg_attr(
324    feature = "cli",
325    derive(serde::Deserialize),
326    serde(rename_all = "camelCase", deny_unknown_fields)
327)]
328pub struct GenerateWebfontsOptions {
329    /// Font ascent in font units. Overrides the value computed from the source
330    /// glyphs.
331    pub ascent: Option<f64>,
332    /// When `true`, centers each glyph horizontally inside the em-square based
333    /// on its bounding box.
334    pub center_horizontally: Option<bool>,
335    /// When `true`, centers each glyph vertically inside the em-square based
336    /// on its bounding box. Convenience alias for
337    /// `formatOptions.svg.centerVertically`.
338    pub center_vertically: Option<bool>,
339    /// Whether to generate a CSS file. Defaults to `true`.
340    pub css: Option<bool>,
341    /// Output path for the generated CSS file. Defaults to
342    /// `path.join(dest, fontName + '.css')`.
343    pub css_dest: Option<String>,
344    /// Path to a custom Handlebars template for CSS generation. The template
345    /// receives the `cssContext` shape plus any `templateOptions` keys.
346    pub css_template: Option<String>,
347    /// Explicit Unicode codepoints for specific glyphs, keyed by glyph name.
348    /// Glyphs not listed here are auto-assigned starting at `startCodepoint`.
349    pub codepoints: Option<HashMap<String, u32>>,
350    /// URL prefix for font files in the generated CSS. Defaults to the
351    /// relative path from `cssDest` to `dest`.
352    pub css_fonts_url: Option<String>,
353    /// Font descent in font units. Overrides the value computed from the
354    /// source glyphs.
355    pub descent: Option<f64>,
356    /// Output directory for generated font files. Required.
357    pub dest: String,
358    /// Paths to the SVG files to include in an ordinary font. Must be empty when `variants` is set.
359    #[cfg_attr(feature = "cli", serde(default))]
360    pub files: Vec<String>,
361    /// When `true`, produces a monospace font sized to the widest glyph.
362    pub fixed_width: Option<bool>,
363    /// Per-format option overrides. See `FormatOptions`.
364    pub format_options: Option<FormatOptions>,
365    /// Whether to generate an HTML preview file. Defaults to `false`.
366    pub html: Option<bool>,
367    /// Output path for the generated HTML preview file. Defaults to
368    /// `path.join(dest, fontName + '.html')`.
369    pub html_dest: Option<String>,
370    /// Path to a custom Handlebars template for HTML preview generation.
371    pub html_template: Option<String>,
372    /// Retain parsed glyph data on the result so `regenerate` can rebuild after file changes
373    /// without re-parsing unchanged glyphs. Defaults to `false`; enable for watch/dev. One-shot
374    /// builds (CLI, production) should leave it off to avoid holding the parsed geometry in memory.
375    /// Multi-variant results retain per-design parse/process caches. Pass
376    /// `RegenerationFiles::Variants` to the same regeneration methods for these results.
377    pub incremental: Option<bool>,
378    /// Explicit output font height in units per em. Overrides the height
379    /// computed from the source glyphs.
380    pub font_height: Option<f64>,
381    /// Name of the generated font family; also used as the base name for
382    /// output files. Defaults to `'iconfont'`.
383    pub font_name: Option<String>,
384    /// CSS `font-style` value for the generated `@font-face` rule.
385    pub font_style: Option<String>,
386    /// CSS `font-weight` value for the generated `@font-face` rule.
387    pub font_weight: Option<String>,
388    /// Enable ligature support so each glyph can be referenced by its name as
389    /// a text ligature. Defaults to `true`.
390    pub ligature: Option<bool>,
391    /// Family-wide missing-glyph policy for multi-variant generation. Defaults to `blank` and is
392    /// invalid without `variants`.
393    pub missing_glyphs: Option<MissingGlyphOptions>,
394    /// Scale icons to the height of the tallest icon. Defaults to `true`.
395    pub normalize: Option<bool>,
396    /// Order of `@font-face` `src:` entries in the generated CSS. Every entry
397    /// must also appear in `types`. Defaults to
398    /// `['eot', 'woff2', 'woff', 'ttf', 'svg']` filtered to the requested
399    /// `types`.
400    pub order: Option<Vec<FontType>>,
401    /// Run an SVG path optimizer over each glyph, trading a small amount of
402    /// build time for smaller output bytes. Convenience alias for
403    /// `formatOptions.svg.optimizeOutput`.
404    pub optimize_output: Option<bool>,
405    /// Preserve the source viewBox aspect ratio when scaling glyphs into the
406    /// em-square. Convenience alias for `formatOptions.svg.preserveAspectRatio`.
407    pub preserve_aspect_ratio: Option<bool>,
408    /// SVG path coordinate rounding precision.
409    pub round: Option<f64>,
410    /// Starting codepoint for auto-assigned glyphs. Defaults to `0xF101`.
411    pub start_codepoint: Option<u32>,
412    /// Additional key-value pairs merged into the Handlebars template
413    /// context for both CSS and HTML rendering. Typical home for
414    /// `classPrefix` and `baseSelector`.
415    pub template_options: Option<Map<String, Value>>,
416    /// Font formats to generate. Ordinary mode defaults to `['eot', 'woff', 'woff2']`;
417    /// variant mode defaults to `['woff', 'woff2']` and rejects SVG and EOT.
418    pub types: Option<Vec<FontType>>,
419    /// Prefix for generated variant modifier classes. Defaults to `icon--` in variant mode and is
420    /// invalid without `variants`.
421    pub variant_class_prefix: Option<String>,
422    /// Ordered named SVG designs for one logical icon family. Variant generation emits shared
423    /// variable TTF/WOFF/WOFF2 fonts. SVG and EOT output are unsupported in variant mode.
424    /// Default CSS emits exact-weight faces sharing those fonts, with modifier classes and no
425    /// synthetic weights. CSS/HTML companions are written when enabled; HTML uses one default grid.
426    /// Template contexts include ordered `variants`, `variantClassPrefix`, `defaultWeight`, and
427    /// `fontStyle`. The SCSS mixin uses each family's default weight and style.
428    pub variants: Option<Vec<FontVariant>>,
429    /// Whether to write generated files to disk. Set to `false` for
430    /// in-memory usage. Defaults to `true`.
431    pub write_files: Option<bool>,
432}