]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcmatch.c
Bug 44826 - <alias> must contain only a single <family>
[fontconfig.git] / src / fcmatch.c
index 49d41a4ad63513569dd546bede96d89db81d5704..422bc384d2ecbabc2df33e3d10122381d985d9df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $RCSId: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp Exp $
+ * fontconfig/src/fcmatch.c
  *
  * Copyright © 2000 Keith Packard
  *
@@ -7,31 +7,32 @@
  * 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 Keith Packard not be used in
+ * 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.  Keith Packard makes no
+ * 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.
  *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * 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"
+#include <assert.h>
 #include <string.h>
 #include <ctype.h>
-#include "fcint.h"
 #include <stdio.h>
 
 static double
-FcCompareNumber (const char *object, FcValue *value1, FcValue *value2)
+FcCompareNumber (FcValue *value1, FcValue *value2)
 {
     double  v1, v2, v;
-    
+
     switch (value1->type) {
     case FcTypeInteger:
        v1 = (double) value1->u.i;
@@ -55,33 +56,36 @@ FcCompareNumber (const char *object, FcValue *value1, FcValue *value2)
     v = v2 - v1;
     if (v < 0)
        v = -v;
-    return (double) v;
+    return v;
 }
 
 static double
-FcCompareString (const char *object, FcValue *v1, FcValue *v2)
+FcCompareString (FcValue *v1, FcValue *v2)
 {
-    FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
-    if (value2.type != FcTypeString || value1.type != FcTypeString)
-       return -1.0;
-    return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
+    return (double) FcStrCmpIgnoreCase (FcValueString(v1), FcValueString(v2)) != 0;
 }
 
 static double
-FcCompareFamily (const char *object, FcValue *v1, FcValue *v2)
+FcCompareFamily (FcValue *v1, FcValue *v2)
 {
-    FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
-    if (value2.type != FcTypeString || value1.type != FcTypeString)
-       return -1.0;
-    return (double) FcStrCmpIgnoreBlanksAndCase (value1.u.s, value2.u.s) != 0;
+    /* rely on the guarantee in FcPatternObjectAddWithBinding that
+     * families are always FcTypeString. */
+    const FcChar8* v1_string = FcValueString(v1);
+    const FcChar8* v2_string = FcValueString(v2);
+
+    if (FcToLower(*v1_string) != FcToLower(*v2_string) &&
+       *v1_string != ' ' && *v2_string != ' ')
+       return 1.0;
+
+    return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0;
 }
 
 static double
-FcCompareLang (const char *object, FcValue *v1, FcValue *v2)
+FcCompareLang (FcValue *v1, FcValue *v2)
 {
     FcLangResult    result;
     FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
-    
+
     switch (value1.type) {
     case FcTypeLangSet:
        switch (value2.type) {
@@ -89,7 +93,7 @@ FcCompareLang (const char *object, FcValue *v1, FcValue *v2)
            result = FcLangSetCompare (value1.u.l, value2.u.l);
            break;
        case FcTypeString:
-           result = FcLangSetHasLang (value1.u.l, 
+           result = FcLangSetHasLang (value1.u.l,
                                       value2.u.s);
            break;
        default:
@@ -102,7 +106,7 @@ FcCompareLang (const char *object, FcValue *v1, FcValue *v2)
            result = FcLangSetHasLang (value2.u.l, value1.u.s);
            break;
        case FcTypeString:
-           result = FcLangCompare (value1.u.s, 
+           result = FcLangCompare (value1.u.s,
                                    value2.u.s);
            break;
        default:
@@ -124,25 +128,21 @@ FcCompareLang (const char *object, FcValue *v1, FcValue *v2)
 }
 
 static double
-FcCompareBool (const char *object, FcValue *value1, FcValue *value2)
+FcCompareBool (FcValue *v1, FcValue *v2)
 {
-    if (value2->type != FcTypeBool || value1->type != FcTypeBool)
+    if (v2->type != FcTypeBool || v1->type != FcTypeBool)
        return -1.0;
-    return (double) value2->u.b != value1->u.b;
+    return (double) v2->u.b != v1->u.b;
 }
 
 static double
-FcCompareCharSet (const char *object, FcValue *v1, FcValue *v2)
+FcCompareCharSet (FcValue *v1, FcValue *v2)
 {
-    FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
-    
-    if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
-       return -1.0;
-    return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
+    return (double) FcCharSetSubtractCount (FcValueCharSet(v1), FcValueCharSet(v2));
 }
 
 static double
-FcCompareSize (const char *object, FcValue *value1, FcValue *value2)
+FcCompareSize (FcValue *value1, FcValue *value2)
 {
     double  v1, v2, v;
 
@@ -175,8 +175,8 @@ FcCompareSize (const char *object, FcValue *value1, FcValue *value2)
 }
 
 typedef struct _FcMatcher {
-    const char     *object;
-    double         (*compare) (const char *object, FcValue *value1, FcValue *value2);
+    FcObject       object;
+    double         (*compare) (FcValue *value1, FcValue *value2);
     int                    strong, weak;
 } FcMatcher;
 
@@ -185,69 +185,89 @@ typedef struct _FcMatcher {
  * each value, earlier values are more significant than
  * later values
  */
-static FcMatcher _FcMatchers [] = {
-    { FC_FOUNDRY,      FcCompareString,        0, 0 },
+static const FcMatcher _FcMatchers [] = {
+    { FC_FOUNDRY_OBJECT,       FcCompareString,        0, 0 },
 #define MATCH_FOUNDRY      0
-#define MATCH_FOUNDRY_INDEX 0
-    
-    { FC_CHARSET,      FcCompareCharSet,       1, 1 },
+    { FC_CHARSET_OBJECT,       FcCompareCharSet,       1, 1 },
 #define MATCH_CHARSET      1
-#define MATCH_CHARSET_INDEX 1
-    
-    { FC_FAMILY,       FcCompareFamily,        2, 4 },
+    { FC_FAMILY_OBJECT,        FcCompareFamily,        2, 4 },
 #define MATCH_FAMILY       2
-#define MATCH_FAMILY_STRONG_INDEX   2
-#define MATCH_FAMILY_WEAK_INDEX            4
-    
-    { FC_LANG,         FcCompareLang,          3, 3 },
+    { FC_LANG_OBJECT,          FcCompareLang,  3, 3 },
 #define MATCH_LANG         3
 #define MATCH_LANG_INDEX    3
-    
-    { FC_SPACING,      FcCompareNumber,        5, 5 },
+    { FC_SPACING_OBJECT,       FcCompareNumber,        5, 5 },
 #define MATCH_SPACING      4
-#define MATCH_SPACING_INDEX 5
-    
-    { FC_PIXEL_SIZE,   FcCompareSize,          6, 6 },
+    { FC_PIXEL_SIZE_OBJECT,    FcCompareSize,  6, 6 },
 #define MATCH_PIXEL_SIZE    5
-#define MATCH_PIXEL_SIZE_INDEX 6
-    
-    { FC_STYLE,                FcCompareString,        7, 7 },
+    { FC_STYLE_OBJECT,         FcCompareString,        7, 7 },
 #define MATCH_STYLE        6
-#define MATCH_STYLE_INDEX   7
-    
-    { FC_SLANT,                FcCompareNumber,        8, 8 },
+    { FC_SLANT_OBJECT,         FcCompareNumber,        8, 8 },
 #define MATCH_SLANT        7
-#define MATCH_SLANT_INDEX   8
-    
-    { FC_WEIGHT,       FcCompareNumber,        9, 9 },
+    { FC_WEIGHT_OBJECT,                FcCompareNumber,        9, 9 },
 #define MATCH_WEIGHT       8
-#define MATCH_WEIGHT_INDEX  9
-    
-    { FC_WIDTH,                FcCompareNumber,        10, 10 },
+    { FC_WIDTH_OBJECT,         FcCompareNumber,        10, 10 },
 #define MATCH_WIDTH        9
-#define MATCH_WIDTH_INDEX   10
-    
-    { FC_ANTIALIAS,    FcCompareBool,          11, 11 },
-#define MATCH_ANTIALIAS            10
-#define MATCH_ANTIALIAS_INDEX      11
-    
-    { FC_RASTERIZER,   FcCompareString,        12, 12 },
-#define MATCH_RASTERIZER    11
-#define MATCH_RASTERIZER_INDEX    12
-
-    { FC_OUTLINE,      FcCompareBool,          13, 13 },
-#define MATCH_OUTLINE      12
-#define MATCH_OUTLINE_INDEX        13
-
-    { FC_FONTVERSION,  FcCompareNumber,        14, 14 },
-#define MATCH_FONTVERSION   13
-#define MATCH_FONTVERSION_INDEX   14
+    { FC_DECORATIVE_OBJECT,    FcCompareBool,          11, 11 },
+#define MATCH_DECORATIVE       10
+    { FC_ANTIALIAS_OBJECT,     FcCompareBool,          12, 12 },
+#define MATCH_ANTIALIAS                    11
+    { FC_RASTERIZER_OBJECT,    FcCompareString,        13, 13 },
+#define MATCH_RASTERIZER           12
+    { FC_OUTLINE_OBJECT,       FcCompareBool,          14, 14 },
+#define MATCH_OUTLINE              13
+    { FC_FONTVERSION_OBJECT,   FcCompareNumber,        15, 15 },
+#define MATCH_FONTVERSION          14
 };
 
-#define NUM_MATCH_VALUES    15
+#define NUM_MATCH_VALUES    16
+
+static const FcMatcher*
+FcObjectToMatcher (FcObject object)
+{
+    int        i;
+
+    i = -1;
+    switch (object) {
+    case FC_FOUNDRY_OBJECT:
+       i = MATCH_FOUNDRY; break;
+    case FC_FONTVERSION_OBJECT:
+       i = MATCH_FONTVERSION; break;
+    case FC_FAMILY_OBJECT:
+       i = MATCH_FAMILY; break;
+    case FC_CHARSET_OBJECT:
+       i = MATCH_CHARSET; break;
+    case FC_ANTIALIAS_OBJECT:
+       i = MATCH_ANTIALIAS; break;
+    case FC_LANG_OBJECT:
+       i = MATCH_LANG; break;
+    case FC_SPACING_OBJECT:
+        i = MATCH_SPACING; break;
+    case FC_STYLE_OBJECT:
+        i = MATCH_STYLE; break;
+    case FC_SLANT_OBJECT:
+        i = MATCH_SLANT; break;
+    case FC_PIXEL_SIZE_OBJECT:
+       i = MATCH_PIXEL_SIZE; break;
+    case FC_WIDTH_OBJECT:
+        i = MATCH_WIDTH; break;
+    case FC_WEIGHT_OBJECT:
+        i = MATCH_WEIGHT; break;
+    case FC_RASTERIZER_OBJECT:
+       i = MATCH_RASTERIZER; break;
+    case FC_OUTLINE_OBJECT:
+       i = MATCH_OUTLINE; break;
+    case FC_DECORATIVE_OBJECT:
+       i = MATCH_DECORATIVE; break;
+    }
+
+    if (i < 0)
+       return NULL;
+
+    return _FcMatchers+i;
+}
 
 static FcBool
-FcCompareValueList (const char  *object,
+FcCompareValueList (FcObject    object,
                    FcValueListPtr v1orig,      /* pattern */
                    FcValueListPtr v2orig,      /* target */
                    FcValue     *bestValue,
@@ -255,112 +275,39 @@ FcCompareValueList (const char  *object,
                    FcResult    *result)
 {
     FcValueListPtr  v1, v2;
-    FcValueList     *v1_ptrU, *v2_ptrU;
     double         v, best, bestStrong, bestWeak;
-    int                    i;
     int                    j;
-    
-    /*
-     * Locate the possible matching entry by examining the
-     * first few characters in object
-     */
-    i = -1;
-    switch (FcToLower (object[0])) {
-    case 'f':
-       switch (FcToLower (object[1])) {
-       case 'o':
-           switch (FcToLower (object[2])) {
-           case 'u':
-               i = MATCH_FOUNDRY; break;
-           case 'n':
-               i = MATCH_FONTVERSION; break;
-           }
-           break;
-       case 'a':
-           i = MATCH_FAMILY; break;
-       }
-       break;
-    case 'c':
-       i = MATCH_CHARSET; break;
-    case 'a':
-       i = MATCH_ANTIALIAS; break;
-    case 'l':
-       i = MATCH_LANG; break;
-    case 's':
-       switch (FcToLower (object[1])) {
-       case 'p':
-           i = MATCH_SPACING; break;
-       case 't':
-           i = MATCH_STYLE; break;
-       case 'l':
-           i = MATCH_SLANT; break;
-       }
-       break;
-    case 'p':
-       i = MATCH_PIXEL_SIZE; break;
-    case 'w':
-       switch (FcToLower (object[1])) {
-       case 'i':
-           i = MATCH_WIDTH; break;
-       case 'e':
-           i = MATCH_WEIGHT; break;
-       }
-       break;
-    case 'r':
-       i = MATCH_RASTERIZER; break;
-    case 'o':
-       i = MATCH_OUTLINE; break;
-    }
-    if (i == -1 || 
-       FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
-                           (FcChar8 *) object) != 0)
-    {
-       if (bestValue)
-           *bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
-       return FcTrue;
-    }
-#if 0
-    for (i = 0; i < NUM_MATCHER; i++)
-    {
-       if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
-                                (FcChar8 *) object))
-           break;
-    }
-    if (i == NUM_MATCHER)
+    const FcMatcher *match = FcObjectToMatcher(object);
+
+    if (!match)
     {
        if (bestValue)
-           *bestValue = v2orig->value;
+           *bestValue = FcValueCanonicalize(&v2orig->value);
        return FcTrue;
     }
-#endif
+
     best = 1e99;
     bestStrong = 1e99;
     bestWeak = 1e99;
-    j = 0;
-    for (v1 = v1orig, v1_ptrU = FcValueListPtrU(v1); v1_ptrU;
-        v1 = FcValueListPtrU(v1)->next, v1_ptrU = FcValueListPtrU(v1))
+    j = 1;
+    for (v1 = v1orig; v1; v1 = FcValueListNext(v1))
     {
-       for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); FcValueListPtrU(v2); 
-            v2 = FcValueListPtrU(v2)->next)
+       for (v2 = v2orig; v2; v2 = FcValueListNext(v2))
        {
-           v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
-                                          &v1_ptrU->value,
-                                          &v2_ptrU->value);
+           v = (match->compare) (&v1->value, &v2->value);
            if (v < 0)
            {
                *result = FcResultTypeMismatch;
                return FcFalse;
            }
-           if (FcDebug () & FC_DBG_MATCHV)
-               printf (" v %g j %d ", v, j);
-           v = v * 100 + j;
+           v = v * 1000 + j;
            if (v < best)
            {
                if (bestValue)
-                   *bestValue = FcValueCanonicalize(&v2_ptrU->value);
+                   *bestValue = FcValueCanonicalize(&v2->value);
                best = v;
            }
-           if (v1_ptrU->binding == FcValueBindingStrong)
+           if (v1->binding == FcValueBindingStrong)
            {
                if (v < bestStrong)
                    bestStrong = v;
@@ -375,7 +322,7 @@ FcCompareValueList (const char  *object,
     }
     if (FcDebug () & FC_DBG_MATCHV)
     {
-       printf (" %s: %g ", object, best);
+       printf (" %s: %g ", FcObjectName (object), best);
        FcValueListPrint (v1orig);
        printf (", ");
        FcValueListPrint (v2orig);
@@ -383,8 +330,8 @@ FcCompareValueList (const char  *object,
     }
     if (value)
     {
-       int weak    = _FcMatchers[i].weak;
-       int strong  = _FcMatchers[i].strong;
+       int weak    = match->weak;
+       int strong  = match->strong;
        if (weak == strong)
            value[strong] += best;
        else
@@ -408,47 +355,34 @@ FcCompare (FcPattern      *pat,
           FcResult     *result)
 {
     int                    i, i1, i2;
-    
+
     for (i = 0; i < NUM_MATCH_VALUES; i++)
        value[i] = 0.0;
-    
+
     i1 = 0;
     i2 = 0;
     while (i1 < pat->num && i2 < fnt->num)
     {
-       i = FcObjectPtrCompare((FcPatternEltU(pat->elts)+i1)->object,
-                              (FcPatternEltU(fnt->elts)+i2)->object);
+       FcPatternElt *elt_i1 = &FcPatternElts(pat)[i1];
+       FcPatternElt *elt_i2 = &FcPatternElts(fnt)[i2];
+
+       i = FcObjectCompare(elt_i1->object, elt_i2->object);
        if (i > 0)
            i2++;
        else if (i < 0)
            i1++;
        else
        {
-           if (!FcCompareValueList (FcObjectPtrU((FcPatternEltU(pat->elts)+i1)->object),
-                                    (FcPatternEltU(pat->elts)+i1)->values,
-                                    (FcPatternEltU(fnt->elts)+i2)->values,
-                                    0,
-                                    value,
-                                    result))
+           if (!FcCompareValueList (elt_i1->object,
+                                    FcPatternEltValues(elt_i1),
+                                    FcPatternEltValues(elt_i2),
+                                    0, value, result))
                return FcFalse;
            i1++;
            i2++;
        }
     }
     return FcTrue;
-#if 0
-    for (i1 = 0; i1 < pat->num; i1++)
-    {
-       for (i2 = 0; i2 < fnt->num; i2++)
-       {
-           if (!strcmp (pat->elts[i1].object, fnt->elts[i2].object))
-           {
-               break;
-           }
-       }
-    }
-    return FcTrue;
-#endif
 }
 
 FcPattern *
@@ -461,49 +395,51 @@ FcFontRenderPrepare (FcConfig         *config,
     FcPatternElt    *fe, *pe;
     FcValue        v;
     FcResult       result;
-    
+
+    assert (pat != NULL);
+    assert (font != NULL);
+
     new = FcPatternCreate ();
     if (!new)
        return 0;
     for (i = 0; i < font->num; i++)
     {
-       fe = FcPatternEltU(font->elts)+i;
-       pe = FcPatternFindElt (pat, FcObjectPtrU(fe->object));
+       fe = &FcPatternElts(font)[i];
+       pe = FcPatternObjectFindElt (pat, fe->object);
        if (pe)
        {
-           if (!FcCompareValueList (FcObjectPtrU(pe->object), pe->values, 
-                                    fe->values, &v, 0, &result))
+           if (!FcCompareValueList (pe->object, FcPatternEltValues(pe),
+                                    FcPatternEltValues(fe), &v, 0, &result))
            {
                FcPatternDestroy (new);
                return 0;
            }
        }
        else
-           v = FcValueCanonicalize(&FcValueListPtrU(fe->values)->value);
-       FcPatternAdd (new, FcObjectPtrU(fe->object), v, FcFalse);
+           v = FcValueCanonicalize(&FcPatternEltValues (fe)->value);
+       FcPatternObjectAdd (new, fe->object, v, FcFalse);
     }
     for (i = 0; i < pat->num; i++)
     {
-       pe = FcPatternEltU(pat->elts)+i;
-       fe = FcPatternFindElt (font, FcObjectPtrU(pe->object));
+       pe = &FcPatternElts(pat)[i];
+       fe = FcPatternObjectFindElt (font, pe->object);
        if (!fe)
-           FcPatternAdd (new, FcObjectPtrU(pe->object), 
-                          FcValueCanonicalize(&FcValueListPtrU(pe->values)->value), FcTrue);
+       {
+           v = FcValueCanonicalize(&FcPatternEltValues(pe)->value);
+           FcPatternObjectAdd (new, pe->object, v, FcTrue);
+       }
     }
 
-    if (FcPatternFindElt (font, FC_FILE))
-       FcPatternTransferFullFname (new, font);
-
     FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
     return new;
 }
 
-FcPattern *
-FcFontSetMatch (FcConfig    *config,
-               FcFontSet   **sets,
-               int         nsets,
-               FcPattern   *p,
-               FcResult    *result)
+static FcPattern *
+FcFontSetMatchInternal (FcConfig    *config,
+                       FcFontSet   **sets,
+                       int         nsets,
+                       FcPattern   *p,
+                       FcResult    *result)
 {
     double         score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
     int                    f;
@@ -520,15 +456,6 @@ FcFontSetMatch (FcConfig    *config,
        printf ("Match ");
        FcPatternPrint (p);
     }
-    if (!config)
-    {
-       config = FcConfigGetCurrent ();
-       if (!config)
-       {
-           *result = FcResultOutOfMemory;
-           return 0;
-       }
-    }
     for (set = 0; set < nsets; set++)
     {
        s = sets[set];
@@ -571,6 +498,7 @@ FcFontSetMatch (FcConfig    *config,
        printf ("Best score");
        for (i = 0; i < NUM_MATCH_VALUES; i++)
            printf (" %g", bestscore[i]);
+       printf ("\n");
        FcPatternPrint (best);
     }
     if (!best)
@@ -578,16 +506,46 @@ FcFontSetMatch (FcConfig    *config,
        *result = FcResultNoMatch;
        return 0;
     }
-    return FcFontRenderPrepare (config, p, best);
+    return best;
+}
+
+FcPattern *
+FcFontSetMatch (FcConfig    *config,
+               FcFontSet   **sets,
+               int         nsets,
+               FcPattern   *p,
+               FcResult    *result)
+{
+    FcPattern      *best;
+
+    assert (sets != NULL);
+    assert (p != NULL);
+    assert (result != NULL);
+
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+    best = FcFontSetMatchInternal (config, sets, nsets, p, result);
+    if (best)
+       return FcFontRenderPrepare (config, p, best);
+    else
+       return NULL;
 }
 
 FcPattern *
 FcFontMatch (FcConfig  *config,
-            FcPattern  *p, 
+            FcPattern  *p,
             FcResult   *result)
 {
     FcFontSet  *sets[2];
     int                nsets;
+    FcPattern   *best;
+
+    assert (p != NULL);
+    assert (result != NULL);
 
     if (!config)
     {
@@ -600,7 +558,12 @@ FcFontMatch (FcConfig      *config,
        sets[nsets++] = config->fonts[FcSetSystem];
     if (config->fonts[FcSetApplication])
        sets[nsets++] = config->fonts[FcSetApplication];
-    return FcFontSetMatch (config, sets, nsets, p, result);
+
+    best = FcFontSetMatchInternal (config, sets, nsets, p, result);
+    if (best)
+       return FcFontRenderPrepare (config, p, best);
+    else
+       return NULL;
 }
 
 typedef struct _FcSortNode {
@@ -625,48 +588,71 @@ FcSortCompare (const void *aa, const void *ab)
 }
 
 static FcBool
-FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
+FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
 {
-    FcCharSet  *ncs;
-    FcSortNode *node;
+    FcBool ret = FcFalse;
+    FcCharSet *cs;
+
+    cs = 0;
+    if (trim || csp)
+    {
+       cs = FcCharSetCreate ();
+       if (cs == NULL)
+           goto bail;
+    }
 
     while (nnode--)
     {
-       node = *n++;
-       if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) == 
-           FcResultMatch)
+       FcSortNode      *node = *n++;
+       FcBool          adds_chars = FcFalse;
+
+       /*
+        * Only fetch node charset if we'd need it
+        */
+       if (cs)
+       {
+           FcCharSet   *ncs;
+
+           if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
+               FcResultMatch)
+               continue;
+
+           if (!FcCharSetMerge (cs, ncs, &adds_chars))
+               goto bail;
+       }
+
+       /*
+        * If this font isn't a subset of the previous fonts,
+        * add it to the list
+        */
+       if (!trim || adds_chars)
        {
-           /*
-            * If this font isn't a subset of the previous fonts,
-            * add it to the list
-            */
-           if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
+           FcPatternReference (node->pattern);
+           if (FcDebug () & FC_DBG_MATCHV)
            {
-               if (*cs)
-               {
-                   ncs = FcCharSetUnion (ncs, *cs);
-                   if (!ncs)
-                       return FcFalse;
-                   FcCharSetDestroy (*cs);
-               }
-               else
-                   ncs = FcCharSetCopy (ncs);
-               *cs = ncs;
-               FcPatternReference (node->pattern);
-               if (FcDebug () & FC_DBG_MATCH)
-               {
-                   printf ("Add ");
-                   FcPatternPrint (node->pattern);
-               }
-               if (!FcFontSetAdd (fs, node->pattern))
-               {
-                   FcPatternDestroy (node->pattern);
-                   return FcFalse;
-               }
+               printf ("Add ");
+               FcPatternPrint (node->pattern);
+           }
+           if (!FcFontSetAdd (fs, node->pattern))
+           {
+               FcPatternDestroy (node->pattern);
+               goto bail;
            }
        }
     }
-    return FcTrue;
+    if (csp)
+    {
+       *csp = cs;
+       cs = 0;
+    }
+
+    ret = FcTrue;
+
+bail:
+    if (cs)
+       FcCharSetDestroy (cs);
+
+    return ret;
 }
 
 void
@@ -690,7 +676,6 @@ FcFontSetSort (FcConfig         *config,
     FcSortNode     **nodeps, **nodep;
     int                    nnodes;
     FcSortNode     *new;
-    FcCharSet      *cs;
     int                    set;
     int                    f;
     int                    i;
@@ -698,6 +683,19 @@ FcFontSetSort (FcConfig        *config,
     FcBool         *patternLangSat;
     FcValue        patternLang;
 
+    assert (sets != NULL);
+    assert (p != NULL);
+    assert (result != NULL);
+
+    /* There are some implementation that relying on the result of
+     * "result" to check if the return value of FcFontSetSort
+     * is valid or not.
+     * So we should initialize it to the conservative way since
+     * this function doesn't return NULL anymore.
+     */
+    if (result)
+       *result = FcResultNoMatch;
+
     if (FcDebug () & FC_DBG_MATCH)
     {
        printf ("Sort ");
@@ -712,22 +710,22 @@ FcFontSetSort (FcConfig       *config,
        nnodes += s->nfont;
     }
     if (!nnodes)
-       goto bail0;
-    
+       return FcFontSetCreate ();
+
     for (nPatternLang = 0;
         FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
         nPatternLang++)
        ;
        
     /* freed below */
-    nodes = malloc (nnodes * sizeof (FcSortNode) + 
+    nodes = malloc (nnodes * sizeof (FcSortNode) +
                    nnodes * sizeof (FcSortNode *) +
                    nPatternLang * sizeof (FcBool));
     if (!nodes)
        goto bail0;
     nodeps = (FcSortNode **) (nodes + nnodes);
     patternLangSat = (FcBool *) (nodeps + nnodes);
-    
+
     new = nodes;
     nodep = nodeps;
     for (set = 0; set < nsets; set++)
@@ -761,13 +759,13 @@ FcFontSetSort (FcConfig       *config,
     }
 
     nnodes = new - nodes;
-    
+
     qsort (nodeps, nnodes, sizeof (FcSortNode *),
           FcSortCompare);
-    
+
     for (i = 0; i < nPatternLang; i++)
        patternLangSat[i] = FcFalse;
-    
+
     for (f = 0; f < nnodes; f++)
     {
        FcBool  satisfies = FcFalse;
@@ -775,7 +773,7 @@ FcFontSetSort (FcConfig         *config,
         * If this node matches any language, go check
         * which ones and satisfy those entries
         */
-       if (nodeps[f]->score[MATCH_LANG_INDEX] < nPatternLang)
+       if (nodeps[f]->score[MATCH_LANG_INDEX] < 2000)
        {
            for (i = 0; i < nPatternLang; i++)
            {
@@ -785,8 +783,7 @@ FcFontSetSort (FcConfig         *config,
                    FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
                    FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
                {
-                   double  compare = FcCompareLang (FC_LANG, &patternLang, 
-                                                    &nodeLang);
+                   double  compare = FcCompareLang (&patternLang, &nodeLang);
                    if (compare >= 0 && compare < 2)
                    {
                        if (FcDebug () & FC_DBG_MATCHV)
@@ -806,7 +803,7 @@ FcFontSetSort (FcConfig         *config,
            }
        }
        if (!satisfies)
-           nodeps[f]->score[MATCH_LANG_INDEX] = 1000.0;
+           nodeps[f]->score[MATCH_LANG_INDEX] = 10000.0;
     }
 
     /*
@@ -819,23 +816,19 @@ FcFontSetSort (FcConfig       *config,
     if (!ret)
        goto bail1;
 
-    cs = 0;
-
-    if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
+    if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
        goto bail2;
 
-    if (csp)
-       *csp = cs;
-    else
-       FcCharSetDestroy (cs);
-
     free (nodes);
 
+    if (FcDebug() & FC_DBG_MATCH)
+    {
+       printf ("First font ");
+       FcPatternPrint (ret->fonts[0]);
+    }
     return ret;
 
 bail2:
-    if (cs)
-       FcCharSetDestroy (cs);
     FcFontSetDestroy (ret);
 bail1:
     free (nodes);
@@ -845,7 +838,7 @@ bail0:
 
 FcFontSet *
 FcFontSort (FcConfig   *config,
-           FcPattern   *p, 
+           FcPattern   *p,
            FcBool      trim,
            FcCharSet   **csp,
            FcResult    *result)
@@ -853,6 +846,9 @@ FcFontSort (FcConfig        *config,
     FcFontSet  *sets[2];
     int                nsets;
 
+    assert (p != NULL);
+    assert (result != NULL);
+
     if (!config)
     {
        config = FcConfigGetCurrent ();
@@ -866,3 +862,6 @@ FcFontSort (FcConfig        *config,
        sets[nsets++] = config->fonts[FcSetApplication];
     return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
 }
+#define __fcmatch__
+#include "fcaliastail.h"
+#undef __fcmatch__