diff options
Diffstat (limited to 'src/font/mod.rs')
| -rw-r--r-- | src/font/mod.rs | 249 |
1 files changed, 0 insertions, 249 deletions
diff --git a/src/font/mod.rs b/src/font/mod.rs deleted file mode 100644 index 2353e51c..00000000 --- a/src/font/mod.rs +++ /dev/null @@ -1,249 +0,0 @@ -//! Font handling. - -mod book; -mod variant; - -pub use self::book::{Coverage, FontBook, FontFlags, FontInfo}; -pub use self::variant::{FontStretch, FontStyle, FontVariant, FontWeight}; - -use std::fmt::{self, Debug, Formatter}; -use std::hash::{Hash, Hasher}; -use std::sync::Arc; - -use ttf_parser::GlyphId; - -use self::book::find_name; -use crate::eval::Cast; -use crate::geom::Em; -use crate::util::Bytes; - -/// An OpenType font. -/// -/// Values of this type are cheap to clone and hash. -#[derive(Clone)] -pub struct Font(Arc<Repr>); - -/// The internal representation of a font. -struct Repr { - /// The raw font data, possibly shared with other fonts from the same - /// collection. The vector's allocation must not move, because `ttf` points - /// into it using unsafe code. - data: Bytes, - /// The font's index in the buffer. - index: u32, - /// Metadata about the font. - info: FontInfo, - /// The font's metrics. - metrics: FontMetrics, - /// The underlying ttf-parser face. - ttf: ttf_parser::Face<'static>, - /// The underlying rustybuzz face. - rusty: rustybuzz::Face<'static>, -} - -impl Font { - /// Parse a font from data and collection index. - pub fn new(data: Bytes, index: u32) -> Option<Self> { - // Safety: - // - The slices's location is stable in memory: - // - We don't move the underlying vector - // - Nobody else can move it since we have a strong ref to the `Arc`. - // - The internal 'static lifetime is not leaked because its rewritten - // to the self-lifetime in `ttf()`. - let slice: &'static [u8] = - unsafe { std::slice::from_raw_parts(data.as_ptr(), data.len()) }; - - let ttf = ttf_parser::Face::parse(slice, index).ok()?; - let rusty = rustybuzz::Face::from_slice(slice, index)?; - let metrics = FontMetrics::from_ttf(&ttf); - let info = FontInfo::from_ttf(&ttf)?; - - Some(Self(Arc::new(Repr { data, index, info, metrics, ttf, rusty }))) - } - - /// Parse all fonts in the given data. - pub fn iter(data: Bytes) -> impl Iterator<Item = Self> { - let count = ttf_parser::fonts_in_collection(&data).unwrap_or(1); - (0..count).filter_map(move |index| Self::new(data.clone(), index)) - } - - /// The underlying buffer. - pub fn data(&self) -> &Bytes { - &self.0.data - } - - /// The font's index in the buffer. - pub fn index(&self) -> u32 { - self.0.index - } - - /// The font's metadata. - pub fn info(&self) -> &FontInfo { - &self.0.info - } - - /// The font's metrics. - pub fn metrics(&self) -> &FontMetrics { - &self.0.metrics - } - - /// The number of font units per one em. - pub fn units_per_em(&self) -> f64 { - self.0.metrics.units_per_em - } - - /// Convert from font units to an em length. - pub fn to_em(&self, units: impl Into<f64>) -> Em { - Em::from_units(units, self.units_per_em()) - } - - /// Look up the horizontal advance width of a glyph. - pub fn advance(&self, glyph: u16) -> Option<Em> { - self.0 - .ttf - .glyph_hor_advance(GlyphId(glyph)) - .map(|units| self.to_em(units)) - } - - /// Lookup a name by id. - pub fn find_name(&self, id: u16) -> Option<String> { - find_name(&self.0.ttf, id) - } - - /// A reference to the underlying `ttf-parser` face. - pub fn ttf(&self) -> &ttf_parser::Face<'_> { - // We can't implement Deref because that would leak the - // internal 'static lifetime. - &self.0.ttf - } - - /// A reference to the underlying `rustybuzz` face. - pub fn rusty(&self) -> &rustybuzz::Face<'_> { - // We can't implement Deref because that would leak the - // internal 'static lifetime. - &self.0.rusty - } -} - -impl Hash for Font { - fn hash<H: Hasher>(&self, state: &mut H) { - self.0.data.hash(state); - self.0.index.hash(state); - } -} - -impl Debug for Font { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "Font({})", self.info().family) - } -} - -impl Eq for Font {} - -impl PartialEq for Font { - fn eq(&self, other: &Self) -> bool { - self.0.data == other.0.data && self.0.index == other.0.index - } -} - -/// Metrics of a font. -#[derive(Debug, Copy, Clone)] -pub struct FontMetrics { - /// How many font units represent one em unit. - pub units_per_em: f64, - /// The distance from the baseline to the typographic ascender. - pub ascender: Em, - /// The approximate height of uppercase letters. - pub cap_height: Em, - /// The approximate height of non-ascending lowercase letters. - pub x_height: Em, - /// The distance from the baseline to the typographic descender. - pub descender: Em, - /// Recommended metrics for a strikethrough line. - pub strikethrough: LineMetrics, - /// Recommended metrics for an underline. - pub underline: LineMetrics, - /// Recommended metrics for an overline. - pub overline: LineMetrics, -} - -impl FontMetrics { - /// Extract the font's metrics. - pub fn from_ttf(ttf: &ttf_parser::Face) -> Self { - let units_per_em = f64::from(ttf.units_per_em()); - let to_em = |units| Em::from_units(units, units_per_em); - - let ascender = to_em(ttf.typographic_ascender().unwrap_or(ttf.ascender())); - let cap_height = ttf.capital_height().filter(|&h| h > 0).map_or(ascender, to_em); - let x_height = ttf.x_height().filter(|&h| h > 0).map_or(ascender, to_em); - let descender = to_em(ttf.typographic_descender().unwrap_or(ttf.descender())); - let strikeout = ttf.strikeout_metrics(); - let underline = ttf.underline_metrics(); - - let strikethrough = LineMetrics { - position: strikeout.map_or(Em::new(0.25), |s| to_em(s.position)), - thickness: strikeout - .or(underline) - .map_or(Em::new(0.06), |s| to_em(s.thickness)), - }; - - let underline = LineMetrics { - position: underline.map_or(Em::new(-0.2), |s| to_em(s.position)), - thickness: underline - .or(strikeout) - .map_or(Em::new(0.06), |s| to_em(s.thickness)), - }; - - let overline = LineMetrics { - position: cap_height + Em::new(0.1), - thickness: underline.thickness, - }; - - Self { - units_per_em, - ascender, - cap_height, - x_height, - descender, - strikethrough, - underline, - overline, - } - } - - /// Look up a vertical metric. - pub fn vertical(&self, metric: VerticalFontMetric) -> Em { - match metric { - VerticalFontMetric::Ascender => self.ascender, - VerticalFontMetric::CapHeight => self.cap_height, - VerticalFontMetric::XHeight => self.x_height, - VerticalFontMetric::Baseline => Em::zero(), - VerticalFontMetric::Descender => self.descender, - } - } -} - -/// Metrics for a decorative line. -#[derive(Debug, Copy, Clone)] -pub struct LineMetrics { - /// The vertical offset of the line from the baseline. Positive goes - /// upwards, negative downwards. - pub position: Em, - /// The thickness of the line. - pub thickness: Em, -} - -/// Identifies a vertical metric of a font. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] -pub enum VerticalFontMetric { - /// The font's ascender, which typically exceeds the height of all glyphs. - Ascender, - /// The approximate height of uppercase letters. - CapHeight, - /// The approximate height of non-ascending lowercase letters. - XHeight, - /// The baseline on which the letters rest. - Baseline, - /// The font's ascender, which typically exceeds the depth of all glyphs. - Descender, -} |
