]> git.wh0rd.org - fontconfig.git/blobdiff - src/fclist.c
Bug 44826 - <alias> must contain only a single <family>
[fontconfig.git] / src / fclist.c
index 47a2f04dc675ea315ed110053b704f46faadc74c..9a84b5c7e9e7b9edf4ed7eb79358fc502ce4292c 100644 (file)
@@ -1,29 +1,29 @@
 /*
- * $RCSId: xc/lib/fontconfig/src/fclist.c,v 1.11tsi Exp $
+ * fontconfig/src/fclist.c
  *
- * Copyright © 2000 Keith Packard
+ * Copyright Â© 2000 Keith Packard
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * the above copyright notice appear in all copies and that both that
  * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of 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 <stdlib.h>
 #include "fcint.h"
+#include <stdlib.h>
 
 FcObjectSet *
 FcObjectSetCreate (void)
@@ -46,7 +46,7 @@ FcObjectSetAdd (FcObjectSet *os, const char *object)
     int                s;
     const char **objects;
     int                high, low, mid, c;
-    
+
     if (os->nobject == os->sobject)
     {
        s = os->sobject + 4;
@@ -67,10 +67,11 @@ FcObjectSetAdd (FcObjectSet *os, const char *object)
     low = 0;
     mid = 0;
     c = 1;
+    object = (char *)FcStrStaticName ((FcChar8 *)object);
     while (low <= high)
     {
        mid = (low + high) >> 1;
-       c = strcmp (os->objects[mid], object);
+       c = os->objects[mid] - object;
        if (c == 0)
            return FcTrue;
        if (c < 0)
@@ -80,7 +81,7 @@ FcObjectSetAdd (FcObjectSet *os, const char *object)
     }
     if (c < 0)
        mid++;
-    memmove (os->objects + mid + 1, os->objects + mid, 
+    memmove (os->objects + mid + 1, os->objects + mid,
             (os->nobject - mid) * sizeof (const char *));
     os->objects[mid] = object;
     os->nobject++;
@@ -120,39 +121,57 @@ FcObjectSetBuild (const char *first, ...)
     return os;
 }
 
+/*
+ * Font must have a containing value for every value in the pattern
+ */
 static FcBool
-FcListValueListMatchAny (FcValueList *v1orig,
-                        FcValueList *v2orig)
+FcListValueListMatchAny (FcValueListPtr patOrig,           /* pattern */
+                        FcValueListPtr fntOrig)            /* font */
 {
-    FcValueList            *v1, *v2;
+    FcValueListPtr      pat, fnt;
 
-    for (v1 = v1orig; v1; v1 = v1->next)
-       for (v2 = v2orig; v2; v2 = v2->next)
-           if (FcConfigCompareValue (v1->value, FcOpContains, v2->value))
-               return FcTrue;
-    return FcFalse;
+    for (pat = patOrig; pat != NULL; pat = FcValueListNext(pat))
+    {
+       for (fnt = fntOrig; fnt != NULL; fnt = FcValueListNext(fnt))
+       {
+           /*
+            * make sure the font 'contains' the pattern.
+            * (OpListing is OpContains except for strings
+            *  where it requires an exact match)
+            */
+           if (FcConfigCompareValue (&fnt->value,
+                                     FcOpListing,
+                                     &pat->value))
+               break;
+       }
+       if (fnt == NULL)
+           return FcFalse;
+    }
+    return FcTrue;
 }
 
 static FcBool
