From 49162eb33c4798badb0eab791aefea8feae341a0 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Fri, 29 Oct 2021 00:43:27 +0100 Subject: [PATCH 1/5] Use ttf-parser 0.13 This reverts commit 3f0f9e7e710c1238f6ae0802018260cc932c0d62. --- glyph/CHANGELOG.md | 2 +- glyph/Cargo.toml | 2 +- glyph/src/ttfp.rs | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/glyph/CHANGELOG.md b/glyph/CHANGELOG.md index 1ba9465..e884373 100644 --- a/glyph/CHANGELOG.md +++ b/glyph/CHANGELOG.md @@ -1,5 +1,5 @@ # Unreleased -* Update _owned_ttf_parser_ to `0.12.1` to ensure consistent glyph bounding box behaviour. +* Update _ttf-parser_ to `0.13.1`. # 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..b11854f 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.1", 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..fc907e9 100644 --- a/glyph/src/ttfp.rs +++ b/glyph/src/ttfp.rs @@ -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] @@ -254,8 +255,11 @@ macro_rules! impl_font { fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { self.0 .as_face_ref() - .kerning_subtables() - .filter(|st| st.is_horizontal() && !st.is_variable()) + .tables() + .kern + .iter() + .flat_map(|c| c.subtables) + .filter(|st| st.horizontal && !st.variable) .find_map(|st| st.glyphs_kerning(first.into(), second.into())) .map(f32::from) .unwrap_or_default() @@ -302,13 +306,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)); } From c2e4359ab658f2a971f3ddb30c2d35b9b2df3ecd Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Tue, 2 Nov 2021 00:15:30 +0000 Subject: [PATCH 2/5] Add GlyphIdentifier & Kerner --- dev/benches/font_method.rs | 22 +++++++++++ dev/src/layout.rs | 6 ++- dev/tests/render_reference.rs | 4 +- glyph/src/font.rs | 23 +++++++++++- glyph/src/font_arc.rs | 17 ++++++++- glyph/src/lib.rs | 2 +- glyph/src/scale.rs | 69 ++++++++++++++++++++++++++++++++++- glyph/src/ttfp.rs | 62 +++++++++++++++++++++++++++++++ 8 files changed, 197 insertions(+), 8 deletions(-) diff --git a/dev/benches/font_method.rs b/dev/benches/font_method.rs index a780437..5dd726a 100644 --- a/dev/benches/font_method.rs +++ b/dev/benches/font_method.rs @@ -9,6 +9,7 @@ const OPENS_SANS_ITALIC: &[u8] = include_bytes!("../fonts/OpenSans-Italic.ttf"); fn bench_font_glyph_id(c: &mut Criterion) { let font = FontRef::try_from_slice(OPENS_SANS_ITALIC).unwrap(); + #[allow(deprecated)] c.bench_function("method:Font::glyph_id", |b| { let mut glyph = GlyphId(0); @@ -19,6 +20,15 @@ fn bench_font_glyph_id(c: &mut Criterion) { assert_eq!(glyph, GlyphId(91)); }); + c.bench_function("method:GlyphIdentifier::glyph_id", |b| { + let c2g = font.glyph_identifier(); + let mut glyph = GlyphId(0); + + b.iter(|| glyph = c2g.glyph_id('x')); + + assert_eq!(glyph, GlyphId(91)); + }); + c.bench_function("method:Font::h_advance", |b| { let glyph = GlyphId(91); let mut h_advance = 0.0; @@ -28,6 +38,7 @@ fn bench_font_glyph_id(c: &mut Criterion) { assert_relative_eq!(h_advance, 979.0); }); + #[allow(deprecated)] c.bench_function("method:Font::kern_unscaled", |b| { let glyph = GlyphId(91); let glyph2 = GlyphId(92); @@ -37,6 +48,17 @@ fn bench_font_glyph_id(c: &mut Criterion) { assert_relative_eq!(kern, 0.0); }); + + c.bench_function("method:Kerner::kern_unscaled", |b| { + let glyph = GlyphId(91); + let glyph2 = GlyphId(92); + let kerner = font.kerner(); + let mut kern = 0.0; + + b.iter(|| kern = kerner.kern_unscaled(glyph, glyph2)); + + assert_relative_eq!(kern, 0.0); + }); } criterion_group!( diff --git a/dev/src/layout.rs b/dev/src/layout.rs index 4138e2f..6aeb715 100644 --- a/dev/src/layout.rs +++ b/dev/src/layout.rs @@ -13,6 +13,8 @@ pub fn layout_paragraph( F: Font, SF: ScaleFont, { + let c2g = font.glyph_identifier(); + let kerner = font.kerner(); let v_advance = font.height() + font.line_gap(); let mut caret = position + point(0.0, font.ascent()); let mut last_glyph: Option = None; @@ -24,9 +26,9 @@ pub fn layout_paragraph( } continue; } - let mut glyph = font.scaled_glyph(c); + let mut glyph = c2g.scaled_glyph(c); if let Some(previous) = last_glyph.take() { - caret.x += font.kern(previous.id, glyph.id); + caret.x += kerner.kern(previous.id, glyph.id); } glyph.position = caret; diff --git a/dev/tests/render_reference.rs b/dev/tests/render_reference.rs index 7b19eef..ce7104b 100644 --- a/dev/tests/render_reference.rs +++ b/dev/tests/render_reference.rs @@ -140,7 +140,9 @@ fn reference_outline_draw_ttf_tailed_e() { fn outline_draw(font: F, c: char, scale: f32) -> image::GrayAlphaImage { let font = font.into_scaled(scale); - let glyph = font.outline_glyph(font.scaled_glyph(c)).unwrap(); + let glyph = font + .outline_glyph(font.glyph_identifier().scaled_glyph(c)) + .unwrap(); let bounds = glyph.px_bounds(); let mut glyph_image = diff --git a/glyph/src/font.rs b/glyph/src/font.rs index dc44d3d..640bfce 100644 --- a/glyph/src/font.rs +++ b/glyph/src/font.rs @@ -1,6 +1,7 @@ use crate::{ - point, Glyph, GlyphId, GlyphImage, Outline, OutlinedGlyph, PxScale, PxScaleFont, Rect, - ScaleFont, + point, + ttfp::{GlyphIdentifier, Kerner}, + Glyph, GlyphId, GlyphImage, Outline, OutlinedGlyph, PxScale, PxScaleFont, Rect, ScaleFont, }; /// Functionality required from font data. @@ -74,6 +75,7 @@ pub trait Font { /// Lookup a `GlyphId` matching a given `char`. /// /// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled). + #[deprecated(note = "Use & re-use glyph_identifier() for better performance")] fn glyph_id(&self, c: char) -> GlyphId; /// Unscaled horizontal advance for a given glyph id. @@ -99,6 +101,7 @@ pub trait Font { /// Returns additional unscaled kerning to apply for a particular pair of glyph ids. /// /// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled). + #[deprecated(note = "Use & re-use kerner() for better performance")] fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32; /// Compute unscaled glyph outline curves & bounding box. @@ -206,6 +209,10 @@ pub trait Font { scale: scale.into(), } } + + fn glyph_identifier(&self) -> GlyphIdentifier<'_>; + + fn kerner(&self) -> Kerner<'_>; } impl Font for &F { @@ -230,6 +237,7 @@ impl Font for &F { } #[inline] + #[allow(deprecated)] fn glyph_id(&self, c: char) -> GlyphId { (*self).glyph_id(c) } @@ -255,6 +263,7 @@ impl Font for &F { } #[inline] + #[allow(deprecated)] fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { (*self).kern_unscaled(first, second) } @@ -278,4 +287,14 @@ impl Font for &F { fn glyph_raster_image(&self, id: GlyphId, size: u16) -> Option { (*self).glyph_raster_image(id, size) } + + #[inline] + fn glyph_identifier(&self) -> GlyphIdentifier<'_> { + (*self).glyph_identifier() + } + + #[inline] + fn kerner(&self) -> Kerner<'_> { + (*self).kerner() + } } diff --git a/glyph/src/font_arc.rs b/glyph/src/font_arc.rs index 03167cf..9d6d355 100644 --- a/glyph/src/font_arc.rs +++ b/glyph/src/font_arc.rs @@ -1,4 +1,7 @@ -use crate::{Font, FontRef, FontVec, GlyphId, GlyphImage, InvalidFont, Outline}; +use crate::{ + ttfp::{GlyphIdentifier, Kerner}, + Font, FontRef, FontVec, GlyphId, GlyphImage, InvalidFont, Outline, +}; use alloc::sync::Arc; use core::fmt; @@ -92,6 +95,7 @@ impl Font for FontArc { } #[inline] + #[allow(deprecated)] fn glyph_id(&self, c: char) -> GlyphId { self.0.glyph_id(c) } @@ -117,6 +121,7 @@ impl Font for FontArc { } #[inline] + #[allow(deprecated)] fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { self.0.kern_unscaled(first, second) } @@ -140,6 +145,16 @@ impl Font for FontArc { fn glyph_raster_image(&self, id: GlyphId, size: u16) -> Option { self.0.glyph_raster_image(id, size) } + + #[inline] + fn glyph_identifier(&self) -> GlyphIdentifier<'_> { + self.0.glyph_identifier() + } + + #[inline] + fn kerner(&self) -> Kerner<'_> { + self.0.kerner() + } } impl From for FontArc { diff --git a/glyph/src/lib.rs b/glyph/src/lib.rs index f2b33bb..f1c00bc 100644 --- a/glyph/src/lib.rs +++ b/glyph/src/lib.rs @@ -42,5 +42,5 @@ pub use crate::{ glyph::*, outlined::*, scale::*, - ttfp::{FontRef, FontVec, GlyphImage, GlyphImageFormat}, + ttfp::{FontRef, FontVec, GlyphIdentifier, GlyphImage, GlyphImageFormat, Kerner}, }; diff --git a/glyph/src/scale.rs b/glyph/src/scale.rs index da0cb04..f9c7975 100644 --- a/glyph/src/scale.rs +++ b/glyph/src/scale.rs @@ -1,4 +1,4 @@ -use crate::{Font, Glyph, GlyphId, OutlinedGlyph, Rect}; +use crate::{Font, Glyph, GlyphId, GlyphIdentifier, OutlinedGlyph, Rect}; /// Pixel scale. /// @@ -116,6 +116,8 @@ pub trait ScaleFont { /// Lookup a `GlyphId` matching a given `char`. #[inline] + #[allow(deprecated)] + #[deprecated(note = "Use & re-use glyph_identifier() for better performance")] fn glyph_id(&self, c: char) -> GlyphId { self.font().glyph_id(c) } @@ -137,6 +139,8 @@ pub trait ScaleFont { /// assert_eq!(a1.position, point(0.0, 0.0)); /// ``` #[inline] + #[allow(deprecated)] + #[deprecated(note = "Use & re-use glyph_identifier() for better performance")] fn scaled_glyph(&self, c: char) -> Glyph { self.font().glyph_id(c).with_scale(self.scale()) } @@ -167,6 +171,8 @@ pub trait ScaleFont { /// Returns additional pixel scaled kerning to apply for a particular pair of glyphs. #[inline] + #[allow(deprecated)] + #[deprecated(note = "Use & re-use kerner() for better performance")] fn kern(&self, first: GlyphId, second: GlyphId) -> f32 { self.h_scale_factor() * self.font().kern_unscaled(first, second) } @@ -203,6 +209,10 @@ pub trait ScaleFont { fn outline_glyph(&self, glyph: Glyph) -> Option { self.font().outline_glyph(glyph) } + + fn glyph_identifier(&self) -> PxScaleGlyphIdentifier<'_>; + + fn kerner(&self) -> PxScaleKerner<'_>; } impl> ScaleFont for &SF { @@ -220,6 +230,16 @@ impl> ScaleFont for &SF { fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> { (*self).codepoint_ids() } + + #[inline] + fn glyph_identifier(&self) -> PxScaleGlyphIdentifier<'_> { + (*self).glyph_identifier() + } + + #[inline] + fn kerner(&self) -> PxScaleKerner<'_> { + (*self).kerner() + } } /// A [`Font`](trait.Font.html) and an associated pixel scale. @@ -252,4 +272,51 @@ impl ScaleFont for PxScaleFont { fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> { self.font.codepoint_ids() } + + #[inline] + fn glyph_identifier(&self) -> PxScaleGlyphIdentifier<'_> { + PxScaleGlyphIdentifier { + gider: self.font.glyph_identifier(), + scale: self.scale, + } + } + + #[inline] + fn kerner(&self) -> PxScaleKerner<'_> { + PxScaleKerner { + kerner: self.font.kerner(), + h_scale_factor: self.h_scale_factor(), + } + } +} + +#[derive(Debug)] +pub struct PxScaleKerner<'a> { + kerner: crate::Kerner<'a>, + h_scale_factor: f32, +} + +impl PxScaleKerner<'_> { + #[inline] + pub fn kern(&self, first: GlyphId, second: GlyphId) -> f32 { + self.kerner.kern_unscaled(first, second) * self.h_scale_factor + } +} + +#[derive(Debug)] +pub struct PxScaleGlyphIdentifier<'a> { + gider: GlyphIdentifier<'a>, + scale: PxScale, +} + +impl PxScaleGlyphIdentifier<'_> { + #[inline] + pub fn glyph_id(&self, c: char) -> GlyphId { + self.gider.glyph_id(c) + } + + #[inline] + pub fn scaled_glyph(&self, c: char) -> Glyph { + self.glyph_id(c).with_scale(self.scale) + } } diff --git a/glyph/src/ttfp.rs b/glyph/src/ttfp.rs index fc907e9..a15d823 100644 --- a/glyph/src/ttfp.rs +++ b/glyph/src/ttfp.rs @@ -336,9 +336,71 @@ macro_rules! impl_font { .glyph_raster_image(id.into(), size) .map(Into::into) } + + #[inline] + fn glyph_identifier(&self) -> GlyphIdentifier<'_> { + GlyphIdentifier { + tables: self + .0 + .as_face_ref() + .tables() + .cmap + .iter() + .flat_map(|cmap| cmap.subtables) + .filter(|st| st.is_unicode()) + .collect(), + } + } + + #[inline] + fn kerner(&self) -> Kerner<'_> { + Kerner { + tables: self + .0 + .as_face_ref() + .tables() + .kern + .iter() + .flat_map(|c| c.subtables) + .filter(|st| st.horizontal && !st.variable) + .collect(), + } + } } }; } impl_font!(FontRef<'_>); impl_font!(FontVec); + +#[derive(Debug)] +pub struct GlyphIdentifier<'font> { + tables: Vec>, +} + +impl GlyphIdentifier<'_> { + #[inline] + pub fn glyph_id(&self, c: char) -> GlyphId { + self.tables + .iter() + .find_map(|t| t.glyph_index(c)) + .map(|gid| GlyphId(gid.0)) + .unwrap_or_default() + } +} + +#[derive(Debug)] +pub struct Kerner<'font> { + tables: Vec>, +} + +impl Kerner<'_> { + #[inline] + pub fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { + self.tables + .iter() + .find_map(|st| st.glyphs_kerning(first.into(), second.into())) + .map(f32::from) + .unwrap_or_default() + } +} From 6c4a7c19238fa340136c6657700b883758ec4a72 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Tue, 2 Nov 2021 00:25:57 +0000 Subject: [PATCH 3/5] Update changelog --- glyph/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/glyph/CHANGELOG.md b/glyph/CHANGELOG.md index e884373..ddf6fb2 100644 --- a/glyph/CHANGELOG.md +++ b/glyph/CHANGELOG.md @@ -1,4 +1,7 @@ # Unreleased +* Add `Font::glyph_identifier`, `Font::kerner` as re-usable better performing replacements + to `Font::glyph_id`, `Font::kern_unscaled` respectively, which are now deprecated. + Similar deprecations have happened, and equivalents are available, in `ScaleFont`. * Update _ttf-parser_ to `0.13.1`. # 0.2.11 From a18a175658b782f1bac3612fbc2a9c848422995b Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Sat, 6 Nov 2021 12:39:35 +0000 Subject: [PATCH 4/5] Use owned-ttf-parser 0.13.2 PreParsedSubtables --- dev/benches/font_method.rs | 22 ------- dev/src/layout.rs | 6 +- dev/tests/render_reference.rs | 4 +- glyph/CHANGELOG.md | 8 +-- glyph/Cargo.toml | 2 +- glyph/src/font.rs | 23 +------- glyph/src/font_arc.rs | 17 +----- glyph/src/lib.rs | 2 +- glyph/src/scale.rs | 69 +--------------------- glyph/src/ttfp.rs | 107 ++++++---------------------------- 10 files changed, 31 insertions(+), 229 deletions(-) diff --git a/dev/benches/font_method.rs b/dev/benches/font_method.rs index 5dd726a..a780437 100644 --- a/dev/benches/font_method.rs +++ b/dev/benches/font_method.rs @@ -9,7 +9,6 @@ const OPENS_SANS_ITALIC: &[u8] = include_bytes!("../fonts/OpenSans-Italic.ttf"); fn bench_font_glyph_id(c: &mut Criterion) { let font = FontRef::try_from_slice(OPENS_SANS_ITALIC).unwrap(); - #[allow(deprecated)] c.bench_function("method:Font::glyph_id", |b| { let mut glyph = GlyphId(0); @@ -20,15 +19,6 @@ fn bench_font_glyph_id(c: &mut Criterion) { assert_eq!(glyph, GlyphId(91)); }); - c.bench_function("method:GlyphIdentifier::glyph_id", |b| { - let c2g = font.glyph_identifier(); - let mut glyph = GlyphId(0); - - b.iter(|| glyph = c2g.glyph_id('x')); - - assert_eq!(glyph, GlyphId(91)); - }); - c.bench_function("method:Font::h_advance", |b| { let glyph = GlyphId(91); let mut h_advance = 0.0; @@ -38,7 +28,6 @@ fn bench_font_glyph_id(c: &mut Criterion) { assert_relative_eq!(h_advance, 979.0); }); - #[allow(deprecated)] c.bench_function("method:Font::kern_unscaled", |b| { let glyph = GlyphId(91); let glyph2 = GlyphId(92); @@ -48,17 +37,6 @@ fn bench_font_glyph_id(c: &mut Criterion) { assert_relative_eq!(kern, 0.0); }); - - c.bench_function("method:Kerner::kern_unscaled", |b| { - let glyph = GlyphId(91); - let glyph2 = GlyphId(92); - let kerner = font.kerner(); - let mut kern = 0.0; - - b.iter(|| kern = kerner.kern_unscaled(glyph, glyph2)); - - assert_relative_eq!(kern, 0.0); - }); } criterion_group!( diff --git a/dev/src/layout.rs b/dev/src/layout.rs index 6aeb715..4138e2f 100644 --- a/dev/src/layout.rs +++ b/dev/src/layout.rs @@ -13,8 +13,6 @@ pub fn layout_paragraph( F: Font, SF: ScaleFont, { - let c2g = font.glyph_identifier(); - let kerner = font.kerner(); let v_advance = font.height() + font.line_gap(); let mut caret = position + point(0.0, font.ascent()); let mut last_glyph: Option = None; @@ -26,9 +24,9 @@ pub fn layout_paragraph( } continue; } - let mut glyph = c2g.scaled_glyph(c); + let mut glyph = font.scaled_glyph(c); if let Some(previous) = last_glyph.take() { - caret.x += kerner.kern(previous.id, glyph.id); + caret.x += font.kern(previous.id, glyph.id); } glyph.position = caret; diff --git a/dev/tests/render_reference.rs b/dev/tests/render_reference.rs index ce7104b..7b19eef 100644 --- a/dev/tests/render_reference.rs +++ b/dev/tests/render_reference.rs @@ -140,9 +140,7 @@ fn reference_outline_draw_ttf_tailed_e() { fn outline_draw(font: F, c: char, scale: f32) -> image::GrayAlphaImage { let font = font.into_scaled(scale); - let glyph = font - .outline_glyph(font.glyph_identifier().scaled_glyph(c)) - .unwrap(); + let glyph = font.outline_glyph(font.scaled_glyph(c)).unwrap(); let bounds = glyph.px_bounds(); let mut glyph_image = diff --git a/glyph/CHANGELOG.md b/glyph/CHANGELOG.md index ddf6fb2..1ee5ff2 100644 --- a/glyph/CHANGELOG.md +++ b/glyph/CHANGELOG.md @@ -1,8 +1,8 @@ # Unreleased -* Add `Font::glyph_identifier`, `Font::kerner` as re-usable better performing replacements - to `Font::glyph_id`, `Font::kern_unscaled` respectively, which are now deprecated. - Similar deprecations have happened, and equivalents are available, in `ScaleFont`. -* Update _ttf-parser_ to `0.13.1`. +* 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, which are used heavily when positioning + glyphs into layouts. # 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 b11854f..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.13.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/font.rs b/glyph/src/font.rs index 640bfce..dc44d3d 100644 --- a/glyph/src/font.rs +++ b/glyph/src/font.rs @@ -1,7 +1,6 @@ use crate::{ - point, - ttfp::{GlyphIdentifier, Kerner}, - Glyph, GlyphId, GlyphImage, Outline, OutlinedGlyph, PxScale, PxScaleFont, Rect, ScaleFont, + point, Glyph, GlyphId, GlyphImage, Outline, OutlinedGlyph, PxScale, PxScaleFont, Rect, + ScaleFont, }; /// Functionality required from font data. @@ -75,7 +74,6 @@ pub trait Font { /// Lookup a `GlyphId` matching a given `char`. /// /// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled). - #[deprecated(note = "Use & re-use glyph_identifier() for better performance")] fn glyph_id(&self, c: char) -> GlyphId; /// Unscaled horizontal advance for a given glyph id. @@ -101,7 +99,6 @@ pub trait Font { /// Returns additional unscaled kerning to apply for a particular pair of glyph ids. /// /// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled). - #[deprecated(note = "Use & re-use kerner() for better performance")] fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32; /// Compute unscaled glyph outline curves & bounding box. @@ -209,10 +206,6 @@ pub trait Font { scale: scale.into(), } } - - fn glyph_identifier(&self) -> GlyphIdentifier<'_>; - - fn kerner(&self) -> Kerner<'_>; } impl Font for &F { @@ -237,7 +230,6 @@ impl Font for &F { } #[inline] - #[allow(deprecated)] fn glyph_id(&self, c: char) -> GlyphId { (*self).glyph_id(c) } @@ -263,7 +255,6 @@ impl Font for &F { } #[inline] - #[allow(deprecated)] fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { (*self).kern_unscaled(first, second) } @@ -287,14 +278,4 @@ impl Font for &F { fn glyph_raster_image(&self, id: GlyphId, size: u16) -> Option { (*self).glyph_raster_image(id, size) } - - #[inline] - fn glyph_identifier(&self) -> GlyphIdentifier<'_> { - (*self).glyph_identifier() - } - - #[inline] - fn kerner(&self) -> Kerner<'_> { - (*self).kerner() - } } diff --git a/glyph/src/font_arc.rs b/glyph/src/font_arc.rs index 9d6d355..03167cf 100644 --- a/glyph/src/font_arc.rs +++ b/glyph/src/font_arc.rs @@ -1,7 +1,4 @@ -use crate::{ - ttfp::{GlyphIdentifier, Kerner}, - Font, FontRef, FontVec, GlyphId, GlyphImage, InvalidFont, Outline, -}; +use crate::{Font, FontRef, FontVec, GlyphId, GlyphImage, InvalidFont, Outline}; use alloc::sync::Arc; use core::fmt; @@ -95,7 +92,6 @@ impl Font for FontArc { } #[inline] - #[allow(deprecated)] fn glyph_id(&self, c: char) -> GlyphId { self.0.glyph_id(c) } @@ -121,7 +117,6 @@ impl Font for FontArc { } #[inline] - #[allow(deprecated)] fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { self.0.kern_unscaled(first, second) } @@ -145,16 +140,6 @@ impl Font for FontArc { fn glyph_raster_image(&self, id: GlyphId, size: u16) -> Option { self.0.glyph_raster_image(id, size) } - - #[inline] - fn glyph_identifier(&self) -> GlyphIdentifier<'_> { - self.0.glyph_identifier() - } - - #[inline] - fn kerner(&self) -> Kerner<'_> { - self.0.kerner() - } } impl From for FontArc { diff --git a/glyph/src/lib.rs b/glyph/src/lib.rs index f1c00bc..f2b33bb 100644 --- a/glyph/src/lib.rs +++ b/glyph/src/lib.rs @@ -42,5 +42,5 @@ pub use crate::{ glyph::*, outlined::*, scale::*, - ttfp::{FontRef, FontVec, GlyphIdentifier, GlyphImage, GlyphImageFormat, Kerner}, + ttfp::{FontRef, FontVec, GlyphImage, GlyphImageFormat}, }; diff --git a/glyph/src/scale.rs b/glyph/src/scale.rs index f9c7975..da0cb04 100644 --- a/glyph/src/scale.rs +++ b/glyph/src/scale.rs @@ -1,4 +1,4 @@ -use crate::{Font, Glyph, GlyphId, GlyphIdentifier, OutlinedGlyph, Rect}; +use crate::{Font, Glyph, GlyphId, OutlinedGlyph, Rect}; /// Pixel scale. /// @@ -116,8 +116,6 @@ pub trait ScaleFont { /// Lookup a `GlyphId` matching a given `char`. #[inline] - #[allow(deprecated)] - #[deprecated(note = "Use & re-use glyph_identifier() for better performance")] fn glyph_id(&self, c: char) -> GlyphId { self.font().glyph_id(c) } @@ -139,8 +137,6 @@ pub trait ScaleFont { /// assert_eq!(a1.position, point(0.0, 0.0)); /// ``` #[inline] - #[allow(deprecated)] - #[deprecated(note = "Use & re-use glyph_identifier() for better performance")] fn scaled_glyph(&self, c: char) -> Glyph { self.font().glyph_id(c).with_scale(self.scale()) } @@ -171,8 +167,6 @@ pub trait ScaleFont { /// Returns additional pixel scaled kerning to apply for a particular pair of glyphs. #[inline] - #[allow(deprecated)] - #[deprecated(note = "Use & re-use kerner() for better performance")] fn kern(&self, first: GlyphId, second: GlyphId) -> f32 { self.h_scale_factor() * self.font().kern_unscaled(first, second) } @@ -209,10 +203,6 @@ pub trait ScaleFont { fn outline_glyph(&self, glyph: Glyph) -> Option { self.font().outline_glyph(glyph) } - - fn glyph_identifier(&self) -> PxScaleGlyphIdentifier<'_>; - - fn kerner(&self) -> PxScaleKerner<'_>; } impl> ScaleFont for &SF { @@ -230,16 +220,6 @@ impl> ScaleFont for &SF { fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> { (*self).codepoint_ids() } - - #[inline] - fn glyph_identifier(&self) -> PxScaleGlyphIdentifier<'_> { - (*self).glyph_identifier() - } - - #[inline] - fn kerner(&self) -> PxScaleKerner<'_> { - (*self).kerner() - } } /// A [`Font`](trait.Font.html) and an associated pixel scale. @@ -272,51 +252,4 @@ impl ScaleFont for PxScaleFont { fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> { self.font.codepoint_ids() } - - #[inline] - fn glyph_identifier(&self) -> PxScaleGlyphIdentifier<'_> { - PxScaleGlyphIdentifier { - gider: self.font.glyph_identifier(), - scale: self.scale, - } - } - - #[inline] - fn kerner(&self) -> PxScaleKerner<'_> { - PxScaleKerner { - kerner: self.font.kerner(), - h_scale_factor: self.h_scale_factor(), - } - } -} - -#[derive(Debug)] -pub struct PxScaleKerner<'a> { - kerner: crate::Kerner<'a>, - h_scale_factor: f32, -} - -impl PxScaleKerner<'_> { - #[inline] - pub fn kern(&self, first: GlyphId, second: GlyphId) -> f32 { - self.kerner.kern_unscaled(first, second) * self.h_scale_factor - } -} - -#[derive(Debug)] -pub struct PxScaleGlyphIdentifier<'a> { - gider: GlyphIdentifier<'a>, - scale: PxScale, -} - -impl PxScaleGlyphIdentifier<'_> { - #[inline] - pub fn glyph_id(&self, c: char) -> GlyphId { - self.gider.glyph_id(c) - } - - #[inline] - pub fn scaled_glyph(&self, c: char) -> Glyph { - self.glyph_id(c).with_scale(self.scale) - } } diff --git a/glyph/src/ttfp.rs b/glyph/src/ttfp.rs index a15d823..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)?, + ))) } } @@ -206,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) } @@ -253,14 +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() - .tables() - .kern - .iter() - .flat_map(|c| c.subtables) - .filter(|st| st.horizontal && !st.variable) - .find_map(|st| st.glyphs_kerning(first.into(), second.into())) + .glyphs_hor_kerning(first.into(), second.into()) .map(f32::from) .unwrap_or_default() } @@ -268,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, @@ -336,71 +327,9 @@ macro_rules! impl_font { .glyph_raster_image(id.into(), size) .map(Into::into) } - - #[inline] - fn glyph_identifier(&self) -> GlyphIdentifier<'_> { - GlyphIdentifier { - tables: self - .0 - .as_face_ref() - .tables() - .cmap - .iter() - .flat_map(|cmap| cmap.subtables) - .filter(|st| st.is_unicode()) - .collect(), - } - } - - #[inline] - fn kerner(&self) -> Kerner<'_> { - Kerner { - tables: self - .0 - .as_face_ref() - .tables() - .kern - .iter() - .flat_map(|c| c.subtables) - .filter(|st| st.horizontal && !st.variable) - .collect(), - } - } } }; } impl_font!(FontRef<'_>); impl_font!(FontVec); - -#[derive(Debug)] -pub struct GlyphIdentifier<'font> { - tables: Vec>, -} - -impl GlyphIdentifier<'_> { - #[inline] - pub fn glyph_id(&self, c: char) -> GlyphId { - self.tables - .iter() - .find_map(|t| t.glyph_index(c)) - .map(|gid| GlyphId(gid.0)) - .unwrap_or_default() - } -} - -#[derive(Debug)] -pub struct Kerner<'font> { - tables: Vec>, -} - -impl Kerner<'_> { - #[inline] - pub fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 { - self.tables - .iter() - .find_map(|st| st.glyphs_kerning(first.into(), second.into())) - .map(f32::from) - .unwrap_or_default() - } -} From a3b61080b329d978d07798120ca39c7399dbf759 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Sat, 6 Nov 2021 13:40:18 +0000 Subject: [PATCH 5/5] Update changelog --- glyph/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/glyph/CHANGELOG.md b/glyph/CHANGELOG.md index 1ee5ff2..54cad58 100644 --- a/glyph/CHANGELOG.md +++ b/glyph/CHANGELOG.md @@ -1,8 +1,8 @@ # Unreleased * 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, which are used heavily when positioning - glyphs into layouts. + 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.