fontconfig: Branch 'main' - 2 commits

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 doc/fcconfig.fncs       |   31 ++++++++++++++++-
 fontconfig/fontconfig.h |   13 +++++++
 src/fccfg.c             |   87 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/fcinit.c            |   27 ++++++++++++--
 src/fcint.h             |    6 ++-
 test/Makefile.am        |    4 ++
 test/run-test-conf.sh   |    1 
 test/test-conf.c        |   64 ++++++++++++++++++++++++++++++++---
 test/test-filter.c      |   59 ++++++++++++++++++++++++++++++++
 test/test-filter.json   |   65 +++++++++++++++++++++++++++++++++++
 10 files changed, 342 insertions(+), 15 deletions(-)

New commits:
commit bd83c04aa6f3cb864ba60dc5eaf2b41c4c269c63
Merge: be2a400 94614ac
Author: Akira TAGOH <akira@xxxxxxxxx>
Date:   Fri Aug 9 14:31:08 2024 +0000

    Merge branch 'filter-fs' into 'main'
    
    Add FcConfigSetFontSetFilter
    
    See merge request fontconfig/fontconfig!328

commit 94614ac73cf412e0d43ecc31dcce57071cfa6be4
Author: Akira TAGOH <akira@xxxxxxxxx>
Date:   Fri Aug 9 22:04:28 2024 +0900

    Add FcConfigSetFontSetFilter
    
    To pre-filtering when loading fonts from caches.
    FcFontSet in FcConfig will be rebuilt if FcConfig is
    already initialized.

diff --git a/doc/fcconfig.fncs b/doc/fcconfig.fncs
index 49e691e..0a072af 100644
--- a/doc/fcconfig.fncs
+++ b/doc/fcconfig.fncs
@@ -71,6 +71,36 @@ in <parameter>config</parameter> since 2.12.0, returning FcFalse if that call fa
 Returns the current default configuration.
 @@
 
+@RET@           FcConfig *
+@FUNC@          FcConfigSetFontSetFilter
+@TYPE1@         FcConfig *                      @ARG1@          config
+@TYPE2@         FcFilterFontSetFunc%            @ARG2@          filter_func
+@TYPE3@         FcDestroyFunc%                  @ARG3@          destroy_data_func
+@TYPE4@         void *                          @ARG4@          user_data
+@PURPOSE@       Set a predicate function to filter fontsets
+@DESC@
+Sets <parameter>filter_func</parameter> as a predicate function and filter out
+fontsets in <parameter>config</parameter> as desired.
+<parameter>filter_func</parameter> will be called with a font pattern and
+<parameter>user_data</parameter> only when loading caches.
+When <parameter>config</parameter> is going to be destroyed,
+<parameter>user_data</parameter> will be destroyed through
+<parameter>destroy_data_func</parameter> if it is set.
+@SINCE@         2.16.0
+@@
+
+@RET@           FcBool
+@FUNC@          FcConfigAcceptFilter
+@TYPE1@         FcConfig *                      @ARG1@          config
+@TYPE2@         const FcPattern *               @ARG2@          font
+@PURPOSE@       Test whether the given pattern matches filter
+@DESC@
+This triggers a predicate function set by <function>FcConfigSetFontSetFilter</function>
+and return FcTrue if <parameter>font</parameter> matches something they expect.
+otherwise FcFalse.
+@SINCE@         2.16.0
+@@
+
 @RET@           FcBool
 @FUNC@          FcConfigUptoDate
 @TYPE1@         FcConfig *                      @ARG1@          config
@@ -514,4 +544,3 @@ in configuration file. This function tries to match 'pat' with them and
 return FcFalse if 'pat' is rejected, otherwise FcTrue.
 @SINCE@		2.15.1
 @@
-
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
index 47d7b83..d7df876 100644
--- a/fontconfig/fontconfig.h
+++ b/fontconfig/fontconfig.h
@@ -337,6 +337,9 @@ typedef struct _FcStrSet    FcStrSet;
 
 typedef struct _FcCache	    FcCache;
 
+typedef void (* FcDestroyFunc) (void *data);
+typedef FcBool (* FcFilterFontSetFunc) (const FcPattern *font, void *user_data);
+
 _FCFUNCPROTOBEGIN
 
 /* fcblanks.c */
