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