Modify it to adjust Tizen IVI enviroment
[platform/upstream/kmscon.git] / src / text.c
index b2db07c..d7e5f0e 100644 (file)
 #include <pthread.h>
 #include <stdlib.h>
 #include <string.h>
-#include "log.h"
-#include "static_misc.h"
+#include "shl_dlist.h"
+#include "shl_log.h"
+#include "shl_misc.h"
+#include "shl_register.h"
 #include "text.h"
-#include "uterm.h"
+#include "uterm_video.h"
 
 #define LOG_SUBSYSTEM "text"
 
-struct text_backend {
-       struct kmscon_dlist list;
-       const struct kmscon_text_ops *ops;
-};
+static struct shl_register text_reg = SHL_REGISTER_INIT(text_reg);
 
-static pthread_mutex_t text_mutex = PTHREAD_MUTEX_INITIALIZER;
-static struct kmscon_dlist text__list = KMSCON_DLIST_INIT(text__list);
-
-static void text_lock()
+static inline void kmscon_text_destroy(void *data)
 {
-       pthread_mutex_lock(&text_mutex);
-}
+       const struct kmscon_text_ops *ops = data;
 
-static void text_unlock()
-{
-       pthread_mutex_unlock(&text_mutex);
+       kmscon_module_unref(ops->owner);
 }
 
 /**
@@ -74,45 +67,26 @@ static void text_unlock()
  *
  * Returns: 0 on success, negative error code on failure
  */
+SHL_EXPORT
 int kmscon_text_register(const struct kmscon_text_ops *ops)
 {
-       struct kmscon_dlist *iter;
-       struct text_backend *be;
        int ret;
 
-       if (!ops || !ops->name)
+       if (!ops)
                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;
+       ret = shl_register_add_cb(&text_reg, ops->name, (void*)ops,
+                                 kmscon_text_destroy);
+       if (ret) {
+               log_error("cannot register text backend %s: %d", ops->name,
+                         ret);
+               return ret;
        }
 
-       memset(be, 0, sizeof(*be));
-       be->ops = ops;
-       kmscon_dlist_link(&text__list, &be->list);
-
-       ret = 0;
-
-out_unlock:
-       text_unlock();
-       return ret;
+       kmscon_module_ref(ops->owner);
+       return 0;
 }
 
 /**
@@ -120,39 +94,49 @@ out_unlock:
  * @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.
+ * @name is not found, nothing is done.
  */
+SHL_EXPORT
 void kmscon_text_unregister(const char *name)
 {
-       struct kmscon_dlist *iter;
-       struct text_backend *be;
-
-       if (!name)
-               return;
-
        log_debug("unregister backend %s", name);
+       shl_register_remove(&text_reg, name);
+}
 
-       text_lock();
+static int new_text(struct kmscon_text *text, const char *backend)
+{
+       struct shl_register_record *record;
+       const char *name = backend ? backend : "<default>";
+       int ret;
 
-       kmscon_dlist_for_each(iter, &text__list) {
-               be = kmscon_dlist_entry(iter, struct text_backend, list);
-               if (strcmp(name, be->ops->name))
-                       continue;
+       memset(text, 0, sizeof(*text));
+       text->ref = 1;
+
+       if (backend)
+               record = shl_register_find(&text_reg, backend);
+       else
+               record = shl_register_first(&text_reg);
 
-               kmscon_dlist_unlink(&be->list);
-               break;
+       if (!record) {
+               log_error("requested backend '%s' not found", name);
+               return -ENOENT;
        }
 
-       if (iter == &text__list)
-               be = NULL;
+       text->record = record;
+       text->ops = record->data;
 
-       text_unlock();
+       if (text->ops->init)
+               ret = text->ops->init(text);
+       else
+               ret = 0;
 
-       if (!be) {
-               log_error("cannot unregister backend %s: not found", name);
-       } else {
-               free(be);
+       if (ret) {
+               log_warning("backend %s cannot create renderer", name);
+               shl_register_record_unref(record);
+               return ret;
        }
+
+       return 0;
 }
 
 /**
@@ -162,94 +146,34 @@ void kmscon_text_unregister(const char *name)
  *
  * Returns: 0 on success, error code on failure
  */
-int kmscon_text_new(struct kmscon_text **out,
-                   const char *backend)
+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.prev,
-                                        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;
+               return -ENOMEM;
        }
-       memset(text, 0, sizeof(*text));
-       text->ref = 1;
-       text->ops = be->ops;
-
-       if (text->ops->init)
-               ret = text->ops->init(text);
-       else
-               ret = 0;
 
+       ret = new_text(text, backend);
        if (ret) {
-               if (be == def) {
-                       log_error("default backend %s cannot create renderer",
-                                 text->ops->name);
+               if (backend)
+                       ret = new_text(text, NULL);
+               if (ret)
                        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;
+       return 0;
 
 err_free:
        free(text);
-out_unlock:
-       text_unlock();
        return ret;
 }
 
@@ -282,20 +206,18 @@ void kmscon_text_unref(struct kmscon_text *text)
        log_debug("freeing text renderer");
        kmscon_text_unset(text);
 
-       text_lock();
-
        if (text->ops->destroy)
                text->ops->destroy(text);
+       shl_register_record_unref(text->record);
        free(text);
-
-       text_unlock();
 }
 
 /**
  * kmscon_text_set:
  * @txt: Valid text-renderer object
  * @font: font object
- * @screen: screen object
+ * @bold_font: bold font object or NULL
+ * @disp: display object
  *
  * This makes the text-renderer @txt use the font @font and screen @screen. You
  * can drop your reference to both after calling this.
@@ -303,34 +225,44 @@ void kmscon_text_unref(struct kmscon_text *text)
  * 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.
+ * If @bold_font is NULL, @font is also used for bold characters. The caller
+ * must make sure that @font and @bold_font have the same metrics. The renderers
+ * will always use the metrics of @font.
  *
  * Returns: 0 on success, negative error code on failure.
  */
 int kmscon_text_set(struct kmscon_text *txt,
                    struct kmscon_font *font,
-                   struct uterm_screen *screen)
+                   struct kmscon_font *bold_font,
+                   struct uterm_display *disp)
 {
        int ret;
 
-       if (!txt || !font || !screen)
+       if (!txt || !font || !disp)
                return -EINVAL;
 
+       if (!bold_font)
+               bold_font = font;
+
        kmscon_text_unset(txt);
 
        txt->font = font;
-       txt->screen = screen;
+       txt->bold_font = bold_font;
+       txt->disp = disp;
 
        if (txt->ops->set) {
                ret = txt->ops->set(txt);
                if (ret) {
                        txt->font = NULL;
-                       txt->screen = NULL;
+                       txt->bold_font = NULL;
+                       txt->disp = NULL;
                        return ret;
                }
        }
 
        kmscon_font_ref(txt->font);
-       uterm_screen_ref(txt->screen);
+       kmscon_font_ref(txt->bold_font);
+       uterm_display_ref(txt->disp);
 
        return 0;
 }
