support optical sizes for script/scriptscript when available (#1580)

This commit is contained in:
damaxwell 2023-06-26 03:51:27 -08:00 committed by GitHub
parent 1861ceb179
commit 9eb350d7de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 103 additions and 8 deletions

View File

@ -31,6 +31,7 @@ pub struct MathContext<'a, 'b, 'v> {
pub ttf: &'a ttf_parser::Face<'a>, pub ttf: &'a ttf_parser::Face<'a>,
pub table: ttf_parser::math::Table<'a>, pub table: ttf_parser::math::Table<'a>,
pub constants: ttf_parser::math::Constants<'a>, pub constants: ttf_parser::math::Constants<'a>,
pub ssty_table: Option<ttf_parser::gsub::AlternateSubstitution<'a>>,
pub space_width: Em, pub space_width: Em,
pub fragments: Vec<MathFragment>, pub fragments: Vec<MathFragment>,
pub local: Styles, pub local: Styles,
@ -50,6 +51,27 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
) -> Self { ) -> Self {
let table = font.ttf().tables().math.unwrap(); let table = font.ttf().tables().math.unwrap();
let constants = table.constants.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 size = TextElem::size_in(styles);
let ttf = font.ttf(); let ttf = font.ttf();
let space_width = ttf let space_width = ttf
@ -66,6 +88,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
ttf: font.ttf(), ttf: font.ttf(),
table, table,
constants, constants,
ssty_table,
space_width, space_width,
fragments: vec![], fragments: vec![],
local: Styles::new(), local: Styles::new(),
@ -129,21 +152,32 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
let text = elem.text(); let text = elem.text();
let span = elem.span(); let span = elem.span();
let mut chars = text.chars(); let mut chars = text.chars();
let fragment = if let Some(glyph) = chars let fragment = if let Some(mut glyph) = chars
.next() .next()
.filter(|_| chars.next().is_none()) .filter(|_| chars.next().is_none())
.map(|c| self.style.styled_char(c)) .map(|c| self.style.styled_char(c))
.and_then(|c| GlyphFragment::try_new(self, c, span)) .and_then(|c| GlyphFragment::try_new(self, c, span))
{ {
// A single letter that is available in the math font. // A single letter that is available in the math font.
if self.style.size == MathSize::Display match self.style.size {
&& glyph.class == Some(MathClass::Large) MathSize::Display => {
{ if glyph.class == Some(MathClass::Large) {
let height = scaled!(self, display_operator_min_height); let height = scaled!(self, display_operator_min_height);
glyph.stretch_vertical(self, height, Abs::zero()).into() glyph.stretch_vertical(self, height, Abs::zero()).into()
} else { } else {
glyph.into() 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()) { } else if text.chars().all(|c| c.is_ascii_digit()) {
// Numbers aren't that difficult. // Numbers aren't that difficult.
let mut fragments = vec![]; let mut fragments = vec![];

View File

@ -1,4 +1,5 @@
use super::*; use super::*;
use ttf_parser::gsub::AlternateSet;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum MathFragment { pub enum MathFragment {
@ -272,6 +273,25 @@ impl GlyphFragment {
frame.meta_iter(self.meta); frame.meta_iter(self.meta);
frame 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 { 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)) 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. /// Look up the italics correction for a glyph.
fn is_extended_shape(ctx: &MathContext, id: GlyphId) -> bool { fn is_extended_shape(ctx: &MathContext, id: GlyphId) -> bool {
ctx.table ctx.table

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -11,6 +11,7 @@ $ &sin x + log_2 x \
--- ---
// Test scripts vs limits. // Test scripts vs limits.
#set page(width: auto)
#set text(font: "New Computer Modern") #set text(font: "New Computer Modern")
Discuss $lim_(n->oo) 1/n$ now. Discuss $lim_(n->oo) 1/n$ now.
$ lim_(n->infinity) 1/n = 0 $ $ lim_(n->infinity) 1/n = 0 $

View File

@ -0,0 +1,30 @@
// test optical sized variants in sub/superscripts
---
// Test transition from script to scriptscript.
#[
#set text(size:20pt)
$ e^(e^(e^(e))) $
]
A large number: $e^(e^(e^(e)))$.
---
// Test prime/double prime via scriptsize
#let prime = [ \u{2032} ]
#let dprime = [ \u{2033} ]
#let tprime = [ \u{2034} ]
$ y^dprime-2y^prime + y = 0 $
$y^dprime-2y^prime + y = 0$
$ y^tprime_3 + g^(prime 2) $
---
// Test prime superscript on large symbol
$ scripts(sum_(k in NN))^prime 1/k^2 $
$sum_(k in NN)^prime 1/k^2$
---
// Test script-script in a fraction.
$ 1/(x^A) $
#[#set text(size:18pt); $1/(x^A)$] vs. #[#set text(size:14pt); $x^A$]