X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=src%2Ffcmatch.c;h=4d20a61fc9b7f09d702f4bb8641b69dee8ff9386;hb=c7641f28;hp=ace6d8c1200577b90f5f3775ce2193e6345dddee;hpb=4c0036053a36678747adfd06777cef39752ca9a4;p=fontconfig.git diff --git a/src/fcmatch.c b/src/fcmatch.c index ace6d8c..4d20a61 100644 --- a/src/fcmatch.c +++ b/src/fcmatch.c @@ -1,7 +1,7 @@ /* - * $XFree86: xc/lib/fontconfig/src/fcmatch.c,v 1.14 2002/06/19 21:32:18 keithp Exp $ + * fontconfig/src/fcmatch.c * - * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * Copyright © 2000 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -22,69 +22,145 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "fcint.h" #include #include -#include "fcint.h" #include static double -FcCompareInteger (char *object, FcValue value1, FcValue value2) +FcCompareNumber (FcValue *value1, FcValue *value2) { - int v; + double v1, v2, v; - if (value2.type != FcTypeInteger || value1.type != FcTypeInteger) + switch (value1->type) { + case FcTypeInteger: + v1 = (double) value1->u.i; + break; + case FcTypeDouble: + v1 = value1->u.d; + break; + default: + return -1.0; + } + switch (value2->type) { + case FcTypeInteger: + v2 = (double) value2->u.i; + break; + case FcTypeDouble: + v2 = value2->u.d; + break; + default: return -1.0; - v = value2.u.i - value1.u.i; + } + v = v2 - v1; if (v < 0) v = -v; - return (double) v; + return v; } static double -FcCompareString (char *object, FcValue value1, FcValue value2) +FcCompareString (FcValue *v1, FcValue *v2) { - if (value2.type != FcTypeString || value1.type != FcTypeString) - return -1.0; - return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0; + return (double) FcStrCmpIgnoreCase (fc_value_string(v1), fc_value_string(v2)) != 0; } static double -FcCompareBool (char *object, FcValue value1, FcValue value2) +FcCompareFamily (FcValue *v1, FcValue *v2) { - if (value2.type != FcTypeBool || value1.type != FcTypeBool) + /* rely on the guarantee in FcPatternAddWithBinding that + * families are always FcTypeString. */ + const FcChar8* v1_string = fc_value_string(v1); + const FcChar8* v2_string = fc_value_string(v2); + + if (FcToLower(*v1_string) != FcToLower(*v2_string) && + *v1_string != ' ' && *v2_string != ' ') + return 1.0; + + return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0; +} + +static double +FcCompareLang (FcValue *v1, FcValue *v2) +{ + FcLangResult result; + FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2); + + switch (value1.type) { + case FcTypeLangSet: + switch (value2.type) { + case FcTypeLangSet: + result = FcLangSetCompare (value1.u.l, value2.u.l); + break; + case FcTypeString: + result = FcLangSetHasLang (value1.u.l, + value2.u.s); + break; + default: + return -1.0; + } + break; + case FcTypeString: + switch (value2.type) { + case FcTypeLangSet: + result = FcLangSetHasLang (value2.u.l, value1.u.s); + break; + case FcTypeString: + result = FcLangCompare (value1.u.s, + value2.u.s); + break; + default: + return -1.0; + } + break; + default: return -1.0; - return (double) value2.u.b != value1.u.b; + } + switch (result) { + case FcLangEqual: + return 0; + case FcLangDifferentCountry: + return 1; + case FcLangDifferentLang: + default: + return 2; + } } static double -FcCompareCharSet (char *object, FcValue value1, FcValue value2) +FcCompareBool (FcValue *v1, FcValue *v2) { - if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet) + if (fc_storage_type(v2) != FcTypeBool || fc_storage_type(v1) != FcTypeBool) return -1.0; - return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c); + return (double) v2->u.b != v1->u.b; } static double -FcCompareSize (char *object, FcValue value1, FcValue value2) +FcCompareCharSet (FcValue *v1, FcValue *v2) +{ + return (double) FcCharSetSubtractCount (fc_value_charset(v1), fc_value_charset(v2)); +} + +static double +FcCompareSize (FcValue *value1, FcValue *value2) { double v1, v2, v; - switch (value1.type) { + switch (value1->type) { case FcTypeInteger: - v1 = value1.u.i; + v1 = value1->u.i; break; case FcTypeDouble: - v1 = value1.u.d; + v1 = value1->u.d; break; default: return -1; } - switch (value2.type) { + switch (value2->type) { case FcTypeInteger: - v2 = value2.u.i; + v2 = value2->u.i; break; case FcTypeDouble: - v2 = value2.u.d; + v2 = value2->u.d; break; default: return -1; @@ -98,8 +174,8 @@ FcCompareSize (char *object, FcValue value1, FcValue value2) } typedef struct _FcMatcher { - char *object; - double (*compare) (char *object, FcValue value1, FcValue value2); + FcObject object; + double (*compare) (FcValue *value1, FcValue *value2); int strong, weak; } FcMatcher; @@ -109,142 +185,154 @@ typedef struct _FcMatcher { * later values */ static FcMatcher _FcMatchers [] = { - { FC_FOUNDRY, FcCompareString, 0, 0 }, + { FC_FOUNDRY_OBJECT, FcCompareString, 0, 0 }, #define MATCH_FOUNDRY 0 +#define MATCH_FOUNDRY_INDEX 0 - { FC_CHARSET, FcCompareCharSet, 1, 1 }, + { FC_CHARSET_OBJECT, FcCompareCharSet, 1, 1 }, #define MATCH_CHARSET 1 +#define MATCH_CHARSET_INDEX 1 - { FC_FAMILY, FcCompareString, 2, 4 }, + { FC_FAMILY_OBJECT, FcCompareFamily, 2, 4 }, #define MATCH_FAMILY 2 +#define MATCH_FAMILY_STRONG_INDEX 2 +#define MATCH_FAMILY_WEAK_INDEX 4 - { FC_LANG, FcCompareString, 3, 3 }, + { FC_LANG_OBJECT, FcCompareLang, 3, 3 }, #define MATCH_LANG 3 +#define MATCH_LANG_INDEX 3 - { FC_SPACING, FcCompareInteger, 5, 5 }, + { FC_SPACING_OBJECT, FcCompareNumber, 5, 5 }, #define MATCH_SPACING 4 +#define MATCH_SPACING_INDEX 5 - { FC_PIXEL_SIZE, FcCompareSize, 6, 6 }, + { FC_PIXEL_SIZE_OBJECT, FcCompareSize, 6, 6 }, #define MATCH_PIXEL_SIZE 5 +#define MATCH_PIXEL_SIZE_INDEX 6 - { FC_STYLE, FcCompareString, 7, 7 }, + { FC_STYLE_OBJECT, FcCompareString, 7, 7 }, #define MATCH_STYLE 6 +#define MATCH_STYLE_INDEX 7 - { FC_SLANT, FcCompareInteger, 8, 8 }, + { FC_SLANT_OBJECT, FcCompareNumber, 8, 8 }, #define MATCH_SLANT 7 +#define MATCH_SLANT_INDEX 8 - { FC_WEIGHT, FcCompareInteger, 9, 9 }, + { FC_WEIGHT_OBJECT, FcCompareNumber, 9, 9 }, #define MATCH_WEIGHT 8 +#define MATCH_WEIGHT_INDEX 9 - { FC_ANTIALIAS, FcCompareBool, 10, 10 }, -#define MATCH_ANTIALIAS 9 + { FC_WIDTH_OBJECT, FcCompareNumber, 10, 10 }, +#define MATCH_WIDTH 9 +#define MATCH_WIDTH_INDEX 10 - { FC_RASTERIZER, FcCompareString, 11, 11 }, -#define MATCH_RASTERIZER 10 + { FC_DECORATIVE_OBJECT, FcCompareBool, 11, 11 }, +#define MATCH_DECORATIVE 10 +#define MATCH_DECORATIVE_INDEX 11 + + { FC_ANTIALIAS_OBJECT, FcCompareBool, 12, 12 }, +#define MATCH_ANTIALIAS 11 +#define MATCH_ANTIALIAS_INDEX 12 - { FC_OUTLINE, FcCompareBool, 12, 12 }, -#define MATCH_OUTLINE 11 + { FC_RASTERIZER_OBJECT, FcCompareString, 13, 13 }, +#define MATCH_RASTERIZER 12 +#define MATCH_RASTERIZER_INDEX 13 + + { FC_OUTLINE_OBJECT, FcCompareBool, 14, 14 }, +#define MATCH_OUTLINE 13 +#define MATCH_OUTLINE_INDEX 14 + + { FC_FONTVERSION_OBJECT, FcCompareNumber, 15, 15 }, +#define MATCH_FONTVERSION 14 +#define MATCH_FONTVERSION_INDEX 15 }; -#define NUM_MATCH_VALUES 13 +#define NUM_MATCH_VALUES 16 -static FcBool -FcCompareValueList (const char *object, - FcValueList *v1orig, /* pattern */ - FcValueList *v2orig, /* target */ - FcValue *bestValue, - double *value, - FcResult *result) +static FcMatcher* +FcObjectToMatcher (FcObject object) { - FcValueList *v1, *v2; - double v, best, bestStrong, bestWeak; - int i; - int j; - - /* - * Locate the possible matching entry by examining the - * first few characters in object - */ + int i; + i = -1; - switch (FcToLower (object[0])) { - case 'f': - switch (FcToLower (object[1])) { - case 'o': - i = MATCH_FOUNDRY; break; - case 'a': - i = MATCH_FAMILY; break; - } - break; - case 'c': + switch (object) { + case FC_FOUNDRY_OBJECT: + i = MATCH_FOUNDRY; break; + case FC_FONTVERSION_OBJECT: + i = MATCH_FONTVERSION; break; + case FC_FAMILY_OBJECT: + i = MATCH_FAMILY; break; + case FC_CHARSET_OBJECT: i = MATCH_CHARSET; break; - case 'a': + case FC_ANTIALIAS_OBJECT: i = MATCH_ANTIALIAS; break; - case 'l': + case FC_LANG_OBJECT: i = MATCH_LANG; break; - case 's': - switch (FcToLower (object[1])) { - case 'p': - i = MATCH_SPACING; break; - case 't': - i = MATCH_STYLE; break; - case 'l': - i = MATCH_SLANT; break; - } - break; - case 'p': + case FC_SPACING_OBJECT: + i = MATCH_SPACING; break; + case FC_STYLE_OBJECT: + i = MATCH_STYLE; break; + case FC_SLANT_OBJECT: + i = MATCH_SLANT; break; + case FC_PIXEL_SIZE_OBJECT: i = MATCH_PIXEL_SIZE; break; - case 'w': - i = MATCH_WEIGHT; break; - case 'r': + case FC_WIDTH_OBJECT: + i = MATCH_WIDTH; break; + case FC_WEIGHT_OBJECT: + i = MATCH_WEIGHT; break; + case FC_RASTERIZER_OBJECT: i = MATCH_RASTERIZER; break; - case 'o': + case FC_OUTLINE_OBJECT: i = MATCH_OUTLINE; break; + case FC_DECORATIVE_OBJECT: + i = MATCH_DECORATIVE; break; } - if (i == -1 || - FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object, - (FcChar8 *) object) != 0) - { - if (bestValue) - *bestValue = v2orig->value; - return FcTrue; - } -#if 0 - for (i = 0; i < NUM_MATCHER; i++) - { - if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object, - (FcChar8 *) object)) - break; - } - if (i == NUM_MATCHER) + + if (i < 0) + return NULL; + + return _FcMatchers+i; +} + +static FcBool +FcCompareValueList (FcObject object, + FcValueListPtr v1orig, /* pattern */ + FcValueListPtr v2orig, /* target */ + FcValue *bestValue, + double *value, + FcResult *result) +{ + FcValueListPtr v1, v2; + double v, best, bestStrong, bestWeak; + int j; + FcMatcher *match = FcObjectToMatcher(object); + + if (!match) { if (bestValue) - *bestValue = v2orig->value; + *bestValue = FcValueCanonicalize(&v2orig->value); return FcTrue; } -#endif + best = 1e99; bestStrong = 1e99; bestWeak = 1e99; j = 0; - for (v1 = v1orig; v1; v1 = v1->next) + for (v1 = v1orig; v1; v1 = FcValueListNext(v1)) { - for (v2 = v2orig; v2; v2 = v2->next) + for (v2 = v2orig; v2; v2 = FcValueListNext(v2)) { - v = (*_FcMatchers[i].compare) (_FcMatchers[i].object, - v1->value, - v2->value); + v = (match->compare) (&v1->value, &v2->value); if (v < 0) { *result = FcResultTypeMismatch; return FcFalse; } - if (FcDebug () & FC_DBG_MATCHV) - printf (" v %g j %d ", v, j); - v = v * 100 + j; + v = v * 1000 + j; if (v < best) { if (bestValue) - *bestValue = v2->value; + *bestValue = FcValueCanonicalize(&v2->value); best = v; } if (v1->binding == FcValueBindingStrong) @@ -262,7 +350,7 @@ FcCompareValueList (const char *object, } if (FcDebug () & FC_DBG_MATCHV) { - printf (" %s: %g ", object, best); + printf (" %s: %g ", FcObjectName (object), best); FcValueListPrint (v1orig); printf (", "); FcValueListPrint (v2orig); @@ -270,8 +358,8 @@ FcCompareValueList (const char *object, } if (value) { - int weak = _FcMatchers[i].weak; - int strong = _FcMatchers[i].strong; + int weak = match->weak; + int strong = match->strong; if (weak == strong) value[strong] += best; else @@ -303,38 +391,26 @@ FcCompare (FcPattern *pat, i2 = 0; while (i1 < pat->num && i2 < fnt->num) { - i = strcmp (pat->elts[i1].object, fnt->elts[i2].object); + FcPatternElt *elt_i1 = &FcPatternElts(pat)[i1]; + FcPatternElt *elt_i2 = &FcPatternElts(fnt)[i2]; + + i = FcObjectCompare(elt_i1->object, elt_i2->object); if (i > 0) i2++; else if (i < 0) i1++; else { - if (!FcCompareValueList (pat->elts[i1].object, - pat->elts[i1].values, - fnt->elts[i2].values, - 0, - value, - result)) + if (!FcCompareValueList (elt_i1->object, + FcPatternEltValues(elt_i1), + FcPatternEltValues(elt_i2), + 0, value, result)) return FcFalse; i1++; i2++; } } return FcTrue; -#if 0 - for (i1 = 0; i1 < pat->num; i1++) - { - for (i2 = 0; i2 < fnt->num; i2++) - { - if (!strcmp (pat->elts[i1].object, fnt->elts[i2].object)) - { - break; - } - } - } - return FcTrue; -#endif } FcPattern * @@ -353,43 +429,33 @@ FcFontRenderPrepare (FcConfig *config, return 0; for (i = 0; i < font->num; i++) { - fe = &font->elts[i]; - pe = FcPatternFindElt (pat, fe->object); + fe = &FcPatternElts(font)[i]; + pe = FcPatternObjectFindElt (pat, fe->object); if (pe) { - int j; - double score[NUM_MATCH_VALUES]; - - for (j = 0; j < NUM_MATCH_VALUES; j++) - score[j] = 0; - if (!FcCompareValueList (pe->object, pe->values, - fe->values, &v, score, &result)) + if (!FcCompareValueList (pe->object, FcPatternEltValues(pe), + FcPatternEltValues(fe), &v, 0, &result)) { FcPatternDestroy (new); return 0; } - for (j = 0; j < NUM_MATCH_VALUES; j++) - if (score[j] >= 100.0) - { - FcValueList *pv; - - for (pv = pe->values; pv; pv = pv->next) - FcPatternAdd (new, fe->object, pv->value, FcTrue); - break; - } } else - v = fe->values->value; - FcPatternAdd (new, fe->object, v, FcFalse); + v = FcValueCanonicalize(&FcPatternEltValues (fe)->value); + FcPatternObjectAdd (new, fe->object, v, FcFalse); } for (i = 0; i < pat->num; i++) { - pe = &pat->elts[i]; - fe = FcPatternFindElt (font, pe->object); + pe = &FcPatternElts(pat)[i]; + fe = FcPatternObjectFindElt (font, pe->object); if (!fe) - FcPatternAdd (new, pe->object, pe->values->value, FcTrue); + { + v = FcValueCanonicalize(&FcPatternEltValues(pe)->value); + FcPatternObjectAdd (new, pe->object, v, FcTrue); + } } - FcConfigSubstitute (config, new, FcMatchFont); + + FcConfigSubstituteWithPat (config, new, pat, FcMatchFont); return new; } @@ -463,6 +529,7 @@ FcFontSetMatch (FcConfig *config, printf ("Best score"); for (i = 0; i < NUM_MATCH_VALUES; i++) printf (" %g", bestscore[i]); + printf ("\n"); FcPatternPrint (best); } if (!best) @@ -517,7 +584,7 @@ FcSortCompare (const void *aa, const void *ab) } static FcBool -FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim) +FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim, FcBool build_cs) { FcCharSet *ncs; FcSortNode *node; @@ -525,31 +592,40 @@ FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool tri while (nnode--) { node = *n++; - if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) == - FcResultMatch) + + /* + * Only fetch node charset if we'd need it + */ + if (trim || build_cs) { - /* - * If this font isn't a subset of the previous fonts, - * add it to the list - */ - if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs)) + if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) != + FcResultMatch) + continue; + } + + /* + * If this font isn't a subset of the previous fonts, + * add it to the list + */ + if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs)) + { + if (trim || build_cs) { - if (*cs) - { - ncs = FcCharSetUnion (ncs, *cs); - if (!ncs) - return FcFalse; - FcCharSetDestroy (*cs); - } - else - ncs = FcCharSetCopy (ncs); - *cs = ncs; - FcPatternReference (node->pattern); - if (!FcFontSetAdd (fs, node->pattern)) - { - FcPatternDestroy (node->pattern); + *cs = FcCharSetMerge (*cs, ncs); + if (*cs == NULL) return FcFalse; - } + } + + FcPatternReference (node->pattern); + if (FcDebug () & FC_DBG_MATCHV) + { + printf ("Add "); + FcPatternPrint (node->pattern); + } + if (!FcFontSetAdd (fs, node->pattern)) + { + FcPatternDestroy (node->pattern); + return FcFalse; } } } @@ -581,7 +657,15 @@ FcFontSetSort (FcConfig *config, int set; int f; int i; + int nPatternLang; + FcBool *patternLangSat; + FcValue patternLang; + if (FcDebug () & FC_DBG_MATCH) + { + printf ("Sort "); + FcPatternPrint (p); + } nnodes = 0; for (set = 0; set < nsets; set++) { @@ -592,10 +676,20 @@ FcFontSetSort (FcConfig *config, } if (!nnodes) goto bail0; - nodes = malloc (nnodes * sizeof (FcSortNode) + nnodes * sizeof (FcSortNode *)); + + for (nPatternLang = 0; + FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch; + nPatternLang++) + ; + + /* freed below */ + nodes = malloc (nnodes * sizeof (FcSortNode) + + nnodes * sizeof (FcSortNode *) + + nPatternLang * sizeof (FcBool)); if (!nodes) goto bail0; nodeps = (FcSortNode **) (nodes + nnodes); + patternLangSat = (FcBool *) (nodeps + nnodes); new = nodes; nodep = nodeps; @@ -633,6 +727,55 @@ FcFontSetSort (FcConfig *config, qsort (nodeps, nnodes, sizeof (FcSortNode *), FcSortCompare); + + for (i = 0; i < nPatternLang; i++) + patternLangSat[i] = FcFalse; + + for (f = 0; f < nnodes; f++) + { + FcBool satisfies = FcFalse; + /* + * If this node matches any language, go check + * which ones and satisfy those entries + */ + if (nodeps[f]->score[MATCH_LANG_INDEX] < 200) + { + for (i = 0; i < nPatternLang; i++) + { + FcValue nodeLang; + + if (!patternLangSat[i] && + FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch && + FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch) + { + double compare = FcCompareLang (&patternLang, &nodeLang); + if (compare >= 0 && compare < 2) + { + if (FcDebug () & FC_DBG_MATCHV) + { + FcChar8 *family; + FcChar8 *style; + + if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch && + FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch) + printf ("Font %s:%s matches language %d\n", family, style, i); + } + patternLangSat[i] = FcTrue; + satisfies = FcTrue; + break; + } + } + } + } + if (!satisfies) + nodeps[f]->score[MATCH_LANG_INDEX] = 10000.0; + } + + /* + * Re-sort once the language issues have been settled + */ + qsort (nodeps, nnodes, sizeof (FcSortNode *), + FcSortCompare); ret = FcFontSetCreate (); if (!ret) @@ -640,16 +783,24 @@ FcFontSetSort (FcConfig *config, cs = 0; - if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim)) + if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim, (csp!=0))) goto bail2; if (csp) *csp = cs; else - FcCharSetDestroy (cs); + { + if (cs) + FcCharSetDestroy (cs); + } free (nodes); + if (FcDebug() & FC_DBG_MATCH) + { + printf ("First font "); + FcPatternPrint (ret->fonts[0]); + } return ret; bail2: @@ -685,3 +836,6 @@ FcFontSort (FcConfig *config, sets[nsets++] = config->fonts[FcSetApplication]; return FcFontSetSort (config, sets, nsets, p, trim, csp, result); } +#define __fcmatch__ +#include "fcaliastail.h" +#undef __fcmatch__