1use super::variations::PackedDeltas;
4pub use super::{
5 layout::{Condition, CoverageTable},
6 postscript::Index2,
7};
8
9#[cfg(feature = "libm")]
10#[allow(unused_imports)]
11use core_maths::*;
12
13include!("../../generated/generated_varc.rs");
14
15trait Get<'a> {
17 fn get(self, nth: usize) -> Result<&'a [u8], ReadError>;
18}
19
20impl<'a> Get<'a> for Option<Result<Index2<'a>, ReadError>> {
21 fn get(self, nth: usize) -> Result<&'a [u8], ReadError> {
22 self.transpose()?
23 .ok_or(ReadError::NullOffset)
24 .and_then(|index| index.get(nth).map_err(|_| ReadError::OutOfBounds))
25 }
26}
27
28impl Varc<'_> {
29 pub fn axis_indices(&self, nth: usize) -> Result<PackedDeltas, ReadError> {
31 let raw = self.axis_indices_list().get(nth)?;
32 Ok(PackedDeltas::consume_all(raw.into()))
33 }
34
35 pub fn glyph(&self, nth: usize) -> Result<VarcGlyph<'_>, ReadError> {
39 let raw = Some(self.var_composite_glyphs()).get(nth)?;
40 Ok(VarcGlyph {
41 table: self,
42 data: raw.into(),
43 })
44 }
45}
46
47pub struct VarcGlyph<'a> {
51 table: &'a Varc<'a>,
52 data: FontData<'a>,
53}
54
55impl<'a> VarcGlyph<'a> {
56 pub fn components(&self) -> impl Iterator<Item = Result<VarcComponent<'a>, ReadError>> {
58 VarcComponentIter {
59 table: self.table,
60 cursor: self.data.cursor(),
61 }
62 }
63}
64
65struct VarcComponentIter<'a> {
66 table: &'a Varc<'a>,
67 cursor: Cursor<'a>,
68}
69
70impl<'a> Iterator for VarcComponentIter<'a> {
71 type Item = Result<VarcComponent<'a>, ReadError>;
72
73 fn next(&mut self) -> Option<Self::Item> {
74 if self.cursor.is_empty() {
75 return None;
76 }
77 Some(VarcComponent::parse(self.table, &mut self.cursor))
78 }
79}
80
81#[allow(dead_code)] pub struct VarcComponent<'a> {
83 flags: VarcFlags,
84 gid: GlyphId,
85 condition_index: Option<u32>,
86 axis_indices_index: Option<u32>,
87 axis_values: Option<PackedDeltas<'a>>,
88 axis_values_var_index: Option<u32>,
89 transform_var_index: Option<u32>,
90 transform: DecomposedTransform,
91}
92
93impl<'a> VarcComponent<'a> {
94 fn parse(table: &Varc, cursor: &mut Cursor<'a>) -> Result<Self, ReadError> {
99 let raw_flags = cursor.read_u32_var()?;
100 let flags = VarcFlags::from_bits_truncate(raw_flags);
101 let gid = if flags.contains(VarcFlags::GID_IS_24BIT) {
105 GlyphId::new(cursor.read::<Uint24>()?.to_u32())
106 } else {
107 GlyphId::from(cursor.read::<u16>()?)
108 };
109
110 let condition_index = if flags.contains(VarcFlags::HAVE_CONDITION) {
111 Some(cursor.read_u32_var()?)
112 } else {
113 None
114 };
115
116 let (axis_indices_index, axis_values) = if flags.contains(VarcFlags::HAVE_AXES) {
117 let axis_indices_index = cursor.read_u32_var()?;
119 let num_axis_values = table.axis_indices(axis_indices_index as usize)?.count();
120 let deltas = if num_axis_values > 0 {
122 let Some(data) = cursor.remaining() else {
123 return Err(ReadError::OutOfBounds);
124 };
125 let deltas = PackedDeltas::new(data, num_axis_values);
126 *cursor = deltas.iter().end(); Some(deltas)
128 } else {
129 None
130 };
131 (Some(axis_indices_index), deltas)
132 } else {
133 (None, None)
134 };
135
136 let axis_values_var_index = flags
137 .contains(VarcFlags::AXIS_VALUES_HAVE_VARIATION)
138 .then(|| cursor.read_u32_var())
139 .transpose()?;
140
141 let transform_var_index = if flags.contains(VarcFlags::TRANSFORM_HAS_VARIATION) {
142 Some(cursor.read_u32_var()?)
143 } else {
144 None
145 };
146
147 let mut transform = DecomposedTransform::default();
148 if flags.contains(VarcFlags::HAVE_TRANSLATE_X) {
149 transform.translate_x = cursor.read::<FWord>()?.to_i16() as f64
150 }
151 if flags.contains(VarcFlags::HAVE_TRANSLATE_Y) {
152 transform.translate_y = cursor.read::<FWord>()?.to_i16() as f64
153 }
154 if flags.contains(VarcFlags::HAVE_ROTATION) {
155 transform.rotation = cursor.read::<F4Dot12>()?.to_f32() as f64
156 }
157 if flags.contains(VarcFlags::HAVE_SCALE_X) {
158 transform.scale_x = cursor.read::<F6Dot10>()?.to_f32() as f64
159 }
160 transform.scale_y = if flags.contains(VarcFlags::HAVE_SCALE_Y) {
161 cursor.read::<F6Dot10>()?.to_f32() as f64
162 } else {
163 transform.scale_x
164 };
165 if flags.contains(VarcFlags::HAVE_SKEW_X) {
166 transform.skew_x = cursor.read::<F4Dot12>()?.to_f32() as f64
167 }
168 if flags.contains(VarcFlags::HAVE_SKEW_Y) {
169 transform.skew_y = cursor.read::<F4Dot12>()?.to_f32() as f64
170 }
171 if flags.contains(VarcFlags::HAVE_TCENTER_X) {
172 transform.center_x = cursor.read::<FWord>()?.to_i16() as f64
173 }
174 if flags.contains(VarcFlags::HAVE_TCENTER_Y) {
175 transform.center_y = cursor.read::<FWord>()?.to_i16() as f64
176 }
177
178 let num_reserved = (raw_flags & VarcFlags::RESERVED_MASK.bits).count_ones();
180 for _ in 0..num_reserved {
181 cursor.read_u32_var()?;
182 }
183 Ok(VarcComponent {
184 flags,
185 gid,
186 condition_index,
187 axis_indices_index,
188 axis_values,
189 axis_values_var_index,
190 transform_var_index,
191 transform,
192 })
193 }
194}
195
196pub struct DecomposedTransform {
198 translate_x: f64,
199 translate_y: f64,
200 rotation: f64, scale_x: f64,
202 scale_y: f64,
203 skew_x: f64,
204 skew_y: f64,
205 center_x: f64,
206 center_y: f64,
207}
208
209impl Default for DecomposedTransform {
210 fn default() -> Self {
211 Self {
212 translate_x: 0.0,
213 translate_y: 0.0,
214 rotation: 0.0,
215 scale_x: 1.0,
216 scale_y: 1.0,
217 skew_x: 0.0,
218 skew_y: 0.0,
219 center_x: 0.0,
220 center_y: 0.0,
221 }
222 }
223}
224
225impl DecomposedTransform {
226 pub fn matrix(&self) -> [f64; 6] {
244 let mut transform = [
246 1.0,
247 0.0,
248 0.0,
249 1.0,
250 self.translate_x + self.center_x,
251 self.translate_y + self.center_y,
252 ];
253
254 if self.rotation != 0.0 {
259 let (s, c) = (self.rotation).to_radians().sin_cos();
260 transform = transform.transform([c, s, -s, c, 0.0, 0.0]);
261 }
262
263 if (self.scale_x, self.scale_y) != (1.0, 1.0) {
265 transform = transform.transform([self.scale_x, 0.0, 0.0, self.scale_y, 0.0, 0.0]);
266 }
267
268 if (self.skew_x, self.skew_y) != (0.0, 0.0) {
270 transform = transform.transform([
271 1.0,
272 self.skew_y.to_radians().tan(),
273 self.skew_x.to_radians().tan(),
274 1.0,
275 0.0,
276 0.0,
277 ])
278 }
279
280 if (self.center_x, self.center_y) != (0.0, 0.0) {
282 transform = transform.transform([1.0, 0.0, 0.0, 1.0, -self.center_x, -self.center_y]);
283 }
284
285 transform
286 }
287}
288
289trait Transform {
290 fn transform(self, other: Self) -> Self;
291}
292
293impl Transform for [f64; 6] {
294 fn transform(self, other: Self) -> Self {
295 [
297 self[0] * other[0] + self[2] * other[1],
298 self[1] * other[0] + self[3] * other[1],
299 self[0] * other[2] + self[2] * other[3],
300 self[1] * other[2] + self[3] * other[3],
301 self[0] * other[4] + self[2] * other[5] + self[4],
302 self[1] * other[4] + self[3] * other[5] + self[5],
303 ]
304 }
305}
306
307impl<'a> MultiItemVariationData<'a> {
308 pub fn delta_sets(&self) -> Result<Index2<'a>, ReadError> {
310 Index2::read(self.raw_delta_sets().into())
311 }
312
313 pub fn delta_set(&self, i: usize) -> Result<PackedDeltas<'a>, ReadError> {
317 let index = self.delta_sets()?;
318 let raw_deltas = index.get(i).map_err(|_| ReadError::OutOfBounds)?;
319 Ok(PackedDeltas::consume_all(raw_deltas.into()))
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use types::GlyphId16;
326
327 use crate::{FontRef, ReadError, TableProvider};
328
329 use super::{Condition, DecomposedTransform, Varc};
330
331 impl Varc<'_> {
332 fn conditions(&self) -> impl Iterator<Item = Condition<'_>> {
333 self.condition_list()
334 .expect("A condition list is present")
335 .expect("We could read the condition list")
336 .conditions()
337 .iter()
338 .enumerate()
339 .map(|(i, c)| c.unwrap_or_else(|e| panic!("condition {i} {e}")))
340 }
341
342 fn axis_indices_count(&self) -> Result<usize, ReadError> {
343 let Some(axis_indices_list) = self.axis_indices_list() else {
344 return Ok(0);
345 };
346 let axis_indices_list = axis_indices_list?;
347 Ok(axis_indices_list.count() as usize)
348 }
349 }
350
351 fn round6(v: f64) -> f64 {
352 (v * 1_000_000.0).round() / 1_000_000.0
353 }
354
355 trait Round {
356 fn round_for_test(self) -> Self;
357 }
358
359 impl Round for [f64; 6] {
360 fn round_for_test(self) -> Self {
361 [
362 round6(self[0]),
363 round6(self[1]),
364 round6(self[2]),
365 round6(self[3]),
366 round6(self[4]),
367 round6(self[5]),
368 ]
369 }
370 }
371
372 #[test]
373 fn read_cjk_0x6868() {
374 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
375 let table = font.varc().unwrap();
376 table.coverage().unwrap(); }
378
379 #[test]
380 fn identify_all_conditional_types() {
381 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
382 let table = font.varc().unwrap();
383
384 assert_eq!(
386 (1..=5).collect::<Vec<_>>(),
387 table.conditions().map(|c| c.format()).collect::<Vec<_>>()
388 );
389 }
390
391 #[test]
392 fn read_condition_format1_axis_range() {
393 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
394 let table = font.varc().unwrap();
395 let Some(Condition::Format1AxisRange(condition)) =
396 table.conditions().find(|c| c.format() == 1)
397 else {
398 panic!("No such item");
399 };
400
401 assert_eq!(
402 (0, 0.5, 1.0),
403 (
404 condition.axis_index(),
405 condition.filter_range_min_value().to_f32(),
406 condition.filter_range_max_value().to_f32(),
407 )
408 );
409 }
410
411 #[test]
412 fn read_condition_format2_variable_value() {
413 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
414 let table = font.varc().unwrap();
415 let Some(Condition::Format2VariableValue(condition)) =
416 table.conditions().find(|c| c.format() == 2)
417 else {
418 panic!("No such item");
419 };
420
421 assert_eq!((1, 2), (condition.default_value(), condition.var_index(),));
422 }
423
424 #[test]
425 fn read_condition_format3_and() {
426 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
427 let table = font.varc().unwrap();
428 let Some(Condition::Format3And(condition)) = table.conditions().find(|c| c.format() == 3)
429 else {
430 panic!("No such item");
431 };
432
433 assert_eq!(
435 vec![1, 2],
436 condition
437 .conditions()
438 .iter()
439 .map(|c| c.unwrap().format())
440 .collect::<Vec<_>>()
441 );
442 }
443
444 #[test]
445 fn read_condition_format4_or() {
446 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
447 let table = font.varc().unwrap();
448 let Some(Condition::Format4Or(condition)) = table.conditions().find(|c| c.format() == 4)
449 else {
450 panic!("No such item");
451 };
452
453 assert_eq!(
455 vec![1, 2],
456 condition
457 .conditions()
458 .iter()
459 .map(|c| c.unwrap().format())
460 .collect::<Vec<_>>()
461 );
462 }
463
464 #[test]
465 fn read_condition_format5_negate() {
466 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
467 let table = font.varc().unwrap();
468 let Some(Condition::Format5Negate(condition)) =
469 table.conditions().find(|c| c.format() == 5)
470 else {
471 panic!("No such item");
472 };
473
474 assert_eq!(1, condition.condition().unwrap().format(),);
476 }
477
478 #[test]
479 fn read_axis_indices_list() {
480 let font = FontRef::new(font_test_data::varc::CONDITIONALS).unwrap();
481 let table = font.varc().unwrap();
482 assert_eq!(table.axis_indices_count().unwrap(), 2);
483 assert_eq!(
484 vec![2, 3, 4, 5, 6],
485 table.axis_indices(1).unwrap().iter().collect::<Vec<_>>()
486 );
487 }
488
489 #[test]
490 fn read_glyph_6868() {
491 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
492 let gid = font.cmap().unwrap().map_codepoint(0x6868_u32).unwrap();
493 let table = font.varc().unwrap();
494 let idx = table.coverage().unwrap().get(gid).unwrap();
495
496 let glyph = table.glyph(idx as usize).unwrap();
497 assert_eq!(
498 vec![GlyphId16::new(2), GlyphId16::new(5), GlyphId16::new(7)],
499 glyph
500 .components()
501 .map(|c| c.unwrap().gid)
502 .collect::<Vec<_>>()
503 );
504 }
505
506 #[test]
508 fn decomposed_scale_to_matrix() {
509 let scale_x = 2.0;
510 let scale_y = 3.0;
511 assert_eq!(
512 [scale_x, 0.0, 0.0, scale_y, 0.0, 0.0],
513 DecomposedTransform {
514 scale_x,
515 scale_y,
516 ..Default::default()
517 }
518 .matrix()
519 .round_for_test()
520 );
521 }
522
523 #[test]
525 fn decomposed_rotate_to_matrix() {
526 assert_eq!(
527 [0.0, 1.0, -1.0, 0.0, 0.0, 0.0],
528 DecomposedTransform {
529 rotation: 90.0,
530 ..Default::default()
531 }
532 .matrix()
533 .round_for_test()
534 );
535 }
536
537 #[test]
539 fn decomposed_skew_to_matrix() {
540 let skew_x: f64 = 30.0;
541 let skew_y: f64 = -60.0;
542 assert_eq!(
543 [
544 1.0,
545 round6(skew_y.to_radians().tan()),
546 round6(skew_x.to_radians().tan()),
547 1.0,
548 0.0,
549 0.0
550 ],
551 DecomposedTransform {
552 skew_x,
553 skew_y,
554 ..Default::default()
555 }
556 .matrix()
557 .round_for_test()
558 );
559 }
560
561 #[test]
563 fn decomposed_scale_rotate_to_matrix() {
564 let scale_x = 2.0;
565 let scale_y = 3.0;
566 assert_eq!(
567 [0.0, scale_x, -scale_y, 0.0, 0.0, 0.0],
568 DecomposedTransform {
569 scale_x,
570 scale_y,
571 rotation: 90.0,
572 ..Default::default()
573 }
574 .matrix()
575 .round_for_test()
576 );
577 }
578
579 #[test]
581 fn decomposed_scale_rotate_translate_to_matrix() {
582 assert_eq!(
583 [0.0, 2.0, -1.0, 0.0, 10.0, 20.0],
584 DecomposedTransform {
585 scale_x: 2.0,
586 rotation: 90.0,
587 translate_x: 10.0,
588 translate_y: 20.0,
589 ..Default::default()
590 }
591 .matrix()
592 .round_for_test()
593 );
594 }
595
596 #[test]
598 fn decomposed_scale_skew_translate_to_matrix() {
599 assert_eq!(
600 [-0.866025, 5.5, -0.5, 3.175426, 10.0, 20.0],
601 DecomposedTransform {
602 scale_x: 2.0,
603 scale_y: 3.0,
604 rotation: 30.0,
605 skew_x: 30.0,
606 skew_y: 60.0,
607 translate_x: 10.0,
608 translate_y: 20.0,
609 ..Default::default()
610 }
611 .matrix()
612 .round_for_test()
613 );
614 }
615
616 #[test]
618 fn decomposed_rotate_around_to_matrix() {
619 assert_eq!(
620 [1.732051, 1.0, -0.5, 0.866025, 10.267949, 19.267949],
621 DecomposedTransform {
622 scale_x: 2.0,
623 rotation: 30.0,
624 translate_x: 10.0,
625 translate_y: 20.0,
626 center_x: 1.0,
627 center_y: 2.0,
628 ..Default::default()
629 }
630 .matrix()
631 .round_for_test()
632 );
633 }
634
635 #[test]
636 fn read_multivar_store_region_list() {
637 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
638 let table = font.varc().unwrap();
639 let varstore = table.multi_var_store().unwrap().unwrap();
640 let regions = varstore.region_list().unwrap().regions();
641
642 let sparse_regions = regions
643 .iter()
644 .map(|r| {
645 r.unwrap()
646 .region_axis_offsets()
647 .iter()
648 .map(|a| {
649 (
650 a.axis_index(),
651 a.start().to_f32(),
652 a.peak().to_f32(),
653 a.end().to_f32(),
654 )
655 })
656 .collect::<Vec<_>>()
657 })
658 .collect::<Vec<_>>();
659
660 assert_eq!(
662 vec![
663 vec![(0, 0.0, 1.0, 1.0),],
664 vec![(0, 0.0, 1.0, 1.0), (1, 0.0, 1.0, 1.0),],
665 vec![(6, -1.0, -1.0, 0.0),],
666 ],
667 [0, 2, 38]
668 .into_iter()
669 .map(|i| sparse_regions[i].clone())
670 .collect::<Vec<_>>()
671 );
672 }
673
674 #[test]
675 fn read_multivar_store_delta_sets() {
676 let font = FontRef::new(font_test_data::varc::CJK_6868).unwrap();
677 let table = font.varc().unwrap();
678 let varstore = table.multi_var_store().unwrap().unwrap();
679 assert_eq!(
680 vec![(3, 6), (33, 6), (10, 5), (25, 8),],
681 varstore
682 .variation_data()
683 .iter()
684 .map(|d| d.unwrap())
685 .map(|d| (d.region_index_count(), d.delta_sets().unwrap().count()))
686 .collect::<Vec<_>>()
687 );
688 assert_eq!(
689 vec![-1, 33, 0, 0, 0, 0],
690 varstore
691 .variation_data()
692 .get(0)
693 .unwrap()
694 .delta_set(5)
695 .unwrap()
696 .iter()
697 .collect::<Vec<_>>()
698 )
699 }
700}