From 651be6acb10dbf0d3d9ea95eb47c7155e3c28b05 Mon Sep 17 00:00:00 2001 From: fvanroie Date: Tue, 3 May 2022 17:51:00 +0200 Subject: [PATCH] Backport lv_lib_freetype from LVGL v8.x #249 --- lib/lv_lib_freetype/lv_freetype.c | 790 ++++++++++++++++++++---------- lib/lv_lib_freetype/lv_freetype.h | 75 ++- src/hasp/hasp_font.cpp | 98 +++- src/hasp/hasp_font.h | 2 +- user_setups/esp32/_esp32.ini | 3 + user_setups/esp32s2/_esp32s2.ini | 3 + 6 files changed, 648 insertions(+), 323 deletions(-) diff --git a/lib/lv_lib_freetype/lv_freetype.c b/lib/lv_lib_freetype/lv_freetype.c index 5b75e065..216a102e 100644 --- a/lib/lv_lib_freetype/lv_freetype.c +++ b/lib/lv_lib_freetype/lv_freetype.c @@ -3,11 +3,19 @@ * */ -#if defined(ARDUINO_ARCH_ESP32) - /********************* * INCLUDES *********************/ +#include "lv_freetype.h" +#if HASP_USE_FREETYPE + +#include "ft2build.h" +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_CACHE_H +#include FT_SIZES_H +#include FT_IMAGE_H +#include FT_OUTLINE_H #include "lv_freetype.h" #include "freertos/FreeRTOS.h" @@ -20,6 +28,8 @@ #define ARDUINO_RUNNING_CORE 1 #endif +#define LV_USE_FT_STACK_SIZE 24 * 1024 // FreeType consumes a large amount of stack + /* * FreeType requires up to 32KB of stack to run, which overflows the stack of 8KB. * @@ -53,36 +63,60 @@ typedef bool FT_glyph_dsc_response; /********************** * TYPEDEFS **********************/ +typedef struct +{ + lv_ll_t face_ll; +} lv_faces_control_t; + +typedef struct name_refer_t +{ + const char* name; /* point to font name string */ + int32_t cnt; /* reference count */ +} name_refer_t; /********************** * STATIC PROTOTYPES **********************/ +#if LV_FREETYPE_CACHE_SIZE >= 0 +static void face_generic_finalizer_cache(void* object); +static FT_Error font_face_requester(FTC_FaceID face_id, FT_Library library_is, FT_Pointer req_data, FT_Face* aface); +static bool lv_ft_font_init_cache(lv_ft_info_t* info); +static void lv_ft_font_destroy_cache(lv_font_t* font); +#else static FT_Face face_find_in_list(lv_ft_info_t* info); static void face_add_to_list(FT_Face face); static void face_remove_from_list(FT_Face face); - static void face_generic_finalizer(void* object); -static bool get_glyph_dsc_cb(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out, uint32_t unicode_letter, - uint32_t unicode_letter_next); -static const uint8_t* get_glyph_bitmap_cb(const lv_font_t* font, uint32_t unicode_letter); - -#if LV_USE_FT_CACHE_MANAGER -static FT_Error font_face_requester(FTC_FaceID face_id, FT_Library library_is, FT_Pointer req_data, FT_Face* aface); +static bool lv_ft_font_init_nocache(lv_ft_info_t* info); +static void lv_ft_font_destroy_nocache(lv_font_t* font); #endif +static const char* name_refer_save(const char* name); +static void name_refer_del(const char* name); +static const char* name_refer_find(const char* name); + /********************** * STATIC VARIABLES **********************/ static FT_Library library; +static lv_ll_t names_ll; -#if LV_USE_FT_CACHE_MANAGER +#if LV_FREETYPE_CACHE_SIZE >= 0 static FTC_Manager cache_manager; static FTC_CMapCache cmap_cache; +static FT_Face current_face = NULL; + +#if LV_FREETYPE_SBIT_CACHE static FTC_SBitCache sbit_cache; static FTC_SBit sbit; +#else +static FTC_ImageCache image_cache; +static FT_Glyph image_glyph; #endif +#else static lv_faces_control_t face_control; +#endif /********************** * MACROS @@ -91,19 +125,20 @@ static lv_faces_control_t face_control; /********************** * GLOBAL FUNCTIONS **********************/ -bool lv_freetype_init(FT_UInt max_faces, FT_UInt max_sizes, FT_ULong max_bytes) -{ - face_control.cnt = 0; - face_control.num = max_faces; - _lv_ll_init(&face_control.face_ll, sizeof(FT_Face*)); +/*********************************************************************************************************************/ + +bool lv_freetype_init(uint16_t max_faces, uint16_t max_sizes, uint32_t max_bytes) +{ FT_Error error = FT_Init_FreeType(&library); if(error) { LV_LOG_ERROR("init freeType error(%d)", error); return false; } -#if LV_USE_FT_CACHE_MANAGER + _lv_ll_init(&names_ll, sizeof(name_refer_t)); + +#if LV_FREETYPE_CACHE_SIZE >= 0 error = FTC_Manager_New(library, max_faces, max_sizes, max_bytes, font_face_requester, NULL, &cache_manager); if(error) { FT_Done_FreeType(library); @@ -117,11 +152,19 @@ bool lv_freetype_init(FT_UInt max_faces, FT_UInt max_sizes, FT_ULong max_bytes) goto Fail; } +#if LV_FREETYPE_SBIT_CACHE error = FTC_SBitCache_New(cache_manager, &sbit_cache); if(error) { LV_LOG_ERROR("Failed to open sbit cache"); goto Fail; } +#else + error = FTC_ImageCache_New(cache_manager, &image_cache); + if(error) { + LV_LOG_ERROR("Failed to open image cache"); + goto Fail; + } +#endif // initialize the queues to send request and receive response FTRequestQueue = xQueueCreate(1, sizeof(FT_glyph_dsc_request)); @@ -138,15 +181,17 @@ Fail: FT_Done_FreeType(library); return false; #else + LV_UNUSED(max_faces); LV_UNUSED(max_sizes); LV_UNUSED(max_bytes); + _lv_ll_init(&face_control.face_ll, sizeof(FT_Face*)); return true; -#endif /* LV_USE_FT_CACHE_MANAGER */ +#endif /* LV_FREETYPE_CACHE_SIZE */ } void lv_freetype_destroy(void) { -#if LV_USE_FT_CACHE_MANAGER +#if LV_FREETYPE_CACHE_SIZE >= 0 FTC_Manager_Done(cache_manager); #endif FT_Done_FreeType(library); @@ -154,170 +199,82 @@ void lv_freetype_destroy(void) bool lv_ft_font_init(lv_ft_info_t* info) { - lv_font_fmt_ft_dsc_t* dsc = lv_mem_alloc(sizeof(lv_font_fmt_ft_dsc_t)); - if(dsc == NULL) return false; - - dsc->font = lv_mem_alloc(sizeof(lv_font_t)); - if(dsc->font == NULL) { - lv_mem_free(dsc); - return false; - } - - lv_face_info_t* face_info = NULL; - FT_Face face = face_find_in_list(info); - if(1 || face == NULL) { - if(face_control.cnt == face_control.num - 1) { - LV_LOG_WARN("face full"); - goto Fail; - } - face_info = lv_mem_alloc(sizeof(lv_face_info_t) + strlen(info->name) + 1); - if(face_info == NULL) { - goto Fail; - } - FT_Error error = FT_New_Face(library, info->name, 0, &face); - if(error) { - lv_mem_free(face_info); - LV_LOG_WARN("create face error(%d)", error); - goto Fail; - } - - face_info->name = ((char*)face_info) + sizeof(lv_face_info_t); - strcpy(face_info->name, info->name); - face_info->cnt = 1; - face->generic.data = face_info; - face->generic.finalizer = face_generic_finalizer; - face_add_to_list(face); - } else { -#if LV_USE_FT_CACHE_MANAGER == 0 - FT_Size size; - FT_Error error = FT_New_Size(face, &size); - if(error) { - goto Fail; - } - FT_Activate_Size(size); - FT_Reference_Face(face); +#if LV_FREETYPE_CACHE_SIZE >= 0 + return lv_ft_font_init_cache(info); #else - face_info = (lv_face_info_t*)face->generic.data; - face_info->cnt++; + return lv_ft_font_init_nocache(info); #endif - } - - FT_Error error = FT_Set_Char_Size(face, 0, info->weight * 64, 0, 0); - if(error) { - lv_mem_free(face_info); - LV_LOG_WARN("set char size error(%d)", error); - goto Fail; - } - - FT_Set_Pixel_Sizes(face, 0, info->weight); - - dsc->face = face; - dsc->size = face->size; - dsc->weight = info->weight; - dsc->style = info->style; - lv_font_t* font = dsc->font; - font->user_data = dsc; - font->get_glyph_dsc = get_glyph_dsc_cb; - font->get_glyph_bitmap = get_glyph_bitmap_cb; - font->line_height = ((dsc->face->size->metrics.ascender - dsc->face->size->metrics.descender ) >> 6); - font->base_line = -((dsc->face->size->metrics.descender ) >> 6); - font->subpx = LV_FONT_SUBPX_NONE; - font->underline_position = dsc->face->underline_position; - font->underline_thickness = dsc->face->underline_thickness; - font->dsc = NULL; - info->font = font; - return true; - -Fail: - lv_mem_free(dsc->font); - lv_mem_free(dsc); - return false; } void lv_ft_font_destroy(lv_font_t* font) { - if(font == NULL) { - return; - } - - lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->user_data); - if(dsc) { -#if LV_USE_FT_CACHE_MANAGER == 0 - FT_Done_Size(dsc->size); - FT_Done_Face(dsc->face); +#if LV_FREETYPE_CACHE_SIZE >= 0 + lv_ft_font_destroy_cache(font); #else - lv_face_info_t* face_info = (lv_face_info_t*)dsc->face->generic.data; - face_info->cnt--; - if(face_info->cnt == 0) { - FTC_Manager_RemoveFaceID(cache_manager, (FTC_FaceID)dsc->face); - } + lv_ft_font_destroy_nocache(font); #endif - lv_mem_free(dsc->font); - lv_mem_free(dsc); - } } /********************** * STATIC FUNCTIONS **********************/ -static void face_generic_finalizer(void* object) +#if LV_FREETYPE_CACHE_SIZE >= 0 + +static void face_generic_finalizer_cache(void* object) { FT_Face face = (FT_Face)object; - face_remove_from_list(face); - if(face->generic.data) { - lv_face_info_t* face_info = (lv_face_info_t*)face->generic.data; - lv_mem_free(face_info); - } - LV_LOG_INFO("face finalizer(%p)\n", face); + LV_LOG_WARN("face finalizer(%p)\n", face); } -static FT_Face face_find_in_list(lv_ft_info_t* info) -{ - lv_face_info_t* face_info; - FT_Face* pface = _lv_ll_get_head(&face_control.face_ll); - while(pface) { - face_info = (lv_face_info_t*)(*pface)->generic.data; - if(strcmp(face_info->name, info->name) == 0) { - return *pface; - } - pface = _lv_ll_get_next(&face_control.face_ll, pface); - } - - return NULL; -} - -static void face_add_to_list(FT_Face face) -{ - FT_Face* pface; - pface = (FT_Face*)_lv_ll_ins_tail(&face_control.face_ll); - *pface = face; - face_control.cnt++; -} - -static void face_remove_from_list(FT_Face face) -{ - FT_Face* pface = _lv_ll_get_head(&face_control.face_ll); - while(pface) { - if(*pface == face) { - _lv_ll_remove(&face_control.face_ll, pface); - lv_mem_free(pface); - face_control.cnt--; - break; - } - pface = _lv_ll_get_next(&face_control.face_ll, pface); - } -} - -#if LV_USE_FT_CACHE_MANAGER - static FT_Error font_face_requester(FTC_FaceID face_id, FT_Library library_is, FT_Pointer req_data, FT_Face* aface) { LV_UNUSED(library_is); LV_UNUSED(req_data); - *aface = face_id; + + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)face_id; + FT_Error error; + if(dsc->mem) { + error = FT_New_Memory_Face(library, dsc->mem, dsc->mem_size, 0, aface); + } else { + error = FT_New_Face(library, dsc->name, 0, aface); + } + if(error) { + LV_LOG_ERROR("FT_New_Face error:%d\n", error); + return error; + } + (*aface)->generic.finalizer = face_generic_finalizer_cache; return FT_Err_Ok; } +static bool get_bold_glyph(const lv_font_t* font, FT_Face face, FT_UInt glyph_index, lv_font_glyph_dsc_t* dsc_out) +{ + if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT)) { + return false; + } + + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->dsc); + if(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + if(dsc->style & FT_FONT_STYLE_BOLD) { + int strength = 1 << 6; + FT_Outline_Embolden(&face->glyph->outline, strength); + } + } + + if(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) { + return false; + } + + dsc_out->adv_w = (face->glyph->metrics.horiAdvance >> 6); + dsc_out->box_h = face->glyph->bitmap.rows; /*Height of the bitmap in [px]*/ + dsc_out->box_w = face->glyph->bitmap.width; /*Width of the bitmap in [px]*/ + dsc_out->ofs_x = face->glyph->bitmap_left; /*X offset of the bitmap in [pf]*/ + dsc_out->ofs_y = + face->glyph->bitmap_top - face->glyph->bitmap.rows; /*Y offset of the bitmap measured from the as line*/ + dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/ + + return true; +} + static bool get_glyph_dsc_cb_cache(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) { @@ -332,17 +289,54 @@ static bool get_glyph_dsc_cb_cache(const lv_font_t* font, lv_font_glyph_dsc_t* d return true; } - lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->user_data); - FT_Face face = dsc->face; + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->dsc); - static FTC_ImageTypeRec desc_sbit_type; - desc_sbit_type.face_id = (FTC_FaceID)face; - desc_sbit_type.flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL; - desc_sbit_type.height = dsc->weight; - desc_sbit_type.width = dsc->weight; - FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap); - FT_UInt glyph_index = FTC_CMapCache_Lookup(cmap_cache, (FTC_FaceID)face, charmap_index, unicode_letter); - FT_Error error = FTC_SBitCache_Lookup(sbit_cache, &desc_sbit_type, glyph_index, &sbit, NULL); + FTC_FaceID face_id = (FTC_FaceID)dsc; + FT_Size face_size; + struct FTC_ScalerRec_ scaler; + scaler.face_id = face_id; + scaler.width = dsc->height; + scaler.height = dsc->height; + scaler.pixel = 1; + if(FTC_Manager_LookupSize(cache_manager, &scaler, &face_size) != 0) { + return false; + } + + FT_Face face = face_size->face; + FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap); + FT_UInt glyph_index = FTC_CMapCache_Lookup(cmap_cache, face_id, charmap_index, unicode_letter); + // dsc_out->is_placeholder = glyph_index == 0; + + if(dsc->style & FT_FONT_STYLE_ITALIC) { + FT_Matrix italic_matrix; + italic_matrix.xx = 1 << 16; + italic_matrix.xy = 0x5800; + italic_matrix.yx = 0; + italic_matrix.yy = 1 << 16; + FT_Set_Transform(face, &italic_matrix, NULL); + } + + if(dsc->style & FT_FONT_STYLE_BOLD) { + current_face = face; + if(!get_bold_glyph(font, face, glyph_index, dsc_out)) { + current_face = NULL; + return false; + } + goto end; + } + + FTC_ImageTypeRec desc_type; + desc_type.face_id = face_id; + desc_type.flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL; + desc_type.height = dsc->height; + desc_type.width = dsc->height; + +#if LV_FREETYPE_SBIT_CACHE + FT_Error error = FTC_SBitCache_Lookup(sbit_cache, &desc_type, glyph_index, &sbit, NULL); + if(error) { + LV_LOG_ERROR("SBitCache_Lookup error"); + return false; + } dsc_out->adv_w = sbit->xadvance; dsc_out->box_h = sbit->height; /*Height of the bitmap in [px]*/ @@ -350,91 +344,57 @@ static bool get_glyph_dsc_cb_cache(const lv_font_t* font, lv_font_glyph_dsc_t* d dsc_out->ofs_x = sbit->left; /*X offset of the bitmap in [pf]*/ dsc_out->ofs_y = sbit->top - sbit->height; /*Y offset of the bitmap measured from the as line*/ dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/ +#else + FT_Error error = FTC_ImageCache_Lookup(image_cache, &desc_type, glyph_index, &image_glyph, NULL); + if(error) { + LV_LOG_ERROR("ImageCache_Lookup error"); + return false; + } + if(image_glyph->format != FT_GLYPH_FORMAT_BITMAP) { + LV_LOG_ERROR("Glyph_To_Bitmap error"); + return false; + } + + FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)image_glyph; + dsc_out->adv_w = (glyph_bitmap->root.advance.x >> 16); + dsc_out->box_h = glyph_bitmap->bitmap.rows; /*Height of the bitmap in [px]*/ + dsc_out->box_w = glyph_bitmap->bitmap.width; /*Width of the bitmap in [px]*/ + dsc_out->ofs_x = glyph_bitmap->left; /*X offset of the bitmap in [pf]*/ + dsc_out->ofs_y = glyph_bitmap->top - glyph_bitmap->bitmap.rows; /*Y offset of the bitmap measured from the as line*/ + dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/ +#endif + +end: + if((dsc->style & FT_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) { + dsc_out->adv_w = dsc_out->box_w + dsc_out->ofs_x; + } return true; } static const uint8_t* get_glyph_bitmap_cb_cache(const lv_font_t* font, uint32_t unicode_letter) { - LV_UNUSED(font); LV_UNUSED(unicode_letter); + + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->dsc); + if(dsc->style & FT_FONT_STYLE_BOLD) { + if(current_face && current_face->glyph->format == FT_GLYPH_FORMAT_BITMAP) { + return (const uint8_t*)(current_face->glyph->bitmap.buffer); + } + return NULL; + } + +#if LV_FREETYPE_SBIT_CACHE return (const uint8_t*)sbit->buffer; +#else + FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)image_glyph; + return (const uint8_t*)glyph_bitmap->bitmap.buffer; +#endif } -#else /* LV_USE_FT_CACHE_MANAGER */ -// extern void berry_log_C(const char * berry_buf, ...); - -static bool get_glyph_dsc_cb_nocache(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out, uint32_t unicode_letter, - uint32_t unicode_letter_next) -{ - // berry_log_C(">> get_glyph_dsc_cb_nocache %i %i", unicode_letter, unicode_letter_next); - LV_UNUSED(unicode_letter_next); - if(unicode_letter < 0x20) { - dsc_out->adv_w = 0; - dsc_out->box_h = 0; - dsc_out->box_w = 0; - dsc_out->ofs_x = 0; - dsc_out->ofs_y = 0; - dsc_out->bpp = 0; - return true; - } - - FT_Error error; - FT_Face face; - lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->user_data); - face = dsc->face; - - FT_UInt glyph_index = FT_Get_Char_Index(face, unicode_letter); - - if(face->size != dsc->size) { - // berry_log_C(">> FT_Activate_Size %i", dsc->size); - FT_Activate_Size(dsc->size); - } - - error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); - // berry_log_C(">> after FT_Load_Glyph error = %i", error); - if(error) { - return false; - } - - error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); - // berry_log_C(">> after FT_Render_Glyph error = %i", error); - if(error) { - return false; - } - - dsc_out->adv_w = (face->glyph->metrics.horiAdvance >> 6); - dsc_out->box_h = face->glyph->bitmap.rows; /*Height of the bitmap in [px]*/ - dsc_out->box_w = face->glyph->bitmap.width; /*Width of the bitmap in [px]*/ - dsc_out->ofs_x = face->glyph->bitmap_left; /*X offset of the bitmap in [pf]*/ - dsc_out->ofs_y = - face->glyph->bitmap_top - face->glyph->bitmap.rows; /*Y offset of the bitmap measured from the as line*/ - dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/ - - // berry_log_C("+++ adv_w %i, h %i, w %i, x %i, y %i", dsc_out->adv_w, dsc_out->box_h, dsc_out->box_w, - // dsc_out->ofs_x, dsc_out->ofs_y); - - return true; -} - -static const uint8_t* get_glyph_bitmap_cb_nocache(const lv_font_t* font, uint32_t unicode_letter) -{ - LV_UNUSED(unicode_letter); - lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->user_data); - FT_Face face = dsc->face; - return (const uint8_t*)(face->glyph->bitmap.buffer); -} - -#endif /* LV_USE_FT_CACHE_MANAGER */ - static bool get_glyph_dsc_cb(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) { - // #if LV_USE_FT_CACHE_MANAGER - // return get_glyph_dsc_cb_cache(font, dsc_out, unicode_letter, unicode_letter_next); - // #else - // return get_glyph_dsc_cb_nocache(font, dsc_out, unicode_letter, unicode_letter_next); - // #endif static FT_glyph_dsc_request request; static FT_glyph_dsc_response response; @@ -450,15 +410,6 @@ static bool get_glyph_dsc_cb(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out } } -static const uint8_t* get_glyph_bitmap_cb(const lv_font_t* font, uint32_t unicode_letter) -{ -#if LV_USE_FT_CACHE_MANAGER - return get_glyph_bitmap_cb_cache(font, unicode_letter); -#else - return get_glyph_bitmap_cb_nocache(font, unicode_letter); -#endif -} - void FT_loop_task(void* pvParameters) { (void)pvParameters; @@ -480,4 +431,343 @@ void FT_loop_task(void* pvParameters) } } -#endif \ No newline at end of file +static bool lv_ft_font_init_cache(lv_ft_info_t* info) +{ + size_t need_size = sizeof(lv_font_fmt_ft_dsc_t) + sizeof(lv_font_t); + lv_font_fmt_ft_dsc_t* dsc = lv_mem_alloc(need_size); + if(dsc == NULL) return false; + _lv_memset_00(dsc, need_size); + + dsc->font = (lv_font_t*)(((char*)dsc) + sizeof(lv_font_fmt_ft_dsc_t)); + dsc->mem = info->mem; + dsc->mem_size = info->mem_size; + dsc->name = name_refer_save(info->name); + dsc->height = info->weight; + dsc->style = info->style; + + /* use to get font info */ + FT_Size face_size; + struct FTC_ScalerRec_ scaler; + scaler.face_id = (FTC_FaceID)dsc; + scaler.width = info->weight; + scaler.height = info->weight; + scaler.pixel = 1; + FT_Error error = FTC_Manager_LookupSize(cache_manager, &scaler, &face_size); + if(error) { + LV_LOG_ERROR("Failed to LookupSize"); + goto Fail; + } + + lv_font_t* font = dsc->font; + font->dsc = dsc; + // font->get_glyph_dsc = get_glyph_dsc_cb_cache; + font->get_glyph_dsc = get_glyph_dsc_cb; + font->get_glyph_bitmap = get_glyph_bitmap_cb_cache; + font->subpx = LV_FONT_SUBPX_NONE; + font->line_height = (face_size->face->size->metrics.height >> 6); + font->base_line = -(face_size->face->size->metrics.descender >> 6); + + FT_Fixed scale = face_size->face->size->metrics.y_scale; + int8_t thickness = FT_MulFix(scale, face_size->face->underline_thickness) >> 6; + font->underline_position = FT_MulFix(scale, face_size->face->underline_position) >> 6; + font->underline_thickness = thickness < 1 ? 1 : thickness; + + /* return to user */ + info->font = font; + + return true; + +Fail: + lv_mem_free(dsc); + return false; +} + +void lv_ft_font_destroy_cache(lv_font_t* font) +{ + if(font == NULL) { + return; + } + + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->dsc); + if(dsc) { + LV_LOG_WARN("RemoveFaceID : %s %u", dsc->name, dsc->height); + + FTC_Manager_RemoveFaceID(cache_manager, (FTC_FaceID)dsc); + name_refer_del(dsc->name); + lv_mem_free(dsc); + font->dsc = NULL; + } +} +#else /* LV_FREETYPE_CACHE_SIZE */ + +static FT_Face face_find_in_list(lv_ft_info_t* info) +{ + lv_font_fmt_ft_dsc_t* dsc; + FT_Face* pface = _lv_ll_get_head(&face_control.face_ll); + while(pface) { + dsc = (lv_font_fmt_ft_dsc_t*)(*pface)->generic.data; + if(strcmp(dsc->name, info->name) == 0) { + return *pface; + } + pface = _lv_ll_get_next(&face_control.face_ll, pface); + } + + return NULL; +} + +static void face_add_to_list(FT_Face face) +{ + FT_Face* pface; + pface = (FT_Face*)_lv_ll_ins_tail(&face_control.face_ll); + *pface = face; +} + +static void face_remove_from_list(FT_Face face) +{ + FT_Face* pface = _lv_ll_get_head(&face_control.face_ll); + while(pface) { + if(*pface == face) { + _lv_ll_remove(&face_control.face_ll, pface); + lv_mem_free(pface); + break; + } + pface = _lv_ll_get_next(&face_control.face_ll, pface); + } +} + +static void face_generic_finalizer(void* object) +{ + FT_Face face = (FT_Face)object; + face_remove_from_list(face); + LV_LOG_INFO("face finalizer(%p)\n", face); +} + +static bool get_glyph_dsc_cb_nocache(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out, uint32_t unicode_letter, + uint32_t unicode_letter_next) +{ + LV_UNUSED(unicode_letter_next); + if(unicode_letter < 0x20) { + dsc_out->adv_w = 0; + dsc_out->box_h = 0; + dsc_out->box_w = 0; + dsc_out->ofs_x = 0; + dsc_out->ofs_y = 0; + dsc_out->bpp = 0; + return true; + } + + FT_Error error; + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->dsc); + FT_Face face = dsc->size->face; + + FT_UInt glyph_index = FT_Get_Char_Index(face, unicode_letter); + + if(face->size != dsc->size) { + FT_Activate_Size(dsc->size); + } + // dsc_out->is_placeholder = glyph_index == 0; + + error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + if(error) { + return false; + } + + if(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + if(dsc->style & FT_FONT_STYLE_BOLD) { + int strength = 1 << 6; + FT_Outline_Embolden(&face->glyph->outline, strength); + } + + if(dsc->style & FT_FONT_STYLE_ITALIC) { + FT_Matrix italic_matrix; + italic_matrix.xx = 1 << 16; + italic_matrix.xy = 0x5800; + italic_matrix.yx = 0; + italic_matrix.yy = 1 << 16; + FT_Outline_Transform(&face->glyph->outline, &italic_matrix); + } + } + + error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); + if(error) { + return false; + } + + dsc_out->adv_w = (face->glyph->metrics.horiAdvance >> 6); + dsc_out->box_h = face->glyph->bitmap.rows; /*Height of the bitmap in [px]*/ + dsc_out->box_w = face->glyph->bitmap.width; /*Width of the bitmap in [px]*/ + dsc_out->ofs_x = face->glyph->bitmap_left; /*X offset of the bitmap in [pf]*/ + dsc_out->ofs_y = + face->glyph->bitmap_top - face->glyph->bitmap.rows; /*Y offset of the bitmap measured from the as line*/ + dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/ + + if((dsc->style & FT_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) { + dsc_out->adv_w = dsc_out->box_w + dsc_out->ofs_x; + } + + return true; +} + +static const uint8_t* get_glyph_bitmap_cb_nocache(const lv_font_t* font, uint32_t unicode_letter) +{ + LV_UNUSED(unicode_letter); + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->dsc); + FT_Face face = dsc->size->face; + return (const uint8_t*)(face->glyph->bitmap.buffer); +} + +static bool lv_ft_font_init_nocache(lv_ft_info_t* info) +{ + size_t need_size = sizeof(lv_font_fmt_ft_dsc_t) + sizeof(lv_font_t); + lv_font_fmt_ft_dsc_t* dsc = lv_mem_alloc(need_size); + if(dsc == NULL) return false; + _lv_memset_00(dsc, need_size); + + dsc->font = (lv_font_t*)(((char*)dsc) + sizeof(lv_font_fmt_ft_dsc_t)); + dsc->mem = info->mem; + dsc->mem_size = info->mem_size; + dsc->name = name_refer_save(info->name); + dsc->height = info->weight; + dsc->style = info->style; + + FT_Face face = face_find_in_list(info); + if(face == NULL) { + FT_Error error; + if(dsc->mem) { + error = FT_New_Memory_Face(library, dsc->mem, (FT_Long)dsc->mem_size, 0, &face); + } else { + error = FT_New_Face(library, dsc->name, 0, &face); + } + if(error) { + LV_LOG_WARN("create face error(%d)", error); + goto Fail; + } + + /* link face and face info */ + face->generic.data = dsc; + face->generic.finalizer = face_generic_finalizer; + face_add_to_list(face); + } else { + FT_Size size; + FT_Error error = FT_New_Size(face, &size); + if(error) { + goto Fail; + } + FT_Activate_Size(size); + FT_Reference_Face(face); + } + + FT_Set_Pixel_Sizes(face, 0, info->weight); + dsc->size = face->size; + + lv_font_t* font = dsc->font; + font->dsc = dsc; + // font->get_glyph_dsc = get_glyph_dsc_cb_nocache; + font->get_glyph_dsc = get_glyph_dsc_cb; + font->get_glyph_bitmap = get_glyph_bitmap_cb_nocache; + font->line_height = (face->size->metrics.height >> 6); + font->base_line = -(face->size->metrics.descender >> 6); + font->subpx = LV_FONT_SUBPX_NONE; + + FT_Fixed scale = face->size->metrics.y_scale; + int8_t thickness = FT_MulFix(scale, face->underline_thickness) >> 6; + font->underline_position = FT_MulFix(scale, face->underline_position) >> 6; + font->underline_thickness = thickness < 1 ? 1 : thickness; + + info->font = font; + return true; + +Fail: + lv_mem_free(dsc); + return false; +} + +static void lv_ft_font_destroy_nocache(lv_font_t* font) +{ + if(font == NULL) { + return; + } + + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)(font->dsc); + if(dsc) { + FT_Face face = dsc->size->face; + FT_Done_Size(dsc->size); + FT_Done_Face(face); + name_refer_del(dsc->name); + lv_mem_free(dsc); + } +} + +#endif /* LV_FREETYPE_CACHE_SIZE */ + +/** + * find name string in names list.name string cnt += 1 if find. + * @param name name string + * @return the string pointer of name. + */ +static const char* name_refer_find(const char* name) +{ + name_refer_t* refer = _lv_ll_get_head(&names_ll); + while(refer) { + if(strcmp(refer->name, name) == 0) { + refer->cnt += 1; + return refer->name; + } + refer = _lv_ll_get_next(&names_ll, refer); + } + return NULL; +} + +/** + * del name string from list. + */ +static void name_refer_del(const char* name) +{ + name_refer_t* refer = _lv_ll_get_head(&names_ll); + while(refer) { + if(strcmp(refer->name, name) == 0) { + refer->cnt -= 1; + if(refer->cnt <= 0) { + LV_LOG_WARN("Release String : %s", refer->name); + + _lv_ll_remove(&names_ll, refer); + lv_mem_free((void*)refer->name); + lv_mem_free(refer); + } + return; + } + refer = _lv_ll_get_next(&names_ll, refer); + } + + LV_LOG_WARN("name_in_names_del error(not find:%p).", name); +} + +/** + * save name string to list. + * @param name name string + * @return Saved string pointer + */ +static const char* name_refer_save(const char* name) +{ + const char* pos = name_refer_find(name); + if(pos) { + return pos; + } + + name_refer_t* refer = _lv_ll_ins_tail(&names_ll); + if(refer) { + uint32_t len = strlen(name) + 1; + refer->name = lv_mem_alloc(len); + if(refer->name) { + _lv_memcpy((void*)refer->name, name, len); + refer->cnt = 1; + return refer->name; + } + _lv_ll_remove(&names_ll, refer); + lv_mem_free(refer); + } + LV_LOG_WARN("save_name_to_names error(not memory)."); + return ""; +} + +#endif /*LV_USE_FREETYPE*/ diff --git a/lib/lv_lib_freetype/lv_freetype.h b/lib/lv_lib_freetype/lv_freetype.h index 1b419b99..cd5ce59e 100644 --- a/lib/lv_lib_freetype/lv_freetype.h +++ b/lib/lv_lib_freetype/lv_freetype.h @@ -2,8 +2,8 @@ * @file lv_freetype.h * */ -#ifndef _LV_FONT_TTF_H -#define _LV_FONT_TTF_H +#ifndef LV_FREETYPE_H +#define LV_FREETYPE_H #ifdef __cplusplus extern "C" { @@ -12,59 +12,40 @@ extern "C" { /********************* * INCLUDES *********************/ -// #include "lvgl/lvgl.h" // TODO #include "lvgl.h" -#include "ft2build.h" -#include FT_FREETYPE_H -#include FT_GLYPH_H -#include FT_CACHE_H -#include FT_SIZES_H +#if LV_USE_FREETYPE /********************* * DEFINES *********************/ -#ifndef LV_USE_FT_CACHE_MANAGER -#define LV_USE_FT_CACHE_MANAGER 0 -#endif - -#define LV_USE_FT_STACK_SIZE 24*1024 // FreeType consumes a large amount of stack /********************** * TYPEDEFS **********************/ -typedef struct { - uint16_t cnt; - char* name; -} lv_face_info_t; +typedef enum { FT_FONT_STYLE_NORMAL = 0, FT_FONT_STYLE_ITALIC = 1 << 0, FT_FONT_STYLE_BOLD = 1 << 1 } LV_FT_FONT_STYLE; -typedef struct { - uint16_t num; - uint16_t cnt; - lv_ll_t face_ll; -} lv_faces_control_t; - -typedef enum { - FT_FONT_STYLE_NORMAL = 0, - FT_FONT_STYLE_ITALIC = 1 << 0, - FT_FONT_STYLE_BOLD = 1 << 1 -} LV_FT_FONT_STYLE; - -typedef struct { - const char* name; /* The name of the font file */ - lv_font_t* font; /* point to lvgl font */ - uint16_t weight; /* font size */ - uint16_t style; /* font style */ +typedef struct +{ + const char* name; /* The name of the font file */ + const void* mem; /* The pointer of the font file */ + size_t mem_size; /* The size of the memory */ + lv_font_t* font; /* point to lvgl font */ + uint16_t weight; /* font size */ + uint16_t style; /* font style */ } lv_ft_info_t; -typedef struct { - FT_Face face; - FT_Size size; - lv_font_t* font; - uint16_t style; - uint16_t weight; -} lv_font_fmt_freetype_dsc_t; - -typedef lv_font_fmt_freetype_dsc_t lv_font_fmt_ft_dsc_t; +typedef struct +{ + const void* mem; + const char* name; + size_t mem_size; +#if LV_FREETYPE_CACHE_SIZE < 0 + FT_Size size; +#endif + lv_font_t* font; + uint16_t style; + uint16_t height; +} lv_font_fmt_ft_dsc_t; /********************** * GLOBAL PROTOTYPES @@ -78,7 +59,7 @@ typedef lv_font_fmt_freetype_dsc_t lv_font_fmt_ft_dsc_t; * Note that this value does not account for managed FT_Face and FT_Size objects. * @return true on success, otherwise false. */ -bool lv_freetype_init(FT_UInt max_faces, FT_UInt max_sizes, FT_ULong max_bytes); +bool lv_freetype_init(uint16_t max_faces, uint16_t max_sizes, uint32_t max_bytes); /** * Destroy freetype library @@ -91,7 +72,7 @@ void lv_freetype_destroy(void); * when success, lv_ft_info_t->font point to the font you created. * @return true on success, otherwise false. */ -bool lv_ft_font_init(lv_ft_info_t *info); +bool lv_ft_font_init(lv_ft_info_t* info); /** * Destroy a font that has been created. @@ -103,8 +84,10 @@ void lv_ft_font_destroy(lv_font_t* font); * MACROS **********************/ +#endif /*LV_USE_FREETYPE*/ + #ifdef __cplusplus } /* extern "C" */ #endif -#endif +#endif /* LV_FREETYPE_H */ diff --git a/src/hasp/hasp_font.cpp b/src/hasp/hasp_font.cpp index 9f2ac79d..2476f1fa 100644 --- a/src/hasp/hasp_font.cpp +++ b/src/hasp/hasp_font.cpp @@ -2,7 +2,14 @@ #include "hasplib.h" #if HASP_USE_FREETYPE > 0 + +#ifndef LV_USE_FREETYPE +#define LV_USE_FREETYPE 1 +#endif + #include "lv_freetype.h" +#include "ft2build.h" // for FT_FREETYPE_H macro +#include FT_FREETYPE_H // for FREETYPE_VERSION macros #else typedef struct { @@ -22,8 +29,19 @@ typedef struct { char* payload; /* The payload with name and size */ lv_font_t* font; /* point to lvgl font */ + uint8_t type; } hasp_font_info_t; +bool font_dummy_glyph_dsc(const struct _lv_font_struct*, lv_font_glyph_dsc_t*, uint32_t letter, uint32_t letter_next) +{ + return false; +} + +const uint8_t* font_dummy_glyph_bitmap(const struct _lv_font_struct*, uint32_t) +{ + return NULL; +} + void font_setup() { _lv_ll_init(&hasp_fonts_ll, sizeof(hasp_font_info_t)); @@ -57,33 +75,56 @@ size_t font_split_payload(const char* payload) return 0; } -void font_clear_list() +static void font_release(void* node) +{ + hasp_font_info_t* font_p = (hasp_font_info_t*)node; + if(font_p->font) { + if(font_p->type = 1) { // It's a FreeType font +#if(HASP_USE_FREETYPE > 0) + lv_ft_font_destroy(font_p->font); +#endif + } else if(font_p->type = 0) { // It's a binary font + hasp_font_free(font_p->font); + } + } + + /* Free the allocated font_name last */ + if(font_p->payload) { + LOG_DEBUG(TAG_FONT, F("Released font %s"), font_p->payload); + hasp_free(font_p->payload); + } +} + +void font_clear_list(const char* payload) { if(_lv_ll_is_empty(&hasp_fonts_ll)) return; - void* node = _lv_ll_get_head(&hasp_fonts_ll); - while(node) { - - hasp_font_info_t* font_p = (hasp_font_info_t*)node; - if(font_p->font) { - if(font_p->font->user_data) { // It's a FreeType font -#if(HASP_USE_FREETYPE > 0) - lv_ft_font_destroy(font_p->font); -#endif - } else { // It's a binary font - hasp_font_free(font_p->font); - } - } - - /* Free the allocated font_name last */ - if(font_p->payload) { - LOG_DEBUG(TAG_FONT, F("Released font %s"), font_p->payload); - hasp_free(font_p->payload); - } - + while(void* node = _lv_ll_get_head(&hasp_fonts_ll)) { + font_release(node); _lv_ll_remove(&hasp_fonts_ll, node); lv_mem_free(node); - node = _lv_ll_get_head(&hasp_fonts_ll); + } +} + +void font_clear_list2(const char* payload) +{ + hasp_font_info_t* font_p = (hasp_font_info_t*)_lv_ll_get_head(&hasp_fonts_ll); + while(font_p) { + if(font_p->type == 1) { + lv_font_fmt_ft_dsc_t* dsc = (lv_font_fmt_ft_dsc_t*)font_p->font->dsc; + if(strcmp(dsc->name, payload) == 0) { // name and size + lv_ft_font_destroy(font_p->font); + *font_p->font = HASP_FONT_1; + font_p->type = 255; + } + } + // if(strcmp(font_p->payload, payload) == 0) { // name and size + // LOG_DEBUG(TAG_FONT, F("Payload %s found => line height = %d - base_line = %d"), payload, + // font_p->font->line_height, font_p->font->base_line); + // return font_p->font; + // } + + font_p = (hasp_font_info_t*)_lv_ll_get_next(&hasp_fonts_ll, font_p); } } @@ -108,8 +149,9 @@ static lv_font_t* font_add_to_list(const char* payload) // Try .bin file snprintf_P(filename, sizeof(filename), PSTR("L:\\%s.bin"), payload); - lv_font_t* font = hasp_font_load(filename); - char* name_p = NULL; + lv_font_t* font = hasp_font_load(filename); + char* name_p = NULL; + uint8_t font_type = 0; #if defined(ARDUINO_ARCH_ESP32) && (HASP_USE_FREETYPE > 0) char* ext[] = {"ttf", "otf"}; @@ -140,9 +182,12 @@ static lv_font_t* font_add_to_list(const char* payload) lv_ft_info_t info; info.name = filename; info.weight = size; + info.mem = NULL; info.style = FT_FONT_STYLE_NORMAL; + LOG_VERBOSE(TAG_FONT, F("Loading font %s size %d"), filename, size); if(lv_ft_font_init(&info)) { - font = info.font; + font = info.font; + font_type = 1; } } } @@ -150,7 +195,7 @@ static lv_font_t* font_add_to_list(const char* payload) #endif if(!font) return NULL; - LOG_VERBOSE(TAG_FONT, F("Loaded font %s size %d"), filename, font->line_height); + LOG_VERBOSE(TAG_FONT, F("Loaded font %s line_height %d"), filename, font->line_height); /* alloc payload str */ size_t len = strlen(payload); @@ -164,6 +209,7 @@ static lv_font_t* font_add_to_list(const char* payload) new_font_item->payload = name_p; new_font_item->font = font; + new_font_item->type = font_type; return font; } diff --git a/src/hasp/hasp_font.h b/src/hasp/hasp_font.h index 7689f2aa..f2e7eee3 100644 --- a/src/hasp/hasp_font.h +++ b/src/hasp/hasp_font.h @@ -6,6 +6,6 @@ void font_setup(); lv_font_t* get_font(const char* payload); -void font_clear_list(); +void font_clear_list(const char* payload); #endif \ No newline at end of file diff --git a/user_setups/esp32/_esp32.ini b/user_setups/esp32/_esp32.ini index 949fbb34..cd82d662 100644 --- a/user_setups/esp32/_esp32.ini +++ b/user_setups/esp32/_esp32.ini @@ -41,6 +41,9 @@ build_flags = ;-D CONFIG_LITTLEFS_FOR_IDF_3_2 ; obsolete in IDF 3.3 ; -- FreeType build options ------------------------ -D HASP_USE_FREETYPE=1 + -D LV_USE_FREETYPE=1 + -D LV_FREETYPE_SBIT_CACHE=1 ; use small bitmap cache + -D LV_FREETYPE_CACHE_SIZE=1 ; cache freetype font sizes -D LV_USE_FT_CACHE_MANAGER=1 ; crashes without cache -D LVGL_FREETYPE_MAX_FACES=16 ; max number of FreeType faces in cache -D LVGL_FREETYPE_MAX_SIZES=16 ; max number of sizes in cache diff --git a/user_setups/esp32s2/_esp32s2.ini b/user_setups/esp32s2/_esp32s2.ini index d4967862..0c1790d7 100644 --- a/user_setups/esp32s2/_esp32s2.ini +++ b/user_setups/esp32s2/_esp32s2.ini @@ -48,6 +48,9 @@ build_flags = ;-D CONFIG_LITTLEFS_FOR_IDF_3_2 ; obsolete in IDF 3.3 ; -- FreeType build options ------------------------ -D HASP_USE_FREETYPE=1 + -D LV_USE_FREETYPE=1 + -D LV_FREETYPE_SBIT_CACHE=1 ; use small bitmap cache + -D LV_FREETYPE_CACHE_SIZE=1 ; cache freetype font sizes -D LV_USE_FT_CACHE_MANAGER=1 ; crashes without cache -D LVGL_FREETYPE_MAX_FACES=8 ; max number of FreeType faces in cache -D LVGL_FREETYPE_MAX_SIZES=8 ; max number of sizes in cache