]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Forward port cworth's patch to branch.
[fontconfig.git] / src / fcpat.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
3 *
4 * Copyright © 2000 Keith Packard
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>
27 #include <assert.h>
28 #include <sys/mman.h>
29 #include "fcint.h"
30
31 static FcPattern * fcpatterns = NULL;
32 static int fcpattern_ptr, fcpattern_count;
33 static FcPatternElt * fcpatternelts = NULL;
34 static int fcpatternelt_ptr, fcpatternelt_count;
35 static FcValueList * fcvaluelists = NULL;
36 static int fcvaluelist_ptr, fcvaluelist_count;
37
38 static FcBool
39 FcPatternEltIsDynamic (FcPatternEltPtr pei);
40
41 static FcPatternEltPtr
42 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
43
44 FcPattern *
45 FcPatternCreate (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;
55 p->elts = FcPatternEltPtrCreateDynamic(0);
56 p->ref = 1;
57 return p;
58 }
59
60 void
61 FcValueDestroy (FcValue v)
62 {
63 switch (v.type) {
64 case FcTypeString:
65 FcObjectPtrDestroy (v.u.si);
66 break;
67 case FcTypeMatrix:
68 FcMatrixPtrDestroy (v.u.mi);
69 break;
70 case FcTypeCharSet:
71 FcCharSetPtrDestroy (v.u.ci);
72 break;
73 case FcTypeLangSet:
74 FcLangSetPtrDestroy (v.u.li);
75 break;
76 default:
77 break;
78 }
79 }
80
81 FcValue
82 FcValueSave (FcValue v)
83 {
84 switch (v.type) {
85 case FcTypeString:
86 v.u.si = FcObjectStaticName(FcObjectPtrU(v.u.si));
87 if (!FcObjectPtrU(v.u.si))
88 v.type = FcTypeVoid;
89 break;
90 case FcTypeMatrix:
91 v.u.mi = FcMatrixPtrCreateDynamic
92 (FcMatrixCopy (FcMatrixPtrU(v.u.mi)));
93 if (!FcMatrixPtrU(v.u.mi))
94 v.type = FcTypeVoid;
95 break;
96 case FcTypeCharSet:
97 v.u.ci = FcCharSetPtrCreateDynamic
98 (FcCharSetCopy (FcCharSetPtrU(v.u.ci)));
99 if (!FcCharSetPtrU(v.u.ci))
100 v.type = FcTypeVoid;
101 break;
102 case FcTypeLangSet:
103 v.u.li = FcLangSetPtrCreateDynamic
104 (FcLangSetCopy (FcLangSetPtrU(v.u.li)));
105 if (!FcLangSetPtrU(v.u.li))
106 v.type = FcTypeVoid;
107 break;
108 default:
109 break;
110 }
111 return v;
112 }
113
114 void
115 FcValueListDestroy (FcValueListPtr l)
116 {
117 FcValueListPtr next;
118 for (; FcValueListPtrU(l); l = next)
119 {
120 switch (FcValueListPtrU(l)->value.type) {
121 case FcTypeString:
122 FcObjectPtrDestroy (FcValueListPtrU(l)->value.u.si);
123 break;
124 case FcTypeMatrix:
125 FcMatrixPtrDestroy (FcValueListPtrU(l)->value.u.mi);
126 break;
127 case FcTypeCharSet:
128 FcCharSetDestroy
129 (FcCharSetPtrU (FcValueListPtrU(l)->value.u.ci));
130 break;
131 case FcTypeLangSet:
132 FcLangSetDestroy
133 (FcLangSetPtrU (FcValueListPtrU(l)->value.u.li));
134 break;
135 default:
136 break;
137 }
138 next = FcValueListPtrU(l)->next;
139
140 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
141 if (l.storage == FcStorageDynamic)
142 free(l.u.dyn);
143 }
144 }
145
146 FcBool
147 FcValueEqual (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:
172 return FcStrCmpIgnoreCase (FcObjectPtrU(va.u.si),
173 FcObjectPtrU(vb.u.si)) == 0;
174 case FcTypeBool:
175 return va.u.b == vb.u.b;
176 case FcTypeMatrix:
177 return FcMatrixEqual (FcMatrixPtrU(va.u.mi),
178 FcMatrixPtrU(vb.u.mi));
179 case FcTypeCharSet:
180 return FcCharSetEqual (FcCharSetPtrU(va.u.ci),
181 FcCharSetPtrU(vb.u.ci));
182 case FcTypeFTFace:
183 return va.u.f == vb.u.f;
184 case FcTypeLangSet:
185 return FcLangSetEqual (FcLangSetPtrU(va.u.li),
186 FcLangSetPtrU(vb.u.li));
187 }
188 return FcFalse;
189 }
190
191 static FcChar32
192 FcDoubleHash (double d)
193 {
194 if (d < 0)
195 d = -d;
196 if (d > 0xffffffff)
197 d = 0xffffffff;
198 return (FcChar32) d;
199 }
200
201 static FcChar32
202 FcStringHash (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
213 static FcChar32
214 FcValueHash (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:
224 return FcStringHash (FcObjectPtrU(v.u.si));
225 case FcTypeBool:
226 return (FcChar32) v.u.b;
227 case FcTypeMatrix:
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 }
235 case FcTypeCharSet:
236 return (FcChar32) (FcCharSetPtrU(v.u.ci))->num;
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);
240 case FcTypeLangSet:
241 return FcLangSetHash (FcLangSetPtrU(v.u.li));
242 }
243 return FcFalse;
244 }
245
246 static FcBool
247 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
248 {
249 if (FcValueListPtrU(la) == FcValueListPtrU(lb))
250 return FcTrue;
251
252 while (FcValueListPtrU(la) && FcValueListPtrU(lb))
253 {
254 if (!FcValueEqual (FcValueListPtrU(la)->value,
255 FcValueListPtrU(lb)->value))
256 return FcFalse;
257 la = FcValueListPtrU(la)->next;
258 lb = FcValueListPtrU(lb)->next;
259 }
260 if (FcValueListPtrU(la) || FcValueListPtrU(lb))
261 return FcFalse;
262 return FcTrue;
263 }
264
265 static FcChar32
266 FcValueListHash (FcValueListPtr l)
267 {
268 FcChar32 hash = 0;
269
270 while (FcValueListPtrU(l))
271 {
272 hash = ((hash << 1) | (hash >> 31)) ^
273 FcValueHash (FcValueListPtrU(l)->value);
274 l = FcValueListPtrU(l)->next;
275 }
276 return hash;
277 }
278
279 void
280 FcPatternDestroy (FcPattern *p)
281 {
282 int i;
283
284 if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
285 return;
286
287 for (i = 0; i < p->num; i++)
288 FcValueListDestroy ((FcPatternEltU(p->elts)+i)->values);
289
290 p->num = 0;
291 if (FcPatternEltU(p->elts) && FcPatternEltIsDynamic(p->elts))
292 {
293 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
294 free (FcPatternEltU(p->elts));
295 p->elts = FcPatternEltPtrCreateDynamic(0);
296 }
297 p->size = 0;
298 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
299 free (p);
300 }
301
302 #define FC_VALUE_LIST_HASH_SIZE 257
303 #define FC_PATTERN_HASH_SIZE 67
304
305 typedef struct _FcValueListEnt FcValueListEnt;
306
307 struct _FcValueListEnt {
308 FcValueListEnt *next;
309 FcValueListPtr list;
310 FcChar32 hash, pad;
311 };
312
313 typedef union _FcValueListAlign {
314 FcValueListEnt ent;
315 FcValueList list;
316 } FcValueListAlign;
317
318 static int FcValueListFrozenCount[FcTypeLangSet + 1];
319 static int FcValueListFrozenBytes[FcTypeLangSet + 1];
320 static char *FcValueListFrozenName[] = {
321 "Void",
322 "Integer",
323 "Double",
324 "String",
325 "Bool",
326 "Matrix",
327 "CharSet",
328 "FTFace",
329 "LangSet"
330 };
331
332 void
333 FcValueListReport (void);
334
335 void
336 FcValueListReport (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
347 static FcValueListEnt *
348 FcValueListEntCreate (FcValueListPtr h)
349 {
350 FcValueListAlign *ea;
351 FcValueListEnt *e;
352 FcValueListPtr l;
353 FcValueList *new;
354 int n;
355 int size;
356
357 n = 0;
358 for (l = h; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
359 n++;
360 size = sizeof (FcValueListAlign) + n * sizeof (FcValueList);
361 FcValueListFrozenCount[FcValueListPtrU(h)->value.type]++;
362 FcValueListFrozenBytes[FcValueListPtrU(h)->value.type] += size;
363 // this leaks for some reason
364 ea = malloc (sizeof (FcValueListAlign));
365 if (!ea)
366 return 0;
367 new = malloc (n * sizeof (FcValueList));
368 if (!new)
369 return 0;
370 memset(new, 0, n * sizeof (FcValueList));
371 FcMemAlloc (FC_MEM_VALLIST, size);
372 e = &ea->ent;
373 e->list = (FcValueListPtr) FcValueListPtrCreateDynamic(new);
374 for (l = h; FcValueListPtrU(l);
375 l = FcValueListPtrU(l)->next, new++)
376 {
377 if (FcValueListPtrU(l)->value.type == FcTypeString)
378 {
379 new->value.type = FcTypeString;
380 new->value.u.si = FcObjectStaticName
381 (FcObjectPtrU(FcValueListPtrU(l)->value.u.si));
382 }
383 else
384 {
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);
391 }
392 else
393 {
394 new->next = FcValueListPtrCreateDynamic(0);
395 }
396 }
397 return e;
398 }
399
400 static void
401 FcValueListEntDestroy (FcValueListEnt *e)
402 {
403 FcValueListPtr l;
404
405 FcValueListFrozenCount[FcValueListPtrU(e->list)->value.type]--;
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
416 for (l = e->list; FcValueListPtrU(l);
417 l = FcValueListPtrU(l)->next)
418 {
419 if (FcValueListPtrU(l)->value.type != FcTypeString)
420 FcValueDestroy (FcValueListPtrU(l)->value);
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
428 static int FcValueListTotal;
429 static int FcValueListUsed;
430
431 static FcValueListEnt *FcValueListHashTable[FC_VALUE_LIST_HASH_SIZE];
432
433 static FcValueListPtr
434 FcValueListFreeze (FcValueListPtr l)
435 {
436 FcChar32 hash = FcValueListHash (l);
437 FcValueListEnt **bucket = &FcValueListHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
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)
449 return FcValueListPtrCreateDynamic(0);
450
451 FcValueListUsed++;
452 ent->hash = hash;
453 ent->next = *bucket;
454 *bucket = ent;
455 return ent->list;
456 }
457
458 static void
459 FcValueListThawAll (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
478 static FcChar32
479 FcPatternBaseHash (FcPattern *b)
480 {
481 FcChar32 hash = b->num;
482 int i;
483
484 for (i = 0; i < b->num; i++)
485 hash = ((hash << 1) | (hash >> 31)) ^
486 (long) (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values));
487 return hash;
488 }
489
490 typedef struct _FcPatternEnt FcPatternEnt;
491
492 struct _FcPatternEnt {
493 FcPatternEnt *next;
494 FcChar32 hash;
495 FcPattern *pattern;
496 };
497
498 static int FcPatternTotal;
499 static int FcPatternUsed;
500
501 static FcPatternEnt *FcPatternHashTable[FC_VALUE_LIST_HASH_SIZE];
502
503 static FcPattern *
504 FcPatternBaseFreeze (FcPattern *b)
505 {
506 FcPattern *ep;
507 FcPatternElt *epp;
508 FcChar32 hash = FcPatternBaseHash (b);
509 FcPatternEnt **bucket = &FcPatternHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
510 FcPatternEnt *ent;
511 int i;
512
513 FcPatternTotal++;
514 for (ent = *bucket; ent; ent = ent->next)
515 {
516 if (ent->hash == hash && b->num == ent->pattern->num)
517 {
518 for (i = 0; i < b->num; i++)
519 {
520 if (FcObjectPtrCompare((FcPatternEltU(b->elts)+i)->object,
521 (FcPatternEltU(ent->pattern->elts)+i)->object) != 0)
522 break;
523 if (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values) !=
524 FcValueListPtrU((FcPatternEltU(ent->pattern->elts)+i)->values))
525 break;
526 }
527 if (i == b->num)
528 return ent->pattern;
529 }
530 }
531
532 /*
533 * Compute size of pattern + elts
534 */
535 ent = malloc (sizeof (FcPatternEnt));
536 if (!ent)
537 return 0;
538
539 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPatternEnt));
540 FcPatternUsed++;
541
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;
556
557 for (i = 0; i < b->num; i++)
558 {
559 (FcPatternEltU(ep->elts)+i)->values =
560 (FcPatternEltU(b->elts)+i)->values;
561 (FcPatternEltU(ep->elts)+i)->object =
562 (FcPatternEltU(b->elts)+i)->object;
563 }
564
565 ent->hash = hash;
566 ent->next = *bucket;
567 *bucket = ent;
568 return ent->pattern;
569 bail:
570 free(ent);
571 FcMemFree (FC_MEM_PATTERN, sizeof (FcPatternEnt));
572 FcPatternUsed--;
573 return 0;
574 }
575
576 static void
577 FcPatternBaseThawAll (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
596 FcPattern *
597 FcPatternFreeze (FcPattern *p)
598 {
599 FcPattern *b, *n = 0;
600 FcPatternElt *e;
601 int i;
602
603 if (p->ref == FC_REF_CONSTANT)
604 return p;
605
606 b = FcPatternCreate();
607 if (!b)
608 return 0;
609
610 b->num = p->num;
611 b->size = b->num;
612 b->ref = 1;
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
620 /*
621 * Freeze object lists
622 */
623 for (i = 0; i < p->num; i++)
624 {
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))
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
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;
648 #ifdef DEBUG
649 assert (FcPatternEqual (n, p));
650 #endif
651 return n;
652 }
653
654 static int
655 FcPatternPosition (const FcPattern *p, const char *object)
656 {
657 int low, high, mid, c;
658 FcObjectPtr obj;
659
660 obj = FcObjectStaticName(object);
661 low = 0;
662 high = p->num - 1;
663 c = 1;
664 mid = 0;
665 while (low <= high)
666 {
667 mid = (low + high) >> 1;
668 c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
669 if (c == 0)
670 return mid;
671 if (c < 0)
672 low = mid + 1;
673 else
674 high = mid - 1;
675 }
676 if (c < 0)
677 mid++;
678 return -(mid + 1);
679 }
680
681 FcPatternElt *
682 FcPatternFindElt (const FcPattern *p, const char *object)
683 {
684 int i = FcPatternPosition (p, object);
685 if (i < 0)
686 return 0;
687 return FcPatternEltU(p->elts)+i;
688 }
689
690 FcPatternElt *
691 FcPatternInsertElt (FcPattern *p, const char *object)
692 {
693 int i;
694 FcPatternElt *e;
695
696 i = FcPatternPosition (p, object);
697 if (i < 0)
698 {
699 i = -i - 1;
700
701 /* reallocate array */
702 if (p->num + 1 >= p->size)
703 {
704 int s = p->size + 16;
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 }
716 else
717 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
718 if (!e)
719 return FcFalse;
720 p->elts = FcPatternEltPtrCreateDynamic(e);
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 {
726 (FcPatternEltU(p->elts)+p->size)->object = 0;
727 (FcPatternEltU(p->elts)+p->size)->values =
728 FcValueListPtrCreateDynamic(0);
729 p->size++;
730 }
731 }
732
733 /* move elts up */
734 memmove (FcPatternEltU(p->elts) + i + 1,
735 FcPatternEltU(p->elts) + i,
736 sizeof (FcPatternElt) *
737 (p->num - i));
738
739 /* bump count */
740 p->num++;
741
742 (FcPatternEltU(p->elts)+i)->object = FcObjectStaticName (object);
743 (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
744 }
745
746 return FcPatternEltU(p->elts)+i;
747 }
748
749 FcBool
750 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
751 {
752 int i;
753
754 if (pa == pb)
755 return FcTrue;
756
757 if (pa->num != pb->num)
758 return FcFalse;
759 for (i = 0; i < pa->num; i++)
760 {
761 if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
762 (FcPatternEltU(pb->elts)+i)->object) != 0)
763 return FcFalse;
764 if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values,
765 (FcPatternEltU(pb->elts)+i)->values))
766 return FcFalse;
767 }
768 return FcTrue;
769 }
770
771 FcChar32
772 FcPatternHash (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)) ^
780 FcStringHash ((const FcChar8 *) FcObjectPtrU(((FcPatternEltU(p->elts)+i)->object))) ^
781 FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
782 }
783 return h;
784 }
785
786 FcBool
787 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
788 {
789 FcPatternElt *ea, *eb;
790 int i;
791
792 for (i = 0; i < os->nobject; i++)
793 {
794 ea = FcPatternFindElt (pai, FcObjectPtrU(os->objects[i]));
795 eb = FcPatternFindElt (pbi, FcObjectPtrU(os->objects[i]));
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
812 FcBool
813 FcPatternAddWithBinding (FcPattern *p,
814 const char *object,
815 FcValue value,
816 FcValueBinding binding,
817 FcBool append)
818 {
819 FcPatternElt *e;
820 FcValueListPtr new, *prev;
821 FcValueList * newp;
822
823 if (p->ref == FC_REF_CONSTANT)
824 goto bail0;
825
826 newp = malloc (sizeof (FcValueList));
827 if (!newp)
828 goto bail0;
829
830 memset(newp, 0, sizeof (FcValueList));
831 new = FcValueListPtrCreateDynamic(newp);
832 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
833 /* dup string */
834 value = FcValueSave (value);
835 if (value.type == FcTypeVoid)
836 goto bail1;
837
838 FcValueListPtrU(new)->value = value;
839 FcValueListPtrU(new)->binding = binding;
840 FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
841
842 e = FcPatternInsertElt (p, object);
843 if (!e)
844 goto bail2;
845
846 if (append)
847 {
848 for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
849 ;
850 *prev = new;
851 }
852 else
853 {
854 FcValueListPtrU(new)->next = e->values;
855 e->values = new;
856 }
857
858 return FcTrue;
859
860 bail2:
861 switch (value.type) {
862 case FcTypeString:
863 FcStrFree ((FcChar8 *) FcObjectPtrU(value.u.si));
864 break;
865 case FcTypeMatrix:
866 FcMatrixFree (FcMatrixPtrU(value.u.mi));
867 break;
868 case FcTypeCharSet:
869 FcCharSetDestroy (FcCharSetPtrU(value.u.ci));
870 break;
871 case FcTypeLangSet:
872 FcLangSetDestroy (FcLangSetPtrU(value.u.li));
873 break;
874 default:
875 break;
876 }
877 bail1:
878 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
879 free (FcValueListPtrU(new));
880 bail0:
881 return FcFalse;
882 }
883
884 FcBool
885 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
886 {
887 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
888 }
889
890 FcBool
891 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
892 {
893 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
894 }
895
896 FcBool
897 FcPatternDel (FcPattern *p, const char *object)
898 {
899 FcPatternElt *e;
900
901 e = FcPatternFindElt (p, object);
902 if (!e)
903 return FcFalse;
904
905 /* destroy value */
906 FcValueListDestroy (e->values);
907
908 /* shuffle existing ones down */
909 memmove (e, e+1,
910 (FcPatternEltU(p->elts) + p->num - (e + 1)) *
911 sizeof (FcPatternElt));
912 p->num--;
913 (FcPatternEltU(p->elts)+p->num)->object = 0;
914 (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
915 return FcTrue;
916 }
917
918 FcBool
919 FcPatternRemove (FcPattern *p, const char *object, int id)
920 {
921 FcPatternElt *e;
922 FcValueListPtr *prev, l;
923
924 e = FcPatternFindElt (p, object);
925 if (!e)
926 return FcFalse;
927 for (prev = &e->values;
928 FcValueListPtrU(l = *prev);
929 prev = &FcValueListPtrU(l)->next)
930 {
931 if (!id)
932 {
933 *prev = FcValueListPtrU(l)->next;
934 FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
935 FcValueListDestroy (l);
936 if (!FcValueListPtrU(e->values))
937 FcPatternDel (p, object);
938 return FcTrue;
939 }
940 id--;
941 }
942 return FcFalse;
943 }
944
945 FcBool
946 FcPatternAddInteger (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
955 FcBool
956 FcPatternAddDouble (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
966 FcBool
967 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
968 {
969 FcValue v;
970
971 v.type = FcTypeString;
972 v.u.si = FcObjectStaticName(s);
973 return FcPatternAdd (p, object, v, FcTrue);
974 }
975
976 FcBool
977 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
978 {
979 FcValue v;
980
981 v.type = FcTypeMatrix;
982 v.u.mi = FcMatrixPtrCreateDynamic((FcMatrix *) s);
983 return FcPatternAdd (p, object, v, FcTrue);
984 }
985
986
987 FcBool
988 FcPatternAddBool (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
997 FcBool
998 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
999 {
1000 FcValue v;
1001
1002 v.type = FcTypeCharSet;
1003 v.u.ci = FcCharSetPtrCreateDynamic((FcCharSet *)c);
1004 return FcPatternAdd (p, object, v, FcTrue);
1005 }
1006
1007 FcBool
1008 FcPatternAddFTFace (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
1017 FcBool
1018 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1019 {
1020 FcValue v;
1021
1022 v.type = FcTypeLangSet;
1023 v.u.li = FcLangSetPtrCreateDynamic((FcLangSet *)ls);
1024 return FcPatternAdd (p, object, v, FcTrue);
1025 }
1026
1027 FcResult
1028 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
1029 {
1030 FcPatternElt *e;
1031 FcValueListPtr l;
1032
1033 e = FcPatternFindElt (p, object);
1034 if (!e)
1035 return FcResultNoMatch;
1036 for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
1037 {
1038 if (!id)
1039 {
1040 *v = FcValueListPtrU(l)->value;
1041 return FcResultMatch;
1042 }
1043 id--;
1044 }
1045 return FcResultNoId;
1046 }
1047
1048 FcResult
1049 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
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
1070 FcResult
1071 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
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
1092 FcResult
1093 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
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;
1103 *s = (FcChar8 *) FcObjectPtrU(v.u.si);
1104 return FcResultMatch;
1105 }
1106
1107 FcResult
1108 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
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;
1118 *m = FcMatrixPtrU(v.u.mi);
1119 return FcResultMatch;
1120 }
1121
1122
1123 FcResult
1124 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
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
1138 FcResult
1139 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
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;
1149 *c = FcCharSetPtrU(v.u.ci);
1150 return FcResultMatch;
1151 }
1152
1153 FcResult
1154 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
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
1168 FcResult
1169 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
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;
1179 *ls = FcLangSetPtrU(v.u.li);
1180 return FcResultMatch;
1181 }
1182
1183 FcPattern *
1184 FcPatternDuplicate (const FcPattern *orig)
1185 {
1186 FcPattern *new;
1187 FcPatternElt *e;
1188 int i;
1189 FcValueListPtr l;
1190
1191 new = FcPatternCreate ();
1192 if (!new)
1193 goto bail0;
1194
1195 e = FcPatternEltU(orig->elts);
1196
1197 for (i = 0; i < orig->num; i++)
1198 {
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))
1204 goto bail1;
1205 }
1206
1207 return new;
1208
1209 bail1:
1210 FcPatternDestroy (new);
1211 bail0:
1212 return 0;
1213 }
1214
1215 void
1216 FcPatternReference (FcPattern *p)
1217 {
1218 if (p->ref != FC_REF_CONSTANT)
1219 p->ref++;
1220 }
1221
1222 FcPattern *
1223 FcPatternVaBuild (FcPattern *orig, va_list va)
1224 {
1225 FcPattern *ret;
1226
1227 FcPatternVapBuild (ret, orig, va);
1228 return ret;
1229 }
1230
1231 FcPattern *
1232 FcPatternBuild (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 }
1241
1242 /*
1243 * Add all of the elements in 's' to 'p'
1244 */
1245 FcBool
1246 FcPatternAppend (FcPattern *p, FcPattern *s)
1247 {
1248 int i;
1249 FcPatternElt *e;
1250 FcValueListPtr v;
1251
1252 for (i = 0; i < s->num; i++)
1253 {
1254 e = FcPatternEltU(s->elts)+i;
1255 for (v = e->values; FcValueListPtrU(v);
1256 v = FcValueListPtrU(v)->next)
1257 {
1258 if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1259 FcValueListPtrU(v)->value,
1260 FcValueListPtrU(v)->binding, FcTrue))
1261 return FcFalse;
1262 }
1263 }
1264 return FcTrue;
1265 }
1266
1267 FcPatternElt *
1268 FcPatternEltU (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
1282 static FcPatternEltPtr
1283 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1284 {
1285 FcPatternEltPtr new;
1286 new.storage = FcStorageDynamic;
1287 new.u.dyn = e;
1288 return new;
1289 }
1290
1291 static FcPatternEltPtr
1292 FcPatternEltPtrCreateStatic (int i)
1293 {
1294 FcPatternEltPtr new;
1295 new.storage = FcStorageStatic;
1296 new.u.stat = i;
1297 return new;
1298 }
1299
1300 static FcBool
1301 FcPatternEltIsDynamic (FcPatternEltPtr pei)
1302 {
1303 return pei.storage == FcStorageDynamic;
1304 }
1305
1306
1307 void
1308 FcPatternClearStatic (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
1319 void
1320 FcValueListClearStatic (void)
1321 {
1322 fcvaluelists = 0;
1323 fcvaluelist_ptr = 0;
1324 fcvaluelist_count = 0;
1325 }
1326
1327 static FcObjectPtr
1328 FcObjectSerialize (FcObjectPtr si);
1329
1330 FcBool
1331 FcPatternPrepareSerialize (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
1350 FcBool
1351 FcValueListPrepareSerialize (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
1383 FcPattern *
1384 FcPatternSerialize (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
1458 FcValueListPtr
1459 FcValueListSerialize(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
1526 FcValueList *
1527 FcValueListPtrU (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
1541 FcValueListPtr
1542 FcValueListPtrCreateDynamic(FcValueList * p)
1543 {
1544 FcValueListPtr r;
1545
1546 r.storage = FcStorageDynamic;
1547 r.u.dyn = p;
1548 return r;
1549 }
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 */
1560 static int objectptr_count = 1;
1561 static int objectptr_alloc = 0;
1562 static int * objectptr_indices = 0;
1563
1564 /* invariant: objectcontent_static_buf must be sorted. */
1565 /* e.g. objectptr_static_buf = "name\0style\0weight\0" */
1566 static int objectcontent_static_bytes = 0;
1567 static char * objectcontent_static_buf;
1568
1569 /* just a bunch of strings. */
1570 static int objectcontent_dynamic_count = 1;
1571 static int objectcontent_dynamic_alloc = 0;
1572 static const char ** objectcontent_dynamic = 0;
1573 static int * objectcontent_dynamic_refcount = 0;
1574
1575 #define OBJECT_HASH_SIZE 31
1576 struct objectBucket {
1577 struct objectBucket *next;
1578 FcChar32 hash;
1579 };
1580 static struct objectBucket **FcObjectBuckets = 0;
1581
1582 FcObjectPtr
1583 FcObjectStaticName (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
1592 if (!FcObjectBuckets)
1593 {
1594 FcObjectBuckets = malloc(sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1595 memset (FcObjectBuckets, 0, sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1596 }
1597
1598 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
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
1645 size = sizeof (struct objectBucket) + strlen (name) + 1;
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
1669 void
1670 FcObjectPtrDestroy (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
1687 const char *
1688 FcObjectPtrU (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
1696 static FcBool objectptr_first_serialization = FcFalse;
1697 static int * object_old_id_to_new = 0;
1698
1699 static void
1700 FcObjectRebuildStaticNameHashtable (void)
1701 {
1702 int i;
1703 struct objectBucket *b, *bn;
1704
1705 if (FcObjectBuckets)
1706 {
1707 for (i = 0; i < OBJECT_HASH_SIZE; i++)
1708 {
1709 b = FcObjectBuckets[i];
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 }
1719 free (FcObjectBuckets);
1720 }
1721
1722 FcObjectBuckets = malloc(sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1723 memset (FcObjectBuckets, 0, sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
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
1734 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p);
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.) */
1754 static FcBool
1755 FcObjectPtrConvertToStatic(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
1870 int
1871 FcObjectPtrCompare (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
1892 void
1893 FcObjectClearStatic(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
1910 static FcObjectPtr
1911 FcObjectSerialize (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). */
1924 FcBool
1925 FcObjectPrepareSerialize (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 }
1944
1945 static void
1946 FcObjectStaticNameFini (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
1966 void
1967 FcPatternFini (void)
1968 {
1969 FcPatternBaseThawAll ();
1970 FcValueListThawAll ();
1971 FcObjectStaticNameFini ();
1972 }