Coverage Report

Created: 2025-09-27 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontations/klippa/src/variations.rs
Line
Count
Source
1
//! impl Subset for OpenType font variations common tables.
2
use crate::{
3
    inc_bimap::IncBiMap,
4
    offset::SerializeSubset,
5
    serialize::{SerializeErrorFlags, Serializer},
6
    Plan, SubsetTable,
7
};
8
use fnv::FnvHashMap;
9
use write_fonts::{
10
    read::{
11
        collections::IntSet,
12
        tables::variations::{
13
            DeltaSetIndexMap, ItemVariationData, ItemVariationStore, VariationRegionList,
14
        },
15
    },
16
    types::{BigEndian, F2Dot14, FixedSize, Offset32},
17
};
18
19
impl<'a> SubsetTable<'a> for ItemVariationStore<'a> {
20
    type ArgsForSubset = &'a [IncBiMap];
21
    type Output = ();
22
23
0
    fn subset(
24
0
        &self,
25
0
        plan: &Plan,
26
0
        s: &mut Serializer,
27
0
        inner_maps: &[IncBiMap],
28
0
    ) -> Result<(), SerializeErrorFlags> {
29
0
        if inner_maps.is_empty() {
30
0
            return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY);
31
0
        }
32
0
        s.embed(self.format())?;
33
34
0
        let regions = self
35
0
            .variation_region_list()
36
0
            .map_err(|_| SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)?;
37
38
0
        let var_data_array = self.item_variation_data();
39
0
        let mut region_indices = IntSet::empty();
40
0
        for (i, inner_map) in inner_maps.iter().enumerate() {
41
0
            match var_data_array.get(i) {
42
0
                Some(Ok(var_data)) => {
43
0
                    collect_region_refs(&var_data, inner_map, &mut region_indices);
44
0
                }
45
0
                None => continue,
46
0
                Some(Err(_e)) => {
47
0
                    return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
48
                }
49
            }
50
        }
51
52
0
        let max_region_count = regions.region_count();
53
0
        region_indices.remove_range(max_region_count..=u16::MAX);
54
55
0
        if region_indices.is_empty() {
56
0
            return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY);
57
0
        }
58
59
0
        let mut region_map = IncBiMap::with_capacity(region_indices.len() as usize);
60
0
        for region in region_indices.iter() {
61
0
            region_map.add(region as u32);
62
0
        }
63
64
0
        let Ok(var_region_list) = self.variation_region_list() else {
65
0
            return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
66
        };
67
68
        // var_region_list
69
0
        let regions_offset_pos = s.embed(Offset32::new(0))?;
70
0
        Offset32::serialize_subset(&var_region_list, s, plan, &region_map, regions_offset_pos)?;
71
72
0
        serialize_var_data_offset_array(self, s, plan, inner_maps, &region_map)
73
0
    }
74
}
75
76
impl<'a> SubsetTable<'a> for VariationRegionList<'a> {
77
    type ArgsForSubset = &'a IncBiMap;
78
    type Output = ();
79
80
0
    fn subset(
81
0
        &self,
82
0
        _plan: &Plan,
83
0
        s: &mut Serializer,
84
0
        region_map: &IncBiMap,
85
0
    ) -> Result<(), SerializeErrorFlags> {
86
0
        let axis_count = self.axis_count();
87
0
        s.embed(axis_count)?;
88
89
0
        let region_count = region_map.len() as u16;
90
0
        s.embed(region_count)?;
91
92
        //Fixed size of a VariationRegion
93
0
        let var_region_size = 3 * axis_count as usize * F2Dot14::RAW_BYTE_LEN;
94
0
        if var_region_size.checked_mul(region_count as usize).is_none() {
95
0
            return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
96
0
        }
97
98
0
        let subset_var_regions_size = var_region_size * region_count as usize;
99
0
        let var_regions_pos = s.allocate_size(subset_var_regions_size, false)?;
100
101
0
        let src_region_count = self.region_count() as u32;
102
0
        let Some(src_var_regions_bytes) = self
103
0
            .offset_data()
104
0
            .as_bytes()
105
0
            .get(self.shape().variation_regions_byte_range())
106
        else {
107
0
            return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
108
        };
109
110
0
        for r in 0..region_count {
111
0
            let Some(backward) = region_map.get_backward(r as u32) else {
112
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
113
            };
114
0
            if *backward >= src_region_count {
115
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
116
0
            }
117
118
0
            let src_pos = (*backward as usize) * var_region_size;
119
0
            let Some(src_bytes) = src_var_regions_bytes.get(src_pos..src_pos + var_region_size)
120
            else {
121
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
122
            };
123
0
            s.copy_assign_from_bytes(var_regions_pos + r as usize * var_region_size, src_bytes);
124
        }
125
0
        Ok(())
126
0
    }
