font: rewrite font backend

We now properly draw fonts with OpenGL. We now use FreeType2 instead of
pango to avoid big dependencies.

We also add a DejaVu font so we currently don't have to deal with font
selection.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-01-22 22:44:12 +01:00
parent 0b320653d8
commit 5a3801386a
14 changed files with 303 additions and 642 deletions

89
COPYING
View File

@ -87,3 +87,92 @@ The xkb input handling is based on the Xlib xkb handling:
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
from the XFree86 Project.
The DejaVu fonts included in this package are from:
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
Bitstream Vera is a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute
the Font Software, including without limitation the rights to use,
copy, merge, publish, distribute, and/or sell copies of the Font
Software, and to permit persons to whom the Font Software is furnished
to do so, subject to the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the Fonts,
only if the fonts are renamed to names not containing either the words
"Bitstream" or the word "Vera".
This License becomes null and void to the extent applicable to Fonts or
Font Software that has been modified and is distributed under the
"Bitstream Vera" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font
Software without prior written authorization from the Gnome Foundation
or Bitstream Inc., respectively. For further information,
contact: fonts at gnome dot org.
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong@free.fr.

View File

@ -40,6 +40,7 @@ libkmscon_core_la_SOURCES = \
src/console.c src/console.h \
src/output.c src/output.h \
src/output_context.c \
src/output_math.c \
src/console_cell.c \
src/unicode.c src/unicode.h \
src/log.c src/log.h \

View File

@ -1,4 +1,4 @@
#!/bin/sh
mkdir -p m4/
autoreconf -i
./configure --enable-debug --enable-pango --enable-gles2 $*
./configure --enable-debug --enable-gles2 $*

BIN
fonts/DejaVuSansMono.ttf Normal file

Binary file not shown.

View File

