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