diff --git a/include/common/scaled_font_buffer.h b/include/common/scaled_font_buffer.h new file mode 100644 index 00000000..94debeaa --- /dev/null +++ b/include/common/scaled_font_buffer.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LAB_COMMON_SCALED_FONT_BUFFER_H +#define __LAB_COMMON_SCALED_FONT_BUFFER_H + +struct font; +struct wlr_scene_tree; +struct wlr_scene_buffer; +struct scaled_scene_buffere; + +struct scaled_font_buffer { + struct wlr_scene_buffer *scene_buffer; + int width; /* unscaled, read only */ + int height; /* unscaled, read only */ + + /* Private */ + char *text; + int max_width; + float color[4]; + struct font font; + struct scaled_scene_buffer *scaled_buffer; +}; + +/** + * Create an auto scaling font buffer, providing a wlr_scene_buffer node for + * display. It gets destroyed automatically when the backing scaled_scene_buffer + * is being destoyed which in turn happens automatically when the backing + * wlr_scene_buffer (or one of its parents) is being destroyed. + * + * To actually show some text, scaled_font_buffer_update() has to be called. + * + */ +struct scaled_font_buffer *scaled_font_buffer_create(struct wlr_scene_tree *parent); + +/** + * Update an existing auto scaling font buffer. + * + * No steps are taken to detect if its actually required to render a new buffer. + * This should be done by the caller to prevent useless recreation of the same + * buffer in case nothing actually changed. + * + * Some basic checks could be something like + * - truncated = buffer->width == max_width + * - text_changed = strcmp(old_text, new_text) + * - font and color the same + */ +void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text, + int max_width, struct font *font, float *color); + +#endif /* __LAB_COMMON_SCALED_FONT_BUFFER_H */ diff --git a/src/common/meson.build b/src/common/meson.build index 2e4407c8..d04e9f63 100644 --- a/src/common/meson.build +++ b/src/common/meson.build @@ -4,6 +4,7 @@ labwc_sources += files( 'font.c', 'grab-file.c', 'nodename.c', + 'scaled_font_buffer.c', 'scaled_scene_buffer.c', 'scene-helpers.c', 'spawn.c', diff --git a/src/common/scaled_font_buffer.c b/src/common/scaled_font_buffer.c new file mode 100644 index 00000000..66375a72 --- /dev/null +++ b/src/common/scaled_font_buffer.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include "buffer.h" +#include "common/font.h" +#include "common/scaled_scene_buffer.h" +#include "common/scaled_font_buffer.h" +#include "common/zfree.h" + +static struct lab_data_buffer * +_create_buffer(struct scaled_scene_buffer *scaled_buffer, double scale) +{ + struct lab_data_buffer *buffer; + struct scaled_font_buffer *self = scaled_buffer->data; + + /* Buffer gets free'd automatically along the backing wlr_buffer */ + font_buffer_create(&buffer, self->max_width, self->text, + &self->font, self->color, scale); + + self->width = buffer ? buffer->unscaled_width : 0; + self->height = buffer ? buffer->unscaled_height : 0; + return buffer; +} + +static void +_destroy(struct scaled_scene_buffer *scaled_buffer) +{ + struct scaled_font_buffer *self = scaled_buffer->data; + if (self->text) { + zfree(self->text); + } + if (self->font.name) { + zfree(self->font.name); + } + zfree(scaled_buffer->data); +} + +static const struct scaled_scene_buffer_impl impl = { + .create_buffer = _create_buffer, + .destroy = _destroy +}; + +/* Public API */ +struct scaled_font_buffer * +scaled_font_buffer_create(struct wlr_scene_tree *parent) +{ + assert(parent); + struct scaled_font_buffer *self = calloc(1, sizeof(*self)); + if (!self) { + return NULL; + } + + struct scaled_scene_buffer *scaled_buffer + = scaled_scene_buffer_create(parent, &impl); + if (!scaled_buffer) { + free(self); + return NULL; + } + + scaled_buffer->data = self; + self->scaled_buffer = scaled_buffer; + self->scene_buffer = scaled_buffer->scene_buffer; + return self; +} + +void +scaled_font_buffer_update(struct scaled_font_buffer *self, + const char *text, int max_width, struct font *font, float *color) +{ + assert(self); + assert(text); + assert(font); + assert(color); + + /* Clean up old internal state */ + if (self->text) { + zfree(self->text); + } + if (self->font.name) { + zfree(self->font.name); + } + + /* Update internal state */ + self->text = strdup(text); + self->max_width = max_width; + if (font->name) { + self->font.name = strdup(font->name); + } + self->font.size = font->size; + memcpy(self->color, color, sizeof(self->color)); + + /* Invalidate cache and force a new render */ + scaled_scene_buffer_invalidate_cache(self->scaled_buffer); +}