diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-27 09:00:37 +0100 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-27 09:00:37 +0100 |
| commit | 7ff0e5d3085aa830f7fe3b32fb5ce1d9c265ae04 (patch) | |
| tree | 6ad6c1f12c9af2d2d5893670f7ea292ae1dfbe5c | |
| parent | b51886c9fe9b591ff7f373c0719fbc51cf0a29e6 (diff) | |
vkvg_font_size_t holding pixel sized font, lightweight vkvg_font_t with only ptSizedev
| -rw-r--r-- | gunit_tests/textDraw.cpp | 12 | ||||
| -rw-r--r-- | include/vkvg.h | 6 | ||||
| -rw-r--r-- | samples/tests/text.cpp | 28 | ||||
| -rw-r--r-- | src/svg/svg-parse.c | 2 | ||||
| -rw-r--r-- | src/vkvg_context.c | 10 | ||||
| -rw-r--r-- | src/vkvg_device.c | 1 | ||||
| -rw-r--r-- | src/vkvg_device_internal.c | 2 | ||||
| -rw-r--r-- | src/vkvg_fonts.c | 306 | ||||
| -rw-r--r-- | src/vkvg_fonts.h | 61 | ||||
| -rw-r--r-- | tests/fonts/allfont.c | 4 | ||||
| -rw-r--r-- | tests/fonts/fontquery.c | 4 | ||||
| -rw-r--r-- | tests/text.c | 14 |
12 files changed, 270 insertions, 180 deletions
diff --git a/gunit_tests/textDraw.cpp b/gunit_tests/textDraw.cpp index a226a99..bf0ce89 100644 --- a/gunit_tests/textDraw.cpp +++ b/gunit_tests/textDraw.cpp @@ -14,15 +14,15 @@ class TextDrawTest : public DrawTestBase { } }; TEST_F(TextDrawTest, References) { - VkvgFont font = vkvg_font_create(surf, "sans", 12); + VkvgFont font = vkvg_font_create(dev, "sans", 12); EXPECT_EQ(VKVG_STATUS_SUCCESS, vkvg_font_status(font)); vkvg_font_destroy(font); - font = vkvg_font_create(surf, "Sans", 12); + font = vkvg_font_create(dev, "Sans", 12); EXPECT_EQ(VKVG_STATUS_SUCCESS, vkvg_font_status(font)); vkvg_font_destroy(font); - font = vkvg_font_create(surf, "noto sans jp", 12); + font = vkvg_font_create(dev, "noto sans jp", 12); EXPECT_EQ(VKVG_STATUS_SUCCESS, vkvg_font_status(font)); vkvg_font_destroy(font); @@ -55,7 +55,7 @@ TEST_F(TextDrawTest, ShowText) { VkvgContext ctx = vkvg_create(surf); vkvg_paint(ctx); - VkvgFont font = vkvg_font_create(surf, "sans", 30); + VkvgFont font = vkvg_font_create(dev, "sans", 30); vkvg_set_font(ctx, font); vkvg_font_extents_t fe = {0}; vkvg_font_extents(ctx, &fe); @@ -67,7 +67,7 @@ TEST_F(TextDrawTest, ShowText) { vkvg_font_destroy(font); - font = vkvg_font_create(surf, "noto sans jp", 30); + font = vkvg_font_create(dev, "noto sans jp", 30); vkvg_set_font(ctx, font); vkvg_move_to(ctx, 40, penY); vkvg_show_text(ctx, "Galvanized by the quartz, The white rabbit just jumped on the red fox for the sake of the crows"); @@ -86,7 +86,7 @@ TEST_F(TextDrawTest, ShowText) { vkvg_font_destroy(font); vkvg_set_text_direction(ctx, VKVG_HORIZONTAL); - font = vkvg_font_create(surf, "Roboto:bold", 30); + font = vkvg_font_create(dev, "Roboto:bold", 30); vkvg_set_font(ctx, font); vkvg_move_to(ctx, 40, penY); vkvg_show_text(ctx, "Galvanized by the quartz, The white rabbit just jumped on the red fox for the sake of the crows"); diff --git a/include/vkvg.h b/include/vkvg.h index 48fca2d..33154b8 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -338,16 +338,16 @@ typedef struct _vkvg_font_t* VkvgFont; * @param pointSize The font size in point unit, 1/72 of an inch. * @return A new VkvgFont or null if an error occured. */ -vkvg_public VkvgFont vkvg_font_create (VkvgSurface surf, const char* queryString, float pointSize); +vkvg_public VkvgFont vkvg_font_create (VkvgDevice dev, const char* queryString, float pointSize); /** * @brief Create a new @ref VkvgFont from the provided font file, face index and size. - * @param surf VkvgDevice holding the font cache. + * @param dev VkvgDevice holding the font cache. * @param fontFilePath a valid font file path. * @param faceIndex Usually 0, except for variable fonts or font file with multiple faces. * @param pointSize The font size in point unit, 1/72 of an inch. * @return */ -vkvg_public VkvgFont vkvg_font_create_from_file (VkvgSurface surf, const char* fontFilePath, int faceIndex, float pointSize); +vkvg_public VkvgFont vkvg_font_create_from_file (VkvgDevice dev, const char* fontFilePath, int faceIndex, float pointSize); /** * @brief Get underlying font face object pointer, if freetype is enable, the FT_Face will be returned. * @param font a valid VkvgFont. diff --git a/samples/tests/text.cpp b/samples/tests/text.cpp index 4eac831..a98f56f 100644 --- a/samples/tests/text.cpp +++ b/samples/tests/text.cpp @@ -272,7 +272,7 @@ TEST(text_random_font_and_size) { TEST(text) { VkvgContext ctx = vkvg_create(test->surf); vkvg_paint(ctx); - VkvgFont font = vkvg_font_create(test->surf, "times", 30); + VkvgFont font = vkvg_font_create(test->device, "times", 30); vkvg_set_font(ctx, font); vkvg_font_extents_t fe = {0}; vkvg_font_extents(ctx, &fe); @@ -284,7 +284,7 @@ TEST(text) { vkvg_font_destroy(font); - font = vkvg_font_create(test->surf, "noto sans jp", 30); + font = vkvg_font_create(test->device, "noto sans jp", 30); vkvg_set_font(ctx, font); vkvg_move_to(ctx, 40, penY); vkvg_show_text(ctx, "Galvanized by the quartz, The white rabbit just jumped on the red fox for the sake of the crows"); @@ -303,7 +303,7 @@ TEST(text) { vkvg_font_destroy(font); vkvg_set_text_direction(ctx, VKVG_HORIZONTAL); - font = vkvg_font_create(test->surf, "Roboto:bold", 30); + font = vkvg_font_create(test->device, "Roboto:bold", 30); vkvg_set_font(ctx, font); vkvg_move_to(ctx, 40, penY); vkvg_show_text(ctx, "Galvanized by the quartz, The white rabbit just jumped on the red fox for the sake of the crows"); @@ -321,8 +321,28 @@ TEST(text_proto_sinaitic) { vkvg_paint(ctx); vkvg_set_source_rgb(ctx, 1, 1, 1); - vkvg_load_font_from_path(ctx, "data/Proto-Sinaitic15.ttf", 30); + vkvg_load_font_from_path(ctx, GET_PATH("Proto-Sinaitic15.ttf"), 30); print_boxed(ctx, "hwhy", 100, 150, 60); vkvg_destroy(ctx); } + +TEST(text_scalled_up) { + VkvgContext ctx = vkvg_create(test->surf); + vkvg_clear(ctx); + + vkvg_set_source_rgb(ctx, 0, 0, 0); + vkvg_paint(ctx); + vkvg_set_source_rgb(ctx, 1, 1, 1); + + VkvgFont font = vkvg_font_create(test->device, "sans", 12); + + vkvg_set_font(ctx,font); + vkvg_move_to(ctx, 2, 15); + vkvg_scale(ctx, 10,10); + vkvg_show_text(ctx, txt); + + vkvg_font_destroy(font); + vkvg_destroy(ctx); +} + diff --git a/src/svg/svg-parse.c b/src/svg/svg-parse.c index 6500fe4..748a397 100644 --- a/src/svg/svg-parse.c +++ b/src/svg/svg-parse.c @@ -1570,7 +1570,7 @@ void process_element(svg_context *const svg, SvgPresentationAttributes *const at if (attribs->font_family_len > 0) { char fam[1024]; sprintf(fam, "%.*s", attribs->font_family_len, attribs->font_family); - font = vkvg_font_create(svg->surf, fam, attribs->font_size_pt); + font = vkvg_font_create(svg->dev, fam, attribs->font_size_pt); vkvg_set_font(svg->ctx, font); vkvg_font_destroy(font); } diff --git a/src/vkvg_context.c b/src/vkvg_context.c index 1711fbe..a9f470f 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -1238,13 +1238,13 @@ void vkvg_select_font_face(VkvgContext ctx, const char* name) { if (vkvg_status(ctx)) return; RECORD(ctx, VKVG_CMD_SET_FONT_FACE, name); - vkvg_set_font(ctx, vkvg_font_create(ctx->pSurf, name, 12)); + vkvg_set_font(ctx, vkvg_font_create(ctx->dev, name, 12)); } void vkvg_load_font_from_path(VkvgContext ctx, const char* path, uint32_t size) { if (vkvg_status(ctx)) return; RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); - vkvg_set_font(ctx, vkvg_font_create_from_file(ctx->pSurf, path, 0, size)); + vkvg_set_font(ctx, vkvg_font_create_from_file(ctx->dev, path, 0, size)); } void vkvg_set_font_size(VkvgContext ctx, uint32_t size) { if (vkvg_status(ctx)) @@ -1276,7 +1276,7 @@ void vkvg_text_extents(VkvgContext ctx, const char* text, vkvg_text_extents_t* e void vkvg_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) { if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont)) return; - _font_cache_font_extents(ctx->currentFont, extents); + _font_cache_font_extents(ctx, extents); } void vkvg_show_text(VkvgContext ctx, const char* text) { if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont)) @@ -1295,7 +1295,7 @@ VkvgText vkvg_text_create(VkvgContext ctx, const char* text) { LOGE("vkvg_text_create error, no memory\n"); return NULL; } - text_run_init(tr, ctx->currentFont, ctx->textDirection, text, -1); + text_run_init(tr, ctx, text, -1); return tr; } VkvgText vkvg_text_create_with_length(VkvgContext ctx, const char* text, uint32_t length) { @@ -1306,7 +1306,7 @@ VkvgText vkvg_text_create_with_length(VkvgContext ctx, const char* text, uint32_ LOGE("vkvg_text_create error, no memory\n"); return NULL; } - text_run_init(tr, ctx->currentFont, ctx->textDirection, text, length); + text_run_init(tr, ctx, text, length); return tr; } uint32_t vkvg_text_get_glyph_count(VkvgText textRun) { diff --git a/src/vkvg_device.c b/src/vkvg_device.c index 2a1535a..60b7e7d 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -299,6 +299,7 @@ VkvgDevice vkvg_device_create(vkvg_device_create_info_t* info) { enabledExtsCount = 0; if (vkvg_get_required_device_extensions(pi->phy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS) { + LOGE("CREATE Device failed, vkvg_get_required_device_extensions failure.\n"); dev->status = VKVG_STATUS_DEVICE_ERROR; vkh_app_free_phyinfos(phyCount, phys); vkh_app_destroy(app); diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c index 0697f95..6c6d160 100644 --- a/src/vkvg_device_internal.c +++ b/src/vkvg_device_internal.c @@ -243,7 +243,7 @@ void _device_check_best_image_tiling(VkvgDevice dev, VkFormat format) { } if (dev->pngStagFormat == VK_FORMAT_UNDEFINED) - LOG(VKVG_LOG_DEBUG, "vkvg create device warning: no suitable image format for png write\n"); + LOGW("vkvg create device warning: no suitable image format for png write\n"); dev->stencilFormat = VK_FORMAT_UNDEFINED; dev->stencilAspectFlag = VK_IMAGE_ASPECT_STENCIL_BIT; diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 2e3dfa3..e8eb465 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -51,15 +51,26 @@ do { \ } #define FT_CHECK_RES(f) \ { \ - FT_Error res = (f); \ - if (res) { \ - char tmp[1024]; \ - ft_face_flags_to_string (face->face->face_flags, tmp, 1024); \ - LOGE("FreeType error is 0x%x in %s at line %d, flags: %s\n", res, __FILE__, __LINE__, tmp);\ - free(font); \ - return (VkvgFont)&_vkvg_status_null_pointer; \ + FT_Error res = (f); \ + if (res) { \ + char tmp[1024]; \ + ft_face_flags_to_string (face->face->face_flags, tmp, 1024); \ + LOGE("FreeType error is 0x%x in %s at line %d, flags: %s\n", res, __FILE__, __LINE__, tmp);\ + free(font); \ + return (VkvgFont)&_vkvg_status_null_pointer; \ } \ } +#define FT_CHECK_SIZE(f) \ +{ \ + FT_Error res = (f); \ + if (res) { \ + char tmp[1024]; \ + ft_face_flags_to_string (face->face->face_flags, tmp, 1024); \ + LOGE("FreeType error is 0x%x in %s at line %d, flags: %s\n", res, __FILE__, __LINE__, tmp);\ + free(fntsize); \ + return false; \ + } \ +} #else #define STBTT_assert(x) ((void)0) #define STB_TRUETYPE_IMPLEMENTATION @@ -95,6 +106,7 @@ void _fonts_cache_update_font_descriptor_set (VkvgDevice dev) { vkUpdateDescriptorSets(dev->vkDev, 1, &writeDescriptorSet, 0, NULL); } void _fonts_cache_create(VkvgDevice dev, const char* fontDirs) { + LOG(VKVG_LOG_FONT, "Font cache create\n"); font_cache_t* cache = (font_cache_t*)calloc(1, sizeof(font_cache_t)); dev->fontCache = cache; @@ -233,7 +245,8 @@ void _fonts_cache_create(VkvgDevice dev, const char* fontDirs) { #if defined(DEBUG) && defined(VKVG_DBG_UTILS) vkh_device_set_object_name(dev->vkhDev, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)cache->descriptorPool, "Font cache Descriptor Pool"); - vkh_device_set_object_name(dev->vkhDev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)cache->dsFont, "Cache DescSet FONT"); + vkh_device_set_object_name(dev->vkhDev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)cache->dsFont, "Font Cache DescSet"); + vkh_device_set_object_name(dev->vkhDev, VK_OBJECT_TYPE_BUFFER, (uint64_t)cache->buff.buffer, "Font Cache Staging buff"); #endif } void _font_buffer_destroy (font_cache_t* cache, FontBuffer fontBuffer) { @@ -243,10 +256,10 @@ void _font_buffer_destroy (font_cache_t* cache, FontBuffer fontBuffer) { array_del_FontBuffer(&cache->fontBuffers, fontBuffer); free(fontBuffer); } -void _font_face_destroy (VkvgFont font) { +void _font_face_destroy (FontSize font) { FontFace face = font->face; LOG(VKVG_LOG_FONT, "FontFace destroy: %s\n", get_face_family_name(face)); - array_destroy_VkvgFont(&face->sizes); + array_destroy_FontSize(&face->sizes); array_destroy_uint64_t(&face->queryHashes); array_del_FontFace(&face->fontBuffer->faces, face); @@ -264,7 +277,31 @@ void _font_face_destroy (VkvgFont font) { } free(face); } +void _font_size_destroy (FontSize font) { +#ifdef VKVG_USE_FREETYPE + FT_Done_Size(font->ftSize); + if (font->coords) + free(font->coords); +#endif + + for (int i = 0; i < font->texLines.count; ++i) { + LOG(VKVG_LOG_FONT, "\treleased line %d of page %d\n", i, font->texLines.elements[i]->pageIdx); + font->texLines.elements[i]->released = true; + } + array_destroy_TexRef(&font->texLines); + + array_del_FontSize(&font->face->sizes , font); + + if (font->face->sizes.count == 0) + _font_face_destroy(font); + free(font->charLookup); + + vkvg_device_destroy(font->dev); + free(font); + font = NULL; +} void _font_cache_destroy(VkvgDevice dev) { + LOG(VKVG_LOG_FONT, "Font cache destroy\n"); font_cache_t* cache = (font_cache_t*)dev->fontCache; free(cache->hostBuff); @@ -273,10 +310,10 @@ void _font_cache_destroy(VkvgDevice dev) { for (int i = 0; i < cache->fontBuffers.count; ++i) { FontFace* faces = buffs[i]->faces.elements; for (int j = 0; j < buffs[i]->faces.count; ++j) { - VkvgFont *fonts = faces[j]->sizes.elements; + FontSize *fonts = faces[j]->sizes.elements; for (int k = 0; k < faces[j]->sizes.count; ++k) { //while (vkvg_font_get_reference_count(fonts[k]) > 0) - vkvg_font_destroy(fonts[k]); + _font_size_destroy (fonts[k]); } } } @@ -383,7 +420,7 @@ void _increase_font_tex_array(VkvgDevice dev) { } // flush font stagging buffer to cache texture array // Trigger stagging buffer to be uploaded in font cache. Groupping upload improve performances. -void _flush_chars_to_tex(VkvgFont f) { +void _flush_chars_to_tex(FontSize f) { font_cache_t* cache = f->dev->fontCache; if (cache->stagingX == 0) // no char in stagging buff to flush return; @@ -428,7 +465,7 @@ void _flush_chars_to_tex(VkvgFont f) { } /// Start a new line in font cache, increase texture layer count if needed. -void _init_next_line_in_tex_cache(VkvgFont f) { +void _init_next_line_in_tex_cache(FontSize f) { font_cache_t* cache = f->dev->fontCache; for (int i = 0; i < cache->texPages.count; ++i) { @@ -478,7 +515,7 @@ void _init_next_line_in_tex_cache(VkvgFont f) { UNLOCK_FONTCACHE(ctx->dev) }*/ // create a new char entry and put glyph in stagging buffer, ready for upload. -glyph_ref _put_glyph_in_cache(VkvgDevice dev, VkvgFont font, uint32_t gindex) { +glyph_ref _put_glyph_in_cache(VkvgDevice dev, FontSize font, uint32_t gindex) { #ifdef VKVG_USE_FREETYPE #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); @@ -493,7 +530,7 @@ glyph_ref _put_glyph_in_cache(VkvgDevice dev, VkvgFont font, uint32_t gindex) { res = FT_Load_Glyph(font->face->face, 0, FT_LOAD_RENDER); if (res) { LOGE("Fatal: FT_Load_Glyph error 0x%x for default glyph 0\n", res); - font->status = VKVG_STATUS_INVALID_FONT; + //font->status = VKVG_STATUS_INVALID_FONT; return (glyph_ref) {0}; } } @@ -563,7 +600,7 @@ glyph_ref _put_glyph_in_cache(VkvgDevice dev, VkvgFont font, uint32_t gindex) { dev->fontCache->stagingX += bmpPixelWidth; return cr; } -vkvg_inline glyph_ref get_cached_glyph (VkvgDevice dev, VkvgFont font, uint32_t gIndex) { +vkvg_inline glyph_ref get_cached_glyph (VkvgDevice dev, FontSize font, uint32_t gIndex) { glyph_ref gr; if (vkvg_unlikely (gIndex > get_face_glyph_count(font->face))) { LOGW("glyph index out of bounds: idx:%d glyphsCount: %d\n", gIndex, get_face_glyph_count(font->face)); @@ -768,31 +805,112 @@ exit_failed: #endif return false; } -bool try_get_font_size (FontFace face, uint32_t pt26_6, signed long* coords, VkvgFont *font) { - *font = NULL; + +bool try_get_or_create_font_size (VkvgSurface surf, VkvgFont font) { + if (font->curSize != NULL) + return true; + FontFace face = font->face; + uint32_t pxSize = (font->ptSize * surf->vdpi + 2304) / 4608; + for (int i = 0; i < face->sizes.count; ++i) { - VkvgFont f = face->sizes.elements[i]; - if (f->charSize == pt26_6) { + FontSize f = face->sizes.elements[i]; + if (f->pxSize == pxSize) { #ifdef VKVG_USE_FREETYPE - if (coords) { + /*if (coords) { for (int axe = 0; axe < face->numAxis; ++axe) { if (f->coords[axe] != coords[axe]) return false; } free(coords);//coords matche, free new coords - } + }*/ #endif - *font = f; + font->curSize = f; return true; } } - return false; + + FontSize fntsize = (FontSize)calloc(1, sizeof(vkvg_font_size_t)); + if (!fntsize) { + LOGE("Create font size failed, no memory\n"); + return false; + } + fntsize->face = face; + VkvgDevice dev = surf->dev; + +#ifdef VKVG_USE_FREETYPE + if (dev->threadAware) + mtx_lock(&face->mutex); + /* if (face->numAxis && coords) + font->coords = coords;*/ + + if (!(face->face->face_flags & FT_FACE_FLAG_SCALABLE) || !(face->face->face_flags & FT_FACE_FLAG_SFNT)) { + char tmp[1024]; + ft_face_flags_to_string (face->face->face_flags, tmp, 1024); + LOGW("Unsuported font flags: %s\n", tmp); + if (dev->threadAware) + mtx_lock(&face->mutex); + free(fntsize); + return false; + } else { + char tmp[1024]; + ft_face_flags_to_string (face->face->face_flags, tmp, 1024); + LOG(VKVG_LOG_FONT, "loading %s\n\tflags: %s\n", face->face->family_name, tmp); + } + if (!face->sizes.size) + face->sizes = array_create_FontSize(5);//new face, + + FT_CHECK_SIZE(FT_New_Size (face->face, &fntsize->ftSize)); + FT_CHECK_SIZE(FT_Activate_Size(fntsize->ftSize)); + //TODO:handle fixed sizes + FT_CHECK_SIZE(FT_Set_Pixel_Sizes(face->face, 0, pxSize)); + + /*if (font->coords) { + FT_Set_Var_Design_Coordinates(face->face, font->face->numAxis, font->coords); + font->face->coords = font->coords; + }*/ +#ifdef VKVG_USE_HARFBUZZ + hb_font_t* hbf = face->hb_font; + hb_ft_font_changed(hbf); + hb_font_set_ppem(hbf, fntsize->ftSize->metrics.x_ppem, fntsize->ftSize->metrics.y_ppem); +#endif + + fntsize->charLookup = (glyph_ref*)calloc(face->face->num_glyphs, sizeof(glyph_ref)); + + if (FT_IS_SCALABLE(face->face)) + fntsize->height = face->face->size->metrics.height >> 6; + else + fntsize->height = face->face->height >> 6; + + fntsize->texLines = array_create_TexRef(2); + + if (dev->threadAware) + mtx_lock(&face->mutex); +#else + font->charSize = pointSize; + stbtt_GetFontVMetrics(&face->stbInfo, &font->ascent, &font->descent, &font->lineGap); + font->charLookup = (glyph_ref*)calloc(face->stbInfo.numGlyphs, sizeof(glyph_ref)); + font->scale = stbtt_ScaleForMappingEmToPixels(&face->stbInfo, font->charSize * surf->vdpi / 72.f); + font->height = roundf(font->scale * (font->ascent - font->descent + font->lineGap)); + font->ascent = roundf(font->scale * font->ascent); + font->descent = roundf(font->scale * font->descent); + font->lineGap = roundf(font->scale * font->lineGap); +#endif + array_add_FontSize(&face->sizes, fntsize); + + fntsize->dev = dev; + vkvg_device_reference(fntsize->dev); + + _init_next_line_in_tex_cache(fntsize); + + font->curSize = fntsize; + return true; } + #ifdef VKVG_USE_HARFBUZZ // Get harfBuzz buffer for provided text. hb_buffer_t* _get_hb_buffer(VkvgText textRun, const char* text, int length) { - VkvgFont font = textRun->font; + FontSize font = textRun->font; hb_buffer_t* buf = hb_buffer_create(); hb_buffer_add_utf8 (buf, text, length, 0, length); hb_buffer_guess_segment_properties (buf); @@ -808,7 +926,7 @@ hb_buffer_t* _get_hb_buffer(VkvgText textRun, const char* text, int length) { return buf; } #endif -void _font_lock_size (VkvgFont font) { +void _font_lock_size (FontSize font) { #ifdef VKVG_USE_FREETYPE FT_Face face = font->face->face; if (face->size != font->ftSize || font->face->coords != font->coords) { @@ -829,7 +947,10 @@ void _font_lock_size (VkvgFont font) { } // retrieve global font extends of context's current font as defined by FreeType -void _font_cache_font_extents(VkvgFont font, vkvg_font_extents_t* extents) { +void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) { + VkvgFont font = ctx->currentFont; + if (!try_get_or_create_font_size(ctx->pSurf, font)) + return; #ifdef VKVG_USE_FREETYPE FT_Face face = font->face->face; /*_font_lock_size(ctx, font); @@ -839,7 +960,7 @@ void _font_cache_font_extents(VkvgFont font, vkvg_font_extents_t* extents) { }*/ //FT_BBox* bbox = &face->bbox; //FT_Size_Metrics* metrics = &face->size->metrics; - FT_Size_Metrics* metrics = &font->ftSize->metrics; + FT_Size_Metrics* metrics = &font->curSize->ftSize->metrics; extents->ascent = (float)(FT_MulFix(face->ascender, metrics->y_scale) >> 6); // metrics->ascender >> 6; extents->descent = -(float)(FT_MulFix(face->descender, metrics->y_scale) >> 6); // metrics->descender >> 6; @@ -867,7 +988,7 @@ void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkv } vkvg_text_run_t tr = {0}; - text_run_init(&tr, ctx->currentFont, ctx->textDirection, text, length); + text_run_init(&tr, ctx, text, length); if (ctx->status) return; @@ -879,7 +1000,7 @@ void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkv // text is expected as utf8 encoded void _font_cache_show_text(VkvgContext ctx, const char* text) { vkvg_text_run_t tr = {0}; - text_run_init(&tr, ctx->currentFont, ctx->textDirection, text, -1); + text_run_init(&tr, ctx, text, -1); if (ctx->status) return; @@ -890,10 +1011,13 @@ void _font_cache_show_text(VkvgContext ctx, const char* text) { } // if length is < 0, text must be null terminated, else it contains glyph count -void text_run_init(VkvgText textRun, VkvgFont font, vkvg_direction_t textDirection, const char* text, int length) { - textRun->font = font; - textRun->textDirection = textDirection; - vkvg_font_reference (textRun->font); +void text_run_init(VkvgText textRun, VkvgContext ctx, const char* text, int length) { + VkvgFont font = ctx->currentFont; + + try_get_or_create_font_size(ctx->pSurf, font); + + textRun->font = font->curSize; + textRun->textDirection = ctx->textDirection; _font_lock_size(textRun->font); @@ -959,7 +1083,7 @@ void text_run_term(VkvgText textRun) { if (textRun->glyph_count > 0) free(textRun->glyphs); #endif - vkvg_font_destroy(textRun->font); + //vkvg_font_destroy(textRun->font); } void text_run_render(VkvgText tr, VkvgContext ctx) { @@ -970,7 +1094,7 @@ void text_run_render(VkvgText tr, VkvgContext ctx) { vkvg_glyph_info_t* glyph_info = tr->glyphs; glyph_count = tr->glyph_count; #endif - VkvgFont f = tr->font; + FontSize f = tr->font; Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; vec2 pen = {0, 0}; @@ -983,8 +1107,8 @@ void text_run_render(VkvgText tr, VkvgContext ctx) { for (uint32_t i = 0; i < glyph_count; ++i) { glyph_ref cr = get_cached_glyph(dev, f, glyph_info[i].codepoint); - if (vkvg_unlikely (f->status)) - break; + /*if (vkvg_unlikely (f->status)) + break;*/ vec2 p0 = {pen.x + cr.bmpDiff.x + (tr->glyphs[i].x_offset >> 6), pen.y - cr.bmpDiff.y + (tr->glyphs[i].y_offset >> 6)}; @@ -1056,7 +1180,9 @@ void* vkvg_font_get_face(VkvgFont font) { #endif } -VkvgFont _create_font_from_face (VkvgSurface surf, FontFace face, float pointSize, signed long* coords) { + + +VkvgFont _create_font_from_face (VkvgDevice dev, FontFace face, float pointSize, signed long* coords) { VkvgFont font = (VkvgFont)calloc(1, sizeof(vkvg_font_t)); if (!font) { LOGE("Create font failed, no memory\n"); @@ -1064,99 +1190,38 @@ VkvgFont _create_font_from_face (VkvgSurface surf, FontFace face, float pointSiz } font->face = face; - VkvgDevice dev = surf->dev; - -#ifdef VKVG_USE_FREETYPE - if (dev->threadAware) - mtx_lock(&font->face->mutex); - if (face->numAxis && coords) - font->coords = coords; - font->charSize = (uint32_t)(pointSize * 64.f);; - if (!(face->face->face_flags & FT_FACE_FLAG_SCALABLE) || !(face->face->face_flags & FT_FACE_FLAG_SFNT)) { - char tmp[1024]; - ft_face_flags_to_string (face->face->face_flags, tmp, 1024); - LOGW("Unsuported font flags: %s\n", tmp); - if (dev->threadAware) - mtx_lock(&font->face->mutex); - free(font); - return (VkvgFont)&_vkvg_status_null_pointer; - } else { - char tmp[1024]; - ft_face_flags_to_string (face->face->face_flags, tmp, 1024); - LOG(VKVG_LOG_FONT, "loading %s\n\tflags: %s\n", face->face->family_name, tmp); - } - if (!face->sizes.size) - face->sizes = array_create_VkvgFont(5);//new face, - - FT_CHECK_RES(FT_New_Size (face->face, &font->ftSize)); - FT_CHECK_RES(FT_Activate_Size(font->ftSize)); - //TODO:handle fixed sizes - FT_CHECK_RES(FT_Set_Char_Size(face->face, 0, font->charSize, surf->hdpi, surf->vdpi)); - if (font->coords) { - FT_Set_Var_Design_Coordinates(face->face, font->face->numAxis, font->coords); - font->face->coords = font->coords; - } -#ifdef VKVG_USE_HARFBUZZ - hb_font_t* hbf = font->face->hb_font; - hb_ft_font_changed(hbf); - hb_font_set_ppem(hbf, font->ftSize->metrics.x_ppem, font->ftSize->metrics.y_ppem); -#endif - - font->charLookup = (glyph_ref*)calloc(face->face->num_glyphs, sizeof(glyph_ref)); - - if (FT_IS_SCALABLE(face->face)) - font->height = face->face->size->metrics.height >> 6; - else - font->height = face->face->height >> 6; - - font->texLines = array_create_TexRef(2); - - if (dev->threadAware) - mtx_lock(&font->face->mutex); -#else - font->charSize = pointSize; - stbtt_GetFontVMetrics(&face->stbInfo, &font->ascent, &font->descent, &font->lineGap); - font->charLookup = (glyph_ref*)calloc(face->stbInfo.numGlyphs, sizeof(glyph_ref)); - font->scale = stbtt_ScaleForMappingEmToPixels(&face->stbInfo, font->charSize * surf->vdpi / 72.f); - font->height = roundf(font->scale * (font->ascent - font->descent + font->lineGap)); - font->ascent = roundf(font->scale * font->ascent); - font->descent = roundf(font->scale * font->descent); - font->lineGap = roundf(font->scale * font->lineGap); -#endif - array_add_VkvgFont(&face->sizes, font); - font->dev = dev; + font->ptSize = (uint32_t)(pointSize * 64.f); + vkvg_device_reference(font->dev); - _init_next_line_in_tex_cache(font); atomic_init(&font->references, 1); - return font; } -VkvgFont vkvg_font_create_from_file (VkvgSurface surf, const char* fontFilePath, int faceIndex, float pointSize) { +VkvgFont vkvg_font_create_from_file (VkvgDevice dev, const char* fontFilePath, int faceIndex, float pointSize) { FontFace face = NULL; - if (!try_create_font_face_from_path(surf->dev, fontFilePath, faceIndex, &face) || !face) { + if (!try_create_font_face_from_path(dev, fontFilePath, faceIndex, &face) || !face) { return NULL; } - return _create_font_from_face(surf, face, pointSize, NULL); + return _create_font_from_face(dev, face, pointSize, NULL); } -VkvgFont vkvg_font_create (VkvgSurface surf, const char* query, float pointSize) { - uint32_t pt26_6 = (uint32_t)(pointSize * 64.f); +VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) { + //uint32_t pt26_6 = (uint32_t)(pointSize * 64.f); VkvgFont font = NULL; FontFace face = NULL; signed long* coords = NULL; unsigned int numAxis = 0; - if (try_get_or_create_font_face_from_query(surf->dev, query, &face, &coords)) { - if (try_get_font_size(face, pt26_6, coords, &font)) { + if (try_get_or_create_font_face_from_query(dev, query, &face, &coords)) { + /*if (try_get_font_size(face, pt26_6, coords, &font)) { vkvg_font_reference(font); return font; - } + }*/ } if (!face) return NULL; - return _create_font_from_face(surf, face, pointSize, coords); + return _create_font_from_face(dev, face, pointSize, coords); } VkvgFont vkvg_font_reference(VkvgFont font) { if (!vkvg_font_status(font)) @@ -1175,23 +1240,6 @@ void vkvg_font_destroy(VkvgFont font) { if (atomic_fetch_sub_explicit(&font->references, 1, memory_order_acq_rel) != 1) return; LOG(VKVG_LOG_FONT, "Font destroy: %s\n", get_face_family_name(font->face)); -#ifdef VKVG_USE_FREETYPE - FT_Done_Size(font->ftSize); - if (font->coords) - free(font->coords); -#endif - - for (int i = 0; i < font->texLines.count; ++i) { - LOG(VKVG_LOG_FONT, "\treleased line %d of page %d\n", i, font->texLines.elements[i]->pageIdx); - font->texLines.elements[i]->released = true; - } - array_destroy_TexRef(&font->texLines); - - array_del_VkvgFont(&font->face->sizes , font); - - if (font->face->sizes.count == 0) - _font_face_destroy(font); - free(font->charLookup); vkvg_device_destroy(font->dev); free(font); diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index 9ef3da0..5395761 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -152,8 +152,12 @@ static inline int get_utf8_char_length(uint8_t first_byte) { return utf8_len_table[first_byte]; } -typedef struct _tex_ref_t tex_ref_t; -typedef struct _tex_ref_t* TexRef; +typedef struct _tex_ref_t tex_ref_t;//? +typedef struct _tex_ref_t *TexRef; +typedef struct _vkvg_font_buffer_t *FontBuffer; +typedef struct _vkvg_font_face_t *FontFace; +typedef struct _vkvg_font_size_t *FontSize; + // texture coordinates of one character in font cache array texture. typedef struct _char_ref { TexRef texRef; /* glyph bitmap ref */ @@ -182,6 +186,9 @@ CTOR_ARRAY(uint64_t) CTOR_ARRAY(VkvgFont) ARRAY_DEL_ELT(VkvgFont) +CTOR_ARRAY(FontSize) +ARRAY_DEL_ELT(FontSize) + typedef struct _tex_page_t { array_TexRef lines; float penY; @@ -189,9 +196,6 @@ typedef struct _tex_page_t { CTOR_ARRAY(tex_page_t) -typedef struct _vkvg_font_buffer_t *FontBuffer; -typedef struct _vkvg_font_face_t *FontFace; - /* Font identification structure */ typedef struct _vkvg_font_face_t{ FontBuffer fontBuffer; @@ -211,7 +215,7 @@ typedef struct _vkvg_font_face_t{ #ifdef VKVG_USE_HARFBUZZ hb_font_t* hb_font; /* HarfBuzz font instance*/ #endif - array_VkvgFont sizes; /* loaded font size array */ + array_FontSize sizes; /* loaded font size array */ } vkvg_font_face_t; CTOR_ARRAY(FontFace) @@ -229,14 +233,11 @@ ARRAY_DEL_ELT(FontBuffer) DIAGNOSTIC_RESTORE_UNUSED -typedef struct _vkvg_font_t { - vkvg_status_t status; - atomic_int references; // reference count - +typedef struct _vkvg_font_size_t { FontFace face; VkvgDevice dev; // to access font cache when required + float pxSize; // self computed pix size from pt with surface dpy used for size matching. #ifdef VKVG_USE_FREETYPE - FT_F26Dot6 charSize; /* Font size in Point as fixed float 26.6 */ FT_Size ftSize; /* FT size rec */ signed long* coords; /* Variable fonts axes coordinates */ #else @@ -246,14 +247,32 @@ typedef struct _vkvg_font_t { int descent; int lineGap; #endif - glyph_ref* charLookup;/* Lookup table of characteres in cache, if not found, upload is queued*/ array_TexRef texLines; /* texture reference where to add new glyph bmp's in cache */ int penX; /* Current X in cache for next char addition */ float height; /* Height in pixel */ +} vkvg_font_size_t; + +typedef struct _vkvg_font_t { + vkvg_status_t status; + atomic_int references; // reference count + + FontFace face; + VkvgDevice dev; // to access font cache when required +#ifdef VKVG_USE_FREETYPE + FT_F26Dot6 ptSize; /* Font size in Point as fixed float 26.6 */ +#else + float charSize; /* Font size in pixel */ + float scale; /* scale factor for the given size */ + int ascent; /* unscalled stb font metrics */ + int descent; + int lineGap; +#endif + vkvg_font_size_t* curSize; } vkvg_font_t; + // Font cache global structure, entry point for all font related operations. typedef struct _font_cache_t { #ifdef VKVG_USE_FREETYPE @@ -261,20 +280,20 @@ typedef struct _font_cache_t { #else #endif #ifdef VKVG_USE_FONTCONFIG - FcConfig* config; /* Font config, used to find font files by font names*/ + FcConfig* config; /* Font config, used to find font files by font names*/ //FcPattern* fcPattern; /* patter used for all Font config queries */ - FcObjectSet* fcReqElts; /* Font config requested metadata elements */ + FcObjectSet* fcReqElts; /* Font config requested metadata elements */ #endif - int stagingX; /* x pen in host buffer */ - uint8_t* hostBuff; /* host memory where bitmaps are first loaded */ + int stagingX; /* x pen in host buffer */ + uint8_t* hostBuff; /* host memory where bitmaps are first loaded */ VkCommandBuffer cmd; /* vulkan command buffer for font textures upload */ vkh_buffer_t buff; /* stagin buffer */ VkhImage texture; /* 2d array texture used by contexts to draw characteres */ VkDescriptorPool descriptorPool; - VkDescriptorSet dsFont; /* fonts glyphs texture atlas descriptor set */ + VkDescriptorSet dsFont; /* fonts glyphs texture atlas descriptor set */ VkFormat texFormat; /* Format of the fonts texture array */ uint8_t texPixelSize; /* Size in byte of a single pixel in a font texture */ @@ -294,7 +313,7 @@ typedef struct _font_cache_t { // Precompute everything necessary to measure and draw one line of text, usefull to draw the same text multiple times. typedef struct _vkvg_text_run_t { - VkvgFont font; /* vkvg font structure pointer */ + FontSize font; /* vkvg font structure pointer */ vkvg_direction_t textDirection; /* horizontal or vertical */ vkvg_text_extents_t extents; /* store computed text extends */ const char* text; /* utf8 char array of text*/ @@ -313,10 +332,12 @@ void _font_cache_destroy(VkvgDevice dev); bool _font_cache_load_font_file_in_memory(vkvg_font_face_t* fontId); void _font_cache_show_text(VkvgContext ctx, const char* text); void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkvg_text_extents_t* extents); -void _font_cache_font_extents(VkvgFont font, vkvg_font_extents_t* extents); +void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents); void _font_cache_update_context_descset(VkvgContext ctx); -void text_run_init(VkvgText textRun, VkvgFont font, vkvg_direction_t textDirection, const char* text, int length); +void _font_size_destroy (FontSize font); + +void text_run_init(VkvgText textRun, VkvgContext ctx, const char* text, int length); void text_run_term(VkvgText textRun); void text_run_render(VkvgText tr, VkvgContext ctx); // Draw text run #endif diff --git a/tests/fonts/allfont.c b/tests/fonts/allfont.c index dc7d20c..8e8374b 100644 --- a/tests/fonts/allfont.c +++ b/tests/fonts/allfont.c @@ -172,7 +172,7 @@ void draw(VkvgSurface surfFont) { char tmp[1024]; - VkvgFont mono = vkvg_font_create(surf, "mono", 12); + VkvgFont mono = vkvg_font_create(device, "mono", 12); for (int i = curFontStartIdx; i < font_database->nfont; i++) { FcPattern* font_entry = font_database->fonts[i]; @@ -199,7 +199,7 @@ void draw(VkvgSurface surfFont) { if (onlyVariable && !variable) continue; - VkvgFont font = vkvg_font_create (surf, tmp, fontSize); + VkvgFont font = vkvg_font_create (device, tmp, fontSize); if (vkvg_font_status(font)) { printf("Error trying to load %s, from %s\n", tmp, file_path); fflush(stdout); diff --git a/tests/fonts/fontquery.c b/tests/fonts/fontquery.c index 3296752..a780d38 100644 --- a/tests/fonts/fontquery.c +++ b/tests/fonts/fontquery.c @@ -282,7 +282,7 @@ void draw(VkvgSurface surfFont) { FcPatternGetString (font, FC_FAMILY, 0, &family_name); FcPatternGetString (font, FC_STYLE, 0, &style_variant); FcPatternGetBool(font, FC_VARIABLE, 0, &var); - VkvgFont f = vkvg_font_create_from_file(surf, (char*)fontFile, index, fontSize); + VkvgFont f = vkvg_font_create_from_file(device, (char*)fontFile, index, fontSize); if (vkvg_font_status(f)) { printf("Error trying to load %s, from %s\n", txtBuffCopy, fontFile); fflush(stdout); @@ -528,7 +528,7 @@ int main(int argc, char* argv[]) { strcpy (txtBuffer, "sans"); txtBuffPtr = 4; - sans16 = vkvg_font_create(surf, "sans", 16); + sans16 = vkvg_font_create(device, "sans", 16); while (!vkengine_should_close(e)) { glfwPollEvents(); diff --git a/tests/text.c b/tests/text.c index fda9c4a..62021e0 100644 --- a/tests/text.c +++ b/tests/text.c @@ -176,7 +176,7 @@ void test() { void single_font_and_size() { VkvgContext ctx = vkvg_create(surf); vkvg_clear(ctx); - VkvgFont font = vkvg_font_create(surf, "mono", 20); + VkvgFont font = vkvg_font_create(device, "mono", 20); for (uint32_t i = 0; i < test_size; i++) { randomize_color(ctx); float x = rndf() * test_width; @@ -195,8 +195,8 @@ void simple_text() { vkvg_paint(ctx); vkvg_set_source_rgb(ctx, 1, 1, 1); - VkvgFont mono = vkvg_font_create(surf, "mono", 12); - VkvgFont norm = vkvg_font_create_from_file(surf, "data/Proto-Sinaitic15.ttf", 0, 24); + VkvgFont mono = vkvg_font_create(device, "mono", 12); + VkvgFont norm = vkvg_font_create_from_file(device, "data/Proto-Sinaitic15.ttf", 0, 24); vkvg_set_font (ctx, mono); vkvg_move_to(ctx, 20, 50); vkvg_show_text(ctx, "hwhy"); @@ -229,7 +229,7 @@ void variable_text() { vkvg_paint(ctx); vkvg_set_source_rgb(ctx, 1, 1, 1); - VkvgFont noto = vkvg_font_create(surf, "Noto Sans JP:fontvariations=wght=150", 30); + VkvgFont noto = vkvg_font_create(device, "Noto Sans JP:fontvariations=wght=150", 30); vkvg_set_font (ctx, noto); vkvg_move_to(ctx, 20, 50); @@ -237,14 +237,14 @@ void variable_text() { vkvg_font_destroy(noto); - noto = vkvg_font_create(surf, "Noto Sans JP:fontvariations=wght=900", 30); + noto = vkvg_font_create(device, "Noto Sans JP:fontvariations=wght=900", 30); vkvg_set_font (ctx, noto); vkvg_move_to(ctx, 20, 150); vkvg_show_text(ctx, txt2); vkvg_font_destroy(noto); - noto = vkvg_font_create(surf, "Cantarell:fontvariations=wght=900", 30); + noto = vkvg_font_create(device, "Cantarell:fontvariations=wght=900", 30); vkvg_set_font (ctx, noto); vkvg_move_to(ctx, 20, 200); vkvg_show_text(ctx, txt); @@ -297,7 +297,7 @@ void random_font_and_size() { float y = rndf() * test_height; uint32_t c = (uint32_t)(rndf() * 80) + 1; uint32_t f = (uint32_t)(rndf() * 4); - VkvgFont font = vkvg_font_create(surf, fonts[f], c); + VkvgFont font = vkvg_font_create(device, fonts[f], c); vkvg_set_font(ctx,font); vkvg_move_to(ctx, x, y); vkvg_show_text(ctx, "This is a test string!"); |