[Fontconfig] fontconfig: Branch 'master' - 4 commits

Akira TAGOH tagoh at kemper.freedesktop.org
Fri May 11 13:18:18 UTC 2018


 conf.d/90-synthetic.conf    |    4 
 configure.ac                |    9 +
 doc/fcpattern.fncs          |  111 ++++++++++++++
 fontconfig/fontconfig.h     |   33 ++++
 src/fcdbg.c                 |   15 --
 src/fcdefault.c             |   32 ++--
 src/fcformat.c              |   22 --
 src/fcint.h                 |    9 +
 src/fcpat.c                 |  233 +++++++++++++++++++++++++------
 test/Makefile.am            |   16 +-
 test/run-test-conf.sh       |   36 ++++
 test/test-90-synthetic.json |   68 +++++++++
 test/test-conf.c            |  328 ++++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 829 insertions(+), 87 deletions(-)

New commits:
commit af964f789762df0b023c8cfd7ea622045892cb54
Author: Akira TAGOH <akira at tagoh.org>
Date:   Fri May 11 22:15:39 2018 +0900

    Add a test case for 90-synthetic.conf

diff --git a/test/Makefile.am b/test/Makefile.am
index 117ba01..48ec3ce 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -13,7 +13,12 @@ BUILT_SOURCES = $(builddir)/out.expected
 SH_LOG_COMPILER = sh
 TESTS=run-test.sh
 
-TESTDATA=4x6.pcf 8x16.pcf fonts.conf.in
+TESTDATA =			\
+	4x6.pcf			\
+	8x16.pcf		\
+	fonts.conf.in		\
+	test-90-synthetic.json	\
+	$(NULL)
 
 if FREETYPE_PCF_LONG_FAMILY_NAMES
 $(builddir)/out.expected: $(srcdir)/out.expected-long-family-names Makefile
@@ -63,10 +68,10 @@ if ENABLE_JSONC
 check_PROGRAMS += test-conf
 test_conf_CFLAGS = $(JSONC_CFLAGS)
 test_conf_LDADD = $(top_builddir)/src/libfontconfig.la $(JSONC_LIBS)
-TESTS += test-conf.sh
+TESTS += run-test-conf.sh
 endif
 
-EXTRA_DIST=run-test.sh $(TESTDATA) out.expected-long-family-names out.expected-no-long-family-names
+EXTRA_DIST=run-test.sh run-test-conf.sh $(TESTDATA) out.expected-long-family-names out.expected-no-long-family-names
 
 CLEANFILES=out fonts.conf out.expected
 
diff --git a/test/run-test-conf.sh b/test/run-test-conf.sh
new file mode 100644
index 0000000..4bcc29c
--- /dev/null
+++ b/test/run-test-conf.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# test/run-test-conf.sh
+#
+# Copyright © 2000 Keith Packard
+# Copyright © 2018 Akira TAGOH
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of the author(s) not be used in
+# advertising or publicity pertaining to distribution of the software without
+# specific, written prior permission.  The authors make no
+# representations about the suitability of this software for any purpose.  It
+# is provided "as is" without express or implied warranty.
+#
+# THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+set -eu
+
+case "$OSTYPE" in
+    msys ) MyPWD=`pwd -W` ;;  # On Msys/MinGW, returns a MS Windows style path.
+    *    ) MyPWD=`pwd`    ;;  # On any other platforms, returns a Unix style path.
+esac
+
+TESTDIR=${srcdir-"$MyPWD"}
+BUILDTESTDIR=${builddir-"$MyPWD"}
+
+RUNNER=../test/test-conf$EXEEXT
+
+$RUNNER $TESTDIR/../conf.d/90-synthetic.conf $TESTDIR/test-90-synthetic.json
diff --git a/test/test-90-synthetic.json b/test/test-90-synthetic.json
new file mode 100644
index 0000000..4205402
--- /dev/null
+++ b/test/test-90-synthetic.json
@@ -0,0 +1,68 @@
+{
+    "fonts": [
+        {
+            "family": "Foo",
+            "style": "Medium",
+            "weight": 100
+        },
+        {
+            "family": "Bar",
+            "style": "Regular",
+            "weight": 80
+        },
+        {
+            "family": "Baz",
+            "style": "Bold",
+            "weight": 200
+        }
+    ],
+    "tests": [
+        {
+            "method": "match",
+            "query": {
+                "family": "Foo",
+                "weight": 200
+            },
+            "result": {
+                "family": "Foo",
+                "weight": 200,
+                "embolden": true
+            }
+        },
+        {
+            "method": "match",
+            "query": {
+                "family": "Bar",
+                "weight": 102
+            },
+            "result": {
+                "family": "Bar",
+                "weight": 80
+            }
+        },
+        {
+            "method": "match",
+            "query": {
+                "family": "Bar",
+                "weight": 200
+            },
+            "result": {
+                "family": "Bar",
+                "weight": 200,
+                "embolden": true
+            }
+        },
+        {
+            "method": "match",
+            "query": {
+                "family": "Baz",
+                "weight": 200
+            },
+            "result": {
+                "family": "Baz",
+                "weight": 200,
+                "embolden": null
+            }
+        }
+    ]
+}
commit f665852df90cd5a28c3040af8f484999ca3dfa4e
Author: Akira TAGOH <akira at tagoh.org>
Date:   Fri May 11 21:39:50 2018 +0900

    Add a testrunner for conf

diff --git a/configure.ac b/configure.ac
index 557d151..3e37663 100644
--- a/configure.ac
+++ b/configure.ac
@@ -474,6 +474,15 @@ if test "$enable_libxml2" = "yes"; then
 fi
 
 #
