We want to avoid any static files that are shared between multiple programs but are not part of SHL. These make the build-process just more complex. Move log.[ch] to SHL so we have a known context. Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
274 lines
6.8 KiB
C
274 lines
6.8 KiB
C
/*
|
|
* kmscon - Fixed unifont font
|
|
*
|
|
* Copyright (c) 2012 Ted Kotz <ted@kotz.us>
|
|
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:font_unifont.c
|
|
* @short_description: Fixed unifont font
|
|
* @include: font.h
|
|
*
|
|
* This is a fixed font renderer backend that supports just one font which is
|
|
* statically compiled into the file. This bitmap font has 8x16 and 16x16
|
|
* glyphs. This can statically compile in any font defined as a unifont style
|
|
* hex format. This font is from the GNU unifont project available at:
|
|
* http://unifoundry.com/unifont.html
|
|
*
|
|
* This file is heavily based on font_8x16.c
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "font.h"
|
|
#include "shl_hashtable.h"
|
|
#include "shl_log.h"
|
|
#include "uterm_video.h"
|
|
|
|
#define LOG_SUBSYSTEM "font_unifont"
|
|
|
|
/*
|
|
* Glyph data is linked to the binary externally as binary data. The data layout
|
|
* is a size-byte followed by 32 data bytes. The data bytes are padded with 0 if
|
|
* the size is smaller than 32.
|
|
* Sizes bigger than 32 are not used.
|
|
*/
|
|
|
|
struct unifont_data {
|
|
uint8_t len;
|
|
uint8_t data[32];
|
|
} __attribute__((__packed__));
|
|
|
|
extern const struct unifont_data _binary_src_font_unifont_data_bin_start[];
|
|
extern const struct unifont_data _binary_src_font_unifont_data_bin_end[];
|
|
|
|
/*
|
|
* Global glyph cache
|
|
* The linked binary glyph data cannot be directly passed to the caller as it
|
|
* has the wrong format. Hence, use a glyph-cache with all used glyphs and add
|
|
* new ones as soon as they are used.
|
|
*/
|
|
|
|
static pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
static struct shl_hashtable *cache;
|
|
static unsigned long cache_refnum;
|
|
|
|
static void cache_ref(void)
|
|
{
|
|
pthread_mutex_lock(&cache_mutex);
|
|
++cache_refnum;
|
|
pthread_mutex_unlock(&cache_mutex);
|
|
}
|
|
|
|
static void cache_unref(void)
|
|
{
|
|
pthread_mutex_lock(&cache_mutex);
|
|
if (!--cache_refnum) {
|
|
shl_hashtable_free(cache);
|
|
cache = NULL;
|
|
}
|
|
pthread_mutex_unlock(&cache_mutex);
|
|
}
|
|
|
|
static void free_glyph(void *data)
|
|
{
|
|
struct kmscon_glyph *g = data;
|
|
|
|
free(g->buf.data);
|
|
free(g);
|
|
}
|
|
|
|
static void unfold(uint8_t *dst, uint8_t val)
|
|
{
|
|
*dst = 0xff * !!val;
|
|
}
|
|
|
|
static int find_glyph(uint32_t id, const struct kmscon_glyph **out)
|
|
{
|
|
struct kmscon_glyph *g;
|
|
int ret;
|
|
bool res;
|
|
const struct unifont_data *start, *end, *d;
|
|
unsigned int i, w;
|
|
|
|
pthread_mutex_lock(&cache_mutex);
|
|
|
|
if (!cache) {
|
|
ret = shl_hashtable_new(&cache, shl_direct_hash,
|
|
shl_direct_equal, NULL, free_glyph);
|
|
if (ret) {
|
|
log_error("cannot create unifont hashtable: %d", ret);
|
|
goto out_unlock;
|
|
}
|
|
} else {
|
|
res = shl_hashtable_find(cache, (void**)out,
|
|
(void*)(long)id);
|
|
if (res) {
|
|
ret = 0;
|
|
goto out_unlock;
|
|
}
|
|
}
|
|
|
|
if (id > 0xffff) {
|
|
ret = -ERANGE;
|
|
goto out_unlock;
|
|
}
|
|
|
|
start = _binary_src_font_unifont_data_bin_start;
|
|
end = _binary_src_font_unifont_data_bin_end;
|
|
d = &start[id];
|
|
|
|
if (d >= end) {
|
|
ret = -ERANGE;
|
|
goto out_unlock;
|
|
}
|
|
|
|
switch (d->len) {
|
|
case 16:
|
|
w = 1;
|
|
break;
|
|
case 32:
|
|
w = 2;
|
|
break;
|
|
default:
|
|
ret = -EFAULT;
|
|
goto out_unlock;
|
|
}
|
|
|
|
g = malloc(sizeof(*g));
|
|
if (!g) {
|
|
ret = -ENOMEM;
|
|
goto out_unlock;
|
|
}
|
|
memset(g, 0, sizeof(*g));
|
|
g->width = w;
|
|
g->buf.width = w * 8;
|
|
g->buf.height = 16;
|
|
g->buf.stride = w * 8;
|
|
g->buf.format = UTERM_FORMAT_GREY;
|
|
|
|
g->buf.data = malloc(g->buf.stride * g->buf.height);
|
|
if (!g->buf.data) {
|
|
ret = -ENOMEM;
|
|
goto err_free;
|
|
}
|
|
|
|
for (i = 0; i < d->len; ++i) {
|
|
unfold(&g->buf.data[i * 8 + 0], d->data[i] & 0x80);
|
|
unfold(&g->buf.data[i * 8 + 1], d->data[i] & 0x40);
|
|
unfold(&g->buf.data[i * 8 + 2], d->data[i] & 0x20);
|
|
unfold(&g->buf.data[i * 8 + 3], d->data[i] & 0x10);
|
|
unfold(&g->buf.data[i * 8 + 4], d->data[i] & 0x08);
|
|
unfold(&g->buf.data[i * 8 + 5], d->data[i] & 0x04);
|
|
unfold(&g->buf.data[i * 8 + 6], d->data[i] & 0x02);
|
|
unfold(&g->buf.data[i * 8 + 7], d->data[i] & 0x01);
|
|
}
|
|
|
|
ret = shl_hashtable_insert(cache, (void*)(long)id, g);
|
|
if (ret) {
|
|
log_error("cannot insert glyph into glyph-cache: %d", ret);
|
|
goto err_data;
|
|
}
|
|
|
|
*out = g;
|
|
ret = 0;
|
|
goto out_unlock;
|
|
|
|
err_data:
|
|
free(g->buf.data);
|
|
err_free:
|
|
free(g);
|
|
out_unlock:
|
|
pthread_mutex_unlock(&cache_mutex);
|
|
return ret;
|
|
}
|
|
|
|
static int kmscon_font_unifont_init(struct kmscon_font *out,
|
|
const struct kmscon_font_attr *attr)
|
|
{
|
|
static const char name[] = "static-unifont";
|
|
const struct unifont_data *start, *end;
|
|
|
|
log_debug("loading static unifont font");
|
|
|
|
start = _binary_src_font_unifont_data_bin_start;
|
|
end = _binary_src_font_unifont_data_bin_end;
|
|
if (start == end) {
|
|
log_error("unifont glyph information not found in binary");
|
|
return -EFAULT;
|
|
}
|
|
|
|
|
|
memset(&out->attr, 0, sizeof(out->attr));
|
|
memcpy(out->attr.name, name, sizeof(name));
|
|
out->attr.bold = false;
|
|
out->attr.italic = false;
|
|
out->attr.width = 8;
|
|
out->attr.height = 16;
|
|
kmscon_font_attr_normalize(&out->attr);
|
|
out->baseline = 4;
|
|
|
|
cache_ref();
|
|
return 0;
|
|
}
|
|
|
|
static void kmscon_font_unifont_destroy(struct kmscon_font *font)
|
|
{
|
|
log_debug("unloading static unifont font");
|
|
cache_unref();
|
|
}
|
|
|
|
static int kmscon_font_unifont_render(struct kmscon_font *font, uint32_t id,
|
|
const uint32_t *ch, size_t len,
|
|
const struct kmscon_glyph **out)
|
|
{
|
|
if (len > 1)
|
|
return -ERANGE;
|
|
|
|
return find_glyph(id, out);
|
|
}
|
|
|
|
static int kmscon_font_unifont_render_inval(struct kmscon_font *font,
|
|
const struct kmscon_glyph **out)
|
|
{
|
|
return find_glyph(0xfffd, out);
|
|
}
|
|
|
|
static int kmscon_font_unifont_render_empty(struct kmscon_font *font,
|
|
const struct kmscon_glyph **out)
|
|
{
|
|
return find_glyph(' ', out);
|
|
}
|
|
|
|
struct kmscon_font_ops kmscon_font_unifont_ops = {
|
|
.name = "unifont",
|
|
.owner = NULL,
|
|
.init = kmscon_font_unifont_init,
|
|
.destroy = kmscon_font_unifont_destroy,
|
|
.render = kmscon_font_unifont_render,
|
|
.render_empty = kmscon_font_unifont_render_empty,
|
|
.render_inval = kmscon_font_unifont_render_inval,
|
|
};
|