rusttype/font.rs
1use crate::{Glyph, GlyphIter, IntoGlyphId, LayoutIter, Point, Scale, VMetrics};
2#[cfg(not(feature = "has-atomics"))]
3use alloc::rc::Rc as Arc;
4#[cfg(feature = "has-atomics")]
5use alloc::sync::Arc;
6#[cfg(not(feature = "std"))]
7use alloc::vec::Vec;
8use core::fmt;
9
10/// A single font. This may or may not own the font data.
11///
12/// # Lifetime
13/// The lifetime reflects the font data lifetime. `Font<'static>` covers most
14/// cases ie both dynamically loaded owned data and for referenced compile time
15/// font data.
16///
17/// # Example
18///
19/// ```
20/// # use rusttype::Font;
21/// # fn example() -> Option<()> {
22/// let font_data: &[u8] = include_bytes!("../dev/fonts/dejavu/DejaVuSansMono.ttf");
23/// let font: Font<'static> = Font::try_from_bytes(font_data)?;
24///
25/// let owned_font_data: Vec<u8> = font_data.to_vec();
26/// let from_owned_font: Font<'static> = Font::try_from_vec(owned_font_data)?;
27/// # Some(())
28/// # }
29/// ```
30#[derive(Clone)]
31pub enum Font<'a> {
32 Ref(Arc<owned_ttf_parser::Face<'a>>),
33 Owned(Arc<owned_ttf_parser::OwnedFace>),
34}
35
36impl fmt::Debug for Font<'_> {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(f, "Font")
39 }
40}
41
42impl Font<'_> {
43 /// Creates a Font from byte-slice data.
44 ///
45 /// Returns `None` for invalid data.
46 pub fn try_from_bytes(bytes: &[u8]) -> Option<Font<'_>> {
47 Self::try_from_bytes_and_index(bytes, 0)
48 }
49
50 /// Creates a Font from byte-slice data & a font collection `index`.
51 ///
52 /// Returns `None` for invalid data.
53 pub fn try_from_bytes_and_index(bytes: &[u8], index: u32) -> Option<Font<'_>> {
54 let inner = Arc::new(owned_ttf_parser::Face::from_slice(bytes, index).ok()?);
55 Some(Font::Ref(inner))
56 }
57
58 /// Creates a Font from owned font data.
59 ///
60 /// Returns `None` for invalid data.
61 pub fn try_from_vec(data: Vec<u8>) -> Option<Font<'static>> {
62 Self::try_from_vec_and_index(data, 0)
63 }
64
65 /// Creates a Font from owned font data & a font collection `index`.
66 ///
67 /// Returns `None` for invalid data.
68 pub fn try_from_vec_and_index(data: Vec<u8>, index: u32) -> Option<Font<'static>> {
69 let inner = Arc::new(owned_ttf_parser::OwnedFace::from_vec(data, index).ok()?);
70 Some(Font::Owned(inner))
71 }
72}
73
74impl<'font> Font<'font> {
75 #[inline]
76 pub(crate) fn inner(&self) -> &owned_ttf_parser::Face<'_> {
77 use owned_ttf_parser::AsFaceRef;
78 match self {
79 Self::Ref(f) => f,
80 Self::Owned(f) => f.as_face_ref(),
81 }
82 }
83
84 /// The "vertical metrics" for this font at a given scale. These metrics are
85 /// shared by all of the glyphs in the font. See `VMetrics` for more detail.
86 pub fn v_metrics(&self, scale: Scale) -> VMetrics {
87 self.v_metrics_unscaled() * self.scale_for_pixel_height(scale.y)
88 }
89
90 /// Get the unscaled VMetrics for this font, shared by all glyphs.
91 /// See `VMetrics` for more detail.
92 pub fn v_metrics_unscaled(&self) -> VMetrics {
93 let font = self.inner();
94 VMetrics {
95 ascent: font.ascender() as f32,
96 descent: font.descender() as f32,
97 line_gap: font.line_gap() as f32,
98 }
99 }
100
101 /// Returns the units per EM square of this font
102 pub fn units_per_em(&self) -> u16 {
103 self.inner().units_per_em()
104 }
105
106 /// The number of glyphs present in this font. Glyph identifiers for this
107 /// font will always be in the range `0..self.glyph_count()`
108 pub fn glyph_count(&self) -> usize {
109 self.inner().number_of_glyphs() as _
110 }
111
112 /// Returns the corresponding glyph for a Unicode code point or a glyph id
113 /// for this font.
114 ///
115 /// If `id` is a `GlyphId`, it must be valid for this font; otherwise, this
116 /// function panics. `GlyphId`s should always be produced by looking up some
117 /// other sort of designator (like a Unicode code point) in a font, and
118 /// should only be used to index the font they were produced for.
119 ///
120 /// Note that code points without corresponding glyphs in this font map to
121 /// the ".notdef" glyph, glyph 0.
122 pub fn glyph<C: IntoGlyphId>(&self, id: C) -> Glyph<'font> {
123 let gid = id.into_glyph_id(self);
124 assert!((gid.0 as usize) < self.glyph_count());
125 // font clone either a reference clone, or arc clone
126 Glyph {
127 font: self.clone(),
128 id: gid,
129 }
130 }
131
132 /// A convenience function.
133 ///
134 /// Returns an iterator that produces the glyphs corresponding to the code
135 /// points or glyph ids produced by the given iterator `itr`.
136 ///
137 /// This is equivalent in behaviour to `itr.map(|c| font.glyph(c))`.
138 pub fn glyphs_for<'a, I: Iterator>(&'a self, itr: I) -> GlyphIter<'a, 'font, I>
139 where
140 I::Item: IntoGlyphId,
141 {
142 GlyphIter { font: self, itr }
143 }
144
145 /// A convenience function for laying out glyphs for a string horizontally.
146 /// It does not take control characters like line breaks into account, as
147 /// treatment of these is likely to depend on the application.
148 ///
149 /// Note that this function does not perform Unicode normalisation.
150 /// Composite characters (such as ö constructed from two code points, ¨ and
151 /// o), will not be normalised to single code points. So if a font does not
152 /// contain a glyph for each separate code point, but does contain one for
153 /// the normalised single code point (which is common), the desired glyph
154 /// will not be produced, despite being present in the font. Deal with this
155 /// by performing Unicode normalisation on the input string before passing
156 /// it to `layout`. The crate
157 /// [unicode-normalization](http://crates.io/crates/unicode-normalization)
158 /// is perfect for this purpose.
159 ///
160 /// Calling this function is equivalent to a longer sequence of operations
161 /// involving `glyphs_for`, e.g.
162 ///
163 /// ```no_run
164 /// # use rusttype::*;
165 /// # let (scale, start) = (Scale::uniform(0.0), point(0.0, 0.0));
166 /// # let font: Font = unimplemented!();
167 /// font.layout("Hello World!", scale, start)
168 /// # ;
169 /// ```
170 ///
171 /// produces an iterator with behaviour equivalent to the following:
172 ///
173 /// ```no_run
174 /// # use rusttype::*;
175 /// # let (scale, start) = (Scale::uniform(0.0), point(0.0, 0.0));
176 /// # let font: Font = unimplemented!();
177 /// font.glyphs_for("Hello World!".chars())
178 /// .scan((None, 0.0), |(last, x), g| {
179 /// let g = g.scaled(scale);
180 /// if let Some(last) = last {
181 /// *x += font.pair_kerning(scale, *last, g.id());
182 /// }
183 /// let w = g.h_metrics().advance_width;
184 /// let next = g.positioned(start + vector(*x, 0.0));
185 /// *last = Some(next.id());
186 /// *x += w;
187 /// Some(next)
188 /// })
189 /// # ;
190 /// ```
191 pub fn layout<'a, 's>(
192 &'a self,
193 s: &'s str,
194 scale: Scale,
195 start: Point<f32>,
196 ) -> LayoutIter<'a, 'font, 's> {
197 LayoutIter {
198 font: self,
199 chars: s.chars(),
200 caret: 0.0,
201 scale,
202 start,
203 last_glyph: None,
204 }
205 }
206
207 /// Returns additional kerning to apply as well as that given by HMetrics
208 /// for a particular pair of glyphs.
209 pub fn pair_kerning<A, B>(&self, scale: Scale, first: A, second: B) -> f32
210 where
211 A: IntoGlyphId,
212 B: IntoGlyphId,
213 {
214 let first_id = first.into_glyph_id(self).into();
215 let second_id = second.into_glyph_id(self).into();
216
217 let factor = {
218 let hscale = self.scale_for_pixel_height(scale.y);
219 hscale * (scale.x / scale.y)
220 };
221
222 let kern = if let Some(kern) = self.inner().tables().kern {
223 kern.subtables
224 .into_iter()
225 .filter(|st| st.horizontal && !st.variable)
226 .find_map(|st| st.glyphs_kerning(first_id, second_id))
227 .unwrap_or(0)
228 } else {
229 0
230 };
231
232 factor * f32::from(kern)
233 }
234
235 /// Computes a scale factor to produce a font whose "height" is 'pixels'
236 /// tall. Height is measured as the distance from the highest ascender
237 /// to the lowest descender; in other words, it's equivalent to calling
238 /// GetFontVMetrics and computing:
239 /// scale = pixels / (ascent - descent)
240 /// so if you prefer to measure height by the ascent only, use a similar
241 /// calculation.
242 pub fn scale_for_pixel_height(&self, height: f32) -> f32 {
243 let inner = self.inner();
244 let fheight = f32::from(inner.ascender()) - f32::from(inner.descender());
245 height / fheight
246 }
247}