]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcmatch.c
Revert to original FcFontSetMatch algorithm to avoid losing fonts.
[fontconfig.git] / src / fcmatch.c
index 38d083ee5283261de28432cc9c279e243f54ef18..739ef3e28d4b8e6593d905d7d33c2be917a75ebd 100644 (file)
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include "fcint.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;
     
@@ -55,29 +55,31 @@ 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 (fc_value_string(v1), fc_value_string(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 FcPatternAddWithBinding that
+     * families are always FcTypeString. */
+    const FcChar8* v1_string = fc_value_string(v1);
+    const FcChar8* v2_string = fc_value_string(v2);
+
+    if (FcToLower(*v1_string) != FcToLower(*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);
@@ -124,25 +126,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 (fc_storage_type(v2) != FcTypeBool || fc_storage_type(v1) != 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 (fc_value_charset(v1), fc_value_charset(v2));
 }
 
 static double
-FcCompareSize (const char *object, FcValue *value1, FcValue *value2)
+FcCompareSize (FcValue *value1, FcValue *value2)
 {
     double  v1, v2, v;
 
@@ -176,7 +174,8 @@ FcCompareSize (const char *object, FcValue *value1, FcValue *value2)
 
 typedef struct _FcMatcher {
     const char     *object;
-    double         (*compare) (const char *object, FcValue *value1, FcValue *value2);
+    FcObjectPtr            objectPtr;
+    double         (*compare) (FcValue *value1, FcValue *value2);
     int                    strong, weak;
 } FcMatcher;
 
@@ -186,89 +185,100 @@ typedef struct _FcMatcher {
  * later values
  */
 static FcMatcher _FcMatchers [] = {
-    { FC_FOUNDRY,      FcCompareString,        0, 0 },
+    { FC_FOUNDRY,      0, FcCompareString,     0, 0 },
 #define MATCH_FOUNDRY      0
 #define MATCH_FOUNDRY_INDEX 0
     
-    { FC_CHARSET,      FcCompareCharSet,       1, 1 },
+    { FC_CHARSET,      0, FcCompareCharSet,    1, 1 },
 #define MATCH_CHARSET      1
 #define MATCH_CHARSET_INDEX 1
     
-    { FC_FAMILY,       FcCompareFamily,        2, 4 },
+    { FC_FAMILY,       0, 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,         0, FcCompareLang,       3, 3 },
 #define MATCH_LANG         3
 #define MATCH_LANG_INDEX    3
     
-    { FC_SPACING,      FcCompareNumber,        5, 5 },
+    { FC_SPACING,      0, FcCompareNumber,     5, 5 },
 #define MATCH_SPACING      4
 #define MATCH_SPACING_INDEX 5
     
-    { FC_PIXEL_SIZE,   FcCompareSize,          6, 6 },
+    { FC_PIXEL_SIZE,   0, FcCompareSize,       6, 6 },
 #define MATCH_PIXEL_SIZE    5
 #define MATCH_PIXEL_SIZE_INDEX 6
     
-    { FC_STYLE,                FcCompareString,        7, 7 },
+    { FC_STYLE,                0, FcCompareString,     7, 7 },
 #define MATCH_STYLE        6
 #define MATCH_STYLE_INDEX   7
     
-    { FC_SLANT,                FcCompareNumber,        8, 8 },
+    { FC_SLANT,                0, FcCompareNumber,     8, 8 },
 #define MATCH_SLANT        7
 #define MATCH_SLANT_INDEX   8
     
-    { FC_WEIGHT,       FcCompareNumber,        9, 9 },
+    { FC_WEIGHT,       0, FcCompareNumber,     9, 9 },
 #define MATCH_WEIGHT       8
 #define MATCH_WEIGHT_INDEX  9
     
-    { FC_WIDTH,                FcCompareNumber,        10, 10 },
+    { FC_WIDTH,                0, FcCompareNumber,     10, 10 },
 #define MATCH_WIDTH        9
 #define MATCH_WIDTH_INDEX   10
     
-    { FC_ANTIALIAS,    FcCompareBool,          11, 11 },
+    { FC_ANTIALIAS,    0, FcCompareBool,       11, 11 },
 #define MATCH_ANTIALIAS            10
 #define MATCH_ANTIALIAS_INDEX      11
     
-    { FC_RASTERIZER,   FcCompareString,        12, 12 },
+    { FC_RASTERIZER,   0, FcCompareString,     12, 12 },
 #define MATCH_RASTERIZER    11
 #define MATCH_RASTERIZER_INDEX    12
 
-    { FC_OUTLINE,      FcCompareBool,          13, 13 },
+    { FC_OUTLINE,      0, FcCompareBool,       13, 13 },
 #define MATCH_OUTLINE      12
 #define MATCH_OUTLINE_INDEX        13
 
-    { FC_FONTVERSION,  FcCompareNumber,        14, 14 },
+    { FC_FONTVERSION,  0, FcCompareNumber,     14, 14 },
 #define MATCH_FONTVERSION   13
 #define MATCH_FONTVERSION_INDEX   14
 };
 
 #define NUM_MATCH_VALUES    15
 
-static FcBool
-FcCompareValueList (const char  *object,
-                   FcValueListPtr v1orig,      /* pattern */
-                   FcValueListPtr v2orig,      /* target */
-                   FcValue     *bestValue,
-                   double      *value,
-                   FcResult    *result)
+static FcBool matchObjectPtrsInit = FcFalse;
+
+static void
+FcMatchObjectPtrsInit (void)
 {
-    FcValueListPtr v1, v2;
-    double         v, best, bestStrong, bestWeak;
-    int                    i;
-    int                    j;
-    
-    /*
-     * Locate the possible matching entry by examining the
-     * first few characters in object
-     */
+    _FcMatchers[MATCH_FOUNDRY].objectPtr = FcObjectToPtr(FC_FOUNDRY);
+    _FcMatchers[MATCH_CHARSET].objectPtr = FcObjectToPtr(FC_CHARSET);
+    _FcMatchers[MATCH_FAMILY].objectPtr = FcObjectToPtr(FC_FAMILY);
+    _FcMatchers[MATCH_LANG].objectPtr = FcObjectToPtr(FC_LANG);
+    _FcMatchers[MATCH_SPACING].objectPtr = FcObjectToPtr(FC_SPACING);
+    _FcMatchers[MATCH_PIXEL_SIZE].objectPtr = FcObjectToPtr(FC_PIXEL_SIZE);
+    _FcMatchers[MATCH_STYLE].objectPtr = FcObjectToPtr(FC_STYLE);
+    _FcMatchers[MATCH_SLANT].objectPtr = FcObjectToPtr(FC_SLANT);
+    _FcMatchers[MATCH_WEIGHT].objectPtr = FcObjectToPtr(FC_WEIGHT);
+    _FcMatchers[MATCH_WIDTH].objectPtr = FcObjectToPtr(FC_WIDTH);
+    _FcMatchers[MATCH_ANTIALIAS].objectPtr = FcObjectToPtr(FC_ANTIALIAS);
+    _FcMatchers[MATCH_RASTERIZER].objectPtr = FcObjectToPtr(FC_RASTERIZER);
+    _FcMatchers[MATCH_OUTLINE].objectPtr = FcObjectToPtr(FC_OUTLINE);
+    _FcMatchers[MATCH_FONTVERSION].objectPtr = FcObjectToPtr(FC_FONTVERSION);
+    matchObjectPtrsInit = FcTrue;
+}
+
+static FcMatcher*
+FcObjectPtrToMatcher (FcObjectPtr o)
+{
+    int        i;
+    const char  *object = FcObjectPtrU(o);
+
     i = -1;
-    switch (FcToLower (object[0])) {
+    switch (object[0]) {
     case 'f':
-       switch (FcToLower (object[1])) {
+       switch (object[1]) {
        case 'o':
-           switch (FcToLower (object[2])) {
+           switch (object[2]) {
            case 'u':
                i = MATCH_FOUNDRY; break;
            case 'n':
@@ -286,7 +296,7 @@ FcCompareValueList (const char  *object,
     case 'l':
        i = MATCH_LANG; break;
     case 's':
-       switch (FcToLower (object[1])) {
+       switch (object[1]) {
        case 'p':
            i = MATCH_SPACING; break;
        case 't':
@@ -298,7 +308,7 @@ FcCompareValueList (const char  *object,
     case 'p':
        i = MATCH_PIXEL_SIZE; break;
     case 'w':
-       switch (FcToLower (object[1])) {
+       switch (object[1]) {
        case 'i':
            i = MATCH_WIDTH; break;
        case 'e':
@@ -310,56 +320,65 @@ FcCompareValueList (const char  *object,
     case 'o':
        i = MATCH_OUTLINE; break;
     }
-    if (i == -1 || 
-       FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
-                           (FcChar8 *) object) != 0)
+
+    if (i < 0)
+       return 0;
+
+    if (!matchObjectPtrsInit)
+        FcMatchObjectPtrsInit();
+
+    if (o != _FcMatchers[i].objectPtr)
+       return 0;
+
+    return _FcMatchers+i;
+}
+
+static FcBool
+FcCompareValueList (FcObjectPtr o,
+                   FcValueListPtr v1orig,      /* pattern */
+                   FcValueListPtr v2orig,      /* target */
+                   FcValue     *bestValue,
+                   double      *value,
+                   FcResult    *result)
+{
+    FcValueListPtr  v1, v2;
+    FcValueList     *v1_ptrU, *v2_ptrU;
+    double         v, best, bestStrong, bestWeak;
+    int                    j;
+    const char     *object = FcObjectPtrU(o);
+    FcMatcher       *match = FcObjectPtrToMatcher(o);
+
+    if (!match)
     {
        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)
-    {
-       if (bestValue)
-           *bestValue = v2orig->value;
-       return FcTrue;
-    }
-#endif
+
     best = 1e99;
     bestStrong = 1e99;
     bestWeak = 1e99;
     j = 0;
-    for (v1 = v1orig; FcValueListPtrU(v1); 
-        v1 = FcValueListPtrU(v1)->next)
+    for (v1 = v1orig, v1_ptrU = FcValueListPtrU(v1); v1_ptrU;
+        v1 = v1_ptrU->next, v1_ptrU = FcValueListPtrU(v1))
     {
-       for (v2 = v2orig; FcValueListPtrU(v2); 
-            v2 = FcValueListPtrU(v2)->next)
+       for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); v2_ptrU;
+            v2 = v2_ptrU->next, v2_ptrU = FcValueListPtrU(v2))
        {
-           v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
-                                           &FcValueListPtrU(v1)->value,
-                                           &FcValueListPtrU(v2)->value);
+           v = (match->compare) (&v1_ptrU->value, &v2_ptrU->value);
            if (v < 0)
            {
                *result = FcResultTypeMismatch;
                return FcFalse;
            }
-           if (FcDebug () & FC_DBG_MATCHV)
-               printf (" v %g j %d ", v, j);
            v = v * 100 + j;
            if (v < best)
            {
                if (bestValue)
-                   *bestValue = FcValueCanonicalize(&FcValueListPtrU(v2)->value);
+                   *bestValue = FcValueCanonicalize(&v2_ptrU->value);
                best = v;
            }
-           if (FcValueListPtrU(v1)->binding == FcValueBindingStrong)
+           if (v1_ptrU->binding == FcValueBindingStrong)
            {
                if (v < bestStrong)
                    bestStrong = v;
@@ -382,8 +401,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
@@ -415,39 +434,25 @@ FcCompare (FcPattern      *pat,
     i2 = 0;
     while (i1 < pat->num && i2 < fnt->num)
     {
-       i = FcObjectPtrCompare((FcPatternEltU(pat->elts)+i1)->object,
-                              (FcPatternEltU(fnt->elts)+i2)->object);
+       FcPatternElt *elt_i1 = FcPatternEltU(pat->elts)+i1;
+       FcPatternElt *elt_i2 = FcPatternEltU(fnt->elts)+i2;
+
+       i = FcObjectPtrCompare(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,
+                                    elt_i1->values, elt_i2->values,
+                                    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 *
@@ -470,7 +475,7 @@ FcFontRenderPrepare (FcConfig           *config,
        pe = FcPatternFindElt (pat, FcObjectPtrU(fe->object));
        if (pe)
        {
-           if (!FcCompareValueList (FcObjectPtrU(pe->object), pe->values, 
+           if (!FcCompareValueList (pe->object, pe->values, 
                                     fe->values, &v, 0, &result))
            {
                FcPatternDestroy (new);
@@ -490,9 +495,6 @@ FcFontRenderPrepare (FcConfig           *config,
                           FcValueCanonicalize(&FcValueListPtrU(pe->values)->value), FcTrue);
     }
 
-    if (FcPatternFindElt (font, FC_FILE))
-       FcPatternTransferFullFname (new, font);
-
     FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
     return new;
 }
@@ -523,10 +525,7 @@ FcFontSetMatch (FcConfig    *config,
     {
        config = FcConfigGetCurrent ();
        if (!config)
-       {
-           *result = FcResultOutOfMemory;
            return 0;
-       }
     }
     for (set = 0; set < nsets; set++)
     {
@@ -624,7 +623,7 @@ 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 **cs, FcBool trim, FcBool build_cs)
 {
     FcCharSet  *ncs;
     FcSortNode *node;
@@ -641,16 +640,20 @@ FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool tri
             */
            if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
            {
-               if (*cs)
-               {
-                   ncs = FcCharSetUnion (ncs, *cs);
-                   if (!ncs)
-                       return FcFalse;
-                   FcCharSetDestroy (*cs);
-               }
-               else
-                   ncs = FcCharSetCopy (ncs);
-               *cs = ncs;
+                if (trim || build_cs)
+                {
+                    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)
                {
@@ -784,8 +787,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)
@@ -820,13 +822,16 @@ FcFontSetSort (FcConfig       *config,
 
     cs = 0;
 
-    if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
+    if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim, (csp!=0)))
        goto bail2;
 
     if (csp)
        *csp = cs;
     else
-       FcCharSetDestroy (cs);
+    {
+        if (cs)
+            FcCharSetDestroy (cs);
+    }
 
     free (nodes);