1include!("../../generated/generated_cvar.rs");
5
6use super::variations::{
7 PackedPointNumbers, TupleDelta, TupleVariationCount, TupleVariationData, TupleVariationHeader,
8};
9
10pub type CvtVariationData<'a> = TupleVariationData<'a, CvtDelta>;
12
13impl<'a> Cvar<'a> {
14 pub fn variation_data(&self, axis_count: u16) -> Result<CvtVariationData<'a>, ReadError> {
20 let count = self.tuple_variation_count();
21 let data = self.data()?;
22 let header_data = self.raw_tuple_header_data();
23 let (shared_point_numbers, serialized_data) = if count.shared_point_numbers() {
25 let (packed, data) = PackedPointNumbers::split_off_front(data);
26 (Some(packed), data)
27 } else {
28 (None, data)
29 };
30 Ok(CvtVariationData {
31 tuple_count: count,
32 axis_count,
33 shared_tuples: None,
34 shared_point_numbers,
35 header_data,
36 serialized_data,
37 _marker: std::marker::PhantomData,
38 })
39 }
40
41 pub fn deltas(
51 &self,
52 axis_count: u16,
53 coords: &[F2Dot14],
54 deltas: &mut [i32],
55 ) -> Result<(), ReadError> {
56 let var_data = self.variation_data(axis_count)?;
57 for (tuple, scalar) in var_data.active_tuples_at(coords) {
58 for delta in tuple.deltas() {
59 let ix = delta.position as usize;
60 if let Some(value) = deltas.get_mut(ix) {
61 *value += delta.apply_scalar(scalar).to_bits();
62 }
63 }
64 }
65 Ok(())
66 }
67
68 fn raw_tuple_header_data(&self) -> FontData<'a> {
69 let range = self.shape.tuple_variation_headers_byte_range();
70 self.data.split_off(range.start).unwrap()
71 }
72}
73
74#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76pub struct CvtDelta {
77 pub position: u16,
79 pub value: i32,
81}
82
83impl CvtDelta {
84 pub fn apply_scalar(self, scalar: Fixed) -> Fixed {
86 Fixed::from_i32(self.value) * scalar
87 }
88}
89
90impl TupleDelta for CvtDelta {
91 fn is_point() -> bool {
92 false
93 }
94
95 fn new(position: u16, x: i32, _y: i32) -> Self {
96 Self { position, value: x }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use font_types::F2Dot14;
103
104 use crate::{FontRef, TableProvider};
105
106 #[test]
107 fn scaled_deltas() {
108 let font = FontRef::new(font_test_data::CVAR).unwrap();
109 let cases = &[
113 (
114 [0.5, 0.5],
115 [
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 720896, 3276800, 1179648, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 622592, 0, 1179648, 0, 0, 0, 0, 0, 622592,
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 ],
122 ),
123 (
124 [-0.5, 0.5],
125 [
126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1441792, -2162688, -1277952, 0, 0, 0,
129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -917504, 0, -1277952, 0, 0, 0, 0, 0,
130 -720896, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131 0, 0, 0,
132 ],
133 ),
134 (
135 [0.5, -0.5],
136 [
137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1900544, 2621440, 2129920, 0, 0, 0, 0,
140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 360448, 0, 1015808, 0, 0, 0, 0, 0,
141 524288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
142 0, 0,
143 ],
144 ),
145 (
146 [-0.5, -0.5],
147 [
148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1212416, -2293760, -1130496, 0, 0, 0,
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1097728, 0, -1277952, 0, 0, 0, 0, 0,
152 -737280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153 0, 0, 0,
154 ],
155 ),
156 (
157 [-1.0, -1.0],
158 [
159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2490368, -4325376, -2490368, 0, 0, 0,
162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1835008, 0, -2555904, 0, 0, 0, 0, 0,
163 -1441792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
164 0, 0, 0,
165 ],
166 ),
167 (
168 [1.0, 1.0],
169 [
170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1441792, 6553600, 2359296, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1245184, 0, 2359296, 0, 0, 0, 0, 0,
174 1245184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
175 0, 0, 0,
176 ],
177 ),
178 (
179 [-1.0, 1.0],
180 [
181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2883584, -4325376, -2555904, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1835008, 0, -2555904, 0, 0, 0, 0, 0,
185 -1441792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186 0, 0, 0,
187 ],
188 ),
189 (
190 [1.0, -1.0],
191 [
192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5636096, 4456448, 5636096, 0, 0, 0, 0,
195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 917504, 0, 1703936, 0, 0, 0, 0, 0,
196 917504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
197 0, 0,
198 ],
199 ),
200 ];
201 let cvar = font.cvar().unwrap();
202 let axis_count = font.fvar().unwrap().axis_count();
203 let cvar_data = cvar.variation_data(axis_count).unwrap();
204 for (coords, expected_deltas) in cases {
205 let coords = coords.map(F2Dot14::from_f32);
206 let mut deltas = vec![0; expected_deltas.len()];
207 for tuple in cvar_data.tuples() {
208 let Some(scalar) = tuple.compute_scalar(&coords) else {
209 continue;
210 };
211 for delta in tuple.deltas() {
212 let scaled_delta = delta.apply_scalar(scalar);
213 deltas[delta.position as usize] += scaled_delta.to_bits();
214 }
215 }
216 assert_eq!(&deltas, expected_deltas);
217 }
218 }
219
220 #[test]
221 fn raw_tuple_deltas() {
222 let font = FontRef::new(font_test_data::CVAR).unwrap();
223 let cvar = font.cvar().unwrap();
224 let axis_count = font.fvar().unwrap().axis_count();
225 let cvar_data = cvar.variation_data(axis_count).unwrap();
226 let expected = [
230 &[(65, 8), (66, -8), (67, 8), (85, -11), (87, 0), (93, -1)],
231 &[(65, -2), (66, 8), (67, -7), (85, 11), (87, 0), (93, 1)],
232 &[(65, 56), (66, -24), (67, 42), (85, 6), (87, -10), (93, -4)],
233 &[
234 (65, -44),
235 (66, -66),
236 (67, -39),
237 (85, -28),
238 (87, -39),
239 (93, -22),
240 ],
241 &[(65, 22), (66, 100), (67, 36), (85, 19), (87, 36), (93, 19)],
242 &[(65, 8), (66, 0), (67, 8), (85, -43), (87, -49), (93, -32)],
243 &[(65, -8), (66, 0), (67, -8), (85, 11), (87, 9), (93, 1)],
244 &[(65, -80), (66, 0), (67, -90), (85, -6), (87, -47), (93, 4)],
245 &[(65, -16), (66, 0), (67, -21), (85, 28), (87, 39), (93, 22)],
246 &[
247 (65, -46),
248 (66, 0),
249 (67, -22),
250 (85, -19),
251 (87, 35),
252 (93, -19),
253 ],
254 &[(65, 2), (66, 0), (67, 7), (85, -11), (87, -9), (93, -1)],
255 ];
256 let mut count = 0;
257 for (tuple, expected) in cvar_data.tuples().zip(&expected) {
258 count += 1;
259 let deltas = tuple
260 .deltas()
261 .map(|delta| (delta.position, delta.value))
262 .collect::<Vec<_>>();
263 assert_eq!(&deltas, expected);
264 }
265 assert_eq!(count, expected.len());
266 }
267}