kas_text/fonts/
face.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Font face types
7
8use crate::conv::{LineMetrics, DPU};
9use crate::GlyphId;
10use ttf_parser::Face;
11
12/// Handle to a loaded font face
13#[derive(Copy, Clone, Debug)]
14pub struct FaceRef<'a>(pub(crate) &'a Face<'a>);
15
16impl<'a> FaceRef<'a> {
17    /// Get glyph identifier for a char
18    ///
19    /// If the char is not found, `GlyphId(0)` is returned (the 'missing glyph'
20    /// representation).
21    #[inline]
22    pub fn glyph_index(&self, c: char) -> GlyphId {
23        // GlyphId 0 is required to be a special glyph representing a missing
24        // character (see cmap table / TrueType specification).
25        GlyphId(self.0.glyph_index(c).map(|id| id.0).unwrap_or(0))
26    }
27
28    /// Convert `dpem` to `dpu`
29    ///
30    /// Output: a font-specific scale.
31    ///
32    /// Input: `dpem` is pixels/em
33    ///
34    /// ```none
35    /// dpem
36    ///   = pt_size × dpp
37    ///   = pt_size × dpi / 72
38    ///   = pt_size × scale_factor × (96 / 72)
39    /// ```
40    #[inline]
41    pub fn dpu(self, dpem: f32) -> DPU {
42        DPU(dpem / f32::from(self.0.units_per_em()))
43    }
44
45    /// Get a scaled reference
46    ///
47    /// Units: `dpem` is dots (pixels) per Em (module documentation).
48    #[inline]
49    pub fn scale_by_dpem(self, dpem: f32) -> ScaledFaceRef<'a> {
50        ScaledFaceRef(self.0, self.dpu(dpem))
51    }
52
53    /// Get a scaled reference
54    ///
55    /// Units: `dpu` is dots (pixels) per font-unit (see module documentation).
56    #[inline]
57    pub fn scale_by_dpu(self, dpu: DPU) -> ScaledFaceRef<'a> {
58        ScaledFaceRef(self.0, dpu)
59    }
60}
61
62/// Handle to a loaded font face
63///
64/// TODO: verify whether these values need adjustment for variations.
65#[derive(Copy, Clone, Debug)]
66pub struct ScaledFaceRef<'a>(&'a Face<'a>, DPU);
67impl<'a> ScaledFaceRef<'a> {
68    /// Unscaled face
69    #[inline]
70    pub fn face(&self) -> FaceRef<'_> {
71        FaceRef(self.0)
72    }
73
74    /// Scale
75    #[inline]
76    pub fn dpu(&self) -> DPU {
77        self.1
78    }
79
80    /// Horizontal advancement after this glyph, without shaping or kerning
81    #[inline]
82    pub fn h_advance(&self, id: GlyphId) -> f32 {
83        let x = self.0.glyph_hor_advance(id.into()).unwrap();
84        self.1.u16_to_px(x)
85    }
86
87    /// Horizontal side bearing
88    ///
89    /// If unspecified by the font this resolves to 0.
90    #[inline]
91    pub fn h_side_bearing(&self, id: GlyphId) -> f32 {
92        let x = self.0.glyph_hor_side_bearing(id.into()).unwrap_or(0);
93        self.1.i16_to_px(x)
94    }
95
96    /// Ascender
97    #[inline]
98    pub fn ascent(&self) -> f32 {
99        self.1.i16_to_px(self.0.ascender())
100    }
101
102    /// Descender
103    #[inline]
104    pub fn descent(&self) -> f32 {
105        self.1.i16_to_px(self.0.descender())
106    }
107
108    /// Line gap
109    #[inline]
110    pub fn line_gap(&self) -> f32 {
111        self.1.i16_to_px(self.0.line_gap())
112    }
113
114    /// Line height
115    #[inline]
116    pub fn height(&self) -> f32 {
117        self.1.i16_to_px(self.0.height())
118    }
119
120    /// Metrics for underline
121    #[inline]
122    pub fn underline_metrics(&self) -> Option<LineMetrics> {
123        self.0
124            .underline_metrics()
125            .map(|m| self.1.to_line_metrics(m))
126    }
127
128    /// Metrics for strike-through
129    #[inline]
130    pub fn strikethrough_metrics(&self) -> Option<LineMetrics> {
131        self.0
132            .strikeout_metrics()
133            .map(|m| self.1.to_line_metrics(m))
134    }
135}