skrifa/outline/glyf/hint/
graphics.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
//! Graphics state for the TrueType interpreter.

use super::{
    round::RoundState,
    zone::{Zone, ZonePointer},
    F26Dot6, Point, Target,
};
use core::ops::{Deref, DerefMut};

/// Describes the axis to which a measurement or point movement operation
/// applies.
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
pub enum CoordAxis {
    #[default]
    Both,
    X,
    Y,
}

/// Context in which instructions are executed.
///
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html>
#[derive(Debug)]
pub struct GraphicsState<'a> {
    /// Fields of the graphics state that persist between calls to the interpreter.
    pub retained: RetainedGraphicsState,
    /// A unit vector whose direction establishes an axis along which
    /// distances are measured.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#projection%20vector>
    pub proj_vector: Point<i32>,
    /// Current axis for the projection vector.
    pub proj_axis: CoordAxis,
    /// A second projection vector set to a line defined by the original
    /// outline location of two points. The dual projection vector is used
    /// when it is necessary to measure distances from the scaled outline
    /// before any instructions were executed.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#dual%20projection%20vector>
    pub dual_proj_vector: Point<i32>,
    /// Current axis for the dual projection vector.
    pub dual_proj_axis: CoordAxis,
    /// A unit vector that establishes an axis along which points can move.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#freedom%20vector>
    pub freedom_vector: Point<i32>,
    /// Current axis for point movement.
    pub freedom_axis: CoordAxis,
    /// Dot product of freedom and projection vectors.
    pub fdotp: i32,
    /// Determines the manner in which values are rounded.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#round%20state>
    pub round_state: RoundState,
    /// First reference point.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#rp0>
    pub rp0: usize,
    /// Second reference point.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#rp1>    
    pub rp1: usize,
    /// Third reference point.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#rp1>     
    pub rp2: usize,
    /// Makes it possible to repeat certain instructions a designated number of
    /// times. The default value of one assures that unless the value of loop
    /// is altered, these instructions will execute one time.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#loop>
    pub loop_counter: u32,
    /// First zone pointer.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#zp0>
    pub zp0: ZonePointer,
    /// Second zone pointer.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#zp1>
    pub zp1: ZonePointer,
    /// Third zone pointer.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#zp2>
    pub zp2: ZonePointer,
    /// Outline data for each zone.
    ///
    /// This array contains the twilight and glyph zones, in that order.
    pub zones: [Zone<'a>; 2],
    /// True if the current glyph is a composite.
    pub is_composite: bool,
    /// If true, enables a set of backward compatibility heuristics that
    /// prevent certain modifications to the outline. The purpose is to
    /// support "modern" vertical only hinting that attempts to preserve
    /// outline shape and metrics in the horizontal direction. This is
    /// enabled by default, but fonts (and specific glyphs) can opt out
    /// of this behavior using the INSTCTRL instruction. In practice,
    /// opting out is usually only done by "ClearType native" fonts.
    ///
    /// See <https://learn.microsoft.com/en-us/typography/cleartype/truetypecleartype>
    /// for more background and some gory details.
    ///
    /// Defaults to true.
    ///
    /// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttinterp.h#L344>
    pub backward_compatibility: bool,
    /// If true, enables more strict error checking.
    ///
    /// Defaults to false.
    ///
    /// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttinterp.h#L195>
    pub is_pedantic: bool,
    /// Set to true when IUP has been executed in the horizontal direction.
    pub did_iup_x: bool,
    /// Set to true when IUP has been executed in the vertical direction.
    pub did_iup_y: bool,
}

impl<'a> GraphicsState<'a> {
    /// Returns the factor for scaling unscaled points to pixels.
    ///
    /// For composite glyphs, "unscaled" points are already scaled so we
    /// return the identity.
    pub fn unscaled_to_pixels(&self) -> i32 {
        if self.is_composite {
            1 << 16
        } else {
            self.scale
        }
    }

    /// Resets the non-retained portions of the graphics state.
    pub fn reset(&mut self) {
        let GraphicsState {
            retained,
            zones,
            is_composite,
            ..
        } = core::mem::take(self);
        *self = GraphicsState {
            retained,
            zones,
            is_composite,
            ..Default::default()
        };
        self.update_projection_state();
    }

    /// Resets the retained portion of the graphics state to default
    /// values while saving the user instance settings.
    pub fn reset_retained(&mut self) {
        let scale = self.scale;
        let ppem = self.ppem;
        let mode = self.target;
        self.retained = RetainedGraphicsState {
            scale,
            ppem,
            target: mode,
            ..Default::default()
        }
    }
}

