summaryrefslogtreecommitdiffstatsci
diff options
context:
space:
mode:
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>2026-10-08 16:50:50 +0200
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>2026-10-08 16:50:50 +0200
commitc5aeefe4836846fff467a0825d07f0ddefc6975d (patch)
tree424e3aa7312b62196580d0d1f8d3bc69697546be
parent748bd9b738df2a789811a02c76bacd4855959d65 (diff)
LOGE/LOGW;unlikely/likely;debug harfbuzz shaping
-rw-r--r--include/vkvg.h2
-rw-r--r--src/cross_os.h17
-rw-r--r--src/vkvg_context.c18
-rw-r--r--src/vkvg_context_internal.c10
-rw-r--r--src/vkvg_device.c12
-rw-r--r--src/vkvg_device_internal.c4
-rw-r--r--src/vkvg_fonts.c289
-rw-r--r--src/vkvg_fonts.h53
-rw-r--r--src/vkvg_internal.h30
-rw-r--r--src/vkvg_surface.c18
-rw-r--r--src/vkvg_surface_internal.c4
-rw-r--r--tests/fonts/allfont.c62
-rw-r--r--tests/svg-parser-new/vkvg_svg_internal.h1
13 files changed, 290 insertions, 230 deletions
diff --git a/include/vkvg.h b/include/vkvg.h
index 011230a..6bd64ff 100644
--- a/include/vkvg.h
+++ b/include/vkvg.h
@@ -105,8 +105,8 @@ extern "C" {
#define VKVG_LOG_INFO 0x00008000 //(VKVG_LOG_INFO_PTS|VKVG_LOG_INFO_PATH|VKVG_LOG_INFO_CMD|VKVG_LOG_INFO_VAO)
-#ifdef DEBUG
vkvg_public extern uint32_t vkvg_log_level;
+#ifdef DEBUG
#ifdef VKVG_WIRED_DEBUG
typedef enum {
vkvg_wired_debug_mode_normal = 0x01,
diff --git a/src/cross_os.h b/src/cross_os.h
index bdd3f7a..13cdc8a 100644
--- a/src/cross_os.h
+++ b/src/cross_os.h
@@ -73,6 +73,23 @@ __pragma(warning(disable : 4505))
#define DIAGNOSTIC_RESTORE_UNUSED
#endif
+#if defined(__GNUC__) || defined(__clang__)
+/* GCC and Clang (Linux, macOS, MinGW) */
+#define vkvg_likely(x) __builtin_expect(!!(x), 1)
+#define vkvg_unlikely(x) __builtin_expect(!!(x), 0)
+#elif defined(_MSC_VER)
+/* MSVC (Windows) */
+/* MSVC does not have a static branch predictor builtin. */
+/* We fall back to standard evaluation. MSVC relies on PGO */
+/* (Profile-Guided Optimization) to sort branches at link time. */
+#define vkvg_likely(x) (!!(x))
+#define vkvg_unlikely(x) (!!(x))
+#else
+/* Fallback for any other exotic compiler */
+#define vkvg_likely(x) (!!(x))
+#define vkvg_unlikely(x) (!!(x))
+#endif
+
// 1. Check if we are in a POSIX environment that supports strncasecmp
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
#include <strings.h> /* Provides the native strncasecmp */
diff --git a/src/vkvg_context.c b/src/vkvg_context.c
index c8d332c..600bd90 100644
--- a/src/vkvg_context.c
+++ b/src/vkvg_context.c
@@ -81,12 +81,12 @@ void _init_ctx(VkvgContext ctx) {
VkvgContext vkvg_create(VkvgSurface surf) {
LOG(VKVG_LOG_INFO, "CREATE Context\n");
if (vkvg_surface_status(surf)) {
- LOG(VKVG_LOG_ERR, "CREATE Context failed, invalid surface\n");
+ LOGE("CREATE Context failed, invalid surface\n");
return (VkvgContext)&_vkvg_status_invalid_surface;
}
VkvgDevice dev = surf->dev;
if (vkvg_device_status(dev)) {
- LOG(VKVG_LOG_ERR, "CREATE Context failed, invalid device\n");
+ LOGE("CREATE Context failed, invalid device\n");
return (VkvgContext)&_vkvg_status_device_error;
}
VkvgContext ctx = NULL;
@@ -103,7 +103,7 @@ VkvgContext vkvg_create(VkvgSurface surf) {
ctx = (vkvg_context*)calloc(1, sizeof(vkvg_context));
if (!ctx) {
- LOG(VKVG_LOG_ERR, "CREATE context failed, no memory\n");
+ LOGE("CREATE context failed, no memory\n");
return (VkvgContext)&_vkvg_status_no_memory;
}
@@ -133,7 +133,7 @@ VkvgContext vkvg_create(VkvgSurface surf) {
if (ctx->indexCache)
free(ctx->indexCache);
free(ctx);
- LOG(VKVG_LOG_ERR, "CREATE context failed, no memory\n");
+ LOGE("CREATE context failed, no memory\n");
return (VkvgContext)&_vkvg_status_no_memory;
}
@@ -1246,14 +1246,14 @@ VkvgText vkvg_text_run_create(VkvgContext ctx, const char* text) {
if (vkvg_status(ctx))
return NULL;
VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t));
- _font_cache_init_text_run(ctx, text, -1, tr);
+ text_run_init(ctx, text, -1, tr);
return tr;
}
VkvgText vkvg_text_run_create_with_length(VkvgContext ctx, const char* text, uint32_t length) {
if (vkvg_status(ctx))
return NULL;
VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t));
- _font_cache_init_text_run(ctx, text, length, tr);
+ text_run_init(ctx, text, length, tr);
return tr;
}
uint32_t vkvg_text_run_get_glyph_count(VkvgText textRun) { return textRun->glyph_count; }
@@ -1269,13 +1269,13 @@ void vkvg_text_run_get_glyph_position(VkvgText textRun, uint32_t index, vkvg
#endif
}
void vkvg_text_run_destroy(VkvgText textRun) {
- _font_cache_term_text_run(textRun);
+ text_run_term(textRun);
free(textRun);
}
void vkvg_show_text_run(VkvgContext ctx, VkvgText textRun) {
if (vkvg_status(ctx))
return;
- _font_cache_show_text_run(ctx, textRun);
+ text_run_show_text(ctx, textRun);
}
void vkvg_text_run_get_extents(VkvgText textRun, vkvg_text_extents_t* extents) { *extents = textRun->extents; }
@@ -1302,7 +1302,7 @@ void vkvg_save(VkvgContext ctx) {
ctx->pSavedCtxs, newSize * sizeof(vkvg_context_save_t));
if (tmp == NULL) {
ctx->status = VKVG_STATUS_NO_MEMORY;
- LOG(VKVG_LOG_ERR, "resize context save stack failed.\n");
+ LOGE("resize context save stack failed.\n");
return;
}
ctx->pSavedCtxs = tmp;
diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c
index effc40b..a8b8853 100644
--- a/src/vkvg_context_internal.c
+++ b/src/vkvg_context_internal.c
@@ -46,7 +46,7 @@ void _resize_vertex_cache(VkvgContext ctx, uint32_t newSize) {
ctx->vertCount, ctx->sizeVertices, newSize, (size_t)newSize * sizeof(Vertex), ctx->vertexCache, tmp);
if (tmp == NULL) {
ctx->status = VKVG_STATUS_NO_MEMORY;
- LOG(VKVG_LOG_ERR, "resize vertex cache failed: vert count: %u byte size: %zu\n", newSize,
+ LOGE("resize vertex cache failed: vert count: %u byte size: %zu\n", newSize,
newSize * sizeof(Vertex));
return;
}
@@ -60,7 +60,7 @@ void _resize_index_cache(VkvgContext ctx, uint32_t newSize) {
ctx->indexCache, tmp);
if (tmp == NULL) {
ctx->status = VKVG_STATUS_NO_MEMORY;
- LOG(VKVG_LOG_ERR, "resize IBO failed: idx count: %u size(byte): %zu\n", newSize,
+ LOGE("resize IBO failed: idx count: %u size(byte): %zu\n", newSize,
(size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE));
return;
}
@@ -106,7 +106,7 @@ bool _check_pathes_array(VkvgContext ctx) {
LOG(VKVG_LOG_DBG_ARRAYS, "resize PATH: new size: %u Ptr: %p -> %p\n", ctx->sizePathes, ctx->pathes, tmp);
if (tmp == NULL) {
ctx->status = VKVG_STATUS_NO_MEMORY;
- LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePathes * sizeof(uint32_t));
+ LOGE("resize PATH failed: new size(byte): %zu\n", ctx->sizePathes * sizeof(uint32_t));
_clear_path(ctx);
return true;
}
@@ -122,7 +122,7 @@ bool _check_point_array(VkvgContext ctx) {
LOG(VKVG_LOG_DBG_ARRAYS, "resize Points: new size(point): %u Ptr: %p -> %p\n", ctx->sizePoints, ctx->points, tmp);
if (tmp == NULL) {
ctx->status = VKVG_STATUS_NO_MEMORY;
- LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePoints * sizeof(vec2));
+ LOGE("resize PATH failed: new size(byte): %zu\n", ctx->sizePoints * sizeof(vec2));
_clear_path(ctx);
return true;
}
@@ -689,7 +689,7 @@ void _update_cur_pattern(VkvgContext ctx, VkvgPattern pat) {
if (lastPat == NULL) // solid
return; // solid to solid transition, no extra action requested
} else if (pat->status) {
- LOG(VKVG_LOG_ERR, "Error: Update pattern fails, pattern status: %d\n", pat->status);
+ LOGE("Error: Update pattern fails, pattern status: %d\n", pat->status);
return;
} else
newPatternType = pat->type;
diff --git a/src/vkvg_device.c b/src/vkvg_device.c
index f9ed284..2922df3 100644
--- a/src/vkvg_device.c
+++ b/src/vkvg_device.c
@@ -224,7 +224,7 @@ vkvg_status_t vkvg_get_required_device_extensions(VkPhysicalDevice phy, const ch
#ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT
if (!scalarBlockLayoutSupport.scalarBlockLayout) {
- LOG(VKVG_LOG_ERR, "CREATE Device failed, vkvg compiled with VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT and feature is "
+ LOGE("CREATE Device failed, vkvg compiled with VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT and feature is "
"not implemented for physical device.\n");
free(pExtensionProperties);
return VKVG_STATUS_DEVICE_ERROR;
@@ -233,7 +233,7 @@ vkvg_status_t vkvg_get_required_device_extensions(VkPhysicalDevice phy, const ch
#endif
#ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE
if (!timelineSemaphoreSupport.timelineSemaphore) {
- LOG(VKVG_LOG_ERR, "CREATE Device failed, VK_SEMAPHORE_TYPE_TIMELINE not supported.\n");
+ LOGE("CREATE Device failed, VK_SEMAPHORE_TYPE_TIMELINE not supported.\n");
free(pExtensionProperties);
return VKVG_STATUS_DEVICE_ERROR;
}
@@ -289,12 +289,12 @@ const void* vkvg_get_device_requirements(VkPhysicalDeviceFeatures* pEnabledFeatu
VkvgDevice vkvg_device_create(vkvg_device_create_info_t* info) {
LOG(VKVG_LOG_INFO, "CREATE Device\n");
if (!info) {
- LOG(VKVG_LOG_ERR, "CREATE Device failed, provided vkvg_device_create_info_t is null\n");
+ LOGE("CREATE Device failed, provided vkvg_device_create_info_t is null\n");
return (VkvgDevice)&_vkvg_status_invalid_dev_ci;
}
VkvgDevice dev = (vkvg_device*)calloc(1, sizeof(vkvg_device));
if (!dev) {
- LOG(VKVG_LOG_ERR, "CREATE Device failed, no memory\n");
+ LOGE("CREATE Device failed, no memory\n");
return (VkvgDevice)&_vkvg_status_no_memory;
}
@@ -354,7 +354,7 @@ VkvgDevice vkvg_device_create(vkvg_device_create_info_t* info) {
info->samples = VK_SAMPLE_COUNT_1_BIT;
if (!(pi->properties.limits.framebufferColorSampleCounts & info->samples)) {
- LOG(VKVG_LOG_ERR, "CREATE Device failed: sample count not supported: %d\n", info->samples);
+ LOGE("CREATE Device failed: sample count not supported: %d\n", info->samples);
dev->status = VKVG_STATUS_DEVICE_ERROR;
vkh_app_free_phyinfos(phyCount, phys);
vkh_app_destroy(app);
@@ -405,7 +405,7 @@ VkvgDevice vkvg_device_create(vkvg_device_create_info_t* info) {
void vkvg_device_destroy(VkvgDevice dev) {
if (vkvg_device_status(dev)) {
- LOG(VKVG_LOG_ERR, "DESTROY Device failed, see Status for info");
+ LOGE("DESTROY Device failed, see Status for info");
return;
}
LOCK_DEVICE
diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c
index a86715f..497e911 100644
--- a/src/vkvg_device_internal.c
+++ b/src/vkvg_device_internal.c
@@ -492,7 +492,7 @@ void _device_submit_cmd(VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence) {
bool _device_init_function_pointers(VkvgDevice dev) {
#if defined(DEBUG) && defined(VKVG_DBG_UTILS)
if (vkGetInstanceProcAddr(dev->instance, "vkSetDebugUtilsObjectNameEXT") == VK_NULL_HANDLE) {
- LOG(VKVG_LOG_ERR, "vkvg create device failed: 'VK_EXT_debug_utils' has to be loaded for Debug build\n");
+ LOGE("vkvg create device failed: 'VK_EXT_debug_utils' has to be loaded for Debug build\n");
return false;
}
vkh_device_init_debug_utils((VkhDevice)&dev->vkDev);
@@ -590,7 +590,7 @@ void _device_check_best_image_tiling(VkvgDevice dev, VkFormat format) {
}
}
dev->status = VKVG_STATUS_INVALID_FORMAT;
- LOG(VKVG_LOG_ERR, "vkvg create device failed: image format not supported: %d\n", format);
+ LOGE("vkvg create device failed: image format not supported: %d\n", format);
}
void _dump_image_format_properties(VkvgDevice dev, VkFormat format) {
diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c
index 2a48645..80e15a1 100644
--- a/src/vkvg_fonts.c
+++ b/src/vkvg_fonts.c
@@ -3,7 +3,6 @@
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
#include "vkvg_fonts.h"
#include "vkvg_context_internal.h"
-#include "vkvg_surface_internal.h"
#include "vkvg_device_internal.h"
#include "vkh.h"
@@ -27,7 +26,7 @@ void _fonts_cache_create(VkvgDevice dev, const char* fontDirs) {
#ifdef VKVG_USE_FONTCONFIG
if (!FcInit()) {
- LOG(VKVG_LOG_ERR, "Font config initialisation failed\n");
+ LOGE("Font config initialisation failed\n");
dev->status = VKVG_STATUS_DEVICE_ERROR;
free(cache);
return;
@@ -35,7 +34,7 @@ void _fonts_cache_create(VkvgDevice dev, const char* fontDirs) {
if (fontDirs) {
cache->config = FcConfigCreate();
if (!cache->config) {
- LOG(VKVG_LOG_ERR, "Failed to create custom Fontconfig configuration.\n");
+ LOGE("Failed to create custom Fontconfig configuration.\n");
dev->status = VKVG_STATUS_DEVICE_ERROR;
free(cache);
return;
@@ -58,7 +57,7 @@ void _fonts_cache_create(VkvgDevice dev, const char* fontDirs) {
} else {
cache->config = FcConfigGetCurrent();
if (!cache->config) {
- LOG(VKVG_LOG_ERR,
+ LOGE(
"Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\
variables to point to 'fonts.conf' needed for FontConfig startup");
dev->status = VKVG_STATUS_DEVICE_ERROR;
@@ -265,19 +264,26 @@ void _init_next_line_in_tex_cache(VkvgDevice dev, vkvg_font_t* f) {
void _font_buffer_destroy (vkvg_font_face_t* face) {
array_destroy_VkvgFont(&face->sizes);
array_destroy_uint64_t(&face->queryHashes);
+#ifdef VKVG_USE_FREETYPE
FT_Done_Face(face->face);
mtx_destroy(&face->mutex);
+#endif
}
void _font_face_destroy (FontFace face) {
array_destroy_VkvgFont(&face->sizes);
array_destroy_uint64_t(&face->queryHashes);
- mtx_destroy(&face->mutex);
-
array_del_FontFace(&face->fontBuffer->faces, face);
+
+#ifdef VKVG_USE_FREETYPE
+ mtx_destroy(&face->mutex);
if (face->fontBuffer->faces.count == 0) {
LOG(VKVG_LOG_FONT, "Done face: %s\n", face->face->family_name);
+ #ifdef VKVG_USE_HARFBUZZ
+ hb_font_destroy(face->hb_font);
+ #endif
FT_Done_Face(face->face);
}
+#endif
free(face);
}
void _font_cache_destroy(VkvgDevice dev) {
@@ -348,21 +354,29 @@ void _font_cache_update_context_descset(VkvgContext ctx) {
UNLOCK_FONTCACHE(ctx->dev)
}
// create a new char entry and put glyph in stagging buffer, ready for upload.
-char_ref _prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) {
- VkvgFont f = tr->font;
+
+glyph_ref _put_glyph_in_cache(VkvgDevice dev, VkvgFont 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));
FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD));
#else
- FT_Error res = FT_Load_Glyph(f->face->face, gindex, FT_LOAD_RENDER);
+ FT_Error res = FT_Load_Glyph(font->face->face, gindex, FT_LOAD_RENDER);
if (res) {
- LOG(VKVG_LOG_WARN, "FT_Load_Glyph error 0x%x for glyph index %d\n", res, gindex);
- FT_Load_Glyph(f->face->face, 0, FT_LOAD_RENDER);
+ LOGW("FT_Load_Glyph error 0x%x for glyph index %d\n", res, gindex);
+ if (font->charLookup[0].texRef) // return default glyph ref 0
+ return font->charLookup[0];
+ // try upload default glyph 0 in cache
+ 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;
+ return (glyph_ref) {0};
+ }
}
#endif
- FT_GlyphSlot slot = f->face->face->glyph;
+ FT_GlyphSlot slot = font->face->face->glyph;
FT_Bitmap bmp = slot->bitmap;
uint32_t bmpByteWidth = bmp.width;
uint32_t bmpPixelWidth = bmp.width;
@@ -373,7 +387,7 @@ char_ref _prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) {
bmpPixelWidth /= 3;
#endif
#else
- stbtt_fontinfo* pStbInfo = &tr->fontId->stbInfo;
+ stbtt_fontinfo* pStbInfo = &tr->font->face->stbInfo;
int c_x1, c_y1, c_x2, c_y2;
stbtt_GetGlyphBitmapBox(pStbInfo, gindex, f->scale, f->scale, &c_x1, &c_y1, &c_x2, &c_y2);
uint32_t bmpByteWidth = c_x2 - c_x1;
@@ -381,12 +395,12 @@ char_ref _prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) {
uint32_t bmpRows = c_y2 - c_y1;
#endif
uint8_t* data = dev->fontCache->hostBuff;
- if (dev->fontCache->stagingX + f->penX + bmpPixelWidth > FONT_PAGE_SIZE) {
- _flush_chars_to_tex(dev, f);
- _init_next_line_in_tex_cache(dev, f);
+ if (dev->fontCache->stagingX + font->penX + bmpPixelWidth > FONT_PAGE_SIZE) {
+ _flush_chars_to_tex(dev, font);
+ _init_next_line_in_tex_cache(dev, font);
}
- //cr.texRefIdx = f->texLines.count - 1;
- char_ref cr = {f->texLines.elements[f->texLines.count - 1]};
+
+ glyph_ref cr = {font->texLines.elements[font->texLines.count - 1]};
int penX = dev->fontCache->stagingX;
#ifdef VKVG_USE_FREETYPE
@@ -418,64 +432,16 @@ char_ref _prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) {
cr.bmpDiff.y = (int16_t)-c_y1;
cr.advance = (vec2){(uint32_t)roundf(f->scale * advance) << 6, 0};
#endif
- vec4 uvBounds = {{(float)(penX + f->penX) / (float)FONT_PAGE_SIZE},
+ vec4 uvBounds = {{(float)(penX + font->penX) / (float)FONT_PAGE_SIZE},
{0.f},
{(float)bmpPixelWidth},
{(float)bmpRows}};
cr.bounds = uvBounds;
-
- f->charLookup[gindex] = cr;
dev->fontCache->stagingX += bmpPixelWidth;
return cr;
}
-/*void _fcpattern_append(FcPattern* dest, const FcPattern* src) {
- FcPatternIter iter;
- FcPatternIterStart(src, &iter);
- while (FcPatternIterIsValid(src, &iter)) {
- const char* object_name = FcPatternIterGetObject(src, &iter);
- int value_count = FcPatternIterValueCount(src, &iter);
- for (int i = 0; i < value_count; i++) {
- FcValue value;
- if (FcPatternIterGetValue(src, &iter, i, &value, NULL) == FcResultMatch) {
- FcPatternAdd(dest, object_name, value, FcTrue);
- }
- }
- FcPatternIterNext(src, &iter);
- }
-}
-FcPattern* _get_font_config_pattern(VkvgContext ctx, const char* fontQueryStr, ...) {
- FcPattern* request = NULL;
- va_list args;
- va_start(args, fontQueryStr);
- if (va_arg(args, const char*) == NULL) { //only one font request
- request = FcNameParse((const FcChar8*)fontQueryStr);
- } else {
- va_end(args);
- va_start(args, fontQueryStr);
-
- request = FcPatternCreate();
-
- const char* str = fontQueryStr;
- int i = 0;
- while (str != NULL) {
- FcPattern* subPat = FcNameParse((const FcChar8*)str);
- if (subPat) {
- _fcpattern_append(request, subPat);
- }
- FcPatternDestroy(subPat);
- str = va_arg(args, const char*);
- }
-
-
- }
- va_end(args);
- FcConfigSubstitute(ctx->dev->fontCache->config, request, FcMatchPattern);
- FcDefaultSubstitute(request);
- return request;
-}
-#define get_font_config_pattern(...) _get_font_config_pattern(__VA_ARGS__, NULL)*/
-bool tryGetFontFaceFromQueryHash(_font_cache_t* cache, uint64_t queryHash, FontFace *const face) {
+bool try_get_font_face_from_query_hash(_font_cache_t* cache, uint64_t queryHash, FontFace *const face) {
*face = NULL;
FontBuffer* buffs = cache->fontBuffers.elements;
for (int i = 0; i < cache->fontBuffers.count; ++i) {
@@ -492,7 +458,7 @@ bool tryGetFontFaceFromQueryHash(_font_cache_t* cache, uint64_t queryHash, FontF
}
return false;
}
-bool tryGetFontBufferFromPathHash(_font_cache_t* cache, uint64_t pathHash, FontBuffer *const fontBuff) {
+bool try_get_font_buffer_from_path_hash(_font_cache_t* cache, uint64_t pathHash, FontBuffer *const fontBuff) {
*fontBuff = NULL;
for (int i = 0; i < cache->fontBuffers.count; ++i) {
if (cache->fontBuffers.elements[i]->fontPathHash == pathHash) {
@@ -503,25 +469,28 @@ bool tryGetFontBufferFromPathHash(_font_cache_t* cache, uint64_t pathHash, FontB
}
return false;
}
-
-#ifdef VKVG_USE_FONTCONFIG
-bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, FontFace *const face) {
+bool try_get_or_create_font_face_from_query (VkvgDevice dev, const char* queryString, FontFace *const face) {
_font_cache_t* cache = dev->fontCache;
- uint64_t queryHash = fnv1a_64_str(fontString);
+ uint64_t queryHash = fnv1a_64_str(queryString);
*face = NULL;
- if (tryGetFontFaceFromQueryHash(cache, queryHash, face))
+ if (try_get_font_face_from_query_hash(cache, queryHash, face))
return true;
char *fontFile = NULL;
+ FontBuffer buffPtr = NULL;
+
+#ifdef VKVG_USE_FONTCONFIG
+ FcPattern* request = FcNameParse((const FcChar8*)queryString);
+
+ FcPatternAddBool(request, FC_SCALABLE, FcTrue);
+ FcPatternAddString(request, FC_FONTFORMAT, (const FcChar8 *)"TrueType");
- FcPattern* request = FcNameParse((const FcChar8*)fontString);
FcConfigSubstitute(cache->config, request, FcMatchPattern);
FcDefaultSubstitute(request);
FcResult result;
FcPattern* font = FcFontMatch(cache->config, request, &result);
- vkvg_font_buffer_t *buffPtr = NULL;
if (font) {
int index = 0;
@@ -529,7 +498,7 @@ bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, F
FcPatternGetInteger (font, FC_INDEX, 0, &index);
uint64_t fontFileHash = fnv1a_64_str(fontFile);
- if (tryGetFontBufferFromPathHash(cache, fontFileHash, &buffPtr)) {
+ if (try_get_font_buffer_from_path_hash(cache, fontFileHash, &buffPtr)) {
for (int f = 0; f < buffPtr->faces.count; ++f) {
if (buffPtr->faces.elements[f]->face->face_index == index) {
*face = buffPtr->faces.elements[f];
@@ -539,26 +508,30 @@ bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, F
}
LOG(VKVG_LOG_FONT, "Font buffer without a face\n");
} else {
- buffPtr = (FontBuffer)calloc(1, sizeof(vkvg_font_buffer_t));
- buffPtr->fontPathHash = fontFileHash;
FILE *file = fopen(fontFile, "rb");
if (!file) {
- LOG(VKVG_LOG_ERR, "Error opening font file: %s\n", fontFile);
+ LOGE("Error opening font file: %s\n", fontFile);
return false;
}
+ buffPtr = (FontBuffer)calloc(1, sizeof(vkvg_font_buffer_t));
+ buffPtr->fontPathHash = fontFileHash;
+
fseek(file, 0, SEEK_END);
buffPtr->bufferSize = ftell(file);
fseek(file, 0, SEEK_SET);
buffPtr->buffer = malloc(buffPtr->bufferSize);
+
if (!buffPtr->buffer) {
- LOG(VKVG_LOG_ERR, "Error opening font file: %s\n", fontFile);
+ LOGE("Error opening font file: %s\n", fontFile);
fclose(file);
+ free(buffPtr);
return false;
}
unsigned long readBytes = fread(buffPtr->buffer, 1, buffPtr->bufferSize, file);
fclose(file);
if (readBytes != buffPtr->bufferSize) {
- LOG(VKVG_LOG_ERR, "Error reading font file: %s\n", fontFile);
+ LOGE("Error reading font file: %s\n", fontFile);
+ free(buffPtr);
return false;
}
@@ -573,16 +546,14 @@ bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, F
mtx_init(&newFace->mutex, mtx_plain);
#ifdef VKVG_USE_FREETYPE
- /*if (cache->fontBuffers.count > 654 && cache->fontBuffers.elements[654] == buffPtr && buffPtr->faces.count > 0) {
- printf("= FontBuffer 654: face count = %d\n", buffPtr->faces.count);
- fflush(stdout);
- }*/
-
FT_Error res = FT_New_Memory_Face(cache->library, buffPtr->buffer, buffPtr->bufferSize, index, &newFace->face);
if (res) {
- LOG(VKVG_LOG_ERR, "FreeType error 0x%x creating memory face in %s at line %d\n", res, __FILE__, __LINE__);
+ LOGE("FreeType error 0x%x creating memory face in %s at line %d\n", res, __FILE__, __LINE__);
return false;
}
+#ifdef VKVG_USE_HARFBUZZ
+ newFace->hb_font = hb_ft_font_create(newFace->face, NULL);
+#endif
#else
int result = stbtt_InitFont(&font->stbInfo, font->fontBuffer, 0);
assert(result && "stbtt_initFont failed");
@@ -602,53 +573,69 @@ bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, F
array_add_FontFace(&buffPtr->faces, newFace);
array_add_uint64_t(&newFace->queryHashes, queryHash);
*face = newFace;
+
FcPatternDestroy(request);
return true;
}
+#endif
return false;
}
-#endif
+
#ifdef VKVG_USE_HARFBUZZ
// Get harfBuzz buffer for provided text.
-hb_buffer_t* _get_hb_buffer(vkvg_font_t* font, const char* text, int length) {
+hb_buffer_t* _get_hb_buffer(VkvgFont font, const char* text, int length) {
hb_buffer_t* buf = hb_buffer_create();
+ hb_buffer_add_utf8 (buf, text, length, 0, length);
+ hb_buffer_guess_segment_properties (buf);
+ hb_shape(font->face->hb_font, buf, NULL, 0);
- hb_script_t script = HB_SCRIPT_LATIN;
- hb_unicode_funcs_t* ucfunc = hb_unicode_funcs_get_default();
- uint32_t firstChar = decode_unicode_codepoint((uint8_t*)text);
-
- script = hb_unicode_script(ucfunc, firstChar);
-
- hb_direction_t dir = hb_script_get_horizontal_direction(script);
- hb_buffer_set_direction(buf, dir);
- hb_buffer_set_script(buf, script);
- // hb_buffer_set_language (buf, hb_language_from_string (lng, (int)strlen(lng)));
- hb_buffer_add_utf8(buf, text, length, 0, length);
- hb_shape(font->hb_font, buf, NULL, 0);
-
+ if (hb_buffer_get_content_type(buf) != HB_BUFFER_CONTENT_TYPE_GLYPHS) {
+ LOGW("HarfBuzz shaping failed: Buffer was not converted to glyphs.");
+ }
return buf;
}
#endif
+void _font_lock_size (VkvgContext ctx, VkvgFont font) {
+#ifdef VKVG_USE_FREETYPE
+ FT_Face face = font->face->face;
+ if (face->size != font->ftSize) {
+ if (ctx->dev->threadAware)
+ mtx_lock(&font->face->mutex);
+ FT_CHECK_RESULT(FT_Activate_Size(font->ftSize));
+#ifdef VKVG_USE_HARFBUZZ
+ hb_ft_font_changed(font->face->hb_font);
+#endif
+ }
+#endif
+}
// retrieve global font extends of context's current font as defined by FreeType
void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) {
- /*_update_current_font(ctx);
-
- if (ctx->status)
- return;
// TODO: ensure correct metrics are returned (scalled/unscalled, etc..)
- vkvg_font_t* font = ctx->currentFontSize;
+ VkvgFont font = ctx->currentFont;
#ifdef VKVG_USE_FREETYPE
- FT_BBox* bbox = &font->face->bbox;
- FT_Size_Metrics* metrics = &font->face->size->metrics;
+ FT_Face face = font->face->face;
+ /*_font_lock_size(ctx, font);
+ if (face->size != font->ftSize) {
+ mtx_lock(&font->face->mutex);
+ FT_CHECK_RESULT(FT_Activate_Size(font->ftSize));
+ }*/
+ //FT_BBox* bbox = &face->bbox;
+ //FT_Size_Metrics* metrics = &face->size->metrics;
+ FT_Size_Metrics* metrics = &font->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;
+ extents->height = (float)(FT_MulFix(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);*/
+ extents->max_x_advance = (float)(FT_MulFix(face->max_advance_width, metrics->x_scale) >> 6);
+ extents->max_y_advance = (float)(FT_MulFix(face->max_advance_height, metrics->y_scale) >> 6);
- 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);
+ /*if (ctx->dev->threadAware)
+ mtx_unlock(&font->face->mutex);*/
#else
extents->ascent = roundf(font->scale * ctx->currentFont->ascent);
extents->descent = -roundf(font->scale * ctx->currentFont->descent);
@@ -656,7 +643,7 @@ void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) {
roundf(font->scale * (ctx->currentFont->ascent - ctx->currentFont->descent + ctx->currentFont->lineGap));
extents->max_x_advance = 0; // TODO
extents->max_y_advance = 0;
-#endif*/
+#endif
}
// compute text extends for provided string.
void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkvg_text_extents_t* extents) {
@@ -666,23 +653,23 @@ void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkv
}
vkvg_text_run_t tr = {0};
- _font_cache_init_text_run(ctx, text, length, &tr);
+ text_run_init(ctx, text, length, &tr);
if (ctx->status)
return;
*extents = tr.extents;
- _font_cache_term_text_run(&tr);
+ text_run_term(&tr);
}
// text is expected as utf8 encoded
// if length is < 0, text must be null terminated, else it contains glyph count
-void _font_cache_init_text_run(VkvgContext ctx, const char* text, int length, VkvgText textRun) {
+void text_run_init(VkvgContext ctx, const char* text, int length, VkvgText textRun) {
textRun->dev = ctx->dev;
textRun->font = ctx->currentFont;
vkvg_font_reference (textRun->font);
- LOCK_FONTCACHE(ctx->dev)
+ _font_lock_size(ctx, textRun->font);
#ifdef VKVG_USE_HARFBUZZ
textRun->hbBuf = _get_hb_buffer(textRun->font, text, length);
@@ -717,7 +704,8 @@ void _font_cache_init_text_run(VkvgContext ctx, const char* text, int length, Vk
free(tmp);
#endif
- UNLOCK_FONTCACHE(ctx->dev)
+ if (ctx->dev->threadAware)
+ mtx_unlock(&textRun->font->face->mutex);
unsigned int string_width_in_pixels = 0;
for (uint32_t i = 0; i < textRun->glyph_count; ++i)
@@ -738,7 +726,7 @@ void _font_cache_init_text_run(VkvgContext ctx, const char* text, int length, Vk
textRun->extents.width = textRun->extents.x_advance;
}
-void _font_cache_term_text_run(VkvgText textRun) {
+void text_run_term(VkvgText textRun) {
#ifdef VKVG_USE_HARFBUZZ
hb_buffer_destroy(textRun->hbBuf);
#else
@@ -747,6 +735,7 @@ void _font_cache_term_text_run(VkvgText textRun) {
#endif
vkvg_font_destroy(textRun->font);
}
+
#ifdef DEBUG
void _show_texture(vkvg_context* ctx) {
Vertex vs[] = {{{0, 0}, 0, {0, 0, 0}},
@@ -764,7 +753,21 @@ void _show_texture(vkvg_context* ctx) {
_add_tri_indices_for_rect(ctx, firstIdx);
}
#endif
-void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr) {
+
+vkvg_inline glyph_ref get_cached_glyph (VkvgDevice dev, VkvgFont font, uint32_t gIndex) {
+ glyph_ref gr;
+ if (vkvg_unlikely (gIndex > font->face->face->num_glyphs)) {
+ LOGW("glyph index out of bounds: idx:%d glyphsCount: %ld\n", gIndex, font->face->face->num_glyphs);
+ if (!font->charLookup[0].texRef) // load default glyph 0
+ font->charLookup[0] = _put_glyph_in_cache(dev, font, 0);
+ return font->charLookup[0]; // set default glyph for index
+ }
+ if (!font->charLookup[gIndex].texRef)
+ font->charLookup[gIndex] = _put_glyph_in_cache(dev, font, gIndex);
+ return font->charLookup[gIndex];
+}
+
+void text_run_show_text(VkvgContext ctx, VkvgText tr) {
unsigned int glyph_count;
#ifdef VKVG_USE_HARFBUZZ
hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos(tr->hbBuf, &glyph_count);
@@ -772,9 +775,7 @@ void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr) {
vkvg_glyph_info_t* glyph_info = tr->glyphs;
glyph_count = tr->glyph_count;
#endif
-
VkvgFont f = tr->font;
-
Vertex v = {{0}, ctx->curColor, {0, 0, -1}};
vec2 pen = {0, 0};
@@ -784,12 +785,10 @@ void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr) {
LOCK_FONTCACHE(ctx->dev)
for (uint32_t i = 0; i < glyph_count; ++i) {
- char_ref cr = tr->font->charLookup[glyph_info[i].codepoint];
+ glyph_ref cr = get_cached_glyph(tr->dev, f, glyph_info[i].codepoint);
-#ifdef VKVG_USE_HARFBUZZ
- if (!cr.texRef)
- cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint);
-#endif
+ if (vkvg_unlikely (f->status))
+ break;
float uvWidth = cr.bounds.width / (float)FONT_PAGE_SIZE;
float uvHeight = cr.bounds.height / (float)FONT_PAGE_SIZE;
@@ -841,14 +840,14 @@ void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr) {
void _font_cache_show_text(VkvgContext ctx, const char* text) {
vkvg_text_run_t tr = {0};
- _font_cache_init_text_run(ctx, text, -1, &tr);
+ text_run_init(ctx, text, -1, &tr);
if (ctx->status)
return;
- _font_cache_show_text_run(ctx, &tr);
+ text_run_show_text(ctx, &tr);
- _font_cache_term_text_run(&tr);
+ text_run_term(&tr);
//_show_texture(ctx); return;
}
@@ -909,6 +908,7 @@ void _clear_cache() {
void* vkvg_font_get_face(VkvgFont font) {
return font->face->face;
}
+
#ifdef VKVG_USE_FREETYPE
#define CHECK_FACE_FLAG(flags, flag, buffer) \
do { \
@@ -918,10 +918,10 @@ do { \
} \
} while (0)
- /**
- * Converts face_flags bitmask to a human-readable string.
- * Make sure the output buffer is large enough (e.g., 512 bytes).
- */
+/**
+ * Converts face_flags bitmask to a human-readable string.
+ * Make sure the output buffer is large enough (e.g., 512 bytes).
+ */
void ft_face_flags_to_string(FT_Long face_flags, char* out_str, size_t max_len) {
if (!out_str || max_len == 0) return;
out_str[0] = '\0';
@@ -951,7 +951,7 @@ void ft_face_flags_to_string(FT_Long face_flags, char* out_str, size_t max_len)
if (res) { \
char tmp[1024]; \
ft_face_flags_to_string (face->face->face_flags, tmp, 1024); \
- LOG(VKVG_LOG_ERR, "FreeType error is 0x%x in %s at line %d, flags: %s\n", res, __FILE__, __LINE__, tmp);\
+ 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; \
} \
@@ -962,7 +962,7 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) {
uint32_t pt26_6 = (uint32_t)(pointSize * 64.f);
VkvgFont font = NULL;
vkvg_font_face_t* face = NULL;
- if (_tryResolveFontNameWithFontConfig(dev, query, &face)) {
+ if (try_get_or_create_font_face_from_query(dev, query, &face)) {
if (_try_get_font_size(face, pt26_6, &font)) {
vkvg_font_reference(font);
return font;
@@ -973,6 +973,7 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) {
font = (vkvg_font_t*)calloc(1, sizeof(vkvg_font_t));
if (!font) {
+ LOGE("Create font failed, no memory\n");
return (VkvgFont)&_vkvg_status_no_memory;
}
@@ -983,7 +984,7 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) {
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);
- LOG(VKVG_LOG_WARN, "Unsuported font flags: %s\n", tmp);
+ LOGW("Unsuported font flags: %s\n", tmp);
free(font);
return (VkvgFont)&_vkvg_status_null_pointer;
} else {
@@ -999,7 +1000,7 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) {
FT_CHECK_RES(FT_Set_Char_Size(face->face, 0, font->charSize, dev->hdpi, dev->vdpi));
//font->ftSize = face->face->size;
- font->charLookup = (char_ref*)calloc(face->face->num_glyphs, sizeof(char_ref));
+ 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;
@@ -1017,9 +1018,6 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) {
font->descent = roundf(font->scale * font->descent);
font->lineGap = roundf(font->scale * font->lineGap);
#endif
-#ifdef VKVG_USE_HARFBUZZ
- font->hb_font = hb_ft_font_create(face->face, NULL);
-#endif
array_add_VkvgFont(&face->sizes, font);
_init_next_line_in_tex_cache(dev, font);
@@ -1048,9 +1046,6 @@ void vkvg_font_destroy(VkvgFont font) {
#ifdef VKVG_USE_FREETYPE
FT_Done_Size(font->ftSize);
#endif
-#ifdef VKVG_USE_HARFBUZZ
- hb_font_destroy(font->hb_font);
-#endif
for (int i = 0; i < font->texLines.count; ++i) {
font->texLines.elements[i]->released = true;
diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h
index 43a4604..453f219 100644
--- a/src/vkvg_fonts.h
+++ b/src/vkvg_fonts.h
@@ -60,13 +60,11 @@ static const uint8_t utf8d[] = {
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
- 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s7
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,2,1,1,1,1,1,1,1,1,1,1, // s8..s9
- 1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // sA..sB
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1, // sC..sD
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1, // sE..sF
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // sG..sH
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, // sI..sJ
+ 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
+ 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
+ 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
+ 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
/**
@@ -86,6 +84,15 @@ static inline uint32_t decode_utf8_byte(uint32_t *const restrict state, uint32_t
*state = utf8d[256 + *state * 16 + type];
return *state;
}
+uint32_t inline decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
+ uint32_t type = utf8d[byte];
+ *codep = (*state != UTF8_ACCEPT) ?
+ (byte & 0x3fu) | (*codep << 6) :
+ (0xff >> type) & (byte);
+
+ *state = utf8d[256 + *state*16 + type];
+ return *state;
+}
// A perfectly optimized, branchless UTF-8 length lookup table
static const uint8_t utf8_len_table[256] = {
@@ -156,7 +163,7 @@ typedef struct _char_ref {
#else
vec2 advance;
#endif
-} char_ref;
+} glyph_ref;
// Current location in font cache texture array for new character addition. Each font holds such structure to locate
// where to upload new chars.
@@ -194,6 +201,9 @@ typedef struct _vkvg_font_face_t{
FT_Face face; /* FreeType face*/
mtx_t mutex; /* Only one font size at a time may use this face */
#endif
+#ifdef VKVG_USE_HARFBUZZ
+ hb_font_t* hb_font; /* HarfBuzz font instance*/
+#endif
array_VkvgFont sizes; /* loaded font size array */
#ifndef VKVG_USE_FREETYPE
@@ -234,10 +244,7 @@ typedef struct _vkvg_font_t {
int lineGap;
#endif
-#ifdef VKVG_USE_HARFBUZZ
- hb_font_t* hb_font; /* HarfBuzz font instance*/
-#endif
- char_ref* charLookup;/* Lookup table of characteres in cache, if not found, upload is queued*/
+ 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 */
@@ -293,24 +300,16 @@ typedef struct _vkvg_text_run_t {
#endif
} vkvg_text_run_t;
-// Create font cache.
+
void _fonts_cache_create(VkvgDevice dev, const char *fontDirs);
-// Release all ressources of font cache.
-void _font_cache_destroy(VkvgDevice dev);
-vkvg_font_face_t* _font_cache_add_font_identity(VkvgContext ctx, const char* fontFile, const char* name);
-bool _font_cache_load_font_file_in_memory(vkvg_font_face_t* fontId);
-// Draw text
+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);
-// Get text dimmensions
void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkvg_text_extents_t* extents);
-// Get font global dimmensions
void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents);
-// Create text object that could be drawn multiple times minimizing harfbuzz and compute processing.
-void _font_cache_init_text_run(VkvgContext ctx, const char* text, int length, VkvgText textRun);
-// Release ressources held by a text run.
-void _font_cache_term_text_run(VkvgText textRun);
-// Draw text run
-void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr);
-// update context font cache descriptor set
void _font_cache_update_context_descset(VkvgContext ctx);
+
+void text_run_init(VkvgContext ctx, const char* text, int length, VkvgText textRun);
+void text_run_term(VkvgText textRun);
+void text_run_show_text(VkvgContext ctx, VkvgText tr); // Draw text run
#endif
diff --git a/src/vkvg_internal.h b/src/vkvg_internal.h
index 8cc3db2..ff592f0 100644
--- a/src/vkvg_internal.h
+++ b/src/vkvg_internal.h
@@ -30,6 +30,8 @@
#endif
#include <assert.h>
+#include <stdio.h> // needed before stdarg.h on Windows
+#include <stdatomic.h>
#include "vkh.h"
#include "vkvg.h"
@@ -37,9 +39,10 @@
#include <float.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h> // needed before stdarg.h on Windows
+
+#include <stdlib.h>
#include <stdarg.h>
-#include <stdatomic.h>
+#include <string.h>
// should be supported by c11
// #include <threads.h>
@@ -81,6 +84,14 @@ static inline uint64_t fnv1a_64_str(const char *const restrict str) {
#define M_2_PI 0.63661977236758134308 // 2/pi
#endif*/
+// 1. Define ANSI Color Codes
+#define CLR_RESET "\x1b[0m"
+#define CLR_RED "\x1b[31m"
+#define CLR_GREEN "\x1b[32m"
+#define CLR_YELLOW "\x1b[33m"
+#define CLR_BLUE "\x1b[34m"
+
+
/*#ifdef DEBUG
#define LOG(level, ...) \
{ \
@@ -121,6 +132,21 @@ static inline uint64_t fnv1a_64_str(const char *const restrict str) {
#include "deps/tinycthread.h"
#include "cross_os.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#define DEBUG_LOG
+
+#ifdef DEBUG_LOG
+#define LOG(level, ...) { if (vkvg_unlikely(vkvg_log_level & level)) { fprintf(stdout, CLR_RESET "[VKVG] " __VA_ARGS__); fflush(stdout); }}
+#else
+#define LOG
+#endif
+#define LOGE(...) { fprintf(stdout, CLR_RED "[VKVG] " __VA_ARGS__); fflush(stdout); }
+#define LOGW(...) { fprintf(stdout, CLR_YELLOW "[VKVG] " __VA_ARGS__); fflush(stdout); }
+
// width of the stencil buffer will determine the number of context saving/restore layers
// the two first bits of the stencil are the FILL and the CLIP bits, all other bits are
// used to store clipping bit on context saving. 8 bit stencil will allow 6 save/restore layer
diff --git a/src/vkvg_surface.c b/src/vkvg_surface.c
index f99a061..8a7c728 100644
--- a/src/vkvg_surface.c
+++ b/src/vkvg_surface.c
@@ -186,7 +186,7 @@ VkvgSurface vkvg_surface_create_from_image(VkvgDevice dev, const char* filePath)
int w = 0, h = 0, channels = 0;
unsigned char* img = stbi_load(filePath, &w, &h, &channels, 4); // force 4 components per pixel
if (!img) {
- LOG(VKVG_LOG_ERR, "Could not load texture from %s, %s\n", filePath, stbi_failure_reason());
+ LOGE("Could not load texture from %s, %s\n", filePath, stbi_failure_reason());
return (VkvgSurface)&_vkvg_status_null_pointer;
}
@@ -199,11 +199,11 @@ VkvgSurface vkvg_surface_create_from_image(VkvgDevice dev, const char* filePath)
void vkvg_surface_destroy(VkvgSurface surf) {
if (vkvg_surface_status(surf)) {
- LOG(VKVG_LOG_ERR, "DESTROY surface failed, invalid surface\n");
+ LOGE("DESTROY surface failed, invalid surface\n");
return;
}
if (vkvg_device_status(surf->dev)) {
- LOG(VKVG_LOG_ERR, "DESTROY surface failed, device error\n");
+ LOGE("DESTROY surface failed, device error\n");
return;
}
@@ -286,20 +286,20 @@ uint32_t vkvg_surface_get_height(VkvgSurface surf) {
vkvg_status_t vkvg_surface_write_to_png(VkvgSurface surf, const char* path) {
if (vkvg_surface_status(surf)) {
- LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid status: %d\n", vkvg_surface_status(surf));
+ LOGE("vkvg_surface_write_to_png failed, invalid status: %d\n", vkvg_surface_status(surf));
return VKVG_STATUS_INVALID_STATUS;
}
if (vkvg_device_status(surf->dev)) {
- LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid device status: %d\n",
+ LOGE("vkvg_surface_write_to_png failed, invalid device status: %d\n",
vkvg_device_status(surf->dev));
return VKVG_STATUS_INVALID_STATUS;
}
if (surf->dev->pngStagFormat == VK_FORMAT_UNDEFINED) {
- LOG(VKVG_LOG_ERR, "no suitable image format for png write\n");
+ LOGE("no suitable image format for png write\n");
return VKVG_STATUS_INVALID_FORMAT;
}
if (!path) {
- LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, null path\n");
+ LOGE("vkvg_surface_write_to_png failed, null path\n");
return VKVG_STATUS_WRITE_ERROR;
}
LOCK_SURFACE(surf)
@@ -397,11 +397,11 @@ vkvg_status_t vkvg_surface_write_to_png(VkvgSurface surf, const char* path) {
vkvg_status_t vkvg_surface_write_to_memory(VkvgSurface surf, unsigned char* const bitmap) {
if (vkvg_surface_status(surf)) {
- LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, invalid status: %d\n", vkvg_surface_status(surf));
+ LOGE("vkvg_surface_write_to_memory failed, invalid status: %d\n", vkvg_surface_status(surf));
return VKVG_STATUS_INVALID_STATUS;
}
if (!bitmap) {
- LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, null path\n");
+ LOGE("vkvg_surface_write_to_memory failed, null path\n");
return VKVG_STATUS_WRITE_ERROR;
}
diff --git a/src/vkvg_surface_internal.c b/src/vkvg_surface_internal.c
index 537a97c..8dcddac 100644
--- a/src/vkvg_surface_internal.c
+++ b/src/vkvg_surface_internal.c
@@ -214,13 +214,13 @@ void _create_surface_images(VkvgSurface surf) {
VkvgSurface _create_surface(VkvgDevice dev, VkFormat format) {
LOG(VKVG_LOG_INFO, "CREATE Surface\n");
if (vkvg_device_status(dev)) {
- LOG(VKVG_LOG_ERR, "CREATE Surface failed, invalid Device\n");
+ LOGE("CREATE Surface failed, invalid Device\n");
return (VkvgSurface)&_vkvg_status_device_error;
}
VkvgSurface surf = (vkvg_surface*)calloc(1, sizeof(vkvg_surface));
if (!surf) {
- LOG(VKVG_LOG_ERR, "CREATE Surface failed, no memory\n");
+ LOGE("CREATE Surface failed, no memory\n");
return (VkvgSurface)&_vkvg_status_no_memory;
}
diff --git a/tests/fonts/allfont.c b/tests/fonts/allfont.c
index b71b2a4..c858f8b 100644
--- a/tests/fonts/allfont.c
+++ b/tests/fonts/allfont.c
@@ -7,7 +7,7 @@
#include FT_TRUETYPE_IDS_H
#include FT_MULTIPLE_MASTERS_H
-float fontSize = 16.0f;
+float fontSize = 32.0f;
int curFontStartIdx = 0;
bool redraw = true;
@@ -31,7 +31,7 @@ static const LocaleSample script_samples[] = {
{ "he", "דג אכל גזר באשחט" }, // Hebrew
{ "hi", "ऋषियों को तपस्या करते देख, दुष्टों के मन में डर पैदा हुआ।" }, // Hindi / Devanagari
{ "el", "διαφυλάξτε γενικά τη ζωή σας από τον φόβο" }, // Greek
- { "th", "เป็นมนุษย์สุดประเสริฐเลิศคุณค่า" }, // Thai
+ { "th", "เป็นมนุษย์สุดประเสริฐเลิIศคุณค่า" }, // Thai
{ "hy", "Ֆիզիկոս Մկրտիչը օճառաջուր ցողելով բժշկում է գնդապետ Հայկի փքված ձախ թևը։" }, // Armenian
{ "agr", "Agatjai juuk tusha numpanum ijuaku jintanum pujawai" }, // Aguaruna (Latin script variation)
//{ "aa", "Afari fanta asat darih doro dahanik xisbisa" }, // Afar (Latin script variation)
@@ -62,7 +62,7 @@ static const LocaleSample script_samples[] = {
{ "mn-cn", "Хүн бүр төрөхDiscussion эрх чөлөөтэй, нэр төр, эрхийн хувьд адилхан." }, // Mongolian - Inner Mongolia (Cyrillic fallback)
};
-void get_sample_by_fc_lang(const char* fc_lang, char* str) {
+bool try_get_sample_by_fc_lang(const char* fc_lang, char* str) {
const char* sample = NULL;
if (fc_lang) {
for (int i = 1; i < 37; i++) {
@@ -73,12 +73,12 @@ void get_sample_by_fc_lang(const char* fc_lang, char* str) {
}
if (!sample) {
sample = script_samples[0].sample_text;
- printf("missing lang sample: %s\n", fc_lang);
+ return false;
}
}
- // Check if the fontconfig language string starts with a known code
strncpy(str, sample, strlen(sample)+1);
+ return true;
}
@@ -143,12 +143,12 @@ bool try_get_sample_string(FcPattern* font_entry, FT_Face face, char* str) {
if (!lang_list)
return false;
- lang = FcStrListNext(lang_list);
-
- if (!lang)
- return false;
- //printf("lang: %s\n", str);
- get_sample_by_fc_lang((char*)lang, str);
+ while ((lang = FcStrListNext(lang_list))) {
+ if (!lang)
+ continue;
+ if (try_get_sample_by_fc_lang((char*)lang, str))
+ break;
+ }
FcStrListDone(lang_list);
return true;
@@ -162,7 +162,6 @@ void draw(VkvgSurface surfFont) {
return;
VkvgContext ctx = vkvg_create(surfFont);
vkvg_clear(ctx);
- vkvg_set_source_rgb(ctx,1,1,1);
float penX = 10.f;
float penY = 50.f;
@@ -190,13 +189,30 @@ void draw(VkvgSurface surfFont) {
continue;
}
vkvg_set_font (ctx, font);
- vkvg_move_to (ctx, penX, penY);
+
FT_Face face = (FT_Face)vkvg_font_get_face(font);
if (!try_get_sample_string(font_entry, face, tmp))
sprintf(tmp, "%s : %s", family_name, style_variant);
- vkvg_show_text (ctx,tmp);
+ vkvg_font_extents_t fe = {0};
+ vkvg_font_extents(ctx, &fe);
+ VkvgText tr = vkvg_text_run_create(ctx, tmp);
+ vkvg_text_extents_t extents = {0};
+ vkvg_text_run_get_extents(tr, &extents);
+ vkvg_rectangle(ctx, penX, penY - fe.ascent, extents.width, extents.height);
+ vkvg_set_line_width(ctx, 1);
+ vkvg_set_source_rgba(ctx,0.5f,0.5f,1, 0.7f);
+ vkvg_stroke(ctx);
+
+ vkvg_move_to (ctx, penX, penY);
+ vkvg_set_source_rgba(ctx,1,0,0,0.5f);
+ vkvg_arc(ctx, penX, penY, 3, 0, 2 * M_PI);
+ vkvg_fill(ctx);
+
+ vkvg_move_to (ctx, penX, penY);
+ vkvg_set_source_rgb(ctx,1,1,1);
+ vkvg_show_text_run(ctx,tr);
vkvg_flush(ctx);
vkvg_font_destroy(font);
@@ -229,12 +245,14 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
static void mouse_move_callback(GLFWwindow* window, double x, double y) {
}
static void scroll_callback(GLFWwindow* window, double x, double y) {
+ const int step = 5;
if (y > 0.f) {
if (curFontStartIdx > 0)
- curFontStartIdx --;
+ curFontStartIdx -= 5;
+ curFontStartIdx = MAX(curFontStartIdx, 0);
} else if (font_database) {
if (curFontStartIdx < font_database->nfont)
- curFontStartIdx ++;
+ curFontStartIdx +=5;
}
redraw = true;
}
@@ -249,7 +267,8 @@ static void mouse_button_callback(GLFWwindow* window, int but, int state, int mo
}
int main(int argc, char* argv[]) {
- vkh_log_level = VKVG_LOG_ERR | VKVG_LOG_WARN | VKVG_LOG_FONT;
+ vkh_log_level = VKH_LOG_FULL;
+ vkvg_log_level = VKVG_LOG_ERR | VKVG_LOG_WARN;// | VKVG_LOG_FONT;
_parse_args(argc, argv);
VkEngine e = vkengine_create (
@@ -279,9 +298,12 @@ int main(int argc, char* argv[]) {
return -1;
}
FcConfig* config = FcConfigGetCurrent();
- FcPattern* blank_pattern = FcPatternCreate();
+ FcPattern* request = FcPatternCreate();
FcObjectSet* requested_elements = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_FILE, FC_LANG, (char *)0);
- font_database = FcFontList(config, blank_pattern, requested_elements);
+ FcPatternAddBool(request, FC_SCALABLE, FcTrue);
+ FcPatternAddString(request, FC_FONTFORMAT, (const FcChar8 *)"TrueType");
+
+ font_database = FcFontList(config, request, requested_elements);
while (!vkengine_should_close(e)) {
glfwPollEvents();
@@ -319,7 +341,7 @@ int main(int argc, char* argv[]) {
FcFontSetDestroy(font_database);
FcObjectSetDestroy(requested_elements);
- FcPatternDestroy(blank_pattern);
+ FcPatternDestroy(request);
FcFini();
return 0;
diff --git a/tests/svg-parser-new/vkvg_svg_internal.h b/tests/svg-parser-new/vkvg_svg_internal.h
index c8d4ff1..749d5f7 100644
--- a/tests/svg-parser-new/vkvg_svg_internal.h
+++ b/tests/svg-parser-new/vkvg_svg_internal.h
@@ -30,6 +30,7 @@
#define LOG
#endif
#define LOGE(...) { fprintf(stdout, CLR_RED "[SVG] " __VA_ARGS__); fflush(stdout); }
+#define LOGW(...) { fprintf(stdout, CLR_YELLOW "[SVG] " __VA_ARGS__); fflush(stdout); }
#ifndef M_PIF
#define M_PIF ((float)3.14159265358979323846)