X Tutup
Skip to content

Font and text overhaul#30161

Draft
QuLogic wants to merge 138 commits intomatplotlib:mainfrom
QuLogic:text-overhaul-figures
Draft

Font and text overhaul#30161
QuLogic wants to merge 138 commits intomatplotlib:mainfrom
QuLogic:text-overhaul-figures

Conversation

@QuLogic
Copy link
Member

@QuLogic QuLogic commented Jun 10, 2025

PR summary

This PR is intended to hold all font and text PRs from the project Font and text overhaul

In order to not overwhelm the main repo with the churn of test image replacements, this PR comes from my fork and should only ever have 1 commit more than the text-overhaul branch with the changes to test images.

PR checklist

QuLogic added 4 commits June 12, 2025 18:46
Glyph indices are specific to each font. It does not make sense to fall
back based on glyph index to another font.

This could only really be populated by calling `FT2Font.set_text`, but
even that was fragile. If a fallback font was used for a character with
the same glyph index as a previous character in the main font, then
these lookups could be overwritten to the fallback instead of the main
font, with a completely different character!

Fortunately, nothing actually uses or requires a fallback through glyph
indices.
Remove ttconv backwards-compatibility code
@QuLogic
Copy link
Member Author

QuLogic commented Jun 19, 2025

Also, if you would like to follow along with the figure changes, I've posted a branch that does the changes per merge commit: https://github.com/QuLogic/matplotlib/tree/text-overhaul-figures-per-commit

QuLogic added 8 commits July 7, 2025 19:06
This allows checking that there are no _new_ failures, without
committing the new figures to the repo until the branch is complete.
ci: Preload existing test images from text-overhaul-figures branch
Also, check some expected conditions at parse time instead of somewhere
during use of the data.
ci: Fix image preload with multiple conflicts
@QuLogic QuLogic force-pushed the text-overhaul-figures branch from 2b3f5c5 to b17bef1 Compare July 10, 2025 04:06
QuLogic and others added 4 commits February 6, 2026 17:26
Refactor RendererAgg.draw_{mathtext,text,tex} to use same base algorithm
As described in *TeX: the Program* by Don Knuth.

New font constants are set to the nearest integral multiples of 0.1 for
which numerators and denominators containing normal text do not have to
be shifted beyond their default shift amounts at font size 30 in display
and text styles. To better process superscripts and subscripts, the
x-height is now always calculated instead of being retrieved from the
font table (which was the case for Computer Modern); the affected font
constants have been changed.

A duplicate test was also fixed in the process.
At the call site
https://github.com/matplotlib/matplotlib/blob/51fbfc4eb0e882ef7e95ceab9777c7047f4db819/lib/matplotlib/_mathtext.py#L1706-L1709
the box should clearly go from `cur_v + off_v` to `cur_v + off_v -
rule_height` (this is why `cur_v` is shifted by `+ rule_height` just
before; also at that point some print debugging indicates that y's go
*downwards*), so `Rule.render` should indeed call `render_rect_filled`
from `y - h` to `y`.
Computer Modern values are taken from `cmsy10.tfm`, and divided by the
x-height in that output to match the scale used in Matplotlib.

DejaVu Sans/Serif and STIX constants are taken from the embedded TeX
table extracted with FontForge.
@QuLogic QuLogic force-pushed the text-overhaul-figures branch from 99f4957 to 517a403 Compare February 6, 2026 23:53
…cal-align

Implement TeX's fraction and script alignment
QuLogic and others added 3 commits February 17, 2026 13:58
The text height includes both the ascender and the descender, but the
logic in _get_layout is that multiline texts should be treated as having
an ascent at least as large as "l" and a descent at least as large as
"p" (not a height at least as large as "lp" and a descent at least as
large as "p") to prevent lines from bumping into each other (see changes
to test_text/test_multiline, where the topmost superscript was close to
bumping into the "p" descender previously).
Fix confusion between text height and ascent in metrics calculations.
@sanrishi
Copy link

Hi @QuLogic,

I've been testing this overhaul branch locally, specifically checking how it handles complex text shaping (like Hindi/Devanagari vowel placement) compared to main. The rendering looks stable so far.

I understand this is the tracking PR for v3.11. I saw in the developer notes that fraction bar placement/snapping might still be an open discussion. Is that something that needs investigation, or are there other unassigned blockers on the project board that I could pick up to help clear the path for review?

QuLogic and others added 16 commits February 24, 2026 09:33
In order to preserve existing image, explicitly set the fontsize to the
old setting, which is easier to read anyway.
This mostly has a minimal change to results as the axis height is fairly
closely aligned with the minus sign as previously implemented.
These are mostly wider than the previous calculation of the 'm' width.
The values are invalid in the DejaVu fonts (-2048), so those still use
the old method.
…rics

mathtext: Fetch quad width & axis height from font metrics
Replace lookup table for font constants based on the family name
by methods in their respective classes.

Removes non-local call of private _get_font method in
_get_font_constant_set.

This simplifies implementing dynamically loaded font constants.
To replicate LaTeX behaviour, distinguish between "italic" and "normal"
math. In particular, digits should be set italic in the \mathit env.

For `cm`, use cmti font for "it"
For general UnicodeFont (stix, DejaVu, ...), maps digits to roman or
italic alphabet, depending on "normal" or "it" environment.
Ensure that \mathnormal is parsed and sets digits upright.
* Cache text rotation Affine2D

Fix tests

* Direct array creation

More robust BBox creation

* Speed up min/max calcs

* Fast path for unrotated text

* Faster FontProperties copy

* Faster array operations

* Faster shape check

* Code review updates

* More robust FontProperties hashing / copying

* Skip redundant wrapped text context manager

* Code review updates

* Restore stub __copy__

* Text consolidate rotation code path

* Prefer np.vstack().T to np.column_stack() for speed

Revert "Prefer np.vstack().T to np.column_stack() for speed"

This reverts commit 2e32436.

Simplify column stack

* Code review updates

* Cleanup

---------

Co-authored-by: Scott Shambaugh <scottshambaugh@users.noreply.github.com>
Apparently, when adding the additional fields in matplotlib#31050, I never noticed
that some of the required fields were not exposed.

Also, fix a few typos in the field names.
Consider a multiline Text object with nonzero rotation.
Text._get_layout performs the layouting of the individual lines.
Previously, it would return (among other things) the axes-aligned bbox
of the whole Text (which can be much bigger than the rotated bbox),
as well as the metrics of each individual line. mpl.text._get_layout
would then take these individual metrics and unrotate their positions
(to horizontal lines) to compute the size of the *rotated* bbox of the
text (and its position as well); this is used solely when drawing a
(text-aligned) bbox around the text (`plt.text(..., bbox=...)`).

The back-and-forth rotation seems a bit complicated; one can instead
simply return the relevant info in Text._get_layout as well: the rotated
bbox size is already available (in the variable previously named
`corners_horiz`), and getting its position is also simple.  Do that,
and get rid of mpl.text._get_textbox (and also adjust the callers of
Text._get_layout accordingly).  Also add some additional drive-by
reformatting of Text._get_layout.
ft2font: Read more entries from OS/2 font table
mathtext: add mathnormal and distinguish between normal and italic family
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Waiting for other PR

Development

Successfully merging this pull request may close these issues.

8 participants

X Tutup