@@ -457,6 +460,10 @@ FcPublic FcBool
 FcConfigAcceptFont (FcConfig	    *config,
 		    const FcPattern *font);
 
+FcPublic FcBool
+FcConfigAcceptFilter (FcConfig        *config,
+		      const FcPattern *font);
+
 FcPublic FcBool
 FcConfigAppFontAddFile (FcConfig    *config,
 			const FcChar8  *file);
@@ -486,6 +493,12 @@ FcPublic void
 FcConfigSetSysRoot (FcConfig      *config,
 		    const FcChar8 *sysroot);
 
+FcPublic FcConfig *
+FcConfigSetFontSetFilter (FcConfig            *config,
+			  FcFilterFontSetFunc filter_func,
+			  FcDestroyFunc       destroy_data_func,
+			  void                *user_data);
+
 FcPublic void
 FcConfigFileInfoIterInit (FcConfig		*config,
 			  FcConfigFileInfoIter	*iter);
diff --git a/src/fccfg.c b/src/fccfg.c
index 41ee611..d1f5856 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -25,6 +25,7 @@
 /* Objects MT-safe for readonly access. */
 
 #include "fcint.h"
+#include "fontconfig/fontconfig.h"
 #ifdef HAVE_DIRENT_H
 #include <dirent.h>
 #endif
@@ -202,6 +203,10 @@ FcConfigCreate (void)
     if (!config->availConfigFiles)
 	goto bail10;
 
+    config->filter_func = NULL;
+    config->filter_data = NULL;
+    config->destroy_data_func = NULL;
+
     FcRefInit (&config->ref, 1);
 
     return config;
@@ -390,6 +395,9 @@ FcConfigDestroy (FcConfig *config)
 	if (config->sysRoot)
 	FcStrFree (config->sysRoot);
 
+	if (config->filter_data && config->destroy_data_func)
+	    config->destroy_data_func (config->filter_data);
+
 	free (config);
     }
 }
@@ -453,10 +461,18 @@ FcConfigAddCache (FcConfig *config, FcCache *cache,
 		continue;
 	    }
 
+	    /*
+	     * Check to see if font is banned by client
+	     */
+	    if (!FcConfigAcceptFilter (config, font))
+	    {
+		free (relocated_font_file);
+		continue;
+	    }
 	    if (relocated_font_file)
 	    {
-	      font = FcPatternCacheRewriteFile (font, cache, relocated_font_file);
-	      free (relocated_font_file);
+		font = FcPatternCacheRewriteFile (font, cache, relocated_font_file);
+		free (relocated_font_file);
 	    }
 
 	    if (FcFontSetAdd (config->fonts[set], font))
@@ -811,6 +827,63 @@ FcConfigSetFonts (FcConfig	*config,
     config->fonts[set] = fonts;
 }
 
+FcConfig *
+FcConfigSetFontSetFilter (FcConfig            *config,
+			  FcFilterFontSetFunc filter_func,
+			  FcDestroyFunc       destroy_data_func,
+			  void                *user_data)
+{
+    FcBool rebuild = FcFalse;
+
+    if (!config)
+    {
+	/* Do not use FcConfigEnsure() here for optimization */
+    retry:
+	config = fc_atomic_ptr_get (&_fcConfig);
+	if (!config)
+	    config = FcConfigCreate ();
+	else
+	    rebuild = FcTrue;
+    }
+    else
+	rebuild = FcTrue;
+    if (config->filter_data == user_data &&
+	config->filter_func == filter_func)
+    {
+	/* No need to update */
+	rebuild = FcFalse;
+    }
+    else
+    {
+	if (config->filter_data && config->destroy_data_func)
+	{
+	    config->destroy_data_func (config->filter_data);
+	}
+	config->filter_func = filter_func;
+	config->destroy_data_func = destroy_data_func;
+	config->filter_data = user_data;
+    }
+
+    if (rebuild)
+    {
+	/* Rebuild FontSet */
+	FcConfigBuildFonts (config);
+    }
+    else
+    {
+	/* Initialize FcConfig with regular procedure */
+	config = FcInitLoadOwnConfigAndFonts (config);
+
+	if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config))
+	{
+	    if (config)
+		FcConfigDestroy (config);
+	    goto retry;
+	}
+    }
+
+    return config;
+}
 
 FcBlanks *
 FcBlanksCreate (void)
