]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
74327456cc27918c0e9af8d49794866fb0dfb851
[fontconfig.git] / src / fcpat.c
1 /*
2 * Copyright © 2000 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #include "fcint.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 static FcBool
29 FcStrHashed (const FcChar8 *name);
30
31 FcPattern *
32 FcPatternCreate (void)
33 {
34 FcPattern *p;
35
36 p = (FcPattern *) malloc (sizeof (FcPattern));
37 if (!p)
38 return 0;
39 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
40 p->num = 0;
41 p->size = 0;
42 p->elts_offset = FcPtrToOffset (p, NULL);
43 p->ref = 1;
44 return p;
45 }
46
47 void
48 FcValueDestroy (FcValue v)
49 {
50 switch (v.type) {
51 case FcTypeString:
52 if (!FcStrHashed (v.u.s))
53 FcStrFree ((FcChar8 *) v.u.s);
54 break;
55 case FcTypeMatrix:
56 FcMatrixFree ((FcMatrix *) v.u.m);
57 break;
58 case FcTypeCharSet:
59 FcCharSetDestroy ((FcCharSet *) v.u.c);
60 break;
61 case FcTypeLangSet:
62 FcLangSetDestroy ((FcLangSet *) v.u.l);
63 break;
64 default:
65 break;
66 }
67 }
68
69 FcValue
70 FcValueCanonicalize (const FcValue *v)
71 {
72 FcValue new;
73
74 switch (v->type)
75 {
76 case FcTypeString:
77 new.u.s = fc_value_string(v);
78 new.type = FcTypeString;
79 break;
80 case FcTypeCharSet:
81 new.u.c = fc_value_charset(v);
82 new.type = FcTypeCharSet;
83 break;
84 case FcTypeLangSet:
85 new.u.l = fc_value_langset(v);
86 new.type = FcTypeLangSet;
87 break;
88 default:
89 new = *v;
90 break;
91 }
92 return new;
93 }
94
95 FcValue
96 FcValueSave (FcValue v)
97 {
98 switch (v.type) {
99 case FcTypeString:
100 v.u.s = FcStrCopy (v.u.s);
101 if (!v.u.s)
102 v.type = FcTypeVoid;
103 break;
104 case FcTypeMatrix:
105 v.u.m = FcMatrixCopy (v.u.m);
106 if (!v.u.m)
107 v.type = FcTypeVoid;
108 break;
109 case FcTypeCharSet:
110 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
111 if (!v.u.c)
112 v.type = FcTypeVoid;
113 break;
114 case FcTypeLangSet:
115 v.u.l = FcLangSetCopy (v.u.l);
116 if (!v.u.l)
117 v.type = FcTypeVoid;
118 break;
119 default:
120 break;
121 }
122 return v;
123 }
124
125 void
126 FcValueListDestroy (FcValueListPtr l)
127 {
128 FcValueListPtr next;
129 for (; l; l = next)
130 {
131 switch (l->value.type) {
132 case FcTypeString:
133 if (!FcStrHashed ((FcChar8 *)l->value.u.s))
134 FcStrFree ((FcChar8 *)l->value.u.s);
135 break;
136 case FcTypeMatrix:
137 FcMatrixFree ((FcMatrix *)l->value.u.m);
138 break;
139 case FcTypeCharSet:
140 FcCharSetDestroy
141 ((FcCharSet *) (l->value.u.c));
142 break;
143 case FcTypeLangSet:
144 FcLangSetDestroy
145 ((FcLangSet *) (l->value.u.l));
146 break;
147 default:
148 break;
149 }
150 next = FcValueListNext(l);
151 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
152 free(l);
153 }
154 }
155
156 FcBool
157 FcValueEqual (FcValue va, FcValue vb)
158 {
159 if (va.type != vb.type)
160 {
161 if (va.type == FcTypeInteger)
162 {
163 va.type = FcTypeDouble;
164 va.u.d = va.u.i;
165 }
166 if (vb.type == FcTypeInteger)
167 {
168 vb.type = FcTypeDouble;
169 vb.u.d = vb.u.i;
170 }
171 if (va.type != vb.type)
172 return FcFalse;
173 }
174 switch (va.type) {
175 case FcTypeVoid:
176 return FcTrue;
177 case FcTypeInteger:
178 return va.u.i == vb.u.i;
179 case FcTypeDouble:
180 return va.u.d == vb.u.d;
181 case FcTypeString:
182 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
183 case FcTypeBool:
184 return va.u.b == vb.u.b;
185 case FcTypeMatrix:
186 return FcMatrixEqual (va.u.m, vb.u.m);
187 case FcTypeCharSet:
188 return FcCharSetEqual (va.u.c, vb.u.c);
189 case FcTypeFTFace:
190 return va.u.f == vb.u.f;
191 case FcTypeLangSet:
192 return FcLangSetEqual (va.u.l, vb.u.l);
193 }
194 return FcFalse;
195 }
196
197 static FcChar32
198 FcDoubleHash (double d)
199 {
200 if (d < 0)
201 d = -d;
202 if (d > 0xffffffff)
203 d = 0xffffffff;
204 return (FcChar32) d;
205 }
206
207 FcChar32
208 FcStringHash (const FcChar8 *s)
209 {
210 FcChar8 c;
211 FcChar32 h = 0;
212
213 if (s)
214 while ((c = *s++))
215 h = ((h << 1) | (h >> 31)) ^ c;
216 return h;
217 }
218
219 static FcChar32
220 FcValueHash (const FcValue *v)
221 {
222 switch (fc_storage_type(v)) {
223 case FcTypeVoid:
224 return 0;
225 case FcTypeInteger:
226 return (FcChar32) v->u.i;
227 case FcTypeDouble:
228 return FcDoubleHash (v->u.d);
229 case FcTypeString:
230 return FcStringHash (fc_value_string(v));
231 case FcTypeBool:
232 return (FcChar32) v->u.b;
233 case FcTypeMatrix:
234 return (FcDoubleHash (v->u.m->xx) ^
235 FcDoubleHash (v->u.m->xy) ^
236 FcDoubleHash (v->u.m->yx) ^
237 FcDoubleHash (v->u.m->yy));
238 case FcTypeCharSet:
239 return (FcChar32) fc_value_charset(v)->num;
240 case FcTypeFTFace:
241 return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
242 FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
243 case FcTypeLangSet:
244 return FcLangSetHash (fc_value_langset(v));
245 }
246 return FcFalse;
247 }
248
249 static FcBool
250 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
251 {
252 if (la == lb)
253 return FcTrue;
254
255 while (la && lb)
256 {
257 if (!FcValueEqual (la->value, lb->value))
258 return FcFalse;
259 la = FcValueListNext(la);
260 lb = FcValueListNext(lb);
261 }
262 if (la || lb)
263 return FcFalse;
264 return FcTrue;
265 }
266
267 static FcChar32
268 FcValueListHash (FcValueListPtr l)
269 {
270 FcChar32 hash = 0;
271
272 for (; l; l = FcValueListNext(l))
273 {
274 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
275 }
276 return hash;
277 }
278
279 void
280 FcPatternDestroy (FcPattern *p)
281 {
282 int i;
283 FcPatternElt *elts;
284
285 if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
286 return;
287
288 elts = FcPatternElts (p);
289 for (i = 0; i < p->num; i++)
290 FcValueListDestroy (FcPatternEltValues(&elts[i]));
291
292 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
293 free (elts);
294 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
295 free (p);
296 }
297
298 static int
299 FcPatternObjectPosition (const FcPattern *p, FcObject object)
300 {
301 int low, high, mid, c;
302 FcPatternElt *elts = FcPatternElts(p);
303
304 low = 0;
305 high = p->num - 1;
306 c = 1;
307 mid = 0;
308 while (low <= high)
309 {
310 mid = (low + high) >> 1;
311 c = elts[mid].object - object;
312 if (c == 0)
313 return mid;
314 if (c < 0)
315 low = mid + 1;
316 else
317 high = mid - 1;
318 }
319 if (c < 0)
320 mid++;
321 return -(mid + 1);
322 }
323
324 FcPatternElt *
325 FcPatternObjectFindElt (const FcPattern *p, FcObject object)
326 {
327 int i = FcPatternObjectPosition (p, object);
328 if (i < 0)
329 return 0;
330 return &FcPatternElts(p)[i];
331 }
332
333 FcPatternElt *
334 FcPatternObjectInsertElt (FcPattern *p, FcObject object)
335 {
336 int i;
337 FcPatternElt *e;
338
339 i = FcPatternObjectPosition (p, object);
340 if (i < 0)
341 {
342 i = -i - 1;
343
344 /* reallocate array */
345 if (p->num + 1 >= p->size)
346 {
347 int s = p->size + 16;
348 if (p->size)
349 {
350 FcPatternElt *e0 = FcPatternElts(p);
351 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
352 if (!e) /* maybe it was mmapped */
353 {
354 e = malloc(s * sizeof (FcPatternElt));
355 if (e)
356 memcpy(e, e0, p->num * sizeof (FcPatternElt));
357 }
358 }
359 else
360 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
361 if (!e)
362 return FcFalse;
363 p->elts_offset = FcPtrToOffset (p, e);
364 if (p->size)
365 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
366 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
367 while (p->size < s)
368 {
369 e[p->size].object = 0;
370 e[p->size].values = NULL;
371 p->size++;
372 }
373 }
374
375 e = FcPatternElts(p);
376 /* move elts up */
377 memmove (e + i + 1,
378 e + i,
379 sizeof (FcPatternElt) *
380 (p->num - i));
381
382 /* bump count */
383 p->num++;
384
385 e[i].object = object;
386 e[i].values = NULL;
387 }
388
389 return FcPatternElts(p) + i;
390 }
391
392 FcBool
393 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
394 {
395 int i;
396 FcPatternElt *pae, *pbe;
397
398 if (pa == pb)
399 return FcTrue;
400
401 if (pa->num != pb->num)
402 return FcFalse;
403 pae = FcPatternElts(pa);
404 pbe = FcPatternElts(pb);
405 for (i = 0; i < pa->num; i++)
406 {
407 if (pae[i].object != pbe[i].object)
408 return FcFalse;
409 if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
410 FcPatternEltValues(&pbe[i])))
411 return FcFalse;
412 }
413 return FcTrue;
414 }
415
416 FcChar32
417 FcPatternHash (const FcPattern *p)
418 {
419 int i;
420 FcChar32 h = 0;
421 FcPatternElt *pe = FcPatternElts(p);
422
423 for (i = 0; i < p->num; i++)
424 {
425 h = (((h << 1) | (h >> 31)) ^
426 pe[i].object ^
427 FcValueListHash (FcPatternEltValues(&pe[i])));
428 }
429 return h;
430 }
431
432 FcBool
433 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
434 {
435 FcPatternElt *ea, *eb;
436 int i;
437
438 for (i = 0; i < os->nobject; i++)
439 {
440 FcObject object = FcObjectFromName (os->objects[i]);
441 ea = FcPatternObjectFindElt (pai, object);
442 eb = FcPatternObjectFindElt (pbi, object);
443 if (ea)
444 {
445 if (!eb)
446 return FcFalse;
447 if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
448 return FcFalse;
449 }
450 else
451 {
452 if (eb)
453 return FcFalse;
454 }
455 }
456 return FcTrue;
457 }
458
459 FcBool
460 FcPatternObjectAddWithBinding (FcPattern *p,
461 FcObject object,
462 FcValue value,
463 FcValueBinding binding,
464 FcBool append)
465 {
466 FcPatternElt *e;
467 FcValueListPtr new, *prev;
468
469 if (p->ref == FC_REF_CONSTANT)
470 goto bail0;
471
472 new = malloc (sizeof (FcValueList));
473 if (!new)
474 goto bail0;
475
476 memset(new, 0, sizeof (FcValueList));
477 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
478 /* dup string */
479 if (value.type == FcTypeString)
480 {
481 value.u.s = FcStrStaticName (value.u.s);
482 if (!value.u.s)
483 value.type = FcTypeVoid;
484 }
485 else
486 value = FcValueSave (value);
487 if (value.type == FcTypeVoid)
488 goto bail1;
489
490 /*
491 * Make sure the stored type is valid for built-in objects
492 */
493 if (!FcObjectValidType (object, value.type))
494 goto bail1;
495
496 new->value = value;
497 new->binding = binding;
498 new->next = NULL;
499
500 e = FcPatternObjectInsertElt (p, object);
501 if (!e)
502 goto bail2;
503
504 if (append)
505 {
506 for (prev = &e->values; *prev; prev = &(*prev)->next)
507 ;
508 *prev = new;
509 }
510 else
511 {
512 new->next = e->values;
513 e->values = new;
514 }
515
516 return FcTrue;
517
518 bail2:
519 FcValueDestroy (value);
520 bail1:
521 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
522 free (new);
523 bail0:
524 return FcFalse;
525 }
526
527 FcBool
528 FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
529 {
530 return FcPatternObjectAddWithBinding (p, object,
531 value, FcValueBindingStrong, append);
532 }
533
534 FcBool
535 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
536 {
537 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
538 value, FcValueBindingStrong, append);
539 }
540
541 FcBool
542 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
543 {
544 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
545 value, FcValueBindingWeak, append);
546 }
547
548 FcBool
549 FcPatternObjectDel (FcPattern *p, FcObject object)
550 {
551 FcPatternElt *e;
552
553 e = FcPatternObjectFindElt (p, object);
554 if (!e)
555 return FcFalse;
556
557 /* destroy value */
558 FcValueListDestroy (e->values);
559
560 /* shuffle existing ones down */
561 memmove (e, e+1,
562 (FcPatternElts(p) + p->num - (e + 1)) *
563 sizeof (FcPatternElt));
564 p->num--;
565 e = FcPatternElts(p) + p->num;
566 e->object = 0;
567 e->values = NULL;
568 return FcTrue;
569 }
570
571 FcBool
572 FcPatternDel (FcPattern *p, const char *object)
573 {
574 return FcPatternObjectDel (p, FcObjectFromName (object));
575 }
576
577 FcBool
578 FcPatternRemove (FcPattern *p, const char *object, int id)
579 {
580 FcPatternElt *e;
581 FcValueListPtr *prev, l;
582
583 e = FcPatternObjectFindElt (p, FcObjectFromName (object));
584 if (!e)
585 return FcFalse;
586 for (prev = &e->values; (l = *prev); prev = &l->next)
587 {
588 if (!id)
589 {
590 *prev = l->next;
591 l->next = NULL;
592 FcValueListDestroy (l);
593 if (!e->values)
594 FcPatternDel (p, object);
595 return FcTrue;
596 }
597 id--;
598 }
599 return FcFalse;
600 }
601
602 FcBool
603 FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
604 {
605 FcValue v;
606
607 v.type = FcTypeInteger;
608 v.u.i = i;
609 return FcPatternObjectAdd (p, object, v, FcTrue);
610 }
611
612 FcBool
613 FcPatternAddInteger (FcPattern *p, const char *object, int i)
614 {
615 return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
616 }
617
618 FcBool
619 FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
620 {
621 FcValue v;
622
623 v.type = FcTypeDouble;
624 v.u.d = d;
625 return FcPatternObjectAdd (p, object, v, FcTrue);
626 }
627
628
629 FcBool
630 FcPatternAddDouble (FcPattern *p, const char *object, double d)
631 {
632 return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
633 }
634
635 FcBool
636 FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
637 {
638 FcValue v;
639
640 if (!s)
641 {
642 v.type = FcTypeVoid;
643 v.u.s = 0;
644 return FcPatternObjectAdd (p, object, v, FcTrue);
645 }
646
647 v.type = FcTypeString;
648 v.u.s = FcStrStaticName(s);
649 return FcPatternObjectAdd (p, object, v, FcTrue);
650 }
651
652 FcBool
653 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
654 {
655 return FcPatternObjectAddString (p, FcObjectFromName (object), s);
656 }
657
658 FcBool
659 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
660 {
661 FcValue v;
662
663 v.type = FcTypeMatrix;
664 v.u.m = s;
665 return FcPatternAdd (p, object, v, FcTrue);
666 }
667
668
669 FcBool
670 FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
671 {
672 FcValue v;
673
674 v.type = FcTypeBool;
675 v.u.b = b;
676 return FcPatternObjectAdd (p, object, v, FcTrue);
677 }
678
679 FcBool
680 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
681 {
682 return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
683 }
684
685 FcBool
686 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
687 {
688 FcValue v;
689
690 v.type = FcTypeCharSet;
691 v.u.c = (FcCharSet *)c;
692 return FcPatternAdd (p, object, v, FcTrue);
693 }
694
695 FcBool
696 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
697 {
698 FcValue v;
699
700 v.type = FcTypeFTFace;
701 v.u.f = (void *) f;
702 return FcPatternAdd (p, object, v, FcTrue);
703 }
704
705 FcBool
706 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
707 {
708 FcValue v;
709
710 v.type = FcTypeLangSet;
711 v.u.l = (FcLangSet *)ls;
712 return FcPatternAdd (p, object, v, FcTrue);
713 }
714
715 FcResult
716 FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
717 {
718 FcPatternElt *e;
719 FcValueListPtr l;
720
721 e = FcPatternObjectFindElt (p, object);
722 if (!e)
723 return FcResultNoMatch;
724 for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
725 {
726 if (!id)
727 {
728 *v = FcValueCanonicalize(&l->value);
729 return FcResultMatch;
730 }
731 id--;
732 }
733 return FcResultNoId;
734 }
735
736 FcResult
737 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
738 {
739 return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
740 }
741
742 FcResult
743 FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
744 {
745 FcValue v;
746 FcResult r;
747
748 r = FcPatternObjectGet (p, object, id, &v);
749 if (r != FcResultMatch)
750 return r;
751 switch (v.type) {
752 case FcTypeDouble:
753 *i = (int) v.u.d;
754 break;
755 case FcTypeInteger:
756 *i = v.u.i;
757 break;
758 default:
759 return FcResultTypeMismatch;
760 }
761 return FcResultMatch;
762 }
763
764 FcResult
765 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
766 {
767 return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
768 }
769
770
771 FcResult
772 FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
773 {
774 FcValue v;
775 FcResult r;
776
777 r = FcPatternObjectGet (p, object, id, &v);
778 if (r != FcResultMatch)
779 return r;
780 switch (v.type) {
781 case FcTypeDouble:
782 *d = v.u.d;
783 break;
784 case FcTypeInteger:
785 *d = (double) v.u.i;
786 break;
787 default:
788 return FcResultTypeMismatch;
789 }
790 return FcResultMatch;
791 }
792
793 FcResult
794 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
795 {
796 return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
797 }
798
799 FcResult
800 FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
801 {
802 FcValue v;
803 FcResult r;
804
805 r = FcPatternObjectGet (p, object, id, &v);
806 if (r != FcResultMatch)
807 return r;
808 if (v.type != FcTypeString)
809 return FcResultTypeMismatch;
810
811 *s = (FcChar8 *) v.u.s;
812 return FcResultMatch;
813 }
814
815 FcResult
816 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
817 {
818 return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
819 }
820
821 FcResult
822 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
823 {
824 FcValue v;
825 FcResult r;
826
827 r = FcPatternGet (p, object, id, &v);
828 if (r != FcResultMatch)
829 return r;
830 if (v.type != FcTypeMatrix)
831 return FcResultTypeMismatch;
832 *m = (FcMatrix *)v.u.m;
833 return FcResultMatch;
834 }
835
836
837 FcResult
838 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
839 {
840 FcValue v;
841 FcResult r;
842
843 r = FcPatternGet (p, object, id, &v);
844 if (r != FcResultMatch)
845 return r;
846 if (v.type != FcTypeBool)
847 return FcResultTypeMismatch;
848 *b = v.u.b;
849 return FcResultMatch;
850 }
851
852 FcResult
853 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
854 {
855 FcValue v;
856 FcResult r;
857
858 r = FcPatternGet (p, object, id, &v);
859 if (r != FcResultMatch)
860 return r;
861 if (v.type != FcTypeCharSet)
862 return FcResultTypeMismatch;
863 *c = (FcCharSet *)v.u.c;
864 return FcResultMatch;
865 }
866
867 FcResult
868 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
869 {
870 FcValue v;
871 FcResult r;
872
873 r = FcPatternGet (p, object, id, &v);
874 if (r != FcResultMatch)
875 return r;
876 if (v.type != FcTypeFTFace)
877 return FcResultTypeMismatch;
878 *f = (FT_Face) v.u.f;
879 return FcResultMatch;
880 }
881
882 FcResult
883 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
884 {
885 FcValue v;
886 FcResult r;
887
888 r = FcPatternGet (p, object, id, &v);
889 if (r != FcResultMatch)
890 return r;
891 if (v.type != FcTypeLangSet)
892 return FcResultTypeMismatch;
893 *ls = (FcLangSet *)v.u.l;
894 return FcResultMatch;
895 }
896
897 FcPattern *
898 FcPatternDuplicate (const FcPattern *orig)
899 {
900 FcPattern *new;
901 FcPatternElt *e;
902 int i;
903 FcValueListPtr l;
904
905 new = FcPatternCreate ();
906 if (!new)
907 goto bail0;
908
909 e = FcPatternElts(orig);
910
911 for (i = 0; i < orig->num; i++)
912 {
913 for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
914 if (!FcPatternObjectAdd (new, e[i].object,
915 FcValueCanonicalize(&l->value),
916 FcTrue))
917 goto bail1;
918 }
919
920 return new;
921
922 bail1:
923 FcPatternDestroy (new);
924 bail0:
925 return 0;
926 }
927
928 void
929 FcPatternReference (FcPattern *p)
930 {
931 if (p->ref != FC_REF_CONSTANT)
932 p->ref++;
933 }
934
935 FcPattern *
936 FcPatternVaBuild (FcPattern *orig, va_list va)
937 {
938 FcPattern *ret;
939
940 FcPatternVapBuild (ret, orig, va);
941 return ret;
942 }
943
944 FcPattern *
945 FcPatternBuild (FcPattern *orig, ...)
946 {
947 va_list va;
948
949 va_start (va, orig);
950 FcPatternVapBuild (orig, orig, va);
951 va_end (va);
952 return orig;
953 }
954
955 /*
956 * Add all of the elements in 's' to 'p'
957 */
958 FcBool
959 FcPatternAppend (FcPattern *p, FcPattern *s)
960 {
961 int i;
962 FcPatternElt *e;
963 FcValueListPtr v;
964
965 for (i = 0; i < s->num; i++)
966 {
967 e = FcPatternElts(s)+i;
968 for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
969 {
970 if (!FcPatternObjectAddWithBinding (p, e->object,
971 FcValueCanonicalize(&v->value),
972 v->binding, FcTrue))
973 return FcFalse;
974 }
975 }
976 return FcTrue;
977 }
978
979 #define OBJECT_HASH_SIZE 31
980 static struct objectBucket {
981 struct objectBucket *next;
982 FcChar32 hash;
983 } *FcObjectBuckets[OBJECT_HASH_SIZE];
984
985 static FcBool
986 FcStrHashed (const FcChar8 *name)
987 {
988 FcChar32 hash = FcStringHash (name);
989 struct objectBucket **p;
990 struct objectBucket *b;
991
992 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
993 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
994 return FcTrue;
995 return FcFalse;
996 }
997
998 const FcChar8 *
999 FcStrStaticName (const FcChar8 *name)
1000 {
1001 FcChar32 hash = FcStringHash (name);
1002 struct objectBucket **p;
1003 struct objectBucket *b;
1004 int size;
1005
1006 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1007 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1008 return (FcChar8 *) (b + 1);
1009 size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
1010 b = malloc (size + sizeof (int));
1011 /* workaround glibc bug which reads strlen in groups of 4 */
1012 FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
1013 if (!b)
1014 return NULL;
1015 b->next = 0;
1016 b->hash = hash;
1017 strcpy ((char *) (b + 1), (char *)name);
1018 *p = b;
1019 return (FcChar8 *) (b + 1);
1020 }
1021
1022 static void
1023 FcStrStaticNameFini (void)
1024 {
1025 int i, size;
1026 struct objectBucket *b, *next;
1027 char *name;
1028
1029 for (i = 0; i < OBJECT_HASH_SIZE; i++)
1030 {
1031 for (b = FcObjectBuckets[i]; b; b = next)
1032 {
1033 next = b->next;
1034 name = (char *) (b + 1);
1035 size = sizeof (struct objectBucket) + strlen (name) + 1;
1036 FcMemFree (FC_MEM_STATICSTR, size);
1037 free (b);
1038 }
1039 FcObjectBuckets[i] = 0;
1040 }
1041 }
1042
1043 void
1044 FcPatternFini (void)
1045 {
1046 FcStrStaticNameFini ();
1047 FcObjectStaticNameFini ();
1048 }
1049
1050 FcBool
1051 FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
1052 {
1053 int i;
1054 FcPatternElt *elts = FcPatternElts(pat);
1055
1056 if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1057 return FcFalse;
1058 if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
1059 return FcFalse;
1060 for (i = 0; i < pat->num; i++)
1061 if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1062 return FcFalse;
1063 return FcTrue;
1064 }
1065
1066 FcPattern *
1067 FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
1068 {
1069 FcPattern *pat_serialized;
1070 FcPatternElt *elts = FcPatternElts (pat);
1071 FcPatternElt *elts_serialized;
1072 FcValueList *values_serialized;
1073 int i;
1074
1075 pat_serialized = FcSerializePtr (serialize, pat);
1076 if (!pat_serialized)
1077 return NULL;
1078 *pat_serialized = *pat;
1079 pat_serialized->size = pat->num;
1080 pat_serialized->ref = FC_REF_CONSTANT;
1081
1082 elts_serialized = FcSerializePtr (serialize, elts);
1083 if (!elts_serialized)
1084 return NULL;
1085
1086 pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1087 elts_serialized);
1088
1089 for (i = 0; i < pat->num; i++)
1090 {
1091 values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1092 if (!values_serialized)
1093 return NULL;
1094 elts_serialized[i].object = elts[i].object;
1095 elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
1096 values_serialized,
1097 FcValueList);
1098 }
1099 return pat_serialized;
1100 }
1101
1102 FcBool
1103 FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
1104 {
1105 while (vl)
1106 {
1107 if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1108 return FcFalse;
1109 switch (vl->value.type) {
1110 case FcTypeString:
1111 if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1112 return FcFalse;
1113 break;
1114 case FcTypeCharSet:
1115 if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1116 return FcFalse;
1117 break;
1118 case FcTypeLangSet:
1119 if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1120 return FcFalse;
1121 break;
1122 default:
1123 break;
1124 }
1125 vl = vl->next;
1126 }
1127 return FcTrue;
1128 }
1129
1130 FcValueList *
1131 FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
1132 {
1133 FcValueList *vl_serialized;
1134 FcChar8 *s_serialized;
1135 FcCharSet *c_serialized;
1136 FcLangSet *l_serialized;
1137 FcValueList *head_serialized = NULL;
1138 FcValueList *prev_serialized = NULL;
1139
1140 while (vl)
1141 {
1142 vl_serialized = FcSerializePtr (serialize, vl);
1143 if (!vl_serialized)
1144 return NULL;
1145
1146 if (prev_serialized)
1147 prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1148 vl_serialized,
1149 FcValueList);
1150 else
1151 head_serialized = vl_serialized;
1152
1153 vl_serialized->next = NULL;
1154 vl_serialized->value = vl->value;
1155 switch (vl->value.type) {
1156 case FcTypeString:
1157 s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1158 if (!s_serialized)
1159 return NULL;
1160 vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1161 s_serialized,
1162 FcChar8);
1163 break;
1164 case FcTypeCharSet:
1165 c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1166 if (!c_serialized)
1167 return NULL;
1168 vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1169 c_serialized,
1170 FcCharSet);
1171 break;
1172 case FcTypeLangSet:
1173 l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1174 if (!l_serialized)
1175 return NULL;
1176 vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1177 l_serialized,
1178 FcLangSet);
1179 break;
1180 default:
1181 break;
1182 }
1183 vl = vl->next;
1184 }
1185 return head_serialized;
1186 }