InfiniTimeOrg / InfiniTimeOrg/InfiniTime
backport lvgl fallback font to enable support for more language (via external flash font loading)
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 3.4k
- Forks
- 1.1k
- PR merge metrics
- No merged PRs in 30d
Description
Verification
- I searched for similar feature request and found none was relevant.
Pitch us your idea!
Let's backport font fallback to enable more languages and emoji
Description
Due to the small size of os storage, we can only fit a very small number of glyphs in the default font.
To support other non-English language, numerous forks have been created to support different language by adding glyphs to jetbrains_mono_bold_20 such as this one
Loading custom font from external storage is another idea that have been proposed several times. (e.g. https://github.com/InfiniTimeOrg/InfiniTime/issues/212 ) There are also watchfaces in current release that already use external flash to store fonts.
However, if a LV_LABEL is set to use a certain font. (as stated here)
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
It can only use the font specified here and cannot fallback to system font (e.g. jetbrains_mono_bold_20) if a glyph is not in this font. This means the custom font will have to duplicate everything in jetbrains_mono_bold_20 including ascii alnum, which is not very efficient.
Starting from LVGL 8.1, a fallback font can be selected. This way, only the extended glyphs (non-english alphabet, emoji ...) needs to be put in the custom font. Unfortunately, InfiniTime is currently using LVGL 7.
I think backporting this function should be considered since previous attempt to upgrade to LVGL 8 is stalled.
If I didn't miss anything, the following patch should be enough.
diff --git a/src/lv_draw/lv_draw_label.c b/src/lv_draw/lv_draw_label.c
index 970791ff..7cbf099b 100644
--- a/src/lv_draw/lv_draw_label.c
+++ b/src/lv_draw/lv_draw_label.c
@@ -433,6 +433,10 @@ LV_ATTRIBUTE_FAST_MEM static void lv_draw_letter(const lv_point_t * pos_p, const
return;
}
+ if (g.resolved_font) {
+ font_p = g.resolved_font;
+ }
+
const uint8_t * map_p = lv_font_get_glyph_bitmap(font_p, letter);
if(map_p == NULL) {
LV_LOG_WARN("lv_draw_letter: character's bitmap not found");
diff --git a/src/lv_font/lv_font.c b/src/lv_font/lv_font.c
index 9e3ec220..49bffcbc 100644
--- a/src/lv_font/lv_font.c
+++ b/src/lv_font/lv_font.c
@@ -61,7 +61,18 @@ const uint8_t * lv_font_get_glyph_bitmap(const lv_font_t * font_p, uint32_t lett
bool lv_font_get_glyph_dsc(const lv_font_t * font_p, lv_font_glyph_dsc_t * dsc_out, uint32_t letter,
uint32_t letter_next)
{
- return font_p->get_glyph_dsc(font_p, dsc_out, letter, letter_next);
+ dsc_out->resolved_font = NULL;
+ const lv_font_t * f = font_p;
+ bool found = false;
+ while(f) {
+ found = f->get_glyph_dsc(f, dsc_out, letter, letter_next);
+ if (found) {
+ dsc_out->resolved_font = f;
+ break;
+ }
+ f = f->fallback;
+ }
+ return found;
}
/**
diff --git a/src/lv_font/lv_font.h b/src/lv_font/lv_font.h
index 26cc653b..b4353c17 100644
--- a/src/lv_font/lv_font.h
+++ b/src/lv_font/lv_font.h
@@ -34,7 +34,9 @@ extern "C" {
*-----------------*/
/** Describes the properties of a glyph. */
+struct _lv_font_struct;
typedef struct {
+ const struct _lv_font_struct *resolved_font; /**< Pointer to a font where the gylph was actually found after handling fallbacks*/
uint16_t adv_w; /**< The glyph needs this space. Draw the next glyph after this width. */
uint16_t box_w; /**< Width of the glyph's bounding box*/
uint16_t box_h; /**< Height of the glyph's bounding box*/
@@ -70,6 +72,7 @@ typedef struct _lv_font_struct {
int8_t underline_thickness; /**< Thickness of the underline*/
void * dsc; /**< Store implementation specific or run_time data or caching here*/
+ const struct _lv_font_struct * fallback; /**< Fallback font for missing glyph. Resolved recursively */
#if LV_USE_USER_DATA
lv_font_user_data_t user_data; /**< Custom user data for font. */
#endif
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading src/lv_draw/lv_draw_label.c, src/lv_font/lv_font.c, and src/lv_font/lv_font.h, then compare the proposed changes with LVGL 8.1's font-fallback documentation. Check doc/ExternalResources.md and existing external-font watchfaces to understand the integration. Done means a custom external font can provide extended glyphs while missing glyphs resolve through the configured fallback font.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- embedded-iot
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100