diff --git a/Cargo.lock b/Cargo.lock index 87ce0d3f0..5406776f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,7 +413,7 @@ dependencies = [ [[package]] name = "codex" version = "0.1.1" -source = "git+https://github.com/mkorje/codex?rev=f02fa4a#f02fa4a04f2a9937f043892ee865dd06628264ba" +source = "git+https://github.com/typst/codex?rev=9ac86f9#9ac86f96af5b89fce555e6bba8b6d1ac7b44ef00" [[package]] name = "color-print" diff --git a/Cargo.toml b/Cargo.toml index c2a58421d..272eed1aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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/mkorje/codex", rev = "f02fa4a" } +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/src/math/text.rs b/crates/typst-layout/src/math/text.rs index d13251e61..ad42119ee 100644 --- a/crates/typst-layout/src/math/text.rs +++ b/crates/typst-layout/src/math/text.rs @@ -65,12 +65,21 @@ fn layout_inline_text( ctx: &mut MathContext, styles: StyleChain, ) -> SourceResult { + let variant = EquationElem::variant_in(styles); + let bold = EquationElem::bold_in(styles); + // Disable auto-italic. + let italic = EquationElem::italic_in(styles).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()); } @@ -84,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); @@ -125,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 = EquationElem::variant_in(styles); + let bold = EquationElem::bold_in(styles); + let italic = EquationElem::italic_in(styles); + + 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() @@ -135,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); @@ -162,38 +179,6 @@ fn adjust_glyph_layout( } } -/// Style the character by selecting the Unicode codepoint for italic, bold, -/// caligraphic, etc. -fn styled_char(styles: StyleChain, c: char, auto_italic: bool) -> char { - if let Some(c) = basic_exception(c) { - return c; - } - - let variant = EquationElem::variant_in(styles); - let bold = EquationElem::bold_in(styles); - let italic = - EquationElem::italic_in(styles).or_else(|| (!auto_italic).then_some(false)); - let style = MathStyle::select(c, variant, bold, italic); - - // At the moment we are only using styles that output a single character, - // so we just grab the first character in the ToStyle iterator. - to_style(c, style).next().unwrap() -} - -fn basic_exception(c: char) -> Option { - Some(match c { - '〈' => '⟨', - '〉' => '⟩', - '《' => '⟪', - '》' => '⟫', - 'א' => 'ℵ', - 'ב' => 'ℶ', - 'ג' => 'ℷ', - 'ד' => 'ℸ', - _ => 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 { diff --git a/crates/typst-library/src/math/mod.rs b/crates/typst-library/src/math/mod.rs index 2e6d42b13..3d39e2fd2 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::(); math.define_func::(); math.define_func::(); + math.define_func::(); math.define_func::(); math.define_func::(); math.define_func::(); diff --git a/crates/typst-library/src/math/style.rs b/crates/typst-library/src/math/style.rs index 9d54d7de3..dd2c243c6 100644 --- a/crates/typst-library/src/math/style.rs +++ b/crates/typst-library/src/math/style.rs @@ -64,20 +64,34 @@ pub fn sans( body.styled(EquationElem::set_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 +/// 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.styled(EquationElem::set_variant(Some(MathVariant::Chancery))) +} + +/// Script (roundhand) font style in math. +/// +/// ```example +/// $ scr(S) $ +/// ``` +/// +/// Very few math fonts currently support differentiating `cal` and `scr`. Some +/// fonts support switching between the styles via /// [font features]($text.features). /// -/// 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: +/// Say, for example, the roundhand style is available through the `ss01` +/// feature. Then, you could define your own version of `\mathscr` like this: /// /// ```example /// #let scr(it) = text( @@ -90,12 +104,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", keywords = ["mathscr", "roundhand"])] +pub fn scr( /// The content to style. body: Content, ) -> Content { - body.styled(EquationElem::set_variant(Some(MathVariant::Script))) + body.styled(EquationElem::set_variant(Some(MathVariant::Roundhand))) } /// Fraktur font style in math. diff --git a/docs/reference/groups.yml b/docs/reference/groups.yml index e01d99dc4..a4dccc071 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-hebrew-exceptions.png b/tests/ref/math-style-hebrew-exceptions.png index 723466e8a..a6f511e0e 100644 Binary files a/tests/ref/math-style-hebrew-exceptions.png and b/tests/ref/math-style-hebrew-exceptions.png differ diff --git a/tests/suite/math/style.typ b/tests/suite/math/style.typ index daf6c0cd6..2f7d8799e 100644 --- a/tests/suite/math/style.typ +++ b/tests/suite/math/style.typ @@ -47,7 +47,8 @@ $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)$ --- issue-3650-italic-equation --- _abc $sin(x) "abc"$_ \