read_fonts/tables/
svg.rs

1//! The [SVG](https://learn.microsoft.com/en-us/typography/opentype/spec/svg) table
2
3use core::cmp::Ordering;
4
5include!("../../generated/generated_svg.rs");
6
7impl<'a> Svg<'a> {
8    /// Get the raw data of the SVG document. Is not guaranteed to be valid and might be compressed.
9    pub fn glyph_data(&self, glyph_id: GlyphId) -> Result<Option<&'a [u8]>, ReadError> {
10        let document_list = self.svg_document_list()?;
11        let svg_document = document_list
12            .document_records()
13            .binary_search_by(|r| {
14                if r.start_glyph_id.get() > glyph_id {
15                    Ordering::Greater
16                } else if r.end_glyph_id.get() < glyph_id {
17                    Ordering::Less
18                } else {
19                    Ordering::Equal
20                }
21            })
22            .ok()
23            .and_then(|index| document_list.document_records().get(index))
24            .and_then(|r| {
25                let all_data = document_list.data.as_bytes();
26                all_data.get(
27                    r.svg_doc_offset.get() as usize
28                        ..(r.svg_doc_offset.get() + r.svg_doc_length.get()) as usize,
29                )
30            });
31
32        Ok(svg_document)
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use font_test_data::bebuffer::BeBuffer;
39
40    use super::*;
41
42    #[test]
43    fn read_dummy_svg_file() {
44        let data: [u16; 32] = [
45            0, // Version
46            0, 10, // SVGDocumentListOffset
47            0, 0, // Reserved
48            // SVGDocumentList
49            3, // numEntries
50            // documentRecords
51            // Record 1
52            1, // startGlyphID
53            3, // endGlyphID
54            0, 38, // svgDocOffset
55            0, 10, // svgDocLength
56            // Record 2
57            6, // startGlyphID
58            7, // endGlyphID
59            0, 48, // svgDocOffset
60            0, 6, // svgDocLength
61            // Record 3
62            9, // startGlyphID
63            9, // endGlyphID
64            0, 38, // svgDocOffset
65            0, 10,
66            // svgDocLength
67            // SVG Documents. Not actual valid SVGs, but just dummy data.
68            1, 0, 0, 0, 1, // Document 1
69            2, 0, 0, // Document 2
70        ];
71
72        let mut buf = BeBuffer::new();
73        buf = buf.extend(data);
74
75        let table = Svg::read(buf.data().into()).unwrap();
76
77        let first_document = &[0, 1, 0, 0, 0, 0, 0, 0, 0, 1][..];
78        let second_document = &[0, 2, 0, 0, 0, 0][..];
79
80        assert_eq!(table.glyph_data(GlyphId::new(0)).unwrap(), None);
81        assert_eq!(
82            table.glyph_data(GlyphId::new(1)).unwrap(),
83            Some(first_document)
84        );
85        assert_eq!(
86            table.glyph_data(GlyphId::new(2)).unwrap(),
87            Some(first_document)
88        );
89        assert_eq!(
90            table.glyph_data(GlyphId::new(3)).unwrap(),
91            Some(first_document)
92        );
93        assert_eq!(table.glyph_data(GlyphId::new(4)).unwrap(), None);
94        assert_eq!(table.glyph_data(GlyphId::new(5)).unwrap(), None);
95        assert_eq!(
96            table.glyph_data(GlyphId::new(6)).unwrap(),
97            Some(second_document)
98        );
99        assert_eq!(
100            table.glyph_data(GlyphId::new(7)).unwrap(),
101            Some(second_document)
102        );
103        assert_eq!(table.glyph_data(GlyphId::new(8)).unwrap(), None);
104        assert_eq!(
105            table.glyph_data(GlyphId::new(9)).unwrap(),
106            Some(first_document)
107        );
108        assert_eq!(table.glyph_data(GlyphId::new(10)).unwrap(), None);
109    }
110}