cff_parser/
cff.rs

1// Useful links:
2// http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
3// http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf
4// https://github.com/opentypejs/opentype.js/blob/master/src/tables/cff.js
5
6use 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
21// Limits according to the Adobe Technical Note #5176, chapter 4 DICT Data.
22const MAX_OPERANDS_LEN: usize = 48;
23
24// Limits according to the Adobe Technical Note #5177 Appendix B.
25const STACK_LIMIT: u8 = 10;
26const MAX_ARGUMENTS_STACK_LEN: usize = 48;
27
28const TWO_BYTE_OPERATOR_MARK: u8 = 12;
29
30/// Enumerates some operators defined in the Adobe Technical Note #5177.
31mod 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
63/// Enumerates some operators defined in the Adobe Technical Note #5176,
64/// Table 9 Top DICT Operator Entries
65mod 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
77/// Enumerates some operators defined in the Adobe Technical Note #5176,
78/// Table 23 Private DICT Operators
79mod 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
85/// Enumerates Charset IDs defined in the Adobe Technical Note #5176, Table 22
86mod charset_id {
87    pub const ISO_ADOBE: usize = 0;
88    pub const EXPERT: usize = 1;
89    pub const EXPERT_SUBSET: usize = 2;
90}
91
92/// Enumerates Charset IDs defined in the Adobe Technical Note #5176, Table 16
93mod 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    /// Can be zero.
108    default_width: f32,
109    /// Can be zero.
110    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/// An affine transformation matrix.
121#[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    // The Top DICT INDEX should have only one dictionary.
164    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// TODO: move to integration
216#[cfg(test)]
217mod tests {
218    use super::*;
219
220    #[test]
221    fn private_dict_size_overflow() {
222        let data = &[
223            0x00, 0x01, // count: 1
224            0x01, // offset size: 1
225            0x01, // index [0]: 1
226            0x0C, // index [1]: 14
227            0x1D, 0x7F, 0xFF, 0xFF, 0xFF, // length: i32::MAX
228            0x1D, 0x7F, 0xFF, 0xFF, 0xFF, // offset: i32::MAX
229            0x12, // operator: 18 (private)
230        ];
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, // count: 1
240            0x01, // offset size: 1
241            0x01, // index [0]: 1
242            0x03, // index [1]: 3
243            // Item 0
244            0x8A, // offset: -1
245            0x11, // operator: 17 (char_string)
246        ];
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, // count: 1
255            0x01, // offset size: 1
256            0x01, // index [0]: 1
257            0x02, // index [1]: 2
258            // Item 0
259            // <-- No number here.
260            0x11, // operator: 17 (char_string)
261        ];
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, // count: 1
270            0x01, // offset size: 1
271            0x01, // index [0]: 1
272            0x04, // index [1]: 4
273            // Item 0
274            0x8A, // length: -1
275            0x8A, // offset: -1
276            0x12, // operator: 18 (private)
277        ];
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
320/// In CID fonts, to get local subroutines we have to:
321///   1. Find Font DICT index via FDSelect by GID.
322///   2. Get Font DICT data from FDArray using this index.
323///   3. Get a Private DICT offset from a Font DICT.
324///   4. Get a local subroutine offset from Private DICT.
325///   5. Parse a local subroutine at offset.
326fn 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    // 'The local subroutines offset is relative to the beginning
339    // of the Private DICT data.'
340    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, // Required to parse local subroutine in CID fonts.
365    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, // Will be resolved on request.
378    };
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], // 192B
397        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    // Check that bbox was changed.
422    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                // Reserved.
442                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                // y dy {dya dyb}* hstem
449                // x dx {dxa dxb}* vstem
450                // y dy {dya dyb}* hstemhm
451                // x dx {dxa dxb}* vstemhm
452
453                // If the stack length is uneven, than the first value is a `width`.
454                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                // We are ignoring the hint operators.
464                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                // Parse and remember the local subroutine for the current glyph.
499                // Since it's a pretty complex task, we're doing it only when
500                // a local subroutine is actually requested by the glyphs charstring.
501                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                // flex
532                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                    // Process 'seac'.
544                    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                // We are ignoring the hint operators.
597                p.stack.clear();
598
599                // If the stack length is uneven, than the first value is a `width`.
600                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    // TODO: 'A charstring subroutine must end with either an endchar or a return operator.'
701
702    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            // ISO Adobe charset only defines string ids up to 228 (zcaron)
714            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]), // It's easier to parse it in-place.
729}
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                // 'A sentinel GID follows the last range element and serves
749                // to delimit the last range in the array.'
750                // So we can simply increase the number of ranges by one.
751                let number_of_ranges = number_of_ranges.checked_add(1)?;
752
753                // Range is: GlyphId + u8
754                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        // 'The local subroutines offset is relative to the beginning
804        // of the Private DICT data.'
805        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, // charset, FDArray and FDSelect must be set.
823    };
824
825    if charset_offset <= charset_id::EXPERT_SUBSET {
826        // 'There are no predefined charsets for CID fonts.'
827        // Adobe Technical Note #5176, chapter 18 CID-keyed Fonts
828        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/// A [Compact Font Format Table](
847/// https://docs.microsoft.com/en-us/typography/opentype/spec/cff).
848#[derive(Clone, Copy)]
849pub struct Table<'a> {
850    // The whole CFF table.
851    // Used to resolve a local subroutine in a CID font.
852    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    /// Parses a table from raw data.
867    pub fn parse(data: &'a [u8]) -> Option<Self> {
868        let mut s = Stream::new(data);
869
870        // Parse Header.
871        let major = s.read::<u8>()?;
872        s.skip::<u8>(); // minor
873        let header_size = s.read::<u8>()?;
874        s.skip::<u8>(); // Absolute offset
875
876        if major != 1 {
877            return None;
878        }
879
880        // Jump to Name INDEX. It's not necessarily right after the header.
881        if header_size > 4 {
882            s.advance(usize::from(header_size) - 4);
883        }
884
885        // Skip Name INDEX.
886        skip_index::<u16>(&mut s)?;
887
888        let top_dict = parse_top_dict(&mut s)?;
889
890        // Must be set, otherwise there are nothing to parse.
891        if top_dict.char_strings_offset == 0 {
892            return None;
893        }
894
895        // String INDEX.
896        let strings = parse_index::<u16>(&mut s)?;
897
898        // Parse Global Subroutines INDEX.
899        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        // 'The number of glyphs is the value of the count field in the CharStrings INDEX.'
907        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, // default
920        };
921
922        let matrix = top_dict.matrix;
923
924        // Only SID fonts are allowed to have an Encoding.
925        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(), // default
930        };
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    /// Returns a total number of glyphs in the font.
952    ///
953    /// Never zero.
954    #[inline]
955    pub fn number_of_glyphs(&self) -> u16 {
956        self.number_of_glyphs.get()
957    }
958
959    /// Returns a font transformation matrix.
960    #[inline]
961    pub fn matrix(&self) -> Matrix {
962        self.matrix
963    }
964
965    /// Outlines a glyph.
966    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    /// Resolves a Glyph ID for a code point.
979    ///
980    /// Similar to [`Face::glyph_index`](crate::Face::glyph_index) but 8bit
981    /// and uses CFF encoding and charset tables instead of TrueType `cmap`.
982    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                        // Try using the Standard encoding otherwise.
989                        // Custom Encodings does not guarantee to include all glyphs.
990                        Encoding::new_standard().code_to_gid(&self.charset, code_point)
991                    }
992                }
993            }
994            FontKind::CID(_) => None,
995        }
996    }
997
998    /// Returns a glyph width.
999    ///
1000    /// This value is different from outline bbox width and is stored separately.
1001    ///
1002    /// Technically similar to [`Face::glyph_hor_advance`](crate::Face::glyph_hor_advance).
1003    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    /// Returns a glyph ID by a name.
1019    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    /// Returns a glyph name.
1039    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    /// Returns the CID corresponding to a glyph ID.
1058    ///
1059    /// Returns `None` if this is not a CIDFont.
1060    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}