Blame src/fcmatch.c

Packit 352660
/*
Packit 352660
 * fontconfig/src/fcmatch.c
Packit 352660
 *
Packit 352660
 * Copyright © 2000 Keith Packard
Packit 352660
 *
Packit 352660
 * Permission to use, copy, modify, distribute, and sell this software and its
Packit 352660
 * documentation for any purpose is hereby granted without fee, provided that
Packit 352660
 * the above copyright notice appear in all copies and that both that
Packit 352660
 * copyright notice and this permission notice appear in supporting
Packit 352660
 * documentation, and that the name of the author(s) not be used in
Packit 352660
 * advertising or publicity pertaining to distribution of the software without
Packit 352660
 * specific, written prior permission.  The authors make no
Packit 352660
 * representations about the suitability of this software for any purpose.  It
Packit 352660
 * is provided "as is" without express or implied warranty.
Packit 352660
 *
Packit 352660
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Packit 352660
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
Packit 352660
 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Packit 352660
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
Packit 352660
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
Packit 352660
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
Packit 352660
 * PERFORMANCE OF THIS SOFTWARE.
Packit 352660
 */
Packit 352660
Packit 352660
#include "fcint.h"
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareNumber (const FcValue *value1, const FcValue *value2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    double  v1, v2, v;
Packit 352660
Packit 352660
    switch ((int) value1->type) {
Packit 352660
    case FcTypeInteger:
Packit 352660
	v1 = (double) value1->u.i;
Packit 352660
	break;
Packit 352660
    case FcTypeDouble:
Packit 352660
	v1 = value1->u.d;
Packit 352660
	break;
Packit 352660
    default:
Packit 352660
	return -1.0;
Packit 352660
    }
Packit 352660
    switch ((int) value2->type) {
Packit 352660
    case FcTypeInteger:
Packit 352660
	v2 = (double) value2->u.i;
Packit 352660
	break;
Packit 352660
    case FcTypeDouble:
Packit 352660
	v2 = value2->u.d;
Packit 352660
	break;
Packit 352660
    default:
Packit 352660
	return -1.0;
Packit 352660
    }
Packit 352660
    v = v2 - v1;
Packit 352660
    if (v < 0)
Packit 352660
	v = -v;
Packit 352660
    *bestValue = FcValueCanonicalize (value2);
Packit 352660
    return v;
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareString (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    *bestValue = FcValueCanonicalize (v2);
Packit 352660
    return (double) FcStrCmpIgnoreCase (FcValueString(v1), FcValueString(v2)) != 0;
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareFamily (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    /* rely on the guarantee in FcPatternObjectAddWithBinding that
Packit 352660
     * families are always FcTypeString. */
Packit 352660
    const FcChar8* v1_string = FcValueString(v1);
Packit 352660
    const FcChar8* v2_string = FcValueString(v2);
Packit 352660
Packit 352660
    *bestValue = FcValueCanonicalize (v2);
Packit 352660
Packit 352660
    if (FcToLower(*v1_string) != FcToLower(*v2_string) &&
Packit 352660
	*v1_string != ' ' && *v2_string != ' ')
Packit 352660
       return 1.0;
Packit 352660
Packit 352660
    return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0;
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcComparePostScript (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    const FcChar8 *v1_string = FcValueString (v1);
Packit 352660
    const FcChar8 *v2_string = FcValueString (v2);
Packit 352660
    int n;
Packit 352660
    size_t len;
Packit 352660
Packit 352660
    *bestValue = FcValueCanonicalize (v2);
Packit 352660
Packit 352660
    if (FcToLower (*v1_string) != FcToLower (*v2_string) &&
Packit 352660
	*v1_string != ' ' && *v2_string != ' ')
Packit 352660
	return 1.0;
Packit 352660
Packit 352660
    n = FcStrMatchIgnoreCaseAndDelims (v1_string, v2_string, (const FcChar8 *)" -");
Packit 352660
    len = strlen ((const char *)v1_string);
Packit 352660
Packit 352660
    return (double)(len - n) / (double)len;
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareLang (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    FcLangResult    result;
Packit 352660
    FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
Packit 352660
Packit 352660
    switch ((int) value1.type) {
Packit 352660
    case FcTypeLangSet:
Packit 352660
	switch ((int) value2.type) {
Packit 352660
	case FcTypeLangSet:
Packit 352660
	    result = FcLangSetCompare (value1.u.l, value2.u.l);
Packit 352660
	    break;
Packit 352660
	case FcTypeString:
Packit 352660
	    result = FcLangSetHasLang (value1.u.l,
Packit 352660
				       value2.u.s);
Packit 352660
	    break;
Packit 352660
	default:
Packit 352660
	    return -1.0;
Packit 352660
	}
Packit 352660
	break;
Packit 352660
    case FcTypeString:
Packit 352660
	switch ((int) value2.type) {
Packit 352660
	case FcTypeLangSet:
Packit 352660
	    result = FcLangSetHasLang (value2.u.l, value1.u.s);
Packit 352660
	    break;
Packit 352660
	case FcTypeString:
Packit 352660
	    result = FcLangCompare (value1.u.s,
Packit 352660
				    value2.u.s);
Packit 352660
	    break;
Packit 352660
	default:
Packit 352660
	    return -1.0;
Packit 352660
	}
Packit 352660
	break;
Packit 352660
    default:
Packit 352660
	return -1.0;
Packit 352660
    }
Packit 352660
    *bestValue = FcValueCanonicalize (v2);
Packit 352660
    switch (result) {
Packit 352660
    case FcLangEqual:
Packit 352660
	return 0;
Packit 352660
    case FcLangDifferentCountry:
Packit 352660
	return 1;
Packit 352660
    case FcLangDifferentLang:
Packit 352660
    default:
Packit 352660
	return 2;
Packit 352660
    }
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareBool (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    if (v2->type != FcTypeBool || v1->type != FcTypeBool)
Packit 352660
	return -1.0;
Packit 352660
Packit 352660
    if (v2->u.b != FcDontCare)
Packit 352660
	*bestValue = FcValueCanonicalize (v2);
Packit 352660
    else
Packit 352660
	*bestValue = FcValueCanonicalize (v1);
Packit 352660
Packit 352660
    return (double) ((v2->u.b ^ v1->u.b) == 1);
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareCharSet (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    *bestValue = FcValueCanonicalize (v2); /* TODO Improve. */
Packit 352660
    return (double) FcCharSetSubtractCount (FcValueCharSet(v1), FcValueCharSet(v2));
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareRange (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    FcValue value1 = FcValueCanonicalize (v1);
Packit 352660
    FcValue value2 = FcValueCanonicalize (v2);
Packit 352660
    double b1, e1, b2, e2, d;
Packit 352660
Packit 352660
    switch ((int) value1.type) {
Packit 352660
    case FcTypeInteger:
Packit 352660
        b1 = e1 = value1.u.i;
Packit 352660
	break;
Packit 352660
    case FcTypeDouble:
Packit 352660
        b1 = e1 = value1.u.d;
Packit 352660
	break;
Packit 352660
    case FcTypeRange:
Packit 352660
	b1 = value1.u.r->begin;
Packit 352660
	e1 = value1.u.r->end;
Packit 352660
	break;
Packit 352660
    default:
Packit 352660
	return -1;
Packit 352660
    }
Packit 352660
    switch ((int) value2.type) {
Packit 352660
    case FcTypeInteger:
Packit 352660
        b2 = e2 = value2.u.i;
Packit 352660
	break;
Packit 352660
    case FcTypeDouble:
Packit 352660
        b2 = e2 = value2.u.d;
Packit 352660
	break;
Packit 352660
    case FcTypeRange:
Packit 352660
	b2 = value2.u.r->begin;
Packit 352660
	e2 = value2.u.r->end;
Packit 352660
	break;
Packit 352660
    default:
Packit 352660
	return -1;
Packit 352660
    }
Packit 352660
Packit 352660
    if (e1 < b2)
Packit 352660
      d = b2;
Packit 352660
    else if (e2 < b1)
Packit 352660
      d = e2;
Packit 352660
    else
Packit 352660
      d = (FC_MAX (b1, b2) + FC_MIN (e1, e2)) * .5;
Packit 352660
Packit 352660
    bestValue->type = FcTypeDouble;
Packit 352660
    bestValue->u.d = d;
Packit 352660
Packit 352660
    /* If the ranges overlap, it's a match, otherwise return closest distance. */
Packit 352660
    if (e1 < b2 || e2 < b1)
Packit 352660
	return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
Packit 352660
    else
Packit 352660
	return 0.0;
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareSize (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    FcValue value1 = FcValueCanonicalize (v1);
Packit 352660
    FcValue value2 = FcValueCanonicalize (v2);
Packit 352660
    double b1, e1, b2, e2;
Packit 352660
Packit 352660
    switch ((int) value1.type) {
Packit 352660
    case FcTypeInteger:
Packit 352660
        b1 = e1 = value1.u.i;
Packit 352660
	break;
Packit 352660
    case FcTypeDouble:
Packit 352660
        b1 = e1 = value1.u.d;
Packit 352660
	break;
Packit 352660
    case FcTypeRange:
Packit 352660
	abort();
Packit 352660
	b1 = value1.u.r->begin;
Packit 352660
	e1 = value1.u.r->end;
Packit 352660
	break;
Packit 352660
    default:
Packit 352660
	return -1;
Packit 352660
    }
Packit 352660
    switch ((int) value2.type) {
Packit 352660
    case FcTypeInteger:
Packit 352660
        b2 = e2 = value2.u.i;
Packit 352660
	break;
Packit 352660
    case FcTypeDouble:
Packit 352660
        b2 = e2 = value2.u.d;
Packit 352660
	break;
Packit 352660
    case FcTypeRange:
Packit 352660
	b2 = value2.u.r->begin;
Packit 352660
	e2 = value2.u.r->end;
Packit 352660
	break;
Packit 352660
    default:
Packit 352660
	return -1;
Packit 352660
    }
Packit 352660
Packit 352660
    bestValue->type = FcTypeDouble;
Packit 352660
    bestValue->u.d = (b1 + e1) * .5;
Packit 352660
Packit 352660
    /* If the ranges overlap, it's a match, otherwise return closest distance. */
Packit 352660
    if (e1 < b2 || e2 < b1)
Packit 352660
	return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
Packit 352660
    if (b2 != e2 && b1 == e2) /* Semi-closed interval. */
Packit 352660
        return 1e-15;
Packit 352660
    else
Packit 352660
	return 0.0;
Packit 352660
}
Packit 352660
Packit 352660
static double
Packit 352660
FcCompareFilename (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
Packit 352660
{
Packit 352660
    const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2);
Packit 352660
    *bestValue = FcValueCanonicalize (v2);
Packit 352660
    if (FcStrCmp (s1, s2) == 0)
Packit 352660
	return 0.0;
Packit 352660
    else if (FcStrCmpIgnoreCase (s1, s2) == 0)
Packit 352660
	return 1.0;
Packit 352660
    else if (FcStrGlobMatch (s1, s2))
Packit 352660
	return 2.0;
Packit 352660
    else
Packit 352660
	return 3.0;
Packit 352660
}
Packit 352660
Packit 352660
Packit 352660
/* Define priorities to -1 for objects that don't have a compare function. */
Packit 352660
Packit 352660
#define PRI_NULL(n)				\
Packit 352660
    PRI_ ## n ## _STRONG = -1,			\
Packit 352660
    PRI_ ## n ## _WEAK = -1,
Packit 352660
#define PRI1(n)
Packit 352660
#define PRI_FcCompareFamily(n)		PRI1(n)
Packit 352660
#define PRI_FcCompareString(n)		PRI1(n)
Packit 352660
#define PRI_FcCompareNumber(n)		PRI1(n)
Packit 352660
#define PRI_FcCompareBool(n)		PRI1(n)
Packit 352660
#define PRI_FcCompareFilename(n)	PRI1(n)
Packit 352660
#define PRI_FcCompareCharSet(n)		PRI1(n)
Packit 352660
#define PRI_FcCompareLang(n)		PRI1(n)
Packit 352660
#define PRI_FcComparePostScript(n)	PRI1(n)
Packit 352660
#define PRI_FcCompareRange(n)		PRI1(n)
Packit 352660
#define PRI_FcCompareSize(n)		PRI1(n)
Packit 352660
Packit 352660
#define FC_OBJECT(NAME, Type, Cmp)	PRI_##Cmp(NAME)
Packit 352660
Packit 352660
typedef enum _FcMatcherPriorityDummy {
Packit 352660
#include "fcobjs.h"
Packit 352660
} FcMatcherPriorityDummy;
Packit 352660
Packit 352660
#undef FC_OBJECT
Packit 352660
Packit 352660
Packit 352660
/* Canonical match priority order. */
Packit 352660
Packit 352660
#undef PRI1
Packit 352660
#define PRI1(n)					\
Packit 352660
    PRI_ ## n,					\
Packit 352660
    PRI_ ## n ## _STRONG = PRI_ ## n,		\
Packit 352660
    PRI_ ## n ## _WEAK = PRI_ ## n
Packit 352660
Packit 352660
typedef enum _FcMatcherPriority {
Packit 352660
    PRI1(FILE),
Packit 352660
    PRI1(FONTFORMAT),
Packit 352660
    PRI1(VARIABLE),
Packit 352660
    PRI1(SCALABLE),
Packit 352660
    PRI1(COLOR),
Packit 352660
    PRI1(FOUNDRY),
Packit 352660
    PRI1(CHARSET),
Packit 352660
    PRI_FAMILY_STRONG,
Packit 352660
    PRI_POSTSCRIPT_NAME_STRONG,
Packit 352660
    PRI1(LANG),
Packit 352660
    PRI_FAMILY_WEAK,
Packit 352660
    PRI_POSTSCRIPT_NAME_WEAK,
Packit 352660
    PRI1(SYMBOL),
Packit 352660
    PRI1(SPACING),
Packit 352660
    PRI1(SIZE),
Packit 352660
    PRI1(PIXEL_SIZE),
Packit 352660
    PRI1(STYLE),
Packit 352660
    PRI1(SLANT),
Packit 352660
    PRI1(WEIGHT),
Packit 352660
    PRI1(WIDTH),
Packit 352660
    PRI1(DECORATIVE),
Packit 352660
    PRI1(ANTIALIAS),
Packit 352660
    PRI1(RASTERIZER),
Packit 352660
    PRI1(OUTLINE),
Packit 352660
    PRI1(FONTVERSION),
Packit 352660
    PRI_END
Packit 352660
} FcMatcherPriority;
Packit 352660
Packit 352660
#undef PRI1
Packit 352660
Packit 352660
typedef struct _FcMatcher {
Packit 352660
    FcObject object;
Packit 352660
    double   (*compare) (const FcValue *v1, const FcValue *v2, FcValue *bestValue);
Packit 352660
    int      strong, weak;
Packit 352660
} FcMatcher;
Packit 352660
Packit 352660
/*
Packit 352660
 * Order is significant, it defines the precedence of
Packit 352660
 * each value, earlier values are more significant than
Packit 352660
 * later values
Packit 352660
 */
Packit 352660
#define FC_OBJECT(NAME, Type, Cmp)	{ FC_##NAME##_OBJECT,	Cmp,	PRI_##NAME##_STRONG,	PRI_##NAME##_WEAK },
Packit 352660
static const FcMatcher _FcMatchers [] = {
Packit 352660
    { FC_INVALID_OBJECT, NULL, -1, -1 },
Packit 352660
#include "fcobjs.h"
Packit 352660
};
Packit 352660
#undef FC_OBJECT
Packit 352660
Packit 352660
static const FcMatcher*
Packit 352660
FcObjectToMatcher (FcObject object,
Packit 352660
		   FcBool   include_lang)
Packit 352660
{
Packit 352660
    if (include_lang)
Packit 352660
    {
Packit 352660
	switch (object) {
Packit 352660
	case FC_FAMILYLANG_OBJECT:
Packit 352660
	case FC_STYLELANG_OBJECT:
Packit 352660
	case FC_FULLNAMELANG_OBJECT:
Packit 352660
	    object = FC_LANG_OBJECT;
Packit 352660
	    break;
Packit 352660
	}
Packit 352660
    }
Packit 352660
    if (object > FC_MAX_BASE_OBJECT ||
Packit 352660
	!_FcMatchers[object].compare ||
Packit 352660
	_FcMatchers[object].strong == -1 ||
Packit 352660
	_FcMatchers[object].weak == -1)
Packit 352660
	return NULL;
Packit 352660
Packit 352660
    return _FcMatchers + object;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCompareValueList (FcObject	     object,
Packit 352660
		    const FcMatcher *match,
Packit 352660
		    FcValueListPtr   v1orig,	/* pattern */
Packit 352660
		    FcValueListPtr   v2orig,	/* target */
Packit 352660
		    FcValue         *bestValue,
Packit 352660
		    double          *value,
Packit 352660
		    int             *n,
Packit 352660
		    FcResult        *result)
Packit 352660
{
Packit 352660
    FcValueListPtr  v1, v2;
Packit 352660
    double    	    v, best, bestStrong, bestWeak;
Packit 352660
    int		    j, k, pos = 0;
Packit 352660
Packit 352660
    if (!match)
Packit 352660
    {
Packit 352660
	if (bestValue)
Packit 352660
	    *bestValue = FcValueCanonicalize(&v2orig->value);
Packit 352660
	if (n)
Packit 352660
	    *n = 0;
Packit 352660
	return FcTrue;
Packit 352660
    }
Packit 352660
Packit 352660
    best = 1e99;
Packit 352660
    bestStrong = 1e99;
Packit 352660
    bestWeak = 1e99;
Packit 352660
    j = 0;
Packit 352660
    for (v1 = v1orig; v1; v1 = FcValueListNext(v1))
Packit 352660
    {
Packit 352660
	for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext(v2), k++)
Packit 352660
	{
Packit 352660
	    FcValue matchValue;
Packit 352660
	    v = (match->compare) (&v1->value, &v2->value, &matchValue);
Packit 352660
	    if (v < 0)
Packit 352660
	    {
Packit 352660
		*result = FcResultTypeMismatch;
Packit 352660
		return FcFalse;
Packit 352660
	    }
Packit 352660
	    v = v * 1000 + j;
Packit 352660
	    if (v < best)
Packit 352660
	    {
Packit 352660
		if (bestValue)
Packit 352660
		    *bestValue = matchValue;
Packit 352660
		best = v;
Packit 352660
		pos = k;
Packit 352660
	    }
Packit 352660
	    if (v1->binding == FcValueBindingStrong)
Packit 352660
	    {
Packit 352660
		if (v < bestStrong)
Packit 352660
		    bestStrong = v;
Packit 352660
	    }
Packit 352660
	    else
Packit 352660
	    {
Packit 352660
		if (v < bestWeak)
Packit 352660
		    bestWeak = v;
Packit 352660
	    }
Packit 352660
	}
Packit 352660
	j++;
Packit 352660
    }
Packit 352660
    if (FcDebug () & FC_DBG_MATCHV)
Packit 352660
    {
Packit 352660
	printf (" %s: %g ", FcObjectName (object), best);
Packit 352660
	FcValueListPrint (v1orig);
Packit 352660
	printf (", ");
Packit 352660
	FcValueListPrint (v2orig);
Packit 352660
	printf ("\n");
Packit 352660
    }
Packit 352660
    if (value)
Packit 352660
    {
Packit 352660
	int weak    = match->weak;
Packit 352660
	int strong  = match->strong;
Packit 352660
	if (weak == strong)
Packit 352660
	    value[strong] += best;
Packit 352660
	else
Packit 352660
	{
Packit 352660
	    value[weak] += bestWeak;
Packit 352660
	    value[strong] += bestStrong;
Packit 352660
	}
Packit 352660
    }
Packit 352660
    if (n)
Packit 352660
	*n = pos;
Packit 352660
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
/*
Packit 352660
 * Return a value indicating the distance between the two lists of
Packit 352660
 * values
Packit 352660
 */
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcCompare (FcPattern	*pat,
Packit 352660
	   FcPattern	*fnt,
Packit 352660
	   double	*value,
Packit 352660
	   FcResult	*result)
Packit 352660
{
Packit 352660
    int		    i, i1, i2;
Packit 352660
Packit 352660
    for (i = 0; i < PRI_END; i++)
Packit 352660
	value[i] = 0.0;
Packit 352660
Packit 352660
    i1 = 0;
Packit 352660
    i2 = 0;
Packit 352660
    while (i1 < pat->num && i2 < fnt->num)
Packit 352660
    {
Packit 352660
	FcPatternElt *elt_i1 = &FcPatternElts(pat)[i1];
Packit 352660
	FcPatternElt *elt_i2 = &FcPatternElts(fnt)[i2];
Packit 352660
Packit 352660
	i = FcObjectCompare(elt_i1->object, elt_i2->object);
Packit 352660
	if (i > 0)
Packit 352660
	    i2++;
Packit 352660
	else if (i < 0)
Packit 352660
	    i1++;
Packit 352660
	else
Packit 352660
	{
Packit 352660
	    const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse);
Packit 352660
	    if (!FcCompareValueList (elt_i1->object, match,
Packit 352660
				     FcPatternEltValues(elt_i1),
Packit 352660
				     FcPatternEltValues(elt_i2),
Packit 352660
				     NULL, value, NULL, result))
Packit 352660
		return FcFalse;
Packit 352660
	    i1++;
Packit 352660
	    i2++;
Packit 352660
	}
Packit 352660
    }
Packit 352660
    return FcTrue;
Packit 352660
}
Packit 352660
Packit 352660
FcPattern *
Packit 352660
FcFontRenderPrepare (FcConfig	    *config,
Packit 352660
		     FcPattern	    *pat,
Packit 352660
		     FcPattern	    *font)
Packit 352660
{
Packit 352660
    FcPattern	    *new;
Packit 352660
    int		    i;
Packit 352660
    FcPatternElt    *fe, *pe;
Packit 352660
    FcValue	    v;
Packit 352660
    FcResult	    result;
Packit 352660
    FcBool	    variable = FcFalse;
Packit 352660
    FcStrBuf        variations;
Packit 352660
Packit 352660
    assert (pat != NULL);
Packit 352660
    assert (font != NULL);
Packit 352660
Packit 352660
    FcPatternObjectGetBool (font, FC_VARIABLE_OBJECT, 0, &variable);
Packit 352660
    assert (variable != FcDontCare);
Packit 352660
    if (variable)
Packit 352660
	FcStrBufInit (&variations, NULL, 0);
Packit 352660
Packit 352660
    new = FcPatternCreate ();
Packit 352660
    if (!new)
Packit 352660
	return NULL;
Packit 352660
    for (i = 0; i < font->num; i++)
Packit 352660
    {
Packit 352660
	fe = &FcPatternElts(font)[i];
Packit 352660
	if (fe->object == FC_FAMILYLANG_OBJECT ||
Packit 352660
	    fe->object == FC_STYLELANG_OBJECT ||
Packit 352660
	    fe->object == FC_FULLNAMELANG_OBJECT)
Packit 352660
	{
Packit 352660
	    /* ignore those objects. we need to deal with them
Packit 352660
	     * another way */
Packit 352660
	    continue;
Packit 352660
	}
Packit 352660
	if (fe->object == FC_FAMILY_OBJECT ||
Packit 352660
	    fe->object == FC_STYLE_OBJECT ||
Packit 352660
	    fe->object == FC_FULLNAME_OBJECT)
Packit 352660
	{
Packit 352660
	    FcPatternElt    *fel, *pel;
Packit 352660
Packit 352660
	    FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT);
Packit 352660
	    FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT);
Packit 352660
	    FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT);
Packit 352660
Packit 352660
	    fel = FcPatternObjectFindElt (font, fe->object + 1);
Packit 352660
	    pel = FcPatternObjectFindElt (pat, fe->object + 1);
Packit 352660
Packit 352660
	    if (fel && pel)
Packit 352660
	    {
Packit 352660
		/* The font has name languages, and pattern asks for specific language(s).
Packit 352660
		 * Match on language and and prefer that result.
Packit 352660
		 * Note:  Currently the code only give priority to first matching language.
Packit 352660
		 */
Packit 352660
		int n = 1, j;
Packit 352660
		FcValueListPtr l1, l2, ln = NULL, ll = NULL;
Packit 352660
		const FcMatcher *match = FcObjectToMatcher (pel->object, FcTrue);
Packit 352660
Packit 352660
		if (!FcCompareValueList (pel->object, match,
Packit 352660
					 FcPatternEltValues (pel),
Packit 352660
					 FcPatternEltValues (fel), NULL, NULL, &n, &result))
Packit 352660
		{
Packit 352660
		    FcPatternDestroy (new);
Packit 352660
		    return NULL;
Packit 352660
		}
Packit 352660
Packit 352660
		for (j = 0, l1 = FcPatternEltValues (fe), l2 = FcPatternEltValues (fel);
Packit 352660
		     l1 != NULL || l2 != NULL;
Packit 352660
		     j++, l1 = l1 ? FcValueListNext (l1) : NULL, l2 = l2 ? FcValueListNext (l2) : NULL)
Packit 352660
		{
Packit 352660
		    if (j == n)
Packit 352660
		    {
Packit 352660
			if (l1)
Packit 352660
			    ln = FcValueListPrepend (ln,
Packit 352660
						     FcValueCanonicalize (&l1->value),
Packit 352660
						     FcValueBindingStrong);
Packit 352660
			if (l2)
Packit 352660
			    ll = FcValueListPrepend (ll,
Packit 352660
						     FcValueCanonicalize (&l2->value),
Packit 352660
						     FcValueBindingStrong);
Packit 352660
		    }
Packit 352660
		    else
Packit 352660
		    {
Packit 352660
			if (l1)
Packit 352660
			    ln = FcValueListAppend (ln,
Packit 352660
						    FcValueCanonicalize (&l1->value),
Packit 352660
						    FcValueBindingStrong);
Packit 352660
			if (l2)
Packit 352660
			    ll = FcValueListAppend (ll,
Packit 352660
						    FcValueCanonicalize (&l2->value),
Packit 352660
						    FcValueBindingStrong);
Packit 352660
		    }
Packit 352660
		}
Packit 352660
		FcPatternObjectListAdd (new, fe->object, ln, FcFalse);
Packit 352660
		FcPatternObjectListAdd (new, fel->object, ll, FcFalse);
Packit 352660
Packit 352660
		continue;
Packit 352660
	    }
Packit 352660
	    else if (fel)
Packit 352660
	    {
Packit 352660
		/* Pattern doesn't ask for specific language.  Copy all for name and
Packit 352660
		 * lang. */
Packit 352660
		FcValueListPtr l1, l2;
Packit 352660
Packit 352660
		l1 = FcValueListDuplicate (FcPatternEltValues (fe));
Packit 352660
		l2 = FcValueListDuplicate (FcPatternEltValues (fel));
Packit 352660
		FcPatternObjectListAdd (new, fe->object, l1, FcFalse);
Packit 352660
		FcPatternObjectListAdd (new, fel->object, l2, FcFalse);
Packit 352660
Packit 352660
		continue;
Packit 352660
	    }
Packit 352660
	}
Packit 352660
Packit 352660
	pe = FcPatternObjectFindElt (pat, fe->object);
Packit 352660
	if (pe)
Packit 352660
	{
Packit 352660
	    const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse);
Packit 352660
	    if (!FcCompareValueList (pe->object, match,
Packit 352660
				     FcPatternEltValues(pe),
Packit 352660
				     FcPatternEltValues(fe), &v, NULL, NULL, &result))
Packit 352660
	    {
Packit 352660
		FcPatternDestroy (new);
Packit 352660
		return NULL;
Packit 352660
	    }
Packit 352660
	    FcPatternObjectAdd (new, fe->object, v, FcFalse);
Packit 352660
Packit 352660
	    /* Set font-variations settings for standard axes in variable fonts. */
Packit 352660
	    if (variable &&
Packit 352660
		FcPatternEltValues(fe)->value.type == FcTypeRange &&
Packit 352660
		(fe->object == FC_WEIGHT_OBJECT ||
Packit 352660
		 fe->object == FC_WIDTH_OBJECT ||
Packit 352660
		 fe->object == FC_SIZE_OBJECT))
Packit 352660
	    {
Packit 352660
		double num;
Packit 352660
		FcChar8 temp[128];
Packit 352660
		const char *tag = "    ";
Packit 352660
		assert (v.type == FcTypeDouble);
Packit 352660
		num = v.u.d;
Packit 352660
		if (variations.len)
Packit 352660
		    FcStrBufChar (&variations, ',');
Packit 352660
		switch (fe->object)
Packit 352660
		{
Packit 352660
		    case FC_WEIGHT_OBJECT:
Packit 352660
			tag = "wght";
Packit 352660
			num = FcWeightToOpenType (num);
Packit 352660
			break;
Packit 352660
Packit 352660
		    case FC_WIDTH_OBJECT:
Packit 352660
			tag = "wdth";
Packit 352660
			break;
Packit 352660
Packit 352660
		    case FC_SIZE_OBJECT:
Packit 352660
			tag = "opsz";
Packit 352660
			break;
Packit 352660
		}
Packit 352660
		sprintf ((char *) temp, "%4s=%g", tag, num);
Packit 352660
		FcStrBufString (&variations, temp);
Packit 352660
	    }
Packit 352660
	}
Packit 352660
	else
Packit 352660
	{
Packit 352660
	    FcPatternObjectListAdd (new, fe->object,
Packit 352660
				    FcValueListDuplicate (FcPatternEltValues (fe)),
Packit 352660
				    FcTrue);
Packit 352660
	}
Packit 352660
    }
Packit 352660
    for (i = 0; i < pat->num; i++)
Packit 352660
    {
Packit 352660
	pe = &FcPatternElts(pat)[i];
Packit 352660
	fe = FcPatternObjectFindElt (font, pe->object);
Packit 352660
	if (!fe &&
Packit 352660
	    pe->object != FC_FAMILYLANG_OBJECT &&
Packit 352660
	    pe->object != FC_STYLELANG_OBJECT &&
Packit 352660
	    pe->object != FC_FULLNAMELANG_OBJECT)
Packit 352660
	{
Packit 352660
	    FcPatternObjectListAdd (new, pe->object,
Packit 352660
				    FcValueListDuplicate (FcPatternEltValues(pe)),
Packit 352660
				    FcFalse);
Packit 352660
	}
Packit 352660
    }
Packit 352660
Packit 352660
    if (variable && variations.len)
Packit 352660
    {
Packit 352660
	FcChar8 *vars = NULL;
Packit 352660
	if (FcPatternObjectGetString (new, FC_FONT_VARIATIONS_OBJECT, 0, &vars) == FcResultMatch)
Packit 352660
	{
Packit 352660
	    FcStrBufChar (&variations, ',');
Packit 352660
	    FcStrBufString (&variations, vars);
Packit 352660
	    FcPatternObjectDel (new, FC_FONT_VARIATIONS_OBJECT);
Packit 352660
	}
Packit 352660
Packit 352660
	FcPatternObjectAddString (new, FC_FONT_VARIATIONS_OBJECT, FcStrBufDoneStatic (&variations));
Packit 352660
	FcStrBufDestroy (&variations);
Packit 352660
    }
Packit 352660
Packit 352660
    FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
Packit 352660
    return new;
Packit 352660
}
Packit 352660
Packit 352660
static FcPattern *
Packit 352660
FcFontSetMatchInternal (FcFontSet   **sets,
Packit 352660
			int	    nsets,
Packit 352660
			FcPattern   *p,
Packit 352660
			FcResult    *result)
Packit 352660
{
Packit 352660
    double    	    score[PRI_END], bestscore[PRI_END];
Packit 352660
    int		    f;
Packit 352660
    FcFontSet	    *s;
Packit 352660
    FcPattern	    *best;
Packit 352660
    int		    i;
Packit 352660
    int		    set;
Packit 352660
Packit 352660
    for (i = 0; i < PRI_END; i++)
Packit 352660
	bestscore[i] = 0;
Packit 352660
    best = 0;
Packit 352660
    if (FcDebug () & FC_DBG_MATCH)
Packit 352660
    {
Packit 352660
	printf ("Match ");
Packit 352660
	FcPatternPrint (p);
Packit 352660
    }
Packit 352660
    for (set = 0; set < nsets; set++)
Packit 352660
    {
Packit 352660
	s = sets[set];
Packit 352660
	if (!s)
Packit 352660
	    continue;
Packit 352660
	for (f = 0; f < s->nfont; f++)
Packit 352660
	{
Packit 352660
	    if (FcDebug () & FC_DBG_MATCHV)
Packit 352660
	    {
Packit 352660
		printf ("Font %d ", f);
Packit 352660
		FcPatternPrint (s->fonts[f]);
Packit 352660
	    }
Packit 352660
	    if (!FcCompare (p, s->fonts[f], score, result))
Packit 352660
		return 0;
Packit 352660
	    if (FcDebug () & FC_DBG_MATCHV)
Packit 352660
	    {
Packit 352660
		printf ("Score");
Packit 352660
		for (i = 0; i < PRI_END; i++)
Packit 352660
		{
Packit 352660
		    printf (" %g", score[i]);
Packit 352660
		}
Packit 352660
		printf ("\n");
Packit 352660
	    }
Packit 352660
	    for (i = 0; i < PRI_END; i++)
Packit 352660
	    {
Packit 352660
		if (best && bestscore[i] < score[i])
Packit 352660
		    break;
Packit 352660
		if (!best || score[i] < bestscore[i])
Packit 352660
		{
Packit 352660
		    for (i = 0; i < PRI_END; i++)
Packit 352660
			bestscore[i] = score[i];
Packit 352660
		    best = s->fonts[f];
Packit 352660
		    break;
Packit 352660
		}
Packit 352660
	    }
Packit 352660
	}
Packit 352660
    }
Packit 352660
    if (FcDebug () & FC_DBG_MATCH)
Packit 352660
    {
Packit 352660
	printf ("Best score");
Packit 352660
	for (i = 0; i < PRI_END; i++)
Packit 352660
	    printf (" %g", bestscore[i]);
Packit 352660
	printf ("\n");
Packit 352660
	FcPatternPrint (best);
Packit 352660
    }
Packit 352660
    if (FcDebug () & FC_DBG_MATCH2)
Packit 352660
    {
Packit 352660
	char *env = getenv ("FC_DBG_MATCH_FILTER");
Packit 352660
	FcObjectSet *os = NULL;
Packit 352660
Packit 352660
	if (env)
Packit 352660
	{
Packit 352660
	    char *ss, *s;
Packit 352660
	    char *p;
Packit 352660
	    FcBool f = FcTrue;
Packit 352660
Packit 352660
	    ss = s = strdup (env);
Packit 352660
	    os = FcObjectSetCreate ();
Packit 352660
	    while (f)
Packit 352660
	    {
Packit 352660
		size_t len;
Packit 352660
		char *x;
Packit 352660
Packit 352660
		if (!(p = strchr (s, ',')))
Packit 352660
		{
Packit 352660
		    f = FcFalse;
Packit 352660
		    len = strlen (s);
Packit 352660
		}
Packit 352660
		else
Packit 352660
		{
Packit 352660
		    len = (p - s);
Packit 352660
		}
Packit 352660
		x = malloc (sizeof (char) * (len + 1));
Packit 352660
		if (x)
Packit 352660
		{
Packit 352660
		    strcpy (x, s);
Packit 352660
		    if (FcObjectFromName (x) > 0)
Packit 352660
			FcObjectSetAdd (os, x);
Packit 352660
		    s = p + 1;
Packit 352660
		    free (x);
Packit 352660
		}
Packit 352660
	    }
Packit 352660
	    free (ss);
Packit 352660
	}
Packit 352660
	FcPatternPrint2 (p, best, os);
Packit 352660
	if (os)
Packit 352660
	    FcObjectSetDestroy (os);
Packit 352660
    }
Packit 352660
    /* assuming that 'result' is initialized with FcResultNoMatch
Packit 352660
     * outside this function */
Packit 352660
    if (best)
Packit 352660
	*result = FcResultMatch;
Packit 352660
Packit 352660
    return best;
Packit 352660
}
Packit 352660
Packit 352660
FcPattern *
Packit 352660
FcFontSetMatch (FcConfig    *config,
Packit 352660
		FcFontSet   **sets,
Packit 352660
		int	    nsets,
Packit 352660
		FcPattern   *p,
Packit 352660
		FcResult    *result)
Packit 352660
{
Packit 352660
    FcPattern	    *best;
Packit 352660
Packit 352660
    assert (sets != NULL);
Packit 352660
    assert (p != NULL);
Packit 352660
    assert (result != NULL);
Packit 352660
Packit 352660
    *result = FcResultNoMatch;
Packit 352660
Packit 352660
    if (!config)
Packit 352660
    {
Packit 352660
	config = FcConfigGetCurrent ();
Packit 352660
	if (!config)
Packit 352660
	    return 0;
Packit 352660
    }
Packit 352660
    best = FcFontSetMatchInternal (sets, nsets, p, result);
Packit 352660
    if (best)
Packit 352660
	return FcFontRenderPrepare (config, p, best);
Packit 352660
    else
Packit 352660
	return NULL;
Packit 352660
}
Packit 352660
Packit 352660
FcPattern *
Packit 352660
FcFontMatch (FcConfig	*config,
Packit 352660
	     FcPattern	*p,
Packit 352660
	     FcResult	*result)
Packit 352660
{
Packit 352660
    FcFontSet	*sets[2];
Packit 352660
    int		nsets;
Packit 352660
    FcPattern   *best;
Packit 352660
Packit 352660
    assert (p != NULL);
Packit 352660
    assert (result != NULL);
Packit 352660
Packit 352660
    *result = FcResultNoMatch;
Packit 352660
Packit 352660
    if (!config)
Packit 352660
    {
Packit 352660
	config = FcConfigGetCurrent ();
Packit 352660
	if (!config)
Packit 352660
	    return 0;
Packit 352660
    }
Packit 352660
    nsets = 0;
Packit 352660
    if (config->fonts[FcSetSystem])
Packit 352660
	sets[nsets++] = config->fonts[FcSetSystem];
Packit 352660
    if (config->fonts[FcSetApplication])
Packit 352660
	sets[nsets++] = config->fonts[FcSetApplication];
Packit 352660
Packit 352660
    best = FcFontSetMatchInternal (sets, nsets, p, result);
Packit 352660
    if (best)
Packit 352660
	return FcFontRenderPrepare (config, p, best);
Packit 352660
    else
Packit 352660
	return NULL;
Packit 352660
}
Packit 352660
Packit 352660
typedef struct _FcSortNode {
Packit 352660
    FcPattern	*pattern;
Packit 352660
    double	score[PRI_END];
Packit 352660
} FcSortNode;
Packit 352660
Packit 352660
static int
Packit 352660
FcSortCompare (const void *aa, const void *ab)
Packit 352660
{
Packit 352660
    FcSortNode  *a = *(FcSortNode **) aa;
Packit 352660
    FcSortNode  *b = *(FcSortNode **) ab;
Packit 352660
    double	*as = &a->score[0];
Packit 352660
    double	*bs = &b->score[0];
Packit 352660
    double	ad = 0, bd = 0;
Packit 352660
    int         i;
Packit 352660
Packit 352660
    i = PRI_END;
Packit 352660
    while (i-- && (ad = *as++) == (bd = *bs++))
Packit 352660
	;
Packit 352660
    return ad < bd ? -1 : ad > bd ? 1 : 0;
Packit 352660
}
Packit 352660
Packit 352660
static FcBool
Packit 352660
FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
Packit 352660
{
Packit 352660
    FcBool ret = FcFalse;
Packit 352660
    FcCharSet *cs;
Packit 352660
    int i;
Packit 352660
Packit 352660
    cs = 0;
Packit 352660
    if (trim || csp)
Packit 352660
    {
Packit 352660
	cs = FcCharSetCreate ();
Packit 352660
	if (cs == NULL)
Packit 352660
	    goto bail;
Packit 352660
    }
Packit 352660
Packit 352660
    for (i = 0; i < nnode; i++)
Packit 352660
    {
Packit 352660
	FcSortNode	*node = *n++;
Packit 352660
	FcBool		adds_chars = FcFalse;
Packit 352660
Packit 352660
	/*
Packit 352660
	 * Only fetch node charset if we'd need it
Packit 352660
	 */
Packit 352660
	if (cs)
Packit 352660
	{
Packit 352660
	    FcCharSet	*ncs;
Packit 352660
Packit 352660
	    if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
Packit 352660
		FcResultMatch)
Packit 352660
	        continue;
Packit 352660
Packit 352660
	    if (!FcCharSetMerge (cs, ncs, &adds_chars))
Packit 352660
		goto bail;
Packit 352660
	}
Packit 352660
Packit 352660
	/*
Packit 352660
	 * If this font isn't a subset of the previous fonts,
Packit 352660
	 * add it to the list
Packit 352660
	 */
Packit 352660
	if (!i || !trim || adds_chars)
Packit 352660
	{
Packit 352660
	    FcPatternReference (node->pattern);
Packit 352660
	    if (FcDebug () & FC_DBG_MATCHV)
Packit 352660
	    {
Packit 352660
		printf ("Add ");
Packit 352660
		FcPatternPrint (node->pattern);
Packit 352660
	    }
Packit 352660
	    if (!FcFontSetAdd (fs, node->pattern))
Packit 352660
	    {
Packit 352660
		FcPatternDestroy (node->pattern);
Packit 352660
		goto bail;
Packit 352660
	    }
Packit 352660
	}
Packit 352660
    }
Packit 352660
    if (csp)
Packit 352660
    {
Packit 352660
	*csp = cs;
Packit 352660
	cs = 0;
Packit 352660
    }
Packit 352660
Packit 352660
    ret = FcTrue;
Packit 352660
Packit 352660
bail:
Packit 352660
    if (cs)
Packit 352660
	FcCharSetDestroy (cs);
Packit 352660
Packit 352660
    return ret;
Packit 352660
}
Packit 352660
Packit 352660
void
Packit 352660
FcFontSetSortDestroy (FcFontSet *fs)
Packit 352660
{
Packit 352660
    FcFontSetDestroy (fs);
Packit 352660
}
Packit 352660
Packit 352660
FcFontSet *
Packit 352660
FcFontSetSort (FcConfig	    *config FC_UNUSED,
Packit 352660
	       FcFontSet    **sets,
Packit 352660
	       int	    nsets,
Packit 352660
	       FcPattern    *p,
Packit 352660
	       FcBool	    trim,
Packit 352660
	       FcCharSet    **csp,
Packit 352660
	       FcResult	    *result)
Packit 352660
{
Packit 352660
    FcFontSet	    *ret;
Packit 352660
    FcFontSet	    *s;
Packit 352660
    FcSortNode	    *nodes;
Packit 352660
    FcSortNode	    **nodeps, **nodep;
Packit 352660
    int		    nnodes;
Packit 352660
    FcSortNode	    *new;
Packit 352660
    int		    set;
Packit 352660
    int		    f;
Packit 352660
    int		    i;
Packit 352660
    int		    nPatternLang;
Packit 352660
    FcBool    	    *patternLangSat;
Packit 352660
    FcValue	    patternLang;
Packit 352660
Packit 352660
    assert (sets != NULL);
Packit 352660
    assert (p != NULL);
Packit 352660
    assert (result != NULL);
Packit 352660
Packit 352660
    /* There are some implementation that relying on the result of
Packit 352660
     * "result" to check if the return value of FcFontSetSort
Packit 352660
     * is valid or not.
Packit 352660
     * So we should initialize it to the conservative way since
Packit 352660
     * this function doesn't return NULL anymore.
Packit 352660
     */
Packit 352660
    if (result)
Packit 352660
	*result = FcResultNoMatch;
Packit 352660
Packit 352660
    if (FcDebug () & FC_DBG_MATCH)
Packit 352660
    {
Packit 352660
	printf ("Sort ");
Packit 352660
	FcPatternPrint (p);
Packit 352660
    }
Packit 352660
    nnodes = 0;
Packit 352660
    for (set = 0; set < nsets; set++)
Packit 352660
    {
Packit 352660
	s = sets[set];
Packit 352660
	if (!s)
Packit 352660
	    continue;
Packit 352660
	nnodes += s->nfont;
Packit 352660
    }
Packit 352660
    if (!nnodes)
Packit 352660
	return FcFontSetCreate ();
Packit 352660
Packit 352660
    for (nPatternLang = 0;
Packit 352660
	 FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
Packit 352660
	 nPatternLang++)
Packit 352660
	;
Packit 352660
	
Packit 352660
    /* freed below */
Packit 352660
    nodes = malloc (nnodes * sizeof (FcSortNode) +
Packit 352660
		    nnodes * sizeof (FcSortNode *) +
Packit 352660
		    nPatternLang * sizeof (FcBool));
Packit 352660
    if (!nodes)
Packit 352660
	goto bail0;
Packit 352660
    nodeps = (FcSortNode **) (nodes + nnodes);
Packit 352660
    patternLangSat = (FcBool *) (nodeps + nnodes);
Packit 352660
Packit 352660
    new = nodes;
Packit 352660
    nodep = nodeps;
Packit 352660
    for (set = 0; set < nsets; set++)
Packit 352660
    {
Packit 352660
	s = sets[set];
Packit 352660
	if (!s)
Packit 352660
	    continue;
Packit 352660
	for (f = 0; f < s->nfont; f++)
Packit 352660
	{
Packit 352660
	    if (FcDebug () & FC_DBG_MATCHV)
Packit 352660
	    {
Packit 352660
		printf ("Font %d ", f);
Packit 352660
		FcPatternPrint (s->fonts[f]);
Packit 352660
	    }
Packit 352660
	    new->pattern = s->fonts[f];
Packit 352660
	    if (!FcCompare (p, new->pattern, new->score, result))
Packit 352660
		goto bail1;
Packit 352660
	    if (FcDebug () & FC_DBG_MATCHV)
Packit 352660
	    {
Packit 352660
		printf ("Score");
Packit 352660
		for (i = 0; i < PRI_END; i++)
Packit 352660
		{
Packit 352660
		    printf (" %g", new->score[i]);
Packit 352660
		}
Packit 352660
		printf ("\n");
Packit 352660
	    }
Packit 352660
	    *nodep = new;
Packit 352660
	    new++;
Packit 352660
	    nodep++;
Packit 352660
	}
Packit 352660
    }
Packit 352660
Packit 352660
    nnodes = new - nodes;
Packit 352660
Packit 352660
    qsort (nodeps, nnodes, sizeof (FcSortNode *),
Packit 352660
	   FcSortCompare);
Packit 352660
Packit 352660
    for (i = 0; i < nPatternLang; i++)
Packit 352660
	patternLangSat[i] = FcFalse;
Packit 352660
Packit 352660
    for (f = 0; f < nnodes; f++)
Packit 352660
    {
Packit 352660
	FcBool	satisfies = FcFalse;
Packit 352660
	/*
Packit 352660
	 * If this node matches any language, go check
Packit 352660
	 * which ones and satisfy those entries
Packit 352660
	 */
Packit 352660
	if (nodeps[f]->score[PRI_LANG] < 2000)
Packit 352660
	{
Packit 352660
	    for (i = 0; i < nPatternLang; i++)
Packit 352660
	    {
Packit 352660
		FcValue	    nodeLang;
Packit 352660
		
Packit 352660
		if (!patternLangSat[i] &&
Packit 352660
		    FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
Packit 352660
		    FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
Packit 352660
		{
Packit 352660
		    FcValue matchValue;
Packit 352660
		    double  compare = FcCompareLang (&patternLang, &nodeLang, &matchValue);
Packit 352660
		    if (compare >= 0 && compare < 2)
Packit 352660
		    {
Packit 352660
			if (FcDebug () & FC_DBG_MATCHV)
Packit 352660
			{
Packit 352660
			    FcChar8 *family;
Packit 352660
			    FcChar8 *style;
Packit 352660
Packit 352660
			    if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
Packit 352660
				FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
Packit 352660
				printf ("Font %s:%s matches language %d\n", family, style, i);
Packit 352660
			}
Packit 352660
			patternLangSat[i] = FcTrue;
Packit 352660
			satisfies = FcTrue;
Packit 352660
			break;
Packit 352660
		    }
Packit 352660
		}
Packit 352660
	    }
Packit 352660
	}
Packit 352660
	if (!satisfies)
Packit 352660
	{
Packit 352660
	    nodeps[f]->score[PRI_LANG] = 10000.0;
Packit 352660
	}
Packit 352660
    }
Packit 352660
Packit 352660
    /*
Packit 352660
     * Re-sort once the language issues have been settled
Packit 352660
     */
Packit 352660
    qsort (nodeps, nnodes, sizeof (FcSortNode *),
Packit 352660
	   FcSortCompare);
Packit 352660
Packit 352660
    ret = FcFontSetCreate ();
Packit 352660
    if (!ret)
Packit 352660
	goto bail1;
Packit 352660
Packit 352660
    if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
Packit 352660
	goto bail2;
Packit 352660
Packit 352660
    free (nodes);
Packit 352660
Packit 352660
    if (FcDebug() & FC_DBG_MATCH)
Packit 352660
    {
Packit 352660
	printf ("First font ");
Packit 352660
	FcPatternPrint (ret->fonts[0]);
Packit 352660
    }
Packit 352660
    if (ret->nfont > 0)
Packit 352660
	*result = FcResultMatch;
Packit 352660
Packit 352660
    return ret;
Packit 352660
Packit 352660
bail2:
Packit 352660
    FcFontSetDestroy (ret);
Packit 352660
bail1:
Packit 352660
    free (nodes);
Packit 352660
bail0:
Packit 352660
    return 0;
Packit 352660
}
Packit 352660
Packit 352660
FcFontSet *
Packit 352660
FcFontSort (FcConfig	*config,
Packit 352660
	    FcPattern	*p,
Packit 352660
	    FcBool	trim,
Packit 352660
	    FcCharSet	**csp,
Packit 352660
	    FcResult	*result)
Packit 352660
{
Packit 352660
    FcFontSet	*sets[2];
Packit 352660
    int		nsets;
Packit 352660
Packit 352660
    assert (p != NULL);
Packit 352660
    assert (result != NULL);
Packit 352660
Packit 352660
    *result = FcResultNoMatch;
Packit 352660
Packit 352660
    if (!config)
Packit 352660
    {
Packit 352660
	config = FcConfigGetCurrent ();
Packit 352660
	if (!config)
Packit 352660
	    return 0;
Packit 352660
    }
Packit 352660
    nsets = 0;
Packit 352660
    if (config->fonts[FcSetSystem])
Packit 352660
	sets[nsets++] = config->fonts[FcSetSystem];
Packit 352660
    if (config->fonts[FcSetApplication])
Packit 352660
	sets[nsets++] = config->fonts[FcSetApplication];
Packit 352660
    return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
Packit 352660
}
Packit 352660
#define __fcmatch__
Packit 352660
#include "fcaliastail.h"
Packit 352660
#undef __fcmatch__