aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-08-17 17:44:35 +0200
committerMattias Andrée <maandree@kth.se>2021-08-17 17:44:35 +0200
commit6b8fc61b772b394d7a205531b492101c519dc47d (patch)
tree85d441e2de4d57e9432a5d0173aa48c214ebb39c
parentm (diff)
downloadlibskrift-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--Makefile3
-rw-r--r--README2
-rw-r--r--common.h25
-rw-r--r--config.mk7
-rw-r--r--libskrift.h6
-rw-r--r--libskrift_apply_glyph.c2
-rw-r--r--libskrift_close_font.c3
-rw-r--r--libskrift_create_context.c4
-rw-r--r--libskrift_open_font.c5
-rw-r--r--libskrift_open_font___.c250
-rw-r--r--libskrift_open_font_adopt_mem.c8
-rw-r--r--libskrift_open_font_adopt_mmap.c8
-rw-r--r--libskrift_open_font_fd.c7
-rw-r--r--libskrift_open_font_file.c12
-rw-r--r--libskrift_open_font_mem.c12
15 files changed, 313 insertions, 41 deletions
diff --git a/Makefile b/Makefile
index 9e52389..2c7879e 100644
--- a/Makefile
+++ b/Makefile
@@ -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\
diff --git a/README b/README
index 5d81582..c95e6c5 100644
--- a/README
+++ b/README
@@ -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”).
diff --git a/common.h b/common.h
index d8c4a56..e643477 100644
--- a/common.h
+++ b/common.h
@@ -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);
diff --git a/config.mk b/config.mk
index 20f94ed..ebb4e93 100644
--- a/config.mk
+++ b/config.mk
@@ -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);
}