[packages/fontconfig] add regression fixes from upstream; rel 2

atler atler at pld-linux.org
Thu May 28 19:32:57 CEST 2026


commit 0a442c7f751503ec88e0bafc214cf4cb26aa6ebe
Author: Jan Palus <atler at pld-linux.org>
Date:   Thu May 28 19:31:23 2026 +0200

    add regression fixes from upstream; rel 2
    
    https://gitlab.freedesktop.org/fontconfig/fontconfig/-/merge_requests/520
    https://gitlab.freedesktop.org/fontconfig/fontconfig/-/merge_requests/521
    https://gitlab.freedesktop.org/fontconfig/fontconfig/-/merge_requests/522
    https://gitlab.freedesktop.org/fontconfig/fontconfig/-/merge_requests/524

 fixes.patch     | 1138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fontconfig.spec |    4 +-
 2 files changed, 1141 insertions(+), 1 deletion(-)
---
diff --git a/fontconfig.spec b/fontconfig.spec
index d467ed5..de69b15 100644
--- a/fontconfig.spec
+++ b/fontconfig.spec
@@ -9,7 +9,7 @@ Summary(pl.UTF-8):	Narzędzia do konfigurowania fontów
 Summary(pt_BR.UTF-8):	Ferramentas para configuração e customização do acesso a fontes
 Name:		fontconfig
 Version:	2.18.0
-Release:	1
+Release:	2
 Epoch:		1
 License:	MIT
 Group:		Libraries
@@ -22,6 +22,7 @@ Source0:	https://gitlab.freedesktop.org/api/v4/projects/890/packages/generic/fon
 Source1:	%{name}-lcd-filter.conf
 Patch0:		%{name}-bitstream-cyberbit.patch
 Patch1:		disable-tests.patch
+Patch2:		fixes.patch
 URL:		http://fontconfig.org/
 BuildRequires:	autoconf >= 2.71
 BuildRequires:	automake >= 1:1.11
@@ -143,6 +144,7 @@ Este pacote contém a biblioteca estática do fontconfig
 %setup -q
 %patch -P0 -p1
 %patch -P1 -p1
+%patch -P2 -p1
 
 # bwrap: No permissions to creating new namespace, likely because the kernel does not allow non-privileged user namespaces...
 sed -i -e 's#BWRAP=.*#BWRAP=#g' test/run-test-map.sh
