read_fonts/tables/
ebdt.rs

1//! The [EBDT (Embedded Bitmap Data)](https://docs.microsoft.com/en-us/typography/opentype/spec/ebdt) table
2
3use super::bitmap::{BitmapData, BitmapLocation};
4
5include!("../../generated/generated_ebdt.rs");
6
7impl<'a> Ebdt<'a> {
8    pub fn data(&self, location: &BitmapLocation) -> Result<BitmapData<'a>, ReadError> {
9        super::bitmap::bitmap_data(self.offset_data(), location, false)
10    }
11}
12
13#[cfg(test)]
14mod tests {
15    use super::super::bitmap::{
16        BigGlyphMetrics, BitmapContent, BitmapData, BitmapDataFormat, BitmapMetrics,
17        SmallGlyphMetrics,
18    };
19    use crate::{
20        types::{GlyphId, GlyphId16},
21        FontRef, TableProvider,
22    };
23
24    impl<'a> BitmapContent<'a> {
25        pub(crate) fn extract_data(&self) -> (BitmapDataFormat, &'a [u8]) {
26            match self {
27                BitmapContent::Data(fmt, data) => (*fmt, *data),
28                _ => panic!("expected data content"),
29            }
30        }
31    }
32
33    impl BitmapData<'_> {
34        pub(crate) fn extract_small_metrics(&self) -> &SmallGlyphMetrics {
35            match &self.metrics {
36                BitmapMetrics::Small(small) => small,
37                _ => panic!("expected small glyph metrics"),
38            }
39        }
40    }
41
42    #[test]
43    fn read_eblc_3_ebdt_2() {
44        let font = FontRef::new(font_test_data::EMBEDDED_BITMAPS).unwrap();
45        let eblc = font.eblc().unwrap();
46        let ebdt = font.ebdt().unwrap();
47        let size = &eblc.bitmap_sizes()[0];
48        // Metrics for size at index 0
49        assert!(
50            size.hori.ascender() == 6
51                && size.hori.descender() == 2
52                && size.hori.width_max() == 4
53                && size.hori.max_before_bl() == 6
54                && size.hori.min_after_bl() == -2
55                && size.vert.ascender() == 6
56                && size.vert.descender() == 2
57                && size.start_glyph_index() == GlyphId16::new(1)
58                && size.end_glyph_index() == GlyphId16::new(2)
59                && size.ppem_x() == 7
60                && size.ppem_y() == 7
61                && size.bit_depth() == 1
62        );
63        // Bit aligned formats in this strike:
64        let expected: &[(GlyphId, &[u8], SmallGlyphMetrics)] = &[
65            (
66                GlyphId::new(1),
67                &[0xee, 0xae, 0xea],
68                SmallGlyphMetrics {
69                    height: 8,
70                    width: 3,
71                    bearing_x: 1.into(),
72                    bearing_y: 6.into(),
73                    advance: 4,
74                },
75            ),
76            (
77                GlyphId::new(2),
78                &[0xf0, 0xf0, 0xf0, 0xf0],
79                SmallGlyphMetrics {
80                    height: 8,
81                    width: 4,
82                    bearing_x: 0.into(),
83                    bearing_y: 6.into(),
84                    advance: 4,
85                },
86            ),
87        ];
88        for (gid, data, metrics) in expected {
89            let location = size.location(eblc.offset_data(), *gid).unwrap();
90            assert_eq!(location.format, 2);
91            let bitmap_data = ebdt.data(&location).unwrap();
92            let (img_fmt, img_data) = bitmap_data.content.extract_data();
93            assert_eq!(img_fmt, BitmapDataFormat::BitAligned);
94            assert_eq!(img_data, *data);
95            assert_eq!(bitmap_data.extract_small_metrics(), metrics);
96        }
97    }
98
99    #[test]
100    fn read_eblc_2_ebdt_5() {
101        let font = FontRef::new(font_test_data::EMBEDDED_BITMAPS).unwrap();
102        let eblc = font.eblc().unwrap();
103        let ebdt = font.ebdt().unwrap();
104        let size = &eblc.bitmap_sizes()[1];
105        // Metrics for size at index 1
106        assert!(
107            size.hori.ascender() == 12
108                && size.hori.descender() == 5
109                && size.hori.width_max() == 9
110                && size.hori.max_before_bl() == 12
111                && size.hori.min_after_bl() == -5
112                && size.vert.ascender() == 12
113                && size.vert.descender() == 5
114                && size.start_glyph_index() == GlyphId16::new(3)
115                && size.end_glyph_index() == GlyphId16::new(3)
116                && size.ppem_x() == 15
117                && size.ppem_y() == 15
118                && size.bit_depth() == 1
119        );
120        let expected: &[(GlyphId, &[u8])] = &[(
121            GlyphId::new(3),
122            &[
123                0xaa, 0xbb, 0xcc, 0xdd, 0x00, 0x11, 0x22, 0x33, 0xff, 0xee, 0x12, 0x34, 0x42, 0x42,
124                0x42, 0xaa, 0x88, 0x99, 0x00, 0x11,
125            ],
126        )];
127        for (gid, data) in expected {
128            let location = size.location(eblc.offset_data(), *gid).unwrap();
129            // Metrics are in EBLC, so the same for all glyphs
130            assert_eq!(
131                &location.metrics,
132                &Some(BigGlyphMetrics {
133                    height: 17,
134                    width: 9,
135                    hori_bearing_x: 0.into(),
136                    hori_bearing_y: 12.into(),
137                    hori_advance: 9,
138                    vert_bearing_x: (-4).into(),
139                    vert_bearing_y: (-9).into(),
140                    vert_advance: 0,
141                })
142            );
143            assert_eq!(location.format, 5);
144            let bitmap_data = ebdt.data(&location).unwrap();
145            let (img_fmt, img_data) = bitmap_data.content.extract_data();
146            assert_eq!(img_fmt, BitmapDataFormat::BitAligned);
147            assert_eq!(img_data, *data);
148        }
149    }
150}