1use crate::LineMetrics;
5use crate::parser::{Stream, Fixed, LazyArray16};
6#[cfg(feature = "glyph-names")] use crate::GlyphId;
7
8const TABLE_SIZE: usize = 32;
9const ITALIC_ANGLE_OFFSET: usize = 4;
10const UNDERLINE_POSITION_OFFSET: usize = 8;
11const UNDERLINE_THICKNESS_OFFSET: usize = 10;
12const IS_FIXED_PITCH_OFFSET: usize = 12;
13
14#[cfg(feature = "glyph-names")]
17const MACINTOSH_NAMES: &[&str] = &[
18 ".notdef",
19 ".null",
20 "nonmarkingreturn",
21 "space",
22 "exclam",
23 "quotedbl",
24 "numbersign",
25 "dollar",
26 "percent",
27 "ampersand",
28 "quotesingle",
29 "parenleft",
30 "parenright",
31 "asterisk",
32 "plus",
33 "comma",
34 "hyphen",
35 "period",
36 "slash",
37 "zero",
38 "one",
39 "two",
40 "three",
41 "four",
42 "five",
43 "six",
44 "seven",
45 "eight",
46 "nine",
47 "colon",
48 "semicolon",
49 "less",
50 "equal",
51 "greater",
52 "question",
53 "at",
54 "A",
55 "B",
56 "C",
57 "D",
58 "E",
59 "F",
60 "G",
61 "H",
62 "I",
63 "J",
64 "K",
65 "L",
66 "M",
67 "N",
68 "O",
69 "P",
70 "Q",
71 "R",
72 "S",
73 "T",
74 "U",
75 "V",
76 "W",
77 "X",
78 "Y",
79 "Z",
80 "bracketleft",
81 "backslash",
82 "bracketright",
83 "asciicircum",
84 "underscore",
85 "grave",
86 "a",
87 "b",
88 "c",
89 "d",
90 "e",
91 "f",
92 "g",
93 "h",
94 "i",
95 "j",
96 "k",
97 "l",
98 "m",
99 "n",
100 "o",
101 "p",
102 "q",
103 "r",
104 "s",
105 "t",
106 "u",
107 "v",
108 "w",
109 "x",
110 "y",
111 "z",
112 "braceleft",
113 "bar",
114 "braceright",
115 "asciitilde",
116 "Adieresis",
117 "Aring",
118 "Ccedilla",
119 "Eacute",
120 "Ntilde",
121 "Odieresis",
122 "Udieresis",
123 "aacute",
124 "agrave",
125 "acircumflex",
126 "adieresis",
127 "atilde",
128 "aring",
129 "ccedilla",
130 "eacute",
131 "egrave",
132 "ecircumflex",
133 "edieresis",
134 "iacute",
135 "igrave",
136 "icircumflex",
137 "idieresis",
138 "ntilde",
139 "oacute",
140 "ograve",
141 "ocircumflex",
142 "odieresis",
143 "otilde",
144 "uacute",
145 "ugrave",
146 "ucircumflex",
147 "udieresis",
148 "dagger",
149 "degree",
150 "cent",
151 "sterling",
152 "section",
153 "bullet",
154 "paragraph",
155 "germandbls",
156 "registered",
157 "copyright",
158 "trademark",
159 "acute",
160 "dieresis",
161 "notequal",
162 "AE",
163 "Oslash",
164 "infinity",
165 "plusminus",
166 "lessequal",
167 "greaterequal",
168 "yen",
169 "mu",
170 "partialdiff",
171 "summation",
172 "product",
173 "pi",
174 "integral",
175 "ordfeminine",
176 "ordmasculine",
177 "Omega",
178 "ae",
179 "oslash",
180 "questiondown",
181 "exclamdown",
182 "logicalnot",
183 "radical",
184 "florin",
185 "approxequal",
186 "Delta",
187 "guillemotleft",
188 "guillemotright",
189 "ellipsis",
190 "nonbreakingspace",
191 "Agrave",
192 "Atilde",
193 "Otilde",
194 "OE",
195 "oe",
196 "endash",
197 "emdash",
198 "quotedblleft",
199 "quotedblright",
200 "quoteleft",
201 "quoteright",
202 "divide",
203 "lozenge",
204 "ydieresis",
205 "Ydieresis",
206 "fraction",
207 "currency",
208 "guilsinglleft",
209 "guilsinglright",
210 "fi",
211 "fl",
212 "daggerdbl",
213 "periodcentered",
214 "quotesinglbase",
215 "quotedblbase",
216 "perthousand",
217 "Acircumflex",
218 "Ecircumflex",
219 "Aacute",
220 "Edieresis",
221 "Egrave",
222 "Iacute",
223 "Icircumflex",
224 "Idieresis",
225 "Igrave",
226 "Oacute",
227 "Ocircumflex",
228 "apple",
229 "Ograve",
230 "Uacute",
231 "Ucircumflex",
232 "Ugrave",
233 "dotlessi",
234 "circumflex",
235 "tilde",
236 "macron",
237 "breve",
238 "dotaccent",
239 "ring",
240 "cedilla",
241 "hungarumlaut",
242 "ogonek",
243 "caron",
244 "Lslash",
245 "lslash",
246 "Scaron",
247 "scaron",
248 "Zcaron",
249 "zcaron",
250 "brokenbar",
251 "Eth",
252 "eth",
253 "Yacute",
254 "yacute",
255 "Thorn",
256 "thorn",
257 "minus",
258 "multiply",
259 "onesuperior",
260 "twosuperior",
261 "threesuperior",
262 "onehalf",
263 "onequarter",
264 "threequarters",
265 "franc",
266 "Gbreve",
267 "gbreve",
268 "Idotaccent",
269 "Scedilla",
270 "scedilla",
271 "Cacute",
272 "cacute",
273 "Ccaron",
274 "ccaron",
275 "dcroat",
276];
277
278
279#[derive(Clone, Copy, Default)]
281pub struct Names<'a> {
282 indexes: LazyArray16<'a, u16>,
283 data: &'a [u8],
284}
285
286impl<'a> Names<'a> {
288 #[cfg(feature = "glyph-names")]
290 pub fn get(&self, glyph_id: GlyphId) -> Option<&'a str> {
291 let mut index = self.indexes.get(glyph_id.0)?;
292
293 if usize::from(index) < MACINTOSH_NAMES.len() {
296 Some(MACINTOSH_NAMES[usize::from(index)])
297 } else {
298 index -= MACINTOSH_NAMES.len() as u16;
301
302 let mut s = Stream::new(self.data);
303 let mut i = 0;
304 while !s.at_end() && i < core::u16::MAX {
305 let len = s.read::<u8>()?;
306
307 if i == index {
308 if len == 0 {
309 break;
311 } else {
312 let name = s.read_bytes(usize::from(len))?;
313 return core::str::from_utf8(name).ok();
314 }
315 } else {
316 s.advance(usize::from(len));
317 }
318
319 i += 1;
320 }
321
322 None
323 }
324 }
325
326 #[inline]
328 pub fn len(&self) -> u16 {
329 self.indexes.len()
330 }
331}
332
333impl core::fmt::Debug for Names<'_> {
334 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
335 write!(f, "Names {{ ... }}")
336 }
337}
338
339
340#[derive(Clone, Copy, Debug)]
342pub struct Table<'a> {
343 pub italic_angle: f32,
345 pub underline_metrics: LineMetrics,
347 pub is_monospaced: bool,
349 pub names: Names<'a>,
351}
352
353
354impl<'a> Table<'a> {
355 pub fn parse(data: &'a [u8]) -> Option<Self> {
357 if data.len() < TABLE_SIZE {
358 return None;
359 }
360
361 let version = Stream::new(data).read::<u32>()?;
362 if !(version == 0x00010000 || version == 0x00020000 ||
363 version == 0x00025000 || version == 0x00030000 ||
364 version == 0x00040000)
365 {
366 return None;
367 }
368
369 let italic_angle = Stream::read_at::<Fixed>(data, ITALIC_ANGLE_OFFSET)?.0;
370
371 let underline_metrics = LineMetrics {
372 position: Stream::read_at::<i16>(data, UNDERLINE_POSITION_OFFSET)?,
373 thickness: Stream::read_at::<i16>(data, UNDERLINE_THICKNESS_OFFSET)?,
374 };
375
376 let is_monospaced = Stream::read_at::<u32>(data, IS_FIXED_PITCH_OFFSET)? != 0;
377
378 let mut names = Names::default();
379 if version == 0x00020000 {
381 let mut s = Stream::new_at(data, TABLE_SIZE)?;
382 let count = s.read::<u16>()?;
383 names.indexes = s.read_array16::<u16>(count)?;
384 names.data = s.tail()?;
385 }
386
387 Some(Table {
388 italic_angle,
389 underline_metrics,
390 is_monospaced,
391 names,
392 })
393 }
394}