]> git.wh0rd.org - fontconfig.git/blame - src/fcpat.c
Convert ObjectPtr from a fat structure to a simple index into an id table;
[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
34cd0514
CW
654void
655FcPatternThawAll (void)
656{
657 FcPatternBaseThawAll ();
658 FcValueListThawAll ();
659}
660
e9be9cd1
KP
661static int
662FcPatternPosition (const FcPattern *p, const char *object)
24330d27 663{
e9be9cd1 664 int low, high, mid, c;
cd2ec1a9 665 FcObjectPtr obj;
0ab36ca8 666
cd2ec1a9 667 obj = FcObjectStaticName(object);
0ab36ca8 668 low = 0;
e9be9cd1
KP
669 high = p->num - 1;
670 c = 1;
671 mid = 0;
672 while (low <= high)
24330d27 673 {
e9be9cd1 674 mid = (low + high) >> 1;
cd2ec1a9 675 c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
e9be9cd1
KP
676 if (c == 0)
677 return mid;
678 if (c < 0)
679 low = mid + 1;
0ab36ca8 680 else
e9be9cd1 681 high = mid - 1;
24330d27 682 }
e9be9cd1
KP
683 if (c < 0)
684 mid++;
685 return -(mid + 1);
686}
24330d27 687
e9be9cd1
KP
688FcPatternElt *
689FcPatternFindElt (const FcPattern *p, const char *object)
690{
691 int i = FcPatternPosition (p, object);
692 if (i < 0)
0ab36ca8 693 return 0;
cd2ec1a9 694 return FcPatternEltU(p->elts)+i;
e9be9cd1 695}
24330d27 696
e9be9cd1
KP
697FcPatternElt *
698FcPatternInsertElt (FcPattern *p, const char *object)
699{
700 int i;
701 FcPatternElt *e;
702
703 i = FcPatternPosition (p, object);
704 if (i < 0)
24330d27 705 {
e9be9cd1
KP
706 i = -i - 1;
707
cd2ec1a9 708 /* reallocate array */
e9be9cd1 709 if (p->num + 1 >= p->size)
24330d27 710 {
e9be9cd1 711 int s = p->size + 16;
cd2ec1a9
PL
712 if (FcPatternEltU(p->elts))
713 {
714 FcPatternElt *e0 = FcPatternEltU(p->elts);
715 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
716 if (!e) /* maybe it was mmapped */
717 {
718 e = malloc(s * sizeof (FcPatternElt));
719 if (e)
720 memcpy(e, e0, p->num * sizeof (FcPatternElt));
721 }
722 }
e9be9cd1
KP
723 else
724 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
725 if (!e)
726 return FcFalse;
cd2ec1a9 727 p->elts = FcPatternEltPtrCreateDynamic(e);
e9be9cd1
KP
728 if (p->size)
729 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
730 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
731 while (p->size < s)
732 {
0fa680f0 733 (FcPatternEltU(p->elts)+p->size)->object = 0;
cd2ec1a9
PL
734 (FcPatternEltU(p->elts)+p->size)->values =
735 FcValueListPtrCreateDynamic(0);
e9be9cd1
KP
736 p->size++;
737 }
24330d27 738 }
e9be9cd1
KP
739
740 /* move elts up */
cd2ec1a9
PL
741 memmove (FcPatternEltU(p->elts) + i + 1,
742 FcPatternEltU(p->elts) + i,
e9be9cd1
KP
743 sizeof (FcPatternElt) *
744 (p->num - i));
745
746 /* bump count */
747 p->num++;
748
cd2ec1a9
PL
749 (FcPatternEltU(p->elts)+i)->object = FcObjectStaticName (object);
750 (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
24330d27
KP
751 }
752
cd2ec1a9 753 return FcPatternEltU(p->elts)+i;
24330d27
KP
754}
755
0ab36ca8 756FcBool
e9be9cd1 757FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
0ab36ca8
KP
758{
759 int i;
760
bd724c85
KP
761 if (pa == pb)
762 return FcTrue;
763
0ab36ca8
KP
764 if (pa->num != pb->num)
765 return FcFalse;
766 for (i = 0; i < pa->num; i++)
767 {
cd2ec1a9
PL
768 if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
769 (FcPatternEltU(pb->elts)+i)->object) != 0)
0ab36ca8 770 return FcFalse;
cd2ec1a9
PL
771 if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values,
772 (FcPatternEltU(pb->elts)+i)->values))
0ab36ca8
KP
773 return FcFalse;
774 }
775 return FcTrue;
776}
777
d0f07b8d
KP
778FcChar32
779FcPatternHash (const FcPattern *p)
780{
781 int i;
782 FcChar32 h = 0;
783
784 for (i = 0; i < p->num; i++)
785 {
786 h = (((h << 1) | (h >> 31)) ^
cd2ec1a9
PL
787 FcStringHash ((const FcChar8 *) FcObjectPtrU(((FcPatternEltU(p->elts)+i)->object))) ^
788 FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
d0f07b8d
KP
789 }
790 return h;
791}
792
e9be9cd1 793FcBool
cd2ec1a9 794FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
e9be9cd1
KP
795{
796 FcPatternElt *ea, *eb;
797 int i;
798
799 for (i = 0; i < os->nobject; i++)
800 {
cd2ec1a9
PL
801 ea = FcPatternFindElt (pai, FcObjectPtrU(os->objects[i]));
802 eb = FcPatternFindElt (pbi, FcObjectPtrU(os->objects[i]));
e9be9cd1
KP
803 if (ea)
804 {
805 if (!eb)
806 return FcFalse;
807 if (!FcValueListEqual (ea->values, eb->values))
808 return FcFalse;
809 }
810 else
811 {
812 if (eb)
813 return FcFalse;
814 }
815 }
816 return FcTrue;
817}
818
24330d27 819FcBool
82f4243f
KP
820FcPatternAddWithBinding (FcPattern *p,
821 const char *object,
822 FcValue value,
823 FcValueBinding binding,
824 FcBool append)
24330d27
KP
825{
826 FcPatternElt *e;
cd2ec1a9
PL
827 FcValueListPtr new, *prev;
828 FcValueList * newp;
24330d27 829
d8d73958
KP
830 if (p->ref == FC_REF_CONSTANT)
831 goto bail0;
832
cd2ec1a9
PL
833 newp = malloc (sizeof (FcValueList));
834 if (!newp)
24330d27
KP
835 goto bail0;
836
cd2ec1a9
PL
837 memset(newp, 0, sizeof (FcValueList));
838 new = FcValueListPtrCreateDynamic(newp);
24330d27
KP
839 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
840 /* dup string */
841 value = FcValueSave (value);
842 if (value.type == FcTypeVoid)
843 goto bail1;
844
cd2ec1a9
PL
845 FcValueListPtrU(new)->value = value;
846 FcValueListPtrU(new)->binding = binding;
847 FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
24330d27 848
e9be9cd1 849 e = FcPatternInsertElt (p, object);
24330d27
KP
850 if (!e)
851 goto bail2;
852
853 if (append)
854 {
cd2ec1a9
PL
855 for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
856 ;
24330d27
KP
857 *prev = new;
858 }
859 else
860 {
cd2ec1a9 861 FcValueListPtrU(new)->next = e->values;
24330d27
KP
862 e->values = new;
863 }
864
865 return FcTrue;
866
867bail2:
868 switch (value.type) {
869 case FcTypeString:
cd2ec1a9 870 FcStrFree ((FcChar8 *) FcObjectPtrU(value.u.si));
24330d27
KP
871 break;
872 case FcTypeMatrix:
cd2ec1a9 873 FcMatrixFree (FcMatrixPtrU(value.u.mi));
24330d27
KP
874 break;
875 case FcTypeCharSet:
cd2ec1a9 876 FcCharSetDestroy (FcCharSetPtrU(value.u.ci));
24330d27 877 break;
d8d73958 878 case FcTypeLangSet:
cd2ec1a9 879 FcLangSetDestroy (FcLangSetPtrU(value.u.li));
d8d73958 880 break;
24330d27
KP
881 default:
882 break;
883 }
884bail1:
885 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
cd2ec1a9 886 free (FcValueListPtrU(new));
24330d27
KP
887bail0:
888 return FcFalse;
889}
890
82f4243f
KP
891FcBool
892FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
893{
894 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
895}
896
897FcBool
898FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
899{
900 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
901}
902
24330d27
KP
903FcBool
904FcPatternDel (FcPattern *p, const char *object)
905{
906 FcPatternElt *e;
24330d27 907
e9be9cd1 908 e = FcPatternFindElt (p, object);
24330d27
KP
909 if (!e)
910 return FcFalse;
911
24330d27
KP
912 /* destroy value */
913 FcValueListDestroy (e->values);
914
915 /* shuffle existing ones down */
cd2ec1a9
PL
916 memmove (e, e+1,
917 (FcPatternEltU(p->elts) + p->num - (e + 1)) *
918 sizeof (FcPatternElt));
24330d27 919 p->num--;
0fa680f0 920 (FcPatternEltU(p->elts)+p->num)->object = 0;
cd2ec1a9 921 (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
24330d27
KP
922 return FcTrue;
923}
924
4f27c1c0
KP
925FcBool
926FcPatternRemove (FcPattern *p, const char *object, int id)
927{
cd2ec1a9
PL
928 FcPatternElt *e;
929 FcValueListPtr *prev, l;
4f27c1c0
KP
930
931 e = FcPatternFindElt (p, object);
932 if (!e)
933 return FcFalse;
cd2ec1a9
PL
934 for (prev = &e->values;
935 FcValueListPtrU(l = *prev);
936 prev = &FcValueListPtrU(l)->next)
4f27c1c0
KP
937 {
938 if (!id)
939 {
cd2ec1a9
PL
940 *prev = FcValueListPtrU(l)->next;
941 FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
4f27c1c0 942 FcValueListDestroy (l);
cd2ec1a9 943 if (!FcValueListPtrU(e->values))
4f27c1c0
KP
944 FcPatternDel (p, object);
945 return FcTrue;
946 }
947 id--;
948 }
949 return FcFalse;
950}
951
24330d27
KP
952FcBool
953FcPatternAddInteger (FcPattern *p, const char *object, int i)
954{
955 FcValue v;
956
957 v.type = FcTypeInteger;
958 v.u.i = i;
959 return FcPatternAdd (p, object, v, FcTrue);
960}
961
962FcBool
963FcPatternAddDouble (FcPattern *p, const char *object, double d)
964{
965 FcValue v;
966
967 v.type = FcTypeDouble;
968 v.u.d = d;
969 return FcPatternAdd (p, object, v, FcTrue);
970}
971
972
973FcBool
ccb3e93b 974FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
24330d27
KP
975{
976 FcValue v;
977
978 v.type = FcTypeString;
0fa680f0 979 v.u.si = FcObjectStaticName(s);
24330d27
KP
980 return FcPatternAdd (p, object, v, FcTrue);
981}
982
983FcBool
984FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
985{
986 FcValue v;
987
988 v.type = FcTypeMatrix;
cd2ec1a9 989 v.u.mi = FcMatrixPtrCreateDynamic((FcMatrix *) s);
24330d27
KP
990 return FcPatternAdd (p, object, v, FcTrue);
991}
992
993
994FcBool
995FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
996{
997 FcValue v;
998
999 v.type = FcTypeBool;
1000 v.u.b = b;
1001 return FcPatternAdd (p, object, v, FcTrue);
1002}
1003
1004FcBool
1005FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
1006{
1007 FcValue v;
1008
1009 v.type = FcTypeCharSet;
cd2ec1a9 1010 v.u.ci = FcCharSetPtrCreateDynamic((FcCharSet *)c);
24330d27
KP
1011 return FcPatternAdd (p, object, v, FcTrue);
1012}
1013
be094850
KP
1014FcBool
1015FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
1016{
1017 FcValue v;
1018
1019 v.type = FcTypeFTFace;
1020 v.u.f = (void *) f;
1021 return FcPatternAdd (p, object, v, FcTrue);
1022}
1023
d8d73958
KP
1024FcBool
1025FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1026{
1027 FcValue v;
1028
1029 v.type = FcTypeLangSet;
cd2ec1a9 1030 v.u.li = FcLangSetPtrCreateDynamic((FcLangSet *)ls);
d8d73958
KP
1031 return FcPatternAdd (p, object, v, FcTrue);
1032}
1033
24330d27 1034FcResult
bff80114 1035FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
24330d27
KP
1036{
1037 FcPatternElt *e;
cd2ec1a9 1038 FcValueListPtr l;
24330d27 1039
e9be9cd1 1040 e = FcPatternFindElt (p, object);
24330d27
KP
1041 if (!e)
1042 return FcResultNoMatch;
cd2ec1a9 1043 for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
24330d27
KP
1044 {
1045 if (!id)
1046 {
cd2ec1a9 1047 *v = FcValueListPtrU(l)->value;
24330d27
KP
1048 return FcResultMatch;
1049 }
1050 id--;
1051 }
1052 return FcResultNoId;
1053}
1054
1055FcResult
bff80114 1056FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
24330d27
KP
1057{
1058 FcValue v;
1059 FcResult r;
1060
1061 r = FcPatternGet (p, object, id, &v);
1062 if (r != FcResultMatch)
1063 return r;
1064 switch (v.type) {
1065 case FcTypeDouble:
1066 *i = (int) v.u.d;
1067 break;
1068 case FcTypeInteger:
1069 *i = v.u.i;
1070 break;
1071 default:
1072 return FcResultTypeMismatch;
1073 }
1074 return FcResultMatch;
1075}
1076
1077FcResult
bff80114 1078FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
24330d27
KP
1079{
1080 FcValue v;
1081 FcResult r;
1082
1083 r = FcPatternGet (p, object, id, &v);
1084 if (r != FcResultMatch)
1085 return r;
1086 switch (v.type) {
1087 case FcTypeDouble:
1088 *d = v.u.d;
1089 break;
1090 case FcTypeInteger:
1091 *d = (double) v.u.i;
1092 break;
1093 default:
1094 return FcResultTypeMismatch;
1095 }
1096 return FcResultMatch;
1097}
1098
1099FcResult
bff80114 1100FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
24330d27
KP
1101{
1102 FcValue v;
1103 FcResult r;
1104
1105 r = FcPatternGet (p, object, id, &v);
1106 if (r != FcResultMatch)
1107 return r;
1108 if (v.type != FcTypeString)
1109 return FcResultTypeMismatch;
cd2ec1a9 1110 *s = (FcChar8 *) FcObjectPtrU(v.u.si);
24330d27
KP
1111 return FcResultMatch;
1112}
1113
1114FcResult
bff80114 1115FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
24330d27
KP
1116{
1117 FcValue v;
1118 FcResult r;
1119
1120 r = FcPatternGet (p, object, id, &v);
1121 if (r != FcResultMatch)
1122 return r;
1123 if (v.type != FcTypeMatrix)
1124 return FcResultTypeMismatch;
cd2ec1a9 1125 *m = FcMatrixPtrU(v.u.mi);
24330d27
KP
1126 return FcResultMatch;
1127}
1128
1129
1130FcResult
bff80114 1131FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
24330d27
KP
1132{
1133 FcValue v;
1134 FcResult r;
1135
1136 r = FcPatternGet (p, object, id, &v);
1137 if (r != FcResultMatch)
1138 return r;
1139 if (v.type != FcTypeBool)
1140 return FcResultTypeMismatch;
1141 *b = v.u.b;
1142 return FcResultMatch;
1143}
1144
1145FcResult
bff80114 1146FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
24330d27
KP
1147{
1148 FcValue v;
1149 FcResult r;
1150
1151 r = FcPatternGet (p, object, id, &v);
1152 if (r != FcResultMatch)
1153 return r;
1154 if (v.type != FcTypeCharSet)
1155 return FcResultTypeMismatch;
cd2ec1a9 1156 *c = FcCharSetPtrU(v.u.ci);
24330d27
KP
1157 return FcResultMatch;
1158}
1159
be094850 1160FcResult
bff80114 1161FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
be094850
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 != FcTypeFTFace)
1170 return FcResultTypeMismatch;
1171 *f = (FT_Face) v.u.f;
1172 return FcResultMatch;
1173}
1174
d8d73958 1175FcResult
bff80114 1176FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
d8d73958
KP
1177{
1178 FcValue v;
1179 FcResult r;
1180
1181 r = FcPatternGet (p, object, id, &v);
1182 if (r != FcResultMatch)
1183 return r;
1184 if (v.type != FcTypeLangSet)
1185 return FcResultTypeMismatch;
cd2ec1a9 1186 *ls = FcLangSetPtrU(v.u.li);
d8d73958
KP
1187 return FcResultMatch;
1188}
1189
24330d27 1190FcPattern *
bff80114 1191FcPatternDuplicate (const FcPattern *orig)
24330d27
KP
1192{
1193 FcPattern *new;
cd2ec1a9 1194 FcPatternElt *e;
24330d27 1195 int i;
cd2ec1a9 1196 FcValueListPtr l;
24330d27
KP
1197
1198 new = FcPatternCreate ();
1199 if (!new)
1200 goto bail0;
1201
cd2ec1a9
PL
1202 e = FcPatternEltU(orig->elts);
1203
24330d27
KP
1204 for (i = 0; i < orig->num; i++)
1205 {
cd2ec1a9
PL
1206 for (l = (e + i)->values;
1207 FcValueListPtrU(l);
1208 l = FcValueListPtrU(l)->next)
1209 if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object),
1210 FcValueListPtrU(l)->value, FcTrue))
24330d27
KP
1211 goto bail1;
1212 }
1213
1214 return new;
1215
1216bail1:
1217 FcPatternDestroy (new);
1218bail0:
1219 return 0;
1220}
1221
6f6563ed
KP
1222void
1223FcPatternReference (FcPattern *p)
1224{
d8d73958
KP
1225 if (p->ref != FC_REF_CONSTANT)
1226 p->ref++;
6f6563ed
KP
1227}
1228
24330d27
KP
1229FcPattern *
1230FcPatternVaBuild (FcPattern *orig, va_list va)
1231{
1232 FcPattern *ret;
1233
1234 FcPatternVapBuild (ret, orig, va);
1235 return ret;
1236}
1237
1238FcPattern *
1239FcPatternBuild (FcPattern *orig, ...)
1240{
1241 va_list va;
1242
1243 va_start (va, orig);
1244 FcPatternVapBuild (orig, orig, va);
1245 va_end (va);
1246 return orig;
1247}
4f27c1c0
KP
1248
1249/*
1250 * Add all of the elements in 's' to 'p'
1251 */
1252FcBool
1253FcPatternAppend (FcPattern *p, FcPattern *s)
1254{
1255 int i;
1256 FcPatternElt *e;
cd2ec1a9 1257 FcValueListPtr v;
4f27c1c0
KP
1258
1259 for (i = 0; i < s->num; i++)
1260 {
cd2ec1a9
PL
1261 e = FcPatternEltU(s->elts)+i;
1262 for (v = e->values; FcValueListPtrU(v);
1263 v = FcValueListPtrU(v)->next)
4f27c1c0 1264 {
cd2ec1a9
PL
1265 if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1266 FcValueListPtrU(v)->value,
1267 FcValueListPtrU(v)->binding, FcTrue))
4f27c1c0
KP
1268 return FcFalse;
1269 }
1270 }
1271 return FcTrue;
1272}
1273
cd2ec1a9
PL
1274FcPatternElt *
1275FcPatternEltU (FcPatternEltPtr pei)
1276{
1277 switch (pei.storage)
1278 {
1279 case FcStorageStatic:
1280 if (pei.u.stat == 0) return 0;
1281 return &fcpatternelts[pei.u.stat];
1282 case FcStorageDynamic:
1283 return pei.u.dyn;
1284 default:
1285 return 0;
1286 }
1287}
1288
1289static FcPatternEltPtr
1290FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1291{
1292 FcPatternEltPtr new;
1293 new.storage = FcStorageDynamic;
1294 new.u.dyn = e;
1295 return new;
1296}
1297
1298static FcPatternEltPtr
1299FcPatternEltPtrCreateStatic (int i)
1300{
1301 FcPatternEltPtr new;
1302 new.storage = FcStorageStatic;
1303 new.u.stat = i;
1304 return new;
1305}
1306
1307static FcBool
1308FcPatternEltIsDynamic (FcPatternEltPtr pei)
1309{
1310 return pei.storage == FcStorageDynamic;
1311}
1312
cd2ec1a9
PL
1313
1314void
1315FcPatternClearStatic (void)
1316{
1317 fcpatterns = 0;
1318 fcpattern_ptr = 0;
1319 fcpattern_count = 0;
1320
1321 fcpatternelts = 0;
1322 fcpatternelt_ptr = 0;
1323 fcpatternelt_count = 0;
1324}
1325
1326void
1327FcValueListClearStatic (void)
1328{
1329 fcvaluelists = 0;
1330 fcvaluelist_ptr = 0;
1331 fcvaluelist_count = 0;
1332}
1333
0fa680f0
PL
1334static FcObjectPtr
1335FcObjectSerialize (FcObjectPtr si);
1336
cd2ec1a9
PL
1337FcBool
1338FcPatternPrepareSerialize (FcPattern * p)
1339{
1340 int i;
1341
1342 fcpattern_count++;
1343 fcpatternelt_count += p->num;
1344
1345 for (i = 0; i < p->num; i++)
1346 {
1347 FcObjectPrepareSerialize
1348 ((FcPatternEltU(p->elts)+i)->object);
1349 if (!FcValueListPrepareSerialize
1350 (FcValueListPtrU(((FcPatternEltU(p->elts)+i)->values))))
1351 return FcFalse;
1352 }
1353
1354 return FcTrue;
1355}
1356
1357FcBool
1358FcValueListPrepareSerialize (FcValueList *p)
1359{
1360 FcValueList *vl;
1361
1362 for (vl = p;
1363 vl;
1364 vl = FcValueListPtrU(vl->next))
1365 {
1366 FcValue v = vl->value;
1367
1368 switch (v.type)
1369 {
1370 case FcTypeMatrix:
1371 FcMatrixPrepareSerialize(FcMatrixPtrU(v.u.mi));
1372 break;
1373 case FcTypeCharSet:
1374 FcCharSetPrepareSerialize(FcCharSetPtrU(v.u.ci));
1375 break;
1376 case FcTypeLangSet:
1377 FcLangSetPrepareSerialize(FcLangSetPtrU(v.u.li));
1378 break;
1379 case FcTypeString:
1380 FcObjectPrepareSerialize(v.u.si);
1381 default:
1382 break;
1383 }
1384 fcvaluelist_count++;
1385 }
1386
1387 return FcTrue;
1388}
1389
1390FcPattern *
1391FcPatternSerialize (FcPattern *old)
1392{
1393 FcPattern *p;
1394 FcPatternElt *e, *nep;
1395 FcValueList * nv;
1396 FcValueListPtr v, nv_head, nvp;
1397 int i, elts;
1398
1399 if (!fcpatterns)
1400 {
1401 p = malloc (sizeof (FcPattern) * fcpattern_count);
1402 if (!p)
1403 goto bail;
1404
1405 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
1406 fcpatterns = p;
1407 fcpattern_ptr = 0;
1408
1409 e = malloc (sizeof (FcPatternElt) * fcpatternelt_count);
1410 if (!e)
1411 goto bail1;
1412
1413 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1414 fcpatternelts = e;
1415 fcpatternelt_ptr = 0;
1416 }
1417
1418 p = FcPatternCreate();
1419 elts = fcpatternelt_ptr;
1420 nep = &fcpatternelts[elts];
1421 if (!nep)
1422 return FcFalse;
1423 fcpatternelt_ptr += old->num;
1424
1425 for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++)
1426 {
1427 v = e->values;
1428 nvp = nv_head = FcValueListSerialize(FcValueListPtrU(v));
1429 if (!FcValueListPtrU(nv_head))
1430 goto bail2;
1431 nv = FcValueListPtrU(nvp);
1432
1433 for (;
1434 FcValueListPtrU(v);
1435 v = FcValueListPtrU(v)->next,
1436 nv = FcValueListPtrU(nv->next))
1437 {
1438
1439 if (FcValueListPtrU(FcValueListPtrU(v)->next))
1440 {
1441 nvp = FcValueListSerialize
1442 (FcValueListPtrU(FcValueListPtrU(v)->next));
1443 nv->next = nvp;
1444 }
1445 }
1446
1447 nep[i].values = nv_head;
1448 nep[i].object = FcObjectSerialize
1449 (FcObjectStaticName(FcObjectPtrU(e->object)));
1450 }
1451
1452 p->elts = FcPatternEltPtrCreateStatic(elts);
1453 p->size = old->num;
1454 p->ref = FC_REF_CONSTANT;
1455 return p;
1456
1457 bail2:
1458 free (fcpatternelts);
1459 bail1:
1460 free (fcpatterns);
1461 bail:
1462 return 0;
1463 }
1464
1465FcValueListPtr
1466FcValueListSerialize(FcValueList *pi)
1467{
1468 FcValueListPtr new;
1469 FcValue * v;
1470 FcValueList * vl;
1471
1472 if (!fcvaluelists)
1473 {
1474 vl = malloc (sizeof (FcValueList) * fcvaluelist_count);
1475 if (!vl)
1476 return FcValueListPtrCreateDynamic(0);
1477
1478 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1479 fcvaluelists = vl;
1480 fcvaluelist_ptr = 0;
1481 }
1482
1483 fcvaluelists[fcvaluelist_ptr] = *pi;
1484 new.storage = FcStorageStatic;
1485 new.u.stat = fcvaluelist_ptr++;
1486 v = &fcvaluelists[new.u.stat].value;
1487 switch (v->type)
1488 {
1489 case FcTypeString:
1490 if (FcObjectPtrU(v->u.si))
1491 {
1492 FcObjectPtr si =
1493 FcObjectSerialize(FcObjectStaticName(FcObjectPtrU(v->u.si)));
1494 if (!FcObjectPtrU(v->u.si))
1495 return FcValueListPtrCreateDynamic(pi);
1496 v->u.si = si;
1497 }
1498 break;
1499 case FcTypeMatrix:
1500 if (FcMatrixPtrU(v->u.mi))
1501 {
1502 FcMatrixPtr mi = FcMatrixSerialize(FcMatrixPtrU(v->u.mi));
1503
1504 if (!FcMatrixPtrU(mi))
1505 return FcValueListPtrCreateDynamic(pi);
1506 v->u.mi = mi;
1507 }
1508 break;
1509 case FcTypeCharSet:
1510 if (FcCharSetPtrU(v->u.ci))
1511 {
1512 FcCharSetPtr ci = FcCharSetSerialize(FcCharSetPtrU(v->u.ci));
1513 if (!FcCharSetPtrU(v->u.ci))
1514 return FcValueListPtrCreateDynamic(pi);
1515 v->u.ci = ci;
1516 }
1517 break;
1518 case FcTypeLangSet:
1519 if (FcLangSetPtrU(v->u.li))
1520 {
1521 FcLangSetPtr li = FcLangSetSerialize(FcLangSetPtrU(v->u.li));
1522 if (!FcLangSetPtrU(v->u.li))
1523 return FcValueListPtrCreateDynamic(pi);
1524 v->u.li = li;
1525 }
1526 break;
1527 default:
1528 break;
1529 }
1530 return new;
1531}
1532
1533FcValueList *
1534FcValueListPtrU (FcValueListPtr pi)
1535{
1536 switch (pi.storage)
1537 {
1538 case FcStorageStatic:
1539 if (pi.u.stat == 0) return 0;
1540 return &fcvaluelists[pi.u.stat];
1541 case FcStorageDynamic:
1542 return pi.u.dyn;
1543 default:
1544 return 0;
1545 }
1546}
1547
1548FcValueListPtr
1549FcValueListPtrCreateDynamic(FcValueList * p)
1550{
1551 FcValueListPtr r;
1552
1553 r.storage = FcStorageDynamic;
1554 r.u.dyn = p;
1555 return r;
4f27c1c0 1556}
0fa680f0
PL
1557
1558/* Indices allow us to convert dynamic strings into static
1559 * strings without having to reassign IDs. We do reassign IDs
1560 * when serializing, which effectively performs mark-and-sweep
1561 * garbage collection. */
1562
1563/* objectptr_count maps FcObjectPtr to:
1564 + offsets in objectcontent_static_buf (if positive)
1565 - entries in objectcontent_dynamic (if negative)
1566*/
1567static int objectptr_count = 1;
1568static int objectptr_alloc = 0;
1569static int * objectptr_indices = 0;
1570
1571/* invariant: objectcontent_static_buf must be sorted. */
1572/* e.g. objectptr_static_buf = "name\0style\0weight\0" */
1573static int objectcontent_static_bytes = 0;
1574static char * objectcontent_static_buf;
1575
1576/* just a bunch of strings. */
1577static int objectcontent_dynamic_count = 1;
1578static int objectcontent_dynamic_alloc = 0;
1579static const char ** objectcontent_dynamic = 0;
1580static int * objectcontent_dynamic_refcount = 0;
1581
1582#define OBJECT_HASH_SIZE 31
1583struct objectBucket {
1584 struct objectBucket *next;
1585 FcChar32 hash;
1586};
1587static struct objectBucket **buckets = 0;
1588
1589FcObjectPtr
1590FcObjectStaticName (const char *name)
1591{
1592 FcChar32 hash = FcStringHash ((const FcChar8 *) name);
1593 struct objectBucket **p;
1594 struct objectBucket *b;
1595 const char * nn;
1596 int size;
1597 FcObjectPtr new;
1598
1599 if (!buckets)
1600 {
1601 buckets = malloc(sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1602 memset (buckets, 0, sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1603 }
1604
1605 for (p = &buckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1606 {
1607 FcObjectPtr bp = *((FcObjectPtr *) (b + 1));
1608 if (b->hash == hash && FcObjectPtrU(bp) && !strcmp (name, FcObjectPtrU(bp)))
1609 {
1610 if (objectptr_indices[bp] < 0)
1611 objectcontent_dynamic_refcount[-objectptr_indices[bp]]++;
1612 return bp;
1613 }
1614 }
1615
1616 /* didn't find it, so add a new dynamic string */
1617 if (objectcontent_dynamic_count >= objectcontent_dynamic_alloc)
1618 {
1619 int s = objectcontent_dynamic_alloc + 4;
1620
1621 const char ** d = realloc (objectcontent_dynamic,
1622 s*sizeof(char *));
1623 if (!d)
1624 return 0;
1625 FcMemFree(FC_MEM_STATICSTR,
1626 objectcontent_dynamic_alloc * sizeof(char *));
1627 FcMemAlloc(FC_MEM_STATICSTR, s*sizeof(char *));
1628 objectcontent_dynamic = d;
1629 objectcontent_dynamic_alloc = s;
1630
1631 int * rc = realloc (objectcontent_dynamic_refcount, s*sizeof(int));
1632 if (!rc)
1633 return 0;
1634 FcMemFree(FC_MEM_STATICSTR,
1635 objectcontent_dynamic_alloc * sizeof(int));
1636 FcMemAlloc(FC_MEM_STATICSTR, s * sizeof(int));
1637 objectcontent_dynamic_refcount = rc;
1638 }
1639 if (objectptr_count >= objectptr_alloc)
1640 {
1641 int s = objectptr_alloc + 4;
1642 int * d = realloc (objectptr_indices, s*sizeof(int));
1643 if (!d)
1644 return 0;
1645 FcMemFree(FC_MEM_STATICSTR, objectptr_alloc * sizeof(int));
1646 FcMemAlloc(FC_MEM_STATICSTR, s);
1647 objectptr_indices = d;
1648 objectptr_indices[0] = 0;
1649 objectptr_alloc = s;
1650 }
1651
1652 size = sizeof (struct objectBucket) + sizeof (FcObjectPtr);
1653 b = malloc (size);
1654 if (!b)
1655 return 0;
1656 FcMemAlloc (FC_MEM_STATICSTR, size);
1657 b->next = 0;
1658 b->hash = hash;
1659 nn = malloc(strlen(name)+1);
1660 if (!nn)
1661 goto bail;
1662 strcpy ((char *)nn, name);
1663 objectptr_indices[objectptr_count] = -objectcontent_dynamic_count;
1664 objectcontent_dynamic_refcount[objectcontent_dynamic_count] = 1;
1665 objectcontent_dynamic[objectcontent_dynamic_count++] = nn;
1666 new = objectptr_count++;
1667 *((FcObjectPtr *)(b+1)) = new;
1668 *p = b;
1669 return new;
1670
1671 bail:
1672 free(b);
1673 return 0;
1674}
1675
1676void
1677FcObjectPtrDestroy (FcObjectPtr p)
1678{
1679 if (objectptr_indices[p] < 0)
1680 {
1681 objectcontent_dynamic_refcount[-objectptr_indices[p]]--;
1682 if (objectcontent_dynamic_refcount[-objectptr_indices[p]] == 0)
1683 {
1684 /* this code doesn't seem to be reached terribly often. */
1685 /* (note that objectcontent_dynamic overapproximates
1686 * the use count, because not every result from
1687 * StaticName is stored. */
1688 FcStrFree((char *)objectcontent_dynamic[-objectptr_indices[p]]);
1689 objectcontent_dynamic[-objectptr_indices[p]] = 0;
1690 }
1691 }
1692}
1693
1694const char *
1695FcObjectPtrU (FcObjectPtr si)
1696{
1697 if (objectptr_indices[si] > 0)
1698 return &objectcontent_static_buf[objectptr_indices[si]];
1699 else
1700 return objectcontent_dynamic[-objectptr_indices[si]];
1701}
1702
1703static FcBool objectptr_first_serialization = FcFalse;
1704static int * object_old_id_to_new = 0;
1705
1706static void
1707FcObjectRebuildStaticNameHashtable (void)
1708{
1709 int i;
1710 struct objectBucket *b, *bn;
1711
1712 if (buckets)
1713 {
1714 for (i = 0; i < OBJECT_HASH_SIZE; i++)
1715 {
1716 b = buckets[i];
1717 while (b)
1718 {
1719 bn = b->next;
1720 free(b);
1721 FcMemFree (FC_MEM_STATICSTR,
1722 sizeof (struct objectBucket)+sizeof (FcObjectPtr));
1723 b = bn;
1724 }
1725 }
1726 free (buckets);
1727 }
1728
1729 buckets = malloc(sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1730 memset (buckets, 0, sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1731
1732 for (i = 1; i < objectptr_count; i++)
1733 {
1734 if (FcObjectPtrU(i))
1735 {
1736 const char * name = FcObjectPtrU(i);
1737 FcChar32 hash = FcStringHash ((const FcChar8 *) name);
1738 struct objectBucket **p;
1739 int size;
1740
1741 for (p = &buckets[hash % OBJECT_HASH_SIZE]; (b = *p);
1742 p = &(b->next))
1743 ;
1744 size = sizeof (struct objectBucket) + sizeof (FcObjectPtr);
1745 b = malloc (size);
1746 if (!b)
1747 return;
1748 FcMemAlloc (FC_MEM_STATICSTR, size);
1749 b->next = 0;
1750 b->hash = hash;
1751 *((FcObjectPtr *)(b+1)) = i;
1752 *p = b;
1753 }
1754 }
1755}
1756
1757/* Hmm. This will have a terrible effect on the memory size,
1758 * because the mmapped strings now get reallocated on the heap.
1759 * Is it all worth it? (Of course, the Serialization codepath is
1760 * not problematic.) */
1761static FcBool
1762FcObjectPtrConvertToStatic(FcBool renumber)
1763{
1764 int active_count, i, j, longest_string = 0,
1765 new_static_bytes = 1;
1766 char * fixed_length_buf, * new_static_buf, * p;
1767 int * new_indices;
1768
1769 if (renumber)
1770 objectptr_first_serialization = FcFalse;
1771
1772 /* collect statistics */
1773 for (i = 1, active_count = 1; i < objectptr_count; i++)
1774 if (!renumber || object_old_id_to_new[i] == -1)
1775 {
1776 int sl = strlen(FcObjectPtrU(i));
1777 active_count++;
1778 if (sl > longest_string)
1779 longest_string = sl;
1780 new_static_bytes += sl + 1;
1781 }
1782
1783 /* allocate storage */
1784 fixed_length_buf = malloc
1785 ((longest_string+1) * active_count * sizeof(char));
1786 if (!fixed_length_buf)
1787 goto bail;
1788 new_static_buf = malloc (new_static_bytes * sizeof(char));
1789 if (!new_static_buf)
1790 goto bail1;
1791 new_indices = malloc (active_count * sizeof(int));
1792 if (!new_indices)
1793 goto bail2;
1794
1795 FcMemAlloc (FC_MEM_STATICSTR, new_static_bytes);
1796 FcMemFree (FC_MEM_STATICSTR, objectptr_count * sizeof (int));
1797 FcMemAlloc (FC_MEM_STATICSTR, active_count * sizeof (int));
1798
1799 /* copy strings to temporary buffers */
1800 for (j = 0, i = 1; i < objectptr_count; i++)
1801 if (!renumber || object_old_id_to_new[i] == -1)
1802 {
1803 strcpy (fixed_length_buf+(j*(longest_string+1)), FcObjectPtrU(i));
1804 j++;
1805 }
1806
1807 /* sort the new statics */
1808 qsort (fixed_length_buf, active_count-1, longest_string+1,
1809 (int (*)(const void *, const void *)) FcStrCmp);
1810
1811 /* now we create the new static buffer in sorted order. */
1812 p = new_static_buf+1;
1813 for (i = 0; i < active_count-1; i++)
1814 {
1815 strcpy(p, fixed_length_buf + i * (longest_string+1));
1816 p += strlen(p)+1;
1817 }
1818
1819 /* create translation table by iterating over sorted strings
1820 * and getting their old values */
1821 p = new_static_buf+1;
1822 for (i = 0; i < active_count-1; i++)
1823 {
1824 int n = FcObjectStaticName(fixed_length_buf+i*(longest_string+1));
1825 if (renumber)
1826 {
1827 object_old_id_to_new[n] = i;
1828 new_indices[i] = p-new_static_buf;
1829 }
1830 else
1831 new_indices[n] = p-new_static_buf;
1832 p += strlen(p)+1;
1833 }
1834
1835 free (objectptr_indices);
1836 objectptr_indices = new_indices;
1837 objectptr_count = active_count;
1838 objectptr_alloc = active_count;
1839
1840 /* free old storage */
1841 for (i = 1; i < objectcontent_dynamic_count; i++)
1842 {
1843 if (objectcontent_dynamic[i])
1844 {
1845 FcMemFree (FC_MEM_STATICSTR, strlen(objectcontent_dynamic[i])+1);
1846 free ((char *)objectcontent_dynamic[i]);
1847 }
1848 }
1849 free (objectcontent_dynamic);
1850 free (objectcontent_dynamic_refcount);
1851 FcMemFree (FC_MEM_STATICSTR, objectcontent_dynamic_count*sizeof (int));
1852 objectcontent_dynamic = 0;
1853 objectcontent_dynamic_refcount = 0;
1854 objectcontent_dynamic_count = 1;
1855 objectcontent_dynamic_alloc = 0;
1856 free (objectcontent_static_buf);
1857 FcMemFree (FC_MEM_STATICSTR, objectcontent_static_bytes);
1858 objectcontent_static_buf = new_static_buf;
1859 objectcontent_static_bytes = new_static_bytes;
1860
1861 /* fix up hash table */
1862 FcObjectRebuildStaticNameHashtable();
1863
1864 free (fixed_length_buf);
1865 return FcTrue;
1866
1867 bail2:
1868 free (new_static_buf);
1869 bail1:
1870 free (fixed_length_buf);
1871 bail:
1872 return FcFalse;
1873}
1874
1875#define OBJECT_PTR_CONVERSION_TRIGGER 100000
1876
1877int
1878FcObjectPtrCompare (const FcObjectPtr a, const FcObjectPtr b)
1879{
1880 /* This is the dynamic count. We could also use a static
1881 * count, i.e. the number of slow strings being created.
1882 * I think dyncount gives us a better estimate of inefficiency. -PL */
1883 static int compare_count = OBJECT_PTR_CONVERSION_TRIGGER;
1884
1885 /* count on sortedness for fast objectptrs. */
1886 if ((a == b) || (objectptr_indices[a] > 0 && objectptr_indices[b] > 0))
1887 return objectptr_indices[a] - objectptr_indices[b];
1888
1889 compare_count--;
1890 if (!compare_count)
1891 {
1892 FcObjectPtrConvertToStatic(FcFalse);
1893 compare_count = OBJECT_PTR_CONVERSION_TRIGGER;
1894 }
1895
1896 return strcmp (FcObjectPtrU(a), FcObjectPtrU(b));
1897}
1898
1899void
1900FcObjectClearStatic(void)
1901{
1902 objectptr_count = 1;
1903 objectptr_alloc = 0;
1904 objectptr_indices = 0;
1905
1906 objectcontent_static_bytes = 0;
1907 objectcontent_static_buf = 0;
1908
1909 objectcontent_dynamic_count = 1;
1910 objectcontent_dynamic_alloc = 0;
1911 objectcontent_dynamic = 0;
1912 objectcontent_dynamic_refcount = 0;
1913
1914 object_old_id_to_new = 0;
1915}
1916
1917static FcObjectPtr
1918FcObjectSerialize (FcObjectPtr si)
1919{
1920 if (objectptr_first_serialization)
1921 if (!FcObjectPtrConvertToStatic(FcTrue))
1922 return 0;
1923
1924 return object_old_id_to_new[si];
1925}
1926
1927/* In the pre-serialization phase, mark the used strings with
1928 * -1 in the mapping array. */
1929/* The first call to the serialization phase assigns actual
1930 * static indices to the strings (sweep). */
1931FcBool
1932FcObjectPrepareSerialize (FcObjectPtr si)
1933{
1934 if (object_old_id_to_new == 0)
1935 {
1936 object_old_id_to_new = malloc(objectptr_count * sizeof(int));
1937 if (!object_old_id_to_new)
1938 goto bail;
1939 memset (object_old_id_to_new, 0,
1940 objectptr_count * sizeof(int));
1941 }
1942
1943 object_old_id_to_new[si] = -1;
1944 objectptr_first_serialization = FcTrue;
1945
1946 return FcTrue;
1947
1948 bail:
1949 return FcFalse;
1950}