Skip to main content

harfrust/hb/
font_funcs.rs

1use core::mem::size_of;
2use core::ptr;
3use core::slice;
4
5use read_fonts::types::F2Dot14;
6use read_fonts::types::GlyphId;
7
8use crate::hb::charmap::Charmap;
9use crate::hb::face::FontKind;
10use crate::hb::face::Scale;
11use crate::hb::glyph_metrics::GlyphMetrics;
12
13use super::buffer::{hb_buffer_t, GlyphInfo, GlyphPosition};
14use super::face::{hb_font_t, GlyphExtents};
15
16/// Raw C-style view over a batch of glyph ids and advance widths.
17#[derive(Clone, Copy, Debug)]
18pub struct RawAdvanceWidthBatch {
19    /// Number of batch entries.
20    pub len: usize,
21    /// Pointer to glyph ids (read-only).
22    pub gids: *const u32,
23    /// Pointer to horizontal advances (writable).
24    ///
25    /// See "Metrics scaling" in the [FontFuncs] for details
26    /// on what value this method should return.
27    pub advances: *mut i32,
28    /// Byte stride between successive glyph ids.
29    pub gid_stride: isize,
30    /// Byte stride between successive advances.
31    pub advance_stride: isize,
32}
33
34/// Safe batch view for glyph id / horizontal-advance updates.
35pub struct AdvanceWidthBatch<'a> {
36    infos: &'a [GlyphInfo],
37    positions: &'a mut [GlyphPosition],
38}
39
40impl<'a> AdvanceWidthBatch<'a> {
41    pub(crate) fn new(buffer: &'a mut hb_buffer_t) -> Self {
42        let len = buffer.len;
43        let infos = &buffer.info[..len];
44        let positions = &mut buffer.pos[..len];
45        Self { infos, positions }
46    }
47
48    /// Returns the number of entries in the batch.
49    pub fn len(&self) -> usize {
50        self.infos.len()
51    }
52
53    /// Returns true if the batch is empty.
54    pub fn is_empty(&self) -> bool {
55        self.infos.is_empty()
56    }
57
58    /// Returns a raw C-style view over this batch.
59    pub fn into_raw(self) -> RawAdvanceWidthBatch {
60        if self.infos.is_empty() {
61            return RawAdvanceWidthBatch {
62                len: 0,
63                gids: ptr::null(),
64                advances: ptr::null_mut(),
65                gid_stride: size_of::<GlyphInfo>() as isize,
66                advance_stride: size_of::<GlyphPosition>() as isize,
67            };
68        }
69
70        RawAdvanceWidthBatch {
71            len: self.infos.len(),
72            // `glyph_id` is the first field in `GlyphInfo`.
73            gids: self.infos.as_ptr().cast::<u32>(),
74            // `x_advance` is the first field in `GlyphPosition`.
75            advances: self.positions.as_mut_ptr().cast::<i32>(),
76            gid_stride: size_of::<GlyphInfo>() as isize,
77            advance_stride: size_of::<GlyphPosition>() as isize,
78        }
79    }
80}
81
82pub struct AdvanceWidthBatchIter<'a> {
83    infos: slice::Iter<'a, GlyphInfo>,
84    positions: slice::IterMut<'a, GlyphPosition>,
85}
86
87impl<'a> Iterator for AdvanceWidthBatchIter<'a> {
88    type Item = (GlyphId, &'a mut i32);
89
90    fn next(&mut self) -> Option<Self::Item> {
91        let info = self.infos.next()?;
92        let pos = self.positions.next()?;
93        Some((info.as_glyph(), &mut pos.x_advance))
94    }
95}
96
97impl<'a> IntoIterator for AdvanceWidthBatch<'a> {
98    type Item = (GlyphId, &'a mut i32);
99    type IntoIter = AdvanceWidthBatchIter<'a>;
100
101    fn into_iter(self) -> Self::IntoIter {
102        AdvanceWidthBatchIter {
103            infos: self.infos.iter(),
104            positions: self.positions.iter_mut(),
105        }
106    }
107}
108
109/// Default implementations backed by font tables.
110pub struct BuiltinFontFuncs<'a> {
111    face: &'a hb_font_t<'a>,
112    glyph_metrics: core::cell::OnceCell<GlyphMetrics<'a>>,
113    charmap: core::cell::OnceCell<Charmap<'a>>,
114}
115
116impl<'a> BuiltinFontFuncs<'a> {
117    pub(crate) fn new(face: &'a hb_font_t<'a>) -> Self {
118        Self {
119            face,
120            glyph_metrics: core::cell::OnceCell::new(),
121            charmap: core::cell::OnceCell::new(),
122        }
123    }
124
125    fn coords(&self) -> &[F2Dot14] {
126        self.face.ot_tables.coords
127    }
128
129    fn charmap(&self) -> &Charmap<'a> {
130        self.charmap.get_or_init(|| match &self.face.font {
131            FontKind::FontRef(font) => font.charmap.clone(),
132            FontKind::FontInstance(instance, _) => Charmap::from_tables(&instance.tables()),
133        })
134    }
135
136    fn glyph_metrics(&self) -> &GlyphMetrics<'a> {
137        self.glyph_metrics.get_or_init(|| match &self.face.font {
138            FontKind::FontRef(font) => font.glyph_metrics.clone(),
139            FontKind::FontInstance(instance, metrics) => {
140                GlyphMetrics::from_tables(&instance.tables(), metrics)
141            }
142        })
143    }
144
145    /// Maps a Unicode scalar value to a nominal glyph.
146    pub fn nominal_glyph(&self, c: u32) -> Option<GlyphId> {
147        self.charmap().map(c)
148    }
149
150    /// Maps a Unicode scalar value and variation selector to a glyph.
151    pub fn variant_glyph(&self, c: u32, vs: u32) -> Option<GlyphId> {
152        self.charmap().map_variant(c, vs)
153    }
154
155    /// Returns the horizontal advance for a glyph.
156    pub fn advance_width(&self, glyph: GlyphId) -> i32 {
157        self.glyph_metrics()
158            .advance_width(glyph, self.coords())
159            .unwrap_or_default()
160    }
161
162    /// Returns the vertical advance for a glyph.
163    pub fn advance_height(&self, glyph: GlyphId) -> i32 {
164        -self
165            .glyph_metrics()
166            .advance_height(glyph, self.coords())
167            .unwrap_or(self.face.units_per_em as i32)
168    }
169
170    /// Returns the vertical origin for a glyph.
171    pub fn vertical_origin(&self, glyph: GlyphId) -> (i32, i32) {
172        let v_origin_y = self
173            .glyph_metrics()
174            .v_origin(glyph, self.coords())
175            .unwrap_or_default();
176        (self.advance_width(glyph) / 2, v_origin_y)
177    }
178
179    /// Returns extents for a glyph if available.
180    pub fn extents(&self, glyph: GlyphId) -> Option<GlyphExtents> {
181        self.glyph_metrics().extents(glyph, self.coords())
182    }
183
184    /// Populates horizontal advances for all entries in the batch.
185    pub fn populate_advance_widths(&self, batch: AdvanceWidthBatch<'_>) {
186        for (glyph, advance) in batch {
187            *advance = self.advance_width(glyph);
188        }
189    }
190}
191
192/// Customizable font callback surface.
193///
194/// # Metrics scaling
195///
196/// All font metrics returned by these callbacks must be consistent with the
197/// scale factor configured via
198/// [`ShapeOptions::scale`](crate::ShapeOptions::scale).
199///
200/// If no scale is set, values must be in unscaled font units (i.e. the same
201/// coordinate space as the font's `units_per_em`). If a scale is set —
202/// for example `font_size * 64` for FreeType-style 26.6 — then all returned
203/// values must already be in that scaled coordinate space.
204pub trait FontFuncs {
205    /// Nominal character-to-glyph mapping callback.
206    fn nominal_glyph(&mut self, builtin: &BuiltinFontFuncs, c: u32) -> Option<GlyphId> {
207        builtin.nominal_glyph(c)
208    }
209
210    /// Variation-selector mapping callback.
211    fn variant_glyph(&mut self, builtin: &BuiltinFontFuncs, c: u32, vs: u32) -> Option<GlyphId> {
212        builtin.variant_glyph(c, vs)
213    }
214
215    /// Horizontal advance callback.
216    ///
217    /// See "Metrics scaling" in the [trait-level docs](FontFuncs) for details
218    /// on what value this method should return.
219    fn advance_width(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> i32 {
220        builtin.advance_width(glyph)
221    }
222
223    /// Batch horizontal-advance callback.
224    ///
225    /// See "Metrics scaling" in the [trait-level docs](FontFuncs) for details
226    /// on what value this method should return.
227    fn populate_advance_widths(
228        &mut self,
229        builtin: &BuiltinFontFuncs,
230        batch: AdvanceWidthBatch<'_>,
231    ) {
232        for (glyph, advance) in batch {
233            *advance = self.advance_width(builtin, glyph);
234        }
235    }
236
237    /// Vertical advance callback.
238    ///
239    /// See "Metrics scaling" in the [trait-level docs](FontFuncs) for details
240    /// on what value this method should return.
241    fn advance_height(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> i32 {
242        builtin.advance_height(glyph)
243    }
244
245    /// Vertical origin callback.
246    ///
247    /// Returns the (x, y) coordinates of the vertical origin for the given glyph.
248    ///
249    /// See "Metrics scaling" in the [trait-level docs](FontFuncs) for details
250    /// on what values this method should return.
251    fn vertical_origin(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> (i32, i32) {
252        builtin.vertical_origin(glyph)
253    }
254
255    /// Glyph extents callback.
256    ///
257    /// See "Metrics scaling" in the [trait-level docs](FontFuncs) for details
258    /// on what values this method should return.
259    fn extents(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> Option<GlyphExtents> {
260        builtin.extents(glyph)
261    }
262}
263
264pub(crate) struct FontFuncsDispatch<'a, 'u> {
265    builtin: BuiltinFontFuncs<'a>,
266    scale: Scale,
267    funcs: Option<&'u mut (dyn FontFuncs + 'u)>,
268}
269
270impl<'a, 'u> FontFuncsDispatch<'a, 'u> {
271    pub(crate) fn new(
272        face: &'a hb_font_t<'a>,
273        scale: Scale,
274        funcs: Option<&'u mut (dyn FontFuncs + 'u)>,
275    ) -> Self {
276        Self {
277            builtin: BuiltinFontFuncs::new(face),
278            scale,
279            funcs,
280        }
281    }
282
283    #[inline(always)]
284    pub(crate) fn font(&self) -> &'a hb_font_t<'a> {
285        self.builtin.face
286    }
287
288    #[inline(always)]
289    pub(crate) fn scale(&self) -> &Scale {
290        &self.scale
291    }
292
293    #[inline(always)]
294    fn scale_x(&self, value: i32) -> i32 {
295        self.scale.scale_x(value)
296    }
297
298    #[inline(always)]
299    fn scale_y(&self, value: i32) -> i32 {
300        self.scale.scale_y(value)
301    }
302
303    #[inline(always)]
304    fn scale_point(&self, point: (i32, i32)) -> (i32, i32) {
305        (self.scale_x(point.0), self.scale_y(point.1))
306    }
307
308    #[inline(always)]
309    fn scale_extents(&self, extents: GlyphExtents) -> GlyphExtents {
310        self.scale.scale_extents(extents)
311    }
312
313    #[inline(always)]
314    pub(crate) fn nominal_glyph(&mut self, c: u32) -> Option<GlyphId> {
315        if let Some(funcs) = &mut self.funcs {
316            funcs.nominal_glyph(&self.builtin, c)
317        } else if let Some(gid) = self.builtin.face.cmap_cache.get(c) {
318            Some(gid.into())
319        } else if let Some(gid) = self.builtin.nominal_glyph(c) {
320            let cache = self.builtin.face.cmap_cache;
321            cache.set(c, gid.to_u32());
322            Some(gid)
323        } else {
324            None
325        }
326    }
327
328    #[inline(always)]
329    pub(crate) fn has_glyph(&mut self, c: u32) -> bool {
330        self.nominal_glyph(c).is_some()
331    }
332
333    #[inline(always)]
334    pub(crate) fn variant_glyph(&mut self, c: u32, vs: u32) -> Option<GlyphId> {
335        if let Some(funcs) = &mut self.funcs {
336            funcs.variant_glyph(&self.builtin, c, vs)
337        } else {
338            self.builtin.variant_glyph(c, vs)
339        }
340    }
341
342    #[inline(always)]
343    pub(crate) fn advance_width(&mut self, glyph: GlyphId) -> i32 {
344        if let Some(funcs) = &mut self.funcs {
345            funcs.advance_width(&self.builtin, glyph)
346        } else {
347            self.scale_x(self.builtin.advance_width(glyph))
348        }
349    }
350
351    #[inline(always)]
352    pub(crate) fn advance_height(&mut self, glyph: GlyphId) -> i32 {
353        if let Some(funcs) = &mut self.funcs {
354            funcs.advance_height(&self.builtin, glyph)
355        } else {
356            self.scale_y(self.builtin.advance_height(glyph))
357        }
358    }
359
360    #[inline(always)]
361    pub(crate) fn vertical_origin(&mut self, glyph: GlyphId) -> (i32, i32) {
362        if let Some(funcs) = &mut self.funcs {
363            funcs.vertical_origin(&self.builtin, glyph)
364        } else {
365            self.scale_point(self.builtin.vertical_origin(glyph))
366        }
367    }
368
369    #[inline(always)]
370    pub(crate) fn extents(&mut self, glyph: GlyphId) -> Option<GlyphExtents> {
371        if let Some(funcs) = &mut self.funcs {
372            funcs.extents(&self.builtin, glyph)
373        } else {
374            Some(self.scale_extents(self.builtin.extents(glyph)?))
375        }
376    }
377
378    pub(crate) fn populate_advance_widths(&mut self, batch: AdvanceWidthBatch<'_>) {
379        if let Some(funcs) = &mut self.funcs {
380            funcs.populate_advance_widths(&self.builtin, batch);
381        } else {
382            self.builtin.glyph_metrics().populate_advance_widths(
383                batch.infos,
384                batch.positions,
385                self.builtin.coords(),
386                self.scale,
387            );
388        }
389    }
390}