]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Fix weird first/not-first lameness in font matches, replacing with target
[fontconfig.git] / src / fcpat.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.12 2002/08/07 01:45:59 keithp Exp $
3 *
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include "fcint.h"
28
29 FcPattern *
30 FcPatternCreate (void)
31 {
32 FcPattern *p;
33
34 p = (FcPattern *) malloc (sizeof (FcPattern));
35 if (!p)
36 return 0;
37 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
38 p->num = 0;
39 p->size = 0;
40 p->elts = 0;
41 p->ref = 1;
42 return p;
43 }
44
45 void
46 FcValueDestroy (FcValue v)
47 {
48 switch (v.type) {
49 case FcTypeString:
50 FcStrFree ((FcChar8 *) v.u.s);
51 break;
52 case FcTypeMatrix:
53 FcMatrixFree ((FcMatrix *) v.u.m);
54 break;
55 case FcTypeCharSet:
56 FcCharSetDestroy ((FcCharSet *) v.u.c);
57 break;
58 case FcTypePattern:
59 FcPatternDestroy ((FcPattern *) v.u.p);
60 break;
61 default:
62 break;
63 }
64 }
65
66 FcValue
67 FcValueSave (FcValue v)
68 {
69 switch (v.type) {
70 case FcTypeString:
71 v.u.s = FcStrCopy (v.u.s);
72 if (!v.u.s)
73 v.type = FcTypeVoid;
74 break;
75 case FcTypeMatrix:
76 v.u.m = FcMatrixCopy (v.u.m);
77 if (!v.u.m)
78 v.type = FcTypeVoid;
79 break;
80 case FcTypeCharSet:
81 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
82 if (!v.u.c)
83 v.type = FcTypeVoid;
84 break;
85 case FcTypePattern:
86 FcPatternReference ((FcPattern *) v.u.p);
87 break;
88 default:
89 break;
90 }
91 return v;
92 }
93
94 void
95 FcValueListDestroy (FcValueList *l)
96 {
97 FcValueList *next;
98 for (; l; l = next)
99 {
100 switch (l->value.type) {
101 case FcTypeString:
102 FcStrFree ((FcChar8 *) l->value.u.s);
103 break;
104 case FcTypeMatrix:
105 FcMatrixFree ((FcMatrix *) l->value.u.m);
106 break;
107 case FcTypeCharSet:
108 FcCharSetDestroy ((FcCharSet *) l->value.u.c);
109 break;
110 case FcTypePattern:
111 FcPatternDestroy ((FcPattern *) l->value.u.p);
112 break;
113 default:
114 break;
115 }
116 next = l->next;
117 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
118 free (l);
119 }
120 }
121
122 FcBool
123 FcValueEqual (FcValue va, FcValue vb)
124 {
125 if (va.type != vb.type)
126 {
127 if (va.type == FcTypeInteger)
128 {
129 va.type = FcTypeDouble;
130 va.u.d = va.u.i;
131 }
132 if (vb.type == FcTypeInteger)
133 {
134 vb.type = FcTypeDouble;
135 vb.u.d = vb.u.i;
136 }
137 if (va.type != vb.type)
138 return FcFalse;
139 }
140 switch (va.type) {
141 case FcTypeVoid:
142 return FcTrue;
143 case FcTypeInteger:
144 return va.u.i == vb.u.i;
145 case FcTypeDouble:
146 return va.u.d == vb.u.d;
147 case FcTypeString:
148 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
149 case FcTypeBool:
150 return va.u.b == vb.u.b;
151 case FcTypeMatrix:
152 return FcMatrixEqual (va.u.m, vb.u.m);
153 case FcTypeCharSet:
154 return FcCharSetEqual (va.u.c, vb.u.c);
155 case FcTypeFTFace:
156 return va.u.f == vb.u.f;
157 case FcTypePattern:
158 return FcPatternEqual (va.u.p, vb.u.p);
159 }
160 return FcFalse;
161 }
162
163 static FcChar32
164 FcDoubleHash (double d)
165 {
166 if (d < 0)
167 d = -d;
168 if (d > 0xffffffff)
169 d = 0xffffffff;
170 return (FcChar32) d;
171 }
172
173 static FcChar32
174 FcStringHash (const FcChar8 *s)
175 {
176 FcChar8 c;
177 FcChar32 h = 0;
178
179 if (s)
180 while ((c = *s++))
181 h = ((h << 1) | (h >> 31)) ^ c;
182 return h;
183 }
184
185 static FcChar32
186 FcValueHash (FcValue v)
187 {
188 switch (v.type) {
189 case FcTypeVoid:
190 return 0;
191 case FcTypeInteger:
192 return (FcChar32) v.u.i;
193 case FcTypeDouble:
194 return FcDoubleHash (v.u.d);
195 case FcTypeString:
196 return FcStringHash (v.u.s);
197 case FcTypeBool:
198 return (FcChar32) v.u.b;
199 case FcTypeMatrix:
200 return (FcDoubleHash (v.u.m->xx) ^
201 FcDoubleHash (v.u.m->xy) ^
202 FcDoubleHash (v.u.m->yx) ^
203 FcDoubleHash (v.u.m->yy));
204 case FcTypeCharSet:
205 return (FcChar32) v.u.c->num;
206 case FcTypeFTFace:
207 return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
208 FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
209 case FcTypePattern:
210 return (FcChar32) v.u.p->num;
211 }
212 return FcFalse;
213 }
214
215 static FcBool
216 FcValueListEqual (FcValueList *la, FcValueList *lb)
217 {
218 while (la && lb)
219 {
220 if (!FcValueEqual (la->value, lb->value))
221 return FcFalse;
222 la = la->next;
223 lb = lb->next;
224 }
225 if (la || lb)
226 return FcFalse;
227 return FcTrue;
228 }
229
230 static FcChar32
231 FcValueListHash (FcValueList *l)
232 {
233 FcChar32 hash = 0;
234
235 while (l)
236 {
237 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
238 l = l->next;
239 }
240 return hash;
241 }
242
243 void
244 FcPatternDestroy (FcPattern *p)
245 {
246 int i;
247
248 if (--p->ref > 0)
249 return;
250
251 for (i = 0; i < p->num; i++)
252 FcValueListDestroy (p->elts[i].values);
253
254 p->num = 0;
255 if (p->elts)
256 {
257 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
258 free (p->elts);
259 p->elts = 0;
260 }
261 p->size = 0;
262 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
263 free (p);
264 }
265
266 static int
267 FcPatternPosition (const FcPattern *p, const char *object)
268 {
269 int low, high, mid, c;
270
271 low = 0;
272 high = p->num - 1;
273 c = 1;
274 mid = 0;
275 while (low <= high)
276 {
277 mid = (low + high) >> 1;
278 c = strcmp (p->elts[mid].object, object);
279 if (c == 0)
280 return mid;
281 if (c < 0)
282 low = mid + 1;
283 else
284 high = mid - 1;
285 }
286 if (c < 0)
287 mid++;
288 return -(mid + 1);
289 }
290
291 FcPatternElt *
292 FcPatternFindElt (const FcPattern *p, const char *object)
293 {
294 int i = FcPatternPosition (p, object);
295 if (i < 0)
296 return 0;
297 return &p->elts[i];
298 }
299
300 FcPatternElt *
301 FcPatternInsertElt (FcPattern *p, const char *object)
302 {
303 int i;
304 FcPatternElt *e;
305
306 i = FcPatternPosition (p, object);
307 if (i < 0)
308 {
309 i = -i - 1;
310
311 /* grow array */
312 if (p->num + 1 >= p->size)
313 {
314 int s = p->size + 16;
315 if (p->elts)
316 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
317 else
318 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
319 if (!e)
320 return FcFalse;
321 p->elts = e;
322 if (p->size)
323 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
324 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
325 while (p->size < s)
326 {
327 p->elts[p->size].object = 0;
328 p->elts[p->size].values = 0;
329 p->size++;
330 }
331 }
332
333 /* move elts up */
334 memmove (p->elts + i + 1,
335 p->elts + i,
336 sizeof (FcPatternElt) *
337 (p->num - i));
338
339 /* bump count */
340 p->num++;
341
342 p->elts[i].object = object;
343 p->elts[i].values = 0;
344 }
345
346 return &p->elts[i];
347 }
348
349 FcBool
350 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
351 {
352 int i;
353
354 if (pa == pb)
355 return FcTrue;
356
357 if (pa->num != pb->num)
358 return FcFalse;
359 for (i = 0; i < pa->num; i++)
360 {
361 if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
362 return FcFalse;
363 if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
364 return FcFalse;
365 }
366 return FcTrue;
367 }
368
369 FcChar32
370 FcPatternHash (const FcPattern *p)
371 {
372 int i;
373 FcChar32 h = 0;
374
375 for (i = 0; i < p->num; i++)
376 {
377 h = (((h << 1) | (h >> 31)) ^
378 FcStringHash ((const FcChar8 *) p->elts[i].object) ^
379 FcValueListHash (p->elts[i].values));
380 }
381 return h;
382 }
383
384 FcBool
385 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
386 {
387 FcPatternElt *ea, *eb;
388 int i;
389
390 for (i = 0; i < os->nobject; i++)
391 {
392 ea = FcPatternFindElt (pa, os->objects[i]);
393 eb = FcPatternFindElt (pb, os->objects[i]);
394 if (ea)
395 {
396 if (!eb)
397 return FcFalse;
398 if (!FcValueListEqual (ea->values, eb->values))
399 return FcFalse;
400 }
401 else
402 {
403 if (eb)
404 return FcFalse;
405 }
406 }
407 return FcTrue;
408 }
409
410 FcBool
411 FcPatternAddWithBinding (FcPattern *p,
412 const char *object,
413 FcValue value,
414 FcValueBinding binding,
415 FcBool append)
416 {
417 FcPatternElt *e;
418 FcValueList *new, **prev;
419
420 new = (FcValueList *) malloc (sizeof (FcValueList));
421 if (!new)
422 goto bail0;
423
424 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
425 /* dup string */
426 value = FcValueSave (value);
427 if (value.type == FcTypeVoid)
428 goto bail1;
429
430 new->value = value;
431 new->binding = binding;
432 new->next = 0;
433
434 e = FcPatternInsertElt (p, object);
435 if (!e)
436 goto bail2;
437
438 if (append)
439 {
440 for (prev = &e->values; *prev; prev = &(*prev)->next);
441 *prev = new;
442 }
443 else
444 {
445 new->next = e->values;
446 e->values = new;
447 }
448
449 return FcTrue;
450
451 bail2:
452 switch (value.type) {
453 case FcTypeString:
454 FcStrFree ((FcChar8 *) value.u.s);
455 break;
456 case FcTypeMatrix:
457 FcMatrixFree ((FcMatrix *) value.u.m);
458 break;
459 case FcTypeCharSet:
460 FcCharSetDestroy ((FcCharSet *) value.u.c);
461 break;
462 case FcTypePattern:
463 FcPatternDestroy ((FcPattern *) value.u.p);
464 break;
465 default:
466 break;
467 }
468 bail1:
469 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
470 free (new);
471 bail0:
472 return FcFalse;
473 }
474
475 FcBool
476 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
477 {
478 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
479 }
480
481 FcBool
482 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
483 {
484 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
485 }
486
487 FcBool
488 FcPatternDel (FcPattern *p, const char *object)
489 {
490 FcPatternElt *e;
491 int i;
492
493 e = FcPatternFindElt (p, object);
494 if (!e)
495 return FcFalse;
496
497 i = e - p->elts;
498
499 /* destroy value */
500 FcValueListDestroy (e->values);
501
502 /* shuffle existing ones down */
503 memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
504 p->num--;
505 p->elts[p->num].object = 0;
506 p->elts[p->num].values = 0;
507 return FcTrue;
508 }
509
510 FcBool
511 FcPatternAddInteger (FcPattern *p, const char *object, int i)
512 {
513 FcValue v;
514
515 v.type = FcTypeInteger;
516 v.u.i = i;
517 return FcPatternAdd (p, object, v, FcTrue);
518 }
519
520 FcBool
521 FcPatternAddDouble (FcPattern *p, const char *object, double d)
522 {
523 FcValue v;
524
525 v.type = FcTypeDouble;
526 v.u.d = d;
527 return FcPatternAdd (p, object, v, FcTrue);
528 }
529
530
531 FcBool
532 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
533 {
534 FcValue v;
535
536 v.type = FcTypeString;
537 v.u.s = s;
538 return FcPatternAdd (p, object, v, FcTrue);
539 }
540
541 FcBool
542 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
543 {
544 FcValue v;
545
546 v.type = FcTypeMatrix;
547 v.u.m = (FcMatrix *) s;
548 return FcPatternAdd (p, object, v, FcTrue);
549 }
550
551
552 FcBool
553 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
554 {
555 FcValue v;
556
557 v.type = FcTypeBool;
558 v.u.b = b;
559 return FcPatternAdd (p, object, v, FcTrue);
560 }
561
562 FcBool
563 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
564 {
565 FcValue v;
566
567 v.type = FcTypeCharSet;
568 v.u.c = (FcCharSet *) c;
569 return FcPatternAdd (p, object, v, FcTrue);
570 }
571
572 FcBool
573 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
574 {
575 FcValue v;
576
577 v.type = FcTypeFTFace;
578 v.u.f = (void *) f;
579 return FcPatternAdd (p, object, v, FcTrue);
580 }
581
582 FcBool
583 FcPatternAddPattern (FcPattern *p, const char *object, const FcPattern *pp)
584 {
585 FcValue v;
586
587 v.type = FcTypePattern;
588 v.u.p = pp;
589 return FcPatternAdd (p, object, v, FcTrue);
590 }
591
592 FcResult
593 FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
594 {
595 FcPatternElt *e;
596 FcValueList *l;
597
598 e = FcPatternFindElt (p, object);
599 if (!e)
600 return FcResultNoMatch;
601 for (l = e->values; l; l = l->next)
602 {
603 if (!id)
604 {
605 *v = l->value;
606 return FcResultMatch;
607 }
608 id--;
609 }
610 return FcResultNoId;
611 }
612
613 FcResult
614 FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
615 {
616 FcValue v;
617 FcResult r;
618
619 r = FcPatternGet (p, object, id, &v);
620 if (r != FcResultMatch)
621 return r;
622 switch (v.type) {
623 case FcTypeDouble:
624 *i = (int) v.u.d;
625 break;
626 case FcTypeInteger:
627 *i = v.u.i;
628 break;
629 default:
630 return FcResultTypeMismatch;
631 }
632 return FcResultMatch;
633 }
634
635 FcResult
636 FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
637 {
638 FcValue v;
639 FcResult r;
640
641 r = FcPatternGet (p, object, id, &v);
642 if (r != FcResultMatch)
643 return r;
644 switch (v.type) {
645 case FcTypeDouble:
646 *d = v.u.d;
647 break;
648 case FcTypeInteger:
649 *d = (double) v.u.i;
650 break;
651 default:
652 return FcResultTypeMismatch;
653 }
654 return FcResultMatch;
655 }
656
657 FcResult
658 FcPatternGetString (FcPattern *p, const char *object, int id, FcChar8 ** s)
659 {
660 FcValue v;
661 FcResult r;
662
663 r = FcPatternGet (p, object, id, &v);
664 if (r != FcResultMatch)
665 return r;
666 if (v.type != FcTypeString)
667 return FcResultTypeMismatch;
668 *s = (FcChar8 *) v.u.s;
669 return FcResultMatch;
670 }
671
672 FcResult
673 FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
674 {
675 FcValue v;
676 FcResult r;
677
678 r = FcPatternGet (p, object, id, &v);
679 if (r != FcResultMatch)
680 return r;
681 if (v.type != FcTypeMatrix)
682 return FcResultTypeMismatch;
683 *m = (FcMatrix *) v.u.m;
684 return FcResultMatch;
685 }
686
687
688 FcResult
689 FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
690 {
691 FcValue v;
692 FcResult r;
693
694 r = FcPatternGet (p, object, id, &v);
695 if (r != FcResultMatch)
696 return r;
697 if (v.type != FcTypeBool)
698 return FcResultTypeMismatch;
699 *b = v.u.b;
700 return FcResultMatch;
701 }
702
703 FcResult
704 FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
705 {
706 FcValue v;
707 FcResult r;
708
709 r = FcPatternGet (p, object, id, &v);
710 if (r != FcResultMatch)
711 return r;
712 if (v.type != FcTypeCharSet)
713 return FcResultTypeMismatch;
714 *c = (FcCharSet *) v.u.c;
715 return FcResultMatch;
716 }
717
718 FcResult
719 FcPatternGetFTFace (FcPattern *p, const char *object, int id, FT_Face *f)
720 {
721 FcValue v;
722 FcResult r;
723
724 r = FcPatternGet (p, object, id, &v);
725 if (r != FcResultMatch)
726 return r;
727 if (v.type != FcTypeFTFace)
728 return FcResultTypeMismatch;
729 *f = (FT_Face) v.u.f;
730 return FcResultMatch;
731 }
732
733 FcResult
734 FcPatternGetPattern (FcPattern *p, const char *object, int id, FcPattern **pp)
735 {
736 FcValue v;
737 FcResult r;
738
739 r = FcPatternGet (p, object, id, &v);
740 if (r != FcResultMatch)
741 return r;
742 if (v.type != FcTypePattern)
743 return FcResultTypeMismatch;
744 *pp = (FcPattern *) v.u.p;
745 return FcResultMatch;
746 }
747
748 FcPattern *
749 FcPatternDuplicate (FcPattern *orig)
750 {
751 FcPattern *new;
752 int i;
753 FcValueList *l;
754
755 new = FcPatternCreate ();
756 if (!new)
757 goto bail0;
758
759 for (i = 0; i < orig->num; i++)
760 {
761 for (l = orig->elts[i].values; l; l = l->next)
762 if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
763 goto bail1;
764 }
765
766 return new;
767
768 bail1:
769 FcPatternDestroy (new);
770 bail0:
771 return 0;
772 }
773
774 void
775 FcPatternReference (FcPattern *p)
776 {
777 p->ref++;
778 }
779
780 FcPattern *
781 FcPatternVaBuild (FcPattern *orig, va_list va)
782 {
783 FcPattern *ret;
784
785 FcPatternVapBuild (ret, orig, va);
786 return ret;
787 }
788
789 FcPattern *
790 FcPatternBuild (FcPattern *orig, ...)
791 {
792 va_list va;
793
794 va_start (va, orig);
795 FcPatternVapBuild (orig, orig, va);
796 va_end (va);
797 return orig;
798 }