]> git.wh0rd.org - fontconfig.git/blame - src/fcpat.c
Replace 'KEITH PACKARD' with 'THE AUTHOR(S)' in license text in all files
[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 *
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:
78 new.u.s = fc_value_string(v);
79 new.type = FcTypeString;
80 break;
81 case FcTypeCharSet:
82 new.u.c = fc_value_charset(v);
83 new.type = FcTypeCharSet;
84 break;
85 case FcTypeLangSet:
86 new.u.l = fc_value_langset(v);
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:
4262e0b3
PL
101 v.u.s = FcStrCopy (v.u.s);
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:
cd2ec1a9 141 FcCharSetDestroy
7ce19673 142 ((FcCharSet *) (l->value.u.c));
24330d27 143 break;
d8d73958 144 case FcTypeLangSet:
cd2ec1a9 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;
213
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{
efb11b36 223 switch (fc_storage_type(v)) {
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:
efb11b36 231 return FcStringHash (fc_value_string(v));
d0f07b8d 232 case FcTypeBool:
efb11b36 233 return (FcChar32) v->u.b;
d0f07b8d 234 case FcTypeMatrix:
efb11b36
PL
235 return (FcDoubleHash (v->u.m->xx) ^
236 FcDoubleHash (v->u.m->xy) ^
237 FcDoubleHash (v->u.m->yx) ^
238 FcDoubleHash (v->u.m->yy));
d0f07b8d 239 case FcTypeCharSet:
efb11b36 240 return (FcChar32) fc_value_charset(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:
efb11b36 245 return FcLangSetHash (fc_value_langset(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;
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;
24330d27 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;
345
7ce19673 346 i = FcPatternObjectPosition (p, object);
e9be9cd1 347 if (i < 0)
24330d27 348 {
e9be9cd1
KP
349 i = -i - 1;
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));
388
389 /* bump count */
390 p->num++;
391
7ce19673
KP
392 e[i].object = object;
393 e[i].values = NULL;
24330d27
KP
394 }
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 {
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;
444
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
KP
484 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
485 /* dup string */
575a37b7
PL
486 if (value.type == FcTypeString)
487 {
488 value.u.s = FcStrStaticName (value.u.s);
489 if (!value.u.s)
490 value.type = FcTypeVoid;
491 }
492 else
493 value = FcValueSave (value);
24330d27
KP
494 if (value.type == FcTypeVoid)
495 goto bail1;
496
7ce19673
KP
497 /*
498 * Make sure the stored type is valid for built-in objects
499 */
500 if (!FcObjectValidType (object, value.type))
bc5e487f
KP
501 {
502 if (FcDebug() & FC_DBG_OBJTYPES)
503 {
504 printf ("FcPattern object %s does not accept value ",
505 FcObjectName (object));
506 FcValuePrint (value);
507 }
7ce19673 508 goto bail1;
bc5e487f 509 }
7ce19673
KP
510
511 new->value = value;
512 new->binding = binding;
513 new->next = NULL;
24330d27 514
7ce19673 515 e = FcPatternObjectInsertElt (p, object);
24330d27
KP
516 if (!e)
517 goto bail2;
518
519 if (append)
520 {
7ce19673 521 for (prev = &e->values; *prev; prev = &(*prev)->next)
cd2ec1a9 522 ;
24330d27
KP
523 *prev = new;
524 }
525 else
526 {
7ce19673 527 new->next = e->values;
24330d27
KP
528 e->values = new;
529 }
530
531 return FcTrue;
532
533bail2:
7ce19673 534 FcValueDestroy (value);
24330d27
KP
535bail1:
536 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
7ce19673 537 free (new);
24330d27
KP
538bail0:
539 return FcFalse;
540}
541
7ce19673
KP
542FcBool
543FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
544{
545 return FcPatternObjectAddWithBinding (p, object,
546 value, FcValueBindingStrong, append);
547}
548
82f4243f
KP
549FcBool
550FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
551{
7ce19673
KP
552 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
553 value, FcValueBindingStrong, append);
82f4243f
KP
554}
555
556FcBool
557FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
558{
7ce19673
KP
559 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
560 value, FcValueBindingWeak, append);
82f4243f
KP
561}
562
24330d27 563FcBool
7ce19673 564FcPatternObjectDel (FcPattern *p, FcObject object)
24330d27
KP
565{
566 FcPatternElt *e;
24330d27 567
7ce19673 568 e = FcPatternObjectFindElt (p, object);
24330d27
KP
569 if (!e)
570 return FcFalse;
571
24330d27
KP
572 /* destroy value */
573 FcValueListDestroy (e->values);
574
575 /* shuffle existing ones down */
cd2ec1a9 576 memmove (e, e+1,
7ce19673 577 (FcPatternElts(p) + p->num - (e + 1)) *
cd2ec1a9 578 sizeof (FcPatternElt));
24330d27 579 p->num--;
7ce19673
KP
580 e = FcPatternElts(p) + p->num;
581 e->object = 0;
582 e->values = NULL;
24330d27
KP
583 return FcTrue;
584}
585
7ce19673
KP
586FcBool
587FcPatternDel (FcPattern *p, const char *object)
588{
589 return FcPatternObjectDel (p, FcObjectFromName (object));
590}
591
4f27c1c0
KP
592FcBool
593FcPatternRemove (FcPattern *p, const char *object, int id)
594{
cd2ec1a9
PL
595 FcPatternElt *e;
596 FcValueListPtr *prev, l;
4f27c1c0 597
7ce19673 598 e = FcPatternObjectFindElt (p, FcObjectFromName (object));
4f27c1c0
KP
599 if (!e)
600 return FcFalse;
7ce19673 601 for (prev = &e->values; (l = *prev); prev = &l->next)
4f27c1c0
KP
602 {
603 if (!id)
604 {
7ce19673
KP
605 *prev = l->next;
606 l->next = NULL;
4f27c1c0 607 FcValueListDestroy (l);
7ce19673 608 if (!e->values)
4f27c1c0
KP
609 FcPatternDel (p, object);
610 return FcTrue;
611 }
612 id--;
613 }
614 return FcFalse;
615}
616
24330d27 617FcBool
7ce19673 618FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
24330d27
KP
619{
620 FcValue v;
621
622 v.type = FcTypeInteger;
623 v.u.i = i;
7ce19673 624 return FcPatternObjectAdd (p, object, v, FcTrue);
24330d27
KP
625}
626
627FcBool
7ce19673
KP
628FcPatternAddInteger (FcPattern *p, const char *object, int i)
629{
630 return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
631}
632
633FcBool
634FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
24330d27
KP
635{
636 FcValue v;
637
638 v.type = FcTypeDouble;
639 v.u.d = d;
7ce19673 640 return FcPatternObjectAdd (p, object, v, FcTrue);
24330d27
KP
641}
642
643
644FcBool
7ce19673
KP
645FcPatternAddDouble (FcPattern *p, const char *object, double d)
646{
647 return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
648}
649
650FcBool
651FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
24330d27
KP
652{
653 FcValue v;
654
204da5a8
PL
655 if (!s)
656 {
657 v.type = FcTypeVoid;
658 v.u.s = 0;
7ce19673 659 return FcPatternObjectAdd (p, object, v, FcTrue);
204da5a8
PL
660 }
661
24330d27 662 v.type = FcTypeString;
7f37423d 663 v.u.s = FcStrStaticName(s);
7ce19673
KP
664 return FcPatternObjectAdd (p, object, v, FcTrue);
665}
666
667FcBool
668FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
669{
670 return FcPatternObjectAddString (p, FcObjectFromName (object), s);
24330d27
KP
671}
672
673FcBool
674FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
675{
676 FcValue v;
677
678 v.type = FcTypeMatrix;
4262e0b3 679 v.u.m = s;
24330d27
KP
680 return FcPatternAdd (p, object, v, FcTrue);
681}
682
683
684FcBool
7ce19673 685FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
24330d27
KP
686{
687 FcValue v;
688
689 v.type = FcTypeBool;
690 v.u.b = b;
7ce19673
KP
691 return FcPatternObjectAdd (p, object, v, FcTrue);
692}
693
694FcBool
695FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
696{
697 return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
24330d27
KP
698}
699
700FcBool
701FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
702{
703 FcValue v;
704
705 v.type = FcTypeCharSet;
4262e0b3 706 v.u.c = (FcCharSet *)c;
24330d27
KP
707 return FcPatternAdd (p, object, v, FcTrue);
708}
709
be094850
KP
710FcBool
711FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
712{
713 FcValue v;
714
715 v.type = FcTypeFTFace;
716 v.u.f = (void *) f;
717 return FcPatternAdd (p, object, v, FcTrue);
718}
719
d8d73958
KP
720FcBool
721FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
722{
723 FcValue v;
724
725 v.type = FcTypeLangSet;
4262e0b3 726 v.u.l = (FcLangSet *)ls;
d8d73958
KP
727 return FcPatternAdd (p, object, v, FcTrue);
728}
729
24330d27 730FcResult
7ce19673 731FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
24330d27
KP
732{
733 FcPatternElt *e;
cd2ec1a9 734 FcValueListPtr l;
24330d27 735
7ce19673 736 e = FcPatternObjectFindElt (p, object);
24330d27
KP
737 if (!e)
738 return FcResultNoMatch;
7ce19673 739 for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
24330d27
KP
740 {
741 if (!id)
742 {
7ce19673 743 *v = FcValueCanonicalize(&l->value);
24330d27
KP
744 return FcResultMatch;
745 }
746 id--;
747 }
748 return FcResultNoId;
749}
750
751FcResult
7ce19673
KP
752FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
753{
754 return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
755}
756
757FcResult
758FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
24330d27
KP
759{
760 FcValue v;
761 FcResult r;
762
7ce19673 763 r = FcPatternObjectGet (p, object, id, &v);
24330d27
KP
764 if (r != FcResultMatch)
765 return r;
766 switch (v.type) {
767 case FcTypeDouble:
768 *i = (int) v.u.d;
769 break;
770 case FcTypeInteger:
771 *i = v.u.i;
772 break;
773 default:
774 return FcResultTypeMismatch;
775 }
776 return FcResultMatch;
777}
778
779FcResult
7ce19673
KP
780FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
781{
782 return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
783}
784
785
786FcResult
787FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
24330d27
KP
788{
789 FcValue v;
790 FcResult r;
791
7ce19673 792 r = FcPatternObjectGet (p, object, id, &v);
24330d27
KP
793 if (r != FcResultMatch)
794 return r;
795 switch (v.type) {
796 case FcTypeDouble:
797 *d = v.u.d;
798 break;
799 case FcTypeInteger:
800 *d = (double) v.u.i;
801 break;
802 default:
803 return FcResultTypeMismatch;
804 }
805 return FcResultMatch;
806}
807
808FcResult
7ce19673
KP
809FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
810{
811 return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
812}
813
814FcResult
815FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
24330d27
KP
816{
817 FcValue v;
818 FcResult r;
819
7ce19673 820 r = FcPatternObjectGet (p, object, id, &v);
24330d27
KP
821 if (r != FcResultMatch)
822 return r;
823 if (v.type != FcTypeString)
824 return FcResultTypeMismatch;
e77c1718 825
4262e0b3 826 *s = (FcChar8 *) v.u.s;
24330d27
KP
827 return FcResultMatch;
828}
829
7ce19673
KP
830FcResult
831FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
832{
833 return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
834}
835
24330d27 836FcResult
bff80114 837FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
24330d27
KP
838{
839 FcValue v;
840 FcResult r;
841
842 r = FcPatternGet (p, object, id, &v);
843 if (r != FcResultMatch)
844 return r;
845 if (v.type != FcTypeMatrix)
846 return FcResultTypeMismatch;
4262e0b3 847 *m = (FcMatrix *)v.u.m;
24330d27
KP
848 return FcResultMatch;
849}
850
851
852FcResult
bff80114 853FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
24330d27
KP
854{
855 FcValue v;
856 FcResult r;
857
858 r = FcPatternGet (p, object, id, &v);
859 if (r != FcResultMatch)
860 return r;
861 if (v.type != FcTypeBool)
862 return FcResultTypeMismatch;
863 *b = v.u.b;
864 return FcResultMatch;
865}
866
867FcResult
bff80114 868FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
24330d27
KP
869{
870 FcValue v;
871 FcResult r;
872
873 r = FcPatternGet (p, object, id, &v);
874 if (r != FcResultMatch)
875 return r;
876 if (v.type != FcTypeCharSet)
877 return FcResultTypeMismatch;
4262e0b3 878 *c = (FcCharSet *)v.u.c;
24330d27
KP
879 return FcResultMatch;
880}
881
be094850 882FcResult
bff80114 883FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
be094850
KP
884{
885 FcValue v;
886 FcResult r;
887
888 r = FcPatternGet (p, object, id, &v);
889 if (r != FcResultMatch)
890 return r;
891 if (v.type != FcTypeFTFace)
892 return FcResultTypeMismatch;
893 *f = (FT_Face) v.u.f;
894 return FcResultMatch;
895}
896
d8d73958 897FcResult
bff80114 898FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
d8d73958
KP
899{
900 FcValue v;
901 FcResult r;
902
903 r = FcPatternGet (p, object, id, &v);
904 if (r != FcResultMatch)
905 return r;
906 if (v.type != FcTypeLangSet)
907 return FcResultTypeMismatch;
4262e0b3 908 *ls = (FcLangSet *)v.u.l;
d8d73958
KP
909 return FcResultMatch;
910}
911
24330d27 912FcPattern *
bff80114 913FcPatternDuplicate (const FcPattern *orig)
24330d27
KP
914{
915 FcPattern *new;
cd2ec1a9 916 FcPatternElt *e;
24330d27 917 int i;
cd2ec1a9 918 FcValueListPtr l;
24330d27
KP
919
920 new = FcPatternCreate ();
921 if (!new)
922 goto bail0;
923
7ce19673 924 e = FcPatternElts(orig);
cd2ec1a9 925
24330d27
KP
926 for (i = 0; i < orig->num; i++)
927 {
7ce19673 928 for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
9b74b78f
SK
929 {
930 if (!FcPatternObjectAddWithBinding (new, e[i].object,
931 FcValueCanonicalize(&l->value),
932 l->binding,
933 FcTrue))
24330d27 934 goto bail1;
9b74b78f
SK
935
936 }
24330d27
KP
937 }
938
939 return new;
940
941bail1:
942 FcPatternDestroy (new);
943bail0:
944 return 0;
945}
946
6f6563ed
KP
947void
948FcPatternReference (FcPattern *p)
949{
d8d73958
KP
950 if (p->ref != FC_REF_CONSTANT)
951 p->ref++;
9e612141
KP
952 else
953 FcCacheObjectReference (p);
6f6563ed
KP
954}
955
24330d27 956FcPattern *
74e16cee 957FcPatternVaBuild (FcPattern *p, va_list va)
24330d27
KP
958{
959 FcPattern *ret;
960
74e16cee 961 FcPatternVapBuild (ret, p, va);
24330d27
KP
962 return ret;
963}
964
965FcPattern *
74e16cee 966FcPatternBuild (FcPattern *p, ...)
24330d27
KP
967{
968 va_list va;
969
74e16cee
BE
970 va_start (va, p);
971 FcPatternVapBuild (p, p, va);
24330d27 972 va_end (va);
74e16cee 973 return p;
24330d27 974}
4f27c1c0
KP
975
976/*
977 * Add all of the elements in 's' to 'p'
978 */
979FcBool
980FcPatternAppend (FcPattern *p, FcPattern *s)
981{
982 int i;
983 FcPatternElt *e;
cd2ec1a9 984 FcValueListPtr v;
4f27c1c0
KP
985
986 for (i = 0; i < s->num; i++)
987 {
7ce19673
KP
988 e = FcPatternElts(s)+i;
989 for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
4f27c1c0 990 {
7ce19673
KP
991 if (!FcPatternObjectAddWithBinding (p, e->object,
992 FcValueCanonicalize(&v->value),
993 v->binding, FcTrue))
4f27c1c0
KP
994 return FcFalse;
995 }
996 }
997 return FcTrue;
998}
999
41fc0fe6
BE
1000FcPattern *
1001FcPatternFilter (FcPattern *p, const FcObjectSet *os)
1002{
1003 int i;
1004 FcPattern *ret;
1005 FcPatternElt *e;
1006 FcValueListPtr v;
1007
1008 if (!os)
1009 return FcPatternDuplicate (p);
1010
1011 ret = FcPatternCreate ();
1012 if (!ret)
1013 return NULL;
1014
1015 for (i = 0; i < os->nobject; i++)
1016 {
1017 FcObject object = FcObjectFromName (os->objects[i]);
1018 e = FcPatternObjectFindElt (p, object);
1019 if (e)
1020 {
1021 for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
1022 {
1023 if (!FcPatternObjectAddWithBinding (ret, e->object,
1024 FcValueCanonicalize(&v->value),
1025 v->binding, FcTrue))
1026 goto bail0;
1027 }
1028 }
1029 }
263f16ce 1030 return ret;
41fc0fe6
BE
1031
1032bail0:
1033 FcPatternDestroy (ret);
1034 return NULL;
1035}
1036
4262e0b3 1037#define OBJECT_HASH_SIZE 31
8245771d 1038static struct objectBucket {
4262e0b3
PL
1039 struct objectBucket *next;
1040 FcChar32 hash;
8245771d 1041} *FcObjectBuckets[OBJECT_HASH_SIZE];
4262e0b3 1042
9ede93f1 1043static FcBool
799691c9 1044FcHashOwnsName (const FcChar8 *name)
9ede93f1
PL
1045{
1046 FcChar32 hash = FcStringHash (name);
1047 struct objectBucket **p;
1048 struct objectBucket *b;
1049
1050 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
799691c9 1051 if (b->hash == hash && ((char *)name == (char *) (b + 1)))
9ede93f1
PL
1052 return FcTrue;
1053 return FcFalse;
1054}
1055
8245771d
PL
1056const FcChar8 *
1057FcStrStaticName (const FcChar8 *name)
4262e0b3 1058{
8245771d
PL
1059 FcChar32 hash = FcStringHash (name);
1060 struct objectBucket **p;
1061 struct objectBucket *b;
1062 int size;
4262e0b3 1063
8245771d
PL
1064 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1065 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1066 return (FcChar8 *) (b + 1);
1067 size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
23787a8f
PL
1068 b = malloc (size + sizeof (int));
1069 /* workaround glibc bug which reads strlen in groups of 4 */
1070 FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
4262e0b3
PL
1071 if (!b)
1072 return NULL;
1073 b->next = 0;
1074 b->hash = hash;
8245771d 1075 strcpy ((char *) (b + 1), (char *)name);
4262e0b3 1076 *p = b;
8245771d 1077 return (FcChar8 *) (b + 1);
4262e0b3
PL
1078}
1079
1080static void
7f37423d 1081FcStrStaticNameFini (void)
cd2ec1a9 1082{
4262e0b3
PL
1083 int i, size;
1084 struct objectBucket *b, *next;
1085 char *name;
1086
1087 for (i = 0; i < OBJECT_HASH_SIZE; i++)
cd2ec1a9 1088 {
4262e0b3
PL
1089 for (b = FcObjectBuckets[i]; b; b = next)
1090 {
1091 next = b->next;
1092 name = (char *) (b + 1);
1093 size = sizeof (struct objectBucket) + strlen (name) + 1;
13a14cbf 1094 FcMemFree (FC_MEM_STATICSTR, size + sizeof (int));
4262e0b3
PL
1095 free (b);
1096 }
1097 FcObjectBuckets[i] = 0;
cd2ec1a9
PL
1098 }
1099}
1100
4262e0b3
PL
1101void
1102FcPatternFini (void)
1103{
7f37423d 1104 FcStrStaticNameFini ();
09f9f6f6 1105 FcObjectFini ();
4262e0b3
PL
1106}
1107
7ce19673
KP
1108FcBool
1109FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
4262e0b3 1110{
7ce19673
KP
1111 int i;
1112 FcPatternElt *elts = FcPatternElts(pat);
4262e0b3 1113
7ce19673
KP
1114 if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1115 return FcFalse;
1116 if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
1117 return FcFalse;
1118 for (i = 0; i < pat->num; i++)
1119 if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1120 return FcFalse;
1121 return FcTrue;
4262e0b3
PL
1122}
1123
cd2ec1a9 1124FcPattern *
7ce19673 1125FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
cd2ec1a9 1126{
7ce19673
KP
1127 FcPattern *pat_serialized;
1128 FcPatternElt *elts = FcPatternElts (pat);
1129 FcPatternElt *elts_serialized;
1130 FcValueList *values_serialized;
1131 int i;
212c9f43 1132
7ce19673
KP
1133 pat_serialized = FcSerializePtr (serialize, pat);
1134 if (!pat_serialized)
1135 return NULL;
1136 *pat_serialized = *pat;
1137 pat_serialized->size = pat->num;
1138 pat_serialized->ref = FC_REF_CONSTANT;
1139
1140 elts_serialized = FcSerializePtr (serialize, elts);
1141 if (!elts_serialized)
1142 return NULL;
1143
1144 pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1145 elts_serialized);
212c9f43 1146
7ce19673 1147 for (i = 0; i < pat->num; i++)
cd2ec1a9 1148 {
7ce19673
KP
1149 values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1150 if (!values_serialized)
1151 return NULL;
1152 elts_serialized[i].object = elts[i].object;
1153 elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
1154 values_serialized,
1155 FcValueList);
cd2ec1a9 1156 }
c0288648
KP
1157 if (FcDebug() & FC_DBG_CACHEV) {
1158 printf ("Raw pattern:\n");
1159 FcPatternPrint (pat);
1160 printf ("Serialized pattern:\n");
1161 FcPatternPrint (pat_serialized);
1162 printf ("\n");
1163 }
7ce19673 1164 return pat_serialized;
4262e0b3 1165}
212c9f43 1166
7ce19673
KP
1167FcBool
1168FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
4262e0b3 1169{
7ce19673 1170 while (vl)
212c9f43 1171 {
7ce19673
KP
1172 if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1173 return FcFalse;
1174 switch (vl->value.type) {
1175 case FcTypeString:
1176 if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1177 return FcFalse;
1178 break;
4262e0b3 1179 case FcTypeCharSet:
7ce19673
KP
1180 if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1181 return FcFalse;
4262e0b3
PL
1182 break;
1183 case FcTypeLangSet:
7ce19673
KP
1184 if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1185 return FcFalse;
4262e0b3 1186 break;
4262e0b3
PL
1187 default:
1188 break;
1189 }
7ce19673 1190 vl = vl->next;
4262e0b3 1191 }
212c9f43
PL
1192 return FcTrue;
1193}
1194
7ce19673
KP
1195FcValueList *
1196FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
212c9f43 1197{
7ce19673
KP
1198 FcValueList *vl_serialized;
1199 FcChar8 *s_serialized;
1200 FcCharSet *c_serialized;
1201 FcLangSet *l_serialized;
1202 FcValueList *head_serialized = NULL;
1203 FcValueList *prev_serialized = NULL;
4262e0b3 1204
7ce19673 1205 while (vl)
0fa680f0 1206 {
7ce19673
KP
1207 vl_serialized = FcSerializePtr (serialize, vl);
1208 if (!vl_serialized)
1209 return NULL;
1210
1211 if (prev_serialized)
1212 prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1213 vl_serialized,
1214 FcValueList);
1215 else
1216 head_serialized = vl_serialized;
1217
1218 vl_serialized->next = NULL;
2b77216e 1219 vl_serialized->value.type = vl->value.type;
7ce19673 1220 switch (vl->value.type) {
2b77216e
KP
1221 case FcTypeInteger:
1222 vl_serialized->value.u.i = vl->value.u.i;
1223 break;
1224 case FcTypeDouble:
1225 vl_serialized->value.u.d = vl->value.u.d;
1226 break;
7ce19673
KP
1227 case FcTypeString:
1228 s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1229 if (!s_serialized)
1230 return NULL;
1231 vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1232 s_serialized,
1233 FcChar8);
1234 break;
2b77216e
KP
1235 case FcTypeBool:
1236 vl_serialized->value.u.b = vl->value.u.b;
1237 break;
1238 case FcTypeMatrix:
1239 /* can't happen */
1240 break;
7ce19673
KP
1241 case FcTypeCharSet:
1242 c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1243 if (!c_serialized)
1244 return NULL;
1245 vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1246 c_serialized,
1247 FcCharSet);
1248 break;
2b77216e
KP
1249 case FcTypeFTFace:
1250 /* can't happen */
1251 break;
7ce19673
KP
1252 case FcTypeLangSet:
1253 l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1254 if (!l_serialized)
1255 return NULL;
1256 vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1257 l_serialized,
1258 FcLangSet);
1259 break;
1260 default:
1261 break;
0fa680f0 1262 }
e9a564e2 1263 prev_serialized = vl_serialized;
7ce19673 1264 vl = vl->next;
0fa680f0 1265 }
7ce19673 1266 return head_serialized;
e1b9d091 1267}
23816bf9
KP
1268#define __fcpat__
1269#include "fcaliastail.h"
a0a1da22 1270#include "fcftaliastail.h"
23816bf9 1271#undef __fcpat__