Skip to content

[v4.1.1] Font commands not respected when using Unicode characters #3536

@myca-rrhiza

Description

@myca-rrhiza

LLM Use Disclaimer

The bug was discovered after using Github Copilot through VSCode to replace Obsidian's v3 MathJax instance with v4. The following summary was written by Copilot as well.

Issue Summary

Font-switching commands (\symup, \mathrm, \mathup, etc.) fail to apply the correct mathvariant to Greek letters in two related scenarios:

  1. lcGreek handler ignores env.font entirely\symup{\alpha}, \mathrm{\alpha}, etc. never produce upright lowercase Greek, regardless of mathStyle. The handler unconditionally applies mathStyle() without checking whether a font command has set env.font. This affects all mathStyle configurations.

  2. hl Unicode handler overwrites env.font with mathStyle — When a literal Unicode Greek character is used inside a font command (e.g. \symup{Π}), the Unicode fallback handler computes the mathStyle variant after env.font has been set and overwrites the mathvariant attribute. For uppercase Greek, this manifests only with mathStyle: 'ISO' (the only style where uppercase Greek is italic). For lowercase Greek, it compounds with bug 1.

The ucGreek handler (used by TeX commands like \Pi) is the only handler that correctly prioritises env.font over mathStyle. The variable handler (used by Latin letters) also works correctly.

Steps to Reproduce

  1. Configure MathJax with tex: { mathStyle: 'ISO' }
  2. Render the following expressions and compare output glyphs:
Input Expected Actual Handler
\symup{\Pi} Upright Π (U+03A0) ✓ Upright (U+03A0) ucGreek
\symup{Π} (Unicode) Upright Π (U+03A0) ✗ Italic 𝛱 (U+1D6F1) hl — bug 2
\mathrm{Π} (Unicode) Upright Π (U+03A0) ✗ Italic 𝛱 (U+1D6F1) hl — bug 2
\symup{\alpha} Upright α (U+03B1) ✗ Italic 𝛼 (U+1D6FC) lcGreek — bug 1
\mathrm{\alpha} Upright α (U+03B1) ✗ Italic 𝛼 (U+1D6FC) lcGreek — bug 1
\symup{α} (Unicode) Upright α (U+03B1) ✗ Italic 𝛼 (U+1D6FC) hl — bugs 1+2
\symup{x} Upright x (U+0078) ✓ Upright (U+0078) variable
\symup{X} Upright X (U+0058) ✓ Upright (U+0058) variable

Bug 1 (lcGreek) reproduces with all mathStyle values. Bug 2 (hl) reproduces with mathStyle: 'ISO' for uppercase Greek; for lowercase Greek and Latin, the effect depends on whether mathStyle returns a non-NORMAL variant.

Root Cause

Bug 1 — lcGreek ignores env.font:

// lcGreek — never checks env.font
lcGreek(t, e) {
  const s = { mathvariant: t.configuration.mathStyle(e.char) || ITALIC };
  // ...
}

// Compare ucGreek — correctly checks env.font first
ucGreek(t, e) {
  const s = { mathvariant: t.stack.env.font || t.configuration.mathStyle(e.char, true) || NORMAL };
  // ...
}

Fix: lcGreek should check t.stack.env.font before falling back to mathStyle, matching ucGreek.

Bug 2 — hl (Unicode fallback handler) overwrites env.font:

function hl(t, e) {
  const s = t.stack.env.font;                      // e.g. "normal" from \symup
  const i = s ? { mathvariant: s } : {};           // correctly sets mathvariant="normal"
  const c = t.create("token", a, i, ...);          // token created with "normal"
  
  const l = isLatinOrGreekChar(e)
    ? t.configuration.mathStyle(e, true) || r
    : "";                                           // l = "italic" (ISO uppercase Greek)
  const h = o[4] || (s && l === NORMAL ? "" : l);   // h = "italic" (since l ≠ NORMAL)
  h && c.attributes.set("mathvariant", h);          // OVERWRITES "normal" → "italic"
}

Fix: hl should skip the mathStyle override when env.font is already set.

Technical Details

  • MathJax Version: 4.1.1
  • Client OS: Windows 11
  • Browser: Electron (Chromium-based, Obsidian desktop app)

I am using the following MathJax configuration:

MathJax = {
  tex: {
    packages: ['base', 'ams', 'newcommand', 'configmacros', 'noundefined', 'textmacros'],
    mathStyle: 'ISO',
  },
  startup: {
    typeset: false,
  },
};

and loading a custom-built tex-chtml component (all TeX extensions pre-bundled via components/bin/makeAll).

Supporting Information

Verification via tex2chtml() in the console:

// Bug 1: lcGreek ignores env.font — all mathStyle values
MathJax.tex2chtml('\\symup{\\alpha}').querySelector('mjx-c').className
// → "mjx-c1D6FC"  (U+1D6FC = italic 𝛼)  ✗ expected "mjx-c3B1" (U+03B1 = upright α)

// Bug 2: hl overwrites env.font — mathStyle: 'ISO' only (for uppercase Greek)
MathJax.tex2chtml('\\symup{Π}').querySelector('mjx-c').className
// → "mjx-c1D6F1"  (U+1D6F1 = italic 𝛱)  ✗ expected "mjx-c3A0" (U+03A0 = upright Π)

// Working: ucGreek handler correctly respects env.font
MathJax.tex2chtml('\\symup{\\Pi}').querySelector('mjx-c').className
// → "mjx-c3A0"  (U+03A0 = upright Π)  ✓

// Working: variable handler correctly respects env.font (Latin)
MathJax.tex2chtml('\\symup{x}').querySelector('mjx-c').className
// → "mjx-c78"  (U+0078 = upright x)  ✓

Metadata

Metadata

Assignees

No one assigned

    Labels

    AcceptedIssue has been reproduced by MathJax teamCode ExampleContains an illustrative code example, solution, or work-aroundv4

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions