1use core::convert::TryFrom;
7use core::num::NonZeroU16;
8use core::ops::Range;
9
10use super::argstack::ArgumentsStack;
11use super::charset::{parse_charset, Charset};
12use super::charstring::CharStringParser;
13use super::dict::DictionaryParser;
14use super::encoding::{parse_encoding, Encoding, STANDARD_ENCODING};
15use super::index::{parse_index, skip_index, Index};
16use super::std_names::STANDARD_NAMES;
17use super::{calc_subroutine_bias, conv_subroutine_index, Builder, CFFError, IsEven, StringId};
18use crate::parser::{LazyArray16, NumFrom, Stream, TryNumFrom};
19use crate::{DummyOutline, GlyphId, OutlineBuilder, Rect, RectF};
20
21const MAX_OPERANDS_LEN: usize = 48;
23
24const STACK_LIMIT: u8 = 10;
26const MAX_ARGUMENTS_STACK_LEN: usize = 48;
27
28const TWO_BYTE_OPERATOR_MARK: u8 = 12;
29
30mod operator {
32 pub const HORIZONTAL_STEM: u8 = 1;
33 pub const VERTICAL_STEM: u8 = 3;
34 pub const VERTICAL_MOVE_TO: u8 = 4;
35 pub const LINE_TO: u8 = 5;
36 pub const HORIZONTAL_LINE_TO: u8 = 6;
37 pub const VERTICAL_LINE_TO: u8 = 7;
38 pub const CURVE_TO: u8 = 8;
39 pub const CALL_LOCAL_SUBROUTINE: u8 = 10;
40 pub const RETURN: u8 = 11;
41 pub const ENDCHAR: u8 = 14;
42 pub const HORIZONTAL_STEM_HINT_MASK: u8 = 18;
43 pub const HINT_MASK: u8 = 19;
44 pub const COUNTER_MASK: u8 = 20;
45 pub const MOVE_TO: u8 = 21;
46 pub const HORIZONTAL_MOVE_TO: u8 = 22;
47 pub const VERTICAL_STEM_HINT_MASK: u8 = 23;
48 pub const CURVE_LINE: u8 = 24;
49 pub const LINE_CURVE: u8 = 25;
50 pub const VV_CURVE_TO: u8 = 26;
51 pub const HH_CURVE_TO: u8 = 27;
52 pub const SHORT_INT: u8 = 28;
53 pub const CALL_GLOBAL_SUBROUTINE: u8 = 29;
54 pub const VH_CURVE_TO: u8 = 30;
55 pub const HV_CURVE_TO: u8 = 31;
56 pub const HFLEX: u8 = 34;
57 pub const FLEX: u8 = 35;
58 pub const HFLEX1: u8 = 36;
59 pub const FLEX1: u8 = 37;
60 pub const FIXED_16_16: u8 = 255;
61}
62
63mod top_dict_operator {
66 pub const VERSION: u16 = 0;
67 pub const NOTICE: u16 = 1;
68 pub const FULL_NAME: u16 = 2;
69 pub const FAMILY_NAME: u16 = 3;
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
80mod 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
88mod charset_id {
90 pub const ISO_ADOBE: usize = 0;
91 pub const EXPERT: usize = 1;
92 pub const EXPERT_SUBSET: usize = 2;
93}
94
95mod 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 default_width: f64,
112 nominal_width: f64,
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#[allow(missing_docs)]
125#[derive(Clone, Copy, Debug)]
126pub struct Matrix {
127 pub sx: f64,
128 pub ky: f64,
129 pub kx: f64,
130 pub sy: f64,
131 pub tx: f64,
132 pub ty: f64,
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 version: Option<StringId>,
151 notice: Option<StringId>,
152 full_name: Option<StringId>,
153 family_name: Option<StringId>,
154 charset_offset: Option<usize>,
155 encoding_offset: Option<usize>,
156 char_strings_offset: usize,
157 private_dict_range: Option<Range<usize>>,
158 matrix: Matrix,
159 has_ros: bool,
160 fd_array_offset: Option<usize>,
161 fd_select_offset: Option<usize>,
162}
163
164fn parse_top_dict(s: &mut Stream) -> Option<TopDict> {
165 let mut top_dict = TopDict::default();
166
167 let index = parse_index::<u16>(s)?;
168
169 let data = index.get(0)?;
171
172 let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
173 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
174 while let Some(operator) = dict_parser.parse_next() {
175 match operator.get() {
176 top_dict_operator::VERSION => {
177 top_dict.version = dict_parser.parse_sid();
178 }
179 top_dict_operator::NOTICE => {
180 top_dict.notice = dict_parser.parse_sid();
181 }
182 top_dict_operator::FULL_NAME => {
183 top_dict.full_name = dict_parser.parse_sid();
184 }
185 top_dict_operator::FAMILY_NAME => {
186 top_dict.family_name = dict_parser.parse_sid();
187 }
188 top_dict_operator::CHARSET_OFFSET => {
189 top_dict.charset_offset = dict_parser.parse_offset();
190 }
191 top_dict_operator::ENCODING_OFFSET => {
192 top_dict.encoding_offset = dict_parser.parse_offset();
193 }
194 top_dict_operator::CHAR_STRINGS_OFFSET => {
195 top_dict.char_strings_offset = dict_parser.parse_offset()?;
196 }
197 top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET => {
198 top_dict.private_dict_range = dict_parser.parse_range();
199 }
200 top_dict_operator::FONT_MATRIX => {
201 dict_parser.parse_operands()?;
202 let operands = dict_parser.operands();
203 if operands.len() == 6 {
204 top_dict.matrix = Matrix {
205 sx: operands[0],
206 ky: operands[1],
207 kx: operands[2],
208 sy: operands[3],
209 tx: operands[4],
210 ty: operands[5],
211 };
212 }
213 }
214 top_dict_operator::ROS => {
215 top_dict.has_ros = true;
216 }
217 top_dict_operator::FD_ARRAY => {
218 top_dict.fd_array_offset = dict_parser.parse_offset();
219 }
220 top_dict_operator::FD_SELECT => {
221 top_dict.fd_select_offset = dict_parser.parse_offset();
222 }
223 _ => {}
224 }
225 }
226
227 Some(top_dict)
228}
229
230#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
236 fn private_dict_size_overflow() {
237 let data = &[
238 0x00, 0x01, 0x01, 0x01, 0x0C, 0x1D, 0x7F, 0xFF, 0xFF, 0xFF, 0x1D, 0x7F, 0xFF, 0xFF, 0xFF, 0x12, ];
246
247 let top_dict = parse_top_dict(&mut Stream::new(data)).unwrap();
248 assert_eq!(top_dict.private_dict_range, Some(2147483647..4294967294));
249 }
250
251 #[test]
252 fn private_dict_negative_char_strings_offset() {
253 let data = &[
254 0x00, 0x01, 0x01, 0x01, 0x03, 0x8A, 0x11, ];
262
263 assert!(parse_top_dict(&mut Stream::new(data)).is_none());
264 }
265
266 #[test]
267 fn private_dict_no_char_strings_offset_operand() {
268 let data = &[
269 0x00, 0x01, 0x01, 0x01, 0x02, 0x11, ];
277
278 assert!(parse_top_dict(&mut Stream::new(data)).is_none());
279 }
280
281 #[test]
282 fn negative_private_dict_offset_and_size() {
283 let data = &[
284 0x00, 0x01, 0x01, 0x01, 0x04, 0x8A, 0x8A, 0x12, ];
293
294 let top_dict = parse_top_dict(&mut Stream::new(data)).unwrap();
295 assert!(top_dict.private_dict_range.is_none());
296 }
297}
298
299#[derive(Default, Debug)]
300struct PrivateDict {
301 local_subroutines_offset: Option<usize>,
302 default_width: Option<f64>,
303 nominal_width: Option<f64>,
304}
305
306fn parse_private_dict(data: &[u8]) -> PrivateDict {
307 let mut dict = PrivateDict::default();
308 let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
309 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
310 while let Some(operator) = dict_parser.parse_next() {
311 if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET {
312 dict.local_subroutines_offset = dict_parser.parse_offset();
313 } else if operator.get() == private_dict_operator::DEFAULT_WIDTH {
314 dict.default_width = dict_parser.parse_number();
315 } else if operator.get() == private_dict_operator::NOMINAL_WIDTH {
316 dict.nominal_width = dict_parser.parse_number();
317 }
318 }
319
320 dict
321}
322
323fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
324 let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
325 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
326 while let Some(operator) = dict_parser.parse_next() {
327 if operator.get() == top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET {
328 return dict_parser.parse_range();
329 }
330 }
331
332 None
333}
334
335fn parse_font_dict_matrix(data: &[u8]) -> Option<Matrix> {
341 let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
342 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
343 while let Some(operator) = dict_parser.parse_next() {
344 if operator.get() == top_dict_operator::FONT_MATRIX {
345 dict_parser.parse_operands()?;
346 let operands = dict_parser.operands();
347 if operands.len() == 6 {
348 return Some(Matrix {
349 sx: operands[0],
350 ky: operands[1],
351 kx: operands[2],
352 sy: operands[3],
353 tx: operands[4],
354 ty: operands[5],
355 });
356 }
357 }
358 }
359 None
360}
361
362fn parse_cid_local_subrs<'a>(
369 data: &'a [u8],
370 glyph_id: GlyphId,
371 cid: &CIDMetadata,
372) -> Option<Index<'a>> {
373 let font_dict_index = cid.fd_select.font_dict_index(glyph_id)?;
374 let font_dict_data = cid.fd_array.get(u32::from(font_dict_index))?;
375 let private_dict_range = parse_font_dict(font_dict_data)?;
376 let private_dict_data = data.get(private_dict_range.clone())?;
377 let private_dict = parse_private_dict(private_dict_data);
378 let subroutines_offset = private_dict.local_subroutines_offset?;
379
380 let start = private_dict_range.start.checked_add(subroutines_offset)?;
383 let subrs_data = data.get(start..)?;
384 let mut s = Stream::new(subrs_data);
385 parse_index::<u16>(&mut s)
386}
387
388pub fn string_by_id<'a>(metadata: &'a Table, sid: StringId) -> Option<&'a str> {
389 let sid = usize::from(sid.0);
390 match STANDARD_NAMES.get(sid) {
391 Some(name) => Some(name),
392 None => {
393 let idx = u32::try_from(sid - STANDARD_NAMES.len()).ok()?;
394 let name = metadata.strings.get(idx)?;
395 core::str::from_utf8(name).ok()
396 }
397 }
398}
399
400struct CharStringParserContext<'a> {
401 metadata: &'a Table<'a>,
402 width: Option<f64>,
403 stems_len: u32,
404 has_endchar: bool,
405 has_seac: bool,
406 glyph_id: GlyphId, local_subrs: Option<Index<'a>>,
408}
409
410fn parse_char_string(
411 data: &[u8],
412 metadata: &Table,
413 glyph_id: GlyphId,
414 width_only: bool,
415 builder: &mut dyn OutlineBuilder,
416) -> Result<(Rect, Option<f64>), CFFError> {
417 let local_subrs = match metadata.kind {
418 FontKind::SID(ref sid) => Some(sid.local_subrs),
419 FontKind::CID(_) => None, };
421
422 let mut ctx = CharStringParserContext {
423 metadata,
424 width: None,
425 stems_len: 0,
426 has_endchar: false,
427 has_seac: false,
428 glyph_id,
429 local_subrs,
430 };
431
432 let mut inner_builder = Builder {
433 builder,
434 bbox: RectF::new(),
435 };
436
437 let stack = ArgumentsStack {
438 data: &mut [0.0; MAX_ARGUMENTS_STACK_LEN], len: 0,
440 max_len: MAX_ARGUMENTS_STACK_LEN,
441 };
442 let mut parser = CharStringParser {
443 stack,
444 builder: &mut inner_builder,
445 x: 0.0,
446 y: 0.0,
447 has_move_to: false,
448 is_first_move_to: true,
449 width_only,
450 };
451 _parse_char_string(&mut ctx, data, 0, &mut parser)?;
452
453 if width_only {
454 return Ok((Rect::zero(), ctx.width));
455 }
456
457 if !ctx.has_endchar {
458 return Err(CFFError::MissingEndChar);
459 }
460
461 let bbox = parser.builder.bbox;
462
463 if bbox.is_default() {
465 return Err(CFFError::ZeroBBox);
466 }
467
468 let rect = bbox.to_rect().ok_or(CFFError::BboxOverflow)?;
469 Ok((rect, ctx.width))
470}
471
472fn _parse_char_string(
473 ctx: &mut CharStringParserContext,
474 char_string: &[u8],
475 depth: u8,
476 p: &mut CharStringParser,
477) -> Result<(), CFFError> {
478 let mut s = Stream::new(char_string);
479 while !s.at_end() {
480 let op = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
481 match op {
482 0 | 2 | 9 | 13 | 15 | 16 | 17 => {
483 return Err(CFFError::InvalidOperator);
485 }
486 operator::HORIZONTAL_STEM
487 | operator::VERTICAL_STEM
488 | operator::HORIZONTAL_STEM_HINT_MASK
489 | operator::VERTICAL_STEM_HINT_MASK => {
490 let len = if p.stack.len().is_odd() && ctx.width.is_none() {
497 ctx.width = Some(p.stack.at(0));
498 p.stack.len() - 1
499 } else {
500 p.stack.len()
501 };
502
503 ctx.stems_len += len as u32 >> 1;
504
505 p.stack.clear();
507 }
508 operator::VERTICAL_MOVE_TO => {
509 let mut i = 0;
510 if p.stack.len() == 2 {
511 i += 1;
512 if ctx.width.is_none() {
513 ctx.width = Some(p.stack.at(0));
514 }
515 }
516
517 p.parse_vertical_move_to(i)?;
518 }
519 operator::LINE_TO => {
520 p.parse_line_to()?;
521 }
522 operator::HORIZONTAL_LINE_TO => {
523 p.parse_horizontal_line_to()?;
524 }
525 operator::VERTICAL_LINE_TO => {
526 p.parse_vertical_line_to()?;
527 }
528 operator::CURVE_TO => {
529 p.parse_curve_to()?;
530 }
531 operator::CALL_LOCAL_SUBROUTINE => {
532 if p.stack.is_empty() {
533 return Err(CFFError::InvalidArgumentsStackLength);
534 }
535
536 if depth == STACK_LIMIT {
537 return Err(CFFError::NestingLimitReached);
538 }
539
540 if ctx.local_subrs.is_none() {
544 if let FontKind::CID(ref cid) = ctx.metadata.kind {
545 ctx.local_subrs =
546 parse_cid_local_subrs(ctx.metadata.table_data, ctx.glyph_id, cid);
547 }
548 }
549
550 if let Some(local_subrs) = ctx.local_subrs {
551 let subroutine_bias = calc_subroutine_bias(local_subrs.len());
552 let index = conv_subroutine_index(p.stack.pop()?, subroutine_bias)?;
553 let char_string = local_subrs
554 .get(index)
555 .ok_or(CFFError::InvalidSubroutineIndex)?;
556 _parse_char_string(ctx, char_string, depth + 1, p)?;
557 } else {
558 return Err(CFFError::NoLocalSubroutines);
559 }
560
561 if ctx.has_endchar && !ctx.has_seac {
562 if !s.at_end() {
563 return Err(CFFError::DataAfterEndChar);
564 }
565
566 break;
567 }
568 }
569 operator::RETURN => {
570 break;
571 }
572 TWO_BYTE_OPERATOR_MARK => {
573 let op2 = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
575 match op2 {
576 operator::HFLEX => p.parse_hflex()?,
577 operator::FLEX => p.parse_flex()?,
578 operator::HFLEX1 => p.parse_hflex1()?,
579 operator::FLEX1 => p.parse_flex1()?,
580 _ => return Err(CFFError::UnsupportedOperator),
581 }
582 }
583 operator::ENDCHAR => {
584 if p.stack.len() == 4 || (ctx.width.is_none() && p.stack.len() == 5) {
585 let accent_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop()?)
587 .ok_or(CFFError::InvalidSeacCode)?;
588 let base_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop()?)
589 .ok_or(CFFError::InvalidSeacCode)?;
590 let dy = p.stack.pop()?;
591 let dx = p.stack.pop()?;
592
593 p.stack.clear();
600
601 ctx.has_seac = true;
602
603 if depth == STACK_LIMIT {
604 return Err(CFFError::NestingLimitReached);
605 }
606
607 let base_char_string = ctx
608 .metadata
609 .char_strings
610 .get(u32::from(base_char.0))
611 .ok_or(CFFError::InvalidSeacCode)?;
612
613 if p.width_only {
614 let _ = _parse_char_string(ctx, base_char_string, depth + 1, p);
621 } else {
622 _parse_char_string(ctx, base_char_string, depth + 1, p)?;
623 p.x = dx;
624 p.y = dy;
625
626 let accent_char_string = ctx
627 .metadata
628 .char_strings
629 .get(u32::from(accent_char.0))
630 .ok_or(CFFError::InvalidSeacCode)?;
631 _parse_char_string(ctx, accent_char_string, depth + 1, p)?;
632 }
633 } else if p.stack.len() == 1 && ctx.width.is_none() {
634 ctx.width = Some(p.stack.pop()?);
635 }
636
637 if !p.is_first_move_to {
638 p.is_first_move_to = true;
639 p.builder.close();
640 }
641
642 if !s.at_end() {
643 return Err(CFFError::DataAfterEndChar);
644 }
645
646 ctx.has_endchar = true;
647
648 break;
649 }
650 operator::HINT_MASK | operator::COUNTER_MASK => {
651 let mut len = p.stack.len();
652
653 p.stack.clear();
655
656 if len.is_odd() {
658 len -= 1;
659 if ctx.width.is_none() {
660 ctx.width = Some(p.stack.at(0));
661 }
662 }
663
664 ctx.stems_len += len as u32 >> 1;
665
666 s.advance(usize::num_from((ctx.stems_len + 7) >> 3));
667 }
668 operator::MOVE_TO => {
669 let mut i = 0;
670 if p.stack.len() == 3 {
671 i += 1;
672 if ctx.width.is_none() {
673 ctx.width = Some(p.stack.at(0));
674 }
675 }
676
677 p.parse_move_to(i)?;
678 }
679 operator::HORIZONTAL_MOVE_TO => {
680 let mut i = 0;
681 if p.stack.len() == 2 {
682 i += 1;
683 if ctx.width.is_none() {
684 ctx.width = Some(p.stack.at(0));
685 }
686 }
687
688 p.parse_horizontal_move_to(i)?;
689 }
690 operator::CURVE_LINE => {
691 p.parse_curve_line()?;
692 }
693 operator::LINE_CURVE => {
694 p.parse_line_curve()?;
695 }
696 operator::VV_CURVE_TO => {
697 p.parse_vv_curve_to()?;
698 }
699 operator::HH_CURVE_TO => {
700 p.parse_hh_curve_to()?;
701 }
702 operator::SHORT_INT => {
703 let n = s.read::<i16>().ok_or(CFFError::ReadOutOfBounds)?;
704 p.stack.push(f64::from(n))?;
705 }
706 operator::CALL_GLOBAL_SUBROUTINE => {
707 if p.stack.is_empty() {
708 return Err(CFFError::InvalidArgumentsStackLength);
709 }
710
711 if depth == STACK_LIMIT {
712 return Err(CFFError::NestingLimitReached);
713 }
714
715 let subroutine_bias = calc_subroutine_bias(ctx.metadata.global_subrs.len());
716 let index = conv_subroutine_index(p.stack.pop()?, subroutine_bias)?;
717 let char_string = ctx
718 .metadata
719 .global_subrs
720 .get(index)
721 .ok_or(CFFError::InvalidSubroutineIndex)?;
722 _parse_char_string(ctx, char_string, depth + 1, p)?;
723
724 if ctx.has_endchar && !ctx.has_seac {
725 if !s.at_end() {
726 return Err(CFFError::DataAfterEndChar);
727 }
728
729 break;
730 }
731 }
732 operator::VH_CURVE_TO => {
733 p.parse_vh_curve_to()?;
734 }
735 operator::HV_CURVE_TO => {
736 p.parse_hv_curve_to()?;
737 }
738 32..=246 => {
739 p.parse_int1(op)?;
740 }
741 247..=250 => {
742 p.parse_int2(op, &mut s)?;
743 }
744 251..=254 => {
745 p.parse_int3(op, &mut s)?;
746 }
747 operator::FIXED_16_16 => {
748 p.parse_fixed(&mut s)?;
749 }
750 }
751
752 if p.width_only && ctx.width.is_some() {
753 break;
754 }
755 }
756
757 Ok(())
760}
761
762fn seac_code_to_glyph_id(charset: &Charset, n: f64) -> Option<GlyphId> {
763 let code = u8::try_num_from(n)?;
764
765 let sid = STANDARD_ENCODING[usize::from(code)];
766 let sid = StringId(u16::from(sid));
767
768 match charset {
769 Charset::ISOAdobe => {
770 if code <= 228 {
772 Some(GlyphId(sid.0))
773 } else {
774 None
775 }
776 }
777 Charset::Expert | Charset::ExpertSubset => None,
778 _ => charset.sid_to_gid(sid),
779 }
780}
781
782#[derive(Clone, Copy, Debug)]
783enum FDSelect<'a> {
784 Format0(LazyArray16<'a, u8>),
785 Format3(&'a [u8]), }
787
788impl Default for FDSelect<'_> {
789 fn default() -> Self {
790 FDSelect::Format0(LazyArray16::default())
791 }
792}
793
794impl FDSelect<'_> {
795 fn font_dict_index(&self, glyph_id: GlyphId) -> Option<u8> {
796 match self {
797 FDSelect::Format0(ref array) => array.get(glyph_id.0),
798 FDSelect::Format3(data) => {
799 let mut s = Stream::new(data);
800 let number_of_ranges = s.read::<u16>()?;
801 if number_of_ranges == 0 {
802 return None;
803 }
804
805 let number_of_ranges = number_of_ranges.checked_add(1)?;
809
810 let mut prev_first_glyph = s.read::<GlyphId>()?;
812 let mut prev_index = s.read::<u8>()?;
813 for _ in 1..number_of_ranges {
814 let curr_first_glyph = s.read::<GlyphId>()?;
815 if (prev_first_glyph..curr_first_glyph).contains(&glyph_id) {
816 return Some(prev_index);
817 } else {
818 prev_index = s.read::<u8>()?;
819 }
820
821 prev_first_glyph = curr_first_glyph;
822 }
823
824 None
825 }
826 }
827 }
828}
829
830fn parse_fd_select<'a>(number_of_glyphs: u16, s: &mut Stream<'a>) -> Option<FDSelect<'a>> {
831 let format = s.read::<u8>()?;
832 match format {
833 0 => Some(FDSelect::Format0(s.read_array16::<u8>(number_of_glyphs)?)),
834 3 => Some(FDSelect::Format3(s.tail()?)),
835 _ => None,
836 }
837}
838
839fn parse_sid_metadata<'a>(
840 data: &'a [u8],
841 top_dict: TopDict,
842 encoding: Encoding<'a>,
843) -> Option<FontKind<'a>> {
844 let mut metadata = SIDMetadata::default();
845 metadata.encoding = encoding;
846
847 let private_dict = if let Some(range) = top_dict.private_dict_range.clone() {
848 parse_private_dict(data.get(range)?)
849 } else {
850 return Some(FontKind::SID(metadata));
851 };
852
853 metadata.default_width = private_dict.default_width.unwrap_or(0.0);
854 metadata.nominal_width = private_dict.nominal_width.unwrap_or(0.0);
855
856 if let (Some(private_dict_range), Some(subroutines_offset)) = (
857 top_dict.private_dict_range,
858 private_dict.local_subroutines_offset,
859 ) {
860 if let Some(start) = private_dict_range.start.checked_add(subroutines_offset) {
863 let data = data.get(start..data.len())?;
864 let mut s = Stream::new(data);
865 metadata.local_subrs = parse_index::<u16>(&mut s)?;
866 }
867 }
868
869 Some(FontKind::SID(metadata))
870}
871
872fn parse_cid_metadata(data: &[u8], top_dict: TopDict, number_of_glyphs: u16) -> Option<FontKind> {
873 let (charset_offset, fd_array_offset, fd_select_offset) = match (
874 top_dict.charset_offset,
875 top_dict.fd_array_offset,
876 top_dict.fd_select_offset,
877 ) {
878 (Some(a), Some(b), Some(c)) => (a, b, c),
879 _ => return None, };
881
882 if charset_offset <= charset_id::EXPERT_SUBSET {
883 return None;
886 }
887
888 let mut metadata = CIDMetadata::default();
889
890 metadata.fd_array = {
891 let mut s = Stream::new_at(data, fd_array_offset)?;
892 parse_index::<u16>(&mut s)?
893 };
894
895 metadata.fd_select = {
896 let mut s = Stream::new_at(data, fd_select_offset)?;
897 parse_fd_select(number_of_glyphs, &mut s)?
898 };
899
900 Some(FontKind::CID(metadata))
901}
902
903#[derive(Clone, Copy)]
906pub struct Table<'a> {
907 table_data: &'a [u8],
910
911 #[allow(dead_code)]
912 strings: Index<'a>,
913 global_subrs: Index<'a>,
914 pub encoding: Encoding<'a>,
915 pub charset: Charset<'a>,
916 number_of_glyphs: NonZeroU16,
917 matrix: Matrix,
918 char_strings: Index<'a>,
919 kind: FontKind<'a>,
920 version: Option<StringId>,
921 notice: Option<StringId>,
922 full_name: Option<StringId>,
923 family_name: Option<StringId>,
924}
925
926impl<'a> Table<'a> {
927 pub fn parse(data: &'a [u8]) -> Option<Self> {
929 let mut s = Stream::new(data);
930
931 let major = s.read::<u8>()?;
933 s.skip::<u8>(); let header_size = s.read::<u8>()?;
935 s.skip::<u8>(); if major != 1 {
938 return None;
939 }
940
941 if header_size > 4 {
943 s.advance(usize::from(header_size) - 4);
944 }
945
946 skip_index::<u16>(&mut s)?;
948
949 let top_dict = parse_top_dict(&mut s)?;
950
951 if top_dict.char_strings_offset == 0 {
953 return None;
954 }
955
956 let strings = parse_index::<u16>(&mut s)?;
958
959 let global_subrs = parse_index::<u16>(&mut s)?;
961
962 let char_strings = {
963 let mut s = Stream::new_at(data, top_dict.char_strings_offset)?;
964 parse_index::<u16>(&mut s)?
965 };
966
967 let number_of_glyphs = u16::try_from(char_strings.len())
969 .ok()
970 .and_then(NonZeroU16::new)?;
971
972 let charset = match top_dict.charset_offset {
973 Some(charset_id::ISO_ADOBE) => Charset::ISOAdobe,
974 Some(charset_id::EXPERT) => Charset::Expert,
975 Some(charset_id::EXPERT_SUBSET) => Charset::ExpertSubset,
976 Some(offset) => {
977 let mut s = Stream::new_at(data, offset)?;
978 parse_charset(number_of_glyphs, &mut s)?
979 }
980 None => Charset::ISOAdobe, };
982
983 let matrix = top_dict.matrix;
984 let version = top_dict.version;
985 let notice = top_dict.notice;
986 let full_name = top_dict.full_name;
987 let family_name = top_dict.family_name;
988
989 let encoding = match top_dict.encoding_offset {
991 Some(encoding_id::STANDARD) => Encoding::new_standard(),
992 Some(encoding_id::EXPERT) => Encoding::new_expert(),
993 Some(offset) => parse_encoding(&mut Stream::new_at(data, offset)?)?,
994 None => Encoding::new_standard(), };
996
997 let kind = if top_dict.has_ros {
998 parse_cid_metadata(data, top_dict, number_of_glyphs.get())?
999 } else {
1000 parse_sid_metadata(data, top_dict, encoding.clone())?
1001 };
1002
1003 Some(Self {
1004 table_data: data,
1005 strings,
1006 global_subrs,
1007 encoding,
1008 charset,
1009 number_of_glyphs,
1010 matrix,
1011 char_strings,
1012 kind,
1013 version,
1014 notice,
1015 full_name,
1016 family_name,
1017 })
1018 }
1019
1020 #[inline]
1024 pub fn number_of_glyphs(&self) -> u16 {
1025 self.number_of_glyphs.get()
1026 }
1027
1028 #[inline]
1030 pub fn matrix(&self) -> Matrix {
1031 self.matrix
1032 }
1033
1034 pub fn glyph_fd_matrix(&self, glyph_id: GlyphId) -> Matrix {
1044 if let FontKind::CID(ref cid) = self.kind {
1045 if let Some(fd_index) = cid.fd_select.font_dict_index(glyph_id) {
1046 if let Some(fd_data) = cid.fd_array.get(u32::from(fd_index)) {
1047 if let Some(fd_matrix) = parse_font_dict_matrix(fd_data) {
1048 return fd_matrix;
1049 }
1050 }
1051 }
1052 }
1053 self.matrix
1054 }
1055
1056 pub fn outline(
1058 &self,
1059 glyph_id: GlyphId,
1060 builder: &mut dyn OutlineBuilder,
1061 ) -> Result<Rect, CFFError> {
1062 let data = self
1063 .char_strings
1064 .get(u32::from(glyph_id.0))
1065 .ok_or(CFFError::NoGlyph)?;
1066 parse_char_string(data, self, glyph_id, false, builder).map(|v| v.0)
1067 }
1068
1069 pub fn glyph_index(&self, code_point: u8) -> Option<GlyphId> {
1074 match self.kind {
1075 FontKind::SID(ref sid_meta) => {
1076 match sid_meta.encoding.code_to_gid(&self.charset, code_point) {
1077 Some(id) => Some(id),
1078 None => {
1079 Encoding::new_standard().code_to_gid(&self.charset, code_point)
1082 }
1083 }
1084 }
1085 FontKind::CID(_) => None,
1086 }
1087 }
1088
1089 pub fn glyph_width(&self, glyph_id: GlyphId) -> Option<u16> {
1095 match self.kind {
1096 FontKind::SID(ref sid) => {
1097 let data = self.char_strings.get(u32::from(glyph_id.0))?;
1098 let (_, width) =
1099 parse_char_string(data, self, glyph_id, true, &mut DummyOutline).ok()?;
1100 let width = width
1101 .map(|w| sid.nominal_width + w)
1102 .unwrap_or(sid.default_width);
1103 u16::try_from(width as i32).ok()
1104 }
1105 FontKind::CID(ref cid) => {
1106 let cs_data = self.char_strings.get(u32::from(glyph_id.0))?;
1111 let (_, width) =
1112 parse_char_string(cs_data, self, glyph_id, true, &mut DummyOutline).ok()?;
1113 let font_dict_index = cid.fd_select.font_dict_index(glyph_id)?;
1114 let font_dict_data = cid.fd_array.get(u32::from(font_dict_index))?;
1115 let private_dict_range = parse_font_dict(font_dict_data)?;
1116 let private_dict_data = self.table_data.get(private_dict_range)?;
1117 let private_dict = parse_private_dict(private_dict_data);
1118 let nominal_width = private_dict.nominal_width.unwrap_or(0.0);
1119 let default_width = private_dict.default_width.unwrap_or(0.0);
1120 let width = width.map(|w| nominal_width + w).unwrap_or(default_width);
1121 u16::try_from(width as i32).ok()
1122 }
1123 }
1124 }
1125
1126 pub fn glyph_width_f64(&self, glyph_id: GlyphId) -> Option<f64> {
1132 match self.kind {
1133 FontKind::SID(ref sid) => {
1134 let data = self.char_strings.get(u32::from(glyph_id.0))?;
1135 let (_, width) =
1136 parse_char_string(data, self, glyph_id, true, &mut DummyOutline).ok()?;
1137 let width = width
1138 .map(|w| sid.nominal_width + w)
1139 .unwrap_or(sid.default_width);
1140 Some(width)
1141 }
1142 FontKind::CID(ref cid) => {
1143 let cs_data = self.char_strings.get(u32::from(glyph_id.0))?;
1144 let (_, width) =
1145 parse_char_string(cs_data, self, glyph_id, true, &mut DummyOutline).ok()?;
1146 let font_dict_index = cid.fd_select.font_dict_index(glyph_id)?;
1147 let font_dict_data = cid.fd_array.get(u32::from(font_dict_index))?;
1148 let private_dict_range = parse_font_dict(font_dict_data)?;
1149 let private_dict_data = self.table_data.get(private_dict_range)?;
1150 let private_dict = parse_private_dict(private_dict_data);
1151 let nominal_width = private_dict.nominal_width.unwrap_or(0.0);
1152 let default_width = private_dict.default_width.unwrap_or(0.0);
1153 let width = width.map(|w| nominal_width + w).unwrap_or(default_width);
1154 Some(width)
1155 }
1156 }
1157 }
1158
1159 pub fn glyph_width_f32(&self, glyph_id: GlyphId) -> Option<f32> {
1163 self.glyph_width_f64(glyph_id).map(|w| w as f32)
1164 }
1165
1166 pub fn glyph_width_f64_verapdf(&self, glyph_id: GlyphId) -> Option<f64> {
1178 match self.kind {
1179 FontKind::SID(ref sid) => {
1180 let data = self.char_strings.get(u32::from(glyph_id.0))?;
1181 let (_, width) =
1182 parse_char_string(data, self, glyph_id, true, &mut DummyOutline).ok()?;
1183 let width = width
1184 .map(|w| sid.nominal_width.trunc() + w)
1185 .unwrap_or(sid.default_width.trunc());
1186 Some(width)
1187 }
1188 FontKind::CID(ref cid) => {
1189 let cs_data = self.char_strings.get(u32::from(glyph_id.0))?;
1190 let (_, width) =
1191 parse_char_string(cs_data, self, glyph_id, true, &mut DummyOutline).ok()?;
1192 let font_dict_index = cid.fd_select.font_dict_index(glyph_id)?;
1193 let font_dict_data = cid.fd_array.get(u32::from(font_dict_index))?;
1194 let private_dict_range = parse_font_dict(font_dict_data)?;
1195 let private_dict_data = self.table_data.get(private_dict_range)?;
1196 let private_dict = parse_private_dict(private_dict_data);
1197 let nominal_width = private_dict.nominal_width.unwrap_or(0.0);
1198 let default_width = private_dict.default_width.unwrap_or(0.0);
1199 let width = width
1200 .map(|w| nominal_width.trunc() + w)
1201 .unwrap_or(default_width.trunc());
1202 Some(width)
1203 }
1204 }
1205 }
1206
1207 pub fn glyph_index_by_name(&self, name: &str) -> Option<GlyphId> {
1209 match self.kind {
1210 FontKind::SID(_) => {
1211 let sid = if let Some(index) = STANDARD_NAMES.iter().position(|n| *n == name) {
1212 StringId(index as u16)
1213 } else {
1214 let index = self
1215 .strings
1216 .into_iter()
1217 .position(|n| n == name.as_bytes())?;
1218 StringId((STANDARD_NAMES.len() + index) as u16)
1219 };
1220
1221 self.charset.sid_to_gid(sid)
1222 }
1223 FontKind::CID(_) => None,
1224 }
1225 }
1226
1227 pub fn default_width_x(&self) -> Option<u16> {
1232 match self.kind {
1233 FontKind::SID(ref sid) => u16::try_from(sid.default_width as i32).ok(),
1234 FontKind::CID(_) => None,
1235 }
1236 }
1237
1238 pub fn default_width_x_f64(&self) -> Option<f64> {
1240 match self.kind {
1241 FontKind::SID(ref sid) => Some(sid.default_width),
1242 FontKind::CID(_) => None,
1243 }
1244 }
1245
1246 pub fn glyph_name(&self, glyph_id: GlyphId) -> Option<&'a str> {
1248 match self.kind {
1249 FontKind::SID(_) => {
1250 let sid = self.charset.gid_to_sid(glyph_id)?;
1251 let sid = usize::from(sid.0);
1252 match STANDARD_NAMES.get(sid) {
1253 Some(name) => Some(name),
1254 None => {
1255 let idx = u32::try_from(sid - STANDARD_NAMES.len()).ok()?;
1256 let name = self.strings.get(idx)?;
1257 core::str::from_utf8(name).ok()
1258 }
1259 }
1260 }
1261 FontKind::CID(_) => None,
1262 }
1263 }
1264
1265 pub fn glyph_cid(&self, glyph_id: GlyphId) -> Option<u16> {
1269 match self.kind {
1270 FontKind::SID(_) => None,
1271 FontKind::CID(_) => self.charset.gid_to_sid(glyph_id).map(|id| id.0),
1272 }
1273 }
1274
1275 pub fn version(&self) -> Option<&str> {
1276 self.version.and_then(|sid| string_by_id(&self, sid))
1277 }
1278
1279 pub fn notice(&self) -> Option<&str> {
1280 self.notice.and_then(|sid| string_by_id(&self, sid))
1281 }
1282
1283 pub fn full_name(&self) -> Option<&str> {
1284 self.full_name.and_then(|sid| string_by_id(&self, sid))
1285 }
1286
1287 pub fn family_name(&self) -> Option<&str> {
1288 self.family_name.and_then(|sid| string_by_id(&self, sid))
1289 }
1290}
1291
1292impl core::fmt::Debug for Table<'_> {
1293 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1294 write!(f, "Table {{ ... }}")
1295 }
1296}
1297
1298#[cfg(test)]
1299mod width_tests {
1300 use super::*;
1301
1302 #[rustfmt::skip]
1321 const MINIMAL_CID_CFF: &[u8] = &[
1322 0x01, 0x00, 0x04, 0x01,
1324
1325 0x00, 0x01, 0x01, 0x01, 0x02, 0x46,
1327
1328 0x00, 0x01, 0x01, 0x01, 0x11,
1330 0xCD, 0xF7, 0x78, 0x8B, 0x0C, 0x1E,
1333 0xAE, 0x0F,
1335 0xB1, 0x0C, 0x25,
1337 0xBE, 0x0C, 0x24,
1339 0xB4, 0x11,
1341
1342 0x00, 0x00,
1344
1345 0x00, 0x00,
1347
1348 0x00, 0x00, 0x01,
1350
1351 0x00, 0x00, 0x00,
1353
1354 0x00, 0x02, 0x01, 0x01, 0x02, 0x05,
1356 0x0E,
1358 0xF9, 0x1E, 0x0E,
1360
1361 0x00, 0x01, 0x01, 0x01, 0x04,
1363 0x90, 0xC6, 0x12,
1366
1367 0xF8, 0x88, 0x14, 0x8B, 0x15, ];
1371
1372 #[test]
1373 fn cid_glyph_width_default() {
1374 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1376 assert_eq!(
1377 table.glyph_width(GlyphId(0)),
1378 Some(500),
1379 "GID 0 must return DefaultWidth=500"
1380 );
1381 }
1382
1383 #[test]
1384 fn cid_glyph_width_nominal_plus_delta() {
1385 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1387 assert_eq!(
1388 table.glyph_width(GlyphId(1)),
1389 Some(650),
1390 "GID 1 must return NominalWidth(0) + 650 = 650"
1391 );
1392 }
1393
1394 #[test]
1395 fn cid_glyph_width_out_of_range() {
1396 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1398 assert_eq!(
1399 table.glyph_width(GlyphId(2)),
1400 None,
1401 "GID 2 is out of range and must return None"
1402 );
1403 }
1404
1405 #[test]
1406 fn number_of_glyphs_matches_charstrings_count() {
1407 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1408 assert_eq!(table.number_of_glyphs(), 2);
1409 }
1410
1411 #[test]
1412 fn glyph_cid_notdef() {
1413 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1415 assert_eq!(table.glyph_cid(GlyphId(0)), Some(0));
1416 }
1417
1418 #[test]
1419 fn glyph_cid_gid1() {
1420 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1422 assert_eq!(table.glyph_cid(GlyphId(1)), Some(1));
1423 }
1424
1425 #[test]
1426 fn glyph_cid_out_of_range() {
1427 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1428 assert_eq!(table.glyph_cid(GlyphId(2)), None);
1429 }
1430
1431 #[test]
1432 fn glyph_name_returns_none_for_cid_font() {
1433 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1435 assert_eq!(table.glyph_name(GlyphId(0)), None);
1436 assert_eq!(table.glyph_name(GlyphId(1)), None);
1437 }
1438
1439 #[test]
1440 fn glyph_index_returns_none_for_cid_font() {
1441 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1443 assert_eq!(table.glyph_index(0x41), None); }
1445
1446 #[test]
1447 fn matrix_is_default_when_absent() {
1448 let table = Table::parse(MINIMAL_CID_CFF).expect("CID CFF should parse");
1450 let m = table.matrix();
1451 assert!((m.sx - 0.001).abs() < f64::EPSILON);
1452 assert!((m.sy - 0.001).abs() < f64::EPSILON);
1453 assert_eq!(m.kx, 0.0);
1454 assert_eq!(m.ky, 0.0);
1455 assert_eq!(m.tx, 0.0);
1456 assert_eq!(m.ty, 0.0);
1457 }
1458
1459 #[test]
1460 fn parse_empty_data_returns_none() {
1461 assert!(Table::parse(&[]).is_none());
1462 }
1463
1464 #[test]
1465 fn parse_truncated_header_returns_none() {
1466 assert!(Table::parse(&[0x01, 0x00, 0x04]).is_none());
1468 }
1469
1470 #[test]
1471 fn malformed_charstring_returns_error() {
1472 let mut data = MINIMAL_CID_CFF.to_vec();
1473 data[48] = operator::CALL_GLOBAL_SUBROUTINE;
1474 data[49] = operator::ENDCHAR;
1475 data[50] = 0;
1476
1477 let table = Table::parse(&data).expect("CID CFF should parse");
1478 assert_eq!(
1479 table.outline(GlyphId(1), &mut DummyOutline),
1480 Err(CFFError::InvalidArgumentsStackLength)
1481 );
1482 }
1483}