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