fcpat.c revision a4e54154
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    case FcTypeRange:
61	FcRangeDestroy ((FcRange *) v.u.r);
62	break;
63    default:
64	break;
65    }
66}
67
68FcValue
69FcValueCanonicalize (const FcValue *v)
70{
71    FcValue new;
72
73    switch ((int) v->type)
74    {
75    case FcTypeString:
76	new.u.s = FcValueString(v);
77	new.type = FcTypeString;
78	break;
79    case FcTypeCharSet:
80	new.u.c = FcValueCharSet(v);
81	new.type = FcTypeCharSet;
82	break;
83    case FcTypeLangSet:
84	new.u.l = FcValueLangSet(v);
85	new.type = FcTypeLangSet;
86	break;
87    case FcTypeRange:
88	new.u.r = FcValueRange(v);
89	new.type = FcTypeRange;
90	break;
91    default:
92	new = *v;
93	break;
94    }
95    return new;
96}
97
98FcValue
99FcValueSave (FcValue v)
100{
101    switch ((int) v.type) {
102    case FcTypeString:
103	v.u.s = FcStrdup (v.u.s);
104	if (!v.u.s)
105	    v.type = FcTypeVoid;
106	break;
107    case FcTypeMatrix:
108	v.u.m = FcMatrixCopy (v.u.m);
109	if (!v.u.m)
110	    v.type = FcTypeVoid;
111	break;
112    case FcTypeCharSet:
113	v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
114	if (!v.u.c)
115	    v.type = FcTypeVoid;
116	break;
117    case FcTypeLangSet:
118	v.u.l = FcLangSetCopy (v.u.l);
119	if (!v.u.l)
120	    v.type = FcTypeVoid;
121	break;
122    case FcTypeRange:
123	v.u.r = FcRangeCopy (v.u.r);
124	if (!v.u.r)
125	    v.type = FcTypeVoid;
126	break;
127    default:
128	break;
129    }
130    return v;
131}
132
133FcValueListPtr
134FcValueListCreate (void)
135{
136    return calloc (1, sizeof (FcValueList));
137}
138
139void
140FcValueListDestroy (FcValueListPtr l)
141{
142    FcValueListPtr next;
143    for (; l; l = next)
144    {
145	FcValueDestroy (l->value);
146	next = FcValueListNext(l);
147	free(l);
148    }
149}
150
151FcValueListPtr
152FcValueListPrepend (FcValueListPtr vallist,
153		    FcValue        value,
154		    FcValueBinding binding)
155{
156    FcValueListPtr new;
157
158    if (value.type == FcTypeVoid)
159	return vallist;
160    new = FcValueListCreate ();
161    if (!new)
162	return vallist;
163
164    new->value = FcValueSave (value);
165    new->binding = binding;
166    new->next = vallist;
167
168    return new;
169}
170
171FcValueListPtr
172FcValueListAppend (FcValueListPtr vallist,
173		   FcValue        value,
174		   FcValueBinding binding)
175{
176    FcValueListPtr new, last;
177
178    if (value.type == FcTypeVoid)
179	return vallist;
180    new = FcValueListCreate ();
181    if (!new)
182	return vallist;
183
184    new->value = FcValueSave (value);
185    new->binding = binding;
186    new->next = NULL;
187
188    if (vallist)
189    {
190	for (last = vallist; FcValueListNext (last); last = FcValueListNext (last));
191
192	last->next = new;
193    }
194    else
195	vallist = new;
196
197    return vallist;
198}
199
200FcValueListPtr
201FcValueListDuplicate(FcValueListPtr orig)
202{
203    FcValueListPtr new = NULL, l, t = NULL;
204    FcValue v;
205
206    for (l = orig; l != NULL; l = FcValueListNext (l))
207    {
208	if (!new)
209	{
210	    t = new = FcValueListCreate();
211	}
212	else
213	{
214	    t->next = FcValueListCreate();
215	    t = FcValueListNext (t);
216	}
217	v = FcValueCanonicalize (&l->value);
218	t->value = FcValueSave (v);
219	t->binding = l->binding;
220	t->next = NULL;
221    }
222
223    return new;
224}
225
226FcBool
227FcValueEqual (FcValue va, FcValue vb)
228{
229    if (va.type != vb.type)
230    {
231	if (va.type == FcTypeInteger)
232	{
233	    va.type = FcTypeDouble;
234	    va.u.d = va.u.i;
235	}
236	if (vb.type == FcTypeInteger)
237	{
238	    vb.type = FcTypeDouble;
239	    vb.u.d = vb.u.i;
240	}
241	if (va.type != vb.type)
242	    return FcFalse;
243    }
244    switch (va.type) {
245    case FcTypeUnknown:
246	return FcFalse;	/* don't know how to compare this object */
247    case FcTypeVoid:
248	return FcTrue;
249    case FcTypeInteger:
250	return va.u.i == vb.u.i;
251    case FcTypeDouble:
252	return va.u.d == vb.u.d;
253    case FcTypeString:
254	return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
255    case FcTypeBool:
256	return va.u.b == vb.u.b;
257    case FcTypeMatrix:
258	return FcMatrixEqual (va.u.m, vb.u.m);
259    case FcTypeCharSet:
260	return FcCharSetEqual (va.u.c, vb.u.c);
261    case FcTypeFTFace:
262	return va.u.f == vb.u.f;
263    case FcTypeLangSet:
264	return FcLangSetEqual (va.u.l, vb.u.l);
265    case FcTypeRange:
266	return FcRangeIsInRange (va.u.r, vb.u.r);
267    }
268    return FcFalse;
269}
270
271static FcChar32
272FcDoubleHash (double d)
273{
274    if (d < 0)
275	d = -d;
276    if (d > 0xffffffff)
277	d = 0xffffffff;
278    return (FcChar32) d;
279}
280
281FcChar32
282FcStringHash (const FcChar8 *s)
283{
284    FcChar8	c;
285    FcChar32	h = 0;
286
287    if (s)
288	while ((c = *s++))
289	    h = ((h << 1) | (h >> 31)) ^ c;
290    return h;
291}
292
293static FcChar32
294FcValueHash (const FcValue *v)
295{
296    switch (v->type) {
297    case FcTypeUnknown:
298    case FcTypeVoid:
299	return 0;
300    case FcTypeInteger:
301	return (FcChar32) v->u.i;
302    case FcTypeDouble:
303	return FcDoubleHash (v->u.d);
304    case FcTypeString:
305	return FcStringHash (FcValueString(v));
306    case FcTypeBool:
307	return (FcChar32) v->u.b;
308    case FcTypeMatrix:
309	return (FcDoubleHash (v->u.m->xx) ^
310		FcDoubleHash (v->u.m->xy) ^
311		FcDoubleHash (v->u.m->yx) ^
312		FcDoubleHash (v->u.m->yy));
313    case FcTypeCharSet:
314	return (FcChar32) FcValueCharSet(v)->num;
315    case FcTypeFTFace:
316	return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
317	       FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
318    case FcTypeLangSet:
319	return FcLangSetHash (FcValueLangSet(v));
320    case FcTypeRange:
321	return FcRangeHash (FcValueRange (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
356static void *
357FcPatternGetCacheObject (FcPattern *p)
358{
359  /* We use a value to find the cache, instead of the FcPattern object
360   * because the pattern itself may be a cache allocation if we rewrote the path,
361   * so the p may not be in the cached region. */
362  return FcPatternEltValues(&FcPatternElts (p)[0]);
363}
364
365FcPattern *
366FcPatternCacheRewriteFile (const FcPattern *p,
367                           FcCache *cache,
368                           const FcChar8 *relocated_font_file)
369{
370    FcPatternElt *elts = FcPatternElts (p);
371    size_t i,j;
372    FcChar8 *data;
373    FcPattern *new_p;
374    FcPatternElt *new_elts;
375    FcValueList *new_value_list;
376    size_t new_path_len = strlen ((char *)relocated_font_file);
377    FcChar8 *new_path;
378
379    /* Allocate space for the patter, the PatternElt headers and
380     * the FC_FILE FcValueList and path that will be freed with the
381     * cache */
382    data = FcCacheAllocate (cache,
383			    sizeof (FcPattern) +
384			    p->num * sizeof (FcPatternElt) +
385			    sizeof (FcValueList) +
386			    new_path_len + 1);
387
388    new_p = (FcPattern *)data;
389    data += sizeof (FcPattern);
390    new_elts = (FcPatternElt *)(data);
391    data += p->num * sizeof (FcPatternElt);
392    new_value_list = (FcValueList *)data;
393    data += sizeof (FcValueList);
394    new_path = data;
395
396    *new_p = *p;
397    new_p->elts_offset = FcPtrToOffset (new_p, new_elts);
398
399    /* Copy all but the FILE values from the cache */
400    for (i = 0, j = 0; i < p->num; i++)
401    {
402	FcPatternElt *elt = &elts[i];
403	new_elts[j].object = elt->object;
404	if (elt->object != FC_FILE_OBJECT)
405	    new_elts[j++].values = FcPatternEltValues(elt);
406	else
407	    new_elts[j++].values = new_value_list;
408    }
409
410    new_value_list->next = NULL;
411    new_value_list->value.type = FcTypeString;
412    new_value_list->value.u.s = new_path;
413    new_value_list->binding = FcValueBindingWeak;
414
415    /* Add rewritten path at the end */
416    strcpy ((char *)new_path, (char *)relocated_font_file);
417
418    return new_p;
419}
420
421void
422FcPatternDestroy (FcPattern *p)
423{
424    int		    i;
425    FcPatternElt    *elts;
426
427    if (!p)
428	return;
429
430    if (FcRefIsConst (&p->ref))
431    {
432	FcCacheObjectDereference (FcPatternGetCacheObject(p));
433	return;
434    }
435
436    if (FcRefDec (&p->ref) != 1)
437	return;
438
439    elts = FcPatternElts (p);
440    for (i = 0; i < FcPatternObjectCount (p); i++)
441	FcValueListDestroy (FcPatternEltValues(&elts[i]));
442
443    free (elts);
444    free (p);
445}
446
447int
448FcPatternObjectCount (const FcPattern *pat)
449{
450    if (pat)
451	return pat->num;
452
453    return 0;
454}
455
456
457static int
458FcPatternObjectPosition (const FcPattern *p, FcObject object)
459{
460    int	    low, high, mid, c;
461    FcPatternElt    *elts = FcPatternElts(p);
462
463    low = 0;
464    high = FcPatternObjectCount (p) - 1;
465    c = 1;
466    mid = 0;
467    while (low <= high)
468    {
469	mid = (low + high) >> 1;
470	c = elts[mid].object - object;
471	if (c == 0)
472	    return mid;
473	if (c < 0)
474	    low = mid + 1;
475	else
476	    high = mid - 1;
477    }
478    if (c < 0)
479	mid++;
480    return -(mid + 1);
481}
482
483int
484FcPatternPosition (const FcPattern *p, const char *object)
485{
486    return FcPatternObjectPosition (p, FcObjectFromName (object));
487}
488
489FcPatternElt *
490FcPatternObjectFindElt (const FcPattern *p, FcObject object)
491{
492    int	    i = FcPatternObjectPosition (p, object);
493    if (i < 0)
494	return 0;
495    return &FcPatternElts(p)[i];
496}
497
498FcPatternElt *
499FcPatternObjectInsertElt (FcPattern *p, FcObject object)
500{
501    int		    i;
502    FcPatternElt   *e;
503
504    i = FcPatternObjectPosition (p, object);
505    if (i < 0)
506    {
507	i = -i - 1;
508
509	/* reallocate array */
510	if (FcPatternObjectCount (p) + 1 >= p->size)
511	{
512	    int s = p->size + 16;
513	    if (p->size)
514	    {
515		FcPatternElt *e0 = FcPatternElts(p);
516		e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
517		if (!e) /* maybe it was mmapped */
518		{
519		    e = malloc(s * sizeof (FcPatternElt));
520		    if (e)
521			memcpy(e, e0, FcPatternObjectCount (p) * sizeof (FcPatternElt));
522		}
523	    }
524	    else
525		e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
526	    if (!e)
527		return FcFalse;
528	    p->elts_offset = FcPtrToOffset (p, e);
529	    while (p->size < s)
530	    {
531		e[p->size].object = 0;
532		e[p->size].values = NULL;
533		p->size++;
534	    }
535	}
536
537	e = FcPatternElts(p);
538	/* move elts up */
539	memmove (e + i + 1,
540		 e + i,
541		 sizeof (FcPatternElt) *
542		 (FcPatternObjectCount (p) - i));
543
544	/* bump count */
545	p->num++;
546
547	e[i].object = object;
548	e[i].values = NULL;
549    }
550
551    return FcPatternElts(p) + i;
552}
553
554FcBool
555FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
556{
557    FcPatternIter ia, ib;
558
559    if (pa == pb)
560	return FcTrue;
561
562    if (FcPatternObjectCount (pa) != FcPatternObjectCount (pb))
563	return FcFalse;
564    FcPatternIterStart (pa, &ia);
565    FcPatternIterStart (pb, &ib);
566    do {
567	FcBool ra, rb;
568
569	if (!FcPatternIterEqual (pa, &ia, pb, &ib))
570	    return FcFalse;
571	ra = FcPatternIterNext (pa, &ia);
572	rb = FcPatternIterNext (pb, &ib);
573	if (!ra && !rb)
574	    break;
575    } while (1);
576
577    return FcTrue;
578}
579
580FcChar32
581FcPatternHash (const FcPattern *p)
582{
583    int		i;
584    FcChar32	h = 0;
585    FcPatternElt    *pe = FcPatternElts(p);
586
587    for (i = 0; i < FcPatternObjectCount (p); i++)
588    {
589	h = (((h << 1) | (h >> 31)) ^
590	     pe[i].object ^
591	     FcValueListHash (FcPatternEltValues(&pe[i])));
592    }
593    return h;
594}
595
596FcBool
597FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
598{
599    FcPatternElt    *ea, *eb;
600    int		    i;
601
602    for (i = 0; i < os->nobject; i++)
603    {
604	FcObject    object = FcObjectFromName (os->objects[i]);
605	ea = FcPatternObjectFindElt (pai, object);
606	eb = FcPatternObjectFindElt (pbi, object);
607	if (ea)
608	{
609	    if (!eb)
610		return FcFalse;
611	    if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
612		return FcFalse;
613	}
614	else
615	{
616	    if (eb)
617		return FcFalse;
618	}
619    }
620    return FcTrue;
621}
622
623FcBool
624FcPatternObjectListAdd (FcPattern	*p,
625			FcObject	object,
626			FcValueListPtr	list,
627			FcBool		append)
628{
629    FcPatternElt   *e;
630    FcValueListPtr l, *prev;
631
632    if (FcRefIsConst (&p->ref))
633	goto bail0;
634
635    /*
636     * Make sure the stored type is valid for built-in objects
637     */
638    for (l = list; l != NULL; l = FcValueListNext (l))
639    {
640	if (!FcObjectValidType (object, l->value.type))
641	{
642	    fprintf (stderr,
643		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
644	    FcValuePrintFile (stderr, l->value);
645	    fprintf (stderr, "\n");
646	    goto bail0;
647	}
648    }
649
650    e = FcPatternObjectInsertElt (p, object);
651    if (!e)
652	goto bail0;
653
654    if (append)
655    {
656	for (prev = &e->values; *prev; prev = &(*prev)->next)
657	    ;
658	*prev = list;
659    }
660    else
661    {
662	for (prev = &list; *prev; prev = &(*prev)->next)
663	    ;
664	*prev = e->values;
665	e->values = list;
666    }
667
668    return FcTrue;
669
670bail0:
671    return FcFalse;
672}
673
674FcBool
675FcPatternObjectAddWithBinding  (FcPattern	*p,
676				FcObject	object,
677				FcValue		value,
678				FcValueBinding  binding,
679				FcBool		append)
680{
681    FcPatternElt   *e;
682    FcValueListPtr new, *prev;
683
684    if (FcRefIsConst (&p->ref))
685	goto bail0;
686
687    new = FcValueListCreate ();
688    if (!new)
689	goto bail0;
690
691    new->value = FcValueSave (value);
692    new->binding = binding;
693    new->next = NULL;
694
695    if (new->value.type == FcTypeVoid)
696	goto bail1;
697
698    /*
699     * Make sure the stored type is valid for built-in objects
700     */
701    if (!FcObjectValidType (object, new->value.type))
702    {
703	fprintf (stderr,
704		 "Fontconfig warning: FcPattern object %s does not accept value",
705		 FcObjectName (object));
706	FcValuePrintFile (stderr, new->value);
707	fprintf (stderr, "\n");
708	goto bail1;
709    }
710
711    e = FcPatternObjectInsertElt (p, object);
712    if (!e)
713	goto bail1;
714
715    if (append)
716    {
717	for (prev = &e->values; *prev; prev = &(*prev)->next)
718	    ;
719	*prev = new;
720    }
721    else
722    {
723	new->next = e->values;
724	e->values = new;
725    }
726
727    return FcTrue;
728
729bail1:
730    FcValueListDestroy (new);
731bail0:
732    return FcFalse;
733}
734
735FcBool
736FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
737{
738    return FcPatternObjectAddWithBinding (p, object,
739					  value, FcValueBindingStrong, append);
740}
741
742FcBool
743FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
744{
745    return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
746					  value, FcValueBindingStrong, append);
747}
748
749FcBool
750FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
751{
752    return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
753					  value, FcValueBindingWeak, append);
754}
755
756FcBool
757FcPatternObjectDel (FcPattern *p, FcObject object)
758{
759    FcPatternElt   *e;
760
761    e = FcPatternObjectFindElt (p, object);
762    if (!e)
763	return FcFalse;
764
765    /* destroy value */
766    FcValueListDestroy (e->values);
767
768    /* shuffle existing ones down */
769    memmove (e, e+1,
770	     (FcPatternElts(p) + FcPatternObjectCount (p) - (e + 1)) *
771	     sizeof (FcPatternElt));
772    p->num--;
773    e = FcPatternElts(p) + FcPatternObjectCount (p);
774    e->object = 0;
775    e->values = NULL;
776    return FcTrue;
777}
778
779FcBool
780FcPatternDel (FcPattern *p, const char *object)
781{
782    return FcPatternObjectDel (p, FcObjectFromName (object));
783}
784
785FcBool
786FcPatternRemove (FcPattern *p, const char *object, int id)
787{
788    FcPatternElt    *e;
789    FcValueListPtr  *prev, l;
790
791    e = FcPatternObjectFindElt (p, FcObjectFromName (object));
792    if (!e)
793	return FcFalse;
794    for (prev = &e->values; (l = *prev); prev = &l->next)
795    {
796	if (!id)
797	{
798	    *prev = l->next;
799	    l->next = NULL;
800	    FcValueListDestroy (l);
801	    if (!e->values)
802		FcPatternDel (p, object);
803	    return FcTrue;
804	}
805	id--;
806    }
807    return FcFalse;
808}
809
810FcBool
811FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
812{
813    FcValue	v;
814
815    v.type = FcTypeInteger;
816    v.u.i = i;
817    return FcPatternObjectAdd (p, object, v, FcTrue);
818}
819
820FcBool
821FcPatternAddInteger (FcPattern *p, const char *object, int i)
822{
823    return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
824}
825
826FcBool
827FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
828{
829    FcValue	v;
830
831    v.type = FcTypeDouble;
832    v.u.d = d;
833    return FcPatternObjectAdd (p, object, v, FcTrue);
834}
835
836
837FcBool
838FcPatternAddDouble (FcPattern *p, const char *object, double d)
839{
840    return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
841}
842
843FcBool
844FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
845{
846    FcValue	v;
847
848    if (!s)
849    {
850	v.type = FcTypeVoid;
851	v.u.s = 0;
852	return FcPatternObjectAdd (p, object, v, FcTrue);
853    }
854
855    v.type = FcTypeString;
856    v.u.s = s;
857    return FcPatternObjectAdd (p, object, v, FcTrue);
858}
859
860FcBool
861FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
862{
863    return FcPatternObjectAddString (p, FcObjectFromName (object), s);
864}
865
866FcBool
867FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
868{
869    FcValue	v;
870
871    v.type = FcTypeMatrix;
872    v.u.m = s;
873    return FcPatternAdd (p, object, v, FcTrue);
874}
875
876
877FcBool
878FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
879{
880    FcValue	v;
881
882    v.type = FcTypeBool;
883    v.u.b = b;
884    return FcPatternObjectAdd (p, object, v, FcTrue);
885}
886
887FcBool
888FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
889{
890    return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
891}
892
893FcBool
894FcPatternObjectAddCharSet (FcPattern *p, FcObject object, const FcCharSet *c)
895{
896    FcValue	v;
897
898    v.type = FcTypeCharSet;
899    v.u.c = (FcCharSet *)c;
900    return FcPatternObjectAdd (p, object, v, FcTrue);
901}
902
903FcBool
904FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
905{
906    return FcPatternObjectAddCharSet (p, FcObjectFromName (object), c);
907}
908
909FcBool
910FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
911{
912    FcValue	v;
913
914    v.type = FcTypeFTFace;
915    v.u.f = (void *) f;
916    return FcPatternAdd (p, object, v, FcTrue);
917}
918
919FcBool
920FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls)
921{
922    FcValue	v;
923
924    v.type = FcTypeLangSet;
925    v.u.l = (FcLangSet *)ls;
926    return FcPatternObjectAdd (p, object, v, FcTrue);
927}
928
929FcBool
930FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
931{
932    return FcPatternObjectAddLangSet (p, FcObjectFromName (object), ls);
933}
934
935FcBool
936FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r)
937{
938    FcValue v;
939
940    v.type = FcTypeRange;
941    v.u.r = (FcRange *)r;
942    return FcPatternObjectAdd (p, object, v, FcTrue);
943}
944
945FcBool
946FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r)
947{
948    return FcPatternObjectAddRange (p, FcObjectFromName (object), r);
949}
950
951FcResult
952FcPatternObjectGetWithBinding (const FcPattern *p, FcObject object, int id, FcValue *v, FcValueBinding *b)
953{
954    FcPatternElt   *e;
955    FcValueListPtr l;
956
957    if (!p)
958	return FcResultNoMatch;
959    e = FcPatternObjectFindElt (p, object);
960    if (!e)
961	return FcResultNoMatch;
962    for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
963    {
964	if (!id)
965	{
966	    *v = FcValueCanonicalize(&l->value);
967	    if (b)
968		*b = l->binding;
969	    return FcResultMatch;
970	}
971	id--;
972    }
973    return FcResultNoId;
974}
975
976FcResult
977FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
978{
979    return FcPatternObjectGetWithBinding (p, object, id, v, NULL);
980}
981
982FcResult
983FcPatternGetWithBinding (const FcPattern *p, const char *object, int id, FcValue *v, FcValueBinding *b)
984{
985    return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, b);
986}
987
988FcResult
989FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
990{
991    return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, NULL);
992}
993
994FcResult
995FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
996{
997    FcValue	v;
998    FcResult	r;
999
1000    r = FcPatternObjectGet (p, object, id, &v);
1001    if (r != FcResultMatch)
1002	return r;
1003    switch ((int) v.type) {
1004    case FcTypeDouble:
1005	*i = (int) v.u.d;
1006	break;
1007    case FcTypeInteger:
1008	*i = v.u.i;
1009	break;
1010    default:
1011        return FcResultTypeMismatch;
1012    }
1013    return FcResultMatch;
1014}
1015
1016FcResult
1017FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
1018{
1019    return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
1020}
1021
1022
1023FcResult
1024FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
1025{
1026    FcValue	v;
1027    FcResult	r;
1028
1029    r = FcPatternObjectGet (p, object, id, &v);
1030    if (r != FcResultMatch)
1031	return r;
1032    switch ((int) v.type) {
1033    case FcTypeDouble:
1034	*d = v.u.d;
1035	break;
1036    case FcTypeInteger:
1037	*d = (double) v.u.i;
1038	break;
1039    default:
1040        return FcResultTypeMismatch;
1041    }
1042    return FcResultMatch;
1043}
1044
1045FcResult
1046FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
1047{
1048    return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
1049}
1050
1051FcResult
1052FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
1053{
1054    FcValue	v;
1055    FcResult	r;
1056
1057    r = FcPatternObjectGet (p, object, id, &v);
1058    if (r != FcResultMatch)
1059	return r;
1060    if (v.type != FcTypeString)
1061        return FcResultTypeMismatch;
1062
1063    *s = (FcChar8 *) v.u.s;
1064    return FcResultMatch;
1065}
1066
1067FcResult
1068FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1069{
1070    return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
1071}
1072
1073FcResult
1074FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1075{
1076    FcValue	v;
1077    FcResult	r;
1078
1079    r = FcPatternGet (p, object, id, &v);
1080    if (r != FcResultMatch)
1081	return r;
1082    if (v.type != FcTypeMatrix)
1083        return FcResultTypeMismatch;
1084    *m = (FcMatrix *)v.u.m;
1085    return FcResultMatch;
1086}
1087
1088
1089FcResult
1090FcPatternObjectGetBool (const FcPattern *p, FcObject object, int id, FcBool *b)
1091{
1092    FcValue	v;
1093    FcResult	r;
1094
1095    r = FcPatternObjectGet (p, object, id, &v);
1096    if (r != FcResultMatch)
1097	return r;
1098    if (v.type != FcTypeBool)
1099        return FcResultTypeMismatch;
1100    *b = v.u.b;
1101    return FcResultMatch;
1102}
1103
1104FcResult
1105FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1106{
1107    return FcPatternObjectGetBool (p, FcObjectFromName (object), id, b);
1108}
1109
1110FcResult
1111FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1112{
1113    FcValue	v;
1114    FcResult	r;
1115
1116    r = FcPatternGet (p, object, id, &v);
1117    if (r != FcResultMatch)
1118	return r;
1119    if (v.type != FcTypeCharSet)
1120        return FcResultTypeMismatch;
1121    *c = (FcCharSet *)v.u.c;
1122    return FcResultMatch;
1123}
1124
1125FcResult
1126FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1127{
1128    FcValue	v;
1129    FcResult	r;
1130
1131    r = FcPatternGet (p, object, id, &v);
1132    if (r != FcResultMatch)
1133	return r;
1134    if (v.type != FcTypeFTFace)
1135	return FcResultTypeMismatch;
1136    *f = (FT_Face) v.u.f;
1137    return FcResultMatch;
1138}
1139
1140FcResult
1141FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1142{
1143    FcValue	v;
1144    FcResult	r;
1145
1146    r = FcPatternGet (p, object, id, &v);
1147    if (r != FcResultMatch)
1148	return r;
1149    if (v.type != FcTypeLangSet)
1150        return FcResultTypeMismatch;
1151    *ls = (FcLangSet *)v.u.l;
1152    return FcResultMatch;
1153}
1154
1155FcResult
1156FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r)
1157{
1158    FcValue	v;
1159    FcResult	res;
1160
1161    res = FcPatternObjectGet (p, object, id, &v);
1162    if (res != FcResultMatch)
1163	return res;
1164    switch ((int)v.type) {
1165    case FcTypeRange:
1166	*r = (FcRange *)v.u.r;
1167	break;
1168    default:
1169	return FcResultTypeMismatch;
1170    }
1171    return FcResultMatch;
1172}
1173
1174FcResult
1175FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r)
1176{
1177    return FcPatternObjectGetRange (p, FcObjectFromName (object), id, r);
1178}
1179
1180FcPattern *
1181FcPatternDuplicate (const FcPattern *orig)
1182{
1183    FcPattern	    *new;
1184    FcPatternIter   iter;
1185    FcValueListPtr  l;
1186
1187    if (!orig)
1188	return NULL;
1189
1190    new = FcPatternCreate ();
1191    if (!new)
1192	goto bail0;
1193
1194    FcPatternIterStart (orig, &iter);
1195    do
1196    {
1197	for (l = FcPatternIterGetValues (orig, &iter); l; l = FcValueListNext (l))
1198	{
1199	    if (!FcPatternObjectAddWithBinding (new, FcPatternIterGetObjectId (orig, &iter),
1200						FcValueCanonicalize(&l->value),
1201						l->binding,
1202						FcTrue))
1203		goto bail1;
1204	}
1205    } while (FcPatternIterNext (orig, &iter));
1206
1207    return new;
1208
1209bail1:
1210    FcPatternDestroy (new);
1211bail0:
1212    return 0;
1213}
1214
1215void
1216FcPatternReference (FcPattern *p)
1217{
1218    if (!FcRefIsConst (&p->ref))
1219	FcRefInc (&p->ref);
1220    else
1221	FcCacheObjectReference (FcPatternGetCacheObject(p));
1222}
1223
1224FcPattern *
1225FcPatternVaBuild (FcPattern *p, va_list va)
1226{
1227    FcPattern	*ret;
1228
1229    FcPatternVapBuild (ret, p, va);
1230    return ret;
1231}
1232
1233FcPattern *
1234FcPatternBuild (FcPattern *p, ...)
1235{
1236    va_list	va;
1237
1238    va_start (va, p);
1239    FcPatternVapBuild (p, p, va);
1240    va_end (va);
1241    return p;
1242}
1243
1244/*
1245 * Add all of the elements in 's' to 'p'
1246 */
1247FcBool
1248FcPatternAppend (FcPattern *p, FcPattern *s)
1249{
1250    FcPatternIter  iter;
1251    FcValueListPtr v;
1252
1253    FcPatternIterStart (s, &iter);
1254    do
1255    {
1256	for (v = FcPatternIterGetValues (s, &iter); v; v = FcValueListNext (v))
1257	{
1258	    if (!FcPatternObjectAddWithBinding (p, FcPatternIterGetObjectId (s, &iter),
1259						FcValueCanonicalize(&v->value),
1260						v->binding, FcTrue))
1261		return FcFalse;
1262	}
1263    } while (FcPatternIterNext (s, &iter));
1264
1265    return FcTrue;
1266}
1267
1268FcPattern *
1269FcPatternFilter (FcPattern *p, const FcObjectSet *os)
1270{
1271    int		    i;
1272    FcPattern	    *ret;
1273    FcPatternElt    *e;
1274    FcValueListPtr  v;
1275
1276    if (!os)
1277	return FcPatternDuplicate (p);
1278
1279    ret = FcPatternCreate ();
1280    if (!ret)
1281	return NULL;
1282
1283    for (i = 0; i < os->nobject; i++)
1284    {
1285	FcObject object = FcObjectFromName (os->objects[i]);
1286	e = FcPatternObjectFindElt (p, object);
1287	if (e)
1288	{
1289	    for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
1290	    {
1291		if (!FcPatternObjectAddWithBinding (ret, e->object,
1292						    FcValueCanonicalize(&v->value),
1293						    v->binding, FcTrue))
1294		    goto bail0;
1295	    }
1296	}
1297    }
1298    return ret;
1299
1300bail0:
1301    FcPatternDestroy (ret);
1302    return NULL;
1303}
1304
1305typedef struct _FcPatternPrivateIter {
1306    FcPatternElt *elt;
1307    int           pos;
1308} FcPatternPrivateIter;
1309
1310static void
1311FcPatternIterSet (const FcPattern *pat, FcPatternPrivateIter *iter)
1312{
1313    iter->elt = FcPatternObjectCount (pat) > 0 && iter->pos < FcPatternObjectCount (pat) ? &FcPatternElts (pat)[iter->pos] : NULL;
1314}
1315
1316void
1317FcPatternIterStart (const FcPattern *pat, FcPatternIter *iter)
1318{
1319    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1320
1321    priv->pos = 0;
1322    FcPatternIterSet (pat, priv);
1323}
1324
1325FcBool
1326FcPatternIterNext (const FcPattern *pat, FcPatternIter *iter)
1327{
1328    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1329
1330    priv->pos++;
1331    if (priv->pos >= FcPatternObjectCount (pat))
1332	return FcFalse;
1333    FcPatternIterSet (pat, priv);
1334
1335    return FcTrue;
1336}
1337
1338FcBool
1339FcPatternIterEqual (const FcPattern *p1, FcPatternIter *i1,
1340		    const FcPattern *p2, FcPatternIter *i2)
1341{
1342    FcBool b1 = FcPatternIterIsValid (p1, i1);
1343    FcBool b2 = FcPatternIterIsValid (p2, i2);
1344
1345    if (!i1 && !i2)
1346	return FcTrue;
1347    if (!b1 || !b2)
1348	return FcFalse;
1349    if (FcPatternIterGetObjectId (p1, i1) != FcPatternIterGetObjectId (p2, i2))
1350	return FcFalse;
1351
1352    return FcValueListEqual (FcPatternIterGetValues (p1, i1),
1353			     FcPatternIterGetValues (p2, i2));
1354}
1355
1356FcBool
1357FcPatternFindObjectIter (const FcPattern *pat, FcPatternIter *iter, FcObject object)
1358{
1359    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1360    int i = FcPatternObjectPosition (pat, object);
1361
1362    priv->elt = NULL;
1363    if (i < 0)
1364	return FcFalse;
1365
1366    priv->pos = i;
1367    FcPatternIterSet (pat, priv);
1368
1369    return FcTrue;
1370}
1371
1372FcBool
1373FcPatternFindIter (const FcPattern *pat, FcPatternIter *iter, const char *object)
1374{
1375    return FcPatternFindObjectIter (pat, iter, FcObjectFromName (object));
1376}
1377
1378FcBool
1379FcPatternIterIsValid (const FcPattern *pat, FcPatternIter *iter)
1380{
1381    FcPatternPrivateIter *priv = (FcPatternPrivateIter *)iter;
1382
1383    if (priv && priv->elt)
1384	return FcTrue;
1385
1386    return FcFalse;
1387}
1388
1389FcObject
1390FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter)
1391{
1392    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1393
1394    if (priv && priv->elt)
1395	return priv->elt->object;
1396
1397    return 0;
1398}
1399
1400const char *
1401FcPatternIterGetObject (const FcPattern *pat, FcPatternIter *iter)
1402{
1403    return FcObjectName (FcPatternIterGetObjectId (pat, iter));
1404}
1405
1406FcValueListPtr
1407FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter)
1408{
1409    FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1410
1411    if (priv && priv->elt)
1412	return FcPatternEltValues (priv->elt);
1413
1414    return NULL;
1415}
1416
1417int
1418FcPatternIterValueCount (const FcPattern *pat, FcPatternIter *iter)
1419{
1420    int count = 0;
1421    FcValueListPtr l;
1422
1423    for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
1424	count++;
1425
1426    return count;
1427}
1428
1429FcResult
1430FcPatternIterGetValue (const FcPattern *pat, FcPatternIter *iter, int id, FcValue *v, FcValueBinding *b)
1431{
1432    FcValueListPtr l;
1433
1434    for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
1435    {
1436	if (id == 0)
1437	{
1438	    *v = FcValueCanonicalize (&l->value);
1439	    if (b)
1440		*b = l->binding;
1441	    return FcResultMatch;
1442	}
1443	id--;
1444    }
1445    return FcResultNoId;
1446}
1447
1448FcBool
1449FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
1450{
1451    int	i;
1452    FcPatternElt    *elts = FcPatternElts(pat);
1453
1454    if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1455	return FcFalse;
1456    if (!FcSerializeAlloc (serialize, elts, FcPatternObjectCount (pat) * sizeof (FcPatternElt)))
1457	return FcFalse;
1458    for (i = 0; i < FcPatternObjectCount (pat); i++)
1459	if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1460	    return FcFalse;
1461    return FcTrue;
1462}
1463
1464FcPattern *
1465FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
1466{
1467    FcPattern	    *pat_serialized;
1468    FcPatternElt    *elts = FcPatternElts (pat);
1469    FcPatternElt    *elts_serialized;
1470    FcValueList	    *values_serialized;
1471    int		    i;
1472
1473    pat_serialized = FcSerializePtr (serialize, pat);
1474    if (!pat_serialized)
1475	return NULL;
1476    *pat_serialized = *pat;
1477    pat_serialized->size = FcPatternObjectCount (pat);
1478    FcRefSetConst (&pat_serialized->ref);
1479
1480    elts_serialized = FcSerializePtr (serialize, elts);
1481    if (!elts_serialized)
1482	return NULL;
1483
1484    pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1485						 elts_serialized);
1486
1487    for (i = 0; i < FcPatternObjectCount (pat); i++)
1488    {
1489	values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1490	if (!values_serialized)
1491	    return NULL;
1492	elts_serialized[i].object = elts[i].object;
1493	elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
1494							  values_serialized,
1495							  FcValueList);
1496    }
1497    if (FcDebug() & FC_DBG_CACHEV) {
1498	printf ("Raw pattern:\n");
1499	FcPatternPrint (pat);
1500	printf ("Serialized pattern:\n");
1501	FcPatternPrint (pat_serialized);
1502	printf ("\n");
1503    }
1504    return pat_serialized;
1505}
1506
1507FcBool
1508FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
1509{
1510    while (vl)
1511    {
1512	if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1513	    return FcFalse;
1514	switch ((int) vl->value.type) {
1515	case FcTypeString:
1516	    if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1517		return FcFalse;
1518	    break;
1519	case FcTypeCharSet:
1520	    if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1521		return FcFalse;
1522	    break;
1523	case FcTypeLangSet:
1524	    if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1525		return FcFalse;
1526	    break;
1527	case FcTypeRange:
1528	    if (!FcRangeSerializeAlloc (serialize, vl->value.u.r))
1529		return FcFalse;
1530	    break;
1531	default:
1532	    break;
1533	}
1534	vl = vl->next;
1535    }
1536    return FcTrue;
1537}
1538
1539FcValueList *
1540FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
1541{
1542    FcValueList	*vl_serialized;
1543    FcChar8	*s_serialized;
1544    FcCharSet	*c_serialized;
1545    FcLangSet	*l_serialized;
1546    FcRange	*r_serialized;
1547    FcValueList	*head_serialized = NULL;
1548    FcValueList	*prev_serialized = NULL;
1549
1550    while (vl)
1551    {
1552	vl_serialized = FcSerializePtr (serialize, vl);
1553	if (!vl_serialized)
1554	    return NULL;
1555
1556	if (prev_serialized)
1557	    prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1558							  vl_serialized,
1559							  FcValueList);
1560	else
1561	    head_serialized = vl_serialized;
1562
1563	vl_serialized->next = NULL;
1564	vl_serialized->value.type = vl->value.type;
1565	switch ((int) vl->value.type) {
1566	case FcTypeInteger:
1567	    vl_serialized->value.u.i = vl->value.u.i;
1568	    break;
1569	case FcTypeDouble:
1570	    vl_serialized->value.u.d = vl->value.u.d;
1571	    break;
1572	case FcTypeString:
1573	    s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1574	    if (!s_serialized)
1575		return NULL;
1576	    vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1577							     s_serialized,
1578							     FcChar8);
1579	    break;
1580	case FcTypeBool:
1581	    vl_serialized->value.u.b = vl->value.u.b;
1582	    break;
1583	case FcTypeMatrix:
1584	    /* can't happen */
1585	    break;
1586	case FcTypeCharSet:
1587	    c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1588	    if (!c_serialized)
1589		return NULL;
1590	    vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1591							     c_serialized,
1592							     FcCharSet);
1593	    break;
1594	case FcTypeFTFace:
1595	    /* can't happen */
1596	    break;
1597	case FcTypeLangSet:
1598	    l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1599	    if (!l_serialized)
1600		return NULL;
1601	    vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1602							     l_serialized,
1603							     FcLangSet);
1604	    break;
1605	case FcTypeRange:
1606	    r_serialized = FcRangeSerialize (serialize, vl->value.u.r);
1607	    if (!r_serialized)
1608		return NULL;
1609	    vl_serialized->value.u.r = FcPtrToEncodedOffset (&vl_serialized->value,
1610							     r_serialized,
1611							     FcRange);
1612	    break;
1613	default:
1614	    break;
1615	}
1616	prev_serialized = vl_serialized;
1617	vl = vl->next;
1618    }
1619    return head_serialized;
1620}
1621
1622#define __fcpat__
1623#include "fcaliastail.h"
1624#include "fcftaliastail.h"
1625#undef __fcpat__
1626