44typedef unsigned char uint8_t;
45typedef unsigned short int uint16_t;
46typedef unsigned int uint32_t;
52#define SSFN_MAGIC "SSFN"
53#define SSFN_COLLECTION "SFNC"
54#define SSFN_ENDMAGIC "NFSS"
57#define SSFN_FAMILY_SERIF 0
58#define SSFN_FAMILY_SANS 1
59#define SSFN_FAMILY_DECOR 2
60#define SSFN_FAMILY_MONOSPACE 3
61#define SSFN_FAMILY_HAND 4
64#define SSFN_STYLE_REGULAR 0
65#define SSFN_STYLE_BOLD 1
66#define SSFN_STYLE_ITALIC 2
69#define SSFN_FEAT_HASBMAP 1
70#define SSFN_FEAT_HASCMAP \
73#define SSFN_FEAT_HASHINT 4
74#define SSFN_FEAT_KBIGLKP 8
75#define SSFN_FEAT_KBIGCHR 16
76#define SSFN_FEAT_KBIGCRD 32
77#define SSFN_FEAT_HBIGCRD 64
80#define SSFN_CONTOUR_MOVE 0
81#define SSFN_CONTOUR_LINE 1
82#define SSFN_CONTOUR_QUAD 2
83#define SSFN_CONTOUR_CUBIC 3
84#define SSFN_CONTOUR_COLOR 4
87#define SSFN_FRAG_BITMAP 0
88#define SSFN_FRAG_LBITMAP 1
89#define SSFN_FRAG_PIXMAP 2
90#define SSFN_FRAG_HINTING 3
93#define SSFN_VARIANT_DEFAULT 0
94#define SSFN_VARIANT_LOCAL0 0
95#define SSFN_VARIANT_INITIAL \
98#define SSFN_VARIANT_LOCAL1 \
100#define SSFN_VARIANT_MEDIAL 2
101#define SSFN_VARIANT_LOCAL2 2
102#define SSFN_VARIANT_FINAL 3
103#define SSFN_VARIANT_LOCAL3 3
104#define SSFN_VARIANT_LOCAL4 4
105#define SSFN_VARIANT_LOCAL5 5
106#define SSFN_VARIANT_LOCAL6 6
107#define SSFN_NUMVARIANTS 7
126 uint16_t bbox_bottom;
127 uint32_t fragments_offs;
128 uint32_t characters_offs[SSFN_NUMVARIANTS];
130 uint32_t kerning_offs;
134#define SSFN_FAMILY_ANY 0xff
135#define SSFN_FAMILY_BYNAME 0xfe
137#define SSFN_STYLE_UNDERLINE 4
138#define SSFN_STYLE_STHROUGH 8
139#define SSFN_STYLE_NOHINTING 0x40
140#define SSFN_STYLE_ABS_SIZE 0x80
142#define SSFN_FRAG_CONTOUR 255
146#define SSFN_ERR_ALLOC 1
147#define SSFN_ERR_NOFACE 2
148#define SSFN_ERR_INVINP 3
149#define SSFN_ERR_BADFILE 4
150#define SSFN_ERR_BADSTYLE 5
151#define SSFN_ERR_BADSIZE 6
152#define SSFN_ERR_BADMODE 7
153#define SSFN_ERR_NOGLYPH 8
154#define SSFN_ERR_NOVARIANT 9
157#define SSFN_MODE_NONE \
159#define SSFN_MODE_OUTLINE 1
160#define SSFN_MODE_BITMAP 2
161#define SSFN_MODE_ALPHA 3
162#define SSFN_MODE_CMAP 4
165#define SSFN_HINTING_THRESHOLD \
169#define SSFN_DATA_MAX 65536
179 uint8_t data[SSFN_DATA_MAX];
202 int m, ix, u, uix, uax, lx, ly, mx, my;
217int ssfn_kern(
ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode,
int *x,
223#define ssfn_lasterr(ctx) ((ssfn_t *)ctx)->err
224#define ssfn_error(err) \
225 (err >= 0 && err <= 9 ? ssfn_errstr[err] \
230int ssfn_putc(uint32_t unicode);
234#ifndef SSFN_NOIMPLEMENTATION
238#define NULL (void *)0
252#ifdef __builtin_memcmp
253#define SSFN_memcmp __builtin_memcmp
255#define SSFN_memcmp memcmp
260#ifdef __builtin_memset
261#define SSFN_memset __builtin_memset
263#define SSFN_memset memset
268#ifdef __builtin_realloc
269#define SSFN_realloc __builtin_realloc
271#define SSFN_realloc realloc
277#define SSFN_free __builtin_free
279#define SSFN_free free
287 "Memory allocation error",
288 "No font face found",
289 "Invalid input value",
295 "Glyph variant not found"};
300#define _ssfn_i2g(x) ((x) ? (((x) << 16) - (1 << 15)) / ctx->m : 0)
301#define _ssfn_g2o(x) (((x) * ctx->m + (1 << 7)) >> 8)
302#define _ssfn_g2i(x) (((x) * ctx->m + (1 << 15)) >> 16)
303#define _ssfn_g2ic(x) (((x) * ctx->m + (1 << 16) - 1) >> 16)
304#define _ssfn_f2i(x) ((((x) << s) * ctx->m + (1 << 15)) >> 16)
305#define _ssfn_o2i(x) (((x) + (1 << 7)) >> 8)
306#define _ssfn_o2ic(x) ((x + (1 << 8) - 1) >> 8)
307#define _ssfn_g2ox(x) ((x) >= (4095 << 4) ? _ssfn_g2o(x) : ctx->h[((x) >> 4)])
308#define _ssfn_g2ix(x) \
309 ((x) >= (4095 << 4) ? _ssfn_g2i(x) : _ssfn_o2i(ctx->h[((x) >> 4)]))
310#define _ssfn_g2ixc(x) \
311 ((x) >= (4095 << 4) ? _ssfn_g2ic(x) : _ssfn_o2ic(ctx->h[((x) >> 4)]))
312#define _ssfn_g2oy(y) (_ssfn_g2o(y))
313#define _ssfn_g2iy(y) (_ssfn_g2i(y))
314#define _ssfn_g2iyc(y) (_ssfn_g2ic(y))
315#define _ssfn_igg(y) (((4096 << 4) - (y)) >> (2))
316#define _ssfn_igi(y) \
317 ((((4096 << 4) - (y)) * ctx->m + (1 << (15 + 3))) >> (16 + 3))
320ssfn_private uint8_t *_ssfn_c(
const ssfn_font_t *font, uint32_t unicode,
325 if (!font->characters_offs[v])
return NULL;
327 ptr = (uint8_t *)font + font->characters_offs[v];
328 l = (font->quality < 5 && font->characters_offs[v] < 65536)
330 : (font->characters_offs[v] < 1048576 ? 5 : 6);
332 for (j = i = 0; i < 0x110000; i++) {
335 i += ptr[1] | ((ptr[0] & 0x3f) << 8);
342 if (i == unicode)
return ptr;
343 ptr += ptr[0] * l + 10;
351ssfn_private
void _ssfn_l(
ssfn_t *ctx,
int x,
int y,
int l) {
352 if (x > (4096 << 4) - 16) x = (4096 << 4) - 16;
353 if (y > (4096 << 4) - 16) y = (4096 << 4) - 16;
354 if (x < -1 || y < -1 || (x == ctx->lx && y == ctx->ly))
return;
356 if (ctx->np + 2 >= ctx->mp) {
358 ctx->p = (uint16_t *)SSFN_realloc(ctx->p, ctx->mp *
sizeof(uint16_t));
360 ctx->err = SSFN_ERR_ALLOC;
364 if (!ctx->np || !l || _ssfn_g2i(ctx->p[ctx->np - 2]) != _ssfn_g2i(x) ||
365 _ssfn_g2i(ctx->p[ctx->np - 1]) != _ssfn_g2i(y)) {
366 ctx->p[ctx->np++] = x;
367 ctx->p[ctx->np++] = y;
371 if ((ctx->style & 0x200) && x >= 0 && ctx->ix > x) ctx->ix = x;
375void _ssfn_b(
ssfn_t *ctx,
int x0,
int y0,
int x1,
int y1,
int x2,
int y2,
376 int x3,
int y3,
int l) {
377 int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y, m5x, m5y;
378 if (l < 8 && (x0 != x3 || y0 != y3)) {
379 m0x = ((x1 - x0) / 2) + x0;
380 m0y = ((y1 - y0) / 2) + y0;
381 m1x = ((x2 - x1) / 2) + x1;
382 m1y = ((y2 - y1) / 2) + y1;
383 m2x = ((x3 - x2) / 2) + x2;
384 m2y = ((y3 - y2) / 2) + y2;
385 m3x = ((m1x - m0x) / 2) + m0x;
386 m3y = ((m1y - m0y) / 2) + m0y;
387 m4x = ((m2x - m1x) / 2) + m1x;
388 m4y = ((m2y - m1y) / 2) + m1y;
389 m5x = ((m4x - m3x) / 2) + m3x;
390 m5y = ((m4y - m3y) / 2) + m3y;
391 _ssfn_b(ctx, x0, y0, m0x, m0y, m3x, m3y, m5x, m5y, l + 1);
392 _ssfn_b(ctx, m5x, m5y, m4x, m4y, m2x, m2y, x3, y3, l + 1);
394 _ssfn_l(ctx, x3, y3, l);
398ssfn_private
void _ssfn_r(
ssfn_t *ctx) {
399 int i, k, l, m, n = 0, x, y, Y, M = 0;
401 uint8_t *pix = ctx->ret->data;
403 for (y = 0; y < ctx->ret->h; y++) {
406 for (n = 0, i = 0; i < ctx->np - 3; i += 2) {
407 if ((ctx->p[i] == 0xffff && ctx->p[i + 1] == 0xffff) ||
408 (ctx->p[i + 2] == 0xffff && ctx->p[i + 3] == 0xffff))
410 if ((ctx->p[i + 1] < Y && ctx->p[i + 3] >= Y) ||
411 (ctx->p[i + 3] < Y && ctx->p[i + 1] >= Y)) {
412 if (_ssfn_g2iy(ctx->p[i + 1]) == _ssfn_g2iy(ctx->p[i + 3]))
413 x = (((int)ctx->p[i] + (
int)ctx->p[i + 2]) >> 1);
415 x = ((int)ctx->p[i]) + ((Y - (int)ctx->p[i + 1]) *
416 ((int)ctx->p[i + 2] - (
int)ctx->p[i]) /
417 ((
int)ctx->p[i + 3] - (int)ctx->p[i + 1]));
426 x = _ssfn_g2ox(x - ctx->ix);
427 for (k = 0; k < n && x > r[k]; k++);
428 if (n >= ctx->nr[y]) {
429 ctx->nr[y] = (n < ctx->np) ? ctx->np : (n + 1) << 1;
430 ctx->r[y] = (uint16_t *)SSFN_realloc(ctx->r[y], (ctx->nr[y] << 1));
432 ctx->err = SSFN_ERR_ALLOC;
437 for (l = n; l > k; l--) r[l] = r[l - 1];
442 if (n > 1 && n & 1) {
449 k = y * ctx->ret->pitch;
450 for (i = 0; i < n - 1; i += 2) {
451 if (ctx->style & 0x100) {
452 l = (r[i] + r[i + 1]) >> 9;
453 if (ctx->mode == SSFN_MODE_BITMAP
454 ? (pix[k + (l >> 3)] & (1 << (l & 7)) ? 1 : 0)
455 : (pix[k + l] == 0xFF)) {
456 if (r[i] + 256 > r[i + 1])
457 r[i] = r[i + 1] - 128;
460 if (r[i + 1] - 256 > r[i]) r[i + 1] -= 256;
462 if (i >= n - 2 || r[i + 1] + 256 < r[i + 2]) r[i + 1] += 256;
465 l = ((r[i] + 128) >> 8);
466 m = ((r[i + 1] + 128) >> 8);
467 if (ctx->mode != SSFN_MODE_BITMAP && l + 1 < m) l++;
470 case SSFN_MODE_BITMAP:
471 pix[k + (l >> 3)] ^= 1 << (l & 7);
473 case SSFN_MODE_ALPHA:
481 if (l + 1 > ctx->ret->w) ctx->ret->w = l + 1;
486 if (M + 1 == ctx->ret->baseline) {
487 ctx->ret->baseline--;
493ssfn_private
void _ssfn_a(
ssfn_t *ctx) {
494 int i, x, y, x0, y0, x1, y1, sx, sy, dx, dy, m, o, p = ctx->ret->pitch;
495 uint8_t *pix = ctx->ret->data, e;
498 if (ctx->mode < SSFN_MODE_ALPHA || !ctx->p || ctx->np < 4)
return;
500 for (y = o = 0; y < ctx->ret->h; y++, o += p) {
501 if (ctx->nr[y] && (r = ctx->r[y])) {
502 for (i = 0; i < ctx->nr[y] - 1; i += 2) {
503 x = (r[i] + 128) >> 8;
504 e = ~((r[i] + 128) & 0xFF);
508 if (x && pix[o + x - 1] > e) e = pix[o + x - 1];
509 if (y && pix[o + x - p] > e) e = pix[o + x - p];
511 if (ctx->mode == SSFN_MODE_CMAP) e = (e >> 4) | 0xF0;
512 if (e > pix[o + x]) pix[o + x] = e;
513 e = ((r[i + 1] + 128) & 0xFF);
514 if (e == 128) e = 255;
515 pix[o + ((r[i + 1] + 128) >> 8)] =
516 ctx->mode == SSFN_MODE_CMAP ? (e >> 4) | 0xF0 : e;
521 for (i = 0; i < ctx->np - 3; i += 2) {
522 if ((ctx->p[i] == 0xffff && ctx->p[i + 1] == 0xffff) ||
523 (ctx->p[i + 2] == 0xffff && ctx->p[i + 3] == 0xffff))
526 x0 = ctx->p[i] - ctx->ix;
528 x1 = ctx->p[i + 2] - ctx->ix;
530 sx = x1 >= x0 ? 1 : -1;
531 sy = y1 >= y0 ? 1 : -1;
534 if (sx * dx >= sy * dy && dx) {
535 for (x = x0, m = sx * dx; m > 0; m -= 16, x += sx * 16) {
536 y = _ssfn_g2oy(y0 + ((x - x0) * dy / dx));
541 o = y * p + ((_ssfn_g2ox(x) + 128) >> 8);
542 if (ctx->mode == SSFN_MODE_CMAP) e = (e >> 4) | 0xF0;
543 if (e > pix[o]) pix[o] = e;
550ssfn_private
void _ssfn_g(
ssfn_t *ctx, uint8_t *rg,
int render) {
551 int i, j, nf, m, n, o, ox, oy, ol, t, x, y, a, b, c, d, w, h, s;
552 uint8_t *raw, *ra, *re, *pix = ctx->ret->data;
554 ctx->lx = ctx->ly = ctx->mx = ctx->my = -1;
555 ol = (ctx->f->quality < 5 && ctx->f->characters_offs[ctx->variant] < 65536)
557 : ((ctx->f->characters_offs[ctx->variant] < 1048576) ? 5 : 6);
562 for (h = 0; nf-- && !ctx->err; rg += ol) {
565 o = ((rg[1] << 8) | rg[0]);
570 o = (((rg[2] & 0xF) << 16) | (rg[1] << 8) | rg[0]);
571 ox = (((rg[2] >> 4) & 3) << 8) | rg[3];
572 oy = (((rg[2] >> 6) & 3) << 8) | rg[4];
575 o = (((rg[3] & 0xF) << 24) | (rg[2] << 16) | (rg[1] << 8) | rg[0]);
576 ox = ((rg[3] & 0xF) << 8) | rg[4];
577 oy = (((rg[3] >> 4) & 0xF) << 8) | rg[5];
582 raw = (uint8_t *)ctx->f + o;
584 t = (raw[0] & 0x60) >> 5;
585 if (!render && t != SSFN_FRAG_HINTING)
break;
587 case SSFN_FRAG_LBITMAP:
588 x = ((((raw[0] >> 2) & 3) << 8) + raw[1]) + 1;
589 y = (((raw[0] & 3) << 8) | raw[2]) + 1;
593 case SSFN_FRAG_BITMAP:
594 x = (raw[0] & 0x1F) + 1;
598 if (ctx->mode == SSFN_MODE_OUTLINE) {
601 ctx->lx = ctx->ly = -1;
604 if (ctx->style & 0x200) {
605 a = (((4096 << 4) - (oy)) >> (3));
606 b = (((4096 << 4) - (oy + y)) >> (3));
607 if (ctx->ix > ox + a) ctx->ix = ox + a;
610 if (ctx->np) _ssfn_l(ctx, -1, -1, 0);
611 _ssfn_l(ctx, ox + a, oy, 0);
612 _ssfn_l(ctx, ox + x + a, oy, 0);
613 _ssfn_l(ctx, ox + x + b, oy + y, 0);
614 _ssfn_l(ctx, ox + b, oy + y, 0);
615 _ssfn_l(ctx, ox + a, oy, 0);
621 w = _ssfn_g2i(x << (3 + s));
623 if (c + h >= ctx->ret->h) c = ctx->ret->h - h;
624 c = t = c * ctx->ret->pitch;
625 for (j = 0; j < h; j++) {
626 o = (((j << 8) * (y << 8) / (h << 8)) >> 8) * x;
627 for (i = 0; i < w; i++) {
628 m = ((i << 8) * (a << 8) / (w << 8)) >> 8;
629 if (raw[o + (m >> 3)] & (1 << (m & 7))) {
631 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
635 case SSFN_MODE_BITMAP:
636 pix[c + (d >> 3)] |= 1 << (d & 7);
638 if ((ctx->style & 0x100) && (d >> 3) < ctx->ret->pitch) {
639 pix[c + (d >> 3)] |= 1 << (d & 7);
641 if (ctx->size > 127 && (d >> 3) < ctx->ret->pitch) {
642 pix[c + (d >> 3)] |= 1 << (d & 7);
647 case SSFN_MODE_ALPHA:
648 pix[c + (d++)] = 0xFF;
649 if ((ctx->style & 0x100) && d < ctx->ret->pitch) {
650 pix[c + (d++)] = 0xFF;
651 if (ctx->size > 127 && d < ctx->ret->pitch) {
657 if (d > ctx->ret->w) ctx->ret->w = d;
658 d = ox + _ssfn_i2g(d);
659 if ((ctx->style & 0x200) && ctx->ix > d) ctx->ix = d;
660 if (_ssfn_g2i(oy) + j == ctx->u) {
670 c += ctx->ret->pitch;
672 if (ctx->mode != SSFN_MODE_BITMAP && h > y && w > 1) {
673 m = (ctx->mode == SSFN_MODE_CMAP) ? 0xF0 : 0;
675 for (a = x; a; a--) {
676 b = ctx->style & 0x100 ? (64 + (128 * a / x)) : (192 * a / x);
677 if (ctx->mode == SSFN_MODE_CMAP) b = (b >> 4) | 0xF0;
678 c = t + ctx->ret->pitch;
679 for (j = 1; j < h - 1; j++) {
680 for (i = 1; i < w - 1; i++) {
682 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s)) : 0) +
684 if (pix[c + d] == m &&
685 (pix[c + d - ctx->ret->pitch] > b ||
686 pix[c + d + ctx->ret->pitch] > b) &&
687 (pix[c + d - 1] > b || pix[c + d + 1] > b))
690 c += ctx->ret->pitch;
698 case SSFN_FRAG_PIXMAP:
699 x = (((raw[0] & 12) << 6) | raw[1]) + 1;
700 y = (((raw[0] & 3) << 8) | raw[2]) + 1;
701 n = ((raw[4] << 8) | raw[3]) + 1;
703 if (ctx->mode == SSFN_MODE_OUTLINE)
goto outline;
704 if (raw[-5] & 0x10) {
708 if (a >= (ctx->nr[0] << 1)) {
709 ctx->nr[0] = (a + 1) >> 1;
710 ctx->r[0] = (uint16_t *)SSFN_realloc(ctx->r[0], (ctx->nr[0] << 1));
712 ctx->err = SSFN_ERR_ALLOC;
716 ctx->ret->cmap = (uint32_t *)((uint8_t *)ctx->f + ctx->f->size - 964);
717 for (re = raw + n, ra = (uint8_t *)ctx->r[0], i = 0;
718 i < a && raw < re;) {
719 c = (raw[0] & 0x7F) + 1;
721 for (j = 0; j < c; j++) ra[i++] = raw[1];
725 for (j = 0; j < c; j++) ra[i++] = *raw++;
731 w = _ssfn_g2i(x << s);
733 if (c + h >= ctx->ret->h) c = ctx->ret->h - h;
734 c = t = c * ctx->ret->pitch;
735 for (j = 0; j < h; j++) {
736 o = (((j << 8) * (y << 8) / (h << 8)) >> 8) * x;
737 for (i = 0; i < w; i++) {
738 m = ((i << 8) * (x << 8) / (w << 8)) >> 8;
739 if (ra[o + m] < 0xF0) {
741 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
744 re = (uint8_t *)&ctx->ret->cmap[ra[o + m]];
745 a = (re[0] + re[1] + re[2] + 255) >> 2;
747 case SSFN_MODE_BITMAP:
748 if (a > 127) pix[c + (d >> 3)] |= 1 << (d & 7);
751 pix[c + d] = ra[o + m];
753 case SSFN_MODE_ALPHA:
759 if (d > ctx->ret->w) ctx->ret->w = d;
762 c += ctx->ret->pitch;
767 case SSFN_FRAG_HINTING:
769 n = ((raw[0] & 0xF) << 8) | raw[1];
776 raw += n << (ctx->f->features & SSFN_FEAT_HBIGCRD ? 1 : 0);
780 x = ((ox >> s) - 1) << (s - 4);
782 for (n++; n-- && x < 4096;) {
785 if (ctx->f->features & SSFN_FEAT_HBIGCRD) {
792 if (y < 4096) ctx->h[y++] = 65535;
797 if (!render && h)
break;
799 n = ((raw[0] & 0x3F) << 8) | raw[1];
805 if (ctx->f->quality < 5) {
810 x = ((raw[0] & 3) << 8) | raw[1];
811 y = ((raw[0] & 0x30) << 4) | raw[2];
817 x += ox + (ctx->style & 0x200 ? _ssfn_igg(y) : 0);
820 _ssfn_l(ctx, ctx->mx, ctx->my, 0);
821 _ssfn_l(ctx, -1, -1, 0);
823 _ssfn_l(ctx, x, y, 0);
825 ctx->lx = ctx->mx = x;
826 ctx->ly = ctx->my = y;
828 t = ctx->g < 8 ? (raw[0] >> 7) | ((raw[1] >> 6) & 2) : raw[0] & 3;
829 x = y = a = b = c = d = j = 0;
839 raw += raw[0] & 4 ? 5 : 2;
864 raw += raw[0] & 4 ? 5 : 2;
885 x = ((raw[0] & 4) << 6) | raw[1];
886 y = ((raw[0] & 8) << 5) | raw[2];
889 raw += raw[0] & 4 ? 5 : 2;
895 a = ((raw[0] & 16) << 4) | raw[3];
896 b = ((raw[0] & 32) << 3) | raw[4];
900 a = ((raw[0] & 16) << 4) | raw[3];
901 b = ((raw[0] & 32) << 3) | raw[4];
902 c = ((raw[0] & 64) << 2) | raw[5];
903 d = ((raw[0] & 128) << 1) | raw[6];
910 x = ((raw[0] & 12) << 6) | raw[1];
911 y = ((raw[0] & 48) << 4) | raw[2];
914 raw += raw[0] & 4 ? 5 : 2;
920 a = ((raw[3] & 3) << 8) | raw[4];
921 b = ((raw[3] & 12) << 6) | raw[5];
925 a = ((raw[3] & 3) << 8) | raw[4];
926 b = ((raw[3] & 12) << 6) | raw[5];
927 c = ((raw[3] & 48) << 4) | raw[6];
928 d = ((raw[3] & 192) << 2) | raw[7];
946 if (ctx->style & 0x200) {
956 _ssfn_l(ctx, x, y, 0);
959 _ssfn_b(ctx, ctx->lx, ctx->ly, ((a - ctx->lx) >> 1) + ctx->lx,
960 ((b - ctx->ly) >> 1) + ctx->ly, ((x - a) >> 1) + a,
961 ((y - b) >> 1) + b, x, y, 0);
964 _ssfn_b(ctx, ctx->lx, ctx->ly, a, b, c, d, x, y, 0);
967 }
else if (t == 1 && x >= 0 && y >= 0) {
968 a = ((ctx->lx < x) ? x - ctx->lx : ctx->lx - x) >> 4;
969 b = ((ctx->ly < y) ? y - ctx->ly : ctx->ly - y) >> 4;
970 c = (ctx->lx + x) >> 5;
972 ctx->h[4096 + (!ctx->h[4096 + c] && c && ctx->h[4096 + c - 1]
983 for (j = m = x = y = 0; j < 4096; j++) {
984 if (ctx->h[4096 + j] >= 4096 / SSFN_HINTING_THRESHOLD) {
988 ctx->h[4096 + m++] = j - x;
993 if (m < 4096) ctx->h[4096 + m] = 65535;
1007#define SSFN_CMAP_TO_ARGB(p, c, fg) \
1008 (p >= 0xF0 ? (uint32_t)((p << 28) | ((p & 0xF) << 24) | fg) : c[p])
1020 if (!ctx || !font) {
1021 if (ctx) ctx->err = SSFN_ERR_INVINP;
1022 return SSFN_ERR_INVINP;
1025 if (!SSFN_memcmp(font->magic, SSFN_COLLECTION, 4)) {
1026 end = (
ssfn_font_t *)((uint8_t *)font + font->size);
1027 for (ptr = (
ssfn_font_t *)((uint8_t *)font + 8); ptr < end && !ctx->err;
1028 ptr = (
ssfn_font_t *)((uint8_t *)ptr + ptr->size))
1031 if (SSFN_memcmp(font->magic, SSFN_MAGIC, 4) ||
1032 SSFN_memcmp((uint8_t *)font + font->size - 4, SSFN_ENDMAGIC, 4) ||
1033 font->family > SSFN_FAMILY_HAND || font->fragments_offs > font->size ||
1034 font->characters_offs[0] > font->size ||
1035 font->kerning_offs > font->size ||
1036 font->fragments_offs >= font->characters_offs[0] || font->quality > 8) {
1037 ctx->err = SSFN_ERR_BADFILE;
1039 ctx->len[font->family]++;
1040 ctx->fnt[font->family] = (
const ssfn_font_t **)SSFN_realloc(
1041 ctx->fnt[font->family], ctx->len[font->family] *
sizeof(
void *));
1042 if (!ctx->fnt[font->family])
1043 ctx->err = SSFN_ERR_ALLOC;
1045 ctx->fnt[font->family][ctx->len[font->family] - 1] = font;
1066 if (!ctx)
return SSFN_ERR_INVINP;
1067 if ((style & ~0xCF))
return (ctx->err = SSFN_ERR_BADSTYLE);
1068 if (size < 8 || size > 255)
return (ctx->err = SSFN_ERR_BADSIZE);
1069 if (mode > SSFN_MODE_CMAP)
return (ctx->err = SSFN_ERR_BADMODE);
1071 if (family == SSFN_FAMILY_BYNAME) {
1072 if (!name || !name[0]) {
1074 return (ctx->err = SSFN_ERR_INVINP);
1076 for (l = 0; name[l]; l++);
1077 for (i = 0; i < 5; i++) {
1078 for (j = 0; j < ctx->len[i]; j++) {
1080 name, (uint8_t *)&ctx->fnt[i][j]->magic +
sizeof(
ssfn_font_t),
1082 ctx->s = ctx->fnt[i][j];
1088 return (ctx->err = SSFN_ERR_NOFACE);
1090 if (family != SSFN_FAMILY_ANY) {
1091 if (family > SSFN_FAMILY_HAND)
goto invinp;
1092 if (!ctx->len[family])
goto noface;
1097 ctx->np = ctx->mp = 0;
1103 ctx->family = family;
1108 return (ctx->err = SSFN_OK);
1119 if (!ctx)
return SSFN_ERR_INVINP;
1120 if (variant < 0 || variant > SSFN_NUMVARIANTS - 1)
1121 return (ctx->err = SSFN_ERR_INVINP);
1122 ctx->variant = variant;
1123 return (ctx->err = SSFN_OK);
1135 int i, j, s, h, p, m, n, bt, bl;
1137 uint8_t *rg = NULL, c, d;
1139 if (!ctx)
return NULL;
1140 if (ctx->size < 8) {
1141 ctx->err = SSFN_ERR_NOFACE;
1147 rg = _ssfn_c(ctx->f, unicode, ctx->variant);
1148 if (!rg) rg = _ssfn_c(ctx->f, unicode, 0);
1153 if (p == SSFN_FAMILY_ANY) {
1158 for (; n <= m; n++) {
1160 if (ctx->style & 3) {
1162 for (i = 0; i < ctx->len[n]; i++)
1163 if ((fl[i]->style & 3) == (ctx->style & 3) &&
1164 (rg = _ssfn_c(fl[i], unicode, k))) {
1170 if (!rg && (ctx->style & 3) == 3)
1171 for (i = 0; i < ctx->len[n]; i++)
1172 if ((fl[i]->style & 3) && (rg = _ssfn_c(fl[i], unicode, k))) {
1180 for (i = 0; i < ctx->len[n]; i++)
1181 if ((rg = _ssfn_c(fl[i], unicode, k))) {
1190 if (p != SSFN_FAMILY_ANY) {
1191 p = SSFN_FAMILY_ANY;
1201 ctx->err = ctx->variant ? SSFN_ERR_NOVARIANT : SSFN_ERR_NOGLYPH;
1206 if ((ctx->style & 1) && !(ctx->f->style & 1)) ctx->style |= 0x100;
1207 if ((ctx->style & 2) && !(ctx->f->style & 2)) ctx->style |= 0x200;
1208 if (ctx->f->family == SSFN_FAMILY_MONOSPACE)
1209 ctx->style |= SSFN_STYLE_ABS_SIZE;
1211 ctx->g = 4 + ctx->f->quality;
1215 if (ctx->mode == SSFN_MODE_OUTLINE) {
1219 if (!(((rg[2] & 0x0F) << 8) | rg[6]) || ctx->style & SSFN_STYLE_ABS_SIZE)
1222 h = (4096 << 4) * ctx->size /
1223 ((ctx->f->baseline - ctx->f->bbox_top) << s);
1224 p = (h + (ctx->style & 0x100 ? 2 : 0) + (ctx->style & 0x200 ? h >> 2 : 0));
1227 if (ctx->style & 0x100) h -= 2;
1228 if (ctx->style & 0x200) h = h * 4 / 5;
1230 if (ctx->mode == SSFN_MODE_BITMAP) p = (p + 7) >> 3;
1235 ctx->h = (uint16_t *)SSFN_realloc(NULL, 4096 * 2 *
sizeof(uint16_t));
1236 if (!ctx->h)
goto erralloc;
1238 if (!(ctx->style & SSFN_STYLE_NOHINTING)) {
1239 SSFN_memset(&ctx->h[4096], 0, 4096 *
sizeof(uint16_t));
1240 _ssfn_g(ctx, rg, 0);
1242 ctx->h[4096] = 65535;
1245 for (i = j = k = x = y = m = 0; i < 4096 && j < 4095; i++) {
1246 y = ctx->h[4096 + i] == 65535 ? 4095 - j : ctx->h[4096 + i];
1249 ctx->h[j] = (((j << 4) * h + (1 << 15)) >> 16) << 8;
1252 y = _ssfn_g2o(y << 4);
1254 if ((i & 1) || y < 256) {
1259 for (l = 0; l + x <= j; l++) ctx->h[x + l] = n + ((m - n) * l / (j - x));
1263 ctx->uix = _ssfn_g2ixc((((rg[2] & 0x0F) << 8) | rg[6]) << s);
1264 ctx->uax = _ssfn_g2iyc((((rg[2] & 0xF0) << 4) | rg[7]) << s);
1265 if (ctx->mode == SSFN_MODE_NONE)
return NULL;
1267 bl = ((((rg[3] & 0x0F) << 8) | rg[8])) << s;
1268 bt = ((((rg[3] & 0xF0) << 4) | rg[9])) << s;
1270 ctx->ret = (
ssfn_glyph_t *)SSFN_realloc(NULL, i + 8 +
sizeof(uint8_t *));
1273 ctx->err = SSFN_ERR_ALLOC;
1276 SSFN_memset(&ctx->ret->data, ctx->mode == SSFN_MODE_CMAP ? 0xF0 : 0, i);
1277 ctx->ret->cmap = NULL;
1278 ctx->ret->mode = ctx->mode;
1279 ctx->ret->pitch = p;
1282 ctx->ret->baseline =
1283 (((ctx->f->baseline << s) - bt) * h + (1 << 16) - 1) >> 16;
1284 ctx->u = ctx->ret->baseline +
1285 ((((ctx->f->underline - ctx->f->baseline) << s) * h) >> 16);
1287 ctx->ret->adv_x = ctx->uix;
1288 ctx->ret->adv_y = ctx->uax;
1290 ctx->ix = ctx->uix = 4096 << 4;
1292 _ssfn_g(ctx, rg, 1);
1295 if (!(ctx->style & 0x200) || ctx->ix == 4096 << 4) ctx->ix = 0;
1296 if (ctx->mode == SSFN_MODE_OUTLINE) {
1297 if (ctx->np > p * h) {
1299 ctx->ret, ctx->np + 8 +
sizeof(uint8_t *));
1300 if (!ctx->ret)
goto erralloc;
1302 for (s = i = 0; i < ctx->np; i += 2) {
1303 c = ctx->p[i + 0] == 0xffff ? 0xff : _ssfn_g2ix(ctx->p[i + 0] + bl);
1304 d = ctx->p[i + 1] == 0xffff ? 0xff : _ssfn_g2iy(ctx->p[i + 1] + bt);
1305 if (s < 2 || ctx->ret->data[s - 2] != c || ctx->ret->data[s - 1] != d) {
1306 ctx->ret->data[s++] = c;
1307 ctx->ret->data[s++] = d;
1310 ctx->ret->pitch = s;
1312 (
ssfn_glyph_t *)SSFN_realloc(ctx->ret, s + 8 +
sizeof(uint8_t *));
1313 if (!ctx->ret)
goto erralloc;
1316 if (ctx->mode != SSFN_MODE_BITMAP) _ssfn_a(ctx);
1317 if (ctx->style & SSFN_STYLE_STHROUGH) {
1318 if (ctx->ret->w < ctx->ret->adv_x) ctx->ret->w = ctx->ret->adv_x;
1320 &ctx->ret->data[(ctx->ret->baseline - (ctx->size >> 2)) * p], 0xFF,
1321 (ctx->size / 64 + 2) * p);
1323 if (ctx->style & SSFN_STYLE_UNDERLINE) {
1324 if (ctx->ret->w < ctx->ret->adv_x) ctx->ret->w = ctx->ret->adv_x;
1325 if (ctx->uax > ctx->ix) ctx->uax = _ssfn_g2i(ctx->uax - ctx->ix);
1326 if (ctx->uix != 4096 << 4)
1327 ctx->uix = _ssfn_g2i(ctx->uix - ctx->ix);
1329 ctx->uix = ctx->ret->w + 3;
1331 n = ctx->size > 127 ? 2 : 1;
1335 if (ctx->mode == SSFN_MODE_BITMAP)
1336 for (i = 0; i < j; i++)
1337 ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1339 SSFN_memset(&ctx->ret->data[m], 0xFF, j);
1343 if (ctx->mode == SSFN_MODE_BITMAP)
1344 for (i = j; i < ctx->ret->w; i++)
1345 ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1347 SSFN_memset(&ctx->ret->data[m + j], 0xFF, p - j);
1353 if (ctx->ret->adv_y) ctx->ret->baseline = ctx->ret->w >> 1;
1354 }
else if (ctx->ret) {
1355 SSFN_free(ctx->ret);
1371int ssfn_kern(
ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode,
int *x,
1374 uint32_t i, j, k, l, a, b, c;
1378 if (!ctx || !x || !y)
return SSFN_ERR_INVINP;
1379 if (!ctx->f && !ctx->s)
return (ctx->err = SSFN_ERR_NOFACE);
1380 font = ctx->s ? ctx->s : ctx->f;
1381 if (unicode && nextunicode && font->kerning_offs) {
1382 ptr = (uint8_t *)font + font->kerning_offs;
1383 a = font->features & SSFN_FEAT_KBIGLKP ? 4 : 3;
1384 b = font->features & SSFN_FEAT_KBIGCHR;
1385 c = font->features & SSFN_FEAT_KBIGCRD;
1386 for (i = 0; i < 0x110000; i++) {
1387 if (ptr[0] & 0x80) {
1388 if (ptr[0] & 0x40) {
1389 i += ptr[1] | ((ptr[0] & 0x3f) << 8);
1397 if (unicode >= i && unicode <= i + m) {
1398 ptr = (uint8_t *)font + font->kerning_offs +
1399 ((a == 4 ? (ptr[3] << 16) : 0) | (ptr[2] << 8) | ptr[1]);
1400 if (ptr[0] & 0x80) {
1401 k = ptr[1] | ((ptr[0] & 0x7f) << 8);
1407 for (m = 0, a = SSFN_ERR_NOGLYPH, i = j = 0;
1408 i <= k && j <= nextunicode; i++) {
1410 j = ptr[0] | (ptr[1] << 8) | ((ptr[2] & 0x7F) << 16);
1414 j = ptr[0] | ((ptr[1] & 0x7F) << 8);
1419 m = (short)(ptr[0] | (ptr[1] << 8));
1422 m = (
signed char)ptr[0];
1425 if (j == nextunicode) {
1427 m = (((m) << (16 - ctx->g)) * ctx->m + (1 << 16) - 1) >> 16;
1434 return (ctx->err = a);
1441 return (ctx->err = SSFN_ERR_NOGLYPH);
1458 if (!ctx)
return SSFN_ERR_INVINP;
1459 if (!str || !w || !h)
return (ctx->err = SSFN_ERR_INVINP);
1462 ctx->mode = SSFN_MODE_NONE;
1466 if (ctx->err == SSFN_OK) {
1471 if (usekern)
ssfn_kern(ctx, u, v, w, h);
1474 if (!*w) *w = ctx->m;
1475 if (!*h) *h = ctx->m;
1487 int i, ret =
sizeof(
ssfn_t);
1491 for (i = 0; i < 5; i++) ret += ctx->len[i] *
sizeof(
ssfn_font_t *);
1492 if (ctx->p) ret += ctx->mp *
sizeof(uint16_t);
1493 for (i = 0; i < 256; i++)
1494 if (ctx->r[i]) ret += ctx->nr[i] *
sizeof(uint16_t);
1495 if (ctx->h) ret += 8192 *
sizeof(uint16_t);
1509 for (i = 0; i < 5; i++)
1510 if (ctx->fnt[i]) SSFN_free(ctx->fnt[i]);
1511 if (ctx->p) SSFN_free(ctx->p);
1512 for (i = 0; i < 256; i++)
1513 if (ctx->r[i]) SSFN_free(ctx->r[i]);
1514 if (ctx->h) SSFN_free(ctx->h);
1515 SSFN_memset(ctx, 0,
sizeof(
ssfn_t));
1521#if !defined(SSFN_NOIMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1522 defined(SSFN_CONSOLEBITMAP_HICOLOR) || \
1523 defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1534 if ((**s & 128) != 0) {
1536 c = ((**s & 0x1F) << 6) | (*(*s + 1) & 0x3F);
1538 }
else if (!(**s & 16)) {
1539 c = ((**s & 0xF) << 12) | ((*(*s + 1) & 0x3F) << 6) | (*(*s + 2) & 0x3F);
1541 }
else if (!(**s & 8)) {
1542 c = ((**s & 0x7) << 18) | ((*(*s + 1) & 0x3F) << 12) |
1543 ((*(*s + 2) & 0x3F) << 6) | (*(*s + 3) & 0x3F);
1553#if defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1554 defined(SSFN_CONSOLEBITMAP_HICOLOR) || \
1555 defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1563uint8_t *ssfn_dst_ptr;
1564uint32_t ssfn_dst_pitch;
1565uint32_t ssfn_dst_w = 0;
1566uint32_t ssfn_dst_h = 0;
1568#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1582int ssfn_putc(uint32_t unicode) {
1583 uint32_t i, j, a, b, m, p, t;
1584 uint8_t *rg, *o, *g, *s, *r, y, n;
1585#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1589 t = (ssfn_font->quality < 5 && ssfn_font->characters_offs[0] < 65536)
1591 : (ssfn_font->characters_offs[0] < 1048576 ? 5 : 6);
1592 rg = (uint8_t *)ssfn_font + ssfn_font->characters_offs[0];
1593 ssfn_adv_x = ssfn_adv_y = 0;
1595 for (j = i = 0; i < 0x110000; i++) {
1599 i += rg[1] | (n << 8);
1608#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1611 if (ssfn_dst_w && (ssfn_x + w >= ssfn_dst_w)) w = ssfn_dst_w - ssfn_x;
1612 s = ssfn_dst_ptr + (ssfn_y)*ssfn_dst_pitch;
1613#ifdef SSFN_CONSOLEBITMAP_PALETTE
1616#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1623 if ((ssfn_dst_w && (ssfn_x > ssfn_dst_w)) ||
1624 (ssfn_dst_h && (ssfn_y + ssfn_font->bbox_bottom >= ssfn_dst_h)))
1625 return SSFN_ERR_INVINP;
1631#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1632 s = ssfn_dst_ptr + (ssfn_y + y + rg[t - 1]) * ssfn_dst_pitch;
1633#ifdef SSFN_CONSOLEBITMAP_PALETTE
1636#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1643 o = (uint8_t *)ssfn_font;
1644 a = ((rg[1] << 8) | rg[0]);
1650 o += ((rg[2] & 0xF) << 16) | a;
1653 o += ((rg[3] & 0xF) << 24) | (rg[2] << 16) | a;
1656 p = ((o[0] & 0xF) + 1);
1660 if (ssfn_dst_w && (ssfn_x + a >= ssfn_dst_w)) a = ssfn_dst_w - ssfn_x;
1661#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1662 for (; j < y + rg[t - 1]; j++, s += ssfn_dst_pitch)
1663 for (r = s, i = 0; i < w; i++) {
1664#ifdef SSFN_CONSOLEBITMAP_PALETTE
1665 *((uint8_t *)r) = (uint8_t)ssfn_bg;
1668#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1669 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1672 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1681 for (; j < b; j++, s += ssfn_dst_pitch, o += p) {
1682 for (g = o, r = s, m = 1, i = 0; i < a; i++, m <<= 1) {
1687#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1690#ifdef SSFN_CONSOLEBITMAP_PALETTE
1691 *((uint8_t *)r) = (uint8_t)(
1692#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1693 *g & m ? ssfn_fg : ssfn_bg
1700#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1701 *((uint16_t *)r) = (uint16_t)(
1702#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1703 *g & m ? ssfn_fg : ssfn_bg
1710 *((uint32_t *)r) = (uint32_t)(
1711#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1712 *g & m ? ssfn_fg : ssfn_bg
1724#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1725 for (; j <= ssfn_font->bbox_bottom; j++, s += ssfn_dst_pitch)
1726 for (r = s, i = 0; i < w; i++) {
1727#ifdef SSFN_CONSOLEBITMAP_PALETTE
1728 *((uint8_t *)r) = (uint8_t)ssfn_bg;
1731#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1732 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1735 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1741 ssfn_x += ssfn_adv_x;
1742 ssfn_y += ssfn_adv_y;
1745 rg += rg[0] * t + 10;
1749 return SSFN_ERR_NOGLYPH;
int ssfn_variant(ssfn_t *ctx, int variant)
Set glyph variant.
int ssfn_mem(ssfn_t *ctx)
Returns how much memory a context consumes.
void ssfn_free(ssfn_t *ctx)
Free renderer context.
const char * ssfn_errstr[]
Error code strings.
int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size, int mode)
Set up rendering parameters.
int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x, int *y)
Return kerning information.
uint32_t ssfn_utf8(char **str)
Decode an UTF-8 multibyte, advance string pointer and return UNICODE.
int ssfn_load(ssfn_t *ctx, const ssfn_font_t *font)
Load a font or font collection into renderer context.
ssfn_glyph_t * ssfn_render(ssfn_t *ctx, uint32_t unicode)
Glyph renderer.
int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w, int *h)
Returns the bounding box of the rendered text.