Remove old font renderer sources
authorDavid Herrmann <dh.herrmann@googlemail.com>
Wed, 1 Aug 2012 13:42:35 +0000 (15:42 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Wed, 1 Aug 2012 13:42:35 +0000 (15:42 +0200)
font_freetype.c was unused for long and font_pango.c has been removed
recently.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/font_freetype.c [deleted file]
src/font_pango.c [deleted file]

diff --git a/src/font_freetype.c b/src/font_freetype.c
deleted file mode 100644 (file)
index 8cbe630..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * kmscon - Font Handling - FreeType2 Backend
- *
- * Copyright (c) 2011 David Herrmann <dh.herrmann@googlemail.com>
- * Copyright (c) 2011 University of Tuebingen
- *
- * 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.
- */
-
-/*
- * Font Handling - FreeType2
- * This provides a font backend based on FreeType2 library. This is inferior to
- * the pango backend as it does not handle combined characters. However, it
- * pulls in a lot less dependencies so may be prefered on some systems.
- */
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include "font.h"
-#include "gl.h"
-#include "log.h"
-#include "static_misc.h"
-#include "unicode.h"
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#define LOG_SUBSYSTEM "font_freetype2"
-
-struct kmscon_font_factory {
-       unsigned long ref;
-       FT_Library lib;
-};
-
-struct kmscon_font {
-       unsigned long ref;
-
-       struct kmscon_font_factory *ff;
-       FT_Face face;
-       unsigned int width;
-       unsigned int height;
-       struct kmscon_hashtable *glyphs;
-};
-
-struct kmscon_glyph {
-       bool valid;
-       unsigned int tex;
-       unsigned int width;
-       unsigned int height;
-       int left;
-       int top;
-       unsigned int advance;
-};
-
-static int kmscon_glyph_new(struct kmscon_glyph **out, kmscon_symbol_t key,
-                                               struct kmscon_font *font)
-{
-       struct kmscon_glyph *glyph;
-       FT_Error err;
-       FT_UInt idx;
-       FT_Bitmap *bmap;
-       int ret;
-       const uint32_t *val;
-       size_t len;
-       unsigned char *data, d;
-       int i, j;
-
-       if (!out)
-               return -EINVAL;
-
-       glyph = malloc(sizeof(*glyph));
-       if (!glyph)
-               return -ENOMEM;
-
-       memset(glyph, 0, sizeof(*glyph));
-
-       val = kmscon_symbol_get(&key, &len);
-
-       if (!val[0])
-               goto ready;
-
-       /* TODO: Add support for combining characters */
-       idx = FT_Get_Char_Index(font->face, val[0]);
-       err = FT_Load_Glyph(font->face, idx, FT_LOAD_DEFAULT);
-       if (err) {
-               ret = -EFAULT;
-               goto err_free;
-       }
-
-       err = FT_Render_Glyph(font->face->glyph, FT_RENDER_MODE_NORMAL);
-       if (err) {
-               ret = -EFAULT;
-               goto err_free;
-       }
-
-       bmap = &font->face->glyph->bitmap;
-       if (!bmap->width || !bmap->rows)
-               goto ready;
-
-       glyph->tex = gl_tex_new();
-       data = malloc(sizeof(unsigned char) * bmap->width * bmap->rows * 4);
-       if (!data) {
-               ret = -ENOMEM;
-               goto err_tex;
-       }
-
-       for (j = 0; j < bmap->rows; ++j) {
-               for (i = 0; i < bmap->width; ++i) {
-                       d = bmap->buffer[i + bmap->width * j];
-                       data[4 * (i + j * bmap->width)] = d;
-                       data[4 * (i + j * bmap->width) + 1] = d;
-                       data[4 * (i + j * bmap->width) + 2] = d;
-                       data[4 * (i + j * bmap->width) + 3] = d;
-               }
-       }
-
-       gl_tex_load(glyph->tex, bmap->width, 0, bmap->rows, data);
-       free(data);
-
-       glyph->width = bmap->width;
-       glyph->height = bmap->rows;
-       glyph->left = font->face->glyph->bitmap_left;
-       glyph->top = font->face->glyph->bitmap_top;
-       glyph->advance = font->face->glyph->advance.x >> 6;
-       glyph->valid = true;
-
-ready:
-       *out = glyph;
-       return 0;
-
-err_tex:
-       gl_tex_free(glyph->tex);
-err_free:
-       free(glyph);
-       return ret;
-}
-
-static void kmscon_glyph_destroy(struct kmscon_glyph *glyph)
-{
-       if (!glyph)
-               return;
-
-       if (glyph->valid)
-               gl_tex_free(glyph->tex);
-       free(glyph);
-}
-
-int kmscon_font_factory_new(struct kmscon_font_factory **out)
-{
-       struct kmscon_font_factory *ff;
-       FT_Error err;
-       int ret;
-
-       if (!out)
-               return -EINVAL;
-
-       ff = malloc(sizeof(*ff));
-       if (!ff)
-               return -ENOMEM;
-
-       memset(ff, 0, sizeof(*ff));
-       ff->ref = 1;
-
-       err = FT_Init_FreeType(&ff->lib);
-       if (err) {
-               log_warn("cannot initialize FreeType library");
-               ret = -EFAULT;
-               goto err_free;
-       }
-
-       log_debug("new font factory");
-       *out = ff;
-
-       return 0;
-
-err_free:
-       free(ff);
-       return ret;
-}
-
-void kmscon_font_factory_ref(struct kmscon_font_factory *ff)
-{
-       if (!ff)
-               return;
-
-       ++ff->ref;
-}
-
-void kmscon_font_factory_unref(struct kmscon_font_factory *ff)
-{
-       FT_Error err;
-
-       if (!ff || !ff->ref)
-               return;
-
-       if (--ff->ref)
-               return;
-
-       log_debug("destroying font factory");
-
-       err = FT_Done_FreeType(ff->lib);
-       if (err)
-               log_warn("cannot deinitialize FreeType library");
-
-       free(ff);
-}
-
-int kmscon_font_factory_load(struct kmscon_font_factory *ff,
-       struct kmscon_font **out, unsigned int width, unsigned int height)
-{
-       struct kmscon_font *font;
-       FT_Error err;
-       const char *estr = "unknown error";
-       int ret;
-       const char *path = "./fonts/DejaVuSansMono.ttf";
-
-       if (!ff || !out || !height)
-               return -EINVAL;
-
-       if (!width)
-               width = height;
-
-       log_debug("loading new font %s", path);
-
-       font = malloc(sizeof(*font));
-       if (!font)
-               return -ENOMEM;
-
-       memset(font, 0, sizeof(*font));
-       font->ref = 1;
-       font->width = width;
-       font->height = height;
-
-       /* TODO: Use fontconfig to get font paths */
-       err = FT_New_Face(ff->lib, path, 0, &font->face);
-       if (err) {
-               if (err == FT_Err_Unknown_File_Format)
-                       estr = "unknown file format";
-
-               log_warn("cannot load font: %s", estr);
-               ret = -EFAULT;
-               goto err_free;
-       }
-
-       if (!font->face->charmap) {
-               log_warn("cannot load charmap of new font");
-               ret = -EFAULT;
-               goto err_face;
-       }
-
-       err = FT_Set_Pixel_Sizes(font->face, width, height);
-       if (err) {
-               log_warn("cannot set pixel size of font");
-               ret = -EFAULT;
-               goto err_face;
-       }
-
-       ret = kmscon_hashtable_new(&font->glyphs, kmscon_direct_hash,
-                               kmscon_direct_equal, NULL,
-                               (kmscon_free_cb)kmscon_glyph_destroy);
-       if (ret)
-               goto err_face;
-
-       kmscon_font_factory_ref(ff);
-       font->ff = ff;
-       *out = font;
-
-       return 0;
-
-err_face:
-       FT_Done_Face(font->face);
-err_free:
-       free(font);
-       return ret;
-}
-
-void kmscon_font_ref(struct kmscon_font *font)
-{
-       if (!font)
-               return;
-
-       ++font->ref;
-}
-
-void kmscon_font_unref(struct kmscon_font *font)
-{
-       if (!font || !font->ref)
-               return;
-
-       if (--font->ref)
-               return;
-
-       log_debug("destroying font");
-
-       kmscon_hashtable_free(font->glyphs);
-       FT_Done_Face(font->face);
-       kmscon_font_factory_unref(font->ff);
-       free(font);
-}
-
-unsigned int kmscon_font_get_height(struct kmscon_font *font)
-{
-       if (!font)
-               return 0;
-
-       return font->height;
-}
-
-unsigned int kmscon_font_get_width(struct kmscon_font *font)
-{
-       if (!font)
-               return 0;
-
-       return font->width;
-}
-
-static int kmscon_font_lookup(struct kmscon_font *font,
-                       kmscon_symbol_t key, struct kmscon_glyph **out)
-{
-       struct kmscon_glyph *glyph;
-       int ret;
-       bool res;
-
-       if (!font || !out)
-               return -EINVAL;
-
-       res = kmscon_hashtable_find(font->glyphs, (void**)&glyph,
-                                       (void*)(long)key);
-       if (!res) {
-               ret = kmscon_glyph_new(&glyph, key, font);
-               if (ret)
-                       return ret;
-
-               kmscon_hashtable_insert(font->glyphs, (void*)(long)key, glyph);
-       }
-
-       *out = glyph;
-       return 0;
-}
-
-int kmscon_font_draw(struct kmscon_font *font, kmscon_symbol_t ch, float *m,
-                       struct gl_shader *shader)
-{
-       int ret;
-       struct kmscon_glyph *glyph;
-       static const float val[] = { 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1 };
-
-       if (!font)
-               return -EINVAL;
-
-       ret = kmscon_font_lookup(font, ch, &glyph);
-       if (ret)
-               return ret;
-
-       if (!glyph->valid)
-               return 0;
-
-       gl_m4_scale(m, 1.0 / glyph->advance, 1.0 / font->height, 1);
-       gl_m4_translate(m, glyph->left, font->height - glyph->top, 0);
-       gl_m4_scale(m, glyph->width, glyph->height, 1);
-
-       gl_shader_draw_tex(shader, val, val, 6, glyph->tex, m);
-
-       return 0;
-}
diff --git a/src/font_pango.c b/src/font_pango.c
deleted file mode 100644 (file)
index 8d4ece2..0000000
+++ /dev/null
@@ -1,796 +0,0 @@
-/*
- * kmscon - Font Handling - Pango Backend
- *
- * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
- * Copyright (c) 2011 University of Tuebingen
- *
- * 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.
- */
-
-/*
- * Font Handling - Pango
- * This provides a font backend based on Pango library. It can draw any kind of
- * text we want so it is perfect for our console.
- */
-
-#include <cairo.h>
-#include <errno.h>
-#include <glib.h>
-#include <pango/pango.h>
-#include <pango/pangocairo.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include "font.h"
-#include "gl.h"
-#include "log.h"
-#include "static_misc.h"
-#include "unicode.h"
-#include "uterm.h"
-
-#define LOG_SUBSYSTEM "font_pango"
-
-enum glyph_type {
-       GLYPH_INVALID,
-       GLYPH_LAYOUT,
-       GLYPH_STRING,
-};
-
-struct font_glyph {
-       kmscon_symbol_t ch;
-       unsigned int type;
-       unsigned int width;
-       unsigned int ascent;
-       unsigned int descent;
-
-       union {
-               PangoLayout *layout;
-               struct glyph_str {
-                       PangoFont *font;
-                       PangoGlyphString *str;
-               } string;
-       };
-};
-
-struct font_face {
-       unsigned long ref;
-       struct font_face *next;
-
-       struct font_attr attr;
-
-       unsigned int width;
-       unsigned int height;
-       PangoContext *ctx;
-       struct kmscon_hashtable *glyphs;
-};
-
-static pthread_mutex_t manager_mutex = PTHREAD_MUTEX_INITIALIZER;
-static struct font_face *manager__faces;
-static PangoFontMap *manager__lib;
-
-static void manager_lock()
-{
-       pthread_mutex_lock(&manager_mutex);
-}
-
-static void manager_unlock()
-{
-       pthread_mutex_unlock(&manager_mutex);
-}
-
-static void glyph_free(struct font_glyph *glyph)
-{
-       manager_lock();
-
-       if (glyph->type == GLYPH_STRING) {
-               g_object_unref(glyph->string.font);
-               pango_glyph_string_free(glyph->string.str);
-       } else if (glyph->type == GLYPH_LAYOUT) {
-               g_object_unref(glyph->layout);
-       }
-
-       manager_unlock();
-
-       free(glyph);
-}
-
-static int face_lookup(struct font_face *face, struct font_glyph **out,
-                       kmscon_symbol_t ch)
-{
-       struct font_glyph *glyph;
-       PangoLayout *layout;
-       PangoLayoutLine *line;
-       PangoGlyphItem *tmp;
-       PangoGlyphString *str;
-       PangoRectangle rec;
-       size_t len;
-       const char *val;
-       bool res;
-       int ret;
-
-       res = kmscon_hashtable_find(face->glyphs, (void**)&glyph,
-                                       (void*)(long)ch);
-       if (res) {
-               *out = glyph;
-               return 0;
-       }
-
-       glyph = malloc(sizeof(*glyph));
-       if (!glyph)
-               return -ENOMEM;
-       memset(glyph, 0, sizeof(*glyph));
-       glyph->ch = ch;
-
-       manager_lock();
-
-       layout = pango_layout_new(face->ctx);
-       val = kmscon_symbol_get_u8(ch, &len);
-       pango_layout_set_text(layout, val, len);
-       kmscon_symbol_free_u8(val);
-
-       pango_layout_get_pixel_extents(layout, NULL, &rec);
-       glyph->ascent = PANGO_PIXELS_CEIL(pango_layout_get_baseline(layout));
-       glyph->descent = rec.height - glyph->ascent;
-       glyph->width = rec.width;
-
-       if (pango_layout_get_line_count(layout) != 1 || !glyph->width) {
-               glyph->type = GLYPH_INVALID;
-               g_object_unref(layout);
-               goto unlock;
-       }
-
-       line = pango_layout_get_line_readonly(layout, 0);
-       if (!line->runs || line->runs->next) {
-               glyph->type = GLYPH_LAYOUT;
-               glyph->layout = layout;
-       } else {
-               tmp = line->runs->data;
-               str = pango_glyph_string_copy(tmp->glyphs);
-               glyph->type = GLYPH_STRING;
-               glyph->string.str = str;
-               glyph->string.font = g_object_ref(tmp->item->analysis.font);
-               g_object_unref(layout);
-       }
-
-unlock:
-       manager_unlock();
-
-       ret = kmscon_hashtable_insert(face->glyphs, (void*)(long)ch, glyph);
-       if (ret) {
-               glyph_free(glyph);
-               return ret;
-       }
-
-       *out = glyph;
-       return 0;
-}
-
-static int attr_cpy(struct font_attr *dest, const struct font_attr *src,
-                       bool alloc)
-{
-       memcpy(dest, src, sizeof(*dest));
-       if (!dest->dpi)
-               dest->dpi = 96;
-       if (!dest->name)
-               dest->name = "monospace";
-
-       if (alloc) {
-               dest->name = strdup(dest->name);
-               if (!dest->name)
-                       return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void attr_clean(struct font_attr *dest)
-{
-       free((char*)dest->name);
-}
-
-static bool attr_equal(const struct font_attr *a1,
-                       const struct font_attr *a2)
-{
-       struct font_attr b1, b2;
-
-       attr_cpy(&b1, a1, false);
-       attr_cpy(&b2, a2, false);
-
-       if (a1->points != a2->points)
-               return false;
-       if (a1->dpi != a2->dpi)
-               return false;
-       if (a1->bold != a2->bold)
-               return false;
-       if (a1->style != a2->style)
-               return false;
-       if (strcmp(a1->name, a2->name))
-               return false;
-
-       return true;
-}
-
-static int face__new(struct font_face **out, const struct font_attr *attr,
-                       bool absolute)
-{
-       struct font_face *face;
-       int ret;
-       cairo_font_options_t *opt;
-       PangoFontDescription *desc;
-       unsigned int style, weight;
-
-       face = malloc(sizeof(*face));
-       if (!face)
-               return -ENOMEM;
-       memset(face, 0, sizeof(*face));
-       face->ref = 1;
-
-       ret = attr_cpy(&face->attr, attr, true);
-       if (ret)
-               goto err_free;
-
-       if (face->attr.bold)
-               weight = PANGO_WEIGHT_BOLD;
-       else
-               weight = PANGO_WEIGHT_NORMAL;
-
-       if (face->attr.style == FONT_ITALIC)
-               style = PANGO_STYLE_ITALIC;
-       else
-               style = PANGO_STYLE_NORMAL;
-
-       ret = kmscon_hashtable_new(&face->glyphs, kmscon_direct_hash,
-                                       kmscon_direct_equal, NULL,
-                                       (kmscon_free_cb)glyph_free);
-       if (ret)
-               goto err_attr;
-
-       log_info("loading new font: %s", face->attr.name);
-
-       face->ctx = pango_font_map_create_context(manager__lib);
-       pango_context_set_base_dir(face->ctx, PANGO_DIRECTION_LTR);
-       pango_context_set_language(face->ctx, pango_language_get_default());
-       pango_cairo_context_set_resolution(face->ctx, face->attr.dpi);
-
-       desc = pango_font_description_from_string(face->attr.name);
-       if (absolute)
-               pango_font_description_set_absolute_size(desc,
-                                       PANGO_SCALE * face->attr.points);
-       else
-               pango_font_description_set_size(desc,
-                                       PANGO_SCALE * face->attr.points);
-       pango_font_description_set_weight(desc, weight);
-       pango_font_description_set_style(desc, style);
-       pango_font_description_set_variant(desc, PANGO_VARIANT_NORMAL);
-       pango_font_description_set_stretch(desc, PANGO_STRETCH_NORMAL);
-       pango_font_description_set_gravity(desc, PANGO_GRAVITY_SOUTH);
-       pango_context_set_font_description(face->ctx, desc);
-       pango_font_description_free(desc);
-
-       if (!pango_cairo_context_get_font_options(face->ctx)) {
-               opt = cairo_font_options_create();
-               if (!opt) {
-                       log_err("cannot create cairo font options");
-                       ret = -EFAULT;
-                       goto err_ctx;
-               }
-               pango_cairo_context_set_font_options(face->ctx, opt);
-               cairo_font_options_destroy(opt);
-       }
-
-       *out = face;
-       return 0;
-
-err_ctx:
-       g_object_unref(face->ctx);
-       kmscon_hashtable_free(face->glyphs);
-err_attr:
-       attr_clean(&face->attr);
-err_free:
-       free(face);
-       return ret;
-}
-
-static void face__free(struct font_face *face)
-{
-       manager_unlock();
-       kmscon_hashtable_free(face->glyphs);
-       manager_lock();
-       g_object_unref(face->ctx);
-       attr_clean(&face->attr);
-       free(face);
-}
-
-static int manager__init()
-{
-       if (!manager__lib) {
-               manager__lib = pango_cairo_font_map_new();
-               if (!manager__lib) {
-                       log_warn("cannot create font map");
-                       return -EFAULT;
-               }
-       }
-
-       return 0;
-}
-
-static void manager__add(struct font_face *face)
-{
-       face->next = manager__faces;
-       manager__faces = face;
-}
-
-static void manager__remove(struct font_face *face)
-{
-       struct font_face *iter;
-
-       if (!manager__faces) {
-               face->next = NULL;
-       } else if (manager__faces == face) {
-               manager__faces = face->next;
-               face->next = NULL;
-       } else {
-               iter = manager__faces;
-               for ( ; iter->next; iter = iter->next) {
-                       if (iter->next == face) {
-                               iter->next = face->next;
-                               face->next = NULL;
-                               break;
-                       }
-               }
-       }
-}
-
-static void face_unref(struct font_face *face)
-{
-       manager_lock();
-       if (!--face->ref) {
-               manager__remove(face);
-               face__free(face);
-       }
-       manager_unlock();
-}
-
-/* Measure font width and height
- * We simply draw all ASCII characters and use the average width as default
- * character width. The height is the maximum ascent+descent.
- * This has the side effect that all ASCII characters are already cached and the
- * console will speed up.
- */
-static int face_measure(struct font_face *face)
-{
-       unsigned int i, num, width, asc, desc;
-       int ret;
-       kmscon_symbol_t ch;
-       struct font_glyph *glyph;
-
-       num = 0;
-       width = 0;
-       asc = 0;
-       desc = 0;
-       for (i = 0x20; i < 0x7f; ++i) {
-               ch = kmscon_symbol_make(i);
-               ret = face_lookup(face, &glyph, ch);
-               if (ret)
-                       continue;
-
-               if (glyph->width > 0) {
-                       width += glyph->width;
-                       if (glyph->ascent > asc)
-                               asc = glyph->ascent;
-                       if (glyph->descent > desc)
-                               desc = glyph->descent;
-                       num++;
-               }
-       }
-
-       if (!num)
-               return -EFAULT;
-
-       face->width = width / num;
-       face->height = asc + desc;
-       log_debug("width/height is %ux%u", face->width, face->height);
-
-       return 0;
-}
-
-static int manager_get(struct font_face **out, const struct font_attr *attr,
-                       bool absolute)
-{
-       struct font_face *iter;
-       int ret;
-
-       manager_lock();
-
-       ret = manager__init();
-       if (ret)
-               goto unlock;
-
-       for (iter = manager__faces; iter; iter = iter->next) {
-               if (attr_equal(&iter->attr, attr)) {
-                       iter->ref++;
-                       break;
-               }
-       }
-
-       if (!iter) {
-               ret = face__new(&iter, attr, absolute);
-               if (ret)
-                       goto unlock;
-
-               manager_unlock();
-               ret = face_measure(iter);
-               manager_lock();
-               if (ret) {
-                       face__free(iter);
-                       goto unlock;
-               }
-
-               manager__add(iter);
-       }
-
-unlock:
-       manager_unlock();
-
-       if (!ret)
-               *out = iter;
-       return ret;
-}
-
-int font_buffer_new(struct font_buffer **out, unsigned int width,
-                       unsigned int height)
-{
-       struct font_buffer *buf;
-       int ret;
-
-       if (!out || !width || !height)
-               return -EINVAL;
-
-       buf = malloc(sizeof(*buf));
-       if (!buf)
-               return -ENOMEM;
-       memset(buf, 0, sizeof(*buf));
-       buf->width = width;
-       buf->height = height;
-       buf->stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
-                                                       width);
-       if (buf->stride <= 0) {
-               log_err("invalid cairo stride");
-               ret = -EFAULT;
-               goto err_free;
-       }
-       buf->data = malloc(buf->stride * buf->height);
-       if (!buf->data) {
-               ret = -ENOMEM;
-               goto err_free;
-       }
-
-       *out = buf;
-       return 0;
-
-err_free:
-       free(buf);
-       return ret;
-}
-
-void font_buffer_free(struct font_buffer *buf)
-{
-       if (!buf)
-               return;
-
-       free(buf->data);
-       free(buf);
-}
-
-struct font_screen {
-       struct font_buffer *buf;
-       struct gl_shader *shader;
-       struct uterm_screen *scr;
-       unsigned int tex;
-
-       unsigned int cols;
-       unsigned int rows;
-       double advance_x;
-       double advance_y;
-
-       bool absolute;
-       double scale_x;
-       double scale_y;
-
-       struct {
-               struct font_face *normal;
-               struct font_face *bold;
-       } faces;
-
-       cairo_surface_t *surface;
-       cairo_t *cr;
-};
-
-static int screen_new(struct font_screen **out, struct font_buffer *buf,
-                       const struct font_attr *attr, bool absolute,
-                       unsigned int cols, unsigned int rows,
-                       struct uterm_screen *scr, struct gl_shader *shader)
-{
-       struct font_screen *screen;
-       int ret;
-       struct font_attr att;
-
-       if (!out || !buf || !attr || !scr)
-               return -EINVAL;
-       if (absolute && (!cols || !rows))
-               return -EINVAL;
-       if (!buf->width || !buf->height || !buf->stride || !buf->data)
-               return -EINVAL;
-
-       if (uterm_screen_use(scr) == -EOPNOTSUPP)
-               shader = NULL;
-       else if (!shader)
-               return -EINVAL;
-
-       log_debug("new screen with size %ux%u for table %ux%u",
-                       buf->width, buf->height, cols, rows);
-
-       screen = malloc(sizeof(*screen));
-       if (!screen)
-               return -ENOMEM;
-       memset(screen, 0, sizeof(*screen));
-       screen->buf = buf;
-       screen->scr = scr;
-       screen->shader = shader;
-       screen->absolute = absolute;
-       attr_cpy(&att, attr, false);
-       att.bold = false;
-       att.style = FONT_NORMAL;
-
-       screen->surface = cairo_image_surface_create_for_data(
-                               (uint8_t*)screen->buf->data,
-                               CAIRO_FORMAT_ARGB32,
-                               screen->buf->width,
-                               screen->buf->height,
-                               screen->buf->stride);
-       if (cairo_surface_status(screen->surface) != CAIRO_STATUS_SUCCESS) {
-               ret = -EFAULT;
-               goto err_surface;
-       }
-
-       screen->cr = cairo_create(screen->surface);
-       if (cairo_status(screen->cr) != CAIRO_STATUS_SUCCESS) {
-               ret = -EFAULT;
-               goto err_cr;
-       }
-
-       if (screen->absolute) {
-               screen->cols = cols;
-               screen->rows = rows;
-               att.points = screen->buf->height / screen->rows;
-
-               ret = manager_get(&screen->faces.normal, &att, true);
-               if (ret)
-                       goto err_cr;
-               att.bold = true;
-               ret = manager_get(&screen->faces.bold, &att, true);
-               if (ret)
-                       goto err_normal;
-
-               screen->scale_x = screen->faces.normal->width;
-               screen->scale_x *= screen->cols;
-               screen->scale_x = screen->buf->width / screen->scale_x;
-               screen->scale_y = screen->faces.normal->height;
-               screen->scale_y *= screen->rows;
-               screen->scale_y = screen->buf->height / screen->scale_y;
-       } else {
-               ret = manager_get(&screen->faces.normal, &att, false);
-               if (ret)
-                       goto err_cr;
-               att.bold = true;
-               ret = manager_get(&screen->faces.bold, &att, false);
-               if (ret)
-                       goto err_normal;
-
-               screen->cols = screen->buf->width /
-                                               screen->faces.normal->width;
-               screen->rows = screen->buf->height /
-                                               screen->faces.normal->height;
-       }
-
-       screen->advance_x = screen->faces.normal->width;
-       screen->advance_y = screen->faces.normal->height;
-
-       screen->tex = gl_tex_new();
-       uterm_screen_ref(screen->scr);
-       gl_shader_ref(screen->shader);
-       *out = screen;
-       return 0;
-
-err_normal:
-       face_unref(screen->faces.normal);
-err_cr:
-       cairo_destroy(screen->cr);
-err_surface:
-       cairo_surface_destroy(screen->surface);
-       free(screen);
-       return ret;
-}
-
-int font_screen_new(struct font_screen **out, struct font_buffer *buf,
-                       const struct font_attr *attr,
-                       struct uterm_screen *scr, struct gl_shader *shader)
-{
-       return screen_new(out, buf, attr, false, 0, 0, scr, shader);
-}
-
-int font_screen_new_fixed(struct font_screen **out, struct font_buffer *buf,
-                       const struct font_attr *attr,
-                       unsigned int cols, unsigned int rows,
-                       struct uterm_screen *scr, struct gl_shader *shader)
-{
-       return screen_new(out, buf, attr, true, cols, rows, scr, shader);
-}
-
-void font_screen_free(struct font_screen *screen)
-{
-       if (!screen)
-               return;
-
-       log_debug("free screen");
-       face_unref(screen->faces.bold);
-       face_unref(screen->faces.normal);
-       cairo_destroy(screen->cr);
-       cairo_surface_destroy(screen->surface);
-       gl_tex_free(screen->tex);
-       gl_shader_unref(screen->shader);
-       uterm_screen_unref(screen->scr);
-       free(screen);
-}
-
-unsigned int font_screen_columns(struct font_screen *screen)
-{
-       return screen ? screen->cols : 0;
-}
-
-unsigned int font_screen_rows(struct font_screen *screen)
-{
-       return screen ? screen->rows : 0;
-}
-
-unsigned int font_screen_points(struct font_screen *screen)
-{
-       return screen ? screen->faces.normal->attr.points : 0;
-}
-
-unsigned int font_screen_width(struct font_screen *screen)
-{
-       return screen ? screen->buf->width : 0;
-}
-
-unsigned int font_screen_height(struct font_screen *screen)
-{
-       return screen ? screen->buf->height : 0;
-}
-
-int font_screen_draw_start(struct font_screen *screen)
-{
-       if (!screen)
-               return -EINVAL;
-
-       cairo_save(screen->cr);
-
-       cairo_set_operator(screen->cr, CAIRO_OPERATOR_SOURCE);
-       cairo_set_source_rgba(screen->cr, 0, 0, 0, 0);
-       cairo_paint(screen->cr);
-
-       cairo_set_operator(screen->cr, CAIRO_OPERATOR_OVER);
-       cairo_set_source_rgb(screen->cr, 1, 1, 1);
-       cairo_set_line_width(screen->cr, 1.0);
-
-       if (screen->absolute)
-               cairo_scale(screen->cr, screen->scale_x, screen->scale_y);
-
-       return 0;
-}
-
-int font_screen_draw_char(struct font_screen *screen, kmscon_symbol_t ch,
-                               const struct font_char_attr *attr,
-                               unsigned int cellx, unsigned int celly,
-                               unsigned int width, unsigned int height,
-                               bool draw_bg)
-{
-       struct font_glyph *glyph;
-       int ret;
-
-       if (!screen || !width || !height || !attr)
-               return -EINVAL;
-
-       if (attr->bold) {
-               ret = face_lookup(screen->faces.bold, &glyph, ch);
-               if (ret)
-                       return ret;
-       } else {
-               ret = face_lookup(screen->faces.normal, &glyph, ch);
-               if (ret)
-                       return ret;
-       }
-
-       if (draw_bg) {
-               if (attr->inverse)
-                       cairo_set_source_rgb(screen->cr, attr->fr, attr->fg,
-                                            attr->fb);
-               else
-                       cairo_set_source_rgb(screen->cr, attr->br, attr->bg,
-                                            attr->bb);
-
-               cairo_move_to(screen->cr, cellx * screen->advance_x,
-                             celly * screen->advance_y);
-               cairo_rel_line_to(screen->cr, screen->advance_x, 0);
-               cairo_rel_line_to(screen->cr, 0, screen->advance_y);
-               cairo_rel_line_to(screen->cr, -screen->advance_x, 0);
-               cairo_close_path(screen->cr);
-               cairo_fill(screen->cr);
-       }
-
-       if (attr->inverse)
-               cairo_set_source_rgb(screen->cr, attr->br, attr->bg, attr->bb);
-       else
-               cairo_set_source_rgb(screen->cr, attr->fr, attr->fg, attr->fb);
-
-       if (glyph->type == GLYPH_STRING) {
-               cairo_move_to(screen->cr, cellx * screen->advance_x,
-                               celly * screen->advance_y + glyph->ascent);
-               pango_cairo_show_glyph_string(screen->cr, glyph->string.font,
-                                               glyph->string.str);
-       } else if (glyph->type == GLYPH_LAYOUT) {
-               cairo_move_to(screen->cr, cellx * screen->advance_x,
-                                       celly * screen->advance_y);
-               pango_cairo_update_layout(screen->cr, glyph->layout);
-               pango_cairo_show_layout(screen->cr, glyph->layout);
-       }
-
-       return 0;
-}
-
-int font_screen_draw_perform(struct font_screen *screen, float *m)
-{
-       static const float ver[] = { -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1 };
-       static const float tex[] = { 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1 };
-       const struct uterm_video_buffer buf = {
-               .width = screen->buf->width,
-               .height = screen->buf->height,
-               .stride = screen->buf->stride,
-               .format = UTERM_FORMAT_XRGB32,
-               .data = (void*)screen->buf->data,
-       };
-
-       if (!screen)
-               return -EINVAL;
-
-       if (screen->shader) {
-               gl_tex_load(screen->tex, screen->buf->width,
-                           screen->buf->stride, screen->buf->height,
-                           screen->buf->data);
-               gl_shader_draw_tex(screen->shader, ver, tex, 6, screen->tex, m);
-       } else {
-               uterm_screen_blit(screen->scr, &buf, 0, 0);
-       }
-
-       cairo_restore(screen->cr);
-
-       return 0;
-}