read_fonts/tables/
hmtx.rs1include!("../../generated/generated_hmtx.rs");
4
5impl Hmtx<'_> {
6 pub fn advance(&self, glyph_id: GlyphId) -> Option<u16> {
8 advance(self.h_metrics(), glyph_id)
9 }
10
11 pub fn side_bearing(&self, glyph_id: GlyphId) -> Option<i16> {
13 side_bearing(self.h_metrics(), self.left_side_bearings(), glyph_id)
14 }
15}
16
17pub(super) fn advance(metrics: &[LongMetric], glyph_id: GlyphId) -> Option<u16> {
18 metrics
19 .get(glyph_id.to_u32() as usize)
20 .or_else(|| metrics.last())
21 .map(|metric| metric.advance())
22}
23
24pub(super) fn side_bearing(
25 metrics: &[LongMetric],
26 side_bearings: &[BigEndian<i16>],
27 glyph_id: GlyphId,
28) -> Option<i16> {
29 let ix = glyph_id.to_u32() as usize;
30 metrics
31 .get(ix)
32 .map(|metric| metric.side_bearing())
33 .or_else(|| {
34 side_bearings
35 .get(ix.saturating_sub(metrics.len()))
36 .map(|sb| sb.get())
37 })
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::{FontRef, TableProvider};
44
45 #[test]
47 fn trimmed_advances() {
48 let font = FontRef::new(font_test_data::CBDT).unwrap();
49 let hmtx = font.hmtx().unwrap();
50 assert!(
51 !hmtx.left_side_bearings().is_empty(),
52 "if this fails then the test is no longer accurate"
53 );
54 let expected_lsbs = [100, 0, 100, 0];
55 for (i, lsb) in expected_lsbs.into_iter().enumerate() {
56 let gid = GlyphId::new(i as _);
57 assert_eq!(hmtx.advance(gid), Some(800));
59 assert_eq!(hmtx.side_bearing(gid), Some(lsb));
60 }
61 }
62
63 #[test]
64 fn metrics() {
65 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
66 let hmtx = font.hmtx().unwrap();
67 let expected = [(908, 100), (1336, 29), (1336, 29), (633, 57)];
68 for (i, (advance, lsb)) in expected.into_iter().enumerate() {
69 let gid = GlyphId::new(i as _);
70 assert_eq!(hmtx.advance(gid), Some(advance));
71 assert_eq!(hmtx.side_bearing(gid), Some(lsb));
72 }
73 }
74}