OpenCPN Partial API docs
Loading...
Searching...
No Matches
ssfn.h
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 * @brief Scalable Screen Font renderer in a single ANSI C/C++ header
27 *
28 */
29
30#ifndef _SSFN_H_
31#define _SSFN_H_
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37/* if stdint.h was not included before us */
38#ifndef uint8_t
39typedef unsigned char uint8_t;
40typedef unsigned short int uint16_t;
41typedef unsigned int uint32_t;
42#endif
43
44/***** file format *****/
45
46/* magic bytes */
47#define SSFN_MAGIC "SSFN"
48#define SSFN_COLLECTION "SFNC"
49#define SSFN_ENDMAGIC "NFSS"
50
51/* font family group */
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
57
58/* font style flags */
59#define SSFN_STYLE_REGULAR 0
60#define SSFN_STYLE_BOLD 1
61#define SSFN_STYLE_ITALIC 2
62
63/* file format features */
64#define SSFN_FEAT_HASBMAP 1 /* there's at least one bitmap fragment */
65#define SSFN_FEAT_HASCMAP \
66 2 /* there's at least one pixmap fragment or one color command, so a color \
67 map too */
68#define SSFN_FEAT_HASHINT 4 /* there's at least one hinting fragment */
69#define SSFN_FEAT_KBIGLKP 8 /* big offsets in kerning look up table */
70#define SSFN_FEAT_KBIGCHR 16 /* big characters in kerning look up tables */
71#define SSFN_FEAT_KBIGCRD 32 /* big coordinates in kerning groups */
72#define SSFN_FEAT_HBIGCRD 64 /* bit coordinates in autohinting fragments */
73
74/* contour commands for vector fragments */
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
80
81/* bitmap and pixmap fragments and hinting grid info */
82#define SSFN_FRAG_BITMAP 0
83#define SSFN_FRAG_LBITMAP 1
84#define SSFN_FRAG_PIXMAP 2
85#define SSFN_FRAG_HINTING 3
86
87/* glyph variants */
88#define SSFN_VARIANT_DEFAULT 0 /* default, also isolated glyphs */
89#define SSFN_VARIANT_LOCAL0 0
90#define SSFN_VARIANT_INITIAL \
91 1 /* currently not needed because contextual glyphs has their own UNICODE \
92 code points, */
93#define SSFN_VARIANT_LOCAL1 \
94 1 /* so its only purpose is to store Serbian / Macedonian B D G P T */
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
104/* main SSFN header */
105typedef struct {
106 uint8_t magic[4]; /* SSFN magic bytes */
107 uint32_t size; /* total size in bytes */
108 uint8_t family; /* font family group */
109 uint8_t style; /* font style, zero or OR'd SSFN_STYLE_BOLD and
110 SSFN_STYLE_ITALIC */
111 uint8_t quality; /* quality, defines grid size, 0 - 8 */
112 uint8_t features; /* feature flags, OR'd SSFN_FEAT_* */
113 uint8_t revision; /* format revision, must be zero */
114 uint8_t reserved0; /* must be zero */
115 uint16_t reserved1;
116 uint16_t baseline; /* horizontal baseline in grid pixels */
117 uint16_t underline; /* position of under line in grid pixels */
118 uint16_t bbox_left; /* overall bounding box for all glyphs in grid pixels */
119 uint16_t bbox_top;
120 uint16_t bbox_right;
121 uint16_t bbox_bottom;
122 uint32_t fragments_offs; /* offset of fragments table relative to magic */
123 uint32_t characters_offs[SSFN_NUMVARIANTS]; /* offset of characters tables per
124 variant relative to magic */
125 uint32_t kerning_offs; /* kerning table offset relative to magic */
127
128/***** renderer API *****/
129#define SSFN_FAMILY_ANY 0xff /* select the first loaded font */
130#define SSFN_FAMILY_BYNAME 0xfe /* select font by its unique name */
131
132#define SSFN_STYLE_UNDERLINE 4 /* under line glyph */
133#define SSFN_STYLE_STHROUGH 8 /* strike through glyph */
134#define SSFN_STYLE_NOHINTING 0x40 /* no auto hinting grid */
135#define SSFN_STYLE_ABS_SIZE 0x80 /* use absolute size value */
136
137#define SSFN_FRAG_CONTOUR 255
138
139/* error codes */
140#define SSFN_OK 0 /* success */
141#define SSFN_ERR_ALLOC 1 /* allocation error */
142#define SSFN_ERR_NOFACE 2 /* no font face selected */
143#define SSFN_ERR_INVINP 3 /* invalid input */
144#define SSFN_ERR_BADFILE 4 /* bad SSFN file format */
145#define SSFN_ERR_BADSTYLE 5 /* bad style */
146#define SSFN_ERR_BADSIZE 6 /* bad size */
147#define SSFN_ERR_BADMODE 7 /* bad mode */
148#define SSFN_ERR_NOGLYPH 8 /* glyph (or kerning info) not found */
149#define SSFN_ERR_NOVARIANT 9 /* no such glyph variant */
150
151/* rendering modes */
152#define SSFN_MODE_NONE \
153 0 /* just select the font to get the glyph (for kerning) */
154#define SSFN_MODE_OUTLINE 1 /* return the glyph's outlines */
155#define SSFN_MODE_BITMAP 2 /* render into bitmap */
156#define SSFN_MODE_ALPHA 3 /* render into alpha channel */
157#define SSFN_MODE_CMAP 4 /* render into color map indexed buffer */
158
159/* grid fitting */
160#define SSFN_HINTING_THRESHOLD \
161 16 /* don't change unless you really know what you're doing */
162
163/* returned bitmap struct */
164#define SSFN_DATA_MAX 65536
165typedef struct {
166 uint8_t mode; /* returned glyph's data format */
167 uint8_t baseline; /* baseline of glyph, scaled to size */
168 uint8_t w; /* width */
169 uint8_t h; /* height */
170 uint8_t adv_x; /* advance x */
171 uint8_t adv_y; /* advance y */
172 uint16_t pitch; /* data buffer bytes per line */
173 uint32_t *cmap; /* pointer to color map */
174 uint8_t data[SSFN_DATA_MAX]; /* data buffer */
177/* renderer context */
178typedef struct {
179 const ssfn_font_t **fnt[5]; /* font registry */
180 const ssfn_font_t *s; /* explicitly selected font */
181 const ssfn_font_t *f; /* font selected by best match */
182 ssfn_glyph_t *ret; /* glyph to return */
183 uint16_t *p; /* outline points */
184 uint16_t *r[256]; /* raster for scanlines */
185 uint16_t *h; /* auto hinting grid */
186 int len[5]; /* number of fonts in registry */
187 int mp; /* memory allocated for points */
188 int np; /* how many points actually are there */
189 int nr[256]; /* number of coordinates in each raster line */
190 int err; /* returned error code */
191 int family; /* required family */
192 int style; /* required style */
193 int size; /* required size */
194 int mode; /* required mode */
195 int variant; /* required variant */
196 int g; /* shift value for grid size */
197 int m, ix, u, uix, uax, lx, ly, mx, my; /* helper variables */
198} ssfn_t;
199
200/***** API function protoypes *****/
201
202/* normal renderer */
203int ssfn_load(ssfn_t *ctx,
204 const ssfn_font_t *font); /* add an SSFN to context */
205int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size,
206 int mode); /* select font to use */
207int ssfn_variant(ssfn_t *ctx,
208 int variant); /* select glyph variant (optional) */
209uint32_t ssfn_utf8(char **str); /* decode UTF-8 sequence */
210ssfn_glyph_t *ssfn_render(ssfn_t *ctx,
211 uint32_t unicode); /* return allocated glyph bitmap */
212int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x,
213 int *y); /* get kerning values */
214int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w,
215 int *h); /* get bounding box of a rendered string */
216int ssfn_mem(ssfn_t *ctx); /* return how much memory is used */
217void ssfn_free(ssfn_t *ctx); /* free context */
218#define ssfn_lasterr(ctx) ((ssfn_t *)ctx)->err /* return last error code */
219#define ssfn_error(err) \
220 (err >= 0 && err <= 9 ? ssfn_errstr[err] \
221 : "Unknown error") /* return string for error code */
222extern const char *ssfn_errstr[];
223
224/* simple renderer */
225int ssfn_putc(uint32_t unicode); /* render console bitmap font */
226
227/***** renderer implementations *****/
228
229#ifndef SSFN_NOIMPLEMENTATION
230/*** normal renderer (ca. 22k, fully featured with error checking) ***/
231
232#ifndef NULL
233#define NULL (void *)0
234#endif
235// # ifndef size_t
236// typedef __SIZE_TYPE__ size_t;
237// # endif
238#ifndef ssfn_private
239#define ssfn_private
240#endif
241// # ifndef inline
242// # define inline __inline__
243// # endif
244
245/* Clang does not have built-in versions of these but gcc has */
246#ifndef SSFN_memcmp
247#ifdef __builtin_memcmp
248#define SSFN_memcmp __builtin_memcmp
249#else
250#define SSFN_memcmp memcmp
251#endif
252#endif
253
254#ifndef SSFN_memset
255#ifdef __builtin_memset
256#define SSFN_memset __builtin_memset
257#else
258#define SSFN_memset memset
259#endif
260#endif
261
262#ifndef SSFN_realloc
263#ifdef __builtin_realloc
264#define SSFN_realloc __builtin_realloc
265#else
266#define SSFN_realloc realloc
267#endif
268#endif
269
270#ifndef SSFN_free
271#ifdef __builtin_free
272#define SSFN_free __builtin_free
273#else
274#define SSFN_free free
275#endif
276#endif
277
281const char *ssfn_errstr[] = {"",
282 "Memory allocation error",
283 "No font face found",
284 "Invalid input value",
285 "Bad file format",
286 "Invalid style",
287 "Invalid size",
288 "Invalid mode",
289 "Glyph not found",
290 "Glyph variant not found"};
291
292/*** Private functions ***/
293/* f = file scale, g = grid 4095.15, o = screen point 255.255, i = screen pixel
294 * 255, c = ceil */
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))
313
314/* parse character table */
315ssfn_private uint8_t *_ssfn_c(const ssfn_font_t *font, uint32_t unicode,
316 int v) {
317 uint32_t i, j, l;
318 uint8_t *ptr;
319
320 if (!font->characters_offs[v]) return NULL;
321
322 ptr = (uint8_t *)font + font->characters_offs[v];
323 l = (font->quality < 5 && font->characters_offs[v] < 65536)
324 ? 4
325 : (font->characters_offs[v] < 1048576 ? 5 : 6);
326
327 for (j = i = 0; i < 0x110000; i++) {
328 if (ptr[0] & 0x80) {
329 if (ptr[0] & 0x40) {
330 i += ptr[1] | ((ptr[0] & 0x3f) << 8);
331 ptr += 2;
332 } else {
333 i += ptr[0] & 0x3f;
334 ptr++;
335 }
336 } else {
337 if (i == unicode) return ptr;
338 ptr += ptr[0] * l + 10;
339 j++;
340 }
341 }
342 return NULL;
343}
344
345/* add a line to contour */
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;
350
351 if (ctx->np + 2 >= ctx->mp) {
352 ctx->mp += 512;
353 ctx->p = (uint16_t *)SSFN_realloc(ctx->p, ctx->mp * sizeof(uint16_t));
354 if (!ctx->p) {
355 ctx->err = SSFN_ERR_ALLOC;
356 return;
357 }
358 }
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;
363 ctx->lx = x;
364 ctx->ly = y;
365 }
366 if ((ctx->style & 0x200) && x >= 0 && ctx->ix > x) ctx->ix = x;
367}
368
369/* add a Bezier curve to contour */
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);
388 }
389 _ssfn_l(ctx, x3, y3, l);
390}
391
392/* rasterize contour */
393ssfn_private void _ssfn_r(ssfn_t *ctx) {
394 int i, k, l, m, n = 0, x, y, Y, M = 0;
395 uint16_t *r;
396 uint8_t *pix = ctx->ret->data;
397
398 for (y = 0; y < ctx->ret->h; y++) {
399 Y = _ssfn_i2g(y);
400 r = ctx->r[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))
404 continue;
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);
409 else
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]));
413 if (y == ctx->u) {
414 if (x < ctx->uix) {
415 ctx->uix = x;
416 }
417 if (x > ctx->uax) {
418 ctx->uax = x;
419 }
420 }
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));
426 if (!ctx->r[y]) {
427 ctx->err = SSFN_ERR_ALLOC;
428 return;
429 }
430 r = ctx->r[y];
431 }
432 for (l = n; l > k; l--) r[l] = r[l - 1];
433 r[k] = x;
434 n++;
435 }
436 }
437 if (n > 1 && n & 1) {
438 r[n - 2] = r[n - 1];
439 n--;
440 }
441 ctx->nr[y] = n;
442 if (n) {
443 if (y > M) M = y;
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;
453 else
454 r[i] += 256;
455 if (r[i + 1] - 256 > r[i]) r[i + 1] -= 256;
456 } else {
457 if (i >= n - 2 || r[i + 1] + 256 < r[i + 2]) r[i + 1] += 256;
458 }
459 }
460 l = ((r[i] + 128) >> 8);
461 m = ((r[i + 1] + 128) >> 8);
462 if (ctx->mode != SSFN_MODE_BITMAP && l + 1 < m) l++;
463 for (; l < m; l++) {
464 switch (ctx->mode) {
465 case SSFN_MODE_BITMAP:
466 pix[k + (l >> 3)] ^= 1 << (l & 7);
467 break;
468 case SSFN_MODE_ALPHA:
469 pix[k + l] ^= 0xFF;
470 break;
471 case SSFN_MODE_CMAP:
472 pix[k + l] ^= 0x0F;
473 break;
474 }
475 }
476 if (l + 1 > ctx->ret->w) ctx->ret->w = l + 1;
477 }
478 }
479 }
480 /* fix rounding errors */
481 if (M + 1 == ctx->ret->baseline) {
482 ctx->ret->baseline--;
483 ctx->u--;
484 }
485}
486
487/* anti-alias a contour */
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;
491 uint16_t *r;
492
493 if (ctx->mode < SSFN_MODE_ALPHA || !ctx->p || ctx->np < 4) return;
494
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);
500 if (e == 127)
501 e = 255;
502 else {
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];
505 }
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;
512 }
513 }
514 }
515
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))
519 continue;
520
521 x0 = ctx->p[i] - ctx->ix;
522 y0 = ctx->p[i + 1];
523 x1 = ctx->p[i + 2] - ctx->ix;
524 y1 = ctx->p[i + 3];
525 sx = x1 >= x0 ? 1 : -1;
526 sy = y1 >= y0 ? 1 : -1;
527 dx = x1 - x0;
528 dy = y1 - y0;
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));
532 y += 128;
533 e = ~(y & 0xFF);
534 y >>= 8;
535 e >>= 1;
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;
539 }
540 }
541 }
542}
543
544/* parse a glyph */
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;
548
549 ctx->lx = ctx->ly = ctx->mx = ctx->my = -1;
550 ol = (ctx->f->quality < 5 && ctx->f->characters_offs[ctx->variant] < 65536)
551 ? 4
552 : ((ctx->f->characters_offs[ctx->variant] < 1048576) ? 5 : 6);
553 s = 16 - ctx->g;
554 nf = rg[0];
555 rg += 10;
556
557 for (h = 0; nf-- && !ctx->err; rg += ol) {
558 switch (ol) {
559 case 4:
560 o = ((rg[1] << 8) | rg[0]);
561 ox = rg[2];
562 oy = rg[3];
563 break;
564 case 5:
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];
568 break;
569 default:
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];
573 break;
574 }
575 ox <<= s;
576 oy <<= s;
577 raw = (uint8_t *)ctx->f + o;
578 if (raw[0] & 0x80) {
579 t = (raw[0] & 0x60) >> 5;
580 if (!render && t != SSFN_FRAG_HINTING) break;
581 switch (t) {
582 case SSFN_FRAG_LBITMAP:
583 x = ((((raw[0] >> 2) & 3) << 8) + raw[1]) + 1;
584 y = (((raw[0] & 3) << 8) | raw[2]) + 1;
585 raw += 3;
586 goto bitmap;
587
588 case SSFN_FRAG_BITMAP:
589 x = (raw[0] & 0x1F) + 1;
590 y = raw[1] + 1;
591 raw += 2;
592 bitmap:
593 if (ctx->mode == SSFN_MODE_OUTLINE) {
594 x <<= 3;
595 outline:
596 ctx->lx = ctx->ly = -1;
597 x <<= s;
598 y <<= s;
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;
603 } else
604 a = b = 0;
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);
611 } else {
612 a = x << 3;
613 b = y << s;
614 c = _ssfn_g2i(oy);
615 n = _ssfn_g2i(ox);
616 w = _ssfn_g2i(x << (3 + s));
617 h = _ssfn_g2i(b);
618 if (c + h >= ctx->ret->h) c = ctx->ret->h - h; /* due to rounding */
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))) {
625 d = n +
626 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
627 : 0) +
628 i;
629 switch (ctx->mode) {
630 case SSFN_MODE_BITMAP:
631 pix[c + (d >> 3)] |= 1 << (d & 7);
632 d++;
633 if ((ctx->style & 0x100) && (d >> 3) < ctx->ret->pitch) {
634 pix[c + (d >> 3)] |= 1 << (d & 7);
635 d++;
636 if (ctx->size > 127 && (d >> 3) < ctx->ret->pitch) {
637 pix[c + (d >> 3)] |= 1 << (d & 7);
638 }
639 }
640 break;
641 case SSFN_MODE_CMAP:
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) {
647 pix[c + d] = 0xFF;
648 }
649 }
650 break;
651 }
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) {
656 if (d < ctx->uix) {
657 ctx->uix = d;
658 }
659 if (d > ctx->uax) {
660 ctx->uax = d;
661 }
662 }
663 }
664 }
665 c += ctx->ret->pitch;
666 }
667 if (ctx->mode != SSFN_MODE_BITMAP && h > y && w > 1) {
668 m = (ctx->mode == SSFN_MODE_CMAP) ? 0xF0 : 0;
669 x = h / y;
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++) {
676 d = n +
677 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s)) : 0) +
678 i;
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))
683 pix[c + d] = b;
684 }
685 c += ctx->ret->pitch;
686 }
687 }
688 }
689 }
690 h = 0;
691 break;
692
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;
697 raw += 5;
698 if (ctx->mode == SSFN_MODE_OUTLINE) goto outline;
699 if (raw[-5] & 0x10) {
700 /* todo: direct ARGB values in pixmap fragment */
701 }
702 a = x * y;
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));
706 if (!ctx->r[0]) {
707 ctx->err = SSFN_ERR_ALLOC;
708 return;
709 }
710 }
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;
715 if (raw[0] & 0x80) {
716 for (j = 0; j < c; j++) ra[i++] = raw[1];
717 raw += 2;
718 } else {
719 raw++;
720 for (j = 0; j < c; j++) ra[i++] = *raw++;
721 }
722 }
723 b = y << s;
724 c = _ssfn_g2i(oy);
725 n = _ssfn_g2i(ox);
726 w = _ssfn_g2i(x << s);
727 h = _ssfn_g2i(b);
728 if (c + h >= ctx->ret->h) c = ctx->ret->h - h; /* due to rounding */
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) {
735 d = n +
736 ((ctx->style & 0x200) ? _ssfn_igi(oy + (j << s) + 127)
737 : 0) +
738 i;
739 re = (uint8_t *)&ctx->ret->cmap[ra[o + m]];
740 a = (re[0] + re[1] + re[2] + 255) >> 2;
741 switch (ctx->mode) {
742 case SSFN_MODE_BITMAP:
743 if (a > 127) pix[c + (d >> 3)] |= 1 << (d & 7);
744 break;
745 case SSFN_MODE_CMAP:
746 pix[c + d] = ra[o + m];
747 break;
748 case SSFN_MODE_ALPHA:
749 a >>= 1;
750 a = ~a;
751 pix[c + d] = a;
752 break;
753 }
754 if (d > ctx->ret->w) ctx->ret->w = d;
755 }
756 }
757 c += ctx->ret->pitch;
758 }
759 h = 0;
760 break;
761
762 case SSFN_FRAG_HINTING:
763 if (raw[0] & 0x10) {
764 n = ((raw[0] & 0xF) << 8) | raw[1];
765 raw += 2;
766 } else {
767 n = raw[0] & 0xF;
768 raw++;
769 }
770 if (render || !ox) {
771 raw += n << (ctx->f->features & SSFN_FEAT_HBIGCRD ? 1 : 0);
772 continue;
773 }
774 y = 4096;
775 x = ((ox >> s) - 1) << (s - 4);
776 ctx->h[y++] = x;
777 for (n++; n-- && x < 4096;) {
778 x = raw[0];
779 raw++;
780 if (ctx->f->features & SSFN_FEAT_HBIGCRD) {
781 x |= (raw[0] << 8);
782 raw++;
783 }
784 x <<= (s - 4);
785 ctx->h[y++] = x;
786 }
787 if (y < 4096) ctx->h[y++] = 65535;
788 h = 1;
789 break;
790 }
791 } else {
792 if (!render && h) break;
793 if (raw[0] & 0x40) {
794 n = ((raw[0] & 0x3F) << 8) | raw[1];
795 raw += 2;
796 } else {
797 n = raw[0] & 0x3F;
798 raw++;
799 }
800 if (ctx->f->quality < 5) {
801 x = raw[0];
802 y = raw[1];
803 raw += 2;
804 } else {
805 x = ((raw[0] & 3) << 8) | raw[1];
806 y = ((raw[0] & 0x30) << 4) | raw[2];
807 raw += 3;
808 }
809 x <<= s;
810 y <<= s;
811 y += oy;
812 x += ox + (ctx->style & 0x200 ? _ssfn_igg(y) : 0);
813 if (render) {
814 if (ctx->np) {
815 _ssfn_l(ctx, ctx->mx, ctx->my, 0);
816 _ssfn_l(ctx, -1, -1, 0);
817 }
818 _ssfn_l(ctx, x, y, 0);
819 }
820 ctx->lx = ctx->mx = x;
821 ctx->ly = ctx->my = y;
822 for (n++; n--;) {
823 t = ctx->g < 8 ? (raw[0] >> 7) | ((raw[1] >> 6) & 2) : raw[0] & 3;
824 x = y = a = b = c = d = j = 0;
825 switch (ctx->g) {
826 case 4:
827 case 5:
828 case 6:
829 case 7:
830 x = raw[0] & 0x7F;
831 y = raw[1] & 0x7F;
832 switch (t) {
833 case 0:
834 raw += raw[0] & 4 ? 5 : 2;
835 break;
836 case 1:
837 raw += 2;
838 break;
839 case 2:
840 a = raw[2] & 0x7F;
841 b = raw[3] & 0x7F;
842 raw += 4;
843 break;
844 case 3:
845 a = raw[2] & 0x7F;
846 b = raw[3] & 0x7F;
847 c = raw[4] & 0x7F;
848 d = raw[5] & 0x7F;
849 raw += 6;
850 break;
851 }
852 break;
853
854 case 8:
855 x = raw[1];
856 y = raw[2];
857 switch (t) {
858 case 0:
859 raw += raw[0] & 4 ? 5 : 2;
860 break;
861 case 1:
862 raw += 3;
863 break;
864 case 2:
865 a = raw[3];
866 b = raw[4];
867 raw += 5;
868 break;
869 case 3:
870 a = raw[3];
871 b = raw[4];
872 c = raw[5];
873 d = raw[6];
874 raw += 7;
875 break;
876 }
877 break;
878
879 case 9:
880 x = ((raw[0] & 4) << 6) | raw[1];
881 y = ((raw[0] & 8) << 5) | raw[2];
882 switch (t) {
883 case 0:
884 raw += raw[0] & 4 ? 5 : 2;
885 break;
886 case 1:
887 raw += 3;
888 break;
889 case 2:
890 a = ((raw[0] & 16) << 4) | raw[3];
891 b = ((raw[0] & 32) << 3) | raw[4];
892 raw += 5;
893 break;
894 case 3:
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];
899 raw += 7;
900 break;
901 }
902 break;
903
904 default:
905 x = ((raw[0] & 12) << 6) | raw[1];
906 y = ((raw[0] & 48) << 4) | raw[2];
907 switch (t) {
908 case 0:
909 raw += raw[0] & 4 ? 5 : 2;
910 break;
911 case 1:
912 raw += 3;
913 break;
914 case 2:
915 a = ((raw[3] & 3) << 8) | raw[4];
916 b = ((raw[3] & 12) << 6) | raw[5];
917 raw += 6;
918 break;
919 case 3:
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];
924 raw += 8;
925 break;
926 }
927 break;
928 }
929 x <<= s;
930 y <<= s;
931 a <<= s;
932 b <<= s;
933 c <<= s;
934 d <<= s;
935 x += ox;
936 y += oy;
937 a += ox;
938 b += oy;
939 c += ox;
940 d += oy;
941 if (ctx->style & 0x200) {
942 x += _ssfn_igg(y);
943 a += _ssfn_igg(b);
944 c += _ssfn_igg(d);
945 }
946 if (render) {
947 switch (t) {
948 case 0: /* this v1.0 renderer does not support colored contours */
949 break;
950 case 1:
951 _ssfn_l(ctx, x, y, 0);
952 break;
953 case 2:
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);
957 break;
958 case 3:
959 _ssfn_b(ctx, ctx->lx, ctx->ly, a, b, c, d, x, y, 0);
960 break;
961 }
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;
966 if (a < 2)
967 ctx->h[4096 + (!ctx->h[4096 + c] && c && ctx->h[4096 + c - 1]
968 ? c - 1
969 : c)] += b;
970 }
971 ctx->lx = x;
972 ctx->ly = y;
973 }
974 }
975 }
976
977 if (!render && !h) {
978 for (j = m = x = y = 0; j < 4096; j++) {
979 if (ctx->h[4096 + j] >= 4096 / SSFN_HINTING_THRESHOLD) {
980 if (!j)
981 m++;
982 else {
983 ctx->h[4096 + m++] = j - x;
984 x = j;
985 }
986 }
987 }
988 if (m < 4096) ctx->h[4096 + m] = 65535;
989 }
990}
991
992/*** public API implementation ***/
993
1002#define SSFN_CMAP_TO_ARGB(p, c, fg) \
1003 (p >= 0xF0 ? (uint32_t)((p << 28) | ((p & 0xF) << 24) | fg) : c[p])
1004
1012int ssfn_load(ssfn_t *ctx, const ssfn_font_t *font) {
1013 ssfn_font_t *ptr, *end;
1014
1015 if (!ctx || !font) {
1016 if (ctx) ctx->err = SSFN_ERR_INVINP;
1017 return SSFN_ERR_INVINP;
1018 }
1019 ctx->err = SSFN_OK;
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);
1025 } else {
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;
1033 } else {
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;
1039 else
1040 ctx->fnt[font->family][ctx->len[font->family] - 1] = font;
1041 }
1042 }
1043 return ctx->err;
1044}
1045
1057int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size,
1058 int mode) {
1059 int i, j, l;
1060
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);
1065
1066 if (family == SSFN_FAMILY_BYNAME) {
1067 if (!name || !name[0]) {
1068 invinp:
1069 return (ctx->err = SSFN_ERR_INVINP);
1070 }
1071 for (l = 0; name[l]; l++);
1072 for (i = 0; i < 5; i++) {
1073 for (j = 0; j < ctx->len[i]; j++) {
1074 if (!SSFN_memcmp(
1075 name, (uint8_t *)&ctx->fnt[i][j]->magic + sizeof(ssfn_font_t),
1076 l)) {
1077 ctx->s = ctx->fnt[i][j];
1078 goto familyfound;
1079 }
1080 }
1081 }
1082 noface:
1083 return (ctx->err = SSFN_ERR_NOFACE);
1084 } else {
1085 if (family != SSFN_FAMILY_ANY) {
1086 if (family > SSFN_FAMILY_HAND) goto invinp;
1087 if (!ctx->len[family]) goto noface;
1088 }
1089 ctx->s = NULL;
1090 }
1091familyfound:
1092 ctx->np = ctx->mp = 0;
1093 if (ctx->p) {
1094 SSFN_free(ctx->p);
1095 ctx->p = NULL;
1096 }
1097 ctx->f = NULL;
1098 ctx->family = family;
1099 ctx->style = style;
1100 ctx->size = size;
1101 ctx->mode = mode;
1102 ctx->variant = 0;
1103 return (ctx->err = SSFN_OK);
1104}
1105
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);
1119}
1120
1128ssfn_glyph_t *ssfn_render(ssfn_t *ctx, uint32_t unicode) {
1129 ssfn_font_t **fl;
1130 int i, j, s, h, p, m, n, bt, bl;
1131 int l, k, x, y;
1132 uint8_t *rg = NULL, c, d;
1133
1134 if (!ctx) return NULL;
1135 if (ctx->size < 8) {
1136 ctx->err = SSFN_ERR_NOFACE;
1137 return NULL;
1138 }
1139 ctx->err = SSFN_OK;
1140 if (ctx->s) {
1141 ctx->f = (ssfn_font_t *)ctx->s;
1142 rg = _ssfn_c(ctx->f, unicode, ctx->variant);
1143 if (!rg) rg = _ssfn_c(ctx->f, unicode, 0);
1144 } else {
1145 p = ctx->family;
1146 k = ctx->variant;
1147 again:
1148 if (p == SSFN_FAMILY_ANY) {
1149 n = 0;
1150 m = 4;
1151 } else
1152 n = m = p;
1153 for (; n <= m; n++) {
1154 fl = (ssfn_font_t **)ctx->fnt[n];
1155 if (ctx->style & 3) {
1156 /* check if we have a specific ctx->f for the requested style */
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))) {
1160 ctx->f = fl[i];
1161 break;
1162 }
1163 /* if bold italic was requested, check if we have at least bold or
1164 * italic */
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))) {
1168 ctx->f = fl[i];
1169 break;
1170 }
1171 }
1172 /* last resort, get the first ctx->f which has a glyph for this unicode,
1173 * no matter style */
1174 if (!rg) {
1175 for (i = 0; i < ctx->len[n]; i++)
1176 if ((rg = _ssfn_c(fl[i], unicode, k))) {
1177 ctx->f = fl[i];
1178 break;
1179 }
1180 }
1181 }
1182 /* if glyph still not found, try any family group, finally only default
1183 * variant */
1184 if (!rg) {
1185 if (p != SSFN_FAMILY_ANY) {
1186 p = SSFN_FAMILY_ANY;
1187 goto again;
1188 }
1189 if (k) {
1190 k = 0;
1191 goto again;
1192 }
1193 }
1194 }
1195 if (!rg) {
1196 ctx->err = ctx->variant ? SSFN_ERR_NOVARIANT : SSFN_ERR_NOGLYPH;
1197 return NULL;
1198 }
1199
1200 ctx->style &= 0xFF;
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;
1205
1206 ctx->g = 4 + ctx->f->quality;
1207 ctx->np = 0;
1208
1209 s = 16 - ctx->g;
1210 if (ctx->mode == SSFN_MODE_OUTLINE) {
1211 h = ctx->size;
1212 p = 0;
1213 } else {
1214 if (!(((rg[2] & 0x0F) << 8) | rg[6]) || ctx->style & SSFN_STYLE_ABS_SIZE)
1215 h = ctx->size;
1216 else
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));
1220 if (p > 255) {
1221 p = h = 255;
1222 if (ctx->style & 0x100) h -= 2;
1223 if (ctx->style & 0x200) h = h * 4 / 5;
1224 }
1225 if (ctx->mode == SSFN_MODE_BITMAP) p = (p + 7) >> 3;
1226 }
1227 ctx->m = h;
1228
1229 if (!ctx->h)
1230 ctx->h = (uint16_t *)SSFN_realloc(NULL, 4096 * 2 * sizeof(uint16_t));
1231 if (!ctx->h) goto erralloc;
1232
1233 if (!(ctx->style & SSFN_STYLE_NOHINTING)) {
1234 SSFN_memset(&ctx->h[4096], 0, 4096 * sizeof(uint16_t));
1235 _ssfn_g(ctx, rg, 0);
1236 } else
1237 ctx->h[4096] = 65535;
1238
1239 ctx->h[0] = 0;
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];
1242 j += y;
1243 if (j == x) {
1244 ctx->h[j] = (((j << 4) * h + (1 << 15)) >> 16) << 8;
1245 if (!y) j++;
1246 } else {
1247 y = _ssfn_g2o(y << 4);
1248 m += y;
1249 if ((i & 1) || y < 256) {
1250 continue;
1251 }
1252 m &= ~0xFF;
1253 n = ctx->h[x];
1254 for (l = 0; l + x <= j; l++) ctx->h[x + l] = n + ((m - n) * l / (j - x));
1255 }
1256 x = j;
1257 }
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;
1261
1262 bl = ((((rg[3] & 0x0F) << 8) | rg[8])) << s;
1263 bt = ((((rg[3] & 0xF0) << 4) | rg[9])) << s;
1264 i = p * h;
1265 ctx->ret = (ssfn_glyph_t *)SSFN_realloc(NULL, i + 8 + sizeof(uint8_t *));
1266 if (!ctx->ret) {
1267 erralloc:
1268 ctx->err = SSFN_ERR_ALLOC;
1269 return NULL;
1270 }
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;
1275 ctx->ret->w = 0;
1276 ctx->ret->h = h;
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);
1281
1282 ctx->ret->adv_x = ctx->uix;
1283 ctx->ret->adv_y = ctx->uax;
1284
1285 ctx->ix = ctx->uix = 4096 << 4;
1286 ctx->uax = 0;
1287 _ssfn_g(ctx, rg, 1);
1288
1289 if (!ctx->err) {
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) {
1293 ctx->ret = (ssfn_glyph_t *)SSFN_realloc(
1294 ctx->ret, ctx->np + 8 + sizeof(uint8_t *));
1295 if (!ctx->ret) goto erralloc;
1296 }
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;
1303 }
1304 }
1305 ctx->ret->pitch = s;
1306 ctx->ret =
1307 (ssfn_glyph_t *)SSFN_realloc(ctx->ret, s + 8 + sizeof(uint8_t *));
1308 if (!ctx->ret) goto erralloc;
1309 } else {
1310 _ssfn_r(ctx);
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;
1314 SSFN_memset(
1315 &ctx->ret->data[(ctx->ret->baseline - (ctx->size >> 2)) * p], 0xFF,
1316 (ctx->size / 64 + 2) * p);
1317 }
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);
1323 else
1324 ctx->uix = ctx->ret->w + 3;
1325 m = ctx->u * p;
1326 n = ctx->size > 127 ? 2 : 1;
1327 while (n--) {
1328 if (ctx->uix > 3) {
1329 j = ctx->uix - 3;
1330 if (ctx->mode == SSFN_MODE_BITMAP)
1331 for (i = 0; i < j; i++)
1332 ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1333 else
1334 SSFN_memset(&ctx->ret->data[m], 0xFF, j);
1335 }
1336 if (ctx->uax) {
1337 j = ctx->uax + 2;
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);
1341 else
1342 SSFN_memset(&ctx->ret->data[m + j], 0xFF, p - j);
1343 }
1344 m += p;
1345 }
1346 }
1347 }
1348 if (ctx->ret->adv_y) ctx->ret->baseline = ctx->ret->w >> 1;
1349 } else if (ctx->ret) {
1350 SSFN_free(ctx->ret);
1351 ctx->ret = NULL;
1352 }
1353 return ctx->ret;
1354}
1355
1366int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x,
1367 int *y) {
1368 const ssfn_font_t *font;
1369 uint32_t i, j, k, l, a, b, c;
1370 uint8_t *ptr;
1371 int m;
1372
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);
1385 ptr += 2;
1386 } else {
1387 i += ptr[0] & 0x3f;
1388 ptr++;
1389 }
1390 } else {
1391 m = ptr[0] & 0x7F;
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);
1397 ptr += 2;
1398 } else {
1399 k = ptr[0] & 0x7F;
1400 ptr++;
1401 }
1402 for (m = 0, a = SSFN_ERR_NOGLYPH, i = j = 0;
1403 i <= k && j <= nextunicode; i++) {
1404 if (b) {
1405 j = ptr[0] | (ptr[1] << 8) | ((ptr[2] & 0x7F) << 16);
1406 l = ptr[2] & 0x80;
1407 ptr += 3;
1408 } else {
1409 j = ptr[0] | ((ptr[1] & 0x7F) << 8);
1410 l = ptr[1] & 0x80;
1411 ptr += 2;
1412 }
1413 if (c) {
1414 m = (short)(ptr[0] | (ptr[1] << 8));
1415 ptr += 2;
1416 } else {
1417 m = (signed char)ptr[0];
1418 ptr++;
1419 }
1420 if (j == nextunicode) {
1421 a = SSFN_OK;
1422 m = (((m) << (16 - ctx->g)) * ctx->m + (1 << 16) - 1) >> 16;
1423 if (l)
1424 *y += m;
1425 else
1426 *x += m;
1427 }
1428 }
1429 return (ctx->err = a);
1430 }
1431 ptr += a;
1432 i += m;
1433 }
1434 }
1435 }
1436 return (ctx->err = SSFN_ERR_NOGLYPH);
1437}
1438
1449int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w, int *h) {
1450 char *s;
1451 int u, v, m;
1452
1453 if (!ctx) return SSFN_ERR_INVINP;
1454 if (!str || !w || !h) return (ctx->err = SSFN_ERR_INVINP);
1455 *w = *h = 0;
1456 m = ctx->mode;
1457 ctx->mode = SSFN_MODE_NONE;
1458 ctx->m = 0;
1459 for (s = str, u = ssfn_utf8(&s); u;) {
1460 ssfn_render(ctx, u);
1461 if (ctx->err == SSFN_OK) {
1462 *w += ctx->uix;
1463 *h += ctx->uax;
1464 }
1465 v = ssfn_utf8(&s);
1466 if (usekern) ssfn_kern(ctx, u, v, w, h);
1467 u = v;
1468 }
1469 if (!*w) *w = ctx->m;
1470 if (!*h) *h = ctx->m;
1471 ctx->mode = m;
1472 return ctx->err;
1473}
1474
1481int ssfn_mem(ssfn_t *ctx) {
1482 int i, ret = sizeof(ssfn_t);
1483
1484 if (!ctx) return 0;
1485
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);
1491 return ret;
1492}
1493
1499void ssfn_free(ssfn_t *ctx) {
1500 int i;
1501
1502 if (!ctx) return;
1503
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));
1511}
1512
1513#endif
1514
1515/*** this function goes for both renderers ***/
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) {
1527 uint32_t c = **s;
1528
1529 if ((**s & 128) != 0) {
1530 if (!(**s & 32)) {
1531 c = ((**s & 0x1F) << 6) | (*(*s + 1) & 0x3F);
1532 *s += 1;
1533 } else if (!(**s & 16)) {
1534 c = ((**s & 0xF) << 12) | ((*(*s + 1) & 0x3F) << 6) | (*(*s + 2) & 0x3F);
1535 *s += 2;
1536 } else if (!(**s & 8)) {
1537 c = ((**s & 0x7) << 18) | ((*(*s + 1) & 0x3F) << 12) |
1538 ((*(*s + 2) & 0x3F) << 6) | (*(*s + 3) & 0x3F);
1539 *s += 3;
1540 } else
1541 c = 0;
1542 }
1543 *s += 1;
1544 return c;
1545}
1546#endif
1547
1548#if defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1549 defined(SSFN_CONSOLEBITMAP_HICOLOR) || \
1550 defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1551/*** special console bitmap font renderer (ca. 1k, no dependencies, no memory
1552 * allocation and no error checking) ***/
1553
1557ssfn_font_t *ssfn_font; /* font buffer */
1558uint8_t *ssfn_dst_ptr; /* screen buffer */
1559uint32_t ssfn_dst_pitch; /* screen dimensions */
1560uint32_t ssfn_dst_w = 0;
1561uint32_t ssfn_dst_h = 0;
1562uint32_t ssfn_fg; /* colors in screen's native format */
1563#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1564uint32_t ssfn_bg;
1565#endif
1566uint32_t ssfn_x; /* coordinate to draw to */
1567uint32_t ssfn_y;
1568uint32_t ssfn_adv_x; /* advance values */
1569uint32_t ssfn_adv_y;
1570
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
1581 uint8_t w;
1582#endif
1583
1584 t = (ssfn_font->quality < 5 && ssfn_font->characters_offs[0] < 65536)
1585 ? 4
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;
1589
1590 for (j = i = 0; i < 0x110000; i++) {
1591 if (rg[0] & 0x80) {
1592 n = (rg[0] & 0x3f);
1593 if (rg[0] & 0x40) {
1594 i += rg[1] | (n << 8);
1595 rg++;
1596 } else {
1597 i += n;
1598 }
1599 rg++;
1600 } else {
1601 if (i == unicode) {
1602 y = rg[9];
1603#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1604 w = rg[4];
1605 j = 0;
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
1609 s += ssfn_x;
1610#else
1611#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1612 s += ssfn_x << 1;
1613#else
1614 s += ssfn_x << 2;
1615#endif
1616#endif
1617#endif
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;
1621 n = rg[0];
1622 ssfn_adv_x = rg[6];
1623 ssfn_adv_y = rg[7];
1624 rg += 10;
1625 while (n--) {
1626#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1627 s = ssfn_dst_ptr + (ssfn_y + y + rg[t - 1]) * ssfn_dst_pitch;
1628#ifdef SSFN_CONSOLEBITMAP_PALETTE
1629 s += ssfn_x;
1630#else
1631#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1632 s += ssfn_x << 1;
1633#else
1634 s += ssfn_x << 2;
1635#endif
1636#endif
1637#endif
1638 o = (uint8_t *)ssfn_font;
1639 a = ((rg[1] << 8) | rg[0]);
1640 switch (t) {
1641 case 4:
1642 o += a;
1643 break;
1644 case 5:
1645 o += ((rg[2] & 0xF) << 16) | a;
1646 break;
1647 default:
1648 o += ((rg[3] & 0xF) << 24) | (rg[2] << 16) | a;
1649 break;
1650 }
1651 p = ((o[0] & 0xF) + 1);
1652 a = p << 3;
1653 b = o[1] + 1;
1654 o += 2;
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;
1661 r++;
1662#else
1663#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1664 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1665 r += 2;
1666#else
1667 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1668 r += 4;
1669#endif
1670#endif
1671 }
1672 b += j;
1673#else
1674 j = 0;
1675#endif
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) {
1678 if (m > 0x80) {
1679 g++;
1680 m = 1;
1681 }
1682#ifndef SSFN_CONSOLEBITMAP_CLEARBG
1683 if (*g & m)
1684#endif
1685#ifdef SSFN_CONSOLEBITMAP_PALETTE
1686 *((uint8_t *)r) = (uint8_t)(
1687#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1688 *g & m ? ssfn_fg : ssfn_bg
1689#else
1690 ssfn_bg
1691#endif
1692 );
1693 r++;
1694#else
1695#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1696 *((uint16_t *)r) = (uint16_t)(
1697#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1698 *g & m ? ssfn_fg : ssfn_bg
1699#else
1700 ssfn_fg
1701#endif
1702 );
1703 r += 2;
1704#else
1705 *((uint32_t *)r) = (uint32_t)(
1706#ifdef SSFN_CONSOLEBITMAP_CLEARBG
1707 *g & m ? ssfn_fg : ssfn_bg
1708#else
1709 ssfn_fg
1710#endif
1711 );
1712 r += 4;
1713#endif
1714#endif
1715 }
1716 }
1717 rg += t;
1718 }
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;
1724 r++;
1725#else
1726#ifdef SSFN_CONSOLEBITMAP_HICOLOR
1727 *((uint16_t *)r) = (uint16_t)ssfn_bg;
1728 r += 2;
1729#else
1730 *((uint32_t *)r) = (uint32_t)ssfn_bg;
1731 r += 4;
1732#endif
1733#endif
1734 }
1735#endif
1736 ssfn_x += ssfn_adv_x;
1737 ssfn_y += ssfn_adv_y;
1738 return SSFN_OK;
1739 }
1740 rg += rg[0] * t + 10;
1741 j++;
1742 }
1743 }
1744 return SSFN_ERR_NOGLYPH;
1745}
1746#endif
1747
1748#ifdef __cplusplus
1749}
1750#endif
1751
1752#endif
Definition ssfn.h:176