Skip to content

Commit

Permalink
implement hmtx table
Browse files Browse the repository at this point in the history
  • Loading branch information
rkusa committed Aug 4, 2020
1 parent 6131f9e commit 669bbbd
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 46 deletions.
26 changes: 18 additions & 8 deletions otf/src/lib.rs
Expand Up @@ -15,6 +15,7 @@ pub struct OpenTypeFont {
cmap_table: tables::cmap::CmapTable,
head_table: tables::head::HeadTable,
hhea_table: tables::hhea::HheaTable,
hmtx_table: tables::hmtx::HmtxTable,
maxp_table: tables::maxp::MaxpTable,
}

Expand All @@ -23,11 +24,18 @@ impl OpenTypeFont {
let mut cursor = Cursor::new(data.as_ref());
let offset_table = OffsetTable::unpack(&mut cursor, ())?;

let hhea_table = offset_table.unpack_required_table("hhea", (), &mut cursor)?;
let maxp_table = offset_table.unpack_required_table("maxp", (), &mut cursor)?;
Ok(OpenTypeFont {
cmap_table: offset_table.unpack_required_table("cmap", (), &mut cursor)?,
head_table: offset_table.unpack_required_table("head", (), &mut cursor)?,
hhea_table: offset_table.unpack_required_table("hhea", (), &mut cursor)?,
maxp_table: offset_table.unpack_required_table("maxp", (), &mut cursor)?,
hmtx_table: offset_table.unpack_required_table(
"hmtx",
(&hhea_table, &maxp_table),
&mut cursor,
)?,
hhea_table,
maxp_table,
offset_table,
})
}
Expand All @@ -40,6 +48,8 @@ impl OpenTypeFont {
self.cmap_table.pack(&mut wr, ())?;
self.head_table.pack(&mut wr, ())?;
self.hhea_table.pack(&mut wr, ())?;
self.hmtx_table
.pack(&mut wr, (&self.hhea_table, &self.maxp_table))?;
self.maxp_table.pack(&mut wr, ())?;

Ok(())
Expand All @@ -65,15 +75,15 @@ impl OffsetTable {
.and_then(|i| self.tables.get(i))
}

fn unpack_table<T, R, D>(
fn unpack_table<'a, T, R, D>(
&self,
tag: &str,
dep: D,
cursor: &mut Cursor<R>,
) -> Result<Option<T>, io::Error>
where
R: io::Read + AsRef<[u8]>,
T: Packed<Dep = D>,
T: Packed<'a, Dep = D>,
{
// TODO: return Option for non-required tables?
let record = match self.get_table_record(tag) {
Expand All @@ -85,22 +95,22 @@ impl OffsetTable {
Ok(Some(T::unpack(&mut limit_read, dep)?))
}

fn unpack_required_table<T, R, D>(
fn unpack_required_table<'a, T, R, D>(
&self,
tag: &str,
dep: D,
cursor: &mut Cursor<R>,
) -> Result<T, io::Error>
where
R: io::Read + AsRef<[u8]>,
T: Packed<Dep = D>,
T: Packed<'a, Dep = D>,
{
self.unpack_table::<T, R, D>(tag, dep, cursor)?
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, format!("{} table missing", tag)))
}
}

