diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2014-05-14 11:50:32 +0200 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2014-05-14 11:50:32 +0200 |
commit | ce19ed8ddffd05e0dc846470be7b22b530d5dc6d (patch) | |
tree | d7a154356e9b013d8d7352f381f297eb1988cdd3 /test |
Initial import
Import new mmap-unifont package, a pre-compiled version of the GNU-Unifont
font files:
GNU-Unifont is a bitmap Unicode font with almost complete Unicode
coverage. It is perfectly suited for low-level system binaries, as
fallback font, in emergency situations, and more.
mmap-unifont compiles a binary font format based on GNU-Unifont. This
compiled file can be memory-mapped by applications to get direct
font-access. This extremely simplifies font-usage for system-applications.
Advantages over using the original BDF font are:
* On-demand glyph loading: The whole font is pre-compiled with fixed
offsets. The header includes offsets and limits. Hence, an application
can directly access the memory-location of a glyph on-demand. The
operating-system can load the required memory-pages on first-access,
thus reducing the memory footprint considerably.
With BDF fonts, the application has to scan the whole BDF file to find
a given glyph. This requires loading 9MB of font-data just to display
the U+FFFD glyph.
* No need to write a BDF-format parser: While BDF is a quite simple
format, it still requires a parser. This is tedious and overkill, if
you don't intend to use other fonts than GNU-Unifont.
* Stronger guarantees: GNU-Unifont has some very handy features, which
cannot be expressed in most font-formats. While it is possible to rely
on them using any font-format, you usually violate the rules of the
font-format and thus make your application dependent on GNU-Unifont
(questioning why you wrote a BDF-parser in the first place).
Those features include:
* fixed size for all glyphs
* fixed underline position and thickness
* fixed horizontal/vertical advancement
* ...
* Additional annotations: Given the very precice use-case of
mmap-unifont, we can add additional glyph-annotations that simplify
rendering. For instance, combining-characters require you to draw
multiple glyphs on top of each other. The mmap-unifont package
provides annotations that describe the relative positioning of the
glyphs when drawn together.
mmap-unifont is strongly targetted at system-applications. It has no
external dependencies, is very memory-friendly, but still provides a font
with full Unicode-coverage. However, please note that it does not provide
any advanced layout-features (like RTL/LTR annotations). To render
fully-internationalized text, a layout-engine like HarfBuzz/Pango is
required.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/test-common.h | 75 | ||||
-rw-r--r-- | test/test-glyphs.c | 216 | ||||
-rw-r--r-- | test/test-valgrind.c | 23 |
3 files changed, 314 insertions, 0 deletions
diff --git a/test/test-common.h b/test/test-common.h new file mode 100644 index 0000000..a4f0fa2 --- /dev/null +++ b/test/test-common.h @@ -0,0 +1,75 @@ +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + +#include <check.h> +#include <endian.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +/* lower address-space is protected from user-allocation, so this is invalid */ +#define TEST_INVALID_PTR ((void*)0x10) + +#define TEST_DEFINE_CASE(_name) \ + static TCase *test_create_case_##_name(void) \ + { \ + TCase *tc; \ + \ + tc = tcase_create(#_name); \ + +#define TEST(_name) tcase_add_test(tc, _name); + +#define TEST_END_CASE \ + return tc; \ + } \ + +#define TEST_END NULL + +#define TEST_CASE(_name) test_create_case_##_name + +static inline Suite *test_create_suite(const char *name, ...) +{ + Suite *s; + va_list list; + TCase *(*fn)(void); + + s = suite_create(name); + + va_start(list, name); + while ((fn = va_arg(list, TCase *(*)(void)))) + suite_add_tcase(s, fn()); + va_end(list); + + return s; +} + +#define TEST_SUITE(_name, ...) test_create_suite((#_name), ##__VA_ARGS__) + +static inline int test_run_suite(Suite *s) +{ + int ret; + SRunner *sr; + + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + ret = srunner_ntests_failed(sr); + srunner_free(sr); + + return ret; +} + +#define TEST_DEFINE(_suite) \ + int main(int argc, char **argv) \ + { \ + return test_run_suite(_suite); \ + } + +#endif /* TEST_COMMON_H */ diff --git a/test/test-glyphs.c b/test/test-glyphs.c new file mode 100644 index 0000000..9c8f621 --- /dev/null +++ b/test/test-glyphs.c @@ -0,0 +1,216 @@ +#include "test-common.h" + +static int font_open(void) +{ + int fd; + + fd = open(PKGDATADIR "/mmap-unifont.bin", O_RDONLY | O_CLOEXEC); + ck_assert_int_ge(fd, 0); + + return fd; +} + +static void font_close(int fd) +{ + int r; + + r = close(fd); + ck_assert_int_ge(r, 0); +} + +static void *font_mmap(int fd, size_t *out_size) +{ + struct stat st; + void *p; + int r; + + r = fstat(fd, &st); + ck_assert_int_ge(r, 0); + + p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + ck_assert_ptr_ne(p, MAP_FAILED); + + if (out_size) + *out_size = st.st_size; + + return p; +} + +static void font_unmap(void *p, size_t size) +{ + int r; + + r = munmap(p, size); + ck_assert_int_ge(r, 0); +} + +static int font_fd = -1; +static void *font_p = NULL; +static size_t font_size = 0; + +static void font_init(void) +{ + font_fd = font_open(); + font_p = font_mmap(font_fd, &font_size); +} + +static void font_destroy(void) +{ + if (font_fd < 0) + return; + + font_unmap(font_p, font_size); + font_close(font_fd); + font_fd = -1; +} + +START_TEST(test_misc_setup) +{ + int fd; + void *p; + size_t size; + + fd = font_open(); + p = font_mmap(fd, &size); + font_unmap(p, size); + font_close(fd); + + font_init(); + ck_assert_int_ge(font_fd, 0); + font_destroy(); + ck_assert_int_lt(font_fd, 0); + font_destroy(); + ck_assert_int_lt(font_fd, 0); +} +END_TEST + +static void font_render(char *w, const uint8_t *glyph, size_t width) +{ + unsigned int i, j; + + for (j = 0; j < 16; ++j) { + for (i = 0; i < 8 * width; ++i) { + if (glyph[i / 8] & (1 << (7 - i % 8))) + *w++ = '#'; + else + *w++ = ' '; + } + *w++ = '\n'; + glyph += 1 * width; + } + + *w++ = 0; +} + +START_TEST(test_misc_draw) +{ + char buf[1024]; + const uint8_t *p, *end, *glyph; + size_t size, width; + uint32_t header_size, glyph_size; + + font_init(); + + p = font_p; + size = font_size; + end = p + font_size; + + /* parse 4-byte header-size */ + { + ck_assert_int_ge(size, 4); + header_size = *(uint32_t*)p; + header_size = le32toh(header_size); + p += sizeof(uint32_t); + } + + /* parse header */ + { + glyph_size = 33; + + switch (header_size) { + default: + /* fallthrough */ + case 4: + glyph_size = *(uint32_t*)p; + glyph_size = le32toh(glyph_size); + /* fallthrough */ + case 0 ... 3: + break; + } + + ck_assert_int_ge(glyph_size, 33); + } + + /* forward @p to end of header */ + p += header_size; + + /* access glyph 'A' */ + glyph = p + glyph_size * 'A'; + ck_assert(end >= glyph + glyph_size); + width = *glyph++; + ck_assert_int_eq(width, 1); + + /* draw glyph 'A' */ + font_render(buf, glyph, width); + ck_assert(!strcmp(buf, + " \n" + " \n" + " \n" + " \n" + " ## \n" + " # # \n" + " # # \n" + " # # \n" + " # # \n" + " ###### \n" + " # # \n" + " # # \n" + " # # \n" + " # # \n" + " \n" + " \n" + )); + + /* access wide glyph 0x4ec0 ('什') */ + glyph = p + glyph_size * 0x4ec0; + ck_assert(end >= glyph + glyph_size); + width = *glyph++; + ck_assert_int_eq(width, 2); + + /* draw wide glyph */ + font_render(buf, glyph, width); + ck_assert(!strcmp(buf, + " # # \n" + " # # \n" + " # # \n" + " # # \n" + " # # \n" + " ## # \n" + " ## ########## \n" + " # # # \n" + "# # # \n" + " # # \n" + " # # \n" + " # # \n" + " # # \n" + " # # \n" + " # # \n" + " # # \n" + )); + + /* close font */ + font_destroy(); +} +END_TEST + +TEST_DEFINE_CASE(misc) + TEST(test_misc_setup) + TEST(test_misc_draw) +TEST_END_CASE + +TEST_DEFINE( + TEST_SUITE(glyphs, + TEST_CASE(misc), + TEST_END + ) +) diff --git a/test/test-valgrind.c b/test/test-valgrind.c new file mode 100644 index 0000000..65034c1 --- /dev/null +++ b/test/test-valgrind.c @@ -0,0 +1,23 @@ +/* Dummy which just leaks memory. Used to verify valgrind memcheck. */ + +#include "test-common.h" + +START_TEST(test_valgrind) +{ + void *p; + + p = malloc(0x100); + ck_assert(!!p); +} +END_TEST + +TEST_DEFINE_CASE(misc) + TEST(test_valgrind) +TEST_END_CASE + +TEST_DEFINE( + TEST_SUITE(valgrind, + TEST_CASE(misc), + TEST_END + ) +) |