diff options
author | Calvin Walton <calvin.walton@kepstin.ca> | 2023-02-28 18:34:05 +0100 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2023-02-28 18:34:05 +0100 |
commit | 241df48d93dbefc1559a6a4e7cea8e60735661d8 (patch) | |
tree | f825ef27d70f3cef3f67f706edd80ab08fc6e922 | |
parent | c8baa84d8cdfe9be774e8dbf62426348025df699 (diff) | |
download | vte-241df48d93dbefc1559a6a4e7cea8e60735661d8.tar.gz |
widget: Add API to override font options
https://gitlab.gnome.org/GNOME/vte/-/issues/2573
-rw-r--r-- | meson.build | 18 | ||||
-rw-r--r-- | src/drawing-cairo.cc | 9 | ||||
-rw-r--r-- | src/drawing-cairo.hh | 1 | ||||
-rw-r--r-- | src/fonts-pangocairo.cc | 58 | ||||
-rw-r--r-- | src/fonts-pangocairo.hh | 8 | ||||
-rw-r--r-- | src/meson.build | 2 | ||||
-rw-r--r-- | src/vte.cc | 18 | ||||
-rw-r--r-- | src/vte/vteterminal.h | 7 | ||||
-rw-r--r-- | src/vtegtk.cc | 81 | ||||
-rw-r--r-- | src/vtegtk.hh | 1 | ||||
-rw-r--r-- | src/vteinternal.hh | 3 |
11 files changed, 172 insertions, 34 deletions
diff --git a/meson.build b/meson.build index dcb2360a..62bfefdf 100644 --- a/meson.build +++ b/meson.build @@ -45,6 +45,8 @@ gtk4_req_version = '4.0.1' gtk4_min_req_version = '4.0' gtk4_max_allowed_version = '4.0' +cairo_req_version = '1.0' +cairo_gobject_req_version = '1.0' fribidi_req_version = '1.0.0' gio_req_version = '2.52.0' glib_req_version = '2.52.0' @@ -617,13 +619,15 @@ endforeach # Dependencies -gio_dep = dependency('gio-2.0', version: '>=' + gio_req_version) -glib_dep = dependency('glib-2.0', version: '>=' + glib_req_version) -gobject_dep = dependency('gobject-2.0') -pango_dep = dependency('pango', version: '>=' + pango_req_version) -pcre2_dep = dependency('libpcre2-8', version: '>=' + pcre2_req_version) -pthreads_dep = dependency('threads') -zlib_dep = dependency('zlib') +cairo_dep = dependency('cairo', version: '>=' + cairo_req_version) +cairo_gobject_dep = dependency('cairo-gobject', version: '>=' + cairo_gobject_req_version) +gio_dep = dependency('gio-2.0', version: '>=' + gio_req_version) +glib_dep = dependency('glib-2.0', version: '>=' + glib_req_version) +gobject_dep = dependency('gobject-2.0') +pango_dep = dependency('pango', version: '>=' + pango_req_version) +pcre2_dep = dependency('libpcre2-8', version: '>=' + pcre2_req_version) +pthreads_dep = dependency('threads') +zlib_dep = dependency('zlib') if get_option('fribidi') fribidi_dep = dependency('fribidi', version: '>=' + fribidi_req_version) diff --git a/src/drawing-cairo.cc b/src/drawing-cairo.cc index 0a1cdae1..202444b4 100644 --- a/src/drawing-cairo.cc +++ b/src/drawing-cairo.cc @@ -138,6 +138,7 @@ DrawingContext::clear(int x, void DrawingContext::set_text_font(GtkWidget* widget, PangoFontDescription const* fontdesc, + cairo_font_options_t const* font_options, double cell_width_scale, double cell_height_scale) { @@ -168,11 +169,11 @@ DrawingContext::set_text_font(GtkWidget* widget, bolditalicdesc = pango_font_description_copy (bolddesc); pango_font_description_set_style (bolditalicdesc, PANGO_STYLE_ITALIC); - m_fonts[VTE_DRAW_NORMAL] = FontInfo::create_for_widget(widget, fontdesc); - m_fonts[VTE_DRAW_BOLD] = FontInfo::create_for_widget(widget, bolddesc); - m_fonts[VTE_DRAW_ITALIC] = FontInfo::create_for_widget(widget, italicdesc); + m_fonts[VTE_DRAW_NORMAL] = FontInfo::create_for_widget(widget, fontdesc, font_options); + m_fonts[VTE_DRAW_BOLD] = FontInfo::create_for_widget(widget, bolddesc, font_options); + m_fonts[VTE_DRAW_ITALIC] = FontInfo::create_for_widget(widget, italicdesc, font_options); m_fonts[VTE_DRAW_ITALIC | VTE_DRAW_BOLD] = - FontInfo::create_for_widget(widget, bolditalicdesc); + FontInfo::create_for_widget(widget, bolditalicdesc, font_options); pango_font_description_free (bolddesc); pango_font_description_free (italicdesc); pango_font_description_free (bolditalicdesc); diff --git a/src/drawing-cairo.hh b/src/drawing-cairo.hh index 24bf5010..65e2ef8c 100644 --- a/src/drawing-cairo.hh +++ b/src/drawing-cairo.hh @@ -77,6 +77,7 @@ public: void clear_font_cache(); void set_text_font(GtkWidget* widget, PangoFontDescription const* fontdesc, + cairo_font_options_t const* font_options, double cell_width_scale, double cell_height_scale); void get_text_metrics(int* cell_width, diff --git a/src/fonts-pangocairo.cc b/src/fonts-pangocairo.cc index 98f1ab08..0fb23b75 100644 --- a/src/fonts-pangocairo.cc +++ b/src/fonts-pangocairo.cc @@ -346,6 +346,7 @@ FontInfo* FontInfo::create_for_context(vte::glib::RefPtr<PangoContext> context, PangoFontDescription const* desc, PangoLanguage* language, + cairo_font_options_t const* font_options, guint fontconfig_timestamp) { if (!PANGO_IS_CAIRO_FONT_MAP(pango_context_get_font_map(context.get()))) { @@ -366,35 +367,50 @@ FontInfo::create_for_context(vte::glib::RefPtr<PangoContext> context, language != pango_context_get_language(context.get())) pango_context_set_language(context.get(), language); - // 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()); + // Make sure our contexts have a font_options set. We use + // this invariant in our context hash and equal functions. + auto builtin_font_options = vte::take_freeable(cairo_font_options_create()); + #if VTE_GTK == 4 - cairo_font_options_set_hint_metrics(font_options.get(), + // On gtk4, we need to 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. + // See issue#2573. + cairo_font_options_set_hint_metrics(builtin_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())) { + // Allow using the API to override the built-in hint metrics setting. + if (!font_options) + font_options = builtin_font_options.get(); + + 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()); + font_options); 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()); + pango_cairo_context_set_font_options(context.get(), font_options); } #if VTE_GTK == 4 - pango_context_set_round_glyph_positions (context.get(), true); + // If hinting font metrics, also make sure to round glyph positions + // to integers. See issue#2573. + if (auto const ctx_font_options = pango_cairo_context_get_font_options(context.get()); + ctx_font_options && + cairo_version() >= CAIRO_VERSION_ENCODE(1, 17, 4)) { + auto const hint_metrics = cairo_font_options_get_hint_metrics(ctx_font_options); + pango_context_set_round_glyph_positions(context.get(), + hint_metrics == CAIRO_HINT_METRICS_ON); + } else { + pango_context_set_round_glyph_positions(context.get(), false); + } #endif /* VTE_GTK == 4 */ } @@ -420,30 +436,32 @@ FontInfo::create_for_context(vte::glib::RefPtr<PangoContext> context, FontInfo* FontInfo::create_for_screen(GdkScreen* screen, PangoFontDescription const* desc, - PangoLanguage* language) + PangoLanguage* language, + cairo_font_options_t const* font_options) { auto settings = gtk_settings_get_for_screen(screen); auto fontconfig_timestamp = guint{}; g_object_get (settings, "gtk-fontconfig-timestamp", &fontconfig_timestamp, nullptr); return create_for_context(vte::glib::take_ref(gdk_pango_context_get_for_screen(screen)), - desc, language, fontconfig_timestamp); + desc, language, font_options, fontconfig_timestamp); } #endif /* VTE_GTK */ FontInfo* FontInfo::create_for_widget(GtkWidget* widget, - PangoFontDescription const* desc) + PangoFontDescription const* desc, + cairo_font_options_t const* font_options) { #if VTE_GTK == 3 auto screen = gtk_widget_get_screen(widget); - return create_for_screen(screen, desc, nullptr); + return create_for_screen(screen, desc, nullptr, font_options); #elif VTE_GTK == 4 auto display = gtk_widget_get_display(widget); auto settings = gtk_settings_get_for_display(display); auto fontconfig_timestamp = guint{}; g_object_get (settings, "gtk-fontconfig-timestamp", &fontconfig_timestamp, nullptr); return create_for_context(vte::glib::take_ref(gtk_widget_create_pango_context(widget)), - desc, nullptr, fontconfig_timestamp); + desc, nullptr, font_options, fontconfig_timestamp); // FIXMEgtk4: this uses a per-widget context, while the gtk3 code uses a per-screen // one. That means there may be a lot less sharing and a lot more FontInfo's around? #endif diff --git a/src/fonts-pangocairo.hh b/src/fonts-pangocairo.hh index 586e6668..6db0a872 100644 --- a/src/fonts-pangocairo.hh +++ b/src/fonts-pangocairo.hh @@ -24,6 +24,7 @@ #include <pango/pangocairo.h> #include <gtk/gtk.h> +#include "cairo-glue.hh" #include "pango-glue.hh" #include "refptr.hh" #include "vteunistr.h" @@ -268,17 +269,20 @@ private: static FontInfo* create_for_context(vte::glib::RefPtr<PangoContext> context, PangoFontDescription const* desc, PangoLanguage* language, + cairo_font_options_t const* font_options, guint fontconfig_timestamp); #if VTE_GTK == 3 static FontInfo *create_for_screen(GdkScreen* screen, PangoFontDescription const* desc, - PangoLanguage* language); + PangoLanguage* language, + cairo_font_options_t const* font_options); #endif public: static FontInfo *create_for_widget(GtkWidget* widget, - PangoFontDescription const* desc); + PangoFontDescription const* desc, + cairo_font_options_t const* font_options); private: static inline GHashTable* s_font_info_for_context{nullptr}; diff --git a/src/meson.build b/src/meson.build index b3f934a2..7737c04a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -274,6 +274,7 @@ libvte_common_sources += gnome.genmarshal( ) libvte_common_public_deps = [ + cairo_dep, gio_dep, glib_dep, gobject_dep, @@ -281,6 +282,7 @@ libvte_common_public_deps = [ ] libvte_common_deps = libvte_common_public_deps + [ + cairo_gobject_dep, fribidi_dep, gnutls_dep, icu_dep, @@ -7218,6 +7218,7 @@ Terminal::ensure_font() m_draw.set_text_font( m_widget, m_unscaled_font_desc.get(), + m_font_options.get(), m_cell_width_scale, m_cell_height_scale); m_draw.get_text_metrics( @@ -7228,6 +7229,7 @@ Terminal::ensure_font() m_draw.set_text_font( m_widget, m_fontdesc.get(), + m_font_options.get(), m_cell_width_scale, m_cell_height_scale); m_draw.get_text_metrics( @@ -7385,6 +7387,22 @@ Terminal::set_font_scale(gdouble scale) } bool +Terminal::set_font_options(vte::Freeable<cairo_font_options_t> font_options) +{ + if ((m_font_options && + font_options && + cairo_font_options_equal(m_font_options.get(), font_options.get())) || + (!m_font_options && + !font_options)) + return false; + + m_font_options = std::move(font_options); + update_font(); + + return true; +} + +bool Terminal::set_cell_width_scale(double scale) { /* FIXME: compare old and new scale in pixel space */ diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h index 90aae937..baaeccf4 100644 --- a/src/vte/vteterminal.h +++ b/src/vte/vteterminal.h @@ -23,6 +23,7 @@ #include <glib.h> #include <gio/gio.h> +#include <cairo.h> #include <pango/pango.h> #include <gtk/gtk.h> @@ -237,6 +238,12 @@ _VTE_PUBLIC gdouble vte_terminal_get_font_scale(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1); _VTE_PUBLIC +void vte_terminal_set_font_options(VteTerminal *terminal, + cairo_font_options_t const* font_options) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1); +_VTE_PUBLIC +cairo_font_options_t const* vte_terminal_get_font_options(VteTerminal *terminal) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1); + +_VTE_PUBLIC void vte_terminal_set_cell_width_scale(VteTerminal *terminal, double scale) _VTE_CXX_NOEXCEPT _VTE_GNUC_NONNULL(1); _VTE_PUBLIC diff --git a/src/vtegtk.cc b/src/vtegtk.cc index cf8ea434..d4eeea4f 100644 --- a/src/vtegtk.cc +++ b/src/vtegtk.cc @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004,2009,2010 Red Hat, Inc. - * Copyright © 2008, 2009, 2010, 2015 Christian Persch + * Copyright © 2008, 2009, 2010, 2015, 2022, 2023 Christian Persch * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -62,6 +62,8 @@ #include "vteptyinternal.hh" #include "vteregexinternal.hh" +#include <cairo-gobject.h> + #ifdef WITH_A11Y #if VTE_GTK == 3 #include "vteaccess.h" @@ -993,6 +995,9 @@ try case PROP_FONT_DESC: g_value_set_boxed (value, vte_terminal_get_font (terminal)); break; + case PROP_FONT_OPTIONS: + g_value_set_boxed(value, vte_terminal_get_font_options(terminal)); + break; case PROP_FONT_SCALE: g_value_set_double (value, vte_terminal_get_font_scale (terminal)); break; @@ -1136,6 +1141,10 @@ try case PROP_FONT_DESC: vte_terminal_set_font (terminal, (PangoFontDescription *)g_value_get_boxed (value)); break; + case PROP_FONT_OPTIONS: + vte_terminal_set_font_options(terminal, + reinterpret_cast<cairo_font_options_t const*>(g_value_get_boxed(value))); + break; case PROP_FONT_SCALE: vte_terminal_set_font_scale (terminal, g_value_get_double (value)); break; @@ -2148,6 +2157,25 @@ vte_terminal_class_init(VteTerminalClass *klass) /** + * VteTerminal:font-options: + * + * The terminal's font options, or %NULL to use the default font options. + * + * Note that on GTK4, the terminal by default uses font options + * with %CAIRO_HINT_METRICS_ON set; to override that, use this + * function to set a #cairo_font_options_t that has + * %CAIRO_HINT_METRICS_OFF set. + * + * Since: 0.74 + */ + pspecs[PROP_FONT_OPTIONS] = + g_param_spec_boxed("font-options", nullptr, nullptr, + CAIRO_GOBJECT_TYPE_FONT_OPTIONS, + GParamFlags(G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY)); + + /** * VteTerminal:font-scale: * * The terminal's font scale. @@ -5584,6 +5612,57 @@ catch (...) } /** + * vte_terminal_get_font_options: + * @terminal: a #VteTerminal + * + * Returns: (nullable): the terminal's font options, or %NULL + * + * Since: 0.74 + */ +cairo_font_options_t const* +vte_terminal_get_font_options(VteTerminal *terminal) noexcept +try +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), nullptr); + + return IMPL(terminal)->get_font_options(); +} +catch (...) +{ + vte::log_exception(); + return nullptr; +} + +/** + * vte_terminal_set_font_options: + * @terminal: a #VteTerminal + * @font_options: (nullable): the font options, or %NULL + * + * Sets the terminal's font options to @options. + * + * Note that on GTK4, the terminal by default uses font options + * with %CAIRO_HINT_METRICS_ON set; to override that, use this + * function to set a #cairo_font_options_t that has + * %CAIRO_HINT_METRICS_OFF set. + * + * Since: 0.74 + */ +void +vte_terminal_set_font_options(VteTerminal *terminal, + cairo_font_options_t const* font_options) noexcept +try +{ + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + + if (IMPL(terminal)->set_font_options(vte::take_freeable(font_options ? cairo_font_options_copy(font_options) : nullptr))) + g_object_notify_by_pspec(G_OBJECT(terminal), pspecs[PROP_FONT_OPTIONS]); +} +catch (...) +{ + vte::log_exception(); +} + +/** * vte_terminal_get_font_scale: * @terminal: a #VteTerminal * diff --git a/src/vtegtk.hh b/src/vtegtk.hh index 778b555a..cca9a188 100644 --- a/src/vtegtk.hh +++ b/src/vtegtk.hh @@ -78,6 +78,7 @@ enum { PROP_ENABLE_SIXEL, PROP_ENCODING, PROP_FONT_DESC, + PROP_FONT_OPTIONS, PROP_FONT_SCALE, PROP_HYPERLINK_HOVER_URI, PROP_ICON_TITLE, diff --git a/src/vteinternal.hh b/src/vteinternal.hh index 88464760..b9f77891 100644 --- a/src/vteinternal.hh +++ b/src/vteinternal.hh @@ -617,6 +617,7 @@ public: /* Data used when rendering the text which does not require server * resources and which can be kept after unrealizing. */ + vte::Freeable<cairo_font_options_t> m_font_options{}; vte::Freeable<PangoFontDescription> m_api_font_desc{}; vte::Freeable<PangoFontDescription> m_unscaled_font_desc{}; vte::Freeable<PangoFontDescription> m_fontdesc{}; @@ -1408,6 +1409,8 @@ public: GError** error); bool set_font_desc(vte::Freeable<PangoFontDescription> desc); bool update_font_desc(); + bool set_font_options(vte::Freeable<cairo_font_options_t> font_options); + cairo_font_options_t const* get_font_options() const noexcept { return m_font_options.get(); } bool set_font_scale(double scale); bool set_input_enabled(bool enabled); bool set_mouse_autohide(bool autohide); |