ttf_parser/tables/cff/
charset.rs

1use super::StringId;
2use crate::parser::{FromData, LazyArray16, Stream};
3use crate::GlyphId;
4use core::num::NonZeroU16;
5
6/// The Expert Encoding conversion as defined in the Adobe Technical Note #5176 Appendix C.
7#[rustfmt::skip]
8#[cfg(feature = "glyph-names")]
9const EXPERT_ENCODING: &[u16] = &[
10      0,    1,  229,  230,  231,  232,  233,  234,  235,  236,  237,  238,   13,   14,   15,   99,
11    239,  240,  241,  242,  243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  252,
12    253,  254,  255,  256,  257,  258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110,
13    267,  268,  269,  270,  271,  272,  273,  274,  275,  276,  277,  278,  279,  280,  281,  282,
14    283,  284,  285,  286,  287,  288,  289,  290,  291,  292,  293,  294,  295,  296,  297,  298,
15    299,  300,  301,  302,  303,  304,  305,  306,  307,  308,  309,  310,  311,  312,  313,  314,
16    315,  316,  317,  318,  158,  155,  163,  319,  320,  321,  322,  323,  324,  325,  326,  150,
17    164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339,  340,
18    341,  342,  343,  344,  345,  346,  347,  348,  349,  350,  351,  352,  353,  354,  355,  356,
19    357,  358,  359,  360,  361,  362,  363,  364,  365,  366,  367,  368,  369,  370,  371,  372,
20    373,  374,  375,  376,  377,  378,
21];
22
23/// The Expert Subset Encoding conversion as defined in the Adobe Technical Note #5176 Appendix C.
24#[rustfmt::skip]
25#[cfg(feature = "glyph-names")]
26const EXPERT_SUBSET_ENCODING: &[u16] = &[
27      0,    1,  231,  232,  235,  236,  237,  238,   13,   14,   15,   99,  239,  240,  241,  242,
28    243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  253,  254,  255,  256,  257,
29    258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110,  267,  268,  269,  270,  272,
30    300,  301,  302,  305,  314,  315,  158,  155,  163,  320,  321,  322,  323,  324,  325,  326,
31    150,  164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339,
32    340,  341,  342,  343,  344,  345,  346
33];
34
35#[derive(Clone, Copy, Debug)]
36pub(crate) struct Format1Range {
37    first: StringId,
38    left: u8,
39}
40
41impl FromData for Format1Range {
42    const SIZE: usize = 3;
43
44    #[inline]
45    fn parse(data: &[u8]) -> Option<Self> {
46        let mut s = Stream::new(data);
47        Some(Format1Range {
48            first: s.read::<StringId>()?,
49            left: s.read::<u8>()?,
50        })
51    }
52}
53
54#[derive(Clone, Copy, Debug)]
55pub(crate) struct Format2Range {
56    first: StringId,
57    left: u16,
58}
59
60impl FromData for Format2Range {
61    const SIZE: usize = 4;
62
63    #[inline]
64    fn parse(data: &[u8]) -> Option<Self> {
65        let mut s = Stream::new(data);
66        Some(Format2Range {
67            first: s.read::<StringId>()?,
68            left: s.read::<u16>()?,
69        })
70    }
71}
72
73#[derive(Clone, Copy, Debug)]
74pub(crate) enum Charset<'a> {
75    ISOAdobe,
76    Expert,
77    ExpertSubset,
78    Format0(LazyArray16<'a, StringId>),
79    Format1(LazyArray16<'a, Format1Range>),
80    Format2(LazyArray16<'a, Format2Range>),
81}
82
83impl Charset<'_> {
84    pub fn sid_to_gid(&self, sid: StringId) -> Option<GlyphId> {
85        if sid.0 == 0 {
86            return Some(GlyphId(0));
87        }
88
89        match self {
90            Charset::ISOAdobe | Charset::Expert | Charset::ExpertSubset => None,
91            Charset::Format0(ref array) => {
92                // First glyph is omitted, so we have to add 1.
93                array
94                    .into_iter()
95                    .position(|n| n == sid)
96                    .map(|n| GlyphId(n as u16 + 1))
97            }
98            Charset::Format1(array) => {
99                let mut glyph_id = GlyphId(1);
100                for range in *array {
101                    let last = u32::from(range.first.0) + u32::from(range.left);
102                    if range.first <= sid && u32::from(sid.0) <= last {
103                        glyph_id.0 += sid.0 - range.first.0;
104                        return Some(glyph_id);
105                    }
106
107                    glyph_id.0 += u16::from(range.left) + 1;
108                }
109
110                None
111            }
112            Charset::Format2(array) => {
113                // The same as format 1, but Range::left is u16.
114                let mut glyph_id = GlyphId(1);
115                for range in *array {
116                    let last = u32::from(range.first.0) + u32::from(range.left);
117                    if sid >= range.first && u32::from(sid.0) <= last {
118                        glyph_id.0 += sid.0 - range.first.0;
119                        return Some(glyph_id);
120                    }
121
122                    glyph_id.0 += range.left + 1;
123                }
124
125                None
126            }
127        }
128    }
129
130    #[cfg(feature = "glyph-names")]
131    pub fn gid_to_sid(&self, gid: GlyphId) -> Option<StringId> {
132        match self {
133            Charset::ISOAdobe => {
134                if gid.0 <= 228 {
135                    Some(StringId(gid.0))
136                } else {
137                    None
138                }
139            }
140            Charset::Expert => EXPERT_ENCODING
141                .get(usize::from(gid.0))
142                .cloned()
143                .map(StringId),
144            Charset::ExpertSubset => EXPERT_SUBSET_ENCODING
145                .get(usize::from(gid.0))
146                .cloned()
147                .map(StringId),
148            Charset::Format0(ref array) => {
149                if gid.0 == 0 {
150                    Some(StringId(0))
151                } else {
152                    array.get(gid.0 - 1)
153                }
154            }
155            Charset::Format1(array) => {
156                if gid.0 == 0 {
157                    Some(StringId(0))
158                } else {
159                    let mut sid = gid.0 - 1;
160                    for range in *array {
161                        if sid <= u16::from(range.left) {
162                            sid = sid.checked_add(range.first.0)?;
163                            return Some(StringId(sid));
164                        }
165
166                        sid = sid.checked_sub(u16::from(range.left) + 1)?;
167                    }
168
169                    None
170                }
171            }
172            Charset::Format2(array) => {
173                if gid.0 == 0 {
174                    Some(StringId(0))
175                } else {
176                    let mut sid = gid.0 - 1;
177                    for range in *array {
178                        if sid <= range.left {
179                            sid = sid.checked_add(range.first.0)?;
180                            return Some(StringId(sid));
181                        }
182
183                        sid = sid.checked_sub(range.left.checked_add(1)?)?;
184                    }
185
186                    None
187                }
188            }
189        }
190    }
191}
192
193pub(crate) fn parse_charset<'a>(
194    number_of_glyphs: NonZeroU16,
195    s: &mut Stream<'a>,
196) -> Option<Charset<'a>> {
197    // -1 everywhere, since `.notdef` is omitted.
198    let format = s.read::<u8>()?;
199    match format {
200        0 => Some(Charset::Format0(
201            s.read_array16::<StringId>(number_of_glyphs.get() - 1)?,
202        )),
203        1 => {
204            // The number of ranges is not defined, so we have to
205            // read until no glyphs are left.
206            let mut count = 0;
207            {
208                let mut s = s.clone();
209                let mut total_left = number_of_glyphs.get() - 1;
210                while total_left > 0 {
211                    s.skip::<StringId>(); // first
212                    let left = s.read::<u8>()?;
213                    total_left = total_left.checked_sub(u16::from(left) + 1)?;
214                    count += 1;
215                }
216            }
217
218            s.read_array16::<Format1Range>(count).map(Charset::Format1)
219        }
220        2 => {
221            // The same as format 1, but Range::left is u16.
222            let mut count = 0;
223            {
224                let mut s = s.clone();
225                let mut total_left = number_of_glyphs.get() - 1;
226                while total_left > 0 {
227                    s.skip::<StringId>(); // first
228                    let left = s.read::<u16>()?.checked_add(1)?;
229                    total_left = total_left.checked_sub(left)?;
230                    count += 1;
231                }
232            }
233
234            s.read_array16::<Format2Range>(count).map(Charset::Format2)
235        }
236        _ => None,
237    }
238}