fontconfig: Branch 'main' - 3 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Apr 25 06:56:50 UTC 2025


 doc/fcconfig.fncs       |   10 +++++
 fontconfig/fontconfig.h |    3 +
 src/fccfg.c             |   12 ++++++
 src/fcint.h             |    3 +
 src/fcmatch.c           |   22 ++++++++----
 src/fcxml.c             |    2 +
 test/run-test-conf.sh   |    1 
 test/test-appfont.json  |   75 +++++++++++++++++++++++++++++++++++++++++
 test/test-conf.c        |   86 ++++++++++++++++++++++++++++++++++++++----------
 9 files changed, 190 insertions(+), 24 deletions(-)

New commits:
commit 2e4e6655c716b495374b6b1f3dd7552e860c82c4
Merge: dd5c5fd 9268bb6
Author: Akira TAGOH <akira at tagoh.org>
Date:   Fri Apr 25 06:56:45 2025 +0000

    Merge branch 'issues/455' into 'main'
    
    Add API to allow changing the order of application fonts
    
    Closes #455
    
    See merge request fontconfig/fontconfig!379

commit 9268bb64bebd1e46a0433d780ebdeea49fc53d95
Author: Akira TAGOH <akira at tagoh.org>
Date:   Fri Apr 25 14:30:21 2025 +0900

    Add FcConfigPerferAppFont() to allow changing the order of application fonts
    
    This basically takes effect for FcFont(Set)Sort only.
    FcFont(Set)Match works without this change and
    FcFont(Set)List doesn't need it.
    
    Fixes https://gitlab.freedesktop.org/fontconfig/fontconfig/-/issues/455
    
    Changelog: added

diff --git a/doc/fcconfig.fncs b/doc/fcconfig.fncs
index 0a072af..7517577 100644
--- a/doc/fcconfig.fncs
+++ b/doc/fcconfig.fncs
@@ -544,3 +544,13 @@ in configuration file. This function tries to match 'pat' with them and
 return FcFalse if 'pat' is rejected, otherwise FcTrue.
 @SINCE@		2.15.1
 @@
