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 FULL_NAME: u16 = 2;
67 pub const CHARSET_OFFSET: u16 = 15;
68 pub const ENCODING_OFFSET: u16 = 16;
69 pub const CHAR_STRINGS_OFFSET: u16 = 17;
70 pub const PRIVATE_DICT_SIZE_AND_OFFSET: u16 = 18;
71 pub const FONT_MATRIX: u16 = 1207;
72 pub const ROS: u16 = 1230;
73 pub const FD_ARRAY: u16 = 1236;
74 pub const FD_SELECT: u16 = 1237;
75}
76
77mod private_dict_operator {
80 pub const LOCAL_SUBROUTINES_OFFSET: u16 = 19;
81 pub const DEFAULT_WIDTH: u16 = 20;
82 pub const NOMINAL_WIDTH: u16 = 21;
83}
84
85mod charset_id {
87 pub const ISO_ADOBE: usize = 0;
88 pub const EXPERT: usize = 1;
89 pub const EXPERT_SUBSET: usize = 2;
90}
91
92mod encoding_id {
94 pub const STANDARD: usize = 0;
95 pub const EXPERT: usize = 1;
96}
97
98#[derive(Clone, Copy, Debug)]
99pub(crate) enum FontKind<'a> {
100 SID(SIDMetadata<'a>),
101 CID(CIDMetadata<'a>),
102}
103
104#[derive(Clone, Copy, Default, Debug)]
105pub(crate) struct SIDMetadata<'a> {
106 local_subrs: Index<'a>,
107 default_width: f32,
109 nominal_width: f32,
111 encoding: Encoding<'a>,
112}
113
114#[derive(Clone, Copy, Default, Debug)]
115pub(crate) struct CIDMetadata<'a> {
116 fd_array: Index<'a>,
117 fd_select: FDSelect<'a>,
118}
119
120#[allow(missing_docs)]
122#[derive(Clone, Copy, Debug)]
123pub struct Matrix {
124 pub sx: f32,
125 pub ky: f32,
126 pub kx: f32,
127 pub sy: f32,
128 pub tx: f32,
129 pub ty: f32,
130}
131
132impl Default for Matrix {
133 fn default() -> Self {
134 Self {
135 sx: 0.001,
136 ky: 0.0,
137 kx: 0.0,
138 sy: 0.001,
139 tx: 0.0,
140 ty: 0.0,
141 }
142 }
143}
144
145#[derive(Default)]
146struct TopDict {
147 full_name: Option<StringId>,
148 charset_offset: Option<usize>,
149 encoding_offset: Option<usize>,
150 char_strings_offset: usize,
151 private_dict_range: Option<Range<usize>>,
152 matrix: Matrix,
153 has_ros: bool,
154 fd_array_offset: Option<usize>,
155 fd_select_offset: Option<usize>,
156}
157
158fn parse_top_dict(s: &mut Stream) -> Option<TopDict> {
159 let mut top_dict = TopDict::default();
160
161 let index = parse_index::<u16>(s)?;
162
163 let data = index.get(0)?;
165
166 let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
167 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
168 while let Some(operator) = dict_parser.parse_next() {
169 match operator.get() {
170 top_dict_operator::FULL_NAME => {
171 top_dict.full_name = dict_parser.parse_sid();
172 }
173 top_dict_operator::CHARSET_OFFSET => {
174 top_dict.charset_offset = dict_parser.parse_offset();
175 }
176 top_dict_operator::ENCODING_OFFSET => {
177 top_dict.encoding_offset = dict_parser.parse_offset();
178 }
179 top_dict_operator::CHAR_STRINGS_OFFSET => {
180 top_dict.char_strings_offset = dict_parser.parse_offset()?;
181 }
182 top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET => {
183 top_dict.private_dict_range = dict_parser.parse_range();
184 }
185 top_dict_operator::FONT_MATRIX => {
186 dict_parser.parse_operands()?;
187 let operands = dict_parser.operands();
188 if operands.len() == 6 {
189 top_dict.matrix = Matrix {
190 sx: operands[0] as f32,
191 ky: operands[1] as f32,
192 kx: operands[2] as f32,
193 sy: operands[3] as f32,
194 tx: operands[4] as f32,
195 ty: operands[5] as f32,
196 };
197 }
198 }
199 top_dict_operator::ROS => {
200 top_dict.has_ros = true;
201 }
202 top_dict_operator::FD_ARRAY => {
203 top_dict.fd_array_offset = dict_parser.parse_offset();
204 }
205 top_dict_operator::FD_SELECT => {
206 top_dict.fd_select_offset = dict_parser.parse_offset();
207 }
208 _ => {}
209 }
210 }
211
212 Some(top_dict)
213}
214
215#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn private_dict_size_overflow() {
222 let data = &[
223 0x00, 0x01, 0x01, 0x01, 0x0C, 0x1D, 0x7F, 0xFF, 0xFF, 0xFF, 0x1D, 0x7F, 0xFF, 0xFF, 0xFF, 0x12, ];
231
232 let top_dict = parse_top_dict(&mut Stream::new(data)).unwrap();
233 assert_eq!(top_dict.private_dict_range, Some(2147483647..4294967294));
234 }
235
236 #[test]
237 fn private_dict_negative_char_strings_offset() {
238 let data = &[
239 0x00, 0x01, 0x01, 0x01, 0x03, 0x8A, 0x11, ];
247
248 assert!(parse_top_dict(&mut Stream::new(data)).is_none());
249 }
250
251 #[test]
252 fn private_dict_no_char_strings_offset_operand() {
253 let data = &[
254 0x00, 0x01, 0x01, 0x01, 0x02, 0x11, ];
262
263 assert!(parse_top_dict(&mut Stream::new(data)).is_none());
264 }
265
266 #[test]
267 fn negative_private_dict_offset_and_size() {
268 let data = &[
269 0x00, 0x01, 0x01, 0x01, 0x04, 0x8A, 0x8A, 0x12, ];
278
279 let top_dict = parse_top_dict(&mut Stream::new(data)).unwrap();
280 assert!(top_dict.private_dict_range.is_none());
281 }
282}
283
284#[derive(Default, Debug)]
285struct PrivateDict {
286 local_subroutines_offset: Option<usize>,
287 default_width: Option<f32>,
288 nominal_width: Option<f32>,
289}
290
291fn parse_private_dict(data: &[u8]) -> PrivateDict {
292 let mut dict = PrivateDict::default();
293 let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
294 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
295 while let Some(operator) = dict_parser.parse_next() {
296 if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET {
297 dict.local_subroutines_offset = dict_parser.parse_offset();
298 } else if operator.get() == private_dict_operator::DEFAULT_WIDTH {
299 dict.default_width = dict_parser.parse_number().map(|n| n as f32);
300 } else if operator.get() == private_dict_operator::NOMINAL_WIDTH {
301 dict.nominal_width = dict_parser.parse_number().map(|n| n as f32);
302 }
303 }
304
305 dict
306}
307
308fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
309 let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
310 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
311 while let Some(operator) = dict_parser.parse_next() {
312 if operator.get() == top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET {
313 return dict_parser.parse_range();
314 }
315 }
316
317 None
318}
319
320fn parse_cid_local_subrs<'a>(
327 data: &'a [u8],
328 glyph_id: GlyphId,
329 cid: &CIDMetadata,
330) -> Option<Index<'a>> {
331 let font_dict_index = cid.fd_select.font_dict_index(glyph_id)?;
332 let font_dict_data = cid.fd_array.get(u32::from(font_dict_index))?;
333 let private_dict_range = parse_font_dict(font_dict_data)?;
334 let private_dict_data = data.get(private_dict_range.clone())?;
335 let private_dict = parse_private_dict(private_dict_data);
336 let subroutines_offset = private_dict.local_subroutines_offset?;
337
338 let start = private_dict_range.start.checked_add(subroutines_offset)?;
341 let subrs_data = data.get(start..)?;
342 let mut s = Stream::new(subrs_data);
343 parse_index::<u16>(&mut s)
344}
345
346pub fn string_by_id<'a>(metadata: &'a Table, sid: StringId) -> Option<&'a str> {
347 let sid = usize::from(sid.0);
348 match STANDARD_NAMES.get(sid) {
349 Some(name) => Some(name),
350 None => {
351 let idx = u32::try_from(sid - STANDARD_NAMES.len()).ok()?;
352 let name = metadata.strings.get(idx)?;
353 core::str::from_utf8(name).ok()
354 }
355 }
356}
357
358struct CharStringParserContext<'a> {
359 metadata: &'a Table<'a>,
360 width: Option<f32>,
361 stems_len: u32,
362 has_endchar: bool,
363 has_seac: bool,
364 glyph_id: GlyphId, local_subrs: Option<Index<'a>>,
366}
367
368fn parse_char_string(
369 data: &[u8],
370 metadata: &Table,
371 glyph_id: GlyphId,
372 width_only: bool,
373 builder: &mut dyn OutlineBuilder,
374) -> Result<(Rect, Option<f32>), CFFError> {
375 let local_subrs = match metadata.kind {
376 FontKind::SID(ref sid) => Some(sid.local_subrs),
377 FontKind::CID(_) => None, };
379
380 let mut ctx = CharStringParserContext {
381 metadata,
382 width: None,
383 stems_len: 0,
384 has_endchar: false,
385 has_seac: false,
386 glyph_id,
387 local_subrs,
388 };
389
390 let mut inner_builder = Builder {
391 builder,
392 bbox: RectF::new(),
393 };
394
395 let stack = ArgumentsStack {
396 data: &mut [0.0; MAX_ARGUMENTS_STACK_LEN], len: 0,
398 max_len: MAX_ARGUMENTS_STACK_LEN,
399 };
400 let mut parser = CharStringParser {
401 stack,
402 builder: &mut inner_builder,
403 x: 0.0,
404 y: 0.0,
405 has_move_to: false,
406 is_first_move_to: true,
407 width_only,
408 };
409 _parse_char_string(&mut ctx, data, 0, &mut parser)?;
410
411 if width_only {
412 return Ok((Rect::zero(), ctx.width));
413 }
414
415 if !ctx.has_endchar {
416 return Err(CFFError::MissingEndChar);
417 }
418
419 let bbox = parser.builder.bbox;
420
421 if bbox.is_default() {
423 return Err(CFFError::ZeroBBox);
424 }
425
426 let rect = bbox.to_rect().ok_or(CFFError::BboxOverflow)?;
427 Ok((rect, ctx.width))
428}
429
430fn _parse_char_string(
431 ctx: &mut CharStringParserContext,
432 char_string: &[u8],
433 depth: u8,
434 p: &mut CharStringParser,
435) -> Result<(), CFFError> {
436 let mut s = Stream::new(char_string);
437 while !s.at_end() {
438 let op = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
439 match op {
440 0 | 2 | 9 | 13 | 15 | 16 | 17 => {
441 return Err(CFFError::InvalidOperator);
443 }
444 operator::HORIZONTAL_STEM
445 | operator::VERTICAL_STEM
446 | operator::HORIZONTAL_STEM_HINT_MASK
447 | operator::VERTICAL_STEM_HINT_MASK => {
448 let len = if p.stack.len().is_odd() && ctx.width.is_none() {
455 ctx.width = Some(p.stack.at(0));
456 p.stack.len() - 1
457 } else {
458 p.stack.len()
459 };
460
461 ctx.stems_len += len as u32 >> 1;
462
463 p.stack.clear();
465 }
466 operator::VERTICAL_MOVE_TO => {
467 let mut i = 0;
468 if p.stack.len() == 2 {
469 i += 1;
470 if ctx.width.is_none() {
471 ctx.width = Some(p.stack.at(0));
472 }
473 }
474
475 p.parse_vertical_move_to(i)?;
476 }
477 operator::LINE_TO => {
478 p.parse_line_to()?;
479 }
480 operator::HORIZONTAL_LINE_TO => {
481 p.parse_horizontal_line_to()?;
482 }
483 operator::VERTICAL_LINE_TO => {
484 p.parse_vertical_line_to()?;
485 }
486 operator::CURVE_TO => {
487 p.parse_curve_to()?;
488 }
489 operator::CALL_LOCAL_SUBROUTINE => {
490 if p.stack.is_empty() {
491 return Err(CFFError::InvalidArgumentsStackLength);
492 }
493
494 if depth == STACK_LIMIT {
495 return Err(CFFError::NestingLimitReached);
496 }
497
498 if ctx.local_subrs.is_none() {
502 if let FontKind::CID(ref cid) = ctx.metadata.kind {
503 ctx.local_subrs =
504 parse_cid_local_subrs(ctx.metadata.table_data, ctx.glyph_id, cid);
505 }
506 }
507
508 if let Some(local_subrs) = ctx.local_subrs {
509 let subroutine_bias = calc_subroutine_bias(local_subrs.len());
510 let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
511 let char_string = local_subrs
512 .get(index)
513 .ok_or(CFFError::InvalidSubroutineIndex)?;
514 _parse_char_string(ctx, char_string, depth + 1, p)?;
515 } else {
516 return Err(CFFError::NoLocalSubroutines);
517 }
518
519 if ctx.has_endchar && !ctx.has_seac {
520 if !s.at_end() {
521 return Err(CFFError::DataAfterEndChar);
522 }
523
524 break;
525 }
526 }
527 operator::RETURN => {
528 break;
529 }
530 TWO_BYTE_OPERATOR_MARK => {
531 let op2 = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
533 match op2 {
534 operator::HFLEX => p.parse_hflex()?,
535 operator::FLEX => p.parse_flex()?,
536 operator::HFLEX1 => p.parse_hflex1()?,
537 operator::FLEX1 => p.parse_flex1()?,
538 _ => return Err(CFFError::UnsupportedOperator),
539 }
540 }
541 operator::ENDCHAR => {
542 if p.stack.len() == 4 || (ctx.width.is_none() && p.stack.len() == 5) {
543 let accent_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop())
545 .ok_or(CFFError::InvalidSeacCode)?;
546 let base_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop())
547 .ok_or(CFFError::InvalidSeacCode)?;
548 let dy = p.stack.pop();
549 let dx = p.stack.pop();
550
551 if ctx.width.is_none() && !p.stack.is_empty() {
552 ctx.width = Some(p.stack.pop())
553 }
554
555 ctx.has_seac = true;
556
557 if depth == STACK_LIMIT {
558 return Err(CFFError::NestingLimitReached);
559 }
560
561 let base_char_string = ctx
562 .metadata
563 .char_strings
564 .get(u32::from(base_char.0))
565 .ok_or(CFFError::InvalidSeacCode)?;
566 _parse_char_string(ctx, base_char_string, depth + 1, p)?;
567 p.x = dx;
568 p.y = dy;
569
570 let accent_char_string = ctx
571 .metadata
572 .char_strings
573 .get(u32::from(accent_char.0))
574 .ok_or(CFFError::InvalidSeacCode)?;
575 _parse_char_string(ctx, accent_char_string, depth + 1, p)?;
576 } else if p.stack.len() == 1 && ctx.width.is_none() {
577 ctx.width = Some(p.stack.pop());
578 }
579
580 if !p.is_first_move_to {
581 p.is_first_move_to = true;
582 p.builder.close();
583 }
584
585 if !s.at_end() {
586 return Err(CFFError::DataAfterEndChar);
587 }
588
589 ctx.has_endchar = true;
590
591 break;
592 }
593 operator::HINT_MASK | operator::COUNTER_MASK => {
594 let mut len = p.stack.len();
595
596 p.stack.clear();
598
599 if len.is_odd() {
601 len -= 1;
602 if ctx.width.is_none() {
603 ctx.width = Some(p.stack.at(0));
604 }
605 }
606
607 ctx.stems_len += len as u32 >> 1;
608
609 s.advance(usize::num_from((ctx.stems_len + 7) >> 3));
610 }
611 operator::MOVE_TO => {
612 let mut i = 0;
613 if p.stack.len() == 3 {
614 i += 1;
615 if ctx.width.is_none() {
616 ctx.width = Some(p.stack.at(0));
617 }
618 }
619
620 p.parse_move_to(i)?;
621 }
622 operator::HORIZONTAL_MOVE_TO => {
623 let mut i = 0;
624 if p.stack.len() == 2 {
625 i += 1;
626 if ctx.width.is_none() {
627 ctx.width = Some(p.stack.at(0));
628 }
629 }
630
631 p.parse_horizontal_move_to(i)?;
632 }
633 operator::CURVE_LINE => {
634 p.parse_curve_line()?;
635 }
636 operator::LINE_CURVE => {
637 p.parse_line_curve()?;
638 }
639 operator::VV_CURVE_TO => {
640 p.parse_vv_curve_to()?;
641 }
642 operator::HH_CURVE_TO => {
643 p.parse_hh_curve_to()?;
644 }
645 operator::SHORT_INT => {
646 let n = s.read::<i16>().ok_or(CFFError::ReadOutOfBounds)?;
647 p.stack.push(f32::from(n))?;
648 }
649 operator::CALL_GLOBAL_SUBROUTINE => {
650 if p.stack.is_empty() {
651 return Err(CFFError::InvalidArgumentsStackLength);
652 }
653
654 if depth == STACK_LIMIT {
655 return Err(CFFError::NestingLimitReached);
656 }
657
658 let subroutine_bias = calc_subroutine_bias(ctx.metadata.global_subrs.len());
659 let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
660 let char_string = ctx
661 .metadata
662 .global_subrs
663 .get(index)
664 .ok_or(CFFError::InvalidSubroutineIndex)?;
665 _parse_char_string(ctx, char_string, depth + 1, p)?;
666
667 if ctx.has_endchar && !ctx.has_seac {
668 if !s.at_end() {
669 return Err(CFFError::DataAfterEndChar);
670 }
671
672 break;
673 }
674 }
675 operator::VH_CURVE_TO => {
676 p.parse_vh_curve_to()?;
677 }
678 operator::HV_CURVE_TO => {
679 p.parse_hv_curve_to()?;
680 }
681 32..=246 => {
682 p.parse_int1(op)?;
683 }
684 247..=250 => {
685 p.parse_int2(op, &mut s)?;
686 }
687 251..=254 => {
688 p.parse_int3(op, &mut s)?;
689 }
690 operator::FIXED_16_16 => {
691 p.parse_fixed(&mut s)?;
692 }
693 }
694
695 if p.width_only && ctx.width.is_some() {
696 break;
697 }
698 }
699
700 Ok(())
703}
704
705fn seac_code_to_glyph_id(charset: &Charset, n: f32) -> Option<GlyphId> {
706 let code = u8::try_num_from(n)?;
707
708 let sid = STANDARD_ENCODING[usize::from(code)];
709 let sid = StringId(u16::from(sid));
710
711 match charset {
712 Charset::ISOAdobe => {
713 if code <= 228 {
715 Some(GlyphId(sid.0))
716 } else {
717 None
718 }
719 }
720 Charset::Expert | Charset::ExpertSubset => None,
721 _ => charset.sid_to_gid(sid),
722 }
723}
724
725#[derive(Clone, Copy, Debug)]
726enum FDSelect<'a> {
727 Format0(LazyArray16<'a, u8>),
728 Format3(&'a [u8]), }
730
731impl Default for FDSelect<'_> {
732 fn default() -> Self {
733 FDSelect::Format0(LazyArray16::default())
734 }
735}
736
737impl FDSelect<'_> {
738 fn font_dict_index(&self, glyph_id: GlyphId) -> Option<u8> {
739 match self {
740 FDSelect::Format0(ref array) => array.get(glyph_id.0),
741 FDSelect::Format3(data) => {
742 let mut s = Stream::new(data);
743 let number_of_ranges = s.read::<u16>()?;
744 if number_of_ranges == 0 {
745 return None;
746 }
747
748 let number_of_ranges = number_of_ranges.checked_add(1)?;
752
753 let mut prev_first_glyph = s.read::<GlyphId>()?;
755 let mut prev_index = s.read::<u8>()?;
756 for _ in 1..number_of_ranges {
757 let curr_first_glyph = s.read::<GlyphId>()?;
758 if (prev_first_glyph..curr_first_glyph).contains(&glyph_id) {
759 return Some(prev_index);
760 } else {
761 prev_index = s.read::<u8>()?;
762 }
763
764 prev_first_glyph = curr_first_glyph;
765 }
766
767 None
768 }
769 }
770 }
771}
772
773fn parse_fd_select<'a>(number_of_glyphs: u16, s: &mut Stream<'a>) -> Option<FDSelect<'a>> {
774 let format = s.read::<u8>()?;
775 match format {
776 0 => Some(FDSelect::Format0(s.read_array16::<u8>(number_of_glyphs)?)),
777 3 => Some(FDSelect::Format3(s.tail()?)),
778 _ => None,
779 }
780}
781
782fn parse_sid_metadata<'a>(
783 data: &'a [u8],
784 top_dict: TopDict,
785 encoding: Encoding<'a>,
786) -> Option<FontKind<'a>> {
787 let mut metadata = SIDMetadata::default();
788 metadata.encoding = encoding;
789
790 let private_dict = if let Some(range) = top_dict.private_dict_range.clone() {
791 parse_private_dict(data.get(range)?)
792 } else {
793 return Some(FontKind::SID(metadata));
794 };
795
796 metadata.default_width = private_dict.default_width.unwrap_or(0.0);
797 metadata.nominal_width = private_dict.nominal_width.unwrap_or(0.0);
798
799 if let (Some(private_dict_range), Some(subroutines_offset)) = (
800 top_dict.private_dict_range,
801 private_dict.local_subroutines_offset,
802 ) {
803 if let Some(start) = private_dict_range.start.checked_add(subroutines_offset) {
806 let data = data.get(start..data.len())?;
807 let mut s = Stream::new(data);
808 metadata.local_subrs = parse_index::<u16>(&mut s)?;
809 }
810 }
811
812 Some(FontKind::SID(metadata))
813}
814
815fn parse_cid_metadata(data: &[u8], top_dict: TopDict, number_of_glyphs: u16) -> Option<FontKind> {
816 let (charset_offset, fd_array_offset, fd_select_offset) = match (
817 top_dict.charset_offset,
818 top_dict.fd_array_offset,
819 top_dict.fd_select_offset,
820 ) {
821 (Some(a), Some(b), Some(c)) => (a, b, c),
822 _ => return None, };
824
825 if charset_offset <= charset_id::EXPERT_SUBSET {
826 return None;
829 }
830
831 let mut metadata = CIDMetadata::default();
832
833 metadata.fd_array = {
834 let mut s = Stream::new_at(data, fd_array_offset)?;
835 parse_index::<u16>(&mut s)?
836 };
837
838 metadata.fd_select = {
839 let mut s = Stream::new_at(data, fd_select_offset)?;
840 parse_fd_select(number_of_glyphs, &mut s)?
841 };
842
843 Some(FontKind::CID(metadata))
844}
845
846#[derive(Clone, Copy)]
849pub struct Table<'a> {
850 table_data: &'a [u8],
853
854 #[allow(dead_code)]
855 strings: Index<'a>,
856 global_subrs: Index<'a>,
857 pub encoding: Encoding<'a>,
858 pub charset: Charset<'a>,
859 number_of_glyphs: NonZeroU16,
860 matrix: Matrix,
861 char_strings: Index<'a>,
862 kind: FontKind<'a>,
863}
864
865impl<'a> Table<'a> {
866 pub fn parse(data: &'a [u8]) -> Option<Self> {
868 let mut s = Stream::new(data);
869
870 let major = s.read::<u8>()?;
872 s.skip::<u8>(); let header_size = s.read::<u8>()?;
874 s.skip::<u8>(); if major != 1 {
877 return None;
878 }
879
880 if header_size > 4 {
882 s.advance(usize::from(header_size) - 4);
883 }
884
885 skip_index::<u16>(&mut s)?;
887
888 let top_dict = parse_top_dict(&mut s)?;
889
890 if top_dict.char_strings_offset == 0 {
892 return None;
893 }
894
895 let strings = parse_index::<u16>(&mut s)?;
897
898 let global_subrs = parse_index::<u16>(&mut s)?;
900
901 let char_strings = {
902 let mut s = Stream::new_at(data, top_dict.char_strings_offset)?;
903 parse_index::<u16>(&mut s)?
904 };
905
906 let number_of_glyphs = u16::try_from(char_strings.len())
908 .ok()
909 .and_then(NonZeroU16::new)?;
910
911 let charset = match top_dict.charset_offset {
912 Some(charset_id::ISO_ADOBE) => Charset::ISOAdobe,
913 Some(charset_id::EXPERT) => Charset::Expert,
914 Some(charset_id::EXPERT_SUBSET) => Charset::ExpertSubset,
915 Some(offset) => {
916 let mut s = Stream::new_at(data, offset)?;
917 parse_charset(number_of_glyphs, &mut s)?
918 }
919 None => Charset::ISOAdobe, };
921
922 let matrix = top_dict.matrix;
923
924 let encoding = match top_dict.encoding_offset {
926 Some(encoding_id::STANDARD) => Encoding::new_standard(),
927 Some(encoding_id::EXPERT) => Encoding::new_expert(),
928 Some(offset) => parse_encoding(&mut Stream::new_at(data, offset)?)?,
929 None => Encoding::new_standard(), };
931
932 let kind = if top_dict.has_ros {
933 parse_cid_metadata(data, top_dict, number_of_glyphs.get())?
934 } else {
935 parse_sid_metadata(data, top_dict, encoding.clone())?
936 };
937
938 Some(Self {
939 table_data: data,
940 strings,
941 global_subrs,
942 encoding,
943 charset,
944 number_of_glyphs,
945 matrix,
946 char_strings,
947 kind,
948 })
949 }
950
951 #[inline]
955 pub fn number_of_glyphs(&self) -> u16 {
956 self.number_of_glyphs.get()
957 }
958
959 #[inline]
961 pub fn matrix(&self) -> Matrix {
962 self.matrix
963 }
964
965 pub fn outline(
967 &self,
968 glyph_id: GlyphId,
969 builder: &mut dyn OutlineBuilder,
970 ) -> Result<Rect, CFFError> {
971 let data = self
972 .char_strings
973 .get(u32::from(glyph_id.0))
974 .ok_or(CFFError::NoGlyph)?;
975 parse_char_string(data, self, glyph_id, false, builder).map(|v| v.0)
976 }
977
978 pub fn glyph_index(&self, code_point: u8) -> Option<GlyphId> {
983 match self.kind {
984 FontKind::SID(ref sid_meta) => {
985 match sid_meta.encoding.code_to_gid(&self.charset, code_point) {
986 Some(id) => Some(id),
987 None => {
988 Encoding::new_standard().code_to_gid(&self.charset, code_point)
991 }
992 }
993 }
994 FontKind::CID(_) => None,
995 }
996 }
997
998 pub fn glyph_width(&self, glyph_id: GlyphId) -> Option<u16> {
1004 match self.kind {
1005 FontKind::SID(ref sid) => {
1006 let data = self.char_strings.get(u32::from(glyph_id.0))?;
1007 let (_, width) =
1008 parse_char_string(data, self, glyph_id, true, &mut DummyOutline).ok()?;
1009 let width = width
1010 .map(|w| sid.nominal_width + w)
1011 .unwrap_or(sid.default_width);
1012 u16::try_from(width as i32).ok()
1013 }
1014 FontKind::CID(_) => None,
1015 }
1016 }
1017
1018 pub fn glyph_index_by_name(&self, name: &str) -> Option<GlyphId> {
1020 match self.kind {
1021 FontKind::SID(_) => {
1022 let sid = if let Some(index) = STANDARD_NAMES.iter().position(|n| *n == name) {
1023 StringId(index as u16)
1024 } else {
1025 let index = self
1026 .strings
1027 .into_iter()
1028 .position(|n| n == name.as_bytes())?;
1029 StringId((STANDARD_NAMES.len() + index) as u16)
1030 };
1031
1032 self.charset.sid_to_gid(sid)
1033 }
1034 FontKind::CID(_) => None,
1035 }
1036 }
1037
1038 pub fn glyph_name(&self, glyph_id: GlyphId) -> Option<&'a str> {
1040 match self.kind {
1041 FontKind::SID(_) => {
1042 let sid = self.charset.gid_to_sid(glyph_id)?;
1043 let sid = usize::from(sid.0);
1044 match STANDARD_NAMES.get(sid) {
1045 Some(name) => Some(name),
1046 None => {
1047 let idx = u32::try_from(sid - STANDARD_NAMES.len()).ok()?;
1048 let name = self.strings.get(idx)?;
1049 core::str::from_utf8(name).ok()
1050 }
1051 }
1052 }
1053 FontKind::CID(_) => None,
1054 }
1055 }
1056
1057 pub fn glyph_cid(&self, glyph_id: GlyphId) -> Option<u16> {
1061 match self.kind {
1062 FontKind::SID(_) => None,
1063 FontKind::CID(_) => self.charset.gid_to_sid(glyph_id).map(|id| id.0),
1064 }
1065 }
1066}
1067
1068impl core::fmt::Debug for Table<'_> {
1069 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1070 write!(f, "Table {{ ... }}")
1071 }
1072}