1use crate::model::Error;
4use crate::{
5 model::glyph::outline::PathSink,
6 ps::{
7 cff::{blend::BlendState, charset::Charset, index::Index, stack::Stack},
8 num,
9 string::Sid,
10 transform::{FontMatrix, Transform},
11 },
12 tables::cff::Cff,
13 types::{BoundingBox, Fixed, Point},
14 Cursor, FontData, FontRead,
15};
16
17pub const NESTING_DEPTH_LIMIT: u32 = 10;
22
23const MAX_OPERATIONS: u32 = 1_000_000;
33
34const STORAGE_SIZE: usize = 32;
38
39const INLINE_BUILD_CHAR_LEN: usize = 32;
42
43#[derive(Copy, Clone, PartialEq, Eq, Debug)]
45pub enum CharstringKind {
46 Type1,
50 Type2,
54}
55
56pub trait CharstringContext {
58 fn kind(&self) -> CharstringKind;
60
61 fn seac_components(&self, base_code: i32, accent_code: i32) -> Result<[&[u8]; 2], Error>;
64
65 fn global_subr(&self, index: i32) -> Result<&[u8], Error>;
68
69 fn subr(&self, index: i32) -> Result<&[u8], Error>;
72
73 fn weight_vector(&self) -> &[Fixed] {
75 &[]
76 }
77
78 fn build_char_len(&self) -> usize {
81 0
82 }
83}
84
85impl<'a> CharstringContext for (&'a [u8], &'a Index<'a>, &'a Index<'a>, &'a Index<'a>) {
90 fn kind(&self) -> CharstringKind {
91 CharstringKind::Type2
92 }
93
94 fn seac_components(&self, base_code: i32, accent_code: i32) -> Result<[&[u8]; 2], Error> {
95 let cff = Cff::read(FontData::new(self.0))?;
96 let charset = cff
97 .charset(0)
98 .or_else(|| Charset::new(FontData::default(), 0, self.1.count()))
99 .ok_or(Error::MissingResource)?;
100 let seac_to_gid = |code: i32| {
101 let code: u8 = code.try_into().ok()?;
102 let sid = *super::encoding::STANDARD_ENCODING.get(code as usize)?;
103 charset.glyph_id(Sid::new(sid as u16))
104 };
105 let accent_gid = seac_to_gid(accent_code).ok_or(Error::InvalidOperation)?;
106 let base_gid = seac_to_gid(base_code).ok_or(Error::InvalidOperation)?;
107 let accent_charstring = self
108 .1
109 .get(accent_gid.to_u32() as usize)
110 .ok_or(Error::Malformed)?;
111 let base_charstring = self
112 .1
113 .get(base_gid.to_u32() as usize)
114 .ok_or(Error::Malformed)?;
115 Ok([base_charstring, accent_charstring])
116 }
117
118 fn global_subr(&self, index: i32) -> Result<&[u8], Error> {
119 self.2
120 .get((index + self.2.subr_bias()) as usize)
121 .ok_or(Error::Malformed)
122 }
123
124 fn subr(&self, index: i32) -> Result<&[u8], Error> {
125 self.3
126 .get((index + self.3.subr_bias()) as usize)
127 .ok_or(Error::Malformed)
128 }
129}
130
131#[allow(unused_variables)]
141pub trait CommandSink {
142 fn move_to(&mut self, x: Fixed, y: Fixed);
144 fn line_to(&mut self, x: Fixed, y: Fixed);
145 fn curve_to(&mut self, cx0: Fixed, cy0: Fixed, cx1: Fixed, cy1: Fixed, x: Fixed, y: Fixed);
146 fn close(&mut self);
147 fn hstem(&mut self, y: Fixed, dy: Fixed) {}
150 fn vstem(&mut self, x: Fixed, dx: Fixed) {}
152 fn hint_mask(&mut self, mask: &[u8]) {}
155 fn counter_mask(&mut self, mask: &[u8]) {}
158 fn clear_hints(&mut self) {}
160 fn finish(&mut self) {}
162}
163
164pub struct NullSink;
166
167impl CommandSink for NullSink {
168 fn move_to(&mut self, _x: Fixed, _y: Fixed) {}
169 fn line_to(&mut self, _x: Fixed, _y: Fixed) {}
170 fn curve_to(
171 &mut self,
172 _cx0: Fixed,
173 _cy0: Fixed,
174 _cx1: Fixed,
175 _cy1: Fixed,
176 _x: Fixed,
177 _y: Fixed,
178 ) {
179 }
180 fn close(&mut self) {}
181}
182
183#[derive(Clone, Default, Debug)]
197pub struct ControlBoundsSink {
198 bounds: Option<BoundingBox<Fixed>>,
199}
200
201impl ControlBoundsSink {
202 pub fn new() -> Self {
204 Self::default()
205 }
206
207 pub fn bounding_box(&self) -> Option<BoundingBox<Fixed>> {
209 self.bounds
210 }
211
212 fn update_bounds(&mut self, x: Fixed, y: Fixed) {
213 self.bounds = Some(match self.bounds {
214 Some(b) => BoundingBox {
215 x_min: b.x_min.min(x),
216 y_min: b.y_min.min(y),
217 x_max: b.x_max.max(x),
218 y_max: b.y_max.max(y),
219 },
220 None => BoundingBox {
221 x_min: x,
222 y_min: y,
223 x_max: x,
224 y_max: y,
225 },
226 });
227 }
228}
229
230impl CommandSink for ControlBoundsSink {
231 fn move_to(&mut self, x: Fixed, y: Fixed) {
232 self.update_bounds(x, y);
233 }
234
235 fn line_to(&mut self, x: Fixed, y: Fixed) {
236 self.update_bounds(x, y);
237 }
238
239 fn curve_to(&mut self, cx0: Fixed, cy0: Fixed, cx1: Fixed, cy1: Fixed, x: Fixed, y: Fixed) {
240 self.update_bounds(cx0, cy0);
241 self.update_bounds(cx1, cy1);
242 self.update_bounds(x, y);
243 }
244
245 fn close(&mut self) {}
246}
247
248pub fn evaluate<'a>(
261 context: &'a impl CharstringContext,
262 blend_state: Option<BlendState<'a>>,
263 charstring_data: &[u8],
264 sink: &'a mut impl CommandSink,
265) -> Result<Option<Fixed>, Error> {
266 let mut evaluator = Evaluator::new(context, blend_state, sink);
267 evaluator.evaluate(charstring_data)?;
268 let width = evaluator.have_read_width.then_some(evaluator.wx);
269 sink.finish();
270 Ok(width)
271}
272
273pub fn evaluate_width<'a>(
285 context: &'a impl CharstringContext,
286 blend_state: Option<BlendState<'a>>,
287 charstring_data: &[u8],
288) -> Result<Option<Fixed>, Error> {
289 let mut sink = NullSink;
290 let mut evaluator = Evaluator::new(context, blend_state, &mut sink);
291 evaluator.width_only = true;
292 evaluator.evaluate(charstring_data)?;
295 Ok(evaluator.have_read_width.then_some(evaluator.wx))
296}
297
298fn fixed_sqrt(value: Fixed) -> Fixed {
305 if value.to_bits() <= 0 {
306 return Fixed::ZERO;
307 }
308 let mut root = if value.to_bits() < 10 {
310 value
311 } else {
312 Fixed::from_bits(value.to_bits() >> 1)
313 };
314 loop {
316 let next = Fixed::from_bits((root.to_bits() + (value / root).to_bits() + 1) >> 1);
317 if next == root {
318 return next;
319 }
320 root = next;
321 }
322}
323
324#[derive(PartialEq)]
326enum SeacMode {
327 Explicit,
329 Implicit,
332}
333
334struct Evaluator<'a> {
337 context: &'a dyn CharstringContext,
338 is_type1: bool,
339 blend_state: Option<BlendState<'a>>,
340 sink: &'a mut dyn CommandSink,
341 is_open: bool,
342 is_flexing: bool,
346 seen_width_command: bool,
348 width_only: bool,
350 have_read_width: bool,
352 stem_count: usize,
353 x: Fixed,
354 y: Fixed,
355 sbx: Fixed,
357 wx: Fixed,
359 stack: Stack,
360 stack_ix: usize,
361 in_seac: bool,
362 ops_done: u32,
364 storage: [Fixed; STORAGE_SIZE],
366 build_char: smallvec::SmallVec<[Fixed; INLINE_BUILD_CHAR_LEN]>,
368}
369
370impl<'a> Evaluator<'a> {
371 fn new(
372 context: &'a dyn CharstringContext,
373 blend_state: Option<BlendState<'a>>,
374 sink: &'a mut dyn CommandSink,
375 ) -> Self {
376 let is_type1 = context.kind() == CharstringKind::Type1;
377 Self {
378 context,
379 is_type1,
380 blend_state,
381 sink,
382 is_open: false,
383 is_flexing: false,
384 seen_width_command: false,
385 width_only: false,
386 have_read_width: false,
387 stem_count: 0,
388 stack: Stack::new(),
389 x: Fixed::ZERO,
390 y: Fixed::ZERO,
391 sbx: Fixed::ZERO,
392 wx: Fixed::ZERO,
393 stack_ix: 0,
394 in_seac: false,
395 ops_done: 0,
396 storage: [Fixed::ZERO; STORAGE_SIZE],
397 build_char: smallvec::SmallVec::new(),
398 }
399 }
400
401 fn evaluate(&mut self, charstring_data: &[u8]) -> Result<(), Error> {
402 let seen_endchar = self.evaluate_impl(charstring_data, 0)?;
403 if !self.is_type1 && !seen_endchar {
404 self.evaluate_operator(
407 Operator::EndChar,
408 &mut crate::FontData::default().cursor(),
409 0,
410 )?;
411 }
412 if self.is_open {
413 self.sink.close();
414 }
415 Ok(())
416 }
417
418 fn evaluate_impl(&mut self, charstring_data: &[u8], nesting_depth: u32) -> Result<bool, Error> {
419 if nesting_depth > NESTING_DEPTH_LIMIT {
420 return Err(Error::LimitExceeded);
421 }
422 let mut cursor = crate::FontData::new(charstring_data).cursor();
423 let mut seen_endchar = false;
424 while cursor.remaining_bytes() != 0 {
425 self.ops_done += 1;
426 if self.ops_done > MAX_OPERATIONS {
427 return Err(Error::LimitExceeded);
428 }
429 let b0 = cursor.read::<u8>()?;
430 match b0 {
431 28 | 32..=254 => {
435 self.stack.push(num::parse_int(&mut cursor, b0)?)?;
436 }
437 255 => {
439 let val = cursor.read::<i32>()?;
440 if self.is_type1 {
441 self.stack.push(val)?;
443 } else {
444 self.stack.push(Fixed::from_bits(val))?;
447 }
448 }
449 _ => {
450 if let Some(operator) = Operator::read(&mut cursor, b0) {
454 seen_endchar |= operator == Operator::EndChar;
455 if !self.evaluate_operator(operator, &mut cursor, nesting_depth)? {
456 break;
457 }
458 if self.width_only && self.seen_width_command {
462 break;
463 }
464 } else {
465 self.reset_stack();
467 }
468 }
469 }
470 }
471 Ok(seen_endchar)
472 }
473
474 fn evaluate_operator(
478 &mut self,
479 operator: Operator,
480 cursor: &mut Cursor,
481 nesting_depth: u32,
482 ) -> Result<bool, Error> {
483 use Operator::*;
484 use PointMode::*;
485 match operator {
486 Flex => {
496 self.emit_curves([DxDy; 6])?;
497 self.reset_stack();
498 }
499 HFlex => {
501 self.emit_curves([DxY, DxDy, DxY, DxY, DxInitialY, DxY])?;
502 self.reset_stack();
503 }
504 HFlex1 => {
506 self.emit_curves([DxDy, DxDy, DxY, DxY, DxDy, DxInitialY])?;
507 self.reset_stack();
508 }
509 Flex1 => {
511 self.emit_curves([DxDy, DxDy, DxDy, DxDy, DxDy, DLargerCoordDist])?;
512 self.reset_stack();
513 }
514 VariationStoreIndex => {
517 if !self.is_type1 {
518 let blend_state = self.blend_state.as_mut().ok_or(Error::MissingResource)?;
519 let store_index = self.stack.pop_i32()? as u16;
520 blend_state.set_store_index(store_index)?;
521 }
522 }
523 Blend => {
526 if !self.is_type1 {
527 let blend_state = self.blend_state.as_ref().ok_or(Error::MissingResource)?;
528 self.stack.apply_blend(blend_state)?;
529 }
530 }
531 Return => {
534 return Ok(false);
535 }
536 EndChar => {
540 let stack_len = self.stack.len();
541 if (stack_len == 1 || stack_len == 5) && !self.seen_width_command {
542 self.read_width()?;
543 }
544 self.seen_width_command = true;
545 if stack_len > 1 && !self.width_only {
546 self.handle_seac(SeacMode::Implicit, nesting_depth)?;
547 }
548 return Ok(false);
549 }
550 HStem | VStem | HStemHm | VStemHm => {
554 let mut i = 0;
555 let len = if self.stack.len_is_odd() && !self.seen_width_command {
556 self.read_width()?;
557 i = 1;
558 self.stack.len() - 1
559 } else {
560 self.stack.len()
561 };
562 self.seen_width_command = true;
563 let is_horizontal = matches!(operator, HStem | HStemHm);
564 let mut u = Fixed::ZERO;
565 while i < self.stack.len() {
566 let args = self.stack.fixed_array::<2>(i)?;
567 u += args[0];
568 let w = args[1];
569 let v = u.wrapping_add(w);
570 if is_horizontal {
571 self.sink.hstem(u, v);
572 } else {
573 self.sink.vstem(u, v);
574 }
575 u = v;
576 i += 2;
577 }
578 self.stem_count += len / 2;
579 self.reset_stack();
580 }
581 HintMask | CntrMask => {
589 let mut i = 0;
590 let len = if self.stack.len_is_odd() && !self.seen_width_command {
591 self.read_width()?;
592 i = 1;
593 self.stack.len() - 1
594 } else {
595 self.stack.len()
596 };
597 self.seen_width_command = true;
598 let mut u = Fixed::ZERO;
599 while i < self.stack.len() {
600 let args = self.stack.fixed_array::<2>(i)?;
601 u += args[0];
602 let w = args[1];
603 let v = u + w;
604 self.sink.vstem(u, v);
605 u = v;
606 i += 2;
607 }
608 self.stem_count += len / 2;
609 let count = self.stem_count.div_ceil(8);
610 let mask = cursor.read_array::<u8>(count)?;
611 if operator == HintMask {
612 self.sink.hint_mask(mask);
613 } else {
614 self.sink.counter_mask(mask);
615 }
616 self.reset_stack();
617 }
618 RMoveTo => {
622 if self.stack.len() > 2 && !self.seen_width_command {
623 self.read_width()?;
624 }
625 self.seen_width_command = true;
626 if !self.is_flexing {
627 let dy = self.stack.pop_fixed()?;
628 let dx = self.stack.pop_fixed()?;
629 self.x += dx;
630 self.y += dy;
631 if !self.is_open {
632 self.is_open = true;
633 } else {
634 self.sink.close();
635 }
636 self.sink.move_to(self.x, self.y);
637 self.reset_stack();
638 }
639 }
640 HMoveTo | VMoveTo => {
645 if self.stack.len() > 1 && !self.seen_width_command {
646 self.read_width()?;
647 }
648 self.seen_width_command = true;
649 if self.is_flexing {
650 self.stack.push(0)?;
653 if operator == VMoveTo {
654 self.stack.exch()?;
657 }
658 } else {
659 let delta = self.stack.pop_fixed()?;
660 if operator == HMoveTo {
661 self.x += delta;
662 } else {
663 self.y += delta;
664 }
665 if !self.is_open {
666 self.is_open = true;
667 } else {
668 self.sink.close();
669 }
670 self.sink.move_to(self.x, self.y);
671 self.reset_stack();
672 }
673 }
674 RLineTo => {
678 let mut i = 0;
679 while i < self.stack.len() {
680 let [dx, dy] = self.stack.fixed_array::<2>(i)?;
681 self.x += dx;
682 self.y += dy;
683 self.emit_line(self.x, self.y);
684 i += 2;
685 }
686 self.reset_stack();
687 }
688 HLineTo | VLineTo => {
693 let mut is_x = operator == HLineTo;
694 for i in 0..self.stack.len() {
695 let delta = self.stack.get_fixed(i)?;
696 if is_x {
697 self.x += delta;
698 } else {
699 self.y += delta;
700 }
701 is_x = !is_x;
702 self.emit_line(self.x, self.y);
703 }
704 self.reset_stack();
705 }
706 HhCurveTo => {
712 let count1 = self.stack.len();
713 let count = count1 & !2;
714 self.stack_ix = count1 - count;
715 while self.stack_ix < count {
716 if (count - self.stack_ix) & 1 != 0 {
717 self.y += self.stack.get_fixed(self.stack_ix)?;
718 self.stack_ix += 1;
719 }
720 self.emit_curves([DxY, DxDy, DxY])?;
721 }
722 self.reset_stack();
723 }
724 HvCurveTo | VhCurveTo => {
729 let count1 = self.stack.len();
730 let count = count1 & !2;
731 let mut is_horizontal = operator == HvCurveTo;
732 self.stack_ix = count1 - count;
733 while self.stack_ix < count {
734 let do_last_delta = count - self.stack_ix == 5;
735 if is_horizontal {
736 self.emit_curves([DxY, DxDy, MaybeDxDy(do_last_delta)])?;
737 } else {
738 self.emit_curves([XDy, DxDy, DxMaybeDy(do_last_delta)])?;
739 }
740 is_horizontal = !is_horizontal;
741 }
742 self.reset_stack();
743 }
744 RrCurveTo | RCurveLine => {
748 while self.coords_remaining() >= 6 {
749 self.emit_curves([DxDy; 3])?;
750 }
751 if operator == RCurveLine {
752 let [dx, dy] = self.stack.fixed_array::<2>(self.stack_ix)?;
753 self.x += dx;
754 self.y += dy;
755 self.emit_line(self.x, self.y);
756 }
757 self.reset_stack();
758 }
759 RLineCurve => {
763 while self.coords_remaining() > 6 {
764 let [dx, dy] = self.stack.fixed_array::<2>(self.stack_ix)?;
765 self.x += dx;
766 self.y += dy;
767 self.emit_line(self.x, self.y);
768 self.stack_ix += 2;
769 }
770 while self.coords_remaining() >= 6 {
771 self.emit_curves([DxDy; 3])?;
772 }
773 self.reset_stack();
774 }
775 VvCurveTo => {
781 let count1 = self.stack.len();
782 let count = count1 & !2;
783 self.stack_ix = count1 - count;
784 while self.stack_ix < count {
785 if (count - self.stack_ix) & 1 != 0 {
786 self.x += self.stack.get_fixed(self.stack_ix)?;
787 self.stack_ix += 1;
788 }
789 self.emit_curves([XDy, DxDy, XDy])?;
790 }
791 self.reset_stack();
792 }
793 CallSubr | CallGsubr => {
797 let index = self.stack.pop_i32()?;
798 let subr_charstring = if operator == CallSubr {
799 self.context.subr(index)?
800 } else {
801 self.context.global_subr(index)?
802 };
803 self.evaluate_impl(subr_charstring, nesting_depth + 1)?;
804 }
805 Hsbw => {
811 if self.is_type1 {
812 let [sbx, wx] = self.stack.fixed_array(0)?;
813 self.sbx += sbx;
814 self.x += sbx;
815 self.wx = wx;
816 self.seen_width_command = true;
817 self.have_read_width = true;
818 self.reset_stack();
819 }
820 }
821 Seac => {
827 if !self.width_only {
828 self.handle_seac(SeacMode::Explicit, nesting_depth)?;
829 }
830 }
831 Sbw => {
837 if self.is_type1 {
838 let [x, y, wx, _wy] = self.stack.fixed_array(0)?;
839 self.x += x;
840 self.y += y;
841 self.sbx += x;
842 self.wx = wx;
843 self.seen_width_command = true;
844 self.have_read_width = true;
845 self.reset_stack();
846 }
847 }
848 DotSection => {
852 }
854 HStem3 | VStem3 => {
858 self.reset_stack();
860 }
861 Div => {
865 self.stack.div(self.is_type1)?;
866 }
867 And | Or | Eq => {
877 let b = self.stack.pop_fixed()?;
878 let a = self.stack.pop_fixed()?;
879 let answer = match operator {
881 And => a != Fixed::ZERO && b != Fixed::ZERO,
882 Or => a != Fixed::ZERO || b != Fixed::ZERO,
883 _ => a == b,
884 };
885 self.stack.push(answer as i32)?;
886 }
887 Not => {
888 let a = self.stack.pop_fixed()?;
889 self.stack.push((a == Fixed::ZERO) as i32)?;
890 }
891 Abs | Neg => {
892 let a = self.stack.pop_fixed()?;
893 let answer = if a.to_bits() < -Fixed::MAX.to_bits() {
896 Fixed::MAX
897 } else if operator == Abs {
898 Fixed::from_bits(a.to_bits().abs())
899 } else {
900 Fixed::from_bits(-a.to_bits())
901 };
902 self.stack.push(answer)?;
903 }
904 Add | Sub => {
905 let b = self.stack.pop_fixed()?;
906 let a = self.stack.pop_fixed()?;
907 let answer = if operator == Add {
909 a.to_bits().wrapping_add(b.to_bits())
910 } else {
911 a.to_bits().wrapping_sub(b.to_bits())
912 };
913 self.stack.push(Fixed::from_bits(answer))?;
914 }
915 Mul => {
916 let b = self.stack.pop_fixed()?;
917 let a = self.stack.pop_fixed()?;
918 self.stack.push(a * b)?;
919 }
920 Sqrt => {
921 let a = self.stack.pop_fixed()?;
922 self.stack.push(fixed_sqrt(a))?;
923 }
924 Drop => {
925 self.stack.pop_fixed()?;
926 }
927 Dup => {
928 let a = self.stack.pop_fixed()?;
929 self.stack.push(a)?;
930 self.stack.push(a)?;
931 }
932 Exch => {
933 self.stack.exch()?;
934 }
935 Index => {
936 let index = self.stack.pop_i32()?;
937 let len = self.stack.len();
938 if len > 0 {
939 let from_bottom = if index < 0 {
942 len - 1
943 } else if index as usize >= len {
944 0
945 } else {
946 len - 1 - index as usize
947 };
948 let value = self.stack.get_fixed(from_bottom)?;
949 self.stack.push(value)?;
950 }
951 }
952 Roll => {
953 let shift = self.stack.pop_i32()?;
954 let count = self.stack.pop_i32()?;
955 self.stack.roll(count, shift)?;
956 }
957 Put => {
958 let index = self.stack.pop_i32()?;
959 let value = self.stack.pop_fixed()?;
960 if let Some(slot) = usize::try_from(index)
962 .ok()
963 .and_then(|i| self.storage.get_mut(i))
964 {
965 *slot = value;
966 }
967 }
968 Get => {
969 let index = self.stack.pop_i32()?;
970 if let Some(value) = usize::try_from(index)
973 .ok()
974 .and_then(|i| self.storage.get(i))
975 {
976 self.stack.push(*value)?;
977 }
978 }
979 IfElse => {
980 let cond2 = self.stack.pop_fixed()?;
981 let cond1 = self.stack.pop_fixed()?;
982 let arg2 = self.stack.pop_fixed()?;
983 let arg1 = self.stack.pop_fixed()?;
984 self.stack.push(if cond1 <= cond2 { arg1 } else { arg2 })?;
985 }
986 CallOtherSubr => {
990 let subr_idx = self.stack.pop_i32()?;
991 let num_args = self.stack.pop_i32()? as usize;
992 let weight_vector = self.context.weight_vector();
993 match (subr_idx, num_args) {
994 (0, 3) => {
997 self.is_flexing = false;
998 self.ensure_open();
999 self.handle_flex()?;
1000 }
1001 (1, 0) => {
1003 self.is_flexing = true;
1004 }
1005 (12 | 13, _) => {
1008 self.reset_stack();
1009 }
1010 (14..=18, _) => {
1013 if weight_vector.is_empty() {
1016 return Err(Error::InvalidOperation);
1017 }
1018 self.handle_mm_blend(subr_idx, num_args)?;
1019 }
1020 (19..=25 | 27, _) => {
1021 self.handle_build_char(subr_idx, num_args)?;
1022 }
1023 _ => {
1024 self.stack.drop(num_args);
1027 }
1028 }
1029 }
1030 Pop => {
1036 }
1038 SetCurrentPoint => {
1042 if self.is_type1 {
1043 let [x, y] = self.stack.fixed_array(0)?;
1044 self.x = x;
1045 self.y = y;
1046 self.reset_stack();
1047 }
1048 }
1049 }
1050 Ok(true)
1051 }
1052
1053 fn read_width(&mut self) -> Result<(), Error> {
1054 self.wx = self.stack.get_fixed(0)?;
1055 self.seen_width_command = true;
1056 self.have_read_width = true;
1057 Ok(())
1058 }
1059
1060 fn handle_seac(&mut self, mode: SeacMode, nesting_depth: u32) -> Result<(), Error> {
1062 if self.in_seac {
1064 return Err(Error::LimitExceeded);
1065 }
1066 self.in_seac = true;
1067 let accent_code = self.stack.pop_i32()?;
1068 let base_code = self.stack.pop_i32()?;
1069 let [base_charstring, accent_charstring] =
1070 self.context.seac_components(base_code, accent_code)?;
1071 let dy = self.stack.pop_fixed()?;
1072 let dx = self.stack.pop_fixed()?;
1073 let sb = if self.is_type1 {
1074 self.stack.pop_fixed()?
1076 } else if !self.stack.is_empty() && !self.seen_width_command {
1077 self.wx = self.stack.pop_fixed()?;
1078 self.seen_width_command = true;
1079 Fixed::ZERO
1080 } else {
1081 Fixed::ZERO
1082 };
1083 let mut sbx = self.sbx;
1085 let mut wx = self.wx;
1086 let seen_width = self.seen_width_command;
1087 let read_width = self.have_read_width;
1088 struct Component<'a> {
1089 charstring: &'a [u8],
1090 x: Fixed,
1091 y: Fixed,
1092 maybe_use_metrics: bool,
1095 }
1096 let x = self.x;
1097 let y = self.y;
1098 let [bx, by] = if mode == SeacMode::Explicit {
1100 [Fixed::ZERO; 2]
1101 } else {
1102 [x, y]
1103 };
1104 let mut components = [
1105 Component {
1106 charstring: base_charstring,
1107 x: bx,
1108 y: by,
1109 maybe_use_metrics: mode == SeacMode::Explicit,
1112 },
1113 Component {
1114 charstring: accent_charstring,
1115 x: dx + self.sbx - sb,
1118 y: dy,
1119 maybe_use_metrics: false,
1120 },
1121 ];
1122 if mode == SeacMode::Implicit {
1125 components.swap(0, 1);
1126 }
1127 for component in components {
1135 self.reset_stack();
1136 self.seen_width_command = false;
1137 self.sink.clear_hints();
1138 self.stem_count = 0;
1139 self.x = component.x;
1140 self.y = component.y;
1141 self.evaluate_impl(component.charstring, nesting_depth + 1)?;
1142 if component.maybe_use_metrics && !seen_width {
1143 sbx = self.sbx;
1144 wx = self.wx;
1145 }
1146 }
1147 self.seen_width_command = seen_width;
1148 self.have_read_width = read_width;
1149 self.sbx = sbx;
1150 self.wx = wx;
1151 self.in_seac = false;
1152 Ok(())
1153 }
1154
1155 fn handle_flex(&mut self) -> Result<(), Error> {
1157 let final_y = self.stack.pop_fixed()?;
1162 let final_x = self.stack.pop_fixed()?;
1163 let _ = self.stack.pop_fixed()?;
1165 let p3y = self.stack.pop_fixed()?;
1166 let p3x = self.stack.pop_fixed()?;
1167 let bcp4y = self.stack.pop_fixed()?;
1168 let bcp4x = self.stack.pop_fixed()?;
1169 let bcp3y = self.stack.pop_fixed()?;
1170 let bcp3x = self.stack.pop_fixed()?;
1171 let p2y = self.stack.pop_fixed()?;
1172 let p2x = self.stack.pop_fixed()?;
1173 let bcp2y = self.stack.pop_fixed()?;
1174 let bcp2x = self.stack.pop_fixed()?;
1175 let bcp1y = self.stack.pop_fixed()?;
1176 let bcp1x = self.stack.pop_fixed()?;
1177 let rpy = self.stack.pop_fixed()?;
1178 let rpx = self.stack.pop_fixed()?;
1179 self.reset_stack();
1180 self.stack.push(bcp1x + rpx)?;
1181 self.stack.push(bcp1y + rpy)?;
1182 self.stack.push(bcp2x)?;
1183 self.stack.push(bcp2y)?;
1184 self.stack.push(p2x)?;
1185 self.stack.push(p2y)?;
1186 self.emit_curves([PointMode::DxDy; 3])?;
1187 self.reset_stack();
1188 self.stack.push(bcp3x)?;
1189 self.stack.push(bcp3y)?;
1190 self.stack.push(bcp4x)?;
1191 self.stack.push(bcp4y)?;
1192 self.stack.push(p3x)?;
1193 self.stack.push(p3y)?;
1194 self.emit_curves([PointMode::DxDy; 3])?;
1195 self.reset_stack();
1196 self.stack.push(final_x)?;
1198 self.stack.push(final_y)?;
1199 Ok(())
1200 }
1201
1202 fn handle_mm_blend(&mut self, subr_idx: i32, num_args: usize) -> Result<(), Error> {
1206 let weight_vector = self.context.weight_vector();
1207 let num_points = (subr_idx - 13) as usize + (subr_idx == 18) as usize;
1208 if num_args != num_points * weight_vector.len() {
1209 return Err(Error::Malformed);
1210 }
1211 let stack_base = self
1220 .stack
1221 .len()
1222 .checked_sub(num_args)
1223 .ok_or(Error::InvalidOperation)?;
1224 let mut delta_idx = stack_base + num_points;
1225 for i in 0..num_points {
1226 let mut val = self.stack.get_fixed(stack_base + i)?;
1227 for &weight in &weight_vector[1..] {
1228 val += self.stack.get_fixed(delta_idx)? * weight;
1229 delta_idx += 1;
1230 }
1231 self.stack.set(stack_base + i, val)?;
1232 }
1233 self.stack.drop(num_args.saturating_sub(num_points));
1234 Ok(())
1235 }
1236
1237 fn handle_build_char(&mut self, subr_idx: i32, num_args: usize) -> Result<(), Error> {
1251 let weights = self.context.weight_vector();
1252 let has_blend = !weights.is_empty();
1253 let len = self.context.build_char_len();
1254 match (subr_idx, num_args) {
1255 (19, 1) if has_blend => {
1258 let idx = self.stack.pop_i32()? as u32 as usize;
1259 if len < weights.len() || len - weights.len() < idx {
1260 return Err(Error::InvalidOperation);
1261 }
1262 self.build_char(len)[idx..idx + weights.len()].copy_from_slice(weights);
1263 }
1264 (20..=23, 2) => {
1266 let b = self.stack.pop_fixed()?;
1267 let a = self.stack.pop_fixed()?;
1268 let result = match subr_idx {
1269 20 => Fixed::from_bits(a.to_bits().wrapping_add(b.to_bits())),
1270 21 => Fixed::from_bits(a.to_bits().wrapping_sub(b.to_bits())),
1271 22 => a * b,
1272 _ if b == Fixed::ZERO => return Err(Error::InvalidOperation),
1273 _ => a / b,
1274 };
1275 self.stack.push(result)?;
1276 }
1277 (24, 2) if has_blend => {
1279 let idx = self.stack.pop_i32()? as u32 as usize;
1280 if idx >= len {
1281 return Err(Error::InvalidOperation);
1282 }
1283 let value = self.stack.pop_fixed()?;
1284 self.build_char(len)[idx] = value;
1285 }
1286 (25, 1) if has_blend => {
1288 let idx = self.stack.pop_i32()? as u32 as usize;
1289 if idx >= len {
1290 return Err(Error::InvalidOperation);
1291 }
1292 let value = self.build_char(len)[idx];
1293 self.stack.push(value)?;
1294 }
1295 (27, 4) => {
1298 let d = self.stack.pop_fixed()?;
1299 let c = self.stack.pop_fixed()?;
1300 let b = self.stack.pop_fixed()?;
1301 let a = self.stack.pop_fixed()?;
1302 self.stack.push(if c <= d { a } else { b })?;
1303 }
1304 _ => return Err(Error::InvalidOperation),
1305 }
1306 Ok(())
1307 }
1308
1309 fn build_char(&mut self, len: usize) -> &mut [Fixed] {
1312 if self.build_char.len() != len {
1313 self.build_char.resize(len, Fixed::ZERO);
1314 }
1315 &mut self.build_char
1316 }
1317
1318 fn coords_remaining(&self) -> usize {
1319 self.stack.len().saturating_sub(self.stack_ix)
1323 }
1324
1325 fn ensure_open(&mut self) {
1326 if !self.is_open {
1327 self.sink.move_to(Fixed::ZERO, Fixed::ZERO);
1328 self.is_open = true;
1329 }
1330 }
1331
1332 fn emit_line(&mut self, x: Fixed, y: Fixed) {
1333 self.ensure_open();
1334 self.sink.line_to(x, y);
1335 }
1336
1337 fn emit_curves<const N: usize>(&mut self, modes: [PointMode; N]) -> Result<(), Error> {
1338 use PointMode::*;
1339 let initial_x = self.x;
1340 let initial_y = self.y;
1341 let mut count = 0;
1342 let mut points = [Point::default(); 2];
1343 self.ensure_open();
1344 for mode in modes {
1345 let stack_used = match mode {
1346 DxDy => {
1347 self.x += self.stack.get_fixed(self.stack_ix)?;
1348 self.y += self.stack.get_fixed(self.stack_ix + 1)?;
1349 2
1350 }
1351 XDy => {
1352 self.y += self.stack.get_fixed(self.stack_ix)?;
1353 1
1354 }
1355 DxY => {
1356 self.x += self.stack.get_fixed(self.stack_ix)?;
1357 1
1358 }
1359 DxInitialY => {
1360 self.x += self.stack.get_fixed(self.stack_ix)?;
1361 self.y = initial_y;
1362 1
1363 }
1364 DLargerCoordDist => {
1368 let delta = self.stack.get_fixed(self.stack_ix)?;
1369 if (self.x - initial_x).abs() > (self.y - initial_y).abs() {
1370 self.x += delta;
1371 self.y = initial_y;
1372 } else {
1373 self.y += delta;
1374 self.x = initial_x;
1375 }
1376 1
1377 }
1378 DxMaybeDy(do_dy) => {
1380 self.x += self.stack.get_fixed(self.stack_ix)?;
1381 if do_dy {
1382 self.y += self.stack.get_fixed(self.stack_ix + 1)?;
1383 2
1384 } else {
1385 1
1386 }
1387 }
1388 MaybeDxDy(do_dx) => {
1390 self.y += self.stack.get_fixed(self.stack_ix)?;
1391 if do_dx {
1392 self.x += self.stack.get_fixed(self.stack_ix + 1)?;
1393 2
1394 } else {
1395 1
1396 }
1397 }
1398 };
1399 self.stack_ix += stack_used;
1400 if count == 2 {
1401 self.sink.curve_to(
1402 points[0].x,
1403 points[0].y,
1404 points[1].x,
1405 points[1].y,
1406 self.x,
1407 self.y,
1408 );
1409 count = 0;
1410 } else {
1411 points[count] = Point::new(self.x, self.y);
1412 count += 1;
1413 }
1414 }
1415 Ok(())
1416 }
1417
1418 fn reset_stack(&mut self) {
1419 self.stack.clear();
1420 self.stack_ix = 0;
1421 }
1422}
1423
1424#[derive(Copy, Clone)]
1426enum PointMode {
1427 DxDy,
1428 XDy,
1429 DxY,
1430 DxInitialY,
1431 DLargerCoordDist,
1432 DxMaybeDy(bool),
1433 MaybeDxDy(bool),
1434}
1435
1436#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1442enum Operator {
1443 HStem,
1444 VStem,
1445 VMoveTo,
1446 RLineTo,
1447 HLineTo,
1448 VLineTo,
1449 RrCurveTo,
1450 CallSubr,
1451 Return,
1452 Hsbw,
1453 EndChar,
1454 VariationStoreIndex,
1455 Blend,
1456 HStemHm,
1457 HintMask,
1458 CntrMask,
1459 RMoveTo,
1460 HMoveTo,
1461 VStemHm,
1462 RCurveLine,
1463 RLineCurve,
1464 VvCurveTo,
1465 HhCurveTo,
1466 CallGsubr,
1467 VhCurveTo,
1468 HvCurveTo,
1469 DotSection,
1470 VStem3,
1471 HStem3,
1472 Seac,
1473 Sbw,
1474 Div,
1475 CallOtherSubr,
1476 Pop,
1477 SetCurrentPoint,
1478 HFlex,
1479 Flex,
1480 HFlex1,
1481 Flex1,
1482 And,
1483 Or,
1484 Not,
1485 Abs,
1486 Add,
1487 Sub,
1488 Neg,
1489 Eq,
1490 Drop,
1491 Put,
1492 Get,
1493 IfElse,
1494 Mul,
1495 Sqrt,
1496 Dup,
1497 Exch,
1498 Index,
1499 Roll,
1500}
1501
1502impl Operator {
1503 #[inline]
1504 fn read(cursor: &mut Cursor, b0: u8) -> Option<Self> {
1505 const ESCAPE: u8 = 12;
1507 if b0 == ESCAPE {
1508 Self::from_two_byte_opcode(cursor.read::<u8>().ok()?)
1509 } else {
1510 Self::from_opcode(b0)
1511 }
1512 }
1513
1514 fn from_opcode(opcode: u8) -> Option<Self> {
1516 use Operator::*;
1517 Some(match opcode {
1518 1 => HStem,
1519 3 => VStem,
1520 4 => VMoveTo,
1521 5 => RLineTo,
1522 6 => HLineTo,
1523 7 => VLineTo,
1524 8 => RrCurveTo,
1525 10 => CallSubr,
1526 11 => Return,
1527 13 => Hsbw,
1528 14 => EndChar,
1529 15 => VariationStoreIndex,
1530 16 => Blend,
1531 18 => HStemHm,
1532 19 => HintMask,
1533 20 => CntrMask,
1534 21 => RMoveTo,
1535 22 => HMoveTo,
1536 23 => VStemHm,
1537 24 => RCurveLine,
1538 25 => RLineCurve,
1539 26 => VvCurveTo,
1540 27 => HhCurveTo,
1541 29 => CallGsubr,
1542 30 => VhCurveTo,
1543 31 => HvCurveTo,
1544 _ => return None,
1545 })
1546 }
1547
1548 pub fn from_two_byte_opcode(opcode: u8) -> Option<Self> {
1552 use Operator::*;
1553 Some(match opcode {
1554 0 => DotSection,
1559 1 => VStem3,
1560 2 => HStem3,
1561 3 => And,
1562 4 => Or,
1563 5 => Not,
1564 6 => Seac,
1565 7 => Sbw,
1566 9 => Abs,
1567 10 => Add,
1568 11 => Sub,
1569 12 => Div,
1570 14 => Neg,
1571 15 => Eq,
1572 18 => Drop,
1573 20 => Put,
1574 21 => Get,
1575 22 => IfElse,
1576 24 => Mul,
1577 26 => Sqrt,
1578 27 => Dup,
1579 28 => Exch,
1580 29 => Index,
1581 30 => Roll,
1582 16 => CallOtherSubr,
1583 17 => Pop,
1584 33 => SetCurrentPoint,
1585 34 => HFlex,
1586 35 => Flex,
1587 36 => HFlex1,
1588 37 => Flex1,
1589 _ => return None,
1590 })
1591 }
1592}
1593
1594const ONE_OVER_64: Fixed = Fixed::from_bits(0x400);
1596
1597pub struct TransformSink<'a, S> {
1599 inner: &'a mut S,
1600 matrix: Option<FontMatrix>,
1601 scale: Option<Fixed>,
1602}
1603
1604impl<'a, S> TransformSink<'a, S> {
1605 pub fn new(sink: &'a mut S, transform: Transform) -> Self {
1607 Self::from_matrix_scale(sink, transform.matrix, transform.scale)
1608 }
1609
1610 pub fn from_matrix_scale(sink: &'a mut S, matrix: FontMatrix, scale: Option<Fixed>) -> Self {
1612 Self {
1613 inner: sink,
1614 matrix: (matrix != FontMatrix::IDENTITY).then_some(matrix),
1615 scale,
1616 }
1617 }
1618
1619 fn transform(&self, x: Fixed, y: Fixed) -> (Fixed, Fixed) {
1620 let ax = x * ONE_OVER_64;
1630 let ay = y * ONE_OVER_64;
1631 let bx = Fixed::from_bits(ax.to_bits() >> 10);
1635 let by = Fixed::from_bits(ay.to_bits() >> 10);
1636 let (cx, cy) = self
1638 .matrix
1639 .as_ref()
1640 .map(|mat| mat.transform(bx, by))
1641 .unwrap_or((bx, by));
1642 if let Some(scale) = self.scale {
1643 let dx = cx * scale;
1647 let dy = cy * scale;
1648 (
1650 Fixed::from_bits(dx.to_bits() << 10),
1651 Fixed::from_bits(dy.to_bits() << 10),
1652 )
1653 } else {
1654 (
1657 Fixed::from_bits(cx.to_bits() << 16),
1658 Fixed::from_bits(cy.to_bits() << 16),
1659 )
1660 }
1661 }
1662}
1663
1664impl<S: CommandSink> CommandSink for TransformSink<'_, S> {
1665 fn hstem(&mut self, y: Fixed, dy: Fixed) {
1666 self.inner.hstem(y, dy);
1667 }
1668
1669 fn vstem(&mut self, x: Fixed, dx: Fixed) {
1670 self.inner.vstem(x, dx);
1671 }
1672
1673 fn hint_mask(&mut self, mask: &[u8]) {
1674 self.inner.hint_mask(mask);
1675 }
1676
1677 fn counter_mask(&mut self, mask: &[u8]) {
1678 self.inner.counter_mask(mask);
1679 }
1680
1681 fn clear_hints(&mut self) {
1682 self.inner.clear_hints();
1683 }
1684
1685 fn move_to(&mut self, x: Fixed, y: Fixed) {
1686 let (x, y) = self.transform(x, y);
1687 self.inner.move_to(x, y);
1688 }
1689
1690 fn line_to(&mut self, x: Fixed, y: Fixed) {
1691 let (x, y) = self.transform(x, y);
1692 self.inner.line_to(x, y);
1693 }
1694
1695 fn curve_to(&mut self, cx1: Fixed, cy1: Fixed, cx2: Fixed, cy2: Fixed, x: Fixed, y: Fixed) {
1696 let (cx1, cy1) = self.transform(cx1, cy1);
1697 let (cx2, cy2) = self.transform(cx2, cy2);
1698 let (x, y) = self.transform(x, y);
1699 self.inner.curve_to(cx1, cy1, cx2, cy2, x, y);
1700 }
1701
1702 fn close(&mut self) {
1703 self.inner.close();
1704 }
1705
1706 fn finish(&mut self) {
1707 self.inner.finish();
1708 }
1709}
1710
1711#[derive(Copy, Clone)]
1712enum PendingElement {
1713 Move([Fixed; 2]),
1714 Line([Fixed; 2]),
1715 Curve([Fixed; 6]),
1716}
1717
1718impl PendingElement {
1719 fn target_point(&self) -> [Fixed; 2] {
1720 match self {
1721 Self::Move(xy) | Self::Line(xy) => *xy,
1722 Self::Curve([.., x, y]) => [*x, *y],
1723 }
1724 }
1725}
1726
1727pub struct NopFilterSink<'a, S> {
1736 is_open: bool,
1737 start: Option<(Fixed, Fixed)>,
1738 pending_element: Option<PendingElement>,
1739 inner: &'a mut S,
1740}
1741
1742impl<'a, S> NopFilterSink<'a, S>
1743where
1744 S: CommandSink,
1745{
1746 pub fn new(inner: &'a mut S) -> Self {
1749 Self {
1750 is_open: false,
1751 start: None,
1752 pending_element: None,
1753 inner,
1754 }
1755 }
1756
1757 fn flush_pending(&mut self, for_close: bool) {
1758 if let Some(pending) = self.pending_element.take() {
1759 match pending {
1760 PendingElement::Move([x, y]) => {
1761 if !for_close {
1762 self.is_open = true;
1763 self.inner.move_to(x, y);
1764 self.start = Some((x, y));
1765 }
1766 }
1767 PendingElement::Line([x, y]) => {
1768 if !for_close || self.start != Some((x, y)) {
1769 self.inner.line_to(x, y);
1770 }
1771 }
1772 PendingElement::Curve([cx0, cy0, cx1, cy1, x, y]) => {
1773 self.inner.curve_to(cx0, cy0, cx1, cy1, x, y);
1774 }
1775 }
1776 }
1777 }
1778}
1779
1780impl<S> CommandSink for NopFilterSink<'_, S>
1781where
1782 S: CommandSink,
1783{
1784 fn hstem(&mut self, y: Fixed, dy: Fixed) {
1785 self.inner.hstem(y, dy);
1786 }
1787
1788 fn vstem(&mut self, x: Fixed, dx: Fixed) {
1789 self.inner.vstem(x, dx);
1790 }
1791
1792 fn hint_mask(&mut self, mask: &[u8]) {
1793 self.inner.hint_mask(mask);
1794 }
1795
1796 fn counter_mask(&mut self, mask: &[u8]) {
1797 self.inner.counter_mask(mask);
1798 }
1799
1800 fn clear_hints(&mut self) {
1801 self.inner.clear_hints();
1802 }
1803
1804 fn move_to(&mut self, x: Fixed, y: Fixed) {
1805 self.pending_element = Some(PendingElement::Move([x, y]));
1806 }
1807
1808 fn line_to(&mut self, x: Fixed, y: Fixed) {
1809 if self
1811 .pending_element
1812 .map(|element| element.target_point() == [x, y])
1813 .unwrap_or_default()
1814 {
1815 return;
1816 }
1817 self.flush_pending(false);
1818 self.pending_element = Some(PendingElement::Line([x, y]));
1819 }
1820
1821 fn curve_to(&mut self, cx1: Fixed, cy1: Fixed, cx2: Fixed, cy2: Fixed, x: Fixed, y: Fixed) {
1822 self.flush_pending(false);
1823 self.pending_element = Some(PendingElement::Curve([cx1, cy1, cx2, cy2, x, y]));
1824 }
1825
1826 fn close(&mut self) {
1827 self.flush_pending(true);
1828 if self.is_open {
1829 self.inner.close();
1830 self.is_open = false;
1831 }
1832 }
1833
1834 fn finish(&mut self) {
1835 self.close();
1836 self.inner.finish();
1837 }
1838}
1839
1840impl<P: PathSink> CommandSink for P {
1841 fn move_to(&mut self, x: Fixed, y: Fixed) {
1842 self.move_to(x.to_f32(), y.to_f32());
1843 }
1844
1845 fn line_to(&mut self, x: Fixed, y: Fixed) {
1846 self.line_to(x.to_f32(), y.to_f32());
1847 }
1848
1849 fn curve_to(&mut self, cx0: Fixed, cy0: Fixed, cx1: Fixed, cy1: Fixed, x: Fixed, y: Fixed) {
1850 self.curve_to(
1851 cx0.to_f32(),
1852 cy0.to_f32(),
1853 cx1.to_f32(),
1854 cy1.to_f32(),
1855 x.to_f32(),
1856 y.to_f32(),
1857 );
1858 }
1859
1860 fn close(&mut self) {
1861 self.close()
1862 }
1863}
1864
1865#[cfg(test)]
1866pub(crate) mod test_helpers {
1867 use super::{CommandSink, Fixed};
1868
1869 #[derive(Copy, Clone, PartialEq, Debug)]
1870 #[allow(clippy::enum_variant_names)]
1871 pub enum Command {
1872 MoveTo(Fixed, Fixed),
1873 LineTo(Fixed, Fixed),
1874 CurveTo(Fixed, Fixed, Fixed, Fixed, Fixed, Fixed),
1875 }
1876
1877 #[derive(PartialEq, Default, Debug)]
1878 pub struct CaptureCommandSink(pub Vec<Command>);
1879
1880 impl CommandSink for CaptureCommandSink {
1881 fn move_to(&mut self, x: Fixed, y: Fixed) {
1882 self.0.push(Command::MoveTo(x, y))
1883 }
1884
1885 fn line_to(&mut self, x: Fixed, y: Fixed) {
1886 self.0.push(Command::LineTo(x, y))
1887 }
1888
1889 fn curve_to(&mut self, cx0: Fixed, cy0: Fixed, cx1: Fixed, cy1: Fixed, x: Fixed, y: Fixed) {
1890 self.0.push(Command::CurveTo(cx0, cy0, cx1, cy1, x, y))
1891 }
1892
1893 fn close(&mut self) {
1894 let mut last_move = [Fixed::ZERO; 2];
1898 for command in self.0.iter().rev() {
1899 if let Command::MoveTo(x, y) = command {
1900 last_move = [*x, *y];
1901 break;
1902 }
1903 }
1904 self.0.push(Command::LineTo(last_move[0], last_move[1]));
1905 }
1906 }
1907
1908 impl CaptureCommandSink {
1909 pub fn to_svg(&self) -> String {
1910 use core::fmt::Write;
1911 let mut buf = String::default();
1912 for cmd in &self.0 {
1913 if !buf.is_empty() {
1914 buf.push(' ');
1915 }
1916 match cmd {
1917 Command::MoveTo(x, y) => write!(buf, "M{},{}", x.to_f32(), y.to_f32()).unwrap(),
1918 Command::LineTo(x, y) => write!(buf, "L{},{}", x.to_f32(), y.to_f32()).unwrap(),
1919 Command::CurveTo(x0, y0, x1, y1, x, y) => write!(
1920 buf,
1921 "C{},{} {},{} {},{}",
1922 x0.to_f32(),
1923 y0.to_f32(),
1924 x1.to_f32(),
1925 y1.to_f32(),
1926 x.to_f32(),
1927 y.to_f32()
1928 )
1929 .unwrap(),
1930 }
1931 }
1932 buf
1933 }
1934 }
1935
1936 #[derive(Default)]
1937 pub struct CharstringCommandCounter(pub usize);
1938
1939 impl CommandSink for CharstringCommandCounter {
1940 fn move_to(&mut self, _x: Fixed, _y: Fixed) {
1941 self.0 += 1;
1942 }
1943
1944 fn line_to(&mut self, _x: Fixed, _y: Fixed) {
1945 self.0 += 1;
1946 }
1947
1948 fn curve_to(
1949 &mut self,
1950 _cx0: Fixed,
1951 _cy0: Fixed,
1952 _cx1: Fixed,
1953 _cy1: Fixed,
1954 _x: Fixed,
1955 _y: Fixed,
1956 ) {
1957 self.0 += 1;
1958 }
1959
1960 fn close(&mut self) {
1961 self.0 += 1;
1962 }
1963 }
1964}
1965
1966#[cfg(test)]
1967mod tests {
1968 use super::{test_helpers::*, *};
1969 use crate::{tables::variations::ItemVariationStore, types::F2Dot14, FontData, FontRead};
1970
1971 #[test]
1972 fn cff2_example_subr() {
1973 use Command::*;
1974 let charstring = &font_test_data::cff2::EXAMPLE[0xc8..=0xe1];
1975 let store =
1976 ItemVariationStore::read(FontData::new(&font_test_data::cff2::EXAMPLE[18..])).unwrap();
1977 let coords = &[F2Dot14::from_f32(0.0)];
1978 let blend_state = BlendState::new(store, coords, 0).unwrap();
1979 let mut commands = CaptureCommandSink::default();
1980 evaluate(
1981 &NullContext(CharstringKind::Type2),
1982 Some(blend_state),
1983 charstring,
1984 &mut commands,
1985 )
1986 .unwrap();
1987 let expected = &[
2004 MoveTo(Fixed::from_f64(50.0), Fixed::ZERO),
2005 LineTo(Fixed::from_f64(550.0), Fixed::ZERO),
2006 LineTo(Fixed::from_f64(550.0), Fixed::from_f64(500.0)),
2007 LineTo(Fixed::from_f64(50.0), Fixed::from_f64(500.0)),
2008 LineTo(Fixed::from_f64(50.0), Fixed::ZERO),
2009 ];
2010 assert_eq!(&commands.0, expected);
2011 }
2012
2013 #[test]
2014 fn all_path_ops() {
2015 let charstring = &[
2045 251, 29, 253, 12, 21, 173, 134, 159, 133, 5, 140, 141, 142, 6, 251, 71, 129, 142, 7,
2046 109, 154, 161, 147, 89, 165, 125, 97, 98, 158, 124, 164, 8, 109, 154, 161, 147, 27,
2047 147, 109, 154, 161, 147, 27, 163, 159, 154, 180, 181, 119, 153, 115, 114, 120, 125, 97,
2048 98, 158, 124, 164, 31, 159, 4, 119, 153, 115, 114, 120, 125, 143, 144, 24, 119, 153,
2049 115, 114, 120, 125, 143, 144, 25, 84, 116, 117, 80, 30, 109, 154, 161, 147, 26, 147,
2050 109, 154, 161, 147, 26, 163, 159, 154, 180, 181, 119, 153, 115, 114, 120, 125, 97, 162,
2051 12, 35, 163, 159, 154, 180, 181, 119, 153, 12, 34, 152, 22, 180, 181, 119, 153, 115,
2052 114, 120, 125, 97, 12, 36, 154, 180, 181, 119, 153, 115, 114, 120, 125, 97, 147, 12,
2053 37, 14,
2054 ];
2055 use Command::*;
2056 let mut commands = CaptureCommandSink::default();
2057 evaluate(
2058 &NullContext(CharstringKind::Type2),
2059 None,
2060 charstring,
2061 &mut commands,
2062 )
2063 .unwrap();
2064 let expected = &[
2105 MoveTo(Fixed::from_i32(-137), Fixed::from_i32(-632)),
2106 LineTo(Fixed::from_i32(-103), Fixed::from_i32(-637)),
2107 LineTo(Fixed::from_i32(-83), Fixed::from_i32(-643)),
2108 LineTo(Fixed::from_i32(-82), Fixed::from_i32(-643)),
2109 LineTo(Fixed::from_i32(-82), Fixed::from_i32(-641)),
2110 LineTo(Fixed::from_i32(-79), Fixed::from_i32(-641)),
2111 LineTo(Fixed::from_i32(-79), Fixed::from_i32(-820)),
2112 LineTo(Fixed::from_i32(-89), Fixed::from_i32(-820)),
2113 LineTo(Fixed::from_i32(-89), Fixed::from_i32(-817)),
2114 CurveTo(
2115 Fixed::from_i32(-119),
2116 Fixed::from_i32(-802),
2117 Fixed::from_i32(-97),
2118 Fixed::from_i32(-794),
2119 Fixed::from_i32(-147),
2120 Fixed::from_i32(-768),
2121 ),
2122 CurveTo(
2123 Fixed::from_i32(-161),
2124 Fixed::from_i32(-810),
2125 Fixed::from_i32(-202),
2126 Fixed::from_i32(-791),
2127 Fixed::from_i32(-217),
2128 Fixed::from_i32(-766),
2129 ),
2130 CurveTo(
2131 Fixed::from_i32(-247),
2132 Fixed::from_i32(-766),
2133 Fixed::from_i32(-232),
2134 Fixed::from_i32(-744),
2135 Fixed::from_i32(-224),
2136 Fixed::from_i32(-744),
2137 ),
2138 CurveTo(
2139 Fixed::from_i32(-254),
2140 Fixed::from_i32(-736),
2141 Fixed::from_i32(-239),
2142 Fixed::from_i32(-714),
2143 Fixed::from_i32(-231),
2144 Fixed::from_i32(-714),
2145 ),
2146 CurveTo(
2147 Fixed::from_i32(-207),
2148 Fixed::from_i32(-714),
2149 Fixed::from_i32(-187),
2150 Fixed::from_i32(-699),
2151 Fixed::from_i32(-187),
2152 Fixed::from_i32(-658),
2153 ),
2154 CurveTo(
2155 Fixed::from_i32(-187),
2156 Fixed::from_i32(-616),
2157 Fixed::from_i32(-207),
2158 Fixed::from_i32(-602),
2159 Fixed::from_i32(-231),
2160 Fixed::from_i32(-602),
2161 ),
2162 CurveTo(
2163 Fixed::from_i32(-256),
2164 Fixed::from_i32(-602),
2165 Fixed::from_i32(-275),
2166 Fixed::from_i32(-616),
2167 Fixed::from_i32(-275),
2168 Fixed::from_i32(-658),
2169 ),
2170 CurveTo(
2171 Fixed::from_i32(-275),
2172 Fixed::from_i32(-699),
2173 Fixed::from_i32(-256),
2174 Fixed::from_i32(-714),
2175 Fixed::from_i32(-231),
2176 Fixed::from_i32(-714),
2177 ),
2178 LineTo(Fixed::from_i32(-137), Fixed::from_i32(-632)),
2179 MoveTo(Fixed::from_i32(-231), Fixed::from_i32(-694)),
2180 CurveTo(
2181 Fixed::from_i32(-251),
2182 Fixed::from_i32(-680),
2183 Fixed::from_i32(-275),
2184 Fixed::from_i32(-705),
2185 Fixed::from_i32(-294),
2186 Fixed::from_i32(-719),
2187 ),
2188 LineTo(Fixed::from_i32(-290), Fixed::from_i32(-714)),
2189 LineTo(Fixed::from_i32(-310), Fixed::from_i32(-700)),
2190 CurveTo(
2191 Fixed::from_i32(-334),
2192 Fixed::from_i32(-725),
2193 Fixed::from_i32(-353),
2194 Fixed::from_i32(-739),
2195 Fixed::from_i32(-349),
2196 Fixed::from_i32(-734),
2197 ),
2198 CurveTo(
2199 Fixed::from_i32(-349),
2200 Fixed::from_i32(-789),
2201 Fixed::from_i32(-372),
2202 Fixed::from_i32(-811),
2203 Fixed::from_i32(-431),
2204 Fixed::from_i32(-811),
2205 ),
2206 CurveTo(
2207 Fixed::from_i32(-431),
2208 Fixed::from_i32(-841),
2209 Fixed::from_i32(-416),
2210 Fixed::from_i32(-819),
2211 Fixed::from_i32(-416),
2212 Fixed::from_i32(-811),
2213 ),
2214 CurveTo(
2215 Fixed::from_i32(-408),
2216 Fixed::from_i32(-841),
2217 Fixed::from_i32(-393),
2218 Fixed::from_i32(-819),
2219 Fixed::from_i32(-393),
2220 Fixed::from_i32(-811),
2221 ),
2222 CurveTo(
2223 Fixed::from_i32(-369),
2224 Fixed::from_i32(-791),
2225 Fixed::from_i32(-354),
2226 Fixed::from_i32(-750),
2227 Fixed::from_i32(-312),
2228 Fixed::from_i32(-770),
2229 ),
2230 CurveTo(
2231 Fixed::from_i32(-298),
2232 Fixed::from_i32(-794),
2233 Fixed::from_i32(-323),
2234 Fixed::from_i32(-813),
2235 Fixed::from_i32(-337),
2236 Fixed::from_i32(-855),
2237 ),
2238 CurveTo(
2239 Fixed::from_i32(-313),
2240 Fixed::from_i32(-855),
2241 Fixed::from_i32(-293),
2242 Fixed::from_i32(-840),
2243 Fixed::from_i32(-252),
2244 Fixed::from_i32(-840),
2245 ),
2246 CurveTo(
2247 Fixed::from_i32(-210),
2248 Fixed::from_i32(-840),
2249 Fixed::from_i32(-230),
2250 Fixed::from_i32(-855),
2251 Fixed::from_i32(-216),
2252 Fixed::from_i32(-855),
2253 ),
2254 LineTo(Fixed::from_i32(-231), Fixed::from_i32(-694)),
2255 MoveTo(Fixed::from_i32(-203), Fixed::from_i32(-855)),
2256 CurveTo(
2257 Fixed::from_i32(-162),
2258 Fixed::from_i32(-813),
2259 Fixed::from_i32(-182),
2260 Fixed::from_i32(-799),
2261 Fixed::from_i32(-206),
2262 Fixed::from_i32(-799),
2263 ),
2264 CurveTo(
2265 Fixed::from_i32(-231),
2266 Fixed::from_i32(-799),
2267 Fixed::from_i32(-250),
2268 Fixed::from_i32(-813),
2269 Fixed::from_i32(-292),
2270 Fixed::from_i32(-855),
2271 ),
2272 CurveTo(
2273 Fixed::from_i32(-277),
2274 Fixed::from_i32(-814),
2275 Fixed::from_i32(-235),
2276 Fixed::from_i32(-834),
2277 Fixed::from_i32(-221),
2278 Fixed::from_i32(-858),
2279 ),
2280 CurveTo(
2281 Fixed::from_i32(-246),
2282 Fixed::from_i32(-877),
2283 Fixed::from_i32(-260),
2284 Fixed::from_i32(-919),
2285 Fixed::from_i32(-292),
2286 Fixed::from_i32(-911),
2287 ),
2288 LineTo(Fixed::from_i32(-203), Fixed::from_i32(-855)),
2289 ];
2290 assert_eq!(&commands.0, expected);
2291 }
2292
2293 #[test]
2296 fn coords_remaining_avoid_overflow() {
2297 let mut commands = CaptureCommandSink::default();
2300 let mut evaluator =
2301 Evaluator::new(&NullContext(CharstringKind::Type2), None, &mut commands);
2302 evaluator.stack.push(0).unwrap();
2303 evaluator.stack.push(0).unwrap();
2304 let mut cursor = FontData::new(&[]).cursor();
2305 let _ = evaluator.evaluate_operator(Operator::HhCurveTo, &mut cursor, 0);
2307 }
2308
2309 #[test]
2310 fn ignore_reserved_operators() {
2311 let charstring = &[
2312 0u8, 32, 22, 2, ];
2317 let mut commands = CaptureCommandSink::default();
2318 evaluate(
2319 &NullContext(CharstringKind::Type2),
2320 None,
2321 charstring,
2322 &mut commands,
2323 )
2324 .unwrap();
2325 let x = Fixed::from_i32(-107);
2326 assert_eq!(
2327 commands.0,
2328 [
2329 Command::MoveTo(x, Fixed::ZERO),
2330 Command::LineTo(x, Fixed::ZERO)
2331 ]
2332 );
2333 }
2334
2335 #[test]
2336 fn operation_limit() {
2337 let charstring = vec![0u8; MAX_OPERATIONS as usize + 1];
2340 let mut commands = CaptureCommandSink::default();
2341 evaluate(
2343 &NullContext(CharstringKind::Type2),
2344 None,
2345 &charstring[..MAX_OPERATIONS as usize],
2346 &mut commands,
2347 )
2348 .unwrap();
2349 let err = evaluate(
2351 &NullContext(CharstringKind::Type2),
2352 None,
2353 &charstring,
2354 &mut commands,
2355 )
2356 .unwrap_err();
2357 assert!(matches!(err, Error::LimitExceeded));
2358 }
2359
2360 #[test]
2361 fn op_div() {
2362 let mut commands = CaptureCommandSink::default();
2363 let mut eval = Evaluator::new(&NullContext(CharstringKind::Type2), None, &mut commands);
2364 let mut cursor = FontData::new(&[]).cursor();
2365 eval.stack.push(Fixed::from_f64(512.5)).unwrap();
2366 eval.stack.push(2).unwrap();
2367 eval.evaluate_operator(Operator::Div, &mut cursor, 0)
2368 .unwrap();
2369 assert_eq!(
2370 eval.stack.pop_fixed().unwrap(),
2371 Fixed::from_f64(512.5 / 2.0)
2372 );
2373 }
2374
2375 #[test]
2376 fn op_div_type1_large_int() {
2377 let mut commands = CaptureCommandSink::default();
2378 let mut eval = Evaluator::new(&NullContext(CharstringKind::Type1), None, &mut commands);
2379 let mut cursor = FontData::new(&[]).cursor();
2380 eval.stack.push(32001).unwrap();
2382 eval.stack.push(2).unwrap();
2383 eval.evaluate_operator(Operator::Div, &mut cursor, 0)
2384 .unwrap();
2385 assert_eq!(
2386 eval.stack.pop_fixed().unwrap(),
2387 Fixed::from_f64(32001.0 / 2.0)
2388 );
2389 }
2390
2391 fn eval_h_sbw(operator: Operator, kind: CharstringKind) -> [Fixed; 2] {
2395 let mut commands = CaptureCommandSink::default();
2396 let ctx = &NullContext(kind);
2397 let mut eval = Evaluator::new(ctx, None, &mut commands);
2398 let mut cursor = FontData::new(&[]).cursor();
2399 eval.stack.push(Fixed::from_f64(42.5)).unwrap();
2400 if operator == Operator::Sbw {
2401 eval.stack.push(0).unwrap();
2403 }
2404 eval.stack.push(501).unwrap();
2405 eval.stack.push(1000).unwrap();
2406 eval.evaluate_operator(operator, &mut cursor, 0).unwrap();
2407 [eval.sbx, eval.wx]
2408 }
2409
2410 #[test]
2411 fn op_sbw_type1() {
2412 let [sbx, wx] = eval_h_sbw(Operator::Sbw, CharstringKind::Type1);
2413 assert_eq!(sbx, Fixed::from_f64(42.5));
2414 assert_eq!(wx, Fixed::from_f64(501.0));
2415 }
2416
2417 #[test]
2418 fn op_hsbw_type1() {
2419 let [sbx, wx] = eval_h_sbw(Operator::Hsbw, CharstringKind::Type1);
2420 assert_eq!(sbx, Fixed::from_f64(42.5));
2421 assert_eq!(wx, Fixed::from_f64(501.0));
2422 }
2423
2424 #[test]
2426 fn op_sbw_type2_no_effect() {
2427 let [sbx, wx] = eval_h_sbw(Operator::Sbw, CharstringKind::Type2);
2428 assert_eq!(sbx, Fixed::ZERO);
2429 assert_eq!(wx, Fixed::ZERO);
2430 }
2431
2432 #[test]
2434 fn op_hsbw_type2_no_effect() {
2435 let [sbx, wx] = eval_h_sbw(Operator::Hsbw, CharstringKind::Type2);
2436 assert_eq!(sbx, Fixed::ZERO);
2437 assert_eq!(wx, Fixed::ZERO);
2438 }
2439
2440 #[test]
2441 fn op_callothersubr_flex() {
2442 let mut commands = CaptureCommandSink::default();
2443 let mut eval = Evaluator::new(&NullContext(CharstringKind::Type1), None, &mut commands);
2444 let mut cursor = FontData::new(&[]).cursor();
2445 macro_rules! op {
2447 ($nums:expr) => {
2448 for n in $nums {
2449 eval.stack.push(n).unwrap();
2450 }
2451 };
2452 ($nums:expr, $op:ident) => {
2453 op!($nums);
2454 eval.evaluate_operator(Operator::$op, &mut cursor, 0)
2455 .unwrap();
2456 };
2457 }
2458 op!([0, 1], CallOtherSubr);
2461 for vec in [[1, 2]; 7] {
2463 op!(vec, RMoveTo);
2464 }
2465 op!([0, 100, 200]);
2467 op!([3, 0], CallOtherSubr);
2469 let none: [i32; 0] = [];
2472 op!(none, SetCurrentPoint);
2473 let expected = [
2474 Command::MoveTo(Fixed::ZERO, Fixed::ZERO),
2475 Command::CurveTo(
2476 Fixed::from_i32(2),
2477 Fixed::from_i32(4),
2478 Fixed::from_i32(3),
2479 Fixed::from_i32(6),
2480 Fixed::from_i32(4),
2481 Fixed::from_i32(8),
2482 ),
2483 Command::CurveTo(
2484 Fixed::from_i32(5),
2485 Fixed::from_i32(10),
2486 Fixed::from_i32(6),
2487 Fixed::from_i32(12),
2488 Fixed::from_i32(7),
2489 Fixed::from_i32(14),
2490 ),
2491 ];
2492 assert_eq!(eval.x, Fixed::from_i32(100));
2493 assert_eq!(eval.y, Fixed::from_i32(200));
2494 assert_eq!(commands.0, expected);
2495 }
2496
2497 struct NullContext(CharstringKind);
2498
2499 impl CharstringContext for NullContext {
2500 fn kind(&self) -> CharstringKind {
2501 self.0
2502 }
2503
2504 fn seac_components(&self, _base_code: i32, _accent_code: i32) -> Result<[&[u8]; 2], Error> {
2505 Err(Error::InvalidOperation)
2506 }
2507
2508 fn global_subr(&self, _index: i32) -> Result<&[u8], Error> {
2509 Err(Error::MissingResource)
2510 }
2511
2512 fn subr(&self, _index: i32) -> Result<&[u8], Error> {
2513 Err(Error::MissingResource)
2514 }
2515 }
2516
2517 #[test]
2518 fn nop_filter_sink() {
2519 let mut commands = CaptureCommandSink::default();
2520 let mut nop_filter = NopFilterSink::new(&mut commands);
2521 let (sx, sy) = (Fixed::from_f64(10.2), Fixed::from_f64(20.4));
2522 nop_filter.move_to(Fixed::from_f64(0.0), Fixed::from_f64(0.0));
2524 nop_filter.move_to(sx, sy);
2525 nop_filter.line_to(sx, sy);
2527 nop_filter.curve_to(
2528 Fixed::from_f64(5.0),
2529 Fixed::from_f64(-5.0),
2530 Fixed::from_f64(1.5),
2531 Fixed::from_f64(2.0),
2532 Fixed::from_f64(4.5),
2533 Fixed::from_f64(-10.0),
2534 );
2535 nop_filter.line_to(Fixed::from_f64(4.5), Fixed::from_f64(-10.0));
2537 nop_filter.line_to(sx, sy);
2539 nop_filter.close();
2540 assert_eq!(
2541 commands.0,
2542 [
2543 Command::MoveTo(sx, sy),
2544 Command::CurveTo(
2545 Fixed::from_f64(5.0),
2546 Fixed::from_f64(-5.0),
2547 Fixed::from_f64(1.5),
2548 Fixed::from_f64(2.0),
2549 Fixed::from_f64(4.5),
2550 Fixed::from_f64(-10.0),
2551 ),
2552 Command::LineTo(sx, sy),
2553 ]
2554 )
2555 }
2556
2557 #[test]
2558 fn scaled_matrix_transform_sink() {
2559 let input = [(150i32, 46i32), (176, 8), (217, -13), (267, -13)]
2562 .map(|(x, y)| (Fixed::from_bits(x << 16), Fixed::from_bits(y << 16)));
2563 let expected = [(404, 118i32), (453, 20), (550, -33), (678, -33)]
2564 .map(|(x, y)| (Fixed::from_bits(x << 10), Fixed::from_bits(y << 10)));
2565 let mut dummy = ();
2566 let sink =
2567 TransformSink::from_matrix_scale(&mut dummy, TRANSFORM, Some(Fixed::from_bits(167772)));
2568 let transformed = input.map(|(x, y)| sink.transform(x, y));
2569 assert_eq!(transformed, expected);
2570 }
2571
2572 #[test]
2573 fn unscaled_matrix_transform_sink() {
2574 let input = [(150i32, 46i32), (176, 8), (217, -13), (267, -13)]
2577 .map(|(x, y)| (Fixed::from_bits(x << 16), Fixed::from_bits(y << 16)));
2578 let expected = [(158, 46i32), (177, 8), (215, -13), (265, -13)]
2579 .map(|(x, y)| (Fixed::from_bits(x << 16), Fixed::from_bits(y << 16)));
2580 let mut dummy = ();
2581 let sink = TransformSink::from_matrix_scale(&mut dummy, TRANSFORM, None);
2582 let transformed = input.map(|(x, y)| sink.transform(x, y));
2583 assert_eq!(transformed, expected);
2584 }
2585
2586 const TRANSFORM: FontMatrix = FontMatrix::from_elements([
2587 Fixed::ONE,
2588 Fixed::ZERO,
2589 Fixed::from_bits(10945),
2591 Fixed::ONE,
2592 Fixed::ZERO,
2593 Fixed::ZERO,
2594 ]);
2595
2596 #[test]
2597 fn unscaled_transform_sink_produces_integers() {
2598 let nothing = &mut ();
2599 let sink = TransformSink::new(nothing, Transform::default());
2600 for coord in [50.0, 50.1, 50.125, 50.5, 50.9] {
2601 assert_eq!(
2602 sink.transform(Fixed::from_f64(coord), Fixed::ZERO)
2603 .0
2604 .to_f32(),
2605 50.0
2606 );
2607 }
2608 }
2609
2610 #[test]
2611 fn scaled_transform_sink() {
2612 let ppem = 20.0;
2613 let upem = 1000.0;
2614 let scale = Fixed::from_bits((ppem * 64.) as i32) / Fixed::from_bits(upem as i32);
2616 let nothing = &mut ();
2617 let sink = TransformSink::from_matrix_scale(nothing, FontMatrix::IDENTITY, Some(scale));
2618 let inputs = [
2619 (0.0, 0.0),
2621 (8.0, 0.15625),
2622 (16.0, 0.3125),
2623 (32.0, 0.640625),
2624 (72.0, 1.4375),
2625 (128.0, 2.5625),
2626 ];
2627 for (coord, expected) in inputs {
2628 assert_eq!(
2629 sink.transform(Fixed::from_f64(coord), Fixed::ZERO)
2630 .0
2631 .to_f32(),
2632 expected,
2633 "scaling coord {coord}"
2634 );
2635 }
2636 }
2637
2638 #[test]
2639 fn mm_blend() {
2640 let mut commands = CaptureCommandSink::default();
2641 let ctx = MmContext([0.0, -0.25, 1.0].map(Fixed::from_f64));
2642 let mut eval = Evaluator::new(&ctx, None, &mut commands);
2643 let mut cursor = FontData::new(&[]).cursor();
2644 for i in [[1, 0], [2, 3], [4, -8], [6, 15]].into_iter().flatten() {
2648 eval.stack.push(i).unwrap();
2649 }
2650 eval.evaluate_operator(Operator::CallOtherSubr, &mut cursor, 0)
2651 .unwrap();
2652 let [a, b] = eval.stack.fixed_array(0).unwrap();
2653 assert_eq!(a.to_f32(), 3.5);
2655 assert_eq!(b.to_f32(), -9.0);
2657 }
2658
2659 struct MmContext([Fixed; 3]);
2660
2661 impl CharstringContext for MmContext {
2662 fn kind(&self) -> CharstringKind {
2663 CharstringKind::Type1
2664 }
2665
2666 fn seac_components(&self, _base_code: i32, _accent_code: i32) -> Result<[&[u8]; 2], Error> {
2667 Err(Error::InvalidOperation)
2668 }
2669
2670 fn global_subr(&self, _index: i32) -> Result<&[u8], Error> {
2671 Err(Error::MissingResource)
2672 }
2673
2674 fn subr(&self, _index: i32) -> Result<&[u8], Error> {
2675 Err(Error::MissingResource)
2676 }
2677
2678 fn weight_vector(&self) -> &[Fixed] {
2679 &self.0
2680 }
2681
2682 fn build_char_len(&self) -> usize {
2683 8
2684 }
2685 }
2686
2687 fn othersubr(eval: &mut Evaluator, args: &[f64]) -> Result<Vec<f64>, Error> {
2690 let mut cursor = FontData::new(&[]).cursor();
2691 for &arg in args {
2692 if arg.fract() == 0.0 {
2693 eval.stack.push(arg as i32)?;
2694 } else {
2695 eval.stack.push(Fixed::from_f64(arg))?;
2696 }
2697 }
2698 eval.evaluate_operator(Operator::CallOtherSubr, &mut cursor, 0)?;
2699 let stack = eval.stack.fixed_values().map(|v| v.to_f64()).collect();
2700 Ok(stack)
2701 }
2702
2703 #[test]
2705 fn othersubr_arithmetic() {
2706 let ctx = MmContext([Fixed::ZERO; 3]);
2707 for (args, result) in [
2708 (&[7.0, 2.0, 2.0, 20.0][..], 9.0),
2709 (&[7.0, 2.0, 2.0, 21.0], 5.0),
2710 (&[7.0, 2.0, 2.0, 22.0], 14.0),
2711 (&[7.0, 2.0, 2.0, 23.0], 3.5),
2712 (&[1.0, 2.0, 3.0, 4.0, 4.0, 27.0], 1.0),
2713 (&[1.0, 2.0, 5.0, 4.0, 4.0, 27.0], 2.0),
2714 ] {
2715 let mut commands = CaptureCommandSink::default();
2716 let mut eval = Evaluator::new(&ctx, None, &mut commands);
2717 assert_eq!(othersubr(&mut eval, args).unwrap(), [result], "{args:?}");
2718 }
2719 let mut commands = CaptureCommandSink::default();
2720 let mut eval = Evaluator::new(&ctx, None, &mut commands);
2721 assert!(othersubr(&mut eval, &[7.0, 0.0, 2.0, 23.0]).is_err());
2723 assert!(othersubr(&mut eval, &[7.0, 2.0, 1.0, 20.0]).is_err());
2724 }
2725
2726 #[test]
2728 fn othersubr_build_char_array() {
2729 let ctx = MmContext([0.25, 0.5, 0.25].map(Fixed::from_f64));
2730 let mut commands = CaptureCommandSink::default();
2731 let mut eval = Evaluator::new(&ctx, None, &mut commands);
2732 assert!(othersubr(&mut eval, &[5.0, 3.0, 2.0, 24.0])
2734 .unwrap()
2735 .is_empty());
2736 assert_eq!(othersubr(&mut eval, &[3.0, 1.0, 25.0]).unwrap(), [5.0]);
2737 eval.stack.clear();
2738 assert!(othersubr(&mut eval, &[2.0, 1.0, 19.0]).unwrap().is_empty());
2740 assert_eq!(othersubr(&mut eval, &[3.0, 1.0, 25.0]).unwrap(), [0.5]);
2741 eval.stack.clear();
2742 assert!(othersubr(&mut eval, &[1.0, 8.0, 2.0, 24.0]).is_err());
2744 assert!(othersubr(&mut eval, &[8.0, 1.0, 25.0]).is_err());
2745 assert!(othersubr(&mut eval, &[6.0, 1.0, 19.0]).is_err());
2746 }
2747
2748 #[test]
2750 fn othersubrs_without_a_blend_fail() {
2751 struct Plain;
2752 impl CharstringContext for Plain {
2753 fn kind(&self) -> CharstringKind {
2754 CharstringKind::Type1
2755 }
2756 fn seac_components(&self, _: i32, _: i32) -> Result<[&[u8]; 2], Error> {
2757 Err(Error::InvalidOperation)
2758 }
2759 fn global_subr(&self, _: i32) -> Result<&[u8], Error> {
2760 Err(Error::MissingResource)
2761 }
2762 fn subr(&self, _: i32) -> Result<&[u8], Error> {
2763 Err(Error::MissingResource)
2764 }
2765 }
2766 for args in [
2767 &[1.0, 2.0, 2.0, 14.0][..],
2768 &[0.0, 1.0, 19.0],
2769 &[5.0, 0.0, 2.0, 24.0],
2770 &[0.0, 1.0, 25.0],
2771 ] {
2772 let mut commands = CaptureCommandSink::default();
2773 let mut eval = Evaluator::new(&Plain, None, &mut commands);
2774 assert!(othersubr(&mut eval, args).is_err(), "{args:?}");
2775 }
2776 let mut commands = CaptureCommandSink::default();
2777 let mut eval = Evaluator::new(&Plain, None, &mut commands);
2778 assert_eq!(othersubr(&mut eval, &[7.0, 2.0, 2.0, 20.0]).unwrap(), [9.0]);
2779 }
2780
2781 fn eval(ops: &[u8]) -> Vec<Command> {
2784 let mut charstring = ops.to_vec();
2785 charstring.push(21); charstring.push(14); let mut commands = CaptureCommandSink::default();
2788 evaluate(
2789 &NullContext(CharstringKind::Type2),
2790 None,
2791 &charstring,
2792 &mut commands,
2793 )
2794 .unwrap();
2795 commands.0
2796 }
2797
2798 fn n(v: i32) -> Vec<u8> {
2800 assert!((-107..=107).contains(&v));
2801 std::vec![(v + 139) as u8]
2802 }
2803
2804 fn esc(op: u8) -> Vec<u8> {
2805 std::vec![12, op]
2806 }
2807
2808 fn binary(a: i32, b: i32, op: u8) -> (Fixed, Fixed) {
2810 let mut cs = n(0);
2811 cs.extend(n(a));
2812 cs.extend(n(b));
2813 cs.extend(esc(op));
2814 match eval(&cs).first() {
2815 Some(Command::MoveTo(x, y)) => (*x, *y),
2816 other => panic!("expected a move, got {other:?}"),
2817 }
2818 }
2819
2820 #[test]
2821 fn arithmetic() {
2822 assert_eq!(binary(7, 5, 10).1, Fixed::from_i32(12)); assert_eq!(binary(7, 5, 11).1, Fixed::from_i32(2)); assert_eq!(binary(7, 5, 24).1, Fixed::from_i32(35)); assert_eq!(binary(10, 4, 12).1, Fixed::from_f64(2.5)); }
2828
2829 #[test]
2830 fn logic_answers_with_one_or_zero() {
2831 for (a, b, op, expected) in [
2832 (1, 1, 3, 1),
2833 (1, 0, 3, 0),
2834 (0, 0, 3, 0), (1, 0, 4, 1),
2836 (0, 0, 4, 0), (5, 5, 15, 1),
2838 (5, 6, 15, 0), ] {
2840 assert_eq!(
2841 binary(a, b, op).1,
2842 Fixed::from_i32(expected),
2843 "12 {op} on {a}, {b}"
2844 );
2845 }
2846 }
2847
2848 #[test]
2849 fn unary() {
2850 let mut cs = n(0);
2852 cs.extend(n(0));
2853 cs.extend(esc(5));
2854 assert_eq!(
2855 match eval(&cs).first() {
2856 Some(Command::MoveTo(_, y)) => *y,
2857 _ => panic!(),
2858 },
2859 Fixed::from_i32(1)
2860 );
2861 for (v, op, expected) in [(-5, 9, 5), (5, 9, 5), (5, 14, -5), (-5, 14, 5)] {
2863 let mut cs = n(0);
2864 cs.extend(n(v));
2865 cs.extend(esc(op));
2866 assert_eq!(
2867 match eval(&cs).first() {
2868 Some(Command::MoveTo(_, y)) => *y,
2869 _ => panic!(),
2870 },
2871 Fixed::from_i32(expected),
2872 "12 {op} on {v}"
2873 );
2874 }
2875 }
2876
2877 #[test]
2878 fn sqrt_of_a_square_is_the_root() {
2879 for v in [1i32, 4, 9, 16, 100] {
2880 let mut cs = n(0);
2881 cs.extend(n(v));
2882 cs.extend(esc(26));
2883 let got = match eval(&cs).first() {
2884 Some(Command::MoveTo(_, y)) => *y,
2885 _ => panic!(),
2886 };
2887 let want = Fixed::from_f64((v as f64).sqrt());
2889 assert!(
2890 (got.to_bits() - want.to_bits()).abs() <= 2,
2891 "sqrt({v}) = {got:?}, wanted about {want:?}"
2892 );
2893 }
2894 for v in [0i32, -4] {
2896 let mut cs = n(0);
2897 cs.extend(n(v));
2898 cs.extend(esc(26));
2899 assert_eq!(
2900 match eval(&cs).first() {
2901 Some(Command::MoveTo(_, y)) => *y,
2902 _ => panic!(),
2903 },
2904 Fixed::ZERO
2905 );
2906 }
2907 }
2908
2909 #[test]
2910 fn the_stack_operators_rearrange_it() {
2911 let mut cs = n(0);
2913 cs.extend(n(7));
2914 cs.extend(esc(27));
2915 assert_eq!(
2916 eval(&cs).first().cloned(),
2917 Some(Command::MoveTo(Fixed::from_i32(7), Fixed::from_i32(7)))
2918 );
2919 let mut cs = n(3);
2921 cs.extend(n(9));
2922 cs.extend(esc(28));
2923 assert_eq!(
2924 eval(&cs).first().cloned(),
2925 Some(Command::MoveTo(Fixed::from_i32(9), Fixed::from_i32(3)))
2926 );
2927 let mut cs = n(4);
2929 cs.extend(n(5));
2930 cs.extend(n(6));
2931 cs.extend(esc(18));
2932 assert_eq!(
2933 eval(&cs).first().cloned(),
2934 Some(Command::MoveTo(Fixed::from_i32(4), Fixed::from_i32(5)))
2935 );
2936 let mut cs = n(0);
2938 cs.extend(n(8));
2939 cs.extend(n(0));
2940 cs.extend(esc(29));
2941 assert_eq!(
2942 eval(&cs).first().cloned(),
2943 Some(Command::MoveTo(Fixed::from_i32(8), Fixed::from_i32(8)))
2944 );
2945 }
2946
2947 #[test]
2948 fn roll_rotates_the_values_it_is_given() {
2949 let mut cs = n(1);
2951 cs.extend(n(2));
2952 cs.extend(n(3));
2953 cs.extend(n(3));
2954 cs.extend(n(1));
2955 cs.extend(esc(30));
2956 assert_eq!(
2957 eval(&cs).first().cloned(),
2958 Some(Command::MoveTo(Fixed::from_i32(1), Fixed::from_i32(2)))
2959 );
2960 }
2961
2962 #[test]
2963 fn roll_leaves_the_values_below_alone() {
2964 let mut cs = n(99);
2967 cs.extend(n(1));
2968 cs.extend(n(2));
2969 cs.extend(n(2));
2970 cs.extend(n(1));
2971 cs.extend(esc(30));
2972 assert_eq!(
2973 eval(&cs).first().cloned(),
2974 Some(Command::MoveTo(Fixed::from_i32(2), Fixed::from_i32(1)))
2975 );
2976 }
2977
2978 #[test]
2979 fn the_transient_array_remembers_between_operators() {
2980 let mut cs = n(0);
2982 cs.extend(n(42));
2983 cs.extend(n(3));
2984 cs.extend(esc(20)); cs.extend(n(3));
2986 cs.extend(esc(21)); assert_eq!(
2988 eval(&cs).first().cloned(),
2989 Some(Command::MoveTo(Fixed::ZERO, Fixed::from_i32(42)))
2990 );
2991 }
2992
2993 #[test]
2994 fn a_slot_the_array_does_not_have_is_ignored() {
2995 let mut cs = n(3);
2997 cs.extend(n(9));
2998 cs.extend(n(99));
2999 cs.extend(esc(20)); cs.extend(n(4));
3001 assert_eq!(
3002 eval(&cs).first().cloned(),
3003 Some(Command::MoveTo(Fixed::from_i32(3), Fixed::from_i32(4)))
3004 );
3005 }
3006
3007 #[test]
3008 fn ifelse_picks_the_first_when_the_conditions_are_ordered() {
3009 for (c1, c2, expected) in [(1, 2, 11), (2, 1, 22), (2, 2, 11)] {
3011 let mut cs = n(0);
3012 cs.extend(n(11));
3013 cs.extend(n(22));
3014 cs.extend(n(c1));
3015 cs.extend(n(c2));
3016 cs.extend(esc(22));
3017 assert_eq!(
3018 match eval(&cs).first() {
3019 Some(Command::MoveTo(_, y)) => *y,
3020 _ => panic!(),
3021 },
3022 Fixed::from_i32(expected),
3023 "conditions {c1}, {c2}"
3024 );
3025 }
3026 }
3027}