Merge pull request #14423 from s-hadinger/lv_freetype_v2

LVGL moved Freetype embedded in LVGL8
This commit is contained in:
s-hadinger 2022-01-13 19:47:50 +01:00 committed by GitHub
commit d0880def62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 515 additions and 602 deletions

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 LittlevGL
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,44 +0,0 @@
# FreeType integration with LVGL
Interface to FreeType to generate font bitmaps run time
## Install FreeType
- Download Freetype from [here](https://sourceforge.net/projects/freetype/files/)
- `make`
- `sudo make install`
## Add FreeType to your project
- Add include path: `/usr/include/freetype2` (for GCC: `-I/usr/include/freetype2 -L/usr/local/lib`)
- Add library: `freetype` (for GCC: `-L/usr/local/lib -lfreetype`)
## Usage in LVGL
To enable cache, set`LV_USE_FT_CACHE_MANAGER 1`in lv_freetype.h.
```c
/* init freetype library */
lv_freetype_init(64, 1, 0);
/*Create a font*/
lv_ft_info_t info;
info.name = "./lv_lib_freetype/arial.ttf"";
info.size = 16;
info.style = FT_FONT_STYLE_NORMAL;
lv_ft_font_init(&info);
/*Create style with the new font*/
static lv_style_t style;
lv_style_init(&style);
lv_style_set_text_font(&style, LV_STATE_DEFAULT, info.font);
/*Create a label with the new style*/
lv_obj_t * label = lv_label_create(lv_scr_act(), NULL);
lv_obj_add_style(label, LV_LABEL_PART_MAIN, &style);
lv_label_set_text(label, "Hello world");
/* free font */
//lv_ft_font_destroy(info.font);
```
## Learn more
- FreeType [tutorial](https://www.freetype.org/freetype2/docs/tutorial/step1.html)
- LVGL's [font interface](https://docs.lvgl.io/v7/en/html/overview/font.html#add-a-new-font-engine)

View File

@ -1,15 +0,0 @@
{
"name":"lv_lib_freetype",
"description":"Interface to FreeType to generate font bitmaps run time",
"keywords":"lvgl, freetype",
"license": "MIT License",
"repository": {
"type": "git",
"url": "https://github.com/lvgl/lv_lib_freetype"
},
"frameworks": "arduino",
"platforms": "espressif32",
"build": {
"flags": [ "-DLV_LVGL_H_INCLUDE_SIMPLE", "-I$PROJECT_DIR/include", "-includetasmota_options.h" ]
}
}

View File

@ -1,469 +0,0 @@
/**
* @file lv_freetype.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_freetype.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
/*
* FreeType requires up to 32KB of stack to run, which overflows the stack of 8KB.
*
* We delegate to a FreeRTOS sub-task with a bigger stack.
*
* Parameters are passed via a RequestQueue, and response back via ResponseQueue
*
* The function that uses this scheme is `get_glyph_dsc_cb()``
*
*/
QueueHandle_t FTRequestQueue;
QueueHandle_t FTResponseQueue;
TaskHandle_t FTTaskHandle;
void FT_loop_task(void *pvParameters);
typedef struct FT_glyph_dsc_request {
const lv_font_t * font;
lv_font_glyph_dsc_t * dsc_out;
uint32_t unicode_letter;
uint32_t unicode_letter_next;
} FT_glyph_dsc_request;
typedef bool FT_glyph_dsc_response;
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
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);
#endif
/**********************
* STATIC VARIABLES
**********************/
static FT_Library library;
#if LV_USE_FT_CACHE_MANAGER
static FTC_Manager cache_manager;
static FTC_CMapCache cmap_cache;
static FTC_SBitCache sbit_cache;
static FTC_SBit sbit;
#endif
static lv_faces_control_t face_control;
/**********************
* MACROS
**********************/
/**********************
* 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 *));
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
error = FTC_Manager_New(library, max_faces, max_sizes,
max_bytes, font_face_requester, NULL, &cache_manager);
if (error) {
FT_Done_FreeType(library);
LV_LOG_ERROR("Failed to open cache manager");
return false;
}
error = FTC_CMapCache_New(cache_manager, &cmap_cache);
if(error) {
LV_LOG_ERROR("Failed to open Cmap Cache");
goto Fail;
}
error = FTC_SBitCache_New(cache_manager, &sbit_cache);
if(error){
LV_LOG_ERROR("Failed to open sbit cache");
goto Fail;
}
// initialize the queues to send request and receive response
FTRequestQueue = xQueueCreate(1, sizeof(FT_glyph_dsc_request));
FTResponseQueue = xQueueCreate(1, sizeof(FT_glyph_dsc_response));
xTaskCreatePinnedToCore(FT_loop_task, "FreeType_task", LV_USE_FT_STACK_SIZE, NULL, 1, &FTTaskHandle, ARDUINO_RUNNING_CORE);
if (FTRequestQueue && FTResponseQueue) {
return true;
}
Fail:
FTC_Manager_Done(cache_manager);
FT_Done_FreeType(library);
return false;
#else
LV_UNUSED(max_sizes);
LV_UNUSED(max_bytes);
return true;
#endif/* LV_USE_FT_CACHE_MANAGER */
}
void lv_freetype_destroy(void)
{
#if LV_USE_FT_CACHE_MANAGER
FTC_Manager_Done(cache_manager);
#endif
FT_Done_FreeType(library);
}
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 (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);
#else
face_info = (lv_face_info_t *)face->generic.data;
face_info->cnt++;
#endif
}
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.height >> 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);
#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);
}
#endif
lv_mem_free(dsc->font);
lv_mem_free(dsc);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void face_generic_finalizer(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);
}
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;
return FT_Err_Ok;
}
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)
{
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;
}
lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->user_data);
FT_Face face = dsc->face;
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);
dsc_out->adv_w = sbit->xadvance;
dsc_out->box_h = sbit->height; /*Height of the bitmap in [px]*/
dsc_out->box_w = sbit->width; /*Width of the bitmap in [px]*/
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*/
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);
return (const uint8_t *)sbit->buffer;
}
#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;
request.font = font;
request.dsc_out = dsc_out;
request.unicode_letter = unicode_letter;
request.unicode_letter_next = unicode_letter_next;
xQueueSendToBack(FTRequestQueue, &request, portMAX_DELAY);
if (xQueueReceive(FTResponseQueue, &response, portMAX_DELAY)) {
return response;
} else {
return false; // should never happen
}
}
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;
while (1) {
FT_glyph_dsc_request request;
FT_glyph_dsc_response response;
if (xQueueReceive(FTRequestQueue, &request, portMAX_DELAY)) {
#if LV_USE_FT_CACHE_MANAGER
response = get_glyph_dsc_cb_cache(request.font, request.dsc_out, request.unicode_letter, request.unicode_letter_next);
#else
response = get_glyph_dsc_cb_nocache(request.font, request.dsc_out, request.unicode_letter, request.unicode_letter_next);
#endif
xQueueSendToBack(FTResponseQueue, &response, portMAX_DELAY); // send back response
}
}
}

