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
use crate::parser::{Stream, FromData, SafeStream, LazyArray};
use crate::{Font, GlyphId, TableName, Result, Error};
impl<'a> Font<'a> {
pub fn glyphs_kerning(&self, glyph_id1: GlyphId, glyph_id2: GlyphId) -> Result<i16> {
self.check_glyph_id(glyph_id1)?;
self.check_glyph_id(glyph_id2)?;
let data = self.kern.ok_or_else(|| Error::TableMissing(TableName::Kerning))?;
let mut s = Stream::new(data);
let version: u16 = s.read()?;
if version != 0 {
return Err(Error::UnsupportedTableVersion(TableName::Kerning, version));
}
let number_of_subtables: u16 = s.read()?;
if number_of_subtables == 0 {
return Err(Error::NoKerning);
}
s.skip::<u16>();
s.skip::<u16>();
let coverage: Coverage = s.read()?;
if !coverage.is_horizontal() {
return Err(Error::NoKerning);
}
if coverage.format != 0 {
return Err(Error::NoKerning);
}
parse_format1(&mut s, glyph_id1, glyph_id2)
}
}
fn parse_format1(s: &mut Stream, glyph_id1: GlyphId, glyph_id2: GlyphId) -> Result<i16> {
let number_of_pairs: u16 = s.read()?;
s.skip_len(6u32);
let pairs: LazyArray<KerningRecord> = s.read_array(number_of_pairs)?;
let needle = (glyph_id1.0 as u32) << 16 | glyph_id2.0 as u32;
match pairs.binary_search_by(|v| v.pair.cmp(&needle)) {
Some(v) => Ok(v.value),
None => Err(Error::NoKerning),
}
}
struct KerningRecord {
pair: u32,
value: i16,
}
impl FromData for KerningRecord {
fn parse(s: &mut SafeStream) -> Self {
KerningRecord {
pair: s.read(),
value: s.read(),
}
}
fn raw_size() -> usize {
6
}
}
struct Coverage {
coverage: u8,
format: u8,
}
impl Coverage {
const HORIZONTAL_BIT: u8 = 0;
fn is_horizontal(&self) -> bool {
(self.coverage >> Coverage::HORIZONTAL_BIT) & 1 == 1
}
}
impl FromData for Coverage {
fn parse(s: &mut SafeStream) -> Self {
Coverage {
format: s.read(),
coverage: s.read(),
}
}
}