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