font_map_core/raw/ttf/glyf/
compound.rs1#![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#[derive(Debug, Clone, Default)]
21pub struct CompoundGlyf {
22 pub components: Vec<Component>,
24}
25
26impl CompoundGlyf {
27 #[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 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 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 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 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 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 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 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}