1use read_fonts::tables::glyf::bytecode::Opcode;
8
9use super::{
10 super::{definition::Definition, program::Program},
11 Engine, HintErrorKind, OpResult,
12};
13
14const MAX_DEFINITION_SIZE: usize = u16::MAX as usize;
18
19impl Engine<'_> {
20 pub(super) fn op_fdef(&mut self) -> OpResult {
35 let f = self.value_stack.pop()?;
36 self.do_def(DefKind::Function, f)
37 }
38
39 pub(super) fn op_endf(&mut self) -> OpResult {
48 self.program.leave()
49 }
50
51 pub(super) fn op_call(&mut self) -> OpResult {
62 let f = self.value_stack.pop()?;
63 self.do_call(DefKind::Function, 1, f)
64 }
65
66 pub(super) fn op_loopcall(&mut self) -> OpResult {
78 let f = self.value_stack.pop()?;
79 let count = self.value_stack.pop()?;
80 if count > 0 {
81 self.loop_budget.doing_loop_call(count as usize)?;
82 self.do_call(DefKind::Function, count as u32, f)
83 } else {
84 Ok(())
85 }
86 }
87
88 pub(super) fn op_idef(&mut self) -> OpResult {
108 let opcode = self.value_stack.pop()?;
109 self.do_def(DefKind::Instruction, opcode)
110 }
111
112 pub(super) fn op_unknown(&mut self, opcode: u8) -> OpResult {
115 self.do_call(DefKind::Instruction, 1, opcode as i32)
116 }
117
118 fn do_def(&mut self, kind: DefKind, key: i32) -> OpResult {
120 if self.program.initial == Program::Glyph {
121 return Err(HintErrorKind::DefinitionInGlyphProgram);
122 }
123 let defs = match kind {
124 DefKind::Function => &mut self.definitions.functions,
125 DefKind::Instruction => &mut self.definitions.instructions,
126 };
127 let def = defs.allocate(key)?;
128 let start = self.program.decoder.pc;
129 while let Some(ins) = self.program.decoder.decode() {
130 let ins = ins?;
131 match ins.opcode {
132 Opcode::FDEF | Opcode::IDEF => return Err(HintErrorKind::NestedDefinition),
133 Opcode::ENDF => {
134 let range = start..ins.pc + 1;
135 if self.graphics.is_pedantic && range.len() > MAX_DEFINITION_SIZE {
136 *def = Default::default();
137 return Err(HintErrorKind::DefinitionTooLarge);
138 }
139 *def = Definition::new(self.program.current, range, key);
140 return Ok(());
141 }
142 _ => {}
143 }
144 }
145 Err(HintErrorKind::UnexpectedEndOfBytecode)
146 }
147
148 fn do_call(&mut self, kind: DefKind, count: u32, key: i32) -> OpResult {
150 if count == 0 {
151 return Ok(());
152 }
153 let def = match kind {
154 DefKind::Function => self.definitions.functions.get(key),
155 DefKind::Instruction => match self.definitions.instructions.get(key) {
156 Err(HintErrorKind::InvalidDefinition(opcode)) => Err(
158 HintErrorKind::UnhandledOpcode(Opcode::from_byte(opcode as u8)),
159 ),
160 result => result,
161 },
162 };
163 self.program.enter(*def?, count)
164 }
165}
166
167enum DefKind {
168 Function,
169 Instruction,
170}
171
172#[cfg(test)]
173mod tests {
174 use super::{
175 super::{
176 super::program::{Program, ProgramState},
177 Engine, MockEngine,
178 },
179 HintErrorKind, Opcode, MAX_DEFINITION_SIZE,
180 };
181
182 #[test]
185 fn define_function_call_loopcall() {
186 use Opcode::*;
187 let mut mock = MockEngine::new();
188 let mut engine = mock.engine();
189 #[rustfmt::skip]
190 let font_code = [
191 op(PUSHB001), 1, 0,
192 op(FDEF),
194 op(PUSHB000), 2,
195 op(ADD),
196 op(ENDF),
197 op(FDEF),
200 op(PUSHB000), 0,
201 op(CALL),
202 op(PUSHB001), 5, 0,
203 op(LOOPCALL),
204 op(NEG),
205 op(ENDF),
206 ];
207 engine.set_font_code(&font_code);
209 engine.run().unwrap();
210 engine.value_stack.push(10).unwrap();
216 engine.value_stack.push(1).unwrap();
217 engine.op_call().unwrap();
218 engine.run().unwrap();
219 assert_eq!(engine.value_stack.pop().ok(), Some(-22));
220 }
221
222 #[test]
225 fn override_function() {
226 use Opcode::*;
227 let mut mock = MockEngine::new();
228 let mut engine = mock.engine();
229 #[rustfmt::skip]
230 let font_code = [
231 op(PUSHB001), 0, 0,
232 op(FDEF),
234 op(PUSHB000), 2,
235 op(ADD),
236 op(ENDF),
237 op(FDEF),
239 op(PUSHB000), 2,
240 op(SUB),
241 op(ENDF),
242 ];
243 engine.set_font_code(&font_code);
245 engine.run().unwrap();
246 engine.value_stack.push(10).unwrap();
250 engine.value_stack.push(0).unwrap();
251 engine.op_call().unwrap();
252 engine.run().unwrap();
253 assert_eq!(engine.value_stack.pop().ok(), Some(8));
254 }
255
256 #[test]
260 fn call_different_program() {
261 use Opcode::*;
262 let mut mock = MockEngine::new();
263 let mut engine = mock.engine();
264 #[rustfmt::skip]
265 let font_code = [
266 op(PUSHB000), 0,
267 op(FDEF),
269 op(PUSHB000), 2,
270 op(ADD),
271 op(ENDF),
272 ];
273 #[rustfmt::skip]
274 let cv_code = [
275 op(PUSHB001), 40, 0,
277 op(CALL),
278 op(NEG)
279 ];
280 let glyph_code = &[];
281 engine.program = ProgramState::new(&font_code, &cv_code, glyph_code, Program::Font);
283 engine.run().unwrap();
284 engine.program = ProgramState::new(&font_code, &cv_code, glyph_code, Program::ControlValue);
286 engine.run().unwrap();
287 assert_eq!(engine.value_stack.pop().ok(), Some(-42));
294 }
295
296 #[test]
298 fn loopcall_budget() {
299 use Opcode::*;
300 let mut mock = MockEngine::new();
301 let mut engine = mock.engine();
302 let limit = engine.loop_budget.limit;
303 #[rustfmt::skip]
304 let font_code = [
305 op(PUSHB001), 1, 0,
306 op(FDEF),
308 op(ENDF),
309 op(FDEF),
312 op(PUSHB001), limit as u8, 0,
313 op(LOOPCALL),
314 op(PUSHB001), 1, 0,
315 op(LOOPCALL), op(ENDF),
317 ];
318 engine.set_font_code(&font_code);
320 engine.run().unwrap();
321 engine.value_stack.push(10).unwrap();
323 engine.value_stack.push(1).unwrap();
324 engine.op_call().unwrap();
325 let err = engine.run().unwrap_err();
326 assert!(matches!(err.kind, HintErrorKind::ExceededExecutionBudget));
327 assert_eq!(err.pc, 13);
328 }
329
330 #[test]
332 fn define_instruction_and_use() {
333 use Opcode::*;
334 let mut mock = MockEngine::new();
335 let mut engine = mock.engine();
336 #[rustfmt::skip]
337 let font_code = [
338 op(PUSHB000), op(INS93),
340 op(IDEF),
341 op(PUSHB000), 2,
342 op(ADD),
343 op(ENDF),
344 op(PUSHB000), 0,
346 op(FDEF),
347 op(INS93),
348 op(NEG),
349 op(ENDF),
350 ];
351 engine.set_font_code(&font_code);
353 engine.run().unwrap();
354 engine.value_stack.push(10).unwrap();
359 engine.value_stack.push(0).unwrap();
360 engine.op_call().unwrap();
361 engine.run().unwrap();
362 assert_eq!(engine.value_stack.pop().ok(), Some(-12));
363 }
364
365 #[test]
367 fn nested_definition() {
368 use Opcode::*;
369 let mut mock = MockEngine::new();
370 let mut engine = mock.engine();
371 #[rustfmt::skip]
372 let font_code = [
373 op(PUSHB001), 1, 0,
374 op(FDEF), op(FDEF),
376 op(ENDF),
377 op(ENDF),
378 ];
379 engine.set_font_code(&font_code);
381 let err = engine.run().unwrap_err();
382 assert!(matches!(err.kind, HintErrorKind::NestedDefinition));
383 assert_eq!(err.pc, 3);
384 }
385
386 #[test]
388 fn definition_in_glyph_program() {
389 use Opcode::*;
390 let mut mock = MockEngine::new();
391 let mut engine = mock.engine();
392 #[rustfmt::skip]
393 let font_code = [
394 op(PUSHB000), 0,
395 op(FDEF), op(ENDF),
397 ];
398 engine.set_font_code(&font_code);
399 engine.program.initial = Program::Glyph;
400 let err = engine.run().unwrap_err();
401 assert!(matches!(err.kind, HintErrorKind::DefinitionInGlyphProgram));
402 assert_eq!(err.pc, 2);
403 }
404
405 #[test]
406 fn undefined_function() {
407 let mut mock = MockEngine::new();
408 let mut engine = mock.engine();
409 engine.value_stack.push(111).unwrap();
410 assert!(matches!(
411 engine.op_call(),
412 Err(HintErrorKind::InvalidDefinition(111))
413 ));
414 }
415
416 #[test]
418 fn infinite_recursion() {
419 use Opcode::*;
420 let mut mock = MockEngine::new();
421 let mut engine = mock.engine();
422 #[rustfmt::skip]
423 let font_code = [
424 op(PUSHB000), 0,
426 op(FDEF),
427 op(PUSHB000), 0,
428 op(CALL), op(ENDF),
430 ];
431 engine.set_font_code(&font_code);
432 engine.run().unwrap();
433 engine.value_stack.push(0).unwrap();
435 engine.op_call().unwrap();
436 let err = engine.run().unwrap_err();
437 assert!(matches!(err.kind, HintErrorKind::CallStackOverflow));
438 assert_eq!(err.pc, 5);
439 }
440
441 #[test]
442 fn call_stack_underflow() {
443 use Opcode::*;
444 let mut mock = MockEngine::new();
445 let mut engine = mock.engine();
446 #[rustfmt::skip]
447 let font_code = [
448 op(ENDF)
449 ];
450 engine.set_font_code(&font_code);
451 let err = engine.run().unwrap_err();
452 assert!(matches!(err.kind, HintErrorKind::CallStackUnderflow));
453 assert_eq!(err.pc, 0);
454 }
455
456 #[test]
457 fn unhandled_opcode() {
458 let mut mock = MockEngine::new();
459 let mut engine = mock.engine();
460 #[rustfmt::skip]
461 let font_code = [
462 op(Opcode::INS28),
463 ];
464 engine.set_font_code(&font_code);
465 let err = engine.run().unwrap_err();
466 assert!(matches!(
467 err.kind,
468 HintErrorKind::UnhandledOpcode(Opcode::INS28)
469 ));
470 assert_eq!(err.pc, 0);
471 }
472
473 #[test]
474 fn too_many_definitions() {
475 use Opcode::*;
476 let mut mock = MockEngine::new();
477 let mut engine = mock.engine();
478 #[rustfmt::skip]
479 let font_code = [
480 op(PUSHB101), 0, 1, 2, 3, 4, 5,
481 op(FDEF), op(ENDF),
482 op(FDEF), op(ENDF),
483 op(FDEF), op(ENDF),
484 op(FDEF), op(ENDF),
485 op(FDEF), op(ENDF),
486 op(FDEF), op(ENDF),
487 ];
488 engine.set_font_code(&font_code);
489 let err = engine.run().unwrap_err();
490 assert!(matches!(err.kind, HintErrorKind::TooManyDefinitions));
491 assert_eq!(err.pc, 17);
492 }
493
494 #[test]
495 fn big_definition() {
496 use Opcode::*;
497 let mut mock = MockEngine::new();
498 let mut engine = mock.engine();
499 let mut font_code = vec![];
500 font_code.extend_from_slice(&[op(PUSHB000), 0, op(FDEF)]);
501 font_code.extend(core::iter::repeat_n(op(NEG), MAX_DEFINITION_SIZE + 1));
502 font_code.push(op(ENDF));
503 engine.set_font_code(&font_code);
504 engine.graphics.is_pedantic = true;
505 engine.value_stack.push(1).unwrap();
506 let err = engine.run().unwrap_err();
507 assert!(matches!(err.kind, HintErrorKind::DefinitionTooLarge));
508 assert_eq!(err.pc, 2);
509 }
510
511 fn op(opcode: Opcode) -> u8 {
512 opcode as u8
513 }
514
515 impl<'a> Engine<'a> {
516 fn set_font_code(&mut self, code: &'a [u8]) {
517 self.program.bytecode[0] = code;
518 self.program.decoder.bytecode = code;
519 self.program.current = Program::Font;
520 }
521 }
522}