Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
ssfn.h
Go to the documentation of this file.
1/*
2 * ssfn.h
3 * https://gitlab.com/bztsrc/scalable-font2
4 *
5 * Copyright (C) 2020 - 2024 bzt
6 *
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use, copy,
11 * modify, merge, publish, distribute, sublicense, and/or sell copies
12 * of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * @brief Scalable Screen Font renderers
28 *
29 */
30
31#ifndef _SSFN_H_
32#define _SSFN_H_
33
34#define SSFN_VERSION 0x0200
35
36#ifdef __cplusplus
37extern "C" {
38# ifndef __THROW
39# define __THROW throw()
40# endif
41#else
42# ifndef __THROW
43# define __THROW
44# endif
45#endif
46/* if stdint.h was not included before us */
47#if !defined(_STDINT) && !defined(_STDINT_H)
48typedef unsigned char uint8_t;
49typedef unsigned short int uint16_t;
50typedef short int int16_t;
51typedef unsigned int uint32_t;
52#ifndef _UINT64_T
53typedef unsigned long int uint64_t;
54#endif
55#endif
56
57/***** file format *****/
58
59/* magic bytes */
60#define SSFN_MAGIC "SFN2"
61#define SSFN_COLLECTION "SFNC"
62#define SSFN_ENDMAGIC "2NFS"
63
64/* ligatures area */
65#define SSFN_LIG_FIRST 0xF000
66#define SSFN_LIG_LAST 0xF8FF
67
68/* font family group in font type byte */
69#define SSFN_TYPE_FAMILY(x) ((x)&15)
70#define SSFN_FAMILY_SERIF 0
71#define SSFN_FAMILY_SANS 1
72#define SSFN_FAMILY_DECOR 2
73#define SSFN_FAMILY_MONOSPACE 3
74#define SSFN_FAMILY_HAND 4
75
76/* font style flags in font type byte */
77#define SSFN_TYPE_STYLE(x) (((x)>>4)&15)
78#define SSFN_STYLE_REGULAR 0
79#define SSFN_STYLE_BOLD 1
80#define SSFN_STYLE_ITALIC 2
81#define SSFN_STYLE_USRDEF1 4 /* user defined variant 1 */
82#define SSFN_STYLE_USRDEF2 8 /* user defined variant 2 */
83
84/* contour commands */
85#define SSFN_CONTOUR_MOVE 0
86#define SSFN_CONTOUR_LINE 1
87#define SSFN_CONTOUR_QUAD 2
88#define SSFN_CONTOUR_CUBIC 3
89
90/* glyph fragments, kerning groups and hinting grid info */
91#define SSFN_FRAG_CONTOUR 0
92#define SSFN_FRAG_BITMAP 1
93#define SSFN_FRAG_PIXMAP 2
94#define SSFN_FRAG_KERNING 3
95#define SSFN_FRAG_HINTING 4
96
97/* main SSFN header, 32 bytes */
98#ifndef _MSC_VER
99#define _pack __attribute__((packed))
100#else
101#define _pack
102#pragma pack(push)
103#pragma pack(1)
104#endif
105typedef struct {
106 uint8_t magic[4]; /* SSFN magic bytes */
107 uint32_t size; /* total size in bytes */
108 uint8_t type; /* font family and style */
109 uint8_t features; /* format features and revision */
110 uint8_t width; /* overall width of the font */
111 uint8_t height; /* overall height of the font */
112 uint8_t baseline; /* horizontal baseline in grid pixels */
113 uint8_t underline; /* position of under line in grid pixels */
114 uint16_t fragments_offs; /* offset of fragments table */
115 uint32_t characters_offs; /* characters table offset */
116 uint32_t ligature_offs; /* ligatures table offset */
117 uint32_t kerning_offs; /* kerning table offset */
118 uint32_t cmap_offs; /* color map offset */
119} _pack ssfn_font_t;
120#ifdef _MSC_VER
121#pragma pack(pop)
122#endif
123
124/***** renderer API *****/
125#define SSFN_FAMILY_ANY 0xff /* select the first loaded font */
126#define SSFN_FAMILY_BYNAME 0xfe /* select font by its unique name */
127
128/* additional styles not stored in fonts */
129#define SSFN_STYLE_UNDERLINE 16 /* under line glyph */
130#define SSFN_STYLE_STHROUGH 32 /* strike through glyph */
131#define SSFN_STYLE_NOAA 64 /* no anti-aliasing */
132#define SSFN_STYLE_NOKERN 128 /* no kerning */
133#define SSFN_STYLE_NODEFGLYPH 256 /* don't draw default glyph */
134#define SSFN_STYLE_NOCACHE 512 /* don't cache rasterized glyph */
135#define SSFN_STYLE_NOHINTING 1024 /* no auto hinting grid (not used as of now) */
136#define SSFN_STYLE_RTL 2048 /* render right-to-left */
137#define SSFN_STYLE_ABS_SIZE 4096 /* scale absoulte height */
138#define SSFN_STYLE_NOSMOOTH 8192 /* no edge-smoothing for bitmaps */
139
140/* error codes */
141#define SSFN_OK 0 /* success */
142#define SSFN_ERR_ALLOC -1 /* allocation error */
143#define SSFN_ERR_BADFILE -2 /* bad SSFN file format */
144#define SSFN_ERR_NOFACE -3 /* no font face selected */
145#define SSFN_ERR_INVINP -4 /* invalid input */
146#define SSFN_ERR_BADSTYLE -5 /* bad style */
147#define SSFN_ERR_BADSIZE -6 /* bad size */
148#define SSFN_ERR_NOGLYPH -7 /* glyph (or kerning info) not found */
149
150#define SSFN_SIZE_MAX 192 /* biggest size we can render */
151#define SSFN_ITALIC_DIV 4 /* italic angle divisor, glyph top side pushed width / this pixels */
152#define SSFN_PREC 4 /* precision in bits */
153
154/* destination frame buffer context */
155typedef struct {
156 uint8_t *ptr; /* pointer to the buffer */
157 int w; /* width (positive: ARGB, negative: ABGR pixels) */
158 int h; /* height */
159 uint16_t p; /* pitch, bytes per line */
160 int x; /* cursor x */
161 int y; /* cursor y */
162 uint32_t fg; /* foreground color */
163 uint32_t bg; /* background color */
164} ssfn_buf_t;
165
166/* cached bitmap struct */
167#define SSFN_DATA_MAX 65536
168typedef struct {
169 uint16_t p; /* data buffer pitch, bytes per line */
170 uint8_t h; /* data buffer height */
171 uint8_t o; /* overlap of glyph, scaled to size */
172 uint8_t x; /* advance x, scaled to size */
173 uint8_t y; /* advance y, scaled to size */
174 uint8_t a; /* ascender, scaled to size */
175 uint8_t d; /* descender, scaled to size */
176 uint8_t data[SSFN_DATA_MAX]; /* data buffer */
178
179/* character metrics */
180typedef struct {
181 uint8_t t; /* type and overlap */
182 uint8_t n; /* number of fragments */
183 uint8_t w; /* width */
184 uint8_t h; /* height */
185 uint8_t x; /* advance x */
186 uint8_t y; /* advance y */
187} ssfn_chr_t;
188
189#ifdef SSFN_PROFILING
190#include <string.h>
191#include <sys/time.h>
192#endif
193
194/* renderer context */
195typedef struct {
196#ifdef SSFN_MAXLINES
197 const ssfn_font_t *fnt[5][16]; /* static font registry */
198#else
199 const ssfn_font_t **fnt[5]; /* dynamic font registry */
200#endif
201 const ssfn_font_t *s; /* explicitly selected font */
202 const ssfn_font_t *f; /* font selected by best match */
203 ssfn_glyph_t ga; /* glyph sketch area */
204 ssfn_glyph_t *g; /* current glyph pointer */
205#ifdef SSFN_MAXLINES
206 uint16_t p[SSFN_MAXLINES*2];
207#else
208 ssfn_glyph_t ***c[17]; /* glyph cache */
210 char **bufs; /* allocated extra buffers */
211#endif
212 ssfn_chr_t *rc; /* pointer to current character */
213 int numbuf, lenbuf, np, ap, ox, oy, ax;
214 int mx, my, lx, ly; /* move to coordinates, last coordinates */
215 int len[5]; /* number of fonts in registry */
216 int family; /* required family */
217 int style; /* required style */
218 int size; /* required size */
219 int line; /* calculate line height */
220#ifdef SSFN_PROFILING
221 uint64_t lookup, raster, blit, kern;/* profiling accumulators */
222#endif
223} ssfn_t;
224
225/***** API function protoypes *****/
226
227uint32_t ssfn_utf8(char **str); /* decode UTF-8 sequence */
228
229/* normal renderer */
230int ssfn_load(ssfn_t *ctx, const void *data); /* add an SSFN to context */
231int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size); /* select font to use */
232int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str); /* render a glyph to a pixel buffer */
233int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top); /* get bounding box */
234int ssfn_bbox2(ssfn_t *ctx, const char *str, const char *end, int *w, int *h, int *left, int *top);
235ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg); /* renders text to a newly allocated buffer */
236int ssfn_mem(ssfn_t *ctx); /* return how much memory is used */
237void ssfn_free(ssfn_t *ctx); /* free context */
238#define ssfn_error(err) (err<0&&err>=-7?ssfn_errstr[-err]:"Unknown error") /* return string for error code */
239extern const char *ssfn_errstr[];
240
241/* simple renderer */
242extern ssfn_font_t *ssfn_src; /* font buffer */
243extern ssfn_buf_t ssfn_dst; /* destination frame buffer */
244int ssfn_putc(uint32_t unicode); /* render console bitmap font */
245
246/***** renderer implementations *****/
247
248/*** these go for both renderers ***/
249#if (defined(SSFN_IMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \
250 defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)) && !defined(SSFN_COMMON)
251#define SSFN_COMMON
252#define le32(a) (uint32_t)(((uint8_t*)&(a))[0]|(((uint8_t*)&(a))[1]<<8)|(((uint8_t*)&(a))[2]<<16)|(((uint8_t*)&(a))[3]<<24))
253
257const char *ssfn_errstr[] = { "",
258 "Memory allocation error",
259 "Bad file format",
260 "No font face found",
261 "Invalid input value",
262 "Invalid style",
263 "Invalid size",
264 "Glyph not found"
265};
266
273uint32_t ssfn_utf8(char **s)
274{
275 uint32_t c = **s;
276
277 if((**s & 128) != 0) {
278 if(!(**s & 32)) { c = ((**s & 0x1F)<<6)|(*(*s+1) & 0x3F); *s += 1; } else
279 if(!(**s & 16)) { c = ((**s & 0xF)<<12)|((*(*s+1) & 0x3F)<<6)|(*(*s+2) & 0x3F); *s += 2; } else
280 if(!(**s & 8)) { c = ((**s & 0x7)<<18)|((*(*s+1) & 0x3F)<<12)|((*(*s+2) & 0x3F)<<6)|(*(*s+3) & 0x3F); *s += 3; }
281 else c = 0;
282 }
283 (*s)++;
284 return c;
285}
286#endif
287
288#ifdef SSFN_IMPLEMENTATION
289/*** normal renderer (ca. 28k, fully featured with error checking) ***/
290
291# ifndef NULL
292# define NULL (void*)0
293# endif
294# ifndef size_t
295# ifndef __SIZE_TYPE__
296# define __SIZE_TYPE__ uint32_t
297# endif
298 typedef __SIZE_TYPE__ size_t;
299# endif
300# ifndef inline
301# ifdef _MSC_VER
302# define inline __inline
303# else
304# define inline __inline__
305# endif
306# endif
307
308#ifndef _STRING_H_
309extern int memcmp (const void *__s1, const void *__s2, size_t __n) __THROW;
310extern void *memset (void *__s, int __c, size_t __n) __THROW;
311#endif
312
313/* Clang does not have built-ins */
314# ifndef SSFN_memcmp
315# ifdef __builtin_memcmp
316# define SSFN_memcmp __builtin_memcmp
317# else
318# ifndef SSFN_MAXLINES
319# define SSFN_memcmp memcmp
320# else
321static int SSFN_memcmp(const void *__s1, const void *__s2, size_t __n)
322{ unsigned char *a = (unsigned char *)__s1, *b = (unsigned char *)__s2;
323 if(__n > 0) { while(__n-- > 0) { if(*a != *b) { return *a - *b; } a++; b++; } } return 0; }
324# endif
325# endif
326# endif
327
328# ifndef SSFN_memset
329# ifdef __builtin_memset
330# define SSFN_memset __builtin_memset
331# else
332# ifndef SSFN_MAXLINES
333# define SSFN_memset memset
334# else
335static void *SSFN_memset(void *__s, int __c, size_t __n)
336{ unsigned char *a = __s; if(__n > 0) { while(__n-- > 0) *a++ = __c; } return __s; }
337# endif
338# endif
339# endif
340
341# ifndef SSFN_MAXLINES
342
343# ifndef SSFN_realloc
344# ifdef __builtin_realloc
345# define SSFN_realloc __builtin_realloc
346# else
347# define SSFN_realloc realloc
348 extern void *realloc (void *__ptr, size_t __size) __THROW;
349# endif
350# endif
351
352# ifndef SSFN_free
353# ifdef __builtin_free
354# define SSFN_free __builtin_free
355# else
356# define SSFN_free free
357 extern void free (void *p) __THROW;
358# endif
359# endif
360
361# endif /* if !SSFN_MAXLINES */
362
363/*** Private functions ***/
364
365/* parse character table */
366static uint8_t *_ssfn_c(const ssfn_font_t *font, const char *str, int *len, uint32_t *unicode)
367{
368 uint32_t i, j, u = -1U;
369 uint16_t *l;
370 uint8_t *ptr, *s;
371
372 *len = 0; *unicode = 0;
373 if(!font || !font->characters_offs || !str || !*str) return NULL;
374
375 if(font->ligature_offs) {
376 for(l = (uint16_t*)((uint8_t*)font + le32(font->ligature_offs)), i = 0; l[i] && u == -1U; i++) {
377 for(ptr = (uint8_t*)font + l[i], s = (uint8_t*)str; *ptr && *ptr == *s; ptr++, s++);
378 if(!*ptr) { u = SSFN_LIG_FIRST + i; break; }
379 }
380 }
381 if(u == -1U) {
382 /* inline ssfn_utf8 to workaround -O2 bug in gcc 11.1 */
383 s = (uint8_t*)str; u = *s;
384 if((*s & 128) != 0) {
385 if(!(*s & 32)) { u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s++; } else
386 if(!(*s & 16)) { u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 2; } else
387 if(!(*s & 8)) { u = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); s += 3; }
388 else u = 0;
389 }
390 s++;
391 }
392 *len = (int)(s - (uint8_t*)str);
393 *unicode = u;
394 for(ptr = (uint8_t*)font + le32(font->characters_offs), i = 0; i < 0x110000; i++) {
395 if(ptr[0] == 0xFF) { i += 65535; ptr++; }
396 else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; }
397 else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; }
398 else {
399 if(i == u) return ptr;
400 ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5);
401 }
402 }
403 return NULL;
404}
405
406/* add a line to contour */
407static void _ssfn_l(ssfn_t *ctx, int p, int h, int x, int y)
408{
409 if(x < 0 || y < 0 || x >= p || y >= h || (
410 ((ctx->lx + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((x + (1 << (SSFN_PREC-1))) >> SSFN_PREC) &&
411 ((ctx->ly + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((y + (1 << (SSFN_PREC-1))) >> SSFN_PREC))) return;
412#ifdef SSFN_MAXLINES
413 if(ctx->np >= SSFN_MAXLINES*2-2) return;
414#else
415 if(ctx->ap <= ctx->np) {
416 ctx->ap = ctx->np + 512;
417 ctx->p = (uint16_t*)SSFN_realloc(ctx->p, ctx->ap * sizeof(uint16_t));
418 if(!ctx->p) { ctx->ap = ctx->np = 0; return; }
419 }
420#endif
421 if(!ctx->np) {
422 ctx->p[0] = ctx->mx;
423 ctx->p[1] = ctx->my;
424 ctx->np += 2;
425 }
426 ctx->p[ctx->np+0] = x;
427 ctx->p[ctx->np+1] = y;
428 ctx->np += 2;
429 ctx->lx = x; ctx->ly = y;
430}
431
432/* add a Bezier curve to contour */
433static void _ssfn_b(ssfn_t *ctx, int p,int h, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, int l)
434{
435 int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y;
436 if(l<4 && (x0!=x3 || y0!=y3)) {
437 m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0;
438 m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1;
439 m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2;
440 m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y;
441 m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y;
442 m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y;
443 _ssfn_b(ctx, p,h, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, l+1);
444 _ssfn_b(ctx, p,h, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, l+1);
445 }
446 if(l) _ssfn_l(ctx, p,h, x3, y3);
447}
448
449#ifndef SSFN_MAXLINES
450static void _ssfn_fc(ssfn_t *ctx)
451{
452 int i, j, k;
453 if(!ctx) return;
454 for(k = 0; k <= 16; k++)
455 if(ctx->c[k]) {
456 for(j = 0; j < 256; j++)
457 if(ctx->c[k][j]) {
458 for(i = 0; i < 256; i++)
459 if(ctx->c[k][j][i]) SSFN_free(ctx->c[k][j][i]);
460 SSFN_free(ctx->c[k][j]);
461 }
462 SSFN_free(ctx->c[k]);
463 ctx->c[k] = NULL;
464 }
465}
466
467/*
468 * gzip deflate uncompressor from stb_image.h with minor modifications to reduce dependency
469 * stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h
470 */
471#define SSFN__ZFAST_BITS 9
472#define SSFN__ZFAST_MASK ((1 << SSFN__ZFAST_BITS) - 1)
473
474typedef struct
475{
476 uint16_t fast[1 << SSFN__ZFAST_BITS];
477 uint16_t firstcode[16];
478 int maxcode[17];
479 uint16_t firstsymbol[16];
480 unsigned char size[288];
481 uint16_t value[288];
482} _ssfn__zhuffman;
483
484inline static int _ssfn__bitreverse16(int n)
485{
486 n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1);
487 n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2);
488 n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4);
489 n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8);
490 return n;
491}
492
493inline static int _ssfn__bit_reverse(int v, int bits)
494{
495 return _ssfn__bitreverse16(v) >> (16-bits);
496}
497
498static int _ssfn__zbuild_huffman(_ssfn__zhuffman *z, unsigned char *sizelist, int num)
499{
500 int i,k=0;
501 int code, next_code[16], sizes[17];
502
503 SSFN_memset(sizes, 0, sizeof(sizes));
504 SSFN_memset(z->fast, 0, sizeof(z->fast));
505 for(i=0; i < num; ++i)
506 ++sizes[sizelist[i]];
507 sizes[0] = 0;
508 for(i=1; i < 16; ++i)
509 if(sizes[i] > (1 << i))
510 return 0;
511 code = 0;
512 for(i=1; i < 16; ++i) {
513 next_code[i] = code;
514 z->firstcode[i] = (uint16_t) code;
515 z->firstsymbol[i] = (uint16_t) k;
516 code = (code + sizes[i]);
517 if(sizes[i])
518 if(code-1 >= (1 << i)) return 0;
519 z->maxcode[i] = code << (16-i);
520 code <<= 1;
521 k += sizes[i];
522 }
523 z->maxcode[16] = 0x10000;
524 for(i=0; i < num; ++i) {
525 int s = sizelist[i];
526 if(s) {
527 int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
528 uint16_t fastv = (uint16_t) ((s << 9) | i);
529 z->size [c] = (unsigned char) s;
530 z->value[c] = (uint16_t) i;
531 if(s <= SSFN__ZFAST_BITS) {
532 int j = _ssfn__bit_reverse(next_code[s],s);
533 while(j < (1 << SSFN__ZFAST_BITS)) {
534 z->fast[j] = fastv;
535 j += (1 << s);
536 }
537 }
538 ++next_code[s];
539 }
540 }
541 return 1;
542}
543
544typedef struct
545{
546 uint8_t *zbuffer;
547 int num_bits;
548 uint32_t code_buffer;
549
550 char *zout;
551 char *zout_start;
552 char *zout_end;
553
554 _ssfn__zhuffman z_length, z_distance;
555} _ssfn__zbuf;
556
557inline static unsigned char _ssfn__zget8(_ssfn__zbuf *z)
558{
559 return *z->zbuffer++;
560}
561
562static void _ssfn__fill_bits(_ssfn__zbuf *z)
563{
564 do {
565 z->code_buffer |= (unsigned int) _ssfn__zget8(z) << z->num_bits;
566 z->num_bits += 8;
567 } while (z->num_bits <= 24);
568}
569
570inline static unsigned int _ssfn__zreceive(_ssfn__zbuf *z, int n)
571{
572 unsigned int k;
573 if(z->num_bits < n) _ssfn__fill_bits(z);
574 k = z->code_buffer & ((1 << n) - 1);
575 z->code_buffer >>= n;
576 z->num_bits -= n;
577 return k;
578}
579
580static int _ssfn__zhuffman_decode_slowpath(_ssfn__zbuf *a, _ssfn__zhuffman *z)
581{
582 int b,s,k;
583 k = _ssfn__bit_reverse(a->code_buffer, 16);
584 for(s=SSFN__ZFAST_BITS+1; ; ++s)
585 if(k < z->maxcode[s]) break;
586 if(s == 16) return -1;
587 b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
588 if(b >= 288 || z->size[b] != s) return -1;
589 a->code_buffer >>= s;
590 a->num_bits -= s;
591 return z->value[b];
592}
593
594inline static int _ssfn__zhuffman_decode(_ssfn__zbuf *a, _ssfn__zhuffman *z)
595{
596 int b,s;
597 if(a->num_bits < 16) _ssfn__fill_bits(a);
598 b = z->fast[a->code_buffer & SSFN__ZFAST_MASK];
599 if(b) {
600 s = b >> 9;
601 a->code_buffer >>= s;
602 a->num_bits -= s;
603 return b & 511;
604 }
605 return _ssfn__zhuffman_decode_slowpath(a, z);
606}
607
608static int _ssfn__zexpand(_ssfn__zbuf *z, char *zout)
609{
610 char *q;
611 unsigned int cur, limit;
612#ifdef __GNUC__
613#pragma GCC diagnostic push
614#pragma GCC diagnostic ignored "-Wuse-after-free"
615#endif
616 z->zout = zout; cur = (unsigned int) (z->zout - z->zout_start); limit = (unsigned int) (z->zout_end - z->zout_start);
617 if(limit == 16) { if(z->zout_start[0] != 'S' || z->zout_start[1] != 'F' || z->zout_start[2] != 'N') return 0; limit = le32(z->zout_start[4]); } else return 0;
618 q = (char *) SSFN_realloc(z->zout_start, limit);
619 if (q == NULL) return 0;
620 z->zout_start = q; z->zout = q + cur; z->zout_end = q + limit;
621#ifdef __GNUC__
622#pragma GCC diagnostic pop
623#endif
624 return 1;
625}
626
627static int _ssfn__zlength_base[31]={3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0};
628static int _ssfn__zlength_extra[31]={0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0};
629static int _ssfn__zdist_base[32]={1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
630static int _ssfn__zdist_extra[32]={0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
631
632static int _ssfn__parse_huffman_block(_ssfn__zbuf *a)
633{
634 char *zout = a->zout;
635 for(;;) {
636 int z = _ssfn__zhuffman_decode(a, &a->z_length);
637 if(z < 256) {
638 if(z < 0) return 0;
639 if(zout >= a->zout_end) { if(!_ssfn__zexpand(a, zout)) return 0; zout = a->zout; }
640 *zout++ = (char)z;
641 } else {
642 uint8_t *p;
643 int len,dist;
644 if(z == 256) { a->zout = zout; return 1; }
645 if(z >= 286) return 0;
646 z -= 257;
647 len = _ssfn__zlength_base[z];
648 if(_ssfn__zlength_extra[z]) len += _ssfn__zreceive(a, _ssfn__zlength_extra[z]);
649 z = _ssfn__zhuffman_decode(a, &a->z_distance);
650 if(z < 0 || z >= 30) return 0;
651 dist = _ssfn__zdist_base[z];
652 if(_ssfn__zdist_extra[z]) dist += _ssfn__zreceive(a, _ssfn__zdist_extra[z]);
653 if(zout - a->zout_start < dist) return 0;
654 if(zout + len > a->zout_end) {
655 if(!_ssfn__zexpand(a, zout)) return 0;
656 zout = a->zout;
657 }
658 p = (uint8_t *)(zout - dist);
659 if(dist == 1) {uint8_t v = *p;if(len) { do *zout++ = v; while(--len); }}
660 else { if(len) { do *zout++ = *p++; while(--len); } }
661 }
662 }
663}
664
665static int _ssfn__compute_huffman_codes(_ssfn__zbuf *a)
666{
667 static uint8_t length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
668 _ssfn__zhuffman z_codelength;
669 uint8_t lencodes[286+32+137];
670 uint8_t codelength_sizes[19];
671 int i,n;
672 int hlit = _ssfn__zreceive(a,5) + 257;
673 int hdist = _ssfn__zreceive(a,5) + 1;
674 int hclen = _ssfn__zreceive(a,4) + 4;
675 int ntot = hlit + hdist;
676
677 SSFN_memset(codelength_sizes, 0, sizeof(codelength_sizes));
678 for(i=0; i < hclen; ++i) {
679 n = _ssfn__zreceive(a,3);
680 codelength_sizes[length_dezigzag[i]] = (uint8_t)n;
681 }
682 if(!_ssfn__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
683
684 n = 0;
685 while(n < ntot) {
686 int c = _ssfn__zhuffman_decode(a, &z_codelength);
687 if(c < 0 || c >= 19) return 0;
688 if(c < 16) lencodes[n++] = (uint8_t)c;
689 else {
690 uint8_t fill = 0;
691 if(c == 16) {
692 c = _ssfn__zreceive(a,2)+3;
693 if(n == 0) return 0;
694 fill = lencodes[n-1];
695 } else
696 if(c == 17) c = _ssfn__zreceive(a,3)+3; else
697 if(c == 18){ c = _ssfn__zreceive(a,7)+11; } else return 0;
698 if(ntot - n < c) return 0;
699 SSFN_memset(lencodes+n, fill, c);
700 n += c;
701 }
702 }
703 if(n != ntot || !_ssfn__zbuild_huffman(&a->z_length, lencodes, hlit) || !_ssfn__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist))
704 return 0;
705 return 1;
706}
707
708inline static int _ssfn__parse_uncompressed_block(_ssfn__zbuf *a)
709{
710 uint8_t header[4];
711 int len,nlen,k;
712 if(a->num_bits & 7) _ssfn__zreceive(a, a->num_bits & 7);
713 k = 0;
714 while(a->num_bits > 0) {
715 header[k++] = (uint8_t)(a->code_buffer & 255);
716 a->code_buffer >>= 8;
717 a->num_bits -= 8;
718 }
719 if(a->num_bits < 0) return 0;
720 while(k < 4) header[k++] = _ssfn__zget8(a);
721 len = header[1] * 256 + header[0];
722 nlen = header[3] * 256 + header[2];
723 if(nlen != (len ^ 0xffff)) return 0;
724 if(a->zout + len > a->zout_end && !_ssfn__zexpand(a, a->zout)) return 0;
725 for(k = 0; k < len; k++) a->zout[k] = a->zbuffer[k];
726 a->zbuffer += len;
727 a->zout += len;
728 return 1;
729}
730
731static uint8_t _ssfn__zdefault_length[288], _ssfn__zdefault_distance[32];
732static void _ssfn__init_zdefaults(void)
733{
734 int i;
735 for(i=0; i <= 143; ++i) _ssfn__zdefault_length[i] = 8;
736 for( ; i <= 255; ++i) _ssfn__zdefault_length[i] = 9;
737 for( ; i <= 279; ++i) _ssfn__zdefault_length[i] = 7;
738 for( ; i <= 287; ++i) _ssfn__zdefault_length[i] = 8;
739 for(i=0; i <= 31; ++i) _ssfn__zdefault_distance[i] = 5;
740}
741
742static int _ssfn__parse_zlib(_ssfn__zbuf *a)
743{
744 int fin, type;
745 a->num_bits = a->code_buffer = 0;
746 do {
747 fin = _ssfn__zreceive(a,1);
748 type = _ssfn__zreceive(a,2);
749 if(type == 0) { if(!_ssfn__parse_uncompressed_block(a)) return 0; }
750 else if(type == 3) { return 0; }
751 else {
752 if(type == 1) {
753 if(!_ssfn__zbuild_huffman(&a->z_length , _ssfn__zdefault_length , 288)) return 0;
754 if(!_ssfn__zbuild_huffman(&a->z_distance, _ssfn__zdefault_distance, 32)) return 0;
755 } else {
756 if(!_ssfn__compute_huffman_codes(a)) return 0;
757 }
758 if(!_ssfn__parse_huffman_block(a)) return 0;
759 }
760 } while(!fin);
761 return 1;
762}
763
764char *_ssfn_zlib_decode(const char *buffer)
765{
766 _ssfn__zbuf a;
767 char *p = (char *) SSFN_realloc(NULL, 16);
768 if (p == NULL) return NULL;
769 a.zbuffer = (uint8_t *) buffer;
770 a.zout_start = p; a.zout = p; a.zout_end = p + 16;
771 _ssfn__init_zdefaults();
772 if (_ssfn__parse_zlib(&a)) { return a.zout_start; } else { SSFN_free(a.zout_start); return NULL; }
773}
774#endif /* if !SSFN_MAXLINES */
775
776/*** Public API implementation ***/
777
785int ssfn_load(ssfn_t *ctx, const void *data)
786{
787 const ssfn_font_t *font = (const ssfn_font_t *)data;
788 ssfn_font_t *fnt, *end;
789 int fam;
790 uint32_t s;
791#ifndef SSFN_MAXLINES
792 uint8_t c, r, *ptr = (uint8_t *)font;
793#endif
794 if(!ctx || !font)
795 return SSFN_ERR_INVINP;
796 if(((uint8_t *)font)[0] == 0x1f && ((uint8_t *)font)[1] == 0x8b) {
797#ifdef SSFN_MAXLINES
798 return SSFN_ERR_BADFILE;
799#else
800 ptr += 2;
801 if(*ptr++ != 8) return SSFN_ERR_BADFILE;
802 c = *ptr++; ptr += 6;
803 if(c & 4) { r = *ptr++; r += (*ptr++ << 8); ptr += r; }
804 if(c & 8) { while(*ptr++ != 0); }
805 if(c & 16) { while(*ptr++ != 0); }
806 font = (ssfn_font_t*)_ssfn_zlib_decode((const char*)ptr);
807 if(!font) return SSFN_ERR_BADFILE;
808 ctx->bufs = (char**)SSFN_realloc(ctx->bufs, (ctx->numbuf + 1) * sizeof(char*));
809 if(!ctx->bufs) { ctx->numbuf = 0; return SSFN_ERR_ALLOC; }
810 ctx->bufs[ctx->numbuf++] = (char*)font;
811 ctx->lenbuf += le32(font->size);
812#endif
813 }
814 if(!SSFN_memcmp(font->magic, SSFN_COLLECTION, 4)) {
815 end = (ssfn_font_t*)((uint8_t*)font + le32(font->size));
816 for(fnt = (ssfn_font_t*)((uint8_t*)font + 8); fnt < end && !ssfn_load(ctx, (const void *)fnt);
817 fnt = (ssfn_font_t*)((uint8_t*)fnt + le32(fnt->size)));
818 } else {
819 fam = SSFN_TYPE_FAMILY(font->type);
820 s = le32(font->size);
821 if(SSFN_memcmp(font->magic, SSFN_MAGIC, 4) || SSFN_memcmp((uint8_t*)font + s - 4, SSFN_ENDMAGIC, 4) ||
822 fam > SSFN_FAMILY_HAND || le32(font->characters_offs) >= s || le32(font->ligature_offs) >= s ||
823 le32(font->kerning_offs) >= s || le32(font->cmap_offs) >= s) {
824 return SSFN_ERR_BADFILE;
825 } else {
826 ctx->size = fam == SSFN_FAMILY_MONOSPACE ? font->height : font->baseline; if(ctx->size > 32) ctx->size = 16;
827 ctx->len[fam]++;
828#ifdef SSFN_MAXLINES
829 if(ctx->len[fam] > 15) return SSFN_ERR_ALLOC;
830#else
831 ctx->fnt[fam] = (const ssfn_font_t**)SSFN_realloc(ctx->fnt[fam], ctx->len[fam]*sizeof(void*));
832 if(!ctx->fnt[fam]) {
833 ctx->len[fam] = 0;
834 return SSFN_ERR_ALLOC;
835 } else
836#endif
837 ctx->fnt[fam][ctx->len[fam]-1] = font;
838 }
839#ifndef SSFN_MAXLINES
840 _ssfn_fc(ctx);
841#endif
842 }
843 return SSFN_OK;
844}
845
851void ssfn_free(ssfn_t *ctx)
852{
853#ifndef SSFN_MAXLINES
854 int i;
855#endif
856 if(!ctx) return;
857#ifndef SSFN_MAXLINES
858 _ssfn_fc(ctx);
859 if(ctx->bufs) {
860 for(i = 0; i < ctx->numbuf; i++)
861 if(ctx->bufs[i]) SSFN_free(ctx->bufs[i]);
862 SSFN_free(ctx->bufs);
863 }
864 for(i = 0; i < 5; i++)
865 if(ctx->fnt[i]) SSFN_free(ctx->fnt[i]);
866 if(ctx->p) SSFN_free(ctx->p);
867#endif
868 SSFN_memset(ctx, 0, sizeof(ssfn_t));
869}
870
877int ssfn_mem(ssfn_t *ctx)
878{
879#ifdef SSFN_MAXLINES
880 return ctx ? sizeof(ssfn_t) : 0;
881#else
882 int i, j, k, ret = sizeof(ssfn_t);
883
884 if(!ctx) return 0;
885 for(i = 0; i < 5; i++) ret += ctx->len[i] * sizeof(ssfn_font_t*);
886 ret += ctx->lenbuf;
887 for(k = 0; k <= 16; k++) {
888 if(ctx->c[k]) {
889 for(j = 0; j < 256; j++)
890 if(ctx->c[k][j]) {
891 for(i = 0; i < 256; i++)
892 if(ctx->c[k][j][i]) ret += 8 + ctx->c[k][j][i]->p * ctx->c[k][j][i]->h;
893 ret += 256 * sizeof(void*);
894 }
895 ret += 256 * sizeof(void*);
896 }
897 }
898 if(ctx->p) ret += ctx->ap * sizeof(uint16_t);
899 return ret;
900#endif
901}
902
913int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size)
914{
915 int i, j, l;
916
917 if(!ctx) return SSFN_ERR_INVINP;
918#ifndef SSFN_MAXLINES
919 _ssfn_fc(ctx);
920#endif
921 if((style & ~0x5FFF)) return SSFN_ERR_BADSTYLE;
923
924 if(family == SSFN_FAMILY_BYNAME) {
925 if(!name || !name[0]) return SSFN_ERR_INVINP;
926 for(l=0; name[l]; l++);
927 for(i=0; i < 5; i++) {
928 for(j=0; j < ctx->len[i]; j++) {
929 if(!SSFN_memcmp(name, (uint8_t*)&ctx->fnt[i][j]->magic + sizeof(ssfn_font_t), l)) {
930 ctx->s = ctx->fnt[i][j];
931 goto familyfound;
932 }
933 }
934 }
935 return SSFN_ERR_NOFACE;
936 } else {
937 if(family != SSFN_FAMILY_ANY && (family > SSFN_FAMILY_HAND || !ctx->len[family])) return SSFN_ERR_NOFACE;
938 ctx->s = NULL;
939 }
940familyfound:
941 ctx->f = NULL;
942 ctx->family = family;
943 ctx->style = style;
944 ctx->size = size;
945 ctx->line = 0;
946 return SSFN_OK;
947}
948
957
958int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str)
959{
960 ssfn_font_t **fl;
961 uint8_t *ptr = NULL, *frg, *end, *tmp, color, ci = 0, cb = 0, cs, dec[65536];
962 uint16_t r[640];
963 uint32_t unicode, P, O, *Op, *Ol, sR, sG, sB, sA, bA;
964 int ret = 0, i, j, k, l, p, m, n, o, s, x, y, w, h, H, a, A, b, B, nr, uix, uax;
965 int ox, oy, y0, y1, Y0, Y1, x0, x1, X0, X1, X2, xs, ys, yp, pc, fB, fG, fR, fA, bB, bG, bR, dB, dG, dR, dA;
966#ifdef SSFN_PROFILING
967 struct timeval tv0, tv1, tvd;
968 gettimeofday(&tv0, NULL);
969#endif
970#define PUTPIXEL O = *Ol;bR = (O >> 16) & 0xFF;bG = (O >> 8) & 0xFF;bB = O & 0xFF;bA = (O >> 24) & 0xFF;\
971 bB += ((fB - bB) * fA) >> 8;bG += ((fG - bG) * fA) >> 8;bR += ((fR - bR) * fA) >> 8;bA += ((fA - bA) * fA) >> 8;\
972 *Ol = (bA << 24) | (bR << 16) | (bG << 8) | bB;
973
974 if(!ctx || !str) return SSFN_ERR_INVINP;
975 if(!*str) return 0;
976 if(*str == '\r') { dst->x = 0; return 1; }
977 if(*str == '\n') { dst->x = 0; dst->y += ctx->line ? ctx->line : ctx->size; return 1; }
978
979 if(ctx->s) {
980 ctx->f = ctx->s;
981 ptr = _ssfn_c(ctx->f, str, &ret, &unicode);
982 } else {
983 /* find best match */
984 p = ctx->family;
985 ctx->f = NULL;
986again: if(p >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = p;
987 for(; n <= m; n++) {
988 fl = (ssfn_font_t **)ctx->fnt[n];
989 if(ctx->style & 3) {
990 /* check if we have a specific ctx->f for the requested style and size */
991 for(i=0;i<ctx->len[n];i++)
992 if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && fl[i]->height == ctx->size &&
993 (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
994 /* if not, check if we have the requested size (for bitmap fonts) */
995 if(!ptr)
996 for(i=0;i<ctx->len[n];i++)
997 if(fl[i]->height == ctx->size && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
998 /* if neither size+style nor size matched, look for style match */
999 if(!ptr)
1000 for(i=0;i<ctx->len[n];i++)
1001 if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode)))
1002 { ctx->f = fl[i]; break; }
1003 /* if bold italic was requested, check if we have at least bold or italic */
1004 if(!ptr && (ctx->style & 3) == 3)
1005 for(i=0;i<ctx->len[n];i++)
1006 if(((fl[i]->type>>4) & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
1007 }
1008 /* last resort, get the first ctx->f which has a glyph for this multibyte, no matter style */
1009 if(!ptr) {
1010 for(i=0;i<ctx->len[n];i++)
1011 if((ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
1012 }
1013 }
1014 /* if glyph still not found, try any family group */
1015 if(!ptr && p != SSFN_FAMILY_ANY) { p = SSFN_FAMILY_ANY; goto again; }
1016 }
1017 if(!ptr) {
1019 else {
1020 unicode = 0;
1021 if(ctx->family >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = ctx->family;
1022 for(; n <= m && !ptr; n++)
1023 if(ctx->len[n] && ctx->fnt[n][0] && !(*((uint8_t*)ctx->fnt[n][0] + le32(ctx->fnt[n][0]->characters_offs)) & 0x80))
1024 { ctx->f = ctx->fnt[n][0]; ptr = (uint8_t*)ctx->f + le32(ctx->f->characters_offs); }
1025 }
1026 if(!ptr) return SSFN_ERR_NOGLYPH;
1027 }
1028 if(!ctx->f || !ctx->f->height || !ctx->size) return SSFN_ERR_NOFACE;
1029 if((unicode >> 16) > 0x10) return SSFN_ERR_INVINP;
1030 ctx->rc = (ssfn_chr_t*)ptr; ptr += sizeof(ssfn_chr_t);
1031 H = (ctx->style & SSFN_STYLE_ABS_SIZE) || SSFN_TYPE_FAMILY(ctx->f->type) == SSFN_FAMILY_MONOSPACE || !ctx->f->baseline ?
1032 ctx->size : ctx->size * ctx->f->height / ctx->f->baseline;
1033
1034#ifdef SSFN_PROFILING
1035 gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
1036 if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
1037 ctx->lookup += tvd.tv_sec * 1000000L + tvd.tv_usec;
1038 memcpy(&tv0, &tv1, sizeof(struct timeval));
1039#endif
1040 /* render glyph into cache */
1041#ifndef SSFN_MAXLINES
1042 if(!(ctx->style & SSFN_STYLE_NOCACHE) && ctx->c[unicode >> 16] && ctx->c[unicode >> 16][(unicode >> 8) & 0xFF] &&
1043 ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]) {
1044 ctx->g = ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF];
1045 } else
1046#endif
1047 {
1048 h = ctx->style & SSFN_STYLE_NOAA ? H : (ctx->size > ctx->f->height ? (ctx->size + 4) & ~3 : ctx->f->height);
1049 ci = (ctx->style & SSFN_STYLE_ITALIC) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_ITALIC);
1050 cb = (ctx->style & SSFN_STYLE_BOLD) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_BOLD) ? (ctx->f->height+64)>>6 : 0;
1051 w = (ctx->rc->w * h + ctx->f->height - 1) / ctx->f->height;
1052 if(w > SSFN_SIZE_MAX) { h = h * SSFN_SIZE_MAX / w; w = SSFN_SIZE_MAX; }
1053 p = w + (ci ? h / SSFN_ITALIC_DIV : 0) + cb;
1054 /* failsafe, should never happen */
1055 if(p * h >= SSFN_DATA_MAX) return SSFN_ERR_BADSIZE;
1056#ifndef SSFN_MAXLINES
1057 if(!(ctx->style & SSFN_STYLE_NOCACHE)) {
1058 if(!ctx->c[unicode >> 16]) {
1059 ctx->c[unicode >> 16] = (ssfn_glyph_t***)SSFN_realloc(NULL, 256 * sizeof(void*));
1060 if(!ctx->c[unicode >> 16]) return SSFN_ERR_ALLOC;
1061 SSFN_memset(ctx->c[unicode >> 16], 0, 256 * sizeof(void*));
1062 }
1063 if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF]) {
1064 ctx->c[unicode >> 16][(unicode >> 8) & 0xFF] = (ssfn_glyph_t**)SSFN_realloc(NULL, 256 * sizeof(void*));
1065 if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF]) return SSFN_ERR_ALLOC;
1066 SSFN_memset(ctx->c[unicode >> 16][(unicode >> 8) & 0xFF], 0, 256 * sizeof(void*));
1067 }
1068 ctx->g = ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF] = (ssfn_glyph_t*)SSFN_realloc(NULL, p * h + 8);
1069 if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]) return SSFN_ERR_ALLOC;
1070 } else
1071#endif
1072 ctx->g = &ctx->ga;
1073 x = (ctx->rc->x > 0 && ci ? (ctx->f->height - ctx->f->baseline) * h / SSFN_ITALIC_DIV / ctx->f->height : 0);
1074 ctx->g->p = p;
1075 ctx->g->h = h;
1076 ctx->g->x = (ctx->rc->x + x > 255 ? 255 : ctx->rc->x + x);
1077 ctx->g->y = ctx->rc->y;
1078 ctx->g->o = (ctx->rc->t & 0x3F) + x;
1079 SSFN_memset(&ctx->g->data, 0xFF, p * h);
1080 color = 0xFE; ctx->g->a = ctx->g->d = 0;
1081 for(n = 0; n < ctx->rc->n; n++) {
1082 if(ptr[0] == 255 && ptr[1] == 255) { color = ptr[2]; ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; }
1083 x = ((ptr[0] + cb) << SSFN_PREC) * h / ctx->f->height; y = (ptr[1] << SSFN_PREC) * h / ctx->f->height;
1084 if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; }
1085 else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; }
1086 frg = (uint8_t*)ctx->f + m;
1087 if(!(frg[0] & 0x80)) {
1088 /* contour */
1089 j = (frg[0] & 0x3F);
1090 if(frg[0] & 0x40) { j <<= 8; j |= frg[1]; frg++; }
1091 j++; frg++; tmp = frg; frg += (j+3)/4; ctx->np = 0;
1092 for(i = 0; i < j; i++) {
1093 k = (frg[0] << SSFN_PREC) * h / ctx->f->height + x; m = (frg[1] << SSFN_PREC) * h / ctx->f->height + y;
1094 switch((tmp[i >> 2] >> ((i & 3) << 1)) & 3) {
1095 case SSFN_CONTOUR_MOVE: ctx->mx = ctx->lx = k; ctx->my = ctx->ly = m; frg += 2; break;
1096 case SSFN_CONTOUR_LINE: _ssfn_l(ctx, p << SSFN_PREC, h << SSFN_PREC, k, m); frg += 2; break;
1097 case SSFN_CONTOUR_QUAD:
1098 a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y;
1099 _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, ((a-ctx->lx)/2)+ctx->lx,
1100 ((A-ctx->ly)/2)+ctx->ly, ((k-a)/2)+a,((A-m)/2)+m, k,m, 0);
1101 frg += 4;
1102 break;
1103 case SSFN_CONTOUR_CUBIC:
1104 a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y;
1105 b = (frg[4] << SSFN_PREC) * h / ctx->f->height + x; B = (frg[5] << SSFN_PREC) * h / ctx->f->height + y;
1106 _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, a,A, b,B, k,m, 0);
1107 frg += 6;
1108 break;
1109 }
1110 }
1111 /* close path */
1112 if(ctx->mx != ctx->lx || ctx->my != ctx->ly) { ctx->p[ctx->np+0] = ctx->mx; ctx->p[ctx->np+1] = ctx->my; ctx->np += 2; }
1113 /* add rasterized vector layers to cached glyph */
1114 if(ctx->np > 4) {
1115 for(b = A = B = o = 0; b < h; b++, B += p) {
1116 a = b << SSFN_PREC;
1117 for(nr = 0, i = 0; i < ctx->np - 3; i += 2) {
1118 if( (ctx->p[i+1] < a && ctx->p[i+3] >= a) ||
1119 (ctx->p[i+3] < a && ctx->p[i+1] >= a)) {
1120 if((ctx->p[i+1] >> SSFN_PREC) == (ctx->p[i+3] >> SSFN_PREC))
1121 x = (((int)ctx->p[i]+(int)ctx->p[i+2])>>1);
1122 else
1123 x = ((int)ctx->p[i]) + ((a - (int)ctx->p[i+1])*
1124 ((int)ctx->p[i+2] - (int)ctx->p[i])/
1125 ((int)ctx->p[i+3] - (int)ctx->p[i+1]));
1126 x >>= SSFN_PREC;
1127 if(ci) x += (h - b) / SSFN_ITALIC_DIV;
1128 if(cb && !o) {
1129 if(ctx->g->data[B + x] != color) { o = -cb; A = cb; }
1130 else { o = cb; A = -cb; }
1131 }
1132 for(k = 0; k < nr && x > r[k]; k++);
1133 for(l = nr; l > k; l--) r[l] = r[l-1];
1134 r[k] = x;
1135 nr++;
1136 }
1137 }
1138 if(nr > 1 && nr & 1) { r[nr - 2] = r[nr - 1]; nr--; }
1139 if(nr) {
1140 if(ctx->g->d < y + b) ctx->g->d = y + b;
1141 for(i = 0; i < nr - 1; i += 2) {
1142 l = r[i] + o; m = r[i + 1] + A;
1143 if(l < 0) l = 0;
1144 if(m > p) m = p;
1145 if(i > 0 && l < r[i - 1] + A) l = r[i - 1] + A;
1146 for(; l < m; l++)
1147 ctx->g->data[B + l] = ctx->g->data[B + l] == color ? 0xFF : color;
1148 }
1149 }
1150 }
1151 }
1152 } else if((frg[0] & 0x60) == 0x00) {
1153 /* bitmap */
1154 B = ((frg[0] & 0x1F) + 1) << 3; A = frg[1] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC;
1155 b = B * h / ctx->f->height; a = A * h / ctx->f->height;
1156 if(ctx->g->d < y + a) ctx->g->d = y + a;
1157 frg += 2;
1158 for(j = 0; j < a; j++) {
1159 k = j * A / a;
1160 l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0);
1161 for(i = 0; i < b; i++) {
1162 m = i * B / b;
1163 if(frg[(k * B + m) >> 3] & (1 << (m & 7))) {
1164 for(o = 0; o <= cb; o++)
1165 ctx->g->data[l + i + o] = color;
1166 }
1167 }
1168 }
1169 if(!(ctx->style & (SSFN_STYLE_NOAA|SSFN_STYLE_NOSMOOTH))) {
1170 m = color == 0xFD ? 0xFC : 0xFD; o = y * p + p + x;
1171 for(k = h; k > ctx->f->height + 4; k -= 2*ctx->f->height) {
1172 for(j = 1, l = o; j < a - 1; j++, l += p)
1173 for(i = 1; i < b - 1; i++) {
1174 if(ctx->g->data[l + i] == 0xFF && (ctx->g->data[l + i - p] == color ||
1175 ctx->g->data[l + i + p] == color) && (ctx->g->data[l + i - 1] == color ||
1176 ctx->g->data[l + i + 1] == color)) ctx->g->data[l + i] = m;
1177 }
1178 for(j = 1, l = o; j < a - 1; j++, l += p)
1179 for(i = 1; i < b - 1; i++) {
1180 if(ctx->g->data[l + i] == m) ctx->g->data[l + i] = color;
1181 }
1182 }
1183 }
1184 } else if((frg[0] & 0x60) == 0x20) {
1185 /* pixmap */
1186 k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; B = frg[2] + 1; A = frg[3] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC;
1187 b = B * h / ctx->f->height; a = A * h / ctx->f->height;
1188 if(ctx->g->d < y + a) ctx->g->d = y + a;
1189 frg += 4; end = frg + k; i = 0;
1190 while(frg < end) {
1191 l = ((*frg++) & 0x7F) + 1;
1192 if(frg[-1] & 0x80) {
1193 while(l--) dec[i++] = *frg;
1194 frg++;
1195 } else while(l--) dec[i++] = *frg++;
1196 }
1197 for(j = 0; j < a; j++) {
1198 k = j * A / a * B;
1199 l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0);
1200 for(i = 0; i < b; i++) {
1201 m = dec[k + i * B / b];
1202 if(m != 0xFF) ctx->g->data[l + i] = m;
1203 }
1204 }
1205 }
1206 color = 0xFE;
1207 }
1208 ctx->g->a = ctx->f->baseline;
1209 if(ctx->g->d > ctx->g->a + 1) ctx->g->d -= ctx->g->a + 1; else ctx->g->d = 0;
1210#ifdef SSFN_DEBUGGLYPH
1211 printf("\nU+%06X size %d p %d h %d base %d under %d overlap %d ascender %d descender %d advance x %d advance y %d cb %d\n",
1212 unicode, ctx->size,p,h,ctx->f->baseline,ctx->f->underline,ctx->g->o,ctx->g->a,ctx->g->d,ctx->g->x,ctx->g->y,cb);
1213 for(j = 0; j < h; j++) { printf("%3d: ", j); for(i = 0; i < p; i++) { if(ctx->g->data[j*p+i] == 0xFF) printf(j == ctx->g->a ? "_" : "."); else printf("%x", ctx->g->data[j*p+i] & 0xF); } printf("\n"); }
1214#endif
1215#ifdef SSFN_PROFILING
1216 gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
1217 if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
1218 ctx->raster += tvd.tv_sec * 1000000L + tvd.tv_usec;
1219 memcpy(&tv0, &tv1, sizeof(struct timeval));
1220#endif
1221 }
1222 if(dst) {
1223 /* blit glyph from cache into buffer */
1224 h = H;
1225 if(h > ctx->line) ctx->line = h;
1226 w = ctx->g->p * h / ctx->g->h;
1227 s = ((ctx->g->x - ctx->g->o) * h + ctx->f->height - 1) / ctx->f->height;
1228 n = ctx->size > 16 ? 2 : 1;
1229 if(w < n) w = n;
1230 if(s < n) s = n;
1231 if(ctx->g->x) {
1232 ctx->ox = ox = ((ctx->g->o * h + ctx->f->height - 1) / ctx->f->height) + (ctx->style & SSFN_STYLE_RTL ? w : 0);
1233 ctx->oy = oy = (ctx->g->a * h + ctx->f->height - 1) / ctx->f->height;
1234 } else { ctx->ox = ox = w / 2; ctx->oy = oy = 0; }
1235 if(dst->ptr) {
1236 j = dst->w < 0 ? -dst->w : dst->w;
1237 cs = dst->w < 0 ? 16 : 0;
1238 cb = (h + 64) >> 6; uix = w > s ? w : s; uax = 0;
1239 n = (ctx->f->underline * h + ctx->f->height - 1) / ctx->f->height;
1240#ifdef SSFN_DEBUGGLYPH
1241 printf("Scaling to w %d h %d (glyph %d %d, cache %d %d, font %d)\n",w,h,ctx->rc->w,ctx->rc->h,ctx->g->p,ctx->g->h,ctx->f->height);
1242#endif
1243 fR = (dst->fg >> 16) & 0xFF; fG = (dst->fg >> 8) & 0xFF; fB = (dst->fg >> 0) & 0xFF; fA = (dst->fg >> 24) & 0xFF;
1244 bR = (dst->bg >> 16) & 0xFF; bG = (dst->bg >> 8) & 0xFF; bB = (dst->bg >> 0) & 0xFF; O = 0xFF000000;
1245 Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy) + ((dst->x - ox) << 2));
1246 for (y = 0; y < h && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) {
1247 if(dst->y + y - oy < 0) continue;
1248 y0 = (y << 8) * ctx->g->h / h; Y0 = y0 >> 8; y1 = ((y + 1) << 8) * ctx->g->h / h; Y1 = y1 >> 8; Ol = Op;
1249 for (x = 0; x < w && dst->x + x - ox < j; x++, Ol++) {
1250 if(dst->x + x - ox < 0) continue;
1251 m = 0; sR = sG = sB = sA = bA = 0;
1252 if(!dst->bg) {
1253 /* real linear frame buffers should be accessed only as uint32_t on 32 bit boundary */
1254 O = *Ol;
1255 bA = (O >> 24) & 0xFF;
1256 bR = (O >> (16 - cs)) & 0xFF;
1257 bG = (O >> 8) & 0xFF;
1258 bB = (O >> cs) & 0xFF;
1259 }
1260 x0 = (x << 8) * ctx->g->p / w; X0 = x0 >> 8; x1 = ((x + 1) << 8) * ctx->g->p / w; X1 = x1 >> 8;
1261 for(ys = y0; ys < y1; ys += 256) {
1262 if(ys >> 8 == Y0) { yp = 256 - (ys & 0xFF); ys &= ~0xFF; if(yp > y1 - y0) yp = y1 - y0; }
1263 else if(ys >> 8 == Y1) yp = y1 & 0xFF; else yp = 256;
1264 X2 = (ys >> 8) * ctx->g->p;
1265 for(xs = x0; xs < x1; xs += 256) {
1266 if (xs >> 8 == X0) {
1267 k = 256 - (xs & 0xFF); xs &= ~0xFF; if(k > x1 - x0) k = x1 - x0; pc = k == 256 ? yp : (k * yp)>>8;
1268 } else
1269 if (xs >> 8 == X1) { k = x1 & 0xFF; pc = k == 256 ? yp : (k * yp) >> 8; }
1270 else pc = yp;
1271 m += pc;
1272 k = ctx->g->data[X2 + (xs >> 8)];
1273 if(k == 0xFF) {
1274 sB += bB * pc; sG += bG * pc; sR += bR * pc; sA += 255;
1275 } else {
1276 if(k == 0xFE || !ctx->f->cmap_offs) {
1277 dB = fB; dG = fG; dR = fR; dA = fA;
1278 } else {
1279 P = *((uint32_t*)((uint8_t*)ctx->f + le32(ctx->f->cmap_offs) + (k << 2)));
1280 dR = (P >> 16) & 0xFF; dG = (P >> 8) & 0xFF; dB = (P >> 0) & 0xFF; dA = (P >> 24) & 0xFF;
1281 }
1282 if(dA == 255) {
1283 sB += dB * pc; sG += dG * pc; sR += dR * pc; sA += dA * pc;
1284 } else {
1285 a = 255 - dA;
1286 sB += ((dB * dA + bB * a) * pc + 255)>>8; sG += ((dG * dA + bG * a) * pc + 255)>>8;
1287 sR += ((dR * dA + bR * a) * pc + 255)>>8; sA += dA * pc;
1288 }
1289 }
1290 }
1291 }
1292 if(m) { sR /= m; sG /= m; sB /= m; sA /= m; } else { sR >>= 8; sG >>= 8; sB >>= 8; sA >>= 8; }
1293 if(ctx->style & SSFN_STYLE_NOAA) sA = sA > 127 ? 255 : 0;
1294 if(sA > 15) {
1295 *Ol = ((sA > 255 ? 255 : (sA > bA ? sA : bA)) << 24) |
1296 ((sR > 255 ? 255 : sR) << (16 - cs)) | ((sG > 255 ? 255 : sG) << 8) | ((sB > 255 ? 255 : sB) << cs);
1297 if(y == n) { if(uix > x) { uix = x; } if(uax < x) { uax = x; } }
1298 }
1299 }
1300 }
1301 if(ctx->style & SSFN_STYLE_UNDERLINE) {
1302 uix -= cb + 1; uax += cb + 2;
1303 if(uax < uix) uax = uix + 1;
1304 k = (w > s ? w : s);
1305 Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2));
1306 for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) {
1307 if(dst->y + y - oy < 0) continue;
1308 for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) {
1309 if(dst->x + x - ox < 0 || (x > uix && x < uax)) continue;
1310 PUTPIXEL;
1311 }
1312 }
1313 }
1314 if(ctx->style & SSFN_STYLE_STHROUGH) {
1315 n = (h >> 1); k = (w > s ? w : s) + 1;
1316 Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2));
1317 for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) {
1318 if(dst->y + y - oy < 0) continue;
1319 for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) {
1320 if(dst->x + x - ox < 0) continue;
1321 PUTPIXEL;
1322 }
1323 }
1324 }
1325#ifdef SSFN_PROFILING
1326 gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec;tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
1327 if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
1328 ctx->blit += tvd.tv_sec * 1000000L + tvd.tv_usec;
1329 memcpy(&tv0, &tv1, sizeof(struct timeval));
1330#endif
1331 }
1332 /* add advance and kerning */
1333 ctx->ax = (ctx->style & SSFN_STYLE_RTL ? -s : s);
1334 dst->x += ctx->ax;
1335 dst->y += (ctx->g->y * h + ctx->f->height - 1) / ctx->f->height;
1336 ptr = (uint8_t*)str + ret;
1337 if(!(ctx->style & SSFN_STYLE_NOKERN) && ctx->f->kerning_offs && _ssfn_c(ctx->f, (const char*)ptr, &i, &P) && P > 32) {
1338 ptr = (uint8_t*)ctx->rc + sizeof(ssfn_chr_t);
1339 /* check all kerning fragments, because we might have both vertical and horizontal kerning offsets */
1340 for(n = 0; n < ctx->rc->n; n++) {
1341 if(ptr[0] == 255 && ptr[1] == 255) { ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; }
1342 x = ptr[0];
1343 if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; }
1344 else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; }
1345 frg = (uint8_t*)ctx->f + m;
1346 if((frg[0] & 0xE0) == 0xC0) {
1347 k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; frg += 2;
1348 while(k--) {
1349 m = ((frg[2] & 0xF) << 16) | (frg[1] << 8) | frg[0];
1350 if(P >= (uint32_t)m && P <= (uint32_t)(((frg[5] & 0xF) << 16) | (frg[4] << 8) | frg[3])) {
1351 P -= m;
1352 m = le32(ctx->f->kerning_offs) + ((((frg[2] >> 4) & 0xF) << 24) | (((frg[5] >> 4) & 0xF) << 16) | (frg[7] << 8) | frg[6]);
1353 tmp = (uint8_t*)ctx->f + m;
1354 while(tmp < (uint8_t*)ctx->f + ctx->f->size - 4) {
1355 if((tmp[0] & 0x7F) < P) {
1356 P -= (tmp[0] & 0x7F) + 1;
1357 tmp += 2 + (tmp[0] & 0x80 ? 0 : tmp[0] & 0x7F);
1358 } else {
1359 y = (int)((signed char)tmp[1 + ((tmp[0] & 0x80) ? 0 : P)]) * h / ctx->f->height;
1360 if(x) dst->x += y; else dst->y += y;
1361 break;
1362 }
1363 }
1364 break;
1365 }
1366 frg += 8;
1367 }
1368 }
1369 }
1370#ifdef SSFN_PROFILING
1371 gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
1372 if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
1373 ctx->kern += tvd.tv_sec * 1000000L + tvd.tv_usec;
1374#endif
1375 }
1376 }
1377 return ret;
1378}
1379
1391int ssfn_bbox2(ssfn_t *ctx, const char *str, const char *end, int *w, int *h, int *left, int *top)
1392{
1393 ssfn_buf_t buf;
1394 int ret, f = 1, l = 0, t = 0;
1395
1396 if(!ctx || !str) return SSFN_ERR_INVINP;
1397 if(w) {*w = 0;} if(h) {*h = 0;} if(top) {*top = 0;} if(left) {*left = 0;}
1398 if(!*str) return SSFN_OK;
1399 SSFN_memset(&buf, 0, sizeof(ssfn_buf_t)); ctx->line = 0;
1400 while((!end || str < end) && (ret = ssfn_render(ctx, &buf, str))) {
1401 if(ret < 0 || !ctx->g) return ret;
1402 if(f) { f = 0; l = ctx->ox; buf.x += l; }
1403 if(ctx->g->x) {
1404 if(ctx->oy > t) t = ctx->oy;
1405 } else {
1406 if(buf.w < ctx->g->p) buf.w = ctx->g->p;
1407 buf.h += ctx->g->y ? ctx->g->y : ctx->g->h;
1408 }
1409 str += ret;
1410 }
1411 if((ctx->style & SSFN_STYLE_ITALIC) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_ITALIC))
1412 buf.x += ctx->size / SSFN_ITALIC_DIV - l;
1413 if(ctx->g->x) { if(w) {*w = buf.x;} if(h) {*h = ctx->line;} if(left) {*left = l;} if(top) {*top = t;} }
1414 else { if(w) {*w = buf.w;} if(h) {*h = buf.y;} if(top) {*top = 0;} if(left) {*left = 0;} }
1415 return SSFN_OK;
1416}
1417int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top) { return ssfn_bbox2(ctx,str,NULL,w,h,left,top); }
1418
1426ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg)
1427{
1428#ifndef SSFN_MAXLINES
1429 ssfn_buf_t *buf;
1430 int ret;
1431
1432 if(!ctx || !str) return NULL;
1433 buf = (ssfn_buf_t*)SSFN_realloc(NULL, sizeof(ssfn_buf_t));
1434 if(!buf) return NULL;
1435 SSFN_memset(buf, 0, sizeof(ssfn_buf_t));
1436 buf->fg = fg;
1437 if(!*str || ssfn_bbox(ctx, str, (int*)&buf->w, (int*)&buf->h, (int*)&buf->x, (int*)&buf->y) != SSFN_OK)
1438 return buf;
1439 buf->p = buf->w * sizeof(uint32_t);
1440 buf->ptr = (uint8_t*)SSFN_realloc(NULL, buf->p * buf->h);
1441 SSFN_memset(buf->ptr, 0, buf->p * buf->h);
1442 while((ret = ssfn_render(ctx, buf, str)) > 0)
1443 str += ret;
1444 if(ret != SSFN_OK) { SSFN_free(buf->ptr); SSFN_free(buf); return NULL; }
1445 return buf;
1446#else
1447 (void)ctx; (void)str; (void)fg;
1448 return NULL;
1449#endif
1450}
1451
1452#endif /* SSFN_IMPLEMENTATION */
1453
1454#if defined(SSFN_CONSOLEBITMAP_PALETTE) || defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
1455/*** special console bitmap font renderer (ca. 1.5k, no dependencies, no memory allocation and no error checking) ***/
1456
1460ssfn_font_t *ssfn_src; /* font buffer with an inflated bitmap font */
1461ssfn_buf_t ssfn_dst; /* destination frame buffer */
1462
1469int ssfn_putc(uint32_t unicode)
1470{
1471# ifdef SSFN_CONSOLEBITMAP_PALETTE
1472# define SSFN_PIXEL uint8_t
1473# else
1474# ifdef SSFN_CONSOLEBITMAP_HICOLOR
1475# define SSFN_PIXEL uint16_t
1476# else
1477# define SSFN_PIXEL uint32_t
1478# endif
1479# endif
1480 register SSFN_PIXEL *o, *p;
1481 register uint8_t *ptr, *chr = NULL, *frg;
1482 register int i, j, k, l, m, y = 0, w, s = ssfn_dst.p / sizeof(SSFN_PIXEL);
1483
1484 if(!ssfn_src || ssfn_src->magic[0] != 'S' || ssfn_src->magic[1] != 'F' || ssfn_src->magic[2] != 'N' ||
1485 ssfn_src->magic[3] != '2' || !ssfn_dst.ptr || !ssfn_dst.p) return SSFN_ERR_INVINP;
1486 w = ssfn_dst.w < 0 ? -ssfn_dst.w : ssfn_dst.w;
1487 for(ptr = (uint8_t*)ssfn_src + le32(ssfn_src->characters_offs), i = 0; i < 0x110000; i++) {
1488 if(ptr[0] == 0xFF) { i += 65535; ptr++; }
1489 else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; }
1490 else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; }
1491 else { if((uint32_t)i == unicode) { chr = ptr; break; } ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5); }
1492 }
1493#ifdef SSFN_CONSOLEBITMAP_CONTROL
1494 i = ssfn_src->height; j = ssfn_dst.h - i - (ssfn_dst.h % i);
1495 if(chr && w) {
1496 if(unicode == '\t') ssfn_dst.x -= ssfn_dst.x % chr[4];
1497 if(ssfn_dst.x + chr[4] > w) { ssfn_dst.x = 0; ssfn_dst.y += i; }
1498 }
1499 if(unicode == '\n') ssfn_dst.y += i;
1500 if(j > 0 && ssfn_dst.y > j) {
1501 ssfn_dst.y = j;
1502 for(k = 0; k < j; k++)
1503 for(l = 0; l < ssfn_dst.p; l++) ssfn_dst.ptr[k * ssfn_dst.p + l] = ssfn_dst.ptr[(k + i) * ssfn_dst.p + l];
1504 }
1505 if(unicode == '\r' || unicode == '\n') { ssfn_dst.x = 0; return SSFN_OK; }
1506#endif
1507 if(!chr) return SSFN_ERR_NOGLYPH;
1508 ptr = chr + 6; o = (SSFN_PIXEL*)(ssfn_dst.ptr + ssfn_dst.y * ssfn_dst.p + ssfn_dst.x * sizeof(SSFN_PIXEL));
1509 for(i = 0; i < chr[1]; i++, ptr += chr[0] & 0x40 ? 6 : 5) {
1510 if(ptr[0] == 255 && ptr[1] == 255) continue;
1511 frg = (uint8_t*)ssfn_src + (chr[0] & 0x40 ? ((ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]) :
1512 ((ptr[4] << 16) | (ptr[3] << 8) | ptr[2]));
1513 if((frg[0] & 0xE0) != 0x80) continue;
1514 if(ssfn_dst.bg) {
1515 for(; y < ptr[1] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) {
1516 for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++) *p = ssfn_dst.bg;
1517 }
1518 } else { o += (int)(ptr[1] - y) * s; y = ptr[1]; }
1519 k = ((frg[0] & 0x1F) + 1) << 3; j = frg[1] + 1; frg += 2;
1520 for(m = 1; j && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); j--, y++, o += s)
1521 for(p = o, l = 0; l < k; l++, p++, m <<= 1) {
1522 if(m > 0x80) { frg++; m = 1; }
1523 if(ssfn_dst.x + l >= 0 && (!w || ssfn_dst.x + l < w)) {
1524 if(*frg & m) *p = ssfn_dst.fg; else
1525 if(ssfn_dst.bg) *p = ssfn_dst.bg;
1526 }
1527 }
1528 }
1529 if(ssfn_dst.bg)
1530 for(; y < chr[3] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) {
1531 for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++) *p = ssfn_dst.bg;
1532 }
1533 ssfn_dst.x += chr[4]; ssfn_dst.y += chr[5];
1534 return SSFN_OK;
1535}
1536
1537#endif /* SSFN_CONSOLEBITMAP */
1538
1539#ifdef __cplusplus
1540}
1541/*** SSFN C++ Wrapper Class ***/
1542#ifndef SSFN_NO_CPP_STD_STRING
1543#include <string>
1544#endif
1545
1546namespace SSFN {
1547#ifndef SSFN_IMPLEMENTATION
1548 class Font {
1549 public:
1550 Font();
1551 ~Font();
1552
1553 public:
1554 int Load(const void *data, int len);
1555 int Select(int family, const char *name, int style, int size);
1556 int Render(ssfn_buf_t *dst, const char *str);
1557 int BBox(const char *str, int *w, int *h, int *left, int *top);
1558 int BBox(const char *str, const char *end, int *w, int *h, int *left, int *top);
1559 ssfn_buf_t *Text(const char *str, unsigned int fg);
1560 int LineHeight();
1561 int Mem();
1562#ifndef SSFN_NO_CPP_STD_STRING
1563 int Load(const std::string &data);
1564 int Select(int family, const std::string &name, int style, int size);
1565 int Render(ssfn_buf_t *dst, const std::string &str);
1566 int BBox(const std::string &str, int *w, int *h, int *left, int *top);
1567 ssfn_buf_t *Text(const std::string &str, unsigned int fg);
1568 const std::string ErrorStr(int err);
1569#endif
1570 };
1571#else
1572 class Font {
1573 private:
1574 ssfn_t ctx;
1575
1576 public:
1577 Font() { SSFN_memset(&this->ctx, 0, sizeof(ssfn_t)); }
1578 ~Font() { ssfn_free(&this->ctx); }
1579
1580 public:
1581 int Load(const void *data) { return ssfn_load(&this->ctx, data); }
1582 int Select(int family, char *name, int style, int size) { return ssfn_select(&this->ctx,family,name,style,size); }
1583 int Render(ssfn_buf_t *dst, const char *str) { return ssfn_render(&this->ctx, dst, str); }
1584 int BBox(const char *str, int *w, int *h, int *left, int *top) { return ssfn_bbox(&this->ctx,str,w,h,left,top); }
1585 int BBox(const char *str, const char *end, int *w, int *h, int *left, int *top) { return ssfn_bbox2(&this->ctx,str,end,w,h,left,top); }
1586 ssfn_buf_t *Text(const char *str, unsigned int fg) { return ssfn_text(&this->ctx, str, fg); }
1587 int LineHeight() { return this->ctx.line ? this->ctx.line : this->ctx.size; }
1588 int Mem() { return ssfn_mem(&this->ctx); }
1589#ifndef SSFN_NO_CPP_STD_STRING
1590 int Load(const std::string &data) { return ssfn_load(&this->ctx,reinterpret_cast<const void*>(data.data())); }
1591 int Select(int family, const std::string &name, int style, int size) { return ssfn_select(&this->ctx, family, (char*)name.data(), style, size); }
1592 int Render(ssfn_buf_t *dst, const std::string &str) { return ssfn_render(&this->ctx,dst,(const char *)str.data()); }
1593 int BBox(const std::string &str, int *w, int *h, int *left, int *top) { return ssfn_bbox(&this->ctx, (const char *)str.data(), w, h, left, top); }
1594 ssfn_buf_t *Text(const std::string &str, unsigned int fg) { return ssfn_text(&this->ctx,(const char*)str.data(), fg); }
1595 const std::string ErrorStr(int err) { return std::string(ssfn_error(err)); }
1596#endif
1597 };
1598#endif
1599}
1600#endif
1601
1602
1603
1604
1605#endif /* _SSFN_H_ */
struct SDT header
Definition acpi.h:0
struct SDT h
Definition acpi.h:0
kstring name
Definition dentry.h:5
volatile uint32_t buffer[5]
Definition ehci.hpp:8
a
Definition entry.h:6
struct fs_data data
Definition filesystem.h:1
static ssfn_buf_t dst
Definition graphic.c:82
#define SSFN_realloc
Definition graphic.c:72
#define SSFN_free
Definition graphic.c:73
#define SSFN_memset
Definition graphic.c:21
#define SSFN_memcmp
Definition graphic.c:19
uint8_t code
Definition icmp.h:1
size_t len
Definition oct2bin.h:7
return value
Definition oct2bin.h:22
#define SSFN_ERR_BADSIZE
Definition ssfn.h:147
#define SSFN_OK
Definition ssfn.h:141
#define SSFN_FAMILY_BYNAME
Definition ssfn.h:126
ssfn_buf_t * ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg)
#define SSFN_TYPE_FAMILY(x)
Definition ssfn.h:69
int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size)
#define SSFN_STYLE_BOLD
Definition ssfn.h:79
#define SSFN_CONTOUR_MOVE
Definition ssfn.h:85
#define _pack
Definition ssfn.h:99
int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str)
#define SSFN_STYLE_STHROUGH
Definition ssfn.h:130
#define SSFN_STYLE_ITALIC
Definition ssfn.h:80
#define SSFN_STYLE_RTL
Definition ssfn.h:136
int ssfn_putc(uint32_t unicode)
int ssfn_mem(ssfn_t *ctx)
#define SSFN_STYLE_NOCACHE
Definition ssfn.h:134
#define SSFN_TYPE_STYLE(x)
Definition ssfn.h:77
#define SSFN_PREC
Definition ssfn.h:152
#define SSFN_FAMILY_HAND
Definition ssfn.h:74
#define SSFN_CONTOUR_CUBIC
Definition ssfn.h:88
#define SSFN_STYLE_NOAA
Definition ssfn.h:131
#define SSFN_CONTOUR_QUAD
Definition ssfn.h:87
#define SSFN_LIG_FIRST
Definition ssfn.h:65
#define SSFN_ERR_BADFILE
Definition ssfn.h:143
void ssfn_free(ssfn_t *ctx)
#define SSFN_STYLE_UNDERLINE
Definition ssfn.h:129
#define SSFN_ERR_INVINP
Definition ssfn.h:145
unsigned long int uint64_t
Definition ssfn.h:53
#define SSFN_STYLE_NOKERN
Definition ssfn.h:132
#define __THROW
Definition ssfn.h:43
ssfn_buf_t ssfn_dst
#define SSFN_ERR_NOGLYPH
Definition ssfn.h:148
#define SSFN_STYLE_NOSMOOTH
Definition ssfn.h:138
#define SSFN_FAMILY_ANY
Definition ssfn.h:125
#define SSFN_ERR_BADSTYLE
Definition ssfn.h:146
int ssfn_bbox2(ssfn_t *ctx, const char *str, const char *end, int *w, int *h, int *left, int *top)
#define SSFN_ITALIC_DIV
Definition ssfn.h:151
#define SSFN_FAMILY_MONOSPACE
Definition ssfn.h:73
int ssfn_load(ssfn_t *ctx, const void *data)
#define SSFN_STYLE_ABS_SIZE
Definition ssfn.h:137
#define SSFN_STYLE_NODEFGLYPH
Definition ssfn.h:133
#define SSFN_CONTOUR_LINE
Definition ssfn.h:86
#define SSFN_MAGIC
Definition ssfn.h:60
#define ssfn_error(err)
Definition ssfn.h:238
#define SSFN_ERR_ALLOC
Definition ssfn.h:142
#define SSFN_ERR_NOFACE
Definition ssfn.h:144
uint32_t ssfn_utf8(char **str)
const char * ssfn_errstr[]
unsigned short int uint16_t
Definition ssfn.h:49
int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top)
#define SSFN_SIZE_MAX
Definition ssfn.h:150
ssfn_font_t * ssfn_src
#define SSFN_COLLECTION
Definition ssfn.h:61
#define SSFN_ENDMAGIC
Definition ssfn.h:62
#define SSFN_DATA_MAX
Definition ssfn.h:167
int memcmp(const void *s1, const void *s2, size_t n)
void memset(void *ptr, int value, size_t num)
kstring str(const char *str)
int32_t height
Definition bmp.h:15
uint32_t cmap_offs
Definition ssfn.h:118
uint8_t baseline
Definition ssfn.h:112
char size[12]
Definition tar.h:43
uint16_t type
Definition ethernet.h:12
uint8_t underline
Definition ssfn.h:113
uint8_t magic[4]
Definition ssfn.h:106
uint16_t fragments_offs
Definition ssfn.h:114
uint32_t ligature_offs
Definition ssfn.h:116
uint8_t features
Definition ssfn.h:109
uint32_t kerning_offs
Definition ssfn.h:117
uint32_t characters_offs
Definition ssfn.h:115
int32_t width
Definition bmp.h:14
int x
Definition ssfn.h:160
int y
Definition ssfn.h:161
int h
Definition ssfn.h:158
int w
Definition ssfn.h:157
uint32_t fg
Definition ssfn.h:162
uint16_t p
Definition ssfn.h:159
uint8_t * ptr
Definition ssfn.h:156
uint32_t bg
Definition ssfn.h:163
uint8_t h
Definition ssfn.h:184
uint8_t w
Definition ssfn.h:183
uint8_t y
Definition ssfn.h:186
uint8_t x
Definition ssfn.h:185
uint8_t t
Definition ssfn.h:181
uint8_t n
Definition ssfn.h:182
uint16_t p
Definition ssfn.h:169
uint8_t a
Definition ssfn.h:174
uint8_t d
Definition ssfn.h:175
uint8_t h
Definition ssfn.h:170
uint8_t data[65536]
Definition ssfn.h:176
uint8_t o
Definition ssfn.h:171
uint8_t y
Definition ssfn.h:173
uint8_t x
Definition ssfn.h:172
Definition ssfn.h:195
ssfn_glyph_t * g
Definition ssfn.h:204
int ox
Definition ssfn.h:213
char ** bufs
Definition ssfn.h:210
int my
Definition ssfn.h:214
int size
Definition ssfn.h:218
int mx
Definition ssfn.h:214
const ssfn_font_t * f
Definition ssfn.h:202
int ap
Definition ssfn.h:213
int len[5]
Definition ssfn.h:215
ssfn_glyph_t *** c[17]
Definition ssfn.h:208
int style
Definition ssfn.h:217
int line
Definition ssfn.h:219
int oy
Definition ssfn.h:213
int family
Definition ssfn.h:216
int lx
Definition ssfn.h:214
int ly
Definition ssfn.h:214
int ax
Definition ssfn.h:213
int lenbuf
Definition ssfn.h:213
int numbuf
Definition ssfn.h:213
ssfn_chr_t * rc
Definition ssfn.h:212
const ssfn_font_t ** fnt[5]
Definition ssfn.h:199
ssfn_glyph_t ga
Definition ssfn.h:203
int np
Definition ssfn.h:213
uint16_t * p
Definition ssfn.h:209
const ssfn_font_t * s
Definition ssfn.h:201
#define NULL
Definition type.h:76
signed short int16_t
Definition type.h:37
unsigned short uint16_t
Definition type.h:13
unsigned int uint32_t
Definition type.h:19
unsigned long uint64_t
Definition type.h:25
unsigned char uint8_t
Definition type.h:7
unsigned long size_t
Definition type.h:55
uint32_t height
Definition virtio-gpu.hpp:3
uint32_t y
Definition virtio-gpu.hpp:1
uint32_t x
Definition virtio-gpu.hpp:0
uint8_t type
Definition vnode.h:2
size_t size
Definition vnode.h:3
uint64_t ptr
Definition xhci.hpp:0