1pub use super::layout::{Condition, CoverageTable};
4use super::variations::PackedDeltas;
5pub use crate::ps::cff::index::Index2;
6use crate::types::{F2Dot14, Matrix};
7
8#[cfg(feature = "libm")]
9#[allow(unused_imports)]
10use core_maths::*;
11
12include!("../../generated/generated_varc.rs");
13
14trait Get<'a> {
16 fn get(self, nth: usize) -> Result<&'a [u8], ReadError>;
17}
18
19impl<'a> Get<'a> for Option<Result<Index2<'a>, ReadError>> {
20 fn get(self, nth: usize) -> Result<&'a [u8], ReadError> {
21 self.transpose()?
22 .ok_or(ReadError::NullOffset)
23 .and_then(|index| index.get(nth).map_err(|_| ReadError::OutOfBounds))
24 }
25}
26
27impl Varc<'_> {
28 pub fn axis_indices(&self, nth: usize) -> Result<PackedDeltas<'_>, ReadError> {
30 let raw = self.axis_indices_list().get(nth)?;
31 Ok(PackedDeltas::consume_all(raw.into()))
32 }
33
34 pub fn glyph(&self, nth: usize) -> Result<VarcGlyph<'_>, ReadError> {
38 let raw = Some(self.var_composite_glyphs()).get(nth)?;
39 Ok(VarcGlyph {
40 table: self,
41 data: raw.into(),
42 })
43 }
44}
45
46impl SparseVariationRegion<'_> {
47 pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> f32 {
50 let mut scalar = 1.0f32;
51 for axis in self.region_axes() {
52 let peak = axis.peak();
53 if peak == F2Dot14::ZERO {
54 continue;
55 }
56 let axis_index = axis.axis_index() as usize;
57 let coord = coords.get(axis_index).copied().unwrap_or(F2Dot14::ZERO);
58 if coord == peak {
59 continue;
60 }
61 if coord == F2Dot14::ZERO {
62 return 0.0;
63 }
64 let start = axis.start();
65 let end = axis.end();
66 if start > peak || peak > end || (start < F2Dot14::ZERO && end > F2Dot14::ZERO) {
67 continue;
68 }
69 if coord < start || coord > end {
70 return 0.0;
71 } else if coord < peak {
72 let numerat = coord.to_bits() - start.to_bits();
74 if numerat == 0 {
75 return 0.0;
76 }
77 let denom = peak.to_bits() - start.to_bits();
78 scalar *= numerat as f32 / denom as f32;
79 } else {
80 let numerat = end.to_bits() - coord.to_bits();
82 if numerat == 0 {
83 return 0.0;
84 }
85 let denom = end.to_bits() - peak.to_bits();
86 scalar *= numerat as f32 / denom as f32;
87 }
88 }
89 scalar
90 }
91}
92
93pub struct VarcGlyph<'a> {
97 table: &'a Varc<'a>,
98 data: FontData<'a>,
99}
100
101impl<'a> VarcGlyph<'a> {
102 pub fn components(&self) -> impl Iterator<Item = Result<VarcComponent<'a>, ReadError>> {
104 VarcComponentIter {
105 table: self.table,
106 cursor: self.data.cursor(),
107 }
108 }
109}
110
111struct VarcComponentIter<'a> {
112 table: &'a Varc<'a>,
113 cursor: Cursor<'a>,
114}
115
116impl<'a> Iterator for VarcComponentIter<'a> {
117 type Item = Result<VarcComponent<'a>, ReadError>;
118
119 fn next(&mut self) -> Option<Self::Item> {
120 if self.cursor.is_empty() {
121 return None;
122 }
123 Some(VarcComponent::parse(self.table, &mut self.cursor))
124 }
125}
126
127pub struct VarcComponent<'a> {
128 flags: VarcFlags,
129 gid: GlyphId,
130 condition_index: Option<u32>,
131 axis_indices_index: Option<u32>,
132 axis_values: Option<PackedDeltas<'a>>,
133 axis_values_var_index: Option<u32>,
134 transform_var_index: Option<u32>,
135 transform: DecomposedTransform,
136}
137
138impl<'a> VarcComponent<'a> {
139 fn parse(table: &Varc, cursor: &mut Cursor<'a>) -> Result<Self, ReadError> {
143 let raw_flags = cursor.read_u32_var()?;
144 let flags = VarcFlags::from_bits_truncate(raw_flags);
145 let gid = if flags.contains(VarcFlags::GID_IS_24BIT) {
149 GlyphId::new(cursor.read::<Uint24>()?.to_u32())
150 } else {
151 GlyphId::from(cursor.read::<u16>()?)
152 };
153
154 let condition_index = if flags.contains(VarcFlags::HAVE_CONDITION) {
155 Some(cursor.read_u32_var()?)
156 } else {
157 None
158 };
159
160 let (axis_indices_index, axis_values) = if flags.contains(VarcFlags::HAVE_AXES) {
161 let axis_indices_index = cursor.read_u32_var()?;
163 let num_axis_values = table
164 .axis_indices(axis_indices_index as usize)?
165 .count_or_compute();
166 let deltas = if num_axis_values > 0 {
168 let Some(data) = cursor.remaining() else {
169 return Err(ReadError::OutOfBounds);
170 };
171 let deltas = PackedDeltas::new(data, num_axis_values);
172 *cursor = deltas.iter().end(); Some(deltas)
174 } else {
175 None
176 };
177 (Some(axis_indices_index), deltas)
178 } else {
179 (None, None)
180 };
181
182 let axis_values_var_index = if flags.contains(VarcFlags::AXIS_VALUES_HAVE_VARIATION) {
183 Some(cursor.read_u32_var()?)
184 } else {
185 None
186 };
187
188 let transform_var_index = if flags.contains(VarcFlags::TRANSFORM_HAS_VARIATION) {
189 Some(cursor.read_u32_var()?)
190 } else {
191 None
192 };
193
194 let mut transform = DecomposedTransform::default();
195 if flags.intersects(VarcFlags::HAVE_TRANSLATE_X | VarcFlags::HAVE_TRANSLATE_Y) {
196 if flags.contains(VarcFlags::HAVE_TRANSLATE_X) {
197 transform.translate_x = cursor.read::<FWord>()?.to_i16() as f32
198 }
199 if flags.contains(VarcFlags::HAVE_TRANSLATE_Y) {
200 transform.translate_y = cursor.read::<FWord>()?.to_i16() as f32
201 }
202 }
203 if flags.contains(VarcFlags::HAVE_ROTATION) {
204 transform.rotation = cursor.read::<F4Dot12>()?.to_f32()
205 }
206 if flags.intersects(VarcFlags::HAVE_SCALE_X | VarcFlags::HAVE_SCALE_Y) {
207 if flags.contains(VarcFlags::HAVE_SCALE_X) {
208 transform.scale_x = cursor.read::<F6Dot10>()?.to_f32()
209 }
210 transform.scale_y = if flags.contains(VarcFlags::HAVE_SCALE_Y) {
211 cursor.read::<F6Dot10>()?.to_f32()
212 } else {
213 transform.scale_x
214 };
215 }
216 if flags.intersects(VarcFlags::HAVE_SKEW_X | VarcFlags::HAVE_SKEW_Y) {
219 if flags.contains(VarcFlags::HAVE_SKEW_X) {
220 transform.skew_x = cursor.read::<F4Dot12>()?.to_f32()
221 }
222 if flags.contains(VarcFlags::HAVE_SKEW_Y) {
223 transform.skew_y = cursor.read::<F4Dot12>()?.to_f32()
224 }
225 }
226 if flags.intersects(VarcFlags::HAVE_TCENTER_X | VarcFlags::HAVE_TCENTER_Y) {
227 if flags.contains(VarcFlags::HAVE_TCENTER_X) {
228 transform.center_x = cursor.read::<FWord>()?.to_i16() as f32
229 }
230 if flags.contains(VarcFlags::HAVE_TCENTER_Y) {
231 transform.center_y = cursor.read::<FWord>()?.to_i16() as f32
232 }
233 }
234
235 let reserved = raw_flags & VarcFlags::RESERVED_MASK.bits;
237 if reserved != 0 {
238 let num_reserved = reserved.count_ones();
239 for _ in 0..num_reserved {
240 cursor.read_u32_var()?;
241 }
242 }
243 Ok(VarcComponent {
244 flags,
245 gid,
246 condition_index,
247 axis_indices_index,
248 axis_values,
249 axis_values_var_index,
250 transform_var_index,
251 transform,
252 })
253 }
254
255 pub fn flags(&self) -> VarcFlags {
256 self.flags
257 }
258 pub fn gid(&self) -> GlyphId {
259 self.gid
260 }
261 pub fn condition_index(&self) -> Option<u32> {
262 self.condition_index
263 }
264 pub fn transform(&self) -> &DecomposedTransform {
265 &self.transform
266 }
267 pub fn axis_indices_index(&self) -> Option<u32> {
268 self.axis_indices_index
269 }
270 pub fn axis_values(&self) -> Option<&PackedDeltas<'a>> {
271 self.axis_values.as_ref()
272 }
273 pub fn axis_values_var_index(&self) -> Option<u32> {
274 self.axis_values_var_index
275 }
276 pub fn transform_var_index(&self) -> Option<u32> {
277 self.transform_var_index
278 }
279}
280
281#[derive(Clone, Copy)]
283pub struct DecomposedTransform {
284 translate_x: f32,
285 translate_y: f32,
286 rotation: f32, scale_x: f32,
288 scale_y: f32,
289 skew_x: f32, skew_y: f32, center_x: f32,
292 center_y: f32,
293}
294
295impl Default for DecomposedTransform {
296 fn default() -> Self {
297 Self {
298 translate_x: 0.0,
299 translate_y: 0.0,
300 rotation: 0.0,
301 scale_x: 1.0,
302 scale_y: 1.0,
303 skew_x: 0.0,
304 skew_y: 0.0,
305 center_x: 0.0,
306 center_y: 0.0,
307 }
308 }
309}
310
311impl DecomposedTransform {
312 pub fn translate_x(&self) -> f32 {
313 self.translate_x
314 }
315
316 pub fn translate_y(&self) -> f32 {
317 self.translate_y
318 }
319
320 pub fn rotation(&self) -> f32 {
321 self.rotation
322 }
323
324 pub fn scale_x(&self) -> f32 {
325 self.scale_x
326 }
327
328 pub fn scale_y(&self) -> f32 {
329 self.scale_y
330 }
331
332 pub fn skew_x(&self) -> f32 {
333 self.skew_x
334 }
335
336 pub fn skew_y(&self) -> f32 {
337 self.skew_y
338 }
339
340 pub fn center_x(&self) -> f32 {
341 self.center_x
342 }
343
344 pub fn center_y(&self) -> f32 {
345 self.center_y
346 }
347
348 pub fn set_translate_x(&mut self, value: f32) {
349 self.translate_x = value;
350 }
351
352 pub fn set_translate_y(&mut self, value: f32) {
353 self.translate_y = value;
354 }
355
356 pub fn set_rotation(&mut self, value: f32) {
357 self.rotation = value;
358 }
359
360 pub fn set_scale_x(&mut self, value: f32) {
361 self.scale_x = value;
362 }
363
364 pub fn set_scale_y(&mut self, value: f32) {
365 self.scale_y = value;
366 }
367
368 pub fn set_skew_x(&mut self, value: f32) {
369 self.skew_x = value;
370 }
371
372 pub fn set_skew_y(&mut self, value: f32) {
373 self.skew_y = value;
374 }
375
376 pub fn set_center_x(&mut self, value: f32) {
377 self.center_x = value;
378 }
379
380 pub fn set_center_y(&mut self, value: f32) {
381 self.center_y = value;
382 }
383
384 pub fn matrix(&self) -> Matrix<f32> {
402 let mut transform = Matrix::IDENTITY;
404 transform.dx = self.translate_x + self.center_x;
405 transform.dy = self.translate_y + self.center_y;
406
407 if self.rotation != 0.0 {
412 let (s, c) = (self.rotation * core::f32::consts::PI).sin_cos();
413 transform *= Matrix::from_elements([c, s, -s, c, 0.0, 0.0]);
414 }
415
416 if (self.scale_x, self.scale_y) != (1.0, 1.0) {
418 transform *= Matrix::from_elements([self.scale_x, 0.0, 0.0, self.scale_y, 0.0, 0.0]);
419 }
420
421 if (self.skew_x, self.skew_y) != (0.0, 0.0) {
423 transform *= Matrix::from_elements([
424 1.0,
425 (self.skew_y * core::f32::consts::PI).tan(),
426 (-self.skew_x * core::f32::consts::PI).tan(),
427 1.0,
428 0.0,
429 0.0,
430 ])
431 }
432
433 if (self.center_x, self.center_y) != (0.0, 0.0) {
435 transform *=
436 Matrix::from_elements([1.0, 0.0, 0.0, 1.0, -self.center_x, -self.center_y]);
437 }
438
439 transform
440 }
441}
442
443impl<'a> MultiItemVariationData<'a> {
444 pub fn delta_sets(&self) -> Result<Index2<'a>, ReadError> {
446 Index2::read(self.raw_delta_sets().into())
447 }
448
449 pub fn delta_set(&self, i: usize) -> Result<PackedDeltas<'a>, ReadError> {
453 let index = self.delta_sets()?;
454 let raw_deltas = index.get(i).map_err(|_| ReadError::OutOfBounds)?;
455 Ok(PackedDeltas::consume_all(raw_deltas.into()))
456 }
457}
458
459#[cfg(test)]
460mod tests {
461 use types::GlyphId16;
462
463 use crate::types::F2Dot14;
464 use crate::FontData;
465 use crate::{FontRef, ReadError, TableProvider};
466
467 use super::{Condition, DecomposedTransform, Varc};
468
469 impl Varc<'_> {
470 fn conditions(&self) -> impl Iterator<Item = Condition<'_>> {
471 self.condition_list()
472 .expect("A condition list is present")
473 .expect("We could read the condition list")
474 .conditions()
475 .iter()
476 .enumerate()
477 .map(|(i, c)| c.unwrap_or_else(|e| panic!("condition {i} {e}")))
478 }
479
480 fn axis_indices_count(&self) -> Result<usize, ReadError> {
481 let Some(axis_indices_list) = self.axis_indices_list() else {
482 return Ok(0);
483 };
484 let axis_indices_list = axis_indices_list?;
485 Ok(axis_indices_list.count() as usize)
486 }
487 }
488
489 fn round6(v: f32) -> f32 {
490 (v * 1_000_000.0).round() / 1_000_000.0
491 }
492
493 fn coord(value: f32) -> F2Dot14 {
494 F2Dot14::from_f32(value)
495 }
496
497 fn assert_close(actual: f32, expected: f32) {
498 let diff = (actual - expected).abs();
499 assert!(
500 diff <= 1e-6,
501 "expected {expected}, got {actual}, diff {diff}"
502 );
503 }
504
505 fn sfnt_table_range(data: &[u8], tag: [u8; 4]) -> (usize, usize) {
506 let font = FontRef::new(data).unwrap();
507 if let Some(rec) = font
508 .table_directory()
509 .table_records()
510 .iter()
511 .find(|rec| rec.tag() == tag)
512 {
513 return (rec.offset() as usize, rec.length() as usize);
514 }
515 panic!(
516 "missing table {:?}",
517 core::str::from_utf8(&tag).unwrap_or("????")
518 );
519 }
520
521 fn write_be_u32(dst: &mut [u8], value: u32) {
522 dst.copy_from_slice(&value.to_be_bytes());
523 }
524
525 fn read_be_u32(src: &[u8]) -> u32 {
526 u32::from_be_bytes([src[0], src[1], src[2], src[3]])
527 }
528
529 fn encode_u32_var(value: u32) -> Vec<u8> {
530 if value < 0x80 {
531 vec![value as u8]
532 } else if value < 0x4000 {
533 vec![0x80 | ((value >> 8) as u8), value as u8]
534 } else if value < 0x20_0000 {
535 vec![
536 0xC0 | ((value >> 16) as u8),
537 (value >> 8) as u8,
538 value as u8,
539 ]
540 } else if value < 0x1000_0000 {
541 vec![
542 0xE0 | ((value >> 24) as u8),
543 (value >> 16) as u8,
544 (value >> 8) as u8,
545 value as u8,
546 ]
547 } else {
548 vec![
549 0xF0,
550 (value >> 24) as u8,
551 (value >> 16) as u8,
552 (value >> 8) as u8,
553 value as u8,
554 ]
555 }
556 }
557
558 #[test]
559 fn read_cjk_0x6868() {
560 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
561 let table = font.varc().unwrap();
562 table.coverage().unwrap(); }
564
565 #[test]
566 fn identify_all_conditional_types() {
567 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
568 let table = font.varc().unwrap();
569
570 assert_eq!(
572 (1..=5).collect::<Vec<_>>(),
573 table.conditions().map(|c| c.format()).collect::<Vec<_>>()
574 );
575 }
576
577 #[test]
578 fn read_condition_format1_axis_range() {
579 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
580 let table = font.varc().unwrap();
581 let Some(Condition::Format1AxisRange(condition)) =
582 table.conditions().find(|c| c.format() == 1)
583 else {
584 panic!("No such item");
585 };
586
587 assert_eq!(
588 (0, 0.5, 1.0),
589 (
590 condition.axis_index(),
591 condition.filter_range_min_value().to_f32(),
592 condition.filter_range_max_value().to_f32(),
593 )
594 );
595 }
596
597 #[test]
598 fn read_condition_format2_variable_value() {
599 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
600 let table = font.varc().unwrap();
601 let Some(Condition::Format2VariableValue(condition)) =
602 table.conditions().find(|c| c.format() == 2)
603 else {
604 panic!("No such item");
605 };
606
607 assert_eq!((1, 2), (condition.default_value(), condition.var_index(),));
608 }
609
610 #[test]
611 fn read_condition_format3_and() {
612 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
613 let table = font.varc().unwrap();
614 let Some(Condition::Format3And(condition)) = table.conditions().find(|c| c.format() == 3)
615 else {
616 panic!("No such item");
617 };
618
619 assert_eq!(
621 vec![1, 2],
622 condition
623 .conditions()
624 .iter()
625 .map(|c| c.unwrap().format())
626 .collect::<Vec<_>>()
627 );
628 }
629
630 #[test]
631 fn read_condition_format4_or() {
632 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
633 let table = font.varc().unwrap();
634 let Some(Condition::Format4Or(condition)) = table.conditions().find(|c| c.format() == 4)
635 else {
636 panic!("No such item");
637 };
638
639 assert_eq!(
641 vec![1, 2],
642 condition
643 .conditions()
644 .iter()
645 .map(|c| c.unwrap().format())
646 .collect::<Vec<_>>()
647 );
648 }
649
650 #[test]
651 fn read_condition_format5_negate() {
652 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
653 let table = font.varc().unwrap();
654 let Some(Condition::Format5Negate(condition)) =
655 table.conditions().find(|c| c.format() == 5)
656 else {
657 panic!("No such item");
658 };
659
660 assert_eq!(1, condition.condition().unwrap().format(),);
662 }
663
664 #[test]
665 fn read_axis_indices_list() {
666 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
667 let table = font.varc().unwrap();
668 assert_eq!(table.axis_indices_count().unwrap(), 2);
669 assert_eq!(
670 vec![2, 3, 4, 5, 6],
671 table.axis_indices(1).unwrap().iter().collect::<Vec<_>>()
672 );
673 }
674
675 #[test]
676 fn compute_sparse_region_scalar_handles_boundaries_and_products() {
677 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
678 let varc = font.varc().unwrap();
679 let store = varc.multi_var_store().unwrap().unwrap();
680 let regions = store.region_list().unwrap();
681 let region_list = regions.regions();
682
683 let axis0_region = region_list.get(0).unwrap();
684 assert_close(axis0_region.compute_scalar_f32(&[coord(1.0)]), 1.0);
685 assert_close(axis0_region.compute_scalar_f32(&[coord(0.5)]), 0.5);
686 assert_close(axis0_region.compute_scalar_f32(&[F2Dot14::ZERO]), 0.0);
687 assert_close(axis0_region.compute_scalar_f32(&[]), 0.0);
688 assert_close(axis0_region.compute_scalar_f32(&[coord(-0.25)]), 0.0);
689
690 let axis0_axis1_region = region_list.get(2).unwrap();
691 assert_close(
692 axis0_axis1_region.compute_scalar_f32(&[coord(0.5), coord(0.25)]),
693 0.125,
694 );
695 }
696
697 #[test]
698 fn axis_indices_offset_out_of_bounds_errors() {
699 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
700 let (varc_offset, varc_len) = sfnt_table_range(&bytes, *b"VARC");
701 let axis_indices_offset = varc_offset + 16;
703 write_be_u32(
704 &mut bytes[axis_indices_offset..axis_indices_offset + 4],
705 (varc_len as u32).saturating_add(8),
706 );
707
708 let font = FontRef::new(&bytes).unwrap();
709 let table = font.varc().unwrap();
710 assert!(matches!(table.axis_indices(0), Err(ReadError::OutOfBounds)));
711 }
712
713 #[test]
714 fn var_composite_glyphs_offset_out_of_bounds_errors() {
715 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
716 let (varc_offset, varc_len) = sfnt_table_range(&bytes, *b"VARC");
717 let glyphs_offset = varc_offset + 20;
719 write_be_u32(
720 &mut bytes[glyphs_offset..glyphs_offset + 4],
721 (varc_len as u32).saturating_add(8),
722 );
723
724 let font = FontRef::new(&bytes).unwrap();
725 let table = font.varc().unwrap();
726 assert!(matches!(table.glyph(0), Err(ReadError::OutOfBounds)));
727 }
728
729 #[test]
730 fn parse_component_with_missing_translate_data_errors() {
731 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
732 let table = font.varc().unwrap();
733 let data = FontData::new(&[0x10, 0x00, 0x01]);
735 let mut cursor = data.cursor();
736 assert!(matches!(
737 super::VarcComponent::parse(&table, &mut cursor),
738 Err(ReadError::OutOfBounds)
739 ));
740 }
741
742 #[test]
743 fn parse_component_with_invalid_axis_indices_index_errors() {
744 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
745 let table = font.varc().unwrap();
746 let data = FontData::new(&[0x02, 0x00, 0x01, 0x7F]);
748 let mut cursor = data.cursor();
749 assert!(matches!(
750 super::VarcComponent::parse(&table, &mut cursor),
751 Err(ReadError::OutOfBounds)
752 ));
753 }
754
755 #[test]
756 fn parse_component_reserved_fields_are_consumed() {
757 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
758 let table = font.varc().unwrap();
759 let flags = 0x0001_8010_u32;
761 let mut bytes = Vec::new();
762 bytes.extend_from_slice(&encode_u32_var(flags));
763 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&[0x00, 0x07]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.extend_from_slice(&encode_u32_var(2)); bytes.push(0xAA); let data = FontData::new(&bytes);
769 let mut cursor = data.cursor();
770
771 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
772 assert_eq!(component.transform().translate_x(), 7.0);
773 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
774 }
775
776 #[test]
777 fn parse_component_reserved_fields_truncation_errors() {
778 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
779 let table = font.varc().unwrap();
780 let flags = 0x0001_8010_u32;
782 let mut bytes = Vec::new();
783 bytes.extend_from_slice(&encode_u32_var(flags));
784 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&[0x00, 0x07]); bytes.extend_from_slice(&encode_u32_var(1)); let data = FontData::new(&bytes);
788 let mut cursor = data.cursor();
789
790 assert!(matches!(
791 super::VarcComponent::parse(&table, &mut cursor),
792 Err(ReadError::OutOfBounds)
793 ));
794 }
795
796 #[test]
797 fn parse_component_gid_is_24bit_path() {
798 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
799 let table = font.varc().unwrap();
800 let mut bytes = Vec::new();
801 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::GID_IS_24BIT.bits()));
802 bytes.extend_from_slice(&[0x12, 0x34, 0x56]);
803 bytes.push(0xAA); let data = FontData::new(&bytes);
805 let mut cursor = data.cursor();
806
807 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
808 assert_eq!(component.gid().to_u32(), 0x12_34_56);
809 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
810 }
811
812 #[test]
813 fn parse_component_gid_is_24bit_truncation_errors() {
814 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
815 let table = font.varc().unwrap();
816 let mut bytes = Vec::new();
817 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::GID_IS_24BIT.bits()));
818 bytes.extend_from_slice(&[0x12, 0x34]); let data = FontData::new(&bytes);
820 let mut cursor = data.cursor();
821
822 assert!(matches!(
823 super::VarcComponent::parse(&table, &mut cursor),
824 Err(ReadError::OutOfBounds)
825 ));
826 }
827
828 #[test]
829 fn parse_component_with_axes_zero_count_does_not_consume_axis_values() {
830 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
831 let (varc_offset, _) = sfnt_table_range(&bytes, *b"VARC");
832 let axis_indices_rel = read_be_u32(&bytes[varc_offset + 16..varc_offset + 20]) as usize;
833 let axis_indices_abs = varc_offset + axis_indices_rel;
834 bytes[axis_indices_abs..axis_indices_abs + 7]
837 .copy_from_slice(&[0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01]);
838 let font = FontRef::new(&bytes).unwrap();
839 let table = font.varc().unwrap();
840 assert_eq!(table.axis_indices(0).unwrap().count_or_compute(), 0);
841
842 let mut bytes = Vec::new();
844 bytes.extend_from_slice(&encode_u32_var(0x12));
845 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(0)); bytes.extend_from_slice(&[0x00, 0x05]); bytes.push(0xAA); let data = FontData::new(&bytes);
850 let mut cursor = data.cursor();
851
852 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
853 assert_eq!(component.transform().translate_x(), 5.0);
854 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
855 }
856
857 #[test]
858 fn parse_component_with_axes_nonzero_count_consumes_axis_values() {
859 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
860 let table = font.varc().unwrap();
861 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
862
863 let mut bytes = Vec::new();
865 bytes.extend_from_slice(&encode_u32_var(0x12));
866 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.push(0x04); bytes.extend_from_slice(&[1, 2, 3, 4, 5]); bytes.extend_from_slice(&[0x00, 0x09]); bytes.push(0xAA); let data = FontData::new(&bytes);
873 let mut cursor = data.cursor();
874
875 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
876 assert_eq!(component.transform().translate_x(), 9.0);
877 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
878 }
879
880 #[test]
881 fn parse_component_scale_x_only_applies_to_scale_y() {
882 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
883 let table = font.varc().unwrap();
884 let mut bytes = Vec::new();
885 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_SCALE_X.bits()));
886 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&[0x08, 0x00]); bytes.push(0xAA); let data = FontData::new(&bytes);
890 let mut cursor = data.cursor();
891
892 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
893 assert_eq!(component.transform().scale_x(), 2.0);
894 assert_eq!(component.transform().scale_y(), 2.0);
895 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
896 }
897
898 #[test]
899 fn parse_component_scale_x_and_scale_y_are_independent() {
900 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
901 let table = font.varc().unwrap();
902 let flags = super::VarcFlags::HAVE_SCALE_X.bits() | super::VarcFlags::HAVE_SCALE_Y.bits();
903 let mut bytes = Vec::new();
904 bytes.extend_from_slice(&encode_u32_var(flags));
905 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&[0x08, 0x00]); bytes.extend_from_slice(&[0x0C, 0x00]); bytes.push(0xAA); let data = FontData::new(&bytes);
910 let mut cursor = data.cursor();
911
912 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
913 assert_eq!(component.transform().scale_x(), 2.0);
914 assert_eq!(component.transform().scale_y(), 3.0);
915 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
916 }
917
918 #[test]
919 fn parse_component_multibyte_condition_and_var_indices() {
920 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
921 let table = font.varc().unwrap();
922 let flags = super::VarcFlags::HAVE_CONDITION.bits()
923 | super::VarcFlags::AXIS_VALUES_HAVE_VARIATION.bits()
924 | super::VarcFlags::TRANSFORM_HAS_VARIATION.bits()
925 | super::VarcFlags::HAVE_TRANSLATE_X.bits();
926 let mut bytes = Vec::new();
927 bytes.extend_from_slice(&encode_u32_var(flags));
928 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(0x2345)); bytes.extend_from_slice(&encode_u32_var(0x0123)); bytes.extend_from_slice(&encode_u32_var(0x0222)); bytes.extend_from_slice(&[0x00, 0x07]); bytes.push(0xAA); let data = FontData::new(&bytes);
935 let mut cursor = data.cursor();
936
937 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
938 assert_eq!(component.condition_index(), Some(0x2345));
939 assert_eq!(component.axis_values_var_index(), Some(0x0123));
940 assert_eq!(component.transform_var_index(), Some(0x0222));
941 assert_eq!(component.transform().translate_x(), 7.0);
942 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
943 }
944
945 #[test]
946 fn parse_component_truncated_multibyte_condition_index_errors() {
947 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
948 let table = font.varc().unwrap();
949 let mut bytes = Vec::new();
950 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_CONDITION.bits()));
951 bytes.extend_from_slice(&[0x00, 0x01]); bytes.push(0x81); let data = FontData::new(&bytes);
954 let mut cursor = data.cursor();
955
956 assert!(matches!(
957 super::VarcComponent::parse(&table, &mut cursor),
958 Err(ReadError::OutOfBounds)
959 ));
960 }
961
962 #[test]
963 fn parse_component_axes_with_var_index_and_zero_axis_count() {
964 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
965 let (varc_offset, _) = sfnt_table_range(&bytes, *b"VARC");
966 let axis_indices_rel = read_be_u32(&bytes[varc_offset + 16..varc_offset + 20]) as usize;
967 let axis_indices_abs = varc_offset + axis_indices_rel;
968 bytes[axis_indices_abs..axis_indices_abs + 7]
970 .copy_from_slice(&[0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01]);
971 let font = FontRef::new(&bytes).unwrap();
972 let table = font.varc().unwrap();
973
974 let flags = super::VarcFlags::HAVE_AXES.bits()
975 | super::VarcFlags::AXIS_VALUES_HAVE_VARIATION.bits()
976 | super::VarcFlags::HAVE_TRANSLATE_X.bits();
977 let mut bytes = Vec::new();
978 bytes.extend_from_slice(&encode_u32_var(flags));
979 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(0)); bytes.extend_from_slice(&encode_u32_var(0x0123)); bytes.extend_from_slice(&[0x00, 0x06]); bytes.push(0xAA); let data = FontData::new(&bytes);
985 let mut cursor = data.cursor();
986
987 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
988 assert_eq!(component.axis_indices_index(), Some(0));
989 assert!(component.axis_values().is_none());
990 assert_eq!(component.axis_values_var_index(), Some(0x0123));
991 assert_eq!(component.transform().translate_x(), 6.0);
992 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
993 }
994
995 #[test]
996 fn parse_component_axes_truncated_i16_payload_detected_on_fetch() {
997 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
998 let table = font.varc().unwrap();
999 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
1000
1001 let mut bytes = Vec::new();
1003 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_AXES.bits()));
1004 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.push(0x44); bytes.extend_from_slice(&[0x00, 0x01, 0x00, 0x02, 0x00, 0x03]); let data = FontData::new(&bytes);
1009 let mut cursor = data.cursor();
1010
1011 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1012 let mut out = [0.0; 5];
1013 assert!(matches!(
1014 component
1015 .axis_values()
1016 .unwrap()
1017 .fetcher()
1018 .add_to_f32_scaled(&mut out, 1.0),
1019 Err(ReadError::OutOfBounds)
1020 ));
1021 }
1022
1023 #[test]
1024 fn parse_component_axes_truncated_i32_payload_detected_on_fetch() {
1025 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
1026 let table = font.varc().unwrap();
1027 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
1028
1029 let mut bytes = Vec::new();
1031 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_AXES.bits()));
1032 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.push(0xC4); bytes.extend_from_slice(&[
1036 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
1038 ]);
1039 let data = FontData::new(&bytes);
1040 let mut cursor = data.cursor();
1041
1042 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1043 let mut out = [0.0; 5];
1044 assert!(matches!(
1045 component
1046 .axis_values()
1047 .unwrap()
1048 .fetcher()
1049 .add_to_f32_scaled(&mut out, 1.0),
1050 Err(ReadError::OutOfBounds)
1051 ));
1052 }
1053
1054 #[test]
1055 fn parse_component_axes_payload_overshoot_causes_following_field_error() {
1056 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
1057 let table = font.varc().unwrap();
1058 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
1059
1060 let mut bytes = Vec::new();
1062 bytes.extend_from_slice(&encode_u32_var(
1063 super::VarcFlags::HAVE_AXES.bits() | super::VarcFlags::HAVE_TRANSLATE_X.bits(),
1064 ));
1065 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.push(0x44); bytes.extend_from_slice(&[0x00, 0x01, 0x00, 0x02]); bytes.extend_from_slice(&[0x00, 0x09]); let data = FontData::new(&bytes);
1071 let mut cursor = data.cursor();
1072
1073 assert!(matches!(
1074 super::VarcComponent::parse(&table, &mut cursor),
1075 Err(ReadError::OutOfBounds)
1076 ));
1077 }
1078
1079 #[test]
1080 fn generated_condition_varints_roundtrip() {
1081 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1082 let table = font.varc().unwrap();
1083 let mut state = 0x1234_5678_u32;
1084 for _ in 0..256 {
1085 state ^= state << 13;
1087 state ^= state >> 17;
1088 state ^= state << 5;
1089 let value = state;
1090
1091 let mut bytes = Vec::new();
1092 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_CONDITION.bits()));
1093 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(value));
1095 bytes.push(0xAA); let data = FontData::new(&bytes);
1097 let mut cursor = data.cursor();
1098
1099 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1100 assert_eq!(component.condition_index(), Some(value));
1101 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
1102 }
1103 }
1104
1105 #[test]
1106 fn generated_axis_values_single_run_roundtrip() {
1107 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
1108 let table = font.varc().unwrap();
1109 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
1110
1111 let mut state = 0xA5A5_5A5A_u32;
1112 for _ in 0..128 {
1113 state ^= state << 13;
1115 state ^= state >> 17;
1116 state ^= state << 5;
1117 let run_kind = state & 3;
1118
1119 let mut payload = Vec::new();
1120 let mut expected = [0f32; 5];
1121 match run_kind {
1122 0 => {
1123 payload.push(0x04);
1125 for out in &mut expected {
1126 state = state.wrapping_mul(1664525).wrapping_add(1013904223);
1127 let v = ((state >> 24) as i8) % 64;
1128 payload.push(v as u8);
1129 *out = v as f32;
1130 }
1131 }
1132 1 => {
1133 payload.push(0x44);
1135 for out in &mut expected {
1136 state = state.wrapping_mul(1664525).wrapping_add(1013904223);
1137 let v = ((state >> 16) as i16) % 2048;
1138 payload.extend_from_slice(&v.to_be_bytes());
1139 *out = v as f32;
1140 }
1141 }
1142 2 => {
1143 payload.push(0xC4);
1145 for out in &mut expected {
1146 state = state.wrapping_mul(1664525).wrapping_add(1013904223);
1147 let v = (state as i32) % 1_000_000;
1148 payload.extend_from_slice(&v.to_be_bytes());
1149 *out = v as f32;
1150 }
1151 }
1152 _ => {
1153 payload.push(0x84);
1155 }
1156 }
1157
1158 let mut bytes = Vec::new();
1159 bytes.extend_from_slice(&encode_u32_var(
1160 super::VarcFlags::HAVE_AXES.bits() | super::VarcFlags::HAVE_TRANSLATE_X.bits(),
1161 ));
1162 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.extend_from_slice(&payload);
1165 bytes.extend_from_slice(&[0x00, 0x07]); bytes.push(0xAA); let data = FontData::new(&bytes);
1169 let mut cursor = data.cursor();
1170 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1171 let mut out = [0.0f32; 5];
1172 component
1173 .axis_values()
1174 .unwrap()
1175 .fetcher()
1176 .add_to_f32_scaled(&mut out, 1.0)
1177 .unwrap();
1178 assert_eq!(out, expected);
1179 assert_eq!(component.transform().translate_x(), 7.0);
1180 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
1181 }
1182 }
1183
1184 #[test]
1185 fn parse_component_truncated_condition_varint_boundaries_error() {
1186 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1187 let table = font.varc().unwrap();
1188 let values = [0x80_u32, 0x4000_u32, 0x20_0000_u32, 0x1000_0000_u32];
1189
1190 for value in values {
1191 let encoded = encode_u32_var(value);
1192 assert!(encoded.len() > 1);
1193 let truncated = &encoded[..encoded.len() - 1];
1194
1195 let mut bytes = Vec::new();
1196 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_CONDITION.bits()));
1197 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(truncated);
1199 let data = FontData::new(&bytes);
1200 let mut cursor = data.cursor();
1201
1202 assert!(matches!(
1203 super::VarcComponent::parse(&table, &mut cursor),
1204 Err(ReadError::OutOfBounds)
1205 ));
1206 }
1207 }
1208
1209 #[test]
1210 fn read_glyph_6868() {
1211 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1212 let gid = font.cmap().unwrap().map_codepoint(0x6868_u32).unwrap();
1213 let table = font.varc().unwrap();
1214 let idx = table.coverage().unwrap().get(gid).unwrap();
1215
1216 let glyph = table.glyph(idx as usize).unwrap();
1217 assert_eq!(
1218 vec![GlyphId16::new(2), GlyphId16::new(5), GlyphId16::new(7)],
1219 glyph
1220 .components()
1221 .map(|c| c.unwrap().gid)
1222 .collect::<Vec<_>>()
1223 );
1224 }
1225
1226 #[test]
1228 fn decomposed_scale_to_matrix() {
1229 let scale_x = 2.0;
1230 let scale_y = 3.0;
1231 assert_eq!(
1232 [scale_x, 0.0, 0.0, scale_y, 0.0, 0.0],
1233 DecomposedTransform {
1234 scale_x,
1235 scale_y,
1236 ..Default::default()
1237 }
1238 .matrix()
1239 .map(round6)
1240 .elements()
1241 );
1242 }
1243
1244 #[test]
1246 fn decomposed_rotate_to_matrix() {
1247 assert_eq!(
1248 [0.0, 1.0, -1.0, 0.0, 0.0, 0.0],
1249 DecomposedTransform {
1250 rotation: 0.5,
1252 ..Default::default()
1253 }
1254 .matrix()
1255 .map(round6)
1256 .elements()
1257 );
1258 }
1259
1260 #[test]
1262 fn decomposed_skew_to_matrix() {
1263 let skew_x: f32 = 1.0 / 6.0; let skew_y: f32 = -1.0 / 3.0; assert_eq!(
1267 [
1268 1.0,
1269 round6((skew_y * core::f32::consts::PI).tan()),
1270 round6((-skew_x * core::f32::consts::PI).tan()),
1271 1.0,
1272 0.0,
1273 0.0
1274 ],
1275 DecomposedTransform {
1276 skew_x,
1277 skew_y,
1278 ..Default::default()
1279 }
1280 .matrix()
1281 .map(round6)
1282 .elements()
1283 );
1284 }
1285
1286 #[test]
1288 fn decomposed_scale_rotate_to_matrix() {
1289 let scale_x = 2.0;
1290 let scale_y = 3.0;
1291 assert_eq!(
1292 [0.0, scale_x, -scale_y, 0.0, 0.0, 0.0],
1293 DecomposedTransform {
1294 scale_x,
1295 scale_y,
1296 rotation: 0.5,
1298 ..Default::default()
1299 }
1300 .matrix()
1301 .map(round6)
1302 .elements()
1303 );
1304 }
1305
1306 #[test]
1308 fn decomposed_scale_rotate_translate_to_matrix() {
1309 assert_eq!(
1310 [0.0, 2.0, -1.0, 0.0, 10.0, 20.0],
1311 DecomposedTransform {
1312 scale_x: 2.0,
1313 rotation: 0.5,
1315 translate_x: 10.0,
1316 translate_y: 20.0,
1317 ..Default::default()
1318 }
1319 .matrix()
1320 .map(round6)
1321 .elements()
1322 );
1323 }
1324
1325 #[test]
1327 fn decomposed_scale_skew_translate_to_matrix() {
1328 assert_eq!(
1329 [-0.866026, 5.5, -2.5, 2.020726, 10.0, 20.0],
1330 DecomposedTransform {
1331 scale_x: 2.0,
1332 scale_y: 3.0,
1333 rotation: 1.0 / 6.0, skew_x: 1.0 / 6.0, skew_y: 1.0 / 3.0, translate_x: 10.0,
1338 translate_y: 20.0,
1339 ..Default::default()
1340 }
1341 .matrix()
1342 .map(round6)
1343 .elements()
1344 );
1345 }
1346
1347 #[test]
1349 fn decomposed_rotate_around_to_matrix() {
1350 assert_eq!(
1351 [1.732051, 1.0, -0.5, 0.866025, 10.267949, 19.267949],
1352 DecomposedTransform {
1353 scale_x: 2.0,
1354 rotation: 1.0 / 6.0,
1356 translate_x: 10.0,
1357 translate_y: 20.0,
1358 center_x: 1.0,
1359 center_y: 2.0,
1360 ..Default::default()
1361 }
1362 .matrix()
1363 .map(round6)
1364 .elements()
1365 );
1366 }
1367
1368 #[test]
1369 fn read_multivar_store_region_list() {
1370 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1371 let table = font.varc().unwrap();
1372 let varstore = table.multi_var_store().unwrap().unwrap();
1373 let regions = varstore.region_list().unwrap().regions();
1374
1375 let sparse_regions = regions
1376 .iter()
1377 .map(|r| {
1378 r.unwrap()
1379 .region_axes()
1380 .iter()
1381 .map(|a| {
1382 (
1383 a.axis_index(),
1384 a.start().to_f32(),
1385 a.peak().to_f32(),
1386 a.end().to_f32(),
1387 )
1388 })
1389 .collect::<Vec<_>>()
1390 })
1391 .collect::<Vec<_>>();
1392
1393 assert_eq!(
1395 vec![
1396 vec![(0, 0.0, 1.0, 1.0),],
1397 vec![(0, 0.0, 1.0, 1.0), (1, 0.0, 1.0, 1.0),],
1398 vec![(6, -1.0, -1.0, 0.0),],
1399 ],
1400 [0, 2, 38]
1401 .into_iter()
1402 .map(|i| sparse_regions[i].clone())
1403 .collect::<Vec<_>>()
1404 );
1405 }
1406
1407 #[test]
1408 fn read_multivar_store_delta_sets() {
1409 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1410 let table = font.varc().unwrap();
1411 let varstore = table.multi_var_store().unwrap().unwrap();
1412 assert_eq!(
1413 vec![(3, 6), (33, 6), (10, 5), (25, 8),],
1414 varstore
1415 .variation_data()
1416 .iter()
1417 .map(|d| d.unwrap())
1418 .map(|d| (d.region_index_count(), d.delta_sets().unwrap().count()))
1419 .collect::<Vec<_>>()
1420 );
1421 assert_eq!(
1422 vec![-1, 33, 0, 0, 0, 0],
1423 varstore
1424 .variation_data()
1425 .get(0)
1426 .unwrap()
1427 .delta_set(5)
1428 .unwrap()
1429 .iter()
1430 .collect::<Vec<_>>()
1431 )
1432 }
1433}