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
9use core::convert::TryFrom;
10use core::num::NonZeroU16;
11use core::ops::Range;
12
13use super::argstack::ArgumentsStack;
14use super::charset::{parse_charset, Charset};
15use super::charstring::CharStringParser;
16use super::dict::DictionaryParser;
17use super::encoding::{parse_encoding, Encoding, STANDARD_ENCODING};
18use super::index::{parse_index, skip_index, Index};
19#[cfg(feature = "glyph-names")]
20use super::std_names::STANDARD_NAMES;
21use super::{calc_subroutine_bias, conv_subroutine_index, Builder, CFFError, IsEven, StringId};
22use crate::parser::{LazyArray16, NumFrom, Stream, TryNumFrom};
23use crate::{BBox, Fixed, GlyphId, OutlineBuilder, Rect};
24
25// Limits according to the Adobe Technical Note #5176, chapter 4 DICT Data.
26const MAX_OPERANDS_LEN: usize = 48;
27
28// Limits according to the Adobe Technical Note #5177 Appendix B.
29const STACK_LIMIT: u8 = 10;
30const MAX_ARGUMENTS_STACK_LEN: usize = 48;
31
32const TWO_BYTE_OPERATOR_MARK: u8 = 12;
33
34/// Enumerates some operators defined in the Adobe Technical Note #5177.
35mod 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
69mod 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
82mod 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
89mod 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
96mod encoding_id {
97 pub const STANDARD: usize = 0;
98 pub const EXPERT: usize = 1;
99}
100
101#[derive(Clone, Copy, Debug)]
102pub(crate) enum FontKind<'a> {
103 SID(SIDMetadata<'a>),
104 CID(CIDMetadata<'a>),
105}
106
107#[derive(Clone, Copy, Default, Debug)]
108pub(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)]
118pub(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)]
126pub 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
135impl 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)]
149struct 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
160fn 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)]
216mod 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)]
284struct PrivateDict {
285 local_subroutines_offset: Option<usize>,
286 default_width: Option<f32>,
287 nominal_width: Option<f32>,
288}
289
290fn 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
307fn 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.
325fn 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
345struct 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
355fn 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
410fn _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
675fn 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.
701fn 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.
711fn _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)]
772enum FDSelect<'a> {
773 Format0(LazyArray16<'a, u8>),
774 Format3(&'a [u8]), // It's easier to parse it in-place.
775}
776
777impl Default for FDSelect<'_> {
778 fn default() -> Self {
779 FDSelect::Format0(LazyArray16::default())
780 }
781}
782
783impl 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
819fn 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
828fn 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
861fn 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)]
895pub 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
910impl<'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
1102impl core::fmt::Debug for Table<'_> {
1103 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1104 write!(f, "Table {{ ... }}")
1105 }
1106}
1107