Skip to main content

font_types/
fword.rs

1//! 16-bit signed and unsigned font-units
2
3use super::{F48Dot16, Fixed};
4
5/// 16-bit signed quantity in font design units.
6#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern))]
9#[repr(transparent)]
10pub struct FWord(i16);
11
12/// 16-bit unsigned quantity in font design units.
13#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern))]
16#[repr(transparent)]
17pub struct UfWord(u16);
18
19impl FWord {
20    pub const fn new(raw: i16) -> Self {
21        Self(raw)
22    }
23
24    pub const fn to_i16(self) -> i16 {
25        self.0
26    }
27
28    /// Converts this number to a 16.16 fixed point value.
29    pub const fn to_fixed(self) -> Fixed {
30        Fixed::from_i32(self.0 as i32)
31    }
32
33    /// Applies an item variation delta, returning the varied value as a
34    /// single precision floating point number.
35    ///
36    /// A delta for a font unit valued target is already in font units, so
37    /// the accumulated 48.16 delta applies unscaled. The result is
38    /// intentionally not rounded back to an integer.
39    #[inline(always)]
40    pub fn apply_delta(self, delta: F48Dot16) -> f32 {
41        self.0 as f32 + delta.to_f64() as f32
42    }
43
44    /// The representation of this number as a big-endian byte array.
45    pub const fn to_be_bytes(self) -> [u8; 2] {
46        self.0.to_be_bytes()
47    }
48}
49
50impl UfWord {
51    pub const fn new(raw: u16) -> Self {
52        Self(raw)
53    }
54
55    pub const fn to_u16(self) -> u16 {
56        self.0
57    }
58
59    /// Converts this number to a 16.16 fixed point value.
60    pub const fn to_fixed(self) -> Fixed {
61        Fixed::from_i32(self.0 as i32)
62    }
63
64    /// Applies an item variation delta, returning the varied value as a
65    /// single precision floating point number.
66    ///
67    /// A delta for a font unit valued target is already in font units, so
68    /// the accumulated 48.16 delta applies unscaled. The result is
69    /// intentionally not rounded back to an integer.
70    #[inline(always)]
71    pub fn apply_delta(self, delta: F48Dot16) -> f32 {
72        self.0 as f32 + delta.to_f64() as f32
73    }
74
75    /// The representation of this number as a big-endian byte array.
76    pub const fn to_be_bytes(self) -> [u8; 2] {
77        self.0.to_be_bytes()
78    }
79}
80
81impl std::fmt::Display for FWord {
82    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
83        self.0.fmt(f)
84    }
85}
86
87impl std::fmt::Display for UfWord {
88    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
89        self.0.fmt(f)
90    }
91}
92
93impl From<u16> for UfWord {
94    fn from(src: u16) -> Self {
95        UfWord(src)
96    }
97}
98
99impl From<i16> for FWord {
100    fn from(src: i16) -> Self {
101        FWord(src)
102    }
103}
104
105impl From<FWord> for i16 {
106    fn from(src: FWord) -> Self {
107        src.0
108    }
109}
110
111impl From<UfWord> for u16 {
112    fn from(src: UfWord) -> Self {
113        src.0
114    }
115}
116
117crate::newtype_scalar!(FWord, [u8; 2]);
118crate::newtype_scalar!(UfWord, [u8; 2]);
119//TODO: we can add addition/etc as needed
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    /// Font unit targets take the accumulated delta unscaled, matching the
126    /// former `FloatItemDeltaTarget` impls in read-fonts these replaced.
127    #[test]
128    fn apply_delta() {
129        assert_eq!(FWord::new(100).apply_delta(F48Dot16::from_f64(2.5)), 102.5);
130        assert_eq!(
131            FWord::new(-100).apply_delta(F48Dot16::from_f64(-0.25)),
132            -100.25
133        );
134        assert_eq!(
135            UfWord::new(1000).apply_delta(F48Dot16::from_f64(-1.5)),
136            998.5
137        );
138        assert_eq!(UfWord::new(0).apply_delta(F48Dot16::ZERO), 0.0);
139    }
140}