use std::collections::HashMap;
use mlua::Table;
use retex_engine::fonts::{CharMetrics, FontInfo, FontKind, LigKernStep, LigOp};
pub fn font_from_table(t: &Table) -> mlua::Result<FontInfo> {
let mut info = FontInfo::null();
info.name = t
.get::<Option<mlua::String>>("name")?
.map(|s| s.as_bytes().to_vec())
.unwrap_or_default();
info.size = t.get::<Option<i32>>("size")?.unwrap_or(655360);
info.design_size = t.get::<Option<i32>>("designsize")?.unwrap_or(655360);
info.checksum = t.get::<Option<i64>>("checksum")?.unwrap_or(0) as u32;
let mut params = vec![0; 8];
if let (Some(st), Some(sh), Some(sp)) = (
t.get::<Option<i32>>("stretch")?,
t.get::<Option<i32>>("shrink")?,
t.get::<Option<i32>>("step")?,
) && (st > 0 || sh > 0)
&& sp > 0
{
info.expansion = Some(retex_engine::expansion::FontExpansion {
stretch: st,
shrink: sh,
step: sp,
});
}
if let Some(p) = t.get::<Option<Table>>("parameters")? {
let names = [
"slant",
"space",
"space_stretch",
"space_shrink",
"x_height",
"quad",
"extra_space",
];
for (i, n) in names.iter().enumerate() {
if let Some(v) = p.get::<Option<i32>>(*n)? {
params[i + 1] = v;
} else if let Some(v) = p.get::<Option<i32>>(i as i64 + 1)? {
params[i + 1] = v;
}
}
}
info.params = params;
let mut chars: HashMap<_, _, retex_engine::hash::FastHash> = HashMap::default();
if let Some(cs) = t.get::<Option<Table>>("characters")? {
for pair in cs.pairs::<i64, Table>() {
let (c, ct) = pair?;
chars.insert(
c as u32,
CharMetrics {
width: ct.get::<Option<i32>>("width")?.unwrap_or(0),
height: ct.get::<Option<i32>>("height")?.unwrap_or(0),
depth: ct.get::<Option<i32>>("depth")?.unwrap_or(0),
italic: ct.get::<Option<i32>>("italic")?.unwrap_or(0),
index: ct.get::<Option<u32>>("index")?.unwrap_or(c as u32),
},
);
let mut steps = Vec::new();
if let Some(l) = ct.get::<Option<Table>>("ligatures")? {
for pair in l.pairs::<i64, Table>() {
let (next, lt) = pair?;
let chr = lt.get::<Option<u32>>("char")?.unwrap_or(0);
let op = lt.get::<Option<u8>>("type")?.unwrap_or(0);
steps.push(LigKernStep {
next: next as u32,
op: LigOp::Lig { op, chr },
});
}
}
if let Some(k) = ct.get::<Option<Table>>("kerns")? {
for pair in k.pairs::<i64, i32>() {
let (next, amount) = pair?;
steps.push(LigKernStep {
next: next as u32,
op: LigOp::Kern(amount),
});
}
}
if !steps.is_empty() {
steps.sort_by_key(|st| st.next);
info.lig_kern.insert(c as u32, steps.into_boxed_slice());
}
}
}
info.chars = chars;
if let Some(mc) = t.get::<Option<Table>>("MathConstants")? {
let mut m = retex_engine::fonts::MathConstants::new();
for pair in mc.pairs::<String, f64>() {
let (k, v) = pair?;
m.insert(k, v.round() as i32);
}
info.math_constants = Some(std::rc::Rc::new(m));
}
info.hyphen_char = t.get::<Option<i32>>("hyphenchar")?.unwrap_or(i32::MIN);
info.skew_char = t.get::<Option<i32>>("skewchar")?.unwrap_or(i32::MIN);
info.kind = FontKind::OpenType;
Ok(info)
}