@@ -346,16 +278,18 @@ int kmscon_text_set(struct kmscon_text *txt,
  */
 void kmscon_text_unset(struct kmscon_text *txt)
 {
-       if (!txt || !txt->screen || !txt->font)
+       if (!txt || !txt->disp || !txt->font)
                return;
 
        if (txt->ops->unset)
                txt->ops->unset(txt);
 
        kmscon_font_unref(txt->font);
-       uterm_screen_unref(txt->screen);
+       kmscon_font_unref(txt->bold_font);
+       uterm_display_unref(txt->disp);
        txt->font = NULL;
-       txt->screen = NULL;
+       txt->bold_font = NULL;
+       txt->disp = NULL;
        txt->cols = 0;
        txt->rows = 0;
        txt->rendering = false;
@@ -416,7 +350,7 @@ int kmscon_text_prepare(struct kmscon_text *txt)
 {
        int ret = 0;
 
-       if (!txt || !txt->font || !txt->screen)
+       if (!txt || !txt->font || !txt->disp)
                return -EINVAL;
 
        txt->rendering = true;
@@ -431,7 +365,10 @@ int kmscon_text_prepare(struct kmscon_text *txt)
 /**
  * kmscon_text_draw:
  * @txt: valid text renderer
- * @ch: symbol you want to draw
+ * @id: a unique ID that identifies @ch globally
+ * @ch: ucs4 symbol you want to draw
+ * @len: length of @ch or 0 for empty cell
+ * @width: cell-width of character
  * @posx: X-position of the glyph
  * @posy: Y-position of the glyph
  * @attr: glyph attributes
@@ -443,16 +380,18 @@ int kmscon_text_prepare(struct kmscon_text *txt)
  *
  * 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)
+int kmscon_text_draw(struct kmscon_text *txt,
+                    uint32_t id, const uint32_t *ch, size_t len,
+                    unsigned int width,
+                    unsigned int posx, unsigned int posy,
+                    const struct tsm_screen_attr *attr)
 {
        if (!txt || !txt->rendering)
                return -EINVAL;
        if (posx >= txt->cols || posy >= txt->rows || !attr)
                return -EINVAL;
 
-       return txt->ops->draw(txt, ch, posx, posy, attr);
+       return txt->ops->draw(txt, id, ch, len, width, posx, posy, attr);
 }
 
 /**
@@ -497,3 +436,13 @@ void kmscon_text_abort(struct kmscon_text *txt)
                txt->ops->abort(txt);
        txt->rendering = false;
 }
+
+int kmscon_text_draw_cb(struct tsm_screen *con,
+                       uint32_t id, const uint32_t *ch, size_t len,
+                       unsigned int width,
+                       unsigned int posx, unsigned int posy,
+                       const struct tsm_screen_attr *attr,
+                       tsm_age_t age, void *data)
+{
+       return kmscon_text_draw(data, id, ch, len, width, posx, posy, attr);
+}