1use ab_glyph::InvalidFont;
4use ab_glyph::{Font as AbFont, FontRef, FontVec, ScaleFont};
5use fey_color::GreyAlpha8;
6use fey_grid::GridMut;
7use fey_img::{Image, Pixel};
8use fey_math::{Vec2, vec2};
9use std::io::BufRead;
10use std::path::Path;
11use thiserror::Error;
12
13#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
15pub struct GlyphId(u16);
16
17impl GlyphId {
18 pub const NUL: Self = Self(0);
19}
20
21#[derive(Debug)]
22enum FontData<'a> {
23 Ref(FontRef<'a>),
24 Vec(FontVec),
25}
26
27#[derive(Debug)]
29pub struct Font<'a> {
30 font: FontData<'a>,
31 size: f32,
32 pt_size: f32,
33}
34
35impl<'a> Font<'a> {
36 pub fn from_slice(data: &'a [u8], size: f32) -> Result<Self, FontError> {
38 let font = FontRef::try_from_slice(data)?;
39 let pt_size = (font.height_unscaled() * size) / font.units_per_em().unwrap();
40 Ok(Self {
41 font: FontData::Ref(font),
42 size,
43 pt_size,
44 })
45 }
46
47 pub fn from_vec(data: Vec<u8>, size: f32) -> Result<Self, FontError> {
49 let font = FontVec::try_from_vec(data)?;
50 let pt_size = (font.height_unscaled() * size) / font.units_per_em().unwrap();
51 Ok(Self {
52 font: FontData::Vec(font),
53 size,
54 pt_size,
55 })
56 }
57
58 pub fn from_read<R: BufRead>(mut r: R, size: f32) -> Result<Self, FontError> {
60 let mut data = Vec::new();
61 _ = r.read_to_end(&mut data)?;
62 Self::from_vec(data, size)
63 }
64
65 pub fn from_file<P: AsRef<Path>>(path: P, size: f32) -> Result<Self, FontError> {
67 let data = std::fs::read(path)?;
68 Self::from_vec(data, size)
69 }
70
71 pub const fn size(&self) -> f32 {
73 self.size
74 }
75
76 #[inline]
78 pub fn ascent(&self) -> f32 {
79 match &self.font {
80 FontData::Ref(f) => f.as_scaled(self.pt_size).ascent(),
81 FontData::Vec(f) => f.as_scaled(self.pt_size).ascent(),
82 }
83 }
84
85 #[inline]
87 pub fn descent(&self) -> f32 {
88 match &self.font {
89 FontData::Ref(f) => f.as_scaled(self.pt_size).descent(),
90 FontData::Vec(f) => f.as_scaled(self.pt_size).descent(),
91 }
92 }
93
94 #[inline]
96 pub fn height(&self) -> f32 {
97 self.ascent() - self.descent()
98 }
99
100 #[inline]
102 pub fn line_gap(&self) -> f32 {
103 match &self.font {
104 FontData::Ref(f) => f.as_scaled(self.pt_size).line_gap(),
105 FontData::Vec(f) => f.as_scaled(self.pt_size).line_gap(),
106 }
107 }
108
109 #[inline]
111 pub fn glyph_count(&self) -> usize {
112 match &self.font {
113 FontData::Ref(f) => f.glyph_count(),
114 FontData::Vec(f) => f.glyph_count(),
115 }
116 }
117
118 #[inline]
120 pub fn char_id(&self, chr: char) -> GlyphId {
121 GlyphId(match &self.font {
122 FontData::Ref(f) => f.glyph_id(chr).0,
123 FontData::Vec(f) => f.glyph_id(chr).0,
124 })
125 }
126
127 #[inline]
129 pub fn glyph_ids(&self) -> impl Iterator<Item = GlyphId> {
130 (0..(self.glyph_count() as u16)).map(GlyphId)
131 }
132
133 #[inline]
135 pub fn glyph_chars(&self) -> Vec<(GlyphId, char)> {
136 match &self.font {
137 FontData::Ref(f) => f
138 .codepoint_ids()
139 .map(|(id, chr)| (GlyphId(id.0), chr))
140 .collect(),
141 FontData::Vec(f) => f
142 .codepoint_ids()
143 .map(|(id, chr)| (GlyphId(id.0), chr))
144 .collect(),
145 }
146 }
147
148 #[inline]
150 pub fn glyph(&self, id: GlyphId) -> Glyph<'_> {
151 let glyph = ab_glyph::GlyphId(id.0).with_scale(self.pt_size);
152 Glyph { font: self, glyph }
153 }
154
155 #[inline]
157 pub fn char_glyph(&self, chr: char) -> Glyph<'_> {
158 self.glyph(self.char_id(chr))
159 }
160
161 #[inline]
164 pub fn kerning(&self, left: GlyphId, right: GlyphId) -> f32 {
165 let [left, right] = [left, right].map(|id| ab_glyph::GlyphId(id.0));
166 match &self.font {
167 FontData::Ref(f) => f.as_scaled(self.pt_size).kern(left, right),
168 FontData::Vec(f) => f.as_scaled(self.pt_size).kern(left, right),
169 }
170 }
171
172 #[inline]
175 pub fn char_kerning(&self, left: char, right: char) -> f32 {
176 self.kerning(self.char_id(left), self.char_id(right))
177 }
178}
179
180#[derive(Debug)]
182pub struct Glyph<'a> {
183 font: &'a Font<'a>,
184 glyph: ab_glyph::Glyph,
185}
186
187impl Glyph<'_> {
188 #[inline]
190 pub fn id(&self) -> GlyphId {
191 GlyphId(self.glyph.id.0)
192 }
193
194 #[inline]
196 pub fn advance(&self) -> f32 {
197 let id = self.glyph.id;
198 match &self.font.font {
199 FontData::Ref(f) => f.as_scaled(self.font.pt_size).h_advance(id),
200 FontData::Vec(f) => f.as_scaled(self.font.pt_size).h_advance(id),
201 }
202 }
203
204 #[inline]
206 pub fn left_side_bearing(&self) -> f32 {
207 let id = self.glyph.id;
208 match &self.font.font {
209 FontData::Ref(f) => f.as_scaled(self.font.pt_size).h_side_bearing(id),
210 FontData::Vec(f) => f.as_scaled(self.font.pt_size).h_side_bearing(id),
211 }
212 }
213
214 pub fn rasterize<P: Pixel, F: FnMut(f32) -> P>(&self, mut f: F) -> Option<RasterizedGlyph<P>> {
216 let outlined = match &self.font.font {
217 FontData::Ref(f) => f
218 .as_scaled(self.font.pt_size)
219 .outline_glyph(self.glyph.clone()),
220 FontData::Vec(f) => f
221 .as_scaled(self.font.pt_size)
222 .outline_glyph(self.glyph.clone()),
223 }?;
224 let bounds = outlined.px_bounds();
225 let w = bounds.width().ceil() as u32;
226 let h = bounds.height().ceil() as u32;
227 let mut image = Image::new_vec((w, h), P::default());
228 outlined.draw(|x, y, a| {
229 image.set(x, y, f(a));
230 });
231 Some(RasterizedGlyph {
232 image,
233 offset: vec2(bounds.min.x, -bounds.min.y),
234 })
235 }
236
237 #[inline]
240 pub fn rasterize_pixelated(&self) -> Option<RasterizedGlyph<GreyAlpha8>> {
241 self.rasterize(|a| {
242 if a > 0.5 {
243 GreyAlpha8::WHITE
244 } else {
245 GreyAlpha8::TRANSPARENT
246 }
247 })
248 }
249
250 #[inline]
252 pub fn rasterize_smooth(&self) -> Option<RasterizedGlyph<GreyAlpha8>> {
253 self.rasterize(|a| {
255 let a = (a * 255.0) as u8;
256 GreyAlpha8::new(a, a)
257 })
258 }
259}
260
261#[derive(Debug, Clone)]
263pub struct RasterizedGlyph<P: Pixel> {
264 pub image: Image<P>,
265 pub offset: Vec2<f32>,
266}
267
268#[derive(Debug, Error)]
269pub enum FontError {
270 #[error("{0}")]
271 Invalid(#[from] InvalidFont),
272
273 #[error("{0}")]
274 Io(#[from] std::io::Error),
275}