From 91d14f778a30055aca6d893bb613feb5e1ee7717 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Mon, 19 Jul 2021 18:41:34 +0200 Subject: [PATCH] split font identity and size structure, the second holding face, hb, and lookup objects --- src/vkvg_context.c | 6 +- src/vkvg_context_internal.h | 7 +- src/vkvg_fonts.c | 174 +++++++++++++++++++++--------------- src/vkvg_fonts.h | 28 +++--- 4 files changed, 126 insertions(+), 89 deletions(-) diff --git a/src/vkvg_context.c b/src/vkvg_context.c index e87c3b7..0ec252e 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -973,8 +973,12 @@ void vkvg_select_font_path (VkvgContext ctx, const char* path){ void vkvg_set_font_size (VkvgContext ctx, uint32_t size){ if (ctx->status) return; - ctx->selectedCharSize = size << 6; + FT_F26Dot6 newSize = size << 6; + if (ctx->selectedCharSize == newSize) + return; + ctx->selectedCharSize = newSize; ctx->currentFont = NULL; + ctx->currentFontSize = NULL; } void vkvg_set_text_direction (vkvg_context* ctx, vkvg_direction_t direction){ diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 6c87485..592bc1f 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -89,8 +89,8 @@ typedef struct _vkvg_context_save_t{ FT_F26Dot6 selectedCharSize; /* Font size*/ char* selectedFontName; - _vkvg_font_t selectedFont; //hold current face and size before cache addition - _vkvg_font_t* currentFont; //font ready for lookup + _vkvg_font_identity_t selectedFont; //hold current face and size before cache addition + _vkvg_font_identity_t* currentFont; //font ready for lookup vkvg_direction_t textDirection; push_constants pushConsts; VkvgPattern pattern; @@ -169,7 +169,8 @@ typedef struct _vkvg_context_t { FT_F26Dot6 selectedCharSize; /* Font size*/ char* selectedFontName; //_vkvg_font_t selectedFont; //hold current face and size before cache addition - _vkvg_font_t* currentFont; //font pointing to cached fonts ready for lookup + _vkvg_font_identity_t* currentFont; //font pointing to cached fonts identity + _vkvg_font_t* currentFontSize; //font structure by size ready for lookup vkvg_direction_t textDirection; push_constants pushConsts; diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 4ac2fe2..96fed15 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -167,17 +167,19 @@ void _destroy_font_cache (VkvgDevice dev){ free (cache->hostBuff); for (int i = 0; i < cache->fontsCount; ++i) { - _vkvg_font_t* f = &cache->fonts[i]; + _vkvg_font_identity_t* f = &cache->fonts[i]; + for (uint32_t j = 0; j < f->sizeCount; j++) { + _vkvg_font_t* s = &f->sizes[j]; + for (int g = 0; g < s->face->num_glyphs; ++g) { + if (s->charLookup[g]!=NULL) + free(s->charLookup[g]); + } + FT_Done_Face (s->face); + hb_font_destroy (s->hb_font); - for (int g = 0; g < f->face->num_glyphs; ++g) { - if (f->charLookup[g]!=NULL) - free(f->charLookup[g]); + free(s->charLookup); } - - FT_Done_Face (f->face); - hb_font_destroy (f->hb_font); - - free(f->charLookup); + free (f->sizes); free(f->fontFile); for (uint32_t j = 0; j < f->fcNamesCount; j++) free (f->fcNames[j]); @@ -325,9 +327,13 @@ void _select_font_path (VkvgContext ctx, const char* fontFile){ } //select current font for context void _select_font_face (VkvgContext ctx, const char* name){ + if (strcmp(ctx->selectedFontName, name) == 0) + return; strcpy (ctx->selectedFontName, name); + ctx->currentFont = NULL; + ctx->currentFontSize = NULL; } -void _font_add_fc_name (_vkvg_font_t* font, const char* fcname) { +void _font_add_fc_name (_vkvg_font_identity_t* font, const char* fcname) { if (++font->fcNamesCount == 1) font->fcNames = (char**) malloc (sizeof(char*)); else @@ -335,92 +341,110 @@ void _font_add_fc_name (_vkvg_font_t* font, const char* fcname) { font->fcNames[font->fcNamesCount-1] = (char*)calloc(FONT_NAME_MAX_SIZE, sizeof (char)); strcpy (font->fcNames[font->fcNamesCount-1], fcname); } +_vkvg_font_t* _find_or_create_font_size (VkvgContext ctx, _vkvg_font_identity_t* font, FT_F26Dot6 charSize) { + for (uint32_t i = 0; i < font->sizeCount; ++i) { + if (font->sizes[i].charSize == charSize) + return &font->sizes[i]; + } + //if not found, create a new font size structure + _font_cache_t* cache = (_font_cache_t*)ctx->pSurf->dev->fontCache; + VkvgDevice dev = ctx->pSurf->dev; -//try to find font in cache with same font file path and font size as selected in context. -_vkvg_font_t* _tryFindVkvgFont (VkvgContext ctx){ + if (++font->sizeCount == 1) + font->sizes = (_vkvg_font_t*) malloc (sizeof(_vkvg_font_t)); + else + font->sizes = (_vkvg_font_t*) realloc (font->sizes, font->sizeCount * sizeof(_vkvg_font_t)); + _vkvg_font_t newSize = {.charSize = charSize}; + + FT_CHECK_RESULT(FT_New_Face(cache->library, font->fontFile, 0, &newSize.face)); + FT_CHECK_RESULT(FT_Set_Char_Size(newSize.face, 0, newSize.charSize, dev->hdpi, dev->vdpi )); + newSize.hb_font = hb_ft_font_create(newSize.face, NULL); + newSize.charLookup = (_char_ref**)calloc(newSize.face->num_glyphs,sizeof(_char_ref*)); + + //nf.curLine.height = (nf.face->bbox.xMax - nf.face->bbox.xMin) >> 6; + if (FT_IS_SCALABLE(newSize.face)) + newSize.curLine.height = FT_MulFix(newSize.face->height, newSize.face->size->metrics.y_scale) >> 6;// nf.face->size->metrics.height >> 6; + else + newSize.curLine.height = newSize.face->height >> 6; + + _init_next_line_in_tex_cache (dev, &newSize); + + font->sizes[font->sizeCount-1] = newSize; + return &font->sizes[font->sizeCount-1]; +} + +//try find font already resolved with fontconfig by font name +_vkvg_font_identity_t* _tryFindFontByName (VkvgContext ctx, const char* fontName){ _font_cache_t* cache = (_font_cache_t*)ctx->pSurf->dev->fontCache; - //try find font already resolved with fontconfig by font name for (int i = 0; i < cache->fontsCount; ++i) { for (uint32_t j = 0; j < cache->fonts[i].fcNamesCount; j++) { - if (strcmp (cache->fonts[i].fcNames[j], ctx->selectedFontName) == 0 && cache->fonts[i].charSize == ctx->selectedCharSize) + if (strcmp (cache->fonts[i].fcNames[j], fontName) == 0) return &cache->fonts[i]; } } - //try resolve name with fontconfig + return NULL; +} +_vkvg_font_identity_t* _tryResolveFontNameWithFontConfig (VkvgContext ctx, const char* fontName) { + _vkvg_font_identity_t* resolvedFont = NULL; + _font_cache_t* cache = (_font_cache_t*)ctx->pSurf->dev->fontCache; FcPattern* pat = FcNameParse((const FcChar8*)ctx->selectedFontName); FcConfigSubstitute(cache->config, pat, FcMatchPattern); FcDefaultSubstitute(pat); - // find the font FcResult result; FcPattern* font = FcFontMatch(cache->config, pat, &result); - if (font) - { - char* fontFile; + char* fontFile; + if (font) { if (FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile) == FcResultMatch) { //try find font in cache by path for (int i = 0; i < cache->fontsCount; ++i) { - if (strcmp (cache->fonts[i].fontFile, fontFile) == 0 && cache->fonts[i].charSize == ctx->selectedCharSize) { + if (strcmp (cache->fonts[i].fontFile, fontFile) == 0) { _font_add_fc_name (&cache->fonts[i], ctx->selectedFontName); - FcPatternDestroy(pat); - FcPatternDestroy(font); - return &cache->fonts[i]; + resolvedFont = &cache->fonts[i]; + break;; } } - //if not found, create a new vkvg_font - cache->fontsCount++; - - if (cache->fontsCount == 1) - cache->fonts = (_vkvg_font_t*) malloc (cache->fontsCount * sizeof(_vkvg_font_t)); - else - cache->fonts = (_vkvg_font_t*) realloc (cache->fonts, cache->fontsCount * sizeof(_vkvg_font_t)); - - _vkvg_font_t* nf = &cache->fonts[cache->fontsCount-1]; - memset (nf, 0, sizeof(_vkvg_font_t)); - - nf->charSize = ctx->selectedCharSize; - nf->fontFile = (char*)malloc (FONT_FILE_NAME_MAX_SIZE * sizeof(char)); - memcpy (nf->fontFile, fontFile, FONT_FILE_NAME_MAX_SIZE); - _font_add_fc_name (nf, ctx->selectedFontName); - FcPatternDestroy(pat); - FcPatternDestroy(font); - return nf; + if (!resolvedFont) { + //if not found, create a new vkvg_font + cache->fontsCount++; + + if (cache->fontsCount == 1) + cache->fonts = (_vkvg_font_identity_t*) malloc (cache->fontsCount * sizeof(_vkvg_font_identity_t)); + else + cache->fonts = (_vkvg_font_identity_t*) realloc (cache->fonts, cache->fontsCount * sizeof(_vkvg_font_identity_t)); + + _vkvg_font_identity_t nf = {0}; + + nf.fontFile = (char*)malloc (FONT_FILE_NAME_MAX_SIZE * sizeof(char)); + memcpy (nf.fontFile, fontFile, FONT_FILE_NAME_MAX_SIZE); + _font_add_fc_name (&nf, ctx->selectedFontName); + + cache->fonts[cache->fontsCount-1] = nf; + resolvedFont = &cache->fonts[cache->fontsCount-1]; + } } } FcPatternDestroy(pat); FcPatternDestroy(font); + return resolvedFont; +} - return NULL; +//try to find font in cache with same font file path and font size as selected in context. +_vkvg_font_identity_t* _find_or_create_font (VkvgContext ctx){ + _vkvg_font_identity_t* resolvedFont = _tryFindFontByName(ctx, ctx->selectedFontName); + if (!resolvedFont) + resolvedFont = _tryResolveFontNameWithFontConfig(ctx, ctx->selectedFontName); + return resolvedFont; } //try to find corresponding font in cache (defined by context selectedFont) and create a new font entry if not found. void _update_current_font (VkvgContext ctx) { - VkvgDevice dev = ctx->pSurf->dev; - if (ctx->currentFont == NULL){ if (ctx->selectedFontName[0] == 0) _select_font_face (ctx, "sans"); - ctx->currentFont = _tryFindVkvgFont (ctx); - - if (ctx->currentFont->face == NULL){ - //create new font in cache - _font_cache_t* cache = dev->fontCache; - - - FT_CHECK_RESULT(FT_New_Face(cache->library, ctx->currentFont->fontFile, 0, &ctx->currentFont->face)); - FT_CHECK_RESULT(FT_Set_Char_Size(ctx->currentFont->face, 0, ctx->currentFont->charSize, dev->hdpi, dev->vdpi )); - ctx->currentFont->hb_font = hb_ft_font_create(ctx->currentFont->face, NULL); - ctx->currentFont->charLookup = (_char_ref**)calloc(ctx->currentFont->face->num_glyphs,sizeof(_char_ref*)); - - //nf.curLine.height = (nf.face->bbox.xMax - nf.face->bbox.xMin) >> 6; - if (FT_IS_SCALABLE(ctx->currentFont->face)) - ctx->currentFont->curLine.height = FT_MulFix(ctx->currentFont->face->height, ctx->currentFont->face->size->metrics.y_scale) >> 6;// nf.face->size->metrics.height >> 6; - else - ctx->currentFont->curLine.height = ctx->currentFont->face->height >> 6; - - _init_next_line_in_tex_cache (dev, ctx->currentFont); - } - } + ctx->currentFont = _find_or_create_font (ctx); + ctx->currentFontSize = _find_or_create_font_size (ctx, ctx->currentFont, ctx->selectedCharSize); + } } //Get harfBuzz buffer for provided text. hb_buffer_t * _get_hb_buffer (_vkvg_font_t* font, const char* text) { @@ -448,11 +472,13 @@ void _font_extents (VkvgContext ctx, vkvg_font_extents_t *extents) { return; //TODO: ensure correct metrics are returned (scalled/unscalled, etc..) - FT_BBox* bbox = &ctx->currentFont->face->bbox; - FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics; - extents->ascent = (float)(FT_MulFix(ctx->currentFont->face->ascender, metrics->y_scale) >> 6);//metrics->ascender >> 6; - extents->descent= -(float)(FT_MulFix(ctx->currentFont->face->descender, metrics->y_scale) >> 6);//metrics->descender >> 6; - extents->height = (float)(FT_MulFix(ctx->currentFont->face->height, metrics->y_scale) >> 6);//metrics->height >> 6; + _vkvg_font_t* font = ctx->currentFontSize; + + FT_BBox* bbox = &font->face->bbox; + FT_Size_Metrics* metrics = &font->face->size->metrics; + extents->ascent = (float)(FT_MulFix(font->face->ascender, metrics->y_scale) >> 6);//metrics->ascender >> 6; + extents->descent= -(float)(FT_MulFix(font->face->descender, metrics->y_scale) >> 6);//metrics->descender >> 6; + extents->height = (float)(FT_MulFix(font->face->height, metrics->y_scale) >> 6);//metrics->height >> 6; extents->max_x_advance = (float)(bbox->xMax >> 6); extents->max_y_advance = (float)(bbox->yMax >> 6); } @@ -477,8 +503,8 @@ void _create_text_run (VkvgContext ctx, const char* text, VkvgText textRun) { if (ctx->status) return; - textRun->hbBuf = _get_hb_buffer (ctx->currentFont, text); - textRun->font = ctx->currentFont; + textRun->hbBuf = _get_hb_buffer (ctx->currentFontSize, text); + textRun->font = ctx->currentFontSize; textRun->dev = ctx->pSurf->dev; textRun->glyph_pos = hb_buffer_get_glyph_positions (textRun->hbBuf, &textRun->glyph_count); @@ -487,13 +513,13 @@ void _create_text_run (VkvgContext ctx, const char* text, VkvgText textRun) { for (uint32_t i=0; i < textRun->glyph_count; ++i) string_width_in_pixels += textRun->glyph_pos[i].x_advance >> 6; - FT_Size_Metrics* metrics = &ctx->currentFont->face->size->metrics; + FT_Size_Metrics* metrics = &ctx->currentFontSize->face->size->metrics; textRun->extents.x_advance = (float)string_width_in_pixels; textRun->extents.y_advance = (float)(textRun->glyph_pos[textRun->glyph_count-1].y_advance >> 6); textRun->extents.x_bearing = -(float)(textRun->glyph_pos[0].x_offset >> 6); textRun->extents.y_bearing = -(float)(textRun->glyph_pos[0].y_offset >> 6); - textRun->extents.height = (float)(FT_MulFix(ctx->currentFont->face->height, metrics->y_scale) >> 6);// (metrics->ascender + metrics->descender) >> 6; + textRun->extents.height = (float)(FT_MulFix(ctx->currentFontSize->face->height, metrics->y_scale) >> 6);// (metrics->ascender + metrics->descender) >> 6; textRun->extents.width = textRun->extents.x_advance; } void _destroy_text_run (VkvgText textRun) { diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index 11f9434..ce06786 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -71,18 +71,24 @@ typedef struct { int penY; /* Current Y in cache for next char addition */ int height; /* Height of current line pointed by this structure */ }_tex_ref_t; -// Loaded font structure, holds informations for glyphes upload in cache and the lookup table of characters. +// Loaded font structure, one per size, holds informations for glyphes upload in cache and the lookup table of characters. typedef struct { - char** fcNames; /* Resolved Input names to this font by fontConfig */ - uint32_t fcNamesCount; /* Count of resolved names by fontConfig */ - char* fontFile; /* Font file full path*/ FT_F26Dot6 charSize; /* Font size*/ - hb_font_t* hb_font; /* HarfBuzz font instance*/ FT_Face face; /* FreeType face*/ + hb_font_t* hb_font; /* HarfBuzz font instance*/ _char_ref** charLookup; /* Lookup table of characteres in cache, if not found, upload is queued*/ _tex_ref_t curLine; /* tex coord where to add new char bmp's */ }_vkvg_font_t; +/* Font identification structure */ +typedef struct { + char** fcNames; /* Resolved Input names to this font by fontConfig */ + uint32_t fcNamesCount; /* Count of resolved names by fontConfig */ + char* fontFile; /* Font file full path*/ + uint32_t sizeCount; /* available font size loaded */ + _vkvg_font_t* sizes /* loaded font size array */ +}_vkvg_font_identity_t; + // Font cache global structure, entry point for all font related operations. typedef struct { FT_Library library; /* FreeType library*/ @@ -100,17 +106,17 @@ typedef struct { int* pensY; /* array of current y pen positions for each texture in cache 2d array */ VkFence uploadFence; /* Signaled when upload is finished */ - _vkvg_font_t* fonts; /* Loaded fonts structure array */ + _vkvg_font_identity_t* fonts; /* Loaded fonts structure array */ int32_t fontsCount; /* Loaded fonts array count*/ }_font_cache_t; // Precompute everything necessary to draw one line of text, usefull to draw the same text multiple times. typedef struct _vkvg_text_run_t { - hb_buffer_t* hbBuf; /* HarfBuzz buffer of text */ - _vkvg_font_t* font; /* vkvg font structure pointer */ - VkvgDevice dev; /* vkvg device associated with this text run */ + hb_buffer_t* hbBuf; /* HarfBuzz buffer of text */ + _vkvg_font_t* font; /* vkvg font structure pointer */ + VkvgDevice dev; /* vkvg device associated with this text run */ vkvg_text_extents_t extents; /* store computed text extends */ - const char* text; /* utf8 char array of text*/ - unsigned int glyph_count;/* Total glyph count */ + const char* text; /* utf8 char array of text*/ + unsigned int glyph_count;/* Total glyph count */ hb_glyph_position_t *glyph_pos; /* HarfBuzz computed glyph positions array */ } vkvg_text_run_t; //Create font cache. -- 2.47.3