| /* |
| * 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" |
| #include <stdlib.h> |
| #include <string.h> |
| #include <assert.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_offset = FcPtrToOffset (p, NULL); |
| p->ref = 1; |
| return p; |
| } |
| |
| void |
| FcValueDestroy (FcValue v) |
| { |
| switch (v.type) { |
| case FcTypeString: |
| if (!FcSharedStrFree (v.u.s)) |
| 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 |
| FcValueCanonicalize (const FcValue *v) |
| { |
| FcValue new; |
| |
| switch (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; |
| default: |
| new = *v; |
| break; |
| } |
| return new; |
| } |
| |
| FcValue |
| FcValueSave (FcValue v) |
| { |
| switch (v.type) { |
| case FcTypeString: |
| v.u.s = FcSharedStr (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 (FcValueListPtr l) |
| { |
| FcValueListPtr next; |
| for (; l; l = next) |
| { |
| switch (l->value.type) { |
| case FcTypeString: |
| if (!FcSharedStrFree ((FcChar8 *)l->value.u.s)) |
| 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 = FcValueListNext(l); |
| 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; |
| } |
| |
| 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 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)); |
| } |
| return FcFalse; |
| } |
| |
| 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; |
| } |
| |
| void |
| FcPatternDestroy (FcPattern *p) |
| { |
| int i; |
| FcPatternElt *elts; |
| |
| if (p->ref == FC_REF_CONSTANT) |
| { |
| FcCacheObjectDereference (p); |
| return; |
| } |
| |
| if (--p->ref > 0) |
| return; |
| |
| elts = FcPatternElts (p); |
| for (i = 0; i < p->num; i++) |
| FcValueListDestroy (FcPatternEltValues(&elts[i])); |
| |
| FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt)); |
| free (elts); |
| FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern)); |
| free (p); |
| } |
| |
| static int |
| FcPatternObjectPosition (const FcPattern *p, FcObject object) |
| { |
| int low, high, mid, c; |
| FcPatternElt *elts = FcPatternElts(p); |
| |
| low = 0; |
| high = p->num - 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); |
| } |
| |
| 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 (p->num + 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, p->num * sizeof (FcPatternElt)); |
| } |
| } |
| else |
| e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt)); |
| if (!e) |
| return FcFalse; |
| p->elts_offset = FcPtrToOffset (p, e); |
| if (p->size) |
| FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt)); |
| FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt)); |
| 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) * |
| (p->num - 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) |
| { |
| int i; |
| FcPatternElt *pae, *pbe; |
| |
| if (pa == pb) |
| return FcTrue; |
| |
| if (pa->num != pb->num) |
| return FcFalse; |
| pae = FcPatternElts(pa); |
| pbe = FcPatternElts(pb); |
| for (i = 0; i < pa->num; i++) |
| { |
| if (pae[i].object != pbe[i].object) |
| return FcFalse; |
| if (!FcValueListEqual (FcPatternEltValues(&pae[i]), |
| FcPatternEltValues(&pbe[i]))) |
| return FcFalse; |
| } |
| return FcTrue; |
| } |
| |
| FcChar32 |
| FcPatternHash (const FcPattern *p) |
| { |
| int i; |
| FcChar32 h = 0; |
| FcPatternElt *pe = FcPatternElts(p); |
| |
| for (i = 0; i < p->num; 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 |
| FcPatternObjectAddWithBinding (FcPattern *p, |
| FcObject object, |
| FcValue value, |
| FcValueBinding binding, |
| FcBool append) |
| { |
| FcPatternElt *e; |
| FcValueListPtr new, *prev; |
| |
| if (p->ref == FC_REF_CONSTANT) |
| goto bail0; |
| |
| new = malloc (sizeof (FcValueList)); |
| if (!new) |
| goto bail0; |
| |
| memset(new, 0, sizeof (FcValueList)); |
| FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); |
| 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)) |
| { |
| if (FcDebug() & FC_DBG_OBJTYPES) |
| { |
| printf ("FcPattern object %s does not accept value ", |
| FcObjectName (object)); |
| FcValuePrint (value); |
| } |
| 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: |
| FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); |
| 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) + p->num - (e + 1)) * |
| sizeof (FcPatternElt)); |
| p->num--; |
| e = FcPatternElts(p) + p->num; |
| 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); |
| } |
| |
| FcResult |
| FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v) |
| { |
| FcPatternElt *e; |
| FcValueListPtr l; |
| |
| e = FcPatternObjectFindElt (p, object); |
| if (!e) |
| return FcResultNoMatch; |
| for (l = FcPatternEltValues(e); l; l = FcValueListNext(l)) |
| { |
| if (!id) |
| { |
| *v = FcValueCanonicalize(&l->value); |
| return FcResultMatch; |
| } |
| id--; |
| } |
| return FcResultNoId; |
| } |
| |
| FcResult |
| FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v) |
| { |
| return FcPatternObjectGet (p, FcObjectFromName (object), id, v); |
| } |
| |
| 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 (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 (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 |
| FcPatternGetBool(const 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(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; |
| } |
| |
| FcPattern * |
| FcPatternDuplicate (const FcPattern *orig) |
| { |
| FcPattern *new; |
| FcPatternElt *e; |
| int i; |
| FcValueListPtr l; |
| |
| new = FcPatternCreate (); |
| if (!new) |
| goto bail0; |
| |
| e = FcPatternElts(orig); |
| |
| for (i = 0; i < orig->num; i++) |
| { |
| for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l)) |
| { |
| if (!FcPatternObjectAddWithBinding (new, e[i].object, |
| FcValueCanonicalize(&l->value), |
| l->binding, |
| FcTrue)) |
| goto bail1; |
| |
| } |
| } |
| |
| return new; |
| |
| bail1: |
| FcPatternDestroy (new); |
| bail0: |
| return 0; |
| } |
| |
| void |
| FcPatternReference (FcPattern *p) |
| { |
| if (p->ref != FC_REF_CONSTANT) |
| p->ref++; |
| else |
| FcCacheObjectReference (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) |
| { |
| int i; |
| FcPatternElt *e; |
| FcValueListPtr v; |
| |
| for (i = 0; i < s->num; i++) |
| { |
| e = FcPatternElts(s)+i; |
| for (v = FcPatternEltValues(e); v; v = FcValueListNext(v)) |
| { |
| if (!FcPatternObjectAddWithBinding (p, e->object, |
| FcValueCanonicalize(&v->value), |
| v->binding, FcTrue)) |
| return FcFalse; |
| } |
| } |
| 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; |
| } |
| |
| #define OBJECT_HASH_SIZE 251 |
| static struct objectBucket { |
| struct objectBucket *next; |
| FcChar32 hash; |
| int ref_count; |
| } *FcObjectBuckets[OBJECT_HASH_SIZE]; |
| |
| FcBool |
| FcSharedStrFree (const FcChar8 *name) |
| { |
| FcChar32 hash = FcStringHash (name); |
| struct objectBucket **p; |
| struct objectBucket *b; |
| int size; |
| |
| for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) |
| if (b->hash == hash && ((char *)name == (char *) (b + 1))) |
| { |
| b->ref_count--; |
| if (!b->ref_count) |
| { |
| *p = b->next; |
| size = sizeof (struct objectBucket) + strlen ((char *)name) + 1; |
| size = (size + 3) & ~3; |
| FcMemFree (FC_MEM_SHAREDSTR, size); |
| free (b); |
| } |
| return FcTrue; |
| } |
| return FcFalse; |
| } |
| |
| const FcChar8 * |
| FcSharedStr (const FcChar8 *name) |
| { |
| FcChar32 hash = FcStringHash (name); |
| struct objectBucket **p; |
| struct objectBucket *b; |
| int size; |
| |
| for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) |
| if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1))) |
| { |
| b->ref_count++; |
| return (FcChar8 *) (b + 1); |
| } |
| size = sizeof (struct objectBucket) + strlen ((char *)name) + 1; |
| /* |
| * workaround valgrind warning because glibc takes advantage of how it knows memory is |
| * allocated to implement strlen by reading in groups of 4 |
| */ |
| size = (size + 3) & ~3; |
| b = malloc (size); |
| FcMemAlloc (FC_MEM_SHAREDSTR, size); |
| if (!b) |
| return NULL; |
| b->next = 0; |
| b->hash = hash; |
| b->ref_count = 1; |
| strcpy ((char *) (b + 1), (char *)name); |
| *p = b; |
| return (FcChar8 *) (b + 1); |
| } |
| |
| 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, pat->num * sizeof (FcPatternElt))) |
| return FcFalse; |
| for (i = 0; i < pat->num; 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 = pat->num; |
| pat_serialized->ref = FC_REF_CONSTANT; |
| |
| elts_serialized = FcSerializePtr (serialize, elts); |
| if (!elts_serialized) |
| return NULL; |
| |
| pat_serialized->elts_offset = FcPtrToOffset (pat_serialized, |
| elts_serialized); |
| |
| for (i = 0; i < pat->num; 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 (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; |
| 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; |
| 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 (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; |
| default: |
| break; |
| } |
| prev_serialized = vl_serialized; |
| vl = vl->next; |
| } |
| return head_serialized; |
| } |
| #define __fcpat__ |
| #include "fcaliastail.h" |
| #include "fcftaliastail.h" |
| #undef __fcpat__ |