perf(core): enable rendering of substrings to avoid slicing

pull/1403/head
Martin Milata 4 years ago committed by matejcik
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…
Cancel
Save