1include!("../../generated/generated_post.rs");
4
5impl<'a> Post<'a> {
6 pub fn num_names(&self) -> usize {
8 match self.version() {
9 Version16Dot16::VERSION_1_0 => DEFAULT_GLYPH_NAMES.len(),
10 Version16Dot16::VERSION_2_0 => self.num_glyphs().unwrap() as usize,
11 _ => 0,
12 }
13 }
14
15 pub fn glyph_name(&self, glyph_id: GlyphId16) -> Option<&str> {
16 let glyph_id = glyph_id.to_u16() as usize;
17 match self.version() {
18 Version16Dot16::VERSION_1_0 => DEFAULT_GLYPH_NAMES.get(glyph_id).copied(),
19 Version16Dot16::VERSION_2_0 => {
20 let idx = self.glyph_name_index()?.get(glyph_id)?.get() as usize;
21 if idx < DEFAULT_GLYPH_NAMES.len() {
22 return DEFAULT_GLYPH_NAMES.get(idx).copied();
23 }
24 let idx = idx - DEFAULT_GLYPH_NAMES.len();
25 match self.string_data().unwrap().get(idx) {
26 Some(Ok(s)) => Some(s.0),
27 _ => None,
28 }
29 }
30 _ => None,
31 }
32 }
33
34 #[cfg(feature = "experimental_traverse")]
37 fn traverse_string_data(&self) -> FieldType<'a> {
38 FieldType::I8(-42) }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub struct PString<'a>(&'a str);
48
49impl<'a> PString<'a> {
50 pub fn as_str(&self) -> &'a str {
51 self.0
52 }
53}
54
55impl std::ops::Deref for PString<'_> {
56 type Target = str;
57 fn deref(&self) -> &Self::Target {
58 self.0
59 }
60}
61
62impl PartialEq<&str> for PString<'_> {
63 fn eq(&self, other: &&str) -> bool {
64 self.0 == *other
65 }
66}
67
68impl<'a> FontRead<'a> for PString<'a> {
69 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
70 let len: u8 = data.read_at(0)?;
71 let pstring = data
72 .as_bytes()
73 .get(1..len as usize + 1)
74 .ok_or(ReadError::OutOfBounds)?;
75
76 if pstring.is_ascii() {
77 Ok(PString(std::str::from_utf8(pstring).unwrap()))
78 } else {
79 Err(ReadError::MalformedData("Must be valid ascii"))
81 }
82 }
83}
84
85impl VarSize for PString<'_> {
86 type Size = u8;
87}
88
89#[rustfmt::skip]
91pub static DEFAULT_GLYPH_NAMES: [&str; 258] = [
92 ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar",
93 "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma",
94 "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
95 "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B",
96 "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
97 "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
98 "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
99 "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
100 "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
101 "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute",
102 "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde",
103 "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex",
104 "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph",
105 "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE",
106 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff",
107 "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae",
108 "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal",
109 "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
110 "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft",
111 "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
112 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase",
113 "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave",
114 "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve",
115 "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve",
116 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash",
117 "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn",
118 "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
119 "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla",
120 "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", "dcroat",
121];
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use font_test_data::{bebuffer::BeBuffer, post as test_data};
127
128 #[test]
129 fn test_post() {
130 let table = Post::read(test_data::SIMPLE.into()).unwrap();
131 assert_eq!(table.version(), Version16Dot16::VERSION_2_0);
132 assert_eq!(table.underline_position(), FWord::new(-75));
133 assert_eq!(table.glyph_name(GlyphId16::new(1)), Some(".notdef"));
134 assert_eq!(table.glyph_name(GlyphId16::new(2)), Some("space"));
135 assert_eq!(table.glyph_name(GlyphId16::new(7)), Some("hello"));
136 assert_eq!(table.glyph_name(GlyphId16::new(8)), Some("hi"));
137 assert_eq!(table.glyph_name(GlyphId16::new(9)), Some("hola"));
138 }
139
140 #[test]
141 fn parse_versioned_fields() {
142 fn make_basic_post(version: Version16Dot16) -> BeBuffer {
143 BeBuffer::new()
144 .push(version)
145 .push(Fixed::from_i32(5))
146 .extend([FWord::new(6), FWord::new(7)]) .push(0u32) .extend([7u32, 8, 9, 10]) }
150
151 let buf = make_basic_post(Version16Dot16::VERSION_2_0);
153 assert!(Post::read(buf.data().into()).is_err());
154
155 let buf = make_basic_post(Version16Dot16::VERSION_3_0);
157 assert!(Post::read(buf.data().into()).is_ok());
158 }
159}