1 //! The [glyf (Glyph Data)](https://docs.microsoft.com/en-us/typography/opentype/spec/glyf) table
2
3 pub mod bytecode;
4
5 use std::fmt;
6 use types::{F26Dot6, Pen, Point};
7
8 include!("../../generated/generated_glyf.rs");
9
10 /// Marker bits for point flags that are set during variation delta
11 /// processing and hinting.
12 #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
13 pub struct PointMarker(u8);
14
15 impl PointMarker {
16 /// Marker for points that have an explicit delta in a glyph variation
17 /// tuple.
18 pub const HAS_DELTA: Self = Self(0x4);
19
20 /// Marker that signifies that the x coordinate of a point has been touched
21 /// by an IUP hinting instruction.
22 pub const TOUCHED_X: Self = Self(0x10);
23
24 /// Marker that signifies that the y coordinate of a point has been touched
25 /// by an IUP hinting instruction.
26 pub const TOUCHED_Y: Self = Self(0x20);
27
28 /// Marker that signifies that the both coordinates of a point has been touched
29 /// by an IUP hinting instruction.
30 pub const TOUCHED: Self = Self(Self::TOUCHED_X.0 | Self::TOUCHED_Y.0);
31 }
32
33 /// Flags describing the properties of a point.
34 ///
35 /// Some properties, such as on- and off-curve flags are intrinsic to the point
36 /// itself. Others, designated as markers are set and cleared while an outline
37 /// is being transformed during variation application and hinting.
38 #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
39 #[repr(transparent)]
40 pub struct PointFlags(u8);
41
42 impl PointFlags {
43 // Note: OFF_CURVE_QUAD is signified by the absence of both ON_CURVE
44 // and OFF_CURVE_CUBIC bits, per FreeType and TrueType convention.
45 const ON_CURVE: u8 = 0x1;
46 const OFF_CURVE_CUBIC: u8 = 0x8;
47 const CURVE_MASK: u8 = Self::ON_CURVE | Self::OFF_CURVE_CUBIC;
48
49 /// Creates a new on curve point flag.
on_curve() -> Self50 pub fn on_curve() -> Self {
51 Self(Self::ON_CURVE)
52 }
53
54 /// Creates a new off curve quadratic point flag.
off_curve_quad() -> Self55 pub fn off_curve_quad() -> Self {
56 Self(0)
57 }
58
59 /// Creates a new off curve cubic point flag.
off_curve_cubic() -> Self60 pub fn off_curve_cubic() -> Self {
61 Self(Self::OFF_CURVE_CUBIC)
62 }
63
64 /// Creates a point flag from the given bits. These are truncated
65 /// to ignore markers.
from_bits(bits: u8) -> Self66 pub fn from_bits(bits: u8) -> Self {
67 Self(bits & Self::CURVE_MASK)
68 }
69
70 /// Returns true if this is an on curve point.
is_on_curve(self) -> bool71 pub fn is_on_curve(self) -> bool {
72 self.0 & Self::ON_CURVE != 0
73 }
74
75 /// Returns true if this is an off curve quadratic point.
is_off_curve_quad(self) -> bool76 pub fn is_off_curve_quad(self) -> bool {
77 self.0 & Self::CURVE_MASK == 0
78 }
79
80 /// Returns true if this is an off curve cubic point.
is_off_curve_cubic(self) -> bool81 pub fn is_off_curve_cubic(self) -> bool {
82 self.0 & Self::OFF_CURVE_CUBIC != 0
83 }
84
85 /// Flips the state of the on curve flag.
86 ///
87 /// This is used for the TrueType `FLIPPT` instruction.
flip_on_curve(&mut self)88 pub fn flip_on_curve(&mut self) {
89 self.0 ^= 1;
90 }
91
92 /// Enables the on curve flag.
93 ///
94 /// This is used for the TrueType `FLIPRGON` instruction.
set_on_curve(&mut self)95 pub fn set_on_curve(&mut self) {
96 self.0 |= Self::ON_CURVE;
97 }
98
99 /// Disables the on curve flag.
100 ///
101 /// This is used for the TrueType `FLIPRGOFF` instruction.
clear_on_curve(&mut self)102 pub fn clear_on_curve(&mut self) {
103 self.0 &= !Self::ON_CURVE;
104 }
105
106 /// Returns true if the given marker is set for this point.
has_marker(self, marker: PointMarker) -> bool107 pub fn has_marker(self, marker: PointMarker) -> bool {
108 self.0 & marker.0 != 0
109 }
110
111 /// Applies the given marker to this point.
set_marker(&mut self, marker: PointMarker)112 pub fn set_marker(&mut self, marker: PointMarker) {
113 self.0 |= marker.0;
114 }
115
116 /// Clears the given marker for this point.
clear_marker(&mut self, marker: PointMarker)117 pub fn clear_marker(&mut self, marker: PointMarker) {
118 self.0 &= !marker.0
119 }
120 }
121
122 impl<'a> SimpleGlyph<'a> {
123 /// Returns the total number of points.
num_points(&self) -> usize124 pub fn num_points(&self) -> usize {
125 self.end_pts_of_contours()
126 .last()
127 .map(|last| last.get() as usize + 1)
128 .unwrap_or(0)
129 }
130
131 /// Returns true if the contours in the simple glyph may overlap.
has_overlapping_contours(&self) -> bool132 pub fn has_overlapping_contours(&self) -> bool {
133 // Checks the first flag for the OVERLAP_SIMPLE bit.
134 // Spec says: "When used, it must be set on the first flag byte for
135 // the glyph."
136 FontData::new(self.glyph_data())
137 .read_at::<SimpleGlyphFlags>(0)
138 .map(|flag| flag.contains(SimpleGlyphFlags::OVERLAP_SIMPLE))
139 .unwrap_or_default()
140 }
141
142 /// Reads points and flags into the provided buffers.
143 ///
144 /// Drops all flag bits except on-curve. The lengths of the buffers must be
145 /// equal to the value returned by [num_points](Self::num_points).
146 ///
147 /// ## Performance
148 ///
149 /// As the name implies, this is faster than using the iterator returned by
150 /// [points](Self::points) so should be used when it is possible to
151 /// preallocate buffers.
read_points_fast( &self, points: &mut [Point<i32>], flags: &mut [PointFlags], ) -> Result<(), ReadError>152 pub fn read_points_fast(
153 &self,
154 points: &mut [Point<i32>],
155 flags: &mut [PointFlags],
156 ) -> Result<(), ReadError> {
157 let n_points = self.num_points();
158 if points.len() != n_points || flags.len() != n_points {
159 return Err(ReadError::InvalidArrayLen);
160 }
161 let mut cursor = FontData::new(self.glyph_data()).cursor();
162 let mut i = 0;
163 while i < n_points {
164 let flag = cursor.read::<SimpleGlyphFlags>()?;
165 let flag_bits = flag.bits();
166 if flag.contains(SimpleGlyphFlags::REPEAT_FLAG) {
167 let count = (cursor.read::<u8>()? as usize + 1).min(n_points - i);
168 for f in &mut flags[i..i + count] {
169 f.0 = flag_bits;
170 }
171 i += count;
172 } else {
173 flags[i].0 = flag_bits;
174 i += 1;
175 }
176 }
177 let mut x = 0i32;
178 for (&point_flags, point) in flags.iter().zip(points.as_mut()) {
179 let mut delta = 0i32;
180 let flag = SimpleGlyphFlags::from_bits_truncate(point_flags.0);
181 if flag.contains(SimpleGlyphFlags::X_SHORT_VECTOR) {
182 delta = cursor.read::<u8>()? as i32;
183 if !flag.contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
184 delta = -delta;
185 }
186 } else if !flag.contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
187 delta = cursor.read::<i16>()? as i32;
188 }
189 x = x.wrapping_add(delta);
190 point.x = x;
191 }
192 let mut y = 0i32;
193 for (point_flags, point) in flags.iter_mut().zip(points.as_mut()) {
194 let mut delta = 0i32;
195 let flag = SimpleGlyphFlags::from_bits_truncate(point_flags.0);
196 if flag.contains(SimpleGlyphFlags::Y_SHORT_VECTOR) {
197 delta = cursor.read::<u8>()? as i32;
198 if !flag.contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
199 delta = -delta;
200 }
201 } else if !flag.contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
202 delta = cursor.read::<i16>()? as i32;
203 }
204 y = y.wrapping_add(delta);
205 point.y = y;
206 // Only keep the on-curve bit
207 point_flags.0 &= 1;
208 }
209 Ok(())
210 }
211
212 /// Returns an iterator over the points in the glyph.
213 ///
214 /// ## Performance
215 ///
216 /// This is slower than [read_points_fast](Self::read_points_fast) but
217 /// provides access to the points without requiring a preallocated buffer.
points(&self) -> impl Iterator<Item = CurvePoint> + 'a + Clone218 pub fn points(&self) -> impl Iterator<Item = CurvePoint> + 'a + Clone {
219 self.points_impl()
220 .unwrap_or_else(|| PointIter::new(&[], &[], &[]))
221 }
222
points_impl(&self) -> Option<PointIter<'a>>223 fn points_impl(&self) -> Option<PointIter<'a>> {
224 let end_points = self.end_pts_of_contours();
225 let n_points = end_points.last()?.get().checked_add(1)?;
226 let data = self.glyph_data();
227 let lens = resolve_coords_len(data, n_points).ok()?;
228 let total_len = lens.flags + lens.x_coords + lens.y_coords;
229 if data.len() < total_len as usize {
230 return None;
231 }
232
233 let (flags, data) = data.split_at(lens.flags as usize);
234 let (x_coords, y_coords) = data.split_at(lens.x_coords as usize);
235
236 Some(PointIter::new(flags, x_coords, y_coords))
237 }
238 }
239
240 /// Point with an associated on-curve flag in a simple glyph.
241 ///
242 /// This type is a simpler representation of the data in the blob.
243 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
244 pub struct CurvePoint {
245 /// X cooordinate.
246 pub x: i16,
247 /// Y cooordinate.
248 pub y: i16,
249 /// True if this is an on-curve point.
250 pub on_curve: bool,
251 }
252
253 impl CurvePoint {
254 /// Construct a new `CurvePoint`
new(x: i16, y: i16, on_curve: bool) -> Self255 pub fn new(x: i16, y: i16, on_curve: bool) -> Self {
256 Self { x, y, on_curve }
257 }
258
259 /// Convenience method to construct an on-curve point
on_curve(x: i16, y: i16) -> Self260 pub fn on_curve(x: i16, y: i16) -> Self {
261 Self::new(x, y, true)
262 }
263
264 /// Convenience method to construct an off-curve point
off_curve(x: i16, y: i16) -> Self265 pub fn off_curve(x: i16, y: i16) -> Self {
266 Self::new(x, y, false)
267 }
268 }
269
270 #[derive(Clone)]
271 struct PointIter<'a> {
272 flags: Cursor<'a>,
273 x_coords: Cursor<'a>,
274 y_coords: Cursor<'a>,
275 flag_repeats: u8,
276 cur_flags: SimpleGlyphFlags,
277 cur_x: i16,
278 cur_y: i16,
279 }
280
281 impl<'a> Iterator for PointIter<'a> {
282 type Item = CurvePoint;
next(&mut self) -> Option<Self::Item>283 fn next(&mut self) -> Option<Self::Item> {
284 self.advance_flags()?;
285 self.advance_points();
286 let is_on_curve = self.cur_flags.contains(SimpleGlyphFlags::ON_CURVE_POINT);
287 Some(CurvePoint::new(self.cur_x, self.cur_y, is_on_curve))
288 }
289 }
290
291 impl<'a> PointIter<'a> {
new(flags: &'a [u8], x_coords: &'a [u8], y_coords: &'a [u8]) -> Self292 fn new(flags: &'a [u8], x_coords: &'a [u8], y_coords: &'a [u8]) -> Self {
293 Self {
294 flags: FontData::new(flags).cursor(),
295 x_coords: FontData::new(x_coords).cursor(),
296 y_coords: FontData::new(y_coords).cursor(),
297 flag_repeats: 0,
298 cur_flags: SimpleGlyphFlags::empty(),
299 cur_x: 0,
300 cur_y: 0,
301 }
302 }
303
advance_flags(&mut self) -> Option<()>304 fn advance_flags(&mut self) -> Option<()> {
305 if self.flag_repeats == 0 {
306 self.cur_flags = SimpleGlyphFlags::from_bits_truncate(self.flags.read().ok()?);
307 self.flag_repeats = self
308 .cur_flags
309 .contains(SimpleGlyphFlags::REPEAT_FLAG)
310 .then(|| self.flags.read().ok())
311 .flatten()
312 .unwrap_or(0)
313 + 1;
314 }
315 self.flag_repeats -= 1;
316 Some(())
317 }
318
advance_points(&mut self)319 fn advance_points(&mut self) {
320 let x_short = self.cur_flags.contains(SimpleGlyphFlags::X_SHORT_VECTOR);
321 let x_same_or_pos = self
322 .cur_flags
323 .contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR);
324 let y_short = self.cur_flags.contains(SimpleGlyphFlags::Y_SHORT_VECTOR);
325 let y_same_or_pos = self
326 .cur_flags
327 .contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR);
328
329 let delta_x = match (x_short, x_same_or_pos) {
330 (true, false) => -(self.x_coords.read::<u8>().unwrap_or(0) as i16),
331 (true, true) => self.x_coords.read::<u8>().unwrap_or(0) as i16,
332 (false, false) => self.x_coords.read::<i16>().unwrap_or(0),
333 _ => 0,
334 };
335
336 let delta_y = match (y_short, y_same_or_pos) {
337 (true, false) => -(self.y_coords.read::<u8>().unwrap_or(0) as i16),
338 (true, true) => self.y_coords.read::<u8>().unwrap_or(0) as i16,
339 (false, false) => self.y_coords.read::<i16>().unwrap_or(0),
340 _ => 0,
341 };
342
343 self.cur_x = self.cur_x.wrapping_add(delta_x);
344 self.cur_y = self.cur_y.wrapping_add(delta_y);
345 }
346 }
347
348 //taken from ttf_parser https://docs.rs/ttf-parser/latest/src/ttf_parser/tables/glyf.rs.html#1-677
349 /// Resolves coordinate arrays length.
350 ///
351 /// The length depends on *Simple Glyph Flags*, so we have to process them all to find it.
resolve_coords_len(data: &[u8], points_total: u16) -> Result<FieldLengths, ReadError>352 fn resolve_coords_len(data: &[u8], points_total: u16) -> Result<FieldLengths, ReadError> {
353 let mut cursor = FontData::new(data).cursor();
354 let mut flags_left = u32::from(points_total);
355 //let mut repeats;
356 let mut x_coords_len = 0;
357 let mut y_coords_len = 0;
358 //let mut flags_seen = 0;
359 while flags_left > 0 {
360 let flags: SimpleGlyphFlags = cursor.read()?;
361
362 // The number of times a glyph point repeats.
363 let repeats = if flags.contains(SimpleGlyphFlags::REPEAT_FLAG) {
364 let repeats: u8 = cursor.read()?;
365 u32::from(repeats) + 1
366 } else {
367 1
368 };
369
370 if repeats > flags_left {
371 return Err(ReadError::MalformedData("repeat count too large in glyf"));
372 }
373
374 // Non-obfuscated code below.
375 // Branchless version is surprisingly faster.
376 //
377 // if flags.x_short() {
378 // // Coordinate is 1 byte long.
379 // x_coords_len += repeats;
380 // } else if !flags.x_is_same_or_positive_short() {
381 // // Coordinate is 2 bytes long.
382 // x_coords_len += repeats * 2;
383 // }
384 // if flags.y_short() {
385 // // Coordinate is 1 byte long.
386 // y_coords_len += repeats;
387 // } else if !flags.y_is_same_or_positive_short() {
388 // // Coordinate is 2 bytes long.
389 // y_coords_len += repeats * 2;
390 // }
391 let x_short = SimpleGlyphFlags::X_SHORT_VECTOR;
392 let x_long = SimpleGlyphFlags::X_SHORT_VECTOR
393 | SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR;
394 let y_short = SimpleGlyphFlags::Y_SHORT_VECTOR;
395 let y_long = SimpleGlyphFlags::Y_SHORT_VECTOR
396 | SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR;
397 x_coords_len += ((flags & x_short).bits() != 0) as u32 * repeats;
398 x_coords_len += ((flags & x_long).bits() == 0) as u32 * repeats * 2;
399
400 y_coords_len += ((flags & y_short).bits() != 0) as u32 * repeats;
401 y_coords_len += ((flags & y_long).bits() == 0) as u32 * repeats * 2;
402
403 flags_left -= repeats;
404 }
405
406 Ok(FieldLengths {
407 flags: cursor.position()? as u32,
408 x_coords: x_coords_len,
409 y_coords: y_coords_len,
410 })
411 //Some((flags_len, x_coords_len, y_coords_len))
412 }
413
414 struct FieldLengths {
415 flags: u32,
416 x_coords: u32,
417 y_coords: u32,
418 }
419
420 /// Transform for a composite component.
421 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
422 pub struct Transform {
423 /// X scale factor.
424 pub xx: F2Dot14,
425 /// YX skew factor.
426 pub yx: F2Dot14,
427 /// XY skew factor.
428 pub xy: F2Dot14,
429 /// Y scale factor.
430 pub yy: F2Dot14,
431 }
432
433 impl Default for Transform {
default() -> Self434 fn default() -> Self {
435 Self {
436 xx: F2Dot14::from_f32(1.0),
437 yx: F2Dot14::from_f32(0.0),
438 xy: F2Dot14::from_f32(0.0),
439 yy: F2Dot14::from_f32(1.0),
440 }
441 }
442 }
443
444 /// A reference to another glyph. Part of [CompositeGlyph].
445 #[derive(Clone, Debug, PartialEq, Eq)]
446 pub struct Component {
447 /// Component flags.
448 pub flags: CompositeGlyphFlags,
449 /// Glyph identifier.
450 pub glyph: GlyphId,
451 /// Anchor for component placement.
452 pub anchor: Anchor,
453 /// Component transformation matrix.
454 pub transform: Transform,
455 }
456
457 /// Anchor position for a composite component.
458 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
459 pub enum Anchor {
460 Offset { x: i16, y: i16 },
461 Point { base: u16, component: u16 },
462 }
463
464 impl<'a> CompositeGlyph<'a> {
465 /// Returns an iterator over the components of the composite glyph.
components(&self) -> impl Iterator<Item = Component> + 'a + Clone466 pub fn components(&self) -> impl Iterator<Item = Component> + 'a + Clone {
467 ComponentIter {
468 cur_flags: CompositeGlyphFlags::empty(),
469 done: false,
470 cursor: FontData::new(self.component_data()).cursor(),
471 }
472 }
473
474 /// Returns an iterator that yields the glyph identifier and flags of each
475 /// component in the composite glyph.
component_glyphs_and_flags( &self, ) -> impl Iterator<Item = (GlyphId, CompositeGlyphFlags)> + 'a + Clone476 pub fn component_glyphs_and_flags(
477 &self,
478 ) -> impl Iterator<Item = (GlyphId, CompositeGlyphFlags)> + 'a + Clone {
479 ComponentGlyphIdFlagsIter {
480 cur_flags: CompositeGlyphFlags::empty(),
481 done: false,
482 cursor: FontData::new(self.component_data()).cursor(),
483 }
484 }
485
486 /// Returns the component count and TrueType interpreter instructions
487 /// in a single pass.
count_and_instructions(&self) -> (usize, Option<&'a [u8]>)488 pub fn count_and_instructions(&self) -> (usize, Option<&'a [u8]>) {
489 let mut iter = ComponentGlyphIdFlagsIter {
490 cur_flags: CompositeGlyphFlags::empty(),
491 done: false,
492 cursor: FontData::new(self.component_data()).cursor(),
493 };
494 let mut count = 0;
495 while iter.by_ref().next().is_some() {
496 count += 1;
497 }
498 let instructions = if iter
499 .cur_flags
500 .contains(CompositeGlyphFlags::WE_HAVE_INSTRUCTIONS)
501 {
502 iter.cursor
503 .read::<u16>()
504 .ok()
505 .map(|len| len as usize)
506 .and_then(|len| iter.cursor.read_array(len).ok())
507 } else {
508 None
509 };
510 (count, instructions)
511 }
512
513 /// Returns the TrueType interpreter instructions.
instructions(&self) -> Option<&'a [u8]>514 pub fn instructions(&self) -> Option<&'a [u8]> {
515 self.count_and_instructions().1
516 }
517 }
518
519 #[derive(Clone)]
520 struct ComponentIter<'a> {
521 cur_flags: CompositeGlyphFlags,
522 done: bool,
523 cursor: Cursor<'a>,
524 }
525
526 impl Iterator for ComponentIter<'_> {
527 type Item = Component;
528
next(&mut self) -> Option<Self::Item>529 fn next(&mut self) -> Option<Self::Item> {
530 if self.done {
531 return None;
532 }
533 let flags: CompositeGlyphFlags = self.cursor.read().ok()?;
534 self.cur_flags = flags;
535 let glyph = self.cursor.read::<GlyphId>().ok()?;
536 let args_are_words = flags.contains(CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS);
537 let args_are_xy_values = flags.contains(CompositeGlyphFlags::ARGS_ARE_XY_VALUES);
538 let anchor = match (args_are_xy_values, args_are_words) {
539 (true, true) => Anchor::Offset {
540 x: self.cursor.read().ok()?,
541 y: self.cursor.read().ok()?,
542 },
543 (true, false) => Anchor::Offset {
544 x: self.cursor.read::<i8>().ok()? as _,
545 y: self.cursor.read::<i8>().ok()? as _,
546 },
547 (false, true) => Anchor::Point {
548 base: self.cursor.read().ok()?,
549 component: self.cursor.read().ok()?,
550 },
551 (false, false) => Anchor::Point {
552 base: self.cursor.read::<u8>().ok()? as _,
553 component: self.cursor.read::<u8>().ok()? as _,
554 },
555 };
556 let mut transform = Transform::default();
557 if flags.contains(CompositeGlyphFlags::WE_HAVE_A_SCALE) {
558 transform.xx = self.cursor.read().ok()?;
559 transform.yy = transform.xx;
560 } else if flags.contains(CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE) {
561 transform.xx = self.cursor.read().ok()?;
562 transform.yy = self.cursor.read().ok()?;
563 } else if flags.contains(CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO) {
564 transform.xx = self.cursor.read().ok()?;
565 transform.yx = self.cursor.read().ok()?;
566 transform.xy = self.cursor.read().ok()?;
567 transform.yy = self.cursor.read().ok()?;
568 }
569 self.done = !flags.contains(CompositeGlyphFlags::MORE_COMPONENTS);
570
571 Some(Component {
572 flags,
573 glyph,
574 anchor,
575 transform,
576 })
577 }
578 }
579
580 /// Iterator that only returns glyph identifiers and flags for each component.
581 ///
582 /// Significantly faster in cases where we're just processing the glyph
583 /// tree, counting components or accessing instructions.
584 #[derive(Clone)]
585 struct ComponentGlyphIdFlagsIter<'a> {
586 cur_flags: CompositeGlyphFlags,
587 done: bool,
588 cursor: Cursor<'a>,
589 }
590
591 impl Iterator for ComponentGlyphIdFlagsIter<'_> {
592 type Item = (GlyphId, CompositeGlyphFlags);
593
next(&mut self) -> Option<Self::Item>594 fn next(&mut self) -> Option<Self::Item> {
595 if self.done {
596 return None;
597 }
598 let flags: CompositeGlyphFlags = self.cursor.read().ok()?;
599 self.cur_flags = flags;
600 let glyph = self.cursor.read::<GlyphId>().ok()?;
601 let args_are_words = flags.contains(CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS);
602 if args_are_words {
603 self.cursor.advance_by(4);
604 } else {
605 self.cursor.advance_by(2);
606 }
607 if flags.contains(CompositeGlyphFlags::WE_HAVE_A_SCALE) {
608 self.cursor.advance_by(2);
609 } else if flags.contains(CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE) {
610 self.cursor.advance_by(4);
611 } else if flags.contains(CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO) {
612 self.cursor.advance_by(8);
613 }
614 self.done = !flags.contains(CompositeGlyphFlags::MORE_COMPONENTS);
615 Some((glyph, flags))
616 }
617 }
618
619 #[cfg(feature = "traversal")]
620 impl<'a> SomeTable<'a> for Component {
type_name(&self) -> &str621 fn type_name(&self) -> &str {
622 "Component"
623 }
624
get_field(&self, idx: usize) -> Option<Field<'a>>625 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
626 match idx {
627 0 => Some(Field::new("flags", self.flags.bits())),
628 1 => Some(Field::new("glyph", self.glyph)),
629 2 => match self.anchor {
630 Anchor::Point { base, .. } => Some(Field::new("base", base)),
631 Anchor::Offset { x, .. } => Some(Field::new("x", x)),
632 },
633 3 => match self.anchor {
634 Anchor::Point { component, .. } => Some(Field::new("component", component)),
635 Anchor::Offset { y, .. } => Some(Field::new("y", y)),
636 },
637 _ => None,
638 }
639 }
640 }
641
642 /// Errors that can occur when converting an outline to a path.
643 #[derive(Clone, Debug)]
644 pub enum ToPathError {
645 /// Contour end point at this index was less than its preceding end point.
646 ContourOrder(usize),
647 /// Expected a quadratic off-curve point at this index.
648 ExpectedQuad(usize),
649 /// Expected a quadratic off-curve or on-curve point at this index.
650 ExpectedQuadOrOnCurve(usize),
651 /// Expected a cubic off-curve point at this index.
652 ExpectedCubic(usize),
653 }
654
655 impl fmt::Display for ToPathError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result656 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657 match self {
658 Self::ContourOrder(ix) => write!(
659 f,
660 "Contour end point at index {ix} was less than preceeding end point"
661 ),
662 Self::ExpectedQuad(ix) => write!(f, "Expected quadatic off-curve point at index {ix}"),
663 Self::ExpectedQuadOrOnCurve(ix) => write!(
664 f,
665 "Expected quadatic off-curve or on-curve point at index {ix}"
666 ),
667 Self::ExpectedCubic(ix) => write!(f, "Expected cubic off-curve point at index {ix}"),
668 }
669 }
670 }
671
672 /// Converts a `glyf` outline described by points, flags and contour end points to a sequence of
673 /// path elements and invokes the appropriate callback on the given sink for each.
674 ///
675 /// The input points are expected in `F26Dot6` format as that is the standard result of scaling
676 /// a TrueType glyph. Output points are generated in `f32`.
677 ///
678 /// This is roughly equivalent to [`FT_Outline_Decompose`](https://freetype.org/freetype2/docs/reference/ft2-outline_processing.html#ft_outline_decompose).
to_path( points: &[Point<F26Dot6>], flags: &[PointFlags], contours: &[u16], sink: &mut impl Pen, ) -> Result<(), ToPathError>679 pub fn to_path(
680 points: &[Point<F26Dot6>],
681 flags: &[PointFlags],
682 contours: &[u16],
683 sink: &mut impl Pen,
684 ) -> Result<(), ToPathError> {
685 // FreeType uses integer division to compute midpoints.
686 // See: https://github.com/freetype/freetype/blob/de8b92dd7ec634e9e2b25ef534c54a3537555c11/src/base/ftoutln.c#L123
687 fn midpoint(a: Point<F26Dot6>, b: Point<F26Dot6>) -> Point<F26Dot6> {
688 ((a + b).map(F26Dot6::to_bits) / 2).map(F26Dot6::from_bits)
689 }
690 let mut count = 0usize;
691 let mut last_was_close = false;
692 for contour_ix in 0..contours.len() {
693 let mut cur_ix = if contour_ix > 0 {
694 contours[contour_ix - 1] as usize + 1
695 } else {
696 0
697 };
698 let mut last_ix = contours[contour_ix] as usize;
699 if last_ix < cur_ix || last_ix >= points.len() {
700 return Err(ToPathError::ContourOrder(contour_ix));
701 }
702 let mut v_start = points[cur_ix];
703 let v_last = points[last_ix];
704 let mut flag = flags[cur_ix];
705 if flag.is_off_curve_cubic() {
706 return Err(ToPathError::ExpectedQuadOrOnCurve(cur_ix));
707 }
708 let mut step_point = true;
709 if flag.is_off_curve_quad() {
710 if flags[last_ix].is_on_curve() {
711 v_start = v_last;
712 last_ix -= 1;
713 } else {
714 v_start = midpoint(v_start, v_last);
715 }
716 step_point = false;
717 }
718 let p = v_start.map(F26Dot6::to_f32);
719 if count > 0 && !last_was_close {
720 sink.close();
721 }
722 sink.move_to(p.x, p.y);
723 count += 1;
724 last_was_close = false;
725 while cur_ix < last_ix || cur_ix == last_ix && !step_point {
726 if step_point {
727 cur_ix += 1;
728 }
729 step_point = true;
730 flag = flags[cur_ix];
731 if flag.is_on_curve() {
732 let p = points[cur_ix].map(F26Dot6::to_f32);
733 sink.line_to(p.x, p.y);
734 count += 1;
735 last_was_close = false;
736 continue;
737 } else if flag.is_off_curve_quad() {
738 let mut do_close_quad = true;
739 let mut v_control = points[cur_ix];
740 while cur_ix < last_ix {
741 cur_ix += 1;
742 let cur_point = points[cur_ix];
743 flag = flags[cur_ix];
744 if flag.is_on_curve() {
745 let control = v_control.map(F26Dot6::to_f32);
746 let point = cur_point.map(F26Dot6::to_f32);
747 sink.quad_to(control.x, control.y, point.x, point.y);
748 count += 1;
749 last_was_close = false;
750 do_close_quad = false;
751 break;
752 }
753 if !flag.is_off_curve_quad() {
754 return Err(ToPathError::ExpectedQuad(cur_ix));
755 }
756 let v_middle = midpoint(v_control, cur_point);
757 let control = v_control.map(F26Dot6::to_f32);
758 let point = v_middle.map(F26Dot6::to_f32);
759 sink.quad_to(control.x, control.y, point.x, point.y);
760 count += 1;
761 last_was_close = false;
762 v_control = cur_point;
763 }
764 if do_close_quad {
765 let control = v_control.map(F26Dot6::to_f32);
766 let point = v_start.map(F26Dot6::to_f32);
767 sink.quad_to(control.x, control.y, point.x, point.y);
768 count += 1;
769 last_was_close = false;
770 break;
771 }
772 continue;
773 } else {
774 if cur_ix + 1 > last_ix || !flags[cur_ix + 1].is_off_curve_cubic() {
775 return Err(ToPathError::ExpectedCubic(cur_ix + 1));
776 }
777 let control0 = points[cur_ix].map(F26Dot6::to_f32);
778 let control1 = points[cur_ix + 1].map(F26Dot6::to_f32);
779 cur_ix += 2;
780 if cur_ix <= last_ix {
781 let point = points[cur_ix].map(F26Dot6::to_f32);
782 sink.curve_to(
783 control0.x, control0.y, control1.x, control1.y, point.x, point.y,
784 );
785 count += 1;
786 last_was_close = false;
787 continue;
788 }
789 let point = v_start.map(F26Dot6::to_f32);
790 sink.curve_to(
791 control0.x, control0.y, control1.x, control1.y, point.x, point.y,
792 );
793 count += 1;
794 last_was_close = false;
795 break;
796 }
797 }
798 if count > 0 && !last_was_close {
799 sink.close();
800 last_was_close = true;
801 }
802 }
803 Ok(())
804 }
805
806 impl Anchor {
807 /// Compute the flags that describe this anchor
compute_flags(&self) -> CompositeGlyphFlags808 pub fn compute_flags(&self) -> CompositeGlyphFlags {
809 const I8_RANGE: Range<i16> = i8::MIN as i16..i8::MAX as i16 + 1;
810 const U8_MAX: u16 = u8::MAX as u16;
811
812 let mut flags = CompositeGlyphFlags::empty();
813 match self {
814 Anchor::Offset { x, y } => {
815 flags |= CompositeGlyphFlags::ARGS_ARE_XY_VALUES;
816 if !I8_RANGE.contains(x) || !I8_RANGE.contains(y) {
817 flags |= CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS;
818 }
819 }
820 Anchor::Point { base, component } => {
821 if base > &U8_MAX || component > &U8_MAX {
822 flags |= CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS;
823 }
824 }
825 }
826 flags
827 }
828 }
829
830 impl Transform {
831 /// Compute the flags that describe this transform
compute_flags(&self) -> CompositeGlyphFlags832 pub fn compute_flags(&self) -> CompositeGlyphFlags {
833 if self.yx != F2Dot14::ZERO || self.xy != F2Dot14::ZERO {
834 CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO
835 } else if self.xx != self.yy {
836 CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
837 } else if self.xx != F2Dot14::ONE {
838 CompositeGlyphFlags::WE_HAVE_A_SCALE
839 } else {
840 CompositeGlyphFlags::empty()
841 }
842 }
843 }
844
845 //NOTE: we want generated_glyf traversal to include this:
846 //7usize => {
847 //let this = self.sneaky_copy();
848 //Some(Field::new(
849 //"components",
850 //FieldType::offset_iter(move || {
851 //Box::new(
852 //this.iter_components()
853 //.map(|item| FieldType::ResolvedOffset(Ok(Box::new(item)))),
854 //) as Box<dyn Iterator<Item = FieldType<'a>> + 'a>
855 //}),
856 //))
857 //}
858
859 #[cfg(test)]
860 mod tests {
861 use super::*;
862
863 use crate::{FontRef, GlyphId, TableProvider};
864
865 #[test]
all_off_curve_to_path()866 fn all_off_curve_to_path() {
867 fn pt(x: i32, y: i32) -> Point<F26Dot6> {
868 Point::new(x, y).map(F26Dot6::from_bits)
869 }
870 let flags = [PointFlags::off_curve_quad(); 4];
871 let contours = [3];
872 // This test is meant to prevent a bug where the first move-to was computed improperly
873 // for a contour consisting of all off curve points.
874 // In this case, the start of the path should be the midpoint between the first and last points.
875 // For this test case (in 26.6 fixed point): [(640, 128) + (128, 128)] / 2 = (384, 128)
876 // which becomes (6.0, 2.0) when converted to floating point.
877 let points = [pt(640, 128), pt(256, 64), pt(640, 64), pt(128, 128)];
878 let expected =
879 "M6.0,2.0 Q10.0,2.0 7.0,1.5 Q4.0,1.0 7.0,1.0 Q10.0,1.0 6.0,1.5 Q2.0,2.0 6.0,2.0 z";
880 struct SvgPen(String);
881 impl Pen for SvgPen {
882 fn move_to(&mut self, x: f32, y: f32) {
883 self.0.push_str(&format!("M{x:.1},{y:.1} "));
884 }
885 fn line_to(&mut self, x: f32, y: f32) {
886 self.0.push_str(&format!("L{x:.1},{y:.1} "));
887 }
888 fn quad_to(&mut self, cx0: f32, cy0: f32, x: f32, y: f32) {
889 self.0
890 .push_str(&format!("Q{cx0:.1},{cy0:.1} {x:.1},{y:.1} "));
891 }
892 fn curve_to(&mut self, cx0: f32, cy0: f32, cx1: f32, cy1: f32, x: f32, y: f32) {
893 self.0.push_str(&format!(
894 "C{cx0:.1},{cy0:.1} {cx1:.1},{cy1:.1} {x:.1},{y:.1} "
895 ));
896 }
897 fn close(&mut self) {
898 self.0.push_str("z ");
899 }
900 }
901 let mut pen = SvgPen(String::default());
902 to_path(&points, &flags, &contours, &mut pen).unwrap();
903 assert_eq!(pen.0.trim(), expected);
904 }
905
906 #[test]
simple_glyph()907 fn simple_glyph() {
908 let font = FontRef::new(font_test_data::COLR_GRADIENT_RECT).unwrap();
909 let loca = font.loca(None).unwrap();
910 let glyf = font.glyf().unwrap();
911 let glyph = loca.get_glyf(GlyphId::new(0), &glyf).unwrap().unwrap();
912 assert_eq!(glyph.number_of_contours(), 2);
913 let simple_glyph = if let Glyph::Simple(simple) = glyph {
914 simple
915 } else {
916 panic!("expected simple glyph");
917 };
918 assert_eq!(
919 simple_glyph
920 .end_pts_of_contours()
921 .iter()
922 .map(|x| x.get())
923 .collect::<Vec<_>>(),
924 &[3, 7]
925 );
926 assert_eq!(
927 simple_glyph
928 .points()
929 .map(|pt| (pt.x, pt.y, pt.on_curve))
930 .collect::<Vec<_>>(),
931 &[
932 (5, 0, true),
933 (5, 100, true),
934 (45, 100, true),
935 (45, 0, true),
936 (10, 5, true),
937 (40, 5, true),
938 (40, 95, true),
939 (10, 95, true),
940 ]
941 );
942 }
943
944 // Test helper to enumerate all TrueType glyphs in the given font
all_glyphs(font_data: &[u8]) -> impl Iterator<Item = Option<Glyph>>945 fn all_glyphs(font_data: &[u8]) -> impl Iterator<Item = Option<Glyph>> {
946 let font = FontRef::new(font_data).unwrap();
947 let loca = font.loca(None).unwrap();
948 let glyf = font.glyf().unwrap();
949 let glyph_count = font.maxp().unwrap().num_glyphs();
950 (0..glyph_count).map(move |gid| loca.get_glyf(GlyphId::new(gid), &glyf).unwrap())
951 }
952
953 #[test]
simple_glyph_overlapping_contour_flag()954 fn simple_glyph_overlapping_contour_flag() {
955 let gids_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR)
956 .enumerate()
957 .filter_map(|(gid, glyph)| match glyph {
958 Some(Glyph::Simple(glyph)) if glyph.has_overlapping_contours() => Some(gid),
959 _ => None,
960 })
961 .collect();
962 // Only GID 3 has the overlap bit set
963 let expected_gids_with_overlap = vec![3];
964 assert_eq!(expected_gids_with_overlap, gids_with_overlap);
965 }
966
967 #[test]
composite_glyph_overlapping_contour_flag()968 fn composite_glyph_overlapping_contour_flag() {
969 let gids_components_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR)
970 .enumerate()
971 .filter_map(|(gid, glyph)| match glyph {
972 Some(Glyph::Composite(glyph)) => Some((gid, glyph)),
973 _ => None,
974 })
975 .flat_map(|(gid, glyph)| {
976 glyph
977 .components()
978 .enumerate()
979 .filter_map(move |(comp_ix, comp)| {
980 comp.flags
981 .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)
982 .then_some((gid, comp_ix))
983 })
984 })
985 .collect();
986 // Only GID 2, component 1 has the overlap bit set
987 let expected_gids_components_with_overlap = vec![(2, 1)];
988 assert_eq!(
989 expected_gids_components_with_overlap,
990 gids_components_with_overlap
991 );
992 }
993
994 #[test]
compute_anchor_flags()995 fn compute_anchor_flags() {
996 let anchor = Anchor::Offset { x: -128, y: 127 };
997 assert_eq!(
998 anchor.compute_flags(),
999 CompositeGlyphFlags::ARGS_ARE_XY_VALUES
1000 );
1001
1002 let anchor = Anchor::Offset { x: -129, y: 127 };
1003 assert_eq!(
1004 anchor.compute_flags(),
1005 CompositeGlyphFlags::ARGS_ARE_XY_VALUES | CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
1006 );
1007 let anchor = Anchor::Offset { x: -1, y: 128 };
1008 assert_eq!(
1009 anchor.compute_flags(),
1010 CompositeGlyphFlags::ARGS_ARE_XY_VALUES | CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
1011 );
1012
1013 let anchor = Anchor::Point {
1014 base: 255,
1015 component: 20,
1016 };
1017 assert_eq!(anchor.compute_flags(), CompositeGlyphFlags::empty());
1018
1019 let anchor = Anchor::Point {
1020 base: 256,
1021 component: 20,
1022 };
1023 assert_eq!(
1024 anchor.compute_flags(),
1025 CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
1026 )
1027 }
1028
1029 #[test]
compute_transform_flags()1030 fn compute_transform_flags() {
1031 fn make_xform(xx: f32, yx: f32, xy: f32, yy: f32) -> Transform {
1032 Transform {
1033 xx: F2Dot14::from_f32(xx),
1034 yx: F2Dot14::from_f32(yx),
1035 xy: F2Dot14::from_f32(xy),
1036 yy: F2Dot14::from_f32(yy),
1037 }
1038 }
1039
1040 assert_eq!(
1041 make_xform(1.0, 0., 0., 1.0).compute_flags(),
1042 CompositeGlyphFlags::empty()
1043 );
1044 assert_eq!(
1045 make_xform(2.0, 0., 0., 2.0).compute_flags(),
1046 CompositeGlyphFlags::WE_HAVE_A_SCALE
1047 );
1048 assert_eq!(
1049 make_xform(2.0, 0., 0., 1.0).compute_flags(),
1050 CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
1051 );
1052 assert_eq!(
1053 make_xform(2.0, 0., 1.0, 1.0).compute_flags(),
1054 CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO
1055 );
1056 }
1057
1058 #[test]
point_flags_and_marker_bits()1059 fn point_flags_and_marker_bits() {
1060 let bits = [
1061 PointFlags::OFF_CURVE_CUBIC,
1062 PointFlags::ON_CURVE,
1063 PointMarker::HAS_DELTA.0,
1064 PointMarker::TOUCHED_X.0,
1065 PointMarker::TOUCHED_Y.0,
1066 ];
1067 // Ensure bits don't overlap
1068 for (i, a) in bits.iter().enumerate() {
1069 for b in &bits[i + 1..] {
1070 assert_eq!(a & b, 0);
1071 }
1072 }
1073 }
1074 }
1075