impl Default for GraphicsState<'_> {
    fn default() -> Self {
        // For table of default values, see <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_graphics_state>
        // All vectors are set to the x-axis (normalized in 2.14)
        let vector = Point::new(0x4000, 0);
        Self {
            retained: RetainedGraphicsState::default(),
            proj_vector: vector,
            proj_axis: CoordAxis::Both,
            dual_proj_vector: vector,
            dual_proj_axis: CoordAxis::Both,
            freedom_vector: vector,
            freedom_axis: CoordAxis::Both,
            fdotp: 0x4000,
            round_state: RoundState::default(),
            rp0: 0,
            rp1: 0,
            rp2: 0,
            loop_counter: 1,
            zp0: ZonePointer::default(),
            zp1: ZonePointer::default(),
            zp2: ZonePointer::default(),
            zones: [Zone::default(), Zone::default()],
            is_composite: false,
            backward_compatibility: true,
            is_pedantic: false,
            did_iup_x: false,
            did_iup_y: false,
        }
    }
}

/// The persistent graphics state.
///
/// Some of the graphics state is set by the control value program and
/// persists between runs of the interpreter. This struct captures that
/// state.
///
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html>
#[derive(Copy, Clone, Debug)]
pub struct RetainedGraphicsState {
    /// Controls whether the sign of control value table entries will be
    /// changed to match the sign of the actual distance measurement with
    /// which it is compared.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#auto%20flip>
    pub auto_flip: bool,
    /// Limits the regularizing effects of control value table entries to
    /// cases where the difference between the table value and the measurement
    /// taken from the original outline is sufficiently small.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#control_value_cut-in>
    pub control_value_cutin: F26Dot6,
    /// Establishes the base value used to calculate the range of point sizes
    /// to which a given DELTAC[] or DELTAP[] instruction will apply.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#delta%20base>
    pub delta_base: u16,
    /// Determines the range of movement and smallest magnitude of movement
    /// (the step) in a DELTAC[] or DELTAP[] instruction.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#delta%20shift>
    pub delta_shift: u16,
    /// Makes it possible to turn off instructions under some circumstances.
    /// When set to TRUE, no instructions will be executed
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#instruct%20control>
    pub instruct_control: u8,
    /// Establishes the smallest possible value to which a distance will be
    /// rounded.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#minimum%20distance>
    pub min_distance: F26Dot6,
    /// Determines whether the interpreter will activate dropout control for
    /// the current glyph.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#scan%20control>
    pub scan_control: bool,
    /// Type associated with `scan_control`.
    pub scan_type: i32,
    /// The distance difference below which the interpreter will replace a
    /// CVT distance or an actual distance in favor of the single width value.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#single_width_cut_in>
    pub single_width_cutin: F26Dot6,
    /// The value used in place of the control value table distance or the
    /// actual distance value when the difference between that distance and
    /// the single width value is less than the single width cut-in.
    ///
    /// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#single_width_value>
    pub single_width: F26Dot6,
    /// The user requested hinting target.
    pub target: Target,
    /// The scale factor for the current instance. Conversion from font units
    /// to 26.6 for current ppem.
    pub scale: i32,
    /// The nominal pixels per em value for the current instance.
    pub ppem: i32,
    /// True if a rotation is being applied.
    pub is_rotated: bool,
    /// True if a non-uniform scale is being applied.
    pub is_stretched: bool,
}

impl RetainedGraphicsState {
    pub fn new(scale: i32, ppem: i32, target: Target) -> Self {
        Self {
            scale,
            ppem,
            target,
            ..Default::default()
        }
    }
}

impl Default for RetainedGraphicsState {
    fn default() -> Self {
        // For table of default values, see <https://learn.microsoft.com/en-us/typography/opentype/spec/tt_graphics_state>
        Self {
            auto_flip: true,
            // 17/16 pixels in 26.6
            // (17 * 64 / 16) = 68
            control_value_cutin: F26Dot6::from_bits(68),
            delta_base: 9,
            delta_shift: 3,
            instruct_control: 0,
            // 1 pixel in 26.6
            min_distance: F26Dot6::from_bits(64),
            scan_control: false,
            scan_type: 0,
            single_width_cutin: F26Dot6::ZERO,
            single_width: F26Dot6::ZERO,
            target: Default::default(),
            scale: 0,
            ppem: 0,
            is_rotated: false,
            is_stretched: false,
        }
    }
}

impl Deref for GraphicsState<'_> {
    type Target = RetainedGraphicsState;

    fn deref(&self) -> &Self::Target {
        &self.retained
    }
}

impl DerefMut for GraphicsState<'_> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.retained
    }
}