skrifa/outline/glyf/hint/engine/
misc.rs
1use super::{Engine, OpResult};
8
9impl Engine<'_> {
10 pub(super) fn op_getinfo(&mut self) -> OpResult {
25 use getinfo::*;
26 let selector = self.value_stack.pop()?;
27 let mut result = 0;
28 if (selector & VERSION_SELECTOR_BIT) != 0 {
30 result = 40;
31 }
32 if (selector & GLYPH_ROTATED_SELECTOR_BIT) != 0 && self.graphics.is_rotated {
34 result |= GLYPH_ROTATED_RESULT_BIT;
35 }
36 if (selector & GLYPH_STRETCHED_SELECTOR_BIT) != 0 && self.graphics.is_stretched {
38 result |= GLYPH_STRETCHED_RESULT_BIT;
39 }
40 if (selector & FONT_VARIATIONS_SELECTOR_BIT) != 0 && self.axis_count != 0 {
42 result |= FONT_VARIATIONS_RESULT_BIT;
43 }
44 if self.graphics.target.is_smooth() {
46 if (selector & SUBPIXEL_HINTING_SELECTOR_BIT) != 0 {
49 result |= SUBPIXEL_HINTING_RESULT_BIT;
50 }
51 if (selector & VERTICAL_LCD_SELECTOR_BIT) != 0 && self.graphics.target.is_vertical_lcd()
53 {
54 result |= VERTICAL_LCD_RESULT_BIT;
55 }
56 if (selector & SUBPIXEL_POSITIONED_SELECTOR_BIT) != 0 {
59 result |= SUBPIXEL_POSITIONED_RESULT_BIT;
60 }
61 if (selector & SYMMETRICAL_SMOOTHING_SELECTOR_BIT) != 0
66 && self.graphics.target.symmetric_rendering()
67 {
68 result |= SYMMETRICAL_SMOOTHING_RESULT_BIT;
69 }
70 if (selector & GRAYSCALE_CLEARTYPE_SELECTOR_BIT) != 0
72 && self.graphics.target.is_grayscale_cleartype()
73 {
74 result |= GRAYSCALE_CLEARTYPE_RESULT_BIT;
75 }
76 }
77 self.value_stack.push(result)
78 }
79
80 pub(super) fn op_getvariation(&mut self) -> OpResult {
95 let axis_count = self.axis_count as usize;
97 if axis_count != 0 {
98 for coord in self
101 .coords
102 .iter()
103 .copied()
104 .chain(std::iter::repeat(Default::default()))
105 .take(axis_count)
106 {
107 self.value_stack.push(coord.to_bits() as i32)?;
108 }
109 Ok(())
110 } else {
111 self.op_unknown(0x91)
112 }
113 }
114
115 pub(super) fn op_getdata(&mut self) -> OpResult {
127 if self.axis_count != 0 {
128 self.value_stack.push(17)
129 } else {
130 self.op_unknown(0x92)
131 }
132 }
133}
134
135mod getinfo {
138 pub const VERSION_SELECTOR_BIT: i32 = 1 << 0;
140
141 pub const GLYPH_ROTATED_SELECTOR_BIT: i32 = 1 << 1;
143 pub const GLYPH_ROTATED_RESULT_BIT: i32 = 1 << 8;
144
145 pub const GLYPH_STRETCHED_SELECTOR_BIT: i32 = 1 << 2;
147 pub const GLYPH_STRETCHED_RESULT_BIT: i32 = 1 << 9;
148
149 pub const FONT_VARIATIONS_SELECTOR_BIT: i32 = 1 << 3;
151 pub const FONT_VARIATIONS_RESULT_BIT: i32 = 1 << 10;
152
153 pub const SUBPIXEL_HINTING_SELECTOR_BIT: i32 = 1 << 6;
156 pub const SUBPIXEL_HINTING_RESULT_BIT: i32 = 1 << 13;
157
158 pub const VERTICAL_LCD_SELECTOR_BIT: i32 = 1 << 8;
160 pub const VERTICAL_LCD_RESULT_BIT: i32 = 1 << 15;
161
162 pub const SUBPIXEL_POSITIONED_SELECTOR_BIT: i32 = 1 << 10;
165 pub const SUBPIXEL_POSITIONED_RESULT_BIT: i32 = 1 << 17;
166
167 pub const SYMMETRICAL_SMOOTHING_SELECTOR_BIT: i32 = 1 << 11;
171 pub const SYMMETRICAL_SMOOTHING_RESULT_BIT: i32 = 1 << 18;
172
173 pub const GRAYSCALE_CLEARTYPE_SELECTOR_BIT: i32 = 1 << 12;
175 pub const GRAYSCALE_CLEARTYPE_RESULT_BIT: i32 = 1 << 19;
176}
177
178#[cfg(test)]
179mod tests {
180 use super::super::{
181 super::super::super::{SmoothMode, Target},
182 Engine, HintErrorKind, MockEngine,
183 };
184 use raw::types::F2Dot14;
185 use read_fonts::tables::glyf::bytecode::Opcode;
186
187 #[test]
188 fn getinfo() {
189 use super::getinfo::*;
190 let mut mock = MockEngine::new();
191 let mut engine = mock.engine();
192 engine.getinfo_test(VERSION_SELECTOR_BIT, 40);
194 engine.getinfo_test(GLYPH_ROTATED_SELECTOR_BIT, 0);
196 engine.graphics.is_rotated = true;
198 engine.getinfo_test(GLYPH_ROTATED_SELECTOR_BIT, GLYPH_ROTATED_RESULT_BIT);
199 engine.getinfo_test(GLYPH_STRETCHED_SELECTOR_BIT, 0);
201 engine.graphics.is_stretched = true;
203 engine.getinfo_test(GLYPH_STRETCHED_SELECTOR_BIT, GLYPH_STRETCHED_RESULT_BIT);
204 engine.getinfo_test(
206 GLYPH_ROTATED_SELECTOR_BIT | GLYPH_STRETCHED_SELECTOR_BIT,
207 GLYPH_ROTATED_RESULT_BIT | GLYPH_STRETCHED_RESULT_BIT,
208 );
209 engine.getinfo_test(FONT_VARIATIONS_SELECTOR_BIT, 0);
211 engine.axis_count = 1;
213 engine.getinfo_test(FONT_VARIATIONS_SELECTOR_BIT, FONT_VARIATIONS_RESULT_BIT);
214 engine.graphics.target = Target::Mono;
216 for selector in [
217 SUBPIXEL_HINTING_SELECTOR_BIT,
218 VERTICAL_LCD_SELECTOR_BIT,
219 SUBPIXEL_POSITIONED_SELECTOR_BIT,
220 SYMMETRICAL_SMOOTHING_SELECTOR_BIT,
221 GRAYSCALE_CLEARTYPE_SELECTOR_BIT,
222 ] {
223 engine.getinfo_test(selector, 0);
224 }
225 engine.graphics.target = Target::default();
227 for (selector, result) in [
228 (
230 GRAYSCALE_CLEARTYPE_SELECTOR_BIT,
231 GRAYSCALE_CLEARTYPE_RESULT_BIT,
232 ),
233 (SUBPIXEL_HINTING_SELECTOR_BIT, SUBPIXEL_HINTING_RESULT_BIT),
235 (
236 SUBPIXEL_POSITIONED_SELECTOR_BIT,
237 SUBPIXEL_POSITIONED_RESULT_BIT,
238 ),
239 ] {
240 engine.getinfo_test(selector, result);
241 }
242 engine.graphics.target = Target::Smooth {
244 mode: SmoothMode::VerticalLcd,
245 preserve_linear_metrics: true,
246 symmetric_rendering: false,
247 };
248 engine.getinfo_test(VERTICAL_LCD_SELECTOR_BIT, VERTICAL_LCD_RESULT_BIT);
249 engine.getinfo_test(SYMMETRICAL_SMOOTHING_SELECTOR_BIT, 0);
251 engine.getinfo_test(GRAYSCALE_CLEARTYPE_SELECTOR_BIT, 0);
253 engine.graphics.target = Target::default();
255 engine.getinfo_test(
257 SYMMETRICAL_SMOOTHING_SELECTOR_BIT,
258 SYMMETRICAL_SMOOTHING_RESULT_BIT,
259 );
260 }
261
262 #[test]
263 fn getvariation() {
264 let mut mock = MockEngine::new();
265 let mut engine = mock.engine();
266 assert!(matches!(
268 engine.op_getvariation(),
269 Err(HintErrorKind::UnhandledOpcode(Opcode::GETVARIATION))
270 ));
271 engine.axis_count = 2;
273 let coords = [
275 F2Dot14::from_f32(-1.0),
276 F2Dot14::from_f32(0.5),
277 F2Dot14::from_f32(1.0),
278 ];
279 let coords_bits = coords.map(|x| x.to_bits() as i32);
280 engine.coords = &coords[0..1];
282 engine.op_getvariation().unwrap();
283 assert_eq!(engine.value_stack.len(), 2);
284 assert_eq!(engine.value_stack.values(), &[coords_bits[0], 0]);
285 engine.value_stack.clear();
286 engine.coords = &coords[0..3];
288 engine.op_getvariation().unwrap();
289 assert_eq!(engine.value_stack.len(), 2);
290 assert_eq!(engine.value_stack.values(), &coords_bits[0..2]);
291 engine.value_stack.clear();
292 engine.coords = &coords[0..2];
294 engine.op_getvariation().unwrap();
295 assert_eq!(engine.value_stack.len(), 2);
296 assert_eq!(engine.value_stack.values(), &coords_bits[0..2]);
297 }
298
299 #[test]
300 fn getdata() {
301 let mut mock = MockEngine::new();
302 let mut engine = mock.engine();
303 assert!(matches!(
305 engine.op_getdata(),
306 Err(HintErrorKind::UnhandledOpcode(Opcode::GETDATA))
307 ));
308 engine.axis_count = 1;
310 engine.op_getdata().unwrap();
311 assert_eq!(engine.value_stack.pop().unwrap(), 17);
313 }
314
315 impl Engine<'_> {
316 fn getinfo_test(&mut self, selector: i32, expected: i32) {
317 self.value_stack.push(selector).unwrap();
318 self.op_getinfo().unwrap();
319 assert_eq!(self.value_stack.pop().unwrap(), expected);
320 }
321 }
322}