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