makepad_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 && ctx.width.is_none() {
456                    i += 1;
457                    ctx.width = Some(p.stack.at(0));
458                }
459
460                p.parse_vertical_move_to(i)?;
461            }
462            operator::LINE_TO => {
463                p.parse_line_to()?;
464            }
465            operator::HORIZONTAL_LINE_TO => {
466                p.parse_horizontal_line_to()?;
467            }
468            operator::VERTICAL_LINE_TO => {
469                p.parse_vertical_line_to()?;
470            }
471            operator::CURVE_TO => {
472                p.parse_curve_to()?;
473            }
474            operator::CALL_LOCAL_SUBROUTINE => {
475                if p.stack.is_empty() {
476                    return Err(CFFError::InvalidArgumentsStackLength);
477                }
478
479                if depth == STACK_LIMIT {
480                    return Err(CFFError::NestingLimitReached);
481                }
482
483                // Parse and remember the local subroutine for the current glyph.
484                // Since it's a pretty complex task, we're doing it only when
485                // a local subroutine is actually requested by the glyphs charstring.
486                if ctx.local_subrs.is_none() {
487                    if let FontKind::CID(ref cid) = ctx.metadata.kind {
488                        ctx.local_subrs =
489                            parse_cid_local_subrs(ctx.metadata.table_data, ctx.glyph_id, cid);
490                    }
491                }
492
493                if let Some(local_subrs) = ctx.local_subrs {
494                    let subroutine_bias = calc_subroutine_bias(local_subrs.len());
495                    let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
496                    let char_string = local_subrs
497                        .get(index)
498                        .ok_or(CFFError::InvalidSubroutineIndex)?;
499                    _parse_char_string(ctx, char_string, depth + 1, p)?;
500                } else {
501                    return Err(CFFError::NoLocalSubroutines);
502                }
503
504                if ctx.has_endchar && !ctx.has_seac {
505                    if !s.at_end() {
506                        return Err(CFFError::DataAfterEndChar);
507                    }
508
509                    break;
510                }
511            }
512            operator::RETURN => {
513                break;
514            }
515            TWO_BYTE_OPERATOR_MARK => {
516                // flex
517                let op2 = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
518                match op2 {
519                    operator::HFLEX => p.parse_hflex()?,
520                    operator::FLEX => p.parse_flex()?,
521                    operator::HFLEX1 => p.parse_hflex1()?,
522                    operator::FLEX1 => p.parse_flex1()?,
523                    _ => return Err(CFFError::UnsupportedOperator),
524                }
525            }
526            operator::ENDCHAR => {
527                if p.stack.len() == 4 || (ctx.width.is_none() && p.stack.len() == 5) {
528                    // Process 'seac'.
529                    let accent_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop())
530                        .ok_or(CFFError::InvalidSeacCode)?;
531                    let base_char = seac_code_to_glyph_id(&ctx.metadata.charset, p.stack.pop())
532                        .ok_or(CFFError::InvalidSeacCode)?;
533                    let dy = p.stack.pop();
534                    let dx = p.stack.pop();
535
536                    if ctx.width.is_none() && !p.stack.is_empty() {
537                        ctx.width = Some(p.stack.pop())
538                    }
539
540                    ctx.has_seac = true;
541
542                    if depth == STACK_LIMIT {
543                        return Err(CFFError::NestingLimitReached);
544                    }
545
546                    let base_char_string = ctx
547                        .metadata
548                        .char_strings
549                        .get(u32::from(base_char.0))
550                        .ok_or(CFFError::InvalidSeacCode)?;
551                    _parse_char_string(ctx, base_char_string, depth + 1, p)?;
552                    p.x = dx;
553                    p.y = dy;
554
555                    let accent_char_string = ctx
556                        .metadata
557                        .char_strings
558                        .get(u32::from(accent_char.0))
559                        .ok_or(CFFError::InvalidSeacCode)?;
560                    _parse_char_string(ctx, accent_char_string, depth + 1, p)?;
561                } else if p.stack.len() == 1 && ctx.width.is_none() {
562                    ctx.width = Some(p.stack.pop());
563                }
564
565                if !p.is_first_move_to {
566                    p.is_first_move_to = true;
567                    p.builder.close();
568                }
569
570                if !s.at_end() {
571                    return Err(CFFError::DataAfterEndChar);
572                }
573
574                ctx.has_endchar = true;
575
576                break;
577            }
578            operator::HINT_MASK | operator::COUNTER_MASK => {
579                let mut len = p.stack.len();
580
581                // We are ignoring the hint operators.
582                p.stack.clear();
583
584                // If the stack length is uneven, than the first value is a `width`.
585                if len.is_odd() && ctx.width.is_none() {
586                    len -= 1;
587                    ctx.width = Some(p.stack.at(0));
588                }
589
590                ctx.stems_len += len as u32 >> 1;
591
592                s.advance(usize::num_from((ctx.stems_len + 7) >> 3));
593            }
594            operator::MOVE_TO => {
595                let mut i = 0;
596                if p.stack.len() == 3 && ctx.width.is_none() {
597                    i += 1;
598                    ctx.width = Some(p.stack.at(0));
599                }
600
601                p.parse_move_to(i)?;
602            }
603            operator::HORIZONTAL_MOVE_TO => {
604                let mut i = 0;
605                if p.stack.len() == 2 && ctx.width.is_none() {
606                    i += 1;
607                    ctx.width = Some(p.stack.at(0));
608                }
609
610                p.parse_horizontal_move_to(i)?;
611            }
612            operator::CURVE_LINE => {
613                p.parse_curve_line()?;
614            }
615            operator::LINE_CURVE => {
616                p.parse_line_curve()?;
617            }
618            operator::VV_CURVE_TO => {
619                p.parse_vv_curve_to()?;
620            }
621            operator::HH_CURVE_TO => {
622                p.parse_hh_curve_to()?;
623            }
624            operator::SHORT_INT => {
625                let n = s.read::<i16>().ok_or(CFFError::ReadOutOfBounds)?;
626                p.stack.push(f32::from(n))?;
627            }
628            operator::CALL_GLOBAL_SUBROUTINE => {
629                if p.stack.is_empty() {
630                    return Err(CFFError::InvalidArgumentsStackLength);
631                }
632
633                if depth == STACK_LIMIT {
634                    return Err(CFFError::NestingLimitReached);
635                }
636
637                let subroutine_bias = calc_subroutine_bias(ctx.metadata.global_subrs.len());
638                let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
639                let char_string = ctx
640                    .metadata
641                    .global_subrs
642                    .get(index)
643                    .ok_or(CFFError::InvalidSubroutineIndex)?;
644                _parse_char_string(ctx, char_string, depth + 1, p)?;
645
646                if ctx.has_endchar && !ctx.has_seac {
647                    if !s.at_end() {
648                        return Err(CFFError::DataAfterEndChar);
649                    }
650
651                    break;
652                }
653            }
654            operator::VH_CURVE_TO => {
655                p.parse_vh_curve_to()?;
656            }
657            operator::HV_CURVE_TO => {
658                p.parse_hv_curve_to()?;
659            }
660            32..=246 => {
661                p.parse_int1(op)?;
662            }
663            247..=250 => {
664                p.parse_int2(op, &mut s)?;
665            }
666            251..=254 => {
667                p.parse_int3(op, &mut s)?;
668            }
669            operator::FIXED_16_16 => {
670                p.parse_fixed(&mut s)?;
671            }
672        }
673
674        if p.width_only && ctx.width.is_some() {
675            break;
676        }
677    }
678
679    // TODO: 'A charstring subroutine must end with either an endchar or a return operator.'
680
681    Ok(())
682}
683
684fn seac_code_to_glyph_id(charset: &Charset, n: f32) -> Option<GlyphId> {
685    let code = u8::try_num_from(n)?;
686
687    let sid = STANDARD_ENCODING[usize::from(code)];
688    let sid = StringId(u16::from(sid));
689
690    match charset {
691        Charset::ISOAdobe => {
692            // ISO Adobe charset only defines string ids up to 228 (zcaron)
693            if code <= 228 {
694                Some(GlyphId(sid.0))
695            } else {
696                None
697            }
698        }
699        Charset::Expert | Charset::ExpertSubset => None,
700        _ => charset.sid_to_gid(sid),
701    }
702}
703
704#[derive(Clone, Copy, Debug)]
705enum FDSelect<'a> {
706    Format0(LazyArray16<'a, u8>),
707    Format3(&'a [u8]), // It's easier to parse it in-place.
708}
709
710impl Default for FDSelect<'_> {
711    fn default() -> Self {
712        FDSelect::Format0(LazyArray16::default())
713    }
714}
715
716impl FDSelect<'_> {
717    fn font_dict_index(&self, glyph_id: GlyphId) -> Option<u8> {
718        match self {
719            FDSelect::Format0(ref array) => array.get(glyph_id.0),
720            FDSelect::Format3(data) => {
721                let mut s = Stream::new(data);
722                let number_of_ranges = s.read::<u16>()?;
723                if number_of_ranges == 0 {
724                    return None;
725                }
726
727                // 'A sentinel GID follows the last range element and serves
728                // to delimit the last range in the array.'
729                // So we can simply increase the number of ranges by one.
730                let number_of_ranges = number_of_ranges.checked_add(1)?;
731
732                // Range is: GlyphId + u8
733                let mut prev_first_glyph = s.read::<GlyphId>()?;
734                let mut prev_index = s.read::<u8>()?;
735                for _ in 1..number_of_ranges {
736                    let curr_first_glyph = s.read::<GlyphId>()?;
737                    if (prev_first_glyph..curr_first_glyph).contains(&glyph_id) {
738                        return Some(prev_index);
739                    } else {
740                        prev_index = s.read::<u8>()?;
741                    }
742
743                    prev_first_glyph = curr_first_glyph;
744                }
745
746                None
747            }
748        }
749    }
750}
751
752fn parse_fd_select<'a>(number_of_glyphs: u16, s: &mut Stream<'a>) -> Option<FDSelect<'a>> {
753    let format = s.read::<u8>()?;
754    match format {
755        0 => Some(FDSelect::Format0(s.read_array16::<u8>(number_of_glyphs)?)),
756        3 => Some(FDSelect::Format3(s.tail()?)),
757        _ => None,
758    }
759}
760
761fn parse_sid_metadata<'a>(
762    data: &'a [u8],
763    top_dict: TopDict,
764    encoding: Encoding<'a>,
765) -> Option<FontKind<'a>> {
766    let mut metadata = SIDMetadata::default();
767    metadata.encoding = encoding;
768
769    let private_dict = if let Some(range) = top_dict.private_dict_range.clone() {
770        parse_private_dict(data.get(range)?)
771    } else {
772        return Some(FontKind::SID(metadata));
773    };
774
775    metadata.default_width = private_dict.default_width.unwrap_or(0.0);
776    metadata.nominal_width = private_dict.nominal_width.unwrap_or(0.0);
777
778    if let (Some(private_dict_range), Some(subroutines_offset)) = (
779        top_dict.private_dict_range,
780        private_dict.local_subroutines_offset,
781    ) {
782        // 'The local subroutines offset is relative to the beginning
783        // of the Private DICT data.'
784        if let Some(start) = private_dict_range.start.checked_add(subroutines_offset) {
785            let data = data.get(start..data.len())?;
786            let mut s = Stream::new(data);
787            metadata.local_subrs = parse_index::<u16>(&mut s)?;
788        }
789    }
790
791    Some(FontKind::SID(metadata))
792}
793
794fn parse_cid_metadata(data: &[u8], top_dict: TopDict, number_of_glyphs: u16) -> Option<FontKind> {
795    let (charset_offset, fd_array_offset, fd_select_offset) = match (
796        top_dict.charset_offset,
797        top_dict.fd_array_offset,
798        top_dict.fd_select_offset,
799    ) {
800        (Some(a), Some(b), Some(c)) => (a, b, c),
801        _ => return None, // charset, FDArray and FDSelect must be set.
802    };
803
804    if charset_offset <= charset_id::EXPERT_SUBSET {
805        // 'There are no predefined charsets for CID fonts.'
806        // Adobe Technical Note #5176, chapter 18 CID-keyed Fonts
807        return None;
808    }
809
810    let mut metadata = CIDMetadata::default();
811
812    metadata.fd_array = {
813        let mut s = Stream::new_at(data, fd_array_offset)?;
814        parse_index::<u16>(&mut s)?
815    };
816
817    metadata.fd_select = {
818        let mut s = Stream::new_at(data, fd_select_offset)?;
819        parse_fd_select(number_of_glyphs, &mut s)?
820    };
821
822    Some(FontKind::CID(metadata))
823}
824
825/// A [Compact Font Format Table](
826/// https://docs.microsoft.com/en-us/typography/opentype/spec/cff).
827#[derive(Clone, Copy)]
828pub struct Table<'a> {
829    // The whole CFF table.
830    // Used to resolve a local subroutine in a CID font.
831    table_data: &'a [u8],
832
833    #[allow(dead_code)]
834    strings: Index<'a>,
835    global_subrs: Index<'a>,
836    charset: Charset<'a>,
837    number_of_glyphs: NonZeroU16,
838    matrix: Matrix,
839    char_strings: Index<'a>,
840    kind: FontKind<'a>,
841}
842
843impl<'a> Table<'a> {
844    /// Parses a table from raw data.
845    pub fn parse(data: &'a [u8]) -> Option<Self> {
846        let mut s = Stream::new(data);
847
848        // Parse Header.
849        let major = s.read::<u8>()?;
850        s.skip::<u8>(); // minor
851        let header_size = s.read::<u8>()?;
852        s.skip::<u8>(); // Absolute offset
853
854        if major != 1 {
855            return None;
856        }
857
858        // Jump to Name INDEX. It's not necessarily right after the header.
859        if header_size > 4 {
860            s.advance(usize::from(header_size) - 4);
861        }
862
863        // Skip Name INDEX.
864        skip_index::<u16>(&mut s)?;
865
866        let top_dict = parse_top_dict(&mut s)?;
867
868        // Must be set, otherwise there are nothing to parse.
869        if top_dict.char_strings_offset == 0 {
870            return None;
871        }
872
873        // String INDEX.
874        let strings = parse_index::<u16>(&mut s)?;
875
876        // Parse Global Subroutines INDEX.
877        let global_subrs = parse_index::<u16>(&mut s)?;
878
879        let char_strings = {
880            let mut s = Stream::new_at(data, top_dict.char_strings_offset)?;
881            parse_index::<u16>(&mut s)?
882        };
883
884        // 'The number of glyphs is the value of the count field in the CharStrings INDEX.'
885        let number_of_glyphs = u16::try_from(char_strings.len())
886            .ok()
887            .and_then(NonZeroU16::new)?;
888
889        let charset = match top_dict.charset_offset {
890            Some(charset_id::ISO_ADOBE) => Charset::ISOAdobe,
891            Some(charset_id::EXPERT) => Charset::Expert,
892            Some(charset_id::EXPERT_SUBSET) => Charset::ExpertSubset,
893            Some(offset) => {
894                let mut s = Stream::new_at(data, offset)?;
895                parse_charset(number_of_glyphs.get(), &mut s)?
896            }
897            None => Charset::ISOAdobe, // default
898        };
899
900        let matrix = top_dict.matrix;
901
902        let kind = if top_dict.has_ros {
903            parse_cid_metadata(data, top_dict, number_of_glyphs.get())?
904        } else {
905            // Only SID fonts are allowed to have an Encoding.
906            let encoding = match top_dict.encoding_offset {
907                Some(encoding_id::STANDARD) => Encoding::new_standard(),
908                Some(encoding_id::EXPERT) => Encoding::new_expert(),
909                Some(offset) => parse_encoding(&mut Stream::new_at(data, offset)?)?,
910                None => Encoding::new_standard(), // default
911            };
912
913            parse_sid_metadata(data, top_dict, encoding)?
914        };
915
916        Some(Self {
917            table_data: data,
918            strings,
919            global_subrs,
920            charset,
921            number_of_glyphs,
922            matrix,
923            char_strings,
924            kind,
925        })
926    }
927
928    /// Returns a total number of glyphs in the font.
929    ///
930    /// Never zero.
931    #[inline]
932    pub fn number_of_glyphs(&self) -> u16 {
933        self.number_of_glyphs.get()
934    }
935
936    /// Returns a font transformation matrix.
937    #[inline]
938    pub fn matrix(&self) -> Matrix {
939        self.matrix
940    }
941
942    /// Outlines a glyph.
943    pub fn outline(
944        &self,
945        glyph_id: GlyphId,
946        builder: &mut dyn OutlineBuilder,
947    ) -> Result<Rect, CFFError> {
948        let data = self
949            .char_strings
950            .get(u32::from(glyph_id.0))
951            .ok_or(CFFError::NoGlyph)?;
952        parse_char_string(data, self, glyph_id, false, builder).map(|v| v.0)
953    }
954
955    /// Resolves a Glyph ID for a code point.
956    ///
957    /// Similar to [`Face::glyph_index`](crate::Face::glyph_index) but 8bit
958    /// and uses CFF encoding and charset tables instead of TrueType `cmap`.
959    pub fn glyph_index(&self, code_point: u8) -> Option<GlyphId> {
960        match self.kind {
961            FontKind::SID(ref sid_meta) => {
962                match sid_meta.encoding.code_to_gid(&self.charset, code_point) {
963                    Some(id) => Some(id),
964                    None => {
965                        // Try using the Standard encoding otherwise.
966                        // Custom Encodings does not guarantee to include all glyphs.
967                        Encoding::new_standard().code_to_gid(&self.charset, code_point)
968                    }
969                }
970            }
971            FontKind::CID(_) => None,
972        }
973    }
974
975    /// Returns a glyph width.
976    ///
977    /// This value is different from outline bbox width and is stored separately.
978    ///
979    /// Technically similar to [`Face::glyph_hor_advance`](crate::Face::glyph_hor_advance).
980    pub fn glyph_width(&self, glyph_id: GlyphId) -> Option<u16> {
981        match self.kind {
982            FontKind::SID(ref sid) => {
983                let data = self.char_strings.get(u32::from(glyph_id.0))?;
984                let (_, width) =
985                    parse_char_string(data, self, glyph_id, true, &mut DummyOutline).ok()?;
986                let width = width
987                    .map(|w| sid.nominal_width + w)
988                    .unwrap_or(sid.default_width);
989                u16::try_from(width as i32).ok()
990            }
991            FontKind::CID(_) => None,
992        }
993    }
994
995    /// Returns a glyph ID by a name.
996    #[cfg(feature = "glyph-names")]
997    pub fn glyph_index_by_name(&self, name: &str) -> Option<GlyphId> {
998        match self.kind {
999            FontKind::SID(_) => {
1000                let sid = if let Some(index) = STANDARD_NAMES.iter().position(|n| *n == name) {
1001                    StringId(index as u16)
1002                } else {
1003                    let index = self
1004                        .strings
1005                        .into_iter()
1006                        .position(|n| n == name.as_bytes())?;
1007                    StringId((STANDARD_NAMES.len() + index) as u16)
1008                };
1009
1010                self.charset.sid_to_gid(sid)
1011            }
1012            FontKind::CID(_) => None,
1013        }
1014    }
1015
1016    /// Returns a glyph name.
1017    #[cfg(feature = "glyph-names")]
1018    pub fn glyph_name(&self, glyph_id: GlyphId) -> Option<&'a str> {
1019        match self.kind {
1020            FontKind::SID(_) => {
1021                let sid = self.charset.gid_to_sid(glyph_id)?;
1022                let sid = usize::from(sid.0);
1023                match STANDARD_NAMES.get(sid) {
1024                    Some(name) => Some(name),
1025                    None => {
1026                        let idx = u32::try_from(sid - STANDARD_NAMES.len()).ok()?;
1027                        let name = self.strings.get(idx)?;
1028                        core::str::from_utf8(name).ok()
1029                    }
1030                }
1031            }
1032            FontKind::CID(_) => None,
1033        }
1034    }
1035
1036    /// Returns the CID corresponding to a glyph ID.
1037    ///
1038    /// Returns `None` if this is not a CIDFont.
1039    #[cfg(feature = "glyph-names")]
1040    pub fn glyph_cid(&self, glyph_id: GlyphId) -> Option<u16> {
1041        match self.kind {
1042            FontKind::SID(_) => None,
1043            FontKind::CID(_) => self.charset.gid_to_sid(glyph_id).map(|id| id.0),
1044        }
1045    }
1046}
1047
1048impl core::fmt::Debug for Table<'_> {
1049    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1050        write!(f, "Table {{ ... }}")
1051    }
1052}