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