fccfg.c revision 1887081f
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/* Objects MT-safe for readonly access. */ 26 27#include "fcint.h" 28#include <dirent.h> 29#include <sys/types.h> 30 31#if defined (_WIN32) && !defined (R_OK) 32#define R_OK 4 33#endif 34 35static FcConfig *_fcConfig; /* MT-safe */ 36 37static FcConfig * 38FcConfigEnsure (void) 39{ 40 FcConfig *config; 41retry: 42 config = fc_atomic_ptr_get (&_fcConfig); 43 if (!config) 44 { 45 config = FcInitLoadConfigAndFonts (); 46 47 if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { 48 FcConfigDestroy (config); 49 goto retry; 50 } 51 } 52 return config; 53} 54 55static FcChar32 56FcHashAsStrIgnoreCase (const void *data) 57{ 58 return FcStrHashIgnoreCase (data); 59} 60 61static int 62FcCompareAsStr (const void *v1, const void *v2) 63{ 64 return FcStrCmp (v1, v2); 65} 66 67static void 68FcDestroyAsRule (void *data) 69{ 70 FcRuleDestroy (data); 71} 72 73static void 74FcDestroyAsRuleSet (void *data) 75{ 76 FcRuleSetDestroy (data); 77} 78 79static void 80FcDestroyAsStr (void *data) 81{ 82 FcStrFree (data); 83} 84 85FcBool 86FcConfigInit (void) 87{ 88 return FcConfigEnsure () ? FcTrue : FcFalse; 89} 90 91void 92FcConfigFini (void) 93{ 94 FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); 95 if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) 96 FcConfigDestroy (cfg); 97} 98 99 100FcConfig * 101FcConfigCreate (void) 102{ 103 FcSetName set; 104 FcConfig *config; 105 FcMatchKind k; 106 FcBool err = FcFalse; 107 108 config = malloc (sizeof (FcConfig)); 109 if (!config) 110 goto bail0; 111 112 config->configDirs = FcStrSetCreate (); 113 if (!config->configDirs) 114 goto bail1; 115 116 config->configFiles = FcStrSetCreate (); 117 if (!config->configFiles) 118 goto bail2; 119 120 config->fontDirs = FcStrSetCreate (); 121 if (!config->fontDirs) 122 goto bail3; 123 124 config->acceptGlobs = FcStrSetCreate (); 125 if (!config->acceptGlobs) 126 goto bail4; 127 128 config->rejectGlobs = FcStrSetCreate (); 129 if (!config->rejectGlobs) 130 goto bail5; 131 132 config->acceptPatterns = FcFontSetCreate (); 133 if (!config->acceptPatterns) 134 goto bail6; 135 136 config->rejectPatterns = FcFontSetCreate (); 137 if (!config->rejectPatterns) 138 goto bail7; 139 140 config->cacheDirs = FcStrSetCreate (); 141 if (!config->cacheDirs) 142 goto bail8; 143 144 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 145 { 146 config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet); 147 if (!config->subst[k]) 148 err = FcTrue; 149 } 150 if (err) 151 goto bail9; 152 153 config->maxObjects = 0; 154 for (set = FcSetSystem; set <= FcSetApplication; set++) 155 config->fonts[set] = 0; 156 157 config->rescanTime = time(0); 158 config->rescanInterval = 30; 159 160 config->expr_pool = NULL; 161 162 config->sysRoot = NULL; 163 164 config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet); 165 if (!config->rulesetList) 166 goto bail9; 167 config->availConfigFiles = FcStrSetCreate (); 168 if (!config->availConfigFiles) 169 goto bail10; 170 171 config->uuid_table = FcHashTableCreate (FcHashAsStrIgnoreCase, 172 FcCompareAsStr, 173 FcHashStrCopy, 174 FcHashUuidCopy, 175 FcDestroyAsStr, 176 FcHashUuidFree); 177 178 FcRefInit (&config->ref, 1); 179 180 return config; 181 182bail10: 183 FcPtrListDestroy (config->rulesetList); 184bail9: 185 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 186 if (config->subst[k]) 187 FcPtrListDestroy (config->subst[k]); 188 FcStrSetDestroy (config->cacheDirs); 189bail8: 190 FcFontSetDestroy (config->rejectPatterns); 191bail7: 192 FcFontSetDestroy (config->acceptPatterns); 193bail6: 194 FcStrSetDestroy (config->rejectGlobs); 195bail5: 196 FcStrSetDestroy (config->acceptGlobs); 197bail4: 198 FcStrSetDestroy (config->fontDirs); 199bail3: 200 FcStrSetDestroy (config->configFiles); 201bail2: 202 FcStrSetDestroy (config->configDirs); 203bail1: 204 free (config); 205bail0: 206 return 0; 207} 208 209static FcFileTime 210FcConfigNewestFile (FcStrSet *files) 211{ 212 FcStrList *list = FcStrListCreate (files); 213 FcFileTime newest = { 0, FcFalse }; 214 FcChar8 *file; 215 struct stat statb; 216 217 if (list) 218 { 219 while ((file = FcStrListNext (list))) 220 if (FcStat (file, &statb) == 0) 221 if (!newest.set || statb.st_mtime - newest.time > 0) 222 { 223 newest.set = FcTrue; 224 newest.time = statb.st_mtime; 225 } 226 FcStrListDone (list); 227 } 228 return newest; 229} 230 231FcBool 232FcConfigUptoDate (FcConfig *config) 233{ 234 FcFileTime config_time, config_dir_time, font_time; 235 time_t now = time(0); 236 if (!config) 237 { 238 config = FcConfigGetCurrent (); 239 if (!config) 240 return FcFalse; 241 } 242 config_time = FcConfigNewestFile (config->configFiles); 243 config_dir_time = FcConfigNewestFile (config->configDirs); 244 font_time = FcConfigNewestFile (config->fontDirs); 245 if ((config_time.set && config_time.time - config->rescanTime > 0) || 246 (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 247 (font_time.set && (font_time.time - config->rescanTime) > 0)) 248 { 249 /* We need to check for potential clock problems here (OLPC ticket #6046) */ 250 if ((config_time.set && (config_time.time - now) > 0) || 251 (config_dir_time.set && (config_dir_time.time - now) > 0) || 252 (font_time.set && (font_time.time - now) > 0)) 253 { 254 fprintf (stderr, 255 "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n"); 256 config->rescanTime = now; 257 return FcTrue; 258 } 259 else 260 return FcFalse; 261 } 262 config->rescanTime = now; 263 return FcTrue; 264} 265 266FcExpr * 267FcConfigAllocExpr (FcConfig *config) 268{ 269 if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 270 { 271 FcExprPage *new_page; 272 273 new_page = malloc (sizeof (FcExprPage)); 274 if (!new_page) 275 return 0; 276 277 new_page->next_page = config->expr_pool; 278 new_page->next = new_page->exprs; 279 config->expr_pool = new_page; 280 } 281 282 return config->expr_pool->next++; 283} 284 285FcConfig * 286FcConfigReference (FcConfig *config) 287{ 288 if (!config) 289 { 290 config = FcConfigGetCurrent (); 291 if (!config) 292 return 0; 293 } 294 295 FcRefInc (&config->ref); 296 297 return config; 298} 299 300void 301FcConfigDestroy (FcConfig *config) 302{ 303 FcSetName set; 304 FcExprPage *page; 305 FcMatchKind k; 306 307 if (FcRefDec (&config->ref) != 1) 308 return; 309 310 (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); 311 312 FcStrSetDestroy (config->configDirs); 313 FcStrSetDestroy (config->fontDirs); 314 FcStrSetDestroy (config->cacheDirs); 315 FcStrSetDestroy (config->configFiles); 316 FcStrSetDestroy (config->acceptGlobs); 317 FcStrSetDestroy (config->rejectGlobs); 318 FcFontSetDestroy (config->acceptPatterns); 319 FcFontSetDestroy (config->rejectPatterns); 320 321 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 322 FcPtrListDestroy (config->subst[k]); 323 FcPtrListDestroy (config->rulesetList); 324 FcStrSetDestroy (config->availConfigFiles); 325 for (set = FcSetSystem; set <= FcSetApplication; set++) 326 if (config->fonts[set]) 327 FcFontSetDestroy (config->fonts[set]); 328 329 page = config->expr_pool; 330 while (page) 331 { 332 FcExprPage *next = page->next_page; 333 free (page); 334 page = next; 335 } 336 if (config->sysRoot) 337 FcStrFree (config->sysRoot); 338 339 FcHashTableDestroy (config->uuid_table); 340 341 free (config); 342} 343 344/* 345 * Add cache to configuration, adding fonts and directories 346 */ 347 348FcBool 349FcConfigAddCache (FcConfig *config, FcCache *cache, 350 FcSetName set, FcStrSet *dirSet, FcChar8 *forDir) 351{ 352 FcFontSet *fs; 353 intptr_t *dirs; 354 int i; 355 FcBool relocated = FcFalse; 356 357 if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0) 358 relocated = FcTrue; 359 360 /* 361 * Add fonts 362 */ 363 fs = FcCacheSet (cache); 364 if (fs) 365 { 366 int nref = 0; 367 368 for (i = 0; i < fs->nfont; i++) 369 { 370 FcPattern *font = FcFontSetFont (fs, i); 371 FcChar8 *font_file; 372 FcChar8 *relocated_font_file = NULL; 373 374 if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 375 0, &font_file) == FcResultMatch) 376 { 377 if (relocated) 378 { 379 FcChar8 *slash = FcStrLastSlash (font_file); 380 relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL); 381 font_file = relocated_font_file; 382 } 383 384 /* 385 * Check to see if font is banned by filename 386 */ 387 if (!FcConfigAcceptFilename (config, font_file)) 388 { 389 free (relocated_font_file); 390 continue; 391 } 392 } 393 394 /* 395 * Check to see if font is banned by pattern 396 */ 397 if (!FcConfigAcceptFont (config, font)) 398 { 399 free (relocated_font_file); 400 continue; 401 } 402 403 if (relocated_font_file) 404 { 405 font = FcPatternCacheRewriteFile (font, cache, relocated_font_file); 406 free (relocated_font_file); 407 } 408 409 if (FcFontSetAdd (config->fonts[set], font)) 410 nref++; 411 } 412 FcDirCacheReference (cache, nref); 413 } 414 415 /* 416 * Add directories 417 */ 418 dirs = FcCacheDirs (cache); 419 if (dirs) 420 { 421 for (i = 0; i < cache->dirs_count; i++) 422 { 423 const FcChar8 *dir = FcCacheSubdir (cache, i); 424 FcChar8 *s = NULL; 425 426 if (relocated) 427 { 428 FcChar8 *base = FcStrBasename (dir); 429 dir = s = FcStrBuildFilename (forDir, base, NULL); 430 FcStrFree (base); 431 } 432 if (FcConfigAcceptFilename (config, dir)) 433 FcStrSetAddFilename (dirSet, dir); 434 if (s) 435 FcStrFree (s); 436 } 437 } 438 return FcTrue; 439} 440 441static FcBool 442FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 443{ 444 FcStrList *dirlist; 445 FcChar8 *dir; 446 FcCache *cache; 447 448 dirlist = FcStrListCreate (dirSet); 449 if (!dirlist) 450 return FcFalse; 451 452 while ((dir = FcStrListNext (dirlist))) 453 { 454 if (FcDebug () & FC_DBG_FONTSET) 455 printf ("adding fonts from %s\n", dir); 456 cache = FcDirCacheRead (dir, FcFalse, config); 457 if (!cache) 458 continue; 459 FcConfigAddCache (config, cache, set, dirSet, dir); 460 FcDirCacheUnload (cache); 461 } 462 FcStrListDone (dirlist); 463 return FcTrue; 464} 465 466/* 467 * Scan the current list of directories in the configuration 468 * and build the set of available fonts. 469 */ 470 471FcBool 472FcConfigBuildFonts (FcConfig *config) 473{ 474 FcFontSet *fonts; 475 476 if (!config) 477 { 478 config = FcConfigGetCurrent (); 479 if (!config) 480 return FcFalse; 481 } 482 483 fonts = FcFontSetCreate (); 484 if (!fonts) 485 return FcFalse; 486 487 FcConfigSetFonts (config, fonts, FcSetSystem); 488 489 if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 490 return FcFalse; 491 if (FcDebug () & FC_DBG_FONTSET) 492 FcFontSetPrint (fonts); 493 return FcTrue; 494} 495 496FcBool 497FcConfigSetCurrent (FcConfig *config) 498{ 499 FcConfig *cfg; 500 501retry: 502 cfg = fc_atomic_ptr_get (&_fcConfig); 503 504 if (config == cfg) 505 return FcTrue; 506 507 if (config && !config->fonts[FcSetSystem]) 508 if (!FcConfigBuildFonts (config)) 509 return FcFalse; 510 511 if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) 512 goto retry; 513 514 FcConfigReference (config); 515 if (cfg) 516 FcConfigDestroy (cfg); 517 518 return FcTrue; 519} 520 521FcConfig * 522FcConfigGetCurrent (void) 523{ 524 return FcConfigEnsure (); 525} 526 527FcBool 528FcConfigAddConfigDir (FcConfig *config, 529 const FcChar8 *d) 530{ 531 return FcStrSetAddFilename (config->configDirs, d); 532} 533 534FcStrList * 535FcConfigGetConfigDirs (FcConfig *config) 536{ 537 if (!config) 538 { 539 config = FcConfigGetCurrent (); 540 if (!config) 541 return 0; 542 } 543 return FcStrListCreate (config->configDirs); 544} 545 546FcBool 547FcConfigAddFontDir (FcConfig *config, 548 const FcChar8 *d) 549{ 550 return FcStrSetAddFilename (config->fontDirs, d); 551} 552 553FcStrList * 554FcConfigGetFontDirs (FcConfig *config) 555{ 556 if (!config) 557 { 558 config = FcConfigGetCurrent (); 559 if (!config) 560 return 0; 561 } 562 return FcStrListCreate (config->fontDirs); 563} 564 565FcBool 566FcConfigAddCacheDir (FcConfig *config, 567 const FcChar8 *d) 568{ 569 return FcStrSetAddFilename (config->cacheDirs, d); 570} 571 572FcStrList * 573FcConfigGetCacheDirs (const FcConfig *config) 574{ 575 if (!config) 576 { 577 config = FcConfigGetCurrent (); 578 if (!config) 579 return 0; 580 } 581 return FcStrListCreate (config->cacheDirs); 582} 583 584FcBool 585FcConfigAddConfigFile (FcConfig *config, 586 const FcChar8 *f) 587{ 588 FcBool ret; 589 FcChar8 *file = FcConfigFilename (f); 590 591 if (!file) 592 return FcFalse; 593 594 ret = FcStrSetAdd (config->configFiles, file); 595 FcStrFree (file); 596 return ret; 597} 598 599FcStrList * 600FcConfigGetConfigFiles (FcConfig *config) 601{ 602 if (!config) 603 { 604 config = FcConfigGetCurrent (); 605 if (!config) 606 return 0; 607 } 608 return FcStrListCreate (config->configFiles); 609} 610 611FcChar8 * 612FcConfigGetCache (FcConfig *config FC_UNUSED) 613{ 614 return NULL; 615} 616 617FcFontSet * 618FcConfigGetFonts (FcConfig *config, 619 FcSetName set) 620{ 621 if (!config) 622 { 623 config = FcConfigGetCurrent (); 624 if (!config) 625 return 0; 626 } 627 return config->fonts[set]; 628} 629 630void 631FcConfigSetFonts (FcConfig *config, 632 FcFontSet *fonts, 633 FcSetName set) 634{ 635 if (config->fonts[set]) 636 FcFontSetDestroy (config->fonts[set]); 637 config->fonts[set] = fonts; 638} 639 640 641FcBlanks * 642FcBlanksCreate (void) 643{ 644 /* Deprecated. */ 645 return NULL; 646} 647 648void 649FcBlanksDestroy (FcBlanks *b FC_UNUSED) 650{ 651 /* Deprecated. */ 652} 653 654FcBool 655FcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) 656{ 657 /* Deprecated. */ 658 return FcFalse; 659} 660 661FcBool 662FcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) 663{ 664 /* Deprecated. */ 665 return FcFalse; 666} 667 668FcBlanks * 669FcConfigGetBlanks (FcConfig *config FC_UNUSED) 670{ 671 /* Deprecated. */ 672 return NULL; 673} 674 675FcBool 676FcConfigAddBlank (FcConfig *config FC_UNUSED, 677 FcChar32 blank FC_UNUSED) 678{ 679 /* Deprecated. */ 680 return FcFalse; 681} 682 683 684int 685FcConfigGetRescanInterval (FcConfig *config) 686{ 687 if (!config) 688 { 689 config = FcConfigGetCurrent (); 690 if (!config) 691 return 0; 692 } 693 return config->rescanInterval; 694} 695 696FcBool 697FcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 698{ 699 if (!config) 700 { 701 config = FcConfigGetCurrent (); 702 if (!config) 703 return FcFalse; 704 } 705 config->rescanInterval = rescanInterval; 706 return FcTrue; 707} 708 709/* 710 * A couple of typos escaped into the library 711 */ 712int 713FcConfigGetRescanInverval (FcConfig *config) 714{ 715 return FcConfigGetRescanInterval (config); 716} 717 718FcBool 719FcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 720{ 721 return FcConfigSetRescanInterval (config, rescanInterval); 722} 723 724FcBool 725FcConfigAddRule (FcConfig *config, 726 FcRule *rule, 727 FcMatchKind kind) 728{ 729 /* deprecated */ 730 return FcFalse; 731} 732 733static FcValue 734FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) 735{ 736 if (v.type == FcTypeInteger) 737 { 738 v.type = FcTypeDouble; 739 v.u.d = (double) v.u.i; 740 } 741 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 742 { 743 v.u.m = &FcIdentityMatrix; 744 v.type = FcTypeMatrix; 745 } 746 else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet) 747 { 748 v.u.l = FcLangSetPromote (v.u.s, buf); 749 v.type = FcTypeLangSet; 750 } 751 else if (buf && v.type == FcTypeVoid && u.type == FcTypeLangSet) 752 { 753 v.u.l = FcLangSetPromote (NULL, buf); 754 v.type = FcTypeLangSet; 755 } 756 else if (buf && v.type == FcTypeVoid && u.type == FcTypeCharSet) 757 { 758 v.u.c = FcCharSetPromote (buf); 759 v.type = FcTypeCharSet; 760 } 761 if (buf && v.type == FcTypeDouble && u.type == FcTypeRange) 762 { 763 v.u.r = FcRangePromote (v.u.d, buf); 764 v.type = FcTypeRange; 765 } 766 return v; 767} 768 769FcBool 770FcConfigCompareValue (const FcValue *left_o, 771 unsigned int op_, 772 const FcValue *right_o) 773{ 774 FcValue left = FcValueCanonicalize(left_o); 775 FcValue right = FcValueCanonicalize(right_o); 776 FcBool ret = FcFalse; 777 FcOp op = FC_OP_GET_OP (op_); 778 int flags = FC_OP_GET_FLAGS (op_); 779 FcValuePromotionBuffer buf1, buf2; 780 781 left = FcConfigPromote (left, right, &buf1); 782 right = FcConfigPromote (right, left, &buf2); 783 if (left.type == right.type) 784 { 785 switch (left.type) { 786 case FcTypeUnknown: 787 break; /* No way to guess how to compare for this object */ 788 case FcTypeInteger: 789 break; /* FcConfigPromote prevents this from happening */ 790 case FcTypeDouble: 791 switch ((int) op) { 792 case FcOpEqual: 793 case FcOpContains: 794 case FcOpListing: 795 ret = left.u.d == right.u.d; 796 break; 797 case FcOpNotEqual: 798 case FcOpNotContains: 799 ret = left.u.d != right.u.d; 800 break; 801 case FcOpLess: 802 ret = left.u.d < right.u.d; 803 break; 804 case FcOpLessEqual: 805 ret = left.u.d <= right.u.d; 806 break; 807 case FcOpMore: 808 ret = left.u.d > right.u.d; 809 break; 810 case FcOpMoreEqual: 811 ret = left.u.d >= right.u.d; 812 break; 813 default: 814 break; 815 } 816 break; 817 case FcTypeBool: 818 switch ((int) op) { 819 case FcOpEqual: 820 ret = left.u.b == right.u.b; 821 break; 822 case FcOpContains: 823 case FcOpListing: 824 ret = left.u.b == right.u.b || left.u.b == FcDontCare; 825 break; 826 case FcOpNotEqual: 827 ret = left.u.b != right.u.b; 828 break; 829 case FcOpNotContains: 830 ret = !(left.u.b == right.u.b || left.u.b == FcDontCare); 831 break; 832 case FcOpLess: 833 ret = left.u.b != right.u.b && right.u.b == FcDontCare; 834 break; 835 case FcOpLessEqual: 836 ret = left.u.b == right.u.b || right.u.b == FcDontCare; 837 break; 838 case FcOpMore: 839 ret = left.u.b != right.u.b && left.u.b == FcDontCare; 840 break; 841 case FcOpMoreEqual: 842 ret = left.u.b == right.u.b || left.u.b == FcDontCare; 843 break; 844 default: 845 break; 846 } 847 break; 848 case FcTypeString: 849 switch ((int) op) { 850 case FcOpEqual: 851 case FcOpListing: 852 if (flags & FcOpFlagIgnoreBlanks) 853 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; 854 else 855 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 856 break; 857 case FcOpContains: 858 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 859 break; 860 case FcOpNotEqual: 861 if (flags & FcOpFlagIgnoreBlanks) 862 ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; 863 else 864 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 865 break; 866 case FcOpNotContains: 867 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 868 break; 869 default: 870 break; 871 } 872 break; 873 case FcTypeMatrix: 874 switch ((int) op) { 875 case FcOpEqual: 876 case FcOpContains: 877 case FcOpListing: 878 ret = FcMatrixEqual (left.u.m, right.u.m); 879 break; 880 case FcOpNotEqual: 881 case FcOpNotContains: 882 ret = !FcMatrixEqual (left.u.m, right.u.m); 883 break; 884 default: 885 break; 886 } 887 break; 888 case FcTypeCharSet: 889 switch ((int) op) { 890 case FcOpContains: 891 case FcOpListing: 892 /* left contains right if right is a subset of left */ 893 ret = FcCharSetIsSubset (right.u.c, left.u.c); 894 break; 895 case FcOpNotContains: 896 /* left contains right if right is a subset of left */ 897 ret = !FcCharSetIsSubset (right.u.c, left.u.c); 898 break; 899 case FcOpEqual: 900 ret = FcCharSetEqual (left.u.c, right.u.c); 901 break; 902 case FcOpNotEqual: 903 ret = !FcCharSetEqual (left.u.c, right.u.c); 904 break; 905 default: 906 break; 907 } 908 break; 909 case FcTypeLangSet: 910 switch ((int) op) { 911 case FcOpContains: 912 case FcOpListing: 913 ret = FcLangSetContains (left.u.l, right.u.l); 914 break; 915 case FcOpNotContains: 916 ret = !FcLangSetContains (left.u.l, right.u.l); 917 break; 918 case FcOpEqual: 919 ret = FcLangSetEqual (left.u.l, right.u.l); 920 break; 921 case FcOpNotEqual: 922 ret = !FcLangSetEqual (left.u.l, right.u.l); 923 break; 924 default: 925 break; 926 } 927 break; 928 case FcTypeVoid: 929 switch ((int) op) { 930 case FcOpEqual: 931 case FcOpContains: 932 case FcOpListing: 933 ret = FcTrue; 934 break; 935 default: 936 break; 937 } 938 break; 939 case FcTypeFTFace: 940 switch ((int) op) { 941 case FcOpEqual: 942 case FcOpContains: 943 case FcOpListing: 944 ret = left.u.f == right.u.f; 945 break; 946 case FcOpNotEqual: 947 case FcOpNotContains: 948 ret = left.u.f != right.u.f; 949 break; 950 default: 951 break; 952 } 953 break; 954 case FcTypeRange: 955 ret = FcRangeCompare (op, left.u.r, right.u.r); 956 break; 957 } 958 } 959 else 960 { 961 if (op == FcOpNotEqual || op == FcOpNotContains) 962 ret = FcTrue; 963 } 964 return ret; 965} 966 967 968#define _FcDoubleFloor(d) ((int) (d)) 969#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 970#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 971#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 972#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 973#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 974 975static FcValue 976FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) 977{ 978 FcValue v, vl, vr, vle, vre; 979 FcMatrix *m; 980 FcChar8 *str; 981 FcOp op = FC_OP_GET_OP (e->op); 982 FcValuePromotionBuffer buf1, buf2; 983 984 switch ((int) op) { 985 case FcOpInteger: 986 v.type = FcTypeInteger; 987 v.u.i = e->u.ival; 988 break; 989 case FcOpDouble: 990 v.type = FcTypeDouble; 991 v.u.d = e->u.dval; 992 break; 993 case FcOpString: 994 v.type = FcTypeString; 995 v.u.s = e->u.sval; 996 v = FcValueSave (v); 997 break; 998 case FcOpMatrix: 999 { 1000 FcMatrix m; 1001 FcValue xx, xy, yx, yy; 1002 v.type = FcTypeMatrix; 1003 xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL); 1004 xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL); 1005 yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL); 1006 yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL); 1007 if (xx.type == FcTypeDouble && xy.type == FcTypeDouble && 1008 yx.type == FcTypeDouble && yy.type == FcTypeDouble) 1009 { 1010 m.xx = xx.u.d; 1011 m.xy = xy.u.d; 1012 m.yx = yx.u.d; 1013 m.yy = yy.u.d; 1014 v.u.m = &m; 1015 } 1016 else 1017 v.type = FcTypeVoid; 1018 v = FcValueSave (v); 1019 } 1020 break; 1021 case FcOpCharSet: 1022 v.type = FcTypeCharSet; 1023 v.u.c = e->u.cval; 1024 v = FcValueSave (v); 1025 break; 1026 case FcOpLangSet: 1027 v.type = FcTypeLangSet; 1028 v.u.l = e->u.lval; 1029 v = FcValueSave (v); 1030 break; 1031 case FcOpRange: 1032 v.type = FcTypeRange; 1033 v.u.r = e->u.rval; 1034 v = FcValueSave (v); 1035 break; 1036 case FcOpBool: 1037 v.type = FcTypeBool; 1038 v.u.b = e->u.bval; 1039 break; 1040 case FcOpField: 1041 if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern) 1042 { 1043 if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v)) 1044 v.type = FcTypeVoid; 1045 } 1046 else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont) 1047 { 1048 fprintf (stderr, 1049 "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n"); 1050 v.type = FcTypeVoid; 1051 } 1052 else 1053 { 1054 if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v)) 1055 v.type = FcTypeVoid; 1056 } 1057 v = FcValueSave (v); 1058 break; 1059 case FcOpConst: 1060 if (FcNameConstant (e->u.constant, &v.u.i)) 1061 v.type = FcTypeInteger; 1062 else 1063 v.type = FcTypeVoid; 1064 break; 1065 case FcOpQuest: 1066 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1067 if (vl.type == FcTypeBool) 1068 { 1069 if (vl.u.b) 1070 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left); 1071 else 1072 v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right); 1073 } 1074 else 1075 v.type = FcTypeVoid; 1076 FcValueDestroy (vl); 1077 break; 1078 case FcOpEqual: 1079 case FcOpNotEqual: 1080 case FcOpLess: 1081 case FcOpLessEqual: 1082 case FcOpMore: 1083 case FcOpMoreEqual: 1084 case FcOpContains: 1085 case FcOpNotContains: 1086 case FcOpListing: 1087 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1088 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 1089 v.type = FcTypeBool; 1090 v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 1091 FcValueDestroy (vl); 1092 FcValueDestroy (vr); 1093 break; 1094 case FcOpOr: 1095 case FcOpAnd: 1096 case FcOpPlus: 1097 case FcOpMinus: 1098 case FcOpTimes: 1099 case FcOpDivide: 1100 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1101 vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 1102 vle = FcConfigPromote (vl, vr, &buf1); 1103 vre = FcConfigPromote (vr, vle, &buf2); 1104 if (vle.type == vre.type) 1105 { 1106 switch ((int) vle.type) { 1107 case FcTypeDouble: 1108 switch ((int) op) { 1109 case FcOpPlus: 1110 v.type = FcTypeDouble; 1111 v.u.d = vle.u.d + vre.u.d; 1112 break; 1113 case FcOpMinus: 1114 v.type = FcTypeDouble; 1115 v.u.d = vle.u.d - vre.u.d; 1116 break; 1117 case FcOpTimes: 1118 v.type = FcTypeDouble; 1119 v.u.d = vle.u.d * vre.u.d; 1120 break; 1121 case FcOpDivide: 1122 v.type = FcTypeDouble; 1123 v.u.d = vle.u.d / vre.u.d; 1124 break; 1125 default: 1126 v.type = FcTypeVoid; 1127 break; 1128 } 1129 if (v.type == FcTypeDouble && 1130 v.u.d == (double) (int) v.u.d) 1131 { 1132 v.type = FcTypeInteger; 1133 v.u.i = (int) v.u.d; 1134 } 1135 break; 1136 case FcTypeBool: 1137 switch ((int) op) { 1138 case FcOpOr: 1139 v.type = FcTypeBool; 1140 v.u.b = vle.u.b || vre.u.b; 1141 break; 1142 case FcOpAnd: 1143 v.type = FcTypeBool; 1144 v.u.b = vle.u.b && vre.u.b; 1145 break; 1146 default: 1147 v.type = FcTypeVoid; 1148 break; 1149 } 1150 break; 1151 case FcTypeString: 1152 switch ((int) op) { 1153 case FcOpPlus: 1154 v.type = FcTypeString; 1155 str = FcStrPlus (vle.u.s, vre.u.s); 1156 v.u.s = FcStrdup (str); 1157 FcStrFree (str); 1158 1159 if (!v.u.s) 1160 v.type = FcTypeVoid; 1161 break; 1162 default: 1163 v.type = FcTypeVoid; 1164 break; 1165 } 1166 break; 1167 case FcTypeMatrix: 1168 switch ((int) op) { 1169 case FcOpTimes: 1170 v.type = FcTypeMatrix; 1171 m = malloc (sizeof (FcMatrix)); 1172 if (m) 1173 { 1174 FcMatrixMultiply (m, vle.u.m, vre.u.m); 1175 v.u.m = m; 1176 } 1177 else 1178 { 1179 v.type = FcTypeVoid; 1180 } 1181 break; 1182 default: 1183 v.type = FcTypeVoid; 1184 break; 1185 } 1186 break; 1187 case FcTypeCharSet: 1188 switch ((int) op) { 1189 case FcOpPlus: 1190 v.type = FcTypeCharSet; 1191 v.u.c = FcCharSetUnion (vle.u.c, vre.u.c); 1192 if (!v.u.c) 1193 v.type = FcTypeVoid; 1194 break; 1195 case FcOpMinus: 1196 v.type = FcTypeCharSet; 1197 v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c); 1198 if (!v.u.c) 1199 v.type = FcTypeVoid; 1200 break; 1201 default: 1202 v.type = FcTypeVoid; 1203 break; 1204 } 1205 break; 1206 case FcTypeLangSet: 1207 switch ((int) op) { 1208 case FcOpPlus: 1209 v.type = FcTypeLangSet; 1210 v.u.l = FcLangSetUnion (vle.u.l, vre.u.l); 1211 if (!v.u.l) 1212 v.type = FcTypeVoid; 1213 break; 1214 case FcOpMinus: 1215 v.type = FcTypeLangSet; 1216 v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l); 1217 if (!v.u.l) 1218 v.type = FcTypeVoid; 1219 break; 1220 default: 1221 v.type = FcTypeVoid; 1222 break; 1223 } 1224 break; 1225 default: 1226 v.type = FcTypeVoid; 1227 break; 1228 } 1229 } 1230 else 1231 v.type = FcTypeVoid; 1232 FcValueDestroy (vl); 1233 FcValueDestroy (vr); 1234 break; 1235 case FcOpNot: 1236 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1237 switch ((int) vl.type) { 1238 case FcTypeBool: 1239 v.type = FcTypeBool; 1240 v.u.b = !vl.u.b; 1241 break; 1242 default: 1243 v.type = FcTypeVoid; 1244 break; 1245 } 1246 FcValueDestroy (vl); 1247 break; 1248 case FcOpFloor: 1249 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1250 switch ((int) vl.type) { 1251 case FcTypeInteger: 1252 v = vl; 1253 break; 1254 case FcTypeDouble: 1255 v.type = FcTypeInteger; 1256 v.u.i = FcDoubleFloor (vl.u.d); 1257 break; 1258 default: 1259 v.type = FcTypeVoid; 1260 break; 1261 } 1262 FcValueDestroy (vl); 1263 break; 1264 case FcOpCeil: 1265 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1266 switch ((int) vl.type) { 1267 case FcTypeInteger: 1268 v = vl; 1269 break; 1270 case FcTypeDouble: 1271 v.type = FcTypeInteger; 1272 v.u.i = FcDoubleCeil (vl.u.d); 1273 break; 1274 default: 1275 v.type = FcTypeVoid; 1276 break; 1277 } 1278 FcValueDestroy (vl); 1279 break; 1280 case FcOpRound: 1281 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1282 switch ((int) vl.type) { 1283 case FcTypeInteger: 1284 v = vl; 1285 break; 1286 case FcTypeDouble: 1287 v.type = FcTypeInteger; 1288 v.u.i = FcDoubleRound (vl.u.d); 1289 break; 1290 default: 1291 v.type = FcTypeVoid; 1292 break; 1293 } 1294 FcValueDestroy (vl); 1295 break; 1296 case FcOpTrunc: 1297 vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1298 switch ((int) vl.type) { 1299 case FcTypeInteger: 1300 v = vl; 1301 break; 1302 case FcTypeDouble: 1303 v.type = FcTypeInteger; 1304 v.u.i = FcDoubleTrunc (vl.u.d); 1305 break; 1306 default: 1307 v.type = FcTypeVoid; 1308 break; 1309 } 1310 FcValueDestroy (vl); 1311 break; 1312 default: 1313 v.type = FcTypeVoid; 1314 break; 1315 } 1316 return v; 1317} 1318 1319static FcValueList * 1320FcConfigMatchValueList (FcPattern *p, 1321 FcPattern *p_pat, 1322 FcMatchKind kind, 1323 FcTest *t, 1324 FcValueList *values) 1325{ 1326 FcValueList *ret = 0; 1327 FcExpr *e = t->expr; 1328 FcValue value; 1329 FcValueList *v; 1330 1331 while (e) 1332 { 1333 /* Compute the value of the match expression */ 1334 if (FC_OP_GET_OP (e->op) == FcOpComma) 1335 { 1336 value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1337 e = e->u.tree.right; 1338 } 1339 else 1340 { 1341 value = FcConfigEvaluate (p, p_pat, kind, e); 1342 e = 0; 1343 } 1344 1345 for (v = values; v; v = FcValueListNext(v)) 1346 { 1347 /* Compare the pattern value to the match expression value */ 1348 if (FcConfigCompareValue (&v->value, t->op, &value)) 1349 { 1350 if (!ret) 1351 ret = v; 1352 } 1353 else 1354 { 1355 if (t->qual == FcQualAll) 1356 { 1357 ret = 0; 1358 break; 1359 } 1360 } 1361 } 1362 FcValueDestroy (value); 1363 } 1364 return ret; 1365} 1366 1367static FcValueList * 1368FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding) 1369{ 1370 FcValueList *l; 1371 1372 if (!e) 1373 return 0; 1374 l = (FcValueList *) malloc (sizeof (FcValueList)); 1375 if (!l) 1376 return 0; 1377 if (FC_OP_GET_OP (e->op) == FcOpComma) 1378 { 1379 l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1380 l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding); 1381 } 1382 else 1383 { 1384 l->value = FcConfigEvaluate (p, p_pat, kind, e); 1385 l->next = NULL; 1386 } 1387 l->binding = binding; 1388 if (l->value.type == FcTypeVoid) 1389 { 1390 FcValueList *next = FcValueListNext(l); 1391 1392 free (l); 1393 l = next; 1394 } 1395 1396 return l; 1397} 1398 1399static FcBool 1400FcConfigAdd (FcValueListPtr *head, 1401 FcValueList *position, 1402 FcBool append, 1403 FcValueList *new, 1404 FcObject object) 1405{ 1406 FcValueListPtr *prev, l, last, v; 1407 FcValueBinding sameBinding; 1408 1409 /* 1410 * Make sure the stored type is valid for built-in objects 1411 */ 1412 for (l = new; l != NULL; l = FcValueListNext (l)) 1413 { 1414 if (!FcObjectValidType (object, l->value.type)) 1415 { 1416 fprintf (stderr, 1417 "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); 1418 FcValuePrintFile (stderr, l->value); 1419 fprintf (stderr, "\n"); 1420 1421 if (FcDebug () & FC_DBG_EDIT) 1422 { 1423 printf ("Not adding\n"); 1424 } 1425 1426 return FcFalse; 1427 } 1428 } 1429 1430 if (position) 1431 sameBinding = position->binding; 1432 else 1433 sameBinding = FcValueBindingWeak; 1434 for (v = new; v != NULL; v = FcValueListNext(v)) 1435 if (v->binding == FcValueBindingSame) 1436 v->binding = sameBinding; 1437 if (append) 1438 { 1439 if (position) 1440 prev = &position->next; 1441 else 1442 for (prev = head; *prev != NULL; 1443 prev = &(*prev)->next) 1444 ; 1445 } 1446 else 1447 { 1448 if (position) 1449 { 1450 for (prev = head; *prev != NULL; 1451 prev = &(*prev)->next) 1452 { 1453 if (*prev == position) 1454 break; 1455 } 1456 } 1457 else 1458 prev = head; 1459 1460 if (FcDebug () & FC_DBG_EDIT) 1461 { 1462 if (*prev == NULL) 1463 printf ("position not on list\n"); 1464 } 1465 } 1466 1467 if (FcDebug () & FC_DBG_EDIT) 1468 { 1469 printf ("%s list before ", append ? "Append" : "Prepend"); 1470 FcValueListPrintWithPosition (*head, *prev); 1471 printf ("\n"); 1472 } 1473 1474 if (new) 1475 { 1476 last = new; 1477 while (last->next != NULL) 1478 last = last->next; 1479 1480 last->next = *prev; 1481 *prev = new; 1482 } 1483 1484 if (FcDebug () & FC_DBG_EDIT) 1485 { 1486 printf ("%s list after ", append ? "Append" : "Prepend"); 1487 FcValueListPrint (*head); 1488 printf ("\n"); 1489 } 1490 1491 return FcTrue; 1492} 1493 1494static void 1495FcConfigDel (FcValueListPtr *head, 1496 FcValueList *position) 1497{ 1498 FcValueListPtr *prev; 1499 1500 for (prev = head; *prev != NULL; prev = &(*prev)->next) 1501 { 1502 if (*prev == position) 1503 { 1504 *prev = position->next; 1505 position->next = NULL; 1506 FcValueListDestroy (position); 1507 break; 1508 } 1509 } 1510} 1511 1512static void 1513FcConfigPatternAdd (FcPattern *p, 1514 FcObject object, 1515 FcValueList *list, 1516 FcBool append) 1517{ 1518 if (list) 1519 { 1520 FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1521 1522 if (!e) 1523 return; 1524 FcConfigAdd (&e->values, 0, append, list, object); 1525 } 1526} 1527 1528/* 1529 * Delete all values associated with a field 1530 */ 1531static void 1532FcConfigPatternDel (FcPattern *p, 1533 FcObject object) 1534{ 1535 FcPatternElt *e = FcPatternObjectFindElt (p, object); 1536 if (!e) 1537 return; 1538 while (e->values != NULL) 1539 FcConfigDel (&e->values, e->values); 1540} 1541 1542static void 1543FcConfigPatternCanon (FcPattern *p, 1544 FcObject object) 1545{ 1546 FcPatternElt *e = FcPatternObjectFindElt (p, object); 1547 if (!e) 1548 return; 1549 if (e->values == NULL) 1550 FcPatternObjectDel (p, object); 1551} 1552 1553FcBool 1554FcConfigSubstituteWithPat (FcConfig *config, 1555 FcPattern *p, 1556 FcPattern *p_pat, 1557 FcMatchKind kind) 1558{ 1559 FcValue v; 1560 FcPtrList *s; 1561 FcPtrListIter iter, iter2; 1562 FcRule *r; 1563 FcRuleSet *rs; 1564 FcValueList *l, **value = NULL, *vl; 1565 FcPattern *m; 1566 FcStrSet *strs; 1567 FcObject object = FC_INVALID_OBJECT; 1568 FcPatternElt **elt = NULL, *e; 1569 int i, nobjs; 1570 FcBool retval = FcTrue; 1571 FcTest **tst = NULL; 1572 1573 if (!config) 1574 { 1575 config = FcConfigGetCurrent (); 1576 if (!config) 1577 return FcFalse; 1578 } 1579 1580 if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd) 1581 return FcFalse; 1582 s = config->subst[kind]; 1583 if (kind == FcMatchPattern) 1584 { 1585 strs = FcGetDefaultLangs (); 1586 if (strs) 1587 { 1588 FcStrList *l = FcStrListCreate (strs); 1589 FcChar8 *lang; 1590 FcValue v; 1591 FcLangSet *lsund = FcLangSetCreate (); 1592 1593 FcLangSetAdd (lsund, (const FcChar8 *)"und"); 1594 FcStrSetDestroy (strs); 1595 while (l && (lang = FcStrListNext (l))) 1596 { 1597 FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT); 1598 1599 if (e) 1600 { 1601 FcValueListPtr ll; 1602 1603 for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll)) 1604 { 1605 FcValue vv = FcValueCanonicalize (&ll->value); 1606 1607 if (vv.type == FcTypeLangSet) 1608 { 1609 FcLangSet *ls = FcLangSetCreate (); 1610 FcBool b; 1611 1612 FcLangSetAdd (ls, lang); 1613 b = FcLangSetContains (vv.u.l, ls); 1614 FcLangSetDestroy (ls); 1615 if (b) 1616 goto bail_lang; 1617 if (FcLangSetContains (vv.u.l, lsund)) 1618 goto bail_lang; 1619 } 1620 else 1621 { 1622 if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0) 1623 goto bail_lang; 1624 if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0) 1625 goto bail_lang; 1626 } 1627 } 1628 } 1629 v.type = FcTypeString; 1630 v.u.s = lang; 1631 1632 FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 1633 } 1634 bail_lang: 1635 FcStrListDone (l); 1636 FcLangSetDestroy (lsund); 1637 } 1638 if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) 1639 { 1640 FcChar8 *prgname = FcGetPrgname (); 1641 if (prgname) 1642 FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); 1643 } 1644 } 1645 1646 nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2; 1647 value = (FcValueList **) malloc (sizeof(void *) * nobjs); 1648 if (!value) 1649 { 1650 retval = FcFalse; 1651 goto bail1; 1652 } 1653 elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs); 1654 if (!elt) 1655 { 1656 retval = FcFalse; 1657 goto bail1; 1658 } 1659 tst = (FcTest **) malloc (sizeof(void *) * nobjs); 1660 if (!tst) 1661 { 1662 retval = FcFalse; 1663 goto bail1; 1664 } 1665 1666 if (FcDebug () & FC_DBG_EDIT) 1667 { 1668 printf ("FcConfigSubstitute "); 1669 FcPatternPrint (p); 1670 } 1671 FcPtrListIterInit (s, &iter); 1672 for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter)) 1673 { 1674 rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter); 1675 if (FcDebug () & FC_DBG_EDIT) 1676 { 1677 printf ("\nRule Set: %s\n", rs->name); 1678 } 1679 FcPtrListIterInit (rs->subst[kind], &iter2); 1680 for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2)) 1681 { 1682 r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2); 1683 for (i = 0; i < nobjs; i++) 1684 { 1685 elt[i] = NULL; 1686 value[i] = NULL; 1687 tst[i] = NULL; 1688 } 1689 for (; r; r = r->next) 1690 { 1691 switch (r->type) { 1692 case FcRuleUnknown: 1693 /* shouldn't be reached */ 1694 break; 1695 case FcRuleTest: 1696 object = FC_OBJ_ID (r->u.test->object); 1697 /* 1698 * Check the tests to see if 1699 * they all match the pattern 1700 */ 1701 if (FcDebug () & FC_DBG_EDIT) 1702 { 1703 printf ("FcConfigSubstitute test "); 1704 FcTestPrint (r->u.test); 1705 } 1706 if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) 1707 m = p_pat; 1708 else 1709 m = p; 1710 if (m) 1711 e = FcPatternObjectFindElt (m, r->u.test->object); 1712 else 1713 e = NULL; 1714 /* different 'kind' won't be the target of edit */ 1715 if (!elt[object] && kind == r->u.test->kind) 1716 { 1717 elt[object] = e; 1718 tst[object] = r->u.test; 1719 } 1720 /* 1721 * If there's no such field in the font, 1722 * then FcQualAll matches while FcQualAny does not 1723 */ 1724 if (!e) 1725 { 1726 if (r->u.test->qual == FcQualAll) 1727 { 1728 value[object] = NULL; 1729 continue; 1730 } 1731 else 1732 { 1733 if (FcDebug () & FC_DBG_EDIT) 1734 printf ("No match\n"); 1735 goto bail; 1736 } 1737 } 1738 /* 1739 * Check to see if there is a match, mark the location 1740 * to apply match-relative edits 1741 */ 1742 vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); 1743 /* different 'kind' won't be the target of edit */ 1744 if (!value[object] && kind == r->u.test->kind) 1745 value[object] = vl; 1746 if (!vl || 1747 (r->u.test->qual == FcQualFirst && vl != e->values) || 1748 (r->u.test->qual == FcQualNotFirst && vl == e->values)) 1749 { 1750 if (FcDebug () & FC_DBG_EDIT) 1751 printf ("No match\n"); 1752 goto bail; 1753 } 1754 break; 1755 case FcRuleEdit: 1756 object = FC_OBJ_ID (r->u.edit->object); 1757 if (FcDebug () & FC_DBG_EDIT) 1758 { 1759 printf ("Substitute "); 1760 FcEditPrint (r->u.edit); 1761 printf ("\n\n"); 1762 } 1763 /* 1764 * Evaluate the list of expressions 1765 */ 1766 l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); 1767 if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) 1768 elt[object] = FcPatternObjectFindElt (p, tst[object]->object); 1769 1770 switch (FC_OP_GET_OP (r->u.edit->op)) { 1771 case FcOpAssign: 1772 /* 1773 * If there was a test, then replace the matched 1774 * value with the new list of values 1775 */ 1776 if (value[object]) 1777 { 1778 FcValueList *thisValue = value[object]; 1779 FcValueList *nextValue = l; 1780 1781 /* 1782 * Append the new list of values after the current value 1783 */ 1784 FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); 1785 /* 1786 * Delete the marked value 1787 */ 1788 if (thisValue) 1789 FcConfigDel (&elt[object]->values, thisValue); 1790 /* 1791 * Adjust a pointer into the value list to ensure 1792 * future edits occur at the same place 1793 */ 1794 value[object] = nextValue; 1795 break; 1796 } 1797 /* fall through ... */ 1798 case FcOpAssignReplace: 1799 /* 1800 * Delete all of the values and insert 1801 * the new set 1802 */ 1803 FcConfigPatternDel (p, r->u.edit->object); 1804 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 1805 /* 1806 * Adjust a pointer into the value list as they no 1807 * longer point to anything valid 1808 */ 1809 value[object] = NULL; 1810 break; 1811 case FcOpPrepend: 1812 if (value[object]) 1813 { 1814 FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); 1815 break; 1816 } 1817 /* fall through ... */ 1818 case FcOpPrependFirst: 1819 FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); 1820 break; 1821 case FcOpAppend: 1822 if (value[object]) 1823 { 1824 FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); 1825 break; 1826 } 1827 /* fall through ... */ 1828 case FcOpAppendLast: 1829 FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 1830 break; 1831 case FcOpDelete: 1832 if (value[object]) 1833 { 1834 FcConfigDel (&elt[object]->values, value[object]); 1835 FcValueListDestroy (l); 1836 break; 1837 } 1838 /* fall through ... */ 1839 case FcOpDeleteAll: 1840 FcConfigPatternDel (p, r->u.edit->object); 1841 FcValueListDestroy (l); 1842 break; 1843 default: 1844 FcValueListDestroy (l); 1845 break; 1846 } 1847 /* 1848 * Now go through the pattern and eliminate 1849 * any properties without data 1850 */ 1851 FcConfigPatternCanon (p, r->u.edit->object); 1852 1853 if (FcDebug () & FC_DBG_EDIT) 1854 { 1855 printf ("FcConfigSubstitute edit"); 1856 FcPatternPrint (p); 1857 } 1858 break; 1859 } 1860 } 1861 bail:; 1862 } 1863 } 1864 if (FcDebug () & FC_DBG_EDIT) 1865 { 1866 printf ("FcConfigSubstitute done"); 1867 FcPatternPrint (p); 1868 } 1869bail1: 1870 if (elt) 1871 free (elt); 1872 if (value) 1873 free (value); 1874 if (tst) 1875 free (tst); 1876 1877 return retval; 1878} 1879 1880FcBool 1881FcConfigSubstitute (FcConfig *config, 1882 FcPattern *p, 1883 FcMatchKind kind) 1884{ 1885 return FcConfigSubstituteWithPat (config, p, 0, kind); 1886} 1887 1888#if defined (_WIN32) 1889 1890static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */ 1891FcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */ 1892 1893# if (defined (PIC) || defined (DLL_EXPORT)) 1894 1895BOOL WINAPI 1896DllMain (HINSTANCE hinstDLL, 1897 DWORD fdwReason, 1898 LPVOID lpvReserved); 1899 1900BOOL WINAPI 1901DllMain (HINSTANCE hinstDLL, 1902 DWORD fdwReason, 1903 LPVOID lpvReserved) 1904{ 1905 FcChar8 *p; 1906 1907 switch (fdwReason) { 1908 case DLL_PROCESS_ATTACH: 1909 if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 1910 sizeof (fontconfig_path))) 1911 break; 1912 1913 /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 1914 * assume it's a Unix-style installation tree, and use 1915 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 1916 * folder where the DLL is as FONTCONFIG_PATH. 1917 */ 1918 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1919 if (p) 1920 { 1921 *p = '\0'; 1922 p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1923 if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 1924 FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 1925 *p = '\0'; 1926 strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path); 1927 strcat ((char *) fontconfig_path, "\\etc\\fonts"); 1928 } 1929 else 1930 fontconfig_path[0] = '\0'; 1931 1932 break; 1933 } 1934 1935 return TRUE; 1936} 1937 1938# endif /* !PIC */ 1939 1940#undef FONTCONFIG_PATH 1941#define FONTCONFIG_PATH fontconfig_path 1942 1943#endif /* !_WIN32 */ 1944 1945#ifndef FONTCONFIG_FILE 1946#define FONTCONFIG_FILE "fonts.conf" 1947#endif 1948 1949static FcChar8 * 1950FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 1951{ 1952 FcChar8 *path; 1953 int size, osize; 1954 1955 if (!dir) 1956 dir = (FcChar8 *) ""; 1957 1958 osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 1959 /* 1960 * workaround valgrind warning because glibc takes advantage of how it knows memory is 1961 * allocated to implement strlen by reading in groups of 4 1962 */ 1963 size = (osize + 3) & ~3; 1964 1965 path = malloc (size); 1966 if (!path) 1967 return 0; 1968 1969 strcpy ((char *) path, (const char *) dir); 1970 /* make sure there's a single separator */ 1971#ifdef _WIN32 1972 if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 1973 path[strlen((char *) path)-1] != '\\')) && 1974 !(file[0] == '/' || 1975 file[0] == '\\' || 1976 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 1977 strcat ((char *) path, "\\"); 1978#else 1979 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 1980 strcat ((char *) path, "/"); 1981 else 1982 osize--; 1983#endif 1984 strcat ((char *) path, (char *) file); 1985 1986 if (access ((char *) path, R_OK) == 0) 1987 return path; 1988 1989 FcStrFree (path); 1990 1991 return 0; 1992} 1993 1994static FcChar8 ** 1995FcConfigGetPath (void) 1996{ 1997 FcChar8 **path; 1998 FcChar8 *env, *e, *colon; 1999 FcChar8 *dir; 2000 int npath; 2001 int i; 2002 2003 npath = 2; /* default dir + null */ 2004 env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 2005 if (env) 2006 { 2007 e = env; 2008 npath++; 2009 while (*e) 2010 if (*e++ == FC_SEARCH_PATH_SEPARATOR) 2011 npath++; 2012 } 2013 path = calloc (npath, sizeof (FcChar8 *)); 2014 if (!path) 2015 goto bail0; 2016 i = 0; 2017 2018 if (env) 2019 { 2020 e = env; 2021 while (*e) 2022 { 2023 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 2024 if (!colon) 2025 colon = e + strlen ((char *) e); 2026 path[i] = malloc (colon - e + 1); 2027 if (!path[i]) 2028 goto bail1; 2029 strncpy ((char *) path[i], (const char *) e, colon - e); 2030 path[i][colon - e] = '\0'; 2031 if (*colon) 2032 e = colon + 1; 2033 else 2034 e = colon; 2035 i++; 2036 } 2037 } 2038 2039#ifdef _WIN32 2040 if (fontconfig_path[0] == '\0') 2041 { 2042 char *p; 2043 if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 2044 goto bail1; 2045 p = strrchr ((const char *) fontconfig_path, '\\'); 2046 if (p) *p = '\0'; 2047 strcat ((char *) fontconfig_path, "\\fonts"); 2048 } 2049#endif 2050 dir = (FcChar8 *) FONTCONFIG_PATH; 2051 path[i] = malloc (strlen ((char *) dir) + 1); 2052 if (!path[i]) 2053 goto bail1; 2054 strcpy ((char *) path[i], (const char *) dir); 2055 return path; 2056 2057bail1: 2058 for (i = 0; path[i]; i++) 2059 free (path[i]); 2060 free (path); 2061bail0: 2062 return 0; 2063} 2064 2065static void 2066FcConfigFreePath (FcChar8 **path) 2067{ 2068 FcChar8 **p; 2069 2070 for (p = path; *p; p++) 2071 free (*p); 2072 free (path); 2073} 2074 2075static FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */ 2076 2077FcChar8 * 2078FcConfigHome (void) 2079{ 2080 if (_FcConfigHomeEnabled) 2081 { 2082 char *home = getenv ("HOME"); 2083 2084#ifdef _WIN32 2085 if (home == NULL) 2086 home = getenv ("USERPROFILE"); 2087#endif 2088 2089 return (FcChar8 *) home; 2090 } 2091 return 0; 2092} 2093 2094FcChar8 * 2095FcConfigXdgCacheHome (void) 2096{ 2097 const char *env = getenv ("XDG_CACHE_HOME"); 2098 FcChar8 *ret = NULL; 2099 2100 if (!_FcConfigHomeEnabled) 2101 return NULL; 2102 if (env) 2103 ret = FcStrCopy ((const FcChar8 *)env); 2104 else 2105 { 2106 const FcChar8 *home = FcConfigHome (); 2107 size_t len = home ? strlen ((const char *)home) : 0; 2108 2109 ret = malloc (len + 7 + 1); 2110 if (ret) 2111 { 2112 if (home) 2113 memcpy (ret, home, len); 2114 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 2115 ret[len + 7] = 0; 2116 } 2117 } 2118 2119 return ret; 2120} 2121 2122FcChar8 * 2123FcConfigXdgConfigHome (void) 2124{ 2125 const char *env = getenv ("XDG_CONFIG_HOME"); 2126 FcChar8 *ret = NULL; 2127 2128 if (!_FcConfigHomeEnabled) 2129 return NULL; 2130 if (env) 2131 ret = FcStrCopy ((const FcChar8 *)env); 2132 else 2133 { 2134 const FcChar8 *home = FcConfigHome (); 2135 size_t len = home ? strlen ((const char *)home) : 0; 2136 2137 ret = malloc (len + 8 + 1); 2138 if (ret) 2139 { 2140 if (home) 2141 memcpy (ret, home, len); 2142 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 2143 ret[len + 8] = 0; 2144 } 2145 } 2146 2147 return ret; 2148} 2149 2150FcChar8 * 2151FcConfigXdgDataHome (void) 2152{ 2153 const char *env = getenv ("XDG_DATA_HOME"); 2154 FcChar8 *ret = NULL; 2155 2156 if (!_FcConfigHomeEnabled) 2157 return NULL; 2158 if (env) 2159 ret = FcStrCopy ((const FcChar8 *)env); 2160 else 2161 { 2162 const FcChar8 *home = FcConfigHome (); 2163 size_t len = home ? strlen ((const char *)home) : 0; 2164 2165 ret = malloc (len + 13 + 1); 2166 if (ret) 2167 { 2168 if (home) 2169 memcpy (ret, home, len); 2170 memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 2171 ret[len + 13] = 0; 2172 } 2173 } 2174 2175 return ret; 2176} 2177 2178FcBool 2179FcConfigEnableHome (FcBool enable) 2180{ 2181 FcBool prev = _FcConfigHomeEnabled; 2182 _FcConfigHomeEnabled = enable; 2183 return prev; 2184} 2185 2186FcChar8 * 2187FcConfigFilename (const FcChar8 *url) 2188{ 2189 FcChar8 *file, *dir, **path, **p; 2190 2191 if (!url || !*url) 2192 { 2193 url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 2194 if (!url) 2195 url = (FcChar8 *) FONTCONFIG_FILE; 2196 } 2197 file = 0; 2198 2199 if (FcStrIsAbsoluteFilename(url)) 2200 return FcConfigFileExists (0, url); 2201 2202 if (*url == '~') 2203 { 2204 dir = FcConfigHome (); 2205 if (dir) 2206 file = FcConfigFileExists (dir, url + 1); 2207 else 2208 file = 0; 2209 } 2210 2211 path = FcConfigGetPath (); 2212 if (!path) 2213 return NULL; 2214 for (p = path; *p; p++) 2215 { 2216 file = FcConfigFileExists (*p, url); 2217 if (file) 2218 break; 2219 } 2220 FcConfigFreePath (path); 2221 return file; 2222} 2223 2224FcChar8 * 2225FcConfigRealFilename (FcConfig *config, 2226 const FcChar8 *url) 2227{ 2228 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 2229 FcChar8 *n = FcConfigFilename (url); 2230 FcChar8 *nn = NULL; 2231 2232 if (n) 2233 { 2234 FcChar8 buf[PATH_MAX]; 2235 ssize_t len; 2236 2237 if (sysroot) 2238 nn = FcStrBuildFilename (sysroot, n, NULL); 2239 else 2240 nn = FcStrdup (n); 2241 FcStrFree (n); 2242 2243 if ((len = FcReadLink (nn, buf, sizeof (buf) - 1)) != -1) 2244 { 2245 buf[len] = 0; 2246 2247 if (!FcStrIsAbsoluteFilename (buf)) 2248 { 2249 FcChar8 *dirname = FcStrDirname (nn); 2250 FcStrFree (nn); 2251 if (!dirname) 2252 return NULL; 2253 2254 FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL); 2255 FcStrFree (dirname); 2256 if (!path) 2257 return NULL; 2258 2259 nn = FcStrCanonFilename (path); 2260 FcStrFree (path); 2261 } 2262 else 2263 { 2264 FcStrFree (nn); 2265 nn = FcStrdup (buf); 2266 } 2267 } 2268 } 2269 2270 return nn; 2271} 2272 2273/* 2274 * Manage the application-specific fonts 2275 */ 2276 2277FcBool 2278FcConfigAppFontAddFile (FcConfig *config, 2279 const FcChar8 *file) 2280{ 2281 FcFontSet *set; 2282 FcStrSet *subdirs; 2283 FcStrList *sublist; 2284 FcChar8 *subdir; 2285 2286 if (!config) 2287 { 2288 config = FcConfigGetCurrent (); 2289 if (!config) 2290 return FcFalse; 2291 } 2292 2293 subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 2294 if (!subdirs) 2295 return FcFalse; 2296 2297 set = FcConfigGetFonts (config, FcSetApplication); 2298 if (!set) 2299 { 2300 set = FcFontSetCreate (); 2301 if (!set) 2302 { 2303 FcStrSetDestroy (subdirs); 2304 return FcFalse; 2305 } 2306 FcConfigSetFonts (config, set, FcSetApplication); 2307 } 2308 2309 if (!FcFileScanConfig (set, subdirs, file, config)) 2310 { 2311 FcStrSetDestroy (subdirs); 2312 return FcFalse; 2313 } 2314 if ((sublist = FcStrListCreate (subdirs))) 2315 { 2316 while ((subdir = FcStrListNext (sublist))) 2317 { 2318 FcConfigAppFontAddDir (config, subdir); 2319 } 2320 FcStrListDone (sublist); 2321 } 2322 FcStrSetDestroy (subdirs); 2323 return FcTrue; 2324} 2325 2326FcBool 2327FcConfigAppFontAddDir (FcConfig *config, 2328 const FcChar8 *dir) 2329{ 2330 FcFontSet *set; 2331 FcStrSet *dirs; 2332 2333 if (!config) 2334 { 2335 config = FcConfigGetCurrent (); 2336 if (!config) 2337 return FcFalse; 2338 } 2339 2340 dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 2341 if (!dirs) 2342 return FcFalse; 2343 2344 set = FcConfigGetFonts (config, FcSetApplication); 2345 if (!set) 2346 { 2347 set = FcFontSetCreate (); 2348 if (!set) 2349 { 2350 FcStrSetDestroy (dirs); 2351 return FcFalse; 2352 } 2353 FcConfigSetFonts (config, set, FcSetApplication); 2354 } 2355 2356 FcStrSetAddFilename (dirs, dir); 2357 2358 if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 2359 { 2360 FcStrSetDestroy (dirs); 2361 return FcFalse; 2362 } 2363 FcStrSetDestroy (dirs); 2364 return FcTrue; 2365} 2366 2367void 2368FcConfigAppFontClear (FcConfig *config) 2369{ 2370 if (!config) 2371 { 2372 config = FcConfigGetCurrent (); 2373 if (!config) 2374 return; 2375 } 2376 2377 FcConfigSetFonts (config, 0, FcSetApplication); 2378} 2379 2380/* 2381 * Manage filename-based font source selectors 2382 */ 2383 2384FcBool 2385FcConfigGlobAdd (FcConfig *config, 2386 const FcChar8 *glob, 2387 FcBool accept) 2388{ 2389 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 2390 2391 return FcStrSetAdd (set, glob); 2392} 2393 2394static FcBool 2395FcConfigGlobsMatch (const FcStrSet *globs, 2396 const FcChar8 *string) 2397{ 2398 int i; 2399 2400 for (i = 0; i < globs->num; i++) 2401 if (FcStrGlobMatch (globs->strs[i], string)) 2402 return FcTrue; 2403 return FcFalse; 2404} 2405 2406FcBool 2407FcConfigAcceptFilename (FcConfig *config, 2408 const FcChar8 *filename) 2409{ 2410 if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 2411 return FcTrue; 2412 if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 2413 return FcFalse; 2414 return FcTrue; 2415} 2416 2417/* 2418 * Manage font-pattern based font source selectors 2419 */ 2420 2421FcBool 2422FcConfigPatternsAdd (FcConfig *config, 2423 FcPattern *pattern, 2424 FcBool accept) 2425{ 2426 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 2427 2428 return FcFontSetAdd (set, pattern); 2429} 2430 2431static FcBool 2432FcConfigPatternsMatch (const FcFontSet *patterns, 2433 const FcPattern *font) 2434{ 2435 int i; 2436 2437 for (i = 0; i < patterns->nfont; i++) 2438 if (FcListPatternMatchAny (patterns->fonts[i], font)) 2439 return FcTrue; 2440 return FcFalse; 2441} 2442 2443FcBool 2444FcConfigAcceptFont (FcConfig *config, 2445 const FcPattern *font) 2446{ 2447 if (FcConfigPatternsMatch (config->acceptPatterns, font)) 2448 return FcTrue; 2449 if (FcConfigPatternsMatch (config->rejectPatterns, font)) 2450 return FcFalse; 2451 return FcTrue; 2452} 2453 2454const FcChar8 * 2455FcConfigGetSysRoot (const FcConfig *config) 2456{ 2457 if (!config) 2458 { 2459 config = FcConfigGetCurrent (); 2460 if (!config) 2461 return NULL; 2462 } 2463 2464 if (config->sysRoot) 2465 return config->sysRoot; 2466 2467 return (FcChar8 *) getenv ("FONTCONFIG_SYSROOT"); 2468} 2469 2470void 2471FcConfigSetSysRoot (FcConfig *config, 2472 const FcChar8 *sysroot) 2473{ 2474 FcChar8 *s = NULL; 2475 FcBool init = FcFalse; 2476 2477 if (!config) 2478 { 2479 /* We can't use FcConfigGetCurrent() here to ensure 2480 * the sysroot is set prior to initialize FcConfig, 2481 * to avoid loading caches from non-sysroot dirs. 2482 * So postpone the initialization later. 2483 */ 2484 config = fc_atomic_ptr_get (&_fcConfig); 2485 if (!config) 2486 { 2487 config = FcConfigCreate (); 2488 if (!config) 2489 return; 2490 init = FcTrue; 2491 } 2492 } 2493 2494 if (sysroot) 2495 { 2496 s = FcStrCopyFilename (sysroot); 2497 if (!s) 2498 return; 2499 } 2500 2501 if (config->sysRoot) 2502 FcStrFree (config->sysRoot); 2503 2504 config->sysRoot = s; 2505 if (init) 2506 { 2507 config = FcInitLoadOwnConfigAndFonts (config); 2508 FcConfigSetCurrent (config); 2509 /* FcConfigSetCurrent() increases the refcount. 2510 * decrease it here to avoid the memory leak. 2511 */ 2512 FcConfigDestroy (config); 2513 } 2514} 2515 2516FcRuleSet * 2517FcRuleSetCreate (const FcChar8 *name) 2518{ 2519 FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet)); 2520 FcMatchKind k; 2521 const FcChar8 *p; 2522 2523 if (!name) 2524 p = (const FcChar8 *)""; 2525 else 2526 p = name; 2527 2528 if (ret) 2529 { 2530 ret->name = FcStrdup (p); 2531 ret->description = NULL; 2532 ret->domain = NULL; 2533 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 2534 ret->subst[k] = FcPtrListCreate (FcDestroyAsRule); 2535 FcRefInit (&ret->ref, 1); 2536 } 2537 2538 return ret; 2539} 2540 2541void 2542FcRuleSetDestroy (FcRuleSet *rs) 2543{ 2544 FcMatchKind k; 2545 2546 if (!rs) 2547 return; 2548 if (FcRefDec (&rs->ref) != 1) 2549 return; 2550 2551 if (rs->name) 2552 FcStrFree (rs->name); 2553 if (rs->description) 2554 FcStrFree (rs->description); 2555 if (rs->domain) 2556 FcStrFree (rs->domain); 2557 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 2558 FcPtrListDestroy (rs->subst[k]); 2559 2560 free (rs); 2561} 2562 2563void 2564FcRuleSetReference (FcRuleSet *rs) 2565{ 2566 if (!FcRefIsConst (&rs->ref)) 2567 FcRefInc (&rs->ref); 2568} 2569 2570void 2571FcRuleSetEnable (FcRuleSet *rs, 2572 FcBool flag) 2573{ 2574 if (rs) 2575 { 2576 rs->enabled = flag; 2577 /* XXX: we may want to provide a feature 2578 * to enable/disable rulesets through API 2579 * in the future? 2580 */ 2581 } 2582} 2583 2584void 2585FcRuleSetAddDescription (FcRuleSet *rs, 2586 const FcChar8 *domain, 2587 const FcChar8 *description) 2588{ 2589 if (rs->domain) 2590 FcStrFree (rs->domain); 2591 if (rs->description) 2592 FcStrFree (rs->description); 2593 2594 rs->domain = domain ? FcStrdup (domain) : NULL; 2595 rs->description = description ? FcStrdup (description) : NULL; 2596} 2597 2598int 2599FcRuleSetAdd (FcRuleSet *rs, 2600 FcRule *rule, 2601 FcMatchKind kind) 2602{ 2603 FcPtrListIter iter; 2604 FcRule *r; 2605 int n = 0, ret; 2606 2607 if (!rs || 2608 kind < FcMatchKindBegin || kind >= FcMatchKindEnd) 2609 return -1; 2610 FcPtrListIterInitAtLast (rs->subst[kind], &iter); 2611 if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule)) 2612 return -1; 2613 2614 for (r = rule; r; r = r->next) 2615 { 2616 switch (r->type) 2617 { 2618 case FcRuleTest: 2619 if (r->u.test) 2620 { 2621 if (r->u.test->kind == FcMatchDefault) 2622 r->u.test->kind = kind; 2623 if (n < r->u.test->object) 2624 n = r->u.test->object; 2625 } 2626 break; 2627 case FcRuleEdit: 2628 if (n < r->u.edit->object) 2629 n = r->u.edit->object; 2630 break; 2631 default: 2632 break; 2633 } 2634 } 2635 if (FcDebug () & FC_DBG_EDIT) 2636 { 2637 printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name); 2638 FcRulePrint (rule); 2639 } 2640 ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; 2641 2642 return ret < 0 ? 0 : ret; 2643} 2644 2645void 2646FcConfigFileInfoIterInit (FcConfig *config, 2647 FcConfigFileInfoIter *iter) 2648{ 2649 FcConfig *c; 2650 FcPtrListIter *i = (FcPtrListIter *)iter; 2651 2652 if (!config) 2653 c = FcConfigGetCurrent (); 2654 else 2655 c = config; 2656 FcPtrListIterInit (c->rulesetList, i); 2657} 2658 2659FcBool 2660FcConfigFileInfoIterNext (FcConfig *config, 2661 FcConfigFileInfoIter *iter) 2662{ 2663 FcConfig *c; 2664 FcPtrListIter *i = (FcPtrListIter *)iter; 2665 2666 if (!config) 2667 c = FcConfigGetCurrent (); 2668 else 2669 c = config; 2670 if (FcPtrListIterIsValid (c->rulesetList, i)) 2671 { 2672 FcPtrListIterNext (c->rulesetList, i); 2673 } 2674 else 2675 return FcFalse; 2676 2677 return FcTrue; 2678} 2679 2680FcBool 2681FcConfigFileInfoIterGet (FcConfig *config, 2682 FcConfigFileInfoIter *iter, 2683 FcChar8 **name, 2684 FcChar8 **description, 2685 FcBool *enabled) 2686{ 2687 FcConfig *c; 2688 FcRuleSet *r; 2689 FcPtrListIter *i = (FcPtrListIter *)iter; 2690 2691 if (!config) 2692 c = FcConfigGetCurrent (); 2693 else 2694 c = config; 2695 if (!FcPtrListIterIsValid (c->rulesetList, i)) 2696 return FcFalse; 2697 r = FcPtrListIterGetValue (c->rulesetList, i); 2698 if (name) 2699 *name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf"); 2700 if (description) 2701 *description = FcStrdup (!r->description ? _("No description") : 2702 dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf", 2703 (const char *) r->description)); 2704 if (enabled) 2705 *enabled = r->enabled; 2706 2707 return FcTrue; 2708} 2709 2710#define __fccfg__ 2711#include "fcaliastail.h" 2712#undef __fccfg__ 2713