1 | #[cfg (all(feature = "libm" , not(feature = "std" )))] |
2 | use crate::nostd_float::FloatExt; |
3 | use crate::{Font, Glyph, GlyphId, OutlinedGlyph, Rect}; |
4 | |
5 | /// Pixel scale. |
6 | /// |
7 | /// This is the pixel-height of text. |
8 | /// |
9 | /// Usually one uses `x == y`, but one may use a different ratio to stretch a |
10 | /// font horizontally or vertically. |
11 | /// |
12 | /// To convert pt size into pixel-scale see [`Font::pt_to_px_scale`]. |
13 | /// |
14 | /// # Example |
15 | /// ``` |
16 | /// use ab_glyph::PxScale; |
17 | /// |
18 | /// let uniform_scale_24px = PxScale::from(24.0); |
19 | /// ``` |
20 | #[derive (Copy, Clone, Debug, PartialEq, PartialOrd)] |
21 | pub struct PxScale { |
22 | /// Horizontal scale in pixels. |
23 | pub x: f32, |
24 | /// Vertical scale in pixels. |
25 | /// |
26 | /// By definition, this is the pixel-height of a font. |
27 | pub y: f32, |
28 | } |
29 | |
30 | impl PxScale { |
31 | /// Returns a `PxScale` with both x & y scale values set to the nearest integer. |
32 | #[inline ] |
33 | pub fn round(self) -> Self { |
34 | Self { |
35 | x: self.x.round(), |
36 | y: self.y.round(), |
37 | } |
38 | } |
39 | } |
40 | |
41 | impl From<f32> for PxScale { |
42 | /// Uniform scaling where x & y are the same. |
43 | #[inline ] |
44 | fn from(s: f32) -> Self { |
45 | PxScale { x: s, y: s } |
46 | } |
47 | } |
48 | |
49 | /// 2D scale factors for use with unscaled metrics. |
50 | #[derive (Copy, Clone, Debug, PartialEq, PartialOrd)] |
51 | pub struct PxScaleFactor { |
52 | pub horizontal: f32, |
53 | pub vertical: f32, |
54 | } |
55 | |
56 | /// A [`Font`](trait.Font.html) with an associated pixel scale. This can be used to provide |
57 | /// pixel scale values for glyph advances, heights etc. |
58 | /// |
59 | /// # Example |
60 | /// ``` |
61 | /// use ab_glyph::{Font, FontRef, PxScale, ScaleFont}; |
62 | /// |
63 | /// # fn main() -> Result<(), ab_glyph::InvalidFont> { |
64 | /// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf" ))?; |
65 | /// |
66 | /// // Associate the font with a scale of 45px |
67 | /// let scaled_font = font.as_scaled(PxScale::from(45.0)); |
68 | /// |
69 | /// assert_eq!(scaled_font.height(), 45.0); |
70 | /// assert_eq!(scaled_font.h_advance(scaled_font.glyph_id('b' )), 21.225); |
71 | /// |
72 | /// // Replace associated scale with another |
73 | /// let scaled_font = scaled_font.with_scale(180.0); |
74 | /// |
75 | /// assert_eq!(scaled_font.height(), 180.0); |
76 | /// assert_eq!(scaled_font.h_advance(scaled_font.glyph_id('b' )), 84.9); |
77 | /// # Ok(()) } |
78 | /// ``` |
79 | pub trait ScaleFont<F: Font> { |
80 | /// Returns the pixel scale associated with this font. |
81 | fn scale(&self) -> PxScale; |
82 | |
83 | /// Returns a font reference. |
84 | fn font(&self) -> &F; |
85 | |
86 | /// Scale factor for unscaled font horizontal values. |
87 | #[inline ] |
88 | fn h_scale_factor(&self) -> f32 { |
89 | self.scale().x / self.font().height_unscaled() |
90 | } |
91 | |
92 | /// Scale factor for unscaled font vertical values. |
93 | #[inline ] |
94 | fn v_scale_factor(&self) -> f32 { |
95 | self.scale().y / self.font().height_unscaled() |
96 | } |
97 | |
98 | #[inline ] |
99 | fn scale_factor(&self) -> PxScaleFactor { |
100 | PxScaleFactor { |
101 | horizontal: self.h_scale_factor(), |
102 | vertical: self.v_scale_factor(), |
103 | } |
104 | } |
105 | |
106 | /// Pixel scaled glyph ascent. |
107 | #[inline ] |
108 | fn ascent(&self) -> f32 { |
109 | self.v_scale_factor() * self.font().ascent_unscaled() |
110 | } |
111 | |
112 | /// Pixel scaled glyph descent. |
113 | #[inline ] |
114 | fn descent(&self) -> f32 { |
115 | self.v_scale_factor() * self.font().descent_unscaled() |
116 | } |
117 | |
118 | /// Pixel scaled height `ascent - descent`. |
119 | /// |
120 | /// By definition of [`PxScale`], this is `self.scale().y`. |
121 | #[inline ] |
122 | fn height(&self) -> f32 { |
123 | self.scale().y |
124 | } |
125 | |
126 | /// Pixel scaled line gap. |
127 | #[inline ] |
128 | fn line_gap(&self) -> f32 { |
129 | self.v_scale_factor() * self.font().line_gap_unscaled() |
130 | } |
131 | |
132 | /// Lookup a `GlyphId` matching a given `char`. |
133 | #[inline ] |
134 | fn glyph_id(&self, c: char) -> GlyphId { |
135 | self.font().glyph_id(c) |
136 | } |
137 | |
138 | /// Construct a [`Glyph`](struct.Glyph.html) with the font's pixel scale at |
139 | /// position `point(0.0, 0.0)`. |
140 | /// |
141 | /// # Example |
142 | /// ``` |
143 | /// # use ab_glyph::*; |
144 | /// # let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf" )).unwrap(); |
145 | /// let scaled_font = font.as_scaled(50.0); |
146 | /// |
147 | /// let a1 = scaled_font.scaled_glyph('a' ); |
148 | /// let a2 = font.glyph_id('a' ).with_scale(50.0); // equivalent |
149 | /// |
150 | /// # assert_eq!(a1.id, a2.id); |
151 | /// assert_eq!(a1.scale, PxScale::from(50.0)); |
152 | /// assert_eq!(a1.position, point(0.0, 0.0)); |
153 | /// ``` |
154 | #[inline ] |
155 | fn scaled_glyph(&self, c: char) -> Glyph { |
156 | self.font().glyph_id(c).with_scale(self.scale()) |
157 | } |
158 | |
159 | /// Pixel scaled horizontal advance for a given glyph. |
160 | #[inline ] |
161 | fn h_advance(&self, id: GlyphId) -> f32 { |
162 | self.h_scale_factor() * self.font().h_advance_unscaled(id) |
163 | } |
164 | |
165 | /// Pixel scaled horizontal side bearing for a given glyph. |
166 | #[inline ] |
167 | fn h_side_bearing(&self, id: GlyphId) -> f32 { |
168 | self.h_scale_factor() * self.font().h_side_bearing_unscaled(id) |
169 | } |
170 | |
171 | /// Pixel scaled vertical advance for a given glyph. |
172 | #[inline ] |
173 | fn v_advance(&self, id: GlyphId) -> f32 { |
174 | self.v_scale_factor() * self.font().v_advance_unscaled(id) |
175 | } |
176 | |
177 | /// Pixel scaled vertical side bearing for a given glyph. |
178 | #[inline ] |
179 | fn v_side_bearing(&self, id: GlyphId) -> f32 { |
180 | self.v_scale_factor() * self.font().v_side_bearing_unscaled(id) |
181 | } |
182 | |
183 | /// Returns additional pixel scaled kerning to apply for a particular pair of glyphs. |
184 | #[inline ] |
185 | fn kern(&self, first: GlyphId, second: GlyphId) -> f32 { |
186 | self.h_scale_factor() * self.font().kern_unscaled(first, second) |
187 | } |
188 | |
189 | /// Returns the layout bounds of this glyph. These are different to the outline `px_bounds()`. |
190 | /// |
191 | /// Horizontally: Glyph position +/- h_advance/h_side_bearing. |
192 | /// Vertically: Glyph position +/- ascent/descent. |
193 | /// |
194 | /// Note this method does not make use of the associated scale, as `Glyph` |
195 | /// already includes one of it's own. |
196 | #[inline ] |
197 | fn glyph_bounds(&self, glyph: &Glyph) -> Rect { |
198 | self.font().glyph_bounds(glyph) |
199 | } |
200 | |
201 | /// The number of glyphs present in this font. Glyph identifiers for this |
202 | /// font will always be in the range `0..self.glyph_count()` |
203 | #[inline ] |
204 | fn glyph_count(&self) -> usize { |
205 | self.font().glyph_count() |
206 | } |
207 | |
208 | /// Returns an iterator of all distinct `(GlyphId, char)` pairs. Not ordered. |
209 | /// |
210 | /// Same as [`Font::codepoint_ids`](trait.Font.html#tymethod.codepoint_ids). |
211 | fn codepoint_ids(&self) -> crate::CodepointIdIter<'_>; |
212 | |
213 | /// Compute glyph outline ready for drawing. |
214 | /// |
215 | /// Note this method does not make use of the associated scale, as `Glyph` |
216 | /// already includes one of it's own. |
217 | #[inline ] |
218 | fn outline_glyph(&self, glyph: Glyph) -> Option<OutlinedGlyph> { |
219 | self.font().outline_glyph(glyph) |
220 | } |
221 | } |
222 | |
223 | impl<F: Font, SF: ScaleFont<F>> ScaleFont<F> for &SF { |
224 | #[inline ] |
225 | fn scale(&self) -> PxScale { |
226 | (*self).scale() |
227 | } |
228 | |
229 | #[inline ] |
230 | fn font(&self) -> &F { |
231 | (*self).font() |
232 | } |
233 | |
234 | #[inline ] |
235 | fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> { |
236 | (*self).codepoint_ids() |
237 | } |
238 | } |
239 | |
240 | /// A [`Font`](trait.Font.html) and an associated pixel scale. |
241 | #[derive (Clone, Copy, Debug)] |
242 | pub struct PxScaleFont<F> { |
243 | pub font: F, |
244 | pub scale: PxScale, |
245 | } |
246 | |
247 | impl<F> PxScaleFont<F> { |
248 | #[inline ] |
249 | pub fn with_scale<S: Into<PxScale>>(mut self, scale: S) -> Self { |
250 | self.scale = scale.into(); |
251 | self |
252 | } |
253 | } |
254 | |
255 | impl<F: Font> ScaleFont<F> for PxScaleFont<F> { |
256 | #[inline ] |
257 | fn scale(&self) -> PxScale { |
258 | self.scale |
259 | } |
260 | |
261 | #[inline ] |
262 | fn font(&self) -> &F { |
263 | &self.font |
264 | } |
265 | |
266 | #[inline ] |
267 | fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> { |
268 | self.font.codepoint_ids() |
269 | } |
270 | } |
271 | |