LCOV - code coverage report
Current view: top level - src/foreign/fontstash - fontstash.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 53.1 % 659 350
Test Date: 2024-12-21 15:45:41 Functions: 56.5 % 46 26

            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         6636 :         font->font.userdata = context;
     283         6636 :         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         6636 :         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        20043 :         return stbtt_FindGlyphIndex(&font->font, codepoint);
     300              : }
     301              : 
     302        20043 : 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        20043 :         stbtt_GetGlyphHMetrics(&font->font, glyph, advance, lsb);
     307              :         stbtt_GetGlyphBitmapBox(&font->font, glyph, scale, scale, x0, y0, x1, y1);
     308        20043 :         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        20043 :         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      1780547 :         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      2858759 :         a += ~(a<<15);
     352      2858759 :         a ^=  (a>>10);
     353              :         a +=  (a<<3);
     354      2858759 :         a ^=  (a>>6);
     355      2858759 :         a += ~(a<<11);
     356      2858759 :         a ^=  (a>>16);
     357              :         return a;
     358              : }
     359              : 
     360              : static int fons__mini(int a, int b)
     361              : {
     362        26679 :         return a < b ? a : b;
     363              : }
     364              : 
     365              : static int fons__maxi(int a, int b)
     366              : {
     367       134186 :         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       100215 :         size = (size + 0xf) & ~0xf;
     456              : 
     457       100215 :         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       100215 :         ptr = stash->scratch + stash->nscratch;
     463        80172 :         stash->nscratch += (int)size;
     464        20043 :         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      2858759 :         unsigned int type = utf8d[byte];
     506              : 
     507      5717518 :         *codep = (*state != FONS_UTF8_ACCEPT) ?
     508            0 :                 (byte & 0x3fu) | (*codep << 6) :
     509      2858759 :                 (0xff >> type) & (byte);
     510              : 
     511      2858759 :         *state = utf8d[256 + *state + type];
     512              :         return *state;
     513              : }
     514              : 
     515              : // Atlas based on Skyline Bin Packer by Jukka Jylänki
     516              : 
     517         6626 : static void fons__deleteAtlas(FONSatlas* atlas)
     518              : {
     519         6626 :         if (atlas == NULL) return;
     520         6626 :         if (atlas->nodes != NULL) free(atlas->nodes);
     521         6626 :         free(atlas);
     522              : }
     523              : 
     524         6636 : static FONSatlas* fons__allocAtlas(int w, int h, int nnodes)
     525              : {
     526              :         FONSatlas* atlas = NULL;
     527              : 
     528              :         // Allocate memory for the font stash.
     529         6636 :         atlas = (FONSatlas*)malloc(sizeof(FONSatlas));
     530         6636 :         if (atlas == NULL) goto error;
     531              :         memset(atlas, 0, sizeof(FONSatlas));
     532              : 
     533         6636 :         atlas->width = w;
     534         6636 :         atlas->height = h;
     535              : 
     536              :         // Allocate space for skyline nodes
     537         6636 :         atlas->nodes = (FONSatlasNode*)malloc(sizeof(FONSatlasNode) * nnodes);
     538         6636 :         if (atlas->nodes == NULL) goto error;
     539              :         memset(atlas->nodes, 0, sizeof(FONSatlasNode) * nnodes);
     540              :         atlas->nnodes = 0;
     541         6636 :         atlas->cnodes = nnodes;
     542              : 
     543              :         // Init root node.
     544         6636 :         atlas->nodes[0].x = 0;
     545         6636 :         atlas->nodes[0].y = 0;
     546         6636 :         atlas->nodes[0].width = (short)w;
     547         6636 :         atlas->nnodes++;
     548              : 
     549         6636 :         return atlas;
     550              : 
     551              : error:
     552            0 :         if (atlas) fons__deleteAtlas(atlas);
     553              :         return NULL;
     554              : }
     555              : 
     556        26679 : static int fons__atlasInsertNode(FONSatlas* atlas, int idx, int x, int y, int w)
     557              : {
     558              :         int i;
     559              :         // Insert node
     560        26679 :         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        53358 :         for (i = atlas->nnodes; i > idx; i--)
     567        26679 :                 atlas->nodes[i] = atlas->nodes[i-1];
     568        26679 :         atlas->nodes[idx].x = (short)x;
     569        26679 :         atlas->nodes[idx].y = (short)y;
     570        26679 :         atlas->nodes[idx].width = (short)w;
     571        26679 :         atlas->nnodes++;
     572              : 
     573        26679 :         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           80 :         for (i = idx; i < atlas->nnodes-1; i++)
     581           40 :                 atlas->nodes[i] = atlas->nodes[i+1];
     582           40 :         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        26679 : 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        26679 :         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        53358 :         for (i = idx+1; i < atlas->nnodes; i++) {
     617        26679 :                 if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) {
     618        26679 :                         int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x;
     619        26679 :                         atlas->nodes[i].x += (short)shrink;
     620        26679 :                         atlas->nodes[i].width -= (short)shrink;
     621        26679 :                         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        93925 :         for (i = 0; i < atlas->nnodes-1; i++) {
     634        67246 :                 if (atlas->nodes[i].y == atlas->nodes[i+1].y) {
     635           40 :                         atlas->nodes[i].width += atlas->nodes[i+1].width;
     636           40 :                         fons__atlasRemoveNode(atlas, i+1);
     637           40 :                         i--;
     638              :                 }
     639              :         }
     640              : 
     641              :         return 1;
     642              : }
     643              : 
     644        67246 : 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        67246 :         int x = atlas->nodes[i].x;
     650        67246 :         int y = atlas->nodes[i].y;
     651              :         int spaceLeft;
     652        67246 :         if (x + w > atlas->width)
     653              :                 return -1;
     654              :         spaceLeft = w;
     655       174753 :         while (spaceLeft > 0) {
     656       107507 :                 if (i == atlas->nnodes) return -1;
     657       107507 :                 y = fons__maxi(y, atlas->nodes[i].y);
     658       107507 :                 if (y + h > atlas->height) return -1;
     659       107507 :                 spaceLeft -= atlas->nodes[i].width;
     660       107507 :                 ++i;
     661              :         }
     662              :         return y;
     663              : }
     664              : 
     665        26679 : static int fons__atlasAddRect(FONSatlas* atlas, int rw, int rh, int* rx, int* ry)
     666              : {
     667        26679 :         int besth = atlas->height, bestw = atlas->width, besti = -1;
     668              :         int bestx = -1, besty = -1, i;
     669              : 
     670              :         // Bottom left fit heuristic.
     671        93925 :         for (i = 0; i < atlas->nnodes; i++) {
     672        67246 :                 int y = fons__atlasRectFits(atlas, i, rw, rh);
     673        67246 :                 if (y != -1) {
     674        67246 :                         if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw)) {
     675              :                                 besti = i;
     676        53474 :                                 bestw = atlas->nodes[i].width;
     677              :                                 besth = y + rh;
     678        53474 :                                 bestx = atlas->nodes[i].x;
     679              :                                 besty = y;
     680              :                         }
     681              :                 }
     682              :         }
     683              : 
     684        26679 :         if (besti == -1)
     685              :                 return 0;
     686              : 
     687              :         // Perform the actual packing.
     688        26679 :         if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0)
     689              :                 return 0;
     690              : 
     691        26679 :         *rx = bestx;
     692        26679 :         *ry = besty;
     693              : 
     694        26679 :         return 1;
     695              : }
     696              : 
     697         6636 : static void fons__addWhiteRect(FONScontext* stash, int w, int h)
     698              : {
     699              :         int x, y, gx, gy;
     700              :         unsigned char* dst;
     701         6636 :         if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
     702            0 :                 return;
     703              : 
     704              :         // Rasterize
     705         6636 :         dst = &stash->texData[gx + gy * stash->params.width];
     706        19908 :         for (y = 0; y < h; y++) {
     707        39816 :                 for (x = 0; x < w; x++)
     708        26544 :                         dst[x] = 0xff;
     709        13272 :                 dst += stash->params.width;
     710              :         }
     711              : 
     712         6636 :         stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
     713         6636 :         stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
     714         6636 :         stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
     715         6636 :         stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
     716              : }
     717              : 
     718         6636 : FONScontext* fonsCreateInternal(FONSparams* params)
     719              : {
     720              :         FONScontext* stash = NULL;
     721              : 
     722              :         // Allocate memory for the font stash.
     723         6636 :         stash = (FONScontext*)malloc(sizeof(FONScontext));
     724         6636 :         if (stash == NULL) goto error;
     725              :         memset(stash, 0, sizeof(FONScontext));
     726              : 
     727         6636 :         stash->params = *params;
     728              : 
     729              :         // Allocate scratch buffer.
     730         6636 :         stash->scratch = (unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE);
     731         6636 :         if (stash->scratch == NULL) goto error;
     732              : 
     733              :         // Initialize implementation library
     734              :         if (!fons__tt_init(stash)) goto error;
     735              : 
     736         6636 :         if (stash->params.renderCreate != NULL) {
     737         6636 :                 if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
     738            0 :                         goto error;
     739              :         }
     740              : 
     741         6636 :         stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES);
     742         6636 :         if (stash->atlas == NULL) goto error;
     743              : 
     744              :         // Allocate space for fonts.
     745         6636 :         stash->fonts = (FONSfont**)malloc(sizeof(FONSfont*) * FONS_INIT_FONTS);
     746         6636 :         if (stash->fonts == NULL) goto error;
     747              :         memset(stash->fonts, 0, sizeof(FONSfont*) * FONS_INIT_FONTS);
     748         6636 :         stash->cfonts = FONS_INIT_FONTS;
     749         6636 :         stash->nfonts = 0;
     750              : 
     751              :         // Create texture for the cache.
     752         6636 :         stash->itw = 1.0f/stash->params.width;
     753         6636 :         stash->ith = 1.0f/stash->params.height;
     754         6636 :         stash->texData = (unsigned char*)malloc(stash->params.width * stash->params.height);
     755         6636 :         if (stash->texData == NULL) goto error;
     756              :         memset(stash->texData, 0, stash->params.width * stash->params.height);
     757              : 
     758         6636 :         stash->dirtyRect[0] = stash->params.width;
     759         6636 :         stash->dirtyRect[1] = stash->params.height;
     760         6636 :         stash->dirtyRect[2] = 0;
     761         6636 :         stash->dirtyRect[3] = 0;
     762              : 
     763              :         // Add white rect at 0,0 for debug drawing.
     764         6636 :         fons__addWhiteRect(stash, 2,2);
     765              : 
     766         6636 :         fonsPushState(stash);
     767         6636 :         fonsClearState(stash);
     768              : 
     769         6636 :         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      3215470 :         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         6636 : void fonsSetSize(FONScontext* stash, float size)
     792              : {
     793         6636 :         fons__getState(stash)->size = size;
     794         6636 : }
     795              : 
     796      1058675 : void fonsSetColor(FONScontext* stash, unsigned int color)
     797              : {
     798      1058675 :         fons__getState(stash)->color = color;
     799      1058675 : }
     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      1058675 : void fonsSetAlign(FONScontext* stash, int align)
     812              : {
     813      1058675 :         fons__getState(stash)->align = align;
     814      1058675 : }
     815              : 
     816         6636 : void fonsSetFont(FONScontext* stash, int font)
     817              : {
     818         6636 :         fons__getState(stash)->font = font;
     819         6636 : }
     820              : 
     821         6636 : void fonsPushState(FONScontext* stash)
     822              : {
     823         6636 :         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         6636 :         if (stash->nstates > 0)
     829            0 :                 memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(FONSstate));
     830         6636 :         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         6636 : void fonsClearState(FONScontext* stash)
     844              : {
     845              :         FONSstate* state = fons__getState(stash);
     846         6636 :         state->size = 12.0f;
     847         6636 :         state->color = 0xffffffff;
     848         6636 :         state->font = 0;
     849         6636 :         state->blur = 0;
     850         6636 :         state->spacing = 0;
     851         6636 :         state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE;
     852         6636 : }
     853              : 
     854         6626 : static void fons__freeFont(FONSfont* font)
     855              : {
     856         6626 :         if (font == NULL) return;
     857         6626 :         if (font->glyphs) free(font->glyphs);
     858         6626 :         if (font->freeData && font->data) free(font->data);
     859         6626 :         free(font);
     860              : }
     861              : 
     862         6636 : static int fons__allocFont(FONScontext* stash)
     863              : {
     864              :         FONSfont* font = NULL;
     865         6636 :         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         6636 :         font = (FONSfont*)malloc(sizeof(FONSfont));
     872         6636 :         if (font == NULL) goto error;
     873              :         memset(font, 0, sizeof(FONSfont));
     874              : 
     875         6636 :         font->glyphs = (FONSglyph*)malloc(sizeof(FONSglyph) * FONS_INIT_GLYPHS);
     876         6636 :         if (font->glyphs == NULL) goto error;
     877         6636 :         font->cglyphs = FONS_INIT_GLYPHS;
     878              :         font->nglyphs = 0;
     879              : 
     880         6636 :         stash->fonts[stash->nfonts++] = font;
     881         6636 :         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              : error:
     911            0 :         if (data) free(data);
     912            0 :         if (fp) fclose(fp);
     913              :         return FONS_INVALID;
     914              : }
     915              : 
     916         6636 : 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         6636 :         int idx = fons__allocFont(stash);
     922         6636 :         if (idx == FONS_INVALID)
     923              :                 return FONS_INVALID;
     924              : 
     925         6636 :         font = stash->fonts[idx];
     926              : 
     927         6636 :         strncpy(font->name, name, sizeof(font->name));
     928         6636 :         font->name[sizeof(font->name)-1] = '\0';
     929              : 
     930              :         // Init hash lookup.
     931      1705452 :         for (i = 0; i < FONS_HASH_LUT_SIZE; ++i)
     932      1698816 :                 font->lut[i] = -1;
     933              : 
     934              :         // Read in the font data.
     935         6636 :         font->dataSize = dataSize;
     936         6636 :         font->data = data;
     937         6636 :         font->freeData = (unsigned char)freeData;
     938              : 
     939              :         // Init font
     940         6636 :         stash->nscratch = 0;
     941         6636 :         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         6636 :         fh = ascent - descent;
     947         6636 :         font->ascender = (float)ascent / (float)fh;
     948         6636 :         font->descender = (float)descent / (float)fh;
     949         6636 :         font->lineh = (float)(fh + lineGap) / (float)fh;
     950              : 
     951         6636 :         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        20043 : static FONSglyph* fons__allocGlyph(FONSfont* font)
     971              : {
     972        20043 :         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        20043 :         font->nglyphs++;
     978        20043 :         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      2858759 : 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      2858759 :         float size = isize/10.0f;
    1055              :         int pad, added;
    1056              :         unsigned char* bdst;
    1057              :         unsigned char* dst;
    1058              :         FONSfont* renderFont = font;
    1059              : 
    1060      2858759 :         if (isize < 2) return NULL;
    1061      2858759 :         if (iblur > 20) iblur = 20;
    1062      2858759 :         pad = iblur+2;
    1063              : 
    1064              :         // Reset allocator.
    1065      2858759 :         stash->nscratch = 0;
    1066              : 
    1067              :         // Find code point and size.
    1068      2858759 :         h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
    1069      2858759 :         i = font->lut[h];
    1070      2858785 :         while (i != -1) {
    1071      2838742 :                 if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur)
    1072      2838716 :                         return &font->glyphs[i];
    1073           26 :                 i = font->glyphs[i].next;
    1074              :         }
    1075              : 
    1076              :         // Could not find glyph, create it.
    1077        20043 :         g = fons__tt_getGlyphIndex(&font->font, codepoint);
    1078              :         // Try to find the glyph in fallback fonts.
    1079        20043 :         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        20043 :         fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
    1094        20043 :         gw = x1-x0 + pad*2;
    1095        20043 :         gh = y1-y0 + pad*2;
    1096              : 
    1097              :         // Find free spot for the rect in the atlas
    1098        20043 :         added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
    1099        20043 :         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            0 :         if (added == 0) return NULL;
    1105              : 
    1106              :         // Init glyph.
    1107        20043 :         glyph = fons__allocGlyph(font);
    1108        20043 :         glyph->codepoint = codepoint;
    1109        20043 :         glyph->size = isize;
    1110        20043 :         glyph->blur = iblur;
    1111        20043 :         glyph->index = g;
    1112        20043 :         glyph->x0 = (short)gx;
    1113        20043 :         glyph->y0 = (short)gy;
    1114        20043 :         glyph->x1 = (short)(glyph->x0+gw);
    1115        20043 :         glyph->y1 = (short)(glyph->y0+gh);
    1116        20043 :         glyph->xadv = (short)(scale * advance * 10.0f);
    1117        20043 :         glyph->xoff = (short)(x0 - pad);
    1118        20043 :         glyph->yoff = (short)(y0 - pad);
    1119        20043 :         glyph->next = 0;
    1120              : 
    1121              :         // Insert char to hash lookup.
    1122        20043 :         glyph->next = font->lut[h];
    1123        20043 :         font->lut[h] = font->nglyphs-1;
    1124              : 
    1125              :         // Rasterize
    1126        20043 :         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        20043 :         dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
    1131       674794 :         for (y = 0; y < gh; y++) {
    1132       654751 :                 dst[y*stash->params.width] = 0;
    1133       654751 :                 dst[gw-1 + y*stash->params.width] = 0;
    1134              :         }
    1135       547840 :         for (x = 0; x < gw; x++) {
    1136       527797 :                 dst[x] = 0;
    1137       527797 :                 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        20043 :         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        20043 :         stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
    1158        20043 :         stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
    1159        20043 :         stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
    1160        20043 :         stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);
    1161              : 
    1162        20043 :         return glyph;
    1163              : }
    1164              : 
    1165      2858759 : 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      2858759 :         if (prevGlyphIndex != -1) {
    1172      1780547 :                 float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale;
    1173      1780547 :                 *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      2858759 :         xoff = (short)(glyph->xoff+1);
    1180      2858759 :         yoff = (short)(glyph->yoff+1);
    1181      2858759 :         x0 = (float)(glyph->x0+1);
    1182      2858759 :         y0 = (float)(glyph->y0+1);
    1183      2858759 :         x1 = (float)(glyph->x1-1);
    1184      2858759 :         y1 = (float)(glyph->y1-1);
    1185              : 
    1186      2858759 :         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      2858759 :                 rx = (float)(int)(*x + xoff);
    1201      2858759 :                 ry = (float)(int)(*y - yoff);
    1202              : 
    1203      2858759 :                 q->x0 = rx;
    1204      2858759 :                 q->y0 = ry;
    1205      2858759 :                 q->x1 = rx + x1 - x0;
    1206      2858759 :                 q->y1 = ry - y1 + y0;
    1207              : 
    1208      2858759 :                 q->s0 = x0 * stash->itw;
    1209      2858759 :                 q->t0 = y0 * stash->ith;
    1210      2858759 :                 q->s1 = x1 * stash->itw;
    1211      2858759 :                 q->t1 = y1 * stash->ith;
    1212              :         }
    1213              : 
    1214      2858759 :         *x += (int)(glyph->xadv / 10.0f + 0.5f);
    1215      2858759 : }
    1216              : 
    1217      1058675 : static void fons__flush(FONScontext* stash)
    1218              : {
    1219              :         // Flush texture
    1220      1058675 :         if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
    1221        13345 :                 if (stash->params.renderUpdate != NULL)
    1222        13345 :                         stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData);
    1223              :                 // Reset dirty rect
    1224        13345 :                 stash->dirtyRect[0] = stash->params.width;
    1225        13345 :                 stash->dirtyRect[1] = stash->params.height;
    1226        13345 :                 stash->dirtyRect[2] = 0;
    1227        13345 :                 stash->dirtyRect[3] = 0;
    1228              :         }
    1229              : 
    1230              :         // Flush triangles
    1231      1058675 :         if (stash->nverts > 0) {
    1232      1058675 :                 if (stash->params.renderDraw != NULL)
    1233      1058675 :                         stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->tcoords, stash->colors, stash->nverts);
    1234      1058675 :                 stash->nverts = 0;
    1235              :         }
    1236      1058675 : }
    1237              : 
    1238              : static __inline void fons__vertex(FONScontext* stash, float x, float y, float s, float t, unsigned int c)
    1239              : {
    1240      2812045 :         stash->verts[stash->nverts*2+0] = x;
    1241      2812045 :         stash->verts[stash->nverts*2+1] = y;
    1242      2812045 :         stash->tcoords[stash->nverts*2+0] = s;
    1243      2812045 :         stash->tcoords[stash->nverts*2+1] = t;
    1244      2812045 :         stash->colors[stash->nverts] = c;
    1245      2812045 :         stash->nverts++;
    1246              : }
    1247              : 
    1248      1078212 : static float fons__getVertAlign(FONScontext* stash, FONSfont* font, int align, short isize)
    1249              : {
    1250      1078212 :         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      1078212 :                 if (align & FONS_ALIGN_TOP) {
    1262            0 :                         return -font->ascender * (float)isize/10.0f;
    1263      1078212 :                 } else if (align & FONS_ALIGN_MIDDLE) {
    1264        39074 :                         return -(font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
    1265      1039138 :                 } else if (align & FONS_ALIGN_BASELINE) {
    1266              :                         return 0.0f;
    1267      1039138 :                 } else if (align & FONS_ALIGN_BOTTOM) {
    1268            0 :                         return -font->descender * (float)isize/10.0f;
    1269              :                 }
    1270              :         }
    1271              :         return 0.0;
    1272              : }
    1273              : 
    1274      1058675 : 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      1058675 :         short isize = (short)(state->size*10.0f);
    1285      1058675 :         short iblur = (short)state->blur;
    1286              :         float scale;
    1287              :         FONSfont* font;
    1288              :         float width;
    1289              : 
    1290              :         if (stash == NULL) return x;
    1291      1058675 :         if (state->font < 0 || state->font >= stash->nfonts) return x;
    1292      1058675 :         font = stash->fonts[state->font];
    1293      1058675 :         if (font->data == NULL) return x;
    1294              : 
    1295      1058675 :         scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
    1296              : 
    1297      1058675 :         if (end == NULL)
    1298      1058675 :                 end = str + strlen(str);
    1299              : 
    1300              :         // Align horizontally
    1301      1058675 :         if (state->align & FONS_ALIGN_LEFT) {
    1302              :                 // empty
    1303        19537 :         } else if (state->align & FONS_ALIGN_RIGHT) {
    1304            0 :                 width = fonsTextBounds(stash, x,y, str, end, NULL);
    1305            0 :                 x -= width;
    1306        19537 :         } else if (state->align & FONS_ALIGN_CENTER) {
    1307        19537 :                 width = fonsTextBounds(stash, x,y, str, end, NULL);
    1308        19537 :                 x -= width * 0.5f;
    1309              :         }
    1310              :         // Align vertically.
    1311      1058675 :         y += fons__getVertAlign(stash, font, state->align, isize);
    1312              : 
    1313      3870720 :         for (; str != end; ++str) {
    1314      5624090 :                 if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
    1315            0 :                         continue;
    1316      2812045 :                 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
    1317      2812045 :                 if (glyph != NULL) {
    1318      2812045 :                         fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
    1319              : 
    1320      2812045 :                         if (stash->nverts+6 > FONS_VERTEX_COUNT)
    1321            0 :                                 fons__flush(stash);
    1322              : 
    1323      2812045 :                         fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
    1324      2812045 :                         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      2812045 :                 prevGlyphIndex = glyph != NULL ? glyph->index : -1;
    1332              :         }
    1333      1058675 :         fons__flush(stash);
    1334              : 
    1335      1058675 :         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        19537 : 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        19537 :         short isize = (short)(state->size*10.0f);
    1470        19537 :         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        19537 :         if (state->font < 0 || state->font >= stash->nfonts) return 0;
    1478        19537 :         font = stash->fonts[state->font];
    1479        19537 :         if (font->data == NULL) return 0;
    1480              : 
    1481        19537 :         scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
    1482              : 
    1483              :         // Align vertically.
    1484        19537 :         y += fons__getVertAlign(stash, font, state->align, isize);
    1485              : 
    1486        19537 :         minx = maxx = x;
    1487              :         miny = maxy = y;
    1488              :         startx = x;
    1489              : 
    1490        19537 :         if (end == NULL)
    1491            0 :                 end = str + strlen(str);
    1492              : 
    1493        66251 :         for (; str != end; ++str) {
    1494        93428 :                 if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
    1495            0 :                         continue;
    1496        46714 :                 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
    1497        46714 :                 if (glyph != NULL) {
    1498        46714 :                         fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
    1499        46714 :                         if (q.x0 < minx) minx = q.x0;
    1500        46714 :                         if (q.x1 > maxx) maxx = q.x1;
    1501        46714 :                         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        46714 :                                 if (q.y1 < miny) miny = q.y1;
    1506        46714 :                                 if (q.y0 > maxy) maxy = q.y0;
    1507              :                         }
    1508              :                 }
    1509        46714 :                 prevGlyphIndex = glyph != NULL ? glyph->index : -1;
    1510              :         }
    1511              : 
    1512        19537 :         advance = x - startx;
    1513              : 
    1514              :         // Align horizontally
    1515        19537 :         if (state->align & FONS_ALIGN_LEFT) {
    1516              :                 // empty
    1517        19537 :         } else if (state->align & FONS_ALIGN_RIGHT) {
    1518            0 :                 minx -= advance;
    1519            0 :                 maxx -= advance;
    1520        19537 :         } else if (state->align & FONS_ALIGN_CENTER) {
    1521        19537 :                 minx -= advance * 0.5f;
    1522        19537 :                 maxx -= advance * 0.5f;
    1523              :         }
    1524              : 
    1525        19537 :         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        22280 : FONS_DEF void fonsDeleteInternal(FONScontext* stash)
    1606              : {
    1607              :         int i;
    1608        22280 :         if (stash == NULL) return;
    1609              : 
    1610         6626 :         if (stash->params.renderDelete)
    1611         6626 :                 stash->params.renderDelete(stash->params.userPtr);
    1612              : 
    1613        13252 :         for (i = 0; i < stash->nfonts; ++i)
    1614         6626 :                 fons__freeFont(stash->fonts[i]);
    1615              : 
    1616         6626 :         if (stash->atlas) fons__deleteAtlas(stash->atlas);
    1617         6626 :         if (stash->fonts) free(stash->fonts);
    1618         6626 :         if (stash->texData) free(stash->texData);
    1619         6626 :         if (stash->scratch) free(stash->scratch);
    1620         6626 :         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 2.0-1