@ -36,8 +36,6 @@
#include <stdlib.h>
#include <string.h>
#include <cairo.h>
#include "console.h"
#include "font.h"
#include "log.h"
@ -50,17 +48,11 @@ struct kmscon_console {
struct kmscon_compositor *comp;
struct kmscon_context *ctx;
/* GL texture and font */
unsigned int tex;
/* font */
unsigned int res_x;
unsigned int res_y;
struct kmscon_font *font;
/* cairo surface */
cairo_t *cr;
cairo_surface_t *surf;
unsigned char *surf_buf;
/* console cells */
struct kmscon_buffer *cells;
unsigned int cells_x;
@ -71,69 +63,6 @@ struct kmscon_console {
unsigned int cursor_y;
};
static void kmscon_console_free_res(struct kmscon_console *con)
{
if (con && con->cr) {
kmscon_context_free_tex(con->ctx, con->tex);
cairo_destroy(con->cr);
cairo_surface_destroy(con->surf);
free(con->surf_buf);
con->tex = 0;
con->cr = NULL;
con->surf = NULL;
con->surf_buf = NULL;
}
}
static int kmscon_console_new_res(struct kmscon_console *con)
{
unsigned char *buf;
cairo_t *cr;
cairo_surface_t *surface;
int stride, ret;
cairo_format_t format = CAIRO_FORMAT_ARGB32;
if (!con)
return -EINVAL;
stride = cairo_format_stride_for_width(format, con->res_x);
buf = malloc(stride * con->res_y);
if (!buf)
return -ENOMEM;
surface = cairo_image_surface_create_for_data(buf, format, con->res_x,
con->res_y, stride);
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
ret = -ENOMEM;
goto err_free;
}
cr = cairo_create(surface);
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
ret = -EFAULT;
goto err_cairo;
}
kmscon_console_free_res(con);
con->surf_buf = buf;
con->surf = surface;
con->cr = cr;
con->tex = kmscon_context_new_tex(con->ctx);
log_debug("console: new resolution %ux%u\n", con->res_x, con->res_y);
return 0;
err_cairo:
cairo_destroy(cr);
err_free:
cairo_surface_destroy(surface);
free(buf);
return ret;
}
int kmscon_console_new(struct kmscon_console **out,
struct kmscon_font_factory *ff, struct kmscon_compositor *comp)
{
@ -192,7 +121,6 @@ void kmscon_console_unref(struct kmscon_console *con)
if (--con->ref)
return;
kmscon_console_free_res(con);
kmscon_font_unref(con->font);
kmscon_buffer_unref(con->cells);
kmscon_compositor_unref(con->comp);
@ -280,48 +208,11 @@ int kmscon_console_resize(struct kmscon_console *con, unsigned int x,
con->font = font;
con->res_x = con->cells_x * kmscon_font_get_width(con->font);
con->res_y = height;
ret = kmscon_console_new_res(con);
if (ret) {
log_err("console: cannot create drawing buffers: %d\n", ret);
return ret;
}
log_debug("console: new resolution %ux%u\n", con->res_x, con->res_y);
return 0;
}
/*
* This redraws the console. It does not clip/copy the image onto any
* framebuffer. You must use kmscon_console_map() to do this.
* This allows to draw the console once and then map it onto multiple
* framebuffers so it is displayed on multiple monitors with different screen
* resolutions.
* You must have called kmscon_console_set_res() before.
*/
void kmscon_console_draw(struct kmscon_console *con)
{
if (!con || !con->cr)
return;
cairo_save(con->cr);
cairo_set_operator(con->cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(con->cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint(con->cr);
cairo_set_operator(con->cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(con->cr, 1.0, 1.0, 1.0, 1.0);
kmscon_buffer_draw(con->cells, con->font, con->cr, con->res_x,
con->res_y);
cairo_restore(con->cr);
/* refresh GL texture contents */
kmscon_context_set_tex(con->ctx, con->tex, con->res_x, con->res_y,
con->surf_buf);
}
/*
* This maps the console onto the current GL framebuffer. It expects the
* framebuffer to have 0/0 in the middle, -1/-1 in the upper left and 1/1 in the
@ -334,15 +225,10 @@ void kmscon_console_draw(struct kmscon_console *con)
*/
void kmscon_console_map(struct kmscon_console *con)
{
static const float vertices[] = { -1, -1, 1, -1, -1, 1,
1, -1, 1, 1, -1, 1 };
static const float texpos[] = { 0, 0, 1, 0, 0, 1,
1, 0, 1, 1, 0, 1 };
if (!con || !con->cr)
if (!con)
return;
kmscon_context_draw_tex(con->ctx, vertices, texpos, 6, con->tex);
kmscon_buffer_draw(con->cells, con->font);
}
void kmscon_console_write(struct kmscon_console *con, kmscon_symbol_t ch)

View File

@ -53,8 +53,7 @@ void kmscon_buffer_unref(struct kmscon_buffer *buf);
int kmscon_buffer_resize(struct kmscon_buffer *buf, unsigned int x,
unsigned int y);
void kmscon_buffer_draw(struct kmscon_buffer *buf, struct kmscon_font *font,
void *dcr, unsigned int width, unsigned int height);
void kmscon_buffer_draw(struct kmscon_buffer *buf, struct kmscon_font *font);
unsigned int kmscon_buffer_get_width(struct kmscon_buffer *buf);
unsigned int kmscon_buffer_get_height(struct kmscon_buffer *buf);
@ -76,7 +75,6 @@ unsigned int kmscon_console_get_height(struct kmscon_console *con);
int kmscon_console_resize(struct kmscon_console *con, unsigned int x,
unsigned int y, unsigned int height);
void kmscon_console_draw(struct kmscon_console *con);
void kmscon_console_map(struct kmscon_console *con);
void kmscon_console_write(struct kmscon_console *con, kmscon_symbol_t ch);

View File

@ -80,8 +80,6 @@
#include <stdlib.h>
#include <string.h>
#include <cairo.h>
#include "console.h"
#include "log.h"
#include "unicode.h"
@ -116,6 +114,8 @@ struct kmscon_buffer {
unsigned int size_y;
unsigned int fill;
struct line **current;
struct kmscon_m4_stack *stack;
};
static void destroy_cell(struct cell *cell)
@ -216,13 +216,19 @@ int kmscon_buffer_new(struct kmscon_buffer **out, unsigned int x,
log_debug("console: new buffer object\n");
ret = kmscon_buffer_resize(buf, x, y);
ret = kmscon_m4_stack_new(&buf->stack);
if (ret)
goto err_free;
ret = kmscon_buffer_resize(buf, x, y);
if (ret)
goto err_stack;
*out = buf;
return 0;
err_stack:
kmscon_m4_stack_free(buf->stack);
err_free:
free(buf);
return ret;
@ -257,6 +263,7 @@ void kmscon_buffer_unref(struct kmscon_buffer *buf)
free_line(buf->current[i]);
free(buf->current);
kmscon_m4_stack_free(buf->stack);
free(buf);
log_debug("console: destroying buffer object\n");
}
@ -415,32 +422,30 @@ int kmscon_buffer_resize(struct kmscon_buffer *buf, unsigned int x,
return 0;
}
void kmscon_buffer_draw(struct kmscon_buffer *buf, struct kmscon_font *font,
void *dcr, unsigned int width, unsigned int height)
void kmscon_buffer_draw(struct kmscon_buffer *buf, struct kmscon_font *font)
{
cairo_t *cr;
double xs, ys, cx, cy;
float xs, ys;
unsigned int i, j, k, num;
struct line *iter, *line;
struct cell *cell;
float *m;
if (!buf || !font || !dcr)
if (!buf || !font)
return;
cr = dcr;
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
m = kmscon_m4_stack_tip(buf->stack);
kmscon_m4_identity(m);
xs = width / (double)buf->size_x;
ys = height / (double)buf->size_y;
xs = 1.0 / buf->size_x;
ys = 1.0 / buf->size_y;
kmscon_m4_scale(m, 2, 2, 1);
kmscon_m4_trans(m, -0.5, -0.5, 0);
kmscon_m4_scale(m, xs, ys, 1);
iter = buf->position;
k = 0;
cy = 0;
for (i = 0; i < buf->size_y; ++i) {
cx = 0;
if (iter) {
line = iter;
iter = iter->next;
@ -460,11 +465,16 @@ void kmscon_buffer_draw(struct kmscon_buffer *buf, struct kmscon_font *font,
for (j = 0; j < num; ++j) {
cell = &line->cells[j];
kmscon_font_draw(font, cell->ch, cr, cx, cy);
cx += xs;
}
m = kmscon_m4_stack_push(buf->stack);
if (!m) {
log_warning("console: cannot push matrix\n");
break;
}
cy += ys;
kmscon_m4_trans(m, j, i, 0);
kmscon_font_draw(font, cell->ch, m);
m = kmscon_m4_stack_pop(buf->stack);
}
}
}

View File

@ -54,7 +54,6 @@ void kmscon_font_unref(struct kmscon_font *font);
unsigned int kmscon_font_get_height(struct kmscon_font *font);
unsigned int kmscon_font_get_width(struct kmscon_font *font);
int kmscon_font_draw(struct kmscon_font *font, kmscon_symbol_t ch,
void *dcr, uint32_t x, uint32_t y);
int kmscon_font_draw(struct kmscon_font *font, kmscon_symbol_t ch, float *m);
#endif /* KMSCON_FONT_H */

View File

@ -32,9 +32,11 @@
*/
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "font.h"
#include "log.h"
#include "output.h"
@ -58,12 +60,115 @@ struct kmscon_font {
FT_Face face;
unsigned int width;
unsigned int height;
GHashTable *glyphs;
};
struct kmscon_glyph {
unsigned long ref;
struct kmscon_context *ctx;
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;
unsigned int i, j;
if (!out)
return -EINVAL;
glyph = malloc(sizeof(*glyph));
if (!glyph)
return -ENOMEM;
memset(glyph, 0, sizeof(*glyph));
glyph->ctx = font->ff->ctx;
val = kmscon_symbol_get(font->ff->st, &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 = kmscon_context_new_tex(glyph->ctx);
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;
}
}
kmscon_context_set_tex(glyph->ctx, glyph->tex, bmap->width,
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:
kmscon_context_free_tex(glyph->ctx, glyph->tex);
err_free:
free(glyph);
return ret;
}
static void kmscon_glyph_destroy(struct kmscon_glyph *glyph)
{
if (!glyph)
return;
if (glyph->valid)
kmscon_context_free_tex(glyph->ctx, glyph->tex);
free(glyph);
}
int kmscon_font_factory_new(struct kmscon_font_factory **out,
struct kmscon_symbol_table *st, struct kmscon_compositor *comp)
{
@ -137,9 +242,12 @@ int kmscon_font_factory_load(struct kmscon_font_factory *ff,
const char *estr = "unknown error";
int ret;
if (!ff || !out)
if (!ff || !out || !height)
return -EINVAL;
if (!width)
width = height;
font = malloc(sizeof(*font));
if (!font)
return -ENOMEM;
@ -149,7 +257,8 @@ int kmscon_font_factory_load(struct kmscon_font_factory *ff,
font->width = width;
font->height = height;
err = FT_New_Face(ff->lib, "/usr/share/fonts/TTF/DejaVuSansMono.ttf",
/* TODO: Use fontconfig to get font paths */
err = FT_New_Face(ff->lib, "./fonts/DejaVuSansMono.ttf",
0, &font->face);
if (err) {
if (err == FT_Err_Unknown_File_Format)
@ -173,6 +282,13 @@ int kmscon_font_factory_load(struct kmscon_font_factory *ff,
goto err_face;
}
font->glyphs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) kmscon_glyph_destroy);
if (!font->glyphs) {
ret = -ENOMEM;
goto err_face;
}
kmscon_font_factory_ref(ff);
font->ff = ff;
*out = font;
@ -202,6 +318,7 @@ void kmscon_font_unref(struct kmscon_font *font)
if (--font->ref)
return;
g_hash_table_unref(font->glyphs);
FT_Done_Face(font->face);
kmscon_font_factory_unref(font->ff);
free(font);
@ -223,13 +340,49 @@ unsigned int kmscon_font_get_width(struct kmscon_font *font)
return font->width;
}
int kmscon_font_draw(struct kmscon_font *font, kmscon_symbol_t ch,
void *dcr, uint32_t x, uint32_t y)
static int kmscon_font_lookup(struct kmscon_font *font,
kmscon_symbol_t key, struct kmscon_glyph **out)
{
struct kmscon_glyph *glyph;
int ret;
if (!font || !out)
return -EINVAL;
glyph = g_hash_table_lookup(font->glyphs, GUINT_TO_POINTER(key));
if (!glyph) {
ret = kmscon_glyph_new(&glyph, key, font);
if (ret)
return ret;
g_hash_table_insert(font->glyphs, GUINT_TO_POINTER(key), glyph);
}
*out = glyph;
return 0;
}
int kmscon_font_draw(struct kmscon_font *font, kmscon_symbol_t ch, float *m)
{
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;
/* still TODO */
ret = kmscon_font_lookup(font, ch, &glyph);
if (ret)
return ret;
if (!glyph->valid)
return 0;
kmscon_m4_scale(m, 1.0 / glyph->advance, 1.0 / font->height, 1);
kmscon_m4_trans(m, glyph->left, font->height - glyph->top, 0);
kmscon_m4_scale(m, glyph->width, glyph->height, 1);
kmscon_context_draw_tex(font->ff->ctx, val, val, 6, glyph->tex, m);
return 0;
}

View File

@ -44,488 +44,9 @@
#include "output.h"
#include "unicode.h"
enum glyph_type {
GLYPH_NONE,
GLYPH_LAYOUT,
GLYPH_STR,
};
struct kmscon_glyph {
size_t ref;
kmscon_symbol_t ch;
unsigned int width;
int type;
union {
struct layout {
PangoLayout *layout;
} layout;
struct str {
PangoFont *font;
PangoGlyphString *str;
uint32_t ascent;
} str;
} src;
};
struct kmscon_font_factory {
unsigned long ref;
struct kmscon_symbol_table *st;
struct kmscon_compositor *comp;
struct kmscon_context *ctx;
};
struct kmscon_font {
size_t ref;
struct kmscon_symbol_table *st;
unsigned int width;
unsigned int height;
GHashTable *glyphs;
PangoContext *ctx;
};
static int kmscon_font_lookup(struct kmscon_font *font,
kmscon_symbol_t key, struct kmscon_glyph **out);
/*
* Glyphs
* Glyphs are for internal use only! The outside world uses kmscon_char
* objects in combination with kmscon_font to draw characters. Internally, we
* cache a kmscon_glyph for every character that is drawn.
* This allows us to speed up the drawing operations because most characters are
* already cached.
*
* Glyphs are cached in a hash-table by each font. If a character is drawn, we
* look it up in the hash-table (or create a new one if none is found) and draw
* it to the framebuffer.
* A glyph may use several ways to cache the glyph description:
* GLYPH_NONE:
* No information is currently attached so the glyph cannot be drawn.
* GLYPH_LAYOUT:
* The most basic drawing operation. This is the slowest of all but can draw
* any text you want. It uses a PangoLayout internally and recalculates the
* character sizes each time we draw them.
*/
static int kmscon_glyph_new(struct kmscon_glyph **out, kmscon_symbol_t ch)
{
struct kmscon_glyph *glyph;
if (!out)
return -EINVAL;
glyph = malloc(sizeof(*glyph));
if (!glyph)
return -ENOMEM;
memset(glyph, 0, sizeof(*glyph));
glyph->ref = 1;
glyph->type = GLYPH_NONE;
glyph->ch = ch;
*out = glyph;
return 0;
}
/*
* Reset internal glyph description. You must use kmscon_glyph_set() again to
* attach new glyph descriptions.
*/
static void kmscon_glyph_reset(struct kmscon_glyph *glyph)
{
if (!glyph)
return;
switch (glyph->type) {
case GLYPH_LAYOUT:
g_object_unref(glyph->src.layout.layout);
break;
case GLYPH_STR:
g_object_unref(glyph->src.str.font);
pango_glyph_string_free(glyph->src.str.str);
break;
}
glyph->type = GLYPH_NONE;
glyph->width = 0;
}
static void kmscon_glyph_ref(struct kmscon_glyph *glyph)
{
if (!glyph)
return;
++glyph->ref;
}
static void kmscon_glyph_unref(struct kmscon_glyph *glyph)
{
if (!glyph || !glyph->ref)
return;
if (--glyph->ref)
return;
kmscon_glyph_reset(glyph);
free(glyph);
}
/*
* Generate glyph description.
* This connects the glyph with the given font an generates the fastest glyph
* description.
* Returns 0 on success.
*/
static int kmscon_glyph_set(struct kmscon_glyph *glyph,
struct kmscon_font *font)
{
PangoLayout *layout;
PangoLayoutLine *line;
PangoGlyphItem *tmp;
PangoGlyphString *str;
PangoRectangle rec;
size_t len;
const char *val;
if (!glyph || !font)
return -EINVAL;
layout = pango_layout_new(font->ctx);
if (!layout)
return -EINVAL;
val = kmscon_symbol_get_u8(font->st, glyph->ch, &len);
pango_layout_set_text(layout, val, len);
kmscon_symbol_free_u8(val);
pango_layout_get_extents(layout, NULL, &rec);
line = pango_layout_get_line_readonly(layout, 0);
if (!line || !line->runs || line->runs->next) {
kmscon_glyph_reset(glyph);
glyph->type = GLYPH_LAYOUT;
glyph->src.layout.layout = layout;
} else {
tmp = line->runs->data;
str = pango_glyph_string_copy(tmp->glyphs);
if (!str) {
g_object_unref(layout);
return -ENOMEM;
}
kmscon_glyph_reset(glyph);
glyph->type = GLYPH_STR;
glyph->src.str.str = str;
glyph->src.str.font =
g_object_ref(tmp->item->analysis.font);
glyph->src.str.ascent =
PANGO_PIXELS_CEIL(pango_layout_get_baseline(layout));
g_object_unref(layout);
}
glyph->width = PANGO_PIXELS(rec.width);
return 0;
}
int kmscon_font_factory_new(struct kmscon_font_factory **out,
struct kmscon_symbol_table *st, struct kmscon_compositor *comp)
{
struct kmscon_font_factory *ff;
if (!out || !st || !comp)
return -EINVAL;
ff = malloc(sizeof(*ff));
if (!ff)
return -ENOMEM;
memset(ff, 0, sizeof(*ff));
ff->ref = 1;
ff->st = st;
ff->comp = comp;
ff->ctx = kmscon_compositor_get_context(comp);
kmscon_compositor_ref(ff->comp);
kmscon_symbol_table_ref(ff->st);
*out = ff;
return 0;
}
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)
{
if (!ff || !ff->ref)
return;
if (--ff->ref)
return;
kmscon_compositor_unref(ff->comp);
kmscon_symbol_table_unref(ff->st);
free(ff);
}
/*
* Measure font width
* We simply draw all ASCII characters and use the average width as default
* character width.
* This has the side effect that all ASCII characters are already cached and the
* console will speed up.
*/
static int measure_width(struct kmscon_font *font)
{
unsigned int i, num, width;
int ret;
kmscon_symbol_t ch;
struct kmscon_glyph *glyph;
if (!font)
return -EINVAL;
width = 0;
num = 0;
for (i = 0; i < 127; ++i) {
ch = kmscon_symbol_make(i);
ret = kmscon_font_lookup(font, ch, &glyph);
if (ret)
continue;
if (glyph->width > 0) {
width += glyph->width;
num++;
}
kmscon_glyph_unref(glyph);
}
if (!num)
return -EFAULT;
font->width = width / num;
log_debug("font: width is %u\n", font->width);
return 0;
}
/*
* Creates a new font
* \height is the height in pixel that we have for each character.
* Returns 0 on success and stores the new font in \out.
* This backend is currently no longer available. See git-history for old pango
* backends. Use FreeType instead.
*/
int kmscon_font_factory_load(struct kmscon_font_factory *ff,
struct kmscon_font **out, unsigned int width, unsigned int height)
{
struct kmscon_font *font;
int ret;
PangoFontDescription *desc;
PangoFontMap *map;
PangoLanguage *lang;
cairo_font_options_t *opt;
if (!ff || !out || !height)
return -EINVAL;
log_debug("font: new font (height %u)\n", height);
font = malloc(sizeof(*font));
if (!font)
return -ENOMEM;
font->ref = 1;
font->height = height;
font->st = ff->st;
map = pango_cairo_font_map_get_default();
if (!map) {
ret = -EFAULT;
goto err_free;
}
font->ctx = pango_font_map_create_context(map);
if (!font->ctx) {
ret = -EFAULT;
goto err_free;
}
pango_context_set_base_dir(font->ctx, PANGO_DIRECTION_LTR);
desc = pango_font_description_from_string("monospace");
if (!desc) {
ret = -EFAULT;
goto err_ctx;
}
pango_font_description_set_absolute_size(desc, PANGO_SCALE * height);
pango_context_set_font_description(font->ctx, desc);
pango_font_description_free(desc);
lang = pango_language_get_default();
if (!lang) {
ret = -EFAULT;
goto err_ctx;
}
pango_context_set_language(font->ctx, lang);
if (!pango_cairo_context_get_font_options(font->ctx)) {
opt = cairo_font_options_create();
if (!opt) {
ret = -EFAULT;
goto err_ctx;
}
pango_cairo_context_set_font_options(font->ctx, opt);
cairo_font_options_destroy(opt);
}
font->glyphs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) kmscon_glyph_unref);
if (!font->glyphs) {
ret = -ENOMEM;
goto err_ctx;
}
ret = measure_width(font);
if (ret)
goto err_hash;
kmscon_symbol_table_ref(font->st);
*out = font;
return 0;
err_hash:
g_hash_table_unref(font->glyphs);
err_ctx:
g_object_unref(font->ctx);
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;
g_hash_table_unref(font->glyphs);
g_object_unref(font->ctx);
kmscon_symbol_table_unref(font->st);
free(font);
log_debug("font: destroying font\n");
}
unsigned int kmscon_font_get_width(struct kmscon_font *font)
{
if (!font)
return 0;
return font->width;
}
unsigned int kmscon_font_get_height(struct kmscon_font *font)
{
if (!font)
return 0;
return font->height;
}
/*
* Get glyph for given key. If no glyph can be found in the hash-table, then a
* new glyph is created and added to the hash-table.
* Returns 0 on success and stores the glyph with a new reference in \out.
*/
static int kmscon_font_lookup(struct kmscon_font *font,
kmscon_symbol_t key, struct kmscon_glyph **out)
{
struct kmscon_glyph *glyph;
int ret;
if (!font || !out)
return -EINVAL;
glyph = g_hash_table_lookup(font->glyphs, GUINT_TO_POINTER(key));
if (!glyph) {
ret = kmscon_glyph_new(&glyph, key);
if (ret)
return ret;
ret = kmscon_glyph_set(glyph, font);
if (ret)
goto err_glyph;
g_hash_table_insert(font->glyphs, GUINT_TO_POINTER(key), glyph);
}
kmscon_glyph_ref(glyph);
*out = glyph;
return 0;
err_glyph:
kmscon_glyph_unref(glyph);
return ret;
}
/*
* This draws a glyph for characters \ch into the given cairo context \cr.
* The glyph will be drawn with the upper-left corner at x/y.
* Returns 0 on success.
*/
int kmscon_font_draw(struct kmscon_font *font, kmscon_symbol_t ch, void *dcr,
uint32_t x, uint32_t y)
{
struct kmscon_glyph *glyph;
int ret;
cairo_t *cr = dcr;
if (!font || !ch || !cr)
return -EINVAL;
ret = kmscon_font_lookup(font, ch, &glyph);
if (ret)
return ret;
switch (glyph->type) {
case GLYPH_LAYOUT:
cairo_move_to(cr, x, y);
pango_cairo_update_layout(cr, glyph->src.layout.layout);
pango_cairo_show_layout(cr, glyph->src.layout.layout);
break;
case GLYPH_STR:
cairo_move_to(cr, x, y + glyph->src.str.ascent);
pango_cairo_show_glyph_string(cr, glyph->src.str.font,
glyph->src.str.str);
break;
default:
ret = -EFAULT;
break;
}
kmscon_glyph_unref(glyph);
return 0;
}
#error "Pango backend is currently not supported"

View File

@ -140,7 +140,7 @@ void kmscon_context_clear(struct kmscon_context *ctx);
void kmscon_context_draw_def(struct kmscon_context *ctx, float *vertices,
float *colors, size_t num);
void kmscon_context_draw_tex(struct kmscon_context *ctx, const float *vertices,
const float *texcoords, size_t num, unsigned int tex);
const float *texcoords, size_t num, unsigned int tex, const float *m);
unsigned int kmscon_context_new_tex(struct kmscon_context *ctx);
void kmscon_context_free_tex(struct kmscon_context *ctx, unsigned int tex);
void kmscon_context_set_tex(struct kmscon_context *ctx, unsigned int tex,

View File

@ -183,7 +183,15 @@ static void clear_gl_error()
/* return true if there is a pending GL error */
static bool has_gl_error()
{
return glGetError() != GL_NO_ERROR;
GLenum err;
err = glGetError();
if (err != GL_NO_ERROR) {
log_err("context: GL error %d\n", err);
return true;
}
return false;
}
/* external shader sources; generated during build */
@ -643,21 +651,19 @@ void kmscon_context_draw_def(struct kmscon_context *ctx, float *vertices,
}
void kmscon_context_draw_tex(struct kmscon_context *ctx, const float *vertices,
const float *texcoords, size_t num, unsigned int tex)
const float *texcoords, size_t num, unsigned int tex, const float *m)
{
static const float m[16] = { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
float mat[16];
if (!ctx)
return;
kmscon_m4_transp_dest(mat, m);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
ctx->proc_use_program(ctx->tex_program);
ctx->proc_uniform_matrix_4fv(ctx->tex_uni_projection, 1, GL_FALSE, m);
ctx->proc_uniform_matrix_4fv(ctx->tex_uni_projection, 1, GL_FALSE, mat);
ctx->proc_uniform_1i(ctx->tex_uni_texture, 0);
ctx->proc_vertex_attrib_pointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);

View File

@ -71,7 +71,6 @@ static void draw_all(struct kmscon_idle *idle, void *data)
ctx = kmscon_compositor_get_context(term->comp);
kmscon_eloop_rm_idle(idle);
kmscon_console_draw(term->console);
iter = term->outputs;
for (; iter; iter = iter->next) {

View File

@ -118,7 +118,6 @@ static void map_outputs(struct console *con)
if (kmscon_compositor_is_asleep(con->comp))
return;
kmscon_console_draw(con->con);
ctx = kmscon_compositor_get_context(con->comp);
iter = kmscon_compositor_get_outputs(con->comp);