1 //! Value stack for TrueType interpreter. 2 3 use super::{code_state::Args, error::HintErrorKind}; 4 5 use HintErrorKind::{ValueStackOverflow, ValueStackUnderflow}; 6 7 /// Value stack for the TrueType interpreter. 8 /// 9 /// This uses a slice as the backing store rather than a `Vec` to enable 10 /// support for allocation from user buffers. 11 /// 12 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#managing-the-stack> 13 pub struct ValueStack<'a> { 14 values: &'a mut [i32], 15 top: usize, 16 } 17 18 impl<'a> ValueStack<'a> { new(values: &'a mut [i32]) -> Self19 pub fn new(values: &'a mut [i32]) -> Self { 20 Self { values, top: 0 } 21 } 22 23 /// Returns the depth of the stack 24 /// <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#returns-the-depth-of-the-stack> len(&self) -> usize25 pub fn len(&self) -> usize { 26 self.top 27 } 28 is_empty(&self) -> bool29 pub fn is_empty(&self) -> bool { 30 self.top == 0 31 } 32 values(&self) -> &[i32]33 pub fn values(&self) -> &[i32] { 34 &self.values[..self.top] 35 } 36 push(&mut self, value: i32) -> Result<(), HintErrorKind>37 pub fn push(&mut self, value: i32) -> Result<(), HintErrorKind> { 38 let ptr = self 39 .values 40 .get_mut(self.top) 41 .ok_or(HintErrorKind::ValueStackOverflow)?; 42 *ptr = value; 43 self.top += 1; 44 Ok(()) 45 } 46 47 /// Pushes values that have been decoded from the instruction stream 48 /// onto the stack. 49 /// 50 /// Implements the PUSHB[], PUSHW[], NPUSHB[] and NPUSHW[] instructions. 51 /// 52 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#pushing-data-onto-the-interpreter-stack> push_args(&mut self, args: &Args) -> Result<(), HintErrorKind>53 pub fn push_args(&mut self, args: &Args) -> Result<(), HintErrorKind> { 54 let push_count = args.len(); 55 let stack_base = self.top; 56 for (stack_value, value) in self 57 .values 58 .get_mut(stack_base..stack_base + push_count) 59 .ok_or(ValueStackOverflow)? 60 .iter_mut() 61 .zip(args.values()) 62 { 63 *stack_value = value; 64 } 65 self.top += push_count; 66 Ok(()) 67 } 68 peek(&mut self) -> Option<i32>69 pub fn peek(&mut self) -> Option<i32> { 70 if self.top > 0 { 71 self.values.get(self.top - 1).copied() 72 } else { 73 None 74 } 75 } 76 77 /// Pops a value from the stack. 78 /// 79 /// Implements the POP[] instruction. 80 /// 81 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#pop-top-stack-element> pop(&mut self) -> Result<i32, HintErrorKind>82 pub fn pop(&mut self) -> Result<i32, HintErrorKind> { 83 let value = self.peek().ok_or(ValueStackUnderflow)?; 84 self.top -= 1; 85 Ok(value) 86 } 87 88 /// Convenience method for instructions that pop values that are used as an 89 /// index. pop_usize(&mut self) -> Result<usize, HintErrorKind>90 pub fn pop_usize(&mut self) -> Result<usize, HintErrorKind> { 91 Ok(self.pop()? as usize) 92 } 93 94 /// Applies a unary operation. 95 /// 96 /// Pops `a` from the stack and pushes `op(a)`. apply_unary( &mut self, mut op: impl FnMut(i32) -> Result<i32, HintErrorKind>, ) -> Result<(), HintErrorKind>97 pub fn apply_unary( 98 &mut self, 99 mut op: impl FnMut(i32) -> Result<i32, HintErrorKind>, 100 ) -> Result<(), HintErrorKind> { 101 let a = self.pop()?; 102 self.push(op(a)?) 103 } 104 105 /// Applies a binary operation. 106 /// 107 /// Pops `b` and `a` from the stack and pushes `op(a, b)`. apply_binary( &mut self, mut op: impl FnMut(i32, i32) -> Result<i32, HintErrorKind>, ) -> Result<(), HintErrorKind>108 pub fn apply_binary( 109 &mut self, 110 mut op: impl FnMut(i32, i32) -> Result<i32, HintErrorKind>, 111 ) -> Result<(), HintErrorKind> { 112 let b = self.pop()?; 113 let a = self.pop()?; 114 self.push(op(a, b)?) 115 } 116 117 /// Clear the entire stack. 118 /// 119 /// Implements the CLEAR[] instruction. 120 /// 121 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#clear-the-entire-stack> clear(&mut self)122 pub fn clear(&mut self) { 123 self.top = 0; 124 } 125 126 /// Duplicate top stack element. 127 /// 128 /// Implements the DUP[] instruction. 129 /// 130 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#duplicate-top-stack-element> dup(&mut self) -> Result<(), HintErrorKind>131 pub fn dup(&mut self) -> Result<(), HintErrorKind> { 132 let value = self.peek().ok_or(ValueStackUnderflow)?; 133 self.push(value) 134 } 135 136 /// Swap the top two elements on the stack. 137 /// 138 /// Implements the SWAP[] instruction. 139 /// 140 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#swap-the-top-two-elements-on-the-stack> swap(&mut self) -> Result<(), HintErrorKind>141 pub fn swap(&mut self) -> Result<(), HintErrorKind> { 142 let a = self.pop()?; 143 let b = self.pop()?; 144 self.push(a)?; 145 self.push(b) 146 } 147 148 /// Copy the indexed element to the top of the stack. 149 /// 150 /// Implements the CINDEX[] instruction. 151 /// 152 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#copy-the-indexed-element-to-the-top-of-the-stack> copy_index(&mut self) -> Result<(), HintErrorKind>153 pub fn copy_index(&mut self) -> Result<(), HintErrorKind> { 154 let top_ix = self.top.checked_sub(1).ok_or(ValueStackUnderflow)?; 155 let index = *self.values.get(top_ix).ok_or(ValueStackUnderflow)? as usize; 156 let element_ix = top_ix.checked_sub(index).ok_or(ValueStackUnderflow)?; 157 self.values[top_ix] = self.values[element_ix]; 158 Ok(()) 159 } 160 161 /// Moves the indexed element to the top of the stack. 162 /// 163 /// Implements the MINDEX[] instruction. 164 /// 165 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#move-the-indexed-element-to-the-top-of-the-stack> move_index(&mut self) -> Result<(), HintErrorKind>166 pub fn move_index(&mut self) -> Result<(), HintErrorKind> { 167 let top_ix = self.top.checked_sub(1).ok_or(ValueStackUnderflow)?; 168 let index = *self.values.get(top_ix).ok_or(ValueStackUnderflow)? as usize; 169 let element_ix = top_ix.checked_sub(index).ok_or(ValueStackUnderflow)?; 170 let value = self.values[element_ix]; 171 self.values 172 .copy_within(element_ix + 1..self.top, element_ix); 173 self.values[top_ix - 1] = value; 174 self.top -= 1; 175 Ok(()) 176 } 177 178 /// Roll the top three stack elements. 179 /// 180 /// Implements the ROLL[] instruction. 181 /// 182 /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#roll-the-top-three-stack-elements> roll(&mut self) -> Result<(), HintErrorKind>183 pub fn roll(&mut self) -> Result<(), HintErrorKind> { 184 let a = self.pop()?; 185 let b = self.pop()?; 186 let c = self.pop()?; 187 self.push(b)?; 188 self.push(a)?; 189 self.push(c)?; 190 Ok(()) 191 } 192 get(&mut self, index: usize) -> Option<i32>193 fn get(&mut self, index: usize) -> Option<i32> { 194 self.values.get(index).copied() 195 } 196 get_mut(&mut self, index: usize) -> Option<&mut i32>197 fn get_mut(&mut self, index: usize) -> Option<&mut i32> { 198 self.values.get_mut(index) 199 } 200 } 201 202 #[cfg(test)] 203 mod tests { 204 use super::{super::code_state::MockArgs, HintErrorKind, ValueStack}; 205 206 // The following are macros because functions can't return a new ValueStack 207 // with a borrowed parameter. 208 macro_rules! make_stack { 209 ($values:expr) => { 210 ValueStack { 211 values: $values, 212 top: $values.len(), 213 } 214 }; 215 } 216 macro_rules! make_empty_stack { 217 ($values:expr) => { 218 ValueStack { 219 values: $values, 220 top: 0, 221 } 222 }; 223 } 224 225 #[test] push()226 fn push() { 227 let mut stack = make_empty_stack!(&mut [0; 4]); 228 for i in 0..4 { 229 stack.push(i).unwrap(); 230 assert_eq!(stack.peek(), Some(i)); 231 } 232 assert!(matches!( 233 stack.push(0), 234 Err(HintErrorKind::ValueStackOverflow) 235 )); 236 } 237 238 #[test] push_args()239 fn push_args() { 240 let mut stack = make_empty_stack!(&mut [0; 32]); 241 let values = [-5, 2, 2845, 92, -26, 42, i16::MIN, i16::MAX]; 242 let mock_args = MockArgs::from_words(&values); 243 stack.push_args(&mock_args.args()).unwrap(); 244 let mut popped = vec![]; 245 while !stack.is_empty() { 246 popped.push(stack.pop().unwrap()); 247 } 248 assert!(values 249 .iter() 250 .rev() 251 .map(|x| *x as i32) 252 .eq(popped.iter().copied())); 253 } 254 255 #[test] pop()256 fn pop() { 257 let mut stack = make_stack!(&mut [0, 1, 2, 3]); 258 for i in (0..4).rev() { 259 assert_eq!(stack.pop().ok(), Some(i)); 260 } 261 assert!(matches!( 262 stack.pop(), 263 Err(HintErrorKind::ValueStackUnderflow) 264 )); 265 } 266 267 #[test] dup()268 fn dup() { 269 let mut stack = make_stack!(&mut [1, 2, 3, 0]); 270 // pop extra element so we have room for dup 271 stack.pop().unwrap(); 272 stack.dup().unwrap(); 273 assert_eq!(stack.values(), &[1, 2, 3, 3]); 274 } 275 276 #[test] swap()277 fn swap() { 278 let mut stack = make_stack!(&mut [1, 2, 3]); 279 stack.swap().unwrap(); 280 assert_eq!(stack.values(), &[1, 3, 2]); 281 } 282 283 #[test] copy_index()284 fn copy_index() { 285 let mut stack = make_stack!(&mut [4, 10, 2, 1, 3]); 286 stack.copy_index().unwrap(); 287 assert_eq!(stack.values(), &[4, 10, 2, 1, 10]); 288 } 289 290 #[test] move_index()291 fn move_index() { 292 let mut stack = make_stack!(&mut [4, 10, 2, 1, 3]); 293 stack.move_index().unwrap(); 294 assert_eq!(stack.values(), &[4, 2, 1, 10]); 295 } 296 297 #[test] roll()298 fn roll() { 299 let mut stack = make_stack!(&mut [1, 2, 3]); 300 stack.roll().unwrap(); 301 assert_eq!(stack.values(), &[2, 3, 1]); 302 } 303 304 #[test] unnop()305 fn unnop() { 306 let mut stack = make_stack!(&mut [42]); 307 stack.apply_unary(|a| Ok(-a)).unwrap(); 308 assert_eq!(stack.peek(), Some(-42)); 309 stack.apply_unary(|a| Ok(!a)).unwrap(); 310 assert_eq!(stack.peek(), Some(!-42)); 311 } 312 313 #[test] binop()314 fn binop() { 315 let mut stack = make_empty_stack!(&mut [0; 32]); 316 for value in 1..=5 { 317 stack.push(value).unwrap(); 318 } 319 stack.apply_binary(|a, b| Ok(a + b)).unwrap(); 320 assert_eq!(stack.peek(), Some(9)); 321 stack.apply_binary(|a, b| Ok(a * b)).unwrap(); 322 assert_eq!(stack.peek(), Some(27)); 323 stack.apply_binary(|a, b| Ok(a - b)).unwrap(); 324 assert_eq!(stack.peek(), Some(-25)); 325 stack.apply_binary(|a, b| Ok(a / b)).unwrap(); 326 assert_eq!(stack.peek(), Some(0)); 327 } 328 } 329