hayro_font/
lib.rs

1/*!
2A CFF and Type1 font parser.
3
4This crate is a fork of the [`ttf-parser`](https://github.com/harfbuzz/ttf-parser) library,
5but with the majority of the functionality completely stripped away.
6The purpose of this crate is to be a light-weight font parser for CFF and Type1 fonts,
7as they can be found in PDFs. Only the code for parsing CFF fonts has been retained, while code
8for parsing Type1 fonts was newly added.
9
10Note that this is an internal crate and not meant to be used directly. Therefore,
11it's not well-documented.
12*/
13
14#![forbid(unsafe_code)]
15#![deny(missing_docs)]
16
17use crate::util::TryNumFrom;
18
19pub mod cff;
20pub mod type1;
21
22mod argstack;
23mod util;
24
25/// A type-safe wrapper for glyph ID.
26#[repr(transparent)]
27#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default, Debug, Hash)]
28pub struct GlyphId(pub u16);
29
30/// A trait for glyph outline construction.
31pub trait OutlineBuilder {
32    /// Appends a `MoveTo` segment.
33    ///
34    /// Start of a contour.
35    fn move_to(&mut self, x: f32, y: f32);
36
37    /// Appends a `LineTo` segment.
38    fn line_to(&mut self, x: f32, y: f32);
39
40    /// Appends a `QuadTo` segment.
41    fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32);
42
43    /// Appends a `CurveTo` segment.
44    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32);
45
46    /// Appends a `ClosePath` segment.
47    ///
48    /// End of a contour.
49    fn close(&mut self);
50}
51
52struct DummyOutline;
53impl OutlineBuilder for DummyOutline {
54    fn move_to(&mut self, _: f32, _: f32) {}
55    fn line_to(&mut self, _: f32, _: f32) {}
56    fn quad_to(&mut self, _: f32, _: f32, _: f32, _: f32) {}
57    fn curve_to(&mut self, _: f32, _: f32, _: f32, _: f32, _: f32, _: f32) {}
58    fn close(&mut self) {}
59}
60
61/// A rectangle.
62///
63/// Doesn't guarantee that `x_min` <= `x_max` and/or `y_min` <= `y_max`.
64#[repr(C)]
65#[allow(missing_docs)]
66#[derive(Clone, Copy, PartialEq, Eq, Debug)]
67pub struct Rect {
68    pub x_min: i16,
69    pub y_min: i16,
70    pub x_max: i16,
71    pub y_max: i16,
72}
73
74impl Rect {
75    #[inline]
76    fn zero() -> Self {
77        Self {
78            x_min: 0,
79            y_min: 0,
80            x_max: 0,
81            y_max: 0,
82        }
83    }
84
85    /// Returns rect's width.
86    #[inline]
87    pub fn width(&self) -> i16 {
88        self.x_max - self.x_min
89    }
90
91    /// Returns rect's height.
92    #[inline]
93    pub fn height(&self) -> i16 {
94        self.y_max - self.y_min
95    }
96}
97
98/// A rectangle described by the left-lower and upper-right points.
99#[derive(Clone, Copy, Debug, PartialEq)]
100pub struct RectF {
101    /// The horizontal minimum of the rect.
102    pub x_min: f32,
103    /// The vertical minimum of the rect.
104    pub y_min: f32,
105    /// The horizontal maximum of the rect.
106    pub x_max: f32,
107    /// The vertical maximum of the rect.
108    pub y_max: f32,
109}
110
111impl RectF {
112    #[inline]
113    fn new() -> Self {
114        Self {
115            x_min: f32::MAX,
116            y_min: f32::MAX,
117            x_max: f32::MIN,
118            y_max: f32::MIN,
119        }
120    }
121
122    #[inline]
123    fn is_default(&self) -> bool {
124        self.x_min == f32::MAX
125            && self.y_min == f32::MAX
126            && self.x_max == f32::MIN
127            && self.y_max == f32::MIN
128    }
129
130    #[inline]
131    fn extend_by(&mut self, x: f32, y: f32) {
132        self.x_min = self.x_min.min(x);
133        self.y_min = self.y_min.min(y);
134        self.x_max = self.x_max.max(x);
135        self.y_max = self.y_max.max(y);
136    }
137
138    #[inline]
139    fn to_rect(self) -> Option<Rect> {
140        Some(Rect {
141            x_min: i16::try_num_from(self.x_min)?,
142            y_min: i16::try_num_from(self.y_min)?,
143            x_max: i16::try_num_from(self.x_max)?,
144            y_max: i16::try_num_from(self.y_max)?,
145        })
146    }
147}
148
149pub(crate) struct Builder<'a> {
150    pub(crate) builder: &'a mut dyn OutlineBuilder,
151    pub(crate) bbox: RectF,
152}
153
154impl<'a> Builder<'a> {
155    #[inline]
156    fn move_to(&mut self, x: f32, y: f32) {
157        self.bbox.extend_by(x, y);
158        self.builder.move_to(x, y);
159    }
160
161    #[inline]
162    fn line_to(&mut self, x: f32, y: f32) {
163        self.bbox.extend_by(x, y);
164        self.builder.line_to(x, y);
165    }
166
167    #[inline]
168    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
169        self.bbox.extend_by(x1, y1);
170        self.bbox.extend_by(x2, y2);
171        self.bbox.extend_by(x, y);
172        self.builder.curve_to(x1, y1, x2, y2, x, y);
173    }
174
175    #[inline]
176    fn close(&mut self) {
177        self.builder.close();
178    }
179}
180
181/// An affine transformation matrix.
182#[allow(missing_docs)]
183#[derive(Clone, Copy, Debug)]
184pub struct Matrix {
185    pub sx: f32,
186    pub ky: f32,
187    pub kx: f32,
188    pub sy: f32,
189    pub tx: f32,
190    pub ty: f32,
191}
192
193impl Default for Matrix {
194    fn default() -> Self {
195        Self {
196            sx: 0.001,
197            ky: 0.0,
198            kx: 0.0,
199            sy: 0.001,
200            tx: 0.0,
201            ty: 0.0,
202        }
203    }
204}
205
206/// A list of errors that can occur during CFF/Type1 glyph outlining.
207#[allow(missing_docs)]
208#[derive(Clone, Copy, PartialEq, Eq, Debug)]
209pub enum OutlineError {
210    NoGlyph,
211    ReadOutOfBounds,
212    ZeroBBox,
213    InvalidOperator,
214    UnsupportedOperator,
215    MissingEndChar,
216    DataAfterEndChar,
217    NestingLimitReached,
218    ArgumentsStackLimitReached,
219    InvalidArgumentsStackLength,
220    BboxOverflow,
221    MissingMoveTo,
222    InvalidSubroutineIndex,
223    NoLocalSubroutines,
224    InvalidSeacCode,
225}