+# Check json-c
+#
+PKG_CHECK_MODULES([JSONC], [json-c], [use_jsonc=yes], [use_jsonc=no])
+
+AM_CONDITIONAL(ENABLE_JSONC, test "x$use_jsonc" = "xyes")
+AC_SUBST(JSONC_CFLAGS)
+AC_SUBST(JSONC_LIBS)
+
+#
 # Set default hinting
 #
 
diff --git a/test/Makefile.am b/test/Makefile.am
index e5b8626..117ba01 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -59,6 +59,13 @@ check_PROGRAMS += test-name-parse
 test_name_parse_LDADD = $(top_builddir)/src/libfontconfig.la
 TESTS += test-name-parse
 
+if ENABLE_JSONC
+check_PROGRAMS += test-conf
+test_conf_CFLAGS = $(JSONC_CFLAGS)
+test_conf_LDADD = $(top_builddir)/src/libfontconfig.la $(JSONC_LIBS)
+TESTS += test-conf.sh
+endif
+
 EXTRA_DIST=run-test.sh $(TESTDATA) out.expected-long-family-names out.expected-no-long-family-names
 
 CLEANFILES=out fonts.conf out.expected
diff --git a/test/test-conf.c b/test/test-conf.c
new file mode 100644
index 0000000..6619ea7
--- /dev/null
+++ b/test/test-conf.c
@@ -0,0 +1,328 @@
+/*
+ * fontconfig/test/test-conf.c
+ *
+ * Copyright © 2000 Keith Packard
+ * Copyright © 2018 Akira TAGOH
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The authors make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <fontconfig/fontconfig.h>
+#include <json.h>
+
+struct _FcConfig {
+    FcStrSet	*configDirs;	    /* directories to scan for fonts */
+    FcStrSet	*fontDirs;
+    FcStrSet	*cacheDirs;
+    FcStrSet	*configFiles;	    /* config files loaded */
+    void	*subst[FcMatchKindEnd];
+    int		maxObjects;	    /* maximum number of tests in all substs */
+    FcStrSet	*acceptGlobs;
+    FcStrSet	*rejectGlobs;
+    FcFontSet	*acceptPatterns;
+    FcFontSet	*rejectPatterns;
+    FcFontSet	*fonts[FcSetApplication + 1];
+};
+
+static FcPattern *
+build_pattern (json_object *obj)
+{
+    json_object_iter iter;
+    FcPattern *pat = FcPatternCreate ();
+
+    json_object_object_foreachC (obj, iter)
+    {
+	FcValue v;
+
+	if (json_object_get_type (iter.val) == json_type_boolean)
+	{
+	    v.type = FcTypeBool;
+	    v.u.b = json_object_get_boolean (iter.val);
+	}
+	else if (json_object_get_type (iter.val) == json_type_double)
+	{
+	    v.type = FcTypeDouble;
+	    v.u.d = json_object_get_double (iter.val);
+	}
+	else if (json_object_get_type (iter.val) == json_type_int)
+	{
+	    v.type = FcTypeInteger;
+	    v.u.i = json_object_get_int (iter.val);
+	}
+	else if (json_object_get_type (iter.val) == json_type_string)
+	{
+	    v.type = FcTypeString;
+	    v.u.s = json_object_get_string (iter.val);
+	}
+	else if (json_object_get_type (iter.val) == json_type_null)
+	{
+	    v.type = FcTypeVoid;
+	}
+	else
+	{
+	    fprintf (stderr, "W: unexpected object to build a pattern: (%s %s)", iter.key, json_type_to_name (json_object_get_type (iter.val)));
+	    continue;
+	}
+	FcPatternAdd (pat, iter.key, v, FcTrue);
+    }
+    return pat;
+}
+
+static FcBool
+build_fonts (FcConfig *config, json_object *root)
+{
+    json_object *fonts;
+    FcFontSet *fs;
+    int i, n;
+
+    if (!json_object_object_get_ex (root, "fonts", &fonts) ||
+	json_object_get_type (fonts) != json_type_array)
+    {
+	fprintf (stderr, "W: No fonts defined\n");
+	return FcFalse;
+    }
+    fs = FcFontSetCreate ();
+    n = json_object_array_length (fonts);
+    for (i = 0; i < n; i++)
+    {
+	json_object *obj = json_object_array_get_idx (fonts, i);
+	FcPattern *pat;
+
+	if (json_object_get_type (obj) != json_type_object)
+	    continue;
+	pat = build_pattern (obj);
+	FcFontSetAdd (fs, pat);
+    }
+    /* FcConfigSetFonts (config, fs, FcSetSystem); */
+    if (config->fonts[FcSetSystem])
+	FcFontSetDestroy (config->fonts[FcSetSystem]);
+    config->fonts[FcSetSystem] = fs;
+
+    return FcTrue;
+}
+
+static FcBool
+run_test (FcConfig *config, json_object *root)
+{
+    json_object *tests;
+    FcFontSet *fs;
+    int i, n, fail = 0;
+
+    if (!json_object_object_get_ex (root, "tests", &tests) ||
+	json_object_get_type (tests) != json_type_array)
+    {
+	fprintf (stderr, "W: No test cases defined\n");
+	return FcFalse;
+    }
+    fs = FcFontSetCreate ();
+    n = json_object_array_length (tests);
+    for (i = 0; i < n; i++)
+    {
+	json_object *obj = json_object_array_get_idx (tests, i);
+	json_object_iter iter;
+	FcPattern *query, *result;
+	const char *method;
+
+	if (json_object_get_type (obj) != json_type_object)
+	    continue;
+	json_object_object_foreachC (obj, iter)
+	{
+	    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;
+		}
+		method = json_object_get_string (iter.val);
+	    }
+	    else if (strcmp (iter.key, "query") == 0)
+	    {
+		if (json_object_get_type (iter.val) != json_type_object)
+		{
+		    fprintf (stderr, "W: invalid type of query: (%s)\n", json_type_to_name (json_object_get_type (iter.val)));
+		    continue;
+		}
+		query = build_pattern (iter.val);
+	    }
+	    else if (strcmp (iter.key, "result") == 0)
+	    {
+		if (json_object_get_type (iter.val) != json_type_object)
+		{
+		    fprintf (stderr, "W: invalid type of result: (%s)\n", json_type_to_name (json_object_get_type (iter.val)));
+		    continue;
+		}
+		result = build_pattern (iter.val);
+	    }
+	    else
+	    {
+		fprintf (stderr, "W: unknown object: %s\n", iter.key);
+	    }
+	}
+	if (strcmp (method, "match") == 0)
+	{
+	    FcPattern *match;
+	    FcResult res;
+
+	    FcConfigSubstitute (config, query, FcMatchPattern);
+	    FcDefaultSubstitute (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:;
+	    }
+	    else
+	    {
+		fprintf (stderr, "E: no match\n");
+		fail++;
+	    }
+	}
+	else
+	{
+	    fprintf (stderr, "W: unknown testing method: %s\n", method);
+	}
+    }
+
+    return fail == 0;
+}
+
+static FcBool
+run_scenario (FcConfig *config, char *file)
+{
+    FcBool ret = FcTrue;
+    json_object *root, *scenario;
+
+    root = json_object_from_file (file);
+    if (!root)
+    {
+	fprintf (stderr, "E: Unable to read the file: %s\n", file);
+	return FcFalse;
+    }
+    if (!build_fonts (config, root))
+    {
+	ret = FcFalse;
+	goto bail1;
+    }
+    if (!run_test (config, root))
+    {
+	ret = FcFalse;
+	goto bail1;
+    }
+
+bail1:
+    json_object_put (root);
+
+    return ret;
+}
+
+static FcBool
+load_config (FcConfig *config, char *file)
+{
+    FILE *fp;
+    long len;
+    char *buf = NULL;
+    FcBool ret = FcTrue;
+
+    if ((fp = fopen(file, "rb")) == NULL)
+	return FcFalse;
+    fseek (fp, 0L, SEEK_END);
+    len = ftell (fp);
+    fseek (fp, 0L, SEEK_SET);
+    buf = malloc (sizeof (char) * (len + 1));
+    if (!buf)
+    {
+	ret = FcFalse;
+	goto bail1;
+    }
+    fread (buf, (size_t)len, sizeof (char), fp);
+    buf[len] = 0;
+
+    ret = FcConfigParseAndLoadFromMemory (config, buf, FcTrue);
+bail1:
+    fclose (fp);
+    if (buf)
+	free (buf);
+
+    return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+    FcConfig *config;
+    int retval = 0;
+
+    if (argc < 3)
+    {
+	fprintf(stderr, "Usage: %s <conf file> <test scenario>\n", argv[0]);
+	return 1;
+    }
+
+    config = FcConfigCreate ();
+    if (!load_config (config, argv[1]))
+    {
+	fprintf(stderr, "E: Failed to load config\n");
+	retval = 1;
+	goto bail1;
+    }
+    if (!run_scenario (config, argv[2]))
+    {
+	retval = 1;
+	goto bail1;
+    }
+bail1:
+    FcConfigDestroy (config);
+
+    return retval;
+}
commit 307639cff143341cb10273db1a19264ba28b247e
Author: Akira TAGOH <akira at tagoh.org>
Date:   Fri May 11 20:48:30 2018 +0900

    Bug 43367 - RFE: iterator to peek objects in FcPattern
    
    Add various APIs to obtain things in FcPattern through the iterator
    
    https://bugs.freedesktop.org/show_bug.cgi?id=43367

