1use std::collections::{BTreeMap, HashMap};
4
5use read_fonts::collections::IntSet;
6use types::GlyphId16;
7
8use crate::tables::{
9 layout::{
10 builders::{Builder, ClassDefBuilder, DeviceOrDeltas, Metric},
11 CoverageTable,
12 },
13 variations::ivs_builder::VariationStoreBuilder,
14};
15
16use super::{
17 AnchorTable, BaseArray, BaseRecord, Class1Record, Class2Record, ComponentRecord,
18 CursivePosFormat1, EntryExitRecord, LigatureArray, LigatureAttach, Mark2Array, Mark2Record,
19 MarkArray, MarkBasePosFormat1, MarkLigPosFormat1, MarkMarkPosFormat1, MarkRecord, PairPos,
20 PairSet, PairValueRecord, SinglePos, ValueFormat, ValueRecord,
21};
22
23type GlyphSet = IntSet<GlyphId16>;
24
25#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub struct ValueRecordBuilder {
29 pub x_advance: Option<Metric>,
31 pub y_advance: Option<Metric>,
33 pub x_placement: Option<Metric>,
35 pub y_placement: Option<Metric>,
37}
38
39#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
42pub struct AnchorBuilder {
43 pub x: Metric,
45 pub y: Metric,
47 pub contourpoint: Option<u16>,
51}
52
53impl ValueRecordBuilder {
54 pub fn new() -> Self {
56 Default::default()
57 }
58
59 pub fn make_rtl_compatible(&mut self) {
64 if self.x_placement.is_none() {
65 self.x_placement.clone_from(&self.x_advance);
66 }
67 }
68
69 pub fn with_x_placement(mut self, val: i16) -> Self {
72 self.x_placement
73 .get_or_insert_with(Default::default)
74 .default = val;
75 self
76 }
77
78 pub fn with_y_placement(mut self, val: i16) -> Self {
80 self.y_placement
81 .get_or_insert_with(Default::default)
82 .default = val;
83 self
84 }
85
86 pub fn with_x_advance(mut self, val: i16) -> Self {
88 self.x_advance.get_or_insert_with(Default::default).default = val;
89 self
90 }
91
92 pub fn with_y_advance(mut self, val: i16) -> Self {
94 self.y_advance.get_or_insert_with(Default::default).default = val;
95 self
96 }
97
98 pub fn with_x_placement_device(mut self, val: impl Into<DeviceOrDeltas>) -> Self {
102 self.x_placement
103 .get_or_insert_with(Default::default)
104 .device_or_deltas = val.into();
105 self
106 }
107
108 pub fn with_y_placement_device(mut self, val: impl Into<DeviceOrDeltas>) -> Self {
112 self.y_placement
113 .get_or_insert_with(Default::default)
114 .device_or_deltas = val.into();
115 self
116 }
117
118 pub fn with_x_advance_device(mut self, val: impl Into<DeviceOrDeltas>) -> Self {
122 self.x_advance
123 .get_or_insert_with(Default::default)
124 .device_or_deltas = val.into();
125 self
126 }
127
128 pub fn with_y_advance_device(mut self, val: impl Into<DeviceOrDeltas>) -> Self {
132 self.y_advance
133 .get_or_insert_with(Default::default)
134 .device_or_deltas = val.into();
135 self
136 }
137
138 pub fn clear_zeros(mut self) -> Self {
140 self.x_advance = self.x_advance.filter(|m| !m.is_zero());
141 self.y_advance = self.y_advance.filter(|m| !m.is_zero());
142 self.x_placement = self.x_placement.filter(|m| !m.is_zero());
143 self.y_placement = self.y_placement.filter(|m| !m.is_zero());
144 self
145 }
146
147 pub fn format(&self) -> ValueFormat {
149 const EMPTY: ValueFormat = ValueFormat::empty();
150 use ValueFormat as VF;
151
152 let get_flags = |field: &Option<Metric>, def_flag, dev_flag| {
153 let field = field.as_ref();
154 let def_flag = if field.is_some() { def_flag } else { EMPTY };
155 let dev_flag = field
156 .and_then(|fld| (!fld.device_or_deltas.is_none()).then_some(dev_flag))
157 .unwrap_or(EMPTY);
158 (def_flag, dev_flag)
159 };
160
161 let (x_adv, x_adv_dev) = get_flags(&self.x_advance, VF::X_ADVANCE, VF::X_ADVANCE_DEVICE);
162 let (y_adv, y_adv_dev) = get_flags(&self.y_advance, VF::Y_ADVANCE, VF::Y_ADVANCE_DEVICE);
163 let (x_place, x_place_dev) =
164 get_flags(&self.x_placement, VF::X_PLACEMENT, VF::X_PLACEMENT_DEVICE);
165 let (y_place, y_place_dev) =
166 get_flags(&self.y_placement, VF::Y_PLACEMENT, VF::Y_PLACEMENT_DEVICE);
167 x_adv | y_adv | x_place | y_place | x_adv_dev | y_adv_dev | x_place_dev | y_place_dev
168 }
169
170 pub fn is_all_zeros(&self) -> bool {
172 let device_mask = ValueFormat::X_PLACEMENT_DEVICE
173 | ValueFormat::Y_PLACEMENT_DEVICE
174 | ValueFormat::X_ADVANCE_DEVICE
175 | ValueFormat::Y_ADVANCE_DEVICE;
176
177 let format = self.format();
178 if format.is_empty() || format.intersects(device_mask) {
179 return false;
180 }
181 let all_values = [
182 &self.x_placement,
183 &self.y_placement,
184 &self.x_advance,
185 &self.y_advance,
186 ];
187 all_values
188 .iter()
189 .all(|v| v.as_ref().map(|v| v.is_zero()).unwrap_or(true))
190 }
191
192 pub fn build(self, var_store: &mut VariationStoreBuilder) -> ValueRecord {
194 let mut result = ValueRecord::new();
195 result.x_advance = self.x_advance.as_ref().map(|val| val.default);
196 result.y_advance = self.y_advance.as_ref().map(|val| val.default);
197 result.x_placement = self.x_placement.as_ref().map(|val| val.default);
198 result.y_placement = self.y_placement.as_ref().map(|val| val.default);
199 result.x_advance_device = self
200 .x_advance
201 .and_then(|val| val.device_or_deltas.build(var_store))
202 .into();
203 result.y_advance_device = self
204 .y_advance
205 .and_then(|val| val.device_or_deltas.build(var_store))
206 .into();
207 result.x_placement_device = self
208 .x_placement
209 .and_then(|val| val.device_or_deltas.build(var_store))
210 .into();
211 result.y_placement_device = self
212 .y_placement
213 .and_then(|val| val.device_or_deltas.build(var_store))
214 .into();
215
216 result
217 }
218}
219
220impl AnchorBuilder {
221 pub fn new(x: i16, y: i16) -> Self {
223 AnchorBuilder {
224 x: x.into(),
225 y: y.into(),
226 contourpoint: None,
227 }
228 }
229
230 pub fn with_x_device(mut self, val: impl Into<DeviceOrDeltas>) -> Self {
234 self.x.device_or_deltas = val.into();
235 self
236 }
237
238 pub fn with_y_device(mut self, val: impl Into<DeviceOrDeltas>) -> Self {
242 self.y.device_or_deltas = val.into();
243 self
244 }
245
246 pub fn with_contourpoint(mut self, idx: u16) -> Self {
251 self.contourpoint = Some(idx);
252 self
253 }
254
255 pub fn build(self, var_store: &mut VariationStoreBuilder) -> AnchorTable {
257 let x = self.x.default;
258 let y = self.y.default;
259 let x_dev = self.x.device_or_deltas.build(var_store);
260 let y_dev = self.y.device_or_deltas.build(var_store);
261 if x_dev.is_some() || y_dev.is_some() {
262 AnchorTable::format_3(x, y, x_dev, y_dev)
263 } else if let Some(point) = self.contourpoint {
264 AnchorTable::format_2(x, y, point)
265 } else {
266 AnchorTable::format_1(x, y)
267 }
268 }
269}
270
271#[derive(Clone, Debug, Default, PartialEq, Eq)]
273#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
274pub struct SinglePosBuilder {
275 items: BTreeMap<GlyphId16, ValueRecordBuilder>,
276}
277
278impl SinglePosBuilder {
279 pub fn len(&self) -> usize {
281 self.items.len()
282 }
283
284 pub fn is_empty(&self) -> bool {
286 self.items.is_empty()
287 }
288
289 pub fn insert(&mut self, glyph: GlyphId16, record: ValueRecordBuilder) {
291 self.items.insert(glyph, record);
292 }
293
294 pub fn can_add(&self, glyph: GlyphId16, value: &ValueRecordBuilder) -> bool {
296 self.items
297 .get(&glyph)
298 .map(|existing| existing == value)
299 .unwrap_or(true)
300 }
301}
302
303impl Builder for SinglePosBuilder {
304 type Output = Vec<SinglePos>;
305
306 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
307 fn build_subtable(items: BTreeMap<GlyphId16, &ValueRecord>) -> SinglePos {
308 let first = *items.values().next().unwrap();
309 let use_format_1 = first.format().is_empty() || items.values().all(|val| val == &first);
310 let coverage: CoverageTable = items.keys().copied().collect();
311 if use_format_1 {
312 SinglePos::format_1(coverage.clone(), first.clone())
313 } else {
314 SinglePos::format_2(coverage, items.into_values().cloned().collect())
315 }
316 }
317 const NEW_SUBTABLE_COST: usize = 10;
318 let items = self
319 .items
320 .into_iter()
321 .map(|(glyph, anchor)| (glyph, anchor.build(var_store)))
322 .collect::<BTreeMap<_, _>>();
323
324 let mut subtables = Vec::new();
326 let mut group_by_record: HashMap<&ValueRecord, BTreeMap<GlyphId16, &ValueRecord>> =
327 Default::default();
328
329 for (gid, value) in &items {
332 group_by_record
333 .entry(value)
334 .or_default()
335 .insert(*gid, value);
336 }
337 let mut group_by_format: HashMap<ValueFormat, BTreeMap<GlyphId16, &ValueRecord>> =
338 Default::default();
339 for (value, glyphs) in group_by_record {
340 if glyphs.len() * value.encoded_size() > NEW_SUBTABLE_COST {
342 subtables.push(glyphs);
343 } else {
346 group_by_format
347 .entry(value.format())
348 .or_default()
349 .extend(glyphs.into_iter());
350 }
351 }
352 subtables.extend(group_by_format.into_values());
353
354 let mut output = subtables
355 .into_iter()
356 .map(build_subtable)
357 .collect::<Vec<_>>();
358
359 output.sort_unstable_by_key(|table| match table {
362 SinglePos::Format1(table) => cmp_coverage_key(&table.coverage),
363 SinglePos::Format2(table) => cmp_coverage_key(&table.coverage),
364 });
365 output
366 }
367}
368
369fn cmp_coverage_key(coverage: &CoverageTable) -> impl Ord {
370 (std::cmp::Reverse(coverage.len()), coverage.iter().next())
371}
372
373#[derive(Clone, Debug, Default, PartialEq)]
377#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
378pub struct PairPosBuilder {
379 pairs: GlyphPairPosBuilder,
380 classes: ClassPairPosBuilder,
381}
382
383#[derive(Clone, Debug, Default, PartialEq)]
384#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
385struct GlyphPairPosBuilder(
386 BTreeMap<GlyphId16, BTreeMap<GlyphId16, (ValueRecordBuilder, ValueRecordBuilder)>>,
387);
388
389#[derive(Clone, Debug, PartialEq)]
390#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
391struct ClassPairPosSubtable {
392 items:
393 BTreeMap<IntSet<GlyphId16>, BTreeMap<GlyphSet, (ValueRecordBuilder, ValueRecordBuilder)>>,
394 classdef_1: ClassDefBuilder,
395 classdef_2: ClassDefBuilder,
396}
397
398impl Default for ClassPairPosSubtable {
399 fn default() -> Self {
400 Self {
401 items: Default::default(),
402 classdef_1: ClassDefBuilder::new_using_class_0(),
403 classdef_2: Default::default(),
404 }
405 }
406}
407
408#[derive(Clone, Debug, Default, PartialEq)]
409#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
410struct ClassPairPosBuilder(Vec<ClassPairPosSubtable>);
411
412impl ClassPairPosBuilder {
413 fn insert(
414 &mut self,
415 class1: GlyphSet,
416 record1: ValueRecordBuilder,
417 class2: GlyphSet,
418 record2: ValueRecordBuilder,
419 ) {
420 if self.0.last().map(|last| last.can_add(&class1, &class2)) != Some(true) {
421 self.0.push(Default::default())
422 }
423 self.0
424 .last_mut()
425 .unwrap()
426 .add(class1, class2, record1, record2);
427 }
428}
429
430impl ClassPairPosSubtable {
431 fn can_add(&self, class1: &GlyphSet, class2: &GlyphSet) -> bool {
432 self.classdef_1.can_add(class1) && self.classdef_2.can_add(class2)
433 }
434
435 fn add(
436 &mut self,
437 class1: GlyphSet,
438 class2: GlyphSet,
439 record1: ValueRecordBuilder,
440 record2: ValueRecordBuilder,
441 ) {
442 self.classdef_1.checked_add(class1.clone());
443 self.classdef_2.checked_add(class2.clone());
444 self.items
445 .entry(class1)
446 .or_default()
447 .insert(class2, (record1, record2));
448 }
449
450 fn compute_value_formats(&self) -> (ValueFormat, ValueFormat) {
457 self.items.values().flat_map(|v| v.values()).fold(
458 (ValueFormat::empty(), ValueFormat::empty()),
459 |(acc1, acc2), (f1, f2)| (acc1 | f1.format(), acc2 | f2.format()),
460 )
461 }
462}
463
464impl PairPosBuilder {
465 pub fn is_empty(&self) -> bool {
467 self.pairs.0.is_empty() && self.classes.0.is_empty()
468 }
469
470 pub fn len(&self) -> usize {
472 self.pairs.0.values().map(|vals| vals.len()).sum::<usize>()
473 + self
474 .classes
475 .0
476 .iter()
477 .map(|sub| sub.items.values().len())
478 .sum::<usize>()
479 }
480
481 pub fn insert_pair(
483 &mut self,
484 glyph1: GlyphId16,
485 record1: ValueRecordBuilder,
486 glyph2: GlyphId16,
487 record2: ValueRecordBuilder,
488 ) {
489 self.pairs
501 .0
502 .entry(glyph1)
503 .or_default()
504 .entry(glyph2)
505 .or_insert((record1, record2));
506 }
507
508 pub fn insert_classes(
510 &mut self,
511 class1: GlyphSet,
512 record1: ValueRecordBuilder,
513 class2: GlyphSet,
514 record2: ValueRecordBuilder,
515 ) {
516 self.classes.insert(class1, record1, class2, record2)
517 }
518}
519
520impl Builder for PairPosBuilder {
521 type Output = Vec<PairPos>;
522
523 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
524 let mut out = self.pairs.build(var_store);
525 out.extend(self.classes.build(var_store));
526 out
527 }
528}
529
530impl Builder for GlyphPairPosBuilder {
531 type Output = Vec<PairPos>;
532
533 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
534 let mut split_by_format = BTreeMap::<_, BTreeMap<_, Vec<_>>>::default();
535 for (g1, map) in self.0 {
536 for (g2, (v1, v2)) in map {
537 split_by_format
538 .entry((v1.format(), v2.format()))
539 .or_default()
540 .entry(g1)
541 .or_default()
542 .push(PairValueRecord::new(
543 g2,
544 v1.build(var_store),
545 v2.build(var_store),
546 ));
547 }
548 }
549
550 split_by_format
551 .into_values()
552 .map(|map| {
553 let coverage = map.keys().copied().collect();
554 let pair_sets = map.into_values().map(PairSet::new).collect();
555 PairPos::format_1(coverage, pair_sets)
556 })
557 .collect()
558 }
559}
560
561impl Builder for ClassPairPosBuilder {
562 type Output = Vec<PairPos>;
563
564 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
565 self.0.into_iter().map(|sub| sub.build(var_store)).collect()
566 }
567}
568
569impl Builder for ClassPairPosSubtable {
570 type Output = PairPos;
571
572 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
573 assert!(!self.items.is_empty(), "filter before here");
574 let (format1, format2) = self.compute_value_formats();
575 let empty_record = Class2Record::new(
579 ValueRecord::new().with_explicit_value_format(format1),
580 ValueRecord::new().with_explicit_value_format(format2),
581 );
582
583 let (class1def, class1map) = self.classdef_1.build_with_mapping();
584 let (class2def, class2map) = self.classdef_2.build_with_mapping();
585
586 let coverage = self.items.keys().flat_map(GlyphSet::iter).collect();
587
588 let mut out = vec![Class1Record::default(); self.items.len()];
589 for (cls1, stuff) in self.items {
590 let idx = class1map.get(&cls1).unwrap();
591 let mut records = vec![empty_record.clone(); class2map.len() + 1];
592 for (class, (v1, v2)) in stuff {
593 let idx = class2map.get(&class).unwrap();
594 records[*idx as usize] = Class2Record::new(
595 v1.build(var_store).with_explicit_value_format(format1),
596 v2.build(var_store).with_explicit_value_format(format2),
597 );
598 }
599 out[*idx as usize] = Class1Record::new(records);
600 }
601 PairPos::format_2(coverage, class1def, class2def, out)
602 }
603}
604
605#[derive(Clone, Debug, Default, PartialEq, Eq)]
607#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
608pub struct CursivePosBuilder {
609 items: BTreeMap<GlyphId16, (Option<AnchorBuilder>, Option<AnchorBuilder>)>,
611}
612
613impl CursivePosBuilder {
614 pub fn len(&self) -> usize {
616 self.items.len()
617 }
618
619 pub fn is_empty(&self) -> bool {
621 self.items.is_empty()
622 }
623
624 pub fn insert(
626 &mut self,
627 glyph: GlyphId16,
628 entry: Option<AnchorBuilder>,
629 exit: Option<AnchorBuilder>,
630 ) {
631 self.items.insert(glyph, (entry, exit));
632 }
633}
634
635impl Builder for CursivePosBuilder {
636 type Output = Vec<CursivePosFormat1>;
637
638 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
639 let coverage = self.items.keys().copied().collect();
640 let records = self
641 .items
642 .into_values()
643 .map(|(entry, exit)| {
644 EntryExitRecord::new(
645 entry.map(|x| x.build(var_store)),
646 exit.map(|x| x.build(var_store)),
647 )
648 })
649 .collect();
650 vec![CursivePosFormat1::new(coverage, records)]
651 }
652}
653
654#[derive(Clone, Debug, Default, PartialEq, Eq)]
656#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
657struct MarkList {
658 glyphs: BTreeMap<GlyphId16, (u16, AnchorBuilder)>,
660 classes: HashMap<String, u16>,
662}
663
664impl MarkList {
665 fn insert(
669 &mut self,
670 glyph: GlyphId16,
671 class: &str,
672 anchor: AnchorBuilder,
673 ) -> Result<u16, PreviouslyAssignedClass> {
674 let next_id = self.classes.len().try_into().unwrap();
675 let id = self.classes.get(class).copied().unwrap_or_else(|| {
676 self.classes.insert(class.to_owned(), next_id);
677 next_id
678 });
679 if let Some(prev) = self
680 .glyphs
681 .insert(glyph, (id, anchor))
682 .filter(|prev| prev.0 != id)
683 {
684 let class = self
685 .classes
686 .iter()
687 .find_map(|(name, idx)| (*idx == prev.0).then(|| name.clone()))
688 .unwrap();
689
690 return Err(PreviouslyAssignedClass {
691 glyph_id: glyph,
692 class,
693 });
694 }
695 Ok(id)
696 }
697
698 fn glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
699 self.glyphs.keys().copied()
700 }
701
702 fn get_class(&self, class_name: &str) -> u16 {
703 *self
704 .classes
705 .get(class_name)
706 .expect("marks added before bases")
708 }
709}
710
711impl Builder for MarkList {
712 type Output = (CoverageTable, MarkArray);
713
714 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
715 let coverage = self.glyphs().collect();
716 let array = MarkArray::new(
717 self.glyphs
718 .into_values()
719 .map(|(class, anchor)| MarkRecord::new(class, anchor.build(var_store)))
720 .collect(),
721 );
722 (coverage, array)
723 }
724}
725
726#[derive(Clone, Debug, Default, PartialEq, Eq)]
728#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
729pub struct MarkToBaseBuilder {
730 marks: MarkList,
731 bases: BTreeMap<GlyphId16, Vec<(u16, AnchorBuilder)>>,
732}
733
734#[derive(Clone, Debug, Default)]
736pub struct PreviouslyAssignedClass {
737 pub glyph_id: GlyphId16,
739 pub class: String,
741}
742
743impl std::error::Error for PreviouslyAssignedClass {}
744
745impl std::fmt::Display for PreviouslyAssignedClass {
746 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
747 write!(
748 f,
749 "Glyph '{}' was previously assigned to class '{}'",
750 self.glyph_id.to_u16(),
751 self.class
752 )
753 }
754}
755
756impl MarkToBaseBuilder {
757 pub fn len(&self) -> usize {
759 self.bases.len()
760 }
761
762 pub fn is_empty(&self) -> bool {
764 self.bases.is_empty()
765 }
766
767 pub fn insert_mark(
772 &mut self,
773 glyph: GlyphId16,
774 class: &str,
775 anchor: AnchorBuilder,
776 ) -> Result<u16, PreviouslyAssignedClass> {
777 self.marks.insert(glyph, class, anchor)
778 }
779
780 pub fn insert_base(&mut self, glyph: GlyphId16, class: &str, anchor: AnchorBuilder) {
782 let class = self.marks.get_class(class);
783 self.bases.entry(glyph).or_default().push((class, anchor))
784 }
785
786 pub fn base_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
788 self.bases.keys().copied()
789 }
790
791 pub fn mark_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
793 self.marks.glyphs()
794 }
795}
796
797impl Builder for MarkToBaseBuilder {
798 type Output = Vec<MarkBasePosFormat1>;
799
800 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
801 let MarkToBaseBuilder { marks, bases } = self;
802 let n_classes = marks.classes.len();
803
804 let (mark_coverage, mark_array) = marks.build(var_store);
805 let base_coverage = bases.keys().copied().collect();
806 let base_records = bases
807 .into_values()
808 .map(|anchors| {
809 let mut anchor_offsets = vec![None; n_classes];
810 for (class, anchor) in anchors {
811 anchor_offsets[class as usize] = Some(anchor.build(var_store));
812 }
813 BaseRecord::new(anchor_offsets)
814 })
815 .collect();
816 let base_array = BaseArray::new(base_records);
817 vec![MarkBasePosFormat1::new(
818 mark_coverage,
819 base_coverage,
820 mark_array,
821 base_array,
822 )]
823 }
824}
825
826#[derive(Clone, Debug, Default, PartialEq, Eq)]
828#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
829pub struct MarkToLigBuilder {
830 marks: MarkList,
831 ligatures: BTreeMap<GlyphId16, Vec<BTreeMap<String, AnchorBuilder>>>,
832}
833
834impl MarkToLigBuilder {
835 pub fn len(&self) -> usize {
837 self.ligatures.len()
838 }
839
840 pub fn is_empty(&self) -> bool {
842 self.ligatures.is_empty()
843 }
844
845 pub fn insert_mark(
850 &mut self,
851 glyph: GlyphId16,
852 class: &str,
853 anchor: AnchorBuilder,
854 ) -> Result<u16, PreviouslyAssignedClass> {
855 self.marks.insert(glyph, class, anchor)
856 }
857
858 pub fn add_ligature_components_directly(
871 &mut self,
872 glyph: GlyphId16,
873 components: Vec<BTreeMap<String, AnchorBuilder>>,
874 ) {
875 self.ligatures.insert(glyph, components);
876 }
877
878 pub fn insert_ligature(
887 &mut self,
888 glyph: GlyphId16,
889 class: &str,
890 components: Vec<Option<AnchorBuilder>>,
891 ) {
892 let component_list = self.ligatures.entry(glyph).or_default();
893 if component_list.is_empty() {
894 component_list.resize(components.len(), Default::default());
895 } else if component_list.len() != components.len() {
896 log::warn!("mismatched component lengths for anchors in glyph {glyph}");
897 }
898 for (i, anchor) in components.into_iter().enumerate() {
899 if let Some(anchor) = anchor {
900 component_list[i].insert(class.to_owned(), anchor);
901 }
902 }
903 }
904
905 pub fn mark_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
907 self.marks.glyphs()
908 }
909
910 pub fn lig_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
912 self.ligatures.keys().copied()
913 }
914}
915
916impl Builder for MarkToLigBuilder {
917 type Output = Vec<MarkLigPosFormat1>;
918
919 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
920 let MarkToLigBuilder { marks, ligatures } = self;
921 let n_classes = marks.classes.len();
922
923 let ligature_coverage = ligatures.keys().copied().collect();
928 let ligature_array = ligatures
929 .into_values()
930 .map(|components| {
931 let comp_records = components
932 .into_iter()
933 .map(|anchors| {
934 let mut anchor_offsets = vec![None; n_classes];
935 for (class, anchor) in anchors {
936 let class_idx = marks.get_class(&class);
937 anchor_offsets[class_idx as usize] = Some(anchor.build(var_store));
938 }
939 ComponentRecord::new(anchor_offsets)
940 })
941 .collect();
942 LigatureAttach::new(comp_records)
943 })
944 .collect();
945 let ligature_array = LigatureArray::new(ligature_array);
946 let (mark_coverage, mark_array) = marks.build(var_store);
947 vec![MarkLigPosFormat1::new(
948 mark_coverage,
949 ligature_coverage,
950 mark_array,
951 ligature_array,
952 )]
953 }
954}
955
956#[derive(Clone, Debug, Default, PartialEq, Eq)]
958#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
959pub struct MarkToMarkBuilder {
960 attaching_marks: MarkList,
961 base_marks: BTreeMap<GlyphId16, Vec<(u16, AnchorBuilder)>>,
962}
963
964impl MarkToMarkBuilder {
965 pub fn len(&self) -> usize {
967 self.base_marks.len()
968 }
969
970 pub fn is_empty(&self) -> bool {
972 self.base_marks.is_empty()
973 }
974
975 pub fn insert_mark1(
980 &mut self,
981 glyph: GlyphId16,
982 class: &str,
983 anchor: AnchorBuilder,
984 ) -> Result<u16, PreviouslyAssignedClass> {
985 self.attaching_marks.insert(glyph, class, anchor)
986 }
987
988 pub fn insert_mark2(&mut self, glyph: GlyphId16, class: &str, anchor: AnchorBuilder) {
990 let id = self.attaching_marks.get_class(class);
991 self.base_marks.entry(glyph).or_default().push((id, anchor))
992 }
993
994 pub fn mark1_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
996 self.attaching_marks.glyphs()
997 }
998
999 pub fn mark2_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
1001 self.base_marks.keys().copied()
1002 }
1003}
1004
1005impl Builder for MarkToMarkBuilder {
1006 type Output = Vec<MarkMarkPosFormat1>;
1007
1008 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
1009 let MarkToMarkBuilder {
1010 attaching_marks,
1011 base_marks,
1012 } = self;
1013 let n_classes = attaching_marks.classes.len();
1014
1015 let (mark_coverage, mark_array) = attaching_marks.build(var_store);
1016 let mark2_coverage = base_marks.keys().copied().collect();
1017 let mark2_records = base_marks
1018 .into_values()
1019 .map(|anchors| {
1020 let mut anchor_offsets = vec![None; n_classes];
1021 for (class, anchor) in anchors {
1022 anchor_offsets[class as usize] = Some(anchor.build(var_store));
1023 }
1024 Mark2Record::new(anchor_offsets)
1025 })
1026 .collect();
1027 let mark2array = Mark2Array::new(mark2_records);
1028 vec![MarkMarkPosFormat1::new(
1029 mark_coverage,
1030 mark2_coverage,
1031 mark_array,
1032 mark2array,
1033 )]
1034 }
1035}