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