Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_draw_text.c
Go to the documentation of this file.
1
7/*********************
8 * INCLUDES
9 *********************/
10#include <string.h>
11#include "nbgl_front.h"
12#include "nbgl_draw.h"
13#include "nbgl_fonts.h"
14#include "nbgl_debug.h"
15#include "nbgl_side.h"
16#ifdef BUILD_SCREENSHOTS
17#include <assert.h>
18#endif // BUILD_SCREENSHOTS
19#include "os_pic.h"
20#include "os_utils.h"
21
22/*********************
23 * DEFINES
24 *********************/
25
26#ifdef SCREEN_SIZE_WALLET
27#define MAX_FONT_HEIGHT 54
28#define AVERAGE_CHAR_WIDTH 40
29#else // SCREEN_SIZE_WALLET
30#define MAX_FONT_HEIGHT 24
31#define AVERAGE_CHAR_WIDTH 24
32#endif // SCREEN_SIZE_WALLET
33
34#ifndef UNIT_TESTING
35#define STATIC static
36#else
37#define STATIC
38#endif
39
40// Additional height for displaying combined characters
41#define COMBINED_HEIGHT 9
42
43// Maximum number of pixels used for RLE COPY
44#define MAX_RLE_COPY_PIXELS 5
45
46// New RLE Custom commands (all possible quartets from 0000 to 1111)
47#define RLE_CMD_COPY_2 0x00
48#define RLE_CMD_COPY_3 0x01
49#define RLE_CMD_COPY_4 0x02
50#define RLE_CMD_COPY_5 0x03
51#define RLE_CMD_FILL_3 0x04
52#define RLE_CMD_FILL_2 0x05
53#define RLE_CMD_2PATTERN_INDEXED_B2W 0x06
54#define RLE_CMD_2PATTERN_INDEXED_W2B 0x07
55#define RLE_CMD_1PATTERN_B2W 0x08
56#define RLE_CMD_1PATTERN_W2B 0x09
57#define RLE_CMD_2PATTERN_B2W 0x0A
58#define RLE_CMD_2PATTERN_W2B 0x0B
59#define RLE_CMD_FILL_BLACK 0x0C
60#define RLE_CMD_FILL_1 0x0D
61#define RLE_CMD_FILL_WHITE 0x0E
62#define RLE_CMD_FILL_WHITE_16 0x0F
63
64/**********************
65 * TYPEDEFS
66 **********************/
67
68// Structure used to handle RLE context
69typedef struct {
70 // Part containing the data to be decoded
71 uint32_t read_cnt;
72 uint32_t buffer_len;
73 const uint8_t *buffer;
74 const uint8_t *patterns;
75 uint8_t byte;
76 uint8_t nb_bits;
77 // Part containing the decoded pixels
78 uint8_t nb_pix;
79 bool copy; // when True, COPY command, otherwise FILL command
80 uint8_t offset; // offset value, for COPY command
81 uint8_t color; // Color to use for the FILL, from 0 to 15
82 uint8_t pixels[MAX_RLE_COPY_PIXELS]; // Maximum 5 pixels (COPY)
83
85
86/**********************
87 * STATIC PROTOTYPES
88 **********************/
89/**********************
90 * STATIC VARIABLES
91 **********************/
92/**********************
93 * VARIABLES
94 **********************/
95
103static uint16_t get_bitmap_byte_cnt(const nbgl_font_t *font, uint8_t charId)
104{
105 if ((charId < font->first_char) || (charId > font->last_char)) {
106 return 0;
107 }
108
109 uint16_t baseId = charId - font->first_char;
110 if (charId < font->last_char) {
111 const nbgl_font_character_t *character
112 = (const nbgl_font_character_t *) PIC(&font->characters[baseId]);
113 const nbgl_font_character_t *nextCharacter
114 = (const nbgl_font_character_t *) PIC(&font->characters[baseId + 1]);
115 return (nextCharacter->bitmap_offset - character->bitmap_offset);
116 }
117 else if (charId == font->last_char) {
118 return (font->bitmap_len - font->characters[baseId].bitmap_offset);
119 }
120 return 0;
121}
122
123//=============================================================================
124#ifdef SCREEN_SIZE_WALLET
142static void nbgl_draw1BPPImageRle(nbgl_area_t *area,
143 const uint8_t *buffer,
144 uint32_t buffer_len,
145 nbgl_area_t *buf_area,
146 uint8_t *dst,
147 uint8_t nb_skipped_bytes)
148{
149 size_t index = 0;
150 // Set the initial number of transparent pixels
151 size_t nb_zeros = (size_t) nb_skipped_bytes * 8;
152 size_t nb_ones = 0;
153 // Width & Height are rotated 90° on Flex/Stax
154 size_t remaining_height = area->width;
155 size_t remaining_width = area->height;
156 size_t dst_index = 0;
157 uint8_t pixels;
158 uint8_t white_pixel;
159
160#ifdef BUILD_SCREENSHOTS
161 assert((buf_area->width & 7) == 0);
162 assert((buf_area->height & 7) == 0);
163#endif // BUILD_SCREENSHOTS
164
165 dst += buf_area->y0 * buf_area->width / 8;
166 dst += buf_area->x0 / 8;
167 white_pixel = 0x80 >> (buf_area->x0 & 7);
168 pixels = 0;
169
170 while (remaining_height && (index < buffer_len || nb_zeros || nb_ones)) {
171 // Reload nb_zeros & nb_ones if needed
172 while (!nb_zeros && !nb_ones && index < buffer_len) {
173 uint8_t byte = buffer[index++];
174 nb_ones = byte & 0x0F;
175 nb_zeros = byte >> 4;
176 }
177 // Get next pixel
178 if (nb_zeros) {
179 --nb_zeros;
180 // Useless, but kept for clarity
181 pixels |= 0;
182 }
183 else if (nb_ones) {
184 --nb_ones;
185 pixels |= white_pixel;
186 }
187 white_pixel >>= 1;
188 if (!white_pixel) {
189 white_pixel = 0x80;
190 dst[dst_index++] |= pixels; // OR because we handle transparency
191 pixels = 0;
192 }
193 --remaining_width;
194
195 // Have we reached the end of the line?
196 if (!remaining_width) {
197 // Width & Height are rotated 90° on Flex/Stax
198 remaining_width = area->height;
199
200 // Store current pixel content
201 dst[dst_index] |= pixels; // OR because we handle transparency
202
203 // Start next line
204 dst += buf_area->width / 8;
205 dst_index = 0;
206 pixels = 0;
207 white_pixel = 0x80 >> (buf_area->x0 & 7);
208
209 --remaining_height;
210 }
211 }
212 // Store remaining pixels
213 if (pixels) {
214 dst[dst_index] |= pixels; // OR because we handle transparency
215 }
216}
217
218// Get next quartet and update Rle_context content
219static inline uint8_t get_next_quartet(rle_context_t *context)
220{
221 uint8_t quartet = 0;
222
223 // We have either 8 or 4 bits remaining to read
224 if (context->nb_bits == 8) {
225 quartet = context->byte >> 4;
226 context->nb_bits = 4;
227 }
228 else if (context->nb_bits == 4) {
229 quartet = context->byte & 0x0F;
230 // Update byte with next 2 quartets
231 if (context->read_cnt < context->buffer_len) {
232 context->byte = context->buffer[context->read_cnt++];
233 context->nb_bits = 8;
234 }
235 else {
236 context->nb_bits = 0;
237 }
238 }
239
240 // That quartet will contain a command, a value, a repeat count or an index
241 return quartet;
242}
243
244// Get next pixel(s) and update Rle_context content
245static inline void get_next_pixels(rle_context_t *context, size_t remaining_width)
246{
247 // Get next command
248 uint8_t cmd = get_next_quartet(context);
249
250 // Was it the last quartet?
251 if (!cmd && context->read_cnt >= context->buffer_len && !context->nb_bits) {
252 // Just return the number of pixels to skip
253 context->nb_pix = remaining_width;
254 context->copy = false;
255 context->color = 0xF; // Background color, which is considered as transparent
256 return;
257 }
258
259 // Update nb_pix & color depending on command
260 switch (cmd) {
261 // Is it a COPY command?
262
263 case RLE_CMD_COPY_2:
264 case RLE_CMD_COPY_3:
265 case RLE_CMD_COPY_4:
266 case RLE_CMD_COPY_5:
267 // CMD=00RR + VVVV + WWWW + XXXX + YYYY + ZZZZ => COPY Quartets
268 // - RR is repeat count - 2 of quartets (max=2+3 => 5 quartets)
269 // - VVVV: value of 1st 4BPP pixel
270 // - WWWW: value of 2nd 4BPP pixel
271 // - XXXX: value of 3rd 4BPP pixel
272 // - YYYY: value of 4th 4BPP pixel
273 // - ZZZZ: value of 5th 4BPP pixel
274 cmd += 2;
275 context->nb_pix = cmd;
276 for (uint8_t i = 0; i < cmd; i++) {
277 context->pixels[i] = get_next_quartet(context);
278 }
279 context->copy = true; // COPY command
280 context->offset = 0; // pixels offset=0
281 break;
282
283 // Is it a FILL command?
284
285 // CMD=0100 + VVVV + RRRR => FILL Value x Repeat+3 (max=18)
286 case RLE_CMD_FILL_3:
287 context->copy = false;
288 context->color = get_next_quartet(context);
289 context->nb_pix = get_next_quartet(context) + 3;
290 break;
291
292 // CMD=0101 + VVVV => FILL Value x 2
293 case RLE_CMD_FILL_2:
294 context->copy = false;
295 context->color = get_next_quartet(context);
296 context->nb_pix = 2;
297 break;
298
299 // CMD=1100 + RRRR => FILL Black (max=16)
301 context->copy = false;
302 context->color = 0;
303 context->nb_pix = get_next_quartet(context) + 1;
304 break;
305
306 // CMD=1101 + VVVV => Fill Value x 1
307 case RLE_CMD_FILL_1:
308 context->copy = false;
309 context->color = get_next_quartet(context);
310 context->nb_pix = 1;
311 break;
312
313 // CMD=111R + RRRR => FILL White (max=32)
315 context->copy = false;
316 context->color = 0x0F;
317 context->nb_pix = get_next_quartet(context) + 1;
318 break;
319
320 // CMD=111R + RRRR => FILL White (max=32)
322 context->copy = false;
323 context->color = 0x0F;
324 context->nb_pix = get_next_quartet(context) + 16 + 1;
325 break;
326
327 // Is it a PATTERN related command?
328
329 // CMD=0110 + IIII => Double Pattern Indexed Black to White: 0x00, Val1, val2, 0x0F
331 uint8_t index = get_next_quartet(context);
332 uint8_t pattern = context->patterns[index];
333
334 context->pixels[0] = 0x00;
335 context->pixels[1] = pattern >> 4;
336 context->pixels[2] = pattern & 0x0F;
337 context->pixels[3] = 0x0F;
338 context->nb_pix = 4;
339 context->copy = true; // COPY command
340 context->offset = 0; // pixels offset=0
341 break;
342 }
343
344 // CMD=0111 + IIII => Double Pattern Indexed White to Black: 0x0F, Val2, Val1, 0x00
346 uint8_t index = get_next_quartet(context);
347 uint8_t pattern = context->patterns[index];
348
349 context->pixels[0] = 0x0F;
350 context->pixels[1] = pattern & 0x0F;
351 context->pixels[2] = pattern >> 4;
352 context->pixels[3] = 0x00;
353 context->nb_pix = 4;
354 context->copy = true; // COPY command
355 context->offset = 0; // pixels offset=0
356 break;
357 }
358
359 // CMD=1000 + VVVV => Simple Pattern Black to White: 0x00, VVVV, 0x0F
361 context->pixels[0] = 0x00;
362 context->pixels[1] = get_next_quartet(context);
363 context->pixels[2] = 0x0F;
364 context->nb_pix = 3;
365 context->copy = true; // COPY command
366 context->offset = 0; // pixels offset=0
367 break;
368 }
369
370 // CMD=1001 + VVVV => Simple Pattern White to Black: 0x0F, VVVV, 0x00
372 context->pixels[0] = 0x0F;
373 context->pixels[1] = get_next_quartet(context);
374 context->pixels[2] = 0x00;
375 context->nb_pix = 3;
376 context->copy = true; // COPY command
377 context->offset = 0; // pixels offset=0
378 break;
379 }
380
381 // CMD=1010 + VVVV + WWWW => Double Pattern Black to White: 0x00, VVVV, WWWW, 0x0F
383 context->pixels[0] = 0x00;
384 context->pixels[1] = get_next_quartet(context);
385 context->pixels[2] = get_next_quartet(context);
386 context->pixels[3] = 0x0F;
387 context->nb_pix = 4;
388 context->copy = true; // COPY command
389 context->offset = 0; // pixels offset=0
390 break;
391 }
392
393 // CMD=1011 + VVVV + WWWW => Double Pattern White to Black: 0x0F, WWWW, VVVV, 0x00
395 context->pixels[0] = 0x0F;
396 context->pixels[2] = get_next_quartet(context);
397 context->pixels[1] = get_next_quartet(context);
398 context->pixels[3] = 0x00;
399 context->nb_pix = 4;
400 context->copy = true; // COPY command
401 context->offset = 0; // pixels offset=0
402 break;
403 }
404 }
405}
406
444 const uint8_t *buffer,
445 uint32_t buffer_len,
446 const uint8_t *patterns,
447 nbgl_area_t *buf_area,
448 uint8_t *dst,
449 uint8_t nb_skipped_bytes)
450{
451 // Width & Height are rotated 90° on Flex/Stax
452 size_t remaining_height = area->width;
453 size_t remaining_width = area->height;
454 size_t dst_index = 0;
455 uint8_t dst_shift = 4; // Next pixel must be shift left 4 bit
456 rle_context_t context = {0};
457 uint8_t dst_pixel;
458
459 if (!buffer_len) {
460 return;
461 }
462
463#ifdef BUILD_SCREENSHOTS
464 assert((buf_area->width & 7) == 0);
465 assert((buf_area->height & 7) == 0);
466#endif // BUILD_SCREENSHOTS
467
468 // Init RLE context
469 context.buffer = buffer;
470 context.buffer_len = buffer_len;
471 context.patterns = patterns;
472 context.byte = buffer[0];
473 context.read_cnt = 1;
474 context.nb_bits = 8;
475
476 // Handle 'transparent' pixels
477 if (nb_skipped_bytes) {
478 context.nb_pix = nb_skipped_bytes * 2;
479 context.color = 0xF; // Background color, which is considered as transparent
480 context.copy = false;
481 }
482
483 dst += buf_area->y0 * buf_area->width / 2;
484 dst += buf_area->x0 / 2;
485 dst_pixel = *dst;
486
487 if (buf_area->x0 & 1) {
488 dst_shift = 0;
489 }
490
491 while (remaining_height) {
492 uint8_t nb_pix;
493
494 // if the context is empty, let's fill it
495 if (context.nb_pix == 0) {
496 get_next_pixels(&context, remaining_width);
497 }
498 // Write those pixels in the RAM buffer
499 nb_pix = context.nb_pix;
500 if (nb_pix > remaining_width) {
501 nb_pix = remaining_width;
502 }
503
504 // if copy is true, it is a COPY command, else it is a FILL command
505 if (context.copy == false) {
506 // It is a FILL command: do we need to just skip transparent pixels?
507 if (context.color == 0x0F) {
508 dst[dst_index] = dst_pixel;
509 dst_index += nb_pix / 2;
510 if (nb_pix & 1) {
511 dst_shift ^= 4;
512 if (dst_shift) {
513 ++dst_index;
514 }
515 }
516 dst_pixel = dst[dst_index];
517 }
518 else {
519 // FILL nb_pix pixels with context.color
520 for (uint8_t i = 0; i < nb_pix; i++) {
521 dst_pixel &= ~(0x0F << dst_shift);
522 dst_pixel |= context.color << dst_shift;
523 dst_shift ^= 4;
524 // Do we need to go to next byte?
525 if (dst_shift) {
526 dst[dst_index] = dst_pixel;
527 ++dst_index;
528 dst_pixel = dst[dst_index];
529 }
530 }
531 }
532 }
533 else {
534 uint8_t *pixels = context.pixels;
535 // Add current offset of the pixels to copy
536 pixels += context.offset;
537
538 // We can consider there is at least 1 used pixel, otherwise it would be a FILL!
539 // COPY nb_pix pixels from &context.pixels[i]
540 for (uint8_t i = 0; i < nb_pix; i++) {
541 uint8_t color = pixels[i];
542 // Handle transparency
543 if (color != 0x0F) {
544 dst_pixel &= ~(0x0F << dst_shift);
545 dst_pixel |= color << dst_shift;
546 }
547 dst_shift ^= 4;
548 // Do we need to go to next byte?
549 if (dst_shift) {
550 dst[dst_index] = dst_pixel;
551 ++dst_index;
552 dst_pixel = dst[dst_index];
553 }
554 }
555 // Update offset of the pixels to copy
556 context.offset += nb_pix;
557 }
558
559 // Take in account displayed pixels
560 context.nb_pix -= nb_pix;
561 remaining_width -= nb_pix;
562
563 // Have we reached the end of the line?
564 if (remaining_width == 0) {
565 // Width & Height are rotated 90° on Flex/Stax
566 remaining_width = area->height;
567
568 // Store last pixels
569 dst[dst_index] = dst_pixel;
570 // Start next line
571 dst_index = 0;
572 dst += buf_area->width / 2;
573 dst_pixel = dst[dst_index];
574 if (buf_area->x0 & 1) {
575 dst_shift = 0;
576 }
577 else {
578 dst_shift = 4;
579 }
580 --remaining_height;
581 }
582 }
583}
584
597static void nbgl_drawImageRle(nbgl_area_t *text_area,
598 const uint8_t *buffer,
599 uint32_t buffer_len,
600 const uint8_t *patterns,
601 nbgl_area_t *buf_area,
602 uint8_t *dst,
603 uint8_t nb_skipped_bytes)
604{
605 if (text_area->bpp == NBGL_BPP_4) {
607 text_area, buffer, buffer_len, patterns, buf_area, dst, nb_skipped_bytes);
608 }
609 else if (text_area->bpp == NBGL_BPP_1) {
610 nbgl_draw1BPPImageRle(text_area, buffer, buffer_len, buf_area, dst, nb_skipped_bytes);
611 }
612}
613
623static void nbgl_draw4BPPImage(nbgl_area_t *area,
624 const uint8_t *buffer,
625 nbgl_area_t *buf_area,
626 uint8_t *dst)
627{
628 uint32_t buffer_len = ((area->width * area->height) + 1) / 2;
629 uint32_t index = 0;
630 // Width & Height are rotated 90° on Flex/Stax
631 size_t remaining_height = area->width;
632 size_t remaining_width = area->height;
633 size_t dst_index = 0;
634 uint8_t dst_shift = 4; // Next pixel must be shift left 4 bit
635 uint8_t dst_pixel;
636 uint8_t src_nb_pix, src_pixels[2];
637
638 if (!buffer_len) {
639 return;
640 }
641
642#ifdef BUILD_SCREENSHOTS
643 assert((buf_area->width & 7) == 0);
644 assert((buf_area->height & 7) == 0);
645#endif // BUILD_SCREENSHOTS
646
647 dst += buf_area->y0 * buf_area->width / 2;
648 dst += buf_area->x0 / 2;
649 dst_pixel = *dst;
650
651 if (buf_area->x0 & 1) {
652 dst_shift = 0;
653 }
654 src_pixels[0] = buffer[index++];
655 src_pixels[1] = src_pixels[0] >> 4;
656 src_pixels[0] &= 0x0F;
657 src_nb_pix = 2;
658
659 while (remaining_height) {
660 uint8_t nb_pix;
661
662 // refill data if ncecessary
663 if (src_nb_pix == 0) {
664 if (index < buffer_len) {
665 src_pixels[0] = buffer[index++];
666 src_pixels[1] = src_pixels[0] >> 4;
667 src_pixels[0] &= 0x0F;
668 src_nb_pix = 2;
669 }
670 else {
671 // We have no more src data => fill with transparent color
672 // Background color, which is considered as transparent
673 src_pixels[0] = 0x0F;
674 src_pixels[1] = 0x0F;
675 src_nb_pix = remaining_width;
676 }
677 }
678 // Write those pixels in the RAM buffer
679 nb_pix = src_nb_pix;
680 if (nb_pix > remaining_width) {
681 nb_pix = remaining_width;
682 }
683
684 for (uint8_t i = 0; i < nb_pix; i++) {
685 uint8_t color = src_pixels[i];
686 // Handle transparency
687 if (color != 0x0F) {
688 dst_pixel &= ~(0x0F << dst_shift);
689 dst_pixel |= color << dst_shift;
690 }
691 dst_shift ^= 4;
692 // Do we need to go to next byte?
693 if (dst_shift) {
694 dst[dst_index] = dst_pixel;
695 ++dst_index;
696 dst_pixel = dst[dst_index];
697 }
698 }
699
700 // Take in account displayed pixels
701 src_nb_pix -= nb_pix;
702 remaining_width -= nb_pix;
703
704 // Have we reached the end of the line?
705 if (remaining_width == 0) {
706 // Width & Height are rotated 90° on Flex/Stax
707 remaining_width = area->height;
708
709 // Store last pixels
710 dst[dst_index] = dst_pixel;
711 // Start next line
712 dst_index = 0;
713 dst += buf_area->width / 2;
714 dst_pixel = dst[dst_index];
715 if (buf_area->x0 & 1) {
716 dst_shift = 0;
717 }
718 else {
719 dst_shift = 4;
720 }
721 --remaining_height;
722 }
723 }
724}
725
735static void nbgl_draw1BPPImage(nbgl_area_t *area,
736 const uint8_t *buffer,
737 nbgl_area_t *buf_area,
738 uint8_t *dst)
739{
740 size_t index = 0;
741 uint32_t buffer_len = ((area->width * area->height) + 7) / 8;
742 // Width & Height are rotated 90° on Flex/Stax
743 size_t remaining_height = area->width;
744 size_t remaining_width = area->height;
745 size_t dst_index = 0;
746 uint8_t pixels;
747 uint8_t white_pixel;
748 uint8_t src_byte, src_msk;
749
750#ifdef BUILD_SCREENSHOTS
751 assert((buf_area->width & 7) == 0);
752 assert((buf_area->height & 7) == 0);
753#endif // BUILD_SCREENSHOTS
754
755 dst += buf_area->y0 * buf_area->width / 8;
756 dst += buf_area->x0 / 8;
757 white_pixel = 0x80 >> (buf_area->x0 & 7);
758 pixels = 0;
759
760 src_byte = buffer[index++];
761 src_msk = 0x80;
762
763 while (remaining_height && (index < buffer_len || src_msk)) {
764 // Reload data if needed
765 if (!src_msk && index < buffer_len) {
766 src_byte = buffer[index++];
767 src_msk = 0x80;
768 }
769 // Get next pixel
770 if (src_byte & src_msk) {
771 pixels |= white_pixel;
772 }
773 else {
774 // Useless, but kept for clarity
775 pixels |= 0;
776 }
777 src_msk >>= 1;
778 white_pixel >>= 1;
779 if (!white_pixel) {
780 white_pixel = 0x80;
781 dst[dst_index++] |= pixels; // OR because we handle transparency
782 pixels = 0;
783 }
784 --remaining_width;
785
786 // Have we reached the end of the line?
787 if (!remaining_width) {
788 // Width & Height are rotated 90° on Flex/Stax
789 remaining_width = area->height;
790
791 // Store current pixel content
792 dst[dst_index] |= pixels; // OR because we handle transparency
793
794 // Start next line
795 dst += buf_area->width / 8;
796 dst_index = 0;
797 pixels = 0;
798 white_pixel = 0x80 >> (buf_area->x0 & 7);
799
800 --remaining_height;
801 }
802 }
803 // Store remaining pixels
804 if (pixels) {
805 dst[dst_index] |= pixels; // OR because we handle transparency
806 }
807}
808
817static void nbgl_drawImage(nbgl_area_t *text_area,
818 const uint8_t *buffer,
819 nbgl_area_t *buf_area,
820 uint8_t *dst)
821{
822 if (text_area->bpp == NBGL_BPP_4) {
823 nbgl_draw4BPPImage(text_area, buffer, buf_area, dst);
824 }
825 else if (text_area->bpp == NBGL_BPP_1) {
826 nbgl_draw1BPPImage(text_area, buffer, buf_area, dst);
827 }
828}
829
838static void pack_ram_buffer(nbgl_area_t *area, uint16_t width, uint16_t height)
839{
840 uint8_t *src = ramBuffer;
841 uint8_t *dst = ramBuffer;
842
843 if (area->bpp == NBGL_BPP_4) {
844 uint16_t bytes_per_line;
845 uint16_t skip;
846
847 src += area->y0 * area->width / 2;
848 src += area->x0 / 2;
849 bytes_per_line = (width + 1) / 2;
850 skip = (area->width + 1) / 2;
851
852 // Do we need to copy quartet by quartet, or can we copy byte by byte?
853 if (area->x0 & 1) {
854 // We need to copy quartet by quartet
855 skip -= bytes_per_line;
856 for (uint16_t h = 0; h < height; h++) {
857 for (uint16_t w = 0; w < bytes_per_line; w++) {
858 uint8_t byte = *src++ & 0x0F; // 1st quartet
859 byte <<= 4;
860 byte |= *src >> 4;
861 *dst++ = byte;
862 }
863 src += skip;
864 }
865 }
866 else {
867 for (uint16_t y = 0; y < height; y++) {
868 memmove(dst, src, bytes_per_line);
869 dst += bytes_per_line;
870 src += skip;
871 }
872 }
873 }
874 else {
875 uint8_t src_pixel;
876 uint8_t src_shift;
877 uint8_t src_index;
878 uint8_t dst_pixel = 0;
879 uint8_t dst_shift = 7;
880
881 src += area->y0 * area->width / 8;
882 src += area->x0 / 8;
883 for (uint16_t y = 0; y < height; y++) {
884 src_shift = (7 - (area->x0 & 7));
885 src_pixel = *src;
886 src_index = 0;
887 for (uint16_t x = 0; x < width; x++) {
888 dst_pixel |= ((src_pixel >> src_shift) & 1) << dst_shift;
889 if (dst_shift == 0) {
890 dst_shift = 8;
891 *dst++ = dst_pixel;
892 dst_pixel = 0;
893 }
894 --dst_shift;
895
896 if (src_shift == 0) {
897 src_shift = 8;
898 ++src_index;
899 src_pixel = src[src_index];
900 }
901 --src_shift;
902 }
903 src += area->width / 8;
904 }
905 // Write last byte, if any
906 if (dst_shift != 7) {
907 *dst++ = dst_pixel;
908 }
909 }
910}
911
920static void display_ram_buffer(int16_t x_min,
921 int16_t y_min,
922 int16_t x_max,
923 int16_t y_max,
924 const nbgl_area_t *area,
925 nbgl_area_t *buf_area,
926 nbgl_area_t *char_area,
927 color_t fontColor)
928{
929 // Move the data at the beginning of RAM buffer, in a packed way
930 buf_area->x0 = x_min;
931 buf_area->y0 = y_min;
932 char_area->height = ((x_max - x_min) + 3) & 0xFFFC;
933 char_area->width = y_max - y_min;
934
935 pack_ram_buffer(buf_area, char_area->height, char_area->width);
936
937 char_area->y0 = area->y0 + x_min - COMBINED_HEIGHT;
938
939 nbgl_frontDrawImage(char_area, ramBuffer, NO_TRANSFORMATION, fontColor);
940}
941#endif // SCREEN_SIZE_WALLET
942
944 const uint8_t **text,
945 uint16_t *textLen,
946 nbgl_unicode_ctx_t *unicode_ctx,
947 const nbgl_font_t *font)
948{
949 char_info->unicode = nbgl_popUnicodeChar(text, textLen, &char_info->is_unicode);
950
951 // Do we still have some characters to read?
952 if (!char_info->unicode) {
953 return;
954 }
955
956 // Retrieves information depending on whether it is an ASCII character or not.
957 if (char_info->is_unicode) {
958 const nbgl_font_unicode_character_t *unicodeCharacter
960 // if not supported char, go to next one (this should never happen, except in Apps, if a
961 // unicode is used !!)
962 if (unicodeCharacter == NULL) {
963#ifdef BUILD_SCREENSHOTS
964 fprintf(stdout,
965 "Inside update_char_info, unicode (%c)[0x%X] is not supported!\n",
966 char_info->unicode,
967 char_info->unicode);
968#endif // BUILD_SCREENSHOTS
969 update_char_info(char_info, text, textLen, unicode_ctx, font);
970 return;
971 }
972 char_info->width = unicodeCharacter->width;
973 char_info->patterns = unicode_ctx->bitmap;
974 char_info->buffer = unicode_ctx->bitmap;
975 char_info->buffer += unicodeCharacter->bitmap_offset;
976
977 char_info->x_max = char_info->width;
978 char_info->y_max = unicode_ctx->font->height;
979#ifdef SCREEN_SIZE_WALLET
980 char_info->over_previous = unicodeCharacter->over_previous;
981#else // SCREEN_SIZE_WALLET
982 char_info->over_previous = 0;
983#endif // SCREEN_SIZE_WALLET
984
985 if (!unicode_ctx->font->crop) {
986 // Take in account the skipped bytes, if any
987 char_info->nb_skipped_bytes = (unicodeCharacter->x_min_offset & 7) << 3;
988 char_info->nb_skipped_bytes |= unicodeCharacter->y_min_offset & 7;
989 char_info->x_min = 0;
990 char_info->y_min = 0;
991 }
992 else {
993 char_info->nb_skipped_bytes = 0;
994 char_info->y_min = unicode_ctx->font->y_min;
995 char_info->y_min += (uint16_t) unicodeCharacter->y_min_offset;
996 char_info->y_max -= (uint16_t) unicodeCharacter->y_max_offset;
997
998 if (char_info->over_previous) {
999 // That character will be displayed over the previous one: get correct X coords
1000 char_info->x_min = -(int16_t) unicodeCharacter->width;
1001 char_info->width = 16 * (uint16_t) unicodeCharacter->x_min_offset;
1002 char_info->width += (uint16_t) unicodeCharacter->x_max_offset;
1003 char_info->x_max = char_info->x_min + char_info->width;
1004 }
1005 else {
1006 char_info->x_min = (uint16_t) unicodeCharacter->x_min_offset;
1007 char_info->x_max -= (uint16_t) unicodeCharacter->x_max_offset;
1008 }
1009 }
1011 char_info->encoding = unicodeCharacter->encoding;
1012 char_info->height = char_info->y_max - char_info->y_min;
1013 }
1014 else {
1015 // Special character: nothing special to do here
1016 if (char_info->unicode == '\f' || char_info->unicode == '\b') {
1017 return;
1018 }
1019 // if not supported char, go to next one (this should never happen!!)
1020 if ((char_info->unicode < font->first_char) || (char_info->unicode > font->last_char)) {
1021#ifdef BUILD_SCREENSHOTS
1022 fprintf(stdout,
1023 "Inside update_char_info, unicode (%c)[0x%X] is not supported!\n",
1024 char_info->unicode,
1025 char_info->unicode);
1026#endif // BUILD_SCREENSHOTS
1027 update_char_info(char_info, text, textLen, unicode_ctx, font);
1028 return;
1029 }
1030 const nbgl_font_character_t *character = (const nbgl_font_character_t *) PIC(
1031 &font->characters[char_info->unicode - font->first_char]);
1032
1033 char_info->patterns = (const uint8_t *) PIC(font->bitmap);
1034 char_info->buffer = (const uint8_t *) PIC(&font->bitmap[character->bitmap_offset]);
1035 char_info->width = character->width;
1036 char_info->encoding = character->encoding;
1037 char_info->over_previous = 0;
1038
1039 char_info->x_max = char_info->width;
1040 char_info->y_max = font->height;
1041
1042 if (!font->crop) {
1043 // Take in account the skipped bytes, if any
1044 char_info->nb_skipped_bytes = (character->x_min_offset & 7) << 3;
1045 char_info->nb_skipped_bytes |= character->y_min_offset & 7;
1046 char_info->x_min = 0;
1047 char_info->y_min = 0;
1048 }
1049 else {
1050 char_info->nb_skipped_bytes = 0;
1051 char_info->x_min = (uint16_t) character->x_min_offset;
1052 char_info->y_min = font->y_min;
1053 char_info->y_min += (uint16_t) character->y_min_offset;
1054 char_info->x_max -= (uint16_t) character->x_max_offset;
1055 char_info->y_max -= (uint16_t) character->y_max_offset;
1056 }
1057
1058 char_info->byte_cnt = get_bitmap_byte_cnt(font, char_info->unicode);
1059 char_info->height = char_info->y_max - char_info->y_min;
1060 }
1061}
1062
1073 const char *text,
1074 uint16_t textLen,
1075 nbgl_font_id_e fontId,
1076 color_t fontColor)
1077{
1078 // text is a series of characters, each character being a bitmap
1079 // we need to align bitmaps on width multiple of 4 limitation.
1080 int16_t x = area->x0;
1081 nbgl_area_t current_area;
1082 character_info_t current_char = {0};
1083 const nbgl_font_t *font = nbgl_getFont(fontId);
1084 nbgl_unicode_ctx_t *unicode_ctx = nbgl_getUnicodeFont(fontId);
1085#ifdef SCREEN_SIZE_WALLET
1086 int16_t next_x = x;
1087 character_info_t previous_char = {0};
1088 character_info_t next_char = {0};
1089 nbgl_area_t previous_area;
1090 int16_t buf_x_min;
1091 int16_t buf_y_min;
1092 int16_t buf_x_max;
1093 int16_t buf_y_max;
1094 // Flag set to 1 when there is data to be drawn in RAM buffer
1095 uint8_t redraw_buf_area = 0;
1096
1097 // Area representing the RAM buffer and in which the glyphs will be drawn
1098 nbgl_area_t buf_area = {0};
1099 // ensure that the ramBuffer also used for image file decompression is big enough
1100 // 4bpp: size of ram_buffer is (font->height * 3*AVERAGE_CHAR_WIDTH/2) / 2
1101 // 1bpp: size of ram_buffer is (font->height * 3*AVERAGE_CHAR_WIDTH/2) / 8
1102 CCASSERT(ram_buffer,
1104 // TODO Investigate why area->bpp is not always initialized correctly
1105 buf_area.bpp = (nbgl_bpp_t) font->bpp;
1106 // Width & Height are rotated 90° on Flex/Stax
1107 if (unicode_ctx) {
1108 buf_area.width
1109 = (unicode_ctx->font->line_height + 7) & 0xFFF8; // Modulo 8 is better for 1BPP
1110 }
1111 else {
1112 buf_area.width = (MAX_FONT_HEIGHT + 7) & 0xFFF8; // Modulo 8 is better for 1BPP
1113 }
1114 buf_area.height = ((3 * AVERAGE_CHAR_WIDTH / 2) + 7) & 0xFFF8;
1115 if (buf_area.bpp == NBGL_BPP_4) {
1116 buf_area.backgroundColor = 0xF; // This will be the transparent color
1117 }
1118 else {
1119 buf_area.backgroundColor = 0; // This will be the transparent color
1120 }
1121#ifdef BUILD_SCREENSHOTS
1122 assert((buf_area.height * buf_area.width / 2) <= GZLIB_UNCOMPRESSED_CHUNK);
1123#endif // BUILD_SCREENSHOTS
1124
1125 // Those variables will be updated with current_char dimension
1126 buf_x_min = AVERAGE_CHAR_WIDTH;
1127 buf_y_min = MAX_FONT_HEIGHT;
1128 buf_x_max = 0;
1129 buf_y_max = 0;
1130#endif // SCREEN_SIZE_WALLET
1131
1133 "nbgl_drawText: x0 = %d, y0 = %d, w = %d, h = %d, fontColor = %d, "
1134 "backgroundColor=%d, text = %s\n",
1135 area->x0,
1136 area->y0,
1137 area->width,
1138 area->height,
1139 fontColor,
1140 area->backgroundColor,
1141 text);
1142
1143 current_area.backgroundColor = area->backgroundColor;
1144 current_area.bpp = (nbgl_bpp_t) font->bpp;
1145
1146#ifndef SCREEN_SIZE_WALLET
1147 while (textLen > 0) {
1148 // Get info for current character
1149 update_char_info(&current_char, (const uint8_t **) &text, &textLen, unicode_ctx, font);
1150
1151 // Handle special characters (for LNX & LNS+ devices)
1152 if (!current_char.is_unicode) {
1153 // If '\f', that string si completed
1154 if (current_char.unicode == '\f') {
1155 break;
1156 }
1157 // if \b, switch fontId
1158 if (current_char.unicode == '\b') {
1159 if (fontId == BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp) { // switch to bold
1161 unicode_ctx = nbgl_getUnicodeFont(fontId);
1162 font = (const nbgl_font_t *) nbgl_getFont(fontId);
1163 }
1164 else if (fontId == BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp) { // switch to regular
1166 unicode_ctx = nbgl_getUnicodeFont(fontId);
1167 font = (const nbgl_font_t *) nbgl_getFont(fontId);
1168 }
1169 continue;
1170 }
1171 }
1172
1173 current_area.x0 = x + current_char.x_min;
1174 current_area.y0 = area->y0 + current_char.y_min;
1175 current_area.height = (current_char.y_max - current_char.y_min);
1176 current_area.width = (current_char.x_max - current_char.x_min);
1177
1178 // If char_byte_cnt = 0, call nbgl_frontDrawImageRle to let speculos notice
1179 // a space character was 'displayed'
1180 if (!current_char.byte_cnt || current_char.encoding == 1) {
1181 // Draw that character in the RAM buffer, with transparency
1182 nbgl_frontDrawImageRle(&current_area,
1183 current_char.buffer,
1184 current_char.byte_cnt,
1185 fontColor,
1186 current_char.nb_skipped_bytes);
1187 // WARNING: current_area was adjusted to height of what was really displayed!
1188 }
1189 else {
1190 nbgl_frontDrawImage(&current_area, current_char.buffer, NO_TRANSFORMATION, fontColor);
1191 }
1192 x += current_char.width - font->char_kerning;
1193 }
1194#else // SCREEN_SIZE_WALLET
1195 // Get the first character, that will go into 'current_char'
1196 // (to correctly handle languages using 'combined characters', we need to
1197 // know current, previous & next characters)
1198 update_char_info(&next_char, (const uint8_t **) &text, &textLen, unicode_ctx, font);
1199
1200 while (textLen > 0 || next_char.unicode) {
1201 // Get the character we already read
1202 current_char = next_char;
1203 // Get info for next character
1204 update_char_info(&next_char, (const uint8_t **) &text, &textLen, unicode_ctx, font);
1205
1206 // Render current character in current_area
1207 if (!current_char.over_previous) {
1208 // This character will not be displayed over previous one => update x
1209 if (next_x > x) {
1210 x = next_x;
1211 }
1212 current_area.x0 = x + current_char.x_min;
1213 }
1214 current_area.y0 = area->y0 + current_char.y_min;
1215 current_area.height = (current_char.y_max - current_char.y_min);
1216 current_area.width = (current_char.x_max - current_char.x_min);
1217
1218 // if current character should not be displayed over previous one,
1219 // send RAM buffer to display
1220 if (!current_char.over_previous) {
1221 // Send RAM buffer content (previous character) to display
1222 if (redraw_buf_area) {
1223 display_ram_buffer(buf_x_min,
1224 buf_y_min,
1225 buf_x_max,
1226 buf_y_max,
1227 area,
1228 &buf_area,
1229 &previous_area,
1230 fontColor);
1231 // Reset that flag
1232 redraw_buf_area = 0;
1233 buf_x_min = AVERAGE_CHAR_WIDTH;
1234 buf_y_min = MAX_FONT_HEIGHT;
1235 buf_x_max = 0;
1236 buf_y_max = 0;
1237 }
1238 // To handle transparency, ramBuffer must be filled with background color
1239 // => Fill ramBuffer with background color (0x0F for 4bpp & 0 for 1bpp)
1240 if (buf_area.bpp == NBGL_BPP_4) {
1241 memset(ramBuffer, 0xFF, (buf_area.height * buf_area.width / 2));
1242 }
1243 else {
1244 memset(ramBuffer, 0x0, (buf_area.height * buf_area.width / 8));
1245 }
1246 // Update display coordinates of current char inside the RAM buffer
1247 //(X & Y are rotated 90° on Stax/Flex)
1248 buf_area.x0 = COMBINED_HEIGHT + current_char.y_min;
1249 buf_area.y0 = (AVERAGE_CHAR_WIDTH / 2) + current_char.x_min;
1250
1251 buf_x_min = buf_area.x0;
1252 buf_x_max = buf_x_min + current_area.height;
1253 buf_y_min = buf_area.y0;
1254 buf_y_max = buf_y_min + current_area.width;
1255
1256 // Compute next x with current char width, to be ready to display next one
1257 x += current_char.width - font->char_kerning;
1258 next_x = x;
1259 }
1260 else {
1261 // Security check: first character can't be a composed one!
1262 if (previous_char.unicode == 0) {
1263#ifdef BUILD_SCREENSHOTS
1264 fprintf(stdout,
1265 "WARNING: First character '%c'(0x%X) is a composed one! (text=>%s<=)\n",
1266 current_char.unicode,
1267 current_char.unicode,
1268 text);
1269#endif // BUILD_SCREENSHOTS
1270 continue;
1271 }
1272 // Update next_x if this character is larger than original one
1273 // (except for vowel 0xE31 which is overflowing on purpose on right side)
1274 if (current_char.unicode != 0x00E31
1275 && (x + current_char.x_min + current_char.width) > next_x) {
1276 next_x = x + current_char.x_min + current_char.width;
1277 // That character is a special one, as it is displayed on top of previous
1278 // character and also on its right => give space for next character
1279 if (current_char.unicode == 0x00E33) {
1280 next_x += 1;
1281 }
1282 }
1283 // Take in account current x_min (which is < 0)
1284 buf_area.x0 = COMBINED_HEIGHT + current_char.y_min;
1285 buf_area.y0 = (AVERAGE_CHAR_WIDTH / 2) - current_char.x_min - current_char.width;
1286
1287 // Thai rules for displaying characters on top of each others
1288 // Order priority, from bottom to top
1289 // 1 - consonnant
1290 // 2 - vowel or sign 0x0E4D and 0x0E4E
1291 // 3 - tone 0x0E48, 0x0E49, 0x0E4A and 0x0E4B or sign 0x0E4C
1292 // => 0x0E48, 0x0E49, 0x0E4A, 0x0E4B & 0x0E4C MUST ALWAYS be displayed on top of
1293 // other characters! WARNING: some vowels, signs or tone may have to be displayed
1294 // left with some consonnant (0E1B, 0E1F etc)
1295
1296 if (current_char.unicode >= 0x0E48 && current_char.unicode <= 0x0E4C) {
1297 if (next_char.unicode == 0x00E33) {
1298 // Display current character up to next one
1299 buf_area.x0 = COMBINED_HEIGHT + 0;
1300 buf_area.x0
1301 -= (current_char.y_max - current_char.y_min) - 2; // minus height of cur
1302 // char TMP
1303 }
1304 else if (previous_char.unicode >= 0x0E31 && previous_char.unicode <= 0x0E37) {
1305 // Take in account the height of previous character
1306 buf_area.x0 = buf_x_min - (current_char.y_max - current_char.y_min) - 1;
1307 }
1308 else if (current_char.unicode == 0x0E4B && previous_char.unicode == 0x0E1B) {
1309 // We must shift 0x0E4B to the left or we will overwrite 0x0E1B
1310 buf_area.y0 -= current_char.x_min / 2;
1311 }
1312 }
1313 // Update RAM buffer x/y min/max
1314 if (buf_area.x0 < buf_x_min) {
1315 buf_x_min = buf_area.x0;
1316 }
1317 if ((buf_area.x0 + current_area.height) > buf_x_max) {
1318 buf_x_max = buf_area.x0 + current_area.height;
1319 }
1320 if (buf_area.y0 < buf_y_min) {
1321 buf_y_min = buf_area.y0;
1322 }
1323 if ((buf_area.y0 + current_area.width) > buf_y_max) {
1324 buf_y_max = buf_area.y0 + current_area.width;
1325 }
1326 }
1327 // If char_byte_cnt = 0, call nbgl_frontDrawImageRle to let speculos notice
1328 // a space character was 'displayed'
1329 if (!current_char.byte_cnt || current_char.encoding == 1) {
1330 // Draw that character in the RAM buffer, with transparency
1331 nbgl_drawImageRle(&current_area,
1332 current_char.buffer,
1333 current_char.byte_cnt,
1334 current_char.patterns,
1335 &buf_area,
1336 ramBuffer,
1337 current_char.nb_skipped_bytes);
1338 }
1339 else {
1340 nbgl_drawImage(&current_area, current_char.buffer, &buf_area, ramBuffer);
1341 }
1342
1343 // Set the flag telling that RAM buffer need to be displayed, if needed
1344 if (current_char.byte_cnt) {
1345 redraw_buf_area = 1;
1346 previous_area = current_area;
1347 }
1348
1349 previous_char = current_char;
1350 }
1351 // Do we need to send RAM buffer content (previous character) to display?
1352 if (redraw_buf_area) {
1353 // Move the data at the beginning of RAM buffer, in a packed way
1354 display_ram_buffer(
1355 buf_x_min, buf_y_min, buf_x_max, buf_y_max, area, &buf_area, &previous_area, fontColor);
1356 }
1357#endif // SCREEN_SIZE_WALLET
1358 return fontId;
1359}
debug traces management
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
@ DRAW_LOGGER
Definition nbgl_debug.h:29
CCASSERT(qr_code_buffer, sizeof(QrCodeBuffer_t)<=GZLIB_UNCOMPRESSED_CHUNK)
Middle Level API of the new BOLOS Graphical Library.
#define STATIC
#define RLE_CMD_COPY_3
#define RLE_CMD_2PATTERN_INDEXED_B2W
#define RLE_CMD_FILL_BLACK
STATIC void nbgl_draw4BPPImageRle(nbgl_area_t *area, const uint8_t *buffer, uint32_t buffer_len, const uint8_t *patterns, nbgl_area_t *buf_area, uint8_t *dst, uint8_t nb_skipped_bytes)
Uncompress a 4BPP RLE-encoded glyph and draw it in a RAM buffer (we handle transparency,...
#define RLE_CMD_2PATTERN_W2B
#define RLE_CMD_FILL_1
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.
#define RLE_CMD_FILL_WHITE_16
#define RLE_CMD_2PATTERN_INDEXED_W2B
#define RLE_CMD_COPY_4
#define RLE_CMD_FILL_3
#define COMBINED_HEIGHT
#define AVERAGE_CHAR_WIDTH
#define RLE_CMD_1PATTERN_W2B
#define MAX_FONT_HEIGHT
#define RLE_CMD_COPY_2
#define RLE_CMD_FILL_2
#define RLE_CMD_COPY_5
#define RLE_CMD_FILL_WHITE
STATIC void update_char_info(character_info_t *char_info, const uint8_t **text, uint16_t *textLen, nbgl_unicode_ctx_t *unicode_ctx, const nbgl_font_t *font)
#define MAX_RLE_COPY_PIXELS
#define RLE_CMD_1PATTERN_B2W
#define RLE_CMD_2PATTERN_B2W
nbgl_unicode_ctx_t * nbgl_getUnicodeFont(nbgl_font_id_e font_id)
Get the font entry for the given font id (sparse font array support)
const nbgl_font_unicode_character_t * nbgl_getUnicodeFontCharacter(uint32_t unicode)
Get the unicode character object matching the given unicode (a unicode character is encoded on max of...
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:126
nbgl_font_id_e
Definition nbgl_fonts.h:132
@ BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
Definition nbgl_fonts.h:141
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition nbgl_fonts.h:139
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
uint32_t nbgl_getUnicodeFontCharacterByteCount(void)
Get the bitmap byte count of the latest used unicode character. (the one returned by nbgl_getUnicodeF...
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_frontDrawImageRle(const nbgl_area_t *area, const uint8_t *buffer, uint32_t buffer_len, color_t fore_color, uint8_t nb_skipped_bytes)
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
#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
@ NBGL_BPP_4
4 bits per pixel
Definition nbgl_types.h:286
struct PACKED__ nbgl_area_s nbgl_area_t
Represents a rectangle area of the screen.
const uint8_t * buffer
Definition nbgl_draw.h:34
const uint8_t * patterns
Definition nbgl_draw.h:35
uint32_t unicode
Definition nbgl_draw.h:33
uint8_t encoding
Definition nbgl_draw.h:45
uint16_t byte_cnt
Definition nbgl_draw.h:36
uint8_t nb_skipped_bytes
Definition nbgl_draw.h:46
uint16_t width
Definition nbgl_draw.h:41
uint16_t height
Definition nbgl_draw.h:42
fonts nicknames to be used for various wallet size targets (non-Nano)
Definition nbgl_fonts.h:63
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:66
uint32_t encoding
method used to encode bitmap data
Definition nbgl_fonts.h:65
uint32_t x_min_offset
x_min = x_min_offset
Definition nbgl_fonts.h:67
uint32_t bitmap_offset
offset of this character in chars buffer
Definition nbgl_fonts.h:64
uint32_t y_min_offset
y_min = (y_min + y_min_offset)
Definition nbgl_fonts.h:68
uint32_t x_max_offset
x_max = width - x_max_offset
Definition nbgl_fonts.h:69
uint32_t y_max_offset
y_max = (height - y_max_offset)
Definition nbgl_fonts.h:70
structure defining an ASCII font
Definition nbgl_fonts.h:77
uint8_t char_kerning
kerning for the font
Definition nbgl_fonts.h:83
uint8_t crop
If false, x_min_offset+y_min_offset=bytes to skip.
Definition nbgl_fonts.h:84
uint8_t first_char
ASCII code of the first character in bitmap and in characters fields.
Definition nbgl_fonts.h:87
uint32_t bitmap_len
Size in bytes of the associated bitmap.
Definition nbgl_fonts.h:78
uint8_t const * bitmap
array containing bitmaps of all characters
Definition nbgl_fonts.h:92
const nbgl_font_character_t *const characters
array containing definitions of all characters
Definition nbgl_fonts.h:91
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:81
uint8_t last_char
ASCII code of the last character in bitmap and in characters fields.
Definition nbgl_fonts.h:89
uint8_t y_min
Most top Y coordinate of any char in the font.
Definition nbgl_fonts.h:85
uint8_t bpp
number of bits per pixels
Definition nbgl_fonts.h:80
structure defining a unicode character (except the bitmap)
Definition nbgl_fonts.h:105
uint32_t encoding
method used to encode bitmap data
Definition nbgl_fonts.h:107
uint32_t width
width of character in pixels
Definition nbgl_fonts.h:108
uint32_t x_min_offset
x_min = x_min_offset
Definition nbgl_fonts.h:109
uint32_t y_min_offset
y_min = (y_min + y_min_offset)
Definition nbgl_fonts.h:110
uint32_t y_max_offset
y_max = (height - y_max_offset)
Definition nbgl_fonts.h:112
uint32_t over_previous
flag set to 1 when displayed over previous char
Definition nbgl_fonts.h:114
uint32_t x_max_offset
x_max = width - x_max_offset
Definition nbgl_fonts.h:111
uint32_t bitmap_offset
offset of this character in chars buffer
Definition nbgl_fonts.h:113
uint8_t crop
If false, x_min_offset+y_min_offset=bytes to skip.
Definition nbgl_fonts.h:127
uint8_t y_min
Most top Y coordinate of any char in the font.
Definition nbgl_fonts.h:128
uint8_t height
height of all characters in pixels
Definition nbgl_fonts.h:124
uint8_t line_height
height of a line for all characters in pixels
Definition nbgl_fonts.h:125
const nbgl_font_unicode_t * font
Definition nbgl_fonts.h:155
const uint8_t * bitmap
Definition nbgl_fonts.h:157
uint8_t pixels[MAX_RLE_COPY_PIXELS]
uint32_t buffer_len
const uint8_t * patterns
const uint8_t * buffer
uint32_t read_cnt