1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences

use crate::GlyphId;
use crate::parser::{Stream, FromData, Offset, Offset32, U24};

#[derive(Clone, Copy)]
struct VariationSelectorRecord {
    var_selector: u32,
    default_uvs_offset: Option<Offset32>,
    non_default_uvs_offset: Option<Offset32>,
}

impl FromData for VariationSelectorRecord {
    const SIZE: usize = 11;

    #[inline]
    fn parse(data: &[u8]) -> Option<Self> {
        let mut s = Stream::new(data);
        Some(VariationSelectorRecord {
            var_selector: s.read::<U24>()?.0,
            default_uvs_offset: s.read::<Option<Offset32>>()?,
            non_default_uvs_offset: s.read::<Option<Offset32>>()?,
        })
    }
}


#[derive(Clone, Copy)]
struct UVSMappingRecord {
    unicode_value: u32,
    glyph_id: GlyphId,
}

impl FromData for UVSMappingRecord {
    const SIZE: usize = 5;

    #[inline]
    fn parse(data: &[u8]) -> Option<Self> {
        let mut s = Stream::new(data);
        Some(UVSMappingRecord {
            unicode_value: s.read::<U24>()?.0,
            glyph_id: s.read::<GlyphId>()?,
        })
    }
}


#[derive(Clone, Copy)]
struct UnicodeRangeRecord {
    start_unicode_value: u32,
    additional_count: u8,
}

impl UnicodeRangeRecord {
    fn contains(&self, c: u32) -> bool {
        // Never overflows, since `start_unicode_value` is actually u24.
        let end = self.start_unicode_value + u32::from(self.additional_count);
        (self.start_unicode_value..=end).contains(&c)
    }
}

impl FromData for UnicodeRangeRecord {
    const SIZE: usize = 4;

    #[inline]
    fn parse(data: &[u8]) -> Option<Self> {
        let mut s = Stream::new(data);
        Some(UnicodeRangeRecord {
            start_unicode_value: s.read::<U24>()?.0,
            additional_count: s.read::<u8>()?,
        })
    }
}


/// A result of a variation glyph mapping.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum GlyphVariationResult {
    /// Glyph was found in the variation encoding table.
    Found(GlyphId),
    /// Glyph should be looked in other, non-variation tables.
    ///
    /// Basically, you should use `Encoding::glyph_index` or `Face::glyph_index`
    /// in this case.
    UseDefault,
}


pub fn parse(data: &[u8], c: u32, variation: u32) -> Option<GlyphVariationResult> {
    let mut s = Stream::new(data);
    s.skip::<u16>(); // format
    s.skip::<u32>(); // length
    let count: u32 = s.read()?;
    let records = s.read_array32::<VariationSelectorRecord>(count)?;

    let (_, record) = records.binary_search_by(|v| v.var_selector.cmp(&variation))?;

    if let Some(offset) = record.default_uvs_offset {
        let data = data.get(offset.to_usize()..)?;
        let mut s = Stream::new(data);
        let count: u32 = s.read()?;
        let ranges = s.read_array32::<UnicodeRangeRecord>(count)?;
        for range in ranges {
            if range.contains(c) {
                return Some(GlyphVariationResult::UseDefault);
            }
        }
    }

    if let Some(offset) = record.non_default_uvs_offset {
        let data = data.get(offset.to_usize()..)?;
        let mut s = Stream::new(data);
        let count: u32 = s.read()?;
        let uvs_mappings = s.read_array32::<UVSMappingRecord>(count)?;
        let (_, mapping) = uvs_mappings.binary_search_by(|v| v.unicode_value.cmp(&c))?;
        return Some(GlyphVariationResult::Found(mapping.glyph_id));
    }

    None
}