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