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