]> git.wh0rd.org Git - 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 }