Skip to main content

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