127
}
128
129
0
fn serialize_var_data_offset_array(
130
0
    var_store: &ItemVariationStore,
131
0
    s: &mut Serializer,
132
0
    plan: &Plan,
133
0
    inner_maps: &[IncBiMap],
134
0
    region_map: &IncBiMap,
135
0
) -> Result<(), SerializeErrorFlags> {
136
0
    let mut vardata_count = 0_u16;
137
0
    let count_pos = s.embed(vardata_count)?;
138
139
0
    let var_data_array = var_store.item_variation_data();
140
0
    for (i, inner_map) in inner_maps.iter().enumerate() {
141
0
        if inner_map.len() == 0 {
142
0
            continue;
143
0
        }
144
0
        match var_data_array.get(i) {
145
0
            Some(Ok(var_data)) => {
146
0
                let offset_pos = s.embed(0_u32)?;
147
0
                Offset32::serialize_subset(
148
0
                    &var_data,
149
0
                    s,
150
0
                    plan,
151
0
                    (inner_map, region_map),
152
0
                    offset_pos,
153
0
                )?;
154
0
                vardata_count += 1;
155
            }
156
            _ => {
157
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
158
            }
159
        }
160
    }
161
0
    if vardata_count == 0 {
162
0
        return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY);
163
0
    }
164
0
    s.copy_assign(count_pos, vardata_count);
165
0
    Ok(())
166
0
}
167
168
impl<'a> SubsetTable<'a> for ItemVariationData<'_> {
169
    type ArgsForSubset = (&'a IncBiMap, &'a IncBiMap);
170
    type Output = ();
