common/font: add scaled_font_buffer_create_for_titlebar()

Co-authored-by: tokyo4j <hrak1529@gmail.com>
This commit is contained in:
John Lindgren 2025-05-29 12:34:03 -04:00
parent 3ca7adace0
commit 54b236e027
4 changed files with 76 additions and 18 deletions

View file

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LABWC_FONT_H
#define LABWC_FONT_H
#include <cairo.h>
#include <pango/pango-font.h>
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

View file

@ -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,

View file

@ -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);

View file

@ -7,6 +7,7 @@
#include <wlr/util/log.h>
#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);
}