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::{BBox, DummyOutline, GlyphId, OutlineBuilder, Rect};
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 = PrivateDict::default();
292 let mut operands_buffer: [f64; 48] = [0.0; MAX_OPERANDS_LEN];
293 let mut dict_parser: DictionaryParser<'_> = DictionaryParser::new(data, &mut operands_buffer);
294 while let Some(operator: 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: f64| n as f32);
299 } else if operator.get() == private_dict_operator::NOMINAL_WIDTH {
300 dict.nominal_width = dict_parser.parse_number().map(|n: f64| n as f32);
301 }
302 }
303
304 dict
305}
306
307fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
308 let mut operands_buffer: [f64; 48] = [0.0; MAX_OPERANDS_LEN];
309 let mut dict_parser: DictionaryParser<'_> = DictionaryParser::new(data, &mut operands_buffer);
310 while let Some(operator: 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: u8 = cid.fd_select.font_dict_index(glyph_id)?;
331 let font_dict_data: &[u8] = cid.fd_array.get(index:u32::from(font_dict_index))?;
332 let private_dict_range: Range = parse_font_dict(font_dict_data)?;
333 let private_dict_data: &[u8] = data.get(index:private_dict_range.clone())?;
334 let private_dict: PrivateDict = parse_private_dict(private_dict_data);
335 let subroutines_offset: usize = 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: usize = private_dict_range.start.checked_add(subroutines_offset)?;
340 let subrs_data: &[u8] = data.get(index:start..)?;
341 let mut s: Stream<'_> = 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: BBox::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 = u8::try_num_from(n)?;
686
687 let sid: u8 = STANDARD_ENCODING[usize::from(code)];
688 let sid: StringId = 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: u8 = s.read::<u8>()?;
754 match format {
755 0 => Some(FDSelect::Format0(s.read_array16::<u8>(count: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}
1053