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