/* * 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 "fcftint.h" /* Objects MT-safe for readonly access. */ FcPattern * FcPatternCreate (void) { FcPattern *p; p = (FcPattern *) malloc (sizeof (FcPattern)); if (!p) return 0; memset (p, 0, sizeof (FcPattern)); p->num = 0; p->size = 0; p->elts_offset = FcPtrToOffset (p, NULL); FcRefInit (&p->ref, 1); return p; } void FcValueDestroy (FcValue v) { switch ((int) v.type) { case FcTypeString: FcFree (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; case FcTypeRange: FcRangeDestroy ((FcRange *) v.u.r); break; default: break; } } FcValue FcValueCanonicalize (const FcValue *v) { FcValue new; switch ((int) v->type) { case FcTypeString: new.u.s = FcValueString(v); new.type = FcTypeString; break; case FcTypeCharSet: new.u.c = FcValueCharSet(v); new.type = FcTypeCharSet; break; case FcTypeLangSet: new.u.l = FcValueLangSet(v); new.type = FcTypeLangSet; break; case FcTypeRange: new.u.r = FcValueRange(v); new.type = FcTypeRange; break; default: new = *v; break; } return new; } FcValue FcValueSave (FcValue v) { switch ((int) v.type) { case FcTypeString: v.u.s = FcStrdup (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; case FcTypeRange: v.u.r = FcRangeCopy (v.u.r); if (!v.u.r) v.type = FcTypeVoid; break; default: break; } return v; } FcValueListPtr FcValueListCreate (void) { return calloc (1, sizeof (FcValueList)); } void FcValueListDestroy (FcValueListPtr l) { FcValueListPtr next; for (; l; l = next) { switch ((int) l->value.type) { case FcTypeString: FcFree (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; case FcTypeRange: FcRangeDestroy ((FcRange *) (l->value.u.r)); break; default: break; } next = FcValueListNext(l); free(l); } } FcValueListPtr FcValueListPrepend (FcValueListPtr vallist, FcValue value, FcValueBinding binding) { FcValueListPtr new; if (value.type == FcTypeVoid) return vallist; new = FcValueListCreate (); if (!new) return vallist; new->value = FcValueSave (value); new->binding = binding; new->next = vallist; return new; } FcValueListPtr FcValueListAppend (FcValueListPtr vallist, FcValue value, FcValueBinding binding) { FcValueListPtr new, last; if (value.type == FcTypeVoid) return vallist; new = FcValueListCreate (); if (!new) return vallist; new->value = FcValueSave (value); new->binding = binding; new->next = NULL; if (vallist) { for (last = vallist; FcValueListNext (last); last = FcValueListNext (last)); last->next = new; } else vallist = new; return vallist; } FcValueListPtr FcValueListDuplicate(FcValueListPtr orig) { FcValueListPtr new = NULL, l, t = NULL; FcValue v; for (l = orig; l != NULL; l = FcValueListNext (l)) { if (!new) { t = new = FcValueListCreate(); } else { t->next = FcValueListCreate(); t = FcValueListNext (t); } v = FcValueCanonicalize (&l->value); t->value = FcValueSave (v); t->binding = l->binding; t->next = NULL; } return new; } 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 FcTypeUnknown: return FcFalse; /* don't know how to compare this object */ 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); case FcTypeRange: return FcRangeIsInRange (va.u.r, vb.u.r); } return FcFalse; } static FcChar32 FcDoubleHash (double d) { if (d < 0) d = -d; if (d > 0xffffffff) d = 0xffffffff; return (FcChar32) d; } 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 (const FcValue *v) { switch (v->type) { case FcTypeUnknown: case FcTypeVoid: return 0; case FcTypeInteger: return (FcChar32) v->u.i; case FcTypeDouble: return FcDoubleHash (v->u.d); case FcTypeString: return FcStringHash (FcValueString(v)); 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) FcValueCharSet(v)->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 (FcValueLangSet(v)); case FcTypeRange: return FcRangeHash (v->u.r); } return 0; } static FcBool FcValueListEqual (FcValueListPtr la, FcValueListPtr lb) { if (la == lb) return FcTrue; while (la && lb) { if (!FcValueEqual (la->value, lb->value)) return FcFalse; la = FcValueListNext(la); lb = FcValueListNext(lb); } if (la || lb) return FcFalse; return FcTrue; } static FcChar32 FcValueListHash (FcValueListPtr l) { FcChar32 hash = 0; for (; l; l = FcValueListNext(l)) { hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value); } return hash; } static void * FcPatternGetCacheObject (FcPattern *p) { /* We use a value to find the cache, instead of the FcPattern object * because the pattern itself may be a cache allocation if we rewrote the path, * so the p may not be in the cached region. */ return FcPatternEltValues(&FcPatternElts (p)[0]); } FcPattern * FcPatternCacheRewriteFile (const FcPattern *p, FcCache *cache, const FcChar8 *relocated_font_file) { FcPatternElt *elts = FcPatternElts (p); size_t i,j; FcChar8 *data; FcPattern *new_p; FcPatternElt *new_elts; FcValueList *new_value_list; size_t new_path_len = strlen ((char *)relocated_font_file); FcChar8 *new_path; /* Allocate space for the patter, the PatternElt headers and * the FC_FILE FcValueList and path that will be freed with the * cache */ data = FcCacheAllocate (cache, sizeof (FcPattern) + p->num * sizeof (FcPatternElt) + sizeof (FcValueList) + new_path_len + 1); new_p = (FcPattern *)data; data += sizeof (FcPattern); new_elts = (FcPatternElt *)(data); data += p->num * sizeof (FcPatternElt); new_value_list = (FcValueList *)data; data += sizeof (FcValueList); new_path = data; *new_p = *p; new_p->elts_offset = FcPtrToOffset (new_p, new_elts); /* Copy all but the FILE values from the cache */ for (i = 0, j = 0; i < p->num; i++) { FcPatternElt *elt = &elts[i]; new_elts[j].object = elt->object; if (elt->object != FC_FILE_OBJECT) new_elts[j++].values = FcPatternEltValues(elt); else new_elts[j++].values = new_value_list; } new_value_list->next = NULL; new_value_list->value.type = FcTypeString; new_value_list->value.u.s = new_path; new_value_list->binding = FcValueBindingWeak; /* Add rewritten path at the end */ strcpy ((char *)new_path, (char *)relocated_font_file); return new_p; } void FcPatternDestroy (FcPattern *p) { int i; FcPatternElt *elts; if (!p) return; if (FcRefIsConst (&p->ref)) { FcCacheObjectDereference (FcPatternGetCacheObject(p)); return; } if (FcRefDec (&p->ref) != 1) return; elts = FcPatternElts (p); for (i = 0; i < FcPatternObjectCount (p); i++) FcValueListDestroy (FcPatternEltValues(&elts[i])); free (elts); free (p); } int FcPatternObjectCount (const FcPattern *pat) { if (pat) return pat->num; return 0; } static int FcPatternObjectPosition (const FcPattern *p, FcObject object) { int low, high, mid, c; FcPatternElt *elts = FcPatternElts(p); low = 0; high = FcPatternObjectCount (p) - 1; c = 1; mid = 0; while (low <= high) { mid = (low + high) >> 1; c = 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); } int FcPatternPosition (const FcPattern *p, const char *object) { return FcPatternObjectPosition (p, FcObjectFromName (object)); } FcPatternElt * FcPatternObjectFindElt (const FcPattern *p, FcObject object) { int i = FcPatternObjectPosition (p, object); if (i < 0) return 0; return &FcPatternElts(p)[i]; } FcPatternElt * FcPatternObjectInsertElt (FcPattern *p, FcObject object) { int i; FcPatternElt *e; i = FcPatternObjectPosition (p, object); if (i < 0) { i = -i - 1; /* reallocate array */ if (FcPatternObjectCount (p) + 1 >= p->size) { int s = p->size + 16; if (p->size) { FcPatternElt *e0 = FcPatternElts(p); e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt)); if (!e) /* maybe it was mmapped */ { e = malloc(s * sizeof (FcPatternElt)); if (e) memcpy(e, e0, FcPatternObjectCount (p) * sizeof (FcPatternElt)); } } else e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt)); if (!e) return FcFalse; p->elts_offset = FcPtrToOffset (p, e); while (p->size < s) { e[p->size].object = 0; e[p->size].values = NULL; p->size++; } } e = FcPatternElts(p); /* move elts up */ memmove (e + i + 1, e + i, sizeof (FcPatternElt) * (FcPatternObjectCount (p) - i)); /* bump count */ p->num++; e[i].object = object; e[i].values = NULL; } return FcPatternElts(p) + i; } FcBool FcPatternEqual (const FcPattern *pa, const FcPattern *pb) { FcPatternIter ia, ib; if (pa == pb) return FcTrue; if (FcPatternObjectCount (pa) != FcPatternObjectCount (pb)) return FcFalse; FcPatternIterStart (pa, &ia); FcPatternIterStart (pb, &ib); do { FcBool ra, rb; if (!FcPatternIterEqual (pa, &ia, pb, &ib)) return FcFalse; ra = FcPatternIterNext (pa, &ia); rb = FcPatternIterNext (pb, &ib); if (!ra && !rb) break; } while (1); return FcTrue; } FcChar32 FcPatternHash (const FcPattern *p) { int i; FcChar32 h = 0; FcPatternElt *pe = FcPatternElts(p); for (i = 0; i < FcPatternObjectCount (p); i++) { h = (((h << 1) | (h >> 31)) ^ pe[i].object ^ FcValueListHash (FcPatternEltValues(&pe[i]))); } return h; } FcBool FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os) { FcPatternElt *ea, *eb; int i; for (i = 0; i < os->nobject; i++) { FcObject object = FcObjectFromName (os->objects[i]); ea = FcPatternObjectFindElt (pai, object); eb = FcPatternObjectFindElt (pbi, object); if (ea) { if (!eb) return FcFalse; if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb))) return FcFalse; } else { if (eb) return FcFalse; } } return FcTrue; } FcBool FcPatternObjectListAdd (FcPattern *p, FcObject object, FcValueListPtr list, FcBool append) { FcPatternElt *e; FcValueListPtr l, *prev; if (FcRefIsConst (&p->ref)) goto bail0; /* * Make sure the stored type is valid for built-in objects */ for (l = list; l != NULL; l = FcValueListNext (l)) { if (!FcObjectValidType (object, l->value.type)) { fprintf (stderr, "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); FcValuePrintFile (stderr, l->value); fprintf (stderr, "\n"); goto bail0; } } e = FcPatternObjectInsertElt (p, object); if (!e) goto bail0; if (append) { for (prev = &e->values; *prev; prev = &(*prev)->next) ; *prev = list; } else { for (prev = &list; *prev; prev = &(*prev)->next) ; *prev = e->values; e->values = list; } return FcTrue; bail0: return FcFalse; } FcBool FcPatternObjectAddWithBinding (FcPattern *p, FcObject object, FcValue value, FcValueBinding binding, FcBool append) { FcPatternElt *e; FcValueListPtr new, *prev; if (FcRefIsConst (&p->ref)) goto bail0; new = FcValueListCreate (); if (!new) goto bail0; value = FcValueSave (value); if (value.type == FcTypeVoid) goto bail1; /* * Make sure the stored type is valid for built-in objects */ if (!FcObjectValidType (object, value.type)) { fprintf (stderr, "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); FcValuePrintFile (stderr, value); fprintf (stderr, "\n"); goto bail1; } new->value = value; new->binding = binding; new->next = NULL; e = FcPatternObjectInsertElt (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: FcValueDestroy (value); bail1: free (new); bail0: return FcFalse; } FcBool FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append) { return FcPatternObjectAddWithBinding (p, object, value, FcValueBindingStrong, append); } FcBool FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append) { return FcPatternObjectAddWithBinding (p, FcObjectFromName (object), value, FcValueBindingStrong, append); } FcBool FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append) { return FcPatternObjectAddWithBinding (p, FcObjectFromName (object), value, FcValueBindingWeak, append); } FcBool FcPatternObjectDel (FcPattern *p, FcObject object) { FcPatternElt *e; e = FcPatternObjectFindElt (p, object); if (!e) return FcFalse; /* destroy value */ FcValueListDestroy (e->values); /* shuffle existing ones down */ memmove (e, e+1, (FcPatternElts(p) + FcPatternObjectCount (p) - (e + 1)) * sizeof (FcPatternElt)); p->num--; e = FcPatternElts(p) + FcPatternObjectCount (p); e->object = 0; e->values = NULL; return FcTrue; } FcBool FcPatternDel (FcPattern *p, const char *object) { return FcPatternObjectDel (p, FcObjectFromName (object)); } FcBool FcPatternRemove (FcPattern *p, const char *object, int id) { FcPatternElt *e; FcValueListPtr *prev, l; e = FcPatternObjectFindElt (p, FcObjectFromName (object)); if (!e) return FcFalse; for (prev = &e->values; (l = *prev); prev = &l->next) { if (!id) { *prev = l->next; l->next = NULL; FcValueListDestroy (l); if (!e->values) FcPatternDel (p, object); return FcTrue; } id--; } return FcFalse; } FcBool FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i) { FcValue v; v.type = FcTypeInteger; v.u.i = i; return FcPatternObjectAdd (p, object, v, FcTrue); } FcBool FcPatternAddInteger (FcPattern *p, const char *object, int i) { return FcPatternObjectAddInteger (p, FcObjectFromName (object), i); } FcBool FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d) { FcValue v; v.type = FcTypeDouble; v.u.d = d; return FcPatternObjectAdd (p, object, v, FcTrue); } FcBool FcPatternAddDouble (FcPattern *p, const char *object, double d) { return FcPatternObjectAddDouble (p, FcObjectFromName (object), d); } FcBool FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s) { FcValue v; if (!s) { v.type = FcTypeVoid; v.u.s = 0; return FcPatternObjectAdd (p, object, v, FcTrue); } v.type = FcTypeString; v.u.s = s; return FcPatternObjectAdd (p, object, v, FcTrue); } FcBool FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s) { return FcPatternObjectAddString (p, FcObjectFromName (object), s); } FcBool FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s) { FcValue v; v.type = FcTypeMatrix; v.u.m = s; return FcPatternAdd (p, object, v, FcTrue); } FcBool FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b) { FcValue v; v.type = FcTypeBool; v.u.b = b; return FcPatternObjectAdd (p, object, v, FcTrue); } FcBool FcPatternAddBool (FcPattern *p, const char *object, FcBool b) { return FcPatternObjectAddBool (p, FcObjectFromName (object), b); } 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); } FcBool FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r) { FcValue v; v.type = FcTypeRange; v.u.r = (FcRange *)r; return FcPatternObjectAdd (p, object, v, FcTrue); } FcBool FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r) { return FcPatternObjectAddRange (p, FcObjectFromName (object), r); } FcResult FcPatternObjectGetWithBinding (const FcPattern *p, FcObject object, int id, FcValue *v, FcValueBinding *b) { FcPatternElt *e; FcValueListPtr l; if (!p) return FcResultNoMatch; e = FcPatternObjectFindElt (p, object); if (!e) return FcResultNoMatch; for (l = FcPatternEltValues(e); l; l = FcValueListNext(l)) { if (!id) { *v = FcValueCanonicalize(&l->value); if (b) *b = l->binding; return FcResultMatch; } id--; } return FcResultNoId; } FcResult FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v) { return FcPatternObjectGetWithBinding (p, object, id, v, NULL); } FcResult FcPatternGetWithBinding (const FcPattern *p, const char *object, int id, FcValue *v, FcValueBinding *b) { return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, b); } FcResult FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v) { return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, NULL); } FcResult FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i) { FcValue v; FcResult r; r = FcPatternObjectGet (p, object, id, &v); if (r != FcResultMatch) return r; switch ((int) v.type) { case FcTypeDouble: *i = (int) v.u.d; break; case FcTypeInteger: *i = v.u.i; break; default: return FcResultTypeMismatch; } return FcResultMatch; } FcResult FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i) { return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i); } FcResult FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d) { FcValue v; FcResult r; r = FcPatternObjectGet (p, object, id, &v); if (r != FcResultMatch) return r; switch ((int) v.type) { case FcTypeDouble: *d = v.u.d; break; case FcTypeInteger: *d = (double) v.u.i; break; default: return FcResultTypeMismatch; } return FcResultMatch; } FcResult FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d) { return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d); } FcResult FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s) { FcValue v; FcResult r; r = FcPatternObjectGet (p, object, id, &v); if (r != FcResultMatch) return r; if (v.type != FcTypeString) return FcResultTypeMismatch; *s = (FcChar8 *) v.u.s; return FcResultMatch; } FcResult FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s) { return FcPatternObjectGetString (p, FcObjectFromName (object), id, s); } FcResult FcPatternGetMatrix(const 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 FcPatternObjectGetBool (const FcPattern *p, FcObject object, int id, FcBool *b) { FcValue v; FcResult r; r = FcPatternObjectGet (p, object, id, &v); if (r != FcResultMatch) return r; if (v.type != FcTypeBool) return FcResultTypeMismatch; *b = v.u.b; return FcResultMatch; } FcResult FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b) { return FcPatternObjectGetBool (p, FcObjectFromName (object), id, b); } FcResult FcPatternGetCharSet(const 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(const 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(const 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; } FcResult FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r) { FcValue v; FcResult res; res = FcPatternObjectGet (p, object, id, &v); if (res != FcResultMatch) return res; switch ((int)v.type) { case FcTypeRange: *r = (FcRange *)v.u.r; break; default: return FcResultTypeMismatch; } return FcResultMatch; } FcResult FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r) { return FcPatternObjectGetRange (p, FcObjectFromName (object), id, r); } FcPattern * FcPatternDuplicate (const FcPattern *orig) { FcPattern *new; FcPatternIter iter; FcValueListPtr l; if (!orig) return NULL; new = FcPatternCreate (); if (!new) goto bail0; FcPatternIterStart (orig, &iter); do { for (l = FcPatternIterGetValues (orig, &iter); l; l = FcValueListNext (l)) { if (!FcPatternObjectAddWithBinding (new, FcPatternIterGetObjectId (orig, &iter), FcValueCanonicalize(&l->value), l->binding, FcTrue)) goto bail1; } } while (FcPatternIterNext (orig, &iter)); return new; bail1: FcPatternDestroy (new); bail0: return 0; } void FcPatternReference (FcPattern *p) { if (!FcRefIsConst (&p->ref)) FcRefInc (&p->ref); else FcCacheObjectReference (FcPatternGetCacheObject(p)); } FcPattern * FcPatternVaBuild (FcPattern *p, va_list va) { FcPattern *ret; FcPatternVapBuild (ret, p, va); return ret; } FcPattern * FcPatternBuild (FcPattern *p, ...) { va_list va; va_start (va, p); FcPatternVapBuild (p, p, va); va_end (va); return p; } /* * Add all of the elements in 's' to 'p' */ FcBool FcPatternAppend (FcPattern *p, FcPattern *s) { FcPatternIter iter; FcValueListPtr v; FcPatternIterStart (s, &iter); do { for (v = FcPatternIterGetValues (s, &iter); v; v = FcValueListNext (v)) { if (!FcPatternObjectAddWithBinding (p, FcPatternIterGetObjectId (s, &iter), FcValueCanonicalize(&v->value), v->binding, FcTrue)) return FcFalse; } } while (FcPatternIterNext (s, &iter)); return FcTrue; } FcPattern * FcPatternFilter (FcPattern *p, const FcObjectSet *os) { int i; FcPattern *ret; FcPatternElt *e; FcValueListPtr v; if (!os) return FcPatternDuplicate (p); ret = FcPatternCreate (); if (!ret) return NULL; for (i = 0; i < os->nobject; i++) { FcObject object = FcObjectFromName (os->objects[i]); e = FcPatternObjectFindElt (p, object); if (e) { for (v = FcPatternEltValues(e); v; v = FcValueListNext(v)) { if (!FcPatternObjectAddWithBinding (ret, e->object, FcValueCanonicalize(&v->value), v->binding, FcTrue)) goto bail0; } } } return ret; bail0: FcPatternDestroy (ret); return NULL; } typedef struct _FcPatternPrivateIter { FcPatternElt *elt; int pos; } FcPatternPrivateIter; static void FcPatternIterSet (const FcPattern *pat, FcPatternPrivateIter *iter) { iter->elt = FcPatternObjectCount (pat) > 0 && iter->pos < FcPatternObjectCount (pat) ? &FcPatternElts (pat)[iter->pos] : NULL; } void FcPatternIterStart (const FcPattern *pat, FcPatternIter *iter) { FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; priv->pos = 0; FcPatternIterSet (pat, priv); } FcBool FcPatternIterNext (const FcPattern *pat, FcPatternIter *iter) { FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; priv->pos++; if (priv->pos >= FcPatternObjectCount (pat)) return FcFalse; FcPatternIterSet (pat, priv); return FcTrue; } FcBool FcPatternIterEqual (const FcPattern *p1, FcPatternIter *i1, const FcPattern *p2, FcPatternIter *i2) { FcBool b1 = FcPatternIterIsValid (p1, i1); FcBool b2 = FcPatternIterIsValid (p2, i2); if (!i1 && !i2) return FcTrue; if (!b1 || !b2) return FcFalse; if (FcPatternIterGetObjectId (p1, i1) != FcPatternIterGetObjectId (p2, i2)) return FcFalse; return FcValueListEqual (FcPatternIterGetValues (p1, i1), FcPatternIterGetValues (p2, i2)); } FcBool FcPatternFindObjectIter (const FcPattern *pat, FcPatternIter *iter, FcObject object) { FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; int i = FcPatternObjectPosition (pat, object); priv->elt = NULL; if (i < 0) return FcFalse; priv->pos = i; FcPatternIterSet (pat, priv); return FcTrue; } FcBool FcPatternFindIter (const FcPattern *pat, FcPatternIter *iter, const char *object) { return FcPatternFindObjectIter (pat, iter, FcObjectFromName (object)); } FcBool FcPatternIterIsValid (const FcPattern *pat, FcPatternIter *iter) { FcPatternPrivateIter *priv = (FcPatternPrivateIter *)iter; if (priv && priv->elt) return FcTrue; return FcFalse; } FcObject FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter) { FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; if (priv && priv->elt) return priv->elt->object; return 0; } const char * FcPatternIterGetObject (const FcPattern *pat, FcPatternIter *iter) { return FcObjectName (FcPatternIterGetObjectId (pat, iter)); } FcValueListPtr FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter) { FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; if (priv && priv->elt) return FcPatternEltValues (priv->elt); return NULL; } int FcPatternIterValueCount (const FcPattern *pat, FcPatternIter *iter) { int count = 0; FcValueListPtr l; for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l)) count++; return count; } FcResult FcPatternIterGetValue (const FcPattern *pat, FcPatternIter *iter, int id, FcValue *v, FcValueBinding *b) { FcValueListPtr l; for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l)) { if (id == 0) { *v = FcValueCanonicalize (&l->value); if (b) *b = l->binding; return FcResultMatch; } id--; } return FcResultNoId; } FcBool FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat) { int i; FcPatternElt *elts = FcPatternElts(pat); if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern))) return FcFalse; if (!FcSerializeAlloc (serialize, elts, FcPatternObjectCount (pat) * sizeof (FcPatternElt))) return FcFalse; for (i = 0; i < FcPatternObjectCount (pat); i++) if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i))) return FcFalse; return FcTrue; } FcPattern * FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat) { FcPattern *pat_serialized; FcPatternElt *elts = FcPatternElts (pat); FcPatternElt *elts_serialized; FcValueList *values_serialized; int i; pat_serialized = FcSerializePtr (serialize, pat); if (!pat_serialized) return NULL; *pat_serialized = *pat; pat_serialized->size = FcPatternObjectCount (pat); FcRefSetConst (&pat_serialized->ref); elts_serialized = FcSerializePtr (serialize, elts); if (!elts_serialized) return NULL; pat_serialized->elts_offset = FcPtrToOffset (pat_serialized, elts_serialized); for (i = 0; i < FcPatternObjectCount (pat); i++) { values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i)); if (!values_serialized) return NULL; elts_serialized[i].object = elts[i].object; elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i], values_serialized, FcValueList); } if (FcDebug() & FC_DBG_CACHEV) { printf ("Raw pattern:\n"); FcPatternPrint (pat); printf ("Serialized pattern:\n"); FcPatternPrint (pat_serialized); printf ("\n"); } return pat_serialized; } FcBool FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl) { while (vl) { if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList))) return FcFalse; switch ((int) vl->value.type) { case FcTypeString: if (!FcStrSerializeAlloc (serialize, vl->value.u.s)) return FcFalse; break; case FcTypeCharSet: if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c)) return FcFalse; break; case FcTypeLangSet: if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l)) return FcFalse; break; case FcTypeRange: if (!FcRangeSerializeAlloc (serialize, vl->value.u.r)) return FcFalse; break; default: break; } vl = vl->next; } return FcTrue; } FcValueList * FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl) { FcValueList *vl_serialized; FcChar8 *s_serialized; FcCharSet *c_serialized; FcLangSet *l_serialized; FcRange *r_serialized; FcValueList *head_serialized = NULL; FcValueList *prev_serialized = NULL; while (vl) { vl_serialized = FcSerializePtr (serialize, vl); if (!vl_serialized) return NULL; if (prev_serialized) prev_serialized->next = FcPtrToEncodedOffset (prev_serialized, vl_serialized, FcValueList); else head_serialized = vl_serialized; vl_serialized->next = NULL; vl_serialized->value.type = vl->value.type; switch ((int) vl->value.type) { case FcTypeInteger: vl_serialized->value.u.i = vl->value.u.i; break; case FcTypeDouble: vl_serialized->value.u.d = vl->value.u.d; break; case FcTypeString: s_serialized = FcStrSerialize (serialize, vl->value.u.s); if (!s_serialized) return NULL; vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value, s_serialized, FcChar8); break; case FcTypeBool: vl_serialized->value.u.b = vl->value.u.b; break; case FcTypeMatrix: /* can't happen */ break; case FcTypeCharSet: c_serialized = FcCharSetSerialize (serialize, vl->value.u.c); if (!c_serialized) return NULL; vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value, c_serialized, FcCharSet); break; case FcTypeFTFace: /* can't happen */ break; case FcTypeLangSet: l_serialized = FcLangSetSerialize (serialize, vl->value.u.l); if (!l_serialized) return NULL; vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value, l_serialized, FcLangSet); break; case FcTypeRange: r_serialized = FcRangeSerialize (serialize, vl->value.u.r); if (!r_serialized) return NULL; vl_serialized->value.u.r = FcPtrToEncodedOffset (&vl_serialized->value, r_serialized, FcRange); break; default: break; } prev_serialized = vl_serialized; vl = vl->next; } return head_serialized; } #define __fcpat__ #include "fcaliastail.h" #include "fcftaliastail.h" #undef __fcpat__