fcpat.c revision a4e54154
1/* 2 * Copyright © 2000 Keith Packard 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 the author(s) not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. The authors make 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 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE AUTHOR(S) 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 23#include "fcint.h" 24#include "fcftint.h" 25 26/* Objects MT-safe for readonly access. */ 27 28FcPattern * 29FcPatternCreate (void) 30{ 31 FcPattern *p; 32 33 p = (FcPattern *) malloc (sizeof (FcPattern)); 34 if (!p) 35 return 0; 36 memset (p, 0, sizeof (FcPattern)); 37 p->num = 0; 38 p->size = 0; 39 p->elts_offset = FcPtrToOffset (p, NULL); 40 FcRefInit (&p->ref, 1); 41 return p; 42} 43 44void 45FcValueDestroy (FcValue v) 46{ 47 switch ((int) v.type) { 48 case FcTypeString: 49 FcFree (v.u.s); 50 break; 51 case FcTypeMatrix: 52 FcMatrixFree ((FcMatrix *) v.u.m); 53 break; 54 case FcTypeCharSet: 55 FcCharSetDestroy ((FcCharSet *) v.u.c); 56 break; 57 case FcTypeLangSet: 58 FcLangSetDestroy ((FcLangSet *) v.u.l); 59 break; 60 case FcTypeRange: 61 FcRangeDestroy ((FcRange *) v.u.r); 62 break; 63 default: 64 break; 65 } 66} 67 68FcValue 69FcValueCanonicalize (const FcValue *v) 70{ 71 FcValue new; 72 73 switch ((int) v->type) 74 { 75 case FcTypeString: 76 new.u.s = FcValueString(v); 77 new.type = FcTypeString; 78 break; 79 case FcTypeCharSet: 80 new.u.c = FcValueCharSet(v); 81 new.type = FcTypeCharSet; 82 break; 83 case FcTypeLangSet: 84 new.u.l = FcValueLangSet(v); 85 new.type = FcTypeLangSet; 86 break; 87 case FcTypeRange: 88 new.u.r = FcValueRange(v); 89 new.type = FcTypeRange; 90 break; 91 default: 92 new = *v; 93 break; 94 } 95 return new; 96} 97 98FcValue 99FcValueSave (FcValue v) 100{ 101 switch ((int) v.type) { 102 case FcTypeString: 103 v.u.s = FcStrdup (v.u.s); 104 if (!v.u.s) 105 v.type = FcTypeVoid; 106 break; 107 case FcTypeMatrix: 108 v.u.m = FcMatrixCopy (v.u.m); 109 if (!v.u.m) 110 v.type = FcTypeVoid; 111 break; 112 case FcTypeCharSet: 113 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c); 114 if (!v.u.c) 115 v.type = FcTypeVoid; 116 break; 117 case FcTypeLangSet: 118 v.u.l = FcLangSetCopy (v.u.l); 119 if (!v.u.l) 120 v.type = FcTypeVoid; 121 break; 122 case FcTypeRange: 123 v.u.r = FcRangeCopy (v.u.r); 124 if (!v.u.r) 125 v.type = FcTypeVoid; 126 break; 127 default: 128 break; 129 } 130 return v; 131} 132 133FcValueListPtr 134FcValueListCreate (void) 135{ 136 return calloc (1, sizeof (FcValueList)); 137} 138 139void 140FcValueListDestroy (FcValueListPtr l) 141{ 142 FcValueListPtr next; 143 for (; l; l = next) 144 { 145 FcValueDestroy (l->value); 146 next = FcValueListNext(l); 147 free(l); 148 } 149} 150 151FcValueListPtr 152FcValueListPrepend (FcValueListPtr vallist, 153 FcValue value, 154 FcValueBinding binding) 155{ 156 FcValueListPtr new; 157 158 if (value.type == FcTypeVoid) 159 return vallist; 160 new = FcValueListCreate (); 161 if (!new) 162 return vallist; 163 164 new->value = FcValueSave (value); 165 new->binding = binding; 166 new->next = vallist; 167 168 return new; 169} 170 171FcValueListPtr 172FcValueListAppend (FcValueListPtr vallist, 173 FcValue value, 174 FcValueBinding binding) 175{ 176 FcValueListPtr new, last; 177 178 if (value.type == FcTypeVoid) 179 return vallist; 180 new = FcValueListCreate (); 181 if (!new) 182 return vallist; 183 184 new->value = FcValueSave (value); 185 new->binding = binding; 186 new->next = NULL; 187 188 if (vallist) 189 { 190 for (last = vallist; FcValueListNext (last); last = FcValueListNext (last)); 191 192 last->next = new; 193 } 194 else 195 vallist = new; 196 197 return vallist; 198} 199 200FcValueListPtr 201FcValueListDuplicate(FcValueListPtr orig) 202{ 203 FcValueListPtr new = NULL, l, t = NULL; 204 FcValue v; 205 206 for (l = orig; l != NULL; l = FcValueListNext (l)) 207 { 208 if (!new) 209 { 210 t = new = FcValueListCreate(); 211 } 212 else 213 { 214 t->next = FcValueListCreate(); 215 t = FcValueListNext (t); 216 } 217 v = FcValueCanonicalize (&l->value); 218 t->value = FcValueSave (v); 219 t->binding = l->binding; 220 t->next = NULL; 221 } 222 223 return new; 224} 225 226FcBool 227FcValueEqual (FcValue va, FcValue vb) 228{ 229 if (va.type != vb.type) 230 { 231 if (va.type == FcTypeInteger) 232 { 233 va.type = FcTypeDouble; 234 va.u.d = va.u.i; 235 } 236 if (vb.type == FcTypeInteger) 237 { 238 vb.type = FcTypeDouble; 239 vb.u.d = vb.u.i; 240 } 241 if (va.type != vb.type) 242 return FcFalse; 243 } 244 switch (va.type) { 245 case FcTypeUnknown: 246 return FcFalse; /* don't know how to compare this object */ 247 case FcTypeVoid: 248 return FcTrue; 249 case FcTypeInteger: 250 return va.u.i == vb.u.i; 251 case FcTypeDouble: 252 return va.u.d == vb.u.d; 253 case FcTypeString: 254 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0; 255 case FcTypeBool: 256 return va.u.b == vb.u.b; 257 case FcTypeMatrix: 258 return FcMatrixEqual (va.u.m, vb.u.m); 259 case FcTypeCharSet: 260 return FcCharSetEqual (va.u.c, vb.u.c); 261 case FcTypeFTFace: 262 return va.u.f == vb.u.f; 263 case FcTypeLangSet: 264 return FcLangSetEqual (va.u.l, vb.u.l); 265 case FcTypeRange: 266 return FcRangeIsInRange (va.u.r, vb.u.r); 267 } 268 return FcFalse; 269} 270 271static FcChar32 272FcDoubleHash (double d) 273{ 274 if (d < 0) 275 d = -d; 276 if (d > 0xffffffff) 277 d = 0xffffffff; 278 return (FcChar32) d; 279} 280 281FcChar32 282FcStringHash (const FcChar8 *s) 283{ 284 FcChar8 c; 285 FcChar32 h = 0; 286 287 if (s) 288 while ((c = *s++)) 289 h = ((h << 1) | (h >> 31)) ^ c; 290 return h; 291} 292 293static FcChar32 294FcValueHash (const FcValue *v) 295{ 296 switch (v->type) { 297 case FcTypeUnknown: 298 case FcTypeVoid: 299 return 0; 300 case FcTypeInteger: 301 return (FcChar32) v->u.i; 302 case FcTypeDouble: 303 return FcDoubleHash (v->u.d); 304 case FcTypeString: 305 return FcStringHash (FcValueString(v)); 306 case FcTypeBool: 307 return (FcChar32) v->u.b; 308 case FcTypeMatrix: 309 return (FcDoubleHash (v->u.m->xx) ^ 310 FcDoubleHash (v->u.m->xy) ^ 311 FcDoubleHash (v->u.m->yx) ^ 312 FcDoubleHash (v->u.m->yy)); 313 case FcTypeCharSet: 314 return (FcChar32) FcValueCharSet(v)->num; 315 case FcTypeFTFace: 316 return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^ 317 FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name); 318 case FcTypeLangSet: 319 return FcLangSetHash (FcValueLangSet(v)); 320 case FcTypeRange: 321 return FcRangeHash (FcValueRange (v)); 322 } 323 return 0; 324} 325 326static FcBool 327FcValueListEqual (FcValueListPtr la, FcValueListPtr lb) 328{ 329 if (la == lb) 330 return FcTrue; 331 332 while (la && lb) 333 { 334 if (!FcValueEqual (la->value, lb->value)) 335 return FcFalse; 336 la = FcValueListNext(la); 337 lb = FcValueListNext(lb); 338 } 339 if (la || lb) 340 return FcFalse; 341 return FcTrue; 342} 343 344static FcChar32 345FcValueListHash (FcValueListPtr l) 346{ 347 FcChar32 hash = 0; 348 349 for (; l; l = FcValueListNext(l)) 350 { 351 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value); 352 } 353 return hash; 354} 355 356static void * 357FcPatternGetCacheObject (FcPattern *p) 358{ 359 /* We use a value to find the cache, instead of the FcPattern object 360 * because the pattern itself may be a cache allocation if we rewrote the path, 361 * so the p may not be in the cached region. */ 362 return FcPatternEltValues(&FcPatternElts (p)[0]); 363} 364 365FcPattern * 366FcPatternCacheRewriteFile (const FcPattern *p, 367 FcCache *cache, 368 const FcChar8 *relocated_font_file) 369{ 370 FcPatternElt *elts = FcPatternElts (p); 371 size_t i,j; 372 FcChar8 *data; 373 FcPattern *new_p; 374 FcPatternElt *new_elts; 375 FcValueList *new_value_list; 376 size_t new_path_len = strlen ((char *)relocated_font_file); 377 FcChar8 *new_path; 378 379 /* Allocate space for the patter, the PatternElt headers and 380 * the FC_FILE FcValueList and path that will be freed with the 381 * cache */ 382 data = FcCacheAllocate (cache, 383 sizeof (FcPattern) + 384 p->num * sizeof (FcPatternElt) + 385 sizeof (FcValueList) + 386 new_path_len + 1); 387 388 new_p = (FcPattern *)data; 389 data += sizeof (FcPattern); 390 new_elts = (FcPatternElt *)(data); 391 data += p->num * sizeof (FcPatternElt); 392 new_value_list = (FcValueList *)data; 393 data += sizeof (FcValueList); 394 new_path = data; 395 396 *new_p = *p; 397 new_p->elts_offset = FcPtrToOffset (new_p, new_elts); 398 399 /* Copy all but the FILE values from the cache */ 400 for (i = 0, j = 0; i < p->num; i++) 401 { 402 FcPatternElt *elt = &elts[i]; 403 new_elts[j].object = elt->object; 404 if (elt->object != FC_FILE_OBJECT) 405 new_elts[j++].values = FcPatternEltValues(elt); 406 else 407 new_elts[j++].values = new_value_list; 408 } 409 410 new_value_list->next = NULL; 411 new_value_list->value.type = FcTypeString; 412 new_value_list->value.u.s = new_path; 413 new_value_list->binding = FcValueBindingWeak; 414 415 /* Add rewritten path at the end */ 416 strcpy ((char *)new_path, (char *)relocated_font_file); 417 418 return new_p; 419} 420 421void 422FcPatternDestroy (FcPattern *p) 423{ 424 int i; 425 FcPatternElt *elts; 426 427 if (!p) 428 return; 429 430 if (FcRefIsConst (&p->ref)) 431 { 432 FcCacheObjectDereference (FcPatternGetCacheObject(p)); 433 return; 434 } 435 436 if (FcRefDec (&p->ref) != 1) 437 return; 438 439 elts = FcPatternElts (p); 440 for (i = 0; i < FcPatternObjectCount (p); i++) 441 FcValueListDestroy (FcPatternEltValues(&elts[i])); 442 443 free (elts); 444 free (p); 445} 446 447int 448FcPatternObjectCount (const FcPattern *pat) 449{ 450 if (pat) 451 return pat->num; 452 453 return 0; 454} 455 456 457static int 458FcPatternObjectPosition (const FcPattern *p, FcObject object) 459{ 460 int low, high, mid, c; 461 FcPatternElt *elts = FcPatternElts(p); 462 463 low = 0; 464 high = FcPatternObjectCount (p) - 1; 465 c = 1; 466 mid = 0; 467 while (low <= high) 468 { 469 mid = (low + high) >> 1; 470 c = elts[mid].object - object; 471 if (c == 0) 472 return mid; 473 if (c < 0) 474 low = mid + 1; 475 else 476 high = mid - 1; 477 } 478 if (c < 0) 479 mid++; 480 return -(mid + 1); 481} 482 483int 484FcPatternPosition (const FcPattern *p, const char *object) 485{ 486 return FcPatternObjectPosition (p, FcObjectFromName (object)); 487} 488 489FcPatternElt * 490FcPatternObjectFindElt (const FcPattern *p, FcObject object) 491{ 492 int i = FcPatternObjectPosition (p, object); 493 if (i < 0) 494 return 0; 495 return &FcPatternElts(p)[i]; 496} 497 498FcPatternElt * 499FcPatternObjectInsertElt (FcPattern *p, FcObject object) 500{ 501 int i; 502 FcPatternElt *e; 503 504 i = FcPatternObjectPosition (p, object); 505 if (i < 0) 506 { 507 i = -i - 1; 508 509 /* reallocate array */ 510 if (FcPatternObjectCount (p) + 1 >= p->size) 511 { 512 int s = p->size + 16; 513 if (p->size) 514 { 515 FcPatternElt *e0 = FcPatternElts(p); 516 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt)); 517 if (!e) /* maybe it was mmapped */ 518 { 519 e = malloc(s * sizeof (FcPatternElt)); 520 if (e) 521 memcpy(e, e0, FcPatternObjectCount (p) * sizeof (FcPatternElt)); 522 } 523 } 524 else 525 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt)); 526 if (!e) 527 return FcFalse; 528 p->elts_offset = FcPtrToOffset (p, e); 529 while (p->size < s) 530 { 531 e[p->size].object = 0; 532 e[p->size].values = NULL; 533 p->size++; 534 } 535 } 536 537 e = FcPatternElts(p); 538 /* move elts up */ 539 memmove (e + i + 1, 540 e + i, 541 sizeof (FcPatternElt) * 542 (FcPatternObjectCount (p) - i)); 543 544 /* bump count */ 545 p->num++; 546 547 e[i].object = object; 548 e[i].values = NULL; 549 } 550 551 return FcPatternElts(p) + i; 552} 553 554FcBool 555FcPatternEqual (const FcPattern *pa, const FcPattern *pb) 556{ 557 FcPatternIter ia, ib; 558 559 if (pa == pb) 560 return FcTrue; 561 562 if (FcPatternObjectCount (pa) != FcPatternObjectCount (pb)) 563 return FcFalse; 564 FcPatternIterStart (pa, &ia); 565 FcPatternIterStart (pb, &ib); 566 do { 567 FcBool ra, rb; 568 569 if (!FcPatternIterEqual (pa, &ia, pb, &ib)) 570 return FcFalse; 571 ra = FcPatternIterNext (pa, &ia); 572 rb = FcPatternIterNext (pb, &ib); 573 if (!ra && !rb) 574 break; 575 } while (1); 576 577 return FcTrue; 578} 579 580FcChar32 581FcPatternHash (const FcPattern *p) 582{ 583 int i; 584 FcChar32 h = 0; 585 FcPatternElt *pe = FcPatternElts(p); 586 587 for (i = 0; i < FcPatternObjectCount (p); i++) 588 { 589 h = (((h << 1) | (h >> 31)) ^ 590 pe[i].object ^ 591 FcValueListHash (FcPatternEltValues(&pe[i]))); 592 } 593 return h; 594} 595 596FcBool 597FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os) 598{ 599 FcPatternElt *ea, *eb; 600 int i; 601 602 for (i = 0; i < os->nobject; i++) 603 { 604 FcObject object = FcObjectFromName (os->objects[i]); 605 ea = FcPatternObjectFindElt (pai, object); 606 eb = FcPatternObjectFindElt (pbi, object); 607 if (ea) 608 { 609 if (!eb) 610 return FcFalse; 611 if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb))) 612 return FcFalse; 613 } 614 else 615 { 616 if (eb) 617 return FcFalse; 618 } 619 } 620 return FcTrue; 621} 622 623FcBool 624FcPatternObjectListAdd (FcPattern *p, 625 FcObject object, 626 FcValueListPtr list, 627 FcBool append) 628{ 629 FcPatternElt *e; 630 FcValueListPtr l, *prev; 631 632 if (FcRefIsConst (&p->ref)) 633 goto bail0; 634 635 /* 636 * Make sure the stored type is valid for built-in objects 637 */ 638 for (l = list; l != NULL; l = FcValueListNext (l)) 639 { 640 if (!FcObjectValidType (object, l->value.type)) 641 { 642 fprintf (stderr, 643 "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); 644 FcValuePrintFile (stderr, l->value); 645 fprintf (stderr, "\n"); 646 goto bail0; 647 } 648 } 649 650 e = FcPatternObjectInsertElt (p, object); 651 if (!e) 652 goto bail0; 653 654 if (append) 655 { 656 for (prev = &e->values; *prev; prev = &(*prev)->next) 657 ; 658 *prev = list; 659 } 660 else 661 { 662 for (prev = &list; *prev; prev = &(*prev)->next) 663 ; 664 *prev = e->values; 665 e->values = list; 666 } 667 668 return FcTrue; 669 670bail0: 671 return FcFalse; 672} 673 674FcBool 675FcPatternObjectAddWithBinding (FcPattern *p, 676 FcObject object, 677 FcValue value, 678 FcValueBinding binding, 679 FcBool append) 680{ 681 FcPatternElt *e; 682 FcValueListPtr new, *prev; 683 684 if (FcRefIsConst (&p->ref)) 685 goto bail0; 686 687 new = FcValueListCreate (); 688 if (!new) 689 goto bail0; 690 691 new->value = FcValueSave (value); 692 new->binding = binding; 693 new->next = NULL; 694 695 if (new->value.type == FcTypeVoid) 696 goto bail1; 697 698 /* 699 * Make sure the stored type is valid for built-in objects 700 */ 701 if (!FcObjectValidType (object, new->value.type)) 702 { 703 fprintf (stderr, 704 "Fontconfig warning: FcPattern object %s does not accept value", 705 FcObjectName (object)); 706 FcValuePrintFile (stderr, new->value); 707 fprintf (stderr, "\n"); 708 goto bail1; 709 } 710 711 e = FcPatternObjectInsertElt (p, object); 712 if (!e) 713 goto bail1; 714 715 if (append) 716 { 717 for (prev = &e->values; *prev; prev = &(*prev)->next) 718 ; 719 *prev = new; 720 } 721 else 722 { 723 new->next = e->values; 724 e->values = new; 725 } 726 727 return FcTrue; 728 729bail1: 730 FcValueListDestroy (new); 731bail0: 732 return FcFalse; 733} 734 735FcBool 736FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append) 737{ 738 return FcPatternObjectAddWithBinding (p, object, 739 value, FcValueBindingStrong, append); 740} 741 742FcBool 743FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append) 744{ 745 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object), 746 value, FcValueBindingStrong, append); 747} 748 749FcBool 750FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append) 751{ 752 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object), 753 value, FcValueBindingWeak, append); 754} 755 756FcBool 757FcPatternObjectDel (FcPattern *p, FcObject object) 758{ 759 FcPatternElt *e; 760 761 e = FcPatternObjectFindElt (p, object); 762 if (!e) 763 return FcFalse; 764 765 /* destroy value */ 766 FcValueListDestroy (e->values); 767 768 /* shuffle existing ones down */ 769 memmove (e, e+1, 770 (FcPatternElts(p) + FcPatternObjectCount (p) - (e + 1)) * 771 sizeof (FcPatternElt)); 772 p->num--; 773 e = FcPatternElts(p) + FcPatternObjectCount (p); 774 e->object = 0; 775 e->values = NULL; 776 return FcTrue; 777} 778 779FcBool 780FcPatternDel (FcPattern *p, const char *object) 781{ 782 return FcPatternObjectDel (p, FcObjectFromName (object)); 783} 784 785FcBool 786FcPatternRemove (FcPattern *p, const char *object, int id) 787{ 788 FcPatternElt *e; 789 FcValueListPtr *prev, l; 790 791 e = FcPatternObjectFindElt (p, FcObjectFromName (object)); 792 if (!e) 793 return FcFalse; 794 for (prev = &e->values; (l = *prev); prev = &l->next) 795 { 796 if (!id) 797 { 798 *prev = l->next; 799 l->next = NULL; 800 FcValueListDestroy (l); 801 if (!e->values) 802 FcPatternDel (p, object); 803 return FcTrue; 804 } 805 id--; 806 } 807 return FcFalse; 808} 809 810FcBool 811FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i) 812{ 813 FcValue v; 814 815 v.type = FcTypeInteger; 816 v.u.i = i; 817 return FcPatternObjectAdd (p, object, v, FcTrue); 818} 819 820FcBool 821FcPatternAddInteger (FcPattern *p, const char *object, int i) 822{ 823 return FcPatternObjectAddInteger (p, FcObjectFromName (object), i); 824} 825 826FcBool 827FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d) 828{ 829 FcValue v; 830 831 v.type = FcTypeDouble; 832 v.u.d = d; 833 return FcPatternObjectAdd (p, object, v, FcTrue); 834} 835 836 837FcBool 838FcPatternAddDouble (FcPattern *p, const char *object, double d) 839{ 840 return FcPatternObjectAddDouble (p, FcObjectFromName (object), d); 841} 842 843FcBool 844FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s) 845{ 846 FcValue v; 847 848 if (!s) 849 { 850 v.type = FcTypeVoid; 851 v.u.s = 0; 852 return FcPatternObjectAdd (p, object, v, FcTrue); 853 } 854 855 v.type = FcTypeString; 856 v.u.s = s; 857 return FcPatternObjectAdd (p, object, v, FcTrue); 858} 859 860FcBool 861FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s) 862{ 863 return FcPatternObjectAddString (p, FcObjectFromName (object), s); 864} 865 866FcBool 867FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s) 868{ 869 FcValue v; 870 871 v.type = FcTypeMatrix; 872 v.u.m = s; 873 return FcPatternAdd (p, object, v, FcTrue); 874} 875 876 877FcBool 878FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b) 879{ 880 FcValue v; 881 882 v.type = FcTypeBool; 883 v.u.b = b; 884 return FcPatternObjectAdd (p, object, v, FcTrue); 885} 886 887FcBool 888FcPatternAddBool (FcPattern *p, const char *object, FcBool b) 889{ 890 return FcPatternObjectAddBool (p, FcObjectFromName (object), b); 891} 892 893FcBool 894FcPatternObjectAddCharSet (FcPattern *p, FcObject object, const FcCharSet *c) 895{ 896 FcValue v; 897 898 v.type = FcTypeCharSet; 899 v.u.c = (FcCharSet *)c; 900 return FcPatternObjectAdd (p, object, v, FcTrue); 901} 902 903FcBool 904FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c) 905{ 906 return FcPatternObjectAddCharSet (p, FcObjectFromName (object), c); 907} 908 909FcBool 910FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f) 911{ 912 FcValue v; 913 914 v.type = FcTypeFTFace; 915 v.u.f = (void *) f; 916 return FcPatternAdd (p, object, v, FcTrue); 917} 918 919FcBool 920FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls) 921{ 922 FcValue v; 923 924 v.type = FcTypeLangSet; 925 v.u.l = (FcLangSet *)ls; 926 return FcPatternObjectAdd (p, object, v, FcTrue); 927} 928 929FcBool 930FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls) 931{ 932 return FcPatternObjectAddLangSet (p, FcObjectFromName (object), ls); 933} 934 935FcBool 936FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r) 937{ 938 FcValue v; 939 940 v.type = FcTypeRange; 941 v.u.r = (FcRange *)r; 942 return FcPatternObjectAdd (p, object, v, FcTrue); 943} 944 945FcBool 946FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r) 947{ 948 return FcPatternObjectAddRange (p, FcObjectFromName (object), r); 949} 950 951FcResult 952FcPatternObjectGetWithBinding (const FcPattern *p, FcObject object, int id, FcValue *v, FcValueBinding *b) 953{ 954 FcPatternElt *e; 955 FcValueListPtr l; 956 957 if (!p) 958 return FcResultNoMatch; 959 e = FcPatternObjectFindElt (p, object); 960 if (!e) 961 return FcResultNoMatch; 962 for (l = FcPatternEltValues(e); l; l = FcValueListNext(l)) 963 { 964 if (!id) 965 { 966 *v = FcValueCanonicalize(&l->value); 967 if (b) 968 *b = l->binding; 969 return FcResultMatch; 970 } 971 id--; 972 } 973 return FcResultNoId; 974} 975 976FcResult 977FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v) 978{ 979 return FcPatternObjectGetWithBinding (p, object, id, v, NULL); 980} 981 982FcResult 983FcPatternGetWithBinding (const FcPattern *p, const char *object, int id, FcValue *v, FcValueBinding *b) 984{ 985 return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, b); 986} 987 988FcResult 989FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v) 990{ 991 return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, NULL); 992} 993 994FcResult 995FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i) 996{ 997 FcValue v; 998 FcResult r; 999 1000 r = FcPatternObjectGet (p, object, id, &v); 1001 if (r != FcResultMatch) 1002 return r; 1003 switch ((int) v.type) { 1004 case FcTypeDouble: 1005 *i = (int) v.u.d; 1006 break; 1007 case FcTypeInteger: 1008 *i = v.u.i; 1009 break; 1010 default: 1011 return FcResultTypeMismatch; 1012 } 1013 return FcResultMatch; 1014} 1015 1016FcResult 1017FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i) 1018{ 1019 return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i); 1020} 1021 1022 1023FcResult 1024FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d) 1025{ 1026 FcValue v; 1027 FcResult r; 1028 1029 r = FcPatternObjectGet (p, object, id, &v); 1030 if (r != FcResultMatch) 1031 return r; 1032 switch ((int) v.type) { 1033 case FcTypeDouble: 1034 *d = v.u.d; 1035 break; 1036 case FcTypeInteger: 1037 *d = (double) v.u.i; 1038 break; 1039 default: 1040 return FcResultTypeMismatch; 1041 } 1042 return FcResultMatch; 1043} 1044 1045FcResult 1046FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d) 1047{ 1048 return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d); 1049} 1050 1051FcResult 1052FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s) 1053{ 1054 FcValue v; 1055 FcResult r; 1056 1057 r = FcPatternObjectGet (p, object, id, &v); 1058 if (r != FcResultMatch) 1059 return r; 1060 if (v.type != FcTypeString) 1061 return FcResultTypeMismatch; 1062 1063 *s = (FcChar8 *) v.u.s; 1064 return FcResultMatch; 1065} 1066 1067FcResult 1068FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s) 1069{ 1070 return FcPatternObjectGetString (p, FcObjectFromName (object), id, s); 1071} 1072 1073FcResult 1074FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m) 1075{ 1076 FcValue v; 1077 FcResult r; 1078 1079 r = FcPatternGet (p, object, id, &v); 1080 if (r != FcResultMatch) 1081 return r; 1082 if (v.type != FcTypeMatrix) 1083 return FcResultTypeMismatch; 1084 *m = (FcMatrix *)v.u.m; 1085 return FcResultMatch; 1086} 1087 1088 1089FcResult 1090FcPatternObjectGetBool (const FcPattern *p, FcObject object, int id, FcBool *b) 1091{ 1092 FcValue v; 1093 FcResult r; 1094 1095 r = FcPatternObjectGet (p, object, id, &v); 1096 if (r != FcResultMatch) 1097 return r; 1098 if (v.type != FcTypeBool) 1099 return FcResultTypeMismatch; 1100 *b = v.u.b; 1101 return FcResultMatch; 1102} 1103 1104FcResult 1105FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b) 1106{ 1107 return FcPatternObjectGetBool (p, FcObjectFromName (object), id, b); 1108} 1109 1110FcResult 1111FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c) 1112{ 1113 FcValue v; 1114 FcResult r; 1115 1116 r = FcPatternGet (p, object, id, &v); 1117 if (r != FcResultMatch) 1118 return r; 1119 if (v.type != FcTypeCharSet) 1120 return FcResultTypeMismatch; 1121 *c = (FcCharSet *)v.u.c; 1122 return FcResultMatch; 1123} 1124 1125FcResult 1126FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f) 1127{ 1128 FcValue v; 1129 FcResult r; 1130 1131 r = FcPatternGet (p, object, id, &v); 1132 if (r != FcResultMatch) 1133 return r; 1134 if (v.type != FcTypeFTFace) 1135 return FcResultTypeMismatch; 1136 *f = (FT_Face) v.u.f; 1137 return FcResultMatch; 1138} 1139 1140FcResult 1141FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls) 1142{ 1143 FcValue v; 1144 FcResult r; 1145 1146 r = FcPatternGet (p, object, id, &v); 1147 if (r != FcResultMatch) 1148 return r; 1149 if (v.type != FcTypeLangSet) 1150 return FcResultTypeMismatch; 1151 *ls = (FcLangSet *)v.u.l; 1152 return FcResultMatch; 1153} 1154 1155FcResult 1156FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r) 1157{ 1158 FcValue v; 1159 FcResult res; 1160 1161 res = FcPatternObjectGet (p, object, id, &v); 1162 if (res != FcResultMatch) 1163 return res; 1164 switch ((int)v.type) { 1165 case FcTypeRange: 1166 *r = (FcRange *)v.u.r; 1167 break; 1168 default: 1169 return FcResultTypeMismatch; 1170 } 1171 return FcResultMatch; 1172} 1173 1174FcResult 1175FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r) 1176{ 1177 return FcPatternObjectGetRange (p, FcObjectFromName (object), id, r); 1178} 1179 1180FcPattern * 1181FcPatternDuplicate (const FcPattern *orig) 1182{ 1183 FcPattern *new; 1184 FcPatternIter iter; 1185 FcValueListPtr l; 1186 1187 if (!orig) 1188 return NULL; 1189 1190 new = FcPatternCreate (); 1191 if (!new) 1192 goto bail0; 1193 1194 FcPatternIterStart (orig, &iter); 1195 do 1196 { 1197 for (l = FcPatternIterGetValues (orig, &iter); l; l = FcValueListNext (l)) 1198 { 1199 if (!FcPatternObjectAddWithBinding (new, FcPatternIterGetObjectId (orig, &iter), 1200 FcValueCanonicalize(&l->value), 1201 l->binding, 1202 FcTrue)) 1203 goto bail1; 1204 } 1205 } while (FcPatternIterNext (orig, &iter)); 1206 1207 return new; 1208 1209bail1: 1210 FcPatternDestroy (new); 1211bail0: 1212 return 0; 1213} 1214 1215void 1216FcPatternReference (FcPattern *p) 1217{ 1218 if (!FcRefIsConst (&p->ref)) 1219 FcRefInc (&p->ref); 1220 else 1221 FcCacheObjectReference (FcPatternGetCacheObject(p)); 1222} 1223 1224FcPattern * 1225FcPatternVaBuild (FcPattern *p, va_list va) 1226{ 1227 FcPattern *ret; 1228 1229 FcPatternVapBuild (ret, p, va); 1230 return ret; 1231} 1232 1233FcPattern * 1234FcPatternBuild (FcPattern *p, ...) 1235{ 1236 va_list va; 1237 1238 va_start (va, p); 1239 FcPatternVapBuild (p, p, va); 1240 va_end (va); 1241 return p; 1242} 1243 1244/* 1245 * Add all of the elements in 's' to 'p' 1246 */ 1247FcBool 1248FcPatternAppend (FcPattern *p, FcPattern *s) 1249{ 1250 FcPatternIter iter; 1251 FcValueListPtr v; 1252 1253 FcPatternIterStart (s, &iter); 1254 do 1255 { 1256 for (v = FcPatternIterGetValues (s, &iter); v; v = FcValueListNext (v)) 1257 { 1258 if (!FcPatternObjectAddWithBinding (p, FcPatternIterGetObjectId (s, &iter), 1259 FcValueCanonicalize(&v->value), 1260 v->binding, FcTrue)) 1261 return FcFalse; 1262 } 1263 } while (FcPatternIterNext (s, &iter)); 1264 1265 return FcTrue; 1266} 1267 1268FcPattern * 1269FcPatternFilter (FcPattern *p, const FcObjectSet *os) 1270{ 1271 int i; 1272 FcPattern *ret; 1273 FcPatternElt *e; 1274 FcValueListPtr v; 1275 1276 if (!os) 1277 return FcPatternDuplicate (p); 1278 1279 ret = FcPatternCreate (); 1280 if (!ret) 1281 return NULL; 1282 1283 for (i = 0; i < os->nobject; i++) 1284 { 1285 FcObject object = FcObjectFromName (os->objects[i]); 1286 e = FcPatternObjectFindElt (p, object); 1287 if (e) 1288 { 1289 for (v = FcPatternEltValues(e); v; v = FcValueListNext(v)) 1290 { 1291 if (!FcPatternObjectAddWithBinding (ret, e->object, 1292 FcValueCanonicalize(&v->value), 1293 v->binding, FcTrue)) 1294 goto bail0; 1295 } 1296 } 1297 } 1298 return ret; 1299 1300bail0: 1301 FcPatternDestroy (ret); 1302 return NULL; 1303} 1304 1305typedef struct _FcPatternPrivateIter { 1306 FcPatternElt *elt; 1307 int pos; 1308} FcPatternPrivateIter; 1309 1310static void 1311FcPatternIterSet (const FcPattern *pat, FcPatternPrivateIter *iter) 1312{ 1313 iter->elt = FcPatternObjectCount (pat) > 0 && iter->pos < FcPatternObjectCount (pat) ? &FcPatternElts (pat)[iter->pos] : NULL; 1314} 1315 1316void 1317FcPatternIterStart (const FcPattern *pat, FcPatternIter *iter) 1318{ 1319 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; 1320 1321 priv->pos = 0; 1322 FcPatternIterSet (pat, priv); 1323} 1324 1325FcBool 1326FcPatternIterNext (const FcPattern *pat, FcPatternIter *iter) 1327{ 1328 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; 1329 1330 priv->pos++; 1331 if (priv->pos >= FcPatternObjectCount (pat)) 1332 return FcFalse; 1333 FcPatternIterSet (pat, priv); 1334 1335 return FcTrue; 1336} 1337 1338FcBool 1339FcPatternIterEqual (const FcPattern *p1, FcPatternIter *i1, 1340 const FcPattern *p2, FcPatternIter *i2) 1341{ 1342 FcBool b1 = FcPatternIterIsValid (p1, i1); 1343 FcBool b2 = FcPatternIterIsValid (p2, i2); 1344 1345 if (!i1 && !i2) 1346 return FcTrue; 1347 if (!b1 || !b2) 1348 return FcFalse; 1349 if (FcPatternIterGetObjectId (p1, i1) != FcPatternIterGetObjectId (p2, i2)) 1350 return FcFalse; 1351 1352 return FcValueListEqual (FcPatternIterGetValues (p1, i1), 1353 FcPatternIterGetValues (p2, i2)); 1354} 1355 1356FcBool 1357FcPatternFindObjectIter (const FcPattern *pat, FcPatternIter *iter, FcObject object) 1358{ 1359 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; 1360 int i = FcPatternObjectPosition (pat, object); 1361 1362 priv->elt = NULL; 1363 if (i < 0) 1364 return FcFalse; 1365 1366 priv->pos = i; 1367 FcPatternIterSet (pat, priv); 1368 1369 return FcTrue; 1370} 1371 1372FcBool 1373FcPatternFindIter (const FcPattern *pat, FcPatternIter *iter, const char *object) 1374{ 1375 return FcPatternFindObjectIter (pat, iter, FcObjectFromName (object)); 1376} 1377 1378FcBool 1379FcPatternIterIsValid (const FcPattern *pat, FcPatternIter *iter) 1380{ 1381 FcPatternPrivateIter *priv = (FcPatternPrivateIter *)iter; 1382 1383 if (priv && priv->elt) 1384 return FcTrue; 1385 1386 return FcFalse; 1387} 1388 1389FcObject 1390FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter) 1391{ 1392 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; 1393 1394 if (priv && priv->elt) 1395 return priv->elt->object; 1396 1397 return 0; 1398} 1399 1400const char * 1401FcPatternIterGetObject (const FcPattern *pat, FcPatternIter *iter) 1402{ 1403 return FcObjectName (FcPatternIterGetObjectId (pat, iter)); 1404} 1405 1406FcValueListPtr 1407FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter) 1408{ 1409 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter; 1410 1411 if (priv && priv->elt) 1412 return FcPatternEltValues (priv->elt); 1413 1414 return NULL; 1415} 1416 1417int 1418FcPatternIterValueCount (const FcPattern *pat, FcPatternIter *iter) 1419{ 1420 int count = 0; 1421 FcValueListPtr l; 1422 1423 for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l)) 1424 count++; 1425 1426 return count; 1427} 1428 1429FcResult 1430FcPatternIterGetValue (const FcPattern *pat, FcPatternIter *iter, int id, FcValue *v, FcValueBinding *b) 1431{ 1432 FcValueListPtr l; 1433 1434 for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l)) 1435 { 1436 if (id == 0) 1437 { 1438 *v = FcValueCanonicalize (&l->value); 1439 if (b) 1440 *b = l->binding; 1441 return FcResultMatch; 1442 } 1443 id--; 1444 } 1445 return FcResultNoId; 1446} 1447 1448FcBool 1449FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat) 1450{ 1451 int i; 1452 FcPatternElt *elts = FcPatternElts(pat); 1453 1454 if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern))) 1455 return FcFalse; 1456 if (!FcSerializeAlloc (serialize, elts, FcPatternObjectCount (pat) * sizeof (FcPatternElt))) 1457 return FcFalse; 1458 for (i = 0; i < FcPatternObjectCount (pat); i++) 1459 if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i))) 1460 return FcFalse; 1461 return FcTrue; 1462} 1463 1464FcPattern * 1465FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat) 1466{ 1467 FcPattern *pat_serialized; 1468 FcPatternElt *elts = FcPatternElts (pat); 1469 FcPatternElt *elts_serialized; 1470 FcValueList *values_serialized; 1471 int i; 1472 1473 pat_serialized = FcSerializePtr (serialize, pat); 1474 if (!pat_serialized) 1475 return NULL; 1476 *pat_serialized = *pat; 1477 pat_serialized->size = FcPatternObjectCount (pat); 1478 FcRefSetConst (&pat_serialized->ref); 1479 1480 elts_serialized = FcSerializePtr (serialize, elts); 1481 if (!elts_serialized) 1482 return NULL; 1483 1484 pat_serialized->elts_offset = FcPtrToOffset (pat_serialized, 1485 elts_serialized); 1486 1487 for (i = 0; i < FcPatternObjectCount (pat); i++) 1488 { 1489 values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i)); 1490 if (!values_serialized) 1491 return NULL; 1492 elts_serialized[i].object = elts[i].object; 1493 elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i], 1494 values_serialized, 1495 FcValueList); 1496 } 1497 if (FcDebug() & FC_DBG_CACHEV) { 1498 printf ("Raw pattern:\n"); 1499 FcPatternPrint (pat); 1500 printf ("Serialized pattern:\n"); 1501 FcPatternPrint (pat_serialized); 1502 printf ("\n"); 1503 } 1504 return pat_serialized; 1505} 1506 1507FcBool 1508FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl) 1509{ 1510 while (vl) 1511 { 1512 if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList))) 1513 return FcFalse; 1514 switch ((int) vl->value.type) { 1515 case FcTypeString: 1516 if (!FcStrSerializeAlloc (serialize, vl->value.u.s)) 1517 return FcFalse; 1518 break; 1519 case FcTypeCharSet: 1520 if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c)) 1521 return FcFalse; 1522 break; 1523 case FcTypeLangSet: 1524 if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l)) 1525 return FcFalse; 1526 break; 1527 case FcTypeRange: 1528 if (!FcRangeSerializeAlloc (serialize, vl->value.u.r)) 1529 return FcFalse; 1530 break; 1531 default: 1532 break; 1533 } 1534 vl = vl->next; 1535 } 1536 return FcTrue; 1537} 1538 1539FcValueList * 1540FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl) 1541{ 1542 FcValueList *vl_serialized; 1543 FcChar8 *s_serialized; 1544 FcCharSet *c_serialized; 1545 FcLangSet *l_serialized; 1546 FcRange *r_serialized; 1547 FcValueList *head_serialized = NULL; 1548 FcValueList *prev_serialized = NULL; 1549 1550 while (vl) 1551 { 1552 vl_serialized = FcSerializePtr (serialize, vl); 1553 if (!vl_serialized) 1554 return NULL; 1555 1556 if (prev_serialized) 1557 prev_serialized->next = FcPtrToEncodedOffset (prev_serialized, 1558 vl_serialized, 1559 FcValueList); 1560 else 1561 head_serialized = vl_serialized; 1562 1563 vl_serialized->next = NULL; 1564 vl_serialized->value.type = vl->value.type; 1565 switch ((int) vl->value.type) { 1566 case FcTypeInteger: 1567 vl_serialized->value.u.i = vl->value.u.i; 1568 break; 1569 case FcTypeDouble: 1570 vl_serialized->value.u.d = vl->value.u.d; 1571 break; 1572 case FcTypeString: 1573 s_serialized = FcStrSerialize (serialize, vl->value.u.s); 1574 if (!s_serialized) 1575 return NULL; 1576 vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value, 1577 s_serialized, 1578 FcChar8); 1579 break; 1580 case FcTypeBool: 1581 vl_serialized->value.u.b = vl->value.u.b; 1582 break; 1583 case FcTypeMatrix: 1584 /* can't happen */ 1585 break; 1586 case FcTypeCharSet: 1587 c_serialized = FcCharSetSerialize (serialize, vl->value.u.c); 1588 if (!c_serialized) 1589 return NULL; 1590 vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value, 1591 c_serialized, 1592 FcCharSet); 1593 break; 1594 case FcTypeFTFace: 1595 /* can't happen */ 1596 break; 1597 case FcTypeLangSet: 1598 l_serialized = FcLangSetSerialize (serialize, vl->value.u.l); 1599 if (!l_serialized) 1600 return NULL; 1601 vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value, 1602 l_serialized, 1603 FcLangSet); 1604 break; 1605 case FcTypeRange: 1606 r_serialized = FcRangeSerialize (serialize, vl->value.u.r); 1607 if (!r_serialized) 1608 return NULL; 1609 vl_serialized->value.u.r = FcPtrToEncodedOffset (&vl_serialized->value, 1610 r_serialized, 1611 FcRange); 1612 break; 1613 default: 1614 break; 1615 } 1616 prev_serialized = vl_serialized; 1617 vl = vl->next; 1618 } 1619 return head_serialized; 1620} 1621 1622#define __fcpat__ 1623#include "fcaliastail.h" 1624#include "fcftaliastail.h" 1625#undef __fcpat__ 1626