1use core::fmt;
4use raw::{model::Error, tables::glyf::bytecode::HintError, types::GlyphId};
5
6use crate::outline::DrawError;
7
8#[non_exhaustive]
14#[derive(Clone, PartialEq, Debug)]
15pub enum ScaleError {
16 GlyphNotFound(GlyphId),
18 InsufficientMemory {
20 required: usize,
24 supplied: usize,
26 },
27 Outline(Error),
29 Hinting(HintError),
34}
35
36impl ScaleError {
37 pub fn kind(&self) -> Error {
39 match self {
40 Self::GlyphNotFound(_) => Error::MissingResource,
41 Self::InsufficientMemory { .. } => Error::InsufficientMemory,
42 Self::Outline(error) => *error,
43 Self::Hinting(_) => Error::InvalidOperation,
44 }
45 }
46
47 pub(super) fn from_outline(error: Error, required: usize, supplied: usize) -> Self {
50 match error {
51 Error::InsufficientMemory => Self::InsufficientMemory { required, supplied },
52 error => Self::Outline(error),
53 }
54 }
55
56 pub(super) fn from_draw_error(error: DrawError, required: usize, supplied: usize) -> Self {
59 match error {
60 DrawError::GlyphNotFound(glyph) => Self::GlyphNotFound(glyph),
61 DrawError::HintingFailed(error) => Self::Hinting(error),
62 DrawError::PostScript(error) => Self::Outline(error),
63 DrawError::InsufficientMemory => Self::InsufficientMemory { required, supplied },
64 DrawError::RecursionLimitExceeded(_) | DrawError::TooManyPoints(_) => {
65 Self::Outline(Error::LimitExceeded)
66 }
67 DrawError::NoSources => Self::Outline(Error::MissingResource),
68 _ => Self::Outline(Error::Malformed),
69 }
70 }
71}
72
73impl From<Error> for ScaleError {
74 fn from(error: Error) -> Self {
75 Self::Outline(error)
76 }
77}
78
79impl From<HintError> for ScaleError {
80 fn from(error: HintError) -> Self {
81 Self::Hinting(error)
82 }
83}
84
85impl fmt::Display for ScaleError {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 match self {
88 Self::GlyphNotFound(glyph) => write!(f, "glyph {glyph} has no outline"),
89 Self::InsufficientMemory { required, supplied } => write!(
90 f,
91 "the glyph needs {required} bytes of memory but {supplied} were supplied"
92 ),
93 Self::Outline(error) => write!(f, "{error}"),
94 Self::Hinting(error) => write!(f, "{error}"),
95 }
96 }
97}
98
99impl core::error::Error for ScaleError {}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use raw::tables::glyf::bytecode::{HintErrorKind, Program};
105
106 #[test]
107 fn each_variant_has_a_kind() {
108 let hinting = HintError {
109 program: Program::Font,
110 glyph_id: None,
111 pc: 0,
112 opcode: None,
113 kind: HintErrorKind::ValueStackUnderflow,
114 };
115 for (error, kind) in [
116 (
117 ScaleError::GlyphNotFound(GlyphId::new(3)),
118 Error::MissingResource,
119 ),
120 (
121 ScaleError::InsufficientMemory {
122 required: 8,
123 supplied: 4,
124 },
125 Error::InsufficientMemory,
126 ),
127 (
128 ScaleError::Outline(Error::LimitExceeded),
129 Error::LimitExceeded,
130 ),
131 (ScaleError::Hinting(hinting), Error::InvalidOperation),
132 ] {
133 assert_eq!(error.kind(), kind, "{error:?}");
134 }
135 }
136
137 #[test]
139 fn autohint_memory_errors_gain_the_memory_sizes() {
140 assert_eq!(
141 ScaleError::from_draw_error(DrawError::InsufficientMemory, 0, 4),
142 ScaleError::InsufficientMemory {
143 required: 0,
144 supplied: 4
145 }
146 );
147 }
148
149 #[test]
151 fn outline_errors_gain_the_memory_sizes() {
152 assert_eq!(
153 ScaleError::from_outline(Error::InsufficientMemory, 64, 16),
154 ScaleError::InsufficientMemory {
155 required: 64,
156 supplied: 16,
157 }
158 );
159 assert_eq!(
160 ScaleError::from_outline(Error::Malformed, 64, 16),
161 ScaleError::Outline(Error::Malformed)
162 );
163 }
164}