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