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