Embedded SDK
Embedded SDK
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
36 static nbgl_unicode_ctx_t unicodeCtx = {0};
37 #endif // HAVE_UNICODE_SUPPORT
38 
39 /**********************
40  * VARIABLES
41  **********************/
42 
43 #ifdef HAVE_LANGUAGE_PACK
44 static const LANGUAGE_PACK *language_pack;
45 #endif // HAVE_LANGUAGE_PACK
46 
47 #if defined(BOLOS_OS_UPGRADER_APP)
48 #ifdef SCREEN_SIZE_WALLET
49 #ifdef TARGET_STAX
50 #include "nbgl_font_inter_regular_24.inc"
51 #include "nbgl_font_inter_semibold_24.inc"
52 #include "nbgl_font_inter_medium_32.inc"
53 #include "nbgl_font_inter_regular_24_1bpp.inc"
54 #include "nbgl_font_inter_semibold_24_1bpp.inc"
55 #include "nbgl_font_inter_medium_32_1bpp.inc"
56 #else // TARGET_STAX
57 #include "nbgl_font_inter_regular_28.inc"
58 #include "nbgl_font_inter_semibold_28.inc"
59 #include "nbgl_font_inter_medium_36.inc"
60 #include "nbgl_font_inter_regular_28_1bpp.inc"
61 #include "nbgl_font_inter_semibold_28_1bpp.inc"
62 #include "nbgl_font_inter_medium_36_1bpp.inc"
63 #endif // TARGET_STAX
64 #else // SCREEN_SIZE_WALLET
65 #include "nbgl_font_open_sans_extrabold_11.inc"
66 #include "nbgl_font_open_sans_regular_11.inc"
67 #include "nbgl_font_open_sans_light_16.inc"
68 #endif // SCREEN_SIZE_WALLET
69 
70 const nbgl_font_t *const C_nbgl_fonts[] = {
71 
72 #include "nbgl_font_rom_struct.inc"
73 
74 };
75 const unsigned int C_nbgl_fonts_count = sizeof(C_nbgl_fonts) / sizeof(C_nbgl_fonts[0]);
76 
77 #endif
78 
79 #if (defined(HAVE_BOLOS) && !defined(BOLOS_OS_UPGRADER_APP))
80 #if !defined(HAVE_LANGUAGE_PACK)
81 const 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!
88 const 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)
97 uint16_t last_nb_lines = 0;
98 uint16_t last_nb_pages = 0;
99 bool last_bold_state = false;
100 
101 // Used to detect when a hyphenation (caesura) has been forced.
102 bool hard_caesura = false;
103 #endif // BUILD_SCREENSHOTS
104 
105 /**********************
106  * STATIC PROTOTYPES
107  **********************/
108 
109 /**********************
110  * GLOBAL FUNCTIONS
111  **********************/
112 
119 #if defined(BOLOS_OS_UPGRADER_APP)
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 #else
137 {
138  return nbgl_font_getFont(fontId);
139 }
140 #endif // BOLOS_OS_UPGRADER_APP
150 uint32_t nbgl_popUnicodeChar(const uint8_t **text, uint16_t *textLen, bool *is_unicode)
151 {
152  const uint8_t *txt = *text;
153  uint8_t cur_char = *txt++;
154  uint32_t unicode;
155 
156  *is_unicode = true;
157  // Handle UTF-8 decoding (RFC3629): (https://www.ietf.org/rfc/rfc3629.txt
158  // Char. number range | UTF-8 octet sequence
159  // (hexadecimal) | (binary)
160  // --------------------+---------------------------------------------
161  // 0000 0000-0000 007F | 0xxxxxxx
162  // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
163  // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
164  // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
165 
166  // 4 bytes UTF-8, Unicode 0x1000 to 0x1FFFF
167  if ((cur_char >= 0xF0) && (*textLen >= 4)) {
168  unicode = (cur_char & 0x07) << 18;
169  unicode |= (*txt++ & 0x3F) << 12;
170  unicode |= (*txt++ & 0x3F) << 6;
171  unicode |= (*txt++ & 0x3F);
172 
173  // 3 bytes, from 0x800 to 0xFFFF
174  }
175  else if ((cur_char >= 0xE0) && (*textLen >= 3)) {
176  unicode = (cur_char & 0x0F) << 12;
177  unicode |= (*txt++ & 0x3F) << 6;
178  unicode |= (*txt++ & 0x3F);
179 
180  // 2 bytes UTF-8, Unicode 0x80 to 0x7FF
181  // (0xC0 & 0xC1 are unused and can be used to store something else)
182  }
183  else if ((cur_char >= 0xC2) && (*textLen >= 2)) {
184  unicode = (cur_char & 0x1F) << 6;
185  unicode |= (*txt++ & 0x3F);
186  }
187  else {
188  *is_unicode = false;
189  unicode = cur_char;
190  }
191  *textLen = *textLen - (txt - *text);
192  *text = txt;
193  return unicode;
194 }
195 
204 static uint8_t getCharWidth(const nbgl_font_t *font, uint32_t unicode, bool is_unicode)
205 {
206  if (is_unicode) {
207 #ifdef HAVE_UNICODE_SUPPORT
208  const nbgl_font_unicode_character_t *unicodeCharacter
209  = nbgl_getUnicodeFontCharacter(unicode);
210  if (!unicodeCharacter) {
211  return 0;
212  }
213  return unicodeCharacter->width - font->char_kerning;
214 #else // HAVE_UNICODE_SUPPORT
215  return 0;
216 #endif // HAVE_UNICODE_SUPPORT
217  }
218  else {
219  const nbgl_font_character_t *character; // non-unicode char
220  if ((unicode < font->first_char) || (unicode > font->last_char)) {
221  return 0;
222  }
223  character
224  = (const nbgl_font_character_t *) PIC(&font->characters[unicode - font->first_char]);
225  return character->width - font->char_kerning;
226  }
227 }
228 
239 static uint16_t getTextWidth(nbgl_font_id_e fontId,
240  const char *text,
241  bool breakOnLineEnd,
242  uint16_t maxLen)
243 {
244 #ifdef BUILD_SCREENSHOTS
245  uint16_t nb_lines = 0;
246 #endif // BUILD_SCREENSHOTS
247  uint16_t line_width = 0;
248  uint16_t max_width = 0;
249  const nbgl_font_t *font = nbgl_getFont(fontId);
250  uint16_t textLen = MIN(strlen(text), maxLen);
251 #ifdef HAVE_UNICODE_SUPPORT
252  nbgl_unicode_ctx_t *unicode_ctx = NULL;
253 #endif // HAVE_UNICODE_SUPPORT
254 
255 #ifdef BUILD_SCREENSHOTS
256  last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
257  bool next_bold_state = last_bold_state;
258 #endif // BUILD_SCREENSHOTS
259 
260  // end loop text len is NULL (max reached)
261  while (textLen) {
262  uint8_t char_width;
263  uint32_t unicode;
264  bool is_unicode;
265 
266  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
267 #ifdef HAVE_UNICODE_SUPPORT
268  if (is_unicode && !unicode_ctx) {
269  unicode_ctx = nbgl_getUnicodeFont(fontId);
270  }
271 #endif
272  if (unicode == '\n') {
273  if (breakOnLineEnd) {
274  break;
275  }
276  // reset line width for next line
277  line_width = 0;
278  continue;
279  }
280  // if \b, switch fontId
281  else if (unicode == '\b') {
282  if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
284 #ifdef HAVE_UNICODE_SUPPORT
285  unicode_ctx = NULL;
286 #endif // HAVE_UNICODE_SUPPORT
287  font = nbgl_getFont(fontId);
288 #ifdef BUILD_SCREENSHOTS
289  next_bold_state = true;
290 #endif // BUILD_SCREENSHOTS
291  }
292  else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
294 #ifdef HAVE_UNICODE_SUPPORT
295  unicode_ctx = NULL;
296 #endif // HAVE_UNICODE_SUPPORT
297  font = nbgl_getFont(fontId);
298 #ifdef BUILD_SCREENSHOTS
299  next_bold_state = false;
300 #endif // BUILD_SCREENSHOTS
301  }
302  continue;
303  }
304  char_width = getCharWidth(font, unicode, is_unicode);
305 #ifdef BUILD_SCREENSHOTS
306  if (char_width != 0) {
307  // Update last 'displayed' char with current bold status
308  last_bold_state = next_bold_state;
309  }
310 #endif // BUILD_SCREENSHOTS
311  line_width += char_width;
312  // memorize max line width if greater than current
313  if (line_width > max_width) {
314  max_width = line_width;
315  }
316  }
317 #ifdef BUILD_SCREENSHOTS
318  if (line_width != 0) {
319  ++nb_lines;
320  }
321  last_nb_lines = nb_lines;
322 #endif // BUILD_SCREENSHOTS
323 
324  return max_width;
325 }
326 
335 {
336  return getTextWidth(fontId, text, true, 0xFFFF);
337 }
338 
349 {
350  return getTextWidth(fontId, text, true, maxLen);
351 }
352 
360 uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
361 {
362  return getTextWidth(fontId, text, false, 0xFFFF);
363 }
364 
372 uint8_t nbgl_getCharWidth(nbgl_font_id_e fontId, const char *text)
373 {
374  const nbgl_font_t *font = nbgl_getFont(fontId);
375  uint32_t unicode;
376  bool is_unicode;
377  uint16_t textLen = 4; // max len for a char
378 #ifdef HAVE_UNICODE_SUPPORT
379  nbgl_unicode_ctx_t *unicode_ctx = NULL;
380 #endif // HAVE_UNICODE_SUPPORT
381 
382  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
383 #ifdef HAVE_UNICODE_SUPPORT
384  if (is_unicode && !unicode_ctx) {
385  unicode_ctx = nbgl_getUnicodeFont(fontId);
386  }
387 #endif
388 
389  return getCharWidth(font, unicode, is_unicode);
390 }
391 
399 {
400  const nbgl_font_t *font = nbgl_getFont(fontId);
401  return font->height;
402 }
403 
411 {
412  const nbgl_font_t *font = nbgl_getFont(fontId);
413  return font->line_height;
414 }
415 
422 uint16_t nbgl_getTextNbLines(const char *text)
423 {
424  uint16_t nbLines = 1;
425  while (*text) {
426  if (*text == '\n') {
427  nbLines++;
428  }
429  text++;
430  }
431  return nbLines;
432 }
433 
441 uint16_t nbgl_getTextHeight(nbgl_font_id_e fontId, const char *text)
442 {
443  const nbgl_font_t *font = nbgl_getFont(fontId);
444  return (nbgl_getTextNbLines(text) * font->line_height);
445 }
446 
454 uint16_t nbgl_getTextLength(const char *text)
455 {
456  const char *origText = text;
457  while (*text) {
458  if (*text == '\f') {
459  break;
460  }
461  else if (*text == '\n') {
462  break;
463  }
464  text++;
465  }
466  return text - origText;
467 }
468 
483  const char *text,
484  uint16_t maxWidth,
485  uint16_t *len,
486  uint16_t *width,
487  bool wrapping)
488 {
489  const nbgl_font_t *font = nbgl_getFont(fontId);
490  uint16_t textLen = nbgl_getTextLength(text);
491  uint32_t lenAtLastDelimiter = 0, widthAtlastDelimiter = 0;
492 #ifdef HAVE_UNICODE_SUPPORT
493  nbgl_unicode_ctx_t *unicode_ctx = NULL;
494 #endif // HAVE_UNICODE_SUPPORT
495 
496  *width = 0;
497  *len = 0;
498  while (textLen) {
499  uint8_t char_width;
500  uint32_t unicode;
501  bool is_unicode;
502  uint16_t curTextLen = textLen;
503 
504  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
505 #ifdef HAVE_UNICODE_SUPPORT
506  if (is_unicode && !unicode_ctx) {
507  unicode_ctx = nbgl_getUnicodeFont(fontId);
508  }
509 #endif
510  // if \f or \n, exit loop
511  if ((unicode == '\f') || (unicode == '\n')) {
512  *len += curTextLen - textLen;
513  return;
514  }
515  // if \b, switch fontId
516  else if (unicode == '\b') {
517  if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
519 #ifdef HAVE_UNICODE_SUPPORT
520  unicode_ctx = NULL;
521 #endif // HAVE_UNICODE_SUPPORT
522  font = nbgl_getFont(fontId);
523  }
524  else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
526 #ifdef HAVE_UNICODE_SUPPORT
527  unicode_ctx = NULL;
528 #endif // HAVE_UNICODE_SUPPORT
529  font = nbgl_getFont(fontId);
530  }
531  *len += curTextLen - textLen;
532  continue;
533  }
534 
535  char_width = getCharWidth(font, unicode, is_unicode);
536  if (char_width == 0) {
537  *len += curTextLen - textLen;
538  continue;
539  }
540 
541  // memorize cursors at last found sepator, when wrapping
542  if ((wrapping == true) && IS_WORD_DELIM(unicode)) {
543  lenAtLastDelimiter = *len;
544  widthAtlastDelimiter = *width;
545  }
546  if ((*width + char_width) > maxWidth) {
547  if ((wrapping == true) && (widthAtlastDelimiter > 0)) {
548  *len = lenAtLastDelimiter + 1;
549  *width = widthAtlastDelimiter;
550  }
551  return;
552  }
553  *len += curTextLen - textLen;
554  *width = *width + char_width;
555  }
556 }
557 
573  const char *text,
574  uint16_t maxWidth,
575  uint16_t maxNbLines,
576  uint16_t *len,
577  bool wrapping)
578 {
579  const nbgl_font_t *font = nbgl_getFont(fontId);
580  uint16_t textLen = strlen(text);
581  uint16_t width = 0;
582  const char *lastDelimiter = NULL;
583  uint32_t lenAtLastDelimiter = 0;
584  const char *origText = text;
585  const char *previousText;
586 #ifdef HAVE_UNICODE_SUPPORT
587  nbgl_unicode_ctx_t *unicode_ctx = NULL;
588 #endif // HAVE_UNICODE_SUPPORT
589 
590  while ((textLen) && (maxNbLines > 0)) {
591  uint8_t char_width;
592  uint32_t unicode;
593  bool is_unicode;
594 
595  previousText = text;
596  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
597 #ifdef HAVE_UNICODE_SUPPORT
598  if (is_unicode && !unicode_ctx) {
599  unicode_ctx = nbgl_getUnicodeFont(fontId);
600  }
601 #endif
602  // memorize cursors at last found delimiter
603  if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
604  lastDelimiter = text;
605  lenAtLastDelimiter = textLen;
606  }
607 
608  // if \n, reset width
609  if (unicode == '\n') {
610  maxNbLines--;
611  // if last line is reached, let's rewind before carriage return
612  if (maxNbLines == 0) {
613  text--;
614  }
615  width = 0;
616  continue;
617  }
618  // if \f, exit
619  else if (unicode == '\f') {
620  maxNbLines = 0;
621  break;
622  }
623  // if \b, switch fontId
624  else if (unicode == '\b') {
625  if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
627 #ifdef HAVE_UNICODE_SUPPORT
628  unicode_ctx = NULL;
629 #endif // HAVE_UNICODE_SUPPORT
630  font = nbgl_getFont(fontId);
631  }
632  else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
634 #ifdef HAVE_UNICODE_SUPPORT
635  unicode_ctx = NULL;
636 #endif // HAVE_UNICODE_SUPPORT
637  font = nbgl_getFont(fontId);
638  }
639  continue;
640  }
641 
642  char_width = getCharWidth(font, unicode, is_unicode);
643  if (char_width == 0) {
644  continue;
645  }
646 
647  if ((width + char_width) > maxWidth) {
648  if ((wrapping == true) && (lastDelimiter != NULL)) {
649  text = lastDelimiter;
650  lastDelimiter = NULL;
651  textLen = lenAtLastDelimiter;
652  }
653  else {
654  textLen += text - previousText;
655  text = previousText;
656  }
657  width = 0;
658  maxNbLines--;
659  continue;
660  }
661  width += char_width;
662  }
663  *len = text - origText;
664  return (maxNbLines == 0);
665 }
666 
682  const char *text,
683  uint16_t maxWidth,
684  uint16_t *len,
685  uint16_t *width)
686 {
687  const nbgl_font_t *font = nbgl_getFont(fontId);
688  uint16_t textLen = nbgl_getTextLength(text);
689 
690  *width = 0;
691  *len = 0;
692  while (textLen) {
693  const nbgl_font_character_t *character;
694  uint8_t char_width;
695  char cur_char;
696 
697  textLen--;
698  cur_char = text[textLen];
699  // if \n, exit
700  if (cur_char == '\n') {
701  *len = *len + 1;
702  continue;
703  }
704 
705  // skip not printable char
706  if ((cur_char < font->first_char) || (cur_char > font->last_char)) {
707  continue;
708  }
709  character
710  = (const nbgl_font_character_t *) PIC(&font->characters[cur_char - font->first_char]);
711  char_width = character->width;
712 
713  if ((*width + char_width) > maxWidth) {
714  return true;
715  }
716  *len = *len + 1;
717  *width = *width + char_width;
718  }
719  return false;
720 }
721 
732  const char *text,
733  uint16_t maxWidth,
734  bool wrapping)
735 {
736  const nbgl_font_t *font = nbgl_getFont(fontId);
737  uint16_t width = 0;
738 #ifdef SCREEN_SIZE_NANO
739  uint16_t nbLines = 0;
740 #else // SCREEN_SIZE_NANO
741  uint16_t nbLines = 1;
742 #endif // SCREEN_SIZE_NANO
743  uint16_t textLen = strlen(text);
744  const char *lastDelimiter = NULL;
745  uint32_t lenAtLastDelimiter = 0;
746  const char *prevText = NULL;
747 #ifdef HAVE_UNICODE_SUPPORT
748  nbgl_unicode_ctx_t *unicode_ctx = NULL;
749 #endif // HAVE_UNICODE_SUPPORT
750 
751 #ifdef BUILD_SCREENSHOTS
752  hard_caesura = false;
753  last_nb_lines = 0;
754  last_nb_pages = 1;
755  last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
756  bool next_bold_state = last_bold_state;
757 #endif // BUILD_SCREENSHOTS
758 
759  // end loop when a '\0' is uncountered
760  while (textLen) {
761  uint8_t char_width;
762  uint32_t unicode;
763  bool is_unicode;
764 
765  // memorize the last char
766  prevText = text;
767  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
768 #ifdef HAVE_UNICODE_SUPPORT
769  if (is_unicode && !unicode_ctx) {
770  unicode_ctx = nbgl_getUnicodeFont(fontId);
771  }
772 #endif
773 
774  // memorize cursors at last found space
775  if ((wrapping == true) && (IS_WORD_DELIM(unicode))) {
776  lastDelimiter = prevText;
777  lenAtLastDelimiter = textLen;
778  }
779  // if \f, exit loop
780  if (unicode == '\f') {
781 #ifdef BUILD_SCREENSHOTS
782  if (textLen) {
783  ++last_nb_pages;
784  }
785 #endif // BUILD_SCREENSHOTS
786  break;
787  }
788  // if \n, increment the number of lines
789  else if (unicode == '\n') {
790  nbLines++;
791 #if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
792  if (!(nbLines % 4)) {
793  if (textLen) {
794  ++last_nb_pages;
795  }
796  }
797 #endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
798  width = 0;
799  lastDelimiter = NULL;
800  continue;
801  }
802  // if \b, switch fontId
803  else if (unicode == '\b') {
804  if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
806 #ifdef HAVE_UNICODE_SUPPORT
807  unicode_ctx = NULL;
808 #endif // HAVE_UNICODE_SUPPORT
809  font = nbgl_getFont(fontId);
810 #ifdef BUILD_SCREENSHOTS
811  next_bold_state = true;
812 #endif // BUILD_SCREENSHOTS
813  }
814  else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
816 #ifdef HAVE_UNICODE_SUPPORT
817  unicode_ctx = NULL;
818 #endif // HAVE_UNICODE_SUPPORT
819  font = nbgl_getFont(fontId);
820 #ifdef BUILD_SCREENSHOTS
821  next_bold_state = false;
822 #endif // BUILD_SCREENSHOTS
823  }
824  continue;
825  }
826 
827  char_width = getCharWidth(font, unicode, is_unicode);
828  if (char_width == 0) {
829  continue;
830  }
831 #ifdef BUILD_SCREENSHOTS
832  // Update last 'displayed' char with current bold status
833  last_bold_state = next_bold_state;
834 #endif // BUILD_SCREENSHOTS
835 
836  // if about to reach max len, increment the number of lines
837  if ((width + char_width) > maxWidth) {
838  if ((wrapping == true) && (lastDelimiter != NULL)) {
839  text = lastDelimiter + 1;
840  lastDelimiter = NULL;
841  textLen = lenAtLastDelimiter;
842  width = 0;
843  }
844  else {
845 #ifdef BUILD_SCREENSHOTS
846  // An hyphenation (caesura) has been forced.
847  hard_caesura = true;
848 #endif // BUILD_SCREENSHOTS
849  width = char_width;
850  }
851  nbLines++;
852 #if defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
853  if (!(nbLines % 4)) {
854  if (textLen) {
855  ++last_nb_pages;
856  }
857  }
858 #endif // defined(BUILD_SCREENSHOTS) && defined(SCREEN_SIZE_NANO)
859  }
860  else {
861  width += char_width;
862  }
863  }
864 #ifdef SCREEN_SIZE_NANO
865  if (width != 0) {
866  ++nbLines;
867  }
868 #endif // SCREEN_SIZE_NANO
869 #ifdef BUILD_SCREENSHOTS
870  last_nb_lines = nbLines;
871 #endif // BUILD_SCREENSHOTS
872  return nbLines;
873 }
874 
886  const char *text,
887  uint8_t nbLinesPerPage,
888  uint16_t maxWidth)
889 {
890  const nbgl_font_t *font = nbgl_getFont(fontId);
891  uint16_t width = 0;
892  uint16_t nbLines = 0;
893  uint8_t nbPages = 1;
894  uint16_t textLen = strlen(text);
895  const char *lastDelimiter = NULL;
896  uint32_t lenAtLastDelimiter = 0;
897  const char *prevText = NULL;
898 #ifdef HAVE_UNICODE_SUPPORT
899  nbgl_unicode_ctx_t *unicode_ctx = NULL;
900 #endif // HAVE_UNICODE_SUPPORT
901 
902 #ifdef BUILD_SCREENSHOTS
903  last_nb_lines = nbLines;
904  last_nb_pages = nbPages;
905  last_bold_state = fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp; // True if Bold
906  bool next_bold_state = last_bold_state;
907 #endif // BUILD_SCREENSHOTS
908  // end loop when a '\0' is uncountered
909  while (textLen) {
910  uint8_t char_width;
911  uint32_t unicode;
912  bool is_unicode;
913 
914  // memorize the last char
915  prevText = text;
916  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
917 #ifdef HAVE_UNICODE_SUPPORT
918  if (is_unicode && !unicode_ctx) {
919  unicode_ctx = nbgl_getUnicodeFont(fontId);
920  }
921 #endif
922 
923  // memorize cursors at last found space
924  if (IS_WORD_DELIM(unicode)) {
925  lastDelimiter = prevText;
926  lenAtLastDelimiter = textLen;
927  }
928  // if \f, updates page number
929  if (unicode == '\f') {
930  nbPages++;
931 #ifdef BUILD_SCREENSHOTS
932 #ifdef SCREEN_SIZE_NANO
933  if (width != 0) {
934 #endif // SCREEN_SIZE_NANO
935  ++nbLines;
936 #ifdef SCREEN_SIZE_NANO
937  }
938 #endif // SCREEN_SIZE_NANO
939  if (last_nb_lines < nbLines) {
940  last_nb_lines = nbLines;
941  }
942 #endif // BUILD_SCREENSHOTS
943  nbLines = 0;
944  width = 0;
945  continue;
946  }
947  // if \n, increment the number of lines
948  else if (unicode == '\n') {
949  nbLines++;
950 #ifdef BUILD_SCREENSHOTS
951  if (last_nb_lines < nbLines) {
952  last_nb_lines = nbLines;
953  }
954 #endif // BUILD_SCREENSHOTS
955  if (nbLines == nbLinesPerPage && textLen) {
956  nbPages++;
957  nbLines = 0;
958  }
959 
960  width = 0;
961  lastDelimiter = NULL;
962  continue;
963  }
964  // if \b, switch fontId
965  else if (unicode == '\b') {
966  if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
968 #ifdef HAVE_UNICODE_SUPPORT
969  unicode_ctx = NULL;
970 #endif // HAVE_UNICODE_SUPPORT
971  font = nbgl_getFont(fontId);
972 #ifdef BUILD_SCREENSHOTS
973  next_bold_state = true;
974 #endif // BUILD_SCREENSHOTS
975  }
976  else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
978 #ifdef HAVE_UNICODE_SUPPORT
979  unicode_ctx = NULL;
980 #endif // HAVE_UNICODE_SUPPORT
981  font = nbgl_getFont(fontId);
982 #ifdef BUILD_SCREENSHOTS
983  next_bold_state = false;
984 #endif // BUILD_SCREENSHOTS
985  }
986  continue;
987  }
988 
989  char_width = getCharWidth(font, unicode, is_unicode);
990  if (char_width == 0) {
991  continue;
992  }
993 
994 #ifdef BUILD_SCREENSHOTS
995  // Update last 'displayed' char with current bold status
996  last_bold_state = next_bold_state;
997 #endif // BUILD_SCREENSHOTS
998 
999  // if about to reach max len, increment the number of lines/pages
1000  if ((width + char_width) > maxWidth) {
1001  if (lastDelimiter != NULL) {
1002  text = lastDelimiter + 1;
1003  lastDelimiter = NULL;
1004  textLen = lenAtLastDelimiter;
1005  width = 0;
1006  }
1007  else {
1008  width = char_width;
1009  }
1010  nbLines++;
1011 #ifdef BUILD_SCREENSHOTS
1012  if (last_nb_lines < nbLines) {
1013  last_nb_lines = nbLines;
1014  }
1015 #endif // BUILD_SCREENSHOTS
1016  if (nbLines == nbLinesPerPage) {
1017  nbPages++;
1018  nbLines = 0;
1019  }
1020  }
1021  else {
1022  width += char_width;
1023  }
1024  }
1025 #ifdef BUILD_SCREENSHOTS
1026 #ifdef SCREEN_SIZE_NANO
1027  if (width != 0) {
1028  ++nbLines;
1029  }
1030 #endif // SCREEN_SIZE_NANO
1031  if (last_nb_lines < nbLines) {
1032  last_nb_lines = nbLines;
1033  }
1034  last_nb_pages = nbPages;
1035 #endif // BUILD_SCREENSHOTS
1036  return nbPages;
1037 }
1038 
1049  const char *text,
1050  uint16_t maxWidth,
1051  bool wrapping)
1052 {
1053  const nbgl_font_t *font = nbgl_getFont(fontId);
1054  return (nbgl_getTextNbLinesInWidth(fontId, text, maxWidth, wrapping) * font->line_height);
1055 }
1056 
1068 void nbgl_textWrapOnNbLines(nbgl_font_id_e fontId, char *text, uint16_t maxWidth, uint8_t nbLines)
1069 {
1070  const nbgl_font_t *font = nbgl_getFont(fontId);
1071  uint16_t textLen = nbgl_getTextLength(text);
1072  uint16_t width = 0;
1073  uint8_t currentNbLines = 1;
1074  char *lastDelimiter = NULL;
1075  uint32_t lenAtLastDelimiter = 0;
1076  char *prevText = NULL;
1077  char *prevPrevText = NULL;
1078  uint16_t prevWidth = 0;
1079 
1080 #ifdef HAVE_UNICODE_SUPPORT
1081  nbgl_unicode_ctx_t *unicode_ctx = NULL;
1082 #endif // HAVE_UNICODE_SUPPORT
1083 
1084  while (*text) {
1085  uint8_t char_width;
1086  uint32_t unicode;
1087  bool is_unicode;
1088  char *prevPrevPrevText;
1089 
1090  // memorize the three last chars
1091  prevPrevPrevText = prevPrevText;
1092  prevPrevText = prevText;
1093  prevText = text;
1094  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
1095  // if \n, reset width
1096  if (unicode == '\n') {
1097  width = 0;
1098  currentNbLines++;
1099  lastDelimiter = NULL;
1100  continue;
1101  }
1102 #ifdef HAVE_UNICODE_SUPPORT
1103  if (is_unicode && !unicode_ctx) {
1104  unicode_ctx = nbgl_getUnicodeFont(fontId);
1105  }
1106 #endif
1107  char_width = getCharWidth(font, unicode, is_unicode);
1108  if (char_width == 0) {
1109  continue;
1110  }
1111 
1112  // memorize cursors at last found space
1113  if (IS_WORD_DELIM(unicode)) {
1114  lastDelimiter = prevText;
1115  lenAtLastDelimiter = textLen + 1;
1116  }
1117  // if the width is about to overpass maxWidth, do something
1118  if ((width + char_width) > maxWidth) {
1119  // if the max number of lines has not been reached, try to wrap on last space
1120  // encountered
1121  if (currentNbLines < nbLines) {
1122  currentNbLines++;
1123  // replace last found space by a \n
1124  if (lastDelimiter != NULL) {
1125  *lastDelimiter++ = '\n';
1126  text = lastDelimiter;
1127  lastDelimiter = NULL;
1128  textLen = lenAtLastDelimiter - 1;
1129  }
1130  else {
1131  textLen += text - prevText;
1132  text = prevText;
1133  }
1134  // reset width for next line
1135  width = 0;
1136  continue;
1137  }
1138  else {
1139  // replace the 2 or 3 last chars by '...'
1140  // try at first with 2, if it fits
1141  if (prevPrevText != NULL) {
1142  if ((prevWidth + (3 * getCharWidth(font, '.', false))) <= maxWidth) {
1143  *prevPrevText++ = '.';
1144  *prevPrevText++ = '.';
1145  *prevPrevText++ = '.';
1146  *prevPrevText = '\0';
1147  }
1148  else if (prevPrevPrevText != NULL) {
1149  *prevPrevPrevText++ = '.';
1150  *prevPrevPrevText++ = '.';
1151  *prevPrevPrevText++ = '.';
1152  *prevPrevPrevText = '\0';
1153  }
1154  }
1155  return;
1156  }
1157  }
1158  // memorize the last width
1159  prevWidth = width;
1160  width += char_width;
1161  }
1162 }
1163 
1180  const char *origText,
1181  uint16_t maxWidth,
1182  uint8_t nbLines,
1183  char *reducedText,
1184  uint16_t reducedTextLen)
1185 {
1186  const nbgl_font_t *font = nbgl_getFont(fontId);
1187  uint16_t textLen = strlen(origText);
1188  uint16_t width = 0;
1189  uint8_t currentNbLines = 1;
1190  uint32_t i = 0, j = 0;
1191  const uint16_t halfWidth = (maxWidth - nbgl_getTextWidth(fontId, " ... ")) / 2;
1192 
1193  if ((nbLines & 0x1) == 0) {
1194  LOG_FATAL(MISC_LOGGER, "nbgl_textReduceOnNbLines: the number of line must be odd\n");
1195  return;
1196  }
1197  while ((i < textLen) && (j < reducedTextLen)) {
1198  uint8_t char_width;
1199  char curChar;
1200 
1201  curChar = origText[i];
1202 
1203  char_width = getCharWidth(font, curChar, false);
1204  if (char_width == 0) {
1205  reducedText[j] = curChar;
1206  j++;
1207  i++;
1208  continue;
1209  }
1210 
1211  // if the width is about to exceed maxWidth, increment number of lines
1212  if ((width + char_width) > maxWidth) {
1213  currentNbLines++;
1214  // reset width for next line
1215  width = 0;
1216  continue;
1217  }
1218  else if ((currentNbLines == ((nbLines / 2) + 1)) && ((width + char_width) > halfWidth)) {
1219  uint32_t halfFullWidth = (nbLines / 2) * maxWidth + halfWidth;
1220  uint32_t countDown = textLen;
1221  // if this if the central line, we have to insert the '...' in the middle of it
1222  reducedText[j - 1] = '.';
1223  reducedText[j] = '.';
1224  reducedText[j + 1] = '.';
1225  // then start from the end
1226  width = 0;
1227  while (width < halfFullWidth) {
1228  countDown--;
1229  curChar = origText[countDown];
1230  char_width = getCharWidth(font, curChar, false);
1231  width += char_width;
1232  }
1233  memcpy(&reducedText[j + 2], &origText[countDown + 1], textLen - countDown + 1);
1234  return;
1235  }
1236  else {
1237  reducedText[j] = curChar;
1238  j++;
1239  i++;
1240  }
1241  width += char_width;
1242  }
1243  reducedText[j] = '\0';
1244 }
1245 
1246 #ifdef HAVE_UNICODE_SUPPORT
1254 nbgl_unicode_ctx_t *nbgl_getUnicodeFont(nbgl_font_id_e fontId)
1255 {
1256  if ((unicodeCtx.font != NULL) && (unicodeCtx.font->font_id == fontId)) {
1257  return &unicodeCtx;
1258  }
1259 #if defined(HAVE_LANGUAGE_PACK)
1260  // Be sure we need to change font
1261  const uint8_t *ptr = (const uint8_t *) language_pack;
1262  const nbgl_font_unicode_t *font = (const void *) (ptr + language_pack->fonts_offset);
1263  unicodeCtx.characters
1264  = (const nbgl_font_unicode_character_t *) (ptr + language_pack->characters_offset);
1265  unicodeCtx.bitmap = (const uint8_t *) (ptr + language_pack->bitmaps_offset);
1266 
1267  for (uint32_t i = 0; i < language_pack->nb_fonts; i++) {
1268  if (font->font_id == fontId) {
1269  // Update all other global variables
1270  unicodeCtx.font = font;
1271  return &unicodeCtx;
1272  }
1273  // Compute next Bitmap offset
1274  unicodeCtx.bitmap += font->bitmap_len;
1275 
1276  // Update all pointers for next font
1277  unicodeCtx.characters += language_pack->nb_characters;
1278  font++;
1279  }
1280 #endif // defined(HAVE_LANGUAGE_PACK)
1281  // id not found
1282  return NULL;
1283 }
1284 
1294 const nbgl_font_unicode_character_t *nbgl_getUnicodeFontCharacter(uint32_t unicode)
1295 {
1296 #if defined(HAVE_LANGUAGE_PACK)
1297  const nbgl_font_unicode_character_t *characters
1298  = (const nbgl_font_unicode_character_t *) PIC(unicodeCtx.characters);
1299  uint32_t n = language_pack->nb_characters;
1300  if (characters == NULL) {
1301  return NULL;
1302  }
1303  // For the moment, let just parse the full array, but at the end let use
1304  // binary search as data are sorted by unicode value !
1305  for (unsigned i = 0; i < n - 1; i++, characters++) {
1306  if (characters->char_unicode == unicode) {
1307  // Compute & store the number of bytes used to display this character
1308  unicodeCtx.unicode_character_byte_count
1309  = (characters + 1)->bitmap_offset - characters->bitmap_offset;
1310  return characters;
1311  }
1312  }
1313  // By default, let's use the last Unicode character, which should be the
1314  // 0x00FFFD one, used to replace unrecognized or unrepresentable character.
1315 
1316  // Compute & store the number of bytes used to display this character
1317  unicodeCtx.unicode_character_byte_count
1318  = unicodeCtx.font->bitmap_len - characters->bitmap_offset;
1319  return characters;
1320 #else // defined(HAVE_LANGUAGE_PACK)
1321  UNUSED(unicode);
1322  // id not found
1323  return NULL;
1324 #endif // defined(HAVE_LANGUAGE_PACK)
1325 }
1326 
1333 uint32_t nbgl_getUnicodeFontCharacterByteCount(void)
1334 {
1335 #ifdef HAVE_LANGUAGE_PACK
1336  return unicodeCtx.unicode_character_byte_count;
1337 #else // defined(HAVE_LANGUAGE_PACK)
1338  return 0;
1339 #endif // HAVE_LANGUAGE_PACK
1340 }
1341 
1342 #ifdef HAVE_LANGUAGE_PACK
1350 void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
1351 {
1352  language_pack = lp;
1353  unicodeCtx.font = NULL;
1354  unicodeCtx.characters = NULL;
1355 }
1356 #endif // HAVE_LANGUAGE_PACK
1357 
1358 #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...
Definition: nbgl_fonts.c:1068
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:482
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:422
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:885
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:334
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:372
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:572
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:681
#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:398
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),...
Definition: nbgl_fonts.c:1179
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:150
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:360
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.
Definition: nbgl_fonts.c:1048
#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:454
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:731
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:441
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
return the non-unicode font corresponding to the given font ID
Definition: nbgl_fonts.c:136
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:410
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:348
const nbgl_font_t * nbgl_font_getFont(unsigned int fontId)
nbgl_font_id_e
Definition: nbgl_fonts.h:140
@ BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
Definition: nbgl_fonts.h:149
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition: nbgl_fonts.h:147
#define LANGUAGE_PACK
Definition: nbgl_fonts.h:29
#define MIN(x, y)
Definition: nbgl_types.h:79
fonts nicknames to be used for various wallet size targets (non-Nano)
Definition: nbgl_fonts.h:66
uint32_t width
width of character in pixels
Definition: nbgl_fonts.h:69
structure defining an ASCII font
Definition: nbgl_fonts.h:80
uint8_t char_kerning
kerning for the font
Definition: nbgl_fonts.h:86
uint8_t first_char
ASCII code of the first character in bitmap and in characters fields.
Definition: nbgl_fonts.h:90
const nbgl_font_character_t *const characters
array containing definitions of all characters
Definition: nbgl_fonts.h:94
uint8_t height
height of all characters in pixels
Definition: nbgl_fonts.h:84
uint8_t line_height
height of a line for all characters in pixels
Definition: nbgl_fonts.h:85
uint8_t last_char
ASCII code of the last character in bitmap and in characters fields.
Definition: nbgl_fonts.h:92
structure defining a unicode character (except the bitmap)
Definition: nbgl_fonts.h:108
uint32_t char_unicode
plane value from 0 to 16 then 16-bit code.
Definition: nbgl_fonts.h:109
uint32_t width
width of character in pixels
Definition: nbgl_fonts.h:111
uint32_t bitmap_offset
offset of this character in chars buffer
Definition: nbgl_fonts.h:116
structure defining a unicode font
Definition: nbgl_fonts.h:122
uint16_t bitmap_len
Size in bytes of all characters bitmaps.
Definition: nbgl_fonts.h:123
uint8_t font_id
ID of the font, from nbgl_font_id_e.
Definition: nbgl_fonts.h:124
const nbgl_font_unicode_character_t * characters
Definition: nbgl_fonts.h:161
const nbgl_font_unicode_t * font
Definition: nbgl_fonts.h:160
uint32_t unicode_character_byte_count
Definition: nbgl_fonts.h:163
const uint8_t * bitmap
Definition: nbgl_fonts.h:162
unsigned short uint16_t
Definition: usbd_conf.h:54
unsigned char uint8_t
Definition: usbd_conf.h:53