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 pub major_version: uint16,
11 pub minor_version: uint16,
12}
13#[repr(C)]
14pub struct HheaV1 {
15 v1: HheaV0,
16 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 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
150impl 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}