diff --git a/doc/fcpattern.fncs b/doc/fcpattern.fncs
index 928f0bc..3b13c22 100644
--- a/doc/fcpattern.fncs
+++ b/doc/fcpattern.fncs
@@ -57,6 +57,15 @@ Decrement the pattern reference count. If all references are gone, destroys
 the pattern, in the process destroying all related values.
 @@
 
+ at RET@		int
+ at FUNC@		FcPatternObjectCount
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at PURPOSE@	Returns the number of the object
+ at DESC@
+Returns the number of the object <parameter>p</parameter> has.
+ at SINCE@		2.13.1
+@@
+
 @RET@		FcBool
 @FUNC@		FcPatternEqual
 @TYPE1@ 	const FcPattern *		@ARG1@ 		pa
@@ -383,7 +392,107 @@ whether the property existed or not.
 Removes the value associated with the property `object' at position `id', returning 
 whether the property existed and had a value at that position or not.
 @@
-		
+
+ at RET@		void
+ at FUNC@		FcPatternIterStart
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at TYPE2@		FcPatternIter *			@ARG2@		iter
+ at PURPOSE@	Initialize the iterator with the first iterator in the pattern
+ at DESC@
+Initialize <parameter>iter</parameter> with the first iterator in <parameter>p</parameter>.
+If there are no objects in <parameter>p</parameter>, <parameter>iter</parameter>
+will not have any valid data.
+ at SINCE@		2.13.1
+@@
+
+ at RET@		FcBool
+ at FUNC@		FcPatternIterNext
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at TYPE2@		FcPatternIter *			@ARG2@		iter
+ at PURPUSE@	Set the iterator to point to the next object in the pattern
+ at DESC@
+Set <parameter>iter</parameter> to point to the next object in <parameter>p</parameter>
+and returns FcTrue if <parameter>iter</parameter> has been changed to the next object.
+returns FcFalse otherwise.
+ at SINCE@		2.13.1
+@@
+
+ at RET@		FcBool
+ at FUNC@		FcPatternIterEqual
+ at TYPE1@		const FcPattern *		@ARG1@		p1
+ at TYPE2@		FcPatternIter *			@ARG2@		i1
+ at TYPE3@		const FcPattern *		@ARG3@		p2
+ at TYPE4@		FcPatternIter *			@ARG4@		i2
+ at PURPOSE@	Compare iterators
+ at DESC@
+Return FcTrue if both <parameter>i1</parameter> and <parameter>i2</parameter>
+point to same object and contains same values. return FcFalse otherwise.
+ at SINCE@		2.13.1
+@@
+
+ at RET@		FcBool
+ at FUNC@		FcPatternFindIter
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at TYPE2@		FcPatternIter *			@ARG2@		iter
+ at TYPE3@		const char *  			@ARG3@		object
+ at PURPOSE@	Set the iterator to point to the object in the pattern
+ at DESC@
+Set <parameter>iter</parameter> to point to <parameter>object</parameter> in
+<parameter>p</parameter> if any and returns FcTrue. returns FcFalse otherwise.
+ at SINCE@		2.13.1
+@@
+
+ at RET@		FcBool
+ at FUNC@		FcPatternIterIsValid
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at TYPE2@		FcPatternIter :			@ARG2@		iter
+ at PURPOSE@	Check whether the iterator is valid or not
+ at DESC@
+Returns FcTrue if <parameter>iter</parameter> point to the valid entry
+in <parameter>p</parameter>. returns FcFalse otherwise.
+ at SINCE@		2.13.1
+@@
+
+ at RET@		const char *
+ at FUNC@		FcPatternIterGetObject
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at TYPE2@		FcPatternIter *			@ARG2@		iter
+ at PURPOSE@	Returns an object name which the iterator point to
+ at DESC@
+Returns an object name in <parameter>p</parameter> which
+<parameter>iter</parameter> point to. returns NULL if
+<parameter>iter</parameter> isn't valid.
+ at SINCE@		2.13.1
+@@
+
+ at RET@		int
+ at FUNC@		FcPatternIterValueCount
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at TYPE2@		FcPatternIter *			@ARG2@		iter
+ at PURPOSE@	Returns the number of the values which the iterator point to
+ at DESC@
+Returns the number of the values in the object which <parameter>iter</parameter>
+point to. if <parameter>iter</parameter> isn't valid, returns 0.
+ at SINCE@		2.13.1
+@@
+
+ at RET@		FcResult
+ at FUNC@		FcPatternIterGetValue
+ at TYPE1@		const FcPattern *		@ARG1@		p
+ at TYPE2@		FcPatternIter *			@ARG2@		iter
+ at TYPE3@		int	      			@ARG3@		id
+ at TYPE4@		FcValue *			@ARG4@		v
+ at TYPE5@		FcValueBinding *		@ARG5@		b
+ at PURPOSE@	Returns a value which the iterator point to
+ at DESC@
+Returns in <parameter>v</parameter> the <parameter>id</parameter>'th value
+which <parameter>iter</parameter> point to. also binding to <parameter>b</parameter>
+if given.
+The value returned is not a copy, but rather refers to the data stored
+within the pattern directly.  Applications must not free this value.
+ at SINCE@		2.13.1
+@@
+
 @RET@		void
 @FUNC@		FcPatternPrint
 @TYPE1@		const FcPattern *		@ARG1@		p 
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
index a89b22f..5c04219 100644
--- a/fontconfig/fontconfig.h
+++ b/fontconfig/fontconfig.h
@@ -248,6 +248,11 @@ typedef enum _FcValueBinding {
 
 typedef struct _FcPattern   FcPattern;
 
+typedef struct _FcPatternIter {
+    void *dummy1;
+    void *dummy2;
+} FcPatternIter;
+
 typedef struct _FcLangSet   FcLangSet;
 
 typedef struct _FcRange	    FcRange;
@@ -861,6 +866,9 @@ FcValueSave (FcValue v);
 FcPublic void
 FcPatternDestroy (FcPattern *p);
 
+int
+FcPatternObjectCount (const FcPattern *pat);
+
 FcPublic FcBool
 FcPatternEqual (const FcPattern *pa, const FcPattern *pb);
 
@@ -961,6 +969,31 @@ FcRangeCopy (const FcRange *r);
 FcPublic FcBool
 FcRangeGetDouble(const FcRange *range, double *begin, double *end);
 
+FcPublic void
+FcPatternIterStart (const FcPattern *pat, FcPatternIter *iter);
+
+FcPublic FcBool
+FcPatternIterNext (const FcPattern *pat, FcPatternIter *iter);
+
+FcPublic FcBool
+FcPatternIterEqual (const FcPattern *p1, FcPatternIter *i1,
+		    const FcPattern *p2, FcPatternIter *i2);
+
+FcPublic FcBool
+FcPatternFindIter (const FcPattern *pat, FcPatternIter *iter, const char *object);
+
+FcPublic FcBool
+FcPatternIterIsValid (const FcPattern *pat, FcPatternIter *iter);
+
+FcPublic const char *
+FcPatternIterGetObject (const FcPattern *pat, FcPatternIter *iter);
+
+FcPublic int
+FcPatternIterValueCount (const FcPattern *pat, FcPatternIter *iter);
+
+FcPublic FcResult
+FcPatternIterGetValue (const FcPattern *pat, FcPatternIter *iter, int id, FcValue *v, FcValueBinding *b);
+
 /* fcweight.c */
 
 FcPublic int
diff --git a/src/fcdbg.c b/src/fcdbg.c
index 2e16a31..e2c6b56 100644
--- a/src/fcdbg.c
+++ b/src/fcdbg.c
@@ -187,22 +187,21 @@ FcCharSetPrint (const FcCharSet *c)
 void
 FcPatternPrint (const FcPattern *p)
 {
-    int		    i;
-    FcPatternElt   *e;
+    FcPatternIter iter;
 
     if (!p)
     {
 	printf ("Null pattern\n");
 	return;
     }
-    printf ("Pattern has %d elts (size %d)\n", p->num, p->size);
-    for (i = 0; i < p->num; i++)
+    printf ("Pattern has %d elts (size %d)\n", FcPatternObjectCount (p), p->size);
+    FcPatternIterStart (p, &iter);
+    do
     {
-	e = &FcPatternElts(p)[i];
-	printf ("\t%s:", FcObjectName(e->object));
-	FcValueListPrint (FcPatternEltValues(e));
+	printf ("\t%s:", FcPatternIterGetObject (p, &iter));
+	FcValueListPrint (FcPatternIterGetValues (p, &iter));
 	printf ("\n");
-    }
+    } while (FcPatternIterNext (p, &iter));
     printf ("\n");
 }
 