-FcListValueListEqual (FcValueList   *v1orig,
-                     FcValueList   *v2orig)
+FcListValueListEqual (FcValueListPtr v1orig,
+                     FcValueListPtr v2orig)
 {
-    FcValueList            *v1, *v2;
+    FcValueListPtr         v1, v2;
 
-    for (v1 = v1orig; v1; v1 = v1->next)
+    for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
     {
-       for (v2 = v2orig; v2; v2 = v2->next)
-           if (FcValueEqual (v1->value, v2->value))
+       for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
+           if (FcValueEqual (FcValueCanonicalize(&(v1)->value),
+                             FcValueCanonicalize(&(v2)->value)))
                break;
-       if (!v2)
+       if (v2 == NULL)
            return FcFalse;
     }
-    for (v2 = v2orig; v2; v2 = v2->next)
+    for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
     {
-       for (v1 = v1orig; v1; v1 = v1->next)
-           if (FcValueEqual (v1->value, v2->value))
+       for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
+           if (FcValueEqual (FcValueCanonicalize(&v1->value),
+                             FcValueCanonicalize(&v2->value)))
                break;
-       if (!v1)
+       if (v1 == NULL)
            return FcFalse;
     }
     return FcTrue;
@@ -168,13 +187,14 @@ FcListPatternEqual (FcPattern     *p1,
 
     for (i = 0; i < os->nobject; i++)
     {
-       e1 = FcPatternFindElt (p1, os->objects[i]);
-       e2 = FcPatternFindElt (p2, os->objects[i]);
+       e1 = FcPatternObjectFindElt (p1, FcObjectFromName (os->objects[i]));
+       e2 = FcPatternObjectFindElt (p2, FcObjectFromName (os->objects[i]));
        if (!e1 && !e2)
            continue;
        if (!e1 || !e2)
            return FcFalse;
-       if (!FcListValueListEqual (e1->values, e2->values))
+       if (!FcListValueListEqual (FcPatternEltValues(e1),
+                                  FcPatternEltValues(e2)))
            return FcFalse;
     }
     return FcTrue;
@@ -184,43 +204,30 @@ FcListPatternEqual (FcPattern     *p1,
  * FcTrue iff all objects in "p" match "font"
  */
 
-static FcBool
-FcListPatternMatchAny (FcPattern *p,
-                      FcPattern *font)
+FcBool
+FcListPatternMatchAny (const FcPattern *p,
+                      const FcPattern *font)
 {
     int                    i;
-    FcPatternElt   *e;
 
     for (i = 0; i < p->num; i++)
     {
-       e = FcPatternFindElt (font, p->elts[i].object);
-       if (!e)
+       FcPatternElt    *pe = &FcPatternElts(p)[i];
+       FcPatternElt    *fe = FcPatternObjectFindElt (font, pe->object);
+       if (!fe)
            return FcFalse;
-       if (!FcListValueListMatchAny (p->elts[i].values, e->values))
+       if (!FcListValueListMatchAny (FcPatternEltValues(pe),    /* pat elts */
+                                     FcPatternEltValues(fe)))   /* font elts */
            return FcFalse;
     }
     return FcTrue;
 }
 
-static FcChar32
-FcListStringHash (const FcChar8        *s)
-{
-    FcChar32   h = 0;
-    FcChar8    c;
-
-    while ((c = *s++))
-    {
-       c = FcToLower (c);
-       h = ((h << 3) ^ (h >> 3)) ^ c;
-    }
-    return h;
-}
-
 static FcChar32
 FcListMatrixHash (const FcMatrix *m)
 {
-    int            xx = (int) (m->xx * 100), 
-           xy = (int) (m->xy * 100), 
+    int            xx = (int) (m->xx * 100),
+           xy = (int) (m->xy * 100),
            yx = (int) (m->yx * 100),
            yy = (int) (m->yy * 100);
 
@@ -228,8 +235,9 @@ FcListMatrixHash (const FcMatrix *m)
 }
 
 static FcChar32
-FcListValueHash (FcValue    v)
+FcListValueHash (FcValue    *value)
 {
+    FcValue v = FcValueCanonicalize(value);
     switch (v.type) {
     case FcTypeVoid:
        return 0;
@@ -238,7 +246,7 @@ FcListValueHash (FcValue    v)
     case FcTypeDouble:
        return (FcChar32) (int) v.u.d;
     case FcTypeString:
-       return FcListStringHash (v.u.s);
+       return FcStrHashIgnoreCase (v.u.s);
     case FcTypeBool:
        return (FcChar32) v.u.b;
     case FcTypeMatrix:
@@ -254,14 +262,14 @@ FcListValueHash (FcValue    v)
 }
 
 static FcChar32
-FcListValueListHash (FcValueList    *list)
+FcListValueListHash (FcValueListPtr list)
 {
     FcChar32   h = 0;
-    
-    while (list)
+
+    while (list != NULL)
     {
-       h = h ^ FcListValueHash (list->value);
-       list = list->next;
+       h = h ^ FcListValueHash (&list->value);
+       list = FcValueListNext(list);
     }
     return h;
 }
@@ -276,9 +284,9 @@ FcListPatternHash (FcPattern        *font,
 
     for (n = 0; n < os->nobject; n++)
     {
-       e = FcPatternFindElt (font, os->objects[n]);
+       e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[n]));
        if (e)
-           h = h ^ FcListValueListHash (e->values);
+           h = h ^ FcListValueListHash (FcPatternEltValues(e));
     }
     return h;
 }
@@ -295,7 +303,7 @@ typedef struct _FcListHashTable {
     int                    entries;
     FcListBucket    *buckets[FC_LIST_HASH_SIZE];
 } FcListHashTable;
-    
+
 static void
 FcListHashTableInit (FcListHashTable *table)
 {
@@ -323,6 +331,37 @@ FcListHashTableCleanup (FcListHashTable *table)
     table->entries = 0;
 }
 
+static int
+FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object)
+{
+    FcChar8       *lang = FcGetDefaultLang ();
+    FcPatternElt   *e = FcPatternObjectFindElt (font, object);
+    FcValueListPtr  v;
+    FcValue         value;
+    int             idx = -1;
+    int             i;
+
+    if (e)
+    {
+       for (v = FcPatternEltValues(e), i = 0; v; v = FcValueListNext(v), ++i)
+       {
+           value = FcValueCanonicalize (&v->value);
+
+           if (value.type == FcTypeString)
+           {
+               FcLangResult res = FcLangCompare (value.u.s, lang);
+               if (res == FcLangEqual)
+                   return i;
+
+               if (res == FcLangDifferentCountry && idx < 0)
+                   idx = i;
+           }
+       }
+    }
+
+    return (idx > 0) ? idx : 0;
+}
+
 static FcBool
 FcListAppend (FcListHashTable  *table,
              FcPattern         *font,
@@ -330,15 +369,20 @@ FcListAppend (FcListHashTable     *table,
 {
     int                    o;
     FcPatternElt    *e;
-    FcValueList            *v;
+    FcValueListPtr  v;
     FcChar32       hash;
     FcListBucket    **prev, *bucket;
+    int             familyidx = -1;
+    int             fullnameidx = -1;
+    int             styleidx = -1;
+    int             defidx = 0;
+    int             idx;
 
     hash = FcListPatternHash (font, os);
     for (prev = &table->buckets[hash % FC_LIST_HASH_SIZE];
         (bucket = *prev); prev = &(bucket->next))
     {
-       if (bucket->hash == hash && 
+       if (bucket->hash == hash &&
            FcListPatternEqual (bucket->pattern, font, os))
            return FcTrue;
     }
@@ -351,17 +395,39 @@ FcListAppend (FcListHashTable     *table,
     bucket->pattern = FcPatternCreate ();
     if (!bucket->pattern)
        goto bail1;
-    
+
     for (o = 0; o < os->nobject; o++)
     {
-       e = FcPatternFindElt (font, os->objects[o]);
+       if (!strcmp (os->objects[o], FC_FAMILY) || !strcmp (os->objects[o], FC_FAMILYLANG))
+       {
+           if (familyidx < 0)
+               familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT);
+           defidx = familyidx;
+       }
+       else if (!strcmp (os->objects[o], FC_FULLNAME) || !strcmp (os->objects[o], FC_FULLNAMELANG))
+       {
+           if (fullnameidx < 0)
+               fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT);
+           defidx = fullnameidx;
+       }
+       else if (!strcmp (os->objects[o], FC_STYLE) || !strcmp (os->objects[o], FC_STYLELANG))
+       {
+           if (styleidx < 0)
+               styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT);
+           defidx = styleidx;
+       }
+       else
+           defidx = 0;
+
+       e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o]));
        if (e)
        {
-           for (v = e->values; v; v = v->next)
+           for (v = FcPatternEltValues(e), idx = 0; v;
+                v = FcValueListNext(v), ++idx)
            {
-               if (!FcPatternAdd (bucket->pattern, 
-                                  os->objects[o], 
-                                  v->value, FcTrue))
+               if (!FcPatternAdd (bucket->pattern,
+                                  os->objects[o],
+                                  FcValueCanonicalize(&v->value), defidx != idx))
                    goto bail2;
            }
        }
@@ -370,7 +436,7 @@ FcListAppend (FcListHashTable       *table,
     ++table->entries;
 
     return FcTrue;
-    
+
 bail2:
     FcPatternDestroy (bucket->pattern);
 bail1:
@@ -394,6 +460,7 @@ FcFontSetList (FcConfig         *config,
     FcListHashTable table;
     int                    i;
     FcListBucket    *bucket;
+    int             destroy_os = 0;
 
     if (!config)
     {
@@ -405,6 +472,13 @@ FcFontSetList (FcConfig        *config,
            goto bail0;
     }
     FcListHashTableInit (&table);
+
+    if (!os)
+    {
+       os = FcObjectGetSet ();
+       destroy_os = 1;
+    }
+
     /*
      * Walk all available fonts adding those that
      * match to the hash table
@@ -415,7 +489,8 @@ FcFontSetList (FcConfig         *config,
        if (!s)
            continue;
        for (f = 0; f < s->nfont; f++)
-           if (FcListPatternMatchAny (p, s->fonts[f]))
+           if (FcListPatternMatchAny (p,               /* pattern */
+                                      s->fonts[f]))    /* font */
                if (!FcListAppend (&table, s->fonts[f], os))
                    goto bail1;
     }
@@ -440,7 +515,7 @@ FcFontSetList (FcConfig         *config,
                full++;
            }
        }
-       printf ("used: %d max: %d avg: %g\n", full, max, 
+       printf ("used: %d max: %d avg: %g\n", full, max,
                (double) ents / FC_LIST_HASH_SIZE);
     }
 #endif
@@ -460,7 +535,7 @@ FcFontSetList (FcConfig         *config,
            FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
            free (bucket);
        }
-    
+
     return ret;
 
 bail2:
@@ -468,6 +543,8 @@ bail2:
 bail1:
     FcListHashTableCleanup (&table);
 bail0:
+    if (destroy_os)
+       FcObjectSetDestroy (os);
     return 0;
 }
 
@@ -481,6 +558,9 @@ FcFontList (FcConfig        *config,
 
     if (!config)
     {
+       if (!FcInitBringUptoDate ())
+           return 0;
+
        config = FcConfigGetCurrent ();
        if (!config)
            return 0;
@@ -492,3 +572,6 @@ FcFontList (FcConfig        *config,
        sets[nsets++] = config->fonts[FcSetApplication];
     return FcFontSetList (config, sets, nsets, p, os);
 }
+#define __fclist__
+#include "fcaliastail.h"
+#undef __fclist__