fcmatch.c revision d81fd2f8
1/* 2 * fontconfig/src/fcmatch.c 3 * 4 * Copyright © 2000 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "fcint.h" 26#include <float.h> 27 28 29static double 30FcCompareNumber (FcValue *value1, FcValue *value2) 31{ 32 double v1, v2, v; 33 34 switch ((int) value1->type) { 35 case FcTypeInteger: 36 v1 = (double) value1->u.i; 37 break; 38 case FcTypeDouble: 39 v1 = value1->u.d; 40 break; 41 default: 42 return -1.0; 43 } 44 switch ((int) value2->type) { 45 case FcTypeInteger: 46 v2 = (double) value2->u.i; 47 break; 48 case FcTypeDouble: 49 v2 = value2->u.d; 50 break; 51 default: 52 return -1.0; 53 } 54 v = v2 - v1; 55 if (v < 0) 56 v = -v; 57 return v; 58} 59 60static double 61FcCompareString (FcValue *v1, FcValue *v2) 62{ 63 return (double) FcStrCmpIgnoreCase (FcValueString(v1), FcValueString(v2)) != 0; 64} 65 66static double 67FcCompareFamily (FcValue *v1, FcValue *v2) 68{ 69 /* rely on the guarantee in FcPatternObjectAddWithBinding that 70 * families are always FcTypeString. */ 71 const FcChar8* v1_string = FcValueString(v1); 72 const FcChar8* v2_string = FcValueString(v2); 73 74 if (FcToLower(*v1_string) != FcToLower(*v2_string) && 75 *v1_string != ' ' && *v2_string != ' ') 76 return 1.0; 77 78 return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0; 79} 80 81static double 82FcComparePostScript (FcValue *v1, FcValue *v2) 83{ 84 const FcChar8 *v1_string = FcValueString (v1); 85 const FcChar8 *v2_string = FcValueString (v2); 86 int n; 87 size_t len; 88 89 if (FcToLower (*v1_string) != FcToLower (*v2_string) && 90 *v1_string != ' ' && *v2_string != ' ') 91 return 1.0; 92 93 n = FcStrMatchIgnoreCaseAndDelims (v1_string, v2_string, (const FcChar8 *)" -"); 94 len = strlen ((const char *)v1_string); 95 96 return (double)(len - n) / (double)len; 97} 98 99static double 100FcCompareLang (FcValue *v1, FcValue *v2) 101{ 102 FcLangResult result; 103 FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2); 104 105 switch ((int) value1.type) { 106 case FcTypeLangSet: 107 switch ((int) value2.type) { 108 case FcTypeLangSet: 109 result = FcLangSetCompare (value1.u.l, value2.u.l); 110 break; 111 case FcTypeString: 112 result = FcLangSetHasLang (value1.u.l, 113 value2.u.s); 114 break; 115 default: 116 return -1.0; 117 } 118 break; 119 case FcTypeString: 120 switch ((int) value2.type) { 121 case FcTypeLangSet: 122 result = FcLangSetHasLang (value2.u.l, value1.u.s); 123 break; 124 case FcTypeString: 125 result = FcLangCompare (value1.u.s, 126 value2.u.s); 127 break; 128 default: 129 return -1.0; 130 } 131 break; 132 default: 133 return -1.0; 134 } 135 switch (result) { 136 case FcLangEqual: 137 return 0; 138 case FcLangDifferentCountry: 139 return 1; 140 case FcLangDifferentLang: 141 default: 142 return 2; 143 } 144} 145 146static double 147FcCompareBool (FcValue *v1, FcValue *v2) 148{ 149 if (v2->type != FcTypeBool || v1->type != FcTypeBool) 150 return -1.0; 151 return (double) v2->u.b != v1->u.b; 152} 153 154static double 155FcCompareCharSet (FcValue *v1, FcValue *v2) 156{ 157 return (double) FcCharSetSubtractCount (FcValueCharSet(v1), FcValueCharSet(v2)); 158} 159 160static double 161FcCompareSize (FcValue *value1, FcValue *value2) 162{ 163 double v1, v2, v; 164 165 switch ((int) value1->type) { 166 case FcTypeInteger: 167 v1 = value1->u.i; 168 break; 169 case FcTypeDouble: 170 v1 = value1->u.d; 171 break; 172 default: 173 return -1; 174 } 175 switch ((int) value2->type) { 176 case FcTypeInteger: 177 v2 = value2->u.i; 178 break; 179 case FcTypeDouble: 180 v2 = value2->u.d; 181 break; 182 default: 183 return -1; 184 } 185 if (v2 == 0) 186 return 0; 187 v = v2 - v1; 188 if (v < 0) 189 v = -v; 190 return v; 191} 192 193static double 194FcCompareFilename (FcValue *v1, FcValue *v2) 195{ 196 const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2); 197 if (FcStrCmp (s1, s2) == 0) 198 return 0.0; 199 else if (FcStrCmpIgnoreCase (s1, s2) == 0) 200 return 1.0; 201 else if (FcStrGlobMatch (s1, s2)) 202 return 2.0; 203 else 204 return 3.0; 205} 206 207static double 208FcCompareHash (FcValue *v1, FcValue *v2) 209{ 210 const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2); 211 212 /* Do not match an empty string */ 213 if (!s1 || !s2 || !s1[0] || !s2[0]) 214 return 1.0; 215 return FcCompareString (v1, v2); 216} 217 218#define PRI_NULL(n) \ 219 PRI_ ## n ## _STRONG = -1, \ 220 PRI_ ## n ## _WEAK = -1, 221#define PRI1(n) 222#define PRI_FcCompareFamily(n) PRI1(n) 223#define PRI_FcCompareString(n) PRI1(n) 224#define PRI_FcCompareNumber(n) PRI1(n) 225#define PRI_FcCompareSize(n) PRI1(n) 226#define PRI_FcCompareBool(n) PRI1(n) 227#define PRI_FcCompareFilename(n) PRI1(n) 228#define PRI_FcCompareCharSet(n) PRI1(n) 229#define PRI_FcCompareLang(n) PRI1(n) 230#define PRI_FcComparePostScript(n) PRI1(n) 231#define PRI_FcCompareHash(n) PRI1(n) 232 233#define FC_OBJECT(NAME, Type, Cmp) PRI_##Cmp(NAME) 234 235typedef enum _FcMatcherPriorityDummy { 236#include "fcobjs.h" 237} FcMatcherPriorityDummy; 238 239#undef FC_OBJECT 240 241#undef PRI1 242#define PRI1(n) \ 243 PRI_ ## n, \ 244 PRI_ ## n ## _STRONG = PRI_ ## n, \ 245 PRI_ ## n ## _WEAK = PRI_ ## n 246 247typedef enum _FcMatcherPriority { 248 PRI1(HASH), 249 PRI1(FILE), 250 PRI1(FOUNDRY), 251 PRI1(CHARSET), 252 PRI_FAMILY_STRONG, 253 PRI_POSTSCRIPT_NAME_STRONG, 254 PRI1(LANG), 255 PRI_FAMILY_WEAK, 256 PRI_POSTSCRIPT_NAME_WEAK, 257 PRI1(SPACING), 258 PRI1(PIXEL_SIZE), 259 PRI1(STYLE), 260 PRI1(SLANT), 261 PRI1(WEIGHT), 262 PRI1(WIDTH), 263 PRI1(DECORATIVE), 264 PRI1(ANTIALIAS), 265 PRI1(RASTERIZER), 266 PRI1(OUTLINE), 267 PRI1(FONTVERSION), 268 PRI_END 269} FcMatcherPriority; 270 271#undef PRI1 272 273typedef struct _FcMatcher { 274 FcObject object; 275 double (*compare) (FcValue *value1, FcValue *value2); 276 int strong, weak; 277} FcMatcher; 278 279/* 280 * Order is significant, it defines the precedence of 281 * each value, earlier values are more significant than 282 * later values 283 */ 284#define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME##_OBJECT, Cmp, PRI_##NAME##_STRONG, PRI_##NAME##_WEAK }, 285static const FcMatcher _FcMatchers [] = { 286 { FC_INVALID_OBJECT, NULL, -1, -1 }, 287#include "fcobjs.h" 288}; 289#undef FC_OBJECT 290 291static const FcMatcher* 292FcObjectToMatcher (FcObject object, 293 FcBool include_lang) 294{ 295 if (include_lang) 296 { 297 switch (object) { 298 case FC_FAMILYLANG_OBJECT: 299 case FC_STYLELANG_OBJECT: 300 case FC_FULLNAMELANG_OBJECT: 301 object = FC_LANG_OBJECT; 302 break; 303 } 304 } 305 if (object > FC_MAX_BASE_OBJECT || 306 !_FcMatchers[object].compare || 307 _FcMatchers[object].strong == -1 || 308 _FcMatchers[object].weak == -1) 309 return NULL; 310 311 return _FcMatchers + object; 312} 313 314static FcBool 315FcCompareValueList (FcObject object, 316 const FcMatcher *match, 317 FcValueListPtr v1orig, /* pattern */ 318 FcValueListPtr v2orig, /* target */ 319 FcValue *bestValue, 320 double *value, 321 int *n, 322 FcResult *result) 323{ 324 FcValueListPtr v1, v2; 325 double v, best, bestStrong, bestWeak; 326 int j, k, pos = 0; 327 328 if (!match) 329 { 330 if (bestValue) 331 *bestValue = FcValueCanonicalize(&v2orig->value); 332 if (n) 333 *n = 0; 334 return FcTrue; 335 } 336 337 best = DBL_MAX; 338 bestStrong = DBL_MAX; 339 bestWeak = DBL_MAX; 340 j = 1; 341 for (v1 = v1orig; v1; v1 = FcValueListNext(v1)) 342 { 343 for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext(v2), k++) 344 { 345 v = (match->compare) (&v1->value, &v2->value); 346 if (v < 0) 347 { 348 *result = FcResultTypeMismatch; 349 return FcFalse; 350 } 351 v = v * 1000 + j; 352 if (v < best) 353 { 354 if (bestValue) 355 *bestValue = FcValueCanonicalize(&v2->value); 356 best = v; 357 pos = k; 358 } 359 if (v1->binding == FcValueBindingStrong) 360 { 361 if (v < bestStrong) 362 bestStrong = v; 363 } 364 else 365 { 366 if (v < bestWeak) 367 bestWeak = v; 368 } 369 } 370 j++; 371 } 372 if (FcDebug () & FC_DBG_MATCHV) 373 { 374 printf (" %s: %g ", FcObjectName (object), best); 375 FcValueListPrint (v1orig); 376 printf (", "); 377 FcValueListPrint (v2orig); 378 printf ("\n"); 379 } 380 if (value) 381 { 382 int weak = match->weak; 383 int strong = match->strong; 384 if (weak == strong) 385 value[strong] += best; 386 else 387 { 388 value[weak] += bestWeak; 389 value[strong] += bestStrong; 390 } 391 } 392 if (n) 393 *n = pos; 394 395 return FcTrue; 396} 397 398/* 399 * Return a value indicating the distance between the two lists of 400 * values 401 */ 402 403static FcBool 404FcCompare (FcPattern *pat, 405 FcPattern *fnt, 406 double *value, 407 FcResult *result) 408{ 409 int i, i1, i2; 410 411 for (i = 0; i < PRI_END; i++) 412 value[i] = 0.0; 413 414 i1 = 0; 415 i2 = 0; 416 while (i1 < pat->num && i2 < fnt->num) 417 { 418 FcPatternElt *elt_i1 = &FcPatternElts(pat)[i1]; 419 FcPatternElt *elt_i2 = &FcPatternElts(fnt)[i2]; 420 421 i = FcObjectCompare(elt_i1->object, elt_i2->object); 422 if (i > 0) 423 i2++; 424 else if (i < 0) 425 i1++; 426 else 427 { 428 const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse); 429 if (!FcCompareValueList (elt_i1->object, match, 430 FcPatternEltValues(elt_i1), 431 FcPatternEltValues(elt_i2), 432 NULL, value, NULL, result)) 433 return FcFalse; 434 i1++; 435 i2++; 436 } 437 } 438 return FcTrue; 439} 440 441FcPattern * 442FcFontRenderPrepare (FcConfig *config, 443 FcPattern *pat, 444 FcPattern *font) 445{ 446 FcPattern *new; 447 int i; 448 FcPatternElt *fe, *pe, *fel, *pel; 449 FcValue v; 450 FcResult result; 451 452 assert (pat != NULL); 453 assert (font != NULL); 454 455 new = FcPatternCreate (); 456 if (!new) 457 return NULL; 458 for (i = 0; i < font->num; i++) 459 { 460 fe = &FcPatternElts(font)[i]; 461 if (fe->object == FC_FAMILYLANG_OBJECT || 462 fe->object == FC_STYLELANG_OBJECT || 463 fe->object == FC_FULLNAMELANG_OBJECT) 464 { 465 /* ignore those objects. we need to deal with them 466 * another way */ 467 continue; 468 } 469 if (fe->object == FC_FAMILY_OBJECT || 470 fe->object == FC_STYLE_OBJECT || 471 fe->object == FC_FULLNAME_OBJECT) 472 { 473 FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT); 474 FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT); 475 FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT); 476 477 fel = FcPatternObjectFindElt (font, fe->object + 1); 478 pel = FcPatternObjectFindElt (pat, fe->object + 1); 479 } 480 else 481 { 482 fel = NULL; 483 pel = NULL; 484 } 485 pe = FcPatternObjectFindElt (pat, fe->object); 486 if (pe) 487 { 488 const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse); 489 490 if (!FcCompareValueList (pe->object, match, 491 FcPatternEltValues(pe), 492 FcPatternEltValues(fe), &v, NULL, NULL, &result)) 493 { 494 FcPatternDestroy (new); 495 return NULL; 496 } 497 if (fel && pel) 498 { 499 int n = 1, j; 500 FcValueListPtr l1, l2, ln = NULL, ll = NULL; 501 502 match = FcObjectToMatcher (pel->object, FcTrue); 503 if (!FcCompareValueList (pel->object, match, 504 FcPatternEltValues (pel), 505 FcPatternEltValues (fel), NULL, NULL, &n, &result)) 506 { 507 FcPatternDestroy (new); 508 return NULL; 509 } 510 511 for (j = 0, l1 = FcPatternEltValues (fe), l2 = FcPatternEltValues (fel); 512 l1 != NULL || l2 != NULL; 513 j++, l1 = l1 ? FcValueListNext (l1) : NULL, l2 = l2 ? FcValueListNext (l2) : NULL) 514 { 515 if (j == n) 516 { 517 if (l1) 518 ln = FcValueListPrepend (ln, 519 FcValueCanonicalize (&l1->value), 520 FcValueBindingStrong); 521 if (l2) 522 ll = FcValueListPrepend (ll, 523 FcValueCanonicalize (&l2->value), 524 FcValueBindingStrong); 525 } 526 else 527 { 528 if (l1) 529 ln = FcValueListAppend (ln, 530 FcValueCanonicalize (&l1->value), 531 FcValueBindingStrong); 532 if (l2) 533 ll = FcValueListAppend (ll, 534 FcValueCanonicalize (&l2->value), 535 FcValueBindingStrong); 536 } 537 } 538 FcPatternObjectListAdd (new, fe->object, ln, FcFalse); 539 FcPatternObjectListAdd (new, fel->object, ll, FcFalse); 540 541 continue; 542 } 543 else if (fel) 544 { 545 FcValueListPtr l1, l2; 546 547 copy_lang: 548 l1 = FcValueListDuplicate (FcPatternEltValues (fe)); 549 l2 = FcValueListDuplicate (FcPatternEltValues (fel)); 550 FcPatternObjectListAdd (new, fe->object, l1, FcFalse); 551 FcPatternObjectListAdd (new, fel->object, l2, FcFalse); 552 553 continue; 554 } 555 } 556 else 557 { 558 if (fel) 559 goto copy_lang; 560 v = FcValueCanonicalize(&FcPatternEltValues (fe)->value); 561 } 562 FcPatternObjectAdd (new, fe->object, v, FcFalse); 563 } 564 for (i = 0; i < pat->num; i++) 565 { 566 pe = &FcPatternElts(pat)[i]; 567 fe = FcPatternObjectFindElt (font, pe->object); 568 if (!fe && 569 pe->object != FC_FAMILYLANG_OBJECT && 570 pe->object != FC_STYLELANG_OBJECT && 571 pe->object != FC_FULLNAMELANG_OBJECT) 572 { 573 FcPatternObjectListAdd (new, pe->object, 574 FcValueListDuplicate (FcPatternEltValues(pe)), 575 FcFalse); 576 } 577 } 578 579 FcConfigSubstituteWithPat (config, new, pat, FcMatchFont); 580 return new; 581} 582 583static FcPattern * 584FcFontSetMatchInternal (FcFontSet **sets, 585 int nsets, 586 FcPattern *p, 587 FcResult *result) 588{ 589 double score[PRI_END], bestscore[PRI_END]; 590 int f; 591 FcFontSet *s; 592 FcPattern *best; 593 int i; 594 int set; 595 596 for (i = 0; i < PRI_END; i++) 597 bestscore[i] = 0; 598 best = 0; 599 if (FcDebug () & FC_DBG_MATCH) 600 { 601 printf ("Match "); 602 FcPatternPrint (p); 603 } 604 for (set = 0; set < nsets; set++) 605 { 606 s = sets[set]; 607 if (!s) 608 continue; 609 for (f = 0; f < s->nfont; f++) 610 { 611 if (FcDebug () & FC_DBG_MATCHV) 612 { 613 printf ("Font %d ", f); 614 FcPatternPrint (s->fonts[f]); 615 } 616 if (!FcCompare (p, s->fonts[f], score, result)) 617 return 0; 618 if (FcDebug () & FC_DBG_MATCHV) 619 { 620 printf ("Score"); 621 for (i = 0; i < PRI_END; i++) 622 { 623 printf (" %g", score[i]); 624 } 625 printf ("\n"); 626 } 627 for (i = 0; i < PRI_END; i++) 628 { 629 if (best && bestscore[i] < score[i]) 630 break; 631 if (!best || score[i] < bestscore[i]) 632 { 633 for (i = 0; i < PRI_END; i++) 634 bestscore[i] = score[i]; 635 best = s->fonts[f]; 636 break; 637 } 638 } 639 } 640 } 641 if (FcDebug () & FC_DBG_MATCH) 642 { 643 printf ("Best score"); 644 for (i = 0; i < PRI_END; i++) 645 printf (" %g", bestscore[i]); 646 printf ("\n"); 647 FcPatternPrint (best); 648 } 649 /* assuming that 'result' is initialized with FcResultNoMatch 650 * outside this function */ 651 if (best) 652 *result = FcResultMatch; 653 654 return best; 655} 656 657FcPattern * 658FcFontSetMatch (FcConfig *config, 659 FcFontSet **sets, 660 int nsets, 661 FcPattern *p, 662 FcResult *result) 663{ 664 FcPattern *best; 665 666 assert (sets != NULL); 667 assert (p != NULL); 668 assert (result != NULL); 669 670 *result = FcResultNoMatch; 671 672 if (!config) 673 { 674 config = FcConfigGetCurrent (); 675 if (!config) 676 return 0; 677 } 678 best = FcFontSetMatchInternal (sets, nsets, p, result); 679 if (best) 680 return FcFontRenderPrepare (config, p, best); 681 else 682 return NULL; 683} 684 685FcPattern * 686FcFontMatch (FcConfig *config, 687 FcPattern *p, 688 FcResult *result) 689{ 690 FcFontSet *sets[2]; 691 int nsets; 692 FcPattern *best; 693 694 assert (p != NULL); 695 assert (result != NULL); 696 697 *result = FcResultNoMatch; 698 699 if (!config) 700 { 701 config = FcConfigGetCurrent (); 702 if (!config) 703 return 0; 704 } 705 nsets = 0; 706 if (config->fonts[FcSetSystem]) 707 sets[nsets++] = config->fonts[FcSetSystem]; 708 if (config->fonts[FcSetApplication]) 709 sets[nsets++] = config->fonts[FcSetApplication]; 710 711 best = FcFontSetMatchInternal (sets, nsets, p, result); 712 if (best) 713 return FcFontRenderPrepare (config, p, best); 714 else 715 return NULL; 716} 717 718typedef struct _FcSortNode { 719 FcPattern *pattern; 720 double score[PRI_END]; 721} FcSortNode; 722 723static int 724FcSortCompare (const void *aa, const void *ab) 725{ 726 FcSortNode *a = *(FcSortNode **) aa; 727 FcSortNode *b = *(FcSortNode **) ab; 728 double *as = &a->score[0]; 729 double *bs = &b->score[0]; 730 double ad = 0, bd = 0; 731 int i; 732 733 i = PRI_END; 734 while (i-- && (ad = *as++) == (bd = *bs++)) 735 ; 736 return ad < bd ? -1 : ad > bd ? 1 : 0; 737} 738 739static FcBool 740FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim) 741{ 742 FcBool ret = FcFalse; 743 FcCharSet *cs; 744 745 cs = 0; 746 if (trim || csp) 747 { 748 cs = FcCharSetCreate (); 749 if (cs == NULL) 750 goto bail; 751 } 752 753 while (nnode--) 754 { 755 FcSortNode *node = *n++; 756 FcBool adds_chars = FcFalse; 757 758 /* 759 * Only fetch node charset if we'd need it 760 */ 761 if (cs) 762 { 763 FcCharSet *ncs; 764 765 if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) != 766 FcResultMatch) 767 continue; 768 769 if (!FcCharSetMerge (cs, ncs, &adds_chars)) 770 goto bail; 771 } 772 773 /* 774 * If this font isn't a subset of the previous fonts, 775 * add it to the list 776 */ 777 if (!trim || adds_chars) 778 { 779 FcPatternReference (node->pattern); 780 if (FcDebug () & FC_DBG_MATCHV) 781 { 782 printf ("Add "); 783 FcPatternPrint (node->pattern); 784 } 785 if (!FcFontSetAdd (fs, node->pattern)) 786 { 787 FcPatternDestroy (node->pattern); 788 goto bail; 789 } 790 } 791 } 792 if (csp) 793 { 794 *csp = cs; 795 cs = 0; 796 } 797 798 ret = FcTrue; 799 800bail: 801 if (cs) 802 FcCharSetDestroy (cs); 803 804 return ret; 805} 806 807void 808FcFontSetSortDestroy (FcFontSet *fs) 809{ 810 FcFontSetDestroy (fs); 811} 812 813FcFontSet * 814FcFontSetSort (FcConfig *config FC_UNUSED, 815 FcFontSet **sets, 816 int nsets, 817 FcPattern *p, 818 FcBool trim, 819 FcCharSet **csp, 820 FcResult *result) 821{ 822 FcFontSet *ret; 823 FcFontSet *s; 824 FcSortNode *nodes; 825 FcSortNode **nodeps, **nodep; 826 int nnodes; 827 FcSortNode *new; 828 int set; 829 int f; 830 int i; 831 int nPatternLang; 832 FcBool *patternLangSat; 833 FcValue patternLang; 834 835 assert (sets != NULL); 836 assert (p != NULL); 837 assert (result != NULL); 838 839 /* There are some implementation that relying on the result of 840 * "result" to check if the return value of FcFontSetSort 841 * is valid or not. 842 * So we should initialize it to the conservative way since 843 * this function doesn't return NULL anymore. 844 */ 845 if (result) 846 *result = FcResultNoMatch; 847 848 if (FcDebug () & FC_DBG_MATCH) 849 { 850 printf ("Sort "); 851 FcPatternPrint (p); 852 } 853 nnodes = 0; 854 for (set = 0; set < nsets; set++) 855 { 856 s = sets[set]; 857 if (!s) 858 continue; 859 nnodes += s->nfont; 860 } 861 if (!nnodes) 862 return FcFontSetCreate (); 863 864 for (nPatternLang = 0; 865 FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch; 866 nPatternLang++) 867 ; 868 869 /* freed below */ 870 nodes = malloc (nnodes * sizeof (FcSortNode) + 871 nnodes * sizeof (FcSortNode *) + 872 nPatternLang * sizeof (FcBool)); 873 if (!nodes) 874 goto bail0; 875 nodeps = (FcSortNode **) (nodes + nnodes); 876 patternLangSat = (FcBool *) (nodeps + nnodes); 877 878 new = nodes; 879 nodep = nodeps; 880 for (set = 0; set < nsets; set++) 881 { 882 s = sets[set]; 883 if (!s) 884 continue; 885 for (f = 0; f < s->nfont; f++) 886 { 887 if (FcDebug () & FC_DBG_MATCHV) 888 { 889 printf ("Font %d ", f); 890 FcPatternPrint (s->fonts[f]); 891 } 892 new->pattern = s->fonts[f]; 893 if (!FcCompare (p, new->pattern, new->score, result)) 894 goto bail1; 895 if (FcDebug () & FC_DBG_MATCHV) 896 { 897 printf ("Score"); 898 for (i = 0; i < PRI_END; i++) 899 { 900 printf (" %g", new->score[i]); 901 } 902 printf ("\n"); 903 } 904 *nodep = new; 905 new++; 906 nodep++; 907 } 908 } 909 910 nnodes = new - nodes; 911 912 qsort (nodeps, nnodes, sizeof (FcSortNode *), 913 FcSortCompare); 914 915 for (i = 0; i < nPatternLang; i++) 916 patternLangSat[i] = FcFalse; 917 918 for (f = 0; f < nnodes; f++) 919 { 920 FcBool satisfies = FcFalse; 921 /* 922 * If this node matches any language, go check 923 * which ones and satisfy those entries 924 */ 925 if (nodeps[f]->score[PRI_LANG] < 2000) 926 { 927 for (i = 0; i < nPatternLang; i++) 928 { 929 FcValue nodeLang; 930 931 if (!patternLangSat[i] && 932 FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch && 933 FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch) 934 { 935 double compare = FcCompareLang (&patternLang, &nodeLang); 936 if (compare >= 0 && compare < 2) 937 { 938 if (FcDebug () & FC_DBG_MATCHV) 939 { 940 FcChar8 *family; 941 FcChar8 *style; 942 943 if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch && 944 FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch) 945 printf ("Font %s:%s matches language %d\n", family, style, i); 946 } 947 patternLangSat[i] = FcTrue; 948 satisfies = FcTrue; 949 break; 950 } 951 } 952 } 953 } 954 if (!satisfies) 955 { 956 nodeps[f]->score[PRI_LANG] = 10000.0; 957 } 958 } 959 960 /* 961 * Re-sort once the language issues have been settled 962 */ 963 qsort (nodeps, nnodes, sizeof (FcSortNode *), 964 FcSortCompare); 965 966 ret = FcFontSetCreate (); 967 if (!ret) 968 goto bail1; 969 970 if (!FcSortWalk (nodeps, nnodes, ret, csp, trim)) 971 goto bail2; 972 973 free (nodes); 974 975 if (FcDebug() & FC_DBG_MATCH) 976 { 977 printf ("First font "); 978 FcPatternPrint (ret->fonts[0]); 979 } 980 if (ret->nfont > 0) 981 *result = FcResultMatch; 982 983 return ret; 984 985bail2: 986 FcFontSetDestroy (ret); 987bail1: 988 free (nodes); 989bail0: 990 return 0; 991} 992 993FcFontSet * 994FcFontSort (FcConfig *config, 995 FcPattern *p, 996 FcBool trim, 997 FcCharSet **csp, 998 FcResult *result) 999{ 1000 FcFontSet *sets[2]; 1001 int nsets; 1002 1003 assert (p != NULL); 1004 assert (result != NULL); 1005 1006 *result = FcResultNoMatch; 1007 1008 if (!config) 1009 { 1010 config = FcConfigGetCurrent (); 1011 if (!config) 1012 return 0; 1013 } 1014 nsets = 0; 1015 if (config->fonts[FcSetSystem]) 1016 sets[nsets++] = config->fonts[FcSetSystem]; 1017 if (config->fonts[FcSetApplication]) 1018 sets[nsets++] = config->fonts[FcSetApplication]; 1019 return FcFontSetSort (config, sets, nsets, p, trim, csp, result); 1020} 1021#define __fcmatch__ 1022#include "fcaliastail.h" 1023#undef __fcmatch__ 1024