]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
Various config changes plus a couple of optimizations from Owen
[fontconfig.git] / src / fcpat.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.13 2002/08/11 18:10:42 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     default:
59         break;
60     }
61 }
62
63 FcValue
64 FcValueSave (FcValue v)
65 {
66     switch (v.type) {
67     case FcTypeString:
68         v.u.s = FcStrCopy (v.u.s);
69         if (!v.u.s)
70             v.type = FcTypeVoid;
71         break;
72     case FcTypeMatrix:
73         v.u.m = FcMatrixCopy (v.u.m);
74         if (!v.u.m)
75             v.type = FcTypeVoid;
76         break;
77     case FcTypeCharSet:
78         v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
79         if (!v.u.c)
80             v.type = FcTypeVoid;
81         break;
82     default:
83         break;
84     }
85     return v;
86 }
87
88 void
89 FcValueListDestroy (FcValueList *l)
90 {
91     FcValueList    *next;
92     for (; l; l = next)
93     {
94         switch (l->value.type) {
95         case FcTypeString:
96             FcStrFree ((FcChar8 *) l->value.u.s);
97             break;
98         case FcTypeMatrix:
99             FcMatrixFree ((FcMatrix *) l->value.u.m);
100             break;
101         case FcTypeCharSet:
102             FcCharSetDestroy ((FcCharSet *) l->value.u.c);
103             break;
104         default:
105             break;
106         }
107         next = l->next;
108         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
109         free (l);
110     }
111 }
112
113 FcBool
114 FcValueEqual (FcValue va, FcValue vb)
115 {
116     if (va.type != vb.type)
117     {
118         if (va.type == FcTypeInteger)
119         {
120             va.type = FcTypeDouble;
121             va.u.d = va.u.i;
122         }
123         if (vb.type == FcTypeInteger)
124         {
125             vb.type = FcTypeDouble;
126             vb.u.d = vb.u.i;
127         }
128         if (va.type != vb.type)
129             return FcFalse;
130     }
131     switch (va.type) {
132     case FcTypeVoid:
133         return FcTrue;
134     case FcTypeInteger:
135         return va.u.i == vb.u.i;
136     case FcTypeDouble:
137         return va.u.d == vb.u.d;
138     case FcTypeString:
139         return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
140     case FcTypeBool:
141         return va.u.b == vb.u.b;
142     case FcTypeMatrix:
143         return FcMatrixEqual (va.u.m, vb.u.m);
144     case FcTypeCharSet:
145         return FcCharSetEqual (va.u.c, vb.u.c);
146     case FcTypeFTFace:
147         return va.u.f == vb.u.f;
148     }
149     return FcFalse;
150 }
151
152 static FcChar32
153 FcDoubleHash (double d)
154 {
155     if (d < 0)
156         d = -d;
157     if (d > 0xffffffff)
158         d = 0xffffffff;
159     return (FcChar32) d;
160 }
161
162 static FcChar32
163 FcStringHash (const FcChar8 *s)
164 {
165     FcChar8     c;
166     FcChar32    h = 0;
167     
168     if (s)
169         while ((c = *s++))
170             h = ((h << 1) | (h >> 31)) ^ c;
171     return h;
172 }
173
174 static FcChar32
175 FcValueHash (FcValue v)
176 {
177     switch (v.type) {
178     case FcTypeVoid:
179         return 0;
180     case FcTypeInteger:
181         return (FcChar32) v.u.i;
182     case FcTypeDouble:
183         return FcDoubleHash (v.u.d);
184     case FcTypeString:
185         return FcStringHash (v.u.s);
186     case FcTypeBool:
187         return (FcChar32) v.u.b;
188     case FcTypeMatrix:
189         return (FcDoubleHash (v.u.m->xx) ^ 
190                 FcDoubleHash (v.u.m->xy) ^ 
191                 FcDoubleHash (v.u.m->yx) ^ 
192                 FcDoubleHash (v.u.m->yy));
193     case FcTypeCharSet:
194         return (FcChar32) v.u.c->num;
195     case FcTypeFTFace:
196         return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
197                FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
198     }
199     return FcFalse;
200 }
201
202 static FcBool
203 FcValueListEqual (FcValueList *la, FcValueList *lb)
204 {
205     while (la && lb)
206     {
207         if (!FcValueEqual (la->value, lb->value))
208             return FcFalse;
209         la = la->next;
210         lb = lb->next;
211     }
212     if (la || lb)
213         return FcFalse;
214     return FcTrue;
215 }
216
217 static FcChar32
218 FcValueListHash (FcValueList *l)
219 {
220     FcChar32    hash = 0;
221     
222     while (l)
223     {
224         hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
225         l = l->next;
226     }
227     return hash;
228 }
229
230 void
231 FcPatternDestroy (FcPattern *p)
232 {
233     int             i;
234     
235     if (--p->ref > 0)
236         return;
237
238     for (i = 0; i < p->num; i++)
239         FcValueListDestroy (p->elts[i].values);
240
241     p->num = 0;
242     if (p->elts)
243     {
244         FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
245         free (p->elts);
246         p->elts = 0;
247     }
248     p->size = 0;
249     FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
250     free (p);
251 }
252
253 static int
254 FcPatternPosition (const FcPattern *p, const char *object)
255 {
256     int     low, high, mid, c;
257
258     low = 0;
259     high = p->num - 1;
260     c = 1;
261     mid = 0;
262     while (low <= high)
263     {
264         mid = (low + high) >> 1;
265         c = strcmp (p->elts[mid].object, object);
266         if (c == 0)
267             return mid;
268         if (c < 0)
269             low = mid + 1;
270         else
271             high = mid - 1;
272     }
273     if (c < 0)
274         mid++;
275     return -(mid + 1);
276 }
277
278 FcPatternElt *
279 FcPatternFindElt (const FcPattern *p, const char *object)
280 {
281     int     i = FcPatternPosition (p, object);
282     if (i < 0)
283         return 0;
284     return &p->elts[i];
285 }
286
287 FcPatternElt *
288 FcPatternInsertElt (FcPattern *p, const char *object)
289 {
290     int             i;
291     FcPatternElt   *e;
292     
293     i = FcPatternPosition (p, object);
294     if (i < 0)
295     {
296         i = -i - 1;
297     
298         /* grow array */
299         if (p->num + 1 >= p->size)
300         {
301             int s = p->size + 16;
302             if (p->elts)
303                 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
304             else
305                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
306             if (!e)
307                 return FcFalse;
308             p->elts = e;
309             if (p->size)
310                 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
311             FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
312             while (p->size < s)
313             {
314                 p->elts[p->size].object = 0;
315                 p->elts[p->size].values = 0;
316                 p->size++;
317             }
318         }
319         
320         /* move elts up */
321         memmove (p->elts + i + 1,
322                  p->elts + i,
323                  sizeof (FcPatternElt) *
324                  (p->num - i));
325                  
326         /* bump count */
327         p->num++;
328         
329         p->elts[i].object = object;
330         p->elts[i].values = 0;
331     }
332     
333     return &p->elts[i];
334 }
335
336 FcBool
337 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
338 {
339     int i;
340
341     if (pa == pb)
342         return FcTrue;
343
344     if (pa->num != pb->num)
345         return FcFalse;
346     for (i = 0; i < pa->num; i++)
347     {
348         if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
349             return FcFalse;
350         if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
351             return FcFalse;
352     }
353     return FcTrue;
354 }
355
356 FcChar32
357 FcPatternHash (const FcPattern *p)
358 {
359     int         i;
360     FcChar32    h = 0;
361
362     for (i = 0; i < p->num; i++)
363     {
364         h = (((h << 1) | (h >> 31)) ^ 
365              FcStringHash ((const FcChar8 *) p->elts[i].object) ^
366              FcValueListHash (p->elts[i].values));
367     }
368     return h;
369 }
370
371 FcBool
372 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
373 {
374     FcPatternElt    *ea, *eb;
375     int             i;
376     
377     for (i = 0; i < os->nobject; i++)
378     {
379         ea = FcPatternFindElt (pa, os->objects[i]);
380         eb = FcPatternFindElt (pb, os->objects[i]);
381         if (ea)
382         {
383             if (!eb)
384                 return FcFalse;
385             if (!FcValueListEqual (ea->values, eb->values))
386                 return FcFalse;
387         }
388         else
389         {
390             if (eb)
391                 return FcFalse;
392         }
393     }
394     return FcTrue;
395 }
396
397 FcBool
398 FcPatternAddWithBinding  (FcPattern         *p,
399                           const char        *object,
400                           FcValue           value,
401                           FcValueBinding    binding,
402                           FcBool            append)
403 {
404     FcPatternElt   *e;
405     FcValueList    *new, **prev;
406
407     new = (FcValueList *) malloc (sizeof (FcValueList));
408     if (!new)
409         goto bail0;
410
411     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
412     /* dup string */
413     value = FcValueSave (value);
414     if (value.type == FcTypeVoid)
415         goto bail1;
416
417     new->value = value;
418     new->binding = binding;
419     new->next = 0;
420     
421     e = FcPatternInsertElt (p, object);
422     if (!e)
423         goto bail2;
424     
425     if (append)
426     {
427         for (prev = &e->values; *prev; prev = &(*prev)->next);
428         *prev = new;
429     }
430     else
431     {
432         new->next = e->values;
433         e->values = new;
434     }
435     
436     return FcTrue;
437
438 bail2:    
439     switch (value.type) {
440     case FcTypeString:
441         FcStrFree ((FcChar8 *) value.u.s);
442         break;
443     case FcTypeMatrix:
444         FcMatrixFree ((FcMatrix *) value.u.m);
445         break;
446     case FcTypeCharSet:
447         FcCharSetDestroy ((FcCharSet *) value.u.c);
448         break;
449     default:
450         break;
451     }
452 bail1:
453     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
454     free (new);
455 bail0:
456     return FcFalse;
457 }
458
459 FcBool
460 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
461 {
462     return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
463 }
464
465 FcBool
466 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
467 {
468     return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
469 }
470
471 FcBool
472 FcPatternDel (FcPattern *p, const char *object)
473 {
474     FcPatternElt   *e;
475     int             i;
476
477     e = FcPatternFindElt (p, object);
478     if (!e)
479         return FcFalse;
480
481     i = e - p->elts;
482     
483     /* destroy value */
484     FcValueListDestroy (e->values);
485     
486     /* shuffle existing ones down */
487     memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
488     p->num--;
489     p->elts[p->num].object = 0;
490     p->elts[p->num].values = 0;
491     return FcTrue;
492 }
493
494 FcBool
495 FcPatternAddInteger (FcPattern *p, const char *object, int i)
496 {
497     FcValue     v;
498
499     v.type = FcTypeInteger;
500     v.u.i = i;
501     return FcPatternAdd (p, object, v, FcTrue);
502 }
503
504 FcBool
505 FcPatternAddDouble (FcPattern *p, const char *object, double d)
506 {
507     FcValue     v;
508
509     v.type = FcTypeDouble;
510     v.u.d = d;
511     return FcPatternAdd (p, object, v, FcTrue);
512 }
513
514
515 FcBool
516 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
517 {
518     FcValue     v;
519
520     v.type = FcTypeString;
521     v.u.s = s;
522     return FcPatternAdd (p, object, v, FcTrue);
523 }
524
525 FcBool
526 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
527 {
528     FcValue     v;
529
530     v.type = FcTypeMatrix;
531     v.u.m = (FcMatrix *) s;
532     return FcPatternAdd (p, object, v, FcTrue);
533 }
534
535
536 FcBool
537 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
538 {
539     FcValue     v;
540
541     v.type = FcTypeBool;
542     v.u.b = b;
543     return FcPatternAdd (p, object, v, FcTrue);
544 }
545
546 FcBool
547 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
548 {
549     FcValue     v;
550
551     v.type = FcTypeCharSet;
552     v.u.c = (FcCharSet *) c;
553     return FcPatternAdd (p, object, v, FcTrue);
554 }
555
556 FcBool
557 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
558 {
559     FcValue     v;
560
561     v.type = FcTypeFTFace;
562     v.u.f = (void *) f;
563     return FcPatternAdd (p, object, v, FcTrue);
564 }
565
566 FcResult
567 FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
568 {
569     FcPatternElt   *e;
570     FcValueList    *l;
571
572     e = FcPatternFindElt (p, object);
573     if (!e)
574         return FcResultNoMatch;
575     for (l = e->values; l; l = l->next)
576     {
577         if (!id)
578         {
579             *v = l->value;
580             return FcResultMatch;
581         }
582         id--;
583     }
584     return FcResultNoId;
585 }
586
587 FcResult
588 FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
589 {
590     FcValue     v;
591     FcResult    r;
592
593     r = FcPatternGet (p, object, id, &v);
594     if (r != FcResultMatch)
595         return r;
596     switch (v.type) {
597     case FcTypeDouble:
598         *i = (int) v.u.d;
599         break;
600     case FcTypeInteger:
601         *i = v.u.i;
602         break;
603     default:
604         return FcResultTypeMismatch;
605     }
606     return FcResultMatch;
607 }
608
609 FcResult
610 FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
611 {
612     FcValue     v;
613     FcResult    r;
614
615     r = FcPatternGet (p, object, id, &v);
616     if (r != FcResultMatch)
617         return r;
618     switch (v.type) {
619     case FcTypeDouble:
620         *d = v.u.d;
621         break;
622     case FcTypeInteger:
623         *d = (double) v.u.i;
624         break;
625     default:
626         return FcResultTypeMismatch;
627     }
628     return FcResultMatch;
629 }
630
631 FcResult
632 FcPatternGetString (FcPattern *p, const char *object, int id, FcChar8 ** s)
633 {
634     FcValue     v;
635     FcResult    r;
636
637     r = FcPatternGet (p, object, id, &v);
638     if (r != FcResultMatch)
639         return r;
640     if (v.type != FcTypeString)
641         return FcResultTypeMismatch;
642     *s = (FcChar8 *) v.u.s;
643     return FcResultMatch;
644 }
645
646 FcResult
647 FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
648 {
649     FcValue     v;
650     FcResult    r;
651
652     r = FcPatternGet (p, object, id, &v);
653     if (r != FcResultMatch)
654         return r;
655     if (v.type != FcTypeMatrix)
656         return FcResultTypeMismatch;
657     *m = (FcMatrix *) v.u.m;
658     return FcResultMatch;
659 }
660
661
662 FcResult
663 FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
664 {
665     FcValue     v;
666     FcResult    r;
667
668     r = FcPatternGet (p, object, id, &v);
669     if (r != FcResultMatch)
670         return r;
671     if (v.type != FcTypeBool)
672         return FcResultTypeMismatch;
673     *b = v.u.b;
674     return FcResultMatch;
675 }
676
677 FcResult
678 FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
679 {
680     FcValue     v;
681     FcResult    r;
682
683     r = FcPatternGet (p, object, id, &v);
684     if (r != FcResultMatch)
685         return r;
686     if (v.type != FcTypeCharSet)
687         return FcResultTypeMismatch;
688     *c = (FcCharSet *) v.u.c;
689     return FcResultMatch;
690 }
691
692 FcResult
693 FcPatternGetFTFace (FcPattern *p, const char *object, int id, FT_Face *f)
694 {
695     FcValue     v;
696     FcResult    r;
697
698     r = FcPatternGet (p, object, id, &v);
699     if (r != FcResultMatch)
700         return r;
701     if (v.type != FcTypeFTFace)
702         return FcResultTypeMismatch;
703     *f = (FT_Face) v.u.f;
704     return FcResultMatch;
705 }
706
707 FcPattern *
708 FcPatternDuplicate (FcPattern *orig)
709 {
710     FcPattern       *new;
711     int             i;
712     FcValueList    *l;
713
714     new = FcPatternCreate ();
715     if (!new)
716         goto bail0;
717
718     for (i = 0; i < orig->num; i++)
719     {
720         for (l = orig->elts[i].values; l; l = l->next)
721             if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
722                 goto bail1;
723     }
724
725     return new;
726
727 bail1:
728     FcPatternDestroy (new);
729 bail0:
730     return 0;
731 }
732
733 void
734 FcPatternReference (FcPattern *p)
735 {
736     p->ref++;
737 }
738
739 FcPattern *
740 FcPatternVaBuild (FcPattern *orig, va_list va)
741 {
742     FcPattern   *ret;
743     
744     FcPatternVapBuild (ret, orig, va);
745     return ret;
746 }
747
748 FcPattern *
749 FcPatternBuild (FcPattern *orig, ...)
750 {
751     va_list     va;
752     
753     va_start (va, orig);
754     FcPatternVapBuild (orig, orig, va);
755     va_end (va);
756     return orig;
757 }