use std::collections::HashMap;
use crate::{ZplError, ZplResult};
use ab_glyph::FontArc;
const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../assets/Oswald-Regular.ttf");
const FONT_MAP: &[char] = &[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
];
#[derive(Debug, Clone)]
pub struct FontManager {
font_map: HashMap<String, String>,
font_index: HashMap<String, FontArc>,
font_bytes: HashMap<String, Vec<u8>>,
}
impl Default for FontManager {
fn default() -> Self {
let mut current = Self {
font_map: HashMap::new(),
font_index: HashMap::new(),
font_bytes: HashMap::new(),
};
let _ = current.register_font("Oswald", DEFAULT_FONT_BYTES, 'A', '9');
current
}
}
impl FontManager {
pub fn get_font_bytes(&self, name: &str) -> Option<&[u8]> {
let font_name = self.font_map.get(name)?;
self.font_bytes.get(font_name).map(|v| v.as_slice())
}
pub fn get_font_name(&self, name: &str) -> Option<&str> {
self.font_map.get(name).map(|s| s.as_str())
}
pub fn get_font(&self, name: &str) -> Option<&FontArc> {
let font_name = self.font_map.get(name);
if let Some(font_name) = font_name {
self.font_index.get(font_name)
} else {
None
}
}
pub fn register_font(
&mut self,
name: &str,
bytes: &[u8],
from: char,
to: char,
) -> ZplResult<()> {
let font = FontArc::try_from_vec(bytes.to_vec())
.map_err(|_| ZplError::FontError("Invalid font data".into()))?;
self.font_index.insert(name.to_string(), font);
self.font_bytes.insert(name.to_string(), bytes.to_vec());
self.assign_font(name, from, to);
Ok(())
}
fn assign_font(&mut self, name: &str, from: char, to: char) {
let from_idx = FONT_MAP.iter().position(|&x| x == from);
let to_idx = FONT_MAP.iter().position(|&x| x == to);
if from_idx.is_none() || to_idx.is_none() {
return;
}
if let (Some(start), Some(end)) = (from_idx, to_idx)
&& start <= end
{
for key in &FONT_MAP[start..=end] {
self.font_map.insert(key.to_string(), name.to_string());
}
}
}
}