/**************************************************************************** * * The MIT License (MIT) * * Copyright 2020 NXP * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * 'Software'), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *****************************************************************************/ /** Include Files */ #include #include #include #include "vg_lite.h" #include "vg_lite_text.h" #include "vft_draw.h" #include "vft_debug.h" #include "rtthread.h" /** Macros */ #define VFT_ALLOC(x) _mem_allocate(x) #define VFT_FREE(x) _mem_free(x) #define READ_BIN_FIELD(x) memcpy(&g->x, (buf + offset), sizeof(g->x)); offset += sizeof(g->x) #define READ_BIN_FIELD_STR(x) READ_BIN_FIELD(x) #define READ_BIN_FIELD_UINT16(x) READ_BIN_FIELD(x) #define READ_BIN_FIELD_UINT32(x) READ_BIN_FIELD(x) #define READ_BIN_FIELD_FLOAT(x) READ_BIN_FIELD(x) #define READ_BIN_FIELD_DUMMY_POINTER(x) offset += 4; #define GLYPH_CACHE_SIZE 16 #define ENABLE_TEXT_WRAP 0 #define HALT_ALLOCATOR_ERROR 1 /** Data structures */ typedef struct glyph_cache_desc { vg_lite_path_t *h_path; glyph_desc_t *g; uint32_t use_count; }glyph_cache_desc_t; /** Internal or external API prototypes */ /** Globals */ static int g_glyph_cache_init_done = 0; static glyph_cache_desc_t g_glyph_cache[GLYPH_CACHE_SIZE]; int g_total_bytes = 0; /** Externs if any */ /* Internal API, not published to user */ font_face_desc_t *_vg_lite_get_vector_font(vg_lite_font_t font_idx); void matrix_multiply(vg_lite_matrix_t * matrix, vg_lite_matrix_t *mult); void *_mem_allocate(int size) { char *buf = NULL; if ( size == 0 ) { printf("ERROR: HALT: Why allocating %d bytes\n", size); #if HALT_ALLOCATOR_ERROR while(1); #else return NULL; #endif } buf = rt_malloc(size); if (buf == NULL) { printf("ERROR: HALT: allocating %d bytes \"system out of memory\"\n", size); #if HALT_ALLOCATOR_ERROR while(1); #else return NULL; #endif } g_total_bytes += size; return buf; } void _mem_free(void *buf) { rt_free(buf); } /** GLYPH CACHING Code */ void glyph_cache_init(void) { if ( g_glyph_cache_init_done == 0 ) { memset(g_glyph_cache,0,sizeof(g_glyph_cache)); g_glyph_cache_init_done = 1; } } void glyph_cache_free(void) { int i; for (i=0; iunicode == g_glyph_cache[i].g->unicode ) { g_glyph_cache[i].use_count++; return g_glyph_cache[i].h_path; } } /* Find least used descriptor */ unused_idx = 0; for (i=1; ipath.num_draw_cmds*4, g->path.draw_cmds, g->path.bounds[0], g->path.bounds[1], g->path.bounds[2], g->path.bounds[3]); g_glyph_cache[unused_idx].g = g; g_glyph_cache[unused_idx].use_count = 1; return g_glyph_cache[unused_idx].h_path; } /** Render text using vector fonts */ int 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) { font_face_desc_t *font_face; glyph_desc_t* g1 = NULL; glyph_desc_t* g2; int error = 0; float font_scale = 1.0; int text_wrap = 0; font_face = (font_face_desc_t *)_vg_lite_get_vector_font(font); attributes->last_dx = 0; font_scale = ((1.0*attributes->font_height)/font_face->units_per_em); vg_lite_matrix_t mat; vg_lite_fill_t fill_rule = VG_LITE_FILL_NON_ZERO; vg_lite_color_t color = attributes->text_color; /* Compute size of tex in pixels * For center alignment adjust x position * Present parser has bug in encoding alignment value, * Once it is fixed following code will align text in center */ if ( attributes->alignment == eTextAlignCenter || attributes->alignment == eTextAlignRight ) { char *t2 = text; int dx = 0; uint16_t ug2; /* Unicode glyph */ int kx; /* Case of center alignement */ while (*t2 != '\0') { ug2 = *t2; kx = 0; g2 = vft_find_glyph(font_face, ug2); if (g1 != NULL && g2 != NULL) { kx = vft_glyph_distance(g1, g2); } dx += ((g2->horiz_adv_x + kx )* font_scale); t2++; } if ( attributes->alignment == eTextAlignCenter) { x -= (dx/2); } else if ( attributes->alignment == eTextAlignRight) { x -= (dx); } } /* Compute pixels that will cover this vector path */ while (*text != '\0') { uint16_t ug2; /* Unicode glyph */ int kx; if (text_wrap == 0) { vg_lite_identity(&mat); matrix_multiply(&mat, matrix); vg_lite_translate(x,y, &mat); vg_lite_scale(font_scale,font_scale, &mat); // 0.35 = height/units_per_em vg_lite_scale(-1.0,1.0, &mat); vg_lite_scale(-1.0,-1.0, &mat); text_wrap = 1; } /* Read unicode character */ kx = 0; ug2 = *text; g2 = vft_find_glyph(font_face, ug2); if (g1 != NULL && g2 != NULL) { kx = vft_glyph_distance(g1, g2); } #if (ENABLE_TEXT_WRAP==1) /* Wrap text */ if ( (x + attributes->last_dx + ((g2->horiz_adv_x + kx )* font_scale)) >= (720 - 5) ) { text_wrap = 0; attributes->last_dx = 0; y += (attributes->font_height + 1); continue; } #endif /* ENABLE_TEXT_WRAP */ /* Compute glyph size in horizontal dimension */ g1 = g2; text++; error = vg_lite_draw(rt, vft_cache_lookup(g2), fill_rule, &mat, blend, color); if ( error != VG_LITE_SUCCESS ) { break; } vg_lite_translate(g2->horiz_adv_x + kx, 0, &mat); attributes->last_dx += ((g2->horiz_adv_x + kx )* font_scale); } attributes->last_dx += 2; /* Space between 2 text strings */ return 0; } void load_font_face(font_face_desc_t* font_face, uint8_t* buf, int font_face_offset) { font_face_desc_t* g = font_face; int offset = font_face_offset; READ_BIN_FIELD_STR(font_family_name); READ_BIN_FIELD_UINT16(units_per_em); READ_BIN_FIELD_UINT16(ascent); READ_BIN_FIELD_UINT16(descent); READ_BIN_FIELD_UINT16(vg_font); READ_BIN_FIELD_UINT32(num_glyphs); } void load_glyph_table(font_face_desc_t* font_face, uint8_t* buf, int glyph_table_offset) { int offset = glyph_table_offset; for (uint32_t i = 0; i < font_face->num_glyphs; i++) { glyph_desc_t* g = &font_face->glyphs[i]; memset(g, 0, sizeof(glyph_desc_t)); READ_BIN_FIELD_UINT16(unicode); READ_BIN_FIELD_UINT16(horiz_adv_x); READ_BIN_FIELD_UINT32(kern_num_entries); READ_BIN_FIELD_UINT32(kern_table_offset); READ_BIN_FIELD_DUMMY_POINTER(); READ_BIN_FIELD_FLOAT(path.bounds[0]); READ_BIN_FIELD_FLOAT(path.bounds[1]); READ_BIN_FIELD_FLOAT(path.bounds[2]); READ_BIN_FIELD_FLOAT(path.bounds[3]); READ_BIN_FIELD_UINT32(path.num_draw_cmds); READ_BIN_FIELD_UINT32(path.draw_cmds_offset); READ_BIN_FIELD_DUMMY_POINTER(); font_face->glyphs[i].kern_table = (kern_desc_t *)(buf + font_face->glyphs[i].kern_table_offset); font_face->glyphs[i].path.draw_cmds = (float *)(buf + font_face->glyphs[i].path.draw_cmds_offset); TRACE_INFO(("Glyph: '%c'\n", g->unicode)); vft_dbg_glyph_desc(g, d_offset); } } /* Load vector font ROM table from file */ font_face_desc_t* vft_load_from_buffer(char* buf_base, int file_size) { font_face_desc_t* font_face = NULL; uint32_t* blk_hdr; //int error = 0; /* Setup internal memory pointers of font_face_desc_t */ int font_face_offset = 0; int glyph_table_offset = 0; //int kern_table_offset = 0; //int path_data_offset = 0; int offset = 0; /* May be we can avoid this lookup */ while (offset < file_size) { blk_hdr = (uint32_t*)(buf_base + offset); eFontBlock_t eType = (eFontBlock_t)((*blk_hdr) >> 24); int size = ((*blk_hdr) & ((1<<24)-1)); TRACE_BIN(("BIN: %08x: block(%hu, %hu)\n", offset, eType, size)); offset += BLK_HDR_SIZE; /* Check integrity of block and then only proceed */ switch (eType) { case eFontFaceDesc: font_face_offset = offset; break; case eGlyphTableDesc: glyph_table_offset = offset; break; case eKernTableDesc: //kern_table_offset = offset; break; case eGlyphData: //path_data_offset = offset; break; default: case eUnkBlock: case eMaxBlock: return NULL;; } offset += size; } if (offset < 0 || offset > file_size) { printf("ERROR: Vector font file integrity error aborting..\n"); return NULL; } /* Make structure binary compliant to reduce loading time */ font_face = (font_face_desc_t*)(buf_base + font_face_offset); font_face->glyphs = (glyph_desc_t*)(buf_base + glyph_table_offset); VFT_DBG_FONT_FACE_DESC(font_face, font_face_offset); for (uint32_t i = 0; i < font_face->num_glyphs; i++) { /* Update internal pointer from memory mapped file */ font_face->glyphs[i].kern_table = (kern_desc_t*)(buf_base + font_face->glyphs[i].kern_table_offset); font_face->glyphs[i].path.draw_cmds = (float*)(buf_base + font_face->glyphs[i].path.draw_cmds_offset); /* Try to get these paramters from Binary object or attributes */ //vg_lite_format_t data_format = VG_LITE_FP32; //VG_LITE_S16; //vg_lite_quality_t quality = VG_LITE_HIGH; } VFT_DBG_GLYPH_TABLE(font_face, glyph_table_offset); VFT_DBG_KERN_TABLE(font_face, kern_table_offset); VFT_DBG_PATH_TABLE(font_face, path_data_offset); return font_face; } /* Find glyph of given character from glyph table */ glyph_desc_t* vft_find_glyph(font_face_desc_t* font_face, uint16_t ug2) { const int num_glyphs = font_face->num_glyphs; glyph_desc_t* glyphs = font_face->glyphs; /* * Present approach is slow linear search, this is ok in 1st prototype * Since glyph table is already sorted, we can have binary search */ for (int i = 0; i < num_glyphs; i++) { if (glyphs[i].unicode == ug2) { return (glyph_desc_t*)&glyphs[i]; } } return (glyph_desc_t*)&glyphs[0];; } /* Find distance between 2 glyph symbols */ int vft_glyph_distance(glyph_desc_t* g1, glyph_desc_t* g2) { signed short kx = 0; uint16_t ug2 = g2->unicode; kern_desc_t* kern_table = &g1->kern_table[0]; for (int i = 0; i < g1->kern_num_entries; i++) { if (kern_table[i].unicode == ug2) { signed short *pkx = (signed short *)&kern_table[i].kern; kx = *pkx; break; } } return kx; } /* * Get internal vector path of given glyph * This is internal function */ path_desc_t* vft_get_glyph_path(glyph_desc_t* g2) { return &g2->path; } /* Unload font face descriptor and all glyphs */ void vft_unload(font_face_desc_t* font_face) { glyph_cache_free(); //VFT_FREE(font_face); }