summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax <max@mkor.je>2025-07-09 13:08:49 +0000
committerGitHub <noreply@github.com>2025-07-09 13:08:49 +0000
commitf9b01f595dba96044c725a97ecb4972bec7d57ed (patch)
tree55ec44d50cf50ab5099a8ee9e0eacee02b0efd08
parenteed34070513e6060f86f86b56ba7071507fe811b (diff)
Move math styling to codex and add `math.scr` (#6309)
-rw-r--r--Cargo.lock5
-rw-r--r--Cargo.toml4
-rw-r--r--crates/typst-layout/Cargo.toml1
-rw-r--r--crates/typst-layout/src/math/text.rs254
-rw-r--r--crates/typst-library/src/math/equation.rs7
-rw-r--r--crates/typst-library/src/math/mod.rs1
-rw-r--r--crates/typst-library/src/math/style.rs68
-rw-r--r--docs/reference/groups.yml2
-rw-r--r--tests/ref/math-style-fallback.pngbin0 -> 935 bytes
-rw-r--r--tests/ref/math-style-hebrew-exceptions.pngbin296 -> 489 bytes
-rw-r--r--tests/ref/math-style-script.pngbin0 -> 585 bytes
-rw-r--r--tests/suite/math/style.typ21
12 files changed, 94 insertions, 269 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5526da48..1893f89f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -413,7 +413,7 @@ dependencies = [
[[package]]
name = "codex"
version = "0.1.1"
-source = "git+https://github.com/typst/codex?rev=a5428cb#a5428cb9c81a41354d44b44dbd5a16a710bbd928"
+source = "git+https://github.com/typst/codex?rev=9ac86f9#9ac86f96af5b89fce555e6bba8b6d1ac7b44ef00"
[[package]]
name = "color-print"
@@ -2861,7 +2861,7 @@ dependencies = [
[[package]]
name = "typst-assets"
version = "0.13.1"
-source = "git+https://github.com/typst/typst-assets?rev=c1089b4#c1089b46c461bdde579c55caa941a3cc7dec3e8a"
+source = "git+https://github.com/typst/typst-assets?rev=edf0d64#edf0d648376e29738a05a933af9ea99bb81557b1"
[[package]]
name = "typst-cli"
@@ -3032,6 +3032,7 @@ version = "0.13.1"
dependencies = [
"az",
"bumpalo",
+ "codex",
"comemo",
"ecow",
"hypher",
diff --git a/Cargo.toml b/Cargo.toml
index 6cc59ee8..9657f207 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,7 +32,7 @@ typst-svg = { path = "crates/typst-svg", version = "0.13.1" }
typst-syntax = { path = "crates/typst-syntax", version = "0.13.1" }
typst-timing = { path = "crates/typst-timing", version = "0.13.1" }
typst-utils = { path = "crates/typst-utils", version = "0.13.1" }
-typst-assets = { git = "https://github.com/typst/typst-assets", rev = "c1089b4" }
+typst-assets = { git = "https://github.com/typst/typst-assets", rev = "edf0d64" }
typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "bfa947f" }
arrayvec = "0.7.4"
az = "1.2"
@@ -47,7 +47,7 @@ clap = { version = "4.4", features = ["derive", "env", "wrap_help"] }
clap_complete = "4.2.1"
clap_mangen = "0.2.10"
codespan-reporting = "0.11"
-codex = { git = "https://github.com/typst/codex", rev = "a5428cb" }
+codex = { git = "https://github.com/typst/codex", rev = "9ac86f9" }
color-print = "0.3.6"
comemo = "0.4"
csv = "1"
diff --git a/crates/typst-layout/Cargo.toml b/crates/typst-layout/Cargo.toml
index cc355a3d..2c314e5c 100644
--- a/crates/typst-layout/Cargo.toml
+++ b/crates/typst-layout/Cargo.toml
@@ -21,6 +21,7 @@ typst-timing = { workspace = true }
typst-utils = { workspace = true }
az = { workspace = true }
bumpalo = { workspace = true }
+codex = { workspace = true }
comemo = { workspace = true }
ecow = { workspace = true }
hypher = { workspace = true }
diff --git a/crates/typst-layout/src/math/text.rs b/crates/typst-layout/src/math/text.rs
index 53f88f2b..634969cd 100644
--- a/crates/typst-layout/src/math/text.rs
+++ b/crates/typst-layout/src/math/text.rs
@@ -1,10 +1,11 @@
use std::f64::consts::SQRT_2;
+use codex::styling::{to_style, MathStyle};
use ecow::EcoString;
use typst_library::diag::SourceResult;
use typst_library::foundations::{Packed, StyleChain, SymbolElem};
use typst_library::layout::{Abs, Size};
-use typst_library::math::{EquationElem, MathSize, MathVariant};
+use typst_library::math::{EquationElem, MathSize};
use typst_library::text::{
BottomEdge, BottomEdgeMetric, TextElem, TopEdge, TopEdgeMetric,
};
@@ -64,12 +65,21 @@ fn layout_inline_text(
ctx: &mut MathContext,
styles: StyleChain,
) -> SourceResult<FrameFragment> {
+ let variant = styles.get(EquationElem::variant);
+ let bold = styles.get(EquationElem::bold);
+ // Disable auto-italic.
+ let italic = styles.get(EquationElem::italic).or(Some(false));
+
if text.chars().all(|c| c.is_ascii_digit() || c == '.') {
// Small optimization for numbers. Note that this lays out slightly
// differently to normal text and is worth re-evaluating in the future.
let mut fragments = vec![];
for unstyled_c in text.chars() {
- let c = styled_char(styles, unstyled_c, false);
+ // This is fine as ascii digits and '.' can never end up as more
+ // than a single char after styling.
+ let style = MathStyle::select(unstyled_c, variant, bold, italic);
+ let c = to_style(unstyled_c, style).next().unwrap();
+
let glyph = GlyphFragment::new_char(ctx.font, styles, c, span)?;
fragments.push(glyph.into());
}
@@ -83,8 +93,10 @@ fn layout_inline_text(
.map(|p| p.wrap());
let styles = styles.chain(&local);
- let styled_text: EcoString =
- text.chars().map(|c| styled_char(styles, c, false)).collect();
+ let styled_text: EcoString = text
+ .chars()
+ .flat_map(|c| to_style(c, MathStyle::select(c, variant, bold, italic)))
+ .collect();
let spaced = styled_text.graphemes(true).nth(1).is_some();
let elem = TextElem::packed(styled_text).spanned(span);
@@ -124,9 +136,16 @@ pub fn layout_symbol(
Some(c) if has_dtls_feat(ctx.font) => (c, styles.chain(&dtls)),
_ => (elem.text, styles),
};
- let c = styled_char(styles, unstyled_c, true);
+
+ let variant = styles.get(EquationElem::variant);
+ let bold = styles.get(EquationElem::bold);
+ let italic = styles.get(EquationElem::italic);
+
+ let style = MathStyle::select(unstyled_c, variant, bold, italic);
+ let text: EcoString = to_style(unstyled_c, style).collect();
+
let fragment: MathFragment =
- match GlyphFragment::new_char(ctx.font, symbol_styles, c, elem.span()) {
+ match GlyphFragment::new(ctx.font, symbol_styles, &text, elem.span()) {
Ok(mut glyph) => {
adjust_glyph_layout(&mut glyph, ctx, styles);
glyph.into()
@@ -134,8 +153,7 @@ pub fn layout_symbol(
Err(_) => {
// Not in the math font, fallback to normal inline text layout.
// TODO: Should replace this with proper fallback in [`GlyphFragment::new`].
- layout_inline_text(c.encode_utf8(&mut [0; 4]), elem.span(), ctx, styles)?
- .into()
+ layout_inline_text(&text, elem.span(), ctx, styles)?.into()
}
};
ctx.push(fragment);
@@ -161,226 +179,6 @@ fn adjust_glyph_layout(
}
}
-/// Style the character by selecting the unicode codepoint for italic, bold,
-/// caligraphic, etc.
-///
-/// <https://www.w3.org/TR/mathml-core/#new-text-transform-mappings>
-/// <https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols>
-fn styled_char(styles: StyleChain, c: char, auto_italic: bool) -> char {
- use MathVariant::*;
-
- let variant = styles.get(EquationElem::variant);
- let bold = styles.get(EquationElem::bold);
- let italic = styles.get(EquationElem::italic).unwrap_or(
- auto_italic
- && matches!(
- c,
- 'a'..='z' | 'ħ' | 'ı' | 'ȷ' | 'A'..='Z' |
- 'α'..='ω' | '∂' | 'ϵ' | 'ϑ' | 'ϰ' | 'ϕ' | 'ϱ' | 'ϖ'
- )
- && matches!(variant, Sans | Serif),
- );
-
- if let Some(c) = basic_exception(c) {
- return c;
- }
-
- if let Some(c) = latin_exception(c, variant, bold, italic) {
- return c;
- }
-
- if let Some(c) = greek_exception(c, variant, bold, italic) {
- return c;
- }
-
- let base = match c {
- 'A'..='Z' => 'A',
- 'a'..='z' => 'a',
- 'Α'..='Ω' => 'Α',
- 'α'..='ω' => 'α',
- '0'..='9' => '0',
- // Hebrew Alef -> Dalet.
- '\u{05D0}'..='\u{05D3}' => '\u{05D0}',
- _ => return c,
- };
-
- let tuple = (variant, bold, italic);
- let start = match c {
- // Latin upper.
- 'A'..='Z' => match tuple {
- (Serif, false, false) => 0x0041,
- (Serif, true, false) => 0x1D400,
- (Serif, false, true) => 0x1D434,
- (Serif, true, true) => 0x1D468,
- (Sans, false, false) => 0x1D5A0,
- (Sans, true, false) => 0x1D5D4,
- (Sans, false, true) => 0x1D608,
- (Sans, true, true) => 0x1D63C,
- (Cal, false, _) => 0x1D49C,
- (Cal, true, _) => 0x1D4D0,
- (Frak, false, _) => 0x1D504,
- (Frak, true, _) => 0x1D56C,
- (Mono, _, _) => 0x1D670,
- (Bb, _, _) => 0x1D538,
- },
-
- // Latin lower.
- 'a'..='z' => match tuple {
- (Serif, false, false) => 0x0061,
- (Serif, true, false) => 0x1D41A,
- (Serif, false, true) => 0x1D44E,
- (Serif, true, true) => 0x1D482,
- (Sans, false, false) => 0x1D5BA,
- (Sans, true, false) => 0x1D5EE,
- (Sans, false, true) => 0x1D622,
- (Sans, true, true) => 0x1D656,
- (Cal, false, _) => 0x1D4B6,
- (Cal, true, _) => 0x1D4EA,
- (Frak, false, _) => 0x1D51E,
- (Frak, true, _) => 0x1D586,
- (Mono, _, _) => 0x1D68A,
- (Bb, _, _) => 0x1D552,
- },
-
- // Greek upper.
- 'Α'..='Ω' => match tuple {
- (Serif, false, false) => 0x0391,
- (Serif, true, false) => 0x1D6A8,
- (Serif, false, true) => 0x1D6E2,
- (Serif, true, true) => 0x1D71C,
- (Sans, _, false) => 0x1D756,
- (Sans, _, true) => 0x1D790,
- (Cal | Frak | Mono | Bb, _, _) => return c,
- },
-
- // Greek lower.
- 'α'..='ω' => match tuple {
- (Serif, false, false) => 0x03B1,
- (Serif, true, false) => 0x1D6C2,
- (Serif, false, true) => 0x1D6FC,
- (Serif, true, true) => 0x1D736,
- (Sans, _, false) => 0x1D770,
- (Sans, _, true) => 0x1D7AA,
- (Cal | Frak | Mono | Bb, _, _) => return c,
- },
-
- // Hebrew Alef -> Dalet.
- '\u{05D0}'..='\u{05D3}' => 0x2135,
-
- // Numbers.
- '0'..='9' => match tuple {
- (Serif, false, _) => 0x0030,
- (Serif, true, _) => 0x1D7CE,
- (Bb, _, _) => 0x1D7D8,
- (Sans, false, _) => 0x1D7E2,
- (Sans, true, _) => 0x1D7EC,
- (Mono, _, _) => 0x1D7F6,
- (Cal | Frak, _, _) => return c,
- },
-
- _ => unreachable!(),
- };
-
- std::char::from_u32(start + (c as u32 - base as u32)).unwrap()
-}
-
-fn basic_exception(c: char) -> Option<char> {
- Some(match c {
- '〈' => '⟨',
- '〉' => '⟩',
- '《' => '⟪',
- '》' => '⟫',
- _ => return None,
- })
-}
-
-fn latin_exception(
- c: char,
- variant: MathVariant,
- bold: bool,
- italic: bool,
-) -> Option<char> {
- use MathVariant::*;
- Some(match (c, variant, bold, italic) {
- ('B', Cal, false, _) => 'ℬ',
- ('E', Cal, false, _) => 'ℰ',
- ('F', Cal, false, _) => 'ℱ',
- ('H', Cal, false, _) => 'ℋ',
- ('I', Cal, false, _) => 'ℐ',
- ('L', Cal, false, _) => 'ℒ',
- ('M', Cal, false, _) => 'ℳ',
- ('R', Cal, false, _) => 'ℛ',
- ('C', Frak, false, _) => 'ℭ',
- ('H', Frak, false, _) => 'ℌ',
- ('I', Frak, false, _) => 'ℑ',
- ('R', Frak, false, _) => 'ℜ',
- ('Z', Frak, false, _) => 'ℨ',
- ('C', Bb, ..) => 'ℂ',
- ('H', Bb, ..) => 'ℍ',
- ('N', Bb, ..) => 'ℕ',
- ('P', Bb, ..) => 'ℙ',
- ('Q', Bb, ..) => 'ℚ',
- ('R', Bb, ..) => 'ℝ',
- ('Z', Bb, ..) => 'ℤ',
- ('D', Bb, _, true) => 'ⅅ',
- ('d', Bb, _, true) => 'ⅆ',
- ('e', Bb, _, true) => 'ⅇ',
- ('i', Bb, _, true) => 'ⅈ',
- ('j', Bb, _, true) => 'ⅉ',
- ('h', Serif, false, true) => 'ℎ',
- ('e', Cal, false, _) => 'ℯ',
- ('g', Cal, false, _) => 'ℊ',
- ('o', Cal, false, _) => 'ℴ',
- ('ħ', Serif, .., true) => 'ℏ',
- ('ı', Serif, .., true) => '𝚤',
- ('ȷ', Serif, .., true) => '𝚥',
- _ => return None,
- })
-}
-
-fn greek_exception(
- c: char,
- variant: MathVariant,
- bold: bool,
- italic: bool,
-) -> Option<char> {
- use MathVariant::*;
- if c == 'Ϝ' && variant == Serif && bold {
- return Some('𝟊');
- }
- if c == 'ϝ' && variant == Serif && bold {
- return Some('𝟋');
- }
-
- let list = match c {
- 'ϴ' => ['𝚹', '𝛳', '𝜭', '𝝧', '𝞡', 'ϴ'],
- '∇' => ['𝛁', '𝛻', '𝜵', '𝝯', '𝞩', '∇'],
- '∂' => ['𝛛', '𝜕', '𝝏', '𝞉', '𝟃', '∂'],
- 'ϵ' => ['𝛜', '𝜖', '𝝐', '𝞊', '𝟄', 'ϵ'],
- 'ϑ' => ['𝛝', '𝜗', '𝝑', '𝞋', '𝟅', 'ϑ'],
- 'ϰ' => ['𝛞', '𝜘', '𝝒', '𝞌', '𝟆', 'ϰ'],
- 'ϕ' => ['𝛟', '𝜙', '𝝓', '𝞍', '𝟇', 'ϕ'],
- 'ϱ' => ['𝛠', '𝜚', '𝝔', '𝞎', '𝟈', 'ϱ'],
- 'ϖ' => ['𝛡', '𝜛', '𝝕', '𝞏', '𝟉', 'ϖ'],
- 'Γ' => ['𝚪', '𝛤', '𝜞', '𝝘', '𝞒', 'ℾ'],
- 'γ' => ['𝛄', '𝛾', '𝜸', '𝝲', '𝞬', 'ℽ'],
- 'Π' => ['𝚷', '𝛱', '𝜫', '𝝥', '𝞟', 'ℿ'],
- 'π' => ['𝛑', '𝜋', '𝝅', '𝝿', '𝞹', 'ℼ'],
- '∑' => ['∑', '∑', '∑', '∑', '∑', '⅀'],
- _ => return None,
- };
-
- Some(match (variant, bold, italic) {
- (Serif, true, false) => list[0],
- (Serif, false, true) => list[1],
- (Serif, true, true) => list[2],
- (Sans, _, false) => list[3],
- (Sans, _, true) => list[4],
- (Bb, ..) => list[5],
- _ => return None,
- })
-}
-
/// The non-dotless version of a dotless character that can be used with the
/// `dtls` OpenType feature.
pub fn try_dotless(c: char) -> Option<char> {
diff --git a/crates/typst-library/src/math/equation.rs b/crates/typst-library/src/math/equation.rs
index 0c9ba11d..a2ae5447 100644
--- a/crates/typst-library/src/math/equation.rs
+++ b/crates/typst-library/src/math/equation.rs
@@ -1,5 +1,6 @@
use std::num::NonZeroUsize;
+use codex::styling::MathVariant;
use typst_utils::NonZeroExt;
use unicode_math_class::MathClass;
@@ -12,7 +13,7 @@ use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
use crate::layout::{
AlignElem, Alignment, BlockElem, OuterHAlignment, SpecificAlignment, VAlignment,
};
-use crate::math::{MathSize, MathVariant};
+use crate::math::MathSize;
use crate::model::{Numbering, Outlinable, ParLine, Refable, Supplement};
use crate::text::{FontFamily, FontList, FontWeight, LocalName, TextElem};
@@ -111,7 +112,7 @@ pub struct EquationElem {
/// The style variant to select.
#[internal]
#[ghost]
- pub variant: MathVariant,
+ pub variant: Option<MathVariant>,
/// Affects the height of exponents.
#[internal]
@@ -128,7 +129,7 @@ pub struct EquationElem {
/// Whether to use italic glyphs.
#[internal]
#[ghost]
- pub italic: Smart<bool>,
+ pub italic: Option<bool>,
/// A forced class to use for all fragment.
#[internal]
diff --git a/crates/typst-library/src/math/mod.rs b/crates/typst-library/src/math/mod.rs
index 2e6d42b1..3d39e2fd 100644
--- a/crates/typst-library/src/math/mod.rs
+++ b/crates/typst-library/src/math/mod.rs
@@ -80,6 +80,7 @@ pub fn module() -> Module {
math.define_func::<italic>();
math.define_func::<serif>();
math.define_func::<sans>();
+ math.define_func::<scr>();
math.define_func::<cal>();
math.define_func::<frak>();
math.define_func::<mono>();
diff --git a/crates/typst-library/src/math/style.rs b/crates/typst-library/src/math/style.rs
index 53242e6e..6a85fd12 100644
--- a/crates/typst-library/src/math/style.rs
+++ b/crates/typst-library/src/math/style.rs
@@ -1,4 +1,6 @@
-use crate::foundations::{func, Cast, Content, Smart};
+use codex::styling::MathVariant;
+
+use crate::foundations::{func, Cast, Content};
use crate::math::EquationElem;
/// Bold font style in math.
@@ -24,7 +26,7 @@ pub fn upright(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::italic, Smart::Custom(false))
+ body.set(EquationElem::italic, Some(false))
}
/// Italic font style in math.
@@ -35,7 +37,7 @@ pub fn italic(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::italic, Smart::Custom(true))
+ body.set(EquationElem::italic, Some(true))
}
/// Serif (roman) font style in math.
@@ -46,7 +48,7 @@ pub fn serif(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::variant, MathVariant::Serif)
+ body.set(EquationElem::variant, Some(MathVariant::Plain))
}
/// Sans-serif font style in math.
@@ -59,23 +61,39 @@ pub fn sans(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::variant, MathVariant::Sans)
+ body.set(EquationElem::variant, Some(MathVariant::SansSerif))
}
-/// Calligraphic font style in math.
+/// Calligraphic (chancery) font style in math.
///
/// ```example
/// Let $cal(P)$ be the set of ...
/// ```
///
-/// This corresponds both to LaTeX's `\mathcal` and `\mathscr` as both of these
-/// styles share the same Unicode codepoints. Switching between the styles is
-/// thus only possible if supported by the font via
-/// [font features]($text.features).
+/// This is the default calligraphic/script style for most math fonts. See
+/// [`scr`]($math.scr) for more on how to get the other style (roundhand).
+#[func(title = "Calligraphic", keywords = ["mathcal", "chancery"])]
+pub fn cal(
+ /// The content to style.
+ body: Content,
+) -> Content {
+ body.set(EquationElem::variant, Some(MathVariant::Chancery))
+}
+
+/// Script (roundhand) font style in math.
+///
+/// ```example
+/// $ scr(S) $
+/// ```
+///
+/// There are two ways that fonts can support differentiating `cal` and `scr`.
+/// The first is using Unicode variation sequences. This works out of the box
+/// in Typst, however only a few math fonts currently support this.
///
-/// For the default math font, the roundhand style is available through the
-/// `ss01` feature. Therefore, you could define your own version of `\mathscr`
-/// like this:
+/// The other way is using [font features]($text.features). For example, the
+/// roundhand style might be available in a font through the `ss01` feature.
+/// To use it in Typst, you could then define your own version of `scr` like
+/// this:
///
/// ```example
/// #let scr(it) = text(
@@ -88,12 +106,12 @@ pub fn sans(
///
/// (The box is not conceptually necessary, but unfortunately currently needed
/// due to limitations in Typst's text style handling in math.)
-#[func(title = "Calligraphic", keywords = ["mathcal", "mathscr"])]
-pub fn cal(
+#[func(title = "Script Style", keywords = ["mathscr", "roundhand"])]
+pub fn scr(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::variant, MathVariant::Cal)
+ body.set(EquationElem::variant, Some(MathVariant::Roundhand))
}
/// Fraktur font style in math.
@@ -106,7 +124,7 @@ pub fn frak(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::variant, MathVariant::Frak)
+ body.set(EquationElem::variant, Some(MathVariant::Fraktur))
}
/// Monospace font style in math.
@@ -119,7 +137,7 @@ pub fn mono(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::variant, MathVariant::Mono)
+ body.set(EquationElem::variant, Some(MathVariant::Monospace))
}
/// Blackboard bold (double-struck) font style in math.
@@ -137,7 +155,7 @@ pub fn bb(
/// The content to style.
body: Content,
) -> Content {
- body.set(EquationElem::variant, MathVariant::Bb)
+ body.set(EquationElem::variant, Some(MathVariant::DoubleStruck))
}
/// Forced display style in math.
@@ -240,15 +258,3 @@ pub enum MathSize {
/// Math on its own line.
Display,
}
-
-/// A mathematical style variant, as defined by Unicode.
-#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Cast, Hash)]
-pub enum MathVariant {
- #[default]
- Serif,
- Sans,
- Cal,
- Frak,
- Mono,
- Bb,
-}
diff --git a/docs/reference/groups.yml b/docs/reference/groups.yml
index 1aaa8f22..b187443e 100644
--- a/docs/reference/groups.yml
+++ b/docs/reference/groups.yml
@@ -5,7 +5,7 @@
title: Variants
category: math
path: ["math"]
- filter: ["serif", "sans", "frak", "mono", "bb", "cal"]
+ filter: ["serif", "sans", "frak", "mono", "bb", "cal", "scr"]
details: |
Alternate typefaces within formulas.
diff --git a/tests/ref/math-style-fallback.png b/tests/ref/math-style-fallback.png
new file mode 100644
index 00000000..de028376
--- /dev/null
+++ b/tests/ref/math-style-fallback.png
Binary files differ
diff --git a/tests/ref/math-style-hebrew-exceptions.png b/tests/ref/math-style-hebrew-exceptions.png
index 723466e8..a6f511e0 100644
--- a/tests/ref/math-style-hebrew-exceptions.png
+++ b/tests/ref/math-style-hebrew-exceptions.png
Binary files differ
diff --git a/tests/ref/math-style-script.png b/tests/ref/math-style-script.png
new file mode 100644
index 00000000..379d270e
--- /dev/null
+++ b/tests/ref/math-style-script.png
Binary files differ
diff --git a/tests/suite/math/style.typ b/tests/suite/math/style.typ
index 1fa2695e..3ecf856b 100644
--- a/tests/suite/math/style.typ
+++ b/tests/suite/math/style.typ
@@ -12,6 +12,15 @@ $A, italic(A), upright(A), bold(A), bold(upright(A)), \
bb("hello") + bold(cal("world")), \
mono("SQRT")(x) wreath mono(123 + 456)$
+--- math-style-fallback ---
+// Test how math styles fallback.
+$upright(frak(bold(alpha))) = upright(bold(alpha)) \
+bold(mono(ϝ)) = bold(ϝ) \
+sans(Theta) = bold(sans(Theta)) \
+bold(upright(planck)) != planck \
+bb(e) != italic(bb(e)) \
+serif(sans(A)) != serif(A)$
+
--- math-style-dotless ---
// Test styling dotless i and j.
$ dotless.i dotless.j,
@@ -21,7 +30,7 @@ $ dotless.i dotless.j,
bb(dotless.i) bb(dotless.j),
cal(dotless.i) cal(dotless.j),
frak(dotless.i) frak(dotless.j),
- mono(dotless.i) mono(dotless.j),
+ mono(dotless.i) mono(dotless.j),
bold(frak(dotless.i)) upright(sans(dotless.j)),
italic(bb(dotless.i)) frak(sans(dotless.j)) $
@@ -38,7 +47,15 @@ $bb(Gamma) , bb(gamma), bb(Pi), bb(pi), bb(sum)$
--- math-style-hebrew-exceptions ---
// Test hebrew exceptions.
-$aleph, beth, gimel, daleth$
+$aleph, beth, gimel, daleth$ \
+$upright(aleph), upright(beth), upright(gimel), upright(daleth)$
+
+--- math-style-script ---
+// Test variation selectors for scr and cal.
+$cal(A) scr(A) bold(cal(O)) scr(bold(O))$
+
+#show math.equation: set text(font: "Noto Sans Math")
+$scr(E) cal(E) bold(scr(Y)) cal(bold(Y))$
--- issue-3650-italic-equation ---
_abc $sin(x) "abc"$_ \