fontconfig: Branch 'main' - 5 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon May 26 10:28:00 UTC 2025


 conf.d/48-guessfamily.conf    |   44 ++++
 conf.d/Makefile.am            |    1 
 conf.d/meson.build            |    1 
 test/run-test-conf.sh         |    1 
 test/test-48-guessfamily.json |   32 +++
 test/test-conf.c              |  383 ++++++++++++++++++++++++++----------------
 test/test-crbug1004254.c      |    8 
 7 files changed, 329 insertions(+), 141 deletions(-)

New commits:
commit 3d7105d635de9ffcb1ab1265a2bce0dc44ae06ce
Merge: 61e603f 605e3a2
Author: Akira TAGOH <akira at tagoh.org>
Date:   Mon May 26 10:27:57 2025 +0000

    Merge branch 'guess-family-conf' into 'main'
    
    conf.d: Add a conf to guess a generic-family for substitution
    
    Closes #457
    
    See merge request fontconfig/fontconfig!411

commit 605e3a2ea15064759ac6fd72ee9ce92c139cb80e
Author: Akira TAGOH <akira at tagoh.org>
Date:   Mon May 26 17:47:12 2025 +0900

    test-crbug1004254: hold FcConfig during running a test in a thread

diff --git a/test/test-crbug1004254.c b/test/test-crbug1004254.c
index e14c2a4..be332b1 100644
--- a/test/test-crbug1004254.c
+++ b/test/test-crbug1004254.c
@@ -38,18 +38,20 @@ run_query (void)
 {
     FcPattern *pat = FcPatternCreate(), *match;
     FcResult   result;
+    FcConfig *config = FcConfigReference (FcConfigGetCurrent());
 
     FcPatternAddString (pat, FC_FAMILY, (const FcChar8 *)"sans-serif");
     FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
-    FcConfigSubstitute (NULL, pat, FcMatchPattern);
-    FcConfigSetDefaultSubstitute (NULL, pat);
-    match = FcFontMatch (NULL, pat, &result);
+    FcConfigSubstitute (config, pat, FcMatchPattern);
+    FcConfigSetDefaultSubstitute (config, pat);
+    match = FcFontMatch (config, pat, &result);
     if (result != FcResultMatch || !match) {
 	fprintf (stderr, "ERROR: No matches found\n");
     }
     if (match)
 	FcPatternDestroy (match);
     FcPatternDestroy (pat);
+    FcConfigDestroy (config);
 }
 
 static void
commit c5a9c84eb1832e891913c049bac7760e7a561e63
Author: Akira TAGOH <akira at tagoh.org>
Date:   Mon May 26 17:16:39 2025 +0900

    test: add a test scenario for 48-guessfamily.conf

diff --git a/test/run-test-conf.sh b/test/run-test-conf.sh
index e87bcc5..6cbdacc 100644
--- a/test/run-test-conf.sh
+++ b/test/run-test-conf.sh
@@ -41,6 +41,7 @@ fi
 
 for i in \
 	45-generic.conf \
+	48-guessfamily.conf \
 	60-generic.conf \
 	70-no-bitmaps-and-emoji.conf \
 	70-no-bitmaps-except-emoji.conf \
diff --git a/test/test-48-guessfamily.json b/test/test-48-guessfamily.json
new file mode 100644
index 0000000..63b92d7
--- /dev/null
+++ b/test/test-48-guessfamily.json
@@ -0,0 +1,32 @@
+{
+  "fonts": [],
+  "tests": [
+    {
+      "method": "pattern",
+      "query": {
+        "family": "Adwaita Mono"
+      },
+      "result": {
+        "family": ["Adwaita Mono", "monospace"]
+      }
+    },
+    {
+      "method": "pattern",
+      "query": {
+        "family": "Adwaita Sans"
+      },
+      "result": {
+        "family": ["Adwaita Sans", "sans-serif"]
+      }
+    },
+    {
+      "method": "pattern",
+      "query": {
+        "family": "Foo Serif"
+      },
+      "result": {
+        "family": ["Foo Serif", "serif"]
+      }
+    }
+  ]
+}
commit 467aebd5be5f810fc6dcd8cb8867f738cc6b52c3
Author: Akira TAGOH <akira at tagoh.org>
Date:   Mon May 26 17:13:36 2025 +0900

    test: add a pattern test

