Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_fonts.c
Go to the documentation of this file.
1
6/*********************
7 * INCLUDES
8 *********************/
9#include <string.h>
10#include "app_config.h"
11#include "nbgl_debug.h"
12#include "nbgl_draw.h"
13#include "nbgl_fonts.h"
14#include "os_helpers.h"
15#include "os_pic.h"
16#if defined(HAVE_LANGUAGE_PACK)
17#include "ux_loc.h"
18#endif // defined(HAVE_LANGUAGE_PACK)
19
20/*********************
21 * DEFINES
22 *********************/
23#define PIC_FONT(x) ((nbgl_font_t const *) PIC(x))
24#define BAGL_FONT_ID_MASK 0x0FFF
25
26#define IS_WORD_DELIM(c) (c == ' ' || c == '\n' || c == '\b' || c == '\f' || c == '-' || c == '_')
27
28/**********************
29 * TYPEDEFS
30 **********************/
31
32/**********************
33 * STATIC VARIABLES
34 **********************/
35#ifdef HAVE_UNICODE_SUPPORT
36static nbgl_unicode_ctx_t unicodeCtx = {0};
37#endif // HAVE_UNICODE_SUPPORT
38
39/**********************
40 * VARIABLES
41 **********************/
42
43#ifdef HAVE_LANGUAGE_PACK
44static const LANGUAGE_PACK *language_pack;
45#endif // HAVE_LANGUAGE_PACK
46
47#if defined(BOLOS_OS_UPGRADER_APP)
48#ifdef SCREEN_SIZE_WALLET
49#ifdef TARGET_STAX
50#include "nbgl_font_inter_regular_24.inc"
51#include "nbgl_font_inter_semibold_24.inc"
52#include "nbgl_font_inter_medium_32.inc"
53#include "nbgl_font_inter_regular_24_1bpp.inc"
54#include "nbgl_font_inter_semibold_24_1bpp.inc"
55#include "nbgl_font_inter_medium_32_1bpp.inc"
56#else // TARGET_STAX
57#include "nbgl_font_inter_regular_28.inc"
58#include "nbgl_font_inter_semibold_28.inc"
59#include "nbgl_font_inter_medium_36.inc"
60#include "nbgl_font_inter_regular_28_1bpp.inc"
61#include "nbgl_font_inter_semibold_28_1bpp.inc"
62#include "nbgl_font_inter_medium_36_1bpp.inc"
63#endif // TARGET_STAX
64#else // SCREEN_SIZE_WALLET
65#include "nbgl_font_open_sans_extrabold_11.inc"
66#include "nbgl_font_open_sans_regular_11.inc"
67#include "nbgl_font_open_sans_light_16.inc"
68#endif // SCREEN_SIZE_WALLET
69
70const nbgl_font_t *const C_nbgl_fonts[] = {
71
72#include "nbgl_font_rom_struct.inc"
73
74};
75const unsigned int C_nbgl_fonts_count = sizeof(C_nbgl_fonts) / sizeof(C_nbgl_fonts[0]);
76
77#endif
78
79#if (defined(HAVE_BOLOS) && !defined(BOLOS_OS_UPGRADER_APP))
80#if !defined(HAVE_LANGUAGE_PACK)
81const nbgl_font_unicode_t *const C_nbgl_fonts_unicode[] = {
82
83#include "nbgl_font_unicode_rom_struct.inc"
84
85};
86
87// All Unicode fonts MUST have the same number of characters!
88const unsigned int C_unicode_characters_count
89 = (sizeof(charactersOPEN_SANS_REGULAR_11PX_UNICODE)
90 / sizeof(charactersOPEN_SANS_REGULAR_11PX_UNICODE[0]));
91
92#endif
93#endif // HAVE_BOLOS
94
95#ifdef BUILD_SCREENSHOTS
96// Variables used to store important values (nb lines, bold state etc)
97uint16_t last_nb_lines = 0;
98uint16_t last_nb_pages = 0;
99bool last_bold_state = false;
100
101// Used to detect when a hyphenation (caesura) has been forced.
102bool hard_caesura = false;
103#endif // BUILD_SCREENSHOTS
104
105/**********************
106 * STATIC PROTOTYPES
107 **********************/
108
109/**********************
110 * GLOBAL FUNCTIONS
111 **********************/
112
119#if defined(BOLOS_OS_UPGRADER_APP)
121{
122 unsigned int i = C_nbgl_fonts_count;
123 fontId &= BAGL_FONT_ID_MASK;
124
125 while (i--) {
126 // font id match this entry (non indexed array)
127 if (PIC_FONT(C_nbgl_fonts[i])->font_id == fontId) {
128 return PIC_FONT(C_nbgl_fonts[i]);
129 }
130 }
131
132 // id not found
133 return NULL;
134}
135#else
137{
138 return nbgl_font_getFont(fontId);
139}
140#endif // BOLOS_OS_UPGRADER_APP
150uint32_t nbgl_popUnicodeChar(const uint8_t **text, uint16_t *textLen, bool *is_unicode)
151{
152 const uint8_t *txt = *text;
153 uint8_t cur_char = *txt++;
154 uint32_t unicode;
155
156 *is_unicode = true;
157 // Handle UTF-8 decoding (RFC3629): (https://www.ietf.org/rfc/rfc3629.txt
158 // Char. number range | UTF-8 octet sequence
159 // (hexadecimal) | (binary)
160 // --------------------+---------------------------------------------
161 // 0000 0000-0000 007F | 0xxxxxxx
162 // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
163 // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
164 // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
165
166 // 4 bytes UTF-8, Unicode 0x1000 to 0x1FFFF
167 if ((cur_char >= 0xF0) && (*textLen >= 4)) {
168 unicode = (cur_char & 0x07) << 18;
169 unicode |= (*txt++ & 0x3F) << 12;
170 unicode |= (*txt++ & 0x3F) << 6;
171 unicode |= (*txt++ & 0x3F);
172
173 // 3 bytes, from 0x800 to 0xFFFF
174 }
175 else if ((cur_char >= 0xE0) && (*textLen >= 3)) {
176 unicode = (cur_char & 0x0F) << 12;
177 unicode |= (*txt++ & 0x3F) << 6;
178 unicode |= (*txt++ & 0x3F);
179
180 // 2 bytes UTF-8, Unicode 0x80 to 0x7FF
181 // (0xC0 & 0xC1 are unused and can be used to store something else)
182 }
183 else if ((cur_char >= 0xC2) && (*textLen >= 2)) {
184 unicode = (cur_char & 0x1F) << 6;
185 unicode |= (*txt++ & 0x3F);
186 }
187 else {
188 *is_unicode = false;
189 unicode = cur_char;
190 }
191 *textLen = *textLen - (txt - *text);
192 *text = txt;
193 return unicode;
194}
195
204static uint8_t getCharWidth(const nbgl_font_t *font, uint32_t unicode, bool is_unicode)
205{
206 if (is_unicode) {
207#ifdef HAVE_UNICODE_SUPPORT
208 const nbgl_font_unicode_character_t *unicodeCharacter
209 = nbgl_getUnicodeFontCharacter(unicode);
210 if (!unicodeCharacter) {
211 return 0;
212 }
213 return unicodeCharacter->width - font->char_kerning;
214#else // HAVE_UNICODE_SUPPORT
215 return 0;
216#endif // HAVE_UNICODE_SUPPORT
217 }
218 else {
219 const nbgl_font_character_t *character; // non-unicode char
220 if ((unicode < font->first_char) || (unicode > font->last_char)) {
221 return 0;
222 }
223 character
224 = (const nbgl_font_character_t *) PIC(&font->characters[unicode - font->first_char]);
225 return character->width - font->char_kerning;
226 }
227}
228
239static uint16_t getTextWidth(nbgl_font_id_e fontId,
240 const char *text,
241 bool breakOnLineEnd,
242 uint16_t maxLen)
243{
244#ifdef BUILD_SCREENSHOTS
245 uint16_t nb_lines = 0;
246#endif // BUILD_SCREENSHOTS
247 uint16_t line_width = 0;
248 uint16_t max_width = 0;
249 const nbgl_font_t *font = nbgl_getFont(fontId);
250 uint16_t textLen = MIN(strlen(text), maxLen);
251#ifdef HAVE_UNICODE_SUPPORT
252 nbgl_unicode_ctx_t *unicode_ctx = NULL;
253#endif // HAVE_UNICODE_SUPPORT
254
255#ifdef BUILD_SCREENSHOTS
256 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
257 bool next_bold_state = last_bold_state;
258#endif // BUILD_SCREENSHOTS
259
260 // end loop text len is NULL (max reached)
261 while (textLen) {
262 uint8_t char_width;
263 uint32_t unicode;
264 bool is_unicode;
265
266 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
267#ifdef HAVE_UNICODE_SUPPORT
268 if (is_unicode && !unicode_ctx) {
269 unicode_ctx = nbgl_getUnicodeFont(fontId);
270 }
271#endif
272 if (unicode == '\n') {
273 if (breakOnLineEnd) {
274 break;
275 }
276 // reset line width for next line
277 line_width = 0;
278 continue;
279 }
280 // if \b, switch fontId
281 else if (unicode == '\b') {
282 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
284#ifdef HAVE_UNICODE_SUPPORT
285 unicode_ctx = NULL;
286#endif // HAVE_UNICODE_SUPPORT
287 font = nbgl_getFont(fontId);
288#ifdef BUILD_SCREENSHOTS
289 next_bold_state = true;
290#endif // BUILD_SCREENSHOTS
291 }
292 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
294#ifdef HAVE_UNICODE_SUPPORT
295 unicode_ctx = NULL;
296#endif // HAVE_UNICODE_SUPPORT
297 font = nbgl_getFont(fontId);
298#ifdef BUILD_SCREENSHOTS
299 next_bold_state = false;
300#endif // BUILD_SCREENSHOTS
301 }
302 continue;
303 }
304 char_width = getCharWidth(font, unicode, is_unicode);
305#ifdef BUILD_SCREENSHOTS
306 if (char_width != 0) {
307 // Update last 'displayed' char with current bold status
308 last_bold_state = next_bold_state;
309 }
310#endif // BUILD_SCREENSHOTS
311 line_width += char_width;
312 // memorize max line width if greater than current
313 if (line_width > max_width) {
314 max_width = line_width;
315 }
316 }
317#ifdef BUILD_SCREENSHOTS
318 if (line_width != 0) {
319 ++nb_lines;
320 }
321 last_nb_lines = nb_lines;
322#endif // BUILD_SCREENSHOTS
323
324 return max_width;
325}
326
335{
336 return getTextWidth(fontId, text, true, 0xFFFF);
337}
338
349{
350 return getTextWidth(fontId, text, true, maxLen);
351}
352
361{
362 return getTextWidth(fontId, text, false, 0xFFFF);
363}
364
372uint8_t nbgl_getCharWidth(nbgl_font_id_e fontId, const char *text)
373{
374 const nbgl_font_t *font = nbgl_getFont(fontId);
375 uint32_t unicode;
376 bool is_unicode;
377 uint16_t textLen = 4; // max len for a char
378#ifdef HAVE_UNICODE_SUPPORT
379 nbgl_unicode_ctx_t *unicode_ctx = NULL;
380#endif // HAVE_UNICODE_SUPPORT
381
382 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
383#ifdef HAVE_UNICODE_SUPPORT
384 if (is_unicode && !unicode_ctx) {
385 unicode_ctx = nbgl_getUnicodeFont(fontId);
386 }
387#endif
388
389 return getCharWidth(font, unicode, is_unicode);
390}
391
399{
400 const nbgl_font_t *font = nbgl_getFont(fontId);
401 return font->height;
402}
403
411{
412 const nbgl_font_t *font = nbgl_getFont(fontId);
413 return font->line_height;
414}
415
423{
424 uint16_t nbLines = 1;
425 while (*text) {
426 if (*text == '\n') {
427 nbLines++;
428 }
429 text++;
430 }
431 return nbLines;
432}
433
442{
443 const nbgl_font_t *font = nbgl_getFont(fontId);
444 return (nbgl_getTextNbLines(text) * font->line_height);
445}
446
455{
456 const char *origText = text;
457 while (*text) {
458 if (*text == '\f') {
459 break;
460 }
461 else if (*text == '\n') {
462 break;
463 }
464 text++;
465 }
466 return text - origText;
467}
468
483 const char *text,
484 uint16_t maxWidth,
485 uint16_t *len,
486 uint16_t *width,
487 bool wrapping)
488{
489 const nbgl_font_t *font = nbgl_getFont(fontId);
490 uint16_t textLen = nbgl_getTextLength(text);
491 uint32_t lenAtLastDelimiter = 0, widthAtlastDelimiter = 0;
492#ifdef HAVE_UNICODE_SUPPORT
493 nbgl_unicode_ctx_t *unicode_ctx = NULL;
494#endif // HAVE_UNICODE_SUPPORT
495
496 *width = 0;
497 *len = 0;
498 while (textLen) {
499 uint8_t char_width;
500 uint32_t unicode;
501 bool is_unicode;
502 uint16_t curTextLen = textLen;
503
504 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
505#ifdef HAVE_UNICODE_SUPPORT
506 if (is_unicode && !unicode_ctx) {
507 unicode_ctx = nbgl_getUnicodeFont(fontId);
508 }
509#endif
510 // if \f or \n, exit loop
511 if ((unicode == '\f') || (unicode == '\n')) {
512 *len += curTextLen - textLen;
513 return;
514 }
515 // if \b, switch fontId
516 else if (unicode == '\b') {
517 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
519#ifdef HAVE_UNICODE_SUPPORT
520 unicode_ctx = NULL;
521#endif // HAVE_UNICODE_SUPPORT
522 font = nbgl_getFont(fontId);
523 }
524 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
526#ifdef HAVE_UNICODE_SUPPORT
527 unicode_ctx = NULL;
528#endif // HAVE_UNICODE_SUPPORT
529 font = nbgl_getFont(fontId);
530 }
531 *len += curTextLen - textLen;
532 continue;
533 }
534
535 char_width = getCharWidth(font, unicode, is_unicode);
536 if (char_width == 0) {
537 *len += curTextLen - textLen;
538 continue;
539 }
540
541 // memorize cursors at last found sepator, when wrapping
542 if ((wrapping == true) && IS_WORD_DELIM(unicode)) {
543 lenAtLastDelimiter = *len;
544 widthAtlastDelimiter = *width;
545 }
546 if ((*width + char_width) > maxWidth) {
547 if ((wrapping == true) && (widthAtlastDelimiter > 0)) {
548 *len = lenAtLastDelimiter + 1;
549 *width = widthAtlastDelimiter;
550 }
551 return;
552 }
553 *len += curTextLen - textLen;
554 *width = *width + char_width;
555 }
556}
557
573 const char *text,
574 uint16_t maxWidth,
575 uint16_t maxNbLines,
576 uint16_t *len,
577 bool wrapping)
578{
579 const nbgl_font_t *font = nbgl_getFont(fontId);
580 uint16_t textLen = strlen(text);
581 uint16_t width = 0;
582 const char *lastDelimiter = NULL;
583 uint32_t lenAtLastDelimiter = 0;
584 const char *origText = text;
585 const char *previousText;
586#ifdef HAVE_UNICODE_SUPPORT
587 nbgl_unicode_ctx_t *unicode_ctx = NULL;
588#endif // HAVE_UNICODE_SUPPORT
589
590 while ((textLen) && (maxNbLines > 0)) {
591 uint8_t char_width;
592 uint32_t unicode;
593 bool is_unicode;
594
595 previousText = text;
596 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
597#ifdef HAVE_UNICODE_SUPPORT
598 if (is_unicode && !unicode_ctx) {
599 unicode_ctx = nbgl_getUnicodeFont(fontId);
600 }
601#endif
602 // memorize cursors at last found delimiter
603 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
604 lastDelimiter = text;
605 lenAtLastDelimiter = textLen;
606 }
607
608 // if \n, reset width
609 if (unicode == '\n') {
610 maxNbLines--;
611 // if last line is reached, let's rewind before carriage return
612 if (maxNbLines == 0) {
613 text--;
614 }
615 width = 0;
616 continue;
617 }
618 // if \f, exit
619 else if (unicode == '\f') {
620 maxNbLines = 0;
621 break;
622 }
623 // if \b, switch fontId
624 else if (unicode == '\b') {
625 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
627#ifdef HAVE_UNICODE_SUPPORT
628 unicode_ctx = NULL;
629#endif // HAVE_UNICODE_SUPPORT
630 font = nbgl_getFont(fontId);
631 }
632 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
634#ifdef HAVE_UNICODE_SUPPORT
635 unicode_ctx = NULL;
636#endif // HAVE_UNICODE_SUPPORT
637 font = nbgl_getFont(fontId);
638 }
639 continue;
640 }
641
642 char_width = getCharWidth(font, unicode, is_unicode);
643 if (char_width == 0) {
644 continue;
645 }
646
647 if ((width + char_width) > maxWidth) {
648 if ((wrapping == true) && (lastDelimiter != NULL)) {
649 text = lastDelimiter;
650 lastDelimiter = NULL;
651 textLen = lenAtLastDelimiter;
652 }
653 else {
654 textLen += text - previousText;
655 text = previousText;
656 }
657 width = 0;
658 maxNbLines--;
659 continue;
660 }
661 width += char_width;
662 }
663 *len = text - origText;
664 return (maxNbLines == 0);
665}
666
682 const char *text,
683 uint16_t maxWidth,
684 uint16_t *len,
685 uint16_t *width)
686{
687 const nbgl_font_t *font = nbgl_getFont(fontId);
688 uint16_t textLen = nbgl_getTextLength(text);
689
690 *width = 0;
691 *len = 0;
692 while (textLen) {
693 const nbgl_font_character_t *character;
694 uint8_t char_width;
695 char cur_char;
696
697 textLen--;
698 cur_char = text[textLen];
699 // if \n, exit
700 if (cur_char == '\n') {
701 *len = *len + 1;
702 continue;
703 }
704
705 // skip not printable char
706 if ((cur_char < font->first_char) || (cur_char > font->last_char)) {
707 continue;
708 }
709 character
710 = (const nbgl_font_character_t *) PIC(&font->characters[cur_char - font->first_char]);
711 char_width = character->width;
712
713 if ((*width + char_width) > maxWidth) {
714 return true;
715 }
716 *len = *len + 1;
717 *width = *width + char_width;
718 }
719 return false;
720}
721
732 const char *text,
733 uint16_t maxWidth,
734 bool wrapping)
735{
736 const nbgl_font_t *font = nbgl_getFont(fontId);
737 uint16_t width = 0;
738#ifdef SCREEN_SIZE_NANO
739 uint16_t nbLines = 0;
740#else // SCREEN_SIZE_NANO
741 uint16_t nbLines = 1;
742#endif // SCREEN_SIZE_NANO
743 uint16_t textLen = strlen(text);
744 const char *lastDelimiter = NULL;
745 uint32_t lenAtLastDelimiter = 0;
746 const char *prevText = NULL;
747#ifdef HAVE_UNICODE_SUPPORT
748 nbgl_unicode_ctx_t *unicode_ctx = NULL;
749#endif // HAVE_UNICODE_SUPPORT
750
751#ifdef BUILD_SCREENSHOTS
752 hard_caesura = false;
753 last_nb_lines = 0;
754 last_nb_pages = 1;
755 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
756 bool next_bold_state = last_bold_state;
757#endif // BUILD_SCREENSHOTS
758
759 // end loop when a '\0' is uncountered
760 while (textLen) {
761 uint8_t char_width;
762 uint32_t unicode;
763 bool is_unicode;
764
765 // memorize the last char
766 prevText = text;
767 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
768#ifdef HAVE_UNICODE_SUPPORT
769 if (is_unicode && !unicode_ctx) {
770 unicode_ctx = nbgl_getUnicodeFont(fontId);
771 }
772#endif
773
774 // memorize cursors at last found space
775 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
776 lastDelimiter = prevText;
777 lenAtLastDelimiter = textLen;
778 }
779 // if \f, exit loop
780 if (unicode == '\f') {
781#ifdef BUILD_SCREENSHOTS
782 if (textLen) {
783 ++last_nb_pages;
784 }
785#endif // BUILD_SCREENSHOTS
786 break;
787 }
788 // if \n, increment the number of lines
789 else if (unicode == '\n') {
790 nbLines++;
791#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
792 if (!(nbLines % 4)) {
793 if (textLen) {
794 ++last_nb_pages;
795 }
796 }
797#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
798 width = 0;
799 lastDelimiter = NULL;
800 continue;
801 }
802 // if \b, switch fontId
803 else if (unicode == '\b') {
804 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
806#ifdef HAVE_UNICODE_SUPPORT
807 unicode_ctx = NULL;
808#endif // HAVE_UNICODE_SUPPORT
809 font = nbgl_getFont(fontId);
810#ifdef BUILD_SCREENSHOTS
811 next_bold_state = true;
812#endif // BUILD_SCREENSHOTS
813 }
814 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
816#ifdef HAVE_UNICODE_SUPPORT
817 unicode_ctx = NULL;
818#endif // HAVE_UNICODE_SUPPORT
819 font = nbgl_getFont(fontId);
820#ifdef BUILD_SCREENSHOTS
821 next_bold_state = false;
822#endif // BUILD_SCREENSHOTS
823 }
824 continue;
825 }
826
827 char_width = getCharWidth(font, unicode, is_unicode);
828 if (char_width == 0) {
829 continue;
830 }
831#ifdef BUILD_SCREENSHOTS
832 // Update last 'displayed' char with current bold status
833 last_bold_state = next_bold_state;
834#endif // BUILD_SCREENSHOTS
835
836 // if about to reach max len, increment the number of lines
837 if ((width + char_width) > maxWidth) {
838 if ((wrapping == true) && (lastDelimiter != NULL)) {
839 text = lastDelimiter + 1;
840 lastDelimiter = NULL;
841 textLen = lenAtLastDelimiter;
842 width = 0;
843 }
844 else {
845#ifdef BUILD_SCREENSHOTS
846 // An hyphenation (caesura) has been forced.
847 hard_caesura = true;
848#endif // BUILD_SCREENSHOTS
849 width = char_width;
850 }
851 nbLines++;
852#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
853 if (!(nbLines % 4)) {
854 if (textLen) {
855 ++last_nb_pages;
856 }
857 }
858#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
859 }
860 else {
861 width += char_width;
862 }
863 }
864#ifdef SCREEN_SIZE_NANO
865 if (width != 0) {
866 ++nbLines;
867 }
868#endif // SCREEN_SIZE_NANO
869#ifdef BUILD_SCREENSHOTS
870 last_nb_lines = nbLines;
871#endif // BUILD_SCREENSHOTS
872 return nbLines;
873}
874
886 const char *text,
887 uint8_t nbLinesPerPage,
888 uint16_t maxWidth)
889{
890 const nbgl_font_t *font = nbgl_getFont(fontId);
891 uint16_t width = 0;
892 uint16_t nbLines = 0;
893 uint8_t nbPages = 1;
894 uint16_t textLen = strlen(text);
895 const char *lastDelimiter = NULL;
896 uint32_t lenAtLastDelimiter = 0;
897 const char *prevText = NULL;
898#ifdef HAVE_UNICODE_SUPPORT
899 nbgl_unicode_ctx_t *unicode_ctx = NULL;
900#endif // HAVE_UNICODE_SUPPORT
901
902#ifdef BUILD_SCREENSHOTS
903 last_nb_lines = nbLines;
904 last_nb_pages = nbPages;
905 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
906 bool next_bold_state = last_bold_state;
907#endif // BUILD_SCREENSHOTS
908 // end loop when a '\0' is uncountered
909 while (textLen) {
910 uint8_t char_width;
911 uint32_t unicode;
912 bool is_unicode;
913
914 // memorize the last char
915 prevText = text;
916 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
917#ifdef HAVE_UNICODE_SUPPORT
918 if (is_unicode && !unicode_ctx) {
919 unicode_ctx = nbgl_getUnicodeFont(fontId);
920 }
921#endif
922
923 // memorize cursors at last found space
924 if (IS_WORD_DELIM(unicode)) {
925 lastDelimiter = prevText;
926 lenAtLastDelimiter = textLen;
927 }
928 // if \f, updates page number
929 if (unicode == '\f') {
930 nbPages++;
931#ifdef BUILD_SCREENSHOTS
932#ifdef SCREEN_SIZE_NANO
933 if (width != 0) {
934#endif // SCREEN_SIZE_NANO
935 ++nbLines;
936#ifdef SCREEN_SIZE_NANO
937 }
938#endif // SCREEN_SIZE_NANO
939 if (last_nb_lines < nbLines) {
940 last_nb_lines = nbLines;
941 }
942#endif // BUILD_SCREENSHOTS
943 nbLines = 0;
944 width = 0;
945 continue;
946 }
947 // if \n, increment the number of lines
948 else if (unicode == '\n') {
949 nbLines++;
950#ifdef BUILD_SCREENSHOTS
951 if (last_nb_lines < nbLines) {
952 last_nb_lines = nbLines;
953 }
954#endif // BUILD_SCREENSHOTS
955 if (nbLines == nbLinesPerPage && textLen) {
956 nbPages++;
957 nbLines = 0;
958 }
959
960 width = 0;
961 lastDelimiter = NULL;
962 continue;
963 }
964 // if \b, switch fontId
965 else if (unicode == '\b') {
966 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
968#ifdef HAVE_UNICODE_SUPPORT
969 unicode_ctx = NULL;
970#endif // HAVE_UNICODE_SUPPORT
971 font = nbgl_getFont(fontId);
972#ifdef BUILD_SCREENSHOTS
973 next_bold_state = true;
974#endif // BUILD_SCREENSHOTS
975 }
976 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
978#ifdef HAVE_UNICODE_SUPPORT
979 unicode_ctx = NULL;
980#endif // HAVE_UNICODE_SUPPORT
981 font = nbgl_getFont(fontId);
982#ifdef BUILD_SCREENSHOTS
983 next_bold_state = false;
984#endif // BUILD_SCREENSHOTS
985 }
986 continue;
987 }
988
989 char_width = getCharWidth(font, unicode, is_unicode);
990 if (char_width == 0) {
991 continue;
992 }
993
994#ifdef BUILD_SCREENSHOTS
995 // Update last 'displayed' char with current bold status
996 last_bold_state = next_bold_state;
997#endif // BUILD_SCREENSHOTS
998
999 // if about to reach max len, increment the number of lines/pages
1000 if ((width + char_width) > maxWidth) {
1001 if (lastDelimiter != NULL) {
1002 text = lastDelimiter + 1;
1003 lastDelimiter = NULL;
1004 textLen = lenAtLastDelimiter;
1005 width = 0;
1006 }
1007 else {
1008 width = char_width;
1009 }
1010 nbLines++;
1011#ifdef BUILD_SCREENSHOTS
1012 if (last_nb_lines < nbLines) {
1013 last_nb_lines = nbLines;
1014 }
1015#endif // BUILD_SCREENSHOTS
1016 if (nbLines == nbLinesPerPage) {
1017 nbPages++;
1018 nbLines = 0;
1019 }
1020 }
1021 else {
1022 width += char_width;
1023 }
1024 }
1025#ifdef BUILD_SCREENSHOTS
1026#ifdef SCREEN_SIZE_NANO
1027 if (width != 0) {
1028 ++nbLines;
1029 }
1030#endif // SCREEN_SIZE_NANO
1031 if (last_nb_lines < nbLines) {
1032 last_nb_lines = nbLines;
1033 }
1034 last_nb_pages = nbPages;
1035#endif // BUILD_SCREENSHOTS
1036 return nbPages;
1037}
1038
1049 const char *text,
1050 uint16_t maxWidth,
1051 bool wrapping)
1052{
1053 const nbgl_font_t *font = nbgl_getFont(fontId);
1054 return (nbgl_getTextNbLinesInWidth(fontId, text, maxWidth, wrapping) * font->line_height);
1055}
1056
1068void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char *text, uint16_t maxWidth, uint8_t nbLines)
1069{
1070 const nbgl_font_t *font = nbgl_getFont(fontId);
1071 uint16_t textLen = nbgl_getTextLength(text);
1072 uint16_t width = 0;
1073 uint8_t currentNbLines = 1;
1074 char *lastDelimiter = NULL;
1075 uint32_t lenAtLastDelimiter = 0;
1076 char *prevText[4] = {0}; // queue of last positions
1077 uint16_t prevWidth[2] = {0}; // queue of last widths
1078
1079#ifdef HAVE_UNICODE_SUPPORT
1080 nbgl_unicode_ctx_t *unicode_ctx = NULL;
1081#endif // HAVE_UNICODE_SUPPORT
1082
1083 while (*text) {
1084 uint8_t char_width;
1085 uint32_t unicode;
1086 bool is_unicode;
1087
1088 // memorize the last positions in the queue
1089 // the oldest is at the highest index
1090 prevText[3] = prevText[2];
1091 prevText[2] = prevText[1];
1092 prevText[1] = prevText[0];
1093 prevText[0] = text;
1094 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
1095 // if \n, reset width
1096 if (unicode == '\n') {
1097 width = 0;
1098 currentNbLines++;
1099 lastDelimiter = NULL;
1100 continue;
1101 }
1102#ifdef HAVE_UNICODE_SUPPORT
1103 if (is_unicode && !unicode_ctx) {
1104 unicode_ctx = nbgl_getUnicodeFont(fontId);
1105 }
1106#endif
1107 char_width = getCharWidth(font, unicode, is_unicode);
1108 if (char_width == 0) {
1109 continue;
1110 }
1111
1112 // memorize cursors at last found space
1113 if (IS_WORD_DELIM(unicode)) {
1114 lastDelimiter = prevText[0];
1115 lenAtLastDelimiter = textLen + 1;
1116 }
1117 // if the width is about to overpass maxWidth, do something
1118 if ((width + char_width) > maxWidth) {
1119 // if the max number of lines has not been reached, try to wrap on last space
1120 // encountered
1121 if (currentNbLines < nbLines) {
1122 currentNbLines++;
1123 // replace last found space by a \n
1124 if (lastDelimiter != NULL) {
1125 *lastDelimiter++ = '\n';
1126 text = lastDelimiter;
1127 lastDelimiter = NULL;
1128 textLen = lenAtLastDelimiter - 1;
1129 }
1130 else {
1131 textLen += text - prevText[0];
1132 text = prevText[0];
1133 }
1134 // reset width for next line
1135 width = 0;
1136 continue;
1137 }
1138 else {
1139 uint32_t i;
1140 // replace the 1, 2 or 3 last chars by '...'
1141 // try at first with 1, then with 2, if it fits
1142 for (i = 0; i < 2; i++) {
1143 if ((prevText[i + 1] != NULL)
1144 && ((prevWidth[i] + (3 * getCharWidth(font, '.', false))) <= maxWidth)) {
1145 break;
1146 }
1147 }
1148 // at worth we are sure it works by replacing the 3 last chars (if i ==2)
1149 if (prevText[i + 1] != NULL) {
1150 memcpy(prevText[i + 1], "...", 4);
1151 }
1152 return;
1153 }
1154 }
1155 // memorize the 2 last widths in a queue
1156 prevWidth[1] = prevWidth[0];
1157 prevWidth[0] = width;
1158 width += char_width;
1159 }
1160}
1161
1178 const char *origText,
1179 uint16_t maxWidth,
1180 uint8_t nbLines,
1181 char *reducedText,
1182 uint16_t reducedTextLen)
1183{
1184 const nbgl_font_t *font = nbgl_getFont(fontId);
1185 uint16_t textLen = strlen(origText);
1186 uint16_t width = 0;
1187 uint8_t currentNbLines = 1;
1188 uint32_t i = 0, j = 0;
1189 const uint16_t halfWidth = (maxWidth - nbgl_getTextWidth(fontId, " ... ")) / 2;
1190
1191 if ((nbLines & 0x1) == 0) {
1192 LOG_FATAL(MISC_LOGGER, "nbgl_textReduceOnNbLines: the number of line must be odd\n");
1193 return;
1194 }
1195 while ((i < textLen) && (j < reducedTextLen)) {
1196 uint8_t char_width;
1197 char curChar;
1198
1199 curChar = origText[i];
1200
1201 char_width = getCharWidth(font, curChar, false);
1202 if (char_width == 0) {
1203 reducedText[j] = curChar;
1204 j++;
1205 i++;
1206 continue;
1207 }
1208
1209 // if the width is about to exceed maxWidth, increment number of lines
1210 if ((width + char_width) > maxWidth) {
1211 currentNbLines++;
1212 // reset width for next line
1213 width = 0;
1214 continue;
1215 }
1216 else if ((currentNbLines == ((nbLines / 2) + 1)) && ((width + char_width) > halfWidth)) {
1217 uint32_t halfFullWidth = (nbLines / 2) * maxWidth + halfWidth;
1218 uint32_t countDown = textLen;
1219 // if this if the central line, we have to insert the '...' in the middle of it
1220 reducedText[j - 1] = '.';
1221 reducedText[j] = '.';
1222 reducedText[j + 1] = '.';
1223 // then start from the end
1224 width = 0;
1225 while (width < halfFullWidth) {
1226 countDown--;
1227 curChar = origText[countDown];
1228 char_width = getCharWidth(font, curChar, false);
1229 width += char_width;
1230 }
1231 memcpy(&reducedText[j + 2], &origText[countDown + 1], textLen - countDown + 1);
1232 return;
1233 }
1234 else {
1235 reducedText[j] = curChar;
1236 j++;
1237 i++;
1238 }
1239 width += char_width;
1240 }
1241 reducedText[j] = '\0';
1242}
1243
1244#ifdef HAVE_UNICODE_SUPPORT
1252nbgl_unicode_ctx_t *nbgl_getUnicodeFont(nbgl_font_id_e fontId)
1253{
1254 if ((unicodeCtx.font != NULL) && (unicodeCtx.font->font_id == fontId)) {
1255 return &unicodeCtx;
1256 }
1257#if defined(HAVE_LANGUAGE_PACK)
1258 // Be sure we need to change font
1259 const uint8_t *ptr = (const uint8_t *) language_pack;
1260 const nbgl_font_unicode_t *font = (const void *) (ptr + language_pack->fonts_offset);
1261 unicodeCtx.characters
1262 = (const nbgl_font_unicode_character_t *) (ptr + language_pack->characters_offset);
1263 unicodeCtx.bitmap = (const uint8_t *) (ptr + language_pack->bitmaps_offset);
1264
1265 for (uint32_t i = 0; i < language_pack->nb_fonts; i++) {
1266 if (font->font_id == fontId) {
1267 // Update all other global variables
1268 unicodeCtx.font = font;
1269 return &unicodeCtx;
1270 }
1271 // Compute next Bitmap offset
1272 unicodeCtx.bitmap += font->bitmap_len;
1273
1274 // Update all pointers for next font
1275 unicodeCtx.characters += language_pack->nb_characters;
1276 font++;
1277 }
1278#endif // defined(HAVE_LANGUAGE_PACK)
1279 // id not found
1280 return NULL;
1281}
1282
1292const nbgl_font_unicode_character_t *nbgl_getUnicodeFontCharacter(uint32_t unicode)
1293{
1294#if defined(HAVE_LANGUAGE_PACK)
1295 const nbgl_font_unicode_character_t *characters
1296 = (const nbgl_font_unicode_character_t *) PIC(unicodeCtx.characters);
1297 uint32_t n = language_pack->nb_characters;
1298 if (characters == NULL) {
1299 return NULL;
1300 }
1301 // For the moment, let just parse the full array, but at the end let use
1302 // binary search as data are sorted by unicode value !
1303 for (unsigned i = 0; i < n - 1; i++, characters++) {
1304 if (characters->char_unicode == unicode) {
1305 // Compute & store the number of bytes used to display this character
1307 = (characters + 1)->bitmap_offset - characters->bitmap_offset;
1308 return characters;
1309 }
1310 }
1311 // By default, let's use the last Unicode character, which should be the
1312 // 0x00FFFD one, used to replace unrecognized or unrepresentable character.
1313
1314 // Compute & store the number of bytes used to display this character
1316 = unicodeCtx.font->bitmap_len - characters->bitmap_offset;
1317 return characters;
1318#else // defined(HAVE_LANGUAGE_PACK)
1319 UNUSED(unicode);
1320 // id not found
1321 return NULL;
1322#endif // defined(HAVE_LANGUAGE_PACK)
1323}
1324
1331uint32_t nbgl_getUnicodeFontCharacterByteCount(void)
1332{
1333#ifdef HAVE_LANGUAGE_PACK
1334 return unicodeCtx.unicode_character_byte_count;
1335#else // defined(HAVE_LANGUAGE_PACK)
1336 return 0;
1337#endif // HAVE_LANGUAGE_PACK
1338}
1339
1340#ifdef HAVE_LANGUAGE_PACK
1348void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
1349{
1350 language_pack = lp;
1351 unicodeCtx.font = NULL;
1352 unicodeCtx.characters = NULL;
1353}
1354#endif // HAVE_LANGUAGE_PACK
1355
1356#endif // HAVE_UNICODE_SUPPORT
debug traces management
#define LOG_FATAL(__logger,...)
Definition nbgl_debug.h:88
@ MISC_LOGGER
Definition nbgl_debug.h:39
Middle Level API of the new BOLOS Graphical Library.
void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char *text, uint16_t maxWidth, uint8_t nbLines)
Modifies the given text to wrap it on the given max width (in pixels), in the given nbLines If possib...
void nbgl_getTextMaxLenAndWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t *len, uint16_t *width, bool wrapping)
compute the max width of the first line of the given text fitting in maxWidth
Definition nbgl_fonts.c:482
uint16_t nbgl_getTextNbLines(const char *text)
return the number of lines in the given text, according to the found ' 's
Definition nbgl_fonts.c:422
uint8_t nbgl_getTextNbPagesInWidth(nbgl_font_id_e fontId, const char *text, uint8_t nbLinesPerPage, uint16_t maxWidth)
compute the number of pages of nbLinesPerPage lines per page of the given text fitting in the given m...
Definition nbgl_fonts.c:885
uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
return the max width in pixels of the given text until the first or \0 is encountered
Definition nbgl_fonts.c:334
uint8_t nbgl_getCharWidth(nbgl_font_id_e fontId, const char *text)
return the width in pixels of the given UTF-8 character
Definition nbgl_fonts.c:372
bool nbgl_getTextMaxLenInNbLines(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t maxNbLines, uint16_t *len, bool wrapping)
compute the len of the given text (in bytes) fitting in the given maximum nb lines,...
Definition nbgl_fonts.c:572
bool nbgl_getTextMaxLenAndWidthFromEnd(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t *len, uint16_t *width)
compute the len and width of the given text fitting in the maxWidth, starting from end of text
Definition nbgl_fonts.c:681
#define IS_WORD_DELIM(c)
Definition nbgl_fonts.c:26
#define PIC_FONT(x)
Definition nbgl_fonts.c:23
uint8_t nbgl_getFontHeight(nbgl_font_id_e fontId)
return the height in pixels of the font with the given font ID
Definition nbgl_fonts.c:398
void nbgl_textReduceOnNbLines(nbgl_font_id_e fontId, const char *origText, uint16_t maxWidth, uint8_t nbLines, char *reducedText, uint16_t reducedTextLen)
Create a reduced version of given ASCII text to wrap it on the given max width (in pixels),...
uint32_t nbgl_popUnicodeChar(const uint8_t **text, uint16_t *textLen, bool *is_unicode)
Get the coming unicode value on the given UTF-8 string. If the value is a simple ASCII character,...
Definition nbgl_fonts.c:150
uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
return the max width in pixels of the given text (can be multiline)
Definition nbgl_fonts.c:360
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
return the height of the given multiline text, with the given font.
#define BAGL_FONT_ID_MASK
Definition nbgl_fonts.c:24
uint16_t nbgl_getTextLength(const char *text)
return the number of bytes of the given text, excluding final ' ' or '\0'
Definition nbgl_fonts.c:454
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
compute the number of lines of the given text fitting in the given maxWidth
Definition nbgl_fonts.c:731
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
return the non-unicode font corresponding to the given font ID
Definition nbgl_fonts.c:136
uint16_t nbgl_getTextHeight(nbgl_font_id_e fontId, const char *text)
return the height of the given multiline text, with the given font.
Definition nbgl_fonts.c:441
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
return the height in pixels of the line of font with the given font ID
Definition nbgl_fonts.c:410
uint16_t nbgl_getSingleLineTextWidthInLen(nbgl_font_id_e fontId, const char *text, uint16_t maxLen)
return the max width in pixels of the given text until the first or \0 is encountered,...
Definition nbgl_fonts.c:348
const nbgl_font_t * nbgl_font_getFont(unsigned int fontId)
nbgl_font_id_e
Definition nbgl_fonts.h:140
@ BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
Definition nbgl_fonts.h:149
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition nbgl_fonts.h:147
#define LANGUAGE_PACK
Definition nbgl_fonts.h:29
#define MIN(x, y)
Definition nbgl_types.h:82
fonts nicknames to be used for various wallet size targets (non-Nano)
Definition nbgl_fonts.h:66
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:69
structure defining an ASCII font
Definition nbgl_fonts.h:80
uint8_t char_kerning
kerning for the font
Definition nbgl_fonts.h:86
uint8_t first_char
ASCII code of the first character in bitmap and in characters fields.
Definition nbgl_fonts.h:90
const nbgl_font_character_t *const characters
array containing definitions of all characters
Definition nbgl_fonts.h:94
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:84
uint8_t line_height
height of a line for all characters in pixels
Definition nbgl_fonts.h:85
uint8_t last_char
ASCII code of the last character in bitmap and in characters fields.
Definition nbgl_fonts.h:92
structure defining a unicode character (except the bitmap)
Definition nbgl_fonts.h:108
uint32_t char_unicode
plane value from 0 to 16 then 16-bit code.
Definition nbgl_fonts.h:109
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:111
uint32_t bitmap_offset
offset of this character in chars buffer
Definition nbgl_fonts.h:116
structure defining a unicode font
Definition nbgl_fonts.h:122
uint16_t bitmap_len
Size in bytes of all characters bitmaps.
Definition nbgl_fonts.h:123
uint8_t font_id
ID of the font, from nbgl_font_id_e.
Definition nbgl_fonts.h:124
const nbgl_font_unicode_character_t * characters
Definition nbgl_fonts.h:161
const nbgl_font_unicode_t * font
Definition nbgl_fonts.h:160
uint32_t unicode_character_byte_count
Definition nbgl_fonts.h:163
const uint8_t * bitmap
Definition nbgl_fonts.h:162
unsigned short uint16_t
Definition usbd_conf.h:54
unsigned char uint8_t
Definition usbd_conf.h:53