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