Parse math fonts only once

This commit is contained in:
Laurenz 2022-05-24 19:30:09 +02:00
parent acdde6d326
commit 018860da9c
3 changed files with 27 additions and 6 deletions

View File

@ -6,6 +6,8 @@ use std::fmt::{self, Debug, Formatter};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use once_cell::sync::OnceCell;
use rex::font::MathFont;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ttf_parser::{name_id, GlyphId, PlatformId, Tag}; use ttf_parser::{name_id, GlyphId, PlatformId, Tag};
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
@ -246,6 +248,8 @@ pub struct Face {
ttf: rustybuzz::Face<'static>, ttf: rustybuzz::Face<'static>,
/// The faces metrics. /// The faces metrics.
metrics: FaceMetrics, metrics: FaceMetrics,
/// The parsed ReX math font.
math: OnceCell<Option<MathFont>>,
} }
impl Face { impl Face {
@ -263,7 +267,13 @@ impl Face {
let ttf = rustybuzz::Face::from_slice(slice, index)?; let ttf = rustybuzz::Face::from_slice(slice, index)?;
let metrics = FaceMetrics::from_ttf(&ttf); let metrics = FaceMetrics::from_ttf(&ttf);
Some(Self { buffer, index, ttf, metrics }) Some(Self {
buffer,
index,
ttf,
metrics,
math: OnceCell::new(),
})
} }
/// The underlying buffer. /// The underlying buffer.
@ -293,6 +303,11 @@ impl Face {
&self.metrics &self.metrics
} }
/// Access the math font, if any.
pub fn math(&self) -> Option<&MathFont> {
self.math.get_or_init(|| MathFont::parse(self.buffer()).ok()).as_ref()
}
/// Convert from font units to an em length. /// Convert from font units to an em length.
pub fn to_em(&self, units: impl Into<f64>) -> Em { pub fn to_em(&self, units: impl Into<f64>) -> Em {
Em::from_units(units, self.units_per_em()) Em::from_units(units, self.units_per_em())

View File

@ -35,13 +35,13 @@ impl Layout for RexNode {
.at(span)?; .at(span)?;
// Prepare the font. // Prepare the font.
let data = ctx.fonts.get(face_id).buffer(); let face = ctx.fonts.get(face_id);
let font = MathFont::parse(data) let ctx = face
.map_err(|_| "failed to parse math font") .math()
.and_then(FontContext::new)
.ok_or("font is not suitable for math")
.at(span)?; .at(span)?;
let ctx = FontContext::new(&font).ok_or("failed to parse math font").at(span)?;
// Layout the formula. // Layout the formula.
let em = styles.get(TextNode::SIZE); let em = styles.get(TextNode::SIZE);
let style = if self.display { Style::Display } else { Style::Text }; let style = if self.display { Style::Display } else { Style::Text };

View File

@ -15,6 +15,12 @@ $[ \sum_{k=0}^n k = \frac{n(n+1)}{2} ]$
// Test that blackboard style looks nice. // Test that blackboard style looks nice.
$[ f: \mathbb{N} \rightarrow \mathbb{R} ]$ $[ f: \mathbb{N} \rightarrow \mathbb{R} ]$
---
#set math(family: "IBM Plex Sans")
// Error: 1-4 font is not suitable for math
$a$
--- ---
// Error: 1-10 expected '}' found EOF // Error: 1-10 expected '}' found EOF
$\sqrt{x$ $\sqrt{x$