//! A [Glyph Data Table]( //! https://docs.microsoft.com/en-us/typography/opentype/spec/glyf) implementation. use core::num::NonZeroU16; use crate::parser::{LazyArray16, NumFrom, Stream, F2DOT14}; use crate::{loca, BBox, GlyphId, OutlineBuilder, Rect, Transform}; pub(crate) struct Builder<'a> { pub builder: &'a mut dyn OutlineBuilder, pub transform: Transform, is_default_ts: bool, // `bool` is faster than `Option` or `is_default`. // We have to always calculate the bbox, because `gvar` doesn't store one // and in case of a malformed bbox in `glyf`. pub bbox: BBox, first_on_curve: Option, first_off_curve: Option, last_off_curve: Option, } impl<'a> Builder<'a> { #[inline] pub fn new(transform: Transform, bbox: BBox, builder: &'a mut dyn OutlineBuilder) -> Self { Builder { builder, transform, is_default_ts: transform.is_default(), bbox, first_on_curve: None, first_off_curve: None, last_off_curve: None, } } #[inline] fn move_to(&mut self, mut x: f32, mut y: f32) { if !self.is_default_ts { self.transform.apply_to(&mut x, &mut y); } self.bbox.extend_by(x, y); self.builder.move_to(x, y); } #[inline] fn line_to(&mut self, mut x: f32, mut y: f32) { if !self.is_default_ts { self.transform.apply_to(&mut x, &mut y); } self.bbox.extend_by(x, y); self.builder.line_to(x, y); } #[inline] fn quad_to(&mut self, mut x1: f32, mut y1: f32, mut x: f32, mut y: f32) { if !self.is_default_ts { self.transform.apply_to(&mut x1, &mut y1); self.transform.apply_to(&mut x, &mut y); } self.bbox.extend_by(x1, y1); self.bbox.extend_by(x, y); self.builder.quad_to(x1, y1, x, y); } // Useful links: // // - https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html // - https://stackoverflow.com/a/20772557 #[inline] pub fn push_point(&mut self, x: f32, y: f32, on_curve_point: bool, last_point: bool) { let p = Point { x, y }; if self.first_on_curve.is_none() { if on_curve_point { self.first_on_curve = Some(p); self.move_to(p.x, p.y); } else { if let Some(offcurve) = self.first_off_curve { let mid = offcurve.lerp(p, 0.5); self.first_on_curve = Some(mid); self.last_off_curve = Some(p); self.move_to(mid.x, mid.y); } else { self.first_off_curve = Some(p); } } } else { match (self.last_off_curve, on_curve_point) { (Some(offcurve), true) => { self.last_off_curve = None; self.quad_to(offcurve.x, offcurve.y, p.x, p.y); } (Some(offcurve), false) => { self.last_off_curve = Some(p); let mid = offcurve.lerp(p, 0.5); self.quad_to(offcurve.x, offcurve.y, mid.x, mid.y); } (None, true) => { self.line_to(p.x, p.y); } (None, false) => { self.last_off_curve = Some(p); } } } if last_point { self.finish_contour(); } } #[inline] fn finish_contour(&mut self) { if let (Some(offcurve1), Some(offcurve2)) = (self.first_off_curve, self.last_off_curve) { self.last_off_curve = None; let mid = offcurve2.lerp(offcurve1, 0.5); self.quad_to(offcurve2.x, offcurve2.y, mid.x, mid.y); } if let (Some(p), Some(offcurve1)) = (self.first_on_curve, self.first_off_curve) { self.quad_to(offcurve1.x, offcurve1.y, p.x, p.y); } else if let (Some(p), Some(offcurve2)) = (self.first_on_curve, self.last_off_curve) { self.quad_to(offcurve2.x, offcurve2.y, p.x, p.y); } else if let Some(p) = self.first_on_curve { self.line_to(p.x, p.y); } self.first_on_curve = None; self.first_off_curve = None; self.last_off_curve = None; self.builder.close(); } } #[derive(Clone, Copy, Debug)] pub(crate) struct CompositeGlyphInfo { pub glyph_id: GlyphId, pub transform: Transform, #[allow(dead_code)] pub flags: CompositeGlyphFlags, } #[derive(Clone)] pub(crate) struct CompositeGlyphIter<'a> { stream: Stream<'a>, } impl<'a> CompositeGlyphIter<'a> { #[inline] pub fn new(data: &'a [u8]) -> Self { CompositeGlyphIter { stream: Stream::new(data), } } } impl<'a> Iterator for CompositeGlyphIter<'a> { type Item = CompositeGlyphInfo; #[inline] fn next(&mut self) -> Option { let flags = CompositeGlyphFlags(self.stream.read::()?); let glyph_id = self.stream.read::()?; let mut ts = Transform::default(); if flags.args_are_xy_values() { if flags.arg_1_and_2_are_words() { ts.e = f32::from(self.stream.read::()?); ts.f = f32::from(self.stream.read::()?); } else { ts.e = f32::from(self.stream.read::()?); ts.f = f32::from(self.stream.read::()?); } } if flags.we_have_a_two_by_two() { ts.a = self.stream.read::()?.to_f32(); ts.b = self.stream.read::()?.to_f32(); ts.c = self.stream.read::()?.to_f32(); ts.d = self.stream.read::()?.to_f32(); } else if flags.we_have_an_x_and_y_scale() { ts.a = self.stream.read::()?.to_f32(); ts.d = self.stream.read::()?.to_f32(); } else if flags.we_have_a_scale() { ts.a = self.stream.read::()?.to_f32(); ts.d = ts.a; } if !flags.more_components() { // Finish the iterator even if stream still has some data. self.stream.jump_to_end(); } Some(CompositeGlyphInfo { glyph_id, transform: ts, flags, }) } } // Due to some optimization magic, using f32 instead of i16 // makes the code ~10% slower. At least on my machine. // I guess it's due to the fact that with i16 the struct // fits into the machine word. #[derive(Clone, Copy, Debug)] pub(crate) struct GlyphPoint { pub x: i16, pub y: i16, /// Indicates that a point is a point on curve /// and not a control point. pub on_curve_point: bool, pub last_point: bool, } #[derive(Clone, Default)] pub(crate) struct GlyphPointsIter<'a> { endpoints: EndpointsIter<'a>, flags: FlagsIter<'a>, x_coords: CoordsIter<'a>, y_coords: CoordsIter<'a>, pub points_left: u16, // Number of points left in the glyph. } #[cfg(feature = "variable-fonts")] impl GlyphPointsIter<'_> { #[inline] pub fn current_contour(&self) -> u16 { self.endpoints.index - 1 } } impl<'a> Iterator for GlyphPointsIter<'a> { type Item = GlyphPoint; #[inline] fn next(&mut self) -> Option { self.points_left = self.points_left.checked_sub(1)?; // TODO: skip empty contours let last_point = self.endpoints.next(); let flags = self.flags.next()?; Some(GlyphPoint { x: self .x_coords .next(flags.x_short(), flags.x_is_same_or_positive_short()), y: self .y_coords .next(flags.y_short(), flags.y_is_same_or_positive_short()), on_curve_point: flags.on_curve_point(), last_point, }) } } /// A simple flattening iterator for glyph's endpoints. /// /// Translates endpoints like: 2 4 7 /// into flags: 0 0 1 0 1 0 0 1 #[derive(Clone, Copy, Default)] struct EndpointsIter<'a> { endpoints: LazyArray16<'a, u16>, // Each endpoint indicates a contour end. index: u16, left: u16, } impl<'a> EndpointsIter<'a> { #[inline] fn new(endpoints: LazyArray16<'a, u16>) -> Option { Some(EndpointsIter { endpoints, index: 1, left: endpoints.get(0)?, }) } #[inline] fn next(&mut self) -> bool { if self.left == 0 { if let Some(end) = self.endpoints.get(self.index) { let prev = self.endpoints.get(self.index - 1).unwrap_or(0); // Malformed font can have endpoints not in increasing order, // so we have to use checked_sub. self.left = end.saturating_sub(prev); self.left = self.left.saturating_sub(1); } // Always advance the index, so we can check the current contour number. if let Some(n) = self.index.checked_add(1) { self.index = n; } true } else { self.left -= 1; false } } } #[derive(Clone, Default)] struct FlagsIter<'a> { stream: Stream<'a>, // Number of times the `flags` should be used // before reading the next one from `stream`. repeats: u8, flags: SimpleGlyphFlags, } impl<'a> FlagsIter<'a> { #[inline] fn new(data: &'a [u8]) -> Self { FlagsIter { stream: Stream::new(data), repeats: 0, flags: SimpleGlyphFlags(0), } } } impl<'a> Iterator for FlagsIter<'a> { type Item = SimpleGlyphFlags; #[inline] fn next(&mut self) -> Option { if self.repeats == 0 { self.flags = SimpleGlyphFlags(self.stream.read::().unwrap_or(0)); if self.flags.repeat_flag() { self.repeats = self.stream.read::().unwrap_or(0); } } else { self.repeats -= 1; } Some(self.flags) } } #[derive(Clone, Default)] struct CoordsIter<'a> { stream: Stream<'a>, prev: i16, // Points are stored as deltas, so we have to keep the previous one. } impl<'a> CoordsIter<'a> { #[inline] fn new(data: &'a [u8]) -> Self { CoordsIter { stream: Stream::new(data), prev: 0, } } #[inline] fn next(&mut self, is_short: bool, is_same_or_short: bool) -> i16 { // See https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description // for details about Simple Glyph Flags processing. // We've already checked the coords data, so it's safe to fallback to 0. let mut n = 0; if is_short { n = i16::from(self.stream.read::().unwrap_or(0)); if !is_same_or_short { n = -n; } } else if !is_same_or_short { n = self.stream.read::().unwrap_or(0); } self.prev = self.prev.wrapping_add(n); self.prev } } #[derive(Clone, Copy, Debug)] struct Point { x: f32, y: f32, } impl Point { #[inline] fn lerp(self, other: Point, t: f32) -> Point { Point { x: self.x + t * (other.x - self.x), y: self.y + t * (other.y - self.y), } } } // https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description #[derive(Clone, Copy, Default)] struct SimpleGlyphFlags(u8); #[rustfmt::skip] impl SimpleGlyphFlags { #[inline] fn on_curve_point(self) -> bool { self.0 & 0x01 != 0 } #[inline] fn x_short(self) -> bool { self.0 & 0x02 != 0 } #[inline] fn y_short(self) -> bool { self.0 & 0x04 != 0 } #[inline] fn repeat_flag(self) -> bool { self.0 & 0x08 != 0 } #[inline] fn x_is_same_or_positive_short(self) -> bool { self.0 & 0x10 != 0 } #[inline] fn y_is_same_or_positive_short(self) -> bool { self.0 & 0x20 != 0 } } // https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description #[derive(Clone, Copy, Debug)] pub(crate) struct CompositeGlyphFlags(u16); #[rustfmt::skip] impl CompositeGlyphFlags { #[inline] pub fn arg_1_and_2_are_words(self) -> bool { self.0 & 0x0001 != 0 } #[inline] pub fn args_are_xy_values(self) -> bool { self.0 & 0x0002 != 0 } #[inline] pub fn we_have_a_scale(self) -> bool { self.0 & 0x0008 != 0 } #[inline] pub fn more_components(self) -> bool { self.0 & 0x0020 != 0 } #[inline] pub fn we_have_an_x_and_y_scale(self) -> bool { self.0 & 0x0040 != 0 } #[inline] pub fn we_have_a_two_by_two(self) -> bool { self.0 & 0x0080 != 0 } } // It's not defined in the spec, so we are using our own value. pub(crate) const MAX_COMPONENTS: u8 = 32; #[allow(clippy::comparison_chain)] #[inline] fn outline_impl( loca_table: loca::Table, glyf_table: &[u8], data: &[u8], depth: u8, builder: &mut Builder, ) -> Option> { if depth >= MAX_COMPONENTS { return None; } let mut s = Stream::new(data); let number_of_contours = s.read::()?; s.advance(8); // Skip bbox. We use calculated one. if number_of_contours > 0 { // Simple glyph. // u16 casting is safe, since we already checked that the value is positive. let number_of_contours = NonZeroU16::new(number_of_contours as u16)?; for point in parse_simple_outline(s.tail()?, number_of_contours)? { builder.push_point( f32::from(point.x), f32::from(point.y), point.on_curve_point, point.last_point, ); } } else if number_of_contours < 0 { // Composite glyph. for comp in CompositeGlyphIter::new(s.tail()?) { if let Some(range) = loca_table.glyph_range(comp.glyph_id) { if let Some(glyph_data) = glyf_table.get(range) { let transform = Transform::combine(builder.transform, comp.transform); let mut b = Builder::new(transform, builder.bbox, builder.builder); outline_impl(loca_table, glyf_table, glyph_data, depth + 1, &mut b)?; // Take updated bbox. builder.bbox = b.bbox; } } } } if builder.bbox.is_default() { return Some(None); } Some(builder.bbox.to_rect()) } #[inline] pub(crate) fn parse_simple_outline( glyph_data: &[u8], number_of_contours: NonZeroU16, ) -> Option { let mut s = Stream::new(glyph_data); let endpoints = s.read_array16::(number_of_contours.get())?; let points_total = endpoints.last()?.checked_add(1)?; // Contours with a single point should be ignored. // But this is not an error, so we should return an "empty" iterator. if points_total == 1 { return Some(GlyphPointsIter::default()); } // Skip instructions byte code. let instructions_len = s.read::()?; s.advance(usize::from(instructions_len)); let flags_offset = s.offset(); let (x_coords_len, y_coords_len) = resolve_coords_len(&mut s, points_total)?; let x_coords_offset = s.offset(); let y_coords_offset = x_coords_offset + usize::num_from(x_coords_len); let y_coords_end = y_coords_offset + usize::num_from(y_coords_len); Some(GlyphPointsIter { endpoints: EndpointsIter::new(endpoints)?, flags: FlagsIter::new(glyph_data.get(flags_offset..x_coords_offset)?), x_coords: CoordsIter::new(glyph_data.get(x_coords_offset..y_coords_offset)?), y_coords: CoordsIter::new(glyph_data.get(y_coords_offset..y_coords_end)?), points_left: points_total, }) } /// Resolves coordinate arrays length. /// /// The length depends on *Simple Glyph Flags*, so we have to process them all to find it. fn resolve_coords_len(s: &mut Stream, points_total: u16) -> Option<(u32, u32)> { let mut flags_left = u32::from(points_total); let mut repeats; let mut x_coords_len = 0; let mut y_coords_len = 0; while flags_left > 0 { let flags = SimpleGlyphFlags(s.read::()?); // The number of times a glyph point repeats. repeats = if flags.repeat_flag() { let repeats = s.read::()?; u32::from(repeats) + 1 } else { 1 }; if repeats > flags_left { return None; } // No need to check for `*_coords_len` overflow since u32 is more than enough. // Non-obfuscated code below. // Branchless version is surprisingly faster. // // if flags.x_short() { // // Coordinate is 1 byte long. // x_coords_len += repeats; // } else if !flags.x_is_same_or_positive_short() { // // Coordinate is 2 bytes long. // x_coords_len += repeats * 2; // } // if flags.y_short() { // // Coordinate is 1 byte long. // y_coords_len += repeats; // } else if !flags.y_is_same_or_positive_short() { // // Coordinate is 2 bytes long. // y_coords_len += repeats * 2; // } x_coords_len += (flags.0 & 0x02 != 0) as u32 * repeats; x_coords_len += (flags.0 & (0x02 | 0x10) == 0) as u32 * (repeats * 2); y_coords_len += (flags.0 & 0x04 != 0) as u32 * repeats; y_coords_len += (flags.0 & (0x04 | 0x20) == 0) as u32 * (repeats * 2); flags_left -= repeats; } Some((x_coords_len, y_coords_len)) } /// A [Glyph Data Table]( /// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf). #[derive(Clone, Copy)] pub struct Table<'a> { pub(crate) data: &'a [u8], loca_table: loca::Table<'a>, } impl core::fmt::Debug for Table<'_> { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "Table {{ ... }}") } } impl<'a> Table<'a> { /// Parses a table from raw data. #[inline] pub fn parse(loca_table: loca::Table<'a>, data: &'a [u8]) -> Option { Some(Table { loca_table, data }) } /// Outlines a glyph. #[inline] pub fn outline(&self, glyph_id: GlyphId, builder: &mut dyn OutlineBuilder) -> Option { let mut b = Builder::new(Transform::default(), BBox::new(), builder); let glyph_data = self.get(glyph_id)?; outline_impl(self.loca_table, self.data, glyph_data, 0, &mut b)? } #[inline] pub(crate) fn get(&self, glyph_id: GlyphId) -> Option<&'a [u8]> { let range = self.loca_table.glyph_range(glyph_id)?; self.data.get(range) } }