171
172
0
    fn subset(
173
0
        &self,
174
0
        _plan: &Plan,
175
0
        s: &mut Serializer,
176
0
        args: (&IncBiMap, &IncBiMap),
177
0
    ) -> Result<(), SerializeErrorFlags> {
178
0
        let (inner_map, region_map) = args;
179
0
        let new_item_count = inner_map.len() as u16;
180
0
        s.embed(new_item_count)?;
181
182
        // optimize word count
183
0
        let ri_count = self.region_index_count() as usize;
184
185
        #[derive(Clone, Copy, PartialEq)]
186
        enum DeltaSize {
187
            Zero,
188
            NonWord,
189
            Word,
190
        }
191
192
0
        let mut delta_sz = Vec::new();
193
0
        delta_sz.resize(ri_count, DeltaSize::Zero);
194
        // maps new index to old index
195
0
        let mut ri_map = vec![0; ri_count];
196
197
0
        let mut new_word_count: u16 = 0;
198
199
0
        let src_delta_bytes = self.delta_sets();
200
0
        let src_row_size = self.get_delta_row_len();
201
202
0
        let src_word_delta_count = self.word_delta_count();
203
0
        let src_word_count = (src_word_delta_count & 0x7FFF) as usize;
204
0
        let src_long_words = src_word_count & 0x8000 != 0;
205
206
0
        let mut has_long = false;
207
0
        if src_long_words {
208
0
            for r in 0..src_word_count {
209
0
                for item in inner_map.keys() {
210
0
                    let delta =
211
0
                        get_item_delta(self, *item as usize, r, src_row_size, src_delta_bytes);
212
0
                    if !(-65536..=65535).contains(&delta) {
213
0
                        has_long = true;
214
0
                        break;
215
0
                    }
216
                }
217
            }
218
0
        }
219
220
0
        let min_threshold = if has_long { -65536 } else { -128 };
221
0
        let max_threshold = if has_long { 65535 } else { 127 };
222
223
0
        for (r, delta_size) in delta_sz.iter_mut().enumerate() {
224
0
            let short_circuit = src_long_words == has_long && src_word_count <= r;
225
0
            for item in inner_map.keys() {
226
0
                let delta = get_item_delta(self, *item as usize, r, src_row_size, src_delta_bytes);
227
0
                if delta < min_threshold || delta > max_threshold {
228
0
                    *delta_size = DeltaSize::Word;
229
0
                    new_word_count += 1;
230
0
                    break;
231
0
                } else if delta != 0 {
232
0
                    *delta_size = DeltaSize::NonWord;
233
0
                    if short_circuit {
234
0
                        break;
235
0
                    }
236
0
                }
237
            }
238
        }
239
240
0
        let mut word_index: u16 = 0;
241
0
        let mut non_word_index = new_word_count;
242
0
        let mut new_ri_count: u16 = 0;
243
244
0
        for (r, delta_type) in delta_sz.iter().enumerate() {
245
0
            if *delta_type == DeltaSize::Zero {
246
0
                continue;
247
0
            }
248
249
0
            if *delta_type == DeltaSize::Word {
250
0
                let new_r = word_index as usize;
251
0
                word_index += 1;
252
0
                ri_map[new_r] = r;
253
0
            } else {
254
0
                let new_r = non_word_index as usize;
255
0
                non_word_index += 1;
256
0
                ri_map[new_r] = r;
257
0
            }
258
0
            new_ri_count += 1;
259
        }
260
261
0
        let new_word_delta_count = if has_long {
262
0
            new_word_count | 0x8000
263
        } else {
264
0
            new_word_count
265
        };
266
0
        s.embed(new_word_delta_count)?;
267
0
        s.embed(new_ri_count)?;
268
269
0
        let region_indices_pos = s.allocate_size(new_ri_count as usize * 2, false)?;
270
0
        let src_region_indices = self.region_indexes();
271
0
        for (idx, src_idx) in ri_map.iter().enumerate().take(new_ri_count as usize) {
272
0
            let Some(old_r) = src_region_indices.get(*src_idx) else {
273
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
274
            };
275
276
0
            let Some(region) = region_map.get(old_r.get() as u32) else {
277
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
278
            };
279
0
            s.copy_assign(region_indices_pos + idx * 2, *region as u16);
280
        }
281
282
0
        let new_row_size = ItemVariationData::delta_row_len(new_word_delta_count, new_ri_count);
283
0
        let new_delta_bytes_len = new_item_count as usize * new_row_size;
284
285
0
        let delta_bytes_pos = s.allocate_size(new_delta_bytes_len, false)?;
286
0
        for i in 0..new_item_count as usize {
287
0
            let Some(old_i) = inner_map.get_backward(i as u32) else {
288
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
289
            };
290
291
0
            let old_i = *old_i as usize;
292
0
            for (r, old_r) in ri_map.iter().enumerate().take(new_ri_count as usize) {
293
0
                set_item_delta(
294
0
                    s,
295
0
                    delta_bytes_pos,
296
0
                    i,
297
0
                    r,
298
0
                    get_item_delta(self, old_i, *old_r, src_row_size, src_delta_bytes),
299
0
                    new_row_size,
300
0
                    has_long,
301
0
                    new_word_count as usize,
302
0
                )?;
303
            }
304
        }
305
306
0
        Ok(())
307
0
    }
