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