1use super::internal::*;
6use super::{FontRef, GlyphId, NormalizedCoord};
7
8#[derive(Copy, Clone, Default)]
10pub struct MetricsProxy {
11 units_per_em: u16,
12 glyph_count: u16,
13 is_monospace: bool,
14 has_vertical_metrics: bool,
15 ascent: i16,
16 descent: i16,
17 leading: i16,
18 vertical_ascent: i16,
19 vertical_descent: i16,
20 vertical_leading: i16,
21 cap_height: i16,
22 x_height: i16,
23 average_width: u16,
24 max_width: u16,
25 underline_offset: i16,
26 strikeout_offset: i16,
27 stroke_size: i16,
28 mvar: u32,
29 hmtx: u32,
30 hvar: u32,
31 hmtx_count: u16,
32 has_vvar: bool,
33 vertical: Vertical,
34}
35
36impl MetricsProxy {
37 pub fn from_font(font: &FontRef) -> Self {
39 let mut metadata = Self {
40 units_per_em: 1,
41 ..Self::default()
42 };
43 metadata.fill(font);
44 metadata
45 }
46
47 pub fn materialize_metrics(&self, font: &FontRef, coords: &[NormalizedCoord]) -> Metrics {
51 let data = font.data;
52 let mut m = Metrics {
53 units_per_em: self.units_per_em,
54 glyph_count: self.glyph_count,
55 is_monospace: self.is_monospace,
56 has_vertical_metrics: self.has_vertical_metrics,
57 ascent: self.ascent as f32,
58 descent: self.descent as f32,
59 leading: self.leading as f32,
60 vertical_ascent: self.vertical_ascent as f32,
61 vertical_descent: self.vertical_descent as f32,
62 vertical_leading: self.vertical_leading as f32,
63 cap_height: self.cap_height as f32,
64 x_height: self.x_height as f32,
65 average_width: self.average_width as f32,
66 max_width: self.max_width as f32,
67 underline_offset: self.underline_offset as f32,
68 strikeout_offset: self.strikeout_offset as f32,
69 stroke_size: self.stroke_size as f32,
70 };
71 if self.mvar != 0 && !coords.is_empty() {
72 if let Some(v) = var::Mvar::new(data, self.mvar, coords) {
73 use var::mvar_tags::*;
74 m.ascent += v.delta(HASC);
75 m.descent += v.delta(HDSC);
76 m.leading += v.delta(HLGP);
77 if self.has_vertical_metrics {
78 m.vertical_ascent += v.delta(VASC);
79 m.vertical_descent += v.delta(VDSC);
80 m.vertical_leading += v.delta(VLGP);
81 }
82 m.cap_height += v.delta(CPHT);
83 m.x_height += v.delta(XHGT);
84 m.underline_offset += v.delta(UNDO);
85 m.strikeout_offset += v.delta(STRO);
86 m.stroke_size += v.delta(UNDS);
87 }
88 }
89 m
90 }
91
92 pub fn materialize_glyph_metrics<'a>(
96 &self,
97 font: &FontRef<'a>,
98 coords: &'a [NormalizedCoord],
99 ) -> GlyphMetrics<'a> {
100 let data = font.data;
101 let mut vertical = self.vertical;
102 if !coords.is_empty() {
103 if let Vertical::Synthesized {
104 mvar,
105 advance,
106 origin,
107 } = &mut vertical
108 {
109 if *mvar != 0 {
110 if let Some(v) = var::Mvar::new(data, *mvar, coords) {
111 use var::mvar_tags::*;
112 let ascent_delta = v.delta(HASC);
113 let descent_delta = v.delta(HDSC);
114 *advance += ascent_delta + descent_delta;
115 *origin += ascent_delta;
116 }
117 }
118 }
119 }
120 GlyphMetrics {
121 data,
122 coords,
123 units_per_em: self.units_per_em,
124 glyph_count: self.glyph_count,
125 hmtx: self.hmtx,
126 hvar: self.hvar,
127 hmtx_count: self.hmtx_count,
128 has_vvar: self.has_vvar,
129 vertical,
130 scale: 1.,
131 }
132 }
133
134 pub fn units_per_em(&self) -> u16 {
136 self.units_per_em
137 }
138
139 pub fn glyph_count(&self) -> u16 {
141 self.glyph_count
142 }
143
144 fn fill(&mut self, font: &FontRef) -> Option<()> {
145 let head = font.head()?;
146 self.units_per_em = head.units_per_em();
147 self.glyph_count = font.maxp()?.glyph_count();
148 let mut have_line_metrics = false;
149 let os2 = font.os2();
150 if let Some(os2) = os2 {
151 let flags = os2.selection_flags();
152 self.average_width = os2.average_char_width() as u16;
153 self.strikeout_offset = os2.strikeout_position();
154 self.stroke_size = os2.strikeout_size();
155 self.x_height = os2.x_height();
156 self.cap_height = os2.cap_height();
157 if flags.use_typographic_metrics() {
158 self.ascent = os2.typographic_ascender();
159 self.descent = -os2.typographic_descender();
160 self.leading = os2.typographic_line_gap();
161 have_line_metrics = self.ascent != 0;
162 }
163 }
164 let hhea = font.hhea();
165 if let Some(hhea) = hhea {
166 self.max_width = hhea.max_advance();
167 if !have_line_metrics {
168 self.ascent = hhea.ascender();
169 self.descent = -hhea.descender();
170 self.leading = hhea.line_gap();
171 }
172 }
173 let vhea = font.vhea();
174 if let Some(vhea) = vhea {
175 self.has_vertical_metrics = true;
176 self.vertical_ascent = vhea.ascender();
177 self.vertical_descent = -vhea.descender();
178 self.vertical_leading = vhea.line_gap();
179 } else {
180 self.vertical_ascent = (self.units_per_em / 2) as i16;
181 self.vertical_descent = self.vertical_ascent;
182 }
183 if let Some(post) = font.post() {
184 self.underline_offset = post.underline_position();
185 self.stroke_size = post.underline_size();
186 self.is_monospace = post.is_fixed_pitch();
187 }
188 self.mvar = font.table_offset(var::MVAR);
189 self.hmtx_count = hhea.map(|t| t.num_long_metrics()).unwrap_or(1);
190 self.hmtx = font.table_offset(xmtx::HMTX);
191 self.hvar = font.table_offset(var::HVAR);
192 let mut vmtx = 0;
193 if vhea.is_some() {
194 vmtx = font.table_offset(xmtx::VMTX);
195 }
196 if vmtx != 0 {
197 let long_count = vhea.unwrap().num_long_metrics();
198 let vvar = font.table_offset(var::VVAR);
199 self.has_vvar = vvar != 0;
200 let vorg = font.table_offset(vorg::VORG);
201 if vorg != 0 {
202 self.vertical = Vertical::VmtxVorg {
203 long_count,
204 vmtx,
205 vvar,
206 vorg,
207 };
208 } else {
209 let glyf = font.table_offset(glyf::GLYF);
210 let loca = font.table_offset(glyf::LOCA);
211 let loca_fmt = font
212 .head()
213 .map(|t| t.index_to_location_format() as u8)
214 .unwrap_or(0xFF);
215 if glyf != 0 && loca != 0 && loca_fmt != 0xFF {
216 self.vertical = Vertical::VmtxGlyf {
217 loca_fmt,
218 long_count,
219 vmtx,
220 vvar,
221 glyf,
222 loca,
223 }
224 }
225 }
226 } else {
227 self.vertical = Vertical::Synthesized {
228 mvar: self.mvar,
229 advance: self.ascent as f32 + self.descent as f32,
230 origin: self.ascent as f32,
231 };
232 }
233 Some(())
234 }
235}
236
237#[derive(Copy, Clone, Default, Debug)]
239pub struct Metrics {
240 pub units_per_em: u16,
242 pub glyph_count: u16,
244 pub is_monospace: bool,
246 pub has_vertical_metrics: bool,
248 pub ascent: f32,
250 pub descent: f32,
252 pub leading: f32,
254 pub vertical_ascent: f32,
257 pub vertical_descent: f32,
260 pub vertical_leading: f32,
262 pub cap_height: f32,
264 pub x_height: f32,
267 pub average_width: f32,
269 pub max_width: f32,
271 pub underline_offset: f32,
274 pub strikeout_offset: f32,
277 pub stroke_size: f32,
279}
280
281impl Metrics {
282 pub(crate) fn from_font(font: &FontRef, coords: &[i16]) -> Self {
285 let meta = MetricsProxy::from_font(font);
286 meta.materialize_metrics(font, coords)
287 }
288
289 pub fn scale(&self, ppem: f32) -> Self {
292 self.linear_scale(if self.units_per_em != 0 {
293 ppem / self.units_per_em as f32
294 } else {
295 1.
296 })
297 }
298
299 pub fn linear_scale(&self, s: f32) -> Self {
301 let mut m = *self;
302 m.ascent *= s;
303 m.descent *= s;
304 m.leading *= s;
305 m.vertical_ascent *= s;
306 m.vertical_descent *= s;
307 m.vertical_leading *= s;
308 m.cap_height *= s;
309 m.x_height *= s;
310 m.average_width *= s;
311 m.max_width *= s;
312 m.underline_offset *= s;
313 m.strikeout_offset *= s;
314 m.stroke_size *= s;
315 m
316 }
317}
318
319#[derive(Copy, Clone)]
321pub struct GlyphMetrics<'a> {
322 data: &'a [u8],
323 coords: &'a [i16],
324 units_per_em: u16,
325 glyph_count: u16,
326 hmtx: u32,
327 hvar: u32,
328 hmtx_count: u16,
329 has_vvar: bool,
330 vertical: Vertical,
331 scale: f32,
332}
333
334impl<'a> GlyphMetrics<'a> {
335 pub(crate) fn from_font(font: &FontRef<'a>, coords: &'a [NormalizedCoord]) -> Self {
338 let proxy = MetricsProxy::from_font(font);
339 proxy.materialize_glyph_metrics(font, coords)
340 }
341
342 pub fn units_per_em(&self) -> u16 {
344 self.units_per_em
345 }
346
347 pub fn glyph_count(&self) -> u16 {
349 self.glyph_count
350 }
351
352 pub fn has_vertical_metrics(&self) -> bool {
354 !matches!(self.vertical, Vertical::Synthesized { .. })
355 }
356
357 pub fn has_variations(&self) -> bool {
359 self.hvar != 0 || self.has_vvar
360 }
361
362 pub fn scale(&self, ppem: f32) -> Self {
365 self.linear_scale(if self.units_per_em() != 0 {
366 ppem / self.units_per_em() as f32
367 } else {
368 1.
369 })
370 }
371
372 pub fn linear_scale(&self, scale: f32) -> Self {
374 let mut copy = *self;
375 copy.scale = scale;
376 copy
377 }
378
379 pub fn advance_width(&self, glyph_id: GlyphId) -> f32 {
381 let mut v = xmtx::advance(self.data, self.hmtx, self.hmtx_count, glyph_id) as f32;
382 if self.hvar != 0 {
383 v += var::advance_delta(self.data, self.hvar, glyph_id, self.coords);
384 }
385 v * self.scale
386 }
387
388 pub fn lsb(&self, glyph_id: GlyphId) -> f32 {
390 let mut v = xmtx::sb(self.data, self.hmtx, self.hmtx_count, glyph_id) as f32;
391 if self.hvar != 0 {
392 v += var::sb_delta(self.data, self.hvar, glyph_id, self.coords);
393 }
394 v * self.scale
395 }
396
397 pub fn advance_height(&self, glyph_id: GlyphId) -> f32 {
399 self.scale
400 * match self.vertical {
401 Vertical::VmtxGlyf {
402 vmtx,
403 vvar,
404 long_count,
405 ..
406 }
407 | Vertical::VmtxVorg {
408 vmtx,
409 vvar,
410 long_count,
411 ..
412 } => {
413 let mut v = xmtx::advance(self.data, vmtx, long_count, glyph_id) as f32;
414 if vvar != 0 {
415 v += var::advance_delta(self.data, vvar, glyph_id, self.coords);
416 }
417 v
418 }
419 Vertical::Synthesized { advance, .. } => advance,
420 }
421 }
422
423 pub fn tsb(&self, glyph_id: GlyphId) -> f32 {
425 self.scale
426 * match self.vertical {
427 Vertical::VmtxGlyf {
428 vmtx,
429 vvar,
430 long_count,
431 ..
432 }
433 | Vertical::VmtxVorg {
434 vmtx,
435 vvar,
436 long_count,
437 ..
438 } => {
439 let mut v = xmtx::sb(self.data, vmtx, long_count, glyph_id) as f32;
440 if vvar != 0 {
441 v += var::sb_delta(self.data, vvar, glyph_id, self.coords);
442 }
443 v
444 }
445 Vertical::Synthesized { .. } => 0.,
446 }
447 }
448
449 pub fn vertical_origin(&self, glyph_id: GlyphId) -> f32 {
451 self.scale
452 * match self.vertical {
453 Vertical::VmtxGlyf {
454 loca_fmt,
455 loca,
456 glyf,
457 ..
458 } => {
459 if let Some(max_y) = glyf::ymax(self.data, loca_fmt, loca, glyf, glyph_id) {
460 max_y as f32 + self.tsb(glyph_id)
461 } else {
462 self.units_per_em as f32
463 }
464 }
465 Vertical::VmtxVorg { vorg, .. } => vorg::origin(self.data, vorg, glyph_id)
466 .unwrap_or(self.units_per_em as i16)
467 as f32,
468 Vertical::Synthesized { origin, .. } => origin,
469 }
470 }
471}
472
473#[derive(Copy, Clone)]
474#[repr(u8)]
475enum Vertical {
476 VmtxGlyf {
477 loca_fmt: u8,
478 long_count: u16,
479 vmtx: u32,
480 vvar: u32,
481 glyf: u32,
482 loca: u32,
483 },
484 VmtxVorg {
485 long_count: u16,
486 vmtx: u32,
487 vvar: u32,
488 vorg: u32,
489 },
490 Synthesized {
491 mvar: u32,
492 advance: f32,
493 origin: f32,
494 },
495}
496
497impl Default for Vertical {
498 fn default() -> Self {
499 Self::Synthesized {
500 mvar: 0,
501 advance: 0.,
502 origin: 0.,
503 }
504 }
505}