Skip to content

Update FreeType to 2.13.3 #29816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Update FreeType to 2.13.3 #29816

wants to merge 10 commits into from

Conversation

QuLogic
Copy link
Member

@QuLogic QuLogic commented Mar 27, 2025

PR summary

On the call last week, we considered whether it made sense to do this upgrade. This PR shows the effect of doing so. Note for simplicity, I simply copied the new images from https://github.com/QuLogic/mpl-images, and then updated any new images directly. It's possible that there were some extraneously changed images as a result. I will check this shortly.

The latest FreeType version supports many newer font features, and fixes several CVEs, which we were mostly hoping were not relevant to us, but this may or may not be true. Additionally, I've found that libraqm runs into issues with hinting in older versions. While I'm not entirely sure which of libraqm or FreeType holds that bug, updating libraqm to new versions would also require newer FreeType anyway.

The main concern here was the repo size. Locally, I started with a completely fresh clone before creating this commit. The .git directory increased from 461M to 482M, or an increase of 21M / 4.6%.

PR checklist

@QuLogic
Copy link
Member Author

QuLogic commented Mar 27, 2025

Another size test:

$ git clone https://github.com/matplotlib/matplotlib.git mpl
$ cd mpl
$ du -hsc .git
461M	.git
461M	total

$ git fetch https://github.com/QuLogic/matplotlib.git ft213:ft213
$ du -hsc .git
477M	.git
477M	total

So once everything is repacked and compressed by git, the repo only gains 16M!

@anntzer
Copy link
Contributor

anntzer commented Mar 27, 2025

If we're going to regen the baselines, we should also take that opportunity to remove some of the backcompat knobs -- at least text.kerning_factor (which clearly only existed to avoid regen'ing the baselines), and possibly text.hinting_factor as well (at least I would switch the default to 1 and generate the images with that amount of hinting, even if we decide to keep this functionality).

@tacaswell
Copy link
Member

Rather than regenerating the images at this point, I would start by pulling the tolerances used by Fedora upstream (so we can backport that to 3.10.x) and then in a second step regenerate the images on main and push the tolerances back to 0.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 27, 2025

If we're going to regen the baselines, we should also take that opportunity to remove some of the backcompat knobs -- at least text.kerning_factor (which clearly only existed to avoid regen'ing the baselines), and possibly text.hinting_factor as well (at least I would switch the default to 1 and generate the images with that amount of hinting, even if we decide to keep this functionality).

Yes, good point; I will see what effect that has on things.

Rather than regenerating the images at this point, I would start by pulling the tolerances used by Fedora upstream (so we can backport that to 3.10.x) and then in a second step regenerate the images on main and push the tolerances back to 0.

Fedora doesn't have any other tolerances other than the 6 other files already changed (though in this PR I changed the results instead of the tolerance, we could do like in Fedora instead). For image tests, we overlay the correct images from my mpl-images repo and don't change any global tolerance.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 28, 2025

Removing kerning_factor from _classic_test.patch causes an additional 100 test failures over this PR. Top 20 RMS are:

  • lib/matplotlib/tests/test_backend_pdf.py::test_kerning[pdf] 23.532
  • lib/matplotlib/tests/test_arrow_patches.py::test_boxarrow[png] 20.492
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout9[png] 17.849
  • lib/matplotlib/tests/test_mathtext.py::test_mathtext_rendering_lightweight[png-mathtext1-dejavusans-8] 17.244
  • lib/matplotlib/tests/test_table.py::test_auto_column[png] 16.872
  • lib/matplotlib/tests/test_text.py::test_basic_wrap[png] 15.712
  • lib/matplotlib/tests/test_axes.py::test_pie_nolabel_but_legend[png] 12.626
  • lib/matplotlib/tests/test_tightlayout.py::test_tight_layout7[pdf] 12.406
  • lib/matplotlib/tests/test_mathtext.py::test_mathtext_rendering[pdf-mathtext-dejavusans-46] 11.002
  • lib/matplotlib/tests/test_axes.py::test_stairs_datetime[png] 10.796
  • lib/matplotlib/tests/test_tightlayout.py::test_tight_layout7[png] 10.388
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout5[png] 10.191
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout2[png] 10.191
  • lib/matplotlib/tests/test_tightlayout.py::test_tight_layout7[svg] 9.704
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout4[png] 9.014
  • lib/matplotlib/tests/test_legend.py::test_multiple_keys[png] 8.322
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout3[png] 7.658
  • lib/matplotlib/tests/test_mathtext.py::test_mathtext_rendering[pdf-mathtext-dejavuserif-60] 7.572
  • lib/matplotlib/tests/test_text.py::test_font_styles[pdf] 7.355
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout15[png] 7.259

