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