OpenCPN Partial API docs
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
34 extern "C" {
35 #endif
36 
37 /* if stdint.h was not included before us */
38 #ifndef uint8_t
39 typedef unsigned char uint8_t;
40 typedef unsigned short int uint16_t;
41 typedef 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 2 /* there's at least one pixmap fragment or one color command, so a color map too */
66 #define SSFN_FEAT_HASHINT 4 /* there's at least one hinting fragment */
67 #define SSFN_FEAT_KBIGLKP 8 /* big offsets in kerning look up table */
68 #define SSFN_FEAT_KBIGCHR 16 /* big characters in kerning look up tables */
69 #define SSFN_FEAT_KBIGCRD 32 /* big coordinates in kerning groups */
70 #define SSFN_FEAT_HBIGCRD 64 /* bit coordinates in autohinting fragments */
71 
72 /* contour commands for vector fragments */
73 #define SSFN_CONTOUR_MOVE 0
74 #define SSFN_CONTOUR_LINE 1
75 #define SSFN_CONTOUR_QUAD 2
76 #define SSFN_CONTOUR_CUBIC 3
77 #define SSFN_CONTOUR_COLOR 4
78 
79 /* bitmap and pixmap fragments and hinting grid info */
80 #define SSFN_FRAG_BITMAP 0
81 #define SSFN_FRAG_LBITMAP 1
82 #define SSFN_FRAG_PIXMAP 2
83 #define SSFN_FRAG_HINTING 3
84 
85 /* glyph variants */
86 #define SSFN_VARIANT_DEFAULT 0 /* default, also isolated glyphs */
87 #define SSFN_VARIANT_LOCAL0 0
88 #define SSFN_VARIANT_INITIAL 1 /* currently not needed because contextual glyphs has their own UNICODE code points, */
89 #define SSFN_VARIANT_LOCAL1 1 /* so its only purpose is to store Serbian / Macedonian B D G P T */
90 #define SSFN_VARIANT_MEDIAL 2
91 #define SSFN_VARIANT_LOCAL2 2
92 #define SSFN_VARIANT_FINAL 3
93 #define SSFN_VARIANT_LOCAL3 3
94 #define SSFN_VARIANT_LOCAL4 4
95 #define SSFN_VARIANT_LOCAL5 5
96 #define SSFN_VARIANT_LOCAL6 6
97 #define SSFN_NUMVARIANTS 7
98 
99 /* main SSFN header */
100 typedef struct {
101  uint8_t magic[4]; /* SSFN magic bytes */
102  uint32_t size; /* total size in bytes */
103  uint8_t family; /* font family group */
104  uint8_t style; /* font style, zero or OR'd SSFN_STYLE_BOLD and SSFN_STYLE_ITALIC */
105  uint8_t quality; /* quality, defines grid size, 0 - 8 */
106  uint8_t features; /* feature flags, OR'd SSFN_FEAT_* */
107  uint8_t revision; /* format revision, must be zero */
108  uint8_t reserved0; /* must be zero */
109  uint16_t reserved1;
110  uint16_t baseline; /* horizontal baseline in grid pixels */
111  uint16_t underline; /* position of under line in grid pixels */
112  uint16_t bbox_left; /* overall bounding box for all glyphs in grid pixels */
113  uint16_t bbox_top;
114  uint16_t bbox_right;
115  uint16_t bbox_bottom;
116  uint32_t fragments_offs; /* offset of fragments table relative to magic */
117  uint32_t characters_offs[SSFN_NUMVARIANTS]; /* offset of characters tables per variant relative to magic */
118  uint32_t kerning_offs; /* kerning table offset relative to magic */
119 } ssfn_font_t;
120 
121 /***** renderer API *****/
122 #define SSFN_FAMILY_ANY 0xff /* select the first loaded font */
123 #define SSFN_FAMILY_BYNAME 0xfe /* select font by its unique name */
124 
125 #define SSFN_STYLE_UNDERLINE 4 /* under line glyph */
126 #define SSFN_STYLE_STHROUGH 8 /* strike through glyph */
127 #define SSFN_STYLE_NOHINTING 0x40 /* no auto hinting grid */
128 #define SSFN_STYLE_ABS_SIZE 0x80 /* use absolute size value */
129 
130 #define SSFN_FRAG_CONTOUR 255
131 
132 /* error codes */
133 #define SSFN_OK 0 /* success */
134 #define SSFN_ERR_ALLOC 1 /* allocation error */
135 #define SSFN_ERR_NOFACE 2 /* no font face selected */
136 #define SSFN_ERR_INVINP 3 /* invalid input */
137 #define SSFN_ERR_BADFILE 4 /* bad SSFN file format */
138 #define SSFN_ERR_BADSTYLE 5 /* bad style */
139 #define SSFN_ERR_BADSIZE 6 /* bad size */
140 #define SSFN_ERR_BADMODE 7 /* bad mode */
141 #define SSFN_ERR_NOGLYPH 8 /* glyph (or kerning info) not found */
142 #define SSFN_ERR_NOVARIANT 9 /* no such glyph variant */
143 
144 /* rendering modes */
145 #define SSFN_MODE_NONE 0 /* just select the font to get the glyph (for kerning) */
146 #define SSFN_MODE_OUTLINE 1 /* return the glyph's outlines */
147 #define SSFN_MODE_BITMAP 2 /* render into bitmap */
148 #define SSFN_MODE_ALPHA 3 /* render into alpha channel */
149 #define SSFN_MODE_CMAP 4 /* render into color map indexed buffer */
150 
151 /* grid fitting */
152 #define SSFN_HINTING_THRESHOLD 16 /* don't change unless you really know what you're doing */
153 
154 /* returned bitmap struct */
155 #define SSFN_DATA_MAX 65536
156 typedef struct {
157  uint8_t mode; /* returned glyph's data format */
158  uint8_t baseline; /* baseline of glyph, scaled to size */
159  uint8_t w; /* width */
160  uint8_t h; /* height */
161  uint8_t adv_x; /* advance x */
162  uint8_t adv_y; /* advance y */
163  uint16_t pitch; /* data buffer bytes per line */
164  uint32_t *cmap; /* pointer to color map */
165  uint8_t data[SSFN_DATA_MAX]; /* data buffer */
166 } ssfn_glyph_t;
167 
168 /* renderer context */
169 typedef struct {
170  const ssfn_font_t **fnt[5]; /* font registry */
171  const ssfn_font_t *s; /* explicitly selected font */
172  const ssfn_font_t *f; /* font selected by best match */
173  ssfn_glyph_t *ret; /* glyph to return */
174  uint16_t *p; /* outline points */
175  uint16_t *r[256]; /* raster for scanlines */
176  uint16_t *h; /* auto hinting grid */
177  int len[5]; /* number of fonts in registry */
178  int mp; /* memory allocated for points */
179  int np; /* how many points actually are there */
180  int nr[256]; /* number of coordinates in each raster line */
181  int err; /* returned error code */
182  int family; /* required family */
183  int style; /* required style */
184  int size; /* required size */
185  int mode; /* required mode */
186  int variant; /* required variant */
187  int g; /* shift value for grid size */
188  int m, ix, u,uix,uax, lx,ly, mx,my; /* helper variables */
189 } ssfn_t;
190 
191 /***** API function protoypes *****/
192 
193 /* normal renderer */
194 int ssfn_load(ssfn_t *ctx, const ssfn_font_t *font); /* add an SSFN to context */
195 int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size, int mode); /* select font to use */
196 int ssfn_variant(ssfn_t *ctx, int variant); /* select glyph variant (optional) */
197 uint32_t ssfn_utf8(char **str); /* decode UTF-8 sequence */
198 ssfn_glyph_t *ssfn_render(ssfn_t *ctx, uint32_t unicode); /* return allocated glyph bitmap */
199 int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x, int *y); /* get kerning values */
200 int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w, int *h); /* get bounding box of a rendered string */
201 int ssfn_mem(ssfn_t *ctx); /* return how much memory is used */
202 void ssfn_free(ssfn_t *ctx); /* free context */
203 #define ssfn_lasterr(ctx) ((ssfn_t*)ctx)->err /* return last error code */
204 #define ssfn_error(err) (err>=0&&err<=9?ssfn_errstr[err]:"Unknown error") /* return string for error code */
205 extern const char *ssfn_errstr[];
206 
207 /* simple renderer */
208 int ssfn_putc(uint32_t unicode); /* render console bitmap font */
209 
210 /***** renderer implementations *****/
211 
212 #ifndef SSFN_NOIMPLEMENTATION
213 /*** normal renderer (ca. 22k, fully featured with error checking) ***/
214 
215 # ifndef NULL
216 # define NULL (void*)0
217 # endif
218 //# ifndef size_t
219 // typedef __SIZE_TYPE__ size_t;
220 //# endif
221 # ifndef ssfn_private
222 #define ssfn_private
223 # endif
224 //# ifndef inline
225 //# define inline __inline__
226 //# endif
227 
228 /* Clang does not have built-in versions of these but gcc has */
229 # ifndef SSFN_memcmp
230 # ifdef __builtin_memcmp
231 # define SSFN_memcmp __builtin_memcmp
232 # else
233 # define SSFN_memcmp memcmp
234 # endif
235 # endif
236 
237 # ifndef SSFN_memset
238 # ifdef __builtin_memset
239 # define SSFN_memset __builtin_memset
240 # else
241 # define SSFN_memset memset
242 # endif
243 # endif
244 
245 # ifndef SSFN_realloc
246 # ifdef __builtin_realloc
247 # define SSFN_realloc __builtin_realloc
248 # else
249 # define SSFN_realloc realloc
250 #endif
251 # endif
252 
253 # ifndef SSFN_free
254 # ifdef __builtin_free
255 # define SSFN_free __builtin_free
256 # else
257 # define SSFN_free free
258 # endif
259 # endif
260 
264 const char *ssfn_errstr[] = { "",
265  "Memory allocation error",
266  "No font face found",
267  "Invalid input value",
268  "Bad file format",
269  "Invalid style",
270  "Invalid size",
271  "Invalid mode",
272  "Glyph not found",
273  "Glyph variant not found"
274 };
275 
276 /*** Private functions ***/
277 /* f = file scale, g = grid 4095.15, o = screen point 255.255, i = screen pixel 255, c = ceil */
278 # define _ssfn_i2g(x) ((x)? (((x) << 16) - (1 << 15)) / ctx->m : 0)
279 # define _ssfn_g2o(x) (((x) * ctx->m + (1 << 7)) >> 8)
280 # define _ssfn_g2i(x) (((x) * ctx->m + (1 << 15)) >> 16)
281 # define _ssfn_g2ic(x) (((x) * ctx->m + (1 << 16) - 1) >> 16)
282 # define _ssfn_f2i(x) ((((x) << s) * ctx->m + (1 << 15)) >> 16)
283 # define _ssfn_o2i(x) (((x) + (1 << 7)) >> 8)
284 # define _ssfn_o2ic(x) ((x + (1<<8) - 1) >> 8)
285 # define _ssfn_g2ox(x) ((x)>=(4095 << 4) ? _ssfn_g2o(x) : ctx->h[((x) >> 4)])
286 # define _ssfn_g2ix(x) ((x)>=(4095 << 4) ? _ssfn_g2i(x) : _ssfn_o2i(ctx->h[((x) >> 4)]))
287 # define _ssfn_g2ixc(x) ((x)>=(4095 << 4) ? _ssfn_g2ic(x) : _ssfn_o2ic(ctx->h[((x) >> 4)]))
288 # define _ssfn_g2oy(y) (_ssfn_g2o(y))
289 # define _ssfn_g2iy(y) (_ssfn_g2i(y))
290 # define _ssfn_g2iyc(y) (_ssfn_g2ic(y))
291 # define _ssfn_igg(y) (((4096<<4)-(y)) >> (2))
292 # define _ssfn_igi(y) ((((4096<<4)-(y)) * ctx->m + (1 << (15+3))) >> (16+3))
293 
294 /* parse character table */
295 ssfn_private uint8_t *_ssfn_c(const ssfn_font_t *font, uint32_t unicode, int v)
296 {
297  uint32_t i, j, l;
298  uint8_t *ptr;
299 
300  if(!font->characters_offs[v]) return NULL;
301 
302  ptr = (uint8_t*)font + font->characters_offs[v];
303  l = (font->quality < 5 && font->characters_offs[v] < 65536) ? 4 : (font->characters_offs[v] < 1048576 ? 5 : 6);
304 
305  for(j=i=0;i<0x110000;i++) {
306  if(ptr[0] & 0x80) {
307  if(ptr[0] & 0x40) { i += ptr[1] | ((ptr[0] & 0x3f) << 8); ptr += 2; }
308  else { i += ptr[0] & 0x3f; ptr++; }
309  } else {
310  if(i == unicode) return ptr;
311  ptr += ptr[0] * l + 10;
312  j++;
313  }
314  }
315  return NULL;
316 }
317 
318 /* add a line to contour */
319 ssfn_private void _ssfn_l(ssfn_t *ctx, int x, int y, int l)
320 {
321  if(x > (4096<<4) - 16) x = (4096<<4) - 16;
322  if(y > (4096<<4) - 16) y = (4096<<4) - 16;
323  if(x < -1 || y < -1 || (x == ctx->lx && y == ctx->ly)) return;
324 
325  if(ctx->np+2 >= ctx->mp) {
326  ctx->mp += 512;
327  ctx->p = (uint16_t *)SSFN_realloc(ctx->p, ctx->mp*sizeof(uint16_t));
328  if(!ctx->p) { ctx->err = SSFN_ERR_ALLOC; return; }
329  }
330  if(!ctx->np || !l || _ssfn_g2i(ctx->p[ctx->np-2]) != _ssfn_g2i(x) ||
331  _ssfn_g2i(ctx->p[ctx->np-1]) != _ssfn_g2i(y)) {
332  ctx->p[ctx->np++] = x;
333  ctx->p[ctx->np++] = y;
334  ctx->lx = x; ctx->ly = y;
335  }
336  if((ctx->style & 0x200) && x >= 0 && ctx->ix > x) ctx->ix = x;
337 }
338 
339 /* add a Bezier curve to contour */
340 void _ssfn_b(ssfn_t *ctx, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, int l)
341 {
342  int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y;
343  if(l<8 && (x0!=x3 || y0!=y3)) {
344  m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0;
345  m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1;
346  m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2;
347  m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y;
348  m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y;
349  m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y;
350  _ssfn_b(ctx, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, l+1);
351  _ssfn_b(ctx, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, l+1);
352  }
353  _ssfn_l(ctx, x3, y3, l);
354 }
355 
356 /* rasterize contour */
357 ssfn_private void _ssfn_r(ssfn_t *ctx)
358 {
359  int i, k, l, m, n = 0, x, y, Y, M = 0;
360  uint16_t *r;
361  uint8_t *pix = ctx->ret->data;
362 
363  for(y = 0; y < ctx->ret->h; y++) {
364  Y = _ssfn_i2g(y); r = ctx->r[y];
365  for(n = 0, i = 0; i < ctx->np - 3; i += 2) {
366  if((ctx->p[i] == 0xffff && ctx->p[i+1] == 0xffff) ||
367  (ctx->p[i+2] == 0xffff && ctx->p[i+3] == 0xffff)) continue;
368  if( (ctx->p[i+1] < Y && ctx->p[i+3] >= Y) ||
369  (ctx->p[i+3] < Y && ctx->p[i+1] >= Y)) {
370  if(_ssfn_g2iy(ctx->p[i+1]) == _ssfn_g2iy(ctx->p[i+3]))
371  x = (((int)ctx->p[i]+(int)ctx->p[i+2])>>1);
372  else
373  x = ((int)ctx->p[i]) + ((Y - (int)ctx->p[i+1])*
374  ((int)ctx->p[i+2] - (int)ctx->p[i])/
375  ((int)ctx->p[i+3] - (int)ctx->p[i+1]));
376  if(y == ctx->u) {
377  if(x < ctx->uix) { ctx->uix = x; }
378  if(x > ctx->uax) { ctx->uax = x; }
379  }
380  x = _ssfn_g2ox(x - ctx->ix);
381  for(k=0; k < n && x > r[k]; k++);
382  if(n >= ctx->nr[y]) {
383  ctx->nr[y] = (n < ctx->np) ? ctx->np : (n+1) << 1;
384  ctx->r[y] = (uint16_t *)SSFN_realloc(ctx->r[y], (ctx->nr[y] << 1));
385  if(!ctx->r[y]) { ctx->err = SSFN_ERR_ALLOC; return; }
386  r = ctx->r[y];
387  }
388  for(l = n; l > k; l--) r[l] = r[l-1];
389  r[k] = x;
390  n++;
391  }
392  }
393  if(n>1 && n&1) { r[n-2] = r[n-1]; n--; }
394  ctx->nr[y] = n;
395  if(n) {
396  if(y > M) M = y;
397  k = y*ctx->ret->pitch;
398  for(i=0; i < n-1; i += 2) {
399  if(ctx->style & 0x100) {
400  l = (r[i] + r[i + 1]) >> 9;
401  if(ctx->mode == SSFN_MODE_BITMAP ? (pix[k + (l >> 3)] & (1 << (l & 7)) ? 1 : 0) : (pix[k + l] == 0xFF)) {
402  if(r[i] + 256 > r[i + 1]) r[i] = r[i + 1] - 128; else r[i] += 256;
403  if(r[i + 1] - 256 > r[i]) r[i + 1] -= 256;
404  } else {
405  if(i >= n-2 || r[i + 1] + 256 < r[i + 2]) r[i + 1] += 256;
406  }
407  }
408  l = ((r[i] + 128) >> 8);
409  m = ((r[i + 1] + 128) >> 8);
410  if(ctx->mode != SSFN_MODE_BITMAP && l + 1 < m) l++;
411  for(; l < m; l++) {
412  switch(ctx->mode) {
413  case SSFN_MODE_BITMAP: pix[k + (l >> 3)] ^= 1 << (l & 7); break;
414  case SSFN_MODE_ALPHA: pix[k + l] ^= 0xFF; break;
415  case SSFN_MODE_CMAP: pix[k + l] ^= 0x0F; break;
416  }
417  }
418  if(l + 1 > ctx->ret->w) ctx->ret->w = l + 1;
419  }
420  }
421  }
422  /* fix rounding errors */
423  if(M + 1 == ctx->ret->baseline) { ctx->ret->baseline--; ctx->u--; }
424 }
425 
426 /* anti-alias a contour */
427 ssfn_private void _ssfn_a(ssfn_t * ctx)
428 {
429  int i, x, y, x0,y0,x1,y1, sx,sy, dx,dy, m, o, p = ctx->ret->pitch;
430  uint8_t *pix = ctx->ret->data, e;
431  uint16_t *r;
432 
433  if(ctx->mode < SSFN_MODE_ALPHA || !ctx->p || ctx->np < 4) return;
434 
435  for(y = o = 0; y < ctx->ret->h; y++, o += p) {
436  if(ctx->nr[y] && (r = ctx->r[y])) {
437  for(i = 0; i < ctx->nr[y] - 1; i += 2) {
438  x = (r[i] + 128) >> 8;
439  e = ~((r[i] + 128) & 0xFF);
440  if(e == 127) e = 255;
441  else {
442  if(x && pix[o + x - 1] > e) e = pix[o + x - 1];
443  if(y && pix[o + x - p] > e) e = pix[o + x - p];
444  }
445  if(ctx->mode == SSFN_MODE_CMAP) e = (e >> 4) | 0xF0;
446  if(e > pix[o + x]) pix[o + x] = e;
447  e = ((r[i + 1] + 128) & 0xFF);
448  if(e == 128) e = 255;
449  pix[o + ((r[i + 1] + 128) >> 8)] = ctx->mode == SSFN_MODE_CMAP ? (e >> 4) | 0xF0 : e;
450  }
451  }
452  }
453 
454  for(i = 0; i < ctx->np - 3; i += 2) {
455  if((ctx->p[i] == 0xffff && ctx->p[i+1] == 0xffff) ||
456  (ctx->p[i+2] == 0xffff && ctx->p[i+3] == 0xffff)) continue;
457 
458  x0 = ctx->p[i] - ctx->ix; y0 = ctx->p[i+1]; x1 = ctx->p[i+2] - ctx->ix; y1 = ctx->p[i+3];
459  sx = x1 >= x0? 1 : -1; sy = y1 >= y0? 1 : -1; dx = x1 - x0; dy = y1 - y0;
460  if(sx * dx >= sy * dy && dx) {
461  for(x = x0, m = sx * dx; m > 0; m -= 16, x += sx * 16) {
462  y = _ssfn_g2oy(y0 + ((x - x0) * dy / dx));
463  y += 128; e = ~(y & 0xFF); y >>= 8; e >>= 1;
464  o = y * p + ((_ssfn_g2ox(x) + 128) >> 8);
465  if(ctx->mode == SSFN_MODE_CMAP) e = (e >> 4) | 0xF0;
466  if(e > pix[o]) pix[o] = e;
467  }
468  }
469  }
470 }
471 
472 /* parse a glyph */
473 ssfn_private void _ssfn_g(ssfn_t *ctx, uint8_t *rg, int render)
474 {
475  int i, j, nf, m, n, o, ox, oy, ol, t, x, y, a, b, c, d, w, h, s;
476  uint8_t *raw, *ra, *re, *pix = ctx->ret->data;
477 
478  ctx->lx = ctx->ly = ctx->mx = ctx->my = -1;
479  ol = (ctx->f->quality < 5 && ctx->f->characters_offs[ctx->variant] < 65536) ? 4 :
480  ((ctx->f->characters_offs[ctx->variant] < 1048576) ? 5 : 6);
481  s = 16 - ctx->g;
482  nf = rg[0];
483  rg += 10;
484 
485  for(h=0; nf-- && !ctx->err; rg += ol) {
486  switch(ol) {
487  case 4: o = ((rg[1] << 8) | rg[0]); ox = rg[2]; oy = rg[3]; break;
488  case 5: o = (((rg[2] & 0xF) << 16) | (rg[1] << 8) | rg[0]);
489  ox = (((rg[2] >> 4) & 3) << 8) | rg[3]; oy = (((rg[2] >> 6) & 3) << 8) | rg[4]; break;
490  default: o = (((rg[3] & 0xF) << 24) | (rg[2] << 16) | (rg[1] << 8) | rg[0]);
491  ox = ((rg[3] & 0xF) << 8) | rg[4]; oy = (((rg[3] >> 4) & 0xF) << 8) | rg[5]; break;
492  }
493  ox <<= s; oy <<= s; raw = (uint8_t*)ctx->f + o;
494  if(raw[0] & 0x80) {
495  t = (raw[0] & 0x60)>>5;
496  if(!render && t != SSFN_FRAG_HINTING) break;
497  switch(t) {
498  case SSFN_FRAG_LBITMAP:
499  x = ((((raw[0]>>2)&3)<<8)+raw[1])+1;
500  y = (((raw[0]&3)<<8)|raw[2])+1;
501  raw += 3;
502  goto bitmap;
503 
504  case SSFN_FRAG_BITMAP:
505  x = (raw[0] & 0x1F)+1;
506  y = raw[1]+1;
507  raw += 2;
508 bitmap: if(ctx->mode == SSFN_MODE_OUTLINE) {
509  x <<= 3;
510 outline: ctx->lx = ctx->ly = -1;
511  x <<= s; y <<= s;
512  if(ctx->style & 0x200) {
513  a = (((4096<<4)-(oy)) >> (3));
514  b = (((4096<<4)-(oy + y)) >> (3));
515  if(ctx->ix > ox + a) ctx->ix = ox + a;
516  } else a = b = 0;
517  if(ctx->np) _ssfn_l(ctx, -1, -1, 0);
518  _ssfn_l(ctx, ox+a, oy, 0);
519  _ssfn_l(ctx, ox+x+a, oy, 0);
520  _ssfn_l(ctx, ox+x+b, oy+y, 0);
521  _ssfn_l(ctx, ox+b, oy+y, 0);
522  _ssfn_l(ctx, ox+a, oy, 0);
523  } else {
524  a = x << 3; b = y << s;
525  c = _ssfn_g2i(oy);
526  n = _ssfn_g2i(ox);
527  w = _ssfn_g2i(x << (3+s));
528  h = _ssfn_g2i(b);
529  if(c + h >= ctx->ret->h) c = ctx->ret->h - h; /* due to rounding */
530  c = t = c * ctx->ret->pitch;
531  for(j=0; j < h; j++) {
532  o = (((j<<8) * (y<<8) / (h<<8)) >> 8) * x;
533  for(i=0; i < w; i++) {
534  m = ((i<<8) * (a<<8) / (w<<8)) >> 8;
535  if(raw[o + (m >> 3)] & (1 << (m & 7))) {
536  d = n + ((ctx->style & 0x200) ? _ssfn_igi(oy + (j<<s) + 127) : 0) + i;
537  switch(ctx->mode) {
538  case SSFN_MODE_BITMAP:
539  pix[c + (d >> 3)] |= 1 << (d & 7); d++;
540  if((ctx->style & 0x100) && (d >> 3) < ctx->ret->pitch) {
541  pix[c + (d >> 3)] |= 1 << (d & 7); d++;
542  if(ctx->size > 127 && (d >> 3) < ctx->ret->pitch) {
543  pix[c + (d >> 3)] |= 1 << (d & 7);
544  }
545  }
546  break;
547  case SSFN_MODE_CMAP:
548  case SSFN_MODE_ALPHA:
549  pix[c + (d++)] = 0xFF;
550  if((ctx->style & 0x100) && d < ctx->ret->pitch) {
551  pix[c + (d++)] = 0xFF;
552  if(ctx->size > 127 && d < ctx->ret->pitch) {
553  pix[c + d] = 0xFF;
554  }
555  }
556  break;
557  }
558  if(d > ctx->ret->w) ctx->ret->w = d;
559  d = ox + _ssfn_i2g(d);
560  if((ctx->style & 0x200) && ctx->ix > d) ctx->ix = d;
561  if(_ssfn_g2i(oy) + j == ctx->u) {
562  if(d < ctx->uix) { ctx->uix = d; }
563  if(d > ctx->uax) { ctx->uax = d; }
564  }
565  }
566  }
567  c += ctx->ret->pitch;
568  }
569  if(ctx->mode != SSFN_MODE_BITMAP && h > y && w > 1) {
570  m = (ctx->mode == SSFN_MODE_CMAP) ? 0xF0 : 0;
571  x = h/y;
572  for(a = x; a; a--) {
573  b = ctx->style & 0x100 ? (64 + (128 * a / x)) : (192 * a / x);
574  if(ctx->mode == SSFN_MODE_CMAP) b = (b >> 4) | 0xF0;
575  c = t + ctx->ret->pitch;
576  for(j=1; j < h-1; j++) {
577  for(i=1; i < w-1; i++) {
578  d = n + ((ctx->style & 0x200) ? _ssfn_igi(oy + (j<<s)) : 0) + i;
579  if(pix[c + d] == m &&
580  (pix[c + d - ctx->ret->pitch] > b || pix[c + d + ctx->ret->pitch] > b) &&
581  (pix[c + d - 1] > b || pix[c + d + 1] > b))
582  pix[c + d] = b;
583  }
584  c += ctx->ret->pitch;
585  }
586  }
587  }
588  }
589  h = 0;
590  break;
591 
592  case SSFN_FRAG_PIXMAP:
593  x = (((raw[0] & 12) << 6) | raw[1])+1;
594  y = (((raw[0] & 3) << 8) | raw[2])+1;
595  n = ((raw[4]<<8) | raw[3])+1;
596  raw += 5;
597  if(ctx->mode == SSFN_MODE_OUTLINE) goto outline;
598  if(raw[-5] & 0x10) {
599  /* todo: direct ARGB values in pixmap fragment */
600  }
601  a = x * y;
602  if(a >= (ctx->nr[0] << 1)) {
603  ctx->nr[0] = (a+1) >> 1;
604  ctx->r[0] = (uint16_t *)SSFN_realloc(ctx->r[0], (ctx->nr[0] << 1));
605  if(!ctx->r[0]) { ctx->err = SSFN_ERR_ALLOC; return; }
606  }
607  ctx->ret->cmap = (uint32_t*)((uint8_t*)ctx->f + ctx->f->size - 964);
608  for(re = raw+n, ra = (uint8_t*)ctx->r[0], i=0; i < a && raw < re;) {
609  c = (raw[0] & 0x7F)+1;
610  if(raw[0] & 0x80) { for(j=0; j < c; j++) ra[i++] = raw[1]; raw += 2; }
611  else { raw++; for(j=0; j < c; j++) ra[i++] = *raw++; }
612  }
613  b = y << s;
614  c = _ssfn_g2i(oy);
615  n = _ssfn_g2i(ox);
616  w = _ssfn_g2i(x << 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) * (x<<8) / (w<<8)) >> 8;
624  if(ra[o + m] < 0xF0) {
625  d = n + ((ctx->style & 0x200) ? _ssfn_igi(oy + (j<<s) + 127) : 0) + i;
626  re = (uint8_t*)&ctx->ret->cmap[ra[o + m]];
627  a = (re[0] + re[1] + re[2] + 255) >> 2;
628  switch(ctx->mode) {
629  case SSFN_MODE_BITMAP:
630  if(a > 127)
631  pix[c + (d >> 3)] |= 1 << (d & 7);
632  break;
633  case SSFN_MODE_CMAP:
634  pix[c + d] = ra[o + m];
635  break;
636  case SSFN_MODE_ALPHA:
637  a >>= 1; a = ~a;
638  pix[c + d] = a;
639  break;
640  }
641  if(d > ctx->ret->w) ctx->ret->w = d;
642  }
643  }
644  c += ctx->ret->pitch;
645  }
646  h = 0;
647  break;
648 
649  case SSFN_FRAG_HINTING:
650  if(raw[0] & 0x10) { n = ((raw[0]&0xF)<<8) | raw[1]; raw += 2; } else { n = raw[0] & 0xF; raw++; }
651  if(render || !ox) { raw += n << (ctx->f->features & SSFN_FEAT_HBIGCRD ? 1 : 0); continue; }
652  y = 4096; x = ((ox >> s) - 1) << (s-4);
653  ctx->h[y++] = x;
654  for(n++;n-- && x < 4096;) {
655  x = raw[0]; raw++;
656  if(ctx->f->features & SSFN_FEAT_HBIGCRD) { x |= (raw[0] << 8); raw++; }
657  x <<= (s-4);
658  ctx->h[y++] = x;
659  }
660  if(y < 4096) ctx->h[y++] = 65535;
661  h = 1;
662  break;
663  }
664  } else {
665  if(!render && h) break;
666  if(raw[0] & 0x40) { n = ((raw[0] & 0x3F) << 8) | raw[1]; raw += 2; } else { n = raw[0] & 0x3F; raw++; }
667  if(ctx->f->quality < 5) { x = raw[0]; y = raw[1]; raw += 2; }
668  else { x = ((raw[0] & 3) << 8) | raw[1]; y = ((raw[0] & 0x30) << 4) | raw[2]; raw += 3; }
669  x <<= s; y <<= s; y += oy;
670  x += ox + (ctx->style & 0x200 ? _ssfn_igg(y) : 0);
671  if(render) {
672  if(ctx->np) { _ssfn_l(ctx, ctx->mx, ctx->my, 0); _ssfn_l(ctx, -1, -1, 0); }
673  _ssfn_l(ctx, x, y, 0);
674  }
675  ctx->lx = ctx->mx = x; ctx->ly = ctx->my = y;
676  for(n++;n--;) {
677  t = ctx->g < 8 ? (raw[0] >> 7) | ((raw[1] >> 6) & 2) : raw[0] & 3;
678  x = y = a = b = c = d = j = 0;
679  switch(ctx->g) {
680  case 4:
681  case 5:
682  case 6:
683  case 7:
684  x = raw[0] & 0x7F; y = raw[1] & 0x7F;
685  switch(t) {
686  case 0: raw += raw[0] & 4 ? 5 : 2; break;
687  case 1: raw += 2; break;
688  case 2: a = raw[2] & 0x7F; b = raw[3] & 0x7F; raw += 4; break;
689  case 3: a = raw[2] & 0x7F; b = raw[3] & 0x7F; c = raw[4] & 0x7F; d = raw[5] & 0x7F; raw += 6; break;
690  }
691  break;
692 
693  case 8:
694  x = raw[1]; y = raw[2];
695  switch(t) {
696  case 0: raw += raw[0] & 4 ? 5 : 2; break;
697  case 1: raw += 3; break;
698  case 2: a = raw[3]; b = raw[4]; raw += 5; break;
699  case 3: a = raw[3]; b = raw[4]; c = raw[5]; d = raw[6]; raw += 7; break;
700  }
701  break;
702 
703  case 9:
704  x = ((raw[0] & 4) << 6) | raw[1]; y = ((raw[0] & 8) << 5) | raw[2];
705  switch(t) {
706  case 0: raw += raw[0] & 4 ? 5 : 2; break;
707  case 1: raw += 3; break;
708  case 2: a = ((raw[0] & 16) << 4) | raw[3]; b = ((raw[0] & 32) << 3) | raw[4]; raw += 5; break;
709  case 3: a = ((raw[0] & 16) << 4) | raw[3]; b = ((raw[0] & 32) << 3) | raw[4];
710  c = ((raw[0] & 64) << 2) | raw[5]; d = ((raw[0] & 128) << 1) | raw[6]; raw += 7; break;
711  }
712  break;
713 
714  default:
715  x = ((raw[0] & 12) << 6) | raw[1]; y = ((raw[0] & 48) << 4) | raw[2];
716  switch(t) {
717  case 0: raw += raw[0] & 4 ? 5 : 2; break;
718  case 1: raw += 3; break;
719  case 2: a = ((raw[3] & 3) << 8) | raw[4]; b = ((raw[3] & 12) << 6) | raw[5]; raw += 6; break;
720  case 3: a = ((raw[3] & 3) << 8) | raw[4]; b = ((raw[3] & 12) << 6) | raw[5];
721  c = ((raw[3] & 48) << 4) | raw[6]; d = ((raw[3] & 192) << 2) | raw[7]; raw += 8; break;
722  }
723  break;
724  }
725  x <<= s; y <<= s; a <<= s; b <<= s; c <<= s; d <<= s;
726  x += ox; y += oy; a += ox; b += oy; c += ox; d += oy;
727  if(ctx->style & 0x200) {
728  x += _ssfn_igg(y);
729  a += _ssfn_igg(b);
730  c += _ssfn_igg(d);
731  }
732  if(render) {
733  switch(t) {
734  case 0: /* this v1.0 renderer does not support colored contours */ break;
735  case 1: _ssfn_l(ctx, x, y, 0); break;
736  case 2: _ssfn_b(ctx, ctx->lx,ctx->ly, ((a-ctx->lx)>>1)+ctx->lx,((b-ctx->ly)>>1)+ctx->ly,
737  ((x-a)>>1)+a,((y-b)>>1)+b, x,y, 0); break;
738  case 3: _ssfn_b(ctx, ctx->lx,ctx->ly, a,b, c,d, x,y, 0); break;
739  }
740  } else if(t == 1 && x >= 0 && y >= 0) {
741  a = ((ctx->lx < x) ? x - ctx->lx : ctx->lx - x) >> 4;
742  b = ((ctx->ly < y) ? y - ctx->ly : ctx->ly - y) >> 4;
743  c = (ctx->lx + x) >> 5;
744  if(a < 2) ctx->h[4096 + (!ctx->h[4096 + c] && c && ctx->h[4096 + c - 1]? c - 1 : c)] += b;
745  }
746  ctx->lx = x; ctx->ly = y;
747  }
748  }
749  }
750 
751  if(!render && !h) {
752  for(j = m = x = y = 0; j < 4096; j++) {
753  if(ctx->h[4096 + j] >= 4096/SSFN_HINTING_THRESHOLD) {
754  if(!j) m++;
755  else { ctx->h[4096 + m++] = j - x; x = j; }
756  }
757  }
758  if(m < 4096) ctx->h[4096 + m] = 65535;
759  }
760 }
761 
762 /*** public API implementation ***/
763 
772 #define SSFN_CMAP_TO_ARGB(p,c,fg) (p>=0xF0?(uint32_t)((p<<28)|((p&0xF)<<24)|fg):c[p])
773 
781 int ssfn_load(ssfn_t *ctx, const ssfn_font_t *font)
782 {
783  ssfn_font_t *ptr, *end;
784 
785  if(!ctx || !font) {
786  if(ctx) ctx->err = SSFN_ERR_INVINP;
787  return SSFN_ERR_INVINP;
788  }
789  ctx->err = SSFN_OK;
790  if(!SSFN_memcmp(font->magic, SSFN_COLLECTION, 4)) {
791  end = (ssfn_font_t*)((uint8_t*)font + font->size);
792  for(ptr = (ssfn_font_t*)((uint8_t*)font + 8); ptr < end && !ctx->err; ptr = (ssfn_font_t*)((uint8_t*)ptr + ptr->size))
793  ssfn_load(ctx, ptr);
794  } else {
795  if(SSFN_memcmp(font->magic, SSFN_MAGIC, 4) || SSFN_memcmp((uint8_t*)font + font->size - 4, SSFN_ENDMAGIC, 4) ||
796  font->family > SSFN_FAMILY_HAND || font->fragments_offs > font->size || font->characters_offs[0] > font->size ||
797  font->kerning_offs > font->size || font->fragments_offs >= font->characters_offs[0] || font->quality > 8) {
798  ctx->err = SSFN_ERR_BADFILE;
799  } else {
800  ctx->len[font->family]++;
801  ctx->fnt[font->family] = (const ssfn_font_t**)SSFN_realloc(ctx->fnt[font->family], ctx->len[font->family]*sizeof(void*));
802  if(!ctx->fnt[font->family])
803  ctx->err = SSFN_ERR_ALLOC;
804  else
805  ctx->fnt[font->family][ctx->len[font->family]-1] = font;
806  }
807  }
808  return ctx->err;
809 }
810 
822 int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size, int mode)
823 {
824  int i, j, l;
825 
826  if(!ctx) return SSFN_ERR_INVINP;
827  if((style & ~0xCF)) return (ctx->err = SSFN_ERR_BADSTYLE);
828  if(size < 8 || size > 255) return (ctx->err = SSFN_ERR_BADSIZE);
829  if(mode > SSFN_MODE_CMAP) return (ctx->err = SSFN_ERR_BADMODE);
830 
831  if(family == SSFN_FAMILY_BYNAME) {
832  if(!name || !name[0]) {
833 invinp: return (ctx->err = SSFN_ERR_INVINP);
834  }
835  for(l=0; name[l]; l++);
836  for(i=0; i < 5; i++) {
837  for(j=0; j < ctx->len[i]; j++) {
838  if(!SSFN_memcmp(name, (uint8_t*)&ctx->fnt[i][j]->magic + sizeof(ssfn_font_t), l)) {
839  ctx->s = ctx->fnt[i][j];
840  goto familyfound;
841  }
842  }
843  }
844 noface: return (ctx->err = SSFN_ERR_NOFACE);
845  } else {
846  if(family != SSFN_FAMILY_ANY) {
847  if(family > SSFN_FAMILY_HAND) goto invinp;
848  if(!ctx->len[family]) goto noface;
849  }
850  ctx->s = NULL;
851  }
852 familyfound:
853  ctx->np = ctx->mp = 0;
854  if(ctx->p) {
855  SSFN_free(ctx->p);
856  ctx->p = NULL;
857  }
858  ctx->f = NULL;
859  ctx->family = family;
860  ctx->style = style;
861  ctx->size = size;
862  ctx->mode = mode;
863  ctx->variant = 0;
864  return (ctx->err = SSFN_OK);
865 }
866 
874 int ssfn_variant(ssfn_t *ctx, int variant)
875 {
876  if(!ctx) return SSFN_ERR_INVINP;
877  if(variant < 0 || variant > SSFN_NUMVARIANTS-1) return (ctx->err = SSFN_ERR_INVINP);
878  ctx->variant = variant;
879  return (ctx->err = SSFN_OK);
880 }
881 
889 ssfn_glyph_t *ssfn_render(ssfn_t *ctx, uint32_t unicode)
890 {
891  ssfn_font_t **fl;
892  int i, j, s, h, p, m, n, bt, bl;
893  int l, k, x, y;
894  uint8_t *rg = NULL, c, d;
895 
896  if(!ctx) return NULL;
897  if(ctx->size < 8) { ctx->err = SSFN_ERR_NOFACE; return NULL; }
898  ctx->err = SSFN_OK;
899  if(ctx->s) {
900  ctx->f = (ssfn_font_t*)ctx->s;
901  rg = _ssfn_c(ctx->f, unicode, ctx->variant);
902  if(!rg) rg = _ssfn_c(ctx->f, unicode, 0);
903  } else {
904  p = ctx->family;
905  k = ctx->variant;
906 again: if(p == SSFN_FAMILY_ANY) { n = 0; m = 4; } else n = m = p;
907  for(; n <= m; n++) {
908  fl = (ssfn_font_t **)ctx->fnt[n];
909  if(ctx->style & 3) {
910  /* check if we have a specific ctx->f for the requested style */
911  for(i=0;i<ctx->len[n];i++)
912  if((fl[i]->style & 3) == (ctx->style & 3) && (rg = _ssfn_c(fl[i], unicode, k))) { ctx->f = fl[i]; break; }
913  /* if bold italic was requested, check if we have at least bold or italic */
914  if(!rg && (ctx->style & 3) == 3)
915  for(i=0;i<ctx->len[n];i++)
916  if((fl[i]->style & 3) && (rg = _ssfn_c(fl[i], unicode, k))) { ctx->f = fl[i]; break; }
917  }
918  /* last resort, get the first ctx->f which has a glyph for this unicode, no matter style */
919  if(!rg) {
920  for(i=0;i<ctx->len[n];i++)
921  if((rg = _ssfn_c(fl[i], unicode, k))) { ctx->f = fl[i]; break; }
922  }
923  }
924  /* if glyph still not found, try any family group, finally only default variant */
925  if(!rg) {
926  if(p != SSFN_FAMILY_ANY) { p = SSFN_FAMILY_ANY; goto again; }
927  if(k) { k = 0; goto again; }
928  }
929  }
930  if(!rg) { ctx->err = ctx->variant ? SSFN_ERR_NOVARIANT : SSFN_ERR_NOGLYPH; return NULL; }
931 
932  ctx->style &= 0xFF;
933  if((ctx->style & 1) && !(ctx->f->style & 1)) ctx->style |= 0x100;
934  if((ctx->style & 2) && !(ctx->f->style & 2)) ctx->style |= 0x200;
935  if(ctx->f->family == SSFN_FAMILY_MONOSPACE) ctx->style |= SSFN_STYLE_ABS_SIZE;
936 
937  ctx->g = 4 + ctx->f->quality;
938  ctx->np = 0;
939 
940  s = 16 - ctx->g;
941  if(ctx->mode == SSFN_MODE_OUTLINE) {
942  h = ctx->size;
943  p = 0;
944  } else {
945  if(!(((rg[2] & 0x0F) << 8) | rg[6]) || ctx->style & SSFN_STYLE_ABS_SIZE)
946  h = ctx->size;
947  else
948  h = (4096 << 4) * ctx->size / ((ctx->f->baseline - ctx->f->bbox_top) << s);
949  p = (h + (ctx->style & 0x100? 2 : 0) + (ctx->style & 0x200 ? h>>2 : 0));
950  if(p > 255) {
951  p = h = 255;
952  if(ctx->style & 0x100) h -= 2;
953  if(ctx->style & 0x200) h = h*4/5;
954  }
955  if(ctx->mode == SSFN_MODE_BITMAP) p = (p + 7) >> 3;
956  }
957  ctx->m = h;
958 
959  if(!ctx->h) ctx->h = (uint16_t*)SSFN_realloc(NULL, 4096*2*sizeof(uint16_t));
960  if(!ctx->h) goto erralloc;
961 
962  if(!(ctx->style & SSFN_STYLE_NOHINTING)) {
963  SSFN_memset(&ctx->h[4096], 0, 4096*sizeof(uint16_t));
964  _ssfn_g(ctx, rg, 0);
965  } else ctx->h[4096] = 65535;
966 
967  ctx->h[0] = 0;
968  for(i = j = k = x = y = m = 0; i < 4096 && j < 4095; i++) {
969  y = ctx->h[4096 + i] == 65535 ? 4095 - j : ctx->h[4096 + i];
970  j += y;
971  if(j == x) {
972  ctx->h[j] = (((j<<4) * h + (1<<15)) >> 16) << 8;
973  if(!y) j++;
974  } else {
975  y = _ssfn_g2o(y<<4);
976  m += y;
977  if((i&1) || y < 256) { continue; }
978  m &= ~0xFF;
979  n = ctx->h[x];
980  for(l = 0; l + x <= j; l++)
981  ctx->h[x + l] = n + ((m-n)*l / (j-x));
982  }
983  x = j;
984  }
985  ctx->uix = _ssfn_g2ixc((((rg[2] & 0x0F) << 8) | rg[6]) << s);
986  ctx->uax = _ssfn_g2iyc((((rg[2] & 0xF0) << 4) | rg[7]) << s);
987  if(ctx->mode == SSFN_MODE_NONE) return NULL;
988 
989  bl = ((((rg[3] & 0x0F) << 8) | rg[8])) << s;
990  bt = ((((rg[3] & 0xF0) << 4) | rg[9])) << s;
991  i = p * h;
992  ctx->ret = (ssfn_glyph_t*)SSFN_realloc(NULL, i + 8 + sizeof(uint8_t*));
993  if(!ctx->ret) {
994 erralloc:
995  ctx->err = SSFN_ERR_ALLOC;
996  return NULL;
997  }
998  SSFN_memset(&ctx->ret->data, ctx->mode == SSFN_MODE_CMAP ? 0xF0 : 0, i);
999  ctx->ret->cmap = NULL;
1000  ctx->ret->mode = ctx->mode;
1001  ctx->ret->pitch = p;
1002  ctx->ret->w = 0;
1003  ctx->ret->h = h;
1004  ctx->ret->baseline = (((ctx->f->baseline << s) - bt) * h + (1<<16) - 1) >> 16;
1005  ctx->u = ctx->ret->baseline + ((((ctx->f->underline - ctx->f->baseline) << s) * h) >> 16);
1006 
1007  ctx->ret->adv_x = ctx->uix;
1008  ctx->ret->adv_y = ctx->uax;
1009 
1010  ctx->ix = ctx->uix = 4096 << 4; ctx->uax = 0;
1011  _ssfn_g(ctx, rg, 1);
1012 
1013  if(!ctx->err) {
1014  if(!(ctx->style & 0x200) || ctx->ix == 4096 << 4) ctx->ix = 0;
1015  if(ctx->mode == SSFN_MODE_OUTLINE) {
1016  if(ctx->np > p * h) {
1017  ctx->ret = (ssfn_glyph_t*)SSFN_realloc(ctx->ret, ctx->np + 8 + sizeof(uint8_t*));
1018  if(!ctx->ret) goto erralloc;
1019  }
1020  for(s=i=0; i < ctx->np; i += 2) {
1021  c = ctx->p[i+0] == 0xffff ? 0xff : _ssfn_g2ix(ctx->p[i+0] + bl);
1022  d = ctx->p[i+1] == 0xffff ? 0xff : _ssfn_g2iy(ctx->p[i+1] + bt);
1023  if(s<2 || ctx->ret->data[s-2] != c || ctx->ret->data[s-1] != d) {
1024  ctx->ret->data[s++] = c;
1025  ctx->ret->data[s++] = d;
1026  }
1027  }
1028  ctx->ret->pitch = s;
1029  ctx->ret = (ssfn_glyph_t*)SSFN_realloc(ctx->ret, s + 8 + sizeof(uint8_t*));
1030  if(!ctx->ret) goto erralloc;
1031  } else {
1032  _ssfn_r(ctx);
1033  if(ctx->mode != SSFN_MODE_BITMAP) _ssfn_a(ctx);
1034  if(ctx->style & SSFN_STYLE_STHROUGH) {
1035  if(ctx->ret->w < ctx->ret->adv_x) ctx->ret->w = ctx->ret->adv_x;
1036  SSFN_memset(&ctx->ret->data[(ctx->ret->baseline - (ctx->size >> 2)) * p], 0xFF, (ctx->size/64 + 2) * p);
1037  }
1038  if(ctx->style & SSFN_STYLE_UNDERLINE) {
1039  if(ctx->ret->w < ctx->ret->adv_x) ctx->ret->w = ctx->ret->adv_x;
1040  if(ctx->uax > ctx->ix) ctx->uax = _ssfn_g2i(ctx->uax - ctx->ix);
1041  if(ctx->uix != 4096<<4) ctx->uix = _ssfn_g2i(ctx->uix - ctx->ix);
1042  else ctx->uix = ctx->ret->w + 3;
1043  m = ctx->u * p;
1044  n = ctx->size > 127 ? 2 : 1;
1045  while(n--) {
1046  if(ctx->uix > 3) {
1047  j = ctx->uix - 3;
1048  if(ctx->mode == SSFN_MODE_BITMAP)
1049  for(i=0; i < j; i++) ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1050  else
1051  SSFN_memset(&ctx->ret->data[m], 0xFF, j);
1052  }
1053  if(ctx->uax) {
1054  j = ctx->uax + 2;
1055  if(ctx->mode == SSFN_MODE_BITMAP)
1056  for(i=j; i < ctx->ret->w; i++) ctx->ret->data[m + (i >> 3)] |= 1 << (i & 7);
1057  else
1058  SSFN_memset(&ctx->ret->data[m + j], 0xFF, p - j);
1059  }
1060  m += p;
1061  }
1062  }
1063  }
1064  if(ctx->ret->adv_y)
1065  ctx->ret->baseline = ctx->ret->w >> 1;
1066  } else if(ctx->ret) {
1067  SSFN_free(ctx->ret);
1068  ctx->ret = NULL;
1069  }
1070  return ctx->ret;
1071 }
1072 
1083 int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x, int *y)
1084 {
1085  const ssfn_font_t *font;
1086  uint32_t i, j, k, l, a, b, c;
1087  uint8_t *ptr;
1088  int m;
1089 
1090  if(!ctx || !x || !y) return SSFN_ERR_INVINP;
1091  if(!ctx->f && !ctx->s) return (ctx->err = SSFN_ERR_NOFACE);
1092  font = ctx->s ? ctx->s : ctx->f;
1093  if(unicode && nextunicode && font->kerning_offs) {
1094  ptr = (uint8_t*)font + font->kerning_offs;
1095  a = font->features & SSFN_FEAT_KBIGLKP ? 4 : 3;
1096  b = font->features & SSFN_FEAT_KBIGCHR;
1097  c = font->features & SSFN_FEAT_KBIGCRD;
1098  for(i=0;i<0x110000;i++) {
1099  if(ptr[0] & 0x80) {
1100  if(ptr[0] & 0x40) { i += ptr[1] | ((ptr[0] & 0x3f) << 8); ptr += 2; }
1101  else { i += ptr[0] & 0x3f; ptr++; }
1102  } else {
1103  m = ptr[0] & 0x7F;
1104  if(unicode >= i && unicode <= i+m) {
1105  ptr = (uint8_t*)font + font->kerning_offs + ((a==4?(ptr[3]<<16):0)|(ptr[2]<<8)|ptr[1]);
1106  if(ptr[0] & 0x80) { k = ptr[1] | ((ptr[0] & 0x7f) << 8); ptr += 2; }
1107  else { k = ptr[0] & 0x7F; ptr++; }
1108  for(m=0,a=SSFN_ERR_NOGLYPH,i=j=0;i<=k && j<=nextunicode;i++) {
1109  if(b) { j = ptr[0] | (ptr[1] << 8) | ((ptr[2] & 0x7F) << 16); l = ptr[2] & 0x80; ptr += 3; }
1110  else { j = ptr[0] | ((ptr[1] & 0x7F) << 8); l = ptr[1] & 0x80; ptr += 2; }
1111  if(c) { m = (short)(ptr[0] | (ptr[1] << 8)); ptr += 2; } else { m = (signed char)ptr[0]; ptr++; }
1112  if(j == nextunicode) {
1113  a = SSFN_OK; m = (((m) << (16 - ctx->g)) * ctx->m + (1 << 16) - 1) >> 16;
1114  if(l) *y += m; else *x += m;
1115  }
1116  }
1117  return (ctx->err = a);
1118  }
1119  ptr += a;
1120  i += m;
1121  }
1122  }
1123  }
1124  return (ctx->err = SSFN_ERR_NOGLYPH);
1125 }
1126 
1137 int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w, int *h)
1138 {
1139  char *s;
1140  int u, v, m;
1141 
1142  if(!ctx) return SSFN_ERR_INVINP;
1143  if(!str || !w || !h) return (ctx->err = SSFN_ERR_INVINP);
1144  *w = *h = 0;
1145  m = ctx->mode; ctx->mode = SSFN_MODE_NONE; ctx->m = 0;
1146  for(s = str, u = ssfn_utf8(&s); u;) {
1147  ssfn_render(ctx, u);
1148  if(ctx->err == SSFN_OK) {
1149  *w += ctx->uix;
1150  *h += ctx->uax;
1151  }
1152  v = ssfn_utf8(&s);
1153  if(usekern) ssfn_kern(ctx, u, v, w, h);
1154  u = v;
1155  }
1156  if(!*w) *w = ctx->m;
1157  if(!*h) *h = ctx->m;
1158  ctx->mode = m;
1159  return ctx->err;
1160 }
1161 
1168 int ssfn_mem(ssfn_t *ctx)
1169 {
1170  int i, ret = sizeof(ssfn_t);
1171 
1172  if(!ctx) return 0;
1173 
1174  for(i=0; i<5; i++) ret += ctx->len[i] * sizeof(ssfn_font_t*);
1175  if(ctx->p) ret += ctx->mp * sizeof(uint16_t);
1176  for(i=0; i<256; i++)
1177  if(ctx->r[i]) ret += ctx->nr[i] * sizeof(uint16_t);
1178  if(ctx->h) ret += 8192 * sizeof(uint16_t);
1179  return ret;
1180 }
1181 
1187 void ssfn_free(ssfn_t *ctx)
1188 {
1189  int i;
1190 
1191  if(!ctx) return;
1192 
1193  for(i=0;i<5;i++)
1194  if(ctx->fnt[i]) SSFN_free(ctx->fnt[i]);
1195  if(ctx->p) SSFN_free(ctx->p);
1196  for(i=0; i<256; i++)
1197  if(ctx->r[i]) SSFN_free(ctx->r[i]);
1198  if(ctx->h) SSFN_free(ctx->h);
1199  SSFN_memset(ctx, 0, sizeof(ssfn_t));
1200 }
1201 
1202 #endif
1203 
1204 /*** this function goes for both renderers ***/
1205 #if !defined(SSFN_NOIMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \
1206  defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1213 uint32_t ssfn_utf8(char **s)
1214 {
1215  uint32_t c = **s;
1216 
1217  if((**s & 128) != 0) {
1218  if(!(**s & 32)) { c = ((**s & 0x1F)<<6)|(*(*s+1) & 0x3F); *s += 1; } else
1219  if(!(**s & 16)) { c = ((**s & 0xF)<<12)|((*(*s+1) & 0x3F)<<6)|(*(*s+2) & 0x3F); *s += 2; } else
1220  if(!(**s & 8)) { c = ((**s & 0x7)<<18)|((*(*s+1) & 0x3F)<<12)|((*(*s+2) & 0x3F)<<6)|(*(*s+3) & 0x3F); *s += 3; }
1221  else c = 0;
1222  }
1223  *s += 1;
1224  return c;
1225 }
1226 #endif
1227 
1228 #if defined(SSFN_CONSOLEBITMAP_PALETTE) || defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1229 /*** special console bitmap font renderer (ca. 1k, no dependencies, no memory allocation and no error checking) ***/
1230 
1234 ssfn_font_t *ssfn_font; /* font buffer */
1235 uint8_t *ssfn_dst_ptr; /* screen buffer */
1236 uint32_t ssfn_dst_pitch; /* screen dimensions */
1237 uint32_t ssfn_dst_w = 0;
1238 uint32_t ssfn_dst_h = 0;
1239 uint32_t ssfn_fg; /* colors in screen's native format */
1240 #ifdef SSFN_CONSOLEBITMAP_CLEARBG
1241 uint32_t ssfn_bg;
1242 #endif
1243 uint32_t ssfn_x; /* coordinate to draw to */
1244 uint32_t ssfn_y;
1245 uint32_t ssfn_adv_x; /* advance values */
1246 uint32_t ssfn_adv_y;
1247 
1254 int ssfn_putc(uint32_t unicode)
1255 {
1256  uint32_t i, j, a, b, m, p, t;
1257  uint8_t *rg, *o, *g, *s, *r, y, n;
1258 #ifdef SSFN_CONSOLEBITMAP_CLEARBG
1259  uint8_t w;
1260 #endif
1261 
1262  t = (ssfn_font->quality < 5 && ssfn_font->characters_offs[0] < 65536) ? 4 : (ssfn_font->characters_offs[0] < 1048576 ? 5 : 6);
1263  rg = (uint8_t*)ssfn_font + ssfn_font->characters_offs[0];
1264  ssfn_adv_x = ssfn_adv_y = 0;
1265 
1266  for(j=i=0;i<0x110000;i++) {
1267  if(rg[0] & 0x80) {
1268  n = (rg[0] & 0x3f);
1269  if(rg[0] & 0x40) { i += rg[1] | (n << 8); rg++; } else { i += n; }
1270  rg++;
1271  } else {
1272  if(i == unicode) {
1273  y = rg[9];
1274 #ifdef SSFN_CONSOLEBITMAP_CLEARBG
1275  w = rg[4]; j = 0;
1276  if(ssfn_dst_w && (ssfn_x + w >= ssfn_dst_w)) w = ssfn_dst_w - ssfn_x;
1277  s = ssfn_dst_ptr + (ssfn_y)*ssfn_dst_pitch;
1278 # ifdef SSFN_CONSOLEBITMAP_PALETTE
1279  s += ssfn_x;
1280 # else
1281 # ifdef SSFN_CONSOLEBITMAP_HICOLOR
1282  s += ssfn_x << 1;
1283 # else
1284  s += ssfn_x << 2;
1285 # endif
1286 # endif
1287 #endif
1288  if((ssfn_dst_w && (ssfn_x > ssfn_dst_w)) || (ssfn_dst_h && (ssfn_y + ssfn_font->bbox_bottom >= ssfn_dst_h)))
1289  return SSFN_ERR_INVINP;
1290  n = rg[0]; ssfn_adv_x = rg[6]; ssfn_adv_y = rg[7]; rg += 10;
1291  while(n--) {
1292 #ifndef SSFN_CONSOLEBITMAP_CLEARBG
1293  s = ssfn_dst_ptr + (ssfn_y + y + rg[t-1])*ssfn_dst_pitch;
1294 # ifdef SSFN_CONSOLEBITMAP_PALETTE
1295  s += ssfn_x;
1296 # else
1297 # ifdef SSFN_CONSOLEBITMAP_HICOLOR
1298  s += ssfn_x << 1;
1299 # else
1300  s += ssfn_x << 2;
1301 # endif
1302 # endif
1303 #endif
1304  o = (uint8_t*)ssfn_font; a = ((rg[1] << 8) | rg[0]);
1305  switch(t) {
1306  case 4: o += a; break;
1307  case 5: o += ((rg[2] & 0xF) << 16) | a; break;
1308  default: o += ((rg[3] & 0xF) << 24) | (rg[2] << 16) | a; break;
1309  }
1310  p = ((o[0] & 0xF)+1); a = p << 3; b = o[1]+1; o += 2;
1311  if(ssfn_dst_w && (ssfn_x + a >= ssfn_dst_w)) a = ssfn_dst_w - ssfn_x;
1312 #ifdef SSFN_CONSOLEBITMAP_CLEARBG
1313  for(;j<y+rg[t-1];j++,s+=ssfn_dst_pitch)
1314  for(r=s,i=0;i<w;i++) {
1315 # ifdef SSFN_CONSOLEBITMAP_PALETTE
1316  *((uint8_t*)r) = (uint8_t)ssfn_bg;
1317  r++;
1318 # else
1319 # ifdef SSFN_CONSOLEBITMAP_HICOLOR
1320  *((uint16_t*)r) = (uint16_t)ssfn_bg;
1321  r += 2;
1322 # else
1323  *((uint32_t*)r) = (uint32_t)ssfn_bg;
1324  r += 4;
1325 # endif
1326 # endif
1327  }
1328  b += j;
1329 #else
1330  j = 0;
1331 #endif
1332  for(;j<b;j++,s+=ssfn_dst_pitch,o+=p) {
1333  for(g=o,r=s,m=1,i=0;i<a;i++,m<<=1) {
1334  if(m > 0x80) { g++; m = 1; }
1335 #ifndef SSFN_CONSOLEBITMAP_CLEARBG
1336  if(*g & m)
1337 #endif
1338 #ifdef SSFN_CONSOLEBITMAP_PALETTE
1339  *((uint8_t*)r) = (uint8_t)(
1340 # ifdef SSFN_CONSOLEBITMAP_CLEARBG
1341  *g & m ? ssfn_fg : ssfn_bg
1342 # else
1343  ssfn_bg
1344 # endif
1345  );
1346  r++;
1347 #else
1348 # ifdef SSFN_CONSOLEBITMAP_HICOLOR
1349  *((uint16_t*)r) = (uint16_t)(
1350 # ifdef SSFN_CONSOLEBITMAP_CLEARBG
1351  *g & m ? ssfn_fg : ssfn_bg
1352 # else
1353  ssfn_fg
1354 # endif
1355  );
1356  r += 2;
1357 # else
1358  *((uint32_t*)r) = (uint32_t)(
1359 # ifdef SSFN_CONSOLEBITMAP_CLEARBG
1360  *g & m ? ssfn_fg : ssfn_bg
1361 # else
1362  ssfn_fg
1363 # endif
1364  );
1365  r += 4;
1366 # endif
1367 #endif
1368  }
1369  }
1370  rg += t;
1371  }
1372 #ifdef SSFN_CONSOLEBITMAP_CLEARBG
1373  for(;j<=ssfn_font->bbox_bottom;j++,s+=ssfn_dst_pitch)
1374  for(r=s,i=0;i<w;i++) {
1375 # ifdef SSFN_CONSOLEBITMAP_PALETTE
1376  *((uint8_t*)r) = (uint8_t)ssfn_bg;
1377  r++;
1378 # else
1379 # ifdef SSFN_CONSOLEBITMAP_HICOLOR
1380  *((uint16_t*)r) = (uint16_t)ssfn_bg;
1381  r += 2;
1382 # else
1383  *((uint32_t*)r) = (uint32_t)ssfn_bg;
1384  r += 4;
1385 # endif
1386 # endif
1387  }
1388 #endif
1389  ssfn_x += ssfn_adv_x; ssfn_y += ssfn_adv_y;
1390  return SSFN_OK;
1391  }
1392  rg += rg[0] * t + 10;
1393  j++;
1394  }
1395  }
1396  return SSFN_ERR_NOGLYPH;
1397 }
1398 #endif
1399 
1400 #ifdef __cplusplus
1401 }
1402 #endif
1403 
1404 #endif
Definition: ssfn.h:169