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
commit241df48d93dbefc1559a6a4e7cea8e60735661d8 (patch)
treef825ef27d70f3cef3f67f706edd80ab08fc6e922
parentc8baa84d8cdfe9be774e8dbf62426348025df699 (diff)
downloadvte-241df48d93dbefc1559a6a4e7cea8e60735661d8.tar.gz
widget: Add API to override font options
https://gitlab.gnome.org/GNOME/vte/-/issues/2573
-rw-r--r--meson.build18
-rw-r--r--src/drawing-cairo.cc9
-rw-r--r--src/drawing-cairo.hh1
-rw-r--r--src/fonts-pangocairo.cc58
-rw-r--r--src/fonts-pangocairo.hh8
-rw-r--r--src/meson.build2
-rw-r--r--src/vte.cc18
-rw-r--r--src/vte/vteterminal.h7
-rw-r--r--src/vtegtk.cc81
-rw-r--r--src/vtegtk.hh1
-rw-r--r--src/vteinternal.hh3
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,
diff --git a/src/vte.cc b/src/vte.cc
index 70815088..05c12901 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -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);