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