blob: 5927be42a861b80acb2eec5c907c2c96c8875343 [file] [log] [blame]
/*
* 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 (FcValueRange (v));
}
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
FcPatternObjectAddCharSet (FcPattern *p, FcObject object, const FcCharSet *c)
{
FcValue v;
v.type = FcTypeCharSet;
v.u.c = (FcCharSet *)c;
return FcPatternObjectAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
{
return FcPatternObjectAddCharSet (p, FcObjectFromName (object), c);
}
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
FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls)
{
FcValue v;
v.type = FcTypeLangSet;
v.u.l = (FcLangSet *)ls;
return FcPatternObjectAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
{
return FcPatternObjectAddLangSet (p, FcObjectFromName (object), ls);
}
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__