font_map_core/raw/ttf/
post.rs

1#![allow(clippy::cast_possible_wrap)]
2#![allow(clippy::cast_possible_truncation)]
3use crate::error::ParseResult;
4use crate::reader::{BinaryReader, Parse};
5
6/// The Post table of a TrueType font  
7/// Contains only the subset of the table needed for mapping glyph indices to glyph names
8#[derive(Debug, Default)]
9pub struct PostTable {
10    /// True if the font is monospaced
11    pub is_monospaced: bool,
12
13    /// The glyph names in the table, by glyph index
14    pub glyph_names: Vec<String>,
15}
16
17impl PostTable {
18    /// Returns the name of the glyph at the specified index, if it exists
19    #[must_use]
20    pub fn get_glyph_name(&self, index: u16) -> Option<&str> {
21        self.glyph_names.get(index as usize).map(String::as_str)
22    }
23}
24
25impl Parse for PostTable {
26    fn parse(reader: &mut BinaryReader) -> ParseResult<Self> {
27        let mut table = Self::default();
28
29        //
30        // Table header
31        let fmt = reader.read_fixed32()?;
32        reader.skip_u32()?; // italic angle
33        reader.skip_u16()?; // underline position
34        reader.skip_u16()?; // underline thickness
35        table.is_monospaced = reader.read_u32()? != 0; // is fixed pitch
36        reader.skip_u32()?; // min memory t42
37        reader.skip_u32()?; // max memory t42
38        reader.skip_u32()?; // min memory t1
39        reader.skip_u32()?; // max memory t1
40
41        debug_msg!("  Format = {}.{}", fmt.0, fmt.1);
42
43        match fmt {
44            (1, 0) => {
45                //
46                // Format 1.0 uses the standard Macintosh character set
47                table.glyph_names = POST_MAC_NAMES.iter().map(ToString::to_string).collect();
48            }
49
50            (2, 0) => {
51                //
52                // Format 2.0 uses a 32-bit offset to the glyph name
53                let num_glyphs = reader.read_u16()?;
54                debug_msg!("  Num glyphs = {}", num_glyphs);
55
56                //
57                // Read the glyph names first
58                let mut names = Vec::with_capacity(num_glyphs as usize);
59                let mut name_reader = reader.clone();
60                name_reader.advance_by(num_glyphs as isize * 2)?;
61                while !name_reader.is_eof() {
62                    let len = name_reader.read_u8()?;
63                    let name = name_reader.read_string(len as usize)?;
64                    names.push(name);
65                }
66
67                for _ in 0..num_glyphs {
68                    let ordinal = reader.read_u16()?;
69                    if ordinal < POST_MAC_NAMES_LEN as u16 {
70                        table
71                            .glyph_names
72                            .push(POST_MAC_NAMES[ordinal as usize].to_string());
73                    } else {
74                        let index = (ordinal - POST_MAC_NAMES_LEN as u16) as usize;
75                        table.glyph_names.push(names[index].clone());
76                    }
77                }
78            }
79
80            (2, 5) => {
81                //
82                // Format 2.5 uses an 8-bit offset to the std glyph names
83                let num_glyphs = reader.read_u16()?;
84
85                let mut glyph_names = Vec::new();
86                for i in 0..num_glyphs {
87                    let offset = reader.read_i8()?;
88                    let index = i.wrapping_add_signed(i16::from(offset));
89                    glyph_names.push(POST_MAC_NAMES[index as usize].to_string());
90                }
91            }
92
93            _ => {
94                // Other formats are not useful to us here
95            }
96        }
97
98        debug_msg!("  Found {} glyph names", table.glyph_names.len());
99        Ok(table)
100    }
101}
102
103//
104// Standard Macintosh glyph names
105const POST_MAC_NAMES_LEN: usize = 258;
106#[rustfmt::skip]
107const POST_MAC_NAMES: [&str; POST_MAC_NAMES_LEN] = [
108    ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", 
109    "ampersand", "quotesingle","parenleft","parenright","asterisk","plus","comma", "hyphen", "period", "slash", 
110    "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
111    "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
112    "O",  "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", 
113    "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", 
114    "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring", 
115    "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", 
116    "atilde", "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave",
117    "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", 
118    "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", 
119    "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", 
120    "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", 
121    "ordmasculine", "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", 
122    "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", "OE", "oe", 
123    "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", 
124    "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", 
125    "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", 
126    "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", 
127    "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", 
128    "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", 
129    "yacute", "Thorn", "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", 
130    "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", 
131    "ccaron", "dcroat"
132];