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