diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-04-05 22:32:09 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-04-05 22:32:09 +0200 |
| commit | de20a21a584a90da682a64e9a79cd18a95195b70 (patch) | |
| tree | 2c7ade7d1078111ebbce889a0fca8cee388d6135 /src/font.rs | |
| parent | a86cf7bd8c58b0ec26f8f53eb90f0dc6c95a1070 (diff) | |
Reshaping with unsafe-to-break ⚡
Co-Authored-By: Martin <mhaug@live.de>
Diffstat (limited to 'src/font.rs')
| -rw-r--r-- | src/font.rs | 74 |
1 files changed, 40 insertions, 34 deletions
diff --git a/src/font.rs b/src/font.rs index bcc64627..a816ed06 100644 --- a/src/font.rs +++ b/src/font.rs @@ -4,12 +4,19 @@ use std::fmt::{self, Display, Formatter}; use fontdock::FaceFromVec; +use crate::geom::Length; + /// An owned font face. pub struct FaceBuf { data: Box<[u8]>, index: u32, ttf: ttf_parser::Face<'static>, buzz: rustybuzz::Face<'static>, + units_per_em: f64, + ascender: f64, + cap_height: f64, + x_height: f64, + descender: f64, } impl FaceBuf { @@ -36,6 +43,22 @@ impl FaceBuf { // lifetime. &self.buzz } + + /// Look up a vertical metric at a given font size. + pub fn vertical_metric(&self, size: Length, metric: VerticalFontMetric) -> Length { + self.convert(size, match metric { + VerticalFontMetric::Ascender => self.ascender, + VerticalFontMetric::CapHeight => self.cap_height, + VerticalFontMetric::XHeight => self.x_height, + VerticalFontMetric::Baseline => 0.0, + VerticalFontMetric::Descender => self.descender, + }) + } + + /// Convert from font units to a length at a given font size. + pub fn convert(&self, size: Length, units: impl Into<f64>) -> Length { + units.into() / self.units_per_em * size + } } impl FaceFromVec for FaceBuf { @@ -47,11 +70,26 @@ impl FaceFromVec for FaceBuf { let slice: &'static [u8] = unsafe { std::slice::from_raw_parts(data.as_ptr(), data.len()) }; + let ttf = ttf_parser::Face::from_slice(slice, index).ok()?; + let buzz = rustybuzz::Face::from_slice(slice, index)?; + + // Look up some metrics we may need often. + let units_per_em = ttf.units_per_em().unwrap_or(1000); + let ascender = ttf.typographic_ascender().unwrap_or(ttf.ascender()); + let cap_height = ttf.capital_height().filter(|&h| h > 0).unwrap_or(ascender); + let x_height = ttf.x_height().filter(|&h| h > 0).unwrap_or(ascender); + let descender = ttf.typographic_descender().unwrap_or(ttf.descender()); + Some(Self { data, index, - ttf: ttf_parser::Face::from_slice(slice, index).ok()?, - buzz: rustybuzz::Face::from_slice(slice, index)?, + ttf, + buzz, + units_per_em: f64::from(units_per_em), + ascender: f64::from(ascender), + cap_height: f64::from(cap_height), + x_height: f64::from(x_height), + descender: f64::from(descender), }) } } @@ -77,38 +115,6 @@ pub enum VerticalFontMetric { Descender, } -impl VerticalFontMetric { - /// Look up the metric in the given font face. - pub fn lookup(self, face: &ttf_parser::Face) -> i16 { - match self { - VerticalFontMetric::Ascender => lookup_ascender(face), - VerticalFontMetric::CapHeight => face - .capital_height() - .filter(|&h| h > 0) - .unwrap_or_else(|| lookup_ascender(face)), - VerticalFontMetric::XHeight => face - .x_height() - .filter(|&h| h > 0) - .unwrap_or_else(|| lookup_ascender(face)), - VerticalFontMetric::Baseline => 0, - VerticalFontMetric::Descender => lookup_descender(face), - } - } -} - -/// The ascender of the face. -fn lookup_ascender(face: &ttf_parser::Face) -> i16 { - // We prefer the typographic ascender over the Windows ascender because - // it can be overly large if the font has large glyphs. - face.typographic_ascender().unwrap_or_else(|| face.ascender()) -} - -/// The descender of the face. -fn lookup_descender(face: &ttf_parser::Face) -> i16 { - // See `lookup_ascender` for reason. - face.typographic_descender().unwrap_or_else(|| face.descender()) -} - impl Display for VerticalFontMetric { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.pad(match self { |
