1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00

feat(freetype): support bold and italic (#2824)

* feat(freetype):support bold and italic

* fix(format): replace code-format.sh with code-format.py

Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
guoweilkd 2021-11-25 03:19:09 +08:00 committed by GitHub
parent 6791522588
commit 81f7d50c45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 227 additions and 20 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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*/

5
scripts/code-format.py Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env python3
import os
os.system('astyle --options=code-format.cfg "../src/*.c,*.h"')

View File

@ -1 +0,0 @@
astyle --options=code-format.cfg "../src/*.c,*.h"

View File

@ -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;
}

View File

@ -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

View File

@ -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*/