mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-09 01:28:45 +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;
|
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
|
// bytes 11xxxxxx are first bytes of UTF-8 characters
|
||||||
if (c >= 0xC0) {
|
if (c >= 0xC0) {
|
||||||
@ -867,3 +867,38 @@ void display_fade(int start, int end, int delay) {
|
|||||||
}
|
}
|
||||||
display_backlight(end);
|
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);
|
int display_backlight(int val);
|
||||||
void display_fade(int start, int end, int delay);
|
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
|
#endif
|
||||||
|
@ -317,11 +317,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_print_obj,
|
|||||||
/// font: int,
|
/// font: int,
|
||||||
/// fgcolor: int,
|
/// fgcolor: int,
|
||||||
/// bgcolor: int,
|
/// bgcolor: int,
|
||||||
|
/// text_offset: int = None,
|
||||||
|
/// text_len: int = None,
|
||||||
/// ) -> None:
|
/// ) -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Renders left-aligned text at position (x,y) where x is left position and
|
/// 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
|
/// y is baseline. Font font is used for rendering, fgcolor is used as
|
||||||
/// foreground color, bgcolor as background.
|
/// 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) {
|
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]);
|
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 font = mp_obj_get_int(args[4]);
|
||||||
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
||||||
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
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;
|
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);
|
mod_trezorui_Display_text);
|
||||||
|
|
||||||
/// def text_center(
|
/// def text_center(
|
||||||
@ -397,19 +417,44 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_right_obj,
|
|||||||
7, 7,
|
7, 7,
|
||||||
mod_trezorui_Display_text_right);
|
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.
|
/// 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,
|
STATIC mp_obj_t mod_trezorui_Display_text_width(size_t n_args,
|
||||||
mp_obj_t font) {
|
const mp_obj_t *args) {
|
||||||
mp_buffer_info_t txt = {0};
|
mp_buffer_info_t txt = {0};
|
||||||
mp_get_buffer_raise(text, &txt, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[1], &txt, MP_BUFFER_READ);
|
||||||
mp_int_t f = mp_obj_get_int(font);
|
mp_int_t f = mp_obj_get_int(args[2]);
|
||||||
int w = display_text_width(txt.buf, txt.len, f);
|
|
||||||
|
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);
|
return mp_obj_new_int(w);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorui_Display_text_width_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_width_obj,
|
||||||
|
3, 5,
|
||||||
mod_trezorui_Display_text_width);
|
mod_trezorui_Display_text_width);
|
||||||
|
|
||||||
/// def text_split(self, text: str, font: int, requested_width: int) -> int:
|
/// def text_split(self, text: str, font: int, requested_width: int) -> int:
|
||||||
|
@ -114,11 +114,15 @@ class Display:
|
|||||||
font: int,
|
font: int,
|
||||||
fgcolor: int,
|
fgcolor: int,
|
||||||
bgcolor: int,
|
bgcolor: int,
|
||||||
|
text_offset: int = None,
|
||||||
|
text_len: int = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Renders left-aligned text at position (x,y) where x is left position and
|
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
|
y is baseline. Font font is used for rendering, fgcolor is used as
|
||||||
foreground color, bgcolor as background.
|
foreground color, bgcolor as background.
|
||||||
|
Arguments text_offset and text_len can be used to render a substring of
|
||||||
|
the text.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def text_center(
|
def text_center(
|
||||||
@ -151,9 +155,17 @@ class Display:
|
|||||||
foreground color, bgcolor as background.
|
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.
|
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:
|
def text_split(self, text: str, font: int, requested_width: int) -> int:
|
||||||
|
@ -25,6 +25,17 @@ class TestDisplay(unittest.TestCase):
|
|||||||
|
|
||||||
def test_text(self):
|
def test_text(self):
|
||||||
display.text(120, 120, 'Test', 0, 0xFFFF, 0x0000)
|
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):
|
def test_text_center(self):
|
||||||
display.text_center(120, 120, 'Test', 0, 0xFFFF, 0x0000)
|
display.text_center(120, 120, 'Test', 0, 0xFFFF, 0x0000)
|
||||||
@ -34,6 +45,24 @@ class TestDisplay(unittest.TestCase):
|
|||||||
|
|
||||||
def test_text_width(self):
|
def test_text_width(self):
|
||||||
display.text_width('Test', 0)
|
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):
|
def test_qrcode(self):
|
||||||
display.qrcode(0, 0, 'Test', 4)
|
display.qrcode(0, 0, 'Test', 4)
|
||||||
|
Loading…
Reference in New Issue
Block a user