mod cache;
mod color;
mod glyphs;
mod ligatures;
mod outlines;
mod tables;
#[cfg(all(test, feature = "fs"))]
mod tests;
mod types;
mod variants;
use std::io::Error;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::input::ResolvedGenerationOptions;
use crate::pipeline::TtfGlyphCache;
use crate::svg::types::ProcessedGlyph;
pub(crate) use types::{CachedCompiledGlyph, TtfOptions};
pub(crate) use variants::build_variant;
use glyphs::{
build_glyf_table, compile_and_dedup_glyphs, compile_and_dedup_glyphs_cached,
compute_glyph_metrics,
};
use ligatures::build_ligature_placeholders;
use tables::assemble_font;
pub(crate) fn ttf_options_from_options(options: &ResolvedGenerationOptions) -> TtfOptions<'_> {
let ttf_format = options
.format_options
.as_ref()
.and_then(|value| value.ttf.as_ref());
TtfOptions {
color_slots: Some(&options.color_slots),
ascent: options.ascent,
copyright: ttf_format.and_then(|v| v.copyright.as_deref()),
descent: options.descent,
description: ttf_format.and_then(|v| v.description.as_deref()),
font_height: options.font_height,
font_name: &options.font_name,
font_style: options.font_style.as_deref(),
font_weight: options.font_weight.as_deref(),
ligature: options.ligature,
manufacturer_url: ttf_format.and_then(|v| v.url.as_deref()),
ts: ttf_format.and_then(|v| v.ts).or(options.fallback_ts),
version: ttf_format.and_then(|v| v.version.as_deref()),
}
}
pub(crate) fn build(
options: TtfOptions,
glyphs: &[ProcessedGlyph],
cache: Option<&mut TtfGlyphCache>,
) -> Result<super::SerializedFontTables, Error> {
match cache {
Some(cache) => build_cached(options, glyphs, cache),
None => build_uncached(options, glyphs),
}
}
fn build_uncached(
options: TtfOptions,
glyphs: &[ProcessedGlyph],
) -> Result<super::SerializedFontTables, Error> {
let font_height = options.font_height.unwrap_or_else(|| {
glyphs
.iter()
.fold(0.0_f64, |current, glyph| current.max(glyph.height))
.max(1.0)
});
let descent = options.descent.unwrap_or(0.0);
let ascent = options.ascent.unwrap_or(font_height - descent);
let (compiled_glyphs, cmap_aliases) = compile_and_dedup_glyphs(glyphs)?;
let ligature_placeholders = build_ligature_placeholders(&compiled_glyphs, options.ligature);
let color = color::build_color(
&compiled_glyphs,
ligature_placeholders.len(),
options.color_slots,
)?;
let (glyf, loca, loca_format) =
build_glyf_table(&compiled_glyphs, &ligature_placeholders, &color.layers)?;
let metrics = compute_glyph_metrics(compiled_glyphs.iter().chain(&color.layers));
assemble_font(
&options,
&compiled_glyphs,
&cmap_aliases,
&ligature_placeholders,
glyf,
loca,
loca_format,
&metrics,
ascent,
descent,
font_height,
color,
None,
)
}
fn build_cached(
options: TtfOptions,
glyphs: &[ProcessedGlyph],
cache: &mut TtfGlyphCache,
) -> Result<super::SerializedFontTables, Error> {
let font_height = options.font_height.unwrap_or_else(|| {
glyphs
.iter()
.fold(0.0_f64, |current, glyph| current.max(glyph.height))
.max(1.0)
});
let descent = options.descent.unwrap_or(0.0);
let ascent = options.ascent.unwrap_or(font_height - descent);
let (compiled_glyphs, cmap_aliases) = compile_and_dedup_glyphs_cached(glyphs, cache)?;
let ligature_placeholders = build_ligature_placeholders(&compiled_glyphs, options.ligature);
let color = color::build_color(
&compiled_glyphs,
ligature_placeholders.len(),
options.color_slots,
)?;
let (glyf, loca, loca_format) =
build_glyf_table(&compiled_glyphs, &ligature_placeholders, &color.layers)?;
let metrics = compute_glyph_metrics(compiled_glyphs.iter().chain(&color.layers));
assemble_font(
&options,
&compiled_glyphs,
&cmap_aliases,
&ligature_placeholders,
glyf,
loca,
loca_format,
&metrics,
ascent,
descent,
font_height,
color,
Some(cache),
)
}
pub(super) fn clamp_to_i16(value: f64) -> i16 {
value
.clamp(f64::from(i16::MIN), f64::from(i16::MAX))
.round() as i16
}
pub(super) fn clamp_to_u16(value: f64, min_value: u16, max_value: u16) -> u16 {
value
.clamp(f64::from(min_value), f64::from(max_value))
.round() as u16
}
pub(super) fn current_unix_timestamp() -> i64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_secs() as i64)
.unwrap_or(0)
}