diff options
author | Mattias Andrée <maandree@kth.se> | 2021-08-17 17:44:35 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2021-08-17 17:44:35 +0200 |
commit | 6b8fc61b772b394d7a205531b492101c519dc47d (patch) | |
tree | 85d441e2de4d57e9432a5d0173aa48c214ebb39c | |
parent | m (diff) | |
download | libskrift-6b8fc61b772b394d7a205531b492101c519dc47d.tar.gz libskrift-6b8fc61b772b394d7a205531b492101c519dc47d.tar.bz2 libskrift-6b8fc61b772b394d7a205531b492101c519dc47d.tar.xz |
Add support for gzip compression and prepare for PSF support
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | common.h | 25 | ||||
-rw-r--r-- | config.mk | 7 | ||||
-rw-r--r-- | libskrift.h | 6 | ||||
-rw-r--r-- | libskrift_apply_glyph.c | 2 | ||||
-rw-r--r-- | libskrift_close_font.c | 3 | ||||
-rw-r--r-- | libskrift_create_context.c | 4 | ||||
-rw-r--r-- | libskrift_open_font.c | 5 | ||||
-rw-r--r-- | libskrift_open_font___.c | 250 | ||||
-rw-r--r-- | libskrift_open_font_adopt_mem.c | 8 | ||||
-rw-r--r-- | libskrift_open_font_adopt_mmap.c | 8 | ||||
-rw-r--r-- | libskrift_open_font_fd.c | 7 | ||||
-rw-r--r-- | libskrift_open_font_file.c | 12 | ||||
-rw-r--r-- | libskrift_open_font_mem.c | 12 |
15 files changed, 313 insertions, 41 deletions
@@ -28,6 +28,9 @@ OBJ =\ libskrift_merge_glyphs.o\ libskrift_millimeters_to_pixels.o\ libskrift_open_font.o\ + libskrift_open_font___.o\ + libskrift_open_font_adopt_mem.o\ + libskrift_open_font_adopt_mmap.o\ libskrift_open_font_at.o\ libskrift_open_font_fd.o\ libskrift_open_font_file.o\ @@ -2,7 +2,7 @@ libskrift is a text drawing library for C that is based on libschrift. The name: - Schrift in libschift is German for “font” (can also mean “scripture”), + Schrift in libschrift is German for “font” (can also mean “scripture”), skrift in libskrift is Swedish for “scripture” (cannot mean “font”). @@ -2,11 +2,14 @@ #include <sys/mman.h> #include <sys/stat.h> +#include <sys/wait.h> #include <alloca.h> #include <endian.h> #include <errno.h> #include <fcntl.h> #include <math.h> +#include <poll.h> +#include <signal.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -17,17 +20,25 @@ #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B)) -#define LEN(ARR) (sizeof(ARR) / sizeof(*(ARR))) +#define ELEMSOF(ARR) (sizeof(ARR) / sizeof(*(ARR))) #define FLEXSTRUCTSIZE(STRUCT, FLEXARRAY, FLEXARRAY_LENGTH)\ (offsetof(STRUCT, FLEXARRAY) + (FLEXARRAY_LENGTH) * sizeof(*((STRUCT *)NULL)->FLEXARRAY)) +enum font_type { + FONT_TYPE_SCHRIFT /* using libschrift backend */ +}; + struct libskrift_font { - SFT_Font *font; - void *memory_free; - void *memory_unmap; - size_t memory_size; - size_t refcount; + enum font_type font_type; + union { + void *any; + SFT_Font *schrift; + } font; + void *memory_free; + void *memory_unmap; + size_t memory_size; + size_t refcount; }; struct libskrift_context { @@ -55,3 +66,5 @@ struct format_settings { }; extern const struct format_settings libskrift_format_settings[LIBSKRIFT_RGBA_LONG_DOUBLE + 1]; + +int libskrift_open_font___(LIBSKRIFT_FONT **fontp, const void *mem_static, void *mem_free, void *mem_unmap, size_t size); @@ -3,12 +3,17 @@ MANPREFIX = $(PREFIX)/share/man DEMO_FONT = /usr/share/fonts/liberation/LiberationSans-Regular.ttf +GUNZIP_PATH = /usr/bin/gunzip +GZIP_SUPPORT = '-DGUNZIP_PATH="$(GUNZIP_PATH)"' +# To exclude gzip support, build with 'GZIP_SUPPORT=' + MERGE_STYLE = MAX # MAX: The max value of the glyph (minimum legal result, insignificantly slower than SUM) # OR: The bitwise OR of the glyph values (within legal range, fastest) # SUM: The saturated sum of the glyph values (maximum legal result) -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE -D$(MERGE_STYLE)_MERGE '-DDEMO_FONT="$(DEMO_FONT)"' +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE \ + -D$(MERGE_STYLE)_MERGE $(GZIP_SUPPORT) '-DDEMO_FONT="$(DEMO_FONT)"' CFLAGS = -std=c99 -Wall -g LDFLAGS = -lschrift -lm -lgrapheme diff --git a/libskrift.h b/libskrift.h index 4c8cd25..41814e6 100644 --- a/libskrift.h +++ b/libskrift.h @@ -233,6 +233,12 @@ _LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) int libskrift_open_font_mem(LIBSKRIFT_FONT **, const void *, size_t); _LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +int libskrift_open_font_adopt_mem(LIBSKRIFT_FONT **, void *, size_t); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +int libskrift_open_font_adopt_mmap(LIBSKRIFT_FONT **, void *, size_t); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) int libskrift_open_font_fd(LIBSKRIFT_FONT **, int); _LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) diff --git a/libskrift_apply_glyph.c b/libskrift_apply_glyph.c index 6e61732..4cf5afc 100644 --- a/libskrift_apply_glyph.c +++ b/libskrift_apply_glyph.c @@ -53,7 +53,7 @@ libskrift_apply_glyph(LIBSKRIFT_CONTEXT *ctx, const struct libskrift_glyph *glyp const uint32_t u32 = 0x01020304L; const uint64_t u64 = 0x0102030405060708LL; - if (image->format == LIBSKRIFT_RAW || (unsigned int)image->format > (unsigned int)LEN(libskrift_format_settings)) { + if (image->format == LIBSKRIFT_RAW || (unsigned int)image->format > (unsigned int)ELEMSOF(libskrift_format_settings)) { errno = EINVAL; return -1; } diff --git a/libskrift_close_font.c b/libskrift_close_font.c index 2786666..c665cdb 100644 --- a/libskrift_close_font.c +++ b/libskrift_close_font.c @@ -5,7 +5,8 @@ void libskrift_close_font(LIBSKRIFT_FONT *font) { if (font && !--font->refcount) { - sft_freefont(font->font); + if (font->font_type == FONT_TYPE_SCHRIFT) + sft_freefont(font->font.schrift); free(font->memory_free); if (font->memory_unmap) munmap(font->memory_unmap, font->memory_size); diff --git a/libskrift_create_context.c b/libskrift_create_context.c index a1d01e0..15f8d50 100644 --- a/libskrift_create_context.c +++ b/libskrift_create_context.c @@ -8,7 +8,7 @@ #define IMPLEMENTED_FLAGS (LIBSKRIFT_REMOVE_GAMMA |\ LIBSKRIFT_MIRROR_TEXT |\ LIBSKRIFT_MIRROR_CHARS |\ - FORCED_FLAGS) /* libschrift does not add gamma, so not handling is required */ + FORCED_FLAGS) /* libschrift does not add gamma, so no handling is required */ #define TRANSFORMING_FLAGS (LIBSKRIFT_MIRROR_TEXT |\ LIBSKRIFT_MIRROR_CHARS |\ @@ -75,7 +75,7 @@ libskrift_create_context(LIBSKRIFT_CONTEXT **ctxp, LIBSKRIFT_FONT **fonts, size_ if (!*ctxp) return -1; - (*ctxp)->schrift_ctx.font = fonts[0]->font; + (*ctxp)->schrift_ctx.font = fonts[0]->font.schrift; (*ctxp)->schrift_ctx.yScale = height; (*ctxp)->char_x_advancement = 1; (*ctxp)->char_y_advancement = 0; diff --git a/libskrift_open_font.c b/libskrift_open_font.c index d829a66..fdd5ba9 100644 --- a/libskrift_open_font.c +++ b/libskrift_open_font.c @@ -38,13 +38,10 @@ libskrift_open_font(LIBSKRIFT_FONT **fontp, FILE *fp) mem = new; errno = saved_errno; - if (libskrift_open_font_mem(fontp, mem, size)) { + if (libskrift_open_font_adopt_mem(fontp, mem, size)) { free(mem); return -1; } - (*fontp)->memory_free = mem; - (*fontp)->memory_size = size; - return 0; } diff --git a/libskrift_open_font___.c b/libskrift_open_font___.c new file mode 100644 index 0000000..c1bcfb5 --- /dev/null +++ b/libskrift_open_font___.c @@ -0,0 +1,250 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +#ifdef GUNZIP_PATH +# define IS_GZIP() (size >= 18 && mem8[0] == 0x1f && mem8[1] == 0x8b) +#endif + +#define IS_PSF_V1() (size >= 4 && mem8[0] == 0x36 && mem8[1] == 0x04) +#define IS_PSF_V2() (size >= 32 && mem8[0] == 0x72 && mem8[1] == 0xb5 && mem8[2] == 0x4a && mem8[3] == 0x86) + +#if defined(GUNZIP_PATH) +static int +decompress(const char *path, const void *mem, size_t size, void **memp, size_t *sizep) +{ + const char *mem_in = mem; + char *mem_out = *memp, *new; + size_t off_in = 0, off_out = 0; + int i, n, mem_fds[2][2], err_fds[2], saved_errno; + struct pollfd pfds[2]; + nfds_t npfds; + int status; + pid_t pid; + ssize_t r; + + if (pipe(mem_fds[0])) + return -1; + + if (pipe(mem_fds[1])) { + saved_errno = errno; + close(mem_fds[0][0]); + close(mem_fds[0][1]); + errno = saved_errno; + return -1; + } + + if (pipe2(err_fds, O_CLOEXEC)) { + saved_errno = errno; + close(mem_fds[0][0]); + close(mem_fds[0][1]); + close(mem_fds[1][0]); + close(mem_fds[1][1]); + errno = saved_errno; + return -1; + } + + switch ((pid = fork())) { + case -1: + saved_errno = errno; + close(mem_fds[0][0]); + close(mem_fds[0][1]); + close(mem_fds[1][0]); + close(mem_fds[1][1]); + close(err_fds[0]); + close(err_fds[1]); + errno = saved_errno; + return -1; + + case 0: + close(err_fds[0]); + for (i = 0; i < 2; i++) { + if (mem_fds[i][i] != i) { + close(i); + dup2_again: + if (dup2(mem_fds[i][i], i) != i) { + if (errno == EINTR) + goto dup2_again; + write(err_fds[1], &errno, sizeof(errno)); + return 255; + } + close(mem_fds[i][i]); + } + close(mem_fds[i][i ^ 1]); + } + execl(path, path, NULL); + write(err_fds[1], &errno, sizeof(errno)); + return 255; + + default: + break; + } + + close(err_fds[1]); + close(mem_fds[0][0]); + close(mem_fds[1][1]); + + memset(pfds, 0, sizeof(pfds)); + pfds[0].fd = mem_fds[1][0]; + pfds[1].fd = mem_fds[0][1]; + pfds[0].events = POLLIN; + pfds[1].events = POLLOUT; + npfds = 2; + for (;;) { + n = poll(pfds, npfds, -1); + if (n <= 0) { + if (!n) + continue; + poll_loop_fail: + saved_errno = errno; + close(err_fds[1]); + if (mem_fds[0][1] >= 0) + close(mem_fds[0][1]); + close(mem_fds[1][0]); + kill(pid, SIGKILL); + waitpid(pid, NULL, 0); + free(mem_out); + errno = saved_errno; + return -1; + } + if (pfds[0].revents) { + if (*sizep == off_out) { + if (*sizep > SIZE_MAX - 4096) { + errno = ENOMEM; + goto poll_loop_fail; + } + new = realloc(mem_out, *sizep += 4096); + if (!new) + goto poll_loop_fail; + mem_out = new; + } + read_again: + r = read(pfds[0].fd, &mem_out[off_out], *sizep - off_out); + if (r <= 0) { + if (!r) + break; + if (errno == EINTR) + goto read_again; + goto poll_loop_fail; + } + off_out += (size_t)r; + } + if (npfds > 1 && pfds[1].revents) { + if (off_in == size) { + npfds -= 1; + close(mem_fds[0][1]); + mem_fds[0][1] = -1; + continue; + } +write_again: + r = write(pfds[1].fd, &mem_in[off_in], MIN(size - off_in, (size_t)1 << 16)); + if (r <= 0) { + if (r < 0 && errno == EINTR) + goto write_again; + goto poll_loop_fail; + } + off_in += (size_t)r; + } + } + + if (mem_fds[0][1] >= 0) + close(mem_fds[0][1]); + close(mem_fds[1][0]); + +waitpid_again: + if (waitpid(pid, &status, 0) != pid) { + if (errno == EINTR) + goto waitpid_again; + saved_errno = errno; + close(err_fds[0]); + free(mem_out); + errno = saved_errno; + } + + if (WIFEXITED(status) && WEXITSTATUS(status) == 255) { + if (read(err_fds[1], &errno, sizeof(errno)) == sizeof(errno)) { + goto child_failed; + } else { + errno = EIO; + goto child_failed; + } + } else if (status) { + errno = WIFEXITED(status) ? EBFONT : EPIPE; + goto child_failed; + } else if (off_in < size) { + errno = EPIPE; + child_failed: + saved_errno = errno; + close(err_fds[0]); + free(mem_out); + errno = saved_errno; + return -1; + } + + close(err_fds[0]); + + if (*sizep > off_out) { + new = realloc(mem_out, off_out); + if (new) + mem_out = new; + } + + *memp = mem_out; + *sizep = off_out; + return 0; +} +#endif + +int +libskrift_open_font___(LIBSKRIFT_FONT **fontp, const void *mem_static, void *mem_free, void *mem_unmap, size_t size) +{ + const void *mem = mem_static ? mem_static : mem_free ? mem_free : mem_unmap; + const uint8_t *mem8 = mem; + void *new_mem = NULL; +#if defined(GUNZIP_PATH) + size_t new_size = 0; +#endif + + *fontp = calloc(1, sizeof(**fontp)); + if (!*fontp) + return -1; + (*fontp)->refcount = 1; + +#if defined(GUNZIP_PATH) + if (IS_GZIP()) { + if (decompress(GUNZIP_PATH, mem, size, &new_mem, &new_size)) + return -1; + if (mem_free) + free(mem_free); + else if (mem_unmap) + munmap(mem_unmap, size); + mem_static = NULL; + mem_unmap = NULL; + mem8 = mem = mem_free = new_mem; + size = new_size; + } +#endif + + if (IS_PSF_V1() || IS_PSF_V2()) { /* TODO */ + errno = EBFONT; + return -1; + } else { + (*fontp)->font_type = FONT_TYPE_SCHRIFT; + (*fontp)->font.schrift = sft_loadmem(mem, size); + } + + if (!(*fontp)->font.any) { + free(*fontp); + *fontp = NULL; + return -1; + } + + if (mem_free) { + (*fontp)->memory_free = mem_free; + (*fontp)->memory_size = size; + } else if (mem_unmap) { + (*fontp)->memory_unmap = mem_unmap; + (*fontp)->memory_size = size; + } + + return 0; +} diff --git a/libskrift_open_font_adopt_mem.c b/libskrift_open_font_adopt_mem.c new file mode 100644 index 0000000..1e5e904 --- /dev/null +++ b/libskrift_open_font_adopt_mem.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libskrift_open_font_adopt_mem(LIBSKRIFT_FONT **fontp, void *mem, size_t size) +{ + return libskrift_open_font___(fontp, NULL, mem, NULL, size); +} diff --git a/libskrift_open_font_adopt_mmap.c b/libskrift_open_font_adopt_mmap.c new file mode 100644 index 0000000..964183a --- /dev/null +++ b/libskrift_open_font_adopt_mmap.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libskrift_open_font_adopt_mmap(LIBSKRIFT_FONT **fontp, void *mem, size_t size) +{ + return libskrift_open_font___(fontp, NULL, NULL, mem, size); +} diff --git a/libskrift_open_font_fd.c b/libskrift_open_font_fd.c index e134cd8..0e8b83d 100644 --- a/libskrift_open_font_fd.c +++ b/libskrift_open_font_fd.c @@ -46,7 +46,8 @@ libskrift_open_font_fd(LIBSKRIFT_FONT **fontp, int fd) mmapped = 1; } - if (libskrift_open_font_mem(fontp, mem, size)) { + if ((mmapped ? libskrift_open_font_adopt_mmap + : libskrift_open_font_adopt_mem)(fontp, mem, size)) { if (mmapped) munmap(mem, size); else @@ -54,9 +55,5 @@ libskrift_open_font_fd(LIBSKRIFT_FONT **fontp, int fd) return -1; } - (*fontp)->memory_free = mmapped ? NULL : mem; - (*fontp)->memory_unmap = mmapped ? mem : NULL; - (*fontp)->memory_size = size; - return 0; } diff --git a/libskrift_open_font_file.c b/libskrift_open_font_file.c index 2a122ef..32e69d6 100644 --- a/libskrift_open_font_file.c +++ b/libskrift_open_font_file.c @@ -4,15 +4,9 @@ int libskrift_open_font_file(LIBSKRIFT_FONT **fontp, const char *path) { - *fontp = calloc(1, sizeof(**fontp)); - if (!*fontp) - return -1; - (*fontp)->refcount = 1; - (*fontp)->font = sft_loadfile(path); - if (!(*fontp)->font) { - free(*fontp); - *fontp = NULL; + if (!*path) { + errno = EINVAL; return -1; } - return 0; + return libskrift_open_font_at(fontp, AT_FDCWD, path); } diff --git a/libskrift_open_font_mem.c b/libskrift_open_font_mem.c index 3828546..bda4252 100644 --- a/libskrift_open_font_mem.c +++ b/libskrift_open_font_mem.c @@ -4,15 +4,5 @@ int libskrift_open_font_mem(LIBSKRIFT_FONT **fontp, const void *mem, size_t size) { - *fontp = calloc(1, sizeof(**fontp)); - if (!*fontp) - return -1; - (*fontp)->refcount = 1; - (*fontp)->font = sft_loadmem(mem, size); - if (!(*fontp)->font) { - free(*fontp); - *fontp = NULL; - return -1; - } - return 0; + return libskrift_open_font___(fontp, mem, NULL, NULL, size); } |