Skip to main content

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