text: rework text renderer system
authorDavid Herrmann <dh.herrmann@googlemail.com>
Fri, 10 Aug 2012 09:42:00 +0000 (11:42 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Fri, 10 Aug 2012 09:42:00 +0000 (11:42 +0200)
This reworks the text renderer system to make it easier to write backends.
We also allow returning errors during rendering now.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/terminal.c
src/text.c
src/text.h
src/text_bblit.c

index a135365..b0d41c1 100644 (file)
@@ -184,9 +184,7 @@ static int add_display(struct kmscon_terminal *term, struct uterm_display *disp)
                goto err_font;
        }
 
-       kmscon_text_set_bgcolor(scr->txt, 0, 0, 0);
-       kmscon_text_set_font(scr->txt, scr->font);
-       kmscon_text_set_screen(scr->txt, scr->screen);
+       kmscon_text_set(scr->txt, scr->font, scr->screen);
 
        cols = kmscon_text_get_cols(scr->txt);
        rows = kmscon_text_get_rows(scr->txt);
index 177f3f1..78411e4 100644 (file)
@@ -214,7 +214,11 @@ int kmscon_text_new(struct kmscon_text **out,
        text->ref = 1;
        text->ops = be->ops;
 
-       ret = text->ops->init(text);
+       if (text->ops->init)
+               ret = text->ops->init(text);
+       else
+               ret = 0;
+
        if (ret) {
                if (be == def) {
                        log_error("default backend %s cannot create renderer",
@@ -275,74 +279,99 @@ 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);
+       kmscon_text_unset(text);
+
+       text_lock();
+
+       if (text->ops->destroy)
+               text->ops->destroy(text);
        free(text);
+
        text_unlock();
 }
 
 /**
- * kmscon_text_set_font:
+ * kmscon_text_set:
  * @txt: Valid text-renderer object
- * @font: Valid font object
+ * @font: font object
+ * @screen: screen object
  *
- * This makes the text-renderer @txt use the font @font. You can drop your
- * reference to @font after calling this.
+ * This makes the text-renderer @txt use the font @font and screen @screen. You
+ * can drop your reference to both after calling this.
+ * This calls kmscon_text_unset() first to remove all previous associations.
+ * None of the arguments can be NULL!
+ * If this function fails then you must assume that no font/screen will be set
+ * and the object is invalid.
+ *
+ * Returns: 0 on success, negative error code on failure.
  */
-void kmscon_text_set_font(struct kmscon_text *txt,
-                         struct kmscon_font *font)
+int kmscon_text_set(struct kmscon_text *txt,
+                   struct kmscon_font *font,
+                   struct uterm_screen *screen)
 {
-       if (!txt || !font)
-               return;
+       int ret;
+
+       if (!txt || !font || !screen)
+               return -EINVAL;
+
+       kmscon_text_unset(txt);
 
-       kmscon_font_unref(txt->font);
        txt->font = font;
+       txt->screen = screen;
+
+       if (txt->ops->set) {
+               ret = txt->ops->set(txt);
+               if (ret) {
+                       txt->font = NULL;
+                       txt->screen = NULL;
+                       return ret;
+               }
+       }
+
        kmscon_font_ref(txt->font);
+       uterm_screen_ref(txt->screen);
 
-       txt->ops->new_font(txt);
+       return 0;
 }
 
 /**
- * kmscon_text_set_bgcolor:
- * @txt: Valid text-renderer object
- * @r: red value
- * @g: green value
- * @b: blue value
+ * kmscon_text_unset():
+ * @txt: text renderer
  *
- * 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.
+ * This redos kmscon_text_set() by dropping the internal references to the font
+ * and screen and invalidating the object. You need to call kmscon_text_set()
+ * again to make use of this text renderer.
+ * This is automatically called when the text renderer is destroyed.
  */
-void kmscon_text_set_bgcolor(struct kmscon_text *txt,
-                            uint8_t r, uint8_t g, uint8_t b)
+void kmscon_text_unset(struct kmscon_text *txt)
 {
-       if (!txt)
+       if (!txt || !txt->screen || !txt->font)
                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;
+       if (txt->ops->unset)
+               txt->ops->unset(txt);
 
+       kmscon_font_unref(txt->font);
        uterm_screen_unref(txt->screen);
-       txt->screen = screen;
-       uterm_screen_ref(txt->screen);
-
-       txt->ops->new_screen(txt);
+       txt->font = NULL;
+       txt->screen = NULL;
+       txt->cols = 0;
+       txt->rows = 0;
+       txt->rendering = false;
 }
 
+/**
+ * kmscon_text_get_cols:
+ * @txt: valid text renderer
+ *
+ * After setting the arguments with kmscon_text_set(), the renderer will compute
+ * the number of columns/rows of the console that it can display on the screen.
+ * You can retrieve these values via these functions.
+ * If kmscon_text_set() hasn't been called, this will return 0.
+ *
+ * Returns: Number of columns or 0 if @txt is invalid
+ */
 unsigned int kmscon_text_get_cols(struct kmscon_text *txt)
 {
        if (!txt)
@@ -351,6 +380,17 @@ unsigned int kmscon_text_get_cols(struct kmscon_text *txt)
        return txt->cols;
 }
 
+/**
+ * kmscon_text_get_rows:
+ * @txt: valid text renderer
+ *
+ * After setting the arguments with kmscon_text_set(), the renderer will compute
+ * the number of columns/rows of the console that it can display on the screen.
+ * You can retrieve these values via these functions.
+ * If kmscon_text_set() hasn't been called, this will return 0.
+ *
+ * Returns: Number of rows or 0 if @txt is invalid
+ */
 unsigned int kmscon_text_get_rows(struct kmscon_text *txt)
 {
        if (!txt)
@@ -359,32 +399,101 @@ unsigned int kmscon_text_get_rows(struct kmscon_text *txt)
        return txt->rows;
 }
 
-void kmscon_text_prepare(struct kmscon_text *txt)
+/**
+ * kmscon_text_prepare:
+ * @txt: valid text renderer
+ *
+ * This starts a rendering-round. When rendering a console via a text renderer,
+ * you have to call this first, then render all your glyphs via
+ * kmscon_text_draw() and finally use kmscon_text_render(). If you modify this
+ * renderer during rendering or if you activate different OpenGL contexts in
+ * between, you need to restart rendering by calling kmscon_text_prepare() again
+ * and redoing everything from the beginning.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int kmscon_text_prepare(struct kmscon_text *txt)
 {
+       int ret = 0;
+
        if (!txt || !txt->font || !txt->screen)
-               return;
+               return -EINVAL;
 
        txt->rendering = true;
-       txt->ops->prepare(txt);
+       if (txt->ops->prepare)
+               ret = txt->ops->prepare(txt);
+       if (ret)
+               txt->rendering = false;
+
+       return ret;
 }
 
-void kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
+/**
+ * kmscon_text_draw:
+ * @txt: valid text renderer
+ * @ch: symbol you want to draw
+ * @posx: X-position of the glyph
+ * @posy: Y-position of the glyph
+ * @attr: glyph attributes
+ *
+ * This draws a single glyph at the requested position. The position is a
+ * console position, not a pixel position! You must precede this call with
+ * kmscon_text_prepare(). Use this function to feed all glyphs into the
+ * rendering pipeline and finally call kmscon_text_render().
+ *
+ * Returns: 0 on success or negative error code if this glyph couldn't be drawn.
+ */
+int 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;
+               return -EINVAL;
        if (posx >= txt->cols || posy >= txt->rows || !attr)
-               return;
+               return -EINVAL;
 
-       txt->ops->draw(txt, ch, posx, posy, attr);
+       return txt->ops->draw(txt, ch, posx, posy, attr);
 }
 
-void kmscon_text_render(struct kmscon_text *txt)
+/**
+ * kmscon_text_render:
+ * @txt: valid text renderer
+ *
+ * This does the final rendering round after kmscon_text_prepare() has been
+ * called and all glyphs were sent to the renderer via kmscon_text_draw().
+ *
+ * Returns: 0 on success, negative error on failure.
+ */
+int kmscon_text_render(struct kmscon_text *txt)
+{
+       int ret = 0;
+
+       if (!txt || !txt->rendering)
+               return -EINVAL;
+
+       if (txt->ops->render)
+               ret = txt->ops->render(txt);
+       txt->rendering = false;
+
+       return ret;
+}
+
+/**
+ * kmscon_text_abort:
+ * @txt: valid text renderer
+ *
+ * If you called kmscon_text_prepare() but you want to abort rendering instead
+ * of finishing it with kmscon_text_render(), you can safely call this to reset
+ * internal state. It is optional to call this or simply restart rendering.
+ * Especially if the other renderers return an error, then they probably already
+ * aborted rendering and it is not required to call this.
+ */
+void kmscon_text_abort(struct kmscon_text *txt)
 {
        if (!txt || !txt->rendering)
                return;
 
-       txt->ops->render(txt);
+       if (txt->ops->abort)
+               txt->ops->abort(txt);
        txt->rendering = false;
 }
index e48bb69..0b612ae 100644 (file)
@@ -133,29 +133,27 @@ struct kmscon_text_ops;
 struct kmscon_text {
        unsigned long ref;
        const struct kmscon_text_ops *ops;
+       void *data;
+
        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 (*set) (struct kmscon_text *txt);
+       void (*unset) (struct kmscon_text *txt);
+       int (*prepare) (struct kmscon_text *txt);
+       int (*draw) (struct kmscon_text *txt, kmscon_symbol_t ch,
+                    unsigned int posx, unsigned int posy,
+                    const struct font_char_attr *attr);
+       int (*render) (struct kmscon_text *txt);
+       void (*abort) (struct kmscon_text *txt);
 };
 
 int kmscon_text_register(const struct kmscon_text_ops *ops);
@@ -165,20 +163,19 @@ 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);
+int kmscon_text_set(struct kmscon_text *txt,
+                   struct kmscon_font *font,
+                   struct uterm_screen *screen);
+void kmscon_text_unset(struct kmscon_text *txt);
 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,
