fccharset.c revision 953daeba
1/* 2 * fontconfig/src/fccharset.c 3 * 4 * Copyright © 2001 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "fcint.h" 26#include <stdlib.h> 27 28/* #define CHECK */ 29 30FcCharSet * 31FcCharSetCreate (void) 32{ 33 FcCharSet *fcs; 34 35 fcs = (FcCharSet *) malloc (sizeof (FcCharSet)); 36 if (!fcs) 37 return 0; 38 FcRefInit (&fcs->ref, 1); 39 fcs->num = 0; 40 fcs->leaves_offset = 0; 41 fcs->numbers_offset = 0; 42 return fcs; 43} 44 45FcCharSet * 46FcCharSetPromote (FcValuePromotionBuffer *vbuf) 47{ 48 FcCharSet *fcs = (FcCharSet *) vbuf; 49 50 FC_ASSERT_STATIC (sizeof (FcCharSet) <= sizeof (FcValuePromotionBuffer)); 51 52 FcRefSetConst (&fcs->ref); 53 fcs->num = 0; 54 fcs->leaves_offset = 0; 55 fcs->numbers_offset = 0; 56 57 return fcs; 58} 59 60FcCharSet * 61FcCharSetNew (void) 62{ 63 return FcCharSetCreate (); 64} 65 66void 67FcCharSetDestroy (FcCharSet *fcs) 68{ 69 int i; 70 71 if (fcs) 72 { 73 if (FcRefIsConst (&fcs->ref)) 74 { 75 FcCacheObjectDereference (fcs); 76 return; 77 } 78 if (FcRefDec (&fcs->ref) != 1) 79 return; 80 for (i = 0; i < fcs->num; i++) 81 free (FcCharSetLeaf (fcs, i)); 82 if (fcs->num) 83 { 84 free (FcCharSetLeaves (fcs)); 85 free (FcCharSetNumbers (fcs)); 86 } 87 free (fcs); 88 } 89} 90 91/* 92 * Search for the leaf containing with the specified num. 93 * Return its index if it exists, otherwise return negative of 94 * the (position + 1) where it should be inserted 95 */ 96 97 98static int 99FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num) 100{ 101 FcChar16 *numbers = FcCharSetNumbers(fcs); 102 FcChar16 page; 103 int low = start; 104 int high = fcs->num - 1; 105 106 if (!numbers) 107 return -1; 108 while (low <= high) 109 { 110 int mid = (low + high) >> 1; 111 page = numbers[mid]; 112 if (page == num) 113 return mid; 114 if (page < num) 115 low = mid + 1; 116 else 117 high = mid - 1; 118 } 119 if (high < 0 || (high < fcs->num && numbers[high] < num)) 120 high++; 121 return -(high + 1); 122} 123 124/* 125 * Locate the leaf containing the specified char, return 126 * its index if it exists, otherwise return negative of 127 * the (position + 1) where it should be inserted 128 */ 129 130static int 131FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4) 132{ 133 return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8); 134} 135 136static FcCharLeaf * 137FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4) 138{ 139 int pos = FcCharSetFindLeafPos (fcs, ucs4); 140 if (pos >= 0) 141 return FcCharSetLeaf(fcs, pos); 142 return 0; 143} 144 145#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1))) 146 147static FcBool 148FcCharSetPutLeaf (FcCharSet *fcs, 149 FcChar32 ucs4, 150 FcCharLeaf *leaf, 151 int pos) 152{ 153 intptr_t *leaves = FcCharSetLeaves (fcs); 154 FcChar16 *numbers = FcCharSetNumbers (fcs); 155 156 ucs4 >>= 8; 157 if (ucs4 >= 0x10000) 158 return FcFalse; 159 160 if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num)) 161 { 162 if (!fcs->num) 163 { 164 unsigned int alloced = 8; 165 leaves = malloc (alloced * sizeof (*leaves)); 166 numbers = malloc (alloced * sizeof (*numbers)); 167 if (!leaves || !numbers) 168 { 169 if (leaves) 170 free (leaves); 171 if (numbers) 172 free (numbers); 173 return FcFalse; 174 } 175 } 176 else 177 { 178 unsigned int alloced = fcs->num; 179 intptr_t *new_leaves, distance; 180 181 alloced *= 2; 182 new_leaves = realloc (leaves, alloced * sizeof (*leaves)); 183 if (!new_leaves) 184 return FcFalse; 185 numbers = realloc (numbers, alloced * sizeof (*numbers)); 186 if (!numbers) 187 { 188 /* Revert the reallocation of leaves */ 189 leaves = realloc (new_leaves, (alloced / 2) * sizeof (*new_leaves)); 190 /* unlikely to fail though */ 191 if (!leaves) 192 return FcFalse; 193 fcs->leaves_offset = FcPtrToOffset (fcs, leaves); 194 return FcFalse; 195 } 196 distance = (intptr_t) new_leaves - (intptr_t) leaves; 197 if (new_leaves && distance) 198 { 199 int i; 200 for (i = 0; i < fcs->num; i++) 201 new_leaves[i] -= distance; 202 } 203 leaves = new_leaves; 204 } 205 206 fcs->leaves_offset = FcPtrToOffset (fcs, leaves); 207 fcs->numbers_offset = FcPtrToOffset (fcs, numbers); 208 } 209 210 memmove (leaves + pos + 1, leaves + pos, 211 (fcs->num - pos) * sizeof (*leaves)); 212 memmove (numbers + pos + 1, numbers + pos, 213 (fcs->num - pos) * sizeof (*numbers)); 214 numbers[pos] = (FcChar16) ucs4; 215 leaves[pos] = FcPtrToOffset (leaves, leaf); 216 fcs->num++; 217 return FcTrue; 218} 219 220/* 221 * Locate the leaf containing the specified char, creating it 222 * if desired 223 */ 224 225FcCharLeaf * 226FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4) 227{ 228 int pos; 229 FcCharLeaf *leaf; 230 231 pos = FcCharSetFindLeafPos (fcs, ucs4); 232 if (pos >= 0) 233 return FcCharSetLeaf(fcs, pos); 234 235 leaf = calloc (1, sizeof (FcCharLeaf)); 236 if (!leaf) 237 return 0; 238 239 pos = -pos - 1; 240 if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos)) 241 { 242 free (leaf); 243 return 0; 244 } 245 return leaf; 246} 247 248static FcBool 249FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf) 250{ 251 int pos; 252 253 pos = FcCharSetFindLeafPos (fcs, ucs4); 254 if (pos >= 0) 255 { 256 free (FcCharSetLeaf (fcs, pos)); 257 FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs), 258 leaf); 259 return FcTrue; 260 } 261 pos = -pos - 1; 262 return FcCharSetPutLeaf (fcs, ucs4, leaf, pos); 263} 264 265FcBool 266FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4) 267{ 268 FcCharLeaf *leaf; 269 FcChar32 *b; 270 271 if (fcs == NULL || FcRefIsConst (&fcs->ref)) 272 return FcFalse; 273 leaf = FcCharSetFindLeafCreate (fcs, ucs4); 274 if (!leaf) 275 return FcFalse; 276 b = &leaf->map[(ucs4 & 0xff) >> 5]; 277 *b |= (1 << (ucs4 & 0x1f)); 278 return FcTrue; 279} 280 281FcBool 282FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4) 283{ 284 FcCharLeaf *leaf; 285 FcChar32 *b; 286 287 if (fcs == NULL || FcRefIsConst (&fcs->ref)) 288 return FcFalse; 289 leaf = FcCharSetFindLeaf (fcs, ucs4); 290 if (!leaf) 291 return FcTrue; 292 b = &leaf->map[(ucs4 & 0xff) >> 5]; 293 *b &= ~(1 << (ucs4 & 0x1f)); 294 /* We don't bother removing the leaf if it's empty */ 295 return FcTrue; 296} 297 298/* 299 * An iterator for the leaves of a charset 300 */ 301 302typedef struct _fcCharSetIter { 303 FcCharLeaf *leaf; 304 FcChar32 ucs4; 305 int pos; 306} FcCharSetIter; 307 308/* 309 * Set iter->leaf to the leaf containing iter->ucs4 or higher 310 */ 311 312static void 313FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter) 314{ 315 int pos = FcCharSetFindLeafPos (fcs, iter->ucs4); 316 317 if (pos < 0) 318 { 319 pos = -pos - 1; 320 if (pos == fcs->num) 321 { 322 iter->ucs4 = ~0; 323 iter->leaf = 0; 324 return; 325 } 326 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8; 327 } 328 iter->leaf = FcCharSetLeaf(fcs, pos); 329 iter->pos = pos; 330} 331 332static void 333FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter) 334{ 335 int pos = iter->pos + 1; 336 if (pos >= fcs->num) 337 { 338 iter->ucs4 = ~0; 339 iter->leaf = 0; 340 } 341 else 342 { 343 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8; 344 iter->leaf = FcCharSetLeaf(fcs, pos); 345 iter->pos = pos; 346 } 347} 348 349 350static void 351FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter) 352{ 353 iter->ucs4 = 0; 354 iter->pos = 0; 355 FcCharSetIterSet (fcs, iter); 356} 357 358FcCharSet * 359FcCharSetCopy (FcCharSet *src) 360{ 361 if (src) 362 { 363 if (!FcRefIsConst (&src->ref)) 364 FcRefInc (&src->ref); 365 else 366 FcCacheObjectReference (src); 367 } 368 return src; 369} 370 371FcBool 372FcCharSetEqual (const FcCharSet *a, const FcCharSet *b) 373{ 374 FcCharSetIter ai, bi; 375 int i; 376 377 if (a == b) 378 return FcTrue; 379 if (!a || !b) 380 return FcFalse; 381 for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi); 382 ai.leaf && bi.leaf; 383 FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi)) 384 { 385 if (ai.ucs4 != bi.ucs4) 386 return FcFalse; 387 for (i = 0; i < 256/32; i++) 388 if (ai.leaf->map[i] != bi.leaf->map[i]) 389 return FcFalse; 390 } 391 return ai.leaf == bi.leaf; 392} 393 394static FcBool 395FcCharSetAddLeaf (FcCharSet *fcs, 396 FcChar32 ucs4, 397 FcCharLeaf *leaf) 398{ 399 FcCharLeaf *new = FcCharSetFindLeafCreate (fcs, ucs4); 400 if (!new) 401 return FcFalse; 402 *new = *leaf; 403 return FcTrue; 404} 405 406static FcCharSet * 407FcCharSetOperate (const FcCharSet *a, 408 const FcCharSet *b, 409 FcBool (*overlap) (FcCharLeaf *result, 410 const FcCharLeaf *al, 411 const FcCharLeaf *bl), 412 FcBool aonly, 413 FcBool bonly) 414{ 415 FcCharSet *fcs; 416 FcCharSetIter ai, bi; 417 418 if (!a || !b) 419 goto bail0; 420 fcs = FcCharSetCreate (); 421 if (!fcs) 422 goto bail0; 423 FcCharSetIterStart (a, &ai); 424 FcCharSetIterStart (b, &bi); 425 while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf))) 426 { 427 if (ai.ucs4 < bi.ucs4) 428 { 429 if (aonly) 430 { 431 if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf)) 432 goto bail1; 433 FcCharSetIterNext (a, &ai); 434 } 435 else 436 { 437 ai.ucs4 = bi.ucs4; 438 FcCharSetIterSet (a, &ai); 439 } 440 } 441 else if (bi.ucs4 < ai.ucs4 ) 442 { 443 if (bonly) 444 { 445 if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf)) 446 goto bail1; 447 FcCharSetIterNext (b, &bi); 448 } 449 else 450 { 451 bi.ucs4 = ai.ucs4; 452 FcCharSetIterSet (b, &bi); 453 } 454 } 455 else 456 { 457 FcCharLeaf leaf; 458 459 if ((*overlap) (&leaf, ai.leaf, bi.leaf)) 460 { 461 if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf)) 462 goto bail1; 463 } 464 FcCharSetIterNext (a, &ai); 465 FcCharSetIterNext (b, &bi); 466 } 467 } 468 return fcs; 469bail1: 470 FcCharSetDestroy (fcs); 471bail0: 472 return 0; 473} 474 475static FcBool 476FcCharSetIntersectLeaf (FcCharLeaf *result, 477 const FcCharLeaf *al, 478 const FcCharLeaf *bl) 479{ 480 int i; 481 FcBool nonempty = FcFalse; 482 483 for (i = 0; i < 256/32; i++) 484 if ((result->map[i] = al->map[i] & bl->map[i])) 485 nonempty = FcTrue; 486 return nonempty; 487} 488 489FcCharSet * 490FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b) 491{ 492 return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse); 493} 494 495static FcBool 496FcCharSetUnionLeaf (FcCharLeaf *result, 497 const FcCharLeaf *al, 498 const FcCharLeaf *bl) 499{ 500 int i; 501 502 for (i = 0; i < 256/32; i++) 503 result->map[i] = al->map[i] | bl->map[i]; 504 return FcTrue; 505} 506 507FcCharSet * 508FcCharSetUnion (const FcCharSet *a, const FcCharSet *b) 509{ 510 return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue); 511} 512 513FcBool 514FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed) 515{ 516 int ai = 0, bi = 0; 517 FcChar16 an, bn; 518 519 if (!a || !b) 520 return FcFalse; 521 522 if (FcRefIsConst (&a->ref)) { 523 if (changed) 524 *changed = FcFalse; 525 return FcFalse; 526 } 527 528 if (changed) { 529 *changed = !FcCharSetIsSubset(b, a); 530 if (!*changed) 531 return FcTrue; 532 } 533 534 while (bi < b->num) 535 { 536 an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0; 537 bn = FcCharSetNumbers(b)[bi]; 538 539 if (an < bn) 540 { 541 ai = FcCharSetFindLeafForward (a, ai + 1, bn); 542 if (ai < 0) 543 ai = -ai - 1; 544 } 545 else 546 { 547 FcCharLeaf *bl = FcCharSetLeaf(b, bi); 548 if (bn < an) 549 { 550 if (!FcCharSetAddLeaf (a, bn << 8, bl)) 551 return FcFalse; 552 } 553 else 554 { 555 FcCharLeaf *al = FcCharSetLeaf(a, ai); 556 FcCharSetUnionLeaf (al, al, bl); 557 } 558 559 ai++; 560 bi++; 561 } 562 } 563 564 return FcTrue; 565} 566 567static FcBool 568FcCharSetSubtractLeaf (FcCharLeaf *result, 569 const FcCharLeaf *al, 570 const FcCharLeaf *bl) 571{ 572 int i; 573 FcBool nonempty = FcFalse; 574 575 for (i = 0; i < 256/32; i++) 576 if ((result->map[i] = al->map[i] & ~bl->map[i])) 577 nonempty = FcTrue; 578 return nonempty; 579} 580 581FcCharSet * 582FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b) 583{ 584 return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse); 585} 586 587FcBool 588FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4) 589{ 590 FcCharLeaf *leaf; 591 592 if (!fcs) 593 return FcFalse; 594 leaf = FcCharSetFindLeaf (fcs, ucs4); 595 if (!leaf) 596 return FcFalse; 597 return (leaf->map[(ucs4 & 0xff) >> 5] & (1 << (ucs4 & 0x1f))) != 0; 598} 599 600static FcChar32 601FcCharSetPopCount (FcChar32 c1) 602{ 603#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) 604 return __builtin_popcount (c1); 605#else 606 /* hackmem 169 */ 607 FcChar32 c2 = (c1 >> 1) & 033333333333; 608 c2 = c1 - c2 - ((c2 >> 1) & 033333333333); 609 return (((c2 + (c2 >> 3)) & 030707070707) % 077); 610#endif 611} 612 613FcChar32 614FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b) 615{ 616 FcCharSetIter ai, bi; 617 FcChar32 count = 0; 618 619 if (a && b) 620 { 621 FcCharSetIterStart (a, &ai); 622 FcCharSetIterStart (b, &bi); 623 while (ai.leaf && bi.leaf) 624 { 625 if (ai.ucs4 == bi.ucs4) 626 { 627 FcChar32 *am = ai.leaf->map; 628 FcChar32 *bm = bi.leaf->map; 629 int i = 256/32; 630 while (i--) 631 count += FcCharSetPopCount (*am++ & *bm++); 632 FcCharSetIterNext (a, &ai); 633 } 634 else if (ai.ucs4 < bi.ucs4) 635 { 636 ai.ucs4 = bi.ucs4; 637 FcCharSetIterSet (a, &ai); 638 } 639 if (bi.ucs4 < ai.ucs4) 640 { 641 bi.ucs4 = ai.ucs4; 642 FcCharSetIterSet (b, &bi); 643 } 644 } 645 } 646 return count; 647} 648 649FcChar32 650FcCharSetCount (const FcCharSet *a) 651{ 652 FcCharSetIter ai; 653 FcChar32 count = 0; 654 655 if (a) 656 { 657 for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai)) 658 { 659 int i = 256/32; 660 FcChar32 *am = ai.leaf->map; 661 662 while (i--) 663 count += FcCharSetPopCount (*am++); 664 } 665 } 666 return count; 667} 668 669FcChar32 670FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b) 671{ 672 FcCharSetIter ai, bi; 673 FcChar32 count = 0; 674 675 if (a && b) 676 { 677 FcCharSetIterStart (a, &ai); 678 FcCharSetIterStart (b, &bi); 679 while (ai.leaf) 680 { 681 if (ai.ucs4 <= bi.ucs4) 682 { 683 FcChar32 *am = ai.leaf->map; 684 int i = 256/32; 685 if (ai.ucs4 == bi.ucs4) 686 { 687 FcChar32 *bm = bi.leaf->map; 688 while (i--) 689 count += FcCharSetPopCount (*am++ & ~*bm++); 690 } 691 else 692 { 693 while (i--) 694 count += FcCharSetPopCount (*am++); 695 } 696 FcCharSetIterNext (a, &ai); 697 } 698 else if (bi.leaf) 699 { 700 bi.ucs4 = ai.ucs4; 701 FcCharSetIterSet (b, &bi); 702 } 703 } 704 } 705 return count; 706} 707 708/* 709 * return FcTrue iff a is a subset of b 710 */ 711FcBool 712FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b) 713{ 714 int ai, bi; 715 FcChar16 an, bn; 716 717 if (a == b) 718 return FcTrue; 719 if (!a || !b) 720 return FcFalse; 721 bi = 0; 722 ai = 0; 723 while (ai < a->num && bi < b->num) 724 { 725 an = FcCharSetNumbers(a)[ai]; 726 bn = FcCharSetNumbers(b)[bi]; 727 /* 728 * Check matching pages 729 */ 730 if (an == bn) 731 { 732 FcChar32 *am = FcCharSetLeaf(a, ai)->map; 733 FcChar32 *bm = FcCharSetLeaf(b, bi)->map; 734 735 if (am != bm) 736 { 737 int i = 256/32; 738 /* 739 * Does am have any bits not in bm? 740 */ 741 while (i--) 742 if (*am++ & ~*bm++) 743 return FcFalse; 744 } 745 ai++; 746 bi++; 747 } 748 /* 749 * Does a have any pages not in b? 750 */ 751 else if (an < bn) 752 return FcFalse; 753 else 754 { 755 bi = FcCharSetFindLeafForward (b, bi + 1, an); 756 if (bi < 0) 757 bi = -bi - 1; 758 } 759 } 760 /* 761 * did we look at every page? 762 */ 763 return ai >= a->num; 764} 765 766/* 767 * These two functions efficiently walk the entire charmap for 768 * other software (like pango) that want their own copy 769 */ 770 771FcChar32 772FcCharSetNextPage (const FcCharSet *a, 773 FcChar32 map[FC_CHARSET_MAP_SIZE], 774 FcChar32 *next) 775{ 776 FcCharSetIter ai; 777 FcChar32 page; 778 779 if (!a) 780 return FC_CHARSET_DONE; 781 ai.ucs4 = *next; 782 FcCharSetIterSet (a, &ai); 783 if (!ai.leaf) 784 return FC_CHARSET_DONE; 785 786 /* 787 * Save current information 788 */ 789 page = ai.ucs4; 790 memcpy (map, ai.leaf->map, sizeof (ai.leaf->map)); 791 /* 792 * Step to next page 793 */ 794 FcCharSetIterNext (a, &ai); 795 *next = ai.ucs4; 796 797 return page; 798} 799 800FcChar32 801FcCharSetFirstPage (const FcCharSet *a, 802 FcChar32 map[FC_CHARSET_MAP_SIZE], 803 FcChar32 *next) 804{ 805 *next = 0; 806 return FcCharSetNextPage (a, map, next); 807} 808 809/* 810 * old coverage API, rather hard to use correctly 811 */ 812 813FcChar32 814FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result) 815{ 816 FcCharSetIter ai; 817 818 ai.ucs4 = page; 819 FcCharSetIterSet (a, &ai); 820 if (!ai.leaf) 821 { 822 memset (result, '\0', 256 / 8); 823 page = 0; 824 } 825 else 826 { 827 memcpy (result, ai.leaf->map, sizeof (ai.leaf->map)); 828 FcCharSetIterNext (a, &ai); 829 page = ai.ucs4; 830 } 831 return page; 832} 833 834static FcBool 835FcNameParseRange (FcChar8 **string, FcChar32 *pfirst, FcChar32 *plast) 836{ 837 char *s = (char *) *string; 838 char *t; 839 long first, last; 840 841 while (isspace(*s)) 842 s++; 843 t = s; 844 errno = 0; 845 first = last = strtol (s, &s, 16); 846 if (errno) 847 return FcFalse; 848 while (isspace(*s)) 849 s++; 850 if (*s == '-') 851 { 852 s++; 853 errno = 0; 854 last = strtol (s, &s, 16); 855 if (errno) 856 return FcFalse; 857 } 858 859 if (s == t || first < 0 || last < 0 || last < first || last > 0x10ffff) 860 return FcFalse; 861 862 *string = (FcChar8 *) s; 863 *pfirst = first; 864 *plast = last; 865 return FcTrue; 866} 867 868FcCharSet * 869FcNameParseCharSet (FcChar8 *string) 870{ 871 FcCharSet *c; 872 FcChar32 first, last; 873 874 c = FcCharSetCreate (); 875 if (!c) 876 goto bail0; 877 while (*string) 878 { 879 FcChar32 u; 880 881 if (!FcNameParseRange (&string, &first, &last)) 882 goto bail1; 883 884 for (u = first; u < last + 1; u++) 885 FcCharSetAddChar (c, u); 886 } 887 return c; 888bail1: 889 FcCharSetDestroy (c); 890bail0: 891 return NULL; 892} 893 894static void 895FcNameUnparseUnicode (FcStrBuf *buf, FcChar32 u) 896{ 897 FcChar8 buf_static[64]; 898 snprintf ((char *) buf_static, sizeof (buf_static), "%x", u); 899 FcStrBufString (buf, buf_static); 900} 901 902FcBool 903FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c) 904{ 905 FcCharSetIter ci; 906 FcChar32 first, last; 907 int i; 908#ifdef CHECK 909 int len = buf->len; 910#endif 911 912 first = last = 0x7FFFFFFF; 913 914 for (FcCharSetIterStart (c, &ci); 915 ci.leaf; 916 FcCharSetIterNext (c, &ci)) 917 { 918 for (i = 0; i < 256/32; i++) 919 { 920 FcChar32 bits = ci.leaf->map[i]; 921 FcChar32 u = ci.ucs4 + i * 32; 922 923 while (bits) 924 { 925 if (bits & 1) 926 { 927 if (u != last + 1) 928 { 929 if (last != first) 930 { 931 FcStrBufChar (buf, '-'); 932 FcNameUnparseUnicode (buf, last); 933 } 934 if (last != 0x7FFFFFFF) 935 FcStrBufChar (buf, ' '); 936 /* Start new range. */ 937 first = u; 938 FcNameUnparseUnicode (buf, u); 939 } 940 last = u; 941 } 942 bits >>= 1; 943 u++; 944 } 945 } 946 } 947 if (last != first) 948 { 949 FcStrBufChar (buf, '-'); 950 FcNameUnparseUnicode (buf, last); 951 } 952#ifdef CHECK 953 { 954 FcCharSet *check; 955 FcChar32 missing; 956 FcCharSetIter ci, checki; 957 958 /* null terminate for parser */ 959 FcStrBufChar (buf, '\0'); 960 /* step back over null for life after test */ 961 buf->len--; 962 check = FcNameParseCharSet (buf->buf + len); 963 FcCharSetIterStart (c, &ci); 964 FcCharSetIterStart (check, &checki); 965 while (ci.leaf || checki.leaf) 966 { 967 if (ci.ucs4 < checki.ucs4) 968 { 969 printf ("Missing leaf node at 0x%x\n", ci.ucs4); 970 FcCharSetIterNext (c, &ci); 971 } 972 else if (checki.ucs4 < ci.ucs4) 973 { 974 printf ("Extra leaf node at 0x%x\n", checki.ucs4); 975 FcCharSetIterNext (check, &checki); 976 } 977 else 978 { 979 int i = 256/32; 980 FcChar32 *cm = ci.leaf->map; 981 FcChar32 *checkm = checki.leaf->map; 982 983 for (i = 0; i < 256; i += 32) 984 { 985 if (*cm != *checkm) 986 printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n", 987 ci.ucs4 + i, *cm, *checkm); 988 cm++; 989 checkm++; 990 } 991 FcCharSetIterNext (c, &ci); 992 FcCharSetIterNext (check, &checki); 993 } 994 } 995 if ((missing = FcCharSetSubtractCount (c, check))) 996 printf ("%d missing in reparsed result\n", missing); 997 if ((missing = FcCharSetSubtractCount (check, c))) 998 printf ("%d extra in reparsed result\n", missing); 999 FcCharSetDestroy (check); 1000 } 1001#endif 1002 1003 return FcTrue; 1004} 1005 1006typedef struct _FcCharLeafEnt FcCharLeafEnt; 1007 1008struct _FcCharLeafEnt { 1009 FcCharLeafEnt *next; 1010 FcChar32 hash; 1011 FcCharLeaf leaf; 1012}; 1013 1014#define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt)) 1015#define FC_CHAR_LEAF_HASH_SIZE 257 1016 1017typedef struct _FcCharSetEnt FcCharSetEnt; 1018 1019struct _FcCharSetEnt { 1020 FcCharSetEnt *next; 1021 FcChar32 hash; 1022 FcCharSet set; 1023}; 1024 1025typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt; 1026 1027struct _FcCharSetOrigEnt { 1028 FcCharSetOrigEnt *next; 1029 const FcCharSet *orig; 1030 const FcCharSet *frozen; 1031}; 1032 1033#define FC_CHAR_SET_HASH_SIZE 67 1034 1035struct _FcCharSetFreezer { 1036 FcCharLeafEnt *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE]; 1037 FcCharLeafEnt **leaf_blocks; 1038 int leaf_block_count; 1039 FcCharSetEnt *set_hash_table[FC_CHAR_SET_HASH_SIZE]; 1040 FcCharSetOrigEnt *orig_hash_table[FC_CHAR_SET_HASH_SIZE]; 1041 FcCharLeafEnt *current_block; 1042 int leaf_remain; 1043 int leaves_seen; 1044 int charsets_seen; 1045 int leaves_allocated; 1046 int charsets_allocated; 1047}; 1048 1049static FcCharLeafEnt * 1050FcCharLeafEntCreate (FcCharSetFreezer *freezer) 1051{ 1052 if (!freezer->leaf_remain) 1053 { 1054 FcCharLeafEnt **newBlocks; 1055 1056 freezer->leaf_block_count++; 1057 newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *)); 1058 if (!newBlocks) 1059 return 0; 1060 freezer->leaf_blocks = newBlocks; 1061 freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt)); 1062 if (!freezer->current_block) 1063 return 0; 1064 freezer->leaf_remain = FC_CHAR_LEAF_BLOCK; 1065 } 1066 freezer->leaf_remain--; 1067 freezer->leaves_allocated++; 1068 return freezer->current_block++; 1069} 1070 1071static FcChar32 1072FcCharLeafHash (FcCharLeaf *leaf) 1073{ 1074 FcChar32 hash = 0; 1075 int i; 1076 1077 for (i = 0; i < 256/32; i++) 1078 hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i]; 1079 return hash; 1080} 1081 1082static FcCharLeaf * 1083FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf) 1084{ 1085 FcChar32 hash = FcCharLeafHash (leaf); 1086 FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE]; 1087 FcCharLeafEnt *ent; 1088 1089 for (ent = *bucket; ent; ent = ent->next) 1090 { 1091 if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf))) 1092 return &ent->leaf; 1093 } 1094 1095 ent = FcCharLeafEntCreate(freezer); 1096 if (!ent) 1097 return 0; 1098 ent->leaf = *leaf; 1099 ent->hash = hash; 1100 ent->next = *bucket; 1101 *bucket = ent; 1102 return &ent->leaf; 1103} 1104 1105static FcChar32 1106FcCharSetHash (FcCharSet *fcs) 1107{ 1108 FcChar32 hash = 0; 1109 int i; 1110 1111 /* hash in leaves */ 1112 for (i = 0; i < fcs->num; i++) 1113 hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf(fcs,i)); 1114 /* hash in numbers */ 1115 for (i = 0; i < fcs->num; i++) 1116 hash = ((hash << 1) | (hash >> 31)) ^ FcCharSetNumbers(fcs)[i]; 1117 return hash; 1118} 1119 1120static FcBool 1121FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen) 1122{ 1123 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE]; 1124 FcCharSetOrigEnt *ent; 1125 1126 ent = malloc (sizeof (FcCharSetOrigEnt)); 1127 if (!ent) 1128 return FcFalse; 1129 ent->orig = orig; 1130 ent->frozen = frozen; 1131 ent->next = *bucket; 1132 *bucket = ent; 1133 return FcTrue; 1134} 1135 1136static FcCharSet * 1137FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs) 1138{ 1139 FcChar32 hash = FcCharSetHash (fcs); 1140 FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE]; 1141 FcCharSetEnt *ent; 1142 int size; 1143 int i; 1144 1145 for (ent = *bucket; ent; ent = ent->next) 1146 { 1147 if (ent->hash == hash && 1148 ent->set.num == fcs->num && 1149 !memcmp (FcCharSetNumbers(&ent->set), 1150 FcCharSetNumbers(fcs), 1151 fcs->num * sizeof (FcChar16))) 1152 { 1153 FcBool ok = FcTrue; 1154 int i; 1155 1156 for (i = 0; i < fcs->num; i++) 1157 if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i)) 1158 ok = FcFalse; 1159 if (ok) 1160 return &ent->set; 1161 } 1162 } 1163 1164 size = (sizeof (FcCharSetEnt) + 1165 fcs->num * sizeof (FcCharLeaf *) + 1166 fcs->num * sizeof (FcChar16)); 1167 ent = malloc (size); 1168 if (!ent) 1169 return 0; 1170 1171 freezer->charsets_allocated++; 1172 1173 FcRefSetConst (&ent->set.ref); 1174 ent->set.num = fcs->num; 1175 if (fcs->num) 1176 { 1177 intptr_t *ent_leaves; 1178 1179 ent->set.leaves_offset = sizeof (ent->set); 1180 ent->set.numbers_offset = (ent->set.leaves_offset + 1181 fcs->num * sizeof (intptr_t)); 1182 1183 ent_leaves = FcCharSetLeaves (&ent->set); 1184 for (i = 0; i < fcs->num; i++) 1185 ent_leaves[i] = FcPtrToOffset (ent_leaves, 1186 FcCharSetLeaf (fcs, i)); 1187 memcpy (FcCharSetNumbers (&ent->set), 1188 FcCharSetNumbers (fcs), 1189 fcs->num * sizeof (FcChar16)); 1190 } 1191 else 1192 { 1193 ent->set.leaves_offset = 0; 1194 ent->set.numbers_offset = 0; 1195 } 1196 1197 ent->hash = hash; 1198 ent->next = *bucket; 1199 *bucket = ent; 1200 1201 return &ent->set; 1202} 1203 1204static const FcCharSet * 1205FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig) 1206{ 1207 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE]; 1208 FcCharSetOrigEnt *ent; 1209 1210 for (ent = *bucket; ent; ent = ent->next) 1211 if (ent->orig == orig) 1212 return ent->frozen; 1213 return NULL; 1214} 1215 1216const FcCharSet * 1217FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs) 1218{ 1219 FcCharSet *b; 1220 const FcCharSet *n = 0; 1221 FcCharLeaf *l; 1222 int i; 1223 1224 b = FcCharSetCreate (); 1225 if (!b) 1226 goto bail0; 1227 for (i = 0; i < fcs->num; i++) 1228 { 1229 l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i)); 1230 if (!l) 1231 goto bail1; 1232 if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l)) 1233 goto bail1; 1234 } 1235 n = FcCharSetFreezeBase (freezer, b); 1236 if (!FcCharSetFreezeOrig (freezer, fcs, n)) 1237 { 1238 n = NULL; 1239 goto bail1; 1240 } 1241 freezer->charsets_seen++; 1242 freezer->leaves_seen += fcs->num; 1243bail1: 1244 if (b->num) 1245 free (FcCharSetLeaves (b)); 1246 if (b->num) 1247 free (FcCharSetNumbers (b)); 1248 free (b); 1249bail0: 1250 return n; 1251} 1252 1253FcCharSetFreezer * 1254FcCharSetFreezerCreate (void) 1255{ 1256 FcCharSetFreezer *freezer; 1257 1258 freezer = calloc (1, sizeof (FcCharSetFreezer)); 1259 return freezer; 1260} 1261 1262void 1263FcCharSetFreezerDestroy (FcCharSetFreezer *freezer) 1264{ 1265 int i; 1266 1267 if (FcDebug() & FC_DBG_CACHE) 1268 { 1269 printf ("\ncharsets %d -> %d leaves %d -> %d\n", 1270 freezer->charsets_seen, freezer->charsets_allocated, 1271 freezer->leaves_seen, freezer->leaves_allocated); 1272 } 1273 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) 1274 { 1275 FcCharSetEnt *ent, *next; 1276 for (ent = freezer->set_hash_table[i]; ent; ent = next) 1277 { 1278 next = ent->next; 1279 free (ent); 1280 } 1281 } 1282 1283 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) 1284 { 1285 FcCharSetOrigEnt *ent, *next; 1286 for (ent = freezer->orig_hash_table[i]; ent; ent = next) 1287 { 1288 next = ent->next; 1289 free (ent); 1290 } 1291 } 1292 1293 for (i = 0; i < freezer->leaf_block_count; i++) 1294 free (freezer->leaf_blocks[i]); 1295 1296 free (freezer->leaf_blocks); 1297 free (freezer); 1298} 1299 1300FcBool 1301FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs) 1302{ 1303 intptr_t *leaves; 1304 FcChar16 *numbers; 1305 int i; 1306 1307 if (!FcRefIsConst (&cs->ref)) 1308 { 1309 if (!serialize->cs_freezer) 1310 { 1311 serialize->cs_freezer = FcCharSetFreezerCreate (); 1312 if (!serialize->cs_freezer) 1313 return FcFalse; 1314 } 1315 if (FcCharSetFindFrozen (serialize->cs_freezer, cs)) 1316 return FcTrue; 1317 1318 cs = FcCharSetFreeze (serialize->cs_freezer, cs); 1319 } 1320 1321 leaves = FcCharSetLeaves (cs); 1322 numbers = FcCharSetNumbers (cs); 1323 1324 if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet))) 1325 return FcFalse; 1326 if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t))) 1327 return FcFalse; 1328 if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16))) 1329 return FcFalse; 1330 for (i = 0; i < cs->num; i++) 1331 if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i), 1332 sizeof (FcCharLeaf))) 1333 return FcFalse; 1334 return FcTrue; 1335} 1336 1337FcCharSet * 1338FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs) 1339{ 1340 FcCharSet *cs_serialized; 1341 intptr_t *leaves, *leaves_serialized; 1342 FcChar16 *numbers, *numbers_serialized; 1343 FcCharLeaf *leaf, *leaf_serialized; 1344 int i; 1345 1346 if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer) 1347 { 1348 cs = FcCharSetFindFrozen (serialize->cs_freezer, cs); 1349 if (!cs) 1350 return NULL; 1351 } 1352 1353 cs_serialized = FcSerializePtr (serialize, cs); 1354 if (!cs_serialized) 1355 return NULL; 1356 1357 FcRefSetConst (&cs_serialized->ref); 1358 cs_serialized->num = cs->num; 1359 1360 if (cs->num) 1361 { 1362 leaves = FcCharSetLeaves (cs); 1363 leaves_serialized = FcSerializePtr (serialize, leaves); 1364 if (!leaves_serialized) 1365 return NULL; 1366 1367 cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized, 1368 leaves_serialized); 1369 1370 numbers = FcCharSetNumbers (cs); 1371 numbers_serialized = FcSerializePtr (serialize, numbers); 1372 if (!numbers) 1373 return NULL; 1374 1375 cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized, 1376 numbers_serialized); 1377 1378 for (i = 0; i < cs->num; i++) 1379 { 1380 leaf = FcCharSetLeaf (cs, i); 1381 leaf_serialized = FcSerializePtr (serialize, leaf); 1382 if (!leaf_serialized) 1383 return NULL; 1384 *leaf_serialized = *leaf; 1385 leaves_serialized[i] = FcPtrToOffset (leaves_serialized, 1386 leaf_serialized); 1387 numbers_serialized[i] = numbers[i]; 1388 } 1389 } 1390 else 1391 { 1392 cs_serialized->leaves_offset = 0; 1393 cs_serialized->numbers_offset = 0; 1394 } 1395 1396 return cs_serialized; 1397} 1398#define __fccharset__ 1399#include "fcaliastail.h" 1400#undef __fccharset__ 1401