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_TCENTER_X | VarcFlags::HAVE_TCENTER_Y) {
217 if flags.contains(VarcFlags::HAVE_TCENTER_X) {
218 transform.center_x = cursor.read::<FWord>()?.to_i16() as f32
219 }
220 if flags.contains(VarcFlags::HAVE_TCENTER_Y) {
221 transform.center_y = cursor.read::<FWord>()?.to_i16() as f32
222 }
223 }
224 if flags.intersects(VarcFlags::HAVE_SKEW_X | VarcFlags::HAVE_SKEW_Y) {
225 if flags.contains(VarcFlags::HAVE_SKEW_X) {
226 transform.skew_x = cursor.read::<F4Dot12>()?.to_f32()
227 }
228 if flags.contains(VarcFlags::HAVE_SKEW_Y) {
229 transform.skew_y = cursor.read::<F4Dot12>()?.to_f32()
230 }
231 }
232
233 let reserved = raw_flags & VarcFlags::RESERVED_MASK.bits;
235 if reserved != 0 {
236 let num_reserved = reserved.count_ones();
237 for _ in 0..num_reserved {
238 cursor.read_u32_var()?;
239 }
240 }
241 Ok(VarcComponent {
242 flags,
243 gid,
244 condition_index,
245 axis_indices_index,
246 axis_values,
247 axis_values_var_index,
248 transform_var_index,
249 transform,
250 })
251 }
252
253 pub fn flags(&self) -> VarcFlags {
254 self.flags
255 }
256 pub fn gid(&self) -> GlyphId {
257 self.gid
258 }
259 pub fn condition_index(&self) -> Option<u32> {
260 self.condition_index
261 }
262 pub fn transform(&self) -> &DecomposedTransform {
263 &self.transform
264 }
265 pub fn axis_indices_index(&self) -> Option<u32> {
266 self.axis_indices_index
267 }
268 pub fn axis_values(&self) -> Option<&PackedDeltas<'a>> {
269 self.axis_values.as_ref()
270 }
271 pub fn axis_values_var_index(&self) -> Option<u32> {
272 self.axis_values_var_index
273 }
274 pub fn transform_var_index(&self) -> Option<u32> {
275 self.transform_var_index
276 }
277}
278
279#[derive(Clone, Copy)]
281pub struct DecomposedTransform {
282 translate_x: f32,
283 translate_y: f32,
284 rotation: f32, scale_x: f32,
286 scale_y: f32,
287 skew_x: f32, skew_y: f32, center_x: f32,
290 center_y: f32,
291}
292
293impl Default for DecomposedTransform {
294 fn default() -> Self {
295 Self {
296 translate_x: 0.0,
297 translate_y: 0.0,
298 rotation: 0.0,
299 scale_x: 1.0,
300 scale_y: 1.0,
301 skew_x: 0.0,
302 skew_y: 0.0,
303 center_x: 0.0,
304 center_y: 0.0,
305 }
306 }
307}
308
309impl DecomposedTransform {
310 pub fn translate_x(&self) -> f32 {
311 self.translate_x
312 }
313
314 pub fn translate_y(&self) -> f32 {
315 self.translate_y
316 }
317
318 pub fn rotation(&self) -> f32 {
319 self.rotation
320 }
321
322 pub fn scale_x(&self) -> f32 {
323 self.scale_x
324 }
325
326 pub fn scale_y(&self) -> f32 {
327 self.scale_y
328 }
329
330 pub fn skew_x(&self) -> f32 {
331 self.skew_x
332 }
333
334 pub fn skew_y(&self) -> f32 {
335 self.skew_y
336 }
337
338 pub fn center_x(&self) -> f32 {
339 self.center_x
340 }
341
342 pub fn center_y(&self) -> f32 {
343 self.center_y
344 }
345
346 pub fn set_translate_x(&mut self, value: f32) {
347 self.translate_x = value;
348 }
349
350 pub fn set_translate_y(&mut self, value: f32) {
351 self.translate_y = value;
352 }
353
354 pub fn set_rotation(&mut self, value: f32) {
355 self.rotation = value;
356 }
357
358 pub fn set_scale_x(&mut self, value: f32) {
359 self.scale_x = value;
360 }
361
362 pub fn set_scale_y(&mut self, value: f32) {
363 self.scale_y = value;
364 }
365
366 pub fn set_skew_x(&mut self, value: f32) {
367 self.skew_x = value;
368 }
369
370 pub fn set_skew_y(&mut self, value: f32) {
371 self.skew_y = value;
372 }
373
374 pub fn set_center_x(&mut self, value: f32) {
375 self.center_x = value;
376 }
377
378 pub fn set_center_y(&mut self, value: f32) {
379 self.center_y = value;
380 }
381
382 pub fn matrix(&self) -> Matrix<f32> {
400 let mut transform = Matrix::IDENTITY;
402 transform.dx = self.translate_x + self.center_x;
403 transform.dy = self.translate_y + self.center_y;
404
405 if self.rotation != 0.0 {
410 let (s, c) = (self.rotation * core::f32::consts::PI).sin_cos();
411 transform *= Matrix::from_elements([c, s, -s, c, 0.0, 0.0]);
412 }
413
414 if (self.scale_x, self.scale_y) != (1.0, 1.0) {
416 transform *= Matrix::from_elements([self.scale_x, 0.0, 0.0, self.scale_y, 0.0, 0.0]);
417 }
418
419 if (self.skew_x, self.skew_y) != (0.0, 0.0) {
421 transform *= Matrix::from_elements([
422 1.0,
423 (self.skew_y * core::f32::consts::PI).tan(),
424 (-self.skew_x * core::f32::consts::PI).tan(),
425 1.0,
426 0.0,
427 0.0,
428 ])
429 }
430
431 if (self.center_x, self.center_y) != (0.0, 0.0) {
433 transform *=
434 Matrix::from_elements([1.0, 0.0, 0.0, 1.0, -self.center_x, -self.center_y]);
435 }
436
437 transform
438 }
439}
440
441impl<'a> MultiItemVariationData<'a> {
442 pub fn delta_sets(&self) -> Result<Index2<'a>, ReadError> {
444 Index2::read(self.raw_delta_sets().into())
445 }
446
447 pub fn delta_set(&self, i: usize) -> Result<PackedDeltas<'a>, ReadError> {
451 let index = self.delta_sets()?;
452 let raw_deltas = index.get(i).map_err(|_| ReadError::OutOfBounds)?;
453 Ok(PackedDeltas::consume_all(raw_deltas.into()))
454 }
455}
456
457#[cfg(test)]
458mod tests {
459 use types::GlyphId16;
460
461 use crate::types::F2Dot14;
462 use crate::FontData;
463 use crate::{FontRef, ReadError, TableProvider};
464
465 use super::{Condition, DecomposedTransform, Varc};
466
467 impl Varc<'_> {
468 fn conditions(&self) -> impl Iterator<Item = Condition<'_>> {
469 self.condition_list()
470 .expect("A condition list is present")
471 .expect("We could read the condition list")
472 .conditions()
473 .iter()
474 .enumerate()
475 .map(|(i, c)| c.unwrap_or_else(|e| panic!("condition {i} {e}")))
476 }
477
478 fn axis_indices_count(&self) -> Result<usize, ReadError> {
479 let Some(axis_indices_list) = self.axis_indices_list() else {
480 return Ok(0);
481 };
482 let axis_indices_list = axis_indices_list?;
483 Ok(axis_indices_list.count() as usize)
484 }
485 }
486
487 fn round6(v: f32) -> f32 {
488 (v * 1_000_000.0).round() / 1_000_000.0
489 }
490
491 fn coord(value: f32) -> F2Dot14 {
492 F2Dot14::from_f32(value)
493 }
494
495 fn assert_close(actual: f32, expected: f32) {
496 let diff = (actual - expected).abs();
497 assert!(
498 diff <= 1e-6,
499 "expected {expected}, got {actual}, diff {diff}"
500 );
501 }
502
503 fn sfnt_table_range(data: &[u8], tag: [u8; 4]) -> (usize, usize) {
504 let font = FontRef::new(data).unwrap();
505 if let Some(rec) = font
506 .table_directory()
507 .table_records()
508 .iter()
509 .find(|rec| rec.tag() == tag)
510 {
511 return (rec.offset() as usize, rec.length() as usize);
512 }
513 panic!(
514 "missing table {:?}",
515 core::str::from_utf8(&tag).unwrap_or("????")
516 );
517 }
518
519 fn write_be_u32(dst: &mut [u8], value: u32) {
520 dst.copy_from_slice(&value.to_be_bytes());
521 }
522
523 fn read_be_u32(src: &[u8]) -> u32 {
524 u32::from_be_bytes([src[0], src[1], src[2], src[3]])
525 }
526
527 fn encode_u32_var(value: u32) -> Vec<u8> {
528 if value < 0x80 {
529 vec![value as u8]
530 } else if value < 0x4000 {
531 vec![0x80 | ((value >> 8) as u8), value as u8]
532 } else if value < 0x20_0000 {
533 vec![
534 0xC0 | ((value >> 16) as u8),
535 (value >> 8) as u8,
536 value as u8,
537 ]
538 } else if value < 0x1000_0000 {
539 vec![
540 0xE0 | ((value >> 24) as u8),
541 (value >> 16) as u8,
542 (value >> 8) as u8,
543 value as u8,
544 ]
545 } else {
546 vec![
547 0xF0,
548 (value >> 24) as u8,
549 (value >> 16) as u8,
550 (value >> 8) as u8,
551 value as u8,
552 ]
553 }
554 }
555
556 #[test]
557 fn read_cjk_0x6868() {
558 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
559 let table = font.varc().unwrap();
560 table.coverage().unwrap(); }
562
563 #[test]
564 fn identify_all_conditional_types() {
565 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
566 let table = font.varc().unwrap();
567
568 assert_eq!(
570 (1..=5).collect::<Vec<_>>(),
571 table.conditions().map(|c| c.format()).collect::<Vec<_>>()
572 );
573 }
574
575 #[test]
576 fn read_condition_format1_axis_range() {
577 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
578 let table = font.varc().unwrap();
579 let Some(Condition::Format1AxisRange(condition)) =
580 table.conditions().find(|c| c.format() == 1)
581 else {
582 panic!("No such item");
583 };
584
585 assert_eq!(
586 (0, 0.5, 1.0),
587 (
588 condition.axis_index(),
589 condition.filter_range_min_value().to_f32(),
590 condition.filter_range_max_value().to_f32(),
591 )
592 );
593 }
594
595 #[test]
596 fn read_condition_format2_variable_value() {
597 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
598 let table = font.varc().unwrap();
599 let Some(Condition::Format2VariableValue(condition)) =
600 table.conditions().find(|c| c.format() == 2)
601 else {
602 panic!("No such item");
603 };
604
605 assert_eq!((1, 2), (condition.default_value(), condition.var_index(),));
606 }
607
608 #[test]
609 fn read_condition_format3_and() {
610 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
611 let table = font.varc().unwrap();
612 let Some(Condition::Format3And(condition)) = table.conditions().find(|c| c.format() == 3)
613 else {
614 panic!("No such item");
615 };
616
617 assert_eq!(
619 vec![1, 2],
620 condition
621 .conditions()
622 .iter()
623 .map(|c| c.unwrap().format())
624 .collect::<Vec<_>>()
625 );
626 }
627
628 #[test]
629 fn read_condition_format4_or() {
630 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
631 let table = font.varc().unwrap();
632 let Some(Condition::Format4Or(condition)) = table.conditions().find(|c| c.format() == 4)
633 else {
634 panic!("No such item");
635 };
636
637 assert_eq!(
639 vec![1, 2],
640 condition
641 .conditions()
642 .iter()
643 .map(|c| c.unwrap().format())
644 .collect::<Vec<_>>()
645 );
646 }
647
648 #[test]
649 fn read_condition_format5_negate() {
650 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
651 let table = font.varc().unwrap();
652 let Some(Condition::Format5Negate(condition)) =
653 table.conditions().find(|c| c.format() == 5)
654 else {
655 panic!("No such item");
656 };
657
658 assert_eq!(1, condition.condition().unwrap().format(),);
660 }
661
662 #[test]
663 fn read_axis_indices_list() {
664 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
665 let table = font.varc().unwrap();
666 assert_eq!(table.axis_indices_count().unwrap(), 2);
667 assert_eq!(
668 vec![2, 3, 4, 5, 6],
669 table.axis_indices(1).unwrap().iter().collect::<Vec<_>>()
670 );
671 }
672
673 #[test]
674 fn compute_sparse_region_scalar_handles_boundaries_and_products() {
675 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
676 let varc = font.varc().unwrap();
677 let store = varc.multi_var_store().unwrap().unwrap();
678 let regions = store.region_list().unwrap();
679 let region_list = regions.regions();
680
681 let axis0_region = region_list.get(0).unwrap();
682 assert_close(axis0_region.compute_scalar_f32(&[coord(1.0)]), 1.0);
683 assert_close(axis0_region.compute_scalar_f32(&[coord(0.5)]), 0.5);
684 assert_close(axis0_region.compute_scalar_f32(&[F2Dot14::ZERO]), 0.0);
685 assert_close(axis0_region.compute_scalar_f32(&[]), 0.0);
686 assert_close(axis0_region.compute_scalar_f32(&[coord(-0.25)]), 0.0);
687
688 let axis0_axis1_region = region_list.get(2).unwrap();
689 assert_close(
690 axis0_axis1_region.compute_scalar_f32(&[coord(0.5), coord(0.25)]),
691 0.125,
692 );
693 }
694
695 #[test]
696 fn axis_indices_offset_out_of_bounds_errors() {
697 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
698 let (varc_offset, varc_len) = sfnt_table_range(&bytes, *b"VARC");
699 let axis_indices_offset = varc_offset + 16;
701 write_be_u32(
702 &mut bytes[axis_indices_offset..axis_indices_offset + 4],
703 (varc_len as u32).saturating_add(8),
704 );
705
706 let font = FontRef::new(&bytes).unwrap();
707 let table = font.varc().unwrap();
708 assert!(matches!(table.axis_indices(0), Err(ReadError::OutOfBounds)));
709 }
710
711 #[test]
712 fn var_composite_glyphs_offset_out_of_bounds_errors() {
713 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
714 let (varc_offset, varc_len) = sfnt_table_range(&bytes, *b"VARC");
715 let glyphs_offset = varc_offset + 20;
717 write_be_u32(
718 &mut bytes[glyphs_offset..glyphs_offset + 4],
719 (varc_len as u32).saturating_add(8),
720 );
721
722 let font = FontRef::new(&bytes).unwrap();
723 let table = font.varc().unwrap();
724 assert!(matches!(table.glyph(0), Err(ReadError::OutOfBounds)));
725 }
726
727 #[test]
728 fn parse_component_with_missing_translate_data_errors() {
729 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
730 let table = font.varc().unwrap();
731 let data = FontData::new(&[0x10, 0x00, 0x01]);
733 let mut cursor = data.cursor();
734 assert!(matches!(
735 super::VarcComponent::parse(&table, &mut cursor),
736 Err(ReadError::OutOfBounds)
737 ));
738 }
739
740 #[test]
741 fn parse_component_with_invalid_axis_indices_index_errors() {
742 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
743 let table = font.varc().unwrap();
744 let data = FontData::new(&[0x02, 0x00, 0x01, 0x7F]);
746 let mut cursor = data.cursor();
747 assert!(matches!(
748 super::VarcComponent::parse(&table, &mut cursor),
749 Err(ReadError::OutOfBounds)
750 ));
751 }
752
753 #[test]
754 fn parse_component_reserved_fields_are_consumed() {
755 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
756 let table = font.varc().unwrap();
757 let flags = 0x0001_8010_u32;
759 let mut bytes = Vec::new();
760 bytes.extend_from_slice(&encode_u32_var(flags));
761 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);
767 let mut cursor = data.cursor();
768
769 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
770 assert_eq!(component.transform().translate_x(), 7.0);
771 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
772 }
773
774 #[test]
775 fn parse_component_reserved_fields_truncation_errors() {
776 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
777 let table = font.varc().unwrap();
778 let flags = 0x0001_8010_u32;
780 let mut bytes = Vec::new();
781 bytes.extend_from_slice(&encode_u32_var(flags));
782 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);
786 let mut cursor = data.cursor();
787
788 assert!(matches!(
789 super::VarcComponent::parse(&table, &mut cursor),
790 Err(ReadError::OutOfBounds)
791 ));
792 }
793
794 #[test]
795 fn parse_component_gid_is_24bit_path() {
796 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
797 let table = font.varc().unwrap();
798 let mut bytes = Vec::new();
799 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::GID_IS_24BIT.bits()));
800 bytes.extend_from_slice(&[0x12, 0x34, 0x56]);
801 bytes.push(0xAA); let data = FontData::new(&bytes);
803 let mut cursor = data.cursor();
804
805 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
806 assert_eq!(component.gid().to_u32(), 0x12_34_56);
807 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
808 }
809
810 #[test]
811 fn parse_component_gid_is_24bit_truncation_errors() {
812 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
813 let table = font.varc().unwrap();
814 let mut bytes = Vec::new();
815 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::GID_IS_24BIT.bits()));
816 bytes.extend_from_slice(&[0x12, 0x34]); let data = FontData::new(&bytes);
818 let mut cursor = data.cursor();
819
820 assert!(matches!(
821 super::VarcComponent::parse(&table, &mut cursor),
822 Err(ReadError::OutOfBounds)
823 ));
824 }
825
826 #[test]
827 fn parse_component_with_axes_zero_count_does_not_consume_axis_values() {
828 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
829 let (varc_offset, _) = sfnt_table_range(&bytes, *b"VARC");
830 let axis_indices_rel = read_be_u32(&bytes[varc_offset + 16..varc_offset + 20]) as usize;
831 let axis_indices_abs = varc_offset + axis_indices_rel;
832 bytes[axis_indices_abs..axis_indices_abs + 7]
835 .copy_from_slice(&[0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01]);
836 let font = FontRef::new(&bytes).unwrap();
837 let table = font.varc().unwrap();
838 assert_eq!(table.axis_indices(0).unwrap().count_or_compute(), 0);
839
840 let mut bytes = Vec::new();
842 bytes.extend_from_slice(&encode_u32_var(0x12));
843 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);
848 let mut cursor = data.cursor();
849
850 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
851 assert_eq!(component.transform().translate_x(), 5.0);
852 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
853 }
854
855 #[test]
856 fn parse_component_with_axes_nonzero_count_consumes_axis_values() {
857 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
858 let table = font.varc().unwrap();
859 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
860
861 let mut bytes = Vec::new();
863 bytes.extend_from_slice(&encode_u32_var(0x12));
864 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);
871 let mut cursor = data.cursor();
872
873 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
874 assert_eq!(component.transform().translate_x(), 9.0);
875 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
876 }
877
878 #[test]
879 fn parse_component_scale_x_only_applies_to_scale_y() {
880 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
881 let table = font.varc().unwrap();
882 let mut bytes = Vec::new();
883 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_SCALE_X.bits()));
884 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&[0x08, 0x00]); bytes.push(0xAA); let data = FontData::new(&bytes);
888 let mut cursor = data.cursor();
889
890 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
891 assert_eq!(component.transform().scale_x(), 2.0);
892 assert_eq!(component.transform().scale_y(), 2.0);
893 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
894 }
895
896 #[test]
897 fn parse_component_scale_x_and_scale_y_are_independent() {
898 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
899 let table = font.varc().unwrap();
900 let flags = super::VarcFlags::HAVE_SCALE_X.bits() | super::VarcFlags::HAVE_SCALE_Y.bits();
901 let mut bytes = Vec::new();
902 bytes.extend_from_slice(&encode_u32_var(flags));
903 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);
908 let mut cursor = data.cursor();
909
910 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
911 assert_eq!(component.transform().scale_x(), 2.0);
912 assert_eq!(component.transform().scale_y(), 3.0);
913 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
914 }
915
916 #[test]
917 fn parse_component_multibyte_condition_and_var_indices() {
918 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
919 let table = font.varc().unwrap();
920 let flags = super::VarcFlags::HAVE_CONDITION.bits()
921 | super::VarcFlags::AXIS_VALUES_HAVE_VARIATION.bits()
922 | super::VarcFlags::TRANSFORM_HAS_VARIATION.bits()
923 | super::VarcFlags::HAVE_TRANSLATE_X.bits();
924 let mut bytes = Vec::new();
925 bytes.extend_from_slice(&encode_u32_var(flags));
926 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);
933 let mut cursor = data.cursor();
934
935 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
936 assert_eq!(component.condition_index(), Some(0x2345));
937 assert_eq!(component.axis_values_var_index(), Some(0x0123));
938 assert_eq!(component.transform_var_index(), Some(0x0222));
939 assert_eq!(component.transform().translate_x(), 7.0);
940 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
941 }
942
943 #[test]
944 fn parse_component_truncated_multibyte_condition_index_errors() {
945 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
946 let table = font.varc().unwrap();
947 let mut bytes = Vec::new();
948 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_CONDITION.bits()));
949 bytes.extend_from_slice(&[0x00, 0x01]); bytes.push(0x81); let data = FontData::new(&bytes);
952 let mut cursor = data.cursor();
953
954 assert!(matches!(
955 super::VarcComponent::parse(&table, &mut cursor),
956 Err(ReadError::OutOfBounds)
957 ));
958 }
959
960 #[test]
961 fn parse_component_axes_with_var_index_and_zero_axis_count() {
962 let mut bytes = font_test_data::varc::CJK_6868.to_vec();
963 let (varc_offset, _) = sfnt_table_range(&bytes, *b"VARC");
964 let axis_indices_rel = read_be_u32(&bytes[varc_offset + 16..varc_offset + 20]) as usize;
965 let axis_indices_abs = varc_offset + axis_indices_rel;
966 bytes[axis_indices_abs..axis_indices_abs + 7]
968 .copy_from_slice(&[0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01]);
969 let font = FontRef::new(&bytes).unwrap();
970 let table = font.varc().unwrap();
971
972 let flags = super::VarcFlags::HAVE_AXES.bits()
973 | super::VarcFlags::AXIS_VALUES_HAVE_VARIATION.bits()
974 | super::VarcFlags::HAVE_TRANSLATE_X.bits();
975 let mut bytes = Vec::new();
976 bytes.extend_from_slice(&encode_u32_var(flags));
977 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);
983 let mut cursor = data.cursor();
984
985 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
986 assert_eq!(component.axis_indices_index(), Some(0));
987 assert!(component.axis_values().is_none());
988 assert_eq!(component.axis_values_var_index(), Some(0x0123));
989 assert_eq!(component.transform().translate_x(), 6.0);
990 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
991 }
992
993 #[test]
994 fn parse_component_axes_truncated_i16_payload_detected_on_fetch() {
995 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
996 let table = font.varc().unwrap();
997 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
998
999 let mut bytes = Vec::new();
1001 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_AXES.bits()));
1002 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);
1007 let mut cursor = data.cursor();
1008
1009 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1010 let mut out = [0.0; 5];
1011 assert!(matches!(
1012 component
1013 .axis_values()
1014 .unwrap()
1015 .fetcher()
1016 .add_to_f32_scaled(&mut out, 1.0),
1017 Err(ReadError::OutOfBounds)
1018 ));
1019 }
1020
1021 #[test]
1022 fn parse_component_axes_truncated_i32_payload_detected_on_fetch() {
1023 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
1024 let table = font.varc().unwrap();
1025 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
1026
1027 let mut bytes = Vec::new();
1029 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_AXES.bits()));
1030 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.push(0xC4); bytes.extend_from_slice(&[
1034 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
1036 ]);
1037 let data = FontData::new(&bytes);
1038 let mut cursor = data.cursor();
1039
1040 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1041 let mut out = [0.0; 5];
1042 assert!(matches!(
1043 component
1044 .axis_values()
1045 .unwrap()
1046 .fetcher()
1047 .add_to_f32_scaled(&mut out, 1.0),
1048 Err(ReadError::OutOfBounds)
1049 ));
1050 }
1051
1052 #[test]
1053 fn parse_component_axes_payload_overshoot_causes_following_field_error() {
1054 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
1055 let table = font.varc().unwrap();
1056 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
1057
1058 let mut bytes = Vec::new();
1060 bytes.extend_from_slice(&encode_u32_var(
1061 super::VarcFlags::HAVE_AXES.bits() | super::VarcFlags::HAVE_TRANSLATE_X.bits(),
1062 ));
1063 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);
1069 let mut cursor = data.cursor();
1070
1071 assert!(matches!(
1072 super::VarcComponent::parse(&table, &mut cursor),
1073 Err(ReadError::OutOfBounds)
1074 ));
1075 }
1076
1077 #[test]
1078 fn generated_condition_varints_roundtrip() {
1079 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1080 let table = font.varc().unwrap();
1081 let mut state = 0x1234_5678_u32;
1082 for _ in 0..256 {
1083 state ^= state << 13;
1085 state ^= state >> 17;
1086 state ^= state << 5;
1087 let value = state;
1088
1089 let mut bytes = Vec::new();
1090 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_CONDITION.bits()));
1091 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(value));
1093 bytes.push(0xAA); let data = FontData::new(&bytes);
1095 let mut cursor = data.cursor();
1096
1097 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1098 assert_eq!(component.condition_index(), Some(value));
1099 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
1100 }
1101 }
1102
1103 #[test]
1104 fn generated_axis_values_single_run_roundtrip() {
1105 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
1106 let table = font.varc().unwrap();
1107 assert_eq!(table.axis_indices(1).unwrap().count_or_compute(), 5);
1108
1109 let mut state = 0xA5A5_5A5A_u32;
1110 for _ in 0..128 {
1111 state ^= state << 13;
1113 state ^= state >> 17;
1114 state ^= state << 5;
1115 let run_kind = state & 3;
1116
1117 let mut payload = Vec::new();
1118 let mut expected = [0f32; 5];
1119 match run_kind {
1120 0 => {
1121 payload.push(0x04);
1123 for out in &mut expected {
1124 state = state.wrapping_mul(1664525).wrapping_add(1013904223);
1125 let v = ((state >> 24) as i8) % 64;
1126 payload.push(v as u8);
1127 *out = v as f32;
1128 }
1129 }
1130 1 => {
1131 payload.push(0x44);
1133 for out in &mut expected {
1134 state = state.wrapping_mul(1664525).wrapping_add(1013904223);
1135 let v = ((state >> 16) as i16) % 2048;
1136 payload.extend_from_slice(&v.to_be_bytes());
1137 *out = v as f32;
1138 }
1139 }
1140 2 => {
1141 payload.push(0xC4);
1143 for out in &mut expected {
1144 state = state.wrapping_mul(1664525).wrapping_add(1013904223);
1145 let v = (state as i32) % 1_000_000;
1146 payload.extend_from_slice(&v.to_be_bytes());
1147 *out = v as f32;
1148 }
1149 }
1150 _ => {
1151 payload.push(0x84);
1153 }
1154 }
1155
1156 let mut bytes = Vec::new();
1157 bytes.extend_from_slice(&encode_u32_var(
1158 super::VarcFlags::HAVE_AXES.bits() | super::VarcFlags::HAVE_TRANSLATE_X.bits(),
1159 ));
1160 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(&encode_u32_var(1)); bytes.extend_from_slice(&payload);
1163 bytes.extend_from_slice(&[0x00, 0x07]); bytes.push(0xAA); let data = FontData::new(&bytes);
1167 let mut cursor = data.cursor();
1168 let component = super::VarcComponent::parse(&table, &mut cursor).unwrap();
1169 let mut out = [0.0f32; 5];
1170 component
1171 .axis_values()
1172 .unwrap()
1173 .fetcher()
1174 .add_to_f32_scaled(&mut out, 1.0)
1175 .unwrap();
1176 assert_eq!(out, expected);
1177 assert_eq!(component.transform().translate_x(), 7.0);
1178 assert_eq!(cursor.read::<u8>().unwrap(), 0xAA);
1179 }
1180 }
1181
1182 #[test]
1183 fn parse_component_truncated_condition_varint_boundaries_error() {
1184 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1185 let table = font.varc().unwrap();
1186 let values = [0x80_u32, 0x4000_u32, 0x20_0000_u32, 0x1000_0000_u32];
1187
1188 for value in values {
1189 let encoded = encode_u32_var(value);
1190 assert!(encoded.len() > 1);
1191 let truncated = &encoded[..encoded.len() - 1];
1192
1193 let mut bytes = Vec::new();
1194 bytes.extend_from_slice(&encode_u32_var(super::VarcFlags::HAVE_CONDITION.bits()));
1195 bytes.extend_from_slice(&[0x00, 0x01]); bytes.extend_from_slice(truncated);
1197 let data = FontData::new(&bytes);
1198 let mut cursor = data.cursor();
1199
1200 assert!(matches!(
1201 super::VarcComponent::parse(&table, &mut cursor),
1202 Err(ReadError::OutOfBounds)
1203 ));
1204 }
1205 }
1206
1207 #[test]
1208 fn read_glyph_6868() {
1209 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1210 let gid = font.cmap().unwrap().map_codepoint(0x6868_u32).unwrap();
1211 let table = font.varc().unwrap();
1212 let idx = table.coverage().unwrap().get(gid).unwrap();
1213
1214 let glyph = table.glyph(idx as usize).unwrap();
1215 assert_eq!(
1216 vec![GlyphId16::new(2), GlyphId16::new(5), GlyphId16::new(7)],
1217 glyph
1218 .components()
1219 .map(|c| c.unwrap().gid)
1220 .collect::<Vec<_>>()
1221 );
1222 }
1223
1224 #[test]
1226 fn decomposed_scale_to_matrix() {
1227 let scale_x = 2.0;
1228 let scale_y = 3.0;
1229 assert_eq!(
1230 [scale_x, 0.0, 0.0, scale_y, 0.0, 0.0],
1231 DecomposedTransform {
1232 scale_x,
1233 scale_y,
1234 ..Default::default()
1235 }
1236 .matrix()
1237 .map(round6)
1238 .elements()
1239 );
1240 }
1241
1242 #[test]
1244 fn decomposed_rotate_to_matrix() {
1245 assert_eq!(
1246 [0.0, 1.0, -1.0, 0.0, 0.0, 0.0],
1247 DecomposedTransform {
1248 rotation: 0.5,
1250 ..Default::default()
1251 }
1252 .matrix()
1253 .map(round6)
1254 .elements()
1255 );
1256 }
1257
1258 #[test]
1260 fn decomposed_skew_to_matrix() {
1261 let skew_x: f32 = 1.0 / 6.0; let skew_y: f32 = -1.0 / 3.0; assert_eq!(
1265 [
1266 1.0,
1267 round6((skew_y * core::f32::consts::PI).tan()),
1268 round6((-skew_x * core::f32::consts::PI).tan()),
1269 1.0,
1270 0.0,
1271 0.0
1272 ],
1273 DecomposedTransform {
1274 skew_x,
1275 skew_y,
1276 ..Default::default()
1277 }
1278 .matrix()
1279 .map(round6)
1280 .elements()
1281 );
1282 }
1283
1284 #[test]
1286 fn decomposed_scale_rotate_to_matrix() {
1287 let scale_x = 2.0;
1288 let scale_y = 3.0;
1289 assert_eq!(
1290 [0.0, scale_x, -scale_y, 0.0, 0.0, 0.0],
1291 DecomposedTransform {
1292 scale_x,
1293 scale_y,
1294 rotation: 0.5,
1296 ..Default::default()
1297 }
1298 .matrix()
1299 .map(round6)
1300 .elements()
1301 );
1302 }
1303
1304 #[test]
1306 fn decomposed_scale_rotate_translate_to_matrix() {
1307 assert_eq!(
1308 [0.0, 2.0, -1.0, 0.0, 10.0, 20.0],
1309 DecomposedTransform {
1310 scale_x: 2.0,
1311 rotation: 0.5,
1313 translate_x: 10.0,
1314 translate_y: 20.0,
1315 ..Default::default()
1316 }
1317 .matrix()
1318 .map(round6)
1319 .elements()
1320 );
1321 }
1322
1323 #[test]
1325 fn decomposed_scale_skew_translate_to_matrix() {
1326 assert_eq!(
1327 [-0.866026, 5.5, -2.5, 2.020726, 10.0, 20.0],
1328 DecomposedTransform {
1329 scale_x: 2.0,
1330 scale_y: 3.0,
1331 rotation: 1.0 / 6.0, skew_x: 1.0 / 6.0, skew_y: 1.0 / 3.0, translate_x: 10.0,
1336 translate_y: 20.0,
1337 ..Default::default()
1338 }
1339 .matrix()
1340 .map(round6)
1341 .elements()
1342 );
1343 }
1344
1345 #[test]
1347 fn decomposed_rotate_around_to_matrix() {
1348 assert_eq!(
1349 [1.732051, 1.0, -0.5, 0.866025, 10.267949, 19.267949],
1350 DecomposedTransform {
1351 scale_x: 2.0,
1352 rotation: 1.0 / 6.0,
1354 translate_x: 10.0,
1355 translate_y: 20.0,
1356 center_x: 1.0,
1357 center_y: 2.0,
1358 ..Default::default()
1359 }
1360 .matrix()
1361 .map(round6)
1362 .elements()
1363 );
1364 }
1365
1366 #[test]
1367 fn read_multivar_store_region_list() {
1368 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1369 let table = font.varc().unwrap();
1370 let varstore = table.multi_var_store().unwrap().unwrap();
1371 let regions = varstore.region_list().unwrap().regions();
1372
1373 let sparse_regions = regions
1374 .iter()
1375 .map(|r| {
1376 r.unwrap()
1377 .region_axes()
1378 .iter()
1379 .map(|a| {
1380 (
1381 a.axis_index(),
1382 a.start().to_f32(),
1383 a.peak().to_f32(),
1384 a.end().to_f32(),
1385 )
1386 })
1387 .collect::<Vec<_>>()
1388 })
1389 .collect::<Vec<_>>();
1390
1391 assert_eq!(
1393 vec![
1394 vec![(0, 0.0, 1.0, 1.0),],
1395 vec![(0, 0.0, 1.0, 1.0), (1, 0.0, 1.0, 1.0),],
1396 vec![(6, -1.0, -1.0, 0.0),],
1397 ],
1398 [0, 2, 38]
1399 .into_iter()
1400 .map(|i| sparse_regions[i].clone())
1401 .collect::<Vec<_>>()
1402 );
1403 }
1404
1405 #[test]
1406 fn read_multivar_store_delta_sets() {
1407 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
1408 let table = font.varc().unwrap();
1409 let varstore = table.multi_var_store().unwrap().unwrap();
1410 assert_eq!(
1411 vec![(3, 6), (33, 6), (10, 5), (25, 8),],
1412 varstore
1413 .variation_data()
1414 .iter()
1415 .map(|d| d.unwrap())
1416 .map(|d| (d.region_index_count(), d.delta_sets().unwrap().count()))
1417 .collect::<Vec<_>>()
1418 );
1419 assert_eq!(
1420 vec![-1, 33, 0, 0, 0, 0],
1421 varstore
1422 .variation_data()
1423 .get(0)
1424 .unwrap()
1425 .delta_set(5)
1426 .unwrap()
1427 .iter()
1428 .collect::<Vec<_>>()
1429 )
1430 }
1431}