Merge branch 'varfonts2'

https://lists.freedesktop.org/archives/fontconfig/2017-September/006048.html
diff --git a/conf.d/90-synthetic.conf b/conf.d/90-synthetic.conf
index b8d1e85..7cd25cf 100644
--- a/conf.d/90-synthetic.conf
+++ b/conf.d/90-synthetic.conf
@@ -40,11 +40,11 @@
 	<match target="font">
 		<!-- check to see if the font is just regular -->
 		<test name="weight" compare="less_eq">
-			<const>medium</const>
+			<const>regular</const>
 		</test>
 		<!-- check to see if the pattern requests bold -->
-		<test target="pattern" name="weight" compare="more">
-			<const>medium</const>
+		<test target="pattern" name="weight" compare="more_eq">
+			<const>bold</const>
 		</test>
 		<!--
 		  set the embolden flag
diff --git a/fc-list/fc-list.c b/fc-list/fc-list.c
index f6c7282..95963e7 100644
--- a/fc-list/fc-list.c
+++ b/fc-list/fc-list.c
@@ -49,6 +49,7 @@
 #include <getopt.h>
 const struct option longopts[] = {
     {"verbose", 0, 0, 'v'},
+    {"brief", 0, 0, 'b'},
     {"format", 1, 0, 'f'},
     {"quiet", 0, 0, 'q'},
     {"version", 0, 0, 'V'},
@@ -67,22 +68,24 @@
 {
     FILE *file = error ? stderr : stdout;
 #if HAVE_GETOPT_LONG
-    fprintf (file, "usage: %s [-vqVh] [-f FORMAT] [--verbose] [--format=FORMAT] [--quiet] [--version] [--help] [pattern] {element ...} \n",
+    fprintf (file, "usage: %s [-vbqVh] [-f FORMAT] [--verbose] [--brief] [--format=FORMAT] [--quiet] [--version] [--help] [pattern] {element ...} \n",
 	     program);
 #else
-    fprintf (file, "usage: %s [-vqVh] [-f FORMAT] [pattern] {element ...} \n",
+    fprintf (file, "usage: %s [-vbqVh] [-f FORMAT] [pattern] {element ...} \n",
 	     program);
 #endif
     fprintf (file, "List fonts matching [pattern]\n");
     fprintf (file, "\n");
 #if HAVE_GETOPT_LONG
     fprintf (file, "  -v, --verbose        display entire font pattern verbosely\n");
+    fprintf (file, "  -b, --brief          display entire font pattern briefly\n");
     fprintf (file, "  -f, --format=FORMAT  use the given output format\n");
     fprintf (file, "  -q, --quiet          suppress all normal output, exit 1 if no fonts matched\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, "  -v         (verbose) display entire font pattern verbosely\n");
+    fprintf (file, "  -b         (brief)   display entire font pattern briefly\n");
     fprintf (file, "  -f FORMAT  (format)  use the given output format\n");
     fprintf (file, "  -q,        (quiet)   suppress all normal output, exit 1 if no fonts matched\n");
     fprintf (file, "  -V         (version) display font config version and exit\n");
@@ -95,6 +98,7 @@
 main (int argc, char **argv)
 {
     int			verbose = 0;
+    int			brief = 0;
     int			quiet = 0;
     const FcChar8	*format = NULL;
     int			nfont = 0;
@@ -106,15 +110,18 @@
     int			c;
 
 #if HAVE_GETOPT_LONG
-    while ((c = getopt_long (argc, argv, "vf:qVh", longopts, NULL)) != -1)
+    while ((c = getopt_long (argc, argv, "vbf:qVh", longopts, NULL)) != -1)
 #else
-    while ((c = getopt (argc, argv, "vf:qVh")) != -1)
+    while ((c = getopt (argc, argv, "vbf:qVh")) != -1)
 #endif
     {
 	switch (c) {
 	case 'v':
 	    verbose = 1;
 	    break;
+	case 'b':
+	    brief = 1;
+	    break;
 	case 'f':
 	    format = (FcChar8 *) strdup (optarg);
 	    break;
@@ -155,7 +162,7 @@
 	pat = FcPatternCreate ();
     if (quiet && !os)
 	os = FcObjectSetCreate ();
-    if (!verbose && !format && !os)
+    if (!verbose && !brief && !format && !os)
 	os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_FILE, (char *) 0);
     if (!format)
         format = (const FcChar8 *) "%{=fclist}\n";
@@ -171,8 +178,13 @@
 
 	for (j = 0; j < fs->nfont; j++)
 	{
-	    if (verbose)
+	    if (verbose || brief)
 	    {
+		if (brief)
+		{
+		    FcPatternDel (fs->fonts[j], FC_CHARSET);
+		    FcPatternDel (fs->fonts[j], FC_LANG);
+		}
 		FcPatternPrint (fs->fonts[j]);
 	    }
 	    else
diff --git a/fc-match/fc-match.c b/fc-match/fc-match.c
index f96c009..88f4ac8 100644
--- a/fc-match/fc-match.c
+++ b/fc-match/fc-match.c
@@ -52,6 +52,7 @@
     {"sort", 0, 0, 's'},
     {"all", 0, 0, 'a'},
     {"verbose", 0, 0, 'v'},
+    {"brief", 0, 0, 'b'},
     {"format", 1, 0, 'f'},
     {"version", 0, 0, 'V'},
     {"help", 0, 0, 'h'},
@@ -69,7 +70,7 @@
 {
     FILE *file = error ? stderr : stdout;
 #if HAVE_GETOPT_LONG
-    fprintf (file, "usage: %s [-savVh] [-f FORMAT] [--sort] [--all] [--verbose] [--format=FORMAT] [--version] [--help] [pattern] {element...}\n",
+    fprintf (file, "usage: %s [-savbVh] [-f FORMAT] [--sort] [--all] [--verbose] [--brief] [--format=FORMAT] [--version] [--help] [pattern] {element...}\n",
 	     program);
 #else
     fprintf (file, "usage: %s [-savVh] [-f FORMAT] [pattern] {element...}\n",
@@ -81,6 +82,7 @@
     fprintf (file, "  -s, --sort           display sorted list of matches\n");
     fprintf (file, "  -a, --all            display unpruned sorted list of matches\n");
     fprintf (file, "  -v, --verbose        display entire font pattern verbosely\n");
+    fprintf (file, "  -b, --brief          display entire font pattern briefly\n");
     fprintf (file, "  -f, --format=FORMAT  use the given output format\n");
     fprintf (file, "  -V, --version        display font config version and exit\n");
     fprintf (file, "  -h, --help           display this help and exit\n");
@@ -88,6 +90,7 @@
     fprintf (file, "  -s,        (sort)    display sorted list of matches\n");
     fprintf (file, "  -a         (all)     display unpruned sorted list of matches\n");
     fprintf (file, "  -v         (verbose) display entire font pattern verbosely\n");
+    fprintf (file, "  -b         (brief)   display entire font pattern briefly\n");
     fprintf (file, "  -f FORMAT  (format)  use the given output format\n");
     fprintf (file, "  -V         (version) display font config version and exit\n");
     fprintf (file, "  -h         (help)    display this help and exit\n");
@@ -99,6 +102,7 @@
 main (int argc, char **argv)
 {
     int			verbose = 0;
+    int			brief = 0;
     int			sort = 0, all = 0;
     const FcChar8	*format = NULL;
     int			i;
@@ -110,9 +114,9 @@
     int			c;
 
 #if HAVE_GETOPT_LONG
-    while ((c = getopt_long (argc, argv, "asvf:Vh", longopts, NULL)) != -1)
+    while ((c = getopt_long (argc, argv, "asvbf:Vh", longopts, NULL)) != -1)
 #else
-    while ((c = getopt (argc, argv, "asvf:Vh")) != -1)
+    while ((c = getopt (argc, argv, "asvbf:Vh")) != -1)
 #endif
     {
 	switch (c) {
@@ -125,6 +129,9 @@
 	case 'v':
 	    verbose = 1;
 	    break;
+	case 'b':
+	    brief = 1;
+	    break;
 	case 'f':
 	    format = (FcChar8 *) strdup (optarg);
 	    break;
@@ -218,8 +225,13 @@
 
 	    font = FcPatternFilter (fs->fonts[j], os);
 
-	    if (verbose)
+	    if (verbose || brief)
 	    {
+		if (brief)
+		{
+		    FcPatternDel (font, FC_CHARSET);
+		    FcPatternDel (font, FC_LANG);
+		}
 		FcPatternPrint (font);
 	    }
 	    else
diff --git a/fc-query/fc-query.c b/fc-query/fc-query.c
index a5b2cda..8a96da0 100644
--- a/fc-query/fc-query.c
+++ b/fc-query/fc-query.c
@@ -52,8 +52,8 @@
 #define _GNU_SOURCE
 #include <getopt.h>
 static const struct option longopts[] = {
-    {"ignore-blanks", 0, 0, 'b'},
     {"index", 1, 0, 'i'},
+    {"brief", 0, 0, 'b'},
     {"format", 1, 0, 'f'},
     {"version", 0, 0, 'V'},
     {"help", 0, 0, 'h'},
@@ -71,23 +71,23 @@
 {
     FILE *file = error ? stderr : stdout;
 #if HAVE_GETOPT_LONG
-    fprintf (file, "usage: %s [-Vbh] [-i index] [-f FORMAT] [--ignore-blanks] [--index index] [--format FORMAT] [--version] [--help] font-file...\n",
+    fprintf (file, "usage: %s [-bVh] [-i index] [-f FORMAT] [--index index] [--brief] [--format FORMAT] [--version] [--help] font-file...\n",
 	     program);
 #else
-    fprintf (file, "usage: %s [-Vbh] [-i index] [-f FORMAT] font-file...\n",
+    fprintf (file, "usage: %s [-bVh] [-i index] [-f FORMAT] font-file...\n",
 	     program);
 #endif
     fprintf (file, "Query font files and print resulting pattern(s)\n");
     fprintf (file, "\n");
 #if HAVE_GETOPT_LONG
-    fprintf (file, "  -b, --ignore-blanks  ignore blanks to compute langauges\n");
     fprintf (file, "  -i, --index INDEX    display the INDEX face of each font file only\n");
+    fprintf (file, "  -b, --brief          display font pattern briefly\n");
     fprintf (file, "  -f, --format=FORMAT  use the given output format\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, "  -b         (ignore-blanks) ignore blanks to compute languages\n");
     fprintf (file, "  -i INDEX   (index)         display the INDEX face of each font file only\n");
+    fprintf (file, "  -b         (brief)         display font pattern briefly\n");
     fprintf (file, "  -f FORMAT  (format)        use the given output format\n");
     fprintf (file, "  -V         (version)       display font config version and exit\n");
     fprintf (file, "  -h         (help)          display this help and exit\n");
@@ -98,28 +98,27 @@
 int
 main (int argc, char **argv)
 {
-    int		id = -1;
-    int		ignore_blanks = 0;
+    unsigned int id = (unsigned int) -1;
+    int         brief = 0;
     FcFontSet   *fs;
     FcChar8     *format = NULL;
-    FcBlanks    *blanks = NULL;
     int		err = 0;
     int		i;
 #if HAVE_GETOPT_LONG || HAVE_GETOPT
     int		c;
 
 #if HAVE_GETOPT_LONG
-    while ((c = getopt_long (argc, argv, "bi:f:Vh", longopts, NULL)) != -1)
+    while ((c = getopt_long (argc, argv, "i:bf:Vh", longopts, NULL)) != -1)
 #else
-    while ((c = getopt (argc, argv, "bi:f:Vh")) != -1)
+    while ((c = getopt (argc, argv, "i:bf:Vh")) != -1)
 #endif
     {
 	switch (c) {
-	case 'b':
-	    ignore_blanks = 1;
-	    break;
 	case 'i':
-	    id = atoi (optarg);
+	    id = (unsigned int) strtol (optarg, NULL, 0); /* strtol() To handle -1. */
+	    break;
+	case 'b':
+	    brief = 1;
 	    break;
 	case 'f':
 	    format = (FcChar8 *) strdup (optarg);
@@ -143,14 +142,12 @@
 	usage (argv[0], 1);
 
     fs = FcFontSetCreate ();
-    if (!ignore_blanks)
-	blanks = FcConfigGetBlanks (NULL);
 
     for (; i < argc; i++)
     {
-	if (!FcFreeTypeQueryAll ((FcChar8*) argv[i], id, blanks, NULL, fs))
+	if (!FcFreeTypeQueryAll ((FcChar8*) argv[i], id, NULL, NULL, fs))
 	{
-	    fprintf (stderr, "Can't query face %d of font file %s\n", id, argv[i]);
+	    fprintf (stderr, "Can't query face %u of font file %s\n", id, argv[i]);
 	    err = 1;
 	}
     }
@@ -159,6 +156,12 @@
     {
 	FcPattern *pat = fs->fonts[i];
 
+	if (brief)
+	{
+	    FcPatternDel (pat, FC_CHARSET);
+	    FcPatternDel (pat, FC_LANG);
+	}
+
 	if (format)
 	{
 	    FcChar8 *s;
diff --git a/fc-scan/fc-scan.c b/fc-scan/fc-scan.c
index 58a0b15..41bd260 100644
--- a/fc-scan/fc-scan.c
+++ b/fc-scan/fc-scan.c
@@ -52,6 +52,7 @@
 #define _GNU_SOURCE
 #include <getopt.h>
 static const struct option longopts[] = {
+    {"brief", 0, 0, 'b'},
     {"format", 1, 0, 'f'},
     {"version", 0, 0, 'V'},
     {"help", 0, 0, 'h'},
@@ -69,19 +70,21 @@
 {
     FILE *file = error ? stderr : stdout;
 #if HAVE_GETOPT_LONG
-    fprintf (file, "usage: %s [-Vh] [-f FORMAT] [--format FORMAT] [--version] [--help] font-file...\n",
+    fprintf (file, "usage: %s [-bVh] [-f FORMAT] [--brief] [--format FORMAT] [--version] [--help] font-file...\n",
 	     program);
 #else
-    fprintf (file, "usage: %s [-Vh] [-f FORMAT] font-file...\n",
+    fprintf (file, "usage: %s [-bVh] [-f FORMAT] font-file...\n",
 	     program);
 #endif
     fprintf (file, "Scan font files and directories, and print resulting pattern(s)\n");
     fprintf (file, "\n");
 #if HAVE_GETOPT_LONG
+    fprintf (file, "  -b, --brief          display font pattern briefly\n");
     fprintf (file, "  -f, --format=FORMAT  use the given output format\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, "  -b         (brief)         display font pattern briefly\n");
     fprintf (file, "  -f FORMAT  (format)        use the given output format\n");
     fprintf (file, "  -V         (version)       display font config version and exit\n");
     fprintf (file, "  -h         (help)          display this help and exit\n");
@@ -92,6 +95,7 @@
 int
 main (int argc, char **argv)
 {
+    int         brief = 0;
     FcChar8     *format = NULL;
     int		i;
     FcFontSet   *fs;
@@ -105,6 +109,9 @@
 #endif
     {
 	switch (c) {
+	case 'b':
+	    brief = 1;
+	    break;
 	case 'f':
 	    format = (FcChar8 *) strdup (optarg);
 	    break;
@@ -152,6 +159,12 @@
     {
 	FcPattern *pat = fs->fonts[i];
 
+	if (brief)
+	{
+	    FcPatternDel (pat, FC_CHARSET);
+	    FcPatternDel (pat, FC_LANG);
+	}
+
 	if (format)
 	{
 	    FcChar8 *s;
diff --git a/fontconfig/fcfreetype.h b/fontconfig/fcfreetype.h
index 753fdf9..20b1128 100644
--- a/fontconfig/fcfreetype.h
+++ b/fontconfig/fcfreetype.h
@@ -51,7 +51,7 @@
 FcPublic FcPattern *
 FcFreeTypeQueryFace (const FT_Face  face,
 		     const FcChar8  *file,
-		     int	    id,
+		     unsigned int   id,
 		     FcBlanks	    *blanks);
 
 _FCFUNCPROTOEND
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
index f085aa0..0f4dcb9 100644
--- a/fontconfig/fontconfig.h
+++ b/fontconfig/fontconfig.h
@@ -72,8 +72,9 @@
 #define _FC_STRINGIFY(s)    	_FC_STRINGIFY_(s)
 #define FC_CACHE_VERSION    	_FC_STRINGIFY(FC_CACHE_VERSION_NUMBER)
 
-#define FcTrue		1
 #define FcFalse		0
+#define FcTrue		1
+#define FcDontCare	2
 
 #define FC_FAMILY	    "family"		/* String */
 #define FC_STYLE	    "style"		/* String */
@@ -99,6 +100,7 @@
 #define FC_OUTLINE	    "outline"		/* Bool */
 #define FC_SCALABLE	    "scalable"		/* Bool */
 #define FC_COLOR	    "color"		/* Bool */
+#define FC_VARIABLE	    "variable"		/* Bool */
 #define FC_SCALE	    "scale"		/* double (deprecated) */
 #define FC_SYMBOL	    "symbol"		/* Bool */
 #define FC_DPI		    "dpi"		/* double */
@@ -119,6 +121,7 @@
 #define FC_DECORATIVE	    "decorative"	/* Bool - true if style is a decorative variant */
 #define FC_LCD_FILTER	    "lcdfilter"		/* Int */
 #define FC_FONT_FEATURES    "fontfeatures"	/* String */
+#define FC_FONT_VARIATIONS  "fontvariations"	/* String */
 #define FC_NAMELANG	    "namelang"		/* String RFC 3866 langs */
 #define FC_PRGNAME	    "prgname"		/* String */
 #define FC_HASH		    "hash"		/* String (deprecated) */
@@ -575,10 +578,10 @@
 
 /* fcfreetype.c */
 FcPublic FcPattern *
-FcFreeTypeQuery (const FcChar8 *file, int id, FcBlanks *blanks, int *count);
+FcFreeTypeQuery (const FcChar8 *file, unsigned int id, FcBlanks *blanks, int *count);
 
 FcPublic unsigned int
-FcFreeTypeQueryAll(const FcChar8 *file, int id, FcBlanks *blanks, int *count, FcFontSet *set);
+FcFreeTypeQueryAll(const FcChar8 *file, unsigned int id, FcBlanks *blanks, int *count, FcFontSet *set);
 
 /* fcfs.c */
 
diff --git a/src/fccfg.c b/src/fccfg.c
index 4f38af1..4b22d48 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -796,14 +796,30 @@
 	case FcTypeBool:
 	    switch ((int) op) {
 	    case FcOpEqual:
-	    case FcOpContains:
-	    case FcOpListing:
 		ret = left.u.b == right.u.b;
 		break;
+	    case FcOpContains:
+	    case FcOpListing:
+		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;
 	    }
diff --git a/src/fcdbg.c b/src/fcdbg.c
index c2853ff..29ff44a 100644
--- a/src/fcdbg.c
+++ b/src/fcdbg.c
@@ -46,7 +46,10 @@
 	fprintf (f, "\"%s\"", v.u.s);
 	break;
     case FcTypeBool:
-	fprintf (f, "%s", v.u.b ? "True" : "False");
+	fprintf (f,
+		 v.u.b == FcTrue  ? (FcChar8 *) "True" :
+		 v.u.b == FcFalse ? (FcChar8 *) "False" :
+				    (FcChar8 *) "DontCare", 0);
 	break;
     case FcTypeMatrix:
 	fprintf (f, "[%g %g; %g %g]", v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
@@ -62,7 +65,7 @@
 	fprintf (f, "face");
 	break;
     case FcTypeRange:
-	fprintf (f, "[%g %g)", v.u.r->begin, v.u.r->end);
+	fprintf (f, "[%g %g]", v.u.r->begin, v.u.r->end);
 	break;
     }
 }
diff --git a/src/fcdefault.c b/src/fcdefault.c
index 5afd7ec..35973d7 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -39,6 +39,7 @@
     { FC_EMBEDDED_BITMAP_OBJECT,   FcTrue 	},  /* !FC_LOAD_NO_BITMAP */
     { FC_DECORATIVE_OBJECT,	   FcFalse	},
     { FC_SYMBOL_OBJECT,		   FcFalse	},
+    { FC_VARIABLE_OBJECT,	   FcFalse	},
 };
 
 #define NUM_FC_BOOL_DEFAULTS	(int) (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
@@ -255,7 +256,14 @@
 	    FcPatternObjectAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
 
     if (FcPatternObjectGetDouble (pattern, FC_SIZE_OBJECT, 0, &size) != FcResultMatch)
-	size = 12.0L;
+    {
+	FcRange *r;
+	double b, e;
+	if (FcPatternObjectGetRange (pattern, FC_SIZE_OBJECT, 0, &r) == FcResultMatch && FcRangeGetDouble (r, &b, &e))
+	    size = (b + e) * .5;
+	else
+	    size = 12.0L;
+    }
     if (FcPatternObjectGetDouble (pattern, FC_SCALE_OBJECT, 0, &scale) != FcResultMatch)
 	scale = 1.0;
     if (FcPatternObjectGetDouble (pattern, FC_DPI_OBJECT, 0, &dpi) != FcResultMatch)
diff --git a/src/fcfreetype.c b/src/fcfreetype.c
index a6e7058..cddd3a1 100644
--- a/src/fcfreetype.c
+++ b/src/fcfreetype.c
@@ -558,6 +558,9 @@
 static FcChar8 *
 FcFontCapabilities(FT_Face face);
 
+static int
+FcFreeTypeSpacing (FT_Face face);
+
 #define NUM_FC_MAC_ROMAN_FAKE	(int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
 
 
@@ -1133,6 +1136,7 @@
     TT_PLATFORM_MICROSOFT,
     TT_PLATFORM_APPLE_UNICODE,
     TT_PLATFORM_MACINTOSH,
+    TT_PLATFORM_ISO,
 };
 #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
 
@@ -1154,19 +1158,51 @@
 };
 
 #define NUM_NAMEID_ORDER  (sizeof (nameid_order) / sizeof (nameid_order[0]))
-FcPattern *
-FcFreeTypeQueryFace (const FT_Face  face,
-		     const FcChar8  *file,
-		     int	    id,
-		     FcBlanks	    *blanks FC_UNUSED)
+
+static FcBool
+FcFreeTypeGetName (const FT_Face face,
+		   unsigned int  platform,
+		   unsigned int  nameid,
+		   FT_SfntName   *sname)
+{
+    int min = 0, max = (int) FT_Get_Sfnt_Name_Count (face) - 1;
+
+    while (min <= max)
+    {
+	int mid = (min + max) / 2;
+
+	if (FT_Get_Sfnt_Name (face, mid, sname) != 0)
+	    return FcFalse;
+
+	if (platform < sname->platform_id || (platform == sname->platform_id && nameid < sname->name_id))
+	    max = mid - 1;
+	else if (platform > sname->platform_id || (platform == sname->platform_id && nameid > sname->name_id))
+	    min = mid + 1;
+	else
+	    return FcTrue;
+    }
+
+    return FcFalse;
+}
+
+static FcPattern *
+FcFreeTypeQueryFaceInternal (const FT_Face  face,
+			     const FcChar8  *file,
+			     unsigned int   id,
+			     FcCharSet      **cs_share,
+			     FcLangSet      **ls_share)
 {
     FcPattern	    *pat;
     int		    slant = -1;
     int		    weight = -1;
     int		    width = -1;
     FcBool	    decorative = FcFalse;
-    FcCharSet	    *cs;
-    FcLangSet	    *ls;
+    FcBool	    variable = FcFalse;
+    FcBool	    variable_weight = FcFalse;
+    FcBool	    variable_width = FcFalse;
+    FcBool	    variable_size = FcFalse;
+    FcCharSet       *cs;
+    FcLangSet       *ls;
 #if 0
     FcChar8	    *family = 0;
 #endif
@@ -1189,8 +1225,6 @@
 #endif
     TT_Header	    *head;
     const FcChar8   *exclusiveLang = 0;
-    FT_SfntName	    sname;
-    FT_UInt    	    snamei, snamec;
 
     int		    nfamily = 0;
     int		    nfamily_lang = 0;
@@ -1199,14 +1233,9 @@
     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;
 
@@ -1238,35 +1267,101 @@
 
     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) (1 << 16);
+	      double def_value = master->axis[i].def / (double) (1 << 16);
+	      double max_value = master->axis[i].maximum / (double) (1 << 16);
+	      const char *elt = NULL;
 
-	      case FT_MAKE_TAG ('w','d','t','h'):
-		width_mult = mult;
-		break;
+	      if (min_value > def_value || def_value > max_value || min_value == max_value)
+		  continue;
 
-	      /* TODO optical size! */
+	      switch (master->axis[i].tag)
+	      {
+		case FT_MAKE_TAG ('w','g','h','t'):
+		  elt = FC_WEIGHT;
+		  min_value = FcWeightFromOpenType (min_value);
+		  max_value = FcWeightFromOpenType (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;
+	      }
+	  }
+
+	  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];
+
+	  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 = 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
@@ -1299,13 +1394,9 @@
      * 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++)
+    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
@@ -1313,159 +1404,142 @@
 	 */
 	for (n = 0; n < NUM_NAMEID_ORDER; n++)
 	{
-	    nameid = nameid_order[n];
+	    FT_SfntName sname;
+	    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++)
+	    nameid = lookupid = nameid_order[n];
+
+	    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;
+
+		if (nameid == TT_NAME_ID_FONT_SUBFAMILY)
+		    lookupid = instance->strid;
+	    }
+
+	    if (!FcFreeTypeGetName (face, platform, lookupid, &sname))
+		continue;
+
+	    switch (nameid) {
+#ifdef TT_NAME_ID_WWS_FAMILY
+	    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)",
+			    sname.name_id, sname.platform_id,
+			    sname.encoding_id, sname.language_id);
+
+		elt = FC_FAMILY;
+		eltlang = FC_FAMILYLANG;
+		np = &nfamily;
+		nlangp = &nfamily_lang;
+		break;
+	    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)",
+			    sname.name_id, sname.platform_id,
+			    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 (variable)
+		    break;
+		if (FcDebug () & FC_DBG_SCANV)
+		    printf ("found style  (n %2d p %d e %d l 0x%04x) ",
+			    sname.name_id, sname.platform_id,
+			    sname.encoding_id, sname.language_id);
+
+		elt = FC_STYLE;
+		eltlang = FC_STYLELANG;
+		np = &nstyle;
+		nlangp = &nstyle_lang;
+		break;
+	    case TT_NAME_ID_TRADEMARK:
+	    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;
-		const FcChar8	*lang;
-		const char	*elt = 0, *eltlang = 0;
-		int		*np = 0, *nlangp = 0;
-		size_t		len;
 
-		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)
-		    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 (FcDebug () & FC_DBG_SCANV)
+		    printf ("%s\n", utf8);
+
 		if (!utf8)
 		    continue;
 
-		switch (sname.name_id) {
-#ifdef TT_NAME_ID_WWS_FAMILY
-		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",
-				sname.name_id, sname.platform_id,
-				sname.encoding_id, sname.language_id,
-				utf8);
+		/* 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;
 
-		    elt = FC_FAMILY;
-		    eltlang = FC_FAMILYLANG;
-		    np = &nfamily;
-		    nlangp = &nfamily_lang;
-		    break;
-		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",
-				sname.name_id, sname.platform_id,
-				sname.encoding_id, sname.language_id,
-				utf8);
-
-		    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 (FcDebug () & FC_DBG_SCANV)
-			printf ("found style  (n %2d p %d e %d l 0x%04x) %s\n",
-				sname.name_id, sname.platform_id,
-				sname.encoding_id, sname.language_id,
-				utf8);
-
-		    elt = FC_STYLE;
-		    eltlang = FC_STYLELANG;
-		    np = &nstyle;
-		    nlangp = &nstyle_lang;
-		    break;
-		case TT_NAME_ID_TRADEMARK:
-		case TT_NAME_ID_MANUFACTURER:
-		    /* If the foundry wasn't found in the OS/2 table, look here */
-		    if(!foundry)
-			foundry = FcNoticeFoundry((FT_String *) utf8);
-		    break;
-		}
-		if (elt)
+		if (FcStringInPatternElement (pat, elt, utf8))
 		{
-		    if (FcStringInPatternElement (pat, elt, utf8))
-		    {
-			free (utf8);
-			continue;
-		    }
-
-		    /* add new element */
-		    if (!FcPatternAddString (pat, elt, utf8))
-		    {
-			free (utf8);
-			goto bail1;
-		    }
 		    free (utf8);
-		    if (lang)
+		    continue;
+		}
+
+		/* add new element */
+		if (!FcPatternAddString (pat, elt, utf8))
+		{
+		    free (utf8);
+		    goto bail1;
+		}
+		free (utf8);
+		if (lang)
+		{
+		    /* pad lang list with 'und' to line up with elt */
+		    while (*nlangp < *np)
 		    {
-			/* pad lang list with 'und' to line up with elt */
-			while (*nlangp < *np)
-			{
-			    if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "und"))
-				goto bail1;
-			    ++*nlangp;
-			}
-			if (!FcPatternAddString (pat, eltlang, lang))
+			if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "und"))
 			    goto bail1;
 			++*nlangp;
 		    }
-		    ++*np;
+		    if (!FcPatternAddString (pat, eltlang, lang))
+			goto bail1;
+		    ++*nlangp;
 		}
-		else
-		    free (utf8);
+		++*np;
 	    }
 	}
     }
@@ -1482,11 +1556,12 @@
 	++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"))
@@ -1523,52 +1598,57 @@
     }
 
     /* Add the PostScript name into the cache */
-    tmp = FT_Get_Postscript_Name (face);
-    if (!tmp)
+    if (!variable)
     {
-	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)
+	char	    psname[256];
+	const char	    *tmp;
+	tmp = FT_Get_Postscript_Name (face);
+	if (!tmp)
 	{
-	    if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0)
-		break;
-	    n++;
-	    familylang = NULL;
-	}
-	if (!familylang)
-	    n = 0;
+	    unsigned int i;
+	    FcChar8 *family, *familylang = NULL;
+	    size_t len;
+	    int n = 0;
 
-	if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch)
+	    /* 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 (strchr(exclusive_chars, family[i]) != NULL)
+		    psname[i] = '-';
+		else
+		    psname[i] = family[i];
+	    }
+	    psname[i] = 0;
+	}
+	else
+	{
+	    strncpy (psname, tmp, 255);
+	    psname[255] = 0;
+	}
+	if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname))
 	    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];
-	}
-	psname[i] = 0;
     }
-    else
-    {
-	strncpy (psname, tmp, 255);
-	psname[255] = 0;
-    }
-    if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname))
-	goto bail1;
 
     if (file && *file && !FcPatternAddString (pat, FC_FILE, file))
 	goto bail1;
@@ -1679,21 +1759,30 @@
     }
 
 #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)
 	{
-	    FcRangeDestroy (r);
-	    goto bail1;
+	    if (!FcPatternAddDouble (pat, FC_SIZE, lower_size))
+		goto bail1;
 	}
-	FcRangeDestroy (r);
+	else
+	{
+	    r = FcRangeCreateDouble (lower_size, upper_size);
+	    if (!FcPatternAddRange (pat, FC_SIZE, r))
+	    {
+		FcRangeDestroy (r);
+		goto bail1;
+	    }
+	    FcRangeDestroy (r);
+	}
     }
 #endif
 
@@ -1835,10 +1924,10 @@
     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
 	goto bail1;
 
-    if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
+    if (!variable_weight && !FcPatternAddInteger (pat, FC_WEIGHT, weight))
 	goto bail1;
 
-    if (!FcPatternAddInteger (pat, FC_WIDTH, width))
+    if (!variable_width && !FcPatternAddInteger (pat, FC_WIDTH, width))
 	goto bail1;
 
     if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
@@ -1851,15 +1940,23 @@
     /*
      * 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 */
@@ -1894,7 +1991,14 @@
 
     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;
     }
@@ -1965,9 +2069,18 @@
 }
 
 FcPattern *
+FcFreeTypeQueryFace (const FT_Face  face,
+		     const FcChar8  *file,
+		     unsigned int   id,
+		     FcBlanks	    *blanks FC_UNUSED)
+{
+    return FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL);
+}
+
+FcPattern *
 FcFreeTypeQuery(const FcChar8	*file,
-		int		id,
-		FcBlanks	*blanks,
+		unsigned int	id,
+		FcBlanks	*blanks FC_UNUSED,
 		int		*count)
 {
     FT_Face	    face;
@@ -1977,13 +2090,13 @@
     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;
 
     if (count)
       *count = face->num_faces;
 
-    pat = FcFreeTypeQueryFace (face, file, id, blanks);
+    pat = FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL);
 
     FT_Done_Face (face);
 bail:
@@ -1993,59 +2106,112 @@
 
 unsigned int
 FcFreeTypeQueryAll(const FcChar8	*file,
-		   int			id,
+		   unsigned int		id,
 		   FcBlanks		*blanks,
 		   int			*count,
 		   FcFontSet            *set)
 {
-    FT_Face face;
+    FT_Face face = NULL;
     FT_Library ftLibrary = NULL;
-    int index_set = id != -1;
-    int set_face_num = index_set ? id & 0xFFFF : 0;
-    int set_instance_num = index_set ? id >> 16 : 0;
-    int face_num = set_face_num;
-    int instance_num = set_instance_num;
-    int num_faces = 0;
-    int num_instances = 0;
+    FcCharSet *cs = NULL;
+    FcLangSet *ls = 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;
+    int err = 0;
+
+    if (count)
+	*count = 0;
 
     if (FT_Init_FreeType (&ftLibrary))
 	return 0;
 
-    do {
-	FcPattern *pat;
+    if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
+	goto bail;
 
-	id = ((instance_num << 16) + face_num);
-	if (FT_New_Face (ftLibrary, (const char *) file, id, &face))
-	  break;
-
-	num_faces = face->num_faces;
-	num_instances = face->style_flags >> 16;
-	pat = FcFreeTypeQueryFace (face, (const FcChar8 *) file, id, blanks);
-	FT_Done_Face (face);
-
-	if (pat)
-	{
-	    ret++;
-	    if (!set || ! FcFontSetAdd (set, pat))
-	      FcPatternDestroy (pat);
-	}
-	else
-	    err = 1;
-
-	if (instance_num < num_instances && !set_instance_num)
-	    instance_num++;
-	else
-	{
-	    face_num++;
-	    instance_num = 0;
-	}
-    } while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces);
+    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);
+	assert (mm_var);
+    }
 
     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;
+
+	    FT_Set_Var_Design_Coordinates (face, mm_var->num_axis, coords);
+	}
+
+	id = ((instance_num << 16) + face_num);
+	pat = FcFreeTypeQueryFaceInternal (face, (const FcChar8 *) file, id, &cs, &ls);
+
+	if (pat)
+	{
+
+	    ret++;
+	    if (!set || ! FcFontSetAdd (set, pat))
+		FcPatternDestroy (pat);
+	}
+	else if (instance_num != 0x8000)
+	    err = 1;
+
+skip:
+	if (!index_set && instance_num < num_instances)
+	    instance_num++;
+	else if (!index_set && instance_num == num_instances)
+	    instance_num = 0x8000; /* variable font */
+	else
+	{
+	    FcLangSetDestroy (ls);
+	    ls = NULL;
+	    FcCharSetDestroy (cs);
+	    cs = NULL;
+	    FT_Done_Face (face);
+	    face = NULL;
+
+	    face_num++;
+	    instance_num = set_instance_num;
+
+	    if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
+	      break;
+	}
+    } while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces);
+
+bail:
+    FcLangSetDestroy (ls);
+    FcCharSetDestroy (cs);
+    if (face)
+	FT_Done_Face (face);
     FT_Done_FreeType (ftLibrary);
 
     return ret;
@@ -2134,18 +2300,13 @@
 static inline FcBool fc_approximately_equal (int x, int y)
 { return abs (x - y) * 33 <= fc_max (abs (x), abs (y)); }
 
-FcCharSet *
-FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing)
+static int
+FcFreeTypeSpacing (FT_Face face)
 {
-    FcCharSet	    *fcs;
-    int		    o;
     FT_Int	    load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
-    FT_Pos	    advances[3];
+    FT_Pos	    advances[3] = {};
     unsigned int    num_advances = 0;
-
-    fcs = FcCharSetCreate ();
-    if (!fcs)
-	goto bail0;
+    int		    o;
 
     /* When using scalable fonts, only report those glyphs
      * which can be scaled; otherwise those fonts will
@@ -2170,18 +2331,65 @@
 		strike_index = i;
 	}
 
-	if (FT_Select_Size (face, strike_index) != FT_Err_Ok)
-	    goto bail1;
+	FT_Select_Size (face, strike_index);
     }
 #endif
 
+    for (o = 0; o < NUM_DECODE; o++)
+    {
+	FcChar32        ucs4;
+	FT_UInt	 	glyph;
+
+	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;
+    }
+
+    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;
+}
+
+FcCharSet *
+FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED)
+{
+    const FT_Int    load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+    FcCharSet	    *fcs;
+    int		    o;
+
+    fcs = FcCharSetCreate ();
+    if (!fcs)
+	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;
+	FcChar32        page, off, ucs4;
+	FcCharLeaf      *leaf;
 	FT_UInt	 	glyph;
 
 	if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
@@ -2206,26 +2414,13 @@
 
 	    if (good)
 	    {
-		if (num_advances < 3)
-		{
-		    FT_Pos advance = 0;
-		    if (!FT_Get_Advance (face, glyph, load_flags, &advance) && advance)
-		    {
-			unsigned int i;
-			for (i = 0; i < num_advances; i++)
-			  if (fc_approximately_equal (advance, advances[i]))
-			    break;
-			if (i == num_advances)
-			  advances[num_advances++] = advance;
-		    }
-		}
-
+		FcCharSetAddChar (fcs, ucs4);
 		if ((ucs4 >> 8) != page)
 		{
 		    page = (ucs4 >> 8);
 		    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
 		    if (!leaf)
-			goto bail1;
+			goto bail;
 		}
 		off = ucs4 & 0xff;
 		leaf->map[off >> 5] |= (1 << (off & 0x1f));
@@ -2265,27 +2460,21 @@
 #endif
 	break;
     }
-    if (num_advances <= 1)
-	*spacing = FC_MONO;
-    else if (num_advances == 2 &&
-	     fc_approximately_equal (fc_min (advances[0], advances[1]) * 2,
-				     fc_max (advances[0], advances[1])))
-        *spacing = FC_DUAL;
-    else
-	*spacing = FC_PROPORTIONAL;
+
     return fcs;
-bail1:
+bail:
     FcCharSetDestroy (fcs);
-bail0:
     return 0;
 }
 
 FcCharSet *
-FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED)
+FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing)
 {
-    int spacing;
 
-    return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
+    if (spacing)
+	*spacing = FcFreeTypeSpacing (face);
+
+    return FcFreeTypeCharSet (face, blanks);
 }
 
 
diff --git a/src/fclang.c b/src/fclang.c
index 107addb..eadf34b 100644
--- a/src/fclang.c
+++ b/src/fclang.c
@@ -485,6 +485,9 @@
 void
 FcLangSetDestroy (FcLangSet *ls)
 {
+    if (!ls)
+	return;
+
     if (ls->extra)
 	FcStrSetDestroy (ls->extra);
     free (ls);
@@ -495,6 +498,9 @@
 {
     FcLangSet	*new;
 
+    if (!ls)
+	return NULL;
+
     new = FcLangSetCreate ();
     if (!new)
 	goto bail0;
diff --git a/src/fcmatch.c b/src/fcmatch.c
index 40efbd3..d5eaea7 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -25,7 +25,7 @@
 #include "fcint.h"
 
 static double
-FcCompareNumber (FcValue *value1, FcValue *value2)
+FcCompareNumber (const FcValue *value1, const FcValue *value2, FcValue *bestValue)
 {
     double  v1, v2, v;
 
@@ -52,23 +52,27 @@
     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;
@@ -77,13 +81,15 @@
 }
 
 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;
@@ -95,7 +101,7 @@
 }
 
 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);
@@ -130,6 +136,7 @@
     default:
 	return -1.0;
     }
+    *bestValue = FcValueCanonicalize (v2);
     switch (result) {
     case FcLangEqual:
 	return 0;
@@ -142,99 +149,134 @@
 }
 
 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)
-{
-    double  v1, v2, v;
-
-    switch ((int) value1->type) {
-    case FcTypeInteger:
-	v1 = value1->u.i;
-	break;
-    case FcTypeDouble:
-	v1 = value1->u.d;
-	break;
-    default:
-	return -1;
-    }
-    switch ((int) value2->type) {
-    case FcTypeInteger:
-	v2 = value2->u.i;
-	break;
-    case FcTypeDouble:
-	v2 = value2->u.d;
-	break;
-    default:
-	return -1;
-    }
-    if (v2 == 0)
-	return 0;
-    v = v2 - v1;
-    if (v < 0)
-	v = -v;
-    return v;
-}
-
-static double
-FcCompareSizeRange (FcValue *v1, FcValue *v2)
+FcCompareRange (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, d;
 
     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;
+    if (e1 < b2)
+      d = b2;
+    else if (e2 < b1)
+      d = e2;
     else
-	ret = FC_MIN (fabs (r1->end - r2->begin), fabs (r1->begin - r2->end));
+      d = (FC_MAX (b1, b2) + FC_MIN (e1, e2)) * .5;
 
-bail:
-    if (r1)
-	FcRangeDestroy (r1);
-    if (r2)
-	FcRangeDestroy (r2);
+    bestValue->type = FcTypeDouble;
+    bestValue->u.d = d;
 
-    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));
+    else
+	return 0.0;
 }
 
 static double
-FcCompareFilename (FcValue *v1, FcValue *v2)
+FcCompareSize (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
+{
+    FcValue value1 = FcValueCanonicalize (v1);
+    FcValue value2 = FcValueCanonicalize (v2);
+    double b1, e1, b2, e2;
+
+    switch ((int) value1.type) {
+    case FcTypeInteger:
+        b1 = e1 = value1.u.i;
+	break;
+    case FcTypeDouble:
+        b1 = e1 = value1.u.d;
+	break;
+    case FcTypeRange:
+	abort();
+	b1 = value1.u.r->begin;
+	e1 = value1.u.r->end;
+	break;
+    default:
+	return -1;
+    }
+    switch ((int) value2.type) {
+    case FcTypeInteger:
+        b2 = e2 = value2.u.i;
+	break;
+    case FcTypeDouble:
+        b2 = e2 = value2.u.d;
+	break;
+    case FcTypeRange:
+	b2 = value2.u.r->begin;
+	e2 = value2.u.r->end;
+	break;
+    default:
+	return -1;
+    }
+
+    bestValue->type = FcTypeDouble;
+    bestValue->u.d = (b1 + e1) * .5;
+
+    /* 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 (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)
@@ -255,13 +297,13 @@
 #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)
 
@@ -283,6 +325,7 @@
 typedef enum _FcMatcherPriority {
     PRI1(FILE),
     PRI1(FONTFORMAT),
+    PRI1(VARIABLE),
     PRI1(SCALABLE),
     PRI1(COLOR),
     PRI1(FOUNDRY),
@@ -312,7 +355,7 @@
 
 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;
 
@@ -382,7 +425,8 @@
     {
 	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;
@@ -392,7 +436,7 @@
 	    if (v < best)
 	    {
 		if (bestValue)
-		    *bestValue = FcValueCanonicalize(&v2->value);
+		    *bestValue = matchValue;
 		best = v;
 		pos = k;
 	    }
@@ -1017,7 +1061,8 @@
 		    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)
diff --git a/src/fcname.c b/src/fcname.c
index 8be36c7..79e413e 100644
--- a/src/fcname.c
+++ b/src/fcname.c
@@ -258,6 +258,11 @@
 	*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 @@
 	    *result = FcFalse;
 	    return FcTrue;
 	}
+	if (c1 == 'r')
+	{
+	    *result = FcDontCare;
+	    return FcTrue;
+	}
     }
     return FcFalse;
 }
@@ -318,7 +328,7 @@
 	    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)
@@ -514,7 +524,10 @@
     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 +539,7 @@
     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;
diff --git a/src/fcobjs.h b/src/fcobjs.h
index d27864b..e3926cc 100644
--- a/src/fcobjs.h
+++ b/src/fcobjs.h
@@ -29,11 +29,11 @@
 FC_OBJECT (FULLNAME,		FcTypeString,	NULL)
 FC_OBJECT (FULLNAMELANG,	FcTypeString,	NULL)
 FC_OBJECT (SLANT,		FcTypeInteger,	FcCompareNumber)
-FC_OBJECT (WEIGHT,		FcTypeInteger,	FcCompareNumber)
-FC_OBJECT (WIDTH,		FcTypeInteger,	FcCompareNumber)
-FC_OBJECT (SIZE,		FcTypeRange,	FcCompareSizeRange)
+FC_OBJECT (WEIGHT,		FcTypeRange,	FcCompareRange)
+FC_OBJECT (WIDTH,		FcTypeRange,	FcCompareRange)
+FC_OBJECT (SIZE,		FcTypeRange,	FcCompareSize)
 FC_OBJECT (ASPECT,		FcTypeDouble,	NULL)
-FC_OBJECT (PIXEL_SIZE,		FcTypeDouble,	FcCompareSize)
+FC_OBJECT (PIXEL_SIZE,		FcTypeDouble,	FcCompareNumber)
 FC_OBJECT (SPACING,		FcTypeInteger,	FcCompareNumber)
 FC_OBJECT (FOUNDRY,		FcTypeString,	FcCompareString)
 FC_OBJECT (ANTIALIAS,		FcTypeBool,	FcCompareBool)
@@ -70,4 +70,6 @@
 FC_OBJECT (POSTSCRIPT_NAME,	FcTypeString,	FcComparePostScript)
 FC_OBJECT (COLOR,		FcTypeBool,	FcCompareBool)
 FC_OBJECT (SYMBOL,		FcTypeBool,	FcCompareBool)
+FC_OBJECT (FONT_VARIATIONS,	FcTypeString,	NULL)
+FC_OBJECT (VARIABLE,		FcTypeBool,	FcCompareBool)
 /* ^-------------- Add new objects here. */
diff --git a/src/fcpat.c b/src/fcpat.c
index cc303c6..dd1307d 100644
--- a/src/fcpat.c
+++ b/src/fcpat.c
@@ -1113,6 +1113,9 @@
     int		    i;
     FcValueListPtr  l;
 
+    if (!orig)
+	return NULL;
+
     new = FcPatternCreate ();
     if (!new)
 	goto bail0;
diff --git a/src/fcrange.c b/src/fcrange.c
index f70226c..8689930 100644
--- a/src/fcrange.c
+++ b/src/fcrange.c
@@ -96,9 +96,6 @@
 FcBool
 FcRangeIsInRange (const FcRange *a, const FcRange *b)
 {
-    if (!a || !b)
-	return FcFalse;
-
     return a->begin >= b->begin && a->end <= b->end;
 }
 
@@ -107,20 +104,22 @@
 {
     switch ((int) op) {
     case FcOpEqual:
+	return a->begin == b->begin && a->end == b->end;
     case FcOpContains:
     case FcOpListing:
 	return FcRangeIsInRange (a, b);
     case FcOpNotEqual:
+	return a->begin != b->begin || a->end != b->end;
     case FcOpNotContains:
 	return !FcRangeIsInRange (a, b);
     case FcOpLess:
-	return a->begin < b->begin;
+	return a->end < b->begin;
     case FcOpLessEqual:
-	return a->begin <= b->begin;
+	return a->end <= b->begin;
     case FcOpMore:
-	return a->end > b->end;
+	return a->begin > b->end;
     case FcOpMoreEqual:
-	return a->end >= b->end;
+	return a->begin >= b->end;
     default:
 	break;
     }