1
/// 26.6 fixed-point number used in TrueType hinting.
2
///
3
/// 26 integer bits + 6 fractional bits = 1/64 pixel precision.
4
/// This is the standard coordinate format used by the TrueType bytecode interpreter.
5
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
6
pub struct F26Dot6(pub i32);
7

            
8
impl F26Dot6 {
9
    pub const ZERO: F26Dot6 = F26Dot6(0);
10
    pub const ONE: F26Dot6 = F26Dot6(64);
11

            
12
    #[inline]
13
    pub fn from_i32(v: i32) -> Self {
14
        F26Dot6(v << 6)
15
    }
16

            
17
    #[inline]
18
1350
    pub fn from_bits(v: i32) -> Self {
19
1350
        F26Dot6(v)
20
1350
    }
21

            
22
    #[inline]
23
11066706
    pub fn to_bits(self) -> i32 {
24
11066706
        self.0
25
11066706
    }
26

            
27
    #[inline]
28
    pub fn to_i32(self) -> i32 {
29
        self.0 >> 6
30
    }
31

            
32
    #[inline]
33
    pub fn to_f64(self) -> f64 {
34
        self.0 as f64 / 64.0
35
    }
36

            
37
    #[inline]
38
6372
    pub fn from_f64(v: f64) -> Self {
39
6372
        F26Dot6((v * 64.0) as i32)
40
6372
    }
41

            
42
    /// Scale an FUnit value to F26Dot6 pixels.
43
    ///
44
    /// `scale` is ppem * 64 / units_per_em, pre-computed as a fixed-point multiplier.
45
    /// Uses FreeType-compatible signed rounding (FT_MulFix): take absolute values,
46
    /// round with positive bias, re-apply sign. This prevents the rounding asymmetry
47
    /// of `(negative + 0x8000) >> 16` which rounds ties toward zero instead of
48
    /// away from zero.
49
    #[inline]
50
11058552
    pub fn from_funits(funits: i32, scale: i64) -> Self {
51
11058552
        let mut s: i64 = 1;
52
11058552
        let mut a = funits as i64;
53
11058552
        let mut b = scale;
54
11058552
        if a < 0 { a = -a; s = -s; }
55
11058552
        if b < 0 { b = -b; s = -s; }
56
11058552
        let c = (a * b + 0x8000) >> 16;
57
11058552
        F26Dot6((if s > 0 { c } else { -c }) as i32)
58
11058552
    }
59

            
60
    #[inline]
61
    pub fn floor(self) -> Self {
62
        F26Dot6(self.0 & !63)
63
    }
64

            
65
    #[inline]
66
    pub fn ceil(self) -> Self {
67
        F26Dot6((self.0 + 63) & !63)
68
    }
69

            
70
    #[inline]
71
648
    pub fn round(self) -> Self {
72
648
        F26Dot6((self.0 + 32) & !63)
73
648
    }
74

            
75
    #[inline]
76
648
    pub fn abs(self) -> Self {
77
648
        F26Dot6(self.0.abs())
78
648
    }
79
}
80

            
81
impl std::ops::Add for F26Dot6 {
82
    type Output = Self;
83
    #[inline]
84
    fn add(self, rhs: Self) -> Self {
85
        F26Dot6(self.0 + rhs.0)
86
    }
87
}
88

            
89
impl std::ops::Sub for F26Dot6 {
90
    type Output = Self;
91
    #[inline]
92
    fn sub(self, rhs: Self) -> Self {
93
        F26Dot6(self.0 - rhs.0)
94
    }
95
}
96

            
97
impl std::ops::Neg for F26Dot6 {
98
    type Output = Self;
99
    #[inline]
100
    fn neg(self) -> Self {
101
        F26Dot6(-self.0)
102
    }
103
}
104

            
105
impl std::ops::AddAssign for F26Dot6 {
106
    #[inline]
107
    fn add_assign(&mut self, rhs: Self) {
108
        self.0 += rhs.0;
109
    }
110
}
111

            
112
impl std::ops::SubAssign for F26Dot6 {
113
    #[inline]
114
    fn sub_assign(&mut self, rhs: Self) {
115
        self.0 -= rhs.0;
116
    }
117
}
118

            
119
/// 2.14 fixed-point number for unit vectors.
120
///
121
/// 14 fractional bits: 0x4000 = 1.0, range approximately [-2, 2).
122
/// Used to represent the projection vector and freedom vector in the graphics state.
123
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
124
pub struct F2Dot14(pub i32);
125

            
126
impl F2Dot14 {
127
    pub const ZERO: F2Dot14 = F2Dot14(0);
128
    pub const ONE: F2Dot14 = F2Dot14(0x4000);
129

            
130
    #[inline]
131
    pub fn to_f64(self) -> f64 {
132
        self.0 as f64 / 16384.0
133
    }
134

            
135
    #[inline]
136
    pub fn from_f64(v: f64) -> Self {
137
        F2Dot14((v * 16384.0) as i32)
138
    }
139

            
140
    #[inline]
141
    pub fn from_bits(v: i32) -> Self {
142
        F2Dot14(v)
143
    }
144

            
145
    #[inline]
146
2707344
    pub fn to_bits(self) -> i32 {
147
2707344
        self.0
148
2707344
    }
149
}
150

            
151
/// Multiply two F2Dot14 values, returning F2Dot14.
152
#[inline]
153
pub fn mul_2dot14(a: F2Dot14, b: F2Dot14) -> F2Dot14 {
154
    F2Dot14(((a.0 as i64 * b.0 as i64 + 0x2000) >> 14) as i32)
155
}
156

            
157
/// Multiply F26Dot6 by F2Dot14, returning F26Dot6.
158
#[inline]
159
pub fn mul_f26dot6_by_f2dot14(a: F26Dot6, b: F2Dot14) -> F26Dot6 {
160
    F26Dot6(((a.0 as i64 * b.0 as i64 + 0x2000) >> 14) as i32)
161
}
162

            
163
/// Compute the length of a 2D vector (F2Dot14 components), returned as F2Dot14.
164
pub fn vec_length(x: F2Dot14, y: F2Dot14) -> F2Dot14 {
165
    let x = x.0 as f64 / 16384.0;
166
    let y = y.0 as f64 / 16384.0;
167
    let len = (x * x + y * y).sqrt();
168
    F2Dot14::from_f64(len)
169
}
170

            
171
/// Compute scale factor for converting FUnits to F26Dot6.
172
///
173
/// Returns a 16.16 fixed-point scale factor: `ppem * 64 / units_per_em`.
174
/// This is used with `F26Dot6::from_funits`.
175
242298
pub fn compute_scale(ppem: u16, units_per_em: u16) -> i64 {
176
242298
    if units_per_em == 0 {
177
        return 0;
178
242298
    }
179
    // We want: funits * ppem * 64 / units_per_em
180
    // Precompute: ppem * 64 * 65536 / units_per_em (as 16.16 fixed point)
181
    // Add upem/2 for proper rounding, matching FreeType's FT_DivFix.
182
242298
    let upem = units_per_em as i64;
183
242298
    (((ppem as i64) << 22) + (upem >> 1)) / upem
184
242298
}