3ef1ed21205827bdea13233a6c8bfb68dbffe811
[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 int
429 FcPatternPosition (const FcPattern *p, const char *object)
430 {
431     return FcPatternObjectPosition (p, FcObjectFromName (object));
432 }
433
434 FcPatternElt *
435 FcPatternObjectFindElt (const FcPattern *p, FcObject object)
436 {
437     int     i = FcPatternObjectPosition (p, object);
438     if (i < 0)
439         return 0;
440     return &FcPatternElts(p)[i];
441 }
442
443 FcPatternElt *
444 FcPatternObjectInsertElt (FcPattern *p, FcObject object)
445 {
446     int             i;
447     FcPatternElt   *e;
448
449     i = FcPatternObjectPosition (p, object);
450     if (i < 0)
451     {
452         i = -i - 1;
453
454         /* reallocate array */
455         if (p->num + 1 >= p->size)
456         {
457             int s = p->size + 16;
458             if (p->size)
459             {
460                 FcPatternElt *e0 = FcPatternElts(p);
461                 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
462                 if (!e) /* maybe it was mmapped */
463                 {
464                     e = malloc(s * sizeof (FcPatternElt));
465                     if (e)
466                         memcpy(e, e0, p->num * sizeof (FcPatternElt));
467                 }
468             }
469             else
470                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
471             if (!e)
472                 return FcFalse;
473             p->elts_offset = FcPtrToOffset (p, e);
474             while (p->size < s)
475             {
476                 e[p->size].object = 0;
477                 e[p->size].values = NULL;
478                 p->size++;
479             }
480         }
481         
482         e = FcPatternElts(p);
483         /* move elts up */
484         memmove (e + i + 1,
485                  e + i,
486                  sizeof (FcPatternElt) *
487                  (p->num - i));
488                 
489         /* bump count */
490         p->num++;
491         
492         e[i].object = object;
493         e[i].values = NULL;
494     }
495
496     return FcPatternElts(p) + i;
497 }
498
499 FcBool
500 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
501 {
502     int i;
503     FcPatternElt   *pae, *pbe;
504
505     if (pa == pb)
506         return FcTrue;
507
508     if (pa->num != pb->num)
509         return FcFalse;
510     pae = FcPatternElts(pa);
511     pbe = FcPatternElts(pb);
512     for (i = 0; i < pa->num; i++)
513     {
514         if (pae[i].object != pbe[i].object)
515             return FcFalse;
516         if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
517                                FcPatternEltValues(&pbe[i])))
518             return FcFalse;
519     }
520     return FcTrue;
521 }
522
523 FcChar32
524 FcPatternHash (const FcPattern *p)
525 {
526     int         i;
527     FcChar32    h = 0;
528     FcPatternElt    *pe = FcPatternElts(p);
529
530     for (i = 0; i < p->num; i++)
531     {
532         h = (((h << 1) | (h >> 31)) ^
533              pe[i].object ^
534              FcValueListHash (FcPatternEltValues(&pe[i])));
535     }
536     return h;
537 }
538
539 FcBool
540 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
541 {
542     FcPatternElt    *ea, *eb;
543     int             i;
544
545     for (i = 0; i < os->nobject; i++)
546     {
547         FcObject    object = FcObjectFromName (os->objects[i]);
548         ea = FcPatternObjectFindElt (pai, object);
549         eb = FcPatternObjectFindElt (pbi, object);
550         if (ea)
551         {
552             if (!eb)
553                 return FcFalse;
554             if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
555                 return FcFalse;
556         }
557         else
558         {
559             if (eb)
560                 return FcFalse;
561         }
562     }
563     return FcTrue;
564 }
565
566 FcBool
567 FcPatternObjectListAdd (FcPattern       *p,
568                         FcObject        object,
569                         FcValueListPtr  list,
570                         FcBool          append)
571 {
572     FcPatternElt   *e;
573     FcValueListPtr l, *prev;
574
575     if (FcRefIsConst (&p->ref))
576         goto bail0;
577
578     /*
579      * Make sure the stored type is valid for built-in objects
580      */
581     for (l = list; l != NULL; l = FcValueListNext (l))
582     {
583         if (!FcObjectValidType (object, l->value.type))
584         {
585             fprintf (stderr,
586                      "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
587             FcValuePrintFile (stderr, l->value);
588             fprintf (stderr, "\n");
589             goto bail0;
590         }
591     }
592
593     e = FcPatternObjectInsertElt (p, object);
594     if (!e)
595         goto bail0;
596
597     if (append)
598     {
599         for (prev = &e->values; *prev; prev = &(*prev)->next)
600             ;
601         *prev = list;
602     }
603     else
604     {
605         for (prev = &list; *prev; prev = &(*prev)->next)
606             ;
607         *prev = e->values;
608         e->values = list;
609     }
610
611     return FcTrue;
612
613 bail0:
614     return FcFalse;
615 }
616
617 FcBool
618 FcPatternObjectAddWithBinding  (FcPattern       *p,
619                                 FcObject        object,
620                                 FcValue         value,
621                                 FcValueBinding  binding,
622                                 FcBool          append)
623 {
624     FcPatternElt   *e;
625     FcValueListPtr new, *prev;
626
627     if (FcRefIsConst (&p->ref))
628         goto bail0;
629
630     new = FcValueListCreate ();
631     if (!new)
632         goto bail0;
633
634     value = FcValueSave (value);
635     if (value.type == FcTypeVoid)
636         goto bail1;
637
638     /*
639      * Make sure the stored type is valid for built-in objects
640      */
641     if (!FcObjectValidType (object, value.type))
642     {
643         fprintf (stderr,
644                  "Fontconfig warning: FcPattern object %s does not accept value",
645                  FcObjectName (object));
646         FcValuePrintFile (stderr, value);
647         fprintf (stderr, "\n");
648         goto bail1;
649     }
650
651     new->value = value;
652     new->binding = binding;
653     new->next = NULL;
654
655     e = FcPatternObjectInsertElt (p, object);
656     if (!e)
657         goto bail2;
658
659     if (append)
660     {
661         for (prev = &e->values; *prev; prev = &(*prev)->next)
662             ;
663         *prev = new;
664     }
665     else
666     {
667         new->next = e->values;
668         e->values = new;
669     }
670
671     return FcTrue;
672
673 bail2:
674     FcValueDestroy (value);
675 bail1:
676     free (new);
677 bail0:
678     return FcFalse;
679 }
680
681 FcBool
682 FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
683 {
684     return FcPatternObjectAddWithBinding (p, object,
685                                           value, FcValueBindingStrong, append);
686 }
687
688 FcBool
689 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
690 {
691     return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
692                                           value, FcValueBindingStrong, append);
693 }
694
695 FcBool
696 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
697 {
698     return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
699                                           value, FcValueBindingWeak, append);
700 }
701
702 FcBool
703 FcPatternObjectDel (FcPattern *p, FcObject object)
704 {
705     FcPatternElt   *e;
706
707     e = FcPatternObjectFindElt (p, object);
708     if (!e)
709         return FcFalse;
710
711     /* destroy value */
712     FcValueListDestroy (e->values);
713
714     /* shuffle existing ones down */
715     memmove (e, e+1,
716              (FcPatternElts(p) + p->num - (e + 1)) *
717              sizeof (FcPatternElt));
718     p->num--;
719     e = FcPatternElts(p) + p->num;
720     e->object = 0;
721     e->values = NULL;
722     return FcTrue;
723 }
724
725 FcBool
726 FcPatternDel (FcPattern *p, const char *object)
727 {
728     return FcPatternObjectDel (p, FcObjectFromName (object));
729 }
730
731 FcBool
732 FcPatternRemove (FcPattern *p, const char *object, int id)
733 {
734     FcPatternElt    *e;
735     FcValueListPtr  *prev, l;
736
737     e = FcPatternObjectFindElt (p, FcObjectFromName (object));
738     if (!e)
739         return FcFalse;
740     for (prev = &e->values; (l = *prev); prev = &l->next)
741     {
742         if (!id)
743         {
744             *prev = l->next;
745             l->next = NULL;
746             FcValueListDestroy (l);
747             if (!e->values)
748                 FcPatternDel (p, object);
749             return FcTrue;
750         }
751         id--;
752     }
753     return FcFalse;
754 }
755
756 FcBool
757 FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
758 {
759     FcValue     v;
760
761     v.type = FcTypeInteger;
762     v.u.i = i;
763     return FcPatternObjectAdd (p, object, v, FcTrue);
764 }
765
766 FcBool
767 FcPatternAddInteger (FcPattern *p, const char *object, int i)
768 {
769     return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
770 }
771
772 FcBool
773 FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
774 {
775     FcValue     v;
776
777     v.type = FcTypeDouble;
778     v.u.d = d;
779     return FcPatternObjectAdd (p, object, v, FcTrue);
780 }
781
782
783 FcBool
784 FcPatternAddDouble (FcPattern *p, const char *object, double d)
785 {
786     return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
787 }
788
789 FcBool
790 FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
791 {
792     FcValue     v;
793
794     if (!s)
795     {
796         v.type = FcTypeVoid;
797         v.u.s = 0;
798         return FcPatternObjectAdd (p, object, v, FcTrue);
799     }
800
801     v.type = FcTypeString;
802     v.u.s = s;
803     return FcPatternObjectAdd (p, object, v, FcTrue);
804 }
805
806 FcBool
807 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
808 {
809     return FcPatternObjectAddString (p, FcObjectFromName (object), s);
810 }
811
812 FcBool
813 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
814 {
815     FcValue     v;
816
817     v.type = FcTypeMatrix;
818     v.u.m = s;
819     return FcPatternAdd (p, object, v, FcTrue);
820 }
821
822
823 FcBool
824 FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
825 {
826     FcValue     v;
827
828     v.type = FcTypeBool;
829     v.u.b = b;
830     return FcPatternObjectAdd (p, object, v, FcTrue);
831 }
832
833 FcBool
834 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
835 {
836     return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
837 }
838
839 FcBool
840 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
841 {
842     FcValue     v;
843
844     v.type = FcTypeCharSet;
845     v.u.c = (FcCharSet *)c;
846     return FcPatternAdd (p, object, v, FcTrue);
847 }
848
849 FcBool
850 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
851 {
852     FcValue     v;
853
854     v.type = FcTypeFTFace;
855     v.u.f = (void *) f;
856     return FcPatternAdd (p, object, v, FcTrue);
857 }
858
859 FcBool
860 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
861 {
862     FcValue     v;
863
864     v.type = FcTypeLangSet;
865     v.u.l = (FcLangSet *)ls;
866     return FcPatternAdd (p, object, v, FcTrue);
867 }
868
869 FcBool
870 FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r)
871 {
872     FcValue v;
873
874     v.type = FcTypeRange;
875     v.u.r = (FcRange *)r;
876     return FcPatternObjectAdd (p, object, v, FcTrue);
877 }
878
879 FcBool
880 FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r)
881 {
882     return FcPatternObjectAddRange (p, FcObjectFromName (object), r);
883 }
884
885 FcResult
886 FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
887 {
888     FcPatternElt   *e;
889     FcValueListPtr l;
890
891     if (!p)
892         return FcResultNoMatch;
893     e = FcPatternObjectFindElt (p, object);
894     if (!e)
895         return FcResultNoMatch;
896     for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
897     {
898         if (!id)
899         {
900             *v = FcValueCanonicalize(&l->value);
901             return FcResultMatch;
902         }
903         id--;
904     }
905     return FcResultNoId;
906 }
907
908 FcResult
909 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
910 {
911     return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
912 }
913
914 FcResult
915 FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
916 {
917     FcValue     v;
918     FcResult    r;
919
920     r = FcPatternObjectGet (p, object, id, &v);
921     if (r != FcResultMatch)
922         return r;
923     switch ((int) v.type) {
924     case FcTypeDouble:
925         *i = (int) v.u.d;
926         break;
927     case FcTypeInteger:
928         *i = v.u.i;
929         break;
930     default:
931         return FcResultTypeMismatch;
932     }
933     return FcResultMatch;
934 }
935
936 FcResult
937 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
938 {
939     return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
940 }
941
942
943 FcResult
944 FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
945 {
946     FcValue     v;
947     FcResult    r;
948
949     r = FcPatternObjectGet (p, object, id, &v);
950     if (r != FcResultMatch)
951         return r;
952     switch ((int) v.type) {
953     case FcTypeDouble:
954         *d = v.u.d;
955         break;
956     case FcTypeInteger:
957         *d = (double) v.u.i;
958         break;
959     default:
960         return FcResultTypeMismatch;
961     }
962     return FcResultMatch;
963 }
964
965 FcResult
966 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
967 {
968     return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
969 }
970
971 FcResult
972 FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
973 {
974     FcValue     v;
975     FcResult    r;
976
977     r = FcPatternObjectGet (p, object, id, &v);
978     if (r != FcResultMatch)
979         return r;
980     if (v.type != FcTypeString)
981         return FcResultTypeMismatch;
982
983     *s = (FcChar8 *) v.u.s;
984     return FcResultMatch;
985 }
986
987 FcResult
988 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
989 {
990     return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
991 }
992
993 FcResult
994 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
995 {
996     FcValue     v;
997     FcResult    r;
998
999     r = FcPatternGet (p, object, id, &v);
1000     if (r != FcResultMatch)
1001         return r;
1002     if (v.type != FcTypeMatrix)
1003         return FcResultTypeMismatch;
1004     *m = (FcMatrix *)v.u.m;
1005     return FcResultMatch;
1006 }
1007
1008
1009 FcResult
1010 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1011 {
1012     FcValue     v;
1013     FcResult    r;
1014
1015     r = FcPatternGet (p, object, id, &v);
1016     if (r != FcResultMatch)
1017         return r;
1018     if (v.type != FcTypeBool)
1019         return FcResultTypeMismatch;
1020     *b = v.u.b;
1021     return FcResultMatch;
1022 }
1023
1024 FcResult
1025 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1026 {
1027     FcValue     v;
1028     FcResult    r;
1029
1030     r = FcPatternGet (p, object, id, &v);
1031     if (r != FcResultMatch)
1032         return r;
1033     if (v.type != FcTypeCharSet)
1034         return FcResultTypeMismatch;
1035     *c = (FcCharSet *)v.u.c;
1036     return FcResultMatch;
1037 }
1038
1039 FcResult
1040 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1041 {
1042     FcValue     v;
1043     FcResult    r;
1044
1045     r = FcPatternGet (p, object, id, &v);
1046     if (r != FcResultMatch)
1047         return r;
1048     if (v.type != FcTypeFTFace)
1049         return FcResultTypeMismatch;
1050     *f = (FT_Face) v.u.f;
1051     return FcResultMatch;
1052 }
1053
1054 FcResult
1055 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1056 {
1057     FcValue     v;
1058     FcResult    r;
1059
1060     r = FcPatternGet (p, object, id, &v);
1061     if (r != FcResultMatch)
1062         return r;
1063     if (v.type != FcTypeLangSet)
1064         return FcResultTypeMismatch;
1065     *ls = (FcLangSet *)v.u.l;
1066     return FcResultMatch;
1067 }
1068
1069 FcResult
1070 FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r)
1071 {
1072     FcValue     v;
1073     FcResult    res;
1074
1075     res = FcPatternObjectGet (p, object, id, &v);
1076     if (res != FcResultMatch)
1077         return res;
1078     switch ((int)v.type) {
1079     case FcTypeRange:
1080         *r = (FcRange *)v.u.r;
1081         break;
1082     default:
1083         return FcResultTypeMismatch;
1084     }
1085     return FcResultMatch;
1086 }
1087
1088 FcResult
1089 FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r)
1090 {
1091     return FcPatternObjectGetRange (p, FcObjectFromName (object), id, r);
1092 }
1093
1094 FcPattern *
1095 FcPatternDuplicate (const FcPattern *orig)
1096 {
1097     FcPattern       *new;
1098     FcPatternElt    *e;
1099     int             i;
1100     FcValueListPtr  l;
1101
1102     new = FcPatternCreate ();
1103     if (!new)
1104         goto bail0;
1105
1106     e = FcPatternElts(orig);
1107
1108     for (i = 0; i < orig->num; i++)
1109     {
1110         for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
1111         {
1112             if (!FcPatternObjectAddWithBinding (new, e[i].object,
1113                                                 FcValueCanonicalize(&l->value),
1114                                                 l->binding,
1115                                                 FcTrue))
1116                 goto bail1;
1117         
1118         }
1119     }
1120
1121     return new;
1122
1123 bail1:
1124     FcPatternDestroy (new);
1125 bail0:
1126     return 0;
1127 }
1128
1129 void
1130 FcPatternReference (FcPattern *p)
1131 {
1132     if (!FcRefIsConst (&p->ref))
1133         FcRefInc (&p->ref);
1134     else
1135         FcCacheObjectReference (p);
1136 }
1137
1138 FcPattern *
1139 FcPatternVaBuild (FcPattern *p, va_list va)
1140 {
1141     FcPattern   *ret;
1142
1143     FcPatternVapBuild (ret, p, va);
1144     return ret;
1145 }
1146
1147 FcPattern *
1148 FcPatternBuild (FcPattern *p, ...)
1149 {
1150     va_list     va;
1151
1152     va_start (va, p);
1153     FcPatternVapBuild (p, p, va);
1154     va_end (va);
1155     return p;
1156 }
1157
1158 /*
1159  * Add all of the elements in 's' to 'p'
1160  */
1161 FcBool
1162 FcPatternAppend (FcPattern *p, FcPattern *s)
1163 {
1164     int             i;
1165     FcPatternElt    *e;
1166     FcValueListPtr  v;
1167
1168     for (i = 0; i < s->num; i++)
1169     {
1170         e = FcPatternElts(s)+i;
1171         for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
1172         {
1173             if (!FcPatternObjectAddWithBinding (p, e->object,
1174                                                 FcValueCanonicalize(&v->value),
1175                                                 v->binding, FcTrue))
1176                 return FcFalse;
1177         }
1178     }
1179     return FcTrue;
1180 }
1181
1182 FcPattern *
1183 FcPatternFilter (FcPattern *p, const FcObjectSet *os)
1184 {
1185     int             i;
1186     FcPattern       *ret;
1187     FcPatternElt    *e;
1188     FcValueListPtr  v;
1189
1190     if (!os)
1191         return FcPatternDuplicate (p);
1192
1193     ret = FcPatternCreate ();
1194     if (!ret)
1195         return NULL;
1196
1197     for (i = 0; i < os->nobject; i++)
1198     {
1199         FcObject object = FcObjectFromName (os->objects[i]);
1200         e = FcPatternObjectFindElt (p, object);
1201         if (e)
1202         {
1203             for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
1204             {
1205                 if (!FcPatternObjectAddWithBinding (ret, e->object,
1206                                                     FcValueCanonicalize(&v->value),
1207                                                     v->binding, FcTrue))
1208                     goto bail0;
1209             }
1210         }
1211     }
1212     return ret;
1213
1214 bail0:
1215     FcPatternDestroy (ret);
1216     return NULL;
1217 }
1218
1219
1220 FcBool
1221 FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
1222 {
1223     int i;
1224     FcPatternElt    *elts = FcPatternElts(pat);
1225
1226     if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1227         return FcFalse;
1228     if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
1229         return FcFalse;
1230     for (i = 0; i < pat->num; i++)
1231         if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1232             return FcFalse;
1233     return FcTrue;
1234 }
1235
1236 FcPattern *
1237 FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
1238 {
1239     FcPattern       *pat_serialized;
1240     FcPatternElt    *elts = FcPatternElts (pat);
1241     FcPatternElt    *elts_serialized;
1242     FcValueList     *values_serialized;
1243     int             i;
1244
1245     pat_serialized = FcSerializePtr (serialize, pat);
1246     if (!pat_serialized)
1247         return NULL;
1248     *pat_serialized = *pat;
1249     pat_serialized->size = pat->num;
1250     FcRefSetConst (&pat_serialized->ref);
1251
1252     elts_serialized = FcSerializePtr (serialize, elts);
1253     if (!elts_serialized)
1254         return NULL;
1255
1256     pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1257                                                  elts_serialized);
1258
1259     for (i = 0; i < pat->num; i++)
1260     {
1261         values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1262         if (!values_serialized)
1263             return NULL;
1264         elts_serialized[i].object = elts[i].object;
1265         elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
1266                                                           values_serialized,
1267                                                           FcValueList);
1268     }
1269     if (FcDebug() & FC_DBG_CACHEV) {
1270         printf ("Raw pattern:\n");
1271         FcPatternPrint (pat);
1272         printf ("Serialized pattern:\n");
1273         FcPatternPrint (pat_serialized);
1274         printf ("\n");
1275     }
1276     return pat_serialized;
1277 }
1278
1279 FcBool
1280 FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
1281 {
1282     while (vl)
1283     {
1284         if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1285             return FcFalse;
1286         switch ((int) vl->value.type) {
1287         case FcTypeString:
1288             if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1289                 return FcFalse;
1290             break;
1291         case FcTypeCharSet:
1292             if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1293                 return FcFalse;
1294             break;
1295         case FcTypeLangSet:
1296             if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1297                 return FcFalse;
1298             break;
1299         case FcTypeRange:
1300             if (!FcRangeSerializeAlloc (serialize, vl->value.u.r))
1301                 return FcFalse;
1302             break;
1303         default:
1304             break;
1305         }
1306         vl = vl->next;
1307     }
1308     return FcTrue;
1309 }
1310
1311 FcValueList *
1312 FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
1313 {
1314     FcValueList *vl_serialized;
1315     FcChar8     *s_serialized;
1316     FcCharSet   *c_serialized;
1317     FcLangSet   *l_serialized;
1318     FcRange     *r_serialized;
1319     FcValueList *head_serialized = NULL;
1320     FcValueList *prev_serialized = NULL;
1321
1322     while (vl)
1323     {
1324         vl_serialized = FcSerializePtr (serialize, vl);
1325         if (!vl_serialized)
1326             return NULL;
1327
1328         if (prev_serialized)
1329             prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1330                                                           vl_serialized,
1331                                                           FcValueList);
1332         else
1333             head_serialized = vl_serialized;
1334         
1335         vl_serialized->next = NULL;
1336         vl_serialized->value.type = vl->value.type;
1337         switch ((int) vl->value.type) {
1338         case FcTypeInteger:
1339             vl_serialized->value.u.i = vl->value.u.i;
1340             break;
1341         case FcTypeDouble:
1342             vl_serialized->value.u.d = vl->value.u.d;
1343             break;
1344         case FcTypeString:
1345             s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1346             if (!s_serialized)
1347                 return NULL;
1348             vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1349                                                              s_serialized,
1350                                                              FcChar8);
1351             break;
1352         case FcTypeBool:
1353             vl_serialized->value.u.b = vl->value.u.b;
1354             break;
1355         case FcTypeMatrix:
1356             /* can't happen */
1357             break;
1358         case FcTypeCharSet:
1359             c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1360             if (!c_serialized)
1361                 return NULL;
1362             vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1363                                                              c_serialized,
1364                                                              FcCharSet);
1365             break;
1366         case FcTypeFTFace:
1367             /* can't happen */
1368             break;
1369         case FcTypeLangSet:
1370             l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1371             if (!l_serialized)
1372                 return NULL;
1373             vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1374                                                              l_serialized,
1375                                                              FcLangSet);
1376             break;
1377         case FcTypeRange:
1378             r_serialized = FcRangeSerialize (serialize, vl->value.u.r);
1379             if (!r_serialized)
1380                 return NULL;
1381             vl_serialized->value.u.r = FcPtrToEncodedOffset (&vl_serialized->value,
1382                                                              r_serialized,
1383                                                              FcRange);
1384             break;
1385         default:
1386             break;
1387         }
1388         prev_serialized = vl_serialized;
1389         vl = vl->next;
1390     }
1391     return head_serialized;
1392 }
1393
1394 #define __fcpat__
1395 #include "fcaliastail.h"
1396 #include "fcftaliastail.h"
1397 #undef __fcpat__