| /* |
| * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.16tsi Exp $ |
| * |
| * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. |
| * |
| * 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. |
| * |
| * KEITH PACKARD 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 |
| * 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 <string.h> |
| #include <assert.h> |
| #include "fcint.h" |
| |
| FcPattern * |
| FcPatternCreate (void) |
| { |
| FcPattern *p; |
| |
| p = (FcPattern *) malloc (sizeof (FcPattern)); |
| if (!p) |
| return 0; |
| FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern)); |
| p->num = 0; |
| p->size = 0; |
| p->elts = 0; |
| p->ref = 1; |
| return p; |
| } |
| |
| void |
| FcValueDestroy (FcValue v) |
| { |
| switch (v.type) { |
| case FcTypeString: |
| FcStrFree ((FcChar8 *) v.u.s); |
| break; |
| case FcTypeMatrix: |
| FcMatrixFree ((FcMatrix *) v.u.m); |
| break; |
| case FcTypeCharSet: |
| FcCharSetDestroy ((FcCharSet *) v.u.c); |
| break; |
| case FcTypeLangSet: |
| FcLangSetDestroy ((FcLangSet *) v.u.l); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| FcValue |
| FcValueSave (FcValue v) |
| { |
| switch (v.type) { |
| case FcTypeString: |
| v.u.s = FcStrCopy (v.u.s); |
| if (!v.u.s) |
| v.type = FcTypeVoid; |
| break; |
| case FcTypeMatrix: |
| v.u.m = FcMatrixCopy (v.u.m); |
| if (!v.u.m) |
| v.type = FcTypeVoid; |
| break; |
| case FcTypeCharSet: |
| v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c); |
| if (!v.u.c) |
| v.type = FcTypeVoid; |
| break; |
| case FcTypeLangSet: |
| v.u.l = FcLangSetCopy (v.u.l); |
| if (!v.u.l) |
| v.type = FcTypeVoid; |
| break; |
| default: |
| break; |
| } |
| return v; |
| } |
| |
| void |
| FcValueListDestroy (FcValueList *l) |
| { |
| FcValueList *next; |
| for (; l; l = next) |
| { |
| switch (l->value.type) { |
| case FcTypeString: |
| FcStrFree ((FcChar8 *) l->value.u.s); |
| break; |
| case FcTypeMatrix: |
| FcMatrixFree ((FcMatrix *) l->value.u.m); |
| break; |
| case FcTypeCharSet: |
| FcCharSetDestroy ((FcCharSet *) l->value.u.c); |
| break; |
| case FcTypeLangSet: |
| FcLangSetDestroy ((FcLangSet *) l->value.u.l); |
| break; |
| default: |
| break; |
| } |
| next = l->next; |
| FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); |
| free (l); |
| } |
| } |
| |
| FcBool |
| FcValueEqual (FcValue va, FcValue vb) |
| { |
| if (va.type != vb.type) |
| { |
| if (va.type == FcTypeInteger) |
| { |
| va.type = FcTypeDouble; |
| va.u.d = va.u.i; |
| } |
| if (vb.type == FcTypeInteger) |
| { |
| vb.type = FcTypeDouble; |
| vb.u.d = vb.u.i; |
| } |
| if (va.type != vb.type) |
| return FcFalse; |
| } |
| switch (va.type) { |
| case FcTypeVoid: |
| return FcTrue; |
| case FcTypeInteger: |
| return va.u.i == vb.u.i; |
| case FcTypeDouble: |
| return va.u.d == vb.u.d; |
| case FcTypeString: |
| return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0; |
| case FcTypeBool: |
| return va.u.b == vb.u.b; |
| case FcTypeMatrix: |
| return FcMatrixEqual (va.u.m, vb.u.m); |
| case FcTypeCharSet: |
| return FcCharSetEqual (va.u.c, vb.u.c); |
| case FcTypeFTFace: |
| return va.u.f == vb.u.f; |
| case FcTypeLangSet: |
| return FcLangSetEqual (va.u.l, vb.u.l); |
| } |
| return FcFalse; |
| } |
| |
| static FcChar32 |
| FcDoubleHash (double d) |
| { |
| if (d < 0) |
| d = -d; |
| if (d > 0xffffffff) |
| d = 0xffffffff; |
| return (FcChar32) d; |
| } |
| |
| static FcChar32 |
| FcStringHash (const FcChar8 *s) |
| { |
| FcChar8 c; |
| FcChar32 h = 0; |
| |
| if (s) |
| while ((c = *s++)) |
| h = ((h << 1) | (h >> 31)) ^ c; |
| return h; |
| } |
| |
| static FcChar32 |
| FcValueHash (FcValue v) |
| { |
| switch (v.type) { |
| case FcTypeVoid: |
| return 0; |
| case FcTypeInteger: |
| return (FcChar32) v.u.i; |
| case FcTypeDouble: |
| return FcDoubleHash (v.u.d); |
| case FcTypeString: |
| return FcStringHash (v.u.s); |
| case FcTypeBool: |
| return (FcChar32) v.u.b; |
| case FcTypeMatrix: |
| return (FcDoubleHash (v.u.m->xx) ^ |
| FcDoubleHash (v.u.m->xy) ^ |
| FcDoubleHash (v.u.m->yx) ^ |
| FcDoubleHash (v.u.m->yy)); |
| case FcTypeCharSet: |
| return (FcChar32) v.u.c->num; |
| case FcTypeFTFace: |
| return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^ |
| FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name); |
| case FcTypeLangSet: |
| return FcLangSetHash (v.u.l); |
| } |
| return FcFalse; |
| } |
| |
| static FcBool |
| FcValueListEqual (FcValueList *la, FcValueList *lb) |
| { |
| if (la == lb) |
| return FcTrue; |
| |
| while (la && lb) |
| { |
| if (!FcValueEqual (la->value, lb->value)) |
| return FcFalse; |
| la = la->next; |
| lb = lb->next; |
| } |
| if (la || lb) |
| return FcFalse; |
| return FcTrue; |
| } |
| |
| static FcChar32 |
| FcValueListHash (FcValueList *l) |
| { |
| FcChar32 hash = 0; |
| |
| while (l) |
| { |
| hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value); |
| l = l->next; |
| } |
| return hash; |
| } |
| |
| void |
| FcPatternDestroy (FcPattern *p) |
| { |
| int i; |
| |
| if (p->ref == FC_REF_CONSTANT || --p->ref > 0) |
| return; |
| |
| for (i = 0; i < p->num; i++) |
| FcValueListDestroy (p->elts[i].values); |
| |
| p->num = 0; |
| if (p->elts) |
| { |
| FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt)); |
| free (p->elts); |
| p->elts = 0; |
| } |
| p->size = 0; |
| FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern)); |
| free (p); |
| } |
| |
| #define FC_VALUE_LIST_HASH_SIZE 257 |
| #define FC_PATTERN_HASH_SIZE 67 |
| |
| typedef struct _FcValueListEnt FcValueListEnt; |
| |
| struct _FcValueListEnt { |
| FcValueListEnt *next; |
| FcValueList *list; |
| FcChar32 hash, pad; |
| }; |
| |
| static int FcValueListFrozenCount[FcTypeLangSet + 1]; |
| static int FcValueListFrozenBytes[FcTypeLangSet + 1]; |
| static char *FcValueListFrozenName[] = { |
| "Void", |
| "Integer", |
| "Double", |
| "String", |
| "Bool", |
| "Matrix", |
| "CharSet", |
| "FTFace", |
| "LangSet" |
| }; |
| |
| void |
| FcValueListReport (void); |
| |
| void |
| FcValueListReport (void) |
| { |
| FcType t; |
| |
| printf ("Fc Frozen Values:\n"); |
| printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes"); |
| for (t = FcTypeVoid; t <= FcTypeLangSet; t++) |
| printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t], |
| FcValueListFrozenCount[t], FcValueListFrozenBytes[t]); |
| } |
| |
| static FcValueListEnt * |
| FcValueListEntCreate (FcValueList *h) |
| { |
| FcValueListEnt *e; |
| FcValueList *l, *new; |
| int n; |
| int string_size = 0; |
| FcChar8 *strs; |
| int size; |
| |
| n = 0; |
| for (l = h; l; l = l->next) |
| { |
| if (l->value.type == FcTypeString) |
| string_size += strlen ((char *) l->value.u.s) + 1; |
| n++; |
| } |
| size = sizeof (FcValueListEnt) + n * sizeof (FcValueList) + string_size; |
| FcValueListFrozenCount[h->value.type]++; |
| FcValueListFrozenBytes[h->value.type] += size; |
| e = malloc (size); |
| if (!e) |
| return 0; |
| FcMemAlloc (FC_MEM_VALLIST, size); |
| e->list = (FcValueList *) (e + 1); |
| strs = (FcChar8 *) (e->list + n); |
| new = e->list; |
| for (l = h; l; l = l->next, new++) |
| { |
| if (l->value.type == FcTypeString) |
| { |
| new->value.type = FcTypeString; |
| new->value.u.s = strs; |
| strcpy ((char *) strs, (char *) l->value.u.s); |
| strs += strlen ((char *) strs) + 1; |
| } |
| else |
| { |
| new->value = l->value; |
| new->value = FcValueSave (new->value); |
| } |
| new->binding = l->binding; |
| if (l->next) |
| new->next = new + 1; |
| else |
| new->next = 0; |
| } |
| return e; |
| } |
| |
| static int FcValueListTotal; |
| static int FcValueListUsed; |
| |
| static FcValueList * |
| FcValueListFreeze (FcValueList *l) |
| { |
| static FcValueListEnt *hashTable[FC_VALUE_LIST_HASH_SIZE]; |
| FcChar32 hash = FcValueListHash (l); |
| FcValueListEnt **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE]; |
| FcValueListEnt *ent; |
| |
| FcValueListTotal++; |
| for (ent = *bucket; ent; ent = ent->next) |
| { |
| if (ent->hash == hash && FcValueListEqual (ent->list, l)) |
| return ent->list; |
| } |
| |
| ent = FcValueListEntCreate (l); |
| if (!ent) |
| return 0; |
| |
| FcValueListUsed++; |
| ent->hash = hash; |
| ent->next = *bucket; |
| *bucket = ent; |
| return ent->list; |
| } |
| |
| static FcChar32 |
| FcPatternBaseHash (FcPattern *b) |
| { |
| FcChar32 hash = b->num; |
| int i; |
| |
| for (i = 0; i < b->num; i++) |
| hash = ((hash << 1) | (hash >> 31)) ^ ((FcChar32) b->elts[i].values); |
| return hash; |
| } |
| |
| typedef struct _FcPatternEnt FcPatternEnt; |
| |
| struct _FcPatternEnt { |
| FcPatternEnt *next; |
| FcChar32 hash; |
| FcPattern pattern; |
| }; |
| |
| static int FcPatternTotal; |
| static int FcPatternUsed; |
| |
| static FcPattern * |
| FcPatternBaseFreeze (FcPattern *b) |
| { |
| static FcPatternEnt *hashTable[FC_VALUE_LIST_HASH_SIZE]; |
| FcChar32 hash = FcPatternBaseHash (b); |
| FcPatternEnt **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE]; |
| FcPatternEnt *ent; |
| int i; |
| char *objects; |
| int size_objects; |
| int size; |
| |
| FcPatternTotal++; |
| for (ent = *bucket; ent; ent = ent->next) |
| { |
| if (ent->hash == hash && b->num == ent->pattern.num) |
| { |
| for (i = 0; i < b->num; i++) |
| { |
| if (strcmp (b->elts[i].object, ent->pattern.elts[i].object)) |
| break; |
| if (b->elts[i].values != ent->pattern.elts[i].values) |
| break; |
| } |
| if (i == b->num) |
| return &ent->pattern; |
| } |
| } |
| |
| /* |
| * Compute size of pattern + elts + object names |
| */ |
| size_objects = 0; |
| for (i = 0; i < b->num; i++) |
| size_objects += strlen (b->elts[i].object) + 1; |
| |
| size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt) + size_objects; |
| ent = malloc (size); |
| if (!ent) |
| return 0; |
| |
| FcMemAlloc (FC_MEM_PATTERN, size); |
| FcPatternUsed++; |
| |
| ent->pattern.elts = (FcPatternElt *) (ent + 1); |
| ent->pattern.num = b->num; |
| ent->pattern.size = b->num; |
| ent->pattern.ref = FC_REF_CONSTANT; |
| |
| objects = (char *) (ent->pattern.elts + b->num); |
| for (i = 0; i < b->num; i++) |
| { |
| ent->pattern.elts[i].values = b->elts[i].values; |
| strcpy (objects, b->elts[i].object); |
| ent->pattern.elts[i].object = objects; |
| objects += strlen (objects) + 1; |
| } |
| |
| ent->hash = hash; |
| ent->next = *bucket; |
| *bucket = ent; |
| return &ent->pattern; |
| } |
| |
| FcPattern * |
| FcPatternFreeze (FcPattern *p) |
| { |
| FcPattern *b, *n = 0; |
| int size; |
| int i; |
| |
| size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt); |
| b = (FcPattern *) malloc (size); |
| if (!b) |
| return 0; |
| FcMemAlloc (FC_MEM_PATTERN, size); |
| b->num = p->num; |
| b->size = b->num; |
| b->ref = 1; |
| b->elts = (FcPatternElt *) (b + 1); |
| /* |
| * Freeze object lists |
| */ |
| for (i = 0; i < p->num; i++) |
| { |
| b->elts[i].object = p->elts[i].object; |
| b->elts[i].values = FcValueListFreeze (p->elts[i].values); |
| if (!b->elts[i].values) |
| goto bail; |
| } |
| /* |
| * Freeze base |
| */ |
| n = FcPatternBaseFreeze (b); |
| #ifdef CHATTY |
| if (FcDebug() & FC_DBG_MEMORY) |
| { |
| printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed); |
| printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed); |
| } |
| #endif |
| bail: |
| free (b); |
| #ifdef DEBUG |
| assert (FcPatternEqual (n, p)); |
| #endif |
| return n; |
| } |
| |
| static int |
| FcPatternPosition (const FcPattern *p, const char *object) |
| { |
| int low, high, mid, c; |
| |
| low = 0; |
| high = p->num - 1; |
| c = 1; |
| mid = 0; |
| while (low <= high) |
| { |
| mid = (low + high) >> 1; |
| c = strcmp (p->elts[mid].object, object); |
| if (c == 0) |
| return mid; |
| if (c < 0) |
| low = mid + 1; |
| else |
| high = mid - 1; |
| } |
| if (c < 0) |
| mid++; |
| return -(mid + 1); |
| } |
| |
| FcPatternElt * |
| FcPatternFindElt (const FcPattern *p, const char *object) |
| { |
| int i = FcPatternPosition (p, object); |
| if (i < 0) |
| return 0; |
| return &p->elts[i]; |
| } |
| |
| FcPatternElt * |
| FcPatternInsertElt (FcPattern *p, const char *object) |
| { |
| int i; |
| FcPatternElt *e; |
| |
| i = FcPatternPosition (p, object); |
| if (i < 0) |
| { |
| i = -i - 1; |
| |
| /* grow array */ |
| if (p->num + 1 >= p->size) |
| { |
| int s = p->size + 16; |
| if (p->elts) |
| e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt)); |
| else |
| e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt)); |
| if (!e) |
| return FcFalse; |
| p->elts = e; |
| if (p->size) |
| FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt)); |
| FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt)); |
| while (p->size < s) |
| { |
| p->elts[p->size].object = 0; |
| p->elts[p->size].values = 0; |
| p->size++; |
| } |
| } |
| |
| /* move elts up */ |
| memmove (p->elts + i + 1, |
| p->elts + i, |
| sizeof (FcPatternElt) * |
| (p->num - i)); |
| |
| /* bump count */ |
| p->num++; |
| |
| p->elts[i].object = object; |
| p->elts[i].values = 0; |
| } |
| |
| return &p->elts[i]; |
| } |
| |
| FcBool |
| FcPatternEqual (const FcPattern *pa, const FcPattern *pb) |
| { |
| int i; |
| |
| if (pa == pb) |
| return FcTrue; |
| |
| if (pa->num != pb->num) |
| return FcFalse; |
| for (i = 0; i < pa->num; i++) |
| { |
| if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0) |
| return FcFalse; |
| if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values)) |
| return FcFalse; |
| } |
| return FcTrue; |
| } |
| |
| FcChar32 |
| FcPatternHash (const FcPattern *p) |
| { |
| int i; |
| FcChar32 h = 0; |
| |
| for (i = 0; i < p->num; i++) |
| { |
| h = (((h << 1) | (h >> 31)) ^ |
| FcStringHash ((const FcChar8 *) p->elts[i].object) ^ |
| FcValueListHash (p->elts[i].values)); |
| } |
| return h; |
| } |
| |
| FcBool |
| FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os) |
| { |
| FcPatternElt *ea, *eb; |
| int i; |
| |
| for (i = 0; i < os->nobject; i++) |
| { |
| ea = FcPatternFindElt (pa, os->objects[i]); |
| eb = FcPatternFindElt (pb, os->objects[i]); |
| if (ea) |
| { |
| if (!eb) |
| return FcFalse; |
| if (!FcValueListEqual (ea->values, eb->values)) |
| return FcFalse; |
| } |
| else |
| { |
| if (eb) |
| return FcFalse; |
| } |
| } |
| return FcTrue; |
| } |
| |
| FcBool |
| FcPatternAddWithBinding (FcPattern *p, |
| const char *object, |
| FcValue value, |
| FcValueBinding binding, |
| FcBool append) |
| { |
| FcPatternElt *e; |
| FcValueList *new, **prev; |
| |
| if (p->ref == FC_REF_CONSTANT) |
| goto bail0; |
| |
| new = (FcValueList *) malloc (sizeof (FcValueList)); |
| if (!new) |
| goto bail0; |
| |
| FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); |
| /* dup string */ |
| value = FcValueSave (value); |
| if (value.type == FcTypeVoid) |
| goto bail1; |
| |
| new->value = value; |
| new->binding = binding; |
| new->next = 0; |
| |
| e = FcPatternInsertElt (p, object); |
| if (!e) |
| goto bail2; |
| |
| if (append) |
| { |
| for (prev = &e->values; *prev; prev = &(*prev)->next); |
| *prev = new; |
| } |
| else |
| { |
| new->next = e->values; |
| e->values = new; |
| } |
| |
| return FcTrue; |
| |
| bail2: |
| switch (value.type) { |
| case FcTypeString: |
| FcStrFree ((FcChar8 *) value.u.s); |
| break; |
| case FcTypeMatrix: |
| FcMatrixFree ((FcMatrix *) value.u.m); |
| break; |
| case FcTypeCharSet: |
| FcCharSetDestroy ((FcCharSet *) value.u.c); |
| break; |
| case FcTypeLangSet: |
| FcLangSetDestroy ((FcLangSet *) value.u.l); |
| break; |
| default: |
| break; |
| } |
| bail1: |
| FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); |
| free (new); |
| bail0: |
| return FcFalse; |
| } |
| |
| FcBool |
| FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append) |
| { |
| return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append); |
| } |
| |
| FcBool |
| FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append) |
| { |
| return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append); |
| } |
| |
| FcBool |
| FcPatternDel (FcPattern *p, const char *object) |
| { |
| FcPatternElt *e; |
| int i; |
| |
| e = FcPatternFindElt (p, object); |
| if (!e) |
| return FcFalse; |
| |
| i = e - p->elts; |
| |
| /* destroy value */ |
| FcValueListDestroy (e->values); |
| |
| /* shuffle existing ones down */ |
| memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt)); |
| p->num--; |
| p->elts[p->num].object = 0; |
| p->elts[p->num].values = 0; |
| return FcTrue; |
| } |
| |
| FcBool |
| FcPatternAddInteger (FcPattern *p, const char *object, int i) |
| { |
| FcValue v; |
| |
| v.type = FcTypeInteger; |
| v.u.i = i; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| FcBool |
| FcPatternAddDouble (FcPattern *p, const char *object, double d) |
| { |
| FcValue v; |
| |
| v.type = FcTypeDouble; |
| v.u.d = d; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| |
| FcBool |
| FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s) |
| { |
| FcValue v; |
| |
| v.type = FcTypeString; |
| v.u.s = s; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| FcBool |
| FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s) |
| { |
| FcValue v; |
| |
| v.type = FcTypeMatrix; |
| v.u.m = (FcMatrix *) s; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| |
| FcBool |
| FcPatternAddBool (FcPattern *p, const char *object, FcBool b) |
| { |
| FcValue v; |
| |
| v.type = FcTypeBool; |
| v.u.b = b; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| FcBool |
| FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c) |
| { |
| FcValue v; |
| |
| v.type = FcTypeCharSet; |
| v.u.c = (FcCharSet *) c; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| FcBool |
| FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f) |
| { |
| FcValue v; |
| |
| v.type = FcTypeFTFace; |
| v.u.f = (void *) f; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| FcBool |
| FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls) |
| { |
| FcValue v; |
| |
| v.type = FcTypeLangSet; |
| v.u.l = (FcLangSet *) ls; |
| return FcPatternAdd (p, object, v, FcTrue); |
| } |
| |
| FcResult |
| FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v) |
| { |
| FcPatternElt *e; |
| FcValueList *l; |
| |
| e = FcPatternFindElt (p, object); |
| if (!e) |
| return FcResultNoMatch; |
| for (l = e->values; l; l = l->next) |
| { |
| if (!id) |
| { |
| *v = l->value; |
| return FcResultMatch; |
| } |
| id--; |
| } |
| return FcResultNoId; |
| } |
| |
| FcResult |
| FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| switch (v.type) { |
| case FcTypeDouble: |
| *i = (int) v.u.d; |
| break; |
| case FcTypeInteger: |
| *i = v.u.i; |
| break; |
| default: |
| return FcResultTypeMismatch; |
| } |
| return FcResultMatch; |
| } |
| |
| FcResult |
| FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| switch (v.type) { |
| case FcTypeDouble: |
| *d = v.u.d; |
| break; |
| case FcTypeInteger: |
| *d = (double) v.u.i; |
| break; |
| default: |
| return FcResultTypeMismatch; |
| } |
| return FcResultMatch; |
| } |
| |
| FcResult |
| FcPatternGetString (FcPattern *p, const char *object, int id, FcChar8 ** s) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| if (v.type != FcTypeString) |
| return FcResultTypeMismatch; |
| *s = (FcChar8 *) v.u.s; |
| return FcResultMatch; |
| } |
| |
| FcResult |
| FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| if (v.type != FcTypeMatrix) |
| return FcResultTypeMismatch; |
| *m = (FcMatrix *) v.u.m; |
| return FcResultMatch; |
| } |
| |
| |
| FcResult |
| FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| if (v.type != FcTypeBool) |
| return FcResultTypeMismatch; |
| *b = v.u.b; |
| return FcResultMatch; |
| } |
| |
| FcResult |
| FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| if (v.type != FcTypeCharSet) |
| return FcResultTypeMismatch; |
| *c = (FcCharSet *) v.u.c; |
| return FcResultMatch; |
| } |
| |
| FcResult |
| FcPatternGetFTFace (FcPattern *p, const char *object, int id, FT_Face *f) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| if (v.type != FcTypeFTFace) |
| return FcResultTypeMismatch; |
| *f = (FT_Face) v.u.f; |
| return FcResultMatch; |
| } |
| |
| FcResult |
| FcPatternGetLangSet (FcPattern *p, const char *object, int id, FcLangSet **ls) |
| { |
| FcValue v; |
| FcResult r; |
| |
| r = FcPatternGet (p, object, id, &v); |
| if (r != FcResultMatch) |
| return r; |
| if (v.type != FcTypeLangSet) |
| return FcResultTypeMismatch; |
| *ls = (FcLangSet *) v.u.l; |
| return FcResultMatch; |
| } |
| |
| FcPattern * |
| FcPatternDuplicate (FcPattern *orig) |
| { |
| FcPattern *new; |
| int i; |
| FcValueList *l; |
| |
| new = FcPatternCreate (); |
| if (!new) |
| goto bail0; |
| |
| for (i = 0; i < orig->num; i++) |
| { |
| for (l = orig->elts[i].values; l; l = l->next) |
| if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue)) |
| goto bail1; |
| } |
| |
| return new; |
| |
| bail1: |
| FcPatternDestroy (new); |
| bail0: |
| return 0; |
| } |
| |
| void |
| FcPatternReference (FcPattern *p) |
| { |
| if (p->ref != FC_REF_CONSTANT) |
| p->ref++; |
| } |
| |
| FcPattern * |
| FcPatternVaBuild (FcPattern *orig, va_list va) |
| { |
| FcPattern *ret; |
| |
| FcPatternVapBuild (ret, orig, va); |
| return ret; |
| } |
| |
| FcPattern * |
| FcPatternBuild (FcPattern *orig, ...) |
| { |
| va_list va; |
| |
| va_start (va, orig); |
| FcPatternVapBuild (orig, orig, va); |
| va_end (va); |
| return orig; |
| } |