]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Fix structure alignment and array wlk bugs
[fontconfig.git] / src / fcpat.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.16tsi Exp $
3 *
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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 static int FcValueListFrozenCount[FcTypeLangSet + 1];
284 static int FcValueListFrozenBytes[FcTypeLangSet + 1];
285 static char *FcValueListFrozenName[] = {
286 "Void",
287 "Integer",
288 "Double",
289 "String",
290 "Bool",
291 "Matrix",
292 "CharSet",
293 "FTFace",
294 "LangSet"
295 };
296
297 void
298 FcValueListReport (void);
299
300 void
301 FcValueListReport (void)
302 {
303 FcType t;
304
305 printf ("Fc Frozen Values:\n");
306 printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
307 for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
308 printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
309 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
310 }
311
312 static FcValueListEnt *
313 FcValueListEntCreate (FcValueList *h)
314 {
315 FcValueListEnt *e;
316 FcValueList *l, *new;
317 int n;
318 int string_size = 0;
319 FcChar8 *strs;
320 int size;
321
322 n = 0;
323 for (l = h; l; l = l->next)
324 {
325 if (l->value.type == FcTypeString)
326 string_size += strlen ((char *) l->value.u.s) + 1;
327 n++;
328 }
329 size = sizeof (FcValueListEnt) + n * sizeof (FcValueList) + string_size;
330 FcValueListFrozenCount[h->value.type]++;
331 FcValueListFrozenBytes[h->value.type] += size;
332 e = malloc (size);
333 if (!e)
334 return 0;
335 FcMemAlloc (FC_MEM_VALLIST, size);
336 e->list = (FcValueList *) (e + 1);
337 strs = (FcChar8 *) (e->list + n);
338 new = e->list;
339 for (l = h; l; l = l->next, new++)
340 {
341 if (l->value.type == FcTypeString)
342 {
343 new->value.type = FcTypeString;
344 new->value.u.s = strs;
345 strcpy ((char *) strs, (char *) l->value.u.s);
346 strs += strlen ((char *) strs) + 1;
347 }
348 else
349 {
350 new->value = l->value;
351 new->value = FcValueSave (new->value);
352 }
353 new->binding = l->binding;
354 if (l->next)
355 new->next = new + 1;
356 else
357 new->next = 0;
358 }
359 return e;
360 }
361
362 static int FcValueListTotal;
363 static int FcValueListUsed;
364
365 static FcValueList *
366 FcValueListFreeze (FcValueList *l)
367 {
368 static FcValueListEnt *hashTable[FC_VALUE_LIST_HASH_SIZE];
369 FcChar32 hash = FcValueListHash (l);
370 FcValueListEnt **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
371 FcValueListEnt *ent;
372
373 FcValueListTotal++;
374 for (ent = *bucket; ent; ent = ent->next)
375 {
376 if (ent->hash == hash && FcValueListEqual (ent->list, l))
377 return ent->list;
378 }
379
380 ent = FcValueListEntCreate (l);
381 if (!ent)
382 return 0;
383
384 FcValueListUsed++;
385 ent->hash = hash;
386 ent->next = *bucket;
387 *bucket = ent;
388 return ent->list;
389 }
390
391 static FcChar32
392 FcPatternBaseHash (FcPattern *b)
393 {
394 FcChar32 hash = b->num;
395 int i;
396
397 for (i = 0; i < b->num; i++)
398 hash = ((hash << 1) | (hash >> 31)) ^ ((FcChar32) b->elts[i].values);
399 return hash;
400 }
401
402 typedef struct _FcPatternEnt FcPatternEnt;
403
404 struct _FcPatternEnt {
405 FcPatternEnt *next;
406 FcChar32 hash;
407 FcPattern pattern;
408 };
409
410 static int FcPatternTotal;
411 static int FcPatternUsed;
412
413 static FcPattern *
414 FcPatternBaseFreeze (FcPattern *b)
415 {
416 static FcPatternEnt *hashTable[FC_VALUE_LIST_HASH_SIZE];
417 FcChar32 hash = FcPatternBaseHash (b);
418 FcPatternEnt **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
419 FcPatternEnt *ent;
420 int i;
421 char *objects;
422 int size_objects;
423 int size;
424
425 FcPatternTotal++;
426 for (ent = *bucket; ent; ent = ent->next)
427 {
428 if (ent->hash == hash && b->num == ent->pattern.num)
429 {
430 for (i = 0; i < b->num; i++)
431 {
432 if (strcmp (b->elts[i].object, ent->pattern.elts[i].object))
433 break;
434 if (b->elts[i].values != ent->pattern.elts[i].values)
435 break;
436 }
437 if (i == b->num)
438 return &ent->pattern;
439 }
440 }
441
442 /*
443 * Compute size of pattern + elts + object names
444 */
445 size_objects = 0;
446 for (i = 0; i < b->num; i++)
447 size_objects += strlen (b->elts[i].object) + 1;
448
449 size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt) + size_objects;
450 ent = malloc (size);
451 if (!ent)
452 return 0;
453
454 FcMemAlloc (FC_MEM_PATTERN, size);
455 FcPatternUsed++;
456
457 ent->pattern.elts = (FcPatternElt *) (ent + 1);
458 ent->pattern.num = b->num;
459 ent->pattern.size = b->num;
460 ent->pattern.ref = FC_REF_CONSTANT;
461
462 objects = (char *) (ent->pattern.elts + b->num);
463 for (i = 0; i < b->num; i++)
464 {
465 ent->pattern.elts[i].values = b->elts[i].values;
466 strcpy (objects, b->elts[i].object);
467 ent->pattern.elts[i].object = objects;
468 objects += strlen (objects) + 1;
469 }
470
471 ent->hash = hash;
472 ent->next = *bucket;
473 *bucket = ent;
474 return &ent->pattern;
475 }
476
477 FcPattern *
478 FcPatternFreeze (FcPattern *p)
479 {
480 FcPattern *b, *n = 0;
481 int size;
482 int i;
483
484 size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
485 b = (FcPattern *) malloc (size);
486 if (!b)
487 return 0;
488 FcMemAlloc (FC_MEM_PATTERN, size);
489 b->num = p->num;
490 b->size = b->num;
491 b->ref = 1;
492 b->elts = (FcPatternElt *) (b + 1);
493 /*
494 * Freeze object lists
495 */
496 for (i = 0; i < p->num; i++)
497 {
498 b->elts[i].object = p->elts[i].object;
499 b->elts[i].values = FcValueListFreeze (p->elts[i].values);
500 if (!b->elts[i].values)
501 goto bail;
502 }
503 /*
504 * Freeze base
505 */
506 n = FcPatternBaseFreeze (b);
507 #ifdef CHATTY
508 if (FcDebug() & FC_DBG_MEMORY)
509 {
510 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
511 printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
512 }
513 #endif
514 bail:
515 free (b);
516 #ifdef DEBUG
517 assert (FcPatternEqual (n, p));
518 #endif
519 return n;
520 }
521
522 static int
523 FcPatternPosition (const FcPattern *p, const char *object)
524 {
525 int low, high, mid, c;
526
527 low = 0;
528 high = p->num - 1;
529 c = 1;
530 mid = 0;
531 while (low <= high)
532 {
533 mid = (low + high) >> 1;
534 c = strcmp (p->elts[mid].object, object);
535 if (c == 0)
536 return mid;
537 if (c < 0)
538 low = mid + 1;
539 else
540 high = mid - 1;
541 }
542 if (c < 0)
543 mid++;
544 return -(mid + 1);
545 }
546
547 FcPatternElt *
548 FcPatternFindElt (const FcPattern *p, const char *object)
549 {
550 int i = FcPatternPosition (p, object);
551 if (i < 0)
552 return 0;
553 return &p->elts[i];
554 }
555
556 FcPatternElt *
557 FcPatternInsertElt (FcPattern *p, const char *object)
558 {
559 int i;
560 FcPatternElt *e;
561
562 i = FcPatternPosition (p, object);
563 if (i < 0)
564 {
565 i = -i - 1;
566
567 /* grow array */
568 if (p->num + 1 >= p->size)
569 {
570 int s = p->size + 16;
571 if (p->elts)
572 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
573 else
574 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
575 if (!e)
576 return FcFalse;
577 p->elts = e;
578 if (p->size)
579 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
580 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
581 while (p->size < s)
582 {
583 p->elts[p->size].object = 0;
584 p->elts[p->size].values = 0;
585 p->size++;
586 }
587 }
588
589 /* move elts up */
590 memmove (p->elts + i + 1,
591 p->elts + i,
592 sizeof (FcPatternElt) *
593 (p->num - i));
594
595 /* bump count */
596 p->num++;
597
598 p->elts[i].object = object;
599 p->elts[i].values = 0;
600 }
601
602 return &p->elts[i];
603 }
604
605 FcBool
606 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
607 {
608 int i;
609
610 if (pa == pb)
611 return FcTrue;
612
613 if (pa->num != pb->num)
614 return FcFalse;
615 for (i = 0; i < pa->num; i++)
616 {
617 if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
618 return FcFalse;
619 if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
620 return FcFalse;
621 }
622 return FcTrue;
623 }
624
625 FcChar32
626 FcPatternHash (const FcPattern *p)
627 {
628 int i;
629 FcChar32 h = 0;
630
631 for (i = 0; i < p->num; i++)
632 {
633 h = (((h << 1) | (h >> 31)) ^
634 FcStringHash ((const FcChar8 *) p->elts[i].object) ^
635 FcValueListHash (p->elts[i].values));
636 }
637 return h;
638 }
639
640 FcBool
641 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
642 {
643 FcPatternElt *ea, *eb;
644 int i;
645
646 for (i = 0; i < os->nobject; i++)
647 {
648 ea = FcPatternFindElt (pa, os->objects[i]);
649 eb = FcPatternFindElt (pb, os->objects[i]);
650 if (ea)
651 {
652 if (!eb)
653 return FcFalse;
654 if (!FcValueListEqual (ea->values, eb->values))
655 return FcFalse;
656 }
657 else
658 {
659 if (eb)
660 return FcFalse;
661 }
662 }
663 return FcTrue;
664 }
665
666 FcBool
667 FcPatternAddWithBinding (FcPattern *p,
668 const char *object,
669 FcValue value,
670 FcValueBinding binding,
671 FcBool append)
672 {
673 FcPatternElt *e;
674 FcValueList *new, **prev;
675
676 if (p->ref == FC_REF_CONSTANT)
677 goto bail0;
678
679 new = (FcValueList *) malloc (sizeof (FcValueList));
680 if (!new)
681 goto bail0;
682
683 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
684 /* dup string */
685 value = FcValueSave (value);
686 if (value.type == FcTypeVoid)
687 goto bail1;
688
689 new->value = value;
690 new->binding = binding;
691 new->next = 0;
692
693 e = FcPatternInsertElt (p, object);
694 if (!e)
695 goto bail2;
696
697 if (append)
698 {
699 for (prev = &e->values; *prev; prev = &(*prev)->next);
700 *prev = new;
701 }
702 else
703 {
704 new->next = e->values;
705 e->values = new;
706 }
707
708 return FcTrue;
709
710 bail2:
711 switch (value.type) {
712 case FcTypeString:
713 FcStrFree ((FcChar8 *) value.u.s);
714 break;
715 case FcTypeMatrix:
716 FcMatrixFree ((FcMatrix *) value.u.m);
717 break;
718 case FcTypeCharSet:
719 FcCharSetDestroy ((FcCharSet *) value.u.c);
720 break;
721 case FcTypeLangSet:
722 FcLangSetDestroy ((FcLangSet *) value.u.l);
723 break;
724 default:
725 break;
726 }
727 bail1:
728 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
729 free (new);
730 bail0:
731 return FcFalse;
732 }
733
734 FcBool
735 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
736 {
737 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
738 }
739
740 FcBool
741 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
742 {
743 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
744 }
745
746 FcBool
747 FcPatternDel (FcPattern *p, const char *object)
748 {
749 FcPatternElt *e;
750 int i;
751
752 e = FcPatternFindElt (p, object);
753 if (!e)
754 return FcFalse;
755
756 i = e - p->elts;
757
758 /* destroy value */
759 FcValueListDestroy (e->values);
760
761 /* shuffle existing ones down */
762 memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
763 p->num--;
764 p->elts[p->num].object = 0;
765 p->elts[p->num].values = 0;
766 return FcTrue;
767 }
768
769 FcBool
770 FcPatternAddInteger (FcPattern *p, const char *object, int i)
771 {
772 FcValue v;
773
774 v.type = FcTypeInteger;
775 v.u.i = i;
776 return FcPatternAdd (p, object, v, FcTrue);
777 }
778
779 FcBool
780 FcPatternAddDouble (FcPattern *p, const char *object, double d)
781 {
782 FcValue v;
783
784 v.type = FcTypeDouble;
785 v.u.d = d;
786 return FcPatternAdd (p, object, v, FcTrue);
787 }
788
789
790 FcBool
791 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
792 {
793 FcValue v;
794
795 v.type = FcTypeString;
796 v.u.s = s;
797 return FcPatternAdd (p, object, v, FcTrue);
798 }
799
800 FcBool
801 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
802 {
803 FcValue v;
804
805 v.type = FcTypeMatrix;
806 v.u.m = (FcMatrix *) s;
807 return FcPatternAdd (p, object, v, FcTrue);
808 }
809
810
811 FcBool
812 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
813 {
814 FcValue v;
815
816 v.type = FcTypeBool;
817 v.u.b = b;
818 return FcPatternAdd (p, object, v, FcTrue);
819 }
820
821 FcBool
822 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
823 {
824 FcValue v;
825
826 v.type = FcTypeCharSet;
827 v.u.c = (FcCharSet *) c;
828 return FcPatternAdd (p, object, v, FcTrue);
829 }
830
831 FcBool
832 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
833 {
834 FcValue v;
835
836 v.type = FcTypeFTFace;
837 v.u.f = (void *) f;
838 return FcPatternAdd (p, object, v, FcTrue);
839 }
840
841 FcBool
842 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
843 {
844 FcValue v;
845
846 v.type = FcTypeLangSet;
847 v.u.l = (FcLangSet *) ls;
848 return FcPatternAdd (p, object, v, FcTrue);
849 }
850
851 FcResult
852 FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
853 {
854 FcPatternElt *e;
855 FcValueList *l;
856
857 e = FcPatternFindElt (p, object);
858 if (!e)
859 return FcResultNoMatch;
860 for (l = e->values; l; l = l->next)
861 {
862 if (!id)
863 {
864 *v = l->value;
865 return FcResultMatch;
866 }
867 id--;
868 }
869 return FcResultNoId;
870 }
871
872 FcResult
873 FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
874 {
875 FcValue v;
876 FcResult r;
877
878 r = FcPatternGet (p, object, id, &v);
879 if (r != FcResultMatch)
880 return r;
881 switch (v.type) {
882 case FcTypeDouble:
883 *i = (int) v.u.d;
884 break;
885 case FcTypeInteger:
886 *i = v.u.i;
887 break;
888 default:
889 return FcResultTypeMismatch;
890 }
891 return FcResultMatch;
892 }
893
894 FcResult
895 FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
896 {
897 FcValue v;
898 FcResult r;
899
900 r = FcPatternGet (p, object, id, &v);
901 if (r != FcResultMatch)
902 return r;
903 switch (v.type) {
904 case FcTypeDouble:
905 *d = v.u.d;
906 break;
907 case FcTypeInteger:
908 *d = (double) v.u.i;
909 break;
910 default:
911 return FcResultTypeMismatch;
912 }
913 return FcResultMatch;
914 }
915
916 FcResult
917 FcPatternGetString (FcPattern *p, const char *object, int id, FcChar8 ** s)
918 {
919 FcValue v;
920 FcResult r;
921
922 r = FcPatternGet (p, object, id, &v);
923 if (r != FcResultMatch)
924 return r;
925 if (v.type != FcTypeString)
926 return FcResultTypeMismatch;
927 *s = (FcChar8 *) v.u.s;
928 return FcResultMatch;
929 }
930
931 FcResult
932 FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
933 {
934 FcValue v;
935 FcResult r;
936
937 r = FcPatternGet (p, object, id, &v);
938 if (r != FcResultMatch)
939 return r;
940 if (v.type != FcTypeMatrix)
941 return FcResultTypeMismatch;
942 *m = (FcMatrix *) v.u.m;
943 return FcResultMatch;
944 }
945
946
947 FcResult
948 FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
949 {
950 FcValue v;
951 FcResult r;
952
953 r = FcPatternGet (p, object, id, &v);
954 if (r != FcResultMatch)
955 return r;
956 if (v.type != FcTypeBool)
957 return FcResultTypeMismatch;
958 *b = v.u.b;
959 return FcResultMatch;
960 }
961
962 FcResult
963 FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
964 {
965 FcValue v;
966 FcResult r;
967
968 r = FcPatternGet (p, object, id, &v);
969 if (r != FcResultMatch)
970 return r;
971 if (v.type != FcTypeCharSet)
972 return FcResultTypeMismatch;
973 *c = (FcCharSet *) v.u.c;
974 return FcResultMatch;
975 }
976
977 FcResult
978 FcPatternGetFTFace (FcPattern *p, const char *object, int id, FT_Face *f)
979 {
980 FcValue v;
981 FcResult r;
982
983 r = FcPatternGet (p, object, id, &v);
984 if (r != FcResultMatch)
985 return r;
986 if (v.type != FcTypeFTFace)
987 return FcResultTypeMismatch;
988 *f = (FT_Face) v.u.f;
989 return FcResultMatch;
990 }
991
992 FcResult
993 FcPatternGetLangSet (FcPattern *p, const char *object, int id, FcLangSet **ls)
994 {
995 FcValue v;
996 FcResult r;
997
998 r = FcPatternGet (p, object, id, &v);
999 if (r != FcResultMatch)
1000 return r;
1001 if (v.type != FcTypeLangSet)
1002 return FcResultTypeMismatch;
1003 *ls = (FcLangSet *) v.u.l;
1004 return FcResultMatch;
1005 }
1006
1007 FcPattern *
1008 FcPatternDuplicate (FcPattern *orig)
1009 {
1010 FcPattern *new;
1011 int i;
1012 FcValueList *l;
1013
1014 new = FcPatternCreate ();
1015 if (!new)
1016 goto bail0;
1017
1018 for (i = 0; i < orig->num; i++)
1019 {
1020 for (l = orig->elts[i].values; l; l = l->next)
1021 if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
1022 goto bail1;
1023 }
1024
1025 return new;
1026
1027 bail1:
1028 FcPatternDestroy (new);
1029 bail0:
1030 return 0;
1031 }
1032
1033 void
1034 FcPatternReference (FcPattern *p)
1035 {
1036 if (p->ref != FC_REF_CONSTANT)
1037 p->ref++;
1038 }
1039
1040 FcPattern *
1041 FcPatternVaBuild (FcPattern *orig, va_list va)
1042 {
1043 FcPattern *ret;
1044
1045 FcPatternVapBuild (ret, orig, va);
1046 return ret;
1047 }
1048
1049 FcPattern *
1050 FcPatternBuild (FcPattern *orig, ...)
1051 {
1052 va_list va;
1053
1054 va_start (va, orig);
1055 FcPatternVapBuild (orig, orig, va);
1056 va_end (va);
1057 return orig;
1058 }