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#include "os_task.h"
17#include "ux_loc.h"
18
19/*********************
20 * DEFINES
21 *********************/
22#define PIC_FONT(x) ((nbgl_font_t const *) PIC(x))
23#define BAGL_FONT_ID_MASK 0x0FFF
24
25#define IS_WORD_DELIM(c) (c == ' ' || c == '\n' || c == '\b' || c == '\f' || c == '-' || c == '_')
26
27/**********************
28 * TYPEDEFS
29 **********************/
30
31/**********************
32 * STATIC VARIABLES
33 **********************/
34static nbgl_unicode_ctx_t unicodeCtx = {0};
35
36/**********************
37 * VARIABLES
38 **********************/
39
40static const LANGUAGE_PACK *language_pack;
41
42#if SMALL_FONT_HEIGHT == 24
43#include "nbgl_font_inter_regular_24.inc"
44#include "nbgl_font_inter_semibold_24.inc"
45#include "nbgl_font_inter_medium_32.inc"
46#include "nbgl_font_inter_regular_24_1bpp.inc"
47#include "nbgl_font_inter_semibold_24_1bpp.inc"
48#include "nbgl_font_inter_medium_32_1bpp.inc"
49#elif SMALL_FONT_HEIGHT == 28
50#include "nbgl_font_inter_regular_28.inc"
51#include "nbgl_font_inter_semibold_28.inc"
52#include "nbgl_font_inter_medium_36.inc"
53#include "nbgl_font_inter_regular_28_1bpp.inc"
54#include "nbgl_font_inter_semibold_28_1bpp.inc"
55#include "nbgl_font_inter_medium_36_1bpp.inc"
56#elif SMALL_FONT_HEIGHT == 18
57#include "nbgl_font_nanotext_medium_18_1bpp.inc"
58#include "nbgl_font_nanotext_bold_18_1bpp.inc"
59#include "nbgl_font_nanodisplay_semibold_24_1bpp.inc"
60#elif SMALL_FONT_HEIGHT == 11
61#include "nbgl_font_open_sans_extrabold_11.inc"
62#include "nbgl_font_open_sans_regular_11.inc"
63#include "nbgl_font_open_sans_light_16.inc"
64#endif // SMALL_FONT_HEIGHT
65
66__attribute__((section("._nbgl_fonts_"))) const nbgl_font_t *const C_nbgl_fonts[] = {
67
68#include "nbgl_font_rom_struct.inc"
69
70};
71__attribute__((section("._nbgl_fonts_"))) const unsigned int C_nbgl_fonts_count
72 = sizeof(C_nbgl_fonts) / sizeof(C_nbgl_fonts[0]);
73
74#if (defined(HAVE_BOLOS) && !defined(BOLOS_OS_UPGRADER_APP))
75#endif // HAVE_BOLOS
76
77#ifdef BUILD_SCREENSHOTS
78// Variables used to store important values (nb lines, bold state etc)
79uint16_t last_nb_lines = 0;
80uint16_t last_nb_pages = 0;
81bool last_bold_state = false;
82
83// Used to detect when a hyphenation (caesura) has been forced.
84bool hard_caesura = false;
85#endif // BUILD_SCREENSHOTS
86
87/**********************
88 * STATIC PROTOTYPES
89 **********************/
90
91/**********************
92 * GLOBAL FUNCTIONS
93 **********************/
94
102{
103 unsigned int i = C_nbgl_fonts_count;
104 fontId &= BAGL_FONT_ID_MASK;
105
106 while (i--) {
107 // font id match this entry (non indexed array)
108 if (PIC_FONT(C_nbgl_fonts[i])->font_id == fontId) {
109 return PIC_FONT(C_nbgl_fonts[i]);
110 }
111 }
112
113 // id not found
114 return NULL;
115}
116
126uint32_t nbgl_popUnicodeChar(const uint8_t **text, uint16_t *textLen, bool *is_unicode)
127{
128 // Be sure there are still some characters to read;
129 if (!*textLen) {
130 return 0;
131 }
132 const uint8_t *txt = *text;
133 uint8_t cur_char = *txt++;
134 uint32_t unicode;
135
136 *is_unicode = true;
137 // Handle UTF-8 decoding (RFC3629): (https://www.ietf.org/rfc/rfc3629.txt
138 // Char. number range | UTF-8 octet sequence
139 // (hexadecimal) | (binary)
140 // --------------------+---------------------------------------------
141 // 0000 0000-0000 007F | 0xxxxxxx
142 // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
143 // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
144 // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
145
146 // 4 bytes UTF-8, Unicode 0x1000 to 0x1FFFF
147 if ((cur_char >= 0xF0) && (*textLen >= 4)) {
148 unicode = (cur_char & 0x07) << 18;
149 unicode |= (*txt++ & 0x3F) << 12;
150 unicode |= (*txt++ & 0x3F) << 6;
151 unicode |= (*txt++ & 0x3F);
152
153 // 3 bytes, from 0x800 to 0xFFFF
154 }
155 else if ((cur_char >= 0xE0) && (*textLen >= 3)) {
156 unicode = (cur_char & 0x0F) << 12;
157 unicode |= (*txt++ & 0x3F) << 6;
158 unicode |= (*txt++ & 0x3F);
159
160 // 2 bytes UTF-8, Unicode 0x80 to 0x7FF
161 // (0xC0 & 0xC1 are unused and can be used to store something else)
162 }
163 else if ((cur_char >= 0xC2) && (*textLen >= 2)) {
164 unicode = (cur_char & 0x1F) << 6;
165 unicode |= (*txt++ & 0x3F);
166 }
167 else {
168 *is_unicode = false;
169 unicode = cur_char;
170 }
171 *textLen = *textLen - (txt - *text);
172 *text = txt;
173 return unicode;
174}
175
184static uint8_t getCharWidth(const nbgl_font_t *font, uint32_t unicode, bool is_unicode)
185{
186 if (is_unicode) {
187 const nbgl_font_unicode_character_t *unicodeCharacter
189 if (!unicodeCharacter) {
190 return 0;
191 }
192 // Don't take in account width of combined characters displayed over previous ones
193#ifdef SCREEN_SIZE_WALLET
194 if (unicodeCharacter->over_previous) {
195 return 0;
196 }
197#endif // SCREEN_SIZE_WALLET
198 return unicodeCharacter->width - font->char_kerning;
199 }
200 else {
201 const nbgl_font_character_t *character; // non-unicode char
202 if ((unicode < font->first_char) || (unicode > font->last_char)) {
203 return 0;
204 }
205 character
206 = (const nbgl_font_character_t *) PIC(&font->characters[unicode - font->first_char]);
207 return character->width - font->char_kerning;
208 }
209}
210
221static uint16_t getTextWidth(nbgl_font_id_e fontId,
222 const char *text,
223 bool breakOnLineEnd,
224 uint16_t maxLen)
225{
226#ifdef BUILD_SCREENSHOTS
227 uint16_t nb_lines = 0;
228#endif // BUILD_SCREENSHOTS
229 uint16_t line_width = 0;
230 uint16_t max_width = 0;
231 const nbgl_font_t *font = nbgl_getFont(fontId);
232 uint16_t textLen = MIN(strlen(text), maxLen);
233 nbgl_unicode_ctx_t *unicode_ctx = NULL;
234
235#ifdef BUILD_SCREENSHOTS
236 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
237 bool next_bold_state = last_bold_state;
238#endif // BUILD_SCREENSHOTS
239
240 // end loop text len is NULL (max reached)
241 while (textLen) {
242 uint8_t char_width;
243 uint32_t unicode;
244 bool is_unicode;
245
246 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
247 // Do we still have some characters to read?
248 if (!unicode) {
249 break;
250 }
251 if (is_unicode && !unicode_ctx) {
252 unicode_ctx = nbgl_getUnicodeFont(fontId);
253 }
254 if (unicode == '\n') {
255 if (breakOnLineEnd) {
256 break;
257 }
258 // reset line width for next line
259 line_width = 0;
260 continue;
261 }
262 // if \b, switch fontId
263 else if (unicode == '\b') {
264 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
266 unicode_ctx = NULL;
267 font = nbgl_getFont(fontId);
268#ifdef BUILD_SCREENSHOTS
269 next_bold_state = true;
270#endif // BUILD_SCREENSHOTS
271 }
272 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
274 unicode_ctx = NULL;
275 font = nbgl_getFont(fontId);
276#ifdef BUILD_SCREENSHOTS
277 next_bold_state = false;
278#endif // BUILD_SCREENSHOTS
279 }
280 continue;
281 }
282 char_width = getCharWidth(font, unicode, is_unicode);
283#ifdef BUILD_SCREENSHOTS
284 if (char_width != 0) {
285 // Update last 'displayed' char with current bold status
286 last_bold_state = next_bold_state;
287 }
288#endif // BUILD_SCREENSHOTS
289 line_width += char_width;
290 // memorize max line width if greater than current
291 if (line_width > max_width) {
292 max_width = line_width;
293 }
294 }
295#ifdef BUILD_SCREENSHOTS
296 if (line_width != 0) {
297 ++nb_lines;
298 }
299 last_nb_lines = nb_lines;
300#endif // BUILD_SCREENSHOTS
301
302 return max_width;
303}
304
312uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
313{
314 return getTextWidth(fontId, text, true, 0xFFFF);
315}
316
326uint16_t nbgl_getSingleLineTextWidthInLen(nbgl_font_id_e fontId, const char *text, uint16_t maxLen)
327{
328 return getTextWidth(fontId, text, true, maxLen);
329}
330
338uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
339{
340 return getTextWidth(fontId, text, false, 0xFFFF);
341}
342
350uint8_t nbgl_getCharWidth(nbgl_font_id_e fontId, const char *text)
351{
352 const nbgl_font_t *font = nbgl_getFont(fontId);
353 uint32_t unicode;
354 bool is_unicode;
355 uint16_t textLen = 4; // max len for a char
356 nbgl_unicode_ctx_t *unicode_ctx = NULL;
357
358 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
359 if (is_unicode && !unicode_ctx) {
360 unicode_ctx = nbgl_getUnicodeFont(fontId);
361 }
362
363 return getCharWidth(font, unicode, is_unicode);
364}
365
373{
374 // Unicode combined fonts can be higher than normal ones, due to supperposition of 'accents'
375 nbgl_unicode_ctx_t *unicode_ctx = nbgl_getUnicodeFont(fontId);
376 if (unicode_ctx) {
377 return unicode_ctx->font->height;
378 }
379 else {
380 const nbgl_font_t *font = nbgl_getFont(fontId);
381 return font->height;
382 }
383}
384
392{
393 // Unicode combined fonts can be higher than normal ones, due to supperposition of 'accents'
394 nbgl_unicode_ctx_t *unicode_ctx = nbgl_getUnicodeFont(fontId);
395 if (unicode_ctx) {
396 return unicode_ctx->font->line_height;
397 }
398 else {
399 const nbgl_font_t *font = nbgl_getFont(fontId);
400 return font->line_height;
401 }
402}
403
410uint16_t nbgl_getTextNbLines(const char *text)
411{
412 uint16_t nbLines = 1;
413 while (*text) {
414 if (*text == '\n') {
415 nbLines++;
416 }
417 text++;
418 }
419 return nbLines;
420}
421
429uint16_t nbgl_getTextHeight(nbgl_font_id_e fontId, const char *text)
430{
431 const nbgl_font_t *font = nbgl_getFont(fontId);
432 return (nbgl_getTextNbLines(text) * font->line_height);
433}
434
442uint16_t nbgl_getTextLength(const char *text)
443{
444 const char *origText = text;
445 while (*text) {
446 if (*text == '\f') {
447 break;
448 }
449 else if (*text == '\n') {
450 break;
451 }
452 text++;
453 }
454 return text - origText;
455}
456
471 const char *text,
472 uint16_t maxWidth,
473 uint16_t *len,
474 uint16_t *width,
475 bool wrapping)
476{
477 const nbgl_font_t *font = nbgl_getFont(fontId);
478 uint16_t textLen = nbgl_getTextLength(text);
479 uint32_t lenAtLastDelimiter = 0, widthAtlastDelimiter = 0;
480 nbgl_unicode_ctx_t *unicode_ctx = NULL;
481
482 *width = 0;
483 *len = 0;
484 while (textLen) {
485 uint8_t char_width;
486 uint32_t unicode;
487 bool is_unicode;
488 uint16_t curTextLen = textLen;
489
490 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
491 if (is_unicode && !unicode_ctx) {
492 unicode_ctx = nbgl_getUnicodeFont(fontId);
493 }
494 // if EOS or \f or \n, exit loop
495 if (!unicode || (unicode == '\f') || (unicode == '\n')) {
496 *len += curTextLen - textLen;
497 return;
498 }
499 // if \b, switch fontId
500 else if (unicode == '\b') {
501 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
503 unicode_ctx = NULL;
504 font = nbgl_getFont(fontId);
505 }
506 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
508 unicode_ctx = NULL;
509 font = nbgl_getFont(fontId);
510 }
511 *len += curTextLen - textLen;
512 continue;
513 }
514
515 char_width = getCharWidth(font, unicode, is_unicode);
516 if (char_width == 0) {
517 *len += curTextLen - textLen;
518 continue;
519 }
520
521 // memorize cursors at last found sepator, when wrapping
522 if ((wrapping == true) && IS_WORD_DELIM(unicode)) {
523 lenAtLastDelimiter = *len;
524 widthAtlastDelimiter = *width;
525 }
526 if ((*width + char_width) > maxWidth) {
527 if ((wrapping == true) && (widthAtlastDelimiter > 0)) {
528 *len = lenAtLastDelimiter + 1;
529 *width = widthAtlastDelimiter;
530 }
531 return;
532 }
533 *len += curTextLen - textLen;
534 *width = *width + char_width;
535 }
536}
537
553 const char *text,
554 uint16_t maxWidth,
555 uint16_t maxNbLines,
556 uint16_t *len,
557 bool wrapping)
558{
559 const nbgl_font_t *font = nbgl_getFont(fontId);
560 uint16_t textLen = strlen(text);
561 uint16_t width = 0;
562 const char *lastDelimiter = NULL;
563 uint32_t lenAtLastDelimiter = 0;
564 const char *origText = text;
565 const char *previousText;
566 nbgl_unicode_ctx_t *unicode_ctx = NULL;
567
568 while ((textLen) && (maxNbLines > 0)) {
569 uint8_t char_width;
570 uint32_t unicode;
571 bool is_unicode;
572
573 previousText = text;
574 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
575 if (is_unicode && !unicode_ctx) {
576 unicode_ctx = nbgl_getUnicodeFont(fontId);
577 }
578 // memorize cursors at last found delimiter
579 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
580 lastDelimiter = text;
581 lenAtLastDelimiter = textLen;
582 }
583
584 // if \n, reset width
585 if (unicode == '\n') {
586 maxNbLines--;
587 // if last line is reached, let's rewind before carriage return
588 if (maxNbLines == 0) {
589 text--;
590 }
591 lastDelimiter = NULL;
592 width = 0;
593 continue;
594 }
595 // if \f, exit
596 else if (unicode == '\f') {
597 maxNbLines = 0;
598 break;
599 }
600 // if \b, switch fontId
601 else if (unicode == '\b') {
602 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
604 unicode_ctx = NULL;
605 font = nbgl_getFont(fontId);
606 }
607 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
609 unicode_ctx = NULL;
610 font = nbgl_getFont(fontId);
611 }
612 continue;
613 }
614
615 char_width = getCharWidth(font, unicode, is_unicode);
616 if (char_width == 0) {
617 continue;
618 }
619
620 if ((width + char_width) > maxWidth) {
621 if ((wrapping == true) && (lastDelimiter != NULL)) {
622 text = lastDelimiter;
623 lastDelimiter = NULL;
624 textLen = lenAtLastDelimiter;
625 }
626 else {
627 textLen += text - previousText;
628 text = previousText;
629 }
630 width = 0;
631 maxNbLines--;
632 continue;
633 }
634 width += char_width;
635 }
636 *len = text - origText;
637 return (maxNbLines == 0);
638}
639
655 const char *text,
656 uint16_t maxWidth,
657 uint16_t *len,
658 uint16_t *width)
659{
660 const nbgl_font_t *font = nbgl_getFont(fontId);
661 uint16_t textLen = nbgl_getTextLength(text);
662
663 *width = 0;
664 *len = 0;
665 while (textLen) {
666 const nbgl_font_character_t *character;
667 uint8_t char_width;
668 char cur_char;
669
670 textLen--;
671 cur_char = text[textLen];
672 // if \n, exit
673 if (cur_char == '\n') {
674 *len = *len + 1;
675 continue;
676 }
677
678 // skip not printable char
679 if ((cur_char < font->first_char) || (cur_char > font->last_char)) {
680 continue;
681 }
682 character
683 = (const nbgl_font_character_t *) PIC(&font->characters[cur_char - font->first_char]);
684 char_width = character->width;
685
686 if ((*width + char_width) > maxWidth) {
687 return true;
688 }
689 *len = *len + 1;
690 *width = *width + char_width;
691 }
692 return false;
693}
694
705 const char *text,
706 uint16_t maxWidth,
707 bool wrapping)
708{
709 const nbgl_font_t *font = nbgl_getFont(fontId);
710 uint16_t width = 0;
711#ifdef SCREEN_SIZE_NANO
712 uint16_t nbLines = 0;
713#else // SCREEN_SIZE_NANO
714 uint16_t nbLines = 1;
715#endif // SCREEN_SIZE_NANO
716 uint16_t textLen = strlen(text);
717 const char *lastDelimiter = NULL;
718 uint32_t lenAtLastDelimiter = 0;
719 const char *prevText = NULL;
720 nbgl_unicode_ctx_t *unicode_ctx = NULL;
721
722#ifdef BUILD_SCREENSHOTS
723 hard_caesura = false;
724 last_nb_lines = 0;
725 last_nb_pages = 1;
726 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
727 bool next_bold_state = last_bold_state;
728#endif // BUILD_SCREENSHOTS
729
730 // end loop when a '\0' is uncountered
731 while (textLen) {
732 uint8_t char_width;
733 uint32_t unicode;
734 bool is_unicode;
735
736 // memorize the last char
737 prevText = text;
738 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
739 if (is_unicode && !unicode_ctx) {
740 unicode_ctx = nbgl_getUnicodeFont(fontId);
741 }
742
743 // memorize cursors at last found space
744 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
745 lastDelimiter = prevText;
746 lenAtLastDelimiter = textLen;
747 }
748 // if \f, exit loop
749 if (unicode == '\f') {
750#ifdef BUILD_SCREENSHOTS
751 if (textLen) {
752 ++last_nb_pages;
753 }
754#endif // BUILD_SCREENSHOTS
755 break;
756 }
757 // if \n, increment the number of lines
758 else if (unicode == '\n') {
759 nbLines++;
760#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
761 if (!(nbLines % 4)) {
762 if (textLen) {
763 ++last_nb_pages;
764 }
765 }
766#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
767 width = 0;
768 lastDelimiter = NULL;
769 continue;
770 }
771 // if \b, switch fontId
772 else if (unicode == '\b') {
773 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
775 unicode_ctx = NULL;
776 font = nbgl_getFont(fontId);
777#ifdef BUILD_SCREENSHOTS
778 next_bold_state = true;
779#endif // BUILD_SCREENSHOTS
780 }
781 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
783 unicode_ctx = NULL;
784 font = nbgl_getFont(fontId);
785#ifdef BUILD_SCREENSHOTS
786 next_bold_state = false;
787#endif // BUILD_SCREENSHOTS
788 }
789 continue;
790 }
791
792 char_width = getCharWidth(font, unicode, is_unicode);
793 if (char_width == 0) {
794 continue;
795 }
796#ifdef BUILD_SCREENSHOTS
797 // Update last 'displayed' char with current bold status
798 last_bold_state = next_bold_state;
799#endif // BUILD_SCREENSHOTS
800
801 // if about to reach max len, increment the number of lines
802 if ((width + char_width) > maxWidth) {
803 if ((wrapping == true) && (lastDelimiter != NULL)) {
804 text = lastDelimiter + 1;
805 lastDelimiter = NULL;
806 textLen = lenAtLastDelimiter;
807 width = 0;
808 }
809 else {
810#ifdef BUILD_SCREENSHOTS
811 // An hyphenation (caesura) has been forced.
812 hard_caesura = true;
813#endif // BUILD_SCREENSHOTS
814 width = char_width;
815 }
816 nbLines++;
817#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
818 if (!(nbLines % 4)) {
819 if (textLen) {
820 ++last_nb_pages;
821 }
822 }
823#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
824 }
825 else {
826 width += char_width;
827 }
828 }
829#ifdef SCREEN_SIZE_NANO
830 if (width != 0) {
831 ++nbLines;
832 }
833#endif // SCREEN_SIZE_NANO
834#ifdef BUILD_SCREENSHOTS
835 last_nb_lines = nbLines;
836#endif // BUILD_SCREENSHOTS
837 return nbLines;
838}
839
851 const char *text,
852 uint8_t nbLinesPerPage,
853 uint16_t maxWidth)
854{
855 const nbgl_font_t *font = nbgl_getFont(fontId);
856 uint16_t width = 0;
857 uint16_t nbLines = 0;
858 uint8_t nbPages = 1;
859 uint16_t textLen = strlen(text);
860 const char *lastDelimiter = NULL;
861 uint32_t lenAtLastDelimiter = 0;
862 const char *prevText = NULL;
863 nbgl_unicode_ctx_t *unicode_ctx = NULL;
864
865#ifdef BUILD_SCREENSHOTS
866 last_nb_lines = nbLines;
867 last_nb_pages = nbPages;
868 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
869 bool next_bold_state = last_bold_state;
870#endif // BUILD_SCREENSHOTS
871 // end loop when a '\0' is uncountered
872 while (textLen) {
873 uint8_t char_width;
874 uint32_t unicode;
875 bool is_unicode;
876
877 // memorize the last char
878 prevText = text;
879 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
880 if (is_unicode && !unicode_ctx) {
881 unicode_ctx = nbgl_getUnicodeFont(fontId);
882 }
883
884 // memorize cursors at last found space
885 if (IS_WORD_DELIM(unicode)) {
886 lastDelimiter = prevText;
887 lenAtLastDelimiter = textLen;
888 }
889 // if \f, updates page number
890 if (unicode == '\f') {
891 nbPages++;
892#ifdef BUILD_SCREENSHOTS
893#ifdef SCREEN_SIZE_NANO
894 if (width != 0) {
895#endif // SCREEN_SIZE_NANO
896 ++nbLines;
897#ifdef SCREEN_SIZE_NANO
898 }
899#endif // SCREEN_SIZE_NANO
900 if (last_nb_lines < nbLines) {
901 last_nb_lines = nbLines;
902 }
903#endif // BUILD_SCREENSHOTS
904 nbLines = 0;
905 width = 0;
906 continue;
907 }
908 // if \n, increment the number of lines
909 else if (unicode == '\n') {
910 nbLines++;
911#ifdef BUILD_SCREENSHOTS
912 if (last_nb_lines < nbLines) {
913 last_nb_lines = nbLines;
914 }
915#endif // BUILD_SCREENSHOTS
916 if (nbLines == nbLinesPerPage && textLen) {
917 nbPages++;
918 nbLines = 0;
919 }
920
921 width = 0;
922 lastDelimiter = NULL;
923 continue;
924 }
925 // if \b, switch fontId
926 else if (unicode == '\b') {
927 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
929 unicode_ctx = NULL;
930 font = nbgl_getFont(fontId);
931#ifdef BUILD_SCREENSHOTS
932 next_bold_state = true;
933#endif // BUILD_SCREENSHOTS
934 }
935 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
937 unicode_ctx = NULL;
938 font = nbgl_getFont(fontId);
939#ifdef BUILD_SCREENSHOTS
940 next_bold_state = false;
941#endif // BUILD_SCREENSHOTS
942 }
943 continue;
944 }
945
946 char_width = getCharWidth(font, unicode, is_unicode);
947 if (char_width == 0) {
948 continue;
949 }
950
951#ifdef BUILD_SCREENSHOTS
952 // Update last 'displayed' char with current bold status
953 last_bold_state = next_bold_state;
954#endif // BUILD_SCREENSHOTS
955
956 // if about to reach max len, increment the number of lines/pages
957 if ((width + char_width) > maxWidth) {
958 if (lastDelimiter != NULL) {
959 text = lastDelimiter + 1;
960 lastDelimiter = NULL;
961 textLen = lenAtLastDelimiter;
962 width = 0;
963 }
964 else {
965 width = char_width;
966 }
967 nbLines++;
968#ifdef BUILD_SCREENSHOTS
969 if (last_nb_lines < nbLines) {
970 last_nb_lines = nbLines;
971 }
972#endif // BUILD_SCREENSHOTS
973 if (nbLines == nbLinesPerPage) {
974 nbPages++;
975 nbLines = 0;
976 }
977 }
978 else {
979 width += char_width;
980 }
981 }
982#ifdef BUILD_SCREENSHOTS
983#ifdef SCREEN_SIZE_NANO
984 if (width != 0) {
985 ++nbLines;
986 }
987#endif // SCREEN_SIZE_NANO
988 if (last_nb_lines < nbLines) {
989 last_nb_lines = nbLines;
990 }
991 last_nb_pages = nbPages;
992#endif // BUILD_SCREENSHOTS
993 return nbPages;
994}
995
1006 const char *text,
1007 uint16_t maxWidth,
1008 bool wrapping)
1009{
1010 const nbgl_font_t *font = nbgl_getFont(fontId);
1011 return (nbgl_getTextNbLinesInWidth(fontId, text, maxWidth, wrapping) * font->line_height);
1012}
1013
1025void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char *text, uint16_t maxWidth, uint8_t nbLines)
1026{
1027 const nbgl_font_t *font = nbgl_getFont(fontId);
1028 uint16_t textLen = nbgl_getTextLength(text);
1029 uint16_t width = 0;
1030 uint8_t currentNbLines = 1;
1031 char *lastDelimiter = NULL;
1032 uint32_t lenAtLastDelimiter = 0;
1033 char *prevText[4] = {0}; // queue of last positions
1034 uint16_t prevWidth[2] = {0}; // queue of last widths
1035 nbgl_unicode_ctx_t *unicode_ctx = NULL;
1036
1037 while (*text) {
1038 uint8_t char_width;
1039 uint32_t unicode;
1040 bool is_unicode;
1041
1042 // memorize the last positions in the queue
1043 // the oldest is at the highest index
1044 prevText[3] = prevText[2];
1045 prevText[2] = prevText[1];
1046 prevText[1] = prevText[0];
1047 prevText[0] = text;
1048 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
1049 // if \n, reset width
1050 if (unicode == '\n') {
1051 width = 0;
1052 currentNbLines++;
1053 lastDelimiter = NULL;
1054 continue;
1055 }
1056 if (is_unicode && !unicode_ctx) {
1057 unicode_ctx = nbgl_getUnicodeFont(fontId);
1058 }
1059 char_width = getCharWidth(font, unicode, is_unicode);
1060 if (char_width == 0) {
1061 continue;
1062 }
1063
1064 // memorize cursors at last found space
1065 if (IS_WORD_DELIM(unicode)) {
1066 lastDelimiter = prevText[0];
1067 lenAtLastDelimiter = textLen + 1;
1068 }
1069 // if the width is about to overpass maxWidth, do something
1070 if ((width + char_width) > maxWidth) {
1071 // if the max number of lines has not been reached, try to wrap on last space
1072 // encountered
1073 if (currentNbLines < nbLines) {
1074 currentNbLines++;
1075 // replace last found space by a \n
1076 if (lastDelimiter != NULL) {
1077 *lastDelimiter++ = '\n';
1078 text = lastDelimiter;
1079 lastDelimiter = NULL;
1080 textLen = lenAtLastDelimiter - 1;
1081 }
1082 else {
1083 textLen += text - prevText[0];
1084 text = prevText[0];
1085 }
1086 // reset width for next line
1087 width = 0;
1088 continue;
1089 }
1090 else {
1091 uint32_t i;
1092 // replace the 1, 2 or 3 last chars by '...'
1093 // try at first with 1, then with 2, if it fits
1094 for (i = 0; i < 2; i++) {
1095 if ((prevText[i + 1] != NULL)
1096 && ((prevWidth[i] + (3 * getCharWidth(font, '.', false))) <= maxWidth)) {
1097 break;
1098 }
1099 }
1100 // at worth we are sure it works by replacing the 3 last chars (if i ==2)
1101 if (prevText[i + 1] != NULL) {
1102 memcpy(prevText[i + 1], "...", 4);
1103 }
1104 return;
1105 }
1106 }
1107 // memorize the 2 last widths in a queue
1108 prevWidth[1] = prevWidth[0];
1109 prevWidth[0] = width;
1110 width += char_width;
1111 }
1112}
1113
1130 const char *origText,
1131 uint16_t maxWidth,
1132 uint8_t nbLines,
1133 char *reducedText,
1134 uint16_t reducedTextLen)
1135{
1136 const nbgl_font_t *font = nbgl_getFont(fontId);
1137 uint16_t textLen = strlen(origText);
1138 uint16_t width = 0;
1139 uint8_t currentNbLines = 1;
1140 uint32_t i = 0, j = 0;
1141 const uint16_t halfWidth = (maxWidth - nbgl_getTextWidth(fontId, " ... ")) / 2;
1142
1143 if ((nbLines & 0x1) == 0) {
1144 LOG_FATAL(MISC_LOGGER, "nbgl_textReduceOnNbLines: the number of line must be odd\n");
1145 return;
1146 }
1147 while ((i < textLen) && (j < reducedTextLen)) {
1148 uint8_t char_width;
1149 char curChar;
1150
1151 curChar = origText[i];
1152
1153 char_width = getCharWidth(font, curChar, false);
1154 if (char_width == 0) {
1155 reducedText[j] = curChar;
1156 j++;
1157 i++;
1158 continue;
1159 }
1160
1161 // if the width is about to exceed maxWidth, increment number of lines
1162 if ((width + char_width) > maxWidth) {
1163 currentNbLines++;
1164 // reset width for next line
1165 width = 0;
1166 continue;
1167 }
1168 else if ((currentNbLines == ((nbLines / 2) + 1)) && ((width + char_width) > halfWidth)) {
1169 uint32_t halfFullWidth = (nbLines / 2) * maxWidth + halfWidth;
1170 uint32_t countDown = textLen;
1171 // if this if the central line, we have to insert the '...' in the middle of it
1172 reducedText[j - 1] = '.';
1173 reducedText[j] = '.';
1174 reducedText[j + 1] = '.';
1175 // then start from the end
1176 width = 0;
1177 while (width < halfFullWidth) {
1178 countDown--;
1179 curChar = origText[countDown];
1180 char_width = getCharWidth(font, curChar, false);
1181 width += char_width;
1182 }
1183 memcpy(&reducedText[j + 2], &origText[countDown + 1], textLen - countDown + 1);
1184 return;
1185 }
1186 else {
1187 reducedText[j] = curChar;
1188 j++;
1189 i++;
1190 }
1191 width += char_width;
1192 }
1193 reducedText[j] = '\0';
1194}
1195
1204{
1205 // if in Apps, do not support unicode
1206 if (os_sched_current_task() != TASK_BOLOS_UX) {
1207 return NULL;
1208 }
1209 if ((unicodeCtx.font != NULL) && (unicodeCtx.font->font_id == fontId)) {
1210 return &unicodeCtx;
1211 }
1212 // Be sure we need to change font
1213 const uint8_t *ptr = (const uint8_t *) language_pack;
1214 const nbgl_font_unicode_t *font = (const void *) (ptr + language_pack->fonts_offset);
1215 unicodeCtx.characters
1216 = (const nbgl_font_unicode_character_t *) (ptr + language_pack->characters_offset);
1217 unicodeCtx.bitmap = (const uint8_t *) (ptr + language_pack->bitmaps_offset);
1218
1219 for (uint32_t i = 0; i < language_pack->nb_fonts; i++) {
1220 if (font->font_id == fontId) {
1221 // Update all other global variables
1222 unicodeCtx.font = font;
1223 return &unicodeCtx;
1224 }
1225 // Compute next Bitmap offset
1226 unicodeCtx.bitmap += font->bitmap_len;
1227
1228 // Update all pointers for next font
1229 unicodeCtx.characters += language_pack->nb_characters;
1230 font++;
1231 }
1232 // id not found
1233 return NULL;
1234}
1235
1246{
1247 // if in Apps, do not support unicode
1248 if (os_sched_current_task() != TASK_BOLOS_UX) {
1249 return NULL;
1250 }
1251 const nbgl_font_unicode_character_t *characters
1252 = (const nbgl_font_unicode_character_t *) PIC(unicodeCtx.characters);
1253 uint32_t n = language_pack->nb_characters;
1254 if (characters == NULL) {
1255 return NULL;
1256 }
1257 // For the moment, let just parse the full array, but at the end let use
1258 // binary search as data are sorted by unicode value !
1259 for (unsigned i = 0; i < n - 1; i++, characters++) {
1260 if (characters->char_unicode == unicode) {
1261 // Compute & store the number of bytes used to display this character
1263 = (characters + 1)->bitmap_offset - characters->bitmap_offset;
1264 return characters;
1265 }
1266 }
1267 // By default, let's use the last Unicode character, which should be the
1268 // 0x00FFFD one, used to replace unrecognized or unrepresentable character.
1269
1270 // Compute & store the number of bytes used to display this character
1272 = unicodeCtx.font->bitmap_len - characters->bitmap_offset;
1273 return characters;
1274}
1275
1283{
1284 // if in Apps, do not support unicode
1285 if (os_sched_current_task() != TASK_BOLOS_UX) {
1286 return 0;
1287 }
1288 return unicodeCtx.unicode_character_byte_count;
1289}
1290
1298void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
1299{
1300 language_pack = lp;
1301 unicodeCtx.font = NULL;
1302 unicodeCtx.characters = NULL;
1303}
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:470
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:410
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:850
const nbgl_font_unicode_character_t * nbgl_getUnicodeFontCharacter(uint32_t unicode)
Get the unicode character object matching the given unicode (a unicode character is encoded on max of...
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:312
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:350
void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
Function to be called when a change on the current language pack is notified by the OS,...
nbgl_unicode_ctx_t * nbgl_getUnicodeFont(nbgl_font_id_e fontId)
Get the font entry for the given font id (sparse font array support)
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:552
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:654
#define IS_WORD_DELIM(c)
Definition nbgl_fonts.c:25
#define PIC_FONT(x)
Definition nbgl_fonts.c:22
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:372
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:126
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:338
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:23
uint16_t nbgl_getTextLength(const char *text)
return the number of bytes of the given text, excluding final ' ' or '\0'
Definition nbgl_fonts.c:442
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:704
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:429
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:391
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:326
uint32_t nbgl_getUnicodeFontCharacterByteCount(void)
Get the bitmap byte count of the latest used unicode character. (the one returned by nbgl_getUnicodeF...
__attribute__((section("._nbgl_fonts_"))) const
return the non-unicode font corresponding to the given font ID
Definition nbgl_fonts.c:66
nbgl_font_id_e
Definition nbgl_fonts.h:132
@ BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
Definition nbgl_fonts.h:141
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition nbgl_fonts.h:139
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
#define MIN(x, y)
Definition nbgl_types.h:118
fonts nicknames to be used for various wallet size targets (non-Nano)
Definition nbgl_fonts.h:63
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:66
structure defining an ASCII font
Definition nbgl_fonts.h:77
uint8_t char_kerning
kerning for the font
Definition nbgl_fonts.h:83
uint8_t first_char
ASCII code of the first character in bitmap and in characters fields.
Definition nbgl_fonts.h:87
const nbgl_font_character_t *const characters
array containing definitions of all characters
Definition nbgl_fonts.h:91
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:81
uint8_t line_height
height of a line for all characters in pixels
Definition nbgl_fonts.h:82
uint8_t last_char
ASCII code of the last character in bitmap and in characters fields.
Definition nbgl_fonts.h:89
structure defining a unicode character (except the bitmap)
Definition nbgl_fonts.h:105
uint32_t char_unicode
plane value from 0 to 16 then 16-bit code.
Definition nbgl_fonts.h:106
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:108
uint32_t over_previous
flag set to 1 when displayed over previous char
Definition nbgl_fonts.h:114
uint32_t bitmap_offset
offset of this character in chars buffer
Definition nbgl_fonts.h:113
structure defining a unicode font
Definition nbgl_fonts.h:120
uint16_t bitmap_len
Size in bytes of all characters bitmaps.
Definition nbgl_fonts.h:121
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:124
uint8_t font_id
ID of the font, from nbgl_font_id_e.
Definition nbgl_fonts.h:122
uint8_t line_height
height of a line for all characters in pixels
Definition nbgl_fonts.h:125
const nbgl_font_unicode_character_t * characters
Definition nbgl_fonts.h:156
const nbgl_font_unicode_t * font
Definition nbgl_fonts.h:155
uint32_t unicode_character_byte_count
Definition nbgl_fonts.h:158
const uint8_t * bitmap
Definition nbgl_fonts.h:157