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)]
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 is_empty(&self) -> bool {
119 self.items.is_empty()
120 }
121
122 pub fn iter_pairs(&self) -> impl Iterator<Item = (GlyphId16, GlyphId16)> + '_ {
126 self.items.iter().map(|(target, alt)| (*target, *alt))
127 }
128
129 pub fn promote_to_multi_sub(self) -> MultipleSubBuilder {
134 MultipleSubBuilder {
135 items: self
136 .items
137 .into_iter()
138 .map(|(key, gid)| (key, vec![gid]))
139 .collect(),
140 }
141 }
142}
143
144impl Builder for SingleSubBuilder {
145 type Output = Vec<super::SingleSubst>;
146
147 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
148 if self.items.is_empty() {
149 return Default::default();
150 }
151 let delta = self
154 .items
155 .iter()
156 .map(|(k, v)| v.to_u16() as i32 - k.to_u16() as i32)
157 .reduce(|acc, val| if acc == val { acc } else { i32::MAX })
158 .and_then(|delta| i16::try_from(delta).ok());
159
160 let coverage = self.items.keys().copied().collect();
161 if let Some(delta) = delta {
162 vec![super::SingleSubst::format_1(coverage, delta)]
163 } else {
164 let replacements = self.items.values().copied().collect();
165 vec![super::SingleSubst::format_2(coverage, replacements)]
166 }
167 }
168}
169
170#[derive(Clone, Debug, Default)]
172pub struct MultipleSubBuilder {
173 items: BTreeMap<GlyphId16, Vec<GlyphId16>>,
174}
175
176impl Builder for MultipleSubBuilder {
177 type Output = Vec<super::MultipleSubstFormat1>;
178
179 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
180 let coverage = self.items.keys().copied().collect();
181 let seq_tables = self.items.into_values().map(super::Sequence::new).collect();
182 vec![super::MultipleSubstFormat1::new(coverage, seq_tables)]
183 }
184}
185
186impl MultipleSubBuilder {
187 pub fn insert(&mut self, target: GlyphId16, replacement: Vec<GlyphId16>) {
192 self.items.insert(target, replacement);
193 }
194
195 pub fn can_add(&self, target: GlyphId16, replacement: &[GlyphId16]) -> bool {
197 match self.items.get(&target) {
198 None => true,
199 Some(thing) => thing == replacement,
200 }
201 }
202}
203
204#[derive(Clone, Debug, Default)]
206pub struct AlternateSubBuilder {
207 items: BTreeMap<GlyphId16, Vec<GlyphId16>>,
208}
209
210impl AlternateSubBuilder {
211 pub fn insert(&mut self, target: GlyphId16, replacement: Vec<GlyphId16>) {
213 self.items.insert(target, replacement);
214 }
215
216 pub fn is_empty(&self) -> bool {
218 self.items.is_empty()
219 }
220
221 pub fn iter_pairs(&self) -> impl Iterator<Item = (GlyphId16, GlyphId16)> + '_ {
225 self.items
226 .iter()
227 .flat_map(|(target, alt)| alt.iter().map(|alt| (*target, *alt)))
228 }
229}
230
231impl Builder for AlternateSubBuilder {
232 type Output = Vec<super::AlternateSubstFormat1>;
233
234 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
235 let coverage = self.items.keys().copied().collect();
236 let seq_tables = self
237 .items
238 .into_values()
239 .map(super::AlternateSet::new)
240 .collect();
241 vec![super::AlternateSubstFormat1::new(coverage, seq_tables)]
242 }
243}
244
245#[derive(Clone, Debug, Default)]
247pub struct LigatureSubBuilder {
248 items: BTreeMap<GlyphId16, Vec<(Vec<GlyphId16>, GlyphId16)>>,
249}
250
251impl LigatureSubBuilder {
252 pub fn insert(&mut self, target: Vec<GlyphId16>, replacement: GlyphId16) {
254 let (first, rest) = target.split_first().unwrap();
255 let entry = self.items.entry(*first).or_default();
256 if !entry
258 .iter()
259 .any(|existing| (existing.0 == rest && existing.1 == replacement))
260 {
261 entry.push((rest.to_owned(), replacement))
262 }
263 }
264
265 pub fn can_add(&self, target: &[GlyphId16], replacement: GlyphId16) -> bool {
267 let Some((first, rest)) = target.split_first() else {
268 return false;
269 };
270 match self.items.get(first) {
271 Some(ligs) => !ligs
272 .iter()
273 .any(|(seq, target)| seq == rest && *target != replacement),
274 None => true,
275 }
276 }
277}
278
279impl Builder for LigatureSubBuilder {
280 type Output = Vec<super::LigatureSubstFormat1>;
281
282 fn build(self, _: &mut VariationStoreBuilder) -> Self::Output {
283 let mut splitter = TableSplitter::<super::LigatureSubstFormat1>::new();
284 for (gid, mut ligs) in self.items.into_iter() {
285 ligs.sort_by_key(|(lig, _)| std::cmp::Reverse(lig.len()));
288 let lig_set = super::LigatureSet::new(
289 ligs.into_iter()
290 .map(|(components, replacement)| super::Ligature::new(replacement, components))
291 .collect(),
292 );
293 splitter.add(gid, lig_set);
294 }
295 splitter.finish()
296 }
297}
298
299impl SplitTable for super::LigatureSubstFormat1 {
300 type Component = super::LigatureSet;
301
302 fn size_for_item(item: &Self::Component) -> usize {
303 item.compute_size()
304 }
305
306 fn initial_size_for_item(_item: &Self::Component) -> usize {
307 u16::RAW_BYTE_LEN * 4
309 }
310
311 fn instantiate(coverage: CoverageTable, items: Vec<Self::Component>) -> Self {
312 Self::new(coverage, items)
313 }
314}
315
316impl super::LigatureSet {
317 fn compute_size(&self) -> usize {
318 u16::RAW_BYTE_LEN
320 + Offset16::RAW_BYTE_LEN * self.ligatures.len()
322 + self
324 .ligatures
325 .iter()
326 .map(|lig| lig.compute_size())
327 .sum::<usize>()
328 }
329}
330
331impl super::Ligature {
332 fn compute_size(&self) -> usize {
333 u16::RAW_BYTE_LEN
335 + u16::RAW_BYTE_LEN
337 + u16::RAW_BYTE_LEN * self.component_glyph_ids.len()
339 }
340}
341
342#[cfg(test)]
343mod tests {
344 use crate::tables::gsub::LigatureSubstFormat1;
345
346 use super::*;
347
348 fn make_lig_table(n_bytes: u16, first: u16) -> super::super::Ligature {
349 assert!(n_bytes >= 6, "minimum table size");
350 assert!(n_bytes % 2 == 0, "can only generate even sizes: {n_bytes}");
351 let n_glyphs = (n_bytes - 6) / 2;
353 let components = (first..=first + n_glyphs).map(GlyphId16::new).collect();
354 super::super::Ligature::new(GlyphId16::new(first), components)
355 }
356 fn make_2048_bytes_of_ligature() -> super::super::LigatureSet {
357 let lig1 = make_lig_table(1022, 1);
361 let lig2 = make_lig_table(1022, 3);
362 super::super::LigatureSet::new(vec![lig1, lig2])
363 }
364
365 #[test]
366 fn who_tests_the_testers1() {
367 for size in [6, 12, 144, 2046, u16::MAX - 1] {
368 let table = make_lig_table(size, 1);
369 let bytes = crate::dump_table(&table).unwrap();
370 assert_eq!(bytes.len(), size as usize);
371 }
372 }
373
374 #[test]
375 fn splitting_ligature_subs() {
376 let mut splitter = TableSplitter::<LigatureSubstFormat1>::new();
377 let ligset = make_2048_bytes_of_ligature();
378 for gid in 0u16..31 {
379 splitter.add(GlyphId16::new(gid), ligset.clone());
381 }
382
383 assert_eq!(splitter.clone().finish().len(), 1);
385 splitter.add(GlyphId16::new(32), ligset);
386 assert_eq!(splitter.finish().len(), 2)
388 }
389}