ttf_parser/tables/
sbix.rs1use core::convert::TryFrom;
5use core::num::NonZeroU16;
6
7use crate::{GlyphId, RasterGlyphImage, RasterImageFormat, Tag};
8use crate::parser::{Stream, FromData, Offset, Offset32, LazyArray16, LazyArray32};
9
10#[derive(Clone, Copy)]
12pub struct Strike<'a> {
13 pub pixels_per_em: u16,
15 pub ppi: u16,
17 offsets: LazyArray16<'a, Offset32>,
18 data: &'a [u8],
20}
21
22impl<'a> Strike<'a> {
23 fn parse(number_of_glyphs: u16, data: &'a [u8]) -> Option<Self> {
24 let mut s = Stream::new(data);
25 let pixels_per_em = s.read::<u16>()?;
26 let ppi = s.read::<u16>()?;
27 let offsets = s.read_array16(number_of_glyphs)?;
28 Some(Strike {
29 pixels_per_em,
30 ppi,
31 offsets,
32 data,
33 })
34 }
35
36 pub fn get(&self, glyph_id: GlyphId) -> Option<RasterGlyphImage<'a>> {
38 self.get_inner(glyph_id, 0)
39 }
40
41 fn get_inner(&self, glyph_id: GlyphId, depth: u8) -> Option<RasterGlyphImage<'a>> {
42 if depth == 10 {
44 return None;
45 }
46
47 let start = self.offsets.get(glyph_id.0)?.to_usize();
48 let end = self.offsets.get(glyph_id.0.checked_add(1)?)?.to_usize();
49
50 if start == end {
51 return None;
52 }
53
54 let data_len = end.checked_sub(start)?.checked_sub(8)?; let mut s = Stream::new_at(self.data, start)?;
57 let x = s.read::<i16>()?;
58 let y = s.read::<i16>()?;
59 let image_type = s.read::<Tag>()?;
60 let image_data = s.read_bytes(data_len)?;
61
62 let format = match &image_type.to_bytes() {
66 b"png " => RasterImageFormat::PNG,
67 b"dupe" => {
68 let glyph_id = GlyphId::parse(image_data)?;
72 return self.get_inner(glyph_id, depth + 1);
75 }
76 _ => {
77 return None;
79 }
80 };
81
82 let (width, height) = png_size(image_data)?;
83
84 Some(RasterGlyphImage {
85 x,
86 y,
87 width,
88 height,
89 pixels_per_em: self.pixels_per_em,
90 format,
91 data: image_data,
92 })
93 }
94
95 #[inline]
97 pub fn len(&self) -> u16 {
98 self.offsets.len() - 1
100 }
101}
102
103impl core::fmt::Debug for Strike<'_> {
104 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
105 write!(f, "Strike {{ ... }}")
106 }
107}
108
109
110#[derive(Clone, Copy)]
112pub struct Strikes<'a> {
113 data: &'a [u8],
115 offsets: LazyArray32<'a, Offset32>,
117 number_of_glyphs: u16,
119}
120
121impl<'a> Strikes<'a> {
122 pub fn get(&self, index: u32) -> Option<Strike<'a>> {
124 let offset = self.offsets.get(index)?.to_usize();
125 let data = self.data.get(offset..)?;
126 Strike::parse(self.number_of_glyphs, data)
127 }
128
129 #[inline]
131 pub fn len(&self) -> u32 {
132 self.offsets.len()
133 }
134}
135
136impl core::fmt::Debug for Strikes<'_> {
137 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
138 write!(f, "Strikes {{ ... }}")
139 }
140}
141
142impl<'a> IntoIterator for Strikes<'a> {
143 type Item = Strike<'a>;
144 type IntoIter = StrikesIter<'a>;
145
146 #[inline]
147 fn into_iter(self) -> Self::IntoIter {
148 StrikesIter {
149 strikes: self,
150 index: 0,
151 }
152 }
153}
154
155#[allow(missing_debug_implementations)]
157pub struct StrikesIter<'a> {
158 strikes: Strikes<'a>,
159 index: u32,
160}
161
162impl<'a> Iterator for StrikesIter<'a> {
163 type Item = Strike<'a>;
164
165 fn next(&mut self) -> Option<Self::Item> {
166 if self.index < self.strikes.len() {
167 self.index += 1;
168 self.strikes.get(self.index - 1)
169 } else {
170 None
171 }
172 }
173}
174
175
176#[derive(Clone, Copy, Debug)]
179pub struct Table<'a> {
180 pub strikes: Strikes<'a>,
182}
183
184impl<'a> Table<'a> {
185 pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
189 let number_of_glyphs = number_of_glyphs.get().checked_add(1)?;
190
191 let mut s = Stream::new(data);
192
193 let version = s.read::<u16>()?;
194 if version != 1 {
195 return None;
196 }
197
198 s.skip::<u16>(); let strikes_count = s.read::<u32>()?;
201 if strikes_count == 0 {
202 return None;
203 }
204
205 let offsets = s.read_array32::<Offset32>(strikes_count)?;
206
207 Some(Table {
208 strikes: Strikes {
209 data,
210 offsets,
211 number_of_glyphs,
212 },
213 })
214 }
215
216 pub fn best_strike(&self, pixels_per_em: u16) -> Option<Strike<'a>> {
218 let mut idx = 0;
219 let mut max_ppem = 0;
220 for (i, strike) in self.strikes.into_iter().enumerate() {
221 if (pixels_per_em <= strike.pixels_per_em && strike.pixels_per_em < max_ppem) ||
222 (pixels_per_em > max_ppem && strike.pixels_per_em > max_ppem)
223 {
224 idx = i as u32;
225 max_ppem = strike.pixels_per_em;
226 }
227 }
228
229 self.strikes.get(idx)
230 }
231}
232
233fn png_size(data: &[u8]) -> Option<(u16, u16)> {
237 let mut s = Stream::new_at(data, 16)?;
239 let width = s.read::<u32>()?;
240 let height = s.read::<u32>()?;
241
242 Some((
244 u16::try_from(width).ok()?,
245 u16::try_from(height).ok()?,
246 ))
247}