Skip to main content

ttf_view/tables/
hhea.rs

1use crate::{
2    tables::{Table, TableDirectory, TableError},
3    types::{FWORD, Tag, UFWORD, int16, tags, uint16},
4};
5
6#[repr(C)]
7pub struct HheaV0 {
8    _exhaustive_but_dont_instantiate: (),
9    // version any:
10    pub major_version: uint16,
11    pub minor_version: uint16,
12}
13#[repr(C)]
14pub struct HheaV1 {
15    v1: HheaV0,
16    // version = 1.x:
17    pub ascender: FWORD,
18    pub descender: FWORD,
19    pub line_gap: FWORD,
20    pub advance_width_max: UFWORD,
21    pub min_left_side_bearing: FWORD,
22    pub min_right_side_bearing: FWORD,
23    pub x_max_extent: FWORD,
24    pub caret_slope_rise: int16,
25    pub caret_slope_run: int16,
26    pub caret_offset: int16,
27    pub reserved0: int16,
28    pub reserved1: int16,
29    pub reserved2: int16,
30    pub reserved3: int16,
31    pub metric_data_format: int16,
32    pub number_of_h_metrics: uint16,
33}
34
35const impl std::ops::Deref for HheaV1 {
36    type Target = HheaV0;
37    fn deref(&self) -> &Self::Target {
38        &self.v1
39    }
40}
41
42impl<'a> Table<'a> for Hhea<'a> {
43    const TAG: Tag = tags::hhea;
44    fn new_in(dir: &'a TableDirectory) -> Result<Self, TableError> {
45        let rec = dir.table_record(Self::TAG).ok_or(TableError::NotFound)?;
46        let v0 = rec.raw_as::<HheaV0>().ok_or(TableError::InvalidLen)?;
47
48        let required_len = match v0.major_version.get() {
49            0 => size_of::<HheaV0>() as u32,
50            1 => size_of::<HheaV1>() as u32,
51            _ => return Err(TableError::UnknownVersion),
52        };
53        if rec.length.get() < required_len {
54            return Err(TableError::InvalidLen);
55        }
56
57        Ok(Self { hhea: v0 })
58    }
59}
60
61#[derive(Copy)]
62#[derive_const(Clone)]
63pub struct Hhea<'a> {
64    hhea: &'a HheaV0,
65}
66
67const impl<'a> std::ops::Deref for Hhea<'a> {
68    type Target = &'a HheaV0;
69    fn deref(&self) -> &Self::Target {
70        &self.hhea
71    }
72}
73
74impl<'a> Hhea<'a> {
75    pub const fn v1(&self) -> Option<&'a HheaV1> {
76        if self.major_version.get() == 1 {
77            Some(unsafe { std::mem::transmute::<&HheaV0, &HheaV1>(self.hhea) })
78        } else {
79            None
80        }
81    }
82
83    // version = 1.x:
84    pub const fn ascender(&self) -> Option<FWORD> {
85        Some(self.v1()?.ascender)
86    }
87    pub const fn descender(&self) -> Option<FWORD> {
88        Some(self.v1()?.descender)
89    }
90    pub const fn line_gap(&self) -> Option<FWORD> {
91        Some(self.v1()?.line_gap)
92    }
93    pub const fn advance_width_max(&self) -> Option<UFWORD> {
94        Some(self.v1()?.advance_width_max)
95    }
96    pub const fn min_left_side_bearing(&self) -> Option<FWORD> {
97        Some(self.v1()?.min_left_side_bearing)
98    }
99    pub const fn min_right_side_bearing(&self) -> Option<FWORD> {
100        Some(self.v1()?.min_right_side_bearing)
101    }
102    pub const fn x_max_extent(&self) -> Option<FWORD> {
103        Some(self.v1()?.x_max_extent)
104    }
105    pub const fn caret_slope_rise(&self) -> Option<int16> {
106        Some(self.v1()?.caret_slope_rise)
107    }
108    pub const fn caret_slope_run(&self) -> Option<int16> {
109        Some(self.v1()?.caret_slope_run)
110    }
111    pub const fn caret_offset(&self) -> Option<int16> {
112        Some(self.v1()?.caret_offset)
113    }
114    pub const fn metric_data_format(&self) -> Option<int16> {
115        Some(self.v1()?.metric_data_format)
116    }
117    pub const fn number_of_h_metrics(&self) -> Option<uint16> {
118        Some(self.v1()?.number_of_h_metrics)
119    }
120}
121
122impl std::fmt::Debug for Hhea<'_> {
123    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
124        let mut f = f.debug_struct("HheaTable");
125        f.field("major_version", &self.major_version.get())
126            .field("minor_version", &self.minor_version.get());
127
128        if let Some(v1) = self.v1() {
129            f.field("ascender", &v1.ascender.get());
130            f.field("descender", &v1.descender.get());
131            f.field("line_gap", &v1.line_gap.get());
132            f.field("advance_width_max", &v1.advance_width_max.get());
133            f.field("min_left_side_bearing", &v1.min_left_side_bearing.get());
134            f.field("min_right_side_bearing", &v1.min_right_side_bearing.get());
135            f.field("x_max_extent", &v1.x_max_extent.get());
136            f.field("caret_slope_rise", &v1.caret_slope_rise.get());
137            f.field("caret_slope_run", &v1.caret_slope_run.get());
138            f.field("caret_offset", &v1.caret_offset.get());
139            f.field("reserved0", &v1.reserved0.get());
140            f.field("reserved1", &v1.reserved1.get());
141            f.field("reserved2", &v1.reserved2.get());
142            f.field("reserved3", &v1.reserved3.get());
143            f.field("metric_data_format", &v1.metric_data_format.get());
144            f.field("number_of_h_metrics", &v1.number_of_h_metrics.get());
145        }
146        f.finish()
147    }
148}
149
150// Monomorphize all fmts to the above fmt for Hhea<'a>
151impl std::fmt::Debug for HheaV0 {
152    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
153        Hhea { hhea: self }.fmt(f)
154    }
155}
156impl std::fmt::Debug for HheaV1 {
157    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
158        Hhea { hhea: self }.fmt(f)
159    }
160}