1//! An [SVG Table](https://docs.microsoft.com/en-us/typography/opentype/spec/svg) implementation.
2
3use crate::parser::{FromData, LazyArray16, NumFrom, Offset, Offset32, Stream};
4use crate::GlyphId;
5
6#[derive(Clone, Copy)]
7struct SvgDocumentRecord {
8 start_glyph_id: GlyphId,
9 end_glyph_id: GlyphId,
10 svg_doc_offset: Option<Offset32>,
11 svg_doc_length: u32,
12}
13
14impl FromData for SvgDocumentRecord {
15 const SIZE: usize = 12;
16
17 #[inline]
18 fn parse(data: &[u8]) -> Option<Self> {
19 let mut s: Stream<'_> = Stream::new(data);
20 Some(SvgDocumentRecord {
21 start_glyph_id: s.read::<GlyphId>()?,
22 end_glyph_id: s.read::<GlyphId>()?,
23 svg_doc_offset: s.read::<Option<Offset32>>()?,
24 svg_doc_length: s.read::<u32>()?,
25 })
26 }
27}
28
29/// A list of [SVG documents](
30/// https://docs.microsoft.com/en-us/typography/opentype/spec/svg#svg-document-list).
31#[derive(Clone, Copy)]
32pub struct SvgDocumentsList<'a> {
33 data: &'a [u8],
34 records: LazyArray16<'a, SvgDocumentRecord>,
35}
36
37impl<'a> SvgDocumentsList<'a> {
38 /// Returns SVG document data at index.
39 ///
40 /// `index` is not a GlyphId. You should use [`find()`](SvgDocumentsList::find) instead.
41 #[inline]
42 pub fn get(&self, index: u16) -> Option<&'a [u8]> {
43 let record = self.records.get(index)?;
44 let offset = record.svg_doc_offset?.to_usize();
45 self.data
46 .get(offset..offset + usize::num_from(record.svg_doc_length))
47 }
48
49 /// Returns a SVG document data by glyph ID.
50 #[inline]
51 pub fn find(&self, glyph_id: GlyphId) -> Option<&'a [u8]> {
52 let index = self
53 .records
54 .into_iter()
55 .position(|v| (v.start_glyph_id..=v.end_glyph_id).contains(&glyph_id))?;
56 self.get(index as u16)
57 }
58
59 /// Returns the number of SVG documents in the list.
60 pub fn len(&self) -> u16 {
61 self.records.len()
62 }
63
64 /// Checks if the list is empty.
65 pub fn is_empty(&self) -> bool {
66 self.records.is_empty()
67 }
68}
69
70impl core::fmt::Debug for SvgDocumentsList<'_> {
71 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
72 write!(f, "SvgDocumentsList {{ ... }}")
73 }
74}
75
76impl<'a> IntoIterator for SvgDocumentsList<'a> {
77 type Item = &'a [u8];
78 type IntoIter = SvgDocumentsListIter<'a>;
79
80 #[inline]
81 fn into_iter(self) -> Self::IntoIter {
82 SvgDocumentsListIter {
83 list: self,
84 index: 0,
85 }
86 }
87}
88
89/// An iterator over [`SvgDocumentsList`] values.
90#[derive(Clone, Copy)]
91#[allow(missing_debug_implementations)]
92pub struct SvgDocumentsListIter<'a> {
93 list: SvgDocumentsList<'a>,
94 index: u16,
95}
96
97impl<'a> Iterator for SvgDocumentsListIter<'a> {
98 type Item = &'a [u8];
99
100 #[inline]
101 fn next(&mut self) -> Option<Self::Item> {
102 if self.index < self.list.len() {
103 self.index += 1;
104 self.list.get(self.index - 1)
105 } else {
106 None
107 }
108 }
109
110 #[inline]
111 fn count(self) -> usize {
112 usize::from(self.list.len().saturating_sub(self.index))
113 }
114}
115
116/// An [SVG Table](https://docs.microsoft.com/en-us/typography/opentype/spec/svg).
117#[derive(Clone, Copy, Debug)]
118pub struct Table<'a> {
119 /// A list of SVG documents.
120 pub documents: SvgDocumentsList<'a>,
121}
122
123impl<'a> Table<'a> {
124 /// Parses a table from raw data.
125 pub fn parse(data: &'a [u8]) -> Option<Self> {
126 let mut s: Stream<'_> = Stream::new(data);
127 s.skip::<u16>(); // version
128 let doc_list_offset: Offset32 = s.read::<Option<Offset32>>()??;
129
130 let mut s: Stream<'_> = Stream::new_at(data, offset:doc_list_offset.to_usize())?;
131 let count: u16 = s.read::<u16>()?;
132 let records: LazyArray16<'_, SvgDocumentRecord> = s.read_array16::<SvgDocumentRecord>(count)?;
133
134 Some(Table {
135 documents: SvgDocumentsList {
136 data: &data[doc_list_offset.0 as usize..],
137 records,
138 },
139 })
140 }
141}
142

Provided by KDAB

Privacy Policy