]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcmatch.c
Configuration changes to request synthetic emboldening of fonts. The actual
[fontconfig.git] / src / fcmatch.c
index 5866db999c17336b8e0189908894c8eb77a372d5..bc46700ceb02fce72b12398cba5cd0329decadae 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fcmatch.c,v 1.11 2002/06/08 17:32:04 keithp Exp $
+ * $RCSId: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp Exp $
  *
- * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2000 Keith Packard
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 #include <stdio.h>
 
 static double
-FcCompareInteger (char *object, FcValue value1, FcValue value2)
+FcCompareNumber (char *object, FcValue value1, FcValue value2)
 {
-    int        v;
+    double  v1, v2, v;
     
-    if (value2.type != FcTypeInteger || value1.type != FcTypeInteger)
+    switch (value1.type) {
+    case FcTypeInteger:
+       v1 = (double) value1.u.i;
+       break;
+    case FcTypeDouble:
+       v1 = value1.u.d;
+       break;
+    default:
+       return -1.0;
+    }
+    switch (value2.type) {
+    case FcTypeInteger:
+       v2 = (double) value2.u.i;
+       break;
+    case FcTypeDouble:
+       v2 = value2.u.d;
+       break;
+    default:
        return -1.0;
-    v = value2.u.i - value1.u.i;
+    }
+    v = v2 - v1;
     if (v < 0)
        v = -v;
     return (double) v;
@@ -48,6 +66,58 @@ FcCompareString (char *object, FcValue value1, FcValue value2)
     return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
 }
 
+static double
+FcCompareFamily (char *object, FcValue value1, FcValue value2)
+{
+    if (value2.type != FcTypeString || value1.type != FcTypeString)
+       return -1.0;
+    return (double) FcStrCmpIgnoreBlanksAndCase (value1.u.s, value2.u.s) != 0;
+}
+
+static double
+FcCompareLang (char *object, FcValue value1, FcValue value2)
+{
+    FcLangResult    result;
+    
+    switch (value1.type) {
+    case FcTypeLangSet:
+       switch (value2.type) {
+       case FcTypeLangSet:
+           result = FcLangSetCompare (value1.u.l, value2.u.l);
+           break;
+       case FcTypeString:
+           result = FcLangSetHasLang (value1.u.l, value2.u.s);
+           break;
+       default:
+           return -1.0;
+       }
+       break;
+    case FcTypeString:
+       switch (value2.type) {
+       case FcTypeLangSet:
+           result = FcLangSetHasLang (value2.u.l, value1.u.s);
+           break;
+       case FcTypeString:
+           result = FcLangCompare (value1.u.s, value2.u.s);
+           break;
+       default:
+           return -1.0;
+       }
+       break;
+    default:
+       return -1.0;
+    }
+    switch (result) {
+    case FcLangEqual:
+       return 0;
+    case FcLangDifferentCountry:
+       return 1;
+    case FcLangDifferentLang:
+    default:
+       return 2;
+    }
+}
+
 static double
 FcCompareBool (char *object, FcValue value1, FcValue value2)
 {
@@ -97,50 +167,62 @@ FcCompareSize (char *object, FcValue value1, FcValue value2)
     return v;
 }
 
