pub trait TextMeasurer {
fn measure_width(&self, text: &str, font_size: f64) -> f64;
fn measure_height(&self, font_size: f64) -> f64;
}
#[derive(Clone, Debug, Default)]
pub struct HeuristicTextMeasurer;
impl HeuristicTextMeasurer {
const AVG_WIDTH: f64 = 0.6;
const NARROW_WIDTH: f64 = 0.35;
const WIDE_WIDTH: f64 = 0.75;
fn char_width_factor(c: char) -> f64 {
match c {
'i' | 'I' | 'l' | '1' | '|' | '!' | '.' | ':' | ';' | ',' | '\'' | ' ' => {
Self::NARROW_WIDTH
}
'm' | 'M' | 'w' | 'W' | '@' => Self::WIDE_WIDTH,
_ => Self::AVG_WIDTH,
}
}
}
impl TextMeasurer for HeuristicTextMeasurer {
fn measure_width(&self, text: &str, font_size: f64) -> f64 {
text.chars()
.map(|c| Self::char_width_factor(c) * font_size)
.sum()
}
fn measure_height(&self, font_size: f64) -> f64 {
font_size * 1.2
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_heuristic_measurer() {
let m = HeuristicTextMeasurer;
let w = m.measure_width("Hello", 12.0);
assert!(w > 0.0);
let narrow = m.measure_width("iii", 12.0);
let wide = m.measure_width("MMM", 12.0);
assert!(narrow < wide);
}
}