+
+ at RET@       void
+ at FUNC@      FcConfigPreferAppFont
+ at TYPE1@     FcConfig *          @ARG1@      config
+ at TYPE2@     FcBool%             @ARG2@      flag
+ at DESC@
+Set 'flag' to change the priority of Application fonts. default behavior is turned off
+for backward compatibility.
+ at SINCE@     2.17.0
+@@
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
index bd04884..6326636 100644
--- a/fontconfig/fontconfig.h
+++ b/fontconfig/fontconfig.h
@@ -485,6 +485,9 @@ FcConfigAppFontAddDir (FcConfig      *config,
 FcPublic void
 FcConfigAppFontClear (FcConfig *config);
 
+FcPublic void
+FcConfigPreferAppFont (FcConfig *config, FcBool flag);
+
 FcPublic FcBool
 FcConfigSubstituteWithPat (FcConfig   *config,
                            FcPattern  *p,
diff --git a/src/fccfg.c b/src/fccfg.c
index 8b82b42..cfa0920 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -2776,6 +2776,18 @@ FcConfigAppFontClear (FcConfig *config)
     FcConfigDestroy (config);
 }
 
+void
+FcConfigPreferAppFont (FcConfig *config, FcBool flag)
+{
+    config = FcConfigReference (config);
+    if (!config)
+	return;
+
+    config->prefer_app_fonts = flag;
+
+    FcConfigDestroy (config);
+}
+
 /*
  * Manage filename-based font source selectors
  */
diff --git a/src/fcint.h b/src/fcint.h
index 334cde0..e422c72 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -613,6 +613,9 @@ struct _FcConfig {
     FcFilterFontSetFunc filter_func;       /* A predicate function to filter out config->fonts */
     FcDestroyFunc       destroy_data_func; /* A callback function to destroy config->filter_data */
     void               *filter_data;       /* An user data to be used for filter_func */
+
+    FcBool prefer_app_fonts; /* Whether FcSetApplication has a priority than
+                                FcSetSystem for lookup */
 };
 
 typedef struct _FcFileTime {
diff --git a/src/fcmatch.c b/src/fcmatch.c
index 444709c..d8523a1 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -564,7 +564,7 @@ FcCompareFamilies (FcPattern     *pat,
 	}
     }
     if (FcDebug() & FC_DBG_MATCHV) {
-	printf ("%s: %g ", FcObjectName (FC_FAMILY_OBJECT), strong_value);
+	printf ("%s: %g (%g) ", FcObjectName (FC_FAMILY_OBJECT), strong_value, weak_value);
 	FcValueListPrint (v1orig);
 	printf (", ");
 	FcValueListPrint (v2orig);
@@ -1107,7 +1107,7 @@ FcFontSetSortDestroy (FcFontSet *fs)
 }
 
 FcFontSet *
-FcFontSetSort (FcConfig   *config FC_UNUSED,
+FcFontSetSort (FcConfig   *config,
                FcFontSet **sets,
                int         nsets,
                FcPattern  *p,
@@ -1186,6 +1186,13 @@ FcFontSetSort (FcConfig   *config FC_UNUSED,
 	    newp->pattern = s->fonts[f];
 	    if (!FcCompare (p, newp->pattern, newp->score, result, &data))
 		goto bail1;
+	    /* TODO: Should we check a FcPattern in FcFontSet?
+	     * This way may not work if someone has own list of application fonts
+	     * That said, just to reduce the cost for lookup so far.
+             */
+	    if (config->prefer_app_fonts && s != config->fonts[FcSetApplication]) {
+		newp->score[PRI_ORDER] += 1000;
+	    }
 	    if (FcDebug() & FC_DBG_MATCHV) {
 		printf ("Score");
 		for (i = 0; i < PRI_END; i++) {
@@ -1260,12 +1267,13 @@ FcFontSetSort (FcConfig   *config FC_UNUSED,
 
     free (nodes);
 
-    if (FcDebug() & FC_DBG_MATCH) {
-	printf ("First font ");
-	FcPatternPrint (ret->fonts[0]);
-    }
-    if (ret->nfont > 0)
+    if (ret->nfont > 0) {
 	*result = FcResultMatch;
+	if (FcDebug() & FC_DBG_MATCH) {
+	    printf ("First font ");
+	    FcPatternPrint (ret->fonts[0]);
+	}
+    }
 
     return ret;
 
diff --git a/test/run-test-conf.sh b/test/run-test-conf.sh
index 88407cd..e87bcc5 100644
--- a/test/run-test-conf.sh
+++ b/test/run-test-conf.sh
@@ -54,6 +54,7 @@ for i in \
 	test-issue-286.json \
 	test-style-match.json \
 	test-filter.json \
+	test-appfont.json \
     ; do
     echo $RUNNER $TESTDIR/$i ...
     $RUNNER $TESTDIR/../conf.d/10-autohint.conf $TESTDIR/$i
diff --git a/test/test-appfont.json b/test/test-appfont.json
new file mode 100644
index 0000000..4ecc15d
--- /dev/null
+++ b/test/test-appfont.json
@@ -0,0 +1,75 @@
+{
+    "fonts": [
+	{
+	    "family": [
+		"Foo"
+	    ],
+	    "style": [
+		"Regular"
+	    ],
+	    "lang": "en",
+	    "charset": [
+		"a",
+            "b"
+	    ],
+	    "file": "/system/path/to/Foo.ttf",
+	    "fontversion": 1,
+	}
+    ],
+    "appfonts": [
+	{
+	    "family": [
+		"Foo"
+	    ],
+	    "style": [
+		"Regular"
+	    ],
+	    "lang": "en",
+	    "charset": [
+		"a",
+            "b"
+	    ],
+	    "file": "/app/path/to/Foo.ttf",
+	    "fontversion": 2,
+	}
+    ],
+    "tests": [
+	{
+	    "config": {
+		"prefer_app_font": false
+	    },
+	    "method": "sort",
+	    "query": {
+		"family": "Foo",
+		"style": "Regular"
+	    },
+	    "result_fs": [
+		{
+		    "family": "Foo",
+		    "style": "Regular",
+		    "file": "/system/path/to/Foo.ttf",
+		    "fontversion": 1
+		}
+	    ]
+	},
+	{
+	    "config": {
+		"prefer_app_font": true
+	    },
+	    "method": "sort",
+	    "query": {
+		"family": "Foo",
+		"style": "Regular"
+	    },
+	    "result_fs": [
+		{
+		    "family": "Foo",
+		    "style": "Regular",
+		    "file": "/app/path/to/Foo.ttf",
+		    "fontversion": 2
+		}
+	    ]
+	}
+
+    ]
+}
diff --git a/test/test-conf.c b/test/test-conf.c
index f73c983..54e5d70 100644
--- a/test/test-conf.c
+++ b/test/test-conf.c
@@ -42,6 +42,25 @@ struct _FcConfig {
     FcFontSet *fonts[FcSetApplication + 1];
 };
 
+static void
+apply_config (FcConfig *config, json_object *obj)
+{
+    json_object_iter iter;
+
+    json_object_object_foreachC (obj, iter)
+    {
+	if (strcmp (iter.key, "prefer_app_font") == 0) {
+	    if (json_object_get_type (iter.val) != json_type_boolean) {
+		fprintf (stderr, "W: invalid type of prefer_app_font: (%s)\n", json_type_to_name (json_object_get_type (iter.val)));
+		continue;
+	    }
+	    FcConfigPreferAppFont (config, json_object_get_boolean (iter.val));
+	} else {
+	    fprintf (stderr, "W: unknown object in config: %s\n", iter.key);
+	}
+    }
+}
+
 static FcPattern *
 build_pattern (json_object *obj)
 {
@@ -137,7 +156,7 @@ build_pattern (json_object *obj)
 			    continue;
 			}
 			if (nchar != 1) {
-			    fprintf (stderr, "E: charset entry not not one codepoint\n");
+			    fprintf (stderr, "E: charset entry not a codepoint\n");
 			    FcValueDestroy (v);
 			    continue;
 			}
@@ -318,7 +337,7 @@ bail:
 static FcBool
 build_fonts (FcConfig *config, json_object *root)
 {
-    json_object *fonts, *filter;
+    json_object *fonts, *filter, *appfonts;
     FcFontSet   *fs;
     FcPattern   *filterpat;
 
@@ -340,6 +359,16 @@ build_fonts (FcConfig *config, json_object *root)
     if (config->fonts[FcSetSystem])
 	FcFontSetDestroy (config->fonts[FcSetSystem]);
     config->fonts[FcSetSystem] = fs;
+    if (json_object_object_get_ex (root, "appfonts", &appfonts)) {
+	if (json_object_get_type (appfonts) != json_type_array) {
+	    fprintf (stderr, "W: Invalid appfonts defined\n");
+	    return FcFalse;
+	}
+	fs = build_fs (config, appfonts, FcTrue);
+	if (config->fonts[FcSetApplication])
+	    FcFontSetDestroy (config->fonts[FcSetApplication]);
+	config->fonts[FcSetApplication] = fs;
+    }
 
     return FcTrue;
 }
@@ -348,7 +377,7 @@ static FcBool
 run_test (FcConfig *config, json_object *root)
 {
     json_object *tests;
-    int          i, n, fail = 0;
+    int          i, j, n, fail = 0;
 
     if (!json_object_object_get_ex (root, "tests", &tests) ||
         json_object_get_type (tests) != json_type_array) {
@@ -361,15 +390,22 @@ run_test (FcConfig *config, json_object *root)
 	json_object_iter iter;
 	FcPattern       *query = NULL;
 	FcPattern       *result = NULL;
-	FcPattern       *filterpat = NULL;
 	FcFontSet       *result_fs = NULL;
 	const char      *method = NULL;
+	FcFontSet       *fs = NULL;
+	FcResult         res;
 
 	if (json_object_get_type (obj) != json_type_object)
 	    continue;
 	json_object_object_foreachC (obj, iter)
 	{
-	    if (strcmp (iter.key, "method") == 0) {
+	    if (strcmp (iter.key, "config") == 0) {
+		if (json_object_get_type (iter.val) != json_type_object) {
+		    fprintf (stderr, "W: invalid type of config: (%s)\n", json_type_to_name (json_object_get_type (iter.val)));
+		    continue;
+		}
+		apply_config (config, iter.val);
+	    } else if (strcmp (iter.key, "method") == 0) {
 		if (json_object_get_type (iter.val) != json_type_string) {
 		    fprintf (stderr, "W: invalid type of method: (%s)\n", json_type_to_name (json_object_get_type (iter.val)));
 		    continue;
@@ -407,7 +443,6 @@ run_test (FcConfig *config, json_object *root)
 	}
 	if (method != NULL && strcmp (method, "match") == 0) {
 	    FcPattern *match = NULL;
-	    FcResult   res;
 
 	    if (!query) {
 		fprintf (stderr, "E: no query defined.\n");
@@ -467,8 +502,6 @@ run_test (FcConfig *config, json_object *root)
 		}
 	    }
 	} else if (method != NULL && strcmp (method, "list") == 0) {
-	    FcFontSet *fs = NULL;
-
 	    if (!query) {
 		fprintf (stderr, "E: no query defined.\n");
 		fail++;
@@ -484,8 +517,7 @@ run_test (FcConfig *config, json_object *root)
 		fprintf (stderr, "E: failed on FcFontList\n");
 		fail++;
 	    } else {
-		int i;
-
+	    process_fs:
 		if (fs->nfont != result_fs->nfont) {
 		    printf ("E: The number of results is different:\n");
 		    printf ("   actual result: %d\n", fs->nfont);
@@ -493,26 +525,26 @@ run_test (FcConfig *config, json_object *root)
 		    fail++;
 		    goto bail2;
 		}
-		for (i = 0; i < fs->nfont; i++) {
+		for (j = 0; j < fs->nfont; j++) {
 		    FcPatternIter iter;
 		    int           x, vc;
 
-		    FcPatternIterStart (result_fs->fonts[i], &iter);
+		    FcPatternIterStart (result_fs->fonts[j], &iter);
 		    do {
-			vc = FcPatternIterValueCount (result_fs->fonts[i], &iter);
+			vc = FcPatternIterValueCount (result_fs->fonts[j], &iter);
 			for (x = 0; x < vc; x++) {
 			    FcValue vr, vm;
 
-			    if (FcPatternIterGetValue (result_fs->fonts[i], &iter, x, &vr, NULL) != FcResultMatch) {
+			    if (FcPatternIterGetValue (result_fs->fonts[j], &iter, x, &vr, NULL) != FcResultMatch) {
 				fprintf (stderr, "E: unable to obtain a value from the expected result\n");
 				fail++;
 				goto bail2;
 			    }
-			    if (FcPatternGet (fs->fonts[i], FcPatternIterGetObject (result_fs->fonts[i], &iter), x, &vm) != FcResultMatch) {
+			    if (FcPatternGet (fs->fonts[j], FcPatternIterGetObject (result_fs->fonts[j], &iter), x, &vm) != FcResultMatch) {
 				vm.type = FcTypeVoid;
 			    }
 			    if (!FcValueEqual (vm, vr)) {
-				printf ("E: failed to compare %s:\n", FcPatternIterGetObject (result_fs->fonts[i], &iter));
+				printf ("E: failed to compare %s:\n", FcPatternIterGetObject (result_fs->fonts[j], &iter));
 				printf ("   actual result:");
 				FcValuePrint (vm);
 				printf ("\n   expected result:");
@@ -522,12 +554,32 @@ run_test (FcConfig *config, json_object *root)
 				goto bail2;
 			    }
 			}
-		    } while (FcPatternIterNext (result_fs->fonts[i], &iter));
+		    } while (FcPatternIterNext (result_fs->fonts[j], &iter));
 		}
 	    bail2:
 		if (fs)
 		    FcFontSetDestroy (fs);
 	    }
+	} else if (method != NULL &&
+	           (strcmp (method, "sort") == 0 ||
+	            strcmp (method, "sort_all") == 0)) {
+	    if (!query) {
+		fprintf (stderr, "E: no query defined.\n");
+		fail++;
+		goto bail2;
+	    }
+	    if (!result_fs) {
+		fprintf (stderr, "E: no result_fs defined.\n");
+		fail++;
+		goto bail2;
+	    }
+	    fs = FcFontSort (config, query, method[4] == 0 ? FcTrue : FcFalse, NULL, &res);
+	    if (!fs) {
+		fprintf (stderr, "E: failed on FcFontSort\n");
+		fail++;
+	    } else {
+		goto process_fs;
+	    }
 	} else {
 	    fprintf (stderr, "W: unknown testing method: %s\n", method);
 	}
commit d89c253ab4ea29a2976a0b8eb6e524ddb9975762
Author: Akira TAGOH <akira at tagoh.org>
Date:   Thu Apr 24 18:41:19 2025 +0900

    Make sure that the debugging facilities are initialized at loading config phase
    
    Changelog: fixed

diff --git a/src/fcxml.c b/src/fcxml.c
index d2e25fc..328e109 100644
--- a/src/fcxml.c
+++ b/src/fcxml.c
@@ -3246,6 +3246,8 @@ FcConfigParseAndLoadFromMemoryInternal (FcConfig      *config,
     size_t         buflen;
 #endif
 
+    FcInitDebug();
+
     if (!buffer)
 	return FcFalse;
     len = strlen ((const char *)buffer);


More information about the Fontconfig mailing list