From 2f352c6f219e8531fc5007dd6d26efb1acea312d Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Wed, 29 Jun 2022 21:38:24 +0200 Subject: [PATCH] Reject font values that are invalid for pango Use pango to parse font configuration early, and reject the command as invalid if the value is invalid for pango. Since we're already parsing the font into a `PangoFontDescription`, keep that instance around and avoid re-parsing the font each time we render text. Fixes: https://github.com/swaywm/sway/issues/6805 --- common/pango.c | 4 +--- include/pango.h | 2 +- include/sway/config.h | 4 +++- sway/commands/font.c | 23 +++++++++++++++++++++++ sway/config.c | 3 ++- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/common/pango.c b/common/pango.c index abc18281f3..e8e2678d01 100644 --- a/common/pango.c +++ b/common/pango.c @@ -109,10 +109,9 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, free(buf); } -void get_text_metrics(const char *font, int *height, int *baseline) { +void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) { cairo_t *cairo = cairo_create(NULL); PangoContext *pango = pango_cairo_create_context(cairo); - PangoFontDescription *description = pango_font_description_from_string(font); // When passing NULL as a language, pango uses the current locale. PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL); @@ -120,7 +119,6 @@ void get_text_metrics(const char *font, int *height, int *baseline) { *height = *baseline + pango_font_metrics_get_descent(metrics) / PANGO_SCALE; pango_font_metrics_unref(metrics); - pango_font_description_free(description); g_object_unref(pango); cairo_destroy(cairo); } diff --git a/include/pango.h b/include/pango.h index 93affc236f..2f14d2bba5 100644 --- a/include/pango.h +++ b/include/pango.h @@ -17,7 +17,7 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text, double scale, bool markup); void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, int *baseline, double scale, bool markup, const char *fmt, ...); -void get_text_metrics(const char *font, int *height, int *baseline); +void get_text_metrics(const PangoFontDescription *font, int *height, int *baseline); void render_text(cairo_t *cairo, const char *font, double scale, bool markup, const char *fmt, ...); diff --git a/include/sway/config.h b/include/sway/config.h index 05678c3342..8939af004a 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -17,6 +17,7 @@ #include "sway/input/tablet.h" #include "sway/tree/root.h" #include "wlr-layer-shell-unstable-v1-protocol.h" +#include // TODO: Refactor this shit @@ -504,7 +505,8 @@ struct sway_config { char *floating_scroll_right_cmd; enum sway_container_layout default_orientation; enum sway_container_layout default_layout; - char *font; + char *font; // Use mostly for IPC. + PangoFontDescription *font_description; // Used internally for rendering and validating. int font_height; int font_baseline; bool pango_markup; diff --git a/sway/commands/font.c b/sway/commands/font.c index 3eda0a9c68..74bb6b9f46 100644 --- a/sway/commands/font.c +++ b/sway/commands/font.c @@ -4,6 +4,7 @@ #include "sway/config.h" #include "log.h" #include "stringop.h" +#include struct cmd_results *cmd_font(int argc, char **argv) { struct cmd_results *error = NULL; @@ -22,6 +23,28 @@ struct cmd_results *cmd_font(int argc, char **argv) { config->font = font; } + // Parse the font early so we can reject it if it's not valid for pango. + // Also avoids re-parsing each time we render text. + PangoFontDescription *font_description = pango_font_description_from_string(config->font); + + const char *family = pango_font_description_get_family(font_description); + if (family == NULL) { + pango_font_description_free(font_description); + return cmd_results_new(CMD_FAILURE, "Invalid font family."); + } + + const gint size = pango_font_description_get_size(font_description); + if (size == 0) { + pango_font_description_free(font_description); + return cmd_results_new(CMD_FAILURE, "Invalid font size."); + } + + if (config->font_description != NULL) { + pango_font_description_free(config->font_description); + } + + config->font_description = font_description; config_update_font_height(); + return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/config.c b/sway/config.c index 8220ece04f..b41dd871b9 100644 --- a/sway/config.c +++ b/sway/config.c @@ -243,6 +243,7 @@ static void config_defaults(struct sway_config *config) { config->default_layout = L_NONE; config->default_orientation = L_NONE; if (!(config->font = strdup("monospace 10"))) goto cleanup; + config->font_description = pango_font_description_from_string(config->font); config->urgent_timeout = 500; config->focus_on_window_activation = FOWA_URGENT; config->popup_during_fullscreen = POPUP_SMART; @@ -1006,7 +1007,7 @@ int workspace_output_cmp_workspace(const void *a, const void *b) { void config_update_font_height(void) { int prev_max_height = config->font_height; - get_text_metrics(config->font, &config->font_height, &config->font_baseline); + get_text_metrics(config->font_description, &config->font_height, &config->font_baseline); if (config->font_height != prev_max_height) { arrange_root();