diff --git a/doc/fontconfig-devel.sgml b/doc/fontconfig-devel.sgml index 8733951..ab39092 100644 --- a/doc/fontconfig-devel.sgml +++ b/doc/fontconfig-devel.sgml @@ -190,6 +190,9 @@ convenience for the application's rendering mechanism. the font embolden FC_EMBOLDEN Bool Rasterizer should synthetically embolden the font + namelang FC_NAMELANG String Language name to be used for the + default value of familylang, + stylelang and fullnamelang diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index e4d5708..2671da7 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -111,6 +111,7 @@ typedef int FcBool; #define FC_EMBEDDED_BITMAP "embeddedbitmap" /* Bool - true to enable embedded bitmaps */ #define FC_DECORATIVE "decorative" /* Bool - true if style is a decorative variant */ #define FC_LCD_FILTER "lcdfilter" /* Int */ +#define FC_NAMELANG "namelang" /* String RFC 3866 langs */ #define FC_CACHE_SUFFIX ".cache-" FC_CACHE_VERSION #define FC_DIR_CACHE_FILE "fonts.cache-" FC_CACHE_VERSION diff --git a/src/fcdefault.c b/src/fcdefault.c index a9165fa..170a8a4 100644 --- a/src/fcdefault.c +++ b/src/fcdefault.c @@ -119,7 +119,7 @@ FcGetDefaultLang (void) void FcDefaultSubstitute (FcPattern *pattern) { - FcValue v; + FcValue v, namelang, v2; int i; if (FcPatternObjectGet (pattern, FC_WEIGHT_OBJECT, 0, &v) == FcResultNoMatch ) @@ -175,6 +175,41 @@ FcDefaultSubstitute (FcPattern *pattern) { FcPatternObjectAddInteger (pattern, FC_HINT_STYLE_OBJECT, FC_HINT_FULL); } + if (FcPatternObjectGet (pattern, FC_NAMELANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAddString (pattern, FC_NAMELANG_OBJECT, FcGetDefaultLang ()); + } + /* shouldn't be failed. */ + FcPatternObjectGet (pattern, FC_NAMELANG_OBJECT, 0, &namelang); + /* Add a fallback to ensure the english name when the requested language + * isn't available. this would helps for the fonts that have non-English + * name at the beginning. + */ + /* Set "en-us" instead of "en" to avoid giving higher score to "en". + * This is a hack for the case that the orth is not like ll-cc, because, + * if no namelang isn't explicitly set, it will has something like ll-cc + * according to current locale. which may causes FcLangDifferentTerritory + * at FcLangCompare(). thus, the English name is selected so that + * exact matched "en" has higher score than ll-cc. + */ + v2.type = FcTypeString; + v2.u.s = FcSharedStr ((FcChar8 *)"en-us"); + if (FcPatternObjectGet (pattern, FC_FAMILYLANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAdd (pattern, FC_FAMILYLANG_OBJECT, namelang, FcTrue); + FcPatternObjectAddWithBinding (pattern, FC_FAMILYLANG_OBJECT, v2, FcValueBindingWeak, FcTrue); + } + if (FcPatternObjectGet (pattern, FC_STYLELANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAdd (pattern, FC_STYLELANG_OBJECT, namelang, FcTrue); + FcPatternObjectAddWithBinding (pattern, FC_STYLELANG_OBJECT, v2, FcValueBindingWeak, FcTrue); + } + if (FcPatternObjectGet (pattern, FC_FULLNAMELANG_OBJECT, 0, &v) == FcResultNoMatch) + { + FcPatternObjectAdd (pattern, FC_FULLNAMELANG_OBJECT, namelang, FcTrue); + FcPatternObjectAddWithBinding (pattern, FC_FULLNAMELANG_OBJECT, v2, FcValueBindingWeak, FcTrue); + } + FcSharedStrFree (v2.u.s); } #define __fcdefault__ #include "fcaliastail.h" diff --git a/src/fcint.h b/src/fcint.h index bada325..fb4a64b 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -858,7 +858,8 @@ FcListPatternMatchAny (const FcPattern *p, #define FC_EMBEDDED_BITMAP_OBJECT 39 #define FC_DECORATIVE_OBJECT 40 #define FC_LCD_FILTER_OBJECT 41 -#define FC_MAX_BASE_OBJECT FC_LCD_FILTER_OBJECT +#define FC_NAMELANG_OBJECT 42 +#define FC_MAX_BASE_OBJECT FC_NAMELANG_OBJECT FcPrivate FcBool FcNameBool (const FcChar8 *v, FcBool *result); diff --git a/src/fclist.c b/src/fclist.c index 88025e9..331352c 100644 --- a/src/fclist.c +++ b/src/fclist.c @@ -221,7 +221,18 @@ FcListPatternMatchAny (const FcPattern *p, for (i = 0; i < p->num; i++) { FcPatternElt *pe = &FcPatternElts(p)[i]; - FcPatternElt *fe = FcPatternObjectFindElt (font, pe->object); + FcPatternElt *fe; + + if (pe->object == FC_NAMELANG_OBJECT) + { + /* "namelang" object is the alias object to change "familylang", + * "stylelang" and "fullnamelang" object alltogether. it won't be + * available on the font pattern. so checking its availability + * causes no results. we should ignore it here. + */ + continue; + } + fe = FcPatternObjectFindElt (font, pe->object); if (!fe) return FcFalse; if (!FcListValueListMatchAny (FcPatternEltValues(pe), /* pat elts */ @@ -340,13 +351,13 @@ FcListHashTableCleanup (FcListHashTable *table) } static int -FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object) +FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object, const FcChar8 *lang) { - FcChar8 *lang = FcGetDefaultLang (); FcPatternElt *e = FcPatternObjectFindElt (font, object); FcValueListPtr v; FcValue value; int idx = -1; + int defidx = -1; int i; if (e) @@ -363,17 +374,27 @@ FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object) if (res == FcLangDifferentCountry && idx < 0) idx = i; + if (defidx < 0) + { + /* workaround for fonts that has non-English value + * at the head of values. + */ + res = FcLangCompare (value.u.s, (FcChar8 *)"en"); + if (res == FcLangEqual) + defidx = i; + } } } } - return (idx > 0) ? idx : 0; + return (idx > 0) ? idx : (defidx > 0) ? defidx : 0; } static FcBool FcListAppend (FcListHashTable *table, FcPattern *font, - FcObjectSet *os) + FcObjectSet *os, + const FcChar8 *lang) { int o; FcPatternElt *e; @@ -409,19 +430,19 @@ FcListAppend (FcListHashTable *table, if (!strcmp (os->objects[o], FC_FAMILY) || !strcmp (os->objects[o], FC_FAMILYLANG)) { if (familyidx < 0) - familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT); + familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT, lang); defidx = familyidx; } else if (!strcmp (os->objects[o], FC_FULLNAME) || !strcmp (os->objects[o], FC_FULLNAMELANG)) { if (fullnameidx < 0) - fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT); + fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT, lang); defidx = fullnameidx; } else if (!strcmp (os->objects[o], FC_STYLE) || !strcmp (os->objects[o], FC_STYLELANG)) { if (styleidx < 0) - styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT); + styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT, lang); defidx = styleidx; } else @@ -499,8 +520,16 @@ FcFontSetList (FcConfig *config, for (f = 0; f < s->nfont; f++) if (FcListPatternMatchAny (p, /* pattern */ s->fonts[f])) /* font */ - if (!FcListAppend (&table, s->fonts[f], os)) + { + FcChar8 *lang; + + if (FcPatternObjectGetString (p, FC_NAMELANG_OBJECT, 0, &lang) != FcResultMatch) + { + lang = FcGetDefaultLang (); + } + if (!FcListAppend (&table, s->fonts[f], os, lang)) goto bail1; + } } #if 0 { diff --git a/src/fcmatch.c b/src/fcmatch.c index 655e62c..623538b 100644 --- a/src/fcmatch.c +++ b/src/fcmatch.c @@ -240,7 +240,8 @@ static const FcMatcher _FcMatchers [] = { #define NUM_MATCH_VALUES 17 static const FcMatcher* -FcObjectToMatcher (FcObject object) +FcObjectToMatcher (FcObject object, + FcBool include_lang) { int i; @@ -278,6 +279,16 @@ FcObjectToMatcher (FcObject object) i = MATCH_OUTLINE; break; case FC_DECORATIVE_OBJECT: i = MATCH_DECORATIVE; break; + default: + if (include_lang) + { + switch (object) { + case FC_FAMILYLANG_OBJECT: + case FC_STYLELANG_OBJECT: + case FC_FULLNAMELANG_OBJECT: + i = MATCH_LANG; break; + } + } } if (i < 0) @@ -287,22 +298,25 @@ FcObjectToMatcher (FcObject object) } static FcBool -FcCompareValueList (FcObject object, - FcValueListPtr v1orig, /* pattern */ - FcValueListPtr v2orig, /* target */ - FcValue *bestValue, - double *value, - FcResult *result) +FcCompareValueList (FcObject object, + const FcMatcher *match, + FcValueListPtr v1orig, /* pattern */ + FcValueListPtr v2orig, /* target */ + FcValue *bestValue, + double *value, + int *n, + FcResult *result) { FcValueListPtr v1, v2; double v, best, bestStrong, bestWeak; - int j; - const FcMatcher *match = FcObjectToMatcher(object); + int j, k, pos = 0; if (!match) { if (bestValue) *bestValue = FcValueCanonicalize(&v2orig->value); + if (n) + *n = 0; return FcTrue; } @@ -312,7 +326,7 @@ FcCompareValueList (FcObject object, j = 1; for (v1 = v1orig; v1; v1 = FcValueListNext(v1)) { - for (v2 = v2orig; v2; v2 = FcValueListNext(v2)) + for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext(v2), k++) { v = (match->compare) (&v1->value, &v2->value); if (v < 0) @@ -326,6 +340,7 @@ FcCompareValueList (FcObject object, if (bestValue) *bestValue = FcValueCanonicalize(&v2->value); best = v; + pos = k; } if (v1->binding == FcValueBindingStrong) { @@ -360,6 +375,9 @@ FcCompareValueList (FcObject object, value[strong] += bestStrong; } } + if (n) + *n = pos; + return FcTrue; } @@ -393,10 +411,11 @@ FcCompare (FcPattern *pat, i1++; else { - if (!FcCompareValueList (elt_i1->object, + const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse); + if (!FcCompareValueList (elt_i1->object, match, FcPatternEltValues(elt_i1), FcPatternEltValues(elt_i2), - 0, value, result)) + NULL, value, NULL, result)) return FcFalse; i1++; i2++; @@ -412,8 +431,8 @@ FcFontRenderPrepare (FcConfig *config, { FcPattern *new; int i; - FcPatternElt *fe, *pe; - FcValue v; + FcPatternElt *fe, *pe, *fel, *pel; + FcValue v, vl; FcResult result; assert (pat != NULL); @@ -425,19 +444,81 @@ FcFontRenderPrepare (FcConfig *config, for (i = 0; i < font->num; i++) { fe = &FcPatternElts(font)[i]; + if (fe->object == FC_FAMILYLANG_OBJECT || + fe->object == FC_STYLELANG_OBJECT || + fe->object == FC_FULLNAMELANG_OBJECT) + { + /* ignore those objects. we need to deal with them + * another way */ + continue; + } + if (fe->object == FC_FAMILY_OBJECT || + fe->object == FC_STYLE_OBJECT || + fe->object == FC_FULLNAME_OBJECT) + { + FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT); + FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT); + FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT); + + fel = FcPatternObjectFindElt (font, fe->object + 1); + pel = FcPatternObjectFindElt (pat, fe->object + 1); + } + else + { + fel = NULL; + pel = NULL; + } pe = FcPatternObjectFindElt (pat, fe->object); if (pe) { - if (!FcCompareValueList (pe->object, FcPatternEltValues(pe), - FcPatternEltValues(fe), &v, 0, &result)) + const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse); + + if (!FcCompareValueList (pe->object, match, + FcPatternEltValues(pe), + FcPatternEltValues(fe), &v, NULL, NULL, &result)) { FcPatternDestroy (new); return 0; } + if (fel && pel) + { + int n = 1, j; + + match = FcObjectToMatcher (pel->object, FcTrue); + if (!FcCompareValueList (pel->object, match, + FcPatternEltValues (pel), + FcPatternEltValues (fel), &vl, NULL, &n, &result)) + { + FcPatternDestroy (new); + return NULL; + } + else + { + FcValueListPtr l; + + for (j = 0, l = FcPatternEltValues (fe); + j < n && l != NULL; + j++, l = FcValueListNext (l)); + if (l) + v = FcValueCanonicalize (&l->value); + else + v = FcValueCanonicalize (&FcPatternEltValues (fe)->value); + } + } + else if (fel) + { + vl = FcValueCanonicalize (&FcPatternEltValues (fel)->value); + } } else + { v = FcValueCanonicalize(&FcPatternEltValues (fe)->value); + if (fel) + vl = FcValueCanonicalize (&FcPatternEltValues (fel)->value); + } FcPatternObjectAdd (new, fe->object, v, FcFalse); + if (fel) + FcPatternObjectAdd (new, fel->object, vl, FcFalse); } for (i = 0; i < pat->num; i++) { diff --git a/src/fcname.c b/src/fcname.c index d0b1ca8..d51307b 100644 --- a/src/fcname.c +++ b/src/fcname.c @@ -76,6 +76,7 @@ static const FcObjectType _FcBaseObjectTypes[] = { { FC_EMBEDDED_BITMAP, FcTypeBool }, { FC_DECORATIVE, FcTypeBool }, { FC_LCD_FILTER, FcTypeInteger }, /* 41 */ + { FC_NAMELANG, FcTypeString }, /* 42 */ }; #define NUM_OBJECT_TYPES (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])