diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-09-18 11:38:05 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-01 13:29:27 +0200 |
| commit | fa2d1104677f27baea503882317e177d7fbfe6ab (patch) | |
| tree | 8c8937264ecd1a445294153f2e21efce5d5656e0 | |
| parent | 9012958b4b9731e2859bf6f6938700dd4745b70b (diff) | |
replace font names char* by 64bit hash (wip)
| -rw-r--r-- | CMakeLists.txt | 12 | ||||
| -rw-r--r-- | src/vkvg_context.c | 6 | ||||
| -rw-r--r-- | src/vkvg_context_internal.c | 5 | ||||
| -rw-r--r-- | src/vkvg_context_internal.h | 4 | ||||
| -rw-r--r-- | src/vkvg_fonts.c | 4 | ||||
| -rw-r--r-- | src/vkvg_fonts.h | 71 | ||||
| -rw-r--r-- | src/vkvg_internal.h | 23 |
7 files changed, 108 insertions, 17 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e47c09..10cac4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,7 +132,7 @@ endif() FIND_PACKAGE(Doxygen QUIET) CMAKE_DEPENDENT_OPTION(VKVG_USE_FREETYPE "use freetype to load and render font glyphs" ON "Freetype_FOUND" OFF) -CMAKE_DEPENDENT_OPTION(VKVG_USE_FONTCONFIG "use FontConfig to resolve font names" ON "Fontconfig_FOUND" OFF) +CMAKE_DEPENDENT_OPTION(VKVG_USE_FONTCONFIG "use FontConfig to resolve font names" OFF "Fontconfig_FOUND" OFF) CMAKE_DEPENDENT_OPTION(VKVG_USE_HARFBUZZ "use Harbuzz for text layouting" ON "HarfBuzz_FOUND" OFF) CMAKE_DEPENDENT_OPTION(VKVG_BUILD_TESTS "build tests with glfw" ON "GLFW3_FOUND" OFF) CMAKE_DEPENDENT_OPTION(VKVG_BUILD_DOCS "build documentation" OFF "DOXYGEN_FOUND" OFF) @@ -263,16 +263,16 @@ SOURCE_GROUP(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${VKVG_SRC}) ADD_LIBRARY("${PROJECT_NAME}" ${VKVG_SRC} ${VKVG_HEADERS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES - OUTPUT_NAME ${PROJECT_NAME} - VERSION ${vkvg_VERSION_MAJOR}.${vkvg_VERSION_MINOR} - SOVERSION ${vkvg_VERSION_MAJOR} - C_STANDARD 11 + OUTPUT_NAME ${PROJECT_NAME} + VERSION ${vkvg_VERSION_MAJOR}.${vkvg_VERSION_MINOR} + SOVERSION ${vkvg_VERSION_MAJOR} + C_STANDARD 11 C_STANDARD_REQUIRED ON C_EXTENSIONS ON POSITION_INDEPENDENT_CODE "${BUILD_SHARED_LIBS}" - PUBLIC_HEADER "${VKVG_PUBLIC_HEADERS}" + PUBLIC_HEADER "${VKVG_PUBLIC_HEADERS}" C_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON diff --git a/src/vkvg_context.c b/src/vkvg_context.c index c6fd714..aae1cef 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -56,7 +56,7 @@ void _init_ctx(VkvgContext ctx) { ctx->selectedCharSize = 10 << 6; ctx->currentFont = NULL; - ctx->selectedFontName[0] = 0; + ctx->selectedFontName = 0; ctx->pattern = NULL; ctx->curColor = 0xff000000; // opaque black ctx->cmdStarted = false; @@ -1359,7 +1359,7 @@ void vkvg_save(VkvgContext ctx) { sav->curFillRule = ctx->curFillRule; sav->selectedCharSize = ctx->selectedCharSize; - strcpy(sav->selectedFontName, ctx->selectedFontName); + sav->selectedFontName =ctx->selectedFontName; sav->currentFont = ctx->currentFont; sav->textDirection = ctx->textDirection; @@ -1496,7 +1496,7 @@ void vkvg_restore(VkvgContext ctx) { ctx->curFillRule = sav->curFillRule; ctx->selectedCharSize = sav->selectedCharSize; - strcpy(ctx->selectedFontName, sav->selectedFontName); + ctx->selectedFontName = sav->selectedFontName; ctx->currentFont = sav->currentFont; ctx->textDirection = sav->textDirection; diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index e89f332..5373035 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -1955,9 +1955,10 @@ void _draw_full_screen_quad(VkvgContext ctx, vec4* scissor) { } void _select_font_face(VkvgContext ctx, const char* name) { - if (strcmp(ctx->selectedFontName, name) == 0) + uint64_t h = fnv1a_64_str(name); + if (ctx->selectedFontName == h) return; - strcpy(ctx->selectedFontName, name); + ctx->selectedFontName = h; ctx->currentFont = NULL; ctx->currentFontSize = NULL; } diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 7858229..327bea5 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -114,7 +114,7 @@ typedef struct _vkvg_context_save_t { vkvg_fill_rule_t curFillRule; long selectedCharSize; /* Font size*/ - char selectedFontName[FONT_NAME_MAX_SIZE]; + uint64_t selectedFontName; _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; @@ -211,7 +211,7 @@ typedef struct _vkvg_context_t { vkvg_fill_rule_t curFillRule; long selectedCharSize; /* Font size*/ - char selectedFontName[FONT_NAME_MAX_SIZE]; + uint64_t selectedFontName; //_vkvg_font_t selectedFont; //hold current face and size before cache addition _vkvg_font_identity_t* currentFont; // font pointing to cached fonts identity _vkvg_font_t* currentFontSize; // font structure by size ready for lookup diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 0a57cc7..d9d9042 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -252,8 +252,6 @@ void _font_cache_destroy(VkvgDevice dev) { } free(f->sizes); free(f->fontFile); - for (uint32_t j = 0; j < f->namesCount; j++) - free(f->names[j]); if (f->namesCount > 0) free(f->names); free(f->fontBuffer); @@ -470,7 +468,7 @@ bool _tryFindFontByName(VkvgContext ctx, _vkvg_font_identity_t** font) { _font_cache_t* cache = ctx->dev->fontCache; for (int i = 0; i < cache->fontsCount; ++i) { for (uint32_t j = 0; j < cache->fonts[i].namesCount; j++) { - if (strcmp(cache->fonts[i].names[j], ctx->selectedFontName) == 0) { + if (cache->fonts[i].names[j] == ctx->selectedFontName) { *font = &cache->fonts[i]; return true; } diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index db9c546..4138ae1 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -63,6 +63,75 @@ #define FONT_FILE_NAME_MAX_SIZE 1024 #define FONT_NAME_MAX_SIZE 128 +// Bjoern Hoehrmann's UTF-8 State Magic Constants +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 1 + +static const uint8_t utf8d[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf + 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 +}; + +/** + * @brief Decodes a single byte stream step into a Unicode code point. + * @param state Pointer to the persistent decoder state tracker (initialize to UTF8_ACCEPT). + * @param codep Pointer to the resulting uint32_t Unicode scalar value. + * @param byte The raw next byte from the UTF-8 stream. + * @return uint32_t Returns UTF8_ACCEPT when a character is fully decoded. + */ +inline uint32_t decode_utf8_byte(uint32_t *const restrict state, uint32_t *const restrict codep, uint8_t byte) { + uint32_t type = utf8d[byte]; + + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xffu >> 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] = { + // 0x00 to 0x7F: Standard ASCII (1 byte) + 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,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,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,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,1,1,1,1,1,1,1,1, + + // 0x80 to 0xBF: Continuation bytes (invalid as first byte, but default to 1 to prevent infinite loops) + 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,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,1,1,1,1, + + // 0xC0 to 0xDF: Multi-byte leaders (2 bytes) + 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,2,2, + + // 0xE0 to 0xEF: Multi-byte leaders (3 bytes) + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + + // 0xF0 to 0xF7: Multi-byte leaders (4 bytes) + 4,4,4,4,4,4,4,4, + + // 0xF8 to 0xFF: Invalid UTF-8 (safely fallback to 1) + 1,1,1,1,1,1,1,1 +}; + +inline int get_utf8_char_length(uint8_t first_byte) { + return utf8_len_table[first_byte]; +} // texture coordinates of one character in font cache array texture. typedef struct { vec4 bounds; /* normalized float bounds of character bitmap in font cache texture. */ @@ -108,7 +177,7 @@ typedef struct { /* Font identification structure */ typedef struct { - char** names; /* Resolved Input names to this font by fontConfig or custom name set by @ref vkvg_load_from_path*/ + uint64_t names[5]; /* Resolved Input names to this font by fontConfig or custom name set by @ref vkvg_load_from_path. Maximum count is 5.*/ uint32_t namesCount; /* Count of resolved names by fontConfig */ unsigned char* fontBuffer; /* stb_truetype in memory buffer */ long fontBufSize; /* */ diff --git a/src/vkvg_internal.h b/src/vkvg_internal.h index 41761d0..876e2d8 100644 --- a/src/vkvg_internal.h +++ b/src/vkvg_internal.h @@ -53,6 +53,29 @@ #define M_2_PIF 0.63661977236758134308f // 2/pi #endif +/** + * @brief Computes the 64-bit FNV-1a hash of a ascii string lowering case. + * + * @param str Pointer to the start of the null terminated ascii string to hash. + * @return uint64_t The 64-bit hash value. + */ +inline uint64_t fnv1a_64_str(const char *const restrict str) { + uint64_t hash = 0xcbf29ce484222325ULL; + const uint8_t *restrict data = (const uint8_t *)str; + + while (*data) { + uint8_t c = *data; + // Fast branchless lowercase for ASCII font names/paths + if (c >= 'A' && c <= 'Z') { + c |= 0x20; + } + hash ^= c; + hash *= 0x00000100000001B3ULL; + data++; + } + + return hash; +} /*#ifndef M_2_PI #define M_2_PI 0.63661977236758134308 // 2/pi #endif*/ |