]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
Add a bunch more consts to Xft and fontconfig apis
[fontconfig.git] / src / fcpat.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
3  *
4  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include "fcint.h"
29
30 FcPattern *
31 FcPatternCreate (void)
32 {
33     FcPattern   *p;
34
35     p = (FcPattern *) malloc (sizeof (FcPattern));
36     if (!p)
37         return 0;
38     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
39     p->num = 0;
40     p->size = 0;
41     p->elts = 0;
42     p->ref = 1;
43     return p;
44 }
45
46 void
47 FcValueDestroy (FcValue v)
48 {
49     switch (v.type) {
50     case FcTypeString:
51         FcStrFree ((FcChar8 *) v.u.s);
52         break;
53     case FcTypeMatrix:
54         FcMatrixFree ((FcMatrix *) v.u.m);
55         break;
56     case FcTypeCharSet:
57         FcCharSetDestroy ((FcCharSet *) v.u.c);
58         break;
59     case FcTypeLangSet:
60         FcLangSetDestroy ((FcLangSet *) v.u.l);
61         break;
62     default:
63         break;
64     }
65 }
66
67 FcValue
68 FcValueSave (FcValue v)
69 {
70     switch (v.type) {
71     case FcTypeString:
72         v.u.s = FcStrCopy (v.u.s);
73         if (!v.u.s)
74             v.type = FcTypeVoid;
75         break;
76     case FcTypeMatrix:
77         v.u.m = FcMatrixCopy (v.u.m);
78         if (!v.u.m)
79             v.type = FcTypeVoid;
80         break;
81     case FcTypeCharSet:
82         v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
83         if (!v.u.c)
84             v.type = FcTypeVoid;
85         break;
86     case FcTypeLangSet:
87         v.u.l = FcLangSetCopy (v.u.l);
88         if (!v.u.l)
89             v.type = FcTypeVoid;
90         break;
91     default:
92         break;
93     }
94     return v;
95 }
96
97 void
98 FcValueListDestroy (FcValueList *l)
99 {
100     FcValueList    *next;
101     for (; l; l = next)
102     {
103         switch (l->value.type) {
104         case FcTypeString:
105             FcStrFree ((FcChar8 *) l->value.u.s);
106             break;
107         case FcTypeMatrix:
108             FcMatrixFree ((FcMatrix *) l->value.u.m);
109             break;
110         case FcTypeCharSet:
111             FcCharSetDestroy ((FcCharSet *) l->value.u.c);
112             break;
113         case FcTypeLangSet:
114             FcLangSetDestroy ((FcLangSet *) l->value.u.l);
115             break;
116         default:
117             break;
118         }
119         next = l->next;
120         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
121         free (l);
122     }
123 }
124
125 FcBool
126 FcValueEqual (FcValue va, FcValue vb)
127 {
128     if (va.type != vb.type)
129     {
130         if (va.type == FcTypeInteger)
131         {
132             va.type = FcTypeDouble;
133             va.u.d = va.u.i;
134         }
135         if (vb.type == FcTypeInteger)
136         {
137             vb.type = FcTypeDouble;
138             vb.u.d = vb.u.i;
139         }
140         if (va.type != vb.type)
141             return FcFalse;
142     }
143     switch (va.type) {
144     case FcTypeVoid:
145         return FcTrue;
146     case FcTypeInteger:
147         return va.u.i == vb.u.i;
148     case FcTypeDouble:
149         return va.u.d == vb.u.d;
150     case FcTypeString:
151         return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
152     case FcTypeBool:
153         return va.u.b == vb.u.b;
154     case FcTypeMatrix:
155         return FcMatrixEqual (va.u.m, vb.u.m);
156     case FcTypeCharSet:
157         return FcCharSetEqual (va.u.c, vb.u.c);
158     case FcTypeFTFace:
159         return va.u.f == vb.u.f;
160     case FcTypeLangSet:
161         return FcLangSetEqual (va.u.l, vb.u.l);
162     }
163     return FcFalse;
164 }
165
166 static FcChar32
167 FcDoubleHash (double d)
168 {
169     if (d < 0)
170         d = -d;
171     if (d > 0xffffffff)
172         d = 0xffffffff;
173     return (FcChar32) d;
174 }
175
176 static FcChar32
177 FcStringHash (const FcChar8 *s)
178 {
179     FcChar8     c;
180     FcChar32    h = 0;
181     
182     if (s)
183         while ((c = *s++))
184             h = ((h << 1) | (h >> 31)) ^ c;
185     return h;
186 }
187
188 static FcChar32
189 FcValueHash (FcValue v)
190 {
191     switch (v.type) {
192     case FcTypeVoid:
193         return 0;
194     case FcTypeInteger:
195         return (FcChar32) v.u.i;
196     case FcTypeDouble:
197         return FcDoubleHash (v.u.d);
198     case FcTypeString:
199         return FcStringHash (v.u.s);
200     case FcTypeBool:
201         return (FcChar32) v.u.b;
202     case FcTypeMatrix:
203         return (FcDoubleHash (v.u.m->xx) ^ 
204                 FcDoubleHash (v.u.m->xy) ^ 
205                 FcDoubleHash (v.u.m->yx) ^ 
206                 FcDoubleHash (v.u.m->yy));
207     case FcTypeCharSet:
208         return (FcChar32) v.u.c->num;
209     case FcTypeFTFace:
210         return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
211                FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
212     case FcTypeLangSet:
213         return FcLangSetHash (v.u.l);
214     }
215     return FcFalse;
216 }
217
218 static FcBool
219 FcValueListEqual (FcValueList *la, FcValueList *lb)
220 {
221     if (la == lb)
222         return FcTrue;
223
224     while (la && lb)
225     {
226         if (!FcValueEqual (la->value, lb->value))
227             return FcFalse;
228         la = la->next;
229         lb = lb->next;
230     }
231     if (la || lb)
232         return FcFalse;
233     return FcTrue;
234 }
235
236 static FcChar32
237 FcValueListHash (FcValueList *l)
238 {
239     FcChar32    hash = 0;
240     
241     while (l)
242     {
243         hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
244         l = l->next;
245     }
246     return hash;
247 }
248
249 void
250 FcPatternDestroy (FcPattern *p)
251 {
252     int             i;
253     
254     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
255         return;
256
257     for (i = 0; i < p->num; i++)
258         FcValueListDestroy (p->elts[i].values);
259
260     p->num = 0;
261     if (p->elts)
262     {
263         FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
264         free (p->elts);
265         p->elts = 0;
266     }
267     p->size = 0;
268     FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
269     free (p);
270 }
271
272 #define FC_VALUE_LIST_HASH_SIZE     257
273 #define FC_PATTERN_HASH_SIZE        67
274
275 typedef struct _FcValueListEnt FcValueListEnt;
276
277 struct _FcValueListEnt {
278     FcValueListEnt  *next;
279     FcValueList     *list;
280     FcChar32        hash, pad;
281 };
282
283 typedef union _FcValueListAlign {
284     FcValueListEnt  ent;
285     FcValueList     list;
286 } FcValueListAlign;
287
288 static int          FcValueListFrozenCount[FcTypeLangSet + 1];
289 static int          FcValueListFrozenBytes[FcTypeLangSet + 1];
290 static char         *FcValueListFrozenName[] = {
291     "Void", 
292     "Integer", 
293     "Double", 
294     "String", 
295     "Bool",
296     "Matrix",
297     "CharSet",
298     "FTFace",
299     "LangSet"
300 };
301
302 void
303 FcValueListReport (void);
304     
305 void
306 FcValueListReport (void)
307 {
308     FcType  t;
309
310     printf ("Fc Frozen Values:\n");
311     printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
312     for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
313         printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
314                 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
315 }
316
317 static FcValueListEnt *
318 FcValueListEntCreate (FcValueList *h)
319 {
320     FcValueListAlign    *ea;
321     FcValueListEnt  *e;
322     FcValueList     *l, *new;
323     int             n;
324     int             string_size = 0;
325     FcChar8         *strs;
326     int             size;
327
328     n = 0;
329     for (l = h; l; l = l->next)
330     {
331         if (l->value.type == FcTypeString)
332             string_size += strlen ((char *) l->value.u.s) + 1;
333         n++;
334     }
335     size = sizeof (FcValueListAlign) + n * sizeof (FcValueList) + string_size;
336     FcValueListFrozenCount[h->value.type]++;
337     FcValueListFrozenBytes[h->value.type] += size;
338     ea = malloc (size);
339     if (!ea)
340         return 0;
341     FcMemAlloc (FC_MEM_VALLIST, size);
342     e = &ea->ent;
343     e->list = (FcValueList *) (ea + 1);
344     strs = (FcChar8 *) (e->list + n);
345     new = e->list;
346     for (l = h; l; l = l->next, new++)
347     {
348         if (l->value.type == FcTypeString)
349         {
350             new->value.type = FcTypeString;
351             new->value.u.s = strs;
352             strcpy ((char *) strs, (char *) l->value.u.s);
353             strs += strlen ((char *) strs) + 1;
354         }
355         else
356         {
357             new->value = l->value;
358             new->value = FcValueSave (new->value);
359         }
360         new->binding = l->binding;
361         if (l->next)
362             new->next = new + 1;
363         else
364             new->next = 0;
365     }
366     return e;
367 }
368
369 static int      FcValueListTotal;
370 static int      FcValueListUsed;
371
372 static FcValueList *
373 FcValueListFreeze (FcValueList *l)
374 {
375     static FcValueListEnt   *hashTable[FC_VALUE_LIST_HASH_SIZE];
376     FcChar32                hash = FcValueListHash (l);
377     FcValueListEnt          **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
378     FcValueListEnt          *ent;
379
380     FcValueListTotal++;
381     for (ent = *bucket; ent; ent = ent->next)
382     {
383         if (ent->hash == hash && FcValueListEqual (ent->list, l))
384             return ent->list;
385     }
386
387     ent = FcValueListEntCreate (l);
388     if (!ent)
389         return 0;
390
391     FcValueListUsed++;
392     ent->hash = hash;
393     ent->next = *bucket;
394     *bucket = ent;
395     return ent->list;
396 }
397
398 static FcChar32
399 FcPatternBaseHash (FcPattern *b)
400 {
401     FcChar32    hash = b->num;
402     int         i;
403
404     for (i = 0; i < b->num; i++)
405         hash = ((hash << 1) | (hash >> 31)) ^ ((long) b->elts[i].values);
406     return hash;
407 }
408
409 typedef struct _FcPatternEnt FcPatternEnt;
410
411 struct _FcPatternEnt {
412     FcPatternEnt    *next;
413     FcChar32        hash;
414     FcPattern       pattern;
415 };
416
417 static int      FcPatternTotal;
418 static int      FcPatternUsed;
419
420 static FcPattern *
421 FcPatternBaseFreeze (FcPattern *b)
422 {
423     static FcPatternEnt *hashTable[FC_VALUE_LIST_HASH_SIZE];
424     FcChar32            hash = FcPatternBaseHash (b);
425     FcPatternEnt        **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
426     FcPatternEnt        *ent;
427     int                 i;
428     char                *objects;
429     int                 size_objects;
430     int                 size;
431
432     FcPatternTotal++;
433     for (ent = *bucket; ent; ent = ent->next)
434     {
435         if (ent->hash == hash && b->num == ent->pattern.num)
436         {
437             for (i = 0; i < b->num; i++)
438             {
439                 if (strcmp (b->elts[i].object, ent->pattern.elts[i].object))
440                     break;
441                 if (b->elts[i].values != ent->pattern.elts[i].values)
442                     break;
443             }
444             if (i == b->num)
445                 return &ent->pattern;
446         }
447     }
448
449     /*
450      * Compute size of pattern + elts + object names
451      */
452     size_objects = 0;
453     for (i = 0; i < b->num; i++)
454         size_objects += strlen (b->elts[i].object) + 1;
455
456     size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt) + size_objects;
457     ent = malloc (size);
458     if (!ent)
459         return 0;
460
461     FcMemAlloc (FC_MEM_PATTERN, size);
462     FcPatternUsed++;
463
464     ent->pattern.elts = (FcPatternElt *) (ent + 1);
465     ent->pattern.num = b->num;
466     ent->pattern.size = b->num;
467     ent->pattern.ref = FC_REF_CONSTANT;
468
469     objects = (char *) (ent->pattern.elts + b->num);
470     for (i = 0; i < b->num; i++)
471     {
472         ent->pattern.elts[i].values = b->elts[i].values;
473         strcpy (objects, b->elts[i].object);
474         ent->pattern.elts[i].object = objects;
475         objects += strlen (objects) + 1;
476     }
477
478     ent->hash = hash;
479     ent->next = *bucket;
480     *bucket = ent;
481     return &ent->pattern;
482 }
483
484 FcPattern *
485 FcPatternFreeze (FcPattern *p)
486 {
487     FcPattern   *b, *n = 0;
488     int         size;
489     int         i;
490     
491     size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
492     b = (FcPattern *) malloc (size);
493     if (!b)
494         return 0;
495     FcMemAlloc (FC_MEM_PATTERN, size);
496     b->num = p->num;
497     b->size = b->num;
498     b->ref = 1;
499     b->elts = (FcPatternElt *) (b + 1);
500     /*
501      * Freeze object lists
502      */
503     for (i = 0; i < p->num; i++)
504     {
505         b->elts[i].object = p->elts[i].object;
506         b->elts[i].values = FcValueListFreeze (p->elts[i].values);
507         if (!b->elts[i].values)
508             goto bail;
509     }
510     /*
511      * Freeze base
512      */
513     n = FcPatternBaseFreeze (b);
514 #ifdef CHATTY
515     if (FcDebug() & FC_DBG_MEMORY)
516     {
517         printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
518         printf ("Patterns:   total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
519     }
520 #endif
521 bail:
522     free (b);
523 #ifdef DEBUG
524     assert (FcPatternEqual (n, p));
525 #endif
526     return n;
527 }
528
529 static int
530 FcPatternPosition (const FcPattern *p, const char *object)
531 {
532     int     low, high, mid, c;
533
534     low = 0;
535     high = p->num - 1;
536     c = 1;
537     mid = 0;
538     while (low <= high)
539     {
540         mid = (low + high) >> 1;
541         c = strcmp (p->elts[mid].object, object);
542         if (c == 0)
543             return mid;
544         if (c < 0)
545             low = mid + 1;
546         else
547             high = mid - 1;
548     }
549     if (c < 0)
550         mid++;
551     return -(mid + 1);
552 }
553
554 FcPatternElt *
555 FcPatternFindElt (const FcPattern *p, const char *object)
556 {
557     int     i = FcPatternPosition (p, object);
558     if (i < 0)
559         return 0;
560     return &p->elts[i];
561 }
562
563 FcPatternElt *
564 FcPatternInsertElt (FcPattern *p, const char *object)
565 {
566     int             i;
567     FcPatternElt   *e;
568     
569     i = FcPatternPosition (p, object);
570     if (i < 0)
571     {
572         i = -i - 1;
573     
574         /* grow array */
575         if (p->num + 1 >= p->size)
576         {
577             int s = p->size + 16;
578             if (p->elts)
579                 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
580             else
581                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
582             if (!e)
583                 return FcFalse;
584             p->elts = e;
585             if (p->size)
586                 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
587             FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
588             while (p->size < s)
589             {
590                 p->elts[p->size].object = 0;
591                 p->elts[p->size].values = 0;
592                 p->size++;
593             }
594         }
595         
596         /* move elts up */
597         memmove (p->elts + i + 1,
598                  p->elts + i,
599                  sizeof (FcPatternElt) *
600                  (p->num - i));
601                  
602         /* bump count */
603         p->num++;
604         
605         p->elts[i].object = object;
606         p->elts[i].values = 0;
607     }
608     
609     return &p->elts[i];
610 }
611
612 FcBool
613 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
614 {
615     int i;
616
617     if (pa == pb)
618         return FcTrue;
619
620     if (pa->num != pb->num)
621         return FcFalse;
622     for (i = 0; i < pa->num; i++)
623     {
624         if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
625             return FcFalse;
626         if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
627             return FcFalse;
628     }
629     return FcTrue;
630 }
631
632 FcChar32
633 FcPatternHash (const FcPattern *p)
634 {
635     int         i;
636     FcChar32    h = 0;
637
638     for (i = 0; i < p->num; i++)
639     {
640         h = (((h << 1) | (h >> 31)) ^ 
641              FcStringHash ((const FcChar8 *) p->elts[i].object) ^
642              FcValueListHash (p->elts[i].values));
643     }
644     return h;
645 }
646
647 FcBool
648 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
649 {
650     FcPatternElt    *ea, *eb;
651     int             i;
652     
653     for (i = 0; i < os->nobject; i++)
654     {
655         ea = FcPatternFindElt (pa, os->objects[i]);
656         eb = FcPatternFindElt (pb, os->objects[i]);
657         if (ea)
658         {
659             if (!eb)
660                 return FcFalse;
661             if (!FcValueListEqual (ea->values, eb->values))
662                 return FcFalse;
663         }
664         else
665         {
666             if (eb)
667                 return FcFalse;
668         }
669     }
670     return FcTrue;
671 }
672
673 FcBool
674 FcPatternAddWithBinding  (FcPattern         *p,
675                           const char        *object,
676                           FcValue           value,
677                           FcValueBinding    binding,
678                           FcBool            append)
679 {
680     FcPatternElt   *e;
681     FcValueList    *new, **prev;
682
683     if (p->ref == FC_REF_CONSTANT)
684         goto bail0;
685
686     new = (FcValueList *) malloc (sizeof (FcValueList));
687     if (!new)
688         goto bail0;
689
690     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
691     /* dup string */
692     value = FcValueSave (value);
693     if (value.type == FcTypeVoid)
694         goto bail1;
695
696     new->value = value;
697     new->binding = binding;
698     new->next = 0;
699     
700     e = FcPatternInsertElt (p, object);
701     if (!e)
702         goto bail2;
703     
704     if (append)
705     {
706         for (prev = &e->values; *prev; prev = &(*prev)->next);
707         *prev = new;
708     }
709     else
710     {
711         new->next = e->values;
712         e->values = new;
713     }
714     
715     return FcTrue;
716
717 bail2:    
718     switch (value.type) {
719     case FcTypeString:
720         FcStrFree ((FcChar8 *) value.u.s);
721         break;
722     case FcTypeMatrix:
723         FcMatrixFree ((FcMatrix *) value.u.m);
724         break;
725     case FcTypeCharSet:
726         FcCharSetDestroy ((FcCharSet *) value.u.c);
727         break;
728     case FcTypeLangSet:
729         FcLangSetDestroy ((FcLangSet *) value.u.l);
730         break;
731     default:
732         break;
733     }
734 bail1:
735     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
736     free (new);
737 bail0:
738     return FcFalse;
739 }
740
741 FcBool
742 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
743 {
744     return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
745 }
746
747 FcBool
748 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
749 {
750     return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
751 }
752
753 FcBool
754 FcPatternDel (FcPattern *p, const char *object)
755 {
756     FcPatternElt   *e;
757     int             i;
758
759     e = FcPatternFindElt (p, object);
760     if (!e)
761         return FcFalse;
762
763     i = e - p->elts;
764     
765     /* destroy value */
766     FcValueListDestroy (e->values);
767     
768     /* shuffle existing ones down */
769     memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
770     p->num--;
771     p->elts[p->num].object = 0;
772     p->elts[p->num].values = 0;
773     return FcTrue;
774 }
775
776 FcBool
777 FcPatternAddInteger (FcPattern *p, const char *object, int i)
778 {
779     FcValue     v;
780
781     v.type = FcTypeInteger;
782     v.u.i = i;
783     return FcPatternAdd (p, object, v, FcTrue);
784 }
785
786 FcBool
787 FcPatternAddDouble (FcPattern *p, const char *object, double d)
788 {
789     FcValue     v;
790
791     v.type = FcTypeDouble;
792     v.u.d = d;
793     return FcPatternAdd (p, object, v, FcTrue);
794 }
795
796
797 FcBool
798 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
799 {
800     FcValue     v;
801
802     v.type = FcTypeString;
803     v.u.s = s;
804     return FcPatternAdd (p, object, v, FcTrue);
805 }
806
807 FcBool
808 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
809 {
810     FcValue     v;
811
812     v.type = FcTypeMatrix;
813     v.u.m = (FcMatrix *) s;
814     return FcPatternAdd (p, object, v, FcTrue);
815 }
816
817
818 FcBool
819 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
820 {
821     FcValue     v;
822
823     v.type = FcTypeBool;
824     v.u.b = b;
825     return FcPatternAdd (p, object, v, FcTrue);
826 }
827
828 FcBool
829 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
830 {
831     FcValue     v;
832
833     v.type = FcTypeCharSet;
834     v.u.c = (FcCharSet *) c;
835     return FcPatternAdd (p, object, v, FcTrue);
836 }
837
838 FcBool
839 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
840 {
841     FcValue     v;
842
843     v.type = FcTypeFTFace;
844     v.u.f = (void *) f;
845     return FcPatternAdd (p, object, v, FcTrue);
846 }
847
848 FcBool
849 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
850 {
851     FcValue     v;
852
853     v.type = FcTypeLangSet;
854     v.u.l = (FcLangSet *) ls;
855     return FcPatternAdd (p, object, v, FcTrue);
856 }
857
858 FcResult
859 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
860 {
861     FcPatternElt   *e;
862     FcValueList    *l;
863
864     e = FcPatternFindElt (p, object);
865     if (!e)
866         return FcResultNoMatch;
867     for (l = e->values; l; l = l->next)
868     {
869         if (!id)
870         {
871             *v = l->value;
872             return FcResultMatch;
873         }
874         id--;
875     }
876     return FcResultNoId;
877 }
878
879 FcResult
880 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
881 {
882     FcValue     v;
883     FcResult    r;
884
885     r = FcPatternGet (p, object, id, &v);
886     if (r != FcResultMatch)
887         return r;
888     switch (v.type) {
889     case FcTypeDouble:
890         *i = (int) v.u.d;
891         break;
892     case FcTypeInteger:
893         *i = v.u.i;
894         break;
895     default:
896         return FcResultTypeMismatch;
897     }
898     return FcResultMatch;
899 }
900
901 FcResult
902 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
903 {
904     FcValue     v;
905     FcResult    r;
906
907     r = FcPatternGet (p, object, id, &v);
908     if (r != FcResultMatch)
909         return r;
910     switch (v.type) {
911     case FcTypeDouble:
912         *d = v.u.d;
913         break;
914     case FcTypeInteger:
915         *d = (double) v.u.i;
916         break;
917     default:
918         return FcResultTypeMismatch;
919     }
920     return FcResultMatch;
921 }
922
923 FcResult
924 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
925 {
926     FcValue     v;
927     FcResult    r;
928
929     r = FcPatternGet (p, object, id, &v);
930     if (r != FcResultMatch)
931         return r;
932     if (v.type != FcTypeString)
933         return FcResultTypeMismatch;
934     *s = (FcChar8 *) v.u.s;
935     return FcResultMatch;
936 }
937
938 FcResult
939 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
940 {
941     FcValue     v;
942     FcResult    r;
943
944     r = FcPatternGet (p, object, id, &v);
945     if (r != FcResultMatch)
946         return r;
947     if (v.type != FcTypeMatrix)
948         return FcResultTypeMismatch;
949     *m = (FcMatrix *) v.u.m;
950     return FcResultMatch;
951 }
952
953
954 FcResult
955 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
956 {
957     FcValue     v;
958     FcResult    r;
959
960     r = FcPatternGet (p, object, id, &v);
961     if (r != FcResultMatch)
962         return r;
963     if (v.type != FcTypeBool)
964         return FcResultTypeMismatch;
965     *b = v.u.b;
966     return FcResultMatch;
967 }
968
969 FcResult
970 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
971 {
972     FcValue     v;
973     FcResult    r;
974
975     r = FcPatternGet (p, object, id, &v);
976     if (r != FcResultMatch)
977         return r;
978     if (v.type != FcTypeCharSet)
979         return FcResultTypeMismatch;
980     *c = (FcCharSet *) v.u.c;
981     return FcResultMatch;
982 }
983
984 FcResult
985 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
986 {
987     FcValue     v;
988     FcResult    r;
989
990     r = FcPatternGet (p, object, id, &v);
991     if (r != FcResultMatch)
992         return r;
993     if (v.type != FcTypeFTFace)
994         return FcResultTypeMismatch;
995     *f = (FT_Face) v.u.f;
996     return FcResultMatch;
997 }
998
999 FcResult
1000 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1001 {
1002     FcValue     v;
1003     FcResult    r;
1004
1005     r = FcPatternGet (p, object, id, &v);
1006     if (r != FcResultMatch)
1007         return r;
1008     if (v.type != FcTypeLangSet)
1009         return FcResultTypeMismatch;
1010     *ls = (FcLangSet *) v.u.l;
1011     return FcResultMatch;
1012 }
1013
1014 FcPattern *
1015 FcPatternDuplicate (const FcPattern *orig)
1016 {
1017     FcPattern       *new;
1018     int             i;
1019     FcValueList    *l;
1020
1021     new = FcPatternCreate ();
1022     if (!new)
1023         goto bail0;
1024
1025     for (i = 0; i < orig->num; i++)
1026     {
1027         for (l = orig->elts[i].values; l; l = l->next)
1028             if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
1029                 goto bail1;
1030     }
1031
1032     return new;
1033
1034 bail1:
1035     FcPatternDestroy (new);
1036 bail0:
1037     return 0;
1038 }
1039
1040 void
1041 FcPatternReference (FcPattern *p)
1042 {
1043     if (p->ref != FC_REF_CONSTANT)
1044         p->ref++;
1045 }
1046
1047 FcPattern *
1048 FcPatternVaBuild (FcPattern *orig, va_list va)
1049 {
1050     FcPattern   *ret;
1051     
1052     FcPatternVapBuild (ret, orig, va);
1053     return ret;
1054 }
1055
1056 FcPattern *
1057 FcPatternBuild (FcPattern *orig, ...)
1058 {
1059     va_list     va;
1060     
1061     va_start (va, orig);
1062     FcPatternVapBuild (orig, orig, va);
1063     va_end (va);
1064     return orig;
1065 }