Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split vvar and hvar #151

Merged
merged 8 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub use tables::CFFError;
#[cfg(feature = "apple-layout")]
pub use tables::{ankr, feat, kerx, morx, trak};
#[cfg(feature = "variable-fonts")]
pub use tables::{avar, cff2, fvar, gvar, hvar, mvar};
pub use tables::{avar, cff2, fvar, gvar, hvar, mvar, vvar};
pub use tables::{cbdt, cblc, cff1 as cff, vhea};
pub use tables::{
cmap, colr, cpal, glyf, head, hhea, hmtx, kern, loca, maxp, name, os2, post, sbix, svg, vorg,
Expand Down Expand Up @@ -991,7 +991,7 @@ pub struct FaceTables<'a> {
#[cfg(feature = "variable-fonts")]
pub mvar: Option<mvar::Table<'a>>,
#[cfg(feature = "variable-fonts")]
pub vvar: Option<hvar::Table<'a>>,
pub vvar: Option<vvar::Table<'a>>,
}

/// A font face.
Expand Down Expand Up @@ -1298,7 +1298,7 @@ impl<'a> Face<'a> {
#[cfg(feature = "variable-fonts")]
mvar: raw_tables.mvar.and_then(mvar::Table::parse),
#[cfg(feature = "variable-fonts")]
vvar: raw_tables.vvar.and_then(hvar::Table::parse),
vvar: raw_tables.vvar.and_then(vvar::Table::parse),
})
}

