Bug 27765 - FcMatch() returns style in wrong language

Add "namelang" object to obtain the localized name in the font regardless
of the lang object. it's applied to "familylang", "stylelang" and
"fullnamelang" alltogether. this would helps if one wants to enforce
selecting them in the specific language if any.  the default value for
the namelang object is determined from current locale.
This commit is contained in:
Akira TAGOH 2012-03-26 16:34:34 +09:00
parent 526f0da93f
commit 7587d1c99d
7 changed files with 178 additions and 27 deletions

View File

@ -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
</programlisting>
</sect2>
</sect1>

View File

@ -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

View File

@ -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"

View File

@ -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);

View File

@ -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
{

View File

@ -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++)
{

View File

@ -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])