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 use font_test_data::{be_buffer, bebuffer::BeBuffer};
45
46 #[test]
48 fn trimmed_advances() {
49 let font = FontRef::new(font_test_data::CBDT).unwrap();
50 let hmtx = font.hmtx().unwrap();
51 assert!(
52 !hmtx.left_side_bearings().is_empty(),
53 "if this fails then the test is no longer accurate"
54 );
55 let expected_lsbs = [100, 0, 100, 0];
56 for (i, lsb) in expected_lsbs.into_iter().enumerate() {
57 let gid = GlyphId::new(i as _);
58 assert_eq!(hmtx.advance(gid), Some(800));
60 assert_eq!(hmtx.side_bearing(gid), Some(lsb));
61 }
62 }
63
64 #[test]
65 fn missing_left_side_bearings() {
66 let hmtx_data = be_buffer! {
67 500u16, 50u16, 600u16, 60u16 };
70
71 let hmtx = Hmtx::read(hmtx_data.data().into(), 2).unwrap();
72
73 assert_eq!(hmtx.advance(GlyphId::new(0)), Some(500));
74 assert_eq!(hmtx.side_bearing(GlyphId::new(0)), Some(50));
75
76 assert_eq!(hmtx.advance(GlyphId::new(1)), Some(600));
77 assert_eq!(hmtx.side_bearing(GlyphId::new(1)), Some(60));
78
79 assert_eq!(hmtx.advance(GlyphId::new(2)), Some(600));
80 assert_eq!(hmtx.side_bearing(GlyphId::new(2)), None);
81
82 assert_eq!(hmtx.advance(GlyphId::new(3)), Some(600));
83 assert_eq!(hmtx.side_bearing(GlyphId::new(3)), None);
84 }
85
86 #[test]
87 fn metrics() {
88 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
89 let hmtx = font.hmtx().unwrap();
90 let expected = [(908, 100), (1336, 29), (1336, 29), (633, 57)];
91 for (i, (advance, lsb)) in expected.into_iter().enumerate() {
92 let gid = GlyphId::new(i as _);
93 assert_eq!(hmtx.advance(gid), Some(advance));
94 assert_eq!(hmtx.side_bearing(gid), Some(lsb));
95 }
96 }
97}