]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
Make FcCompareString and FcCompareFamily less expensive. Only add a value
[fontconfig.git] / src / fcpat.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
3  *
4  * Copyright © 2000 Keith Packard
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 static FcPattern ** fcpatterns = 0;
31 static int fcpattern_bank_count = 0, fcpattern_ptr, fcpattern_count;
32 static FcPatternElt ** fcpatternelts = 0;
33 static int fcpatternelt_ptr, fcpatternelt_count;
34 static FcValueList ** fcvaluelists = 0;
35 static int fcvaluelist_bank_count = 0, fcvaluelist_ptr, fcvaluelist_count;
36
37 static const char *
38 FcPatternFindFullFname (const FcPattern *p);
39 static FcPatternEltPtr
40 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
41
42 /* If you are trying to duplicate an FcPattern which will be used for
43  * rendering, be aware that (internally) you also have to use
44  * FcPatternTransferFullFname to transfer the associated filename.  If
45  * you are copying the font (externally) using FcPatternGetString,
46  * then everything's fine; this caveat only applies if you're copying
47  * the bits individually.  */
48
49 FcPattern *
50 FcPatternCreate (void)
51 {
52     FcPattern   *p;
53
54     p = (FcPattern *) malloc (sizeof (FcPattern));
55     if (!p)
56         return 0;
57     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
58     p->num = 0;
59     p->size = 0;
60     p->elts = FcPatternEltPtrCreateDynamic(0);
61     p->bank = FC_BANK_DYNAMIC;
62     p->ref = 1;
63     return p;
64 }
65
66 void
67 FcValueDestroy (FcValue v)
68 {
69     switch (v.type) {
70     case FcTypeString:
71         FcStrFree ((FcChar8 *) v.u.s);
72         break;
73     case FcTypeMatrix:
74         FcMatrixFree ((FcMatrix *) v.u.m);
75         break;
76     case FcTypeCharSet:
77         FcCharSetDestroy ((FcCharSet *) v.u.c);
78         break;
79     case FcTypeLangSet:
80         FcLangSetDestroy ((FcLangSet *) v.u.l);
81         break;
82     default:
83         break;
84     }
85 }
86
87 FcValue
88 FcValueCanonicalize (const FcValue *v)
89 {
90     if (v->type & FC_STORAGE_STATIC)
91     {
92         FcValue new = *v;
93
94         switch (v->type & ~FC_STORAGE_STATIC)
95         {
96         case FcTypeString:
97             new.u.s = fc_value_string(v);
98             new.type = FcTypeString;
99             break;
100         case FcTypeCharSet:
101             new.u.c = fc_value_charset(v);
102             new.type = FcTypeCharSet;
103             break;
104         case FcTypeLangSet:
105             new.u.l = fc_value_langset(v);
106             new.type = FcTypeLangSet;
107             break;
108         }
109         return new;
110     }
111     return *v;
112 }
113
114 FcValue
115 FcValueSave (FcValue v)
116 {
117     switch (v.type) {
118     case FcTypeString:
119         v.u.s = FcStrCopy (v.u.s);
120         if (!v.u.s)
121             v.type = FcTypeVoid;
122         break;
123     case FcTypeMatrix:
124         v.u.m = FcMatrixCopy (v.u.m);
125         if (!v.u.m)
126             v.type = FcTypeVoid;
127         break;
128     case FcTypeCharSet:
129         v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
130         if (!v.u.c)
131             v.type = FcTypeVoid;
132         break;
133     case FcTypeLangSet:
134         v.u.l = FcLangSetCopy (v.u.l);
135         if (!v.u.l)
136             v.type = FcTypeVoid;
137         break;
138     default:
139         break;
140     }
141     return v;
142 }
143
144 void
145 FcValueListDestroy (FcValueListPtr l)
146 {
147     FcValueListPtr next;
148     for (; FcValueListPtrU(l); l = next)
149     {
150         switch (FcValueListPtrU(l)->value.type) {
151         case FcTypeString:
152             FcStrFree ((FcChar8 *)FcValueListPtrU(l)->value.u.s);
153             break;
154         case FcTypeMatrix:
155             FcMatrixFree ((FcMatrix *)FcValueListPtrU(l)->value.u.m);
156             break;
157         case FcTypeCharSet:
158             FcCharSetDestroy 
159                 ((FcCharSet *) (FcValueListPtrU(l)->value.u.c));
160             break;
161         case FcTypeLangSet:
162             FcLangSetDestroy 
163                 ((FcLangSet *) (FcValueListPtrU(l)->value.u.l));
164             break;
165         default:
166             break;
167         }
168         next = FcValueListPtrU(l)->next;
169         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
170         if (l.bank == FC_BANK_DYNAMIC)
171             free(l.u.dyn);
172     }
173 }
174
175 FcBool
176 FcValueEqual (FcValue va, FcValue vb)
177 {
178     if (va.type != vb.type)
179     {
180         if (va.type == FcTypeInteger)
181         {
182             va.type = FcTypeDouble;
183             va.u.d = va.u.i;
184         }
185         if (vb.type == FcTypeInteger)
186         {
187             vb.type = FcTypeDouble;
188             vb.u.d = vb.u.i;
189         }
190         if (va.type != vb.type)
191             return FcFalse;
192     }
193     switch (va.type) {
194     case FcTypeVoid:
195         return FcTrue;
196     case FcTypeInteger:
197         return va.u.i == vb.u.i;
198     case FcTypeDouble:
199         return va.u.d == vb.u.d;
200     case FcTypeString:
201         return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
202     case FcTypeBool:
203         return va.u.b == vb.u.b;
204     case FcTypeMatrix:
205         return FcMatrixEqual (va.u.m, vb.u.m);
206     case FcTypeCharSet:
207         return FcCharSetEqual (va.u.c, vb.u.c);
208     case FcTypeFTFace:
209         return va.u.f == vb.u.f;
210     case FcTypeLangSet:
211         return FcLangSetEqual (va.u.l, vb.u.l);
212     }
213     return FcFalse;
214 }
215
216 static FcChar32
217 FcDoubleHash (double d)
218 {
219     if (d < 0)
220         d = -d;
221     if (d > 0xffffffff)
222         d = 0xffffffff;
223     return (FcChar32) d;
224 }
225
226 FcChar32
227 FcStringHash (const FcChar8 *s)
228 {
229     FcChar8     c;
230     FcChar32    h = 0;
231     
232     if (s)
233         while ((c = *s++))
234             h = ((h << 1) | (h >> 31)) ^ c;
235     return h;
236 }
237
238 static FcChar32
239 FcValueHash (const FcValue *v0)
240 {
241     FcValue v = FcValueCanonicalize(v0);
242     switch (v.type) {
243     case FcTypeVoid:
244         return 0;
245     case FcTypeInteger:
246         return (FcChar32) v.u.i;
247     case FcTypeDouble:
248         return FcDoubleHash (v.u.d);
249     case FcTypeString:
250         return FcStringHash (v.u.s);
251     case FcTypeBool:
252         return (FcChar32) v.u.b;
253     case FcTypeMatrix:
254         return (FcDoubleHash (v.u.m->xx) ^ 
255                 FcDoubleHash (v.u.m->xy) ^ 
256                 FcDoubleHash (v.u.m->yx) ^ 
257                 FcDoubleHash (v.u.m->yy));
258     case FcTypeCharSet:
259         return (FcChar32) v.u.c->num;
260     case FcTypeFTFace:
261         return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
262                FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
263     case FcTypeLangSet:
264         return FcLangSetHash (v.u.l);
265     }
266     return FcFalse;
267 }
268
269 static FcBool
270 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
271 {
272     if (FcValueListPtrU(la) == FcValueListPtrU(lb))
273         return FcTrue;
274
275     while (FcValueListPtrU(la) && FcValueListPtrU(lb))
276     {
277         if (!FcValueEqual (FcValueListPtrU(la)->value, 
278                            FcValueListPtrU(lb)->value))
279             return FcFalse;
280         la = FcValueListPtrU(la)->next;
281         lb = FcValueListPtrU(lb)->next;
282     }
283     if (FcValueListPtrU(la) || FcValueListPtrU(lb))
284         return FcFalse;
285     return FcTrue;
286 }
287
288 static FcChar32
289 FcValueListHash (FcValueListPtr l)
290 {
291     FcChar32    hash = 0;
292     
293     while (FcValueListPtrU(l))
294     {
295         hash = ((hash << 1) | (hash >> 31)) ^ 
296             FcValueHash (&FcValueListPtrU(l)->value);
297         l = FcValueListPtrU(l)->next;
298     }
299     return hash;
300 }
301
302 void
303 FcPatternDestroy (FcPattern *p)
304 {
305     int             i;
306     
307     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
308         return;
309
310     if (FcPatternFindFullFname (p))
311     {
312         FcStrFree ((FcChar8 *)FcPatternFindFullFname (p));
313         FcPatternAddFullFname (p, 0);
314     }
315
316     for (i = 0; i < p->num; i++)
317         FcValueListDestroy ((FcPatternEltU(p->elts)+i)->values);
318
319     p->num = 0;
320     if (FcPatternEltU(p->elts) && p->elts.bank == FC_BANK_DYNAMIC)
321     {
322         FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
323         free (FcPatternEltU(p->elts));
324         p->elts = FcPatternEltPtrCreateDynamic(0);
325     }
326     p->size = 0;
327     FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
328     free (p);
329 }
330
331 #define FC_VALUE_LIST_HASH_SIZE     257
332 #define FC_PATTERN_HASH_SIZE        67
333
334 typedef struct _FcValueListEnt FcValueListEnt;
335
336 struct _FcValueListEnt {
337     FcValueListEnt  *next;
338     FcValueListPtr  list;
339     FcChar32        hash, pad;
340 };
341
342 typedef union _FcValueListAlign {
343     FcValueListEnt  ent;
344     FcValueList     list;
345 } FcValueListAlign;
346
347 static int          FcValueListFrozenCount[FcTypeLangSet + 1];
348 static int          FcValueListFrozenBytes[FcTypeLangSet + 1];
349 static char         FcValueListFrozenName[][8] = {
350     "Void", 
351     "Integer", 
352     "Double", 
353     "String", 
354     "Bool",
355     "Matrix",
356     "CharSet",
357     "FTFace",
358     "LangSet"
359 };
360
361 void
362 FcValueListReport (void);
363     
364 void
365 FcValueListReport (void)
366 {
367     FcType  t;
368
369     printf ("Fc Frozen Values:\n");
370     printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
371     for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
372         printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
373                 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
374 }
375
376 static FcValueListEnt *
377 FcValueListEntCreate (FcValueListPtr h)
378 {
379     FcValueListAlign    *ea;
380     FcValueListEnt  *e;
381     FcValueListPtr  l;
382     FcValueList     *new;
383     int             n;
384     int             size;
385
386     n = 0;
387     for (l = h; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
388         n++;
389     size = sizeof (FcValueListAlign) + n * sizeof (FcValueList);
390     FcValueListFrozenCount[FcValueListPtrU(h)->value.type]++;
391     FcValueListFrozenBytes[FcValueListPtrU(h)->value.type] += size;
392     // this leaks for some reason
393     ea = malloc (sizeof (FcValueListAlign));
394     if (!ea)
395         return 0;
396     new = malloc (n * sizeof (FcValueList));
397     if (!new)
398         return 0;
399     memset(new, 0, n * sizeof (FcValueList));
400     FcMemAlloc (FC_MEM_VALLIST, size);
401     e = &ea->ent;
402     e->list = (FcValueListPtr) FcValueListPtrCreateDynamic(new);
403     for (l = h; FcValueListPtrU(l); 
404          l = FcValueListPtrU(l)->next, new++)
405     {
406         if ((FcValueListPtrU(l)->value.type & ~FC_STORAGE_STATIC) == FcTypeString)
407         {
408             new->value.type = FcTypeString;
409             new->value.u.s = FcStrStaticName
410                 (fc_value_string(&FcValueListPtrU(l)->value));
411         }
412         else
413         {
414             new->value = FcValueSave (FcValueCanonicalize
415                                       (&FcValueListPtrU(l)->value));
416         }
417         new->binding = FcValueListPtrU(l)->binding;
418         if (FcValueListPtrU(FcValueListPtrU(l)->next))
419         {
420             new->next = FcValueListPtrCreateDynamic(new + 1);
421         }
422         else
423         {
424             new->next = FcValueListPtrCreateDynamic(0);
425         }
426     }
427     return e;
428 }
429
430 static void
431 FcValueListEntDestroy (FcValueListEnt *e)
432 {
433     FcValueListPtr      l;
434
435     FcValueListFrozenCount[FcValueListPtrU(e->list)->value.type]--;
436
437     /* XXX: We should perform these two operations with "size" as
438        computed in FcValueListEntCreate, but we don't have access to
439        that value here. Without this, the FcValueListFrozenBytes
440        values will be wrong as will the FcMemFree counts.
441
442        FcValueListFrozenBytes[e->list->value.type] -= size;
443        FcMemFree (FC_MEM_VALLIST, size);
444     */
445
446     for (l = e->list; FcValueListPtrU(l); 
447          l = FcValueListPtrU(l)->next)
448     {
449         if (FcValueListPtrU(l)->value.type != FcTypeString)
450             FcValueDestroy (FcValueListPtrU(l)->value);
451     }
452     /* XXX: Are we being too chummy with the implementation here to
453        free(e) when it was actually the enclosing FcValueListAlign
454        that was allocated? */
455     free (e);
456 }
457
458 static int      FcValueListTotal;
459 static int      FcValueListUsed;
460
461 static FcValueListEnt   *FcValueListHashTable[FC_VALUE_LIST_HASH_SIZE];
462
463 static FcValueListPtr
464 FcValueListFreeze (FcValueListPtr l)
465 {
466     FcChar32                hash = FcValueListHash (l);
467     FcValueListEnt          **bucket = &FcValueListHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
468     FcValueListEnt          *ent;
469
470     FcValueListTotal++;
471     for (ent = *bucket; ent; ent = ent->next)
472     {
473         if (ent->hash == hash && FcValueListEqual (ent->list, l))
474             return ent->list;
475     }
476
477     ent = FcValueListEntCreate (l);
478     if (!ent)
479         return FcValueListPtrCreateDynamic(0);
480
481     FcValueListUsed++;
482     ent->hash = hash;
483     ent->next = *bucket;
484     *bucket = ent;
485     return ent->list;
486 }
487
488 static void
489 FcValueListThawAll (void)
490 {
491     int i;
492     FcValueListEnt      *ent, *next;
493
494     for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
495     {
496         for (ent = FcValueListHashTable[i]; ent; ent = next)
497         {
498             next = ent->next;
499             FcValueListEntDestroy (ent);
500         }
501         FcValueListHashTable[i] = 0;
502     }
503
504     FcValueListTotal = 0;
505     FcValueListUsed = 0;
506 }
507
508 static FcChar32
509 FcPatternBaseHash (FcPattern *b)
510 {
511     FcChar32    hash = b->num;
512     int         i;
513
514     for (i = 0; i < b->num; i++)
515         hash = ((hash << 1) | (hash >> 31)) ^ 
516             (long) (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values));
517     return hash;
518 }
519
520 typedef struct _FcPatternEnt FcPatternEnt;
521
522 struct _FcPatternEnt {
523     FcPatternEnt    *next;
524     FcChar32        hash;
525     FcPattern       *pattern;
526 };
527
528 static int      FcPatternTotal;
529 static int      FcPatternUsed;
530
531 static FcPatternEnt     *FcPatternHashTable[FC_VALUE_LIST_HASH_SIZE];
532
533 static FcPattern *
534 FcPatternBaseFreeze (FcPattern *b)
535 {
536     FcPattern           *ep;
537     FcPatternElt        *epp;
538     FcChar32            hash = FcPatternBaseHash (b);
539     FcPatternEnt        **bucket = &FcPatternHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
540     FcPatternEnt        *ent;
541     int                 i;
542
543     FcPatternTotal++;
544     for (ent = *bucket; ent; ent = ent->next)
545     {
546         if (ent->hash == hash && b->num == ent->pattern->num)
547         {
548             for (i = 0; i < b->num; i++)
549             {
550                 if (FcObjectPtrCompare((FcPatternEltU(b->elts)+i)->object,
551                                        (FcPatternEltU(ent->pattern->elts)+i)->object) != 0)
552                     break;
553                 if (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values) != 
554                     FcValueListPtrU((FcPatternEltU(ent->pattern->elts)+i)->values))
555                     break;
556             }
557             if (i == b->num)
558                 return ent->pattern;
559         }
560     }
561
562     /*
563      * Compute size of pattern + elts
564      */
565     ent = malloc (sizeof (FcPatternEnt));
566     if (!ent)
567         return 0;
568
569     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPatternEnt));
570     FcPatternUsed++;
571
572     ep = FcPatternCreate();
573     if (!ep)
574         return 0;
575     ent->pattern = ep;
576     epp = malloc(b->num * sizeof (FcPatternElt));
577     if (!epp)
578         goto bail;
579     ep->elts = FcPatternEltPtrCreateDynamic(epp);
580
581     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
582
583     ep->num = b->num;
584     ep->size = b->num;
585     ep->ref = FC_REF_CONSTANT;
586
587     for (i = 0; i < b->num; i++)
588     {
589         (FcPatternEltU(ep->elts)+i)->values = 
590             (FcPatternEltU(b->elts)+i)->values;
591         (FcPatternEltU(ep->elts)+i)->object = 
592             (FcPatternEltU(b->elts)+i)->object;
593     }
594
595     if (FcPatternFindElt (b, FC_FILE))
596         FcPatternTransferFullFname (ep, b);
597
598     ent->hash = hash;
599     ent->next = *bucket;
600     *bucket = ent;
601     return ent->pattern;
602  bail:
603     free(ent);
604     FcMemFree (FC_MEM_PATTERN, sizeof (FcPatternEnt));
605     FcPatternUsed--;
606     return 0;
607 }
608
609 static void
610 FcPatternBaseThawAll (void)
611 {
612     int i;
613     FcPatternEnt        *ent, *next;
614
615     for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
616     {
617         for (ent = FcPatternHashTable[i]; ent; ent = next)
618         {
619             next = ent->next;
620             free (ent);
621         }
622         FcPatternHashTable[i] = 0;
623     }
624
625     FcPatternTotal = 0;
626     FcPatternUsed = 0;
627 }
628
629 FcPattern *
630 FcPatternFreeze (FcPattern *p)
631 {
632     FcPattern   *b, *n = 0;
633     FcPatternElt *e;
634     int         i;
635     
636     if (p->ref == FC_REF_CONSTANT)
637        return p;
638
639     b = FcPatternCreate();
640     if (!b)
641         return 0;
642
643     b->num = p->num;
644     b->size = b->num;
645     b->ref = 1;
646
647     e = malloc(b->num * sizeof (FcPatternElt));
648     if (!e)
649         return 0;
650     b->elts = FcPatternEltPtrCreateDynamic(e);
651     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
652
653     /*
654      * Freeze object lists
655      */
656     for (i = 0; i < p->num; i++)
657     {
658         (FcPatternEltU(b->elts)+i)->object = 
659             (FcPatternEltU(p->elts)+i)->object;
660         (FcPatternEltU(b->elts)+i)->values = 
661             FcValueListFreeze((FcPatternEltU(p->elts)+i)->values);
662         if (!FcValueListPtrU((FcPatternEltU(p->elts)+i)->values))
663             goto bail;
664     }
665
666     if (FcPatternFindElt (p, FC_FILE))
667         FcPatternTransferFullFname (b, p);
668
669     /*
670      * Freeze base
671      */
672     n = FcPatternBaseFreeze (b);
673 #ifdef CHATTY
674     if (FcDebug() & FC_DBG_MEMORY)
675     {
676         printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
677         printf ("Patterns:   total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
678     }
679 #endif
680  bail:
681     free(FcPatternEltU(b->elts));
682     b->elts = FcPatternEltPtrCreateDynamic(0);
683     FcMemFree (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
684     b->num = -1;
685 #ifdef DEBUG
686     assert (FcPatternEqual (n, p));
687 #endif
688     return n;
689 }
690
691 static int
692 FcPatternPosition (const FcPattern *p, const char *object)
693 {
694     int     low, high, mid, c;
695     FcObjectPtr obj;
696
697     obj = FcObjectToPtr(object);
698     low = 0;
699     high = p->num - 1;
700     c = 1;
701     mid = 0;
702     while (low <= high)
703     {
704         mid = (low + high) >> 1;
705         c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
706         if (c == 0)
707             return mid;
708         if (c < 0)
709             low = mid + 1;
710         else
711             high = mid - 1;
712     }
713     if (c < 0)
714         mid++;
715     return -(mid + 1);
716 }
717
718 FcPatternElt *
719 FcPatternFindElt (const FcPattern *p, const char *object)
720 {
721     int     i = FcPatternPosition (p, object);
722     if (i < 0)
723         return 0;
724     return FcPatternEltU(p->elts)+i;
725 }
726
727 FcPatternElt *
728 FcPatternInsertElt (FcPattern *p, const char *object)
729 {
730     int             i;
731     FcPatternElt   *e;
732     
733     i = FcPatternPosition (p, object);
734     if (i < 0)
735     {
736         i = -i - 1;
737     
738         /* reallocate array */
739         if (p->num + 1 >= p->size)
740         {
741             int s = p->size + 16;
742             if (FcPatternEltU(p->elts))
743             {
744                 FcPatternElt *e0 = FcPatternEltU(p->elts);
745                 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
746                 if (!e) /* maybe it was mmapped */
747                 {
748                     e = malloc(s * sizeof (FcPatternElt));
749                     if (e)
750                         memcpy(e, e0, p->num * sizeof (FcPatternElt));
751                 }
752             }
753             else
754                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
755             if (!e)
756                 return FcFalse;
757             p->elts = FcPatternEltPtrCreateDynamic(e);
758             if (p->size)
759                 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
760             FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
761             while (p->size < s)
762             {
763                 (FcPatternEltU(p->elts)+p->size)->object = 0;
764                 (FcPatternEltU(p->elts)+p->size)->values = 
765                     FcValueListPtrCreateDynamic(0);
766                 p->size++;
767             }
768         }
769         
770         /* move elts up */
771         memmove (FcPatternEltU(p->elts) + i + 1,
772                  FcPatternEltU(p->elts) + i,
773                  sizeof (FcPatternElt) *
774                  (p->num - i));
775                  
776         /* bump count */
777         p->num++;
778         
779         (FcPatternEltU(p->elts)+i)->object = FcObjectToPtr (object);
780         (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
781     }
782     
783     return FcPatternEltU(p->elts)+i;
784 }
785
786 FcBool
787 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
788 {
789     int i;
790
791     if (pa == pb)
792         return FcTrue;
793
794     if (pa->num != pb->num)
795         return FcFalse;
796     for (i = 0; i < pa->num; i++)
797     {
798         if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
799                                (FcPatternEltU(pb->elts)+i)->object) != 0)
800             return FcFalse;
801         if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values, 
802                                (FcPatternEltU(pb->elts)+i)->values))
803             return FcFalse;
804     }
805     return FcTrue;
806 }
807
808 FcChar32
809 FcPatternHash (const FcPattern *p)
810 {
811     int         i;
812     FcChar32    h = 0;
813
814     for (i = 0; i < p->num; i++)
815     {
816         h = (((h << 1) | (h >> 31)) ^ 
817              FcStringHash ((FcChar8 *)FcObjectPtrU ((FcPatternEltU(p->elts)+i)->object)) ^
818              FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
819     }
820     return h;
821 }
822
823 FcBool
824 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
825 {
826     FcPatternElt    *ea, *eb;
827     int             i;
828     
829     for (i = 0; i < os->nobject; i++)
830     {
831         ea = FcPatternFindElt (pai, os->objects[i]);
832         eb = FcPatternFindElt (pbi, os->objects[i]);
833         if (ea)
834         {
835             if (!eb)
836                 return FcFalse;
837             if (!FcValueListEqual (ea->values, eb->values))
838                 return FcFalse;
839         }
840         else
841         {
842             if (eb)
843                 return FcFalse;
844         }
845     }
846     return FcTrue;
847 }
848
849 FcBool
850 FcPatternAddWithBinding  (FcPattern         *p,
851                           const char        *object,
852                           FcValue           value,
853                           FcValueBinding    binding,
854                           FcBool            append)
855 {
856     FcPatternElt   *e;
857     FcValueListPtr new, *prev;
858     FcValueList *  newp;
859
860     if (p->ref == FC_REF_CONSTANT)
861         goto bail0;
862
863     newp = malloc (sizeof (FcValueList));
864     if (!newp)
865         goto bail0;
866
867     memset(newp, 0, sizeof (FcValueList));
868     new = FcValueListPtrCreateDynamic(newp);
869     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
870     /* dup string */
871     value = FcValueSave (value);
872     if (value.type == FcTypeVoid)
873         goto bail1;
874
875     /* quick and dirty hack to enable FcCompareFamily speedup:
876      * only allow strings to be added under the FC_FAMILY key.
877      * a better hack would use FcBaseObjectTypes to check all objects. */
878     if (FcObjectToPtr(object) == FcObjectToPtr(FC_FAMILY) &&
879         value.type != FcTypeString)
880         goto bail1;
881
882     FcValueListPtrU(new)->value = value;
883     FcValueListPtrU(new)->binding = binding;
884     FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
885     
886     e = FcPatternInsertElt (p, object);
887     if (!e)
888         goto bail2;
889     
890     if (append)
891     {
892         for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
893             ;
894         *prev = new;
895     }
896     else
897     {
898         FcValueListPtrU(new)->next = e->values;
899         e->values = new;
900     }
901     
902     return FcTrue;
903
904 bail2:    
905     switch (value.type) {
906     case FcTypeString:
907         FcStrFree ((FcChar8 *) value.u.s);
908         break;
909     case FcTypeMatrix:
910         FcMatrixFree ((FcMatrix *) value.u.m);
911         break;
912     case FcTypeCharSet:
913         FcCharSetDestroy ((FcCharSet *) value.u.c);
914         break;
915     case FcTypeLangSet:
916         FcLangSetDestroy ((FcLangSet *) value.u.l);
917         break;
918     default:
919         break;
920     }
921 bail1:
922     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
923     free (FcValueListPtrU(new));
924 bail0:
925     return FcFalse;
926 }
927
928 FcBool
929 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
930 {
931     return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
932 }
933
934 FcBool
935 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
936 {
937     return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
938 }
939
940 FcBool
941 FcPatternDel (FcPattern *p, const char *object)
942 {
943     FcPatternElt   *e;
944
945     e = FcPatternFindElt (p, object);
946     if (!e)
947         return FcFalse;
948
949     /* destroy value */
950     FcValueListDestroy (e->values);
951     
952     /* shuffle existing ones down */
953     memmove (e, e+1, 
954              (FcPatternEltU(p->elts) + p->num - (e + 1)) * 
955              sizeof (FcPatternElt));
956     p->num--;
957     (FcPatternEltU(p->elts)+p->num)->object = 0;
958     (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
959     return FcTrue;
960 }
961
962 FcBool
963 FcPatternRemove (FcPattern *p, const char *object, int id)
964 {
965     FcPatternElt    *e;
966     FcValueListPtr  *prev, l;
967
968     e = FcPatternFindElt (p, object);
969     if (!e)
970         return FcFalse;
971     for (prev = &e->values; 
972          FcValueListPtrU(l = *prev); 
973          prev = &FcValueListPtrU(l)->next)
974     {
975         if (!id)
976         {
977             *prev = FcValueListPtrU(l)->next;
978             FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
979             FcValueListDestroy (l);
980             if (!FcValueListPtrU(e->values))
981                 FcPatternDel (p, object);
982             return FcTrue;
983         }
984         id--;
985     }
986     return FcFalse;
987 }
988
989 FcBool
990 FcPatternAddInteger (FcPattern *p, const char *object, int i)
991 {
992     FcValue     v;
993
994     v.type = FcTypeInteger;
995     v.u.i = i;
996     return FcPatternAdd (p, object, v, FcTrue);
997 }
998
999 FcBool
1000 FcPatternAddDouble (FcPattern *p, const char *object, double d)
1001 {
1002     FcValue     v;
1003
1004     v.type = FcTypeDouble;
1005     v.u.d = d;
1006     return FcPatternAdd (p, object, v, FcTrue);
1007 }
1008
1009
1010 FcBool
1011 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
1012 {
1013     FcValue     v;
1014
1015     v.type = FcTypeString;
1016     v.u.s = FcStrStaticName(s);
1017     return FcPatternAdd (p, object, v, FcTrue);
1018 }
1019
1020 FcBool
1021 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
1022 {
1023     FcValue     v;
1024
1025     v.type = FcTypeMatrix;
1026     v.u.m = s;
1027     return FcPatternAdd (p, object, v, FcTrue);
1028 }
1029
1030
1031 FcBool
1032 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
1033 {
1034     FcValue     v;
1035
1036     v.type = FcTypeBool;
1037     v.u.b = b;
1038     return FcPatternAdd (p, object, v, FcTrue);
1039 }
1040
1041 FcBool
1042 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
1043 {
1044     FcValue     v;
1045
1046     v.type = FcTypeCharSet;
1047     v.u.c = (FcCharSet *)c;
1048     return FcPatternAdd (p, object, v, FcTrue);
1049 }
1050
1051 FcBool
1052 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
1053 {
1054     FcValue     v;
1055
1056     v.type = FcTypeFTFace;
1057     v.u.f = (void *) f;
1058     return FcPatternAdd (p, object, v, FcTrue);
1059 }
1060
1061 FcBool
1062 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1063 {
1064     FcValue     v;
1065
1066     v.type = FcTypeLangSet;
1067     v.u.l = (FcLangSet *)ls;
1068     return FcPatternAdd (p, object, v, FcTrue);
1069 }
1070
1071 FcResult
1072 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
1073 {
1074     FcPatternElt   *e;
1075     FcValueListPtr l;
1076
1077     e = FcPatternFindElt (p, object);
1078     if (!e)
1079         return FcResultNoMatch;
1080     for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
1081     {
1082         if (!id)
1083         {
1084             *v = FcValueCanonicalize(&FcValueListPtrU(l)->value);
1085             return FcResultMatch;
1086         }
1087         id--;
1088     }
1089     return FcResultNoId;
1090 }
1091
1092 FcResult
1093 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
1094 {
1095     FcValue     v;
1096     FcResult    r;
1097
1098     r = FcPatternGet (p, object, id, &v);
1099     if (r != FcResultMatch)
1100         return r;
1101     switch (v.type) {
1102     case FcTypeDouble:
1103         *i = (int) v.u.d;
1104         break;
1105     case FcTypeInteger:
1106         *i = v.u.i;
1107         break;
1108     default:
1109         return FcResultTypeMismatch;
1110     }
1111     return FcResultMatch;
1112 }
1113
1114 FcResult
1115 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
1116 {
1117     FcValue     v;
1118     FcResult    r;
1119
1120     r = FcPatternGet (p, object, id, &v);
1121     if (r != FcResultMatch)
1122         return r;
1123     switch (v.type) {
1124     case FcTypeDouble:
1125         *d = v.u.d;
1126         break;
1127     case FcTypeInteger:
1128         *d = (double) v.u.i;
1129         break;
1130     default:
1131         return FcResultTypeMismatch;
1132     }
1133     return FcResultMatch;
1134 }
1135
1136 FcResult
1137 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1138 {
1139     FcValue     v;
1140     FcResult    r;
1141
1142     r = FcPatternGet (p, object, id, &v);
1143     if (r != FcResultMatch)
1144         return r;
1145     if (v.type != FcTypeString)
1146         return FcResultTypeMismatch;
1147
1148     if (FcObjectToPtr(object) == FcObjectToPtr(FC_FILE))
1149     {
1150         const char *fn, *fpath;
1151         FcChar8 *fname;
1152         int size;
1153
1154         fn = FcPatternFindFullFname(p);
1155         if (fn)
1156         {
1157             *s = (FcChar8 *) fn;
1158             return FcResultMatch;
1159         }
1160
1161         if (!p->bank)
1162         {
1163             *s = (FcChar8 *) v.u.s;
1164             return FcResultMatch;
1165         }
1166
1167         fpath = FcCacheFindBankDir (p->bank);
1168         size = strlen((char*)fpath) + 1 + strlen ((char *)v.u.s) + 1;
1169         fname = malloc (size);
1170         if (!fname)
1171             return FcResultOutOfMemory;
1172
1173         FcMemAlloc (FC_MEM_STRING, size);
1174         strcpy ((char *)fname, (char *)fpath);
1175         strcat ((char *)fname, "/");
1176         strcat ((char *)fname, (char *)v.u.s);
1177         
1178         FcPatternAddFullFname (p, (const char *)fname);
1179         *s = (FcChar8 *)fname;
1180         return FcResultMatch;
1181     }
1182
1183     *s = (FcChar8 *) v.u.s;
1184     return FcResultMatch;
1185 }
1186
1187 FcResult
1188 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1189 {
1190     FcValue     v;
1191     FcResult    r;
1192
1193     r = FcPatternGet (p, object, id, &v);
1194     if (r != FcResultMatch)
1195         return r;
1196     if (v.type != FcTypeMatrix)
1197         return FcResultTypeMismatch;
1198     *m = (FcMatrix *)v.u.m;
1199     return FcResultMatch;
1200 }
1201
1202
1203 FcResult
1204 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1205 {
1206     FcValue     v;
1207     FcResult    r;
1208
1209     r = FcPatternGet (p, object, id, &v);
1210     if (r != FcResultMatch)
1211         return r;
1212     if (v.type != FcTypeBool)
1213         return FcResultTypeMismatch;
1214     *b = v.u.b;
1215     return FcResultMatch;
1216 }
1217
1218 FcResult
1219 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1220 {
1221     FcValue     v;
1222     FcResult    r;
1223
1224     r = FcPatternGet (p, object, id, &v);
1225     if (r != FcResultMatch)
1226         return r;
1227     if (v.type != FcTypeCharSet)
1228         return FcResultTypeMismatch;
1229     *c = (FcCharSet *)v.u.c;
1230     return FcResultMatch;
1231 }
1232
1233 FcResult
1234 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1235 {
1236     FcValue     v;
1237     FcResult    r;
1238
1239     r = FcPatternGet (p, object, id, &v);
1240     if (r != FcResultMatch)
1241         return r;
1242     if (v.type != FcTypeFTFace)
1243         return FcResultTypeMismatch;
1244     *f = (FT_Face) v.u.f;
1245     return FcResultMatch;
1246 }
1247
1248 FcResult
1249 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1250 {
1251     FcValue     v;
1252     FcResult    r;
1253
1254     r = FcPatternGet (p, object, id, &v);
1255     if (r != FcResultMatch)
1256         return r;
1257     if (v.type != FcTypeLangSet)
1258         return FcResultTypeMismatch;
1259     *ls = (FcLangSet *)v.u.l;
1260     return FcResultMatch;
1261 }
1262
1263 FcPattern *
1264 FcPatternDuplicate (const FcPattern *orig)
1265 {
1266     FcPattern       *new;
1267     FcPatternElt    *e;
1268     int             i;
1269     FcValueListPtr  l;
1270
1271     new = FcPatternCreate ();
1272     if (!new)
1273         goto bail0;
1274
1275     e = FcPatternEltU(orig->elts);
1276
1277     for (i = 0; i < orig->num; i++)
1278     {
1279         for (l = (e + i)->values; 
1280              FcValueListPtrU(l); 
1281              l = FcValueListPtrU(l)->next)
1282             if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object), 
1283                                FcValueCanonicalize(&FcValueListPtrU(l)->value),
1284                                FcTrue))
1285                 goto bail1;
1286     }
1287     FcPatternTransferFullFname (new, orig);
1288
1289     return new;
1290
1291 bail1:
1292     FcPatternDestroy (new);
1293 bail0:
1294     return 0;
1295 }
1296
1297 void
1298 FcPatternReference (FcPattern *p)
1299 {
1300     if (p->ref != FC_REF_CONSTANT)
1301         p->ref++;
1302 }
1303
1304 FcPattern *
1305 FcPatternVaBuild (FcPattern *orig, va_list va)
1306 {
1307     FcPattern   *ret;
1308     
1309     FcPatternVapBuild (ret, orig, va);
1310     return ret;
1311 }
1312
1313 FcPattern *
1314 FcPatternBuild (FcPattern *orig, ...)
1315 {
1316     va_list     va;
1317     
1318     va_start (va, orig);
1319     FcPatternVapBuild (orig, orig, va);
1320     va_end (va);
1321     return orig;
1322 }
1323
1324 /*
1325  * Add all of the elements in 's' to 'p'
1326  */
1327 FcBool
1328 FcPatternAppend (FcPattern *p, FcPattern *s)
1329 {
1330     int             i;
1331     FcPatternElt    *e;
1332     FcValueListPtr  v;
1333     
1334     for (i = 0; i < s->num; i++)
1335     {
1336         e = FcPatternEltU(s->elts)+i;
1337         for (v = e->values; FcValueListPtrU(v); 
1338              v = FcValueListPtrU(v)->next)
1339         {
1340             if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1341                                           FcValueCanonicalize(&FcValueListPtrU(v)->value), 
1342                                           FcValueListPtrU(v)->binding, FcTrue))
1343                 return FcFalse;
1344         }
1345     }
1346     return FcTrue;
1347 }
1348
1349 #define OBJECT_HASH_SIZE    31
1350 static struct objectBucket {
1351     struct objectBucket *next;
1352     FcChar32            hash;
1353 } *FcObjectBuckets[OBJECT_HASH_SIZE];
1354
1355 const FcChar8 *
1356 FcStrStaticName (const FcChar8 *name)
1357 {
1358     FcChar32            hash = FcStringHash (name);
1359     struct objectBucket **p;
1360     struct objectBucket *b;
1361     int                 size;
1362
1363     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1364         if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1365             return (FcChar8 *) (b + 1);
1366     size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
1367     b = malloc (size + sizeof (int));
1368     /* workaround glibc bug which reads strlen in groups of 4 */
1369     FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
1370     if (!b)
1371         return NULL;
1372     b->next = 0;
1373     b->hash = hash;
1374     strcpy ((char *) (b + 1), (char *)name);
1375     *p = b;
1376     return (FcChar8 *) (b + 1);
1377 }
1378
1379 static void
1380 FcStrStaticNameFini (void)
1381 {
1382     int i, size;
1383     struct objectBucket *b, *next;
1384     char *name;
1385
1386     for (i = 0; i < OBJECT_HASH_SIZE; i++)
1387     {
1388         for (b = FcObjectBuckets[i]; b; b = next)
1389         {
1390             next = b->next;
1391             name = (char *) (b + 1);
1392             size = sizeof (struct objectBucket) + strlen (name) + 1;
1393             FcMemFree (FC_MEM_STATICSTR, size);
1394             free (b);
1395         }
1396         FcObjectBuckets[i] = 0;
1397     }
1398 }
1399
1400 void
1401 FcPatternFini (void)
1402 {
1403     FcPatternBaseThawAll ();
1404     FcValueListThawAll ();
1405     FcStrStaticNameFini ();
1406     FcObjectStaticNameFini ();
1407 }
1408
1409 FcPatternElt *
1410 FcPatternEltU (FcPatternEltPtr pei)
1411 {
1412     if (pei.bank == FC_BANK_DYNAMIC)
1413         return pei.u.dyn;
1414
1415     return &fcpatternelts[FcCacheBankToIndex(pei.bank)][pei.u.stat];
1416 }
1417
1418 static FcPatternEltPtr
1419 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1420 {
1421     FcPatternEltPtr new;
1422     new.bank = FC_BANK_DYNAMIC;
1423     new.u.dyn = e;
1424     return new;
1425 }
1426
1427 static FcPatternEltPtr
1428 FcPatternEltPtrCreateStatic (int bank, int i)
1429 {
1430     FcPatternEltPtr new;
1431     new.bank = bank;
1432     new.u.stat = i;
1433     return new;
1434 }
1435
1436 static void
1437 FcStrNewBank (void);
1438 static int
1439 FcStrNeededBytes (const FcChar8 * s);
1440 static int
1441 FcStrNeededBytesAlign (void);
1442 static void *
1443 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
1444 static const FcChar8 *
1445 FcStrSerialize (int bank, const FcChar8 * s);
1446 static void *
1447 FcStrUnserialize (FcCache metadata, void *block_ptr);
1448
1449 static void
1450 FcValueListNewBank (void);
1451 static int
1452 FcValueListNeededBytes (FcValueList * vl);
1453 static int
1454 FcValueListNeededBytesAlign (void);
1455 static void *
1456 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
1457 static FcValueListPtr
1458 FcValueListSerialize(int bank, FcValueList *pi);
1459 static void *
1460 FcValueListUnserialize (FcCache metadata, void *block_ptr);
1461
1462
1463 void
1464 FcPatternNewBank (void)
1465 {
1466     fcpattern_count = 0;
1467     fcpatternelt_count = 0;
1468
1469     FcStrNewBank();
1470     FcValueListNewBank();
1471 }
1472
1473 int
1474 FcPatternNeededBytes (FcPattern * p)
1475 {
1476     int i, cum = 0, c;
1477
1478     fcpattern_count++;
1479     fcpatternelt_count += p->num;
1480
1481     for (i = 0; i < p->num; i++)
1482     {
1483         c = FcValueListNeededBytes (FcValueListPtrU
1484                                     (((FcPatternEltU(p->elts)+i)->values)));
1485         if (c < 0)
1486             return c;
1487         cum += c;
1488     }
1489
1490     return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
1491 }
1492
1493 int
1494 FcPatternNeededBytesAlign (void)
1495 {
1496     return __alignof__ (FcPattern) + __alignof__ (FcPatternElt) + 
1497         FcValueListNeededBytesAlign ();
1498 }
1499
1500 static FcBool
1501 FcPatternEnsureBank (int bi)
1502 {
1503     FcPattern **pp;
1504     FcPatternElt **ep;
1505     int i;
1506
1507     if (!fcpatterns || fcpattern_bank_count <= bi)
1508     {
1509         int new_count = bi + 4;
1510         pp = realloc (fcpatterns, sizeof (FcPattern *) * new_count);
1511         if (!pp)
1512             return 0;
1513
1514         FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
1515         fcpatterns = pp;
1516
1517         ep = realloc (fcpatternelts, sizeof (FcPatternElt *) * new_count);
1518         if (!ep)
1519             return 0;
1520
1521         FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
1522         fcpatternelts = ep;
1523
1524         for (i = fcpattern_bank_count; i < new_count; i++)
1525         {
1526             fcpatterns[i] = 0;
1527             fcpatternelts[i] = 0;
1528         }
1529
1530         fcpattern_bank_count = new_count;
1531     }
1532
1533     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
1534     return FcTrue;
1535 }
1536
1537 void *
1538 FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
1539 {
1540     int bi = FcCacheBankToIndex(metadata->bank);
1541
1542     if (!FcPatternEnsureBank(bi))
1543         return 0;
1544
1545     fcpattern_ptr = 0;
1546     block_ptr = ALIGN(block_ptr, FcPattern);
1547     fcpatterns[bi] = (FcPattern *)block_ptr;
1548     block_ptr = (void *)((char *)block_ptr + 
1549                          (sizeof (FcPattern) * fcpattern_count));
1550     
1551     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1552     fcpatternelt_ptr = 0;
1553     block_ptr = ALIGN(block_ptr, FcPatternElt);
1554     fcpatternelts[bi] = (FcPatternElt *)block_ptr;
1555     block_ptr = (void *)((char *)block_ptr + 
1556                          (sizeof (FcPatternElt) * fcpatternelt_count));
1557
1558     metadata->pattern_count = fcpattern_count;
1559     metadata->patternelt_count = fcpatternelt_count;
1560
1561     block_ptr = FcStrDistributeBytes (metadata, block_ptr);
1562     block_ptr = FcValueListDistributeBytes (metadata, block_ptr);
1563     return block_ptr;
1564 }
1565
1566 FcPattern *
1567 FcPatternSerialize (int bank, FcPattern *old)
1568 {
1569     FcPattern *p;
1570     FcPatternElt *e, *nep;
1571     FcValueList * nv;
1572     FcValueListPtr v, nv_head, nvp;
1573     int i, elts, bi = FcCacheBankToIndex(bank);
1574
1575     p = &fcpatterns[bi][fcpattern_ptr++];
1576     p->bank = bank;
1577     elts = fcpatternelt_ptr;
1578     nep = &fcpatternelts[bi][elts];
1579     if (!nep)
1580         return FcFalse;
1581
1582     fcpatternelt_ptr += old->num;
1583
1584     for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++) 
1585     {
1586         v = e->values;
1587         nvp = nv_head = FcValueListSerialize(bank, FcValueListPtrU(v));
1588         if (!FcValueListPtrU(nv_head))
1589             return 0;
1590         nv = FcValueListPtrU(nvp);
1591         
1592         for (;
1593              FcValueListPtrU(v);
1594              v = FcValueListPtrU(v)->next, 
1595                  nv = FcValueListPtrU(nv->next))
1596         {
1597             
1598             if (FcValueListPtrU(FcValueListPtrU(v)->next))
1599             {
1600                 nvp = FcValueListSerialize
1601                     (bank, FcValueListPtrU(FcValueListPtrU(v)->next));
1602                 nv->next = nvp;
1603             }
1604         }
1605         
1606         nep[i].values = nv_head;
1607         nep[i].object = e->object;
1608     }
1609
1610     p->elts = old->elts;
1611     p->elts = FcPatternEltPtrCreateStatic(bank, elts);
1612     p->size = old->num;
1613     p->num = old->num;
1614     p->ref = FC_REF_CONSTANT;
1615     return p;
1616 }
1617
1618 void *
1619 FcPatternUnserialize (FcCache metadata, void *block_ptr)
1620 {
1621     int bi = FcCacheBankToIndex(metadata.bank);
1622     if (!FcPatternEnsureBank(bi))
1623         return FcFalse;
1624
1625     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata.pattern_count);
1626     block_ptr = ALIGN(block_ptr, FcPattern);
1627     fcpatterns[bi] = (FcPattern *)block_ptr;
1628     block_ptr = (void *)((char *)block_ptr + 
1629                          (sizeof (FcPattern) * metadata.pattern_count));
1630     
1631     FcMemAlloc (FC_MEM_PATELT, 
1632                 sizeof (FcPatternElt) * metadata.patternelt_count);
1633     block_ptr = ALIGN(block_ptr, FcPatternElt);
1634     fcpatternelts[bi] = (FcPatternElt *)block_ptr;
1635     block_ptr = (void *)((char *)block_ptr + 
1636                          (sizeof (FcPatternElt) * metadata.patternelt_count));
1637         
1638     block_ptr = FcStrUnserialize (metadata, block_ptr);
1639     block_ptr = FcValueListUnserialize (metadata, block_ptr);
1640
1641     return block_ptr;
1642 }
1643
1644 static void
1645 FcValueListNewBank (void)
1646 {
1647     fcvaluelist_count = 0;
1648
1649     FcCharSetNewBank();
1650     FcLangSetNewBank();
1651 }
1652
1653 static int
1654 FcValueListNeededBytes (FcValueList *p)
1655 {
1656     FcValueList *vl;
1657     int cum = 0;
1658
1659     for (vl = p;
1660          vl; 
1661          vl = FcValueListPtrU(vl->next))
1662     {
1663         FcValue v = FcValueCanonicalize(&vl->value); // unserialize just in case
1664
1665         switch (v.type)
1666         {
1667         case FcTypeCharSet:
1668             cum += FcCharSetNeededBytes(v.u.c);
1669             break;
1670         case FcTypeLangSet:
1671             cum += FcLangSetNeededBytes(v.u.l);
1672             break;
1673         case FcTypeString:
1674             cum += FcStrNeededBytes(v.u.s);
1675         default:
1676             break;
1677         }
1678         fcvaluelist_count++;
1679         cum += sizeof (FcValueList);
1680     }
1681     
1682     return cum;
1683 }
1684
1685 static int
1686 FcValueListNeededBytesAlign (void)
1687 {
1688     return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() + 
1689         FcStrNeededBytesAlign() + __alignof__ (FcValueList);
1690 }
1691
1692 static FcBool
1693 FcValueListEnsureBank (int bi)
1694 {
1695     FcValueList **pvl;
1696
1697     if (!fcvaluelists || fcvaluelist_bank_count <= bi)
1698     {
1699         int new_count = bi + 2, i;
1700
1701         pvl = realloc (fcvaluelists, sizeof (FcValueList *) * new_count);
1702         if (!pvl)
1703             return FcFalse;
1704
1705         FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
1706
1707         fcvaluelists = pvl;
1708         for (i = fcvaluelist_bank_count; i < new_count; i++)
1709             fcvaluelists[i] = 0;
1710
1711         fcvaluelist_bank_count = new_count;
1712     }
1713     return FcTrue;
1714 }
1715
1716 static void *
1717 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
1718 {
1719     int bi = FcCacheBankToIndex(metadata->bank);
1720
1721     if (!FcValueListEnsureBank(bi))
1722         return 0;
1723
1724     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1725     fcvaluelist_ptr = 0;
1726     block_ptr = ALIGN(block_ptr, FcValueList);
1727     fcvaluelists[bi] = (FcValueList *)block_ptr;
1728     block_ptr = (void *)((char *)block_ptr + 
1729                          (sizeof (FcValueList) * fcvaluelist_count));
1730     metadata->valuelist_count = fcvaluelist_count;
1731
1732     block_ptr = FcCharSetDistributeBytes(metadata, block_ptr);
1733     block_ptr = FcLangSetDistributeBytes(metadata, block_ptr);
1734
1735     return block_ptr;
1736 }
1737
1738 static FcValueListPtr
1739 FcValueListSerialize(int bank, FcValueList *pi)
1740 {
1741     FcValueListPtr new; 
1742     FcValue * v;
1743     int bi = FcCacheBankToIndex(bank);
1744
1745     if (!pi)
1746     {
1747         new.bank = FC_BANK_DYNAMIC;
1748         new.u.dyn = 0;
1749         return new;
1750     }
1751
1752     fcvaluelists[bi][fcvaluelist_ptr] = *pi;
1753     new.bank = bank;
1754     new.u.stat = fcvaluelist_ptr++;
1755     fcvaluelists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
1756     v = &fcvaluelists[bi][new.u.stat].value;
1757     switch (v->type)
1758     {
1759     case FcTypeString:
1760         if (v->u.s)
1761         {
1762             const FcChar8 * s = FcStrSerialize(bank, v->u.s);
1763             if (!s)
1764                 return FcValueListPtrCreateDynamic(pi);
1765             v->u.s_off = s - (const FcChar8 *)v;
1766             v->type |= FC_STORAGE_STATIC;
1767         }
1768         break;
1769     case FcTypeMatrix:
1770         break;
1771     case FcTypeCharSet:
1772         if (v->u.c)
1773         {
1774             FcCharSet * c = FcCharSetSerialize(bank, (FcCharSet *)v->u.c);
1775             if (!c)
1776                 return FcValueListPtrCreateDynamic(pi);
1777             v->u.c_off = (char *)c - (char *)v;
1778             v->type |= FC_STORAGE_STATIC;
1779         }
1780         break;
1781     case FcTypeLangSet:
1782         if (v->u.l)
1783         {
1784             FcLangSet * l = FcLangSetSerialize(bank, (FcLangSet *)v->u.l);
1785             if (!l)
1786                 return FcValueListPtrCreateDynamic(pi);
1787             v->u.l_off = (char *)l - (char *)v;
1788             v->type |= FC_STORAGE_STATIC;
1789         }
1790         break;
1791     default:
1792         break;
1793     }
1794     return new;
1795 }
1796
1797 static void *
1798 FcValueListUnserialize (FcCache metadata, void *block_ptr)
1799 {
1800     int bi = FcCacheBankToIndex(metadata.bank);
1801
1802     if (!FcValueListEnsureBank(bi))
1803         return 0;
1804
1805     FcMemAlloc (FC_MEM_VALLIST, 
1806                 sizeof (FcValueList) * metadata.valuelist_count);
1807     block_ptr = ALIGN(block_ptr, FcValueList);
1808     fcvaluelists[bi] = (FcValueList *)block_ptr;
1809     block_ptr = (void *)((char *)block_ptr + 
1810                          (sizeof (FcValueList) * metadata.valuelist_count));
1811
1812     block_ptr = FcCharSetUnserialize(metadata, block_ptr);
1813     block_ptr = FcLangSetUnserialize(metadata, block_ptr);
1814
1815     return block_ptr;
1816 }
1817
1818 FcValueList * 
1819 FcValueListPtrU (FcValueListPtr pi)
1820 {
1821     if (pi.bank == FC_BANK_DYNAMIC)
1822         return pi.u.dyn;
1823
1824     return &fcvaluelists[FcCacheBankToIndex(pi.bank)][pi.u.stat];
1825 }
1826
1827 FcValueListPtr
1828 FcValueListPtrCreateDynamic(FcValueList * p)
1829 {
1830     FcValueListPtr r; 
1831
1832     r.bank = FC_BANK_DYNAMIC; 
1833     r.u.dyn = p;
1834     return r;
1835 }
1836
1837 static FcChar8 ** static_strs;
1838 static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
1839
1840 static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
1841
1842 static void
1843 FcStrNewBank (void)
1844 {
1845     int i, size;
1846     struct objectBucket *b, *next;
1847     char *name;
1848
1849     for (i = 0; i < OBJECT_HASH_SIZE; i++)
1850     {
1851         for (b = FcStrBuckets[i]; b; b = next)
1852         {
1853             next = b->next;
1854             name = (char *) (b + 1);
1855             size = sizeof (struct objectBucket) + strlen (name) + 1;
1856             FcMemFree (FC_MEM_STATICSTR, size);
1857             free (b);
1858         }
1859         FcStrBuckets[i] = 0;
1860     }
1861
1862     fcstr_count = 0;
1863 }
1864
1865 static int
1866 FcStrNeededBytes (const FcChar8 * s)
1867 {
1868     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
1869     struct objectBucket **p;
1870     struct objectBucket *b;
1871     int                 size;
1872
1873     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1874         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1875             return 0;
1876     size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
1877     b = malloc (size);
1878     FcMemAlloc (FC_MEM_STATICSTR, size);
1879     if (!b)
1880         return -1;
1881     b->next = 0;
1882     b->hash = hash;
1883     strcpy ((char *) (b + 1), (char *)s);
1884
1885     /* Yes, the following line is convoluted.  However, it is
1886      * incorrect to replace the with a memset, because the C
1887      * specification doesn't guarantee that the null pointer is
1888      * the same as the zero bit pattern. */
1889     *(char **)((char *) (b + 1) + strlen((char *)s) + 1) = 0;
1890     *p = b;
1891
1892     fcstr_count += strlen((char *)s) + 1;
1893     return strlen((char *)s) + 1;
1894 }
1895
1896 static int
1897 FcStrNeededBytesAlign (void)
1898 {
1899     return __alignof__ (char);
1900 }
1901
1902 static FcBool
1903 FcStrEnsureBank (int bi)
1904 {
1905     FcChar8 ** ss;
1906
1907     if (!static_strs || static_str_bank_count <= bi)
1908     {
1909         int new_count = bi + 4, i;
1910         ss = realloc (static_strs, sizeof (const char *) * new_count);
1911         if (!ss)
1912             return FcFalse;
1913
1914         FcMemAlloc (FC_MEM_STRING, sizeof (const char *) * (new_count-static_str_bank_count));
1915         static_strs = ss;
1916
1917         for (i = static_str_bank_count; i < new_count; i++)
1918             static_strs[i] = 0;
1919         static_str_bank_count = new_count;
1920     }
1921     return FcTrue;
1922 }
1923
1924 static void *
1925 FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
1926 {
1927     int bi = FcCacheBankToIndex(metadata->bank);
1928     if (!FcStrEnsureBank(bi)) 
1929         return 0;
1930
1931     FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
1932     block_ptr = ALIGN (block_ptr, FcChar8);
1933     static_strs[bi] = (FcChar8 *)block_ptr;
1934     block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
1935     metadata->str_count = fcstr_count;
1936     fcstr_ptr = 0;
1937
1938     return block_ptr;
1939 }
1940
1941 static const FcChar8 *
1942 FcStrSerialize (int bank, const FcChar8 * s)
1943 {
1944     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
1945     struct objectBucket **p;
1946     struct objectBucket *b;
1947     int bi = FcCacheBankToIndex(bank);
1948
1949     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1950         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1951         {
1952             FcChar8 * t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
1953             if (!t)
1954             {
1955                 strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
1956                 *(FcChar8 **)((FcChar8 *) (b + 1) + strlen((char *)s) + 1) = (static_strs[bi] + fcstr_ptr);
1957                 fcstr_ptr += strlen((char *)s) + 1;
1958                 t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
1959             }
1960             return t;
1961         }
1962     return 0;
1963 }
1964
1965 static void *
1966 FcStrUnserialize (FcCache metadata, void *block_ptr)
1967 {
1968     int bi = FcCacheBankToIndex(metadata.bank);
1969     if (!FcStrEnsureBank(bi))
1970         return 0;
1971
1972     FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata.str_count);
1973     block_ptr = ALIGN (block_ptr, FcChar8);
1974     static_strs[bi] = (FcChar8 *)block_ptr;
1975     block_ptr = (void *)((char *)block_ptr + 
1976                          (sizeof (char) * metadata.str_count));
1977
1978     return block_ptr;
1979 }
1980
1981 /* we don't store these in the FcPattern itself because
1982  * we don't want to serialize the directory names */
1983
1984 /* I suppose this should be cleaned, too... */
1985 typedef struct _FcPatternDirMapping {
1986     const FcPattern     *p;
1987     const char *fname;
1988 } FcPatternDirMapping;
1989
1990 #define PATTERNDIR_HASH_SIZE    31
1991 static struct patternDirBucket {
1992     struct patternDirBucket     *next;
1993     FcPatternDirMapping         m;
1994 } FcPatternDirBuckets[PATTERNDIR_HASH_SIZE];
1995
1996 void
1997 FcPatternAddFullFname (const FcPattern *p, const char *fname)
1998 {
1999     struct patternDirBucket     *pb;
2000
2001     /* N.B. FcPatternHash fails, since it's contents-based, not
2002      * address-based, and we're in the process of mutating the FcPattern. */
2003     for (pb = &FcPatternDirBuckets
2004              [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
2005          pb->m.p != p && pb->next; 
2006          pb = pb->next)
2007         ;
2008
2009     if (pb->m.p == p)
2010     {
2011         pb->m.fname = fname;
2012         return;
2013     }
2014
2015     pb->next = malloc (sizeof (struct patternDirBucket));
2016     if (!pb->next)
2017         return;
2018     FcMemAlloc (FC_MEM_CACHE, sizeof (struct patternDirBucket));
2019
2020     pb->next->next = 0;
2021     pb->next->m.p = p;
2022     pb->next->m.fname = fname;
2023 }
2024
2025 static const char *
2026 FcPatternFindFullFname (const FcPattern *p)
2027 {
2028     struct patternDirBucket     *pb;
2029
2030     for (pb = &FcPatternDirBuckets
2031              [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE]; 
2032          pb; pb = pb->next)
2033         if (pb->m.p == p)
2034             return pb->m.fname;
2035
2036     return 0;
2037 }
2038
2039 void
2040 FcPatternTransferFullFname (const FcPattern *new, const FcPattern *orig)
2041 {
2042     FcChar8 * s;
2043     FcPatternGetString (orig, FC_FILE, 0, &s);
2044     FcPatternAddFullFname (new, 
2045                            (char *)FcStrCopy 
2046                            ((FcChar8 *)FcPatternFindFullFname(orig)));
2047 }