Skip to content

Commit d4bace4

Browse files
authored
Merge pull request matplotlib#31110 from QuLogic/space-axisheight-metrics
mathtext: Fetch quad width & axis height from font metrics
2 parents dfe4e55 + 383028b commit d4bace4

2 files changed

Lines changed: 62 additions & 21 deletions

File tree

lib/matplotlib/_mathtext.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,12 @@ def get_axis_height(self, font: str, fontsize: float, dpi: float) -> float:
312312
"""
313313
raise NotImplementedError()
314314

315+
def get_quad(self, font: str, fontsize: float, dpi: float) -> float:
316+
"""
317+
Get the size of a quad for the given *font* and *fontsize*.
318+
"""
319+
raise NotImplementedError()
320+
315321
def get_xheight(self, font: str, fontsize: float, dpi: float) -> float:
316322
"""
317323
Get the xheight for the given *font* and *fontsize*.
@@ -414,11 +420,25 @@ def _get_info(self, fontname: str, font_class: str, sym: str, fontsize: float,
414420
)
415421

416422
def get_axis_height(self, fontname: str, fontsize: float, dpi: float) -> float:
417-
# The fraction line (if present) must be aligned with the minus sign. Therefore,
418-
# the height of the latter from the baseline is the axis height.
419-
metrics = self.get_metrics(
420-
fontname, mpl.rcParams['mathtext.default'], '\u2212', fontsize, dpi)
421-
return (metrics.ymax + metrics.ymin) / 2
423+
consts = _get_font_constants(self, fontname)
424+
if consts.axis_height is not None:
425+
return consts.axis_height * fontsize * dpi / 72
426+
else:
427+
# The fraction line (if present) must be aligned with the minus sign.
428+
# Therefore, the height of the latter from the baseline is the axis height.
429+
metrics = self.get_metrics(
430+
fontname, mpl.rcParams['mathtext.default'], '\u2212', fontsize, dpi)
431+
return (metrics.ymax + metrics.ymin) / 2
432+
433+
def get_quad(self, fontname: str, fontsize: float, dpi: float) -> float:
434+
consts = _get_font_constants(self, fontname)
435+
if consts.quad is not None:
436+
return consts.quad * fontsize * dpi / 72
437+
else:
438+
# With no other option, we measure the size of an 'm'.
439+
metrics = self.get_metrics(
440+
fontname, mpl.rcParams['mathtext.default'], 'm', fontsize, dpi)
441+
return metrics.advance
422442

423443
def get_xheight(self, fontname: str, fontsize: float, dpi: float) -> float:
424444
# Some fonts report the wrong x-height, while some don't store it, so
@@ -950,6 +970,13 @@ class FontConstantsBase:
950970
# and scriptscript styles.
951971
denom2: T.ClassVar[float] = 1.1
952972

973+
# The height of a horizontal reference line used for positioning elements in a
974+
# formula, similar to a baseline, as a multiple of design size.
975+
axis_height: T.ClassVar[float | None] = None
976+
977+
# The size of a quad space in LaTeX, as a multiple of design size.
978+
quad: T.ClassVar[float | None] = None
979+
953980

954981
class ComputerModernFontConstants(FontConstantsBase):
955982
# Previously, the x-height of Computer Modern was obtained from the font
@@ -974,14 +1001,18 @@ class ComputerModernFontConstants(FontConstantsBase):
9741001
num3 = 465286 / _x_height
9751002
denom1 = 719272 / _x_height
9761003
denom2 = 361592 / _x_height
1004+
# These come from the cmsy10.tfm metrics, scaled so they are in multiples of design
1005+
# size.
1006+
axis_height = 262144 / 2**20
1007+
quad = 1048579 / 2**20
9771008

9781009

9791010
class STIXFontConstants(FontConstantsBase):
9801011
script_space = 0.1
9811012
delta = 0.05
9821013
delta_slanted = 0.3
9831014
delta_integral = 0.3
984-
# These values are extracted from the TeX table of STIXGeneral.ttf using FreeType,
1015+
# These values are extracted from the TeX table of STIXGeneral.ttf using FontForge,
9851016
# and then divided by design xheight, since we multiply these values by the scaled
9861017
# xheight later.
9871018
_x_height = 450
@@ -995,6 +1026,10 @@ class STIXFontConstants(FontConstantsBase):
9951026
num3 = 474 / _x_height
9961027
denom1 = 756 / _x_height
9971028
denom2 = 375 / _x_height
1029+
# These come from the same TeX table, scaled by Em size so they are in multiples of
1030+
# design size.
1031+
axis_height = 250 / 1000
1032+
quad = 1000 / 1000
9981033

9991034

10001035
class STIXSansFontConstants(STIXFontConstants):
@@ -1004,7 +1039,7 @@ class STIXSansFontConstants(STIXFontConstants):
10041039

10051040

