Embedded SDK
Embedded SDK
nbgl_draw.c
Go to the documentation of this file.
1 
8 /*********************
9  * INCLUDES
10  *********************/
11 #include <string.h>
12 #include "nbgl_front.h"
13 #include "nbgl_draw.h"
14 #include "nbgl_fonts.h"
15 #include "nbgl_debug.h"
16 #include "nbgl_side.h"
17 #ifdef NBGL_QRCODE
18 #include "qrcodegen.h"
19 #endif // NBGL_QRCODE
20 #include "glyphs.h"
21 #include "os_pic.h"
22 #include "os_utils.h"
23 
24 /*********************
25  * DEFINES
26  *********************/
27 typedef enum {
33 
34 #define QR_PIXEL_WIDTH_HEIGHT 4
35 
36 /**********************
37  * TYPEDEFS
38  **********************/
39 #ifdef NBGL_QRCODE
40 typedef struct {
41  uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
42  uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
45 
46 #define qrcode ((QrCodeBuffer_t *) ramBuffer)->qrcode
47 #define tempBuffer ((QrCodeBuffer_t *) ramBuffer)->tempBuffer
48 #define QrDrawBuffer ((QrCodeBuffer_t *) ramBuffer)->QrDrawBuffer
49 #endif // NBGL_QRCODE
50 
51 /**********************
52  * STATIC PROTOTYPES
53  **********************/
54 
55 /**********************
56  * STATIC VARIABLES
57  **********************/
58 #ifndef SCREEN_SIZE_WALLET
59 static const uint8_t quarter_disc_3px_1bpp[] = {0xEC, 0xFF};
60 static const uint8_t quarter_disc_3px_90_1bpp[] = {0x2F, 0xFF};
61 static const uint8_t quarter_disc_3px_180_1bpp[] = {0x9B, 0xFF};
62 static const uint8_t quarter_disc_3px_270_1bpp[] = {0xFA, 0x00};
63 
64 static const uint8_t quarter_circle_3px_1bpp[] = {0x4C, 0x00};
65 static const uint8_t quarter_circle_3px_90_1bpp[] = {0x0D, 0x00};
66 static const uint8_t quarter_circle_3px_180_1bpp[] = {0x19, 0x00};
67 static const uint8_t quarter_circle_3px_270_1bpp[] = {0x58, 0x00};
68 #endif // SCREEN_SIZE_WALLET
69 
70 // indexed by nbgl_radius_t (except RADIUS_0_PIXELS)
71 static const uint8_t radiusValues[] = {
72 #ifdef SCREEN_SIZE_WALLET
73  32,
74 #ifdef TARGET_STAX
75  40,
76 #else // TARGET_STAX
77  44
78 #endif // TARGET_STAX
79 #else // SCREEN_SIZE_WALLET
80  1,
81  3
82 #endif // SCREEN_SIZE_WALLET
83 };
84 
85 #ifdef SCREEN_SIZE_WALLET
86 // indexed by nbgl_radius_t (except RADIUS_0_PIXELS)
87 static const uint8_t *topQuarterDiscs[] = {
88  C_quarter_disc_top_left_32px_1bpp_bitmap,
89 #ifdef TARGET_STAX
90  C_quarter_disc_top_left_40px_1bpp_bitmap,
91 #else // TARGET_STAX
92  C_quarter_disc_top_left_44px_1bpp_bitmap
93 #endif // TARGET_STAX
94 };
95 
96 static const uint8_t *bottomQuarterDiscs[] = {
97  C_quarter_disc_bottom_left_32px_1bpp_bitmap,
98 #ifdef TARGET_STAX
99  C_quarter_disc_bottom_left_40px_1bpp_bitmap,
100 #else // TARGET_STAX
101  C_quarter_disc_bottom_left_44px_1bpp_bitmap
102 #endif // TARGET_STAX
103 };
104 
105 // indexed by nbgl_radius_t (except RADIUS_0_PIXELS)
106 static const uint8_t *topQuarterCircles[] = {
107  C_quarter_circle_top_left_32px_1bpp_bitmap,
108 #ifdef TARGET_STAX
109  C_quarter_circle_top_left_40px_1bpp_bitmap,
110 #else // TARGET_STAX
111  C_quarter_circle_top_left_44px_1bpp_bitmap
112 #endif // TARGET_STAX
113 };
114 
115 static const uint8_t *bottomQuarterCircles[] = {
116  C_quarter_circle_bottom_left_32px_1bpp_bitmap,
117 #ifdef TARGET_STAX
118  C_quarter_circle_bottom_left_40px_1bpp_bitmap,
119 #else // TARGET_STAX
120  C_quarter_circle_bottom_left_44px_1bpp_bitmap
121 #endif // TARGET_STAX
122 };
123 #endif // SCREEN_SIZE_WALLET
124 
125 #ifdef NBGL_QRCODE
126 // ensure that the ramBuffer also used for image file decompression is big enough for QR code
128 #endif // NBGL_QRCODE
129 
130 /**********************
131  * VARIABLES
132  **********************/
133 
134 /**********************
135  * STATIC PROTOTYPES
136  **********************/
137 
138 static void draw_circle_helper(int x_center,
139  int y_center,
140  nbgl_radius_t radiusIndex,
141  quarter_t quarter,
142  color_t borderColor,
143  color_t innerColor,
144  color_t backgroundColor)
145 {
146  const uint8_t *quarter_buffer = NULL;
147  nbgl_area_t area = {.bpp = NBGL_BPP_1, .backgroundColor = backgroundColor};
148 
149  // radius is not supported
150  if (radiusIndex > RADIUS_MAX) {
151  return;
152  }
153  area.width = area.height = radiusValues[radiusIndex];
154 #ifdef SCREEN_SIZE_WALLET
155  if (borderColor == innerColor) {
156  if (quarter < BAGL_FILL_CIRCLE_PI_3PI2) {
157  quarter_buffer = (const uint8_t *) PIC(topQuarterDiscs[radiusIndex]);
158  }
159  else {
160  quarter_buffer = (const uint8_t *) PIC(bottomQuarterDiscs[radiusIndex]);
161  }
162  }
163  else {
164  if (quarter < BAGL_FILL_CIRCLE_PI_3PI2) {
165  quarter_buffer = (const uint8_t *) PIC(topQuarterCircles[radiusIndex]);
166  }
167  else {
168  quarter_buffer = (const uint8_t *) PIC(bottomQuarterCircles[radiusIndex]);
169  }
170  }
171  switch (quarter) {
172  case BAGL_FILL_CIRCLE_3PI2_2PI: // bottom right
173  area.x0 = x_center;
174  area.y0 = y_center;
175  nbgl_frontDrawImage(&area, quarter_buffer, VERTICAL_MIRROR, borderColor);
176  break;
177  case BAGL_FILL_CIRCLE_PI_3PI2: // bottom left
178  area.x0 = x_center - area.width;
179  area.y0 = y_center;
180  nbgl_frontDrawImage(&area, quarter_buffer, NO_TRANSFORMATION, borderColor);
181  break;
182  case BAGL_FILL_CIRCLE_0_PI2: // top right
183  area.x0 = x_center;
184  area.y0 = y_center - area.width;
185  nbgl_frontDrawImage(&area, quarter_buffer, VERTICAL_MIRROR, borderColor);
186  break;
187  case BAGL_FILL_CIRCLE_PI2_PI: // top left
188  area.x0 = x_center - area.width;
189  area.y0 = y_center - area.width;
190  nbgl_frontDrawImage(&area, quarter_buffer, NO_TRANSFORMATION, borderColor);
191  break;
192  }
193 #else // SCREEN_SIZE_WALLET
194  switch (quarter) {
195  case BAGL_FILL_CIRCLE_3PI2_2PI: // bottom right
196  area.x0 = x_center;
197  area.y0 = y_center;
198  quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_180_1bpp
199  : quarter_circle_3px_180_1bpp;
200  break;
201  case BAGL_FILL_CIRCLE_PI_3PI2: // bottom left
202  area.x0 = x_center - area.width;
203  area.y0 = y_center;
204  quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_270_1bpp
205  : quarter_circle_3px_270_1bpp;
206  break;
207  case BAGL_FILL_CIRCLE_0_PI2: // top right
208  area.x0 = x_center;
209  area.y0 = y_center - area.width;
210  quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_90_1bpp
211  : quarter_circle_3px_90_1bpp;
212  break;
213  case BAGL_FILL_CIRCLE_PI2_PI: // top left
214  area.x0 = x_center - area.width;
215  area.y0 = y_center - area.width;
216  quarter_buffer
217  = (borderColor == innerColor) ? quarter_disc_3px_1bpp : quarter_circle_3px_1bpp;
218  break;
219  }
220  nbgl_frontDrawImage(&area, quarter_buffer, NO_TRANSFORMATION, borderColor);
221 #endif // SCREEN_SIZE_WALLET
222 }
223 
224 /**********************
225  * GLOBAL FUNCTIONS
226  **********************/
227 
237 void nbgl_drawRoundedRect(const nbgl_area_t *area, nbgl_radius_t radiusIndex, color_t innerColor)
238 {
239  nbgl_area_t rectArea;
240  uint8_t radius;
241 
243  "nbgl_drawRoundedRect x0 = %d, y0 = %d, width =%d, height =%d\n",
244  area->x0,
245  area->y0,
246  area->width,
247  area->height);
248 
249  if (radiusIndex <= RADIUS_MAX) {
250  radius = radiusValues[radiusIndex];
251  }
252  else if (radiusIndex == RADIUS_0_PIXELS) {
253  radius = 0;
254  }
255  else {
256  // radius not supported
257  LOG_WARN(DRAW_LOGGER, "nbgl_drawRoundedRect forbidden radius index =%d\n", radiusIndex);
258  return;
259  }
260 
261  // Draw main inner rectangle
262  rectArea.x0 = area->x0 + radius;
263  rectArea.y0 = area->y0;
264  rectArea.width = area->width - (2 * radius);
265  rectArea.height = area->height;
266  rectArea.backgroundColor = innerColor;
267  nbgl_frontDrawRect(&rectArea);
268  // special case when radius is null, just draw a rectangle
269  if (radiusIndex == RADIUS_0_PIXELS) {
270  return;
271  }
272  // Draw left inner rectangle
273  rectArea.x0 = area->x0;
274  rectArea.y0 = area->y0 + radius;
275  rectArea.width = radius;
276  rectArea.height = area->height - (2 * radius);
277  nbgl_frontDrawRect(&rectArea);
278  // Draw right inner rectangle
279  rectArea.x0 = area->x0 + area->width - radius;
280  rectArea.y0 = area->y0 + radius;
281  rectArea.width = radius;
282  rectArea.height = area->height - (2 * radius);
283  nbgl_frontDrawRect(&rectArea);
284 
285 #ifdef SCREEN_SIZE_NANO
286  if (radiusIndex == RADIUS_1_PIXEL) {
287  return;
288  }
289 #endif // SCREEN_SIZE_NANO
290  // Draw 4 quarters of disc
291  draw_circle_helper(area->x0 + radius,
292  area->y0 + radius,
293  radiusIndex,
295  innerColor, // unused
296  innerColor,
297  area->backgroundColor);
298  draw_circle_helper(area->x0 + area->width - radius,
299  area->y0 + radius,
300  radiusIndex,
302  innerColor, // unused
303  innerColor,
304  area->backgroundColor);
305  draw_circle_helper(area->x0 + radius,
306  area->y0 + area->height - radius,
307  radiusIndex,
309  innerColor, // unused
310  innerColor,
311  area->backgroundColor);
312  draw_circle_helper(area->x0 + area->width - radius,
313  area->y0 + area->height - radius,
314  radiusIndex,
316  innerColor, // unused
317  innerColor,
318  area->backgroundColor);
319 }
320 
332  nbgl_radius_t radiusIndex,
333  uint8_t stroke,
334  color_t innerColor,
335  color_t borderColor)
336 {
337  uint8_t radius;
338  nbgl_area_t rectArea;
339 
340  LOG_DEBUG(
341  DRAW_LOGGER,
342  "nbgl_drawRoundedBorderedRect: innerColor = %d, borderColor = %d, backgroundColor=%d\n",
343  innerColor,
344  borderColor,
345  area->backgroundColor);
346 
347  if (radiusIndex <= RADIUS_MAX) {
348  radius = radiusValues[radiusIndex];
349  }
350  else if (radiusIndex == RADIUS_0_PIXELS) {
351  radius = 0;
352  }
353  else {
354  // radius not supported
355  LOG_WARN(
356  DRAW_LOGGER, "nbgl_drawRoundedBorderedRect forbidden radius index =%d\n", radiusIndex);
357  return;
358  }
359  rectArea.backgroundColor = innerColor;
360 
361  // special case, when border_color == inner_color == background_color, just draw a rectangle
362  if ((innerColor == borderColor) && (borderColor == area->backgroundColor)) {
363  rectArea.x0 = area->x0;
364  rectArea.y0 = area->y0;
365  rectArea.width = area->width;
366  rectArea.height = area->height;
367  nbgl_frontDrawRect(&rectArea);
368  return;
369  }
370  // Draw 3 rectangles
371  if ((2 * radius) < area->width) {
372  rectArea.x0 = area->x0 + radius;
373  rectArea.y0 = area->y0;
374  rectArea.width = area->width - (2 * radius);
375  rectArea.height = area->height;
376  nbgl_frontDrawRect(&rectArea);
377  }
378  // special case when radius is null, left and right rectangles are not necessary
379  if (radiusIndex <= RADIUS_MAX) {
380  if ((2 * radius) < area->height) {
381  rectArea.x0 = area->x0;
382  rectArea.y0 = area->y0 + radius;
383  rectArea.width = radius;
384  rectArea.height = area->height - (2 * radius);
385  nbgl_frontDrawRect(&rectArea);
386  rectArea.x0 = area->x0 + area->width - radius;
387  rectArea.y0 = area->y0 + radius;
388  nbgl_frontDrawRect(&rectArea);
389  }
390  }
391  // border
392  // 4 rectangles (with last pixel of each corner not set)
393 #ifdef SCREEN_SIZE_WALLET
394  uint8_t maskTop, maskBottom;
395  if (stroke == 1) {
396  maskTop = 0x1;
397  maskBottom = 0x8;
398  }
399  else if (stroke == 2) {
400  maskTop = 0x3;
401  maskBottom = 0xC;
402  }
403  else if (stroke == 3) {
404  maskTop = 0x7;
405  maskBottom = 0xE;
406  }
407  else if (stroke == 4) {
408  maskTop = 0xF;
409  maskBottom = 0xF;
410  }
411  else {
412  LOG_WARN(DRAW_LOGGER, "nbgl_drawRoundedBorderedRect forbidden stroke=%d\n", stroke);
413  return;
414  }
415  rectArea.x0 = area->x0 + radius;
416  rectArea.y0 = area->y0;
417  rectArea.width = area->width - 2 * radius;
418  rectArea.height = 4;
419  nbgl_frontDrawHorizontalLine(&rectArea, maskTop, borderColor); // top
420  rectArea.x0 = area->x0 + radius;
421  rectArea.y0 = area->y0 + area->height - 4;
422  nbgl_frontDrawHorizontalLine(&rectArea, maskBottom, borderColor); // bottom
423 #else // SCREEN_SIZE_WALLET
424  rectArea.x0 = area->x0 + radius;
425  rectArea.y0 = area->y0;
426  rectArea.width = area->width - 2 * radius;
427  rectArea.height = stroke;
428  rectArea.backgroundColor = borderColor;
429  nbgl_frontDrawRect(&rectArea); // top
430  rectArea.y0 = area->y0 + area->height - stroke;
431  nbgl_frontDrawRect(&rectArea); // bottom
432 #endif // SCREEN_SIZE_WALLET
433  if ((2 * radius) < area->height) {
434  rectArea.x0 = area->x0;
435  rectArea.y0 = area->y0 + radius;
436  rectArea.width = stroke;
437  rectArea.height = area->height - 2 * radius;
438  rectArea.backgroundColor = borderColor;
439  nbgl_frontDrawRect(&rectArea); // left
440  rectArea.x0 = area->x0 + area->width - stroke;
441  nbgl_frontDrawRect(&rectArea); // right
442  }
443 
444  if (radiusIndex <= RADIUS_MAX) {
445  // Draw 4 quarters of circles
446  draw_circle_helper(area->x0 + radius,
447  area->y0 + radius,
448  radiusIndex,
450  borderColor,
451  innerColor,
452  area->backgroundColor);
453  draw_circle_helper(area->x0 + area->width - radius,
454  area->y0 + radius,
455  radiusIndex,
457  borderColor,
458  innerColor,
459  area->backgroundColor);
460  draw_circle_helper(area->x0 + radius,
461  area->y0 + area->height - radius,
462  radiusIndex,
464  borderColor,
465  innerColor,
466  area->backgroundColor);
467  draw_circle_helper(area->x0 + area->width - radius,
468  area->y0 + area->height - radius,
469  radiusIndex,
471  borderColor,
472  innerColor,
473  area->backgroundColor);
474  }
475 }
476 
490  nbgl_transformation_t transformation,
491  nbgl_color_map_t color_map,
492  const nbgl_icon_details_t *icon)
493 {
494  if (icon->isFile) {
495  nbgl_frontDrawImageFile(area, icon->bitmap, color_map, ramBuffer);
496  }
497  else {
498  nbgl_frontDrawImage(area, icon->bitmap, transformation, color_map);
499  }
500 }
501 
509 static uint16_t get_bitmap_byte_cnt(const nbgl_font_t *font, uint8_t charId)
510 {
511  if ((charId < font->first_char) || (charId > font->last_char)) {
512  return 0;
513  }
514 
515  uint16_t baseId = charId - font->first_char;
516  if (charId < font->last_char) {
517  const nbgl_font_character_t *character
518  = (const nbgl_font_character_t *) PIC(&font->characters[baseId]);
519  const nbgl_font_character_t *nextCharacter
520  = (const nbgl_font_character_t *) PIC(&font->characters[baseId + 1]);
521  return (nextCharacter->bitmap_offset - character->bitmap_offset);
522  }
523  else if (charId == font->last_char) {
524  return (font->bitmap_len - font->characters[baseId].bitmap_offset);
525  }
526  return 0;
527 }
528 
539  const char *text,
540  uint16_t textLen,
541  nbgl_font_id_e fontId,
542  color_t fontColor)
543 {
544  // text is a series of characters, each character being a bitmap
545  // we need to align bitmaps on width multiple of 4 limitation.
546  int16_t x = area->x0;
547  nbgl_area_t rectArea;
548  const nbgl_font_t *font = nbgl_getFont(fontId);
549 #ifdef HAVE_UNICODE_SUPPORT
550  nbgl_unicode_ctx_t *unicode_ctx = NULL;
551 #endif // HAVE_UNICODE_SUPPORT
552 
554  "nbgl_drawText: x0 = %d, y0 = %d, w = %d, h = %d, fontColor = %d, "
555  "backgroundColor=%d, text = %s\n",
556  area->x0,
557  area->y0,
558  area->width,
559  area->height,
560  fontColor,
561  area->backgroundColor,
562  text);
563 
564  rectArea.backgroundColor = area->backgroundColor;
565  rectArea.bpp = (nbgl_bpp_t) font->bpp;
566 
567  while (textLen > 0) {
568  const nbgl_font_character_t *character;
569  uint8_t char_width;
570  uint32_t unicode;
571  bool is_unicode;
572  const uint8_t *char_buffer;
573  int16_t char_x_min;
574  int16_t char_y_min;
575  int16_t char_x_max;
576  int16_t char_y_max;
577  uint16_t char_byte_cnt;
578  uint8_t encoding;
579  uint8_t nb_skipped_bytes;
580 
581  unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
582 
583  if (is_unicode) {
584 #ifdef HAVE_UNICODE_SUPPORT
585  if (unicode_ctx == NULL) {
586  unicode_ctx = nbgl_getUnicodeFont(fontId);
587  }
588  const nbgl_font_unicode_character_t *unicodeCharacter
589  = nbgl_getUnicodeFontCharacter(unicode);
590  // if not supported char, go to next one
591  if (unicodeCharacter == NULL) {
592  continue;
593  }
594  char_width = unicodeCharacter->width;
595 #if defined(HAVE_LANGUAGE_PACK)
596  char_buffer = unicode_ctx->bitmap;
597  char_buffer += unicodeCharacter->bitmap_offset;
598 
599  char_x_max = char_width;
600  char_y_max = unicode_ctx->font->height;
601 
602  if (!unicode_ctx->font->crop) {
603  // Take in account the skipped bytes, if any
604  nb_skipped_bytes = (unicodeCharacter->x_min_offset & 7) << 3;
605  nb_skipped_bytes |= unicodeCharacter->y_min_offset & 7;
606  char_x_min = 0;
607  char_y_min = 0;
608  }
609  else {
610  nb_skipped_bytes = 0;
611  char_x_min = (uint16_t) unicodeCharacter->x_min_offset;
612  char_y_min = unicode_ctx->font->y_min;
613  char_y_min += (uint16_t) unicodeCharacter->y_min_offset;
614  char_x_max -= (uint16_t) unicodeCharacter->x_max_offset;
615  char_y_max -= (uint16_t) unicodeCharacter->y_max_offset;
616  }
617 
618  char_byte_cnt = nbgl_getUnicodeFontCharacterByteCount();
619  encoding = unicodeCharacter->encoding;
620 #endif // defined(HAVE_LANGUAGE_PACK)
621 #else // HAVE_UNICODE_SUPPORT
622  continue;
623 #endif // HAVE_UNICODE_SUPPORT
624  }
625  else {
626  if (unicode == '\f') {
627  break;
628  }
629  // if \b, switch fontId
630  else if (unicode == '\b') {
631  if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
633 #ifdef HAVE_UNICODE_SUPPORT
634  unicode_ctx = nbgl_getUnicodeFont(fontId);
635 #endif // HAVE_UNICODE_SUPPORT
636  font = (const nbgl_font_t *) nbgl_getFont(fontId);
637  }
638  else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
640 #ifdef HAVE_UNICODE_SUPPORT
641  unicode_ctx = nbgl_getUnicodeFont(fontId);
642 #endif // HAVE_UNICODE_SUPPORT
643  font = (const nbgl_font_t *) nbgl_getFont(fontId);
644  }
645  continue;
646  }
647  // if not supported char, go to next one
648  if ((unicode < font->first_char) || (unicode > font->last_char)) {
649  continue;
650  }
651  character = (const nbgl_font_character_t *) PIC(
652  &font->characters[unicode - font->first_char]);
653  char_buffer = (const uint8_t *) PIC(&font->bitmap[character->bitmap_offset]);
654  char_width = character->width;
655  encoding = character->encoding;
656 
657  char_x_max = char_width;
658  char_y_max = font->height;
659 
660  if (!font->crop) {
661  // Take in account the skipped bytes, if any
662  nb_skipped_bytes = (character->x_min_offset & 7) << 3;
663  nb_skipped_bytes |= character->y_min_offset & 7;
664  char_x_min = 0;
665  char_y_min = 0;
666  }
667  else {
668  nb_skipped_bytes = 0;
669  char_x_min = (uint16_t) character->x_min_offset;
670  char_y_min = font->y_min;
671  char_y_min += (uint16_t) character->y_min_offset;
672  char_x_max -= (uint16_t) character->x_max_offset;
673  char_y_max -= (uint16_t) character->y_max_offset;
674  }
675 
676  char_byte_cnt = get_bitmap_byte_cnt(font, unicode);
677  }
678 
679  // Render character
680  rectArea.x0 = x + char_x_min;
681  rectArea.y0 = area->y0 + char_y_min;
682  rectArea.height = (char_y_max - char_y_min);
683  rectArea.width = (char_x_max - char_x_min);
684 
685  // If char_byte_cnt = 0, call nbgl_frontDrawImageRle to let speculos notice
686  // a space character was 'displayed'
687  if (!char_byte_cnt || encoding == 1) {
689  &rectArea, char_buffer, char_byte_cnt, fontColor, nb_skipped_bytes);
690  }
691  else {
692  nbgl_frontDrawImage(&rectArea, char_buffer, NO_TRANSFORMATION, fontColor);
693  }
694  x += char_width - font->char_kerning;
695  }
696  return fontId;
697 }
698 
699 #ifdef NBGL_QRCODE
700 static void nbgl_frontDrawQrInternal(const nbgl_area_t *area,
701  color_t foregroundColor,
702  nbgl_qrcode_version_t version)
703 {
704  int size = qrcodegen_getSize(qrcode);
705  uint16_t idx = 0;
706 
707  nbgl_area_t qrArea = {.x0 = area->x0,
708  .y0 = area->y0,
709  .backgroundColor = area->backgroundColor,
710  // QR codes are 1 BPP only
711  .bpp = NBGL_BPP_1};
712  if (version == QRCODE_V4) {
713  // for each point of the V4 QR code, paint 64 pixels in image (8 in width, 8 in height)
714  qrArea.width = 2;
715  qrArea.height = QR_PIXEL_WIDTH_HEIGHT * 2 * size;
716  // paint a column of 2*size pixels in width by 8 pixels in height
717  for (int x = 0; x < size; x++) {
718  idx = 0;
719  for (int y = 0; y < size; y++) {
720  // draw 2 columns at once
721  QrDrawBuffer[idx] = qrcodegen_getModule(qrcode, x, y) ? 0xFF : 0x00;
723  idx += 1;
724  }
725  nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
726  qrArea.x0 += 2;
727  nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
728  qrArea.x0 += 2;
729  nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
730  qrArea.x0 += 2;
731  nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
732  qrArea.x0 += 2;
733  }
734  }
735  else { // V4 small or V10
736  // for each point of the V10 QR code, paint 16 pixels in image (4 in width, 4 in height)
737  qrArea.width = QR_PIXEL_WIDTH_HEIGHT * size;
738  qrArea.height = QR_PIXEL_WIDTH_HEIGHT;
739  // paint a line of 4*size pixels in width by 4 pixels in height
740  for (int y = 0; y < size; y++) {
741  idx = 0;
742  for (int x = 0; x < size; x++) {
743  memset(&QrDrawBuffer[idx], qrcodegen_getModule(qrcode, x, y) ? 0xFF : 0x00, 2);
744  idx += 2;
745  }
746  nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
747  qrArea.y0 += QR_PIXEL_WIDTH_HEIGHT;
748  }
749  }
750 }
751 
764 void nbgl_drawQrCode(const nbgl_area_t *area,
765  nbgl_qrcode_version_t version,
766  const char *text,
767  color_t foregroundColor)
768 {
769  uint8_t versionNum = (version == QRCODE_V10) ? 10 : 4;
770  bool ok = qrcodegen_encodeText(text,
771  tempBuffer,
772  qrcode,
773  qrcodegen_Ecc_LOW,
774  versionNum,
775  versionNum,
776  qrcodegen_Mask_AUTO,
777  true);
778 
779  if (ok) {
780  nbgl_frontDrawQrInternal(area, foregroundColor, version);
781  }
782  else {
783  LOG_WARN(
784  DRAW_LOGGER, "Impossible to draw QRCode text %s with version %d\n", text, versionNum);
785  }
786 }
787 #endif // NBGL_QRCODE
debug traces management
#define LOG_WARN(__logger,...)
Definition: nbgl_debug.h:87
#define LOG_DEBUG(__logger,...)
Definition: nbgl_debug.h:86
@ DRAW_LOGGER
Definition: nbgl_debug.h:29
#define QrDrawBuffer
Definition: nbgl_draw.c:48
void nbgl_drawIcon(nbgl_area_t *area, nbgl_transformation_t transformation, nbgl_color_map_t color_map, const nbgl_icon_details_t *icon)
Helper function to render an icon directly from its nbgl_icon_details_t structure.
Definition: nbgl_draw.c:489
#define QR_PIXEL_WIDTH_HEIGHT
Definition: nbgl_draw.c:34
nbgl_font_id_e nbgl_drawText(const nbgl_area_t *area, const char *text, uint16_t textLen, nbgl_font_id_e fontId, color_t fontColor)
This function draws the given single-line text, with the given parameters.
Definition: nbgl_draw.c:538
quarter_t
Definition: nbgl_draw.c:27
@ BAGL_FILL_CIRCLE_PI_3PI2
Definition: nbgl_draw.c:30
@ BAGL_FILL_CIRCLE_0_PI2
Definition: nbgl_draw.c:28
@ BAGL_FILL_CIRCLE_3PI2_2PI
Definition: nbgl_draw.c:31
@ BAGL_FILL_CIRCLE_PI2_PI
Definition: nbgl_draw.c:29
#define tempBuffer
Definition: nbgl_draw.c:47
#define qrcode
Definition: nbgl_draw.c:46
void nbgl_drawRoundedBorderedRect(const nbgl_area_t *area, nbgl_radius_t radiusIndex, uint8_t stroke, color_t innerColor, color_t borderColor)
This functions draws a rounded corners rectangle with a border, with the given parameters.
Definition: nbgl_draw.c:331
CCASSERT(qr_code_buffer, sizeof(QrCodeBuffer_t)<=GZLIB_UNCOMPRESSED_CHUNK)
void nbgl_drawQrCode(const nbgl_area_t *area, nbgl_qrcode_version_t version, const char *text, color_t foregroundColor)
Draws the given text into a V10 QR code (QR code version is fixed using qrcodegen_VERSION_MIN/qrcodeg...
Definition: nbgl_draw.c:764
void nbgl_drawRoundedRect(const nbgl_area_t *area, nbgl_radius_t radiusIndex, color_t innerColor)
This functions draws a rounded corners rectangle (without border), with the given parameters.
Definition: nbgl_draw.c:237
Middle Level API of the new BOLOS Graphical Library.
#define QR_MAX_PIX_SIZE
Definition: nbgl_draw.h:25
#define QR_V4_NB_PIX_SIZE
Definition: nbgl_draw.h:23
uint32_t nbgl_popUnicodeChar(const uint8_t **text, uint16_t *text_length, 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
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
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
Font screen low-Level driver API, to draw elementary forms.
void nbgl_frontDrawImage(const nbgl_area_t *area, const uint8_t *buffer, nbgl_transformation_t transformation, nbgl_color_map_t colorMap)
void nbgl_frontDrawImageFile(const nbgl_area_t *area, const uint8_t *buffer, nbgl_color_map_t colorMap, const uint8_t *uzlib_chunk_buffer)
void nbgl_frontDrawImageRle(const nbgl_area_t *area, const uint8_t *buffer, uint32_t buffer_len, color_t fore_color, uint8_t nb_skipped_bytes)
void nbgl_frontDrawHorizontalLine(const nbgl_area_t *area, uint8_t mask, color_t lineColor)
void nbgl_frontDrawRect(const nbgl_area_t *area)
Side screen low-Level driver API, to draw elementary forms.
uint8_t ramBuffer[]
Definition: nbgl_obj.c:124
color_t
Definition: nbgl_types.h:101
uint8_t nbgl_transformation_t
Represents the transformation to be applied on the bitmap before rendering This is a bitfield using m...
Definition: nbgl_types.h:348
#define VERTICAL_MIRROR
Definition: nbgl_types.h:61
uint8_t nbgl_color_map_t
Represents the color_map to be used for 2BPP image, or the foreground color for 1BPP image.
Definition: nbgl_types.h:355
nbgl_radius_t
possible radius for objects
Definition: nbgl_types.h:326
@ RADIUS_MAX
Definition: nbgl_types.h:334
@ RADIUS_0_PIXELS
no radius (square angle)
Definition: nbgl_types.h:341
nbgl_qrcode_version_t
possible modes for QR Code
Definition: nbgl_types.h:190
@ QRCODE_V10
QRCode V10, can encode text len up to 1500 chars, display size = 228*228.
Definition: nbgl_types.h:192
@ QRCODE_V4
QRCode V4, can encode text len up to 62 chars, display size = 264*264.
Definition: nbgl_types.h:191
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
#define GZLIB_UNCOMPRESSED_CHUNK
size of gzlib uncompression buffer in bytes
Definition: nbgl_types.h:266
#define NO_TRANSFORMATION
Definition: nbgl_types.h:55
nbgl_bpp_t
Enum to represent the number of bits per pixel (BPP)
Definition: nbgl_types.h:244
@ NBGL_BPP_1
1 bit per pixel
Definition: nbgl_types.h:245
struct PACKED__ nbgl_area_s nbgl_area_t
Represents a rectangle area of the screen.
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
uint32_t encoding
method used to encode bitmap data
Definition: nbgl_fonts.h:68
uint32_t x_min_offset
x_min = x_min_offset
Definition: nbgl_fonts.h:70
uint32_t bitmap_offset
offset of this character in chars buffer
Definition: nbgl_fonts.h:67
uint32_t y_min_offset
y_min = (y_min + y_min_offset)
Definition: nbgl_fonts.h:71
uint32_t x_max_offset
x_max = width - x_max_offset
Definition: nbgl_fonts.h:72
uint32_t y_max_offset
y_max = (height - y_max_offset)
Definition: nbgl_fonts.h:73
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 crop
If false, x_min_offset+y_min_offset=bytes to skip.
Definition: nbgl_fonts.h:87
uint8_t first_char
ASCII code of the first character in bitmap and in characters fields.
Definition: nbgl_fonts.h:90
uint32_t bitmap_len
Size in bytes of the associated bitmap.
Definition: nbgl_fonts.h:81
uint8_t const * bitmap
array containing bitmaps of all characters
Definition: nbgl_fonts.h:95
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 last_char
ASCII code of the last character in bitmap and in characters fields.
Definition: nbgl_fonts.h:92
uint8_t y_min
Most top Y coordinate of any char in the font.
Definition: nbgl_fonts.h:88
uint8_t bpp
number of bits per pixels
Definition: nbgl_fonts.h:83
structure defining a unicode character (except the bitmap)
Definition: nbgl_fonts.h:108
uint32_t encoding
method used to encode bitmap data
Definition: nbgl_fonts.h:110
uint32_t width
width of character in pixels
Definition: nbgl_fonts.h:111
uint32_t x_min_offset
x_min = x_min_offset
Definition: nbgl_fonts.h:112
uint32_t y_min_offset
y_min = (y_min + y_min_offset)
Definition: nbgl_fonts.h:113
uint32_t y_max_offset
y_max = (height - y_max_offset)
Definition: nbgl_fonts.h:115
uint32_t x_max_offset
x_max = width - x_max_offset
Definition: nbgl_fonts.h:114
uint32_t bitmap_offset
offset of this character in chars buffer
Definition: nbgl_fonts.h:116
uint8_t crop
If false, x_min_offset+y_min_offset=bytes to skip.
Definition: nbgl_fonts.h:129
uint8_t y_min
Most top Y coordinate of any char in the font.
Definition: nbgl_fonts.h:130
uint8_t height
height of all characters in pixels
Definition: nbgl_fonts.h:126
const nbgl_font_unicode_t * font
Definition: nbgl_fonts.h:160
const uint8_t * bitmap
Definition: nbgl_fonts.h:162
signed short int16_t
Definition: usbd_conf.h:50
unsigned short uint16_t
Definition: usbd_conf.h:54
unsigned char uint8_t
Definition: usbd_conf.h:53