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