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