1use std::{collections::BTreeMap, convert::TryFrom};
4
5use types::{FixedSize, GlyphId16, Offset16};
6
7use crate::{
8 tables::{
9 layout::{builders::Builder, CoverageTable},
10 variations::ivs_builder::VariationStoreBuilder,
11 },
12 FontWrite,
13};
14
15#[derive(Clone, Debug)]
19struct TableSplitter<T: SplitTable> {
20 finished: Vec<T>,
21 current_coverage: Vec<GlyphId16>,
22 current_items: Vec<T::Component>,
23 current_size: usize,
24}
25
26trait SplitTable {
28 type Component;
30
31 fn size_for_item(item: &Self::Component) -> usize;
39 fn initial_size_for_item(item: &Self::Component) -> usize;
44 fn instantiate(coverage: CoverageTable, items: Vec<Self::Component>) -> Self;
45}
46
47impl<T: SplitTable + FontWrite> TableSplitter<T> {
48 const MAX_TABLE_SIZE: usize = u16::MAX as usize;
49
50 fn new() -> Self {
51 Self {
52 finished: Vec::new(),
53 current_coverage: Vec::new(),
54 current_items: Vec::new(),
55 current_size: 0,
56 }
57 }
58
59 fn add(&mut self, gid: GlyphId16, item: T::Component) {
60 let item_size = T::size_for_item(&item);
61 if item_size + self.current_size > Self::MAX_TABLE_SIZE {
62 let current_len = self.current_coverage.len();
63 self.finish_current();
64 let type_ = self.finished.last().unwrap().table_type();
65 log::info!("adding split in {type_} at {current_len}");
66 }
67
68 if self.current_size == 0 {
69 self.current_size = T::initial_size_for_item(&item);
70 }
71 self.current_coverage.push(gid);
72 self.current_items.push(item);
73 self.current_size += item_size + GlyphId16::RAW_BYTE_LEN;
75 }
76
77 fn finish_current(&mut self) {
78 if !self.current_coverage.is_empty() {
79 let coverage = std::mem::take(&mut self.current_coverage).into();
80 self.finished.push(T::instantiate(
81 coverage,
82 std::mem::take(&mut self.current_items),
83 ));
84 self.current_size = 0;
85 }
86 }
87
88 fn finish(mut self) -> Vec<T> {
89 self.finish_current();
90 self.finished
91 }
92}
93#[derive(Clone, Debug, Default, PartialEq, Eq)]
95pub struct SingleSubBuilder {
96 items: BTreeMap<GlyphId16, GlyphId16>,
97}
98
99impl SingleSubBuilder {
100 pub fn insert(&mut self, target: GlyphId16, replacement: GlyphId16) {
105 self.items.insert(target, replacement);
106 }
107
108 pub fn can_add(&self, target: GlyphId16, replacement: GlyphId16) -> bool {
113 !matches!(self.items.get(&target), Some(x) if *x != replacement)
115 }
116
117 pub fn len(&self) -> usize {
119 self.items.len()
120 }
121
122 pub fn is_empty(&self) -> bool {
124 self.items.is_empty()
125 }
126
127 #[deprecated(since = "0.38.2", note = "use ::iter instead")]
131 pub fn iter_pairs(&self) -> impl Iterator<Item = (GlyphId16, GlyphId16)> + '_ {
132 self.iter()
133 }
134
135 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, GlyphId16)> + '_ {
137 self.items.iter().map(|(target, alt)| (*target, *alt))
138 }
139
140 pub fn promote_to_multi_sub(self) -> MultipleSubBuilder {
145 MultipleSubBuilder {
146 items: self
147 .items
148 .into_iter()
149 .map(|(key, gid)| (key, vec![gid]))
150 .collect(),
151 }
152 }
153
154 pub fn promote_to_ligature_sub(self) -> LigatureSubBuilder {
159 let mut items = BTreeMap::new();
160 for (from, to) in self.items.into_iter() {
161 items
162 .entry(from)
163 .or_insert(Vec::new())
164 .push((Vec::new(), to));
165 }
166 LigatureSubBuilder { items }
167 }
168}
169
170impl Builder for SingleSubBuilder {
171 type Output = Vec<super::SingleSubst>;
172
173 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
174 if self.items.is_empty() {
175 return Default::default();
176 }
177 let delta = self
180 .items
181 .iter()
182 .map(|(k, v)| v.to_u16() as i32 - k.to_u16() as i32)
183 .reduce(|acc, val| if acc == val { acc } else { i32::MAX })
184 .and_then(|delta| i16::try_from(delta).ok());
185
186 let coverage = self.items.keys().copied().collect();
187 if let Some(delta) = delta {
188 vec![super::SingleSubst::format_1(coverage, delta)]
189 } else {
190 let replacements = self.items.values().copied().collect();
191 vec![super::SingleSubst::format_2(coverage, replacements)]
192 }
193 }
194}
195
196#[derive(Clone, Debug, Default, PartialEq, Eq)]
198pub struct MultipleSubBuilder {
199 items: BTreeMap<GlyphId16, Vec<GlyphId16>>,
200}
201
202impl Builder for MultipleSubBuilder {
203 type Output = Vec<super::MultipleSubstFormat1>;
204
205 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
206 if self.items.is_empty() {
207 return Default::default();
208 }
209 let coverage = self.items.keys().copied().collect();
210 let seq_tables = self.items.into_values().map(super::Sequence::new).collect();
211 vec![super::MultipleSubstFormat1::new(coverage, seq_tables)]
212 }
213}
214
215impl MultipleSubBuilder {
216 pub fn len(&self) -> usize {
218 self.items.len()
219 }
220
221 pub fn is_empty(&self) -> bool {
223 self.items.is_empty()
224 }
225
226 pub fn insert(&mut self, target: GlyphId16, replacement: Vec<GlyphId16>) {
231 self.items.insert(target, replacement);
232 }
233
234 pub fn can_add(&self, target: GlyphId16, replacement: &[GlyphId16]) -> bool {
236 match self.items.get(&target) {
237 None => true,
238 Some(thing) => thing == replacement,
239 }
240 }
241
242 pub fn iter(&self) -> impl Iterator<Item = (&GlyphId16, &Vec<GlyphId16>)> {
244 self.items.iter()
245 }
246}
247
248#[derive(Clone, Debug, Default, PartialEq, Eq)]
250pub struct AlternateSubBuilder {
251 items: BTreeMap<GlyphId16, Vec<GlyphId16>>,
252}
253
254impl AlternateSubBuilder {
255 pub fn len(&self) -> usize {
257 self.items.len()
258 }
259
260 pub fn is_empty(&self) -> bool {
262 self.items.is_empty()
263 }
264
265 pub fn insert(&mut self, target: GlyphId16, replacement: Vec<GlyphId16>) {
267 self.items.insert(target, replacement);
268 }
269
270 pub fn iter(&self) -> impl Iterator<Item = (&GlyphId16, &Vec<GlyphId16>)> {
272 self.items.iter()
273 }
274
275 pub fn iter_pairs(&self) -> impl Iterator<Item = (GlyphId16, GlyphId16)> + '_ {
279 self.items
280 .iter()
281 .flat_map(|(target, alt)| alt.iter().map(|alt| (*target, *alt)))
282 }
283}
284
285impl Builder for AlternateSubBuilder {
286 type Output = Vec<super::AlternateSubstFormat1>;
287
288 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
289 if self.items.is_empty() {
290 return Default::default();
291 }
292 let coverage = self.items.keys().copied().collect();
293 let seq_tables = self
294 .items
295 .into_values()
296 .map(super::AlternateSet::new)
297 .collect();
298 vec![super::AlternateSubstFormat1::new(coverage, seq_tables)]
299 }
300}
301
302#[derive(Clone, Debug, Default, PartialEq, Eq)]
304pub struct LigatureSubBuilder {
305 items: BTreeMap<GlyphId16, Vec<(Vec<GlyphId16>, GlyphId16)>>,
306}
307
308impl LigatureSubBuilder {
309 pub fn len(&self) -> usize {
311 self.items.len()
312 }
313
314 pub fn is_empty(&self) -> bool {
316 self.items.is_empty()
317 }
318
319 pub fn insert(&mut self, target: Vec<GlyphId16>, replacement: GlyphId16) {
321 let (first, rest) = target.split_first().unwrap();
322 let entry = self.items.entry(*first).or_default();
323 if !entry
325 .iter()
326 .any(|existing| existing.0 == rest && existing.1 == replacement)
327 {
328 entry.push((rest.to_owned(), replacement))
329 }
330 }
331
332 pub fn can_add(&self, target: &[GlyphId16], replacement: GlyphId16) -> bool {
334 let Some((first, rest)) = target.split_first() else {
335 return false;
336 };
337 match self.items.get(first) {
338 Some(ligs) => !ligs
339 .iter()
340 .any(|(seq, target)| seq == rest && *target != replacement),
341 None => true,
342 }
343 }
344
345 pub fn iter(&self) -> impl Iterator<Item = (&GlyphId16, &Vec<(Vec<GlyphId16>, GlyphId16)>)> {
350 self.items.iter()
351 }
352}
353
354impl Builder for LigatureSubBuilder {
355 type Output = Vec<super::LigatureSubstFormat1>;
356
357 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
358 let mut splitter = TableSplitter::<super::LigatureSubstFormat1>::new();
359 for (gid, mut ligs) in self.items.into_iter() {
360 ligs.sort_by_key(|(lig, _)| std::cmp::Reverse(lig.len()));
363 let lig_set = super::LigatureSet::new(
364 ligs.into_iter()
365 .map(|(components, replacement)| super::Ligature::new(replacement, components))
366 .collect(),
367 );
368 splitter.add(gid, lig_set);
369 }
370 splitter.finish()
371 }
372}
373
374impl SplitTable for super::LigatureSubstFormat1 {
375 type Component = super::LigatureSet;
376
377 fn size_for_item(item: &Self::Component) -> usize {
378 item.compute_size()
379 }
380
381 fn initial_size_for_item(_item: &Self::Component) -> usize {
382 u16::RAW_BYTE_LEN * 4
384 }
385
386 fn instantiate(coverage: CoverageTable, items: Vec<Self::Component>) -> Self {
387 Self::new(coverage, items)
388 }
389}
390
391impl super::LigatureSet {
392 fn compute_size(&self) -> usize {
393 u16::RAW_BYTE_LEN
395 + Offset16::RAW_BYTE_LEN * self.ligatures.len()
397 + self
399 .ligatures
400 .iter()
401 .map(|lig| lig.compute_size())
402 .sum::<usize>()
403 }
404}
405
406impl super::Ligature {
407 fn compute_size(&self) -> usize {
408 u16::RAW_BYTE_LEN
410 + u16::RAW_BYTE_LEN
412 + u16::RAW_BYTE_LEN * self.component_glyph_ids.len()
414 }
415}
416
417#[cfg(test)]
418mod tests {
419 use crate::tables::gsub::LigatureSubstFormat1;
420
421 use super::*;
422
423 fn make_lig_table(n_bytes: u16, first: u16) -> super::super::Ligature {
424 assert!(n_bytes >= 6, "minimum table size");
425 assert!(n_bytes % 2 == 0, "can only generate even sizes: {n_bytes}");
426 let n_glyphs = (n_bytes - 6) / 2;
428 let components = (first..=first + n_glyphs).map(GlyphId16::new).collect();
429 super::super::Ligature::new(GlyphId16::new(first), components)
430 }
431 fn make_2048_bytes_of_ligature() -> super::super::LigatureSet {
432 let lig1 = make_lig_table(1022, 1);
436 let lig2 = make_lig_table(1022, 3);
437 super::super::LigatureSet::new(vec![lig1, lig2])
438 }
439
440 #[test]
441 fn who_tests_the_testers1() {
442 for size in [6, 12, 144, 2046, u16::MAX - 1] {
443 let table = make_lig_table(size, 1);
444 let bytes = crate::dump_table(&table).unwrap();
445 assert_eq!(bytes.len(), size as usize);
446 }
447 }
448
449 #[test]
450 fn splitting_ligature_subs() {
451 let mut splitter = TableSplitter::<LigatureSubstFormat1>::new();
452 let ligset = make_2048_bytes_of_ligature();
453 for gid in 0u16..31 {
454 splitter.add(GlyphId16::new(gid), ligset.clone());
456 }
457
458 assert_eq!(splitter.clone().finish().len(), 1);
460 splitter.add(GlyphId16::new(32), ligset);
461 assert_eq!(splitter.finish().len(), 2)
463 }
464
465 #[test]
467 fn empty_builders_build_no_subtables() {
468 let vs = &mut VariationStoreBuilder::new(0);
469 assert!(SingleSubBuilder::default().build(vs).is_empty());
470 assert!(MultipleSubBuilder::default().build(vs).is_empty());
471 assert!(AlternateSubBuilder::default().build(vs).is_empty());
472 assert!(LigatureSubBuilder::default().build(vs).is_empty());
473 }
474}