use std::collections::{HashMap, HashSet};
use stet_core::object::EntityId;
use stet_graphics::device::TextParams;
const STANDARD_14: &[&[u8]] = &[
b"Times-Roman",
b"Times-Bold",
b"Times-Italic",
b"Times-BoldItalic",
b"Helvetica",
b"Helvetica-Bold",
b"Helvetica-Oblique",
b"Helvetica-BoldOblique",
b"Courier",
b"Courier-Bold",
b"Courier-Oblique",
b"Courier-BoldOblique",
b"Symbol",
b"ZapfDingbats",
];
#[allow(dead_code)]
pub struct FontUsage {
pub pdf_name: String,
pub font_name: Vec<u8>,
pub font_type: i32,
pub font_entity: EntityId,
pub all_entities: Vec<EntityId>,
pub used_codes: HashSet<u16>,
pub is_standard_14: bool,
pub sample_params: TextParams,
pub widths: HashMap<u16, i32>,
}
type FontKey = (Vec<u8>, i32);
pub struct FontTracker {
fonts: HashMap<FontKey, FontUsage>,
entity_to_name: HashMap<EntityId, String>,
next_idx: usize,
}
impl FontTracker {
pub fn new() -> Self {
Self {
fonts: HashMap::new(),
entity_to_name: HashMap::new(),
next_idx: 0,
}
}
pub fn track(&mut self, params: &TextParams) -> &str {
let key = (params.font_name.clone(), params.font_type);
let entity = EntityId(params.font_entity);
let usage = self.fonts.entry(key).or_insert_with(|| {
let idx = self.next_idx;
self.next_idx += 1;
let is_std14 = STANDARD_14.contains(¶ms.font_name.as_slice());
FontUsage {
pdf_name: format!("F{}", idx),
font_name: params.font_name.clone(),
font_type: params.font_type,
font_entity: entity,
all_entities: vec![entity],
used_codes: HashSet::new(),
is_standard_14: is_std14,
sample_params: params.clone(),
widths: HashMap::new(),
}
});
if !usage.all_entities.contains(&entity) {
usage.all_entities.push(entity);
}
if params.font_type == 0 {
for chunk in params.text.chunks(2) {
if chunk.len() == 2 {
let cid = ((chunk[0] as u16) << 8) | chunk[1] as u16;
usage.used_codes.insert(cid);
}
}
} else {
for &b in ¶ms.text {
usage.used_codes.insert(b as u16);
}
}
let name = usage.pdf_name.clone();
self.entity_to_name.insert(entity, name);
&usage.pdf_name
}
pub fn get_pdf_name(&self, entity: EntityId) -> Option<&str> {
self.entity_to_name.get(&entity).map(|s| s.as_str())
}
pub fn fonts(&self) -> impl Iterator<Item = &FontUsage> {
self.fonts.values()
}
pub fn fonts_mut(&mut self) -> impl Iterator<Item = &mut FontUsage> {
self.fonts.values_mut()
}
pub fn get_glyph_width(&self, font_entity: EntityId, code: u16) -> Option<i32> {
let pdf_name = self.entity_to_name.get(&font_entity)?;
self.fonts
.values()
.find(|u| u.pdf_name == *pdf_name)
.and_then(|u| u.widths.get(&code).copied())
}
}