Skip to content

Fix math spacing, delimiters, radicals, and script fractions#156

Open
AshtonSBradley wants to merge 3 commits intoKolaru:masterfrom
AshtonSBradley:align-fixes
Open

Fix math spacing, delimiters, radicals, and script fractions#156
AshtonSBradley wants to merge 3 commits intoKolaru:masterfrom
AshtonSBradley:align-fixes

Conversation

@AshtonSBradley
Copy link
Copy Markdown

@AshtonSBradley AshtonSBradley commented May 7, 2026

Fix math spacing, delimiters, radicals, and script fractions

Summary

This PR improves several related math layout regressions that show up in labels, scripts, and multi-font rendering:

  • Fixes italic/upright boundary spacing such as f(t), g(x), (f)x, and η(t).
  • Treats lower-case Greek math symbols as slanted for spacing decisions, so Greek/script combinations do not crowd roman delimiters or subscripts.
  • Tracks script nesting with LayoutState.script_level, allowing script-style fractions and operator spacing to be tuned separately from top-level math.
  • Improves subscript and superscript placement around tall cores such as \left(...\right)_0 and \left(...\right)^{1/4}.
  • Shortens and recenters fraction rules in scripts, especially cases such as x^{\frac{1}{1+2}} and x_{\frac{1}{1+2}}.
  • Selects usable square-root variants and adds top clearance for empty, ordinary, and tall radicals.
  • Uses default math glyphs for delimiters and missing math symbols across font families, including \langle, \rangle, vertical bars, and integrals.
  • Uses the normal NewComputerModern inline integral glyph instead of the display-sized glyph for \int.
  • Adds regression tests and an optional visual comparison sheet for multi-font inspection.

Closes #9.
Closes #95.
Closes #129.
Closes #142.

Explanation

The main layout change is to carry script depth in LayoutState. Decorated expressions now lay out their lower and upper scripts in an incremented script state, which lets nested fractions and spaced operators use script-style rules without changing top-level layout. Tall cores use ink bounds to place scripts relative to the visible shape, reducing the over-high subscripts and over-low superscripts around scaled delimiters.

Italic/upright spacing still uses glyph ink bounds rather than only advance widths. Lower-case Greek symbols are marked as slanted for layout purposes, including symbols loaded through a font family's special-character path, so Greek letters participate in the same boundary correction as italic Latin letters.

Delimiter and radical rendering now falls back to the default math font when the selected font lacks a usable math glyph or has text-shaped delimiter glyphs. This keeps \langle...\rangle, vertical bars, square roots, and integrals visible and consistent across NewComputerModern, TeXGyreHeros, TeXGyrePagella, and LucioleMath. The NewComputerModern \int mapping is corrected to use the normal inline integral, avoiding accidental delimiter over-scaling around a display-sized integral.

The parser change is small: manual_texexpr now treats delimiter and punctuation tuple heads as leaves, matching isleaf. That keeps layout code from needing to normalize parser/test helper artifacts.

Visual Regression

This PR uses an extensive visual regression sheet as part of the debugging workflow, not just as a final artifact. MathTeX layout bugs are often coupled: fixing a subscript can shift tall delimiters, changing a missing glyph fallback can expose radical or fraction placement issues, and behavior can differ substantially across font families. A broad visual sheet made it possible to inspect many representative expressions at once, catch second-order regressions quickly, and iterate on the small numerical layout constants with the same before/after context each time.

The generated multi-font visual regression sheet compares this branch against a clean baseline worktree. Blue marks the current branch, red marks the baseline. The cases intentionally cover issue-specific examples plus neighboring stress cases: italic/upright boundaries, lower-case Greek, nested scripts, primes, roman text, operators, delimiters, fractions, radicals, integrals, and nested expressions across NewComputerModern, TeXGyreHeros, TeXGyrePagella, and LucioleMath.

Open the full-size visual regression PNG

Spacing visual regression sheet

Tests

  • julia --project=/Users/braas09p/Dropbox/Julia/Dev/MathTeXEngine.jl -e 'using Pkg; Pkg.test()'
  • Local result: all package tests passed.
  • Observed test summaries: TeXExpr 1 pass, Parser 128 pass, Fonts 5 pass, Layout 115 pass, Generate elements 4 pass.
  • julia --project=@runic -e 'using Runic; foreach(file -> Runic.format_file(file; inplace = true), files)' was run on the touched Julia files, then formatter-only churn outside the PR changes was trimmed back.
  • Generated the optional visual spacing sheet comparing the current checkout against a clean baseline worktree.

Notes

This does not attempt a full OpenType MATH-table implementation. The visual sheet includes related cases from #93, #105, #110, #126, and PR #151 so they can be inspected, but this PR should not claim to fully close all of those issues.

This partially overlaps #61 by improving unary/operator spacing, but #61 also discusses superscript vertical placement, so I would not close it from this PR alone.

No new dependencies are added.
No public exports are added.

@AshtonSBradley AshtonSBradley changed the title Fix math spacing around italic boundaries, Greek scripts, and operators Fix math spacing, delimiters, radicals, and script fractions May 8, 2026
@AshtonSBradley
Copy link
Copy Markdown
Author

Hi @Kolaru

This tests quite a lot of corner cases (coverage inspired by other font packages) and took quite a lot of manual iteration loops to converge on the current visual regression state where all fonts look pretty consistent and not obviously broken. Quite a few things were just broken for some fonts, or used weird glyphs. I also went to a fair bit of effort to make this a compact change to code.

I hope it is useful to close a bunch of issues all at once.

@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 93.93939% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.91%. Comparing base (efdbaab) to head (d03417e).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
src/engine/layout.jl 97.03% 4 Missing ⚠️
src/engine/layout_context.jl 63.63% 4 Missing ⚠️
src/engine/fonts.jl 50.00% 1 Missing ⚠️
src/engine/texelements.jl 96.00% 1 Missing ⚠️
src/parser/parser.jl 95.45% 1 Missing ⚠️
src/parser/texexpr.jl 50.00% 1 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #156      +/-   ##
==========================================
+ Coverage   79.93%   82.91%   +2.97%     
==========================================
  Files          10       10              
  Lines         658      796     +138     
==========================================
+ Hits          526      660     +134     
- Misses        132      136       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AshtonSBradley
Copy link
Copy Markdown
Author

AshtonSBradley commented May 9, 2026

Looks like the main change in the ReferenceTests is the integral symbol become smaller. A minor shift in space between top of characters and bottom of square root vinculum. The rest look either unchanged or a little better to my eye.

Expansion of the package ReferenceTest to improve coverage could also be a useful direction, but I didn't go there in this PR yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Italic text and conjugate alignment Math operator missing space lower case greek spacing inconsistent Cursive / normal text boundaries

2 participants