LCOV - code coverage report
Current view: top level - src/foreign/fontstash - fontstash.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 349 659 53.0 %
Date: 2024-05-01 15:34:42 Functions: 26 46 56.5 %

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

Generated by: LCOV version 1.14