1 //
2 // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
3 //
4 // This software is provided 'as-is', without any express or implied
5 // warranty.  In no event will the authors be held liable for any damages
6 // arising from the use of this software.
7 // Permission is granted to anyone to use this software for any purpose,
8 // including commercial applications, and to alter it and redistribute it
9 // freely, subject to the following restrictions:
10 // 1. The origin of this software must not be misrepresented; you must not
11 //    claim that you wrote the original software. If you use this software
12 //    in a product, an acknowledgment in the product documentation would be
13 //    appreciated but is not required.
14 // 2. Altered source versions must be plainly marked as such, and must not be
15 //    misrepresented as being the original software.
16 // 3. This notice may not be removed or altered from any source distribution.
17 //
18 
19 #ifndef FONS_H
20 #define FONS_H
21 
22 #define FONS_INVALID -1
23 
24 enum FONSflags {
25 	FONS_ZERO_TOPLEFT = 1,
26 	FONS_ZERO_BOTTOMLEFT = 2,
27 };
28 
29 enum FONSalign {
30 	// Horizontal align
31 	FONS_ALIGN_LEFT 	= 1<<0,	// Default
32 	FONS_ALIGN_CENTER 	= 1<<1,
33 	FONS_ALIGN_RIGHT 	= 1<<2,
34 	// Vertical align
35 	FONS_ALIGN_TOP 		= 1<<3,
36 	FONS_ALIGN_MIDDLE	= 1<<4,
37 	FONS_ALIGN_BOTTOM	= 1<<5,
38 	FONS_ALIGN_BASELINE	= 1<<6, // Default
39 };
40 
41 enum FONSglyphBitmap {
42 	FONS_GLYPH_BITMAP_OPTIONAL = 1,
43 	FONS_GLYPH_BITMAP_REQUIRED = 2,
44 };
45 
46 enum FONSerrorCode {
47 	// Font atlas is full.
48 	FONS_ATLAS_FULL = 1,
49 	// Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE.
50 	FONS_SCRATCH_FULL = 2,
51 	// Calls to fonsPushState has created too large stack, if you need deep state stack bump up FONS_MAX_STATES.
52 	FONS_STATES_OVERFLOW = 3,
53 	// Trying to pop too many states fonsPopState().
54 	FONS_STATES_UNDERFLOW = 4,
55 };
56 
57 struct FONSparams {
58 	int width, height;
59 	unsigned char flags;
60 	void* userPtr;
61 	int (*renderCreate)(void* uptr, int width, int height);
62 	int (*renderResize)(void* uptr, int width, int height);
63 	void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data);
64 	void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts);
65 	void (*renderDelete)(void* uptr);
66 };
67 typedef struct FONSparams FONSparams;
68 
69 struct FONSquad
70 {
71 	float x0,y0,s0,t0;
72 	float x1,y1,s1,t1;
73 };
74 typedef struct FONSquad FONSquad;
75 
76 struct FONStextIter {
77 	float x, y, nextx, nexty, scale, spacing;
78 	unsigned int codepoint;
79 	short isize, iblur;
80 	struct FONSfont* font;
81 	int prevGlyphIndex;
82 	const char* str;
83 	const char* next;
84 	const char* end;
85 	unsigned int utf8state;
86 	int bitmapOption;
87 };
88 typedef struct FONStextIter FONStextIter;
89 
90 typedef struct FONScontext FONScontext;
91 
92 // Constructor and destructor.
93 FONScontext* fonsCreateInternal(FONSparams* params);
94 void fonsDeleteInternal(FONScontext* s);
95 
96 void fonsSetErrorCallback(FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr);
97 // Returns current atlas size.
98 void fonsGetAtlasSize(FONScontext* s, int* width, int* height);
99 // Expands the atlas size.
100 int fonsExpandAtlas(FONScontext* s, int width, int height);
101 // Resets the whole stash.
102 int fonsResetAtlas(FONScontext* stash, int width, int height);
103 
104 // Add fonts
105 int fonsAddFont(FONScontext* s, const char* name, const char* path, int fontIndex);
106 int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData, int fontIndex);
107 int fonsGetFontByName(FONScontext* s, const char* name);
108 
109 // State handling
110 void fonsPushState(FONScontext* s);
111 void fonsPopState(FONScontext* s);
112 void fonsClearState(FONScontext* s);
113 
114 // State setting
115 void fonsSetSize(FONScontext* s, float size);
116 void fonsSetColor(FONScontext* s, unsigned int color);
117 void fonsSetSpacing(FONScontext* s, float spacing);
118 void fonsSetBlur(FONScontext* s, float blur);
119 void fonsSetAlign(FONScontext* s, int align);
120 void fonsSetFont(FONScontext* s, int font);
121 
122 // Draw text
123 float fonsDrawText(FONScontext* s, float x, float y, const char* string, const char* end);
124 
125 // Measure text
126 float fonsTextBounds(FONScontext* s, float x, float y, const char* string, const char* end, float* bounds);
127 void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy);
128 void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh);
129 
130 // Text iterator
131 int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end, int bitmapOption);
132 int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, struct FONSquad* quad);
133 
134 // Pull texture changes
135 const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height);
136 int fonsValidateTexture(FONScontext* s, int* dirty);
137 
138 // Draws the stash texture for debugging
139 void fonsDrawDebug(FONScontext* s, float x, float y);
140 
141 #endif // FONTSTASH_H
142 
143 
144 #ifdef FONTSTASH_IMPLEMENTATION
145 
146 #define FONS_NOTUSED(v)  (void)sizeof(v)
147 
148 #ifdef FONS_USE_FREETYPE
149 
150 #include <ft2build.h>
151 #include FT_FREETYPE_H
152 #include FT_ADVANCES_H
153 #include <math.h>
154 
155 struct FONSttFontImpl {
156 	FT_Face font;
157 };
158 typedef struct FONSttFontImpl FONSttFontImpl;
159 
160 static FT_Library ftLibrary;
161 
fons__tt_init(FONScontext * context)162 int fons__tt_init(FONScontext *context)
163 {
164 	FT_Error ftError;
165 	FONS_NOTUSED(context);
166 	ftError = FT_Init_FreeType(&ftLibrary);
167 	return ftError == 0;
168 }
169 
fons__tt_done(FONScontext * context)170 int fons__tt_done(FONScontext *context)
171 {
172 	FT_Error ftError;
173 	FONS_NOTUSED(context);
174 	ftError = FT_Done_FreeType(ftLibrary);
175 	return ftError == 0;
176 }
177 
fons__tt_loadFont(FONScontext * context,FONSttFontImpl * font,unsigned char * data,int dataSize,int fontIndex)178 int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
179 {
180 	FT_Error ftError;
181 	FONS_NOTUSED(context);
182 
183 	//font->font.userdata = stash;
184 	ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, fontIndex, &font->font);
185 	return ftError == 0;
186 }
187 
fons__tt_getFontVMetrics(FONSttFontImpl * font,int * ascent,int * descent,int * lineGap)188 void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
189 {
190 	*ascent = font->font->ascender;
191 	*descent = font->font->descender;
192 	*lineGap = font->font->height - (*ascent - *descent);
193 }
194 
fons__tt_getPixelHeightScale(FONSttFontImpl * font,float size)195 float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
196 {
197 #if 1
198 	// Note(DPF) maintain pixel-based units for compat after nanovg update
199 	return size / (font->font->ascender - font->font->descender);
200 #else
201 	return size / font->font->units_per_EM;
202 #endif
203 }
204 
fons__tt_getGlyphIndex(FONSttFontImpl * font,int codepoint)205 int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
206 {
207 	return FT_Get_Char_Index(font->font, codepoint);
208 }
209 
fons__tt_buildGlyphBitmap(FONSttFontImpl * font,int glyph,float size,float scale,int * advance,int * lsb,int * x0,int * y0,int * x1,int * y1)210 int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
211 							  int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
212 {
213 	FT_Error ftError;
214 	FT_GlyphSlot ftGlyph;
215 	FT_Fixed advFixed;
216 	FONS_NOTUSED(scale);
217 
218 #if 1
219 	// Note(DPF) maintain pixel-based units for compat after nanovg update
220 	ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender)));
221 #else
222 	ftError = FT_Set_Pixel_Sizes(font->font, 0, size);
223 #endif
224 	if (ftError) return 0;
225 #if 1
226 	// Note(DPF) maintain pixel-based units for compat after nanovg update
227 	ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER);
228 #else
229 	ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
230 #endif
231 	if (ftError) return 0;
232 	ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
233 	if (ftError) return 0;
234 	ftGlyph = font->font->glyph;
235 	*advance = (int)advFixed;
236 	*lsb = (int)ftGlyph->metrics.horiBearingX;
237 	*x0 = ftGlyph->bitmap_left;
238 	*x1 = *x0 + ftGlyph->bitmap.width;
239 	*y0 = -ftGlyph->bitmap_top;
240 	*y1 = *y0 + ftGlyph->bitmap.rows;
241 	return 1;
242 }
243 
fons__tt_renderGlyphBitmap(FONSttFontImpl * font,unsigned char * output,int outWidth,int outHeight,int outStride,float scaleX,float scaleY,int glyph)244 void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
245 								float scaleX, float scaleY, int glyph)
246 {
247 	FT_GlyphSlot ftGlyph = font->font->glyph;
248 	int ftGlyphOffset = 0;
249 	unsigned int x, y;
250 	FONS_NOTUSED(outWidth);
251 	FONS_NOTUSED(outHeight);
252 	FONS_NOTUSED(scaleX);
253 	FONS_NOTUSED(scaleY);
254 	FONS_NOTUSED(glyph);	// glyph has already been loaded by fons__tt_buildGlyphBitmap
255 
256 	for ( y = 0; y < ftGlyph->bitmap.rows; y++ ) {
257 		for ( x = 0; x < ftGlyph->bitmap.width; x++ ) {
258 			output[(y * outStride) + x] = ftGlyph->bitmap.buffer[ftGlyphOffset++];
259 		}
260 	}
261 }
262 
fons__tt_getGlyphKernAdvance(FONSttFontImpl * font,int glyph1,int glyph2)263 int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
264 {
265 	FT_Vector ftKerning;
266 	FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
267 	return (int)((ftKerning.x + 32) >> 6);  // Round up and convert to integer
268 }
269 
270 #else
271 
272 #define STB_TRUETYPE_IMPLEMENTATION
273 static void* fons__tmpalloc(size_t size, void* up);
274 static void fons__tmpfree(void* ptr, void* up);
275 #define STBTT_malloc(x,u)    fons__tmpalloc(x,u)
276 #define STBTT_free(x,u)      fons__tmpfree(x,u)
277 #include "stb_truetype.h"
278 
279 struct FONSttFontImpl {
280 	stbtt_fontinfo font;
281 };
282 typedef struct FONSttFontImpl FONSttFontImpl;
283 
fons__tt_init(FONScontext * context)284 int fons__tt_init(FONScontext *context)
285 {
286 	FONS_NOTUSED(context);
287 	return 1;
288 }
289 
fons__tt_done(FONScontext * context)290 int fons__tt_done(FONScontext *context)
291 {
292 	FONS_NOTUSED(context);
293 	return 1;
294 }
295 
fons__tt_loadFont(FONScontext * context,FONSttFontImpl * font,unsigned char * data,int dataSize,int fontIndex)296 int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
297 {
298 	int offset, stbError;
299 	FONS_NOTUSED(dataSize);
300 
301 	font->font.userdata = context;
302 	offset = stbtt_GetFontOffsetForIndex(data, fontIndex);
303 	if (offset == -1) {
304 		stbError = 0;
305 	} else {
306 		stbError = stbtt_InitFont(&font->font, data, offset);
307 	}
308 	return stbError;
309 }
310 
fons__tt_getFontVMetrics(FONSttFontImpl * font,int * ascent,int * descent,int * lineGap)311 void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
312 {
313 	stbtt_GetFontVMetrics(&font->font, ascent, descent, lineGap);
314 }
315 
fons__tt_getPixelHeightScale(FONSttFontImpl * font,float size)316 float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
317 {
318 #if 1
319 	// Note(DPF) maintain pixel-based units for compat after nanovg update
320 	return stbtt_ScaleForPixelHeight(&font->font, size);
321 #else
322 	return stbtt_ScaleForMappingEmToPixels(&font->font, size);
323 #endif
324 }
325 
fons__tt_getGlyphIndex(FONSttFontImpl * font,int codepoint)326 int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
327 {
328 	return stbtt_FindGlyphIndex(&font->font, codepoint);
329 }
330 
fons__tt_buildGlyphBitmap(FONSttFontImpl * font,int glyph,float size,float scale,int * advance,int * lsb,int * x0,int * y0,int * x1,int * y1)331 int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
332 							  int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
333 {
334 	FONS_NOTUSED(size);
335 	stbtt_GetGlyphHMetrics(&font->font, glyph, advance, lsb);
336 	stbtt_GetGlyphBitmapBox(&font->font, glyph, scale, scale, x0, y0, x1, y1);
337 	return 1;
338 }
339 
fons__tt_renderGlyphBitmap(FONSttFontImpl * font,unsigned char * output,int outWidth,int outHeight,int outStride,float scaleX,float scaleY,int glyph)340 void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
341 								float scaleX, float scaleY, int glyph)
342 {
343 	stbtt_MakeGlyphBitmap(&font->font, output, outWidth, outHeight, outStride, scaleX, scaleY, glyph);
344 }
345 
fons__tt_getGlyphKernAdvance(FONSttFontImpl * font,int glyph1,int glyph2)346 int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
347 {
348 	return stbtt_GetGlyphKernAdvance(&font->font, glyph1, glyph2);
349 }
350 
351 #endif
352 
353 #ifndef FONS_SCRATCH_BUF_SIZE
354 #	define FONS_SCRATCH_BUF_SIZE 96000
355 #endif
356 #ifndef FONS_HASH_LUT_SIZE
357 #	define FONS_HASH_LUT_SIZE 256
358 #endif
359 #ifndef FONS_INIT_FONTS
360 #	define FONS_INIT_FONTS 4
361 #endif
362 #ifndef FONS_INIT_GLYPHS
363 #	define FONS_INIT_GLYPHS 256
364 #endif
365 #ifndef FONS_INIT_ATLAS_NODES
366 #	define FONS_INIT_ATLAS_NODES 256
367 #endif
368 #ifndef FONS_VERTEX_COUNT
369 #	define FONS_VERTEX_COUNT 1024
370 #endif
371 #ifndef FONS_MAX_STATES
372 #	define FONS_MAX_STATES 20
373 #endif
374 #ifndef FONS_MAX_FALLBACKS
375 #	define FONS_MAX_FALLBACKS 20
376 #endif
377 
fons__hashint(unsigned int a)378 static unsigned int fons__hashint(unsigned int a)
379 {
380 	a += ~(a<<15);
381 	a ^=  (a>>10);
382 	a +=  (a<<3);
383 	a ^=  (a>>6);
384 	a += ~(a<<11);
385 	a ^=  (a>>16);
386 	return a;
387 }
388 
fons__mini(int a,int b)389 static int fons__mini(int a, int b)
390 {
391 	return a < b ? a : b;
392 }
393 
fons__maxi(int a,int b)394 static int fons__maxi(int a, int b)
395 {
396 	return a > b ? a : b;
397 }
398 
399 struct FONSglyph
400 {
401 	unsigned int codepoint;
402 	int index;
403 	int next;
404 	short size, blur;
405 	short x0,y0,x1,y1;
406 	short xadv,xoff,yoff;
407 };
408 typedef struct FONSglyph FONSglyph;
409 
410 struct FONSfont
411 {
412 	FONSttFontImpl font;
413 	char name[64];
414 	unsigned char* data;
415 	int dataSize;
416 	unsigned char freeData;
417 	float ascender;
418 	float descender;
419 	float lineh;
420 	FONSglyph* glyphs;
421 	int cglyphs;
422 	int nglyphs;
423 	int lut[FONS_HASH_LUT_SIZE];
424 	int fallbacks[FONS_MAX_FALLBACKS];
425 	int nfallbacks;
426 };
427 typedef struct FONSfont FONSfont;
428 
429 struct FONSstate
430 {
431 	int font;
432 	int align;
433 	float size;
434 	unsigned int color;
435 	float blur;
436 	float spacing;
437 };
438 typedef struct FONSstate FONSstate;
439 
440 struct FONSatlasNode {
441     short x, y, width;
442 };
443 typedef struct FONSatlasNode FONSatlasNode;
444 
445 struct FONSatlas
446 {
447 	int width, height;
448 	FONSatlasNode* nodes;
449 	int nnodes;
450 	int cnodes;
451 };
452 typedef struct FONSatlas FONSatlas;
453 
454 struct FONScontext
455 {
456 	FONSparams params;
457 	float itw,ith;
458 	unsigned char* texData;
459 	int dirtyRect[4];
460 	FONSfont** fonts;
461 	FONSatlas* atlas;
462 	int cfonts;
463 	int nfonts;
464 	float verts[FONS_VERTEX_COUNT*2];
465 	float tcoords[FONS_VERTEX_COUNT*2];
466 	unsigned int colors[FONS_VERTEX_COUNT];
467 	int nverts;
468 	unsigned char* scratch;
469 	int nscratch;
470 	FONSstate states[FONS_MAX_STATES];
471 	int nstates;
472 	void (*handleError)(void* uptr, int error, int val);
473 	void* errorUptr;
474 };
475 
476 #ifdef STB_TRUETYPE_IMPLEMENTATION
477 
fons__tmpalloc(size_t size,void * up)478 static void* fons__tmpalloc(size_t size, void* up)
479 {
480 	unsigned char* ptr;
481 	FONScontext* stash = (FONScontext*)up;
482 
483 	// 16-byte align the returned pointer
484 	size = (size + 0xf) & ~0xf;
485 
486 	if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE) {
487 		if (stash->handleError)
488 			stash->handleError(stash->errorUptr, FONS_SCRATCH_FULL, stash->nscratch+(int)size);
489 		return NULL;
490 	}
491 	ptr = stash->scratch + stash->nscratch;
492 	stash->nscratch += (int)size;
493 	return ptr;
494 }
495 
fons__tmpfree(void * ptr,void * up)496 static void fons__tmpfree(void* ptr, void* up)
497 {
498 	(void)ptr;
499 	(void)up;
500 	// empty
501 }
502 
503 #endif // STB_TRUETYPE_IMPLEMENTATION
504 
505 // Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
506 // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
507 
508 #define FONS_UTF8_ACCEPT 0
509 #define FONS_UTF8_REJECT 12
510 
fons__decutf8(unsigned int * state,unsigned int * codep,unsigned int byte)511 static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
512 {
513 	static const unsigned char utf8d[] = {
514 		// The first part of the table maps bytes to character classes that
515 		// to reduce the size of the transition table and create bitmasks.
516 		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
517 		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
518 		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
519 		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
520 		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
521 		7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
522 		8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
523 		10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
524 
525 		// The second part is a transition table that maps a combination
526 		// of a state of the automaton and a character class to a state.
527 		0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
528 		12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
529 		12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
530 		12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
531 		12,36,12,12,12,12,12,12,12,12,12,12,
532     };
533 
534 	unsigned int type = utf8d[byte];
535 
536     *codep = (*state != FONS_UTF8_ACCEPT) ?
537 		(byte & 0x3fu) | (*codep << 6) :
538 		(0xff >> type) & (byte);
539 
540 	*state = utf8d[256 + *state + type];
541 	return *state;
542 }
543 
544 // Atlas based on Skyline Bin Packer by Jukka Jylänki
545 
fons__deleteAtlas(FONSatlas * atlas)546 static void fons__deleteAtlas(FONSatlas* atlas)
547 {
548 	if (atlas == NULL) return;
549 	if (atlas->nodes != NULL) free(atlas->nodes);
550 	free(atlas);
551 }
552 
fons__allocAtlas(int w,int h,int nnodes)553 static FONSatlas* fons__allocAtlas(int w, int h, int nnodes)
554 {
555 	FONSatlas* atlas = NULL;
556 
557 	// Allocate memory for the font stash.
558 	atlas = (FONSatlas*)malloc(sizeof(FONSatlas));
559 	if (atlas == NULL) goto error;
560 	memset(atlas, 0, sizeof(FONSatlas));
561 
562 	atlas->width = w;
563 	atlas->height = h;
564 
565 	// Allocate space for skyline nodes
566 	atlas->nodes = (FONSatlasNode*)malloc(sizeof(FONSatlasNode) * nnodes);
567 	if (atlas->nodes == NULL) goto error;
568 	memset(atlas->nodes, 0, sizeof(FONSatlasNode) * nnodes);
569 	atlas->nnodes = 0;
570 	atlas->cnodes = nnodes;
571 
572 	// Init root node.
573 	atlas->nodes[0].x = 0;
574 	atlas->nodes[0].y = 0;
575 	atlas->nodes[0].width = (short)w;
576 	atlas->nnodes++;
577 
578 	return atlas;
579 
580 error:
581 	if (atlas) fons__deleteAtlas(atlas);
582 	return NULL;
583 }
584 
fons__atlasInsertNode(FONSatlas * atlas,int idx,int x,int y,int w)585 static int fons__atlasInsertNode(FONSatlas* atlas, int idx, int x, int y, int w)
586 {
587 	int i;
588 	// Insert node
589 	if (atlas->nnodes+1 > atlas->cnodes) {
590 		atlas->cnodes = atlas->cnodes == 0 ? 8 : atlas->cnodes * 2;
591 		atlas->nodes = (FONSatlasNode*)realloc(atlas->nodes, sizeof(FONSatlasNode) * atlas->cnodes);
592 		if (atlas->nodes == NULL)
593 			return 0;
594 	}
595 	for (i = atlas->nnodes; i > idx; i--)
596 		atlas->nodes[i] = atlas->nodes[i-1];
597 	atlas->nodes[idx].x = (short)x;
598 	atlas->nodes[idx].y = (short)y;
599 	atlas->nodes[idx].width = (short)w;
600 	atlas->nnodes++;
601 
602 	return 1;
603 }
604 
fons__atlasRemoveNode(FONSatlas * atlas,int idx)605 static void fons__atlasRemoveNode(FONSatlas* atlas, int idx)
606 {
607 	int i;
608 	if (atlas->nnodes == 0) return;
609 	for (i = idx; i < atlas->nnodes-1; i++)
610 		atlas->nodes[i] = atlas->nodes[i+1];
611 	atlas->nnodes--;
612 }
613 
fons__atlasExpand(FONSatlas * atlas,int w,int h)614 static void fons__atlasExpand(FONSatlas* atlas, int w, int h)
615 {
616 	// Insert node for empty space
617 	if (w > atlas->width)
618 		fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width);
619 	atlas->width = w;
620 	atlas->height = h;
621 }
622 
fons__atlasReset(FONSatlas * atlas,int w,int h)623 static void fons__atlasReset(FONSatlas* atlas, int w, int h)
624 {
625 	atlas->width = w;
626 	atlas->height = h;
627 	atlas->nnodes = 0;
628 
629 	// Init root node.
630 	atlas->nodes[0].x = 0;
631 	atlas->nodes[0].y = 0;
632 	atlas->nodes[0].width = (short)w;
633 	atlas->nnodes++;
634 }
635 
fons__atlasAddSkylineLevel(FONSatlas * atlas,int idx,int x,int y,int w,int h)636 static int fons__atlasAddSkylineLevel(FONSatlas* atlas, int idx, int x, int y, int w, int h)
637 {
638 	int i;
639 
640 	// Insert new node
641 	if (fons__atlasInsertNode(atlas, idx, x, y+h, w) == 0)
642 		return 0;
643 
644 	// Delete skyline segments that fall under the shadow of the new segment.
645 	for (i = idx+1; i < atlas->nnodes; i++) {
646 		if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) {
647 			int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x;
648 			atlas->nodes[i].x += (short)shrink;
649 			atlas->nodes[i].width -= (short)shrink;
650 			if (atlas->nodes[i].width <= 0) {
651 				fons__atlasRemoveNode(atlas, i);
652 				i--;
653 			} else {
654 				break;
655 			}
656 		} else {
657 			break;
658 		}
659 	}
660 
661 	// Merge same height skyline segments that are next to each other.
662 	for (i = 0; i < atlas->nnodes-1; i++) {
663 		if (atlas->nodes[i].y == atlas->nodes[i+1].y) {
664 			atlas->nodes[i].width += atlas->nodes[i+1].width;
665 			fons__atlasRemoveNode(atlas, i+1);
666 			i--;
667 		}
668 	}
669 
670 	return 1;
671 }
672 
fons__atlasRectFits(FONSatlas * atlas,int i,int w,int h)673 static int fons__atlasRectFits(FONSatlas* atlas, int i, int w, int h)
674 {
675 	// Checks if there is enough space at the location of skyline span 'i',
676 	// and return the max height of all skyline spans under that at that location,
677 	// (think tetris block being dropped at that position). Or -1 if no space found.
678 	int x = atlas->nodes[i].x;
679 	int y = atlas->nodes[i].y;
680 	int spaceLeft;
681 	if (x + w > atlas->width)
682 		return -1;
683 	spaceLeft = w;
684 	while (spaceLeft > 0) {
685 		if (i == atlas->nnodes) return -1;
686 		y = fons__maxi(y, atlas->nodes[i].y);
687 		if (y + h > atlas->height) return -1;
688 		spaceLeft -= atlas->nodes[i].width;
689 		++i;
690 	}
691 	return y;
692 }
693 
fons__atlasAddRect(FONSatlas * atlas,int rw,int rh,int * rx,int * ry)694 static int fons__atlasAddRect(FONSatlas* atlas, int rw, int rh, int* rx, int* ry)
695 {
696 	int besth = atlas->height, bestw = atlas->width, besti = -1;
697 	int bestx = -1, besty = -1, i;
698 
699 	// Bottom left fit heuristic.
700 	for (i = 0; i < atlas->nnodes; i++) {
701 		int y = fons__atlasRectFits(atlas, i, rw, rh);
702 		if (y != -1) {
703 			if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw)) {
704 				besti = i;
705 				bestw = atlas->nodes[i].width;
706 				besth = y + rh;
707 				bestx = atlas->nodes[i].x;
708 				besty = y;
709 			}
710 		}
711 	}
712 
713 	if (besti == -1)
714 		return 0;
715 
716 	// Perform the actual packing.
717 	if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0)
718 		return 0;
719 
720 	*rx = bestx;
721 	*ry = besty;
722 
723 	return 1;
724 }
725 
fons__addWhiteRect(FONScontext * stash,int w,int h)726 static void fons__addWhiteRect(FONScontext* stash, int w, int h)
727 {
728 	int x, y, gx, gy;
729 	unsigned char* dst;
730 	if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
731 		return;
732 
733 	// Rasterize
734 	dst = &stash->texData[gx + gy * stash->params.width];
735 	for (y = 0; y < h; y++) {
736 		for (x = 0; x < w; x++)
737 			dst[x] = 0xff;
738 		dst += stash->params.width;
739 	}
740 
741 	stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
742 	stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
743 	stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
744 	stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
745 }
746 
fonsCreateInternal(FONSparams * params)747 FONScontext* fonsCreateInternal(FONSparams* params)
748 {
749 	FONScontext* stash = NULL;
750 
751 	// Allocate memory for the font stash.
752 	stash = (FONScontext*)malloc(sizeof(FONScontext));
753 	if (stash == NULL) goto error;
754 	memset(stash, 0, sizeof(FONScontext));
755 
756 	stash->params = *params;
757 
758 	// Allocate scratch buffer.
759 	stash->scratch = (unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE);
760 	if (stash->scratch == NULL) goto error;
761 
762 	// Initialize implementation library
763 	if (!fons__tt_init(stash)) goto error;
764 
765 	if (stash->params.renderCreate != NULL) {
766 		if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
767 			goto error;
768 	}
769 
770 	stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES);
771 	if (stash->atlas == NULL) goto error;
772 
773 	// Allocate space for fonts.
774 	stash->fonts = (FONSfont**)malloc(sizeof(FONSfont*) * FONS_INIT_FONTS);
775 	if (stash->fonts == NULL) goto error;
776 	memset(stash->fonts, 0, sizeof(FONSfont*) * FONS_INIT_FONTS);
777 	stash->cfonts = FONS_INIT_FONTS;
778 	stash->nfonts = 0;
779 
780 	// Create texture for the cache.
781 	stash->itw = 1.0f/stash->params.width;
782 	stash->ith = 1.0f/stash->params.height;
783 	stash->texData = (unsigned char*)malloc(stash->params.width * stash->params.height);
784 	if (stash->texData == NULL) goto error;
785 	memset(stash->texData, 0, stash->params.width * stash->params.height);
786 
787 	stash->dirtyRect[0] = stash->params.width;
788 	stash->dirtyRect[1] = stash->params.height;
789 	stash->dirtyRect[2] = 0;
790 	stash->dirtyRect[3] = 0;
791 
792 	// Add white rect at 0,0 for debug drawing.
793 	fons__addWhiteRect(stash, 2,2);
794 
795 	fonsPushState(stash);
796 	fonsClearState(stash);
797 
798 	return stash;
799 
800 error:
801 	fonsDeleteInternal(stash);
802 	return NULL;
803 }
804 
fons__getState(FONScontext * stash)805 static FONSstate* fons__getState(FONScontext* stash)
806 {
807 	return &stash->states[stash->nstates-1];
808 }
809 
fonsAddFallbackFont(FONScontext * stash,int base,int fallback)810 int fonsAddFallbackFont(FONScontext* stash, int base, int fallback)
811 {
812 	FONSfont* baseFont = stash->fonts[base];
813 	if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
814 		baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
815 		return 1;
816 	}
817 	return 0;
818 }
819 
fonsResetFallbackFont(FONScontext * stash,int base)820 void fonsResetFallbackFont(FONScontext* stash, int base)
821 {
822 	int i;
823 
824 	FONSfont* baseFont = stash->fonts[base];
825 	baseFont->nfallbacks = 0;
826 	baseFont->nglyphs = 0;
827 	for (i = 0; i < FONS_HASH_LUT_SIZE; i++)
828 		baseFont->lut[i] = -1;
829 }
830 
fonsSetSize(FONScontext * stash,float size)831 void fonsSetSize(FONScontext* stash, float size)
832 {
833 	fons__getState(stash)->size = size;
834 }
835 
fonsSetColor(FONScontext * stash,unsigned int color)836 void fonsSetColor(FONScontext* stash, unsigned int color)
837 {
838 	fons__getState(stash)->color = color;
839 }
840 
fonsSetSpacing(FONScontext * stash,float spacing)841 void fonsSetSpacing(FONScontext* stash, float spacing)
842 {
843 	fons__getState(stash)->spacing = spacing;
844 }
845 
fonsSetBlur(FONScontext * stash,float blur)846 void fonsSetBlur(FONScontext* stash, float blur)
847 {
848 	fons__getState(stash)->blur = blur;
849 }
850 
fonsSetAlign(FONScontext * stash,int align)851 void fonsSetAlign(FONScontext* stash, int align)
852 {
853 	fons__getState(stash)->align = align;
854 }
855 
fonsSetFont(FONScontext * stash,int font)856 void fonsSetFont(FONScontext* stash, int font)
857 {
858 	fons__getState(stash)->font = font;
859 }
860 
fonsPushState(FONScontext * stash)861 void fonsPushState(FONScontext* stash)
862 {
863 	if (stash->nstates >= FONS_MAX_STATES) {
864 		if (stash->handleError)
865 			stash->handleError(stash->errorUptr, FONS_STATES_OVERFLOW, 0);
866 		return;
867 	}
868 	if (stash->nstates > 0)
869 		memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(FONSstate));
870 	stash->nstates++;
871 }
872 
fonsPopState(FONScontext * stash)873 void fonsPopState(FONScontext* stash)
874 {
875 	if (stash->nstates <= 1) {
876 		if (stash->handleError)
877 			stash->handleError(stash->errorUptr, FONS_STATES_UNDERFLOW, 0);
878 		return;
879 	}
880 	stash->nstates--;
881 }
882 
fonsClearState(FONScontext * stash)883 void fonsClearState(FONScontext* stash)
884 {
885 	FONSstate* state = fons__getState(stash);
886 	state->size = 12.0f;
887 	state->color = 0xffffffff;
888 	state->font = 0;
889 	state->blur = 0;
890 	state->spacing = 0;
891 	state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE;
892 }
893 
fons__freeFont(FONSfont * font)894 static void fons__freeFont(FONSfont* font)
895 {
896 	if (font == NULL) return;
897 	if (font->glyphs) free(font->glyphs);
898 	if (font->freeData && font->data) free(font->data);
899 	free(font);
900 }
901 
fons__allocFont(FONScontext * stash)902 static int fons__allocFont(FONScontext* stash)
903 {
904 	FONSfont* font = NULL;
905 	if (stash->nfonts+1 > stash->cfonts) {
906 		stash->cfonts = stash->cfonts == 0 ? 8 : stash->cfonts * 2;
907 		stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts);
908 		if (stash->fonts == NULL)
909 			return -1;
910 	}
911 	font = (FONSfont*)malloc(sizeof(FONSfont));
912 	if (font == NULL) goto error;
913 	memset(font, 0, sizeof(FONSfont));
914 
915 	font->glyphs = (FONSglyph*)malloc(sizeof(FONSglyph) * FONS_INIT_GLYPHS);
916 	if (font->glyphs == NULL) goto error;
917 	font->cglyphs = FONS_INIT_GLYPHS;
918 	font->nglyphs = 0;
919 
920 	stash->fonts[stash->nfonts++] = font;
921 	return stash->nfonts-1;
922 
923 error:
924 	fons__freeFont(font);
925 
926 	return FONS_INVALID;
927 }
928 
fonsAddFont(FONScontext * stash,const char * name,const char * path,int fontIndex)929 int fonsAddFont(FONScontext* stash, const char* name, const char* path, int fontIndex)
930 {
931 	FILE* fp = 0;
932 	int dataSize = 0;
933 	size_t readed;
934 	unsigned char* data = NULL;
935 
936 	// Read in the font data.
937 	fp = fopen(path, "rb");
938 	if (fp == NULL) goto error;
939 	fseek(fp,0,SEEK_END);
940 	dataSize = (int)ftell(fp);
941 	fseek(fp,0,SEEK_SET);
942 	data = (unsigned char*)malloc(dataSize);
943 	if (data == NULL) goto error;
944 	readed = fread(data, 1, dataSize, fp);
945 	fclose(fp);
946 	fp = 0;
947 	if (readed != (size_t)dataSize) goto error;
948 
949 	return fonsAddFontMem(stash, name, data, dataSize, 1, fontIndex);
950 
951 error:
952 	if (data) free(data);
953 	if (fp) fclose(fp);
954 	return FONS_INVALID;
955 }
956 
fonsAddFontMem(FONScontext * stash,const char * name,unsigned char * data,int dataSize,int freeData,int fontIndex)957 int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData, int fontIndex)
958 {
959 	int i, ascent, descent, fh, lineGap;
960 	FONSfont* font;
961 
962 	int idx = fons__allocFont(stash);
963 	if (idx == FONS_INVALID)
964 		return FONS_INVALID;
965 
966 	font = stash->fonts[idx];
967 
968 	strncpy(font->name, name, sizeof(font->name));
969 	font->name[sizeof(font->name)-1] = '\0';
970 
971 	// Init hash lookup.
972 	for (i = 0; i < FONS_HASH_LUT_SIZE; ++i)
973 		font->lut[i] = -1;
974 
975 	// Read in the font data.
976 	font->dataSize = dataSize;
977 	font->data = data;
978 	font->freeData = (unsigned char)freeData;
979 
980 	// Init font
981 	stash->nscratch = 0;
982 	if (!fons__tt_loadFont(stash, &font->font, data, dataSize, fontIndex)) goto error;
983 
984 	// Store normalized line height. The real line height is got
985 	// by multiplying the lineh by font size.
986 	fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);
987 	ascent += lineGap;
988 	fh = ascent - descent;
989 	font->ascender = (float)ascent / (float)fh;
990 	font->descender = (float)descent / (float)fh;
991 	font->lineh = font->ascender - font->descender;
992 
993 	return idx;
994 
995 error:
996 	fons__freeFont(font);
997 	stash->nfonts--;
998 	return FONS_INVALID;
999 }
1000 
fonsGetFontByName(FONScontext * s,const char * name)1001 int fonsGetFontByName(FONScontext* s, const char* name)
1002 {
1003 	int i;
1004 	for (i = 0; i < s->nfonts; i++) {
1005 		if (strcmp(s->fonts[i]->name, name) == 0)
1006 			return i;
1007 	}
1008 	return FONS_INVALID;
1009 }
1010 
1011 
fons__allocGlyph(FONSfont * font)1012 static FONSglyph* fons__allocGlyph(FONSfont* font)
1013 {
1014 	if (font->nglyphs+1 > font->cglyphs) {
1015 		font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2;
1016 		font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs);
1017 		if (font->glyphs == NULL) return NULL;
1018 	}
1019 	font->nglyphs++;
1020 	return &font->glyphs[font->nglyphs-1];
1021 }
1022 
1023 
1024 // Based on Exponential blur, Jani Huhtanen, 2006
1025 
1026 #define APREC 16
1027 #define ZPREC 7
1028 
fons__blurCols(unsigned char * dst,int w,int h,int dstStride,int alpha)1029 static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha)
1030 {
1031 	int x, y;
1032 	for (y = 0; y < h; y++) {
1033 		int z = 0; // force zero border
1034 		for (x = 1; x < w; x++) {
1035 			z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
1036 			dst[x] = (unsigned char)(z >> ZPREC);
1037 		}
1038 		dst[w-1] = 0; // force zero border
1039 		z = 0;
1040 		for (x = w-2; x >= 0; x--) {
1041 			z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
1042 			dst[x] = (unsigned char)(z >> ZPREC);
1043 		}
1044 		dst[0] = 0; // force zero border
1045 		dst += dstStride;
1046 	}
1047 }
1048 
fons__blurRows(unsigned char * dst,int w,int h,int dstStride,int alpha)1049 static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha)
1050 {
1051 	int x, y;
1052 	for (x = 0; x < w; x++) {
1053 		int z = 0; // force zero border
1054 		for (y = dstStride; y < h*dstStride; y += dstStride) {
1055 			z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
1056 			dst[y] = (unsigned char)(z >> ZPREC);
1057 		}
1058 		dst[(h-1)*dstStride] = 0; // force zero border
1059 		z = 0;
1060 		for (y = (h-2)*dstStride; y >= 0; y -= dstStride) {
1061 			z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
1062 			dst[y] = (unsigned char)(z >> ZPREC);
1063 		}
1064 		dst[0] = 0; // force zero border
1065 		dst++;
1066 	}
1067 }
1068 
1069 
fons__blur(FONScontext * stash,unsigned char * dst,int w,int h,int dstStride,int blur)1070 static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur)
1071 {
1072 	int alpha;
1073 	float sigma;
1074 	(void)stash;
1075 
1076 	if (blur < 1)
1077 		return;
1078 	// Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity)
1079 	sigma = (float)blur * 0.57735f; // 1 / sqrt(3)
1080 	alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma+1.0f))));
1081 	fons__blurRows(dst, w, h, dstStride, alpha);
1082 	fons__blurCols(dst, w, h, dstStride, alpha);
1083 	fons__blurRows(dst, w, h, dstStride, alpha);
1084 	fons__blurCols(dst, w, h, dstStride, alpha);
1085 //	fons__blurrows(dst, w, h, dstStride, alpha);
1086 //	fons__blurcols(dst, w, h, dstStride, alpha);
1087 }
1088 
fons__getGlyph(FONScontext * stash,FONSfont * font,unsigned int codepoint,short isize,short iblur,int bitmapOption)1089 static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
1090 								 short isize, short iblur, int bitmapOption)
1091 {
1092 	int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
1093 	float scale;
1094 	FONSglyph* glyph = NULL;
1095 	unsigned int h;
1096 	float size = isize/10.0f;
1097 	int pad, added;
1098 	unsigned char* bdst;
1099 	unsigned char* dst;
1100 	FONSfont* renderFont = font;
1101 
1102 	if (isize < 2) return NULL;
1103 	if (iblur > 20) iblur = 20;
1104 	pad = iblur+2;
1105 
1106 	// Reset allocator.
1107 	stash->nscratch = 0;
1108 
1109 	// Find code point and size.
1110 	h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
1111 	i = font->lut[h];
1112 	while (i != -1) {
1113 		if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur) {
1114 			glyph = &font->glyphs[i];
1115 			if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL || (glyph->x0 >= 0 && glyph->y0 >= 0)) {
1116 			  return glyph;
1117 			}
1118 			// At this point, glyph exists but the bitmap data is not yet created.
1119 			break;
1120 		}
1121 		i = font->glyphs[i].next;
1122 	}
1123 
1124 	// Create a new glyph or rasterize bitmap data for a cached glyph.
1125 	g = fons__tt_getGlyphIndex(&font->font, codepoint);
1126 	// Try to find the glyph in fallback fonts.
1127 	if (g == 0) {
1128 		for (i = 0; i < font->nfallbacks; ++i) {
1129 			FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
1130 			int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
1131 			if (fallbackIndex != 0) {
1132 				g = fallbackIndex;
1133 				renderFont = fallbackFont;
1134 				break;
1135 			}
1136 		}
1137 		// It is possible that we did not find a fallback glyph.
1138 		// In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph.
1139 	}
1140 	scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
1141 	fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
1142 	gw = x1-x0 + pad*2;
1143 	gh = y1-y0 + pad*2;
1144 
1145 	// Determines the spot to draw glyph in the atlas.
1146 	if (bitmapOption == FONS_GLYPH_BITMAP_REQUIRED) {
1147 		// Find free spot for the rect in the atlas
1148 		added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1149 		if (added == 0 && stash->handleError != NULL) {
1150 			// Atlas is full, let the user to resize the atlas (or not), and try again.
1151 			stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
1152 			added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1153 		}
1154 		if (added == 0) return NULL;
1155 	} else {
1156 		// Negative coordinate indicates there is no bitmap data created.
1157 		gx = -1;
1158 		gy = -1;
1159 	}
1160 
1161 	// Init glyph.
1162 	if (glyph == NULL) {
1163 		glyph = fons__allocGlyph(font);
1164 		glyph->codepoint = codepoint;
1165 		glyph->size = isize;
1166 		glyph->blur = iblur;
1167 		glyph->next = 0;
1168 
1169 		// Insert char to hash lookup.
1170 		glyph->next = font->lut[h];
1171 		font->lut[h] = font->nglyphs-1;
1172 	}
1173 	glyph->index = g;
1174 	glyph->x0 = (short)gx;
1175 	glyph->y0 = (short)gy;
1176 	glyph->x1 = (short)(glyph->x0+gw);
1177 	glyph->y1 = (short)(glyph->y0+gh);
1178 	glyph->xadv = (short)(scale * advance * 10.0f);
1179 	glyph->xoff = (short)(x0 - pad);
1180 	glyph->yoff = (short)(y0 - pad);
1181 
1182 	if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL) {
1183 		return glyph;
1184 	}
1185 
1186 	// Rasterize
1187 	dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
1188 	fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale, scale, g);
1189 
1190 	// Make sure there is one pixel empty border.
1191 	dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1192 	for (y = 0; y < gh; y++) {
1193 		dst[y*stash->params.width] = 0;
1194 		dst[gw-1 + y*stash->params.width] = 0;
1195 	}
1196 	for (x = 0; x < gw; x++) {
1197 		dst[x] = 0;
1198 		dst[x + (gh-1)*stash->params.width] = 0;
1199 	}
1200 
1201 	// Debug code to color the glyph background
1202 /*	unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1203 	for (y = 0; y < gh; y++) {
1204 		for (x = 0; x < gw; x++) {
1205 			int a = (int)fdst[x+y*stash->params.width] + 20;
1206 			if (a > 255) a = 255;
1207 			fdst[x+y*stash->params.width] = a;
1208 		}
1209 	}*/
1210 
1211 	// Blur
1212 	if (iblur > 0) {
1213 		stash->nscratch = 0;
1214 		bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1215 		fons__blur(stash, bdst, gw, gh, stash->params.width, iblur);
1216 	}
1217 
1218 	stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
1219 	stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
1220 	stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
1221 	stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);
1222 
1223 	return glyph;
1224 }
1225 
fons__getQuad(FONScontext * stash,FONSfont * font,int prevGlyphIndex,FONSglyph * glyph,float scale,float spacing,float * x,float * y,FONSquad * q)1226 static void fons__getQuad(FONScontext* stash, FONSfont* font,
1227 						   int prevGlyphIndex, FONSglyph* glyph,
1228 						   float scale, float spacing, float* x, float* y, FONSquad* q)
1229 {
1230 	float rx,ry,xoff,yoff,x0,y0,x1,y1;
1231 
1232 	if (prevGlyphIndex != -1) {
1233 		float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale;
1234 		*x += (int)(adv + spacing + 0.5f);
1235 	}
1236 
1237 	// Each glyph has 2px border to allow good interpolation,
1238 	// one pixel to prevent leaking, and one to allow good interpolation for rendering.
1239 	// Inset the texture region by one pixel for correct interpolation.
1240 	xoff = (short)(glyph->xoff+1);
1241 	yoff = (short)(glyph->yoff+1);
1242 	x0 = (float)(glyph->x0+1);
1243 	y0 = (float)(glyph->y0+1);
1244 	x1 = (float)(glyph->x1-1);
1245 	y1 = (float)(glyph->y1-1);
1246 
1247 	if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1248 		rx = floorf(*x + xoff);
1249 		ry = floorf(*y + yoff);
1250 
1251 		q->x0 = rx;
1252 		q->y0 = ry;
1253 		q->x1 = rx + x1 - x0;
1254 		q->y1 = ry + y1 - y0;
1255 
1256 		q->s0 = x0 * stash->itw;
1257 		q->t0 = y0 * stash->ith;
1258 		q->s1 = x1 * stash->itw;
1259 		q->t1 = y1 * stash->ith;
1260 	} else {
1261 		rx = floorf(*x + xoff);
1262 		ry = floorf(*y - yoff);
1263 
1264 		q->x0 = rx;
1265 		q->y0 = ry;
1266 		q->x1 = rx + x1 - x0;
1267 		q->y1 = ry - y1 + y0;
1268 
1269 		q->s0 = x0 * stash->itw;
1270 		q->t0 = y0 * stash->ith;
1271 		q->s1 = x1 * stash->itw;
1272 		q->t1 = y1 * stash->ith;
1273 	}
1274 
1275 	*x += (int)(glyph->xadv / 10.0f + 0.5f);
1276 }
1277 
fons__flush(FONScontext * stash)1278 static void fons__flush(FONScontext* stash)
1279 {
1280 	// Flush texture
1281 	if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1282 		if (stash->params.renderUpdate != NULL)
1283 			stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData);
1284 		// Reset dirty rect
1285 		stash->dirtyRect[0] = stash->params.width;
1286 		stash->dirtyRect[1] = stash->params.height;
1287 		stash->dirtyRect[2] = 0;
1288 		stash->dirtyRect[3] = 0;
1289 	}
1290 
1291 	// Flush triangles
1292 	if (stash->nverts > 0) {
1293 		if (stash->params.renderDraw != NULL)
1294 			stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->tcoords, stash->colors, stash->nverts);
1295 		stash->nverts = 0;
1296 	}
1297 }
1298 
fons__vertex(FONScontext * stash,float x,float y,float s,float t,unsigned int c)1299 static __inline void fons__vertex(FONScontext* stash, float x, float y, float s, float t, unsigned int c)
1300 {
1301 	stash->verts[stash->nverts*2+0] = x;
1302 	stash->verts[stash->nverts*2+1] = y;
1303 	stash->tcoords[stash->nverts*2+0] = s;
1304 	stash->tcoords[stash->nverts*2+1] = t;
1305 	stash->colors[stash->nverts] = c;
1306 	stash->nverts++;
1307 }
1308 
fons__getVertAlign(FONScontext * stash,FONSfont * font,int align,short isize)1309 static float fons__getVertAlign(FONScontext* stash, FONSfont* font, int align, short isize)
1310 {
1311 	if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1312 		if (align & FONS_ALIGN_TOP) {
1313 			return font->ascender * (float)isize/10.0f;
1314 		} else if (align & FONS_ALIGN_MIDDLE) {
1315 			return (font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
1316 		} else if (align & FONS_ALIGN_BASELINE) {
1317 			return 0.0f;
1318 		} else if (align & FONS_ALIGN_BOTTOM) {
1319 			return font->descender * (float)isize/10.0f;
1320 		}
1321 	} else {
1322 		if (align & FONS_ALIGN_TOP) {
1323 			return -font->ascender * (float)isize/10.0f;
1324 		} else if (align & FONS_ALIGN_MIDDLE) {
1325 			return -(font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
1326 		} else if (align & FONS_ALIGN_BASELINE) {
1327 			return 0.0f;
1328 		} else if (align & FONS_ALIGN_BOTTOM) {
1329 			return -font->descender * (float)isize/10.0f;
1330 		}
1331 	}
1332 	return 0.0;
1333 }
1334 
fonsDrawText(FONScontext * stash,float x,float y,const char * str,const char * end)1335 float fonsDrawText(FONScontext* stash,
1336 				   float x, float y,
1337 				   const char* str, const char* end)
1338 {
1339 	FONSstate* state = fons__getState(stash);
1340 	unsigned int codepoint;
1341 	unsigned int utf8state = 0;
1342 	FONSglyph* glyph = NULL;
1343 	FONSquad q;
1344 	int prevGlyphIndex = -1;
1345 	short isize = (short)(state->size*10.0f);
1346 	short iblur = (short)state->blur;
1347 	float scale;
1348 	FONSfont* font;
1349 	float width;
1350 
1351 	if (stash == NULL) return x;
1352 	if (state->font < 0 || state->font >= stash->nfonts) return x;
1353 	font = stash->fonts[state->font];
1354 	if (font->data == NULL) return x;
1355 
1356 	scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
1357 
1358 	if (end == NULL)
1359 		end = str + strlen(str);
1360 
1361 	// Align horizontally
1362 	if (state->align & FONS_ALIGN_LEFT) {
1363 		// empty
1364 	} else if (state->align & FONS_ALIGN_RIGHT) {
1365 		width = fonsTextBounds(stash, x,y, str, end, NULL);
1366 		x -= width;
1367 	} else if (state->align & FONS_ALIGN_CENTER) {
1368 		width = fonsTextBounds(stash, x,y, str, end, NULL);
1369 		x -= width * 0.5f;
1370 	}
1371 	// Align vertically.
1372 	y += fons__getVertAlign(stash, font, state->align, isize);
1373 
1374 	for (; str != end; ++str) {
1375 		if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
1376 			continue;
1377 		glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_REQUIRED);
1378 		if (glyph != NULL) {
1379 			fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1380 
1381 			if (stash->nverts+6 > FONS_VERTEX_COUNT)
1382 				fons__flush(stash);
1383 
1384 			fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
1385 			fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
1386 			fons__vertex(stash, q.x1, q.y0, q.s1, q.t0, state->color);
1387 
1388 			fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
1389 			fons__vertex(stash, q.x0, q.y1, q.s0, q.t1, state->color);
1390 			fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
1391 		}
1392 		prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1393 	}
1394 	fons__flush(stash);
1395 
1396 	return x;
1397 }
1398 
fonsTextIterInit(FONScontext * stash,FONStextIter * iter,float x,float y,const char * str,const char * end,int bitmapOption)1399 int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
1400 					 float x, float y, const char* str, const char* end, int bitmapOption)
1401 {
1402 	FONSstate* state = fons__getState(stash);
1403 	float width;
1404 
1405 	memset(iter, 0, sizeof(*iter));
1406 
1407 	if (stash == NULL) return 0;
1408 	if (state->font < 0 || state->font >= stash->nfonts) return 0;
1409 	iter->font = stash->fonts[state->font];
1410 	if (iter->font->data == NULL) return 0;
1411 
1412 	iter->isize = (short)(state->size*10.0f);
1413 	iter->iblur = (short)state->blur;
1414 	iter->scale = fons__tt_getPixelHeightScale(&iter->font->font, (float)iter->isize/10.0f);
1415 
1416 	// Align horizontally
1417 	if (state->align & FONS_ALIGN_LEFT) {
1418 		// empty
1419 	} else if (state->align & FONS_ALIGN_RIGHT) {
1420 		width = fonsTextBounds(stash, x,y, str, end, NULL);
1421 		x -= width;
1422 	} else if (state->align & FONS_ALIGN_CENTER) {
1423 		width = fonsTextBounds(stash, x,y, str, end, NULL);
1424 		x -= width * 0.5f;
1425 	}
1426 	// Align vertically.
1427 	y += fons__getVertAlign(stash, iter->font, state->align, iter->isize);
1428 
1429 	if (end == NULL)
1430 		end = str + strlen(str);
1431 
1432 	iter->x = iter->nextx = x;
1433 	iter->y = iter->nexty = y;
1434 	iter->spacing = state->spacing;
1435 	iter->str = str;
1436 	iter->next = str;
1437 	iter->end = end;
1438 	iter->codepoint = 0;
1439 	iter->prevGlyphIndex = -1;
1440 	iter->bitmapOption = bitmapOption;
1441 
1442 	return 1;
1443 }
1444 
fonsTextIterNext(FONScontext * stash,FONStextIter * iter,FONSquad * quad)1445 int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
1446 {
1447 	FONSglyph* glyph = NULL;
1448 	const char* str = iter->next;
1449 	iter->str = iter->next;
1450 
1451 	if (str == iter->end)
1452 		return 0;
1453 
1454 	for (; str != iter->end; str++) {
1455 		if (fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str))
1456 			continue;
1457 		str++;
1458 		// Get glyph and quad
1459 		iter->x = iter->nextx;
1460 		iter->y = iter->nexty;
1461 		glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur, iter->bitmapOption);
1462 		// If the iterator was initialized with FONS_GLYPH_BITMAP_OPTIONAL, then the UV coordinates of the quad will be invalid.
1463 		if (glyph != NULL)
1464 			fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad);
1465 		iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1466 		break;
1467 	}
1468 	iter->next = str;
1469 
1470 	return 1;
1471 }
1472 
fonsDrawDebug(FONScontext * stash,float x,float y)1473 void fonsDrawDebug(FONScontext* stash, float x, float y)
1474 {
1475 	int i;
1476 	int w = stash->params.width;
1477 	int h = stash->params.height;
1478 	float u = w == 0 ? 0 : (1.0f / w);
1479 	float v = h == 0 ? 0 : (1.0f / h);
1480 
1481 	if (stash->nverts+6+6 > FONS_VERTEX_COUNT)
1482 		fons__flush(stash);
1483 
1484 	// Draw background
1485 	fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
1486 	fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
1487 	fons__vertex(stash, x+w, y+0, u, v, 0x0fffffff);
1488 
1489 	fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
1490 	fons__vertex(stash, x+0, y+h, u, v, 0x0fffffff);
1491 	fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
1492 
1493 	// Draw texture
1494 	fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
1495 	fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
1496 	fons__vertex(stash, x+w, y+0, 1, 0, 0xffffffff);
1497 
1498 	fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
1499 	fons__vertex(stash, x+0, y+h, 0, 1, 0xffffffff);
1500 	fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
1501 
1502 	// Drawbug draw atlas
1503 	for (i = 0; i < stash->atlas->nnodes; i++) {
1504 		FONSatlasNode* n = &stash->atlas->nodes[i];
1505 
1506 		if (stash->nverts+6 > FONS_VERTEX_COUNT)
1507 			fons__flush(stash);
1508 
1509 		fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
1510 		fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
1511 		fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc00000ff);
1512 
1513 		fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
1514 		fons__vertex(stash, x+n->x+0, y+n->y+1, u, v, 0xc00000ff);
1515 		fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
1516 	}
1517 
1518 	fons__flush(stash);
1519 }
1520 
fonsTextBounds(FONScontext * stash,float x,float y,const char * str,const char * end,float * bounds)1521 float fonsTextBounds(FONScontext* stash,
1522 					 float x, float y,
1523 					 const char* str, const char* end,
1524 					 float* bounds)
1525 {
1526 	FONSstate* state = fons__getState(stash);
1527 	unsigned int codepoint;
1528 	unsigned int utf8state = 0;
1529 	FONSquad q;
1530 	FONSglyph* glyph = NULL;
1531 	int prevGlyphIndex = -1;
1532 	short isize = (short)(state->size*10.0f);
1533 	short iblur = (short)state->blur;
1534 	float scale;
1535 	FONSfont* font;
1536 	float startx, advance;
1537 	float minx, miny, maxx, maxy;
1538 
1539 	if (stash == NULL) return 0;
1540 	if (state->font < 0 || state->font >= stash->nfonts) return 0;
1541 	font = stash->fonts[state->font];
1542 	if (font->data == NULL) return 0;
1543 
1544 	scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
1545 
1546 	// Align vertically.
1547 	y += fons__getVertAlign(stash, font, state->align, isize);
1548 
1549 	minx = maxx = x;
1550 	miny = maxy = y;
1551 	startx = x;
1552 
1553 	if (end == NULL)
1554 		end = str + strlen(str);
1555 
1556 	for (; str != end; ++str) {
1557 		if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
1558 			continue;
1559 		glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_OPTIONAL);
1560 		if (glyph != NULL) {
1561 			fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1562 			if (q.x0 < minx) minx = q.x0;
1563 			if (q.x1 > maxx) maxx = q.x1;
1564 			if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1565 				if (q.y0 < miny) miny = q.y0;
1566 				if (q.y1 > maxy) maxy = q.y1;
1567 			} else {
1568 				if (q.y1 < miny) miny = q.y1;
1569 				if (q.y0 > maxy) maxy = q.y0;
1570 			}
1571 		}
1572 		prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1573 	}
1574 
1575 	advance = x - startx;
1576 
1577 	// Align horizontally
1578 	if (state->align & FONS_ALIGN_LEFT) {
1579 		// empty
1580 	} else if (state->align & FONS_ALIGN_RIGHT) {
1581 		minx -= advance;
1582 		maxx -= advance;
1583 	} else if (state->align & FONS_ALIGN_CENTER) {
1584 		minx -= advance * 0.5f;
1585 		maxx -= advance * 0.5f;
1586 	}
1587 
1588 	if (bounds) {
1589 		bounds[0] = minx;
1590 		bounds[1] = miny;
1591 		bounds[2] = maxx;
1592 		bounds[3] = maxy;
1593 	}
1594 
1595 	return advance;
1596 }
1597 
fonsVertMetrics(FONScontext * stash,float * ascender,float * descender,float * lineh)1598 void fonsVertMetrics(FONScontext* stash,
1599 					 float* ascender, float* descender, float* lineh)
1600 {
1601 	FONSfont* font;
1602 	FONSstate* state = fons__getState(stash);
1603 	short isize;
1604 
1605 	if (stash == NULL) return;
1606 	if (state->font < 0 || state->font >= stash->nfonts) return;
1607 	font = stash->fonts[state->font];
1608 	isize = (short)(state->size*10.0f);
1609 	if (font->data == NULL) return;
1610 
1611 	if (ascender)
1612 		*ascender = font->ascender*isize/10.0f;
1613 	if (descender)
1614 		*descender = font->descender*isize/10.0f;
1615 	if (lineh)
1616 		*lineh = font->lineh*isize/10.0f;
1617 }
1618 
fonsLineBounds(FONScontext * stash,float y,float * miny,float * maxy)1619 void fonsLineBounds(FONScontext* stash, float y, float* miny, float* maxy)
1620 {
1621 	FONSfont* font;
1622 	FONSstate* state = fons__getState(stash);
1623 	short isize;
1624 
1625 	if (stash == NULL) return;
1626 	if (state->font < 0 || state->font >= stash->nfonts) return;
1627 	font = stash->fonts[state->font];
1628 	isize = (short)(state->size*10.0f);
1629 	if (font->data == NULL) return;
1630 
1631 	y += fons__getVertAlign(stash, font, state->align, isize);
1632 
1633 	if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1634 		*miny = y - font->ascender * (float)isize/10.0f;
1635 		*maxy = *miny + font->lineh*isize/10.0f;
1636 	} else {
1637 		*maxy = y + font->descender * (float)isize/10.0f;
1638 		*miny = *maxy - font->lineh*isize/10.0f;
1639 	}
1640 }
1641 
fonsGetTextureData(FONScontext * stash,int * width,int * height)1642 const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height)
1643 {
1644 	if (width != NULL)
1645 		*width = stash->params.width;
1646 	if (height != NULL)
1647 		*height = stash->params.height;
1648 	return stash->texData;
1649 }
1650 
fonsValidateTexture(FONScontext * stash,int * dirty)1651 int fonsValidateTexture(FONScontext* stash, int* dirty)
1652 {
1653 	if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1654 		dirty[0] = stash->dirtyRect[0];
1655 		dirty[1] = stash->dirtyRect[1];
1656 		dirty[2] = stash->dirtyRect[2];
1657 		dirty[3] = stash->dirtyRect[3];
1658 		// Reset dirty rect
1659 		stash->dirtyRect[0] = stash->params.width;
1660 		stash->dirtyRect[1] = stash->params.height;
1661 		stash->dirtyRect[2] = 0;
1662 		stash->dirtyRect[3] = 0;
1663 		return 1;
1664 	}
1665 	return 0;
1666 }
1667 
fonsDeleteInternal(FONScontext * stash)1668 void fonsDeleteInternal(FONScontext* stash)
1669 {
1670 	int i;
1671 	if (stash == NULL) return;
1672 
1673 	if (stash->params.renderDelete)
1674 		stash->params.renderDelete(stash->params.userPtr);
1675 
1676 	for (i = 0; i < stash->nfonts; ++i)
1677 		fons__freeFont(stash->fonts[i]);
1678 
1679 	if (stash->atlas) fons__deleteAtlas(stash->atlas);
1680 	if (stash->fonts) free(stash->fonts);
1681 	if (stash->texData) free(stash->texData);
1682 	if (stash->scratch) free(stash->scratch);
1683 	free(stash);
1684 	fons__tt_done(stash);
1685 }
1686 
fonsSetErrorCallback(FONScontext * stash,void (* callback)(void * uptr,int error,int val),void * uptr)1687 void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
1688 {
1689 	if (stash == NULL) return;
1690 	stash->handleError = callback;
1691 	stash->errorUptr = uptr;
1692 }
1693 
fonsGetAtlasSize(FONScontext * stash,int * width,int * height)1694 void fonsGetAtlasSize(FONScontext* stash, int* width, int* height)
1695 {
1696 	if (stash == NULL) return;
1697 	*width = stash->params.width;
1698 	*height = stash->params.height;
1699 }
1700 
fonsExpandAtlas(FONScontext * stash,int width,int height)1701 int fonsExpandAtlas(FONScontext* stash, int width, int height)
1702 {
1703 	int i, maxy = 0;
1704 	unsigned char* data = NULL;
1705 	if (stash == NULL) return 0;
1706 
1707 	width = fons__maxi(width, stash->params.width);
1708 	height = fons__maxi(height, stash->params.height);
1709 
1710 	if (width == stash->params.width && height == stash->params.height)
1711 		return 1;
1712 
1713 	// Flush pending glyphs.
1714 	fons__flush(stash);
1715 
1716 	// Create new texture
1717 	if (stash->params.renderResize != NULL) {
1718 		if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1719 			return 0;
1720 	}
1721 	// Copy old texture data over.
1722 	data = (unsigned char*)malloc(width * height);
1723 	if (data == NULL)
1724 		return 0;
1725 	for (i = 0; i < stash->params.height; i++) {
1726 		unsigned char* dst = &data[i*width];
1727 		unsigned char* src = &stash->texData[i*stash->params.width];
1728 		memcpy(dst, src, stash->params.width);
1729 		if (width > stash->params.width)
1730 			memset(dst+stash->params.width, 0, width - stash->params.width);
1731 	}
1732 	if (height > stash->params.height)
1733 		memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width);
1734 
1735 	free(stash->texData);
1736 	stash->texData = data;
1737 
1738 	// Increase atlas size
1739 	fons__atlasExpand(stash->atlas, width, height);
1740 
1741 	// Add existing data as dirty.
1742 	for (i = 0; i < stash->atlas->nnodes; i++)
1743 		maxy = fons__maxi(maxy, stash->atlas->nodes[i].y);
1744 	stash->dirtyRect[0] = 0;
1745 	stash->dirtyRect[1] = 0;
1746 	stash->dirtyRect[2] = stash->params.width;
1747 	stash->dirtyRect[3] = maxy;
1748 
1749 	stash->params.width = width;
1750 	stash->params.height = height;
1751 	stash->itw = 1.0f/stash->params.width;
1752 	stash->ith = 1.0f/stash->params.height;
1753 
1754 	return 1;
1755 }
1756 
fonsResetAtlas(FONScontext * stash,int width,int height)1757 int fonsResetAtlas(FONScontext* stash, int width, int height)
1758 {
1759 	int i, j;
1760 	if (stash == NULL) return 0;
1761 
1762 	// Flush pending glyphs.
1763 	fons__flush(stash);
1764 
1765 	// Create new texture
1766 	if (stash->params.renderResize != NULL) {
1767 		if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1768 			return 0;
1769 	}
1770 
1771 	// Reset atlas
1772 	fons__atlasReset(stash->atlas, width, height);
1773 
1774 	// Clear texture data.
1775 	stash->texData = (unsigned char*)realloc(stash->texData, width * height);
1776 	if (stash->texData == NULL) return 0;
1777 	memset(stash->texData, 0, width * height);
1778 
1779 	// Reset dirty rect
1780 	stash->dirtyRect[0] = width;
1781 	stash->dirtyRect[1] = height;
1782 	stash->dirtyRect[2] = 0;
1783 	stash->dirtyRect[3] = 0;
1784 
1785 	// Reset cached glyphs
1786 	for (i = 0; i < stash->nfonts; i++) {
1787 		FONSfont* font = stash->fonts[i];
1788 		font->nglyphs = 0;
1789 		for (j = 0; j < FONS_HASH_LUT_SIZE; j++)
1790 			font->lut[j] = -1;
1791 	}
1792 
1793 	stash->params.width = width;
1794 	stash->params.height = height;
1795 	stash->itw = 1.0f/stash->params.width;
1796 	stash->ith = 1.0f/stash->params.height;
1797 
1798 	// Add white rect at 0,0 for debug drawing.
1799 	fons__addWhiteRect(stash, 2,2);
1800 
1801 	return 1;
1802 }
1803 
1804 
1805 #endif
1806