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 insert(&mut self, glyph: GlyphId16, record: ValueRecordBuilder) {
281 self.items.insert(glyph, record);
282 }
283
284 pub fn can_add(&self, glyph: GlyphId16, value: &ValueRecordBuilder) -> bool {
286 self.items
287 .get(&glyph)
288 .map(|existing| existing == value)
289 .unwrap_or(true)
290 }
291}
292
293impl Builder for SinglePosBuilder {
294 type Output = Vec<SinglePos>;
295
296 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
297 fn build_subtable(items: BTreeMap<GlyphId16, &ValueRecord>) -> SinglePos {
298 let first = *items.values().next().unwrap();
299 let use_format_1 = first.format().is_empty() || items.values().all(|val| val == &first);
300 let coverage: CoverageTable = items.keys().copied().collect();
301 if use_format_1 {
302 SinglePos::format_1(coverage.clone(), first.clone())
303 } else {
304 SinglePos::format_2(coverage, items.into_values().cloned().collect())
305 }
306 }
307 const NEW_SUBTABLE_COST: usize = 10;
308 let items = self
309 .items
310 .into_iter()
311 .map(|(glyph, anchor)| (glyph, anchor.build(var_store)))
312 .collect::<BTreeMap<_, _>>();
313
314 let mut subtables = Vec::new();
316 let mut group_by_record: HashMap<&ValueRecord, BTreeMap<GlyphId16, &ValueRecord>> =
317 Default::default();
318
319 for (gid, value) in &items {
322 group_by_record
323 .entry(value)
324 .or_default()
325 .insert(*gid, value);
326 }
327 let mut group_by_format: HashMap<ValueFormat, BTreeMap<GlyphId16, &ValueRecord>> =
328 Default::default();
329 for (value, glyphs) in group_by_record {
330 if glyphs.len() * value.encoded_size() > NEW_SUBTABLE_COST {
332 subtables.push(glyphs);
333 } else {
336 group_by_format
337 .entry(value.format())
338 .or_default()
339 .extend(glyphs.into_iter());
340 }
341 }
342 subtables.extend(group_by_format.into_values());
343
344 let mut output = subtables
345 .into_iter()
346 .map(build_subtable)
347 .collect::<Vec<_>>();
348
349 output.sort_unstable_by_key(|table| match table {
352 SinglePos::Format1(table) => cmp_coverage_key(&table.coverage),
353 SinglePos::Format2(table) => cmp_coverage_key(&table.coverage),
354 });
355 output
356 }
357}
358
359fn cmp_coverage_key(coverage: &CoverageTable) -> impl Ord {
360 (std::cmp::Reverse(coverage.len()), coverage.iter().next())
361}
362
363#[derive(Clone, Debug, Default, PartialEq)]
367#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
368pub struct PairPosBuilder {
369 pairs: GlyphPairPosBuilder,
370 classes: ClassPairPosBuilder,
371}
372
373#[derive(Clone, Debug, Default, PartialEq)]
374#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
375struct GlyphPairPosBuilder(
376 BTreeMap<GlyphId16, BTreeMap<GlyphId16, (ValueRecordBuilder, ValueRecordBuilder)>>,
377);
378
379#[derive(Clone, Debug, PartialEq)]
380#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
381struct ClassPairPosSubtable {
382 items:
383 BTreeMap<IntSet<GlyphId16>, BTreeMap<GlyphSet, (ValueRecordBuilder, ValueRecordBuilder)>>,
384 classdef_1: ClassDefBuilder,
385 classdef_2: ClassDefBuilder,
386}
387
388impl Default for ClassPairPosSubtable {
389 fn default() -> Self {
390 Self {
391 items: Default::default(),
392 classdef_1: ClassDefBuilder::new_using_class_0(),
393 classdef_2: Default::default(),
394 }
395 }
396}
397
398#[derive(Clone, Debug, Default, PartialEq)]
399#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
400struct ClassPairPosBuilder(Vec<ClassPairPosSubtable>);
401
402impl ClassPairPosBuilder {
403 fn insert(
404 &mut self,
405 class1: GlyphSet,
406 record1: ValueRecordBuilder,
407 class2: GlyphSet,
408 record2: ValueRecordBuilder,
409 ) {
410 if self.0.last().map(|last| last.can_add(&class1, &class2)) != Some(true) {
411 self.0.push(Default::default())
412 }
413 self.0
414 .last_mut()
415 .unwrap()
416 .add(class1, class2, record1, record2);
417 }
418}
419
420impl ClassPairPosSubtable {
421 fn can_add(&self, class1: &GlyphSet, class2: &GlyphSet) -> bool {
422 self.classdef_1.can_add(class1) && self.classdef_2.can_add(class2)
423 }
424
425 fn add(
426 &mut self,
427 class1: GlyphSet,
428 class2: GlyphSet,
429 record1: ValueRecordBuilder,
430 record2: ValueRecordBuilder,
431 ) {
432 self.classdef_1.checked_add(class1.clone());
433 self.classdef_2.checked_add(class2.clone());
434 self.items
435 .entry(class1)
436 .or_default()
437 .insert(class2, (record1, record2));
438 }
439
440 fn compute_value_formats(&self) -> (ValueFormat, ValueFormat) {
447 self.items.values().flat_map(|v| v.values()).fold(
448 (ValueFormat::empty(), ValueFormat::empty()),
449 |(acc1, acc2), (f1, f2)| (acc1 | f1.format(), acc2 | f2.format()),
450 )
451 }
452}
453
454impl PairPosBuilder {
455 pub fn is_empty(&self) -> bool {
457 self.pairs.0.is_empty() && self.classes.0.is_empty()
458 }
459
460 pub fn len(&self) -> usize {
462 self.pairs.0.values().map(|vals| vals.len()).sum::<usize>()
463 + self
464 .classes
465 .0
466 .iter()
467 .map(|sub| sub.items.values().len())
468 .sum::<usize>()
469 }
470
471 pub fn insert_pair(
473 &mut self,
474 glyph1: GlyphId16,
475 record1: ValueRecordBuilder,
476 glyph2: GlyphId16,
477 record2: ValueRecordBuilder,
478 ) {
479 self.pairs
491 .0
492 .entry(glyph1)
493 .or_default()
494 .entry(glyph2)
495 .or_insert((record1, record2));
496 }
497
498 pub fn insert_classes(
500 &mut self,
501 class1: GlyphSet,
502 record1: ValueRecordBuilder,
503 class2: GlyphSet,
504 record2: ValueRecordBuilder,
505 ) {
506 self.classes.insert(class1, record1, class2, record2)
507 }
508}
509
510impl Builder for PairPosBuilder {
511 type Output = Vec<PairPos>;
512
513 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
514 let mut out = self.pairs.build(var_store);
515 out.extend(self.classes.build(var_store));
516 out
517 }
518}
519
520impl Builder for GlyphPairPosBuilder {
521 type Output = Vec<PairPos>;
522
523 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
524 let mut split_by_format = BTreeMap::<_, BTreeMap<_, Vec<_>>>::default();
525 for (g1, map) in self.0 {
526 for (g2, (v1, v2)) in map {
527 split_by_format
528 .entry((v1.format(), v2.format()))
529 .or_default()
530 .entry(g1)
531 .or_default()
532 .push(PairValueRecord::new(
533 g2,
534 v1.build(var_store),
535 v2.build(var_store),
536 ));
537 }
538 }
539
540 split_by_format
541 .into_values()
542 .map(|map| {
543 let coverage = map.keys().copied().collect();
544 let pair_sets = map.into_values().map(PairSet::new).collect();
545 PairPos::format_1(coverage, pair_sets)
546 })
547 .collect()
548 }
549}
550
551impl Builder for ClassPairPosBuilder {
552 type Output = Vec<PairPos>;
553
554 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
555 self.0.into_iter().map(|sub| sub.build(var_store)).collect()
556 }
557}
558
559impl Builder for ClassPairPosSubtable {
560 type Output = PairPos;
561
562 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
563 assert!(!self.items.is_empty(), "filter before here");
564 let (format1, format2) = self.compute_value_formats();
565 let empty_record = Class2Record::new(
569 ValueRecord::new().with_explicit_value_format(format1),
570 ValueRecord::new().with_explicit_value_format(format2),
571 );
572
573 let (class1def, class1map) = self.classdef_1.build_with_mapping();
574 let (class2def, class2map) = self.classdef_2.build_with_mapping();
575
576 let coverage = self.items.keys().flat_map(GlyphSet::iter).collect();
577
578 let mut out = vec![Class1Record::default(); self.items.len()];
579 for (cls1, stuff) in self.items {
580 let idx = class1map.get(&cls1).unwrap();
581 let mut records = vec![empty_record.clone(); class2map.len() + 1];
582 for (class, (v1, v2)) in stuff {
583 let idx = class2map.get(&class).unwrap();
584 records[*idx as usize] = Class2Record::new(
585 v1.build(var_store).with_explicit_value_format(format1),
586 v2.build(var_store).with_explicit_value_format(format2),
587 );
588 }
589 out[*idx as usize] = Class1Record::new(records);
590 }
591 PairPos::format_2(coverage, class1def, class2def, out)
592 }
593}
594
595#[derive(Clone, Debug, Default, PartialEq, Eq)]
597#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
598pub struct CursivePosBuilder {
599 items: BTreeMap<GlyphId16, (Option<AnchorBuilder>, Option<AnchorBuilder>)>,
601}
602
603impl CursivePosBuilder {
604 pub fn insert(
606 &mut self,
607 glyph: GlyphId16,
608 entry: Option<AnchorBuilder>,
609 exit: Option<AnchorBuilder>,
610 ) {
611 self.items.insert(glyph, (entry, exit));
612 }
613}
614
615impl Builder for CursivePosBuilder {
616 type Output = Vec<CursivePosFormat1>;
617
618 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
619 let coverage = self.items.keys().copied().collect();
620 let records = self
621 .items
622 .into_values()
623 .map(|(entry, exit)| {
624 EntryExitRecord::new(
625 entry.map(|x| x.build(var_store)),
626 exit.map(|x| x.build(var_store)),
627 )
628 })
629 .collect();
630 vec![CursivePosFormat1::new(coverage, records)]
631 }
632}
633
634#[derive(Clone, Debug, Default, PartialEq, Eq)]
636#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
637struct MarkList {
638 glyphs: BTreeMap<GlyphId16, (u16, AnchorBuilder)>,
640 classes: HashMap<String, u16>,
642}
643
644impl MarkList {
645 fn insert(
649 &mut self,
650 glyph: GlyphId16,
651 class: &str,
652 anchor: AnchorBuilder,
653 ) -> Result<u16, PreviouslyAssignedClass> {
654 let next_id = self.classes.len().try_into().unwrap();
655 let id = self.classes.get(class).copied().unwrap_or_else(|| {
656 self.classes.insert(class.to_owned(), next_id);
657 next_id
658 });
659 if let Some(prev) = self
660 .glyphs
661 .insert(glyph, (id, anchor))
662 .filter(|prev| prev.0 != id)
663 {
664 let class = self
665 .classes
666 .iter()
667 .find_map(|(name, idx)| (*idx == prev.0).then(|| name.clone()))
668 .unwrap();
669
670 return Err(PreviouslyAssignedClass {
671 glyph_id: glyph,
672 class,
673 });
674 }
675 Ok(id)
676 }
677
678 fn glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
679 self.glyphs.keys().copied()
680 }
681
682 fn get_class(&self, class_name: &str) -> u16 {
683 *self
684 .classes
685 .get(class_name)
686 .expect("marks added before bases")
688 }
689}
690
691impl Builder for MarkList {
692 type Output = (CoverageTable, MarkArray);
693
694 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
695 let coverage = self.glyphs().collect();
696 let array = MarkArray::new(
697 self.glyphs
698 .into_values()
699 .map(|(class, anchor)| MarkRecord::new(class, anchor.build(var_store)))
700 .collect(),
701 );
702 (coverage, array)
703 }
704}
705
706#[derive(Clone, Debug, Default, PartialEq, Eq)]
708#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
709pub struct MarkToBaseBuilder {
710 marks: MarkList,
711 bases: BTreeMap<GlyphId16, Vec<(u16, AnchorBuilder)>>,
712}
713
714#[derive(Clone, Debug, Default)]
716pub struct PreviouslyAssignedClass {
717 pub glyph_id: GlyphId16,
719 pub class: String,
721}
722
723impl std::error::Error for PreviouslyAssignedClass {}
724
725impl std::fmt::Display for PreviouslyAssignedClass {
726 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
727 write!(
728 f,
729 "Glyph '{}' was previously assigned to class '{}'",
730 self.glyph_id.to_u16(),
731 self.class
732 )
733 }
734}
735
736impl MarkToBaseBuilder {
737 pub fn insert_mark(
742 &mut self,
743 glyph: GlyphId16,
744 class: &str,
745 anchor: AnchorBuilder,
746 ) -> Result<u16, PreviouslyAssignedClass> {
747 self.marks.insert(glyph, class, anchor)
748 }
749
750 pub fn insert_base(&mut self, glyph: GlyphId16, class: &str, anchor: AnchorBuilder) {
752 let class = self.marks.get_class(class);
753 self.bases.entry(glyph).or_default().push((class, anchor))
754 }
755
756 pub fn base_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
758 self.bases.keys().copied()
759 }
760
761 pub fn mark_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
763 self.marks.glyphs()
764 }
765}
766
767impl Builder for MarkToBaseBuilder {
768 type Output = Vec<MarkBasePosFormat1>;
769
770 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
771 let MarkToBaseBuilder { marks, bases } = self;
772 let n_classes = marks.classes.len();
773
774 let (mark_coverage, mark_array) = marks.build(var_store);
775 let base_coverage = bases.keys().copied().collect();
776 let base_records = bases
777 .into_values()
778 .map(|anchors| {
779 let mut anchor_offsets = vec![None; n_classes];
780 for (class, anchor) in anchors {
781 anchor_offsets[class as usize] = Some(anchor.build(var_store));
782 }
783 BaseRecord::new(anchor_offsets)
784 })
785 .collect();
786 let base_array = BaseArray::new(base_records);
787 vec![MarkBasePosFormat1::new(
788 mark_coverage,
789 base_coverage,
790 mark_array,
791 base_array,
792 )]
793 }
794}
795
796#[derive(Clone, Debug, Default, PartialEq, Eq)]
798#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
799pub struct MarkToLigBuilder {
800 marks: MarkList,
801 ligatures: BTreeMap<GlyphId16, Vec<BTreeMap<String, AnchorBuilder>>>,
802}
803
804impl MarkToLigBuilder {
805 pub fn is_empty(&self) -> bool {
807 self.ligatures.is_empty()
808 }
809
810 pub fn insert_mark(
815 &mut self,
816 glyph: GlyphId16,
817 class: &str,
818 anchor: AnchorBuilder,
819 ) -> Result<u16, PreviouslyAssignedClass> {
820 self.marks.insert(glyph, class, anchor)
821 }
822
823 pub fn add_ligature_components_directly(
836 &mut self,
837 glyph: GlyphId16,
838 components: Vec<BTreeMap<String, AnchorBuilder>>,
839 ) {
840 self.ligatures.insert(glyph, components);
841 }
842
843 pub fn insert_ligature(
852 &mut self,
853 glyph: GlyphId16,
854 class: &str,
855 components: Vec<Option<AnchorBuilder>>,
856 ) {
857 let component_list = self.ligatures.entry(glyph).or_default();
858 if component_list.is_empty() {
859 component_list.resize(components.len(), Default::default());
860 } else if component_list.len() != components.len() {
861 log::warn!("mismatched component lengths for anchors in glyph {glyph}");
862 }
863 for (i, anchor) in components.into_iter().enumerate() {
864 if let Some(anchor) = anchor {
865 component_list[i].insert(class.to_owned(), anchor);
866 }
867 }
868 }
869
870 pub fn mark_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
872 self.marks.glyphs()
873 }
874
875 pub fn lig_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
877 self.ligatures.keys().copied()
878 }
879}
880
881impl Builder for MarkToLigBuilder {
882 type Output = Vec<MarkLigPosFormat1>;
883
884 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
885 let MarkToLigBuilder { marks, ligatures } = self;
886 let n_classes = marks.classes.len();
887
888 let ligature_coverage = ligatures.keys().copied().collect();
893 let ligature_array = ligatures
894 .into_values()
895 .map(|components| {
896 let comp_records = components
897 .into_iter()
898 .map(|anchors| {
899 let mut anchor_offsets = vec![None; n_classes];
900 for (class, anchor) in anchors {
901 let class_idx = marks.get_class(&class);
902 anchor_offsets[class_idx as usize] = Some(anchor.build(var_store));
903 }
904 ComponentRecord::new(anchor_offsets)
905 })
906 .collect();
907 LigatureAttach::new(comp_records)
908 })
909 .collect();
910 let ligature_array = LigatureArray::new(ligature_array);
911 let (mark_coverage, mark_array) = marks.build(var_store);
912 vec![MarkLigPosFormat1::new(
913 mark_coverage,
914 ligature_coverage,
915 mark_array,
916 ligature_array,
917 )]
918 }
919}
920
921#[derive(Clone, Debug, Default, PartialEq, Eq)]
923#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
924pub struct MarkToMarkBuilder {
925 attaching_marks: MarkList,
926 base_marks: BTreeMap<GlyphId16, Vec<(u16, AnchorBuilder)>>,
927}
928
929impl MarkToMarkBuilder {
930 pub fn insert_mark1(
935 &mut self,
936 glyph: GlyphId16,
937 class: &str,
938 anchor: AnchorBuilder,
939 ) -> Result<u16, PreviouslyAssignedClass> {
940 self.attaching_marks.insert(glyph, class, anchor)
941 }
942
943 pub fn insert_mark2(&mut self, glyph: GlyphId16, class: &str, anchor: AnchorBuilder) {
945 let id = self.attaching_marks.get_class(class);
946 self.base_marks.entry(glyph).or_default().push((id, anchor))
947 }
948
949 pub fn mark1_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
951 self.attaching_marks.glyphs()
952 }
953
954 pub fn mark2_glyphs(&self) -> impl Iterator<Item = GlyphId16> + Clone + '_ {
956 self.base_marks.keys().copied()
957 }
958}
959
960impl Builder for MarkToMarkBuilder {
961 type Output = Vec<MarkMarkPosFormat1>;
962
963 fn build(self, var_store: &mut VariationStoreBuilder) -> Self::Output {
964 let MarkToMarkBuilder {
965 attaching_marks,
966 base_marks,
967 } = self;
968 let n_classes = attaching_marks.classes.len();
969
970 let (mark_coverage, mark_array) = attaching_marks.build(var_store);
971 let mark2_coverage = base_marks.keys().copied().collect();
972 let mark2_records = base_marks
973 .into_values()
974 .map(|anchors| {
975 let mut anchor_offsets = vec![None; n_classes];
976 for (class, anchor) in anchors {
977 anchor_offsets[class as usize] = Some(anchor.build(var_store));
978 }
979 Mark2Record::new(anchor_offsets)
980 })
981 .collect();
982 let mark2array = Mark2Array::new(mark2_records);
983 vec![MarkMarkPosFormat1::new(
984 mark_coverage,
985 mark2_coverage,
986 mark_array,
987 mark2array,
988 )]
989 }
990}