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 <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "vg_lite.h"
35 #include "vg_lite_text.h"
36 #include "vft_draw.h"
37 #include "vft_debug.h"
38 
39 #include "rtthread.h"
40 
41 /** Macros */
42 #define VFT_ALLOC(x) _mem_allocate(x)
43 #define VFT_FREE(x) _mem_free(x)
44 #define READ_BIN_FIELD(x) memcpy(&g->x, (buf + offset), sizeof(g->x));  offset += sizeof(g->x)
45 #define READ_BIN_FIELD_STR(x) READ_BIN_FIELD(x)
46 #define READ_BIN_FIELD_UINT16(x) READ_BIN_FIELD(x)
47 #define READ_BIN_FIELD_UINT32(x) READ_BIN_FIELD(x)
48 #define READ_BIN_FIELD_FLOAT(x) READ_BIN_FIELD(x)
49 #define READ_BIN_FIELD_DUMMY_POINTER(x) offset += 4;
50 #define GLYPH_CACHE_SIZE 16
51 #define ENABLE_TEXT_WRAP 0
52 #define HALT_ALLOCATOR_ERROR 1
53 
54 /** Data structures */
55 typedef struct glyph_cache_desc {
56     vg_lite_path_t *h_path;
57     glyph_desc_t *g;
58     uint32_t use_count;
59 }glyph_cache_desc_t;
60 
61 /** Internal or external API prototypes */
62 
63 /** Globals */
64 static int g_glyph_cache_init_done = 0;
65 static glyph_cache_desc_t g_glyph_cache[GLYPH_CACHE_SIZE];
66 int g_total_bytes = 0;
67 
68 /** Externs if any */
69 
70 /* Internal API, not published to user */
71 font_face_desc_t *_vg_lite_get_vector_font(vg_lite_font_t font_idx);
72 void matrix_multiply(vg_lite_matrix_t * matrix, vg_lite_matrix_t *mult);
73 
_mem_allocate(int size)74 void *_mem_allocate(int size)
75 {
76   char *buf = NULL;
77 
78   if ( size == 0 ) {
79     printf("ERROR: HALT: Why allocating %d bytes\n", size);
80 #if HALT_ALLOCATOR_ERROR
81     while(1);
82 #else
83     return NULL;
84 #endif
85   }
86 
87   buf = rt_malloc(size);
88   if (buf == NULL) {
89     printf("ERROR: HALT: allocating %d bytes \"system out of memory\"\n", size);
90 #if HALT_ALLOCATOR_ERROR
91     while(1);
92 #else
93     return NULL;
94 #endif
95   }
96   g_total_bytes += size;
97   return buf;
98 }
99 
_mem_free(void * buf)100 void _mem_free(void *buf)
101 {
102     rt_free(buf);
103 }
104 
105 /** GLYPH CACHING Code */
glyph_cache_init(void)106 void glyph_cache_init(void)
107 {
108     if ( g_glyph_cache_init_done == 0 ) {
109         memset(g_glyph_cache,0,sizeof(g_glyph_cache));
110         g_glyph_cache_init_done = 1;
111     }
112 }
113 
glyph_cache_free(void)114 void glyph_cache_free(void)
115 {
116     int i;
117     for (i=0; i<GLYPH_CACHE_SIZE; i++) {
118         if ( g_glyph_cache[i].h_path != NULL ) {
119             /* For non-mapped path this resetting is sufficient */
120             vg_lite_clear_path(g_glyph_cache[i].h_path);
121 
122             /* Release path handle */
123             VFT_FREE(g_glyph_cache[i].h_path);
124 
125             /* Reset pointer */
126             g_glyph_cache[i].h_path = NULL;
127         }
128     }
129 
130     /* Next time font init will be required */
131     g_glyph_cache_init_done = 0;
132 }
133 
vft_cache_lookup(glyph_desc_t * g)134 vg_lite_path_t *vft_cache_lookup(glyph_desc_t *g)
135 {
136     int i;
137     int unused_idx = 0;
138 
139     /* Not present caching code does not handle multiple font-face */
140     glyph_cache_init();
141 
142     /* Check if path object for given glyph exists */
143     for (i=0; i<GLYPH_CACHE_SIZE; i++) {
144         if ( g_glyph_cache[i].g != NULL && g->unicode ==
145             g_glyph_cache[i].g->unicode )
146         {
147             g_glyph_cache[i].use_count++;
148             return g_glyph_cache[i].h_path;
149         }
150     }
151 
152     /* Find least used descriptor */
153     unused_idx = 0;
154     for (i=1; i<GLYPH_CACHE_SIZE; i++) {
155       if ( g_glyph_cache[i].use_count <
156           g_glyph_cache[unused_idx].use_count ) {
157             unused_idx = i;
158       }
159     }
160     /* Re-cycle descriptor */
161     if ( g_glyph_cache[unused_idx].h_path != NULL ) {
162         /* For non-mapped path this resetting is sufficient */
163         vg_lite_clear_path(g_glyph_cache[unused_idx].h_path);
164     } else {
165         /* Allocate new path object */
166         g_glyph_cache[unused_idx].h_path =
167             (vg_lite_path_t *)VFT_ALLOC(sizeof(vg_lite_path_t));
168     }
169     /* Allocate new path */
170     vg_lite_init_path(g_glyph_cache[unused_idx].h_path,
171                       VG_LITE_FP32, VG_LITE_HIGH,
172                       g->path.num_draw_cmds*4,
173                       g->path.draw_cmds,
174                       g->path.bounds[0],
175                       g->path.bounds[1],
176                       g->path.bounds[2],
177                       g->path.bounds[3]);
178     g_glyph_cache[unused_idx].g = g;
179     g_glyph_cache[unused_idx].use_count = 1;
180     return g_glyph_cache[unused_idx].h_path;
181 }
182 
183 /** Render text using vector fonts */
vg_lite_vtf_draw_text(vg_lite_buffer_t * rt,int x,int y,vg_lite_blend_t blend,vg_lite_font_t font,vg_lite_matrix_t * matrix,vg_lite_font_attributes_t * attributes,char * text)184 int vg_lite_vtf_draw_text(vg_lite_buffer_t *rt, int x, int y,
185                       vg_lite_blend_t blend,
186                       vg_lite_font_t font,
187                       vg_lite_matrix_t *matrix,
188                       vg_lite_font_attributes_t  * attributes,
189                       char *text)
190 {
191     font_face_desc_t *font_face;
192     glyph_desc_t* g1 = NULL;
193     glyph_desc_t* g2;
194     int error = 0;
195     float font_scale = 1.0;
196     int text_wrap = 0;
197 
198     font_face = (font_face_desc_t *)_vg_lite_get_vector_font(font);
199 
200     attributes->last_dx = 0;
201     font_scale = ((1.0*attributes->font_height)/font_face->units_per_em);
202 
203     vg_lite_matrix_t mat;
204 
205     vg_lite_fill_t    fill_rule = VG_LITE_FILL_NON_ZERO;
206     vg_lite_color_t   color = attributes->text_color;
207 
208     /* Compute size of tex in pixels
209      * For center alignment adjust x position
210      * Present parser has bug in encoding alignment value,
211      * Once it is fixed following code will align text in center
212      */
213     if ( attributes->alignment == eTextAlignCenter ||
214          attributes->alignment == eTextAlignRight ) {
215         char *t2 = text;
216         int dx = 0;
217         uint16_t ug2; /* Unicode glyph */
218         int kx;
219 
220         /* Case of center alignement */
221         while (*t2 != '\0') {
222             ug2 = *t2;
223             kx = 0;
224             g2 = vft_find_glyph(font_face, ug2);
225             if (g1 != NULL && g2 != NULL) {
226                 kx = vft_glyph_distance(g1, g2);
227             }
228 
229             dx += ((g2->horiz_adv_x + kx )* font_scale);
230             t2++;
231         }
232 
233         if ( attributes->alignment == eTextAlignCenter) {
234             x -= (dx/2);
235         } else if ( attributes->alignment == eTextAlignRight) {
236             x -= (dx);
237         }
238     }
239 
240     /* Compute pixels that will cover this vector path */
241     while (*text != '\0') {
242         uint16_t ug2; /* Unicode glyph */
243         int kx;
244 
245         if (text_wrap == 0) {
246             vg_lite_identity(&mat);
247             matrix_multiply(&mat, matrix);
248             vg_lite_translate(x,y, &mat);
249             vg_lite_scale(font_scale,font_scale, &mat); // 0.35 = height/units_per_em
250             vg_lite_scale(-1.0,1.0, &mat);
251             vg_lite_scale(-1.0,-1.0, &mat);
252             text_wrap = 1;
253         }
254 
255         /* Read unicode character */
256         kx = 0;
257         ug2 = *text;
258         g2 = vft_find_glyph(font_face, ug2);
259         if (g1 != NULL && g2 != NULL) {
260             kx = vft_glyph_distance(g1, g2);
261         }
262 
263 #if (ENABLE_TEXT_WRAP==1)
264         /* Wrap text */
265         if ( (x + attributes->last_dx + ((g2->horiz_adv_x + kx )* font_scale))
266               >= (720 - 5) )
267         {
268           text_wrap = 0;
269           attributes->last_dx = 0;
270           y += (attributes->font_height + 1);
271           continue;
272         }
273 #endif /* ENABLE_TEXT_WRAP */
274 
275         /* Compute glyph size in horizontal dimension */
276         g1 = g2;
277         text++;
278 
279         error = vg_lite_draw(rt, vft_cache_lookup(g2),
280                              fill_rule,
281                              &mat,
282                              blend,
283                              color);
284         if ( error != VG_LITE_SUCCESS ) {
285           break;
286         }
287 
288         vg_lite_translate(g2->horiz_adv_x + kx, 0, &mat);
289         attributes->last_dx += ((g2->horiz_adv_x + kx )* font_scale);
290     }
291 
292     attributes->last_dx += 2; /* Space between 2 text strings */
293 
294     return 0;
295 }
296 
load_font_face(font_face_desc_t * font_face,uint8_t * buf,int font_face_offset)297 void load_font_face(font_face_desc_t* font_face, uint8_t* buf, int font_face_offset)
298 {
299     font_face_desc_t* g = font_face;
300     int offset = font_face_offset;
301 
302     READ_BIN_FIELD_STR(font_family_name);
303     READ_BIN_FIELD_UINT16(units_per_em);
304     READ_BIN_FIELD_UINT16(ascent);
305     READ_BIN_FIELD_UINT16(descent);
306     READ_BIN_FIELD_UINT16(vg_font);
307     READ_BIN_FIELD_UINT32(num_glyphs);
308 }
309 
load_glyph_table(font_face_desc_t * font_face,uint8_t * buf,int glyph_table_offset)310 void load_glyph_table(font_face_desc_t* font_face, uint8_t* buf, int glyph_table_offset)
311 {
312     int offset = glyph_table_offset;
313 
314     for (uint32_t i = 0; i < font_face->num_glyphs; i++) {
315         glyph_desc_t* g = &font_face->glyphs[i];
316 
317         memset(g, 0, sizeof(glyph_desc_t));
318         READ_BIN_FIELD_UINT16(unicode);
319         READ_BIN_FIELD_UINT16(horiz_adv_x);
320         READ_BIN_FIELD_UINT32(kern_num_entries);
321         READ_BIN_FIELD_UINT32(kern_table_offset);
322         READ_BIN_FIELD_DUMMY_POINTER();
323         READ_BIN_FIELD_FLOAT(path.bounds[0]);
324         READ_BIN_FIELD_FLOAT(path.bounds[1]);
325         READ_BIN_FIELD_FLOAT(path.bounds[2]);
326         READ_BIN_FIELD_FLOAT(path.bounds[3]);
327         READ_BIN_FIELD_UINT32(path.num_draw_cmds);
328         READ_BIN_FIELD_UINT32(path.draw_cmds_offset);
329         READ_BIN_FIELD_DUMMY_POINTER();
330 
331         font_face->glyphs[i].kern_table = (kern_desc_t *)(buf + font_face->glyphs[i].kern_table_offset);
332         font_face->glyphs[i].path.draw_cmds = (float *)(buf + font_face->glyphs[i].path.draw_cmds_offset);
333 
334         TRACE_INFO(("Glyph: '%c'\n", g->unicode));
335         vft_dbg_glyph_desc(g, d_offset);
336     }
337 }
338 
339 /* Load vector font ROM table from file */
vft_load_from_buffer(char * buf_base,int file_size)340 font_face_desc_t* vft_load_from_buffer(char* buf_base, int file_size)
341 {
342     font_face_desc_t* font_face = NULL;
343     uint32_t* blk_hdr;
344     //int error = 0;
345 
346     /* Setup internal memory pointers of font_face_desc_t */
347     int font_face_offset = 0;
348     int glyph_table_offset = 0;
349     //int kern_table_offset = 0;
350     //int path_data_offset = 0;
351     int offset = 0;
352 
353     /* May be we can avoid this lookup */
354     while (offset < file_size) {
355         blk_hdr = (uint32_t*)(buf_base + offset);
356         eFontBlock_t eType = (eFontBlock_t)((*blk_hdr) >> 24);
357         int size  = ((*blk_hdr) & ((1<<24)-1));
358         TRACE_BIN(("BIN: %08x:  block(%hu, %hu)\n",
359             offset, eType, size));
360         offset += BLK_HDR_SIZE;
361 
362         /* Check integrity of block and then only proceed */
363         switch (eType) {
364         case eFontFaceDesc:
365             font_face_offset = offset;
366             break;
367         case eGlyphTableDesc:
368             glyph_table_offset = offset;
369             break;
370         case eKernTableDesc:
371             //kern_table_offset = offset;
372             break;
373         case eGlyphData:
374             //path_data_offset = offset;
375             break;
376         default:
377         case eUnkBlock:
378         case eMaxBlock:
379             return NULL;;
380         }
381         offset += size;
382     }
383 
384     if (offset < 0 || offset > file_size) {
385         printf("ERROR: Vector font file integrity error aborting..\n");
386         return NULL;
387     }
388 
389     /* Make structure binary compliant to reduce loading time */
390     font_face = (font_face_desc_t*)(buf_base + font_face_offset);
391     font_face->glyphs = (glyph_desc_t*)(buf_base + glyph_table_offset);
392 
393     VFT_DBG_FONT_FACE_DESC(font_face, font_face_offset);
394     for (uint32_t i = 0; i < font_face->num_glyphs; i++) {
395         /* Update internal pointer from memory mapped file */
396         font_face->glyphs[i].kern_table =
397             (kern_desc_t*)(buf_base + font_face->glyphs[i].kern_table_offset);
398         font_face->glyphs[i].path.draw_cmds =
399             (float*)(buf_base +
400                 font_face->glyphs[i].path.draw_cmds_offset);
401        /* Try to get these paramters from Binary object or attributes */
402        //vg_lite_format_t data_format = VG_LITE_FP32; //VG_LITE_S16;
403        //vg_lite_quality_t quality = VG_LITE_HIGH;
404     }
405     VFT_DBG_GLYPH_TABLE(font_face, glyph_table_offset);
406 
407     VFT_DBG_KERN_TABLE(font_face, kern_table_offset);
408     VFT_DBG_PATH_TABLE(font_face, path_data_offset);
409 
410     return font_face;
411 }
412 
413 /* Find glyph of given character from glyph table */
vft_find_glyph(font_face_desc_t * font_face,uint16_t ug2)414 glyph_desc_t* vft_find_glyph(font_face_desc_t* font_face, uint16_t ug2)
415 {
416     const int num_glyphs = font_face->num_glyphs;
417     glyph_desc_t* glyphs = font_face->glyphs;
418 
419     /*
420     * Present approach is slow linear search, this is ok in 1st prototype
421     * Since glyph table is already sorted, we can have binary search
422     */
423     for (int i = 0; i < num_glyphs; i++) {
424         if (glyphs[i].unicode == ug2) {
425             return (glyph_desc_t*)&glyphs[i];
426         }
427     }
428     return (glyph_desc_t*)&glyphs[0];;
429 }
430 
431 /* Find distance between 2 glyph symbols */
vft_glyph_distance(glyph_desc_t * g1,glyph_desc_t * g2)432 int vft_glyph_distance(glyph_desc_t* g1, glyph_desc_t* g2)
433 {
434     signed short kx = 0;
435     uint16_t ug2 = g2->unicode;
436     kern_desc_t* kern_table = &g1->kern_table[0];
437 
438     for (int i = 0; i < g1->kern_num_entries; i++) {
439         if (kern_table[i].unicode == ug2) {
440             signed short *pkx = (signed short *)&kern_table[i].kern;
441             kx = *pkx;
442             break;
443         }
444     }
445 
446     return kx;
447 }
448 
449 /*
450 * Get internal vector path of given glyph
451 * This is internal function
452 */
vft_get_glyph_path(glyph_desc_t * g2)453 path_desc_t* vft_get_glyph_path(glyph_desc_t* g2)
454 {
455     return &g2->path;
456 }
457 
458 /* Unload font face descriptor and all glyphs */
vft_unload(font_face_desc_t * font_face)459 void vft_unload(font_face_desc_t* font_face)
460 {
461     glyph_cache_free();
462     //VFT_FREE(font_face);
463 }
464