1 | //! A [Font Header Table]( |
2 | //! https://docs.microsoft.com/en-us/typography/opentype/spec/head) implementation. |
3 | |
4 | use crate::parser::{Fixed, Stream}; |
5 | use crate::Rect; |
6 | |
7 | /// An index format used by the [Index to Location Table]( |
8 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/loca). |
9 | #[allow (missing_docs)] |
10 | #[derive (Clone, Copy, PartialEq, Eq, Debug)] |
11 | pub enum IndexToLocationFormat { |
12 | Short, |
13 | Long, |
14 | } |
15 | |
16 | /// A [Font Header Table](https://docs.microsoft.com/en-us/typography/opentype/spec/head). |
17 | #[derive (Clone, Copy, Debug)] |
18 | pub struct Table { |
19 | /// Units per EM. |
20 | /// |
21 | /// Guarantee to be in a 16..=16384 range. |
22 | pub units_per_em: u16, |
23 | /// A bounding box that large enough to enclose any glyph from the face. |
24 | pub global_bbox: Rect, |
25 | /// An index format used by the [Index to Location Table]( |
26 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/loca). |
27 | pub index_to_location_format: IndexToLocationFormat, |
28 | } |
29 | |
30 | impl Table { |
31 | /// Parses a table from raw data. |
32 | pub fn parse(data: &[u8]) -> Option<Self> { |
33 | // Do not check the exact length, because some fonts include |
34 | // padding in table's length in table records, which is incorrect. |
35 | if data.len() < 54 { |
36 | return None; |
37 | } |
38 | |
39 | let mut s = Stream::new(data); |
40 | s.skip::<u32>(); // version |
41 | s.skip::<Fixed>(); // font revision |
42 | s.skip::<u32>(); // checksum adjustment |
43 | s.skip::<u32>(); // magic number |
44 | s.skip::<u16>(); // flags |
45 | let units_per_em = s.read::<u16>()?; |
46 | s.skip::<u64>(); // created time |
47 | s.skip::<u64>(); // modified time |
48 | let x_min = s.read::<i16>()?; |
49 | let y_min = s.read::<i16>()?; |
50 | let x_max = s.read::<i16>()?; |
51 | let y_max = s.read::<i16>()?; |
52 | s.skip::<u16>(); // mac style |
53 | s.skip::<u16>(); // lowest PPEM |
54 | s.skip::<i16>(); // font direction hint |
55 | let index_to_location_format = s.read::<u16>()?; |
56 | |
57 | if !(16..=16384).contains(&units_per_em) { |
58 | return None; |
59 | } |
60 | |
61 | let index_to_location_format = match index_to_location_format { |
62 | 0 => IndexToLocationFormat::Short, |
63 | 1 => IndexToLocationFormat::Long, |
64 | _ => return None, |
65 | }; |
66 | |
67 | Some(Table { |
68 | units_per_em, |
69 | global_bbox: Rect { |
70 | x_min, |
71 | y_min, |
72 | x_max, |
73 | y_max, |
74 | }, |
75 | index_to_location_format, |
76 | }) |
77 | } |
78 | } |
79 | |