1 /**
2  * @file lv_draw_sdl_label.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../../lv_conf_internal.h"
11 
12 #if LV_USE_GPU_SDL
13 
14 #include LV_GPU_SDL_INCLUDE_PATH
15 
16 #include "../lv_draw_label.h"
17 #include "../../misc/lv_utils.h"
18 
19 #include "lv_draw_sdl_utils.h"
20 #include "lv_draw_sdl_texture_cache.h"
21 #include "lv_draw_sdl_composite.h"
22 #include "lv_draw_sdl_layer.h"
23 
24 /*********************
25  *      DEFINES
26  *********************/
27 
28 /**********************
29  *      TYPEDEFS
30  **********************/
31 
32 typedef struct {
33     lv_sdl_cache_key_magic_t magic;
34     const lv_font_t * font_p;
35     uint32_t letter;
36 } lv_font_glyph_key_t;
37 
38 /**********************
39  *  STATIC PROTOTYPES
40  **********************/
41 
42 static lv_font_glyph_key_t font_key_glyph_create(const lv_font_t * font_p, uint32_t letter);
43 
44 /**********************
45  *  STATIC VARIABLES
46  **********************/
47 
48 /**********************
49  *      MACROS
50  **********************/
51 
52 /**********************
53  *   GLOBAL FUNCTIONS
54  **********************/
55 
lv_draw_sdl_draw_letter(lv_draw_ctx_t * draw_ctx,const lv_draw_label_dsc_t * dsc,const lv_point_t * pos_p,uint32_t letter)56 void lv_draw_sdl_draw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p,
57                              uint32_t letter)
58 {
59     const lv_area_t * clip_area = draw_ctx->clip_area;
60     const lv_font_t * font_p = dsc->font;
61     lv_opa_t opa = dsc->opa;
62     lv_color_t color = dsc->color;
63     if(opa < LV_OPA_MIN) return;
64     if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
65 
66     if(font_p == NULL) {
67         LV_LOG_WARN("lv_draw_letter: font is NULL");
68         return;
69     }
70 
71     lv_font_glyph_dsc_t g;
72     bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0');
73     if(g_ret == false) {
74         /*Add warning if the dsc is not found
75          *but do not print warning for non printable ASCII chars (e.g. '\n')*/
76         if(letter >= 0x20 &&
77            letter != 0xf8ff && /*LV_SYMBOL_DUMMY*/
78            letter != 0x200c) { /*ZERO WIDTH NON-JOINER*/
79             LV_LOG_WARN("lv_draw_letter: glyph dsc. not found for U+%X", letter);
80 
81             /* draw placeholder */
82             lv_area_t glyph_coords;
83             lv_draw_rect_dsc_t glyph_dsc;
84             lv_coord_t begin_x = pos_p->x + g.ofs_x;
85             lv_coord_t begin_y = pos_p->y + g.ofs_y;
86             lv_area_set(&glyph_coords, begin_x, begin_y, begin_x + g.box_w, begin_y + g.box_h);
87             lv_draw_rect_dsc_init(&glyph_dsc);
88             glyph_dsc.bg_opa = LV_OPA_MIN;
89             glyph_dsc.outline_opa = LV_OPA_MIN;
90             glyph_dsc.shadow_opa = LV_OPA_MIN;
91             glyph_dsc.bg_img_opa = LV_OPA_MIN;
92             glyph_dsc.border_color = dsc->color;
93             glyph_dsc.border_width = 1;
94             draw_ctx->draw_rect(draw_ctx, &glyph_dsc, &glyph_coords);
95         }
96         return;
97     }
98 
99     /*Don't draw anything if the character is empty. E.g. space*/
100     if((g.box_h == 0) || (g.box_w == 0)) return;
101 
102     int32_t pos_x = pos_p->x + g.ofs_x;
103     int32_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y;
104 
105     const lv_area_t letter_area = {pos_x, pos_y, pos_x + g.box_w - 1, pos_y + g.box_h - 1};
106     lv_area_t draw_area;
107 
108     /*If the letter is completely out of mask don't draw it*/
109     if(!_lv_area_intersect(&draw_area, &letter_area, clip_area)) {
110         return;
111     }
112 
113     lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
114     SDL_Renderer * renderer = ctx->renderer;
115 
116     lv_font_glyph_key_t glyph_key = font_key_glyph_create(font_p, letter);
117     bool glyph_found = false;
118     SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &glyph_key, sizeof(glyph_key), &glyph_found);
119     bool in_cache = false;
120     if(!glyph_found) {
121         if(g.resolved_font) {
122             font_p = g.resolved_font;
123         }
124         const uint8_t * bmp = lv_font_get_glyph_bitmap(font_p, letter);
125         uint8_t * buf = lv_mem_alloc(g.box_w * g.box_h);
126         lv_sdl_to_8bpp(buf, bmp, g.box_w, g.box_h, g.box_w, g.bpp);
127         SDL_Surface * mask = lv_sdl_create_opa_surface(buf, g.box_w, g.box_h, g.box_w);
128         texture = SDL_CreateTextureFromSurface(renderer, mask);
129         SDL_FreeSurface(mask);
130         lv_mem_free(buf);
131         in_cache = lv_draw_sdl_texture_cache_put(ctx, &glyph_key, sizeof(glyph_key), texture);
132     }
133     else {
134         in_cache = true;
135     }
136     if(!texture) {
137         return;
138     }
139 
140     lv_area_t t_letter = letter_area, t_clip = *clip_area, apply_area;
141     bool has_composite = lv_draw_sdl_composite_begin(ctx, &letter_area, clip_area, NULL, dsc->blend_mode, &t_letter,
142                                                      &t_clip, &apply_area);
143 
144     lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_letter, &t_clip);
145 
146     /*If the letter is completely out of mask don't draw it*/
147     if(!_lv_area_intersect(&draw_area, &t_letter, &t_clip)) {
148         if(!in_cache) {
149             LV_LOG_WARN("Texture is not cached, this will impact performance.");
150             SDL_DestroyTexture(texture);
151         }
152         return;
153     }
154     SDL_Rect srcrect, dstrect;
155     lv_area_to_sdl_rect(&draw_area, &dstrect);
156     srcrect.x = draw_area.x1 - t_letter.x1;
157     srcrect.y = draw_area.y1 - t_letter.y1;
158     srcrect.w = dstrect.w;
159     srcrect.h = dstrect.h;
160     SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
161     SDL_SetTextureAlphaMod(texture, opa);
162     SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue);
163     SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);
164 
165     lv_draw_sdl_composite_end(ctx, &apply_area, dsc->blend_mode);
166 
167     if(!in_cache) {
168         LV_LOG_WARN("Texture is not cached, this will impact performance.");
169         SDL_DestroyTexture(texture);
170     }
171 }
172 
173 /**********************
174  *   STATIC FUNCTIONS
175  **********************/
176 
font_key_glyph_create(const lv_font_t * font_p,uint32_t letter)177 static lv_font_glyph_key_t font_key_glyph_create(const lv_font_t * font_p, uint32_t letter)
178 {
179     lv_font_glyph_key_t key;
180     /* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
181     SDL_memset(&key, 0, sizeof(key));
182     key.magic = LV_GPU_CACHE_KEY_MAGIC_FONT_GLYPH;
183     key.font_p = font_p;
184     key.letter = letter;
185     return key;
186 }
187 
188 #endif /*LV_USE_GPU_SDL*/
189