diff --git a/src/fcdefault.c b/src/fcdefault.c
index 35973d7..f3addca 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -238,21 +238,22 @@ FcDefaultFini (void)
 void
 FcDefaultSubstitute (FcPattern *pattern)
 {
+    FcPatternIter iter;
     FcValue v, namelang, v2;
     int	    i;
     double	dpi, size, scale, pixelsize;
 
-    if (FcPatternObjectGet (pattern, FC_WEIGHT_OBJECT, 0, &v) == FcResultNoMatch )
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_WEIGHT_OBJECT))
 	FcPatternObjectAddInteger (pattern, FC_WEIGHT_OBJECT, FC_WEIGHT_NORMAL);
 
-    if (FcPatternObjectGet (pattern, FC_SLANT_OBJECT, 0, &v) == FcResultNoMatch)
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_SLANT_OBJECT))
 	FcPatternObjectAddInteger (pattern, FC_SLANT_OBJECT, FC_SLANT_ROMAN);
 
-    if (FcPatternObjectGet (pattern, FC_WIDTH_OBJECT, 0, &v) == FcResultNoMatch)
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_WIDTH_OBJECT))
 	FcPatternObjectAddInteger (pattern, FC_WIDTH_OBJECT, FC_WIDTH_NORMAL);
 
     for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++)
