skrifa/outline/glyf/hint/
error.rs

1//! Hinting error definitions.
2
3use read_fonts::tables::glyf::bytecode::{DecodeError, Opcode};
4
5use super::program::Program;
6use crate::GlyphId;
7
8/// Errors that may occur when interpreting TrueType bytecode.
9#[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/// Hinting error with additional context.
95#[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}