fcmatch.c revision 7872e0a1
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 (const FcValue *value1, const FcValue *value2, FcValue *bestValue)
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    *bestValue = FcValueCanonicalize (value2);
58    return v;
59}
60
61static double
62FcCompareString (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
63{
64    *bestValue = FcValueCanonicalize (v2);
65    return (double) FcStrCmpIgnoreCase (FcValueString(v1), FcValueString(v2)) != 0;
66}
67
68static double
69FcCompareFamily (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
70{
71    /* rely on the guarantee in FcPatternObjectAddWithBinding that
72     * families are always FcTypeString. */
73    const FcChar8* v1_string = FcValueString(v1);
74    const FcChar8* v2_string = FcValueString(v2);
75
76    *bestValue = FcValueCanonicalize (v2);
77
78    if (FcToLower(*v1_string) != FcToLower(*v2_string) &&
79	*v1_string != ' ' && *v2_string != ' ')
80       return 1.0;
81
82    return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0;
83}
84
85static double
86FcComparePostScript (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
87{
88    const FcChar8 *v1_string = FcValueString (v1);
89    const FcChar8 *v2_string = FcValueString (v2);
90    int n;
91    size_t len1, len2, mlen;
92
93    *bestValue = FcValueCanonicalize (v2);
94
95    if (FcToLower (*v1_string) != FcToLower (*v2_string) &&
96	*v1_string != ' ' && *v2_string != ' ')
97	return 1.0;
98
99    n = FcStrMatchIgnoreCaseAndDelims (v1_string, v2_string, (const FcChar8 *)" -");
100    len1 = strlen ((const char *)v1_string);
101    len2 = strlen ((const char *)v2_string);
102    mlen = FC_MAX (len1, len2);
103
104    return (double)(mlen - n) / (double)mlen;
105}
106
107static double
108FcCompareLang (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
109{
110    FcLangResult    result;
111
112    switch ((int) v1->type) {
113    case FcTypeLangSet:
114	switch ((int) v2->type) {
115	case FcTypeLangSet:
116	    result = FcLangSetCompare (FcValueLangSet (v1), FcValueLangSet (v2));
117	    break;
118	case FcTypeString:
119	    result = FcLangSetHasLang (FcValueLangSet (v1), FcValueString (v2));
120	    break;
121	default:
122	    return -1.0;
123	}
124	break;
125    case FcTypeString:
126	switch ((int) v2->type) {
127	case FcTypeLangSet:
128	    result = FcLangSetHasLang (FcValueLangSet (v2), FcValueString (v1));
129	    break;
130	case FcTypeString:
131	    result = FcLangCompare (FcValueString (v1), FcValueString (v2));
132	    break;
133	default:
134	    return -1.0;
135	}
136	break;
137    default:
138	return -1.0;
139    }
140    *bestValue = FcValueCanonicalize (v2);
141    switch (result) {
142    case FcLangEqual:
143	return 0;
144    case FcLangDifferentCountry:
145	return 1;
146    case FcLangDifferentLang:
147    default:
148	return 2;
149    }
150}
151
152static double
153FcCompareBool (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
154{
155    if (v2->type != FcTypeBool || v1->type != FcTypeBool)
156	return -1.0;
157
158    bestValue->type = FcTypeBool;
159    if (v2->u.b != FcDontCare)
160	bestValue->u.b = v2->u.b;
161    else
162	bestValue->u.b = v1->u.b;
163
164    return (double) ((v2->u.b ^ v1->u.b) == 1);
165}
166
167static double
168FcCompareCharSet (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
169{
170    *bestValue = FcValueCanonicalize (v2); /* TODO Improve. */
171    return (double) FcCharSetSubtractCount (FcValueCharSet(v1), FcValueCharSet(v2));
172}
173
174static double
175FcCompareRange (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
176{
177    FcValue value1 = FcValueCanonicalize (v1);
178    FcValue value2 = FcValueCanonicalize (v2);
179    double b1, e1, b2, e2, d;
180
181    switch ((int) value1.type) {
182    case FcTypeInteger:
183        b1 = e1 = value1.u.i;
184	break;
185    case FcTypeDouble:
186        b1 = e1 = value1.u.d;
187	break;
188    case FcTypeRange:
189	b1 = value1.u.r->begin;
190	e1 = value1.u.r->end;
191	break;
192    default:
193	return -1;
194    }
195    switch ((int) value2.type) {
196    case FcTypeInteger:
197        b2 = e2 = value2.u.i;
198	break;
199    case FcTypeDouble:
200        b2 = e2 = value2.u.d;
201	break;
202    case FcTypeRange:
203	b2 = value2.u.r->begin;
204	e2 = value2.u.r->end;
205	break;
206    default:
207	return -1;
208    }
209
210    if (e1 < b2)
211      d = b2;
212    else if (e2 < b1)
213      d = e2;
214    else
215      d = (FC_MAX (b1, b2) + FC_MIN (e1, e2)) * .5;
216
217    bestValue->type = FcTypeDouble;
218    bestValue->u.d = d;
219
220    /* If the ranges overlap, it's a match, otherwise return closest distance. */
221    if (e1 < b2 || e2 < b1)
222	return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
223    else
224	return 0.0;
225}
226
227static double
228FcCompareSize (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
229{
230    FcValue value1 = FcValueCanonicalize (v1);
231    FcValue value2 = FcValueCanonicalize (v2);
232    double b1, e1, b2, e2;
233
234    switch ((int) value1.type) {
235    case FcTypeInteger:
236        b1 = e1 = value1.u.i;
237	break;
238    case FcTypeDouble:
239        b1 = e1 = value1.u.d;
240	break;
241    case FcTypeRange:
242	b1 = value1.u.r->begin;
243	e1 = value1.u.r->end;
244	break;
245    default:
246	return -1;
247    }
248    switch ((int) value2.type) {
249    case FcTypeInteger:
250        b2 = e2 = value2.u.i;
251	break;
252    case FcTypeDouble:
253        b2 = e2 = value2.u.d;
254	break;
255    case FcTypeRange:
256	b2 = value2.u.r->begin;
257	e2 = value2.u.r->end;
258	break;
259    default:
260	return -1;
261    }
262
263    bestValue->type = FcTypeDouble;
264    bestValue->u.d = (b1 + e1) * .5;
265
266    /* If the ranges overlap, it's a match, otherwise return closest distance. */
267    if (e1 < b2 || e2 < b1)
268	return FC_MIN (fabs (b2 - e1), fabs (b1 - e2));
269    if (b2 != e2 && b1 == e2) /* Semi-closed interval. */
270        return 1e-15;
271    else
272	return 0.0;
273}
274
275static double
276FcCompareFilename (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
277{
278    const FcChar8 *s1 = FcValueString (v1), *s2 = FcValueString (v2);
279    *bestValue = FcValueCanonicalize (v2);
280    if (FcStrCmp (s1, s2) == 0)
281	return 0.0;
282    else if (FcStrCmpIgnoreCase (s1, s2) == 0)
283	return 1.0;
284    else if (FcStrGlobMatch (s1, s2))
285	return 2.0;
286    else
287	return 3.0;
288}
289
290
291/* Define priorities to -1 for objects that don't have a compare function. */
292
293#define PRI_NULL(n)				\
294    PRI_ ## n ## _STRONG = -1,			\
295    PRI_ ## n ## _WEAK = -1,
296#define PRI1(n)
297#define PRI_FcCompareFamily(n)		PRI1(n)
298#define PRI_FcCompareString(n)		PRI1(n)
299#define PRI_FcCompareNumber(n)		PRI1(n)
300#define PRI_FcCompareBool(n)		PRI1(n)
301#define PRI_FcCompareFilename(n)	PRI1(n)
302#define PRI_FcCompareCharSet(n)		PRI1(n)
303#define PRI_FcCompareLang(n)		PRI1(n)
304#define PRI_FcComparePostScript(n)	PRI1(n)
305#define PRI_FcCompareRange(n)		PRI1(n)
306#define PRI_FcCompareSize(n)		PRI1(n)
307
308#define FC_OBJECT(NAME, Type, Cmp)	PRI_##Cmp(NAME)
309
310typedef enum _FcMatcherPriorityDummy {
311#include "fcobjs.h"
312} FcMatcherPriorityDummy;
313
314#undef FC_OBJECT
315
316
317/* Canonical match priority order. */
318
319#undef PRI1
320#define PRI1(n)					\
321    PRI_ ## n,					\
322    PRI_ ## n ## _STRONG = PRI_ ## n,		\
323    PRI_ ## n ## _WEAK = PRI_ ## n
324
325typedef enum _FcMatcherPriority {
326    PRI1(FILE),
327    PRI1(FONTFORMAT),
328    PRI1(VARIABLE),
329    PRI1(SCALABLE),
330    PRI1(COLOR),
331    PRI1(FOUNDRY),
332    PRI1(CHARSET),
333    PRI_FAMILY_STRONG,
334    PRI_POSTSCRIPT_NAME_STRONG,
335    PRI1(LANG),
336    PRI_FAMILY_WEAK,
337    PRI_POSTSCRIPT_NAME_WEAK,
338    PRI1(SYMBOL),
339    PRI1(SPACING),
340    PRI1(SIZE),
341    PRI1(PIXEL_SIZE),
342    PRI1(STYLE),
343    PRI1(SLANT),
344    PRI1(WEIGHT),
345    PRI1(WIDTH),
346    PRI1(FONT_HAS_HINT),
347    PRI1(DECORATIVE),
348    PRI1(ANTIALIAS),
349    PRI1(RASTERIZER),
350    PRI1(OUTLINE),
351    PRI1(ORDER),
352    PRI1(FONTVERSION),
353    PRI_END
354} FcMatcherPriority;
355
356#undef PRI1
357
358typedef struct _FcMatcher {
359    FcObject object;
360    double   (*compare) (const FcValue *v1, const FcValue *v2, FcValue *bestValue);
361    int      strong, weak;
362} FcMatcher;
363
364/*
365 * Order is significant, it defines the precedence of
366 * each value, earlier values are more significant than
367 * later values
368 */
369#define FC_OBJECT(NAME, Type, Cmp)	{ FC_##NAME##_OBJECT,	Cmp,	PRI_##NAME##_STRONG,	PRI_##NAME##_WEAK },
370static const FcMatcher _FcMatchers [] = {
371    { FC_INVALID_OBJECT, NULL, -1, -1 },
372#include "fcobjs.h"
373};
374#undef FC_OBJECT
375
376static const FcMatcher*
377FcObjectToMatcher (FcObject object,
378		   FcBool   include_lang)
379{
380    if (include_lang)
381    {
382	switch (object) {
383	case FC_FAMILYLANG_OBJECT:
384	case FC_STYLELANG_OBJECT:
385	case FC_FULLNAMELANG_OBJECT:
386	    object = FC_LANG_OBJECT;
387	    break;
388	}
389    }
390    if (object > FC_MAX_BASE_OBJECT ||
391	!_FcMatchers[object].compare ||
392	_FcMatchers[object].strong == -1 ||
393	_FcMatchers[object].weak == -1)
394	return NULL;
395
396    return _FcMatchers + object;
397}
398
399static FcBool
400FcCompareValueList (FcObject	     object,
401		    const FcMatcher *match,
402		    FcValueListPtr   v1orig,	/* pattern */
403		    FcValueListPtr   v2orig,	/* target */
404		    FcValue         *bestValue,
405		    double          *value,
406		    int             *n,
407		    FcResult        *result)
408{
409    FcValueListPtr  v1, v2;
410    double    	    v, best, bestStrong, bestWeak;
411    int		    j, k, pos = 0;
412    int weak, strong;
413
414    if (!match)
415    {
416	if (bestValue)
417	    *bestValue = FcValueCanonicalize(&v2orig->value);
418	if (n)
419	    *n = 0;
420	return FcTrue;
421    }
422
423    weak    = match->weak;
424    strong  = match->strong;
425
426    best = DBL_MAX;
427    bestStrong = DBL_MAX;
428    bestWeak = DBL_MAX;
429    for (v1 = v1orig, j = 0; v1; v1 = FcValueListNext(v1), j++)
430    {
431	for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext(v2), k++)
432	{
433	    FcValue matchValue;
434	    v = (match->compare) (&v1->value, &v2->value, &matchValue);
435	    if (v < 0)
436	    {
437		*result = FcResultTypeMismatch;
438		return FcFalse;
439	    }
440	    v = v * 1000 + j * 100 + k * (v2->value.type == FcTypeString ? 1 : 0);
441	    if (v < best)
442	    {
443		if (bestValue)
444		    *bestValue = matchValue;
445		best = v;
446		pos = k;
447	    }
448            if (weak == strong)
449            {
450                /* found the best possible match */
451                if (best < 1000)
452                    goto done;
453            }
454            else if (v1->binding == FcValueBindingStrong)
455	    {
456		if (v < bestStrong)
457		    bestStrong = v;
458	    }
459	    else
460	    {
461		if (v < bestWeak)
462		    bestWeak = v;
463	    }
464	}
465    }
466done:
467    if (FcDebug () & FC_DBG_MATCHV)
468    {
469	printf (" %s: %g ", FcObjectName (object), best);
470	FcValueListPrint (v1orig);
471	printf (", ");
472	FcValueListPrint (v2orig);
473	printf ("\n");
474    }
475    if (value)
476    {
477	if (weak == strong)
478	    value[strong] += best;
479	else
480	{
481	    value[weak] += bestWeak;
482	    value[strong] += bestStrong;
483	}
484    }
485    if (n)
486	*n = pos;
487
488    return FcTrue;
489}
490
491/* The bulk of the time in FcFontMatch and FcFontSort goes to
492 * walking long lists of family names. We speed this up with a
493 * hash table.
494 */
495typedef struct
496{
497    double strong_value;
498    double weak_value;
499} FamilyEntry;
500
501typedef struct
502{
503    FcHashTable *family_hash;
504} FcCompareData;
505
506static void
507FcCompareDataClear (FcCompareData *data)
508{
509    FcHashTableDestroy (data->family_hash);
510}
511
512static void
513FcCompareDataInit (FcPattern     *pat,
514                   FcCompareData *data)
515{
516    FcHashTable *table;
517    FcPatternElt *elt;
518    FcValueListPtr l;
519    int i;
520    const void *key;
521    FamilyEntry *e;
522
523    table = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
524                               (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
525                               NULL,
526                               NULL,
527                               NULL,
528                               free);
529
530    elt = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
531    if (elt)
532    {
533        for (l = FcPatternEltValues(elt), i = 0; l; l = FcValueListNext(l), i++)
534        {
535            key = FcValueString (&l->value);
536            if (!FcHashTableFind (table, key, (void **)&e))
537            {
538                e = malloc (sizeof (FamilyEntry));
539                e->strong_value = 1e99;
540                e->weak_value = 1e99;
541                FcHashTableAdd (table, (void *)key, e);
542            }
543            if (l->binding == FcValueBindingWeak)
544            {
545                if (i < e->weak_value)
546                    e->weak_value = i;
547            }
548            else
549            {
550                if (i < e->strong_value)
551                    e->strong_value = i;
552            }
553        }
554    }
555
556    data->family_hash = table;
557}
558
559static FcBool
560FcCompareFamilies (FcPattern       *pat,
561                   FcValueListPtr   v1orig,
562                   FcPattern       *fnt,
563                   FcValueListPtr   v2orig,
564                   double          *value,
565                   FcResult        *result,
566                   FcHashTable     *table)
567{
568    FcValueListPtr v2;
569    double strong_value;
570    double weak_value;
571    const void *key;
572    FamilyEntry *e;
573
574    assert (table != NULL);
575
576    strong_value = 1e99;
577    weak_value = 1e99;
578
579    for (v2 = v2orig; v2; v2 = FcValueListNext(v2))
580    {
581        key = FcValueString (&v2->value);
582        if (FcHashTableFind (table, key, (void **)&e))
583        {
584            if (e->strong_value < strong_value)
585                strong_value = e->strong_value;
586            if (e->weak_value < weak_value)
587                weak_value = e->weak_value;
588        }
589    }
590    if (FcDebug () & FC_DBG_MATCHV)
591    {
592	printf ("%s: %g ", FcObjectName (FC_FAMILY_OBJECT), strong_value);
593	FcValueListPrint (v1orig);
594	printf (", ");
595	FcValueListPrint (v2orig);
596	printf ("\n");
597    }
598
599    value[PRI_FAMILY_STRONG] = strong_value;
600    value[PRI_FAMILY_WEAK] = weak_value;
601
602    return FcTrue;
603}
604
605/*
606 * Return a value indicating the distance between the two lists of
607 * values
608 */
609
610static FcBool
611FcCompare (FcPattern	*pat,
612	   FcPattern	*fnt,
613	   double	*value,
614	   FcResult	*result,
615           FcCompareData *data)
616{
617    int		    i, i1, i2;
618
619    for (i = 0; i < PRI_END; i++)
620	value[i] = 0.0;
621
622    i1 = 0;
623    i2 = 0;
624    while (i1 < pat->num && i2 < fnt->num)
625    {
626	FcPatternElt *elt_i1 = &FcPatternElts(pat)[i1];
627	FcPatternElt *elt_i2 = &FcPatternElts(fnt)[i2];
628
629	i = FcObjectCompare(elt_i1->object, elt_i2->object);
630	if (i > 0)
631	    i2++;
632	else if (i < 0)
633	    i1++;
634	else if (elt_i1->object == FC_FAMILY_OBJECT && data->family_hash)
635        {
636            if (!FcCompareFamilies (pat, FcPatternEltValues(elt_i1),
637                                    fnt, FcPatternEltValues(elt_i2),
638                                    value, result,
639                                    data->family_hash))
640                return FcFalse;
641	    i1++;
642	    i2++;
643        }
644        else
645        {
646	    const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse);
647	    if (!FcCompareValueList (elt_i1->object, match,
648				     FcPatternEltValues(elt_i1),
649				     FcPatternEltValues(elt_i2),
650				     NULL, value, NULL, result))
651		return FcFalse;
652	    i1++;
653	    i2++;
654	}
655    }
656    return FcTrue;
657}
658
659FcPattern *
660FcFontRenderPrepare (FcConfig	    *config,
661		     FcPattern	    *pat,
662		     FcPattern	    *font)
663{
664    FcPattern	    *new;
665    int		    i;
666    FcPatternElt    *fe, *pe;
667    FcValue	    v;
668    FcResult	    result;
669    FcBool	    variable = FcFalse;
670    FcStrBuf        variations;
671
672    assert (pat != NULL);
673    assert (font != NULL);
674
675    FcPatternObjectGetBool (font, FC_VARIABLE_OBJECT, 0, &variable);
676    assert (variable != FcDontCare);
677    if (variable)
678	FcStrBufInit (&variations, NULL, 0);
679
680    new = FcPatternCreate ();
681    if (!new)
682	return NULL;
683    for (i = 0; i < font->num; i++)
684    {
685	fe = &FcPatternElts(font)[i];
686	if (fe->object == FC_FAMILYLANG_OBJECT ||
687	    fe->object == FC_STYLELANG_OBJECT ||
688	    fe->object == FC_FULLNAMELANG_OBJECT)
689	{
690	    /* ignore those objects. we need to deal with them
691	     * another way */
692	    continue;
693	}
694	if (fe->object == FC_FAMILY_OBJECT ||
695	    fe->object == FC_STYLE_OBJECT ||
696	    fe->object == FC_FULLNAME_OBJECT)
697	{
698	    FcPatternElt    *fel, *pel;
699
700	    FC_ASSERT_STATIC ((FC_FAMILY_OBJECT + 1) == FC_FAMILYLANG_OBJECT);
701	    FC_ASSERT_STATIC ((FC_STYLE_OBJECT + 1) == FC_STYLELANG_OBJECT);
702	    FC_ASSERT_STATIC ((FC_FULLNAME_OBJECT + 1) == FC_FULLNAMELANG_OBJECT);
703
704	    fel = FcPatternObjectFindElt (font, fe->object + 1);
705	    pel = FcPatternObjectFindElt (pat, fe->object + 1);
706
707	    if (fel && pel)
708	    {
709		/* The font has name languages, and pattern asks for specific language(s).
710		 * Match on language and and prefer that result.
711		 * Note:  Currently the code only give priority to first matching language.
712		 */
713		int n = 1, j;
714		FcValueListPtr l1, l2, ln = NULL, ll = NULL;
715		const FcMatcher *match = FcObjectToMatcher (pel->object, FcTrue);
716
717		if (!FcCompareValueList (pel->object, match,
718					 FcPatternEltValues (pel),
719					 FcPatternEltValues (fel), NULL, NULL, &n, &result))
720		{
721		    FcPatternDestroy (new);
722		    return NULL;
723		}
724
725		for (j = 0, l1 = FcPatternEltValues (fe), l2 = FcPatternEltValues (fel);
726		     l1 != NULL || l2 != NULL;
727		     j++, l1 = l1 ? FcValueListNext (l1) : NULL, l2 = l2 ? FcValueListNext (l2) : NULL)
728		{
729		    FcValueListPtr (* func) (FcValueListPtr, FcValue, FcValueBinding);
730		    FcValueBinding binding = FcValueBindingEnd;
731
732		    if (j == n)
733		    {
734			binding = FcValueBindingStrong;
735			func = FcValueListPrepend;
736		    }
737		    else
738			func = FcValueListAppend;
739		    if (l1)
740		    {
741			ln = func (ln,
742				   FcValueCanonicalize (&l1->value),
743				   l1->binding);
744		    }
745		    if (l2)
746		    {
747			if (binding == FcValueBindingEnd)
748			    binding = l2->binding;
749			ll = func (ll,
750				   FcValueCanonicalize (&l2->value),
751				   binding);
752		    }
753		}
754		FcPatternObjectListAdd (new, fe->object, ln, FcFalse);
755		FcPatternObjectListAdd (new, fel->object, ll, FcFalse);
756
757		continue;
758	    }
759	    else if (fel)
760	    {
761		/* Pattern doesn't ask for specific language.  Copy all for name and
762		 * lang. */
763		FcValueListPtr l1, l2;
764
765		l1 = FcValueListDuplicate (FcPatternEltValues (fe));
766		l2 = FcValueListDuplicate (FcPatternEltValues (fel));
767		FcPatternObjectListAdd (new, fe->object, l1, FcFalse);
768		FcPatternObjectListAdd (new, fel->object, l2, FcFalse);
769
770		continue;
771	    }
772	}
773
774	pe = FcPatternObjectFindElt (pat, fe->object);
775	if (pe)
776	{
777	    const FcMatcher *match = FcObjectToMatcher (pe->object, FcFalse);
778	    if (!FcCompareValueList (pe->object, match,
779				     FcPatternEltValues(pe),
780				     FcPatternEltValues(fe), &v, NULL, NULL, &result))
781	    {
782		FcPatternDestroy (new);
783		return NULL;
784	    }
785	    FcPatternObjectAdd (new, fe->object, v, FcFalse);
786
787	    /* Set font-variations settings for standard axes in variable fonts. */
788	    if (variable &&
789		FcPatternEltValues(fe)->value.type == FcTypeRange &&
790		(fe->object == FC_WEIGHT_OBJECT ||
791		 fe->object == FC_WIDTH_OBJECT ||
792		 fe->object == FC_SIZE_OBJECT))
793	    {
794		double num;
795		FcChar8 temp[128];
796		const char *tag = "    ";
797		assert (v.type == FcTypeDouble);
798		num = v.u.d;
799		if (variations.len)
800		    FcStrBufChar (&variations, ',');
801		switch (fe->object)
802		{
803		    case FC_WEIGHT_OBJECT:
804			tag = "wght";
805			num = FcWeightToOpenType (num);
806			break;
807
808		    case FC_WIDTH_OBJECT:
809			tag = "wdth";
810			break;
811
812		    case FC_SIZE_OBJECT:
813			tag = "opsz";
814			break;
815		}
816		sprintf ((char *) temp, "%4s=%g", tag, num);
817		FcStrBufString (&variations, temp);
818	    }
819	}
820	else
821	{
822	    FcPatternObjectListAdd (new, fe->object,
823				    FcValueListDuplicate (FcPatternEltValues (fe)),
824				    FcTrue);
825	}
826    }
827    for (i = 0; i < pat->num; i++)
828    {
829	pe = &FcPatternElts(pat)[i];
830	fe = FcPatternObjectFindElt (font, pe->object);
831	if (!fe &&
832	    pe->object != FC_FAMILYLANG_OBJECT &&
833	    pe->object != FC_STYLELANG_OBJECT &&
834	    pe->object != FC_FULLNAMELANG_OBJECT)
835	{
836	    FcPatternObjectListAdd (new, pe->object,
837				    FcValueListDuplicate (FcPatternEltValues(pe)),
838				    FcFalse);
839	}
840    }
841
842    if (variable && variations.len)
843    {
844	FcChar8 *vars = NULL;
845	if (FcPatternObjectGetString (new, FC_FONT_VARIATIONS_OBJECT, 0, &vars) == FcResultMatch)
846	{
847	    FcStrBufChar (&variations, ',');
848	    FcStrBufString (&variations, vars);
849	    FcPatternObjectDel (new, FC_FONT_VARIATIONS_OBJECT);
850	}
851
852	FcPatternObjectAddString (new, FC_FONT_VARIATIONS_OBJECT, FcStrBufDoneStatic (&variations));
853	FcStrBufDestroy (&variations);
854    }
855
856    FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
857    return new;
858}
859
860static FcPattern *
861FcFontSetMatchInternal (FcFontSet   **sets,
862			int	    nsets,
863			FcPattern   *p,
864			FcResult    *result)
865{
866    double    	    score[PRI_END], bestscore[PRI_END];
867    int		    f;
868    FcFontSet	    *s;
869    FcPattern	    *best, *pat = NULL;
870    int		    i;
871    int		    set;
872    FcCompareData   data;
873    const FcPatternElt *elt;
874
875    for (i = 0; i < PRI_END; i++)
876	bestscore[i] = 0;
877    best = 0;
878    if (FcDebug () & FC_DBG_MATCH)
879    {
880	printf ("Match ");
881	FcPatternPrint (p);
882    }
883
884    FcCompareDataInit (p, &data);
885
886    for (set = 0; set < nsets; set++)
887    {
888	s = sets[set];
889	if (!s)
890	    continue;
891	for (f = 0; f < s->nfont; f++)
892	{
893	    if (FcDebug () & FC_DBG_MATCHV)
894	    {
895		printf ("Font %d ", f);
896		FcPatternPrint (s->fonts[f]);
897	    }
898	    if (!FcCompare (p, s->fonts[f], score, result, &data))
899            {
900                FcCompareDataClear (&data);
901		return 0;
902            }
903	    if (FcDebug () & FC_DBG_MATCHV)
904	    {
905		printf ("Score");
906		for (i = 0; i < PRI_END; i++)
907		{
908		    printf (" %g", score[i]);
909		}
910		printf ("\n");
911	    }
912	    for (i = 0; i < PRI_END; i++)
913	    {
914		if (best && bestscore[i] < score[i])
915		    break;
916		if (!best || score[i] < bestscore[i])
917		{
918		    for (i = 0; i < PRI_END; i++)
919			bestscore[i] = score[i];
920		    best = s->fonts[f];
921		    break;
922		}
923	    }
924	}
925    }
926
927    FcCompareDataClear (&data);
928
929    /* Update the binding according to the score to indicate how exactly values matches on. */
930    if (best)
931    {
932	pat = FcPatternCreate ();
933	elt = FcPatternElts (best);
934	for (i = 0; i < FcPatternObjectCount (best); i++)
935	{
936	    const FcMatcher *match = FcObjectToMatcher (elt[i].object, FcFalse);
937	    FcValueListPtr l = FcPatternEltValues (&elt[i]);
938
939	    if (!match)
940		FcPatternObjectListAdd(pat, elt[i].object,
941				       FcValueListDuplicate(l), FcTrue);
942	    else
943	    {
944		FcValueBinding binding = FcValueBindingWeak;
945		FcValueListPtr new = NULL, ll, t = NULL;
946		FcValue v;
947
948		/* If the value was matched exactly, update the binding to Strong. */
949		if (bestscore[match->strong] < 1000)
950		    binding = FcValueBindingStrong;
951
952		for (ll = l; ll != NULL; ll = FcValueListNext (ll))
953		{
954		    if (!new)
955		    {
956			t = new = FcValueListCreate ();
957		    }
958		    else
959		    {
960			t->next = FcValueListCreate ();
961			t = FcValueListNext (t);
962		    }
963		    v = FcValueCanonicalize (&ll->value);
964		    t->value = FcValueSave (v);
965		    t->binding = binding;
966		    t->next = NULL;
967		}
968		FcPatternObjectListAdd (pat, elt[i].object, new, FcTrue);
969	    }
970	}
971    }
972    if (FcDebug () & FC_DBG_MATCH)
973    {
974	printf ("Best score");
975	for (i = 0; i < PRI_END; i++)
976	    printf (" %g", bestscore[i]);
977	printf ("\n");
978	FcPatternPrint (pat);
979    }
980    if (FcDebug () & FC_DBG_MATCH2)
981    {
982	char *env = getenv ("FC_DBG_MATCH_FILTER");
983	FcObjectSet *os = NULL;
984
985	if (env)
986	{
987	    char *ss, *s;
988	    char *p;
989	    FcBool f = FcTrue;
990
991	    ss = s = strdup (env);
992	    if (ss == NULL)
993	    {
994		    fprintf (stderr, "Fontconfig Error: %s\n",
995			strerror (errno));
996		    exit (1);
997	    }
998	    os = FcObjectSetCreate ();
999	    while (f)
1000	    {
1001		size_t len;
1002		char *x;
1003
1004		if (!(p = strchr (s, ',')))
1005		{
1006		    f = FcFalse;
1007		    len = strlen (s);
1008		}
1009		else
1010		{
1011		    len = (p - s);
1012		}
1013		x = malloc (sizeof (char) * (len + 1));
1014		if (x)
1015		{
1016		    strcpy (x, s);
1017		    if (FcObjectFromName (x) > 0)
1018			FcObjectSetAdd (os, x);
1019		    s = p + 1;
1020		    free (x);
1021		}
1022	    }
1023	    free (ss);
1024	}
1025	FcPatternPrint2 (p, pat, os);
1026	if (os)
1027	    FcObjectSetDestroy (os);
1028    }
1029    /* assuming that 'result' is initialized with FcResultNoMatch
1030     * outside this function */
1031    if (pat)
1032	*result = FcResultMatch;
1033
1034    return pat;
1035}
1036
1037FcPattern *
1038FcFontSetMatch (FcConfig    *config,
1039		FcFontSet   **sets,
1040		int	    nsets,
1041		FcPattern   *p,
1042		FcResult    *result)
1043{
1044    FcPattern	    *best, *ret = NULL;
1045
1046    assert (sets != NULL);
1047    assert (p != NULL);
1048    assert (result != NULL);
1049
1050    *result = FcResultNoMatch;
1051
1052    config = FcConfigReference (config);
1053    if (!config)
1054	    return NULL;
1055    best = FcFontSetMatchInternal (sets, nsets, p, result);
1056    if (best)
1057    {
1058	ret = FcFontRenderPrepare (config, p, best);
1059	FcPatternDestroy (best);
1060    }
1061
1062    FcConfigDestroy (config);
1063
1064    return ret;
1065}
1066
1067FcPattern *
1068FcFontMatch (FcConfig	*config,
1069	     FcPattern	*p,
1070	     FcResult	*result)
1071{
1072    FcFontSet	*sets[2];
1073    int		nsets;
1074    FcPattern   *best, *ret = NULL;
1075
1076    assert (p != NULL);
1077    assert (result != NULL);
1078
1079    *result = FcResultNoMatch;
1080
1081    config = FcConfigReference (config);
1082    if (!config)
1083	return NULL;
1084    nsets = 0;
1085    if (config->fonts[FcSetSystem])
1086	sets[nsets++] = config->fonts[FcSetSystem];
1087    if (config->fonts[FcSetApplication])
1088	sets[nsets++] = config->fonts[FcSetApplication];
1089
1090    best = FcFontSetMatchInternal (sets, nsets, p, result);
1091    if (best)
1092    {
1093	ret = FcFontRenderPrepare (config, p, best);
1094	FcPatternDestroy (best);
1095    }
1096
1097    FcConfigDestroy (config);
1098
1099    return ret;
1100}
1101
1102typedef struct _FcSortNode {
1103    FcPattern	*pattern;
1104    double	score[PRI_END];
1105} FcSortNode;
1106
1107static int
1108FcSortCompare (const void *aa, const void *ab)
1109{
1110    FcSortNode  *a = *(FcSortNode **) aa;
1111    FcSortNode  *b = *(FcSortNode **) ab;
1112    double	*as = &a->score[0];
1113    double	*bs = &b->score[0];
1114    double	ad = 0, bd = 0;
1115    int         i;
1116
1117    i = PRI_END;
1118    while (i-- && (ad = *as++) == (bd = *bs++))
1119	;
1120    return ad < bd ? -1 : ad > bd ? 1 : 0;
1121}
1122
1123static FcBool
1124FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **csp, FcBool trim)
1125{
1126    FcBool ret = FcFalse;
1127    FcCharSet *cs;
1128    int i;
1129
1130    cs = 0;
1131    if (trim || csp)
1132    {
1133	cs = FcCharSetCreate ();
1134	if (cs == NULL)
1135	    goto bail;
1136    }
1137
1138    for (i = 0; i < nnode; i++)
1139    {
1140	FcSortNode	*node = *n++;
1141	FcBool		adds_chars = FcFalse;
1142
1143	/*
1144	 * Only fetch node charset if we'd need it
1145	 */
1146	if (cs)
1147	{
1148	    FcCharSet	*ncs;
1149
1150	    if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) !=
1151		FcResultMatch)
1152	        continue;
1153
1154	    if (!FcCharSetMerge (cs, ncs, &adds_chars))
1155		goto bail;
1156	}
1157
1158	/*
1159	 * If this font isn't a subset of the previous fonts,
1160	 * add it to the list
1161	 */
1162	if (!i || !trim || adds_chars)
1163	{
1164	    FcPatternReference (node->pattern);
1165	    if (FcDebug () & FC_DBG_MATCHV)
1166	    {
1167		printf ("Add ");
1168		FcPatternPrint (node->pattern);
1169	    }
1170	    if (!FcFontSetAdd (fs, node->pattern))
1171	    {
1172		FcPatternDestroy (node->pattern);
1173		goto bail;
1174	    }
1175	}
1176    }
1177    if (csp)
1178    {
1179	*csp = cs;
1180	cs = 0;
1181    }
1182
1183    ret = FcTrue;
1184
1185bail:
1186    if (cs)
1187	FcCharSetDestroy (cs);
1188
1189    return ret;
1190}
1191
1192void
1193FcFontSetSortDestroy (FcFontSet *fs)
1194{
1195    FcFontSetDestroy (fs);
1196}
1197
1198FcFontSet *
1199FcFontSetSort (FcConfig	    *config FC_UNUSED,
1200	       FcFontSet    **sets,
1201	       int	    nsets,
1202	       FcPattern    *p,
1203	       FcBool	    trim,
1204	       FcCharSet    **csp,
1205	       FcResult	    *result)
1206{
1207    FcFontSet	    *ret;
1208    FcFontSet	    *s;
1209    FcSortNode	    *nodes;
1210    FcSortNode	    **nodeps, **nodep;
1211    int		    nnodes;
1212    FcSortNode	    *new;
1213    int		    set;
1214    int		    f;
1215    int		    i;
1216    int		    nPatternLang;
1217    FcBool    	    *patternLangSat;
1218    FcValue	    patternLang;
1219    FcCompareData   data;
1220
1221    assert (sets != NULL);
1222    assert (p != NULL);
1223    assert (result != NULL);
1224
1225    /* There are some implementation that relying on the result of
1226     * "result" to check if the return value of FcFontSetSort
1227     * is valid or not.
1228     * So we should initialize it to the conservative way since
1229     * this function doesn't return NULL anymore.
1230     */
1231    if (result)
1232	*result = FcResultNoMatch;
1233
1234    if (FcDebug () & FC_DBG_MATCH)
1235    {
1236	printf ("Sort ");
1237	FcPatternPrint (p);
1238    }
1239    nnodes = 0;
1240    for (set = 0; set < nsets; set++)
1241    {
1242	s = sets[set];
1243	if (!s)
1244	    continue;
1245	nnodes += s->nfont;
1246    }
1247    if (!nnodes)
1248	return FcFontSetCreate ();
1249
1250    for (nPatternLang = 0;
1251	 FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
1252	 nPatternLang++)
1253	;
1254
1255    /* freed below */
1256    nodes = malloc (nnodes * sizeof (FcSortNode) +
1257		    nnodes * sizeof (FcSortNode *) +
1258		    nPatternLang * sizeof (FcBool));
1259    if (!nodes)
1260	goto bail0;
1261    nodeps = (FcSortNode **) (nodes + nnodes);
1262    patternLangSat = (FcBool *) (nodeps + nnodes);
1263
1264    FcCompareDataInit (p, &data);
1265
1266    new = nodes;
1267    nodep = nodeps;
1268    for (set = 0; set < nsets; set++)
1269    {
1270	s = sets[set];
1271	if (!s)
1272	    continue;
1273	for (f = 0; f < s->nfont; f++)
1274	{
1275	    if (FcDebug () & FC_DBG_MATCHV)
1276	    {
1277		printf ("Font %d ", f);
1278		FcPatternPrint (s->fonts[f]);
1279	    }
1280	    new->pattern = s->fonts[f];
1281	    if (!FcCompare (p, new->pattern, new->score, result, &data))
1282		goto bail1;
1283	    if (FcDebug () & FC_DBG_MATCHV)
1284	    {
1285		printf ("Score");
1286		for (i = 0; i < PRI_END; i++)
1287		{
1288		    printf (" %g", new->score[i]);
1289		}
1290		printf ("\n");
1291	    }
1292	    *nodep = new;
1293	    new++;
1294	    nodep++;
1295	}
1296    }
1297
1298    FcCompareDataClear (&data);
1299
1300    nnodes = new - nodes;
1301
1302    qsort (nodeps, nnodes, sizeof (FcSortNode *),
1303	   FcSortCompare);
1304
1305    for (i = 0; i < nPatternLang; i++)
1306	patternLangSat[i] = FcFalse;
1307
1308    for (f = 0; f < nnodes; f++)
1309    {
1310	FcBool	satisfies = FcFalse;
1311	/*
1312	 * If this node matches any language, go check
1313	 * which ones and satisfy those entries
1314	 */
1315	if (nodeps[f]->score[PRI_LANG] < 2000)
1316	{
1317	    for (i = 0; i < nPatternLang; i++)
1318	    {
1319		FcValue	    nodeLang;
1320
1321		if (!patternLangSat[i] &&
1322		    FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
1323		    FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
1324		{
1325		    FcValue matchValue;
1326		    double  compare = FcCompareLang (&patternLang, &nodeLang, &matchValue);
1327		    if (compare >= 0 && compare < 2)
1328		    {
1329			if (FcDebug () & FC_DBG_MATCHV)
1330			{
1331			    FcChar8 *family;
1332			    FcChar8 *style;
1333
1334			    if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
1335				FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
1336				printf ("Font %s:%s matches language %d\n", family, style, i);
1337			}
1338			patternLangSat[i] = FcTrue;
1339			satisfies = FcTrue;
1340			break;
1341		    }
1342		}
1343	    }
1344	}
1345	if (!satisfies)
1346	{
1347	    nodeps[f]->score[PRI_LANG] = 10000.0;
1348	}
1349    }
1350
1351    /*
1352     * Re-sort once the language issues have been settled
1353     */
1354    qsort (nodeps, nnodes, sizeof (FcSortNode *),
1355	   FcSortCompare);
1356
1357    ret = FcFontSetCreate ();
1358    if (!ret)
1359	goto bail1;
1360
1361    if (!FcSortWalk (nodeps, nnodes, ret, csp, trim))
1362	goto bail2;
1363
1364    free (nodes);
1365
1366    if (FcDebug() & FC_DBG_MATCH)
1367    {
1368	printf ("First font ");
1369	FcPatternPrint (ret->fonts[0]);
1370    }
1371    if (ret->nfont > 0)
1372	*result = FcResultMatch;
1373
1374    return ret;
1375
1376bail2:
1377    FcFontSetDestroy (ret);
1378bail1:
1379    free (nodes);
1380bail0:
1381    return 0;
1382}
1383
1384FcFontSet *
1385FcFontSort (FcConfig	*config,
1386	    FcPattern	*p,
1387	    FcBool	trim,
1388	    FcCharSet	**csp,
1389	    FcResult	*result)
1390{
1391    FcFontSet	*sets[2], *ret;
1392    int		nsets;
1393
1394    assert (p != NULL);
1395    assert (result != NULL);
1396
1397    *result = FcResultNoMatch;
1398
1399    config = FcConfigReference (config);
1400    if (!config)
1401	return NULL;
1402    nsets = 0;
1403    if (config->fonts[FcSetSystem])
1404	sets[nsets++] = config->fonts[FcSetSystem];
1405    if (config->fonts[FcSetApplication])
1406	sets[nsets++] = config->fonts[FcSetApplication];
1407    ret = FcFontSetSort (config, sets, nsets, p, trim, csp, result);
1408    FcConfigDestroy (config);
1409
1410    return ret;
1411}
1412#define __fcmatch__
1413#include "fcaliastail.h"
1414#undef __fcmatch__
1415