1use crate::table::parse::*;
2use hashbrown::HashMap;
3
4// Apple: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
5// Microsoft: https://docs.microsoft.com/en-us/typography/opentype/spec/kern
6
7#[derive(Debug)]
8pub struct TableKern {
9 pub horizontal_mappings: HashMap<u32, i16>,
10}
11
12#[derive(Copy, Clone, Debug)]
13struct Header {
14 pub version_major: u16,
15 pub version_minor: u16,
16 pub number_sub_tables: u32,
17}
18
19#[derive(Copy, Clone, Debug)]
20struct SubTableHeader {
21 pub version: u16,
22 pub length: usize,
23 pub coverage: Coverage,
24 pub format: u8,
25 pub tuple_index: u16,
26}
27
28#[derive(Copy, Clone, Debug)]
29struct Coverage {
30 is_horizontal: bool,
31}
32
33impl Coverage {
34 pub const fn aat(cov: u8) -> Coverage {
35 Coverage {
36 is_horizontal: cov & 0x80 != 0x80,
37 }
38 }
39
40 pub const fn ot(cov: u8) -> Coverage {
41 Coverage {
42 is_horizontal: cov & 0x01 == 0x01,
43 }
44 }
45}
46
47impl TableKern {
48 pub fn new(kern: &[u8]) -> Option<TableKern> {
49 let mut stream = Stream::new(kern);
50 let version_major = stream.read_u16()?;
51
52 let header;
53 match version_major {
54 0x0000 => header = Self::read_ot_header(&mut stream)?,
55 0x0001 => header = Self::read_aat_header(&mut stream)?,
56 _ => return None, // Font.kern: Unsupported kern table version.
57 }
58
59 for _ in 0..header.number_sub_tables {
60 let sub_table_start = stream.offset();
61 let sub_header = if version_major == 0x0000 {
62 Self::read_ot_subtable(&mut stream)?
63 } else {
64 Self::read_aat_subtable(&mut stream)?
65 };
66 match sub_header.format {
67 // Ordered List of Kerning Pairs
68 0 => {
69 if sub_header.coverage.is_horizontal {
70 let mappings = Self::read_format0(&mut stream)?;
71 return Some(TableKern {
72 horizontal_mappings: mappings,
73 });
74 }
75 }
76 // State Table for Contextual Kerning
77 // 1 => { /* TODO: State Table for Contextual Kerning */ }
78 // Simple n x m Array of Kerning Values
79 // 2 => { /* TODO: Simple n x m Array of Kerning Values */ }
80 // Simple n x m Array of Kerning Indices
81 3 => {
82 if sub_header.coverage.is_horizontal {
83 let mappings = Self::read_format3(&mut stream)?;
84 return Some(TableKern {
85 horizontal_mappings: mappings,
86 });
87 }
88 }
89 _ => {
90 stream.seek(sub_table_start + sub_header.length);
91 }
92 }
93 }
94
95 None // Font.kern: No supported sub-table format available.
96 }
97
98 fn read_format0(stream: &mut Stream) -> Option<HashMap<u32, i16>> {
99 let pairs = stream.read_u16()?;
100 stream.skip(6); // searchRange: u16, entrySelector: u16, rangeShift: u16
101 let mut mappings = HashMap::new();
102 for _ in 0..pairs {
103 let left = stream.read_u16()?;
104 let right = stream.read_u16()?;
105 let id = u32::from(left) << 16 | u32::from(right);
106 let value = stream.read_i16()?;
107 mappings.insert(id, value);
108 }
109 Some(mappings)
110 }
111
112 fn read_format3(stream: &mut Stream) -> Option<HashMap<u32, i16>> {
113 let glyph_count = stream.read_u16()?;
114 let kerning_values_count = stream.read_u8()?;
115 let left_hand_classes_count = stream.read_u8()?;
116 let right_hand_classes_count = stream.read_u8()?;
117 stream.skip(1); // flags - reserved
118 let indices_count = u16::from(left_hand_classes_count) * u16::from(right_hand_classes_count);
119
120 let kerning_values = stream.read_i16_slice(usize::from(kerning_values_count))?;
121 let left_hand_classes = stream.read_u8_slice(usize::from(glyph_count))?;
122 let right_hand_classes = stream.read_u8_slice(usize::from(glyph_count))?;
123 let indices = stream.read_u8_slice(usize::from(indices_count))?;
124
125 let mut mappings = HashMap::new();
126 for left in 0..glyph_count {
127 for right in 0..glyph_count {
128 if let Some((id, value)) = {
129 let left_class = left_hand_classes.get(usize::from(left))?;
130 let right_class = right_hand_classes.get(usize::from(right))?;
131
132 if left_class > left_hand_classes_count || right_class > right_hand_classes_count {
133 continue;
134 }
135
136 let index =
137 u16::from(left_class) * u16::from(right_hand_classes_count) + u16::from(right_class);
138 let index = indices.get(usize::from(index))?;
139 let id = u32::from(left) << 16 | u32::from(right);
140 let value = kerning_values.get(usize::from(index))?;
141 Some((id, value))
142 } {
143 mappings.insert(id, value);
144 };
145 }
146 }
147
148 Some(mappings)
149 }
150
151 fn read_ot_header(stream: &mut Stream) -> Option<Header> {
152 let version_major = 0x0000;
153 let version_minor = 0x0000;
154 let number_sub_tables = stream.read_u16()? as u32;
155 Some(Header {
156 version_major,
157 version_minor,
158 number_sub_tables,
159 })
160 }
161
162 fn read_aat_header(stream: &mut Stream) -> Option<Header> {
163 let version_major = 0x0001;
164 let version_minor = stream.read_u16()?;
165 let number_sub_tables = stream.read_u32()?;
166 Some(Header {
167 version_major,
168 version_minor,
169 number_sub_tables,
170 })
171 }
172
173 fn read_ot_subtable(stream: &mut Stream) -> Option<SubTableHeader> {
174 let version = stream.read_u16()?;
175 let length = stream.read_u16()? as usize;
176 let format = stream.read_u8()?;
177 let coverage = Coverage::ot(stream.read_u8()?);
178 Some(SubTableHeader {
179 version,
180 length,
181 coverage,
182 format,
183 tuple_index: 0,
184 })
185 }
186
187 fn read_aat_subtable(stream: &mut Stream) -> Option<SubTableHeader> {
188 let length = stream.read_u32()? as usize;
189 let coverage = Coverage::aat(stream.read_u8()?);
190 let format = stream.read_u8()?;
191 let tuple_index = stream.read_u16()?;
192 Some(SubTableHeader {
193 version: 0x0001,
194 length,
195 coverage,
196 format,
197 tuple_index,
198 })
199 }
200}
201