+int kmscon_text_prepare(struct kmscon_text *txt);
+int 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);
+int kmscon_text_render(struct kmscon_text *txt);
+void kmscon_text_abort(struct kmscon_text *txt);
 
 /* modularized backends */
 
index 50ebb2c..38adbd4 100644 (file)
 
 #define LOG_SUBSYSTEM "text_bblit"
 
-static int bblit_init(struct kmscon_text *txt)
-{
-       return 0;
-}
-
-static void bblit_destroy(struct kmscon_text *txt)
-{
-}
-
-static void bblit_recalculate_size(struct kmscon_text *txt)
+static int bblit_set(struct kmscon_text *txt)
 {
        unsigned int sw, sh, fw, fh;
 
-       if (!txt->font || !txt->screen)
-               return;
-
        fw = txt->font->attr.width;
        fh = txt->font->attr.height;
        sw = uterm_screen_width(txt->screen);
@@ -67,29 +55,13 @@ static void bblit_recalculate_size(struct kmscon_text *txt)
 
        txt->cols = sw / fw;
        txt->rows = sh / fh;
-}
-
-static void bblit_new_font(struct kmscon_text *txt)
-{
-       bblit_recalculate_size(txt);
-}
-
-static void bblit_new_bgcolor(struct kmscon_text *txt)
-{
-}
 
