diff --git a/glyph/CHANGELOG.md b/glyph/CHANGELOG.md index 1ba9465..54cad58 100644 --- a/glyph/CHANGELOG.md +++ b/glyph/CHANGELOG.md @@ -1,5 +1,8 @@ # Unreleased -* Update _owned_ttf_parser_ to `0.12.1` to ensure consistent glyph bounding box behaviour. +* Update _owned-ttf-parser_ to `0.13.2`. +* Pre-parse cmap & kern subtables on all `Font` variants at initialization. This provides + much faster `glyph_id` & `kern` method performance, results in 25-30% faster layout + benchmark performance. # 0.2.11 * `Font::outline` will return `None` for rare invalid/empty glyph bounds instead of panicking. diff --git a/glyph/Cargo.toml b/glyph/Cargo.toml index a244672..3436702 100644 --- a/glyph/Cargo.toml +++ b/glyph/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" readme="README.md" [dependencies] -owned_ttf_parser = { version = "0.12.1", default-features = false } +owned_ttf_parser = { version = "0.13.2", default-features = false } ab_glyph_rasterizer = { version = "0.1.2", path = "../rasterizer", default-features = false } # no_std float stuff # renamed to enable a "libm" feature diff --git a/glyph/src/ttfp.rs b/glyph/src/ttfp.rs index ba5177d..e1685a3 100644 --- a/glyph/src/ttfp.rs +++ b/glyph/src/ttfp.rs @@ -7,9 +7,9 @@ use alloc::boxed::Box; use alloc::vec::Vec; use core::convert::TryFrom; use core::fmt; -use owned_ttf_parser::AsFaceRef; +use owned_ttf_parser::{self as ttfp, AsFaceRef}; -impl From for owned_ttf_parser::GlyphId { +impl From for ttfp::GlyphId { #[inline] fn from(id: GlyphId) -> Self { Self(id.0) @@ -31,14 +31,14 @@ pub struct GlyphImage<'a> { pub format: GlyphImageFormat, } -impl<'a> From> for GlyphImage<'a> { - fn from(img: owned_ttf_parser::RasterGlyphImage<'a>) -> Self { +impl<'a> From> for GlyphImage<'a> { + fn from(img: ttfp::RasterGlyphImage<'a>) -> Self { GlyphImage { origin: point(img.x.into(), img.y.into()), scale: img.pixels_per_em.into(), data: img.data, format: match img.format { - owned_ttf_parser::RasterImageFormat::PNG => GlyphImageFormat::Png, + ttfp::RasterImageFormat::PNG => GlyphImageFormat::Png, }, } } @@ -68,7 +68,7 @@ pub enum GlyphImageFormat { /// # Ok(()) } /// ``` #[derive(Clone)] -pub struct FontRef<'font>(owned_ttf_parser::Face<'font>); +pub struct FontRef<'font>(ttfp::PreParsedSubtables<'font, ttfp::Face<'font>>); impl fmt::Debug for FontRef<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -109,9 +109,9 @@ impl<'font> FontRef<'font> { /// ``` #[inline] pub fn try_from_slice_and_index(data: &'font [u8], index: u32) -> Result { - Ok(Self( - owned_ttf_parser::Face::from_slice(data, index).map_err(|_| InvalidFont)?, - )) + Ok(Self(ttfp::PreParsedSubtables::from( + ttfp::Face::from_slice(data, index).map_err(|_| InvalidFont)?, + ))) } } @@ -131,7 +131,7 @@ impl<'font> FontRef<'font> { /// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56)); /// # Ok(()) } /// ``` -pub struct FontVec(owned_ttf_parser::OwnedFace); +pub struct FontVec(ttfp::PreParsedSubtables<'static, ttfp::OwnedFace>); impl fmt::Debug for FontVec { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -173,9 +173,9 @@ impl FontVec { /// ``` #[inline] pub fn try_from_vec_and_index(data: Vec, index: u32) -> Result { - Ok(Self( - owned_ttf_parser::OwnedFace::from_vec(data, index).map_err(|_| InvalidFont)?, - )) + Ok(Self(ttfp::PreParsedSubtables::from( + ttfp::OwnedFace::from_vec(data, index).map_err(|_| InvalidFont)?, + ))) } } @@ -185,7 +185,8 @@ macro_rules! impl_font { impl Font for $font { #[inline] fn units_per_em(&self) -> Option { - self.0.as_face_ref().units_per_em().map(f32::from) + // TODO unwrap signature when making next breaking change + Some(self.0.as_face_ref().units_per_em().into()) } #[inline] @@ -205,12 +206,8 @@ macro_rules! impl_font { #[inline] fn glyph_id(&self, c: char) -> GlyphId { - let index = self - .0 - .as_face_ref() - .glyph_index(c) - .map(|id| id.0) - .unwrap_or(0); + // Note: Using `PreParsedSubtables` method for better performance. + let index = self.0.glyph_index(c).map(|id| id.0).unwrap_or(0); GlyphId(index) } @@ -252,11 +249,9 @@ macro_rules! impl_font { #[inline] fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { + // Note: Using `PreParsedSubtables` method for better performance. self.0 - .as_face_ref() - .kerning_subtables() - .filter(|st| st.is_horizontal() && !st.is_variable()) - .find_map(|st| st.glyphs_kerning(first.into(), second.into())) + .glyphs_hor_kerning(first.into(), second.into()) .map(f32::from) .unwrap_or_default() } @@ -264,7 +259,7 @@ macro_rules! impl_font { fn outline(&self, id: GlyphId) -> Option { let mut outliner = outliner::OutlineCurveBuilder::default(); - let owned_ttf_parser::Rect { + let ttfp::Rect { x_min, x_max, y_min, @@ -302,13 +297,17 @@ macro_rules! impl_font { let inner = Box::new( face_ref - .character_mapping_subtables() + .tables() + .cmap + .iter() + .flat_map(|c| c.subtables) .filter(|s| s.is_unicode()) .flat_map(move |subtable| { let mut pairs = Vec::new(); subtable.codepoints(|c| { if let Ok(ch) = char::try_from(c) { - if let Some(idx) = subtable.glyph_index(c).filter(|i| i.0 > 0) { + if let Some(idx) = subtable.glyph_index(ch).filter(|i| i.0 > 0) + { if used_indices.insert(idx.0) { pairs.push((GlyphId(idx.0), ch)); }