Skip to content

Commit

Permalink
Reject font values that are invalid for pango
Browse files Browse the repository at this point in the history
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: #6805
  • Loading branch information
Hugo Osvaldo Barrera authored and emersion committed Jul 1, 2022
1 parent 9e8866a commit 7560549
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 6 deletions.
4 changes: 1 addition & 3 deletions common/pango.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,16 @@ 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);

*baseline = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
*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);
}
Expand Down
2 changes: 1 addition & 1 deletion include/pango.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...);

Expand Down
4 changes: 3 additions & 1 deletion include/sway/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "sway/input/tablet.h"
#include "sway/tree/root.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include <pango/pangocairo.h>

// TODO: Refactor this shit

Expand Down Expand Up @@ -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;
Expand Down
23 changes: 23 additions & 0 deletions sway/commands/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "sway/config.h"
#include "log.h"
#include "stringop.h"
#include <pango/pangocairo.h>

struct cmd_results *cmd_font(int argc, char **argv) {
struct cmd_results *error = NULL;
Expand All @@ -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);
}
3 changes: 2 additions & 1 deletion sway/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 7560549

Please sign in to comment.