-	if (FcPatternObjectGet (pattern, FcBoolDefaults[i].field, 0, &v) == FcResultNoMatch)
+	if (!FcPatternFindObjectIter (pattern, &iter, FcBoolDefaults[i].field))
 	    FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
 
     if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch)
@@ -269,7 +270,7 @@ FcDefaultSubstitute (FcPattern *pattern)
     if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
 	dpi = 75.0;
 
-    if (FcPatternObjectGet (pattern, FC_PIXEL_SIZE_OBJECT, 0, &v) != FcResultMatch)
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_PIXEL_SIZE_OBJECT))
     {
 	(void) FcPatternObjectDel (pattern, FC_SCALE_OBJECT);
 	FcPatternObjectAddDouble (pattern, FC_SCALE_OBJECT, scale);
@@ -281,25 +282,22 @@ FcDefaultSubstitute (FcPattern *pattern)
     }
     else
     {
+	FcPatternIterGetValue(pattern, &iter, 0, &v, NULL);
 	size = v.u.d;
 	size = size / dpi * 72.0 / scale;
     }
     (void) FcPatternObjectDel (pattern, FC_SIZE_OBJECT);
     FcPatternObjectAddDouble (pattern, FC_SIZE_OBJECT, size);
 
-    if (FcPatternObjectGet (pattern, FC_FONTVERSION_OBJECT, 0, &v) == FcResultNoMatch)
-    {
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_FONTVERSION_OBJECT))
 	FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff);
-    }
 
-    if (FcPatternObjectGet (pattern, FC_HINT_STYLE_OBJECT, 0, &v) == FcResultNoMatch)
-    {
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_HINT_STYLE_OBJECT))
 	FcPatternObjectAddInteger (pattern, FC_HINT_STYLE_OBJECT, FC_HINT_FULL);
-    }
-    if (FcPatternObjectGet (pattern, FC_NAMELANG_OBJECT, 0, &v) == FcResultNoMatch)
-    {
+
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_NAMELANG_OBJECT))
 	FcPatternObjectAddString (pattern, FC_NAMELANG_OBJECT, FcGetDefaultLang ());
-    }
+
     /* shouldn't be failed. */
     FcPatternObjectGet (pattern, FC_NAMELANG_OBJECT, 0, &namelang);
     /* Add a fallback to ensure the english name when the requested language
@@ -315,17 +313,17 @@ FcDefaultSubstitute (FcPattern *pattern)
      */
     v2.type = FcTypeString;
     v2.u.s = (FcChar8 *) "en-us";
