Module Name: xsrc Committed By: mrg Date: Fri Mar 8 09:49:08 UTC 2019
Modified Files: xsrc/external/mit/fontconfig/dist/doc: FcLangSetGetLangs.3 xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel: fclangsetgetlangs.html xsrc/external/mit/fontconfig/dist/fc-cache: fc-cache.c xsrc/external/mit/fontconfig/dist/src: fccache.c fccfg.c fcformat.c fcfreetype.c fcinit.c fcint.h fcmatch.c fcname.c fcstat.c Added Files: xsrc/external/mit/fontconfig/dist/src: fchash.c Removed Files: xsrc/external/mit/fontconfig/dist/conf.d: 30-urw-aliases.conf xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel: x102.html xsrc/external/mit/fontconfig/dist/fc-blanks: Makefile.am Makefile.in fc-blanks.py fcblanks.h fcblanks.tmpl.h xsrc/external/mit/fontconfig/dist/fc-glyphname: Makefile.am Makefile.in fc-glyphname.c fcglyphname.h fcglyphname.tmpl.h zapfdingbats.txt xsrc/external/mit/fontconfig/dist/src: fcblanks.c fcobjshash.gperf fcobjshash.h xsrc/external/mit/fontconfig/dist/test: out.expected out271.expected run-test271.sh Log Message: merge fontconfig 2.13.1. To generate a diff of this commit: cvs rdiff -u -r1.1.1.5 -r0 \ xsrc/external/mit/fontconfig/dist/conf.d/30-urw-aliases.conf cvs rdiff -u -r1.4 -r1.5 \ xsrc/external/mit/fontconfig/dist/doc/FcLangSetGetLangs.3 cvs rdiff -u -r1.4 -r1.5 \ xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel/fclangsetgetlangs.html cvs rdiff -u -r1.1.1.7 -r0 \ xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel/x102.html cvs rdiff -u -r1.1.1.1 -r0 \ xsrc/external/mit/fontconfig/dist/fc-blanks/Makefile.am \ xsrc/external/mit/fontconfig/dist/fc-blanks/Makefile.in \ xsrc/external/mit/fontconfig/dist/fc-blanks/fc-blanks.py \ xsrc/external/mit/fontconfig/dist/fc-blanks/fcblanks.h \ xsrc/external/mit/fontconfig/dist/fc-blanks/fcblanks.tmpl.h cvs rdiff -u -r1.7 -r1.8 \ xsrc/external/mit/fontconfig/dist/fc-cache/fc-cache.c cvs rdiff -u -r1.1.1.4 -r0 \ xsrc/external/mit/fontconfig/dist/fc-glyphname/Makefile.am cvs rdiff -u -r1.1.1.7 -r0 \ xsrc/external/mit/fontconfig/dist/fc-glyphname/Makefile.in cvs rdiff -u -r1.1.1.5 -r0 \ xsrc/external/mit/fontconfig/dist/fc-glyphname/fc-glyphname.c cvs rdiff -u -r1.1.1.1 -r0 \ xsrc/external/mit/fontconfig/dist/fc-glyphname/fcglyphname.h \ xsrc/external/mit/fontconfig/dist/fc-glyphname/zapfdingbats.txt cvs rdiff -u -r1.1.1.3 -r0 \ xsrc/external/mit/fontconfig/dist/fc-glyphname/fcglyphname.tmpl.h cvs rdiff -u -r1.1.1.5 -r0 xsrc/external/mit/fontconfig/dist/src/fcblanks.c cvs rdiff -u -r1.9 -r1.10 xsrc/external/mit/fontconfig/dist/src/fccache.c cvs rdiff -u -r1.3 -r1.4 xsrc/external/mit/fontconfig/dist/src/fccfg.c \ xsrc/external/mit/fontconfig/dist/src/fcinit.c cvs rdiff -u -r1.2 -r1.3 xsrc/external/mit/fontconfig/dist/src/fcformat.c \ xsrc/external/mit/fontconfig/dist/src/fcfreetype.c cvs rdiff -u -r0 -r1.5 xsrc/external/mit/fontconfig/dist/src/fchash.c cvs rdiff -u -r1.8 -r1.9 xsrc/external/mit/fontconfig/dist/src/fcint.h \ xsrc/external/mit/fontconfig/dist/src/fcname.c \ xsrc/external/mit/fontconfig/dist/src/fcstat.c cvs rdiff -u -r1.10 -r1.11 xsrc/external/mit/fontconfig/dist/src/fcmatch.c cvs rdiff -u -r1.1.1.2 -r0 \ xsrc/external/mit/fontconfig/dist/src/fcobjshash.gperf cvs rdiff -u -r1.2 -r0 xsrc/external/mit/fontconfig/dist/src/fcobjshash.h cvs rdiff -u -r1.1.1.1 -r0 \ xsrc/external/mit/fontconfig/dist/test/out.expected \ xsrc/external/mit/fontconfig/dist/test/out271.expected \ xsrc/external/mit/fontconfig/dist/test/run-test271.sh Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: xsrc/external/mit/fontconfig/dist/doc/FcLangSetGetLangs.3 diff -u xsrc/external/mit/fontconfig/dist/doc/FcLangSetGetLangs.3:1.4 xsrc/external/mit/fontconfig/dist/doc/FcLangSetGetLangs.3:1.5 --- xsrc/external/mit/fontconfig/dist/doc/FcLangSetGetLangs.3:1.4 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/doc/FcLangSetGetLangs.3 Fri Mar 8 09:49:07 2019 @@ -1,5 +1,5 @@ .\" auto-generated by docbook2man-spec from docbook-utils package -.TH "FcLangSetGetLangs" "3" "05 7月 2017" "Fontconfig 2.12.4" "" +.TH "FcLangSetGetLangs" "3" "30 8月 2018" "Fontconfig 2.13.1" "" .SH NAME FcLangSetGetLangs \- get the list of languages in the langset .SH SYNOPSIS Index: xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel/fclangsetgetlangs.html diff -u xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel/fclangsetgetlangs.html:1.4 xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel/fclangsetgetlangs.html:1.5 --- xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel/fclangsetgetlangs.html:1.4 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/doc/fontconfig-devel/fclangsetgetlangs.html Fri Mar 8 09:49:07 2019 @@ -10,7 +10,7 @@ REL="HOME" HREF="t1.html"><LINK REL="UP" TITLE="FcLangSet" -HREF="x102.html#AEN2016"><LINK +HREF="x103.html#AEN2336"><LINK REL="PREVIOUS" TITLE="FcGetDefaultLangs" HREF="fcgetdefaultlangs.html"><LINK @@ -75,7 +75,7 @@ NAME="FCLANGSETGETLANGS" ><DIV CLASS="REFNAMEDIV" ><A -NAME="AEN2334" +NAME="AEN2654" ></A ><H2 >Name</H2 @@ -83,7 +83,7 @@ NAME="AEN2334" ><DIV CLASS="REFSYNOPSISDIV" ><A -NAME="AEN2337" +NAME="AEN2657" ></A ><H2 >Synopsis</H2 @@ -92,7 +92,7 @@ CLASS="FUNCSYNOPSIS" ><P ></P ><A -NAME="AEN2338" +NAME="AEN2658" ></A ><TABLE BORDER="0" @@ -129,7 +129,7 @@ CLASS="PARAMETER" ><DIV CLASS="REFSECT1" ><A -NAME="AEN2345" +NAME="AEN2665" ></A ><H2 >Description</H2 @@ -192,7 +192,7 @@ WIDTH="34%" ALIGN="center" VALIGN="top" ><A -HREF="x102.html#AEN2016" +HREF="x103.html#AEN2336" ACCESSKEY="U" >Up</A ></TD Index: xsrc/external/mit/fontconfig/dist/fc-cache/fc-cache.c diff -u xsrc/external/mit/fontconfig/dist/fc-cache/fc-cache.c:1.7 xsrc/external/mit/fontconfig/dist/fc-cache/fc-cache.c:1.8 --- xsrc/external/mit/fontconfig/dist/fc-cache/fc-cache.c:1.7 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/fc-cache/fc-cache.c Fri Mar 8 09:49:07 2019 @@ -41,6 +41,7 @@ #include <fcntl.h> #include <dirent.h> #include <string.h> +#include <locale.h> #if defined (_WIN32) #define STRICT @@ -49,6 +50,14 @@ #undef STRICT #endif +#ifdef ENABLE_NLS +#include <libintl.h> +#define _(x) (dgettext(GETTEXT_PACKAGE, x)) +#else +#define dgettext(d, s) (s) +#define _(x) (x) +#endif + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -87,37 +96,36 @@ static void usage (char *program, int error) { FILE *file = error ? stderr : stdout; -#if HAVE_GETOPT_LONG - fprintf (file, "usage: %s [-EfqrsvVh] [--quick] [-y SYSROOT] [--error-on-no-fonts] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--verbose] [--version] [--help] [dirs]\n", + fprintf (file, _("usage: %s [-EfqrsvVh] [--quick] [-y SYSROOT] [--error-on-no-fonts] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--verbose] [--version] [--help] [dirs]\n"), program); #else - fprintf (file, "usage: %s [-EfqrsvVh] [-y SYSROOT] [dirs]\n", + fprintf (file, _("usage: %s [-EfqrsvVh] [-y SYSROOT] [dirs]\n"), program); #endif - fprintf (file, "Build font information caches in [dirs]\n" - "(all directories in font configuration by default).\n"); + fprintf (file, _("Build font information caches in [dirs]\n" + "(all directories in font configuration by default).\n")); fprintf (file, "\n"); #if HAVE_GETOPT_LONG - fprintf (file, " -E, --error-on-no-fonts raise an error if no fonts in a directory\n"); - fprintf (file, " -f, --force scan directories with apparently valid caches\n"); - fprintf (file, " -q, --quick don't sleep before exiting\n"); - fprintf (file, " -r, --really-force erase all existing caches, then rescan\n"); - fprintf (file, " -s, --system-only scan system-wide directories only\n"); - fprintf (file, " -y, --sysroot=SYSROOT prepend SYSROOT to all paths for scanning\n"); - fprintf (file, " -v, --verbose display status information while busy\n"); - fprintf (file, " -V, --version display font config version and exit\n"); - fprintf (file, " -h, --help display this help and exit\n"); + fprintf (file, _(" -E, --error-on-no-fonts raise an error if no fonts in a directory\n")); + fprintf (file, _(" -f, --force scan directories with apparently valid caches\n")); + fprintf (file, _(" -q, --quick don't sleep before exiting\n")); + fprintf (file, _(" -r, --really-force erase all existing caches, then rescan\n")); + fprintf (file, _(" -s, --system-only scan system-wide directories only\n")); + fprintf (file, _(" -y, --sysroot=SYSROOT prepend SYSROOT to all paths for scanning\n")); + fprintf (file, _(" -v, --verbose display status information while busy\n")); + fprintf (file, _(" -V, --version display font config version and exit\n")); + fprintf (file, _(" -h, --help display this help and exit\n")); #else - fprintf (file, " -E (error-on-no-fonts)\n"); - fprintf (file, " raise an error if no fonts in a directory\n"); - fprintf (file, " -f (force) scan directories with apparently valid caches\n"); - fprintf (file, " -q (quick) don't sleep before exiting\n"); - fprintf (file, " -r, (really force) erase all existing caches, then rescan\n"); - fprintf (file, " -s (system) scan system-wide directories only\n"); - fprintf (file, " -y SYSROOT (sysroot) prepend SYSROOT to all paths for scanning\n"); - fprintf (file, " -v (verbose) display status information while busy\n"); - fprintf (file, " -V (version) display font config version and exit\n"); - fprintf (file, " -h (help) display this help and exit\n"); + fprintf (file, _(" -E (error-on-no-fonts)\n")); + fprintf (file, _(" raise an error if no fonts in a directory\n")); + fprintf (file, _(" -f (force) scan directories with apparently valid caches\n")); + fprintf (file, _(" -q (quick) don't sleep before exiting\n")); + fprintf (file, _(" -r, (really force) erase all existing caches, then rescan\n")); + fprintf (file, _(" -s (system) scan system-wide directories only\n")); + fprintf (file, _(" -y SYSROOT (sysroot) prepend SYSROOT to all paths for scanning\n")); + fprintf (file, _(" -v (verbose) display status information while busy\n")); + fprintf (file, _(" -V (version) display font config version and exit\n")); + fprintf (file, _(" -h (help) display this help and exit\n")); #endif exit (error); } @@ -154,7 +162,7 @@ scanDirs (FcStrList *list, FcConfig *con if (FcStrSetMember (processed_dirs, dir)) { if (verbose) - printf ("skipping, looped directory detected\n"); + printf (_("skipping, looped directory detected\n")); continue; } @@ -164,7 +172,7 @@ scanDirs (FcStrList *list, FcConfig *con case ENOENT: case ENOTDIR: if (verbose) - printf ("skipping, no such directory\n"); + printf (_("skipping, no such directory\n")); break; default: fprintf (stderr, "\"%s\": ", dir); @@ -177,13 +185,16 @@ scanDirs (FcStrList *list, FcConfig *con if (!S_ISDIR (statb.st_mode)) { - fprintf (stderr, "\"%s\": not a directory, skipping\n", dir); + fprintf (stderr, _("\"%s\": not a directory, skipping\n"), dir); continue; } was_processed = FcTrue; if (really_force) + { FcDirCacheUnlink (dir, config); + FcDirCacheCreateUUID ((FcChar8 *) dir, FcTrue, config); + } cache = NULL; was_valid = FcFalse; @@ -199,7 +210,7 @@ scanDirs (FcStrList *list, FcConfig *con cache = FcDirCacheRead (dir, FcTrue, config); if (!cache) { - fprintf (stderr, "%s: error scanning\n", dir); + fprintf (stderr, _("\"%s\": scanning error\n"), dir); ret++; continue; } @@ -208,18 +219,18 @@ scanDirs (FcStrList *list, FcConfig *con if (was_valid) { if (verbose) - printf ("skipping, existing cache is valid: %d fonts, %d dirs\n", + printf (_("skipping, existing cache is valid: %d fonts, %d dirs\n"), FcCacheNumFont (cache), FcCacheNumSubdir (cache)); } else { if (verbose) - printf ("caching, new cache contents: %d fonts, %d dirs\n", + printf (_("caching, new cache contents: %d fonts, %d dirs\n"), FcCacheNumFont (cache), FcCacheNumSubdir (cache)); if (!FcDirCacheValid (dir)) { - fprintf (stderr, "%s: failed to write cache\n", dir); + fprintf (stderr, _("%s: failed to write cache\n"), dir); (void) FcDirCacheUnlink (dir, config); ret++; } @@ -228,7 +239,7 @@ scanDirs (FcStrList *list, FcConfig *con subdirs = FcStrSetCreate (); if (!subdirs) { - fprintf (stderr, "%s: Can't create subdir set\n", dir); + fprintf (stderr, _("%s: Can't create subdir set\n"), dir); ret++; FcDirCacheUnload (cache); continue; @@ -242,7 +253,7 @@ scanDirs (FcStrList *list, FcConfig *con FcStrSetDestroy (subdirs); if (!sublist) { - fprintf (stderr, "%s: Can't create subdir list\n", dir); + fprintf (stderr, _("%s: Can't create subdir list\n"), dir); ret++; continue; } @@ -295,6 +306,7 @@ main (int argc, char **argv) #if HAVE_GETOPT_LONG || HAVE_GETOPT int c; + setlocale (LC_ALL, ""); #if HAVE_GETOPT_LONG while ((c = getopt_long (argc, argv, "Efqrsy:Vvh", longopts, NULL)) != -1) #else @@ -321,7 +333,7 @@ main (int argc, char **argv) sysroot = FcStrCopy ((const FcChar8 *)optarg); break; case 'V': - fprintf (stderr, "fontconfig version %d.%d.%d\n", + fprintf (stderr, "fontconfig version %d.%d.%d\n", FC_MAJOR, FC_MINOR, FC_REVISION); exit (0); case 'v': @@ -352,7 +364,7 @@ main (int argc, char **argv) } if (!config) { - fprintf (stderr, "%s: Can't init font config library\n", argv[0]); + fprintf (stderr, _("%s: Can't initialize font config library\n"), argv[0]); return 1; } FcConfigSetCurrent (config); @@ -362,7 +374,7 @@ main (int argc, char **argv) dirs = FcStrSetCreate (); if (!dirs) { - fprintf (stderr, "%s: Can't create list of directories\n", + fprintf (stderr, _("%s: Can't create list of directories\n"), argv[0]); return 1; } @@ -370,7 +382,7 @@ main (int argc, char **argv) { if (!FcStrSetAddFilename (dirs, (FcChar8 *) argv[i])) { - fprintf (stderr, "%s: Can't add directory\n", argv[0]); + fprintf (stderr, _("%s: Can't add directory\n"), argv[0]); return 1; } i++; @@ -379,10 +391,10 @@ main (int argc, char **argv) FcStrSetDestroy (dirs); } else - list = FcConfigGetConfigDirs (config); + list = FcConfigGetFontDirs (config); if ((processed_dirs = FcStrSetCreate()) == NULL) { - fprintf(stderr, "Cannot malloc\n"); + fprintf(stderr, _("Out of Memory\n")); return 1; } @@ -414,6 +426,6 @@ main (int argc, char **argv) if (!quick && changed) sleep (2); if (verbose) - printf ("%s: %s\n", argv[0], ret ? "failed" : "succeeded"); + printf ("%s: %s\n", argv[0], ret ? _("failed") : _("succeeded")); return ret; } Index: xsrc/external/mit/fontconfig/dist/src/fccache.c diff -u xsrc/external/mit/fontconfig/dist/src/fccache.c:1.9 xsrc/external/mit/fontconfig/dist/src/fccache.c:1.10 --- xsrc/external/mit/fontconfig/dist/src/fccache.c:1.9 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/src/fccache.c Fri Mar 8 09:49:07 2019 @@ -30,6 +30,7 @@ #include <limits.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/time.h> #include <assert.h> #if defined(HAVE_MMAP) || defined(__CYGWIN__) # include <unistd.h> @@ -37,12 +38,196 @@ #endif #if defined(_WIN32) #include <sys/locking.h> +#else +#if !defined TOOL_FCCACHE +#include <uuid/uuid.h> +#endif #endif #ifndef O_BINARY #define O_BINARY 0 #endif +FcBool +FcDirCacheCreateUUID (FcChar8 *dir, + FcBool force, + FcConfig *config) +{ + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *target; + FcBool ret = FcTrue; +#if !defined TOOL_FCCACHE +#ifndef _WIN32 + FcChar8 *uuidname; + + if (sysroot) + target = FcStrBuildFilename (sysroot, dir, NULL); + else + target = FcStrdup (dir); + uuidname = FcStrBuildFilename (target, ".uuid", NULL); + + if (!uuidname) + { + FcStrFree (target); + return FcFalse; + } + + if (force || access ((const char *) uuidname, F_OK) < 0) + { + FcAtomic *atomic; + int fd; + uuid_t uuid; + char out[37]; + FcBool (* hash_add) (FcHashTable *, void*, void*); + struct stat statb; + struct timeval times[2]; + + if (FcStat (target, &statb) != 0) + { + ret = FcFalse; + goto bail1; + } + atomic = FcAtomicCreate (uuidname); + if (!atomic) + { + ret = FcFalse; + goto bail1; + } + if (!FcAtomicLock (atomic)) + { + ret = FcFalse; + goto bail2; + } + fd = FcOpen ((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT, 0644); + if (fd == -1) + { + ret = FcFalse; + goto bail3; + } + uuid_generate_random (uuid); + if (force) + hash_add = FcHashTableReplace; + else + hash_add = FcHashTableAdd; + if (!hash_add (config->uuid_table, target, uuid)) + { + ret = FcFalse; + FcAtomicDeleteNew (atomic); + close (fd); + goto bail3; + } + uuid_unparse (uuid, out); + if (FcDebug () & FC_DBG_CACHE) + printf ("FcDirCacheCreateUUID %s: %s\n", uuidname, out); + write (fd, out, strlen (out)); + close (fd); + FcAtomicReplaceOrig (atomic); + bail3: + FcAtomicUnlock (atomic); + bail2: + FcAtomicDestroy (atomic); + + if (ret) + { + /* revert mtime of the directory */ + times[0].tv_sec = statb.st_atime; + times[1].tv_sec = statb.st_mtime; +#ifdef HAVE_STRUCT_STAT_ST_MTIM + times[0].tv_usec = statb.st_atim.tv_nsec / 1000; + times[1].tv_usec = statb.st_mtim.tv_nsec / 1000; +#else + times[0].tv_usec = 0; + times[1].tv_usec = 0; +#endif + if (utimes ((const char *) target, times) != 0) + { + fprintf (stderr, "Unable to revert mtime: %s\n", target); + } + } + } +bail1: + FcStrFree (uuidname); + FcStrFree (target); +#endif +#endif + + return ret; +} + +FcBool +FcDirCacheDeleteUUID (const FcChar8 *dir, + FcConfig *config) +{ + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *target; + FcBool ret = FcTrue; + + if (sysroot) + target = FcStrBuildFilename (sysroot, dir, ".uuid", NULL); + else + target = FcStrBuildFilename (dir, ".uuid", NULL); + + ret = unlink ((char *) target) == 0; + FcHashTableRemove (config->uuid_table, target); + FcStrFree(target); + + return ret; +} + +#if !defined TOOL_FCCACHE +#ifndef _WIN32 +static void +FcDirCacheReadUUID (FcChar8 *dir, + FcConfig *config) +{ + void *u; + uuid_t uuid; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *target; + + if (sysroot) + target = FcStrBuildFilename (sysroot, dir, NULL); + else + target = FcStrdup (dir); + + if (!FcHashTableFind (config->uuid_table, target, &u)) + { + FcChar8 *uuidname = FcStrBuildFilename (target, ".uuid", NULL); + int fd; + + if ((fd = FcOpen ((char *) uuidname, O_RDONLY)) >= 0) + { + char suuid[37]; + ssize_t len; + + memset (suuid, 0, sizeof (suuid)); + len = read (fd, suuid, 36); + if (len != -1) + { + suuid[len] = 0; + memset (uuid, 0, sizeof (uuid)); + if (uuid_parse (suuid, uuid) == 0) + { + if (FcDebug () & FC_DBG_CACHE) + printf ("FcDirCacheReadUUID %s -> %s\n", uuidname, suuid); + FcHashTableAdd (config->uuid_table, target, uuid); + } + } + close (fd); + } + else + { + if (FcDebug () & FC_DBG_CACHE) + printf ("FcDirCacheReadUUID Unable to read %s\n", uuidname); + } + FcStrFree (uuidname); + } + else + FcHashUuidFree (u); + FcStrFree (target); +} +#endif +#endif struct MD5Context { FcChar32 buf[4]; @@ -55,7 +240,7 @@ static void MD5Update(struct MD5Context static void MD5Final(unsigned char digest[16], struct MD5Context *ctx); static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]); -#define CACHEBASE_LEN (1 + 32 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX)) +#define CACHEBASE_LEN (1 + 36 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX)) static FcBool FcCacheIsMmapSafe (int fd) @@ -94,7 +279,7 @@ static const char bin2hex[] = { '0', '1' 'c', 'd', 'e', 'f' }; static FcChar8 * -FcDirCacheBasename (const FcChar8 * dir, FcChar8 cache_base[CACHEBASE_LEN]) +FcDirCacheBasenameMD5 (const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN]) { unsigned char hash[16]; FcChar8 *hex_hash; @@ -119,6 +304,33 @@ FcDirCacheBasename (const FcChar8 * dir, return cache_base; } +#if !defined TOOL_FCCACHE +#ifndef _WIN32 +static FcChar8 * +FcDirCacheBasenameUUID (const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN], FcConfig *config) +{ + void *u; + FcChar8 *target; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + + if (sysroot) + target = FcStrBuildFilename (sysroot, dir, NULL); + else + target = FcStrdup (dir); + if (FcHashTableFind (config->uuid_table, target, &u)) + { + uuid_unparse (u, (char *) cache_base); + strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX); + FcHashUuidFree (u); + FcStrFree (target); + return cache_base; + } + FcStrFree (target); + return NULL; +} +#endif +#endif + FcBool FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config) { @@ -128,7 +340,12 @@ FcDirCacheUnlink (const FcChar8 *dir, Fc FcChar8 *cache_dir; const FcChar8 *sysroot = FcConfigGetSysRoot (config); - FcDirCacheBasename (dir, cache_base); +#if !defined TOOL_FCCACHE +#ifndef _WIN32 + if (!FcDirCacheBasenameUUID (dir, cache_base, config)) +#endif +#endif + FcDirCacheBasenameMD5 (dir, cache_base); list = FcStrListCreate (config->cacheDirs); if (!list) @@ -143,6 +360,7 @@ FcDirCacheUnlink (const FcChar8 *dir, Fc if (!cache_hashed) break; (void) unlink ((char *) cache_hashed); + FcDirCacheDeleteUUID (dir, config); FcStrFree (cache_hashed); } FcStrListDone (list); @@ -204,7 +422,12 @@ FcDirCacheProcess (FcConfig *config, con } FcStrFree (d); - FcDirCacheBasename (dir, cache_base); +#if !defined TOOL_FCCACHE +#ifndef _WIN32 + if (!FcDirCacheBasenameUUID (dir, cache_base, config)) +#endif +#endif + FcDirCacheBasenameMD5 (dir, cache_base); list = FcStrListCreate (config->cacheDirs); if (!list) @@ -254,6 +477,7 @@ struct _FcCacheSkip { FcCache *cache; FcRef ref; intptr_t size; + void *allocated; dev_t cache_dev; ino_t cache_ino; time_t cache_mtime; @@ -379,6 +603,7 @@ FcCacheInsert (FcCache *cache, struct st s->cache = cache; s->size = cache->size; + s->allocated = NULL; FcRefInit (&s->ref, 1); if (cache_stat) { @@ -453,6 +678,7 @@ FcCacheRemoveUnlocked (FcCache *cache) FcCacheSkip **update[FC_CACHE_MAX_LEVEL]; FcCacheSkip *s, **next; int i; + void *allocated; /* * Find links along each chain @@ -470,6 +696,15 @@ FcCacheRemoveUnlocked (FcCache *cache) *update[i] = s->next[i]; while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL) fcCacheMaxLevel--; + + allocated = s->allocated; + while (allocated) + { + /* First element in allocated chunk is the free list */ + next = *(void **)allocated; + free (allocated); + allocated = next; + } free (s); } @@ -485,7 +720,7 @@ FcCacheFindByStat (struct stat *cache_st s->cache_mtime == cache_stat->st_mtime) { #ifdef HAVE_STRUCT_STAT_ST_MTIM - if (s->cache_mtime != cache_stat->st_mtim.tv_nsec) + if (s->cache_mtime_nano != cache_stat->st_mtim.tv_nsec) continue; #endif FcRefInc (&s->ref); @@ -539,6 +774,30 @@ FcCacheObjectDereference (void *object) unlock_cache (); } +void * +FcCacheAllocate (FcCache *cache, size_t len) +{ + FcCacheSkip *skip; + void *allocated = NULL; + + lock_cache (); + skip = FcCacheFindByAddrUnlocked (cache); + if (skip) + { + void *chunk = malloc (sizeof (void *) + len); + if (chunk) + { + /* First element in allocated chunk is the free list */ + *(void **)chunk = skip->allocated; + skip->allocated = chunk; + /* Return the rest */ + allocated = ((FcChar8 *)chunk) + sizeof (void *); + } + } + unlock_cache (); + return allocated; +} + void FcCacheFini (void) { @@ -632,7 +891,7 @@ FcCacheOffsetsValid (FcCache *cache) if (fs->nfont > (end - (char *) fs) / sizeof (FcPattern)) return FcFalse; - if (fs->fonts != 0 && !FcIsEncodedOffset(fs->fonts)) + if (!FcIsEncodedOffset(fs->fonts)) return FcFalse; for (i = 0; i < fs->nfont; i++) @@ -646,7 +905,8 @@ FcCacheOffsetsValid (FcCache *cache) (char *) font > end - sizeof (FcFontSet) || font->elts_offset < 0 || font->elts_offset > end - (char *) font || - font->num > (end - (char *) font - font->elts_offset) / sizeof (FcPatternElt)) + font->num > (end - (char *) font - font->elts_offset) / sizeof (FcPatternElt) || + !FcRefIsConst (&font->ref)) return FcFalse; @@ -792,6 +1052,11 @@ FcDirCacheLoad (const FcChar8 *dir, FcCo { FcCache *cache = NULL; +#if !defined TOOL_FCCACHE +#ifndef _WIN32 + FcDirCacheReadUUID ((FcChar8 *) dir, config); +#endif +#endif if (!FcDirCacheProcess (config, dir, FcDirCacheMapHelper, &cache, cache_file)) @@ -817,6 +1082,55 @@ FcDirCacheLoadFile (const FcChar8 *cache return cache; } +static int +FcDirChecksum (struct stat *statb) +{ + int ret = (int) statb->st_mtime; + char *endptr; + char *source_date_epoch; + unsigned long long epoch; + + source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + if (source_date_epoch) + { + epoch = strtoull(source_date_epoch, &endptr, 10); + + if (endptr == source_date_epoch) + fprintf (stderr, + "Fontconfig: SOURCE_DATE_EPOCH invalid\n"); + else if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) + || (errno != 0 && epoch == 0)) + fprintf (stderr, + "Fontconfig: SOURCE_DATE_EPOCH: strtoull: %s: %llu\n", + strerror(errno), epoch); + else if (*endptr != '\0') + fprintf (stderr, + "Fontconfig: SOURCE_DATE_EPOCH has trailing garbage\n"); + else if (epoch > ULONG_MAX) + fprintf (stderr, + "Fontconfig: SOURCE_DATE_EPOCH must be <= %lu but saw: %llu\n", + ULONG_MAX, epoch); + else if (epoch < ret) + /* Only override if directory is newer */ + ret = (int) epoch; + } + + return ret; +} + +static int64_t +FcDirChecksumNano (struct stat *statb) +{ +#ifdef HAVE_STRUCT_STAT_ST_MTIM + /* No nanosecond component to parse */ + if (getenv("SOURCE_DATE_EPOCH")) + return 0; + return statb->st_mtim.tv_nsec; +#else + return 0; +#endif +} + /* * Validate a cache file by reading the header and checking * the magic number and the size field @@ -835,10 +1149,10 @@ FcDirCacheValidateHelper (FcConfig *conf ret = FcFalse; else if (fd_stat->st_size != c.size) ret = FcFalse; - else if (c.checksum != (int) dir_stat->st_mtime) + else if (c.checksum != FcDirChecksum (dir_stat)) ret = FcFalse; #ifdef HAVE_STRUCT_STAT_ST_MTIM - else if (c.checksum_nano != dir_stat->st_mtim.tv_nsec) + else if (c.checksum_nano != FcDirChecksumNano (dir_stat)) ret = FcFalse; #endif return ret; @@ -914,10 +1228,8 @@ FcDirCacheBuild (FcFontSet *set, const F cache->magic = FC_CACHE_MAGIC_ALLOC; cache->version = FC_CACHE_VERSION_NUMBER; cache->size = serialize->size; - cache->checksum = (int) dir_stat->st_mtime; -#ifdef HAVE_STRUCT_STAT_ST_MTIM - cache->checksum_nano = dir_stat->st_mtim.tv_nsec; -#endif + cache->checksum = FcDirChecksum (dir_stat); + cache->checksum_nano = FcDirChecksumNano (dir_stat); /* * Serialize directory name @@ -1048,11 +1360,16 @@ FcDirCacheWrite (FcCache *cache, FcConfi if (!cache_dir) return FcFalse; - FcDirCacheBasename (dir, cache_base); +#if !defined TOOL_FCCACHE +#ifndef _WIN32 + if (!FcDirCacheBasenameUUID (dir, cache_base, config)) +#endif +#endif + FcDirCacheBasenameMD5 (dir, cache_base); cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); + FcStrFree (cache_dir); if (!cache_hashed) return FcFalse; - FcStrFree (cache_dir); if (FcDebug () & FC_DBG_CACHE) printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n", @@ -1245,7 +1562,12 @@ FcDirCacheLock (const FcChar8 *dir, const FcChar8 *sysroot = FcConfigGetSysRoot (config); int fd = -1; - FcDirCacheBasename (dir, cache_base); +#if !defined TOOL_FCCACHE +#ifndef _WIN32 + if (!FcDirCacheBasenameUUID (dir, cache_base, config)) +#endif +#endif + FcDirCacheBasenameMD5 (dir, cache_base); list = FcStrListCreate (config->cacheDirs); if (!list) return -1; Index: xsrc/external/mit/fontconfig/dist/src/fccfg.c diff -u xsrc/external/mit/fontconfig/dist/src/fccfg.c:1.3 xsrc/external/mit/fontconfig/dist/src/fccfg.c:1.4 --- xsrc/external/mit/fontconfig/dist/src/fccfg.c:1.3 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/src/fccfg.c Fri Mar 8 09:49:07 2019 @@ -27,7 +27,6 @@ #include "fcint.h" #include <dirent.h> #include <sys/types.h> -#include "../fc-blanks/fcblanks.h" #if defined (_WIN32) && !defined (R_OK) #define R_OK 4 @@ -53,6 +52,36 @@ retry: return config; } +static FcChar32 +FcHashAsStrIgnoreCase (const void *data) +{ + return FcStrHashIgnoreCase (data); +} + +static int +FcCompareAsStr (const void *v1, const void *v2) +{ + return FcStrCmp (v1, v2); +} + +static void +FcDestroyAsRule (void *data) +{ + FcRuleDestroy (data); +} + +static void +FcDestroyAsRuleSet (void *data) +{ + FcRuleSetDestroy (data); +} + +static void +FcDestroyAsStr (void *data) +{ + FcStrFree (data); +} + FcBool FcConfigInit (void) { @@ -73,6 +102,8 @@ FcConfigCreate (void) { FcSetName set; FcConfig *config; + FcMatchKind k; + FcBool err = FcFalse; config = malloc (sizeof (FcConfig)); if (!config) @@ -110,11 +141,15 @@ FcConfigCreate (void) if (!config->cacheDirs) goto bail8; - config->blanks = &fcBlanks; + for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) + { + config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet); + if (!config->subst[k]) + err = FcTrue; + } + if (err) + goto bail9; - config->substPattern = 0; - config->substFont = 0; - config->substScan = 0; config->maxObjects = 0; for (set = FcSetSystem; set <= FcSetApplication; set++) config->fonts[set] = 0; @@ -126,10 +161,31 @@ FcConfigCreate (void) config->sysRoot = NULL; + config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet); + if (!config->rulesetList) + goto bail9; + config->availConfigFiles = FcStrSetCreate (); + if (!config->availConfigFiles) + goto bail10; + + config->uuid_table = FcHashTableCreate (FcHashAsStrIgnoreCase, + FcCompareAsStr, + FcHashStrCopy, + FcHashUuidCopy, + FcDestroyAsStr, + FcHashUuidFree); + FcRefInit (&config->ref, 1); return config; +bail10: + FcPtrListDestroy (config->rulesetList); +bail9: + for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) + if (config->subst[k]) + FcPtrListDestroy (config->subst[k]); + FcStrSetDestroy (config->cacheDirs); bail8: FcFontSetDestroy (config->rejectPatterns); bail7: @@ -207,21 +263,6 @@ FcConfigUptoDate (FcConfig *config) return FcTrue; } -static void -FcSubstDestroy (FcSubst *s) -{ - FcSubst *n; - - while (s) - { - n = s->next; - if (s->rule) - FcRuleDestroy (s->rule); - free (s); - s = n; - } -} - FcExpr * FcConfigAllocExpr (FcConfig *config) { @@ -261,6 +302,7 @@ FcConfigDestroy (FcConfig *config) { FcSetName set; FcExprPage *page; + FcMatchKind k; if (FcRefDec (&config->ref) != 1) return; @@ -276,12 +318,10 @@ FcConfigDestroy (FcConfig *config) FcFontSetDestroy (config->acceptPatterns); FcFontSetDestroy (config->rejectPatterns); - if (config->blanks) - FcBlanksDestroy (config->blanks); - - FcSubstDestroy (config->substPattern); - FcSubstDestroy (config->substFont); - FcSubstDestroy (config->substScan); + for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) + FcPtrListDestroy (config->subst[k]); + FcPtrListDestroy (config->rulesetList); + FcStrSetDestroy (config->availConfigFiles); for (set = FcSetSystem; set <= FcSetApplication; set++) if (config->fonts[set]) FcFontSetDestroy (config->fonts[set]); @@ -296,6 +336,8 @@ FcConfigDestroy (FcConfig *config) if (config->sysRoot) FcStrFree (config->sysRoot); + FcHashTableDestroy (config->uuid_table); + free (config); } @@ -305,11 +347,15 @@ FcConfigDestroy (FcConfig *config) FcBool FcConfigAddCache (FcConfig *config, FcCache *cache, - FcSetName set, FcStrSet *dirSet) + FcSetName set, FcStrSet *dirSet, FcChar8 *forDir) { FcFontSet *fs; intptr_t *dirs; int i; + FcBool relocated = FcFalse; + + if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0) + relocated = FcTrue; /* * Add fonts @@ -323,23 +369,43 @@ FcConfigAddCache (FcConfig *config, FcCa { FcPattern *font = FcFontSetFont (fs, i); FcChar8 *font_file; + FcChar8 *relocated_font_file = NULL; - /* - * Check to see if font is banned by filename - */ if (FcPatternObjectGetString (font, FC_FILE_OBJECT, - 0, &font_file) == FcResultMatch && - !FcConfigAcceptFilename (config, font_file)) + 0, &font_file) == FcResultMatch) { - continue; + if (relocated) + { + FcChar8 *slash = FcStrLastSlash (font_file); + relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL); + font_file = relocated_font_file; + } + + /* + * Check to see if font is banned by filename + */ + if (!FcConfigAcceptFilename (config, font_file)) + { + free (relocated_font_file); + continue; + } } - + /* * Check to see if font is banned by pattern */ if (!FcConfigAcceptFont (config, font)) + { + free (relocated_font_file); continue; - + } + + if (relocated_font_file) + { + font = FcPatternCacheRewriteFile (font, cache, relocated_font_file); + free (relocated_font_file); + } + if (FcFontSetAdd (config->fonts[set], font)) nref++; } @@ -354,9 +420,19 @@ FcConfigAddCache (FcConfig *config, FcCa { for (i = 0; i < cache->dirs_count; i++) { - FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); + const FcChar8 *dir = FcCacheSubdir (cache, i); + FcChar8 *s = NULL; + + if (relocated) + { + FcChar8 *base = FcStrBasename (dir); + dir = s = FcStrBuildFilename (forDir, base, NULL); + FcStrFree (base); + } if (FcConfigAcceptFilename (config, dir)) FcStrSetAddFilename (dirSet, dir); + if (s) + FcStrFree (s); } } return FcTrue; @@ -380,7 +456,7 @@ FcConfigAddDirList (FcConfig *config, Fc cache = FcDirCacheRead (dir, FcFalse, config); if (!cache) continue; - FcConfigAddCache (config, cache, set, dirSet); + FcConfigAddCache (config, cache, set, dirSet, dir); FcDirCacheUnload (cache); } FcStrListDone (dirlist); @@ -474,14 +550,6 @@ FcConfigAddFontDir (FcConfig *config return FcStrSetAddFilename (config->fontDirs, d); } -FcBool -FcConfigAddDir (FcConfig *config, - const FcChar8 *d) -{ - return (FcConfigAddConfigDir (config, d) && - FcConfigAddFontDir (config, d)); -} - FcStrList * FcConfigGetFontDirs (FcConfig *config) { @@ -569,41 +637,50 @@ FcConfigSetFonts (FcConfig *config, config->fonts[set] = fonts; } + FcBlanks * -FcConfigGetBlanks (FcConfig *config) +FcBlanksCreate (void) { - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return config->blanks; + /* Deprecated. */ + return NULL; +} + +void +FcBlanksDestroy (FcBlanks *b FC_UNUSED) +{ + /* Deprecated. */ } FcBool -FcConfigAddBlank (FcConfig *config, - FcChar32 blank) +FcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) { - FcBlanks *b, *freeme = 0; + /* Deprecated. */ + return FcFalse; +} - b = config->blanks; - if (!b) - { - freeme = b = FcBlanksCreate (); - if (!b) - return FcFalse; - } - if (!FcBlanksAdd (b, blank)) - { - if (freeme) - FcBlanksDestroy (freeme); - return FcFalse; - } - config->blanks = b; - return FcTrue; +FcBool +FcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) +{ + /* Deprecated. */ + return FcFalse; +} + +FcBlanks * +FcConfigGetBlanks (FcConfig *config FC_UNUSED) +{ + /* Deprecated. */ + return NULL; +} + +FcBool +FcConfigAddBlank (FcConfig *config FC_UNUSED, + FcChar32 blank FC_UNUSED) +{ + /* Deprecated. */ + return FcFalse; } + int FcConfigGetRescanInterval (FcConfig *config) { @@ -649,61 +726,8 @@ FcConfigAddRule (FcConfig *config, FcRule *rule, FcMatchKind kind) { - FcSubst *subst, **prev; - FcRule *r; - int n = 0; - - if (!rule) - return FcFalse; - switch (kind) { - case FcMatchPattern: - prev = &config->substPattern; - break; - case FcMatchFont: - prev = &config->substFont; - break; - case FcMatchScan: - prev = &config->substScan; - break; - default: - return FcFalse; - } - subst = (FcSubst *) malloc (sizeof (FcSubst)); - if (!subst) - return FcFalse; - for (; *prev; prev = &(*prev)->next); - *prev = subst; - subst->next = NULL; - subst->rule = rule; - for (r = rule; r; r = r->next) - { - switch (r->type) - { - case FcRuleTest: - if (r->u.test && - r->u.test->kind == FcMatchDefault) - r->u.test->kind = kind; - - if (n < r->u.test->object) - n = r->u.test->object; - break; - case FcRuleEdit: - if (n < r->u.edit->object) - n = r->u.edit->object; - break; - default: - break; - } - } - n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; - if (config->maxObjects < n) - config->maxObjects = n; - if (FcDebug () & FC_DBG_EDIT) - { - printf ("Add Subst "); - FcSubstPrint (subst); - } - return FcTrue; + /* deprecated */ + return FcFalse; } static FcValue @@ -724,12 +748,12 @@ FcConfigPromote (FcValue v, FcValue u, F v.u.l = FcLangSetPromote (v.u.s, buf); v.type = FcTypeLangSet; } - else if (v.type == FcTypeVoid && u.type == FcTypeLangSet) + else if (buf && v.type == FcTypeVoid && u.type == FcTypeLangSet) { v.u.l = FcLangSetPromote (NULL, buf); v.type = FcTypeLangSet; } - else if (v.type == FcTypeVoid && u.type == FcTypeCharSet) + else if (buf && v.type == FcTypeVoid && u.type == FcTypeCharSet) { v.u.c = FcCharSetPromote (buf); v.type = FcTypeCharSet; @@ -793,14 +817,30 @@ FcConfigCompareValue (const FcValue *lef case FcTypeBool: switch ((int) op) { case FcOpEqual: + ret = left.u.b == right.u.b; + break; case FcOpContains: case FcOpListing: - ret = left.u.b == right.u.b; + ret = left.u.b == right.u.b || left.u.b == FcDontCare; break; case FcOpNotEqual: - case FcOpNotContains: ret = left.u.b != right.u.b; break; + case FcOpNotContains: + ret = !(left.u.b == right.u.b || left.u.b == FcDontCare); + break; + case FcOpLess: + ret = left.u.b != right.u.b && right.u.b == FcDontCare; + break; + case FcOpLessEqual: + ret = left.u.b == right.u.b || right.u.b == FcDontCare; + break; + case FcOpMore: + ret = left.u.b != right.u.b && left.u.b == FcDontCare; + break; + case FcOpMoreEqual: + ret = left.u.b == right.u.b || left.u.b == FcDontCare; + break; default: break; } @@ -1517,8 +1557,10 @@ FcConfigSubstituteWithPat (FcConfig * FcMatchKind kind) { FcValue v; - FcSubst *s; + FcPtrList *s; + FcPtrListIter iter, iter2; FcRule *r; + FcRuleSet *rs; FcValueList *l, **value = NULL, *vl; FcPattern *m; FcStrSet *strs; @@ -1535,9 +1577,11 @@ FcConfigSubstituteWithPat (FcConfig * return FcFalse; } - switch (kind) { - case FcMatchPattern: - s = config->substPattern; + if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd) + return FcFalse; + s = config->subst[kind]; + if (kind == FcMatchPattern) + { strs = FcGetDefaultLangs (); if (strs) { @@ -1597,15 +1641,6 @@ FcConfigSubstituteWithPat (FcConfig * if (prgname) FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); } - break; - case FcMatchFont: - s = config->substFont; - break; - case FcMatchScan: - s = config->substScan; - break; - default: - return FcFalse; } nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2; @@ -1633,186 +1668,198 @@ FcConfigSubstituteWithPat (FcConfig * printf ("FcConfigSubstitute "); FcPatternPrint (p); } - for (; s; s = s->next) + FcPtrListIterInit (s, &iter); + for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter)) { - r = s->rule; - for (i = 0; i < nobjs; i++) + rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter); + if (FcDebug () & FC_DBG_EDIT) { - elt[i] = NULL; - value[i] = NULL; - tst[i] = NULL; + printf ("\nRule Set: %s\n", rs->name); } - for (; r; r = r->next) + FcPtrListIterInit (rs->subst[kind], &iter2); + for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2)) { - switch (r->type) { - case FcRuleUnknown: - /* shouldn't be reached */ - break; - case FcRuleTest: - object = FC_OBJ_ID (r->u.test->object); - /* - * Check the tests to see if - * they all match the pattern - */ - if (FcDebug () & FC_DBG_EDIT) - { - printf ("FcConfigSubstitute test "); - FcTestPrint (r->u.test); - } - if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) - m = p_pat; - else - m = p; - if (m) - e = FcPatternObjectFindElt (m, r->u.test->object); - else - e = NULL; - /* different 'kind' won't be the target of edit */ - if (!elt[object] && kind == r->u.test->kind) - { - elt[object] = e; - tst[object] = r->u.test; - } - /* - * If there's no such field in the font, - * then FcQualAll matches while FcQualAny does not - */ - if (!e) - { - if (r->u.test->qual == FcQualAll) + r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2); + for (i = 0; i < nobjs; i++) + { + elt[i] = NULL; + value[i] = NULL; + tst[i] = NULL; + } + for (; r; r = r->next) + { + switch (r->type) { + case FcRuleUnknown: + /* shouldn't be reached */ + break; + case FcRuleTest: + object = FC_OBJ_ID (r->u.test->object); + /* + * Check the tests to see if + * they all match the pattern + */ + if (FcDebug () & FC_DBG_EDIT) { - value[object] = NULL; - continue; + printf ("FcConfigSubstitute test "); + FcTestPrint (r->u.test); } + if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) + m = p_pat; else + m = p; + if (m) + e = FcPatternObjectFindElt (m, r->u.test->object); + else + e = NULL; + /* different 'kind' won't be the target of edit */ + if (!elt[object] && kind == r->u.test->kind) + { + elt[object] = e; + tst[object] = r->u.test; + } + /* + * If there's no such field in the font, + * then FcQualAll matches while FcQualAny does not + */ + if (!e) + { + if (r->u.test->qual == FcQualAll) + { + value[object] = NULL; + continue; + } + else + { + if (FcDebug () & FC_DBG_EDIT) + printf ("No match\n"); + goto bail; + } + } + /* + * Check to see if there is a match, mark the location + * to apply match-relative edits + */ + vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); + /* different 'kind' won't be the target of edit */ + if (!value[object] && kind == r->u.test->kind) + value[object] = vl; + if (!vl || + (r->u.test->qual == FcQualFirst && vl != e->values) || + (r->u.test->qual == FcQualNotFirst && vl == e->values)) { if (FcDebug () & FC_DBG_EDIT) printf ("No match\n"); goto bail; } - } - /* - * Check to see if there is a match, mark the location - * to apply match-relative edits - */ - vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); - /* different 'kind' won't be the target of edit */ - if (!value[object] && kind == r->u.test->kind) - value[object] = vl; - if (!vl || - (r->u.test->qual == FcQualFirst && vl != e->values) || - (r->u.test->qual == FcQualNotFirst && vl == e->values)) - { + break; + case FcRuleEdit: + object = FC_OBJ_ID (r->u.edit->object); if (FcDebug () & FC_DBG_EDIT) - printf ("No match\n"); - goto bail; - } - break; - case FcRuleEdit: - object = FC_OBJ_ID (r->u.edit->object); - if (FcDebug () & FC_DBG_EDIT) - { - printf ("Substitute "); - FcEditPrint (r->u.edit); - printf ("\n\n"); - } - /* - * Evaluate the list of expressions - */ - l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); - if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) - elt[object] = FcPatternObjectFindElt (p, tst[object]->object); - - switch (FC_OP_GET_OP (r->u.edit->op)) { - case FcOpAssign: + { + printf ("Substitute "); + FcEditPrint (r->u.edit); + printf ("\n\n"); + } /* - * If there was a test, then replace the matched - * value with the new list of values + * Evaluate the list of expressions */ - if (value[object]) - { - FcValueList *thisValue = value[object]; - FcValueList *nextValue = l; + l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); + if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) + elt[object] = FcPatternObjectFindElt (p, tst[object]->object); + switch (FC_OP_GET_OP (r->u.edit->op)) { + case FcOpAssign: /* - * Append the new list of values after the current value + * If there was a test, then replace the matched + * value with the new list of values */ - FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); + if (value[object]) + { + FcValueList *thisValue = value[object]; + FcValueList *nextValue = l; + + /* + * Append the new list of values after the current value + */ + FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); + /* + * Delete the marked value + */ + if (thisValue) + FcConfigDel (&elt[object]->values, thisValue); + /* + * Adjust a pointer into the value list to ensure + * future edits occur at the same place + */ + value[object] = nextValue; + break; + } + /* fall through ... */ + case FcOpAssignReplace: /* - * Delete the marked value + * Delete all of the values and insert + * the new set */ - if (thisValue) - FcConfigDel (&elt[object]->values, thisValue); + FcConfigPatternDel (p, r->u.edit->object); + FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); /* - * Adjust a pointer into the value list to ensure - * future edits occur at the same place + * Adjust a pointer into the value list as they no + * longer point to anything valid */ - value[object] = nextValue; + value[object] = NULL; break; - } - /* fall through ... */ - case FcOpAssignReplace: - /* - * Delete all of the values and insert - * the new set - */ - FcConfigPatternDel (p, r->u.edit->object); - FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); - /* - * Adjust a pointer into the value list as they no - * longer point to anything valid - */ - value[object] = NULL; - break; - case FcOpPrepend: - if (value[object]) - { - FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); + case FcOpPrepend: + if (value[object]) + { + FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); + break; + } + /* fall through ... */ + case FcOpPrependFirst: + FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); break; - } - /* fall through ... */ - case FcOpPrependFirst: - FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); - break; - case FcOpAppend: - if (value[object]) - { - FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); + case FcOpAppend: + if (value[object]) + { + FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); + break; + } + /* fall through ... */ + case FcOpAppendLast: + FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); + break; + case FcOpDelete: + if (value[object]) + { + FcConfigDel (&elt[object]->values, value[object]); + FcValueListDestroy (l); + break; + } + /* fall through ... */ + case FcOpDeleteAll: + FcConfigPatternDel (p, r->u.edit->object); + FcValueListDestroy (l); + break; + default: + FcValueListDestroy (l); break; } - /* fall through ... */ - case FcOpAppendLast: - FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); - break; - case FcOpDelete: - if (value[object]) + /* + * Now go through the pattern and eliminate + * any properties without data + */ + FcConfigPatternCanon (p, r->u.edit->object); + + if (FcDebug () & FC_DBG_EDIT) { - FcConfigDel (&elt[object]->values, value[object]); - break; + printf ("FcConfigSubstitute edit"); + FcPatternPrint (p); } - /* fall through ... */ - case FcOpDeleteAll: - FcConfigPatternDel (p, r->u.edit->object); - break; - default: - FcValueListDestroy (l); break; } - /* - * Now go through the pattern and eliminate - * any properties without data - */ - FcConfigPatternCanon (p, r->u.edit->object); - - if (FcDebug () & FC_DBG_EDIT) - { - printf ("FcConfigSubstitute edit"); - FcPatternPrint (p); - } - break; } + bail:; } - bail:; } if (FcDebug () & FC_DBG_EDIT) { @@ -2062,7 +2109,8 @@ FcConfigXdgCacheHome (void) ret = malloc (len + 7 + 1); if (ret) { - memcpy (ret, home, len); + if (home) + memcpy (ret, home, len); memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); ret[len + 7] = 0; } @@ -2089,7 +2137,8 @@ FcConfigXdgConfigHome (void) ret = malloc (len + 8 + 1); if (ret) { - memcpy (ret, home, len); + if (home) + memcpy (ret, home, len); memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); ret[len + 8] = 0; } @@ -2116,7 +2165,8 @@ FcConfigXdgDataHome (void) ret = malloc (len + 13 + 1); if (ret) { - memcpy (ret, home, len); + if (home) + memcpy (ret, home, len); memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); ret[len + 13] = 0; } @@ -2146,43 +2196,78 @@ FcConfigFilename (const FcChar8 *url) } file = 0; -#ifdef _WIN32 - if (isalpha (*url) && - url[1] == ':' && - (url[2] == '/' || url[2] == '\\')) - goto absolute_path; -#endif + if (FcStrIsAbsoluteFilename(url)) + return FcConfigFileExists (0, url); - switch (*url) { - case '~': + if (*url == '~') + { dir = FcConfigHome (); if (dir) file = FcConfigFileExists (dir, url + 1); else file = 0; - break; -#ifdef _WIN32 - case '\\': - absolute_path: -#endif - case '/': - file = FcConfigFileExists (0, url); - break; - default: - path = FcConfigGetPath (); - if (!path) - return NULL; - for (p = path; *p; p++) + } + + path = FcConfigGetPath (); + if (!path) + return NULL; + for (p = path; *p; p++) + { + file = FcConfigFileExists (*p, url); + if (file) + break; + } + FcConfigFreePath (path); + return file; +} + +FcChar8 * +FcConfigRealFilename (FcConfig *config, + const FcChar8 *url) +{ + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *n = FcConfigFilename (url); + FcChar8 *nn = NULL; + + if (n) + { + FcChar8 buf[PATH_MAX]; + ssize_t len; + + if (sysroot) + nn = FcStrBuildFilename (sysroot, n, NULL); + else + nn = FcStrdup (n); + FcStrFree (n); + + if ((len = FcReadLink (nn, buf, sizeof (buf) - 1)) != -1) { - file = FcConfigFileExists (*p, url); - if (file) - break; + buf[len] = 0; + + if (!FcStrIsAbsoluteFilename (buf)) + { + FcChar8 *dirname = FcStrDirname (nn); + FcStrFree (nn); + if (!dirname) + return NULL; + + FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL); + FcStrFree (dirname); + if (!path) + return NULL; + + nn = FcStrCanonFilename (path); + FcStrFree (path); + } + else + { + FcStrFree (nn); + nn = FcStrdup (buf); + } } - FcConfigFreePath (path); - break; } - return file; + return nn; } /* @@ -2221,7 +2306,7 @@ FcConfigAppFontAddFile (FcConfig *con FcConfigSetFonts (config, set, FcSetApplication); } - if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) + if (!FcFileScanConfig (set, subdirs, file, config)) { FcStrSetDestroy (subdirs); return FcFalse; @@ -2376,7 +2461,10 @@ FcConfigGetSysRoot (const FcConfig *conf return NULL; } - return config->sysRoot; + if (config->sysRoot) + return config->sysRoot; + + return (FcChar8 *) getenv ("FONTCONFIG_SYSROOT"); } void @@ -2425,6 +2513,200 @@ FcConfigSetSysRoot (FcConfig *confi } } +FcRuleSet * +FcRuleSetCreate (const FcChar8 *name) +{ + FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet)); + FcMatchKind k; + const FcChar8 *p; + + if (!name) + p = (const FcChar8 *)""; + else + p = name; + + if (ret) + { + ret->name = FcStrdup (p); + ret->description = NULL; + ret->domain = NULL; + for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) + ret->subst[k] = FcPtrListCreate (FcDestroyAsRule); + FcRefInit (&ret->ref, 1); + } + + return ret; +} + +void +FcRuleSetDestroy (FcRuleSet *rs) +{ + FcMatchKind k; + + if (!rs) + return; + if (FcRefDec (&rs->ref) != 1) + return; + + if (rs->name) + FcStrFree (rs->name); + if (rs->description) + FcStrFree (rs->description); + if (rs->domain) + FcStrFree (rs->domain); + for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) + FcPtrListDestroy (rs->subst[k]); + + free (rs); +} + +void +FcRuleSetReference (FcRuleSet *rs) +{ + if (!FcRefIsConst (&rs->ref)) + FcRefInc (&rs->ref); +} + +void +FcRuleSetEnable (FcRuleSet *rs, + FcBool flag) +{ + if (rs) + { + rs->enabled = flag; + /* XXX: we may want to provide a feature + * to enable/disable rulesets through API + * in the future? + */ + } +} + +void +FcRuleSetAddDescription (FcRuleSet *rs, + const FcChar8 *domain, + const FcChar8 *description) +{ + if (rs->domain) + FcStrFree (rs->domain); + if (rs->description) + FcStrFree (rs->description); + + rs->domain = domain ? FcStrdup (domain) : NULL; + rs->description = description ? FcStrdup (description) : NULL; +} + +int +FcRuleSetAdd (FcRuleSet *rs, + FcRule *rule, + FcMatchKind kind) +{ + FcPtrListIter iter; + FcRule *r; + int n = 0, ret; + + if (!rs || + kind < FcMatchKindBegin || kind >= FcMatchKindEnd) + return -1; + FcPtrListIterInitAtLast (rs->subst[kind], &iter); + if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule)) + return -1; + + for (r = rule; r; r = r->next) + { + switch (r->type) + { + case FcRuleTest: + if (r->u.test) + { + if (r->u.test->kind == FcMatchDefault) + r->u.test->kind = kind; + if (n < r->u.test->object) + n = r->u.test->object; + } + break; + case FcRuleEdit: + if (n < r->u.edit->object) + n = r->u.edit->object; + break; + default: + break; + } + } + if (FcDebug () & FC_DBG_EDIT) + { + printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name); + FcRulePrint (rule); + } + ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; + + return ret < 0 ? 0 : ret; +} + +void +FcConfigFileInfoIterInit (FcConfig *config, + FcConfigFileInfoIter *iter) +{ + FcConfig *c; + FcPtrListIter *i = (FcPtrListIter *)iter; + + if (!config) + c = FcConfigGetCurrent (); + else + c = config; + FcPtrListIterInit (c->rulesetList, i); +} + +FcBool +FcConfigFileInfoIterNext (FcConfig *config, + FcConfigFileInfoIter *iter) +{ + FcConfig *c; + FcPtrListIter *i = (FcPtrListIter *)iter; + + if (!config) + c = FcConfigGetCurrent (); + else + c = config; + if (FcPtrListIterIsValid (c->rulesetList, i)) + { + FcPtrListIterNext (c->rulesetList, i); + } + else + return FcFalse; + + return FcTrue; +} + +FcBool +FcConfigFileInfoIterGet (FcConfig *config, + FcConfigFileInfoIter *iter, + FcChar8 **name, + FcChar8 **description, + FcBool *enabled) +{ + FcConfig *c; + FcRuleSet *r; + FcPtrListIter *i = (FcPtrListIter *)iter; + + if (!config) + c = FcConfigGetCurrent (); + else + c = config; + if (!FcPtrListIterIsValid (c->rulesetList, i)) + return FcFalse; + r = FcPtrListIterGetValue (c->rulesetList, i); + if (name) + *name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf"); + if (description) + *description = FcStrdup (!r->description ? _("No description") : + dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf", + (const char *) r->description)); + if (enabled) + *enabled = r->enabled; + + return FcTrue; +} + #define __fccfg__ #include "fcaliastail.h" #undef __fccfg__ Index: xsrc/external/mit/fontconfig/dist/src/fcinit.c diff -u xsrc/external/mit/fontconfig/dist/src/fcinit.c:1.3 xsrc/external/mit/fontconfig/dist/src/fcinit.c:1.4 --- xsrc/external/mit/fontconfig/dist/src/fcinit.c:1.3 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/src/fcinit.c Fri Mar 8 09:49:07 2019 @@ -39,15 +39,23 @@ static FcConfig * FcInitFallbackConfig (const FcChar8 *sysroot) { FcConfig *config; + const FcChar8 *fallback = (const FcChar8 *) "" \ + "<fontconfig>" \ + " <dir>" FC_DEFAULT_FONTS "</dir>" \ + " <dir prefix=\"xdg\">fonts</dir>" \ + " <cachedir>" FC_CACHEDIR "</cachedir>" \ + " <cachedir prefix=\"xdg\">fontconfig</cachedir>" \ + " <include ignore_missing=\"yes\" prefix=\"xdg\">fontconfig/conf.d</include>" \ + " <include ignore_missing=\"yes\" prefix=\"xdg\">fontconfig/fonts.conf</include>" \ + "</fontconfig>"; config = FcConfigCreate (); if (!config) goto bail0; FcConfigSetSysRoot (config, sysroot); - if (!FcConfigAddDir (config, (FcChar8 *) FC_DEFAULT_FONTS)) - goto bail1; - if (!FcConfigAddCacheDir (config, (FcChar8 *) FC_CACHEDIR)) + if (!FcConfigParseAndLoadFromMemory (config, fallback, FcFalse)) goto bail1; + return config; bail1: @@ -86,6 +94,7 @@ FcInitLoadOwnConfig (FcConfig *config) return fallback; } + (void) FcConfigParseOnly (config, (const FcChar8 *)FC_TEMPLATEDIR, FcFalse); if (config->cacheDirs && config->cacheDirs->num == 0) { Index: xsrc/external/mit/fontconfig/dist/src/fcformat.c diff -u xsrc/external/mit/fontconfig/dist/src/fcformat.c:1.2 xsrc/external/mit/fontconfig/dist/src/fcformat.c:1.3 --- xsrc/external/mit/fontconfig/dist/src/fcformat.c:1.2 Tue Dec 10 23:08:36 2013 +++ xsrc/external/mit/fontconfig/dist/src/fcformat.c Fri Mar 8 09:49:07 2019 @@ -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) - { - FcValueListPtr l; - count++; - for (l = FcPatternEltValues(e); - l->next; - l = l->next) - count++; + if (FcPatternFindIter (pat, &iter, (const char *) c->word)) + { + 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) { Index: xsrc/external/mit/fontconfig/dist/src/fcfreetype.c diff -u xsrc/external/mit/fontconfig/dist/src/fcfreetype.c:1.2 xsrc/external/mit/fontconfig/dist/src/fcfreetype.c:1.3 --- xsrc/external/mit/fontconfig/dist/src/fcfreetype.c:1.2 Wed Aug 30 20:09:45 2017 +++ xsrc/external/mit/fontconfig/dist/src/fcfreetype.c Fri Mar 8 09:49:07 2019 @@ -51,6 +51,7 @@ #include <string.h> #include <ft2build.h> #include FT_FREETYPE_H +#include FT_ADVANCES_H #include FT_TRUETYPE_TABLES_H #include FT_SFNT_NAMES_H #include FT_TRUETYPE_IDS_H @@ -66,16 +67,6 @@ #include "ftglue.h" -#if HAVE_WARNING_CPP_DIRECTIVE -#if !HAVE_FT_GET_BDF_PROPERTY -#warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later" -#endif - -#if !HAVE_FT_GET_PS_FONT_INFO -#warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later" -#endif -#endif - /* * Keep Han languages separated by eliminating languages * that the codePageRange bits says aren't supported @@ -385,12 +376,7 @@ static const FcFtLanguage fcFtLanguage { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" }, { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" }, { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" }, - -#ifdef TT_MS_LANGID_MAORI_NEW_ZELAND - /* this seems to be an error that have been dropped */ { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" }, -#endif - { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" }, { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" }, { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" }, @@ -557,6 +543,9 @@ static const FcMacRomanFake fcMacRomanFa static FcChar8 * FcFontCapabilities(FT_Face face); +static int +FcFreeTypeSpacing (FT_Face face); + #define NUM_FC_MAC_ROMAN_FAKE (int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0])) @@ -1108,11 +1097,7 @@ FcGetPixelSize (FT_Face face, int i) return (double) prop.u.integer; } #endif -#if HAVE_FT_BITMAP_SIZE_Y_PPEM return (double) face->available_sizes[i].y_ppem / 64.0; -#else - return (double) face->available_sizes[i].height; -#endif } static FcBool @@ -1132,20 +1117,17 @@ static const FT_UShort platform_order[] TT_PLATFORM_MICROSOFT, TT_PLATFORM_APPLE_UNICODE, TT_PLATFORM_MACINTOSH, + TT_PLATFORM_ISO, }; #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0])) static const FT_UShort nameid_order[] = { -#ifdef TT_NAME_ID_WWS_FAMILY TT_NAME_ID_WWS_FAMILY, -#endif TT_NAME_ID_PREFERRED_FAMILY, TT_NAME_ID_FONT_FAMILY, TT_NAME_ID_MAC_FULL_NAME, TT_NAME_ID_FULL_NAME, -#ifdef TT_NAME_ID_WWS_SUBFAMILY TT_NAME_ID_WWS_SUBFAMILY, -#endif TT_NAME_ID_PREFERRED_SUBFAMILY, TT_NAME_ID_FONT_SUBFAMILY, TT_NAME_ID_TRADEMARK, @@ -1153,20 +1135,88 @@ static const FT_UShort nameid_order[] = }; #define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0])) -FcPattern * -FcFreeTypeQueryFace (const FT_Face face, - const FcChar8 *file, - int id, - FcBlanks *blanks) + +typedef struct +{ + unsigned int platform_id; + unsigned int name_id; + unsigned int encoding_id; + unsigned int language_id; + unsigned int idx; +} FcNameMapping; + +static int +name_mapping_cmp (const void *pa, const void *pb) +{ + const FcNameMapping *a = (const FcNameMapping *) pa; + const FcNameMapping *b = (const FcNameMapping *) pb; + + if (a->platform_id != b->platform_id) return (int) a->platform_id - (int) b->platform_id; + if (a->name_id != b->name_id) return (int) a->name_id - (int) b->name_id; + if (a->encoding_id != b->encoding_id) return (int) a->encoding_id - (int) b->encoding_id; + if (a->language_id != b->language_id) return (int) a->language_id - (int) b->language_id; + if (a->idx != b->idx) return (int) a->idx - (int) b->idx; + + return 0; +} + +static int +FcFreeTypeGetFirstName (const FT_Face face, + unsigned int platform, + unsigned int nameid, + FcNameMapping *mapping, + unsigned int count, + FT_SfntName *sname) +{ + int min = 0, max = (int) count - 1; + + while (min <= max) + { + int mid = (min + max) / 2; + + if (FT_Get_Sfnt_Name (face, mapping[mid].idx, sname) != 0) + return FcFalse; + + if (platform < sname->platform_id || + (platform == sname->platform_id && + (nameid < sname->name_id || + (nameid == sname->name_id && + (mid && + platform == mapping[mid - 1].platform_id && + nameid == mapping[mid - 1].name_id + ))))) + max = mid - 1; + else if (platform > sname->platform_id || + (platform == sname->platform_id && + nameid > sname->name_id)) + min = mid + 1; + else + return mid; + } + + return -1; +} + +static FcPattern * +FcFreeTypeQueryFaceInternal (const FT_Face face, + const FcChar8 *file, + unsigned int id, + FcCharSet **cs_share, + FcLangSet **ls_share, + FcNameMapping **nm_share) { FcPattern *pat; int slant = -1; - int weight = -1; - int width = -1; + double weight = -1; + double width = -1; FcBool decorative = FcFalse; - int i; - FcCharSet *cs; - FcLangSet *ls; + FcBool variable = FcFalse; + FcBool variable_weight = FcFalse; + FcBool variable_width = FcFalse; + FcBool variable_size = FcFalse; + FcCharSet *cs; + FcLangSet *ls; + FcNameMapping *name_mapping = NULL; #if 0 FcChar8 *family = 0; #endif @@ -1189,9 +1239,8 @@ FcFreeTypeQueryFace (const FT_Face face #endif TT_Header *head; const FcChar8 *exclusiveLang = 0; - FT_SfntName sname; - FT_UInt snamei, snamec; + int name_count = 0; int nfamily = 0; int nfamily_lang = 0; int nstyle = 0; @@ -1199,14 +1248,9 @@ FcFreeTypeQueryFace (const FT_Face face int nfullname = 0; int nfullname_lang = 0; unsigned int p, n; - int platform, nameid; FcChar8 *style = 0; int st; - char psname[256]; - const char *tmp; - - FcRange *r = NULL; FcBool symbol = FcFalse; @@ -1220,17 +1264,12 @@ FcFreeTypeQueryFace (const FT_Face face int has_outline = !!(face->face_flags & FT_FACE_FLAG_SCALABLE); int has_color = 0; -#ifdef FT_FACE_FLAG_COLOR - has_color = !!(face->face_flags & FT_FACE_FLAG_COLOR); -#endif - if (!FcPatternAddBool (pat, FC_OUTLINE, has_outline)) goto bail1; -#ifdef FT_FACE_FLAG_COLOR + has_color = FT_HAS_COLOR (face); if (!FcPatternAddBool (pat, FC_COLOR, has_color)) goto bail1; -#endif /* All color fonts are designed to be scaled, even if they only have * bitmap strikes. Client is responsible to scale the bitmaps. This @@ -1241,40 +1280,106 @@ FcFreeTypeQueryFace (const FT_Face face if (id >> 16) { - if (!FT_Get_MM_Var (face, &master)) - instance = &master->namedstyle[(id >> 16) - 1]; + if (FT_Get_MM_Var (face, &master)) + goto bail1; - if (instance) + if (id >> 16 == 0x8000) { - /* Pull out weight and width from named-instance. */ + /* Query variable font itself. */ unsigned int i; for (i = 0; i < master->num_axis; i++) { - double value = instance->coords[i] / (double) (1 << 16); - double default_value = master->axis[i].def / (double) (1 << 16); - double mult = value / default_value; - //printf ("named-instance, axis %d tag %lx value %g\n", i, master->axis[i].tag, value); - switch (master->axis[i].tag) - { - case FT_MAKE_TAG ('w','g','h','t'): - weight_mult = mult; - break; + double min_value = master->axis[i].minimum / (double) (1U << 16); + double def_value = master->axis[i].def / (double) (1U << 16); + double max_value = master->axis[i].maximum / (double) (1U << 16); + const char *elt = NULL; + + if (min_value > def_value || def_value > max_value || min_value == max_value) + continue; + + switch (master->axis[i].tag) + { + case FT_MAKE_TAG ('w','g','h','t'): + elt = FC_WEIGHT; + min_value = FcWeightFromOpenTypeDouble (min_value); + max_value = FcWeightFromOpenTypeDouble (max_value); + variable_weight = FcTrue; + weight = 0; /* To stop looking for weight. */ + break; + + case FT_MAKE_TAG ('w','d','t','h'): + elt = FC_WIDTH; + /* Values in 'wdth' match Fontconfig FC_WIDTH_* scheme directly. */ + variable_width = FcTrue; + width = 0; /* To stop looking for width. */ + break; + + case FT_MAKE_TAG ('o','p','s','z'): + elt = FC_SIZE; + /* Values in 'opsz' match Fontconfig FC_SIZE, both are in points. */ + variable_size = FcTrue; + break; + } + + if (elt) + { + FcRange *r = FcRangeCreateDouble (min_value, max_value); + if (!FcPatternAddRange (pat, elt, r)) + { + FcRangeDestroy (r); + goto bail1; + } + FcRangeDestroy (r); + variable = FcTrue; + } + } - case FT_MAKE_TAG ('w','d','t','h'): - width_mult = mult; - break; + if (!variable) + goto bail1; + + id &= 0xFFFF; + } + else if ((id >> 16) - 1 < master->num_namedstyles) + { + /* Pull out weight and width from named-instance. */ + unsigned int i; + + instance = &master->namedstyle[(id >> 16) - 1]; - /* TODO optical size! */ + for (i = 0; i < master->num_axis; i++) + { + double value = instance->coords[i] / (double) (1U << 16); + double default_value = master->axis[i].def / (double) (1U << 16); + double mult = default_value ? value / default_value : 1; + //printf ("named-instance, axis %d tag %lx value %g\n", i, master->axis[i].tag, value); + switch (master->axis[i].tag) + { + case FT_MAKE_TAG ('w','g','h','t'): + weight_mult = mult; + break; + + case FT_MAKE_TAG ('w','d','t','h'): + width_mult = mult; + break; + + case FT_MAKE_TAG ('o','p','s','z'): + if (!FcPatternAddDouble (pat, FC_SIZE, value)) + goto bail1; + break; } } } + else + goto bail1; } + if (!FcPatternAddBool (pat, FC_VARIABLE, variable)) + goto bail1; /* * Get the OS/2 table */ - os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2); + os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, FT_SFNT_OS2); /* * Look first in the OS/2 table for the foundry, if @@ -1302,13 +1407,44 @@ FcFreeTypeQueryFace (const FT_Face face * and style names. FreeType makes quite a hash * of them */ - snamec = FT_Get_Sfnt_Name_Count (face); - for (p = 0; p <= NUM_PLATFORM_ORDER; p++) + name_count = FT_Get_Sfnt_Name_Count (face); + if (nm_share) + name_mapping = *nm_share; + if (!name_mapping) + { + int i = 0; + name_mapping = malloc (name_count * sizeof (FcNameMapping)); + if (!name_mapping) + name_count = 0; + for (i = 0; i < name_count; i++) + { + FcNameMapping *p = &name_mapping[i]; + FT_SfntName sname; + if (FT_Get_Sfnt_Name (face, i, &sname) == 0) + { + p->platform_id = sname.platform_id; + p->name_id = sname.name_id; + p->encoding_id = sname.encoding_id; + p->language_id = sname.language_id; + p->idx = i; + } + else + { + p->platform_id = + p->name_id = + p->encoding_id = + p->language_id = + p->idx = (unsigned int) -1; + } + } + qsort (name_mapping, name_count, sizeof(FcNameMapping), name_mapping_cmp); + + if (nm_share) + *nm_share = name_mapping; + } + for (p = 0; p < NUM_PLATFORM_ORDER; p++) { - if (p < NUM_PLATFORM_ORDER) - platform = platform_order[p]; - else - platform = 0xffff; + int platform = platform_order[p]; /* * Order nameids so preferred names appear first @@ -1316,73 +1452,47 @@ FcFreeTypeQueryFace (const FT_Face face */ for (n = 0; n < NUM_NAMEID_ORDER; n++) { - nameid = nameid_order[n]; + FT_SfntName sname; + int nameidx; + const FcChar8 *lang; + const char *elt = 0, *eltlang = 0; + int *np = 0, *nlangp = 0; + size_t len; + int nameid, lookupid; - for (snamei = 0; snamei < snamec; snamei++) - { - FcChar8 *utf8, *pp; - const FcChar8 *lang; - const char *elt = 0, *eltlang = 0; - int *np = 0, *nlangp = 0; - size_t len; + nameid = lookupid = nameid_order[n]; - if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0) - continue; - - if (instance) - { - /* For named-instances, we regular style nameIDs, - * and map the instance's strid to FONT_SUBFAMILY. */ - if (sname.name_id == TT_NAME_ID_WWS_SUBFAMILY || - sname.name_id == TT_NAME_ID_PREFERRED_SUBFAMILY || - sname.name_id == TT_NAME_ID_FONT_SUBFAMILY) - continue; - if (sname.name_id == instance->strid) - sname.name_id = TT_NAME_ID_FONT_SUBFAMILY; - } - - if (sname.name_id != nameid) + if (instance) + { + /* For named-instances, we skip regular style nameIDs, + * and treat the instance's nameid as FONT_SUBFAMILY. + * Postscript name is automatically handled by FreeType. */ + if (nameid == TT_NAME_ID_WWS_SUBFAMILY || + nameid == TT_NAME_ID_PREFERRED_SUBFAMILY) continue; - /* - * Sort platforms in preference order, accepting - * all other platforms last - */ - if (p < NUM_PLATFORM_ORDER) - { - if (sname.platform_id != platform) - continue; - } - else - { - unsigned int sp; - - for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++) - if (sname.platform_id == platform_order[sp]) - break; - if (sp != NUM_PLATFORM_ORDER) - continue; - } - utf8 = FcSfntNameTranscode (&sname); - lang = FcSfntNameLanguage (&sname); - - if (!utf8) - continue; + if (nameid == TT_NAME_ID_FONT_SUBFAMILY) + lookupid = instance->strid; + } - switch (sname.name_id) { -#ifdef TT_NAME_ID_WWS_FAMILY + nameidx = FcFreeTypeGetFirstName (face, platform, lookupid, + name_mapping, name_count, + &sname); + if (nameidx == -1) + continue; + do + { + switch (nameid) { case TT_NAME_ID_WWS_FAMILY: -#endif case TT_NAME_ID_PREFERRED_FAMILY: case TT_NAME_ID_FONT_FAMILY: #if 0 case TT_NAME_ID_UNIQUE_ID: #endif if (FcDebug () & FC_DBG_SCANV) - printf ("found family (n %2d p %d e %d l 0x%04x) %s\n", + printf ("found family (n %2d p %d e %d l 0x%04x)", sname.name_id, sname.platform_id, - sname.encoding_id, sname.language_id, - utf8); + sname.encoding_id, sname.language_id); elt = FC_FAMILY; eltlang = FC_FAMILYLANG; @@ -1392,38 +1502,24 @@ FcFreeTypeQueryFace (const FT_Face face case TT_NAME_ID_MAC_FULL_NAME: case TT_NAME_ID_FULL_NAME: if (FcDebug () & FC_DBG_SCANV) - printf ("found full (n %2d p %d e %d l 0x%04x) %s\n", + printf ("found full (n %2d p %d e %d l 0x%04x)", sname.name_id, sname.platform_id, - sname.encoding_id, sname.language_id, - utf8); + sname.encoding_id, sname.language_id); elt = FC_FULLNAME; eltlang = FC_FULLNAMELANG; np = &nfullname; nlangp = &nfullname_lang; break; -#ifdef TT_NAME_ID_WWS_SUBFAMILY case TT_NAME_ID_WWS_SUBFAMILY: -#endif case TT_NAME_ID_PREFERRED_SUBFAMILY: case TT_NAME_ID_FONT_SUBFAMILY: - if (utf8) - { - pp = utf8; - while (*pp == ' ') - pp++; - len = strlen ((const char *) pp); - memmove (utf8, pp, len + 1); - pp = utf8 + len - 1; - while (*pp == ' ') - pp--; - *(pp + 1) = 0; - } + if (variable) + break; if (FcDebug () & FC_DBG_SCANV) - printf ("found style (n %2d p %d e %d l 0x%04x) %s\n", + printf ("found style (n %2d p %d e %d l 0x%04x) ", sname.name_id, sname.platform_id, - sname.encoding_id, sname.language_id, - utf8); + sname.encoding_id, sname.language_id); elt = FC_STYLE; eltlang = FC_STYLELANG; @@ -1434,11 +1530,38 @@ FcFreeTypeQueryFace (const FT_Face face case TT_NAME_ID_MANUFACTURER: /* If the foundry wasn't found in the OS/2 table, look here */ if(!foundry) + { + FcChar8 *utf8; + utf8 = FcSfntNameTranscode (&sname); foundry = FcNoticeFoundry((FT_String *) utf8); + free (utf8); + } break; } if (elt) { + FcChar8 *utf8, *pp; + + utf8 = FcSfntNameTranscode (&sname); + lang = FcSfntNameLanguage (&sname); + + if (FcDebug () & FC_DBG_SCANV) + printf ("%s\n", utf8); + + if (!utf8) + continue; + + /* Trim surrounding whitespace. */ + pp = utf8; + while (*pp == ' ') + pp++; + len = strlen ((const char *) pp); + memmove (utf8, pp, len + 1); + pp = utf8 + len; + while (pp > utf8 && *(pp - 1) == ' ') + pp--; + *pp = 0; + if (FcStringInPatternElement (pat, elt, utf8)) { free (utf8); @@ -1467,11 +1590,14 @@ FcFreeTypeQueryFace (const FT_Face face } ++*np; } - else - free (utf8); } + while (++nameidx < name_count && + FT_Get_Sfnt_Name (face, name_mapping[nameidx].idx, &sname) == 0 && + platform == sname.platform_id && lookupid == sname.name_id); } } + if (!nm_share) + free (name_mapping); if (!nfamily && face->family_name && FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0) @@ -1485,11 +1611,12 @@ FcFreeTypeQueryFace (const FT_Face face ++nfamily; } - if (!nstyle && face->style_name && + if (!variable && !nstyle && face->style_name && FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0) { if (FcDebug () & FC_DBG_SCANV) printf ("using FreeType style \"%s\"\n", face->style_name); + if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name)) goto bail1; if (!FcPatternAddString (pat, FC_STYLELANG, (FcChar8 *) "en")) @@ -1526,51 +1653,57 @@ FcFreeTypeQueryFace (const FT_Face face } /* Add the PostScript name into the cache */ - tmp = FT_Get_Postscript_Name (face); - if (!tmp) + if (!variable) { - FcChar8 *family, *familylang = NULL; - size_t len; - int n = 0; + char psname[256]; + const char *tmp; + tmp = FT_Get_Postscript_Name (face); + if (!tmp) + { + unsigned int i; + FcChar8 *family, *familylang = NULL; + size_t len; + int n = 0; - /* Workaround when FT_Get_Postscript_Name didn't give any name. - * try to find out the English family name and convert. - */ - while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch) - { - if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0) - break; - n++; - familylang = NULL; - } - if (!familylang) - n = 0; + /* Workaround when FT_Get_Postscript_Name didn't give any name. + * try to find out the English family name and convert. + */ + while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch) + { + if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0) + break; + n++; + familylang = NULL; + } + if (!familylang) + n = 0; - if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch) - goto bail1; - len = strlen ((const char *)family); - /* the literal name in PostScript Language is limited to 127 characters though, - * It is the architectural limit. so assuming 255 characters may works enough. - */ - for (i = 0; i < len && i < 255; i++) - { - /* those characters are not allowed to be the literal name in PostScript */ - static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n "; + if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch) + goto bail1; + len = strlen ((const char *)family); + /* the literal name in PostScript Language is limited to 127 characters though, + * It is the architectural limit. so assuming 255 characters may works enough. + */ + for (i = 0; i < len && i < 255; i++) + { + /* those characters are not allowed to be the literal name in PostScript */ + static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n "; - if (strchr(exclusive_chars, family[i]) != NULL) - psname[i] = '-'; - else - psname[i] = family[i]; + if (strchr(exclusive_chars, family[i]) != NULL) + psname[i] = '-'; + else + psname[i] = family[i]; + } + psname[i] = 0; } - psname[i] = 0; - } - else - { - strncpy (psname, tmp, 255); - psname[255] = 0; + else + { + strncpy (psname, tmp, 255); + psname[255] = 0; + } + if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname)) + goto bail1; } - if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname)) - goto bail1; if (file && *file && !FcPatternAddString (pat, FC_FILE, file)) goto bail1; @@ -1606,6 +1739,7 @@ FcFreeTypeQueryFace (const FT_Face face if (os2 && os2->version >= 0x0001 && os2->version != 0xffff) { + unsigned int i; for (i = 0; i < NUM_CODE_PAGE_RANGE; i++) { FT_ULong bits; @@ -1620,7 +1754,7 @@ FcFreeTypeQueryFace (const FT_Face face bits = os2->ulCodePageRange2; bit = FcCodePageRange[i].bit - 32; } - if (bits & (1 << bit)) + if (bits & (1U << bit)) { /* * If the font advertises support for multiple @@ -1640,21 +1774,12 @@ FcFreeTypeQueryFace (const FT_Face face if (os2 && os2->version != 0xffff) { weight = os2->usWeightClass; - if (weight < 10 && weight_mult != 1.0) - { - /* Work around bad values by cleaning them up before - * multiplying by weight_mult. */ - weight = FcWeightToOpenType (FcWeightFromOpenType (weight)); - } - weight = FcWeightFromOpenType ((int) (weight * weight_mult + .5)); + weight = FcWeightFromOpenTypeDouble (weight * weight_mult); if ((FcDebug() & FC_DBG_SCANV) && weight != -1) - printf ("\tos2 weight class %d multiplier %g maps to weight %d\n", + printf ("\tos2 weight class %d multiplier %g maps to weight %g\n", os2->usWeightClass, weight_mult, weight); - /* TODO: - * Add FcWidthFromOpenType and FcWidthToOpenType, - * and apply width_mult post-conversion? */ - switch ((int) (os2->usWidthClass * width_mult + .5)) { + switch (os2->usWidthClass) { case 1: width = FC_WIDTH_ULTRACONDENSED; break; case 2: width = FC_WIDTH_EXTRACONDENSED; break; case 3: width = FC_WIDTH_CONDENSED; break; @@ -1665,8 +1790,9 @@ FcFreeTypeQueryFace (const FT_Face face case 8: width = FC_WIDTH_EXTRAEXPANDED; break; case 9: width = FC_WIDTH_ULTRAEXPANDED; break; } + width *= width_mult; if ((FcDebug() & FC_DBG_SCANV) && width != -1) - printf ("\tos2 width class %d multiplier %g maps to width %d\n", + printf ("\tos2 width class %d multiplier %g maps to width %g\n", os2->usWidthClass, width_mult, width); } if (os2 && (complex_ = FcFontCapabilities(face))) @@ -1679,24 +1805,31 @@ FcFreeTypeQueryFace (const FT_Face face free (complex_); } -#if defined (HAVE_TT_OS2_USUPPEROPTICALPOINTSIZE) && defined (HAVE_TT_OS2_USLOWEROPTICALPOINTSIZE) - if (os2 && os2->version >= 0x0005 && os2->version != 0xffff) + if (!variable_size && os2 && os2->version >= 0x0005 && os2->version != 0xffff) { double lower_size, upper_size; + FcRange *r; /* usLowerPointSize and usUpperPointSize is actually twips */ lower_size = os2->usLowerOpticalPointSize / 20.0L; upper_size = os2->usUpperOpticalPointSize / 20.0L; - r = FcRangeCreateDouble (lower_size, upper_size); - if (!FcPatternAddRange (pat, FC_SIZE, r)) + if (lower_size == upper_size) { + if (!FcPatternAddDouble (pat, FC_SIZE, lower_size)) + goto bail1; + } + else + { + r = FcRangeCreateDouble (lower_size, upper_size); + if (!FcPatternAddRange (pat, FC_SIZE, r)) + { + FcRangeDestroy (r); + goto bail1; + } FcRangeDestroy (r); - goto bail1; } - FcRangeDestroy (r); } -#endif /* * Type 1: Check for FontInfo dictionary information @@ -1710,7 +1843,7 @@ FcFreeTypeQueryFace (const FT_Face face { weight = FcIsWeight ((FcChar8 *) psfontinfo.weight); if (FcDebug() & FC_DBG_SCANV) - printf ("\tType1 weight %s maps to %d\n", + printf ("\tType1 weight %s maps to %g\n", psfontinfo.weight, weight); } @@ -1774,7 +1907,7 @@ FcFreeTypeQueryFace (const FT_Face face { width = FcIsWidth ((FcChar8 *) prop.u.atom); if (FcDebug () & FC_DBG_SCANV) - printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width); + printf ("\tsetwidth %s maps to %g\n", prop.u.atom, width); } } #endif @@ -1788,13 +1921,13 @@ FcFreeTypeQueryFace (const FT_Face face { weight = FcContainsWeight (style); if (FcDebug() & FC_DBG_SCANV) - printf ("\tStyle %s maps to weight %d\n", style, weight); + printf ("\tStyle %s maps to weight %g\n", style, weight); } if (width == -1) { width = FcContainsWidth (style); if (FcDebug() & FC_DBG_SCANV) - printf ("\tStyle %s maps to width %d\n", style, width); + printf ("\tStyle %s maps to width %g\n", style, width); } if (slant == -1) { @@ -1836,10 +1969,10 @@ FcFreeTypeQueryFace (const FT_Face face if (!FcPatternAddInteger (pat, FC_SLANT, slant)) goto bail1; - if (!FcPatternAddInteger (pat, FC_WEIGHT, weight)) + if (!variable_weight && !FcPatternAddDouble (pat, FC_WEIGHT, weight)) goto bail1; - if (!FcPatternAddInteger (pat, FC_WIDTH, width)) + if (!variable_width && !FcPatternAddDouble (pat, FC_WIDTH, width)) goto bail1; if (!FcPatternAddString (pat, FC_FOUNDRY, foundry)) @@ -1852,15 +1985,23 @@ FcFreeTypeQueryFace (const FT_Face face /* * Compute the unicode coverage for the font */ - cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing); + if (cs_share && *cs_share) + cs = FcCharSetCopy (*cs_share); + else + { + cs = FcFreeTypeCharSet (face, NULL); + if (cs_share) + *cs_share = FcCharSetCopy (cs); + } if (!cs) goto bail1; - /* The FcFreeTypeCharSetAndSpacing() chose the encoding; test it for symbol. */ + /* The FcFreeTypeCharSet() chose the encoding; test it for symbol. */ symbol = face->charmap && face->charmap->encoding == FT_ENCODING_MS_SYMBOL; if (!FcPatternAddBool (pat, FC_SYMBOL, symbol)) goto bail1; + spacing = FcFreeTypeSpacing (face); #if HAVE_FT_GET_BDF_PROPERTY /* For PCF fonts, override the computed spacing with the one from the property */ @@ -1895,7 +2036,14 @@ FcFreeTypeQueryFace (const FT_Face face if (!symbol) { - ls = FcFreeTypeLangSet (cs, exclusiveLang); + if (ls_share && *ls_share) + ls = FcLangSetCopy (*ls_share); + else + { + ls = FcFreeTypeLangSet (cs, exclusiveLang); + if (ls_share) + *ls_share = FcLangSetCopy (ls); + } if (!ls) goto bail2; } @@ -1920,6 +2068,7 @@ FcFreeTypeQueryFace (const FT_Face face if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) { + int i; for (i = 0; i < face->num_fixed_sizes; i++) if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE, FcGetPixelSize (face, i))) @@ -1965,9 +2114,18 @@ bail0: } FcPattern * +FcFreeTypeQueryFace (const FT_Face face, + const FcChar8 *file, + unsigned int id, + FcBlanks *blanks FC_UNUSED) +{ + return FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL, NULL); +} + +FcPattern * FcFreeTypeQuery(const FcChar8 *file, - int id, - FcBlanks *blanks, + unsigned int id, + FcBlanks *blanks FC_UNUSED, int *count) { FT_Face face; @@ -1977,12 +2135,13 @@ FcFreeTypeQuery(const FcChar8 *file, if (FT_Init_FreeType (&ftLibrary)) return NULL; - if (FT_New_Face (ftLibrary, (char *) file, id, &face)) + if (FT_New_Face (ftLibrary, (char *) file, id & 0x7FFFFFFFF, &face)) goto bail; - *count = face->num_faces; + if (count) + *count = face->num_faces; - pat = FcFreeTypeQueryFace (face, file, id, blanks); + pat = FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL, NULL); FT_Done_Face (face); bail: @@ -1990,138 +2149,135 @@ bail: return pat; } -/* - * For our purposes, this approximation is sufficient - */ -#if !HAVE_FT_GET_NEXT_CHAR -#define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \ - (*(gi) = 0), 0 : \ - (*(gi) = 1), (ucs4) + 1) -#warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer" -#endif +unsigned int +FcFreeTypeQueryAll(const FcChar8 *file, + unsigned int id, + FcBlanks *blanks, + int *count, + FcFontSet *set) +{ + FT_Face face = NULL; + FT_Library ftLibrary = NULL; + FcCharSet *cs = NULL; + FcLangSet *ls = NULL; + FcNameMapping *nm = NULL; + FT_MM_Var *mm_var = NULL; + FcBool index_set = id != (unsigned int) -1; + unsigned int set_face_num = index_set ? id & 0xFFFF : 0; + unsigned int set_instance_num = index_set ? id >> 16 : 0; + unsigned int face_num = set_face_num; + unsigned int instance_num = set_instance_num; + unsigned int num_faces = 0; + unsigned int num_instances = 0; + unsigned int ret = 0; + int err = 0; -static const FT_Encoding fcFontEncodings[] = { - FT_ENCODING_UNICODE, - FT_ENCODING_MS_SYMBOL -}; + if (count) + *count = 0; -#define NUM_DECODE (int) (sizeof (fcFontEncodings) / sizeof (fcFontEncodings[0])) + if (FT_Init_FreeType (&ftLibrary)) + return 0; -#include "../fc-glyphname/fcglyphname.h" + if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face)) + goto bail; -static FcChar32 -FcHashGlyphName (const FcChar8 *name) -{ - FcChar32 h = 0; - FcChar8 c; + num_faces = face->num_faces; + num_instances = face->style_flags >> 16; + if (num_instances && (!index_set || instance_num)) + { + FT_Get_MM_Var (face, &mm_var); + if (!mm_var) + num_instances = 0; + } + + if (count) + *count = num_faces; + + do { + FcPattern *pat = NULL; + + if (instance_num == 0x8000 || instance_num > num_instances) + FT_Set_Var_Design_Coordinates (face, 0, NULL); /* Reset variations. */ + else if (instance_num) + { + FT_Var_Named_Style *instance = &mm_var->namedstyle[instance_num - 1]; + FT_Fixed *coords = instance->coords; + FcBool nonzero; + unsigned int i; + + /* Skip named-instance that coincides with base instance. */ + nonzero = FcFalse; + for (i = 0; i < mm_var->num_axis; i++) + if (coords[i] != mm_var->axis[i].def) + { + nonzero = FcTrue; + break; + } + if (!nonzero) + goto skip; - while ((c = *name++)) - { - h = ((h << 1) | (h >> 31)) ^ c; - } - return h; -} + FT_Set_Var_Design_Coordinates (face, mm_var->num_axis, coords); + } -#if HAVE_FT_HAS_PS_GLYPH_NAMES -/* - * Use Type1 glyph names for fonts which have reliable names - * and which export an Adobe Custom mapping - */ -static FcBool -FcFreeTypeUseNames (FT_Face face) -{ - FT_Int map; + id = ((instance_num << 16) + face_num); + pat = FcFreeTypeQueryFaceInternal (face, (const FcChar8 *) file, id, &cs, &ls, &nm); - if (!FT_Has_PS_Glyph_Names (face)) - return FcFalse; - for (map = 0; map < face->num_charmaps; map++) - if (face->charmaps[map]->encoding == ft_encoding_adobe_custom) - return FcTrue; - return FcFalse; -} + if (pat) + { -static const FcChar8 * -FcUcs4ToGlyphName (FcChar32 ucs4) -{ - int i = (int) (ucs4 % FC_GLYPHNAME_HASH); - int r = 0; - FcGlyphId gn; + ret++; + if (!set || ! FcFontSetAdd (set, pat)) + FcPatternDestroy (pat); + } + else if (instance_num != 0x8000) + err = 1; - while ((gn = _fc_ucs_to_name[i]) != -1) - { - if (_fc_glyph_names[gn].ucs == ucs4) - return _fc_glyph_names[gn].name; - if (!r) +skip: + if (!index_set && instance_num < num_instances) + instance_num++; + else if (!index_set && instance_num == num_instances) + instance_num = 0x8000; /* variable font */ + else { - r = (int) (ucs4 % FC_GLYPHNAME_REHASH); - if (!r) - r = 1; - } - i += r; - if (i >= FC_GLYPHNAME_HASH) - i -= FC_GLYPHNAME_HASH; - } - return 0; -} + free (nm); + nm = NULL; + FcLangSetDestroy (ls); + ls = NULL; + FcCharSetDestroy (cs); + cs = NULL; + FT_Done_Face (face); + face = NULL; -static FcChar32 -FcGlyphNameToUcs4 (FcChar8 *name) -{ - FcChar32 h = FcHashGlyphName (name); - int i = (int) (h % FC_GLYPHNAME_HASH); - int r = 0; - FcGlyphId gn; + face_num++; + instance_num = set_instance_num; - while ((gn = _fc_name_to_ucs[i]) != -1) - { - if (!strcmp ((char *) name, (char *) _fc_glyph_names[gn].name)) - return _fc_glyph_names[gn].ucs; - if (!r) - { - r = (int) (h % FC_GLYPHNAME_REHASH); - if (!r) - r = 1; + if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face)) + break; } - i += r; - if (i >= FC_GLYPHNAME_HASH) - i -= FC_GLYPHNAME_HASH; - } - return 0xffff; -} - -/* - * Work around a bug in some FreeType versions which fail - * to correctly bounds check glyph name buffers and overwrite - * the stack. As Postscript names have a limit of 127 characters, - * this should be sufficient. - */ + } while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces); -#if FC_GLYPHNAME_MAXLEN < 127 -# define FC_GLYPHNAME_BUFLEN 127 +bail: +#ifdef HAVE_FT_DONE_MM_VAR + FT_Done_MM_Var (ftLibrary, mm_var); #else -# define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN + free (mm_var); #endif + FcLangSetDestroy (ls); + FcCharSetDestroy (cs); + if (face) + FT_Done_Face (face); + FT_Done_FreeType (ftLibrary); -/* - * Search through a font for a glyph by name. This is - * currently a linear search as there doesn't appear to be - * any defined order within the font - */ -static FT_UInt -FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name) -{ - FT_UInt gindex; - FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2]; - - for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++) - { - if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0) - if (!strcmp ((char *) name, (char *) name_buf)) - return gindex; - } - return 0; + return ret; } -#endif + + +static const FT_Encoding fcFontEncodings[] = { + FT_ENCODING_UNICODE, + FT_ENCODING_MS_SYMBOL +}; + +#define NUM_DECODE (int) (sizeof (fcFontEncodings) / sizeof (fcFontEncodings[0])) /* * Map a UCS4 glyph to a glyph index. Use all available encoding @@ -2180,38 +2336,23 @@ FcFreeTypeCharIndex (FT_Face face, FcCha return glyphindex; } } -#if HAVE_FT_HAS_PS_GLYPH_NAMES - /* - * Check postscript name table if present - */ - if (FcFreeTypeUseNames (face)) - { - const FcChar8 *name = FcUcs4ToGlyphName (ucs4); - if (name) - { - glyphindex = FcFreeTypeGlyphNameIndex (face, name); - if (glyphindex) - return glyphindex; - } - } -#endif return 0; } -static FcBool -FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, - FT_UInt glyph, FcBlanks *blanks, - FT_Pos *advance, - FcBool using_strike) +static inline int fc_min (int a, int b) { return a <= b ? a : b; } +static inline int fc_max (int a, int b) { return a >= b ? a : b; } +static inline FcBool fc_approximately_equal (int x, int y) +{ return abs (x - y) * 33 <= fc_max (abs (x), abs (y)); } + +static int +FcFreeTypeSpacing (FT_Face face) { FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; - FT_GlyphSlot slot; - - if (using_strike) - load_flags &= ~FT_LOAD_NO_SCALE; + FT_Pos advances[3] = {0}; + unsigned int num_advances = 0; + int o; - /* - * When using scalable fonts, only report those glyphs + /* When using scalable fonts, only report those glyphs * which can be scaled; otherwise those fonts will * only be available at some sizes, and never when * transformed. Avoid this by simply reporting bitmap-only @@ -2220,273 +2361,162 @@ FcFreeTypeCheckGlyph (FT_Face face, FcCh if (face->face_flags & FT_FACE_FLAG_SCALABLE) load_flags |= FT_LOAD_NO_BITMAP; - if (FT_Load_Glyph (face, glyph, load_flags)) - return FcFalse; + if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && + face->num_fixed_sizes > 0 && + FT_Get_Sfnt_Table (face, ft_sfnt_head)) + { + FT_Int strike_index = 0, i; + /* Select the face closest to 16 pixels tall */ + for (i = 1; i < face->num_fixed_sizes; i++) + { + if (abs (face->available_sizes[i].height - 16) < + abs (face->available_sizes[strike_index].height - 16)) + strike_index = i; + } - slot = face->glyph; - if (!glyph) - return FcFalse; + FT_Select_Size (face, strike_index); + } - *advance = slot->metrics.horiAdvance; + for (o = 0; o < NUM_DECODE; o++) + { + FcChar32 ucs4; + FT_UInt glyph; - switch ((int) slot->format) { - case ft_glyph_format_bitmap: - /* - * Bitmaps are assumed to be reasonable; if - * this proves to be a rash assumption, this - * code can be easily modified - */ - return FcTrue; - case ft_glyph_format_outline: - /* - * Glyphs with contours are always OK - */ - if (slot->outline.n_contours != 0) - return FcTrue; - /* - * Glyphs with no contours are only OK if - * they're members of the Blanks set specified - * in the configuration. If blanks isn't set, - * then allow any glyph to be blank - */ - if (!blanks || FcBlanksIsMember (blanks, ucs4)) - return FcTrue; - /* fall through ... */ - default: + if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0) + continue; + + ucs4 = FT_Get_First_Char (face, &glyph); + while (glyph != 0 && num_advances < 3) + { + FT_Pos advance = 0; + if (!FT_Get_Advance (face, glyph, load_flags, &advance) && advance) + { + unsigned int j; + for (j = 0; j < num_advances; j++) + if (fc_approximately_equal (advance, advances[j])) + break; + if (j == num_advances) + advances[num_advances++] = advance; + } + + ucs4 = FT_Get_Next_Char (face, ucs4, &glyph); + } break; } - return FcFalse; -} -#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33) + if (num_advances <= 1) + return FC_MONO; + else if (num_advances == 2 && + fc_approximately_equal (fc_min (advances[0], advances[1]) * 2, + fc_max (advances[0], advances[1]))) + return FC_DUAL; + else + return FC_PROPORTIONAL; +} -static FcCharSet * -FcFreeTypeCharSetAndSpacingForSize (FT_Face face, FcBlanks *blanks, int *spacing, FT_Int strike_index) +FcCharSet * +FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED) { - FcChar32 page, off, ucs4; -#ifdef CHECK - FcChar32 font_max = 0; -#endif + const FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; FcCharSet *fcs; - FcCharLeaf *leaf; int o; - FT_UInt glyph; - FT_Pos advance, advance_one = 0, advance_two = 0; - FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse; - FcBool using_strike = FcFalse; fcs = FcCharSetCreate (); if (!fcs) - goto bail0; - -#if HAVE_FT_SELECT_SIZE - if (strike_index >= 0) { - if (FT_Select_Size (face, strike_index) != FT_Err_Ok) - goto bail1; - using_strike = FcTrue; - } -#endif + goto bail; #ifdef CHECK printf ("Family %s style %s\n", face->family_name, face->style_name); #endif for (o = 0; o < NUM_DECODE; o++) { + FcChar32 page, off, ucs4; + FcCharLeaf *leaf; + FT_UInt glyph; + if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0) continue; - { - page = ~0; - leaf = NULL; - ucs4 = FT_Get_First_Char (face, &glyph); - while (glyph != 0) + page = ~0; + leaf = NULL; + ucs4 = FT_Get_First_Char (face, &glyph); + while (glyph != 0) + { + FcBool good = FcTrue; + + /* CID fonts built by Adobe used to make ASCII control chars to cid1 + * (space glyph). As such, always check contour for those characters. */ + if (ucs4 <= 0x001F) { - if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) - { - if (advance) - { - if (!has_advance) - { - has_advance = FcTrue; - advance_one = advance; - } - else if (!APPROXIMATELY_EQUAL (advance, advance_one)) - { - if (fixed_advance) - { - dual_advance = FcTrue; - fixed_advance = FcFalse; - advance_two = advance; - } - else if (!APPROXIMATELY_EQUAL (advance, advance_two)) - dual_advance = FcFalse; - } - } - - if ((ucs4 >> 8) != page) - { - page = (ucs4 >> 8); - leaf = FcCharSetFindLeafCreate (fcs, ucs4); - if (!leaf) - goto bail1; - } - off = ucs4 & 0xff; - leaf->map[off >> 5] |= (1 << (off & 0x1f)); -#ifdef CHECK - if (ucs4 > font_max) - font_max = ucs4; -#endif - } - ucs4 = FT_Get_Next_Char (face, ucs4, &glyph); + if (FT_Load_Glyph (face, glyph, load_flags) || + (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && + face->glyph->outline.n_contours == 0)) + good = FcFalse; } - if (fcFontEncodings[o] == FT_ENCODING_MS_SYMBOL) + + if (good) { - /* For symbol-encoded OpenType fonts, we duplicate the - * U+F000..F0FF range at U+0000..U+00FF. That's what - * Windows seems to do, and that's hinted about at: - * http://www.microsoft.com/typography/otspec/recom.htm - * under "Non-Standard (Symbol) Fonts". - * - * See thread with subject "Webdings and other MS symbol - * fonts don't display" on mailing list from May 2015. - */ - for (ucs4 = 0xF000; ucs4 < 0xF100; ucs4++) + FcCharSetAddChar (fcs, ucs4); + if ((ucs4 >> 8) != page) { - if (FcCharSetHasChar (fcs, ucs4)) - FcCharSetAddChar (fcs, ucs4 - 0xF000); + page = (ucs4 >> 8); + leaf = FcCharSetFindLeafCreate (fcs, ucs4); + if (!leaf) + goto bail; } + off = ucs4 & 0xff; + leaf->map[off >> 5] |= (1U << (off & 0x1f)); } -#ifdef CHECK - for (ucs4 = 0; ucs4 < 0x10000; ucs4++) - { - FcBool FT_Has, FC_Has; - FT_Has = FT_Get_Char_Index (face, ucs4) != 0; - FC_Has = FcCharSetHasChar (fcs, ucs4); - if (FT_Has != FC_Has) - { - printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has); - } - } -#endif + ucs4 = FT_Get_Next_Char (face, ucs4, &glyph); } - - break; - } -#if HAVE_FT_HAS_PS_GLYPH_NAMES - /* - * Add mapping from PS glyph names if available - */ - if (FcFreeTypeUseNames (face)) - { - FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2]; - - for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++) + if (fcFontEncodings[o] == FT_ENCODING_MS_SYMBOL) { - if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0) + /* For symbol-encoded OpenType fonts, we duplicate the + * U+F000..F0FF range at U+0000..U+00FF. That's what + * Windows seems to do, and that's hinted about at: + * http://www.microsoft.com/typography/otspec/recom.htm + * under "Non-Standard (Symbol) Fonts". + * + * See thread with subject "Webdings and other MS symbol + * fonts don't display" on mailing list from May 2015. + */ + for (ucs4 = 0xF000; ucs4 < 0xF100; ucs4++) { - ucs4 = FcGlyphNameToUcs4 (name_buf); - if (ucs4 != 0xffff && - FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) - { - if (advance) - { - if (!has_advance) - { - has_advance = FcTrue; - advance_one = advance; - } - else if (!APPROXIMATELY_EQUAL (advance, advance_one)) - { - if (fixed_advance) - { - dual_advance = FcTrue; - fixed_advance = FcFalse; - advance_two = advance; - } - else if (!APPROXIMATELY_EQUAL (advance, advance_two)) - dual_advance = FcFalse; - } - } - leaf = FcCharSetFindLeafCreate (fcs, ucs4); - if (!leaf) - goto bail1; - leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f)); -#ifdef CHECK - if (ucs4 > font_max) - font_max = ucs4; -#endif - } + if (FcCharSetHasChar (fcs, ucs4)) + FcCharSetAddChar (fcs, ucs4 - 0xF000); } } - } -#endif #ifdef CHECK - printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs)); - for (ucs4 = 0; ucs4 <= font_max; ucs4++) - { - FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0; - FcBool has_bit = FcCharSetHasChar (fcs, ucs4); - - if (has_char && !has_bit) + for (ucs4 = 0x0020; ucs4 < 0x10000; ucs4++) { - if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance, using_strike)) - printf ("Bitmap missing broken char 0x%x\n", ucs4); - else - printf ("Bitmap missing char 0x%x\n", ucs4); + FcBool FT_Has, FC_Has; + + FT_Has = FT_Get_Char_Index (face, ucs4) != 0; + FC_Has = FcCharSetHasChar (fcs, ucs4); + if (FT_Has != FC_Has) + { + printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has); + } } - else if (!has_char && has_bit) - printf ("Bitmap extra char 0x%x\n", ucs4); - } #endif - if (fixed_advance) - *spacing = FC_MONO; - else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two))) - *spacing = FC_DUAL; - else - *spacing = FC_PROPORTIONAL; + break; + } + return fcs; -bail1: +bail: FcCharSetDestroy (fcs); -bail0: return 0; } FcCharSet * -FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing) +FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing) { - FcCharSet *cs; - - /* - * Check for bitmap-only ttf fonts that are missing the glyf table. - * In that case, pick a size and look for glyphs in that size instead - */ - if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && - face->num_fixed_sizes > 0 && - FT_Get_Sfnt_Table (face, ft_sfnt_head)) - { - FT_Int strike_index = 0; - int i; - /* Select the face closest to 16 pixels tall */ - for (i = 1; i < face->num_fixed_sizes; i++) { - if (abs (face->available_sizes[i].height - 16) < - abs (face->available_sizes[strike_index].height - 16)) - strike_index = i; - } - cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, strike_index); - } - else - cs = FcFreeTypeCharSetAndSpacingForSize (face, blanks, spacing, -1); - return cs; -} - -FcCharSet * -FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks) -{ - int spacing; + if (spacing) + *spacing = FcFreeTypeSpacing (face); - return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing); + return FcFreeTypeCharSet (face, blanks); } @@ -2584,7 +2614,7 @@ GetScriptTags(FT_Face face, FT_ULong tab ftglue_stream_frame_exit( stream ); *stags = malloc(script_count * sizeof (FT_ULong)); - if (!stags) + if (!*stags) return 0; p = 0; Index: xsrc/external/mit/fontconfig/dist/src/fcint.h diff -u xsrc/external/mit/fontconfig/dist/src/fcint.h:1.8 xsrc/external/mit/fontconfig/dist/src/fcint.h:1.9 --- xsrc/external/mit/fontconfig/dist/src/fcint.h:1.8 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/src/fcint.h Fri Mar 8 09:49:07 2019 @@ -101,7 +101,6 @@ extern pfnSHGetFolderPathA pSHGetFolderP #define FC_MIN(a,b) ((a) < (b) ? (a) : (b)) #define FC_MAX(a,b) ((a) > (b) ? (a) : (b)) -#define FC_ABS(a) ((a) < 0 ? -(a) : (a)) /* slim_internal.h */ #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun) @@ -114,13 +113,18 @@ extern pfnSHGetFolderPathA pSHGetFolderP #define FcPrivate #endif -FC_ASSERT_STATIC (sizeof (FcRef) == sizeof (int)); +/* NLS */ +#ifdef ENABLE_NLS +#include <libintl.h> +#define _(x) (dgettext(GETTEXT_PACKAGE, x)) +#else +#define dgettext(d, s) (s) +#define _(x) (x) +#endif + +#define N_(x) x -typedef enum _FcValueBinding { - FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame, - /* to make sure sizeof (FcValueBinding) == 4 even with -fshort-enums */ - FcValueBindingEnd = INT_MAX -} FcValueBinding; +FC_ASSERT_STATIC (sizeof (FcRef) == sizeof (int)); #define FcStrdup(s) ((FcChar8 *) strdup ((const char *) (s))) #define FcFree(s) (free ((FcChar8 *) (s))) @@ -238,7 +242,7 @@ typedef enum _FcOp { } FcOp; typedef enum _FcOpFlags { - FcOpFlagIgnoreBlanks = 1 << 0 + FcOpFlagIgnoreBlanks = 1U << 0 } FcOpFlags; #define FC_OP_GET_OP(_x_) ((_x_) & 0xffff) @@ -310,6 +314,16 @@ 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 { + void *dummy1; + void *dummy2; + void *dummy3; +} FcPtrListIter; + typedef enum _FcRuleType { FcRuleUnknown, FcRuleTest, FcRuleEdit } FcRuleType; @@ -323,10 +337,14 @@ typedef struct _FcRule { } u; } FcRule; -typedef struct _FcSubst { - struct _FcSubst *next; - FcRule *rule; -} FcSubst; +typedef struct _FcRuleSet { + FcRef ref; + FcChar8 *name; + FcChar8 *description; + FcChar8 *domain; + FcBool enabled; + FcPtrList *subst[FcMatchKindEnd]; +} FcRuleSet; typedef struct _FcCharLeaf { FcChar32 map[256/32]; @@ -374,6 +392,13 @@ typedef struct _FcStrBuf { FcChar8 buf_static[16 * sizeof (void *)]; } FcStrBuf; +typedef struct _FcHashTable FcHashTable; + +typedef FcChar32 (* FcHashFunc) (const void *data); +typedef int (* FcCompareFunc) (const void *v1, const void *v2); +typedef FcBool (* FcCopyFunc) (const void *src, void **dest); + + struct _FcCache { unsigned int magic; /* FC_CACHE_MAGIC_MMAP or FC_CACHE_ALLOC */ int version; /* FC_CACHE_VERSION_NUMBER */ @@ -477,12 +502,6 @@ struct _FcAtomic { FcChar8 *tmp; /* tmpfile name (used for locking) */ }; -struct _FcBlanks { - int nblank; - int sblank; - FcChar32 *blanks; -}; - struct _FcConfig { /* * File names loaded from the configuration -- saved here as the @@ -491,11 +510,6 @@ struct _FcConfig { */ FcStrSet *configDirs; /* directories to scan for fonts */ /* - * Set of allowed blank chars -- used to - * trim fonts of bogus glyphs - */ - FcBlanks *blanks; - /* * List of directories containing fonts, * built by recursively scanning the set * of configured directories @@ -514,10 +528,12 @@ struct _FcConfig { * Substitution instructions for patterns and fonts; * maxObjects is used to allocate appropriate intermediate storage * while performing a whole set of substitutions + * + * 0.. substitutions for patterns + * 1.. substitutions for fonts + * 2.. substitutions for scanned fonts */ - FcSubst *substPattern; /* substitutions for patterns */ - FcSubst *substFont; /* substitutions for fonts */ - FcSubst *substScan; /* substitutions for scanned fonts */ + FcPtrList *subst[FcMatchKindEnd]; int maxObjects; /* maximum number of tests in all substs */ /* * List of patterns used to control font file selection @@ -547,6 +563,9 @@ struct _FcConfig { FcExprPage *expr_pool; /* pool of FcExpr's */ FcChar8 *sysRoot; /* override the system root directory */ + FcStrSet *availConfigFiles; /* config files available */ + FcPtrList *rulesetList; /* List of rulesets being installed */ + FcHashTable *uuid_table; /* UUID table for cachedirs */ }; typedef struct _FcFileTime { @@ -574,8 +593,6 @@ struct _FcValuePromotionBuffer { } u; }; -/* fcblanks.c */ - /* fccache.c */ FcPrivate FcCache * @@ -599,9 +616,13 @@ FcCacheObjectReference (void *object); FcPrivate void FcCacheObjectDereference (void *object); +FcPrivate void * +FcCacheAllocate (FcCache *cache, size_t len); + FcPrivate void FcCacheFini (void); + FcPrivate void FcDirCacheReference (FcCache *cache, int nref); @@ -641,10 +662,6 @@ FcConfigAddFontDir (FcConfig *config const FcChar8 *d); FcPrivate FcBool -FcConfigAddDir (FcConfig *config, - const FcChar8 *d); - -FcPrivate FcBool FcConfigAddCacheDir (FcConfig *config, const FcChar8 *d); @@ -694,7 +711,30 @@ FcConfigModifiedTime (FcConfig *config); FcPrivate FcBool FcConfigAddCache (FcConfig *config, FcCache *cache, - FcSetName set, FcStrSet *dirSet); + FcSetName set, FcStrSet *dirSet, FcChar8 *forDir); + +FcPrivate FcRuleSet * +FcRuleSetCreate (const FcChar8 *name); + +FcPrivate void +FcRuleSetDestroy (FcRuleSet *rs); + +FcPrivate void +FcRuleSetReference (FcRuleSet *rs); + +FcPrivate void +FcRuleSetEnable (FcRuleSet *rs, + FcBool flag); + +FcPrivate void +FcRuleSetAddDescription (FcRuleSet *rs, + const FcChar8 *domain, + const FcChar8 *description); + +FcPrivate int +FcRuleSetAdd (FcRuleSet *rs, + FcRule *rule, + FcMatchKind kind); /* fcserialize.c */ FcPrivate intptr_t @@ -781,6 +821,11 @@ FcRandom (void); FcPrivate FcBool FcMakeDirectory (const FcChar8 *dir); +FcPrivate ssize_t +FcReadLink (const FcChar8 *pathname, + FcChar8 *buf, + size_t bufsiz); + /* fcdbg.c */ FcPrivate void @@ -811,7 +856,7 @@ FcPrivate void FcEditPrint (const FcEdit *edit); FcPrivate void -FcSubstPrint (const FcSubst *subst); +FcRulePrint (const FcRule *rule); FcPrivate void FcCharSetPrint (const FcCharSet *c); @@ -847,14 +892,12 @@ FcFileIsFile (const FcChar8 *file); FcPrivate FcBool FcFileScanConfig (FcFontSet *set, FcStrSet *dirs, - FcBlanks *blanks, const FcChar8 *file, FcConfig *config); FcPrivate FcBool FcDirScanConfig (FcFontSet *set, FcStrSet *dirs, - FcBlanks *blanks, const FcChar8 *dir, FcBool force, FcConfig *config); @@ -874,6 +917,42 @@ FcFontSetSerialize (FcSerialize *seriali FcPrivate FcFontSet * FcFontSetDeserialize (const FcFontSet *set); +/* fcplist.c */ +FcPrivate FcPtrList * +FcPtrListCreate (FcDestroyFunc func); + +FcPrivate void +FcPtrListDestroy (FcPtrList *list); + +FcPrivate void +FcPtrListIterInit (const FcPtrList *list, + FcPtrListIter *iter); + +FcPrivate void +FcPtrListIterInitAtLast (FcPtrList *list, + FcPtrListIter *iter); + +FcPrivate FcBool +FcPtrListIterNext (const FcPtrList *list, + FcPtrListIter *iter); + +FcPrivate FcBool +FcPtrListIterIsValid (const FcPtrList *list, + const FcPtrListIter *iter); + +FcPrivate void * +FcPtrListIterGetValue (const FcPtrList *list, + const FcPtrListIter *iter); + +FcPrivate FcBool +FcPtrListIterAdd (FcPtrList *list, + FcPtrListIter *iter, + void *data); + +FcPrivate FcBool +FcPtrListIterRemove (FcPtrList *list, + FcPtrListIter *iter); + /* fcinit.c */ FcPrivate FcConfig * FcInitLoadOwnConfig (FcConfig *config); @@ -914,6 +993,15 @@ FcNameUnparseLangSet (FcStrBuf *buf, con FcPrivate FcChar8 * FcNameUnparseEscaped (FcPattern *pat, FcBool escape); +FcPrivate FcBool +FcConfigParseOnly (FcConfig *config, + const FcChar8 *name, + FcBool complain); + +FcPrivate FcChar8 * +FcConfigRealFilename (FcConfig *config, + const FcChar8 *url); + /* fclist.c */ FcPrivate FcBool @@ -1000,6 +1088,9 @@ FcPrivate FcBool FcPatternObjectAddWeak (FcPattern *p, FcObject object, FcValue value, FcBool append); FcPrivate FcResult +FcPatternObjectGetWithBinding (const FcPattern *p, FcObject object, int id, FcValue *v, FcValueBinding *b); + +FcPrivate FcResult FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v); FcPrivate FcBool @@ -1062,6 +1153,18 @@ FcPatternAppend (FcPattern *p, FcPattern 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 FcPattern * +FcPatternCacheRewriteFile (const FcPattern *pat, FcCache *cache, const FcChar8 *relocated_font_file); + FcPrivate FcChar32 FcStringHash (const FcChar8 *s); @@ -1176,6 +1279,9 @@ FcStrGlobMatch (const FcChar8 *glob, FcPrivate FcBool FcStrUsesHome (const FcChar8 *s); +FcPrivate FcBool +FcStrIsAbsoluteFilename (const FcChar8 *s); + FcPrivate FcChar8 * FcStrBuildFilename (const FcChar8 *path, ...); @@ -1215,4 +1321,46 @@ FcObjectLookupOtherTypeById (FcObject id FcPrivate const FcObjectType * FcObjectLookupOtherTypeByName (const char *str); +/* fchash.c */ +FcPrivate FcBool +FcHashStrCopy (const void *src, + void **dest); + +FcPrivate FcBool +FcHashUuidCopy (const void *src, + void **dest); + +FcPrivate void +FcHashUuidFree (void *data); + +FcPrivate FcHashTable * +FcHashTableCreate (FcHashFunc hash_func, + FcCompareFunc compare_func, + FcCopyFunc key_copy_func, + FcCopyFunc value_copy_func, + FcDestroyFunc key_destroy_func, + FcDestroyFunc value_destroy_func); + +FcPrivate void +FcHashTableDestroy (FcHashTable *table); + +FcPrivate FcBool +FcHashTableFind (FcHashTable *table, + const void *key, + void **value); + +FcPrivate FcBool +FcHashTableAdd (FcHashTable *table, + void *key, + void *value); + +FcPrivate FcBool +FcHashTableReplace (FcHashTable *table, + void *key, + void *value); + +FcPrivate FcBool +FcHashTableRemove (FcHashTable *table, + void *key); + #endif /* _FC_INT_H_ */ Index: xsrc/external/mit/fontconfig/dist/src/fcname.c diff -u xsrc/external/mit/fontconfig/dist/src/fcname.c:1.8 xsrc/external/mit/fontconfig/dist/src/fcname.c:1.9 --- xsrc/external/mit/fontconfig/dist/src/fcname.c:1.8 Tue Aug 29 08:38:50 2017 +++ xsrc/external/mit/fontconfig/dist/src/fcname.c Fri Mar 8 09:49:07 2019 @@ -258,6 +258,11 @@ FcNameBool (const FcChar8 *v, FcBool *re *result = FcFalse; return FcTrue; } + if (c0 == 'd' || c0 == 'x' || c0 == '2') + { + *result = FcDontCare; + return FcTrue; + } if (c0 == 'o') { c1 = v[1]; @@ -272,6 +277,11 @@ FcNameBool (const FcChar8 *v, FcBool *re *result = FcFalse; return FcTrue; } + if (c1 == 'r') + { + *result = FcDontCare; + return FcTrue; + } } return FcFalse; } @@ -318,15 +328,39 @@ FcNameConvert (FcType type, FcChar8 *str v.type = FcTypeVoid; break; case FcTypeRange: - if (sscanf ((char *) string, "[%lg %lg)", &b, &e) != 2) + if (sscanf ((char *) string, "[%lg %lg]", &b, &e) != 2) { - v.u.d = strtod ((char *) string, &p); - if (p != NULL && p[0] != 0) + char *sc, *ec; + size_t len = strlen ((const char *) string); + int si, ei; + + sc = malloc (len + 1); + ec = malloc (len + 1); + if (sc && ec && sscanf ((char *) string, "[%s %[^]]]", sc, ec) == 2) { - v.type = FcTypeVoid; - break; + if (FcNameConstant ((const FcChar8 *) sc, &si) && + FcNameConstant ((const FcChar8 *) ec, &ei)) + v.u.r = FcRangeCreateDouble (si, ei); + else + goto bail1; } - v.type = FcTypeDouble; + else + { + bail1: + v.type = FcTypeDouble; + if (FcNameConstant (string, &si)) + { + v.u.d = (double) si; + } else { + v.u.d = strtod ((char *) string, &p); + if (p != NULL && p[0] != 0) + v.type = FcTypeVoid; + } + } + if (sc) + free (sc); + if (ec) + free (ec); } else v.u.r = FcRangeCreateDouble (b, e); @@ -456,6 +490,10 @@ FcNameParse (const FcChar8 *name) if (!FcPatternAddBool (pat, c->object, c->value)) goto bail2; break; + case FcTypeRange: + if (!FcPatternAddInteger (pat, c->object, c->value)) + goto bail2; + break; default: break; } @@ -514,7 +552,10 @@ FcNameUnparseValue (FcStrBuf *buf, case FcTypeString: return FcNameUnparseString (buf, v.u.s, escape); case FcTypeBool: - return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0); + return FcNameUnparseString (buf, + v.u.b == FcTrue ? (FcChar8 *) "True" : + v.u.b == FcFalse ? (FcChar8 *) "False" : + (FcChar8 *) "DontCare", 0); case FcTypeMatrix: sprintf ((char *) temp, "%g %g %g %g", v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy); @@ -526,7 +567,7 @@ FcNameUnparseValue (FcStrBuf *buf, case FcTypeFTFace: return FcTrue; case FcTypeRange: - sprintf ((char *) temp, "[%g %g)", v.u.r->begin, v.u.r->end); + sprintf ((char *) temp, "[%g %g]", v.u.r->begin, v.u.r->end); return FcNameUnparseString (buf, temp, 0); } return FcFalse; Index: xsrc/external/mit/fontconfig/dist/src/fcstat.c diff -u xsrc/external/mit/fontconfig/dist/src/fcstat.c:1.8 xsrc/external/mit/fontconfig/dist/src/fcstat.c:1.9 --- xsrc/external/mit/fontconfig/dist/src/fcstat.c:1.8 Sun Jan 28 16:43:32 2018 +++ xsrc/external/mit/fontconfig/dist/src/fcstat.c Fri Mar 8 09:49:07 2019 @@ -217,17 +217,23 @@ FcScandir (const char *dirp, { size_t dentlen = FcPtrToOffset (dent, dent->d_name) + strlen (dent->d_name) + 1; dentlen = ((dentlen + ALIGNOF_VOID_P - 1) & ~(ALIGNOF_VOID_P - 1)); - p = malloc (dentlen); - if (!p) - goto out; + p = (struct dirent *) malloc (dentlen); + if (!p) + { + free_dirent (dlist); + closedir (d); + errno = ENOMEM; + + return -1; + } memcpy (p, dent, dentlen); if ((n + 1) >= lsize) { lsize += 128; - dlp = realloc (dlist, sizeof (struct dirent *) * lsize); + dlp = (struct dirent **) realloc (dlist, sizeof (struct dirent *) * lsize); if (!dlp) { -out: + free (p); free_dirent (dlist); closedir (d); errno = ENOMEM; Index: xsrc/external/mit/fontconfig/dist/src/fcmatch.c diff -u xsrc/external/mit/fontconfig/dist/src/fcmatch.c:1.10 xsrc/external/mit/fontconfig/dist/src/fcmatch.c:1.11 --- xsrc/external/mit/fontconfig/dist/src/fcmatch.c:1.10 Sun Jan 28 16:44:15 2018 +++ xsrc/external/mit/fontconfig/dist/src/fcmatch.c Fri Mar 8 09:49:07 2019 @@ -27,7 +27,7 @@ static double -FcCompareNumber (FcValue *value1, FcValue *value2) +FcCompareNumber (const FcValue *value1, const FcValue *value2, FcValue *bestValue) { double v1, v2, v; @@ -54,23 +54,27 @@ FcCompareNumber (FcValue *value1, FcValu v = v2 - v1; if (v < 0) v = -v; + *bestValue = FcValueCanonicalize (value2); return v; } static double -FcCompareString (FcValue *v1, FcValue *v2) +FcCompareString (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { + *bestValue = FcValueCanonicalize (v2); return (double) FcStrCmpIgnoreCase (FcValueString(v1), FcValueString(v2)) != 0; } static double -FcCompareFamily (FcValue *v1, FcValue *v2) +FcCompareFamily (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { /* rely on the guarantee in FcPatternObjectAddWithBinding that * families are always FcTypeString. */ const FcChar8* v1_string = FcValueString(v1); const FcChar8* v2_string = FcValueString(v2); + *bestValue = FcValueCanonicalize (v2); + if (FcToLower(*v1_string) != FcToLower(*v2_string) && *v1_string != ' ' && *v2_string != ' ') return 1.0; @@ -79,13 +83,15 @@ FcCompareFamily (FcValue *v1, FcValue *v } static double -FcComparePostScript (FcValue *v1, FcValue *v2) +FcComparePostScript (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { const FcChar8 *v1_string = FcValueString (v1); const FcChar8 *v2_string = FcValueString (v2); int n; size_t len; + *bestValue = FcValueCanonicalize (v2); + if (FcToLower (*v1_string) != FcToLower (*v2_string) && *v1_string != ' ' && *v2_string != ' ') return 1.0; @@ -97,7 +103,7 @@ FcComparePostScript (FcValue *v1, FcValu } static double -FcCompareLang (FcValue *v1, FcValue *v2) +FcCompareLang (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { FcLangResult result; FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2); @@ -132,6 +138,7 @@ FcCompareLang (FcValue *v1, FcValue *v2) default: return -1.0; } + *bestValue = FcValueCanonicalize (v2); switch (result) { case FcLangEqual: return 0; @@ -144,99 +151,133 @@ FcCompareLang (FcValue *v1, FcValue *v2) } static double -FcCompareBool (FcValue *v1, FcValue *v2) +FcCompareBool (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { if (v2->type != FcTypeBool || v1->type != FcTypeBool) return -1.0; - return (double) v2->u.b != v1->u.b; + + if (v2->u.b != FcDontCare) + *bestValue = FcValueCanonicalize (v2); + else + *bestValue = FcValueCanonicalize (v1); + + return (double) ((v2->u.b ^ v1->u.b) == 1); } static double -FcCompareCharSet (FcValue *v1, FcValue *v2) +FcCompareCharSet (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { + *bestValue = FcValueCanonicalize (v2); /* TODO Improve. */ return (double) FcCharSetSubtractCount (FcValueCharSet(v1), FcValueCharSet(v2)); } static double -FcCompareSize (FcValue *value1, FcValue *value2) +FcCompareRange (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { - double v1, v2, v; + FcValue value1 = FcValueCanonicalize (v1); + FcValue value2 = FcValueCanonicalize (v2); + double b1, e1, b2, e2, d; - switch ((int) value1->type) { + switch ((int) value1.type) { case FcTypeInteger: - v1 = value1->u.i; + b1 = e1 = value1.u.i; break; case FcTypeDouble: - v1 = value1->u.d; + b1 = e1 = value1.u.d; + break; + case FcTypeRange: + b1 = value1.u.r->begin; + e1 = value1.u.r->end; break; default: return -1; } - switch ((int) value2->type) { + switch ((int) value2.type) { case FcTypeInteger: - v2 = value2->u.i; + b2 = e2 = value2.u.i; break; case FcTypeDouble: - v2 = value2->u.d; + b2 = e2 = value2.u.d; + break; + case FcTypeRange: + b2 = value2.u.r->begin; + e2 = value2.u.r->end; break; default: return -1; } - if (v2 == 0) - return 0; - v = v2 - v1; - if (v < 0) - v = -v; - return v; + + if (e1 < b2) + d = b2; + else if (e2 < b1) + d = e2; + else + d = (FC_MAX (b1, b2) + FC_MIN (e1, e2)) * .5; + + bestValue->type = FcTypeDouble; + bestValue->u.d = d; + + /* If the ranges overlap, it's a match, otherwise return closest distance. */ + if (e1 < b2 || e2 < b1) + return FC_MIN (fabs (b2 - e1), fabs (b1 - e2)); + else + return 0.0; } static double -FcCompareSizeRange (FcValue *v1, FcValue *v2) +FcCompareSize (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { FcValue value1 = FcValueCanonicalize (v1); FcValue value2 = FcValueCanonicalize (v2); - FcRange *r1 = NULL, *r2 = NULL; - double ret = -1.0; + double b1, e1, b2, e2; switch ((int) value1.type) { + case FcTypeInteger: + b1 = e1 = value1.u.i; + break; case FcTypeDouble: - r1 = FcRangeCreateDouble (value1.u.d, value1.u.d); + b1 = e1 = value1.u.d; break; case FcTypeRange: - r1 = FcRangeCopy (value1.u.r); + abort(); + b1 = value1.u.r->begin; + e1 = value1.u.r->end; break; default: - goto bail; + return -1; } switch ((int) value2.type) { + case FcTypeInteger: + b2 = e2 = value2.u.i; + break; case FcTypeDouble: - r2 = FcRangeCreateDouble (value2.u.d, value2.u.d); + b2 = e2 = value2.u.d; break; case FcTypeRange: - r2 = FcRangeCopy (value2.u.r); + b2 = value2.u.r->begin; + e2 = value2.u.r->end; break; default: - goto bail; + return -1; } - if (FcRangeIsInRange (r1, r2)) - ret = 0.0; - else - ret = FC_MIN (fabs (r1->end - r2->begin), fabs (r1->begin - r2->end)); - -bail: - if (r1) - FcRangeDestroy (r1); - if (r2) - FcRangeDestroy (r2); + bestValue->type = FcTypeDouble; + bestValue->u.d = (b1 + e1) * .5; - return ret; + /* If the ranges overlap, it's a match, otherwise return closest distance. */ + if (e1 < b2 || e2 < b1) + return FC_MIN (fabs (b2 - e1), fabs (b1 - e2)); + if (b2 != e2 && b1 == e2) /* Semi-closed interval. */ + return 1e-15; + else + return 0.0; } static double -FcCompareFilename (FcValue *v1, FcValue *v2) +FcCompareFilename (const FcValue *v1, const FcValue *v2, FcValue *bestValue) { const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2); + *bestValue = FcValueCanonicalize (v2); if (FcStrCmp (s1, s2) == 0) return 0.0; else if (FcStrCmpIgnoreCase (s1, s2) == 0) @@ -257,13 +298,13 @@ FcCompareFilename (FcValue *v1, FcValue #define PRI_FcCompareFamily(n) PRI1(n) #define PRI_FcCompareString(n) PRI1(n) #define PRI_FcCompareNumber(n) PRI1(n) -#define PRI_FcCompareSize(n) PRI1(n) #define PRI_FcCompareBool(n) PRI1(n) #define PRI_FcCompareFilename(n) PRI1(n) #define PRI_FcCompareCharSet(n) PRI1(n) #define PRI_FcCompareLang(n) PRI1(n) #define PRI_FcComparePostScript(n) PRI1(n) -#define PRI_FcCompareSizeRange(n) PRI1(n) +#define PRI_FcCompareRange(n) PRI1(n) +#define PRI_FcCompareSize(n) PRI1(n) #define FC_OBJECT(NAME, Type, Cmp) PRI_##Cmp(NAME) @@ -285,6 +326,7 @@ typedef enum _FcMatcherPriorityDummy { typedef enum _FcMatcherPriority { PRI1(FILE), PRI1(FONTFORMAT), + PRI1(VARIABLE), PRI1(SCALABLE), PRI1(COLOR), PRI1(FOUNDRY), @@ -314,7 +356,7 @@ typedef enum _FcMatcherPriority { typedef struct _FcMatcher { FcObject object; - double (*compare) (FcValue *value1, FcValue *value2); + double (*compare) (const FcValue *v1, const FcValue *v2, FcValue *bestValue); int strong, weak; } FcMatcher; @@ -384,7 +426,8 @@ FcCompareValueList (FcObject object { for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext(v2), k++) { - v = (match->compare) (&v1->value, &v2->value); + FcValue matchValue; + v = (match->compare) (&v1->value, &v2->value, &matchValue); if (v < 0) { *result = FcResultTypeMismatch; @@ -394,7 +437,7 @@ FcCompareValueList (FcObject object if (v < best) { if (bestValue) - *bestValue = FcValueCanonicalize(&v2->value); + *bestValue = matchValue; best = v; pos = k; } @@ -490,10 +533,17 @@ FcFontRenderPrepare (FcConfig *confi FcPatternElt *fe, *pe; FcValue v; FcResult result; + FcBool variable = FcFalse; + FcStrBuf variations; assert (pat != NULL); assert (font != NULL); + FcPatternObjectGetBool (font, FC_VARIABLE_OBJECT, 0, &variable); + assert (variable != FcDontCare); + if (variable) + FcStrBufInit (&variations, NULL, 0); + new = FcPatternCreate (); if (!new) return NULL; @@ -598,6 +648,39 @@ FcFontRenderPrepare (FcConfig *confi return NULL; } FcPatternObjectAdd (new, fe->object, v, FcFalse); + + /* Set font-variations settings for standard axes in variable fonts. */ + if (variable && + FcPatternEltValues(fe)->value.type == FcTypeRange && + (fe->object == FC_WEIGHT_OBJECT || + fe->object == FC_WIDTH_OBJECT || + fe->object == FC_SIZE_OBJECT)) + { + double num; + FcChar8 temp[128]; + const char *tag = " "; + assert (v.type == FcTypeDouble); + num = v.u.d; + if (variations.len) + FcStrBufChar (&variations, ','); + switch (fe->object) + { + case FC_WEIGHT_OBJECT: + tag = "wght"; + num = FcWeightToOpenType (num); + break; + + case FC_WIDTH_OBJECT: + tag = "wdth"; + break; + + case FC_SIZE_OBJECT: + tag = "opsz"; + break; + } + sprintf ((char *) temp, "%4s=%g", tag, num); + FcStrBufString (&variations, temp); + } } else { @@ -621,6 +704,20 @@ FcFontRenderPrepare (FcConfig *confi } } + if (variable && variations.len) + { + FcChar8 *vars = NULL; + if (FcPatternObjectGetString (new, FC_FONT_VARIATIONS_OBJECT, 0, &vars) == FcResultMatch) + { + FcStrBufChar (&variations, ','); + FcStrBufString (&variations, vars); + FcPatternObjectDel (new, FC_FONT_VARIATIONS_OBJECT); + } + + FcPatternObjectAddString (new, FC_FONT_VARIATIONS_OBJECT, FcStrBufDoneStatic (&variations)); + FcStrBufDestroy (&variations); + } + FcConfigSubstituteWithPat (config, new, pat, FcMatchFont); return new; } @@ -718,25 +815,21 @@ FcFontSetMatchInternal (FcFontSet **se if (!(p = strchr (s, ','))) { f = FcFalse; - len = strlen (s) + 1; + len = strlen (s); } else { - len = (p - s) + 1; + len = (p - s); } - x = malloc (sizeof (char) * len); - if (x == NULL) + x = malloc (sizeof (char) * (len + 1)); + if (x) { - fprintf (stderr, "Fontconfig Error: %s\n", - strerror (errno)); - exit (1); + strcpy (x, s); + if (FcObjectFromName (x) > 0) + FcObjectSetAdd (os, x); + s = p + 1; + free (x); } - strncpy (x, s, len - 1); - x[len - 1] = 0; - if (FcObjectFromName (x) > 0) - FcObjectSetAdd (os, x); - s = p + 1; - free (x); } free (ss); } @@ -1031,7 +1124,8 @@ FcFontSetSort (FcConfig *config FC_U FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch && FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch) { - double compare = FcCompareLang (&patternLang, &nodeLang); + FcValue matchValue; + double compare = FcCompareLang (&patternLang, &nodeLang, &matchValue); if (compare >= 0 && compare < 2) { if (FcDebug () & FC_DBG_MATCHV) Added files: Index: xsrc/external/mit/fontconfig/dist/src/fchash.c diff -u /dev/null xsrc/external/mit/fontconfig/dist/src/fchash.c:1.5 --- /dev/null Fri Mar 8 09:49:08 2019 +++ xsrc/external/mit/fontconfig/dist/src/fchash.c Fri Mar 8 09:49:07 2019 @@ -0,0 +1,249 @@ +/* + * Copyright © 2000 Keith Packard + * + * 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 "fcint.h" +#if !defined TOOL_FCCACHE +#ifndef _WIN32 +#include <uuid/uuid.h> +#endif +#endif + +#define FC_HASH_SIZE 227 + +typedef struct _FcHashBucket { + struct _FcHashBucket *next; + void *key; + void *value; +} FcHashBucket; + +struct _FcHashTable { + FcHashBucket *buckets[FC_HASH_SIZE]; + FcHashFunc hash_func; + FcCompareFunc compare_func; + FcCopyFunc key_copy_func; + FcCopyFunc value_copy_func; + FcDestroyFunc key_destroy_func; + FcDestroyFunc value_destroy_func; +}; + + +FcBool +FcHashStrCopy (const void *src, + void **dest) +{ + *dest = FcStrdup (src); + + return *dest != NULL; +} + +FcBool +FcHashUuidCopy (const void *src, + void **dest) +{ +#if !defined TOOL_FCCACHE +#ifndef _WIN32 + *dest = malloc (sizeof (uuid_t)); + uuid_copy (*dest, src); +#endif +#endif + return FcTrue; +} + +void +FcHashUuidFree (void *data) +{ + free (data); +} + +FcHashTable * +FcHashTableCreate (FcHashFunc hash_func, + FcCompareFunc compare_func, + FcCopyFunc key_copy_func, + FcCopyFunc value_copy_func, + FcDestroyFunc key_destroy_func, + FcDestroyFunc value_destroy_func) +{ + FcHashTable *ret = malloc (sizeof (FcHashTable)); + + if (ret) + { + memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE); + ret->hash_func = hash_func; + ret->compare_func = compare_func; + ret->key_copy_func = key_copy_func; + ret->value_copy_func = value_copy_func; + ret->key_destroy_func = key_destroy_func; + ret->value_destroy_func = value_destroy_func; + } + return ret; +} + +void +FcHashTableDestroy (FcHashTable *table) +{ + int i; + + for (i = 0; i < FC_HASH_SIZE; i++) + { + FcHashBucket *bucket = table->buckets[i], *prev; + + while (bucket) + { + if (table->key_destroy_func) + table->key_destroy_func (bucket->key); + if (table->value_destroy_func) + table->value_destroy_func (bucket->value); + prev = bucket; + bucket = bucket->next; + free (prev); + } + table->buckets[i] = NULL; + } + free (table); +} + +FcBool +FcHashTableFind (FcHashTable *table, + const void *key, + void **value) +{ + FcHashBucket *bucket; + FcChar32 hash = table->hash_func (key); + + for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next) + { + if (!table->compare_func(bucket->key, key)) + { + if (table->value_copy_func) + { + if (!table->value_copy_func (bucket->value, value)) + return FcFalse; + } + else + *value = bucket->value; + return FcTrue; + } + } + return FcFalse; +} + +static FcBool +FcHashTableAddInternal (FcHashTable *table, + void *key, + void *value, + FcBool replace) +{ + FcHashBucket **prev, *bucket, *b; + FcChar32 hash = table->hash_func (key); + FcBool ret = FcFalse; + + bucket = (FcHashBucket *) malloc (sizeof (FcHashBucket)); + if (!bucket) + return FcFalse; + memset (bucket, 0, sizeof (FcHashBucket)); + if (table->key_copy_func) + ret |= !table->key_copy_func (key, &bucket->key); + else + bucket->key = key; + if (table->value_copy_func) + ret |= !table->value_copy_func (value, &bucket->value); + else + bucket->value = value; + if (ret) + { + destroy: + if (bucket->key && table->key_destroy_func) + table->key_destroy_func (bucket->key); + if (bucket->value && table->value_destroy_func) + table->value_destroy_func (bucket->value); + free (bucket); + + return !ret; + } + retry: + for (prev = &table->buckets[hash % FC_HASH_SIZE]; + (b = fc_atomic_ptr_get (prev)); prev = &(b->next)) + { + if (!table->compare_func (b->key, key)) + { + if (replace) + { + bucket->next = b->next; + if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) + goto retry; + bucket = b; + } + else + ret = FcTrue; + goto destroy; + } + } + bucket->next = NULL; + if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) + goto retry; + + return FcTrue; +} + +FcBool +FcHashTableAdd (FcHashTable *table, + void *key, + void *value) +{ + return FcHashTableAddInternal (table, key, value, FcFalse); +} + +FcBool +FcHashTableReplace (FcHashTable *table, + void *key, + void *value) +{ + return FcHashTableAddInternal (table, key, value, FcTrue); +} + +FcBool +FcHashTableRemove (FcHashTable *table, + void *key) +{ + FcHashBucket **prev, *bucket; + FcChar32 hash = table->hash_func (key); + FcBool ret = FcFalse; + +retry: + for (prev = &table->buckets[hash % FC_HASH_SIZE]; + (bucket = fc_atomic_ptr_get (prev)); prev = &(bucket->next)) + { + if (!table->compare_func (bucket->key, key)) + { + if (!fc_atomic_ptr_cmpexch (prev, bucket, bucket->next)) + goto retry; + if (table->key_destroy_func) + table->key_destroy_func (bucket->key); + if (table->value_destroy_func) + table->value_destroy_func (bucket->value); + free (bucket); + ret = FcTrue; + break; + } + } + + return ret; +}