diff --git a/test/test-conf.c b/test/test-conf.c
index 725cd7f..1b5aa22 100644
--- a/test/test-conf.c
+++ b/test/test-conf.c
@@ -373,11 +373,248 @@ build_fonts (FcConfig *config, json_object *root)
     return FcTrue;
 }
 
+static int
+process_match (FcConfig  *config,
+               FcPattern *query,
+               FcPattern *result)
+{
+    int        fail = 0;
+    FcPattern *match = NULL;
+    FcResult   res;
+
+    if (!query) {
+	fprintf (stderr, "E: no query defined.\n");
+	fail++;
+	goto bail;
+    }
+    if (!result) {
+	fprintf (stderr, "E: no result defined.\n");
+	fail++;
+	goto bail;
+    }
+    FcConfigSubstitute (config, query, FcMatchPattern);
+    FcConfigSetDefaultSubstitute (config, query);
+    match = FcFontMatch (config, query, &res);
+    if (match) {
+	FcPatternIter iter;
+	int           x, vc;
+
+	FcPatternIterStart (result, &iter);
+	do {
+	    vc = FcPatternIterValueCount (result, &iter);
+	    for (x = 0; x < vc; x++) {
+		FcValue vr, vm;
+
+		if (FcPatternIterGetValue (result, &iter, x, &vr, NULL) != FcResultMatch) {
+		    fprintf (stderr, "E: unable to obtain a value from the expected result\n");
+		    fail++;
+		    goto bail;
+		}
+		if (FcPatternGet (match, FcPatternIterGetObject (result, &iter), x, &vm) != FcResultMatch) {
+		    vm.type = FcTypeVoid;
+		}
+		if (!FcValueEqual (vm, vr)) {
+		    printf ("E: failed to compare %s:\n", FcPatternIterGetObject (result, &iter));
+		    printf ("   actual result:");
+		    FcValuePrint (vm);
+		    printf ("\n   expected result:");
+		    FcValuePrint (vr);
+		    printf ("\n");
+		    fail++;
+		    goto bail;
+		}
+	    }
+	} while (FcPatternIterNext (result, &iter));
+    bail:
+	if (match)
+	    FcPatternDestroy (match);
+    } else {
+	FcPatternIter iter;
+	int           vc;
+
+	FcPatternIterStart (result, &iter);
+	vc = FcPatternIterValueCount (result, &iter);
+	if (vc > 0) {
+	    fprintf (stderr, "E: no match\n");
+	    fail++;
+	}
+    }
+
+    return fail;
+}
+
+static int
+process_fs (FcConfig  *config,
+            FcFontSet *fs,
+            FcFontSet *result_fs)
+{
+    int fail = 0;
+    int j;
+
+    if (fs->nfont != result_fs->nfont) {
+	printf ("E: The number of results is different:\n");
+	printf ("   actual result: %d\n", fs->nfont);
+	printf ("   expected result: %d\n", result_fs->nfont);
+	fail++;
+	goto bail;
+    }
+    for (j = 0; j < fs->nfont; j++) {
+	FcPatternIter iter;
+	int           x, vc;
+
+	FcPatternIterStart (result_fs->fonts[j], &iter);
+	do {
+	    vc = FcPatternIterValueCount (result_fs->fonts[j], &iter);
+	    for (x = 0; x < vc; x++) {
+		FcValue vr, vm;
+
+		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 bail;
+		}
+		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[j], &iter));
+		    printf ("   actual result:");
+		    FcValuePrint (vm);
+		    printf ("\n   expected result:");
+		    FcValuePrint (vr);
+		    printf ("\n");
+		    fail++;
+		    goto bail;
+		}
+	    }
+	} while (FcPatternIterNext (result_fs->fonts[j], &iter));
+    }
+ bail:
+
+    return fail;
+}
+
+static int
+process_list (FcConfig  *config,
+              FcPattern *query,
+              FcFontSet *result_fs)
+{
+    FcFontSet *fs = NULL;
+    int        fail = 0;
+
+    if (!query) {
+	fprintf (stderr, "E: no query defined.\n");
+	fail++;
+	goto bail;
+    }
+    if (!result_fs) {
+	fprintf (stderr, "E: no result_fs defined.\n");
+	fail++;
+	goto bail;
+    }
+    fs = FcFontList (config, query, NULL);
+    if (!fs) {
+	fprintf (stderr, "E: failed on FcFontList\n");
+	fail++;
+    } else {
+	fail += process_fs (config, fs, result_fs);
+    }
+ bail:
+    if (fs)
+	FcFontSetDestroy (fs);
+
+    return fail;
+}
+
+static int
+process_sort (FcConfig   *config,
+              FcPattern  *query,
+              FcFontSet  *result_fs,
+              const char *method)
+{
+    int        fail = 0;
+    FcFontSet *fs = NULL;
+    FcResult   res;
+
+    if (!query) {
+	fprintf (stderr, "E: no query defined.\n");
+	fail++;
+	goto bail;
+    }
+    if (!result_fs) {
+	fprintf (stderr, "E: no result_fs defined.\n");
+	fail++;
+	goto bail;
+    }
+    fs = FcFontSort (config, query, method[4] == 0 ? FcTrue : FcFalse, NULL, &res);
+    if (!fs) {
+	fprintf (stderr, "E: failed on FcFontSort\n");
+	fail++;
+    } else {
+	fail += process_fs (config, fs, result_fs);
+    }
+ bail:
+    if (fs)
+	FcFontSetDestroy (fs);
+
+    return fail;
+}
+
+static int
+process_pattern (FcConfig  *config,
+                 FcPattern *query,
+                 FcPattern *result)
+{
+    FcPatternIter iter;
+    int           x, vc, fail = 0;
+
+    if (!query) {
+	fprintf (stderr, "E: no query defined.\n");
+	fail++;
+	goto bail;
+    }
+    if (!result) {
+	fprintf (stderr, "E: no result defined.\n");
+	fail++;
+	goto bail;
+    }
+    FcConfigSubstitute (config, query, FcMatchPattern);
+
+    FcPatternIterStart (result, &iter);
+    do {
+	vc = FcPatternIterValueCount (result, &iter);
+	for (x = 0; x < vc; x++) {
+	    FcValue vr, vp;
+
+	    if (FcPatternIterGetValue (result, &iter, x, &vr, NULL) != FcResultMatch) {
+		fprintf (stderr, "E: unable to obtain a value from the expected result\n");
+		fail++;
+		goto bail;
+	    }
+	    if (FcPatternGet (query, FcPatternIterGetObject (result, &iter), x, &vp) != FcResultMatch) {
+		vp.type = FcTypeVoid;
+	    }
+	    if (!FcValueEqual (vp, vr)) {
+		printf ("E: failed to compare %s:\n", FcPatternIterGetObject (result, &iter));
+		printf ("   actual result:");
+		FcValuePrint (vp);
+		printf ("\n   expected result:");
+		FcValuePrint (vr);
+		printf ("\n");
+		fail++;
+		goto bail;
+	    }
+	}
+    } while (FcPatternIterNext (result, &iter));
+ bail:
+    return fail;
+}
+
 static FcBool
 run_test (FcConfig *config, json_object *root)
 {
     json_object *tests;
-    int          i, j, n, fail = 0;
+    int          i, n, fail = 0;
 
     if (!json_object_object_get_ex (root, "tests", &tests) ||
         json_object_get_type (tests) != json_type_array) {
@@ -392,8 +629,6 @@ run_test (FcConfig *config, json_object *root)
 	FcPattern       *result = NULL;
 	FcFontSet       *result_fs = NULL;
 	const char      *method = NULL;
-	FcFontSet       *fs = NULL;
-	FcResult         res;
 
 	if (json_object_get_type (obj) != json_type_object)
 	    continue;
@@ -442,145 +677,17 @@ run_test (FcConfig *config, json_object *root)
 	    }
 	}
 	if (method != NULL && strcmp (method, "match") == 0) {
-	    FcPattern *match = NULL;
-
-	    if (!query) {
-		fprintf (stderr, "E: no query defined.\n");
-		fail++;
-		goto bail;
-	    }
-	    if (!result) {
-		fprintf (stderr, "E: no result defined.\n");
-		fail++;
-		goto bail;
-	    }
-	    FcConfigSubstitute (config, query, FcMatchPattern);
-	    FcConfigSetDefaultSubstitute (config, query);
-	    match = FcFontMatch (config, query, &res);
-	    if (match) {
-		FcPatternIter iter;
-		int           x, vc;
-
-		FcPatternIterStart (result, &iter);
-		do {
-		    vc = FcPatternIterValueCount (result, &iter);
-		    for (x = 0; x < vc; x++) {
-			FcValue vr, vm;
-
-			if (FcPatternIterGetValue (result, &iter, x, &vr, NULL) != FcResultMatch) {
-			    fprintf (stderr, "E: unable to obtain a value from the expected result\n");
-			    fail++;
-			    goto bail;
-			}
-			if (FcPatternGet (match, FcPatternIterGetObject (result, &iter), x, &vm) != FcResultMatch) {
-			    vm.type = FcTypeVoid;
-			}
-			if (!FcValueEqual (vm, vr)) {
-			    printf ("E: failed to compare %s:\n", FcPatternIterGetObject (result, &iter));
-			    printf ("   actual result:");
-			    FcValuePrint (vm);
-			    printf ("\n   expected result:");
-			    FcValuePrint (vr);
-			    printf ("\n");
-			    fail++;
-			    goto bail;
-			}
-		    }
-		} while (FcPatternIterNext (result, &iter));
-	    bail:
-		if (match)
-		    FcPatternDestroy (match);
-	    } else {
-		FcPatternIter iter;
-		int           vc;
-
-		FcPatternIterStart (result, &iter);
-		vc = FcPatternIterValueCount (result, &iter);
-		if (vc > 0) {
-		    fprintf (stderr, "E: no match\n");
-		    fail++;
-		}
-	    }
+	    fail += process_match (config, query, result);
 	} else if (method != NULL && strcmp (method, "list") == 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 = FcFontList (config, query, NULL);
-	    if (!fs) {
-		fprintf (stderr, "E: failed on FcFontList\n");
-		fail++;
-	    } else {
-	    process_fs:
-		if (fs->nfont != result_fs->nfont) {
-		    printf ("E: The number of results is different:\n");
-		    printf ("   actual result: %d\n", fs->nfont);
-		    printf ("   expected result: %d\n", result_fs->nfont);
-		    fail++;
-		    goto bail2;
-		}
-		for (j = 0; j < fs->nfont; j++) {
-		    FcPatternIter iter;
-		    int           x, vc;
-
-		    FcPatternIterStart (result_fs->fonts[j], &iter);
-		    do {
-			vc = FcPatternIterValueCount (result_fs->fonts[j], &iter);
-			for (x = 0; x < vc; x++) {
-			    FcValue vr, vm;
-
-			    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[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[j], &iter));
-				printf ("   actual result:");
-				FcValuePrint (vm);
-				printf ("\n   expected result:");
-				FcValuePrint (vr);
-				printf ("\n");
-				fail++;
-				goto bail2;
-			    }
-			}
-		    } while (FcPatternIterNext (result_fs->fonts[j], &iter));
-		}
-	    bail2:
-		if (fs)
-		    FcFontSetDestroy (fs);
-	    }
+	    fail += process_list (config, query, result_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 {
+	    fail += process_sort (config, query, result_fs, method);
+	} else if (method != NULL &&
+	           strcmp (method, "pattern") == 0) {
+	    fail += process_pattern (config, query, result);
+        } else {
 	    fprintf (stderr, "W: unknown testing method: %s\n", method);
 	}
 	if (method)
commit 7661a9b4d49df61d66359b532eebb34c0be73367
Author: Akira TAGOH <akira at tagoh.org>
Date:   Mon May 26 16:13:19 2025 +0900

    conf.d: Add a conf to guess a generic-family for substitution
    
    This config file aims to add proper generic-family name for substitution
    when no fallback for requested family name and also to avoid unexpected
    substitution by 49-sanserif.conf such as "Blah Mono" to sans-serif.
    
    Without this:
      $ fc-pattern -c "Adwaita Mono"
      Pattern has 9 elts (size 16)
              family: "Adwaita Mono"(s) "Noto Sans"(w) ...
    
    With this:
      $ fc-pattern -c "Adwaita Mono"
      Pattern has 9 elts (size 16)
              family: "Adwaita Mono"(s) "Noto Sans Mono"(w) ...
    
    Fixes https://gitlab.freedesktop.org/fontconfig/fontconfig/-/issues/457
    
    Changelog: fixed

diff --git a/conf.d/48-guessfamily.conf b/conf.d/48-guessfamily.conf
new file mode 100644
index 0000000..aaf8527
--- /dev/null
+++ b/conf.d/48-guessfamily.conf
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
+<fontconfig>
+  <description>Guess a generic-family for substitution</description>
+  <!-- sans-serif -->
+  <match target="pattern">
+    <test qual="all" name="family" compare="not_eq">
+      <string>sans-serif</string>
+    </test>
+    <test name="family" compare="contains">
+      <string>sans</string>
+    </test>
+    <edit name="family" mode="append_last">
+      <string>sans-serif</string>
+    </edit>
+  </match>
+  <!-- serif -->
+  <match target="pattern">
+    <test qual="all" name="family" compare="not_eq">
+      <string>sans-serif</string>
+    </test>
+    <test qual="all" name="family" compare="not_eq">
+      <string>serif</string>
+    </test>
+    <test name="family" compare="contains">
+      <string>serif</string>
+    </test>
+    <edit name="family" mode="append_last">
+      <string>serif</string>
+    </edit>
+  </match>
+  <!-- monospace -->
+  <match target="pattern">
+    <test qual="all" name="family" compare="not_eq">
+      <string>monospace</string>
+    </test>
+    <test name="family" compare="contains">
+      <string>mono</string>
+    </test>
+    <edit name="family" mode="append_last">
+      <string>monospace</string>
+    </edit>
+  </match>
+</fontconfig>
diff --git a/conf.d/Makefile.am b/conf.d/Makefile.am
index 737b4fb..e9b3ddc 100644
--- a/conf.d/Makefile.am
+++ b/conf.d/Makefile.am
@@ -87,6 +87,7 @@ template_DATA =				\
 	40-nonlatin.conf		\
 	45-generic.conf			\
 	45-latin.conf			\
+	48-guessfamily.conf		\
 	48-spacing.conf			\
 	49-sansserif.conf		\
 	50-user.conf			\
diff --git a/conf.d/meson.build b/conf.d/meson.build
index ef9b0cc..66699fd 100644
--- a/conf.d/meson.build
+++ b/conf.d/meson.build
@@ -25,6 +25,7 @@ conf_files = [
   '40-nonlatin.conf',
   '45-generic.conf',
   '45-latin.conf',
+  '48-guessfamily.conf',
   '48-spacing.conf',
   '49-sansserif.conf',
   '50-user.conf',


More information about the Fontconfig mailing list