diff --git a/fixes.patch b/fixes.patch
new file mode 100644
index 0000000..f2cd1a7
--- /dev/null
+++ b/fixes.patch
@@ -0,0 +1,1138 @@
+From ec3ac5609a95d9338744d2e39af3a29c6349d2d5 Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira at tagoh.org>
+Date: Fri, 22 May 2026 08:07:00 +0900
+Subject: [PATCH] Fix not matching with a font family name
+
+Give higher priority to FC_FAMILY with the strong binding more than
+FC_GENERIC_FAMILY. So even if we add a default value for
+genericfamily in 49-sansserif.conf, a font that is actually
+available on the system will be picked up when it matches a query.
+
+https://gitlab.freedesktop.org/fontconfig/fontconfig/-/work_items/520
+
+Changelog: fixed
+---
+ src/fcmatch.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/fcmatch.c b/src/fcmatch.c
+index e0ab9503..ea6c2243 100644
+--- a/src/fcmatch.c
++++ b/src/fcmatch.c
+@@ -330,8 +330,8 @@ typedef enum _FcMatcherPriority {
+     PRI1 (COLOR),
+     PRI1 (FOUNDRY),
+     PRI1 (CHARSET),
+-    PRI1 (GENERIC_FAMILY),
+     PRI_FAMILY_STRONG,
++    PRI1 (GENERIC_FAMILY),
+     PRI_POSTSCRIPT_NAME_STRONG,
+     PRI1 (LANG),
+     PRI_FAMILY_WEAK,
+-- 
+GitLab
+
+From 56a2f98298642ce34311a02f1299b0282f89a46b Mon Sep 17 00:00:00 2001
+From: Marcus Spencer <marcus at marcusspencer.us>
+Date: Fri, 22 May 2026 01:28:46 -0500
+Subject: [PATCH] Fix a null pointer dereference when computing a pattern from
+ a FreeType face that has no family name
+
+Changelog: fixed
+---
+ src/fcfreetype.c | 39 +++++++++++++++++++++------------------
+ 1 file changed, 21 insertions(+), 18 deletions(-)
+
+diff --git a/src/fcfreetype.c b/src/fcfreetype.c
+index c57f9b33..05c2e8a0 100644
+--- a/src/fcfreetype.c
++++ b/src/fcfreetype.c
+@@ -2080,28 +2080,31 @@ FcFreeTypeQueryFaceInternal (const FT_Face   face,
+ 	int generic_family = FC_FAMILY_UNKNOWN;
+ 
+ 	elt = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
+-	for (l = FcPatternEltValues (elt); l; l = FcValueListNext (l)) {
+-	    FcValue v = FcValueCanonicalize (&l->value);
++	if (elt) {
++	    for (l = FcPatternEltValues (elt); l; l = FcValueListNext (l)) {
++		FcValue v = FcValueCanonicalize (&l->value);
+ 
+-	    if (v.type == FcTypeString) {
+-		if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"mono")) {
+-		    generic_family = FC_FAMILY_MONO;
+-		    break;
+-		} else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"sans")) {
+-		    generic_family = FC_FAMILY_SANS;
+-		    break;
+-		} else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"serif")) {
+-		    generic_family = FC_FAMILY_SERIF;
+-		    break;
+-		} else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"emoji")) {
+-		    generic_family = FC_FAMILY_EMOJI;
+-		    break;
+-		} else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"math")) {
+-		    generic_family = FC_FAMILY_MATH;
+-		    break;
++		if (v.type == FcTypeString) {
++		    if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"mono")) {
++			generic_family = FC_FAMILY_MONO;
++			break;
++		    } else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"sans")) {
++			generic_family = FC_FAMILY_SANS;
++			break;
++		    } else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"serif")) {
++			generic_family = FC_FAMILY_SERIF;
++			break;
++		    } else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"emoji")) {
++			generic_family = FC_FAMILY_EMOJI;
++			break;
++		    } else if (FcStrStrIgnoreCase (v.u.s, (FcChar8 *)"math")) {
++			generic_family = FC_FAMILY_MATH;
++			break;
++		    }
+ 		}
+ 	    }
+ 	}
++
+ 	FcPatternObjectAddInteger(pat, FC_GENERIC_FAMILY_OBJECT, generic_family);
+     }
+ 
+-- 
+GitLab
+
+From 661fb663fd37be1ff637f1eed9832a388981191e Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira at tagoh.org>
+Date: Wed, 27 May 2026 13:24:33 +0900
+Subject: [PATCH 1/3] test-conf: Add a feature to load a certain config for
+ testing
+
+---
+ test/Makefile.am |  2 +-
+ test/meson.build |  3 ++-
+ test/test-conf.c | 60 ++++++++++++++++++++++++++++++++++++++++++++----
+ 3 files changed, 58 insertions(+), 7 deletions(-)
+
+diff --git a/test/Makefile.am b/test/Makefile.am
+index 4b6fd1e4..f6dcf2d3 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -104,7 +104,7 @@ TESTS += test-name-parse
+ 
+ if ENABLE_JSONC
+ check_PROGRAMS += test-conf
+-test_conf_CFLAGS = $(JSONC_CFLAGS)
++test_conf_CFLAGS = $(JSONC_CFLAGS) -DSRCDIR="\"$(abs_srcdir)\""
+ test_conf_LDADD = $(top_builddir)/src/libfontconfig.la $(JSONC_LIBS)
+ endif
+ 
+diff --git a/test/meson.build b/test/meson.build
+index 64d0035c..8bc31646 100644
+--- a/test/meson.build
++++ b/test/meson.build
+@@ -112,7 +112,8 @@ endif
+ 
+ if jsonc_dep.found()
+   test_conf = executable('test-conf', 'test-conf.c',
+-                         dependencies: [fontconfig_dep, jsonc_dep])
++                         dependencies: [fontconfig_dep, jsonc_dep],
++                         c_args: ['-DSRCDIR="@0@"'.format(meson.current_source_dir())])
+ endif
+ 
+ test_const_name = executable('test_const_name', test_const_name_c,
+diff --git a/test/test-conf.c b/test/test-conf.c
+index 8dcc367d..8709f509 100644
+--- a/test/test-conf.c
++++ b/test/test-conf.c
+@@ -53,9 +53,9 @@ int
+ setenv (const char *name, const char *value, int overwrite)
+ {
+     if (!overwrite) {
+-        char *s = getenv (name);
+-        if (s)
+-            return 0;
++	char *s = getenv (name);
++	if (s)
++	    return 0;
+     }
+     return _putenv_s (name, value);
+ }
+@@ -110,6 +110,48 @@ build_env (FcConfig *config, json_object *root)
+     return FcTrue;
+ }
+ 
++static FcBool
++build_config (FcConfig *config, json_object *obj)
++{
++    int    n, i;
++    FcBool ret = FcTrue;
++
++    n = json_object_array_length (obj);
++    for (i = 0; i < n; i++) {
++	json_object   *o = json_object_array_get_idx (obj, i);
++	char          *allocated = NULL;
++	const char    *s;
++	const FcChar8 *m;
++
++	if (json_object_get_type (o) != json_type_string) {
++	    fprintf (stderr, "W: Invalid config item\n");
++	    continue;
++	}
++	s = json_object_get_string (o);
++	if ((m = FcStrStr ((const FcChar8 *)s, (const FcChar8 *)"%test%")) != 0) {
++	    size_t root_len = strlen (SRCDIR);
++	    size_t len = strlen (s);
++
++	    allocated = malloc (root_len + len);
++	    if (!allocated)
++		return FcFalse;
++	    strcpy (allocated, SRCDIR);
++	    allocated[root_len] = '/';
++	    strcpy (&allocated[root_len + 1], (const char *)&m[6]);
++	    s = allocated;
++	}
++	ret = FcConfigParseAndLoad (config, (const FcChar8 *)s, FcTrue);
++	if (allocated) {
++	    free (allocated);
++	    allocated = NULL;
++	}
++	if (!ret)
++	    goto bail;
++    }
++bail:
++    return ret;
++}
++
+ static FcPattern *
+ build_pattern (json_object *obj)
+ {
+@@ -416,7 +458,7 @@ bail:
+ static FcBool
+ build_fonts (FcConfig *config, json_object *root)
+ {
+-    json_object *fonts, *filter, *appfonts;
++    json_object *fonts, *filter, *appfonts, *cfg_xml;
+     FcFontSet   *fs;
+     FcPattern   *filterpat;
+ 
+@@ -448,6 +490,14 @@ build_fonts (FcConfig *config, json_object *root)
+ 	    FcFontSetDestroy (config->fonts[FcSetApplication]);
+ 	config->fonts[FcSetApplication] = fs;
+     }
++    if (json_object_object_get_ex (root, "load_xml", &cfg_xml)) {
++	if (json_object_get_type (cfg_xml) != json_type_array) {
++	    fprintf (stderr, "W: Invalid load_xml defined\n");
++	    return FcFalse;
++	}
++	if (!build_config (config, cfg_xml))
++	    return FcFalse;
++    }
+ 
+     return FcTrue;
+ }
+@@ -695,7 +745,7 @@ process_pattern (FcConfig  *config,
+ 	    }
+ 	}
+     } while (FcPatternIterNext (result, &iter2));
+- bail:
++bail:
+     return fail;
+ }
+ 
+-- 
+GitLab
+
+
+From 466454b59b4110dda237001deba30be3ff77a603 Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira at tagoh.org>
+Date: Wed, 27 May 2026 13:29:44 +0900
+Subject: [PATCH 2/3] test: Add comprehensive documentation for test-conf JSON
+ format
+
+Document the JSON schema used by test-conf for defining test scenarios,
+including all top-level fields (env, fonts, appfonts, filter, load_xml,
+tests), pattern value types, test methods, and common fontconfig properties.
+
+Assisted-By: Claude Sonnet 4.5 <noreply at anthropic.com>
+---
+ test/TEST-JSON-FORMAT.md | 482 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 482 insertions(+)
+ create mode 100644 test/TEST-JSON-FORMAT.md
+
+diff --git a/test/TEST-JSON-FORMAT.md b/test/TEST-JSON-FORMAT.md
+new file mode 100644
+index 00000000..1a1cfc14
+--- /dev/null
++++ b/test/TEST-JSON-FORMAT.md
+@@ -0,0 +1,482 @@
++# Fontconfig Test JSON Format Documentation
++
++This document describes the JSON format used by the `test-conf` test harness for testing fontconfig behavior.
++
++## Overview
++
++The test JSON format allows you to define:
++- A mock font database with specific font properties
++- Environment variables and configuration files to load
++- Test queries and expected results
++
++## Top-Level Structure
++
++```json
++{
++  "env": { ... },
++  "fonts": [ ... ],
++  "appfonts": [ ... ],
++  "filter": { ... },
++  "load_xml": [ ... ],
++  "tests": [ ... ]
++}
++```
++
++### Fields
++
++#### `env` (optional)
++Type: Object
++
++Environment variables to set before running tests. Special key `"locale"` calls `setlocale()` instead of `setenv()`.
++
++**Example:**
++```json
++{
++  "env": {
++    "locale": "de_DE.UTF-8",
++    "FC_DEBUG": "1"
++  }
++}
++```
++
++#### `fonts` (required)
++Type: Array of Pattern objects
++
++Defines the system font database. Each entry represents a font with its properties.
++
++**Example:**
++```json
++{
++  "fonts": [
++    {
++      "family": "Noto Sans",
++      "style": "Regular",
++      "file": "/path/to/NotoSans.ttf",
++      "fontversion": 1
++    }
++  ]
++}
++```
++
++#### `appfonts` (optional)
++Type: Array of Pattern objects
++
++Defines application-level fonts, which can take precedence over system fonts depending on configuration.
++
++**Example:**
++```json
++{
++  "appfonts": [
++    {
++      "family": "Custom Font",
++      "file": "/app/path/to/CustomFont.ttf",
++      "fontversion": 2
++    }
++  ]
++}
++```
++
++#### `filter` (optional)
++Type: Pattern object
++
++A pattern used to filter which fonts from the `fonts` array are actually included in the font set. Only fonts matching all properties in the filter pattern are included.
++
++**Example:**
++```json
++{
++  "filter": {
++    "fontwrapper": "SFNT"
++  }
++}
++```
++
++#### `load_xml` (optional)
++Type: Array of strings
++
++List of fontconfig XML configuration files to load and apply. Use `%test%` as a placeholder for the test directory (defined by SRCDIR).
++
++**Example:**
++```json
++{
++  "load_xml": [
++    "conf.d/48-guessfamily.conf",
++    "conf.d/49-sansserif.conf",
++    "%test%/test-custom.conf"
++  ]
++}
++```
++
++#### `tests` (required)
++Type: Array of Test objects
++
++Test cases to execute against the configured fontconfig instance.
++
++## Pattern Object Format
++
++Patterns are used in `fonts`, `appfonts`, `filter`, test `query`, and test `result` objects. A pattern is a JSON object where keys are fontconfig property names and values specify the property values.
++
++### Value Types
++
++#### String Values
++
++Simple string properties:
++```json
++{
++  "family": "Noto Sans",
++  "style": "Regular",
++  "file": "/path/to/font.ttf"
++}
++```
++
++For properties that expect constants (like `weight`, `slant`, `width`), you can use constant names:
++```json
++{
++  "weight": "bold",
++  "slant": "italic",
++  "width": "condensed"
++}
++```
++
++Special string value:
++- `"DontCare"`: Represents the FcDontCare boolean value
++
++#### Numeric Values
++
++Integer or double values:
++```json
++{
++  "fontversion": 1,
++  "size": 12.5,
++  "weight": 200,
++  "index": 0
++}
++```
++
++#### Boolean Values
++
++```json
++{
++  "scalable": true,
++  "variable": false,
++  "namedinstance": false,
++  "embolden": true
++}
++```
++
++#### Null Values
++
++```json
++{
++  "embolden": null
++}
++```
++
++#### Array Values
++
++Arrays are interpreted based on the property type and array content:
++
++**String Arrays** (for properties like `family`, `style`):
++```json
++{
++  "family": ["Noto Sans", "sans-serif"],
++  "style": ["Regular", "Normal"]
++}
++```
++
++**Charset Arrays** (for `charset` property):
++Each element is a single UTF-8 character (codepoint):
++```json
++{
++  "charset": ["a", "b", "c", "あ", "😀"]
++}
++```
++
++**LangSet Arrays** (for `lang` property):
++Each element is a language code:
++```json
++{
++  "lang": ["en", "de", "ja"]
++}
++```
++
++**Integer Arrays** (for properties like `weight` when multiple values needed):
++```json
++{
++  "weight": [80, 100, 200]
++}
++```
++Can also use constant names:
++```json
++{
++  "weight": ["light", "medium", "bold"]
++}
++```
++
++**Double Arrays** (for properties expecting multiple double values):
++```json
++{
++  "dpi": [96.0, 120.0]
++}
++```
++
++**Range Arrays** (2-element numeric array):
++```json
++{
++  "size": [8.0, 48.0]
++}
++```
++
++**Matrix Arrays** (4-element numeric array `[xx, xy, yx, yy]`):
++```json
++{
++  "matrix": [1.0, 0.0, 0.0, 1.0]
++}
++```
++
++## Test Object Format
++
++```json
++{
++  "method": "match",
++  "config": { ... },
++  "query": { ... },
++  "result": { ... },
++  "result_fs": [ ... ],
++  "$comment": "Optional comment"
++}
++```
++
++### Fields
++
++#### `method` (required)
++Type: String
++
++The test method to use. Valid values:
++- `"match"`: Test `FcFontMatch()` - find the best matching font
++- `"list"`: Test `FcFontList()` - list all fonts matching a pattern
++- `"sort"`: Test `FcFontSort()` with trimming - sorted list of matching fonts (trimmed)
++- `"sort_all"`: Test `FcFontSort()` without trimming - sorted list of all matching fonts
++- `"pattern"`: Test `FcConfigSubstitute()` - pattern substitution without font matching
++
++#### `config` (optional)
++Type: Object
++
++Per-test configuration options applied before running the test.
++
++**Supported options:**
++- `"prefer_app_font"`: Boolean - whether to prefer application fonts over system fonts
++
++**Example:**
++```json
++{
++  "config": {
++    "prefer_app_font": true
++  }
++}
++```
++
++#### `query` (required)
++Type: Pattern object
++
++The input pattern for the query.
++
++**Example:**
++```json
++{
++  "query": {
++    "family": "Noto Sans",
++    "weight": "bold",
++    "size": 12.0
++  }
++}
++```
++
++#### `result` (required for `match` and `pattern` methods)
++Type: Pattern object
++
++The expected result pattern. The test verifies that all properties specified in this pattern match the corresponding properties in the actual result.
++
++**Example:**
++```json
++{
++  "result": {
++    "family": "Noto Sans",
++    "file": "/path/to/NotoSans-Bold.ttf",
++    "weight": 200
++  }
++}
++```
++
++#### `result_fs` (required for `list`, `sort`, and `sort_all` methods)
++Type: Array of Pattern objects
++
++The expected result font set. The test verifies:
++1. The number of results matches
++2. Each result pattern matches the expected pattern at the same index
++
++**Example:**
++```json
++{
++  "result_fs": [
++    {
++      "family": "Noto Sans",
++      "file": "/path/to/NotoSans-Regular.ttf"
++    },
++    {
++      "family": "Noto Sans",
++      "file": "/path/to/NotoSans-Bold.ttf"
++    }
++  ]
++}
++```
++
++#### `$comment` (optional)
++Type: String
++
++A comment field that is ignored by the test runner. Use for documentation purposes.
++
++**Example:**
++```json
++{
++  "$comment": "This test verifies that bold synthesis works correctly"
++}
++```
++
++## Common Pattern Properties
++
++Here are commonly used fontconfig properties you can use in patterns:
++
++### Font Identification
++- `family`: String or Array - Font family name(s)
++- `style`: String or Array - Font style name(s)
++- `fullname`: String - Full font name
++- `file`: String - Font file path
++- `index`: Integer - Font index in collection
++
++### Font Attributes
++- `weight`: Integer or Constant - Font weight (0-215, or "thin", "light", "medium", "bold", "black", etc.)
++- `slant`: Integer or Constant - Font slant ("roman", "italic", "oblique")
++- `width`: Integer or Constant - Font width ("condensed", "normal", "expanded", etc.)
++- `size`: Double or Range - Font size in points
++- `pixelsize`: Double or Range - Font size in pixels
++- `fontversion`: Integer - Font version number
++
++### Font Capabilities
++- `scalable`: Boolean - Whether font is scalable
++- `outline`: Boolean - Whether font has outlines
++- `color`: Boolean - Whether font has color glyphs
++- `variable`: Boolean - Whether font is a variable font
++- `namedinstance`: Boolean - Whether font is a named instance
++
++### Character Support
++- `charset`: Array of characters - Supported characters
++- `lang`: String or Array - Supported language(s)
++
++### Typography
++- `spacing`: Integer or Constant - Character spacing ("proportional", "mono", "charcell")
++- `fontformat`: String - Font format ("TrueType", "Type 1", "CFF", etc.)
++- `fontwrapper`: String - Font wrapper format ("SFNT", "CFF", "WOFF", etc.)
++
++### Rendering
++- `antialias`: Boolean - Whether to antialias
++- `hinting`: Boolean - Whether to hint
++- `hintstyle`: Integer or Constant - Hint style ("none", "slight", "medium", "full")
++- `rgba`: Integer or Constant - Subpixel order ("none", "rgb", "bgr", "vrgb", "vbgr")
++- `embolden`: Boolean or Null - Whether to embolden (synthetic bold)
++- `matrix`: Array[4] - Transformation matrix
++
++### Advanced
++- `dpi`: Double - DPI setting
++- `genericfamily`: Integer or Constant - Generic family ("serif", "sans-serif", "monospace", etc.)
++- `fontvariations`: String - Font variation settings (e.g., "wght=400,wdth=100")
++
++## Complete Example
++
++```json
++{
++  "env": {
++    "locale": "en_US.UTF-8"
++  },
++  "fonts": [
++    {
++      "family": "Noto Sans",
++      "style": "Regular",
++      "file": "/path/to/NotoSans-Regular.ttf",
++      "weight": 80,
++      "slant": "roman",
++      "fontversion": 1,
++      "scalable": true,
++      "outline": true
++    },
++    {
++      "family": "Noto Sans",
++      "style": "Bold",
++      "file": "/path/to/NotoSans-Bold.ttf",
++      "weight": 200,
++      "slant": "roman",
++      "fontversion": 1,
++      "scalable": true,
++      "outline": true
++    }
++  ],
++  "load_xml": [
++    "conf.d/10-autohint.conf",
++    "conf.d/10-hinting-slight.conf"
++  ],
++  "tests": [
++    {
++      "$comment": "Test that bold weight request matches bold font",
++      "method": "match",
++      "query": {
++        "family": "Noto Sans",
++        "weight": "bold"
++      },
++      "result": {
++        "family": "Noto Sans",
++        "file": "/path/to/NotoSans-Bold.ttf",
++        "weight": 200
++      }
++    },
++    {
++      "$comment": "Test that listing returns all Noto Sans variants",
++      "method": "list",
++      "query": {
++        "family": "Noto Sans"
++      },
++      "result_fs": [
++        {
++          "family": "Noto Sans",
++          "file": "/path/to/NotoSans-Regular.ttf"
++        },
++        {
++          "family": "Noto Sans",
++          "file": "/path/to/NotoSans-Bold.ttf"
++        }
++      ]
++    }
++  ]
++}
++```
++
++## Usage
++
++To run a test:
++
++```bash
++test-conf <config-file> <test-json-file>
++```
++
++Where:
++- `<config-file>`: Base fontconfig configuration file (XML format)
++- `<test-json-file>`: Test scenario file (JSON format described in this document)
++
++The test harness will:
++1. Create a fontconfig configuration instance
++2. Load the base config file
++3. Set environment variables from `env`
++4. Build the mock font database from `fonts` and `appfonts`
++5. Apply the `filter` if specified
++6. Load additional config files from `load_xml`
++7. Execute each test in `tests` and verify results
++
++Exit code is 0 if all tests pass, non-zero otherwise.
+-- 
+GitLab
+
+
+From e17806afda817cf8ba2fe6e0d063617994dcdc0f Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira at tagoh.org>
+Date: Wed, 27 May 2026 13:36:49 +0900
+Subject: [PATCH 3/3] Fix another font matching issue
+
+Do not score genericfamily by difference. it isn't like other properties.
+If it doesn't match, the matching decision should simply leaves to the next
+property.
+So we can't use FcCompareNumber for this.
+
+Fixes https://gitlab.freedesktop.org/fontconfig/fontconfig/-/work_items/525
+
+Changelog: fixed
+---
+ src/fcmatch.c            | 36 ++++++++++++++++++++++++++++++++++++
+ src/fcobjs.h             |  2 +-
+ test/test-issue-525.conf |  8 ++++++++
+ test/test-issue-525.json | 38 ++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 83 insertions(+), 1 deletion(-)
+ create mode 100644 test/test-issue-525.conf
+ create mode 100644 test/test-issue-525.json
+
+diff --git a/src/fcmatch.c b/src/fcmatch.c
+index ea6c2243..1adbbdc2 100644
+--- a/src/fcmatch.c
++++ b/src/fcmatch.c
+@@ -164,6 +164,41 @@ FcCompareBool (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
+     return (double)((v2->u.b ^ v1->u.b) == 1);
+ }
+ 
++static double
++FcCompareEqual (const FcValue *value1, const FcValue *value2, FcValue *bestValue)
++{
++    double v1, v2, v;
++
++    switch ((int)value1->type) {
++    case FcTypeInteger:
++	v1 = (double)value1->u.i;
++	break;
++    case FcTypeDouble:
++	v1 = value1->u.d;
++	break;
++    case FcTypeBool:
++	return FcCompareBool (value1, value2, bestValue);
++    default:
++	return -1.0;
++    }
++    switch ((int)value2->type) {
++    case FcTypeInteger:
++	v2 = (double)value2->u.i;
++	break;
++    case FcTypeDouble:
++	v2 = value2->u.d;
++	break;
++    case FcTypeBool:
++	return FcCompareBool (value1, value2, bestValue);
++    default:
++	return -1.0;
++    }
++    v = !(v1 == v2);
++    *bestValue = FcValueCanonicalize (value2);
++
++    return v;
++}
++
+ static double
+ FcCompareCharSet (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
+ {
+@@ -296,6 +331,7 @@ FcCompareFilename (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
+ #define PRI_FcCompareFamily(n)     PRI1 (n)
+ #define PRI_FcCompareString(n)     PRI1 (n)
+ #define PRI_FcCompareNumber(n)     PRI1 (n)
++#define PRI_FcCompareEqual(n)      PRI1 (n)
+ #define PRI_FcCompareBool(n)       PRI1 (n)
+ #define PRI_FcCompareFilename(n)   PRI1 (n)
+ #define PRI_FcCompareCharSet(n)    PRI1 (n)
+diff --git a/src/fcobjs.h b/src/fcobjs.h
+index 1de0ad0e..bace9a96 100644
+--- a/src/fcobjs.h
++++ b/src/fcobjs.h
+@@ -77,5 +77,5 @@ FC_OBJECT (ORDER,		FcTypeInteger,	FcCompareNumber)
+ FC_OBJECT (DESKTOP_NAME,	FcTypeString,	NULL)
+ FC_OBJECT (NAMED_INSTANCE,	FcTypeBool,	FcCompareBool)
+ FC_OBJECT (FONT_WRAPPER,	FcTypeString,	FcCompareString)
+-FC_OBJECT (GENERIC_FAMILY,	FcTypeInteger,	FcCompareNumber)
++FC_OBJECT (GENERIC_FAMILY,	FcTypeInteger,	FcCompareEqual)
+ /* ^-------------- Add new objects here. */
+diff --git a/test/test-issue-525.conf b/test/test-issue-525.conf
+new file mode 100644
+index 00000000..31eb2fd1
+--- /dev/null
++++ b/test/test-issue-525.conf
+@@ -0,0 +1,8 @@
++<fontconfig>
++  <alias>
++    <family>system-ui</family>
++    <prefer>
++      <family>Lato</family>
++    </prefer>
++  </alias>
++</fontconfig>
+diff --git a/test/test-issue-525.json b/test/test-issue-525.json
+new file mode 100644
+index 00000000..86e9890e
+--- /dev/null
++++ b/test/test-issue-525.json
+@@ -0,0 +1,38 @@
++{
++  "fonts": [
++    {
++      "family": "Noto Sans",
++      "style": "Regular",
++      "file": "/path/to/NotoSans.ttf",
++      "fontversion": 1,
++      "genericfamily": 1
++    },
++    {
++      "family": "Lato",
++      "style": "Regular",
++      "file": "/path/to/Lato.ttf",
++      "fontversion": 1,
++      "genericfamily": 0
++    }
++  ],
++  "load_xml": [
++    "conf.d/48-guessfamily.conf",
++    "conf.d/49-sansserif.conf",
++    "conf.d/60-latin.conf",
++    "%test%/test-issue-525.conf",
++  ],
++  "tests": [
++    {
++      "method": "match",
++      "query": {
++        "family": "system-ui"
++      },
++      "result": {
++        "family": "Lato",
++        "style": "Regular",
++        "file": "/path/to/Lato.ttf",
++        "fontversion": 1
++      }
++    }
++  ]
++}
+-- 
+GitLab
+
+From 66757ccdbd43260bba3195265311cf8ca268f0d4 Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira at tagoh.org>
+Date: Thu, 28 May 2026 12:56:25 +0900
+Subject: [PATCH 1/2] Do not set 'sans-serif' for default genericfamily
+
+To allow a custom family name for alias.
+
+Changelog: fixed
+---
+ conf.d/49-sansserif.conf   | 21 ---------------------
+ test/test-issue-525-2.conf |  8 ++++++++
+ test/test-issue-525-2.json | 38 ++++++++++++++++++++++++++++++++++++++
+ test/test-issue-525.json   |  2 +-
+ 4 files changed, 47 insertions(+), 22 deletions(-)
+ create mode 100644 test/test-issue-525-2.conf
+ create mode 100644 test/test-issue-525-2.json
+
+diff --git a/conf.d/49-sansserif.conf b/conf.d/49-sansserif.conf
+index 8446b235..b6f8f713 100644
+--- a/conf.d/49-sansserif.conf
++++ b/conf.d/49-sansserif.conf
+@@ -45,27 +45,6 @@
+     </edit>
+   </match>
+ 
+-  <!--
+-      If the font still has no generic name, add sans-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 qual="all" name="family" compare="not_eq">
+-	  <string>monospace</string>
+-	</test>
+-    <test qual="all" name="genericfamily" compare="contains">
+-      <const xsi:nil="true" />
+-    </test>
+-    <edit name="genericfamily" mode="append">
+-      <const>sans-serif</const>
+-    </edit>
+-  </match>
+-
+   <match target="pattern">
+ 	<test qual="all" name="family" compare="not_eq">
+ 	  <string>sans-serif</string>
+diff --git a/test/test-issue-525-2.conf b/test/test-issue-525-2.conf
+new file mode 100644
+index 00000000..8531931c
+--- /dev/null
++++ b/test/test-issue-525-2.conf
+@@ -0,0 +1,8 @@
++<fontconfig>
++  <alias>
++    <family>-apple-system</family>
++    <prefer>
++      <family>Lato</family>
++    </prefer>
++  </alias>
++</fontconfig>
+diff --git a/test/test-issue-525-2.json b/test/test-issue-525-2.json
+new file mode 100644
+index 00000000..cf410cab
+--- /dev/null
++++ b/test/test-issue-525-2.json
+@@ -0,0 +1,38 @@
++{
++  "fonts": [
++    {
++      "family": "Noto Sans",
++      "style": "Regular",
++      "file": "/path/to/NotoSans.ttf",
++      "fontversion": 1,
++      "genericfamily": 2
++    },
++    {
++      "family": "Lato",
++      "style": "Regular",
++      "file": "/path/to/Lato.ttf",
++      "fontversion": 1,
++      "genericfamily": 0
++    }
++  ],
++  "load_xml": [
++    "conf.d/48-guessfamily.conf",
++    "conf.d/49-sansserif.conf",
++    "%test%/test-issue-525-2.conf",
++    "conf.d/60-latin.conf",
++  ],
++  "tests": [
++    {
++      "method": "match",
++      "query": {
++        "family": "-apple-system",
++      },
++      "result": {
++        "family": "Lato",
++        "style": "Regular",
++        "file": "/path/to/Lato.ttf",
++        "fontversion": 1
++      }
++    }
++  ]
++}
+diff --git a/test/test-issue-525.json b/test/test-issue-525.json
+index 86e9890e..cf61dc19 100644
+--- a/test/test-issue-525.json
++++ b/test/test-issue-525.json
+@@ -18,8 +18,8 @@
+   "load_xml": [
+     "conf.d/48-guessfamily.conf",
+     "conf.d/49-sansserif.conf",
+-    "conf.d/60-latin.conf",
+     "%test%/test-issue-525.conf",
++    "conf.d/60-latin.conf",
+   ],
+   "tests": [
+     {
+-- 
+GitLab
+
+
+From 31d3b16c97f8965eec7e3361015b3cb10910fc12 Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira at tagoh.org>
+Date: Thu, 28 May 2026 13:00:06 +0900
+Subject: [PATCH 2/2] test: use const instead of number for genericfamily
+
+---
+ test/test-48-guessfamily.json | 16 ++++++++--------
+ test/test-issue-525-2.json    |  2 +-
+ test/test-issue-525.json      |  2 +-
+ 3 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/test/test-48-guessfamily.json b/test/test-48-guessfamily.json
+index 7dedbf81..01fe8e1f 100644
+--- a/test/test-48-guessfamily.json
++++ b/test/test-48-guessfamily.json
+@@ -5,28 +5,28 @@
+       "style": "Regular",
+       "file": "/path/to/LiberationMono-Regular.ttf",
+       "fontversion": 1,
+-      "genericfamily": 3
++      "genericfamily": "monospace"
+     },
+     {
+       "family": "Liberation Sans",
+       "style": "Regular",
+       "file": "/path/to/LiberationSans-Regular.ttf",
+       "fontversion": 1,
+-      "genericfamily": 2
++      "genericfamily": "sans-serif"
+     },
+     {
+       "family": "Liberation Serif",
+       "style": "Regular",
+       "file": "/path/to/LiberationSerif-Regular.ttf",
+       "fontversion": 1,
+-      "genericfamily": 1
++      "genericfamily": "serif"
+     },
+     {
+       "family": "Noto Sans Mono",
+       "style": "Regular",
+       "file": "/path/to/NotoSansMono-Regular.ttf",
+       "fontversion": 1,
+-      "genericfamily": 3
++      "genericfamily": "monospace"
+     },
+   ],
+   "tests": [
+@@ -40,7 +40,7 @@
+         "style": "Regular",
+         "file": "/path/to/LiberationMono-Regular.ttf",
+         "fontversion": 1,
+-        "genericfamily": 3
++        "genericfamily": "monospace"
+       }
+     },
+     {
+@@ -53,7 +53,7 @@
+         "style": "Regular",
+         "file": "/path/to/LiberationSans-Regular.ttf",
+         "fontversion": 1,
+-        "genericfamily": 2
++        "genericfamily": "sans-serif"
+       }
+     },
+     {
+@@ -66,7 +66,7 @@
+         "style": "Regular",
+         "file": "/path/to/LiberationSerif-Regular.ttf",
+         "fontversion": 1,
+-        "genericfamily": 1
++        "genericfamily": "serif"
+       }
+     },
+     {
+@@ -79,7 +79,7 @@
+         "style": "Regular",
+         "file": "/path/to/LiberationSans-Regular.ttf",
+         "fontversion": 1,
+-        "genericfamily": 2
++        "genericfamily": "sans-serif"
+       }
+     },
+     {
+diff --git a/test/test-issue-525-2.json b/test/test-issue-525-2.json
+index cf410cab..ccf0e90f 100644
+--- a/test/test-issue-525-2.json
++++ b/test/test-issue-525-2.json
+@@ -5,7 +5,7 @@
+       "style": "Regular",
+       "file": "/path/to/NotoSans.ttf",
+       "fontversion": 1,
+-      "genericfamily": 2
++      "genericfamily": "sans-serif"
+     },
+     {
+       "family": "Lato",
+diff --git a/test/test-issue-525.json b/test/test-issue-525.json
+index cf61dc19..ba8e3332 100644
+--- a/test/test-issue-525.json
++++ b/test/test-issue-525.json
+@@ -5,7 +5,7 @@
+       "style": "Regular",
+       "file": "/path/to/NotoSans.ttf",
+       "fontversion": 1,
+-      "genericfamily": 1
++      "genericfamily": "sans-serif"
+     },
+     {
+       "family": "Lato",
+-- 
+GitLab
+
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/fontconfig.git/commitdiff/0a442c7f751503ec88e0bafc214cf4cb26aa6ebe



More information about the pld-cvs-commit mailing list