@@ -2985,6 +3058,16 @@ FcConfigAcceptFont (FcConfig	    *config,
     return FcTrue;
 }
 
+FcBool
+FcConfigAcceptFilter (FcConfig        *config,
+		      const FcPattern *font)
+{
+    if (config && config->filter_func)
+    {
+	return config->filter_func (font, config->filter_data);
+    }
+    return FcTrue;
+}
 const FcChar8 *
 FcConfigGetSysRoot (const FcConfig *config)
 {
diff --git a/src/fcinit.c b/src/fcinit.c
index c05cdc5..e267821 100644
--- a/src/fcinit.c
+++ b/src/fcinit.c
@@ -65,6 +65,26 @@ bail0:
     return 0;
 }
 
+static FcConfig *
+FcInitFallbackConfigWithFilter (FcConfig *config, const FcChar8 *sysroot)
+{
+    FcConfig *fallback = FcInitFallbackConfig (sysroot);
+
+    /* Copy filter data */
+    fallback->filter_func = config->filter_func;
+    fallback->filter_data = config->filter_data;
+    fallback->destroy_data_func = config->destroy_data_func;
+    config->filter_func = NULL;
+    config->filter_data = NULL;
+    config->destroy_data_func = NULL;
+    /* Rebuild fontset */
+    FcConfigBuildFonts (fallback);
+
+    FcConfigDestroy (config);
+
+    return fallback;
+}
+
 int
 FcGetVersion (void)
 {
@@ -89,9 +109,7 @@ FcInitLoadOwnConfig (FcConfig *config)
     if (!FcConfigParseAndLoad (config, 0, FcTrue))
     {
 	const FcChar8 *sysroot = FcConfigGetSysRoot (config);
-	FcConfig *fallback = FcInitFallbackConfig (sysroot);
-
-	FcConfigDestroy (config);
+	FcConfig *fallback = FcInitFallbackConfigWithFilter (config, sysroot);
 
 	return fallback;
     }
@@ -144,8 +162,7 @@ FcInitLoadOwnConfig (FcConfig *config)
 		     "Fontconfig error: out of memory");
 	    if (prefix)
 		FcStrFree (prefix);
-	    fallback = FcInitFallbackConfig (sysroot);
-	    FcConfigDestroy (config);
+	    fallback = FcInitFallbackConfigWithFilter (config, sysroot);
 
 	    return fallback;
 	}
diff --git a/src/fcint.h b/src/fcint.h
index 86676b3..8a3c0ac 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -328,8 +328,6 @@ typedef struct _FcEdit {
     FcValueBinding  binding;
 } FcEdit;
 
