fccfg.c revision ca08ab68
1/* 2 * fontconfig/src/fccfg.c 3 * 4 * Copyright © 2000 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 <dirent.h> 27#include <sys/types.h> 28 29#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT)) 30#define STRICT 31#include <windows.h> 32#undef STRICT 33#endif 34 35#if defined (_WIN32) && !defined (R_OK) 36#define R_OK 4 37#endif 38 39FcConfig *_fcConfig; 40 41FcConfig * 42FcConfigCreate (void) 43{ 44 FcSetName set; 45 FcConfig *config; 46 47 config = malloc (sizeof (FcConfig)); 48 if (!config) 49 goto bail0; 50 FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig)); 51 52 config->configDirs = FcStrSetCreate (); 53 if (!config->configDirs) 54 goto bail1; 55 56 config->configFiles = FcStrSetCreate (); 57 if (!config->configFiles) 58 goto bail2; 59 60 config->fontDirs = FcStrSetCreate (); 61 if (!config->fontDirs) 62 goto bail3; 63 64 config->acceptGlobs = FcStrSetCreate (); 65 if (!config->acceptGlobs) 66 goto bail4; 67 68 config->rejectGlobs = FcStrSetCreate (); 69 if (!config->rejectGlobs) 70 goto bail5; 71 72 config->acceptPatterns = FcFontSetCreate (); 73 if (!config->acceptPatterns) 74 goto bail6; 75 76 config->rejectPatterns = FcFontSetCreate (); 77 if (!config->rejectPatterns) 78 goto bail7; 79 80 config->cacheDirs = FcStrSetCreate (); 81 if (!config->cacheDirs) 82 goto bail8; 83 84 config->blanks = 0; 85 86 config->substPattern = 0; 87 config->substFont = 0; 88 config->substScan = 0; 89 config->maxObjects = 0; 90 for (set = FcSetSystem; set <= FcSetApplication; set++) 91 config->fonts[set] = 0; 92 93 config->rescanTime = time(0); 94 config->rescanInterval = 30; 95 96 config->expr_pool = NULL; 97 98 config->ref = 1; 99 100 return config; 101 102bail8: 103 FcFontSetDestroy (config->rejectPatterns); 104bail7: 105 FcFontSetDestroy (config->acceptPatterns); 106bail6: 107 FcStrSetDestroy (config->rejectGlobs); 108bail5: 109 FcStrSetDestroy (config->acceptGlobs); 110bail4: 111 FcStrSetDestroy (config->fontDirs); 112bail3: 113 FcStrSetDestroy (config->configFiles); 114bail2: 115 FcStrSetDestroy (config->configDirs); 116bail1: 117 free (config); 118 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); 119bail0: 120 return 0; 121} 122 123static FcFileTime 124FcConfigNewestFile (FcStrSet *files) 125{ 126 FcStrList *list = FcStrListCreate (files); 127 FcFileTime newest = { 0, FcFalse }; 128 FcChar8 *file; 129 struct stat statb; 130 131 if (list) 132 { 133 while ((file = FcStrListNext (list))) 134 if (FcStat (file, &statb) == 0) 135 if (!newest.set || statb.st_mtime - newest.time > 0) 136 { 137 newest.set = FcTrue; 138 newest.time = statb.st_mtime; 139 } 140 FcStrListDone (list); 141 } 142 return newest; 143} 144 145FcBool 146FcConfigUptoDate (FcConfig *config) 147{ 148 FcFileTime config_time, config_dir_time, font_time; 149 time_t now = time(0); 150 if (!config) 151 { 152 config = FcConfigGetCurrent (); 153 if (!config) 154 return FcFalse; 155 } 156 config_time = FcConfigNewestFile (config->configFiles); 157 config_dir_time = FcConfigNewestFile (config->configDirs); 158 font_time = FcConfigNewestFile (config->fontDirs); 159 if ((config_time.set && config_time.time - config->rescanTime > 0) || 160 (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 161 (font_time.set && (font_time.time - config->rescanTime) > 0)) 162 { 163 /* We need to check for potential clock problems here (OLPC ticket #6046) */ 164 if ((config_time.set && (config_time.time - now) > 0) || 165 (config_dir_time.set && (config_dir_time.time - now) > 0) || 166 (font_time.set && (font_time.time - now) > 0)) 167 { 168 fprintf (stderr, 169 "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n"); 170 config->rescanTime = now; 171 return FcTrue; 172 } 173 else 174 return FcFalse; 175 } 176 config->rescanTime = now; 177 return FcTrue; 178} 179 180static void 181FcSubstDestroy (FcSubst *s) 182{ 183 FcSubst *n; 184 185 while (s) 186 { 187 n = s->next; 188 if (s->test) 189 FcTestDestroy (s->test); 190 if (s->edit) 191 FcEditDestroy (s->edit); 192 free (s); 193 FcMemFree (FC_MEM_SUBST, sizeof (FcSubst)); 194 s = n; 195 } 196} 197 198FcExpr * 199FcConfigAllocExpr (FcConfig *config) 200{ 201 if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 202 { 203 FcExprPage *new_page; 204 205 new_page = malloc (sizeof (FcExprPage)); 206 if (!new_page) 207 return 0; 208 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExprPage)); 209 210 new_page->next_page = config->expr_pool; 211 new_page->next = new_page->exprs; 212 config->expr_pool = new_page; 213 } 214 215 return config->expr_pool->next++; 216} 217 218FcConfig * 219FcConfigReference (FcConfig *config) 220{ 221 if (!config) 222 { 223 config = FcConfigGetCurrent (); 224 if (!config) 225 return 0; 226 } 227 228 config->ref++; 229 230 return config; 231} 232 233void 234FcConfigDestroy (FcConfig *config) 235{ 236 FcSetName set; 237 FcExprPage *page; 238 239 if (--config->ref > 0) 240 return; 241 242 if (config == _fcConfig) 243 _fcConfig = 0; 244 245 FcStrSetDestroy (config->configDirs); 246 FcStrSetDestroy (config->fontDirs); 247 FcStrSetDestroy (config->cacheDirs); 248 FcStrSetDestroy (config->configFiles); 249 FcStrSetDestroy (config->acceptGlobs); 250 FcStrSetDestroy (config->rejectGlobs); 251 FcFontSetDestroy (config->acceptPatterns); 252 FcFontSetDestroy (config->rejectPatterns); 253 254 if (config->blanks) 255 FcBlanksDestroy (config->blanks); 256 257 FcSubstDestroy (config->substPattern); 258 FcSubstDestroy (config->substFont); 259 FcSubstDestroy (config->substScan); 260 for (set = FcSetSystem; set <= FcSetApplication; set++) 261 if (config->fonts[set]) 262 FcFontSetDestroy (config->fonts[set]); 263 264 page = config->expr_pool; 265 while (page) 266 { 267 FcExprPage *next = page->next_page; 268 FcMemFree (FC_MEM_EXPR, sizeof (FcExprPage)); 269 free (page); 270 page = next; 271 } 272 273 free (config); 274 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); 275} 276 277/* 278 * Add cache to configuration, adding fonts and directories 279 */ 280 281FcBool 282FcConfigAddCache (FcConfig *config, FcCache *cache, 283 FcSetName set, FcStrSet *dirSet) 284{ 285 FcFontSet *fs; 286 intptr_t *dirs; 287 int i; 288 289 /* 290 * Add fonts 291 */ 292 fs = FcCacheSet (cache); 293 if (fs) 294 { 295 int nref = 0; 296 297 for (i = 0; i < fs->nfont; i++) 298 { 299 FcPattern *font = FcFontSetFont (fs, i); 300 FcChar8 *font_file; 301 302 /* 303 * Check to see if font is banned by filename 304 */ 305 if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 306 0, &font_file) == FcResultMatch && 307 !FcConfigAcceptFilename (config, font_file)) 308 { 309 continue; 310 } 311 312 /* 313 * Check to see if font is banned by pattern 314 */ 315 if (!FcConfigAcceptFont (config, font)) 316 continue; 317 318 nref++; 319 FcFontSetAdd (config->fonts[set], font); 320 } 321 FcDirCacheReference (cache, nref); 322 } 323 324 /* 325 * Add directories 326 */ 327 dirs = FcCacheDirs (cache); 328 if (dirs) 329 { 330 for (i = 0; i < cache->dirs_count; i++) 331 { 332 FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); 333 if (FcConfigAcceptFilename (config, dir)) 334 FcStrSetAddFilename (dirSet, dir); 335 } 336 } 337 return FcTrue; 338} 339 340static FcBool 341FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 342{ 343 FcStrList *dirlist; 344 FcChar8 *dir; 345 FcCache *cache; 346 347 dirlist = FcStrListCreate (dirSet); 348 if (!dirlist) 349 return FcFalse; 350 351 while ((dir = FcStrListNext (dirlist))) 352 { 353 if (FcDebug () & FC_DBG_FONTSET) 354 printf ("adding fonts from%s\n", dir); 355 cache = FcDirCacheRead (dir, FcFalse, config); 356 if (!cache) 357 continue; 358 FcConfigAddCache (config, cache, set, dirSet); 359 FcDirCacheUnload (cache); 360 } 361 FcStrListDone (dirlist); 362 return FcTrue; 363} 364 365/* 366 * Scan the current list of directories in the configuration 367 * and build the set of available fonts. 368 */ 369 370FcBool 371FcConfigBuildFonts (FcConfig *config) 372{ 373 FcFontSet *fonts; 374 375 if (!config) 376 { 377 config = FcConfigGetCurrent (); 378 if (!config) 379 return FcFalse; 380 } 381 382 fonts = FcFontSetCreate (); 383 if (!fonts) 384 return FcFalse; 385 386 FcConfigSetFonts (config, fonts, FcSetSystem); 387 388 if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 389 return FcFalse; 390 if (FcDebug () & FC_DBG_FONTSET) 391 FcFontSetPrint (fonts); 392 return FcTrue; 393} 394 395FcBool 396FcConfigSetCurrent (FcConfig *config) 397{ 398 if (config == _fcConfig) 399 return FcTrue; 400 401 if (!config->fonts) 402 if (!FcConfigBuildFonts (config)) 403 return FcFalse; 404 405 if (_fcConfig) 406 FcConfigDestroy (_fcConfig); 407 _fcConfig = config; 408 return FcTrue; 409} 410 411FcConfig * 412FcConfigGetCurrent (void) 413{ 414 if (!_fcConfig) 415 if (!FcInit ()) 416 return 0; 417 return _fcConfig; 418} 419 420FcBool 421FcConfigAddConfigDir (FcConfig *config, 422 const FcChar8 *d) 423{ 424 return FcStrSetAddFilename (config->configDirs, d); 425} 426 427FcStrList * 428FcConfigGetConfigDirs (FcConfig *config) 429{ 430 if (!config) 431 { 432 config = FcConfigGetCurrent (); 433 if (!config) 434 return 0; 435 } 436 return FcStrListCreate (config->configDirs); 437} 438 439FcBool 440FcConfigAddFontDir (FcConfig *config, 441 const FcChar8 *d) 442{ 443 return FcStrSetAddFilename (config->fontDirs, d); 444} 445 446FcBool 447FcConfigAddDir (FcConfig *config, 448 const FcChar8 *d) 449{ 450 return (FcConfigAddConfigDir (config, d) && 451 FcConfigAddFontDir (config, d)); 452} 453 454FcStrList * 455FcConfigGetFontDirs (FcConfig *config) 456{ 457 if (!config) 458 { 459 config = FcConfigGetCurrent (); 460 if (!config) 461 return 0; 462 } 463 return FcStrListCreate (config->fontDirs); 464} 465 466FcBool 467FcConfigAddCacheDir (FcConfig *config, 468 const FcChar8 *d) 469{ 470 return FcStrSetAddFilename (config->cacheDirs, d); 471} 472 473FcStrList * 474FcConfigGetCacheDirs (const FcConfig *config) 475{ 476 if (!config) 477 { 478 config = FcConfigGetCurrent (); 479 if (!config) 480 return 0; 481 } 482 return FcStrListCreate (config->cacheDirs); 483} 484 485FcBool 486FcConfigAddConfigFile (FcConfig *config, 487 const FcChar8 *f) 488{ 489 FcBool ret; 490 FcChar8 *file = FcConfigFilename (f); 491 492 if (!file) 493 return FcFalse; 494 495 ret = FcStrSetAdd (config->configFiles, file); 496 FcStrFree (file); 497 return ret; 498} 499 500FcStrList * 501FcConfigGetConfigFiles (FcConfig *config) 502{ 503 if (!config) 504 { 505 config = FcConfigGetCurrent (); 506 if (!config) 507 return 0; 508 } 509 return FcStrListCreate (config->configFiles); 510} 511 512FcChar8 * 513FcConfigGetCache (FcConfig *config) 514{ 515 return NULL; 516} 517 518FcFontSet * 519FcConfigGetFonts (FcConfig *config, 520 FcSetName set) 521{ 522 if (!config) 523 { 524 config = FcConfigGetCurrent (); 525 if (!config) 526 return 0; 527 } 528 return config->fonts[set]; 529} 530 531void 532FcConfigSetFonts (FcConfig *config, 533 FcFontSet *fonts, 534 FcSetName set) 535{ 536 if (config->fonts[set]) 537 FcFontSetDestroy (config->fonts[set]); 538 config->fonts[set] = fonts; 539} 540 541FcBlanks * 542FcConfigGetBlanks (FcConfig *config) 543{ 544 if (!config) 545 { 546 config = FcConfigGetCurrent (); 547 if (!config) 548 return 0; 549 } 550 return config->blanks; 551} 552 553FcBool 554FcConfigAddBlank (FcConfig *config, 555 FcChar32 blank) 556{ 557 FcBlanks *b, *freeme = 0; 558 559 b = config->blanks; 560 if (!b) 561 { 562 freeme = b = FcBlanksCreate (); 563 if (!b) 564 return FcFalse; 565 } 566 if (!FcBlanksAdd (b, blank)) 567 { 568 if (freeme) 569 FcBlanksDestroy (freeme); 570 return FcFalse; 571 } 572 config->blanks = b; 573 return FcTrue; 574} 575 576int 577FcConfigGetRescanInterval (FcConfig *config) 578{ 579 if (!config) 580 { 581 config = FcConfigGetCurrent (); 582 if (!config) 583 return 0; 584 } 585 return config->rescanInterval; 586} 587 588FcBool 589FcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 590{ 591 if (!config) 592 { 593 config = FcConfigGetCurrent (); 594 if (!config) 595 return FcFalse; 596 } 597 config->rescanInterval = rescanInterval; 598 return FcTrue; 599} 600 601/* 602 * A couple of typos escaped into the library 603 */ 604int 605FcConfigGetRescanInverval (FcConfig *config) 606{ 607 return FcConfigGetRescanInterval (config); 608} 609 610FcBool 611FcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 612{ 613 return FcConfigSetRescanInterval (config, rescanInterval); 614} 615 616 617FcBool 618FcConfigAddEdit (FcConfig *config, 619 FcTest *test, 620 FcEdit *edit, 621 FcMatchKind kind) 622{ 623 FcSubst *subst, **prev; 624 FcTest *t; 625 int num; 626 627 switch (kind) { 628 case FcMatchPattern: 629 prev = &config->substPattern; 630 break; 631 case FcMatchFont: 632 prev = &config->substFont; 633 break; 634 case FcMatchScan: 635 prev = &config->substScan; 636 break; 637 default: 638 return FcFalse; 639 } 640 subst = (FcSubst *) malloc (sizeof (FcSubst)); 641 if (!subst) 642 return FcFalse; 643 FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst)); 644 for (; *prev; prev = &(*prev)->next); 645 *prev = subst; 646 subst->next = 0; 647 subst->test = test; 648 subst->edit = edit; 649 num = 0; 650 for (t = test; t; t = t->next) 651 { 652 if (t->kind == FcMatchDefault) 653 t->kind = kind; 654 num++; 655 } 656 if (config->maxObjects < num) 657 config->maxObjects = num; 658 if (FcDebug () & FC_DBG_EDIT) 659 { 660 printf ("Add Subst "); 661 FcSubstPrint (subst); 662 } 663 return FcTrue; 664} 665 666typedef struct _FcSubState { 667 FcPatternElt *elt; 668 FcValueList *value; 669} FcSubState; 670 671static FcValue 672FcConfigPromote (FcValue v, FcValue u) 673{ 674 if (v.type == FcTypeInteger) 675 { 676 v.type = FcTypeDouble; 677 v.u.d = (double) v.u.i; 678 } 679 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 680 { 681 v.u.m = &FcIdentityMatrix; 682 v.type = FcTypeMatrix; 683 } 684 else if (v.type == FcTypeString && u.type == FcTypeLangSet) 685 { 686 v.u.l = FcLangSetPromote (v.u.s); 687 v.type = FcTypeLangSet; 688 } 689 return v; 690} 691 692FcBool 693FcConfigCompareValue (const FcValue *left_o, 694 FcOp op_, 695 const FcValue *right_o) 696{ 697 FcValue left = FcValueCanonicalize(left_o); 698 FcValue right = FcValueCanonicalize(right_o); 699 FcBool ret = FcFalse; 700 FcOp op = FC_OP_GET_OP (op_); 701 int flags = FC_OP_GET_FLAGS (op_); 702 703 left = FcConfigPromote (left, right); 704 right = FcConfigPromote (right, left); 705 if (left.type == right.type) 706 { 707 switch (left.type) { 708 case FcTypeInteger: 709 break; /* FcConfigPromote prevents this from happening */ 710 case FcTypeDouble: 711 switch (op) { 712 case FcOpEqual: 713 case FcOpContains: 714 case FcOpListing: 715 ret = left.u.d == right.u.d; 716 break; 717 case FcOpNotEqual: 718 case FcOpNotContains: 719 ret = left.u.d != right.u.d; 720 break; 721 case FcOpLess: 722 ret = left.u.d < right.u.d; 723 break; 724 case FcOpLessEqual: 725 ret = left.u.d <= right.u.d; 726 break; 727 case FcOpMore: 728 ret = left.u.d > right.u.d; 729 break; 730 case FcOpMoreEqual: 731 ret = left.u.d >= right.u.d; 732 break; 733 default: 734 break; 735 } 736 break; 737 case FcTypeBool: 738 switch (op) { 739 case FcOpEqual: 740 case FcOpContains: 741 case FcOpListing: 742 ret = left.u.b == right.u.b; 743 break; 744 case FcOpNotEqual: 745 case FcOpNotContains: 746 ret = left.u.b != right.u.b; 747 break; 748 default: 749 break; 750 } 751 break; 752 case FcTypeString: 753 switch (op) { 754 case FcOpEqual: 755 case FcOpListing: 756 if (flags & FcOpFlagIgnoreBlanks) 757 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; 758 else 759 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 760 break; 761 case FcOpContains: 762 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 763 break; 764 case FcOpNotEqual: 765 if (flags & FcOpFlagIgnoreBlanks) 766 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; 767 else 768 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 769 break; 770 case FcOpNotContains: 771 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 772 break; 773 default: 774 break; 775 } 776 break; 777 case FcTypeMatrix: 778 switch (op) { 779 case FcOpEqual: 780 case FcOpContains: 781 case FcOpListing: 782 ret = FcMatrixEqual (left.u.m, right.u.m); 783 break; 784 case FcOpNotEqual: 785 case FcOpNotContains: 786 ret = !FcMatrixEqual (left.u.m, right.u.m); 787 break; 788 default: 789 break; 790 } 791 break; 792 case FcTypeCharSet: 793 switch (op) { 794 case FcOpContains: 795 case FcOpListing: 796 /* left contains right if right is a subset of left */ 797 ret = FcCharSetIsSubset (right.u.c, left.u.c); 798 break; 799 case FcOpNotContains: 800 /* left contains right if right is a subset of left */ 801 ret = !FcCharSetIsSubset (right.u.c, left.u.c); 802 break; 803 case FcOpEqual: 804 ret = FcCharSetEqual (left.u.c, right.u.c); 805 break; 806 case FcOpNotEqual: 807 ret = !FcCharSetEqual (left.u.c, right.u.c); 808 break; 809 default: 810 break; 811 } 812 break; 813 case FcTypeLangSet: 814 switch (op) { 815 case FcOpContains: 816 case FcOpListing: 817 ret = FcLangSetContains (left.u.l, right.u.l); 818 break; 819 case FcOpNotContains: 820 ret = !FcLangSetContains (left.u.l, right.u.l); 821 break; 822 case FcOpEqual: 823 ret = FcLangSetEqual (left.u.l, right.u.l); 824 break; 825 case FcOpNotEqual: 826 ret = !FcLangSetEqual (left.u.l, right.u.l); 827 break; 828 default: 829 break; 830 } 831 break; 832 case FcTypeVoid: 833 switch (op) { 834 case FcOpEqual: 835 case FcOpContains: 836 case FcOpListing: 837 ret = FcTrue; 838 break; 839 default: 840 break; 841 } 842 break; 843 case FcTypeFTFace: 844 switch (op) { 845 case FcOpEqual: 846 case FcOpContains: 847 case FcOpListing: 848 ret = left.u.f == right.u.f; 849 break; 850 case FcOpNotEqual: 851 case FcOpNotContains: 852 ret = left.u.f != right.u.f; 853 break; 854 default: 855 break; 856 } 857 break; 858 } 859 } 860 else 861 { 862 if (op == FcOpNotEqual || op == FcOpNotContains) 863 ret = FcTrue; 864 } 865 return ret; 866} 867 868 869#define _FcDoubleFloor(d) ((int) (d)) 870#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 871#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 872#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 873#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 874#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 875 876static FcValue 877FcConfigEvaluate (FcPattern *p, FcExpr *e) 878{ 879 FcValue v, vl, vr; 880 FcResult r; 881 FcMatrix *m; 882 FcChar8 *str; 883 FcOp op = FC_OP_GET_OP (e->op); 884 885 switch (op) { 886 case FcOpInteger: 887 v.type = FcTypeInteger; 888 v.u.i = e->u.ival; 889 break; 890 case FcOpDouble: 891 v.type = FcTypeDouble; 892 v.u.d = e->u.dval; 893 break; 894 case FcOpString: 895 v.type = FcTypeString; 896 v.u.s = e->u.sval; 897 v = FcValueSave (v); 898 break; 899 case FcOpMatrix: 900 v.type = FcTypeMatrix; 901 v.u.m = e->u.mval; 902 v = FcValueSave (v); 903 break; 904 case FcOpCharSet: 905 v.type = FcTypeCharSet; 906 v.u.c = e->u.cval; 907 v = FcValueSave (v); 908 break; 909 case FcOpLangSet: 910 v.type = FcTypeLangSet; 911 v.u.l = e->u.lval; 912 v = FcValueSave (v); 913 break; 914 case FcOpBool: 915 v.type = FcTypeBool; 916 v.u.b = e->u.bval; 917 break; 918 case FcOpField: 919 r = FcPatternObjectGet (p, e->u.object, 0, &v); 920 if (r != FcResultMatch) 921 v.type = FcTypeVoid; 922 v = FcValueSave (v); 923 break; 924 case FcOpConst: 925 if (FcNameConstant (e->u.constant, &v.u.i)) 926 v.type = FcTypeInteger; 927 else 928 v.type = FcTypeVoid; 929 break; 930 case FcOpQuest: 931 vl = FcConfigEvaluate (p, e->u.tree.left); 932 if (vl.type == FcTypeBool) 933 { 934 if (vl.u.b) 935 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left); 936 else 937 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right); 938 } 939 else 940 v.type = FcTypeVoid; 941 FcValueDestroy (vl); 942 break; 943 case FcOpEqual: 944 case FcOpNotEqual: 945 case FcOpLess: 946 case FcOpLessEqual: 947 case FcOpMore: 948 case FcOpMoreEqual: 949 case FcOpContains: 950 case FcOpNotContains: 951 case FcOpListing: 952 vl = FcConfigEvaluate (p, e->u.tree.left); 953 vr = FcConfigEvaluate (p, e->u.tree.right); 954 v.type = FcTypeBool; 955 v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 956 FcValueDestroy (vl); 957 FcValueDestroy (vr); 958 break; 959 case FcOpOr: 960 case FcOpAnd: 961 case FcOpPlus: 962 case FcOpMinus: 963 case FcOpTimes: 964 case FcOpDivide: 965 vl = FcConfigEvaluate (p, e->u.tree.left); 966 vr = FcConfigEvaluate (p, e->u.tree.right); 967 vl = FcConfigPromote (vl, vr); 968 vr = FcConfigPromote (vr, vl); 969 if (vl.type == vr.type) 970 { 971 switch (vl.type) { 972 case FcTypeDouble: 973 switch (op) { 974 case FcOpPlus: 975 v.type = FcTypeDouble; 976 v.u.d = vl.u.d + vr.u.d; 977 break; 978 case FcOpMinus: 979 v.type = FcTypeDouble; 980 v.u.d = vl.u.d - vr.u.d; 981 break; 982 case FcOpTimes: 983 v.type = FcTypeDouble; 984 v.u.d = vl.u.d * vr.u.d; 985 break; 986 case FcOpDivide: 987 v.type = FcTypeDouble; 988 v.u.d = vl.u.d / vr.u.d; 989 break; 990 default: 991 v.type = FcTypeVoid; 992 break; 993 } 994 if (v.type == FcTypeDouble && 995 v.u.d == (double) (int) v.u.d) 996 { 997 v.type = FcTypeInteger; 998 v.u.i = (int) v.u.d; 999 } 1000 break; 1001 case FcTypeBool: 1002 switch (op) { 1003 case FcOpOr: 1004 v.type = FcTypeBool; 1005 v.u.b = vl.u.b || vr.u.b; 1006 break; 1007 case FcOpAnd: 1008 v.type = FcTypeBool; 1009 v.u.b = vl.u.b && vr.u.b; 1010 break; 1011 default: 1012 v.type = FcTypeVoid; 1013 break; 1014 } 1015 break; 1016 case FcTypeString: 1017 switch (op) { 1018 case FcOpPlus: 1019 v.type = FcTypeString; 1020 str = FcStrPlus (vl.u.s, vr.u.s); 1021 v.u.s = FcSharedStr (str); 1022 FcStrFree (str); 1023 1024 if (!v.u.s) 1025 v.type = FcTypeVoid; 1026 break; 1027 default: 1028 v.type = FcTypeVoid; 1029 break; 1030 } 1031 break; 1032 case FcTypeMatrix: 1033 switch (op) { 1034 case FcOpTimes: 1035 v.type = FcTypeMatrix; 1036 m = malloc (sizeof (FcMatrix)); 1037 if (m) 1038 { 1039 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix)); 1040 FcMatrixMultiply (m, vl.u.m, vr.u.m); 1041 v.u.m = m; 1042 } 1043 else 1044 { 1045 v.type = FcTypeVoid; 1046 } 1047 break; 1048 default: 1049 v.type = FcTypeVoid; 1050 break; 1051 } 1052 break; 1053 case FcTypeCharSet: 1054 switch (op) { 1055 case FcOpPlus: 1056 v.type = FcTypeCharSet; 1057 v.u.c = FcCharSetUnion (vl.u.c, vr.u.c); 1058 if (!v.u.c) 1059 v.type = FcTypeVoid; 1060 break; 1061 case FcOpMinus: 1062 v.type = FcTypeCharSet; 1063 v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c); 1064 if (!v.u.c) 1065 v.type = FcTypeVoid; 1066 break; 1067 default: 1068 v.type = FcTypeVoid; 1069 break; 1070 } 1071 break; 1072 case FcTypeLangSet: 1073 switch (op) { 1074 case FcOpPlus: 1075 v.type = FcTypeLangSet; 1076 v.u.l = FcLangSetUnion (vl.u.l, vr.u.l); 1077 if (!v.u.l) 1078 v.type = FcTypeVoid; 1079 break; 1080 case FcOpMinus: 1081 v.type = FcTypeLangSet; 1082 v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l); 1083 if (!v.u.l) 1084 v.type = FcTypeVoid; 1085 break; 1086 default: 1087 v.type = FcTypeVoid; 1088 break; 1089 } 1090 break; 1091 default: 1092 v.type = FcTypeVoid; 1093 break; 1094 } 1095 } 1096 else 1097 v.type = FcTypeVoid; 1098 FcValueDestroy (vl); 1099 FcValueDestroy (vr); 1100 break; 1101 case FcOpNot: 1102 vl = FcConfigEvaluate (p, e->u.tree.left); 1103 switch (vl.type) { 1104 case FcTypeBool: 1105 v.type = FcTypeBool; 1106 v.u.b = !vl.u.b; 1107 break; 1108 default: 1109 v.type = FcTypeVoid; 1110 break; 1111 } 1112 FcValueDestroy (vl); 1113 break; 1114 case FcOpFloor: 1115 vl = FcConfigEvaluate (p, e->u.tree.left); 1116 switch (vl.type) { 1117 case FcTypeInteger: 1118 v = vl; 1119 break; 1120 case FcTypeDouble: 1121 v.type = FcTypeInteger; 1122 v.u.i = FcDoubleFloor (vl.u.d); 1123 break; 1124 default: 1125 v.type = FcTypeVoid; 1126 break; 1127 } 1128 FcValueDestroy (vl); 1129 break; 1130 case FcOpCeil: 1131 vl = FcConfigEvaluate (p, e->u.tree.left); 1132 switch (vl.type) { 1133 case FcTypeInteger: 1134 v = vl; 1135 break; 1136 case FcTypeDouble: 1137 v.type = FcTypeInteger; 1138 v.u.i = FcDoubleCeil (vl.u.d); 1139 break; 1140 default: 1141 v.type = FcTypeVoid; 1142 break; 1143 } 1144 FcValueDestroy (vl); 1145 break; 1146 case FcOpRound: 1147 vl = FcConfigEvaluate (p, e->u.tree.left); 1148 switch (vl.type) { 1149 case FcTypeInteger: 1150 v = vl; 1151 break; 1152 case FcTypeDouble: 1153 v.type = FcTypeInteger; 1154 v.u.i = FcDoubleRound (vl.u.d); 1155 break; 1156 default: 1157 v.type = FcTypeVoid; 1158 break; 1159 } 1160 FcValueDestroy (vl); 1161 break; 1162 case FcOpTrunc: 1163 vl = FcConfigEvaluate (p, e->u.tree.left); 1164 switch (vl.type) { 1165 case FcTypeInteger: 1166 v = vl; 1167 break; 1168 case FcTypeDouble: 1169 v.type = FcTypeInteger; 1170 v.u.i = FcDoubleTrunc (vl.u.d); 1171 break; 1172 default: 1173 v.type = FcTypeVoid; 1174 break; 1175 } 1176 FcValueDestroy (vl); 1177 break; 1178 default: 1179 v.type = FcTypeVoid; 1180 break; 1181 } 1182 return v; 1183} 1184 1185static FcValueList * 1186FcConfigMatchValueList (FcPattern *p, 1187 FcTest *t, 1188 FcValueList *values) 1189{ 1190 FcValueList *ret = 0; 1191 FcExpr *e = t->expr; 1192 FcValue value; 1193 FcValueList *v; 1194 1195 while (e) 1196 { 1197 /* Compute the value of the match expression */ 1198 if (FC_OP_GET_OP (e->op) == FcOpComma) 1199 { 1200 value = FcConfigEvaluate (p, e->u.tree.left); 1201 e = e->u.tree.right; 1202 } 1203 else 1204 { 1205 value = FcConfigEvaluate (p, e); 1206 e = 0; 1207 } 1208 1209 for (v = values; v; v = FcValueListNext(v)) 1210 { 1211 /* Compare the pattern value to the match expression value */ 1212 if (FcConfigCompareValue (&v->value, t->op, &value)) 1213 { 1214 if (!ret) 1215 ret = v; 1216 } 1217 else 1218 { 1219 if (t->qual == FcQualAll) 1220 { 1221 ret = 0; 1222 break; 1223 } 1224 } 1225 } 1226 FcValueDestroy (value); 1227 } 1228 return ret; 1229} 1230 1231static FcValueList * 1232FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding) 1233{ 1234 FcValueList *l; 1235 1236 if (!e) 1237 return 0; 1238 l = (FcValueList *) malloc (sizeof (FcValueList)); 1239 if (!l) 1240 return 0; 1241 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); 1242 if (FC_OP_GET_OP (e->op) == FcOpComma) 1243 { 1244 l->value = FcConfigEvaluate (p, e->u.tree.left); 1245 l->next = FcConfigValues (p, e->u.tree.right, binding); 1246 } 1247 else 1248 { 1249 l->value = FcConfigEvaluate (p, e); 1250 l->next = NULL; 1251 } 1252 l->binding = binding; 1253 if (l->value.type == FcTypeVoid) 1254 { 1255 FcValueList *next = FcValueListNext(l); 1256 1257 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); 1258 free (l); 1259 l = next; 1260 } 1261 1262 return l; 1263} 1264 1265static FcBool 1266FcConfigAdd (FcValueListPtr *head, 1267 FcValueList *position, 1268 FcBool append, 1269 FcValueList *new) 1270{ 1271 FcValueListPtr *prev, last, v; 1272 FcValueBinding sameBinding; 1273 1274 if (position) 1275 sameBinding = position->binding; 1276 else 1277 sameBinding = FcValueBindingWeak; 1278 for (v = new; v != NULL; v = FcValueListNext(v)) 1279 if (v->binding == FcValueBindingSame) 1280 v->binding = sameBinding; 1281 if (append) 1282 { 1283 if (position) 1284 prev = &position->next; 1285 else 1286 for (prev = head; *prev != NULL; 1287 prev = &(*prev)->next) 1288 ; 1289 } 1290 else 1291 { 1292 if (position) 1293 { 1294 for (prev = head; *prev != NULL; 1295 prev = &(*prev)->next) 1296 { 1297 if (*prev == position) 1298 break; 1299 } 1300 } 1301 else 1302 prev = head; 1303 1304 if (FcDebug () & FC_DBG_EDIT) 1305 { 1306 if (*prev == NULL) 1307 printf ("position not on list\n"); 1308 } 1309 } 1310 1311 if (FcDebug () & FC_DBG_EDIT) 1312 { 1313 printf ("%s list before ", append ? "Append" : "Prepend"); 1314 FcValueListPrintWithPosition (*head, *prev); 1315 printf ("\n"); 1316 } 1317 1318 if (new) 1319 { 1320 last = new; 1321 while (last->next != NULL) 1322 last = last->next; 1323 1324 last->next = *prev; 1325 *prev = new; 1326 } 1327 1328 if (FcDebug () & FC_DBG_EDIT) 1329 { 1330 printf ("%s list after ", append ? "Append" : "Prepend"); 1331 FcValueListPrint (*head); 1332 printf ("\n"); 1333 } 1334 1335 return FcTrue; 1336} 1337 1338static void 1339FcConfigDel (FcValueListPtr *head, 1340 FcValueList *position) 1341{ 1342 FcValueListPtr *prev; 1343 1344 for (prev = head; *prev != NULL; prev = &(*prev)->next) 1345 { 1346 if (*prev == position) 1347 { 1348 *prev = position->next; 1349 position->next = NULL; 1350 FcValueListDestroy (position); 1351 break; 1352 } 1353 } 1354} 1355 1356static void 1357FcConfigPatternAdd (FcPattern *p, 1358 FcObject object, 1359 FcValueList *list, 1360 FcBool append) 1361{ 1362 if (list) 1363 { 1364 FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1365 1366 if (!e) 1367 return; 1368 FcConfigAdd (&e->values, 0, append, list); 1369 } 1370} 1371 1372/* 1373 * Delete all values associated with a field 1374 */ 1375static void 1376FcConfigPatternDel (FcPattern *p, 1377 FcObject object) 1378{ 1379 FcPatternElt *e = FcPatternObjectFindElt (p, object); 1380 if (!e) 1381 return; 1382 while (e->values != NULL) 1383 FcConfigDel (&e->values, e->values); 1384} 1385 1386static void 1387FcConfigPatternCanon (FcPattern *p, 1388 FcObject object) 1389{ 1390 FcPatternElt *e = FcPatternObjectFindElt (p, object); 1391 if (!e) 1392 return; 1393 if (e->values == NULL) 1394 FcPatternObjectDel (p, object); 1395} 1396 1397FcBool 1398FcConfigSubstituteWithPat (FcConfig *config, 1399 FcPattern *p, 1400 FcPattern *p_pat, 1401 FcMatchKind kind) 1402{ 1403 FcSubst *s; 1404 FcSubState *st; 1405 int i; 1406 FcTest *t; 1407 FcEdit *e; 1408 FcValueList *l; 1409 FcPattern *m; 1410 FcStrSet *strs; 1411 1412 if (!config) 1413 { 1414 config = FcConfigGetCurrent (); 1415 if (!config) 1416 return FcFalse; 1417 } 1418 1419 switch (kind) { 1420 case FcMatchPattern: 1421 s = config->substPattern; 1422 strs = FcGetDefaultLangs (); 1423 if (strs) 1424 { 1425 FcStrList *l = FcStrListCreate (strs); 1426 FcChar8 *lang; 1427 FcValue v; 1428 1429 FcStrSetDestroy (strs); 1430 while (l && (lang = FcStrListNext (l))) 1431 { 1432 v.type = FcTypeString; 1433 v.u.s = lang; 1434 FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 1435 } 1436 FcStrListDone (l); 1437 } 1438 break; 1439 case FcMatchFont: 1440 s = config->substFont; 1441 break; 1442 case FcMatchScan: 1443 s = config->substScan; 1444 break; 1445 default: 1446 return FcFalse; 1447 } 1448 1449 st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState)); 1450 if (!st && config->maxObjects) 1451 return FcFalse; 1452 FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 1453 1454 if (FcDebug () & FC_DBG_EDIT) 1455 { 1456 printf ("FcConfigSubstitute "); 1457 FcPatternPrint (p); 1458 } 1459 for (; s; s = s->next) 1460 { 1461 /* 1462 * Check the tests to see if 1463 * they all match the pattern 1464 */ 1465 for (t = s->test, i = 0; t; t = t->next, i++) 1466 { 1467 if (FcDebug () & FC_DBG_EDIT) 1468 { 1469 printf ("FcConfigSubstitute test "); 1470 FcTestPrint (t); 1471 } 1472 st[i].elt = 0; 1473 if (kind == FcMatchFont && t->kind == FcMatchPattern) 1474 m = p_pat; 1475 else 1476 m = p; 1477 if (m) 1478 st[i].elt = FcPatternObjectFindElt (m, t->object); 1479 else 1480 st[i].elt = 0; 1481 /* 1482 * If there's no such field in the font, 1483 * then FcQualAll matches while FcQualAny does not 1484 */ 1485 if (!st[i].elt) 1486 { 1487 if (t->qual == FcQualAll) 1488 { 1489 st[i].value = 0; 1490 continue; 1491 } 1492 else 1493 break; 1494 } 1495 /* 1496 * Check to see if there is a match, mark the location 1497 * to apply match-relative edits 1498 */ 1499 st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values); 1500 if (!st[i].value) 1501 break; 1502 if (t->qual == FcQualFirst && st[i].value != st[i].elt->values) 1503 break; 1504 if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values) 1505 break; 1506 } 1507 if (t) 1508 { 1509 if (FcDebug () & FC_DBG_EDIT) 1510 printf ("No match\n"); 1511 continue; 1512 } 1513 if (FcDebug () & FC_DBG_EDIT) 1514 { 1515 printf ("Substitute "); 1516 FcSubstPrint (s); 1517 } 1518 for (e = s->edit; e; e = e->next) 1519 { 1520 /* 1521 * Evaluate the list of expressions 1522 */ 1523 l = FcConfigValues (p, e->expr, e->binding); 1524 /* 1525 * Locate any test associated with this field, skipping 1526 * tests associated with the pattern when substituting in 1527 * the font 1528 */ 1529 for (t = s->test, i = 0; t; t = t->next, i++) 1530 { 1531 if ((t->kind == FcMatchFont || kind == FcMatchPattern) && 1532 t->object == e->object) 1533 { 1534 /* 1535 * KLUDGE - the pattern may have been reallocated or 1536 * things may have been inserted or deleted above 1537 * this element by other edits. Go back and find 1538 * the element again 1539 */ 1540 if (e != s->edit && st[i].elt) 1541 st[i].elt = FcPatternObjectFindElt (p, t->object); 1542 if (!st[i].elt) 1543 t = 0; 1544 break; 1545 } 1546 } 1547 switch (FC_OP_GET_OP (e->op)) { 1548 case FcOpAssign: 1549 /* 1550 * If there was a test, then replace the matched 1551 * value with the new list of values 1552 */ 1553 if (t) 1554 { 1555 FcValueList *thisValue = st[i].value; 1556 FcValueList *nextValue = thisValue; 1557 1558 /* 1559 * Append the new list of values after the current value 1560 */ 1561 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l); 1562 /* 1563 * Delete the marked value 1564 */ 1565 if (thisValue) 1566 FcConfigDel (&st[i].elt->values, thisValue); 1567 /* 1568 * Adjust any pointers into the value list to ensure 1569 * future edits occur at the same place 1570 */ 1571 for (t = s->test, i = 0; t; t = t->next, i++) 1572 { 1573 if (st[i].value == thisValue) 1574 st[i].value = nextValue; 1575 } 1576 break; 1577 } 1578 /* fall through ... */ 1579 case FcOpAssignReplace: 1580 /* 1581 * Delete all of the values and insert 1582 * the new set 1583 */ 1584 FcConfigPatternDel (p, e->object); 1585 FcConfigPatternAdd (p, e->object, l, FcTrue); 1586 /* 1587 * Adjust any pointers into the value list as they no 1588 * longer point to anything valid 1589 */ 1590 if (t) 1591 { 1592 FcPatternElt *thisElt = st[i].elt; 1593 for (t = s->test, i = 0; t; t = t->next, i++) 1594 { 1595 if (st[i].elt == thisElt) 1596 st[i].value = 0; 1597 } 1598 } 1599 break; 1600 case FcOpPrepend: 1601 if (t) 1602 { 1603 FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l); 1604 break; 1605 } 1606 /* fall through ... */ 1607 case FcOpPrependFirst: 1608 FcConfigPatternAdd (p, e->object, l, FcFalse); 1609 break; 1610 case FcOpAppend: 1611 if (t) 1612 { 1613 FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l); 1614 break; 1615 } 1616 /* fall through ... */ 1617 case FcOpAppendLast: 1618 FcConfigPatternAdd (p, e->object, l, FcTrue); 1619 break; 1620 default: 1621 FcValueListDestroy (l); 1622 break; 1623 } 1624 } 1625 /* 1626 * Now go through the pattern and eliminate 1627 * any properties without data 1628 */ 1629 for (e = s->edit; e; e = e->next) 1630 FcConfigPatternCanon (p, e->object); 1631 1632 if (FcDebug () & FC_DBG_EDIT) 1633 { 1634 printf ("FcConfigSubstitute edit"); 1635 FcPatternPrint (p); 1636 } 1637 } 1638 FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 1639 free (st); 1640 if (FcDebug () & FC_DBG_EDIT) 1641 { 1642 printf ("FcConfigSubstitute done"); 1643 FcPatternPrint (p); 1644 } 1645 return FcTrue; 1646} 1647 1648FcBool 1649FcConfigSubstitute (FcConfig *config, 1650 FcPattern *p, 1651 FcMatchKind kind) 1652{ 1653 return FcConfigSubstituteWithPat (config, p, 0, kind); 1654} 1655 1656#if defined (_WIN32) 1657 1658# define WIN32_LEAN_AND_MEAN 1659# define WIN32_EXTRA_LEAN 1660# include <windows.h> 1661 1662static FcChar8 fontconfig_path[1000] = ""; 1663 1664# if (defined (PIC) || defined (DLL_EXPORT)) 1665 1666BOOL WINAPI 1667DllMain (HINSTANCE hinstDLL, 1668 DWORD fdwReason, 1669 LPVOID lpvReserved) 1670{ 1671 FcChar8 *p; 1672 1673 switch (fdwReason) { 1674 case DLL_PROCESS_ATTACH: 1675 if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 1676 sizeof (fontconfig_path))) 1677 break; 1678 1679 /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 1680 * assume it's a Unix-style installation tree, and use 1681 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 1682 * folder where the DLL is as FONTCONFIG_PATH. 1683 */ 1684 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1685 if (p) 1686 { 1687 *p = '\0'; 1688 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1689 if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 1690 FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 1691 *p = '\0'; 1692 strcat ((char *) fontconfig_path, "\\etc\\fonts"); 1693 } 1694 else 1695 fontconfig_path[0] = '\0'; 1696 1697 break; 1698 } 1699 1700 return TRUE; 1701} 1702 1703# endif /* !PIC */ 1704 1705#undef FONTCONFIG_PATH 1706#define FONTCONFIG_PATH fontconfig_path 1707 1708#endif /* !_WIN32 */ 1709 1710#ifndef FONTCONFIG_FILE 1711#define FONTCONFIG_FILE "fonts.conf" 1712#endif 1713 1714static FcChar8 * 1715FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 1716{ 1717 FcChar8 *path; 1718 int size, osize; 1719 1720 if (!dir) 1721 dir = (FcChar8 *) ""; 1722 1723 osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 1724 /* 1725 * workaround valgrind warning because glibc takes advantage of how it knows memory is 1726 * allocated to implement strlen by reading in groups of 4 1727 */ 1728 size = (osize + 3) & ~3; 1729 1730 path = malloc (size); 1731 if (!path) 1732 return 0; 1733 1734 strcpy ((char *) path, (const char *) dir); 1735 /* make sure there's a single separator */ 1736#ifdef _WIN32 1737 if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 1738 path[strlen((char *) path)-1] != '\\')) && 1739 !(file[0] == '/' || 1740 file[0] == '\\' || 1741 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 1742 strcat ((char *) path, "\\"); 1743#else 1744 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 1745 strcat ((char *) path, "/"); 1746#endif 1747 strcat ((char *) path, (char *) file); 1748 1749 FcMemAlloc (FC_MEM_STRING, osize); 1750 if (access ((char *) path, R_OK) == 0) 1751 return path; 1752 1753 FcStrFree (path); 1754 1755 return 0; 1756} 1757 1758static FcChar8 ** 1759FcConfigGetPath (void) 1760{ 1761 FcChar8 **path; 1762 FcChar8 *env, *e, *colon; 1763 FcChar8 *dir; 1764 int npath; 1765 int i; 1766 1767 npath = 2; /* default dir + null */ 1768 env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 1769 if (env) 1770 { 1771 e = env; 1772 npath++; 1773 while (*e) 1774 if (*e++ == FC_SEARCH_PATH_SEPARATOR) 1775 npath++; 1776 } 1777 path = calloc (npath, sizeof (FcChar8 *)); 1778 if (!path) 1779 goto bail0; 1780 i = 0; 1781 1782 if (env) 1783 { 1784 e = env; 1785 while (*e) 1786 { 1787 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 1788 if (!colon) 1789 colon = e + strlen ((char *) e); 1790 path[i] = malloc (colon - e + 1); 1791 if (!path[i]) 1792 goto bail1; 1793 strncpy ((char *) path[i], (const char *) e, colon - e); 1794 path[i][colon - e] = '\0'; 1795 if (*colon) 1796 e = colon + 1; 1797 else 1798 e = colon; 1799 i++; 1800 } 1801 } 1802 1803#ifdef _WIN32 1804 if (fontconfig_path[0] == '\0') 1805 { 1806 char *p; 1807 if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 1808 goto bail1; 1809 p = strrchr ((const char *) fontconfig_path, '\\'); 1810 if (p) *p = '\0'; 1811 strcat ((char *) fontconfig_path, "\\fonts"); 1812 } 1813#endif 1814 dir = (FcChar8 *) FONTCONFIG_PATH; 1815 path[i] = malloc (strlen ((char *) dir) + 1); 1816 if (!path[i]) 1817 goto bail1; 1818 strcpy ((char *) path[i], (const char *) dir); 1819 return path; 1820 1821bail1: 1822 for (i = 0; path[i]; i++) 1823 free (path[i]); 1824 free (path); 1825bail0: 1826 return 0; 1827} 1828 1829static void 1830FcConfigFreePath (FcChar8 **path) 1831{ 1832 FcChar8 **p; 1833 1834 for (p = path; *p; p++) 1835 free (*p); 1836 free (path); 1837} 1838 1839static FcBool _FcConfigHomeEnabled = FcTrue; 1840 1841FcChar8 * 1842FcConfigHome (void) 1843{ 1844 if (_FcConfigHomeEnabled) 1845 { 1846 char *home = getenv ("HOME"); 1847 1848#ifdef _WIN32 1849 if (home == NULL) 1850 home = getenv ("USERPROFILE"); 1851#endif 1852 1853 return (FcChar8 *) home; 1854 } 1855 return 0; 1856} 1857 1858FcChar8 * 1859FcConfigXdgCacheHome (void) 1860{ 1861 const char *env = getenv ("XDG_CACHE_HOME"); 1862 FcChar8 *ret = NULL; 1863 1864 if (env) 1865 ret = FcStrCopy ((const FcChar8 *)env); 1866 else 1867 { 1868 const FcChar8 *home = FcConfigHome (); 1869 size_t len = home ? strlen ((const char *)home) : 0; 1870 1871 ret = malloc (len + 7 + 1); 1872 if (ret) 1873 { 1874 FcMemAlloc (FC_MEM_STRING, len + 7 + 1); 1875 memcpy (ret, home, len); 1876 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 1877 ret[len + 7] = 0; 1878 } 1879 } 1880 1881 return ret; 1882} 1883 1884FcChar8 * 1885FcConfigXdgConfigHome (void) 1886{ 1887 const char *env = getenv ("XDG_CONFIG_HOME"); 1888 FcChar8 *ret = NULL; 1889 1890 if (env) 1891 ret = FcStrCopy ((const FcChar8 *)env); 1892 else 1893 { 1894 const FcChar8 *home = FcConfigHome (); 1895 size_t len = home ? strlen ((const char *)home) : 0; 1896 1897 ret = malloc (len + 8 + 1); 1898 if (ret) 1899 { 1900 FcMemAlloc (FC_MEM_STRING, len + 8 + 1); 1901 memcpy (ret, home, len); 1902 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 1903 ret[len + 8] = 0; 1904 } 1905 } 1906 1907 return ret; 1908} 1909 1910FcChar8 * 1911FcConfigXdgDataHome (void) 1912{ 1913 const char *env = getenv ("XDG_DATA_HOME"); 1914 FcChar8 *ret = NULL; 1915 1916 if (env) 1917 ret = FcStrCopy ((const FcChar8 *)env); 1918 else 1919 { 1920 const FcChar8 *home = FcConfigHome (); 1921 size_t len = home ? strlen ((const char *)home) : 0; 1922 1923 ret = malloc (len + 13 + 1); 1924 if (ret) 1925 { 1926 FcMemAlloc (FC_MEM_STRING, len + 13 + 1); 1927 memcpy (ret, home, len); 1928 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 1929 ret[len + 13] = 0; 1930 } 1931 } 1932 1933 return ret; 1934} 1935 1936FcBool 1937FcConfigEnableHome (FcBool enable) 1938{ 1939 FcBool prev = _FcConfigHomeEnabled; 1940 _FcConfigHomeEnabled = enable; 1941 return prev; 1942} 1943 1944FcChar8 * 1945FcConfigFilename (const FcChar8 *url) 1946{ 1947 FcChar8 *file, *dir, **path, **p; 1948 1949 if (!url || !*url) 1950 { 1951 url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 1952 if (!url) 1953 url = (FcChar8 *) FONTCONFIG_FILE; 1954 } 1955 file = 0; 1956 1957#ifdef _WIN32 1958 if (isalpha (*url) && 1959 url[1] == ':' && 1960 (url[2] == '/' || url[2] == '\\')) 1961 goto absolute_path; 1962#endif 1963 1964 switch (*url) { 1965 case '~': 1966 dir = FcConfigHome (); 1967 if (dir) 1968 file = FcConfigFileExists (dir, url + 1); 1969 else 1970 file = 0; 1971 break; 1972#ifdef _WIN32 1973 case '\\': 1974 absolute_path: 1975#endif 1976 case '/': 1977 file = FcConfigFileExists (0, url); 1978 break; 1979 default: 1980 path = FcConfigGetPath (); 1981 if (!path) 1982 return NULL; 1983 for (p = path; *p; p++) 1984 { 1985 file = FcConfigFileExists (*p, url); 1986 if (file) 1987 break; 1988 } 1989 FcConfigFreePath (path); 1990 break; 1991 } 1992 1993 return file; 1994} 1995 1996/* 1997 * Manage the application-specific fonts 1998 */ 1999 2000FcBool 2001FcConfigAppFontAddFile (FcConfig *config, 2002 const FcChar8 *file) 2003{ 2004 FcFontSet *set; 2005 FcStrSet *subdirs; 2006 FcStrList *sublist; 2007 FcChar8 *subdir; 2008 2009 if (!config) 2010 { 2011 config = FcConfigGetCurrent (); 2012 if (!config) 2013 return FcFalse; 2014 } 2015 2016 subdirs = FcStrSetCreate (); 2017 if (!subdirs) 2018 return FcFalse; 2019 2020 set = FcConfigGetFonts (config, FcSetApplication); 2021 if (!set) 2022 { 2023 set = FcFontSetCreate (); 2024 if (!set) 2025 { 2026 FcStrSetDestroy (subdirs); 2027 return FcFalse; 2028 } 2029 FcConfigSetFonts (config, set, FcSetApplication); 2030 } 2031 2032 if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) 2033 { 2034 FcStrSetDestroy (subdirs); 2035 return FcFalse; 2036 } 2037 if ((sublist = FcStrListCreate (subdirs))) 2038 { 2039 while ((subdir = FcStrListNext (sublist))) 2040 { 2041 FcConfigAppFontAddDir (config, subdir); 2042 } 2043 FcStrListDone (sublist); 2044 } 2045 FcStrSetDestroy (subdirs); 2046 return FcTrue; 2047} 2048 2049FcBool 2050FcConfigAppFontAddDir (FcConfig *config, 2051 const FcChar8 *dir) 2052{ 2053 FcFontSet *set; 2054 FcStrSet *dirs; 2055 2056 if (!config) 2057 { 2058 config = FcConfigGetCurrent (); 2059 if (!config) 2060 return FcFalse; 2061 } 2062 2063 dirs = FcStrSetCreate (); 2064 if (!dirs) 2065 return FcFalse; 2066 2067 set = FcConfigGetFonts (config, FcSetApplication); 2068 if (!set) 2069 { 2070 set = FcFontSetCreate (); 2071 if (!set) 2072 { 2073 FcStrSetDestroy (dirs); 2074 return FcFalse; 2075 } 2076 FcConfigSetFonts (config, set, FcSetApplication); 2077 } 2078 2079 FcStrSetAddFilename (dirs, dir); 2080 2081 if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 2082 { 2083 FcStrSetDestroy (dirs); 2084 return FcFalse; 2085 } 2086 FcStrSetDestroy (dirs); 2087 return FcTrue; 2088} 2089 2090void 2091FcConfigAppFontClear (FcConfig *config) 2092{ 2093 if (!config) 2094 { 2095 config = FcConfigGetCurrent (); 2096 if (!config) 2097 return; 2098 } 2099 2100 FcConfigSetFonts (config, 0, FcSetApplication); 2101} 2102 2103/* 2104 * Manage filename-based font source selectors 2105 */ 2106 2107FcBool 2108FcConfigGlobAdd (FcConfig *config, 2109 const FcChar8 *glob, 2110 FcBool accept) 2111{ 2112 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 2113 2114 return FcStrSetAdd (set, glob); 2115} 2116 2117static FcBool 2118FcConfigGlobMatch (const FcChar8 *glob, 2119 const FcChar8 *string) 2120{ 2121 FcChar8 c; 2122 2123 while ((c = *glob++)) 2124 { 2125 switch (c) { 2126 case '*': 2127 /* short circuit common case */ 2128 if (!*glob) 2129 return FcTrue; 2130 /* short circuit another common case */ 2131 if (strchr ((char *) glob, '*') == 0) 2132 { 2133 size_t l1, l2; 2134 2135 l1 = strlen ((char *) string); 2136 l2 = strlen ((char *) glob); 2137 if (l1 < l2) 2138 return FcFalse; 2139 string += (l1 - l2); 2140 } 2141 while (*string) 2142 { 2143 if (FcConfigGlobMatch (glob, string)) 2144 return FcTrue; 2145 string++; 2146 } 2147 return FcFalse; 2148 case '?': 2149 if (*string++ == '\0') 2150 return FcFalse; 2151 break; 2152 default: 2153 if (*string++ != c) 2154 return FcFalse; 2155 break; 2156 } 2157 } 2158 return *string == '\0'; 2159} 2160 2161static FcBool 2162FcConfigGlobsMatch (const FcStrSet *globs, 2163 const FcChar8 *string) 2164{ 2165 int i; 2166 2167 for (i = 0; i < globs->num; i++) 2168 if (FcConfigGlobMatch (globs->strs[i], string)) 2169 return FcTrue; 2170 return FcFalse; 2171} 2172 2173FcBool 2174FcConfigAcceptFilename (FcConfig *config, 2175 const FcChar8 *filename) 2176{ 2177 if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 2178 return FcTrue; 2179 if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 2180 return FcFalse; 2181 return FcTrue; 2182} 2183 2184/* 2185 * Manage font-pattern based font source selectors 2186 */ 2187 2188FcBool 2189FcConfigPatternsAdd (FcConfig *config, 2190 FcPattern *pattern, 2191 FcBool accept) 2192{ 2193 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 2194 2195 return FcFontSetAdd (set, pattern); 2196} 2197 2198static FcBool 2199FcConfigPatternsMatch (const FcFontSet *patterns, 2200 const FcPattern *font) 2201{ 2202 int i; 2203 2204 for (i = 0; i < patterns->nfont; i++) 2205 if (FcListPatternMatchAny (patterns->fonts[i], font)) 2206 return FcTrue; 2207 return FcFalse; 2208} 2209 2210FcBool 2211FcConfigAcceptFont (FcConfig *config, 2212 const FcPattern *font) 2213{ 2214 if (FcConfigPatternsMatch (config->acceptPatterns, font)) 2215 return FcTrue; 2216 if (FcConfigPatternsMatch (config->rejectPatterns, font)) 2217 return FcFalse; 2218 return FcTrue; 2219} 2220#define __fccfg__ 2221#include "fcaliastail.h" 2222#undef __fccfg__ 2223