OpenCPN Partial API docs
Loading...
Searching...
No Matches
ssfn.h
Go to the documentation of this file.
1/*
2 * ssfn.h
3 *
4 * Copyright (C) 2019 bzt (bztsrc@gitlab)
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 */
27
35#ifndef _SSFN_H_
36#define _SSFN_H_
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42/* if stdint.h was not included before us */
43#ifndef uint8_t
44typedef unsigned char uint8_t;
45typedef unsigned short int uint16_t;
46typedef unsigned int uint32_t;
47#endif
48
49/***** file format *****/
50
51/* magic bytes */
52#define SSFN_MAGIC "SSFN"
53#define SSFN_COLLECTION "SFNC"
54#define SSFN_ENDMAGIC "NFSS"
55
56/* font family group */
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
62
63/* font style flags */
64#define SSFN_STYLE_REGULAR 0
65#define SSFN_STYLE_BOLD 1
66#define SSFN_STYLE_ITALIC 2
67
68/* file format features */
69#define SSFN_FEAT_HASBMAP 1 /* there's at least one bitmap fragment */
70#define SSFN_FEAT_HASCMAP \
71 2 /* there's at least one pixmap fragment or one color command, so a color \
72 map too */
73#define SSFN_FEAT_HASHINT 4 /* there's at least one hinting fragment */
74#define SSFN_FEAT_KBIGLKP 8 /* big offsets in kerning look up table */
75#define SSFN_FEAT_KBIGCHR 16 /* big characters in kerning look up tables */
76#define SSFN_FEAT_KBIGCRD 32 /* big coordinates in kerning groups */
77#define SSFN_FEAT_HBIGCRD 64 /* bit coordinates in autohinting fragments */
78
79/* contour commands for vector fragments */
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
85
86/* bitmap and pixmap fragments and hinting grid info */
87#define SSFN_FRAG_BITMAP 0
88#define SSFN_FRAG_LBITMAP 1
89#define SSFN_FRAG_PIXMAP 2
90#define SSFN_FRAG_HINTING 3
91
92/* glyph variants */
93#define SSFN_VARIANT_DEFAULT 0 /* default, also isolated glyphs */
94#define SSFN_VARIANT_LOCAL0 0
95#define SSFN_VARIANT_INITIAL \
96 1 /* currently not needed because contextual glyphs has their own UNICODE \
97 code points, */
98#define SSFN_VARIANT_LOCAL1 \
99 1 /* so its only purpose is to store Serbian / Macedonian B D G P T */
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
109/* main SSFN header */
110typedef struct {
111 uint8_t magic[4]; /* SSFN magic bytes */
112 uint32_t size; /* total size in bytes */
113 uint8_t family; /* font family group */
114 uint8_t style; /* font style, zero or OR'd SSFN_STYLE_BOLD and
115 SSFN_STYLE_ITALIC */
116 uint8_t quality; /* quality, defines grid size, 0 - 8 */
117 uint8_t features; /* feature flags, OR'd SSFN_FEAT_* */
118 uint8_t revision; /* format revision, must be zero */
119 uint8_t reserved0; /* must be zero */
120 uint16_t reserved1;
121 uint16_t baseline; /* horizontal baseline in grid pixels */
122 uint16_t underline; /* position of under line in grid pixels */
123 uint16_t bbox_left; /* overall bounding box for all glyphs in grid pixels */
124 uint16_t bbox_top;
125 uint16_t bbox_right;
126 uint16_t bbox_bottom;
127 uint32_t fragments_offs; /* offset of fragments table relative to magic */
128 uint32_t characters_offs[SSFN_NUMVARIANTS]; /* offset of characters tables per
129 variant relative to magic */
130 uint32_t kerning_offs; /* kerning table offset relative to magic */
132
133/***** renderer API *****/
134#define SSFN_FAMILY_ANY 0xff /* select the first loaded font */
135#define SSFN_FAMILY_BYNAME 0xfe /* select font by its unique name */
136
137#define SSFN_STYLE_UNDERLINE 4 /* under line glyph */
138#define SSFN_STYLE_STHROUGH 8 /* strike through glyph */
139#define SSFN_STYLE_NOHINTING 0x40 /* no auto hinting grid */
140#define SSFN_STYLE_ABS_SIZE 0x80 /* use absolute size value */
141
142#define SSFN_FRAG_CONTOUR 255
143
144/* error codes */
145#define SSFN_OK 0 /* success */
146#define SSFN_ERR_ALLOC 1 /* allocation error */
147#define SSFN_ERR_NOFACE 2 /* no font face selected */
148#define SSFN_ERR_INVINP 3 /* invalid input */
149#define SSFN_ERR_BADFILE 4 /* bad SSFN file format */
150#define SSFN_ERR_BADSTYLE 5 /* bad style */
151#define SSFN_ERR_BADSIZE 6 /* bad size */
152#define SSFN_ERR_BADMODE 7 /* bad mode */
153#define SSFN_ERR_NOGLYPH 8 /* glyph (or kerning info) not found */
154#define SSFN_ERR_NOVARIANT 9 /* no such glyph variant */
155
156/* rendering modes */
157#define SSFN_MODE_NONE \
158 0 /* just select the font to get the glyph (for kerning) */
159#define SSFN_MODE_OUTLINE 1 /* return the glyph's outlines */
160#define SSFN_MODE_BITMAP 2 /* render into bitmap */
161#define SSFN_MODE_ALPHA 3 /* render into alpha channel */
162#define SSFN_MODE_CMAP 4 /* render into color map indexed buffer */
163
164/* grid fitting */
165#define SSFN_HINTING_THRESHOLD \
166 16 /* don't change unless you really know what you're doing */
167
168/* returned bitmap struct */
169#define SSFN_DATA_MAX 65536
170typedef struct {
171 uint8_t mode; /* returned glyph's data format */
172 uint8_t baseline; /* baseline of glyph, scaled to size */
173 uint8_t w; /* width */
174 uint8_t h; /* height */
175 uint8_t adv_x; /* advance x */
176 uint8_t adv_y; /* advance y */
177 uint16_t pitch; /* data buffer bytes per line */
178 uint32_t *cmap; /* pointer to color map */
179 uint8_t data[SSFN_DATA_MAX]; /* data buffer */
182/* renderer context */
183typedef struct {
184 const ssfn_font_t **fnt[5]; /* font registry */
185 const ssfn_font_t *s; /* explicitly selected font */
186 const ssfn_font_t *f; /* font selected by best match */
187 ssfn_glyph_t *ret; /* glyph to return */
188 uint16_t *p; /* outline points */
189 uint16_t *r[256]; /* raster for scanlines */
190 uint16_t *h; /* auto hinting grid */
191 int len[5]; /* number of fonts in registry */
192 int mp; /* memory allocated for points */
193 int np; /* how many points actually are there */
194 int nr[256]; /* number of coordinates in each raster line */
195 int err; /* returned error code */
196 int family; /* required family */
197 int style; /* required style */
198 int size; /* required size */
199 int mode; /* required mode */
200 int variant; /* required variant */
201 int g; /* shift value for grid size */
202 int m, ix, u, uix, uax, lx, ly, mx, my; /* helper variables */
203} ssfn_t;
204
205/***** API function protoypes *****/
206
207/* normal renderer */
208int ssfn_load(ssfn_t *ctx,
209 const ssfn_font_t *font); /* add an SSFN to context */
210int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size,
211 int mode); /* select font to use */
212int ssfn_variant(ssfn_t *ctx,
213 int variant); /* select glyph variant (optional) */
214uint32_t ssfn_utf8(char **str); /* decode UTF-8 sequence */
216 uint32_t unicode); /* return allocated glyph bitmap */
217int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x,
218 int *y); /* get kerning values */
219int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w,
220 int *h); /* get bounding box of a rendered string */
221int ssfn_mem(ssfn_t *ctx); /* return how much memory is used */
222void ssfn_free(ssfn_t *ctx); /* free context */
223#define ssfn_lasterr(ctx) ((ssfn_t *)ctx)->err /* return last error code */
224#define ssfn_error(err) \
225 (err >= 0 && err <= 9 ? ssfn_errstr[err] \
226 : "Unknown error") /* return string for error code */
227extern const char *ssfn_errstr[];
228
229/* simple renderer */
230int ssfn_putc(uint32_t unicode); /* render console bitmap font */
231
232/***** renderer implementations *****/
233
234#ifndef SSFN_NOIMPLEMENTATION
235/*** normal renderer (ca. 22k, fully featured with error checking) ***/
236
237#ifndef NULL
238#define NULL (void *)0
239#endif
240// # ifndef size_t
241// typedef __SIZE_TYPE__ size_t;
242// # endif
243#ifndef ssfn_private
244#define ssfn_private
245#endif
246// # ifndef inline
247// # define inline __inline__
248// # endif
249
250/* Clang does not have built-in versions of these but gcc has */
251#ifndef SSFN_memcmp
252#ifdef __builtin_memcmp
253#define SSFN_memcmp __builtin_memcmp
254#else
255#define SSFN_memcmp memcmp
256#endif
257#endif
258
259#ifndef SSFN_memset
260#ifdef __builtin_memset
261#define SSFN_memset __builtin_memset
262#else
263#define SSFN_memset memset
264#endif
265#endif
266
267#ifndef SSFN_realloc
268#ifdef __builtin_realloc
269#define SSFN_realloc __builtin_realloc
270#else
271#define SSFN_realloc realloc
272#endif
273#endif
274
275#ifndef SSFN_free
276#ifdef __builtin_free
277#define SSFN_free __builtin_free
278#else
279#define SSFN_free free
280#endif
281#endif
282
286const char *ssfn_errstr[] = {"",
287 "Memory allocation error",
288 "No font face found",
289 "Invalid input value",
290 "Bad file format",
291 "Invalid style",
292 "Invalid size",
293 "Invalid mode",
294 "Glyph not found",
295 "Glyph variant not found"};
296
297/*** Private functions ***/
298/* f = file scale, g = grid 4095.15, o = screen point 255.255, i = screen pixel
299 * 255, c = ceil */
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))
318
319/* parse character table */
320ssfn_private uint8_t *_ssfn_c(const ssfn_font_t *font, uint32_t unicode,
321 int v) {
322 uint32_t i, j, l;
323 uint8_t *ptr;
324
325 if (!font->characters_offs[v]) return NULL;
326
327 ptr = (uint8_t *)font + font->characters_offs[v];
328 l = (font->quality < 5 && font->characters_offs[v] < 65536)
329 ? 4
330 : (font->characters_offs[v] < 1048576 ? 5 : 6);
331
332 for (j = i = 0; i < 0x110000; i++) {
333 if (ptr[0] & 0x80) {
334 if (ptr[0] & 0x40) {
335 i += ptr[1] | ((ptr[0] & 0x3f) << 8);
336 ptr += 2;
337 } else {
338 i += ptr[0] & 0x3f;
339 ptr++;
340 }
341 } else {
342 if (i == unicode) return ptr;
343 ptr += ptr[0] * l + 10;
344 j++;
345 }
346 }
347 return NULL;
348}
349
350/* add a line to contour */
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;
355
356 if (ctx->np + 2 >= ctx->mp) {
357 ctx->mp += 512;
358 ctx->p = (uint16_t *)SSFN_realloc(ctx->p, ctx->mp * sizeof(uint16_t));
359 if (!ctx->p) {
360 ctx->err = SSFN_ERR_ALLOC;
361 return;
362 }
363 }
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;
368 ctx->lx = x;
369 ctx->ly = y;
370 }
371 if ((ctx->style & 0x200) && x >= 0 && ctx->ix > x) ctx->ix = x;
372}
373
374/* add a Bezier curve to contour */
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);
393 }
394 _ssfn_l(ctx, x3, y3, l);
395}
396
397/* rasterize contour */
398ssfn_private void _ssfn_r(ssfn_t *ctx) {
399 int i, k, l, m, n = 0, x, y, Y, M = 0;
400 uint16_t *r;
401 uint8_t *pix = ctx->ret->data;
402
403 for (y = 0; y < ctx->ret->h; y++) {
404 Y = _ssfn_i2g(y);
405 r = ctx->r[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))
409 continue;
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);
414 else
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]));
418 if (y == ctx->u) {
419 if (x < ctx->uix) {
420 ctx->uix = x;
421 }
422 if (x > ctx->uax) {
423 ctx->uax = x;
424 }
425 }
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));
431 if (!ctx->r[y]) {
432 ctx->err = SSFN_ERR_ALLOC;
433 return;
434 }
435 r = ctx->r[y];
436 }
437 for (l = n; l > k; l--) r[l] = r[l - 1];
438 r[k] = x;
439 n++;
440 }
441 }
442 if (n > 1 && n & 1) {
443 r[n - 2] = r[n - 1];
444 n--;
445 }
446 ctx->nr[y] = n;
447 if (n) {
448 if (y > M) M = y;
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;
458 else
459 r[i] += 256;
460 if (r[i + 1] - 256 > r[i]) r[i + 1] -= 256;
461 } else {
462 if (i >= n - 2 || r[i + 1] + 256 < r[i + 2]) r[i + 1] += 256;
463 }
464 }
465 l = ((r[i] + 128) >> 8);
466 m = ((r[i + 1] + 128) >> 8);
467 if (ctx->mode != SSFN_MODE_BITMAP && l + 1 < m) l++;
468 for (; l < m; l++) {
469 switch (ctx->mode) {
470 case SSFN_MODE_BITMAP:
471 pix[k + (l >> 3)] ^= 1 << (l & 7);
472 break;
473 case SSFN_MODE_ALPHA:
474 pix[k + l] ^= 0xFF;
475 break;
476 case SSFN_MODE_CMAP:
477 pix[k + l] ^= 0x0F;
478 break;
479 }
480 }
481 if (l + 1 > ctx->ret->w) ctx->ret->w = l + 1;
482 }
483 }
484 }
485 /* fix rounding errors */
486 if (M + 1 == ctx->ret->baseline) {
487 ctx->ret->baseline--;
488 ctx->u--;
489 }
490}
491
492/* anti-alias a contour */
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;
496 uint16_t *r;
497
498 if (ctx->mode < SSFN_MODE_ALPHA || !ctx->p || ctx->np < 4) return;
499
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);
505 if (e == 127)
506 e = 255;
507 else {
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];
510 }
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;
517 }
518 }
519 }
520
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))
524 continue;
525
526 x0 = ctx->p[i] - ctx->ix;
527 y0 = ctx->p[i + 1];
528 x1 = ctx->p[i + 2] - ctx->ix;
529 y1 = ctx->p[i + 3];
530 sx = x1 >= x0 ? 1 : -1;
531 sy = y1 >= y0 ? 1 : -1;
532 dx = x1 - x0;
533 dy = y1 - y0;
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));
537 y += 128;
538 e = ~(y & 0xFF);
539 y >>= 8;
540 e >>= 1;
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;
544 }
545 }
546 }
547}
548
549/* parse a glyph */
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;
553
554 ctx->lx = ctx->ly = ctx->mx = ctx->my = -1;
555 ol = (ctx->f->quality < 5 && ctx->f->characters_offs[ctx->variant] < 65536)
556 ? 4
557 : ((ctx->f->characters_offs[ctx->variant] < 1048576) ? 5 : 6);
558 s = 16 - ctx->g;
559 nf = rg[0];
560 rg += 10;
561
562 for (h = 0; nf-- && !ctx->err; rg += ol) {
563 switch (ol) {
564 case 4:
565 o = ((rg[1] << 8) | rg[0]);
566 ox = rg[2];
567 oy = rg[3];
568 break;
569 case 5:
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];
573 break;
574 default:
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];
578 break;
579 }
580 ox <<= s;
581 oy <<= s;
582 raw = (uint8_t *)ctx->f + o;
583 if (raw[0] & 0x80) {
584 t = (raw[0] & 0x60) >> 5;
585 if (!render && t != SSFN_FRAG_HINTING) break;
586 switch (t) {
587 case SSFN_FRAG_LBITMAP:
588 x = ((((raw[0] >> 2) & 3) << 8) + raw[1]) + 1;
589 y = (((raw[0] & 3) << 8) | raw[2]) + 1;
590 raw += 3;
591 goto bitmap;
592
593 case SSFN_FRAG_BITMAP:
594 x = (raw[0] & 0x1F) + 1;
595 y = raw[1] + 1;
596 raw += 2;
597 bitmap:
598 if (ctx->mode == SSFN_MODE_OUTLINE) {
599 x <<= 3;
600 outline:
601 ctx->lx = ctx->ly = -1;
602 x <<= s;
603 y <<= s;
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;
608 } else
609 a = b = 0;
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);
616 } else {
617 a = x << 3;
618 b = y << s;
619 c = _ssfn_g2i(oy);
620 n = _ssfn_g2i(ox);
621 w = _ssfn_g2i(x << (3 + s));
622 h = _ssfn_g2i(b);
623 if (c + h >= ctx->ret->h) c = ctx->ret->h - h; /* due to rounding */
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))) {
630 d = n +
631 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
632 : 0) +
633 i;
634 switch (ctx->mode) {
635 case SSFN_MODE_BITMAP:
636 pix[c + (d >> 3)] |= 1 << (d & 7);
637 d++;
638 if ((ctx->style & 0x100) && (d >> 3) < ctx->ret->pitch) {
639 pix[c + (d >> 3)] |= 1 << (d & 7);
640 d++;
641 if (ctx->size > 127 && (d >> 3) < ctx->ret->pitch) {
642 pix[c + (d >> 3)] |= 1 << (d & 7);
643 }
644 }
645 break;
646 case SSFN_MODE_CMAP:
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) {
652 pix[c + d] = 0xFF;
653 }
654 }
655 break;
656 }
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) {
661 if (d < ctx->uix) {
662 ctx->uix = d;
663 }
664 if (d > ctx->uax) {
665 ctx->uax = d;
666 }
667 }
668 }
669 }
670 c += ctx->ret->pitch;
671 }
672 if (ctx->mode != SSFN_MODE_BITMAP && h > y && w > 1) {
673 m = (ctx->mode == SSFN_MODE_CMAP) ? 0xF0 : 0;
674 x = h / y;
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++) {
681 d = n +
682 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s)) : 0) +
683 i;
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))
688 pix[c + d] = b;
689 }
690 c += ctx->ret->pitch;
691 }
692 }
693 }
694 }
695 h = 0;
696 break;
697
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;
702 raw += 5;
703 if (ctx->mode == SSFN_MODE_OUTLINE) goto outline;
704 if (raw[-5] & 0x10) {
705 /* todo: direct ARGB values in pixmap fragment */
706 }
707 a = x * y;
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));
711 if (!ctx->r[0]) {
712 ctx->err = SSFN_ERR_ALLOC;
713 return;
714 }
715 }
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;
720 if (raw[0] & 0x80) {
721 for (j = 0; j < c; j++) ra[i++] = raw[1];
722 raw += 2;
723 } else {
724 raw++;
725 for (j = 0; j < c; j++) ra[i++] = *raw++;
726 }
727 }
728 b = y << s;
729 c = _ssfn_g2i(oy);
730 n = _ssfn_g2i(ox);
731 w = _ssfn_g2i(x << s);
732 h = _ssfn_g2i(b);
733 if (c + h >= ctx->ret->h) c = ctx->ret->h - h; /* due to rounding */
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) {
740 d = n +
741 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
742 : 0) +
743 i;
744 re = (uint8_t *)&ctx->ret->cmap[ra[o + m]];
745 a = (re[0] + re[1] + re[2] + 255) >> 2;
746 switch (ctx->mode) {
747 case SSFN_MODE_BITMAP:
748 if (a > 127) pix[c + (d >> 3)] |= 1 << (d & 7);
749 break;
750 case SSFN_MODE_CMAP:
751 pix[c + d] = ra[o + m];
752 break;
753 case SSFN_MODE_ALPHA:
754 a >>= 1;
755 a = ~a;
756 pix[c + d] = a;
757 break;
758 }
759 if (d > ctx->ret->w) ctx->ret->w = d;
760 }
761 }
762 c += ctx->ret->pitch;
763 }
764 h = 0;
765 break;
766
767 case SSFN_FRAG_HINTING:
768 if (raw[0] & 0x10) {
769 n = ((raw[0] & 0xF) << 8) | raw[1];
770 raw += 2;
771 } else {
772 n = raw[0] & 0xF;
773 raw++;
774 }
775 if (render || !ox) {
776 raw += n << (ctx->f->features & SSFN_FEAT_HBIGCRD ? 1 : 0);
777 continue;
778 }
779 y = 4096;
780 x = ((ox >> s) - 1) << (s - 4);
781 ctx->h[y++] = x;
782 for (n++; n-- && x < 4096;) {
783 x = raw[0];
784 raw++;
785 if (ctx->f->features & SSFN_FEAT_HBIGCRD) {
786 x |= (raw[0] << 8);
787 raw++;
788 }
789 x <<= (s - 4);
790 ctx->h[y++] = x;
791 }
792 if (y < 4096) ctx->h[y++] = 65535;
793 h = 1;
794 break;
795 }
796 } else {
797 if (!render && h) break;
798 if (raw[0] & 0x40) {
799 n = ((raw[0] & 0x3F) << 8) | raw[1];
800 raw += 2;
801 } else {
802 n = raw[0] & 0x3F;
803 raw++;
804 }
805 if (ctx->f->quality < 5) {
806 x = raw[0];
807 y = raw[1];
808 raw += 2;
809 } else {
810 x = ((raw[0] & 3) << 8) | raw[1];
811 y = ((raw[0] & 0x30) << 4) | raw[2];
812 raw += 3;
813 }
814 x <<= s;
815 y <<= s;
816 y += oy;
817 x += ox + (ctx->style & 0x200 ? _ssfn_igg(y) : 0);
818 if (render) {
819 if (ctx->np) {
820 _ssfn_l(ctx, ctx->mx, ctx->my, 0);
821 _ssfn_l(ctx, -1, -1, 0);
822 }
823 _ssfn_l(ctx, x, y, 0);
824 }
825 ctx->lx = ctx->mx = x;
826 ctx->ly = ctx->my = y;
827 for (n++; n--;) {
828 t = ctx->g < 8 ? (raw[0] >> 7) | ((raw[1] >> 6) & 2) : raw[0] & 3;
829 x = y = a = b = c = d = j = 0;
830 switch (ctx->g) {
831 case 4:
832 case 5:
833 case 6:
834 case 7:
835 x = raw[0] & 0x7F;
836 y = raw[1] & 0x7F;
837 switch (t) {
838 case 0:
839 raw += raw[0] & 4 ? 5 : 2;
840 break;
841 case 1:
842 raw += 2;
843 break;
844 case 2:
845 a = raw[2] & 0x7F;
846 b = raw[3] & 0x7F;
847 raw += 4;
848 break;
849 case 3:
850 a = raw[2] & 0x7F;
851 b = raw[3] & 0x7F;
852 c = raw[4] & 0x7F;
853 d = raw[5] & 0x7F;
854 raw += 6;
855 break;
856 }
857 break;
858
859 case 8:
860 x = raw[1];
861 y = raw[2];
862 switch (t) {
863 case 0:
864 raw += raw[0] & 4 ? 5 : 2;
865 break;
866 case 1:
867 raw += 3;
868 break;
869 case 2:
870 a = raw[3];
871 b = raw[4];
872 raw += 5;
873 break;
874 case 3:
875 a = raw[3];
876 b = raw[4];
877 c = raw[5];
878 d = raw[6];
879 raw += 7;
880 break;
881 }
882 break;
883
884 case 9:
885 x = ((raw[0] & 4) << 6) | raw[1];
886 y = ((raw[0] & 8) << 5) | raw[2];
887 switch (t) {
888 case 0:
889 raw += raw[0] & 4 ? 5 : 2;
890 break;
891 case 1:
892 raw += 3;
893 break;
894 case 2:
895 a = ((raw[0] & 16) << 4) | raw[3];
896 b = ((raw[0] & 32) << 3) | raw[4];
897 raw += 5;
898 break;
899 case 3:
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];
904 raw += 7;
905 break;
906 }
907 break;
908
909 default:
910 x = ((raw[0] & 12) << 6) | raw[1];
911 y = ((raw[0] & 48) << 4) | raw[2];
912 switch (t) {
913 case 0:
914 raw += raw[0] & 4 ? 5 : 2;
915 break;
916 case 1:
917 raw += 3;
918 break;
919 case 2:
920 a = ((raw[3] & 3) << 8) | raw[4];
921 b = ((raw[3] & 12) << 6) | raw[5];
922 raw += 6;
923 break;
924 case 3:
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];
929 raw += 8;
930 break;
931 }
932 break;
933 }
934 x <<= s;
935 y <<= s;
936 a <<= s;
937 b <<= s;
938 c <<= s;
939 d <<= s;
940 x += ox;
941 y += oy;
942 a += ox;
943 b += oy;
944 c += ox;
945 d += oy;
946 if (ctx->style & 0x200) {
947 x += _ssfn_igg(y);
948 a += _ssfn_igg(b);
949 c += _ssfn_igg(d);
950 }
951 if (render) {
952 switch (t) {
953 case 0: /* this v1.0 renderer does not support colored contours */
954 break;
955 case 1:
956 _ssfn_l(ctx, x, y, 0);
957 break;
958 case 2:
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);
962 break;
963 case 3:
964 _ssfn_b(ctx, ctx->lx, ctx->ly, a, b, c, d, x, y, 0);
965 break;
966 }
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;
971 if (a < 2)
972 ctx->h[4096 + (!ctx->h[4096 + c] && c && ctx->h[4096 + c - 1]
973 ? c - 1
974 : c)] += b;
975 }
976 ctx->lx = x;
977 ctx->ly = y;
978 }
979 }
980 }
981
982 if (!render && !h) {
983 for (j = m = x = y = 0; j < 4096; j++) {
984 if (ctx->h[4096 + j] >= 4096 / SSFN_HINTING_THRESHOLD) {
985 if (!j)
986 m++;
987 else {
988 ctx->h[4096 + m++] = j - x;
989 x = j;
990 }
991 }
992 }
993 if (m < 4096) ctx->h[4096 + m] = 65535;
994 }
995}
996
997/*** public API implementation ***/
998
1007#define SSFN_CMAP_TO_ARGB(p, c, fg) \
1008 (p >= 0xF0 ? (uint32_t)((p << 28) | ((p & 0xF) << 24) | fg) : c[p])
1009
1017int ssfn_load(ssfn_t *ctx, const ssfn_font_t *font) {
1018 ssfn_font_t *ptr, *end;
1019
1020 if (!ctx || !font) {
1021 if (ctx) ctx->err = SSFN_ERR_INVINP;
1022 return SSFN_ERR_INVINP;
1023 }
1024 ctx->err = SSFN_OK;
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))
1029 ssfn_load(ctx, ptr);
1030 } else {
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;
1038 } else {
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;
1044 else
1045 ctx->fnt[font->family][ctx->len[font->family] - 1] = font;
1046 }
1047 }
1048 return ctx->err;
1049}
1050
1062int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size,
1063 int mode) {
1064 int i, j, l;
1065
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);
1070
1071 if (family == SSFN_FAMILY_BYNAME) {
1072 if (!name || !name[0]) {
1073 invinp:
1074 return (ctx->err = SSFN_ERR_INVINP);
1075 }
1076 for (l = 0; name[l]; l++);
1077 for (i = 0; i < 5; i++) {
1078 for (j = 0; j < ctx->len[i]; j++) {
1079 if (!SSFN_memcmp(
1080 name, (uint8_t *)&ctx->fnt[i][j]->magic + sizeof(ssfn_font_t),
1081 l)) {
1082 ctx->s = ctx->fnt[i][j];
1083 goto familyfound;
1084 }
1085 }
1086 }
1087 noface:
1088 return (ctx->err = SSFN_ERR_NOFACE);
1089 } else {
1090 if (family != SSFN_FAMILY_ANY) {
1091 if (family > SSFN_FAMILY_HAND) goto invinp;
1092 if (!ctx->len[family]) goto noface;
1093 }
1094 ctx->s = NULL;
1095 }
1096familyfound:
1097 ctx->np = ctx->mp = 0;
1098 if (ctx->p) {
1099 SSFN_free(ctx->p);
1100 ctx->p = NULL;
1101 }
1102 ctx->f = NULL;
1103 ctx->family = family;
1104 ctx->style = style;
1105 ctx->size = size;
1106 ctx->mode = mode;
1107 ctx->variant = 0;
1108 return (ctx->err = SSFN_OK);
1109}
1110
1118int ssfn_variant(ssfn_t *ctx, int variant) {
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);
1124}
1125
1133ssfn_glyph_t *ssfn_render(ssfn_t *ctx, uint32_t unicode) {
1134 ssfn_font_t **fl;
1135 int i, j, s, h, p, m, n, bt, bl;
1136 int l, k, x, y;
1137 uint8_t *rg = NULL, c, d;
1138
1139 if (!ctx) return NULL;
1140 if (ctx->size < 8) {
1141 ctx->err = SSFN_ERR_NOFACE;
1142 return NULL;
1143 }
1144 ctx->err = SSFN_OK;
1145 if (ctx->s) {
1146 ctx->f = (ssfn_font_t *)ctx->s;
1147 rg = _ssfn_c(ctx->f, unicode, ctx->variant);
1148 if (!rg) rg = _ssfn_c(ctx->f, unicode, 0);
1149 } else {
1150 p = ctx->family;
1151 k = ctx->variant;
1152 again:
1153 if (p == SSFN_FAMILY_ANY) {
1154 n = 0;
1155 m = 4;
1156 } else
1157 n = m = p;
1158 for (; n <= m; n++) {
1159 fl = (ssfn_font_t **)ctx->fnt[n];
1160 if (ctx->style & 3) {
1161 /* check if we have a specific ctx->f for the requested style */
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))) {
1165 ctx->f = fl[i];
1166 break;
1167 }
1168 /* if bold italic was requested, check if we have at least bold or
1169 * italic */
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))) {
1173 ctx->f = fl[i];
1174 break;
1175 }
1176 }
1177 /* last resort, get the first ctx->f which has a glyph for this unicode,
1178 * no matter style */
1179 if (!rg) {
1180 for (i = 0; i < ctx->len[n]; i++)
1181 if ((rg = _ssfn_c(fl[i], unicode, k))) {
1182 ctx->f = fl[i];
1183 break;
1184 }
1185 }
1186 }
1187 /* if glyph still not found, try any family group, finally only default
1188 * variant */
1189 if (!rg) {
1190 if (p != SSFN_FAMILY_ANY) {
1191 p = SSFN_FAMILY_ANY;
1192 goto again;
1193 }
1194 if (k) {
1195 k = 0;
1196 goto again;
1197 }
1198 }
1199 }
1200 if (!rg) {
1201 ctx->err = ctx->variant ? SSFN_ERR_NOVARIANT : SSFN_ERR_NOGLYPH;
1202 return NULL;
1203 }
1204
1205 ctx->style &= 0xFF;
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;
1210
1211 ctx->g = 4 + ctx->f->quality;
1212 ctx->np = 0;
1213
1214 s = 16 - ctx->g;
1215 if (ctx->mode == SSFN_MODE_OUTLINE) {
1216 h = ctx->size;
1217 p = 0;
1218 } else {
1219 if (!(((rg[2] & 0x0F) << 8) | rg[6]) || ctx->style & SSFN_STYLE_ABS_SIZE)
1220 h = ctx->size;
1221 else
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));
1225 if (p > 255) {
1226 p = h = 255;
1227 if (ctx->style & 0x100) h -= 2;
1228 if (ctx->style & 0x200) h = h * 4 / 5;
1229 }
1230 if (ctx->mode == SSFN_MODE_BITMAP) p = (p + 7) >> 3;
1231 }
1232 ctx->m = h;
1233
1234 if (!ctx->h)
1235 ctx->h = (uint16_t *)SSFN_realloc(NULL, 4096 * 2 * sizeof(uint16_t));
1236 if (!ctx->h) goto erralloc;
1237
1238 if (!(ctx->style & SSFN_STYLE_NOHINTING)) {
1239 SSFN_memset(&ctx->h[4096], 0, 4096 * sizeof(uint16_t));
1240 _ssfn_g(ctx, rg, 0);
1241 } else
1242 ctx->h[4096] = 65535;
1243
1244 ctx->h[0] = 0;
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];
1247 j += y;
1248 if (j == x) {
1249 ctx->h[j] = (((j << 4) * h + (1 << 15)) >> 16) << 8;
1250 if (!y) j++;
1251 } else {
1252 y = _ssfn_g2o(y << 4);
1253 m += y;
1254 if ((i & 1) || y < 256) {
1255 continue;
1256 }
1257 m &= ~0xFF;
1258 n = ctx->h[x];
1259 for (l = 0; l + x <= j; l++) ctx->h[x + l] = n + ((m - n) * l / (j - x));
1260 }
1261 x = j;
1262 }
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;
1266
1267 bl = ((((rg[3] & 0x0F) << 8) | rg[8])) << s;
1268 bt = ((((rg[3] & 0xF0) << 4) | rg[9])) << s;
1269 i = p * h;
1270 ctx->ret = (ssfn_glyph_t *)SSFN_realloc(NULL, i + 8 + sizeof(uint8_t *));
1271 if (!ctx->ret) {
1272 erralloc:
1273 ctx->err = SSFN_ERR_ALLOC;
1274 return NULL;
1275 }
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;
1280 ctx->ret->w = 0;
1281 ctx->ret->h = h;
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);
1286
1287 ctx->ret->adv_x = ctx->uix;
1288 ctx->ret->adv_y = ctx->uax;
1289
1290 ctx->ix = ctx->uix = 4096 << 4;
1291 ctx->uax = 0;
1292 _ssfn_g(ctx, rg, 1);
1293
1294 if (!ctx->err) {
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) {
1298 ctx->ret = (ssfn_glyph_t *)SSFN_realloc(
1299 ctx->ret, ctx->np + 8 + sizeof(uint8_t *));
1300 if (!ctx->ret) goto erralloc;
1301 }
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;
1308 }
1309 }
1310 ctx->ret->pitch = s;
1311 ctx->ret =
1312 (ssfn_glyph_t *)SSFN_realloc(ctx->ret, s + 8 + sizeof(uint8_t *));
1313 if (!ctx->ret) goto erralloc;
1314 } else {
1315 _ssfn_r(ctx);
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;
1319 SSFN_memset(
1320 &ctx->ret->data[(ctx->ret->baseline - (ctx->size >> 2)) * p], 0xFF,
1321 (ctx->size / 64 + 2) * p);
1322 }
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);
1328 else
1329 ctx->uix = ctx->ret->w + 3;
1330 m = ctx->u * p;
1331 n = ctx->size > 127 ? 2 : 1;
1332 while (n--) {
1333 if (ctx->uix > 3) {
1334 j = ctx->uix - 3;
1335 if (ctx->mode == SSFN_MODE_BITMAP)
1336 for (i = 0; i < j; i++)
1337 ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1338 else
1339 SSFN_memset(&ctx->ret->data[m], 0xFF, j);
1340 }
1341 if (ctx->uax) {
1342 j = ctx->uax + 2;
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);
1346 else
1347 SSFN_memset(&ctx->ret->data[m + j], 0xFF, p - j);
1348 }
1349 m += p;
1350 }
1351 }
1352 }
1353 if (ctx->ret->adv_y) ctx->ret->baseline = ctx->ret->w >> 1;
1354 } else if (ctx->ret) {
1355 SSFN_free(ctx->ret);
1356 ctx->ret = NULL;
1357 }
1358 return ctx->ret;
1359}
1360
1371int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x,
1372 int *y) {
1373 const ssfn_font_t *font;
1374 uint32_t i, j, k, l, a, b, c;
1375 uint8_t *ptr;
1376 int m;
1377
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);
1390 ptr += 2;
1391 } else {
1392 i += ptr[0] & 0x3f;
1393 ptr++;
1394 }
1395 } else {
1396 m = ptr[0] & 0x7F;
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);
1402 ptr += 2;
1403 } else {
1404 k = ptr[0] & 0x7F;
1405 ptr++;
1406 }
1407 for (m = 0, a = SSFN_ERR_NOGLYPH, i = j = 0;
1408 i <= k && j <= nextunicode; i++) {
1409 if (b) {
1410 j = ptr[0] | (ptr[1] << 8) | ((ptr[2] & 0x7F) << 16);
1411 l = ptr[2] & 0x80;
1412 ptr += 3;
1413 } else {
1414 j = ptr[0] | ((ptr[1] & 0x7F) << 8);
1415 l = ptr[1] & 0x80;
1416 ptr += 2;
1417 }
1418 if (c) {
1419 m = (short)(ptr[0] | (ptr[1] << 8));
1420 ptr += 2;
1421 } else {
1422 m = (signed char)ptr[0];
1423 ptr++;
1424 }
1425 if (j == nextunicode) {
1426 a = SSFN_OK;
1427 m = (((m) << (16 - ctx->g)) * ctx->m + (1 << 16) - 1) >> 16;
1428 if (l)
1429 *y += m;
1430 else
1431 *x += m;
1432 }
1433 }
1434 return (ctx->err = a);
1435 }
1436 ptr += a;
1437 i += m;
1438 }
1439 }
1440 }
1441 return (ctx->err = SSFN_ERR_NOGLYPH);
1442}
1443
1454int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w, int *h) {
1455 char *s;
1456 int u, v, m;
1457
1458 if (!ctx) return SSFN_ERR_INVINP;
1459 if (!str || !w || !h) return (ctx->err = SSFN_ERR_INVINP);
1460 *w = *h = 0;
1461 m = ctx->mode;
1462 ctx->mode = SSFN_MODE_NONE;
1463 ctx->m = 0;
1464 for (s = str, u = ssfn_utf8(&s); u;) {
1465 ssfn_render(ctx, u);
1466 if (ctx->err == SSFN_OK) {
1467 *w += ctx->uix;
1468 *h += ctx->uax;
1469 }
1470 v = ssfn_utf8(&s);
1471 if (usekern) ssfn_kern(ctx, u, v, w, h);
1472 u = v;
1473 }
1474 if (!*w) *w = ctx->m;
1475 if (!*h) *h = ctx->m;
1476 ctx->mode = m;
1477 return ctx->err;
1478}
1479
1486int ssfn_mem(ssfn_t *ctx) {
1487 int i, ret = sizeof(ssfn_t);
1488
1489 if (!ctx) return 0;
1490
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);
1496 return ret;
1497}
1498
1504void ssfn_free(ssfn_t *ctx) {
1505 int i;
1506
1507 if (!ctx) return;
1508
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));
1516}
1517
1518#endif
1519
1520/*** this function goes for both renderers ***/
1521#if !defined(SSFN_NOIMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1522 defined(SSFN_CONSOLEBITMAP_HICOLOR) || \
1523 defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1531uint32_t ssfn_utf8(char **s) {
1532 uint32_t c = **s;
1533
1534 if ((**s & 128) != 0) {
1535 if (!(**s & 32)) {
1536 c = ((**s & 0x1F) << 6) | (*(*s + 1) & 0x3F);
1537 *s += 1;
1538 } else if (!(**s & 16)) {
1539 c = ((**s & 0xF) << 12) | ((*(*s + 1) & 0x3F) << 6) | (*(*s + 2) & 0x3F);
1540 *s += 2;
1541 } else if (!(**s & 8)) {
1542 c = ((**s & 0x7) << 18) | ((*(*s + 1) & 0x3F) << 12) |
1543 ((*(*s + 2) & 0x3F) << 6) | (*(*s + 3) & 0x3F);
1544 *s += 3;
1545 } else
1546 c = 0;
1547 }
1548 *s += 1;
1549 return c;
1550}
1551#endif
1552
1553#if defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1554 defined(SSFN_CONSOLEBITMAP_HICOLOR) || \
1555 defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1556/*** special console bitmap font renderer (ca. 1k, no dependencies, no memory
1557 * allocation and no error checking) ***/
1558
1562ssfn_font_t *ssfn_font; /* font buffer */
1563uint8_t *ssfn_dst_ptr; /* screen buffer */
1564uint32_t ssfn_dst_pitch; /* screen dimensions */
1565uint32_t ssfn_dst_w = 0;
1566uint32_t ssfn_dst_h = 0;
1567uint32_t ssfn_fg; /* colors in screen's native format */
1568#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1569uint32_t ssfn_bg;
1570#endif
1571uint32_t ssfn_x; /* coordinate to draw to */
1572uint32_t ssfn_y;
1573uint32_t ssfn_adv_x; /* advance values */
1574uint32_t ssfn_adv_y;
1575
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
1586 uint8_t w;
1587#endif
1588
1589 t = (ssfn_font->quality < 5 && ssfn_font->characters_offs[0] < 65536)
1590 ? 4
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;
1594
1595 for (j = i = 0; i < 0x110000; i++) {
1596 if (rg[0] & 0x80) {
1597 n = (rg[0] & 0x3f);
1598 if (rg[0] & 0x40) {
1599 i += rg[1] | (n << 8);
1600 rg++;
1601 } else {
1602 i += n;
1603 }
1604 rg++;
1605 } else {
1606 if (i == unicode) {
1607 y = rg[9];
1608#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1609 w = rg[4];
1610 j = 0;
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
1614 s += ssfn_x;
1615#else
1616#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1617 s += ssfn_x << 1;
1618#else
1619 s += ssfn_x << 2;
1620#endif
1621#endif
1622#endif
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;
1626 n = rg[0];
1627 ssfn_adv_x = rg[6];
1628 ssfn_adv_y = rg[7];
1629 rg += 10;
1630 while (n--) {
1631#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1632 s = ssfn_dst_ptr + (ssfn_y + y + rg[t - 1]) * ssfn_dst_pitch;
1633#ifdef SSFN_CONSOLEBITMAP_PALETTE
1634 s += ssfn_x;
1635#else
1636#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1637 s += ssfn_x << 1;
1638#else
1639 s += ssfn_x << 2;
1640#endif
1641#endif
1642#endif
1643 o = (uint8_t *)ssfn_font;
1644 a = ((rg[1] << 8) | rg[0]);
1645 switch (t) {
1646 case 4:
1647 o += a;
1648 break;
1649 case 5:
1650 o += ((rg[2] & 0xF) << 16) | a;
1651 break;
1652 default:
1653 o += ((rg[3] & 0xF) << 24) | (rg[2] << 16) | a;
1654 break;
1655 }
1656 p = ((o[0] & 0xF) + 1);
1657 a = p << 3;
1658 b = o[1] + 1;
1659 o += 2;
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;
1666 r++;
1667#else
1668#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1669 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1670 r += 2;
1671#else
1672 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1673 r += 4;
1674#endif
1675#endif
1676 }
1677 b += j;
1678#else
1679 j = 0;
1680#endif
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) {
1683 if (m > 0x80) {
1684 g++;
1685 m = 1;
1686 }
1687#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1688 if (*g & m)
1689#endif
1690#ifdef SSFN_CONSOLEBITMAP_PALETTE
1691 *((uint8_t *)r) = (uint8_t)(
1692#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1693 *g & m ? ssfn_fg : ssfn_bg
1694#else
1695 ssfn_bg
1696#endif
1697 );
1698 r++;
1699#else
1700#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1701 *((uint16_t *)r) = (uint16_t)(
1702#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1703 *g & m ? ssfn_fg : ssfn_bg
1704#else
1705 ssfn_fg
1706#endif
1707 );
1708 r += 2;
1709#else
1710 *((uint32_t *)r) = (uint32_t)(
1711#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1712 *g & m ? ssfn_fg : ssfn_bg
1713#else
1714 ssfn_fg
1715#endif
1716 );
1717 r += 4;
1718#endif
1719#endif
1720 }
1721 }
1722 rg += t;
1723 }
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;
1729 r++;
1730#else
1731#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1732 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1733 r += 2;
1734#else
1735 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1736 r += 4;
1737#endif
1738#endif
1739 }
1740#endif
1741 ssfn_x += ssfn_adv_x;
1742 ssfn_y += ssfn_adv_y;
1743 return SSFN_OK;
1744 }
1745 rg += rg[0] * t + 10;
1746 j++;
1747 }
1748 }
1749 return SSFN_ERR_NOGLYPH;
1750}
1751#endif
1752
1753#ifdef __cplusplus
1754}
1755#endif
1756
1757#endif
int ssfn_variant(ssfn_t *ctx, int variant)
Set glyph variant.
Definition ssfn.h:1116
int ssfn_mem(ssfn_t *ctx)
Returns how much memory a context consumes.
Definition ssfn.h:1484
void ssfn_free(ssfn_t *ctx)
Free renderer context.
Definition ssfn.h:1502
const char * ssfn_errstr[]
Error code strings.
Definition ssfn.h:284
int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size, int mode)
Set up rendering parameters.
Definition ssfn.h:1060
int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x, int *y)
Return kerning information.
Definition ssfn.h:1369
uint32_t ssfn_utf8(char **str)
Decode an UTF-8 multibyte, advance string pointer and return UNICODE.
Definition ssfn.h:1529
int ssfn_load(ssfn_t *ctx, const ssfn_font_t *font)
Load a font or font collection into renderer context.
Definition ssfn.h:1015
ssfn_glyph_t * ssfn_render(ssfn_t *ctx, uint32_t unicode)
Glyph renderer.
Definition ssfn.h:1131
int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w, int *h)
Returns the bounding box of the rendered text.
Definition ssfn.h:1452
Definition ssfn.h:181