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