Fix math spacing, delimiters, radicals, and script fractions#156
Fix math spacing, delimiters, radicals, and script fractions#156AshtonSBradley wants to merge 11 commits into
Conversation
|
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 Report❌ Patch coverage is
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. 🚀 New features to boost your workflow:
|
|
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. |
Kolaru
left a comment
There was a problem hiding this comment.
Thanks a lot @AshtonSBradley, this is fantastic!
Overall, things looks good to me, and I could even follow you change to the monster parser.
I have to admit that for the layouting part, I haven't necessarily looked deep into the formula, but I trust your reference sheet and the reference tests regarding position tweaks :)
I still don't fully understand why the script level needs to be tracked, I feel like that shrinking everything down should do the trick, but well... it doesn't.
Regarding the reference tests, it is expected to fail since you are fixing some of them.
I inspected them, and I think that there are only few regressions:
- Subscripts
Was it a conscious choice to align the sub and superscript for cases like V^1_2 and U_{ij}? LaTeX is definitely closer to the current version.
Also x_{y \leftarrow 0} subscript is aligned too low. I assume that it may be related to the fact that you changed both subscripts and spaced symbol logic.
- Square root
The \sqrt{\frac{1}{2}} looks really cramped. However, I think that this one can be fixed later, comparing with MathJax, it seems like already on master the alignment is off. So I'm fine with having both fixed at a later point.
| @@ -1,5 +1,5 @@ | |||
| _latex_to_new_computer_modern = Dict( | |||
| raw"\int" => 5930, | |||
| raw"\int" => 878, | |||
There was a problem hiding this comment.
I hope nobody will complain about this change.
I agree with the change, considering that the proper way to handle it would be to differentiate inline mode (math part of a line) and equation mode (where the full string is a single equation). However, this is outside the scope of the current PR.
| export @L_str | ||
|
|
||
| const _italic_correction_enabled = Ref(true) | ||
| const _unspace_binary_operators_heuristic_enabled = Ref(true) |
There was a problem hiding this comment.
I would remove the leading _: as far as I understand, it only makes sense to have them have Ref if they are intended to be modified by user, so I wouldn't mark them as private.
Still we should not export them, as they are advanced settings.
|
Thanks again for the detailed pass. I pushed an update addressing each point:
Updated visual artifacts:
Local checks pass:
|
|
Pushed a follow-up that makes subscript placement more generally slant-aware. The subscript rule is now based on the core glyph, not the subscript character class:
This removes the previous special case that pushed lower-case Greek subscripts outward just because the subscript itself was Greek. The tests now cover Updated artifacts: Local checks pass:
|
|
@Kolaru i think I have addressed all of your comments, I hope this is converging. |
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:
f(t),g(x),(f)x, andη(t).LayoutState.script_level, allowing script-style fractions and operator spacing to be tuned separately from top-level math.x^{\frac{1}{1+2}}andx_{\frac{1}{1+2}}.\langle,\rangle, vertical bars, and integrals.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.Subscript and superscript anchors are now deliberately asymmetric. Subscripts are driven by the core glyph: slanted cores use the advance-width anchor so subscripts can tuck under italic lean, while upright/non-slanted cores use
max(hadvance(core), rightinkbound(core))to avoid ink collisions. Superscripts continue to usemax(hadvance(core), rightinkbound(core)), preserving the desiredV^1_2stagger where the subscript tucks inward but the superscript stays farther out. This also removes the old lower-case-Greek-subscript special case, soN_\nuandJ_\nuare handled the same way as other subscripts on slanted capital cores.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. Adjacent slanted glyphs also get a small ink-gap correction, covering cramped cases such as
k\xiwithout adding a broad operator-space rule.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. Delimiter sizing uses the visible contents to avoid over-scaling brackets and bars around a lone display operator, which allows the NewComputerModern long integral glyph to be restored without bringing back the oversized-delimiter artifact. The latest delimiter pass computes a visual axis from non-operator, non-delimiter content so simple and nested brackets sit on the apparent expression midline; rule-containing delimiters are scaled around the chosen axis, with a small brace-specific cap to avoid over-growing
{α/β}solely because of the beta descender.Fraction rules are positioned from combined numerator/denominator ink bounds. This fixes the offset vinculum in reference fractions and keeps shortened script-fraction rules centered over the actual script contents. The latest update also lengthens top-level fraction rules slightly and gives square-root vincula a small right padding so
\sqrt{2}and\sqrt{\frac{1}{2}}do not look clipped or left-centered.The parser change is small:
manual_texexprnow treats delimiter and punctuation tuple heads as leaves, matchingisleaf. 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
The updated reference sheets are also linked as generated artifacts on the same artifact branch:
subsuper.png,square_roots.png,fractions.png,delimiters.png,symbols.png,integrals.png.Tests
julia --project=/Users/braas09p/Dropbox/Julia/Dev/MathTeXEngine.jl test/runtests.jljulia --project=@runic -m Runic --check src/engine/layout.jl test/layout.jl reference/spacing_visuals.jlpassed.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.