308
}
309
310
0
fn get_item_delta(
311
0
    var_data: &ItemVariationData,
312
0
    item: usize,
313
0
    region: usize,
314
0
    row_size: usize,
315
0
    delta_bytes: &[u8],
316
0
) -> i32 {
317
0
    if item >= var_data.item_count() as usize || region >= var_data.region_index_count() as usize {
318
0
        return 0;
319
0
    }
320
321
0
    let p = item * row_size;
322
0
    let word_delta_count = var_data.word_delta_count();
323
0
    let word_count = (word_delta_count & 0x7FFF) as usize;
324
0
    let is_long = word_delta_count & 0x8000 != 0;
325
326
    // direct port from Harfbuzz: <https://github.com/harfbuzz/harfbuzz/blob/22fbc7568828b9acfd116be44b2d77d56d2d448b/src/hb-ot-layout-common.hh#L3061>
327
    // ignore the lint here
328
    #[allow(clippy::collapsible_else_if)]
329
0
    if is_long {
330
0
        if region < word_count {
331
0
            let pos = p + region * 4;
332
0
            let Some(delta_bytes) = delta_bytes.get(pos..pos + 4) else {
333
0
                return 0;
334
            };
335
0
            BigEndian::<i32>::from_slice(delta_bytes).unwrap().get()
336
        } else {
337
0
            let pos = p + 4 * word_count + 2 * (region - word_count);
338
0
            let Some(delta_bytes) = delta_bytes.get(pos..pos + 2) else {
339
0
                return 0;
340
            };
341
0
            BigEndian::<i16>::from_slice(delta_bytes).unwrap().get() as i32
342
        }
343
    } else {
344
0
        if region < word_count {
345
0
            let pos = p + region * 2;
346
0
            let Some(delta_bytes) = delta_bytes.get(pos..pos + 2) else {
347
0
                return 0;
348
            };
349
0
            BigEndian::<i16>::from_slice(delta_bytes).unwrap().get() as i32
350
        } else {
351
0
            let pos = p + 2 * word_count + (region - word_count);
352
0
            let Some(delta_bytes) = delta_bytes.get(pos..pos + 1) else {
353
0
                return 0;
354
            };
355
0
            BigEndian::<i8>::from_slice(delta_bytes).unwrap().get() as i32
356
        }
357
    }
358
0
}
359
360
// direct port from Harfbuzz: <https://github.com/harfbuzz/harfbuzz/blob/22fbc7568828b9acfd116be44b2d77d56d2d448b/src/hb-ot-layout-common.hh#L3090>
361
// ignore the lint here
362
#[allow(clippy::too_many_arguments)]
363
0
fn set_item_delta(
364
0
    s: &mut Serializer,
365
0
    pos: usize,
366
0
    item: usize,
367
0
    region: usize,
368
0
    delta: i32,
369
0
    row_size: usize,
370
0
    has_long: bool,
371
0
    word_count: usize,
372
0
) -> Result<(), SerializeErrorFlags> {
373
0
    let p = pos + item * row_size;
374
    #[allow(clippy::collapsible_else_if)]
375
0
    if has_long {
376
0
        if region < word_count {
377
0
            let pos = p + region * 4;
378
0
            s.copy_assign(pos, delta);
379
0
        } else {
380
0
            let pos = p + 4 * word_count + 2 * (region - word_count);
381
0
            let Ok(delta) = i16::try_from(delta) else {
382
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
383
            };
384
0
            s.copy_assign(pos, delta);
385
        }
386
    } else {
387
0
        if region < word_count {
388
0
            let pos = p + region * 2;
389
0
            let Ok(delta) = i16::try_from(delta) else {
390
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
391
            };
392
0
            s.copy_assign(pos, delta);
393
        } else {
394
0
            let pos = p + 2 * word_count + (region - word_count);
395
0
            let Ok(delta) = i8::try_from(delta) else {
396
0
                return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
397
            };
398
0
            s.copy_assign(pos, delta);
399
        }
400
    }
401
0
    Ok(())
402
0
}
403
404
0
fn collect_region_refs(
405
0
    var_data: &ItemVariationData,
406
0
    inner_map: &IncBiMap,
407
0
    region_indices: &mut IntSet<u16>,
408
0
) {
409
0
    if inner_map.len() == 0 {
410
0
        return;
411
0
    }
412
0
    let delta_bytes = var_data.delta_sets();
413
0
    let row_size = var_data.get_delta_row_len();
414
415
0
    let regions = var_data.region_indexes();
416
0
    for (i, region) in regions.iter().enumerate() {
417
0
        let region = region.get();
418
0
        if region_indices.contains(region) {
419
0
            continue;
420
0
        }
421
422
0
        for item in inner_map.keys() {
423
0
            if get_item_delta(var_data, *item as usize, i, row_size, delta_bytes) != 0 {
424
0
                region_indices.insert(region);
425
0
                break;
426
0
            }
427
        }
428
    }
429
0
}
430
431
pub(crate) struct DeltaSetIndexMapSerializePlan<'a> {
432
    outer_bit_count: u8,