10061041
class DejaVuSerifFontConstants(FontConstantsBase):
1007-
# These values are extracted from the TeX table of DejaVuSerif.ttf using FreeType,
1042+
# These values are extracted from the TeX table of DejaVuSerif.ttf using FontForge,
10081043
# and then divided by design xheight, since we multiply these values by the scaled
10091044
# xheight later.
10101045
_x_height = 1063
@@ -1018,10 +1053,13 @@ class DejaVuSerifFontConstants(FontConstantsBase):
10181053
num3 = 970.752 / _x_height
10191054
denom1 = 1548.29 / _x_height
10201055
denom2 = 768 / _x_height
1056+
# These come from the same TeX table, scaled by Em size so they are in multiples of
1057+
# design size.
1058+
axis_height = 512 / 2048
10211059

10221060

10231061
class DejaVuSansFontConstants(FontConstantsBase):
1024-
# These values are extracted from the TeX table of DejaVuSans.ttf using FreeType,
1062+
# These values are extracted from the TeX table of DejaVuSans.ttf using FontForge,
10251063
# and then divided by design xheight, since we multiply these values by the scaled
10261064
# xheight later.
10271065
_x_height = 1120
@@ -1035,6 +1073,9 @@ class DejaVuSansFontConstants(FontConstantsBase):
10351073
num3 = 970.752 / _x_height
10361074
denom1 = 1548.29 / _x_height
10371075
denom2 = 768 / _x_height
1076+
# These come from the same TeX table, scaled by Em size so they are in multiples of
1077+
# design size.
1078+
axis_height = 512 / 2048
10381079

10391080

10401081
# Maps font family names to the FontConstantBase subclass to use
@@ -1062,17 +1103,20 @@ class DejaVuSansFontConstants(FontConstantsBase):
10621103
}
10631104

10641105

1065-
def _get_font_constant_set(state: ParserState) -> type[FontConstantsBase]:
1066-
constants = _font_constant_mapping.get(
1067-
state.fontset._get_font(state.font).family_name, FontConstantsBase)
1106+
def _get_font_constants(fontset: Fonts, font: str) -> type[FontConstantsBase]:
1107+
constants = _font_constant_mapping.get(fontset._get_font(font).family_name,
1108+
FontConstantsBase)
10681109
# STIX sans isn't really its own fonts, just different code points
10691110
# in the STIX fonts, so we have to detect this one separately.
1070-
if (constants is STIXFontConstants and
1071-
isinstance(state.fontset, StixSansFonts)):
1111+
if constants is STIXFontConstants and isinstance(fontset, StixSansFonts):
10721112
return STIXSansFontConstants
10731113
return constants
10741114

10751115

1116+
def _get_font_constant_set(state: ParserState) -> type[FontConstantsBase]:
1117+
return _get_font_constants(state.fontset, state.font)
1118+
1119+
10761120
class Node:
10771121
"""A node in the TeX box model."""
10781122

@@ -2306,10 +2350,7 @@ def _make_space(self, percentage: float) -> Kern:
23062350
key = (state.font, state.fontsize, state.dpi)
23072351
width = self._em_width_cache.get(key)
23082352
if width is None:
2309-
metrics = state.fontset.get_metrics(
2310-
'it', mpl.rcParams['mathtext.default'], 'm',
2311-
state.fontsize, state.dpi)
2312-
width = metrics.advance
2353+
width = state.fontset.get_quad('it', state.fontsize, state.dpi)
23132354
self._em_width_cache[key] = width
23142355
return Kern(width * percentage)
23152356

lib/matplotlib/tests/test_mathtext.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -577,12 +577,12 @@ def test_box_repr():
577577
_mathtext.DejaVuSansFonts(fm.FontProperties(), LoadFlags.NO_HINTING),
578578
fontsize=12, dpi=100))
579579
assert s == textwrap.dedent("""\
580-
Hlist<w=9.51 h=15.30 d=5.00 s=0.00>[
580+
Hlist<w=9.51 h=14.24 d=6.06 s=0.00>[
581581
Hlist<w=0.00 h=0.00 d=0.00 s=0.00>[],
582-
Hlist<w=9.51 h=15.30 d=5.00 s=0.00>[
583-
Hlist<w=9.51 h=15.30 d=5.00 s=0.00>[
582+
Hlist<w=9.51 h=14.24 d=6.06 s=0.00>[
583+
Hlist<w=9.51 h=14.24 d=6.06 s=0.00>[
584584
Hbox,
585-
Vlist<w=7.43 h=20.30 d=0.00 s=5.00>[
585+
Vlist<w=7.43 h=20.30 d=0.00 s=6.06>[
586586
HCentered<w=7.43 h=8.51 d=0.00 s=0.00>[
587587
Glue,
588588
Hlist<w=7.43 h=8.51 d=0.00 s=0.00>[

0 commit comments

Comments
 (0)