fccfg.c revision a6844aab
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 Keith Packard not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. Keith Packard makes 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 ((char *) 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 (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 701 left = FcConfigPromote (left, right); 702 right = FcConfigPromote (right, left); 703 if (left.type == right.type) 704 { 705 switch (left.type) { 706 case FcTypeInteger: 707 break; /* FcConfigPromote prevents this from happening */ 708 case FcTypeDouble: 709 switch (op) { 710 case FcOpEqual: 711 case FcOpContains: 712 case FcOpListing: 713 ret = left.u.d == right.u.d; 714 break; 715 case FcOpNotEqual: 716 case FcOpNotContains: 717 ret = left.u.d != right.u.d; 718 break; 719 case FcOpLess: 720 ret = left.u.d < right.u.d; 721 break; 722 case FcOpLessEqual: 723 ret = left.u.d <= right.u.d; 724 break; 725 case FcOpMore: 726 ret = left.u.d > right.u.d; 727 break; 728 case FcOpMoreEqual: 729 ret = left.u.d >= right.u.d; 730 break; 731 default: 732 break; 733 } 734 break; 735 case FcTypeBool: 736 switch (op) { 737 case FcOpEqual: 738 case FcOpContains: 739 case FcOpListing: 740 ret = left.u.b == right.u.b; 741 break; 742 case FcOpNotEqual: 743 case FcOpNotContains: 744 ret = left.u.b != right.u.b; 745 break; 746 default: 747 break; 748 } 749 break; 750 case FcTypeString: 751 switch (op) { 752 case FcOpEqual: 753 case FcOpListing: 754 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 755 break; 756 case FcOpContains: 757 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 758 break; 759 case FcOpNotEqual: 760 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 761 break; 762 case FcOpNotContains: 763 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 764 break; 765 default: 766 break; 767 } 768 break; 769 case FcTypeMatrix: 770 switch (op) { 771 case FcOpEqual: 772 case FcOpContains: 773 case FcOpListing: 774 ret = FcMatrixEqual (left.u.m, right.u.m); 775 break; 776 case FcOpNotEqual: 777 case FcOpNotContains: 778 ret = !FcMatrixEqual (left.u.m, right.u.m); 779 break; 780 default: 781 break; 782 } 783 break; 784 case FcTypeCharSet: 785 switch (op) { 786 case FcOpContains: 787 case FcOpListing: 788 /* left contains right if right is a subset of left */ 789 ret = FcCharSetIsSubset (right.u.c, left.u.c); 790 break; 791 case FcOpNotContains: 792 /* left contains right if right is a subset of left */ 793 ret = !FcCharSetIsSubset (right.u.c, left.u.c); 794 break; 795 case FcOpEqual: 796 ret = FcCharSetEqual (left.u.c, right.u.c); 797 break; 798 case FcOpNotEqual: 799 ret = !FcCharSetEqual (left.u.c, right.u.c); 800 break; 801 default: 802 break; 803 } 804 break; 805 case FcTypeLangSet: 806 switch (op) { 807 case FcOpContains: 808 case FcOpListing: 809 ret = FcLangSetContains (left.u.l, right.u.l); 810 break; 811 case FcOpNotContains: 812 ret = !FcLangSetContains (left.u.l, right.u.l); 813 break; 814 case FcOpEqual: 815 ret = FcLangSetEqual (left.u.l, right.u.l); 816 break; 817 case FcOpNotEqual: 818 ret = !FcLangSetEqual (left.u.l, right.u.l); 819 break; 820 default: 821 break; 822 } 823 break; 824 case FcTypeVoid: 825 switch (op) { 826 case FcOpEqual: 827 case FcOpContains: 828 case FcOpListing: 829 ret = FcTrue; 830 break; 831 default: 832 break; 833 } 834 break; 835 case FcTypeFTFace: 836 switch (op) { 837 case FcOpEqual: 838 case FcOpContains: 839 case FcOpListing: 840 ret = left.u.f == right.u.f; 841 break; 842 case FcOpNotEqual: 843 case FcOpNotContains: 844 ret = left.u.f != right.u.f; 845 break; 846 default: 847 break; 848 } 849 break; 850 } 851 } 852 else 853 { 854 if (op == FcOpNotEqual || op == FcOpNotContains) 855 ret = FcTrue; 856 } 857 return ret; 858} 859 860 861#define _FcDoubleFloor(d) ((int) (d)) 862#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 863#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 864#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 865#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 866#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 867 868static FcValue 869FcConfigEvaluate (FcPattern *p, FcExpr *e) 870{ 871 FcValue v, vl, vr; 872 FcResult r; 873 FcMatrix *m; 874 FcChar8 *str; 875 876 switch (e->op) { 877 case FcOpInteger: 878 v.type = FcTypeInteger; 879 v.u.i = e->u.ival; 880 break; 881 case FcOpDouble: 882 v.type = FcTypeDouble; 883 v.u.d = e->u.dval; 884 break; 885 case FcOpString: 886 v.type = FcTypeString; 887 v.u.s = e->u.sval; 888 v = FcValueSave (v); 889 break; 890 case FcOpMatrix: 891 v.type = FcTypeMatrix; 892 v.u.m = e->u.mval; 893 v = FcValueSave (v); 894 break; 895 case FcOpCharSet: 896 v.type = FcTypeCharSet; 897 v.u.c = e->u.cval; 898 v = FcValueSave (v); 899 break; 900 case FcOpBool: 901 v.type = FcTypeBool; 902 v.u.b = e->u.bval; 903 break; 904 case FcOpField: 905 r = FcPatternObjectGet (p, e->u.object, 0, &v); 906 if (r != FcResultMatch) 907 v.type = FcTypeVoid; 908 v = FcValueSave (v); 909 break; 910 case FcOpConst: 911 if (FcNameConstant (e->u.constant, &v.u.i)) 912 v.type = FcTypeInteger; 913 else 914 v.type = FcTypeVoid; 915 break; 916 case FcOpQuest: 917 vl = FcConfigEvaluate (p, e->u.tree.left); 918 if (vl.type == FcTypeBool) 919 { 920 if (vl.u.b) 921 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left); 922 else 923 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right); 924 } 925 else 926 v.type = FcTypeVoid; 927 FcValueDestroy (vl); 928 break; 929 case FcOpEqual: 930 case FcOpNotEqual: 931 case FcOpLess: 932 case FcOpLessEqual: 933 case FcOpMore: 934 case FcOpMoreEqual: 935 case FcOpContains: 936 case FcOpNotContains: 937 case FcOpListing: 938 vl = FcConfigEvaluate (p, e->u.tree.left); 939 vr = FcConfigEvaluate (p, e->u.tree.right); 940 v.type = FcTypeBool; 941 v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 942 FcValueDestroy (vl); 943 FcValueDestroy (vr); 944 break; 945 case FcOpOr: 946 case FcOpAnd: 947 case FcOpPlus: 948 case FcOpMinus: 949 case FcOpTimes: 950 case FcOpDivide: 951 vl = FcConfigEvaluate (p, e->u.tree.left); 952 vr = FcConfigEvaluate (p, e->u.tree.right); 953 vl = FcConfigPromote (vl, vr); 954 vr = FcConfigPromote (vr, vl); 955 if (vl.type == vr.type) 956 { 957 switch (vl.type) { 958 case FcTypeDouble: 959 switch (e->op) { 960 case FcOpPlus: 961 v.type = FcTypeDouble; 962 v.u.d = vl.u.d + vr.u.d; 963 break; 964 case FcOpMinus: 965 v.type = FcTypeDouble; 966 v.u.d = vl.u.d - vr.u.d; 967 break; 968 case FcOpTimes: 969 v.type = FcTypeDouble; 970 v.u.d = vl.u.d * vr.u.d; 971 break; 972 case FcOpDivide: 973 v.type = FcTypeDouble; 974 v.u.d = vl.u.d / vr.u.d; 975 break; 976 default: 977 v.type = FcTypeVoid; 978 break; 979 } 980 if (v.type == FcTypeDouble && 981 v.u.d == (double) (int) v.u.d) 982 { 983 v.type = FcTypeInteger; 984 v.u.i = (int) v.u.d; 985 } 986 break; 987 case FcTypeBool: 988 switch (e->op) { 989 case FcOpOr: 990 v.type = FcTypeBool; 991 v.u.b = vl.u.b || vr.u.b; 992 break; 993 case FcOpAnd: 994 v.type = FcTypeBool; 995 v.u.b = vl.u.b && vr.u.b; 996 break; 997 default: 998 v.type = FcTypeVoid; 999 break; 1000 } 1001 break; 1002 case FcTypeString: 1003 switch (e->op) { 1004 case FcOpPlus: 1005 v.type = FcTypeString; 1006 str = FcStrPlus (vl.u.s, vr.u.s); 1007 v.u.s = FcStrStaticName (str); 1008 FcStrFree (str); 1009 1010 if (!v.u.s) 1011 v.type = FcTypeVoid; 1012 break; 1013 default: 1014 v.type = FcTypeVoid; 1015 break; 1016 } 1017 break; 1018 case FcTypeMatrix: 1019 switch (e->op) { 1020 case FcOpTimes: 1021 v.type = FcTypeMatrix; 1022 m = malloc (sizeof (FcMatrix)); 1023 if (m) 1024 { 1025 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix)); 1026 FcMatrixMultiply (m, vl.u.m, vr.u.m); 1027 v.u.m = m; 1028 } 1029 else 1030 { 1031 v.type = FcTypeVoid; 1032 } 1033 break; 1034 default: 1035 v.type = FcTypeVoid; 1036 break; 1037 } 1038 break; 1039 default: 1040 v.type = FcTypeVoid; 1041 break; 1042 } 1043 } 1044 else 1045 v.type = FcTypeVoid; 1046 FcValueDestroy (vl); 1047 FcValueDestroy (vr); 1048 break; 1049 case FcOpNot: 1050 vl = FcConfigEvaluate (p, e->u.tree.left); 1051 switch (vl.type) { 1052 case FcTypeBool: 1053 v.type = FcTypeBool; 1054 v.u.b = !vl.u.b; 1055 break; 1056 default: 1057 v.type = FcTypeVoid; 1058 break; 1059 } 1060 FcValueDestroy (vl); 1061 break; 1062 case FcOpFloor: 1063 vl = FcConfigEvaluate (p, e->u.tree.left); 1064 switch (vl.type) { 1065 case FcTypeInteger: 1066 v = vl; 1067 break; 1068 case FcTypeDouble: 1069 v.type = FcTypeInteger; 1070 v.u.i = FcDoubleFloor (vl.u.d); 1071 break; 1072 default: 1073 v.type = FcTypeVoid; 1074 break; 1075 } 1076 FcValueDestroy (vl); 1077 break; 1078 case FcOpCeil: 1079 vl = FcConfigEvaluate (p, e->u.tree.left); 1080 switch (vl.type) { 1081 case FcTypeInteger: 1082 v = vl; 1083 break; 1084 case FcTypeDouble: 1085 v.type = FcTypeInteger; 1086 v.u.i = FcDoubleCeil (vl.u.d); 1087 break; 1088 default: 1089 v.type = FcTypeVoid; 1090 break; 1091 } 1092 FcValueDestroy (vl); 1093 break; 1094 case FcOpRound: 1095 vl = FcConfigEvaluate (p, e->u.tree.left); 1096 switch (vl.type) { 1097 case FcTypeInteger: 1098 v = vl; 1099 break; 1100 case FcTypeDouble: 1101 v.type = FcTypeInteger; 1102 v.u.i = FcDoubleRound (vl.u.d); 1103 break; 1104 default: 1105 v.type = FcTypeVoid; 1106 break; 1107 } 1108 FcValueDestroy (vl); 1109 break; 1110 case FcOpTrunc: 1111 vl = FcConfigEvaluate (p, e->u.tree.left); 1112 switch (vl.type) { 1113 case FcTypeInteger: 1114 v = vl; 1115 break; 1116 case FcTypeDouble: 1117 v.type = FcTypeInteger; 1118 v.u.i = FcDoubleTrunc (vl.u.d); 1119 break; 1120 default: 1121 v.type = FcTypeVoid; 1122 break; 1123 } 1124 FcValueDestroy (vl); 1125 break; 1126 default: 1127 v.type = FcTypeVoid; 1128 break; 1129 } 1130 return v; 1131} 1132 1133static FcValueList * 1134FcConfigMatchValueList (FcPattern *p, 1135 FcTest *t, 1136 FcValueList *values) 1137{ 1138 FcValueList *ret = 0; 1139 FcExpr *e = t->expr; 1140 FcValue value; 1141 FcValueList *v; 1142 1143 while (e) 1144 { 1145 /* Compute the value of the match expression */ 1146 if (e->op == FcOpComma) 1147 { 1148 value = FcConfigEvaluate (p, e->u.tree.left); 1149 e = e->u.tree.right; 1150 } 1151 else 1152 { 1153 value = FcConfigEvaluate (p, e); 1154 e = 0; 1155 } 1156 1157 for (v = values; v; v = FcValueListNext(v)) 1158 { 1159 /* Compare the pattern value to the match expression value */ 1160 if (FcConfigCompareValue (&v->value, t->op, &value)) 1161 { 1162 if (!ret) 1163 ret = v; 1164 } 1165 else 1166 { 1167 if (t->qual == FcQualAll) 1168 { 1169 ret = 0; 1170 break; 1171 } 1172 } 1173 } 1174 FcValueDestroy (value); 1175 } 1176 return ret; 1177} 1178 1179static FcValueList * 1180FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding) 1181{ 1182 FcValueList *l; 1183 1184 if (!e) 1185 return 0; 1186 l = (FcValueList *) malloc (sizeof (FcValueList)); 1187 if (!l) 1188 return 0; 1189 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); 1190 if (e->op == FcOpComma) 1191 { 1192 l->value = FcConfigEvaluate (p, e->u.tree.left); 1193 l->next = FcConfigValues (p, e->u.tree.right, binding); 1194 } 1195 else 1196 { 1197 l->value = FcConfigEvaluate (p, e); 1198 l->next = NULL; 1199 } 1200 l->binding = binding; 1201 if (l->value.type == FcTypeVoid) 1202 { 1203 FcValueList *next = FcValueListNext(l); 1204 1205 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); 1206 free (l); 1207 l = next; 1208 } 1209 1210 return l; 1211} 1212 1213static FcBool 1214FcConfigAdd (FcValueListPtr *head, 1215 FcValueList *position, 1216 FcBool append, 1217 FcValueList *new) 1218{ 1219 FcValueListPtr *prev, last, v; 1220 FcValueBinding sameBinding; 1221 1222 if (position) 1223 sameBinding = position->binding; 1224 else 1225 sameBinding = FcValueBindingWeak; 1226 for (v = new; v != NULL; v = FcValueListNext(v)) 1227 if (v->binding == FcValueBindingSame) 1228 v->binding = sameBinding; 1229 if (append) 1230 { 1231 if (position) 1232 prev = &position->next; 1233 else 1234 for (prev = head; *prev != NULL; 1235 prev = &(*prev)->next) 1236 ; 1237 } 1238 else 1239 { 1240 if (position) 1241 { 1242 for (prev = head; *prev != NULL; 1243 prev = &(*prev)->next) 1244 { 1245 if (*prev == position) 1246 break; 1247 } 1248 } 1249 else 1250 prev = head; 1251 1252 if (FcDebug () & FC_DBG_EDIT) 1253 { 1254 if (*prev == NULL) 1255 printf ("position not on list\n"); 1256 } 1257 } 1258 1259 if (FcDebug () & FC_DBG_EDIT) 1260 { 1261 printf ("%s list before ", append ? "Append" : "Prepend"); 1262 FcValueListPrint (*head); 1263 printf ("\n"); 1264 } 1265 1266 if (new) 1267 { 1268 last = new; 1269 while (last->next != NULL) 1270 last = last->next; 1271 1272 last->next = *prev; 1273 *prev = new; 1274 } 1275 1276 if (FcDebug () & FC_DBG_EDIT) 1277 { 1278 printf ("%s list after ", append ? "Append" : "Prepend"); 1279 FcValueListPrint (*head); 1280 printf ("\n"); 1281 } 1282 1283 return FcTrue; 1284} 1285 1286static void 1287FcConfigDel (FcValueListPtr *head, 1288 FcValueList *position) 1289{ 1290 FcValueListPtr *prev; 1291 1292 for (prev = head; *prev != NULL; prev = &(*prev)->next) 1293 { 1294 if (*prev == position) 1295 { 1296 *prev = position->next; 1297 position->next = NULL; 1298 FcValueListDestroy (position); 1299 break; 1300 } 1301 } 1302} 1303 1304static void 1305FcConfigPatternAdd (FcPattern *p, 1306 FcObject object, 1307 FcValueList *list, 1308 FcBool append) 1309{ 1310 if (list) 1311 { 1312 FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1313 1314 if (!e) 1315 return; 1316 FcConfigAdd (&e->values, 0, append, list); 1317 } 1318} 1319 1320/* 1321 * Delete all values associated with a field 1322 */ 1323static void 1324FcConfigPatternDel (FcPattern *p, 1325 FcObject object) 1326{ 1327 FcPatternElt *e = FcPatternObjectFindElt (p, object); 1328 if (!e) 1329 return; 1330 while (e->values != NULL) 1331 FcConfigDel (&e->values, e->values); 1332} 1333 1334static void 1335FcConfigPatternCanon (FcPattern *p, 1336 FcObject object) 1337{ 1338 FcPatternElt *e = FcPatternObjectFindElt (p, object); 1339 if (!e) 1340 return; 1341 if (e->values == NULL) 1342 FcPatternObjectDel (p, object); 1343} 1344 1345FcBool 1346FcConfigSubstituteWithPat (FcConfig *config, 1347 FcPattern *p, 1348 FcPattern *p_pat, 1349 FcMatchKind kind) 1350{ 1351 FcSubst *s; 1352 FcSubState *st; 1353 int i; 1354 FcTest *t; 1355 FcEdit *e; 1356 FcValueList *l; 1357 FcPattern *m; 1358 1359 if (!config) 1360 { 1361 config = FcConfigGetCurrent (); 1362 if (!config) 1363 return FcFalse; 1364 } 1365 1366 switch (kind) { 1367 case FcMatchPattern: 1368 s = config->substPattern; 1369 break; 1370 case FcMatchFont: 1371 s = config->substFont; 1372 break; 1373 case FcMatchScan: 1374 s = config->substScan; 1375 break; 1376 default: 1377 return FcFalse; 1378 } 1379 1380 st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState)); 1381 if (!st && config->maxObjects) 1382 return FcFalse; 1383 FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 1384 1385 if (FcDebug () & FC_DBG_EDIT) 1386 { 1387 printf ("FcConfigSubstitute "); 1388 FcPatternPrint (p); 1389 } 1390 for (; s; s = s->next) 1391 { 1392 /* 1393 * Check the tests to see if 1394 * they all match the pattern 1395 */ 1396 for (t = s->test, i = 0; t; t = t->next, i++) 1397 { 1398 if (FcDebug () & FC_DBG_EDIT) 1399 { 1400 printf ("FcConfigSubstitute test "); 1401 FcTestPrint (t); 1402 } 1403 st[i].elt = 0; 1404 if (kind == FcMatchFont && t->kind == FcMatchPattern) 1405 m = p_pat; 1406 else 1407 m = p; 1408 if (m) 1409 st[i].elt = FcPatternObjectFindElt (m, t->object); 1410 else 1411 st[i].elt = 0; 1412 /* 1413 * If there's no such field in the font, 1414 * then FcQualAll matches while FcQualAny does not 1415 */ 1416 if (!st[i].elt) 1417 { 1418 if (t->qual == FcQualAll) 1419 { 1420 st[i].value = 0; 1421 continue; 1422 } 1423 else 1424 break; 1425 } 1426 /* 1427 * Check to see if there is a match, mark the location 1428 * to apply match-relative edits 1429 */ 1430 st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values); 1431 if (!st[i].value) 1432 break; 1433 if (t->qual == FcQualFirst && st[i].value != st[i].elt->values) 1434 break; 1435 if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values) 1436 break; 1437 } 1438 if (t) 1439 { 1440 if (FcDebug () & FC_DBG_EDIT) 1441 printf ("No match\n"); 1442 continue; 1443 } 1444 if (FcDebug () & FC_DBG_EDIT) 1445 { 1446 printf ("Substitute "); 1447 FcSubstPrint (s); 1448 } 1449 for (e = s->edit; e; e = e->next) 1450 { 1451 /* 1452 * Evaluate the list of expressions 1453 */ 1454 l = FcConfigValues (p, e->expr, e->binding); 1455 /* 1456 * Locate any test associated with this field, skipping 1457 * tests associated with the pattern when substituting in 1458 * the font 1459 */ 1460 for (t = s->test, i = 0; t; t = t->next, i++) 1461 { 1462 if ((t->kind == FcMatchFont || kind == FcMatchPattern) && 1463 t->object == e->object) 1464 { 1465 /* 1466 * KLUDGE - the pattern may have been reallocated or 1467 * things may have been inserted or deleted above 1468 * this element by other edits. Go back and find 1469 * the element again 1470 */ 1471 if (e != s->edit && st[i].elt) 1472 st[i].elt = FcPatternObjectFindElt (p, t->object); 1473 if (!st[i].elt) 1474 t = 0; 1475 break; 1476 } 1477 } 1478 switch (e->op) { 1479 case FcOpAssign: 1480 /* 1481 * If there was a test, then replace the matched 1482 * value with the new list of values 1483 */ 1484 if (t) 1485 { 1486 FcValueList *thisValue = st[i].value; 1487 FcValueList *nextValue = thisValue; 1488 1489 /* 1490 * Append the new list of values after the current value 1491 */ 1492 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l); 1493 /* 1494 * Delete the marked value 1495 */ 1496 if (thisValue) 1497 FcConfigDel (&st[i].elt->values, thisValue); 1498 /* 1499 * Adjust any pointers into the value list to ensure 1500 * future edits occur at the same place 1501 */ 1502 for (t = s->test, i = 0; t; t = t->next, i++) 1503 { 1504 if (st[i].value == thisValue) 1505 st[i].value = nextValue; 1506 } 1507 break; 1508 } 1509 /* fall through ... */ 1510 case FcOpAssignReplace: 1511 /* 1512 * Delete all of the values and insert 1513 * the new set 1514 */ 1515 FcConfigPatternDel (p, e->object); 1516 FcConfigPatternAdd (p, e->object, l, FcTrue); 1517 /* 1518 * Adjust any pointers into the value list as they no 1519 * longer point to anything valid 1520 */ 1521 if (t) 1522 { 1523 FcPatternElt *thisElt = st[i].elt; 1524 for (t = s->test, i = 0; t; t = t->next, i++) 1525 { 1526 if (st[i].elt == thisElt) 1527 st[i].value = 0; 1528 } 1529 } 1530 break; 1531 case FcOpPrepend: 1532 if (t) 1533 { 1534 FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l); 1535 break; 1536 } 1537 /* fall through ... */ 1538 case FcOpPrependFirst: 1539 FcConfigPatternAdd (p, e->object, l, FcFalse); 1540 break; 1541 case FcOpAppend: 1542 if (t) 1543 { 1544 FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l); 1545 break; 1546 } 1547 /* fall through ... */ 1548 case FcOpAppendLast: 1549 FcConfigPatternAdd (p, e->object, l, FcTrue); 1550 break; 1551 default: 1552 FcValueListDestroy (l); 1553 break; 1554 } 1555 } 1556 /* 1557 * Now go through the pattern and eliminate 1558 * any properties without data 1559 */ 1560 for (e = s->edit; e; e = e->next) 1561 FcConfigPatternCanon (p, e->object); 1562 1563 if (FcDebug () & FC_DBG_EDIT) 1564 { 1565 printf ("FcConfigSubstitute edit"); 1566 FcPatternPrint (p); 1567 } 1568 } 1569 FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 1570 free (st); 1571 if (FcDebug () & FC_DBG_EDIT) 1572 { 1573 printf ("FcConfigSubstitute done"); 1574 FcPatternPrint (p); 1575 } 1576 return FcTrue; 1577} 1578 1579FcBool 1580FcConfigSubstitute (FcConfig *config, 1581 FcPattern *p, 1582 FcMatchKind kind) 1583{ 1584 return FcConfigSubstituteWithPat (config, p, 0, kind); 1585} 1586 1587#if defined (_WIN32) 1588 1589# define WIN32_LEAN_AND_MEAN 1590# define WIN32_EXTRA_LEAN 1591# include <windows.h> 1592 1593static FcChar8 fontconfig_path[1000] = ""; 1594 1595# if (defined (PIC) || defined (DLL_EXPORT)) 1596 1597BOOL WINAPI 1598DllMain (HINSTANCE hinstDLL, 1599 DWORD fdwReason, 1600 LPVOID lpvReserved) 1601{ 1602 FcChar8 *p; 1603 1604 switch (fdwReason) { 1605 case DLL_PROCESS_ATTACH: 1606 if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path, 1607 sizeof (fontconfig_path))) 1608 break; 1609 1610 /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 1611 * assume it's a Unix-style installation tree, and use 1612 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 1613 * folder where the DLL is as FONTCONFIG_PATH. 1614 */ 1615 p = strrchr (fontconfig_path, '\\'); 1616 if (p) 1617 { 1618 *p = '\0'; 1619 p = strrchr (fontconfig_path, '\\'); 1620 if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 || 1621 FcStrCmpIgnoreCase (p + 1, "lib") == 0)) 1622 *p = '\0'; 1623 strcat (fontconfig_path, "\\etc\\fonts"); 1624 } 1625 else 1626 fontconfig_path[0] = '\0'; 1627 1628 break; 1629 } 1630 1631 return TRUE; 1632} 1633 1634# endif /* !PIC */ 1635 1636#undef FONTCONFIG_PATH 1637#define FONTCONFIG_PATH fontconfig_path 1638 1639#endif /* !_WIN32 */ 1640 1641#ifndef FONTCONFIG_FILE 1642#define FONTCONFIG_FILE "fonts.conf" 1643#endif 1644 1645static FcChar8 * 1646FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 1647{ 1648 FcChar8 *path; 1649 1650 if (!dir) 1651 dir = (FcChar8 *) ""; 1652 path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1); 1653 if (!path) 1654 return 0; 1655 1656 strcpy ((char *) path, (const char *) dir); 1657 /* make sure there's a single separator */ 1658#ifdef _WIN32 1659 if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 1660 path[strlen((char *) path)-1] != '\\')) && 1661 !(file[0] == '/' || 1662 file[0] == '\\' || 1663 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 1664 strcat ((char *) path, "\\"); 1665#else 1666 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 1667 strcat ((char *) path, "/"); 1668#endif 1669 strcat ((char *) path, (char *) file); 1670 1671 FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1); 1672 if (access ((char *) path, R_OK) == 0) 1673 return path; 1674 1675 FcStrFree (path); 1676 return 0; 1677} 1678 1679static FcChar8 ** 1680FcConfigGetPath (void) 1681{ 1682 FcChar8 **path; 1683 FcChar8 *env, *e, *colon; 1684 FcChar8 *dir; 1685 int npath; 1686 int i; 1687 1688 npath = 2; /* default dir + null */ 1689 env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 1690 if (env) 1691 { 1692 e = env; 1693 npath++; 1694 while (*e) 1695 if (*e++ == FC_SEARCH_PATH_SEPARATOR) 1696 npath++; 1697 } 1698 path = calloc (npath, sizeof (FcChar8 *)); 1699 if (!path) 1700 goto bail0; 1701 i = 0; 1702 1703 if (env) 1704 { 1705 e = env; 1706 while (*e) 1707 { 1708 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 1709 if (!colon) 1710 colon = e + strlen ((char *) e); 1711 path[i] = malloc (colon - e + 1); 1712 if (!path[i]) 1713 goto bail1; 1714 strncpy ((char *) path[i], (const char *) e, colon - e); 1715 path[i][colon - e] = '\0'; 1716 if (*colon) 1717 e = colon + 1; 1718 else 1719 e = colon; 1720 i++; 1721 } 1722 } 1723 1724#ifdef _WIN32 1725 if (fontconfig_path[0] == '\0') 1726 { 1727 char *p; 1728 if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path))) 1729 goto bail1; 1730 p = strrchr (fontconfig_path, '\\'); 1731 if (p) *p = '\0'; 1732 strcat (fontconfig_path, "\\fonts"); 1733 } 1734#endif 1735 dir = (FcChar8 *) FONTCONFIG_PATH; 1736 path[i] = malloc (strlen ((char *) dir) + 1); 1737 if (!path[i]) 1738 goto bail1; 1739 strcpy ((char *) path[i], (const char *) dir); 1740 return path; 1741 1742bail1: 1743 for (i = 0; path[i]; i++) 1744 free (path[i]); 1745 free (path); 1746bail0: 1747 return 0; 1748} 1749 1750static void 1751FcConfigFreePath (FcChar8 **path) 1752{ 1753 FcChar8 **p; 1754 1755 for (p = path; *p; p++) 1756 free (*p); 1757 free (path); 1758} 1759 1760static FcBool _FcConfigHomeEnabled = FcTrue; 1761 1762FcChar8 * 1763FcConfigHome (void) 1764{ 1765 if (_FcConfigHomeEnabled) 1766 { 1767 char *home = getenv ("HOME"); 1768 1769#ifdef _WIN32 1770 if (home == NULL) 1771 home = getenv ("USERPROFILE"); 1772#endif 1773 1774 return (FcChar8 *) home; 1775 } 1776 return 0; 1777} 1778 1779FcBool 1780FcConfigEnableHome (FcBool enable) 1781{ 1782 FcBool prev = _FcConfigHomeEnabled; 1783 _FcConfigHomeEnabled = enable; 1784 return prev; 1785} 1786 1787FcChar8 * 1788FcConfigFilename (const FcChar8 *url) 1789{ 1790 FcChar8 *file, *dir, **path, **p; 1791 1792 if (!url || !*url) 1793 { 1794 url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 1795 if (!url) 1796 url = (FcChar8 *) FONTCONFIG_FILE; 1797 } 1798 file = 0; 1799 1800#ifdef _WIN32 1801 if (isalpha (*url) && 1802 url[1] == ':' && 1803 (url[2] == '/' || url[2] == '\\')) 1804 goto absolute_path; 1805#endif 1806 1807 switch (*url) { 1808 case '~': 1809 dir = FcConfigHome (); 1810 if (dir) 1811 file = FcConfigFileExists (dir, url + 1); 1812 else 1813 file = 0; 1814 break; 1815#ifdef _WIN32 1816 case '\\': 1817 absolute_path: 1818#endif 1819 case '/': 1820 file = FcConfigFileExists (0, url); 1821 break; 1822 default: 1823 path = FcConfigGetPath (); 1824 if (!path) 1825 return 0; 1826 for (p = path; *p; p++) 1827 { 1828 file = FcConfigFileExists (*p, url); 1829 if (file) 1830 break; 1831 } 1832 FcConfigFreePath (path); 1833 break; 1834 } 1835 return file; 1836} 1837 1838/* 1839 * Manage the application-specific fonts 1840 */ 1841 1842FcBool 1843FcConfigAppFontAddFile (FcConfig *config, 1844 const FcChar8 *file) 1845{ 1846 FcFontSet *set; 1847 FcStrSet *subdirs; 1848 FcStrList *sublist; 1849 FcChar8 *subdir; 1850 1851 if (!config) 1852 { 1853 config = FcConfigGetCurrent (); 1854 if (!config) 1855 return FcFalse; 1856 } 1857 1858 subdirs = FcStrSetCreate (); 1859 if (!subdirs) 1860 return FcFalse; 1861 1862 set = FcConfigGetFonts (config, FcSetApplication); 1863 if (!set) 1864 { 1865 set = FcFontSetCreate (); 1866 if (!set) 1867 { 1868 FcStrSetDestroy (subdirs); 1869 return FcFalse; 1870 } 1871 FcConfigSetFonts (config, set, FcSetApplication); 1872 } 1873 1874 if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) 1875 { 1876 FcStrSetDestroy (subdirs); 1877 return FcFalse; 1878 } 1879 if ((sublist = FcStrListCreate (subdirs))) 1880 { 1881 while ((subdir = FcStrListNext (sublist))) 1882 { 1883 FcConfigAppFontAddDir (config, subdir); 1884 } 1885 FcStrListDone (sublist); 1886 } 1887 FcStrSetDestroy (subdirs); 1888 return FcTrue; 1889} 1890 1891FcBool 1892FcConfigAppFontAddDir (FcConfig *config, 1893 const FcChar8 *dir) 1894{ 1895 FcFontSet *set; 1896 FcStrSet *dirs; 1897 1898 if (!config) 1899 { 1900 config = FcConfigGetCurrent (); 1901 if (!config) 1902 return FcFalse; 1903 } 1904 1905 dirs = FcStrSetCreate (); 1906 if (!dirs) 1907 return FcFalse; 1908 1909 set = FcConfigGetFonts (config, FcSetApplication); 1910 if (!set) 1911 { 1912 set = FcFontSetCreate (); 1913 if (!set) 1914 { 1915 FcStrSetDestroy (dirs); 1916 return FcFalse; 1917 } 1918 FcConfigSetFonts (config, set, FcSetApplication); 1919 } 1920 1921 FcStrSetAddFilename (dirs, dir); 1922 1923 if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 1924 { 1925 FcStrSetDestroy (dirs); 1926 return FcFalse; 1927 } 1928 FcStrSetDestroy (dirs); 1929 return FcTrue; 1930} 1931 1932void 1933FcConfigAppFontClear (FcConfig *config) 1934{ 1935 if (!config) 1936 { 1937 config = FcConfigGetCurrent (); 1938 if (!config) 1939 return; 1940 } 1941 1942 FcConfigSetFonts (config, 0, FcSetApplication); 1943} 1944 1945/* 1946 * Manage filename-based font source selectors 1947 */ 1948 1949FcBool 1950FcConfigGlobAdd (FcConfig *config, 1951 const FcChar8 *glob, 1952 FcBool accept) 1953{ 1954 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 1955 1956 return FcStrSetAdd (set, glob); 1957} 1958 1959static FcBool 1960FcConfigGlobMatch (const FcChar8 *glob, 1961 const FcChar8 *string) 1962{ 1963 FcChar8 c; 1964 1965 while ((c = *glob++)) 1966 { 1967 switch (c) { 1968 case '*': 1969 /* short circuit common case */ 1970 if (!*glob) 1971 return FcTrue; 1972 /* short circuit another common case */ 1973 if (strchr ((char *) glob, '*') == 0) 1974 string += strlen ((char *) string) - strlen ((char *) glob); 1975 while (*string) 1976 { 1977 if (FcConfigGlobMatch (glob, string)) 1978 return FcTrue; 1979 string++; 1980 } 1981 return FcFalse; 1982 case '?': 1983 if (*string++ == '\0') 1984 return FcFalse; 1985 break; 1986 default: 1987 if (*string++ != c) 1988 return FcFalse; 1989 break; 1990 } 1991 } 1992 return *string == '\0'; 1993} 1994 1995static FcBool 1996FcConfigGlobsMatch (const FcStrSet *globs, 1997 const FcChar8 *string) 1998{ 1999 int i; 2000 2001 for (i = 0; i < globs->num; i++) 2002 if (FcConfigGlobMatch (globs->strs[i], string)) 2003 return FcTrue; 2004 return FcFalse; 2005} 2006 2007FcBool 2008FcConfigAcceptFilename (FcConfig *config, 2009 const FcChar8 *filename) 2010{ 2011 if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 2012 return FcTrue; 2013 if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 2014 return FcFalse; 2015 return FcTrue; 2016} 2017 2018/* 2019 * Manage font-pattern based font source selectors 2020 */ 2021 2022FcBool 2023FcConfigPatternsAdd (FcConfig *config, 2024 FcPattern *pattern, 2025 FcBool accept) 2026{ 2027 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 2028 2029 return FcFontSetAdd (set, pattern); 2030} 2031 2032static FcBool 2033FcConfigPatternsMatch (const FcFontSet *patterns, 2034 const FcPattern *font) 2035{ 2036 int i; 2037 2038 for (i = 0; i < patterns->nfont; i++) 2039 if (FcListPatternMatchAny (patterns->fonts[i], font)) 2040 return FcTrue; 2041 return FcFalse; 2042} 2043 2044FcBool 2045FcConfigAcceptFont (FcConfig *config, 2046 const FcPattern *font) 2047{ 2048 if (FcConfigPatternsMatch (config->acceptPatterns, font)) 2049 return FcTrue; 2050 if (FcConfigPatternsMatch (config->rejectPatterns, font)) 2051 return FcFalse; 2052 return FcTrue; 2053} 2054#define __fccfg__ 2055#include "fcaliastail.h" 2056#undef __fccfg__ 2057