Fork of Tangara with customizations
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
tangara-fw/lib/luavgl/src/font.c

283 lines
6.0 KiB

#include "luavgl.h"
#include "private.h"
#define FONT_DEFAULT_SIZE 12
#define _ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
/**
* Follow css style, specify the name by name family, name size,
* name weight. Font weight can be numeric value or 'bold'. Alls strings
* are converted to lower-case before matching with local supported name.
*
* weight named weight
* 100 thin
* 200 extra light
* 300 light
* 400 normal (*default)
* 500 medium
* 600 semi bold
* 700 bold
* 800 extra bold
* 900 ultra bold
*
* Only normal weight is supported to builtin name.
*
* Font returned to lua is a userdata, it's used by object style, or style
* directly. If name is no longer ref'ed by any object or style, it's
* gc'ed.
*/
/**
* lvgl.Font("montserrat, unscii", 8, bold)
* lvgl.Font("montserrat", 8)
* lvgl.Font("montserrat")
*
* return nil if failed
*/
typedef enum {
FONT_WEIGHT_THIN = 100,
FONT_WEIGHT_EXTRA_LIGHT = 200,
FONT_WEIGHT_LIGHT = 300,
FONT_WEIGHT_NORMAL = 400,
FONT_WEIGHT_MEDIUM = 500,
FONT_WEIGHT_SEMI_BOLD = 600,
FONT_WEIGHT_BOLD = 700,
FONT_WEIGHT_EXTRA_BOLD = 800,
FONT_WEIGHT_ULTRA_BOLD = 900,
} font_weight_t;
static const struct {
char *name;
int value;
} g_named_weight[] = {
{"thin", 100},
{"extra light", 200},
{"light", 300},
{"normal", 400},
{"medium", 500},
{"semi bold", 600},
{"bold", 700},
{"extra bold", 800},
{"ultra bold", 900},
};
static const struct {
int size;
const lv_font_t *font;
} g_builtin_montserrat[] = {
#if LV_FONT_MONTSERRAT_8
{8, &lv_font_montserrat_8 },
#endif
#if LV_FONT_MONTSERRAT_10
{10, &lv_font_montserrat_10},
#endif
#if LV_FONT_MONTSERRAT_12
{12, &lv_font_montserrat_12},
#endif
#if LV_FONT_MONTSERRAT_14
{14, &lv_font_montserrat_14},
#endif
#if LV_FONT_MONTSERRAT_16
{16, &lv_font_montserrat_16},
#endif
#if LV_FONT_MONTSERRAT_18
{18, &lv_font_montserrat_18},
#endif
#if LV_FONT_MONTSERRAT_20
{20, &lv_font_montserrat_20},
#endif
#if LV_FONT_MONTSERRAT_22
{22, &lv_font_montserrat_22},
#endif
#if LV_FONT_MONTSERRAT_24
{24, &lv_font_montserrat_24},
#endif
#if LV_FONT_MONTSERRAT_26
{26, &lv_font_montserrat_26},
#endif
#if LV_FONT_MONTSERRAT_28
{28, &lv_font_montserrat_28},
#endif
#if LV_FONT_MONTSERRAT_30
{30, &lv_font_montserrat_30},
#endif
#if LV_FONT_MONTSERRAT_32
{32, &lv_font_montserrat_32},
#endif
#if LV_FONT_MONTSERRAT_34
{34, &lv_font_montserrat_34},
#endif
#if LV_FONT_MONTSERRAT_36
{36, &lv_font_montserrat_36},
#endif
#if LV_FONT_MONTSERRAT_38
{38, &lv_font_montserrat_38},
#endif
#if LV_FONT_MONTSERRAT_40
{40, &lv_font_montserrat_40},
#endif
#if LV_FONT_MONTSERRAT_42
{42, &lv_font_montserrat_42},
#endif
#if LV_FONT_MONTSERRAT_44
{44, &lv_font_montserrat_44},
#endif
#if LV_FONT_MONTSERRAT_46
{46, &lv_font_montserrat_46},
#endif
#if LV_FONT_MONTSERRAT_48
{48, &lv_font_montserrat_48},
#endif
};
static int luavgl_get_named_weight(const char *name)
{
if (name == NULL) {
return FONT_DEFAULT_SIZE;
}
for (int i = 0; i < _ARRAY_LEN(g_named_weight); i++) {
if (strcmp(name, g_named_weight[i].name) == 0) {
return g_named_weight[i].value;
}
}
return FONT_DEFAULT_SIZE;
}
static char *to_lower(char *str)
{
for (char *s = str; *s; ++s)
*s = *s >= 'A' && *s <= 'Z' ? *s | 0x60 : *s;
return str;
}
static const lv_font_t *_luavgl_font_create(lua_State *L, const char *name,
int size, int weight)
{
/* check builtin font firstly. */
if (strcmp(name, "montserrat") == 0) {
if (FONT_WEIGHT_NORMAL != weight)
return NULL;
for (int i = 0; i < _ARRAY_LEN(g_builtin_montserrat); i++) {
if (size == g_builtin_montserrat[i].size) {
return g_builtin_montserrat[i].font;
}
}
} else if (strcmp(name, "unscii") == 0) {
if (FONT_WEIGHT_NORMAL != weight)
return NULL;
#if LV_FONT_UNSCII_8
if (size == 8)
return &lv_font_unscii_8;
#endif
#if LV_FONT_UNSCII_16
if (size == 16)
return &lv_font_unscii_16;
#endif
}
#if LV_FONT_MONTSERRAT_12_SUBPX
else if (strcmp(name, "montserrat_subpx") == 0) {
if (size == 12)
return &lv_font_montserrat_12_subpx;
}
#endif
#if LV_FONT_DEJAVU_16_PERSIAN_HEBREW
else if (strcmp(name, "dejavu_persian_hebrew") == 0) {
if (size == 16)
return &lv_font_dejavu_16_persian_hebrew;
}
#endif
#if LV_FONT_SIMSUN_16_CJK
else if (strcmp(name, "dejavu_persian_hebrew") == 0) {
if (size == 16)
return &lv_font_simsun_16_cjk;
}
#endif
/* not built-in font, check extension */
luavgl_ctx_t *ctx = luavgl_context(L);
if (ctx->make_font) {
return ctx->make_font(name, size, weight);
}
return NULL;
}
/**
* Dynamic font family fallback is not supported.
* The fallback only happen when font creation fails and continue to try next
* one. Fallback logic in lvgl is supposed to be system wide.
*
* lvgl.Font("MiSansW medium, montserrat", 24, "normal")
*/
static int luavgl_font_create(lua_State *L)
{
int weight;
int size;
const char *name;
const lv_font_t *font = NULL;
if (!lua_isstring(L, 1)) {
return luaL_argerror(L, 1, "expect string");
}
/* size is optional, default to FONT_DEFAULT_SIZE */
size = lua_tointeger(L, 2);
if (size == 0) {
size = FONT_DEFAULT_SIZE;
}
if (!lua_isnoneornil(L, 3)) {
if (lua_isinteger(L, 3)) {
weight = lua_tointeger(L, 3);
} else {
char *luastr = (char *)lua_tostring(L, 3);
int len = strlen(luastr);
if (len > 128) {
/* not likely to happen */
return luaL_argerror(L, 3, "too long");
}
char s[len + 1];
strcpy(s, luastr);
weight = luavgl_get_named_weight(to_lower(s));
}
} else {
weight = FONT_WEIGHT_NORMAL;
}
name = lua_tostring(L, 1);
font = _luavgl_font_create(L, name, size, weight);
if (font) {
lua_pushlightuserdata(L, (void *)font);
return 1;
}
return luaL_error(L, "cannot create font.");
}