I'll commit these all separately to make it easier to review, but we can squash these all together if it's all working fine. The majority of these are things like Te, te, x, er all kern a little bit closer together now.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 28, 2025

On a related note, and I'm not sure which ones are relevant here, but I wonder if we should drop several PDF and SVG test images when they would be changed but don't effectively test anything different from the PNG.

@jklymak
Copy link
Member

jklymak commented Mar 28, 2025

For the repo size problem we could provide some guidance for the depth flag so most contributors don't need to download the whole thing. Eg --depth=500 gets you the last two years of commits and is x MB. Most folks don't need the full commit history (or even anything more than depth=1)

@greglucas
Copy link
Contributor

The first image comparison that shows up lib/matplotlib/tests/baseline_images/test_agg/agg_filter.png doesn't have any text in it at all so is presumably not an update due to freetype. Is this all images that have had tolerances ever adjusted in the past? If so, do you know if there would be any size difference with just text-based freetype updates versus all others?

Is it beneficial/necessary to grab the images from that other repo you've been keeping, or would it make sense to blow away the images directory on CI and move all the resultant images into the directory to start fresh in a sense?

@QuLogic
Copy link
Member Author

QuLogic commented Mar 28, 2025

and possibly text.hinting_factor as well (at least I would switch the default to 1 and generate the images with that amount of hinting, even if we decide to keep this functionality).

Surprisingly, this doesn't appear to make any difference to test images. It only affects 9 tests, and only with regards to bboxes and tight layout that are explicitly compared. This doesn't matter whether I try with FreeType 2.6.1 or 2.13.3.

The first image comparison that shows up lib/matplotlib/tests/baseline_images/test_agg/agg_filter.png doesn't have any text in it at all so is presumably not an update due to freetype. Is this all images that have had tolerances ever adjusted in the past? If so, do you know if there would be any size difference with just text-based freetype updates versus all others?

Ah, you're right. I had not done a deep dive into the changes, but likely this was an image that had text that was removed, so it was regenerated from the FreeType changes, but effectively looked the same. I will go through these again and make sure we don't have any extraneous changes like this one.

Is it beneficial/necessary to grab the images from that other repo you've been keeping, or would it make sense to blow away the images directory on CI and move all the resultant images into the directory to start fresh in a sense?

The other repo was useful for tracking purposes and a quick changeover, but it might be best to start fresh and make sure we don't change too many extra images.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 29, 2025

I haven't updated this PR for it yet, but going over the diffs, one surprising change is that while the mathtext tests with DejaVu Sans look better (more consistent baselines, tweaks to kerning), the same ones with Computer Modern look worse (mostly due to a wobbly baseline.) But on the other hand, a lot of those had the wobbly baseline before...

I've also opened #29827 to remove most of the redundant PDFs that would be changed here (except the ones from test_backend_pdf, plus a few others noted in that PR).

@anntzer
Copy link
Contributor

anntzer commented Mar 29, 2025

See also #14177 (comment) and #22459 re: wobbly baseline. I have some hopes that switching agg+usetex to rasterizing glyphs ourselves (see also #29807) would be one way to fix that.

@oscargus
Copy link
Member

Slightly unrelated, but if we decide to update this many PNGs, it should be a good time to add an oxipng pre-commit hook. https://github.com/shssoichiro/oxipng I would expect that the sizes are halved or so on average. (It would be useful independent of this, but I have not gotten around to propose it and it would be unfortunate to change all those images without compression.)

