]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Short circuit FcPatternEqual when both args point at the same pattern
[fontconfig.git] / src / fcpat.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.11 2002/07/06 23:47:44 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 }