summaryrefslogtreecommitdiff
path: root/src/font.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-04-05 22:32:09 +0200
committerLaurenz <laurmaedje@gmail.com>2021-04-05 22:32:09 +0200
commitde20a21a584a90da682a64e9a79cd18a95195b70 (patch)
tree2c7ade7d1078111ebbce889a0fca8cee388d6135 /src/font.rs
parenta86cf7bd8c58b0ec26f8f53eb90f0dc6c95a1070 (diff)
Reshaping with unsafe-to-break ⚡
Co-Authored-By: Martin <mhaug@live.de>
Diffstat (limited to 'src/font.rs')
-rw-r--r--src/font.rs74
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 {