]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Reviewed by: Keith Packard <keithp@keithp.com>
[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 size;
325
326 n = 0;
327 for (l = h; l; l = l->next)
328 n++;
329 size = sizeof (FcValueListAlign) + n * sizeof (FcValueList);
330 FcValueListFrozenCount[h->value.type]++;
331 FcValueListFrozenBytes[h->value.type] += size;
332 ea = malloc (size);
333 if (!ea)
334 return 0;
335 FcMemAlloc (FC_MEM_VALLIST, size);
336 e = &ea->ent;
337 e->list = (FcValueList *) (ea + 1);
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 = FcObjectStaticName (l->value.u.s);
345 }
346 else
347 {
348 new->value = FcValueSave (l->value);
349 }
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 void
360 FcValueListEntDestroy (FcValueListEnt *e)
361 {
362 FcValueList *l;
363
364 FcValueListFrozenCount[e->list->value.type]--;
365
366 /* XXX: We should perform these two operations with "size" as
367 computed in FcValueListEntCreate, but we don't have access to
368 that value here. Without this, the FcValueListFrozenBytes
369 values will be wrong as will the FcMemFree counts.
370
371 FcValueListFrozenBytes[e->list->value.type] -= size;
372 FcMemFree (FC_MEM_VALLIST, size);
373 */
374
375 for (l = e->list; l; l = l->next)
376 {
377 if (l->value.type != FcTypeString)
378 FcValueDestroy (l->value);
379 }
380 /* XXX: Are we being too chummy with the implementation here to
381 free(e) when it was actually the enclosing FcValueListAlign
382 that was allocated? */
383 free (e);
384 }
385
386 static int FcValueListTotal;
387 static int FcValueListUsed;
388
389 static FcValueListEnt *FcValueListHashTable[FC_VALUE_LIST_HASH_SIZE];
390
391 static FcValueList *
392 FcValueListFreeze (FcValueList *l)
393 {
394 FcChar32 hash = FcValueListHash (l);
395 FcValueListEnt **bucket = &FcValueListHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
396 FcValueListEnt *ent;
397
398 FcValueListTotal++;
399 for (ent = *bucket; ent; ent = ent->next)
400 {
401 if (ent->hash == hash && FcValueListEqual (ent->list, l))
402 return ent->list;
403 }
404
405 ent = FcValueListEntCreate (l);
406 if (!ent)
407 return 0;
408
409 FcValueListUsed++;
410 ent->hash = hash;
411 ent->next = *bucket;
412 *bucket = ent;
413 return ent->list;
414 }
415
416 static void
417 FcValueListThawAll (void)
418 {
419 int i;
420 FcValueListEnt *ent, *next;
421
422 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
423 {
424 for (ent = FcValueListHashTable[i]; ent; ent = next)
425 {
426 next = ent->next;
427 FcValueListEntDestroy (ent);
428 }
429 FcValueListHashTable[i] = 0;
430 }
431
432 FcValueListTotal = 0;
433 FcValueListUsed = 0;
434 }
435
436 static FcChar32
437 FcPatternBaseHash (FcPattern *b)
438 {
439 FcChar32 hash = b->num;
440 int i;
441
442 for (i = 0; i < b->num; i++)
443 hash = ((hash << 1) | (hash >> 31)) ^ ((long) b->elts[i].values);
444 return hash;
445 }
446
447 typedef struct _FcPatternEnt FcPatternEnt;
448
449 struct _FcPatternEnt {
450 FcPatternEnt *next;
451 FcChar32 hash;
452 FcPattern pattern;
453 };
454
455 static int FcPatternTotal;
456 static int FcPatternUsed;
457
458 static FcPatternEnt *FcPatternHashTable[FC_VALUE_LIST_HASH_SIZE];
459
460 static FcPattern *
461 FcPatternBaseFreeze (FcPattern *b)
462 {
463 FcChar32 hash = FcPatternBaseHash (b);
464 FcPatternEnt **bucket = &FcPatternHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
465 FcPatternEnt *ent;
466 int i;
467 int size;
468
469 FcPatternTotal++;
470 for (ent = *bucket; ent; ent = ent->next)
471 {
472 if (ent->hash == hash && b->num == ent->pattern.num)
473 {
474 for (i = 0; i < b->num; i++)
475 {
476 if (b->elts[i].object != ent->pattern.elts[i].object)
477 break;
478 if (b->elts[i].values != ent->pattern.elts[i].values)
479 break;
480 }
481 if (i == b->num)
482 return &ent->pattern;
483 }
484 }
485
486 /*
487 * Compute size of pattern + elts
488 */
489 size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt);
490 ent = malloc (size);
491 if (!ent)
492 return 0;
493
494 FcMemAlloc (FC_MEM_PATTERN, size);
495 FcPatternUsed++;
496
497 ent->pattern.elts = (FcPatternElt *) (ent + 1);
498 ent->pattern.num = b->num;
499 ent->pattern.size = b->num;
500 ent->pattern.ref = FC_REF_CONSTANT;
501
502 for (i = 0; i < b->num; i++)
503 {
504 ent->pattern.elts[i].values = b->elts[i].values;
505 ent->pattern.elts[i].object = b->elts[i].object;
506 }
507
508 ent->hash = hash;
509 ent->next = *bucket;
510 *bucket = ent;
511 return &ent->pattern;
512 }
513
514 static void
515 FcPatternBaseThawAll (void)
516 {
517 int i;
518 FcPatternEnt *ent, *next;
519
520 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
521 {
522 for (ent = FcPatternHashTable[i]; ent; ent = next)
523 {
524 next = ent->next;
525 free (ent);
526 }
527 FcPatternHashTable[i] = 0;
528 }
529
530 FcPatternTotal = 0;
531 FcPatternUsed = 0;
532 }
533
534 FcPattern *
535 FcPatternFreeze (FcPattern *p)
536 {
537 FcPattern *b, *n = 0;
538 int size;
539 int i;
540
541 size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
542 b = (FcPattern *) malloc (size);
543 if (!b)
544 return 0;
545 FcMemAlloc (FC_MEM_PATTERN, size);
546 b->num = p->num;
547 b->size = b->num;
548 b->ref = 1;
549 b->elts = (FcPatternElt *) (b + 1);
550 /*
551 * Freeze object lists
552 */
553 for (i = 0; i < p->num; i++)
554 {
555 b->elts[i].object = p->elts[i].object;
556 b->elts[i].values = FcValueListFreeze (p->elts[i].values);
557 if (!b->elts[i].values)
558 goto bail;
559 }
560 /*
561 * Freeze base
562 */
563 n = FcPatternBaseFreeze (b);
564 #ifdef CHATTY
565 if (FcDebug() & FC_DBG_MEMORY)
566 {
567 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
568 printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
569 }
570 #endif
571 bail:
572 free (b);
573 #ifdef DEBUG
574 assert (FcPatternEqual (n, p));
575 #endif
576 return n;
577 }
578
579 void
580 FcPatternThawAll (void)
581 {
582 FcPatternBaseThawAll ();
583 FcValueListThawAll ();
584 }
585
586 static int
587 FcPatternPosition (const FcPattern *p, const char *object)
588 {
589 int low, high, mid, c;
590
591 low = 0;
592 high = p->num - 1;
593 c = 1;
594 mid = 0;
595 while (low <= high)
596 {
597 mid = (low + high) >> 1;
598 c = strcmp (p->elts[mid].object, object);
599 if (c == 0)
600 return mid;
601 if (c < 0)
602 low = mid + 1;
603 else
604 high = mid - 1;
605 }
606 if (c < 0)
607 mid++;
608 return -(mid + 1);
609 }
610
611 FcPatternElt *
612 FcPatternFindElt (const FcPattern *p, const char *object)
613 {
614 int i = FcPatternPosition (p, object);
615 if (i < 0)
616 return 0;
617 return &p->elts[i];
618 }
619
620 FcPatternElt *
621 FcPatternInsertElt (FcPattern *p, const char *object)
622 {
623 int i;
624 FcPatternElt *e;
625
626 i = FcPatternPosition (p, object);
627 if (i < 0)
628 {
629 i = -i - 1;
630
631 /* grow array */
632 if (p->num + 1 >= p->size)
633 {
634 int s = p->size + 16;
635 if (p->elts)
636 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
637 else
638 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
639 if (!e)
640 return FcFalse;
641 p->elts = e;
642 if (p->size)
643 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
644 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
645 while (p->size < s)
646 {
647 p->elts[p->size].object = 0;
648 p->elts[p->size].values = 0;
649 p->size++;
650 }
651 }
652
653 /* move elts up */
654 memmove (p->elts + i + 1,
655 p->elts + i,
656 sizeof (FcPatternElt) *
657 (p->num - i));
658
659 /* bump count */
660 p->num++;
661
662 p->elts[i].object = FcObjectStaticName (object);
663 p->elts[i].values = 0;
664 }
665
666 return &p->elts[i];
667 }
668
669 FcBool
670 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
671 {
672 int i;
673
674 if (pa == pb)
675 return FcTrue;
676
677 if (pa->num != pb->num)
678 return FcFalse;
679 for (i = 0; i < pa->num; i++)
680 {
681 if (pa->elts[i].object != pb->elts[i].object)
682 return FcFalse;
683 if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
684 return FcFalse;
685 }
686 return FcTrue;
687 }
688
689 FcChar32
690 FcPatternHash (const FcPattern *p)
691 {
692 int i;
693 FcChar32 h = 0;
694
695 for (i = 0; i < p->num; i++)
696 {
697 h = (((h << 1) | (h >> 31)) ^
698 FcStringHash ((const FcChar8 *) p->elts[i].object) ^
699 FcValueListHash (p->elts[i].values));
700 }
701 return h;
702 }
703
704 FcBool
705 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
706 {
707 FcPatternElt *ea, *eb;
708 int i;
709
710 for (i = 0; i < os->nobject; i++)
711 {
712 ea = FcPatternFindElt (pa, os->objects[i]);
713 eb = FcPatternFindElt (pb, os->objects[i]);
714 if (ea)
715 {
716 if (!eb)
717 return FcFalse;
718 if (!FcValueListEqual (ea->values, eb->values))
719 return FcFalse;
720 }
721 else
722 {
723 if (eb)
724 return FcFalse;
725 }
726 }
727 return FcTrue;
728 }
729
730 FcBool
731 FcPatternAddWithBinding (FcPattern *p,
732 const char *object,
733 FcValue value,
734 FcValueBinding binding,
735 FcBool append)
736 {
737 FcPatternElt *e;
738 FcValueList *new, **prev;
739
740 if (p->ref == FC_REF_CONSTANT)
741 goto bail0;
742
743 new = (FcValueList *) malloc (sizeof (FcValueList));
744 if (!new)
745 goto bail0;
746
747 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
748 /* dup string */
749 value = FcValueSave (value);
750 if (value.type == FcTypeVoid)
751 goto bail1;
752
753 new->value = value;
754 new->binding = binding;
755 new->next = 0;
756
757 e = FcPatternInsertElt (p, object);
758 if (!e)
759 goto bail2;
760
761 if (append)
762 {
763 for (prev = &e->values; *prev; prev = &(*prev)->next);
764 *prev = new;
765 }
766 else
767 {
768 new->next = e->values;
769 e->values = new;
770 }
771
772 return FcTrue;
773
774 bail2:
775 switch (value.type) {
776 case FcTypeString:
777 FcStrFree ((FcChar8 *) value.u.s);
778 break;
779 case FcTypeMatrix:
780 FcMatrixFree ((FcMatrix *) value.u.m);
781 break;
782 case FcTypeCharSet:
783 FcCharSetDestroy ((FcCharSet *) value.u.c);
784 break;
785 case FcTypeLangSet:
786 FcLangSetDestroy ((FcLangSet *) value.u.l);
787 break;
788 default:
789 break;
790 }
791 bail1:
792 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
793 free (new);
794 bail0:
795 return FcFalse;
796 }
797
798 FcBool
799 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
800 {
801 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
802 }
803
804 FcBool
805 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
806 {
807 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
808 }
809
810 FcBool
811 FcPatternDel (FcPattern *p, const char *object)
812 {
813 FcPatternElt *e;
814 int i;
815
816 e = FcPatternFindElt (p, object);
817 if (!e)
818 return FcFalse;
819
820 i = e - p->elts;
821
822 /* destroy value */
823 FcValueListDestroy (e->values);
824
825 /* shuffle existing ones down */
826 memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
827 p->num--;
828 p->elts[p->num].object = 0;
829 p->elts[p->num].values = 0;
830 return FcTrue;
831 }
832
833 FcBool
834 FcPatternRemove (FcPattern *p, const char *object, int id)
835 {
836 FcPatternElt *e;
837 FcValueList **prev, *l;
838
839 e = FcPatternFindElt (p, object);
840 if (!e)
841 return FcFalse;
842 for (prev = &e->values; (l = *prev); prev = &l->next)
843 {
844 if (!id)
845 {
846 *prev = l->next;
847 l->next = 0;
848 FcValueListDestroy (l);
849 if (!e->values)
850 FcPatternDel (p, object);
851 return FcTrue;
852 }
853 id--;
854 }
855 return FcFalse;
856 }
857
858 FcBool
859 FcPatternAddInteger (FcPattern *p, const char *object, int i)
860 {
861 FcValue v;
862
863 v.type = FcTypeInteger;
864 v.u.i = i;
865 return FcPatternAdd (p, object, v, FcTrue);
866 }
867
868 FcBool
869 FcPatternAddDouble (FcPattern *p, const char *object, double d)
870 {
871 FcValue v;
872
873 v.type = FcTypeDouble;
874 v.u.d = d;
875 return FcPatternAdd (p, object, v, FcTrue);
876 }
877
878
879 FcBool
880 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
881 {
882 FcValue v;
883
884 v.type = FcTypeString;
885 v.u.s = s;
886 return FcPatternAdd (p, object, v, FcTrue);
887 }
888
889 FcBool
890 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
891 {
892 FcValue v;
893
894 v.type = FcTypeMatrix;
895 v.u.m = (FcMatrix *) s;
896 return FcPatternAdd (p, object, v, FcTrue);
897 }
898
899
900 FcBool
901 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
902 {
903 FcValue v;
904
905 v.type = FcTypeBool;
906 v.u.b = b;
907 return FcPatternAdd (p, object, v, FcTrue);
908 }
909
910 FcBool
911 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
912 {
913 FcValue v;
914
915 v.type = FcTypeCharSet;
916 v.u.c = (FcCharSet *) c;
917 return FcPatternAdd (p, object, v, FcTrue);
918 }
919
920 FcBool
921 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
922 {
923 FcValue v;
924
925 v.type = FcTypeFTFace;
926 v.u.f = (void *) f;
927 return FcPatternAdd (p, object, v, FcTrue);
928 }
929
930 FcBool
931 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
932 {
933 FcValue v;
934
935 v.type = FcTypeLangSet;
936 v.u.l = (FcLangSet *) ls;
937 return FcPatternAdd (p, object, v, FcTrue);
938 }
939
940 FcResult
941 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
942 {
943 FcPatternElt *e;
944 FcValueList *l;
945
946 e = FcPatternFindElt (p, object);
947 if (!e)
948 return FcResultNoMatch;
949 for (l = e->values; l; l = l->next)
950 {
951 if (!id)
952 {
953 *v = l->value;
954 return FcResultMatch;
955 }
956 id--;
957 }
958 return FcResultNoId;
959 }
960
961 FcResult
962 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
963 {
964 FcValue v;
965 FcResult r;
966
967 r = FcPatternGet (p, object, id, &v);
968 if (r != FcResultMatch)
969 return r;
970 switch (v.type) {
971 case FcTypeDouble:
972 *i = (int) v.u.d;
973 break;
974 case FcTypeInteger:
975 *i = v.u.i;
976 break;
977 default:
978 return FcResultTypeMismatch;
979 }
980 return FcResultMatch;
981 }
982
983 FcResult
984 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
985 {
986 FcValue v;
987 FcResult r;
988
989 r = FcPatternGet (p, object, id, &v);
990 if (r != FcResultMatch)
991 return r;
992 switch (v.type) {
993 case FcTypeDouble:
994 *d = v.u.d;
995 break;
996 case FcTypeInteger:
997 *d = (double) v.u.i;
998 break;
999 default:
1000 return FcResultTypeMismatch;
1001 }
1002 return FcResultMatch;
1003 }
1004
1005 FcResult
1006 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1007 {
1008 FcValue v;
1009 FcResult r;
1010
1011 r = FcPatternGet (p, object, id, &v);
1012 if (r != FcResultMatch)
1013 return r;
1014 if (v.type != FcTypeString)
1015 return FcResultTypeMismatch;
1016 *s = (FcChar8 *) v.u.s;
1017 return FcResultMatch;
1018 }
1019
1020 FcResult
1021 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1022 {
1023 FcValue v;
1024 FcResult r;
1025
1026 r = FcPatternGet (p, object, id, &v);
1027 if (r != FcResultMatch)
1028 return r;
1029 if (v.type != FcTypeMatrix)
1030 return FcResultTypeMismatch;
1031 *m = (FcMatrix *) v.u.m;
1032 return FcResultMatch;
1033 }
1034
1035
1036 FcResult
1037 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1038 {
1039 FcValue v;
1040 FcResult r;
1041
1042 r = FcPatternGet (p, object, id, &v);
1043 if (r != FcResultMatch)
1044 return r;
1045 if (v.type != FcTypeBool)
1046 return FcResultTypeMismatch;
1047 *b = v.u.b;
1048 return FcResultMatch;
1049 }
1050
1051 FcResult
1052 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1053 {
1054 FcValue v;
1055 FcResult r;
1056
1057 r = FcPatternGet (p, object, id, &v);
1058 if (r != FcResultMatch)
1059 return r;
1060 if (v.type != FcTypeCharSet)
1061 return FcResultTypeMismatch;
1062 *c = (FcCharSet *) v.u.c;
1063 return FcResultMatch;
1064 }
1065
1066 FcResult
1067 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1068 {
1069 FcValue v;
1070 FcResult r;
1071
1072 r = FcPatternGet (p, object, id, &v);
1073 if (r != FcResultMatch)
1074 return r;
1075 if (v.type != FcTypeFTFace)
1076 return FcResultTypeMismatch;
1077 *f = (FT_Face) v.u.f;
1078 return FcResultMatch;
1079 }
1080
1081 FcResult
1082 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1083 {
1084 FcValue v;
1085 FcResult r;
1086
1087 r = FcPatternGet (p, object, id, &v);
1088 if (r != FcResultMatch)
1089 return r;
1090 if (v.type != FcTypeLangSet)
1091 return FcResultTypeMismatch;
1092 *ls = (FcLangSet *) v.u.l;
1093 return FcResultMatch;
1094 }
1095
1096 FcPattern *
1097 FcPatternDuplicate (const FcPattern *orig)
1098 {
1099 FcPattern *new;
1100 int i;
1101 FcValueList *l;
1102
1103 new = FcPatternCreate ();
1104 if (!new)
1105 goto bail0;
1106
1107 for (i = 0; i < orig->num; i++)
1108 {
1109 for (l = orig->elts[i].values; l; l = l->next)
1110 if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
1111 goto bail1;
1112 }
1113
1114 return new;
1115
1116 bail1:
1117 FcPatternDestroy (new);
1118 bail0:
1119 return 0;
1120 }
1121
1122 void
1123 FcPatternReference (FcPattern *p)
1124 {
1125 if (p->ref != FC_REF_CONSTANT)
1126 p->ref++;
1127 }
1128
1129 FcPattern *
1130 FcPatternVaBuild (FcPattern *orig, va_list va)
1131 {
1132 FcPattern *ret;
1133
1134 FcPatternVapBuild (ret, orig, va);
1135 return ret;
1136 }
1137
1138 FcPattern *
1139 FcPatternBuild (FcPattern *orig, ...)
1140 {
1141 va_list va;
1142
1143 va_start (va, orig);
1144 FcPatternVapBuild (orig, orig, va);
1145 va_end (va);
1146 return orig;
1147 }
1148
1149 /*
1150 * Add all of the elements in 's' to 'p'
1151 */
1152 FcBool
1153 FcPatternAppend (FcPattern *p, FcPattern *s)
1154 {
1155 int i;
1156 FcPatternElt *e;
1157 FcValueList *v;
1158
1159 for (i = 0; i < s->num; i++)
1160 {
1161 e = &s->elts[i];
1162 for (v = e->values; v; v = v->next)
1163 {
1164 if (!FcPatternAddWithBinding (p, e->object,
1165 v->value, v->binding, FcTrue))
1166 return FcFalse;
1167 }
1168 }
1169 return FcTrue;
1170 }
1171
1172 const char *
1173 FcObjectStaticName (const char *name)
1174 {
1175 #define OBJECT_HASH_SIZE 31
1176 static struct objectBucket {
1177 struct objectBucket *next;
1178 FcChar32 hash;
1179 } *buckets[OBJECT_HASH_SIZE];
1180 FcChar32 hash = FcStringHash ((const FcChar8 *) name);
1181 struct objectBucket **p;
1182 struct objectBucket *b;
1183 int size;
1184
1185 for (p = &buckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1186 if (b->hash == hash && !strcmp (name, (char *) (b + 1)))
1187 return (char *) (b + 1);
1188 size = sizeof (struct objectBucket) + strlen (name) + 1;
1189 b = malloc (size);
1190 FcMemAlloc (FC_MEM_STATICSTR, size);
1191 if (!b)
1192 return NULL;
1193 b->next = 0;
1194 b->hash = hash;
1195 strcpy ((char *) (b + 1), name);
1196 *p = b;
1197 return (char *) (b + 1);
1198 }