1use crate::{
4 model::pen::OutlinePen,
5 ps::{
6 cff::{blend::BlendState, charset::Charset, index::Index, stack::Stack},
7 error::Error,
8 num,
9 string::Sid,
10 transform::{FontMatrix, Transform},
11 },
12 tables::cff::Cff,
13 types::{Fixed, Point},
14 Cursor, FontData, FontRead,
15};
16
17pub const NESTING_DEPTH_LIMIT: u32 = 10;
22
23const MAX_OPERATIONS: u32 = 1_000_000;
33
34#[derive(Copy, Clone, PartialEq, Eq, Debug)]
36pub enum CharstringKind {
37 Type1,
41 Type2,
45}
46
47pub trait CharstringContext {
49 fn kind(&self) -> CharstringKind;
51
52 fn seac_components(&self, base_code: i32, accent_code: i32) -> Result<[&[u8]; 2], Error>;
55
56 fn global_subr(&self, index: i32) -> Result<&[u8], Error>;
59
60 fn subr(&self, index: i32) -> Result<&[u8], Error>;
63
64 fn weight_vector(&self) -> &[Fixed] {
66 &[]
67 }
68}
69
70impl<'a> CharstringContext for (&'a [u8], &'a Index<'a>, &'a Index<'a>, &'a Index<'a>) {
75 fn kind(&self) -> CharstringKind {
76 CharstringKind::Type2
77 }
78
79 fn seac_components(&self, base_code: i32, accent_code: i32) -> Result<[&[u8]; 2], Error> {
80 let cff = Cff::read(FontData::new(self.0))?;
81 let charset = cff
82 .charset(0)?
83 .or_else(|| Charset::new(FontData::default(), 0, self.1.count()).ok())
84 .ok_or(Error::MissingCharset)?;
85 let seac_to_gid = |code: i32| {
86 let code: u8 = code.try_into().ok()?;
87 let sid = *super::encoding::STANDARD_ENCODING.get(code as usize)?;
88 charset.glyph_id(Sid::new(sid as u16)).ok()
89 };
90 let accent_gid = seac_to_gid(accent_code).ok_or(Error::InvalidSeacCode(accent_code))?;
91 let base_gid = seac_to_gid(base_code).ok_or(Error::InvalidSeacCode(base_code))?;
92 let accent_charstring = self.1.get(accent_gid.to_u32() as usize)?;
93 let base_charstring = self.1.get(base_gid.to_u32() as usize)?;
94 Ok([base_charstring, accent_charstring])
95 }
96
97 fn global_subr(&self, index: i32) -> Result<&[u8], Error> {
98 self.2.get((index + self.2.subr_bias()) as usize)
99 }
100
101 fn subr(&self, index: i32) -> Result<&[u8], Error> {
102 self.3.get((index + self.3.subr_bias()) as usize)
103 }
104}
105
106#[allow(unused_variables)]
116pub trait CommandSink {
117 fn move_to(&mut self, x: Fixed, y: Fixed);
119 fn line_to(&mut self, x: Fixed, y: Fixed);
120 fn curve_to(&mut self, cx0: Fixed, cy0: Fixed, cx1: Fixed, cy1: Fixed, x: Fixed, y: Fixed);
121 fn close(&mut self);
122 fn hstem(&mut self, y: Fixed, dy: Fixed) {}
125 fn vstem(&mut self, x: Fixed, dx: Fixed) {}
127 fn hint_mask(&mut self, mask: &[u8]) {}
130 fn counter_mask(&mut self, mask: &[u8]) {}
133 fn clear_hints(&mut self) {}
135 fn finish(&mut self) {}
137}
138
139pub fn evaluate<'a>(
152 context: &'a impl CharstringContext,
153 blend_state: Option<BlendState<'a>>,
154 charstring_data: &[u8],
155 sink: &'a mut impl CommandSink,
156) -> Result<Option<Fixed>, Error> {
157 let mut evaluator = Evaluator::new(context, blend_state, sink);
158 evaluator.evaluate(charstring_data)?;
159 let width = evaluator.have_read_width.then_some(evaluator.wx);
160 sink.finish();
161 Ok(width)
162}
163
164#[derive(PartialEq)]
166enum SeacMode {
167 Explicit,
169 Implicit,
172}
173
174struct Evaluator<'a, S> {
177 context: &'a dyn CharstringContext,
178 is_type1: bool,
179 blend_state: Option<BlendState<'a>>,
180 sink: &'a mut S,
181 is_open: bool,
182 is_flexing: bool,
186 seen_width_command: bool,
188 have_read_width: bool,
190 stem_count: usize,
191 x: Fixed,
192 y: Fixed,
193 sbx: Fixed,
195 wx: Fixed,
197 stack: Stack,
198 stack_ix: usize,
199 in_seac: bool,
200 ops_done: u32,
202}
203
204impl<'a, S> Evaluator<'a, S>
205where
206 S: CommandSink,
207{
208 fn new(
209 context: &'a dyn CharstringContext,
210 blend_state: Option<BlendState<'a>>,
211 sink: &'a mut S,
212 ) -> Self {
213 let is_type1 = context.kind() == CharstringKind::Type1;
214 Self {
215 context,
216 is_type1,
217 blend_state,
218 sink,
219 is_open: false,
220 is_flexing: false,
221 seen_width_command: false,
222 have_read_width: false,
223 stem_count: 0,
224 stack: Stack::new(),
225 x: Fixed::ZERO,
226 y: Fixed::ZERO,
227 sbx: Fixed::ZERO,
228 wx: Fixed::ZERO,
229 stack_ix: 0,
230 in_seac: false,
231 ops_done: 0,
232 }
233 }
234
235 fn evaluate(&mut self, charstring_data: &[u8]) -> Result<(), Error> {
236 let seen_endchar = self.evaluate_impl(charstring_data, 0)?;
237 if !self.is_type1 && !seen_endchar {
238 self.evaluate_operator(
241 Operator::EndChar,
242 &mut crate::FontData::default().cursor(),
243 0,
244 )?;
245 }
246 if self.is_open {
247 self.sink.close();
248 }
249 Ok(())
250 }
251
252 fn evaluate_impl(&mut self, charstring_data: &[u8], nesting_depth: u32) -> Result<bool, Error> {
253 if nesting_depth > NESTING_DEPTH_LIMIT {
254 return Err(Error::CharstringNestingDepthLimitExceeded);
255 }
256 let mut cursor = crate::FontData::new(charstring_data).cursor();
257 let mut seen_endchar = false;
258 while cursor.remaining_bytes() != 0 {
259 self.ops_done += 1;
260 if self.ops_done > MAX_OPERATIONS {
261 return Err(Error::CharstringNestingDepthLimitExceeded);
262 }
263 let b0 = cursor.read::<u8>()?;
264 match b0 {
265 28 | 32..=254 => {
269 self.stack.push(num::parse_int(&mut cursor, b0)?)?;
270 }
271 255 => {
273 let val = cursor.read::<i32>()?;
274 if self.is_type1 {
275 self.stack.push(val)?;
277 } else {
278 self.stack.push(Fixed::from_bits(val))?;
281 }
282 }
283 _ => {
284 if let Ok(operator) = Operator::read(&mut cursor, b0) {
288 seen_endchar |= operator == Operator::EndChar;
289 if !self.evaluate_operator(operator, &mut cursor, nesting_depth)? {
290 break;
291 }
292 } else {
293 self.reset_stack();
295 }
296 }
297 }
298 }
299 Ok(seen_endchar)
300 }
301
302 fn evaluate_operator(
306 &mut self,
307 operator: Operator,
308 cursor: &mut Cursor,
309 nesting_depth: u32,
310 ) -> Result<bool, Error> {
311 use Operator::*;
312 use PointMode::*;
313 match operator {
314 Flex => {
324 self.emit_curves([DxDy; 6])?;
325 self.reset_stack();
326 }
327 HFlex => {
329 self.emit_curves([DxY, DxDy, DxY, DxY, DxInitialY, DxY])?;
330 self.reset_stack();
331 }
332 HFlex1 => {
334 self.emit_curves([DxDy, DxDy, DxY, DxY, DxDy, DxInitialY])?;
335 self.reset_stack();
336 }
337 Flex1 => {
339 self.emit_curves([DxDy, DxDy, DxDy, DxDy, DxDy, DLargerCoordDist])?;
340 self.reset_stack();
341 }
342 VariationStoreIndex => {
345 if !self.is_type1 {
346 let blend_state = self.blend_state.as_mut().ok_or(Error::MissingBlendState)?;
347 let store_index = self.stack.pop_i32()? as u16;
348 blend_state.set_store_index(store_index)?;
349 }
350 }
351 Blend => {
354 if !self.is_type1 {
355 let blend_state = self.blend_state.as_ref().ok_or(Error::MissingBlendState)?;
356 self.stack.apply_blend(blend_state)?;
357 }
358 }
359 Return => {
362 return Ok(false);
363 }
364 EndChar => {
368 let stack_len = self.stack.len();
369 if (stack_len == 1 || stack_len == 5) && !self.seen_width_command {
370 self.read_width()?;
371 }
372 self.seen_width_command = true;
373 if stack_len > 1 {
374 self.handle_seac(SeacMode::Implicit, nesting_depth)?;
375 }
376 return Ok(false);
377 }
378 HStem | VStem | HStemHm | VStemHm => {
382 let mut i = 0;
383 let len = if self.stack.len_is_odd() && !self.seen_width_command {
384 self.read_width()?;
385 i = 1;
386 self.stack.len() - 1
387 } else {
388 self.stack.len()
389 };
390 self.seen_width_command = true;
391 let is_horizontal = matches!(operator, HStem | HStemHm);
392 let mut u = Fixed::ZERO;
393 while i < self.stack.len() {
394 let args = self.stack.fixed_array::<2>(i)?;
395 u += args[0];
396 let w = args[1];
397 let v = u.wrapping_add(w);
398 if is_horizontal {
399 self.sink.hstem(u, v);
400 } else {
401 self.sink.vstem(u, v);
402 }
403 u = v;
404 i += 2;
405 }
406 self.stem_count += len / 2;
407 self.reset_stack();
408 }
409 HintMask | CntrMask => {
417 let mut i = 0;
418 let len = if self.stack.len_is_odd() && !self.seen_width_command {
419 self.read_width()?;
420 i = 1;
421 self.stack.len() - 1
422 } else {
423 self.stack.len()
424 };
425 self.seen_width_command = true;
426 let mut u = Fixed::ZERO;
427 while i < self.stack.len() {
428 let args = self.stack.fixed_array::<2>(i)?;
429 u += args[0];
430 let w = args[1];
431 let v = u + w;
432 self.sink.vstem(u, v);
433 u = v;
434 i += 2;
435 }
436 self.stem_count += len / 2;
437 let count = self.stem_count.div_ceil(8);
438 let mask = cursor.read_array::<u8>(count)?;
439 if operator == HintMask {
440 self.sink.hint_mask(mask);
441 } else {
442 self.sink.counter_mask(mask);
443 }
444 self.reset_stack();
445 }
446 RMoveTo => {
450 if self.stack.len() > 2 && !self.seen_width_command {
451 self.read_width()?;
452 }
453 self.seen_width_command = true;
454 if !self.is_flexing {
455 let dy = self.stack.pop_fixed()?;
456 let dx = self.stack.pop_fixed()?;
457 self.x += dx;
458 self.y += dy;
459 if !self.is_open {
460 self.is_open = true;
461 } else {
462 self.sink.close();
463 }
464 self.sink.move_to(self.x, self.y);
465 self.reset_stack();
466 }
467 }
468 HMoveTo | VMoveTo => {
473 if self.stack.len() > 1 && !self.seen_width_command {
474 self.read_width()?;
475 }
476 self.seen_width_command = true;
477 if self.is_flexing {
478 self.stack.push(0)?;
481 if operator == VMoveTo {
482 self.stack.exch()?;
485 }
486 } else {
487 let delta = self.stack.pop_fixed()?;
488 if operator == HMoveTo {
489 self.x += delta;
490 } else {
491 self.y += delta;
492 }
493 if !self.is_open {
494 self.is_open = true;
495 } else {
496 self.sink.close();
497 }
498 self.sink.move_to(self.x, self.y);
499 self.reset_stack();
500 }
501 }
502 RLineTo => {
506 let mut i = 0;
507 while i < self.stack.len() {
508 let [dx, dy] = self.stack.fixed_array::<2>(i)?;
509 self.x += dx;
510 self.y += dy;
511 self.emit_line(self.x, self.y);
512 i += 2;
513 }
514 self.reset_stack();
515 }
516 HLineTo | VLineTo => {
521 let mut is_x = operator == HLineTo;
522 for i in 0..self.stack.len() {
523 let delta = self.stack.get_fixed(i)?;
524 if is_x {
525 self.x += delta;
526 } else {
527 self.y += delta;
528 }
529 is_x = !is_x;
530 self.emit_line(self.x, self.y);
531 }
532 self.reset_stack();
533 }
534 HhCurveTo => {
540 let count1 = self.stack.len();
541 let count = count1 & !2;
542 self.stack_ix = count1 - count;
543 while self.stack_ix < count {
544 if (count - self.stack_ix) & 1 != 0 {
545 self.y += self.stack.get_fixed(self.stack_ix)?;
546 self.stack_ix += 1;
547 }
548 self.emit_curves([DxY, DxDy, DxY])?;
549 }
550 self.reset_stack();
551 }
552 HvCurveTo | VhCurveTo => {
557 let count1 = self.stack.len();
558 let count = count1 & !2;
559 let mut is_horizontal = operator == HvCurveTo;
560 self.stack_ix = count1 - count;
561 while self.stack_ix < count {
562 let do_last_delta = count - self.stack_ix == 5;
563 if is_horizontal {
564 self.emit_curves([DxY, DxDy, MaybeDxDy(do_last_delta)])?;
565 } else {
566 self.emit_curves([XDy, DxDy, DxMaybeDy(do_last_delta)])?;
567 }
568 is_horizontal = !is_horizontal;
569 }
570 self.reset_stack();
571 }
572 RrCurveTo | RCurveLine => {
576 while self.coords_remaining() >= 6 {
577 self.emit_curves([DxDy; 3])?;
578 }
579 if operator == RCurveLine {
580 let [dx, dy] = self.stack.fixed_array::<2>(self.stack_ix)?;
581 self.x += dx;
582 self.y += dy;
583 self.emit_line(self.x, self.y);
584 }
585 self.reset_stack();
586 }
587 RLineCurve => {
591 while self.coords_remaining() > 6 {
592 let [dx, dy] = self.stack.fixed_array::<2>(self.stack_ix)?;
593 self.x += dx;
594 self.y += dy;
595 self.emit_line(self.x, self.y);
596 self.stack_ix += 2;
597 }
598 while self.coords_remaining() >= 6 {
599 self.emit_curves([DxDy; 3])?;
600 }
601 self.reset_stack();
602 }
603 VvCurveTo => {
609 let count1 = self.stack.len();
610 let count = count1 & !2;
611 self.stack_ix = count1 - count;
612 while self.stack_ix < count {
613 if (count - self.stack_ix) & 1 != 0 {
614 self.x += self.stack.get_fixed(self.stack_ix)?;
615 self.stack_ix += 1;
616 }
617 self.emit_curves([XDy, DxDy, XDy])?;
618 }
619 self.reset_stack();
620 }
621 CallSubr | CallGsubr => {
625 let index = self.stack.pop_i32()?;
626 let subr_charstring = if operator == CallSubr {
627 self.context.subr(index)?
628 } else {
629 self.context.global_subr(index)?
630 };
631 self.evaluate_impl(subr_charstring, nesting_depth + 1)?;
632 }
633 Hsbw => {
639 if self.is_type1 {
640 let [sbx, wx] = self.stack.fixed_array(0)?;
641 self.sbx += sbx;
642 self.x += sbx;
643 self.wx = wx;
644 self.seen_width_command = true;
645 self.have_read_width = true;
646 self.reset_stack();
647 }
648 }
649 Seac => {
655 self.handle_seac(SeacMode::Explicit, nesting_depth)?;
656 }
657 Sbw => {
663 if self.is_type1 {
664 let [x, y, wx, _wy] = self.stack.fixed_array(0)?;
665 self.x += x;
666 self.y += y;
667 self.sbx += x;
668 self.wx = wx;
669 self.seen_width_command = true;
670 self.have_read_width = true;
671 self.reset_stack();
672 }
673 }
674 DotSection => {
678 }
680 HStem3 | VStem3 => {
684 self.reset_stack();
686 }
687 Div => {
691 self.stack.div(self.is_type1)?;
692 }
693 CallOtherSubr => {
697 let subr_idx = self.stack.pop_i32()?;
698 let num_args = self.stack.pop_i32()? as usize;
699 let weight_vector = self.context.weight_vector();
700 match (subr_idx, num_args) {
701 (0, 3) => {
704 self.is_flexing = false;
705 self.ensure_open();
706 self.handle_flex()?;
707 }
708 (1, 0) => {
710 self.is_flexing = true;
711 }
712 (12 | 13, _) => {
715 self.reset_stack();
716 }
717 (14..=18, _) if weight_vector.len() > 1 => {
720 self.handle_mm_blend(subr_idx, num_args)?;
721 }
722 _ => {
723 self.stack.drop(num_args);
726 }
727 }
728 }
729 Pop => {
735 }
737 SetCurrentPoint => {
741 if self.is_type1 {
742 let [x, y] = self.stack.fixed_array(0)?;
743 self.x = x;
744 self.y = y;
745 self.reset_stack();
746 }
747 }
748 }
749 Ok(true)
750 }
751
752 fn read_width(&mut self) -> Result<(), Error> {
753 self.wx = self.stack.get_fixed(0)?;
754 self.seen_width_command = true;
755 self.have_read_width = true;
756 Ok(())
757 }
758
759 fn handle_seac(&mut self, mode: SeacMode, nesting_depth: u32) -> Result<(), Error> {
761 if self.in_seac {
763 return Err(Error::CharstringNestingDepthLimitExceeded);
764 }
765 self.in_seac = true;
766 let accent_code = self.stack.pop_i32()?;
767 let base_code = self.stack.pop_i32()?;
768 let [base_charstring, accent_charstring] =
769 self.context.seac_components(base_code, accent_code)?;
770 let dy = self.stack.pop_fixed()?;
771 let dx = self.stack.pop_fixed()?;
772 let sb = if self.is_type1 {
773 self.stack.pop_fixed()?
775 } else if !self.stack.is_empty() && !self.seen_width_command {
776 self.wx = self.stack.pop_fixed()?;
777 self.seen_width_command = true;
778 Fixed::ZERO
779 } else {
780 Fixed::ZERO
781 };
782 let mut sbx = self.sbx;
784 let mut wx = self.wx;
785 let seen_width = self.seen_width_command;
786 let read_width = self.have_read_width;
787 struct Component<'a> {
788 charstring: &'a [u8],
789 x: Fixed,
790 y: Fixed,
791 maybe_use_metrics: bool,
794 }
795 let x = self.x;
796 let y = self.y;
797 let [bx, by] = if mode == SeacMode::Explicit {
799 [Fixed::ZERO; 2]
800 } else {
801 [x, y]
802 };
803 let mut components = [
804 Component {
805 charstring: base_charstring,
806 x: bx,
807 y: by,
808 maybe_use_metrics: mode == SeacMode::Explicit,
811 },
812 Component {
813 charstring: accent_charstring,
814 x: dx + self.sbx - sb,
817 y: dy,
818 maybe_use_metrics: false,
819 },
820 ];
821 if mode == SeacMode::Implicit {
824 components.swap(0, 1);
825 }
826 for component in components {
834 self.reset_stack();
835 self.seen_width_command = false;
836 self.sink.clear_hints();
837 self.stem_count = 0;
838 self.x = component.x;
839 self.y = component.y;
840 self.evaluate_impl(component.charstring, nesting_depth + 1)?;
841 if component.maybe_use_metrics && !seen_width {
842 sbx = self.sbx;
843 wx = self.wx;
844 }
845 }
846 self.seen_width_command = seen_width;
847 self.have_read_width = read_width;
848 self.sbx = sbx;
849 self.wx = wx;
850 self.in_seac = false;
851 Ok(())
852 }
853
854 fn handle_flex(&mut self) -> Result<(), Error> {
856 let final_y = self.stack.pop_fixed()?;
861 let final_x = self.stack.pop_fixed()?;
862 let _ = self.stack.pop_fixed()?;
864 let p3y = self.stack.pop_fixed()?;
865 let p3x = self.stack.pop_fixed()?;
866 let bcp4y = self.stack.pop_fixed()?;
867 let bcp4x = self.stack.pop_fixed()?;
868 let bcp3y = self.stack.pop_fixed()?;
869 let bcp3x = self.stack.pop_fixed()?;
870 let p2y = self.stack.pop_fixed()?;
871 let p2x = self.stack.pop_fixed()?;
872 let bcp2y = self.stack.pop_fixed()?;
873 let bcp2x = self.stack.pop_fixed()?;
874 let bcp1y = self.stack.pop_fixed()?;
875 let bcp1x = self.stack.pop_fixed()?;
876 let rpy = self.stack.pop_fixed()?;
877 let rpx = self.stack.pop_fixed()?;
878 self.reset_stack();
879 self.stack.push(bcp1x + rpx)?;
880 self.stack.push(bcp1y + rpy)?;
881 self.stack.push(bcp2x)?;
882 self.stack.push(bcp2y)?;
883 self.stack.push(p2x)?;
884 self.stack.push(p2y)?;
885 self.emit_curves([PointMode::DxDy; 3])?;
886 self.reset_stack();
887 self.stack.push(bcp3x)?;
888 self.stack.push(bcp3y)?;
889 self.stack.push(bcp4x)?;
890 self.stack.push(bcp4y)?;
891 self.stack.push(p3x)?;
892 self.stack.push(p3y)?;
893 self.emit_curves([PointMode::DxDy; 3])?;
894 self.reset_stack();
895 self.stack.push(final_x)?;
897 self.stack.push(final_y)?;
898 Ok(())
899 }
900
901 fn handle_mm_blend(&mut self, subr_idx: i32, num_args: usize) -> Result<(), Error> {
905 let weight_vector = self.context.weight_vector();
906 let num_points = (subr_idx - 13) as usize + (subr_idx == 18) as usize;
907 if num_args != num_points * weight_vector.len() {
908 return Err(Error::Read(crate::ReadError::MalformedData(
909 "incorrect number of multiple masters arguments",
910 )));
911 }
912 let stack_base = self
921 .stack
922 .len()
923 .checked_sub(num_args)
924 .ok_or(Error::StackUnderflow)?;
925 let mut delta_idx = stack_base + num_points;
926 for i in 0..num_points {
927 let mut val = self.stack.get_fixed(stack_base + i)?;
928 for &weight in &weight_vector[1..] {
929 val += self.stack.get_fixed(delta_idx)? * weight;
930 delta_idx += 1;
931 }
932 self.stack.set(stack_base + i, val)?;
933 }
934 self.stack.drop(num_args.saturating_sub(num_points));
935 Ok(())
936 }
937
938 fn coords_remaining(&self) -> usize {
939 self.stack.len().saturating_sub(self.stack_ix)
943 }
944
945 fn ensure_open(&mut self) {
946 if !self.is_open {
947 self.sink.move_to(Fixed::ZERO, Fixed::ZERO);
948 self.is_open = true;
949 }
950 }
951
952 fn emit_line(&mut self, x: Fixed, y: Fixed) {
953 self.ensure_open();
954 self.sink.line_to(x, y);
955 }
956
957 fn emit_curves<const N: usize>(&mut self, modes: [PointMode; N]) -> Result<(), Error> {
958 use PointMode::*;
959 let initial_x = self.x;
960 let initial_y = self.y;
961 let mut count = 0;
962 let mut points = [Point::default(); 2];
963 self.ensure_open();
964 for mode in modes {
965 let stack_used = match mode {
966 DxDy => {
967 self.x += self.stack.get_fixed(self.stack_ix)?;
968 self.y += self.stack.get_fixed(self.stack_ix + 1)?;
969 2
970 }
971 XDy => {
972 self.y += self.stack.get_fixed(self.stack_ix)?;
973 1
974 }
975 DxY => {
976 self.x += self.stack.get_fixed(self.stack_ix)?;
977 1
978 }
979 DxInitialY => {
980 self.x += self.stack.get_fixed(self.stack_ix)?;
981 self.y = initial_y;
982 1
983 }
984 DLargerCoordDist => {
988 let delta = self.stack.get_fixed(self.stack_ix)?;
989 if (self.x - initial_x).abs() > (self.y - initial_y).abs() {
990 self.x += delta;
991 self.y = initial_y;
992 } else {
993 self.y += delta;
994 self.x = initial_x;
995 }
996 1
997 }
998 DxMaybeDy(do_dy) => {
1000 self.x += self.stack.get_fixed(self.stack_ix)?;
1001 if do_dy {
1002 self.y += self.stack.get_fixed(self.stack_ix + 1)?;
1003 2
1004 } else {
1005 1
1006 }
1007 }
1008 MaybeDxDy(do_dx) => {
1010 self.y += self.stack.get_fixed(self.stack_ix)?;
1011 if do_dx {
1012 self.x += self.stack.get_fixed(self.stack_ix + 1)?;
1013 2
1014 } else {
1015 1
1016 }
1017 }
1018 };
1019 self.stack_ix += stack_used;
1020 if count == 2 {
1021 self.sink.curve_to(
1022 points[0].x,
1023 points[0].y,
1024 points[1].x,
1025 points[1].y,
1026 self.x,
1027 self.y,
1028 );
1029 count = 0;
1030 } else {
1031 points[count] = Point::new(self.x, self.y);
1032 count += 1;
1033 }
1034 }
1035 Ok(())
1036 }
1037
1038 fn reset_stack(&mut self) {
1039 self.stack.clear();
1040 self.stack_ix = 0;
1041 }
1042}
1043
1044#[derive(Copy, Clone)]
1046enum PointMode {
1047 DxDy,
1048 XDy,
1049 DxY,
1050 DxInitialY,
1051 DLargerCoordDist,
1052 DxMaybeDy(bool),
1053 MaybeDxDy(bool),
1054}
1055
1056#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1062enum Operator {
1063 HStem,
1064 VStem,
1065 VMoveTo,
1066 RLineTo,
1067 HLineTo,
1068 VLineTo,
1069 RrCurveTo,
1070 CallSubr,
1071 Return,
1072 Hsbw,
1073 EndChar,
1074 VariationStoreIndex,
1075 Blend,
1076 HStemHm,
1077 HintMask,
1078 CntrMask,
1079 RMoveTo,
1080 HMoveTo,
1081 VStemHm,
1082 RCurveLine,
1083 RLineCurve,
1084 VvCurveTo,
1085 HhCurveTo,
1086 CallGsubr,
1087 VhCurveTo,
1088 HvCurveTo,
1089 DotSection,
1090 VStem3,
1091 HStem3,
1092 Seac,
1093 Sbw,
1094 Div,
1095 CallOtherSubr,
1096 Pop,
1097 SetCurrentPoint,
1098 HFlex,
1099 Flex,
1100 HFlex1,
1101 Flex1,
1102}
1103
1104impl Operator {
1105 fn read(cursor: &mut Cursor, b0: u8) -> Result<Self, Error> {
1106 const ESCAPE: u8 = 12;
1108 let (opcode, operator) = if b0 == ESCAPE {
1109 let b1 = cursor.read::<u8>()?;
1110 (b1, Self::from_two_byte_opcode(b1))
1111 } else {
1112 (b0, Self::from_opcode(b0))
1113 };
1114 operator.ok_or(Error::InvalidCharstringOperator(opcode))
1115 }
1116
1117 fn from_opcode(opcode: u8) -> Option<Self> {
1119 use Operator::*;
1120 Some(match opcode {
1121 1 => HStem,
1122 3 => VStem,
1123 4 => VMoveTo,
1124 5 => RLineTo,
1125 6 => HLineTo,
1126 7 => VLineTo,
1127 8 => RrCurveTo,
1128 10 => CallSubr,
1129 11 => Return,
1130 13 => Hsbw,
1131 14 => EndChar,
1132 15 => VariationStoreIndex,
1133 16 => Blend,
1134 18 => HStemHm,
1135 19 => HintMask,
1136 20 => CntrMask,
1137 21 => RMoveTo,
1138 22 => HMoveTo,
1139 23 => VStemHm,
1140 24 => RCurveLine,
1141 25 => RLineCurve,
1142 26 => VvCurveTo,
1143 27 => HhCurveTo,
1144 29 => CallGsubr,
1145 30 => VhCurveTo,
1146 31 => HvCurveTo,
1147 _ => return None,
1148 })
1149 }
1150
1151 pub fn from_two_byte_opcode(opcode: u8) -> Option<Self> {
1155 use Operator::*;
1156 Some(match opcode {
1157 0 => DotSection,
1158 1 => VStem3,
1159 2 => HStem3,
1160 6 => Seac,
1161 7 => Sbw,
1162 12 => Div,
1163 16 => CallOtherSubr,
1164 17 => Pop,
1165 33 => SetCurrentPoint,
1166 34 => HFlex,
1167 35 => Flex,
1168 36 => HFlex1,
1169 37 => Flex1,
1170 _ => return None,
1171 })
1172 }
1173}
1174
1175const ONE_OVER_64: Fixed = Fixed::from_bits(0x400);
1177
1178pub struct TransformSink<'a, S> {
1180 inner: &'a mut S,
1181 matrix: Option<FontMatrix>,
1182 scale: Option<Fixed>,
1183}
1184
1185impl<'a, S> TransformSink<'a, S> {
1186 pub fn new(sink: &'a mut S, transform: Transform) -> Self {
1188 Self::from_matrix_scale(sink, transform.matrix, transform.scale)
1189 }
1190
1191 pub fn from_matrix_scale(sink: &'a mut S, matrix: FontMatrix, scale: Option<Fixed>) -> Self {
1193 Self {
1194 inner: sink,
1195 matrix: (matrix != FontMatrix::IDENTITY).then_some(matrix),
1196 scale,
1197 }
1198 }
1199
1200 fn transform(&self, x: Fixed, y: Fixed) -> (Fixed, Fixed) {
1201 let ax = x * ONE_OVER_64;
1211 let ay = y * ONE_OVER_64;
1212 let bx = Fixed::from_bits(ax.to_bits() >> 10);
1216 let by = Fixed::from_bits(ay.to_bits() >> 10);
1217 let (cx, cy) = self
1219 .matrix
1220 .as_ref()
1221 .map(|mat| mat.transform(bx, by))
1222 .unwrap_or((bx, by));
1223 if let Some(scale) = self.scale {
1224 let dx = cx * scale;
1228 let dy = cy * scale;
1229 (
1231 Fixed::from_bits(dx.to_bits() << 10),
1232 Fixed::from_bits(dy.to_bits() << 10),
1233 )
1234 } else {
1235 (
1238 Fixed::from_bits(cx.to_bits() << 16),
1239 Fixed::from_bits(cy.to_bits() << 16),
1240 )
1241 }
1242 }
1243}
1244
1245impl<S: CommandSink> CommandSink for TransformSink<'_, S> {
1246 fn hstem(&mut self, y: Fixed, dy: Fixed) {
1247 self.inner.hstem(y, dy);
1248 }
1249
1250 fn vstem(&mut self, x: Fixed, dx: Fixed) {
1251 self.inner.vstem(x, dx);
1252 }
1253
1254 fn hint_mask(&mut self, mask: &[u8]) {
1255 self.inner.hint_mask(mask);
1256 }
1257
1258 fn counter_mask(&mut self, mask: &[u8]) {
1259 self.inner.counter_mask(mask);
1260 }
1261
1262 fn clear_hints(&mut self) {
1263 self.inner.clear_hints();
1264 }
1265
1266 fn move_to(&mut self, x: Fixed, y: Fixed) {
1267 let (x, y) = self.transform(x, y);
1268 self.inner.move_to(x, y);
1269 }
1270
1271 fn line_to(&mut self, x: Fixed, y: Fixed) {
1272 let (x, y) = self.transform(x, y);
1273 self.inner.line_to(x, y);
1274 }
1275
1276 fn curve_to(&mut self, cx1: Fixed, cy1: Fixed, cx2: Fixed, cy2: Fixed, x: Fixed, y: Fixed) {
1277 let (cx1, cy1) = self.transform(cx1, cy1);
1278 let (cx2, cy2) = self.transform(cx2, cy2);
1279 let (x, y) = self.transform(x, y);
1280 self.inner.curve_to(cx1, cy1, cx2, cy2, x, y);
1281 }
1282
1283 fn close(&mut self) {
1284 self.inner.close();
1285 }
1286
1287 fn finish(&mut self) {
1288 self.inner.finish();
1289 }
1290}
1291
1292#[derive(Copy, Clone)]
1293enum PendingElement {
1294 Move([Fixed; 2]),
1295 Line([Fixed; 2]),
1296 Curve([Fixed; 6]),
1297}
1298
1299impl PendingElement {
1300 fn target_point(&self) -> [Fixed; 2] {
1301 match self {
1302 Self::Move(xy) | Self::Line(xy) => *xy,
1303 Self::Curve([.., x, y]) => [*x, *y],
1304 }
1305 }
1306}
1307
1308pub struct NopFilterSink<'a, S> {
1317 is_open: bool,
1318 start: Option<(Fixed, Fixed)>,
1319 pending_element: Option<PendingElement>,
1320 inner: &'a mut S,
1321}
1322
1323impl<'a, S> NopFilterSink<'a, S>
1324where
1325 S: CommandSink,
1326{
1327 pub fn new(inner: &'a mut S) -> Self {
1330 Self {
1331 is_open: false,
1332 start: None,
1333 pending_element: None,
1334 inner,
1335 }
1336 }
1337
1338 fn flush_pending(&mut self, for_close: bool) {
1339 if let Some(pending) = self.pending_element.take() {
1340 match pending {
1341 PendingElement::Move([x, y]) => {
1342 if !for_close {
1343 self.is_open = true;
1344 self.inner.move_to(x, y);
1345 self.start = Some((x, y));
1346 }
1347 }
1348 PendingElement::Line([x, y]) => {
1349 if !for_close || self.start != Some((x, y)) {
1350 self.inner.line_to(x, y);
1351 }
1352 }
1353 PendingElement::Curve([cx0, cy0, cx1, cy1, x, y]) => {
1354 self.inner.curve_to(cx0, cy0, cx1, cy1, x, y);
1355 }
1356 }
1357 }
1358 }
1359}
1360
1361impl<S> CommandSink for NopFilterSink<'_, S>
1362where
1363 S: CommandSink,
1364{
1365 fn hstem(&mut self, y: Fixed, dy: Fixed) {
1366 self.inner.hstem(y, dy);
1367 }
1368
1369 fn vstem(&mut self, x: Fixed, dx: Fixed) {
1370 self.inner.vstem(x, dx);
1371 }
1372
1373 fn hint_mask(&mut self, mask: &[u8]) {
1374 self.inner.hint_mask(mask);
1375 }
1376
1377 fn counter_mask(&mut self, mask: &[u8]) {
1378 self.inner.counter_mask(mask);
1379 }
1380
1381 fn clear_hints(&mut self) {
1382 self.inner.clear_hints();
1383 }
1384
1385 fn move_to(&mut self, x: Fixed, y: Fixed) {
1386 self.pending_element = Some(PendingElement::Move([x, y]));
1387 }
1388
1389 fn line_to(&mut self, x: Fixed, y: Fixed) {
1390 if self
1392 .pending_element
1393 .map(|element| element.target_point() == [x, y])
1394 .unwrap_or_default()
1395 {
1396 return;
1397 }
1398 self.flush_pending(false);
1399 self.pending_element = Some(PendingElement::Line([x, y]));
1400 }
1401
1402 fn curve_to(&mut self, cx1: Fixed, cy1: Fixed, cx2: Fixed, cy2: Fixed, x: Fixed, y: Fixed) {
1403 self.flush_pending(false);
1404 self.pending_element = Some(PendingElement::Curve([cx1, cy1, cx2, cy2, x, y]));
1405 }
1406
1407 fn close(&mut self) {
1408 self.flush_pending(true);
1409 if self.is_open {
1410 self.inner.close();
1411 self.is_open = false;
1412 }
1413 }
1414
1415 fn finish(&mut self) {
1416 self.close();
1417 self.inner.finish();
1418 }
1419}
1420
1421impl<P: OutlinePen> CommandSink for P {
1422 fn move_to(&mut self, x: Fixed, y: Fixed) {
1423 self.move_to(x.to_f32(), y.to_f32());
1424 }
1425
1426 fn line_to(&mut self, x: Fixed, y: Fixed) {
1427 self.line_to(x.to_f32(), y.to_f32());
1428 }
1429
1430 fn curve_to(&mut self, cx0: Fixed, cy0: Fixed, cx1: Fixed, cy1: Fixed, x: Fixed, y: Fixed) {
1431 self.curve_to(
1432 cx0.to_f32(),
1433 cy0.to_f32(),
1434 cx1.to_f32(),
1435 cy1.to_f32(),
1436 x.to_f32(),
1437 y.to_f32(),
1438 );
1439 }
1440
1441 fn close(&mut self) {
1442 self.close()
1443 }
1444}
1445
1446#[cfg(test)]
1447pub(crate) mod test_helpers {
1448 use super::{CommandSink, Fixed};
1449
1450 #[derive(Copy, Clone, PartialEq, Debug)]
1451 #[allow(clippy::enum_variant_names)]
1452 pub enum Command {
1453 MoveTo(Fixed, Fixed),
1454 LineTo(Fixed, Fixed),
1455 CurveTo(Fixed, Fixed, Fixed, Fixed, Fixed, Fixed),
1456 }
1457
1458 #[derive(PartialEq, Default, Debug)]
1459 pub struct CaptureCommandSink(pub Vec<Command>);
1460
1461 impl CommandSink for CaptureCommandSink {
1462 fn move_to(&mut self, x: Fixed, y: Fixed) {
1463 self.0.push(Command::MoveTo(x, y))
1464 }
1465
1466 fn line_to(&mut self, x: Fixed, y: Fixed) {
1467 self.0.push(Command::LineTo(x, y))
1468 }
1469
1470 fn curve_to(&mut self, cx0: Fixed, cy0: Fixed, cx1: Fixed, cy1: Fixed, x: Fixed, y: Fixed) {
1471 self.0.push(Command::CurveTo(cx0, cy0, cx1, cy1, x, y))
1472 }
1473
1474 fn close(&mut self) {
1475 let mut last_move = [Fixed::ZERO; 2];
1479 for command in self.0.iter().rev() {
1480 if let Command::MoveTo(x, y) = command {
1481 last_move = [*x, *y];
1482 break;
1483 }
1484 }
1485 self.0.push(Command::LineTo(last_move[0], last_move[1]));
1486 }
1487 }
1488
1489 impl CaptureCommandSink {
1490 pub fn to_svg(&self) -> String {
1491 use core::fmt::Write;
1492 let mut buf = String::default();
1493 for cmd in &self.0 {
1494 if !buf.is_empty() {
1495 buf.push(' ');
1496 }
1497 match cmd {
1498 Command::MoveTo(x, y) => write!(buf, "M{},{}", x.to_f32(), y.to_f32()).unwrap(),
1499 Command::LineTo(x, y) => write!(buf, "L{},{}", x.to_f32(), y.to_f32()).unwrap(),
1500 Command::CurveTo(x0, y0, x1, y1, x, y) => write!(
1501 buf,
1502 "C{},{} {},{} {},{}",
1503 x0.to_f32(),
1504 y0.to_f32(),
1505 x1.to_f32(),
1506 y1.to_f32(),
1507 x.to_f32(),
1508 y.to_f32()
1509 )
1510 .unwrap(),
1511 }
1512 }
1513 buf
1514 }
1515 }
1516
1517 #[derive(Default)]
1518 pub struct CharstringCommandCounter(pub usize);
1519
1520 impl CommandSink for CharstringCommandCounter {
1521 fn move_to(&mut self, _x: Fixed, _y: Fixed) {
1522 self.0 += 1;
1523 }
1524
1525 fn line_to(&mut self, _x: Fixed, _y: Fixed) {
1526 self.0 += 1;
1527 }
1528
1529 fn curve_to(
1530 &mut self,
1531 _cx0: Fixed,
1532 _cy0: Fixed,
1533 _cx1: Fixed,
1534 _cy1: Fixed,
1535 _x: Fixed,
1536 _y: Fixed,
1537 ) {
1538 self.0 += 1;
1539 }
1540
1541 fn close(&mut self) {
1542 self.0 += 1;
1543 }
1544 }
1545}
1546
1547#[cfg(test)]
1548mod tests {
1549 use super::{test_helpers::*, *};
1550 use crate::{tables::variations::ItemVariationStore, types::F2Dot14, FontData, FontRead};
1551
1552 #[test]
1553 fn cff2_example_subr() {
1554 use Command::*;
1555 let charstring = &font_test_data::cff2::EXAMPLE[0xc8..=0xe1];
1556 let store =
1557 ItemVariationStore::read(FontData::new(&font_test_data::cff2::EXAMPLE[18..])).unwrap();
1558 let coords = &[F2Dot14::from_f32(0.0)];
1559 let blend_state = BlendState::new(store, coords, 0).unwrap();
1560 let mut commands = CaptureCommandSink::default();
1561 evaluate(
1562 &NullContext(CharstringKind::Type2),
1563 Some(blend_state),
1564 charstring,
1565 &mut commands,
1566 )
1567 .unwrap();
1568 let expected = &[
1585 MoveTo(Fixed::from_f64(50.0), Fixed::ZERO),
1586 LineTo(Fixed::from_f64(550.0), Fixed::ZERO),
1587 LineTo(Fixed::from_f64(550.0), Fixed::from_f64(500.0)),
1588 LineTo(Fixed::from_f64(50.0), Fixed::from_f64(500.0)),
1589 LineTo(Fixed::from_f64(50.0), Fixed::ZERO),
1590 ];
1591 assert_eq!(&commands.0, expected);
1592 }
1593
1594 #[test]
1595 fn all_path_ops() {
1596 let charstring = &[
1626 251, 29, 253, 12, 21, 173, 134, 159, 133, 5, 140, 141, 142, 6, 251, 71, 129, 142, 7,
1627 109, 154, 161, 147, 89, 165, 125, 97, 98, 158, 124, 164, 8, 109, 154, 161, 147, 27,
1628 147, 109, 154, 161, 147, 27, 163, 159, 154, 180, 181, 119, 153, 115, 114, 120, 125, 97,
1629 98, 158, 124, 164, 31, 159, 4, 119, 153, 115, 114, 120, 125, 143, 144, 24, 119, 153,
1630 115, 114, 120, 125, 143, 144, 25, 84, 116, 117, 80, 30, 109, 154, 161, 147, 26, 147,
1631 109, 154, 161, 147, 26, 163, 159, 154, 180, 181, 119, 153, 115, 114, 120, 125, 97, 162,
1632 12, 35, 163, 159, 154, 180, 181, 119, 153, 12, 34, 152, 22, 180, 181, 119, 153, 115,
1633 114, 120, 125, 97, 12, 36, 154, 180, 181, 119, 153, 115, 114, 120, 125, 97, 147, 12,
1634 37, 14,
1635 ];
1636 use Command::*;
1637 let mut commands = CaptureCommandSink::default();
1638 evaluate(
1639 &NullContext(CharstringKind::Type2),
1640 None,
1641 charstring,
1642 &mut commands,
1643 )
1644 .unwrap();
1645 let expected = &[
1686 MoveTo(Fixed::from_i32(-137), Fixed::from_i32(-632)),
1687 LineTo(Fixed::from_i32(-103), Fixed::from_i32(-637)),
1688 LineTo(Fixed::from_i32(-83), Fixed::from_i32(-643)),
1689 LineTo(Fixed::from_i32(-82), Fixed::from_i32(-643)),
1690 LineTo(Fixed::from_i32(-82), Fixed::from_i32(-641)),
1691 LineTo(Fixed::from_i32(-79), Fixed::from_i32(-641)),
1692 LineTo(Fixed::from_i32(-79), Fixed::from_i32(-820)),
1693 LineTo(Fixed::from_i32(-89), Fixed::from_i32(-820)),
1694 LineTo(Fixed::from_i32(-89), Fixed::from_i32(-817)),
1695 CurveTo(
1696 Fixed::from_i32(-119),
1697 Fixed::from_i32(-802),
1698 Fixed::from_i32(-97),
1699 Fixed::from_i32(-794),
1700 Fixed::from_i32(-147),
1701 Fixed::from_i32(-768),
1702 ),
1703 CurveTo(
1704 Fixed::from_i32(-161),
1705 Fixed::from_i32(-810),
1706 Fixed::from_i32(-202),
1707 Fixed::from_i32(-791),
1708 Fixed::from_i32(-217),
1709 Fixed::from_i32(-766),
1710 ),
1711 CurveTo(
1712 Fixed::from_i32(-247),
1713 Fixed::from_i32(-766),
1714 Fixed::from_i32(-232),
1715 Fixed::from_i32(-744),
1716 Fixed::from_i32(-224),
1717 Fixed::from_i32(-744),
1718 ),
1719 CurveTo(
1720 Fixed::from_i32(-254),
1721 Fixed::from_i32(-736),
1722 Fixed::from_i32(-239),
1723 Fixed::from_i32(-714),
1724 Fixed::from_i32(-231),
1725 Fixed::from_i32(-714),
1726 ),
1727 CurveTo(
1728 Fixed::from_i32(-207),
1729 Fixed::from_i32(-714),
1730 Fixed::from_i32(-187),
1731 Fixed::from_i32(-699),
1732 Fixed::from_i32(-187),
1733 Fixed::from_i32(-658),
1734 ),
1735 CurveTo(
1736 Fixed::from_i32(-187),
1737 Fixed::from_i32(-616),
1738 Fixed::from_i32(-207),
1739 Fixed::from_i32(-602),
1740 Fixed::from_i32(-231),
1741 Fixed::from_i32(-602),
1742 ),
1743 CurveTo(
1744 Fixed::from_i32(-256),
1745 Fixed::from_i32(-602),
1746 Fixed::from_i32(-275),
1747 Fixed::from_i32(-616),
1748 Fixed::from_i32(-275),
1749 Fixed::from_i32(-658),
1750 ),
1751 CurveTo(
1752 Fixed::from_i32(-275),
1753 Fixed::from_i32(-699),
1754 Fixed::from_i32(-256),
1755 Fixed::from_i32(-714),
1756 Fixed::from_i32(-231),
1757 Fixed::from_i32(-714),
1758 ),
1759 LineTo(Fixed::from_i32(-137), Fixed::from_i32(-632)),
1760 MoveTo(Fixed::from_i32(-231), Fixed::from_i32(-694)),
1761 CurveTo(
1762 Fixed::from_i32(-251),
1763 Fixed::from_i32(-680),
1764 Fixed::from_i32(-275),
1765 Fixed::from_i32(-705),
1766 Fixed::from_i32(-294),
1767 Fixed::from_i32(-719),
1768 ),
1769 LineTo(Fixed::from_i32(-290), Fixed::from_i32(-714)),
1770 LineTo(Fixed::from_i32(-310), Fixed::from_i32(-700)),
1771 CurveTo(
1772 Fixed::from_i32(-334),
1773 Fixed::from_i32(-725),
1774 Fixed::from_i32(-353),
1775 Fixed::from_i32(-739),
1776 Fixed::from_i32(-349),
1777 Fixed::from_i32(-734),
1778 ),
1779 CurveTo(
1780 Fixed::from_i32(-349),
1781 Fixed::from_i32(-789),
1782 Fixed::from_i32(-372),
1783 Fixed::from_i32(-811),
1784 Fixed::from_i32(-431),
1785 Fixed::from_i32(-811),
1786 ),
1787 CurveTo(
1788 Fixed::from_i32(-431),
1789 Fixed::from_i32(-841),
1790 Fixed::from_i32(-416),
1791 Fixed::from_i32(-819),
1792 Fixed::from_i32(-416),
1793 Fixed::from_i32(-811),
1794 ),
1795 CurveTo(
1796 Fixed::from_i32(-408),
1797 Fixed::from_i32(-841),
1798 Fixed::from_i32(-393),
1799 Fixed::from_i32(-819),
1800 Fixed::from_i32(-393),
1801 Fixed::from_i32(-811),
1802 ),
1803 CurveTo(
1804 Fixed::from_i32(-369),
1805 Fixed::from_i32(-791),
1806 Fixed::from_i32(-354),
1807 Fixed::from_i32(-750),
1808 Fixed::from_i32(-312),
1809 Fixed::from_i32(-770),
1810 ),
1811 CurveTo(
1812 Fixed::from_i32(-298),
1813 Fixed::from_i32(-794),
1814 Fixed::from_i32(-323),
1815 Fixed::from_i32(-813),
1816 Fixed::from_i32(-337),
1817 Fixed::from_i32(-855),
1818 ),
1819 CurveTo(
1820 Fixed::from_i32(-313),
1821 Fixed::from_i32(-855),
1822 Fixed::from_i32(-293),
1823 Fixed::from_i32(-840),
1824 Fixed::from_i32(-252),
1825 Fixed::from_i32(-840),
1826 ),
1827 CurveTo(
1828 Fixed::from_i32(-210),
1829 Fixed::from_i32(-840),
1830 Fixed::from_i32(-230),
1831 Fixed::from_i32(-855),
1832 Fixed::from_i32(-216),
1833 Fixed::from_i32(-855),
1834 ),
1835 LineTo(Fixed::from_i32(-231), Fixed::from_i32(-694)),
1836 MoveTo(Fixed::from_i32(-203), Fixed::from_i32(-855)),
1837 CurveTo(
1838 Fixed::from_i32(-162),
1839 Fixed::from_i32(-813),
1840 Fixed::from_i32(-182),
1841 Fixed::from_i32(-799),
1842 Fixed::from_i32(-206),
1843 Fixed::from_i32(-799),
1844 ),
1845 CurveTo(
1846 Fixed::from_i32(-231),
1847 Fixed::from_i32(-799),
1848 Fixed::from_i32(-250),
1849 Fixed::from_i32(-813),
1850 Fixed::from_i32(-292),
1851 Fixed::from_i32(-855),
1852 ),
1853 CurveTo(
1854 Fixed::from_i32(-277),
1855 Fixed::from_i32(-814),
1856 Fixed::from_i32(-235),
1857 Fixed::from_i32(-834),
1858 Fixed::from_i32(-221),
1859 Fixed::from_i32(-858),
1860 ),
1861 CurveTo(
1862 Fixed::from_i32(-246),
1863 Fixed::from_i32(-877),
1864 Fixed::from_i32(-260),
1865 Fixed::from_i32(-919),
1866 Fixed::from_i32(-292),
1867 Fixed::from_i32(-911),
1868 ),
1869 LineTo(Fixed::from_i32(-203), Fixed::from_i32(-855)),
1870 ];
1871 assert_eq!(&commands.0, expected);
1872 }
1873
1874 #[test]
1877 fn coords_remaining_avoid_overflow() {
1878 let mut commands = CaptureCommandSink::default();
1881 let mut evaluator =
1882 Evaluator::new(&NullContext(CharstringKind::Type2), None, &mut commands);
1883 evaluator.stack.push(0).unwrap();
1884 evaluator.stack.push(0).unwrap();
1885 let mut cursor = FontData::new(&[]).cursor();
1886 let _ = evaluator.evaluate_operator(Operator::HhCurveTo, &mut cursor, 0);
1888 }
1889
1890 #[test]
1891 fn ignore_reserved_operators() {
1892 let charstring = &[
1893 0u8, 32, 22, 2, ];
1898 let mut commands = CaptureCommandSink::default();
1899 evaluate(
1900 &NullContext(CharstringKind::Type2),
1901 None,
1902 charstring,
1903 &mut commands,
1904 )
1905 .unwrap();
1906 let x = Fixed::from_i32(-107);
1907 assert_eq!(
1908 commands.0,
1909 [
1910 Command::MoveTo(x, Fixed::ZERO),
1911 Command::LineTo(x, Fixed::ZERO)
1912 ]
1913 );
1914 }
1915
1916 #[test]
1917 fn operation_limit() {
1918 let charstring = vec![0u8; MAX_OPERATIONS as usize + 1];
1921 let mut commands = CaptureCommandSink::default();
1922 evaluate(
1924 &NullContext(CharstringKind::Type2),
1925 None,
1926 &charstring[..MAX_OPERATIONS as usize],
1927 &mut commands,
1928 )
1929 .unwrap();
1930 let err = evaluate(
1932 &NullContext(CharstringKind::Type2),
1933 None,
1934 &charstring,
1935 &mut commands,
1936 )
1937 .unwrap_err();
1938 assert!(matches!(err, Error::CharstringNestingDepthLimitExceeded));
1939 }
1940
1941 #[test]
1942 fn op_div() {
1943 let mut commands = CaptureCommandSink::default();
1944 let mut eval = Evaluator::new(&NullContext(CharstringKind::Type2), None, &mut commands);
1945 let mut cursor = FontData::new(&[]).cursor();
1946 eval.stack.push(Fixed::from_f64(512.5)).unwrap();
1947 eval.stack.push(2).unwrap();
1948 eval.evaluate_operator(Operator::Div, &mut cursor, 0)
1949 .unwrap();
1950 assert_eq!(
1951 eval.stack.pop_fixed().unwrap(),
1952 Fixed::from_f64(512.5 / 2.0)
1953 );
1954 }
1955
1956 #[test]
1957 fn op_div_type1_large_int() {
1958 let mut commands = CaptureCommandSink::default();
1959 let mut eval = Evaluator::new(&NullContext(CharstringKind::Type1), None, &mut commands);
1960 let mut cursor = FontData::new(&[]).cursor();
1961 eval.stack.push(32001).unwrap();
1963 eval.stack.push(2).unwrap();
1964 eval.evaluate_operator(Operator::Div, &mut cursor, 0)
1965 .unwrap();
1966 assert_eq!(
1967 eval.stack.pop_fixed().unwrap(),
1968 Fixed::from_f64(32001.0 / 2.0)
1969 );
1970 }
1971
1972 fn eval_h_sbw(operator: Operator, kind: CharstringKind) -> [Fixed; 2] {
1976 let mut commands = CaptureCommandSink::default();
1977 let ctx = &NullContext(kind);
1978 let mut eval = Evaluator::new(ctx, None, &mut commands);
1979 let mut cursor = FontData::new(&[]).cursor();
1980 eval.stack.push(Fixed::from_f64(42.5)).unwrap();
1981 if operator == Operator::Sbw {
1982 eval.stack.push(0).unwrap();
1984 }
1985 eval.stack.push(501).unwrap();
1986 eval.stack.push(1000).unwrap();
1987 eval.evaluate_operator(operator, &mut cursor, 0).unwrap();
1988 [eval.sbx, eval.wx]
1989 }
1990
1991 #[test]
1992 fn op_sbw_type1() {
1993 let [sbx, wx] = eval_h_sbw(Operator::Sbw, CharstringKind::Type1);
1994 assert_eq!(sbx, Fixed::from_f64(42.5));
1995 assert_eq!(wx, Fixed::from_f64(501.0));
1996 }
1997
1998 #[test]
1999 fn op_hsbw_type1() {
2000 let [sbx, wx] = eval_h_sbw(Operator::Hsbw, CharstringKind::Type1);
2001 assert_eq!(sbx, Fixed::from_f64(42.5));
2002 assert_eq!(wx, Fixed::from_f64(501.0));
2003 }
2004
2005 #[test]
2007 fn op_sbw_type2_no_effect() {
2008 let [sbx, wx] = eval_h_sbw(Operator::Sbw, CharstringKind::Type2);
2009 assert_eq!(sbx, Fixed::ZERO);
2010 assert_eq!(wx, Fixed::ZERO);
2011 }
2012
2013 #[test]
2015 fn op_hsbw_type2_no_effect() {
2016 let [sbx, wx] = eval_h_sbw(Operator::Hsbw, CharstringKind::Type2);
2017 assert_eq!(sbx, Fixed::ZERO);
2018 assert_eq!(wx, Fixed::ZERO);
2019 }
2020
2021 #[test]
2022 fn op_callothersubr_flex() {
2023 let mut commands = CaptureCommandSink::default();
2024 let mut eval = Evaluator::new(&NullContext(CharstringKind::Type1), None, &mut commands);
2025 let mut cursor = FontData::new(&[]).cursor();
2026 macro_rules! op {
2028 ($nums:expr) => {
2029 for n in $nums {
2030 eval.stack.push(n).unwrap();
2031 }
2032 };
2033 ($nums:expr, $op:ident) => {
2034 op!($nums);
2035 eval.evaluate_operator(Operator::$op, &mut cursor, 0)
2036 .unwrap();
2037 };
2038 }
2039 op!([0, 1], CallOtherSubr);
2042 for vec in [[1, 2]; 7] {
2044 op!(vec, RMoveTo);
2045 }
2046 op!([0, 100, 200]);
2048 op!([3, 0], CallOtherSubr);
2050 let none: [i32; 0] = [];
2053 op!(none, SetCurrentPoint);
2054 let expected = [
2055 Command::MoveTo(Fixed::ZERO, Fixed::ZERO),
2056 Command::CurveTo(
2057 Fixed::from_i32(2),
2058 Fixed::from_i32(4),
2059 Fixed::from_i32(3),
2060 Fixed::from_i32(6),
2061 Fixed::from_i32(4),
2062 Fixed::from_i32(8),
2063 ),
2064 Command::CurveTo(
2065 Fixed::from_i32(5),
2066 Fixed::from_i32(10),
2067 Fixed::from_i32(6),
2068 Fixed::from_i32(12),
2069 Fixed::from_i32(7),
2070 Fixed::from_i32(14),
2071 ),
2072 ];
2073 assert_eq!(eval.x, Fixed::from_i32(100));
2074 assert_eq!(eval.y, Fixed::from_i32(200));
2075 assert_eq!(commands.0, expected);
2076 }
2077
2078 struct NullContext(CharstringKind);
2079
2080 impl CharstringContext for NullContext {
2081 fn kind(&self) -> CharstringKind {
2082 self.0
2083 }
2084
2085 fn seac_components(&self, base_code: i32, _accent_code: i32) -> Result<[&[u8]; 2], Error> {
2086 Err(Error::InvalidSeacCode(base_code))
2087 }
2088
2089 fn global_subr(&self, _index: i32) -> Result<&[u8], Error> {
2090 Err(Error::MissingSubroutines)
2091 }
2092
2093 fn subr(&self, _index: i32) -> Result<&[u8], Error> {
2094 Err(Error::MissingSubroutines)
2095 }
2096 }
2097
2098 #[test]
2099 fn nop_filter_sink() {
2100 let mut commands = CaptureCommandSink::default();
2101 let mut nop_filter = NopFilterSink::new(&mut commands);
2102 let (sx, sy) = (Fixed::from_f64(10.2), Fixed::from_f64(20.4));
2103 nop_filter.move_to(Fixed::from_f64(0.0), Fixed::from_f64(0.0));
2105 nop_filter.move_to(sx, sy);
2106 nop_filter.line_to(sx, sy);
2108 nop_filter.curve_to(
2109 Fixed::from_f64(5.0),
2110 Fixed::from_f64(-5.0),
2111 Fixed::from_f64(1.5),
2112 Fixed::from_f64(2.0),
2113 Fixed::from_f64(4.5),
2114 Fixed::from_f64(-10.0),
2115 );
2116 nop_filter.line_to(Fixed::from_f64(4.5), Fixed::from_f64(-10.0));
2118 nop_filter.line_to(sx, sy);
2120 nop_filter.close();
2121 assert_eq!(
2122 commands.0,
2123 [
2124 Command::MoveTo(sx, sy),
2125 Command::CurveTo(
2126 Fixed::from_f64(5.0),
2127 Fixed::from_f64(-5.0),
2128 Fixed::from_f64(1.5),
2129 Fixed::from_f64(2.0),
2130 Fixed::from_f64(4.5),
2131 Fixed::from_f64(-10.0),
2132 ),
2133 Command::LineTo(sx, sy),
2134 ]
2135 )
2136 }
2137
2138 #[test]
2139 fn scaled_matrix_transform_sink() {
2140 let input = [(150i32, 46i32), (176, 8), (217, -13), (267, -13)]
2143 .map(|(x, y)| (Fixed::from_bits(x << 16), Fixed::from_bits(y << 16)));
2144 let expected = [(404, 118i32), (453, 20), (550, -33), (678, -33)]
2145 .map(|(x, y)| (Fixed::from_bits(x << 10), Fixed::from_bits(y << 10)));
2146 let mut dummy = ();
2147 let sink =
2148 TransformSink::from_matrix_scale(&mut dummy, TRANSFORM, Some(Fixed::from_bits(167772)));
2149 let transformed = input.map(|(x, y)| sink.transform(x, y));
2150 assert_eq!(transformed, expected);
2151 }
2152
2153 #[test]
2154 fn unscaled_matrix_transform_sink() {
2155 let input = [(150i32, 46i32), (176, 8), (217, -13), (267, -13)]
2158 .map(|(x, y)| (Fixed::from_bits(x << 16), Fixed::from_bits(y << 16)));
2159 let expected = [(158, 46i32), (177, 8), (215, -13), (265, -13)]
2160 .map(|(x, y)| (Fixed::from_bits(x << 16), Fixed::from_bits(y << 16)));
2161 let mut dummy = ();
2162 let sink = TransformSink::from_matrix_scale(&mut dummy, TRANSFORM, None);
2163 let transformed = input.map(|(x, y)| sink.transform(x, y));
2164 assert_eq!(transformed, expected);
2165 }
2166
2167 const TRANSFORM: FontMatrix = FontMatrix::from_elements([
2168 Fixed::ONE,
2169 Fixed::ZERO,
2170 Fixed::from_bits(10945),
2172 Fixed::ONE,
2173 Fixed::ZERO,
2174 Fixed::ZERO,
2175 ]);
2176
2177 #[test]
2178 fn unscaled_transform_sink_produces_integers() {
2179 let nothing = &mut ();
2180 let sink = TransformSink::new(nothing, Transform::default());
2181 for coord in [50.0, 50.1, 50.125, 50.5, 50.9] {
2182 assert_eq!(
2183 sink.transform(Fixed::from_f64(coord), Fixed::ZERO)
2184 .0
2185 .to_f32(),
2186 50.0
2187 );
2188 }
2189 }
2190
2191 #[test]
2192 fn scaled_transform_sink() {
2193 let ppem = 20.0;
2194 let upem = 1000.0;
2195 let scale = Fixed::from_bits((ppem * 64.) as i32) / Fixed::from_bits(upem as i32);
2197 let nothing = &mut ();
2198 let sink = TransformSink::from_matrix_scale(nothing, FontMatrix::IDENTITY, Some(scale));
2199 let inputs = [
2200 (0.0, 0.0),
2202 (8.0, 0.15625),
2203 (16.0, 0.3125),
2204 (32.0, 0.640625),
2205 (72.0, 1.4375),
2206 (128.0, 2.5625),
2207 ];
2208 for (coord, expected) in inputs {
2209 assert_eq!(
2210 sink.transform(Fixed::from_f64(coord), Fixed::ZERO)
2211 .0
2212 .to_f32(),
2213 expected,
2214 "scaling coord {coord}"
2215 );
2216 }
2217 }
2218
2219 #[test]
2220 fn mm_blend() {
2221 let mut commands = CaptureCommandSink::default();
2222 let ctx = MmContext([0.0, -0.25, 1.0].map(Fixed::from_f64));
2223 let mut eval = Evaluator::new(&ctx, None, &mut commands);
2224 let mut cursor = FontData::new(&[]).cursor();
2225 for i in [[1, 0], [2, 3], [4, -8], [6, 15]].into_iter().flatten() {
2229 eval.stack.push(i).unwrap();
2230 }
2231 eval.evaluate_operator(Operator::CallOtherSubr, &mut cursor, 0)
2232 .unwrap();
2233 let [a, b] = eval.stack.fixed_array(0).unwrap();
2234 assert_eq!(a.to_f32(), 3.5);
2236 assert_eq!(b.to_f32(), -9.0);
2238 }
2239
2240 struct MmContext([Fixed; 3]);
2241
2242 impl CharstringContext for MmContext {
2243 fn kind(&self) -> CharstringKind {
2244 CharstringKind::Type1
2245 }
2246
2247 fn seac_components(&self, base_code: i32, _accent_code: i32) -> Result<[&[u8]; 2], Error> {
2248 Err(Error::InvalidSeacCode(base_code))
2249 }
2250
2251 fn global_subr(&self, _index: i32) -> Result<&[u8], Error> {
2252 Err(Error::MissingSubroutines)
2253 }
2254
2255 fn subr(&self, _index: i32) -> Result<&[u8], Error> {
2256 Err(Error::MissingSubroutines)
2257 }
2258
2259 fn weight_vector(&self) -> &[Fixed] {
2260 &self.0
2261 }
2262 }
2263}