@QuLogic
Copy link
Member Author

QuLogic commented Apr 1, 2025

See also #14177 (comment) and #22459 re: wobbly baseline. I have some hopes that switching agg+usetex to rasterizing glyphs ourselves (see also #29807) would be one way to fix that.

But these are not usetex, just plain mathtext. However, thanks to those links, I've come across #5414 which claimed to fix the wobbly baseline. It turns out that that isn't due to changing to external FreeType, but to a change in MathtextBackendAgg.render_glyph. Copying that out fixes all the wobbly baselines, both before and after updating FreeType.

Unfortunately, updating FreeType still causes changes in those test images due to different kerning and metrics (the whole line may move up/down a pixel, but individual glyphs no longer do.) So I'm going to roll that change in here for the changed images to be squashed together.

@QuLogic
Copy link
Member Author

QuLogic commented Apr 1, 2025

I've now rebased this on top of #29827, and gone through and removed the extra image changes. Now it's about 60% the number it was before.

As I expect this will be squashed, there are a few things here:

  1. Fixing the wobbly baseline in mathtext (e.g., for the Latin alphabet, the t is no longer floating, while for the Greek alphabet, everything shifts down to match theta).
  2. Updating to FreeType 2.13.3.
  3. Removing the kerning_factor setting from the tests (the majority of these are things like Te, te, x, er all kerning a little bit closer.)
  4. Removing any compatibility styling flags on images that were already regenerated.
  5. Compressing everything that was already changed with oxipng; this compresses from about 12M to 7M.

@anntzer
Copy link
Contributor

anntzer commented Apr 1, 2025

Are the new tests also using hinting_factor=1?

@QuLogic
Copy link
Member Author

QuLogic commented Apr 1, 2025

No, as I mentioned earlier, that barely changed anything. I'm trying to see if that's true or whether I didn't set it up right.

@QuLogic
Copy link
Member Author

QuLogic commented Apr 18, 2025

While looking at #29936, I came across a bug in the kerning calculation for mathtext; I've added the fix here in 6c7b9d0 It only affects 27 tests, but I can rebase this together later.

@QuLogic
Copy link
Member Author

QuLogic commented Apr 23, 2025

For the minimum version builds, it looks like we're hitting mesonbuild/meson-python#424, which was fixed in meson-python 0.13.2, so I guess we'll have to bump that requirement (but it's already 0.13.1, so that's not a big jump.)

@QuLogic
Copy link
Member Author

QuLogic commented Apr 24, 2025

Hmm, something seems a bit off with the kerning. For example, https://github.com/matplotlib/matplotlib/pull/29816/files#diff-a98ee9405471b4a49ef6fa8d8083e4a485936d4d8f8568782b8e1d70bc311f3e spreads the Te apart, but the opposite happens once libraqm is involved, so there may be some unnecessary churn there.

mdboom and others added 10 commits April 26, 2025 05:25
Namely, `text.hinting` is now `default` instead of `force_autohint` (or
`none` for classic tests) and `text.hinting_factor` is now 1, not 8.
If we've updated an image in the past couple commits, then we can remove
the backwards-compatibility styling so that they're generated as
intended.
The `FontInfo.num` value returned by `TruetypeFonts._get_info` is a
character code, but `FT2Font.get_kerning` takes *glyph indices*, meaning
that kerning was likely off in most cases.
@QuLogic
Copy link
Member Author

QuLogic commented Apr 26, 2025

