1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8pub use read_fonts::tables::os2::SelectionFlags;
9
10impl FontWrite for SelectionFlags {
11 fn write_into(&self, writer: &mut TableWriter) {
12 writer.write_slice(&self.bits().to_be_bytes())
13 }
14}
15
16#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct Os2 {
20 pub x_avg_char_width: i16,
25 pub us_weight_class: u16,
30 pub us_width_class: u16,
35 pub fs_type: u16,
39 pub y_subscript_x_size: i16,
42 pub y_subscript_y_size: i16,
45 pub y_subscript_x_offset: i16,
48 pub y_subscript_y_offset: i16,
51 pub y_superscript_x_size: i16,
54 pub y_superscript_y_size: i16,
57 pub y_superscript_x_offset: i16,
60 pub y_superscript_y_offset: i16,
63 pub y_strikeout_size: i16,
65 pub y_strikeout_position: i16,
68 pub s_family_class: i16,
71 pub panose_10: [u8; 10],
76 pub ul_unicode_range_1: u32,
80 pub ul_unicode_range_2: u32,
82 pub ul_unicode_range_3: u32,
84 pub ul_unicode_range_4: u32,
86 pub ach_vend_id: Tag,
90 pub fs_selection: SelectionFlags,
94 pub us_first_char_index: u16,
96 pub us_last_char_index: u16,
98 pub s_typo_ascender: i16,
100 pub s_typo_descender: i16,
102 pub s_typo_line_gap: i16,
104 pub us_win_ascent: u16,
109 pub us_win_descent: u16,
114 pub ul_code_page_range_1: Option<u32>,
116 pub ul_code_page_range_2: Option<u32>,
118 pub sx_height: Option<i16>,
122 pub s_cap_height: Option<i16>,
125 pub us_default_char: Option<u16>,
128 pub us_break_char: Option<u16>,
131 pub us_max_context: Option<u16>,
133 pub us_lower_optical_point_size: Option<u16>,
135 pub us_upper_optical_point_size: Option<u16>,
137}
138
139impl Default for Os2 {
140 fn default() -> Self {
141 Self {
142 x_avg_char_width: Default::default(),
143 us_weight_class: 400,
144 us_width_class: 5,
145 fs_type: Default::default(),
146 y_subscript_x_size: Default::default(),
147 y_subscript_y_size: Default::default(),
148 y_subscript_x_offset: Default::default(),
149 y_subscript_y_offset: Default::default(),
150 y_superscript_x_size: Default::default(),
151 y_superscript_y_size: Default::default(),
152 y_superscript_x_offset: Default::default(),
153 y_superscript_y_offset: Default::default(),
154 y_strikeout_size: Default::default(),
155 y_strikeout_position: Default::default(),
156 s_family_class: Default::default(),
157 panose_10: Default::default(),
158 ul_unicode_range_1: Default::default(),
159 ul_unicode_range_2: Default::default(),
160 ul_unicode_range_3: Default::default(),
161 ul_unicode_range_4: Default::default(),
162 ach_vend_id: Default::default(),
163 fs_selection: Default::default(),
164 us_first_char_index: Default::default(),
165 us_last_char_index: Default::default(),
166 s_typo_ascender: Default::default(),
167 s_typo_descender: Default::default(),
168 s_typo_line_gap: Default::default(),
169 us_win_ascent: Default::default(),
170 us_win_descent: Default::default(),
171 ul_code_page_range_1: Default::default(),
172 ul_code_page_range_2: Default::default(),
173 sx_height: Default::default(),
174 s_cap_height: Default::default(),
175 us_default_char: Default::default(),
176 us_break_char: Default::default(),
177 us_max_context: Default::default(),
178 us_lower_optical_point_size: Default::default(),
179 us_upper_optical_point_size: Default::default(),
180 }
181 }
182}
183
184impl FontWrite for Os2 {
185 #[allow(clippy::unnecessary_cast)]
186 fn write_into(&self, writer: &mut TableWriter) {
187 let version = self.compute_version() as u16;
188 version.write_into(writer);
189 self.x_avg_char_width.write_into(writer);
190 self.us_weight_class.write_into(writer);
191 self.us_width_class.write_into(writer);
192 self.fs_type.write_into(writer);
193 self.y_subscript_x_size.write_into(writer);
194 self.y_subscript_y_size.write_into(writer);
195 self.y_subscript_x_offset.write_into(writer);
196 self.y_subscript_y_offset.write_into(writer);
197 self.y_superscript_x_size.write_into(writer);
198 self.y_superscript_y_size.write_into(writer);
199 self.y_superscript_x_offset.write_into(writer);
200 self.y_superscript_y_offset.write_into(writer);
201 self.y_strikeout_size.write_into(writer);
202 self.y_strikeout_position.write_into(writer);
203 self.s_family_class.write_into(writer);
204 self.panose_10.write_into(writer);
205 self.ul_unicode_range_1.write_into(writer);
206 self.ul_unicode_range_2.write_into(writer);
207 self.ul_unicode_range_3.write_into(writer);
208 self.ul_unicode_range_4.write_into(writer);
209 self.ach_vend_id.write_into(writer);
210 self.fs_selection.write_into(writer);
211 self.us_first_char_index.write_into(writer);
212 self.us_last_char_index.write_into(writer);
213 self.s_typo_ascender.write_into(writer);
214 self.s_typo_descender.write_into(writer);
215 self.s_typo_line_gap.write_into(writer);
216 self.us_win_ascent.write_into(writer);
217 self.us_win_descent.write_into(writer);
218 version.compatible(1u16).then(|| {
219 self.ul_code_page_range_1
220 .as_ref()
221 .expect("missing conditional field should have failed validation")
222 .write_into(writer)
223 });
224 version.compatible(1u16).then(|| {
225 self.ul_code_page_range_2
226 .as_ref()
227 .expect("missing conditional field should have failed validation")
228 .write_into(writer)
229 });
230 version.compatible(2u16).then(|| {
231 self.sx_height
232 .as_ref()
233 .expect("missing conditional field should have failed validation")
234 .write_into(writer)
235 });
236 version.compatible(2u16).then(|| {
237 self.s_cap_height
238 .as_ref()
239 .expect("missing conditional field should have failed validation")
240 .write_into(writer)
241 });
242 version.compatible(2u16).then(|| {
243 self.us_default_char
244 .as_ref()
245 .expect("missing conditional field should have failed validation")
246 .write_into(writer)
247 });
248 version.compatible(2u16).then(|| {
249 self.us_break_char
250 .as_ref()
251 .expect("missing conditional field should have failed validation")
252 .write_into(writer)
253 });
254 version.compatible(2u16).then(|| {
255 self.us_max_context
256 .as_ref()
257 .expect("missing conditional field should have failed validation")
258 .write_into(writer)
259 });
260 version.compatible(5u16).then(|| {
261 self.us_lower_optical_point_size
262 .as_ref()
263 .expect("missing conditional field should have failed validation")
264 .write_into(writer)
265 });
266 version.compatible(5u16).then(|| {
267 self.us_upper_optical_point_size
268 .as_ref()
269 .expect("missing conditional field should have failed validation")
270 .write_into(writer)
271 });
272 }
273 fn table_type(&self) -> TableType {
274 TableType::TopLevel(Os2::TAG)
275 }
276}
277
278impl Validate for Os2 {
279 fn validate_impl(&self, ctx: &mut ValidationCtx) {
280 ctx.in_table("Os2", |ctx| {
281 let version: u16 = self.compute_version();
282 ctx.in_field("ul_code_page_range_1", |ctx| {
283 if version.compatible(1u16) && self.ul_code_page_range_1.is_none() {
284 ctx.report(format!("field must be present for version {version}"));
285 }
286 });
287 ctx.in_field("ul_code_page_range_2", |ctx| {
288 if version.compatible(1u16) && self.ul_code_page_range_2.is_none() {
289 ctx.report(format!("field must be present for version {version}"));
290 }
291 });
292 ctx.in_field("sx_height", |ctx| {
293 if version.compatible(2u16) && self.sx_height.is_none() {
294 ctx.report(format!("field must be present for version {version}"));
295 }
296 });
297 ctx.in_field("s_cap_height", |ctx| {
298 if version.compatible(2u16) && self.s_cap_height.is_none() {
299 ctx.report(format!("field must be present for version {version}"));
300 }
301 });
302 ctx.in_field("us_default_char", |ctx| {
303 if version.compatible(2u16) && self.us_default_char.is_none() {
304 ctx.report(format!("field must be present for version {version}"));
305 }
306 });
307 ctx.in_field("us_break_char", |ctx| {
308 if version.compatible(2u16) && self.us_break_char.is_none() {
309 ctx.report(format!("field must be present for version {version}"));
310 }
311 });
312 ctx.in_field("us_max_context", |ctx| {
313 if version.compatible(2u16) && self.us_max_context.is_none() {
314 ctx.report(format!("field must be present for version {version}"));
315 }
316 });
317 ctx.in_field("us_lower_optical_point_size", |ctx| {
318 if version.compatible(5u16) && self.us_lower_optical_point_size.is_none() {
319 ctx.report(format!("field must be present for version {version}"));
320 }
321 });
322 ctx.in_field("us_upper_optical_point_size", |ctx| {
323 if version.compatible(5u16) && self.us_upper_optical_point_size.is_none() {
324 ctx.report(format!("field must be present for version {version}"));
325 }
326 });
327 })
328 }
329}
330
331impl TopLevelTable for Os2 {
332 const TAG: Tag = Tag::new(b"OS/2");
333}
334
335impl<'a> FromObjRef<read_fonts::tables::os2::Os2<'a>> for Os2 {
336 fn from_obj_ref(obj: &read_fonts::tables::os2::Os2<'a>, _: FontData) -> Self {
337 Os2 {
338 x_avg_char_width: obj.x_avg_char_width(),
339 us_weight_class: obj.us_weight_class(),
340 us_width_class: obj.us_width_class(),
341 fs_type: obj.fs_type(),
342 y_subscript_x_size: obj.y_subscript_x_size(),
343 y_subscript_y_size: obj.y_subscript_y_size(),
344 y_subscript_x_offset: obj.y_subscript_x_offset(),
345 y_subscript_y_offset: obj.y_subscript_y_offset(),
346 y_superscript_x_size: obj.y_superscript_x_size(),
347 y_superscript_y_size: obj.y_superscript_y_size(),
348 y_superscript_x_offset: obj.y_superscript_x_offset(),
349 y_superscript_y_offset: obj.y_superscript_y_offset(),
350 y_strikeout_size: obj.y_strikeout_size(),
351 y_strikeout_position: obj.y_strikeout_position(),
352 s_family_class: obj.s_family_class(),
353 panose_10: convert_panose(obj.panose_10()),
354 ul_unicode_range_1: obj.ul_unicode_range_1(),
355 ul_unicode_range_2: obj.ul_unicode_range_2(),
356 ul_unicode_range_3: obj.ul_unicode_range_3(),
357 ul_unicode_range_4: obj.ul_unicode_range_4(),
358 ach_vend_id: obj.ach_vend_id(),
359 fs_selection: obj.fs_selection(),
360 us_first_char_index: obj.us_first_char_index(),
361 us_last_char_index: obj.us_last_char_index(),
362 s_typo_ascender: obj.s_typo_ascender(),
363 s_typo_descender: obj.s_typo_descender(),
364 s_typo_line_gap: obj.s_typo_line_gap(),
365 us_win_ascent: obj.us_win_ascent(),
366 us_win_descent: obj.us_win_descent(),
367 ul_code_page_range_1: obj.ul_code_page_range_1(),
368 ul_code_page_range_2: obj.ul_code_page_range_2(),
369 sx_height: obj.sx_height(),
370 s_cap_height: obj.s_cap_height(),
371 us_default_char: obj.us_default_char(),
372 us_break_char: obj.us_break_char(),
373 us_max_context: obj.us_max_context(),
374 us_lower_optical_point_size: obj.us_lower_optical_point_size(),
375 us_upper_optical_point_size: obj.us_upper_optical_point_size(),
376 }
377 }
378}
379
380#[allow(clippy::needless_lifetimes)]
381impl<'a> FromTableRef<read_fonts::tables::os2::Os2<'a>> for Os2 {}
382
383impl<'a> FontRead<'a> for Os2 {
384 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
385 <read_fonts::tables::os2::Os2 as FontRead>::read(data).map(|x| x.to_owned_table())
386 }
387}