font_map_core/raw/ttf/glyf/
compound.rs

1#![allow(clippy::cast_possible_truncation)]
2#![allow(clippy::cast_possible_wrap)]
3
4use crate::error::ParseResult;
5use crate::reader::{BinaryReader, Parse};
6
7use super::{
8    simple::{Contour, Point},
9    GlyfOutline, SimpleGlyf,
10};
11
12const ARG_1_AND_2_ARE_WORDS: u16 = 0x0001;
13const ARGS_ARE_XY_VALUES: u16 = 0x0002;
14const WE_HAVE_A_SCALE: u16 = 0x0008;
15const MORE_COMPONENTS: u16 = 0x0020;
16const WE_HAVE_AN_X_AND_Y_SCALE: u16 = 0x0040;
17const WE_HAVE_A_TWO_BY_TWO: u16 = 0x0080;
18
19/// A compound glyph outline
20#[derive(Debug, Clone, Default)]
21pub struct CompoundGlyf {
22    /// The components of the compound glyph
23    pub components: Vec<Component>,
24}
25
26impl CompoundGlyf {
27    /// Converts the compound glyph to a simple glyph by resolving the components
28    #[must_use]
29    pub fn as_simple(&self, glyf_table: &[GlyfOutline]) -> SimpleGlyf {
30        let mut contours = Vec::new();
31        let (mut min_x, mut max_x) = (i16::MAX, i16::MIN);
32        let (mut min_y, mut max_y) = (i16::MAX, i16::MIN);
33
34        debug_msg!("Glyph has {} components", self.components.len());
35        for component in &self.components {
36            let glyph = &glyf_table[component.glyph_id as usize];
37            match glyph {
38                GlyfOutline::Simple(glyph) => {
39                    let glyph = component.apply_to_glyf(glyph, &contours);
40                    contours.extend_from_slice(&glyph.contours);
41
42                    min_x = min_x.min(glyph.x.0);
43                    max_x = max_x.max(glyph.x.1);
44                    min_y = min_y.min(glyph.y.0);
45                    max_y = max_y.max(glyph.y.1);
46                }
47
48                GlyfOutline::Compound(glyph) => {
49                    let glyph = glyph.as_simple(glyf_table);
50                    contours.extend_from_slice(&glyph.contours);
51
52                    min_x = min_x.min(glyph.x.0);
53                    max_x = max_x.max(glyph.x.1);
54                    min_y = min_y.min(glyph.y.0);
55                    max_y = max_y.max(glyph.y.1);
56                }
57            }
58        }
59
60        SimpleGlyf {
61            num_contours: contours.len() as i16,
62            contours,
63            x: (min_x, max_x),
64            y: (min_y, max_y),
65        }
66    }
67}
68
69impl Parse for CompoundGlyf {
70    fn parse(reader: &mut BinaryReader) -> ParseResult<Self> {
71        let mut flags;
72        let mut components = Vec::new();
73        loop {
74            flags = reader.read_u16()?;
75            let glyph_id = reader.read_u16()?;
76
77            //
78            // Get the arguments
79            let is_words = flags & ARG_1_AND_2_ARE_WORDS != 0;
80            let is_xy = flags & ARGS_ARE_XY_VALUES != 0;
81            let args = match (is_words, is_xy) {
82                (true, true) => {
83                    let arg1 = reader.read_i16()?;
84                    let arg2 = reader.read_i16()?;
85                    ComponentArguments::ShortCoordinates(arg1, arg2)
86                }
87
88                (true, false) => {
89                    let arg1 = reader.read_u16()?;
90                    let arg2 = reader.read_u16()?;
91                    ComponentArguments::ShortIndex(arg1, arg2)
92                }
93
94                (false, true) => {
95                    let arg1 = reader.read_i8()?;
96                    let arg2 = reader.read_i8()?;
97                    ComponentArguments::ByteCoordinates(arg1, arg2)
98                }
99
100                (false, false) => {
101                    let arg1 = reader.read_u8()?;
102                    let arg2 = reader.read_u8()?;
103                    ComponentArguments::ByteIndex(arg1, arg2)
104                }
105            };
106
107            //
108            // Get the scale
109            let scale = if flags & WE_HAVE_A_SCALE != 0 {
110                let scale = reader.read_f2dot14()?;
111                ComponentScale::Scale(scale)
112            } else if flags & WE_HAVE_AN_X_AND_Y_SCALE != 0 {
113                let x_scale = reader.read_f2dot14()?;
114                let y_scale = reader.read_f2dot14()?;
115                ComponentScale::XYScale(x_scale, y_scale)
116            } else if flags & WE_HAVE_A_TWO_BY_TWO != 0 {
117                let x_scale = reader.read_f2dot14()?;
118                let scale01 = reader.read_f2dot14()?;
119                let scale10 = reader.read_f2dot14()?;
120                let y_scale = reader.read_f2dot14()?;
121                ComponentScale::TwoByTwo(x_scale, scale01, scale10, y_scale)
122            } else {
123                ComponentScale::None
124            };
125
126            components.push(Component {
127                glyph_id,
128                flags,
129                args,
130                scale,
131            });
132
133            if flags & MORE_COMPONENTS == 0 {
134                break;
135            }
136        }
137
138        Ok(Self { components })
139    }
140}
141
142#[derive(Debug, Clone)]
143pub enum ComponentArguments {
144    ByteCoordinates(i8, i8),
145    ShortCoordinates(i16, i16),
146    ByteIndex(u8, u8),
147    ShortIndex(u16, u16),
148}
149
150#[derive(Debug, Clone)]
151pub enum ComponentScale {
152    None,
153    Scale(f64),
154    XYScale(f64, f64),
155    TwoByTwo(f64, f64, f64, f64),
156}
157
158#[derive(Debug, Clone)]
159pub struct Component {
160    pub glyph_id: u16,
161    pub flags: u16,
162    pub args: ComponentArguments,
163    pub scale: ComponentScale,
164}
165impl Component {
166    #[allow(clippy::many_single_char_names)]
167    pub fn apply_to_point(&self, point: &mut Point, parent: &Vec<Contour>, child: &Vec<Contour>) {
168        //
169        // Get the first set of parameters
170        let (a, b, c, d) = match self.scale {
171            ComponentScale::None => (1.0, 0.0, 0.0, 1.0),
172            ComponentScale::Scale(scale) => (scale, 0.0, 0.0, scale),
173            ComponentScale::XYScale(x_scale, y_scale) => (x_scale, 0.0, 0.0, y_scale),
174            ComponentScale::TwoByTwo(x_scale, scale01, scale10, y_scale) => {
175                (x_scale, scale01, scale10, y_scale)
176            }
177        };
178
179        //
180        // Get the 2nd set
181        let (e, f) = match self.args {
182            ComponentArguments::ShortCoordinates(e, f) => {
183                let e = f64::from(e);
184                let f = f64::from(f);
185                let e = a * e + b * f;
186                let f = c * e + d * f;
187                (e, f)
188            }
189            ComponentArguments::ByteCoordinates(e, f) => {
190                let e = f64::from(e);
191                let f = f64::from(f);
192                let e = a * e + b * f;
193                let f = c * e + d * f;
194                (e, f)
195            }
196
197            ComponentArguments::ShortIndex(compound_i, component_i) => {
198                let mut index = compound_i;
199                let mut point1 = Point::default();
200                for contour in parent {
201                    for point in &contour.points {
202                        if index == 0 {
203                            point1 = *point;
204                            break;
205                        }
206                        index -= 1;
207                    }
208                }
209
210                index = component_i;
211                let mut point2 = Point::default();
212                for contour in child {
213                    for point in &contour.points {
214                        if index == 0 {
215                            point2 = *point;
216                            break;
217                        }
218                        index -= 1;
219                    }
220                }
221
222                let e = f64::from(point1.x) - f64::from(point2.x);
223                let f = f64::from(point1.y) - f64::from(point2.y);
224                (e, f)
225            }
226
227            ComponentArguments::ByteIndex(compound_i, component_i) => {
228                let mut index = compound_i;
229                let mut point1 = Point::default();
230                for contour in parent {
231                    for point in &contour.points {
232                        if index == 0 {
233                            point1 = *point;
234                            break;
235                        }
236                        index -= 1;
237                    }
238                }
239
240                index = component_i;
241                let mut point2 = Point::default();
242                for contour in child {
243                    for point in &contour.points {
244                        if index == 0 {
245                            point2 = *point;
246                            break;
247                        }
248                        index -= 1;
249                    }
250                }
251
252                let e = f64::from(point1.x) - f64::from(point2.x);
253                let f = f64::from(point1.y) - f64::from(point2.y);
254                (e, f)
255            }
256        };
257
258        //
259        // Calculate the last set of parameters
260        let m0 = a.abs().max(b.abs());
261        let n0 = c.abs().max(d.abs());
262        let m = if (a.abs() - c.abs()) <= 33.0 / 65536.0 {
263            2.0 * m0
264        } else {
265            m0
266        };
267        let n = if (b.abs() - d.abs()) <= 33.0 / 65536.0 {
268            2.0 * n0
269        } else {
270            n0
271        };
272
273        //
274        // Perform linear transformation
275        let x = m * ((a / m) * f64::from(point.x) + (c / m) * f64::from(point.y) + e);
276        let y = n * ((b / n) * f64::from(point.x) + (d / n) * f64::from(point.y) + f);
277
278        point.x = x.round() as i16;
279        point.y = y.round() as i16;
280    }
281
282    pub fn apply_to_glyf(&self, glyf: &SimpleGlyf, parent: &Vec<Contour>) -> SimpleGlyf {
283        let mut new_glyf = glyf.clone();
284
285        for contour in &mut new_glyf.contours {
286            for point in &mut contour.points {
287                self.apply_to_point(point, parent, &glyf.contours);
288            }
289        }
290
291        //
292        // Apply to bounds too
293        let mut min_pt = Point {
294            x: glyf.x.0,
295            y: glyf.y.0,
296            on_curve: false,
297        };
298        let mut max_pt = Point {
299            x: glyf.x.1,
300            y: glyf.y.1,
301            on_curve: false,
302        };
303        self.apply_to_point(&mut min_pt, parent, &glyf.contours);
304        self.apply_to_point(&mut max_pt, parent, &glyf.contours);
305        new_glyf.x = (min_pt.x, max_pt.x);
306        new_glyf.y = (min_pt.y, max_pt.y);
307
308        new_glyf
309    }
310}