After discussing it a bit, I think the kerning is fine (or as good as it'll be.) I was misled by only testing "Text" and not "2D Text" as in the test. With the additional "2D ", the Te is kerned a little differently in all cases of hinting-factor/FreeType/libraqm, and even at larger font sizes.

With hinting-factor=1:
image
With hinting-factor=8:
image

In these images, on the left is "2D Text" and just "Text" to the right, at 12pt and 24pt. With "2D " to shift the T over, the kerning for Te is a bit wider than when the T is at the beginning of the string.

The reason for the change is that FreeType kerning is rounded to integer pixels; with hinting-factor=8, the "pixels" are 8 times smaller and so can be a little closer than with a 1 factor. Unfortunately, the libraqm update will shrink this kerning back to similar results as before.

We did discuss perhaps setting hinting-factor=8 now and only changing to 1 with libraqm (which does require it or else everything is broken) since libraqm will shrink the kerning again. However, reverting that change will cause 1100 image changes whereas libraqm is only about 90, so I don't think we should do that.

I've rebased this PR, and squashed the image changes into the last change. I've also run oxipng on them to shrink them down.

@anntzer
Copy link
Contributor

anntzer commented Apr 27, 2025

Now that I remember it, this may also be the opportunity to remove a few hacks in mathtext. In particular the following should be quite clear:

diff --git i/lib/matplotlib/_mathtext.py w/lib/matplotlib/_mathtext.py
index 415033b9ac..059dd6d5dc 100644
--- i/lib/matplotlib/_mathtext.py
+++ w/lib/matplotlib/_mathtext.py
@@ -149,20 +149,20 @@ class Output:
         d = ymax - ymin - self.box.height
         image = FT2Image(int(np.ceil(w)), int(np.ceil(h + max(d, 0))))

-        # Ideally, we could just use self.glyphs and self.rects here, shifting
-        # their coordinates by (-xmin, -ymin), but this yields slightly
-        # different results due to floating point slop; shipping twice is the
-        # old approach and keeps baseline images backcompat.
-        shifted = ship(self.box, (-xmin, -ymin))
-
-        for ox, oy, info in shifted.glyphs:
+        for ox, oy, info in self.glyphs:
+            ox -= xmin
+            oy -= ymin
             info.font.draw_glyph_to_bitmap(
                 image,
                 int(ox),
                 int(oy - np.ceil(info.metrics.iceberg)),
                 info.glyph,
                 antialiased=antialiased)
-        for x1, y1, x2, y2 in shifted.rects:
+        for x1, y1, x2, y2 in self.rects:
+            x1 -= xmin
+            x2 -= xmin
+            y1 -= ymin
+            y2 -= ymin
             height = max(int(y2 - y1) - 1, 0)
             if height == 0:
                 center = (y2 + y1) / 2

(a few baseline images change, which can be squashed with the changes here)

The idea is that the mathtext parser first places the glyphs relative to the "pen position at the start of the string" (during the ship(box, [xy=(0, 0)]) call in MathTextParser._parse_cached), then needs to shift the coordinates of these glyphs to be relative to the bounding box of the rasterization of the string (so that the low-level rendering code can indeed place the glyphs where needed). In theory this is just a matter of subtracting (xmin, ymin) to all coordinates (as can be checked by examining the implementation of ship()), but due to the presence of floating point slop (and then truncation to full pixels), doing the subtraction from the start yields slightly different results than doing it post-facto; thus, solely to avoid changing the baselines, I had left the two-pass approach when refactoring this code some time ago. However, this second pass can now be dropped (which would also be a small performance improvement).

There's a few other changes in mathtext (essentially related to fixing #15313/#15339, still broken with this PR) that would also result in tiny baseline image changes that I'd like to figure out and also squash with the changes here, but I would need more time to fully flesh them out so I would not hold this PR up for that.

@anntzer
Copy link
Contributor

anntzer commented Apr 28, 2025

I also realized that the changes here (likely the "wobbly-baseline fixing" one, although I didn't check) make some mathtext rendering clearly worse, e.g. rcParams["mathtext.fontset"] = "cm"; text(.5, .5, r"$\frac{1}{2}$")
old:
old
new (with or without the patch proposed in the comment immediately above):
new
note how the denominator now bumps into the fraction bar.

@anntzer
Copy link
Contributor

anntzer commented Apr 28, 2025

I pushed to https://github.com/anntzer/matplotlib/tree/mt1 an updated version of #15539 #15339, which I think should be worth looking at to merge with the baseline changes here (it changes all the baseline images). Note that the version I pushed doesn't contain, for now, the updated baseline images (you need run the tests and accept all changes). Apologies for the somewhat rough state of the proposal (I will try to polish it later, I'm just trying to put down a marker so that massive baseline changes can perhaps be squashed together).

The idea of the change is basically the following: mathtext currently rasterizes glyphs by passing the coordinate of their top left corner to draw_glyph_to_bitmap (which makes pasting the rasterized glyph bitmap into the whole image more convenient, but leads to wobbly baselines if one isn't careful with rounding and hinting); instead, modify draw_glyph_to_bitmap (which should likely be renamed into another function) to accept glyph origins, which can be directly passed from the mathtext glyph layouting algorithm. While at it, also restore the subpixel glyph localization code which was commented out (e.g. sub_offset in draw_glyph_to_bitmap).

A few changes which I think are for the better:
new mathtext_stixsans_26: note the more consistent accent height positioning
mathtext_stixsans_26
old
mathtext_stixsans_26-expected

new mathfont_dejavusans_60: note the more homogeneous spacing between the "bfit" letters
mathfont_dejavusans_60
old
mathfont_dejavusans_60-expected

This also fixes #15313.

(Note that I have another good reason to have the mathtext rasterizer work using glyph origins instead of glyph topleft corners: I would like to reuse it to rasterize usetex dvi's, which will allow getting rid of the dvipng dependency (this is in particular needed for luatex/xetex support, as dvipng doesn't support their dvi dialects, but is a worthwhile improvement in itself too, I think).)

@QuLogic
Copy link
Member Author

QuLogic commented Apr 28, 2025

note how the denominator now bumps into the fraction bar.

I was thinking this had something to do with #18389, which was a long-standing issue so I didn't worry about it too much yet.

I pushed to https://github.com/anntzer/matplotlib/tree/mt1 an updated version of #15539

That was merged and seems to be a docs change; did you mean a different PR?

While at it, also restore the subpixel glyph localization code which was commented out (e.g. sub_offset in draw_glyph_to_bitmap).

Do you think this would also help with #29551? That seemed to be a problem with subpixel positioning.

new mathfont_dejavusans_60: note the more homogeneous spacing between the "bfit" letters

This is definitely something that annoyed me. and happy to see it fixed better.

@anntzer
Copy link
Contributor

anntzer commented Apr 29, 2025

note how the denominator now bumps into the fraction bar.

I was thinking this had something to do with #18389, which was a long-standing issue so I didn't worry about it too much yet.

Possible, didn't really investigate.

I pushed to https://github.com/anntzer/matplotlib/tree/mt1 an updated version of #15539

That was merged and seems to be a docs change; did you mean a different PR?

Typo, should have been #15339. Edited in the message above as well.

While at it, also restore the subpixel glyph localization code which was commented out (e.g. sub_offset in draw_glyph_to_bitmap).

Do you think this would also help with #29551? That seemed to be a problem with subpixel positioning.

Testing #29551 (comment) but switching to mathtext ("$ABC123$") shows that it doesn't, but that's not too surprising, because the final step of blitting the mathtext (intermediate, FT2Image) raster onto the Agg raster still rounds to full pixels (in RendererAgg.draw_mathtext), which is likely anyways needed so as not to undo the glyph hinting done when drawing the glyph to the mathtext raster.

The correct fix for that problem is likely to completely get rid of the intermediate mathtext raster and directly rasterize to the Agg raster at the correct position. (This is essentially mplcairo's approach, and would also get rid of the need to figure out the exact size of the FT2Image to allocate, which is surprisingly complicated (see comments in Output.to_raster() in the mt1 branch).)
Alternatively, one could pass the required final subpixel position to Output.to_raster(), obtain a subpixel positioned raster, and blit that to the Agg raster, but that seems to add more complexity than needed.
Of course, doing either would likely again break all baseline images, but heh...

new mathfont_dejavusans_60: note the more homogeneous spacing between the "bfit" letters

This is definitely something that annoyed me. and happy to see it fixed better.

@anntzer
Copy link
Contributor

anntzer commented May 1, 2025

Further note for self: check whether #18181's backcompat hack can be removed and folded with the changes here.

Edit: The change would be the patch below, which indeed again changes a bunch of baseline images; I haven't checked how much are files already touched by this PR.

diff --git i/lib/matplotlib/backends/backend_pdf.py w/lib/matplotlib/backends/backend_pdf.py
index 4c6bb266e0..702110b1f0 100644
--- i/lib/matplotlib/backends/backend_pdf.py
+++ w/lib/matplotlib/backends/backend_pdf.py
@@ -617,40 +617,18 @@ def _get_pdf_charprocs(font_path, glyph_ids):
     procs = {}
     for glyph_id in glyph_ids:
         g = font.load_glyph(glyph_id, LoadFlags.NO_SCALE)
-        # NOTE: We should be using round(), but instead use
-        # "(x+.5).astype(int)" to keep backcompat with the old ttconv code
-        # (this is different for negative x's).
-        d1 = (np.array([g.horiAdvance, 0, *g.bbox]) * conv + .5).astype(int)
+        d1 = [
+            round(g.horiAdvance * conv), 0,
+            # Round bbox corners *outwards*, so that they indeed bound th glyph.
+            math.floor(g.bbox[0] * conv), math.floor(g.bbox[1] * conv),
+            math.ceil(g.bbox[2] * conv), math.ceil(g.bbox[3] * conv),
+        ]
         v, c = font.get_path()
-        v = (v * 64).astype(int)  # Back to TrueType's internal units (1/64's).
-        # Backcompat with old ttconv code: control points between two quads are
-        # omitted if they are exactly at the midpoint between the control of
-        # the quad before and the quad after, but ttconv used to interpolate
-        # *after* conversion to PS units, causing floating point errors.  Here
-        # we reproduce ttconv's logic, detecting these "implicit" points and
-        # re-interpolating them.  Note that occasionally (e.g. with DejaVu Sans
-        # glyph "0") a point detected as "implicit" is actually explicit, and
-        # will thus be shifted by 1.
-        quads, = np.nonzero(c == 3)
-        quads_on = quads[1::2]
-        quads_mid_on = np.array(
-            sorted({*quads_on} & {*(quads - 1)} & {*(quads + 1)}), int)
-        implicit = quads_mid_on[
-            (v[quads_mid_on]  # As above, use astype(int), not // division
-             == ((v[quads_mid_on - 1] + v[quads_mid_on + 1]) / 2).astype(int))
-            .all(axis=1)]
-        if (font.postscript_name, glyph_id) in [
-                ("DejaVuSerif-Italic", 77),  # j
-                ("DejaVuSerif-Italic", 135),  # \AA
-        ]:
-            v[:, 0] -= 1  # Hard-coded backcompat (FreeType shifts glyph by 1).
-        v = (v * conv + .5).astype(int)  # As above re: truncation vs rounding.
-        v[implicit] = ((  # Fix implicit points; again, truncate.
-            (v[implicit - 1] + v[implicit + 1]) / 2).astype(int))
+        v = (v * 64 * conv).round()  # Back to TrueType's internal units (1/64's).
         procs[font.get_glyph_name(glyph_id)] = (
             " ".join(map(str, d1)).encode("ascii") + b" d1\n"
             + _path.convert_to_string(
-                Path(v, c), None, None, False, None, -1,
+                Path(v, c), None, None, False, None, 0,
                 # no code for quad Beziers triggers auto-conversion to cubics.
                 [b"m", b"l", b"", b"c", b"h"], True)
             + b"f")
diff --git i/src/_path.h w/src/_path.h
index c037037767..1b54426c7e 100644
--- i/src/_path.h
+++ w/src/_path.h
@@ -1066,38 +1066,25 @@ void quad2cubic(double x0, double y0,
 void __add_number(double val, char format_code, int precision,
                   std::string& buffer)
 {
-    if (precision == -1) {
-        // Special-case for compat with old ttconv code, which *truncated*
-        // values with a cast to int instead of rounding them as printf
-        // would do.  The only point where non-integer values arise is from
-        // quad2cubic conversion (as we already perform a first truncation
-        // on Python's side), which can introduce additional floating point
-        // error (by adding 2/3 delta-x and then 1/3 delta-x), so compensate by
-        // first rounding to the closest 1/3 and then truncating.
-        char str[255];
-        PyOS_snprintf(str, 255, "%d", (int)(round(val * 3)) / 3);
-        buffer += str;
-    } else {
-        char *str = PyOS_double_to_string(
-          val, format_code, precision, Py_DTSF_ADD_DOT_0, nullptr);
-        // Delete trailing zeros and decimal point
-        char *c = str + strlen(str) - 1;  // Start at last character.
-        // Rewind through all the zeros and, if present, the trailing decimal
-        // point.  Py_DTSF_ADD_DOT_0 ensures we won't go past the start of str.
-        while (*c == '0') {
-            --c;
-        }
-        if (*c == '.') {
-            --c;
-        }
-        try {
-            buffer.append(str, c + 1);
-        } catch (std::bad_alloc& e) {
-            PyMem_Free(str);
-            throw e;
-        }
+    char *str = PyOS_double_to_string(
+        val, format_code, precision, Py_DTSF_ADD_DOT_0, nullptr);
+    // Delete trailing zeros and decimal point
+    char *c = str + strlen(str) - 1;  // Start at last character.
+    // Rewind through all the zeros and, if present, the trailing decimal
+    // point.  Py_DTSF_ADD_DOT_0 ensures we won't go past the start of str.
+    while (*c == '0') {
+        --c;
+    }
+    if (*c == '.') {
+        --c;
+    }
+    try {
+        buffer.append(str, c + 1);
+    } catch (std::bad_alloc& e) {
         PyMem_Free(str);
+        throw e;
     }
+    PyMem_Free(str);
 }
 
 

@ksunden ksunden mentioned this pull request May 2, 2025
2 tasks
@ksunden ksunden modified the milestones: v3.10.2, v3.10.3 May 2, 2025
@QuLogic
Copy link
Member Author

QuLogic commented May 3, 2025

I pushed to https://github.com/anntzer/matplotlib/tree/mt1 an updated version of #15539 #15339, which I think should be worth looking at to merge with the baseline changes here (it changes all the baseline images). Note that the version I pushed doesn't contain, for now, the updated baseline images (you need run the tests and accept all changes).

I ran this, and without checking the changes, it will change several of the images changed here, with the addition of:

  • lib/matplotlib/tests/test_ft2font.py::test_ft2font_drawing
  • lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf
  • lib/matplotlib/tests/baseline_images/test_backend_ps/type42_without_prep.eps
  • lib/matplotlib/tests/baseline_images/test_contour/contour_log_locator.svg
  • lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg
  • lib/matplotlib/tests/baseline_images/test_text/text_pdf_chars_beyond_bmp.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg
  • almost all of the PDF and many of the SVG that are in lib/matplotlib/tests/baseline_images/test_mathtext/ (note that all the PNG there were already changed)

The change would be the patch below, which indeed again changes a bunch of baseline images; I haven't checked how much are files already touched by this PR.

There are not really a whole bunch of changes here; only 111 tests. Again, I didn't do a full review yet, but it will change:

  • lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.pdf
  • lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.pdf
  • lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type3.pdf
  • lib/matplotlib/tests/baseline_images/test_backend_pdf/truetype-conversion.pdf
  • lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.pdf
  • lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf
  • lib/matplotlib/tests/baseline_images/test_contour/contour_rasterization.pdf
  • lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.pdf
  • lib/matplotlib/tests/baseline_images/test_legend/framealpha.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg
  • lib/matplotlib/tests/baseline_images/test_text/multiline.pdf
  • lib/matplotlib/tests/baseline_images/test_text/multiline2.pdf
  • lib/matplotlib/tests/baseline_images/test_text/text_alignment.pdf
  • lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.pdf
  • lib/matplotlib/tests/baseline_images/test_text/titles.pdf
  • many, but not nearly all, PDF and SVG in lib/matplotlib/tests/baseline_images/test_mathtext/ again

I have pushed the corresponding test image changes here for now: https://github.com/QuLogic/matplotlib/tree/ft213-additions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Determine if hinting_factor setting can be dropped
9 participants