mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
terminal: add unifont font-handling
The unifont layer of libsystemd-terminal provides a fallback font for situations where no system-fonts are available, or if you don't want to deal with traditional font-formats for some reasons. The unifont API mmaps a pre-compiled bitmap font that was generated out of GNU-Unifont font-data. This guarantees, that all users of the font will share the pages in memory. Furthermore, the layout of the binary file allows accessing glyph data in O(1) without pre-rendering glyphs etc. That is, the OS can skip loading pages for glyphs that we never access. Note that this is currently a test-run and we want to include the binary file in the GNU-Unifont package. However, until it was considered stable and accepted by the maintainers, we will ship it as part of systemd. So far it's only enabled with the experimental --enable-terminal, anyway.
This commit is contained in:
parent
545149a2fc
commit
86db5dfb6d
1
.gitignore
vendored
1
.gitignore
vendored
@ -225,6 +225,7 @@
|
||||
/test-time
|
||||
/test-tmpfiles
|
||||
/test-udev
|
||||
/test-unifont
|
||||
/test-unit-file
|
||||
/test-unit-name
|
||||
/test-utf8
|
||||
|
26
Makefile.am
26
Makefile.am
@ -2838,9 +2838,15 @@ noinst_LTLIBRARIES += \
|
||||
noinst_PROGRAMS += \
|
||||
systemd-subterm
|
||||
|
||||
unifontdatadir=$(datadir)/unifont
|
||||
|
||||
dist_unifontdata_DATA = \
|
||||
src/libsystemd-terminal/unifont-glyph-array.bin
|
||||
|
||||
tests += \
|
||||
test-term-page \
|
||||
test-term-parser
|
||||
test-term-parser \
|
||||
test-unifont
|
||||
endif
|
||||
|
||||
libsystemd_terminal_la_CFLAGS = \
|
||||
@ -2852,7 +2858,9 @@ libsystemd_terminal_la_SOURCES = \
|
||||
src/libsystemd-terminal/term-page.c \
|
||||
src/libsystemd-terminal/term-parser.c \
|
||||
src/libsystemd-terminal/term-screen.c \
|
||||
src/libsystemd-terminal/term-wcwidth.c
|
||||
src/libsystemd-terminal/term-wcwidth.c \
|
||||
src/libsystemd-terminal/unifont-internal.h \
|
||||
src/libsystemd-terminal/unifont.c
|
||||
|
||||
libsystemd_terminal_la_LIBADD = \
|
||||
libsystemd-internal.la \
|
||||
@ -2882,6 +2890,20 @@ test_term_parser_LDADD = \
|
||||
libsystemd-internal.la \
|
||||
libsystemd-shared.la
|
||||
|
||||
test_unifont_SOURCES = \
|
||||
src/libsystemd-terminal/test-unifont.c
|
||||
|
||||
test_unifont_LDADD = \
|
||||
libsystemd-terminal.la \
|
||||
libsystemd-internal.la \
|
||||
libsystemd-shared.la
|
||||
|
||||
update-unifont:
|
||||
$(AM_V_GEN)cat $(top_srcdir)/src/libsystemd-terminal/unifont.hex | $(PYTHON) $(top_srcdir)/tools/compile-unifont.py >$(top_srcdir)/src/libsystemd-terminal/unifont-glyph-array.bin
|
||||
@echo "unifont-glyph-array.bin has been regenerated"
|
||||
|
||||
.PHONY: update-unifont
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
if ENABLE_GTK_DOC
|
||||
SUBDIRS += \
|
||||
|
128
src/libsystemd-terminal/test-unifont.c
Normal file
128
src/libsystemd-terminal/test-unifont.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
/*
|
||||
* Test Unifont Helper
|
||||
* This tries opening the binary unifont glyph-array and renders some glyphs.
|
||||
* The glyphs are then compared to hard-coded glyphs.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "macro.h"
|
||||
#include "unifont-def.h"
|
||||
#include "unifont-internal.h"
|
||||
#include "util.h"
|
||||
|
||||
static void render(char *w, const unifont_glyph *g) {
|
||||
unsigned int i, j;
|
||||
const uint8_t *d = g->data;
|
||||
|
||||
for (j = 0; j < 16; ++j) {
|
||||
for (i = 0; i < 8 * g->cwidth; ++i) {
|
||||
if (d[i / 8] & (1 << (7 - i % 8)))
|
||||
*w++ = '#';
|
||||
else
|
||||
*w++ = ' ';
|
||||
}
|
||||
*w++ = '\n';
|
||||
d += g->stride;
|
||||
}
|
||||
|
||||
*w++ = 0;
|
||||
}
|
||||
|
||||
static void test_unifont(void) {
|
||||
char buf[4096];
|
||||
unifont_glyph g;
|
||||
unifont *u;
|
||||
|
||||
assert_se(unifont_new(&u) >= 0);
|
||||
|
||||
/* lookup invalid font */
|
||||
assert_se(unifont_lookup(u, &g, 0xffffffffU) < 0);
|
||||
|
||||
/* lookup and render 'A' */
|
||||
assert_se(unifont_lookup(u, &g, 'A') >= 0);
|
||||
assert_se(g.width == 8);
|
||||
assert_se(g.height == 16);
|
||||
assert_se(g.stride >= 1);
|
||||
assert_se(g.cwidth == 1);
|
||||
assert_se(g.data != NULL);
|
||||
render(buf, &g);
|
||||
assert_se(!strcmp(buf,
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" ## \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" ###### \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" \n"
|
||||
" \n"
|
||||
));
|
||||
|
||||
/* lookup and render '什' */
|
||||
assert_se(unifont_lookup(u, &g, 0x4ec0) >= 0);
|
||||
assert_se(g.width == 16);
|
||||
assert_se(g.height == 16);
|
||||
assert_se(g.stride >= 2);
|
||||
assert_se(g.cwidth == 2);
|
||||
assert_se(g.data != NULL);
|
||||
render(buf, &g);
|
||||
assert_se(!strcmp(buf,
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" ## # \n"
|
||||
" ## ########## \n"
|
||||
" # # # \n"
|
||||
"# # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
" # # \n"
|
||||
));
|
||||
|
||||
unifont_unref(u);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (access(UNIFONT_PATH, F_OK))
|
||||
return 77;
|
||||
|
||||
test_unifont();
|
||||
|
||||
return 0;
|
||||
}
|
137
src/libsystemd-terminal/unifont-def.h
Normal file
137
src/libsystemd-terminal/unifont-def.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "sparse-endian.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct unifont_header unifont_header;
|
||||
typedef struct unifont_glyph_header unifont_glyph_header;
|
||||
|
||||
/*
|
||||
* Unifont: On-disk data
|
||||
* Conventional font-formats have the problem that you have to pre-render each
|
||||
* glyph before you can use it. If you just need one glyph, you have to parse
|
||||
* the font-file until you found that glyph.
|
||||
* GNU-Unifont is a bitmap font with very good Unicode coverage. All glyphs are
|
||||
* (n*8)x16 bitmaps. Our on-disk data stores all those glyphs pre-compiled with
|
||||
* fixed offsets. Therefore, the font-file can be mmap()ed and all glyphs can
|
||||
* be accessed in O(1) (because all glyphs have the same size and thus their
|
||||
* offsets can be easily computed). This guarantees, that the kernel only loads
|
||||
* the pages that are really accessed. Thus, we have a far lower overhead than
|
||||
* traditional font-formats like BDF. Furthermore, the backing file is read-only
|
||||
* and can be shared in memory between multiple users.
|
||||
*
|
||||
* The binary-format starts with a fixed header:
|
||||
*
|
||||
* | 2bytes | 2bytes | 2bytes | 2bytes |
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | SIGNATURE | 8 bytes
|
||||
* +-----------------+-----------------+
|
||||
* | COMPAT FLAGS | INCOMPAT FLAGS | 8 bytes
|
||||
* +-----------------+--------+--------+
|
||||
* | HEADER SIZE |GH-SIZE |G-STRIDE| 8 bytes
|
||||
* +-----------------+--------+--------+
|
||||
* | GLYPH BODY SIZE | 8 bytes
|
||||
* +-----------------------------------+
|
||||
*
|
||||
* * The 8 bytes signature must be set to the ASCII string "DVDHRMUF".
|
||||
* * The 4 bytes compatible-flags field contains flags for new features that
|
||||
* might be added in the future and which are compatible to older parsers.
|
||||
* * The 4 bytes incompatible-flags field contains flags for new features that
|
||||
* might be added in the future and which are incompatible to old parses.
|
||||
* Thus, if you encounter an unknown bit set, you must abort!
|
||||
* * The 4 bytes header-size field contains the size of the header in bytes. It
|
||||
* must be at least 32 (the size of this fixed header). If new features are
|
||||
* added, it might be increased. It can also be used to add padding to the
|
||||
* end of the header.
|
||||
* * The 2 bytes glyph-header-size field specifies the size of each glyph
|
||||
* header in bytes (see below).
|
||||
* * The 2 bytes glyph-stride field specifies the stride of each line of glyph
|
||||
* data in "bytes per line".
|
||||
* * The 8 byte glyph-body-size field defines the size of each glyph body in
|
||||
* bytes.
|
||||
*
|
||||
* After the header, the file can contain padding bytes, depending on the
|
||||
* header-size field. Everything beyond the header+padding is treated as a big
|
||||
* array of glyphs. Each glyph looks like this:
|
||||
*
|
||||
* | 1 byte |
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | WIDTH | 1 byte
|
||||
* +-----------------------------------+
|
||||
* ~ PADDING ~
|
||||
* +-----------------------------------+
|
||||
* ~ ~
|
||||
* ~ ~
|
||||
* ~ DATA ~
|
||||
* ~ ~
|
||||
* ~ ~
|
||||
* +-----------------------------------+
|
||||
*
|
||||
* * The first byte specifies the width of the glyph. If it is 0, the glyph
|
||||
* must be treated as non-existant.
|
||||
* All glyphs are "8*n" pixels wide and "16" pixels high. The width-field
|
||||
* specifies the width multiplier "n".
|
||||
* * After the width field padding might be added. This depends on the global
|
||||
* glyph-header-size field. It defines the total size of each glyph-header.
|
||||
* After the glyph-header+padding, the data-field starts.
|
||||
* * The data-field contains a byte-array of bitmap data. The array is always
|
||||
* as big as specified in the global glyph-body-size header field. This might
|
||||
* include padding.
|
||||
* The array contains all 16 lines of bitmap information for that glyph. The
|
||||
* stride is given in the global glyph-stride header field. This can be used
|
||||
* to add padding after each line.
|
||||
* Each line is encoded as 1 bit per pixel bitmap. That is, each byte encodes
|
||||
* data for 8 pixels (left most pixel is encoded in the LSB, right most pixel
|
||||
* in the MSB). The width field defines the number of bytes valid per line.
|
||||
* For width==1, you need 1 byte to encode the 8 pixels. The stride defines
|
||||
* where the encoding of the next line starts.
|
||||
* Any data beyond the 16th line is padding and must be ignored.
|
||||
*/
|
||||
|
||||
/* path to binary file */
|
||||
#define UNIFONT_PATH "/usr/share/unifont/unifont-glyph-array.bin"
|
||||
|
||||
/* header-size of version 1 */
|
||||
#define UNIFONT_HEADER_SIZE_MIN 32
|
||||
|
||||
struct unifont_header {
|
||||
/* fields available in version 1 */
|
||||
uint8_t signature[8];
|
||||
le32_t compatible_flags;
|
||||
le32_t incompatible_flags;
|
||||
le32_t header_size;
|
||||
le16_t glyph_header_size;
|
||||
le16_t glyph_stride;
|
||||
le64_t glyph_body_size;
|
||||
} _packed_;
|
||||
|
||||
struct unifont_glyph_header {
|
||||
/* fields available in version 1 */
|
||||
uint8_t width;
|
||||
} _packed_;
|
BIN
src/libsystemd-terminal/unifont-glyph-array.bin
Normal file
BIN
src/libsystemd-terminal/unifont-glyph-array.bin
Normal file
Binary file not shown.
54
src/libsystemd-terminal/unifont-internal.h
Normal file
54
src/libsystemd-terminal/unifont-internal.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "util.h"
|
||||
|
||||
typedef struct unifont unifont;
|
||||
typedef struct unifont_glyph unifont_glyph;
|
||||
|
||||
/*
|
||||
* Unifont
|
||||
* The unifont API provides a glyph-lookup for bitmap fonts which can be used
|
||||
* as fallback if no system-font is available or if you don't want to deal with
|
||||
* full font renderers.
|
||||
*/
|
||||
|
||||
struct unifont_glyph {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int stride;
|
||||
unsigned int cwidth;
|
||||
const void *data; /* unaligned! */
|
||||
};
|
||||
|
||||
int unifont_new(unifont **out);
|
||||
unifont *unifont_ref(unifont *u);
|
||||
unifont *unifont_unref(unifont *u);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(unifont*, unifont_unref);
|
||||
|
||||
unsigned int unifont_get_stride(unifont *u);
|
||||
int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4);
|
211
src/libsystemd-terminal/unifont.c
Normal file
211
src/libsystemd-terminal/unifont.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
/*
|
||||
* Unifont
|
||||
* This implements the unifont glyph-array parser and provides it via a simple
|
||||
* API to the caller. No heavy transformations are performed so glyph-lookups
|
||||
* stay as fast as possible.
|
||||
*/
|
||||
|
||||
#include <endian.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "macro.h"
|
||||
#include "unifont-def.h"
|
||||
#include "unifont-internal.h"
|
||||
#include "util.h"
|
||||
|
||||
struct unifont {
|
||||
unsigned long ref;
|
||||
|
||||
int fd;
|
||||
const uint8_t *map;
|
||||
size_t size;
|
||||
|
||||
unifont_header header;
|
||||
const void *glyphs; /* unaligned! */
|
||||
size_t n_glyphs;
|
||||
size_t glyphsize;
|
||||
};
|
||||
|
||||
static int unifont_fetch_header(unifont *u) {
|
||||
unifont_header h = { };
|
||||
uint64_t glyphsize;
|
||||
|
||||
if (u->size < UNIFONT_HEADER_SIZE_MIN)
|
||||
return -EBFONT;
|
||||
|
||||
assert_cc(sizeof(h) >= UNIFONT_HEADER_SIZE_MIN);
|
||||
memcpy(&h, u->map, UNIFONT_HEADER_SIZE_MIN);
|
||||
|
||||
h.compatible_flags = le32toh(h.compatible_flags);
|
||||
h.incompatible_flags = le32toh(h.incompatible_flags);
|
||||
h.header_size = le32toh(h.header_size);
|
||||
h.glyph_header_size = le16toh(h.glyph_header_size);
|
||||
h.glyph_stride = le16toh(h.glyph_stride);
|
||||
h.glyph_body_size = le64toh(h.glyph_body_size);
|
||||
|
||||
if (memcmp(h.signature, "DVDHRMUF", 8))
|
||||
return -EBFONT;
|
||||
if (h.incompatible_flags != 0)
|
||||
return -EBFONT;
|
||||
if (h.header_size < UNIFONT_HEADER_SIZE_MIN || h.header_size > u->size)
|
||||
return -EBFONT;
|
||||
if (h.glyph_header_size + h.glyph_body_size < h.glyph_header_size)
|
||||
return -EBFONT;
|
||||
if (h.glyph_stride * 16ULL > h.glyph_body_size)
|
||||
return -EBFONT;
|
||||
|
||||
glyphsize = h.glyph_header_size + h.glyph_body_size;
|
||||
|
||||
if (glyphsize == 0 || glyphsize > u->size - h.header_size) {
|
||||
u->n_glyphs = 0;
|
||||
} else {
|
||||
u->glyphs = u->map + h.header_size;
|
||||
u->n_glyphs = (u->size - h.header_size) / glyphsize;
|
||||
u->glyphsize = glyphsize;
|
||||
}
|
||||
|
||||
memcpy(&u->header, &h, sizeof(h));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unifont_fetch_glyph(unifont *u, unifont_glyph_header *out_header, const void **out_body, uint32_t ucs4) {
|
||||
unifont_glyph_header glyph_header = { };
|
||||
const void *glyph_body = NULL;
|
||||
const uint8_t *p;
|
||||
|
||||
if (ucs4 >= u->n_glyphs)
|
||||
return -ENOENT;
|
||||
|
||||
p = u->glyphs;
|
||||
|
||||
/* copy glyph-header data */
|
||||
p += ucs4 * u->glyphsize;
|
||||
memcpy(&glyph_header, p, MIN(sizeof(glyph_header), u->header.glyph_header_size));
|
||||
|
||||
/* copy glyph-body pointer */
|
||||
p += u->header.glyph_header_size;
|
||||
glyph_body = p;
|
||||
|
||||
if (glyph_header.width < 1)
|
||||
return -ENOENT;
|
||||
if (glyph_header.width > u->header.glyph_stride)
|
||||
return -EBFONT;
|
||||
|
||||
memcpy(out_header, &glyph_header, sizeof(glyph_header));
|
||||
*out_body = glyph_body;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unifont_new(unifont **out) {
|
||||
_cleanup_(unifont_unrefp) unifont *u = NULL;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert_return(out, -EINVAL);
|
||||
|
||||
u = new0(unifont, 1);
|
||||
if (!u)
|
||||
return -ENOMEM;
|
||||
|
||||
u->ref = 1;
|
||||
u->fd = -1;
|
||||
u->map = MAP_FAILED;
|
||||
|
||||
u->fd = open(UNIFONT_PATH, O_RDONLY | O_CLOEXEC | O_NOCTTY);
|
||||
if (u->fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = fstat(u->fd, &st);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
u->size = st.st_size;
|
||||
u->map = mmap(NULL, u->size, PROT_READ, MAP_PRIVATE, u->fd, 0);
|
||||
if (u->map == MAP_FAILED)
|
||||
return -errno;
|
||||
|
||||
r = unifont_fetch_header(u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*out = u;
|
||||
u = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unifont *unifont_ref(unifont *u) {
|
||||
if (!u || !u->ref)
|
||||
return NULL;
|
||||
|
||||
++u->ref;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
unifont *unifont_unref(unifont *u) {
|
||||
if (!u || !u->ref || --u->ref)
|
||||
return NULL;
|
||||
|
||||
if (u->map != MAP_FAILED)
|
||||
munmap((void*)u->map, u->size);
|
||||
u->fd = safe_close(u->fd);
|
||||
free(u);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int unifont_get_stride(unifont *u) {
|
||||
assert(u);
|
||||
|
||||
return u->header.glyph_stride;
|
||||
}
|
||||
|
||||
int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4) {
|
||||
unifont_glyph_header h = { };
|
||||
const void *b = NULL;
|
||||
unifont_glyph g = { };
|
||||
int r;
|
||||
|
||||
assert_return(u, -EINVAL);
|
||||
|
||||
r = unifont_fetch_glyph(u, &h, &b, ucs4);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
g.width = h.width * 8U;
|
||||
g.height = 16U;
|
||||
g.stride = u->header.glyph_stride;
|
||||
g.cwidth = h.width;
|
||||
g.data = b;
|
||||
|
||||
if (out)
|
||||
memcpy(out, &g, sizeof(g));
|
||||
return 0;
|
||||
}
|
63488
src/libsystemd-terminal/unifont.hex
Normal file
63488
src/libsystemd-terminal/unifont.hex
Normal file
File diff suppressed because it is too large
Load Diff
116
tools/compile-unifont.py
Executable file
116
tools/compile-unifont.py
Executable file
@ -0,0 +1,116 @@
|
||||
# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# Copyright 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# systemd is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#
|
||||
# Parse a unifont.hex file and produce a compressed binary-format.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
import re
|
||||
import sys
|
||||
import fileinput
|
||||
import struct
|
||||
|
||||
#
|
||||
# Write "bits" array as binary output.
|
||||
#
|
||||
|
||||
def write_bin_entry(entry):
|
||||
l = len(entry)
|
||||
if l != 32 and l != 64:
|
||||
entry = "0" * 64
|
||||
l = 0
|
||||
elif l < 64:
|
||||
entry += "0" * (64 - l)
|
||||
|
||||
sys.stdout.buffer.write(struct.pack('B', int(l / 32))) # width
|
||||
sys.stdout.buffer.write(struct.pack('B', 0)) # padding
|
||||
sys.stdout.buffer.write(struct.pack('H', 0)) # padding
|
||||
sys.stdout.buffer.write(struct.pack('I', 0)) # padding
|
||||
|
||||
i = 0
|
||||
for j in range(0, 16):
|
||||
for k in range(0, 2):
|
||||
if l <= k * 16 * 2:
|
||||
c = 0
|
||||
else:
|
||||
c = int(entry[i:i+2], 16)
|
||||
i += 2
|
||||
|
||||
sys.stdout.buffer.write(struct.pack('B', c))
|
||||
|
||||
def write_bin(bits):
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x44)) # ASCII: 'D'
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x56)) # ASCII: 'V'
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x44)) # ASCII: 'D'
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x48)) # ASCII: 'H'
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x52)) # ASCII: 'R'
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x4d)) # ASCII: 'M'
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x55)) # ASCII: 'U'
|
||||
sys.stdout.buffer.write(struct.pack('B', 0x46)) # ASCII: 'F'
|
||||
sys.stdout.buffer.write(struct.pack('<I', 0)) # compatible-flags
|
||||
sys.stdout.buffer.write(struct.pack('<I', 0)) # incompatible-flags
|
||||
sys.stdout.buffer.write(struct.pack('<I', 32)) # header-size
|
||||
sys.stdout.buffer.write(struct.pack('<H', 8)) # glyph-header-size
|
||||
sys.stdout.buffer.write(struct.pack('<H', 2)) # glyph-stride
|
||||
sys.stdout.buffer.write(struct.pack('<Q', 32)) # glyph-body-size
|
||||
|
||||
# write glyphs
|
||||
for idx in range(len(bits)):
|
||||
write_bin_entry(bits[idx])
|
||||
|
||||
#
|
||||
# Parse hex file into "bits" array
|
||||
#
|
||||
|
||||
def parse_hex_line(bits, line):
|
||||
m = re.match(r"^([0-9A-Fa-f]+):([0-9A-Fa-f]+)$", line)
|
||||
if m == None:
|
||||
return
|
||||
|
||||
idx = int(m.group(1), 16)
|
||||
val = m.group(2)
|
||||
|
||||
# insert skipped lines
|
||||
for i in range(len(bits), idx):
|
||||
bits.append("")
|
||||
|
||||
bits.insert(idx, val)
|
||||
|
||||
def parse_hex():
|
||||
bits = []
|
||||
|
||||
for line in sys.stdin:
|
||||
if not line:
|
||||
continue
|
||||
if line.startswith("#"):
|
||||
continue
|
||||
|
||||
parse_hex_line(bits, line)
|
||||
|
||||
return bits
|
||||
|
||||
#
|
||||
# In normal mode we simply read line by line from standard-input and write the
|
||||
# binary-file to standard-output.
|
||||
#
|
||||
|
||||
if __name__ == "__main__":
|
||||
bits = parse_hex()
|
||||
write_bin(bits)
|
Loading…
Reference in New Issue
Block a user