1use crate::{
2 hb::{
3 face::{BasicFontMetrics, Scale},
4 tables::TableRanges,
5 },
6 GlyphExtents, GlyphInfo, GlyphPosition, Tag,
7};
8use read_fonts::{
9 tables::{
10 glyf::Glyf,
11 gvar::Gvar,
12 hmtx::{Hmtx, LongMetric},
13 hvar::Hvar,
14 loca::Loca,
15 mvar::Mvar,
16 vmtx::Vmtx,
17 vorg::Vorg,
18 vvar::Vvar,
19 },
20 types::{BoundingBox, F2Dot14, Fixed, GlyphId, Point},
21 FontRef, TableProvider,
22};
23
24#[derive(Clone)]
25pub struct GlyphMetrics<'a> {
26 _hmtx: Option<Hmtx<'a>>,
27 h_metrics: &'a [LongMetric],
28 hvar: Option<Hvar<'a>>,
29 vmtx: Option<Vmtx<'a>>,
30 vvar: Option<Vvar<'a>>,
31 vorg: Option<Vorg<'a>>,
32 glyf: Option<GlyfTables<'a>>,
33 mvar: Option<Mvar<'a>>,
34 num_glyphs: u32,
35 upem: u16,
36 ascent: i16,
37 descent: i16,
38}
39
40#[derive(Clone)]
41struct GlyfTables<'a> {
42 loca: Loca<'a>,
43 glyf: Glyf<'a>,
44 gvar: Option<Gvar<'a>>,
45}
46
47impl<'a> GlyphMetrics<'a> {
48 pub(crate) fn new(font: &FontRef<'a>, table_ranges: &TableRanges) -> Self {
49 let num_glyphs = table_ranges.num_glyphs;
50 let upem = table_ranges.units_per_em;
51 let hmtx = table_ranges
52 .hmtx
53 .resolve_data(font)
54 .and_then(|data| Hmtx::read(data, table_ranges.num_h_metrics).ok());
55 let h_metrics = hmtx
56 .as_ref()
57 .map(|hmtx| hmtx.h_metrics())
58 .unwrap_or_default();
59 let hvar = table_ranges.hvar.resolve_table(font);
60 let vmtx = table_ranges
61 .vmtx
62 .resolve_data(font)
63 .and_then(|data| Vmtx::read(data, table_ranges.num_v_metrics).ok());
64 let vvar = table_ranges.vvar.resolve_table(font);
65 let vorg = table_ranges.vorg.resolve_table(font);
66 let loca = table_ranges
67 .loca
68 .resolve_data(font)
69 .and_then(|data| Loca::read(data, table_ranges.loca_long).ok());
70 let glyf = table_ranges.glyf.resolve_table(font);
71 let glyf = if let Some((loca, glyf)) = loca.zip(glyf) {
72 let gvar = table_ranges.gvar.resolve_table(font);
73 Some(GlyfTables { loca, glyf, gvar })
74 } else {
75 None
76 };
77 let mvar = table_ranges.mvar.resolve_table(font);
78 let ascent = table_ranges.ascent;
79 let descent = table_ranges.descent;
80 Self {
81 _hmtx: hmtx,
82 h_metrics,
83 hvar,
84 vmtx,
85 vvar,
86 vorg,
87 glyf,
88 mvar,
89 num_glyphs,
90 upem,
91 ascent,
92 descent,
93 }
94 }
95
96 pub(crate) fn from_tables(font: &impl TableProvider<'a>, metrics: &BasicFontMetrics) -> Self {
97 let hmtx = font.hmtx().ok();
98 let h_metrics = hmtx
99 .as_ref()
100 .map(|hmtx| hmtx.h_metrics())
101 .unwrap_or_default();
102 let hvar = font.hvar().ok();
103 let vmtx = font.vmtx().ok();
104 let vvar = font.vvar().ok();
105 let vorg = font.vorg().ok();
106 let loca = font.loca(None).ok();
107 let glyf = font.glyf().ok();
108 let glyf = if let Some((loca, glyf)) = loca.zip(glyf) {
109 let gvar = font.gvar().ok();
110 Some(GlyfTables { loca, glyf, gvar })
111 } else {
112 None
113 };
114 let mvar = font.mvar().ok();
115 Self {
116 _hmtx: hmtx,
117 h_metrics,
118 hvar,
119 vmtx,
120 vvar,
121 vorg,
122 glyf,
123 mvar,
124 num_glyphs: metrics.num_glyphs,
125 upem: metrics.units_per_em,
126 ascent: metrics.ascent,
127 descent: metrics.descent,
128 }
129 }
130
131 pub(crate) fn advance_width(&self, gid: impl Into<GlyphId>, coords: &[F2Dot14]) -> Option<i32> {
132 let gid = gid.into();
133 let Some(mut advance) = self
134 .h_metrics
135 .get(gid.to_u32() as usize)
136 .or_else(|| self.h_metrics.last())
137 .map(|metric| metric.advance() as i32)
138 else {
139 return (gid.to_u32() < self.num_glyphs).then_some(self.upem as i32 / 2);
140 };
141 if !coords.is_empty() {
142 if let Some(hvar) = self.hvar.as_ref() {
143 advance += hvar
144 .advance_width_delta(gid, coords)
145 .unwrap_or_default()
146 .to_i32();
147 } else if let Some(deltas) = self.phantom_deltas(gid, coords) {
148 advance += deltas[1].x.to_i32() - deltas[0].x.to_i32();
149 }
150 }
151 Some(advance)
152 }
153
154 pub(crate) fn populate_advance_widths(
155 &self,
156 infos: &[GlyphInfo],
157 pos: &mut [GlyphPosition],
158 coords: &[F2Dot14],
159 scale: Scale,
160 ) {
161 for (info, pos) in infos.iter().zip(pos.iter_mut()) {
162 pos.x_advance = self
163 .h_metrics
164 .get(info.glyph_id as usize)
165 .or_else(|| self.h_metrics.last())
166 .map(|metric| metric.advance() as i32)
167 .or_else(|| (info.glyph_id < self.num_glyphs).then_some(self.upem as i32 / 2))
168 .unwrap_or_default();
169 }
170 if !coords.is_empty() {
171 if let Some(hvar) = self.hvar.as_ref() {
172 for (info, pos) in infos.iter().zip(pos.iter_mut()) {
173 pos.x_advance += hvar
174 .advance_width_delta(info.as_glyph(), coords)
175 .unwrap_or_default()
176 .to_i32();
177 }
178 } else {
179 for (info, pos) in infos.iter().zip(pos.iter_mut()) {
180 if let Some(deltas) = self.phantom_deltas(info.as_glyph(), coords) {
181 pos.x_advance += deltas[1].x.to_i32() - deltas[0].x.to_i32();
182 }
183 }
184 }
185 }
186 for pos in pos.iter_mut() {
187 pos.x_advance = scale.scale_x(pos.x_advance);
188 }
189 }
190
191 pub(crate) fn _left_side_bearing(
192 &self,
193 gid: impl Into<GlyphId>,
194 coords: &[F2Dot14],
195 ) -> Option<i32> {
196 let gid = gid.into();
197 let mut bearing = if let Some(hmtx) = self._hmtx.as_ref() {
198 hmtx.side_bearing(gid).unwrap_or_default() as i32
199 } else if let Some(extents) = self.bounds(gid, coords) {
200 return Some(extents.x_min);
201 } else {
202 return None;
203 };
204 if !coords.is_empty() {
205 if let Some(hvar) = self.hvar.as_ref() {
206 bearing += hvar.lsb_delta(gid, coords).unwrap_or_default().to_i32();
207 } else if let Some(deltas) = self.phantom_deltas(gid, coords) {
208 bearing += deltas[0].x.to_i32();
209 }
210 }
211 Some(bearing)
212 }
213
214 pub(crate) fn advance_height(
215 &self,
216 gid: impl Into<GlyphId>,
217 coords: &[F2Dot14],
218 ) -> Option<i32> {
219 let gid = gid.into();
220 let Some(mut advance) = self
221 .vmtx
222 .as_ref()
223 .and_then(|vmtx| vmtx.advance(gid))
224 .map(|advance| advance as i32)
225 else {
226 return Some(self.ascent as i32 - self.descent as i32);
227 };
228 if !coords.is_empty() {
229 if let Some(vvar) = self.vvar.as_ref() {
230 advance += vvar
231 .advance_height_delta(gid, coords)
232 .unwrap_or_default()
233 .to_i32();
234 } else if let Some(deltas) = self.phantom_deltas(gid, coords) {
235 advance += deltas[3].y.to_i32() - deltas[2].y.to_i32();
236 }
237 }
238 Some(advance)
239 }
240
241 pub(crate) fn top_side_bearing(
242 &self,
243 gid: impl Into<GlyphId>,
244 coords: &[F2Dot14],
245 ) -> Option<i32> {
246 let gid = gid.into();
247 let mut bearing = if let Some(vmtx) = self.vmtx.as_ref() {
248 vmtx.side_bearing(gid).unwrap_or_default() as i32
249 } else {
250 return None;
251 };
252 if !coords.is_empty() {
253 if let Some(vvar) = self.vvar.as_ref() {
254 bearing += vvar.tsb_delta(gid, coords).unwrap_or_default().to_i32();
255 } else if let Some(deltas) = self.phantom_deltas(gid, coords) {
256 bearing += deltas[3].y.to_i32();
257 }
258 }
259 Some(bearing)
260 }
261
262 pub(crate) fn v_origin(&self, gid: impl Into<GlyphId>, coords: &[F2Dot14]) -> Option<i32> {
263 let gid = gid.into();
264 let origin = if let Some(vorg) = self.vorg.as_ref() {
265 let mut origin = vorg.vertical_origin_y(gid) as i32;
266 if !coords.is_empty() {
267 if let Some(vvar) = self.vvar.as_ref() {
268 origin += vvar.v_org_delta(gid, coords).unwrap_or_default().to_i32();
269 }
270 }
271 origin
272 } else if let Some(extents) = self.bounds(gid, coords) {
273 let origin = if self.vmtx.is_some() {
274 let mut origin = Some(extents.y_max);
275 let tsb = self.top_side_bearing(gid, coords);
276 if let Some(tsb) = tsb {
277 origin = Some(origin.unwrap() + tsb);
278 } else {
279 origin = None;
280 }
281 if origin.is_some() && !coords.is_empty() {
282 if let Some(vvar) = self.vvar.as_ref() {
283 origin = Some(
284 origin.unwrap()
285 + vvar.v_org_delta(gid, coords).unwrap_or_default().to_i32(),
286 );
287 }
288 }
289 origin
290 } else {
291 None
292 };
293
294 if let Some(origin) = origin {
295 origin
296 } else {
297 let mut advance = self.ascent as i32 - self.descent as i32;
298 if let Some(mvar) = self.mvar.as_ref() {
299 advance += mvar
300 .metric_delta(Tag::new(b"hasc"), coords)
301 .unwrap_or_default()
302 .to_i32()
303 - mvar
304 .metric_delta(Tag::new(b"hdsc"), coords)
305 .unwrap_or_default()
306 .to_i32();
307 }
308 let diff = advance - (extents.y_max - extents.y_min);
309 extents.y_max + (diff >> 1)
310 }
311 } else {
312 let mut ascent = self.ascent as i32;
313 if let Some(mvar) = self.mvar.as_ref() {
314 ascent += mvar
315 .metric_delta(Tag::new(b"hasc"), coords)
316 .unwrap_or_default()
317 .to_i32();
318 }
319 ascent
320 };
321 Some(origin)
322 }
323
324 fn bounds(&self, gid: impl Into<GlyphId>, coords: &[F2Dot14]) -> Option<BoundingBox<i32>> {
325 let gid = gid.into();
326 let glyf = self.glyf.as_ref()?;
327 let glyph = glyf.loca.get_glyf(gid, &glyf.glyf).ok()?;
328 let Some(glyph) = glyph else {
329 return Some(BoundingBox::default());
331 };
332 if !coords.is_empty() {
333 return None; }
335 Some(BoundingBox {
336 x_min: glyph.x_min() as i32,
337 y_min: glyph.y_min() as i32,
338 x_max: glyph.x_max() as i32,
339 y_max: glyph.y_max() as i32,
340 })
341 }
342
343 pub(crate) fn extents(
344 &self,
345 gid: impl Into<GlyphId>,
346 coords: &[F2Dot14],
347 ) -> Option<GlyphExtents> {
348 let gid = gid.into();
349 let glyf = self.glyf.as_ref()?;
350 let glyph = glyf.loca.get_glyf(gid, &glyf.glyf).ok()?;
351 let Some(glyph) = glyph else {
352 return Some(GlyphExtents::default());
354 };
355 if !coords.is_empty() {
356 return None; }
358 Some(GlyphExtents {
359 x_bearing: glyph.x_min() as i32,
360 y_bearing: glyph.y_max() as i32,
361 width: glyph.x_max() as i32 - glyph.x_min() as i32,
362 height: glyph.y_min() as i32 - glyph.y_max() as i32,
363 })
364 }
365
366 fn phantom_deltas(&self, gid: GlyphId, coords: &[F2Dot14]) -> Option<[Point<Fixed>; 4]> {
367 let glyf = self.glyf.as_ref()?;
368 let gvar = glyf.gvar.as_ref()?;
369 gvar.phantom_point_deltas(&glyf.glyf, &glyf.loca, coords, gid)
370 .ok()?
371 }
372}