diff --git a/.github/workflows/check_style.yml b/.github/workflows/check_style.yml index b879a3405b..94a9de50fe 100644 --- a/.github/workflows/check_style.yml +++ b/.github/workflows/check_style.yml @@ -18,7 +18,7 @@ jobs: sudo apt-get update -y -qq sudo apt-get install astyle - name: Format code - run: ./code-format.sh + run: python code-format.py working-directory: scripts - name: Check that repository is clean run: git diff --exit-code || (echo "Please apply the preceding diff to your code or run scripts/code-format.sh"; false) diff --git a/docs/libs/freetype.md b/docs/libs/freetype.md index 9b5c96e452..b394eb70a3 100644 --- a/docs/libs/freetype.md +++ b/docs/libs/freetype.md @@ -1,6 +1,6 @@ ```eval_rst .. include:: /header.rst -:github_url: |github_link_base|/libs/bmp.md +:github_url: |github_link_base|/libs/freetype.md ``` # FreeType support @@ -19,11 +19,33 @@ Interface to [FreeType](https://www.freetype.org/) to generate font bitmaps run Enable `LV_USE_FREETYPE` in `lv_conf.h`. -See the examples below. +To cache the glyphs from the opened fonts set `LV_FREETYPE_CACHE_SIZE >= 0` and then use the following macros for detailed configuration: +1. `LV_FREETYPE_CACHE_SIZE`:maximum memory(bytes) used to cache font bitmap, outline, character maps, etc. 0 means use the system default value, less than 0 means disable cache.Note: that this value does not account for managed FT_Face and FT_Size objects. +1. `LV_FREETYPE_CACHE_FT_FACES`:maximum number of opened FT_Face objects managed by this cache instance.0 means use the system default value.Only useful when LV_FREETYPE_CACHE_SIZE >= 0. +1. `LV_FREETYPE_CACHE_FT_SIZES`:maximum number of opened FT_Size objects managed by this cache instance. 0 means use the system default value.Only useful when LV_FREETYPE_CACHE_SIZE >= 0. + +When you are sure that all the used fonts size will not be greater than 256, you can enable `LV_FREETYPE_SBIT_CACHE`, which is much more memory efficient for small bitmaps. + +You can use `lv_ft_font_init()` to create FreeType fonts. It returns `true` to indicate success, at the same time, the `font` member of `lv_ft_info_t` will be filled with a pointer to an lvgl font, and you can use it like any lvgl font. + +Font style supports bold and italic, you can use the following macro to set: +1. `FT_FONT_STYLE_NORMAL`:default style. +1. `FT_FONT_STYLE_ITALIC`:Italic style +1. `FT_FONT_STYLE_BOLD`:bold style + +They can be combined.eg:`FT_FONT_STYLE_BOLD | FT_FONT_STYLE_ITALIC`. Note that, the FreeType extension doesn't use LVGL's file system. You can simply pass the path to the font as usual on your operating system or platform. +## Example +```eval_rst + +.. include:: ../../examples/libs/freetype/index.rst + +``` + + ## 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) diff --git a/examples/libs/freetype/lv_example_freetype_1.c b/examples/libs/freetype/lv_example_freetype_1.c index 9cccc82f56..cacbd19db1 100644 --- a/examples/libs/freetype/lv_example_freetype_1.c +++ b/examples/libs/freetype/lv_example_freetype_1.c @@ -12,7 +12,10 @@ void lv_example_freetype_1(void) info.name = "./lvgl/examples/libs/freetype/arial.ttf"; info.weight = 24; info.style = FT_FONT_STYLE_NORMAL; - lv_ft_font_init(&info); + info.mem = NULL; + if(!lv_ft_font_init(&info)) { + LV_LOG_ERROR("create failed."); + } /*Create style with the new font*/ static lv_style_t style; diff --git a/lv_conf_template.h b/lv_conf_template.h index 9f59db8e2e..77bb35d42f 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -576,6 +576,16 @@ #if LV_USE_FREETYPE /*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/ #define LV_FREETYPE_CACHE_SIZE (16 * 1024) + #if LV_FREETYPE_CACHE_SIZE >= 0 + /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ + /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ + /* if font size >= 256, must be configured as image cache */ + #define LV_FREETYPE_SBIT_CACHE 0 + /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ + /* (0:use system defaults) */ + #define LV_FREETYPE_CACHE_FT_FACES 0 + #define LV_FREETYPE_CACHE_FT_SIZES 0 + #endif #endif /*Rlottie library*/ diff --git a/scripts/code-format.py b/scripts/code-format.py new file mode 100755 index 0000000000..f7e65e7f41 --- /dev/null +++ b/scripts/code-format.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 + +import os + +os.system('astyle --options=code-format.cfg "../src/*.c,*.h"') diff --git a/scripts/code-format.sh b/scripts/code-format.sh deleted file mode 100755 index 561f433098..0000000000 --- a/scripts/code-format.sh +++ /dev/null @@ -1 +0,0 @@ -astyle --options=code-format.cfg "../src/*.c,*.h" diff --git a/src/extra/libs/freetype/lv_freetype.c b/src/extra/libs/freetype/lv_freetype.c index bf8edf6b17..c2512c0fed 100644 --- a/src/extra/libs/freetype/lv_freetype.c +++ b/src/extra/libs/freetype/lv_freetype.c @@ -14,6 +14,8 @@ #include FT_GLYPH_H #include FT_CACHE_H #include FT_SIZES_H +#include FT_IMAGE_H +#include FT_OUTLINE_H /********************* * DEFINES @@ -67,8 +69,16 @@ 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; + 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 @@ -104,11 +114,19 @@ bool lv_freetype_init(uint16_t max_faces, uint16_t max_sizes, uint32_t 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 return true; Fail: @@ -176,6 +194,36 @@ static FT_Error font_face_requester(FTC_FaceID face_id, 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) { @@ -192,20 +240,51 @@ static bool get_glyph_dsc_cb_cache(const lv_font_t * font, 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); + 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; + } - 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_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); - FT_Error error = FTC_SBitCache_Lookup(sbit_cache, &desc_sbit_type, glyph_index, &sbit, NULL); + 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; @@ -214,16 +293,53 @@ static bool get_glyph_dsc_cb_cache(const lv_font_t * font, 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*/ - dsc_out->is_placeholder = glyph_index == 0; +#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 } static bool lv_ft_font_init_cache(lv_ft_info_t * info) @@ -297,6 +413,7 @@ void lv_ft_font_destroy_cache(lv_font_t * font) lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc); if(dsc) { + FTC_Manager_RemoveFaceID(cache_manager, (FTC_FaceID)dsc->face_id); lv_mem_free(dsc->face_id); lv_mem_free(dsc->font); lv_mem_free(dsc); @@ -380,6 +497,22 @@ static bool get_glyph_dsc_cb_nocache(const lv_font_t * font, 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; @@ -393,6 +526,10 @@ static bool get_glyph_dsc_cb_nocache(const lv_font_t * font, 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; } diff --git a/src/extra/lv_extra.c b/src/extra/lv_extra.c index 6cbcbe860b..17707a3a79 100644 --- a/src/extra/lv_extra.c +++ b/src/extra/lv_extra.c @@ -71,9 +71,12 @@ void lv_extra_init(void) #endif #if LV_USE_FREETYPE - /*Init freetype library - *Cache max 64 faces and 1 size*/ - lv_freetype_init(0, 0, LV_FREETYPE_CACHE_SIZE); + /*Init freetype library*/ +# if LV_FREETYPE_CACHE_SIZE >= 0 + lv_freetype_init(LV_FREETYPE_CACHE_FT_FACES, LV_FREETYPE_CACHE_FT_SIZES, LV_FREETYPE_CACHE_SIZE); +# else + lv_freetype_init(0, 0, 0); +# endif #endif #if LV_USE_FFMPEG diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 81b33d6965..ddc13e0b9a 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -1867,6 +1867,34 @@ #define LV_FREETYPE_CACHE_SIZE (16 * 1024) #endif #endif + #if LV_FREETYPE_CACHE_SIZE >= 0 + /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ + /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ + /* if font size >= 256, must be configured as image cache */ + #ifndef LV_FREETYPE_SBIT_CACHE + #ifdef CONFIG_LV_FREETYPE_SBIT_CACHE + #define LV_FREETYPE_SBIT_CACHE CONFIG_LV_FREETYPE_SBIT_CACHE + #else + #define LV_FREETYPE_SBIT_CACHE 0 + #endif + #endif + /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ + /* (0:use system defaults) */ + #ifndef LV_FREETYPE_CACHE_FT_FACES + #ifdef CONFIG_LV_FREETYPE_CACHE_FT_FACES + #define LV_FREETYPE_CACHE_FT_FACES CONFIG_LV_FREETYPE_CACHE_FT_FACES + #else + #define LV_FREETYPE_CACHE_FT_FACES 0 + #endif + #endif + #ifndef LV_FREETYPE_CACHE_FT_SIZES + #ifdef CONFIG_LV_FREETYPE_CACHE_FT_SIZES + #define LV_FREETYPE_CACHE_FT_SIZES CONFIG_LV_FREETYPE_CACHE_FT_SIZES + #else + #define LV_FREETYPE_CACHE_FT_SIZES 0 + #endif + #endif + #endif #endif /*Rlottie library*/