+typedef struct _FcMatcher {
+    char           *object;
+    double         (*compare) (char *object, FcValue value1, FcValue value2);
+    int                    strong, weak;
+} FcMatcher;
+
 /*
  * Order is significant, it defines the precedence of
  * each value, earlier values are more significant than
  * later values
  */
 static FcMatcher _FcMatchers [] = {
-    { FC_FOUNDRY,      FcCompareString, },
-#define MATCH_FOUNDRY  0
+    { FC_FOUNDRY,      FcCompareString,        0, 0 },
+#define MATCH_FOUNDRY      0
+    
+    { FC_CHARSET,      FcCompareCharSet,       1, 1 },
+#define MATCH_CHARSET      1
     
-    { FC_CHARSET,      FcCompareCharSet },
-#define MATCH_CHARSET  1
+    { FC_FAMILY,       FcCompareFamily,        2, 4 },
+#define MATCH_FAMILY       2
     
-    { FC_LANG,         FcCompareString },
-#define MATCH_LANG     2
+    { FC_LANG,         FcCompareLang,          3, 3 },
+#define MATCH_LANG         3
     
-    { FC_FAMILY,       FcCompareString, },
-#define MATCH_FAMILY   3
+    { FC_SPACING,      FcCompareNumber,        5, 5 },
+#define MATCH_SPACING      4
     
-    { FC_SPACING,      FcCompareInteger, },
-#define MATCH_SPACING  4
+    { FC_PIXEL_SIZE,   FcCompareSize,          6, 6 },
+#define MATCH_PIXEL_SIZE    5
     
-    { FC_PIXEL_SIZE,   FcCompareSize, },
-#define MATCH_PIXEL_SIZE       5
+    { FC_STYLE,                FcCompareString,        7, 7 },
+#define MATCH_STYLE        6
     
-    { FC_STYLE,                FcCompareString, },
-#define MATCH_STYLE    6
+    { FC_SLANT,                FcCompareNumber,        8, 8 },
+#define MATCH_SLANT        7
     
-    { FC_SLANT,                FcCompareInteger, },
-#define MATCH_SLANT    7
+    { FC_WEIGHT,       FcCompareNumber,        9, 9 },
+#define MATCH_WEIGHT       8
     
-    { FC_WEIGHT,       FcCompareInteger, },
-#define MATCH_WEIGHT   8
+    { FC_WIDTH,                FcCompareNumber,        10, 10 },
+#define MATCH_WIDTH        9
     
-    { FC_ANTIALIAS,    FcCompareBool, },
-#define MATCH_ANTIALIAS        9
+    { FC_ANTIALIAS,    FcCompareBool,          11, 11 },
+#define MATCH_ANTIALIAS            10
     
-    { FC_RASTERIZER,   FcCompareString, },
-#define MATCH_RASTERIZER       10
+    { FC_RASTERIZER,   FcCompareString,        12, 12 },
+#define MATCH_RASTERIZER    11
     
-    { FC_OUTLINE,      FcCompareBool, },
-#define MATCH_OUTLINE  11
+    { FC_OUTLINE,      FcCompareBool,          13, 13 },
+#define MATCH_OUTLINE      12
+
+    { FC_FONTVERSION,  FcCompareNumber,        14, 14 },
+#define MATCH_FONTVERSION   13
 };
 
