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;
233 nbgl_unicode_ctx_t *unicode_ctx = NULL;
234
235 if (text == NULL) {
236 return 0;
237 }
238 textLen = MIN(strlen(text), maxLen);
239
240#ifdef BUILD_SCREENSHOTS
241 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
242 bool next_bold_state = last_bold_state;
243#endif // BUILD_SCREENSHOTS
244
245 // end loop text len is NULL (max reached)
246 while (textLen) {
247 uint8_t char_width;
248 uint32_t unicode;
249 bool is_unicode;
250
251 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
252 // Do we still have some characters to read?
253 if (!unicode) {
254 break;
255 }
256 if (is_unicode && !unicode_ctx) {
257 unicode_ctx = nbgl_getUnicodeFont(fontId);
258 }
259 if (unicode == '\n') {
260 if (breakOnLineEnd) {
261 break;
262 }
263 // reset line width for next line
264 line_width = 0;
265 continue;
266 }
267 // if \b, switch fontId
268 else if (unicode == '\b') {
269 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
271 unicode_ctx = NULL;
272 font = nbgl_getFont(fontId);
273#ifdef BUILD_SCREENSHOTS
274 next_bold_state = true;
275#endif // BUILD_SCREENSHOTS
276 }
277 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
279 unicode_ctx = NULL;
280 font = nbgl_getFont(fontId);
281#ifdef BUILD_SCREENSHOTS
282 next_bold_state = false;
283#endif // BUILD_SCREENSHOTS
284 }
285 continue;
286 }
287 char_width = getCharWidth(font, unicode, is_unicode);
288#ifdef BUILD_SCREENSHOTS
289 if (char_width != 0) {
290 // Update last 'displayed' char with current bold status
291 last_bold_state = next_bold_state;
292 }
293#endif // BUILD_SCREENSHOTS
294 line_width += char_width;
295 // memorize max line width if greater than current
296 if (line_width > max_width) {
297 max_width = line_width;
298 }
299 }
300#ifdef BUILD_SCREENSHOTS
301 if (line_width != 0) {
302 ++nb_lines;
303 }
304 last_nb_lines = nb_lines;
305#endif // BUILD_SCREENSHOTS
306
307 return max_width;
308}
309
317uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
318{
319 return getTextWidth(fontId, text, true, 0xFFFF);
320}
321
331uint16_t nbgl_getSingleLineTextWidthInLen(nbgl_font_id_e fontId, const char *text, uint16_t maxLen)
332{
333 return getTextWidth(fontId, text, true, maxLen);
334}
335
343uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
344{
345 return getTextWidth(fontId, text, false, 0xFFFF);
346}
347
355uint8_t nbgl_getCharWidth(nbgl_font_id_e fontId, const char *text)
356{
357 const nbgl_font_t *font = nbgl_getFont(fontId);
358 uint32_t unicode;
359 bool is_unicode;
360 uint16_t textLen = 4; // max len for a char
361
362 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
363 if (is_unicode) {
364 nbgl_getUnicodeFont(fontId);
365 }
366
367 return getCharWidth(font, unicode, is_unicode);
368}
369
377{
378 // Unicode combined fonts can be higher than normal ones, due to supperposition of 'accents'
379 nbgl_unicode_ctx_t *unicode_ctx = nbgl_getUnicodeFont(fontId);
380 if (unicode_ctx) {
381 return unicode_ctx->font->height;
382 }
383 else {
384 const nbgl_font_t *font = nbgl_getFont(fontId);
385 return font->height;
386 }
387}
388
396{
397 // Unicode combined fonts can be higher than normal ones, due to supperposition of 'accents'
398 nbgl_unicode_ctx_t *unicode_ctx = nbgl_getUnicodeFont(fontId);
399 if (unicode_ctx) {
400 return unicode_ctx->font->line_height;
401 }
402 else {
403 const nbgl_font_t *font = nbgl_getFont(fontId);
404 return font->line_height;
405 }
406}
407
414uint16_t nbgl_getTextNbLines(const char *text)
415{
416 uint16_t nbLines = 1;
417 while (*text) {
418 if (*text == '\n') {
419 nbLines++;
420 }
421 text++;
422 }
423 return nbLines;
424}
425
433uint16_t nbgl_getTextHeight(nbgl_font_id_e fontId, const char *text)
434{
435 const nbgl_font_t *font = nbgl_getFont(fontId);
436 return (nbgl_getTextNbLines(text) * font->line_height);
437}
438
446uint16_t nbgl_getTextLength(const char *text)
447{
448 const char *origText = text;
449 while (*text) {
450 if (*text == '\f') {
451 break;
452 }
453 else if (*text == '\n') {
454 break;
455 }
456 text++;
457 }
458 return text - origText;
459}
460
475 const char *text,
476 uint16_t maxWidth,
477 uint16_t *len,
478 uint16_t *width,
479 bool wrapping)
480{
481 const nbgl_font_t *font = nbgl_getFont(fontId);
482 uint16_t textLen = nbgl_getTextLength(text);
483 uint32_t lenAtLastDelimiter = 0, widthAtlastDelimiter = 0;
484 nbgl_unicode_ctx_t *unicode_ctx = NULL;
485
486 *width = 0;
487 *len = 0;
488 while (textLen) {
489 uint8_t char_width;
490 uint32_t unicode;
491 bool is_unicode;
492 uint16_t curTextLen = textLen;
493
494 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
495 if (is_unicode && !unicode_ctx) {
496 unicode_ctx = nbgl_getUnicodeFont(fontId);
497 }
498 // if EOS or \f or \n, exit loop
499 if (!unicode || (unicode == '\f') || (unicode == '\n')) {
500 *len += curTextLen - textLen;
501 return;
502 }
503 // if \b, switch fontId
504 else if (unicode == '\b') {
505 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
507 unicode_ctx = NULL;
508 font = nbgl_getFont(fontId);
509 }
510 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
512 unicode_ctx = NULL;
513 font = nbgl_getFont(fontId);
514 }
515 *len += curTextLen - textLen;
516 continue;
517 }
518
519 char_width = getCharWidth(font, unicode, is_unicode);
520 if (char_width == 0) {
521 *len += curTextLen - textLen;
522 continue;
523 }
524
525 // memorize cursors at last found sepator, when wrapping
526 if ((wrapping == true) && IS_WORD_DELIM(unicode)) {
527 lenAtLastDelimiter = *len;
528 widthAtlastDelimiter = *width;
529 }
530 if ((*width + char_width) > maxWidth) {
531 if ((wrapping == true) && (widthAtlastDelimiter > 0)) {
532 *len = lenAtLastDelimiter + 1;
533 *width = widthAtlastDelimiter;
534 }
535 return;
536 }
537 *len += curTextLen - textLen;
538 *width = *width + char_width;
539 }
540}
541
557 const char *text,
558 uint16_t maxWidth,
559 uint16_t maxNbLines,
560 uint16_t *len,
561 bool wrapping)
562{
563 const nbgl_font_t *font = nbgl_getFont(fontId);
564 uint16_t textLen;
565 uint16_t width = 0;
566 const char *lastDelimiter = NULL;
567 uint32_t lenAtLastDelimiter = 0;
568 const char *origText = text;
569 const char *previousText;
570 nbgl_unicode_ctx_t *unicode_ctx = NULL;
571
572 if (text == NULL) {
573 *len = 0;
574 return false;
575 }
576 textLen = strlen(text);
577
578 while ((textLen) && (maxNbLines > 0)) {
579 uint8_t char_width;
580 uint32_t unicode;
581 bool is_unicode = false;
582
583 previousText = text;
584 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
585 if (is_unicode && !unicode_ctx) {
586 unicode_ctx = nbgl_getUnicodeFont(fontId);
587 }
588 // memorize cursors at last found delimiter
589 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
590 lastDelimiter = text;
591 lenAtLastDelimiter = textLen;
592 }
593
594 // if \n, reset width
595 if (unicode == '\n') {
596 maxNbLines--;
597 // if last line is reached, let's rewind before carriage return
598 if (maxNbLines == 0) {
599 text--;
600 }
601 lastDelimiter = NULL;
602 width = 0;
603 continue;
604 }
605 // if \f, exit
606 else if (unicode == '\f') {
607 maxNbLines = 0;
608 break;
609 }
610 // if \b, switch fontId
611 else if (unicode == '\b') {
612 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
614 unicode_ctx = NULL;
615 font = nbgl_getFont(fontId);
616 }
617 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
619 unicode_ctx = NULL;
620 font = nbgl_getFont(fontId);
621 }
622 continue;
623 }
624
625 char_width = getCharWidth(font, unicode, is_unicode);
626 if (char_width == 0) {
627 continue;
628 }
629
630 if ((width + char_width) > maxWidth) {
631 if ((wrapping == true) && (lastDelimiter != NULL)) {
632 text = lastDelimiter;
633 lastDelimiter = NULL;
634 textLen = lenAtLastDelimiter;
635 }
636 else {
637 textLen += text - previousText;
638 text = previousText;
639 }
640 width = 0;
641 maxNbLines--;
642 continue;
643 }
644 width += char_width;
645 }
646 *len = text - origText;
647 return (maxNbLines == 0);
648}
649
665 const char *text,
666 uint16_t maxWidth,
667 uint16_t *len,
668 uint16_t *width)
669{
670 const nbgl_font_t *font = nbgl_getFont(fontId);
671 uint16_t textLen = nbgl_getTextLength(text);
672
673 *width = 0;
674 *len = 0;
675 while (textLen) {
676 const nbgl_font_character_t *character;
677 uint8_t char_width;
678 char cur_char;
679
680 textLen--;
681 cur_char = text[textLen];
682 // if \n, exit
683 if (cur_char == '\n') {
684 *len = *len + 1;
685 continue;
686 }
687
688 // skip not printable char
689 if ((cur_char < font->first_char) || (cur_char > font->last_char)) {
690 continue;
691 }
692 character
693 = (const nbgl_font_character_t *) PIC(&font->characters[cur_char - font->first_char]);
694 char_width = character->width;
695
696 if ((*width + char_width) > maxWidth) {
697 return true;
698 }
699 *len = *len + 1;
700 *width = *width + char_width;
701 }
702 return false;
703}
704
715 const char *text,
716 uint16_t maxWidth,
717 bool wrapping)
718{
719 const nbgl_font_t *font = nbgl_getFont(fontId);
720 uint16_t width = 0;
721#ifdef SCREEN_SIZE_NANO
722 uint16_t nbLines = 0;
723#else // SCREEN_SIZE_NANO
724 uint16_t nbLines = 1;
725#endif // SCREEN_SIZE_NANO
726 uint16_t textLen;
727 const char *lastDelimiter = NULL;
728 uint32_t lenAtLastDelimiter = 0;
729 const char *prevText = NULL;
730 nbgl_unicode_ctx_t *unicode_ctx = NULL;
731
732#ifdef BUILD_SCREENSHOTS
733 hard_caesura = false;
734 last_nb_lines = 0;
735 last_nb_pages = 1;
736 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
737 bool next_bold_state = last_bold_state;
738#endif // BUILD_SCREENSHOTS
739
740 if (text == NULL) {
741 return 1;
742 }
743 textLen = strlen(text);
744 // end loop when a '\0' is uncountered
745 while (textLen) {
746 uint8_t char_width;
747 uint32_t unicode;
748 bool is_unicode = false;
749
750 // memorize the last char
751 prevText = text;
752 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
753 if (is_unicode && !unicode_ctx) {
754 unicode_ctx = nbgl_getUnicodeFont(fontId);
755 }
756
757 // memorize cursors at last found space
758 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
759 lastDelimiter = prevText;
760 lenAtLastDelimiter = textLen;
761 }
762 // if \f, exit loop
763 if (unicode == '\f') {
764#ifdef BUILD_SCREENSHOTS
765 if (textLen) {
766 ++last_nb_pages;
767 }
768#endif // BUILD_SCREENSHOTS
769 break;
770 }
771 // if \n, increment the number of lines
772 else if (unicode == '\n') {
773 nbLines++;
774#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
775 if (!(nbLines % 4)) {
776 if (textLen) {
777 ++last_nb_pages;
778 }
779 }
780#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
781 width = 0;
782 lastDelimiter = NULL;
783 continue;
784 }
785 // if \b, switch fontId
786 else if (unicode == '\b') {
787 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
789 unicode_ctx = NULL;
790 font = nbgl_getFont(fontId);
791#ifdef BUILD_SCREENSHOTS
792 next_bold_state = true;
793#endif // BUILD_SCREENSHOTS
794 }
795 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
797 unicode_ctx = NULL;
798 font = nbgl_getFont(fontId);
799#ifdef BUILD_SCREENSHOTS
800 next_bold_state = false;
801#endif // BUILD_SCREENSHOTS
802 }
803 continue;
804 }
805
806 char_width = getCharWidth(font, unicode, is_unicode);
807 if (char_width == 0) {
808 continue;
809 }
810#ifdef BUILD_SCREENSHOTS
811 // Update last 'displayed' char with current bold status
812 last_bold_state = next_bold_state;
813#endif // BUILD_SCREENSHOTS
814
815 // if about to reach max len, increment the number of lines
816 if ((width + char_width) > maxWidth) {
817 if ((wrapping == true) && (lastDelimiter != NULL)) {
818 text = lastDelimiter + 1;
819 lastDelimiter = NULL;
820 textLen = lenAtLastDelimiter;
821 width = 0;
822 }
823 else {
824#ifdef BUILD_SCREENSHOTS
825 // An hyphenation (caesura) has been forced.
826 hard_caesura = true;
827#endif // BUILD_SCREENSHOTS
828 width = char_width;
829 }
830 nbLines++;
831#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
832 if (!(nbLines % 4)) {
833 if (textLen) {
834 ++last_nb_pages;
835 }
836 }
837#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
838 }
839 else {
840 width += char_width;
841 }
842 }
843#ifdef SCREEN_SIZE_NANO
844 if (width != 0) {
845 ++nbLines;
846 }
847#endif // SCREEN_SIZE_NANO
848#ifdef BUILD_SCREENSHOTS
849 last_nb_lines = nbLines;
850#endif // BUILD_SCREENSHOTS
851 return nbLines;
852}
853
865 const char *text,
866 uint8_t nbLinesPerPage,
867 uint16_t maxWidth)
868{
869 const nbgl_font_t *font = nbgl_getFont(fontId);
870 uint16_t width = 0;
871 uint16_t nbLines = 0;
872 uint8_t nbPages = 1;
873 uint16_t textLen;
874 const char *lastDelimiter = NULL;
875 uint32_t lenAtLastDelimiter = 0;
876 const char *prevText = NULL;
877 nbgl_unicode_ctx_t *unicode_ctx = NULL;
878
879#ifdef BUILD_SCREENSHOTS
880 last_nb_lines = nbLines;
881 last_nb_pages = nbPages;
882 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
883 bool next_bold_state = last_bold_state;
884#endif // BUILD_SCREENSHOTS
885
886 if (text == NULL) {
887 return 1;
888 }
889 textLen = strlen(text);
890
891 // end loop when a '\0' is uncountered
892 while (textLen) {
893 uint8_t char_width;
894 uint32_t unicode;
895 bool is_unicode = false;
896
897 // memorize the last char
898 prevText = text;
899 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
900 if (is_unicode && !unicode_ctx) {
901 unicode_ctx = nbgl_getUnicodeFont(fontId);
902 }
903
904 // memorize cursors at last found space
905 if (IS_WORD_DELIM(unicode)) {
906 lastDelimiter = prevText;
907 lenAtLastDelimiter = textLen;
908 }
909 // if \f, updates page number
910 if (unicode == '\f') {
911 nbPages++;
912#ifdef BUILD_SCREENSHOTS
913#ifdef SCREEN_SIZE_NANO
914 if (width != 0) {
915#endif // SCREEN_SIZE_NANO
916 ++nbLines;
917#ifdef SCREEN_SIZE_NANO
918 }
919#endif // SCREEN_SIZE_NANO
920 if (last_nb_lines < nbLines) {
921 last_nb_lines = nbLines;
922 }
923#endif // BUILD_SCREENSHOTS
924 nbLines = 0;
925 width = 0;
926 continue;
927 }
928 // if \n, increment the number of lines
929 else if (unicode == '\n') {
930 nbLines++;
931#ifdef BUILD_SCREENSHOTS
932 if (last_nb_lines < nbLines) {
933 last_nb_lines = nbLines;
934 }
935#endif // BUILD_SCREENSHOTS
936 if (nbLines == nbLinesPerPage && textLen) {
937 nbPages++;
938 nbLines = 0;
939 }
940
941 width = 0;
942 lastDelimiter = NULL;
943 continue;
944 }
945 // if \b, switch fontId
946 else if (unicode == '\b') {
947 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
949 unicode_ctx = NULL;
950 font = nbgl_getFont(fontId);
951#ifdef BUILD_SCREENSHOTS
952 next_bold_state = true;
953#endif // BUILD_SCREENSHOTS
954 }
955 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
957 unicode_ctx = NULL;
958 font = nbgl_getFont(fontId);
959#ifdef BUILD_SCREENSHOTS
960 next_bold_state = false;
961#endif // BUILD_SCREENSHOTS
962 }
963 continue;
964 }
965
966 char_width = getCharWidth(font, unicode, is_unicode);
967 if (char_width == 0) {
968 continue;
969 }
970
971#ifdef BUILD_SCREENSHOTS
972 // Update last 'displayed' char with current bold status
973 last_bold_state = next_bold_state;
974#endif // BUILD_SCREENSHOTS
975
976 // if about to reach max len, increment the number of lines/pages
977 if ((width + char_width) > maxWidth) {
978 if (lastDelimiter != NULL) {
979 text = lastDelimiter + 1;
980 lastDelimiter = NULL;
981 textLen = lenAtLastDelimiter;
982 width = 0;
983 }
984 else {
985 width = char_width;
986 }
987 nbLines++;
988#ifdef BUILD_SCREENSHOTS
989 if (last_nb_lines < nbLines) {
990 last_nb_lines = nbLines;
991 }
992#endif // BUILD_SCREENSHOTS
993 if (nbLines == nbLinesPerPage) {
994 nbPages++;
995 nbLines = 0;
996 }
997 }
998 else {
999 width += char_width;
1000 }
1001 }
1002#ifdef BUILD_SCREENSHOTS
1003#ifdef SCREEN_SIZE_NANO
1004 if (width != 0) {
1005 ++nbLines;
1006 }
1007#endif // SCREEN_SIZE_NANO
1008 if (last_nb_lines < nbLines) {
1009 last_nb_lines = nbLines;
1010 }
1011 last_nb_pages = nbPages;
1012#endif // BUILD_SCREENSHOTS
1013 return nbPages;
1014}
1015
1026 const char *text,
1027 uint16_t maxWidth,
1028 bool wrapping)
1029{
1030 const nbgl_font_t *font = nbgl_getFont(fontId);
1031 return (nbgl_getTextNbLinesInWidth(fontId, text, maxWidth, wrapping) * font->line_height);
1032}
1033
1034#ifndef OS_UNIT_TEST
1046void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char *text, uint16_t maxWidth, uint8_t nbLines)
1047{
1048 const nbgl_font_t *font = nbgl_getFont(fontId);
1049 uint16_t textLen = nbgl_getTextLength(text);
1050 uint16_t width = 0;
1051 uint8_t currentNbLines = 1;
1052 char *lastDelimiter = NULL;
1053 uint32_t lenAtLastDelimiter = 0;
1054 char *prevText[4] = {0}; // queue of last positions
1055 uint16_t prevWidth[2] = {0}; // queue of last widths
1056 nbgl_unicode_ctx_t *unicode_ctx = NULL;
1057
1058 while (*text) {
1059 uint8_t char_width;
1060 uint32_t unicode;
1061 bool is_unicode;
1062
1063 // memorize the last positions in the queue
1064 // the oldest is at the highest index
1065 prevText[3] = prevText[2];
1066 prevText[2] = prevText[1];
1067 prevText[1] = prevText[0];
1068 prevText[0] = text;
1069 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
1070 // if \n, reset width
1071 if (unicode == '\n') {
1072 width = 0;
1073 currentNbLines++;
1074 lastDelimiter = NULL;
1075 continue;
1076 }
1077 if (is_unicode && !unicode_ctx) {
1078 unicode_ctx = nbgl_getUnicodeFont(fontId);
1079 }
1080 char_width = getCharWidth(font, unicode, is_unicode);
1081 if (char_width == 0) {
1082 continue;
1083 }
1084
1085 // memorize cursors at last found space
1086 if (IS_WORD_DELIM(unicode)) {
1087 lastDelimiter = prevText[0];
1088 lenAtLastDelimiter = textLen + 1;
1089 }
1090 // if the width is about to overpass maxWidth, do something
1091 if ((width + char_width) > maxWidth) {
1092 // if the max number of lines has not been reached, try to wrap on last space
1093 // encountered
1094 if (currentNbLines < nbLines) {
1095 currentNbLines++;
1096 // replace last found space by a \n
1097 if (lastDelimiter != NULL) {
1098 *lastDelimiter++ = '\n';
1099 text = lastDelimiter;
1100 lastDelimiter = NULL;
1101 textLen = lenAtLastDelimiter - 1;
1102 }
1103 else {
1104 textLen += text - prevText[0];
1105 text = prevText[0];
1106 }
1107 // reset width for next line
1108 width = 0;
1109 continue;
1110 }
1111 else {
1112 uint32_t i;
1113 // replace the 1, 2 or 3 last chars by '...'
1114 // try at first with 1, then with 2, if it fits
1115 for (i = 0; i < 2; i++) {
1116 if ((prevText[i + 1] != NULL)
1117 && ((prevWidth[i] + (3 * getCharWidth(font, '.', false))) <= maxWidth)) {
1118 break;
1119 }
1120 }
1121 // at worth we are sure it works by replacing the 3 last chars (if i ==2)
1122 if (prevText[i + 1] != NULL) {
1123 memcpy(prevText[i + 1], "...", 4);
1124 }
1125 return;
1126 }
1127 }
1128 // memorize the 2 last widths in a queue
1129 prevWidth[1] = prevWidth[0];
1130 prevWidth[0] = width;
1131 width += char_width;
1132 }
1133}
1134#endif // OS_UNIT_TEST
1135
1152 const char *origText,
1153 uint16_t maxWidth,
1154 uint8_t nbLines,
1155 char *reducedText,
1156 uint16_t reducedTextLen)
1157{
1158 const nbgl_font_t *font = nbgl_getFont(fontId);
1159 uint16_t textLen = strlen(origText);
1160 uint16_t width = 0;
1161 uint8_t currentNbLines = 1;
1162 uint32_t i = 0, j = 0;
1163 const uint16_t halfWidth = (maxWidth - nbgl_getTextWidth(fontId, " ... ")) / 2;
1164
1165 if ((nbLines & 0x1) == 0) {
1166 LOG_FATAL(MISC_LOGGER, "nbgl_textReduceOnNbLines: the number of line must be odd\n");
1167 return;
1168 }
1169 while ((i < textLen) && (j < reducedTextLen)) {
1170 uint8_t char_width;
1171 char curChar;
1172
1173 curChar = origText[i];
1174
1175 char_width = getCharWidth(font, curChar, false);
1176 if (char_width == 0) {
1177 reducedText[j] = curChar;
1178 j++;
1179 i++;
1180 continue;
1181 }
1182
1183 // if the width is about to exceed maxWidth, increment number of lines
1184 if ((width + char_width) > maxWidth) {
1185 currentNbLines++;
1186 // reset width for next line
1187 width = 0;
1188 continue;
1189 }
1190 else if ((currentNbLines == ((nbLines / 2) + 1)) && ((width + char_width) > halfWidth)) {
1191 uint32_t halfFullWidth = (nbLines / 2) * maxWidth + halfWidth;
1192 uint32_t countDown = textLen;
1193 // if this if the central line, we have to insert the '...' in the middle of it
1194 reducedText[j - 1] = '.';
1195 reducedText[j] = '.';
1196 reducedText[j + 1] = '.';
1197 // then start from the end
1198 width = 0;
1199 while (width < halfFullWidth) {
1200 countDown--;
1201 curChar = origText[countDown];
1202 char_width = getCharWidth(font, curChar, false);
1203 width += char_width;
1204 }
1205 memcpy(&reducedText[j + 2], &origText[countDown + 1], textLen - countDown + 1);
1206 return;
1207 }
1208 else {
1209 reducedText[j] = curChar;
1210 j++;
1211 i++;
1212 }
1213 width += char_width;
1214 }
1215 reducedText[j] = '\0';
1216}
1217
1226{
1227 // if in Apps, do not support unicode
1228 if (os_sched_current_task() != TASK_BOLOS_UX) {
1229 return NULL;
1230 }
1231 if ((unicodeCtx.font != NULL) && (unicodeCtx.font->font_id == fontId)) {
1232 return &unicodeCtx;
1233 }
1234 // Be sure we need to change font
1235 const uint8_t *ptr = (const uint8_t *) language_pack;
1236 const nbgl_font_unicode_t *font = (const void *) (ptr + language_pack->fonts_offset);
1237 unicodeCtx.characters
1238 = (const nbgl_font_unicode_character_t *) (ptr + language_pack->characters_offset);
1239 unicodeCtx.bitmap = (const uint8_t *) (ptr + language_pack->bitmaps_offset);
1240
1241 for (uint32_t i = 0; i < language_pack->nb_fonts; i++) {
1242 if (font->font_id == fontId) {
1243 // Update all other global variables
1244 unicodeCtx.font = font;
1245 return &unicodeCtx;
1246 }
1247 // Compute next Bitmap offset
1248 unicodeCtx.bitmap += font->bitmap_len;
1249
1250 // Update all pointers for next font
1251 unicodeCtx.characters += language_pack->nb_characters;
1252 font++;
1253 }
1254 // id not found
1255 return NULL;
1256}
1257
1268{
1269 // if in Apps, do not support unicode
1270 if (os_sched_current_task() != TASK_BOLOS_UX) {
1271 return NULL;
1272 }
1273 const nbgl_font_unicode_character_t *characters
1274 = (const nbgl_font_unicode_character_t *) PIC(unicodeCtx.characters);
1275 uint32_t n = language_pack->nb_characters;
1276 if (characters == NULL) {
1277 return NULL;
1278 }
1279 // For the moment, let just parse the full array, but at the end let use
1280 // binary search as data are sorted by unicode value !
1281 for (unsigned i = 0; i < n - 1; i++, characters++) {
1282 if (characters->char_unicode == unicode) {
1283 // Compute & store the number of bytes used to display this character
1285 = (characters + 1)->bitmap_offset - characters->bitmap_offset;
1286 return characters;
1287 }
1288 }
1289 // By default, let's use the last Unicode character, which should be the
1290 // 0x00FFFD one, used to replace unrecognized or unrepresentable character.
1291
1292 // Compute & store the number of bytes used to display this character
1294 = unicodeCtx.font->bitmap_len - characters->bitmap_offset;
1295 return characters;
1296}
1297
1305{
1306 // if in Apps, do not support unicode
1307 if (os_sched_current_task() != TASK_BOLOS_UX) {
1308 return 0;
1309 }
1310 return unicodeCtx.unicode_character_byte_count;
1311}
1312
1320void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
1321{
1322 language_pack = lp;
1323 unicodeCtx.font = NULL;
1324 unicodeCtx.characters = NULL;
1325}
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:474
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:414
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:864
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:317
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:355
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:556
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:664
#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:376
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:343
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:446
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:714
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:433
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:395
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:331
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