+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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;
-}