1mod afm;
6pub use afm::{is_standard_14, standard_14_width};
7
8const WIN_ANSI_80_9F: [Option<char>; 32] = [
11 Some('\u{20AC}'),
12 None,
13 Some('\u{201A}'),
14 Some('\u{0192}'),
15 Some('\u{201E}'),
16 Some('\u{2026}'),
17 Some('\u{2020}'),
18 Some('\u{2021}'),
19 Some('\u{02C6}'),
20 Some('\u{2030}'),
21 Some('\u{0160}'),
22 Some('\u{2039}'),
23 Some('\u{0152}'),
24 None,
25 Some('\u{017D}'),
26 None,
27 None,
28 Some('\u{2018}'),
29 Some('\u{2019}'),
30 Some('\u{201C}'),
31 Some('\u{201D}'),
32 Some('\u{2022}'),
33 Some('\u{2013}'),
34 Some('\u{2014}'),
35 Some('\u{02DC}'),
36 Some('\u{2122}'),
37 Some('\u{0161}'),
38 Some('\u{203A}'),
39 Some('\u{0153}'),
40 None,
41 Some('\u{017E}'),
42 Some('\u{0178}'),
43];
44
45pub fn win_ansi(code: u8) -> Option<char> {
47 match code {
48 0x20..=0x7E => Some(code as char),
49 0x80..=0x9F => WIN_ANSI_80_9F[(code - 0x80) as usize],
50 0xA0..=0xFF => Some(code as char),
51 _ => None,
52 }
53}
54
55const MAC_ROMAN_HIGH: [char; 128] = [
57 '\u{C4}', '\u{C5}', '\u{C7}', '\u{C9}', '\u{D1}', '\u{D6}', '\u{DC}', '\u{E1}', '\u{E0}',
58 '\u{E2}', '\u{E4}', '\u{E3}', '\u{E5}', '\u{E7}', '\u{E9}', '\u{E8}', '\u{EA}', '\u{EB}',
59 '\u{ED}', '\u{EC}', '\u{EE}', '\u{EF}', '\u{F1}', '\u{F3}', '\u{F2}', '\u{F4}', '\u{F6}',
60 '\u{F5}', '\u{FA}', '\u{F9}', '\u{FB}', '\u{FC}', '\u{2020}', '\u{B0}', '\u{A2}', '\u{A3}',
61 '\u{A7}', '\u{2022}', '\u{B6}', '\u{DF}', '\u{AE}', '\u{A9}', '\u{2122}', '\u{B4}', '\u{A8}',
62 '\u{2260}', '\u{C6}', '\u{D8}', '\u{221E}', '\u{B1}', '\u{2264}', '\u{2265}', '\u{A5}',
63 '\u{B5}', '\u{2202}', '\u{2211}', '\u{220F}', '\u{3C0}', '\u{222B}', '\u{AA}', '\u{BA}',
64 '\u{3A9}', '\u{E6}', '\u{F8}', '\u{BF}', '\u{A1}', '\u{AC}', '\u{221A}', '\u{192}', '\u{2248}',
65 '\u{2206}', '\u{AB}', '\u{BB}', '\u{2026}', '\u{A0}', '\u{C0}', '\u{C3}', '\u{D5}', '\u{152}',
66 '\u{153}', '\u{2013}', '\u{2014}', '\u{201C}', '\u{201D}', '\u{2018}', '\u{2019}', '\u{F7}',
67 '\u{25CA}', '\u{FF}', '\u{178}', '\u{2044}', '\u{20AC}', '\u{2039}', '\u{203A}', '\u{FB01}',
68 '\u{FB02}', '\u{2021}', '\u{B7}', '\u{201A}', '\u{201E}', '\u{2030}', '\u{C2}', '\u{CA}',
69 '\u{C1}', '\u{CB}', '\u{C8}', '\u{CD}', '\u{CE}', '\u{CF}', '\u{CC}', '\u{D3}', '\u{D4}',
70 '\u{F8FF}', '\u{D2}', '\u{DA}', '\u{DB}', '\u{D9}', '\u{131}', '\u{2C6}', '\u{2DC}', '\u{AF}',
71 '\u{2D8}', '\u{2D9}', '\u{2DA}', '\u{B8}', '\u{2DD}', '\u{2DB}', '\u{2C7}',
72];
73
74pub fn mac_roman(code: u8) -> Option<char> {
76 match code {
77 0x20..=0x7E => Some(code as char),
78 0x80..=0xFF => Some(MAC_ROMAN_HIGH[(code - 0x80) as usize]),
79 _ => None,
80 }
81}
82
83const STANDARD_HIGH: &[(u8, char)] = &[
85 (0xA1, '\u{A1}'),
86 (0xA2, '\u{A2}'),
87 (0xA3, '\u{A3}'),
88 (0xA4, '\u{2044}'),
89 (0xA5, '\u{A5}'),
90 (0xA6, '\u{192}'),
91 (0xA7, '\u{A7}'),
92 (0xA8, '\u{A4}'),
93 (0xA9, '\u{27}'),
94 (0xAA, '\u{201C}'),
95 (0xAB, '\u{AB}'),
96 (0xAC, '\u{2039}'),
97 (0xAD, '\u{203A}'),
98 (0xAE, '\u{FB01}'),
99 (0xAF, '\u{FB02}'),
100 (0xB1, '\u{2013}'),
101 (0xB2, '\u{2020}'),
102 (0xB3, '\u{2021}'),
103 (0xB4, '\u{B7}'),
104 (0xB6, '\u{B6}'),
105 (0xB7, '\u{2022}'),
106 (0xB8, '\u{201A}'),
107 (0xB9, '\u{201E}'),
108 (0xBA, '\u{201D}'),
109 (0xBB, '\u{BB}'),
110 (0xBC, '\u{2026}'),
111 (0xBD, '\u{2030}'),
112 (0xBF, '\u{BF}'),
113 (0xC1, '\u{60}'),
114 (0xC2, '\u{B4}'),
115 (0xC3, '\u{2C6}'),
116 (0xC4, '\u{2DC}'),
117 (0xC5, '\u{AF}'),
118 (0xC6, '\u{2D8}'),
119 (0xC7, '\u{2D9}'),
120 (0xC8, '\u{A8}'),
121 (0xCA, '\u{2DA}'),
122 (0xCB, '\u{B8}'),
123 (0xCD, '\u{2DD}'),
124 (0xCE, '\u{2DB}'),
125 (0xCF, '\u{2C7}'),
126 (0xD0, '\u{2014}'),
127 (0xE1, '\u{C6}'),
128 (0xE3, '\u{AA}'),
129 (0xE8, '\u{141}'),
130 (0xE9, '\u{D8}'),
131 (0xEA, '\u{152}'),
132 (0xEB, '\u{BA}'),
133 (0xF1, '\u{E6}'),
134 (0xF5, '\u{131}'),
135 (0xF8, '\u{142}'),
136 (0xF9, '\u{F8}'),
137 (0xFA, '\u{153}'),
138 (0xFB, '\u{DF}'),
139];
140
141pub fn standard(code: u8) -> Option<char> {
143 match code {
144 0x27 => Some('\u{2019}'),
145 0x60 => Some('\u{2018}'),
146 0x20..=0x7E => Some(code as char),
147 0xA1..=0xFF => STANDARD_HIGH
148 .iter()
149 .find(|&&(c, _)| c == code)
150 .map(|&(_, u)| u),
151 _ => None,
152 }
153}
154
155const STANDARD_ASCII_NAMES: [&str; 95] = [
161 "space",
162 "exclam",
163 "quotedbl",
164 "numbersign",
165 "dollar",
166 "percent",
167 "ampersand",
168 "quoteright",
169 "parenleft",
170 "parenright",
171 "asterisk",
172 "plus",
173 "comma",
174 "hyphen",
175 "period",
176 "slash",
177 "zero",
178 "one",
179 "two",
180 "three",
181 "four",
182 "five",
183 "six",
184 "seven",
185 "eight",
186 "nine",
187 "colon",
188 "semicolon",
189 "less",
190 "equal",
191 "greater",
192 "question",
193 "at",
194 "A",
195 "B",
196 "C",
197 "D",
198 "E",
199 "F",
200 "G",
201 "H",
202 "I",
203 "J",
204 "K",
205 "L",
206 "M",
207 "N",
208 "O",
209 "P",
210 "Q",
211 "R",
212 "S",
213 "T",
214 "U",
215 "V",
216 "W",
217 "X",
218 "Y",
219 "Z",
220 "bracketleft",
221 "backslash",
222 "bracketright",
223 "asciicircum",
224 "underscore",
225 "quoteleft",
226 "a",
227 "b",
228 "c",
229 "d",
230 "e",
231 "f",
232 "g",
233 "h",
234 "i",
235 "j",
236 "k",
237 "l",
238 "m",
239 "n",
240 "o",
241 "p",
242 "q",
243 "r",
244 "s",
245 "t",
246 "u",
247 "v",
248 "w",
249 "x",
250 "y",
251 "z",
252 "braceleft",
253 "bar",
254 "braceright",
255 "asciitilde",
256];
257
258const STANDARD_HIGH_NAMES: &[(u8, &str)] = &[
262 (0xA1, "exclamdown"),
263 (0xA2, "cent"),
264 (0xA3, "sterling"),
265 (0xA4, "fraction"),
266 (0xA5, "yen"),
267 (0xA6, "florin"),
268 (0xA7, "section"),
269 (0xA8, "currency"),
270 (0xA9, "quotesingle"),
271 (0xAA, "quotedblleft"),
272 (0xAB, "guillemotleft"),
273 (0xAC, "guilsinglleft"),
274 (0xAD, "guilsinglright"),
275 (0xAE, "fi"),
276 (0xAF, "fl"),
277 (0xB1, "endash"),
278 (0xB2, "dagger"),
279 (0xB3, "daggerdbl"),
280 (0xB4, "periodcentered"),
281 (0xB6, "paragraph"),
282 (0xB7, "bullet"),
283 (0xB8, "quotesinglbase"),
284 (0xB9, "quotedblbase"),
285 (0xBA, "quotedblright"),
286 (0xBB, "guillemotright"),
287 (0xBC, "ellipsis"),
288 (0xBD, "perthousand"),
289 (0xBF, "questiondown"),
290 (0xC1, "grave"),
291 (0xC2, "acute"),
292 (0xC3, "circumflex"),
293 (0xC4, "tilde"),
294 (0xC5, "macron"),
295 (0xC6, "breve"),
296 (0xC7, "dotaccent"),
297 (0xC8, "dieresis"),
298 (0xCA, "ring"),
299 (0xCB, "cedilla"),
300 (0xCD, "hungarumlaut"),
301 (0xCE, "ogonek"),
302 (0xCF, "caron"),
303 (0xD0, "emdash"),
304 (0xE1, "AE"),
305 (0xE3, "ordfeminine"),
306 (0xE8, "Lslash"),
307 (0xE9, "Oslash"),
308 (0xEA, "OE"),
309 (0xEB, "ordmasculine"),
310 (0xF1, "ae"),
311 (0xF5, "dotlessi"),
312 (0xF8, "lslash"),
313 (0xF9, "oslash"),
314 (0xFA, "oe"),
315 (0xFB, "germandbls"),
316];
317
318pub fn standard_encoding_name(code: u8) -> Option<&'static str> {
325 match code {
326 0x20..=0x7E => Some(STANDARD_ASCII_NAMES[(code - 0x20) as usize]),
327 0xA1..=0xFF => STANDARD_HIGH_NAMES
328 .iter()
329 .find(|&&(c, _)| c == code)
330 .map(|&(_, n)| n),
331 _ => None,
332 }
333}
334
335pub fn glyph_to_unicode(name: &str) -> Option<char> {
339 if let Some(hex) = name.strip_prefix("uni") {
340 if hex.len() == 4 && hex.bytes().all(|b| b.is_ascii_hexdigit()) {
341 return char::from_u32(u32::from_str_radix(hex, 16).ok()?);
342 }
343 }
344 if let Some(hex) = name.strip_prefix('u') {
345 if (4..=6).contains(&hex.len()) && hex.bytes().all(|b| b.is_ascii_hexdigit()) {
346 return char::from_u32(u32::from_str_radix(hex, 16).ok()?);
347 }
348 }
349 let mut chars = name.chars();
350 if let (Some(c), None) = (chars.next(), chars.next()) {
351 if c.is_ascii_alphabetic() {
352 return Some(c);
353 }
354 }
355 GLYPH_TABLES
356 .iter()
357 .flat_map(|t| t.iter())
358 .find(|&&(n, _)| n == name)
359 .map(|&(_, u)| u)
360}
361
362pub fn glyph_to_text(name: &str) -> Option<String> {
370 let base = name.split('.').next().unwrap_or_default();
371 if base.is_empty() {
372 return None;
373 }
374 let mut out = String::new();
375 for component in base.split('_') {
376 push_component(component, &mut out)?;
377 }
378 Some(out)
379}
380
381fn push_component(component: &str, out: &mut String) -> Option<()> {
384 let hex = component.strip_prefix("uni").unwrap_or_default();
385 if hex.len() >= 8 && hex.len().is_multiple_of(4) && hex.bytes().all(|b| b.is_ascii_hexdigit()) {
386 for group in hex.as_bytes().chunks(4) {
389 let group = std::str::from_utf8(group).ok()?;
390 let scalar = u32::from_str_radix(group, 16).ok()?;
391 out.push(char::from_u32(scalar)?);
392 }
393 return Some(());
394 }
395 out.push(glyph_to_unicode(component)?);
396 Some(())
397}
398
399const GLYPH_TABLES: [&[(&str, char)]; 5] = [
401 GLYPHS_ASCII,
402 GLYPHS_LATIN1,
403 GLYPHS_PUNCT,
404 GLYPHS_GREEK,
405 GLYPHS_MISC,
406];
407
408const GLYPHS_ASCII: &[(&str, char)] = &[
410 ("space", ' '),
411 ("exclam", '!'),
412 ("quotedbl", '"'),
413 ("numbersign", '#'),
414 ("dollar", '$'),
415 ("percent", '%'),
416 ("ampersand", '&'),
417 ("quotesingle", '\''),
418 ("parenleft", '('),
419 ("parenright", ')'),
420 ("asterisk", '*'),
421 ("plus", '+'),
422 ("comma", ','),
423 ("hyphen", '-'),
424 ("period", '.'),
425 ("slash", '/'),
426 ("zero", '0'),
427 ("one", '1'),
428 ("two", '2'),
429 ("three", '3'),
430 ("four", '4'),
431 ("five", '5'),
432 ("six", '6'),
433 ("seven", '7'),
434 ("eight", '8'),
435 ("nine", '9'),
436 ("colon", ':'),
437 ("semicolon", ';'),
438 ("less", '<'),
439 ("equal", '='),
440 ("greater", '>'),
441 ("question", '?'),
442 ("at", '@'),
443 ("bracketleft", '['),
444 ("backslash", '\\'),
445 ("bracketright", ']'),
446 ("asciicircum", '^'),
447 ("underscore", '_'),
448 ("grave", '`'),
449 ("braceleft", '{'),
450 ("bar", '|'),
451 ("braceright", '}'),
452 ("asciitilde", '~'),
453];
454
455const GLYPHS_LATIN1: &[(&str, char)] = &[
457 ("exclamdown", '\u{A1}'),
458 ("cent", '\u{A2}'),
459 ("sterling", '\u{A3}'),
460 ("currency", '\u{A4}'),
461 ("yen", '\u{A5}'),
462 ("brokenbar", '\u{A6}'),
463 ("section", '\u{A7}'),
464 ("dieresis", '\u{A8}'),
465 ("copyright", '\u{A9}'),
466 ("ordfeminine", '\u{AA}'),
467 ("guillemotleft", '\u{AB}'),
468 ("logicalnot", '\u{AC}'),
469 ("registered", '\u{AE}'),
470 ("macron", '\u{AF}'),
471 ("degree", '\u{B0}'),
472 ("plusminus", '\u{B1}'),
473 ("twosuperior", '\u{B2}'),
474 ("threesuperior", '\u{B3}'),
475 ("acute", '\u{B4}'),
476 ("mu", '\u{B5}'),
477 ("paragraph", '\u{B6}'),
478 ("periodcentered", '\u{B7}'),
479 ("cedilla", '\u{B8}'),
480 ("onesuperior", '\u{B9}'),
481 ("ordmasculine", '\u{BA}'),
482 ("guillemotright", '\u{BB}'),
483 ("onequarter", '\u{BC}'),
484 ("onehalf", '\u{BD}'),
485 ("threequarters", '\u{BE}'),
486 ("questiondown", '\u{BF}'),
487 ("Agrave", '\u{C0}'),
488 ("Aacute", '\u{C1}'),
489 ("Acircumflex", '\u{C2}'),
490 ("Atilde", '\u{C3}'),
491 ("Adieresis", '\u{C4}'),
492 ("Aring", '\u{C5}'),
493 ("AE", '\u{C6}'),
494 ("Ccedilla", '\u{C7}'),
495 ("Egrave", '\u{C8}'),
496 ("Eacute", '\u{C9}'),
497 ("Ecircumflex", '\u{CA}'),
498 ("Edieresis", '\u{CB}'),
499 ("Igrave", '\u{CC}'),
500 ("Iacute", '\u{CD}'),
501 ("Icircumflex", '\u{CE}'),
502 ("Idieresis", '\u{CF}'),
503 ("Eth", '\u{D0}'),
504 ("Ntilde", '\u{D1}'),
505 ("Ograve", '\u{D2}'),
506 ("Oacute", '\u{D3}'),
507 ("Ocircumflex", '\u{D4}'),
508 ("Otilde", '\u{D5}'),
509 ("Odieresis", '\u{D6}'),
510 ("multiply", '\u{D7}'),
511 ("Oslash", '\u{D8}'),
512 ("Ugrave", '\u{D9}'),
513 ("Uacute", '\u{DA}'),
514 ("Ucircumflex", '\u{DB}'),
515 ("Udieresis", '\u{DC}'),
516 ("Yacute", '\u{DD}'),
517 ("Thorn", '\u{DE}'),
518 ("germandbls", '\u{DF}'),
519 ("agrave", '\u{E0}'),
520 ("aacute", '\u{E1}'),
521 ("acircumflex", '\u{E2}'),
522 ("atilde", '\u{E3}'),
523 ("adieresis", '\u{E4}'),
524 ("aring", '\u{E5}'),
525 ("ae", '\u{E6}'),
526 ("ccedilla", '\u{E7}'),
527 ("egrave", '\u{E8}'),
528 ("eacute", '\u{E9}'),
529 ("ecircumflex", '\u{EA}'),
530 ("edieresis", '\u{EB}'),
531 ("igrave", '\u{EC}'),
532 ("iacute", '\u{ED}'),
533 ("icircumflex", '\u{EE}'),
534 ("idieresis", '\u{EF}'),
535 ("eth", '\u{F0}'),
536 ("ntilde", '\u{F1}'),
537 ("ograve", '\u{F2}'),
538 ("oacute", '\u{F3}'),
539 ("ocircumflex", '\u{F4}'),
540 ("otilde", '\u{F5}'),
541 ("odieresis", '\u{F6}'),
542 ("divide", '\u{F7}'),
543 ("oslash", '\u{F8}'),
544 ("ugrave", '\u{F9}'),
545 ("uacute", '\u{FA}'),
546 ("ucircumflex", '\u{FB}'),
547 ("udieresis", '\u{FC}'),
548 ("yacute", '\u{FD}'),
549 ("thorn", '\u{FE}'),
550 ("ydieresis", '\u{FF}'),
551];
552
553const GLYPHS_PUNCT: &[(&str, char)] = &[
555 ("quoteleft", '\u{2018}'),
556 ("quoteright", '\u{2019}'),
557 ("quotesinglbase", '\u{201A}'),
558 ("quotedblleft", '\u{201C}'),
559 ("quotedblright", '\u{201D}'),
560 ("quotedblbase", '\u{201E}'),
561 ("endash", '\u{2013}'),
562 ("emdash", '\u{2014}'),
563 ("bullet", '\u{2022}'),
564 ("ellipsis", '\u{2026}'),
565 ("dagger", '\u{2020}'),
566 ("daggerdbl", '\u{2021}'),
567 ("perthousand", '\u{2030}'),
568 ("guilsinglleft", '\u{2039}'),
569 ("guilsinglright", '\u{203A}'),
570 ("fraction", '\u{2044}'),
571 ("minus", '\u{2212}'),
572 ("florin", '\u{192}'),
573 ("Euro", '\u{20AC}'),
574 ("trademark", '\u{2122}'),
575 ("fi", '\u{FB01}'),
576 ("fl", '\u{FB02}'),
577 ("ff", '\u{FB00}'),
578 ("ffi", '\u{FB03}'),
579 ("ffl", '\u{FB04}'),
580 ("circumflex", '\u{2C6}'),
581 ("caron", '\u{2C7}'),
582 ("breve", '\u{2D8}'),
583 ("dotaccent", '\u{2D9}'),
584 ("ring", '\u{2DA}'),
585 ("ogonek", '\u{2DB}'),
586 ("tilde", '\u{2DC}'),
587 ("hungarumlaut", '\u{2DD}'),
588 ("OE", '\u{152}'),
589 ("oe", '\u{153}'),
590 ("Scaron", '\u{160}'),
591 ("scaron", '\u{161}'),
592 ("Zcaron", '\u{17D}'),
593 ("zcaron", '\u{17E}'),
594 ("Ydieresis", '\u{178}'),
595 ("Lslash", '\u{141}'),
596 ("lslash", '\u{142}'),
597 ("dotlessi", '\u{131}'),
598 ("nbspace", '\u{A0}'),
599 ("sfthyphen", '\u{AD}'),
600];
601
602const GLYPHS_GREEK: &[(&str, char)] = &[
605 ("Alpha", '\u{391}'),
606 ("Beta", '\u{392}'),
607 ("Gamma", '\u{393}'),
608 ("Delta", '\u{2206}'),
609 ("Epsilon", '\u{395}'),
610 ("Zeta", '\u{396}'),
611 ("Eta", '\u{397}'),
612 ("Theta", '\u{398}'),
613 ("Iota", '\u{399}'),
614 ("Kappa", '\u{39A}'),
615 ("Lambda", '\u{39B}'),
616 ("Mu", '\u{39C}'),
617 ("Nu", '\u{39D}'),
618 ("Xi", '\u{39E}'),
619 ("Omicron", '\u{39F}'),
620 ("Pi", '\u{3A0}'),
621 ("Rho", '\u{3A1}'),
622 ("Sigma", '\u{3A3}'),
623 ("Tau", '\u{3A4}'),
624 ("Upsilon", '\u{3A5}'),
625 ("Phi", '\u{3A6}'),
626 ("Chi", '\u{3A7}'),
627 ("Psi", '\u{3A8}'),
628 ("Omega", '\u{2126}'),
629 ("alpha", '\u{3B1}'),
630 ("beta", '\u{3B2}'),
631 ("gamma", '\u{3B3}'),
632 ("delta", '\u{3B4}'),
633 ("epsilon", '\u{3B5}'),
634 ("zeta", '\u{3B6}'),
635 ("eta", '\u{3B7}'),
636 ("theta", '\u{3B8}'),
637 ("iota", '\u{3B9}'),
638 ("kappa", '\u{3BA}'),
639 ("lambda", '\u{3BB}'),
640 ("nu", '\u{3BD}'),
641 ("xi", '\u{3BE}'),
642 ("omicron", '\u{3BF}'),
643 ("pi", '\u{3C0}'),
644 ("rho", '\u{3C1}'),
645 ("sigma", '\u{3C3}'),
646 ("sigma1", '\u{3C2}'),
647 ("tau", '\u{3C4}'),
648 ("upsilon", '\u{3C5}'),
649 ("phi", '\u{3C6}'),
650 ("chi", '\u{3C7}'),
651 ("psi", '\u{3C8}'),
652 ("omega", '\u{3C9}'),
653];
654
655const GLYPHS_MISC: &[(&str, char)] = &[
657 ("infinity", '\u{221E}'),
658 ("notequal", '\u{2260}'),
659 ("lessequal", '\u{2264}'),
660 ("greaterequal", '\u{2265}'),
661 ("partialdiff", '\u{2202}'),
662 ("summation", '\u{2211}'),
663 ("product", '\u{220F}'),
664 ("integral", '\u{222B}'),
665 ("radical", '\u{221A}'),
666 ("approxequal", '\u{2248}'),
667 ("equivalence", '\u{2261}'),
668 ("element", '\u{2208}'),
669 ("intersection", '\u{2229}'),
670 ("union", '\u{222A}'),
671 ("arrowleft", '\u{2190}'),
672 ("arrowup", '\u{2191}'),
673 ("arrowright", '\u{2192}'),
674 ("arrowdown", '\u{2193}'),
675 ("arrowboth", '\u{2194}'),
676 ("lozenge", '\u{25CA}'),
677 ("apple", '\u{F8FF}'),
678];
679
680#[cfg(test)]
681mod tests {
682 use super::*;
683
684 #[test]
685 fn win_ansi_spot_checks() {
686 assert_eq!(win_ansi(b'A'), Some('A'));
687 assert_eq!(win_ansi(0x93), Some('\u{201C}')); assert_eq!(win_ansi(0x80), Some('\u{20AC}')); assert_eq!(win_ansi(0xE9), Some('\u{E9}')); assert_eq!(win_ansi(0x81), None); assert_eq!(win_ansi(0x0A), None); }
693
694 #[test]
695 fn mac_roman_spot_checks() {
696 assert_eq!(mac_roman(b'A'), Some('A'));
697 assert_eq!(mac_roman(0xD0), Some('\u{2013}')); assert_eq!(mac_roman(0x80), Some('\u{C4}')); assert_eq!(mac_roman(0xA5), Some('\u{2022}')); assert_eq!(mac_roman(0xFF), Some('\u{2C7}')); assert_eq!(mac_roman(0x00), None);
702 }
703
704 #[test]
705 fn standard_spot_checks() {
706 assert_eq!(standard(b'A'), Some('A'));
707 assert_eq!(standard(0xA9), Some('\u{27}')); assert_eq!(standard(0x27), Some('\u{2019}')); assert_eq!(standard(0x60), Some('\u{2018}')); assert_eq!(standard(0xD0), Some('\u{2014}')); assert_eq!(standard(0x7F), None);
712 assert_eq!(standard(0xA0), None); }
714
715 #[test]
716 fn glyph_names_hex_forms() {
717 assert_eq!(glyph_to_unicode("uni03B1"), Some('\u{3B1}'));
718 assert_eq!(glyph_to_unicode("uni20AC"), Some('\u{20AC}'));
719 assert_eq!(glyph_to_unicode("u1F600"), Some('\u{1F600}'));
720 assert_eq!(glyph_to_unicode("u00E9"), Some('\u{E9}'));
721 assert_eq!(glyph_to_unicode("uniD800"), None); assert_eq!(glyph_to_unicode("uniXYZW"), None);
723 }
724
725 #[test]
734 fn standard_encoding_name_matches_standard_table() {
735 for code in 0u16..=255 {
736 let code = code as u8;
737 assert_eq!(
738 standard_encoding_name(code).is_some(),
739 standard(code).is_some(),
740 "code {code:#04x}: standard_encoding_name/standard domain mismatch"
741 );
742 if let (Some(name), Some(expected)) = (standard_encoding_name(code), standard(code)) {
743 if let Some(resolved) = glyph_to_unicode(name) {
744 assert_eq!(
745 resolved, expected,
746 "code {code:#04x} name {name:?}: glyph_to_unicode disagrees with standard"
747 );
748 }
749 }
750 }
751 }
752
753 #[test]
754 fn standard_encoding_name_spot_checks() {
755 assert_eq!(standard_encoding_name(b'A'), Some("A"));
756 assert_eq!(standard_encoding_name(0x27), Some("quoteright"));
757 assert_eq!(standard_encoding_name(0x60), Some("quoteleft"));
758 assert_eq!(standard_encoding_name(0xA1), Some("exclamdown"));
759 assert_eq!(standard_encoding_name(0xA4), Some("fraction"));
760 assert_eq!(standard_encoding_name(0xA6), Some("florin"));
761 assert_eq!(standard_encoding_name(0xC1), Some("grave"));
762 assert_eq!(standard_encoding_name(0xC6), Some("breve"));
763 assert_eq!(standard_encoding_name(0xE1), Some("AE"));
764 assert_eq!(standard_encoding_name(0xF1), Some("ae"));
765 assert_eq!(standard_encoding_name(0xFB), Some("germandbls"));
766 assert_eq!(standard_encoding_name(0x7F), None);
767 assert_eq!(standard_encoding_name(0xA0), None);
768 }
769
770 #[test]
771 fn glyph_names_letters_and_tables() {
772 assert_eq!(glyph_to_unicode("A"), Some('A'));
773 assert_eq!(glyph_to_unicode("z"), Some('z'));
774 assert_eq!(glyph_to_unicode("alpha"), Some('\u{3B1}'));
775 assert_eq!(glyph_to_unicode("eacute"), Some('\u{E9}'));
776 assert_eq!(glyph_to_unicode("quotedblleft"), Some('\u{201C}'));
777 assert_eq!(glyph_to_unicode("seven"), Some('7'));
778 assert_eq!(glyph_to_unicode("union"), Some('\u{222A}'));
779 assert_eq!(glyph_to_unicode("nosuchglyphname"), None);
780 }
781
782 #[test]
783 fn glyph_text_ligatures_and_variants() {
784 assert_eq!(glyph_to_text("f_i").as_deref(), Some("fi"));
785 assert_eq!(glyph_to_text("f_l").as_deref(), Some("fl"));
786 assert_eq!(glyph_to_text("T_h").as_deref(), Some("Th"));
787 assert_eq!(glyph_to_text("f_f_i").as_deref(), Some("ffi"));
788 assert_eq!(glyph_to_text("eight.oldstyle").as_deref(), Some("8"));
789 assert_eq!(glyph_to_text("x.sc").as_deref(), Some("x"));
790 assert_eq!(glyph_to_text("C.a").as_deref(), Some("C"));
791 assert_eq!(glyph_to_text("f_i.alt").as_deref(), Some("fi"));
793 assert_eq!(glyph_to_text("uni00A0").as_deref(), Some("\u{A0}"));
794 assert_eq!(glyph_to_text("eacute").as_deref(), Some("\u{E9}"));
795 }
796
797 #[test]
798 fn glyph_text_multi_group_uni() {
799 assert_eq!(
800 glyph_to_text("uni20AC0308").as_deref(),
801 Some("\u{20AC}\u{0308}")
802 );
803 assert_eq!(glyph_to_text("uniD800DC00"), None); }
805
806 #[test]
807 fn glyph_text_rejects_unknowns() {
808 assert_eq!(glyph_to_text(".notdef"), None);
809 assert_eq!(glyph_to_text(""), None);
810 assert_eq!(glyph_to_text("glorp"), None);
811 assert_eq!(glyph_to_text("f_glorp"), None);
813 assert_eq!(glyph_to_text("f__i"), None);
814 }
815}