1 | //! A [Vertical Origin Table]( |
2 | //! https://docs.microsoft.com/en-us/typography/opentype/spec/vorg) implementation. |
3 | |
4 | use crate::parser::{FromData, LazyArray16, Stream}; |
5 | use crate::GlyphId; |
6 | |
7 | /// Vertical origin metrics for the |
8 | /// [Vertical Origin Table](https://docs.microsoft.com/en-us/typography/opentype/spec/vorg). |
9 | #[derive (Clone, Copy, Debug)] |
10 | pub struct VerticalOriginMetrics { |
11 | /// Glyph ID. |
12 | pub glyph_id: GlyphId, |
13 | /// Y coordinate, in the font's design coordinate system, of the vertical origin. |
14 | pub y: i16, |
15 | } |
16 | |
17 | impl FromData for VerticalOriginMetrics { |
18 | const SIZE: usize = 4; |
19 | |
20 | #[inline ] |
21 | fn parse(data: &[u8]) -> Option<Self> { |
22 | let mut s: Stream<'_> = Stream::new(data); |
23 | Some(VerticalOriginMetrics { |
24 | glyph_id: s.read::<GlyphId>()?, |
25 | y: s.read::<i16>()?, |
26 | }) |
27 | } |
28 | } |
29 | |
30 | /// A [Vertical Origin Table](https://docs.microsoft.com/en-us/typography/opentype/spec/vorg). |
31 | #[derive (Clone, Copy, Debug)] |
32 | pub struct Table<'a> { |
33 | /// Default origin. |
34 | pub default_y: i16, |
35 | /// A list of metrics for each glyph. |
36 | /// |
37 | /// Ordered by `glyph_id`. |
38 | pub metrics: LazyArray16<'a, VerticalOriginMetrics>, |
39 | } |
40 | |
41 | impl<'a> Table<'a> { |
42 | /// Parses a table from raw data. |
43 | pub fn parse(data: &'a [u8]) -> Option<Self> { |
44 | let mut s = Stream::new(data); |
45 | |
46 | let version = s.read::<u32>()?; |
47 | if version != 0x00010000 { |
48 | return None; |
49 | } |
50 | |
51 | let default_y = s.read::<i16>()?; |
52 | let count = s.read::<u16>()?; |
53 | let metrics = s.read_array16::<VerticalOriginMetrics>(count)?; |
54 | |
55 | Some(Table { default_y, metrics }) |
56 | } |
57 | |
58 | /// Returns glyph's Y origin. |
59 | pub fn glyph_y_origin(&self, glyph_id: GlyphId) -> i16 { |
60 | self.metrics |
61 | .binary_search_by(|m| m.glyph_id.cmp(&glyph_id)) |
62 | .map(|(_, m)| m.y) |
63 | .unwrap_or(self.default_y) |
64 | } |
65 | } |
66 | |