From 48b29a52c52884f85d91e604b15daffb550e539e Mon Sep 17 00:00:00 2001 From: Nicolas Roggeman Date: Mon, 3 Jul 2023 11:28:02 +0200 Subject: [PATCH] Improve robustness of strings management in NBGL (especially nbgl_getTextHeightInWidth()) --- lib_nbgl/src/nbgl_fonts.c | 92 +++++++++++++++++++------------------- lib_nbgl/src/nbgl_layout.c | 46 +++++++++---------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/lib_nbgl/src/nbgl_fonts.c b/lib_nbgl/src/nbgl_fonts.c index a7d69a9e6..7a0c007bf 100644 --- a/lib_nbgl/src/nbgl_fonts.c +++ b/lib_nbgl/src/nbgl_fonts.c @@ -23,6 +23,9 @@ #define PIC_FONT(x) ((nbgl_font_t const *)PIC(x)) #define BAGL_FONT_ID_MASK 0x0FFF +#define IS_WORD_DELIM(c) (c == ' ' || c == '\n' || c == '\b' || c == '\f' || c == '-' || c == '_') + + /********************** * TYPEDEFS **********************/ @@ -107,7 +110,7 @@ const nbgl_font_t *nbgl_getFont(nbgl_font_id_e fontId) { } #else const nbgl_font_t *nbgl_getFont(nbgl_font_id_e fontId) { - return (nbgl_font_t *) nbgl_font_getFont(fontId); + return nbgl_font_getFont(fontId); } #endif // BOLOS_OS_UPGRADER_APP /** @@ -183,11 +186,11 @@ static uint8_t getCharWidth(const nbgl_font_t *font, uint32_t unicode, bool is_u #endif // HAVE_UNICODE_SUPPORT } else { - nbgl_font_character_t *character; // non-unicode char + const nbgl_font_character_t *character; // non-unicode char if ((unicode < font->first_char) || (unicode > font->last_char)) { return 0; } - character = (nbgl_font_character_t *)PIC(&font->characters[unicode-font->first_char]); + character = (const nbgl_font_character_t *)PIC(&font->characters[unicode-font->first_char]); return character->width; } } @@ -353,12 +356,11 @@ uint16_t nbgl_getTextHeight(nbgl_font_id_e fontId, const char*text) { * @return the number of bytes in the given text */ uint16_t nbgl_getTextLength(const char* text) { - uint16_t nbChars=0; - while ((*text)&&(*text != '\n')) { - nbChars++; + const char* origText = text; + while ((*text) && (*text != '\n')) { text++; } - return nbChars; + return text-origText; } /** @@ -376,7 +378,7 @@ uint16_t nbgl_getTextLength(const char* text) { void nbgl_getTextMaxLenAndWidth(nbgl_font_id_e fontId, const char* text, uint16_t maxWidth, uint16_t *len, uint16_t *width, bool wrapping) { const nbgl_font_t *font = nbgl_getFont(fontId); uint16_t textLen = nbgl_getTextLength(text); - uint32_t lenAtLastSpace = 0, widthAtLastSpace = 0; + uint32_t lenAtLastDelimiter = 0, widthAtlastDelimiter = 0; #ifdef HAVE_UNICODE_SUPPORT nbgl_getUnicodeFont(fontId); @@ -402,14 +404,14 @@ void nbgl_getTextMaxLenAndWidth(nbgl_font_id_e fontId, const char* text, uint16_ continue; // memorize cursors at last found sepator, when wrapping - if ((wrapping == true) && (unicode == ' ')) { - lenAtLastSpace = *len; - widthAtLastSpace = *width; + if ((wrapping == true) && IS_WORD_DELIM(unicode)) { + lenAtLastDelimiter = *len; + widthAtlastDelimiter = *width; } if ((*width+char_width) > maxWidth) { - if ((wrapping == true)&&(widthAtLastSpace>0)) { - *len = lenAtLastSpace+1; - *width = widthAtLastSpace; + if ((wrapping == true) && (widthAtlastDelimiter > 0)) { + *len = lenAtLastDelimiter+1; + *width = widthAtlastDelimiter; } return; } @@ -435,20 +437,18 @@ bool nbgl_getTextMaxLenInNbLines(nbgl_font_id_e fontId, const char* text, uint16 const nbgl_font_t *font = nbgl_getFont(fontId); uint16_t textLen = strlen(text); uint16_t width = 0; + const char *origText = text; #ifdef HAVE_UNICODE_SUPPORT nbgl_getUnicodeFont(fontId); #endif // HAVE_UNICODE_SUPPORT - *len=0; while ((textLen)&&(maxNbLines>0)) { uint8_t char_width; uint32_t unicode; bool is_unicode; - uint16_t curTextLen = textLen; unicode = nbgl_popUnicodeChar((const uint8_t **)&text, &textLen, &is_unicode); - *len += curTextLen-textLen; // if \n, reset width if (unicode == '\n') { maxNbLines--; @@ -464,13 +464,13 @@ bool nbgl_getTextMaxLenInNbLines(nbgl_font_id_e fontId, const char* text, uint16 width = 0; maxNbLines--; if (maxNbLines == 0) { - // remove last char nb_bytes - *len -= curTextLen-textLen; break; } + continue; } width += char_width; } + *len = text-origText; return (maxNbLines == 0); } @@ -494,7 +494,7 @@ bool nbgl_getTextMaxLenAndWidthFromEnd(nbgl_font_id_e fontId, const char* text, *width=0; *len=0; while (textLen) { - nbgl_font_character_t *character; + const nbgl_font_character_t *character; uint8_t char_width; char cur_char; @@ -510,7 +510,7 @@ bool nbgl_getTextMaxLenAndWidthFromEnd(nbgl_font_id_e fontId, const char* text, if ((cur_char < font->first_char) || (cur_char > font->last_char)) { continue; } - character = (nbgl_font_character_t *)PIC(&font->characters[cur_char-font->first_char]); + character = (const nbgl_font_character_t *)PIC(&font->characters[cur_char-font->first_char]); char_width = character->width; if ((*width+char_width) > maxWidth) { @@ -536,8 +536,8 @@ uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char* text, uin uint16_t width=0; uint16_t nbLines=1; uint16_t textLen = strlen(text); - const char *lastSpace = NULL; - uint32_t lenAtLastSpace = 0; + const char *lastDelimiter = NULL; + uint32_t lenAtLastDelimiter = 0; const char *prevText = NULL; #ifdef HAVE_UNICODE_SUPPORT @@ -553,11 +553,16 @@ uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char* text, uin prevText = text; unicode = nbgl_popUnicodeChar((const uint8_t **)&text, &textLen, &is_unicode); + // memorize cursors at last found space + if ((wrapping == true) && (IS_WORD_DELIM(unicode))) { + lastDelimiter = prevText; + lenAtLastDelimiter = textLen; + } // if \n, increment the number of lines if (unicode == '\n') { nbLines++; width = 0; - lastSpace = NULL; + lastDelimiter = NULL; continue; } @@ -565,17 +570,12 @@ uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char* text, uin if (char_width == 0) continue; - // memorize cursors at last found space - if ((wrapping == true) && (unicode == ' ')) { - lastSpace = prevText; - lenAtLastSpace = textLen+1; - } // if about to reach max len, increment the number of lines if ((width+char_width)>maxWidth) { - if ((wrapping == true) && (lastSpace != NULL)) { - text = lastSpace+1; - lastSpace = NULL; - textLen = lenAtLastSpace; + if ((wrapping == true) && (lastDelimiter != NULL)) { + text = lastDelimiter+1; + lastDelimiter = NULL; + textLen = lenAtLastDelimiter; width = 0; } else { @@ -618,8 +618,8 @@ void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char* text, uint16_t maxWidth uint16_t textLen = nbgl_getTextLength(text); uint16_t width = 0; uint8_t currentNbLines = 1; - char *lastSpace = NULL; - uint32_t lenAtLastSpace = 0; + char *lastDelimiter = NULL; + uint32_t lenAtLastDelimiter = 0; char *prevText = NULL; #ifdef HAVE_UNICODE_SUPPORT @@ -640,7 +640,7 @@ void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char* text, uint16_t maxWidth if (unicode == '\n') { width = 0; currentNbLines++; - lastSpace = NULL; + lastDelimiter = NULL; continue; } @@ -649,9 +649,9 @@ void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char* text, uint16_t maxWidth continue; // memorize cursors at last found space - if (unicode == ' ') { - lastSpace = prevText; - lenAtLastSpace = textLen+1; + if (IS_WORD_DELIM(unicode)) { + lastDelimiter = prevText; + lenAtLastDelimiter = textLen+1; } // if the width is about to overpass maxWidth, do something if ((width+char_width) > maxWidth) { @@ -659,11 +659,11 @@ void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char* text, uint16_t maxWidth if (currentNbLinesfonts_offset); - unicodeCtx.characters = (nbgl_font_unicode_character_t *)(ptr + language_pack->characters_offset); - unicodeCtx.bitmap = (uint8_t *)(ptr + language_pack->bitmaps_offset); + unicodeCtx.characters = (const nbgl_font_unicode_character_t *)(ptr + language_pack->characters_offset); + unicodeCtx.bitmap = (const uint8_t *)(ptr + language_pack->bitmaps_offset); for (uint32_t i=0; i < language_pack->nb_fonts; i++) { if (font->font_id == fontId) { diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index ab88573a4..3c5c86639 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -58,7 +58,7 @@ if ((__layout)->panel.nbChildren==(NB_MAX_MAIN_PANEL_CHILDREN-1)) return NO_MORE_OBJ_ERROR; \ } -#define GET_AVAILABLE_WIDTH(__layout) (SCREEN_WIDTH-2*BORDER_MARGIN) +#define AVAILABLE_WIDTH (SCREEN_WIDTH-(2*BORDER_MARGIN)) /********************** * TYPEDEFS @@ -635,7 +635,7 @@ int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *ba container->children = nbgl_containerPoolGet(4,layoutInt->layer); container->nbChildren = 0; - container->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + container->obj.area.width = AVAILABLE_WIDTH; container->obj.area.height = TOUCHABLE_BAR_HEIGHT; container->layout = HORIZONTAL; container->obj.alignmentMarginX = BORDER_MARGIN; @@ -750,7 +750,7 @@ int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switc // get container children container->children = nbgl_containerPoolGet(3,layoutInt->layer); - container->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + container->obj.area.width = AVAILABLE_WIDTH; container->obj.area.height = 2*BORDER_MARGIN; container->layout = VERTICAL; container->obj.alignmentMarginX = BORDER_MARGIN; @@ -827,7 +827,7 @@ int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subT container->nbChildren++; container->children = nbgl_containerPoolGet(container->nbChildren,layoutInt->layer); - container->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + container->obj.area.width = AVAILABLE_WIDTH; if (text != NULL) { textArea = (nbgl_text_area_t *)nbgl_objPoolGet(TEXT_AREA,layoutInt->layer); @@ -895,7 +895,7 @@ int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text) { textArea->text = PIC(text); textArea->textAlignment = MID_LEFT; textArea->fontId = BAGL_FONT_INTER_MEDIUM_32px; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeightInWidth(textArea->fontId,textArea->text,textArea->obj.area.width,false); textArea->style = NO_STYLE; textArea->obj.alignment = NO_ALIGNMENT; @@ -1059,7 +1059,7 @@ int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredI else { textArea->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; } - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeightInWidth(textArea->fontId,textArea->text,textArea->obj.area.width,false); if (info->style == LEDGER_INFO) { @@ -1097,7 +1097,7 @@ int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredI textArea->text = PIC(info->text2); textArea->textAlignment = CENTER; textArea->fontId = (info->style != LARGE_CASE_BOLD_INFO) ? BAGL_FONT_INTER_REGULAR_24px: BAGL_FONT_INTER_SEMIBOLD_24px; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeightInWidth(textArea->fontId,textArea->text,textArea->obj.area.width,false); textArea->style = NO_STYLE; @@ -1151,7 +1151,7 @@ int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredI textArea->text = PIC(info->text3); textArea->textAlignment = CENTER; textArea->fontId = BAGL_FONT_INTER_REGULAR_24px; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeightInWidth(textArea->fontId,textArea->text,textArea->obj.area.width,false); textArea->style = NO_STYLE; if (container->nbChildren>0) { @@ -1181,7 +1181,7 @@ int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredI container->obj.alignment = CENTER; } - container->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + container->obj.area.width = AVAILABLE_WIDTH; // set this new container as child of main container addObjectToLayout(layoutInt,(nbgl_obj_t*)container); @@ -1243,7 +1243,7 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) textArea->text = PIC(info->text1); textArea->textAlignment = CENTER; textArea->fontId = (info->largeText1 == true)? BAGL_FONT_INTER_MEDIUM_32px : BAGL_FONT_INTER_REGULAR_24px; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeightInWidth(textArea->fontId,textArea->text,textArea->obj.area.width,false); textArea->obj.alignment = BOTTOM_MIDDLE; textArea->obj.alignTo = (nbgl_obj_t*)container->children[container->nbChildren-1]; @@ -1260,7 +1260,7 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) textArea->text = PIC(info->text2); textArea->textAlignment = CENTER; textArea->fontId = BAGL_FONT_INTER_REGULAR_24px; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeightInWidth(textArea->fontId, textArea->text, textArea->obj.area.width, false); textArea->obj.alignment = BOTTOM_MIDDLE; textArea->obj.alignTo = (nbgl_obj_t*)container->children[container->nbChildren-1]; @@ -1283,7 +1283,7 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) container->obj.alignTo = layoutInt->container->children[layoutInt->container->nbChildren-1]; } - container->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + container->obj.area.width = AVAILABLE_WIDTH; // set this new container as child of main container addObjectToLayout(layoutInt,(nbgl_obj_t*)container); @@ -1330,7 +1330,7 @@ int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceBu } bottomButton->innerColor = WHITE; bottomButton->foregroundColor = BLACK; - bottomButton->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + bottomButton->obj.area.width = AVAILABLE_WIDTH; bottomButton->obj.area.height = BUTTON_DIAMETER; bottomButton->radius = BUTTON_RADIUS; bottomButton->text = PIC(info->bottomText); @@ -1398,7 +1398,7 @@ int nbgl_layoutAddTagValueList(nbgl_layout_t *layout, const nbgl_layoutTagValueL pair = list->callback(list->startIndex+i); } // width that can be used for item and text - usableWidth = GET_AVAILABLE_WIDTH(layoutInt); + usableWidth = AVAILABLE_WIDTH; container = (nbgl_container_t *)nbgl_objPoolGet(CONTAINER,layoutInt->layer); @@ -1511,7 +1511,7 @@ int nbgl_layoutAddProgressBar(nbgl_layout_t *layout, const nbgl_layoutProgressBa textArea->text = PIC(barLayout->text); textArea->textAlignment = MID_LEFT; textArea->fontId = BAGL_FONT_INTER_REGULAR_24px; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(((nbgl_layoutInternal_t *)layout)); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeight(textArea->fontId,textArea->text); textArea->style = NO_STYLE; textArea->obj.alignment = NO_ALIGNMENT; @@ -1526,7 +1526,7 @@ int nbgl_layoutAddProgressBar(nbgl_layout_t *layout, const nbgl_layoutProgressBa progress->obj.area.width = 120; progress->obj.area.height = 12; progress->obj.alignment = NO_ALIGNMENT; - progress->obj.alignmentMarginX = (GET_AVAILABLE_WIDTH(((nbgl_layoutInternal_t *)layout))-progress->obj.area.width)/2; + progress->obj.alignmentMarginX = (AVAILABLE_WIDTH-progress->obj.area.width)/2; progress->obj.alignmentMarginY = BORDER_MARGIN; addObjectToLayout(layoutInt,(nbgl_obj_t*)progress); @@ -1538,7 +1538,7 @@ int nbgl_layoutAddProgressBar(nbgl_layout_t *layout, const nbgl_layoutProgressBa subTextArea->text = PIC(barLayout->subText); subTextArea->textAlignment = MID_LEFT; subTextArea->fontId = BAGL_FONT_INTER_REGULAR_24px; - subTextArea->obj.area.width = GET_AVAILABLE_WIDTH(((nbgl_layoutInternal_t *)layout)); + subTextArea->obj.area.width = AVAILABLE_WIDTH; subTextArea->obj.area.height = nbgl_getTextHeight(subTextArea->fontId,subTextArea->text); subTextArea->style = NO_STYLE; subTextArea->obj.alignment = NO_ALIGNMENT; @@ -1627,7 +1627,7 @@ int nbgl_layoutAddButton(nbgl_layout_t *layout, const nbgl_layoutButton_t *butto button->obj.alignmentMarginX += (SCREEN_WIDTH-2*BORDER_MARGIN-button->obj.area.width)/2; } else { - button->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + button->obj.area.width = AVAILABLE_WIDTH; button->obj.area.height = BUTTON_DIAMETER; button->radius = BUTTON_RADIUS; } @@ -1744,7 +1744,7 @@ int nbgl_layoutAddFooter(nbgl_layout_t *layout, const char *text, uint8_t token, textArea->obj.alignment = BOTTOM_MIDDLE; textArea->textColor = BLACK; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = BUTTON_DIAMETER; textArea->text = PIC(text); textArea->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; @@ -1793,7 +1793,7 @@ int nbgl_layoutAddSplitFooter(nbgl_layout_t *layout, const char *leftText, uint8 textArea->obj.alignment = BOTTOM_LEFT; textArea->textColor = BLACK; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt)/2; + textArea->obj.area.width = AVAILABLE_WIDTH/2; textArea->obj.area.height = BUTTON_DIAMETER; textArea->text = PIC(leftText); textArea->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; @@ -1810,7 +1810,7 @@ int nbgl_layoutAddSplitFooter(nbgl_layout_t *layout, const char *leftText, uint8 textArea->obj.alignment = BOTTOM_RIGHT; textArea->textColor = BLACK; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt)/2; + textArea->obj.area.width = AVAILABLE_WIDTH/2; textArea->obj.area.height = BUTTON_DIAMETER; textArea->text = PIC(rightText); textArea->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; @@ -1944,7 +1944,7 @@ int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, bool fixed) { textArea->obj.alignmentMarginY = 20; textArea->obj.alignTo = (nbgl_obj_t*)spinner; textArea->obj.alignment = BOTTOM_MIDDLE; - textArea->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getFontLineHeight(textArea->fontId); textArea->style = NO_STYLE; @@ -2342,7 +2342,7 @@ int nbgl_layoutAddConfirmationButton(nbgl_layout_t *layout, bool active, const c } button->text = PIC(text); button->fontId = BAGL_FONT_INTER_SEMIBOLD_24px_1bpp; - button->obj.area.width = GET_AVAILABLE_WIDTH(layoutInt); + button->obj.area.width = AVAILABLE_WIDTH; button->obj.area.height = BUTTON_DIAMETER; button->radius = BUTTON_RADIUS; button->obj.alignTo = layoutInt->container->children[layoutInt->container->nbChildren-1];