-#define NUM_MATCHER (sizeof _FcMatchers / sizeof _FcMatchers[0])
+#define NUM_MATCH_VALUES    15
 
 static FcBool
 FcCompareValueList (const char  *object,
@@ -151,9 +233,9 @@ FcCompareValueList (const char  *object,
                    FcResult    *result)
 {
     FcValueList    *v1, *v2;
-    double         v, best;
-    int                    j;
+    double         v, best, bestStrong, bestWeak;
     int                    i;
+    int                    j;
     
     /*
      * Locate the possible matching entry by examining the
@@ -164,7 +246,13 @@ FcCompareValueList (const char  *object,
     case 'f':
        switch (FcToLower (object[1])) {
        case 'o':
-           i = MATCH_FOUNDRY; break;
+           switch (FcToLower (object[2])) {
+           case 'u':
+               i = MATCH_FOUNDRY; break;
+           case 'n':
+               i = MATCH_FONTVERSION; break;
+           }
+           break;
        case 'a':
            i = MATCH_FAMILY; break;
        }
@@ -188,7 +276,13 @@ FcCompareValueList (const char  *object,
     case 'p':
        i = MATCH_PIXEL_SIZE; break;
     case 'w':
-       i = MATCH_WEIGHT; break;
+       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':
@@ -217,6 +311,8 @@ FcCompareValueList (const char  *object,
     }
 #endif
     best = 1e99;
+    bestStrong = 1e99;
+    bestWeak = 1e99;
     j = 0;
     for (v1 = v1orig; v1; v1 = v1->next)
     {
@@ -239,6 +335,16 @@ FcCompareValueList (const char  *object,
                    *bestValue = v2->value;
                best = v;
            }
+           if (v1->binding == FcValueBindingStrong)
+           {
+               if (v < bestStrong)
+                   bestStrong = v;
+           }
+           else
+           {
+               if (v < bestWeak)
+                   bestWeak = v;
+           }
        }
        j++;
     }
@@ -251,7 +357,17 @@ FcCompareValueList (const char  *object,
        printf ("\n");
     }
     if (value)
-       value[i] += best;
+    {
+       int weak    = _FcMatchers[i].weak;
+       int strong  = _FcMatchers[i].strong;
+       if (weak == strong)
+           value[strong] += best;
+       else
+       {
+           value[weak] += bestWeak;
+           value[strong] += bestStrong;
+       }
+    }
     return FcTrue;
 }
 
@@ -268,7 +384,7 @@ FcCompare (FcPattern        *pat,
 {
     int                    i, i1, i2;
     
-    for (i = 0; i < NUM_MATCHER; i++)
+    for (i = 0; i < NUM_MATCH_VALUES; i++)
        value[i] = 0.0;
     
     i1 = 0;
@@ -329,26 +445,12 @@ FcFontRenderPrepare (FcConfig         *config,
        pe = FcPatternFindElt (pat, fe->object);
        if (pe)
        {
-           int     j;
-           double  score[NUM_MATCHER];
-
-           for (j = 0; j < NUM_MATCHER; j++)
-               score[j] = 0;
            if (!FcCompareValueList (pe->object, pe->values, 
                                     fe->values, &v, 0, &result))
            {
                FcPatternDestroy (new);
                return 0;
            }
-           for (j = 0; j < NUM_MATCHER; j++)
-               if (score[j] >= 100.0)
-               {
-                   FcValueList *pv;
-
-                   for (pv = pe->values; pv; pv = pv->next)
-                       FcPatternAdd (new, fe->object, pv->value, FcTrue);
-                   break;
-               }
        }
        else
            v = fe->values->value;
@@ -361,7 +463,7 @@ FcFontRenderPrepare (FcConfig           *config,
        if (!fe)
            FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
     }
-    FcConfigSubstitute (config, new, FcMatchFont);
+    FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
     return new;
 }
 
@@ -372,14 +474,14 @@ FcFontSetMatch (FcConfig    *config,
                FcPattern   *p,
                FcResult    *result)
 {
-    double         score[NUM_MATCHER], bestscore[NUM_MATCHER];
+    double         score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
     int                    f;
     FcFontSet      *s;
     FcPattern      *best;
     int                    i;
     int                    set;
 
-    for (i = 0; i < NUM_MATCHER; i++)
+    for (i = 0; i < NUM_MATCH_VALUES; i++)
        bestscore[i] = 0;
     best = 0;
     if (FcDebug () & FC_DBG_MATCH)
@@ -391,7 +493,10 @@ FcFontSetMatch (FcConfig    *config,
     {
        config = FcConfigGetCurrent ();
        if (!config)
+       {
+           *result = FcResultOutOfMemory;
            return 0;
+       }
     }
     for (set = 0; set < nsets; set++)
     {
@@ -410,19 +515,19 @@ FcFontSetMatch (FcConfig    *config,
            if (FcDebug () & FC_DBG_MATCHV)
            {
                printf ("Score");
-               for (i = 0; i < NUM_MATCHER; i++)
+               for (i = 0; i < NUM_MATCH_VALUES; i++)
                {
                    printf (" %g", score[i]);
                }
                printf ("\n");
            }
-           for (i = 0; i < NUM_MATCHER; i++)
+           for (i = 0; i < NUM_MATCH_VALUES; i++)
            {
                if (best && bestscore[i] < score[i])
                    break;
                if (!best || score[i] < bestscore[i])
                {
-                   for (i = 0; i < NUM_MATCHER; i++)
+                   for (i = 0; i < NUM_MATCH_VALUES; i++)
                        bestscore[i] = score[i];
                    best = s->fonts[f];
                    break;
@@ -433,7 +538,7 @@ FcFontSetMatch (FcConfig    *config,
     if (FcDebug () & FC_DBG_MATCH)
     {
        printf ("Best score");
-       for (i = 0; i < NUM_MATCHER; i++)
+       for (i = 0; i < NUM_MATCH_VALUES; i++)
            printf (" %g", bestscore[i]);
        FcPatternPrint (best);
     }
@@ -469,7 +574,7 @@ FcFontMatch (FcConfig       *config,
 
 typedef struct _FcSortNode {
     FcPattern  *pattern;
-    double     score[NUM_MATCHER];
+    double     score[NUM_MATCH_VALUES];
 } FcSortNode;
 
 static int
@@ -482,7 +587,7 @@ FcSortCompare (const void *aa, const void *ab)
     double     ad = 0, bd = 0;
     int         i;
 
-    i = NUM_MATCHER;
+    i = NUM_MATCH_VALUES;
     while (i-- && (ad = *as++) == (bd = *bs++))
        ;
     return ad < bd ? -1 : ad > bd ? 1 : 0;
@@ -517,6 +622,11 @@ FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool tri
                    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);
@@ -554,6 +664,11 @@ FcFontSetSort (FcConfig        *config,
     int                    f;
     int                    i;
 
+    if (FcDebug () & FC_DBG_MATCH)
+    {
+       printf ("Sort ");
+       FcPatternPrint (p);
+    }
     nnodes = 0;
     for (set = 0; set < nsets; set++)
     {
@@ -564,6 +679,7 @@ FcFontSetSort (FcConfig         *config,
     }
     if (!nnodes)
        goto bail0;
+    /* freed below */
     nodes = malloc (nnodes * sizeof (FcSortNode) + nnodes * sizeof (FcSortNode *));
     if (!nodes)
        goto bail0;
@@ -589,7 +705,7 @@ FcFontSetSort (FcConfig         *config,
            if (FcDebug () & FC_DBG_MATCHV)
            {
                printf ("Score");
-               for (i = 0; i < NUM_MATCHER; i++)
+               for (i = 0; i < NUM_MATCH_VALUES; i++)
                {
                    printf (" %g", new->score[i]);
                }