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