[BUG] Persian digit 2 (U+06F2) corrupted and replaced by 0 (U+06F0) due to typo in ap_chars_map (lv_text_ap.c)
Author: mansouri93Created Sep 15, 2026Updated Sep 17, 2026
LVGL version
v9.x / v8.x / master (verified on v9.5.0)
Platform
Platform-independent (affecting all platforms when LV_USE_ARABIC_PERSIAN_CHARS is enabled)
What happened?
When Arabic/Persian text shaping is enabled (LV_USE_ARABIC_PERSIAN_CHARS 1), the Persian digit two (۲, Unicode U+06F2) is incorrectly mutated and rendered on screen as the Persian digit zero (۰, Unicode U+06F0).
For instance:
- The day number
۲۴is rendered as۰۴. - The year
۲۰۲۶is rendered as۰۰۰۶. - Time
۱۰:۲۵is rendered as۱۰:۰۵.
Root Cause Analysis:
In src/misc/lv_text_ap.c, the lookup table ap_chars_map[] defines character joining behaviors and forms. In Arabic and Persian, numeric digits do not connect or have contextual initial/medial/final forms; thus, all digits have their shaping offsets set to 0, which is correctly defined for digits 1 through 9 (U+06F1 to U+06F9):
{207, 0x06F1, 0, 0, 0, {0, 0}}, // ۱
{208, 0x06F2, 0, 0, 0, {0, 0}}, // ۲
...
However, line 91 for Persian digit zero (۰, U+06F0) contains an accidental copy-paste typo from the Arabic Teh Marbuta line immediately above it ({7, 0xFE94, -1, 2, -1, {1, 0}}):
c
{7, 0xFE94, -1, 2, -1, {1, 0}}, // ة
{206, 0x06F0, -1, 2, 0, {0, 0}}, // ۰ <-- BUG: char_middle_form_offset is 2!
Because char_middle_form_offset is set to 2: Inside lv_ap_get_char_index():
c
if(c == (ap_chars_map[i].char_end_form + ap_chars_map[i].char_middle_form_offset)) {
return i;
}
When i = 206 (index of ۰), this evaluates to: 0x06F0 + 2 = 0x06F2 (which is the Unicode point for Persian digit ۲).
As a result, whenever lv_text_ap_proc() encounters the digit ۲ (0x06F2), lv_ap_get_char_index() matches it to index 206 (digit ۰) as its supposed middle form. The contextual processing engine then replaces U+06F2 with the isolated form of U+06F0, turning every Persian digit ۲ into ۰.
Proposed Fix:
Set all offsets for Persian zero (0x06F0) to 0, 0, 0, identical to all other digits:
diff
--- a/src/misc/lv_text_ap.c
+++ b/src/misc/lv_text_ap.c
@@ -88,7 +88,7 @@ static const ap_chars_map_t ap_chars_map[] = {
{40, 0xFEF2, 1, 2, -1, {1, 1}}, // ي
{170, 0xFBFD, 1, 2, -1, {1, 1}}, // ی
{7, 0xFE94, -1, 2, -1, {1, 0}}, // ة
- {206, 0x06F0, -1, 2, 0, {0, 0}}, // ۰
+ {206, 0x06F0, 0, 0, 0, {0, 0}}, // ۰
{207, 0x06F1, 0, 0, 0, {0, 0}}, // ۱
{208, 0x06F2, 0, 0, 0, {0, 0}}, // ۲
---
### 5.(`How to reproduce?`):
```c
/* 1. Ensure LV_USE_ARABIC_PERSIAN_CHARS is enabled in lv_conf.h: */
#define LV_USE_ARABIC_PERSIAN_CHARS 1
/* 2. Create a label containing Persian digit 2: */
lv_obj_t * label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "۱۴۰۵/۰۶/۲۴"); /* 1405/06/24 */
/*
* Observed behavior:
* The label renders as "۱۴۰۵/۰۶/۰۴" on screen (the digit ۲ is replaced by ۰).
*
* Expected behavior:
* The label should render as "۱۴۰۵/۰۶/۲۴".
*/
### How to reproduce?
_No response_Source: lvgl/lvgl