-typedef void (* FcDestroyFunc) (void *data);
-
 typedef struct _FcPtrList	FcPtrList;
 /* need to sync with FcConfigFileInfoIter at fontconfig.h */
 typedef struct _FcPtrListIter {
@@ -580,6 +578,10 @@ struct _FcConfig {
     FcChar8     *sysRoot;	    /* override the system root directory */
     FcStrSet	*availConfigFiles;  /* config files available */
     FcPtrList	*rulesetList;	    /* List of rulesets being installed */
+
+    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 */
 };
 
 typedef struct _FcFileTime {
diff --git a/test/Makefile.am b/test/Makefile.am
index 3b79c78..3b4e3e8 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -49,6 +49,7 @@ TESTDATA =			\
 	test-70-no-bitmaps-and-emoji.json	\
 	test-70-no-bitmaps-except-emoji.json	\
 	test-90-synthetic.json	\
+	test-filter.json	\
 	test-issue-286.json	\
 	test-style-match.json	\
 	$(NULL)
@@ -176,6 +177,9 @@ check_PROGRAMS += test-family-matching
 test_family_matching_LDADD = $(top_builddir)/src/libfontconfig.la
 TESTS += test-family-matching
 
+check_PROGRAMS += test-filter
+test_filter_LDADD = $(top_builddir)/src/libfontconfig.la
+
 EXTRA_DIST=run-test.sh run-test-conf.sh wrapper-script.sh $(TESTDATA) out.expected-long-family-names out.expected-no-long-family-names
 
 CLEANFILES =		\
diff --git a/test/run-test-conf.sh b/test/run-test-conf.sh
index cc41185..88407cd 100644
--- a/test/run-test-conf.sh
+++ b/test/run-test-conf.sh
@@ -53,6 +53,7 @@ done
 for i in \
 	test-issue-286.json \
 	test-style-match.json \
+	test-filter.json \
     ; do
     echo $RUNNER $TESTDIR/$i ...
     $RUNNER $TESTDIR/../conf.d/10-autohint.conf $TESTDIR/$i
diff --git a/test/test-conf.c b/test/test-conf.c
index 8b298ef..b5f702b 100644
--- a/test/test-conf.c
+++ b/test/test-conf.c
@@ -278,7 +278,7 @@ build_pattern (json_object *obj)
 }
 
 static FcFontSet *
-build_fs (FcConfig *config, json_object *obj)
+build_fs (FcConfig *config, json_object *obj, FcBool filter)
 {
     FcFontSet *fs = FcFontSetCreate ();
     int i, n;
@@ -292,7 +292,8 @@ build_fs (FcConfig *config, json_object *obj)
 	if (json_object_get_type (o) != json_type_object)
 	    continue;
 	pat = build_pattern (o);
-	if (FcConfigAcceptFont (config, pat))
+	if (FcConfigAcceptFont (config, pat) &&
+	    (!filter || FcConfigAcceptFilter (config, pat)))
 	    FcFontSetAdd (fs, pat);
 	else
 	    FcPatternDestroy(pat);
@@ -301,19 +302,71 @@ build_fs (FcConfig *config, json_object *obj)
     return fs;
 }
 
+static FcBool
+filter_func (const FcPattern *f, void *user_data)
+{
+    FcPattern *filter = (FcPattern *)user_data;
+    FcPatternIter iter;
+    FcBool ret = FcTrue;
+
+    FcPatternIterStart (filter, &iter);
+    if (!(ret = FcPatternIterIsValid (filter, &iter)))
+	goto bail;
+    do
+    {
+	const char *obj = FcPatternIterGetObject (filter, &iter);
+	int i, n = FcPatternIterValueCount(filter, &iter);
+
+	for (i = 0; i < n; i++)
+	{
+	    FcValue v, v2;
+	    FcValueBinding b;
+
+	    if (FcPatternIterGetValue (filter, &iter, i, &v, &b) != FcResultMatch)
+	    {
+		ret = FcFalse;
+		goto bail;
+	    }
+	    if (FcPatternGet (f, obj, 0, &v2) != FcResultMatch)
+	    {
+		ret = FcFalse;
+		goto bail;
+	    }
+	    if (!FcValueEqual (v, v2))
+	    {
+		ret = FcFalse;
+		goto bail;
+	    }
+	}
+    } while (FcPatternIterNext (filter, &iter));
+bail:
+    return ret;
+}
+
 static FcBool
 build_fonts (FcConfig *config, json_object *root)
 {
-    json_object *fonts;
+    json_object *fonts, *filter;
     FcFontSet *fs;
+    FcPattern *filterpat;
 
+    if (json_object_object_get_ex (root, "filter", &filter))
+    {
+	if (json_object_get_type (filter) != json_type_object)
+	{
+	    fprintf (stderr, "W: Invalid filter defined\n");
+	    return FcFalse;
+	}
+	filterpat = build_pattern (filter);
+	FcConfigSetFontSetFilter(config, filter_func, (FcDestroyFunc)FcPatternDestroy, filterpat);
+    }
     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 = build_fs (config, fonts);
+    fs = build_fs (config, fonts, FcTrue);
     /* FcConfigSetFonts (config, fs, FcSetSystem); */
     if (config->fonts[FcSetSystem])
 	FcFontSetDestroy (config->fonts[FcSetSystem]);
@@ -341,6 +394,7 @@ 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;
 
@@ -388,7 +442,7 @@ run_test (FcConfig *config, json_object *root)
 		}
 		if (result_fs)
 		    FcFontSetDestroy (result_fs);
-		result_fs = build_fs (config, iter.val);
+		result_fs = build_fs (config, iter.val, FcFalse);
 	    }
 	    else if (strcmp (iter.key, "$comment") == 0)
 	    {
diff --git a/test/test-filter.c b/test/test-filter.c
new file mode 100644
index 0000000..9eebdf0
--- /dev/null
+++ b/test/test-filter.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <fontconfig/fontconfig.h>
+#include <time.h>
+
+static FcBool
+filter (const FcPattern *f, void *user_data)
+{
+    FcChar8 *s = NULL;
+
+    if (FcPatternGetString (f, FC_FONT_WRAPPER, 0, &s) == FcResultMatch)
+    {
+	/* accept "SFNT" only */
+	if (FcStrCmp (s, (FcChar8 *)"SFNT") == 0)
+	    return FcTrue;
+    }
+    return FcFalse;
+}
+
+int
+main (void)
+{
+    FcPattern *p;
+    FcObjectSet *os;
+    FcFontSet *fs;
+    int i, ret = 0;
+    FcChar8 *s = NULL, *f;
+
+    FcConfigSetFontSetFilter(NULL, filter, NULL, NULL);
+    p = FcPatternCreate ();
+    os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_FILE, FC_FONT_WRAPPER, NULL);
+    fs = FcFontList (NULL, p, os);
+    FcObjectSetDestroy (os);
+    FcPatternDestroy (p);
+
+    printf ("%d matched\n", fs->nfont);
+    for (i = 0; i < fs->nfont; i++)
+    {
+	if (FcPatternGetString (fs->fonts[i], FC_FONT_WRAPPER, 0, &s) == FcResultMatch)
+	{
+	    f = FcPatternFormat (fs->fonts[i], (FcChar8 *)"%{=fclist}\n");
+	    printf ("%s", f);
+	    FcStrFree (f);
+	    if (FcStrCmp (s, (FcChar8 *)"SFNT") != 0)
+	    {
+		printf ("failed:\n");
+	    fail:
+		ret = 1;
+	    }
+	}
+	else
+	{
+	    printf ("no font wrapper\n");
+	    goto fail;
+	}
+    }
+    FcFontSetDestroy (fs);
+
+    return ret;
+}
diff --git a/test/test-filter.json b/test/test-filter.json
new file mode 100644
index 0000000..25bce57
--- /dev/null
+++ b/test/test-filter.json
@@ -0,0 +1,65 @@
+{
+  "fonts": [
+    {
+      "family": [
+        "Foo"
+      ],
+      "style": [
+        "Regular"
+      ],
+      "file": "/path/to/Foo.ttf",
+      "fontwrapper": "SFNT"
+    },
+    {
+      "family": [
+        "Bar"
+      ],
+      "style": [
+        "Regular"
+      ],
+      "file": "/path/to/Bar.otf",
+      "fontwrapper": "CFF"
+    },
+    {
+      "family": [
+        "Baz"
+      ],
+      "style": [
+        "Regular"
+      ],
+      "file": "/path/to/Baz.woff",
+      "fontwrapper": "WOFF"
+    },
+    {
+      "family": [
+        "Blah"
+      ],
+      "style": [
+        "Regular"
+      ],
+      "file": "/path/to/Baz.bdf"
+    }
+  ],
+  "filter": {
+    "fontwrapper": "SFNT"
+  },
+  "tests": [
+    {
+      "method": "list",
+      "query": {
+      },
+      "result_fs": [
+        {
+          "family": [
+            "Foo"
+          ],
+          "style": [
+            "Regular"
+          ],
+          "file": "/path/to/Foo.ttf",
+          "fontwrapper": "SFNT"
+        }
+      ]
+    }
+  ]
+}



[Index of Archives]     [Fedora Fonts]     [Fedora Users]     [Fedora Cloud]     [Kernel]     [Fedora Packaging]     [Fedora Desktop]     [PAM]     [Gimp Graphics Editor]     [Yosemite News]

  Powered by Linux