use crate::tables::glyf::{CompositeComponent, Glyph, ProtoGlyph, SimpleGlyph, ARGS_ARE_XY_VALUES, WE_HAVE_AN_X_AND_Y_SCALE, WE_HAVE_A_SCALE, WE_HAVE_A_TWO_BY_TWO};
use crate::font::TrueTypeFont;
use crate::Vec;
#[derive(Debug, Copy, Clone)]
pub(crate) struct Point {
pub(crate) x: f32,
pub(crate) y: f32,
pub(crate) on_curve: bool,
}
#[derive(Debug, Clone)]
pub(crate) struct Contour {
pub(crate) points: Vec<Point>,
}
impl Contour {
pub(crate) fn new(size: usize) -> Self {
Contour { points: Vec::with_capacity(size) }
}
}
impl TrueTypeFont {
pub(crate) fn load_points(&self, glyph: &mut ProtoGlyph, font: &TrueTypeFont, font_bytes: &[u8]) -> Glyph {
match glyph {
ProtoGlyph::Simple(g) => {
load_simple_glyph(g, None);
}
ProtoGlyph::Composite(g) => {
load_from_parent(&mut g.points, &g.components, font, font_bytes);
}
ProtoGlyph::Empty => {}
}
let glyph = glyph.finalize();
glyph
}
}
pub(crate) fn load_from_parent(master: &mut Vec<Contour>, comps: &Vec<CompositeComponent>, font: &TrueTypeFont, font_bytes: &[u8]) {
for component in comps.iter() {
let real_glyph = &mut font.get_glyph(font_bytes, component.glyph_index as u32);
match real_glyph {
ProtoGlyph::Simple(g) => {
load_simple_glyph(g, Some(component));
master.extend(g.points.iter().cloned());
}
ProtoGlyph::Composite(g) => {
load_from_parent(master, &g.components, font, font_bytes);
}
ProtoGlyph::Empty => {}
}
}
}
pub fn load_simple_glyph(g: &mut SimpleGlyph, component: Option<&CompositeComponent>) {
if !g.points.is_empty() {
return;
}
let end_pts = &g.end_pts_of_contours;
let num_points = end_pts.last().map(|&e| (e + 1) as usize).unwrap_or(0);
if g.flags.len() < num_points {
return;
}
g.points.reserve(end_pts.len());
let mut contour_start = 0;
for &end_pt in end_pts {
let end_pt = end_pt as usize;
let contour_size = end_pt - contour_start + 1;
let mut contour = Contour::new(contour_size);
for j in contour_start..=end_pt {
contour.points.push(Point {
x: g.x_coordinates[j] as f32,
y: g.y_coordinates[j] as f32,
on_curve: (g.flags[j] & 0x01) != 0,
});
}
if let Some(ref component) = component {
transform_points(&mut contour.points, component);
}
contour_start = end_pt + 1;
g.points.push(contour);
}
}
fn transform_points(points: &mut [Point], component: &CompositeComponent) {
let (x_scale, y_scale, scale_01, scale_10) = if component.flags & WE_HAVE_A_TWO_BY_TWO != 0 {
(
component.x_scale.unwrap_or(1.0),
component.y_scale.unwrap_or(1.0),
component.scale_01.unwrap_or(0.0),
component.scale_10.unwrap_or(0.0),
)
} else if component.flags & WE_HAVE_AN_X_AND_Y_SCALE != 0 {
(component.x_scale.unwrap_or(1.0), component.y_scale.unwrap_or(1.0), 0.0, 0.0)
} else if component.flags & WE_HAVE_A_SCALE != 0 {
let s = component.scale.unwrap_or(1.0);
(s, s, 0.0, 0.0)
} else {
(1.0, 1.0, 0.0, 0.0)
};
for p in points.iter_mut() {
let old_x = p.x;
let old_y = p.y;
let nx = old_x * x_scale + old_y * scale_10;
let ny = old_x * scale_01 + old_y * y_scale;
p.x = nx;
p.y = ny;
}
if component.flags & ARGS_ARE_XY_VALUES != 0 {
let dx = component.argument1 as f32;
let dy = component.argument2 as f32;
for p in points.iter_mut() {
p.x = p.x + dx;
p.y = p.y + dy;
}
}
}