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