-    if (FcPatternObjectGet (pattern, FC_FAMILYLANG_OBJECT, 0, &v) == FcResultNoMatch)
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_FAMILYLANG_OBJECT))
     {
 	FcPatternObjectAdd (pattern, FC_FAMILYLANG_OBJECT, namelang, FcTrue);
 	FcPatternObjectAddWithBinding (pattern, FC_FAMILYLANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
     }
-    if (FcPatternObjectGet (pattern, FC_STYLELANG_OBJECT, 0, &v) == FcResultNoMatch)
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_STYLELANG_OBJECT))
     {
 	FcPatternObjectAdd (pattern, FC_STYLELANG_OBJECT, namelang, FcTrue);
 	FcPatternObjectAddWithBinding (pattern, FC_STYLELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
     }
-    if (FcPatternObjectGet (pattern, FC_FULLNAMELANG_OBJECT, 0, &v) == FcResultNoMatch)
+    if (!FcPatternFindObjectIter (pattern, &iter, FC_FULLNAMELANG_OBJECT))
     {
 	FcPatternObjectAdd (pattern, FC_FULLNAMELANG_OBJECT, namelang, FcTrue);
 	FcPatternObjectAddWithBinding (pattern, FC_FULLNAMELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
diff --git a/src/fcformat.c b/src/fcformat.c
index 59f8681..c76dc5e 100644
--- a/src/fcformat.c
+++ b/src/fcformat.c
@@ -544,7 +544,7 @@ interpret_count (FcFormatContext *c,
 		 FcStrBuf        *buf)
 {
     int count;
-    FcPatternElt *e;
+    FcPatternIter iter;
     FcChar8 buf_static[64];
 
     if (!expect_char (c, '#'))
@@ -554,16 +554,9 @@ interpret_count (FcFormatContext *c,
 	return FcFalse;
 
     count = 0;
-    e = FcPatternObjectFindElt (pat,
-				FcObjectFromName ((const char *) c->word));
-    if (e)
+    if (FcPatternFindIter (pat, &iter, (const char *) c->word))
     {
-	FcValueListPtr l;
-	count++;
-	for (l = FcPatternEltValues(e);
-	     l->next;
-	     l = l->next)
-	    count++;
+	count = FcPatternIterValueCount (pat, &iter);
     }
 
     snprintf ((char *) buf_static, sizeof (buf_static), "%d", count);
@@ -695,7 +688,7 @@ interpret_simple (FcFormatContext *c,
 		  FcPattern       *pat,
 		  FcStrBuf        *buf)
 {
-    FcPatternElt *e;
+    FcPatternIter iter;
     FcBool        add_colon = FcFalse;
     FcBool        add_elt_name = FcFalse;
     int           idx;
@@ -743,9 +736,7 @@ interpret_simple (FcFormatContext *c,
 	c->word = orig;
     }
 
-    e = FcPatternObjectFindElt (pat,
-				FcObjectFromName ((const char *) c->word));
-    if (e || else_string)
+    if (FcPatternFindIter (pat, &iter, (const char *) c->word) || else_string)
     {
 	FcValueListPtr l = NULL;
 
@@ -757,8 +748,7 @@ interpret_simple (FcFormatContext *c,
 	    FcStrBufChar (buf, '=');
 	}
 
-	if (e)
-	    l = FcPatternEltValues(e);
+	l = FcPatternIterGetValues (pat, &iter);
 
 	if (idx != -1)
 	{
diff --git a/src/fcint.h b/src/fcint.h
index d837a38..a402ca2 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -1150,6 +1150,15 @@ FcPatternAppend (FcPattern *p, FcPattern *s);
 FcPrivate int
 FcPatternPosition (const FcPattern *p, const char *object);
 
+FcPrivate FcBool
+FcPatternFindObjectIter (const FcPattern *pat, FcPatternIter *iter, FcObject object);
+
+FcPrivate FcObject
+FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter);
+
+FcPrivate FcValueListPtr
+FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter);
+
 FcPrivate FcChar32
 FcStringHash (const FcChar8 *s);
 
diff --git a/src/fcpat.c b/src/fcpat.c
index e624aea..eb534c3 100644
--- a/src/fcpat.c
+++ b/src/fcpat.c
@@ -392,13 +392,23 @@ FcPatternDestroy (FcPattern *p)
 	return;
 
     elts = FcPatternElts (p);
-    for (i = 0; i < p->num; i++)
+    for (i = 0; i < FcPatternObjectCount (p); i++)
 	FcValueListDestroy (FcPatternEltValues(&elts[i]));
 
     free (elts);
     free (p);
 }
 
+int
+FcPatternObjectCount (const FcPattern *pat)
+{
+    if (pat)
+	return pat->num;
+
+    return 0;
+}
+
+
 static int
 FcPatternObjectPosition (const FcPattern *p, FcObject object)
 {
@@ -406,7 +416,7 @@ FcPatternObjectPosition (const FcPattern *p, FcObject object)
     FcPatternElt    *elts = FcPatternElts(p);
 
     low = 0;
-    high = p->num - 1;
+    high = FcPatternObjectCount (p) - 1;
     c = 1;
     mid = 0;
     while (low <= high)
@@ -452,7 +462,7 @@ FcPatternObjectInsertElt (FcPattern *p, FcObject object)
 	i = -i - 1;
 
 	/* reallocate array */
-	if (p->num + 1 >= p->size)
+	if (FcPatternObjectCount (p) + 1 >= p->size)
 	{
 	    int s = p->size + 16;
 	    if (p->size)
@@ -463,7 +473,7 @@ FcPatternObjectInsertElt (FcPattern *p, FcObject object)
 		{
 		    e = malloc(s * sizeof (FcPatternElt));
 		    if (e)
-			memcpy(e, e0, p->num * sizeof (FcPatternElt));
+			memcpy(e, e0, FcPatternObjectCount (p) * sizeof (FcPatternElt));
 		}
 	    }
 	    else
@@ -484,7 +494,7 @@ FcPatternObjectInsertElt (FcPattern *p, FcObject object)
 	memmove (e + i + 1,
 		 e + i,
 		 sizeof (FcPatternElt) *
-		 (p->num - i));
+		 (FcPatternObjectCount (p) - i));
 		
 	/* bump count */
 	p->num++;
@@ -499,24 +509,26 @@ FcPatternObjectInsertElt (FcPattern *p, FcObject object)
 FcBool
 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
 {
-    int	i;
-    FcPatternElt   *pae, *pbe;
+    FcPatternIter ia, ib;
 
     if (pa == pb)
 	return FcTrue;
 
-    if (pa->num != pb->num)
+    if (FcPatternObjectCount (pa) != FcPatternObjectCount (pb))
 	return FcFalse;
-    pae = FcPatternElts(pa);
-    pbe = FcPatternElts(pb);
-    for (i = 0; i < pa->num; i++)
-    {
-	if (pae[i].object != pbe[i].object)
-	    return FcFalse;
-	if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
-			       FcPatternEltValues(&pbe[i])))
+    FcPatternIterStart (pa, &ia);
+    FcPatternIterStart (pb, &ib);
+    do {
+	FcBool ra, rb;
+
+	if (!FcPatternIterEqual (pa, &ia, pb, &ib))
 	    return FcFalse;
-    }
+	ra = FcPatternIterNext (pa, &ia);
+	rb = FcPatternIterNext (pb, &ib);
+	if (!ra && !rb)
+	    break;
+    } while (1);
+
     return FcTrue;
 }
 
@@ -527,7 +539,7 @@ FcPatternHash (const FcPattern *p)
     FcChar32	h = 0;
     FcPatternElt    *pe = FcPatternElts(p);
 
-    for (i = 0; i < p->num; i++)
+    for (i = 0; i < FcPatternObjectCount (p); i++)
     {
 	h = (((h << 1) | (h >> 31)) ^
 	     pe[i].object ^
@@ -713,10 +725,10 @@ FcPatternObjectDel (FcPattern *p, FcObject object)
 
     /* shuffle existing ones down */
     memmove (e, e+1,
-	     (FcPatternElts(p) + p->num - (e + 1)) *
+	     (FcPatternElts(p) + FcPatternObjectCount (p) - (e + 1)) *
 	     sizeof (FcPatternElt));
     p->num--;
-    e = FcPatternElts(p) + p->num;
+    e = FcPatternElts(p) + FcPatternObjectCount (p);
     e->object = 0;
     e->values = NULL;
     return FcTrue;
@@ -1115,8 +1127,7 @@ FcPattern *
 FcPatternDuplicate (const FcPattern *orig)
 {
     FcPattern	    *new;
-    FcPatternElt    *e;
-    int		    i;
+    FcPatternIter   iter;
     FcValueListPtr  l;
 
     if (!orig)
@@ -1126,20 +1137,18 @@ FcPatternDuplicate (const FcPattern *orig)
     if (!new)
 	goto bail0;
 
-    e = FcPatternElts(orig);
-
-    for (i = 0; i < orig->num; i++)
+    FcPatternIterStart (orig, &iter);
+    do
     {
-	for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
+	for (l = FcPatternIterGetValues (orig, &iter); l; l = FcValueListNext (l))
 	{
-	    if (!FcPatternObjectAddWithBinding (new, e[i].object,
+	    if (!FcPatternObjectAddWithBinding (new, FcPatternIterGetObjectId (orig, &iter),
 						FcValueCanonicalize(&l->value),
 						l->binding,
 						FcTrue))
 		goto bail1;
-	
 	}
-    }
+    } while (FcPatternIterNext (orig, &iter));
 
     return new;
 
@@ -1184,21 +1193,21 @@ FcPatternBuild (FcPattern *p, ...)
 FcBool
 FcPatternAppend (FcPattern *p, FcPattern *s)
 {
-    int		    i;
-    FcPatternElt    *e;
-    FcValueListPtr  v;
+    FcPatternIter  iter;
+    FcValueListPtr v;
 
-    for (i = 0; i < s->num; i++)
+    FcPatternIterStart (s, &iter);
+    do
     {
-	e = FcPatternElts(s)+i;
-	for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
+	for (v = FcPatternIterGetValues (s, &iter); v; v = FcValueListNext (v))
 	{
-	    if (!FcPatternObjectAddWithBinding (p, e->object,
+	    if (!FcPatternObjectAddWithBinding (p, FcPatternIterGetObjectId (s, &iter),
 						FcValueCanonicalize(&v->value),
 						v->binding, FcTrue))
 		return FcFalse;
 	}
-    }
+    } while (FcPatternIterNext (s, &iter));
+
     return FcTrue;
 }
 
@@ -1239,6 +1248,148 @@ bail0:
     return NULL;
 }
 
+typedef struct _FcPatternPrivateIter {
+    FcPatternElt *elt;
+    int           pos;
+} FcPatternPrivateIter;
+
+static void
+FcPatternIterSet (const FcPattern *pat, FcPatternPrivateIter *iter)
+{
+    iter->elt = FcPatternObjectCount (pat) > 0 && iter->pos < FcPatternObjectCount (pat) ? &FcPatternElts (pat)[iter->pos] : NULL;
+}
+
+void
+FcPatternIterStart (const FcPattern *pat, FcPatternIter *iter)
+{
+    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
+
+    priv->pos = 0;
+    FcPatternIterSet (pat, priv);
+}
+
+FcBool
+FcPatternIterNext (const FcPattern *pat, FcPatternIter *iter)
+{
+    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
+
+    priv->pos++;
+    if (priv->pos >= FcPatternObjectCount (pat))
+	return FcFalse;
+    FcPatternIterSet (pat, priv);
+
+    return FcTrue;
+}
+
+FcBool
+FcPatternIterEqual (const FcPattern *p1, FcPatternIter *i1,
+		    const FcPattern *p2, FcPatternIter *i2)
+{
+    FcBool b1 = FcPatternIterIsValid (p1, i1);
+    FcBool b2 = FcPatternIterIsValid (p2, i2);
+
+    if (!i1 && !i2)
+	return FcTrue;
+    if (!b1 || !b2)
+	return FcFalse;
+    if (FcPatternIterGetObjectId (p1, i1) != FcPatternIterGetObjectId (p2, i2))
+	return FcFalse;
+
+    return FcValueListEqual (FcPatternIterGetValues (p1, i1),
+			     FcPatternIterGetValues (p2, i2));
+}
+
+FcBool
+FcPatternFindObjectIter (const FcPattern *pat, FcPatternIter *iter, FcObject object)
+{
+    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
+    int i = FcPatternObjectPosition (pat, object);
+
+    priv->elt = NULL;
+    if (i < 0)
+	return FcFalse;
+
+    priv->pos = i;
+    FcPatternIterSet (pat, priv);
+
+    return FcTrue;
+}
+
+FcBool
+FcPatternFindIter (const FcPattern *pat, FcPatternIter *iter, const char *object)
+{
+    return FcPatternFindObjectIter (pat, iter, FcObjectFromName (object));
+}
+
+FcBool
+FcPatternIterIsValid (const FcPattern *pat, FcPatternIter *iter)
+{
+    FcPatternPrivateIter *priv = (FcPatternPrivateIter *)iter;
+
+    if (priv && priv->elt)
+	return FcTrue;
+
+    return FcFalse;
+}
+
+FcObject
+FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter)
+{
+    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
+
+    if (priv && priv->elt)
+	return priv->elt->object;
+
+    return 0;
+}
+
+const char *
+FcPatternIterGetObject (const FcPattern *pat, FcPatternIter *iter)
+{
+    return FcObjectName (FcPatternIterGetObjectId (pat, iter));
+}
+
+FcValueListPtr
+FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter)
+{
+    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
+
+    if (priv && priv->elt)
+	return FcPatternEltValues (priv->elt);
+
+    return NULL;
+}
+
+int
+FcPatternIterValueCount (const FcPattern *pat, FcPatternIter *iter)
+{
+    int count = 0;
+    FcValueListPtr l;
+
+    for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
+	count++;
+
+    return count;
+}
+
+FcResult
+FcPatternIterGetValue (const FcPattern *pat, FcPatternIter *iter, int id, FcValue *v, FcValueBinding *b)
+{
+    FcValueListPtr l;
+
+    for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
+    {
+	if (id == 0)
+	{
+	    *v = FcValueCanonicalize (&l->value);
+	    if (b)
+		*b = l->binding;
+	    return FcResultMatch;
+	}
+	id--;
+    }
+    return FcResultNoId;
+}
 
 FcBool
 FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
@@ -1248,9 +1399,9 @@ FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
 
     if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
 	return FcFalse;
-    if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
+    if (!FcSerializeAlloc (serialize, elts, FcPatternObjectCount (pat) * sizeof (FcPatternElt)))
 	return FcFalse;
-    for (i = 0; i < pat->num; i++)
+    for (i = 0; i < FcPatternObjectCount (pat); i++)
 	if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
 	    return FcFalse;
     return FcTrue;
@@ -1269,7 +1420,7 @@ FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
     if (!pat_serialized)
 	return NULL;
     *pat_serialized = *pat;
-    pat_serialized->size = pat->num;
+    pat_serialized->size = FcPatternObjectCount (pat);
     FcRefSetConst (&pat_serialized->ref);
 
     elts_serialized = FcSerializePtr (serialize, elts);
@@ -1279,7 +1430,7 @@ FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
     pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
 						 elts_serialized);
 
-    for (i = 0; i < pat->num; i++)
+    for (i = 0; i < FcPatternObjectCount (pat); i++)
     {
 	values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
 	if (!values_serialized)
commit 454923709a1a1e480554c400e053aea9a1ba951a
Author: Akira TAGOH <akira at tagoh.org>
Date:   Thu May 10 22:01:29 2018 +0900

    Change the emboldening logic again
    
    enable emboldening when request was >= bold and font was <= medium
    
    https://bugs.freedesktop.org/show_bug.cgi?id=106460

diff --git a/conf.d/90-synthetic.conf b/conf.d/90-synthetic.conf
index e344e4a..6b929dd 100644
--- a/conf.d/90-synthetic.conf
+++ b/conf.d/90-synthetic.conf
@@ -42,9 +42,9 @@
  -->
 
 	<match target="font">
-		<!-- check to see if the font is just regular -->
+		<!-- check to see if the weight in the font is less than medium which possibly need emboldening -->
 		<test name="weight" compare="less_eq">
-			<const>regular</const>
+			<const>medium</const>
 		</test>
 		<!-- check to see if the pattern requests bold -->
 		<test target="pattern" name="weight" compare="more_eq">


More information about the Fontconfig mailing list