Expand Down Expand Up @@ -1914,7 +1914,7 @@ impl<'a> Face<'a> {
if self.is_variable() {
// Ignore variation offset when `hvar` is not set.
if let Some(hvar) = self.tables.hvar {
if let Some(offset) = hvar.side_bearing_offset(glyph_id, self.coords()) {
if let Some(offset) = hvar.left_side_bearing_offset(glyph_id, self.coords()) {
// We can't use `round()` in `no_std`, so this is the next best thing.
bearing += offset + 0.5;
}
Expand Down Expand Up @@ -1942,7 +1942,7 @@ impl<'a> Face<'a> {
if self.is_variable() {
// Ignore variation offset when `vvar` is not set.
if let Some(vvar) = self.tables.vvar {
if let Some(offset) = vvar.side_bearing_offset(glyph_id, self.coords()) {
if let Some(offset) = vvar.top_side_bearing_offset(glyph_id, self.coords()) {
// We can't use `round()` in `no_std`, so this is the next best thing.
bearing += offset + 0.5;
}
Expand All @@ -1960,8 +1960,30 @@ impl<'a> Face<'a> {

/// Returns glyph's vertical origin according to
/// [Vertical Origin Table](https://docs.microsoft.com/en-us/typography/opentype/spec/vorg).
///
/// This method is affected by variation axes.
pub fn glyph_y_origin(&self, glyph_id: GlyphId) -> Option<i16> {
self.tables.vorg.map(|vorg| vorg.glyph_y_origin(glyph_id))
#[cfg(feature = "variable-fonts")]
{
let mut origin = self.tables.vorg.map(|vorg| vorg.glyph_y_origin(glyph_id))? as f32;

if self.is_variable() {
// Ignore variation offset when `vvar` is not set.
if let Some(vvar) = self.tables.vvar {
if let Some(offset) = vvar.vertical_origin_offset(glyph_id, self.coords()) {
// We can't use `round()` in `no_std`, so this is the next best thing.
origin += offset + 0.5;
}
}
}

i16::try_num_from(origin)
}

#[cfg(not(feature = "variable-fonts"))]
{
self.tables.vorg.map(|vorg| vorg.glyph_y_origin(glyph_id))
}
}

/// Returns glyph's name.
Expand Down
32 changes: 27 additions & 5 deletions src/tables/hvar.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
//! A [Horizontal/Vertical Metrics Variations Table](
//! A [Horizontal Metrics Variations Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/hvar) implementation.

use crate::delta_set::DeltaSetIndexMap;
use crate::parser::{Offset, Offset32, Stream};
use crate::var_store::ItemVariationStore;
use crate::{GlyphId, NormalizedCoordinate};

/// A [Horizontal/Vertical Metrics Variations Table](
/// A [Horizontal Metrics Variations Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/hvar).
#[derive(Clone, Copy)]
pub struct Table<'a> {
data: &'a [u8],
variation_store: ItemVariationStore<'a>,
advance_width_mapping_offset: Option<Offset32>,
lsb_mapping_offset: Option<Offset32>,
rsb_mapping_offset: Option<Offset32>,
}

impl<'a> Table<'a> {
Expand All @@ -35,10 +36,11 @@ impl<'a> Table<'a> {
variation_store,
advance_width_mapping_offset: s.read::<Option<Offset32>>()?,
lsb_mapping_offset: s.read::<Option<Offset32>>()?,
rsb_mapping_offset: s.read::<Option<Offset32>>()?,
})
}

/// Returns advance offset for a glyph.
/// Returns the advance width offset for a glyph.
#[inline]
pub fn advance_offset(
&self,
Expand All @@ -59,14 +61,34 @@ impl<'a> Table<'a> {
.parse_delta(outer_idx, inner_idx, coordinates)
}

/// Returns side bearing offset for a glyph.
/// Returns the left side bearing offset for a glyph.
#[inline]
pub fn side_bearing_offset(
pub fn left_side_bearing_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let set_data = self.data.get(self.lsb_mapping_offset?.to_usize()..)?;
self.side_bearing_offset(glyph_id, coordinates, set_data)
}

/// Returns the right side bearing offset for a glyph.
#[inline]
pub fn right_side_bearing_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let set_data = self.data.get(self.rsb_mapping_offset?.to_usize()..)?;
self.side_bearing_offset(glyph_id, coordinates, set_data)
}

fn side_bearing_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
set_data: &[u8],
) -> Option<f32> {
let (outer_idx, inner_idx) = DeltaSetIndexMap::new(set_data).map(glyph_id.0 as u32)?;
self.variation_store
.parse_delta(outer_idx, inner_idx, coordinates)
Expand Down
2 changes: 2 additions & 0 deletions src/tables/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub mod gvar;
pub mod hvar;
#[cfg(feature = "variable-fonts")]
pub mod mvar;
#[cfg(feature = "variable-fonts")]
pub mod vvar;

pub use cff::cff1;
#[cfg(feature = "variable-fonts")]
Expand Down
115 changes: 115 additions & 0 deletions src/tables/vvar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//! A [Vertical Metrics Variations Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/hvar) implementation.

use crate::delta_set::DeltaSetIndexMap;
use crate::parser::{Offset, Offset32, Stream};
use crate::var_store::ItemVariationStore;
use crate::{GlyphId, NormalizedCoordinate};

/// A [Vertical Metrics Variations Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/hvar).
#[derive(Clone, Copy)]
pub struct Table<'a> {
data: &'a [u8],
variation_store: ItemVariationStore<'a>,
advance_height_mapping_offset: Option<Offset32>,
tsb_mapping_offset: Option<Offset32>,
bsb_mapping_offset: Option<Offset32>,
vorg_mapping_offset: Option<Offset32>,
}

impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);

let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}

let variation_store_offset = s.read::<Offset32>()?;
let var_store_s = Stream::new_at(data, variation_store_offset.to_usize())?;
let variation_store = ItemVariationStore::parse(var_store_s)?;

Some(Table {
data,
variation_store,
advance_height_mapping_offset: s.read::<Option<Offset32>>()?,
tsb_mapping_offset: s.read::<Option<Offset32>>()?,
bsb_mapping_offset: s.read::<Option<Offset32>>()?,
vorg_mapping_offset: s.read::<Option<Offset32>>()?,
})
}

/// Returns the advance height offset for a glyph.
#[inline]
pub fn advance_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let (outer_idx, inner_idx) = if let Some(offset) = self.advance_height_mapping_offset {
DeltaSetIndexMap::new(self.data.get(offset.to_usize()..)?).map(glyph_id.0 as u32)?
} else {
// 'If there is no delta-set index mapping table for advance widths,
// then glyph IDs implicitly provide the indices:
// for a given glyph ID, the delta-set outer-level index is zero,
// and the glyph ID is the delta-set inner-level index.'
(0, glyph_id.0)
};

self.variation_store
.parse_delta(outer_idx, inner_idx, coordinates)
}

/// Returns the top side bearing offset for a glyph.
#[inline]
pub fn top_side_bearing_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let set_data = self.data.get(self.tsb_mapping_offset?.to_usize()..)?;
self.side_bearing_offset(glyph_id, coordinates, set_data)
}

/// Returns the bottom side bearing offset for a glyph.
#[inline]
pub fn bottom_side_bearing_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let set_data = self.data.get(self.bsb_mapping_offset?.to_usize()..)?;
self.side_bearing_offset(glyph_id, coordinates, set_data)
}

/// Returns the vertical origin offset for a glyph.
#[inline]
pub fn vertical_origin_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let set_data = self.data.get(self.vorg_mapping_offset?.to_usize()..)?;
self.side_bearing_offset(glyph_id, coordinates, set_data)
}

fn side_bearing_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
set_data: &[u8],
) -> Option<f32> {
let (outer_idx, inner_idx) = DeltaSetIndexMap::new(set_data).map(glyph_id.0 as u32)?;
self.variation_store
.parse_delta(outer_idx, inner_idx, coordinates)
}
}

impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}
Loading