1use std::collections::BTreeMap;
4
5pub use super::layout::{Condition, CoverageTable};
6use crate::ps::cff::v2::Index as Index2;
7use crate::tables::variations::{
8 common_builder::{TemporaryDeltaSetId, NO_VARIATION_INDEX},
9 mivs_builder::{MultiItemVariationStoreBuilder, MultiVariationIndexRemapping},
10 PackedDeltas,
11};
12
13include!("../../generated/generated_varc.rs");
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum VarcVariationIndex {
17 PendingVariationIndex(TemporaryDeltaSetId),
18 VariationIndex(u32),
19}
20
21impl VarcVariationIndex {
22 pub fn to_u32(&self, remappings: &MultiVariationIndexRemapping) -> u32 {
23 match self {
24 VarcVariationIndex::PendingVariationIndex(temp_id) => {
25 remappings.get(*temp_id).unwrap_or(NO_VARIATION_INDEX)
26 }
27 VarcVariationIndex::VariationIndex(idx) => *idx,
28 }
29 }
30}
31
32impl Varc {
33 pub fn new_from_composite_glyphs(
34 coverage: CoverageTable,
35 store_builder: MultiItemVariationStoreBuilder,
36 conditions: Vec<Condition>,
37 composites: Vec<VarCompositeGlyph>,
38 ) -> Self {
39 let axis_indices_list = Varc::create_axis_indices_list(&composites);
40 let axis_indices_list_items = axis_indices_list
41 .iter()
42 .map(|axes_indices| {
43 let mut writer = TableWriter::default();
44 let packed = PackedDeltas::new(axes_indices.iter().map(|v| *v as i32).collect());
45 packed.write_into(&mut writer);
46 writer.into_data().bytes
47 })
48 .collect();
49 let (store, remappings) = store_builder.build();
50
51 let axis_indices_list_raw = Index2::from_items(axis_indices_list_items);
52 let var_composite_glyphs = Index2::from_items(
53 composites
54 .iter()
55 .map(|x| x.to_bytes(&axis_indices_list, &remappings))
56 .collect(),
57 );
58 let condition_list: NullableOffsetMarker<ConditionList, WIDTH_32> =
59 NullableOffsetMarker::new(if conditions.is_empty() {
60 None
61 } else {
62 Some(ConditionList::new(conditions.len() as u32, conditions))
63 });
64 let multi_var_store: NullableOffsetMarker<MultiItemVariationStore, WIDTH_32> =
65 NullableOffsetMarker::new(if store.variation_data_count == 0 {
66 None
67 } else {
68 Some(store)
69 });
70 Self {
71 coverage: coverage.into(),
72 multi_var_store,
73 condition_list,
74 axis_indices_list: axis_indices_list_raw.into(),
75 var_composite_glyphs: var_composite_glyphs.into(),
76 }
77 }
78
79 fn create_axis_indices_list(composites: &Vec<VarCompositeGlyph>) -> Vec<Vec<u16>> {
80 let mut axis_indices_counter: BTreeMap<Vec<u16>, u32> = BTreeMap::new();
81
82 for composite in composites {
83 for component in &composite.0 {
84 if let Some(axis_values) = &component.axis_values {
85 let axis_indices: Vec<u16> = axis_values.keys().cloned().collect();
86 *axis_indices_counter.entry(axis_indices).or_insert(0) += 1;
87 }
88 }
89 }
90 let mut axis_indices_list: Vec<(Vec<u16>, u32)> = axis_indices_counter
92 .into_iter()
93 .collect::<Vec<(Vec<u16>, u32)>>();
94 axis_indices_list.sort_by_key(|(_, count)| std::cmp::Reverse(*count));
95
96 axis_indices_list
97 .into_iter()
98 .map(|(indices, _)| indices)
99 .collect()
100 }
101}
102
103pub struct VarCompositeGlyph(pub Vec<VarComponent>);
104impl VarCompositeGlyph {
105 fn to_bytes(
106 &self,
107 axis_indices_list: &[Vec<u16>],
108 remappings: &MultiVariationIndexRemapping,
109 ) -> Vec<u8> {
110 let mut writer = TableWriter::default();
111 for component in &self.0 {
112 let raw_component = RawVarComponent {
113 flags: if component.reset_unspecified_axes {
114 VarcFlags::RESET_UNSPECIFIED_AXES
115 } else {
116 VarcFlags::empty()
117 },
118 gid: component.gid,
119 condition_index: component.condition_index.map(|ci| ci.to_u32(remappings)),
120 axis_indices_index: component.axis_values.as_ref().and_then(|axis_values| {
121 let axis_indices: Vec<u16> = axis_values.keys().cloned().collect();
122 axis_indices_list
123 .iter()
124 .position(|indices| *indices == axis_indices)
125 .map(|idx| idx as u32)
126 }),
127 axis_values: component
128 .axis_values
129 .as_ref()
130 .map(|axis_values| axis_values.values().cloned().collect::<Vec<f32>>()),
131 axis_values_var_index: component
132 .axis_values_var_index
133 .map(|avi| avi.to_u32(remappings)),
134 transform_var_index: component
135 .transform_var_index
136 .map(|tvi| tvi.to_u32(remappings)),
137 transform: component.transform.clone(),
138 };
139 raw_component.write_into(&mut writer);
140 }
141 writer.into_data().bytes
142 }
143}
144
145pub struct VarComponent {
146 pub reset_unspecified_axes: bool,
147 pub gid: GlyphId,
148 pub condition_index: Option<VarcVariationIndex>,
149 pub axis_values: Option<BTreeMap<u16, f32>>,
150 pub axis_values_var_index: Option<VarcVariationIndex>,
151 pub transform: DecomposedTransform,
152 pub transform_var_index: Option<VarcVariationIndex>,
153}
154
155struct RawVarComponent {
156 flags: VarcFlags,
157 gid: GlyphId,
158 condition_index: Option<u32>,
159 axis_indices_index: Option<u32>,
160 axis_values: Option<Vec<f32>>,
161 axis_values_var_index: Option<u32>,
162 transform_var_index: Option<u32>,
163 transform: DecomposedTransform,
164}
165
166impl RawVarComponent {
167 fn determine_flags(&self) -> Uint32Var {
168 let mut flags = self.flags;
169
170 if self.gid.to_u32() > 0xFFFF {
171 flags.insert(VarcFlags::GID_IS_24BIT);
172 }
173
174 if self.condition_index.is_some() {
175 flags.insert(VarcFlags::HAVE_CONDITION);
176 }
177
178 if self.axis_indices_index.is_some() {
179 flags.insert(VarcFlags::HAVE_AXES);
180 }
181
182 if self.axis_values_var_index.is_some() {
183 flags.insert(VarcFlags::AXIS_VALUES_HAVE_VARIATION);
184 }
185
186 if self.transform_var_index.is_some() {
187 flags.insert(VarcFlags::TRANSFORM_HAS_VARIATION);
188 }
189 flags |= self.transform.flags();
190
191 flags.remove(VarcFlags::RESERVED_MASK);
193
194 Uint32Var(flags.bits())
195 }
196}
197
198impl FontWrite for RawVarComponent {
199 fn write_into(&self, writer: &mut TableWriter) {
201 self.determine_flags().write_into(writer);
202 if self.gid.to_u32() > 0xFFFF {
203 Uint24::new(self.gid.to_u32()).write_into(writer);
204 } else {
205 (self.gid.to_u32() as u16).write_into(writer);
206 }
207 if let Some(condition_index) = self.condition_index {
208 Uint32Var(condition_index).write_into(writer);
209 }
210 if let Some(axis_indices_index) = self.axis_indices_index {
211 Uint32Var(axis_indices_index).write_into(writer);
212 }
213 if let Some(axis_values) = &self.axis_values {
214 let converted_axis_values = axis_values
215 .iter()
216 .map(|v| F2Dot14::from_f32(*v).to_bits() as i32)
217 .collect();
218 let packed = PackedDeltas::new(converted_axis_values);
219 packed.write_into(writer);
220 }
221 if let Some(axis_values_var_index) = self.axis_values_var_index {
222 Uint32Var(axis_values_var_index).write_into(writer);
223 }
224
225 if let Some(transform_var_index) = self.transform_var_index {
226 Uint32Var(transform_var_index).write_into(writer);
227 }
228
229 self.transform.write_into(writer);
230
231 }
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq)]
241struct Uint32Var(u32);
242
243impl FontWrite for Uint32Var {
244 fn write_into(&self, writer: &mut TableWriter) {
245 let value = self.0;
246 if value < 0x80 {
247 (value as u8).write_into(writer);
248 } else if value < 0x4000 {
249 let byte1 = ((value >> 8) as u8) | 0x80;
250 let byte2 = (value & 0xFF) as u8;
251 (byte1).write_into(writer);
252 (byte2).write_into(writer);
253 } else if value < 0x200000 {
254 let byte1 = ((value >> 16) as u8) | 0xC0;
255 let byte2 = ((value >> 8) & 0xFF) as u8;
256 let byte3 = (value & 0xFF) as u8;
257 (byte1).write_into(writer);
258 (byte2).write_into(writer);
259 (byte3).write_into(writer);
260 } else if value < 0x10000000 {
261 let byte1 = ((value >> 24) as u8) | 0xE0;
262 let byte2 = ((value >> 16) & 0xFF) as u8;
263 let byte3 = ((value >> 8) & 0xFF) as u8;
264 let byte4 = (value & 0xFF) as u8;
265 (byte1).write_into(writer);
266 (byte2).write_into(writer);
267 (byte3).write_into(writer);
268 (byte4).write_into(writer);
269 } else {
270 (0xF0u8).write_into(writer);
271 (((value >> 24) & 0xFF) as u8).write_into(writer);
272 (((value >> 16) & 0xFF) as u8).write_into(writer);
273 (((value >> 8) & 0xFF) as u8).write_into(writer);
274 ((value & 0xFF) as u8).write_into(writer);
275 }
276 }
277}
278
279#[derive(Debug, Clone, Default, PartialEq)]
281pub struct DecomposedTransform {
282 pub translate_x: Option<f64>,
283 pub translate_y: Option<f64>,
284 pub rotation: Option<f64>, pub scale_x: Option<f64>,
286 pub scale_y: Option<f64>,
287 pub skew_x: Option<f64>,
288 pub skew_y: Option<f64>,
289 pub center_x: Option<f64>,
290 pub center_y: Option<f64>,
291}
292
293impl DecomposedTransform {
294 fn flags(&self) -> VarcFlags {
295 let mut flags = VarcFlags::empty();
296 if self.translate_x.is_some() {
297 flags.insert(VarcFlags::HAVE_TRANSLATE_X);
298 }
299 if self.translate_y.is_some() {
300 flags.insert(VarcFlags::HAVE_TRANSLATE_Y);
301 }
302 if self.rotation.is_some() {
303 flags.insert(VarcFlags::HAVE_ROTATION);
304 }
305 if self.scale_x.is_some() {
306 flags.insert(VarcFlags::HAVE_SCALE_X);
307 }
308 if self.scale_y.is_some() {
309 flags.insert(VarcFlags::HAVE_SCALE_Y);
310 }
311 if self.skew_x.is_some() {
312 flags.insert(VarcFlags::HAVE_SKEW_X);
313 }
314 if self.skew_y.is_some() {
315 flags.insert(VarcFlags::HAVE_SKEW_Y);
316 }
317 if self.center_x.is_some() {
318 flags.insert(VarcFlags::HAVE_TCENTER_X);
319 }
320 if self.center_y.is_some() {
321 flags.insert(VarcFlags::HAVE_TCENTER_Y);
322 }
323 flags
324 }
325}
326
327impl FontWrite for DecomposedTransform {
328 fn write_into(&self, writer: &mut TableWriter) {
329 if let Some(translate_x) = self.translate_x {
330 FWord::from(translate_x as i16).write_into(writer);
331 }
332 if let Some(translate_y) = self.translate_y {
333 FWord::from(translate_y as i16).write_into(writer);
334 }
335 if let Some(rotation) = self.rotation {
336 F4Dot12::from_f32(rotation as f32).write_into(writer);
337 }
338 if let Some(scale_x) = self.scale_x {
339 F6Dot10::from_f32(scale_x as f32).write_into(writer);
340 }
341 if let Some(scale_y) = self.scale_y {
342 F6Dot10::from_f32(scale_y as f32).write_into(writer);
343 }
344 if let Some(skew_x) = self.skew_x {
345 F4Dot12::from_f32(skew_x as f32).write_into(writer);
346 }
347 if let Some(skew_y) = self.skew_y {
348 F4Dot12::from_f32(skew_y as f32).write_into(writer);
349 }
350 if let Some(center_x) = self.center_x {
351 FWord::from(center_x as i16).write_into(writer);
352 }
353 if let Some(center_y) = self.center_y {
354 FWord::from(center_y as i16).write_into(writer);
355 }
356 }
357}
358#[cfg(test)]
359mod tests {
360 use crate::{
361 dump_table,
362 tables::{layout::CoverageFormat1, variations::mivs_builder::SparseRegion},
363 write::TableWriter,
364 };
365
366 use super::*;
367
368 #[test]
369 fn sparse_region_count_uint32() {
370 let region = SparseVariationRegion::new(0, vec![]);
371 let list = SparseVariationRegionList::new(0x10000, vec![region; 0x10000]);
372 let bytes = dump_table(&list).unwrap();
373 assert_eq!(&bytes[..4], &[0, 1, 0, 0]);
374 let read = read_fonts::tables::varc::SparseVariationRegionList::read(FontData::new(&bytes))
375 .unwrap();
376 assert_eq!(read.region_count(), 0x10000);
377 assert_eq!(read.regions().get(0xFFFF).unwrap().region_axis_count(), 0);
378 }
379
380 #[test]
381 fn empty_delta_set_index_offset() {
382 let data = MultiItemVariationData::new(0, vec![], Index2::from_items(vec![]));
383 let bytes = dump_table(&data).unwrap();
384 assert_eq!(&bytes[..11], &[1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0]);
385 let read =
386 read_fonts::tables::varc::MultiItemVariationData::read(FontData::new(&bytes)).unwrap();
387 assert_eq!(read.delta_sets().unwrap().count(), 0);
388 }
389
390 #[test]
391 fn test_write_uint32var() {
392 let mut writer = TableWriter::default();
393 Uint32Var(0x7F).write_into(&mut writer);
394 assert_eq!(writer.into_data().bytes, vec![0x7F]);
395
396 let mut writer = TableWriter::default();
397 Uint32Var(0x3FFF).write_into(&mut writer);
398 assert_eq!(writer.into_data().bytes, vec![0xBF, 0xFF]);
399
400 let mut writer = TableWriter::default();
401 Uint32Var(0x1FFFFF).write_into(&mut writer);
402 assert_eq!(writer.into_data().bytes, vec![0xDF, 0xFF, 0xFF]);
403
404 let mut writer = TableWriter::default();
405 Uint32Var(0x0FFFFFFF).write_into(&mut writer);
406 assert_eq!(writer.into_data().bytes, vec![0xEF, 0xFF, 0xFF, 0xFF]);
407
408 let mut writer = TableWriter::default();
409 Uint32Var(0xB2D05E00).write_into(&mut writer);
410 assert_eq!(writer.into_data().bytes, vec![0xF0, 0xB2, 0xD0, 0x5E, 0x00]);
411 }
412
413 #[test]
414
415 fn test_basic_varc() {
416 let storebuilder = MultiItemVariationStoreBuilder::new();
417 let component = VarComponent {
418 reset_unspecified_axes: false,
419 gid: GlyphId::new(42),
420 condition_index: None,
421 axis_values: None,
422 axis_values_var_index: None,
423 transform: DecomposedTransform {
424 translate_x: None,
425 translate_y: None,
426 ..Default::default()
427 },
428 transform_var_index: None,
429 };
430 let composite = VarCompositeGlyph(vec![component]);
431 let varc = Varc::new_from_composite_glyphs(
432 CoverageTable::Format1(CoverageFormat1::new(vec![1.into()])),
433 storebuilder,
434 vec![],
435 vec![composite],
436 );
437 varc.validate().expect("Varc validation failed");
438 let bytes = dump_table(&varc).expect("Failed to dump varc table");
439
440 let varc_roundtrip = read_fonts::tables::varc::Varc::read(FontData::new(&bytes))
441 .expect("Failed to read varc table");
442 let glyphs: Vec<_> = varc_roundtrip.coverage().unwrap().iter().collect();
443 assert_eq!(glyphs, vec![GlyphId16::new(1)]);
444 assert!(varc_roundtrip.multi_var_store().is_none());
445 assert!(varc_roundtrip.condition_list().is_none());
446 let composite = varc_roundtrip.glyph(0).unwrap();
447 assert_eq!(composite.components().count(), 1);
448 let mut components = composite.components();
449 let component = components.next().unwrap().unwrap();
450 assert_eq!(component.gid(), GlyphId16::new(42));
451 assert_eq!(component.condition_index(), None);
452 assert_eq!(component.axis_indices_index(), None);
453 assert!(component.axis_values().is_none());
454 assert_eq!(component.axis_values_var_index(), None);
455 assert_eq!(component.transform_var_index(), None);
456 }
457
458 #[test]
460 fn test_varc_with_axis_values_and_transform() {
461 let storebuilder = MultiItemVariationStoreBuilder::new();
462 let component = VarComponent {
463 reset_unspecified_axes: true,
464 gid: GlyphId::new(100),
465 condition_index: None,
466 axis_values: Some(
467 vec![(0u16, 0.2199707f32), (1u16, 0.2999878f32)]
469 .into_iter()
470 .collect::<BTreeMap<u16, f32>>(),
471 ),
472 axis_values_var_index: None,
473 transform: DecomposedTransform {
474 translate_x: Some(10.0),
475 translate_y: Some(-10.0),
476 ..Default::default()
477 },
478 transform_var_index: None,
479 };
480 let composite = VarCompositeGlyph(vec![component]);
481 let varc = Varc::new_from_composite_glyphs(
482 CoverageTable::Format1(CoverageFormat1::new(vec![2.into()])),
483 storebuilder,
484 vec![],
485 vec![composite],
486 );
487 varc.validate().expect("Varc validation failed");
488 let bytes = dump_table(&varc).expect("Failed to dump varc table");
489 let varc_roundtrip = read_fonts::tables::varc::Varc::read(FontData::new(&bytes))
490 .expect("Failed to read varc table");
491 let glyphs: Vec<_> = varc_roundtrip.coverage().unwrap().iter().collect();
492 assert_eq!(glyphs, vec![GlyphId16::new(2)]);
493 assert!(varc_roundtrip.multi_var_store().is_none());
494 assert!(varc_roundtrip.condition_list().is_none());
495 let axis_indices_list = varc_roundtrip.axis_indices_list().unwrap().unwrap();
496 assert_eq!(axis_indices_list.count(), 1);
497 assert_eq!(
498 varc_roundtrip
499 .axis_indices(0)
500 .unwrap()
501 .iter()
502 .collect::<Vec<_>>(),
503 vec![0, 1],
504 );
505 let composite = varc_roundtrip.glyph(0).unwrap();
506 assert_eq!(composite.components().count(), 1);
507 let mut components = composite.components();
508 let component = components.next().unwrap().unwrap();
509 assert!(component
510 .flags()
511 .contains(VarcFlags::RESET_UNSPECIFIED_AXES));
512 assert!(component.flags().contains(VarcFlags::HAVE_AXES));
513 assert_eq!(component.gid(), GlyphId16::new(100));
514 assert_eq!(component.condition_index(), None);
515 assert_eq!(component.axis_indices_index(), Some(0));
516 let axis_values = component.axis_values().unwrap();
517 let axis_values_vec: Vec<f32> = axis_values
518 .iter()
519 .map(|b| F2Dot14::from_bits(b as i16).to_f32())
520 .collect();
521 assert_eq!(axis_values_vec, vec![0.2199707, 0.2999878]);
522 assert_eq!(component.axis_values_var_index(), None);
523 assert_eq!(component.transform_var_index(), None);
524 let matrix = component.transform().matrix();
525 assert_eq!(matrix.dx, 10.0); assert_eq!(matrix.dy, -10.0); }
528
529 #[test]
531 fn test_varc_with_var_store() {
532 let mut storebuilder = MultiItemVariationStoreBuilder::new();
533 let region1 = SparseRegion::new(vec![(
534 0,
535 F2Dot14::from_f32(0.0),
536 F2Dot14::from_f32(1.0),
537 F2Dot14::from_f32(1.0),
538 )]);
539 let region2 = SparseRegion::new(vec![(
540 1,
541 F2Dot14::from_f32(-1.0),
542 F2Dot14::from_f32(-1.0),
543 F2Dot14::from_f32(0.0),
544 )]);
545
546 let delta_set_id = storebuilder
547 .add_deltas(vec![
548 (region1, vec![500, 0]),
550 (region2, vec![0, 500]),
552 ])
553 .unwrap();
554 let component = VarComponent {
555 reset_unspecified_axes: true,
556 gid: GlyphId::new(150),
557 condition_index: None,
558 axis_values: None,
559 axis_values_var_index: None,
560 transform: DecomposedTransform {
561 translate_x: Some(0.0),
562 translate_y: Some(0.0),
563 ..Default::default()
564 },
565 transform_var_index: Some(VarcVariationIndex::PendingVariationIndex(delta_set_id)),
566 };
567 let composite = VarCompositeGlyph(vec![component]);
568 let varc = Varc::new_from_composite_glyphs(
569 CoverageTable::Format1(CoverageFormat1::new(vec![3.into()])),
570 storebuilder,
571 vec![],
572 vec![composite],
573 );
574 varc.validate().expect("Varc validation failed");
575 let bytes = dump_table(&varc).expect("Failed to dump varc table");
576
577 let varc_roundtrip = read_fonts::tables::varc::Varc::read(FontData::new(&bytes))
578 .expect("Failed to read varc table");
579 let glyphs: Vec<_> = varc_roundtrip.coverage().unwrap().iter().collect();
580 assert_eq!(glyphs, vec![GlyphId16::new(3)]);
581
582 let multi_var_store = varc_roundtrip.multi_var_store().unwrap().unwrap();
584 assert_eq!(multi_var_store.format(), 1);
585 let region_list = multi_var_store.region_list().unwrap();
586 assert_eq!(region_list.region_count(), 2);
587
588 let region_0 = region_list.regions().get(0).unwrap();
589 assert_eq!(region_0.region_axis_count(), 1);
590 let region_1 = region_list.regions().get(1).unwrap();
591 assert_eq!(region_1.region_axis_count(), 1);
592
593 let composite = varc_roundtrip.glyph(0).unwrap();
595 assert_eq!(composite.components().count(), 1);
596 let mut components = composite.components();
597 let component = components.next().unwrap().unwrap();
598 assert!(component
599 .flags()
600 .contains(VarcFlags::RESET_UNSPECIFIED_AXES));
601 assert_eq!(component.gid(), GlyphId16::new(150));
602 assert_eq!(component.condition_index(), None);
603 assert_eq!(component.axis_indices_index(), None);
604 assert!(component.axis_values().is_none());
605 assert_eq!(component.axis_values_var_index(), None);
606 assert_eq!(component.transform_var_index(), Some(0));
607
608 let matrix = component.transform().matrix();
610 assert_eq!(matrix.dx, 0.0); assert_eq!(matrix.dy, 0.0); }
613}