use crate::context::Context;
use crate::context::InterpreterCache;
use crate::device::Device;
use crate::interpret::state::State;
use crate::util::hash128;
use crate::{CacheKey, InterpreterSettings, Paint};
use hayro_cmap::{BfString, WritingMode};
use hayro_syntax::page::Resources;
use hayro_syntax::xref::XRef;
use kurbo::{Affine, Rect};
use std::ops::Deref;
mod type3;
pub use hayro_font::{
FallbackFontQuery, FontData, FontQuery, FontStretch, GlyphId, GlyphIdentifier, HintingCache,
OutlineFontData, OutlineGlyph, StandardFont,
};
pub(crate) use hayro_font::{Font, FontCache, FontGlyph, UNITS_PER_EM};
pub enum Glyph<'a> {
Outline(OutlineGlyph),
Type3(Box<Type3Glyph<'a>>),
}
impl Glyph<'_> {
pub fn as_unicode(&self) -> Option<BfString> {
match self {
Glyph::Outline(g) => g.as_unicode(),
Glyph::Type3(g) => g.as_unicode(),
}
}
pub fn char_code(&self) -> u32 {
match self {
Glyph::Outline(g) => g.char_code(),
Glyph::Type3(g) => g.char_code(),
}
}
}
pub struct PositionedGlyph<'a> {
pub(crate) glyph: Glyph<'a>,
pub(crate) transform: Affine,
}
impl PositionedGlyph<'_> {
pub fn transform(&self) -> Affine {
self.transform
}
}
impl<'a> Deref for PositionedGlyph<'a> {
type Target = Glyph<'a>;
fn deref(&self) -> &Self::Target {
&self.glyph
}
}
pub struct GlyphRun<'run, 'a> {
pub(crate) glyphs: &'run [PositionedGlyph<'a>],
pub(crate) writing_mode: WritingMode,
}
impl<'run, 'a> GlyphRun<'run, 'a> {
pub fn glyphs(&self) -> &'run [PositionedGlyph<'a>] {
self.glyphs
}
pub fn writing_mode(&self) -> WritingMode {
self.writing_mode
}
}
#[derive(Clone)]
pub struct Type3Glyph<'a> {
pub(crate) glyph: hayro_font::Type3Glyph<'a>,
pub(crate) state: State<'a>,
pub(crate) bbox: Rect,
pub(crate) parent_resources: Resources<'a>,
pub(crate) cache: InterpreterCache<'a>,
pub(crate) xref: &'a XRef,
pub(crate) settings: InterpreterSettings,
pub(crate) nesting_depth: u32,
}
impl<'a> Type3Glyph<'a> {
pub fn interpret(
&self,
device: &mut impl Device<'a>,
transform: Affine,
glyph_transform: Affine,
paint: &Paint<'a>,
) {
type3::render_glyph(self, transform, glyph_transform, paint, device);
}
pub fn as_unicode(&self) -> Option<BfString> {
self.glyph.as_unicode()
}
pub fn char_code(&self) -> u32 {
self.glyph.char_code()
}
pub fn advance_width(&self) -> Option<f32> {
Some(self.glyph.advance_width())
}
}
impl CacheKey for Type3Glyph<'_> {
fn cache_key(&self) -> u128 {
hash128(&(self.glyph.cache_key(), self.bbox.cache_key()))
}
}
impl CacheKey for GlyphIdentifier {
fn cache_key(&self) -> u128 {
Self::cache_key(self)
}
}
pub(crate) fn get_glyph<'a>(
font: &Font<'a>,
glyph: GlyphId,
char_code: u32,
ctx: &mut Context<'a>,
resources: &Resources<'a>,
) -> Glyph<'a> {
match font.glyph(glyph, char_code) {
FontGlyph::Outline(outline) => Glyph::Outline(outline),
FontGlyph::Type3(glyph) => {
let nesting_depth = ctx.nesting_depth() + 1;
Glyph::Type3(Box::new(Type3Glyph {
glyph,
state: ctx.snapshot(),
bbox: ctx.bbox(),
parent_resources: resources.clone(),
cache: ctx.interpreter_cache.clone(),
xref: ctx.xref,
settings: ctx.settings.clone(),
nesting_depth,
}))
}
}
}