1//! A [Glyph Data Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/glyf) implementation.
3
4use core::num::NonZeroU16;
5
6use crate::parser::{LazyArray16, NumFrom, Stream, F2DOT14};
7use crate::{loca, BBox, GlyphId, OutlineBuilder, Rect};
8
9pub(crate) struct Builder<'a> {
10 pub builder: &'a mut dyn OutlineBuilder,
11 pub transform: Transform,
12 is_default_ts: bool, // `bool` is faster than `Option` or `is_default`.
13 // We have to always calculate the bbox, because `gvar` doesn't store one
14 // and in case of a malformed bbox in `glyf`.
15 pub bbox: BBox,
16 first_on_curve: Option<Point>,
17 first_off_curve: Option<Point>,
18 last_off_curve: Option<Point>,
19}
20
21impl<'a> Builder<'a> {
22 #[inline]
23 pub fn new(transform: Transform, bbox: BBox, builder: &'a mut dyn OutlineBuilder) -> Self {
24 Builder {
25 builder,
26 transform,
27 is_default_ts: transform.is_default(),
28 bbox,
29 first_on_curve: None,
30 first_off_curve: None,
31 last_off_curve: None,
32 }
33 }
34
35 #[inline]
36 fn move_to(&mut self, mut x: f32, mut y: f32) {
37 if !self.is_default_ts {
38 self.transform.apply_to(&mut x, &mut y);
39 }
40
41 self.bbox.extend_by(x, y);
42
43 self.builder.move_to(x, y);
44 }
45
46 #[inline]
47 fn line_to(&mut self, mut x: f32, mut y: f32) {
48 if !self.is_default_ts {
49 self.transform.apply_to(&mut x, &mut y);
50 }
51
52 self.bbox.extend_by(x, y);
53
54 self.builder.line_to(x, y);
55 }
56
57 #[inline]
58 fn quad_to(&mut self, mut x1: f32, mut y1: f32, mut x: f32, mut y: f32) {
59 if !self.is_default_ts {
60 self.transform.apply_to(&mut x1, &mut y1);
61 self.transform.apply_to(&mut x, &mut y);
62 }
63
64 self.bbox.extend_by(x1, y1);
65 self.bbox.extend_by(x, y);
66
67 self.builder.quad_to(x1, y1, x, y);
68 }
69
70 // Useful links:
71 //
72 // - https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
73 // - https://stackoverflow.com/a/20772557
74 #[inline]
75 pub fn push_point(&mut self, x: f32, y: f32, on_curve_point: bool, last_point: bool) {
76 let p = Point { x, y };
77 if self.first_on_curve.is_none() {
78 if on_curve_point {
79 self.first_on_curve = Some(p);
80 self.move_to(p.x, p.y);
81 } else {
82 if let Some(offcurve) = self.first_off_curve {
83 let mid = offcurve.lerp(p, 0.5);
84 self.first_on_curve = Some(mid);
85 self.last_off_curve = Some(p);
86 self.move_to(mid.x, mid.y);
87 } else {
88 self.first_off_curve = Some(p);
89 }
90 }
91 } else {
92 match (self.last_off_curve, on_curve_point) {
93 (Some(offcurve), true) => {
94 self.last_off_curve = None;
95 self.quad_to(offcurve.x, offcurve.y, p.x, p.y);
96 }
97 (Some(offcurve), false) => {
98 self.last_off_curve = Some(p);
99 let mid = offcurve.lerp(p, 0.5);
100 self.quad_to(offcurve.x, offcurve.y, mid.x, mid.y);
101 }
102 (None, true) => {
103 self.line_to(p.x, p.y);
104 }
105 (None, false) => {
106 self.last_off_curve = Some(p);
107 }
108 }
109 }
110
111 if last_point {
112 self.finish_contour();
113 }
114 }
115
116 #[inline]
117 fn finish_contour(&mut self) {
118 if let (Some(offcurve1), Some(offcurve2)) = (self.first_off_curve, self.last_off_curve) {
119 self.last_off_curve = None;
120 let mid = offcurve2.lerp(offcurve1, 0.5);
121 self.quad_to(offcurve2.x, offcurve2.y, mid.x, mid.y);
122 }
123
124 if let (Some(p), Some(offcurve1)) = (self.first_on_curve, self.first_off_curve) {
125 self.quad_to(offcurve1.x, offcurve1.y, p.x, p.y);
126 } else if let (Some(p), Some(offcurve2)) = (self.first_on_curve, self.last_off_curve) {
127 self.quad_to(offcurve2.x, offcurve2.y, p.x, p.y);
128 } else if let Some(p) = self.first_on_curve {
129 self.line_to(p.x, p.y);
130 }
131
132 self.first_on_curve = None;
133 self.first_off_curve = None;
134 self.last_off_curve = None;
135
136 self.builder.close();
137 }
138}
139
140#[derive(Clone, Copy)]
141pub(crate) struct Transform {
142 pub a: f32,
143 pub b: f32,
144 pub c: f32,
145 pub d: f32,
146 pub e: f32,
147 pub f: f32,
148}
149
150impl Transform {
151 #[cfg(feature = "variable-fonts")]
152 #[inline]
153 pub fn new_translate(tx: f32, ty: f32) -> Self {
154 Transform {
155 a: 1.0,
156 b: 0.0,
157 c: 0.0,
158 d: 1.0,
159 e: tx,
160 f: ty,
161 }
162 }
163
164 #[inline]
165 pub fn combine(ts1: Self, ts2: Self) -> Self {
166 Transform {
167 a: ts1.a * ts2.a + ts1.c * ts2.b,
168 b: ts1.b * ts2.a + ts1.d * ts2.b,
169 c: ts1.a * ts2.c + ts1.c * ts2.d,
170 d: ts1.b * ts2.c + ts1.d * ts2.d,
171 e: ts1.a * ts2.e + ts1.c * ts2.f + ts1.e,
172 f: ts1.b * ts2.e + ts1.d * ts2.f + ts1.f,
173 }
174 }
175
176 #[inline]
177 fn apply_to(&self, x: &mut f32, y: &mut f32) {
178 let tx = *x;
179 let ty = *y;
180 *x = self.a * tx + self.c * ty + self.e;
181 *y = self.b * tx + self.d * ty + self.f;
182 }
183
184 #[inline]
185 fn is_default(&self) -> bool {
186 // A direct float comparison is fine in our case.
187 self.a == 1.0
188 && self.b == 0.0
189 && self.c == 0.0
190 && self.d == 1.0
191 && self.e == 0.0
192 && self.f == 0.0
193 }
194}
195
196impl Default for Transform {
197 #[inline]
198 fn default() -> Self {
199 Transform {
200 a: 1.0,
201 b: 0.0,
202 c: 0.0,
203 d: 1.0,
204 e: 0.0,
205 f: 0.0,
206 }
207 }
208}
209
210impl core::fmt::Debug for Transform {
211 #[inline]
212 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
213 write!(
214 f,
215 "Transform({} {} {} {} {} {})",
216 self.a, self.b, self.c, self.d, self.e, self.f
217 )
218 }
219}
220
221#[derive(Clone, Copy, Debug)]
222pub(crate) struct CompositeGlyphInfo {
223 pub glyph_id: GlyphId,
224 pub transform: Transform,
225 #[allow(dead_code)]
226 pub flags: CompositeGlyphFlags,
227}
228
229#[derive(Clone)]
230pub(crate) struct CompositeGlyphIter<'a> {
231 stream: Stream<'a>,
232}
233
234impl<'a> CompositeGlyphIter<'a> {
235 #[inline]
236 pub fn new(data: &'a [u8]) -> Self {
237 CompositeGlyphIter {
238 stream: Stream::new(data),
239 }
240 }
241}
242
243impl<'a> Iterator for CompositeGlyphIter<'a> {
244 type Item = CompositeGlyphInfo;
245
246 #[inline]
247 fn next(&mut self) -> Option<Self::Item> {
248 let flags = CompositeGlyphFlags(self.stream.read::<u16>()?);
249 let glyph_id = self.stream.read::<GlyphId>()?;
250
251 let mut ts = Transform::default();
252
253 if flags.args_are_xy_values() {
254 if flags.arg_1_and_2_are_words() {
255 ts.e = f32::from(self.stream.read::<i16>()?);
256 ts.f = f32::from(self.stream.read::<i16>()?);
257 } else {
258 ts.e = f32::from(self.stream.read::<i8>()?);
259 ts.f = f32::from(self.stream.read::<i8>()?);
260 }
261 }
262
263 if flags.we_have_a_two_by_two() {
264 ts.a = self.stream.read::<F2DOT14>()?.to_f32();
265 ts.b = self.stream.read::<F2DOT14>()?.to_f32();
266 ts.c = self.stream.read::<F2DOT14>()?.to_f32();
267 ts.d = self.stream.read::<F2DOT14>()?.to_f32();
268 } else if flags.we_have_an_x_and_y_scale() {
269 ts.a = self.stream.read::<F2DOT14>()?.to_f32();
270 ts.d = self.stream.read::<F2DOT14>()?.to_f32();
271 } else if flags.we_have_a_scale() {
272 ts.a = self.stream.read::<F2DOT14>()?.to_f32();
273 ts.d = ts.a;
274 }
275
276 if !flags.more_components() {
277 // Finish the iterator even if stream still has some data.
278 self.stream.jump_to_end();
279 }
280
281 Some(CompositeGlyphInfo {
282 glyph_id,
283 transform: ts,
284 flags,
285 })
286 }
287}
288
289// Due to some optimization magic, using f32 instead of i16
290// makes the code ~10% slower. At least on my machine.
291// I guess it's due to the fact that with i16 the struct
292// fits into the machine word.
293#[derive(Clone, Copy, Debug)]
294pub(crate) struct GlyphPoint {
295 pub x: i16,
296 pub y: i16,
297 /// Indicates that a point is a point on curve
298 /// and not a control point.
299 pub on_curve_point: bool,
300 pub last_point: bool,
301}
302
303#[derive(Clone, Default)]
304pub(crate) struct GlyphPointsIter<'a> {
305 endpoints: EndpointsIter<'a>,
306 flags: FlagsIter<'a>,
307 x_coords: CoordsIter<'a>,
308 y_coords: CoordsIter<'a>,
309 pub points_left: u16, // Number of points left in the glyph.
310}
311
312#[cfg(feature = "variable-fonts")]
313impl GlyphPointsIter<'_> {
314 #[inline]
315 pub fn current_contour(&self) -> u16 {
316 self.endpoints.index - 1
317 }
318}
319
320impl<'a> Iterator for GlyphPointsIter<'a> {
321 type Item = GlyphPoint;
322
323 #[inline]
324 fn next(&mut self) -> Option<Self::Item> {
325 self.points_left = self.points_left.checked_sub(1)?;
326
327 // TODO: skip empty contours
328
329 let last_point: bool = self.endpoints.next();
330 let flags: SimpleGlyphFlags = self.flags.next()?;
331 Some(GlyphPoint {
332 x: self
333 .x_coords
334 .next(is_short:flags.x_short(), is_same_or_short:flags.x_is_same_or_positive_short()),
335 y: self
336 .y_coords
337 .next(is_short:flags.y_short(), is_same_or_short:flags.y_is_same_or_positive_short()),
338 on_curve_point: flags.on_curve_point(),
339 last_point,
340 })
341 }
342}
343
344/// A simple flattening iterator for glyph's endpoints.
345///
346/// Translates endpoints like: 2 4 7
347/// into flags: 0 0 1 0 1 0 0 1
348#[derive(Clone, Copy, Default)]
349struct EndpointsIter<'a> {
350 endpoints: LazyArray16<'a, u16>, // Each endpoint indicates a contour end.
351 index: u16,
352 left: u16,
353}
354
355impl<'a> EndpointsIter<'a> {
356 #[inline]
357 fn new(endpoints: LazyArray16<'a, u16>) -> Option<Self> {
358 Some(EndpointsIter {
359 endpoints,
360 index: 1,
361 left: endpoints.get(0)?,
362 })
363 }
364
365 #[inline]
366 fn next(&mut self) -> bool {
367 if self.left == 0 {
368 if let Some(end) = self.endpoints.get(self.index) {
369 let prev = self.endpoints.get(self.index - 1).unwrap_or(0);
370 // Malformed font can have endpoints not in increasing order,
371 // so we have to use checked_sub.
372 self.left = end.saturating_sub(prev);
373 self.left = self.left.saturating_sub(1);
374 }
375
376 // Always advance the index, so we can check the current contour number.
377 if let Some(n) = self.index.checked_add(1) {
378 self.index = n;
379 }
380
381 true
382 } else {
383 self.left -= 1;
384 false
385 }
386 }
387}
388
389#[derive(Clone, Default)]
390struct FlagsIter<'a> {
391 stream: Stream<'a>,
392 // Number of times the `flags` should be used
393 // before reading the next one from `stream`.
394 repeats: u8,
395 flags: SimpleGlyphFlags,
396}
397
398impl<'a> FlagsIter<'a> {
399 #[inline]
400 fn new(data: &'a [u8]) -> Self {
401 FlagsIter {
402 stream: Stream::new(data),
403 repeats: 0,
404 flags: SimpleGlyphFlags(0),
405 }
406 }
407}
408
409impl<'a> Iterator for FlagsIter<'a> {
410 type Item = SimpleGlyphFlags;
411
412 #[inline]
413 fn next(&mut self) -> Option<Self::Item> {
414 if self.repeats == 0 {
415 self.flags = SimpleGlyphFlags(self.stream.read::<u8>().unwrap_or(default:0));
416 if self.flags.repeat_flag() {
417 self.repeats = self.stream.read::<u8>().unwrap_or(default:0);
418 }
419 } else {
420 self.repeats -= 1;
421 }
422
423 Some(self.flags)
424 }
425}
426
427#[derive(Clone, Default)]
428struct CoordsIter<'a> {
429 stream: Stream<'a>,
430 prev: i16, // Points are stored as deltas, so we have to keep the previous one.
431}
432
433impl<'a> CoordsIter<'a> {
434 #[inline]
435 fn new(data: &'a [u8]) -> Self {
436 CoordsIter {
437 stream: Stream::new(data),
438 prev: 0,
439 }
440 }
441
442 #[inline]
443 fn next(&mut self, is_short: bool, is_same_or_short: bool) -> i16 {
444 // See https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description
445 // for details about Simple Glyph Flags processing.
446
447 // We've already checked the coords data, so it's safe to fallback to 0.
448
449 let mut n = 0;
450 if is_short {
451 n = i16::from(self.stream.read::<u8>().unwrap_or(0));
452 if !is_same_or_short {
453 n = -n;
454 }
455 } else if !is_same_or_short {
456 n = self.stream.read::<i16>().unwrap_or(0);
457 }
458
459 self.prev = self.prev.wrapping_add(n);
460 self.prev
461 }
462}
463
464#[derive(Clone, Copy, Debug)]
465struct Point {
466 x: f32,
467 y: f32,
468}
469
470impl Point {
471 #[inline]
472 fn lerp(self, other: Point, t: f32) -> Point {
473 Point {
474 x: self.x + t * (other.x - self.x),
475 y: self.y + t * (other.y - self.y),
476 }
477 }
478}
479
480// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description
481#[derive(Clone, Copy, Default)]
482struct SimpleGlyphFlags(u8);
483
484#[rustfmt::skip]
485impl SimpleGlyphFlags {
486 #[inline] fn on_curve_point(self) -> bool { self.0 & 0x01 != 0 }
487 #[inline] fn x_short(self) -> bool { self.0 & 0x02 != 0 }
488 #[inline] fn y_short(self) -> bool { self.0 & 0x04 != 0 }
489 #[inline] fn repeat_flag(self) -> bool { self.0 & 0x08 != 0 }
490 #[inline] fn x_is_same_or_positive_short(self) -> bool { self.0 & 0x10 != 0 }
491 #[inline] fn y_is_same_or_positive_short(self) -> bool { self.0 & 0x20 != 0 }
492}
493
494// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
495#[derive(Clone, Copy, Debug)]
496pub(crate) struct CompositeGlyphFlags(u16);
497
498#[rustfmt::skip]
499impl CompositeGlyphFlags {
500 #[inline] pub fn arg_1_and_2_are_words(self) -> bool { self.0 & 0x0001 != 0 }
501 #[inline] pub fn args_are_xy_values(self) -> bool { self.0 & 0x0002 != 0 }
502 #[inline] pub fn we_have_a_scale(self) -> bool { self.0 & 0x0008 != 0 }
503 #[inline] pub fn more_components(self) -> bool { self.0 & 0x0020 != 0 }
504 #[inline] pub fn we_have_an_x_and_y_scale(self) -> bool { self.0 & 0x0040 != 0 }
505 #[inline] pub fn we_have_a_two_by_two(self) -> bool { self.0 & 0x0080 != 0 }
506}
507
508// It's not defined in the spec, so we are using our own value.
509pub(crate) const MAX_COMPONENTS: u8 = 32;
510
511#[allow(clippy::comparison_chain)]
512#[inline]
513fn outline_impl(
514 loca_table: loca::Table,
515 glyf_table: &[u8],
516 data: &[u8],
517 depth: u8,
518 builder: &mut Builder,
519) -> Option<Option<Rect>> {
520 if depth >= MAX_COMPONENTS {
521 return None;
522 }
523
524 let mut s = Stream::new(data);
525 let number_of_contours = s.read::<i16>()?;
526 s.advance(8); // Skip bbox. We use calculated one.
527
528 if number_of_contours > 0 {
529 // Simple glyph.
530
531 // u16 casting is safe, since we already checked that the value is positive.
532 let number_of_contours = NonZeroU16::new(number_of_contours as u16)?;
533 for point in parse_simple_outline(s.tail()?, number_of_contours)? {
534 builder.push_point(
535 f32::from(point.x),
536 f32::from(point.y),
537 point.on_curve_point,
538 point.last_point,
539 );
540 }
541 } else if number_of_contours < 0 {
542 // Composite glyph.
543 for comp in CompositeGlyphIter::new(s.tail()?) {
544 if let Some(range) = loca_table.glyph_range(comp.glyph_id) {
545 if let Some(glyph_data) = glyf_table.get(range) {
546 let transform = Transform::combine(builder.transform, comp.transform);
547 let mut b = Builder::new(transform, builder.bbox, builder.builder);
548 outline_impl(loca_table, glyf_table, glyph_data, depth + 1, &mut b)?;
549
550 // Take updated bbox.
551 builder.bbox = b.bbox;
552 }
553 }
554 }
555 }
556
557 if builder.bbox.is_default() {
558 return Some(None);
559 }
560
561 Some(builder.bbox.to_rect())
562}
563
564#[inline]
565pub(crate) fn parse_simple_outline(
566 glyph_data: &[u8],
567 number_of_contours: NonZeroU16,
568) -> Option<GlyphPointsIter> {
569 let mut s = Stream::new(glyph_data);
570 let endpoints = s.read_array16::<u16>(number_of_contours.get())?;
571
572 let points_total = endpoints.last()?.checked_add(1)?;
573
574 // Contours with a single point should be ignored.
575 // But this is not an error, so we should return an "empty" iterator.
576 if points_total == 1 {
577 return Some(GlyphPointsIter::default());
578 }
579
580 // Skip instructions byte code.
581 let instructions_len = s.read::<u16>()?;
582 s.advance(usize::from(instructions_len));
583
584 let flags_offset = s.offset();
585 let (x_coords_len, y_coords_len) = resolve_coords_len(&mut s, points_total)?;
586 let x_coords_offset = s.offset();
587 let y_coords_offset = x_coords_offset + usize::num_from(x_coords_len);
588 let y_coords_end = y_coords_offset + usize::num_from(y_coords_len);
589
590 Some(GlyphPointsIter {
591 endpoints: EndpointsIter::new(endpoints)?,
592 flags: FlagsIter::new(glyph_data.get(flags_offset..x_coords_offset)?),
593 x_coords: CoordsIter::new(glyph_data.get(x_coords_offset..y_coords_offset)?),
594 y_coords: CoordsIter::new(glyph_data.get(y_coords_offset..y_coords_end)?),
595 points_left: points_total,
596 })
597}
598
599/// Resolves coordinate arrays length.
600///
601/// The length depends on *Simple Glyph Flags*, so we have to process them all to find it.
602fn resolve_coords_len(s: &mut Stream, points_total: u16) -> Option<(u32, u32)> {
603 let mut flags_left = u32::from(points_total);
604 let mut repeats;
605 let mut x_coords_len = 0;
606 let mut y_coords_len = 0;
607 while flags_left > 0 {
608 let flags = SimpleGlyphFlags(s.read::<u8>()?);
609
610 // The number of times a glyph point repeats.
611 repeats = if flags.repeat_flag() {
612 let repeats = s.read::<u8>()?;
613 u32::from(repeats) + 1
614 } else {
615 1
616 };
617
618 if repeats > flags_left {
619 return None;
620 }
621
622 // No need to check for `*_coords_len` overflow since u32 is more than enough.
623
624 // Non-obfuscated code below.
625 // Branchless version is surprisingly faster.
626 //
627 // if flags.x_short() {
628 // // Coordinate is 1 byte long.
629 // x_coords_len += repeats;
630 // } else if !flags.x_is_same_or_positive_short() {
631 // // Coordinate is 2 bytes long.
632 // x_coords_len += repeats * 2;
633 // }
634 // if flags.y_short() {
635 // // Coordinate is 1 byte long.
636 // y_coords_len += repeats;
637 // } else if !flags.y_is_same_or_positive_short() {
638 // // Coordinate is 2 bytes long.
639 // y_coords_len += repeats * 2;
640 // }
641
642 x_coords_len += (flags.0 & 0x02 != 0) as u32 * repeats;
643 x_coords_len += (flags.0 & (0x02 | 0x10) == 0) as u32 * (repeats * 2);
644
645 y_coords_len += (flags.0 & 0x04 != 0) as u32 * repeats;
646 y_coords_len += (flags.0 & (0x04 | 0x20) == 0) as u32 * (repeats * 2);
647
648 flags_left -= repeats;
649 }
650
651 Some((x_coords_len, y_coords_len))
652}
653
654/// A [Glyph Data Table](
655/// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf).
656#[derive(Clone, Copy)]
657pub struct Table<'a> {
658 pub(crate) data: &'a [u8],
659 loca_table: loca::Table<'a>,
660}
661
662impl core::fmt::Debug for Table<'_> {
663 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
664 write!(f, "Table {{ ... }}")
665 }
666}
667
668impl<'a> Table<'a> {
669 /// Parses a table from raw data.
670 #[inline]
671 pub fn parse(loca_table: loca::Table<'a>, data: &'a [u8]) -> Option<Self> {
672 Some(Table { loca_table, data })
673 }
674
675 /// Outlines a glyph.
676 #[inline]
677 pub fn outline(&self, glyph_id: GlyphId, builder: &mut dyn OutlineBuilder) -> Option<Rect> {
678 let mut b: Builder<'_> = Builder::new(Transform::default(), BBox::new(), builder);
679 let glyph_data: &[u8] = self.get(glyph_id)?;
680 outline_impl(self.loca_table, self.data, glyph_data, depth:0, &mut b)?
681 }
682
683 #[inline]
684 pub(crate) fn get(&self, glyph_id: GlyphId) -> Option<&'a [u8]> {
685 let range: Range = self.loca_table.glyph_range(glyph_id)?;
686 self.data.get(index:range)
687 }
688}
689