@@ -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
954981class 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
9791010class 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
10001035class STIXSansFontConstants (STIXFontConstants ):
@@ -1004,7 +1039,7 @@ class STIXSansFontConstants(STIXFontConstants):
10041039
10051040
10061041class 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
10231061class 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+
10761120class 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
0 commit comments