ttf_parser/tables/cff/
cff1.rs

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