1 | //! A [Compact Font Format Table]( |
2 | //! https://docs.microsoft.com/en-us/typography/opentype/spec/cff) implementation. |
3 | |
4 | // Useful links: |
5 | // http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf |
6 | // http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf |
7 | // https://github.com/opentypejs/opentype.js/blob/master/src/tables/cff.js |
8 | |
9 | use core::convert::TryFrom; |
10 | use core::num::NonZeroU16; |
11 | use core::ops::Range; |
12 | |
13 | use super::argstack::ArgumentsStack; |
14 | use super::charset::{parse_charset, Charset}; |
15 | use super::charstring::CharStringParser; |
16 | use super::dict::DictionaryParser; |
17 | use super::encoding::{parse_encoding, Encoding, STANDARD_ENCODING}; |
18 | use super::index::{parse_index, skip_index, Index}; |
19 | #[cfg (feature = "glyph-names" )] |
20 | use super::std_names::STANDARD_NAMES; |
21 | use super::{calc_subroutine_bias, conv_subroutine_index, Builder, CFFError, IsEven, StringId}; |
22 | use crate::parser::{LazyArray16, NumFrom, Stream, TryNumFrom}; |
23 | use crate::{BBox, Fixed, GlyphId, OutlineBuilder, Rect}; |
24 | |
25 | // Limits according to the Adobe Technical Note #5176, chapter 4 DICT Data. |
26 | const MAX_OPERANDS_LEN: usize = 48; |
27 | |
28 | // Limits according to the Adobe Technical Note #5177 Appendix B. |
29 | const STACK_LIMIT: u8 = 10; |
30 | const MAX_ARGUMENTS_STACK_LEN: usize = 48; |
31 | |
32 | const TWO_BYTE_OPERATOR_MARK: u8 = 12; |
33 | |
34 | /// Enumerates some operators defined in the Adobe Technical Note #5177. |
35 | mod operator { |
36 | pub const HORIZONTAL_STEM: u8 = 1; |
37 | pub const VERTICAL_STEM: u8 = 3; |
38 | pub const VERTICAL_MOVE_TO: u8 = 4; |
39 | pub const LINE_TO: u8 = 5; |
40 | pub const HORIZONTAL_LINE_TO: u8 = 6; |
41 | pub const VERTICAL_LINE_TO: u8 = 7; |
42 | pub const CURVE_TO: u8 = 8; |
43 | pub const CALL_LOCAL_SUBROUTINE: u8 = 10; |
44 | pub const RETURN: u8 = 11; |
45 | pub const ENDCHAR: u8 = 14; |
46 | pub const HORIZONTAL_STEM_HINT_MASK: u8 = 18; |
47 | pub const HINT_MASK: u8 = 19; |
48 | pub const COUNTER_MASK: u8 = 20; |
49 | pub const MOVE_TO: u8 = 21; |
50 | pub const HORIZONTAL_MOVE_TO: u8 = 22; |
51 | pub const VERTICAL_STEM_HINT_MASK: u8 = 23; |
52 | pub const CURVE_LINE: u8 = 24; |
53 | pub const LINE_CURVE: u8 = 25; |
54 | pub const VV_CURVE_TO: u8 = 26; |
55 | pub const HH_CURVE_TO: u8 = 27; |
56 | pub const SHORT_INT: u8 = 28; |
57 | pub const CALL_GLOBAL_SUBROUTINE: u8 = 29; |
58 | pub const VH_CURVE_TO: u8 = 30; |
59 | pub const HV_CURVE_TO: u8 = 31; |
60 | pub const HFLEX: u8 = 34; |
61 | pub const FLEX: u8 = 35; |
62 | pub const HFLEX1: u8 = 36; |
63 | pub const FLEX1: u8 = 37; |
64 | pub const FIXED_16_16: u8 = 255; |
65 | } |
66 | |
67 | /// Enumerates some operators defined in the Adobe Technical Note #5176, |
68 | /// Table 9 Top DICT Operator Entries |
69 | mod top_dict_operator { |
70 | pub const CHARSET_OFFSET: u16 = 15; |
71 | pub const ENCODING_OFFSET: u16 = 16; |
72 | pub const CHAR_STRINGS_OFFSET: u16 = 17; |
73 | pub const PRIVATE_DICT_SIZE_AND_OFFSET: u16 = 18; |
74 | pub const FONT_MATRIX: u16 = 1207; |
75 | pub const ROS: u16 = 1230; |
76 | pub const FD_ARRAY: u16 = 1236; |
77 | pub const FD_SELECT: u16 = 1237; |
78 | } |
79 | |
80 | /// Enumerates some operators defined in the Adobe Technical Note #5176, |
81 | /// Table 23 Private DICT Operators |
82 | mod private_dict_operator { |
83 | pub const LOCAL_SUBROUTINES_OFFSET: u16 = 19; |
84 | pub const DEFAULT_WIDTH: u16 = 20; |
85 | pub const NOMINAL_WIDTH: u16 = 21; |
86 | } |
87 | |
88 | /// Enumerates Charset IDs defined in the Adobe Technical Note #5176, Table 22 |
89 | mod charset_id { |
90 | pub const ISO_ADOBE: usize = 0; |
91 | pub const EXPERT: usize = 1; |
92 | pub const EXPERT_SUBSET: usize = 2; |
93 | } |
94 | |
95 | /// Enumerates Charset IDs defined in the Adobe Technical Note #5176, Table 16 |
96 | mod encoding_id { |
97 | pub const STANDARD: usize = 0; |
98 | pub const EXPERT: usize = 1; |
99 | } |
100 | |
101 | #[derive (Clone, Copy, Debug)] |
102 | pub(crate) enum FontKind<'a> { |
103 | SID(SIDMetadata<'a>), |
104 | CID(CIDMetadata<'a>), |
105 | } |
106 | |
107 | #[derive (Clone, Copy, Default, Debug)] |
108 | pub(crate) struct SIDMetadata<'a> { |
109 | local_subrs: Index<'a>, |
110 | /// Can be zero. |
111 | default_width: f32, |
112 | /// Can be zero. |
113 | nominal_width: f32, |
114 | encoding: Encoding<'a>, |
115 | } |
116 | |
117 | #[derive (Clone, Copy, Default, Debug)] |
118 | pub(crate) struct CIDMetadata<'a> { |
119 | fd_array: Index<'a>, |
120 | fd_select: FDSelect<'a>, |
121 | } |
122 | |
123 | /// An affine transformation matrix. |
124 | #[allow (missing_docs)] |
125 | #[derive (Clone, Copy, Debug)] |
126 | pub struct Matrix { |
127 | pub sx: f32, |
128 | pub ky: f32, |
129 | pub kx: f32, |
130 | pub sy: f32, |
131 | pub tx: f32, |
132 | pub ty: f32, |
133 | } |
134 | |
135 | impl Default for Matrix { |
136 | fn default() -> Self { |
137 | Self { |
138 | sx: 0.001, |
139 | ky: 0.0, |
140 | kx: 0.0, |
141 | sy: 0.001, |
142 | tx: 0.0, |
143 | ty: 0.0, |
144 | } |
145 | } |
146 | } |
147 | |
148 | #[derive (Default)] |
149 | struct TopDict { |
150 | charset_offset: Option<usize>, |
151 | encoding_offset: Option<usize>, |
152 | char_strings_offset: usize, |
153 | private_dict_range: Option<Range<usize>>, |
154 | matrix: Matrix, |
155 | has_ros: bool, |
156 | fd_array_offset: Option<usize>, |
157 | fd_select_offset: Option<usize>, |
158 | } |
159 | |
160 | fn parse_top_dict(s: &mut Stream) -> Option<TopDict> { |
161 | let mut top_dict = TopDict::default(); |
162 | |
163 | let index = parse_index::<u16>(s)?; |
164 | |
165 | // The Top DICT INDEX should have only one dictionary. |
166 | let data = index.get(0)?; |
167 | |
168 | let mut operands_buffer = [0.0; MAX_OPERANDS_LEN]; |
169 | let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer); |
170 | while let Some(operator) = dict_parser.parse_next() { |
171 | match operator.get() { |
172 | top_dict_operator::CHARSET_OFFSET => { |
173 | top_dict.charset_offset = dict_parser.parse_offset(); |
174 | } |
175 | top_dict_operator::ENCODING_OFFSET => { |
176 | top_dict.encoding_offset = dict_parser.parse_offset(); |
177 | } |
178 | top_dict_operator::CHAR_STRINGS_OFFSET => { |
179 | top_dict.char_strings_offset = dict_parser.parse_offset()?; |
180 | } |
181 | top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET => { |
182 | top_dict.private_dict_range = dict_parser.parse_range(); |
183 | } |
184 | top_dict_operator::FONT_MATRIX => { |
185 | dict_parser.parse_operands()?; |
186 | let operands = dict_parser.operands(); |
187 | if operands.len() == 6 { |
188 | top_dict.matrix = Matrix { |
189 | sx: operands[0] as f32, |
190 | ky: operands[1] as f32, |
191 | kx: operands[2] as f32, |
192 | sy: operands[3] as f32, |
193 | tx: operands[4] as f32, |
194 | ty: operands[5] as f32, |
195 | }; |
196 | } |
197 | } |
198 | top_dict_operator::ROS => { |
199 | top_dict.has_ros = true; |
200 | } |
201 | top_dict_operator::FD_ARRAY => { |
202 | top_dict.fd_array_offset = dict_parser.parse_offset(); |
203 | } |
204 | top_dict_operator::FD_SELECT => { |
205 | top_dict.fd_select_offset = dict_parser.parse_offset(); |
206 | } |
207 | _ => {} |
208 | } |
209 | } |
210 | |
211 | Some(top_dict) |
212 | } |
213 | |
214 | // TODO: move to integration |
215 | #[cfg (test)] |
216 | mod tests { |
217 | use super::*; |
218 | |
219 | #[test ] |
220 | fn private_dict_size_overflow() { |
221 | let data = &[ |
222 | 0x00, 0x01, // count: 1 |
223 | 0x01, // offset size: 1 |
224 | 0x01, // index [0]: 1 |
225 | 0x0C, // index [1]: 14 |
226 | 0x1D, 0x7F, 0xFF, 0xFF, 0xFF, // length: i32::MAX |
227 | 0x1D, 0x7F, 0xFF, 0xFF, 0xFF, // offset: i32::MAX |
228 | 0x12, // operator: 18 (private) |
229 | ]; |
230 | |
231 | let top_dict = parse_top_dict(&mut Stream::new(data)).unwrap(); |
232 | assert_eq!(top_dict.private_dict_range, Some(2147483647..4294967294)); |
233 | } |
234 | |
235 | #[test ] |
236 | fn private_dict_negative_char_strings_offset() { |
237 | let data = &[ |
238 | 0x00, 0x01, // count: 1 |
239 | 0x01, // offset size: 1 |
240 | 0x01, // index [0]: 1 |
241 | 0x03, // index [1]: 3 |
242 | // Item 0 |
243 | 0x8A, // offset: -1 |
244 | 0x11, // operator: 17 (char_string) |
245 | ]; |
246 | |
247 | assert!(parse_top_dict(&mut Stream::new(data)).is_none()); |
248 | } |
249 | |
250 | #[test ] |
251 | fn private_dict_no_char_strings_offset_operand() { |
252 | let data = &[ |
253 | 0x00, 0x01, // count: 1 |
254 | 0x01, // offset size: 1 |
255 | 0x01, // index [0]: 1 |
256 | 0x02, // index [1]: 2 |
257 | // Item 0 |
258 | // <-- No number here. |
259 | 0x11, // operator: 17 (char_string) |
260 | ]; |
261 | |
262 | assert!(parse_top_dict(&mut Stream::new(data)).is_none()); |
263 | } |
264 | |
265 | #[test ] |
266 | fn negative_private_dict_offset_and_size() { |
267 | let data = &[ |
268 | 0x00, 0x01, // count: 1 |
269 | 0x01, // offset size: 1 |
270 | 0x01, // index [0]: 1 |
271 | 0x04, // index [1]: 4 |
272 | // Item 0 |
273 | 0x8A, // length: -1 |
274 | 0x8A, // offset: -1 |
275 | 0x12, // operator: 18 (private) |
276 | ]; |
277 | |
278 | let top_dict = parse_top_dict(&mut Stream::new(data)).unwrap(); |
279 | assert!(top_dict.private_dict_range.is_none()); |
280 | } |
281 | } |
282 | |
283 | #[derive (Default, Debug)] |
284 | struct PrivateDict { |
285 | local_subroutines_offset: Option<usize>, |
286 | default_width: Option<f32>, |
287 | nominal_width: Option<f32>, |
288 | } |
289 | |
290 | fn parse_private_dict(data: &[u8]) -> PrivateDict { |
291 | let mut dict: PrivateDict = PrivateDict::default(); |
292 | let mut operands_buffer: [f64; 48] = [0.0; MAX_OPERANDS_LEN]; |
293 | let mut dict_parser: DictionaryParser<'_> = DictionaryParser::new(data, &mut operands_buffer); |
294 | while let Some(operator: Operator) = dict_parser.parse_next() { |
295 | if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET { |
296 | dict.local_subroutines_offset = dict_parser.parse_offset(); |
297 | } else if operator.get() == private_dict_operator::DEFAULT_WIDTH { |
298 | dict.default_width = dict_parser.parse_number().map(|n: f64| n as f32); |
299 | } else if operator.get() == private_dict_operator::NOMINAL_WIDTH { |
300 | dict.nominal_width = dict_parser.parse_number().map(|n: f64| n as f32); |
301 | } |
302 | } |
303 | |
304 | dict |
305 | } |
306 | |
307 | fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> { |
308 | let mut operands_buffer: [f64; 48] = [0.0; MAX_OPERANDS_LEN]; |
309 | let mut dict_parser: DictionaryParser<'_> = DictionaryParser::new(data, &mut operands_buffer); |
310 | while let Some(operator: Operator) = dict_parser.parse_next() { |
311 | if operator.get() == top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET { |
312 | return dict_parser.parse_range(); |
313 | } |
314 | } |
315 | |
316 | None |
317 | } |
318 | |
319 | /// In CID fonts, to get local subroutines we have to: |
320 | /// 1. Find Font DICT index via FDSelect by GID. |
321 | /// 2. Get Font DICT data from FDArray using this index. |
322 | /// 3. Get a Private DICT offset from a Font DICT. |
323 | /// 4. Get a local subroutine offset from Private DICT. |
324 | /// 5. Parse a local subroutine at offset. |
325 | fn parse_cid_local_subrs<'a>( |
326 | data: &'a [u8], |
327 | glyph_id: GlyphId, |
328 | cid: &CIDMetadata, |
329 | ) -> Option<Index<'a>> { |
330 | let font_dict_index: u8 = cid.fd_select.font_dict_index(glyph_id)?; |
331 | let font_dict_data: &[u8] = cid.fd_array.get(index:u32::from(font_dict_index))?; |
332 | let private_dict_range: Range = parse_font_dict(font_dict_data)?; |
333 | let private_dict_data: &[u8] = data.get(index:private_dict_range.clone())?; |
334 | let private_dict: PrivateDict = parse_private_dict(private_dict_data); |
335 | let subroutines_offset: usize = private_dict.local_subroutines_offset?; |
336 | |
337 | // 'The local subroutines offset is relative to the beginning |
338 | // of the Private DICT data.' |
339 | let start: usize = private_dict_range.start.checked_add(subroutines_offset)?; |
340 | let subrs_data: &[u8] = data.get(index:start..)?; |
341 | let mut s: Stream<'_> = Stream::new(subrs_data); |
342 | parse_index::<u16>(&mut s) |
343 | } |
344 | |
345 | struct CharStringParserContext<'a> { |
346 | metadata: &'a Table<'a>, |
347 | width_parsed: bool, |
348 | stems_len: u32, |
349 | has_endchar: bool, |
350 | has_seac: bool, |
351 | glyph_id: GlyphId, // Required to parse local subroutine in CID fonts. |
352 | local_subrs: Option<Index<'a>>, |
353 | } |
354 | |
355 | fn parse_char_string( |
356 | data: &[u8], |
357 | metadata: &Table, |
358 | glyph_id: GlyphId, |
359 | builder: &mut dyn OutlineBuilder, |
360 | ) -> Result<Rect, CFFError> { |
361 | let local_subrs = match metadata.kind { |
362 | FontKind::SID(ref sid) => Some(sid.local_subrs), |
363 | FontKind::CID(_) => None, // Will be resolved on request. |
364 | }; |
365 | |
366 | let mut ctx = CharStringParserContext { |
367 | metadata, |
368 | width_parsed: false, |
369 | stems_len: 0, |
370 | has_endchar: false, |
371 | has_seac: false, |
372 | glyph_id, |
373 | local_subrs, |
374 | }; |
375 | |
376 | let mut inner_builder = Builder { |
377 | builder, |
378 | bbox: BBox::new(), |
379 | }; |
380 | |
381 | let stack = ArgumentsStack { |
382 | data: &mut [0.0; MAX_ARGUMENTS_STACK_LEN], // 192B |
383 | len: 0, |
384 | max_len: MAX_ARGUMENTS_STACK_LEN, |
385 | }; |
386 | let mut parser = CharStringParser { |
387 | stack, |
388 | builder: &mut inner_builder, |
389 | x: 0.0, |
390 | y: 0.0, |
391 | has_move_to: false, |
392 | is_first_move_to: true, |
393 | }; |
394 | _parse_char_string(&mut ctx, data, 0, &mut parser)?; |
395 | |
396 | if !ctx.has_endchar { |
397 | return Err(CFFError::MissingEndChar); |
398 | } |
399 | |
400 | let bbox = parser.builder.bbox; |
401 | |
402 | // Check that bbox was changed. |
403 | if bbox.is_default() { |
404 | return Err(CFFError::ZeroBBox); |
405 | } |
406 | |
407 | bbox.to_rect().ok_or(CFFError::BboxOverflow) |
408 | } |
409 | |
410 | fn _parse_char_string( |
411 | ctx: &mut CharStringParserContext, |
412 | char_string: &[u8], |
413 | depth: u8, |
414 | p: &mut CharStringParser, |
415 | ) -> Result<(), CFFError> { |
416 | let mut s = Stream::new(char_string); |
417 | while !s.at_end() { |
418 | let op = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?; |
419 | match op { |
420 | 0 | 2 | 9 | 13 | 15 | 16 | 17 => { |
421 | // Reserved. |
422 | return Err(CFFError::InvalidOperator); |
423 | } |
424 | operator::HORIZONTAL_STEM |
425 | | operator::VERTICAL_STEM |
426 | | operator::HORIZONTAL_STEM_HINT_MASK |
427 | | operator::VERTICAL_STEM_HINT_MASK => { |
428 | // y dy {dya dyb}* hstem |
429 | // x dx {dxa dxb}* vstem |
430 | // y dy {dya dyb}* hstemhm |
431 | // x dx {dxa dxb}* vstemhm |
432 | |
433 | // If the stack length is uneven, than the first value is a `width`. |
434 | let len = if p.stack.len().is_odd() && !ctx.width_parsed { |
435 | ctx.width_parsed = true; |
436 | p.stack.len() - 1 |
437 | } else { |
438 | p.stack.len() |
439 | }; |
440 | |
441 | ctx.stems_len += len as u32 >> 1; |
442 | |
443 | // We are ignoring the hint operators. |
444 | p.stack.clear(); |
445 | } |
446 | operator::VERTICAL_MOVE_TO => { |
447 | let mut i = 0; |
448 | if p.stack.len() == 2 && !ctx.width_parsed { |
449 | i += 1; |
450 | ctx.width_parsed = true; |
451 | } |
452 | |
453 | p.parse_vertical_move_to(i)?; |
454 | } |
455 | operator::LINE_TO => { |
456 | p.parse_line_to()?; |
457 | } |
458 | operator::HORIZONTAL_LINE_TO => { |
459 | p.parse_horizontal_line_to()?; |
460 | } |
461 | operator::VERTICAL_LINE_TO => { |
462 | p.parse_vertical_line_to()?; |
463 | } |
464 | operator::CURVE_TO => { |
465 | p.parse_curve_to()?; |
466 | } |
467 | operator::CALL_LOCAL_SUBROUTINE => { |
468 | if p.stack.is_empty() { |
469 | return Err(CFFError::InvalidArgumentsStackLength); |
470 | } |
471 | |
472 | if depth == STACK_LIMIT { |
473 | return Err(CFFError::NestingLimitReached); |
474 | } |
475 | |
476 | // Parse and remember the local subroutine for the current glyph. |
477 | // Since it's a pretty complex task, we're doing it only when |
478 | // a local subroutine is actually requested by the glyphs charstring. |
479 | if ctx.local_subrs.is_none() { |
480 | if let FontKind::CID(ref cid) = ctx.metadata.kind { |
481 | ctx.local_subrs = |
482 | parse_cid_local_subrs(ctx.metadata.table_data, ctx.glyph_id, cid); |
483 | } |
484 | } |
485 | |
486 | if let Some(local_subrs) = ctx.local_subrs { |
487 | let subroutine_bias = calc_subroutine_bias(local_subrs.len()); |
488 | let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?; |
489 | let char_string = local_subrs |
490 | .get(index) |
491 | .ok_or(CFFError::InvalidSubroutineIndex)?; |
492 | _parse_char_string(ctx, char_string, depth + 1, p)?; |
493 | } else { |
494 | return Err(CFFError::NoLocalSubroutines); |
495 | } |
496 | |
497 | if ctx.has_endchar && !ctx.has_seac { |
498 | if !s.at_end() { |
499 | return Err(CFFError::DataAfterEndChar); |
500 | } |
501 | |
502 | break; |
503 | } |
504 | } |
505 | operator::RETURN => { |
506 | break; |
507 | } |
508 | TWO_BYTE_OPERATOR_MARK => { |
509 | // flex |
510 | let op2 = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?; |
511 | match op2 { |
512 | operator::HFLEX => p.parse_hflex()?, |
513 | operator::FLEX => p.parse_flex()?, |
514 | operator::HFLEX1 => p.parse_hflex1()?, |
515 | operator::FLEX1 => p.parse_flex1()?, |
516 | _ => return Err(CFFError::UnsupportedOperator), |
517 | } |
518 | } |
519 | operator::ENDCHAR => { |
520 | if p.stack.len() == 4 || (!ctx.width_parsed && p.stack.len() == 5) { |
521 | // Process 'seac'. |
522 | let accent_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop()) |
523 | .ok_or(CFFError::InvalidSeacCode)?; |
524 | let base_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop()) |
525 | .ok_or(CFFError::InvalidSeacCode)?; |
526 | let dy = p.stack.pop(); |
527 | let dx = p.stack.pop(); |
528 | |
529 | if !ctx.width_parsed && !p.stack.is_empty() { |
530 | p.stack.pop(); |
531 | ctx.width_parsed = true; |
532 | } |
533 | |
534 | ctx.has_seac = true; |
535 | |
536 | if depth == STACK_LIMIT { |
537 | return Err(CFFError::NestingLimitReached); |
538 | } |
539 | |
540 | let base_char_string = ctx |
541 | .metadata |
542 | .char_strings |
543 | .get(u32::from(base_char.0)) |
544 | .ok_or(CFFError::InvalidSeacCode)?; |
545 | _parse_char_string(ctx, base_char_string, depth + 1, p)?; |
546 | p.x = dx; |
547 | p.y = dy; |
548 | |
549 | let accent_char_string = ctx |
550 | .metadata |
551 | .char_strings |
552 | .get(u32::from(accent_char.0)) |
553 | .ok_or(CFFError::InvalidSeacCode)?; |
554 | _parse_char_string(ctx, accent_char_string, depth + 1, p)?; |
555 | } else if p.stack.len() == 1 && !ctx.width_parsed { |
556 | p.stack.pop(); |
557 | ctx.width_parsed = true; |
558 | } |
559 | |
560 | if !p.is_first_move_to { |
561 | p.is_first_move_to = true; |
562 | p.builder.close(); |
563 | } |
564 | |
565 | if !s.at_end() { |
566 | return Err(CFFError::DataAfterEndChar); |
567 | } |
568 | |
569 | ctx.has_endchar = true; |
570 | |
571 | break; |
572 | } |
573 | operator::HINT_MASK | operator::COUNTER_MASK => { |
574 | let mut len = p.stack.len(); |
575 | |
576 | // We are ignoring the hint operators. |
577 | p.stack.clear(); |
578 | |
579 | // If the stack length is uneven, than the first value is a `width`. |
580 | if len.is_odd() && !ctx.width_parsed { |
581 | len -= 1; |
582 | ctx.width_parsed = true; |
583 | } |
584 | |
585 | ctx.stems_len += len as u32 >> 1; |
586 | |
587 | s.advance(usize::num_from((ctx.stems_len + 7) >> 3)); |
588 | } |
589 | operator::MOVE_TO => { |
590 | let mut i = 0; |
591 | if p.stack.len() == 3 && !ctx.width_parsed { |
592 | i += 1; |
593 | ctx.width_parsed = true; |
594 | } |
595 | |
596 | p.parse_move_to(i)?; |
597 | } |
598 | operator::HORIZONTAL_MOVE_TO => { |
599 | let mut i = 0; |
600 | if p.stack.len() == 2 && !ctx.width_parsed { |
601 | i += 1; |
602 | ctx.width_parsed = true; |
603 | } |
604 | |
605 | p.parse_horizontal_move_to(i)?; |
606 | } |
607 | operator::CURVE_LINE => { |
608 | p.parse_curve_line()?; |
609 | } |
610 | operator::LINE_CURVE => { |
611 | p.parse_line_curve()?; |
612 | } |
613 | operator::VV_CURVE_TO => { |
614 | p.parse_vv_curve_to()?; |
615 | } |
616 | operator::HH_CURVE_TO => { |
617 | p.parse_hh_curve_to()?; |
618 | } |
619 | operator::SHORT_INT => { |
620 | let n = s.read::<i16>().ok_or(CFFError::ReadOutOfBounds)?; |
621 | p.stack.push(f32::from(n))?; |
622 | } |
623 | operator::CALL_GLOBAL_SUBROUTINE => { |
624 | if p.stack.is_empty() { |
625 | return Err(CFFError::InvalidArgumentsStackLength); |
626 | } |
627 | |
628 | if depth == STACK_LIMIT { |
629 | return Err(CFFError::NestingLimitReached); |
630 | } |
631 | |
632 | let subroutine_bias = calc_subroutine_bias(ctx.metadata.global_subrs.len()); |
633 | let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?; |
634 | let char_string = ctx |
635 | .metadata |
636 | .global_subrs |
637 | .get(index) |
638 | .ok_or(CFFError::InvalidSubroutineIndex)?; |
639 | _parse_char_string(ctx, char_string, depth + 1, p)?; |
640 | |
641 | if ctx.has_endchar && !ctx.has_seac { |
642 | if !s.at_end() { |
643 | return Err(CFFError::DataAfterEndChar); |
644 | } |
645 | |
646 | break; |
647 | } |
648 | } |
649 | operator::VH_CURVE_TO => { |
650 | p.parse_vh_curve_to()?; |
651 | } |
652 | operator::HV_CURVE_TO => { |
653 | p.parse_hv_curve_to()?; |
654 | } |
655 | 32..=246 => { |
656 | p.parse_int1(op)?; |
657 | } |
658 | 247..=250 => { |
659 | p.parse_int2(op, &mut s)?; |
660 | } |
661 | 251..=254 => { |
662 | p.parse_int3(op, &mut s)?; |
663 | } |
664 | operator::FIXED_16_16 => { |
665 | p.parse_fixed(&mut s)?; |
666 | } |
667 | } |
668 | } |
669 | |
670 | // TODO: 'A charstring subroutine must end with either an endchar or a return operator.' |
671 | |
672 | Ok(()) |
673 | } |
674 | |
675 | fn seac_code_to_glyph_id(charset: &Charset, n: f32) -> Option<GlyphId> { |
676 | let code: u8 = u8::try_num_from(n)?; |
677 | |
678 | let sid: u8 = STANDARD_ENCODING[usize::from(code)]; |
679 | let sid: StringId = StringId(u16::from(sid)); |
680 | |
681 | match charset { |
682 | Charset::ISOAdobe => { |
683 | // ISO Adobe charset only defines string ids up to 228 (zcaron) |
684 | if code <= 228 { |
685 | Some(GlyphId(sid.0)) |
686 | } else { |
687 | None |
688 | } |
689 | } |
690 | Charset::Expert | Charset::ExpertSubset => None, |
691 | _ => charset.sid_to_gid(sid), |
692 | } |
693 | } |
694 | |
695 | // The first number of the first char string operator (well, some of them) can be a width. |
696 | // This width is different from glyph's bbox width and somewhat relates to |
697 | // glyph's advance (`hmtx`). |
698 | // |
699 | // We ignore this width during glyph outlining, because we don't really care about it. |
700 | // But when parsing standalone CFF tables/fonts it might be useful. |
701 | fn parse_char_string_width(data: &[u8]) -> Option<f32> { |
702 | let mut stack: ArgumentsStack<'_> = ArgumentsStack { |
703 | data: &mut [0.0; MAX_ARGUMENTS_STACK_LEN], // 192B |
704 | len: 0, |
705 | max_len: MAX_ARGUMENTS_STACK_LEN, |
706 | }; |
707 | _parse_char_string_width(char_string:data, &mut stack) |
708 | } |
709 | |
710 | // Just like `_parse_char_string`, but parses only the first operator. |
711 | fn _parse_char_string_width(char_string: &[u8], stack: &mut ArgumentsStack) -> Option<f32> { |
712 | let mut s = Stream::new(char_string); |
713 | while !s.at_end() { |
714 | let op = s.read::<u8>()?; |
715 | match op { |
716 | operator::HORIZONTAL_STEM |
717 | | operator::VERTICAL_STEM |
718 | | operator::HORIZONTAL_STEM_HINT_MASK |
719 | | operator::VERTICAL_STEM_HINT_MASK |
720 | | operator::HINT_MASK |
721 | | operator::COUNTER_MASK |
722 | | operator::MOVE_TO |
723 | | operator::ENDCHAR => { |
724 | return if stack.len().is_odd() { |
725 | Some(stack.at(0)) |
726 | } else { |
727 | None |
728 | }; |
729 | } |
730 | operator::HORIZONTAL_MOVE_TO | operator::VERTICAL_MOVE_TO => { |
731 | return if stack.len() == 2 { |
732 | Some(stack.at(0)) |
733 | } else { |
734 | None |
735 | }; |
736 | } |
737 | operator::RETURN => { |
738 | break; |
739 | } |
740 | operator::SHORT_INT => { |
741 | let n = s.read::<i16>()?; |
742 | stack.push(f32::from(n)).ok()?; |
743 | } |
744 | 32..=246 => { |
745 | let n = i16::from(op) - 139; |
746 | stack.push(f32::from(n)).ok()?; |
747 | } |
748 | 247..=250 => { |
749 | let b1 = s.read::<u8>()?; |
750 | let n = (i16::from(op) - 247) * 256 + i16::from(b1) + 108; |
751 | debug_assert!((108..=1131).contains(&n)); |
752 | stack.push(f32::from(n)).ok()?; |
753 | } |
754 | 251..=254 => { |
755 | let b1 = s.read::<u8>()?; |
756 | let n = -(i16::from(op) - 251) * 256 - i16::from(b1) - 108; |
757 | debug_assert!((-1131..=-108).contains(&n)); |
758 | stack.push(f32::from(n)).ok()?; |
759 | } |
760 | operator::FIXED_16_16 => { |
761 | let n = s.read::<Fixed>()?; |
762 | stack.push(n.0).ok()?; |
763 | } |
764 | _ => return None, |
765 | } |
766 | } |
767 | |
768 | None |
769 | } |
770 | |
771 | #[derive (Clone, Copy, Debug)] |
772 | enum FDSelect<'a> { |
773 | Format0(LazyArray16<'a, u8>), |
774 | Format3(&'a [u8]), // It's easier to parse it in-place. |
775 | } |
776 | |
777 | impl Default for FDSelect<'_> { |
778 | fn default() -> Self { |
779 | FDSelect::Format0(LazyArray16::default()) |
780 | } |
781 | } |
782 | |
783 | impl FDSelect<'_> { |
784 | fn font_dict_index(&self, glyph_id: GlyphId) -> Option<u8> { |
785 | match self { |
786 | FDSelect::Format0(ref array) => array.get(glyph_id.0), |
787 | FDSelect::Format3(data) => { |
788 | let mut s = Stream::new(data); |
789 | let number_of_ranges = s.read::<u16>()?; |
790 | if number_of_ranges == 0 { |
791 | return None; |
792 | } |
793 | |
794 | // 'A sentinel GID follows the last range element and serves |
795 | // to delimit the last range in the array.' |
796 | // So we can simply increase the number of ranges by one. |
797 | let number_of_ranges = number_of_ranges.checked_add(1)?; |
798 | |
799 | // Range is: GlyphId + u8 |
800 | let mut prev_first_glyph = s.read::<GlyphId>()?; |
801 | let mut prev_index = s.read::<u8>()?; |
802 | for _ in 1..number_of_ranges { |
803 | let curr_first_glyph = s.read::<GlyphId>()?; |
804 | if (prev_first_glyph..curr_first_glyph).contains(&glyph_id) { |
805 | return Some(prev_index); |
806 | } else { |
807 | prev_index = s.read::<u8>()?; |
808 | } |
809 | |
810 | prev_first_glyph = curr_first_glyph; |
811 | } |
812 | |
813 | None |
814 | } |
815 | } |
816 | } |
817 | } |
818 | |
819 | fn parse_fd_select<'a>(number_of_glyphs: u16, s: &mut Stream<'a>) -> Option<FDSelect<'a>> { |
820 | let format: u8 = s.read::<u8>()?; |
821 | match format { |
822 | 0 => Some(FDSelect::Format0(s.read_array16::<u8>(count:number_of_glyphs)?)), |
823 | 3 => Some(FDSelect::Format3(s.tail()?)), |
824 | _ => None, |
825 | } |
826 | } |
827 | |
828 | fn parse_sid_metadata<'a>( |
829 | data: &'a [u8], |
830 | top_dict: TopDict, |
831 | encoding: Encoding<'a>, |
832 | ) -> Option<FontKind<'a>> { |
833 | let mut metadata = SIDMetadata::default(); |
834 | metadata.encoding = encoding; |
835 | |
836 | let private_dict = if let Some(range) = top_dict.private_dict_range.clone() { |
837 | parse_private_dict(data.get(range)?) |
838 | } else { |
839 | return Some(FontKind::SID(metadata)); |
840 | }; |
841 | |
842 | metadata.default_width = private_dict.default_width.unwrap_or(0.0); |
843 | metadata.nominal_width = private_dict.nominal_width.unwrap_or(0.0); |
844 | |
845 | if let (Some(private_dict_range), Some(subroutines_offset)) = ( |
846 | top_dict.private_dict_range, |
847 | private_dict.local_subroutines_offset, |
848 | ) { |
849 | // 'The local subroutines offset is relative to the beginning |
850 | // of the Private DICT data.' |
851 | if let Some(start) = private_dict_range.start.checked_add(subroutines_offset) { |
852 | let data = data.get(start..data.len())?; |
853 | let mut s = Stream::new(data); |
854 | metadata.local_subrs = parse_index::<u16>(&mut s)?; |
855 | } |
856 | } |
857 | |
858 | Some(FontKind::SID(metadata)) |
859 | } |
860 | |
861 | fn parse_cid_metadata(data: &[u8], top_dict: TopDict, number_of_glyphs: u16) -> Option<FontKind> { |
862 | let (charset_offset, fd_array_offset, fd_select_offset) = match ( |
863 | top_dict.charset_offset, |
864 | top_dict.fd_array_offset, |
865 | top_dict.fd_select_offset, |
866 | ) { |
867 | (Some(a), Some(b), Some(c)) => (a, b, c), |
868 | _ => return None, // charset, FDArray and FDSelect must be set. |
869 | }; |
870 | |
871 | if charset_offset <= charset_id::EXPERT_SUBSET { |
872 | // 'There are no predefined charsets for CID fonts.' |
873 | // Adobe Technical Note #5176, chapter 18 CID-keyed Fonts |
874 | return None; |
875 | } |
876 | |
877 | let mut metadata = CIDMetadata::default(); |
878 | |
879 | metadata.fd_array = { |
880 | let mut s = Stream::new_at(data, fd_array_offset)?; |
881 | parse_index::<u16>(&mut s)? |
882 | }; |
883 | |
884 | metadata.fd_select = { |
885 | let mut s = Stream::new_at(data, fd_select_offset)?; |
886 | parse_fd_select(number_of_glyphs, &mut s)? |
887 | }; |
888 | |
889 | Some(FontKind::CID(metadata)) |
890 | } |
891 | |
892 | /// A [Compact Font Format Table]( |
893 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/cff). |
894 | #[derive (Clone, Copy)] |
895 | pub struct Table<'a> { |
896 | // The whole CFF table. |
897 | // Used to resolve a local subroutine in a CID font. |
898 | table_data: &'a [u8], |
899 | |
900 | #[allow (dead_code)] |
901 | strings: Index<'a>, |
902 | global_subrs: Index<'a>, |
903 | charset: Charset<'a>, |
904 | number_of_glyphs: NonZeroU16, |
905 | matrix: Matrix, |
906 | char_strings: Index<'a>, |
907 | kind: FontKind<'a>, |
908 | } |
909 | |
910 | impl<'a> Table<'a> { |
911 | /// Parses a table from raw data. |
912 | pub fn parse(data: &'a [u8]) -> Option<Self> { |
913 | let mut s = Stream::new(data); |
914 | |
915 | // Parse Header. |
916 | let major = s.read::<u8>()?; |
917 | s.skip::<u8>(); // minor |
918 | let header_size = s.read::<u8>()?; |
919 | s.skip::<u8>(); // Absolute offset |
920 | |
921 | if major != 1 { |
922 | return None; |
923 | } |
924 | |
925 | // Jump to Name INDEX. It's not necessarily right after the header. |
926 | if header_size > 4 { |
927 | s.advance(usize::from(header_size) - 4); |
928 | } |
929 | |
930 | // Skip Name INDEX. |
931 | skip_index::<u16>(&mut s)?; |
932 | |
933 | let top_dict = parse_top_dict(&mut s)?; |
934 | |
935 | // Must be set, otherwise there are nothing to parse. |
936 | if top_dict.char_strings_offset == 0 { |
937 | return None; |
938 | } |
939 | |
940 | // String INDEX. |
941 | let strings = parse_index::<u16>(&mut s)?; |
942 | |
943 | // Parse Global Subroutines INDEX. |
944 | let global_subrs = parse_index::<u16>(&mut s)?; |
945 | |
946 | let char_strings = { |
947 | let mut s = Stream::new_at(data, top_dict.char_strings_offset)?; |
948 | parse_index::<u16>(&mut s)? |
949 | }; |
950 | |
951 | // 'The number of glyphs is the value of the count field in the CharStrings INDEX.' |
952 | let number_of_glyphs = u16::try_from(char_strings.len()) |
953 | .ok() |
954 | .and_then(NonZeroU16::new)?; |
955 | |
956 | let charset = match top_dict.charset_offset { |
957 | Some(charset_id::ISO_ADOBE) => Charset::ISOAdobe, |
958 | Some(charset_id::EXPERT) => Charset::Expert, |
959 | Some(charset_id::EXPERT_SUBSET) => Charset::ExpertSubset, |
960 | Some(offset) => { |
961 | let mut s = Stream::new_at(data, offset)?; |
962 | parse_charset(number_of_glyphs.get(), &mut s)? |
963 | } |
964 | None => Charset::ISOAdobe, // default |
965 | }; |
966 | |
967 | let matrix = top_dict.matrix; |
968 | |
969 | let kind = if top_dict.has_ros { |
970 | parse_cid_metadata(data, top_dict, number_of_glyphs.get())? |
971 | } else { |
972 | // Only SID fonts are allowed to have an Encoding. |
973 | let encoding = match top_dict.encoding_offset { |
974 | Some(encoding_id::STANDARD) => Encoding::new_standard(), |
975 | Some(encoding_id::EXPERT) => Encoding::new_expert(), |
976 | Some(offset) => parse_encoding(&mut Stream::new_at(data, offset)?)?, |
977 | None => Encoding::new_standard(), // default |
978 | }; |
979 | |
980 | parse_sid_metadata(data, top_dict, encoding)? |
981 | }; |
982 | |
983 | Some(Self { |
984 | table_data: data, |
985 | strings, |
986 | global_subrs, |
987 | charset, |
988 | number_of_glyphs, |
989 | matrix, |
990 | char_strings, |
991 | kind, |
992 | }) |
993 | } |
994 | |
995 | /// Returns a total number of glyphs in the font. |
996 | /// |
997 | /// Never zero. |
998 | #[inline ] |
999 | pub fn number_of_glyphs(&self) -> u16 { |
1000 | self.number_of_glyphs.get() |
1001 | } |
1002 | |
1003 | /// Returns a font transformation matrix. |
1004 | #[inline ] |
1005 | pub fn matrix(&self) -> Matrix { |
1006 | self.matrix |
1007 | } |
1008 | |
1009 | /// Outlines a glyph. |
1010 | pub fn outline( |
1011 | &self, |
1012 | glyph_id: GlyphId, |
1013 | builder: &mut dyn OutlineBuilder, |
1014 | ) -> Result<Rect, CFFError> { |
1015 | let data = self |
1016 | .char_strings |
1017 | .get(u32::from(glyph_id.0)) |
1018 | .ok_or(CFFError::NoGlyph)?; |
1019 | parse_char_string(data, self, glyph_id, builder) |
1020 | } |
1021 | |
1022 | /// Resolves a Glyph ID for a code point. |
1023 | /// |
1024 | /// Similar to [`Face::glyph_index`](crate::Face::glyph_index) but 8bit |
1025 | /// and uses CFF encoding and charset tables instead of TrueType `cmap`. |
1026 | pub fn glyph_index(&self, code_point: u8) -> Option<GlyphId> { |
1027 | match self.kind { |
1028 | FontKind::SID(ref sid_meta) => { |
1029 | match sid_meta.encoding.code_to_gid(&self.charset, code_point) { |
1030 | Some(id) => Some(id), |
1031 | None => { |
1032 | // Try using the Standard encoding otherwise. |
1033 | // Custom Encodings does not guarantee to include all glyphs. |
1034 | Encoding::new_standard().code_to_gid(&self.charset, code_point) |
1035 | } |
1036 | } |
1037 | } |
1038 | FontKind::CID(_) => None, |
1039 | } |
1040 | } |
1041 | |
1042 | /// Returns a glyph width. |
1043 | /// |
1044 | /// This value is different from outline bbox width and is stored separately. |
1045 | /// |
1046 | /// Technically similar to [`Face::glyph_hor_advance`](crate::Face::glyph_hor_advance). |
1047 | pub fn glyph_width(&self, glyph_id: GlyphId) -> Option<u16> { |
1048 | match self.kind { |
1049 | FontKind::SID(ref sid) => { |
1050 | let data = self.char_strings.get(u32::from(glyph_id.0))?; |
1051 | let width = parse_char_string_width(data) |
1052 | .map(|w| sid.nominal_width + w) |
1053 | .unwrap_or(sid.default_width); |
1054 | u16::try_from(width as i32).ok() |
1055 | } |
1056 | FontKind::CID(_) => None, |
1057 | } |
1058 | } |
1059 | |
1060 | /// Returns a glyph ID by a name. |
1061 | #[cfg (feature = "glyph-names" )] |
1062 | pub fn glyph_index_by_name(&self, name: &str) -> Option<GlyphId> { |
1063 | match self.kind { |
1064 | FontKind::SID(_) => { |
1065 | let sid = if let Some(index) = STANDARD_NAMES.iter().position(|n| *n == name) { |
1066 | StringId(index as u16) |
1067 | } else { |
1068 | let index = self |
1069 | .strings |
1070 | .into_iter() |
1071 | .position(|n| n == name.as_bytes())?; |
1072 | StringId((STANDARD_NAMES.len() + index) as u16) |
1073 | }; |
1074 | |
1075 | self.charset.sid_to_gid(sid) |
1076 | } |
1077 | FontKind::CID(_) => None, |
1078 | } |
1079 | } |
1080 | |
1081 | /// Returns a glyph name. |
1082 | #[cfg (feature = "glyph-names" )] |
1083 | pub fn glyph_name(&self, glyph_id: GlyphId) -> Option<&'a str> { |
1084 | match self.kind { |
1085 | FontKind::SID(_) => { |
1086 | let sid = self.charset.gid_to_sid(glyph_id)?; |
1087 | let sid = usize::from(sid.0); |
1088 | match STANDARD_NAMES.get(sid) { |
1089 | Some(name) => Some(name), |
1090 | None => { |
1091 | let idx = u32::try_from(sid - STANDARD_NAMES.len()).ok()?; |
1092 | let name = self.strings.get(idx)?; |
1093 | core::str::from_utf8(name).ok() |
1094 | } |
1095 | } |
1096 | } |
1097 | FontKind::CID(_) => None, |
1098 | } |
1099 | } |
1100 | } |
1101 | |
1102 | impl core::fmt::Debug for Table<'_> { |
1103 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
1104 | write!(f, "Table {{ ... }}" ) |
1105 | } |
1106 | } |
1107 | |