1#![allow(non_camel_case_types)]
2use crate::{
3 tables::{Table, TableDirectory, TableError},
4 types::{FWORD, Tag, UFWORD, int16, tags, uint16, uint32},
5};
6
7mod code_pages;
8mod panose;
9mod unicode_ranges;
10
11pub use code_pages::*;
12pub use panose::*;
13pub use unicode_ranges::*;
14
15#[repr(C)]
16pub struct Os_2Base {
17 _exhaustive_but_dont_instantiate: (),
18 pub version: uint16,
20 pub x_avg_char_width: FWORD,
21 pub us_weight_class: uint16,
22 pub us_width_class: uint16,
23 pub fs_type: uint16,
24 pub y_subscript_x_size: FWORD,
25 pub y_subscript_y_size: FWORD,
26 pub y_subscript_x_offset: FWORD,
27 pub y_subscript_y_offset: FWORD,
28 pub y_superscript_x_size: FWORD,
29 pub y_superscript_y_size: FWORD,
30 pub y_superscript_x_offset: FWORD,
31 pub y_superscript_y_offset: FWORD,
32 pub y_strikeout_size: FWORD,
33 pub y_strikeout_position: FWORD,
34 pub s_family_class: int16,
35 pub panose: Panose,
36 pub ul_unicode_range_1: uint32,
37 pub ul_unicode_range_2: uint32,
38 pub ul_unicode_range_3: uint32,
39 pub ul_unicode_range_4: uint32,
40 pub ach_vend_id: Tag,
41 pub fs_selection: uint16,
42 pub us_first_char_index: uint16,
43 pub us_last_char_index: uint16,
44}
45#[repr(C)]
46pub struct Os_2V0 {
47 base: Os_2Base,
48 pub s_typo_ascender: FWORD,
53 pub s_typo_descender: FWORD,
54 pub s_typo_line_gap: FWORD,
55 pub us_win_ascent: UFWORD,
56 pub us_win_descent: UFWORD,
57}
58#[repr(C)]
59pub struct Os_2V1 {
60 v0: Os_2V0,
61 pub ul_code_page_range_1: uint32,
63 pub ul_code_page_range_2: uint32,
64}
65#[repr(C)]
66pub struct Os_2V4 {
67 v1: Os_2V1,
68 pub sx_height: FWORD,
70 pub s_cap_height: FWORD,
71 pub us_default_char: uint16,
72 pub us_break_char: uint16,
73 pub us_max_content: uint16,
74}
75#[repr(C)]
76pub struct Os_2V5 {
77 v4: Os_2V4,
78 pub us_lower_optical_point_size: uint16,
80 pub us_upper_optical_point_size: uint16,
81}
82
83const impl std::ops::Deref for Os_2V0 {
84 type Target = Os_2Base;
85 fn deref(&self) -> &Self::Target {
86 &self.base
87 }
88}
89const impl std::ops::Deref for Os_2V1 {
90 type Target = Os_2V0;
91 fn deref(&self) -> &Self::Target {
92 &self.v0
93 }
94}
95const impl std::ops::Deref for Os_2V4 {
96 type Target = Os_2V1;
97 fn deref(&self) -> &Self::Target {
98 &self.v1
99 }
100}
101const impl std::ops::Deref for Os_2V5 {
102 type Target = Os_2V4;
103 fn deref(&self) -> &Self::Target {
104 &self.v4
105 }
106}
107
108impl<'a> Table<'a> for Os_2<'a> {
109 const TAG: Tag = tags::OS_2;
110 fn new_in(dir: &'a TableDirectory) -> Result<Self, TableError> {
111 let rec = dir.table_record(tags::OS_2).ok_or(TableError::NotFound)?;
112 let base = rec.raw_as::<Os_2Base>().ok_or(TableError::InvalidLen)?;
113
114 let required_len = match base.version.get() {
115 0 => size_of::<Os_2Base>() as u32,
116 1..=3 => size_of::<Os_2V1>() as u32,
117 4 => size_of::<Os_2V4>() as u32,
118 5.. => size_of::<Os_2V5>() as u32,
119 };
120 if rec.length.get() < required_len {
121 return Err(TableError::InvalidLen);
122 }
123
124 Ok(Self { base, len: rec.length.get() })
125 }
126}
127
128#[derive(Copy)]
129#[derive_const(Clone)]
130pub struct Os_2<'a> {
131 base: &'a Os_2Base,
132 len: u32,
133}
134
135const impl<'a> std::ops::Deref for Os_2<'a> {
136 type Target = &'a Os_2Base;
137 fn deref(&self) -> &Self::Target {
138 &self.base
139 }
140}
141
142impl<'a> Os_2<'a> {
143 pub const fn v0(&self) -> Option<&'a Os_2V0> {
144 const V0_SIZE: u32 = size_of::<Os_2V0>() as u32;
145 if self.len >= V0_SIZE {
146 Some(unsafe { std::mem::transmute::<&Os_2Base, &Os_2V0>(self.base) })
147 } else {
148 None
149 }
150 }
151 pub const fn v1(&self) -> Option<&'a Os_2V1> {
152 if self.version.get() >= 1 {
153 Some(unsafe { std::mem::transmute::<&Os_2Base, &Os_2V1>(self.base) })
154 } else {
155 None
156 }
157 }
158 pub const fn v4(&self) -> Option<&'a Os_2V4> {
159 if self.version.get() >= 4 {
160 Some(unsafe { std::mem::transmute::<&Os_2Base, &Os_2V4>(self.base) })
161 } else {
162 None
163 }
164 }
165 pub const fn v5(&self) -> Option<&'a Os_2V5> {
166 if self.version.get() >= 5 {
167 Some(unsafe { std::mem::transmute::<&Os_2Base, &Os_2V5>(self.base) })
168 } else {
169 None
170 }
171 }
172
173 pub const fn unicode_range(&self) -> UnicodeRanges {
175 UnicodeRanges::from_parts(
176 self.ul_unicode_range_1.get(),
177 self.ul_unicode_range_2.get(),
178 self.ul_unicode_range_3.get(),
179 self.ul_unicode_range_4.get(),
180 )
181 }
182
183 pub const fn s_typo_ascender(&self) -> Option<FWORD> {
185 Some(self.v0()?.s_typo_ascender)
186 }
187 pub const fn s_typo_descender(&self) -> Option<FWORD> {
188 Some(self.v0()?.s_typo_descender)
189 }
190 pub const fn s_typo_line_gap(&self) -> Option<FWORD> {
191 Some(self.v0()?.s_typo_line_gap)
192 }
193 pub const fn us_win_ascent(&self) -> Option<UFWORD> {
194 Some(self.v0()?.us_win_ascent)
195 }
196 pub const fn us_win_descent(&self) -> Option<UFWORD> {
197 Some(self.v0()?.us_win_descent)
198 }
199
200 pub const fn ul_code_page_range_1(&self) -> Option<uint32> {
202 Some(self.v1()?.ul_code_page_range_1)
203 }
204 pub const fn ul_code_page_range_2(&self) -> Option<uint32> {
205 Some(self.v1()?.ul_code_page_range_2)
206 }
207 pub const fn code_page_range(&self) -> Option<CodePages> {
208 let v1 = self.v1()?;
209 Some(CodePages::from_parts(v1.ul_code_page_range_1.get(), v1.ul_code_page_range_2.get()))
210 }
211
212 pub const fn sx_height(&self) -> Option<FWORD> {
214 Some(self.v4()?.sx_height)
215 }
216 pub const fn s_cap_height(&self) -> Option<FWORD> {
217 Some(self.v4()?.s_cap_height)
218 }
219 pub const fn us_default_char(&self) -> Option<uint16> {
220 Some(self.v4()?.us_default_char)
221 }
222 pub const fn us_break_char(&self) -> Option<uint16> {
223 Some(self.v4()?.us_break_char)
224 }
225 pub const fn us_max_content(&self) -> Option<uint16> {
226 Some(self.v4()?.us_max_content)
227 }
228
229 pub const fn us_lower_optical_point_size(&self) -> Option<uint16> {
231 Some(self.v5()?.us_lower_optical_point_size)
232 }
233 pub const fn us_upper_optical_point_size(&self) -> Option<uint16> {
234 Some(self.v5()?.us_upper_optical_point_size)
235 }
236}
237
238impl std::fmt::Debug for Os_2<'_> {
239 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
240 let mut f = f.debug_struct("OS/2");
241
242 f.field("version", &self.version.get())
243 .field("x_avg_char_width", &self.x_avg_char_width.get())
244 .field("us_weight_class", &self.us_weight_class.get())
245 .field("us_width_class", &self.us_width_class.get())
246 .field_with("fs_type", |f| write!(f, "{:#010b}", self.fs_type))
247 .field("y_subscript_x_size", &self.y_subscript_x_size.get())
249 .field("y_subscript_y_size", &self.y_subscript_y_size.get())
250 .field("y_subscript_x_offset", &self.y_subscript_x_offset.get())
251 .field("y_subscript_y_offset", &self.y_subscript_y_offset.get())
252 .field("y_superscript_x_size", &self.y_superscript_x_size.get())
253 .field("y_superscript_y_size", &self.y_superscript_y_size.get())
254 .field("y_superscript_x_offset", &self.y_superscript_x_offset.get())
255 .field("y_superscript_y_offset", &self.y_superscript_y_offset.get())
256 .field("y_strikeout_size", &self.y_strikeout_size.get())
258 .field("y_strikeout_position", &self.y_strikeout_position.get())
259 .field("s_family_class", &self.s_family_class.get())
260 .field("panose", &self.panose)
261 .field("ul_unicode_range_1", &self.ul_unicode_range_1.get())
263 .field("ul_unicode_range_2", &self.ul_unicode_range_2.get())
264 .field("ul_unicode_range_3", &self.ul_unicode_range_3.get())
265 .field("ul_unicode_range_4", &self.ul_unicode_range_4.get())
266 .field("ach_vend_id", &self.ach_vend_id)
267 .field("fs_selection", &self.fs_selection.get())
268 .field("us_first_char_index", &self.us_first_char_index.get())
269 .field("us_last_char_index", &self.us_last_char_index.get());
270
271 if let Some(v0) = self.v0() {
272 f.field("s_typo_ascender", &v0.s_typo_ascender.get())
274 .field("s_typo_descender", &v0.s_typo_descender.get())
275 .field("s_typo_line_gap", &v0.s_typo_line_gap.get())
276 .field("us_win_ascent", &v0.us_win_ascent.get())
277 .field("us_win_descent", &v0.us_win_descent.get());
278 }
279 if let Some(v1) = self.v1() {
280 f.field("ul_code_page_range_1", &v1.ul_code_page_range_1.get())
282 .field("ul_code_page_range_2", &v1.ul_code_page_range_2.get());
283 }
284 if let Some(v4) = self.v4() {
285 f.field("sx_height", &v4.sx_height.get())
286 .field("s_cap_height", &v4.s_cap_height.get())
287 .field("us_default_char", &v4.us_default_char.get())
289 .field("us_break_char", &v4.us_break_char.get())
290 .field("us_max_content", &v4.us_max_content.get());
291 }
292 if let Some(v5) = self.v5() {
293 f.field("us_lower_optical_point_size", &v5.us_lower_optical_point_size.get())
294 .field("us_upper_optical_point_size", &v5.us_upper_optical_point_size.get());
295 }
296
297 f.finish()
298 }
299}
300
301impl std::fmt::Debug for Os_2Base {
303 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
304 Os_2 { base: self, len: size_of_val(self) as u32 }.fmt(f)
305 }
306}
307impl std::fmt::Debug for Os_2V0 {
308 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
309 Os_2 { base: self, len: size_of_val(self) as u32 }.fmt(f)
310 }
311}
312impl std::fmt::Debug for Os_2V1 {
313 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
314 Os_2 { base: self, len: size_of_val(self) as u32 }.fmt(f)
315 }
316}
317impl std::fmt::Debug for Os_2V4 {
318 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
319 Os_2 { base: self, len: size_of_val(self) as u32 }.fmt(f)
320 }
321}
322impl std::fmt::Debug for Os_2V5 {
323 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
324 Os_2 { base: self, len: size_of_val(self) as u32 }.fmt(f)
325 }
326}