diff --git a/doc/api/next_api_changes/development/30143-ES.rst b/doc/api/next_api_changes/development/30143-ES.rst new file mode 100644 index 000000000000..2d79ad6bbe9d --- /dev/null +++ b/doc/api/next_api_changes/development/30143-ES.rst @@ -0,0 +1,7 @@ +Glyph indices now typed distinctly from character codes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, character codes and glyph indices were both typed as `int`, which means you +could mix and match them erroneously. While the character code can't be made a distinct +type (because it's used for `chr`/`ord`), typing glyph indices as a distinct type means +these can't be fully swapped. diff --git a/lib/matplotlib/_afm.py b/lib/matplotlib/_afm.py index 352d3c42247e..3d7f7a44baca 100644 --- a/lib/matplotlib/_afm.py +++ b/lib/matplotlib/_afm.py @@ -30,9 +30,10 @@ import inspect import logging import re -from typing import BinaryIO, NamedTuple, TypedDict +from typing import BinaryIO, NamedTuple, TypedDict, cast from ._mathtext_data import uni2type1 +from .ft2font import CharacterCodeType, GlyphIndexType _log = logging.getLogger(__name__) @@ -197,7 +198,7 @@ class CharMetrics(NamedTuple): The bbox of the character (B) as a tuple (*llx*, *lly*, *urx*, *ury*).""" -def _parse_char_metrics(fh: BinaryIO) -> tuple[dict[int, CharMetrics], +def _parse_char_metrics(fh: BinaryIO) -> tuple[dict[CharacterCodeType, CharMetrics], dict[str, CharMetrics]]: """ Parse the given filehandle for character metrics information. @@ -218,7 +219,7 @@ def _parse_char_metrics(fh: BinaryIO) -> tuple[dict[int, CharMetrics], """ required_keys = {'C', 'WX', 'N', 'B'} - ascii_d: dict[int, CharMetrics] = {} + ascii_d: dict[CharacterCodeType, CharMetrics] = {} name_d: dict[str, CharMetrics] = {} for bline in fh: # We are defensively letting values be utf8. The spec requires @@ -409,19 +410,21 @@ def get_str_bbox_and_descent(self, s: str) -> tuple[int, int, float, int, int]: return left, miny, total_width, maxy - miny, -miny - def get_glyph_name(self, glyph_ind: int) -> str: # For consistency with FT2Font. + def get_glyph_name(self, # For consistency with FT2Font. + glyph_ind: GlyphIndexType) -> str: """Get the name of the glyph, i.e., ord(';') is 'semicolon'.""" - return self._metrics[glyph_ind].name + return self._metrics[cast(CharacterCodeType, glyph_ind)].name - def get_char_index(self, c: int) -> int: # For consistency with FT2Font. + def get_char_index(self, # For consistency with FT2Font. + c: CharacterCodeType) -> GlyphIndexType: """ Return the glyph index corresponding to a character code point. Note, for AFM fonts, we treat the glyph index the same as the codepoint. """ - return c + return cast(GlyphIndexType, c) - def get_width_char(self, c: int) -> float: + def get_width_char(self, c: CharacterCodeType) -> float: """Get the width of the character code from the character metric WX field.""" return self._metrics[c].width diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 19ddbb6d0883..78f8913cd65a 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -37,7 +37,8 @@ if T.TYPE_CHECKING: from collections.abc import Iterable - from .ft2font import Glyph + from .ft2font import CharacterCodeType, Glyph + ParserElement.enable_packrat() _log = logging.getLogger("matplotlib.mathtext") @@ -47,7 +48,7 @@ # FONTS -def get_unicode_index(symbol: str) -> int: # Publicly exported. +def get_unicode_index(symbol: str) -> CharacterCodeType: # Publicly exported. r""" Return the integer index (from the Unicode table) of *symbol*. @@ -85,7 +86,7 @@ class VectorParse(NamedTuple): width: float height: float depth: float - glyphs: list[tuple[FT2Font, float, int, float, float]] + glyphs: list[tuple[FT2Font, float, CharacterCodeType, float, float]] rects: list[tuple[float, float, float, float]] VectorParse.__module__ = "matplotlib.mathtext" @@ -212,7 +213,7 @@ class FontInfo(NamedTuple): fontsize: float postscript_name: str metrics: FontMetrics - num: int + num: CharacterCodeType glyph: Glyph offset: float @@ -365,7 +366,7 @@ def _get_offset(self, font: FT2Font, glyph: Glyph, fontsize: float, return 0. def _get_glyph(self, fontname: str, font_class: str, - sym: str) -> tuple[FT2Font, int, bool]: + sym: str) -> tuple[FT2Font, CharacterCodeType, bool]: raise NotImplementedError # The return value of _get_info is cached per-instance. @@ -425,7 +426,9 @@ def get_kern(self, font1: str, fontclass1: str, sym1: str, fontsize1: float, info1 = self._get_info(font1, fontclass1, sym1, fontsize1, dpi) info2 = self._get_info(font2, fontclass2, sym2, fontsize2, dpi) font = info1.font - return font.get_kerning(info1.num, info2.num, Kerning.DEFAULT) / 64 + return font.get_kerning(font.get_char_index(info1.num), + font.get_char_index(info2.num), + Kerning.DEFAULT) / 64 return super().get_kern(font1, fontclass1, sym1, fontsize1, font2, fontclass2, sym2, fontsize2, dpi) @@ -459,7 +462,7 @@ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlag _slanted_symbols = set(r"\int \oint".split()) def _get_glyph(self, fontname: str, font_class: str, - sym: str) -> tuple[FT2Font, int, bool]: + sym: str) -> tuple[FT2Font, CharacterCodeType, bool]: font = None if fontname in self.fontmap and sym in latex_to_bakoma: basename, num = latex_to_bakoma[sym] @@ -551,7 +554,7 @@ class UnicodeFonts(TruetypeFonts): # Some glyphs are not present in the `cmr10` font, and must be brought in # from `cmsy10`. Map the Unicode indices of those glyphs to the indices at # which they are found in `cmsy10`. - _cmr10_substitutions = { + _cmr10_substitutions: dict[CharacterCodeType, CharacterCodeType] = { 0x00D7: 0x00A3, # Multiplication sign. 0x2212: 0x00A1, # Minus sign. } @@ -594,11 +597,11 @@ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlag _slanted_symbols = set(r"\int \oint".split()) def _map_virtual_font(self, fontname: str, font_class: str, - uniindex: int) -> tuple[str, int]: + uniindex: CharacterCodeType) -> tuple[str, CharacterCodeType]: return fontname, uniindex def _get_glyph(self, fontname: str, font_class: str, - sym: str) -> tuple[FT2Font, int, bool]: + sym: str) -> tuple[FT2Font, CharacterCodeType, bool]: try: uniindex = get_unicode_index(sym) found_symbol = True @@ -607,8 +610,7 @@ def _get_glyph(self, fontname: str, font_class: str, found_symbol = False _log.warning("No TeX to Unicode mapping for %a.", sym) - fontname, uniindex = self._map_virtual_font( - fontname, font_class, uniindex) + fontname, uniindex = self._map_virtual_font(fontname, font_class, uniindex) new_fontname = fontname @@ -693,7 +695,7 @@ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlag self.fontmap[name] = fullpath def _get_glyph(self, fontname: str, font_class: str, - sym: str) -> tuple[FT2Font, int, bool]: + sym: str) -> tuple[FT2Font, CharacterCodeType, bool]: # Override prime symbol to use Bakoma. if sym == r'\prime': return self.bakoma._get_glyph(fontname, font_class, sym) @@ -783,7 +785,7 @@ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlag self.fontmap[name] = fullpath def _map_virtual_font(self, fontname: str, font_class: str, - uniindex: int) -> tuple[str, int]: + uniindex: CharacterCodeType) -> tuple[str, CharacterCodeType]: # Handle these "fonts" that are actually embedded in # other fonts. font_mapping = stix_virtual_fonts.get(fontname) @@ -1170,7 +1172,7 @@ def __init__(self, elements: T.Sequence[Node]): self.glue_sign = 0 # 0: normal, -1: shrinking, 1: stretching self.glue_order = 0 # The order of infinity (0 - 3) for the glue - def __repr__(self): + def __repr__(self) -> str: return "{}[{}]".format( super().__repr__(), self.width, self.height, diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py index 5819ee743044..0451791e9f26 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -3,9 +3,12 @@ """ from __future__ import annotations -from typing import overload +from typing import TypeAlias, overload -latex_to_bakoma = { +from .ft2font import CharacterCodeType + + +latex_to_bakoma: dict[str, tuple[str, CharacterCodeType]] = { '\\__sqrt__' : ('cmex10', 0x70), '\\bigcap' : ('cmex10', 0x5c), '\\bigcup' : ('cmex10', 0x5b), @@ -241,7 +244,7 @@ # Automatically generated. -type12uni = { +type12uni: dict[str, CharacterCodeType] = { 'aring' : 229, 'quotedblright' : 8221, 'V' : 86, @@ -475,7 +478,7 @@ # for key in sd: # print("{0:24} : {1: dict[str, float]: ... @property - def index(self) -> int: ... # type: ignore[override] + def index(self) -> GlyphIndexType: ... # type: ignore[override] @property - def glyph_name_or_index(self) -> int | str: ... + def glyph_name_or_index(self) -> GlyphIndexType | str: ... class Dvi: file: io.BufferedReader diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 5257893b380a..a4ddc84358c1 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -1,6 +1,6 @@ from enum import Enum, Flag import sys -from typing import BinaryIO, Literal, TypedDict, final, overload, cast +from typing import BinaryIO, Literal, NewType, TypeAlias, TypedDict, cast, final, overload from typing_extensions import Buffer # < Py 3.12 import numpy as np @@ -9,6 +9,12 @@ from numpy.typing import NDArray __freetype_build_type__: str __freetype_version__: str +# We can't change the type hints for standard library chr/ord, so character codes are a +# simple type alias. +CharacterCodeType: TypeAlias = int +# But glyph indices are internal, so use a distinct type hint. +GlyphIndexType = NewType('GlyphIndexType', int) + class FaceFlags(Flag): SCALABLE = cast(int, ...) FIXED_SIZES = cast(int, ...) @@ -202,13 +208,13 @@ class FT2Font(Buffer): ) -> None: ... def draw_glyphs_to_bitmap(self, antialiased: bool = ...) -> None: ... def get_bitmap_offset(self) -> tuple[int, int]: ... - def get_char_index(self, codepoint: int) -> int: ... - def get_charmap(self) -> dict[int, int]: ... + def get_char_index(self, codepoint: CharacterCodeType) -> GlyphIndexType: ... + def get_charmap(self) -> dict[CharacterCodeType, GlyphIndexType]: ... def get_descent(self) -> int: ... - def get_glyph_name(self, index: int) -> str: ... + def get_glyph_name(self, index: GlyphIndexType) -> str: ... def get_image(self) -> NDArray[np.uint8]: ... - def get_kerning(self, left: int, right: int, mode: Kerning) -> int: ... - def get_name_index(self, name: str) -> int: ... + def get_kerning(self, left: GlyphIndexType, right: GlyphIndexType, mode: Kerning) -> int: ... + def get_name_index(self, name: str) -> GlyphIndexType: ... def get_num_glyphs(self) -> int: ... def get_path(self) -> tuple[NDArray[np.float64], NDArray[np.int8]]: ... def get_ps_font_info( @@ -230,8 +236,8 @@ class FT2Font(Buffer): @overload def get_sfnt_table(self, name: Literal["pclt"]) -> _SfntPcltDict | None: ... def get_width_height(self) -> tuple[int, int]: ... - def load_char(self, charcode: int, flags: LoadFlags = ...) -> Glyph: ... - def load_glyph(self, glyphindex: int, flags: LoadFlags = ...) -> Glyph: ... + def load_char(self, charcode: CharacterCodeType, flags: LoadFlags = ...) -> Glyph: ... + def load_glyph(self, glyphindex: GlyphIndexType, flags: LoadFlags = ...) -> Glyph: ... def select_charmap(self, i: int) -> None: ... def set_charmap(self, i: int) -> None: ... def set_size(self, ptsize: float, dpi: float) -> None: ... diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg index 6967f80a1186..a7195c665c14 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:36.846948 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,721 +26,752 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png index 0317cb99e1c0..c2076843da4a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg index 9d57faac5f18..09dd81f56563 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:33.031781 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,297 +26,317 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - + - - - + - + - - + - - - - + - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg index 90f9b2cec969..b6236288603d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:40.551077 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,437 +26,467 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.png index d6802f84bfda..5a615d92e166 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg index 77ded780c3f1..4d7fdcc30954 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:40.658346 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,268 +26,288 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - + - - - + - - + - - + - - + - + - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg index 7a7b7ec42c25..e73b1c5e872b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:39.585869 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,190 +26,202 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - - + - - - + - - - + - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg index 0846b552246a..ca0439485b08 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:40.642097 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,115 +26,121 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - - - + - - - - - - +M 1381 2969 +Q 1594 3256 1914 3420 +Q 2234 3584 2584 3584 +Q 3122 3584 3439 3221 +Q 3756 2859 3756 2241 +Q 3756 1734 3570 1259 +Q 3384 784 3041 416 +Q 2816 172 2522 40 +Q 2228 -91 1906 -91 +Q 1566 -91 1316 65 +Q 1066 222 909 531 +L 806 0 +L 231 0 +L 1178 4863 +L 1753 4863 +L 1381 2969 +z +" transform="scale(0.015625)"/> + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg index 24db824fd37c..8287a2338258 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:40.896681 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,103 +26,109 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - - - + + - + - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg index 189491319c10..0bbef213526f 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:39.508765 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,209 +26,220 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - + + - + - - - + - - + - - - - - - - - - - - - - +M 1959 2075 +Q 2384 2075 2632 2365 +Q 2881 2656 2881 3163 +Q 2881 3666 2632 3958 +Q 2384 4250 1959 4250 +Q 1534 4250 1286 3958 +Q 1038 3666 1038 3163 +Q 1038 2656 1286 2365 +Q 1534 2075 1959 2075 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg index e0721c9e47a4..3e7c6dc1c42c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:40.642033 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,493 +26,524 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.png index b405dd438309..c8bae48383aa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg index 13ec8213ff31..ced57fed3b2b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:40.725227 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,278 +26,298 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - + - - - + - + - + - - - + - - + - - - - - - - - - - - - - - - - - - - - - +M 3022 2063 +Q 3016 2534 2758 2815 +Q 2500 3097 2075 3097 +Q 1594 3097 1305 2825 +Q 1016 2553 972 2059 +L 3022 2063 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg index a4fb4be582a4..cd7dfc34183b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:42.172241 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,223 +26,234 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - + - + - - - + - - + - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg index 4623754e2963..045cc829e0cf 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:38.874726 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,531 +26,562 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png index 1923648b80a3..d0233a4ee7a0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg index bc6756feadc8..8184565aaf2a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:38.959357 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,284 +26,304 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - + - - - + - - + - - + - - - + - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg index d61317816ad6..c3dd8722b044 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:38.040182 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,435 +26,466 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png index a86119004e62..6f816c2ee723 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg index 4e129aa6c87d..50bdb38d37b1 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg @@ -1,12 +1,23 @@ - - + + + + + + 2025-07-24T15:42:38.119948 + image/svg+xml + + + Matplotlib v3.11.0.dev1119+gc6e6904896.d20250724, https://matplotlib.org/ + + + + + - + @@ -15,269 +26,289 @@ L 378 54 L 378 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> - - + + - + - - - + - + - - + - - - + - - + - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/test_ft2font.py b/lib/matplotlib/tests/test_ft2font.py index 5dd96ce9cafe..6b405287e5d7 100644 --- a/lib/matplotlib/tests/test_ft2font.py +++ b/lib/matplotlib/tests/test_ft2font.py @@ -1,6 +1,7 @@ import itertools import io from pathlib import Path +from typing import cast import numpy as np import pytest @@ -241,7 +242,7 @@ def enc(name): assert unic == after # This is just a random sample from FontForge. - glyph_names = { + glyph_names = cast(dict[str, ft2font.GlyphIndexType], { 'non-existent-glyph-name': 0, 'plusminus': 115, 'Racute': 278, @@ -253,7 +254,7 @@ def enc(name): 'uni2A02': 4464, 'u1D305': 5410, 'u1F0A1': 5784, - } + }) for name, index in glyph_names.items(): assert font.get_name_index(name) == index if name == 'non-existent-glyph-name': diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 5ba4bec36874..31202f018e42 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -1774,5 +1774,8 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) m.attr("__freetype_version__") = version_string; m.attr("__freetype_build_type__") = FREETYPE_BUILD_TYPE; + auto py_int = py::module_::import("builtins").attr("int"); + m.attr("CharacterCodeType") = py_int; + m.attr("GlyphIndexType") = py_int; m.def("__getattr__", ft2font__getattr__); }