skrifa/outline/glyf/hint/
program.rs1use raw::tables::glyf::bytecode::Decoder;
4
5use super::{
6 call_stack::{CallRecord, CallStack},
7 definition::Definition,
8 error::HintErrorKind,
9};
10
11#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
13#[repr(u8)]
14pub enum Program {
15 #[default]
18 Font = 0,
19 ControlValue = 1,
22 Glyph = 2,
24}
25
26pub struct ProgramState<'a> {
28 pub bytecode: [&'a [u8]; 3],
30 pub initial: Program,
32 pub current: Program,
34 pub decoder: Decoder<'a>,
36 pub call_stack: CallStack,
38}
39
40impl<'a> ProgramState<'a> {
41 pub fn new(
42 font_code: &'a [u8],
43 cv_code: &'a [u8],
44 glyph_code: &'a [u8],
45 initial_program: Program,
46 ) -> Self {
47 let bytecode = [font_code, cv_code, glyph_code];
48 Self {
49 bytecode,
50 initial: initial_program,
51 current: initial_program,
52 decoder: Decoder::new(bytecode[initial_program as usize], 0),
53 call_stack: CallStack::default(),
54 }
55 }
56
57 pub fn reset(&mut self, program: Program) {
59 self.initial = program;
60 self.current = program;
61 self.decoder = Decoder::new(self.bytecode[program as usize], 0);
62 self.call_stack.clear();
63 }
64
65 pub fn enter(&mut self, definition: Definition, count: u32) -> Result<(), HintErrorKind> {
68 let program = definition.program();
69 let pc = definition.code_range().start;
70 let bytecode = self.bytecode[program as usize];
71 self.call_stack.push(CallRecord {
72 caller_program: self.current,
73 return_pc: self.decoder.pc,
74 current_count: count,
75 definition,
76 })?;
77 self.current = program;
78 self.decoder = Decoder::new(bytecode, pc);
79 Ok(())
80 }
81
82 pub fn leave(&mut self) -> Result<(), HintErrorKind> {
88 let mut record = self.call_stack.pop()?;
89 if record.current_count > 1 {
90 record.current_count -= 1;
92 self.decoder.pc = record.definition.code_range().start;
93 self.call_stack.push(record)?;
94 } else {
95 self.current = record.caller_program;
96 self.decoder.bytecode = self.bytecode[record.caller_program as usize];
98 self.decoder.pc = record.return_pc;
99 }
100 Ok(())
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
111 fn accounting() {
112 let font_code = &[0][..];
113 let cv_code = &[1][..];
114 let glyph_code = &[2][..];
115 let mut state = ProgramState::new(font_code, cv_code, glyph_code, Program::Glyph);
116 assert_eq!(state.active_state(), (Program::Glyph, glyph_code, 0));
118 let font_def = Definition::new(Program::Font, 10..20, 0);
119 let cv_def = Definition::new(Program::ControlValue, 33..111, 1);
120 state.enter(cv_def, 1).unwrap();
122 assert_eq!(state.active_state(), (Program::ControlValue, cv_code, 33));
123 state.decoder.pc += 20;
125 state.enter(font_def, 1).unwrap();
127 assert_eq!(state.active_state(), (Program::Font, font_code, 10));
128 state.leave().unwrap();
130 assert_eq!(state.active_state(), (Program::ControlValue, cv_code, 53));
131 state.leave().unwrap();
133 assert_eq!(state.active_state(), (Program::Glyph, glyph_code, 0));
134 }
135
136 #[test]
140 fn loop_call() {
141 let font_code = &[0][..];
142 let cv_code = &[1][..];
143 let glyph_code = &[2][..];
144 let mut state = ProgramState::new(font_code, cv_code, glyph_code, Program::Glyph);
145 let font_def = Definition::new(Program::Font, 10..20, 0);
146 state.enter(font_def, 3).unwrap();
148 for _ in 0..3 {
149 assert_eq!(state.active_state(), (Program::Font, font_code, 10));
150 state.decoder.pc += 22;
152 state.leave().unwrap();
153 }
154 assert_eq!(state.active_state(), (Program::Glyph, glyph_code, 0));
156 }
157
158 impl<'a> ProgramState<'a> {
159 fn active_state(&self) -> (Program, &'a [u8], usize) {
160 (self.current, self.decoder.bytecode, self.decoder.pc)
161 }
162 }
163}