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 SMALL_FONT_HEIGHT == 24
48#include "nbgl_font_inter_regular_24.inc"
49#include "nbgl_font_inter_semibold_24.inc"
50#include "nbgl_font_inter_medium_32.inc"
51#include "nbgl_font_inter_regular_24_1bpp.inc"
52#include "nbgl_font_inter_semibold_24_1bpp.inc"
53#include "nbgl_font_inter_medium_32_1bpp.inc"
54#elif SMALL_FONT_HEIGHT == 28
55#include "nbgl_font_inter_regular_28.inc"
56#include "nbgl_font_inter_semibold_28.inc"
57#include "nbgl_font_inter_medium_36.inc"
58#include "nbgl_font_inter_regular_28_1bpp.inc"
59#include "nbgl_font_inter_semibold_28_1bpp.inc"
60#include "nbgl_font_inter_medium_36_1bpp.inc"
61#elif SMALL_FONT_HEIGHT == 11
62#include "nbgl_font_open_sans_extrabold_11.inc"
63#include "nbgl_font_open_sans_regular_11.inc"
64#include "nbgl_font_open_sans_light_16.inc"
65#endif // SMALL_FONT_HEIGHT
66
67__attribute__((section("._nbgl_fonts_"))) const nbgl_font_t *const C_nbgl_fonts[] = {
68
69#include "nbgl_font_rom_struct.inc"
70
71};
72__attribute__((section("._nbgl_fonts_"))) const unsigned int C_nbgl_fonts_count
73 = sizeof(C_nbgl_fonts) / sizeof(C_nbgl_fonts[0]);
74
75#if (defined(HAVE_BOLOS) && !defined(BOLOS_OS_UPGRADER_APP))
76#if !defined(HAVE_LANGUAGE_PACK)
77const nbgl_font_unicode_t *const C_nbgl_fonts_unicode[] = {
78
79#include "nbgl_font_unicode_rom_struct.inc"
80
81};
82
83// All Unicode fonts MUST have the same number of characters!
84const unsigned int C_unicode_characters_count
85 = (sizeof(charactersOPEN_SANS_REGULAR_11PX_UNICODE)
86 / sizeof(charactersOPEN_SANS_REGULAR_11PX_UNICODE[0]));
87
88#endif
89#endif // HAVE_BOLOS
90
91#ifdef BUILD_SCREENSHOTS
92// Variables used to store important values (nb lines, bold state etc)
93uint16_t last_nb_lines = 0;
94uint16_t last_nb_pages = 0;
95bool last_bold_state = false;
96
97// Used to detect when a hyphenation (caesura) has been forced.
98bool hard_caesura = false;
99#endif // BUILD_SCREENSHOTS
100
101/**********************
102 * STATIC PROTOTYPES
103 **********************/
104
105/**********************
106 * GLOBAL FUNCTIONS
107 **********************/
108
116{
117 unsigned int i = C_nbgl_fonts_count;
118 fontId &= BAGL_FONT_ID_MASK;
119
120 while (i--) {
121 // font id match this entry (non indexed array)
122 if (PIC_FONT(C_nbgl_fonts[i])->font_id == fontId) {
123 return PIC_FONT(C_nbgl_fonts[i]);
124 }
125 }
126
127 // id not found
128 return NULL;
129}
130
140uint32_t nbgl_popUnicodeChar(const uint8_t **text, uint16_t *textLen, bool *is_unicode)
141{
142 const uint8_t *txt = *text;
143 uint8_t cur_char = *txt++;
144 uint32_t unicode;
145
146 *is_unicode = true;
147 // Handle UTF-8 decoding (RFC3629): (https://www.ietf.org/rfc/rfc3629.txt
148 // Char. number range | UTF-8 octet sequence
149 // (hexadecimal) | (binary)
150 // --------------------+---------------------------------------------
151 // 0000 0000-0000 007F | 0xxxxxxx
152 // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
153 // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
154 // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
155
156 // 4 bytes UTF-8, Unicode 0x1000 to 0x1FFFF
157 if ((cur_char >= 0xF0) && (*textLen >= 4)) {
158 unicode = (cur_char & 0x07) << 18;
159 unicode |= (*txt++ & 0x3F) << 12;
160 unicode |= (*txt++ & 0x3F) << 6;
161 unicode |= (*txt++ & 0x3F);
162
163 // 3 bytes, from 0x800 to 0xFFFF
164 }
165 else if ((cur_char >= 0xE0) && (*textLen >= 3)) {
166 unicode = (cur_char & 0x0F) << 12;
167 unicode |= (*txt++ & 0x3F) << 6;
168 unicode |= (*txt++ & 0x3F);
169
170 // 2 bytes UTF-8, Unicode 0x80 to 0x7FF
171 // (0xC0 & 0xC1 are unused and can be used to store something else)
172 }
173 else if ((cur_char >= 0xC2) && (*textLen >= 2)) {
174 unicode = (cur_char & 0x1F) << 6;
175 unicode |= (*txt++ & 0x3F);
176 }
177 else {
178 *is_unicode = false;
179 unicode = cur_char;
180 }
181 *textLen = *textLen - (txt - *text);
182 *text = txt;
183 return unicode;
184}
185
194static uint8_t getCharWidth(const nbgl_font_t *font, uint32_t unicode, bool is_unicode)
195{
196 if (is_unicode) {
197#ifdef HAVE_UNICODE_SUPPORT
198 const nbgl_font_unicode_character_t *unicodeCharacter
199 = nbgl_getUnicodeFontCharacter(unicode);
200 if (!unicodeCharacter) {
201 return 0;
202 }
203 return unicodeCharacter->width - font->char_kerning;
204#else // HAVE_UNICODE_SUPPORT
205 return 0;
206#endif // HAVE_UNICODE_SUPPORT
207 }
208 else {
209 const nbgl_font_character_t *character; // non-unicode char
210 if ((unicode < font->first_char) || (unicode > font->last_char)) {
211 return 0;
212 }
213 character
214 = (const nbgl_font_character_t *) PIC(&font->characters[unicode - font->first_char]);
215 return character->width - font->char_kerning;
216 }
217}
218
229static uint16_t getTextWidth(nbgl_font_id_e fontId,
230 const char *text,
231 bool breakOnLineEnd,
232 uint16_t maxLen)
233{
234#ifdef BUILD_SCREENSHOTS
235 uint16_t nb_lines = 0;
236#endif // BUILD_SCREENSHOTS
237 uint16_t line_width = 0;
238 uint16_t max_width = 0;
239 const nbgl_font_t *font = nbgl_getFont(fontId);
240 uint16_t textLen = MIN(strlen(text), maxLen);
241#ifdef HAVE_UNICODE_SUPPORT
242 nbgl_unicode_ctx_t *unicode_ctx = NULL;
243#endif // HAVE_UNICODE_SUPPORT
244
245#ifdef BUILD_SCREENSHOTS
246 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
247 bool next_bold_state = last_bold_state;
248#endif // BUILD_SCREENSHOTS
249
250 // end loop text len is NULL (max reached)
251 while (textLen) {
252 uint8_t char_width;
253 uint32_t unicode;
254 bool is_unicode;
255
256 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
257#ifdef HAVE_UNICODE_SUPPORT
258 if (is_unicode && !unicode_ctx) {
259 unicode_ctx = nbgl_getUnicodeFont(fontId);
260 }
261#endif
262 if (unicode == '\n') {
263 if (breakOnLineEnd) {
264 break;
265 }
266 // reset line width for next line
267 line_width = 0;
268 continue;
269 }
270 // if \b, switch fontId
271 else if (unicode == '\b') {
272 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
274#ifdef HAVE_UNICODE_SUPPORT
275 unicode_ctx = NULL;
276#endif // HAVE_UNICODE_SUPPORT
277 font = nbgl_getFont(fontId);
278#ifdef BUILD_SCREENSHOTS
279 next_bold_state = true;
280#endif // BUILD_SCREENSHOTS
281 }
282 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
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 = false;
290#endif // BUILD_SCREENSHOTS
291 }
292 continue;
293 }
294 char_width = getCharWidth(font, unicode, is_unicode);
295#ifdef BUILD_SCREENSHOTS
296 if (char_width != 0) {
297 // Update last 'displayed' char with current bold status
298 last_bold_state = next_bold_state;
299 }
300#endif // BUILD_SCREENSHOTS
301 line_width += char_width;
302 // memorize max line width if greater than current
303 if (line_width > max_width) {
304 max_width = line_width;
305 }
306 }
307#ifdef BUILD_SCREENSHOTS
308 if (line_width != 0) {
309 ++nb_lines;
310 }
311 last_nb_lines = nb_lines;
312#endif // BUILD_SCREENSHOTS
313
314 return max_width;
315}
316
325{
326 return getTextWidth(fontId, text, true, 0xFFFF);
327}
328
339{
340 return getTextWidth(fontId, text, true, maxLen);
341}
342
351{
352 return getTextWidth(fontId, text, false, 0xFFFF);
353}
354
362uint8_t nbgl_getCharWidth(nbgl_font_id_e fontId, const char *text)
363{
364 const nbgl_font_t *font = nbgl_getFont(fontId);
365 uint32_t unicode;
366 bool is_unicode;
367 uint16_t textLen = 4; // max len for a char
368#ifdef HAVE_UNICODE_SUPPORT
369 nbgl_unicode_ctx_t *unicode_ctx = NULL;
370#endif // HAVE_UNICODE_SUPPORT
371
372 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
373#ifdef HAVE_UNICODE_SUPPORT
374 if (is_unicode && !unicode_ctx) {
375 unicode_ctx = nbgl_getUnicodeFont(fontId);
376 }
377#endif
378
379 return getCharWidth(font, unicode, is_unicode);
380}
381
389{
390 const nbgl_font_t *font = nbgl_getFont(fontId);
391 return font->height;
392}
393
401{
402 const nbgl_font_t *font = nbgl_getFont(fontId);
403 return font->line_height;
404}
405
413{
414 uint16_t nbLines = 1;
415 while (*text) {
416 if (*text == '\n') {
417 nbLines++;
418 }
419 text++;
420 }
421 return nbLines;
422}
423
432{
433 const nbgl_font_t *font = nbgl_getFont(fontId);
434 return (nbgl_getTextNbLines(text) * font->line_height);
435}
436
445{
446 const char *origText = text;
447 while (*text) {
448 if (*text == '\f') {
449 break;
450 }
451 else if (*text == '\n') {
452 break;
453 }
454 text++;
455 }
456 return text - origText;
457}
458
473 const char *text,
474 uint16_t maxWidth,
475 uint16_t *len,
476 uint16_t *width,
477 bool wrapping)
478{
479 const nbgl_font_t *font = nbgl_getFont(fontId);
480 uint16_t textLen = nbgl_getTextLength(text);
481 uint32_t lenAtLastDelimiter = 0, widthAtlastDelimiter = 0;
482#ifdef HAVE_UNICODE_SUPPORT
483 nbgl_unicode_ctx_t *unicode_ctx = NULL;
484#endif // HAVE_UNICODE_SUPPORT
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#ifdef HAVE_UNICODE_SUPPORT
496 if (is_unicode && !unicode_ctx) {
497 unicode_ctx = nbgl_getUnicodeFont(fontId);
498 }
499#endif
500 // if \f or \n, exit loop
501 if ((unicode == '\f') || (unicode == '\n')) {
502 *len += curTextLen - textLen;
503 return;
504 }
505 // if \b, switch fontId
506 else if (unicode == '\b') {
507 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
509#ifdef HAVE_UNICODE_SUPPORT
510 unicode_ctx = NULL;
511#endif // HAVE_UNICODE_SUPPORT
512 font = nbgl_getFont(fontId);
513 }
514 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
516#ifdef HAVE_UNICODE_SUPPORT
517 unicode_ctx = NULL;
518#endif // HAVE_UNICODE_SUPPORT
519 font = nbgl_getFont(fontId);
520 }
521 *len += curTextLen - textLen;
522 continue;
523 }
524
525 char_width = getCharWidth(font, unicode, is_unicode);
526 if (char_width == 0) {
527 *len += curTextLen - textLen;
528 continue;
529 }
530
531 // memorize cursors at last found sepator, when wrapping
532 if ((wrapping == true) && IS_WORD_DELIM(unicode)) {
533 lenAtLastDelimiter = *len;
534 widthAtlastDelimiter = *width;
535 }
536 if ((*width + char_width) > maxWidth) {
537 if ((wrapping == true) && (widthAtlastDelimiter > 0)) {
538 *len = lenAtLastDelimiter + 1;
539 *width = widthAtlastDelimiter;
540 }
541 return;
542 }
543 *len += curTextLen - textLen;
544 *width = *width + char_width;
545 }
546}
547
563 const char *text,
564 uint16_t maxWidth,
565 uint16_t maxNbLines,
566 uint16_t *len,
567 bool wrapping)
568{
569 const nbgl_font_t *font = nbgl_getFont(fontId);
570 uint16_t textLen = strlen(text);
571 uint16_t width = 0;
572 const char *lastDelimiter = NULL;
573 uint32_t lenAtLastDelimiter = 0;
574 const char *origText = text;
575 const char *previousText;
576#ifdef HAVE_UNICODE_SUPPORT
577 nbgl_unicode_ctx_t *unicode_ctx = NULL;
578#endif // HAVE_UNICODE_SUPPORT
579
580 while ((textLen) && (maxNbLines > 0)) {
581 uint8_t char_width;
582 uint32_t unicode;
583 bool is_unicode;
584
585 previousText = text;
586 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
587#ifdef HAVE_UNICODE_SUPPORT
588 if (is_unicode && !unicode_ctx) {
589 unicode_ctx = nbgl_getUnicodeFont(fontId);
590 }
591#endif
592 // memorize cursors at last found delimiter
593 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
594 lastDelimiter = text;
595 lenAtLastDelimiter = textLen;
596 }
597
598 // if \n, reset width
599 if (unicode == '\n') {
600 maxNbLines--;
601 // if last line is reached, let's rewind before carriage return
602 if (maxNbLines == 0) {
603 text--;
604 }
605 width = 0;
606 continue;
607 }
608 // if \f, exit
609 else if (unicode == '\f') {
610 maxNbLines = 0;
611 break;
612 }
613 // if \b, switch fontId
614 else if (unicode == '\b') {
615 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
617#ifdef HAVE_UNICODE_SUPPORT
618 unicode_ctx = NULL;
619#endif // HAVE_UNICODE_SUPPORT
620 font = nbgl_getFont(fontId);
621 }
622 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
624#ifdef HAVE_UNICODE_SUPPORT
625 unicode_ctx = NULL;
626#endif // HAVE_UNICODE_SUPPORT
627 font = nbgl_getFont(fontId);
628 }
629 continue;
630 }
631
632 char_width = getCharWidth(font, unicode, is_unicode);
633 if (char_width == 0) {
634 continue;
635 }
636
637 if ((width + char_width) > maxWidth) {
638 if ((wrapping == true) && (lastDelimiter != NULL)) {
639 text = lastDelimiter;
640 lastDelimiter = NULL;
641 textLen = lenAtLastDelimiter;
642 }
643 else {
644 textLen += text - previousText;
645 text = previousText;
646 }
647 width = 0;
648 maxNbLines--;
649 continue;
650 }
651 width += char_width;
652 }
653 *len = text - origText;
654 return (maxNbLines == 0);
655}
656
672 const char *text,
673 uint16_t maxWidth,
674 uint16_t *len,
675 uint16_t *width)
676{
677 const nbgl_font_t *font = nbgl_getFont(fontId);
678 uint16_t textLen = nbgl_getTextLength(text);
679
680 *width = 0;
681 *len = 0;
682 while (textLen) {
683 const nbgl_font_character_t *character;
684 uint8_t char_width;
685 char cur_char;
686
687 textLen--;
688 cur_char = text[textLen];
689 // if \n, exit
690 if (cur_char == '\n') {
691 *len = *len + 1;
692 continue;
693 }
694
695 // skip not printable char
696 if ((cur_char < font->first_char) || (cur_char > font->last_char)) {
697 continue;
698 }
699 character
700 = (const nbgl_font_character_t *) PIC(&font->characters[cur_char - font->first_char]);
701 char_width = character->width;
702
703 if ((*width + char_width) > maxWidth) {
704 return true;
705 }
706 *len = *len + 1;
707 *width = *width + char_width;
708 }
709 return false;
710}
711
722 const char *text,
723 uint16_t maxWidth,
724 bool wrapping)
725{
726 const nbgl_font_t *font = nbgl_getFont(fontId);
727 uint16_t width = 0;
728#ifdef SCREEN_SIZE_NANO
729 uint16_t nbLines = 0;
730#else // SCREEN_SIZE_NANO
731 uint16_t nbLines = 1;
732#endif // SCREEN_SIZE_NANO
733 uint16_t textLen = strlen(text);
734 const char *lastDelimiter = NULL;
735 uint32_t lenAtLastDelimiter = 0;
736 const char *prevText = NULL;
737#ifdef HAVE_UNICODE_SUPPORT
738 nbgl_unicode_ctx_t *unicode_ctx = NULL;
739#endif // HAVE_UNICODE_SUPPORT
740
741#ifdef BUILD_SCREENSHOTS
742 hard_caesura = false;
743 last_nb_lines = 0;
744 last_nb_pages = 1;
745 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
746 bool next_bold_state = last_bold_state;
747#endif // BUILD_SCREENSHOTS
748
749 // end loop when a '\0' is uncountered
750 while (textLen) {
751 uint8_t char_width;
752 uint32_t unicode;
753 bool is_unicode;
754
755 // memorize the last char
756 prevText = text;
757 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
758#ifdef HAVE_UNICODE_SUPPORT
759 if (is_unicode && !unicode_ctx) {
760 unicode_ctx = nbgl_getUnicodeFont(fontId);
761 }
762#endif
763
764 // memorize cursors at last found space
765 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
766 lastDelimiter = prevText;
767 lenAtLastDelimiter = textLen;
768 }
769 // if \f, exit loop
770 if (unicode == '\f') {
771#ifdef BUILD_SCREENSHOTS
772 if (textLen) {
773 ++last_nb_pages;
774 }
775#endif // BUILD_SCREENSHOTS
776 break;
777 }
778 // if \n, increment the number of lines
779 else if (unicode == '\n') {
780 nbLines++;
781#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
782 if (!(nbLines % 4)) {
783 if (textLen) {
784 ++last_nb_pages;
785 }
786 }
787#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
788 width = 0;
789 lastDelimiter = NULL;
790 continue;
791 }
792 // if \b, switch fontId
793 else if (unicode == '\b') {
794 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
796#ifdef HAVE_UNICODE_SUPPORT
797 unicode_ctx = NULL;
798#endif // HAVE_UNICODE_SUPPORT
799 font = nbgl_getFont(fontId);
800#ifdef BUILD_SCREENSHOTS
801 next_bold_state = true;
802#endif // BUILD_SCREENSHOTS
803 }
804 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
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 = false;
812#endif // BUILD_SCREENSHOTS
813 }
814 continue;
815 }
816
817 char_width = getCharWidth(font, unicode, is_unicode);
818 if (char_width == 0) {
819 continue;
820 }
821#ifdef BUILD_SCREENSHOTS
822 // Update last 'displayed' char with current bold status
823 last_bold_state = next_bold_state;
824#endif // BUILD_SCREENSHOTS
825
826 // if about to reach max len, increment the number of lines
827 if ((width + char_width) > maxWidth) {
828 if ((wrapping == true) && (lastDelimiter != NULL)) {
829 text = lastDelimiter + 1;
830 lastDelimiter = NULL;
831 textLen = lenAtLastDelimiter;
832 width = 0;
833 }
834 else {
835#ifdef BUILD_SCREENSHOTS
836 // An hyphenation (caesura) has been forced.
837 hard_caesura = true;
838#endif // BUILD_SCREENSHOTS
839 width = char_width;
840 }
841 nbLines++;
842#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
843 if (!(nbLines % 4)) {
844 if (textLen) {
845 ++last_nb_pages;
846 }
847 }
848#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
849 }
850 else {
851 width += char_width;
852 }
853 }
854#ifdef SCREEN_SIZE_NANO
855 if (width != 0) {
856 ++nbLines;
857 }
858#endif // SCREEN_SIZE_NANO
859#ifdef BUILD_SCREENSHOTS
860 last_nb_lines = nbLines;
861#endif // BUILD_SCREENSHOTS
862 return nbLines;
863}
864
876 const char *text,
877 uint8_t nbLinesPerPage,
878 uint16_t maxWidth)
879{
880 const nbgl_font_t *font = nbgl_getFont(fontId);
881 uint16_t width = 0;
882 uint16_t nbLines = 0;
883 uint8_t nbPages = 1;
884 uint16_t textLen = strlen(text);
885 const char *lastDelimiter = NULL;
886 uint32_t lenAtLastDelimiter = 0;
887 const char *prevText = NULL;
888#ifdef HAVE_UNICODE_SUPPORT
889 nbgl_unicode_ctx_t *unicode_ctx = NULL;
890#endif // HAVE_UNICODE_SUPPORT
891
892#ifdef BUILD_SCREENSHOTS
893 last_nb_lines = nbLines;
894 last_nb_pages = nbPages;
895 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
896 bool next_bold_state = last_bold_state;
897#endif // BUILD_SCREENSHOTS
898 // end loop when a '\0' is uncountered
899 while (textLen) {
900 uint8_t char_width;
901 uint32_t unicode;
902 bool is_unicode;
903
904 // memorize the last char
905 prevText = text;
906 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
907#ifdef HAVE_UNICODE_SUPPORT
908 if (is_unicode && !unicode_ctx) {
909 unicode_ctx = nbgl_getUnicodeFont(fontId);
910 }
911#endif
912
913 // memorize cursors at last found space
914 if (IS_WORD_DELIM(unicode)) {
915 lastDelimiter = prevText;
916 lenAtLastDelimiter = textLen;
917 }
918 // if \f, updates page number
919 if (unicode == '\f') {
920 nbPages++;
921#ifdef BUILD_SCREENSHOTS
922#ifdef SCREEN_SIZE_NANO
923 if (width != 0) {
924#endif // SCREEN_SIZE_NANO
925 ++nbLines;
926#ifdef SCREEN_SIZE_NANO
927 }
928#endif // SCREEN_SIZE_NANO
929 if (last_nb_lines < nbLines) {
930 last_nb_lines = nbLines;
931 }
932#endif // BUILD_SCREENSHOTS
933 nbLines = 0;
934 width = 0;
935 continue;
936 }
937 // if \n, increment the number of lines
938 else if (unicode == '\n') {
939 nbLines++;
940#ifdef BUILD_SCREENSHOTS
941 if (last_nb_lines < nbLines) {
942 last_nb_lines = nbLines;
943 }
944#endif // BUILD_SCREENSHOTS
945 if (nbLines == nbLinesPerPage && textLen) {
946 nbPages++;
947 nbLines = 0;
948 }
949
950 width = 0;
951 lastDelimiter = NULL;
952 continue;
953 }
954 // if \b, switch fontId
955 else if (unicode == '\b') {
956 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
958#ifdef HAVE_UNICODE_SUPPORT
959 unicode_ctx = NULL;
960#endif // HAVE_UNICODE_SUPPORT
961 font = nbgl_getFont(fontId);
962#ifdef BUILD_SCREENSHOTS
963 next_bold_state = true;
964#endif // BUILD_SCREENSHOTS
965 }
966 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
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 = false;
974#endif // BUILD_SCREENSHOTS
975 }
976 continue;
977 }
978
979 char_width = getCharWidth(font, unicode, is_unicode);
980 if (char_width == 0) {
981 continue;
982 }
983
984#ifdef BUILD_SCREENSHOTS
985 // Update last 'displayed' char with current bold status
986 last_bold_state = next_bold_state;
987#endif // BUILD_SCREENSHOTS
988
989 // if about to reach max len, increment the number of lines/pages
990 if ((width + char_width) > maxWidth) {
991 if (lastDelimiter != NULL) {
992 text = lastDelimiter + 1;
993 lastDelimiter = NULL;
994 textLen = lenAtLastDelimiter;
995 width = 0;
996 }
997 else {
998 width = char_width;
999 }
1000 nbLines++;
1001#ifdef BUILD_SCREENSHOTS
1002 if (last_nb_lines < nbLines) {
1003 last_nb_lines = nbLines;
1004 }
1005#endif // BUILD_SCREENSHOTS
1006 if (nbLines == nbLinesPerPage) {
1007 nbPages++;
1008 nbLines = 0;
1009 }
1010 }
1011 else {
1012 width += char_width;
1013 }
1014 }
1015#ifdef BUILD_SCREENSHOTS
1016#ifdef SCREEN_SIZE_NANO
1017 if (width != 0) {
1018 ++nbLines;
1019 }
1020#endif // SCREEN_SIZE_NANO
1021 if (last_nb_lines < nbLines) {
1022 last_nb_lines = nbLines;
1023 }
1024 last_nb_pages = nbPages;
1025#endif // BUILD_SCREENSHOTS
1026 return nbPages;
1027}
1028
1039 const char *text,
1040 uint16_t maxWidth,
1041 bool wrapping)
1042{
1043 const nbgl_font_t *font = nbgl_getFont(fontId);
1044 return (nbgl_getTextNbLinesInWidth(fontId, text, maxWidth, wrapping) * font->line_height);
1045}
1046
1058void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char *text, uint16_t maxWidth, uint8_t nbLines)
1059{
1060 const nbgl_font_t *font = nbgl_getFont(fontId);
1061 uint16_t textLen = nbgl_getTextLength(text);
1062 uint16_t width = 0;
1063 uint8_t currentNbLines = 1;
1064 char *lastDelimiter = NULL;
1065 uint32_t lenAtLastDelimiter = 0;
1066 char *prevText[4] = {0}; // queue of last positions
1067 uint16_t prevWidth[2] = {0}; // queue of last widths
1068
1069#ifdef HAVE_UNICODE_SUPPORT
1070 nbgl_unicode_ctx_t *unicode_ctx = NULL;
1071#endif // HAVE_UNICODE_SUPPORT
1072
1073 while (*text) {
1074 uint8_t char_width;
1075 uint32_t unicode;
1076 bool is_unicode;
1077
1078 // memorize the last positions in the queue
1079 // the oldest is at the highest index
1080 prevText[3] = prevText[2];
1081 prevText[2] = prevText[1];
1082 prevText[1] = prevText[0];
1083 prevText[0] = text;
1084 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
1085 // if \n, reset width
1086 if (unicode == '\n') {
1087 width = 0;
1088 currentNbLines++;
1089 lastDelimiter = NULL;
1090 continue;
1091 }
1092#ifdef HAVE_UNICODE_SUPPORT
1093 if (is_unicode && !unicode_ctx) {
1094 unicode_ctx = nbgl_getUnicodeFont(fontId);
1095 }
1096#endif
1097 char_width = getCharWidth(font, unicode, is_unicode);
1098 if (char_width == 0) {
1099 continue;
1100 }
1101
1102 // memorize cursors at last found space
1103 if (IS_WORD_DELIM(unicode)) {
1104 lastDelimiter = prevText[0];
1105 lenAtLastDelimiter = textLen + 1;
1106 }
1107 // if the width is about to overpass maxWidth, do something
1108 if ((width + char_width) > maxWidth) {
1109 // if the max number of lines has not been reached, try to wrap on last space
1110 // encountered
1111 if (currentNbLines < nbLines) {
1112 currentNbLines++;
1113 // replace last found space by a \n
1114 if (lastDelimiter != NULL) {
1115 *lastDelimiter++ = '\n';
1116 text = lastDelimiter;
1117 lastDelimiter = NULL;
1118 textLen = lenAtLastDelimiter - 1;
1119 }
1120 else {
1121 textLen += text - prevText[0];
1122 text = prevText[0];
1123 }
1124 // reset width for next line
1125 width = 0;
1126 continue;
1127 }
1128 else {
1129 uint32_t i;
1130 // replace the 1, 2 or 3 last chars by '...'
1131 // try at first with 1, then with 2, if it fits
1132 for (i = 0; i < 2; i++) {
1133 if ((prevText[i + 1] != NULL)
1134 && ((prevWidth[i] + (3 * getCharWidth(font, '.', false))) <= maxWidth)) {
1135 break;
1136 }
1137 }
1138 // at worth we are sure it works by replacing the 3 last chars (if i ==2)
1139 if (prevText[i + 1] != NULL) {
1140 memcpy(prevText[i + 1], "...", 4);
1141 }
1142 return;
1143 }
1144 }
1145 // memorize the 2 last widths in a queue
1146 prevWidth[1] = prevWidth[0];
1147 prevWidth[0] = width;
1148 width += char_width;
1149 }
1150}
1151
1168 const char *origText,
1169 uint16_t maxWidth,
1170 uint8_t nbLines,
1171 char *reducedText,
1172 uint16_t reducedTextLen)
1173{
1174 const nbgl_font_t *font = nbgl_getFont(fontId);
1175 uint16_t textLen = strlen(origText);
1176 uint16_t width = 0;
1177 uint8_t currentNbLines = 1;
1178 uint32_t i = 0, j = 0;
1179 const uint16_t halfWidth = (maxWidth - nbgl_getTextWidth(fontId, " ... ")) / 2;
1180
1181 if ((nbLines & 0x1) == 0) {
1182 LOG_FATAL(MISC_LOGGER, "nbgl_textReduceOnNbLines: the number of line must be odd\n");
1183 return;
1184 }
1185 while ((i < textLen) && (j < reducedTextLen)) {
1186 uint8_t char_width;
1187 char curChar;
1188
1189 curChar = origText[i];
1190
1191 char_width = getCharWidth(font, curChar, false);
1192 if (char_width == 0) {
1193 reducedText[j] = curChar;
1194 j++;
1195 i++;
1196 continue;
1197 }
1198
1199 // if the width is about to exceed maxWidth, increment number of lines
1200 if ((width + char_width) > maxWidth) {
1201 currentNbLines++;
1202 // reset width for next line
1203 width = 0;
1204 continue;
1205 }
1206 else if ((currentNbLines == ((nbLines / 2) + 1)) && ((width + char_width) > halfWidth)) {
1207 uint32_t halfFullWidth = (nbLines / 2) * maxWidth + halfWidth;
1208 uint32_t countDown = textLen;
1209 // if this if the central line, we have to insert the '...' in the middle of it
1210 reducedText[j - 1] = '.';
1211 reducedText[j] = '.';
1212 reducedText[j + 1] = '.';
1213 // then start from the end
1214 width = 0;
1215 while (width < halfFullWidth) {
1216 countDown--;
1217 curChar = origText[countDown];
1218 char_width = getCharWidth(font, curChar, false);
1219 width += char_width;
1220 }
1221 memcpy(&reducedText[j + 2], &origText[countDown + 1], textLen - countDown + 1);
1222 return;
1223 }
1224 else {
1225 reducedText[j] = curChar;
1226 j++;
1227 i++;
1228 }
1229 width += char_width;
1230 }
1231 reducedText[j] = '\0';
1232}
1233
1234#ifdef HAVE_UNICODE_SUPPORT
1242nbgl_unicode_ctx_t *nbgl_getUnicodeFont(nbgl_font_id_e fontId)
1243{
1244 if ((unicodeCtx.font != NULL) && (unicodeCtx.font->font_id == fontId)) {
1245 return &unicodeCtx;
1246 }
1247#if defined(HAVE_LANGUAGE_PACK)
1248 // Be sure we need to change font
1249 const uint8_t *ptr = (const uint8_t *) language_pack;
1250 const nbgl_font_unicode_t *font = (const void *) (ptr + language_pack->fonts_offset);
1251 unicodeCtx.characters
1252 = (const nbgl_font_unicode_character_t *) (ptr + language_pack->characters_offset);
1253 unicodeCtx.bitmap = (const uint8_t *) (ptr + language_pack->bitmaps_offset);
1254
1255 for (uint32_t i = 0; i < language_pack->nb_fonts; i++) {
1256 if (font->font_id == fontId) {
1257 // Update all other global variables
1258 unicodeCtx.font = font;
1259 return &unicodeCtx;
1260 }
1261 // Compute next Bitmap offset
1262 unicodeCtx.bitmap += font->bitmap_len;
1263
1264 // Update all pointers for next font
1265 unicodeCtx.characters += language_pack->nb_characters;
1266 font++;
1267 }
1268#endif // defined(HAVE_LANGUAGE_PACK)
1269 // id not found
1270 return NULL;
1271}
1272
1282const nbgl_font_unicode_character_t *nbgl_getUnicodeFontCharacter(uint32_t unicode)
1283{
1284#if defined(HAVE_LANGUAGE_PACK)
1285 const nbgl_font_unicode_character_t *characters
1286 = (const nbgl_font_unicode_character_t *) PIC(unicodeCtx.characters);
1287 uint32_t n = language_pack->nb_characters;
1288 if (characters == NULL) {
1289 return NULL;
1290 }
1291 // For the moment, let just parse the full array, but at the end let use
1292 // binary search as data are sorted by unicode value !
1293 for (unsigned i = 0; i < n - 1; i++, characters++) {
1294 if (characters->char_unicode == unicode) {
1295 // Compute & store the number of bytes used to display this character
1297 = (characters + 1)->bitmap_offset - characters->bitmap_offset;
1298 return characters;
1299 }
1300 }
1301 // By default, let's use the last Unicode character, which should be the
1302 // 0x00FFFD one, used to replace unrecognized or unrepresentable character.
1303
1304 // Compute & store the number of bytes used to display this character
1306 = unicodeCtx.font->bitmap_len - characters->bitmap_offset;
1307 return characters;
1308#else // defined(HAVE_LANGUAGE_PACK)
1309 UNUSED(unicode);
1310 // id not found
1311 return NULL;
1312#endif // defined(HAVE_LANGUAGE_PACK)
1313}
1314
1321uint32_t nbgl_getUnicodeFontCharacterByteCount(void)
1322{
1323#ifdef HAVE_LANGUAGE_PACK
1324 return unicodeCtx.unicode_character_byte_count;
1325#else // defined(HAVE_LANGUAGE_PACK)
1326 return 0;
1327#endif // HAVE_LANGUAGE_PACK
1328}
1329
1330#ifdef HAVE_LANGUAGE_PACK
1338void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
1339{
1340 language_pack = lp;
1341 unicodeCtx.font = NULL;
1342 unicodeCtx.characters = NULL;
1343}
1344#endif // HAVE_LANGUAGE_PACK
1345
1346#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:472
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:412
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:875
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:324
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:362
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:562
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:671
#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:388
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:140
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:350
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:444
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:721
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:431
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:400
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:338
__attribute__((section("._nbgl_fonts_"))) const
return the non-unicode font corresponding to the given font ID
Definition nbgl_fonts.c:67
nbgl_font_id_e
Definition nbgl_fonts.h:136
@ BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
Definition nbgl_fonts.h:145
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition nbgl_fonts.h:143
#define LANGUAGE_PACK
Definition nbgl_fonts.h:29
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
#define MIN(x, y)
Definition nbgl_types.h:98
fonts nicknames to be used for various wallet size targets (non-Nano)
Definition nbgl_fonts.h:62
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:65
structure defining an ASCII font
Definition nbgl_fonts.h:76
uint8_t char_kerning
kerning for the font
Definition nbgl_fonts.h:82
uint8_t first_char
ASCII code of the first character in bitmap and in characters fields.
Definition nbgl_fonts.h:86
const nbgl_font_character_t *const characters
array containing definitions of all characters
Definition nbgl_fonts.h:90
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:80
uint8_t line_height
height of a line for all characters in pixels
Definition nbgl_fonts.h:81
uint8_t last_char
ASCII code of the last character in bitmap and in characters fields.
Definition nbgl_fonts.h:88
structure defining a unicode character (except the bitmap)
Definition nbgl_fonts.h:104
uint32_t char_unicode
plane value from 0 to 16 then 16-bit code.
Definition nbgl_fonts.h:105
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:107
uint32_t bitmap_offset
offset of this character in chars buffer
Definition nbgl_fonts.h:112
structure defining a unicode font
Definition nbgl_fonts.h:118
uint16_t bitmap_len
Size in bytes of all characters bitmaps.
Definition nbgl_fonts.h:119
uint8_t font_id
ID of the font, from nbgl_font_id_e.
Definition nbgl_fonts.h:120
const nbgl_font_unicode_character_t * characters
Definition nbgl_fonts.h:157
const nbgl_font_unicode_t * font
Definition nbgl_fonts.h:156
uint32_t unicode_character_byte_count
Definition nbgl_fonts.h:159
const uint8_t * bitmap
Definition nbgl_fonts.h:158
unsigned short uint16_t
Definition usbd_conf.h:54
unsigned char uint8_t
Definition usbd_conf.h:53