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