-static void bblit_new_screen(struct kmscon_text *txt)
-{
-       bblit_recalculate_size(txt);
-}
-
-static void bblit_prepare(struct kmscon_text *txt)
-{
+       return 0;
 }
 
-static void bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
-                      unsigned int posx, unsigned int posy,
-                      const struct font_char_attr *attr)
+static int bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
+                     unsigned int posx, unsigned int posy,
+                     const struct font_char_attr *attr)
 {
        const struct kmscon_glyph *glyph;
        int ret;
@@ -103,39 +75,37 @@ static void bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
        if (ret) {
                ret = kmscon_font_render_inval(txt->font, &glyph);
                if (ret)
-                       return;
+                       return ret;
        }
 
        /* draw glyph */
        if (attr->inverse) {
-               uterm_screen_blend(txt->screen, &glyph->buf,
-                                  posx * txt->font->attr.width,
-                                  posy * txt->font->attr.height,
-                                  attr->br, attr->bg, attr->bb,
-                                  attr->fr, attr->fg, attr->fb);
+               ret = uterm_screen_blend(txt->screen, &glyph->buf,
+                                        posx * txt->font->attr.width,
+                                        posy * txt->font->attr.height,
+                                        attr->br, attr->bg, attr->bb,
+                                        attr->fr, attr->fg, attr->fb);
        } else {
-               uterm_screen_blend(txt->screen, &glyph->buf,
-                                  posx * txt->font->attr.width,
-                                  posy * txt->font->attr.height,
-                                  attr->fr, attr->fg, attr->fb,
-                                  attr->br, attr->bg, attr->bb);
+               ret = uterm_screen_blend(txt->screen, &glyph->buf,
+                                        posx * txt->font->attr.width,
+                                        posy * txt->font->attr.height,
+                                        attr->fr, attr->fg, attr->fb,
+                                        attr->br, attr->bg, attr->bb);
        }
-}
 
-static void bblit_render(struct kmscon_text *txt)
-{
+       return ret;
 }
 
 static const struct kmscon_text_ops kmscon_text_bblit_ops = {
        .name = "bblit",
-       .init = bblit_init,
-       .destroy = bblit_destroy,
-       .new_font = bblit_new_font,
-       .new_bgcolor = bblit_new_bgcolor,
-       .new_screen = bblit_new_screen,
-       .prepare = bblit_prepare,
+       .init = NULL,
+       .destroy = NULL,
+       .set = bblit_set,
+       .unset = NULL,
+       .prepare = NULL,
        .draw = bblit_draw,
-       .render = bblit_render,
+       .render = NULL,
+       .abort = NULL,
 };
 
 int kmscon_text_bblit_load(void)