1 /****************************************************************************
2 *
3 *    The MIT License (MIT)
4 *
5 *    Copyright 2020 NXP
6 *    All Rights Reserved.
7 *
8 *    Permission is hereby granted, free of charge, to any person obtaining
9 *    a copy of this software and associated documentation files (the
10 *    'Software'), to deal in the Software without restriction, including
11 *    without limitation the rights to use, copy, modify, merge, publish,
12 *    distribute, sub license, and/or sell copies of the Software, and to
13 *    permit persons to whom the Software is furnished to do so, subject
14 *    to the following conditions:
15 *
16 *    The above copyright notice and this permission notice (including the
17 *    next paragraph) shall be included in all copies or substantial
18 *    portions of the Software.
19 *
20 *    THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
21 *    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23 *    IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
24 *    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 *    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 *    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 *
28 *****************************************************************************/
29 
30 /** Include Files */
31 #include "vg_lite.h"
32 #include "vg_lite_text.h"
33 #include <stdio.h>
34 #include <string.h>
35 
36 #include <mcufont.h>
37 #include "vft_draw.h"
38 
39 /** Macros */
40 
41 /** Data structures */
42 typedef struct {
43     /* Font related parameters */
44     vg_lite_font_attributes_t *attributes;
45     vg_lite_buffer_t buffer;
46     uint16_t width;
47     uint16_t height;
48     uint16_t y;
49     const struct mf_font_s *rcd_font;
50 } text_context_t;
51 
52 /** Internal or external API prototypes */
53 struct mf_font_s *_vg_lite_get_raster_font(vg_lite_font_t font_idx);
54 int vg_lite_is_font_valid(vg_lite_font_t font);
55 
56 /** Globals */
57 vg_lite_font_attributes_t g_font_attribs;
58 vg_lite_font_t g_last_font = VG_LITE_INVALID_FONT;
59 int g_last_font_attrib_idx;
60 
61 /** Externs if any */
62 
63 /* Capture unique values of alpha */
64 static unsigned int g_index_table[257];
65 
66 /* text_color is in ARGB8888 format */
init_256pallet_color_table(unsigned int bg_color,unsigned int fg_color)67 int init_256pallet_color_table(unsigned int bg_color, unsigned int fg_color)
68 {
69   int i;
70   g_index_table[0] = 0; /* Background color */
71   int fg_r = ((fg_color>>0)&0xff);
72   int fg_g = ((fg_color>>8)&0xff);
73   int fg_b = ((fg_color>>16)&0xff);
74 
75   int bg_r = ((bg_color>>0)&0xff);
76   int bg_g = ((bg_color>>8)&0xff);
77   int bg_b = ((bg_color>>16)&0xff);
78 
79   for (i=1; i<256; i++) {
80     int r, g, b;
81     int a = 0xff;
82     register int mult, mult2;
83 
84     mult = ((i*1024)/256);
85     mult2 = (((256-i)*1024)/256);
86 
87     /* Blend with white bg */
88     r = ( ((bg_r * mult2)>>10) +((fg_r * mult)>>10) );
89     g = ( ((bg_g * mult2)>>10) +((fg_g * mult)>>10) );
90     b = ( ((bg_b * mult2)>>10) +((fg_b * mult)>>10) );
91     g_index_table[i] = ((a) + (r<<8) + (g<<16)+(b<<24));
92   }
93   return 0;
94 }
95 
96 /* Callback to write to a memory buffer. */
pixel_callback(int16_t x,int16_t y,uint8_t count,uint8_t alpha,void * state)97 static void pixel_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha,
98                            void *state)
99 {
100     text_context_t *s = (text_context_t*)state;
101     uint32_t pos;
102     uint32_t value;
103     uint32_t *raw_pixel_buffer = (uint32_t *)s->buffer.memory;
104     int stride = s->buffer.stride;
105 
106     if (y < 0 || y >= s->height) return;
107     if (x < 0 || x + count >= s->width) return;
108 
109     while (count--)
110     {
111         pos = (uint32_t)stride * y + x;
112         value = g_index_table[alpha];
113 
114         raw_pixel_buffer[pos] = value;
115 
116         x++;
117     }
118 }
119 
120 /* Callback to render characters. */
character_callback(int16_t x,int16_t y,mf_char character,void * state)121 static uint8_t character_callback(int16_t x, int16_t y, mf_char character,
122                                   void *state)
123 {
124     text_context_t *s = (text_context_t*)state;
125     return mf_render_character(s->rcd_font, x, y, character, pixel_callback, state);
126 }
127 
128 /* Callback to render lines. */
line_callback(const char * line,uint16_t count,void * state)129 static bool line_callback(const char *line, uint16_t count, void *state)
130 {
131     text_context_t *s = (text_context_t*)state;
132 
133     if (s->attributes->justify)
134     {
135         mf_render_justified(s->rcd_font, s->attributes->anchor, s->y,
136                             s->width - s->attributes->margin * 2,
137                             line, count, character_callback, state);
138     }
139     else
140     {
141         mf_render_aligned(s->rcd_font, s->attributes->anchor, s->y,
142                           (enum mf_align_t)s->attributes->alignment, line, count,
143                           character_callback, state);
144     }
145     s->y += s->rcd_font->line_height;
146     return true;
147 }
148 
149 /* Callback to just count the lines.
150  * Used to decide the image height */
count_lines(const char * line,uint16_t count,void * state)151 bool count_lines(const char *line, uint16_t count, void *state)
152 {
153     int *linecount = (int*)state;
154     (*linecount)++;
155     return true;
156 }
157 
alloc_font_buffer(vg_lite_buffer_t * buffer,int width,int height)158 vg_lite_error_t alloc_font_buffer(vg_lite_buffer_t *buffer, int width , int height)
159 {
160     vg_lite_error_t error;
161 
162     /* Align width to 16 pixels, heigh to 16 pixels */
163     width = ((width+15)&(~15));
164     height = ((height+15)&(~15));
165 
166     /* Allocate memory from VGLITE space */
167     buffer->width  = width;
168     buffer->height = height;
169     buffer->format = VG_LITE_ARGB8888;
170     buffer->stride = 0;
171     error = vg_lite_allocate(buffer);
172     buffer->stride = width;
173     buffer->tiled = VG_LITE_LINEAR;
174 
175     return error;
176 }
177 
free_font_buffer(vg_lite_buffer_t * buffer)178 static vg_lite_error_t free_font_buffer(vg_lite_buffer_t *buffer)
179 {
180     vg_lite_error_t error;
181 
182     error = vg_lite_free(buffer);
183 
184     return error;
185 }
186 
matrix_multiply(vg_lite_matrix_t * matrix,vg_lite_matrix_t * mult)187 void matrix_multiply(vg_lite_matrix_t * matrix, vg_lite_matrix_t * mult)
188 {
189     vg_lite_matrix_t temp;
190     int row, column;
191 
192     /* Process all rows. */
193     for (row = 0; row < 3; row++) {
194         /* Process all columns. */
195         for (column = 0; column < 3; column++) {
196             /* Compute matrix entry. */
197             temp.m[row][column] =  (matrix->m[row][0] * mult->m[0][column])
198             + (matrix->m[row][1] * mult->m[1][column])
199             + (matrix->m[row][2] * mult->m[2][column]);
200         }
201     }
202 
203     /* Copy temporary matrix into result. */
204     memcpy(matrix, &temp, sizeof(temp));
205 }
206 
vg_lite_draw_text(vg_lite_buffer_t * target,char * text,vg_lite_font_t font,int x,int y,vg_lite_matrix_t * matrix,vg_lite_blend_t blend,vg_lite_font_attributes_t * attributes)207 vg_lite_error_t vg_lite_draw_text(vg_lite_buffer_t *target,
208                                   char *text,
209                                   vg_lite_font_t font,
210                                   int x,
211                                   int y,
212                                   vg_lite_matrix_t *matrix,
213                                   vg_lite_blend_t blend,
214                                   vg_lite_font_attributes_t *attributes)
215 {
216     vg_lite_error_t error;
217     int height;
218     text_context_t ctx_text;
219     vg_lite_matrix_t m_text;
220     int text_img_size = 0;
221     font_face_desc_t* font_face = NULL;
222     int text_width_in_pixels = 0;
223     int tmpX;
224 
225     memset(&ctx_text, 0, sizeof(ctx_text));
226     ctx_text.attributes = attributes;
227 
228     if ( vg_lite_is_font_valid(font) != 0 ) {
229         return VG_LITE_INVALID_ARGUMENT;
230     }
231 
232     error = vg_lite_load_font_data(font,
233                                  attributes->font_height);
234     if ( error != 0 ) {
235         return VG_LITE_INVALID_ARGUMENT;
236     }
237 
238     if(attributes->tspan_has_dx_dy != 0)
239     {
240         if ( x < 0 )
241             x = attributes->last_x + attributes->last_dx;
242         if ( y < 0 )
243             y = attributes->last_y;
244     }
245 
246     // Dynamic decision
247     if ( attributes->is_vector_font == 0 ) {
248         init_256pallet_color_table(attributes->bg_color, attributes->text_color);
249 
250         /* Application specifies actual font by reading proper rcd file */
251         ctx_text.rcd_font = _vg_lite_get_raster_font(font);
252 
253         /* Count number of lines to decide font buffer size. */
254         height = 0;
255         mf_text_draw_area(ctx_text.rcd_font, attributes->width - 2 * attributes->margin,
256                     text, &height, &text_width_in_pixels);
257         height *= attributes->font_height;
258         height += 4;
259 
260         if( attributes->tspan_has_dx_dy == 0) {
261             y -= attributes->font_height;
262         }
263 
264         tmpX = x;
265         if(attributes->alignment == eTextAlignCenter) {
266             tmpX -= text_width_in_pixels/2;
267         } else if(attributes->alignment == eTextAlignRight) {
268             tmpX -= text_width_in_pixels;
269         }
270         /* Manually calculate X-offset for text-alignemnt; mcufont just
271          * doesn't render half part(left-part) for center alignment and
272          * full string skipped for right-alignment, So again set it to
273          * left-alignment for font-attrib, as offsets are already
274          * calculated and alignment handled in other way */
275         attributes->alignment = 0;
276 
277         /* Allocate and initialize vg_lite_buffer that can hold font text
278          * Note: ctx_text.width and ctx_text.height get used by internal
279          *   state of MF rendering engine. Based on amount of text to render
280          *   This buffer gets allocated, and buffer width gets aligned to
281          *   16 pixel boundary
282          */
283         ctx_text.width = attributes->width;
284         /* Memory optimization */
285         ctx_text.width = text_width_in_pixels;
286         /* Align width to 16 pixel boundary */
287         if (ctx_text.width & 15) {
288             ctx_text.width += 15;
289             ctx_text.width &= (~15);
290         }
291 
292         ctx_text.height = height;
293         error = alloc_font_buffer(&ctx_text.buffer, ctx_text.width, ctx_text.height);
294         if ( error != VG_LITE_SUCCESS) {
295             printf("WARNING: alloc_font_buffer failed(%d).\r\n",error);
296         }
297         ctx_text.y = 2;
298 
299         /* Initialize vg_lite buffer with transperant color */
300         /* Due to alignment requirement of vg_lite, font buffer can be larger */
301         if ( ctx_text.buffer.format == VG_LITE_ARGB8888 )
302           text_img_size = ctx_text.buffer.width * ctx_text.buffer.height * 4;
303         else
304           text_img_size = ctx_text.buffer.width * ctx_text.buffer.height;
305         memset(ctx_text.buffer.memory, 0,
306                text_img_size);
307 
308         /* Render font text into vg_lite_buffer  */
309         mf_wordwrap(ctx_text.rcd_font, attributes->width - 2 * attributes->margin,
310                     text, line_callback, &ctx_text);
311 
312         /* Draw font bitmap on render target */
313         vg_lite_identity(&m_text);
314         matrix_multiply(&m_text, matrix);
315         vg_lite_translate(x, y, &m_text);
316         vg_lite_scale(1.0, 1.0, &m_text);
317         if ( ctx_text.buffer.format == VG_LITE_ARGB8888 )
318           ctx_text.buffer.stride = ctx_text.width*4;
319 
320         error = vg_lite_blit(target, &ctx_text.buffer, &m_text, blend,
321                     0, VG_LITE_FILTER_POINT);
322         if ( error != VG_LITE_SUCCESS) {
323             printf("WARNING: vg_lite_blit failed(%d).\r\n",error);
324         }
325 
326         error = vg_lite_finish();
327         if ( error != VG_LITE_SUCCESS) {
328             printf("WARNING: vg_lite_finish failed(%d).\r\n",error);
329         }
330 
331         error = free_font_buffer(&ctx_text.buffer);
332         if ( error != VG_LITE_SUCCESS) {
333             printf("WARNING: vg_lite_finish failed(%d).\r\n",error);
334         }
335         attributes->last_dx = text_width_in_pixels;
336     } else {
337       error = (vg_lite_error_t)vg_lite_vtf_draw_text(target,
338                                     x, y,
339                                     blend,
340                                     font,
341                                     matrix,
342                                     attributes,
343                                     text);
344          /* Note: vg_lite_vtf_draw_text updates attributes->last_dx internally
345             This assignment is just to keep code similar to rcd code */
346         attributes->last_dx = attributes->last_dx;
347 
348         error = vg_lite_finish();
349         if ( error != VG_LITE_SUCCESS) {
350             printf("WARNING: vg_lite_finish failed(%d).\r\n",error);
351         }
352 
353         vft_unload(font_face);
354     }
355     attributes->last_x = x;
356     attributes->last_y = y;
357 
358     return error;
359 }
360