View File

@ -0,0 +1,486 @@
/**
* @file lv_freetype.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_freetype.h"
#if LV_USE_FREETYPE
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_CACHE_H
#include FT_SIZES_H
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
char * name;
} lv_face_info_t;
typedef struct {
lv_ll_t face_ll;
} lv_faces_control_t;
typedef struct {
#if LV_FREETYPE_CACHE_SIZE >= 0
void * face_id;
#else
FT_Size size;
#endif
lv_font_t * font;
uint16_t style;
uint16_t height;
} lv_font_fmt_ft_dsc_t;
/**********************
* STATIC PROTOTYPES
**********************/
#if LV_FREETYPE_CACHE_SIZE >= 0
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);
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 lv_ft_font_init_nocache(lv_ft_info_t * info);
static void lv_ft_font_destroy_nocache(lv_font_t * font);
#endif
/**********************
* STATIC VARIABLES
**********************/
static FT_Library library;
#if LV_FREETYPE_CACHE_SIZE >= 0
static FTC_Manager cache_manager;
static FTC_CMapCache cmap_cache;
static FTC_SBitCache sbit_cache;
static FTC_SBit sbit;
#else
static lv_faces_control_t face_control;
#endif
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
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_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);
LV_LOG_ERROR("Failed to open cache manager");
return false;
}
error = FTC_CMapCache_New(cache_manager, &cmap_cache);
if(error) {
LV_LOG_ERROR("Failed to open Cmap Cache");
goto Fail;
}
error = FTC_SBitCache_New(cache_manager, &sbit_cache);
if(error) {
LV_LOG_ERROR("Failed to open sbit cache");
goto Fail;
}
return true;
Fail:
FTC_Manager_Done(cache_manager);
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_FREETYPE_CACHE_SIZE */
}
void lv_freetype_destroy(void)
{
#if LV_FREETYPE_CACHE_SIZE >= 0
FTC_Manager_Done(cache_manager);
#endif
FT_Done_FreeType(library);
}
bool lv_ft_font_init(lv_ft_info_t * info)
{
#if LV_FREETYPE_CACHE_SIZE >= 0
return lv_ft_font_init_cache(info);
#else
return lv_ft_font_init_nocache(info);
#endif
}
void lv_ft_font_destroy(lv_font_t * font)
{
#if LV_FREETYPE_CACHE_SIZE >= 0
lv_ft_font_destroy_cache(font);
#else
lv_ft_font_destroy_nocache(font);
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
#if LV_FREETYPE_CACHE_SIZE >= 0
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);
lv_face_info_t * info = (lv_face_info_t *)face_id;
FT_Error error = FT_New_Face(library, info->name, 0, aface);
if(error) {
LV_LOG_ERROR("FT_New_Face error:%d\n", error);
return error;
}
return FT_Err_Ok;
}
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)
{
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;
}
lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
FT_Face face;
FTC_ImageTypeRec desc_sbit_type;
FTC_FaceID face_id = (FTC_FaceID)dsc->face_id;
FTC_Manager_LookupFace(cache_manager, face_id, &face);
desc_sbit_type.face_id = face_id;
desc_sbit_type.flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
desc_sbit_type.height = dsc->height;
desc_sbit_type.width = dsc->height;
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);
FT_Error error = FTC_SBitCache_Lookup(sbit_cache, &desc_sbit_type, glyph_index, &sbit, NULL);
if(error) {
LV_LOG_ERROR("SBitCache_Lookup error");
}
dsc_out->adv_w = sbit->xadvance;
dsc_out->box_h = sbit->height; /*Height of the bitmap in [px]*/
dsc_out->box_w = sbit->width; /*Width of the bitmap in [px]*/
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*/
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);
return (const uint8_t *)sbit->buffer;
}
static bool lv_ft_font_init_cache(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;
face_info = lv_mem_alloc(sizeof(lv_face_info_t) + strlen(info->name) + 1);
if(face_info == NULL) {
goto Fail;
}
face_info->name = ((char *)face_info) + sizeof(lv_face_info_t);
strcpy(face_info->name, info->name);
dsc->face_id = face_info;
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->face_id;
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_mem_free(face_info);
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_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->font);
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_mem_free(dsc->face_id);
lv_mem_free(dsc->font);
lv_mem_free(dsc);
}
}
#else/* LV_FREETYPE_CACHE_SIZE */
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;
}
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);
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);
}
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);
}
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if(error) {
return false;
}
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*/
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)
{
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(face == NULL) {
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;
}
/* link face and face info */
face_info->name = ((char *)face_info) + sizeof(lv_face_info_t);
strcpy(face_info->name, info->name);
face->generic.data = face_info;
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;
dsc->height = info->weight;
dsc->style = info->style;
lv_font_t * font = dsc->font;
font->dsc = dsc;
font->get_glyph_dsc = get_glyph_dsc_cb_nocache;
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->font);
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);
lv_mem_free(dsc->font);
lv_mem_free(dsc);
}
}
#endif/* LV_FREETYPE_CACHE_SIZE */
#endif /*LV_USE_FREETYPE*/

