mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 15:38:11 +00:00
perf(core): enable rendering of substrings to avoid slicing
This commit is contained in:
parent
fa2e672f98
commit
db5b65a420
@ -594,7 +594,7 @@ static uint8_t convert_char(const uint8_t c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
// UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Description
|
||||
// UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Encoding
|
||||
|
||||
// bytes 11xxxxxx are first bytes of UTF-8 characters
|
||||
if (c >= 0xC0) {
|
||||
@ -867,3 +867,38 @@ void display_fade(int start, int end, int delay) {
|
||||
}
|
||||
display_backlight(end);
|
||||
}
|
||||
|
||||
#define UTF8_IS_CONT(ch) (((ch)&0xC0) == 0x80)
|
||||
|
||||
void display_utf8_substr(const char *buf_start, size_t buf_len, int char_off,
|
||||
int char_len, const char **out_start, int *out_len) {
|
||||
size_t i = 0;
|
||||
|
||||
for (; i < buf_len; i++) {
|
||||
if (char_off == 0) {
|
||||
break;
|
||||
}
|
||||
if (!UTF8_IS_CONT(buf_start[i])) {
|
||||
char_off--;
|
||||
}
|
||||
}
|
||||
size_t i_start = i;
|
||||
|
||||
for (; i < buf_len; i++) {
|
||||
if (char_len == 0) {
|
||||
break;
|
||||
}
|
||||
if (!UTF8_IS_CONT(buf_start[i])) {
|
||||
char_len--;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < buf_len; i++) {
|
||||
if (!UTF8_IS_CONT(buf_start[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*out_start = buf_start + i_start;
|
||||
*out_len = i - i_start;
|
||||
}
|
||||
|
@ -113,4 +113,8 @@ int display_orientation(int degrees);
|
||||
int display_backlight(int val);
|
||||
void display_fade(int start, int end, int delay);
|
||||
|
||||
// helper for locating a substring in buffer with utf-8 string
|
||||
void display_utf8_substr(const char *buf_start, size_t buf_len, int char_off,
|
||||
int char_len, const char **out_start, int *out_len);
|
||||
|
||||
#endif
|
||||
|
@ -317,11 +317,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_print_obj,
|
||||
/// font: int,
|
||||
/// fgcolor: int,
|
||||
/// bgcolor: int,
|
||||
/// text_offset: int = None,
|
||||
/// text_len: int = None,
|
||||
/// ) -> None:
|
||||
/// """
|
||||
/// Renders left-aligned text at position (x,y) where x is left position and
|
||||
/// y is baseline. Font font is used for rendering, fgcolor is used as
|
||||
/// foreground color, bgcolor as background.
|
||||
///
|
||||
/// Arguments text_offset and text_len can be used to render a substring of
|
||||
/// the text.
|
||||
/// """
|
||||
STATIC mp_obj_t mod_trezorui_Display_text(size_t n_args, const mp_obj_t *args) {
|
||||
mp_int_t x = mp_obj_get_int(args[1]);
|
||||
@ -331,10 +336,25 @@ STATIC mp_obj_t mod_trezorui_Display_text(size_t n_args, const mp_obj_t *args) {
|
||||
mp_int_t font = mp_obj_get_int(args[4]);
|
||||
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
||||
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
||||
display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor);
|
||||
|
||||
const char *buf_start = text.buf;
|
||||
int buf_len = text.len;
|
||||
if (n_args > 7) {
|
||||
mp_int_t off = mp_obj_get_int(args[7]);
|
||||
mp_int_t len = n_args > 8 ? mp_obj_get_int(args[8]) : text.len - off;
|
||||
if (off < 0 || off > text.len) {
|
||||
mp_raise_ValueError("Invalid text_offset");
|
||||
}
|
||||
if (len < 0 || len + off > text.len) {
|
||||
mp_raise_ValueError("Invalid text_len");
|
||||
}
|
||||
display_utf8_substr(text.buf, text.len, off, len, &buf_start, &buf_len);
|
||||
}
|
||||
|
||||
display_text(x, y, buf_start, buf_len, font, fgcolor, bgcolor);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_obj, 7, 7,
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_obj, 7, 9,
|
||||
mod_trezorui_Display_text);
|
||||
|
||||
/// def text_center(
|
||||
@ -397,20 +417,45 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_right_obj,
|
||||
7, 7,
|
||||
mod_trezorui_Display_text_right);
|
||||
|
||||
/// def text_width(self, text: str, font: int) -> int:
|
||||
/// def text_width(
|
||||
/// self,
|
||||
/// text: str,
|
||||
/// font: int,
|
||||
/// text_offset: int = None,
|
||||
/// text_len: int = None,
|
||||
/// ) -> int:
|
||||
/// """
|
||||
/// Returns a width of text in pixels. Font font is used for rendering.
|
||||
///
|
||||
/// Arguments text_offset and text_len can be used to render a substring of
|
||||
/// the text.
|
||||
/// """
|
||||
STATIC mp_obj_t mod_trezorui_Display_text_width(mp_obj_t self, mp_obj_t text,
|
||||
mp_obj_t font) {
|
||||
STATIC mp_obj_t mod_trezorui_Display_text_width(size_t n_args,
|
||||
const mp_obj_t *args) {
|
||||
mp_buffer_info_t txt = {0};
|
||||
mp_get_buffer_raise(text, &txt, MP_BUFFER_READ);
|
||||
mp_int_t f = mp_obj_get_int(font);
|
||||
int w = display_text_width(txt.buf, txt.len, f);
|
||||
mp_get_buffer_raise(args[1], &txt, MP_BUFFER_READ);
|
||||
mp_int_t f = mp_obj_get_int(args[2]);
|
||||
|
||||
const char *buf_start = txt.buf;
|
||||
int buf_len = txt.len;
|
||||
if (n_args > 3) {
|
||||
mp_int_t off = mp_obj_get_int(args[3]);
|
||||
mp_int_t len = n_args > 4 ? mp_obj_get_int(args[4]) : txt.len - off;
|
||||
if (off < 0 || off > txt.len) {
|
||||
mp_raise_ValueError("Invalid text_offset");
|
||||
}
|
||||
if (len < 0 || len + off > txt.len) {
|
||||
mp_raise_ValueError("Invalid text_len");
|
||||
}
|
||||
display_utf8_substr(txt.buf, txt.len, off, len, &buf_start, &buf_len);
|
||||
}
|
||||
|
||||
int w = display_text_width(buf_start, buf_len, f);
|
||||
return mp_obj_new_int(w);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorui_Display_text_width_obj,
|
||||
mod_trezorui_Display_text_width);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_width_obj,
|
||||
3, 5,
|
||||
mod_trezorui_Display_text_width);
|
||||
|
||||
/// def text_split(self, text: str, font: int, requested_width: int) -> int:
|
||||
/// """
|
||||
|
@ -114,11 +114,15 @@ class Display:
|
||||
font: int,
|
||||
fgcolor: int,
|
||||
bgcolor: int,
|
||||
text_offset: int = None,
|
||||
text_len: int = None,
|
||||
) -> None:
|
||||
"""
|
||||
Renders left-aligned text at position (x,y) where x is left position and
|
||||
y is baseline. Font font is used for rendering, fgcolor is used as
|
||||
foreground color, bgcolor as background.
|
||||
Arguments text_offset and text_len can be used to render a substring of
|
||||
the text.
|
||||
"""
|
||||
|
||||
def text_center(
|
||||
@ -151,9 +155,17 @@ class Display:
|
||||
foreground color, bgcolor as background.
|
||||
"""
|
||||
|
||||
def text_width(self, text: str, font: int) -> int:
|
||||
def text_width(
|
||||
self,
|
||||
text: str,
|
||||
font: int,
|
||||
text_offset: int = None,
|
||||
text_len: int = None,
|
||||
) -> int:
|
||||
"""
|
||||
Returns a width of text in pixels. Font font is used for rendering.
|
||||
Arguments text_offset and text_len can be used to render a substring of
|
||||
the text.
|
||||
"""
|
||||
|
||||
def text_split(self, text: str, font: int, requested_width: int) -> int:
|
||||
|
@ -25,6 +25,17 @@ class TestDisplay(unittest.TestCase):
|
||||
|
||||
def test_text(self):
|
||||
display.text(120, 120, 'Test', 0, 0xFFFF, 0x0000)
|
||||
display.text(120, 120, 'Test', 0, 0xFFFF, 0x0000, 2)
|
||||
display.text(120, 120, 'Test', 0, 0xFFFF, 0x0000, 2, 1)
|
||||
display.text(120, 120, 'Těst', 0, 0xFFFF, 0x0000, 2, 2)
|
||||
|
||||
display.text(120, 120, "ǑǑǑǑǑǑǑǑ", 0, 0xFFFF, 0x0000)
|
||||
for off in (0, 2, 3, 8, 16):
|
||||
display.text(120, 120, "ǑǑǑǑǑǑǑǑ", 0, 0xFFFF, 0x0000, off)
|
||||
display.text(120, 120, "ǑǑǑǑǑǑǑǑ", 0, 0xFFFF, 0x0000, off, 0)
|
||||
|
||||
for off, tlen in ((2, 5), (2, 14), (3, 5), (3, 13), (8, 1), (8, 8)):
|
||||
display.text(120, 120, "ǑǑǑǑǑǑǑǑ", 0, 0xFFFF, 0x0000, off, tlen)
|
||||
|
||||
def test_text_center(self):
|
||||
display.text_center(120, 120, 'Test', 0, 0xFFFF, 0x0000)
|
||||
@ -34,6 +45,24 @@ class TestDisplay(unittest.TestCase):
|
||||
|
||||
def test_text_width(self):
|
||||
display.text_width('Test', 0)
|
||||
display.text_width('Test', 0, 2)
|
||||
display.text_width('Test', 0, 2, 1)
|
||||
display.text_width('Těst', 0, 2, 2)
|
||||
|
||||
display.text_width("ǑǑǑǑǑǑǑǑ", 0)
|
||||
for off in (0, 2, 3, 8, 16):
|
||||
display.text_width("ǑǑǑǑǑǑǑǑ", 0, off)
|
||||
self.assertEqual(display.text_width("ǑǑǑǑǑǑǑǑ", 0, off, 0), 0)
|
||||
|
||||
for off, tlen in ((0, 8), (0, 16), (2, 5), (2, 14), (3, 5), (3, 13)):
|
||||
display.text_width("ǑǑǑǑǑǑǑǑ", 0, off, tlen)
|
||||
|
||||
self.assertEqual(display.text_width("ǑǑǑǑǑǑǑǑ", 8), 0)
|
||||
self.assertEqual(display.text_width("ǑǑǑǑǑǑǑǑ", 8, 1), 0)
|
||||
self.assertEqual(display.text_width("ǑǑǑǑǑǑǑǑ", 8, 8), 0)
|
||||
self.assertEqual(display.text_width("ǑǑǑǑǑǑǑǑ", 9), 0)
|
||||
self.assertEqual(display.text_width("ǑǑǑǑǑǑǑǑ", 9, 1), 0)
|
||||
self.assertEqual(display.text_width("ǑǑǑǑǑǑǑǑ", 15, 1), 0)
|
||||
|
||||
def test_qrcode(self):
|
||||
display.qrcode(0, 0, 'Test', 4)
|
||||
|
Loading…
Reference in New Issue
Block a user