39typedef unsigned char uint8_t;
40typedef unsigned short int uint16_t;
41typedef unsigned int uint32_t;
47#define SSFN_MAGIC "SSFN"
48#define SSFN_COLLECTION "SFNC"
49#define SSFN_ENDMAGIC "NFSS"
52#define SSFN_FAMILY_SERIF 0
53#define SSFN_FAMILY_SANS 1
54#define SSFN_FAMILY_DECOR 2
55#define SSFN_FAMILY_MONOSPACE 3
56#define SSFN_FAMILY_HAND 4
59#define SSFN_STYLE_REGULAR 0
60#define SSFN_STYLE_BOLD 1
61#define SSFN_STYLE_ITALIC 2
64#define SSFN_FEAT_HASBMAP 1
65#define SSFN_FEAT_HASCMAP \
68#define SSFN_FEAT_HASHINT 4
69#define SSFN_FEAT_KBIGLKP 8
70#define SSFN_FEAT_KBIGCHR 16
71#define SSFN_FEAT_KBIGCRD 32
72#define SSFN_FEAT_HBIGCRD 64
75#define SSFN_CONTOUR_MOVE 0
76#define SSFN_CONTOUR_LINE 1
77#define SSFN_CONTOUR_QUAD 2
78#define SSFN_CONTOUR_CUBIC 3
79#define SSFN_CONTOUR_COLOR 4
82#define SSFN_FRAG_BITMAP 0
83#define SSFN_FRAG_LBITMAP 1
84#define SSFN_FRAG_PIXMAP 2
85#define SSFN_FRAG_HINTING 3
88#define SSFN_VARIANT_DEFAULT 0
89#define SSFN_VARIANT_LOCAL0 0
90#define SSFN_VARIANT_INITIAL \
93#define SSFN_VARIANT_LOCAL1 \
95#define SSFN_VARIANT_MEDIAL 2
96#define SSFN_VARIANT_LOCAL2 2
97#define SSFN_VARIANT_FINAL 3
98#define SSFN_VARIANT_LOCAL3 3
99#define SSFN_VARIANT_LOCAL4 4
100#define SSFN_VARIANT_LOCAL5 5
101#define SSFN_VARIANT_LOCAL6 6
102#define SSFN_NUMVARIANTS 7
121 uint16_t bbox_bottom;
122 uint32_t fragments_offs;
123 uint32_t characters_offs[SSFN_NUMVARIANTS];
125 uint32_t kerning_offs;
129#define SSFN_FAMILY_ANY 0xff
130#define SSFN_FAMILY_BYNAME 0xfe
132#define SSFN_STYLE_UNDERLINE 4
133#define SSFN_STYLE_STHROUGH 8
134#define SSFN_STYLE_NOHINTING 0x40
135#define SSFN_STYLE_ABS_SIZE 0x80
137#define SSFN_FRAG_CONTOUR 255
141#define SSFN_ERR_ALLOC 1
142#define SSFN_ERR_NOFACE 2
143#define SSFN_ERR_INVINP 3
144#define SSFN_ERR_BADFILE 4
145#define SSFN_ERR_BADSTYLE 5
146#define SSFN_ERR_BADSIZE 6
147#define SSFN_ERR_BADMODE 7
148#define SSFN_ERR_NOGLYPH 8
149#define SSFN_ERR_NOVARIANT 9
152#define SSFN_MODE_NONE \
154#define SSFN_MODE_OUTLINE 1
155#define SSFN_MODE_BITMAP 2
156#define SSFN_MODE_ALPHA 3
157#define SSFN_MODE_CMAP 4
160#define SSFN_HINTING_THRESHOLD \
164#define SSFN_DATA_MAX 65536
174 uint8_t data[SSFN_DATA_MAX];
197 int m, ix, u, uix, uax, lx, ly, mx, my;
205int ssfn_select(
ssfn_t *ctx,
int family,
char *name,
int style,
int size,
207int ssfn_variant(
ssfn_t *ctx,
209uint32_t ssfn_utf8(
char **str);
212int ssfn_kern(
ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode,
int *x,
214int ssfn_bbox(
ssfn_t *ctx,
char *str,
int usekern,
int *w,
217void ssfn_free(
ssfn_t *ctx);
218#define ssfn_lasterr(ctx) ((ssfn_t *)ctx)->err
219#define ssfn_error(err) \
220 (err >= 0 && err <= 9 ? ssfn_errstr[err] \
222extern const char *ssfn_errstr[];
225int ssfn_putc(uint32_t unicode);
229#ifndef SSFN_NOIMPLEMENTATION
233#define NULL (void *)0
247#ifdef __builtin_memcmp
248#define SSFN_memcmp __builtin_memcmp
250#define SSFN_memcmp memcmp
255#ifdef __builtin_memset
256#define SSFN_memset __builtin_memset
258#define SSFN_memset memset
263#ifdef __builtin_realloc
264#define SSFN_realloc __builtin_realloc
266#define SSFN_realloc realloc
272#define SSFN_free __builtin_free
274#define SSFN_free free
281const char *ssfn_errstr[] = {
"",
282 "Memory allocation error",
283 "No font face found",
284 "Invalid input value",
290 "Glyph variant not found"};
295#define _ssfn_i2g(x) ((x) ? (((x) << 16) - (1 << 15)) / ctx->m : 0)
296#define _ssfn_g2o(x) (((x) * ctx->m + (1 << 7)) >> 8)
297#define _ssfn_g2i(x) (((x) * ctx->m + (1 << 15)) >> 16)
298#define _ssfn_g2ic(x) (((x) * ctx->m + (1 << 16) - 1) >> 16)
299#define _ssfn_f2i(x) ((((x) << s) * ctx->m + (1 << 15)) >> 16)
300#define _ssfn_o2i(x) (((x) + (1 << 7)) >> 8)
301#define _ssfn_o2ic(x) ((x + (1 << 8) - 1) >> 8)
302#define _ssfn_g2ox(x) ((x) >= (4095 << 4) ? _ssfn_g2o(x) : ctx->h[((x) >> 4)])
303#define _ssfn_g2ix(x) \
304 ((x) >= (4095 << 4) ? _ssfn_g2i(x) : _ssfn_o2i(ctx->h[((x) >> 4)]))
305#define _ssfn_g2ixc(x) \
306 ((x) >= (4095 << 4) ? _ssfn_g2ic(x) : _ssfn_o2ic(ctx->h[((x) >> 4)]))
307#define _ssfn_g2oy(y) (_ssfn_g2o(y))
308#define _ssfn_g2iy(y) (_ssfn_g2i(y))
309#define _ssfn_g2iyc(y) (_ssfn_g2ic(y))
310#define _ssfn_igg(y) (((4096 << 4) - (y)) >> (2))
311#define _ssfn_igi(y) \
312 ((((4096 << 4) - (y)) * ctx->m + (1 << (15 + 3))) >> (16 + 3))
315ssfn_private uint8_t *_ssfn_c(
const ssfn_font_t *font, uint32_t unicode,
320 if (!font->characters_offs[v])
return NULL;
322 ptr = (uint8_t *)font + font->characters_offs[v];
323 l = (font->quality < 5 && font->characters_offs[v] < 65536)
325 : (font->characters_offs[v] < 1048576 ? 5 : 6);
327 for (j = i = 0; i < 0x110000; i++) {
330 i += ptr[1] | ((ptr[0] & 0x3f) << 8);
337 if (i == unicode)
return ptr;
338 ptr += ptr[0] * l + 10;
346ssfn_private
void _ssfn_l(
ssfn_t *ctx,
int x,
int y,
int l) {
347 if (x > (4096 << 4) - 16) x = (4096 << 4) - 16;
348 if (y > (4096 << 4) - 16) y = (4096 << 4) - 16;
349 if (x < -1 || y < -1 || (x == ctx->lx && y == ctx->ly))
return;
351 if (ctx->np + 2 >= ctx->mp) {
353 ctx->p = (uint16_t *)SSFN_realloc(ctx->p, ctx->mp *
sizeof(uint16_t));
355 ctx->err = SSFN_ERR_ALLOC;
359 if (!ctx->np || !l || _ssfn_g2i(ctx->p[ctx->np - 2]) != _ssfn_g2i(x) ||
360 _ssfn_g2i(ctx->p[ctx->np - 1]) != _ssfn_g2i(y)) {
361 ctx->p[ctx->np++] = x;
362 ctx->p[ctx->np++] = y;
366 if ((ctx->style & 0x200) && x >= 0 && ctx->ix > x) ctx->ix = x;
370void _ssfn_b(
ssfn_t *ctx,
int x0,
int y0,
int x1,
int y1,
int x2,
int y2,
371 int x3,
int y3,
int l) {
372 int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y, m5x, m5y;
373 if (l < 8 && (x0 != x3 || y0 != y3)) {
374 m0x = ((x1 - x0) / 2) + x0;
375 m0y = ((y1 - y0) / 2) + y0;
376 m1x = ((x2 - x1) / 2) + x1;
377 m1y = ((y2 - y1) / 2) + y1;
378 m2x = ((x3 - x2) / 2) + x2;
379 m2y = ((y3 - y2) / 2) + y2;
380 m3x = ((m1x - m0x) / 2) + m0x;
381 m3y = ((m1y - m0y) / 2) + m0y;
382 m4x = ((m2x - m1x) / 2) + m1x;
383 m4y = ((m2y - m1y) / 2) + m1y;
384 m5x = ((m4x - m3x) / 2) + m3x;
385 m5y = ((m4y - m3y) / 2) + m3y;
386 _ssfn_b(ctx, x0, y0, m0x, m0y, m3x, m3y, m5x, m5y, l + 1);
387 _ssfn_b(ctx, m5x, m5y, m4x, m4y, m2x, m2y, x3, y3, l + 1);
389 _ssfn_l(ctx, x3, y3, l);
393ssfn_private
void _ssfn_r(
ssfn_t *ctx) {
394 int i, k, l, m, n = 0, x, y, Y, M = 0;
396 uint8_t *pix = ctx->ret->data;
398 for (y = 0; y < ctx->ret->h; y++) {
401 for (n = 0, i = 0; i < ctx->np - 3; i += 2) {
402 if ((ctx->p[i] == 0xffff && ctx->p[i + 1] == 0xffff) ||
403 (ctx->p[i + 2] == 0xffff && ctx->p[i + 3] == 0xffff))
405 if ((ctx->p[i + 1] < Y && ctx->p[i + 3] >= Y) ||
406 (ctx->p[i + 3] < Y && ctx->p[i + 1] >= Y)) {
407 if (_ssfn_g2iy(ctx->p[i + 1]) == _ssfn_g2iy(ctx->p[i + 3]))
408 x = (((int)ctx->p[i] + (
int)ctx->p[i + 2]) >> 1);
410 x = ((int)ctx->p[i]) + ((Y - (int)ctx->p[i + 1]) *
411 ((int)ctx->p[i + 2] - (
int)ctx->p[i]) /
412 ((
int)ctx->p[i + 3] - (int)ctx->p[i + 1]));
421 x = _ssfn_g2ox(x - ctx->ix);
422 for (k = 0; k < n && x > r[k]; k++);
423 if (n >= ctx->nr[y]) {
424 ctx->nr[y] = (n < ctx->np) ? ctx->np : (n + 1) << 1;
425 ctx->r[y] = (uint16_t *)SSFN_realloc(ctx->r[y], (ctx->nr[y] << 1));
427 ctx->err = SSFN_ERR_ALLOC;
432 for (l = n; l > k; l--) r[l] = r[l - 1];
437 if (n > 1 && n & 1) {
444 k = y * ctx->ret->pitch;
445 for (i = 0; i < n - 1; i += 2) {
446 if (ctx->style & 0x100) {
447 l = (r[i] + r[i + 1]) >> 9;
448 if (ctx->mode == SSFN_MODE_BITMAP
449 ? (pix[k + (l >> 3)] & (1 << (l & 7)) ? 1 : 0)
450 : (pix[k + l] == 0xFF)) {
451 if (r[i] + 256 > r[i + 1])
452 r[i] = r[i + 1] - 128;
455 if (r[i + 1] - 256 > r[i]) r[i + 1] -= 256;
457 if (i >= n - 2 || r[i + 1] + 256 < r[i + 2]) r[i + 1] += 256;
460 l = ((r[i] + 128) >> 8);
461 m = ((r[i + 1] + 128) >> 8);
462 if (ctx->mode != SSFN_MODE_BITMAP && l + 1 < m) l++;
465 case SSFN_MODE_BITMAP:
466 pix[k + (l >> 3)] ^= 1 << (l & 7);
468 case SSFN_MODE_ALPHA:
476 if (l + 1 > ctx->ret->w) ctx->ret->w = l + 1;
481 if (M + 1 == ctx->ret->baseline) {
482 ctx->ret->baseline--;
488ssfn_private
void _ssfn_a(
ssfn_t *ctx) {
489 int i, x, y, x0, y0, x1, y1, sx, sy, dx, dy, m, o, p = ctx->ret->pitch;
490 uint8_t *pix = ctx->ret->data, e;
493 if (ctx->mode < SSFN_MODE_ALPHA || !ctx->p || ctx->np < 4)
return;
495 for (y = o = 0; y < ctx->ret->h; y++, o += p) {
496 if (ctx->nr[y] && (r = ctx->r[y])) {
497 for (i = 0; i < ctx->nr[y] - 1; i += 2) {
498 x = (r[i] + 128) >> 8;
499 e = ~((r[i] + 128) & 0xFF);
503 if (x && pix[o + x - 1] > e) e = pix[o + x - 1];
504 if (y && pix[o + x - p] > e) e = pix[o + x - p];
506 if (ctx->mode == SSFN_MODE_CMAP) e = (e >> 4) | 0xF0;
507 if (e > pix[o + x]) pix[o + x] = e;
508 e = ((r[i + 1] + 128) & 0xFF);
509 if (e == 128) e = 255;
510 pix[o + ((r[i + 1] + 128) >> 8)] =
511 ctx->mode == SSFN_MODE_CMAP ? (e >> 4) | 0xF0 : e;
516 for (i = 0; i < ctx->np - 3; i += 2) {
517 if ((ctx->p[i] == 0xffff && ctx->p[i + 1] == 0xffff) ||
518 (ctx->p[i + 2] == 0xffff && ctx->p[i + 3] == 0xffff))
521 x0 = ctx->p[i] - ctx->ix;
523 x1 = ctx->p[i + 2] - ctx->ix;
525 sx = x1 >= x0 ? 1 : -1;
526 sy = y1 >= y0 ? 1 : -1;
529 if (sx * dx >= sy * dy && dx) {
530 for (x = x0, m = sx * dx; m > 0; m -= 16, x += sx * 16) {
531 y = _ssfn_g2oy(y0 + ((x - x0) * dy / dx));
536 o = y * p + ((_ssfn_g2ox(x) + 128) >> 8);
537 if (ctx->mode == SSFN_MODE_CMAP) e = (e >> 4) | 0xF0;
538 if (e > pix[o]) pix[o] = e;
545ssfn_private
void _ssfn_g(
ssfn_t *ctx, uint8_t *rg,
int render) {
546 int i, j, nf, m, n, o, ox, oy, ol, t, x, y, a, b, c, d, w, h, s;
547 uint8_t *raw, *ra, *re, *pix = ctx->ret->data;
549 ctx->lx = ctx->ly = ctx->mx = ctx->my = -1;
550 ol = (ctx->f->quality < 5 && ctx->f->characters_offs[ctx->variant] < 65536)
552 : ((ctx->f->characters_offs[ctx->variant] < 1048576) ? 5 : 6);
557 for (h = 0; nf-- && !ctx->err; rg += ol) {
560 o = ((rg[1] << 8) | rg[0]);
565 o = (((rg[2] & 0xF) << 16) | (rg[1] << 8) | rg[0]);
566 ox = (((rg[2] >> 4) & 3) << 8) | rg[3];
567 oy = (((rg[2] >> 6) & 3) << 8) | rg[4];
570 o = (((rg[3] & 0xF) << 24) | (rg[2] << 16) | (rg[1] << 8) | rg[0]);
571 ox = ((rg[3] & 0xF) << 8) | rg[4];
572 oy = (((rg[3] >> 4) & 0xF) << 8) | rg[5];
577 raw = (uint8_t *)ctx->f + o;
579 t = (raw[0] & 0x60) >> 5;
580 if (!render && t != SSFN_FRAG_HINTING)
break;
582 case SSFN_FRAG_LBITMAP:
583 x = ((((raw[0] >> 2) & 3) << 8) + raw[1]) + 1;
584 y = (((raw[0] & 3) << 8) | raw[2]) + 1;
588 case SSFN_FRAG_BITMAP:
589 x = (raw[0] & 0x1F) + 1;
593 if (ctx->mode == SSFN_MODE_OUTLINE) {
596 ctx->lx = ctx->ly = -1;
599 if (ctx->style & 0x200) {
600 a = (((4096 << 4) - (oy)) >> (3));
601 b = (((4096 << 4) - (oy + y)) >> (3));
602 if (ctx->ix > ox + a) ctx->ix = ox + a;
605 if (ctx->np) _ssfn_l(ctx, -1, -1, 0);
606 _ssfn_l(ctx, ox + a, oy, 0);
607 _ssfn_l(ctx, ox + x + a, oy, 0);
608 _ssfn_l(ctx, ox + x + b, oy + y, 0);
609 _ssfn_l(ctx, ox + b, oy + y, 0);
610 _ssfn_l(ctx, ox + a, oy, 0);
616 w = _ssfn_g2i(x << (3 + s));
618 if (c + h >= ctx->ret->h) c = ctx->ret->h - h;
619 c = t = c * ctx->ret->pitch;
620 for (j = 0; j < h; j++) {
621 o = (((j << 8) * (y << 8) / (h << 8)) >> 8) * x;
622 for (i = 0; i < w; i++) {
623 m = ((i << 8) * (a << 8) / (w << 8)) >> 8;
624 if (raw[o + (m >> 3)] & (1 << (m & 7))) {
626 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
630 case SSFN_MODE_BITMAP:
631 pix[c + (d >> 3)] |= 1 << (d & 7);
633 if ((ctx->style & 0x100) && (d >> 3) < ctx->ret->pitch) {
634 pix[c + (d >> 3)] |= 1 << (d & 7);
636 if (ctx->size > 127 && (d >> 3) < ctx->ret->pitch) {
637 pix[c + (d >> 3)] |= 1 << (d & 7);
642 case SSFN_MODE_ALPHA:
643 pix[c + (d++)] = 0xFF;
644 if ((ctx->style & 0x100) && d < ctx->ret->pitch) {
645 pix[c + (d++)] = 0xFF;
646 if (ctx->size > 127 && d < ctx->ret->pitch) {
652 if (d > ctx->ret->w) ctx->ret->w = d;
653 d = ox + _ssfn_i2g(d);
654 if ((ctx->style & 0x200) && ctx->ix > d) ctx->ix = d;
655 if (_ssfn_g2i(oy) + j == ctx->u) {
665 c += ctx->ret->pitch;
667 if (ctx->mode != SSFN_MODE_BITMAP && h > y && w > 1) {
668 m = (ctx->mode == SSFN_MODE_CMAP) ? 0xF0 : 0;
670 for (a = x; a; a--) {
671 b = ctx->style & 0x100 ? (64 + (128 * a / x)) : (192 * a / x);
672 if (ctx->mode == SSFN_MODE_CMAP) b = (b >> 4) | 0xF0;
673 c = t + ctx->ret->pitch;
674 for (j = 1; j < h - 1; j++) {
675 for (i = 1; i < w - 1; i++) {
677 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s)) : 0) +
679 if (pix[c + d] == m &&
680 (pix[c + d - ctx->ret->pitch] > b ||
681 pix[c + d + ctx->ret->pitch] > b) &&
682 (pix[c + d - 1] > b || pix[c + d + 1] > b))
685 c += ctx->ret->pitch;
693 case SSFN_FRAG_PIXMAP:
694 x = (((raw[0] & 12) << 6) | raw[1]) + 1;
695 y = (((raw[0] & 3) << 8) | raw[2]) + 1;
696 n = ((raw[4] << 8) | raw[3]) + 1;
698 if (ctx->mode == SSFN_MODE_OUTLINE)
goto outline;
699 if (raw[-5] & 0x10) {
703 if (a >= (ctx->nr[0] << 1)) {
704 ctx->nr[0] = (a + 1) >> 1;
705 ctx->r[0] = (uint16_t *)SSFN_realloc(ctx->r[0], (ctx->nr[0] << 1));
707 ctx->err = SSFN_ERR_ALLOC;
711 ctx->ret->cmap = (uint32_t *)((uint8_t *)ctx->f + ctx->f->size - 964);
712 for (re = raw + n, ra = (uint8_t *)ctx->r[0], i = 0;
713 i < a && raw < re;) {
714 c = (raw[0] & 0x7F) + 1;
716 for (j = 0; j < c; j++) ra[i++] = raw[1];
720 for (j = 0; j < c; j++) ra[i++] = *raw++;
726 w = _ssfn_g2i(x << s);
728 if (c + h >= ctx->ret->h) c = ctx->ret->h - h;
729 c = t = c * ctx->ret->pitch;
730 for (j = 0; j < h; j++) {
731 o = (((j << 8) * (y << 8) / (h << 8)) >> 8) * x;
732 for (i = 0; i < w; i++) {
733 m = ((i << 8) * (x << 8) / (w << 8)) >> 8;
734 if (ra[o + m] < 0xF0) {
736 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
739 re = (uint8_t *)&ctx->ret->cmap[ra[o + m]];
740 a = (re[0] + re[1] + re[2] + 255) >> 2;
742 case SSFN_MODE_BITMAP:
743 if (a > 127) pix[c + (d >> 3)] |= 1 << (d & 7);
746 pix[c + d] = ra[o + m];
748 case SSFN_MODE_ALPHA:
754 if (d > ctx->ret->w) ctx->ret->w = d;
757 c += ctx->ret->pitch;
762 case SSFN_FRAG_HINTING:
764 n = ((raw[0] & 0xF) << 8) | raw[1];
771 raw += n << (ctx->f->features & SSFN_FEAT_HBIGCRD ? 1 : 0);
775 x = ((ox >> s) - 1) << (s - 4);
777 for (n++; n-- && x < 4096;) {
780 if (ctx->f->features & SSFN_FEAT_HBIGCRD) {
787 if (y < 4096) ctx->h[y++] = 65535;
792 if (!render && h)
break;
794 n = ((raw[0] & 0x3F) << 8) | raw[1];
800 if (ctx->f->quality < 5) {
805 x = ((raw[0] & 3) << 8) | raw[1];
806 y = ((raw[0] & 0x30) << 4) | raw[2];
812 x += ox + (ctx->style & 0x200 ? _ssfn_igg(y) : 0);
815 _ssfn_l(ctx, ctx->mx, ctx->my, 0);
816 _ssfn_l(ctx, -1, -1, 0);
818 _ssfn_l(ctx, x, y, 0);
820 ctx->lx = ctx->mx = x;
821 ctx->ly = ctx->my = y;
823 t = ctx->g < 8 ? (raw[0] >> 7) | ((raw[1] >> 6) & 2) : raw[0] & 3;
824 x = y = a = b = c = d = j = 0;
834 raw += raw[0] & 4 ? 5 : 2;
859 raw += raw[0] & 4 ? 5 : 2;
880 x = ((raw[0] & 4) << 6) | raw[1];
881 y = ((raw[0] & 8) << 5) | raw[2];
884 raw += raw[0] & 4 ? 5 : 2;
890 a = ((raw[0] & 16) << 4) | raw[3];
891 b = ((raw[0] & 32) << 3) | raw[4];
895 a = ((raw[0] & 16) << 4) | raw[3];
896 b = ((raw[0] & 32) << 3) | raw[4];
897 c = ((raw[0] & 64) << 2) | raw[5];
898 d = ((raw[0] & 128) << 1) | raw[6];
905 x = ((raw[0] & 12) << 6) | raw[1];
906 y = ((raw[0] & 48) << 4) | raw[2];
909 raw += raw[0] & 4 ? 5 : 2;
915 a = ((raw[3] & 3) << 8) | raw[4];
916 b = ((raw[3] & 12) << 6) | raw[5];
920 a = ((raw[3] & 3) << 8) | raw[4];
921 b = ((raw[3] & 12) << 6) | raw[5];
922 c = ((raw[3] & 48) << 4) | raw[6];
923 d = ((raw[3] & 192) << 2) | raw[7];
941 if (ctx->style & 0x200) {
951 _ssfn_l(ctx, x, y, 0);
954 _ssfn_b(ctx, ctx->lx, ctx->ly, ((a - ctx->lx) >> 1) + ctx->lx,
955 ((b - ctx->ly) >> 1) + ctx->ly, ((x - a) >> 1) + a,
956 ((y - b) >> 1) + b, x, y, 0);
959 _ssfn_b(ctx, ctx->lx, ctx->ly, a, b, c, d, x, y, 0);
962 }
else if (t == 1 && x >= 0 && y >= 0) {
963 a = ((ctx->lx < x) ? x - ctx->lx : ctx->lx - x) >> 4;
964 b = ((ctx->ly < y) ? y - ctx->ly : ctx->ly - y) >> 4;
965 c = (ctx->lx + x) >> 5;
967 ctx->h[4096 + (!ctx->h[4096 + c] && c && ctx->h[4096 + c - 1]
978 for (j = m = x = y = 0; j < 4096; j++) {
979 if (ctx->h[4096 + j] >= 4096 / SSFN_HINTING_THRESHOLD) {
983 ctx->h[4096 + m++] = j - x;
988 if (m < 4096) ctx->h[4096 + m] = 65535;
1002#define SSFN_CMAP_TO_ARGB(p, c, fg) \
1003 (p >= 0xF0 ? (uint32_t)((p << 28) | ((p & 0xF) << 24) | fg) : c[p])
1015 if (!ctx || !font) {
1016 if (ctx) ctx->err = SSFN_ERR_INVINP;
1017 return SSFN_ERR_INVINP;
1020 if (!SSFN_memcmp(font->magic, SSFN_COLLECTION, 4)) {
1021 end = (
ssfn_font_t *)((uint8_t *)font + font->size);
1022 for (ptr = (
ssfn_font_t *)((uint8_t *)font + 8); ptr < end && !ctx->err;
1023 ptr = (
ssfn_font_t *)((uint8_t *)ptr + ptr->size))
1024 ssfn_load(ctx, ptr);
1026 if (SSFN_memcmp(font->magic, SSFN_MAGIC, 4) ||
1027 SSFN_memcmp((uint8_t *)font + font->size - 4, SSFN_ENDMAGIC, 4) ||
1028 font->family > SSFN_FAMILY_HAND || font->fragments_offs > font->size ||
1029 font->characters_offs[0] > font->size ||
1030 font->kerning_offs > font->size ||
1031 font->fragments_offs >= font->characters_offs[0] || font->quality > 8) {
1032 ctx->err = SSFN_ERR_BADFILE;
1034 ctx->len[font->family]++;
1035 ctx->fnt[font->family] = (
const ssfn_font_t **)SSFN_realloc(
1036 ctx->fnt[font->family], ctx->len[font->family] *
sizeof(
void *));
1037 if (!ctx->fnt[font->family])
1038 ctx->err = SSFN_ERR_ALLOC;
1040 ctx->fnt[font->family][ctx->len[font->family] - 1] = font;
1057int ssfn_select(
ssfn_t *ctx,
int family,
char *name,
int style,
int size,
1061 if (!ctx)
return SSFN_ERR_INVINP;
1062 if ((style & ~0xCF))
return (ctx->err = SSFN_ERR_BADSTYLE);
1063 if (size < 8 || size > 255)
return (ctx->err = SSFN_ERR_BADSIZE);
1064 if (mode > SSFN_MODE_CMAP)
return (ctx->err = SSFN_ERR_BADMODE);
1066 if (family == SSFN_FAMILY_BYNAME) {
1067 if (!name || !name[0]) {
1069 return (ctx->err = SSFN_ERR_INVINP);
1071 for (l = 0; name[l]; l++);
1072 for (i = 0; i < 5; i++) {
1073 for (j = 0; j < ctx->len[i]; j++) {
1075 name, (uint8_t *)&ctx->fnt[i][j]->magic +
sizeof(
ssfn_font_t),
1077 ctx->s = ctx->fnt[i][j];
1083 return (ctx->err = SSFN_ERR_NOFACE);
1085 if (family != SSFN_FAMILY_ANY) {
1086 if (family > SSFN_FAMILY_HAND)
goto invinp;
1087 if (!ctx->len[family])
goto noface;
1092 ctx->np = ctx->mp = 0;
1098 ctx->family = family;
1103 return (ctx->err = SSFN_OK);
1113int ssfn_variant(
ssfn_t *ctx,
int variant) {
1114 if (!ctx)
return SSFN_ERR_INVINP;
1115 if (variant < 0 || variant > SSFN_NUMVARIANTS - 1)
1116 return (ctx->err = SSFN_ERR_INVINP);
1117 ctx->variant = variant;
1118 return (ctx->err = SSFN_OK);
1130 int i, j, s, h, p, m, n, bt, bl;
1132 uint8_t *rg = NULL, c, d;
1134 if (!ctx)
return NULL;
1135 if (ctx->size < 8) {
1136 ctx->err = SSFN_ERR_NOFACE;
1142 rg = _ssfn_c(ctx->f, unicode, ctx->variant);
1143 if (!rg) rg = _ssfn_c(ctx->f, unicode, 0);
1148 if (p == SSFN_FAMILY_ANY) {
1153 for (; n <= m; n++) {
1155 if (ctx->style & 3) {
1157 for (i = 0; i < ctx->len[n]; i++)
1158 if ((fl[i]->style & 3) == (ctx->style & 3) &&
1159 (rg = _ssfn_c(fl[i], unicode, k))) {
1165 if (!rg && (ctx->style & 3) == 3)
1166 for (i = 0; i < ctx->len[n]; i++)
1167 if ((fl[i]->style & 3) && (rg = _ssfn_c(fl[i], unicode, k))) {
1175 for (i = 0; i < ctx->len[n]; i++)
1176 if ((rg = _ssfn_c(fl[i], unicode, k))) {
1185 if (p != SSFN_FAMILY_ANY) {
1186 p = SSFN_FAMILY_ANY;
1196 ctx->err = ctx->variant ? SSFN_ERR_NOVARIANT : SSFN_ERR_NOGLYPH;
1201 if ((ctx->style & 1) && !(ctx->f->style & 1)) ctx->style |= 0x100;
1202 if ((ctx->style & 2) && !(ctx->f->style & 2)) ctx->style |= 0x200;
1203 if (ctx->f->family == SSFN_FAMILY_MONOSPACE)
1204 ctx->style |= SSFN_STYLE_ABS_SIZE;
1206 ctx->g = 4 + ctx->f->quality;
1210 if (ctx->mode == SSFN_MODE_OUTLINE) {
1214 if (!(((rg[2] & 0x0F) << 8) | rg[6]) || ctx->style & SSFN_STYLE_ABS_SIZE)
1217 h = (4096 << 4) * ctx->size /
1218 ((ctx->f->baseline - ctx->f->bbox_top) << s);
1219 p = (h + (ctx->style & 0x100 ? 2 : 0) + (ctx->style & 0x200 ? h >> 2 : 0));
1222 if (ctx->style & 0x100) h -= 2;
1223 if (ctx->style & 0x200) h = h * 4 / 5;
1225 if (ctx->mode == SSFN_MODE_BITMAP) p = (p + 7) >> 3;
1230 ctx->h = (uint16_t *)SSFN_realloc(NULL, 4096 * 2 *
sizeof(uint16_t));
1231 if (!ctx->h)
goto erralloc;
1233 if (!(ctx->style & SSFN_STYLE_NOHINTING)) {
1234 SSFN_memset(&ctx->h[4096], 0, 4096 *
sizeof(uint16_t));
1235 _ssfn_g(ctx, rg, 0);
1237 ctx->h[4096] = 65535;
1240 for (i = j = k = x = y = m = 0; i < 4096 && j < 4095; i++) {
1241 y = ctx->h[4096 + i] == 65535 ? 4095 - j : ctx->h[4096 + i];
1244 ctx->h[j] = (((j << 4) * h + (1 << 15)) >> 16) << 8;
1247 y = _ssfn_g2o(y << 4);
1249 if ((i & 1) || y < 256) {
1254 for (l = 0; l + x <= j; l++) ctx->h[x + l] = n + ((m - n) * l / (j - x));
1258 ctx->uix = _ssfn_g2ixc((((rg[2] & 0x0F) << 8) | rg[6]) << s);
1259 ctx->uax = _ssfn_g2iyc((((rg[2] & 0xF0) << 4) | rg[7]) << s);
1260 if (ctx->mode == SSFN_MODE_NONE)
return NULL;
1262 bl = ((((rg[3] & 0x0F) << 8) | rg[8])) << s;
1263 bt = ((((rg[3] & 0xF0) << 4) | rg[9])) << s;
1265 ctx->ret = (
ssfn_glyph_t *)SSFN_realloc(NULL, i + 8 +
sizeof(uint8_t *));
1268 ctx->err = SSFN_ERR_ALLOC;
1271 SSFN_memset(&ctx->ret->data, ctx->mode == SSFN_MODE_CMAP ? 0xF0 : 0, i);
1272 ctx->ret->cmap = NULL;
1273 ctx->ret->mode = ctx->mode;
1274 ctx->ret->pitch = p;
1277 ctx->ret->baseline =
1278 (((ctx->f->baseline << s) - bt) * h + (1 << 16) - 1) >> 16;
1279 ctx->u = ctx->ret->baseline +
1280 ((((ctx->f->underline - ctx->f->baseline) << s) * h) >> 16);
1282 ctx->ret->adv_x = ctx->uix;
1283 ctx->ret->adv_y = ctx->uax;
1285 ctx->ix = ctx->uix = 4096 << 4;
1287 _ssfn_g(ctx, rg, 1);
1290 if (!(ctx->style & 0x200) || ctx->ix == 4096 << 4) ctx->ix = 0;
1291 if (ctx->mode == SSFN_MODE_OUTLINE) {
1292 if (ctx->np > p * h) {
1294 ctx->ret, ctx->np + 8 +
sizeof(uint8_t *));
1295 if (!ctx->ret)
goto erralloc;
1297 for (s = i = 0; i < ctx->np; i += 2) {
1298 c = ctx->p[i + 0] == 0xffff ? 0xff : _ssfn_g2ix(ctx->p[i + 0] + bl);
1299 d = ctx->p[i + 1] == 0xffff ? 0xff : _ssfn_g2iy(ctx->p[i + 1] + bt);
1300 if (s < 2 || ctx->ret->data[s - 2] != c || ctx->ret->data[s - 1] != d) {
1301 ctx->ret->data[s++] = c;
1302 ctx->ret->data[s++] = d;
1305 ctx->ret->pitch = s;
1307 (
ssfn_glyph_t *)SSFN_realloc(ctx->ret, s + 8 +
sizeof(uint8_t *));
1308 if (!ctx->ret)
goto erralloc;
1311 if (ctx->mode != SSFN_MODE_BITMAP) _ssfn_a(ctx);
1312 if (ctx->style & SSFN_STYLE_STHROUGH) {
1313 if (ctx->ret->w < ctx->ret->adv_x) ctx->ret->w = ctx->ret->adv_x;
1315 &ctx->ret->data[(ctx->ret->baseline - (ctx->size >> 2)) * p], 0xFF,
1316 (ctx->size / 64 + 2) * p);
1318 if (ctx->style & SSFN_STYLE_UNDERLINE) {
1319 if (ctx->ret->w < ctx->ret->adv_x) ctx->ret->w = ctx->ret->adv_x;
1320 if (ctx->uax > ctx->ix) ctx->uax = _ssfn_g2i(ctx->uax - ctx->ix);
1321 if (ctx->uix != 4096 << 4)
1322 ctx->uix = _ssfn_g2i(ctx->uix - ctx->ix);
1324 ctx->uix = ctx->ret->w + 3;
1326 n = ctx->size > 127 ? 2 : 1;
1330 if (ctx->mode == SSFN_MODE_BITMAP)
1331 for (i = 0; i < j; i++)
1332 ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1334 SSFN_memset(&ctx->ret->data[m], 0xFF, j);
1338 if (ctx->mode == SSFN_MODE_BITMAP)
1339 for (i = j; i < ctx->ret->w; i++)
1340 ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1342 SSFN_memset(&ctx->ret->data[m + j], 0xFF, p - j);
1348 if (ctx->ret->adv_y) ctx->ret->baseline = ctx->ret->w >> 1;
1349 }
else if (ctx->ret) {
1350 SSFN_free(ctx->ret);
1366int ssfn_kern(
ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode,
int *x,
1369 uint32_t i, j, k, l, a, b, c;
1373 if (!ctx || !x || !y)
return SSFN_ERR_INVINP;
1374 if (!ctx->f && !ctx->s)
return (ctx->err = SSFN_ERR_NOFACE);
1375 font = ctx->s ? ctx->s : ctx->f;
1376 if (unicode && nextunicode && font->kerning_offs) {
1377 ptr = (uint8_t *)font + font->kerning_offs;
1378 a = font->features & SSFN_FEAT_KBIGLKP ? 4 : 3;
1379 b = font->features & SSFN_FEAT_KBIGCHR;
1380 c = font->features & SSFN_FEAT_KBIGCRD;
1381 for (i = 0; i < 0x110000; i++) {
1382 if (ptr[0] & 0x80) {
1383 if (ptr[0] & 0x40) {
1384 i += ptr[1] | ((ptr[0] & 0x3f) << 8);
1392 if (unicode >= i && unicode <= i + m) {
1393 ptr = (uint8_t *)font + font->kerning_offs +
1394 ((a == 4 ? (ptr[3] << 16) : 0) | (ptr[2] << 8) | ptr[1]);
1395 if (ptr[0] & 0x80) {
1396 k = ptr[1] | ((ptr[0] & 0x7f) << 8);
1402 for (m = 0, a = SSFN_ERR_NOGLYPH, i = j = 0;
1403 i <= k && j <= nextunicode; i++) {
1405 j = ptr[0] | (ptr[1] << 8) | ((ptr[2] & 0x7F) << 16);
1409 j = ptr[0] | ((ptr[1] & 0x7F) << 8);
1414 m = (short)(ptr[0] | (ptr[1] << 8));
1417 m = (
signed char)ptr[0];
1420 if (j == nextunicode) {
1422 m = (((m) << (16 - ctx->g)) * ctx->m + (1 << 16) - 1) >> 16;
1429 return (ctx->err = a);
1436 return (ctx->err = SSFN_ERR_NOGLYPH);
1449int ssfn_bbox(
ssfn_t *ctx,
char *str,
int usekern,
int *w,
int *h) {
1453 if (!ctx)
return SSFN_ERR_INVINP;
1454 if (!str || !w || !h)
return (ctx->err = SSFN_ERR_INVINP);
1457 ctx->mode = SSFN_MODE_NONE;
1459 for (s = str, u = ssfn_utf8(&s); u;) {
1460 ssfn_render(ctx, u);
1461 if (ctx->err == SSFN_OK) {
1466 if (usekern) ssfn_kern(ctx, u, v, w, h);
1469 if (!*w) *w = ctx->m;
1470 if (!*h) *h = ctx->m;
1481int ssfn_mem(
ssfn_t *ctx) {
1482 int i, ret =
sizeof(
ssfn_t);
1486 for (i = 0; i < 5; i++) ret += ctx->len[i] *
sizeof(
ssfn_font_t *);
1487 if (ctx->p) ret += ctx->mp *
sizeof(uint16_t);
1488 for (i = 0; i < 256; i++)
1489 if (ctx->r[i]) ret += ctx->nr[i] *
sizeof(uint16_t);
1490 if (ctx->h) ret += 8192 *
sizeof(uint16_t);
1499void ssfn_free(
ssfn_t *ctx) {
1504 for (i = 0; i < 5; i++)
1505 if (ctx->fnt[i]) SSFN_free(ctx->fnt[i]);
1506 if (ctx->p) SSFN_free(ctx->p);
1507 for (i = 0; i < 256; i++)
1508 if (ctx->r[i]) SSFN_free(ctx->r[i]);
1509 if (ctx->h) SSFN_free(ctx->h);
1510 SSFN_memset(ctx, 0,
sizeof(
ssfn_t));
1516#if !defined(SSFN_NOIMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1517 defined(SSFN_CONSOLEBITMAP_HICOLOR) || \
1518 defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1526uint32_t ssfn_utf8(
char **s) {
1529 if ((**s & 128) != 0) {
1531 c = ((**s & 0x1F) << 6) | (*(*s + 1) & 0x3F);
1533 }
else if (!(**s & 16)) {
1534 c = ((**s & 0xF) << 12) | ((*(*s + 1) & 0x3F) << 6) | (*(*s + 2) & 0x3F);
1536 }
else if (!(**s & 8)) {
1537 c = ((**s & 0x7) << 18) | ((*(*s + 1) & 0x3F) << 12) |
1538 ((*(*s + 2) & 0x3F) << 6) | (*(*s + 3) & 0x3F);
1548#if defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1549 defined(SSFN_CONSOLEBITMAP_HICOLOR) || \
1550 defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1558uint8_t *ssfn_dst_ptr;
1559uint32_t ssfn_dst_pitch;
1560uint32_t ssfn_dst_w = 0;
1561uint32_t ssfn_dst_h = 0;
1563#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1577int ssfn_putc(uint32_t unicode) {
1578 uint32_t i, j, a, b, m, p, t;
1579 uint8_t *rg, *o, *g, *s, *r, y, n;
1580#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1584 t = (ssfn_font->quality < 5 && ssfn_font->characters_offs[0] < 65536)
1586 : (ssfn_font->characters_offs[0] < 1048576 ? 5 : 6);
1587 rg = (uint8_t *)ssfn_font + ssfn_font->characters_offs[0];
1588 ssfn_adv_x = ssfn_adv_y = 0;
1590 for (j = i = 0; i < 0x110000; i++) {
1594 i += rg[1] | (n << 8);
1603#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1606 if (ssfn_dst_w && (ssfn_x + w >= ssfn_dst_w)) w = ssfn_dst_w - ssfn_x;
1607 s = ssfn_dst_ptr + (ssfn_y)*ssfn_dst_pitch;
1608#ifdef SSFN_CONSOLEBITMAP_PALETTE
1611#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1618 if ((ssfn_dst_w && (ssfn_x > ssfn_dst_w)) ||
1619 (ssfn_dst_h && (ssfn_y + ssfn_font->bbox_bottom >= ssfn_dst_h)))
1620 return SSFN_ERR_INVINP;
1626#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1627 s = ssfn_dst_ptr + (ssfn_y + y + rg[t - 1]) * ssfn_dst_pitch;
1628#ifdef SSFN_CONSOLEBITMAP_PALETTE
1631#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1638 o = (uint8_t *)ssfn_font;
1639 a = ((rg[1] << 8) | rg[0]);
1645 o += ((rg[2] & 0xF) << 16) | a;
1648 o += ((rg[3] & 0xF) << 24) | (rg[2] << 16) | a;
1651 p = ((o[0] & 0xF) + 1);
1655 if (ssfn_dst_w && (ssfn_x + a >= ssfn_dst_w)) a = ssfn_dst_w - ssfn_x;
1656#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1657 for (; j < y + rg[t - 1]; j++, s += ssfn_dst_pitch)
1658 for (r = s, i = 0; i < w; i++) {
1659#ifdef SSFN_CONSOLEBITMAP_PALETTE
1660 *((uint8_t *)r) = (uint8_t)ssfn_bg;
1663#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1664 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1667 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1676 for (; j < b; j++, s += ssfn_dst_pitch, o += p) {
1677 for (g = o, r = s, m = 1, i = 0; i < a; i++, m <<= 1) {
1682#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1685#ifdef SSFN_CONSOLEBITMAP_PALETTE
1686 *((uint8_t *)r) = (uint8_t)(
1687#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1688 *g & m ? ssfn_fg : ssfn_bg
1695#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1696 *((uint16_t *)r) = (uint16_t)(
1697#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1698 *g & m ? ssfn_fg : ssfn_bg
1705 *((uint32_t *)r) = (uint32_t)(
1706#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1707 *g & m ? ssfn_fg : ssfn_bg
1719#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1720 for (; j <= ssfn_font->bbox_bottom; j++, s += ssfn_dst_pitch)
1721 for (r = s, i = 0; i < w; i++) {
1722#ifdef SSFN_CONSOLEBITMAP_PALETTE
1723 *((uint8_t *)r) = (uint8_t)ssfn_bg;
1726#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1727 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1730 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1736 ssfn_x += ssfn_adv_x;
1737 ssfn_y += ssfn_adv_y;
1740 rg += rg[0] * t + 10;
1744 return SSFN_ERR_NOGLYPH;