summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCalvin Walton <calvin.walton@kepstin.ca>2023-02-28 18:34:05 +0100
committerChristian Persch <chpe@src.gnome.org>2023-02-28 18:34:05 +0100
commite343088f9d02be69c2ff377566b942553e6e21fd (patch)
tree549faf0fb5cdc3b3b817bfb717504bee23d0e1ff
parente8dcb5e0187f10dce9bdc67af66cff31f8dc630b (diff)
downloadvte-e343088f9d02be69c2ff377566b942553e6e21fd.tar.gz
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
-rw-r--r--src/cairo-glue.hh1
-rw-r--r--src/fonts-pangocairo.cc40
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<PangoContext> 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);