ab_glyph/
ttfp.rs

1//! ttf-parser crate specific code. ttf-parser types should not be leaked publicly.
2mod outliner;
3#[cfg(feature = "variable-fonts")]
4mod variable;
5
6use crate::{point, v2, Font, GlyphId, GlyphImageFormat, GlyphSvg, InvalidFont, Outline, Rect};
7use alloc::boxed::Box;
8#[cfg(not(feature = "std"))]
9use alloc::vec::Vec;
10use core::fmt;
11use owned_ttf_parser::{self as ttfp, AsFaceRef};
12
13impl From<GlyphId> for ttfp::GlyphId {
14    #[inline]
15    fn from(id: GlyphId) -> Self {
16        Self(id.0)
17    }
18}
19
20/// Font data handle stored as a `&[u8]` + parsed data.
21/// See [`Font`] for more methods.
22///
23/// Also see the owned version [`FontVec`].
24///
25/// # Example
26/// ```
27/// use ab_glyph::{Font, FontRef};
28///
29/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
30/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
31///
32/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
33/// # Ok(()) }
34/// ```
35#[derive(Clone)]
36pub struct FontRef<'font>(ttfp::PreParsedSubtables<'font, ttfp::Face<'font>>);
37
38impl fmt::Debug for FontRef<'_> {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(f, "FontRef")
41    }
42}
43
44impl<'font> FontRef<'font> {
45    /// Creates an `FontRef` from a byte-slice.
46    ///
47    /// For font collections see
48    /// [`FontRef::try_from_slice_and_index`].
49    ///
50    /// # Example
51    /// ```
52    /// # use ab_glyph::*;
53    /// # fn main() -> Result<(), InvalidFont> {
54    /// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
55    /// # Ok(()) }
56    /// ```
57    #[inline]
58    pub fn try_from_slice(data: &'font [u8]) -> Result<Self, InvalidFont> {
59        Self::try_from_slice_and_index(data, 0)
60    }
61
62    /// Creates an `FontRef` from byte-slice.
63    ///
64    /// You can set index for font collections. For simple fonts use `0` or
65    /// [`FontRef::try_from_slice`].
66    ///
67    /// # Example
68    /// ```
69    /// # use ab_glyph::*;
70    /// # fn main() -> Result<(), InvalidFont> {
71    /// let font =
72    ///     FontRef::try_from_slice_and_index(include_bytes!("../../dev/fonts/Exo2-Light.otf"), 0)?;
73    /// # Ok(()) }
74    /// ```
75    #[inline]
76    pub fn try_from_slice_and_index(data: &'font [u8], index: u32) -> Result<Self, InvalidFont> {
77        Ok(Self(ttfp::PreParsedSubtables::from(
78            ttfp::Face::parse(data, index).map_err(|_| InvalidFont)?,
79        )))
80    }
81}
82
83/// Font data handle stored in a `Vec<u8>`  + parsed data.
84/// See [`Font`] for more methods.
85///
86/// Also see [`FontRef`].
87///
88/// # Example
89/// ```
90/// use ab_glyph::{Font, FontVec};
91///
92/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
93/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
94/// let font = FontVec::try_from_vec_and_index(owned_font_data, 0)?;
95///
96/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
97/// # Ok(()) }
98/// ```
99pub struct FontVec(ttfp::PreParsedSubtables<'static, ttfp::OwnedFace>);
100
101impl fmt::Debug for FontVec {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        write!(f, "FontVec")
104    }
105}
106
107impl FontVec {
108    /// Creates an `FontVec` from owned data.
109    ///
110    /// For font collections see
111    /// [`FontVec::try_from_vec_and_index`].
112    ///
113    /// # Example
114    /// ```
115    /// # use ab_glyph::*;
116    /// # fn main() -> Result<(), InvalidFont> {
117    /// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
118    /// let font = FontVec::try_from_vec(owned_font_data)?;
119    /// # Ok(()) }
120    /// ```
121    #[inline]
122    pub fn try_from_vec(data: Vec<u8>) -> Result<Self, InvalidFont> {
123        Self::try_from_vec_and_index(data, 0)
124    }
125
126    /// Creates an `FontVec` from owned data.
127    ///
128    /// You can set index for font collections. For simple fonts use `0` or
129    /// [`FontVec::try_from_vec`].
130    ///
131    /// # Example
132    /// ```
133    /// # use ab_glyph::*;
134    /// # fn main() -> Result<(), InvalidFont> {
135    /// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
136    /// let font = FontVec::try_from_vec_and_index(owned_font_data, 0)?;
137    /// # Ok(()) }
138    /// ```
139    #[inline]
140    pub fn try_from_vec_and_index(data: Vec<u8>, index: u32) -> Result<Self, InvalidFont> {
141        Ok(Self(ttfp::PreParsedSubtables::from(
142            ttfp::OwnedFace::from_vec(data, index).map_err(|_| InvalidFont)?,
143        )))
144    }
145
146    /// Extracts a slice containing the data passed into e.g. [`FontVec::try_from_vec`].
147    ///
148    /// # Example
149    /// ```
150    /// # use ab_glyph::*;
151    /// # fn main() -> Result<(), InvalidFont> {
152    /// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
153    /// let font_data_clone = owned_font_data.clone();
154    /// let font = FontVec::try_from_vec(owned_font_data)?;
155    /// assert_eq!(font.as_slice(), font_data_clone);
156    /// # Ok(()) }
157    /// ```
158    #[inline]
159    pub fn as_slice(&self) -> &[u8] {
160        self.0.face.as_slice()
161    }
162
163    /// Unwraps the data passed into e.g. [`FontVec::try_from_vec`].
164    ///
165    /// # Example
166    /// ```
167    /// # use ab_glyph::*;
168    /// # fn main() -> Result<(), InvalidFont> {
169    /// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
170    /// let font_data_clone = owned_font_data.clone();
171    /// let font = FontVec::try_from_vec(owned_font_data)?;
172    /// assert_eq!(font.into_vec(), font_data_clone);
173    /// # Ok(()) }
174    /// ```
175    #[inline]
176    pub fn into_vec(self) -> Vec<u8> {
177        self.0.face.into_vec()
178    }
179}
180
181/// Implement `Font` for `Self(AsFontRef)` types.
182macro_rules! impl_font {
183    ($font:ty) => {
184        impl Font for $font {
185            #[inline]
186            fn units_per_em(&self) -> Option<f32> {
187                // TODO unwrap signature when making next breaking change
188                Some(self.0.as_face_ref().units_per_em().into())
189            }
190
191            #[inline]
192            fn ascent_unscaled(&self) -> f32 {
193                self.0.as_face_ref().ascender().into()
194            }
195
196            #[inline]
197            fn descent_unscaled(&self) -> f32 {
198                self.0.as_face_ref().descender().into()
199            }
200
201            #[inline]
202            fn line_gap_unscaled(&self) -> f32 {
203                self.0.as_face_ref().line_gap().into()
204            }
205
206            #[inline]
207            fn glyph_id(&self, c: char) -> GlyphId {
208                // Note: Using `PreParsedSubtables` method for better performance.
209                let index = self.0.glyph_index(c).map(|id| id.0).unwrap_or(0);
210                GlyphId(index)
211            }
212
213            #[inline]
214            fn h_advance_unscaled(&self, id: GlyphId) -> f32 {
215                self.0
216                    .as_face_ref()
217                    .glyph_hor_advance(id.into())
218                    .unwrap_or_default()
219                    .into()
220            }
221
222            #[inline]
223            fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
224                self.0
225                    .as_face_ref()
226                    .glyph_hor_side_bearing(id.into())
227                    .unwrap_or_default()
228                    .into()
229            }
230
231            #[inline]
232            fn v_advance_unscaled(&self, id: GlyphId) -> f32 {
233                self.0
234                    .as_face_ref()
235                    .glyph_ver_advance(id.into())
236                    .unwrap_or_default()
237                    .into()
238            }
239
240            #[inline]
241            fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
242                self.0
243                    .as_face_ref()
244                    .glyph_ver_side_bearing(id.into())
245                    .unwrap_or_default()
246                    .into()
247            }
248
249            #[inline]
250            fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 {
251                // Note: Using `PreParsedSubtables` method for better performance.
252                self.0
253                    .glyphs_hor_kerning(first.into(), second.into())
254                    .map(f32::from)
255                    .unwrap_or_default()
256            }
257
258            fn outline(&self, id: GlyphId) -> Option<Outline> {
259                let mut outliner = outliner::OutlineCurveBuilder::default();
260
261                let ttfp::Rect {
262                    x_min,
263                    x_max,
264                    y_min,
265                    y_max,
266                } = self
267                    .0
268                    .as_face_ref()
269                    .outline_glyph(id.into(), &mut outliner)
270                    // invalid bounds are treated as having no outline
271                    .filter(|b| b.x_min < b.x_max && b.y_min < b.y_max)?;
272
273                let curves = outliner.take_outline();
274
275                let bounds = Rect {
276                    min: point(x_min.into(), y_max.into()),
277                    max: point(x_max.into(), y_min.into()),
278                };
279
280                Some(Outline { bounds, curves })
281            }
282
283            #[inline]
284            fn glyph_count(&self) -> usize {
285                self.0.as_face_ref().number_of_glyphs() as _
286            }
287
288            fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
289                let face_ref = self.0.as_face_ref();
290
291                #[cfg(feature = "std")]
292                let mut used_indices =
293                    std::collections::HashSet::with_capacity(face_ref.number_of_glyphs() as _);
294                #[cfg(not(feature = "std"))]
295                let mut used_indices = alloc::collections::BTreeSet::new();
296
297                let inner = Box::new(
298                    face_ref
299                        .tables()
300                        .cmap
301                        .iter()
302                        .flat_map(|c| c.subtables)
303                        .filter(|s| s.is_unicode())
304                        .flat_map(move |subtable| {
305                            let mut pairs = Vec::new();
306                            subtable.codepoints(|c| {
307                                if let Ok(ch) = char::try_from(c) {
308                                    if let Some(idx) = subtable.glyph_index(c).filter(|i| i.0 > 0) {
309                                        if used_indices.insert(idx.0) {
310                                            pairs.push((GlyphId(idx.0), ch));
311                                        }
312                                    }
313                                }
314                            });
315                            pairs
316                        }),
317                );
318
319                crate::CodepointIdIter { inner }
320            }
321
322            fn glyph_raster_image2(&self, id: GlyphId, size: u16) -> Option<v2::GlyphImage> {
323                use GlyphImageFormat::*;
324
325                let img = self.0.as_face_ref().glyph_raster_image(id.into(), size)?;
326                Some(v2::GlyphImage {
327                    origin: point(img.x.into(), img.y.into()),
328                    width: img.width,
329                    height: img.height,
330                    pixels_per_em: img.pixels_per_em,
331                    data: img.data,
332                    format: match img.format {
333                        ttfp::RasterImageFormat::PNG => Png,
334                        ttfp::RasterImageFormat::BitmapMono => BitmapMono,
335                        ttfp::RasterImageFormat::BitmapMonoPacked => BitmapMonoPacked,
336                        ttfp::RasterImageFormat::BitmapGray2 => BitmapGray2,
337                        ttfp::RasterImageFormat::BitmapGray2Packed => BitmapGray2Packed,
338                        ttfp::RasterImageFormat::BitmapGray4 => BitmapGray4,
339                        ttfp::RasterImageFormat::BitmapGray4Packed => BitmapGray4Packed,
340                        ttfp::RasterImageFormat::BitmapGray8 => BitmapGray8,
341                        ttfp::RasterImageFormat::BitmapPremulBgra32 => BitmapPremulBgra32,
342                    },
343                })
344            }
345
346            fn glyph_svg_image(&self, id: GlyphId) -> Option<GlyphSvg> {
347                let img = self.0.as_face_ref().glyph_svg_image(id.into())?;
348
349                Some(GlyphSvg {
350                    data: img.data,
351                    start_glyph_id: GlyphId(img.start_glyph_id.0),
352                    end_glyph_id: GlyphId(img.end_glyph_id.0),
353                })
354            }
355
356            #[inline]
357            fn font_data(&self) -> &[u8] {
358                self.0.as_face_ref().raw_face().data
359            }
360        }
361    };
362}
363
364impl_font!(FontRef<'_>);
365impl_font!(FontVec);