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 test_write_uint32var() {
370 let mut writer = TableWriter::default();
371 Uint32Var(0x7F).write_into(&mut writer);
372 assert_eq!(writer.into_data().bytes, vec![0x7F]);
373
374 let mut writer = TableWriter::default();
375 Uint32Var(0x3FFF).write_into(&mut writer);
376 assert_eq!(writer.into_data().bytes, vec![0xBF, 0xFF]);
377
378 let mut writer = TableWriter::default();
379 Uint32Var(0x1FFFFF).write_into(&mut writer);
380 assert_eq!(writer.into_data().bytes, vec![0xDF, 0xFF, 0xFF]);
381
382 let mut writer = TableWriter::default();
383 Uint32Var(0x0FFFFFFF).write_into(&mut writer);
384 assert_eq!(writer.into_data().bytes, vec![0xEF, 0xFF, 0xFF, 0xFF]);
385
386 let mut writer = TableWriter::default();
387 Uint32Var(0xB2D05E00).write_into(&mut writer);
388 assert_eq!(writer.into_data().bytes, vec![0xF0, 0xB2, 0xD0, 0x5E, 0x00]);
389 }
390
391 #[test]
392
393 fn test_basic_varc() {
394 let storebuilder = MultiItemVariationStoreBuilder::new();
395 let component = VarComponent {
396 reset_unspecified_axes: false,
397 gid: GlyphId::new(42),
398 condition_index: None,
399 axis_values: None,
400 axis_values_var_index: None,
401 transform: DecomposedTransform {
402 translate_x: None,
403 translate_y: None,
404 ..Default::default()
405 },
406 transform_var_index: None,
407 };
408 let composite = VarCompositeGlyph(vec![component]);
409 let varc = Varc::new_from_composite_glyphs(
410 CoverageTable::Format1(CoverageFormat1::new(vec![1.into()])),
411 storebuilder,
412 vec![],
413 vec![composite],
414 );
415 varc.validate().expect("Varc validation failed");
416 let bytes = dump_table(&varc).expect("Failed to dump varc table");
417
418 let varc_roundtrip = read_fonts::tables::varc::Varc::read(FontData::new(&bytes))
419 .expect("Failed to read varc table");
420 let glyphs: Vec<GlyphId16> = varc_roundtrip.coverage().unwrap().iter().collect();
421 assert_eq!(glyphs, vec![GlyphId16::new(1)]);
422 assert!(varc_roundtrip.multi_var_store().is_none());
423 assert!(varc_roundtrip.condition_list().is_none());
424 let composite = varc_roundtrip.glyph(0).unwrap();
425 assert_eq!(composite.components().count(), 1);
426 let mut components = composite.components();
427 let component = components.next().unwrap().unwrap();
428 assert_eq!(component.gid(), GlyphId16::new(42));
429 assert_eq!(component.condition_index(), None);
430 assert_eq!(component.axis_indices_index(), None);
431 assert!(component.axis_values().is_none());
432 assert_eq!(component.axis_values_var_index(), None);
433 assert_eq!(component.transform_var_index(), None);
434 }
435
436 #[test]
438 fn test_varc_with_axis_values_and_transform() {
439 let storebuilder = MultiItemVariationStoreBuilder::new();
440 let component = VarComponent {
441 reset_unspecified_axes: true,
442 gid: GlyphId::new(100),
443 condition_index: None,
444 axis_values: Some(
445 vec![(0u16, 0.2199707f32), (1u16, 0.2999878f32)]
447 .into_iter()
448 .collect::<BTreeMap<u16, f32>>(),
449 ),
450 axis_values_var_index: None,
451 transform: DecomposedTransform {
452 translate_x: Some(10.0),
453 translate_y: Some(-10.0),
454 ..Default::default()
455 },
456 transform_var_index: None,
457 };
458 let composite = VarCompositeGlyph(vec![component]);
459 let varc = Varc::new_from_composite_glyphs(
460 CoverageTable::Format1(CoverageFormat1::new(vec![2.into()])),
461 storebuilder,
462 vec![],
463 vec![composite],
464 );
465 varc.validate().expect("Varc validation failed");
466 let bytes = dump_table(&varc).expect("Failed to dump varc table");
467 let varc_roundtrip = read_fonts::tables::varc::Varc::read(FontData::new(&bytes))
468 .expect("Failed to read varc table");
469 let glyphs: Vec<GlyphId16> = varc_roundtrip.coverage().unwrap().iter().collect();
470 assert_eq!(glyphs, vec![GlyphId16::new(2)]);
471 assert!(varc_roundtrip.multi_var_store().is_none());
472 assert!(varc_roundtrip.condition_list().is_none());
473 let axis_indices_list = varc_roundtrip.axis_indices_list().unwrap().unwrap();
474 assert_eq!(axis_indices_list.count(), 1);
475 assert_eq!(
476 varc_roundtrip
477 .axis_indices(0)
478 .unwrap()
479 .iter()
480 .collect::<Vec<_>>(),
481 vec![0, 1],
482 );
483 let composite = varc_roundtrip.glyph(0).unwrap();
484 assert_eq!(composite.components().count(), 1);
485 let mut components = composite.components();
486 let component = components.next().unwrap().unwrap();
487 assert!(component
488 .flags()
489 .contains(VarcFlags::RESET_UNSPECIFIED_AXES));
490 assert!(component.flags().contains(VarcFlags::HAVE_AXES));
491 assert_eq!(component.gid(), GlyphId16::new(100));
492 assert_eq!(component.condition_index(), None);
493 assert_eq!(component.axis_indices_index(), Some(0));
494 let axis_values = component.axis_values().unwrap();
495 let axis_values_vec: Vec<f32> = axis_values
496 .iter()
497 .map(|b| F2Dot14::from_bits(b as i16).to_f32())
498 .collect();
499 assert_eq!(axis_values_vec, vec![0.2199707, 0.2999878]);
500 assert_eq!(component.axis_values_var_index(), None);
501 assert_eq!(component.transform_var_index(), None);
502 let matrix = component.transform().matrix();
503 assert_eq!(matrix.dx, 10.0); assert_eq!(matrix.dy, -10.0); }
506
507 #[test]
509 fn test_varc_with_var_store() {
510 let mut storebuilder = MultiItemVariationStoreBuilder::new();
511 let region1 = SparseRegion::new(vec![(
512 0,
513 F2Dot14::from_f32(0.0),
514 F2Dot14::from_f32(1.0),
515 F2Dot14::from_f32(1.0),
516 )]);
517 let region2 = SparseRegion::new(vec![(
518 1,
519 F2Dot14::from_f32(-1.0),
520 F2Dot14::from_f32(-1.0),
521 F2Dot14::from_f32(0.0),
522 )]);
523
524 let delta_set_id = storebuilder
525 .add_deltas(vec![
526 (region1, vec![500, 0]),
528 (region2, vec![0, 500]),
530 ])
531 .unwrap();
532 let component = VarComponent {
533 reset_unspecified_axes: true,
534 gid: GlyphId::new(150),
535 condition_index: None,
536 axis_values: None,
537 axis_values_var_index: None,
538 transform: DecomposedTransform {
539 translate_x: Some(0.0),
540 translate_y: Some(0.0),
541 ..Default::default()
542 },
543 transform_var_index: Some(VarcVariationIndex::PendingVariationIndex(delta_set_id)),
544 };
545 let composite = VarCompositeGlyph(vec![component]);
546 let varc = Varc::new_from_composite_glyphs(
547 CoverageTable::Format1(CoverageFormat1::new(vec![3.into()])),
548 storebuilder,
549 vec![],
550 vec![composite],
551 );
552 varc.validate().expect("Varc validation failed");
553 let bytes = dump_table(&varc).expect("Failed to dump varc table");
554
555 let varc_roundtrip = read_fonts::tables::varc::Varc::read(FontData::new(&bytes))
556 .expect("Failed to read varc table");
557 let glyphs: Vec<GlyphId16> = varc_roundtrip.coverage().unwrap().iter().collect();
558 assert_eq!(glyphs, vec![GlyphId16::new(3)]);
559
560 let multi_var_store = varc_roundtrip.multi_var_store().unwrap().unwrap();
562 assert_eq!(multi_var_store.format(), 1);
563 let region_list = multi_var_store.region_list().unwrap();
564 assert_eq!(region_list.region_count(), 2);
565
566 let region_0 = region_list.regions().get(0).unwrap();
567 assert_eq!(region_0.region_axis_count(), 1);
568 let region_1 = region_list.regions().get(1).unwrap();
569 assert_eq!(region_1.region_axis_count(), 1);
570
571 let composite = varc_roundtrip.glyph(0).unwrap();
573 assert_eq!(composite.components().count(), 1);
574 let mut components = composite.components();
575 let component = components.next().unwrap().unwrap();
576 assert!(component
577 .flags()
578 .contains(VarcFlags::RESET_UNSPECIFIED_AXES));
579 assert_eq!(component.gid(), GlyphId16::new(150));
580 assert_eq!(component.condition_index(), None);
581 assert_eq!(component.axis_indices_index(), None);
582 assert!(component.axis_values().is_none());
583 assert_eq!(component.axis_values_var_index(), None);
584 assert_eq!(component.transform_var_index(), Some(0));
585
586 let matrix = component.transform().matrix();
588 assert_eq!(matrix.dx, 0.0); assert_eq!(matrix.dy, 0.0); }
591}