impl Packed for OffsetTable {
impl<'a> Packed<'a> for OffsetTable {
type Dep = ();

fn unpack<R: io::Read>(mut rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand All @@ -125,7 +135,7 @@ impl Packed for OffsetTable {
})
}

fn pack<W: io::Write>(&self, mut wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, mut wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
self.sfnt_version.pack(&mut wr)?;
wr.write_u16::<BigEndian>(self.num_tables)?;

Expand Down
4 changes: 2 additions & 2 deletions otf/src/packed.rs
@@ -1,7 +1,7 @@
use std::io;

pub trait Packed: Sized {
pub trait Packed<'a>: Sized {
type Dep;
fn unpack<R: io::Read>(rd: &mut R, _: Self::Dep) -> Result<Self, io::Error>;
fn pack<W: io::Write>(&self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error>;
fn pack<W: io::Write>(&'a self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error>;
}
12 changes: 6 additions & 6 deletions otf/src/tables/cmap.rs
Expand Up @@ -34,7 +34,7 @@ pub struct CmapTable {
encoding_records: Vec<EncodingRecord>,
}

impl Packed for CmapTable {
impl<'a> Packed<'a> for CmapTable {
type Dep = ();

fn unpack<R: io::Read>(mut rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand Down Expand Up @@ -68,7 +68,7 @@ impl Packed for CmapTable {
})
}

fn pack<W: io::Write>(&self, mut wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, mut wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
wr.write_u16::<BigEndian>(self.version)?;
wr.write_u16::<BigEndian>(self.num_tables)?;
for table in &self.encoding_records {
Expand All @@ -86,7 +86,7 @@ pub struct EncodingRecord {
offset: u32,
}

impl Packed for EncodingRecord {
impl<'a> Packed<'a> for EncodingRecord {
type Dep = ();

fn unpack<R: io::Read>(rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand All @@ -97,7 +97,7 @@ impl Packed for EncodingRecord {
})
}

fn pack<W: io::Write>(&self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
wr.write_u16::<BigEndian>(self.platform_id)?;
wr.write_u16::<BigEndian>(self.encoding_id)?;
wr.write_u32::<BigEndian>(self.offset)?;
Expand All @@ -122,7 +122,7 @@ impl Subtable {
}
}

impl Packed for Subtable {
impl<'a> Packed<'a> for Subtable {
type Dep = ();

fn unpack<R: io::Read>(rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand Down Expand Up @@ -151,7 +151,7 @@ impl Packed for Subtable {
}
}

fn pack<W: io::Write>(&self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
let mut buf = Vec::new();
match self {
Subtable::Format4(subtable) => subtable.pack(&mut buf, ())?,
Expand Down
8 changes: 4 additions & 4 deletions otf/src/tables/cmap/format12.rs
Expand Up @@ -41,7 +41,7 @@ impl Format12 {
}
}

impl Packed for Format12 {
impl<'a> Packed<'a> for Format12 {
type Dep = ();

fn unpack<R: io::Read>(mut rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand All @@ -60,7 +60,7 @@ impl Packed for Format12 {
})
}

fn pack<W: io::Write>(&self, mut wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, mut wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
wr.write_u32::<BigEndian>(self.language)?;
wr.write_u32::<BigEndian>(self.sequential_map_groups.len() as u32)?;
for group in &self.sequential_map_groups {
Expand All @@ -77,7 +77,7 @@ pub struct SequentialMapGroup {
start_glyph_id: u32,
}

impl Packed for SequentialMapGroup {
impl<'a> Packed<'a> for SequentialMapGroup {
type Dep = ();

fn unpack<R: io::Read>(rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand All @@ -88,7 +88,7 @@ impl Packed for SequentialMapGroup {
})
}

fn pack<W: io::Write>(&self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
wr.write_u32::<BigEndian>(self.start_char_code)?;
wr.write_u32::<BigEndian>(self.end_char_code)?;
wr.write_u32::<BigEndian>(self.start_glyph_id)?;
Expand Down
4 changes: 2 additions & 2 deletions otf/src/tables/cmap/format4.rs
Expand Up @@ -64,7 +64,7 @@ impl Format4 {
}
}

impl Packed for Format4 {
impl<'a> Packed<'a> for Format4 {
type Dep = ();

fn unpack<R: io::Read>(rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand Down Expand Up @@ -103,7 +103,7 @@ impl Packed for Format4 {
})
}

fn pack<W: io::Write>(&self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
wr.write_u16::<BigEndian>(self.language)?;
wr.write_u16::<BigEndian>(self.seg_count_x2)?;
let search_range = 2 * 2u16.pow(((self.seg_count_x2 / 2) as f32).log2().floor() as u32);
Expand Down
4 changes: 2 additions & 2 deletions otf/src/tables/head.rs
Expand Up @@ -26,7 +26,7 @@ pub struct HeadTable {
glyph_data_format: i16,
}

impl Packed for HeadTable {
impl<'a> Packed<'a> for HeadTable {
type Dep = ();

fn unpack<R: io::Read>(rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand Down Expand Up @@ -58,7 +58,7 @@ impl Packed for HeadTable {
})
}

fn pack<W: io::Write>(&self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
wr.write_u16::<BigEndian>(self.major_version)?;
wr.write_u16::<BigEndian>(self.minor_version)?;
wr.write_i16::<BigEndian>(self.font_revision.0)?;
Expand Down
32 changes: 16 additions & 16 deletions otf/src/tables/hhea.rs
Expand Up @@ -10,37 +10,37 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
#[derive(Debug, PartialEq)]
pub struct HheaTable {
/// Major version number of the horizontal header table — set to 1.
major_version: u16,
pub major_version: u16,
/// Minor version number of the horizontal header table — set to 0.
minor_version: u16,
pub minor_version: u16,
/// Distance from baseline of highest ascender.
ascent: i16,
pub ascent: i16,
/// Distance from baseline of lowest descender
descent: i16,
pub descent: i16,
/// Typographic line gap.
line_gap: i16,
pub line_gap: i16,
/// Maximum advance width value in 'hmtx' table.
advance_width_max: u16,
pub advance_width_max: u16,
/// Minimum left sidebearing value in 'hmtx' table.
min_left_side_bearing: i16,
pub min_left_side_bearing: i16,
/// Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)).
min_right_side_bearing: i16,
pub min_right_side_bearing: i16,
/// Max(lsb + (xMax - xMin)).
x_max_extent: i16,
pub x_max_extent: i16,
/// Used to calculate the slope of the cursor (rise/run); 1 for vertical.
caret_slope_rise: i16,
pub caret_slope_rise: i16,
/// 0 for vertical.
caret_slope_run: i16,
pub caret_slope_run: i16,
/// The amount by which a slanted highlight on a glyph needs to be shifted to produce the best
/// appearance.
caret_offset: i16,
pub caret_offset: i16,
/// 0 for current format.
metric_data_format: i16,
pub metric_data_format: i16,
/// Number of hMetric entries in 'hmtx' table
number_of_h_metrics: u16,
pub number_of_h_metrics: u16,
}

impl Packed for HheaTable {
impl<'a> Packed<'a> for HheaTable {
type Dep = ();

fn unpack<R: io::Read>(rd: &mut R, _: Self::Dep) -> Result<Self, io::Error> {
Expand Down Expand Up @@ -79,7 +79,7 @@ impl Packed for HheaTable {
})
}

fn pack<W: io::Write>(&self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
fn pack<W: io::Write>(&'a self, wr: &mut W, _: Self::Dep) -> Result<(), io::Error> {
// TODO: update values based on hmax table
wr.write_u16::<BigEndian>(self.major_version)?;
wr.write_u16::<BigEndian>(self.minor_version)?;
Expand Down

0 comments on commit 669bbbd

Please sign in to comment.