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[4] = {0}; // queue of last positions
1077  uint16_t prevWidth[2] = {0}; // queue of last widths
1078 
1079 #ifdef HAVE_UNICODE_SUPPORT
1080  nbgl_unicode_ctx_t *unicode_ctx = NULL;
1081 #endif // HAVE_UNICODE_SUPPORT
1082 
1083  while (*text) {
1084  uint8_t char_width;
1085  uint32_t unicode;
1086  bool is_unicode;
1087 
1088  // memorize the last positions in the queue
1089  // the oldest is at the highest index
1090  prevText[3] = prevText[2];
1091  prevText[2] = prevText[1];
1092  prevText[1] = prevText[0];
1093  prevText[0] = 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[0];
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[0];
1132  text = prevText[0];
1133  }
1134  // reset width for next line
1135  width = 0;
1136  continue;
1137  }
1138  else {
1139  uint32_t i;
1140  // replace the 1, 2 or 3 last chars by '...'
1141  // try at first with 1, then with 2, if it fits
1142  for (i = 0; i < 2; i++) {
1143  if ((prevText[i + 1] != NULL)
1144  && ((prevWidth[i] + (3 * getCharWidth(font, '.', false))) <= maxWidth)) {
1145  break;
1146  }
1147  }
1148  // at worth we are sure it works by replacing the 3 last chars (if i ==2)
1149  if (prevText[i + 1] != NULL) {
1150  memcpy(prevText[i + 1], "...", 4);
1151  }
1152  return;
1153  }
1154  }
1155  // memorize the 2 last widths in a queue
1156  prevWidth[1] = prevWidth[0];
1157  prevWidth[0] = width;
1158  width += char_width;
1159  }
1160 }
1161 
1178  const char *origText,
1179  uint16_t maxWidth,
1180  uint8_t nbLines,
1181  char *reducedText,
1182  uint16_t reducedTextLen)
1183 {
1184  const nbgl_font_t *font = nbgl_getFont(fontId);
1185  uint16_t textLen = strlen(origText);
1186  uint16_t width = 0;
1187  uint8_t currentNbLines = 1;
1188  uint32_t i = 0, j = 0;
1189  const uint16_t halfWidth = (maxWidth - nbgl_getTextWidth(fontId, " ... ")) / 2;
1190 
1191  if ((nbLines & 0x1) == 0) {
1192  LOG_FATAL(MISC_LOGGER, "nbgl_textReduceOnNbLines: the number of line must be odd\n");
1193  return;
1194  }
1195  while ((i < textLen) && (j < reducedTextLen)) {
1196  uint8_t char_width;
1197  char curChar;
1198 
1199  curChar = origText[i];
1200 
1201  char_width = getCharWidth(font, curChar, false);
1202  if (char_width == 0) {
1203  reducedText[j] = curChar;
1204  j++;
1205  i++;
1206  continue;
1207  }
1208 
1209  // if the width is about to exceed maxWidth, increment number of lines
1210  if ((width + char_width) > maxWidth) {
1211  currentNbLines++;
1212  // reset width for next line
1213  width = 0;
1214  continue;
1215  }
1216  else if ((currentNbLines == ((nbLines / 2) + 1)) && ((width + char_width) > halfWidth)) {
1217  uint32_t halfFullWidth = (nbLines / 2) * maxWidth + halfWidth;
1218  uint32_t countDown = textLen;
1219  // if this if the central line, we have to insert the '...' in the middle of it
1220  reducedText[j - 1] = '.';
1221  reducedText[j] = '.';
1222  reducedText[j + 1] = '.';
1223  // then start from the end
1224  width = 0;
1225  while (width < halfFullWidth) {
1226  countDown--;
1227  curChar = origText[countDown];
1228  char_width = getCharWidth(font, curChar, false);
1229  width += char_width;
1230  }
1231  memcpy(&reducedText[j + 2], &origText[countDown + 1], textLen - countDown + 1);
1232  return;
1233  }
1234  else {
1235  reducedText[j] = curChar;
1236  j++;
1237  i++;
1238  }
1239  width += char_width;
1240  }
1241  reducedText[j] = '\0';
1242 }
1243 
1244 #ifdef HAVE_UNICODE_SUPPORT
1252 nbgl_unicode_ctx_t *nbgl_getUnicodeFont(nbgl_font_id_e fontId)
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 
1292 const nbgl_font_unicode_character_t *nbgl_getUnicodeFontCharacter(uint32_t unicode)
1293 {
1294 #if defined(HAVE_LANGUAGE_PACK)
1295  const nbgl_font_unicode_character_t *characters
1296  = (const nbgl_font_unicode_character_t *) PIC(unicodeCtx.characters);
1297  uint32_t n = language_pack->nb_characters;
1298  if (characters == NULL) {
1299  return NULL;
1300  }
1301  // For the moment, let just parse the full array, but at the end let use
1302  // binary search as data are sorted by unicode value !
1303  for (unsigned i = 0; i < n - 1; i++, characters++) {
1304  if (characters->char_unicode == unicode) {
1305  // Compute & store the number of bytes used to display this character
1306  unicodeCtx.unicode_character_byte_count
1307  = (characters + 1)->bitmap_offset - characters->bitmap_offset;
1308  return characters;
1309  }
1310  }
1311  // By default, let's use the last Unicode character, which should be the
1312  // 0x00FFFD one, used to replace unrecognized or unrepresentable character.
1313 
1314  // Compute & store the number of bytes used to display this character
1315  unicodeCtx.unicode_character_byte_count
1316  = unicodeCtx.font->bitmap_len - characters->bitmap_offset;
1317  return characters;
1318 #else // defined(HAVE_LANGUAGE_PACK)
1319  UNUSED(unicode);
1320  // id not found
1321  return NULL;
1322 #endif // defined(HAVE_LANGUAGE_PACK)
1323 }
1324 
1331 uint32_t nbgl_getUnicodeFontCharacterByteCount(void)
1332 {
1333 #ifdef HAVE_LANGUAGE_PACK
1334  return unicodeCtx.unicode_character_byte_count;
1335 #else // defined(HAVE_LANGUAGE_PACK)
1336  return 0;
1337 #endif // HAVE_LANGUAGE_PACK
1338 }
1339 
1340 #ifdef HAVE_LANGUAGE_PACK
1348 void nbgl_refreshUnicodeFont(const LANGUAGE_PACK *lp)
1349 {
1350  language_pack = lp;
1351  unicodeCtx.font = NULL;
1352  unicodeCtx.characters = NULL;
1353 }
1354 #endif // HAVE_LANGUAGE_PACK
1355 
1356 #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:1177
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