From a7cfac824aea80080ded585d4ad78177d622a355 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 17 Apr 2026 18:15:05 -0400 Subject: [PATCH] Drop support for font hinting factor In #9681 we decided that the hinting factor is not needed with modern font rendering engines, but we only set our defaults to 1. The classic style remained as 8, but our internal testing framework then reset that to 1 as well. Unfortunately, with the new pipeline, anything other than 1 is broken (cf. https://github.com/SciTools/cartopy/issues/2666), and we were just not seeing it because of the testing override. As we expect downstreams to have to update results for all the rest of the font changes, there's not much need to preserve this functionality. So like the kerning factor, deprecate the hinting factor setting/parameters, and drop all related code. --- .../deprecations/31521-ES.rst | 7 +++++ lib/matplotlib/__init__.py | 4 +-- lib/matplotlib/backends/backend_agg.py | 4 +-- lib/matplotlib/backends/backend_pdf.py | 2 +- lib/matplotlib/backends/backend_ps.py | 2 +- lib/matplotlib/dviread.py | 2 +- lib/matplotlib/font_manager.py | 15 ++++------ lib/matplotlib/font_manager.pyi | 1 - lib/matplotlib/ft2font.pyi | 1 - lib/matplotlib/mpl-data/matplotlibrc | 4 +-- .../stylelib/_classic_test_patch.mplstyle | 1 - lib/matplotlib/mpl-data/stylelib/bmh.mplstyle | 2 -- .../mpl-data/stylelib/classic.mplstyle | 3 -- lib/matplotlib/rcsetup.py | 10 +++---- lib/matplotlib/testing/__init__.py | 1 - lib/matplotlib/tests/test_font_manager.py | 20 ------------- lib/matplotlib/tests/test_ft2font.py | 24 ++++++++------- lib/matplotlib/tests/test_text.py | 14 --------- src/ft2font.cpp | 16 ++++------ src/ft2font.h | 8 +---- src/ft2font_wrapper.cpp | 30 ++++++++----------- 21 files changed, 57 insertions(+), 114 deletions(-) create mode 100644 doc/api/next_api_changes/deprecations/31521-ES.rst diff --git a/doc/api/next_api_changes/deprecations/31521-ES.rst b/doc/api/next_api_changes/deprecations/31521-ES.rst new file mode 100644 index 000000000000..fc04b69a50fd --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31521-ES.rst @@ -0,0 +1,7 @@ +Font hinting factor is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Due to internal changes to support complex text rendering, the hinting factor on fonts is +no longer used. Setting the ``text.hinting_factor`` rcParam to any value other than None +is deprecated, and the rcParam will be removed in the future. Likewise, passing the +``hinting_factor`` argument to the `.FT2Font` constructor is deprecated. diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 1ba5e9522436..2a83cc1f1091 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -779,8 +779,8 @@ def __setitem__(self, key, val): cval = valid_key(val) except ValueError as ve: raise ValueError(f"Key {key}: {ve}") from None - if key == "text.kerning_factor" and cval is not None: - _api.warn_deprecated("3.11", name="text.kerning_factor", obj_type="rcParam") + if key in {"text.hinting_factor", "text.kerning_factor"} and cval is not None: + _api.warn_deprecated("3.11", name=key, obj_type="rcParam") self._set(key, cval) def __getitem__(self, key): diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index f0006a2d7dbe..1f2b6a45a07e 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -179,11 +179,9 @@ def _draw_text_glyphs_and_boxes(self, gc, x, y, angle, glyphs, boxes): load_flags = get_hinting_flag() for font, size, glyph_index, slant, extend, dx, dy in glyphs: # dy is upwards. font.set_size(size, self.dpi) - hf = font._hinting_factor font._set_transform( (0x10000 * np.array([[cos, -sin], [sin, cos]]) - @ [[extend, extend * slant], [0, 1]] - @ [[1 / hf, 0], [0, 1]]).round().astype(int), + @ [[extend, extend * slant], [0, 1]]).round().astype(int), [round(0x40 * (x + dx * cos - dy * sin)), # FreeType's y is upwards. round(0x40 * (self.height - y + dx * sin + dy * cos))] diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 280a72d534ad..f429bd9c9e4a 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -597,7 +597,7 @@ def _flush(self): def _get_pdf_charprocs(font_path, glyph_indices): - font = get_font(font_path, hinting_factor=1) + font = get_font(font_path) conv = 1000 / font.units_per_EM # Conversion to PS units (1/1000's). procs = {} for glyph_index in glyph_indices: diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index f4d29ecfe347..266e80f9a742 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -107,7 +107,7 @@ def _font_to_ps_type3(font_path, subset_index, glyph_indices): The string representation of a Type 3 font, which can be included verbatim into a PostScript file. """ - font = get_font(font_path, hinting_factor=1) + font = get_font(font_path) preamble = """\ %!PS-Adobe-3.0 Resource-Font diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index dd5efdc85b34..e41618d67579 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -1026,7 +1026,7 @@ def get_metrics(self, idx): class TtfMetrics: def __init__(self, filename): - self._face = font_manager.get_font(filename, hinting_factor=1) + self._face = font_manager.get_font(filename) def get_metrics(self, idx): # _mul1220 uses a truncating bitshift for compatibility with dvitype. diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 2f2a258d568c..3146a484f0fe 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1731,11 +1731,11 @@ def is_opentype_cff_font(filename): @lru_cache(64) -def _get_font(font_filepaths, hinting_factor, *, _kerning_factor, thread_id, +def _get_font(font_filepaths, *, _kerning_factor, thread_id, enable_last_resort): (first_fontpath, first_fontindex), *rest = font_filepaths fallback_list = [ - ft2font.FT2Font(fpath, hinting_factor, face_index=index, + ft2font.FT2Font(fpath, face_index=index, _kerning_factor=_kerning_factor) for fpath, index in rest ] @@ -1749,12 +1749,12 @@ def _get_font(font_filepaths, hinting_factor, *, _kerning_factor, thread_id, # already in the list. if enable_last_resort: fallback_list.append( - ft2font.FT2Font(last_resort_path, hinting_factor, + ft2font.FT2Font(last_resort_path, _kerning_factor=_kerning_factor, _warn_if_used=True)) last_resort_index = len(fallback_list) font = ft2font.FT2Font( - first_fontpath, hinting_factor, face_index=first_fontindex, + first_fontpath, face_index=first_fontindex, _fallback_list=fallback_list, _kerning_factor=_kerning_factor ) @@ -1783,6 +1783,7 @@ def _cached_realpath(path): return os.path.realpath(path) +@_api.delete_parameter('3.11', 'hinting_factor') def get_font(font_filepaths, hinting_factor=None): """ Get an `.ft2font.FT2Font` object given a list of file paths. @@ -1816,20 +1817,16 @@ def get_font(font_filepaths, hinting_factor=None): if isinstance(fname, FontPath) else (_cached_realpath(fname), 0) for fname in font_filepaths) - hinting_factor = mpl._val_or_rc(hinting_factor, 'text.hinting_factor') - font = _get_font( # must be a tuple to be cached paths, - hinting_factor, _kerning_factor=mpl.rcParams['text.kerning_factor'], # also key on the thread ID to prevent segfaults with multi-threading thread_id=threading.get_ident(), enable_last_resort=mpl.rcParams['font.enable_last_resort'], ) # Ensure the transform is always consistent. - font._set_transform([[round(0x10000 / font._hinting_factor), 0], [0, 0x10000]], - [0, 0]) + font._set_transform([[0x10000, 0], [0, 0x10000]], [0, 0]) return font diff --git a/lib/matplotlib/font_manager.pyi b/lib/matplotlib/font_manager.pyi index faaa028635fd..b5c131d33702 100644 --- a/lib/matplotlib/font_manager.pyi +++ b/lib/matplotlib/font_manager.pyi @@ -142,7 +142,6 @@ class FontManager: def is_opentype_cff_font(filename: str) -> bool: ... def get_font( font_filepaths: Iterable[str | bytes | os.PathLike | FontPath] | str | bytes | os.PathLike | FontPath, - hinting_factor: int | None = ..., ) -> ft2font.FT2Font: ... fontManager: FontManager diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 3003f83932bc..05f987292ffc 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -236,7 +236,6 @@ class FT2Font(Buffer): def __init__( self, filename: str | bytes | PathLike | BinaryIO, - hinting_factor: int = ..., *, face_index: int = ..., _fallback_list: list[FT2Font] | None = ..., diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc index 67fd6c0d18be..3b8d222bb3a0 100644 --- a/lib/matplotlib/mpl-data/matplotlibrc +++ b/lib/matplotlib/mpl-data/matplotlibrc @@ -308,9 +308,7 @@ ## - no_hinting: Disable hinting. ("none" is a synonym.) #text.hinting: default -#text.hinting_factor: 1 # Specifies the amount of softness for hinting in the - # horizontal direction. A value of 1 will hint to full - # pixels. A value of 2 will hint to half pixels etc. +#text.hinting_factor: None # This setting does nothing and is deprecated. #text.kerning_factor: None # Specifies the scaling factor for kerning values. Values # other than 0, 6, or None have no defined meaning. # This setting is deprecated. diff --git a/lib/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle b/lib/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle index 3dc92f832b20..3dde19c0884b 100644 --- a/lib/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle @@ -6,4 +6,3 @@ ytick.alignment: center_baseline hatch.color: edge text.hinting: default -text.hinting_factor: 1 diff --git a/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle b/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle index 1b449cc09fbf..508445362f3a 100644 --- a/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle @@ -8,8 +8,6 @@ patch.facecolor: blue patch.edgecolor: eeeeee patch.antialiased: True -text.hinting_factor : 8 - mathtext.fontset : cm axes.facecolor: eeeeee diff --git a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle index 302a25ca29a9..43753c693fea 100644 --- a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle @@ -137,9 +137,6 @@ text.hinting : auto # May be one of the following: # or the autohinter if none is available. # For backward compatibility, this value may also be # True === 'auto' or False === 'none'. -text.hinting_factor : 8 # Specifies the amount of softness for hinting in the - # horizontal direction. A value of 1 will hint to full - # pixels. A value of 2 will hint to half pixels etc. text.antialiased : True # If True (default), the text will be antialiased. # This only affects the Agg backend. diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index eefbae5e68f5..f88f07c0e82d 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -1115,7 +1115,7 @@ def _convert_validator_spec(key, conv): "text.latex.preamble": validate_string, "text.hinting": ["default", "no_autohint", "force_autohint", "no_hinting", "auto", "native", "either", "none"], - "text.hinting_factor": validate_int, + "text.hinting_factor": validate_int_or_None, "text.kerning_factor": validate_int_or_None, "text.antialiased": validate_bool, "text.parse_math": validate_bool, @@ -1875,11 +1875,9 @@ class _Subsection: ), _Param( "text.hinting_factor", - default=1, - validator=validate_int, - description="Specifies the amount of softness for hinting in the horizontal " - "direction. A value of 1 will hint to full pixels. A value of 2 " - "will hint to half pixels etc." + default=None, + validator=validate_int_or_None, + description="[DEPRECATED] This setting has no effect." ), _Param( "text.kerning_factor", diff --git a/lib/matplotlib/testing/__init__.py b/lib/matplotlib/testing/__init__.py index 9de9785d2b5f..3c7cc76c5570 100644 --- a/lib/matplotlib/testing/__init__.py +++ b/lib/matplotlib/testing/__init__.py @@ -20,7 +20,6 @@ def set_font_settings_for_testing(): mpl.rcParams['font.family'] = 'DejaVu Sans' mpl.rcParams['text.hinting'] = 'default' - mpl.rcParams['text.hinting_factor'] = 1 def set_reproducibility_for_testing(): diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index 6ba9f338f6d7..73571298de4f 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -8,7 +8,6 @@ import sys import warnings -import numpy as np import pytest from unittest.mock import MagicMock, patch @@ -118,25 +117,6 @@ def test_get_fontconfig_fonts(): assert len(_get_fontconfig_fonts()) > 1 -@pytest.mark.parametrize('factor', [2, 4, 6, 8]) -def test_hinting_factor(factor): - font = findfont(FontProperties(family=["sans-serif"])) - - font1 = get_font(font, hinting_factor=1) - font1.clear() - font1.set_size(12, 100) - font1.set_text('abc') - expected = font1.get_width_height() - - hinted_font = get_font(font, hinting_factor=factor) - hinted_font.clear() - hinted_font.set_size(12, 100) - hinted_font.set_text('abc') - # Check that hinting only changes text layout by a small (10%) amount. - np.testing.assert_allclose(hinted_font.get_width_height(), expected, - rtol=0.1) - - def test_utf16m_sfnt(): try: # seguisbi = Microsoft Segoe UI Semibold diff --git a/lib/matplotlib/tests/test_ft2font.py b/lib/matplotlib/tests/test_ft2font.py index 8b44792a0c2d..b96505197890 100644 --- a/lib/matplotlib/tests/test_ft2font.py +++ b/lib/matplotlib/tests/test_ft2font.py @@ -179,7 +179,11 @@ def test_ft2font_invalid_args(tmp_path): # hinting_factor argument. with pytest.raises(TypeError, match='incompatible constructor arguments'): ft2font.FT2Font(file, 1.3) - with pytest.raises(ValueError, match='hinting_factor must be greater than 0'): + with pytest.warns(mpl.MatplotlibDeprecationWarning, + match='text.hinting_factor rcParam was deprecated .+ 3.11'): + mpl.rcParams['text.hinting_factor'] = 8 + with pytest.warns(mpl.MatplotlibDeprecationWarning, + match='The hinting_factor parameter was deprecated'): ft2font.FT2Font(file, 0) with pytest.raises(TypeError, match='incompatible constructor arguments'): @@ -236,7 +240,7 @@ def test_ft2font_clear(): def test_ft2font_set_size(): file = fm.findfont('DejaVu Sans') - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_size(12, 72) font.set_text('ABabCDcd') orig = font.get_width_height() @@ -791,7 +795,7 @@ def test_ft2font_get_sfnt_table(font_name, header): def test_ft2font_get_kerning(left, right, unscaled, unfitted, default): file = fm.findfont('DejaVu Sans') # With unscaled, these settings should produce exact values found in FontForge. - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_size(100, 100) assert font.get_kerning(font.get_char_index(ord(left)), font.get_char_index(ord(right)), @@ -830,7 +834,7 @@ def test_ft2font_get_kerning(left, right, unscaled, unfitted, default): def test_ft2font_set_text(): file = fm.findfont('DejaVu Sans') - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_size(12, 72) xys = font.set_text('') np.testing.assert_array_equal(xys, np.empty((0, 2))) @@ -867,7 +871,7 @@ def test_ft2font_set_text(): ) def test_ft2font_language_invalid(input): file = fm.findfont('DejaVu Sans') - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) with pytest.raises(TypeError): font.set_text('foo', language=input) @@ -875,7 +879,7 @@ def test_ft2font_language_invalid(input): def test_ft2font_language(): # This is just a smoke test. file = fm.findfont('DejaVu Sans') - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_text('foo') font.set_text('foo', language='en') font.set_text('foo', language=[('en', 1, 2)]) @@ -883,7 +887,7 @@ def test_ft2font_language(): def test_ft2font_loading(): file = fm.findfont('DejaVu Sans') - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_size(12, 72) for glyph in [font.load_char(ord('M')), font.load_glyph(font.get_char_index(ord('M')))]: @@ -924,13 +928,13 @@ def test_ft2font_drawing(): ]) expected *= 255 file = fm.findfont('DejaVu Sans') - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_size(12, 72) font.set_text('M') font.draw_glyphs_to_bitmap(antialiased=False) image = font.get_image() np.testing.assert_array_equal(image, expected) - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_size(12, 72) glyph = font.load_char(ord('M')) image = np.zeros(expected.shape, np.uint8) @@ -940,7 +944,7 @@ def test_ft2font_drawing(): def test_ft2font_get_path(): file = fm.findfont('DejaVu Sans') - font = ft2font.FT2Font(file, hinting_factor=1) + font = ft2font.FT2Font(file) font.set_size(12, 72) vertices, codes = font.get_path() assert vertices.shape == (0, 2) diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 70715696df30..83b65be400db 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -591,20 +591,6 @@ def test_nonfinite_pos(): fig.canvas.draw() -def test_hinting_factor_backends(): - plt.rcParams['text.hinting_factor'] = 1 - fig = plt.figure() - t = fig.text(0.5, 0.5, 'some text') - - fig.savefig(io.BytesIO(), format='svg') - expected = t.get_window_extent().intervalx - - fig.savefig(io.BytesIO(), format='png') - # Backends should apply hinting_factor consistently (within 10%). - np.testing.assert_allclose(t.get_window_extent().intervalx, expected, - rtol=0.1) - - @needs_usetex def test_usetex_is_copied(): # Indirectly tests that update_from (which is used to copy tick label diff --git a/src/ft2font.cpp b/src/ft2font.cpp index dc9397dd75f0..e99f9a7e1095 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -207,10 +207,8 @@ FT2Font::get_path(std::vector &vertices, std::vector &cod codes.push_back(CLOSEPOLY); } -FT2Font::FT2Font(long hinting_factor_, std::vector &fallback_list, - bool warn_if_used) +FT2Font::FT2Font(std::vector &fallback_list, bool warn_if_used) : warn_if_used(warn_if_used), image({1, 1}), face(nullptr), fallbacks(fallback_list), - hinting_factor(hinting_factor_), // set default kerning factor to 0, i.e., no kerning manipulation kerning_factor(0) { @@ -274,8 +272,8 @@ void FT2Font::set_size(double ptsize, double dpi) { FT_CHECK( FT_Set_Char_Size, - face, (FT_F26Dot6)(ptsize * 64), 0, (FT_UInt)(dpi * hinting_factor), (FT_UInt)dpi); - FT_Matrix transform = { 65536 / hinting_factor, 0, 0, 65536 }; + face, (FT_F26Dot6)(ptsize * 64), 0, (FT_UInt)dpi, (FT_UInt)dpi); + FT_Matrix transform = { 65536, 0, 0, 65536 }; FT_Set_Transform(face, &transform, nullptr); for (auto & fallback : fallbacks) { @@ -315,7 +313,7 @@ int FT2Font::get_kerning(FT_UInt left, FT_UInt right, FT_Kerning_Mode mode) FT_Vector delta; if (!FT_Get_Kerning(face, left, right, mode, &delta)) { - return (int)(delta.x) / (hinting_factor << kerning_factor); + return (int)(delta.x) / (1 << kerning_factor); } else { return 0; } @@ -527,11 +525,7 @@ void FT2Font::set_text( bbox.yMin = std::min(bbox.yMin, glyph_bbox.yMin); bbox.yMax = std::max(bbox.yMax, glyph_bbox.yMax); - if ((flags & FT_LOAD_NO_HINTING) != 0) { - pen.x += rglyph.x_advance - rglyph.x_offset; - } else { - pen.x += hinting_factor * rglyph.x_advance - rglyph.x_offset; - } + pen.x += rglyph.x_advance - rglyph.x_offset; pen.y += rglyph.y_advance - rglyph.y_offset; glyphs.push_back(thisGlyph); diff --git a/src/ft2font.h b/src/ft2font.h index 3facec0fb244..0c438d9107de 100644 --- a/src/ft2font.h +++ b/src/ft2font.h @@ -105,8 +105,7 @@ class FT2Font using LanguageRange = std::tuple; using LanguageType = std::optional>; - FT2Font(long hinting_factor, std::vector &fallback_list, - bool warn_if_used); + FT2Font(std::vector &fallback_list, bool warn_if_used); virtual ~FT2Font(); void open(FT_Open_Args &open_args, FT_Long face_index); void close(); @@ -174,10 +173,6 @@ class FT2Font { return glyphs.size(); } - long get_hinting_factor() const - { - return hinting_factor; - } FT_Bool has_kerning() const { return FT_HAS_KERNING(face); @@ -195,7 +190,6 @@ class FT2Font std::unordered_map char_to_font; FT_BBox bbox; FT_Pos advance; - long hinting_factor; int kerning_factor; // prevent copying diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 41f8e9ee3be8..d0df659c5918 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -357,7 +357,6 @@ static PyGlyph * PyGlyph_from_FT2Font(const FT2Font *font) { const FT_Face &face = font->get_face(); - const long hinting_factor = font->get_hinting_factor(); const FT_Glyph &glyph = font->get_last_glyph(); PyGlyph *self = new PyGlyph(); @@ -365,12 +364,12 @@ PyGlyph_from_FT2Font(const FT2Font *font) self->glyphInd = font->get_last_glyph_index(); FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_subpixels, &self->bbox); - self->width = face->glyph->metrics.width / hinting_factor; + self->width = face->glyph->metrics.width; self->height = face->glyph->metrics.height; - self->horiBearingX = face->glyph->metrics.horiBearingX / hinting_factor; + self->horiBearingX = face->glyph->metrics.horiBearingX; self->horiBearingY = face->glyph->metrics.horiBearingY; self->horiAdvance = face->glyph->metrics.horiAdvance; - self->linearHoriAdvance = face->glyph->linearHoriAdvance / hinting_factor; + self->linearHoriAdvance = face->glyph->linearHoriAdvance; self->vertBearingX = face->glyph->metrics.vertBearingX; self->vertBearingY = face->glyph->metrics.vertBearingY; self->vertAdvance = face->glyph->metrics.vertAdvance; @@ -485,9 +484,6 @@ const char *PyFT2Font_init__doc__ = R"""( filename : str, bytes, os.PathLike, or io.BinaryIO The source of the font data in a format (ttf or ttc) that FreeType can read. - hinting_factor : int, optional - Must be positive. Used to scale the hinting in the x-direction. - face_index : int, optional The index of the face in the font file to load. @@ -505,13 +501,16 @@ const char *PyFT2Font_init__doc__ = R"""( )"""; static PyFT2Font * -PyFT2Font_init(py::object filename, long hinting_factor = 8, FT_Long face_index = 0, +PyFT2Font_init(py::object filename, std::optional hinting_factor = std::nullopt, + FT_Long face_index = 0, std::optional> fallback_list = std::nullopt, std::optional kerning_factor = std::nullopt, bool warn_if_used = false) { - if (hinting_factor <= 0) { - throw py::value_error("hinting_factor must be greater than 0"); + if (hinting_factor) { + auto api = py::module_::import("matplotlib._api"); + auto warn = api.attr("warn_deprecated"); + warn("since"_a="3.11", "name"_a="hinting_factor", "obj_type"_a="parameter"); } if (kerning_factor) { auto api = py::module_::import("matplotlib._api"); @@ -532,7 +531,7 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8, FT_Long face_index std::back_inserter(fallback_fonts)); } - auto self = new PyFT2Font(hinting_factor, fallback_fonts, warn_if_used); + auto self = new PyFT2Font(fallback_fonts, warn_if_used); self->set_kerning_factor(*kerning_factor); if (fallback_list) { @@ -1514,7 +1513,6 @@ PyFT2Font_layout(PyFT2Font *self, std::u32string text, LoadFlags flags, std::optional> features = std::nullopt, std::variant languages_or_str = nullptr) { - const auto hinting_factor = self->get_hinting_factor(); const auto load_flags = static_cast(flags); FT2Font::LanguageType languages; @@ -1567,7 +1565,7 @@ PyFT2Font_layout(PyFT2Font *self, std::u32string text, LoadFlags flags, x += glyph.x_advance; y += glyph.y_advance; // Note, linearHoriAdvance is a 16.16 instead of 26.6 fixed-point value. - prev_advance = ft_object->get_face()->glyph->linearHoriAdvance / 1024.0 / hinting_factor; + prev_advance = ft_object->get_face()->glyph->linearHoriAdvance / 1024.0; } return items; @@ -1752,7 +1750,8 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) auto cls = py::class_(m, "FT2Font", py::is_final(), py::buffer_protocol(), PyFT2Font__doc__) .def(py::init(&PyFT2Font_init), - "filename"_a, "hinting_factor"_a=8, py::kw_only(), "face_index"_a=0, + "filename"_a, "hinting_factor"_a=py::none(), py::kw_only(), + "face_index"_a=0, "_fallback_list"_a=py::none(), "_kerning_factor"_a=py::none(), "_warn_if_used"_a=false, PyFT2Font_init__doc__) @@ -1923,9 +1922,6 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) .def_property_readonly( "fname", &PyFT2Font_fname, "The original filename for this object.") - .def_property_readonly( - "_hinting_factor", &PyFT2Font::get_hinting_factor, - "The hinting factor.") .def_buffer([](PyFT2Font &self) -> py::buffer_info { return self.get_image().request();