summaryrefslogtreecommitdiffstatsci
diff options
context:
space:
mode:
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>2026-10-13 11:10:04 +0200
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>2026-10-13 11:10:04 +0200
commitd238e7da22967f8da18e6aa03233417f8554e040 (patch)
tree2df0f17ba97e180a988feac13087d9afea9e9107
parent426535e4cd481b3bf65af4798ab05a7af1a2a1fc (diff)
variable font support when freetype and fontconfig are enabled
-rw-r--r--src/vkvg_context.c2
-rw-r--r--src/vkvg_fonts.c108
-rw-r--r--src/vkvg_fonts.h4
3 files changed, 94 insertions, 20 deletions
diff --git a/src/vkvg_context.c b/src/vkvg_context.c
index 79dcd53..be91447 100644
--- a/src/vkvg_context.c
+++ b/src/vkvg_context.c
@@ -1240,7 +1240,7 @@ void vkvg_set_text_direction(vkvg_context* ctx, vkvg_direction_t direction) {
}
void vkvg_show_text(VkvgContext ctx, const char* text) {
- if (vkvg_status(ctx))
+ if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont))
return;
RECORD(ctx, VKVG_CMD_SHOW_TEXT, text);
LOG(VKVG_LOG_INFO_CMD, "CMD: show_text:\n");
diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c
index 3752c8d..bbaba7d 100644
--- a/src/vkvg_fonts.c
+++ b/src/vkvg_fonts.c
@@ -623,22 +623,23 @@ bool try_create_font_face_from_path (VkvgDevice dev, const char *fontFile, int f
*face = newFace;
return true;
}
-bool try_get_or_create_font_face_from_query (VkvgDevice dev, const char* queryString, FontFace *const face) {
+
+bool try_get_or_create_font_face_from_query (VkvgDevice dev, const char* queryString, FontFace *const face,
+ signed long** pCoords) {
_font_cache_t* cache = dev->fontCache;
uint64_t queryHash = fnv1a_64_str(queryString);
*face = NULL;
- if (try_get_font_face_from_query_hash(cache, queryHash, face))
+#ifdef VKVG_USE_FONTCONFIG
+ if (try_get_font_face_from_query_hash(cache, queryHash, face) && (*face)->numAxis > 0)
return true;
-#ifdef VKVG_USE_FONTCONFIG
FcPattern* request = FcNameParse((const FcChar8*)queryString);
- FcPatternAddBool(request, FC_SCALABLE, FcTrue);
- FcPatternAddString(request, FC_FONTFORMAT, (const FcChar8 *)"TrueType");
-
- FcConfigSubstitute(cache->config, request, FcMatchPattern);
- FcDefaultSubstitute(request);
+ //FcPatternAddBool(request, FC_SCALABLE, FcTrue);
+ //FcPatternAddString(request, FC_FONTFORMAT, (const FcChar8 *)"TrueType");
+ //FcConfigSubstitute(cache->config, request, FcMatchPattern);
+ //FcDefaultSubstitute(request);
FcResult result;
FcPattern* font = FcFontMatch(cache->config, request, &result);
@@ -649,11 +650,52 @@ bool try_get_or_create_font_face_from_query (VkvgDevice dev, const char* querySt
FcPatternGetString (font, FC_FILE, 0, (FcChar8**)&fontFile);
FcPatternGetInteger (font, FC_INDEX, 0, &index);
- if (!try_create_font_face_from_path(dev, fontFile, index, face)) {
+ if (!*face && !try_create_font_face_from_path(dev, fontFile, index, face))
goto exit_failed;
- }
+
array_add_uint64_t (&(*face)->queryHashes, queryHash);
+#if VKVG_USE_FREETYPE
+ FT_Face ftface = (*face)->face;
+ FT_MM_Var* mm_var = NULL;
+ if (!FT_Get_MM_Var(ftface, &mm_var)) {
+ FT_Fixed* coords = (FT_Fixed*)malloc(sizeof(FT_Fixed) * mm_var->num_axis);
+ int num_axes_retrieved = 0;
+ FcChar8* var_string = NULL;
+ if (FcPatternGetString(font, FC_FONT_VARIATIONS, 0, &var_string) == FcResultMatch) {
+ for (FT_UInt i = 0; i < mm_var->num_axis; i++) {
+ coords[i] = mm_var->axis[i].def;
+ }
+ char* token = strtok((char*)var_string, ",");
+ while (token != NULL) {
+ char axis_name[5] = {0};
+ float axis_val = 0.0f;
+
+ // Parse out the 4-character tag and its companion numerical scalar value
+ if (sscanf(token, "%4[^=]=%f", axis_name, &axis_val) == 2) {
+ // Convert tag string directly to a 32-bit OpenType Tag integer
+ FT_Long target_tag = FT_MAKE_TAG(axis_name[0], axis_name[1], axis_name[2], axis_name[3]);
+
+ // Match our parsed tag against the axes array exposed by FreeType
+ for (FT_UInt i = 0; i < mm_var->num_axis; i++) {
+ if (mm_var->axis[i].tag == target_tag) {
+ // FreeType handles design positions in 16.16 Fixed Point formats
+ coords[i] = (FT_Fixed)(axis_val * 65536.0f);
+ break;
+ }
+ }
+ }
+ token = strtok(NULL, ",");
+ }
+ *pCoords = coords;
+ (*face)->numAxis = mm_var->num_axis;
+ FT_Done_MM_Var(cache->library, mm_var);
+ }
+
+ }
+
+#endif
+
FcPatternDestroy(request);
FcPatternDestroy(font);
return true;
@@ -661,14 +703,22 @@ bool try_get_or_create_font_face_from_query (VkvgDevice dev, const char* querySt
exit_failed:
FcPatternDestroy(request);
FcPatternDestroy(font);
+#else
+ if (try_get_font_face_from_query_hash(cache, queryHash, face))
+ return true;
#endif
return false;
}
-bool try_get_font_size (FontFace face, uint32_t pt26_6, VkvgFont *font) {
+bool try_get_font_size (FontFace face, uint32_t pt26_6, signed long* coords, VkvgFont *font) {
*font = NULL;
for (int i = 0; i < face->sizes.count; ++i) {
- if (face->sizes.elements[i]->charSize == pt26_6) {
- *font = face->sizes.elements[i];
+ VkvgFont f = face->sizes.elements[i];
+ if (f->charSize == pt26_6) {
+ for (int axe = 0; axe < face->numAxis; ++axe) {
+ if (f->coords[axe] != coords[axe])
+ return false;
+ }
+ *font = f;
return true;
}
}
@@ -697,9 +747,13 @@ hb_buffer_t* _get_hb_buffer(VkvgText textRun, const char* text, int length) {
void _font_lock_size (VkvgFont font) {
#ifdef VKVG_USE_FREETYPE
FT_Face face = font->face->face;
- if (face->size != font->ftSize) {
+ if (face->size != font->ftSize || font->face->coords != font->coords) {
if (font->dev->threadAware)
mtx_lock(&font->face->mutex);
+ if (font->coords && font->face->coords != font->coords) {
+ FT_Set_Var_Design_Coordinates(face, font->face->numAxis, font->coords);
+ font->face->coords = font->coords;
+ }
FT_CHECK_RESULT(FT_Activate_Size(font->ftSize));
#ifdef VKVG_USE_HARFBUZZ
hb_font_t* hbf = font->face->hb_font;
@@ -941,7 +995,7 @@ void* vkvg_font_get_face(VkvgFont font) {
#endif
}
-VkvgFont _create_font_from_face (VkvgDevice dev, FontFace face, float pointSize) {
+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");
@@ -951,12 +1005,17 @@ VkvgFont _create_font_from_face (VkvgDevice dev, FontFace face, float pointSize)
font->face = face;
#ifdef VKVG_USE_FREETYPE
+ if (dev->threadAware)
+ mtx_lock(&font->face->mutex);
+ 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);
free(font);
+ if (dev->threadAware)
+ mtx_lock(&font->face->mutex);
return (VkvgFont)&_vkvg_status_null_pointer;
} else {
char tmp[1024];
@@ -969,6 +1028,10 @@ VkvgFont _create_font_from_face (VkvgDevice dev, FontFace face, float pointSize)
FT_CHECK_RES(FT_New_Size (face->face, &font->ftSize));
FT_CHECK_RES(FT_Activate_Size(font->ftSize));
FT_CHECK_RES(FT_Set_Char_Size(face->face, 0, font->charSize, dev->hdpi, dev->vdpi));
+ if (font->coords) {
+ FT_Set_Var_Design_Coordinates(face->face, font->face->numAxis, font->coords);
+ font->face->coords = font->coords;
+ }
font->charLookup = (glyph_ref*)calloc(face->face->num_glyphs, sizeof(glyph_ref));
@@ -978,6 +1041,9 @@ VkvgFont _create_font_from_face (VkvgDevice dev, FontFace face, float pointSize)
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);
@@ -1004,15 +1070,17 @@ VkvgFont vkvg_font_create_from_file (VkvgDevice dev, const char* fontFilePath, i
if (!try_create_font_face_from_path(dev, fontFilePath, faceIndex, &face) || !face) {
return NULL;
}
- return _create_font_from_face(dev, face, pointSize);
+ return _create_font_from_face(dev, face, pointSize, NULL);
}
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;
- if (try_get_or_create_font_face_from_query(dev, query, &face)) {
- if (try_get_font_size(face, pt26_6, &font)) {
+ signed long* coords;
+ unsigned int numAxis;
+ 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;
}
@@ -1020,7 +1088,7 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) {
if (!face)
return NULL;
- return _create_font_from_face(dev, face, pointSize);
+ return _create_font_from_face(dev, face, pointSize, coords);
}
VkvgFont vkvg_font_reference(VkvgFont font) {
if (!vkvg_font_status(font))
@@ -1041,6 +1109,8 @@ void vkvg_font_destroy(VkvgFont font) {
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) {
diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h
index e898ec8..00c1edc 100644
--- a/src/vkvg_fonts.h
+++ b/src/vkvg_fonts.h
@@ -14,6 +14,7 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_SIZES_H
+#include FT_MULTIPLE_MASTERS_H
#if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
#include <freetype/ftlcdfil.h>
#endif
@@ -199,6 +200,8 @@ typedef struct _vkvg_font_face_t{
#ifdef VKVG_USE_FREETYPE
FT_Face face; /* FreeType face*/
mtx_t mutex; /* Only one font size at a time may use this face */
+ signed long* coords; /* Active coordinates for variable fonts */
+ unsigned int numAxis; /* face axis count */
#else
stbtt_fontinfo stbInfo; /* stb_truetype structure */
int ascent; /* unscalled stb font metrics */
@@ -235,6 +238,7 @@ typedef struct _vkvg_font_t {
#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
float charSize; /* Font size in pixel */
float scale; /* scale factor for the given size */