diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index b548328..dcab28d 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -18,10 +18,12 @@ typedef struct _MwLLCommonPixmap* MwLLCommonPixmap; typedef union _MwLL* MwLL; typedef union _MwLLColor* MwLLColor; typedef union _MwLLPixmap* MwLLPixmap; +typedef struct _MwFLFont* MwFLFont; #else typedef void* MwLL; typedef void* MwLLColor; typedef void* MwLLPixmap; +typedef void* MwFLFont; #endif enum MwLLBackends { @@ -166,6 +168,14 @@ struct _MwLLHandler { void (*dark_theme)(MwLL handle, void* data); }; +struct _MwLLTextDispatchTable { + int (*drawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); + int (*textWidth)(MwWidget handle, const char* text); + int (*textHeight)(MwWidget handle, int count); + void* (*fontLoad)(unsigned char* data, unsigned int size); + void (*fontFree)(void* handle); +}; + #ifdef __cplusplus extern "C" { #endif @@ -225,6 +235,22 @@ MWDECL void (*MwLLGetClipboard)(MwLL handle); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); +/*font renderer */ +MWDECL void MwFLSetup(); + +#ifdef USE_FREETYPE2 +MWDECL int MWFL_FT2Setup(); +#endif +#ifdef USE_STB_TRUETYPE +MWDECL int MwFL_STBTTSetup(); +#endif + +MWDECL int (*MwFLDrawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); +MWDECL int (*MwFLTextWidth)(MwWidget handle, const char* text); +MWDECL int (*MwFLTextHeight)(MwWidget handle, int count); +MWDECL void* (*MwFLFontLoad)(unsigned char* data, unsigned int size); +MWDECL void (*MwFLFontFree)(void* handle); + #ifdef __cplusplus } #endif diff --git a/pl/rules.pl b/pl/rules.pl index 59605a8..d4784e1 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -76,8 +76,9 @@ if (param_get("vulkan") && param_get("vulkan-string-helper")) { } new_object("src/icon/*.c"); -new_object("src/font/*.c"); new_object("src/cursor/*.c"); +new_object("src/text/*.c"); +new_object("src/text/font/*.c"); new_object("src/widget/box.c"); new_object("src/widget/button.c"); diff --git a/src/core.c b/src/core.c index 6985a02..9902a30 100644 --- a/src/core.c +++ b/src/core.c @@ -784,6 +784,8 @@ int MwLibraryInit(void) { NULL}; int i; + MwFLSetup(); + for(i = 0; calls[i] != NULL; i++) { if(calls[i]() == 0) return 0; } diff --git a/src/text.c b/src/text.c deleted file mode 100644 index c0e00c6..0000000 --- a/src/text.c +++ /dev/null @@ -1,384 +0,0 @@ -#include - -#if defined(USE_FREETYPE2) -#include -#include FT_FREETYPE_H - -typedef struct ttf { - FT_Library library; - FT_Face face; - void* data; -} ttf_t; - -#define TTF -#elif defined(USE_STB_TRUETYPE) -#include "../external/stb_truetype.h" - -typedef struct ttf { - stbtt_fontinfo font; - void* data; - float scale; - int ascent; - int descent; -} ttf_t; - -#define TTF -#endif - -#define FontWidth 7 -#define FontHeight 14 - -static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - int i = 0, x, y, sx, sy; - int tw, th; - unsigned char* px; - MwRect r; - MwLLPixmap p; - - if(strlen(text) == 0) text = " "; - tw = MwTextWidth(handle, text); - th = MwTextHeight(handle, text); - px = malloc(tw * th * 4); - - memset(px, 0, tw * th * 4); - - sx = 0; - sy = 0; - - while(text[i] != 0) { - int out; - i += MwUTF8ToUTF32(text + i, &out); - - if(out > 0xff) { - out = 0; - } - - if(out == '\n') { - sx = 0; - sy += FontHeight; - } else { - for(y = 0; y < FontHeight; y++) { - for(x = 0; x < FontWidth; x++) { - unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; - if((bold ? MwBoldFontData : MwFontData)[out].data[y] & (1 << ((FontWidth - 1) - x))) { - ppx[0] = color->common.red; - ppx[1] = color->common.green; - ppx[2] = color->common.blue; - ppx[3] = 255; - } else { - ppx[0] = 0; - ppx[1] = 0; - ppx[2] = 0; - ppx[3] = 0; - } - } - } - sx += FontWidth; - } - } - - p = MwLoadRaw(handle, px, tw, th); - r.x = point->x; - r.y = point->y - th / 2; - r.width = tw; - r.height = th; - - if(align == MwALIGNMENT_CENTER) { - r.x -= tw / 2; - } else if(align == MwALIGNMENT_END) { - r.x -= tw; - } - - MwLLDrawPixmap(handle->lowlevel, &r, p); - MwLLDestroyPixmap(p); - free(px); -} - -#if defined(USE_STB_TRUETYPE) -static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - ttf_t* ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); - unsigned char* px; - int tw, th; - MwRect r; - MwLLPixmap p; - int ax, lsb; - int x = 0, y = 0; - if(ttf == NULL) return 1; - - tw = MwTextWidth(handle, text); - th = MwTextHeight(handle, text); - px = malloc(tw * th * 4); - - memset(px, 0, tw * th * 4); - while(text[0] != 0) { - int c; - int x0, y0, x1, y1, cx, cy; - int ow, oh; - unsigned char* out; - - text += MwUTF8ToUTF32(text, &c); - if(c == '\n') { - x = 0; - y += (ttf->ascent - ttf->descent) * ttf->scale; - continue; - } - - stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); - - stbtt_GetCodepointBitmapBox(&ttf->font, c, ttf->scale, ttf->scale, &x0, &y0, &x1, &y1); - ow = x1 - x0; - oh = y1 - y0; - out = malloc(ow * oh); - stbtt_MakeCodepointBitmap(&ttf->font, out, ow, oh, ow, ttf->scale, ttf->scale, c); - - for(cy = 0; cy < oh; cy++) { - for(cx = 0; cx < ow; cx++) { - int ox = x + (lsb * ttf->scale) + cx; - int oy = y + (ttf->ascent * ttf->scale) + y0 + cy; - unsigned char* opx = &px[(oy * tw + ox) * 4]; - - opx[0] = color->common.red; - opx[1] = color->common.green; - opx[2] = color->common.blue; - opx[3] = out[cy * ow + cx]; - } - } - - x += ax * ttf->scale; - - free(out); - } - - p = MwLoadRaw(handle, px, tw, th); - r.x = point->x; - r.y = point->y - th / 2; - r.width = tw; - r.height = th; - - if(align == MwALIGNMENT_CENTER) { - r.x -= tw / 2; - } else if(align == MwALIGNMENT_END) { - r.x -= tw; - } - - MwLLDrawPixmap(handle->lowlevel, &r, p); - MwLLDestroyPixmap(p); - free(px); - - return 0; -} - -static int ttf_MwTextWidth(MwWidget handle, const char* text) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - int ax, lsb; - int tw = 0; - if(ttf == NULL) return -1; - - while(text[0] != 0) { - int c; - text += MwUTF8ToUTF32(text, &c); - - stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); - - tw += ax * ttf->scale; - } - - return tw; -} - -static int ttf_MwTextHeight(MwWidget handle, int count) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - if(ttf == NULL) return -1; - - return (ttf->ascent - ttf->descent) * ttf->scale * count; -} -#elif defined(USE_FREETYPE2) -static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - ttf_t* ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); - int tw, th; - unsigned char* px; - MwLLPixmap p; - MwRect r; - int x = 0, y = 0; - if(ttf == NULL) return 1; - - tw = MwTextWidth(handle, text); - th = MwTextHeight(handle, text); - px = malloc(tw * th * 4); - - memset(px, 0, tw * th * 4); - while(text[0] != 0) { - int c; - FT_Bitmap* bmp; - int cy, cx; - int l = MwUTF8ToUTF32(text, &c); - if(l <= 0) break; - text += l; - - if(c == '\n') { - x = 0; - y += ttf->face->height * 14 / ttf->face->units_per_EM; - continue; - } - - FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); - bmp = &ttf->face->glyph->bitmap; - - for(cy = 0; cy < bmp->rows; cy++) { - for(cx = 0; cx < bmp->width; cx++) { - int ox = x + cx + ttf->face->glyph->bitmap_left; - int oy = y + (ttf->face->height * 14 / ttf->face->units_per_EM) - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * 14 / ttf->face->units_per_EM); - unsigned char* opx = &px[(oy * tw + ox) * 4]; - - opx[0] = color->common.red; - opx[1] = color->common.green; - opx[2] = color->common.blue; - opx[3] = bmp->buffer[cy * bmp->pitch + cx]; - } - } - - x += ttf->face->glyph->metrics.horiAdvance / 64; - } - - p = MwLoadRaw(handle, px, tw, th); - r.x = point->x; - r.y = point->y - th / 2; - r.width = tw; - r.height = th; - - if(align == MwALIGNMENT_CENTER) { - r.x -= tw / 2; - } else if(align == MwALIGNMENT_END) { - r.x -= tw; - } - - MwLLDrawPixmap(handle->lowlevel, &r, p); - MwLLDestroyPixmap(p); - free(px); - - return 0; -} - -static int ttf_MwTextWidth(MwWidget handle, const char* text) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - int tw = 0, mtw = 0; - if(ttf == NULL) return -1; - - while(text[0] != 0) { - int c; - int l = MwUTF8ToUTF32(text, &c); - if(l <= 0) break; - text += l; - if(c == '\n') { - tw = 0; - continue; - } - - FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); - - tw += ttf->face->glyph->metrics.horiAdvance / 64; - if(tw > mtw) mtw = tw; - } - - return mtw; -} - -static int ttf_MwTextHeight(MwWidget handle, int count) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - if(ttf == NULL) return -1; - - return (ttf->face->height * 14 / ttf->face->units_per_EM) * count; -} -#endif - -void MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - if(strlen(text) == 0) return; -#ifdef TTF - if(MwGetInteger(handle, MwNbitmapFont) || ttf_MwDrawText(handle, point, text, bold, align, color)) -#endif - bitmap_MwDrawText(handle, point, text, bold, align, color); -} - -int MwTextWidth(MwWidget handle, const char* text) { - /* TODO: check newline */ -#ifdef TTF - int st; - - if(!MwGetInteger(handle, MwNbitmapFont) && (st = ttf_MwTextWidth(handle, text)) != -1) return st; -#else - (void)handle; - -#endif - return MwUTF8Length(text) * FontWidth; -} - -int MwTextHeight(MwWidget handle, const char* text) { - int c = 1; - int i = 0; -#ifdef TTF - int st; -#endif - - (void)handle; - (void)text; - - while(text[i] != 0) { - int out; - int l = MwUTF8ToUTF32(text + i, &out); - if(l == 0) break; - i += l; - - if(out == '\n') c++; - } -#ifdef TTF - if(!MwGetInteger(handle, MwNbitmapFont) && (st = ttf_MwTextHeight(handle, c)) != -1) return st; -#endif - return FontHeight * c; -} - -void* MwFontLoad(unsigned char* data, unsigned int size) { -#if defined(USE_FREETYPE2) - ttf_t* ttf = malloc(sizeof(*ttf)); - ttf->data = malloc(size); - memcpy(ttf->data, data, size); - FT_Init_FreeType(&ttf->library); - FT_New_Memory_Face(ttf->library, ttf->data, size, 0, &ttf->face); - - FT_Set_Pixel_Sizes(ttf->face, 0, 14); - - return ttf; -#elif defined(USE_STB_TRUETYPE) - ttf_t* ttf = malloc(sizeof(*ttf)); - ttf->data = malloc(size); - memcpy(ttf->data, data, size); - stbtt_InitFont(&ttf->font, ttf->data, 0); - - ttf->scale = stbtt_ScaleForPixelHeight(&ttf->font, 16); - stbtt_GetFontVMetrics(&ttf->font, &ttf->ascent, &ttf->descent, 0); - - return ttf; -#else - (void)data; - (void)size; - return NULL; -#endif -} - -void MwFontFree(void* handle) { -#if defined(USE_FREETYPE2) - ttf_t* ttf = handle; - - FT_Done_Face(ttf->face); - FT_Done_FreeType(ttf->library); - - free(ttf->data); - free(ttf); -#elif defined(USE_STB_TRUETYPE) - ttf_t* ttf = handle; - - free(ttf->data); - free(ttf); -#else - (void)handle; -#endif -} diff --git a/src/font/boldfont.c b/src/text/font/boldfont.c similarity index 100% rename from src/font/boldfont.c rename to src/text/font/boldfont.c diff --git a/src/font/boldttf.c b/src/text/font/boldttf.c similarity index 100% rename from src/font/boldttf.c rename to src/text/font/boldttf.c diff --git a/src/font/font.c b/src/text/font/font.c similarity index 100% rename from src/font/font.c rename to src/text/font/font.c diff --git a/src/font/ttf.c b/src/text/font/ttf.c similarity index 100% rename from src/font/ttf.c rename to src/text/font/ttf.c diff --git a/src/text/ft2.c b/src/text/ft2.c new file mode 100644 index 0000000..a5fb920 --- /dev/null +++ b/src/text/ft2.c @@ -0,0 +1,139 @@ +#ifdef USE_FREETYPE2 +#include + +#include +#include FT_FREETYPE_H + +struct _MwFLFont { + FT_Library library; + FT_Face face; + void* data; +}; +static int ft2_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + MwFLFont ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); + int tw, th; + unsigned char* px; + MwLLPixmap p; + MwRect r; + int x = 0, y = 0; + if(ttf == NULL) return 1; + + tw = MwTextWidth(handle, text); + th = MwTextHeight(handle, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + while(text[0] != 0) { + int c; + FT_Bitmap* bmp; + int cy, cx; + int l = MwUTF8ToUTF32(text, &c); + if(l <= 0) break; + text += l; + + if(c == '\n') { + x = 0; + y += ttf->face->height * 14 / ttf->face->units_per_EM; + continue; + } + + FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); + bmp = &ttf->face->glyph->bitmap; + + for(cy = 0; cy < bmp->rows; cy++) { + for(cx = 0; cx < bmp->width; cx++) { + int ox = x + cx + ttf->face->glyph->bitmap_left; + int oy = y + (ttf->face->height * 14 / ttf->face->units_per_EM) - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * 14 / ttf->face->units_per_EM); + unsigned char* opx = &px[(oy * tw + ox) * 4]; + + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + opx[3] = bmp->buffer[cy * bmp->pitch + cx]; + } + } + + x += ttf->face->glyph->metrics.horiAdvance / 64; + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + if(align == MwALIGNMENT_CENTER) { + r.x -= tw / 2; + } else if(align == MwALIGNMENT_END) { + r.x -= tw; + } + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + return 0; +} + +static int ft2_MwTextWidth(MwWidget handle, const char* text) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + int tw = 0, mtw = 0; + if(ttf == NULL) return -1; + + while(text[0] != 0) { + int c; + int l = MwUTF8ToUTF32(text, &c); + if(l <= 0) break; + text += l; + if(c == '\n') { + tw = 0; + continue; + } + + FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); + + tw += ttf->face->glyph->metrics.horiAdvance / 64; + if(tw > mtw) mtw = tw; + } + + return mtw; +} + +static int ft2_MwTextHeight(MwWidget handle, int count) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + if(ttf == NULL) return -1; + + return (ttf->face->height * 14 / ttf->face->units_per_EM) * count; +} + +static void* ft2_MwFontLoad(unsigned char* data, unsigned int size) { + MwFLFont ttf = malloc(sizeof(*ttf)); + ttf->data = malloc(size); + memcpy(ttf->data, data, size); + FT_Init_FreeType(&ttf->library); + FT_New_Memory_Face(ttf->library, ttf->data, size, 0, &ttf->face); + + FT_Set_Pixel_Sizes(ttf->face, 0, 14); + + return ttf; +} + +static void ft2_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + FT_Done_Face(ttf->face); + FT_Done_FreeType(ttf->library); + + free(ttf->data); + free(ttf); +} + +int MWFL_FT2Setup() { + MwFLDrawText = ft2_MwDrawText; + MwFLTextWidth = ft2_MwTextWidth; + MwFLTextHeight = ft2_MwTextHeight; + MwFLFontLoad = ft2_MwFontLoad; + MwFLFontFree = ft2_MwFontFree; + return 0; +} +#endif diff --git a/src/text/stbtt.c b/src/text/stbtt.c new file mode 100644 index 0000000..fb5e783 --- /dev/null +++ b/src/text/stbtt.c @@ -0,0 +1,141 @@ +#ifdef USE_STB_TRUETYPE +#include +#include + +#include "../../external/stb_truetype.h" + +struct _MwFLFont { + stbtt_fontinfo font; + void* data; + float scale; + int ascent; + int descent; +}; + +static int stbtt_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + MwFLFont ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); + unsigned char* px; + int tw, th; + MwRect r; + MwLLPixmap p; + int ax, lsb; + int x = 0, y = 0; + if(ttf == NULL) return 1; + + tw = MwTextWidth(handle, text); + th = MwTextHeight(handle, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + while(text[0] != 0) { + int c; + int x0, y0, x1, y1, cx, cy; + int ow, oh; + unsigned char* out; + + text += MwUTF8ToUTF32(text, &c); + if(c == '\n') { + x = 0; + y += (ttf->ascent - ttf->descent) * ttf->scale; + continue; + } + + stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); + + stbtt_GetCodepointBitmapBox(&ttf->font, c, ttf->scale, ttf->scale, &x0, &y0, &x1, &y1); + ow = x1 - x0; + oh = y1 - y0; + out = malloc(ow * oh); + stbtt_MakeCodepointBitmap(&ttf->font, out, ow, oh, ow, ttf->scale, ttf->scale, c); + + for(cy = 0; cy < oh; cy++) { + for(cx = 0; cx < ow; cx++) { + int ox = x + (lsb * ttf->scale) + cx; + int oy = y + (ttf->ascent * ttf->scale) + y0 + cy; + unsigned char* opx = &px[(oy * tw + ox) * 4]; + + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + opx[3] = out[cy * ow + cx]; + } + } + + x += ax * ttf->scale; + + free(out); + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + if(align == MwALIGNMENT_CENTER) { + r.x -= tw / 2; + } else if(align == MwALIGNMENT_END) { + r.x -= tw; + } + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + return 0; +} + +static int stbtt_MwTextWidth(MwWidget handle, const char* text) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + int ax, lsb; + int tw = 0; + if(ttf == NULL) return -1; + + while(text[0] != 0) { + int c; + text += MwUTF8ToUTF32(text, &c); + + stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); + + tw += ax * ttf->scale; + } + + return tw; +} + +static int stbtt_MwTextHeight(MwWidget handle, int count) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + if(ttf == NULL) return -1; + + return (ttf->ascent - ttf->descent) * ttf->scale * count; +} + +static void* stbtt_MwFontLoad(unsigned char* data, unsigned int size) { + MwFLFont ttf = malloc(sizeof(*ttf)); + ttf->data = malloc(size); + memcpy(ttf->data, data, size); + stbtt_InitFont(&ttf->font, ttf->data, 0); + + ttf->scale = stbtt_ScaleForPixelHeight(&ttf->font, 16); + stbtt_GetFontVMetrics(&ttf->font, &ttf->ascent, &ttf->descent, 0); + + return ttf; +} + +static void stbtt_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + free(ttf->data); + free(ttf); +} + +int MwFL_STBTTSetup() { + MwFLDrawText = stbtt_MwDrawText; + MwFLTextWidth = stbtt_MwTextWidth; + MwFLTextHeight = stbtt_MwTextHeight; + MwFLFontLoad = stbtt_MwFontLoad; + MwFLFontFree = stbtt_MwFontFree; + return 0; +} + +#endif diff --git a/src/text/text.c b/src/text/text.c new file mode 100644 index 0000000..e25d28b --- /dev/null +++ b/src/text/text.c @@ -0,0 +1,158 @@ +#include + +int (*MwFLDrawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) = NULL; +int (*MwFLTextWidth)(MwWidget handle, const char* text) = NULL; +int (*MwFLTextHeight)(MwWidget handle, int count) = NULL; +void* (*MwFLFontLoad)(unsigned char* data, unsigned int size) = NULL; +void (*MwFLFontFree)(void* handle) = NULL; + +#if defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE) +#define TTF +#endif + +#define FontWidth 7 +#define FontHeight 14 + +static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); + +void MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + if(strlen(text) == 0) return; +#ifdef TTF + if(MwFLDrawText) + if(MwGetInteger(handle, MwNbitmapFont) || MwFLDrawText(handle, point, text, bold, align, color)) +#endif + bitmap_MwDrawText(handle, point, text, bold, align, color); +} + +int MwTextWidth(MwWidget handle, const char* text) { + /* TODO: check newline */ +#ifdef TTF + int st; + + if(MwFLTextWidth) + if(!MwGetInteger(handle, MwNbitmapFont) && (st = MwFLTextWidth(handle, text)) != -1) return st; +#else + (void)handle; + +#endif + return MwUTF8Length(text) * FontWidth; +} + +int MwTextHeight(MwWidget handle, const char* text) { + int c = 1; + int i = 0; +#ifdef TTF + int st; +#endif + + (void)handle; + (void)text; + + while(text[i] != 0) { + int out; + int l = MwUTF8ToUTF32(text + i, &out); + if(l == 0) break; + i += l; + + if(out == '\n') c++; + } +#ifdef TTF + if(MwFLTextHeight) + if(!MwGetInteger(handle, MwNbitmapFont) && (st = MwFLTextHeight(handle, c)) != -1) return st; +#endif + return FontHeight * c; +} + +void* MwFontLoad(unsigned char* data, unsigned int size) { + if(MwFLFontLoad) + return MwFLFontLoad(data, size); + return NULL; +} + +void MwFontFree(void* handle) { + if(MwFLFontFree) + return MwFLFontFree(handle); +} + +static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + int i = 0, x, y, sx, sy; + int tw, th; + unsigned char* px; + MwRect r; + MwLLPixmap p; + + if(strlen(text) == 0) text = " "; + tw = MwTextWidth(handle, text); + th = MwTextHeight(handle, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + + sx = 0; + sy = 0; + + while(text[i] != 0) { + int out; + i += MwUTF8ToUTF32(text + i, &out); + + if(out > 0xff) { + out = 0; + } + + if(out == '\n') { + sx = 0; + sy += FontHeight; + } else { + for(y = 0; y < FontHeight; y++) { + for(x = 0; x < FontWidth; x++) { + unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; + if((bold ? MwBoldFontData : MwFontData)[out].data[y] & (1 << ((FontWidth - 1) - x))) { + ppx[0] = color->common.red; + ppx[1] = color->common.green; + ppx[2] = color->common.blue; + ppx[3] = 255; + } else { + ppx[0] = 0; + ppx[1] = 0; + ppx[2] = 0; + ppx[3] = 0; + } + } + } + sx += FontWidth; + } + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + if(align == MwALIGNMENT_CENTER) { + r.x -= tw / 2; + } else if(align == MwALIGNMENT_END) { + r.x -= tw; + } + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); +} + +typedef int (*call_t)(); +void MwFLSetup() { + call_t calls[] = { +#ifdef USE_FREETYPE2 + MWFL_FT2Setup, +#endif +#ifdef USE_STB_TRUETYPE + MwFL_STBTTSetup, +#endif + NULL}; + int i; + + for(i = 0; calls[i] != NULL; i++) { + if(calls[i]() == 0) return; + } +}