From 933799d9f0aaf811b37aebf71db2634c4f80e23b Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 26 Apr 2020 11:02:57 +0200 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 8 ++ LICENSE | 15 +++ Makefile | 60 ++++++++++++ common.h | 32 +++++++ config.mk | 10 ++ demo.c | 73 +++++++++++++++ libskrift.h | 183 +++++++++++++++++++++++++++++++++++++ libskrift_calculate_dpi.c | 4 + libskrift_close_font.c | 14 +++ libskrift_create_context.c | 82 +++++++++++++++++ libskrift_free_context.c | 11 +++ libskrift_get_cluster_glyph.c | 69 ++++++++++++++ libskrift_get_grapheme_glyph.c | 133 +++++++++++++++++++++++++++ libskrift_get_rendering_settings.c | 8 ++ libskrift_inches_to_pixels.c | 4 + libskrift_merge_glyphs.c | 62 +++++++++++++ libskrift_millimeters_to_pixels.c | 4 + libskrift_open_font.c | 50 ++++++++++ libskrift_open_font_fd.c | 59 ++++++++++++ libskrift_open_font_file.c | 18 ++++ libskrift_open_font_mem.c | 18 ++++ libskrift_points_to_pixels.c | 4 + 22 files changed, 921 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 common.h create mode 100644 config.mk create mode 100644 demo.c create mode 100644 libskrift.h create mode 100644 libskrift_calculate_dpi.c create mode 100644 libskrift_close_font.c create mode 100644 libskrift_create_context.c create mode 100644 libskrift_free_context.c create mode 100644 libskrift_get_cluster_glyph.c create mode 100644 libskrift_get_grapheme_glyph.c create mode 100644 libskrift_get_rendering_settings.c create mode 100644 libskrift_inches_to_pixels.c create mode 100644 libskrift_merge_glyphs.c create mode 100644 libskrift_millimeters_to_pixels.c create mode 100644 libskrift_open_font.c create mode 100644 libskrift_open_font_fd.c create mode 100644 libskrift_open_font_file.c create mode 100644 libskrift_open_font_mem.c create mode 100644 libskrift_points_to_pixels.c 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 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..38e536c --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +© 2020 Mattias Andrée + +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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 diff --git a/demo.c b/demo.c new file mode 100644 index 0000000..79cf920 --- /dev/null +++ b/demo.c @@ -0,0 +1,73 @@ +/* See LICENSE file for copyright and license details. */ +#include "libskrift.h" + +#include +#include + +#include + +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 +#include +#include + +#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); -- cgit v1.2.3-70-g09d2