From 10a67001a69b9fe41b9977e702e2b66cbb59ce96 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Mon, 2 Mar 2026 23:21:54 +0530 Subject: [PATCH] ft2font: Read more entries from OS/2 font table Apparently, when adding the additional fields in #31050, I never noticed that some of the required fields were not exposed. Also, fix a few typos in the field names. --- lib/matplotlib/ft2font.pyi | 13 +++++++++---- lib/matplotlib/tests/test_ft2font.py | 18 ++++++++++++------ src/ft2font_wrapper.cpp | 15 ++++++++++----- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 10be9e9e69a9..2be018c40d63 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -137,11 +137,16 @@ class _SfntOs2Dict(TypedDict): yStrikeoutPosition: int sFamilyClass: int panose: bytes - ulCharRange: tuple[int, int, int, int] + ulUnicodeRange: tuple[int, int, int, int] achVendID: bytes fsSelection: int - fsFirstCharIndex: int - fsLastCharIndex: int + usFirstCharIndex: int + usLastCharIndex: int + sTypoAscender: int + sTypoDescender: int + sTypoLineGap: int + usWinAscent: int + usWinDescent: int # version >= 1 ulCodePageRange: NotRequired[tuple[int, int]] # version >= 2 @@ -176,7 +181,7 @@ class _SfntVheaDict(TypedDict): vertTypoLineGap: int advanceHeightMax: int minTopSideBearing: int - minBottomSizeBearing: int + minBottomSideBearing: int yMaxExtent: int caretSlopeRise: int caretSlopeRun: int diff --git a/lib/matplotlib/tests/test_ft2font.py b/lib/matplotlib/tests/test_ft2font.py index 61312f57bb6f..a55d1051779b 100644 --- a/lib/matplotlib/tests/test_ft2font.py +++ b/lib/matplotlib/tests/test_ft2font.py @@ -587,9 +587,11 @@ def test_ft2font_get_sfnt(font_name, expected): 'yStrikeoutSize': 102, 'yStrikeoutPosition': 530, 'sFamilyClass': 0, 'panose': b'\x02\x0b\x06\x03\x03\x08\x04\x02\x02\x04', - 'ulCharRange': (3875565311, 3523280383, 170156073, 67117068), + 'ulUnicodeRange': (3875565311, 3523280383, 170156073, 67117068), 'achVendID': b'PfEd', - 'fsSelection': 64, 'fsFirstCharIndex': 32, 'fsLastCharIndex': 65535, + 'fsSelection': 64, 'usFirstCharIndex': 32, 'usLastCharIndex': 65535, + 'sTypoAscender': 1556, 'sTypoDescender': -492, 'sTypoLineGap': 410, + 'usWinAscent': 1901, 'usWinDescent': 483, 'ulCodePageRange': (1610613247, 3758030848), }, 'hhea': { @@ -654,9 +656,11 @@ def test_ft2font_get_sfnt(font_name, expected): 'yStrikeoutSize': 102, 'yStrikeoutPosition': 530, 'sFamilyClass': 0, 'panose': b'\x02\x0b\x05\x00\x00\x00\x00\x00\x00\x00', - 'ulCharRange': (0, 0, 0, 0), + 'ulUnicodeRange': (0, 0, 0, 0), 'achVendID': b'\x00\x00\x00\x00', - 'fsSelection': 64, 'fsFirstCharIndex': 32, 'fsLastCharIndex': 9835, + 'fsSelection': 64, 'usFirstCharIndex': 32, 'usLastCharIndex': 9835, + 'sTypoAscender': 1276, 'sTypoDescender': -469, 'sTypoLineGap': 0, + 'usWinAscent': 1430, 'usWinDescent': 477, }, 'hhea': { 'version': (1, 0), @@ -734,9 +738,11 @@ def test_ft2font_get_sfnt(font_name, expected): 'yStrikeoutSize': 20, 'yStrikeoutPosition': 1037, 'sFamilyClass': 0, 'panose': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - 'ulCharRange': (3, 192, 0, 0), + 'ulUnicodeRange': (3, 192, 0, 0), 'achVendID': b'STIX', - 'fsSelection': 32, 'fsFirstCharIndex': 32, 'fsLastCharIndex': 10217, + 'fsSelection': 32, 'usFirstCharIndex': 32, 'usLastCharIndex': 10217, + 'sTypoAscender': 750, 'sTypoDescender': -250, 'sTypoLineGap': 1499, + 'usWinAscent': 2095, 'usWinDescent': 404, 'ulCodePageRange': (2688417793, 2432565248), 'sxHeight': 0, 'sCapHeight': 0, diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 72aec2a437ab..bf345cd1d044 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -1282,12 +1282,17 @@ PyFT2Font_get_sfnt_table(PyFT2Font *self, std::string tagname) "yStrikeoutPosition"_a=t->yStrikeoutPosition, "sFamilyClass"_a=t->sFamilyClass, "panose"_a=py::bytes(reinterpret_cast(t->panose), 10), - "ulCharRange"_a=py::make_tuple(t->ulUnicodeRange1, t->ulUnicodeRange2, - t->ulUnicodeRange3, t->ulUnicodeRange4), + "ulUnicodeRange"_a=py::make_tuple(t->ulUnicodeRange1, t->ulUnicodeRange2, + t->ulUnicodeRange3, t->ulUnicodeRange4), "achVendID"_a=py::bytes(reinterpret_cast(t->achVendID), 4), "fsSelection"_a=t->fsSelection, - "fsFirstCharIndex"_a=t->usFirstCharIndex, - "fsLastCharIndex"_a=t->usLastCharIndex); + "usFirstCharIndex"_a=t->usFirstCharIndex, + "usLastCharIndex"_a=t->usLastCharIndex, + "sTypoAscender"_a=t->sTypoAscender, + "sTypoDescender"_a=t->sTypoDescender, + "sTypoLineGap"_a=t->sTypoLineGap, + "usWinAscent"_a=t->usWinAscent, + "usWinDescent"_a=t->usWinDescent); if (version >= 1) { result["ulCodePageRange"] = py::make_tuple(t->ulCodePageRange1, t->ulCodePageRange2); @@ -1333,7 +1338,7 @@ PyFT2Font_get_sfnt_table(PyFT2Font *self, std::string tagname) "vertTypoLineGap"_a=t->Line_Gap, "advanceHeightMax"_a=t->advance_Height_Max, "minTopSideBearing"_a=t->min_Top_Side_Bearing, - "minBottomSizeBearing"_a=t->min_Bottom_Side_Bearing, + "minBottomSideBearing"_a=t->min_Bottom_Side_Bearing, "yMaxExtent"_a=t->yMax_Extent, "caretSlopeRise"_a=t->caret_Slope_Rise, "caretSlopeRun"_a=t->caret_Slope_Run,