skrifa/outline/glyf/hint/
error.rs1use read_fonts::tables::glyf::bytecode::{DecodeError, Opcode};
4
5use super::program::Program;
6use crate::GlyphId;
7
8#[derive(Clone, PartialEq, Debug)]
10pub enum HintErrorKind {
11 UnexpectedEndOfBytecode,
12 UnhandledOpcode(Opcode),
13 DefinitionInGlyphProgram,
14 NestedDefinition,
15 DefinitionTooLarge,
16 TooManyDefinitions,
17 InvalidDefinition(usize),
18 ValueStackOverflow,
19 ValueStackUnderflow,
20 CallStackOverflow,
21 CallStackUnderflow,
22 InvalidStackValue(i32),
23 InvalidPointIndex(usize),
24 InvalidPointRange(usize, usize),
25 InvalidContourIndex(usize),
26 InvalidCvtIndex(usize),
27 InvalidStorageIndex(usize),
28 DivideByZero,
29 InvalidZoneIndex(i32),
30 NegativeLoopCounter,
31 InvalidJump,
32 ExceededExecutionBudget,
33}
34
35impl core::fmt::Display for HintErrorKind {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 Self::UnexpectedEndOfBytecode => write!(f, "unexpected end of bytecode"),
39 Self::UnhandledOpcode(opcode) => write!(f, "unhandled instruction opcode {opcode}"),
40 Self::DefinitionInGlyphProgram => {
41 write!(
42 f,
43 "function or instruction definition present in glyph program"
44 )
45 }
46 Self::NestedDefinition => write!(f, "nested function or instruction definition"),
47 Self::DefinitionTooLarge => write!(
48 f,
49 "function or instruction definition exceeded the maximum size of 64k"
50 ),
51 Self::TooManyDefinitions => write!(f, "too many function or instruction definitions"),
52 Self::InvalidDefinition(key) => {
53 write!(f, "function or instruction definition {key} not found")
54 }
55 Self::ValueStackOverflow => write!(f, "value stack overflow"),
56 Self::ValueStackUnderflow => write!(f, "value stack underflow"),
57 Self::CallStackOverflow => write!(f, "call stack overflow"),
58 Self::CallStackUnderflow => write!(f, "call stack underflow"),
59 Self::InvalidStackValue(value) => write!(
60 f,
61 "stack value {value} was invalid for the current operation"
62 ),
63 Self::InvalidPointIndex(index) => write!(f, "point index {index} was out of bounds"),
64 Self::InvalidPointRange(start, end) => {
65 write!(f, "point range {start}..{end} was out of bounds")
66 }
67 Self::InvalidContourIndex(index) => {
68 write!(f, "contour index {index} was out of bounds")
69 }
70 Self::InvalidCvtIndex(index) => write!(f, "cvt index {index} was out of bounds"),
71 Self::InvalidStorageIndex(index) => {
72 write!(f, "storage area index {index} was out of bounds")
73 }
74 Self::DivideByZero => write!(f, "attempt to divide by 0"),
75 Self::InvalidZoneIndex(index) => write!(
76 f,
77 "zone index {index} was invalid (only 0 or 1 are permitted)"
78 ),
79 Self::NegativeLoopCounter => {
80 write!(f, "attempt to set the loop counter to a negative value")
81 }
82 Self::InvalidJump => write!(f, "the target of a jump instruction was invalid"),
83 Self::ExceededExecutionBudget => write!(f, "too many instructions executed"),
84 }
85 }
86}
87
88impl From<DecodeError> for HintErrorKind {
89 fn from(_: DecodeError) -> Self {
90 Self::UnexpectedEndOfBytecode
91 }
92}
93
94#[derive(Clone, Debug)]
96pub struct HintError {
97 pub program: Program,
98 pub glyph_id: Option<GlyphId>,
99 pub pc: usize,
100 pub opcode: Option<Opcode>,
101 pub kind: HintErrorKind,
102}
103
104impl core::fmt::Display for HintError {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 match self.program {
107 Program::ControlValue => write!(f, "prep")?,
108 Program::Font => write!(f, "fpgm")?,
109 Program::Glyph => write!(f, "glyf")?,
110 }
111 if let Some(glyph_id) = self.glyph_id {
112 write!(f, "[{}]", glyph_id.to_u32())?;
113 }
114 let (opcode, colon) = match self.opcode {
115 Some(opcode) => (opcode.name(), ":"),
116 _ => ("", ""),
117 };
118 write!(f, "@{}:{opcode}{colon} {}", self.pc, self.kind)
119 }
120}