From b31e7565c314d32ee6ffb64f5488b355ade6dae1 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 31 Jul 2012 16:49:32 +0200 Subject: [PATCH] text: add text renderer subsystem The text-renderer subsystem provides a way to register arbitrary text-rendering backends. These backends use the font-objects to draw the console into a framebuffer. Signed-off-by: David Herrmann --- src/text.c | 391 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/text.h | 56 +++++++++ 2 files changed, 447 insertions(+) create mode 100644 src/text.c diff --git a/src/text.c b/src/text.c new file mode 100644 index 0000000..1a9bc60 --- /dev/null +++ b/src/text.c @@ -0,0 +1,391 @@ +/* + * kmscon - Text Renderer + * + * Copyright (c) 2012 David Herrmann + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * SECTION:text + * @short_description: Text Renderer + * @include: text.h + * + * TODO + */ + +#include +#include +#include +#include +#include "font.h" +#include "log.h" +#include "static_misc.h" +#include "text.h" +#include "uterm.h" + +#define LOG_SUBSYSTEM "text" + +struct text_backend { + struct kmscon_dlist list; + const struct kmscon_text_ops *ops; +}; + +static pthread_mutex_t text_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct kmscon_dlist text__list = KMSCON_DLIST_INIT(text__list); + +static void text_lock() +{ + pthread_mutex_lock(&text_mutex); +} + +static void text_unlock() +{ + pthread_mutex_unlock(&text_mutex); +} + +/** + * kmscon_text_register: + * @ops: Text operations and name for new backend + * + * This register a new text backend with operations set to @ops. The name + * @ops->name must be valid. + * + * The first font that is registered automatically becomes the default and + * fallback. So make sure you register a safe fallback as first backend. + * If this is unregistered, the next in the list becomes the default + * and fallback. + * + * Returns: 0 on success, negative error code on failure + */ +int kmscon_text_register(const struct kmscon_text_ops *ops) +{ + struct kmscon_dlist *iter; + struct text_backend *be; + int ret; + + if (!ops || !ops->name) + return -EINVAL; + + log_debug("register text backend %s", ops->name); + + text_lock(); + + kmscon_dlist_for_each(iter, &text__list) { + be = kmscon_dlist_entry(iter, struct text_backend, list); + if (!strcmp(be->ops->name, ops->name)) { + log_error("registering already available backend %s", + ops->name); + ret = -EALREADY; + goto out_unlock; + } + } + + be = malloc(sizeof(*be)); + if (!be) { + log_error("cannot allocate memory for backend"); + ret = -ENOMEM; + goto out_unlock; + } + + memset(be, 0, sizeof(*be)); + be->ops = ops; + kmscon_dlist_link(&text__list, &be->list); + + ret = 0; + +out_unlock: + text_unlock(); + return ret; +} + +/** + * kmscon_text_unregister: + * @name: Name of backend + * + * This unregisters the text-backend that is registered with name @name. If + * @name is not found, a warning is printed but nothing else is done. + */ +void kmscon_text_unregister(const char *name) +{ + struct kmscon_dlist *iter; + struct text_backend *be; + + if (!name) + return; + + log_debug("unregister backend %s", name); + + text_lock(); + + kmscon_dlist_for_each(iter, &text__list) { + be = kmscon_dlist_entry(iter, struct text_backend, list); + if (strcmp(name, be->ops->name)) + continue; + + kmscon_dlist_unlink(&be->list); + break; + } + + if (iter == &text__list) + be = NULL; + + text_unlock(); + + if (!be) { + log_error("cannot unregister backend %s: not found", name); + } else { + free(be); + } +} + +/** + * kmscon_text_new: + * @out: A pointer to the new text-renderer is stored here + * @backend: Backend to use or NULL for default backend + * + * Returns: 0 on success, error code on failure + */ +int kmscon_text_new(struct kmscon_text **out, + const char *backend) +{ + struct kmscon_text *text; + struct kmscon_dlist *iter; + struct text_backend *be, *def; + int ret; + + if (!out) + return -EINVAL; + + text_lock(); + + if (kmscon_dlist_empty(&text__list)) { + log_error("no text backend available"); + ret = -EFAULT; + } else { + ret = 0; + def = kmscon_dlist_entry(text__list.next, + struct text_backend, + list); + if (!backend) { + be = def; + } else { + kmscon_dlist_for_each(iter, &text__list) { + be = kmscon_dlist_entry(iter, + struct text_backend, + list); + if (!strcmp(backend, be->ops->name)) + break; + } + if (iter == &text__list) { + log_warning("requested backend %s not found", + backend); + be = def; + } + } + } + + if (ret) + goto out_unlock; + + text = malloc(sizeof(*text)); + if (!text) { + log_error("cannot allocate memory for new text-renderer"); + ret = -ENOMEM; + goto out_unlock; + } + memset(text, 0, sizeof(*text)); + text->ref = 1; + text->ops = be->ops; + + ret = text->ops->init(text); + if (ret) { + if (be == def) { + log_error("default backend %s cannot create renderer", + text->ops->name); + goto err_free; + } + + log_warning("backend %s cannot create renderer; trying default backend %s", + be->ops->name, def->ops->name); + + memset(text, 0, sizeof(*text)); + text->ref = 1; + text->ops = def->ops; + + ret = text->ops->init(text); + if (ret) { + log_error("default backend %s cannot create renderer", + text->ops->name); + goto err_free; + } + } + + log_debug("using: be: %s", text->ops->name); + *out = text; + ret = 0; + goto out_unlock; + +err_free: + free(text); +out_unlock: + text_unlock(); + return ret; +} + +/** + * kmscon_text_ref: + * @text: Valid text-renderer object + * + * This increases the reference count of @text by one. + */ +void kmscon_text_ref(struct kmscon_text *text) +{ + if (!text || !text->ref) + return; + + ++text->ref; +} + +/** + * kmscon_text_unref: + * @text: Valid text-renderer object + * + * This decreases the reference count of @text by one. If it drops to zero, the + * object is freed. + */ +void kmscon_text_unref(struct kmscon_text *text) +{ + if (!text || !text->ref || --text->ref) + return; + + text_lock(); + log_debug("freeing text renderer"); + text->ops->destroy(text); + kmscon_font_unref(text->font); + uterm_screen_unref(text->screen); + free(text); + text_unlock(); +} + +/** + * kmscon_text_set_font: + * @txt: Valid text-renderer object + * @font: Valid font object + * + * This makes the text-renderer @txt use the font @font. You can drop your + * reference to @font after calling this. + */ +void kmscon_text_set_font(struct kmscon_text *txt, + struct kmscon_font *font) +{ + if (!txt || !font) + return; + + kmscon_font_unref(txt->font); + txt->font = font; + kmscon_font_ref(txt->font); + + txt->ops->new_font(txt); +} + +/** + * kmscon_text_set_bgcolor: + * @txt: Valid text-renderer object + * @r: red value + * @g: green value + * @b: blue value + * + * This sets the background color to r/g/b. The background color is a solid + * color which is used for the whole background. You should give the same as the + * default background color of your characters as this will speed up the drawing + * operations. + */ +void kmscon_text_set_bgcolor(struct kmscon_text *txt, + uint8_t r, uint8_t g, uint8_t b) +{ + if (!txt) + return; + + txt->bg_r = r; + txt->bg_g = g; + txt->bg_b = b; + + txt->ops->new_bgcolor(txt); +} + +void kmscon_text_set_screen(struct kmscon_text *txt, + struct uterm_screen *screen) +{ + if (!txt || !screen) + return; + + uterm_screen_unref(txt->screen); + txt->screen = screen; + uterm_screen_ref(txt->screen); + + txt->ops->new_screen(txt); +} + +unsigned int kmscon_text_get_cols(struct kmscon_text *txt) +{ + if (!txt) + return 0; + + return txt->cols; +} + +unsigned int kmscon_text_get_rows(struct kmscon_text *txt) +{ + if (!txt) + return 0; + + return txt->rows; +} + +void kmscon_text_prepare(struct kmscon_text *txt) +{ + if (!txt || !txt->font || !txt->screen) + return; + + txt->rendering = true; + txt->ops->prepare(txt); +} + +void kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch, + unsigned int posx, unsigned int posy, + const struct font_char_attr *attr) +{ + if (!txt || !txt->rendering) + return; + if (posx >= txt->cols || posy >= txt->rows || !attr) + return; + + txt->ops->draw(txt, ch, posx, posy, attr); +} + +void kmscon_text_render(struct kmscon_text *txt) +{ + if (!txt || !txt->rendering) + return; + + txt->ops->render(txt); + txt->rendering = false; +} diff --git a/src/text.h b/src/text.h index c1944af..944e727 100644 --- a/src/text.h +++ b/src/text.h @@ -39,6 +39,7 @@ #define KMSCON_TEXT_H #include +#include "font.h" #include "unicode.h" #include "uterm.h" @@ -106,6 +107,61 @@ int kmscon_font_render(struct kmscon_font *font, kmscon_symbol_t sym, void kmscon_font_drop(struct kmscon_font *font, const struct kmscon_glyph *glyph); +/* text renderer */ + +struct kmscon_text; +struct kmscon_text_ops; + +struct kmscon_text { + unsigned long ref; + const struct kmscon_text_ops *ops; + struct kmscon_font *font; + struct uterm_screen *screen; + uint8_t bg_r; + uint8_t bg_g; + uint8_t bg_b; + unsigned int cols; + unsigned int rows; + bool rendering; + void *data; +}; + +struct kmscon_text_ops { + const char *name; + int (*init) (struct kmscon_text *txt); + void (*destroy) (struct kmscon_text *txt); + void (*new_font) (struct kmscon_text *txt); + void (*new_bgcolor) (struct kmscon_text *txt); + void (*new_screen) (struct kmscon_text *txt); + void (*prepare) (struct kmscon_text *txt); + void (*draw) (struct kmscon_text *txt, kmscon_symbol_t ch, + unsigned int posx, unsigned int posy, + const struct font_char_attr *attr); + void (*render) (struct kmscon_text *txt); +}; + +int kmscon_text_register(const struct kmscon_text_ops *ops); +void kmscon_text_unregister(const char *name); + +int kmscon_text_new(struct kmscon_text **out, const char *backend); +void kmscon_text_ref(struct kmscon_text *txt); +void kmscon_text_unref(struct kmscon_text *txt); + +void kmscon_text_set_font(struct kmscon_text *txt, + struct kmscon_font *font); +void kmscon_text_set_bgcolor(struct kmscon_text *txt, + uint8_t r, uint8_t g, uint8_t b); +void kmscon_text_set_screen(struct kmscon_text *txt, + struct uterm_screen *screen); +unsigned int kmscon_text_get_cols(struct kmscon_text *txt); +unsigned int kmscon_text_get_rows(struct kmscon_text *txt); + +void kmscon_text_prepare(struct kmscon_text *txt); +void kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch, + unsigned int posx, unsigned int posy, + const struct font_char_attr *attr); +void kmscon_text_render(struct kmscon_text *txt); + /* modularized backends */ int kmscon_font_8x16_load(void); -- 2.7.4