summaryrefslogtreecommitdiff
path: root/library/src/math
diff options
context:
space:
mode:
authordamaxwell <damaxwell@alaska.edu>2023-06-26 03:51:27 -0800
committerGitHub <noreply@github.com>2023-06-26 13:51:27 +0200
commit9eb350d7deadd59efba50b0e33acfd0967b8d0a6 (patch)
treed3a96e090bca97fb207c583ea4991ed26e939de3 /library/src/math
parent1861ceb1792d2a42979dff2fa721246ada922a42 (diff)
support optical sizes for script/scriptscript when available (#1580)
Diffstat (limited to 'library/src/math')
-rw-r--r--library/src/math/ctx.rs50
-rw-r--r--library/src/math/fragment.rs30
2 files changed, 72 insertions, 8 deletions
diff --git a/library/src/math/ctx.rs b/library/src/math/ctx.rs
index a6487476..a1dc6cf4 100644
--- a/library/src/math/ctx.rs
+++ b/library/src/math/ctx.rs
@@ -31,6 +31,7 @@ pub struct MathContext<'a, 'b, 'v> {
pub ttf: &'a ttf_parser::Face<'a>,
pub table: ttf_parser::math::Table<'a>,
pub constants: ttf_parser::math::Constants<'a>,
+ pub ssty_table: Option<ttf_parser::gsub::AlternateSubstitution<'a>>,
pub space_width: Em,
pub fragments: Vec<MathFragment>,
pub local: Styles,
@@ -50,6 +51,27 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
) -> Self {
let table = font.ttf().tables().math.unwrap();
let constants = table.constants.unwrap();
+
+ let ssty_table = font
+ .ttf()
+ .tables()
+ .gsub
+ .and_then(|gsub| {
+ gsub.features
+ .find(ttf_parser::Tag::from_bytes(b"ssty"))
+ .and_then(|feature| feature.lookup_indices.get(0))
+ .and_then(|index| gsub.lookups.get(index))
+ })
+ .and_then(|ssty| {
+ ssty.subtables.get::<ttf_parser::gsub::SubstitutionSubtable>(0)
+ })
+ .and_then(|ssty| match ssty {
+ ttf_parser::gsub::SubstitutionSubtable::Alternate(alt_glyphs) => {
+ Some(alt_glyphs)
+ }
+ _ => None,
+ });
+
let size = TextElem::size_in(styles);
let ttf = font.ttf();
let space_width = ttf
@@ -66,6 +88,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
ttf: font.ttf(),
table,
constants,
+ ssty_table,
space_width,
fragments: vec![],
local: Styles::new(),
@@ -129,20 +152,31 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
let text = elem.text();
let span = elem.span();
let mut chars = text.chars();
- let fragment = if let Some(glyph) = chars
+ let fragment = if let Some(mut glyph) = chars
.next()
.filter(|_| chars.next().is_none())
.map(|c| self.style.styled_char(c))
.and_then(|c| GlyphFragment::try_new(self, c, span))
{
// A single letter that is available in the math font.
- if self.style.size == MathSize::Display
- && glyph.class == Some(MathClass::Large)
- {
- let height = scaled!(self, display_operator_min_height);
- glyph.stretch_vertical(self, height, Abs::zero()).into()
- } else {
- glyph.into()
+ match self.style.size {
+ MathSize::Display => {
+ if glyph.class == Some(MathClass::Large) {
+ let height = scaled!(self, display_operator_min_height);
+ glyph.stretch_vertical(self, height, Abs::zero()).into()
+ } else {
+ glyph.into()
+ }
+ }
+ MathSize::Script => {
+ glyph.make_scriptsize(self);
+ glyph.into()
+ }
+ MathSize::ScriptScript => {
+ glyph.make_scriptscriptsize(self);
+ glyph.into()
+ }
+ _ => glyph.into(),
}
} else if text.chars().all(|c| c.is_ascii_digit()) {
// Numbers aren't that difficult.
diff --git a/library/src/math/fragment.rs b/library/src/math/fragment.rs
index b70a3f7d..139ce07b 100644
--- a/library/src/math/fragment.rs
+++ b/library/src/math/fragment.rs
@@ -1,4 +1,5 @@
use super::*;
+use ttf_parser::gsub::AlternateSet;
#[derive(Debug, Clone)]
pub enum MathFragment {
@@ -272,6 +273,25 @@ impl GlyphFragment {
frame.meta_iter(self.meta);
frame
}
+
+ pub fn make_scriptsize(&mut self, ctx: &MathContext) {
+ let alt_id =
+ script_alternatives(ctx, self.id).and_then(|alts| alts.alternates.get(0));
+
+ if let Some(alt_id) = alt_id {
+ self.set_id(ctx, alt_id);
+ }
+ }
+
+ pub fn make_scriptscriptsize(&mut self, ctx: &MathContext) {
+ let alts = script_alternatives(ctx, self.id);
+ let alt_id = alts
+ .and_then(|alts| alts.alternates.get(1).or_else(|| alts.alternates.get(0)));
+
+ if let Some(alt_id) = alt_id {
+ self.set_id(ctx, alt_id);
+ }
+ }
}
impl Debug for GlyphFragment {
@@ -347,6 +367,16 @@ fn italics_correction(ctx: &MathContext, id: GlyphId) -> Option<Abs> {
Some(ctx.table.glyph_info?.italic_corrections?.get(id)?.scaled(ctx))
}
+/// Look up the script/scriptscript alternates for a glyph
+fn script_alternatives<'a>(
+ ctx: &MathContext<'a, '_, '_>,
+ id: GlyphId,
+) -> Option<AlternateSet<'a>> {
+ ctx.ssty_table.and_then(|ssty| {
+ ssty.coverage.get(id).and_then(|index| ssty.alternate_sets.get(index))
+ })
+}
+
/// Look up the italics correction for a glyph.
fn is_extended_shape(ctx: &MathContext, id: GlyphId) -> bool {
ctx.table