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