View File

@ -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,37 +12,16 @@ 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
#include "../../../lvgl.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 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,
@ -50,22 +29,12 @@ typedef enum {
} LV_FT_FONT_STYLE;
typedef struct {
const char* name; /* The name of the font file */
lv_font_t* font; /* point to lvgl font */
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 */
} 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;
/**********************
* GLOBAL PROTOTYPES
**********************/
@ -78,7 +47,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,20 +60,22 @@ 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.
* @param font pointer to font.
*/
void lv_ft_font_destroy(lv_font_t* font);
void lv_ft_font_destroy(lv_font_t * font);
/**********************
* MACROS
**********************/
#endif /*LV_USE_FREETYPE*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
#endif /* LV_FREETYPE_H */

View File

@ -20,7 +20,7 @@ extern "C" {
// #include "gif/lv_gif.h"
// #include "qrcode/lv_qrcode.h"
// #include "sjpg/lv_sjpg.h"
// #include "freetype/lv_freetype.h"
#include "freetype/lv_freetype.h"
// #include "rlottie/lv_rlottie.h"
/*********************

View File

@ -571,7 +571,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
#define LV_USE_QRCODE 0
/*FreeType library*/
#define LV_USE_FREETYPE 0
#define LV_USE_FREETYPE 1
#if LV_USE_FREETYPE
/*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/
# define LV_FREETYPE_CACHE_SIZE (16 * 1024)

View File

@ -1131,4 +1131,15 @@
#include "user_config_override.h" // Configuration overrides for my_user_config.h
#endif
/*********************************************************************************************\
* Post-process stack size adjustment
\*********************************************************************************************/
#if defined(USE_LVGL) && defined(USE_LVGL_FREETYPE) // Freetype requires a stack of at least 24KB
#if SET_ESP32_STACK_SIZE < (24 * 1024)
#undef SET_ESP32_STACK_SIZE
#define SET_ESP32_STACK_SIZE (24 * 1024)
#endif
#endif // USE_LVGL && USE_LVGL_FREETYPE
#endif // _MY_USER_CONFIG_H_

View File

@ -28,11 +28,6 @@
#include "lv_berry.h"
#include "Adafruit_LvGL_Glue.h"
#ifdef USE_LVGL_FREETYPE
#include "esp_task_wdt.h"
#include "lv_freetype.h"
#endif
// Berry easy logging
extern "C" {
extern void berry_log_C(const char * berry_buf, ...);
@ -126,7 +121,7 @@ extern "C" {
#ifdef USE_LVGL_FREETYPE
int argc = be_top(vm);
if (argc == 3 && be_isstring(vm, 1) && be_isint(vm, 2) && be_isint(vm, 3)) {
lv_ft_info_t info;
lv_ft_info_t info = {};
info.name = be_tostring(vm, 1);
info.weight = be_toint(vm, 2);
info.style = be_toint(vm, 3);

View File

@ -214,6 +214,9 @@ extern "C" {
be_map_insert_int(vm, "program_free", ESP.getFreeSketchSpace() / 1024);
be_map_insert_int(vm, "heap_free", ESP_getFreeHeap() / 1024);
be_map_insert_int(vm, "frag", ESP_getHeapFragmentation());
// give info about stack size
be_map_insert_int(vm, "stack_size", SET_ESP32_STACK_SIZE / 1024);
be_map_insert_int(vm, "stack_low", uxTaskGetStackHighWaterMark(nullptr) / 1024);
if (UsePSRAM()) {
be_map_insert_int(vm, "psram", ESP.getPsramSize() / 1024);
be_map_insert_int(vm, "psram_free", ESP.getFreePsram() / 1024);

View File

@ -32,10 +32,6 @@
#include "Adafruit_LvGL_Glue.h"
#ifdef USE_LVGL_FREETYPE
#include "lv_freetype.h"
#endif // USE_LVGL_FREETYPE
Adafruit_LvGL_Glue * glue;
// **************************************************