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