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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use crate::parse::*;
use crate::FontResult;
use hashbrown::HashMap;

// Apple: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
// Microsoft: https://docs.microsoft.com/en-us/typography/opentype/spec/kern

#[derive(Debug)]
pub struct TableKern {
    pub horizontal_mappings: Option<HashMap<u32, i16>>,
    pub vertical_mappings: Option<HashMap<u32, i16>>,
}

#[derive(Copy, Clone, Debug)]
pub struct Header {
    pub version_major: u16,
    pub version_minor: u16,
    pub number_sub_tables: u32,
}

#[derive(Copy, Clone, Debug)]
pub struct SubTableHeader {
    pub version: u16,
    pub length: usize,
    pub coverage: Coverage,
    pub tuple_index: u16,
}

#[derive(Copy, Clone, Debug)]
pub struct Coverage(u16);

impl Coverage {
    pub fn is_horizontal(&self) -> bool {
        self.0 & 0x0001 == 0x0001
    }

    pub fn is_minimum(&self) -> bool {
        self.0 & 0x0002 == 0x0002
    }

    pub fn is_cross_stream(&self) -> bool {
        self.0 & 0x0004 == 0x0004
    }

    pub fn is_override(&self) -> bool {
        self.0 & 0x0008 == 0x0008
    }

    pub fn format(&self) -> u16 {
        self.0 >> 8
    }
}

impl TableKern {
    pub fn new(kern: &[u8]) -> FontResult<TableKern> {
        let mut stream = Stream::new(kern);
        let version_major = stream.read_u16();

        let header;
        match version_major {
            0x0000 => header = Self::read_header(&mut stream),
            0x0001 => header = Self::read_aat_header(&mut stream),
            _ => return Err("Font.kern: Unsupported kern table version."),
        }

        for _ in 0..header.number_sub_tables {
            let sub_table_start = stream.offset();
            let sub_header = if version_major == 0x0000 {
                Self::read_subtable(&mut stream)
            } else {
                Self::read_aat_subtable(&mut stream)
            };
            match sub_header.coverage.format() {
                // Ordered List of Kerning Pairs
                0 => {
                    let mappings = Self::read_format0(&mut stream);
                    let (h, v) = if sub_header.coverage.is_horizontal() {
                        (Some(mappings), None)
                    } else {
                        (None, Some(mappings))
                    };
                    return Ok(TableKern {
                        horizontal_mappings: h,
                        vertical_mappings: v,
                    });
                }
                // State Table for Contextual Kerning
                // 1 => { /* TODO: State Table for Contextual Kerning */ }
                // Simple n x m Array of Kerning Values
                // 2 => { /* TODO: Simple n x m Array of Kerning Values */ }
                // Simple n x m Array of Kerning Indices
                // 3 => { /* TODO: Simple n x m Array of Kerning Indices */ }
                _ => {
                    stream.seek(sub_table_start + sub_header.length);
                }
            }
        }

        Err("Font.kern: No supported sub-table format available.")
    }

    fn read_format0(stream: &mut Stream) -> HashMap<u32, i16> {
        let mut mappings = HashMap::new();
        let pairs = stream.read_u16();
        stream.skip(6); // searchRange: u16, entrySelector: u16, rangeShift: u16
        for _ in 0..pairs {
            let left = stream.read_u16();
            let right = stream.read_u16();
            let id = u32::from(left) << 16 | u32::from(right);
            let offset = stream.read_i16();
            mappings.insert(id, offset);
        }
        mappings
    }

    fn read_header(stream: &mut Stream) -> Header {
        let version_major = 0x0000;
        let version_minor = 0x0000;
        let number_sub_tables = stream.read_u16() as u32;
        Header {
            version_major,
            version_minor,
            number_sub_tables,
        }
    }

    fn read_aat_header(stream: &mut Stream) -> Header {
        let version_major = 0x0001;
        let version_minor = stream.read_u16();
        let number_sub_tables = stream.read_u32();
        Header {
            version_major,
            version_minor,
            number_sub_tables,
        }
    }

    fn read_subtable(stream: &mut Stream) -> SubTableHeader {
        let version = stream.read_u16();
        let length = stream.read_u16() as usize;
        let coverage = Coverage(stream.read_u16());
        SubTableHeader {
            version,
            length,
            coverage,
            tuple_index: 0,
        }
    }

    fn read_aat_subtable(stream: &mut Stream) -> SubTableHeader {
        let length = stream.read_u32() as usize;
        let coverage = Coverage(stream.read_u16());
        let tuple_index = stream.read_u16();
        SubTableHeader {
            version: 0x0001,
            length,
            coverage,
            tuple_index,
        }
    }
}