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