Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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#include "os_helpers.h"
24
25/*********************
26 * DEFINES
27 *********************/
28#ifdef SCREEN_SIZE_WALLET
29typedef enum {
33#else // SCREEN_SIZE_WALLET
34typedef enum {
35 BAGL_FILL_CIRCLE_0_PI2,
36 BAGL_FILL_CIRCLE_PI2_PI,
37 BAGL_FILL_CIRCLE_PI_3PI2,
38 BAGL_FILL_CIRCLE_3PI2_2PI
39} quarter_t;
40#endif // SCREEN_SIZE_WALLET
41
42#define QR_PIXEL_WIDTH_HEIGHT 4
43
44/**********************
45 * TYPEDEFS
46 **********************/
47#ifdef NBGL_QRCODE
48typedef struct {
49 uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
50 uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
53
54#define qrcode ((QrCodeBuffer_t *) ramBuffer)->qrcode
55#define tempBuffer ((QrCodeBuffer_t *) ramBuffer)->tempBuffer
56#define QrDrawBuffer ((QrCodeBuffer_t *) ramBuffer)->QrDrawBuffer
57#endif // NBGL_QRCODE
58
59// icons to be used to draw circles or discs for a given radius
60#ifdef SCREEN_SIZE_WALLET
65#else // SCREEN_SIZE_WALLET
66typedef struct {
67 const uint8_t *topLeftDisc;
68 const uint8_t *bottomLeftDisc;
69 const uint8_t *topLeftCircle;
70 const uint8_t *bottomLeftCircle;
72#endif // SCREEN_SIZE_WALLET
73
74/**********************
75 * STATIC PROTOTYPES
76 **********************/
77
78/**********************
79 * STATIC VARIABLES
80 **********************/
81#ifndef SCREEN_SIZE_WALLET
82static const uint8_t quarter_disc_3px_1bpp[] = {0xEC, 0xFF};
83static const uint8_t quarter_disc_3px_90_1bpp[] = {0x2F, 0xFF};
84static const uint8_t quarter_disc_3px_180_1bpp[] = {0x9B, 0xFF};
85static const uint8_t quarter_disc_3px_270_1bpp[] = {0xFA, 0x00};
86
87static const uint8_t quarter_circle_3px_1bpp[] = {0x4C, 0x00};
88static const uint8_t quarter_circle_3px_90_1bpp[] = {0x0D, 0x00};
89static const uint8_t quarter_circle_3px_180_1bpp[] = {0x19, 0x00};
90static const uint8_t quarter_circle_3px_270_1bpp[] = {0x58, 0x00};
91#endif // SCREEN_SIZE_WALLET
92
93// indexed by nbgl_radius_t (except RADIUS_0_PIXELS)
94static const uint8_t radiusValues[RADIUS_MAX + 1] = {
95#ifdef SCREEN_SIZE_WALLET
96 20,
97 28,
98 32,
99 40,
100 44
101#else // SCREEN_SIZE_WALLET
102 1,
103 3
104#endif // SCREEN_SIZE_WALLET
105};
106
107#ifdef SCREEN_SIZE_WALLET
108
109#if COMMON_RADIUS == 28
110static const radiusIcons_t radiusIcons28px
111 = {&C_half_disc_left_56px_1bpp, &C_half_circle_left_56px_1bpp};
112#elif COMMON_RADIUS == 40
113static const radiusIcons_t radiusIcons40px
114 = {&C_half_disc_left_80px_1bpp, &C_half_circle_left_80px_1bpp};
115#elif COMMON_RADIUS == 44
116static const radiusIcons_t radiusIcons44px
117 = {&C_half_disc_left_88px_1bpp, &C_half_circle_left_88px_1bpp};
118#endif
119#if SMALL_BUTTON_RADIUS == 20
120static const radiusIcons_t radiusIcons20px = {&C_half_disc_left_40px_1bpp, NULL};
121#elif SMALL_BUTTON_RADIUS == 32
122static const radiusIcons_t radiusIcons32px
123 = {&C_half_disc_left_64px_1bpp, &C_half_circle_left_64px_1bpp};
124#endif
125
126// indexed by nbgl_radius_t (except RADIUS_0_PIXELS)
127static const radiusIcons_t *radiusIcons[RADIUS_MAX + 1] = {
128#if SMALL_BUTTON_RADIUS == 20
129 &radiusIcons20px,
130#else
131 NULL,
132#endif
133#if COMMON_RADIUS == 28
134 &radiusIcons28px,
135#else
136 NULL,
137#endif
138#if SMALL_BUTTON_RADIUS == 32
139 &radiusIcons32px,
140#else
141 NULL,
142#endif
143#if COMMON_RADIUS == 40
144 &radiusIcons40px,
145#else
146 NULL,
147#endif
148#if COMMON_RADIUS == 44
149 &radiusIcons44px
150#else
151 NULL
152#endif // COMMON_RADIUS
153};
154#endif // SCREEN_SIZE_WALLET
155
156#ifdef NBGL_QRCODE
157// ensure that the ramBuffer also used for image file decompression is big enough for QR code
159#endif // NBGL_QRCODE
160
161/**********************
162 * VARIABLES
163 **********************/
164
165/**********************
166 * STATIC PROTOTYPES
167 **********************/
168
169#ifdef SCREEN_SIZE_WALLET
170static void draw_circle_helper(int x0,
171 int y0,
172 nbgl_radius_t radiusIndex,
173 half_t half,
174 color_t borderColor,
175 color_t innerColor,
176 color_t backgroundColor)
177{
178 const nbgl_icon_details_t *half_icon = NULL;
179 nbgl_area_t area = {.bpp = NBGL_BPP_1, .backgroundColor = backgroundColor};
180
181 // radius is not supported
182 if (radiusIndex > RADIUS_MAX) {
183 return;
184 }
185 if (borderColor == innerColor) {
186 half_icon = PIC(radiusIcons[radiusIndex]->leftDisc);
187 }
188 else {
189#if NB_COLOR_BITS == 1
190 borderColor = BLACK;
191#endif
192 half_icon = PIC(radiusIcons[radiusIndex]->leftCircle);
193 }
194 area.width = half_icon->width;
195 area.height = half_icon->height;
196 switch (half) {
197 case LEFT_HALF: // left
198 area.x0 = x0;
199 area.y0 = y0;
200 nbgl_frontDrawImage(&area, half_icon->bitmap, NO_TRANSFORMATION, borderColor);
201 break;
202 case RIGHT_HALF: // right
203 area.x0 = x0 - half_icon->width;
204 area.y0 = y0;
205 nbgl_frontDrawImage(&area, half_icon->bitmap, VERTICAL_MIRROR, borderColor);
206 break;
207 }
208}
209#else // SCREEN_SIZE_WALLET
210static void draw_circle_helper(int x_center,
211 int y_center,
212 nbgl_radius_t radiusIndex,
213 quarter_t quarter,
214 color_t borderColor,
215 color_t innerColor,
216 color_t backgroundColor)
217{
218 const uint8_t *quarter_buffer = NULL;
219 nbgl_area_t area = {.bpp = NBGL_BPP_1, .backgroundColor = backgroundColor};
220
221 // radius is not supported
222 if (radiusIndex > RADIUS_MAX) {
223 return;
224 }
225 area.width = area.height = radiusValues[radiusIndex];
226 switch (quarter) {
227 case BAGL_FILL_CIRCLE_3PI2_2PI: // bottom right
228 area.x0 = x_center;
229 area.y0 = y_center;
230 quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_180_1bpp
231 : quarter_circle_3px_180_1bpp;
232 break;
233 case BAGL_FILL_CIRCLE_PI_3PI2: // bottom left
234 area.x0 = x_center - area.width;
235 area.y0 = y_center;
236 quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_270_1bpp
237 : quarter_circle_3px_270_1bpp;
238 break;
239 case BAGL_FILL_CIRCLE_0_PI2: // top right
240 area.x0 = x_center;
241 area.y0 = y_center - area.width;
242 quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_90_1bpp
243 : quarter_circle_3px_90_1bpp;
244 break;
245 case BAGL_FILL_CIRCLE_PI2_PI: // top left
246 area.x0 = x_center - area.width;
247 area.y0 = y_center - area.width;
248 quarter_buffer
249 = (borderColor == innerColor) ? quarter_disc_3px_1bpp : quarter_circle_3px_1bpp;
250 break;
251 }
252 nbgl_frontDrawImage(&area, quarter_buffer, NO_TRANSFORMATION, borderColor);
253}
254#endif // SCREEN_SIZE_WALLET
255
256/**********************
257 * GLOBAL FUNCTIONS
258 **********************/
259
269void nbgl_drawRoundedRect(const nbgl_area_t *area, nbgl_radius_t radiusIndex, color_t innerColor)
270{
271 nbgl_area_t rectArea;
272 uint8_t radius;
273
275 "nbgl_drawRoundedRect x0 = %d, y0 = %d, width =%d, height =%d\n",
276 area->x0,
277 area->y0,
278 area->width,
279 area->height);
280
281 if (radiusIndex <= RADIUS_MAX) {
282 radius = radiusValues[radiusIndex];
283 }
284 else if (radiusIndex == RADIUS_0_PIXELS) {
285 radius = 0;
286 }
287 else {
288 // radius not supported
289 LOG_WARN(DRAW_LOGGER, "nbgl_drawRoundedRect forbidden radius index =%d\n", radiusIndex);
290 return;
291 }
292
293 // Draw full rectangle
294 rectArea.x0 = area->x0;
295 rectArea.y0 = area->y0;
296 rectArea.width = area->width;
297 rectArea.height = area->height;
298 rectArea.backgroundColor = innerColor;
299 nbgl_frontDrawRect(&rectArea);
300 // special case when radius is null, just draw a rectangle
301 if (radiusIndex == RADIUS_0_PIXELS) {
302 return;
303 }
304
305#ifdef SCREEN_SIZE_WALLET
306 UNUSED(radius);
307 // Draw 2 halves of disc
308 draw_circle_helper(area->x0,
309 area->y0,
310 radiusIndex,
311 LEFT_HALF,
312 innerColor, // unused
313 innerColor,
314 area->backgroundColor);
315 draw_circle_helper(area->x0 + area->width,
316 area->y0,
317 radiusIndex,
319 innerColor, // unused
320 innerColor,
321 area->backgroundColor);
322#else // SCREEN_SIZE_WALLET
323 if (radiusIndex == RADIUS_1_PIXEL) {
324 return;
325 }
326 // Draw 4 quarters of disc
327 draw_circle_helper(area->x0 + radius,
328 area->y0 + radius,
329 radiusIndex,
330 BAGL_FILL_CIRCLE_PI2_PI,
331 innerColor, // unused
332 innerColor,
333 area->backgroundColor);
334 draw_circle_helper(area->x0 + area->width - radius,
335 area->y0 + radius,
336 radiusIndex,
337 BAGL_FILL_CIRCLE_0_PI2,
338 innerColor, // unused
339 innerColor,
340 area->backgroundColor);
341 draw_circle_helper(area->x0 + radius,
342 area->y0 + area->height - radius,
343 radiusIndex,
344 BAGL_FILL_CIRCLE_PI_3PI2,
345 innerColor, // unused
346 innerColor,
347 area->backgroundColor);
348 draw_circle_helper(area->x0 + area->width - radius,
349 area->y0 + area->height - radius,
350 radiusIndex,
351 BAGL_FILL_CIRCLE_3PI2_2PI,
352 innerColor, // unused
353 innerColor,
354 area->backgroundColor);
355#endif // SCREEN_SIZE_WALLET
356}
357
369 nbgl_radius_t radiusIndex,
370 uint8_t stroke,
371 color_t innerColor,
372 color_t borderColor)
373{
374 uint8_t radius;
375 nbgl_area_t rectArea;
376
377 LOG_DEBUG(
379 "nbgl_drawRoundedBorderedRect: innerColor = %d, borderColor = %d, backgroundColor=%d\n",
380 innerColor,
381 borderColor,
382 area->backgroundColor);
383
384 if (radiusIndex <= RADIUS_MAX) {
385 radius = radiusValues[radiusIndex];
386 }
387 else if (radiusIndex == RADIUS_0_PIXELS) {
388 radius = 0;
389 }
390 else {
391 // radius not supported
392 LOG_WARN(
393 DRAW_LOGGER, "nbgl_drawRoundedBorderedRect forbidden radius index =%d\n", radiusIndex);
394 return;
395 }
396 rectArea.backgroundColor = innerColor;
397
398 // Draw 1 rectangle in inner rectangle
399 rectArea.x0 = area->x0;
400 rectArea.y0 = area->y0;
401 rectArea.width = area->width;
402 rectArea.height = area->height;
403 nbgl_frontDrawRect(&rectArea);
404 // special case, when border_color == inner_color == background_color, return
405 if ((innerColor == borderColor) && (borderColor == area->backgroundColor)) {
406 return;
407 }
408 // border
409 // 4 rectangles (with last pixel of each corner not set)
410#ifdef SCREEN_SIZE_WALLET
411 uint16_t circle_width = 0;
412 if (radiusIndex <= RADIUS_MAX) {
413 const nbgl_icon_details_t *half_icon = PIC(radiusIcons[radiusIndex]->leftDisc);
414 circle_width = half_icon->width;
415 }
416 if ((2 * circle_width) < area->width) {
417 if ((area->height - stroke) > VERTICAL_ALIGNMENT) {
418 rectArea.height = stroke;
419 nbgl_frontDrawLine(&rectArea, 0, borderColor); // top
420 rectArea.y0 = area->y0 + area->height - stroke;
421 nbgl_frontDrawLine(&rectArea, 0, borderColor); // bottom
422 }
423 else {
424 uint8_t pattern = 0;
425 uint32_t i;
426 for (i = 0; i < stroke; i++) {
427 pattern |= 1 << (7 - i);
428 }
429 for (i = area->height - stroke; i < area->height; i++) {
430 pattern |= 1 << (7 - i);
431 }
432 memset(ramBuffer, pattern, area->width);
433 rectArea.height = 8;
434 rectArea.bpp = NBGL_BPP_1;
435 nbgl_frontDrawImage(&rectArea, ramBuffer, NO_TRANSFORMATION, borderColor);
436 }
437 }
438 if ((2 * radius) < area->height) {
439 rectArea.x0 = area->x0;
440 rectArea.y0 = area->y0;
441 rectArea.width = stroke;
442 rectArea.height = area->height;
443 rectArea.backgroundColor = area->backgroundColor;
444 nbgl_frontDrawLine(&rectArea, 0, borderColor); // left
445 rectArea.x0 = area->x0 + area->width - stroke;
446 nbgl_frontDrawLine(&rectArea, 0, borderColor); // right
447 }
448 if (radiusIndex <= RADIUS_MAX) {
449 // Draw 4 quarters of circles
450 draw_circle_helper(area->x0,
451 area->y0,
452 radiusIndex,
453 LEFT_HALF,
454 borderColor,
455 innerColor,
456 area->backgroundColor);
457 draw_circle_helper(area->x0 + area->width,
458 area->y0,
459 radiusIndex,
461 borderColor,
462 innerColor,
463 area->backgroundColor);
464 }
465#else // SCREEN_SIZE_WALLET
466 rectArea.x0 = area->x0 + radius;
467 rectArea.y0 = area->y0;
468 rectArea.width = area->width - 2 * radius;
469 rectArea.height = stroke;
470 rectArea.backgroundColor = borderColor;
471 nbgl_frontDrawRect(&rectArea); // top
472 rectArea.y0 = area->y0 + area->height - stroke;
473 nbgl_frontDrawRect(&rectArea); // bottom
474 if ((2 * radius) < area->height) {
475 rectArea.x0 = area->x0;
476 rectArea.y0 = area->y0 + radius;
477 rectArea.width = stroke;
478 rectArea.height = area->height - 2 * radius;
479 rectArea.backgroundColor = area->backgroundColor;
480 nbgl_frontDrawLine(&rectArea, 0, borderColor); // left
481 rectArea.x0 = area->x0 + area->width - stroke;
482 nbgl_frontDrawLine(&rectArea, 0, borderColor); // right
483 }
484
485 if (radiusIndex <= RADIUS_MAX) {
486 // Draw 4 quarters of circles
487 draw_circle_helper(area->x0 + radius,
488 area->y0 + radius,
489 radiusIndex,
490 BAGL_FILL_CIRCLE_PI2_PI,
491 borderColor,
492 innerColor,
493 area->backgroundColor);
494 draw_circle_helper(area->x0 + area->width - radius,
495 area->y0 + radius,
496 radiusIndex,
497 BAGL_FILL_CIRCLE_0_PI2,
498 borderColor,
499 innerColor,
500 area->backgroundColor);
501 draw_circle_helper(area->x0 + radius,
502 area->y0 + area->height - radius,
503 radiusIndex,
504 BAGL_FILL_CIRCLE_PI_3PI2,
505 borderColor,
506 innerColor,
507 area->backgroundColor);
508 draw_circle_helper(area->x0 + area->width - radius,
509 area->y0 + area->height - radius,
510 radiusIndex,
511 BAGL_FILL_CIRCLE_3PI2_2PI,
512 borderColor,
513 innerColor,
514 area->backgroundColor);
515 }
516#endif // SCREEN_SIZE_WALLET
517}
518
532 nbgl_transformation_t transformation,
533 nbgl_color_map_t color_map,
534 const nbgl_icon_details_t *icon)
535{
536 if (icon->isFile) {
537 nbgl_frontDrawImageFile(area, icon->bitmap, color_map, ramBuffer);
538 }
539 else {
540 nbgl_frontDrawImage(area, icon->bitmap, transformation, color_map);
541 }
542}
543
551static uint16_t get_bitmap_byte_cnt(const nbgl_font_t *font, uint8_t charId)
552{
553 if ((charId < font->first_char) || (charId > font->last_char)) {
554 return 0;
555 }
556
557 uint16_t baseId = charId - font->first_char;
558 if (charId < font->last_char) {
559 const nbgl_font_character_t *character
560 = (const nbgl_font_character_t *) PIC(&font->characters[baseId]);
561 const nbgl_font_character_t *nextCharacter
562 = (const nbgl_font_character_t *) PIC(&font->characters[baseId + 1]);
563 return (nextCharacter->bitmap_offset - character->bitmap_offset);
564 }
565 else if (charId == font->last_char) {
566 return (font->bitmap_len - font->characters[baseId].bitmap_offset);
567 }
568 return 0;
569}
570
581 const char *text,
582 uint16_t textLen,
583 nbgl_font_id_e fontId,
584 color_t fontColor)
585{
586 // text is a series of characters, each character being a bitmap
587 // we need to align bitmaps on width multiple of 4 limitation.
588 int16_t x = area->x0;
589 nbgl_area_t rectArea;
590 const nbgl_font_t *font = nbgl_getFont(fontId);
591#ifdef HAVE_UNICODE_SUPPORT
592 nbgl_unicode_ctx_t *unicode_ctx = NULL;
593#endif // HAVE_UNICODE_SUPPORT
594
596 "nbgl_drawText: x0 = %d, y0 = %d, w = %d, h = %d, fontColor = %d, "
597 "backgroundColor=%d, text = %s\n",
598 area->x0,
599 area->y0,
600 area->width,
601 area->height,
602 fontColor,
603 area->backgroundColor,
604 text);
605
606 rectArea.backgroundColor = area->backgroundColor;
607 rectArea.bpp = (nbgl_bpp_t) font->bpp;
608
609 while (textLen > 0) {
610 const nbgl_font_character_t *character;
611 uint8_t char_width;
612 uint32_t unicode;
613 bool is_unicode;
614 const uint8_t *char_buffer;
615 int16_t char_x_min;
616 int16_t char_y_min;
617 int16_t char_x_max;
618 int16_t char_y_max;
619 uint16_t char_byte_cnt;
620 uint8_t encoding;
621 uint8_t nb_skipped_bytes;
622
623 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
624
625 if (is_unicode) {
626#ifdef HAVE_UNICODE_SUPPORT
627 if (unicode_ctx == NULL) {
628 unicode_ctx = nbgl_getUnicodeFont(fontId);
629 }
630 const nbgl_font_unicode_character_t *unicodeCharacter
631 = nbgl_getUnicodeFontCharacter(unicode);
632 // if not supported char, go to next one
633 if (unicodeCharacter == NULL) {
634 continue;
635 }
636 char_width = unicodeCharacter->width;
637#if defined(HAVE_LANGUAGE_PACK)
638 char_buffer = unicode_ctx->bitmap;
639 char_buffer += unicodeCharacter->bitmap_offset;
640
641 char_x_max = char_width;
642 char_y_max = unicode_ctx->font->height;
643
644 if (!unicode_ctx->font->crop) {
645 // Take in account the skipped bytes, if any
646 nb_skipped_bytes = (unicodeCharacter->x_min_offset & 7) << 3;
647 nb_skipped_bytes |= unicodeCharacter->y_min_offset & 7;
648 char_x_min = 0;
649 char_y_min = 0;
650 }
651 else {
652 nb_skipped_bytes = 0;
653 char_x_min = (uint16_t) unicodeCharacter->x_min_offset;
654 char_y_min = unicode_ctx->font->y_min;
655 char_y_min += (uint16_t) unicodeCharacter->y_min_offset;
656 char_x_max -= (uint16_t) unicodeCharacter->x_max_offset;
657 char_y_max -= (uint16_t) unicodeCharacter->y_max_offset;
658 }
659
660 char_byte_cnt = nbgl_getUnicodeFontCharacterByteCount();
661 encoding = unicodeCharacter->encoding;
662#endif // defined(HAVE_LANGUAGE_PACK)
663#else // HAVE_UNICODE_SUPPORT
664 continue;
665#endif // HAVE_UNICODE_SUPPORT
666 }
667 else {
668 if (unicode == '\f') {
669 break;
670 }
671 // if \b, switch fontId
672 else if (unicode == '\b') {
673 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
675#ifdef HAVE_UNICODE_SUPPORT
676 unicode_ctx = nbgl_getUnicodeFont(fontId);
677#endif // HAVE_UNICODE_SUPPORT
678 font = (const nbgl_font_t *) nbgl_getFont(fontId);
679 }
680 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
682#ifdef HAVE_UNICODE_SUPPORT
683 unicode_ctx = nbgl_getUnicodeFont(fontId);
684#endif // HAVE_UNICODE_SUPPORT
685 font = (const nbgl_font_t *) nbgl_getFont(fontId);
686 }
687 continue;
688 }
689 // if not supported char, go to next one
690 if ((unicode < font->first_char) || (unicode > font->last_char)) {
691 continue;
692 }
693 character = (const nbgl_font_character_t *) PIC(
694 &font->characters[unicode - font->first_char]);
695 char_buffer = (const uint8_t *) PIC(&font->bitmap[character->bitmap_offset]);
696 char_width = character->width;
697 encoding = character->encoding;
698
699 char_x_max = char_width;
700 char_y_max = font->height;
701
702 if (!font->crop) {
703 // Take in account the skipped bytes, if any
704 nb_skipped_bytes = (character->x_min_offset & 7) << 3;
705 nb_skipped_bytes |= character->y_min_offset & 7;
706 char_x_min = 0;
707 char_y_min = 0;
708 }
709 else {
710 nb_skipped_bytes = 0;
711 char_x_min = (uint16_t) character->x_min_offset;
712 char_y_min = font->y_min;
713 char_y_min += (uint16_t) character->y_min_offset;
714 char_x_max -= (uint16_t) character->x_max_offset;
715 char_y_max -= (uint16_t) character->y_max_offset;
716 }
717
718 char_byte_cnt = get_bitmap_byte_cnt(font, unicode);
719 }
720
721 // Render character
722 rectArea.x0 = x + char_x_min;
723 rectArea.y0 = area->y0 + char_y_min;
724 rectArea.height = (char_y_max - char_y_min);
725 rectArea.width = (char_x_max - char_x_min);
726
727 // If char_byte_cnt = 0, call nbgl_frontDrawImageRle to let speculos notice
728 // a space character was 'displayed'
729 if (!char_byte_cnt || encoding == 1) {
731 &rectArea, char_buffer, char_byte_cnt, fontColor, nb_skipped_bytes);
732 }
733 else {
734 nbgl_frontDrawImage(&rectArea, char_buffer, NO_TRANSFORMATION, fontColor);
735 }
736 x += char_width - font->char_kerning;
737 }
738 return fontId;
739}
740
741#ifdef NBGL_QRCODE
742#ifdef TARGET_APEX
743static void push_bits(uint8_t *buffer, uint16_t current_bits, uint8_t bits, uint8_t nb_bits)
744{
745 uint8_t byte = current_bits / 8;
746 uint8_t remaining_bits = 8 - current_bits % 8;
747
748 if (remaining_bits >= nb_bits) {
749 // put bits in possible MSB
750 buffer[byte] |= bits << (remaining_bits - nb_bits);
751 }
752 else {
753 // manage MSB
754 buffer[byte] |= bits >> (nb_bits - remaining_bits);
755 nb_bits -= remaining_bits;
756 // then LSB
757 buffer[byte + 1] |= bits << (8 - nb_bits);
758 }
759}
760#endif // TARGET_APEX
761
762static void nbgl_frontDrawQrInternal(const nbgl_area_t *area,
763 color_t foregroundColor,
764 nbgl_qrcode_version_t version)
765{
766 int size = qrcodegen_getSize(qrcode);
767 uint16_t idx = 0;
768
769 nbgl_area_t qrArea = {.x0 = area->x0,
770 .y0 = area->y0,
771 .backgroundColor = area->backgroundColor,
772 // QR codes are 1 BPP only
773 .bpp = NBGL_BPP_1};
774 if (version == QRCODE_V4) {
775#ifndef TARGET_APEX
776 // for each point of the V4 QR code, paint 64 pixels in image (8 in width, 8 in height)
777 qrArea.width = 2;
778 qrArea.height = QR_PIXEL_WIDTH_HEIGHT * 2 * size;
779 // paint a column of 2*size pixels in width by 8 pixels in height
780 for (int x = 0; x < size; x++) {
781 idx = 0;
782 for (int y = 0; y < size; y++) {
783 // draw 2 columns at once
784 QrDrawBuffer[idx] = qrcodegen_getModule(qrcode, x, y) ? 0xFF : 0x00;
786 idx += 1;
787 }
788 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
789 qrArea.x0 += 2;
790 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
791 qrArea.x0 += 2;
792 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
793 qrArea.x0 += 2;
794 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
795 qrArea.x0 += 2;
796 }
797#else // TARGET_APEX
798 // for each point of the V4 QR code, paint 5*5 pixels in image
799 qrArea.width = 1;
800 qrArea.height = 5 * size;
801 for (int x = 0; x < size; x++) {
802 idx = 0;
803 memset(QrDrawBuffer, 0, (size * 5 + 7) / 8);
804 // paint a column of 5*size pixels in width by 5 pixels in height
805 for (int y = 0; y < size; y++) {
806 push_bits(QrDrawBuffer, 5 * y, qrcodegen_getModule(qrcode, x, y) ? 0x1F : 0x00, 5);
807 }
808 for (int z = 0; z < 5; z++) {
809 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
810 qrArea.x0 += 1;
811 }
812 }
813#endif // TARGET_APEX
814 }
815 else { // V4 small or V10
816 // for each point of the V10 QR code, paint 16 pixels in image (4 in width, 4 in height)
817 qrArea.width = 1;
818 qrArea.height = QR_PIXEL_WIDTH_HEIGHT * size;
819 // paint a line of 4*size pixels in width by 4 pixels in height
820 for (int x = 0; x < size; x++) {
821 idx = 0;
822 memset(QrDrawBuffer, 0, (size + 1) / 2);
823 for (int y = 0; y < size; y++) {
824 QrDrawBuffer[idx] |= qrcodegen_getModule(qrcode, x, y) ? 0xF0 >> ((y & 1) * 4) : 0;
825 if (y & 1) {
826 idx++;
827 }
828 }
829 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
830 qrArea.x0++;
831 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
832 qrArea.x0++;
833 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
834 qrArea.x0++;
835 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
836 qrArea.x0++;
837 }
838 }
839}
840
854 nbgl_qrcode_version_t version,
855 const char *text,
856 color_t foregroundColor)
857{
858 uint8_t versionNum = (version == QRCODE_V10) ? 10 : 4;
859 bool ok = qrcodegen_encodeText(text,
861 qrcode,
862 qrcodegen_Ecc_LOW,
863 versionNum,
864 versionNum,
865 qrcodegen_Mask_AUTO,
866 true);
867
868 if (ok) {
869 nbgl_frontDrawQrInternal(area, foregroundColor, version);
870 }
871 else {
872 LOG_WARN(
873 DRAW_LOGGER, "Impossible to draw QRCode text %s with version %d\n", text, versionNum);
874 }
875}
876#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:56
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:531
#define QR_PIXEL_WIDTH_HEIGHT
Definition nbgl_draw.c:42
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:580
#define tempBuffer
Definition nbgl_draw.c:55
#define qrcode
Definition nbgl_draw.c:54
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:368
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:853
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:269
half_t
Definition nbgl_draw.c:29
@ RIGHT_HALF
Definition nbgl_draw.c:31
@ LEFT_HALF
Definition nbgl_draw.c:30
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:144
nbgl_font_id_e
Definition nbgl_fonts.h:143
@ BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
Definition nbgl_fonts.h:152
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition nbgl_fonts.h:150
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
Font screen low-Level driver API, to draw elementary forms.
void nbgl_frontDrawLine(const nbgl_area_t *area, uint8_t dotStartIdx, color_t lineColor)
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_frontDrawRect(const nbgl_area_t *area)
Side screen low-Level driver API, to draw elementary forms.
uint8_t ramBuffer[]
Definition nbgl_obj.c:145
color_t
Definition nbgl_types.h:140
@ BLACK
Definition nbgl_types.h:141
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:383
#define VERTICAL_MIRROR
Definition nbgl_types.h:97
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:390
nbgl_radius_t
possible radius indexes for objects
Definition nbgl_types.h:363
@ RADIUS_MAX
Definition nbgl_types.h:370
@ RADIUS_0_PIXELS
no radius (square angle)
Definition nbgl_types.h:376
nbgl_qrcode_version_t
possible modes for QR Code
Definition nbgl_types.h:229
@ QRCODE_V10
QRCode V10, can encode text len up to 1500 chars, display size = 228*228.
Definition nbgl_types.h:231
@ QRCODE_V4
QRCode V4, can encode text len up to 62 chars, display size = 264*264.
Definition nbgl_types.h:230
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:305
#define NO_TRANSFORMATION
Definition nbgl_types.h:91
nbgl_bpp_t
Enum to represent the number of bits per pixel (BPP)
Definition nbgl_types.h:283
@ NBGL_BPP_1
1 bit per pixel
Definition nbgl_types.h:284
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:69
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:72
uint32_t encoding
method used to encode bitmap data
Definition nbgl_fonts.h:71
uint32_t x_min_offset
x_min = x_min_offset
Definition nbgl_fonts.h:73
uint32_t bitmap_offset
offset of this character in chars buffer
Definition nbgl_fonts.h:70
uint32_t y_min_offset
y_min = (y_min + y_min_offset)
Definition nbgl_fonts.h:74
uint32_t x_max_offset
x_max = width - x_max_offset
Definition nbgl_fonts.h:75
uint32_t y_max_offset
y_max = (height - y_max_offset)
Definition nbgl_fonts.h:76
structure defining an ASCII font
Definition nbgl_fonts.h:83
uint8_t char_kerning
kerning for the font
Definition nbgl_fonts.h:89
uint8_t crop
If false, x_min_offset+y_min_offset=bytes to skip.
Definition nbgl_fonts.h:90
uint8_t first_char
ASCII code of the first character in bitmap and in characters fields.
Definition nbgl_fonts.h:93
uint32_t bitmap_len
Size in bytes of the associated bitmap.
Definition nbgl_fonts.h:84
uint8_t const * bitmap
array containing bitmaps of all characters
Definition nbgl_fonts.h:98
const nbgl_font_character_t *const characters
array containing definitions of all characters
Definition nbgl_fonts.h:97
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:87
uint8_t last_char
ASCII code of the last character in bitmap and in characters fields.
Definition nbgl_fonts.h:95
uint8_t y_min
Most top Y coordinate of any char in the font.
Definition nbgl_fonts.h:91
uint8_t bpp
number of bits per pixels
Definition nbgl_fonts.h:86
structure defining a unicode character (except the bitmap)
Definition nbgl_fonts.h:111
uint32_t encoding
method used to encode bitmap data
Definition nbgl_fonts.h:113
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:114
uint32_t x_min_offset
x_min = x_min_offset
Definition nbgl_fonts.h:115
uint32_t y_min_offset
y_min = (y_min + y_min_offset)
Definition nbgl_fonts.h:116
uint32_t y_max_offset
y_max = (height - y_max_offset)
Definition nbgl_fonts.h:118
uint32_t x_max_offset
x_max = width - x_max_offset
Definition nbgl_fonts.h:117
uint32_t bitmap_offset
offset of this character in chars buffer
Definition nbgl_fonts.h:119
uint8_t crop
If false, x_min_offset+y_min_offset=bytes to skip.
Definition nbgl_fonts.h:132
uint8_t y_min
Most top Y coordinate of any char in the font.
Definition nbgl_fonts.h:133
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:129
const nbgl_font_unicode_t * font
Definition nbgl_fonts.h:166
const uint8_t * bitmap
Definition nbgl_fonts.h:168
const nbgl_icon_details_t * leftCircle
Definition nbgl_draw.c:63
const nbgl_icon_details_t * leftDisc
Definition nbgl_draw.c:62