123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /****************************************************************************
- *
- * 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 <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #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; i<GLYPH_CACHE_SIZE; i++) {
- if ( g_glyph_cache[i].h_path != NULL ) {
- /* For non-mapped path this resetting is sufficient */
- vg_lite_clear_path(g_glyph_cache[i].h_path);
- /* Release path handle */
- VFT_FREE(g_glyph_cache[i].h_path);
- /* Reset pointer */
- g_glyph_cache[i].h_path = NULL;
- }
- }
- /* Next time font init will be required */
- g_glyph_cache_init_done = 0;
- }
- vg_lite_path_t *vft_cache_lookup(glyph_desc_t *g)
- {
- int i;
- int unused_idx = 0;
- /* Not present caching code does not handle multiple font-face */
- glyph_cache_init();
- /* Check if path object for given glyph exists */
- for (i=0; i<GLYPH_CACHE_SIZE; i++) {
- if ( g_glyph_cache[i].g != NULL && g->unicode ==
- 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; i<GLYPH_CACHE_SIZE; i++) {
- if ( g_glyph_cache[i].use_count <
- g_glyph_cache[unused_idx].use_count ) {
- unused_idx = i;
- }
- }
- /* Re-cycle descriptor */
- if ( g_glyph_cache[unused_idx].h_path != NULL ) {
- /* For non-mapped path this resetting is sufficient */
- vg_lite_clear_path(g_glyph_cache[unused_idx].h_path);
- } else {
- /* Allocate new path object */
- g_glyph_cache[unused_idx].h_path =
- (vg_lite_path_t *)VFT_ALLOC(sizeof(vg_lite_path_t));
- }
- /* Allocate new path */
- vg_lite_init_path(g_glyph_cache[unused_idx].h_path,
- VG_LITE_FP32, VG_LITE_HIGH,
- g->path.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);
- }
|