From e343088f9d02be69c2ff377566b942553e6e21fd Mon Sep 17 00:00:00 2001 From: Calvin Walton Date: Tue, 28 Feb 2023 18:34:05 +0100 Subject: widget: gtk4: Hint and quantize font metrics With gtk4, the font metrics are unhinted by default. This causes problems when measuring the font, since the width or height may have fractional pixel values that get rounded up - resulting in vte using integer cell sizes that are larger than would be appropriate for the font - the usual side-effect is that horizontal letter spacing looks too wide. To fix this, set the cairo font option to hint vertical metrics, which will result in the glyph ascent and descent values both being integers. Also make pango round glyph positions, so that the horizontal advance of the glyphs will be integers appropirate for a renderer that doesn't do sub-pixel glyph positioning. Fixes: https://gitlab.gnome.org/GNOME/vte/-/issues/2573 --- src/cairo-glue.hh | 1 + src/fonts-pangocairo.cc | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/cairo-glue.hh b/src/cairo-glue.hh index 168356ab..6f10d9c0 100644 --- a/src/cairo-glue.hh +++ b/src/cairo-glue.hh @@ -23,6 +23,7 @@ namespace vte { +VTE_DECLARE_FREEABLE(cairo_font_options_t, cairo_font_options_destroy); VTE_DECLARE_FREEABLE(cairo_rectangle_list_t, cairo_rectangle_list_destroy); VTE_DECLARE_FREEABLE(cairo_region_t, cairo_region_destroy); VTE_DECLARE_FREEABLE(cairo_surface_t, cairo_surface_destroy); diff --git a/src/fonts-pangocairo.cc b/src/fonts-pangocairo.cc index 8d0cb2a3..98f1ab08 100644 --- a/src/fonts-pangocairo.cc +++ b/src/fonts-pangocairo.cc @@ -20,6 +20,7 @@ #include "fonts-pangocairo.hh" +#include "cairo-glue.hh" #include "debug.h" #include "vtedefines.hh" @@ -365,17 +366,40 @@ FontInfo::create_for_context(vte::glib::RefPtr context, language != pango_context_get_language(context.get())) pango_context_set_language(context.get(), language); - /* Make sure our contexts have a font_options set. We use - * this invariant in our context hash and equal functions. - */ - if (!pango_cairo_context_get_font_options(context.get())) { - cairo_font_options_t *font_options; + // Ensure Pango and cairo are configured to quantize and hint font metrics. + // Terminal cells in vte have integer pixel sizes. If Pango is configured to do sub-pixel + // glyph advances, a small fractional part might get rounded up to a whole pixel - so the + // character spacing will appear too wide. Setting the cairo hint metrics option ensures + // that there are integer numbers of pixels both above and below the baseline. + { + auto font_options = vte::take_freeable(cairo_font_options_create()); +#if VTE_GTK == 4 + cairo_font_options_set_hint_metrics(font_options.get(), + CAIRO_HINT_METRICS_ON); +#endif /* VTE_GTK == 4 */ + + if (auto const ctx_font_options = + pango_cairo_context_get_font_options(context.get())) { + auto const merged_font_options = + vte::take_freeable(cairo_font_options_copy(ctx_font_options)); + cairo_font_options_merge(merged_font_options.get(), + font_options.get()); + pango_cairo_context_set_font_options(context.get(), + merged_font_options.get()); + } else { + // Make sure our contexts have a font_options set. We use + // this invariant in our context hash and equal functions. + pango_cairo_context_set_font_options(context.get(), + font_options.get()); + } - font_options = cairo_font_options_create (); - pango_cairo_context_set_font_options(context.get(), font_options); - cairo_font_options_destroy (font_options); +#if VTE_GTK == 4 + pango_context_set_round_glyph_positions (context.get(), true); +#endif /* VTE_GTK == 4 */ } + pango_context_changed (context.get()); + if (G_UNLIKELY(s_font_info_for_context == nullptr)) s_font_info_for_context = g_hash_table_new((GHashFunc) context_hash, (GEqualFunc) context_equal); -- cgit v1.2.1