read_fonts/ps/cff/
encoding.rs1use super::charset::Charset;
9use crate::{
10 ps::{encoding::PredefinedEncoding, string::Sid},
11 FontData, GlyphId,
12};
13
14#[doc(inline)]
15pub use super::v1::{EncodingRange1 as Range1, EncodingSupplement as Supplement};
16
17#[derive(Clone)]
21pub enum Encoding<'a> {
22 Predefined(PredefinedEncoding),
23 Custom(CustomEncoding<'a>),
24}
25
26impl<'a> Encoding<'a> {
27 pub fn new(data: &'a [u8], offset: usize) -> Option<Self> {
32 match offset {
33 0 => Some(Self::Predefined(PredefinedEncoding::Standard)),
34 1 => Some(Self::Predefined(PredefinedEncoding::Expert)),
35 _ => CustomEncoding::new(data.get(offset..)?).map(Self::Custom),
36 }
37 }
38
39 pub fn map(&self, charset: &Charset, code: u8) -> Option<GlyphId> {
41 match self {
42 Self::Predefined(predefined) => charset.glyph_id(predefined.sid(code)?),
43 Self::Custom(custom) => custom.map(charset, code),
44 }
45 }
46}
47
48#[derive(Clone)]
50pub enum CustomEncoding<'a> {
51 Format0(&'a [u8], &'a [Supplement]),
54 Format1(&'a [Range1], &'a [Supplement]),
56}
57
58impl<'a> CustomEncoding<'a> {
59 pub fn new(data: &'a [u8]) -> Option<Self> {
61 let mut cursor = FontData::new(data).cursor();
62 let header = cursor.read::<u8>().ok()?;
63 let has_supplement = header & 0x80 != 0;
64 macro_rules! read_supplement {
66 () => {
67 if has_supplement {
68 let count = cursor.read::<u8>().ok()?;
69 cursor.read_array::<Supplement>(count as usize).ok()?
70 } else {
71 &[]
72 }
73 };
74 }
75 let format = header & 0x7F;
76 match format {
77 0 => {
78 let n_codes = cursor.read::<u8>().ok()?;
79 let codes = cursor.read_array(n_codes as usize).ok()?;
80 let supp = read_supplement!();
81 Some(Self::Format0(codes, supp))
82 }
83 1 => {
84 let n_ranges = cursor.read::<u8>().ok()?;
85 let ranges = cursor.read_array(n_ranges as usize).ok()?;
86 let supp = read_supplement!();
87 Some(Self::Format1(ranges, supp))
88 }
89 _ => None,
91 }
92 }
93
94 pub fn map(&self, charset: &Charset, code: u8) -> Option<GlyphId> {
96 let read_sup = |sup: &[Supplement]| {
97 sup.iter()
98 .find(|s| s.code == code)
99 .and_then(|s| charset.glyph_id(Sid::new(s.glyph.get())))
100 };
101 match self {
102 Self::Format0(codes, sup) => read_sup(sup).or_else(|| {
103 codes
104 .iter()
105 .position(|c| *c == code)
106 .map(|gid| GlyphId::new(gid as u32 + 1))
108 }),
109 Self::Format1(ranges, sup) => read_sup(sup).or_else(|| {
110 let mut gid = 1u32;
111 for range in ranges.iter() {
112 let end = range.first.saturating_add(range.n_left);
113 if (range.first..=end).contains(&code) {
114 gid += (code - range.first) as u32;
115 return Some(GlyphId::new(gid));
116 }
117 gid += range.n_left as u32 + 1;
118 }
119 None
120 }),
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn predefined_standard() {
131 let encoding = Encoding::Predefined(PredefinedEncoding::Standard);
132 let charset = iso_adobe_charset();
133 for code in 0..=255 {
134 let gid = encoding.map(&charset, code);
135 assert_eq!(
136 gid.unwrap(),
137 charset
138 .glyph_id(PredefinedEncoding::Standard.sid(code).unwrap())
139 .unwrap()
140 );
141 }
142 }
143
144 #[test]
145 fn predefined_expert() {
146 let encoding = Encoding::Predefined(PredefinedEncoding::Expert);
147 let charset = iso_expert_charset();
148 for code in 0..=255 {
149 let gid = encoding.map(&charset, code);
150 assert_eq!(
151 gid.unwrap(),
152 charset
153 .glyph_id(PredefinedEncoding::Expert.sid(code).unwrap())
154 .unwrap()
155 );
156 }
157 }
158
159 #[test]
160 fn custom_format_0() {
161 let codes = [3, 8, 9, 10, 11];
162 let encoding = Encoding::Custom(CustomEncoding::Format0(&codes, &[]));
163 let charset = iso_adobe_charset();
164 for (i, code) in codes.into_iter().enumerate() {
165 assert_eq!(
166 encoding.map(&charset, code).unwrap(),
167 GlyphId::new(i as u32 + 1)
168 );
169 }
170 }
171
172 #[test]
173 fn custom_format_1() {
174 let ranges = [(51, 4), (250, 5)].map(|(first, n_left)| Range1 { first, n_left });
175 let encoding = Encoding::Custom(CustomEncoding::Format1(&ranges, &[]));
176 let charset = iso_adobe_charset();
177 for code in 0..=255 {
178 let gid = encoding.map(&charset, code);
179 let expected = match code {
180 51..=55 => Some(code as u32 - 50),
181 250..=255 => Some(code as u32 - 250 + 6),
182 _ => None,
183 };
184 assert_eq!(gid, expected.map(GlyphId::new));
185 }
186 }
187
188 #[test]
189 fn supplemental() {
190 let supplement = [(40, 91), (122, 9)].map(|(code, glyph)| Supplement {
192 code,
193 glyph: glyph.into(),
194 });
195 let encoding = Encoding::Custom(CustomEncoding::Format0(&[], &supplement));
196 let charset = iso_adobe_charset();
197 assert_eq!(encoding.map(&charset, 40).unwrap().to_u32(), 91);
198 assert_eq!(encoding.map(&charset, 122).unwrap().to_u32(), 9);
199 assert_eq!(
200 charset
201 .string_id(91u32.into())
202 .unwrap()
203 .resolve_standard()
204 .unwrap(),
205 b"z"
206 );
207 assert_eq!(
208 charset
209 .string_id(9u32.into())
210 .unwrap()
211 .resolve_standard()
212 .unwrap(),
213 b"parenleft"
214 );
215 }
216
217 fn iso_adobe_charset() -> Charset<'static> {
218 Charset::new(Default::default(), 0, 256).unwrap()
219 }
220
221 fn iso_expert_charset() -> Charset<'static> {
222 Charset::new(Default::default(), 1, 256).unwrap()
223 }
224}