]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
Move FC_BANK_DYNAMIC, FC_BANK_FIRST to internal header.
[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     FcObjectPtr    objectPtr;
860
861     if (p->ref == FC_REF_CONSTANT)
862         goto bail0;
863
864     newp = malloc (sizeof (FcValueList));
865     if (!newp)
866         goto bail0;
867
868     memset(newp, 0, sizeof (FcValueList));
869     new = FcValueListPtrCreateDynamic(newp);
870     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
871     /* dup string */
872     value = FcValueSave (value);
873     if (value.type == FcTypeVoid)
874         goto bail1;
875
876     /* quick and dirty hack to enable FcCompareFamily/FcCompareString
877      * speedup: only allow strings to be added under the FC_FAMILY,
878      * FC_FOUNDRY, FC_STYLE, FC_RASTERIZER keys.  
879      * and charsets under FC_CHARSET key.
880      * This is slightly semantically different from the old behaviour,
881      * but fonts shouldn't be getting non-strings here anyway.
882      * a better hack would use FcBaseObjectTypes to check all objects. */
883     objectPtr = FcObjectToPtr(object);
884     if ((objectPtr == FcObjectToPtr(FC_FAMILY)
885          || objectPtr == FcObjectToPtr(FC_FOUNDRY)
886          || objectPtr == FcObjectToPtr(FC_STYLE)
887          || objectPtr == FcObjectToPtr(FC_RASTERIZER))
888         && value.type != FcTypeString)
889         goto bail1;
890     if (objectPtr == FcObjectToPtr(FC_CHARSET)
891         && value.type != FcTypeCharSet)
892         goto bail1;
893
894     FcValueListPtrU(new)->value = value;
895     FcValueListPtrU(new)->binding = binding;
896     FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
897     
898     e = FcPatternInsertElt (p, object);
899     if (!e)
900         goto bail2;
901     
902     if (append)
903     {
904         for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
905             ;
906         *prev = new;
907     }
908     else
909     {
910         FcValueListPtrU(new)->next = e->values;
911         e->values = new;
912     }
913     
914     return FcTrue;
915
916 bail2:    
917     switch (value.type) {
918     case FcTypeString:
919         FcStrFree ((FcChar8 *) value.u.s);
920         break;
921     case FcTypeMatrix:
922         FcMatrixFree ((FcMatrix *) value.u.m);
923         break;
924     case FcTypeCharSet:
925         FcCharSetDestroy ((FcCharSet *) value.u.c);
926         break;
927     case FcTypeLangSet:
928         FcLangSetDestroy ((FcLangSet *) value.u.l);
929         break;
930     default:
931         break;
932     }
933 bail1:
934     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
935     free (FcValueListPtrU(new));
936 bail0:
937     return FcFalse;
938 }
939
940 FcBool
941 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
942 {
943     return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
944 }
945
946 FcBool
947 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
948 {
949     return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
950 }
951
952 FcBool
953 FcPatternDel (FcPattern *p, const char *object)
954 {
955     FcPatternElt   *e;
956
957     e = FcPatternFindElt (p, object);
958     if (!e)
959         return FcFalse;
960
961     /* destroy value */
962     FcValueListDestroy (e->values);
963     
964     /* shuffle existing ones down */
965     memmove (e, e+1, 
966              (FcPatternEltU(p->elts) + p->num - (e + 1)) * 
967              sizeof (FcPatternElt));
968     p->num--;
969     (FcPatternEltU(p->elts)+p->num)->object = 0;
970     (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
971     return FcTrue;
972 }
973
974 FcBool
975 FcPatternRemove (FcPattern *p, const char *object, int id)
976 {
977     FcPatternElt    *e;
978     FcValueListPtr  *prev, l;
979
980     e = FcPatternFindElt (p, object);
981     if (!e)
982         return FcFalse;
983     for (prev = &e->values; 
984          FcValueListPtrU(l = *prev); 
985          prev = &FcValueListPtrU(l)->next)
986     {
987         if (!id)
988         {
989             *prev = FcValueListPtrU(l)->next;
990             FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
991             FcValueListDestroy (l);
992             if (!FcValueListPtrU(e->values))
993                 FcPatternDel (p, object);
994             return FcTrue;
995         }
996         id--;
997     }
998     return FcFalse;
999 }
1000
1001 FcBool
1002 FcPatternAddInteger (FcPattern *p, const char *object, int i)
1003 {
1004     FcValue     v;
1005
1006     v.type = FcTypeInteger;
1007     v.u.i = i;
1008     return FcPatternAdd (p, object, v, FcTrue);
1009 }
1010
1011 FcBool
1012 FcPatternAddDouble (FcPattern *p, const char *object, double d)
1013 {
1014     FcValue     v;
1015
1016     v.type = FcTypeDouble;
1017     v.u.d = d;
1018     return FcPatternAdd (p, object, v, FcTrue);
1019 }
1020
1021
1022 FcBool
1023 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
1024 {
1025     FcValue     v;
1026
1027     v.type = FcTypeString;
1028     v.u.s = FcStrStaticName(s);
1029     return FcPatternAdd (p, object, v, FcTrue);
1030 }
1031
1032 FcBool
1033 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
1034 {
1035     FcValue     v;
1036
1037     v.type = FcTypeMatrix;
1038     v.u.m = s;
1039     return FcPatternAdd (p, object, v, FcTrue);
1040 }
1041
1042
1043 FcBool
1044 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
1045 {
1046     FcValue     v;
1047
1048     v.type = FcTypeBool;
1049     v.u.b = b;
1050     return FcPatternAdd (p, object, v, FcTrue);
1051 }
1052
1053 FcBool
1054 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
1055 {
1056     FcValue     v;
1057
1058     v.type = FcTypeCharSet;
1059     v.u.c = (FcCharSet *)c;
1060     return FcPatternAdd (p, object, v, FcTrue);
1061 }
1062
1063 FcBool
1064 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
1065 {
1066     FcValue     v;
1067
1068     v.type = FcTypeFTFace;
1069     v.u.f = (void *) f;
1070     return FcPatternAdd (p, object, v, FcTrue);
1071 }
1072
1073 FcBool
1074 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1075 {
1076     FcValue     v;
1077
1078     v.type = FcTypeLangSet;
1079     v.u.l = (FcLangSet *)ls;
1080     return FcPatternAdd (p, object, v, FcTrue);
1081 }
1082
1083 FcResult
1084 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
1085 {
1086     FcPatternElt   *e;
1087     FcValueListPtr l;
1088
1089     e = FcPatternFindElt (p, object);
1090     if (!e)
1091         return FcResultNoMatch;
1092     for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
1093     {
1094         if (!id)
1095         {
1096             *v = FcValueCanonicalize(&FcValueListPtrU(l)->value);
1097             return FcResultMatch;
1098         }
1099         id--;
1100     }
1101     return FcResultNoId;
1102 }
1103
1104 FcResult
1105 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
1106 {
1107     FcValue     v;
1108     FcResult    r;
1109
1110     r = FcPatternGet (p, object, id, &v);
1111     if (r != FcResultMatch)
1112         return r;
1113     switch (v.type) {
1114     case FcTypeDouble:
1115         *i = (int) v.u.d;
1116         break;
1117     case FcTypeInteger:
1118         *i = v.u.i;
1119         break;
1120     default:
1121         return FcResultTypeMismatch;
1122     }
1123     return FcResultMatch;
1124 }
1125
1126 FcResult
1127 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
1128 {
1129     FcValue     v;
1130     FcResult    r;
1131
1132     r = FcPatternGet (p, object, id, &v);
1133     if (r != FcResultMatch)
1134         return r;
1135     switch (v.type) {
1136     case FcTypeDouble:
1137         *d = v.u.d;
1138         break;
1139     case FcTypeInteger:
1140         *d = (double) v.u.i;
1141         break;
1142     default:
1143         return FcResultTypeMismatch;
1144     }
1145     return FcResultMatch;
1146 }
1147
1148 FcResult
1149 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1150 {
1151     FcValue     v;
1152     FcResult    r;
1153
1154     r = FcPatternGet (p, object, id, &v);
1155     if (r != FcResultMatch)
1156         return r;
1157     if (v.type != FcTypeString)
1158         return FcResultTypeMismatch;
1159
1160     if (FcObjectToPtr(object) == FcObjectToPtr(FC_FILE))
1161     {
1162         const char *fn, *fpath;
1163         FcChar8 *fname;
1164         int size;
1165
1166         fn = FcPatternFindFullFname(p);
1167         if (fn)
1168         {
1169             *s = (FcChar8 *) fn;
1170             return FcResultMatch;
1171         }
1172
1173         if (!p->bank)
1174         {
1175             *s = (FcChar8 *) v.u.s;
1176             return FcResultMatch;
1177         }
1178
1179         fpath = FcCacheFindBankDir (p->bank);
1180         size = strlen((char*)fpath) + 1 + strlen ((char *)v.u.s) + 1;
1181         fname = malloc (size);
1182         if (!fname)
1183             return FcResultOutOfMemory;
1184
1185         FcMemAlloc (FC_MEM_STRING, size);
1186         strcpy ((char *)fname, (char *)fpath);
1187         strcat ((char *)fname, "/");
1188         strcat ((char *)fname, (char *)v.u.s);
1189         
1190         FcPatternAddFullFname (p, (const char *)fname);
1191         *s = (FcChar8 *)fname;
1192         return FcResultMatch;
1193     }
1194
1195     *s = (FcChar8 *) v.u.s;
1196     return FcResultMatch;
1197 }
1198
1199 FcResult
1200 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1201 {
1202     FcValue     v;
1203     FcResult    r;
1204
1205     r = FcPatternGet (p, object, id, &v);
1206     if (r != FcResultMatch)
1207         return r;
1208     if (v.type != FcTypeMatrix)
1209         return FcResultTypeMismatch;
1210     *m = (FcMatrix *)v.u.m;
1211     return FcResultMatch;
1212 }
1213
1214
1215 FcResult
1216 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1217 {
1218     FcValue     v;
1219     FcResult    r;
1220
1221     r = FcPatternGet (p, object, id, &v);
1222     if (r != FcResultMatch)
1223         return r;
1224     if (v.type != FcTypeBool)
1225         return FcResultTypeMismatch;
1226     *b = v.u.b;
1227     return FcResultMatch;
1228 }
1229
1230 FcResult
1231 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1232 {
1233     FcValue     v;
1234     FcResult    r;
1235
1236     r = FcPatternGet (p, object, id, &v);
1237     if (r != FcResultMatch)
1238         return r;
1239     if (v.type != FcTypeCharSet)
1240         return FcResultTypeMismatch;
1241     *c = (FcCharSet *)v.u.c;
1242     return FcResultMatch;
1243 }
1244
1245 FcResult
1246 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1247 {
1248     FcValue     v;
1249     FcResult    r;
1250
1251     r = FcPatternGet (p, object, id, &v);
1252     if (r != FcResultMatch)
1253         return r;
1254     if (v.type != FcTypeFTFace)
1255         return FcResultTypeMismatch;
1256     *f = (FT_Face) v.u.f;
1257     return FcResultMatch;
1258 }
1259
1260 FcResult
1261 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1262 {
1263     FcValue     v;
1264     FcResult    r;
1265
1266     r = FcPatternGet (p, object, id, &v);
1267     if (r != FcResultMatch)
1268         return r;
1269     if (v.type != FcTypeLangSet)
1270         return FcResultTypeMismatch;
1271     *ls = (FcLangSet *)v.u.l;
1272     return FcResultMatch;
1273 }
1274
1275 FcPattern *
1276 FcPatternDuplicate (const FcPattern *orig)
1277 {
1278     FcPattern       *new;
1279     FcPatternElt    *e;
1280     int             i;
1281     FcValueListPtr  l;
1282
1283     new = FcPatternCreate ();
1284     if (!new)
1285         goto bail0;
1286
1287     e = FcPatternEltU(orig->elts);
1288
1289     for (i = 0; i < orig->num; i++)
1290     {
1291         for (l = (e + i)->values; 
1292              FcValueListPtrU(l); 
1293              l = FcValueListPtrU(l)->next)
1294             if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object), 
1295                                FcValueCanonicalize(&FcValueListPtrU(l)->value),
1296                                FcTrue))
1297                 goto bail1;
1298     }
1299     FcPatternTransferFullFname (new, orig);
1300
1301     return new;
1302
1303 bail1:
1304     FcPatternDestroy (new);
1305 bail0:
1306     return 0;
1307 }
1308
1309 void
1310 FcPatternReference (FcPattern *p)
1311 {
1312     if (p->ref != FC_REF_CONSTANT)
1313         p->ref++;
1314 }
1315
1316 FcPattern *
1317 FcPatternVaBuild (FcPattern *orig, va_list va)
1318 {
1319     FcPattern   *ret;
1320     
1321     FcPatternVapBuild (ret, orig, va);
1322     return ret;
1323 }
1324
1325 FcPattern *
1326 FcPatternBuild (FcPattern *orig, ...)
1327 {
1328     va_list     va;
1329     
1330     va_start (va, orig);
1331     FcPatternVapBuild (orig, orig, va);
1332     va_end (va);
1333     return orig;
1334 }
1335
1336 /*
1337  * Add all of the elements in 's' to 'p'
1338  */
1339 FcBool
1340 FcPatternAppend (FcPattern *p, FcPattern *s)
1341 {
1342     int             i;
1343     FcPatternElt    *e;
1344     FcValueListPtr  v;
1345     
1346     for (i = 0; i < s->num; i++)
1347     {
1348         e = FcPatternEltU(s->elts)+i;
1349         for (v = e->values; FcValueListPtrU(v); 
1350              v = FcValueListPtrU(v)->next)
1351         {
1352             if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1353                                           FcValueCanonicalize(&FcValueListPtrU(v)->value), 
1354                                           FcValueListPtrU(v)->binding, FcTrue))
1355                 return FcFalse;
1356         }
1357     }
1358     return FcTrue;
1359 }
1360
1361 #define OBJECT_HASH_SIZE    31
1362 static struct objectBucket {
1363     struct objectBucket *next;
1364     FcChar32            hash;
1365 } *FcObjectBuckets[OBJECT_HASH_SIZE];
1366
1367 const FcChar8 *
1368 FcStrStaticName (const FcChar8 *name)
1369 {
1370     FcChar32            hash = FcStringHash (name);
1371     struct objectBucket **p;
1372     struct objectBucket *b;
1373     int                 size;
1374
1375     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1376         if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1377             return (FcChar8 *) (b + 1);
1378     size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
1379     b = malloc (size + sizeof (int));
1380     /* workaround glibc bug which reads strlen in groups of 4 */
1381     FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
1382     if (!b)
1383         return NULL;
1384     b->next = 0;
1385     b->hash = hash;
1386     strcpy ((char *) (b + 1), (char *)name);
1387     *p = b;
1388     return (FcChar8 *) (b + 1);
1389 }
1390
1391 static void
1392 FcStrStaticNameFini (void)
1393 {
1394     int i, size;
1395     struct objectBucket *b, *next;
1396     char *name;
1397
1398     for (i = 0; i < OBJECT_HASH_SIZE; i++)
1399     {
1400         for (b = FcObjectBuckets[i]; b; b = next)
1401         {
1402             next = b->next;
1403             name = (char *) (b + 1);
1404             size = sizeof (struct objectBucket) + strlen (name) + 1;
1405             FcMemFree (FC_MEM_STATICSTR, size);
1406             free (b);
1407         }
1408         FcObjectBuckets[i] = 0;
1409     }
1410 }
1411
1412 void
1413 FcPatternFini (void)
1414 {
1415     FcPatternBaseThawAll ();
1416     FcValueListThawAll ();
1417     FcStrStaticNameFini ();
1418     FcObjectStaticNameFini ();
1419 }
1420
1421 FcPatternElt *
1422 FcPatternEltU (FcPatternEltPtr pei)
1423 {
1424     if (pei.bank == FC_BANK_DYNAMIC)
1425         return pei.u.dyn;
1426
1427     return &fcpatternelts[FcCacheBankToIndex(pei.bank)][pei.u.stat];
1428 }
1429
1430 static FcPatternEltPtr
1431 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1432 {
1433     FcPatternEltPtr new;
1434     new.bank = FC_BANK_DYNAMIC;
1435     new.u.dyn = e;
1436     return new;
1437 }
1438
1439 static FcPatternEltPtr
1440 FcPatternEltPtrCreateStatic (int bank, int i)
1441 {
1442     FcPatternEltPtr new;
1443     new.bank = bank;
1444     new.u.stat = i;
1445     return new;
1446 }
1447
1448 static void
1449 FcStrNewBank (void);
1450 static int
1451 FcStrNeededBytes (const FcChar8 * s);
1452 static int
1453 FcStrNeededBytesAlign (void);
1454 static void *
1455 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
1456 static const FcChar8 *
1457 FcStrSerialize (int bank, const FcChar8 * s);
1458 static void *
1459 FcStrUnserialize (FcCache metadata, void *block_ptr);
1460
1461 static void
1462 FcValueListNewBank (void);
1463 static int
1464 FcValueListNeededBytes (FcValueList * vl);
1465 static int
1466 FcValueListNeededBytesAlign (void);
1467 static void *
1468 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
1469 static FcValueListPtr
1470 FcValueListSerialize(int bank, FcValueList *pi);
1471 static void *
1472 FcValueListUnserialize (FcCache metadata, void *block_ptr);
1473
1474
1475 void
1476 FcPatternNewBank (void)
1477 {
1478     fcpattern_count = 0;
1479     fcpatternelt_count = 0;
1480
1481     FcStrNewBank();
1482     FcValueListNewBank();
1483 }
1484
1485 int
1486 FcPatternNeededBytes (FcPattern * p)
1487 {
1488     int i, cum = 0, c;
1489
1490     fcpattern_count++;
1491     fcpatternelt_count += p->num;
1492
1493     for (i = 0; i < p->num; i++)
1494     {
1495         c = FcValueListNeededBytes (FcValueListPtrU
1496                                     (((FcPatternEltU(p->elts)+i)->values)));
1497         if (c < 0)
1498             return c;
1499         cum += c;
1500     }
1501
1502     return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
1503 }
1504
1505 int
1506 FcPatternNeededBytesAlign (void)
1507 {
1508     return __alignof__ (FcPattern) + __alignof__ (FcPatternElt) + 
1509         FcValueListNeededBytesAlign ();
1510 }
1511
1512 static FcBool
1513 FcPatternEnsureBank (int bi)
1514 {
1515     FcPattern **pp;
1516     FcPatternElt **ep;
1517     int i;
1518
1519     if (!fcpatterns || fcpattern_bank_count <= bi)
1520     {
1521         int new_count = bi + 4;
1522         pp = realloc (fcpatterns, sizeof (FcPattern *) * new_count);
1523         if (!pp)
1524             return 0;
1525
1526         FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
1527         fcpatterns = pp;
1528
1529         ep = realloc (fcpatternelts, sizeof (FcPatternElt *) * new_count);
1530         if (!ep)
1531             return 0;
1532
1533         FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
1534         fcpatternelts = ep;
1535
1536         for (i = fcpattern_bank_count; i < new_count; i++)
1537         {
1538             fcpatterns[i] = 0;
1539             fcpatternelts[i] = 0;
1540         }
1541
1542         fcpattern_bank_count = new_count;
1543     }
1544
1545     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
1546     return FcTrue;
1547 }
1548
1549 void *
1550 FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
1551 {
1552     int bi = FcCacheBankToIndex(metadata->bank);
1553
1554     if (!FcPatternEnsureBank(bi))
1555         return 0;
1556
1557     fcpattern_ptr = 0;
1558     block_ptr = ALIGN(block_ptr, FcPattern);
1559     fcpatterns[bi] = (FcPattern *)block_ptr;
1560     block_ptr = (void *)((char *)block_ptr + 
1561                          (sizeof (FcPattern) * fcpattern_count));
1562     
1563     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1564     fcpatternelt_ptr = 0;
1565     block_ptr = ALIGN(block_ptr, FcPatternElt);
1566     fcpatternelts[bi] = (FcPatternElt *)block_ptr;
1567     block_ptr = (void *)((char *)block_ptr + 
1568                          (sizeof (FcPatternElt) * fcpatternelt_count));
1569
1570     metadata->pattern_count = fcpattern_count;
1571     metadata->patternelt_count = fcpatternelt_count;
1572
1573     block_ptr = FcStrDistributeBytes (metadata, block_ptr);
1574     block_ptr = FcValueListDistributeBytes (metadata, block_ptr);
1575     return block_ptr;
1576 }
1577
1578 FcPattern *
1579 FcPatternSerialize (int bank, FcPattern *old)
1580 {
1581     FcPattern *p;
1582     FcPatternElt *e, *nep;
1583     FcValueList * nv;
1584     FcValueListPtr v, nv_head, nvp;
1585     int i, elts, bi = FcCacheBankToIndex(bank);
1586
1587     p = &fcpatterns[bi][fcpattern_ptr++];
1588     p->bank = bank;
1589     elts = fcpatternelt_ptr;
1590     nep = &fcpatternelts[bi][elts];
1591     if (!nep)
1592         return FcFalse;
1593
1594     fcpatternelt_ptr += old->num;
1595
1596     for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++) 
1597     {
1598         v = e->values;
1599         nvp = nv_head = FcValueListSerialize(bank, FcValueListPtrU(v));
1600         if (!FcValueListPtrU(nv_head))
1601             return 0;
1602         nv = FcValueListPtrU(nvp);
1603         
1604         for (;
1605              FcValueListPtrU(v);
1606              v = FcValueListPtrU(v)->next, 
1607                  nv = FcValueListPtrU(nv->next))
1608         {
1609             
1610             if (FcValueListPtrU(FcValueListPtrU(v)->next))
1611             {
1612                 nvp = FcValueListSerialize
1613                     (bank, FcValueListPtrU(FcValueListPtrU(v)->next));
1614                 nv->next = nvp;
1615             }
1616         }
1617         
1618         nep[i].values = nv_head;
1619         nep[i].object = e->object;
1620     }
1621
1622     p->elts = old->elts;
1623     p->elts = FcPatternEltPtrCreateStatic(bank, elts);
1624     p->size = old->num;
1625     p->num = old->num;
1626     p->ref = FC_REF_CONSTANT;
1627     return p;
1628 }
1629
1630 void *
1631 FcPatternUnserialize (FcCache metadata, void *block_ptr)
1632 {
1633     int bi = FcCacheBankToIndex(metadata.bank);
1634     if (!FcPatternEnsureBank(bi))
1635         return FcFalse;
1636
1637     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata.pattern_count);
1638     block_ptr = ALIGN(block_ptr, FcPattern);
1639     fcpatterns[bi] = (FcPattern *)block_ptr;
1640     block_ptr = (void *)((char *)block_ptr + 
1641                          (sizeof (FcPattern) * metadata.pattern_count));
1642     
1643     FcMemAlloc (FC_MEM_PATELT, 
1644                 sizeof (FcPatternElt) * metadata.patternelt_count);
1645     block_ptr = ALIGN(block_ptr, FcPatternElt);
1646     fcpatternelts[bi] = (FcPatternElt *)block_ptr;
1647     block_ptr = (void *)((char *)block_ptr + 
1648                          (sizeof (FcPatternElt) * metadata.patternelt_count));
1649         
1650     block_ptr = FcStrUnserialize (metadata, block_ptr);
1651     block_ptr = FcValueListUnserialize (metadata, block_ptr);
1652
1653     return block_ptr;
1654 }
1655
1656 static void
1657 FcValueListNewBank (void)
1658 {
1659     fcvaluelist_count = 0;
1660
1661     FcCharSetNewBank();
1662     FcLangSetNewBank();
1663 }
1664
1665 static int
1666 FcValueListNeededBytes (FcValueList *p)
1667 {
1668     FcValueList *vl;
1669     int cum = 0;
1670
1671     for (vl = p;
1672          vl; 
1673          vl = FcValueListPtrU(vl->next))
1674     {
1675         FcValue v = FcValueCanonicalize(&vl->value); // unserialize just in case
1676
1677         switch (v.type)
1678         {
1679         case FcTypeCharSet:
1680             cum += FcCharSetNeededBytes(v.u.c);
1681             break;
1682         case FcTypeLangSet:
1683             cum += FcLangSetNeededBytes(v.u.l);
1684             break;
1685         case FcTypeString:
1686             cum += FcStrNeededBytes(v.u.s);
1687         default:
1688             break;
1689         }
1690         fcvaluelist_count++;
1691         cum += sizeof (FcValueList);
1692     }
1693     
1694     return cum;
1695 }
1696
1697 static int
1698 FcValueListNeededBytesAlign (void)
1699 {
1700     return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() + 
1701         FcStrNeededBytesAlign() + __alignof__ (FcValueList);
1702 }
1703
1704 static FcBool
1705 FcValueListEnsureBank (int bi)
1706 {
1707     FcValueList **pvl;
1708
1709     if (!fcvaluelists || fcvaluelist_bank_count <= bi)
1710     {
1711         int new_count = bi + 2, i;
1712
1713         pvl = realloc (fcvaluelists, sizeof (FcValueList *) * new_count);
1714         if (!pvl)
1715             return FcFalse;
1716
1717         FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
1718
1719         fcvaluelists = pvl;
1720         for (i = fcvaluelist_bank_count; i < new_count; i++)
1721             fcvaluelists[i] = 0;
1722
1723         fcvaluelist_bank_count = new_count;
1724     }
1725     return FcTrue;
1726 }
1727
1728 static void *
1729 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
1730 {
1731     int bi = FcCacheBankToIndex(metadata->bank);
1732
1733     if (!FcValueListEnsureBank(bi))
1734         return 0;
1735
1736     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1737     fcvaluelist_ptr = 0;
1738     block_ptr = ALIGN(block_ptr, FcValueList);
1739     fcvaluelists[bi] = (FcValueList *)block_ptr;
1740     block_ptr = (void *)((char *)block_ptr + 
1741                          (sizeof (FcValueList) * fcvaluelist_count));
1742     metadata->valuelist_count = fcvaluelist_count;
1743
1744     block_ptr = FcCharSetDistributeBytes(metadata, block_ptr);
1745     block_ptr = FcLangSetDistributeBytes(metadata, block_ptr);
1746
1747     return block_ptr;
1748 }
1749
1750 static FcValueListPtr
1751 FcValueListSerialize(int bank, FcValueList *pi)
1752 {
1753     FcValueListPtr new; 
1754     FcValue * v;
1755     int bi = FcCacheBankToIndex(bank);
1756
1757     if (!pi)
1758     {
1759         new.bank = FC_BANK_DYNAMIC;
1760         new.u.dyn = 0;
1761         return new;
1762     }
1763
1764     fcvaluelists[bi][fcvaluelist_ptr] = *pi;
1765     new.bank = bank;
1766     new.u.stat = fcvaluelist_ptr++;
1767     fcvaluelists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
1768     v = &fcvaluelists[bi][new.u.stat].value;
1769     switch (v->type)
1770     {
1771     case FcTypeString:
1772         if (v->u.s)
1773         {
1774             const FcChar8 * s = FcStrSerialize(bank, v->u.s);
1775             if (!s)
1776                 return FcValueListPtrCreateDynamic(pi);
1777             v->u.s_off = s - (const FcChar8 *)v;
1778             v->type |= FC_STORAGE_STATIC;
1779         }
1780         break;
1781     case FcTypeMatrix:
1782         break;
1783     case FcTypeCharSet:
1784         if (v->u.c)
1785         {
1786             FcCharSet * c = FcCharSetSerialize(bank, (FcCharSet *)v->u.c);
1787             if (!c)
1788                 return FcValueListPtrCreateDynamic(pi);
1789             v->u.c_off = (char *)c - (char *)v;
1790             v->type |= FC_STORAGE_STATIC;
1791         }
1792         break;
1793     case FcTypeLangSet:
1794         if (v->u.l)
1795         {
1796             FcLangSet * l = FcLangSetSerialize(bank, (FcLangSet *)v->u.l);
1797             if (!l)
1798                 return FcValueListPtrCreateDynamic(pi);
1799             v->u.l_off = (char *)l - (char *)v;
1800             v->type |= FC_STORAGE_STATIC;
1801         }
1802         break;
1803     default:
1804         break;
1805     }
1806     return new;
1807 }
1808
1809 static void *
1810 FcValueListUnserialize (FcCache metadata, void *block_ptr)
1811 {
1812     int bi = FcCacheBankToIndex(metadata.bank);
1813
1814     if (!FcValueListEnsureBank(bi))
1815         return 0;
1816
1817     FcMemAlloc (FC_MEM_VALLIST, 
1818                 sizeof (FcValueList) * metadata.valuelist_count);
1819     block_ptr = ALIGN(block_ptr, FcValueList);
1820     fcvaluelists[bi] = (FcValueList *)block_ptr;
1821     block_ptr = (void *)((char *)block_ptr + 
1822                          (sizeof (FcValueList) * metadata.valuelist_count));
1823
1824     block_ptr = FcCharSetUnserialize(metadata, block_ptr);
1825     block_ptr = FcLangSetUnserialize(metadata, block_ptr);
1826
1827     return block_ptr;
1828 }
1829
1830 FcValueList * 
1831 FcValueListPtrU (FcValueListPtr pi)
1832 {
1833     if (pi.bank == FC_BANK_DYNAMIC)
1834         return pi.u.dyn;
1835
1836     return &fcvaluelists[FcCacheBankToIndex(pi.bank)][pi.u.stat];
1837 }
1838
1839 FcValueListPtr
1840 FcValueListPtrCreateDynamic(FcValueList * p)
1841 {
1842     FcValueListPtr r; 
1843
1844     r.bank = FC_BANK_DYNAMIC; 
1845     r.u.dyn = p;
1846     return r;
1847 }
1848
1849 static FcChar8 ** static_strs;
1850 static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
1851
1852 static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
1853
1854 static void
1855 FcStrNewBank (void)
1856 {
1857     int i, size;
1858     struct objectBucket *b, *next;
1859     char *name;
1860
1861     for (i = 0; i < OBJECT_HASH_SIZE; i++)
1862     {
1863         for (b = FcStrBuckets[i]; b; b = next)
1864         {
1865             next = b->next;
1866             name = (char *) (b + 1);
1867             size = sizeof (struct objectBucket) + strlen (name) + 1;
1868             FcMemFree (FC_MEM_STATICSTR, size);
1869             free (b);
1870         }
1871         FcStrBuckets[i] = 0;
1872     }
1873
1874     fcstr_count = 0;
1875 }
1876
1877 static int
1878 FcStrNeededBytes (const FcChar8 * s)
1879 {
1880     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
1881     struct objectBucket **p;
1882     struct objectBucket *b;
1883     int                 size;
1884
1885     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1886         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1887             return 0;
1888     size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
1889     b = malloc (size);
1890     FcMemAlloc (FC_MEM_STATICSTR, size);
1891     if (!b)
1892         return -1;
1893     b->next = 0;
1894     b->hash = hash;
1895     strcpy ((char *) (b + 1), (char *)s);
1896
1897     /* Yes, the following line is convoluted.  However, it is
1898      * incorrect to replace the with a memset, because the C
1899      * specification doesn't guarantee that the null pointer is
1900      * the same as the zero bit pattern. */
1901     *(char **)((char *) (b + 1) + strlen((char *)s) + 1) = 0;
1902     *p = b;
1903
1904     fcstr_count += strlen((char *)s) + 1;
1905     return strlen((char *)s) + 1;
1906 }
1907
1908 static int
1909 FcStrNeededBytesAlign (void)
1910 {
1911     return __alignof__ (char);
1912 }
1913
1914 static FcBool
1915 FcStrEnsureBank (int bi)
1916 {
1917     FcChar8 ** ss;
1918
1919     if (!static_strs || static_str_bank_count <= bi)
1920     {
1921         int new_count = bi + 4, i;
1922         ss = realloc (static_strs, sizeof (const char *) * new_count);
1923         if (!ss)
1924             return FcFalse;
1925
1926         FcMemAlloc (FC_MEM_STRING, sizeof (const char *) * (new_count-static_str_bank_count));
1927         static_strs = ss;
1928
1929         for (i = static_str_bank_count; i < new_count; i++)
1930             static_strs[i] = 0;
1931         static_str_bank_count = new_count;
1932     }
1933     return FcTrue;
1934 }
1935
1936 static void *
1937 FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
1938 {
1939     int bi = FcCacheBankToIndex(metadata->bank);
1940     if (!FcStrEnsureBank(bi)) 
1941         return 0;
1942
1943     FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
1944     block_ptr = ALIGN (block_ptr, FcChar8);
1945     static_strs[bi] = (FcChar8 *)block_ptr;
1946     block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
1947     metadata->str_count = fcstr_count;
1948     fcstr_ptr = 0;
1949
1950     return block_ptr;
1951 }
1952
1953 static const FcChar8 *
1954 FcStrSerialize (int bank, const FcChar8 * s)
1955 {
1956     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
1957     struct objectBucket **p;
1958     struct objectBucket *b;
1959     int bi = FcCacheBankToIndex(bank);
1960
1961     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1962         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1963         {
1964             FcChar8 * t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
1965             if (!t)
1966             {
1967                 strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
1968                 *(FcChar8 **)((FcChar8 *) (b + 1) + strlen((char *)s) + 1) = (static_strs[bi] + fcstr_ptr);
1969                 fcstr_ptr += strlen((char *)s) + 1;
1970                 t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
1971             }
1972             return t;
1973         }
1974     return 0;
1975 }
1976
1977 static void *
1978 FcStrUnserialize (FcCache metadata, void *block_ptr)
1979 {
1980     int bi = FcCacheBankToIndex(metadata.bank);
1981     if (!FcStrEnsureBank(bi))
1982         return 0;
1983
1984     FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata.str_count);
1985     block_ptr = ALIGN (block_ptr, FcChar8);
1986     static_strs[bi] = (FcChar8 *)block_ptr;
1987     block_ptr = (void *)((char *)block_ptr + 
1988                          (sizeof (char) * metadata.str_count));
1989
1990     return block_ptr;
1991 }
1992
1993 /* we don't store these in the FcPattern itself because
1994  * we don't want to serialize the directory names */
1995
1996 /* I suppose this should be cleaned, too... */
1997 typedef struct _FcPatternDirMapping {
1998     const FcPattern     *p;
1999     const char *fname;
2000 } FcPatternDirMapping;
2001
2002 #define PATTERNDIR_HASH_SIZE    31
2003 static struct patternDirBucket {
2004     struct patternDirBucket     *next;
2005     FcPatternDirMapping         m;
2006 } FcPatternDirBuckets[PATTERNDIR_HASH_SIZE];
2007
2008 void
2009 FcPatternAddFullFname (const FcPattern *p, const char *fname)
2010 {
2011     struct patternDirBucket     *pb;
2012
2013     /* N.B. FcPatternHash fails, since it's contents-based, not
2014      * address-based, and we're in the process of mutating the FcPattern. */
2015     for (pb = &FcPatternDirBuckets
2016              [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
2017          pb->m.p != p && pb->next; 
2018          pb = pb->next)
2019         ;
2020
2021     if (pb->m.p == p)
2022     {
2023         pb->m.fname = fname;
2024         return;
2025     }
2026
2027     pb->next = malloc (sizeof (struct patternDirBucket));
2028     if (!pb->next)
2029         return;
2030     FcMemAlloc (FC_MEM_CACHE, sizeof (struct patternDirBucket));
2031
2032     pb->next->next = 0;
2033     pb->next->m.p = p;
2034     pb->next->m.fname = fname;
2035 }
2036
2037 static const char *
2038 FcPatternFindFullFname (const FcPattern *p)
2039 {
2040     struct patternDirBucket     *pb;
2041
2042     for (pb = &FcPatternDirBuckets
2043              [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE]; 
2044          pb; pb = pb->next)
2045         if (pb->m.p == p)
2046             return pb->m.fname;
2047
2048     return 0;
2049 }
2050
2051 void
2052 FcPatternTransferFullFname (const FcPattern *new, const FcPattern *orig)
2053 {
2054     FcChar8 * s;
2055     FcPatternGetString (orig, FC_FILE, 0, &s);
2056     FcPatternAddFullFname (new, 
2057                            (char *)FcStrCopy 
2058                            ((FcChar8 *)FcPatternFindFullFname(orig)));
2059 }