diff options
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | LICENSE | 15 | ||||
-rw-r--r-- | Makefile | 60 | ||||
-rw-r--r-- | common.h | 32 | ||||
-rw-r--r-- | config.mk | 10 | ||||
-rw-r--r-- | demo.c | 73 | ||||
-rw-r--r-- | libskrift.h | 183 | ||||
-rw-r--r-- | libskrift_calculate_dpi.c | 4 | ||||
-rw-r--r-- | libskrift_close_font.c | 14 | ||||
-rw-r--r-- | libskrift_create_context.c | 82 | ||||
-rw-r--r-- | libskrift_free_context.c | 11 | ||||
-rw-r--r-- | libskrift_get_cluster_glyph.c | 69 | ||||
-rw-r--r-- | libskrift_get_grapheme_glyph.c | 133 | ||||
-rw-r--r-- | libskrift_get_rendering_settings.c | 8 | ||||
-rw-r--r-- | libskrift_inches_to_pixels.c | 4 | ||||
-rw-r--r-- | libskrift_merge_glyphs.c | 62 | ||||
-rw-r--r-- | libskrift_millimeters_to_pixels.c | 4 | ||||
-rw-r--r-- | libskrift_open_font.c | 50 | ||||
-rw-r--r-- | libskrift_open_font_fd.c | 59 | ||||
-rw-r--r-- | libskrift_open_font_file.c | 18 | ||||
-rw-r--r-- | libskrift_open_font_mem.c | 18 | ||||
-rw-r--r-- | libskrift_points_to_pixels.c | 4 |
22 files changed, 921 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28edc93 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +\#*\# +*~ +*.o +*.a +*.so +*.su +*.lo +/demo @@ -0,0 +1,15 @@ +ISC License + +© 2020 Mattias Andrée <maandree@kth.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..84c04d5 --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OBJ =\ + libskrift_calculate_dpi.o\ + libskrift_close_font.o\ + libskrift_create_context.o\ + libskrift_free_context.o\ + libskrift_get_grapheme_glyph.o\ + libskrift_get_cluster_glyph.o\ + libskrift_get_rendering_settings.o\ + libskrift_inches_to_pixels.o\ + libskrift_merge_glyphs.o\ + libskrift_millimeters_to_pixels.o\ + libskrift_open_font.o\ + libskrift_open_font_fd.o\ + libskrift_open_font_file.o\ + libskrift_open_font_mem.o\ + libskrift_points_to_pixels.o + +LIB_HDR =\ + libskrift.h + +HDR =\ + common.h\ + $(LIB_HDR) + +all: libskrift.a demo +$(OBJ): $(@:.o=.c) $(HDR) +demo.o: demo.c $(LIB_HDR) + +libskrift.a: $(OBJ) + $(AR) rc $@ $(OBJ) + $(AR) ts $@ > /dev/null + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +demo: demo.o libskrift.a + $(CC) -o $@ $@.o libskrift.a $(LDFLAGS) + +install: libskrift.a + mkdir -p -- "$(DESTDIR)$(PREFIX)/lib" + mkdir -p -- "$(DESTDIR)$(PREFIX)/include" + cp -- libskrift.a "$(DESTDIR)$(PREFIX)/lib" + cp -- libskrift.h "$(DESTDIR)$(PREFIX)/include" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libskrift.a" + -rm -f -- "$(DESTDIR)$(PREFIX)/include/libskrift.h" + +clean: + -rm -f -- *.o *.lo *.su libskrift.a libskrift.so libskrift.so.* + +.SUFFIXES: +.SUFFIXES: .c .o + +.PHONY: all install uninstall clean diff --git a/common.h b/common.h new file mode 100644 index 0000000..fdc17f5 --- /dev/null +++ b/common.h @@ -0,0 +1,32 @@ +#include "libskrift.h" + +#include <sys/mman.h> +#include <sys/stat.h> +#include <errno.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <schrift.h> +#include <grapheme.h> + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define MAX(A, B) ((A) > (B) ? (A) : (B)) + +struct libskrift_context { + LIBSKRIFT_FONT *font; + struct libskrift_rendering rendering; + struct SFT schrift_ctx; + char subpixel_horizontally; + char subpixel_vertically; + char subpixel_bgr; +}; + +struct libskrift_font { + SFT_Font *font; + void *memory_free; + void *memory_unmap; + size_t memory_size; + size_t refcount; +}; diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..de63532 --- /dev/null +++ b/config.mk @@ -0,0 +1,10 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +DEMO_FONT = /usr/share/fonts/liberation/LiberationSans-Regular.ttf + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE '-DDEMO_FONT="$(DEMO_FONT)"' +CFLAGS = -std=c99 -Wall -g +LDFLAGS = -lschrift -lm -lgrapheme + +CC = cc @@ -0,0 +1,73 @@ +/* See LICENSE file for copyright and license details. */ +#include "libskrift.h" + +#include <stdlib.h> +#include <string.h> + +#include <grapheme.h> + +int +main(void) +{ + LIBSKRIFT_FONT *font; + LIBSKRIFT_CONTEXT *ctx; + struct libskrift_glyph *glyph; + struct libskrift_rendering rendering = LIBSKRIFT_DEFAULT_RENDERING; + uint16_t i, x, y; + double height; + + rendering.smoothing = LIBSKRIFT_SUBPIXEL; + rendering.subpixel_order = LIBSKRIFT_RGB; + rendering.flags = 0; + + if (libskrift_open_font_file(&font, DEMO_FONT)) { + perror("libskrift_open_font_file"); + return -1; + } + height = libskrift_points_to_pixels(72, &rendering); + if (libskrift_create_context(&ctx, font, &rendering, height)) { + perror("libskrift_create_context"); + return -1; + } + libskrift_close_font(font); + +#if 1 + if (libskrift_get_cluster_glyph(ctx, "x̴̑", NULL, 0, 0, &glyph) < 0) { + perror("libskrift_get_cluster_glyph"); + return -1; + } +#else + if (libskrift_get_grapheme_glyph(ctx, 197 /* Å */, 0, 0, &glyph)) { + perror("libskrift_get_grapheme_glyph"); + return -1; + } +#endif + + if (rendering.smoothing == LIBSKRIFT_GREYSCALE) { + printf("P2\n%u %u\n255\n", glyph->width, glyph->height); + printf("# x-position: %i\n", glyph->x); + printf("# y-position: %i\n", glyph->y); + printf("# advance: %lf\n", glyph->advance); + for (i = y = 0; y < glyph->height; y++) { + for (x = 0; x < glyph->width; x++, i++) + printf("%3u ", glyph->image[i]); + printf("\n\n"); + } + fflush(stdout); + } else { + printf("P3\n%u %u\n255\n", glyph->width, glyph->height); + printf("# x-position: %i\n", glyph->x); + printf("# y-position: %i\n", glyph->y); + printf("# advance: %lf\n", glyph->advance); + for (i = y = 0; y < glyph->height; y++) { + for (x = 0; x < glyph->width * 3; x++, i++) + printf("%3u ", glyph->image[i]); + printf("\n\n"); + } + fflush(stdout); + } + + free(glyph); + libskrift_free_context(ctx); + return 0; +} diff --git a/libskrift.h b/libskrift.h new file mode 100644 index 0000000..5c2e937 --- /dev/null +++ b/libskrift.h @@ -0,0 +1,183 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBSKRIFT_H +#define LIBSKRIFT_H 1 + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#if defined(__GNUC__) +# define _LIBSKRIFT_GCC_ONLY(...) __VA_ARGS__ +#else +# define _LIBSKRIFT_GCC_ONLY(...) +#endif + + +#define LIBSKRIFT_RENDERING_STRUCT_VERSION 0 + +#define LIBSKRIFT_NONE 0 + +typedef struct libskrift_context LIBSKRIFT_CONTEXT; +typedef struct libskrift_font LIBSKRIFT_FONT; +typedef uint_least32_t libskrift_codepoint_t; + + +enum libskrift_subpixel_order { + LIBSKRIFT_OTHER, /* LIBSKRIFT_NONE */ + LIBSKRIFT_RGB, + LIBSKRIFT_BGR, + LIBSKRIFT_VRGB, + LIBSKRIFT_VBGR +}; + +enum libskrift_smoothing { + LIBSKRIFT_MONOCHROME, /* LIBSKRIFT_NONE */ + LIBSKRIFT_GREYSCALE, + LIBSKRIFT_SUBPIXEL +}; + +enum libskrift_hinting { + LIBSKRIFT_UNHINTED = 0, /* LIBSKRIFT_NONE */ + LIBSKRIFT_SLIGHT = 25, + LIBSKRIFT_MEDIUM = 50, + LIBSKRIFT_FULL = 100 +}; + +enum libskrift_rendering_flags { + LIBSKRIFT_CORRECT_GAMMA = 0x0001, + LIBSKRIFT_REMOVE_GAMMA = 0x0002, + LIBSKRIFT_Y_INCREASES_UPWARDS = 0x0004, /* SFT_DOWNWARD_Y otherwise */ + LIBSKRIFT_FLIP_TEXT = 0x0008, + LIBSKRIFT_MIRROR_TEXT = 0x0010, + LIBSKRIFT_MIRROR_CHARS = 0x0020, + LIBSKRIFT_TRANSPOSE_TEXT = 0x0040, + LIBSKRIFT_TRANSPOSE_CHARS = 0x0080, + LIBSKRIFT_NO_LIGATURES = 0x0100, + LIBSKRIFT_ADVANCE_TO_GRID = 0x0200, + LIBSKRIFT_REGRESS_TO_GRID = 0x0400, /* Combine with LIBSKRIFT_ADVANCE_TO_GRID for closest alternative */ + LIBSKRIFT_USE_SUBPIXEL_GRID = 0x0800 +}; + +struct libskrift_rendering { + int struct_version; + enum libskrift_subpixel_order subpixel_order; + enum libskrift_smoothing smoothing; + enum libskrift_hinting hinting; + enum libskrift_rendering_flags flags; + double horizontal_dpi; + double vertical_dpi; + double kerning; + double interletter_spacing; + double prestroke_transformation_rotation[4]; + double left_transformation[6]; + double right_transformation[6]; + double top_transformation[6]; + double bottom_transformation[6]; + double poststroke_transformation_rotation[4]; + double char_transformation[6]; + double text_transformation[6]; +}; + +struct libskrift_glyph { + double advance; + int16_t x; + int16_t y; + uint16_t width; + uint16_t height; + size_t size; + uint8_t image[]; +}; + +struct libskrift_saved_grapheme { + libskrift_codepoint_t cp; + size_t len; +}; + + +#define LIBSKRIFT_DEFAULT_RENDERING {\ + .struct_version = LIBSKRIFT_RENDERING_STRUCT_VERSION,\ + .subpixel_order = LIBSKRIFT_NONE,\ + .smoothing = LIBSKRIFT_GREYSCALE,\ + .hinting = LIBSKRIFT_FULL,\ + .flags = 0,\ + .horizontal_dpi = (double)1920 * 254 / 5180,\ + .vertical_dpi = (double)1200 * 254 / 3240,\ + .kerning = 1,\ + .interletter_spacing = 0,\ + .prestroke_transformation_rotation = {1, 0, 0, 1},\ + .left_transformation = {1, 0, 0, 0, 1, 0},\ + .right_transformation = {1, 0, 0, 0, 1, 0},\ + .top_transformation = {1, 0, 0, 0, 1, 0},\ + .bottom_transformation = {1, 0, 0, 0, 1, 0},\ + .poststroke_transformation_rotation = {1, 0, 0, 1},\ + .char_transformation = {1, 0, 0, 0, 1, 0},\ + .text_transformation = {1, 0, 0, 0, 1, 0},\ +} + +#define LIBSKRIFT_NO_SAVED_GRAPHEME {0, 0} + + +_LIBSKRIFT_GCC_ONLY(__attribute__((__const__, __warn_unused_result__))) +inline double +libskrift_calculate_dpi(double pixels, double millimeters) +{ + return pixels * 254 / 10 / millimeters; +} + +_LIBSKRIFT_GCC_ONLY(__attribute__((__const__, __warn_unused_result__))) +inline double +libskrift_inches_to_pixels(double inches, const struct libskrift_rendering *rendering) +{ + return inches * rendering->vertical_dpi; +} + +_LIBSKRIFT_GCC_ONLY(__attribute__((__const__, __warn_unused_result__))) +inline double +libskrift_millimeters_to_pixels(double millimeters, const struct libskrift_rendering *rendering) +{ + return millimeters * 10 / 254 * rendering->vertical_dpi; +} + +_LIBSKRIFT_GCC_ONLY(__attribute__((__const__, __warn_unused_result__))) +inline double +libskrift_points_to_pixels(double points, const struct libskrift_rendering *rendering) +{ + return points / 72 * rendering->vertical_dpi; +} + + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +int libskrift_open_font_file(LIBSKRIFT_FONT **, const char *); + +_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_fd(LIBSKRIFT_FONT **, int); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +int libskrift_open_font(LIBSKRIFT_FONT **, FILE *); + +void libskrift_close_font(LIBSKRIFT_FONT *); + + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__(1, 2)))) +int libskrift_create_context(LIBSKRIFT_CONTEXT **, LIBSKRIFT_FONT *, const struct libskrift_rendering *, double); + +void libskrift_free_context(LIBSKRIFT_CONTEXT *); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__, __warn_unused_result__, __const__))) +const struct libskrift_rendering *libskrift_get_rendering_settings(LIBSKRIFT_CONTEXT *); + + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +int libskrift_get_grapheme_glyph(LIBSKRIFT_CONTEXT *, libskrift_codepoint_t, double, double, struct libskrift_glyph **); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__(1, 2, 6)))) +ssize_t libskrift_get_cluster_glyph(LIBSKRIFT_CONTEXT *, const char *, struct libskrift_saved_grapheme *, + double, double, struct libskrift_glyph **); + +_LIBSKRIFT_GCC_ONLY(__attribute__((__nonnull__))) +int libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *, struct libskrift_glyph *, struct libskrift_glyph *, struct libskrift_glyph **); + +#endif diff --git a/libskrift_calculate_dpi.c b/libskrift_calculate_dpi.c new file mode 100644 index 0000000..fb70855 --- /dev/null +++ b/libskrift_calculate_dpi.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline double libskrift_calculate_dpi(double pixels, double millimeters); diff --git a/libskrift_close_font.c b/libskrift_close_font.c new file mode 100644 index 0000000..2786666 --- /dev/null +++ b/libskrift_close_font.c @@ -0,0 +1,14 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +void +libskrift_close_font(LIBSKRIFT_FONT *font) +{ + if (font && !--font->refcount) { + sft_freefont(font->font); + free(font->memory_free); + if (font->memory_unmap) + munmap(font->memory_unmap, font->memory_size); + free(font); + } +} diff --git a/libskrift_create_context.c b/libskrift_create_context.c new file mode 100644 index 0000000..16c215e --- /dev/null +++ b/libskrift_create_context.c @@ -0,0 +1,82 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +#define IMPLEMENTED_FLAGS (LIBSKRIFT_CORRECT_GAMMA |\ + LIBSKRIFT_REMOVE_GAMMA) /* libschrift does not add gamma, so not handling is required */ + +#define HAVE_MULTIPLE_FLAGS(HAVE, CHECK) (((HAVE) & (CHECK)) & (((HAVE) & (CHECK)) - 1)) + +#define COPY_ARRAY(DEST_STRUCT, SRC_STRUCT, FIELD)\ + memcpy((DEST_STRUCT).FIELD, (SRC_STRUCT).FIELD, sizeof((SRC_STRUCT).FIELD)) + +static const struct libskrift_rendering default_rendering = LIBSKRIFT_DEFAULT_RENDERING; + +int +libskrift_create_context(LIBSKRIFT_CONTEXT **ctxp, LIBSKRIFT_FONT *font, const struct libskrift_rendering *rendering, double height) +{ + if (rendering) { + if (HAVE_MULTIPLE_FLAGS(rendering->flags, LIBSKRIFT_CORRECT_GAMMA | LIBSKRIFT_REMOVE_GAMMA)) { + errno = EINVAL; + return -1; + } + } + + *ctxp = calloc(1, sizeof(**ctxp)); + if (!*ctxp) + return -1; + + (*ctxp)->font = font; + (*ctxp)->schrift_ctx.font = font->font; + (*ctxp)->schrift_ctx.yScale = height; + + if (rendering) { + memcpy(&(*ctxp)->rendering, rendering, sizeof(*rendering)); + + COPY_ARRAY((*ctxp)->rendering, default_rendering, prestroke_transformation_rotation); + COPY_ARRAY((*ctxp)->rendering, default_rendering, left_transformation); + COPY_ARRAY((*ctxp)->rendering, default_rendering, right_transformation); + COPY_ARRAY((*ctxp)->rendering, default_rendering, top_transformation); + COPY_ARRAY((*ctxp)->rendering, default_rendering, bottom_transformation); + COPY_ARRAY((*ctxp)->rendering, default_rendering, poststroke_transformation_rotation); + COPY_ARRAY((*ctxp)->rendering, default_rendering, char_transformation); + COPY_ARRAY((*ctxp)->rendering, default_rendering, text_transformation); + } else { + memcpy(&(*ctxp)->rendering, &default_rendering, sizeof(default_rendering)); + } + + (*ctxp)->rendering.struct_version = LIBSKRIFT_RENDERING_STRUCT_VERSION; + (*ctxp)->rendering.hinting = LIBSKRIFT_NONE; + (*ctxp)->rendering.flags &= IMPLEMENTED_FLAGS; + (*ctxp)->rendering.kerning = 0; + (*ctxp)->rendering.interletter_spacing = 0; + + if (!(*ctxp)->rendering.smoothing) + (*ctxp)->rendering.smoothing = LIBSKRIFT_GREYSCALE; + + (*ctxp)->schrift_ctx.xScale = (*ctxp)->schrift_ctx.yScale; + (*ctxp)->schrift_ctx.xScale *= (*ctxp)->rendering.horizontal_dpi / (*ctxp)->rendering.vertical_dpi; + + if ((*ctxp)->rendering.smoothing == LIBSKRIFT_SUBPIXEL) { + if ((*ctxp)->rendering.subpixel_order == LIBSKRIFT_RGB) { + (*ctxp)->schrift_ctx.xScale *= 3; + (*ctxp)->subpixel_horizontally = 1; + } else if ((*ctxp)->rendering.subpixel_order == LIBSKRIFT_BGR) { + (*ctxp)->schrift_ctx.xScale *= 3; + (*ctxp)->subpixel_horizontally = 1; + (*ctxp)->subpixel_bgr = 1; + } else if ((*ctxp)->rendering.subpixel_order == LIBSKRIFT_VRGB) { + (*ctxp)->schrift_ctx.yScale *= 3; + (*ctxp)->subpixel_vertically = 1; + } else if ((*ctxp)->rendering.subpixel_order == LIBSKRIFT_VBGR) { + (*ctxp)->schrift_ctx.yScale *= 3; + (*ctxp)->subpixel_vertically = 1; + (*ctxp)->subpixel_bgr = 1; + } else { + (*ctxp)->rendering.subpixel_order = LIBSKRIFT_NONE; + (*ctxp)->rendering.smoothing = LIBSKRIFT_GREYSCALE; + } + } + + font->refcount += 1; + return 0; +} diff --git a/libskrift_free_context.c b/libskrift_free_context.c new file mode 100644 index 0000000..2375c05 --- /dev/null +++ b/libskrift_free_context.c @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +void +libskrift_free_context(LIBSKRIFT_CONTEXT *ctx) +{ + if (ctx) { + libskrift_close_font(ctx->font); + free(ctx); + } +} diff --git a/libskrift_get_cluster_glyph.c b/libskrift_get_cluster_glyph.c new file mode 100644 index 0000000..e8d5724 --- /dev/null +++ b/libskrift_get_cluster_glyph.c @@ -0,0 +1,69 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +/* TODO try normalisation if not found, then try fallback fonts */ + +ssize_t +libskrift_get_cluster_glyph(LIBSKRIFT_CONTEXT *ctx, const char *text, struct libskrift_saved_grapheme *saved, + double x, double y, struct libskrift_glyph **glyphp) +{ + struct libskrift_glyph *glyph0, *glyph1, *glyph2; + uint32_t cp0, cp1; + int state = 0; + size_t r, len; + + *glyphp = NULL; + + if (saved && saved->cp) { + cp0 = saved->cp; + len = saved->len; + } else { + len = grapheme_decode(text, &cp0); + if (!len) { + errno = EINVAL; + return -1; + } + } + + if (libskrift_get_grapheme_glyph(ctx, cp0, x, y, &glyph0)) + return -1; + + x += glyph0->advance; + for (; cp0; cp0 = cp1, len += r) { + r = grapheme_decode(&text[len], &cp1); + if (!r) { + if (saved) { + saved->cp = 0; + saved->len = 0; + } + break; + } + if (grapheme_boundary(cp0, cp1, &state)) { + if (saved) { + saved->cp = cp1; + saved->len = r; + } + break; + } + + if (libskrift_get_grapheme_glyph(ctx, cp1, x, y, &glyph1)) { + free(glyph0); + return -1; + } + x += glyph1->advance; + + if (libskrift_merge_glyphs(ctx, glyph0, glyph1, &glyph2)) { + free(glyph0); + free(glyph1); + return -1; + } + + free(glyph0); + free(glyph1); + glyph0 = glyph2; + } + + *glyphp = glyph0; + + return (ssize_t)len; +} diff --git a/libskrift_get_grapheme_glyph.c b/libskrift_get_grapheme_glyph.c new file mode 100644 index 0000000..cdaee2d --- /dev/null +++ b/libskrift_get_grapheme_glyph.c @@ -0,0 +1,133 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +static const uint8_t gamma_map[] = { + 0, 13, 22, 28, 34, 38, 42, 46, 50, 53, 56, 59, 61, 64, 66, 69, + 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 93, 95, 96, 98, + 99, 101, 102, 104, 105, 106, 108, 109, 110, 112, 113, 114, 115, 117, 118, 119, + 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, + 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, + 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 175, 176, + 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184, 185, 185, 186, 187, 187, + 188, 189, 189, 190, 190, 191, 192, 192, 193, 194, 194, 195, 196, 196, 197, 197, + 198, 199, 199, 200, 200, 201, 202, 202, 203, 203, 204, 205, 205, 206, 206, 207, + 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, + 216, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, + 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, + 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, + 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, + 248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255 +}; + +int +libskrift_get_grapheme_glyph(LIBSKRIFT_CONTEXT *ctx, libskrift_codepoint_t codepoint, + double cursor_x, double cursor_y, struct libskrift_glyph **glyphp) +{ + struct SFT_Char sft_chr; + size_t size = 1, width0, width1, width2, width3, osize, off, r, c, i; + int top = 0, left = 0, right = 0, bottom = 0; + uint16_t width, height, vmul = 1, hmul = 1; + uint8_t *image, *in_image, t; + + memset(&sft_chr, 0, sizeof(sft_chr)); + + ctx->schrift_ctx.x = cursor_x * (ctx->subpixel_horizontally ? 3 : 1); + ctx->schrift_ctx.y = cursor_y * (ctx->subpixel_vertically ? 3 : 1); + ctx->schrift_ctx.flags = SFT_DOWNWARD_Y | SFT_CHAR_IMAGE; + + if (sft_char(&ctx->schrift_ctx, codepoint, &sft_chr)) + return -1; + + if (ctx->subpixel_horizontally) { + hmul = 3; + size = 3; + left = (3 + sft_chr.x % 3) % 3; + right = (3 - (sft_chr.width + left) % 3) % 3; + } else if (ctx->subpixel_vertically) { + vmul = 3; + size = 3; + top = (3 + sft_chr.y % 3) % 3; + bottom = (3 - (sft_chr.height + top) % 3) % 3; + } + + width = (uint16_t)(sft_chr.width + left + right) / hmul; + height = (uint16_t)(sft_chr.height + top + bottom) / vmul; + size *= (size_t)width * (size_t)height; + + *glyphp = malloc(offsetof(struct libskrift_glyph, image) + size); + if (!*glyphp) { + free(sft_chr.image); + return -1; + } + + (*glyphp)->advance = sft_chr.advance / hmul; + (*glyphp)->x = (int16_t)((sft_chr.x - left) / (int16_t)hmul); + (*glyphp)->y = (int16_t)((sft_chr.y - top) / (int16_t)vmul); + (*glyphp)->width = width; + (*glyphp)->height = height; + (*glyphp)->size = size; + + image = (*glyphp)->image; + in_image = sft_chr.image; + if (ctx->subpixel_horizontally && width) { + width3 = (size_t)width * 3; + for (r = 0; r < height; r++) { + image[0] = image[width3 - 3] = 0; + image[1] = image[width3 - 2] = 0; + image[2] = image[width3 - 1] = 0; + memcpy(&image[left], in_image, (size_t)sft_chr.width); + image += width3; + in_image += sft_chr.width; + } + if (ctx->subpixel_bgr) { + image = (*glyphp)->image; + for (i = 0; i < size; i += 3) { + t = image[i + 0]; + image[i + 0] = image[i + 2]; + image[i + 2] = t; + } + } + } else if (ctx->subpixel_vertically && height) { + width0 = (size_t)width * (ctx->subpixel_bgr ? 2 : 0); + width1 = (size_t)width * 1; + width2 = (size_t)width * (ctx->subpixel_bgr ? 0 : 2); + width3 = (size_t)width * 3; + in_image = realloc(in_image, size); + if (!in_image) { + free(sft_chr.image); + free(*glyphp); + *glyphp = NULL; + return -1; + } + sft_chr.image = in_image; + osize = (size_t)sft_chr.width * (size_t)sft_chr.height; + off = (size_t)top; + if (off) { + off *= width; + memmove(&in_image[off], in_image, osize); + memset(in_image, 0, off); + osize += off; + } + memset(&in_image[osize], 0, size - osize); + for (i = r = 0; r < height; r++) { + for (c = 0; c < width; c++, i += 3) { + image[i + 0] = in_image[c + width0]; + image[i + 1] = in_image[c + width1]; + image[i + 2] = in_image[c + width2]; + } + in_image += width3; + } + } else { + memcpy(image, in_image, size); + } + + if (ctx->rendering.flags & LIBSKRIFT_CORRECT_GAMMA) { + image = (*glyphp)->image; + for (i = 0; i < size; i++) + image[i] = gamma_map[image[i]]; + } + + free(sft_chr.image); + return 0; +} diff --git a/libskrift_get_rendering_settings.c b/libskrift_get_rendering_settings.c new file mode 100644 index 0000000..4ad7f81 --- /dev/null +++ b/libskrift_get_rendering_settings.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +const struct libskrift_rendering * +libskrift_get_rendering_settings(LIBSKRIFT_CONTEXT *ctx) +{ + return &ctx->rendering; +} diff --git a/libskrift_inches_to_pixels.c b/libskrift_inches_to_pixels.c new file mode 100644 index 0000000..3901175 --- /dev/null +++ b/libskrift_inches_to_pixels.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline double libskrift_points_to_pixels(double points, const struct libskrift_rendering *rendering); diff --git a/libskrift_merge_glyphs.c b/libskrift_merge_glyphs.c new file mode 100644 index 0000000..548e8fb --- /dev/null +++ b/libskrift_merge_glyphs.c @@ -0,0 +1,62 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +/* TODO How common are grapheme clusters with more than two glyphs? Should we need a variadic version? */ + +int +libskrift_merge_glyphs(LIBSKRIFT_CONTEXT *ctx, struct libskrift_glyph *glyph1, + struct libskrift_glyph *glyph2, struct libskrift_glyph **glyphp) +{ + int16_t x1a, x1b, x2a, x2b, y1a, y1b, y2a, y2b, x1, x2, y1, y2; + size_t width, height, r, c, size = 1, psize = 1; + size_t src_off, dest_off, src_linesize, dest_linesize; + + if (ctx->rendering.smoothing == LIBSKRIFT_SUBPIXEL) + size = psize = 3; + + x1a = glyph1->x; + x1b = glyph2->x; + y1a = glyph1->y; + y1b = glyph2->y; + + x2a = (int16_t)(x1a + (int16_t)glyph1->width); + x2b = (int16_t)(x1b + (int16_t)glyph2->width); + y2a = (int16_t)(y1a + (int16_t)glyph1->height); + y2b = (int16_t)(y1b + (int16_t)glyph2->height); + + x1 = MIN(x1a, x1b); + y1 = MIN(y1a, y1b); + x2 = MAX(x2a, x2b); + y2 = MAX(y2a, y2b); + + size *= width = (uint16_t)(x2 - x1); + size *= height = (uint16_t)(y2 - y1); + + *glyphp = calloc(1, offsetof(struct libskrift_glyph, image) + size); + if (!*glyphp) + return -1; + + (*glyphp)->advance = glyph1->advance + glyph2->advance; + (*glyphp)->x = x1; + (*glyphp)->y = y1; + (*glyphp)->width = (uint16_t)width; + (*glyphp)->height = (uint16_t)height; + (*glyphp)->size = size; + + dest_linesize = width * psize; + + src_linesize = glyph1->width * psize; + dest_off = (size_t)(glyph1->y - y1) * dest_linesize; + dest_off += (size_t)(glyph1->x - x1) * psize; + for (r = src_off = 0; r < glyph1->height; r++, dest_off += dest_linesize, src_off += src_linesize) + memcpy(&(*glyphp)->image[dest_off], &glyph1->image[src_off], src_linesize); + + src_linesize = glyph2->width * psize; + dest_off = (size_t)(glyph2->y - y1) * dest_linesize; + dest_off += (size_t)(glyph2->x - x1) * psize; + for (r = src_off = 0; r < glyph2->height; r++, dest_off += dest_linesize, src_off += src_linesize) + for (c = 0; c < src_linesize; c++) + (*glyphp)->image[dest_off + c] = MAX((*glyphp)->image[dest_off + c], glyph2->image[src_off + c]); + + return 0; +} diff --git a/libskrift_millimeters_to_pixels.c b/libskrift_millimeters_to_pixels.c new file mode 100644 index 0000000..531a775 --- /dev/null +++ b/libskrift_millimeters_to_pixels.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline double libskrift_inches_to_pixels(double inches, const struct libskrift_rendering *rendering); diff --git a/libskrift_open_font.c b/libskrift_open_font.c new file mode 100644 index 0000000..1eb8ff9 --- /dev/null +++ b/libskrift_open_font.c @@ -0,0 +1,50 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libskrift_open_font(LIBSKRIFT_FONT **fontp, FILE *fp) +{ + int saved_errno; + char *mem = NULL, *new; + size_t size = 0, off = 0, r; + + *fontp = calloc(1, sizeof(**fontp)); + + saved_errno = errno; + errno = 0; + for (;;) { + if (off + 2048 > size) { + size += 8192; + new = realloc(mem, size); + if (!new) { + free(mem); + return -1; + } + mem = new; + } + r = fread(&mem[off], 1, size - off, fp); + if (!r) + break; + off += r; + } + if (errno) { + free(mem); + return -1; + } + + size = off; + new = realloc(mem, size); + if (new) + mem = new; + errno = saved_errno; + + if (libskrift_open_font_mem(fontp, mem, size)) { + free(mem); + return -1; + } + + (*fontp)->memory_free = mem; + (*fontp)->memory_size = size; + + return 0; +} diff --git a/libskrift_open_font_fd.c b/libskrift_open_font_fd.c new file mode 100644 index 0000000..c00422e --- /dev/null +++ b/libskrift_open_font_fd.c @@ -0,0 +1,59 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libskrift_open_font_fd(LIBSKRIFT_FONT **fontp, int fd) +{ + int saved_errno; + struct stat st; + char *mem = NULL, *new; + size_t size = 0, off = 0; + int mmapped = 0; + ssize_t r; + + saved_errno = errno; + if (fstat(fd, &st) < 0 || !st.st_size || !S_ISREG(st.st_mode)) { + for (;;) { + if (off + 2048 > size) { + size += 8192; + new = realloc(mem, size); + if (!new) { + free(mem); + return -1; + } + mem = new; + } + r = read(fd, &mem[off], size - off); + if (r <= 0) { + if (!r) + break; + free(mem); + return -1; + } + off += (size_t)r; + } + size = off; + new = realloc(mem, size); + if (new) + mem = new; + errno = saved_errno; + } else { + mem = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + size = (size_t)st.st_size; + mmapped = 1; + } + + if (libskrift_open_font_mem(fontp, mem, size)) { + if (mmapped) + munmap(mem, size); + else + free(mem); + 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 new file mode 100644 index 0000000..2a122ef --- /dev/null +++ b/libskrift_open_font_file.c @@ -0,0 +1,18 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +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; + return -1; + } + return 0; +} diff --git a/libskrift_open_font_mem.c b/libskrift_open_font_mem.c new file mode 100644 index 0000000..3828546 --- /dev/null +++ b/libskrift_open_font_mem.c @@ -0,0 +1,18 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +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; +} diff --git a/libskrift_points_to_pixels.c b/libskrift_points_to_pixels.c new file mode 100644 index 0000000..3901175 --- /dev/null +++ b/libskrift_points_to_pixels.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline double libskrift_points_to_pixels(double points, const struct libskrift_rendering *rendering); |