fcpat.c revision b09479dc
1/*
2 * Copyright © 2000 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the author(s) not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  The authors make no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include "fcint.h"
24#include "fcftint.h"
25
26/* Objects MT-safe for readonly access. */
27
28FcPattern *
29FcPatternCreate (void)
30{
31    FcPattern	*p;
32
33    p = (FcPattern *) malloc (sizeof (FcPattern));
34    if (!p)
35	return 0;
36    memset (p, 0, sizeof (FcPattern));
37    p->num = 0;
38    p->size = 0;
39    p->elts_offset = FcPtrToOffset (p, NULL);
40    FcRefInit (&p->ref, 1);
41    return p;
42}
43
44void
45FcValueDestroy (FcValue v)
46{
47    switch ((int) v.type) {
48    case FcTypeString:
49	FcFree (v.u.s);
50	break;
51    case FcTypeMatrix:
52	FcMatrixFree ((FcMatrix *) v.u.m);
53	break;
54    case FcTypeCharSet:
55	FcCharSetDestroy ((FcCharSet *) v.u.c);
56	break;
57    case FcTypeLangSet:
58	FcLangSetDestroy ((FcLangSet *) v.u.l);
59	break;
60    default:
61	break;
62    }
63}
64
65FcValue
66FcValueCanonicalize (const FcValue *v)
67{
68    FcValue new;
69
70    switch ((int) v->type)
71    {
72    case FcTypeString:
73	new.u.s = FcValueString(v);
74	new.type = FcTypeString;
75	break;
76    case FcTypeCharSet:
77	new.u.c = FcValueCharSet(v);
78	new.type = FcTypeCharSet;
79	break;
80    case FcTypeLangSet:
81	new.u.l = FcValueLangSet(v);
82	new.type = FcTypeLangSet;
83	break;
84    default:
85	new = *v;
86	break;
87    }
88    return new;
89}
90
91FcValue
92FcValueSave (FcValue v)
93{
94    switch ((int) v.type) {
95    case FcTypeString:
96	v.u.s = FcStrdup (v.u.s);
97	if (!v.u.s)
98	    v.type = FcTypeVoid;
99	break;
100    case FcTypeMatrix:
101	v.u.m = FcMatrixCopy (v.u.m);
102	if (!v.u.m)
103	    v.type = FcTypeVoid;
104	break;
105    case FcTypeCharSet:
106	v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
107	if (!v.u.c)
108	    v.type = FcTypeVoid;
109	break;
110    case FcTypeLangSet:
111	v.u.l = FcLangSetCopy (v.u.l);
112	if (!v.u.l)
113	    v.type = FcTypeVoid;
114	break;
115    default:
116	break;
117    }
118    return v;
119}
120
121FcValueListPtr
122FcValueListCreate (void)
123{
124    return calloc (1, sizeof (FcValueList));
125}
126
127void
128FcValueListDestroy (FcValueListPtr l)
129{
130    FcValueListPtr next;
131    for (; l; l = next)
132    {
133	switch ((int) l->value.type) {
134	case FcTypeString:
135	    FcFree (l->value.u.s);
136	    break;
137	case FcTypeMatrix:
138	    FcMatrixFree ((FcMatrix *)l->value.u.m);
139	    break;
140	case FcTypeCharSet:
141	    FcCharSetDestroy
142		((FcCharSet *) (l->value.u.c));
143	    break;
144	case FcTypeLangSet:
145	    FcLangSetDestroy
146		((FcLangSet *) (l->value.u.l));
147	    break;
148	default:
149	    break;
150	}
151	next = FcValueListNext(l);
152	free(l);
153    }
154}
155
156FcValueListPtr
157FcValueListPrepend (FcValueListPtr vallist,
158		    FcValue        value,
159		    FcValueBinding binding)
160{
161    FcValueListPtr new;
162
163    if (value.type == FcTypeVoid)
164	return vallist;
165    new = FcValueListCreate ();
166    if (!new)
167	return vallist;
168
169    new->value = FcValueSave (value);
170    new->binding = binding;
171    new->next = vallist;
172
173    return new;
174}
175
176FcValueListPtr
177FcValueListAppend (FcValueListPtr vallist,
178		   FcValue        value,
179		   FcValueBinding binding)
180{
181    FcValueListPtr new, last;
182
183    if (value.type == FcTypeVoid)
184	return vallist;
185    new = FcValueListCreate ();
186    if (!new)
187	return vallist;
188
189    new->value = FcValueSave (value);
190    new->binding = binding;
191    new->next = NULL;
192
193    if (vallist)
194    {
195	for (last = vallist; FcValueListNext (last); last = FcValueListNext (last));
196
197	last->next = new;
198    }
199    else
200	vallist = new;
201
202    return vallist;
203}
204
205FcValueListPtr
206FcValueListDuplicate(FcValueListPtr orig)
207{
208    FcValueListPtr new = NULL, l, t = NULL;
209    FcValue v;
210
211    for (l = orig; l != NULL; l = FcValueListNext (l))
212    {
213	if (!new)
214	{
215	    t = new = FcValueListCreate();
216	}
217	else
218	{
219	    t->next = FcValueListCreate();
220	    t = FcValueListNext (t);
221	}
222	v = FcValueCanonicalize (&l->value);
223	t->value = FcValueSave (v);
224	t->binding = l->binding;
225	t->next = NULL;
226    }
227
228    return new;
229}
230
231FcBool
232FcValueEqual (FcValue va, FcValue vb)
233{
234    if (va.type != vb.type)
235    {
236	if (va.type == FcTypeInteger)
237	{
238	    va.type = FcTypeDouble;
239	    va.u.d = va.u.i;
240	}
241	if (vb.type == FcTypeInteger)
242	{
243	    vb.type = FcTypeDouble;
244	    vb.u.d = vb.u.i;
245	}
246	if (va.type != vb.type)
247	    return FcFalse;
248    }
249    switch (va.type) {
250    case FcTypeUnknown:
251	return FcFalse;	/* don't know how to compare this object */
252    case FcTypeVoid:
253	return FcTrue;
254    case FcTypeInteger:
255	return va.u.i == vb.u.i;
256    case FcTypeDouble:
257	return va.u.d == vb.u.d;
258    case FcTypeString:
259	return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
260    case FcTypeBool:
261	return va.u.b == vb.u.b;
262    case FcTypeMatrix:
263	return FcMatrixEqual (va.u.m, vb.u.m);
264    case FcTypeCharSet:
265	return FcCharSetEqual (va.u.c, vb.u.c);
266    case FcTypeFTFace:
267	return va.u.f == vb.u.f;
268    case FcTypeLangSet:
269	return FcLangSetEqual (va.u.l, vb.u.l);
270    }
271    return FcFalse;
272}
273
274static FcChar32
275FcDoubleHash (double d)
276{
277    if (d < 0)
278	d = -d;
279    if (d > 0xffffffff)
280	d = 0xffffffff;
281    return (FcChar32) d;
282}
283
284FcChar32
285FcStringHash (const FcChar8 *s)
286{
287    FcChar8	c;
288    FcChar32	h = 0;
289
290    if (s)
291	while ((c = *s++))
292	    h = ((h << 1) | (h >> 31)) ^ c;
293    return h;
294}
295
296static FcChar32
297FcValueHash (const FcValue *v)
298{
299    switch (v->type) {
300    case FcTypeUnknown:
301    case FcTypeVoid:
302	return 0;
303    case FcTypeInteger:
304	return (FcChar32) v->u.i;
305    case FcTypeDouble:
306	return FcDoubleHash (v->u.d);
307    case FcTypeString:
308	return FcStringHash (FcValueString(v));
309    case FcTypeBool:
310	return (FcChar32) v->u.b;
311    case FcTypeMatrix:
312	return (FcDoubleHash (v->u.m->xx) ^
313		FcDoubleHash (v->u.m->xy) ^
314		FcDoubleHash (v->u.m->yx) ^
315		FcDoubleHash (v->u.m->yy));
316    case FcTypeCharSet:
317	return (FcChar32) FcValueCharSet(v)->num;
318    case FcTypeFTFace:
319	return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
320	       FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
321    case FcTypeLangSet:
322	return FcLangSetHash (FcValueLangSet(v));
323    }
324    return 0;
325}
326
327static FcBool
328FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
329{
330    if (la == lb)
331	return FcTrue;
332
333    while (la && lb)
334    {
335	if (!FcValueEqual (la->value, lb->value))
336	    return FcFalse;
337	la = FcValueListNext(la);
338	lb = FcValueListNext(lb);
339    }
340    if (la || lb)
341	return FcFalse;
342    return FcTrue;
343}
344
345static FcChar32
346FcValueListHash (FcValueListPtr l)
347{
348    FcChar32	hash = 0;
349
350    for (; l; l = FcValueListNext(l))
351    {
352	hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
353    }
354    return hash;
355}
356
357void
358FcPatternDestroy (FcPattern *p)
359{
360    int		    i;
361    FcPatternElt    *elts;
362
363    if (!p)
364	return;
365
366    if (FcRefIsConst (&p->ref))
367    {
368	FcCacheObjectDereference (p);
369	return;
370    }
371
372    if (FcRefDec (&p->ref) != 1)
373	return;
374
375    elts = FcPatternElts (p);
376    for (i = 0; i < p->num; i++)
377	FcValueListDestroy (FcPatternEltValues(&elts[i]));
378
379    free (elts);
380    free (p);
381}
382
383static int
384FcPatternObjectPosition (const FcPattern *p, FcObject object)
385{
386    int	    low, high, mid, c;
387    FcPatternElt    *elts = FcPatternElts(p);
388
389    low = 0;
390    high = p->num - 1;
391    c = 1;
392    mid = 0;
393    while (low <= high)
394    {
395	mid = (low + high) >> 1;
396	c = elts[mid].object - object;
397	if (c == 0)
398	    return mid;
399	if (c < 0)
400	    low = mid + 1;
401	else
402	    high = mid - 1;
403    }
404    if (c < 0)
405	mid++;
406    return -(mid + 1);
407}
408
409FcPatternElt *
410FcPatternObjectFindElt (const FcPattern *p, FcObject object)
411{
412    int	    i = FcPatternObjectPosition (p, object);
413    if (i < 0)
414	return 0;
415    return &FcPatternElts(p)[i];
416}
417
418FcPatternElt *
419FcPatternObjectInsertElt (FcPattern *p, FcObject object)
420{
421    int		    i;
422    FcPatternElt   *e;
423
424    i = FcPatternObjectPosition (p, object);
425    if (i < 0)
426    {
427	i = -i - 1;
428
429	/* reallocate array */
430	if (p->num + 1 >= p->size)
431	{
432	    int s = p->size + 16;
433	    if (p->size)
434	    {
435		FcPatternElt *e0 = FcPatternElts(p);
436		e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
437		if (!e) /* maybe it was mmapped */
438		{
439		    e = malloc(s * sizeof (FcPatternElt));
440		    if (e)
441			memcpy(e, e0, p->num * sizeof (FcPatternElt));
442		}
443	    }
444	    else
445		e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
446	    if (!e)
447		return FcFalse;
448	    p->elts_offset = FcPtrToOffset (p, e);
449	    while (p->size < s)
450	    {
451		e[p->size].object = 0;
452		e[p->size].values = NULL;
453		p->size++;
454	    }
455	}
456
457	e = FcPatternElts(p);
458	/* move elts up */
459	memmove (e + i + 1,
460		 e + i,
461		 sizeof (FcPatternElt) *
462		 (p->num - i));
463
464	/* bump count */
465	p->num++;
466
467	e[i].object = object;
468	e[i].values = NULL;
469    }
470
471    return FcPatternElts(p) + i;
472}
473
474FcBool
475FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
476{
477    int	i;
478    FcPatternElt   *pae, *pbe;
479
480    if (pa == pb)
481	return FcTrue;
482
483    if (pa->num != pb->num)
484	return FcFalse;
485    pae = FcPatternElts(pa);
486    pbe = FcPatternElts(pb);
487    for (i = 0; i < pa->num; i++)
488    {
489	if (pae[i].object != pbe[i].object)
490	    return FcFalse;
491	if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
492			       FcPatternEltValues(&pbe[i])))
493	    return FcFalse;
494    }
495    return FcTrue;
496}
497
498FcChar32
499FcPatternHash (const FcPattern *p)
500{
501    int		i;
502    FcChar32	h = 0;
503    FcPatternElt    *pe = FcPatternElts(p);
504
505    for (i = 0; i < p->num; i++)
506    {
507	h = (((h << 1) | (h >> 31)) ^
508	     pe[i].object ^
509	     FcValueListHash (FcPatternEltValues(&pe[i])));
510    }
511    return h;
512}
513
514FcBool
515FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
516{
517    FcPatternElt    *ea, *eb;
518    int		    i;
519
520    for (i = 0; i < os->nobject; i++)
521    {
522	FcObject    object = FcObjectFromName (os->objects[i]);
523	ea = FcPatternObjectFindElt (pai, object);
524	eb = FcPatternObjectFindElt (pbi, object);
525	if (ea)
526	{
527	    if (!eb)
528		return FcFalse;
529	    if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
530		return FcFalse;
531	}
532	else
533	{
534	    if (eb)
535		return FcFalse;
536	}
537    }
538    return FcTrue;
539}
540
541FcBool
542FcPatternObjectListAdd (FcPattern	*p,
543			FcObject	object,
544			FcValueListPtr	list,
545			FcBool		append)
546{
547    FcPatternElt   *e;
548    FcValueListPtr l, *prev;
549
550    if (FcRefIsConst (&p->ref))
551	goto bail0;
552
553    /*
554     * Make sure the stored type is valid for built-in objects
555     */
556    for (l = list; l != NULL; l = FcValueListNext (l))
557    {
558	if (!FcObjectValidType (object, l->value.type))
559	{
560	    fprintf (stderr,
561		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
562	    FcValuePrintFile (stderr, l->value);
563	    fprintf (stderr, "\n");
564	    goto bail0;
565	}
566    }
567
568    e = FcPatternObjectInsertElt (p, object);
569    if (!e)
570	goto bail0;
571
572    if (append)
573    {
574	for (prev = &e->values; *prev; prev = &(*prev)->next)
575	    ;
576	*prev = list;
577    }
578    else
579    {
580	for (prev = &list; *prev; prev = &(*prev)->next)
581	    ;
582	*prev = e->values;
583	e->values = list;
584    }
585
586    return FcTrue;
587
588bail0:
589    return FcFalse;
590}
591
592FcBool
593FcPatternObjectAddWithBinding  (FcPattern	*p,
594				FcObject	object,
595				FcValue		value,
596				FcValueBinding  binding,
597				FcBool		append)
598{
599    FcPatternElt   *e;
600    FcValueListPtr new, *prev;
601
602    if (FcRefIsConst (&p->ref))
603	goto bail0;
604
605    new = FcValueListCreate ();
606    if (!new)
607	goto bail0;
608
609    value = FcValueSave (value);
610    if (value.type == FcTypeVoid)
611	goto bail1;
612
613    /*
614     * Make sure the stored type is valid for built-in objects
615     */
616    if (!FcObjectValidType (object, value.type))
617    {
618	fprintf (stderr,
619		 "Fontconfig warning: FcPattern object %s does not accept value",
620		 FcObjectName (object));
621	FcValuePrintFile (stderr, value);
622	fprintf (stderr, "\n");
623	goto bail1;
624    }
625
626    new->value = value;
627    new->binding = binding;
628    new->next = NULL;
629
630    e = FcPatternObjectInsertElt (p, object);
631    if (!e)
632	goto bail2;
633
634    if (append)
635    {
636	for (prev = &e->values; *prev; prev = &(*prev)->next)
637	    ;
638	*prev = new;
639    }
640    else
641    {
642	new->next = e->values;
643	e->values = new;
644    }
645
646    return FcTrue;
647
648bail2:
649    FcValueDestroy (value);
650bail1:
651    free (new);
652bail0:
653    return FcFalse;
654}
655
656FcBool
657FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
658{
659    return FcPatternObjectAddWithBinding (p, object,
660					  value, FcValueBindingStrong, append);
661}
662
663FcBool
664FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
665{
666    return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
667					  value, FcValueBindingStrong, append);
668}
669
670FcBool
671FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
672{
673    return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
674					  value, FcValueBindingWeak, append);
675}
676
677FcBool
678FcPatternObjectDel (FcPattern *p, FcObject object)
679{
680    FcPatternElt   *e;
681
682    e = FcPatternObjectFindElt (p, object);
683    if (!e)
684	return FcFalse;
685
686    /* destroy value */
687    FcValueListDestroy (e->values);
688
689    /* shuffle existing ones down */
690    memmove (e, e+1,
691	     (FcPatternElts(p) + p->num - (e + 1)) *
692	     sizeof (FcPatternElt));
693    p->num--;
694    e = FcPatternElts(p) + p->num;
695    e->object = 0;
696    e->values = NULL;
697    return FcTrue;
698}
699
700FcBool
701FcPatternDel (FcPattern *p, const char *object)
702{
703    return FcPatternObjectDel (p, FcObjectFromName (object));
704}
705
706FcBool
707FcPatternRemove (FcPattern *p, const char *object, int id)
708{
709    FcPatternElt    *e;
710    FcValueListPtr  *prev, l;
711
712    e = FcPatternObjectFindElt (p, FcObjectFromName (object));
713    if (!e)
714	return FcFalse;
715    for (prev = &e->values; (l = *prev); prev = &l->next)
716    {
717	if (!id)
718	{
719	    *prev = l->next;
720	    l->next = NULL;
721	    FcValueListDestroy (l);
722	    if (!e->values)
723		FcPatternDel (p, object);
724	    return FcTrue;
725	}
726	id--;
727    }
728    return FcFalse;
729}
730
731FcBool
732FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
733{
734    FcValue	v;
735
736    v.type = FcTypeInteger;
737    v.u.i = i;
738    return FcPatternObjectAdd (p, object, v, FcTrue);
739}
740
741FcBool
742FcPatternAddInteger (FcPattern *p, const char *object, int i)
743{
744    return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
745}
746
747FcBool
748FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
749{
750    FcValue	v;
751
752    v.type = FcTypeDouble;
753    v.u.d = d;
754    return FcPatternObjectAdd (p, object, v, FcTrue);
755}
756
757
758FcBool
759FcPatternAddDouble (FcPattern *p, const char *object, double d)
760{
761    return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
762}
763
764FcBool
765FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
766{
767    FcValue	v;
768
769    if (!s)
770    {
771	v.type = FcTypeVoid;
772	v.u.s = 0;
773	return FcPatternObjectAdd (p, object, v, FcTrue);
774    }
775
776    v.type = FcTypeString;
777    v.u.s = s;
778    return FcPatternObjectAdd (p, object, v, FcTrue);
779}
780
781FcBool
782FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
783{
784    return FcPatternObjectAddString (p, FcObjectFromName (object), s);
785}
786
787FcBool
788FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
789{
790    FcValue	v;
791
792    v.type = FcTypeMatrix;
793    v.u.m = s;
794    return FcPatternAdd (p, object, v, FcTrue);
795}
796
797
798FcBool
799FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
800{
801    FcValue	v;
802
803    v.type = FcTypeBool;
804    v.u.b = b;
805    return FcPatternObjectAdd (p, object, v, FcTrue);
806}
807
808FcBool
809FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
810{
811    return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
812}
813
814FcBool
815FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
816{
817    FcValue	v;
818
819    v.type = FcTypeCharSet;
820    v.u.c = (FcCharSet *)c;
821    return FcPatternAdd (p, object, v, FcTrue);
822}
823
824FcBool
825FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
826{
827    FcValue	v;
828
829    v.type = FcTypeFTFace;
830    v.u.f = (void *) f;
831    return FcPatternAdd (p, object, v, FcTrue);
832}
833
834FcBool
835FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
836{
837    FcValue	v;
838
839    v.type = FcTypeLangSet;
840    v.u.l = (FcLangSet *)ls;
841    return FcPatternAdd (p, object, v, FcTrue);
842}
843
844FcResult
845FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
846{
847    FcPatternElt   *e;
848    FcValueListPtr l;
849
850    if (!p)
851	return FcResultNoMatch;
852    e = FcPatternObjectFindElt (p, object);
853    if (!e)
854	return FcResultNoMatch;
855    for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
856    {
857	if (!id)
858	{
859	    *v = FcValueCanonicalize(&l->value);
860	    return FcResultMatch;
861	}
862	id--;
863    }
864    return FcResultNoId;
865}
866
867FcResult
868FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
869{
870    return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
871}
872
873FcResult
874FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
875{
876    FcValue	v;
877    FcResult	r;
878
879    r = FcPatternObjectGet (p, object, id, &v);
880    if (r != FcResultMatch)
881	return r;
882    switch ((int) v.type) {
883    case FcTypeDouble:
884	*i = (int) v.u.d;
885	break;
886    case FcTypeInteger:
887	*i = v.u.i;
888	break;
889    default:
890        return FcResultTypeMismatch;
891    }
892    return FcResultMatch;
893}
894
895FcResult
896FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
897{
898    return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
899}
900
901
902FcResult
903FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
904{
905    FcValue	v;
906    FcResult	r;
907
908    r = FcPatternObjectGet (p, object, id, &v);
909    if (r != FcResultMatch)
910	return r;
911    switch ((int) v.type) {
912    case FcTypeDouble:
913	*d = v.u.d;
914	break;
915    case FcTypeInteger:
916	*d = (double) v.u.i;
917	break;
918    default:
919        return FcResultTypeMismatch;
920    }
921    return FcResultMatch;
922}
923
924FcResult
925FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
926{
927    return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
928}
929
930FcResult
931FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
932{
933    FcValue	v;
934    FcResult	r;
935
936    r = FcPatternObjectGet (p, object, id, &v);
937    if (r != FcResultMatch)
938	return r;
939    if (v.type != FcTypeString)
940        return FcResultTypeMismatch;
941
942    *s = (FcChar8 *) v.u.s;
943    return FcResultMatch;
944}
945
946FcResult
947FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
948{
949    return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
950}
951
952FcResult
953FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
954{
955    FcValue	v;
956    FcResult	r;
957
958    r = FcPatternGet (p, object, id, &v);
959    if (r != FcResultMatch)
960	return r;
961    if (v.type != FcTypeMatrix)
962        return FcResultTypeMismatch;
963    *m = (FcMatrix *)v.u.m;
964    return FcResultMatch;
965}
966
967
968FcResult
969FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
970{
971    FcValue	v;
972    FcResult	r;
973
974    r = FcPatternGet (p, object, id, &v);
975    if (r != FcResultMatch)
976	return r;
977    if (v.type != FcTypeBool)
978        return FcResultTypeMismatch;
979    *b = v.u.b;
980    return FcResultMatch;
981}
982
983FcResult
984FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
985{
986    FcValue	v;
987    FcResult	r;
988
989    r = FcPatternGet (p, object, id, &v);
990    if (r != FcResultMatch)
991	return r;
992    if (v.type != FcTypeCharSet)
993        return FcResultTypeMismatch;
994    *c = (FcCharSet *)v.u.c;
995    return FcResultMatch;
996}
997
998FcResult
999FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1000{
1001    FcValue	v;
1002    FcResult	r;
1003
1004    r = FcPatternGet (p, object, id, &v);
1005    if (r != FcResultMatch)
1006	return r;
1007    if (v.type != FcTypeFTFace)
1008	return FcResultTypeMismatch;
1009    *f = (FT_Face) v.u.f;
1010    return FcResultMatch;
1011}
1012
1013FcResult
1014FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1015{
1016    FcValue	v;
1017    FcResult	r;
1018
1019    r = FcPatternGet (p, object, id, &v);
1020    if (r != FcResultMatch)
1021	return r;
1022    if (v.type != FcTypeLangSet)
1023        return FcResultTypeMismatch;
1024    *ls = (FcLangSet *)v.u.l;
1025    return FcResultMatch;
1026}
1027
1028FcPattern *
1029FcPatternDuplicate (const FcPattern *orig)
1030{
1031    FcPattern	    *new;
1032    FcPatternElt    *e;
1033    int		    i;
1034    FcValueListPtr  l;
1035
1036    new = FcPatternCreate ();
1037    if (!new)
1038	goto bail0;
1039
1040    e = FcPatternElts(orig);
1041
1042    for (i = 0; i < orig->num; i++)
1043    {
1044	for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
1045	{
1046	    if (!FcPatternObjectAddWithBinding (new, e[i].object,
1047						FcValueCanonicalize(&l->value),
1048						l->binding,
1049						FcTrue))
1050		goto bail1;
1051
1052	}
1053    }
1054
1055    return new;
1056
1057bail1:
1058    FcPatternDestroy (new);
1059bail0:
1060    return 0;
1061}
1062
1063void
1064FcPatternReference (FcPattern *p)
1065{
1066    if (!FcRefIsConst (&p->ref))
1067	FcRefInc (&p->ref);
1068    else
1069	FcCacheObjectReference (p);
1070}
1071
1072FcPattern *
1073FcPatternVaBuild (FcPattern *p, va_list va)
1074{
1075    FcPattern	*ret;
1076
1077    FcPatternVapBuild (ret, p, va);
1078    return ret;
1079}
1080
1081FcPattern *
1082FcPatternBuild (FcPattern *p, ...)
1083{
1084    va_list	va;
1085
1086    va_start (va, p);
1087    FcPatternVapBuild (p, p, va);
1088    va_end (va);
1089    return p;
1090}
1091
1092/*
1093 * Add all of the elements in 's' to 'p'
1094 */
1095FcBool
1096FcPatternAppend (FcPattern *p, FcPattern *s)
1097{
1098    int		    i;
1099    FcPatternElt    *e;
1100    FcValueListPtr  v;
1101
1102    for (i = 0; i < s->num; i++)
1103    {
1104	e = FcPatternElts(s)+i;
1105	for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
1106	{
1107	    if (!FcPatternObjectAddWithBinding (p, e->object,
1108						FcValueCanonicalize(&v->value),
1109						v->binding, FcTrue))
1110		return FcFalse;
1111	}
1112    }
1113    return FcTrue;
1114}
1115
1116FcPattern *
1117FcPatternFilter (FcPattern *p, const FcObjectSet *os)
1118{
1119    int		    i;
1120    FcPattern	    *ret;
1121    FcPatternElt    *e;
1122    FcValueListPtr  v;
1123
1124    if (!os)
1125	return FcPatternDuplicate (p);
1126
1127    ret = FcPatternCreate ();
1128    if (!ret)
1129	return NULL;
1130
1131    for (i = 0; i < os->nobject; i++)
1132    {
1133	FcObject object = FcObjectFromName (os->objects[i]);
1134	e = FcPatternObjectFindElt (p, object);
1135	if (e)
1136	{
1137	    for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
1138	    {
1139		if (!FcPatternObjectAddWithBinding (ret, e->object,
1140						    FcValueCanonicalize(&v->value),
1141						    v->binding, FcTrue))
1142		    goto bail0;
1143	    }
1144	}
1145    }
1146    return ret;
1147
1148bail0:
1149    FcPatternDestroy (ret);
1150    return NULL;
1151}
1152
1153
1154FcBool
1155FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
1156{
1157    int	i;
1158    FcPatternElt    *elts = FcPatternElts(pat);
1159
1160    if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1161	return FcFalse;
1162    if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
1163	return FcFalse;
1164    for (i = 0; i < pat->num; i++)
1165	if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1166	    return FcFalse;
1167    return FcTrue;
1168}
1169
1170FcPattern *
1171FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
1172{
1173    FcPattern	    *pat_serialized;
1174    FcPatternElt    *elts = FcPatternElts (pat);
1175    FcPatternElt    *elts_serialized;
1176    FcValueList	    *values_serialized;
1177    int		    i;
1178
1179    pat_serialized = FcSerializePtr (serialize, pat);
1180    if (!pat_serialized)
1181	return NULL;
1182    *pat_serialized = *pat;
1183    pat_serialized->size = pat->num;
1184    FcRefSetConst (&pat_serialized->ref);
1185
1186    elts_serialized = FcSerializePtr (serialize, elts);
1187    if (!elts_serialized)
1188	return NULL;
1189
1190    pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1191						 elts_serialized);
1192
1193    for (i = 0; i < pat->num; i++)
1194    {
1195	values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1196	if (!values_serialized)
1197	    return NULL;
1198	elts_serialized[i].object = elts[i].object;
1199	elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
1200							  values_serialized,
1201							  FcValueList);
1202    }
1203    if (FcDebug() & FC_DBG_CACHEV) {
1204	printf ("Raw pattern:\n");
1205	FcPatternPrint (pat);
1206	printf ("Serialized pattern:\n");
1207	FcPatternPrint (pat_serialized);
1208	printf ("\n");
1209    }
1210    return pat_serialized;
1211}
1212
1213FcBool
1214FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
1215{
1216    while (vl)
1217    {
1218	if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1219	    return FcFalse;
1220	switch ((int) vl->value.type) {
1221	case FcTypeString:
1222	    if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1223		return FcFalse;
1224	    break;
1225	case FcTypeCharSet:
1226	    if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1227		return FcFalse;
1228	    break;
1229	case FcTypeLangSet:
1230	    if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1231		return FcFalse;
1232	    break;
1233	default:
1234	    break;
1235	}
1236	vl = vl->next;
1237    }
1238    return FcTrue;
1239}
1240
1241FcValueList *
1242FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
1243{
1244    FcValueList	*vl_serialized;
1245    FcChar8	*s_serialized;
1246    FcCharSet	*c_serialized;
1247    FcLangSet	*l_serialized;
1248    FcValueList	*head_serialized = NULL;
1249    FcValueList	*prev_serialized = NULL;
1250
1251    while (vl)
1252    {
1253	vl_serialized = FcSerializePtr (serialize, vl);
1254	if (!vl_serialized)
1255	    return NULL;
1256
1257	if (prev_serialized)
1258	    prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1259							  vl_serialized,
1260							  FcValueList);
1261	else
1262	    head_serialized = vl_serialized;
1263
1264	vl_serialized->next = NULL;
1265	vl_serialized->value.type = vl->value.type;
1266	switch ((int) vl->value.type) {
1267	case FcTypeInteger:
1268	    vl_serialized->value.u.i = vl->value.u.i;
1269	    break;
1270	case FcTypeDouble:
1271	    vl_serialized->value.u.d = vl->value.u.d;
1272	    break;
1273	case FcTypeString:
1274	    s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1275	    if (!s_serialized)
1276		return NULL;
1277	    vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1278							     s_serialized,
1279							     FcChar8);
1280	    break;
1281	case FcTypeBool:
1282	    vl_serialized->value.u.b = vl->value.u.b;
1283	    break;
1284	case FcTypeMatrix:
1285	    /* can't happen */
1286	    break;
1287	case FcTypeCharSet:
1288	    c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1289	    if (!c_serialized)
1290		return NULL;
1291	    vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1292							     c_serialized,
1293							     FcCharSet);
1294	    break;
1295	case FcTypeFTFace:
1296	    /* can't happen */
1297	    break;
1298	case FcTypeLangSet:
1299	    l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1300	    if (!l_serialized)
1301		return NULL;
1302	    vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1303							     l_serialized,
1304							     FcLangSet);
1305	    break;
1306	default:
1307	    break;
1308	}
1309	prev_serialized = vl_serialized;
1310	vl = vl->next;
1311    }
1312    return head_serialized;
1313}
1314
1315#define __fcpat__
1316#include "fcaliastail.h"
1317#include "fcftaliastail.h"
1318#undef __fcpat__
1319