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, weight) in cvar_data.active_tuples_at(&coords) {
208 for delta in tuple.deltas() {
209 let scaled_delta = delta.apply_scalar(weight);
210 deltas[delta.position as usize] += scaled_delta.to_bits();
211 }
212 }
213 assert_eq!(&deltas, expected_deltas);
214 }
215 }
216
217 #[test]
218 fn raw_tuple_deltas() {
219 let font = FontRef::new(font_test_data::CVAR).unwrap();
220 let cvar = font.cvar().unwrap();
221 let axis_count = font.fvar().unwrap().axis_count();
222 let cvar_data = cvar.variation_data(axis_count).unwrap();
223 let expected = [
227 &[(65, 8), (66, -8), (67, 8), (85, -11), (87, 0), (93, -1)],
228 &[(65, -2), (66, 8), (67, -7), (85, 11), (87, 0), (93, 1)],
229 &[(65, 56), (66, -24), (67, 42), (85, 6), (87, -10), (93, -4)],
230 &[
231 (65, -44),
232 (66, -66),
233 (67, -39),
234 (85, -28),
235 (87, -39),
236 (93, -22),
237 ],
238 &[(65, 22), (66, 100), (67, 36), (85, 19), (87, 36), (93, 19)],
239 &[(65, 8), (66, 0), (67, 8), (85, -43), (87, -49), (93, -32)],
240 &[(65, -8), (66, 0), (67, -8), (85, 11), (87, 9), (93, 1)],
241 &[(65, -80), (66, 0), (67, -90), (85, -6), (87, -47), (93, 4)],
242 &[(65, -16), (66, 0), (67, -21), (85, 28), (87, 39), (93, 22)],
243 &[
244 (65, -46),
245 (66, 0),
246 (67, -22),
247 (85, -19),
248 (87, 35),
249 (93, -19),
250 ],
251 &[(65, 2), (66, 0), (67, 7), (85, -11), (87, -9), (93, -1)],
252 ];
253 let mut count = 0;
254 for (tuple, expected) in cvar_data.tuples().zip(&expected) {
255 count += 1;
256 let deltas = tuple
257 .deltas()
258 .map(|delta| (delta.position, delta.value))
259 .collect::<Vec<_>>();
260 assert_eq!(&deltas, expected);
261 }
262 assert_eq!(count, expected.len());
263 }
264}