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 lastDelimiter = NULL;
610 width = 0;
611 continue;
612 }
613 // if \f, exit
614 else if (unicode == '\f') {
615 maxNbLines = 0;
616 break;
617 }
618 // if \b, switch fontId
619 else if (unicode == '\b') {
620 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
622#ifdef HAVE_UNICODE_SUPPORT
623 unicode_ctx = NULL;
624#endif // HAVE_UNICODE_SUPPORT
625 font = nbgl_getFont(fontId);
626 }
627 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
629#ifdef HAVE_UNICODE_SUPPORT
630 unicode_ctx = NULL;
631#endif // HAVE_UNICODE_SUPPORT
632 font = nbgl_getFont(fontId);
633 }
634 continue;
635 }
636
637 char_width = getCharWidth(font, unicode, is_unicode);
638 if (char_width == 0) {
639 continue;
640 }
641
642 if ((width + char_width) > maxWidth) {
643 if ((wrapping == true) && (lastDelimiter != NULL)) {
644 text = lastDelimiter;
645 lastDelimiter = NULL;
646 textLen = lenAtLastDelimiter;
647 }
648 else {
649 textLen += text - previousText;
650 text = previousText;
651 }
652 width = 0;
653 maxNbLines--;
654 continue;
655 }
656 width += char_width;
657 }
658 *len = text - origText;
659 return (maxNbLines == 0);
660}
661
677 const char *text,
678 uint16_t maxWidth,
679 uint16_t *len,
680 uint16_t *width)
681{
682 const nbgl_font_t *font = nbgl_getFont(fontId);
683 uint16_t textLen = nbgl_getTextLength(text);
684
685 *width = 0;
686 *len = 0;
687 while (textLen) {
688 const nbgl_font_character_t *character;
689 uint8_t char_width;
690 char cur_char;
691
692 textLen--;
693 cur_char = text[textLen];
694 // if \n, exit
695 if (cur_char == '\n') {
696 *len = *len + 1;
697 continue;
698 }
699
700 // skip not printable char
701 if ((cur_char < font->first_char) || (cur_char > font->last_char)) {
702 continue;
703 }
704 character
705 = (const nbgl_font_character_t *) PIC(&font->characters[cur_char - font->first_char]);
706 char_width = character->width;
707
708 if ((*width + char_width) > maxWidth) {
709 return true;
710 }
711 *len = *len + 1;
712 *width = *width + char_width;
713 }
714 return false;
715}
716
727 const char *text,
728 uint16_t maxWidth,
729 bool wrapping)
730{
731 const nbgl_font_t *font = nbgl_getFont(fontId);
732 uint16_t width = 0;
733#ifdef SCREEN_SIZE_NANO
734 uint16_t nbLines = 0;
735#else // SCREEN_SIZE_NANO
736 uint16_t nbLines = 1;
737#endif // SCREEN_SIZE_NANO
738 uint16_t textLen = strlen(text);
739 const char *lastDelimiter = NULL;
740 uint32_t lenAtLastDelimiter = 0;
741 const char *prevText = NULL;
742#ifdef HAVE_UNICODE_SUPPORT
743 nbgl_unicode_ctx_t *unicode_ctx = NULL;
744#endif // HAVE_UNICODE_SUPPORT
745
746#ifdef BUILD_SCREENSHOTS
747 hard_caesura = false;
748 last_nb_lines = 0;
749 last_nb_pages = 1;
750 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
751 bool next_bold_state = last_bold_state;
752#endif // BUILD_SCREENSHOTS
753
754 // end loop when a '\0' is uncountered
755 while (textLen) {
756 uint8_t char_width;
757 uint32_t unicode;
758 bool is_unicode;
759
760 // memorize the last char
761 prevText = text;
762 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
763#ifdef HAVE_UNICODE_SUPPORT
764 if (is_unicode && !unicode_ctx) {
765 unicode_ctx = nbgl_getUnicodeFont(fontId);
766 }
767#endif
768
769 // memorize cursors at last found space
770 if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
771 lastDelimiter = prevText;
772 lenAtLastDelimiter = textLen;
773 }
774 // if \f, exit loop
775 if (unicode == '\f') {
776#ifdef BUILD_SCREENSHOTS
777 if (textLen) {
778 ++last_nb_pages;
779 }
780#endif // BUILD_SCREENSHOTS
781 break;
782 }
783 // if \n, increment the number of lines
784 else if (unicode == '\n') {
785 nbLines++;
786#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
787 if (!(nbLines % 4)) {
788 if (textLen) {
789 ++last_nb_pages;
790 }
791 }
792#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
793 width = 0;
794 lastDelimiter = NULL;
795 continue;
796 }
797 // if \b, switch fontId
798 else if (unicode == '\b') {
799 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
801#ifdef HAVE_UNICODE_SUPPORT
802 unicode_ctx = NULL;
803#endif // HAVE_UNICODE_SUPPORT
804 font = nbgl_getFont(fontId);
805#ifdef BUILD_SCREENSHOTS
806 next_bold_state = true;
807#endif // BUILD_SCREENSHOTS
808 }
809 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
811#ifdef HAVE_UNICODE_SUPPORT
812 unicode_ctx = NULL;
813#endif // HAVE_UNICODE_SUPPORT
814 font = nbgl_getFont(fontId);
815#ifdef BUILD_SCREENSHOTS
816 next_bold_state = false;
817#endif // BUILD_SCREENSHOTS
818 }
819 continue;
820 }
821
822 char_width = getCharWidth(font, unicode, is_unicode);
823 if (char_width == 0) {
824 continue;
825 }
826#ifdef BUILD_SCREENSHOTS
827 // Update last 'displayed' char with current bold status
828 last_bold_state = next_bold_state;
829#endif // BUILD_SCREENSHOTS
830
831 // if about to reach max len, increment the number of lines
832 if ((width + char_width) > maxWidth) {
833 if ((wrapping == true) && (lastDelimiter != NULL)) {
834 text = lastDelimiter + 1;
835 lastDelimiter = NULL;
836 textLen = lenAtLastDelimiter;
837 width = 0;
838 }
839 else {
840#ifdef BUILD_SCREENSHOTS
841 // An hyphenation (caesura) has been forced.
842 hard_caesura = true;
843#endif // BUILD_SCREENSHOTS
844 width = char_width;
845 }
846 nbLines++;
847#if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
848 if (!(nbLines % 4)) {
849 if (textLen) {
850 ++last_nb_pages;
851 }
852 }
853#endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
854 }
855 else {
856 width += char_width;
857 }
858 }
859#ifdef SCREEN_SIZE_NANO
860 if (width != 0) {
861 ++nbLines;
862 }
863#endif // SCREEN_SIZE_NANO
864#ifdef BUILD_SCREENSHOTS
865 last_nb_lines = nbLines;
866#endif // BUILD_SCREENSHOTS
867 return nbLines;
868}
869
881 const char *text,
882 uint8_t nbLinesPerPage,
883 uint16_t maxWidth)
884{
885 const nbgl_font_t *font = nbgl_getFont(fontId);
886 uint16_t width = 0;
887 uint16_t nbLines = 0;
888 uint8_t nbPages = 1;
889 uint16_t textLen = strlen(text);
890 const char *lastDelimiter = NULL;
891 uint32_t lenAtLastDelimiter = 0;
892 const char *prevText = NULL;
893#ifdef HAVE_UNICODE_SUPPORT
894 nbgl_unicode_ctx_t *unicode_ctx = NULL;
895#endif // HAVE_UNICODE_SUPPORT
896
897#ifdef BUILD_SCREENSHOTS
898 last_nb_lines = nbLines;
899 last_nb_pages = nbPages;
900 last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
901 bool next_bold_state = last_bold_state;
902#endif // BUILD_SCREENSHOTS
903 // end loop when a '\0' is uncountered
904 while (textLen) {
905 uint8_t char_width;
906 uint32_t unicode;
907 bool is_unicode;
908
909 // memorize the last char
910 prevText = text;
911 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
912#ifdef HAVE_UNICODE_SUPPORT
913 if (is_unicode && !unicode_ctx) {
914 unicode_ctx = nbgl_getUnicodeFont(fontId);
915 }
916#endif
917
918 // memorize cursors at last found space
919 if (IS_WORD_DELIM(unicode)) {
920 lastDelimiter = prevText;
921 lenAtLastDelimiter = textLen;
922 }
923 // if \f, updates page number
924 if (unicode == '\f') {
925 nbPages++;
926#ifdef BUILD_SCREENSHOTS
927#ifdef SCREEN_SIZE_NANO
928 if (width != 0) {
929#endif // SCREEN_SIZE_NANO
930 ++nbLines;
931#ifdef SCREEN_SIZE_NANO
932 }
933#endif // SCREEN_SIZE_NANO
934 if (last_nb_lines < nbLines) {
935 last_nb_lines = nbLines;
936 }
937#endif // BUILD_SCREENSHOTS
938 nbLines = 0;
939 width = 0;
940 continue;
941 }
942 // if \n, increment the number of lines
943 else if (unicode == '\n') {
944 nbLines++;
945#ifdef BUILD_SCREENSHOTS
946 if (last_nb_lines < nbLines) {
947 last_nb_lines = nbLines;
948 }
949#endif // BUILD_SCREENSHOTS
950 if (nbLines == nbLinesPerPage && textLen) {
951 nbPages++;
952 nbLines = 0;
953 }
954
955 width = 0;
956 lastDelimiter = NULL;
957 continue;
958 }
959 // if \b, switch fontId
960 else if (unicode == '\b') {
961 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
963#ifdef HAVE_UNICODE_SUPPORT
964 unicode_ctx = NULL;
965#endif // HAVE_UNICODE_SUPPORT
966 font = nbgl_getFont(fontId);
967#ifdef BUILD_SCREENSHOTS
968 next_bold_state = true;
969#endif // BUILD_SCREENSHOTS
970 }
971 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
973#ifdef HAVE_UNICODE_SUPPORT
974 unicode_ctx = NULL;
975#endif // HAVE_UNICODE_SUPPORT
976 font = nbgl_getFont(fontId);
977#ifdef BUILD_SCREENSHOTS
978 next_bold_state = false;
979#endif // BUILD_SCREENSHOTS
980 }
981 continue;
982 }
983
984 char_width = getCharWidth(font, unicode, is_unicode);
985 if (char_width == 0) {
986 continue;
987 }
988
989#ifdef BUILD_SCREENSHOTS
990 // Update last 'displayed' char with current bold status
991 last_bold_state = next_bold_state;
992#endif // BUILD_SCREENSHOTS
993
994 // if about to reach max len, increment the number of lines/pages
995 if ((width + char_width) > maxWidth) {
996 if (lastDelimiter != NULL) {
997 text = lastDelimiter + 1;
998 lastDelimiter = NULL;
999 textLen = lenAtLastDelimiter;
1000 width = 0;
1001 }
1002 else {
1003 width = char_width;
1004 }
1005 nbLines++;
1006#ifdef BUILD_SCREENSHOTS
1007 if (last_nb_lines < nbLines) {
1008 last_nb_lines = nbLines;
1009 }
1010#endif // BUILD_SCREENSHOTS
1011 if (nbLines == nbLinesPerPage) {
1012 nbPages++;
1013 nbLines = 0;
1014 }
1015 }
1016 else {
1017 width += char_width;
1018 }
1019 }
1020#ifdef BUILD_SCREENSHOTS
1021#ifdef SCREEN_SIZE_NANO
1022 if (width != 0) {
1023 ++nbLines;
1024 }
1025#endif // SCREEN_SIZE_NANO
1026 if (last_nb_lines < nbLines) {
1027 last_nb_lines = nbLines;
1028 }
1029 last_nb_pages = nbPages;
1030#endif // BUILD_SCREENSHOTS
1031 return nbPages;
1032}
1033
1044 const char *text,
1045 uint16_t maxWidth,
1046 bool wrapping)
1047{
1048 const nbgl_font_t *font = nbgl_getFont(fontId);
1049 return (nbgl_getTextNbLinesInWidth(fontId, text, maxWidth, wrapping) * font->line_height);
1050}
1051
1063void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char *text, uint16_t maxWidth, uint8_t nbLines)
1064{
1065 const nbgl_font_t *font = nbgl_getFont(fontId);
1066 uint16_t textLen = nbgl_getTextLength(text);
1067 uint16_t width = 0;
1068 uint8_t currentNbLines = 1;
1069 char *lastDelimiter = NULL;
1070 uint32_t lenAtLastDelimiter = 0;
1071 char *prevText[4] = {0}; // queue of last positions
1072 uint16_t prevWidth[2] = {0}; // queue of last widths
1073
1074#ifdef HAVE_UNICODE_SUPPORT
1075 nbgl_unicode_ctx_t *unicode_ctx = NULL;
1076#endif // HAVE_UNICODE_SUPPORT
1077
1078 while (*text) {
1079 uint8_t char_width;
1080 uint32_t unicode;
1081 bool is_unicode;
1082
1083 // memorize the last positions in the queue
1084 // the oldest is at the highest index
1085 prevText[3] = prevText[2];
1086 prevText[2] = prevText[1];
1087 prevText[1] = prevText[0];
1088 prevText[0] = text;
1089 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
1090 // if \n, reset width
1091 if (unicode == '\n') {
1092 width = 0;
1093 currentNbLines++;
1094 lastDelimiter = NULL;
1095 continue;
1096 }
1097#ifdef HAVE_UNICODE_SUPPORT
1098 if (is_unicode && !unicode_ctx) {
1099 unicode_ctx = nbgl_getUnicodeFont(fontId);
1100 }
1101#endif
1102 char_width = getCharWidth(font, unicode, is_unicode);
1103 if (char_width == 0) {
1104 continue;
1105 }
1106
1107 // memorize cursors at last found space
1108 if (IS_WORD_DELIM(unicode)) {
1109 lastDelimiter = prevText[0];
1110 lenAtLastDelimiter = textLen + 1;
1111 }
1112 // if the width is about to overpass maxWidth, do something
1113 if ((width + char_width) > maxWidth) {
1114 // if the max number of lines has not been reached, try to wrap on last space
1115 // encountered
1116 if (currentNbLines < nbLines) {
1117 currentNbLines++;
1118 // replace last found space by a \n
1119 if (lastDelimiter != NULL) {
1120 *lastDelimiter++ = '\n';
1121 text = lastDelimiter;
1122 lastDelimiter = NULL;
1123 textLen = lenAtLastDelimiter - 1;
1124 }
1125 else {
1126 textLen += text - prevText[0];
1127 text = prevText[0];
1128 }
1129 // reset width for next line
1130 width = 0;
1131 continue;
1132 }
1133 else {
1134 uint32_t i;
1135 // replace the 1, 2 or 3 last chars by '...'
1136 // try at first with 1, then with 2, if it fits
1137 for (i = 0; i < 2; i++) {
1138 if ((prevText[i + 1] != NULL)
1139 && ((prevWidth[i] + (3 * getCharWidth(font, '.', false))) <= maxWidth)) {
1140 break;
1141 }
1142 }
1143 // at worth we are sure it works by replacing the 3 last chars (if i ==2)
1144 if (prevText[i + 1] != NULL) {
1145 memcpy(prevText[i + 1], "...", 4);
1146 }
1147 return;
1148 }
1149 }
1150 // memorize the 2 last widths in a queue
1151 prevWidth[1] = prevWidth[0];
1152 prevWidth[0] = width;
1153 width += char_width;
1154 }
1155}
1156
1173 const char *origText,
1174 uint16_t maxWidth,
1175 uint8_t nbLines,
1176 char *reducedText,
1177 uint16_t reducedTextLen)
1178{
1179 const nbgl_font_t *font = nbgl_getFont(fontId);
1180 uint16_t textLen = strlen(origText);
1181 uint16_t width = 0;
1182 uint8_t currentNbLines = 1;
1183 uint32_t i = 0, j = 0;
1184 const uint16_t halfWidth = (maxWidth - nbgl_getTextWidth(fontId, " ... ")) / 2;
1185
1186 if ((nbLines & 0x1) == 0) {
1187 LOG_FATAL(MISC_LOGGER, "nbgl_textReduceOnNbLines: the number of line must be odd\n");
1188 return;
1189 }
1190 while ((i < textLen) && (j < reducedTextLen)) {
1191 uint8_t char_width;
1192 char curChar;
1193
1194 curChar = origText[i];
1195
1196 char_width = getCharWidth(font, curChar, false);
1197 if (char_width == 0) {
1198 reducedText[j] = curChar;
1199 j++;
1200 i++;
1201 continue;
1202 }
1203
1204 // if the width is about to exceed maxWidth, increment number of lines
1205 if ((width + char_width) > maxWidth) {
1206 currentNbLines++;
1207 // reset width for next line
1208 width = 0;
1209 continue;
1210 }
1211 else if ((currentNbLines == ((nbLines / 2) + 1)) && ((width + char_width) > halfWidth)) {
1212 uint32_t halfFullWidth = (nbLines / 2) * maxWidth + halfWidth;
1213 uint32_t countDown = textLen;
1214 // if this if the central line, we have to insert the '...' in the middle of it
1215 reducedText[j - 1] = '.';
1216 reducedText[j] = '.';
1217 reducedText[j + 1] = '.';
1218 // then start from the end
1219 width = 0;
1220 while (width < halfFullWidth) {
1221 countDown--;
1222 curChar = origText[countDown];
1223 char_width = getCharWidth(font, curChar, false);
1224 width += char_width;
1225 }
1226 memcpy(&reducedText[j + 2], &origText[countDown + 1], textLen - countDown + 1);
1227 return;
1228 }
1229 else {
1230 reducedText[j] = curChar;
1231 j++;
1232 i++;
1233 }
1234 width += char_width;
1235 }
1236 reducedText[j] = '\0';
1237}
1238
1239#ifdef HAVE_UNICODE_SUPPORT
1247nbgl_unicode_ctx_t *nbgl_getUnicodeFont(nbgl_font_id_e fontId)
1248{
1249 if ((unicodeCtx.font != NULL) && (unicodeCtx.font->font_id == fontId)) {
1250 return &unicodeCtx;
1251 }
1252#if defined(HAVE_LANGUAGE_PACK)
1253 // Be sure we need to change font
1254 const uint8_t *ptr = (const uint8_t *) language_pack;
1255 const nbgl_font_unicode_t *font = (const void *) (ptr + language_pack->fonts_offset);
1256 unicodeCtx.characters
1257 = (const nbgl_font_unicode_character_t *) (ptr + language_pack->characters_offset);
1258 unicodeCtx.bitmap = (const uint8_t *) (ptr + language_pack->bitmaps_offset);
1259
1260 for (uint32_t i = 0; i < language_pack->nb_fonts; i++) {
1261 if (font->font_id == fontId) {
1262 // Update all other global variables
1263 unicodeCtx.font = font;
1264 return &unicodeCtx;
1265 }
1266 // Compute next Bitmap offset
1267 unicodeCtx.bitmap += font->bitmap_len;
1268
1269 // Update all pointers for next font
1270 unicodeCtx.characters += language_pack->nb_characters;
1271 font++;
1272 }
1273#endif // defined(HAVE_LANGUAGE_PACK)
1274 // id not found
1275 return NULL;
1276}
1277
1287const nbgl_font_unicode_character_t *nbgl_getUnicodeFontCharacter(uint32_t unicode)
1288{
1289#if defined(HAVE_LANGUAGE_PACK)
1290 const nbgl_font_unicode_character_t *characters
1291 = (const nbgl_font_unicode_character_t *) PIC(unicodeCtx.characters);
1292 uint32_t n = language_pack->nb_characters;
1293 if (characters == NULL) {
1294 return NULL;
1295 }
1296 // For the moment, let just parse the full array, but at the end let use
1297 // binary search as data are sorted by unicode value !
1298 for (unsigned i = 0; i < n - 1; i++, characters++) {
1299 if (characters->char_unicode == unicode) {
1300 // Compute & store the number of bytes used to display this character
1302 = (characters + 1)->bitmap_offset - characters->bitmap_offset;
1303 return characters;
1304 }
1305 }
1306 // By default, let's use the last Unicode character, which should be the
1307 // 0x00FFFD one, used to replace unrecognized or unrepresentable character.
1308
1309 // Compute & store the number of bytes used to display this character
1311 = unicodeCtx.font->bitmap_len - characters->bitmap_offset;
1312 return characters;
1313#else // defined(HAVE_LANGUAGE_PACK)
1314 UNUSED(unicode);
1315 // id not found
1316 return NULL;
1317#endif // defined(HAVE_LANGUAGE_PACK)
1318}
1319
1326uint32_t nbgl_getUnicodeFontCharacterByteCount(void)
1327{
1328#ifdef HAVE_LANGUAGE_PACK
1329 return unicodeCtx.unicode_character_byte_count;
1330#else // defined(HAVE_LANGUAGE_PACK)
1331 return 0;
1332#endif // HAVE_LANGUAGE_PACK
1333}
1334
1335#ifdef HAVE_LANGUAGE_PACK
1343void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
1344{
1345 language_pack = lp;
1346 unicodeCtx.font = NULL;
1347 unicodeCtx.characters = NULL;
1348}
1349#endif // HAVE_LANGUAGE_PACK
1350
1351#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:880
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:676
#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:726
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