use crate::encoding::{
Encoding, SYMBOL_ENCODING, WIN_ANSI_ENCODING, ZAPFDINGBATS_ENCODING,
};
use crate::fontmetrics::{get_builtin_metrics, FontMetrics};
use crate::Pdf;
use std::cmp::Eq;
use std::hash::Hash;
use std::io::{self, Write};
#[allow(non_camel_case_types, missing_docs)]
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
pub enum BuiltinFont {
Courier,
Courier_Bold,
Courier_Oblique,
Courier_BoldOblique,
Helvetica,
Helvetica_Bold,
Helvetica_Oblique,
Helvetica_BoldOblique,
Times_Roman,
Times_Bold,
Times_Italic,
Times_BoldItalic,
Symbol,
ZapfDingbats,
}
pub trait FontSource: PartialEq + Eq + Hash {
fn write_object(&self, pdf: &mut Pdf) -> io::Result<usize>;
fn pdf_name(&self) -> String;
fn get_encoding(&self) -> &Encoding;
fn get_width(&self, size: f32, text: &str) -> f32;
fn get_width_raw(&self, text: &str) -> u32;
fn get_metrics(&self) -> FontMetrics;
}
impl FontSource for BuiltinFont {
fn write_object(&self, pdf: &mut Pdf) -> io::Result<usize> {
pdf.write_new_object(|font_object_id, pdf| {
writeln!(
pdf.output,
"<< /Type /Font /Subtype /Type1 /BaseFont /{} /Encoding /{} >>",
self.pdf_name(),
self.get_encoding().get_name()
)?;
Ok(font_object_id)
})
}
fn pdf_name(&self) -> String {
format!("{:?}", self).replace("_", "-")
}
fn get_encoding(&self) -> &'static Encoding {
match *self {
BuiltinFont::Symbol => &SYMBOL_ENCODING,
BuiltinFont::ZapfDingbats => &ZAPFDINGBATS_ENCODING,
_ => &WIN_ANSI_ENCODING,
}
}
fn get_width(&self, size: f32, text: &str) -> f32 {
size * self.get_width_raw(text) as f32 / 1000.0
}
fn get_width_raw(&self, text: &str) -> u32 {
let metrics = self.get_metrics();
self.get_encoding().encode_string(text).iter().fold(
0,
|result, &ch| {
result + u32::from(metrics.get_width(ch).unwrap_or(100))
},
)
}
fn get_metrics(&self) -> FontMetrics {
get_builtin_metrics(*self).clone()
}
}