use crate::text::{CustomFont, Font, FontManager};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum ExtendedFont {
Standard(Font),
Custom(Arc<CustomFont>),
}
impl ExtendedFont {
pub fn from_standard(font: Font) -> Self {
ExtendedFont::Standard(font)
}
pub fn from_custom(font: CustomFont) -> Self {
ExtendedFont::Custom(Arc::new(font))
}
pub fn pdf_name(&self) -> String {
match self {
ExtendedFont::Standard(font) => font.pdf_name().to_string(),
ExtendedFont::Custom(font) => font.name.clone(),
}
}
pub fn is_symbolic(&self) -> bool {
match self {
ExtendedFont::Standard(font) => font.is_symbolic(),
ExtendedFont::Custom(font) => font.descriptor.flags.symbolic,
}
}
pub fn get_width(&self, char_code: u8) -> f64 {
match self {
ExtendedFont::Standard(_) => {
600.0 }
ExtendedFont::Custom(font) => font.metrics.get_width(char_code),
}
}
pub fn measure_text(&self, text: &str, font_size: f64) -> f64 {
let mut width = 0.0;
for ch in text.bytes() {
width += self.get_width(ch);
}
width * font_size / 1000.0
}
}
#[derive(Debug, Clone)]
pub struct ExtendedFontManager {
custom_fonts: FontManager,
registered_fonts: Vec<(String, ExtendedFont)>,
}
impl Default for ExtendedFontManager {
fn default() -> Self {
Self::new()
}
}
impl ExtendedFontManager {
pub fn new() -> Self {
let mut manager = Self {
custom_fonts: FontManager::new(),
registered_fonts: Vec::new(),
};
manager.register_standard_fonts();
manager
}
fn register_standard_fonts(&mut self) {
use Font::*;
let standard_fonts = vec![
Helvetica,
HelveticaBold,
HelveticaOblique,
HelveticaBoldOblique,
TimesRoman,
TimesBold,
TimesItalic,
TimesBoldItalic,
Courier,
CourierBold,
CourierOblique,
CourierBoldOblique,
Symbol,
ZapfDingbats,
];
for font in standard_fonts {
let name = font.pdf_name().to_string();
self.registered_fonts
.push((name, ExtendedFont::Standard(font)));
}
}
pub fn register_custom_font(
&mut self,
font: CustomFont,
) -> Result<String, crate::error::PdfError> {
let font_name = self.custom_fonts.register_font(font.clone())?;
self.registered_fonts
.push((font_name.clone(), ExtendedFont::Custom(Arc::new(font))));
Ok(font_name)
}
pub fn get_font(&self, name: &str) -> Option<&ExtendedFont> {
self.registered_fonts
.iter()
.find(|(n, _)| n == name)
.map(|(_, font)| font)
}
pub fn fonts(&self) -> &[(String, ExtendedFont)] {
&self.registered_fonts
}
pub fn custom_fonts(&self) -> &FontManager {
&self.custom_fonts
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::text::{FontDescriptor, FontEncoding, FontFlags, FontMetrics};
#[test]
fn test_extended_font_standard() {
let font = ExtendedFont::from_standard(Font::Helvetica);
assert_eq!(font.pdf_name(), "Helvetica");
assert!(!font.is_symbolic());
}
#[test]
fn test_extended_font_custom() {
let flags = FontFlags {
symbolic: true,
..Default::default()
};
let descriptor = FontDescriptor::new(
"CustomFont".to_string(),
flags,
[0.0, 0.0, 1000.0, 1000.0],
0.0,
750.0,
-250.0,
750.0,
100.0,
);
let metrics = FontMetrics::new(32, 126, vec![500.0; 95], 500.0);
let custom = CustomFont::new_type1(
"CustomFont".to_string(),
FontEncoding::StandardEncoding,
descriptor,
metrics,
);
let font = ExtendedFont::from_custom(custom);
assert_eq!(font.pdf_name(), "CustomFont");
assert!(font.is_symbolic());
}
#[test]
fn test_font_measurement() {
let font = ExtendedFont::from_standard(Font::Helvetica);
let width = font.measure_text("Hello", 12.0);
assert!(width > 0.0);
}
#[test]
fn test_extended_font_manager() {
let manager = ExtendedFontManager::new();
assert!(manager.get_font("Helvetica").is_some());
assert!(manager.get_font("Times-Roman").is_some());
assert!(manager.get_font("Courier").is_some());
let helvetica = manager.get_font("Helvetica").unwrap();
assert!(matches!(helvetica, ExtendedFont::Standard(_)));
}
#[test]
fn test_register_custom_font() {
let mut manager = ExtendedFontManager::new();
let flags = FontFlags::default();
let descriptor = FontDescriptor::new(
"MyCustomFont".to_string(),
flags,
[0.0, 0.0, 1000.0, 1000.0],
0.0,
750.0,
-250.0,
750.0,
100.0,
);
let metrics = FontMetrics::new(32, 126, vec![500.0; 95], 500.0);
let custom = CustomFont::new_truetype(
"MyCustomFont".to_string(),
FontEncoding::WinAnsiEncoding,
descriptor,
metrics,
);
let font_name = manager.register_custom_font(custom).unwrap();
assert!(font_name.starts_with('F'));
let registered = manager.get_font(&font_name).unwrap();
assert!(matches!(registered, ExtendedFont::Custom(_)));
}
}