433
    inner_bit_count: u8,
434
    output_map: &'a FnvHashMap<u32, u32>,
435
    map_count: u32,
436
}
437
438
impl<'a> DeltaSetIndexMapSerializePlan<'a> {
439
0
    pub(crate) fn new(
440
0
        outer_bit_count: u8,
441
0
        inner_bit_count: u8,
442
0
        output_map: &'a FnvHashMap<u32, u32>,
443
0
        map_count: u32,
444
0
    ) -> Self {
445
0
        Self {
446
0
            outer_bit_count,
447
0
            inner_bit_count,
448
0
            output_map,
449
0
            map_count,
450
0
        }
451
0
    }
452
453
0
    pub(crate) fn width(&self) -> u8 {
454
0
        (self.outer_bit_count + self.inner_bit_count).div_ceil(8)
455
0
    }
456
457
0
    pub(crate) fn inner_bit_count(&self) -> u8 {
458
0
        self.inner_bit_count
459
0
    }
460
461
0
    pub(crate) fn output_map(&self) -> &'a FnvHashMap<u32, u32> {
462
0
        self.output_map
463
0
    }
464
465
0
    pub(crate) fn map_count(&self) -> u32 {
466
0
        self.map_count
467
0
    }
468
}
469
470
impl<'a> SubsetTable<'a> for DeltaSetIndexMap<'a> {
471
    type ArgsForSubset = &'a DeltaSetIndexMapSerializePlan<'a>;
472
    type Output = ();
473
474
0
    fn subset(
475
0
        &self,
476
0
        _plan: &Plan,
477
0
        s: &mut Serializer,
478
0
        index_map_subset_plan: &'a DeltaSetIndexMapSerializePlan<'a>,
479
0
    ) -> Result<(), SerializeErrorFlags> {
480
0
        let output_map = index_map_subset_plan.output_map();
481
0
        let width = index_map_subset_plan.width();
482
0
        let inner_bit_count = index_map_subset_plan.inner_bit_count();
483
484
0
        let map_count = index_map_subset_plan.map_count();
485
        // sanity check
486
0
        if map_count > 0 && (((inner_bit_count - 1) & (!0xF)) != 0 || (((width - 1) & (!0x3)) != 0))
487
        {
488
0
            return Err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER);
489
0
        }
490
491
0
        let format: u8 = if map_count <= 0xFFFF { 0 } else { 1 };
492
0
        s.embed(format)?;
493
494
0
        let entry_format = ((width - 1) << 4) | (inner_bit_count - 1);
495
0
        s.embed(entry_format)?;
496
497
0
        if format == 0 {
498
0
            s.embed(map_count as u16)?;
499
        } else {
500
0
            s.embed(map_count)?;
501
        }
502
503
0
        let num_data_bytes = width as usize * map_count as usize;
504
0
        let mapdata_pos = s.allocate_size(num_data_bytes, true)?;
505
506
0
        let be_byte_index_start = 4 - width as usize;
507
0
        for i in 0..map_count {
508
0
            let Some(v) = output_map.get(&i) else {
509
0
                continue;
510
            };
511
0
            if *v == 0 {
512
0
                continue;
513
0
            }
514
515
0
            let outer = v >> 16;
516
0
            let inner = v & 0xFFFF;
517
0
            let u = (outer << inner_bit_count) | inner;
518
0
            let data_bytes = u.to_be_bytes();
519
0
            let data_pos = mapdata_pos + (i as usize) * width as usize;
520
0
            s.copy_assign_from_bytes(data_pos, data_bytes.get(be_byte_index_start..4).unwrap());
521
        }
