diff options
Diffstat (limited to 'libskrift_apply_glyph.c')
-rw-r--r-- | libskrift_apply_glyph.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/libskrift_apply_glyph.c b/libskrift_apply_glyph.c new file mode 100644 index 0000000..05770ce --- /dev/null +++ b/libskrift_apply_glyph.c @@ -0,0 +1,219 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +static const float uint8_rmap[] = { + 0/255.f, 1/255.f, 2/255.f, 3/255.f, 4/255.f, 5/255.f, 6/255.f, 7/255.f, + 8/255.f, 9/255.f, 10/255.f, 11/255.f, 12/255.f, 13/255.f, 14/255.f, 15/255.f, + 16/255.f, 17/255.f, 18/255.f, 19/255.f, 20/255.f, 21/255.f, 22/255.f, 23/255.f, + 24/255.f, 25/255.f, 26/255.f, 27/255.f, 28/255.f, 29/255.f, 30/255.f, 31/255.f, + 32/255.f, 33/255.f, 34/255.f, 35/255.f, 36/255.f, 37/255.f, 38/255.f, 39/255.f, + 40/255.f, 41/255.f, 42/255.f, 43/255.f, 44/255.f, 45/255.f, 46/255.f, 47/255.f, + 48/255.f, 49/255.f, 50/255.f, 51/255.f, 52/255.f, 53/255.f, 54/255.f, 55/255.f, + 56/255.f, 57/255.f, 58/255.f, 59/255.f, 60/255.f, 61/255.f, 62/255.f, 63/255.f, + 64/255.f, 65/255.f, 66/255.f, 67/255.f, 68/255.f, 69/255.f, 70/255.f, 71/255.f, + 72/255.f, 73/255.f, 74/255.f, 75/255.f, 76/255.f, 77/255.f, 78/255.f, 79/255.f, + 80/255.f, 81/255.f, 82/255.f, 83/255.f, 84/255.f, 85/255.f, 86/255.f, 87/255.f, + 88/255.f, 89/255.f, 90/255.f, 91/255.f, 92/255.f, 93/255.f, 94/255.f, 95/255.f, + 96/255.f, 97/255.f, 98/255.f, 99/255.f, 100/255.f, 101/255.f, 102/255.f, 103/255.f, + 104/255.f, 105/255.f, 106/255.f, 107/255.f, 108/255.f, 109/255.f, 110/255.f, 111/255.f, + 112/255.f, 113/255.f, 114/255.f, 115/255.f, 116/255.f, 117/255.f, 118/255.f, 119/255.f, + 120/255.f, 121/255.f, 122/255.f, 123/255.f, 124/255.f, 125/255.f, 126/255.f, 127/255.f, + 128/255.f, 129/255.f, 130/255.f, 131/255.f, 132/255.f, 133/255.f, 134/255.f, 135/255.f, + 136/255.f, 137/255.f, 138/255.f, 139/255.f, 140/255.f, 141/255.f, 142/255.f, 143/255.f, + 144/255.f, 145/255.f, 146/255.f, 147/255.f, 148/255.f, 149/255.f, 150/255.f, 151/255.f, + 152/255.f, 153/255.f, 154/255.f, 155/255.f, 156/255.f, 157/255.f, 158/255.f, 159/255.f, + 160/255.f, 161/255.f, 162/255.f, 163/255.f, 164/255.f, 165/255.f, 166/255.f, 167/255.f, + 168/255.f, 169/255.f, 170/255.f, 171/255.f, 172/255.f, 173/255.f, 174/255.f, 175/255.f, + 176/255.f, 177/255.f, 178/255.f, 179/255.f, 180/255.f, 181/255.f, 182/255.f, 183/255.f, + 184/255.f, 185/255.f, 186/255.f, 187/255.f, 188/255.f, 189/255.f, 190/255.f, 191/255.f, + 192/255.f, 193/255.f, 194/255.f, 195/255.f, 196/255.f, 197/255.f, 198/255.f, 199/255.f, + 200/255.f, 201/255.f, 202/255.f, 203/255.f, 204/255.f, 205/255.f, 206/255.f, 207/255.f, + 208/255.f, 209/255.f, 210/255.f, 211/255.f, 212/255.f, 213/255.f, 214/255.f, 215/255.f, + 216/255.f, 217/255.f, 218/255.f, 219/255.f, 220/255.f, 221/255.f, 222/255.f, 223/255.f, + 224/255.f, 225/255.f, 226/255.f, 227/255.f, 228/255.f, 229/255.f, 230/255.f, 231/255.f, + 232/255.f, 233/255.f, 234/255.f, 235/255.f, 236/255.f, 237/255.f, 238/255.f, 239/255.f, + 240/255.f, 241/255.f, 242/255.f, 243/255.f, 244/255.f, 245/255.f, 246/255.f, 247/255.f, + 248/255.f, 249/255.f, 250/255.f, 251/255.f, 252/255.f, 253/255.f, 254/255.f, 255/255.f +}; + +int +libskrift_apply_glyph(LIBSKRIFT_CONTEXT *ctx, const struct libskrift_glyph *glyph, const struct libskrift_colour *colour, + int16_t x, int16_t y, struct libskrift_image *image) +{ + struct format_settings settings; + size_t psize, startr, startc, endr, endc, r, c, n, j; + size_t img_linesize, gly_linesize, i, gly_psize, usize; + size_t ri, gi, bi, rj, gj, bj; + uint16_t x1, y1, x2, y2; + int16_t sx2, sy2; + uint8_t high; + uint8_t *img, *img_start = image->image; + const uint8_t *gly = glyph->image; + const uint16_t u16 = 0x0102; + 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)) { + errno = EINVAL; + return -1; + } + + settings = libskrift_format_settings[image->format]; + psize = settings.spsize * (size_t)(4 - (settings.apos <= -2)); + + if ((unsigned int)image->endian > LIBSKRIFT_REVERSE_NETWORK_SUBPIXEL || + (settings.float_type && (unsigned int)image->endian < LIBSKRIFT_HOST_SUBPIXEL) || + (!colour && settings.float_type) || + (image->endian % 3 && psize != 1 && psize != 2 && psize != 4 && psize != 8)) { + errno = EINVAL; + return -1; + } + + /* Drawing area on image */ + sx2 = (int16_t)(x + (int16_t)glyph->width); + sy2 = (int16_t)(y + (int16_t)glyph->height); + x1 = x < 0 ? 0 : (uint16_t)x; + y1 = y < 0 ? 0 : (uint16_t)y; + if (sx2 <= 0 || sy2 <= 0 || x1 >= image->width || y1 >= image->height) + return 0; + x2 = (uint16_t)sx2 < image->width ? (uint16_t)sx2 : image->width; + y2 = (uint16_t)sy2 < image->height ? (uint16_t)sy2 : image->height; + sx2 = (int16_t)x2; + sy2 = (int16_t)y2; + + /* Drawing area on glyph */ + startc = x <= 0 ? 0 : (size_t)-x; + startr = y <= 0 ? 0 : (size_t)-y; + endc = x2 < image->width ? glyph->width : (uint16_t)(sx2 - x); + endr = y2 < image->height ? glyph->height : (uint16_t)(sy2 - y); + + img_linesize = (size_t)image->width * psize; + img_start += (size_t)y1 * img_linesize; + img_start += (size_t)x1 * psize; + + gly_psize = ctx->rendering.smoothing ? 3 : 1; + gly_linesize = (size_t)image->width * gly_psize; + gly += startr * gly_linesize; + + usize = image->endian >= LIBSKRIFT_HOST_SUBPIXEL ? settings.spsize : psize; + +#define CHECK_ENDIAN(UPPER, LOWER, BITS)\ + ((image->endian == LIBSKRIFT_##UPPER##_PIXEL || image->endian == LIBSKRIFT_##UPPER##_SUBPIXEL) &&\ + usize == sizeof(uint##BITS##_t) &&\ + LOWER##BITS##toh(u##BITS) != u##BITS) + +#define EACH_UNIT\ + img = img_start, r = startr; r < endr; r++, img += img_linesize)\ + for (n = (endc - startc) * psize, i = 0; i < n; i += usize + + /* Convert endian in image to host endian */ + if (CHECK_ENDIAN(BE, be, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = be16toh(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = be32toh(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = be64toh(*(uint64_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = le16toh(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = le32toh(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = le64toh(*(uint64_t *)&img[i]); + + /* Preprocess (e.g. remove gamma or colour model conversion) */ + if (image->preprocess) + image->preprocess(image, (size_t)x1, (size_t)y1, (size_t)(x2 - x1), (size_t)(y2 - y1)); + + /* Apply glyph */ + if (ctx->rendering.smoothing != LIBSKRIFT_SUBPIXEL) + ri = 0, gi = 0, bi = 0; + else if (ctx->subpixel_bgr) + bi = 0, gi = 1, ri = 2; + else + ri = 0, gi = 1, bi = 2; + startc *= gly_psize; + endc *= gly_psize; + if (colour) { + switch (settings.float_type) { + case 0: + switch (settings.spsize) { + case 1: +#define TYPE uint8_t +#define NARROW_FLOAT_TYPE float +#define RMAP(Y) uint8_rmap[Y] +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE +#undef RMAP +#undef TYPE + break; + case 2: +#define TYPE uint16_t +#include "apply-glyph.h" +#undef TYPE + break; + case 4: +#define TYPE uint32_t +#include "apply-glyph.h" +#undef TYPE + break; + default: +#define TYPE uint64_t +#define WIDE_FLOAT_TYPE long double +#include "apply-glyph.h" +#undef TYPE +#undef WIDE_FLOAT_TYPE + break; + } + break; + case 1: +#define NARROW_FLOAT_TYPE float +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE + break; + case 2: +#define NARROW_FLOAT_TYPE double +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE + break; + default: +#define NARROW_FLOAT_TYPE long double +#include "apply-glyph.h" +#undef NARROW_FLOAT_TYPE + break; + } + } else { + /* Optimised version for opaque black-on-white/white-on-black, assumes no glyph overlap */ + rj = (size_t)settings.rpos * settings.spsize; + gj = (size_t)settings.gpos * settings.spsize; + bj = (size_t)settings.bpos * settings.spsize; + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + img[i + rj] ^= gly[c + ri]; + img[i + gj] ^= gly[c + gi]; + img[i + bj] ^= gly[c + bi]; + } + } + for (j = 1; j < settings.spsize; j++) { + ri = rj + j; + gi = gj + j; + bi = bj + j; + for (img = img_start, r = startr; r < endr; r++, img += img_linesize, gly += gly_linesize) { + for (c = startc, i = 0; c < endc; c += gly_psize, i += psize) { + img[i + ri] = img[i + rj]; + img[i + gi] = img[i + gj]; + img[i + bi] = img[i + bj]; + } + } + } + } + startc /= gly_psize; + endc /= gly_psize; + + /* Postprocess (e.g. add gamma or colour model conversion) */ + if (image->postprocess) + image->postprocess(image, (size_t)x1, (size_t)y1, (size_t)(x2 - x1), (size_t)(y2 - y1)); + + /* Convert endian in image from host endian */ + if (CHECK_ENDIAN(BE, be, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = htobe16(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = htobe32(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(BE, be, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = htobe64(*(uint64_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 16)) for (EACH_UNIT) *(uint16_t *)&img[i] = htole16(*(uint16_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 32)) for (EACH_UNIT) *(uint32_t *)&img[i] = htole32(*(uint32_t *)&img[i]); + else if (CHECK_ENDIAN(LE, le, 64)) for (EACH_UNIT) *(uint64_t *)&img[i] = htole64(*(uint64_t *)&img[i]); + + return 0; +} |