diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-01 12:07:01 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-01 13:29:27 +0200 |
| commit | 1e47b44f5e5284d2f0e8c8a2cab84c0f5680d8f4 (patch) | |
| tree | fc22df93962061c2ff5eb97bb2e5b74af3f42b22 | |
| parent | 9dab17b080f715c9597fa5d5a285ed81d600a8a0 (diff) | |
wip
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | include/vkvg.h | 5 | ||||
| -rw-r--r-- | src/vkvg_context_internal.h | 3 | ||||
| -rw-r--r-- | src/vkvg_device.c | 5 | ||||
| -rw-r--r-- | src/vkvg_fonts.c | 10 | ||||
| -rw-r--r-- | src/vkvg_fonts.h | 2 | ||||
| -rw-r--r-- | tests/font_tests/font_tests.c | 329 |
7 files changed, 343 insertions, 13 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index bb38ebc..ead44f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -343,11 +343,13 @@ IF (VKVG_BUILD_TESTS) ${HarfBuzz_INCLUDE_DIRS} ${Vulkan_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include + ${Fontconfig_INCLUDE_DIRS} ) TARGET_LINK_LIBRARIES(fonts_test PUBLIC #vkvg ${HarfBuzz_LIBRARIES} ${FREETYPE_LIBRARY} + ${Fontconfig_LIBRARIES} ${Vulkan_LIBRARIES} ) diff --git a/include/vkvg.h b/include/vkvg.h index fa588d6..0a52a0d 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -565,7 +565,10 @@ typedef struct { VkDevice vkdev; uint32_t qFamIdx; uint32_t qIndex; - bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ + bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ + const char* fontsDirectories; /**< Coma sepparated list of font directories to scan. + With font-config, leave empty for default system configuration. + Set FONTCONFIG_SYSROOT env variable if font-config complaints.*/ } vkvg_device_create_info_t; vkvg_public diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index d09535d..2fb5712 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -176,6 +176,8 @@ typedef struct _vkvg_context_t { VkvgDevice dev; VkvgSurface pSurf; // surface bound to context, set on creation of ctx + + #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE uint64_t timelineStep; // context cmd last submission timeline id. #else @@ -195,6 +197,7 @@ typedef struct _vkvg_context_t { vkh_buffer_t uboGrad; // uniform buff obj holdings gradient infos vkh_buffer_t indices; // index buffer with persistent map memory vkh_buffer_t vertices; // vertex buffer with persistent mapped memory + Vertex* vertexCache; VKVG_IBO_INDEX_TYPE* indexCache; vec2* points; // points array diff --git a/src/vkvg_device.c b/src/vkvg_device.c index 25d4482..f9ed284 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -112,8 +112,9 @@ void _device_init(VkvgDevice dev, const vkvg_device_create_info_t* info) { dev->cmd = vkh_cmd_buff_create(vkhd, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); dev->fence = vkh_fence_create_signaled(vkhd); - _device_create_pipeline_cache(dev); - _fonts_cache_create(dev); + //_device_create_pipeline_cache(dev); + _fonts_cache_create(dev, info->fontsDirectories); + if (dev->deferredResolve || dev->samples == VK_SAMPLE_COUNT_1_BIT) { dev->renderPass = _device_createRenderPassNoResolve(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 9a109c0..2ddbb93 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -38,14 +38,20 @@ static int defaultFontCharSize = 12 << 6; -void _fonts_cache_create(VkvgDevice dev) { +void _fonts_cache_create(VkvgDevice dev, const char* fontDirs) { _font_cache_t* cache = (_font_cache_t*)calloc(1, sizeof(_font_cache_t)); if (dev->threadAware) mtx_init(&cache->mutex, mtx_plain); #ifdef VKVG_USE_FONTCONFIG - cache->config = FcInitLoadConfigAndFonts(); + if (!FcInit()) { + LOG(VKVG_LOG_ERR, "Font config initialisation failed\n"); + dev->status = VKVG_STATUS_DEVICE_ERROR; + free(cache); + return; + } + cache->config = FcConfigGetCurrent(); if (!cache->config) { LOG(VKVG_LOG_DEBUG, "Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\ diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index 60fd80f..037c254 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -245,7 +245,7 @@ typedef struct _vkvg_text_run_t { } vkvg_text_run_t; // Create font cache. -void _fonts_cache_create(VkvgDevice dev); +void _fonts_cache_create(VkvgDevice dev, const char *fontDirs); // Release all ressources of font cache. void _font_cache_destroy(VkvgDevice dev); _vkvg_font_identity_t* _font_cache_add_font_identity(VkvgContext ctx, const char* fontFile, const char* name); diff --git a/tests/font_tests/font_tests.c b/tests/font_tests/font_tests.c index 6cc2608..8d29a45 100644 --- a/tests/font_tests/font_tests.c +++ b/tests/font_tests/font_tests.c @@ -7,6 +7,7 @@ #include FT_MULTIPLE_MASTERS_H +#include <fontconfig/fontconfig.h> /* serif Liberation Serif, DejaVu Serif, Times @@ -20,6 +21,162 @@ math fangsong traditional chinese */ +typedef enum { + + OldstyleSerifs = 0x0100, + NoClassification = 0x0100, + IBMRoundedLegibility = 0x0101, + Garalde = 0x0102, + Venetian = 0x0103, + ModifiedGaralde = 0x0104, + DutchModern = 0x0105, + Centaur = 0x0106, + NoStyle = 0x0107, + Contemporary = 0x0108, + TransitionalSerifs = 0x0200, + DirectLine = 0x0201, + ScriptStyle = 0x0202, + Neoclassical = 0x0203, + Modern = 0x0204, + Clarendon = 0x0205, + SlabSerif = 0x0206, + Typewriter = 0x0207, + ModernSerifs = 0x0300, + Italian = 0x0301, + ModernSerifsScriptStyle = 0x0302, + ClarendonSerifs = 0x0400, + ModernSerifsClarendon = 0x0401, + ModernClarendon = 0x0402, + TraditionalClarendon = 0x0403, + NewspaperClarendon = 0x0404, + StubSerif = 0x0405, + Monospaced = 0x0406, + FreeformSerifs = 0x0500, + FreeformSerifsModern = 0x0501, + Traditional = 0x0502, + SansSerif = 0x0700, + IBMNeogrotesqueGothic = 0x0701, + Humanist = 0x0702, + LowcontrastGrotesque = 0x0703, + HighcontrastGrotesque = 0x0704, + NeogrotesqueGothic = 0x0705, + ModifiedNeogrotesqueGothic = 0x0706, + GeometricGrotesque = 0x0707, + GeometricHumanist = 0x0708, + GrotesqueGothic = 0x0709, + Ornamentals = 0x0800, + + Engraved = 0x0801, + Novelty = 0x0802, + Retro = 0x0803, + Synthetic = 0x0804, + + Scripts = 0x0900, + Uncial = 0x0901, + BrushCalligraphy = 0x0902, + FormalCalligraphy = 0x0903, + MonolineCalligraphy = 0x0904, + TraditionalCalligraphy = 0x0905, + ContemporaryCalligraphy = 0x0906, + Cursive = 0x0907, + Calligraphic = 0x0908, + InlineOutline = 0x0909, + Symbolic = 0x0A00, + MixedSerif = 0x0A01, + OldstyleSerif = 0x0A02, + NeoclassicalSerif = 0x0A03, + ModernSerif = 0x0A04, + ClarendonSerif = 0x0A05, + SymbolicSansSerif = 0x0A07, + Ornamental = 0x0A08, + Script = 0x0A09, + Texture = 0x0A0A, +} font_class; + +/* +Class 0x01 — Oldstyle Serifs + 0x0100 (Subclass 0x00): No Classification + 0x0101 (Subclass 0x01): IBM Rounded Legibility + 0x0102 (Subclass 0x02): Garalde + 0x0103 (Subclass 0x03): Venetian + 0x0104 (Subclass 0x04): Modified Garalde + 0x0105 (Subclass 0x05): Dutch Modern + 0x0106 (Subclass 0x06): Centaur + 0x0107 (Subclass 0x07): No Style + 0x0108 (Subclass 0x08): Contemporary + +Class 0x02 — Transitional Serifs + 0x0200 (Subclass 0x00): No Classification + 0x0201 (Subclass 0x01): Direct Line + 0x0202 (Subclass 0x02): Script Style + 0x0203 (Subclass 0x03): Neo-classical + 0x0204 (Subclass 0x04): Modern + 0x0205 (Subclass 0x05): Clarendon + 0x0206 (Subclass 0x06): Slab Serif + 0x0207 (Subclass 0x07): Typewriter + +Class 0x03 — Modern Serifs + 0x0300 (Subclass 0x00): No Classification + 0x0301 (Subclass 0x01): Italian + 0x0302 (Subclass 0x02): Script Style + +Class 0x04 — Clarendon Serifs + 0x0400 (Subclass 0x00): No Classification + 0x0401 (Subclass 0x01): Clarendon + 0x0402 (Subclass 0x02): Modern Clarendon + 0x0403 (Subclass 0x03): Traditional Clarendon + 0x0404 (Subclass 0x04): Newspaper Clarendon + 0x0405 (Subclass 0x05): Stub Serif + 0x0406 (Subclass 0x06): Monospaced + +Class 0x05 — Freeform Serifs + 0x0500 (Subclass 0x00): No Classification + 0x0501 (Subclass 0x01): Modern + 0x0502 (Subclass 0x02): Traditional + +Class 0x07 — Sans Serif + 0x0700 (Subclass 0x00): No Classification + 0x0701 (Subclass 0x01): IBM Neo-grotesque Gothic + 0x0702 (Subclass 0x02): Humanist + 0x0703 (Subclass 0x03): Low-contrast Grotesque + 0x0704 (Subclass 0x04): High-contrast Grotesque + 0x0705 (Subclass 0x05): Neo-grotesque Gothic + 0x0706 (Subclass 0x06): Modified Neo-grotesque Gothic + 0x0707 (Subclass 0x07): Geometric Grotesque + 0x0708 (Subclass 0x08): Geometric Humanist + 0x0709 (Subclass 0x09): Grotesque Gothic + +Class 0x08 — Ornamentals + 0x0800 (Subclass 0x00): No Classification + 0x0801 (Subclass 0x01): Engraved + 0x0802 (Subclass 0x02): Novelty + 0x0803 (Subclass 0x03): Retro + 0x0804 (Subclass 0x04): Synthetic + +Class 0x09 — Scripts + 0x0900 (Subclass 0x00): No Classification + 0x0901 (Subclass 0x01): Uncial + 0x0902 (Subclass 0x02): Brush Calligraphy + 0x0903 (Subclass 0x03): Formal Calligraphy + 0x0904 (Subclass 0x04): Monoline Calligraphy + 0x0905 (Subclass 0x05): Traditional Calligraphy + 0x0906 (Subclass 0x06): Contemporary Calligraphy + 0x0907 (Subclass 0x07): Cursive + 0x0908 (Subclass 0x08): Calligraphic + 0x0909 (Subclass 0x09): Inline / Outline + +Class 0x0A — Symbolic + 0x0A00 (Subclass 0x00): No Classification + 0x0A01 (Subclass 0x01): Mixed Serif + 0x0A02 (Subclass 0x02): Oldstyle Serif + 0x0A03 (Subclass 0x03): Neo-classical Serif + 0x0A04 (Subclass 0x04): Modern Serif + 0x0A05 (Subclass 0x05): Clarendon Serif + 0x0A07 (Subclass 0x07): Sans Serif + 0x0A08 (Subclass 0x08): Ornamental + 0x0A09 (Subclass 0x09): Script + 0x0A0A (Subclass 0x0A): Texture +*/ #include <sys/types.h> #include <sys/stat.h> @@ -286,6 +443,7 @@ void process_font_file (const char* const fontDir, const char* fontFile) { font_weight weight = font_weight_normal; font_width width = font_width_normal; font_slant slant = font_slant_regular; + FT_Int16 fntClass = 0; FT_Error error = FT_New_Face(library, path, 0, &face ); if (error) { @@ -316,9 +474,10 @@ void process_font_file (const char* const fontDir, const char* fontFile) { weight = os2_table->usWeightClass; width = os2_table->usWidthClass; slant = os2_table->fsSelection; + fntClass = os2_table->sFamilyClass; } - printf("\tWeight: %4d width: %4d slant: %4d\n", weight, width, slant); + printf("\tClass %04x Weight: %4d width: %4d slant: %4d\n",fntClass, weight, width, slant); FT_UInt sfntCount = FT_Get_Sfnt_Name_Count(face); @@ -349,15 +508,17 @@ void process_font_file (const char* const fontDir, const char* fontFile) { name.name_id == TT_NAME_ID_FULL_NAME || name.name_id == TT_NAME_ID_TYPOGRAPHIC_FAMILY || name.name_id == TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY || + //name.name_id == TT_NAME_ID_WWS_FAMILY || + //name.name_id == TT_NAME_ID_WWS_SUBFAMILY || name.name_id == TT_NAME_ID_UNIQUE_ID) { - fprintf(stdout, "sfntName(%1d:%3d:%4d:%6d): %-20s = ", name.platform_id, name.encoding_id, name.language_id, name.name_id, sfnt_nameid_to_string(name.name_id)); + /*fprintf(stdout, "sfntName(%1d:%3d:%4d:%6d): %-20s = ", name.platform_id, name.encoding_id, name.language_id, name.name_id, sfnt_nameid_to_string(name.name_id)); if (name.platform_id == 3) { convert_utf16be_to_ascii(name.string, name.string_len, stringAscii, 1024); fprintf(stdout, "%s\n", stringAscii); } else { fprintf(stdout, "%.*s\n", name.string_len, name.string); - } + }*/ fflush(stdout); } else @@ -575,6 +736,152 @@ void radix_sort_structs(font_id_t *array, size_t n) { free(dst); } +void font_config_tests () { + if (!FcInit()) { + fprintf(stderr, "Fatal Error: Failed to initialize Fontconfig.\n"); + return; + } + + // Load the system configuration and default user fonts + FcConfig* config = FcConfigGetCurrent(); + + // 2. Create an empty pattern filter (empty means "Match everything") + FcPattern* blank_pattern = FcPatternCreate(); + + // 3. Declare exactly what metadata elements you want to extract + // Passing trailing 0/NULL tells the builder array arguments are complete + FcObjectSet* requested_elements = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_FILE, (char *)0); + + // 4. Generate the sorted unique array list of matching fonts + FcFontSet* font_database = FcFontList(config, blank_pattern, requested_elements); + + if (font_database) { + printf("Successfully indexed %d font variants.\n\n", font_database->nfont); + + for (int i = 0; i < font_database->nfont; i++) { + FcPattern* font_entry = font_database->fonts[i]; + + FcChar8* family_name = NULL; + FcChar8* style_variant = NULL; + FcChar8* file_path = NULL; + + // Extract the strings cleanly out of the font structure + if (FcPatternGetString(font_entry, FC_FAMILY, 0, &family_name) == FcResultMatch && + FcPatternGetString(font_entry, FC_STYLE, 0, &style_variant) == FcResultMatch) { + + // Optional: Also fetch the file system location if you need to open it in FreeType + FcPatternGetString(font_entry, FC_FILE, 0, &file_path); + + printf("[%d] Family: %s \n Style: %s\n Path: %s\n\n", + i + 1, family_name, style_variant, file_path ? (char*)file_path : "Unknown"); + } + } + + // 5. Always free memory assets to prevent memory leaks + FcFontSetDestroy(font_database); + } + + FcObjectSetDestroy(requested_elements); + FcPatternDestroy(blank_pattern); + FcFini(); // Clean up environment space +} + +void font_config_sandboxing() { + setenv("FONTCONFIG_SYSROOT", "/tmp", 1); + + // 1. Create a brand new, completely blank configuration instance + FcConfig* local_config = FcConfigCreate(); + if (!local_config) { + fprintf(stderr, "Failed to create custom Fontconfig configuration.\n"); + return; + } + + // 2. Define your local asset path + const FcChar8* font_dir = (const FcChar8*)"/usr/local/share/fonts"; + + // 3. Force Fontconfig to scan this directory and add it to the local config instance + // This parses the font binaries in this directory into memory. + if (!FcConfigAppFontAddDir(local_config, font_dir)) { + fprintf(stderr, "Failed to register application font directory: %s\n", font_dir); + FcConfigDestroy(local_config); + return; + } + + // 4. (Optional but Recommended) Bind this config as the active thread configuration. + // This ensures subsequent generic Fc calls use your lightweight sandbox. + FcConfigSetCurrent(local_config); + + printf("Fontconfig sandboxed successfully. Scanning only: %s\n\n", font_dir); + + // ========================================================================= + // Example: Let's query our sandbox for a font to prove it works + // ========================================================================= + + // Create a request pattern + FcPattern* request = FcPatternCreate(); + FcPatternAddString(request, FC_FAMILY, (const FcChar8*)"sans-serif"); + + // Apply substitutions using our custom config object instead of NULL (system default) + FcConfigSubstitute(local_config, request, FcMatchPattern); + FcDefaultSubstitute(request); + + FcResult result; + // Match against our clean, local configuration file list + FcPattern* matched_font = FcFontMatch(local_config, request, &result); + + if (matched_font) { + FcChar8* file_path = NULL; + FcChar8* family_name = NULL; + + if (FcPatternGetString(matched_font, FC_FILE, 0, &file_path) == FcResultMatch && + FcPatternGetString(matched_font, FC_FAMILY, 0, &family_name) == FcResultMatch) { + + printf("Successfully matched!\n"); + printf("Family: %s\n", family_name); + printf("File Path: %s\n", file_path); + } + FcPatternDestroy(matched_font); + } else { + printf("No matching font found in the local asset folder.\n"); + } + + // 5. Cleanup + FcPatternDestroy(request); + + // This unloads the memory assets allocated by FcConfigCreate + FcConfigDestroy(local_config); + + // Clean up global libraries state + FcFini(); +} + +/* requesting variable font + * +FcPattern* request = FcPatternCreate(); +FcPatternAddString(request, FC_FAMILY, (const FcChar8*)"Roboto Flex"); +FcPatternAddString(request, FC_FONT_VARIATIONS, (const FcChar8*)"wght=625,wdth=80"); +*/ + +void setup_variable_font(FcPattern* matched_font) { + // 1. Verify if the font handles open vector variables + FcBool is_variable = FcFalse; + if (FcPatternGetBool(matched_font, FC_VARIABLE, 0, &is_variable) == FcResultMatch && is_variable) { + printf("This matched font file is variable-capable!\n"); + } + + // 2. Extract specific axis configuration parameters requested by a pattern string + // This returns a string formatted exactly like CSS: "wght=525.0,wdth=85.5" + FcChar8* variations_string = NULL; + if (FcPatternGetString(matched_font, FC_FONT_VARIATIONS, 0, &variations_string) == FcResultMatch) { + printf("Requested layout coordinates: %s\n", variations_string); + + // 3. You can pass this string directly to your rendering subsystem. + // Inside FreeType, you convert this string into an array of FT_Fixed coordinates + // and apply it directly via: + // FT_Set_Var_Design_Coordinates(face, num_coords, coords); + } +} + int main(int argc, char* argv[]) { int i = 1; char* output = NULL; @@ -608,7 +915,15 @@ int main(int argc, char* argv[]) { exit(-1); } + //font_config_tests(); + font_config_sandboxing(); + + + + //font_id_cache = array_create(); + +/* font_names = array_create(); font_sub_names = array_create(); @@ -616,9 +931,9 @@ int main(int argc, char* argv[]) { parse_font_dir(directory); } printf("Total font files: %d\n", fontIndex); - - radix_sort_structs(font_id_cache, fontIndex); +*/ + /*for (int i = 0; i < fontIndex; ++i) { printf("%lu %u %u\n", font_id_cache[i].pathHash, font_id_cache[i].nameHash, font_id_cache[i].styleHash); @@ -639,7 +954,7 @@ int main(int argc, char* argv[]) { } printf("==============================\n");*/ - array_destroy(font_names); - array_destroy(font_sub_names); + // array_destroy(font_names); + // array_destroy(font_sub_names); } |