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(),
}
}
}