1use core::convert::TryFrom;
5use core::ops::Range;
6
7use crate::{GlyphId, OutlineBuilder, Rect, BBox, NormalizedCoordinate};
8use crate::parser::{Stream, NumFrom, TryNumFrom};
9use crate::var_store::*;
10use super::{Builder, CFFError, calc_subroutine_bias, conv_subroutine_index};
11use super::argstack::ArgumentsStack;
12use super::charstring::CharStringParser;
13use super::dict::DictionaryParser;
14use super::index::{Index, parse_index};
15
16const MAX_OPERANDS_LEN: usize = 513;
19
20const STACK_LIMIT: u8 = 10;
22const MAX_ARGUMENTS_STACK_LEN: usize = 513;
23
24const TWO_BYTE_OPERATOR_MARK: u8 = 12;
25
26mod operator {
28 pub const HORIZONTAL_STEM: u8 = 1;
29 pub const VERTICAL_STEM: u8 = 3;
30 pub const VERTICAL_MOVE_TO: u8 = 4;
31 pub const LINE_TO: u8 = 5;
32 pub const HORIZONTAL_LINE_TO: u8 = 6;
33 pub const VERTICAL_LINE_TO: u8 = 7;
34 pub const CURVE_TO: u8 = 8;
35 pub const CALL_LOCAL_SUBROUTINE: u8 = 10;
36 pub const VS_INDEX: u8 = 15;
37 pub const BLEND: u8 = 16;
38 pub const HORIZONTAL_STEM_HINT_MASK: u8 = 18;
39 pub const HINT_MASK: u8 = 19;
40 pub const COUNTER_MASK: u8 = 20;
41 pub const MOVE_TO: u8 = 21;
42 pub const HORIZONTAL_MOVE_TO: u8 = 22;
43 pub const VERTICAL_STEM_HINT_MASK: u8 = 23;
44 pub const CURVE_LINE: u8 = 24;
45 pub const LINE_CURVE: u8 = 25;
46 pub const VV_CURVE_TO: u8 = 26;
47 pub const HH_CURVE_TO: u8 = 27;
48 pub const SHORT_INT: u8 = 28;
49 pub const CALL_GLOBAL_SUBROUTINE: u8 = 29;
50 pub const VH_CURVE_TO: u8 = 30;
51 pub const HV_CURVE_TO: u8 = 31;
52 pub const HFLEX: u8 = 34;
53 pub const FLEX: u8 = 35;
54 pub const HFLEX1: u8 = 36;
55 pub const FLEX1: u8 = 37;
56 pub const FIXED_16_16: u8 = 255;
57}
58
59mod top_dict_operator {
61 pub const CHAR_STRINGS_OFFSET: u16 = 17;
62 pub const VARIATION_STORE_OFFSET: u16 = 24;
63 pub const FONT_DICT_INDEX_OFFSET: u16 = 1236;
64}
65
66mod font_dict_operator {
68 pub const PRIVATE_DICT_SIZE_AND_OFFSET: u16 = 18;
69}
70
71mod private_dict_operator {
73 pub const LOCAL_SUBROUTINES_OFFSET: u16 = 19;
74}
75
76
77#[derive(Clone, Copy, Default)]
78pub struct Metadata<'a> {
79 global_subrs: Index<'a>,
80 local_subrs: Index<'a>,
81 char_strings: Index<'a>,
82 item_variation_store: ItemVariationStore<'a>,
83}
84
85pub(crate) fn parse_metadata(data: &[u8]) -> Option<Metadata> {
86 let mut s = Stream::new(data);
87
88 let major: u8 = s.read()?;
90 s.skip::<u8>(); let header_size: u8 = s.read()?;
92 let top_dict_length: u16 = s.read()?;
93
94 if major != 2 {
95 return None;
96 }
97
98 if header_size > 5 {
100 s.advance(usize::from(header_size) - 5);
101 }
102
103 let top_dict_data = s.read_bytes(usize::from(top_dict_length))?;
104 let top_dict = parse_top_dict(top_dict_data)?;
105
106 let mut metadata = Metadata::default();
107
108 metadata.global_subrs = parse_index::<u32>(&mut s)?;
110
111 metadata.char_strings = {
112 let mut s = Stream::new_at(data, top_dict.char_strings_offset)?;
113 parse_index::<u32>(&mut s)?
114 };
115
116 if let Some(offset) = top_dict.variation_store_offset {
117 let mut s = Stream::new_at(data, offset)?;
118 s.skip::<u16>(); metadata.item_variation_store = ItemVariationStore::parse(s)?;
120 }
121
122 if let Some(offset) = top_dict.font_dict_index_offset {
124 let mut s = Stream::new_at(data, offset)?;
125 'outer: for font_dict_data in parse_index::<u32>(&mut s)? {
126 if let Some(private_dict_range) = parse_font_dict(font_dict_data) {
127 let private_dict_data = data.get(private_dict_range.clone())?;
129 if let Some(subroutines_offset) = parse_private_dict(private_dict_data) {
130 if let Some(start) = private_dict_range.start.checked_add(subroutines_offset) {
133 let data = data.get(start..data.len())?;
134 let mut s = Stream::new(data);
135 metadata.local_subrs = parse_index::<u32>(&mut s)?;
136 break 'outer;
137 }
138 }
139 }
140 }
141 }
142
143 Some(metadata)
144}
145
146
147pub(crate) fn outline(
148 metadata: &Metadata,
149 coordinates: &[NormalizedCoordinate],
150 glyph_id: GlyphId,
151 builder: &mut dyn OutlineBuilder,
152) -> Option<Rect> {
153 let data = metadata.char_strings.get(u32::from(glyph_id.0))?;
154 parse_char_string(data, metadata, coordinates, builder).ok()
155}
156
157#[derive(Clone, Copy, Default)]
158struct TopDictData {
159 char_strings_offset: usize,
160 font_dict_index_offset: Option<usize>,
161 variation_store_offset: Option<usize>,
162}
163
164fn parse_top_dict(data: &[u8]) -> Option<TopDictData> {
165 let mut dict_data = TopDictData::default();
166
167 let mut operands_buffer = [0; MAX_OPERANDS_LEN];
168 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
169 while let Some(operator) = dict_parser.parse_next() {
170 if operator.get() == top_dict_operator::CHAR_STRINGS_OFFSET {
171 dict_data.char_strings_offset = dict_parser.parse_offset()?;
172 } else if operator.get() == top_dict_operator::FONT_DICT_INDEX_OFFSET {
173 dict_data.font_dict_index_offset = dict_parser.parse_offset();
174 } else if operator.get() == top_dict_operator::VARIATION_STORE_OFFSET {
175 dict_data.variation_store_offset = dict_parser.parse_offset();
176 }
177 }
178
179 if dict_data.char_strings_offset == 0 {
181 return None;
182 }
183
184 Some(dict_data)
185}
186
187fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
188 let mut private_dict_range = None;
189
190 let mut operands_buffer = [0; MAX_OPERANDS_LEN];
191 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
192 while let Some(operator) = dict_parser.parse_next() {
193 if operator.get() == font_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET {
194 dict_parser.parse_operands()?;
195 let operands = dict_parser.operands();
196
197 if operands.len() == 2 {
198 let len = usize::try_from(operands[0]).ok()?;
199 let start = usize::try_from(operands[1]).ok()?;
200 let end = start.checked_add(len)?;
201 private_dict_range = Some(start..end);
202 }
203
204 break;
205 }
206 }
207
208 private_dict_range
209}
210
211fn parse_private_dict(data: &[u8]) -> Option<usize> {
212 let mut subroutines_offset = None;
213 let mut operands_buffer = [0; MAX_OPERANDS_LEN];
214 let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
215 while let Some(operator) = dict_parser.parse_next() {
216 if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET {
217 dict_parser.parse_operands()?;
218 let operands = dict_parser.operands();
219
220 if operands.len() == 1 {
221 subroutines_offset = usize::try_from(operands[0]).ok();
222 }
223
224 break;
225 }
226 }
227
228 subroutines_offset
229}
230
231const SCALARS_MAX: u8 = 64;
234
235#[derive(Clone, Copy)]
236pub struct Scalars {
237 d: [f32; SCALARS_MAX as usize], len: u8,
239}
240
241impl Default for Scalars {
242 fn default() -> Self {
243 Scalars {
244 d: [0.0; SCALARS_MAX as usize],
245 len: 0,
246 }
247 }
248}
249
250impl Scalars {
251 pub fn len(&self) -> u8 {
252 self.len
253 }
254
255 pub fn clear(&mut self) {
256 self.len = 0;
257 }
258
259 pub fn at(&self, i: u8) -> f32 {
260 if i < self.len {
261 self.d[usize::from(i)]
262 } else {
263 0.0
264 }
265 }
266
267 pub fn push(&mut self, n: f32) -> Option<()> {
268 if self.len < SCALARS_MAX {
269 self.d[usize::from(self.len)] = n;
270 self.len += 1;
271 Some(())
272 } else {
273 None
274 }
275 }
276}
277
278struct CharStringParserContext<'a> {
279 metadata: &'a Metadata<'a>,
280 coordinates: &'a [NormalizedCoordinate],
281 scalars: Scalars,
282 had_vsindex: bool,
283 had_blend: bool,
284 stems_len: u32,
285}
286
287impl CharStringParserContext<'_> {
288 fn update_scalars(&mut self, index: u16) -> Result<(), CFFError> {
289 self.scalars.clear();
290
291 let indices = self.metadata.item_variation_store.region_indices(index)
292 .ok_or(CFFError::InvalidItemVariationDataIndex)?;
293 for index in indices {
294 let scalar = self.metadata.item_variation_store.regions
295 .evaluate_region(index, self.coordinates);
296 self.scalars.push(scalar)
297 .ok_or(CFFError::BlendRegionsLimitReached)?;
298 }
299
300 Ok(())
301 }
302}
303
304fn parse_char_string(
305 data: &[u8],
306 metadata: &Metadata,
307 coordinates: &[NormalizedCoordinate],
308 builder: &mut dyn OutlineBuilder,
309) -> Result<Rect, CFFError> {
310 let mut ctx = CharStringParserContext {
311 metadata,
312 coordinates,
313 scalars: Scalars::default(),
314 had_vsindex: false,
315 had_blend: false,
316 stems_len: 0,
317 };
318
319 ctx.update_scalars(0)?;
321
322 let mut inner_builder = Builder {
323 builder,
324 bbox: BBox::new(),
325 };
326
327 let stack = ArgumentsStack {
328 data: &mut [0.0; MAX_ARGUMENTS_STACK_LEN], len: 0,
330 max_len: MAX_ARGUMENTS_STACK_LEN,
331 };
332 let mut parser = CharStringParser {
333 stack,
334 builder: &mut inner_builder,
335 x: 0.0,
336 y: 0.0,
337 has_move_to: false,
338 is_first_move_to: true,
339 };
340 _parse_char_string(&mut ctx, data, 0, &mut parser)?;
341 let bbox = parser.builder.bbox;
344
345 if bbox.is_default() {
347 return Err(CFFError::ZeroBBox);
348 }
349
350 bbox.to_rect().ok_or(CFFError::BboxOverflow)
351}
352
353fn _parse_char_string(
354 ctx: &mut CharStringParserContext,
355 char_string: &[u8],
356 depth: u8,
357 p: &mut CharStringParser,
358) -> Result<(), CFFError> {
359 let mut s = Stream::new(char_string);
360 while !s.at_end() {
361 let op: u8 = s.read().ok_or(CFFError::ReadOutOfBounds)?;
362 match op {
363 0 | 2 | 9 | 11 | 13 | 14 | 17 => {
364 return Err(CFFError::InvalidOperator);
366 }
367 operator::HORIZONTAL_STEM |
368 operator::VERTICAL_STEM |
369 operator::HORIZONTAL_STEM_HINT_MASK |
370 operator::VERTICAL_STEM_HINT_MASK => {
371 ctx.stems_len += p.stack.len() as u32 >> 1;
377
378 p.stack.clear();
380 }
381 operator::VERTICAL_MOVE_TO => {
382 p.parse_vertical_move_to(0)?;
383 }
384 operator::LINE_TO => {
385 p.parse_line_to()?;
386 }
387 operator::HORIZONTAL_LINE_TO => {
388 p.parse_horizontal_line_to()?;
389 }
390 operator::VERTICAL_LINE_TO => {
391 p.parse_vertical_line_to()?;
392 }
393 operator::CURVE_TO => {
394 p.parse_curve_to()?;
395 }
396 operator::CALL_LOCAL_SUBROUTINE => {
397 if p.stack.is_empty() {
398 return Err(CFFError::InvalidArgumentsStackLength);
399 }
400
401 if depth == STACK_LIMIT {
402 return Err(CFFError::NestingLimitReached);
403 }
404
405 let subroutine_bias = calc_subroutine_bias(ctx.metadata.local_subrs.len());
406 let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
407 let char_string = ctx.metadata.local_subrs.get(index)
408 .ok_or(CFFError::InvalidSubroutineIndex)?;
409 _parse_char_string(ctx, char_string, depth + 1, p)?;
410 }
411 TWO_BYTE_OPERATOR_MARK => {
412 let op2: u8 = s.read().ok_or(CFFError::ReadOutOfBounds)?;
414 match op2 {
415 operator::HFLEX => p.parse_hflex()?,
416 operator::FLEX => p.parse_flex()?,
417 operator::HFLEX1 => p.parse_hflex1()?,
418 operator::FLEX1 => p.parse_flex1()?,
419 _ => return Err(CFFError::UnsupportedOperator),
420 }
421 }
422 operator::VS_INDEX => {
423 if ctx.had_blend || ctx.had_vsindex {
427 return Err(CFFError::InvalidOperator);
429 }
430
431 if p.stack.len() != 1 {
432 return Err(CFFError::InvalidArgumentsStackLength);
433 }
434
435 let index = u16::try_num_from(p.stack.pop())
436 .ok_or(CFFError::InvalidItemVariationDataIndex)?;
437 ctx.update_scalars(index)?;
438
439 ctx.had_vsindex = true;
440
441 p.stack.clear();
442 }
443 operator::BLEND => {
444 ctx.had_blend = true;
449
450 let n = u16::try_num_from(p.stack.pop())
451 .ok_or(CFFError::InvalidNumberOfBlendOperands)?;
452 let k = ctx.scalars.len();
453
454 let len = usize::from(n) * (usize::from(k) + 1);
455 if p.stack.len() < len {
456 return Err(CFFError::InvalidArgumentsStackLength);
457 }
458
459 let start = p.stack.len() - len;
460 for i in (0..n).rev() {
461 for j in 0..k {
462 let delta = p.stack.pop();
463 p.stack.data[start + usize::from(i)] += delta * ctx.scalars.at(k - j - 1);
464 }
465 }
466 }
467 operator::HINT_MASK | operator::COUNTER_MASK => {
468 ctx.stems_len += p.stack.len() as u32 >> 1;
469 s.advance(usize::num_from((ctx.stems_len + 7) >> 3));
470
471 p.stack.clear();
473 }
474 operator::MOVE_TO => {
475 p.parse_move_to(0)?;
476 }
477 operator::HORIZONTAL_MOVE_TO => {
478 p.parse_horizontal_move_to(0)?;
479 }
480 operator::CURVE_LINE => {
481 p.parse_curve_line()?;
482 }
483 operator::LINE_CURVE => {
484 p.parse_line_curve()?;
485 }
486 operator::VV_CURVE_TO => {
487 p.parse_vv_curve_to()?;
488 }
489 operator::HH_CURVE_TO => {
490 p.parse_hh_curve_to()?;
491 }
492 operator::SHORT_INT => {
493 let n = s.read::<i16>().ok_or(CFFError::ReadOutOfBounds)?;
494 p.stack.push(f32::from(n))?;
495 }
496 operator::CALL_GLOBAL_SUBROUTINE => {
497 if p.stack.is_empty() {
498 return Err(CFFError::InvalidArgumentsStackLength);
499 }
500
501 if depth == STACK_LIMIT {
502 return Err(CFFError::NestingLimitReached);
503 }
504
505 let subroutine_bias = calc_subroutine_bias(ctx.metadata.global_subrs.len());
506 let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
507 let char_string = ctx.metadata.global_subrs.get(index)
508 .ok_or(CFFError::InvalidSubroutineIndex)?;
509 _parse_char_string(ctx, char_string, depth + 1, p)?;
510 }
511 operator::VH_CURVE_TO => {
512 p.parse_vh_curve_to()?;
513 }
514 operator::HV_CURVE_TO => {
515 p.parse_hv_curve_to()?;
516 }
517 32..=246 => {
518 p.parse_int1(op)?;
519 }
520 247..=250 => {
521 p.parse_int2(op, &mut s)?;
522 }
523 251..=254 => {
524 p.parse_int3(op, &mut s)?;
525 }
526 operator::FIXED_16_16 => {
527 p.parse_fixed(&mut s)?;
528 }
529 }
530 }
531
532 Ok(())
533}