]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Convert ObjectPtr from a fat structure to a simple index into an id table;
[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 void
655 FcPatternThawAll (void)
656 {
657 FcPatternBaseThawAll ();
658 FcValueListThawAll ();
659 }
660
661 static int
662 FcPatternPosition (const FcPattern *p, const char *object)
663 {
664 int low, high, mid, c;
665 FcObjectPtr obj;
666
667 obj = FcObjectStaticName(object);
668 low = 0;
669 high = p->num - 1;
670 c = 1;
671 mid = 0;
672 while (low <= high)
673 {
674 mid = (low + high) >> 1;
675 c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
676 if (c == 0)
677 return mid;
678 if (c < 0)
679 low = mid + 1;
680 else
681 high = mid - 1;
682 }
683 if (c < 0)
684 mid++;
685 return -(mid + 1);
686 }
687
688 FcPatternElt *
689 FcPatternFindElt (const FcPattern *p, const char *object)
690 {
691 int i = FcPatternPosition (p, object);
692 if (i < 0)
693 return 0;
694 return FcPatternEltU(p->elts)+i;
695 }
696
697 FcPatternElt *
698 FcPatternInsertElt (FcPattern *p, const char *object)
699 {
700 int i;
701 FcPatternElt *e;
702
703 i = FcPatternPosition (p, object);
704 if (i < 0)
705 {
706 i = -i - 1;
707
708 /* reallocate array */
709 if (p->num + 1 >= p->size)
710 {
711 int s = p->size + 16;
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 }
723 else
724 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
725 if (!e)
726 return FcFalse;
727 p->elts = FcPatternEltPtrCreateDynamic(e);
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 {
733 (FcPatternEltU(p->elts)+p->size)->object = 0;
734 (FcPatternEltU(p->elts)+p->size)->values =
735 FcValueListPtrCreateDynamic(0);
736 p->size++;
737 }
738 }
739
740 /* move elts up */
741 memmove (FcPatternEltU(p->elts) + i + 1,
742 FcPatternEltU(p->elts) + i,
743 sizeof (FcPatternElt) *
744 (p->num - i));
745
746 /* bump count */
747 p->num++;
748
749 (FcPatternEltU(p->elts)+i)->object = FcObjectStaticName (object);
750 (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
751 }
752
753 return FcPatternEltU(p->elts)+i;
754 }
755
756 FcBool
757 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
758 {
759 int i;
760
761 if (pa == pb)
762 return FcTrue;
763
764 if (pa->num != pb->num)
765 return FcFalse;
766 for (i = 0; i < pa->num; i++)
767 {
768 if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
769 (FcPatternEltU(pb->elts)+i)->object) != 0)
770 return FcFalse;
771 if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values,
772 (FcPatternEltU(pb->elts)+i)->values))
773 return FcFalse;
774 }
775 return FcTrue;
776 }
777
778 FcChar32
779 FcPatternHash (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)) ^
787 FcStringHash ((const FcChar8 *) FcObjectPtrU(((FcPatternEltU(p->elts)+i)->object))) ^
788 FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
789 }
790 return h;
791 }
792
793 FcBool
794 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
795 {
796 FcPatternElt *ea, *eb;
797 int i;
798
799 for (i = 0; i < os->nobject; i++)
800 {
801 ea = FcPatternFindElt (pai, FcObjectPtrU(os->objects[i]));
802 eb = FcPatternFindElt (pbi, FcObjectPtrU(os->objects[i]));
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
819 FcBool
820 FcPatternAddWithBinding (FcPattern *p,
821 const char *object,
822 FcValue value,
823 FcValueBinding binding,
824 FcBool append)
825 {
826 FcPatternElt *e;
827 FcValueListPtr new, *prev;
828 FcValueList * newp;
829
830 if (p->ref == FC_REF_CONSTANT)
831 goto bail0;
832
833 newp = malloc (sizeof (FcValueList));
834 if (!newp)
835 goto bail0;
836
837 memset(newp, 0, sizeof (FcValueList));
838 new = FcValueListPtrCreateDynamic(newp);
839 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
840 /* dup string */
841 value = FcValueSave (value);
842 if (value.type == FcTypeVoid)
843 goto bail1;
844
845 FcValueListPtrU(new)->value = value;
846 FcValueListPtrU(new)->binding = binding;
847 FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
848
849 e = FcPatternInsertElt (p, object);
850 if (!e)
851 goto bail2;
852
853 if (append)
854 {
855 for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
856 ;
857 *prev = new;
858 }
859 else
860 {
861 FcValueListPtrU(new)->next = e->values;
862 e->values = new;
863 }
864
865 return FcTrue;
866
867 bail2:
868 switch (value.type) {
869 case FcTypeString:
870 FcStrFree ((FcChar8 *) FcObjectPtrU(value.u.si));
871 break;
872 case FcTypeMatrix:
873 FcMatrixFree (FcMatrixPtrU(value.u.mi));
874 break;
875 case FcTypeCharSet:
876 FcCharSetDestroy (FcCharSetPtrU(value.u.ci));
877 break;
878 case FcTypeLangSet:
879 FcLangSetDestroy (FcLangSetPtrU(value.u.li));
880 break;
881 default:
882 break;
883 }
884 bail1:
885 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
886 free (FcValueListPtrU(new));
887 bail0:
888 return FcFalse;
889 }
890
891 FcBool
892 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
893 {
894 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
895 }
896
897 FcBool
898 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
899 {
900 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
901 }
902
903 FcBool
904 FcPatternDel (FcPattern *p, const char *object)
905 {
906 FcPatternElt *e;
907
908 e = FcPatternFindElt (p, object);
909 if (!e)
910 return FcFalse;
911
912 /* destroy value */
913 FcValueListDestroy (e->values);
914
915 /* shuffle existing ones down */
916 memmove (e, e+1,
917 (FcPatternEltU(p->elts) + p->num - (e + 1)) *
918 sizeof (FcPatternElt));
919 p->num--;
920 (FcPatternEltU(p->elts)+p->num)->object = 0;
921 (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
922 return FcTrue;
923 }
924
925 FcBool
926 FcPatternRemove (FcPattern *p, const char *object, int id)
927 {
928 FcPatternElt *e;
929 FcValueListPtr *prev, l;
930
931 e = FcPatternFindElt (p, object);
932 if (!e)
933 return FcFalse;
934 for (prev = &e->values;
935 FcValueListPtrU(l = *prev);
936 prev = &FcValueListPtrU(l)->next)
937 {
938 if (!id)
939 {
940 *prev = FcValueListPtrU(l)->next;
941 FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
942 FcValueListDestroy (l);
943 if (!FcValueListPtrU(e->values))
944 FcPatternDel (p, object);
945 return FcTrue;
946 }
947 id--;
948 }
949 return FcFalse;
950 }
951
952 FcBool
953 FcPatternAddInteger (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
962 FcBool
963 FcPatternAddDouble (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
973 FcBool
974 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
975 {
976 FcValue v;
977
978 v.type = FcTypeString;
979 v.u.si = FcObjectStaticName(s);
980 return FcPatternAdd (p, object, v, FcTrue);
981 }
982
983 FcBool
984 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
985 {
986 FcValue v;
987
988 v.type = FcTypeMatrix;
989 v.u.mi = FcMatrixPtrCreateDynamic((FcMatrix *) s);
990 return FcPatternAdd (p, object, v, FcTrue);
991 }
992
993
994 FcBool
995 FcPatternAddBool (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
1004 FcBool
1005 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
1006 {
1007 FcValue v;
1008
1009 v.type = FcTypeCharSet;
1010 v.u.ci = FcCharSetPtrCreateDynamic((FcCharSet *)c);
1011 return FcPatternAdd (p, object, v, FcTrue);
1012 }
1013
1014 FcBool
1015 FcPatternAddFTFace (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
1024 FcBool
1025 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1026 {
1027 FcValue v;
1028
1029 v.type = FcTypeLangSet;
1030 v.u.li = FcLangSetPtrCreateDynamic((FcLangSet *)ls);
1031 return FcPatternAdd (p, object, v, FcTrue);
1032 }
1033
1034 FcResult
1035 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
1036 {
1037 FcPatternElt *e;
1038 FcValueListPtr l;
1039
1040 e = FcPatternFindElt (p, object);
1041 if (!e)
1042 return FcResultNoMatch;
1043 for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
1044 {
1045 if (!id)
1046 {
1047 *v = FcValueListPtrU(l)->value;
1048 return FcResultMatch;
1049 }
1050 id--;
1051 }
1052 return FcResultNoId;
1053 }
1054
1055 FcResult
1056 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
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
1077 FcResult
1078 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
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
1099 FcResult
1100 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
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;
1110 *s = (FcChar8 *) FcObjectPtrU(v.u.si);
1111 return FcResultMatch;
1112 }
1113
1114 FcResult
1115 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
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;
1125 *m = FcMatrixPtrU(v.u.mi);
1126 return FcResultMatch;
1127 }
1128
1129
1130 FcResult
1131 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
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
1145 FcResult
1146 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
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;
1156 *c = FcCharSetPtrU(v.u.ci);
1157 return FcResultMatch;
1158 }
1159
1160 FcResult
1161 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
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
1175 FcResult
1176 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
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;
1186 *ls = FcLangSetPtrU(v.u.li);
1187 return FcResultMatch;
1188 }
1189
1190 FcPattern *
1191 FcPatternDuplicate (const FcPattern *orig)
1192 {
1193 FcPattern *new;
1194 FcPatternElt *e;
1195 int i;
1196 FcValueListPtr l;
1197
1198 new = FcPatternCreate ();
1199 if (!new)
1200 goto bail0;
1201
1202 e = FcPatternEltU(orig->elts);
1203
1204 for (i = 0; i < orig->num; i++)
1205 {
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))
1211 goto bail1;
1212 }
1213
1214 return new;
1215
1216 bail1:
1217 FcPatternDestroy (new);
1218 bail0:
1219 return 0;
1220 }
1221
1222 void
1223 FcPatternReference (FcPattern *p)
1224 {
1225 if (p->ref != FC_REF_CONSTANT)
1226 p->ref++;
1227 }
1228
1229 FcPattern *
1230 FcPatternVaBuild (FcPattern *orig, va_list va)
1231 {
1232 FcPattern *ret;
1233
1234 FcPatternVapBuild (ret, orig, va);
1235 return ret;
1236 }
1237
1238 FcPattern *
1239 FcPatternBuild (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 }
1248
1249 /*
1250 * Add all of the elements in 's' to 'p'
1251 */
1252 FcBool
1253 FcPatternAppend (FcPattern *p, FcPattern *s)
1254 {
1255 int i;
1256 FcPatternElt *e;
1257 FcValueListPtr v;
1258
1259 for (i = 0; i < s->num; i++)
1260 {
1261 e = FcPatternEltU(s->elts)+i;
1262 for (v = e->values; FcValueListPtrU(v);
1263 v = FcValueListPtrU(v)->next)
1264 {
1265 if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1266 FcValueListPtrU(v)->value,
1267 FcValueListPtrU(v)->binding, FcTrue))
1268 return FcFalse;
1269 }
1270 }
1271 return FcTrue;
1272 }
1273
1274 FcPatternElt *
1275 FcPatternEltU (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
1289 static FcPatternEltPtr
1290 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1291 {
1292 FcPatternEltPtr new;
1293 new.storage = FcStorageDynamic;
1294 new.u.dyn = e;
1295 return new;
1296 }
1297
1298 static FcPatternEltPtr
1299 FcPatternEltPtrCreateStatic (int i)
1300 {
1301 FcPatternEltPtr new;
1302 new.storage = FcStorageStatic;
1303 new.u.stat = i;
1304 return new;
1305 }
1306
1307 static FcBool
1308 FcPatternEltIsDynamic (FcPatternEltPtr pei)
1309 {
1310 return pei.storage == FcStorageDynamic;
1311 }
1312
1313
1314 void
1315 FcPatternClearStatic (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
1326 void
1327 FcValueListClearStatic (void)
1328 {
1329 fcvaluelists = 0;
1330 fcvaluelist_ptr = 0;
1331 fcvaluelist_count = 0;
1332 }
1333
1334 static FcObjectPtr
1335 FcObjectSerialize (FcObjectPtr si);
1336
1337 FcBool
1338 FcPatternPrepareSerialize (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
1357 FcBool
1358 FcValueListPrepareSerialize (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
1390 FcPattern *
1391 FcPatternSerialize (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
1465 FcValueListPtr
1466 FcValueListSerialize(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
1533 FcValueList *
1534 FcValueListPtrU (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
1548 FcValueListPtr
1549 FcValueListPtrCreateDynamic(FcValueList * p)
1550 {
1551 FcValueListPtr r;
1552
1553 r.storage = FcStorageDynamic;
1554 r.u.dyn = p;
1555 return r;
1556 }
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 */
1567 static int objectptr_count = 1;
1568 static int objectptr_alloc = 0;
1569 static int * objectptr_indices = 0;
1570
1571 /* invariant: objectcontent_static_buf must be sorted. */
1572 /* e.g. objectptr_static_buf = "name\0style\0weight\0" */
1573 static int objectcontent_static_bytes = 0;
1574 static char * objectcontent_static_buf;
1575
1576 /* just a bunch of strings. */
1577 static int objectcontent_dynamic_count = 1;
1578 static int objectcontent_dynamic_alloc = 0;
1579 static const char ** objectcontent_dynamic = 0;
1580 static int * objectcontent_dynamic_refcount = 0;
1581
1582 #define OBJECT_HASH_SIZE 31
1583 struct objectBucket {
1584 struct objectBucket *next;
1585 FcChar32 hash;
1586 };
1587 static struct objectBucket **buckets = 0;
1588
1589 FcObjectPtr
1590 FcObjectStaticName (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
1676 void
1677 FcObjectPtrDestroy (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
1694 const char *
1695 FcObjectPtrU (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
1703 static FcBool objectptr_first_serialization = FcFalse;
1704 static int * object_old_id_to_new = 0;
1705
1706 static void
1707 FcObjectRebuildStaticNameHashtable (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.) */
1761 static FcBool
1762 FcObjectPtrConvertToStatic(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
1877 int
1878 FcObjectPtrCompare (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
1899 void
1900 FcObjectClearStatic(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
1917 static FcObjectPtr
1918 FcObjectSerialize (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). */
1931 FcBool
1932 FcObjectPrepareSerialize (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 }