1 //! TrueType outline types. 2 3 use std::mem::size_of; 4 5 use read_fonts::{ 6 tables::glyf::{to_path, Glyph, PointFlags, ToPathError}, 7 types::{F26Dot6, Fixed, GlyphId, Pen, Point}, 8 }; 9 10 use super::{super::Hinting, OutlineMemory}; 11 12 /// Represents the information necessary to scale a glyph outline. 13 /// 14 /// Contains a reference to the glyph data itself as well as metrics that 15 /// can be used to compute the memory requirements for scaling the glyph. 16 #[derive(Clone, Default)] 17 pub struct Outline<'a> { 18 pub glyph_id: GlyphId, 19 /// The associated top-level glyph for the outline. 20 pub glyph: Option<Glyph<'a>>, 21 /// Sum of the point counts of all simple glyphs in an outline. 22 pub points: usize, 23 /// Sum of the contour counts of all simple glyphs in an outline. 24 pub contours: usize, 25 /// Maximum number of points in a single simple glyph. 26 pub max_simple_points: usize, 27 /// "Other" points are the unscaled or original scaled points. 28 /// 29 /// The size of these buffer is the same and this value tracks the size 30 /// for one (not both) of the buffers. This is the maximum of 31 /// `max_simple_points` and the total number of points for all component 32 /// glyphs in a single composite glyph. 33 pub max_other_points: usize, 34 /// Maximum size of the component delta stack. 35 /// 36 /// For composite glyphs in variable fonts, delta values are computed 37 /// for each component. This tracks the maximum stack depth necessary 38 /// to store those values during processing. 39 pub max_component_delta_stack: usize, 40 /// True if any component of a glyph has bytecode instructions. 41 pub has_hinting: bool, 42 /// True if the glyph requires variation delta processing. 43 pub has_variations: bool, 44 /// True if the glyph contains any simple or compound overlap flags. 45 pub has_overlaps: bool, 46 } 47 48 impl<'a> Outline<'a> { 49 /// Returns the minimum size in bytes required to scale an outline based 50 /// on the computed sizes. required_buffer_size(&self, hinting: Hinting) -> usize51 pub fn required_buffer_size(&self, hinting: Hinting) -> usize { 52 let mut size = 0; 53 let hinting = self.has_hinting && hinting == Hinting::Embedded; 54 // Scaled, unscaled and (for hinting) original scaled points 55 size += self.points * size_of::<Point<F26Dot6>>(); 56 // Unscaled and (if hinted) original scaled points 57 size += self.max_other_points * size_of::<Point<i32>>() * if hinting { 2 } else { 1 }; 58 // Contour end points 59 size += self.contours * size_of::<u16>(); 60 // Point flags 61 size += self.points * size_of::<PointFlags>(); 62 if self.has_variations { 63 // Interpolation buffer for delta IUP 64 size += self.max_simple_points * size_of::<Point<Fixed>>(); 65 // Delta buffer for points 66 size += self.max_simple_points * size_of::<Point<Fixed>>(); 67 // Delta buffer for composite components 68 size += self.max_component_delta_stack * size_of::<Point<Fixed>>(); 69 } 70 if size != 0 { 71 // If we're given a buffer that is not aligned, we'll need to 72 // adjust, so add our maximum alignment requirement in bytes. 73 size += std::mem::align_of::<i32>(); 74 } 75 size 76 } 77 78 /// Allocates new memory for scaling this glyph from the given buffer. 79 /// 80 /// The size of the buffer must be at least as large as the size returned 81 /// by [`Self::required_buffer_size`]. memory_from_buffer( &self, buf: &'a mut [u8], hinting: Hinting, ) -> Option<OutlineMemory<'a>>82 pub fn memory_from_buffer( 83 &self, 84 buf: &'a mut [u8], 85 hinting: Hinting, 86 ) -> Option<OutlineMemory<'a>> { 87 OutlineMemory::new(self, buf, hinting) 88 } 89 } 90 91 #[derive(Debug)] 92 pub struct ScaledOutline<'a> { 93 pub points: &'a mut [Point<F26Dot6>], 94 pub flags: &'a mut [PointFlags], 95 pub contours: &'a mut [u16], 96 pub phantom_points: [Point<F26Dot6>; 4], 97 } 98 99 impl<'a> ScaledOutline<'a> { adjusted_lsb(&self) -> F26Dot6100 pub fn adjusted_lsb(&self) -> F26Dot6 { 101 self.phantom_points[0].x 102 } 103 adjusted_advance_width(&self) -> F26Dot6104 pub fn adjusted_advance_width(&self) -> F26Dot6 { 105 self.phantom_points[1].x - self.phantom_points[0].x 106 } 107 to_path(&self, pen: &mut impl Pen) -> Result<(), ToPathError>108 pub fn to_path(&self, pen: &mut impl Pen) -> Result<(), ToPathError> { 109 to_path(self.points, self.flags, self.contours, pen) 110 } 111 } 112