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
121 = {&C_half_disc_left_40px_1bpp, &C_half_circle_left_40px_1bpp};
122#elif SMALL_BUTTON_RADIUS == 32
123static const radiusIcons_t radiusIcons32px
124 = {&C_half_disc_left_64px_1bpp, &C_half_circle_left_64px_1bpp};
125#endif
126
127// indexed by nbgl_radius_t (except RADIUS_0_PIXELS)
128static const radiusIcons_t *radiusIcons[RADIUS_MAX + 1] = {
129#if SMALL_BUTTON_RADIUS == 20
130 &radiusIcons20px,
131#else
132 NULL,
133#endif
134#if COMMON_RADIUS == 28
135 &radiusIcons28px,
136#else
137 NULL,
138#endif
139#if SMALL_BUTTON_RADIUS == 32
140 &radiusIcons32px,
141#else
142 NULL,
143#endif
144#if COMMON_RADIUS == 40
145 &radiusIcons40px,
146#else
147 NULL,
148#endif
149#if COMMON_RADIUS == 44
150 &radiusIcons44px
151#else
152 NULL
153#endif // COMMON_RADIUS
154};
155#endif // SCREEN_SIZE_WALLET
156
157#ifdef NBGL_QRCODE
158// ensure that the ramBuffer also used for image file decompression is big enough for QR code
160#endif // NBGL_QRCODE
161
162/**********************
163 * VARIABLES
164 **********************/
165
166/**********************
167 * STATIC PROTOTYPES
168 **********************/
169
170#ifdef SCREEN_SIZE_WALLET
171static void draw_circle_helper(int x0,
172 int y0,
173 nbgl_radius_t radiusIndex,
174 half_t half,
175 color_t borderColor,
176 color_t innerColor,
177 color_t backgroundColor)
178{
179 const nbgl_icon_details_t *half_icon = NULL;
180 nbgl_area_t area = {.bpp = NBGL_BPP_1, .backgroundColor = backgroundColor};
181
182 // radius is not supported
183 if (radiusIndex > RADIUS_MAX) {
184 return;
185 }
186 if (borderColor == innerColor) {
187 half_icon = PIC(radiusIcons[radiusIndex]->leftDisc);
188 }
189 else {
190#if NB_COLOR_BITS == 1
191 borderColor = BLACK;
192#endif
193 half_icon = PIC(radiusIcons[radiusIndex]->leftCircle);
194 }
195 area.width = half_icon->width;
196 area.height = half_icon->height;
197 switch (half) {
198 case LEFT_HALF: // left
199 area.x0 = x0;
200 area.y0 = y0;
201 nbgl_frontDrawImage(&area, half_icon->bitmap, NO_TRANSFORMATION, borderColor);
202 break;
203 case RIGHT_HALF: // right
204 area.x0 = x0 - half_icon->width;
205 area.y0 = y0;
206 nbgl_frontDrawImage(&area, half_icon->bitmap, VERTICAL_MIRROR, borderColor);
207 break;
208 }
209}
210#else // SCREEN_SIZE_WALLET
211static void draw_circle_helper(int x_center,
212 int y_center,
213 nbgl_radius_t radiusIndex,
214 quarter_t quarter,
215 color_t borderColor,
216 color_t innerColor,
217 color_t backgroundColor)
218{
219 const uint8_t *quarter_buffer = NULL;
220 nbgl_area_t area = {.bpp = NBGL_BPP_1, .backgroundColor = backgroundColor};
221
222 // radius is not supported
223 if (radiusIndex > RADIUS_MAX) {
224 return;
225 }
226 area.width = area.height = radiusValues[radiusIndex];
227 switch (quarter) {
228 case BAGL_FILL_CIRCLE_3PI2_2PI: // bottom right
229 area.x0 = x_center;
230 area.y0 = y_center;
231 quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_180_1bpp
232 : quarter_circle_3px_180_1bpp;
233 break;
234 case BAGL_FILL_CIRCLE_PI_3PI2: // bottom left
235 area.x0 = x_center - area.width;
236 area.y0 = y_center;
237 quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_270_1bpp
238 : quarter_circle_3px_270_1bpp;
239 break;
240 case BAGL_FILL_CIRCLE_0_PI2: // top right
241 area.x0 = x_center;
242 area.y0 = y_center - area.width;
243 quarter_buffer = (borderColor == innerColor) ? quarter_disc_3px_90_1bpp
244 : quarter_circle_3px_90_1bpp;
245 break;
246 case BAGL_FILL_CIRCLE_PI2_PI: // top left
247 area.x0 = x_center - area.width;
248 area.y0 = y_center - area.width;
249 quarter_buffer
250 = (borderColor == innerColor) ? quarter_disc_3px_1bpp : quarter_circle_3px_1bpp;
251 break;
252 }
253 nbgl_frontDrawImage(&area, quarter_buffer, NO_TRANSFORMATION, borderColor);
254}
255#endif // SCREEN_SIZE_WALLET
256
257/**********************
258 * GLOBAL FUNCTIONS
259 **********************/
260
270void nbgl_drawRoundedRect(const nbgl_area_t *area, nbgl_radius_t radiusIndex, color_t innerColor)
271{
272 nbgl_area_t rectArea;
273 uint8_t radius;
274
276 "nbgl_drawRoundedRect x0 = %d, y0 = %d, width =%d, height =%d\n",
277 area->x0,
278 area->y0,
279 area->width,
280 area->height);
281
282 if (radiusIndex <= RADIUS_MAX) {
283 radius = radiusValues[radiusIndex];
284 }
285 else if (radiusIndex == RADIUS_0_PIXELS) {
286 radius = 0;
287 }
288 else {
289 // radius not supported
290 LOG_WARN(DRAW_LOGGER, "nbgl_drawRoundedRect forbidden radius index =%d\n", radiusIndex);
291 return;
292 }
293
294 // Draw full rectangle
295 rectArea.x0 = area->x0;
296 rectArea.y0 = area->y0;
297 rectArea.width = area->width;
298 rectArea.height = area->height;
299 rectArea.backgroundColor = innerColor;
300 nbgl_frontDrawRect(&rectArea);
301 // special case when radius is null, just draw a rectangle
302 if (radiusIndex == RADIUS_0_PIXELS) {
303 return;
304 }
305
306#ifdef SCREEN_SIZE_WALLET
307 UNUSED(radius);
308 // Draw 2 halves of disc
309 draw_circle_helper(area->x0,
310 area->y0,
311 radiusIndex,
312 LEFT_HALF,
313 innerColor, // unused
314 innerColor,
315 area->backgroundColor);
316 draw_circle_helper(area->x0 + area->width,
317 area->y0,
318 radiusIndex,
320 innerColor, // unused
321 innerColor,
322 area->backgroundColor);
323#else // SCREEN_SIZE_WALLET
324 if (radiusIndex == RADIUS_1_PIXEL) {
325 return;
326 }
327 // Draw 4 quarters of disc
328 draw_circle_helper(area->x0 + radius,
329 area->y0 + radius,
330 radiusIndex,
331 BAGL_FILL_CIRCLE_PI2_PI,
332 innerColor, // unused
333 innerColor,
334 area->backgroundColor);
335 draw_circle_helper(area->x0 + area->width - radius,
336 area->y0 + radius,
337 radiusIndex,
338 BAGL_FILL_CIRCLE_0_PI2,
339 innerColor, // unused
340 innerColor,
341 area->backgroundColor);
342 draw_circle_helper(area->x0 + radius,
343 area->y0 + area->height - radius,
344 radiusIndex,
345 BAGL_FILL_CIRCLE_PI_3PI2,
346 innerColor, // unused
347 innerColor,
348 area->backgroundColor);
349 draw_circle_helper(area->x0 + area->width - radius,
350 area->y0 + area->height - radius,
351 radiusIndex,
352 BAGL_FILL_CIRCLE_3PI2_2PI,
353 innerColor, // unused
354 innerColor,
355 area->backgroundColor);
356#endif // SCREEN_SIZE_WALLET
357}
358
370 nbgl_radius_t radiusIndex,
371 uint8_t stroke,
372 color_t innerColor,
373 color_t borderColor)
374{
375 uint8_t radius;
376 nbgl_area_t rectArea;
377
378 LOG_DEBUG(
380 "nbgl_drawRoundedBorderedRect: innerColor = %d, borderColor = %d, backgroundColor=%d\n",
381 innerColor,
382 borderColor,
383 area->backgroundColor);
384
385 if (radiusIndex <= RADIUS_MAX) {
386 radius = radiusValues[radiusIndex];
387 }
388 else if (radiusIndex == RADIUS_0_PIXELS) {
389 radius = 0;
390 }
391 else {
392 // radius not supported
393 LOG_WARN(
394 DRAW_LOGGER, "nbgl_drawRoundedBorderedRect forbidden radius index =%d\n", radiusIndex);
395 return;
396 }
397 rectArea.backgroundColor = innerColor;
398
399 // Draw 1 rectangle in inner rectangle
400 rectArea.x0 = area->x0;
401 rectArea.y0 = area->y0;
402 rectArea.width = area->width;
403 rectArea.height = area->height;
404 nbgl_frontDrawRect(&rectArea);
405 // special case, when border_color == inner_color == background_color, return
406 if ((innerColor == borderColor) && (borderColor == area->backgroundColor)) {
407 return;
408 }
409 // border
410 // 4 rectangles (with last pixel of each corner not set)
411#ifdef SCREEN_SIZE_WALLET
412 uint16_t circle_width = 0;
413 if (radiusIndex <= RADIUS_MAX) {
414 const nbgl_icon_details_t *half_icon = PIC(radiusIcons[radiusIndex]->leftDisc);
415 circle_width = half_icon->width;
416 }
417 if ((2 * circle_width) < area->width) {
418 if ((area->height - stroke) > VERTICAL_ALIGNMENT) {
419 // draw the 2 horizontal lines
420 rectArea.height = stroke;
421 rectArea.width = area->width - 2 * circle_width;
422 rectArea.x0 += circle_width;
423 nbgl_frontDrawLine(&rectArea, 1, borderColor); // top
424 rectArea.y0 = area->y0 + area->height - stroke;
425 nbgl_frontDrawLine(&rectArea, 1, borderColor); // bottom
426 }
427 else {
428 uint8_t pattern = 0;
429 uint32_t i;
430 for (i = 0; i < stroke; i++) {
431 pattern |= 1 << (7 - i);
432 }
433 for (i = area->height - stroke; i < area->height; i++) {
434 pattern |= 1 << (7 - i);
435 }
436 memset(ramBuffer, pattern, area->width);
437 rectArea.height = 8;
438 rectArea.bpp = NBGL_BPP_1;
439 nbgl_frontDrawImage(&rectArea, ramBuffer, NO_TRANSFORMATION, borderColor);
440 }
441 }
442 if ((2 * radius) < area->height) {
443 rectArea.x0 = area->x0;
444 rectArea.y0 = area->y0;
445 rectArea.width = stroke;
446 rectArea.height = area->height;
447 rectArea.backgroundColor = area->backgroundColor;
448 nbgl_frontDrawLine(&rectArea, 0, borderColor); // left
449 rectArea.x0 = area->x0 + area->width - stroke;
450 nbgl_frontDrawLine(&rectArea, 0, borderColor); // right
451 }
452 if (radiusIndex <= RADIUS_MAX) {
453 // Draw 4 quarters of circles
454 draw_circle_helper(area->x0,
455 area->y0,
456 radiusIndex,
457 LEFT_HALF,
458 borderColor,
459 innerColor,
460 area->backgroundColor);
461 draw_circle_helper(area->x0 + area->width,
462 area->y0,
463 radiusIndex,
465 borderColor,
466 innerColor,
467 area->backgroundColor);
468 }
469#else // SCREEN_SIZE_WALLET
470 rectArea.x0 = area->x0 + radius;
471 rectArea.y0 = area->y0;
472 rectArea.width = area->width - 2 * radius;
473 rectArea.height = stroke;
474 rectArea.backgroundColor = borderColor;
475 nbgl_frontDrawRect(&rectArea); // top
476 rectArea.y0 = area->y0 + area->height - stroke;
477 nbgl_frontDrawRect(&rectArea); // bottom
478 if ((2 * radius) < area->height) {
479 rectArea.x0 = area->x0;
480 rectArea.y0 = area->y0 + radius;
481 rectArea.width = stroke;
482 rectArea.height = area->height - 2 * radius;
483 rectArea.backgroundColor = area->backgroundColor;
484 nbgl_frontDrawLine(&rectArea, 0, borderColor); // left
485 rectArea.x0 = area->x0 + area->width - stroke;
486 nbgl_frontDrawLine(&rectArea, 0, borderColor); // right
487 }
488
489 if (radiusIndex <= RADIUS_MAX) {
490 // Draw 4 quarters of circles
491 draw_circle_helper(area->x0 + radius,
492 area->y0 + radius,
493 radiusIndex,
494 BAGL_FILL_CIRCLE_PI2_PI,
495 borderColor,
496 innerColor,
497 area->backgroundColor);
498 draw_circle_helper(area->x0 + area->width - radius,
499 area->y0 + radius,
500 radiusIndex,
501 BAGL_FILL_CIRCLE_0_PI2,
502 borderColor,
503 innerColor,
504 area->backgroundColor);
505 draw_circle_helper(area->x0 + radius,
506 area->y0 + area->height - radius,
507 radiusIndex,
508 BAGL_FILL_CIRCLE_PI_3PI2,
509 borderColor,
510 innerColor,
511 area->backgroundColor);
512 draw_circle_helper(area->x0 + area->width - radius,
513 area->y0 + area->height - radius,
514 radiusIndex,
515 BAGL_FILL_CIRCLE_3PI2_2PI,
516 borderColor,
517 innerColor,
518 area->backgroundColor);
519 }
520#endif // SCREEN_SIZE_WALLET
521}
522
536 nbgl_transformation_t transformation,
537 nbgl_color_map_t color_map,
538 const nbgl_icon_details_t *icon)
539{
540 if (icon->isFile) {
541 nbgl_frontDrawImageFile(area, icon->bitmap, color_map, ramBuffer);
542 }
543 else {
544 nbgl_frontDrawImage(area, icon->bitmap, transformation, color_map);
545 }
546}
547
555static uint16_t get_bitmap_byte_cnt(const nbgl_font_t *font, uint8_t charId)
556{
557 if ((charId < font->first_char) || (charId > font->last_char)) {
558 return 0;
559 }
560
561 uint16_t baseId = charId - font->first_char;
562 if (charId < font->last_char) {
563 const nbgl_font_character_t *character
564 = (const nbgl_font_character_t *) PIC(&font->characters[baseId]);
565 const nbgl_font_character_t *nextCharacter
566 = (const nbgl_font_character_t *) PIC(&font->characters[baseId + 1]);
567 return (nextCharacter->bitmap_offset - character->bitmap_offset);
568 }
569 else if (charId == font->last_char) {
570 return (font->bitmap_len - font->characters[baseId].bitmap_offset);
571 }
572 return 0;
573}
574
585 const char *text,
586 uint16_t textLen,
587 nbgl_font_id_e fontId,
588 color_t fontColor)
589{
590 // text is a series of characters, each character being a bitmap
591 // we need to align bitmaps on width multiple of 4 limitation.
592 int16_t x = area->x0;
593 nbgl_area_t rectArea;
594 const nbgl_font_t *font = nbgl_getFont(fontId);
595#ifdef HAVE_UNICODE_SUPPORT
596 nbgl_unicode_ctx_t *unicode_ctx = NULL;
597#endif // HAVE_UNICODE_SUPPORT
598
600 "nbgl_drawText: x0 = %d, y0 = %d, w = %d, h = %d, fontColor = %d, "
601 "backgroundColor=%d, text = %s\n",
602 area->x0,
603 area->y0,
604 area->width,
605 area->height,
606 fontColor,
607 area->backgroundColor,
608 text);
609
610 rectArea.backgroundColor = area->backgroundColor;
611 rectArea.bpp = (nbgl_bpp_t) font->bpp;
612
613 while (textLen > 0) {
614 const nbgl_font_character_t *character;
615 uint8_t char_width;
616 uint32_t unicode;
617 bool is_unicode;
618 const uint8_t *char_buffer;
619 int16_t char_x_min;
620 int16_t char_y_min;
621 int16_t char_x_max;
622 int16_t char_y_max;
623 uint16_t char_byte_cnt;
624 uint8_t encoding;
625 uint8_t nb_skipped_bytes;
626
627 unicode = nbgl_popUnicodeChar((const uint8_t **) &text, &textLen, &is_unicode);
628
629 if (is_unicode) {
630#ifdef HAVE_UNICODE_SUPPORT
631 if (unicode_ctx == NULL) {
632 unicode_ctx = nbgl_getUnicodeFont(fontId);
633 }
634 const nbgl_font_unicode_character_t *unicodeCharacter
635 = nbgl_getUnicodeFontCharacter(unicode);
636 // if not supported char, go to next one
637 if (unicodeCharacter == NULL) {
638 continue;
639 }
640 char_width = unicodeCharacter->width;
641#if defined(HAVE_LANGUAGE_PACK)
642 char_buffer = unicode_ctx->bitmap;
643 char_buffer += unicodeCharacter->bitmap_offset;
644
645 char_x_max = char_width;
646 char_y_max = unicode_ctx->font->height;
647
648 if (!unicode_ctx->font->crop) {
649 // Take in account the skipped bytes, if any
650 nb_skipped_bytes = (unicodeCharacter->x_min_offset & 7) << 3;
651 nb_skipped_bytes |= unicodeCharacter->y_min_offset & 7;
652 char_x_min = 0;
653 char_y_min = 0;
654 }
655 else {
656 nb_skipped_bytes = 0;
657 char_x_min = (uint16_t) unicodeCharacter->x_min_offset;
658 char_y_min = unicode_ctx->font->y_min;
659 char_y_min += (uint16_t) unicodeCharacter->y_min_offset;
660 char_x_max -= (uint16_t) unicodeCharacter->x_max_offset;
661 char_y_max -= (uint16_t) unicodeCharacter->y_max_offset;
662 }
663
664 char_byte_cnt = nbgl_getUnicodeFontCharacterByteCount();
665 encoding = unicodeCharacter->encoding;
666#endif // defined(HAVE_LANGUAGE_PACK)
667#else // HAVE_UNICODE_SUPPORT
668 continue;
669#endif // HAVE_UNICODE_SUPPORT
670 }
671 else {
672 if (unicode == '\f') {
673 break;
674 }
675 // if \b, switch fontId
676 else if (unicode == '\b') {
677 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
679#ifdef HAVE_UNICODE_SUPPORT
680 unicode_ctx = nbgl_getUnicodeFont(fontId);
681#endif // HAVE_UNICODE_SUPPORT
682 font = (const nbgl_font_t *) nbgl_getFont(fontId);
683 }
684 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
686#ifdef HAVE_UNICODE_SUPPORT
687 unicode_ctx = nbgl_getUnicodeFont(fontId);
688#endif // HAVE_UNICODE_SUPPORT
689 font = (const nbgl_font_t *) nbgl_getFont(fontId);
690 }
691 continue;
692 }
693 // if not supported char, go to next one
694 if ((unicode < font->first_char) || (unicode > font->last_char)) {
695 continue;
696 }
697 character = (const nbgl_font_character_t *) PIC(
698 &font->characters[unicode - font->first_char]);
699 char_buffer = (const uint8_t *) PIC(&font->bitmap[character->bitmap_offset]);
700 char_width = character->width;
701 encoding = character->encoding;
702
703 char_x_max = char_width;
704 char_y_max = font->height;
705
706 if (!font->crop) {
707 // Take in account the skipped bytes, if any
708 nb_skipped_bytes = (character->x_min_offset & 7) << 3;
709 nb_skipped_bytes |= character->y_min_offset & 7;
710 char_x_min = 0;
711 char_y_min = 0;
712 }
713 else {
714 nb_skipped_bytes = 0;
715 char_x_min = (uint16_t) character->x_min_offset;
716 char_y_min = font->y_min;
717 char_y_min += (uint16_t) character->y_min_offset;
718 char_x_max -= (uint16_t) character->x_max_offset;
719 char_y_max -= (uint16_t) character->y_max_offset;
720 }
721
722 char_byte_cnt = get_bitmap_byte_cnt(font, unicode);
723 }
724
725 // Render character
726 rectArea.x0 = x + char_x_min;
727 rectArea.y0 = area->y0 + char_y_min;
728 rectArea.height = (char_y_max - char_y_min);
729 rectArea.width = (char_x_max - char_x_min);
730
731 // If char_byte_cnt = 0, call nbgl_frontDrawImageRle to let speculos notice
732 // a space character was 'displayed'
733 if (!char_byte_cnt || encoding == 1) {
735 &rectArea, char_buffer, char_byte_cnt, fontColor, nb_skipped_bytes);
736 }
737 else {
738 nbgl_frontDrawImage(&rectArea, char_buffer, NO_TRANSFORMATION, fontColor);
739 }
740 x += char_width - font->char_kerning;
741 }
742 return fontId;
743}
744
745#ifdef NBGL_QRCODE
746#ifdef TARGET_APEX
747static void push_bits(uint8_t *buffer, uint16_t current_bits, uint8_t bits, uint8_t nb_bits)
748{
749 uint8_t byte = current_bits / 8;
750 uint8_t remaining_bits = 8 - current_bits % 8;
751
752 if (remaining_bits >= nb_bits) {
753 // put bits in possible MSB
754 buffer[byte] |= bits << (remaining_bits - nb_bits);
755 }
756 else {
757 // manage MSB
758 buffer[byte] |= bits >> (nb_bits - remaining_bits);
759 nb_bits -= remaining_bits;
760 // then LSB
761 buffer[byte + 1] |= bits << (8 - nb_bits);
762 }
763}
764#endif // TARGET_APEX
765
766static void nbgl_frontDrawQrInternal(const nbgl_area_t *area,
767 color_t foregroundColor,
768 nbgl_qrcode_version_t version)
769{
770 int size = qrcodegen_getSize(qrcode);
771 uint16_t idx = 0;
772
773 nbgl_area_t qrArea = {.x0 = area->x0,
774 .y0 = area->y0,
775 .backgroundColor = area->backgroundColor,
776 // QR codes are 1 BPP only
777 .bpp = NBGL_BPP_1};
778 if (version == QRCODE_V4) {
779#ifndef TARGET_APEX
780 // for each point of the V4 QR code, paint 64 pixels in image (8 in width, 8 in height)
781 qrArea.width = 2;
782 qrArea.height = QR_PIXEL_WIDTH_HEIGHT * 2 * size;
783 // paint a column of 2*size pixels in width by 8 pixels in height
784 for (int x = 0; x < size; x++) {
785 idx = 0;
786 for (int y = 0; y < size; y++) {
787 // draw 2 columns at once
788 QrDrawBuffer[idx] = qrcodegen_getModule(qrcode, x, y) ? 0xFF : 0x00;
790 idx += 1;
791 }
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 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
797 qrArea.x0 += 2;
798 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
799 qrArea.x0 += 2;
800 }
801#else // TARGET_APEX
802 // for each point of the V4 QR code, paint 5*5 pixels in image
803 qrArea.width = 1;
804 qrArea.height = 5 * size;
805 for (int x = 0; x < size; x++) {
806 idx = 0;
807 memset(QrDrawBuffer, 0, (size * 5 + 7) / 8);
808 // paint a column of 5*size pixels in width by 5 pixels in height
809 for (int y = 0; y < size; y++) {
810 push_bits(QrDrawBuffer, 5 * y, qrcodegen_getModule(qrcode, x, y) ? 0x1F : 0x00, 5);
811 }
812 for (int z = 0; z < 5; z++) {
813 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
814 qrArea.x0 += 1;
815 }
816 }
817#endif // TARGET_APEX
818 }
819 else { // V4 small or V10
820 // for each point of the V10 QR code, paint 16 pixels in image (4 in width, 4 in height)
821 qrArea.width = 1;
822 qrArea.height = QR_PIXEL_WIDTH_HEIGHT * size;
823 // paint a line of 4*size pixels in width by 4 pixels in height
824 for (int x = 0; x < size; x++) {
825 idx = 0;
826 memset(QrDrawBuffer, 0, (size + 1) / 2);
827 for (int y = 0; y < size; y++) {
828 QrDrawBuffer[idx] |= qrcodegen_getModule(qrcode, x, y) ? 0xF0 >> ((y & 1) * 4) : 0;
829 if (y & 1) {
830 idx++;
831 }
832 }
833 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
834 qrArea.x0++;
835 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
836 qrArea.x0++;
837 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
838 qrArea.x0++;
839 nbgl_frontDrawImage(&qrArea, QrDrawBuffer, NO_TRANSFORMATION, foregroundColor);
840 qrArea.x0++;
841 }
842 }
843}
844
858 nbgl_qrcode_version_t version,
859 const char *text,
860 color_t foregroundColor)
861{
862 uint8_t versionNum = (version == QRCODE_V10) ? 10 : 4;
863 bool ok = qrcodegen_encodeText(text,
865 qrcode,
866 qrcodegen_Ecc_LOW,
867 versionNum,
868 versionNum,
869 qrcodegen_Mask_AUTO,
870 true);
871
872 if (ok) {
873 nbgl_frontDrawQrInternal(area, foregroundColor, version);
874 }
875 else {
876 LOG_WARN(
877 DRAW_LOGGER, "Impossible to draw QRCode text %s with version %d\n", text, versionNum);
878 }
879}
880#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:535
#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:584
#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:369
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:857
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:270
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:146
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