]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Added new FcFini function for cleaning up all memory. Fixed a few memory
[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 "fcint.h"
29
30 FcPattern *
31 FcPatternCreate (void)
32 {
33 FcPattern *p;
34
35 p = (FcPattern *) malloc (sizeof (FcPattern));
36 if (!p)
37 return 0;
38 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
39 p->num = 0;
40 p->size = 0;
41 p->elts = 0;
42 p->ref = 1;
43 return p;
44 }
45
46 void
47 FcValueDestroy (FcValue v)
48 {
49 switch (v.type) {
50 case FcTypeString:
51 FcStrFree ((FcChar8 *) v.u.s);
52 break;
53 case FcTypeMatrix:
54 FcMatrixFree ((FcMatrix *) v.u.m);
55 break;
56 case FcTypeCharSet:
57 FcCharSetDestroy ((FcCharSet *) v.u.c);
58 break;
59 case FcTypeLangSet:
60 FcLangSetDestroy ((FcLangSet *) v.u.l);
61 break;
62 default:
63 break;
64 }
65 }
66
67 FcValue
68 FcValueSave (FcValue v)
69 {
70 switch (v.type) {
71 case FcTypeString:
72 v.u.s = FcStrCopy (v.u.s);
73 if (!v.u.s)
74 v.type = FcTypeVoid;
75 break;
76 case FcTypeMatrix:
77 v.u.m = FcMatrixCopy (v.u.m);
78 if (!v.u.m)
79 v.type = FcTypeVoid;
80 break;
81 case FcTypeCharSet:
82 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
83 if (!v.u.c)
84 v.type = FcTypeVoid;
85 break;
86 case FcTypeLangSet:
87 v.u.l = FcLangSetCopy (v.u.l);
88 if (!v.u.l)
89 v.type = FcTypeVoid;
90 break;
91 default:
92 break;
93 }
94 return v;
95 }
96
97 void
98 FcValueListDestroy (FcValueList *l)
99 {
100 FcValueList *next;
101 for (; l; l = next)
102 {
103 switch (l->value.type) {
104 case FcTypeString:
105 FcStrFree ((FcChar8 *) l->value.u.s);
106 break;
107 case FcTypeMatrix:
108 FcMatrixFree ((FcMatrix *) l->value.u.m);
109 break;
110 case FcTypeCharSet:
111 FcCharSetDestroy ((FcCharSet *) l->value.u.c);
112 break;
113 case FcTypeLangSet:
114 FcLangSetDestroy ((FcLangSet *) l->value.u.l);
115 break;
116 default:
117 break;
118 }
119 next = l->next;
120 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
121 free (l);
122 }
123 }
124
125 FcBool
126 FcValueEqual (FcValue va, FcValue vb)
127 {
128 if (va.type != vb.type)
129 {
130 if (va.type == FcTypeInteger)
131 {
132 va.type = FcTypeDouble;
133 va.u.d = va.u.i;
134 }
135 if (vb.type == FcTypeInteger)
136 {
137 vb.type = FcTypeDouble;
138 vb.u.d = vb.u.i;
139 }
140 if (va.type != vb.type)
141 return FcFalse;
142 }
143 switch (va.type) {
144 case FcTypeVoid:
145 return FcTrue;
146 case FcTypeInteger:
147 return va.u.i == vb.u.i;
148 case FcTypeDouble:
149 return va.u.d == vb.u.d;
150 case FcTypeString:
151 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
152 case FcTypeBool:
153 return va.u.b == vb.u.b;
154 case FcTypeMatrix:
155 return FcMatrixEqual (va.u.m, vb.u.m);
156 case FcTypeCharSet:
157 return FcCharSetEqual (va.u.c, vb.u.c);
158 case FcTypeFTFace:
159 return va.u.f == vb.u.f;
160 case FcTypeLangSet:
161 return FcLangSetEqual (va.u.l, vb.u.l);
162 }
163 return FcFalse;
164 }
165
166 static FcChar32
167 FcDoubleHash (double d)
168 {
169 if (d < 0)
170 d = -d;
171 if (d > 0xffffffff)
172 d = 0xffffffff;
173 return (FcChar32) d;
174 }
175
176 static FcChar32
177 FcStringHash (const FcChar8 *s)
178 {
179 FcChar8 c;
180 FcChar32 h = 0;
181
182 if (s)
183 while ((c = *s++))
184 h = ((h << 1) | (h >> 31)) ^ c;
185 return h;
186 }
187
188 static FcChar32
189 FcValueHash (FcValue v)
190 {
191 switch (v.type) {
192 case FcTypeVoid:
193 return 0;
194 case FcTypeInteger:
195 return (FcChar32) v.u.i;
196 case FcTypeDouble:
197 return FcDoubleHash (v.u.d);
198 case FcTypeString:
199 return FcStringHash (v.u.s);
200 case FcTypeBool:
201 return (FcChar32) v.u.b;
202 case FcTypeMatrix:
203 return (FcDoubleHash (v.u.m->xx) ^
204 FcDoubleHash (v.u.m->xy) ^
205 FcDoubleHash (v.u.m->yx) ^
206 FcDoubleHash (v.u.m->yy));
207 case FcTypeCharSet:
208 return (FcChar32) v.u.c->num;
209 case FcTypeFTFace:
210 return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
211 FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
212 case FcTypeLangSet:
213 return FcLangSetHash (v.u.l);
214 }
215 return FcFalse;
216 }
217
218 static FcBool
219 FcValueListEqual (FcValueList *la, FcValueList *lb)
220 {
221 if (la == lb)
222 return FcTrue;
223
224 while (la && lb)
225 {
226 if (!FcValueEqual (la->value, lb->value))
227 return FcFalse;
228 la = la->next;
229 lb = lb->next;
230 }
231 if (la || lb)
232 return FcFalse;
233 return FcTrue;
234 }
235
236 static FcChar32
237 FcValueListHash (FcValueList *l)
238 {
239 FcChar32 hash = 0;
240
241 while (l)
242 {
243 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
244 l = l->next;
245 }
246 return hash;
247 }
248
249 void
250 FcPatternDestroy (FcPattern *p)
251 {
252 int i;
253
254 if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
255 return;
256
257 for (i = 0; i < p->num; i++)
258 FcValueListDestroy (p->elts[i].values);
259
260 p->num = 0;
261 if (p->elts)
262 {
263 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
264 free (p->elts);
265 p->elts = 0;
266 }
267 p->size = 0;
268 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
269 free (p);
270 }
271
272 #define FC_VALUE_LIST_HASH_SIZE 257
273 #define FC_PATTERN_HASH_SIZE 67
274
275 typedef struct _FcValueListEnt FcValueListEnt;
276
277 struct _FcValueListEnt {
278 FcValueListEnt *next;
279 FcValueList *list;
280 FcChar32 hash, pad;
281 };
282
283 typedef union _FcValueListAlign {
284 FcValueListEnt ent;
285 FcValueList list;
286 } FcValueListAlign;
287
288 static int FcValueListFrozenCount[FcTypeLangSet + 1];
289 static int FcValueListFrozenBytes[FcTypeLangSet + 1];
290 static char *FcValueListFrozenName[] = {
291 "Void",
292 "Integer",
293 "Double",
294 "String",
295 "Bool",
296 "Matrix",
297 "CharSet",
298 "FTFace",
299 "LangSet"
300 };
301
302 void
303 FcValueListReport (void);
304
305 void
306 FcValueListReport (void)
307 {
308 FcType t;
309
310 printf ("Fc Frozen Values:\n");
311 printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
312 for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
313 printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
314 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
315 }
316
317 static FcValueListEnt *
318 FcValueListEntCreate (FcValueList *h)
319 {
320 FcValueListAlign *ea;
321 FcValueListEnt *e;
322 FcValueList *l, *new;
323 int n;
324 int string_size = 0;
325 FcChar8 *strs;
326 int size;
327
328 n = 0;
329 for (l = h; l; l = l->next)
330 {
331 if (l->value.type == FcTypeString)
332 string_size += strlen ((char *) l->value.u.s) + 1;
333 n++;
334 }
335 size = sizeof (FcValueListAlign) + n * sizeof (FcValueList) + string_size;
336 FcValueListFrozenCount[h->value.type]++;
337 FcValueListFrozenBytes[h->value.type] += size;
338 ea = malloc (size);
339 if (!ea)
340 return 0;
341 FcMemAlloc (FC_MEM_VALLIST, size);
342 e = &ea->ent;
343 e->list = (FcValueList *) (ea + 1);
344 strs = (FcChar8 *) (e->list + n);
345 new = e->list;
346 for (l = h; l; l = l->next, new++)
347 {
348 if (l->value.type == FcTypeString)
349 {
350 new->value.type = FcTypeString;
351 new->value.u.s = strs;
352 strcpy ((char *) strs, (char *) l->value.u.s);
353 strs += strlen ((char *) strs) + 1;
354 }
355 else
356 {
357 new->value = l->value;
358 new->value = FcValueSave (new->value);
359 }
360 new->binding = l->binding;
361 if (l->next)
362 new->next = new + 1;
363 else
364 new->next = 0;
365 }
366 return e;
367 }
368
369 static void
370 FcValueListEntDestroy (FcValueListEnt *e)
371 {
372 FcValueList *l;
373
374 FcValueListFrozenCount[e->list->value.type]--;
375
376 /* XXX: We should perform these two operations with "size" as
377 computed in FcValueListEntCreate, but we don't have access to
378 that value here. Without this, the FcValueListFrozenBytes
379 values will be wrong as will the FcMemFree counts.
380
381 FcValueListFrozenBytes[e->list->value.type] -= size;
382 FcMemFree (FC_MEM_VALLIST, size);
383 */
384
385 for (l = e->list; l; l = l->next)
386 {
387 if (l->value.type != FcTypeString)
388 FcValueDestroy (l->value);
389 }
390 /* XXX: Are we being too chummy with the implementation here to
391 free(e) when it was actually the enclosing FcValueListAlign
392 that was allocated? */
393 free (e);
394 }
395
396 static int FcValueListTotal;
397 static int FcValueListUsed;
398
399 static FcValueListEnt *FcValueListHashTable[FC_VALUE_LIST_HASH_SIZE];
400
401 static FcValueList *
402 FcValueListFreeze (FcValueList *l)
403 {
404 FcChar32 hash = FcValueListHash (l);
405 FcValueListEnt **bucket = &FcValueListHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
406 FcValueListEnt *ent;
407
408 FcValueListTotal++;
409 for (ent = *bucket; ent; ent = ent->next)
410 {
411 if (ent->hash == hash && FcValueListEqual (ent->list, l))
412 return ent->list;
413 }
414
415 ent = FcValueListEntCreate (l);
416 if (!ent)
417 return 0;
418
419 FcValueListUsed++;
420 ent->hash = hash;
421 ent->next = *bucket;
422 *bucket = ent;
423 return ent->list;
424 }
425
426 static void
427 FcValueListThawAll (void)
428 {
429 int i;
430 FcValueListEnt *ent, *next;
431
432 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
433 {
434 for (ent = FcValueListHashTable[i]; ent; ent = next)
435 {
436 next = ent->next;
437 FcValueListEntDestroy (ent);
438 }
439 FcValueListHashTable[i] = 0;
440 }
441
442 FcValueListTotal = 0;
443 FcValueListUsed = 0;
444 }
445
446 static FcChar32
447 FcPatternBaseHash (FcPattern *b)
448 {
449 FcChar32 hash = b->num;
450 int i;
451
452 for (i = 0; i < b->num; i++)
453 hash = ((hash << 1) | (hash >> 31)) ^ ((long) b->elts[i].values);
454 return hash;
455 }
456
457 typedef struct _FcPatternEnt FcPatternEnt;
458
459 struct _FcPatternEnt {
460 FcPatternEnt *next;
461 FcChar32 hash;
462 FcPattern pattern;
463 };
464
465 static int FcPatternTotal;
466 static int FcPatternUsed;
467
468 static FcPatternEnt *FcPatternHashTable[FC_VALUE_LIST_HASH_SIZE];
469
470 static FcPattern *
471 FcPatternBaseFreeze (FcPattern *b)
472 {
473 FcChar32 hash = FcPatternBaseHash (b);
474 FcPatternEnt **bucket = &FcPatternHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
475 FcPatternEnt *ent;
476 int i;
477 char *objects;
478 int size_objects;
479 int size;
480
481 FcPatternTotal++;
482 for (ent = *bucket; ent; ent = ent->next)
483 {
484 if (ent->hash == hash && b->num == ent->pattern.num)
485 {
486 for (i = 0; i < b->num; i++)
487 {
488 if (strcmp (b->elts[i].object, ent->pattern.elts[i].object))
489 break;
490 if (b->elts[i].values != ent->pattern.elts[i].values)
491 break;
492 }
493 if (i == b->num)
494 return &ent->pattern;
495 }
496 }
497
498 /*
499 * Compute size of pattern + elts + object names
500 */
501 size_objects = 0;
502 for (i = 0; i < b->num; i++)
503 size_objects += strlen (b->elts[i].object) + 1;
504
505 size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt) + size_objects;
506 ent = malloc (size);
507 if (!ent)
508 return 0;
509
510 FcMemAlloc (FC_MEM_PATTERN, size);
511 FcPatternUsed++;
512
513 ent->pattern.elts = (FcPatternElt *) (ent + 1);
514 ent->pattern.num = b->num;
515 ent->pattern.size = b->num;
516 ent->pattern.ref = FC_REF_CONSTANT;
517
518 objects = (char *) (ent->pattern.elts + b->num);
519 for (i = 0; i < b->num; i++)
520 {
521 ent->pattern.elts[i].values = b->elts[i].values;
522 strcpy (objects, b->elts[i].object);
523 ent->pattern.elts[i].object = objects;
524 objects += strlen (objects) + 1;
525 }
526
527 ent->hash = hash;
528 ent->next = *bucket;
529 *bucket = ent;
530 return &ent->pattern;
531 }
532
533 static void
534 FcPatternBaseThawAll (void)
535 {
536 int i;
537 FcPatternEnt *ent, *next;
538
539 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
540 {
541 for (ent = FcPatternHashTable[i]; ent; ent = next)
542 {
543 next = ent->next;
544 free (ent);
545 }
546 FcPatternHashTable[i] = 0;
547 }
548
549 FcPatternTotal = 0;
550 FcPatternUsed = 0;
551 }
552
553 FcPattern *
554 FcPatternFreeze (FcPattern *p)
555 {
556 FcPattern *b, *n = 0;
557 int size;
558 int i;
559
560 size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
561 b = (FcPattern *) malloc (size);
562 if (!b)
563 return 0;
564 FcMemAlloc (FC_MEM_PATTERN, size);
565 b->num = p->num;
566 b->size = b->num;
567 b->ref = 1;
568 b->elts = (FcPatternElt *) (b + 1);
569 /*
570 * Freeze object lists
571 */
572 for (i = 0; i < p->num; i++)
573 {
574 b->elts[i].object = p->elts[i].object;
575 b->elts[i].values = FcValueListFreeze (p->elts[i].values);
576 if (!b->elts[i].values)
577 goto bail;
578 }
579 /*
580 * Freeze base
581 */
582 n = FcPatternBaseFreeze (b);
583 #ifdef CHATTY
584 if (FcDebug() & FC_DBG_MEMORY)
585 {
586 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
587 printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
588 }
589 #endif
590 bail:
591 free (b);
592 #ifdef DEBUG
593 assert (FcPatternEqual (n, p));
594 #endif
595 return n;
596 }
597
598 void
599 FcPatternThawAll (void)
600 {
601 FcPatternBaseThawAll ();
602 FcValueListThawAll ();
603 }
604
605 static int
606 FcPatternPosition (const FcPattern *p, const char *object)
607 {
608 int low, high, mid, c;
609
610 low = 0;
611 high = p->num - 1;
612 c = 1;
613 mid = 0;
614 while (low <= high)
615 {
616 mid = (low + high) >> 1;
617 c = strcmp (p->elts[mid].object, object);
618 if (c == 0)
619 return mid;
620 if (c < 0)
621 low = mid + 1;
622 else
623 high = mid - 1;
624 }
625 if (c < 0)
626 mid++;
627 return -(mid + 1);
628 }
629
630 FcPatternElt *
631 FcPatternFindElt (const FcPattern *p, const char *object)
632 {
633 int i = FcPatternPosition (p, object);
634 if (i < 0)
635 return 0;
636 return &p->elts[i];
637 }
638
639 FcPatternElt *
640 FcPatternInsertElt (FcPattern *p, const char *object)
641 {
642 int i;
643 FcPatternElt *e;
644
645 i = FcPatternPosition (p, object);
646 if (i < 0)
647 {
648 i = -i - 1;
649
650 /* grow array */
651 if (p->num + 1 >= p->size)
652 {
653 int s = p->size + 16;
654 if (p->elts)
655 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
656 else
657 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
658 if (!e)
659 return FcFalse;
660 p->elts = e;
661 if (p->size)
662 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
663 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
664 while (p->size < s)
665 {
666 p->elts[p->size].object = 0;
667 p->elts[p->size].values = 0;
668 p->size++;
669 }
670 }
671
672 /* move elts up */
673 memmove (p->elts + i + 1,
674 p->elts + i,
675 sizeof (FcPatternElt) *
676 (p->num - i));
677
678 /* bump count */
679 p->num++;
680
681 p->elts[i].object = object;
682 p->elts[i].values = 0;
683 }
684
685 return &p->elts[i];
686 }
687
688 FcBool
689 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
690 {
691 int i;
692
693 if (pa == pb)
694 return FcTrue;
695
696 if (pa->num != pb->num)
697 return FcFalse;
698 for (i = 0; i < pa->num; i++)
699 {
700 if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
701 return FcFalse;
702 if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
703 return FcFalse;
704 }
705 return FcTrue;
706 }
707
708 FcChar32
709 FcPatternHash (const FcPattern *p)
710 {
711 int i;
712 FcChar32 h = 0;
713
714 for (i = 0; i < p->num; i++)
715 {
716 h = (((h << 1) | (h >> 31)) ^
717 FcStringHash ((const FcChar8 *) p->elts[i].object) ^
718 FcValueListHash (p->elts[i].values));
719 }
720 return h;
721 }
722
723 FcBool
724 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
725 {
726 FcPatternElt *ea, *eb;
727 int i;
728
729 for (i = 0; i < os->nobject; i++)
730 {
731 ea = FcPatternFindElt (pa, os->objects[i]);
732 eb = FcPatternFindElt (pb, os->objects[i]);
733 if (ea)
734 {
735 if (!eb)
736 return FcFalse;
737 if (!FcValueListEqual (ea->values, eb->values))
738 return FcFalse;
739 }
740 else
741 {
742 if (eb)
743 return FcFalse;
744 }
745 }
746 return FcTrue;
747 }
748
749 FcBool
750 FcPatternAddWithBinding (FcPattern *p,
751 const char *object,
752 FcValue value,
753 FcValueBinding binding,
754 FcBool append)
755 {
756 FcPatternElt *e;
757 FcValueList *new, **prev;
758
759 if (p->ref == FC_REF_CONSTANT)
760 goto bail0;
761
762 new = (FcValueList *) malloc (sizeof (FcValueList));
763 if (!new)
764 goto bail0;
765
766 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
767 /* dup string */
768 value = FcValueSave (value);
769 if (value.type == FcTypeVoid)
770 goto bail1;
771
772 new->value = value;
773 new->binding = binding;
774 new->next = 0;
775
776 e = FcPatternInsertElt (p, object);
777 if (!e)
778 goto bail2;
779
780 if (append)
781 {
782 for (prev = &e->values; *prev; prev = &(*prev)->next);
783 *prev = new;
784 }
785 else
786 {
787 new->next = e->values;
788 e->values = new;
789 }
790
791 return FcTrue;
792
793 bail2:
794 switch (value.type) {
795 case FcTypeString:
796 FcStrFree ((FcChar8 *) value.u.s);
797 break;
798 case FcTypeMatrix:
799 FcMatrixFree ((FcMatrix *) value.u.m);
800 break;
801 case FcTypeCharSet:
802 FcCharSetDestroy ((FcCharSet *) value.u.c);
803 break;
804 case FcTypeLangSet:
805 FcLangSetDestroy ((FcLangSet *) value.u.l);
806 break;
807 default:
808 break;
809 }
810 bail1:
811 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
812 free (new);
813 bail0:
814 return FcFalse;
815 }
816
817 FcBool
818 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
819 {
820 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
821 }
822
823 FcBool
824 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
825 {
826 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
827 }
828
829 FcBool
830 FcPatternDel (FcPattern *p, const char *object)
831 {
832 FcPatternElt *e;
833 int i;
834
835 e = FcPatternFindElt (p, object);
836 if (!e)
837 return FcFalse;
838
839 i = e - p->elts;
840
841 /* destroy value */
842 FcValueListDestroy (e->values);
843
844 /* shuffle existing ones down */
845 memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
846 p->num--;
847 p->elts[p->num].object = 0;
848 p->elts[p->num].values = 0;
849 return FcTrue;
850 }
851
852 FcBool
853 FcPatternAddInteger (FcPattern *p, const char *object, int i)
854 {
855 FcValue v;
856
857 v.type = FcTypeInteger;
858 v.u.i = i;
859 return FcPatternAdd (p, object, v, FcTrue);
860 }
861
862 FcBool
863 FcPatternAddDouble (FcPattern *p, const char *object, double d)
864 {
865 FcValue v;
866
867 v.type = FcTypeDouble;
868 v.u.d = d;
869 return FcPatternAdd (p, object, v, FcTrue);
870 }
871
872
873 FcBool
874 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
875 {
876 FcValue v;
877
878 v.type = FcTypeString;
879 v.u.s = s;
880 return FcPatternAdd (p, object, v, FcTrue);
881 }
882
883 FcBool
884 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
885 {
886 FcValue v;
887
888 v.type = FcTypeMatrix;
889 v.u.m = (FcMatrix *) s;
890 return FcPatternAdd (p, object, v, FcTrue);
891 }
892
893
894 FcBool
895 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
896 {
897 FcValue v;
898
899 v.type = FcTypeBool;
900 v.u.b = b;
901 return FcPatternAdd (p, object, v, FcTrue);
902 }
903
904 FcBool
905 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
906 {
907 FcValue v;
908
909 v.type = FcTypeCharSet;
910 v.u.c = (FcCharSet *) c;
911 return FcPatternAdd (p, object, v, FcTrue);
912 }
913
914 FcBool
915 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
916 {
917 FcValue v;
918
919 v.type = FcTypeFTFace;
920 v.u.f = (void *) f;
921 return FcPatternAdd (p, object, v, FcTrue);
922 }
923
924 FcBool
925 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
926 {
927 FcValue v;
928
929 v.type = FcTypeLangSet;
930 v.u.l = (FcLangSet *) ls;
931 return FcPatternAdd (p, object, v, FcTrue);
932 }
933
934 FcResult
935 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
936 {
937 FcPatternElt *e;
938 FcValueList *l;
939
940 e = FcPatternFindElt (p, object);
941 if (!e)
942 return FcResultNoMatch;
943 for (l = e->values; l; l = l->next)
944 {
945 if (!id)
946 {
947 *v = l->value;
948 return FcResultMatch;
949 }
950 id--;
951 }
952 return FcResultNoId;
953 }
954
955 FcResult
956 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
957 {
958 FcValue v;
959 FcResult r;
960
961 r = FcPatternGet (p, object, id, &v);
962 if (r != FcResultMatch)
963 return r;
964 switch (v.type) {
965 case FcTypeDouble:
966 *i = (int) v.u.d;
967 break;
968 case FcTypeInteger:
969 *i = v.u.i;
970 break;
971 default:
972 return FcResultTypeMismatch;
973 }
974 return FcResultMatch;
975 }
976
977 FcResult
978 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
979 {
980 FcValue v;
981 FcResult r;
982
983 r = FcPatternGet (p, object, id, &v);
984 if (r != FcResultMatch)
985 return r;
986 switch (v.type) {
987 case FcTypeDouble:
988 *d = v.u.d;
989 break;
990 case FcTypeInteger:
991 *d = (double) v.u.i;
992 break;
993 default:
994 return FcResultTypeMismatch;
995 }
996 return FcResultMatch;
997 }
998
999 FcResult
1000 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1001 {
1002 FcValue v;
1003 FcResult r;
1004
1005 r = FcPatternGet (p, object, id, &v);
1006 if (r != FcResultMatch)
1007 return r;
1008 if (v.type != FcTypeString)
1009 return FcResultTypeMismatch;
1010 *s = (FcChar8 *) v.u.s;
1011 return FcResultMatch;
1012 }
1013
1014 FcResult
1015 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1016 {
1017 FcValue v;
1018 FcResult r;
1019
1020 r = FcPatternGet (p, object, id, &v);
1021 if (r != FcResultMatch)
1022 return r;
1023 if (v.type != FcTypeMatrix)
1024 return FcResultTypeMismatch;
1025 *m = (FcMatrix *) v.u.m;
1026 return FcResultMatch;
1027 }
1028
1029
1030 FcResult
1031 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1032 {
1033 FcValue v;
1034 FcResult r;
1035
1036 r = FcPatternGet (p, object, id, &v);
1037 if (r != FcResultMatch)
1038 return r;
1039 if (v.type != FcTypeBool)
1040 return FcResultTypeMismatch;
1041 *b = v.u.b;
1042 return FcResultMatch;
1043 }
1044
1045 FcResult
1046 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1047 {
1048 FcValue v;
1049 FcResult r;
1050
1051 r = FcPatternGet (p, object, id, &v);
1052 if (r != FcResultMatch)
1053 return r;
1054 if (v.type != FcTypeCharSet)
1055 return FcResultTypeMismatch;
1056 *c = (FcCharSet *) v.u.c;
1057 return FcResultMatch;
1058 }
1059
1060 FcResult
1061 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1062 {
1063 FcValue v;
1064 FcResult r;
1065
1066 r = FcPatternGet (p, object, id, &v);
1067 if (r != FcResultMatch)
1068 return r;
1069 if (v.type != FcTypeFTFace)
1070 return FcResultTypeMismatch;
1071 *f = (FT_Face) v.u.f;
1072 return FcResultMatch;
1073 }
1074
1075 FcResult
1076 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1077 {
1078 FcValue v;
1079 FcResult r;
1080
1081 r = FcPatternGet (p, object, id, &v);
1082 if (r != FcResultMatch)
1083 return r;
1084 if (v.type != FcTypeLangSet)
1085 return FcResultTypeMismatch;
1086 *ls = (FcLangSet *) v.u.l;
1087 return FcResultMatch;
1088 }
1089
1090 FcPattern *
1091 FcPatternDuplicate (const FcPattern *orig)
1092 {
1093 FcPattern *new;
1094 int i;
1095 FcValueList *l;
1096
1097 new = FcPatternCreate ();
1098 if (!new)
1099 goto bail0;
1100
1101 for (i = 0; i < orig->num; i++)
1102 {
1103 for (l = orig->elts[i].values; l; l = l->next)
1104 if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
1105 goto bail1;
1106 }
1107
1108 return new;
1109
1110 bail1:
1111 FcPatternDestroy (new);
1112 bail0:
1113 return 0;
1114 }
1115
1116 void
1117 FcPatternReference (FcPattern *p)
1118 {
1119 if (p->ref != FC_REF_CONSTANT)
1120 p->ref++;
1121 }
1122
1123 FcPattern *
1124 FcPatternVaBuild (FcPattern *orig, va_list va)
1125 {
1126 FcPattern *ret;
1127
1128 FcPatternVapBuild (ret, orig, va);
1129 return ret;
1130 }
1131
1132 FcPattern *
1133 FcPatternBuild (FcPattern *orig, ...)
1134 {
1135 va_list va;
1136
1137 va_start (va, orig);
1138 FcPatternVapBuild (orig, orig, va);
1139 va_end (va);
1140 return orig;
1141 }