From 54b236e02721442abb974da85eff6b573b076aa6 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Thu, 29 May 2025 12:34:03 -0400 Subject: [PATCH] common/font: add scaled_font_buffer_create_for_titlebar() Co-authored-by: tokyo4j --- include/common/font.h | 9 ++++--- include/common/scaled-font-buffer.h | 24 +++++++++++++++++ src/common/font.c | 21 +++++++-------- src/common/scaled-font-buffer.c | 40 +++++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 18 deletions(-) diff --git a/include/common/font.h b/include/common/font.h index 17d1181e..a7a5ba55 100644 --- a/include/common/font.h +++ b/include/common/font.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #ifndef LABWC_FONT_H #define LABWC_FONT_H + +#include #include struct lab_data_buffer; @@ -36,14 +38,15 @@ void font_get_buffer_size(int max_width, const char *text, struct font *font, * font_buffer_create - Create ARGB8888 lab_data_buffer using pango * @buffer: buffer pointer * @max_width: max allowable width; will be ellipsized if longer + * @height: buffer height or -1 to compute from font * @text: text to be generated as texture * @font: font description * @color: foreground color in rgba format - * @bg_color: background color in rgba format + * @bg_pattern: background pattern */ void font_buffer_create(struct lab_data_buffer **buffer, int max_width, - const char *text, struct font *font, const float *color, - const float *bg_color, double scale); + int height, const char *text, struct font *font, const float *color, + cairo_pattern_t *bg_pattern, double scale); /** * font_finish - free some font related resources diff --git a/include/common/scaled-font-buffer.h b/include/common/scaled-font-buffer.h index e3de0248..ddccbc82 100644 --- a/include/common/scaled-font-buffer.h +++ b/include/common/scaled-font-buffer.h @@ -20,6 +20,16 @@ struct scaled_font_buffer { float bg_color[4]; struct font font; struct scaled_scene_buffer *scaled_buffer; + + /* + * The following fields are used only for the titlebar, where + * the font buffer can be rendered with a pattern background to + * support gradients. In this case, the font buffer is also + * padded to a fixed height (with the text centered vertically) + * in order to align the pattern with the rest of the titlebar. + */ + int fixed_height; + cairo_pattern_t *bg_pattern; /* overrides bg_color if set */ }; /** @@ -33,6 +43,17 @@ struct scaled_font_buffer { */ struct scaled_font_buffer *scaled_font_buffer_create(struct wlr_scene_tree *parent); +/** + * Create an auto scaling font buffer for titlebar text. + * The font buffer takes a new reference to bg_pattern. + * + * @param fixed_height Fixed height for the buffer (logical pixels) + * @param bg_pattern Background pattern (solid color or gradient) + */ +struct scaled_font_buffer * +scaled_font_buffer_create_for_titlebar(struct wlr_scene_tree *parent, + int fixed_height, cairo_pattern_t *bg_pattern); + /** * Update an existing auto scaling font buffer. * @@ -44,6 +65,9 @@ struct scaled_font_buffer *scaled_font_buffer_create(struct wlr_scene_tree *pare * - truncated = buffer->width == max_width * - text_changed = strcmp(old_text, new_text) * - font and color the same + * + * bg_color is ignored for font buffers created with + * scaled_font_buffer_create_for_titlebar(). */ void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text, int max_width, struct font *font, const float *color, diff --git a/src/common/font.c b/src/common/font.c index d2173467..9599c846 100644 --- a/src/common/font.c +++ b/src/common/font.c @@ -86,15 +86,18 @@ font_get_buffer_size(int max_width, const char *text, struct font *font, void font_buffer_create(struct lab_data_buffer **buffer, int max_width, - const char *text, struct font *font, const float *color, - const float *bg_color, double scale) + int height, const char *text, struct font *font, const float *color, + cairo_pattern_t *bg_pattern, double scale) { if (string_null_or_empty(text)) { return; } - int width, height; - font_get_buffer_size(max_width, text, font, &width, &height); + int width, computed_height; + font_get_buffer_size(max_width, text, font, &width, &computed_height); + if (height <= 0) { + height = computed_height; + } *buffer = buffer_create_cairo(width, height, scale); if (!*buffer) { @@ -114,18 +117,16 @@ font_buffer_create(struct lab_data_buffer **buffer, int max_width, * buffer unfilled (completely transparent) since the background * is already rendered by the scene element underneath. In this * case we have to disable subpixel rendering. - * - * Note: the 0.999 cutoff was chosen to be greater than 254/255 - * (about 0.996) but leave some margin for rounding errors. */ - bool opaque_bg = (bg_color[3] > 0.999f); + bool opaque_bg = is_pattern_opaque(bg_pattern); if (opaque_bg) { - set_cairo_color(cairo, bg_color); + cairo_set_source(cairo, bg_pattern); cairo_paint(cairo); } set_cairo_color(cairo, color); - cairo_move_to(cairo, 0, 0); + /* center vertically if height was explicitly specified */ + cairo_move_to(cairo, 0, (height - computed_height) / 2); PangoLayout *layout = pango_cairo_create_layout(cairo); pango_context_set_round_glyph_positions(pango_layout_get_context(layout), false); diff --git a/src/common/scaled-font-buffer.c b/src/common/scaled-font-buffer.c index e0d79a57..64584b03 100644 --- a/src/common/scaled-font-buffer.c +++ b/src/common/scaled-font-buffer.c @@ -7,6 +7,7 @@ #include #include "buffer.h" #include "common/font.h" +#include "common/graphic-helpers.h" #include "common/mem.h" #include "common/scaled-scene-buffer.h" #include "common/scaled-font-buffer.h" @@ -17,15 +18,23 @@ _create_buffer(struct scaled_scene_buffer *scaled_buffer, double scale) { struct lab_data_buffer *buffer = NULL; struct scaled_font_buffer *self = scaled_buffer->data; + cairo_pattern_t *bg_pattern = self->bg_pattern; + cairo_pattern_t *solid_bg_pattern = NULL; + + if (!bg_pattern) { + solid_bg_pattern = color_to_pattern(self->bg_color); + bg_pattern = solid_bg_pattern; + } /* Buffer gets free'd automatically along the backing wlr_buffer */ - font_buffer_create(&buffer, self->max_width, self->text, - &self->font, self->color, self->bg_color, scale); + font_buffer_create(&buffer, self->max_width, self->height, self->text, + &self->font, self->color, bg_pattern, scale); if (!buffer) { wlr_log(WLR_ERROR, "font_buffer_create() failed"); } + zfree_pattern(solid_bg_pattern); return buffer; } @@ -37,6 +46,7 @@ _destroy(struct scaled_scene_buffer *scaled_buffer) zfree(self->text); zfree(self->font.name); + zfree_pattern(self->bg_pattern); free(self); } @@ -54,7 +64,9 @@ _equal(struct scaled_scene_buffer *scaled_buffer_a, && a->font.slant == b->font.slant && a->font.weight == b->font.weight && !memcmp(a->color, b->color, sizeof(a->color)) - && !memcmp(a->bg_color, b->bg_color, sizeof(a->bg_color)); + && !memcmp(a->bg_color, b->bg_color, sizeof(a->bg_color)) + && a->fixed_height == b->fixed_height + && a->bg_pattern == b->bg_pattern; } static const struct scaled_scene_buffer_impl impl = { @@ -82,6 +94,18 @@ scaled_font_buffer_create(struct wlr_scene_tree *parent) return self; } +struct scaled_font_buffer * +scaled_font_buffer_create_for_titlebar(struct wlr_scene_tree *parent, + int fixed_height, cairo_pattern_t *bg_pattern) +{ + struct scaled_font_buffer *self = scaled_font_buffer_create(parent); + if (self) { + self->fixed_height = fixed_height; + self->bg_pattern = cairo_pattern_reference(bg_pattern); + } + return self; +} + void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text, int max_width, struct font *font, const float *color, @@ -109,8 +133,11 @@ scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text, memcpy(self->bg_color, bg_color, sizeof(self->bg_color)); /* Calculate the size of font buffer and request re-rendering */ + int computed_height; font_get_buffer_size(self->max_width, self->text, &self->font, - &self->width, &self->height); + &self->width, &computed_height); + self->height = (self->fixed_height > 0) ? + self->fixed_height : computed_height; scaled_scene_buffer_request_update(self->scaled_buffer, self->width, self->height); } @@ -120,8 +147,11 @@ scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width) { self->max_width = max_width; + int computed_height; font_get_buffer_size(self->max_width, self->text, &self->font, - &self->width, &self->height); + &self->width, &computed_height); + self->height = (self->fixed_height > 0) ? + self->fixed_height : computed_height; scaled_scene_buffer_request_update(self->scaled_buffer, self->width, self->height); }