Skip to main content

skrifa/outline/glyf/hint/engine/
dispatch.rs

1//! Instruction decoding and dispatch.
2
3use read_fonts::tables::glyf::bytecode::Opcode;
4
5use super::{
6    super::program::Program, Engine, HintError, HintErrorKind, Instruction, MAX_RUN_INSTRUCTIONS,
7};
8
9impl<'a> Engine<'a> {
10    /// Resets state for the specified program and executes all instructions.
11    pub fn run_program(&mut self, program: Program, is_pedantic: bool) -> Result<(), HintError> {
12        self.reset(program, is_pedantic);
13        self.run()
14    }
15
16    /// Set internal state for running the specified program.
17    pub fn reset(&mut self, program: Program, is_pedantic: bool) {
18        self.program.reset(program);
19        // Reset overall graphics state, keeping the retained bits.
20        self.graphics.reset();
21        self.graphics.is_pedantic = is_pedantic;
22        self.work_budget.reset();
23        // Program specific setup.
24        match program {
25            Program::Font => {
26                self.definitions.functions.reset();
27                self.definitions.instructions.reset();
28            }
29            Program::ControlValue => {
30                self.graphics.backward_compatibility = false;
31            }
32            Program::Glyph => {
33                // Instruct control bit 1 says we reset retained graphics state
34                // to default values.
35                if self.graphics.instruct_control & 2 != 0 {
36                    self.graphics.reset_retained();
37                }
38                // Set backward compatibility mode
39                if self.graphics.target.preserve_linear_metrics() {
40                    self.graphics.backward_compatibility = true;
41                } else if self.graphics.target.is_smooth() {
42                    self.graphics.backward_compatibility =
43                        (self.graphics.instruct_control & 0x4) == 0;
44                } else {
45                    self.graphics.backward_compatibility = false;
46                }
47            }
48        }
49    }
50
51    /// Decodes and dispatches all instructions until completion or error.
52    pub fn run(&mut self) -> Result<(), HintError> {
53        let mut count = 0;
54        while let Some(ins) = self.decode() {
55            let ins = ins?;
56            self.dispatch(&ins)?;
57            count += 1;
58            if count > MAX_RUN_INSTRUCTIONS {
59                return Err(HintError {
60                    program: self.program.current,
61                    glyph_id: None,
62                    pc: ins.pc,
63                    opcode: Some(ins.opcode),
64                    kind: HintErrorKind::ExceededExecutionBudget,
65                });
66            }
67        }
68        Ok(())
69    }
70
71    /// Decodes the next instruction from the current program.
72    pub fn decode(&mut self) -> Option<Result<Instruction<'a>, HintError>> {
73        let ins = self.program.decoder.decode()?;
74        Some(ins.map_err(|_| HintError {
75            program: self.program.current,
76            glyph_id: None,
77            pc: self.program.decoder.pc,
78            opcode: None,
79            kind: HintErrorKind::UnexpectedEndOfBytecode,
80        }))
81    }
82
83    /// Executes the appropriate code for the given instruction.
84    pub fn dispatch(&mut self, ins: &Instruction) -> Result<(), HintError> {
85        let current_program = self.program.current;
86        self.dispatch_inner(ins).map_err(|kind| HintError {
87            program: current_program,
88            glyph_id: None,
89            pc: ins.pc,
90            opcode: Some(ins.opcode),
91            kind,
92        })
93    }
94
95    fn dispatch_inner(&mut self, ins: &Instruction) -> Result<(), HintErrorKind> {
96        use Opcode::*;
97        let opcode = ins.opcode;
98        let raw_opcode = opcode as u8;
99        match ins.opcode {
100            SVTCA0 | SVTCA1 | SPVTCA0 | SPVTCA1 | SFVTCA0 | SFVTCA1 => self.op_svtca(raw_opcode)?,
101            SPVTL0 | SPVTL1 | SFVTL0 | SFVTL1 => self.op_svtl(raw_opcode)?,
102            SPVFS => self.op_spvfs()?,
103            SFVFS => self.op_sfvfs()?,
104            GPV => self.op_gpv()?,
105            GFV => self.op_gfv()?,
106            SFVTPV => self.op_sfvtpv()?,
107            ISECT => self.op_isect()?,
108            SRP0 => self.op_srp0()?,
109            SRP1 => self.op_srp1()?,
110            SRP2 => self.op_srp2()?,
111            SZP0 => self.op_szp0()?,
112            SZP1 => self.op_szp1()?,
113            SZP2 => self.op_szp2()?,
114            SZPS => self.op_szps()?,
115            SLOOP => self.op_sloop()?,
116            RTG => self.op_rtg()?,
117            RTHG => self.op_rthg()?,
118            SMD => self.op_smd()?,
119            ELSE => self.op_else()?,
120            JMPR => self.op_jmpr()?,
121            SCVTCI => self.op_scvtci()?,
122            SSWCI => self.op_sswci()?,
123            SSW => self.op_ssw()?,
124            DUP => self.op_dup()?,
125            POP => self.op_pop()?,
126            CLEAR => self.op_clear()?,
127            SWAP => self.op_swap()?,
128            DEPTH => self.op_depth()?,
129            CINDEX => self.op_cindex()?,
130            MINDEX => self.op_mindex()?,
131            ALIGNPTS => self.op_alignpts()?,
132            // UNUSED: 0x28
133            UTP => self.op_utp()?,
134            LOOPCALL => self.op_loopcall()?,
135            CALL => self.op_call()?,
136            FDEF => self.op_fdef()?,
137            ENDF => self.op_endf()?,
138            MDAP0 | MDAP1 => self.op_mdap(raw_opcode)?,
139            IUP0 | IUP1 => self.op_iup(raw_opcode)?,
140            SHP0 | SHP1 => self.op_shp(raw_opcode)?,
141            SHC0 | SHC1 => self.op_shc(raw_opcode)?,
142            SHZ0 | SHZ1 => self.op_shz(raw_opcode)?,
143            SHPIX => self.op_shpix()?,
144            IP => self.op_ip()?,
145            MSIRP0 | MSIRP1 => self.op_msirp(raw_opcode)?,
146            ALIGNRP => self.op_alignrp()?,
147            RTDG => self.op_rtdg()?,
148            MIAP0 | MIAP1 => self.op_miap(raw_opcode)?,
149            NPUSHB | NPUSHW => self.op_push(&ins.inline_operands)?,
150            WS => self.op_ws()?,
151            RS => self.op_rs()?,
152            WCVTP => self.op_wcvtp()?,
153            RCVT => self.op_rcvt()?,
154            GC0 | GC1 => self.op_gc(raw_opcode)?,
155            SCFS => self.op_scfs()?,
156            MD0 | MD1 => self.op_md(raw_opcode)?,
157            MPPEM => self.op_mppem()?,
158            MPS => self.op_mps()?,
159            FLIPON => self.op_flipon()?,
160            FLIPOFF => self.op_flipoff()?,
161            // Should be unused in production fonts, but we may want to
162            // support debugging at some point. Just pops a value from
163            // the stack.
164            DEBUG => {
165                self.value_stack.pop()?;
166            }
167            LT => self.op_lt()?,
168            LTEQ => self.op_lteq()?,
169            GT => self.op_gt()?,
170            GTEQ => self.op_gteq()?,
171            EQ => self.op_eq()?,
172            NEQ => self.op_neq()?,
173            ODD => self.op_odd()?,
174            EVEN => self.op_even()?,
175            IF => self.op_if()?,
176            EIF => self.op_eif()?,
177            AND => self.op_and()?,
178            OR => self.op_or()?,
179            NOT => self.op_not()?,
180            DELTAP1 => self.op_deltap(opcode)?,
181            SDB => self.op_sdb()?,
182            SDS => self.op_sds()?,
183            ADD => self.op_add()?,
184            SUB => self.op_sub()?,
185            DIV => self.op_div()?,
186            MUL => self.op_mul()?,
187            ABS => self.op_abs()?,
188            NEG => self.op_neg()?,
189            FLOOR => self.op_floor()?,
190            CEILING => self.op_ceiling()?,
191            ROUND00 | ROUND01 | ROUND10 | ROUND11 => self.op_round()?,
192            // "No round" means do nothing :)
193            NROUND00 | NROUND01 | NROUND10 | NROUND11 => {}
194            WCVTF => self.op_wcvtf()?,
195            DELTAP2 | DELTAP3 => self.op_deltap(opcode)?,
196            DELTAC1 | DELTAC2 | DELTAC3 => self.op_deltac(opcode)?,
197            SROUND => self.op_sround()?,
198            S45ROUND => self.op_s45round()?,
199            JROT => self.op_jrot()?,
200            JROF => self.op_jrof()?,
201            ROFF => self.op_roff()?,
202            // UNUSED: 0x7B
203            RUTG => self.op_rutg()?,
204            RDTG => self.op_rdtg()?,
205            SANGW => self.op_sangw()?,
206            // Unsupported instruction, do nothing
207            AA => {}
208            FLIPPT => self.op_flippt()?,
209            FLIPRGON => self.op_fliprgon()?,
210            FLIPRGOFF => self.op_fliprgoff()?,
211            // UNUSED: 0x83 | 0x84
212            SCANCTRL => self.op_scanctrl()?,
213            SDPVTL0 | SDPVTL1 => self.op_sdpvtl(raw_opcode)?,
214            GETINFO => self.op_getinfo()?,
215            IDEF => self.op_idef()?,
216            ROLL => self.op_roll()?,
217            MAX => self.op_max()?,
218            MIN => self.op_min()?,
219            SCANTYPE => self.op_scantype()?,
220            INSTCTRL => self.op_instctrl()?,
221            // UNUSED: 0x8F | 0x90 (ADJUST?)
222            GETVARIATION => self.op_getvariation()?,
223            GETDATA => self.op_getdata()?,
224            _ => {
225                // FreeType handles MIRP, MDRP and pushes here.
226                // <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttinterp.c#L7629>
227                if opcode >= MIRP00000 {
228                    self.op_mirp(raw_opcode)?
229                } else if opcode >= MDRP00000 {
230                    self.op_mdrp(raw_opcode)?
231                } else if opcode >= PUSHB000 {
232                    self.op_push(&ins.inline_operands)?;
233                } else {
234                    return self.op_unknown(opcode as u8);
235                }
236            }
237        }
238        Ok(())
239    }
240}