diff options
Diffstat (limited to 'fontconfig/src/fclist.c')
-rw-r--r-- | fontconfig/src/fclist.c | 1154 |
1 files changed, 577 insertions, 577 deletions
diff --git a/fontconfig/src/fclist.c b/fontconfig/src/fclist.c index d804c1503..0f9a1235c 100644 --- a/fontconfig/src/fclist.c +++ b/fontconfig/src/fclist.c @@ -1,577 +1,577 @@ -/* - * fontconfig/src/fclist.c - * - * 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 - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * 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 <stdlib.h> - -FcObjectSet * -FcObjectSetCreate (void) -{ - FcObjectSet *os; - - os = (FcObjectSet *) malloc (sizeof (FcObjectSet)); - if (!os) - return 0; - FcMemAlloc (FC_MEM_OBJECTSET, sizeof (FcObjectSet)); - os->nobject = 0; - os->sobject = 0; - os->objects = 0; - return os; -} - -FcBool -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; - if (os->objects) - objects = (const char **) realloc ((void *) os->objects, - s * sizeof (const char *)); - else - objects = (const char **) malloc (s * sizeof (const char *)); - if (!objects) - return FcFalse; - if (os->sobject) - FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *)); - FcMemAlloc (FC_MEM_OBJECTPTR, s * sizeof (const char *)); - os->objects = objects; - os->sobject = s; - } - high = os->nobject - 1; - low = 0; - mid = 0; - c = 1; - object = (char *)FcStrStaticName ((FcChar8 *)object); - while (low <= high) - { - mid = (low + high) >> 1; - c = os->objects[mid] - object; - if (c == 0) - return FcTrue; - if (c < 0) - low = mid + 1; - else - high = mid - 1; - } - if (c < 0) - mid++; - memmove (os->objects + mid + 1, os->objects + mid, - (os->nobject - mid) * sizeof (const char *)); - os->objects[mid] = object; - os->nobject++; - return FcTrue; -} - -void -FcObjectSetDestroy (FcObjectSet *os) -{ - if (os->objects) - { - FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *)); - free ((void *) os->objects); - } - FcMemFree (FC_MEM_OBJECTSET, sizeof (FcObjectSet)); - free (os); -} - -FcObjectSet * -FcObjectSetVaBuild (const char *first, va_list va) -{ - FcObjectSet *ret; - - FcObjectSetVapBuild (ret, first, va); - return ret; -} - -FcObjectSet * -FcObjectSetBuild (const char *first, ...) -{ - va_list va; - FcObjectSet *os; - - va_start (va, first); - FcObjectSetVapBuild (os, first, va); - va_end (va); - return os; -} - -/* - * Font must have a containing value for every value in the pattern - */ -static FcBool -FcListValueListMatchAny (FcValueListPtr patOrig, /* pattern */ - FcValueListPtr fntOrig) /* font */ -{ - FcValueListPtr pat, fnt; - - 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 (FcValueListPtr v1orig, - FcValueListPtr v2orig) -{ - FcValueListPtr v1, v2; - - for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1)) - { - for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2)) - if (FcValueEqual (FcValueCanonicalize(&(v1)->value), - FcValueCanonicalize(&(v2)->value))) - break; - if (v2 == NULL) - return FcFalse; - } - for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2)) - { - for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1)) - if (FcValueEqual (FcValueCanonicalize(&v1->value), - FcValueCanonicalize(&v2->value))) - break; - if (v1 == NULL) - return FcFalse; - } - return FcTrue; -} - -static FcBool -FcListPatternEqual (FcPattern *p1, - FcPattern *p2, - FcObjectSet *os) -{ - int i; - FcPatternElt *e1, *e2; - - for (i = 0; i < os->nobject; 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 (FcPatternEltValues(e1), - FcPatternEltValues(e2))) - return FcFalse; - } - return FcTrue; -} - -/* - * FcTrue iff all objects in "p" match "font" - */ - -FcBool -FcListPatternMatchAny (const FcPattern *p, - const FcPattern *font) -{ - int i; - - for (i = 0; i < p->num; i++) - { - FcPatternElt *pe = &FcPatternElts(p)[i]; - FcPatternElt *fe = FcPatternObjectFindElt (font, pe->object); - if (!fe) - return FcFalse; - if (!FcListValueListMatchAny (FcPatternEltValues(pe), /* pat elts */ - FcPatternEltValues(fe))) /* font elts */ - return FcFalse; - } - return FcTrue; -} - -static FcChar32 -FcListMatrixHash (const FcMatrix *m) -{ - int xx = (int) (m->xx * 100), - xy = (int) (m->xy * 100), - yx = (int) (m->yx * 100), - yy = (int) (m->yy * 100); - - return ((FcChar32) xx) ^ ((FcChar32) xy) ^ ((FcChar32) yx) ^ ((FcChar32) yy); -} - -static FcChar32 -FcListValueHash (FcValue *value) -{ - FcValue v = FcValueCanonicalize(value); - switch (v.type) { - case FcTypeVoid: - return 0; - case FcTypeInteger: - return (FcChar32) v.u.i; - case FcTypeDouble: - return (FcChar32) (int) v.u.d; - case FcTypeString: - return FcStrHashIgnoreCase (v.u.s); - case FcTypeBool: - return (FcChar32) v.u.b; - case FcTypeMatrix: - return FcListMatrixHash (v.u.m); - case FcTypeCharSet: - return FcCharSetCount (v.u.c); - case FcTypeFTFace: - return (long) v.u.f; - case FcTypeLangSet: - return FcLangSetHash (v.u.l); - } - return 0; -} - -static FcChar32 -FcListValueListHash (FcValueListPtr list) -{ - FcChar32 h = 0; - - while (list != NULL) - { - h = h ^ FcListValueHash (&list->value); - list = FcValueListNext(list); - } - return h; -} - -static FcChar32 -FcListPatternHash (FcPattern *font, - FcObjectSet *os) -{ - int n; - FcPatternElt *e; - FcChar32 h = 0; - - for (n = 0; n < os->nobject; n++) - { - e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[n])); - if (e) - h = h ^ FcListValueListHash (FcPatternEltValues(e)); - } - return h; -} - -typedef struct _FcListBucket { - struct _FcListBucket *next; - FcChar32 hash; - FcPattern *pattern; -} FcListBucket; - -#define FC_LIST_HASH_SIZE 4099 - -typedef struct _FcListHashTable { - int entries; - FcListBucket *buckets[FC_LIST_HASH_SIZE]; -} FcListHashTable; - -static void -FcListHashTableInit (FcListHashTable *table) -{ - table->entries = 0; - memset (table->buckets, '\0', sizeof (table->buckets)); -} - -static void -FcListHashTableCleanup (FcListHashTable *table) -{ - int i; - FcListBucket *bucket, *next; - - for (i = 0; i < FC_LIST_HASH_SIZE; i++) - { - for (bucket = table->buckets[i]; bucket; bucket = next) - { - next = bucket->next; - FcPatternDestroy (bucket->pattern); - FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket)); - free (bucket); - } - table->buckets[i] = 0; - } - 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, - FcObjectSet *os) -{ - int o; - FcPatternElt *e; - 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 && - FcListPatternEqual (bucket->pattern, font, os)) - return FcTrue; - } - bucket = (FcListBucket *) malloc (sizeof (FcListBucket)); - if (!bucket) - goto bail0; - FcMemAlloc (FC_MEM_LISTBUCK, sizeof (FcListBucket)); - bucket->next = 0; - bucket->hash = hash; - bucket->pattern = FcPatternCreate (); - if (!bucket->pattern) - goto bail1; - - for (o = 0; o < os->nobject; 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 = FcPatternEltValues(e), idx = 0; v; - v = FcValueListNext(v), ++idx) - { - if (!FcPatternAdd (bucket->pattern, - os->objects[o], - FcValueCanonicalize(&v->value), defidx != idx)) - goto bail2; - } - } - } - *prev = bucket; - ++table->entries; - - return FcTrue; - -bail2: - FcPatternDestroy (bucket->pattern); -bail1: - FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket)); - free (bucket); -bail0: - return FcFalse; -} - -FcFontSet * -FcFontSetList (FcConfig *config, - FcFontSet **sets, - int nsets, - FcPattern *p, - FcObjectSet *os) -{ - FcFontSet *ret; - FcFontSet *s; - int f; - int set; - FcListHashTable table; - int i; - FcListBucket *bucket; - int destroy_os = 0; - - if (!config) - { - if (!FcInitBringUptoDate ()) - goto bail0; - - config = FcConfigGetCurrent (); - if (!config) - goto bail0; - } - FcListHashTableInit (&table); - - if (!os) - { - os = FcObjectGetSet (); - destroy_os = 1; - } - - /* - * Walk all available fonts adding those that - * match to the hash table - */ - for (set = 0; set < nsets; set++) - { - s = sets[set]; - if (!s) - continue; - for (f = 0; f < s->nfont; f++) - if (FcListPatternMatchAny (p, /* pattern */ - s->fonts[f])) /* font */ - if (!FcListAppend (&table, s->fonts[f], os)) - goto bail1; - } -#if 0 - { - int max = 0; - int full = 0; - int ents = 0; - int len; - for (i = 0; i < FC_LIST_HASH_SIZE; i++) - { - if ((bucket = table.buckets[i])) - { - len = 0; - for (; bucket; bucket = bucket->next) - { - ents++; - len++; - } - if (len > max) - max = len; - full++; - } - } - printf ("used: %d max: %d avg: %g\n", full, max, - (double) ents / FC_LIST_HASH_SIZE); - } -#endif - /* - * Walk the hash table and build - * a font set - */ - ret = FcFontSetCreate (); - if (!ret) - goto bail0; - for (i = 0; i < FC_LIST_HASH_SIZE; i++) - while ((bucket = table.buckets[i])) - { - if (!FcFontSetAdd (ret, bucket->pattern)) - goto bail2; - table.buckets[i] = bucket->next; - FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket)); - free (bucket); - } - - return ret; - -bail2: - FcFontSetDestroy (ret); -bail1: - FcListHashTableCleanup (&table); -bail0: - if (destroy_os) - FcObjectSetDestroy (os); - return 0; -} - -FcFontSet * -FcFontList (FcConfig *config, - FcPattern *p, - FcObjectSet *os) -{ - FcFontSet *sets[2]; - int nsets; - - if (!config) - { - if (!FcInitBringUptoDate ()) - return 0; - - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - nsets = 0; - if (config->fonts[FcSetSystem]) - sets[nsets++] = config->fonts[FcSetSystem]; - if (config->fonts[FcSetApplication]) - sets[nsets++] = config->fonts[FcSetApplication]; - return FcFontSetList (config, sets, nsets, p, os); -} -#define __fclist__ -#include "fcaliastail.h" -#undef __fclist__ +/*
+ * fontconfig/src/fclist.c
+ *
+ * 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 the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * 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.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * 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 <stdlib.h>
+
+FcObjectSet *
+FcObjectSetCreate (void)
+{
+ FcObjectSet *os;
+
+ os = (FcObjectSet *) malloc (sizeof (FcObjectSet));
+ if (!os)
+ return 0;
+ FcMemAlloc (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
+ os->nobject = 0;
+ os->sobject = 0;
+ os->objects = 0;
+ return os;
+}
+
+FcBool
+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;
+ if (os->objects)
+ objects = (const char **) realloc ((void *) os->objects,
+ s * sizeof (const char *));
+ else
+ objects = (const char **) malloc (s * sizeof (const char *));
+ if (!objects)
+ return FcFalse;
+ if (os->sobject)
+ FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
+ FcMemAlloc (FC_MEM_OBJECTPTR, s * sizeof (const char *));
+ os->objects = objects;
+ os->sobject = s;
+ }
+ high = os->nobject - 1;
+ low = 0;
+ mid = 0;
+ c = 1;
+ object = (char *)FcStrStaticName ((FcChar8 *)object);
+ while (low <= high)
+ {
+ mid = (low + high) >> 1;
+ c = os->objects[mid] - object;
+ if (c == 0)
+ return FcTrue;
+ if (c < 0)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+ if (c < 0)
+ mid++;
+ memmove (os->objects + mid + 1, os->objects + mid,
+ (os->nobject - mid) * sizeof (const char *));
+ os->objects[mid] = object;
+ os->nobject++;
+ return FcTrue;
+}
+
+void
+FcObjectSetDestroy (FcObjectSet *os)
+{
+ if (os->objects)
+ {
+ FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
+ free ((void *) os->objects);
+ }
+ FcMemFree (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
+ free (os);
+}
+
+FcObjectSet *
+FcObjectSetVaBuild (const char *first, va_list va)
+{
+ FcObjectSet *ret;
+
+ FcObjectSetVapBuild (ret, first, va);
+ return ret;
+}
+
+FcObjectSet *
+FcObjectSetBuild (const char *first, ...)
+{
+ va_list va;
+ FcObjectSet *os;
+
+ va_start (va, first);
+ FcObjectSetVapBuild (os, first, va);
+ va_end (va);
+ return os;
+}
+
+/*
+ * Font must have a containing value for every value in the pattern
+ */
+static FcBool
+FcListValueListMatchAny (FcValueListPtr patOrig, /* pattern */
+ FcValueListPtr fntOrig) /* font */
+{
+ FcValueListPtr pat, fnt;
+
+ 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 (FcValueListPtr v1orig,
+ FcValueListPtr v2orig)
+{
+ FcValueListPtr v1, v2;
+
+ for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
+ {
+ for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
+ if (FcValueEqual (FcValueCanonicalize(&(v1)->value),
+ FcValueCanonicalize(&(v2)->value)))
+ break;
+ if (v2 == NULL)
+ return FcFalse;
+ }
+ for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
+ {
+ for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
+ if (FcValueEqual (FcValueCanonicalize(&v1->value),
+ FcValueCanonicalize(&v2->value)))
+ break;
+ if (v1 == NULL)
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+static FcBool
+FcListPatternEqual (FcPattern *p1,
+ FcPattern *p2,
+ FcObjectSet *os)
+{
+ int i;
+ FcPatternElt *e1, *e2;
+
+ for (i = 0; i < os->nobject; 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 (FcPatternEltValues(e1),
+ FcPatternEltValues(e2)))
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+/*
+ * FcTrue iff all objects in "p" match "font"
+ */
+
+FcBool
+FcListPatternMatchAny (const FcPattern *p,
+ const FcPattern *font)
+{
+ int i;
+
+ for (i = 0; i < p->num; i++)
+ {
+ FcPatternElt *pe = &FcPatternElts(p)[i];
+ FcPatternElt *fe = FcPatternObjectFindElt (font, pe->object);
+ if (!fe)
+ return FcFalse;
+ if (!FcListValueListMatchAny (FcPatternEltValues(pe), /* pat elts */
+ FcPatternEltValues(fe))) /* font elts */
+ return FcFalse;
+ }
+ return FcTrue;
+}
+
+static FcChar32
+FcListMatrixHash (const FcMatrix *m)
+{
+ int xx = (int) (m->xx * 100),
+ xy = (int) (m->xy * 100),
+ yx = (int) (m->yx * 100),
+ yy = (int) (m->yy * 100);
+
+ return ((FcChar32) xx) ^ ((FcChar32) xy) ^ ((FcChar32) yx) ^ ((FcChar32) yy);
+}
+
+static FcChar32
+FcListValueHash (FcValue *value)
+{
+ FcValue v = FcValueCanonicalize(value);
+ switch (v.type) {
+ case FcTypeVoid:
+ return 0;
+ case FcTypeInteger:
+ return (FcChar32) v.u.i;
+ case FcTypeDouble:
+ return (FcChar32) (int) v.u.d;
+ case FcTypeString:
+ return FcStrHashIgnoreCase (v.u.s);
+ case FcTypeBool:
+ return (FcChar32) v.u.b;
+ case FcTypeMatrix:
+ return FcListMatrixHash (v.u.m);
+ case FcTypeCharSet:
+ return FcCharSetCount (v.u.c);
+ case FcTypeFTFace:
+ return (long) v.u.f;
+ case FcTypeLangSet:
+ return FcLangSetHash (v.u.l);
+ }
+ return 0;
+}
+
+static FcChar32
+FcListValueListHash (FcValueListPtr list)
+{
+ FcChar32 h = 0;
+
+ while (list != NULL)
+ {
+ h = h ^ FcListValueHash (&list->value);
+ list = FcValueListNext(list);
+ }
+ return h;
+}
+
+static FcChar32
+FcListPatternHash (FcPattern *font,
+ FcObjectSet *os)
+{
+ int n;
+ FcPatternElt *e;
+ FcChar32 h = 0;
+
+ for (n = 0; n < os->nobject; n++)
+ {
+ e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[n]));
+ if (e)
+ h = h ^ FcListValueListHash (FcPatternEltValues(e));
+ }
+ return h;
+}
+
+typedef struct _FcListBucket {
+ struct _FcListBucket *next;
+ FcChar32 hash;
+ FcPattern *pattern;
+} FcListBucket;
+
+#define FC_LIST_HASH_SIZE 4099
+
+typedef struct _FcListHashTable {
+ int entries;
+ FcListBucket *buckets[FC_LIST_HASH_SIZE];
+} FcListHashTable;
+
+static void
+FcListHashTableInit (FcListHashTable *table)
+{
+ table->entries = 0;
+ memset (table->buckets, '\0', sizeof (table->buckets));
+}
+
+static void
+FcListHashTableCleanup (FcListHashTable *table)
+{
+ int i;
+ FcListBucket *bucket, *next;
+
+ for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+ {
+ for (bucket = table->buckets[i]; bucket; bucket = next)
+ {
+ next = bucket->next;
+ FcPatternDestroy (bucket->pattern);
+ FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ free (bucket);
+ }
+ table->buckets[i] = 0;
+ }
+ 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,
+ FcObjectSet *os)
+{
+ int o;
+ FcPatternElt *e;
+ 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 &&
+ FcListPatternEqual (bucket->pattern, font, os))
+ return FcTrue;
+ }
+ bucket = (FcListBucket *) malloc (sizeof (FcListBucket));
+ if (!bucket)
+ goto bail0;
+ FcMemAlloc (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ bucket->next = 0;
+ bucket->hash = hash;
+ bucket->pattern = FcPatternCreate ();
+ if (!bucket->pattern)
+ goto bail1;
+
+ for (o = 0; o < os->nobject; 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 = FcPatternEltValues(e), idx = 0; v;
+ v = FcValueListNext(v), ++idx)
+ {
+ if (!FcPatternAdd (bucket->pattern,
+ os->objects[o],
+ FcValueCanonicalize(&v->value), defidx != idx))
+ goto bail2;
+ }
+ }
+ }
+ *prev = bucket;
+ ++table->entries;
+
+ return FcTrue;
+
+bail2:
+ FcPatternDestroy (bucket->pattern);
+bail1:
+ FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ free (bucket);
+bail0:
+ return FcFalse;
+}
+
+FcFontSet *
+FcFontSetList (FcConfig *config,
+ FcFontSet **sets,
+ int nsets,
+ FcPattern *p,
+ FcObjectSet *os)
+{
+ FcFontSet *ret;
+ FcFontSet *s;
+ int f;
+ int set;
+ FcListHashTable table;
+ int i;
+ FcListBucket *bucket;
+ int destroy_os = 0;
+
+ if (!config)
+ {
+ if (!FcInitBringUptoDate ())
+ goto bail0;
+
+ config = FcConfigGetCurrent ();
+ if (!config)
+ goto bail0;
+ }
+ FcListHashTableInit (&table);
+
+ if (!os)
+ {
+ os = FcObjectGetSet ();
+ destroy_os = 1;
+ }
+
+ /*
+ * Walk all available fonts adding those that
+ * match to the hash table
+ */
+ for (set = 0; set < nsets; set++)
+ {
+ s = sets[set];
+ if (!s)
+ continue;
+ for (f = 0; f < s->nfont; f++)
+ if (FcListPatternMatchAny (p, /* pattern */
+ s->fonts[f])) /* font */
+ if (!FcListAppend (&table, s->fonts[f], os))
+ goto bail1;
+ }
+#if 0
+ {
+ int max = 0;
+ int full = 0;
+ int ents = 0;
+ int len;
+ for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+ {
+ if ((bucket = table.buckets[i]))
+ {
+ len = 0;
+ for (; bucket; bucket = bucket->next)
+ {
+ ents++;
+ len++;
+ }
+ if (len > max)
+ max = len;
+ full++;
+ }
+ }
+ printf ("used: %d max: %d avg: %g\n", full, max,
+ (double) ents / FC_LIST_HASH_SIZE);
+ }
+#endif
+ /*
+ * Walk the hash table and build
+ * a font set
+ */
+ ret = FcFontSetCreate ();
+ if (!ret)
+ goto bail0;
+ for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+ while ((bucket = table.buckets[i]))
+ {
+ if (!FcFontSetAdd (ret, bucket->pattern))
+ goto bail2;
+ table.buckets[i] = bucket->next;
+ FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+ free (bucket);
+ }
+
+ return ret;
+
+bail2:
+ FcFontSetDestroy (ret);
+bail1:
+ FcListHashTableCleanup (&table);
+bail0:
+ if (destroy_os)
+ FcObjectSetDestroy (os);
+ return 0;
+}
+
+FcFontSet *
+FcFontList (FcConfig *config,
+ FcPattern *p,
+ FcObjectSet *os)
+{
+ FcFontSet *sets[2];
+ int nsets;
+
+ if (!config)
+ {
+ if (!FcInitBringUptoDate ())
+ return 0;
+
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ nsets = 0;
+ if (config->fonts[FcSetSystem])
+ sets[nsets++] = config->fonts[FcSetSystem];
+ if (config->fonts[FcSetApplication])
+ sets[nsets++] = config->fonts[FcSetApplication];
+ return FcFontSetList (config, sets, nsets, p, os);
+}
+#define __fclist__
+#include "fcaliastail.h"
+#undef __fclist__
|