522
523
0
        Ok(())
524
0
    }
525
}
526
527
#[cfg(test)]
528
mod test {
529
    use super::*;
530
    use skrifa::raw::{FontData, FontRead};
531
    #[test]
532
    fn test_subset_item_varstore() {
533
        use crate::DEFAULT_LAYOUT_FEATURES;
534
        let raw_bytes: [u8; 471] = [
535
            0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00,
536
            0x00, 0x6f, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x02, 0x00, 0x05,
537
            0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538
            0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539
            0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00,
540
            0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00,
541
            0x40, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xdd,
542
            0xe2, 0xec, 0xf1, 0xf6, 0xfb, 0x05, 0x0a, 0x0f, 0x14, 0x1e, 0x28, 0x32, 0x3c, 0x00,
543
            0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x8d, 0xa1, 0xb5, 0xba, 0xbf, 0xc4, 0xce,
544
            0xd8, 0xdd, 0xe2, 0xe7, 0xec, 0xf1, 0xf6, 0xfb, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e,
545
            0x28, 0x2d, 0x32, 0x3c, 0x46, 0x64, 0x00, 0x90, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
546
            0x00, 0x01, 0xba, 0xa1, 0xba, 0x14, 0xba, 0x32, 0xc4, 0xc4, 0xc4, 0xd8, 0xc4, 0xe2,
547
            0xc4, 0x0a, 0xc4, 0x28, 0xce, 0xba, 0xce, 0xc4, 0xce, 0xd8, 0xce, 0xe2, 0xce, 0xec,
548
            0xce, 0x28, 0xce, 0x32, 0xd8, 0x92, 0xd8, 0x9c, 0xd8, 0xbf, 0xd8, 0xce, 0xd8, 0xd8,
549
            0xd8, 0xe2, 0xd8, 0xe7, 0xd8, 0xec, 0xd8, 0xf6, 0xd8, 0x1e, 0xe2, 0xc4, 0xe2, 0xce,
550
            0xe2, 0xd8, 0xe2, 0xe2, 0xe2, 0xe7, 0xe2, 0xec, 0xe2, 0xf1, 0xe2, 0xf6, 0xe2, 0x0a,
551
            0xe2, 0x14, 0xe2, 0x28, 0xe2, 0x32, 0xe2, 0x46, 0xec, 0xba, 0xec, 0xc4, 0xec, 0xce,
552
            0xec, 0xd8, 0xec, 0xdd, 0xec, 0xe2, 0xec, 0xec, 0xec, 0xf1, 0xec, 0xf6, 0xec, 0xfb,
553
            0xec, 0x05, 0xec, 0x0a, 0xec, 0x14, 0xec, 0x1e, 0xec, 0x28, 0xec, 0x32, 0xec, 0x50,
554
            0xf1, 0xd3, 0xf1, 0xf6, 0xf1, 0xfb, 0xf6, 0xc4, 0xf6, 0xce, 0xf6, 0xd8, 0xf6, 0xe2,
555
            0xf6, 0xe7, 0xf6, 0xec, 0xf6, 0xf1, 0xf6, 0xf6, 0xf6, 0xfb, 0xf6, 0x05, 0xf6, 0x0a,
556
            0xf6, 0x14, 0xf6, 0x19, 0xf6, 0x1e, 0xf6, 0x28, 0xf6, 0x32, 0xf6, 0x3c, 0xf6, 0x50,
557
            0xfb, 0xec, 0xfb, 0xf6, 0xfb, 0x05, 0xfb, 0x0a, 0xfb, 0x14, 0xfb, 0x19, 0xfb, 0x2d,
558
            0xfb, 0x37, 0x05, 0xe7, 0x05, 0xec, 0x05, 0xf1, 0x05, 0xf6, 0x05, 0xfb, 0x05, 0x05,
559
            0x05, 0x0a, 0x0a, 0xc9, 0x0a, 0xce, 0x0a, 0xd3, 0x0a, 0xd8, 0x0a, 0xe2, 0x0a, 0xec,
560
            0x0a, 0xf1, 0x0a, 0xf6, 0x0a, 0xfb, 0x0a, 0x05, 0x0a, 0x0a, 0x0a, 0x0f, 0x0a, 0x14,
561
            0x0a, 0x1e, 0x0a, 0x28, 0x0a, 0x32, 0x0a, 0x3c, 0x0a, 0x46, 0x0a, 0x50, 0x0f, 0xfb,
562
            0x0f, 0x05, 0x0f, 0x0a, 0x0f, 0x0f, 0x14, 0xc4, 0x14, 0xce, 0x14, 0xd8, 0x14, 0xe2,
563
            0x14, 0xec, 0x14, 0xf6, 0x14, 0x0a, 0x14, 0x0f, 0x14, 0x14, 0x14, 0x1e, 0x14, 0x28,
564
            0x14, 0x32, 0x14, 0x3c, 0x14, 0x46, 0x1e, 0xec, 0x1e, 0xf6, 0x1e, 0xfb, 0x1e, 0x0a,
565
            0x1e, 0x14, 0x1e, 0x1e, 0x1e, 0x28, 0x1e, 0x32, 0x1e, 0x3c, 0x28, 0xe2, 0x28, 0x0a,
566
            0x28, 0x14, 0x28, 0x1e, 0x28, 0x28, 0x28, 0x32, 0x32, 0x14, 0x00, 0x05, 0x00, 0x00,
567
            0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0xe2, 0xf6, 0x1e, 0xe2, 0x00, 0x1e,
568
            0xec, 0x00, 0x14, 0x00, 0x1e, 0x1e, 0x14, 0x1e, 0x0a,
569
        ];
570
571
        let item_varstore = ItemVariationStore::read(FontData::new(&raw_bytes)).unwrap();
572
573
        let mut plan = Plan::default();
574
        // create inner maps
575
        let mut bimap = IncBiMap::with_capacity(1);
576
        bimap.add(10);
577
        plan.base_varstore_inner_maps.push(bimap);
578
579
        let mut bimap = IncBiMap::with_capacity(4);
580
        bimap.add(13);
581
        bimap.add(16);
582
        bimap.add(17);
583
        bimap.add(18);
584
        plan.base_varstore_inner_maps.push(bimap);
585
586
        let mut bimap = IncBiMap::with_capacity(3);
587
        bimap.add(100);
588
        bimap.add(101);
589
        bimap.add(122);
590
        plan.base_varstore_inner_maps.push(bimap);
591
592
        let bimap = IncBiMap::default();
593
        plan.base_varstore_inner_maps.push(bimap);
594
595
        //layout_scripts
596
        plan.layout_scripts.invert();
597
598
        //layout_features
599
        plan.layout_features
600
            .extend(DEFAULT_LAYOUT_FEATURES.iter().copied());
601
602
        let mut s = Serializer::new(1024);
603
        assert_eq!(s.start_serialize(), Ok(()));
604
        let ret = item_varstore.subset(&plan, &mut s, &plan.base_varstore_inner_maps);
605
        assert_eq!(ret, Ok(()));
606
        assert!(!s.in_error());
607
        s.end_serialize();
608
609
        let subsetted_data = s.copy_bytes();
610
        let expected_bytes: [u8; 85] = [
611
            0x00, 0x01, 0x00, 0x00, 0x00, 0x39, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
612
            0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
613
            0x00, 0x01, 0x0a, 0x05, 0x0a, 0x0a, 0x14, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01,
614
            0x00, 0x01, 0xf6, 0x0a, 0x0f, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
615
            0x14, 0x00, 0x02, 0x00, 0x02, 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616
            0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617
            0x00,
618
        ];
619
620
        assert_eq!(subsetted_data, expected_bytes);
621
    }
622
}