(root)/
fontconfig-2.14.2/
src/
fcfreetype.c
       1  /*
       2   * fontconfig/src/fcfreetype.c
       3   *
       4   * Copyright © 2001 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 "fcftint.h"
      27  #include <stdlib.h>
      28  #include <stdio.h>
      29  #include <string.h>
      30  #include <ft2build.h>
      31  #include FT_FREETYPE_H
      32  #include FT_ADVANCES_H
      33  #include FT_TRUETYPE_TABLES_H
      34  #include FT_SFNT_NAMES_H
      35  #include FT_TRUETYPE_IDS_H
      36  #include FT_TYPE1_TABLES_H
      37  #if HAVE_FT_GET_X11_FONT_FORMAT
      38  #include FT_XFREE86_H
      39  #endif
      40  #if HAVE_FT_GET_BDF_PROPERTY
      41  #include FT_BDF_H
      42  #include FT_MODULE_H
      43  #endif
      44  #include FT_MULTIPLE_MASTERS_H
      45  
      46  #include "fcfoundry.h"
      47  #include "ftglue.h"
      48  
      49  /*
      50   * Keep Han languages separated by eliminating languages
      51   * that the codePageRange bits says aren't supported
      52   */
      53  
      54  static const struct {
      55      char    	    bit;
      56      const FcChar8   lang[6];
      57  } FcCodePageRange[] = {
      58      { 17,	"ja" },
      59      { 18,	"zh-cn" },
      60      { 19,	"ko" },
      61      { 20,	"zh-tw" },
      62  };
      63  
      64  #define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
      65  
      66  FcBool
      67  FcFreeTypeIsExclusiveLang (const FcChar8  *lang)
      68  {
      69      int	    i;
      70  
      71      for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
      72      {
      73  	if (FcLangCompare (lang, FcCodePageRange[i].lang) == FcLangEqual)
      74  	    return FcTrue;
      75      }
      76      return FcFalse;
      77  }
      78  
      79  typedef struct {
      80      const FT_UShort	platform_id;
      81      const FT_UShort	encoding_id;
      82      const char	fromcode[12];
      83  } FcFtEncoding;
      84  
      85  #define TT_ENCODING_DONT_CARE	0xffff
      86  #define FC_ENCODING_MAC_ROMAN	"MACINTOSH"
      87  
      88  static const FcFtEncoding   fcFtEncoding[] = {
      89   {  TT_PLATFORM_APPLE_UNICODE,	TT_ENCODING_DONT_CARE,	"UTF-16BE" },
      90   {  TT_PLATFORM_MACINTOSH,	TT_MAC_ID_ROMAN,	"MACINTOSH" },
      91   {  TT_PLATFORM_MACINTOSH,	TT_MAC_ID_JAPANESE,	"SJIS" },
      92   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_SYMBOL_CS,	"UTF-16BE" },
      93   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_UNICODE_CS,	"UTF-16BE" },
      94   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_SJIS,		"SJIS-WIN" },
      95   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_GB2312,	"GB2312" },
      96   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_BIG_5,		"BIG-5" },
      97   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_WANSUNG,	"Wansung" },
      98   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_JOHAB,		"Johab" },
      99   {  TT_PLATFORM_MICROSOFT,	TT_MS_ID_UCS_4,		"UTF-16BE" },
     100   {  TT_PLATFORM_ISO,		TT_ISO_ID_7BIT_ASCII,	"ASCII" },
     101   {  TT_PLATFORM_ISO,		TT_ISO_ID_10646,	"UTF-16BE" },
     102   {  TT_PLATFORM_ISO,		TT_ISO_ID_8859_1,	"ISO-8859-1" },
     103  };
     104  
     105  #define NUM_FC_FT_ENCODING  (int) (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0]))
     106  
     107  typedef struct {
     108      const FT_UShort	platform_id;
     109      const FT_UShort	language_id;
     110      const char	lang[8];
     111  } FcFtLanguage;
     112  
     113  #define TT_LANGUAGE_DONT_CARE	0xffff
     114  
     115  static const FcFtLanguage   fcFtLanguage[] = {
     116   {  TT_PLATFORM_APPLE_UNICODE,	TT_LANGUAGE_DONT_CARE,		    "" },
     117   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ENGLISH,		    "en" },
     118   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_FRENCH,		    "fr" },
     119   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GERMAN,		    "de" },
     120   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ITALIAN,		    "it" },
     121   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_DUTCH,		    "nl" },
     122   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SWEDISH,		    "sv" },
     123   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SPANISH,		    "es" },
     124   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_DANISH,		    "da" },
     125   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_PORTUGUESE,	    "pt" },
     126   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_NORWEGIAN,	    "no" },
     127   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_HEBREW,		    "he" },
     128   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_JAPANESE,		    "ja" },
     129   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ARABIC,		    "ar" },
     130   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_FINNISH,		    "fi" },
     131   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GREEK,		    "el" },
     132   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ICELANDIC,	    "is" },
     133   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MALTESE,		    "mt" },
     134   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TURKISH,		    "tr" },
     135   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_CROATIAN,		    "hr" },
     136   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_CHINESE_TRADITIONAL,  "zh-tw" },
     137   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_URDU,		    "ur" },
     138   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_HINDI,		    "hi" },
     139   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_THAI,		    "th" },
     140   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_KOREAN,		    "ko" },
     141   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_LITHUANIAN,	    "lt" },
     142   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_POLISH,		    "pl" },
     143   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_HUNGARIAN,	    "hu" },
     144   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ESTONIAN,		    "et" },
     145   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_LETTISH,		    "lv" },
     146  /* {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SAAMISK, ??? */
     147   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_FAEROESE,		    "fo" },
     148   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_FARSI,		    "fa" },
     149   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_RUSSIAN,		    "ru" },
     150   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_CHINESE_SIMPLIFIED,   "zh-cn" },
     151   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_FLEMISH,		    "nl" },
     152   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_IRISH,		    "ga" },
     153   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ALBANIAN,		    "sq" },
     154   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ROMANIAN,		    "ro" },
     155   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_CZECH,		    "cs" },
     156   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SLOVAK,		    "sk" },
     157   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SLOVENIAN,	    "sl" },
     158   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_YIDDISH,		    "yi" },
     159   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SERBIAN,		    "sr" },
     160   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MACEDONIAN,	    "mk" },
     161   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_BULGARIAN,	    "bg" },
     162   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_UKRAINIAN,	    "uk" },
     163   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_BYELORUSSIAN,	    "be" },
     164   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_UZBEK,		    "uz" },
     165   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_KAZAKH,		    "kk" },
     166   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_AZERBAIJANI,	    "az" },
     167   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
     168   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT,    "ar" },
     169   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ARMENIAN,		    "hy" },
     170   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GEORGIAN,		    "ka" },
     171   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MOLDAVIAN,	    "mo" },
     172   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_KIRGHIZ,		    "ky" },
     173   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TAJIKI,		    "tg" },
     174   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TURKMEN,		    "tk" },
     175   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MONGOLIAN,	    "mn" },
     176   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mn" },
     177   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mn" },
     178   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_PASHTO,		    "ps" },
     179   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_KURDISH,		    "ku" },
     180   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_KASHMIRI,		    "ks" },
     181   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SINDHI,		    "sd" },
     182   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TIBETAN,		    "bo" },
     183   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_NEPALI,		    "ne" },
     184   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SANSKRIT,		    "sa" },
     185   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MARATHI,		    "mr" },
     186   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_BENGALI,		    "bn" },
     187   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ASSAMESE,		    "as" },
     188   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GUJARATI,		    "gu" },
     189   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_PUNJABI,		    "pa" },
     190   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ORIYA,		    "or" },
     191   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MALAYALAM,	    "ml" },
     192   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_KANNADA,		    "kn" },
     193   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TAMIL,		    "ta" },
     194   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TELUGU,		    "te" },
     195   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SINHALESE,	    "si" },
     196   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_BURMESE,		    "my" },
     197   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_KHMER,		    "km" },
     198   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_LAO,		    "lo" },
     199   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_VIETNAMESE,	    "vi" },
     200   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_INDONESIAN,	    "id" },
     201   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TAGALOG,		    "tl" },
     202   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MALAY_ROMAN_SCRIPT,   "ms" },
     203   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MALAY_ARABIC_SCRIPT,  "ms" },
     204   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_AMHARIC,		    "am" },
     205   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TIGRINYA,		    "ti" },
     206   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GALLA,		    "om" },
     207   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SOMALI,		    "so" },
     208   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SWAHILI,		    "sw" },
     209   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_RUANDA,		    "rw" },
     210   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_RUNDI,		    "rn" },
     211   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_CHEWA,		    "ny" },
     212   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MALAGASY,		    "mg" },
     213   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_ESPERANTO,	    "eo" },
     214   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_WELSH,		    "cy" },
     215   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_BASQUE,		    "eu" },
     216   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_CATALAN,		    "ca" },
     217   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_LATIN,		    "la" },
     218   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_QUECHUA,		    "qu" },
     219   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GUARANI,		    "gn" },
     220   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_AYMARA,		    "ay" },
     221   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TATAR,		    "tt" },
     222   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_UIGHUR,		    "ug" },
     223   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_DZONGKHA,		    "dz" },
     224   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_JAVANESE,		    "jw" },
     225   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SUNDANESE,	    "su" },
     226  
     227  #if 0  /* these seem to be errors that have been dropped */
     228  
     229   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SCOTTISH_GAELIC },
     230   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_IRISH_GAELIC },
     231  
     232  #endif
     233  
     234    /* The following codes are new as of 2000-03-10 */
     235   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GALICIAN,		    "gl" },
     236   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_AFRIKAANS,	    "af" },
     237   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_BRETON,		    "br" },
     238   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_INUKTITUT,	    "iu" },
     239   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_SCOTTISH_GAELIC,	    "gd" },
     240   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_MANX_GAELIC,	    "gv" },
     241   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_IRISH_GAELIC,	    "ga" },
     242   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_TONGAN,		    "to" },
     243   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GREEK_POLYTONIC,	    "el" },
     244   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_GREELANDIC,	    "ik" },
     245   {  TT_PLATFORM_MACINTOSH,	TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
     246  
     247   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_SAUDI_ARABIA,	"ar" },
     248   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_IRAQ,		"ar" },
     249   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_EGYPT,		"ar" },
     250   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_LIBYA,		"ar" },
     251   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_ALGERIA,		"ar" },
     252   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_MOROCCO,		"ar" },
     253   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_TUNISIA,		"ar" },
     254   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_OMAN,		"ar" },
     255   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_YEMEN,		"ar" },
     256   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_SYRIA,		"ar" },
     257   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_JORDAN,		"ar" },
     258   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_LEBANON,		"ar" },
     259   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_KUWAIT,		"ar" },
     260   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_UAE,		"ar" },
     261   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_BAHRAIN,		"ar" },
     262   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_QATAR,		"ar" },
     263   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_BULGARIAN_BULGARIA,	"bg" },
     264   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CATALAN_SPAIN,		"ca" },
     265   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CHINESE_TAIWAN,		"zh-tw" },
     266   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CHINESE_PRC,		"zh-cn" },
     267   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CHINESE_HONG_KONG,		"zh-hk" },
     268   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CHINESE_SINGAPORE,		"zh-sg" },
     269  
     270   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CHINESE_MACAU,		"zh-mo" },
     271  
     272   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CZECH_CZECH_REPUBLIC,	"cs" },
     273   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_DANISH_DENMARK,		"da" },
     274   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GERMAN_GERMANY,		"de" },
     275   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GERMAN_SWITZERLAND,	"de" },
     276   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GERMAN_AUSTRIA,		"de" },
     277   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GERMAN_LUXEMBOURG,		"de" },
     278   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GERMAN_LIECHTENSTEI,	"de" },
     279   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GREEK_GREECE,		"el" },
     280   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_UNITED_STATES,	"en" },
     281   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_UNITED_KINGDOM,	"en" },
     282   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_AUSTRALIA,		"en" },
     283   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_CANADA,		"en" },
     284   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_NEW_ZEALAND,	"en" },
     285   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_IRELAND,		"en" },
     286   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_SOUTH_AFRICA,	"en" },
     287   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_JAMAICA,		"en" },
     288   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_CARIBBEAN,		"en" },
     289   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_BELIZE,		"en" },
     290   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_TRINIDAD,		"en" },
     291   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_ZIMBABWE,		"en" },
     292   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_PHILIPPINES,	"en" },
     293   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
     294   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_MEXICO,		"es" },
     295   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
     296   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_GUATEMALA,		"es" },
     297   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_COSTA_RICA,	"es" },
     298   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_PANAMA,		"es" },
     299   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
     300   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_VENEZUELA,		"es" },
     301   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_COLOMBIA,		"es" },
     302   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_PERU,		"es" },
     303   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_ARGENTINA,		"es" },
     304   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_ECUADOR,		"es" },
     305   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_CHILE,		"es" },
     306   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_URUGUAY,		"es" },
     307   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_PARAGUAY,		"es" },
     308   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_BOLIVIA,		"es" },
     309   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_EL_SALVADOR,	"es" },
     310   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_HONDURAS,		"es" },
     311   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_NICARAGUA,		"es" },
     312   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_PUERTO_RICO,	"es" },
     313   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FINNISH_FINLAND,		"fi" },
     314   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_FRANCE,		"fr" },
     315   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_BELGIUM,		"fr" },
     316   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_CANADA,		"fr" },
     317   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_SWITZERLAND,	"fr" },
     318   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_LUXEMBOURG,		"fr" },
     319   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_MONACO,		"fr" },
     320   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_HEBREW_ISRAEL,		"he" },
     321   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_HUNGARIAN_HUNGARY,		"hu" },
     322   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ICELANDIC_ICELAND,		"is" },
     323   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ITALIAN_ITALY,		"it" },
     324   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ITALIAN_SWITZERLAND,	"it" },
     325   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_JAPANESE_JAPAN,		"ja" },
     326   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
     327   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KOREAN_JOHAB_KOREA,	"ko" },
     328   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_DUTCH_NETHERLANDS,		"nl" },
     329   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_DUTCH_BELGIUM,		"nl" },
     330   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL,	"no" },
     331   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK,	"nn" },
     332   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_POLISH_POLAND,		"pl" },
     333   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_PORTUGUESE_BRAZIL,		"pt" },
     334   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_PORTUGUESE_PORTUGAL,	"pt" },
     335   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
     336   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ROMANIAN_ROMANIA,		"ro" },
     337   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MOLDAVIAN_MOLDAVIA,	"mo" },
     338   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_RUSSIAN_RUSSIA,		"ru" },
     339   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_RUSSIAN_MOLDAVIA,		"ru" },
     340   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CROATIAN_CROATIA,		"hr" },
     341   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SERBIAN_SERBIA_LATIN,	"sr" },
     342   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC,	"sr" },
     343   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SLOVAK_SLOVAKIA,		"sk" },
     344   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ALBANIAN_ALBANIA,		"sq" },
     345   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SWEDISH_SWEDEN,		"sv" },
     346   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SWEDISH_FINLAND,		"sv" },
     347   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_THAI_THAILAND,		"th" },
     348   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TURKISH_TURKEY,		"tr" },
     349   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_URDU_PAKISTAN,		"ur" },
     350   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_INDONESIAN_INDONESIA,	"id" },
     351   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_UKRAINIAN_UKRAINE,		"uk" },
     352   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_BELARUSIAN_BELARUS,	"be" },
     353   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SLOVENE_SLOVENIA,		"sl" },
     354   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ESTONIAN_ESTONIA,		"et" },
     355   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_LATVIAN_LATVIA,		"lv" },
     356   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_LITHUANIAN_LITHUANIA,	"lt" },
     357   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
     358   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MAORI_NEW_ZEALAND,		"mi" },
     359   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FARSI_IRAN,		"fa" },
     360   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_VIETNAMESE_VIET_NAM,	"vi" },
     361   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARMENIAN_ARMENIA,		"hy" },
     362   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN,	"az" },
     363   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC,	"az" },
     364   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_BASQUE_SPAIN,		"eu" },
     365   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SORBIAN_GERMANY,		"wen" },
     366   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MACEDONIAN_MACEDONIA,	"mk" },
     367   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SUTU_SOUTH_AFRICA,		"st" },
     368   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TSONGA_SOUTH_AFRICA,	"ts" },
     369   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TSWANA_SOUTH_AFRICA,	"tn" },
     370   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_VENDA_SOUTH_AFRICA,	"ven" },
     371   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_XHOSA_SOUTH_AFRICA,	"xh" },
     372   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ZULU_SOUTH_AFRICA,		"zu" },
     373   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA,	"af" },
     374   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GEORGIAN_GEORGIA,		"ka" },
     375   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS,	"fo" },
     376   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_HINDI_INDIA,		"hi" },
     377   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MALTESE_MALTA,		"mt" },
     378   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SAAMI_LAPONIA,		"se" },
     379  
     380   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
     381   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_IRISH_GAELIC_IRELAND,	"ga" },
     382  
     383   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MALAY_MALAYSIA,		"ms" },
     384   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM,	"ms" },
     385   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KAZAK_KAZAKSTAN,		"kk" },
     386   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SWAHILI_KENYA,		"sw" },
     387   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN,	"uz" },
     388   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC,	"uz" },
     389   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TATAR_TATARSTAN,		"tt" },
     390   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_BENGALI_INDIA,		"bn" },
     391   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_PUNJABI_INDIA,		"pa" },
     392   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GUJARATI_INDIA,		"gu" },
     393   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ORIYA_INDIA,		"or" },
     394   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TAMIL_INDIA,		"ta" },
     395   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TELUGU_INDIA,		"te" },
     396   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KANNADA_INDIA,		"kn" },
     397   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MALAYALAM_INDIA,		"ml" },
     398   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ASSAMESE_INDIA,		"as" },
     399   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MARATHI_INDIA,		"mr" },
     400   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SANSKRIT_INDIA,		"sa" },
     401   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KONKANI_INDIA,		"kok" },
     402  
     403    /* new as of 2001-01-01 */
     404   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ARABIC_GENERAL,		"ar" },
     405   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CHINESE_GENERAL,		"zh" },
     406   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_GENERAL,		"en" },
     407   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_WEST_INDIES,	"fr" },
     408   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_REUNION,		"fr" },
     409   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_CONGO,		"fr" },
     410  
     411   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_SENEGAL,		"fr" },
     412   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_CAMEROON,		"fr" },
     413   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_COTE_D_IVOIRE,	"fr" },
     414   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_MALI,		"fr" },
     415   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
     416   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_URDU_INDIA,		"ur" },
     417   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TAJIK_TAJIKISTAN,		"tg" },
     418   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_YIDDISH_GERMANY,		"yi" },
     419   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN,	"ky" },
     420  
     421   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TURKMEN_TURKMENISTAN,	"tk" },
     422   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MONGOLIAN_MONGOLIA,	"mn" },
     423  
     424    /* the following seems to be inconsistent;
     425       here is the current "official" way: */
     426   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TIBETAN_BHUTAN,		"bo" },
     427    /* and here is what is used by Passport SDK */
     428   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TIBETAN_CHINA,		"bo" },
     429   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_DZONGHKA_BHUTAN,		"dz" },
     430    /* end of inconsistency */
     431  
     432   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_WELSH_WALES,		"cy" },
     433   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KHMER_CAMBODIA,		"km" },
     434   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_LAO_LAOS,			"lo" },
     435   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_BURMESE_MYANMAR,		"my" },
     436   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GALICIAN_SPAIN,		"gl" },
     437   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MANIPURI_INDIA,		"mni" },
     438   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SINDHI_INDIA,		"sd" },
     439    /* the following one is only encountered in Microsoft RTF specification */
     440   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KASHMIRI_PAKISTAN,		"ks" },
     441    /* the following one is not in the Passport list, looks like an omission */
     442   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KASHMIRI_INDIA,		"ks" },
     443   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_NEPALI_NEPAL,		"ne" },
     444   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_NEPALI_INDIA,		"ne" },
     445   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRISIAN_NETHERLANDS,	"fy" },
     446  
     447    /* new as of 2001-03-01 (from Office Xp) */
     448   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_HONG_KONG,		"en" },
     449   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_INDIA,		"en" },
     450   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_MALAYSIA,		"en" },
     451   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_ENGLISH_SINGAPORE,		"en" },
     452   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SYRIAC_SYRIA,		"syr" },
     453   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SINHALESE_SRI_LANKA,	"si" },
     454   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_CHEROKEE_UNITED_STATES,	"chr" },
     455   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_INUKTITUT_CANADA,		"iu" },
     456   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_AMHARIC_ETHIOPIA,		"am" },
     457  #if 0
     458   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TAMAZIGHT_MOROCCO },
     459   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
     460  #endif
     461   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_PASHTO_AFGHANISTAN,	"ps" },
     462   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FILIPINO_PHILIPPINES,	"phi" },
     463   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_DHIVEHI_MALDIVES,		"div" },
     464  
     465   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_OROMO_ETHIOPIA,		"om" },
     466   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TIGRIGNA_ETHIOPIA,		"ti" },
     467   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_TIGRIGNA_ERYTHREA,		"ti" },
     468  
     469    /* New additions from Windows Xp/Passport SDK 2001-11-10. */
     470  
     471    /* don't ask what this one means... It is commented out currently. */
     472  #if 0
     473   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GREEK_GREECE2 },
     474  #endif
     475  
     476   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_UNITED_STATES,	"es" },
     477    /* The following two IDs blatantly violate MS specs by using a */
     478    /* sublanguage >,.                                         */
     479   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SPANISH_LATIN_AMERICA,	"es" },
     480   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_NORTH_AFRICA,	"fr" },
     481  
     482   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_MOROCCO,		"fr" },
     483   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FRENCH_HAITI,		"fr" },
     484   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_BENGALI_BANGLADESH,	"bn" },
     485   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN,	"ar" },
     486   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
     487  #if 0
     488   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_EDO_NIGERIA },
     489   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_FULFULDE_NIGERIA },
     490   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_IBIBIO_NIGERIA },
     491  #endif
     492   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_HAUSA_NIGERIA,		"ha" },
     493   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_YORUBA_NIGERIA,		"yo" },
     494    /* language codes from, to, are (still) unknown. */
     495   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_IGBO_NIGERIA,		"ibo" },
     496   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_KANURI_NIGERIA,		"kau" },
     497   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_GUARANI_PARAGUAY,		"gn" },
     498   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_HAWAIIAN_UNITED_STATES,	"haw" },
     499   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_LATIN,			"la" },
     500   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_SOMALI_SOMALIA,		"so" },
     501  #if 0
     502    /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
     503    /*       not written (but OTOH the peculiar writing system is worth     */
     504    /*       studying).                                                     */
     505   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_YI_CHINA },
     506  #endif
     507   {  TT_PLATFORM_MICROSOFT,	TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
     508  };
     509  
     510  #define NUM_FC_FT_LANGUAGE  (int) (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0]))
     511  
     512  typedef struct {
     513      FT_UShort	language_id;
     514      char	fromcode[12];
     515  } FcMacRomanFake;
     516  
     517  static const FcMacRomanFake fcMacRomanFake[] = {
     518   {  TT_MS_LANGID_JAPANESE_JAPAN,	"SJIS-WIN" },
     519   {  TT_MS_LANGID_ENGLISH_UNITED_STATES,	"ASCII" },
     520  };
     521  
     522  static FcChar8 *
     523  FcFontCapabilities(FT_Face face);
     524  
     525  static FcBool
     526  FcFontHasHint (FT_Face face);
     527  
     528  static int
     529  FcFreeTypeSpacing (FT_Face face);
     530  
     531  #define NUM_FC_MAC_ROMAN_FAKE	(int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
     532  
     533  
     534  /* From http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT */
     535  static const FcChar16 fcMacRomanNonASCIIToUnicode[128] = {
     536    /*0x80*/ 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
     537    /*0x81*/ 0x00C5, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
     538    /*0x82*/ 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */
     539    /*0x83*/ 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */
     540    /*0x84*/ 0x00D1, /* LATIN CAPITAL LETTER N WITH TILDE */
     541    /*0x85*/ 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
     542    /*0x86*/ 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
     543    /*0x87*/ 0x00E1, /* LATIN SMALL LETTER A WITH ACUTE */
     544    /*0x88*/ 0x00E0, /* LATIN SMALL LETTER A WITH GRAVE */
     545    /*0x89*/ 0x00E2, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
     546    /*0x8A*/ 0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */
     547    /*0x8B*/ 0x00E3, /* LATIN SMALL LETTER A WITH TILDE */
     548    /*0x8C*/ 0x00E5, /* LATIN SMALL LETTER A WITH RING ABOVE */
     549    /*0x8D*/ 0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */
     550    /*0x8E*/ 0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */
     551    /*0x8F*/ 0x00E8, /* LATIN SMALL LETTER E WITH GRAVE */
     552    /*0x90*/ 0x00EA, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
     553    /*0x91*/ 0x00EB, /* LATIN SMALL LETTER E WITH DIAERESIS */
     554    /*0x92*/ 0x00ED, /* LATIN SMALL LETTER I WITH ACUTE */
     555    /*0x93*/ 0x00EC, /* LATIN SMALL LETTER I WITH GRAVE */
     556    /*0x94*/ 0x00EE, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
     557    /*0x95*/ 0x00EF, /* LATIN SMALL LETTER I WITH DIAERESIS */
     558    /*0x96*/ 0x00F1, /* LATIN SMALL LETTER N WITH TILDE */
     559    /*0x97*/ 0x00F3, /* LATIN SMALL LETTER O WITH ACUTE */
     560    /*0x98*/ 0x00F2, /* LATIN SMALL LETTER O WITH GRAVE */
     561    /*0x99*/ 0x00F4, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
     562    /*0x9A*/ 0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */
     563    /*0x9B*/ 0x00F5, /* LATIN SMALL LETTER O WITH TILDE */
     564    /*0x9C*/ 0x00FA, /* LATIN SMALL LETTER U WITH ACUTE */
     565    /*0x9D*/ 0x00F9, /* LATIN SMALL LETTER U WITH GRAVE */
     566    /*0x9E*/ 0x00FB, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
     567    /*0x9F*/ 0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */
     568    /*0xA0*/ 0x2020, /* DAGGER */
     569    /*0xA1*/ 0x00B0, /* DEGREE SIGN */
     570    /*0xA2*/ 0x00A2, /* CENT SIGN */
     571    /*0xA3*/ 0x00A3, /* POUND SIGN */
     572    /*0xA4*/ 0x00A7, /* SECTION SIGN */
     573    /*0xA5*/ 0x2022, /* BULLET */
     574    /*0xA6*/ 0x00B6, /* PILCROW SIGN */
     575    /*0xA7*/ 0x00DF, /* LATIN SMALL LETTER SHARP S */
     576    /*0xA8*/ 0x00AE, /* REGISTERED SIGN */
     577    /*0xA9*/ 0x00A9, /* COPYRIGHT SIGN */
     578    /*0xAA*/ 0x2122, /* TRADE MARK SIGN */
     579    /*0xAB*/ 0x00B4, /* ACUTE ACCENT */
     580    /*0xAC*/ 0x00A8, /* DIAERESIS */
     581    /*0xAD*/ 0x2260, /* NOT EQUAL TO */
     582    /*0xAE*/ 0x00C6, /* LATIN CAPITAL LETTER AE */
     583    /*0xAF*/ 0x00D8, /* LATIN CAPITAL LETTER O WITH STROKE */
     584    /*0xB0*/ 0x221E, /* INFINITY */
     585    /*0xB1*/ 0x00B1, /* PLUS-MINUS SIGN */
     586    /*0xB2*/ 0x2264, /* LESS-THAN OR EQUAL TO */
     587    /*0xB3*/ 0x2265, /* GREATER-THAN OR EQUAL TO */
     588    /*0xB4*/ 0x00A5, /* YEN SIGN */
     589    /*0xB5*/ 0x00B5, /* MICRO SIGN */
     590    /*0xB6*/ 0x2202, /* PARTIAL DIFFERENTIAL */
     591    /*0xB7*/ 0x2211, /* N-ARY SUMMATION */
     592    /*0xB8*/ 0x220F, /* N-ARY PRODUCT */
     593    /*0xB9*/ 0x03C0, /* GREEK SMALL LETTER PI */
     594    /*0xBA*/ 0x222B, /* INTEGRAL */
     595    /*0xBB*/ 0x00AA, /* FEMININE ORDINAL INDICATOR */
     596    /*0xBC*/ 0x00BA, /* MASCULINE ORDINAL INDICATOR */
     597    /*0xBD*/ 0x03A9, /* GREEK CAPITAL LETTER OMEGA */
     598    /*0xBE*/ 0x00E6, /* LATIN SMALL LETTER AE */
     599    /*0xBF*/ 0x00F8, /* LATIN SMALL LETTER O WITH STROKE */
     600    /*0xC0*/ 0x00BF, /* INVERTED QUESTION MARK */
     601    /*0xC1*/ 0x00A1, /* INVERTED EXCLAMATION MARK */
     602    /*0xC2*/ 0x00AC, /* NOT SIGN */
     603    /*0xC3*/ 0x221A, /* SQUARE ROOT */
     604    /*0xC4*/ 0x0192, /* LATIN SMALL LETTER F WITH HOOK */
     605    /*0xC5*/ 0x2248, /* ALMOST EQUAL TO */
     606    /*0xC6*/ 0x2206, /* INCREMENT */
     607    /*0xC7*/ 0x00AB, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
     608    /*0xC8*/ 0x00BB, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
     609    /*0xC9*/ 0x2026, /* HORIZONTAL ELLIPSIS */
     610    /*0xCA*/ 0x00A0, /* NO-BREAK SPACE */
     611    /*0xCB*/ 0x00C0, /* LATIN CAPITAL LETTER A WITH GRAVE */
     612    /*0xCC*/ 0x00C3, /* LATIN CAPITAL LETTER A WITH TILDE */
     613    /*0xCD*/ 0x00D5, /* LATIN CAPITAL LETTER O WITH TILDE */
     614    /*0xCE*/ 0x0152, /* LATIN CAPITAL LIGATURE OE */
     615    /*0xCF*/ 0x0153, /* LATIN SMALL LIGATURE OE */
     616    /*0xD0*/ 0x2013, /* EN DASH */
     617    /*0xD1*/ 0x2014, /* EM DASH */
     618    /*0xD2*/ 0x201C, /* LEFT DOUBLE QUOTATION MARK */
     619    /*0xD3*/ 0x201D, /* RIGHT DOUBLE QUOTATION MARK */
     620    /*0xD4*/ 0x2018, /* LEFT SINGLE QUOTATION MARK */
     621    /*0xD5*/ 0x2019, /* RIGHT SINGLE QUOTATION MARK */
     622    /*0xD6*/ 0x00F7, /* DIVISION SIGN */
     623    /*0xD7*/ 0x25CA, /* LOZENGE */
     624    /*0xD8*/ 0x00FF, /* LATIN SMALL LETTER Y WITH DIAERESIS */
     625    /*0xD9*/ 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
     626    /*0xDA*/ 0x2044, /* FRACTION SLASH */
     627    /*0xDB*/ 0x20AC, /* EURO SIGN */
     628    /*0xDC*/ 0x2039, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
     629    /*0xDD*/ 0x203A, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
     630    /*0xDE*/ 0xFB01, /* LATIN SMALL LIGATURE FI */
     631    /*0xDF*/ 0xFB02, /* LATIN SMALL LIGATURE FL */
     632    /*0xE0*/ 0x2021, /* DOUBLE DAGGER */
     633    /*0xE1*/ 0x00B7, /* MIDDLE DOT */
     634    /*0xE2*/ 0x201A, /* SINGLE LOW-9 QUOTATION MARK */
     635    /*0xE3*/ 0x201E, /* DOUBLE LOW-9 QUOTATION MARK */
     636    /*0xE4*/ 0x2030, /* PER MILLE SIGN */
     637    /*0xE5*/ 0x00C2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
     638    /*0xE6*/ 0x00CA, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
     639    /*0xE7*/ 0x00C1, /* LATIN CAPITAL LETTER A WITH ACUTE */
     640    /*0xE8*/ 0x00CB, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
     641    /*0xE9*/ 0x00C8, /* LATIN CAPITAL LETTER E WITH GRAVE */
     642    /*0xEA*/ 0x00CD, /* LATIN CAPITAL LETTER I WITH ACUTE */
     643    /*0xEB*/ 0x00CE, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
     644    /*0xEC*/ 0x00CF, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
     645    /*0xED*/ 0x00CC, /* LATIN CAPITAL LETTER I WITH GRAVE */
     646    /*0xEE*/ 0x00D3, /* LATIN CAPITAL LETTER O WITH ACUTE */
     647    /*0xEF*/ 0x00D4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
     648    /*0xF0*/ 0xF8FF, /* Apple logo */
     649    /*0xF1*/ 0x00D2, /* LATIN CAPITAL LETTER O WITH GRAVE */
     650    /*0xF2*/ 0x00DA, /* LATIN CAPITAL LETTER U WITH ACUTE */
     651    /*0xF3*/ 0x00DB, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
     652    /*0xF4*/ 0x00D9, /* LATIN CAPITAL LETTER U WITH GRAVE */
     653    /*0xF5*/ 0x0131, /* LATIN SMALL LETTER DOTLESS I */
     654    /*0xF6*/ 0x02C6, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
     655    /*0xF7*/ 0x02DC, /* SMALL TILDE */
     656    /*0xF8*/ 0x00AF, /* MACRON */
     657    /*0xF9*/ 0x02D8, /* BREVE */
     658    /*0xFA*/ 0x02D9, /* DOT ABOVE */
     659    /*0xFB*/ 0x02DA, /* RING ABOVE */
     660    /*0xFC*/ 0x00B8, /* CEDILLA */
     661    /*0xFD*/ 0x02DD, /* DOUBLE ACUTE ACCENT */
     662    /*0xFE*/ 0x02DB, /* OGONEK */
     663    /*0xFF*/ 0x02C7, /* CARON */
     664  };
     665  
     666  #if USE_ICONV
     667  #include <iconv.h>
     668  #endif
     669  
     670  /*
     671   * A shift-JIS will have many high bits turned on
     672   */
     673  static FcBool
     674  FcLooksLikeSJIS (FcChar8 *string, int len)
     675  {
     676      int	    nhigh = 0, nlow = 0;
     677  
     678      while (len-- > 0)
     679      {
     680  	if (*string++ & 0x80) nhigh++;
     681  	else nlow++;
     682      }
     683      /*
     684       * Heuristic -- if more than 1/3 of the bytes have the high-bit set,
     685       * this is likely to be SJIS and not ROMAN
     686       */
     687      if (nhigh * 2 > nlow)
     688  	return FcTrue;
     689      return FcFalse;
     690  }
     691  
     692  static FcChar8 *
     693  FcSfntNameTranscode (FT_SfntName *sname)
     694  {
     695      int	       i;
     696      const char *fromcode;
     697  #if USE_ICONV
     698      iconv_t cd;
     699  #endif
     700      FcChar8 *utf8;
     701  
     702      for (i = 0; i < NUM_FC_FT_ENCODING; i++)
     703  	if (fcFtEncoding[i].platform_id == sname->platform_id &&
     704  	    (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
     705  	     fcFtEncoding[i].encoding_id == sname->encoding_id))
     706  	    break;
     707      if (i == NUM_FC_FT_ENCODING)
     708  	return 0;
     709      fromcode = fcFtEncoding[i].fromcode;
     710  
     711      /*
     712       * Many names encoded for TT_PLATFORM_MACINTOSH are broken
     713       * in various ways. Kludge around them.
     714       */
     715      if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
     716      {
     717  	if (sname->language_id == TT_MAC_LANGID_ENGLISH &&
     718  	    FcLooksLikeSJIS (sname->string, sname->string_len))
     719  	{
     720  	    fromcode = "SJIS";
     721  	}
     722  	else if (sname->language_id >= 0x100)
     723  	{
     724  	    /*
     725  	     * "real" Mac language IDs are all less than 150.
     726  	     * Names using one of the MS language IDs are assumed
     727  	     * to use an associated encoding (Yes, this is a kludge)
     728  	     */
     729  	    int	f;
     730  
     731  	    fromcode = NULL;
     732  	    for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
     733  		if (fcMacRomanFake[f].language_id == sname->language_id)
     734  		{
     735  		    fromcode = fcMacRomanFake[f].fromcode;
     736  		    break;
     737  		}
     738  	    if (!fromcode)
     739  		return 0;
     740  	}
     741      }
     742      if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
     743      {
     744  	FcChar8	    *src = sname->string;
     745  	int	    src_len = sname->string_len;
     746  	int	    len;
     747  	int	    wchar;
     748  	int	    ilen, olen;
     749  	FcChar8	    *u8;
     750  	FcChar32    ucs4;
     751  	
     752  	/*
     753  	 * Convert Utf16 to Utf8
     754  	 */
     755  
     756  	if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
     757  	    return 0;
     758  
     759  	/*
     760  	 * Allocate plenty of space.  Freed below
     761  	 */
     762  	utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
     763  	if (!utf8)
     764  	    return 0;
     765  
     766  	u8 = utf8;
     767  
     768  	while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
     769  	{
     770  	    src_len -= ilen;
     771  	    src += ilen;
     772  	    olen = FcUcs4ToUtf8 (ucs4, u8);
     773  	    u8 += olen;
     774  	}
     775  	*u8 = '\0';
     776  	goto done;
     777      }
     778      if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
     779      {
     780  	FcChar8	    *src = sname->string;
     781  	int	    src_len = sname->string_len;
     782  	int	    olen;
     783  	FcChar8	    *u8;
     784  	FcChar32    ucs4;
     785  	
     786  	/*
     787  	 * Convert Latin1 to Utf8. Freed below
     788  	 */
     789  	utf8 = malloc (src_len * 2 + 1);
     790  	if (!utf8)
     791  	    return 0;
     792  
     793  	u8 = utf8;
     794  	while (src_len > 0)
     795  	{
     796  	    ucs4 = *src++;
     797  	    src_len--;
     798  	    olen = FcUcs4ToUtf8 (ucs4, u8);
     799  	    u8 += olen;
     800  	}
     801  	*u8 = '\0';
     802  	goto done;
     803      }
     804      if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
     805      {
     806  	FcChar8	    *src = sname->string;
     807  	int	    src_len = sname->string_len;
     808  	int	    olen;
     809  	FcChar8	    *u8;
     810  	FcChar32    ucs4;
     811  
     812  	/*
     813  	 * Convert Latin1 to Utf8. Freed below
     814  	 */
     815  	utf8 = malloc (src_len * 3 + 1);
     816  	if (!utf8)
     817  	    return 0;
     818  
     819  	u8 = utf8;
     820  	while (src_len > 0)
     821  	{
     822  	    ucs4 = *src++;
     823  	    if (ucs4 >= 128)
     824  	        ucs4 = fcMacRomanNonASCIIToUnicode[ucs4 - 128];
     825  	    src_len--;
     826  	    olen = FcUcs4ToUtf8 (ucs4, u8);
     827  	    u8 += olen;
     828  	}
     829  	*u8 = '\0';
     830  	goto done;
     831      }
     832  
     833  #if USE_ICONV
     834      cd = iconv_open ("UTF-8", fromcode);
     835      if (cd && cd != (iconv_t) (-1))
     836      {
     837  	size_t	    in_bytes_left = sname->string_len;
     838  	size_t	    out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
     839  	char	    *inbuf, *outbuf;
     840  	
     841  	utf8 = malloc (out_bytes_left + 1);
     842  	if (!utf8)
     843  	{
     844  	    iconv_close (cd);
     845  	    return 0;
     846  	}
     847  	
     848  	outbuf = (char *) utf8;
     849  	inbuf = (char *) sname->string;
     850  	
     851  	while (in_bytes_left)
     852  	{
     853  	    size_t	did = iconv (cd,
     854  				 &inbuf, &in_bytes_left,
     855  				 &outbuf, &out_bytes_left);
     856  	    if (did == (size_t) (-1))
     857  	    {
     858  		iconv_close (cd);
     859  		free (utf8);
     860  		return 0;
     861  	    }
     862  	}
     863      	iconv_close (cd);
     864  	*outbuf = '\0';
     865  	goto done;
     866      }
     867  #endif
     868      return 0;
     869  done:
     870      if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0)
     871      {
     872  	free (utf8);
     873  	return 0;
     874      }
     875      return utf8;
     876  }
     877  
     878  static const FcChar8 *
     879  FcSfntNameLanguage (FT_SfntName *sname)
     880  {
     881      int i;
     882      FT_UShort	platform_id = sname->platform_id;
     883      FT_UShort	language_id = sname->language_id;
     884  
     885      /*
     886       * Many names encoded for TT_PLATFORM_MACINTOSH are broken
     887       * in various ways. Kludge around them.
     888       */
     889      if (platform_id == TT_PLATFORM_MACINTOSH &&
     890  	sname->encoding_id == TT_MAC_ID_ROMAN &&
     891  	FcLooksLikeSJIS (sname->string, sname->string_len))
     892      {
     893  	language_id = TT_MAC_LANGID_JAPANESE;
     894      }
     895  
     896      for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
     897  	if (fcFtLanguage[i].platform_id == platform_id &&
     898  	    (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
     899  	     fcFtLanguage[i].language_id == language_id))
     900  	{
     901  	    if (fcFtLanguage[i].lang[0] == '\0')
     902  	      return NULL;
     903  	    else
     904  	      return (FcChar8 *) fcFtLanguage[i].lang;
     905  	}
     906      return 0;
     907  }
     908  
     909  static const FcChar8 *
     910  FcNoticeFoundry(const FT_String *notice)
     911  {
     912      int i;
     913  
     914      if (notice)
     915  	for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
     916          {
     917              const char *n = FcNoticeFoundries[i][0];
     918              const char *f = FcNoticeFoundries[i][1];
     919  
     920  	    if (strstr ((const char *) notice, n))
     921  		return (const FcChar8 *) f;
     922          }
     923      return 0;
     924  }
     925  
     926  typedef struct _FcStringConst {
     927      const FcChar8   *name;
     928      int		    value;
     929  } FcStringConst;
     930  
     931  static int
     932  FcStringIsConst (const FcChar8		*string,
     933  		 const FcStringConst	*c,
     934  		 int			nc)
     935  {
     936      int	i;
     937  
     938      for (i = 0; i < nc; i++)
     939  	if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
     940  	    return c[i].value;
     941      return -1;
     942  }
     943  
     944  static int
     945  FcStringContainsConst (const FcChar8	    *string,
     946  		       const FcStringConst  *c,
     947  		       int		    nc)
     948  {
     949      int	i;
     950  
     951      for (i = 0; i < nc; i++)
     952      {
     953  	if (c[i].name[0] == '<')
     954  	{
     955  	    if (FcStrContainsWord (string, c[i].name + 1))
     956  		return c[i].value;
     957  	}
     958  	else
     959  	{
     960  	    if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
     961  		return c[i].value;
     962  	}
     963      }
     964      return -1;
     965  }
     966  
     967  typedef FcChar8 *FC8;
     968  
     969  static const FcStringConst  weightConsts[] = {
     970      { (FC8) "thin",		FC_WEIGHT_THIN },
     971      { (FC8) "extralight",	FC_WEIGHT_EXTRALIGHT },
     972      { (FC8) "ultralight",	FC_WEIGHT_ULTRALIGHT },
     973      { (FC8) "demilight",	FC_WEIGHT_DEMILIGHT },
     974      { (FC8) "semilight",	FC_WEIGHT_SEMILIGHT },
     975      { (FC8) "light",		FC_WEIGHT_LIGHT },
     976      { (FC8) "book",		FC_WEIGHT_BOOK },
     977      { (FC8) "regular",		FC_WEIGHT_REGULAR },
     978      { (FC8) "normal",		FC_WEIGHT_NORMAL },
     979      { (FC8) "medium",		FC_WEIGHT_MEDIUM },
     980      { (FC8) "demibold",		FC_WEIGHT_DEMIBOLD },
     981      { (FC8) "demi",		FC_WEIGHT_DEMIBOLD },
     982      { (FC8) "semibold",		FC_WEIGHT_SEMIBOLD },
     983      { (FC8) "extrabold",	FC_WEIGHT_EXTRABOLD },
     984      { (FC8) "superbold",	FC_WEIGHT_EXTRABOLD },
     985      { (FC8) "ultrabold",	FC_WEIGHT_ULTRABOLD },
     986      { (FC8) "bold",		FC_WEIGHT_BOLD },
     987      { (FC8) "ultrablack",	FC_WEIGHT_ULTRABLACK },
     988      { (FC8) "superblack",	FC_WEIGHT_EXTRABLACK },
     989      { (FC8) "extrablack",	FC_WEIGHT_EXTRABLACK },
     990      { (FC8) "<ultra",		FC_WEIGHT_ULTRABOLD }, /* only if a word */
     991      { (FC8) "black",		FC_WEIGHT_BLACK },
     992      { (FC8) "heavy",		FC_WEIGHT_HEAVY },
     993  };
     994  
     995  #define NUM_WEIGHT_CONSTS  (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
     996  
     997  #define FcIsWeight(s)	    FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
     998  #define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
     999  
    1000  static const FcStringConst  widthConsts[] = {
    1001      { (FC8) "ultracondensed",	FC_WIDTH_ULTRACONDENSED },
    1002      { (FC8) "extracondensed",	FC_WIDTH_EXTRACONDENSED },
    1003      { (FC8) "semicondensed",	FC_WIDTH_SEMICONDENSED },
    1004      { (FC8) "condensed",	FC_WIDTH_CONDENSED },	/* must be after *condensed */
    1005      { (FC8) "normal",		FC_WIDTH_NORMAL },
    1006      { (FC8) "semiexpanded",	FC_WIDTH_SEMIEXPANDED },
    1007      { (FC8) "extraexpanded",	FC_WIDTH_EXTRAEXPANDED },
    1008      { (FC8) "ultraexpanded",	FC_WIDTH_ULTRAEXPANDED },
    1009      { (FC8) "expanded",		FC_WIDTH_EXPANDED },	/* must be after *expanded */
    1010      { (FC8) "extended",		FC_WIDTH_EXPANDED },
    1011  };
    1012  
    1013  #define NUM_WIDTH_CONSTS    (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
    1014  
    1015  #define FcIsWidth(s)	    FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
    1016  #define FcContainsWidth(s)  FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
    1017  
    1018  static const FcStringConst  slantConsts[] = {
    1019      { (FC8) "italic",		FC_SLANT_ITALIC },
    1020      { (FC8) "kursiv",		FC_SLANT_ITALIC },
    1021      { (FC8) "oblique",		FC_SLANT_OBLIQUE },
    1022  };
    1023  
    1024  #define NUM_SLANT_CONSTS    (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
    1025  
    1026  #define FcContainsSlant(s)  FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
    1027  
    1028  static const FcStringConst  decorativeConsts[] = {
    1029      { (FC8) "shadow",		FcTrue },
    1030      { (FC8) "caps",		FcTrue },
    1031      { (FC8) "antiqua",		FcTrue },
    1032      { (FC8) "romansc",		FcTrue },
    1033      { (FC8) "embosed",		FcTrue },
    1034      { (FC8) "dunhill",		FcTrue },
    1035  };
    1036  
    1037  #define NUM_DECORATIVE_CONSTS	(int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
    1038  
    1039  #define FcContainsDecorative(s)	FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
    1040  
    1041  static double
    1042  FcGetPixelSize (FT_Face face, int i)
    1043  {
    1044  #if HAVE_FT_GET_BDF_PROPERTY
    1045      if (face->num_fixed_sizes == 1)
    1046      {
    1047  	BDF_PropertyRec	prop;
    1048  	int		rc;
    1049  
    1050  	rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
    1051  	if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
    1052  	    return (double) prop.u.integer;
    1053      }
    1054  #endif
    1055      return (double) face->available_sizes[i].y_ppem / 64.0;
    1056  }
    1057  
    1058  static FcBool
    1059  FcStringInPatternElement (FcPattern *pat, FcObject obj, const FcChar8 *string)
    1060  {
    1061      FcPatternIter iter;
    1062      FcValueListPtr l;
    1063  
    1064      FcPatternIterStart (pat, &iter);
    1065      if (!FcPatternFindObjectIter (pat, &iter, obj))
    1066  	return FcFalse;
    1067      for (l = FcPatternIterGetValues (pat, &iter); l; l = FcValueListNext (l))
    1068      {
    1069  	FcValue v = FcValueCanonicalize (&l->value);
    1070  	if (v.type != FcTypeString)
    1071  	    break;
    1072  	if (!FcStrCmpIgnoreBlanksAndCase (v.u.s, string))
    1073  	    return FcTrue;
    1074      }
    1075      return FcFalse;
    1076  }
    1077  
    1078  static const FT_UShort platform_order[] = {
    1079      TT_PLATFORM_MICROSOFT,
    1080      TT_PLATFORM_APPLE_UNICODE,
    1081      TT_PLATFORM_MACINTOSH,
    1082      TT_PLATFORM_ISO,
    1083  };
    1084  #define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
    1085  
    1086  static const FT_UShort nameid_order[] = {
    1087      TT_NAME_ID_WWS_FAMILY,
    1088      TT_NAME_ID_TYPOGRAPHIC_FAMILY,
    1089      TT_NAME_ID_FONT_FAMILY,
    1090      TT_NAME_ID_MAC_FULL_NAME,
    1091      TT_NAME_ID_FULL_NAME,
    1092      TT_NAME_ID_WWS_SUBFAMILY,
    1093      TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY,
    1094      TT_NAME_ID_FONT_SUBFAMILY,
    1095      TT_NAME_ID_TRADEMARK,
    1096      TT_NAME_ID_MANUFACTURER,
    1097  };
    1098  
    1099  #define NUM_NAMEID_ORDER  (sizeof (nameid_order) / sizeof (nameid_order[0]))
    1100  
    1101  typedef struct
    1102  {
    1103    unsigned int platform_id;
    1104    unsigned int name_id;
    1105    unsigned int encoding_id;
    1106    unsigned int language_id;
    1107    unsigned int idx;
    1108  } FcNameMapping;
    1109  
    1110  static FcBool
    1111  _is_english(int platform, int language)
    1112  {
    1113      FcBool ret = FcFalse;
    1114  
    1115      switch (platform)
    1116      {
    1117      case TT_PLATFORM_MACINTOSH:
    1118  	ret = language == TT_MAC_LANGID_ENGLISH;
    1119  	break;
    1120      case TT_PLATFORM_MICROSOFT:
    1121  	ret = language == TT_MS_LANGID_ENGLISH_UNITED_STATES;
    1122  	break;
    1123      }
    1124      return ret;
    1125  }
    1126  
    1127  static int
    1128  name_mapping_cmp (const void *pa, const void *pb)
    1129  {
    1130    const FcNameMapping *a = (const FcNameMapping *) pa;
    1131    const FcNameMapping *b = (const FcNameMapping *) pb;
    1132  
    1133    if (a->platform_id != b->platform_id) return (int) a->platform_id - (int) b->platform_id;
    1134    if (a->name_id != b->name_id) return (int) a->name_id - (int) b->name_id;
    1135    if (a->encoding_id != b->encoding_id) return (int) a->encoding_id - (int) b->encoding_id;
    1136    if (a->language_id != b->language_id) return _is_english(a->platform_id, a->language_id) ? -1 : _is_english(b->platform_id, b->language_id) ? 1 : (int) a->language_id - (int) b->language_id;
    1137    if (a->idx != b->idx) return (int) a->idx - (int) b->idx;
    1138  
    1139    return 0;
    1140  }
    1141  
    1142  static int
    1143  FcFreeTypeGetFirstName (const FT_Face face,
    1144  			unsigned int  platform,
    1145  			unsigned int  nameid,
    1146  			FcNameMapping *mapping,
    1147  			unsigned int   count,
    1148  			FT_SfntName   *sname)
    1149  {
    1150      int min = 0, max = (int) count - 1;
    1151  
    1152      while (min <= max)
    1153      {
    1154  	int mid = (min + max) / 2;
    1155  
    1156  	if (FT_Get_Sfnt_Name (face, mapping[mid].idx, sname) != 0)
    1157  	    return FcFalse;
    1158  
    1159  	if (platform < sname->platform_id ||
    1160  	    (platform == sname->platform_id &&
    1161  	     (nameid < sname->name_id ||
    1162  	      (nameid == sname->name_id &&
    1163  	       (mid &&
    1164  		platform == mapping[mid - 1].platform_id &&
    1165  		nameid == mapping[mid - 1].name_id
    1166  	       )))))
    1167  	    max = mid - 1;
    1168  	else if (platform > sname->platform_id ||
    1169  		 (platform == sname->platform_id &&
    1170  		  nameid > sname->name_id))
    1171  	    min = mid + 1;
    1172  	else
    1173  	    return mid;
    1174      }
    1175  
    1176      return -1;
    1177  }
    1178  
    1179  static FcPattern *
    1180  FcFreeTypeQueryFaceInternal (const FT_Face  face,
    1181  			     const FcChar8  *file,
    1182  			     unsigned int   id,
    1183  			     FcCharSet      **cs_share,
    1184  			     FcLangSet      **ls_share,
    1185  			     FcNameMapping  **nm_share)
    1186  {
    1187      FcPattern	    *pat;
    1188      int		    slant = -1;
    1189      double	    weight = -1;
    1190      double	    width = -1;
    1191      FcBool	    decorative = FcFalse;
    1192      FcBool	    variable = FcFalse;
    1193      FcBool	    variable_weight = FcFalse;
    1194      FcBool	    variable_width = FcFalse;
    1195      FcBool	    variable_size = FcFalse;
    1196      FcCharSet       *cs;
    1197      FcLangSet       *ls;
    1198      FcNameMapping   *name_mapping = NULL;
    1199  #if 0
    1200      FcChar8	    *family = 0;
    1201  #endif
    1202      FcChar8	    *complex_, *foundry_ = NULL;
    1203      const FcChar8   *foundry = 0;
    1204      int		    spacing;
    1205  
    1206      /* Support for glyph-variation named-instances. */
    1207      FT_MM_Var       *master = NULL;
    1208      FT_Var_Named_Style *instance = NULL;
    1209      double          weight_mult = 1.0;
    1210      double          width_mult = 1.0;
    1211  
    1212      TT_OS2	    *os2;
    1213  #if HAVE_FT_GET_PS_FONT_INFO
    1214      PS_FontInfoRec  psfontinfo;
    1215  #endif
    1216  #if HAVE_FT_GET_BDF_PROPERTY
    1217      BDF_PropertyRec prop;
    1218  #endif
    1219      TT_Header	    *head;
    1220      const FcChar8   *exclusiveLang = 0;
    1221  
    1222      int		    name_count = 0;
    1223      int		    nfamily = 0;
    1224      int		    nfamily_lang = 0;
    1225      int		    nstyle = 0;
    1226      int		    nstyle_lang = 0;
    1227      int		    nfullname = 0;
    1228      int		    nfullname_lang = 0;
    1229      unsigned int    p, n;
    1230  
    1231      FcChar8	    *style = 0;
    1232      int		    st;
    1233  
    1234      FcBool	    symbol = FcFalse;
    1235      FT_Error	    ftresult;
    1236  
    1237      FcInitDebug (); /* We might be called with no initizalization whatsoever. */
    1238  
    1239      pat = FcPatternCreate ();
    1240      if (!pat)
    1241  	goto bail0;
    1242  
    1243      {
    1244  	int has_outline = !!(face->face_flags & FT_FACE_FLAG_SCALABLE);
    1245  	int has_color = 0;
    1246  
    1247  	if (!FcPatternObjectAddBool (pat, FC_OUTLINE_OBJECT, has_outline))
    1248  	    goto bail1;
    1249  
    1250  	has_color = !!FT_HAS_COLOR (face);
    1251  	if (!FcPatternObjectAddBool (pat, FC_COLOR_OBJECT, has_color))
    1252  	    goto bail1;
    1253  
    1254  	/* All color fonts are designed to be scaled, even if they only have
    1255  	 * bitmap strikes.  Client is responsible to scale the bitmaps.  This
    1256  	 * is in contrast to non-color strikes... */
    1257  	if (!FcPatternObjectAddBool (pat, FC_SCALABLE_OBJECT, has_outline || has_color))
    1258  	    goto bail1;
    1259      }
    1260  
    1261      ftresult = FT_Get_MM_Var (face, &master);
    1262  
    1263      if (id >> 16)
    1264      {
    1265  	if (ftresult)
    1266  	    goto bail1;
    1267  
    1268        if (id >> 16 == 0x8000)
    1269        {
    1270  	  /* Query variable font itself. */
    1271  	  unsigned int i;
    1272  	  for (i = 0; i < master->num_axis; i++)
    1273  	  {
    1274  	      double min_value = master->axis[i].minimum / (double) (1U << 16);
    1275  	      double def_value = master->axis[i].def / (double) (1U << 16);
    1276  	      double max_value = master->axis[i].maximum / (double) (1U << 16);
    1277  	      FcObject obj = FC_INVALID_OBJECT;
    1278  
    1279  	      if (min_value > def_value || def_value > max_value || min_value == max_value)
    1280  		  continue;
    1281  
    1282  	      switch (master->axis[i].tag)
    1283  	      {
    1284  		case FT_MAKE_TAG ('w','g','h','t'):
    1285  		  obj = FC_WEIGHT_OBJECT;
    1286  		  min_value = FcWeightFromOpenTypeDouble (min_value);
    1287  		  max_value = FcWeightFromOpenTypeDouble (max_value);
    1288  		  variable_weight = FcTrue;
    1289  		  weight = 0; /* To stop looking for weight. */
    1290  		  break;
    1291  
    1292  		case FT_MAKE_TAG ('w','d','t','h'):
    1293  		  obj = FC_WIDTH_OBJECT;
    1294  		  /* Values in 'wdth' match Fontconfig FC_WIDTH_* scheme directly. */
    1295  		  variable_width = FcTrue;
    1296  		  width = 0; /* To stop looking for width. */
    1297  		  break;
    1298  
    1299  		case FT_MAKE_TAG ('o','p','s','z'):
    1300  		  obj = FC_SIZE_OBJECT;
    1301  		  /* Values in 'opsz' match Fontconfig FC_SIZE, both are in points. */
    1302  		  variable_size = FcTrue;
    1303  		  break;
    1304  	      }
    1305  
    1306  	      if (obj != FC_INVALID_OBJECT)
    1307  	      {
    1308  		  FcRange *r = FcRangeCreateDouble (min_value, max_value);
    1309  		  if (!FcPatternObjectAddRange (pat, obj, r))
    1310  		  {
    1311  		      FcRangeDestroy (r);
    1312  		      goto bail1;
    1313  		  }
    1314  		  FcRangeDestroy (r);
    1315  		  variable = FcTrue;
    1316  	      }
    1317  	  }
    1318  
    1319  	  if (!variable)
    1320  	      goto bail1;
    1321  
    1322  	  id &= 0xFFFF;
    1323        }
    1324        else if ((id >> 16) - 1 < master->num_namedstyles)
    1325        {
    1326  	  /* Pull out weight and width from named-instance. */
    1327  	  unsigned int i;
    1328  
    1329  	  instance = &master->namedstyle[(id >> 16) - 1];
    1330  
    1331  	  for (i = 0; i < master->num_axis; i++)
    1332  	  {
    1333  	      double value = instance->coords[i] / (double) (1U << 16);
    1334  	      double default_value = master->axis[i].def / (double) (1U << 16);
    1335  	      double mult = default_value ? value / default_value : 1;
    1336  	      //printf ("named-instance, axis %d tag %lx value %g\n", i, master->axis[i].tag, value);
    1337  	      switch (master->axis[i].tag)
    1338  	      {
    1339  		case FT_MAKE_TAG ('w','g','h','t'):
    1340  		  weight_mult = mult;
    1341  		  break;
    1342  
    1343  		case FT_MAKE_TAG ('w','d','t','h'):
    1344  		  width_mult = mult;
    1345  		  break;
    1346  
    1347  		case FT_MAKE_TAG ('o','p','s','z'):
    1348  		  if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, value))
    1349  		      goto bail1;
    1350  		  break;
    1351  	    }
    1352  	  }
    1353  	}
    1354          else
    1355  	    goto bail1;
    1356      }
    1357      else
    1358      {
    1359  	if (!ftresult)
    1360  	{
    1361  	    unsigned int i;
    1362  	    for (i = 0; i < master->num_axis; i++)
    1363  	    {
    1364  		switch (master->axis[i].tag)
    1365  		{
    1366  		case FT_MAKE_TAG ('o','p','s','z'):
    1367  		    if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, master->axis[i].def / (double) (1U << 16)))
    1368  			goto bail1;
    1369  		    variable_size = FcTrue;
    1370  		    break;
    1371  		}
    1372  	    }
    1373  	}
    1374  	else
    1375  	{
    1376  	    /* ignore an error of FT_Get_MM_Var() */
    1377  	}
    1378      }
    1379      if (!FcPatternObjectAddBool (pat, FC_VARIABLE_OBJECT, variable))
    1380  	goto bail1;
    1381  
    1382      /*
    1383       * Get the OS/2 table
    1384       */
    1385      os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, FT_SFNT_OS2);
    1386  
    1387      /*
    1388       * Look first in the OS/2 table for the foundry, if
    1389       * not found here, the various notices will be searched for
    1390       * that information, either from the sfnt name tables or
    1391       * the Postscript FontInfo dictionary.  Finally, the
    1392       * BDF properties will queried.
    1393       */
    1394  
    1395      if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
    1396      {
    1397  	if (os2->achVendID[0] != 0)
    1398  	{
    1399  	    foundry_ = (FcChar8 *) malloc (sizeof (os2->achVendID) + 1);
    1400  	    memcpy ((void *)foundry_, os2->achVendID, sizeof (os2->achVendID));
    1401  	    foundry_[sizeof (os2->achVendID)] = 0;
    1402  	    foundry = foundry_;
    1403  	}
    1404      }
    1405  
    1406      if (FcDebug () & FC_DBG_SCANV)
    1407  	printf ("\n");
    1408      /*
    1409       * Grub through the name table looking for family
    1410       * and style names.  FreeType makes quite a hash
    1411       * of them
    1412       */
    1413      name_count = FT_Get_Sfnt_Name_Count (face);
    1414      if (nm_share)
    1415  	name_mapping = *nm_share;
    1416      if (!name_mapping)
    1417      {
    1418  	int i = 0;
    1419  	name_mapping = malloc (name_count * sizeof (FcNameMapping));
    1420  	if (!name_mapping)
    1421  	    name_count = 0;
    1422  	for (i = 0; i < name_count; i++)
    1423  	{
    1424  	    FcNameMapping *p = &name_mapping[i];
    1425  	    FT_SfntName sname;
    1426  	    if (FT_Get_Sfnt_Name (face, i, &sname) == 0)
    1427  	    {
    1428  		p->platform_id = sname.platform_id;
    1429  		p->name_id  = sname.name_id;
    1430  		p->encoding_id = sname.encoding_id;
    1431  		p->language_id = sname.language_id;
    1432  		p->idx = i;
    1433  	    }
    1434  	    else
    1435  	    {
    1436  		p->platform_id =
    1437  		p->name_id  =
    1438  		p->encoding_id =
    1439  		p->language_id =
    1440  		p->idx = (unsigned int) -1;
    1441  	    }
    1442  	}
    1443  	qsort (name_mapping, name_count, sizeof(FcNameMapping), name_mapping_cmp);
    1444  
    1445  	if (nm_share)
    1446  	    *nm_share = name_mapping;
    1447      }
    1448      for (p = 0; p < NUM_PLATFORM_ORDER; p++)
    1449      {
    1450  	int platform = platform_order[p];
    1451  
    1452  	/*
    1453  	 * Order nameids so preferred names appear first
    1454  	 * in the resulting list
    1455  	 */
    1456  	for (n = 0; n < NUM_NAMEID_ORDER; n++)
    1457  	{
    1458  	    FT_SfntName sname;
    1459  	    int nameidx;
    1460  	    const FcChar8	*lang;
    1461  	    int		*np = 0, *nlangp = 0;
    1462  	    size_t		len;
    1463  	    int nameid, lookupid;
    1464  	    FcObject obj = FC_INVALID_OBJECT, objlang = FC_INVALID_OBJECT;
    1465  
    1466  	    nameid = lookupid = nameid_order[n];
    1467  
    1468  	    if (instance)
    1469  	    {
    1470  		/* For named-instances, we skip regular style nameIDs,
    1471  		 * and treat the instance's nameid as FONT_SUBFAMILY.
    1472  		 * Postscript name is automatically handled by FreeType. */
    1473  		if (nameid == TT_NAME_ID_WWS_SUBFAMILY ||
    1474  		    nameid == TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY ||
    1475  		    nameid == TT_NAME_ID_FULL_NAME)
    1476  		    continue;
    1477  
    1478  		if (nameid == TT_NAME_ID_FONT_SUBFAMILY)
    1479  		    lookupid = instance->strid;
    1480  	    }
    1481  
    1482  	    nameidx = FcFreeTypeGetFirstName (face, platform, lookupid,
    1483  					      name_mapping, name_count,
    1484  					      &sname);
    1485  	    if (nameidx == -1)
    1486  		continue;
    1487  	    do
    1488  	    {
    1489  		switch (nameid) {
    1490  		case TT_NAME_ID_WWS_FAMILY:
    1491  		case TT_NAME_ID_TYPOGRAPHIC_FAMILY:
    1492  		case TT_NAME_ID_FONT_FAMILY:
    1493  #if 0	
    1494  		case TT_NAME_ID_UNIQUE_ID:
    1495  #endif
    1496  		    if (FcDebug () & FC_DBG_SCANV)
    1497  			printf ("found family (n %2d p %d e %d l 0x%04x)",
    1498  				sname.name_id, sname.platform_id,
    1499  				sname.encoding_id, sname.language_id);
    1500  
    1501  		    obj = FC_FAMILY_OBJECT;
    1502  		    objlang = FC_FAMILYLANG_OBJECT;
    1503  		    np = &nfamily;
    1504  		    nlangp = &nfamily_lang;
    1505  		    break;
    1506  		case TT_NAME_ID_MAC_FULL_NAME:
    1507  		case TT_NAME_ID_FULL_NAME:
    1508  		    if (variable)
    1509  			break;
    1510  		    if (FcDebug () & FC_DBG_SCANV)
    1511  			printf ("found full   (n %2d p %d e %d l 0x%04x)",
    1512  				sname.name_id, sname.platform_id,
    1513  				sname.encoding_id, sname.language_id);
    1514  
    1515  		    obj = FC_FULLNAME_OBJECT;
    1516  		    objlang = FC_FULLNAMELANG_OBJECT;
    1517  		    np = &nfullname;
    1518  		    nlangp = &nfullname_lang;
    1519  		    break;
    1520  		case TT_NAME_ID_WWS_SUBFAMILY:
    1521  		case TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY:
    1522  		case TT_NAME_ID_FONT_SUBFAMILY:
    1523  		    if (variable)
    1524  			break;
    1525  		    if (FcDebug () & FC_DBG_SCANV)
    1526  			printf ("found style  (n %2d p %d e %d l 0x%04x) ",
    1527  				sname.name_id, sname.platform_id,
    1528  				sname.encoding_id, sname.language_id);
    1529  
    1530  		    obj = FC_STYLE_OBJECT;
    1531  		    objlang = FC_STYLELANG_OBJECT;
    1532  		    np = &nstyle;
    1533  		    nlangp = &nstyle_lang;
    1534  		    break;
    1535  		case TT_NAME_ID_TRADEMARK:
    1536  		case TT_NAME_ID_MANUFACTURER:
    1537  		    /* If the foundry wasn't found in the OS/2 table, look here */
    1538  		    if(!foundry)
    1539  		    {
    1540  			FcChar8 *utf8;
    1541  			utf8 = FcSfntNameTranscode (&sname);
    1542  			foundry = FcNoticeFoundry((FT_String *) utf8);
    1543  			free (utf8);
    1544  		    }
    1545  		    break;
    1546  		}
    1547  		if (obj != FC_INVALID_OBJECT)
    1548  		{
    1549  		    FcChar8		*utf8, *pp;
    1550  
    1551  		    utf8 = FcSfntNameTranscode (&sname);
    1552  		    lang = FcSfntNameLanguage (&sname);
    1553  
    1554  		    if (FcDebug () & FC_DBG_SCANV)
    1555  			printf ("%s\n", utf8 ? (char *)utf8 : "(null)");
    1556  
    1557  		    if (!utf8)
    1558  			continue;
    1559  
    1560  		    /* Trim surrounding whitespace. */
    1561  		    pp = utf8;
    1562  		    while (*pp == ' ')
    1563  			pp++;
    1564  		    len = strlen ((const char *) pp);
    1565  		    memmove (utf8, pp, len + 1);
    1566  		    pp = utf8 + len;
    1567  		    while (pp > utf8 && *(pp - 1) == ' ')
    1568  			pp--;
    1569  		    *pp = 0;
    1570  
    1571  		    if (FcStringInPatternElement (pat, obj, utf8))
    1572  		    {
    1573  			free (utf8);
    1574  			continue;
    1575  		    }
    1576  
    1577  		    /* add new element */
    1578  		    if (!FcPatternObjectAddString (pat, obj, utf8))
    1579  		    {
    1580  			free (utf8);
    1581  			goto bail1;
    1582  		    }
    1583  		    free (utf8);
    1584  		    if (lang)
    1585  		    {
    1586  			/* pad lang list with 'und' to line up with elt */
    1587  			while (*nlangp < *np)
    1588  			{
    1589  			    if (!FcPatternObjectAddString (pat, objlang, (FcChar8 *) "und"))
    1590  				goto bail1;
    1591  			    ++*nlangp;
    1592  			}
    1593  			if (!FcPatternObjectAddString (pat, objlang, lang))
    1594  			    goto bail1;
    1595  			++*nlangp;
    1596  		    }
    1597  		    ++*np;
    1598  		}
    1599  	    }
    1600  	    while (++nameidx < name_count &&
    1601  		   FT_Get_Sfnt_Name (face, name_mapping[nameidx].idx, &sname) == 0 &&
    1602  		   platform == sname.platform_id && lookupid == sname.name_id);
    1603  	}
    1604      }
    1605      if (!nm_share)
    1606      {
    1607  	free (name_mapping);
    1608  	name_mapping = NULL;
    1609      }
    1610  
    1611      if (!nfamily && face->family_name &&
    1612  	FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
    1613      {
    1614  	if (FcDebug () & FC_DBG_SCANV)
    1615  	    printf ("using FreeType family \"%s\"\n", face->family_name);
    1616  	if (!FcPatternObjectAddString (pat, FC_FAMILY_OBJECT, (FcChar8 *) face->family_name))
    1617  	    goto bail1;
    1618  	if (!FcPatternObjectAddString (pat, FC_FAMILYLANG_OBJECT, (FcChar8 *) "en"))
    1619  	    goto bail1;
    1620  	++nfamily;
    1621      }
    1622  
    1623      if (!variable && !nstyle)
    1624      {
    1625  	const FcChar8 *style_regular = (const FcChar8 *) "Regular";
    1626  	const FcChar8 *ss;
    1627  
    1628  	if (face->style_name &&
    1629  	    FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
    1630  	{
    1631  	    if (FcDebug () & FC_DBG_SCANV)
    1632  		printf ("using FreeType style \"%s\"\n", face->style_name);
    1633  
    1634  	    ss = (const FcChar8 *) face->style_name;
    1635  	}
    1636  	else
    1637  	{
    1638  	    if (FcDebug () & FC_DBG_SCANV)
    1639  		printf ("applying default style Regular\n");
    1640  	    ss = style_regular;
    1641  	}
    1642  	if (!FcPatternObjectAddString (pat, FC_STYLE_OBJECT, ss))
    1643  	    goto bail1;
    1644  	if (!FcPatternObjectAddString (pat, FC_STYLELANG_OBJECT, (FcChar8 *) "en"))
    1645  	    goto bail1;
    1646  	++nstyle;
    1647      }
    1648  
    1649      if (!nfamily && file && *file)
    1650      {
    1651  	FcChar8	*start, *end;
    1652  	FcChar8	*family;
    1653  	
    1654  	start = (FcChar8 *) strrchr ((char *) file, '/');
    1655  	if (start)
    1656  	    start++;
    1657  	else
    1658  	    start = (FcChar8 *) file;
    1659  	end = (FcChar8 *) strrchr ((char *) start, '.');
    1660  	if (!end)
    1661  	    end = start + strlen ((char *) start);
    1662  	/* freed below */
    1663  	family = malloc (end - start + 1);
    1664  	strncpy ((char *) family, (char *) start, end - start);
    1665  	family[end - start] = '\0';
    1666  	if (FcDebug () & FC_DBG_SCANV)
    1667  	    printf ("using filename for family %s\n", family);
    1668  	if (!FcPatternObjectAddString (pat, FC_FAMILY_OBJECT, family))
    1669  	{
    1670  	    free (family);
    1671  	    goto bail1;
    1672  	}
    1673  	if (!FcPatternObjectAddString (pat, FC_FAMILYLANG_OBJECT, (FcChar8 *) "en"))
    1674  	{
    1675  	    free (family);
    1676  	    goto bail1;
    1677  	}
    1678  	free (family);
    1679  	++nfamily;
    1680      }
    1681  
    1682      /* Add the fullname into the cache */
    1683      if (!variable && !nfullname)
    1684      {
    1685  	FcChar8 *family, *style, *lang = NULL;
    1686  	int n = 0;
    1687  	size_t len, i;
    1688  	FcStrBuf sbuf;
    1689  
    1690  	while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &lang) == FcResultMatch)
    1691  	{
    1692  	    if (FcStrCmp (lang, (const FcChar8 *) "en") == 0)
    1693  		break;
    1694  	    n++;
    1695  	    lang = NULL;
    1696  	}
    1697  	if (!lang)
    1698  	    n = 0;
    1699  	if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch)
    1700  	    goto bail1;
    1701  	len = strlen ((const char *) family);
    1702  	for (i = len; i > 0; i--)
    1703  	{
    1704  	    if (!isspace (family[i-1]))
    1705  		break;
    1706  	}
    1707  	family[i] = 0;
    1708  	n = 0;
    1709  	while (FcPatternObjectGetString (pat, FC_STYLELANG_OBJECT, n, &lang) == FcResultMatch)
    1710  	{
    1711  	    if (FcStrCmp (lang, (const FcChar8 *) "en") == 0)
    1712  		break;
    1713  	    n++;
    1714  	    lang = NULL;
    1715  	}
    1716  	if (!lang)
    1717  	    n = 0;
    1718  	if (FcPatternObjectGetString (pat, FC_STYLE_OBJECT, n, &style) != FcResultMatch)
    1719  	    goto bail1;
    1720  	len = strlen ((const char *) style);
    1721  	for (i = 0; style[i] != 0 && isspace (style[i]); i++);
    1722  	memcpy (style, &style[i], len - i);
    1723  	FcStrBufInit (&sbuf, NULL, 0);
    1724  	FcStrBufString (&sbuf, family);
    1725  	FcStrBufChar (&sbuf, ' ');
    1726  	FcStrBufString (&sbuf, style);
    1727  	if (!FcPatternObjectAddString (pat, FC_FULLNAME_OBJECT, FcStrBufDoneStatic (&sbuf)))
    1728  	{
    1729  	    FcStrBufDestroy (&sbuf);
    1730  	    goto bail1;
    1731  	}
    1732  	FcStrBufDestroy (&sbuf);
    1733  	if (!FcPatternObjectAddString (pat, FC_FULLNAMELANG_OBJECT, (const FcChar8 *) "en"))
    1734  	    goto bail1;
    1735  	++nfullname;
    1736      }
    1737      /* Add the PostScript name into the cache */
    1738      if (!variable)
    1739      {
    1740  	char	    psname[256];
    1741  	const char	    *tmp;
    1742  	tmp = FT_Get_Postscript_Name (face);
    1743  	if (!tmp)
    1744  	{
    1745  	    unsigned int i;
    1746  	    FcChar8 *family, *familylang = NULL;
    1747  	    size_t len;
    1748  	    int n = 0;
    1749  
    1750  	    /* Workaround when FT_Get_Postscript_Name didn't give any name.
    1751  	     * try to find out the English family name and convert.
    1752  	     */
    1753  	    while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch)
    1754  	    {
    1755  		if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0)
    1756  		    break;
    1757  		n++;
    1758  		familylang = NULL;
    1759  	    }
    1760  	    if (!familylang)
    1761  		n = 0;
    1762  
    1763  	    if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch)
    1764  		goto bail1;
    1765  	    len = strlen ((const char *)family);
    1766  	    /* the literal name in PostScript Language is limited to 127 characters though,
    1767  	     * It is the architectural limit. so assuming 255 characters may works enough.
    1768  	     */
    1769  	    for (i = 0; i < len && i < 255; i++)
    1770  	    {
    1771  		/* those characters are not allowed to be the literal name in PostScript */
    1772  		static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n ";
    1773  
    1774  		if (strchr(exclusive_chars, family[i]) != NULL)
    1775  		    psname[i] = '-';
    1776  		else
    1777  		    psname[i] = family[i];
    1778  	    }
    1779  	    psname[i] = 0;
    1780  	}
    1781  	else
    1782  	{
    1783  	    strncpy (psname, tmp, 255);
    1784  	    psname[255] = 0;
    1785  	}
    1786  	if (!FcPatternObjectAddString (pat, FC_POSTSCRIPT_NAME_OBJECT, (const FcChar8 *)psname))
    1787  	    goto bail1;
    1788      }
    1789  
    1790      if (file && *file && !FcPatternObjectAddString (pat, FC_FILE_OBJECT, file))
    1791  	goto bail1;
    1792  
    1793      if (!FcPatternObjectAddInteger (pat, FC_INDEX_OBJECT, id))
    1794  	goto bail1;
    1795  
    1796  #if 0
    1797      /*
    1798       * don't even try this -- CJK 'monospace' fonts are really
    1799       * dual width, and most other fonts don't bother to set
    1800       * the attribute.  Sigh.
    1801       */
    1802      if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
    1803  	if (!FcPatternObjectAddInteger (pat, FC_SPACING_OBJECT, FC_MONO))
    1804  	    goto bail1;
    1805  #endif
    1806  
    1807      /*
    1808       * Find the font revision (if available)
    1809       */
    1810      head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
    1811      if (head)
    1812      {
    1813  	if (!FcPatternObjectAddInteger (pat, FC_FONTVERSION_OBJECT, head->Font_Revision))
    1814  	    goto bail1;
    1815      }
    1816      else
    1817      {
    1818  	if (!FcPatternObjectAddInteger (pat, FC_FONTVERSION_OBJECT, 0))
    1819  	    goto bail1;
    1820      }
    1821      if (!FcPatternObjectAddInteger (pat, FC_ORDER_OBJECT, 0))
    1822  	goto bail1;
    1823  
    1824      if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
    1825      {
    1826  	unsigned int i;
    1827  	for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
    1828  	{
    1829  	    FT_ULong	bits;
    1830  	    int		bit;
    1831  	    if (FcCodePageRange[i].bit < 32)
    1832  	    {
    1833  		bits = os2->ulCodePageRange1;
    1834  		bit = FcCodePageRange[i].bit;
    1835  	    }
    1836  	    else
    1837  	    {
    1838  		bits = os2->ulCodePageRange2;
    1839  		bit = FcCodePageRange[i].bit - 32;
    1840  	    }
    1841  	    if (bits & (1U << bit))
    1842  	    {
    1843  		/*
    1844  		 * If the font advertises support for multiple
    1845  		 * "exclusive" languages, then include support
    1846  		 * for any language found to have coverage
    1847  		 */
    1848  		if (exclusiveLang)
    1849  		{
    1850  		    exclusiveLang = 0;
    1851  		    break;
    1852  		}
    1853  		exclusiveLang = FcCodePageRange[i].lang;
    1854  	    }
    1855  	}
    1856      }
    1857  
    1858      if (os2 && os2->version != 0xffff)
    1859      {
    1860  	weight = os2->usWeightClass;
    1861  	weight = FcWeightFromOpenTypeDouble (weight * weight_mult);
    1862  	if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
    1863  	    printf ("\tos2 weight class %d multiplier %g maps to weight %g\n",
    1864  		    os2->usWeightClass, weight_mult, weight);
    1865  
    1866  	switch (os2->usWidthClass) {
    1867  	case 1:	width = FC_WIDTH_ULTRACONDENSED; break;
    1868  	case 2:	width = FC_WIDTH_EXTRACONDENSED; break;
    1869  	case 3:	width = FC_WIDTH_CONDENSED; break;
    1870  	case 4:	width = FC_WIDTH_SEMICONDENSED; break;
    1871  	case 5:	width = FC_WIDTH_NORMAL; break;
    1872  	case 6:	width = FC_WIDTH_SEMIEXPANDED; break;
    1873  	case 7:	width = FC_WIDTH_EXPANDED; break;
    1874  	case 8:	width = FC_WIDTH_EXTRAEXPANDED; break;
    1875  	case 9:	width = FC_WIDTH_ULTRAEXPANDED; break;
    1876  	}
    1877  	width *= width_mult;
    1878  	if ((FcDebug() & FC_DBG_SCANV) && width != -1)
    1879  	    printf ("\tos2 width class %d multiplier %g maps to width %g\n",
    1880  		    os2->usWidthClass, width_mult, width);
    1881      }
    1882      if (os2 && (complex_ = FcFontCapabilities(face)))
    1883      {
    1884  	if (!FcPatternObjectAddString (pat, FC_CAPABILITY_OBJECT, complex_))
    1885  	{
    1886  	    free (complex_);
    1887  	    goto bail1;
    1888  	}
    1889  	free (complex_);
    1890      }
    1891  
    1892      if (!FcPatternObjectAddBool (pat, FC_FONT_HAS_HINT_OBJECT, FcFontHasHint (face)))
    1893  	goto bail1;
    1894  
    1895      if (!variable_size && os2 && os2->version >= 0x0005 && os2->version != 0xffff)
    1896      {
    1897  	double lower_size, upper_size;
    1898  	FcRange *r;
    1899  
    1900  	/* usLowerPointSize and usUpperPointSize is actually twips */
    1901  	lower_size = os2->usLowerOpticalPointSize / 20.0L;
    1902  	upper_size = os2->usUpperOpticalPointSize / 20.0L;
    1903  
    1904  	if (lower_size == upper_size)
    1905  	{
    1906  	    if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, lower_size))
    1907  		goto bail1;
    1908  	}
    1909  	else
    1910  	{
    1911  	    r = FcRangeCreateDouble (lower_size, upper_size);
    1912  	    if (!FcPatternObjectAddRange (pat, FC_SIZE_OBJECT, r))
    1913  	    {
    1914  		FcRangeDestroy (r);
    1915  		goto bail1;
    1916  	    }
    1917  	    FcRangeDestroy (r);
    1918  	}
    1919      }
    1920  
    1921      /*
    1922       * Type 1: Check for FontInfo dictionary information
    1923       * Code from g2@magestudios.net (Gerard Escalante)
    1924       */
    1925  
    1926  #if HAVE_FT_GET_PS_FONT_INFO
    1927      if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
    1928      {
    1929  	if (weight == -1 && psfontinfo.weight)
    1930  	{
    1931  	    weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
    1932      	    if (FcDebug() & FC_DBG_SCANV)
    1933  		printf ("\tType1 weight %s maps to %g\n",
    1934  			psfontinfo.weight, weight);
    1935  	}
    1936  
    1937  #if 0
    1938  	/*
    1939  	 * Don't bother with italic_angle; FreeType already extracts that
    1940  	 * information for us and sticks it into style_flags
    1941  	 */
    1942          if (psfontinfo.italic_angle)
    1943              slant = FC_SLANT_ITALIC;
    1944          else
    1945              slant = FC_SLANT_ROMAN;
    1946  #endif
    1947  
    1948          if(!foundry)
    1949              foundry = FcNoticeFoundry(psfontinfo.notice);
    1950      }
    1951  #endif /* HAVE_FT_GET_PS_FONT_INFO */
    1952  
    1953  #if HAVE_FT_GET_BDF_PROPERTY
    1954      /*
    1955       * Finally, look for a FOUNDRY BDF property if no other
    1956       * mechanism has managed to locate a foundry
    1957       */
    1958  
    1959      if (!foundry)
    1960      {
    1961  	int             rc;
    1962  	rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
    1963  	if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
    1964  	    foundry = (FcChar8 *) prop.u.atom;
    1965      }
    1966  
    1967      if (width == -1)
    1968      {
    1969  	if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
    1970  	    (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
    1971  	     prop.type == BDF_PROPERTY_TYPE_CARDINAL))
    1972  	{
    1973  	    FT_Int32	value;
    1974  	
    1975  	    if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
    1976  		value = prop.u.integer;
    1977  	    else
    1978  		value = (FT_Int32) prop.u.cardinal;
    1979  	    switch ((value + 5) / 10) {
    1980  	    case 1: width = FC_WIDTH_ULTRACONDENSED; break;
    1981  	    case 2: width = FC_WIDTH_EXTRACONDENSED; break;
    1982  	    case 3: width = FC_WIDTH_CONDENSED; break;
    1983  	    case 4: width = FC_WIDTH_SEMICONDENSED; break;
    1984  	    case 5: width = FC_WIDTH_NORMAL; break;
    1985  	    case 6: width = FC_WIDTH_SEMIEXPANDED; break;
    1986  	    case 7: width = FC_WIDTH_EXPANDED; break;
    1987  	    case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
    1988  	    case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
    1989  	    }
    1990  	}
    1991  	if (width == -1 &&
    1992  	    FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
    1993  	    prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL)
    1994  	{
    1995  	    width = FcIsWidth ((FcChar8 *) prop.u.atom);
    1996  	    if (FcDebug () & FC_DBG_SCANV)
    1997  		printf ("\tsetwidth %s maps to %g\n", prop.u.atom, width);
    1998  	}
    1999      }
    2000  #endif
    2001  
    2002      /*
    2003       * Look for weight, width and slant names in the style value
    2004       */
    2005      for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
    2006      {
    2007  	if (weight == -1)
    2008  	{
    2009  	    weight = FcContainsWeight (style);
    2010  	    if (FcDebug() & FC_DBG_SCANV)
    2011  		printf ("\tStyle %s maps to weight %g\n", style, weight);
    2012  	}
    2013  	if (width == -1)
    2014  	{
    2015  	    width = FcContainsWidth (style);
    2016  	    if (FcDebug() & FC_DBG_SCANV)
    2017  		printf ("\tStyle %s maps to width %g\n", style, width);
    2018  	}
    2019  	if (slant == -1)
    2020  	{
    2021  	    slant = FcContainsSlant (style);
    2022  	    if (FcDebug() & FC_DBG_SCANV)
    2023  		printf ("\tStyle %s maps to slant %d\n", style, slant);
    2024  	}
    2025  	if (decorative == FcFalse)
    2026  	{
    2027  	    decorative = FcContainsDecorative (style) > 0;
    2028  	    if (FcDebug() & FC_DBG_SCANV)
    2029  		printf ("\tStyle %s maps to decorative %d\n", style, decorative);
    2030  	}
    2031      }
    2032      /*
    2033       * Pull default values from the FreeType flags if more
    2034       * specific values not found above
    2035       */
    2036      if (slant == -1)
    2037      {
    2038  	slant = FC_SLANT_ROMAN;
    2039  	if (face->style_flags & FT_STYLE_FLAG_ITALIC)
    2040  	    slant = FC_SLANT_ITALIC;
    2041      }
    2042  
    2043      if (weight == -1)
    2044      {
    2045  	weight = FC_WEIGHT_MEDIUM;
    2046  	if (face->style_flags & FT_STYLE_FLAG_BOLD)
    2047  	    weight = FC_WEIGHT_BOLD;
    2048      }
    2049  
    2050      if (width == -1)
    2051  	width = FC_WIDTH_NORMAL;
    2052  
    2053      if (foundry == 0)
    2054  	foundry = (FcChar8 *) "unknown";
    2055  
    2056      if (!FcPatternObjectAddInteger (pat, FC_SLANT_OBJECT, slant))
    2057  	goto bail1;
    2058  
    2059      if (!variable_weight && !FcPatternObjectAddDouble (pat, FC_WEIGHT_OBJECT, weight))
    2060  	goto bail1;
    2061  
    2062      if (!variable_width && !FcPatternObjectAddDouble (pat, FC_WIDTH_OBJECT, width))
    2063  	goto bail1;
    2064  
    2065      if (!FcPatternObjectAddString (pat, FC_FOUNDRY_OBJECT, foundry))
    2066  	goto bail1;
    2067  
    2068      if (!FcPatternObjectAddBool (pat, FC_DECORATIVE_OBJECT, decorative))
    2069  	goto bail1;
    2070  
    2071  
    2072      /*
    2073       * Compute the unicode coverage for the font
    2074       */
    2075      if (cs_share && *cs_share)
    2076  	cs = FcCharSetCopy (*cs_share);
    2077      else
    2078      {
    2079  	cs = FcFreeTypeCharSet (face, NULL);
    2080  	if (cs_share)
    2081  	    *cs_share = FcCharSetCopy (cs);
    2082      }
    2083      if (!cs)
    2084  	goto bail1;
    2085  
    2086      /* The FcFreeTypeCharSet() chose the encoding; test it for symbol. */
    2087      symbol = face->charmap && face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
    2088      if (!FcPatternObjectAddBool (pat, FC_SYMBOL_OBJECT, symbol))
    2089  	goto bail1;
    2090  
    2091      spacing = FcFreeTypeSpacing (face);
    2092  #if HAVE_FT_GET_BDF_PROPERTY
    2093      /* For PCF fonts, override the computed spacing with the one from
    2094         the property */
    2095      if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
    2096         prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL) {
    2097          if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
    2098              spacing = FC_CHARCELL;
    2099          else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
    2100              spacing = FC_MONO;
    2101          else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
    2102              spacing = FC_PROPORTIONAL;
    2103      }
    2104  #endif
    2105  
    2106      /*
    2107       * Skip over PCF fonts that have no encoded characters; they're
    2108       * usually just Unicode fonts transcoded to some legacy encoding
    2109       * FT forces us to approximate whether a font is a PCF font
    2110       * or not by whether it has any BDF properties.  Try PIXEL_SIZE;
    2111       * I don't know how to get a list of BDF properties on the font. -PL
    2112       */
    2113      if (FcCharSetCount (cs) == 0)
    2114      {
    2115  #if HAVE_FT_GET_BDF_PROPERTY
    2116  	if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
    2117  	    goto bail2;
    2118  #endif
    2119      }
    2120  
    2121      if (!FcPatternObjectAddCharSet (pat, FC_CHARSET_OBJECT, cs))
    2122  	goto bail2;
    2123  
    2124      if (!symbol)
    2125      {
    2126  	if (ls_share && *ls_share)
    2127  	    ls = FcLangSetCopy (*ls_share);
    2128  	else
    2129  	{
    2130  	    ls = FcFreeTypeLangSet (cs, exclusiveLang);
    2131  	    if (ls_share)
    2132  		*ls_share = FcLangSetCopy (ls);
    2133  	}
    2134  	if (!ls)
    2135  	    goto bail2;
    2136      }
    2137      else
    2138      {
    2139  	/* Symbol fonts don't cover any language, even though they
    2140  	 * claim to support Latin1 range. */
    2141  	ls = FcLangSetCreate ();
    2142      }
    2143  
    2144      if (!FcPatternObjectAddLangSet (pat, FC_LANG_OBJECT, ls))
    2145      {
    2146  	FcLangSetDestroy (ls);
    2147  	goto bail2;
    2148      }
    2149  
    2150      FcLangSetDestroy (ls);
    2151  
    2152      if (spacing != FC_PROPORTIONAL)
    2153  	if (!FcPatternObjectAddInteger (pat, FC_SPACING_OBJECT, spacing))
    2154  	    goto bail2;
    2155  
    2156      if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
    2157      {
    2158  	int i;
    2159  	for (i = 0; i < face->num_fixed_sizes; i++)
    2160  	    if (!FcPatternObjectAddDouble (pat, FC_PIXEL_SIZE_OBJECT,
    2161  					   FcGetPixelSize (face, i)))
    2162  		goto bail2;
    2163  	if (!FcPatternObjectAddBool (pat, FC_ANTIALIAS_OBJECT, FcFalse))
    2164  	    goto bail2;
    2165      }
    2166  #if HAVE_FT_GET_X11_FONT_FORMAT
    2167      /*
    2168       * Use the (not well documented or supported) X-specific function
    2169       * from FreeType to figure out the font format
    2170       */
    2171      {
    2172  	const char *font_format = FT_Get_X11_Font_Format (face);
    2173  	if (font_format)
    2174  	    if (!FcPatternObjectAddString (pat, FC_FONTFORMAT_OBJECT, (FcChar8 *) font_format))
    2175  		goto bail2;
    2176      }
    2177  #endif
    2178  
    2179      /*
    2180       * Drop our reference to the charset
    2181       */
    2182      FcCharSetDestroy (cs);
    2183      if (foundry_)
    2184  	free (foundry_);
    2185  
    2186      if (master)
    2187      {
    2188  #ifdef HAVE_FT_DONE_MM_VAR
    2189  	if (face->glyph)
    2190  	    FT_Done_MM_Var (face->glyph->library, master);
    2191  #else
    2192  	free (master);
    2193  #endif
    2194      }
    2195  
    2196      return pat;
    2197  
    2198  bail2:
    2199      FcCharSetDestroy (cs);
    2200  bail1:
    2201      FcPatternDestroy (pat);
    2202      if (master)
    2203      {
    2204  #ifdef HAVE_FT_DONE_MM_VAR
    2205  	if (face->glyph)
    2206  	    FT_Done_MM_Var (face->glyph->library, master);
    2207  #else
    2208  	free (master);
    2209  #endif
    2210      }
    2211      if (!nm_share && name_mapping)
    2212  	free (name_mapping);
    2213      if (foundry_)
    2214  	free (foundry_);
    2215  bail0:
    2216      return NULL;
    2217  }
    2218  
    2219  FcPattern *
    2220  FcFreeTypeQueryFace (const FT_Face  face,
    2221  		     const FcChar8  *file,
    2222  		     unsigned int   id,
    2223  		     FcBlanks	    *blanks FC_UNUSED)
    2224  {
    2225      return FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL, NULL);
    2226  }
    2227  
    2228  FcPattern *
    2229  FcFreeTypeQuery(const FcChar8	*file,
    2230  		unsigned int	id,
    2231  		FcBlanks	*blanks FC_UNUSED,
    2232  		int		*count)
    2233  {
    2234      FT_Face	    face;
    2235      FT_Library	    ftLibrary;
    2236      FcPattern	    *pat = NULL;
    2237  
    2238      if (FT_Init_FreeType (&ftLibrary))
    2239  	return NULL;
    2240  
    2241      if (FT_New_Face (ftLibrary, (char *) file, id & 0x7FFFFFFF, &face))
    2242  	goto bail;
    2243  
    2244      if (count)
    2245        *count = face->num_faces;
    2246  
    2247      pat = FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL, NULL);
    2248  
    2249      FT_Done_Face (face);
    2250  bail:
    2251      FT_Done_FreeType (ftLibrary);
    2252      return pat;
    2253  }
    2254  
    2255  unsigned int
    2256  FcFreeTypeQueryAll(const FcChar8	*file,
    2257  		   unsigned int		id,
    2258  		   FcBlanks		*blanks,
    2259  		   int			*count,
    2260  		   FcFontSet            *set)
    2261  {
    2262      FT_Face face = NULL;
    2263      FT_Library ftLibrary = NULL;
    2264      FcCharSet *cs = NULL;
    2265      FcLangSet *ls = NULL;
    2266      FcNameMapping  *nm = NULL;
    2267      FT_MM_Var *mm_var = NULL;
    2268      FcBool index_set = id != (unsigned int) -1;
    2269      unsigned int set_face_num = index_set ? id & 0xFFFF : 0;
    2270      unsigned int set_instance_num = index_set ? id >> 16 : 0;
    2271      unsigned int face_num = set_face_num;
    2272      unsigned int instance_num = set_instance_num;
    2273      unsigned int num_faces = 0;
    2274      unsigned int num_instances = 0;
    2275      unsigned int ret = 0;
    2276      int err = 0;
    2277  
    2278      if (count)
    2279  	*count = 0;
    2280  
    2281      if (FT_Init_FreeType (&ftLibrary))
    2282  	return 0;
    2283  
    2284      if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
    2285  	goto bail;
    2286  
    2287      num_faces = face->num_faces;
    2288      num_instances = face->style_flags >> 16;
    2289      if (num_instances && (!index_set || instance_num))
    2290      {
    2291  	FT_Get_MM_Var (face, &mm_var);
    2292  	if (!mm_var)
    2293  	  num_instances = 0;
    2294      }
    2295  
    2296      if (count)
    2297        *count = num_faces;
    2298  
    2299      do {
    2300  	FcPattern *pat = NULL;
    2301  
    2302  	if (instance_num == 0x8000 || instance_num > num_instances)
    2303  	    FT_Set_Var_Design_Coordinates (face, 0, NULL); /* Reset variations. */
    2304  	else if (instance_num)
    2305  	{
    2306  	    FT_Var_Named_Style *instance = &mm_var->namedstyle[instance_num - 1];
    2307  	    FT_Fixed *coords = instance->coords;
    2308  	    FcBool nonzero;
    2309  	    unsigned int i;
    2310  
    2311  	    /* Skip named-instance that coincides with base instance. */
    2312  	    nonzero = FcFalse;
    2313  	    for (i = 0; i < mm_var->num_axis; i++)
    2314  		if (coords[i] != mm_var->axis[i].def)
    2315  		{
    2316  		    nonzero = FcTrue;
    2317  		    break;
    2318  		}
    2319  	    if (!nonzero)
    2320  		goto skip;
    2321  
    2322  	    FT_Set_Var_Design_Coordinates (face, mm_var->num_axis, coords);
    2323  	}
    2324  
    2325  	id = ((instance_num << 16) + face_num);
    2326  	pat = FcFreeTypeQueryFaceInternal (face, (const FcChar8 *) file, id, &cs, &ls, &nm);
    2327  
    2328  	if (pat)
    2329  	{
    2330  
    2331  	    ret++;
    2332  	    if (!set || ! FcFontSetAdd (set, pat))
    2333  		FcPatternDestroy (pat);
    2334  	}
    2335  	else if (instance_num != 0x8000)
    2336  	    err = 1;
    2337  
    2338  skip:
    2339  	if (!index_set && instance_num < num_instances)
    2340  	    instance_num++;
    2341  	else if (!index_set && instance_num == num_instances)
    2342  	    instance_num = 0x8000; /* variable font */
    2343  	else
    2344  	{
    2345  	    free (nm);
    2346  	    nm = NULL;
    2347  	    FcLangSetDestroy (ls);
    2348  	    ls = NULL;
    2349  	    FcCharSetDestroy (cs);
    2350  	    cs = NULL;
    2351  	    FT_Done_Face (face);
    2352  	    face = NULL;
    2353  
    2354  	    face_num++;
    2355  	    instance_num = set_instance_num;
    2356  
    2357  	    if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
    2358  	      break;
    2359  	}
    2360      } while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces);
    2361  
    2362  bail:
    2363  #ifdef HAVE_FT_DONE_MM_VAR
    2364      FT_Done_MM_Var (ftLibrary, mm_var);
    2365  #else
    2366      free (mm_var);
    2367  #endif
    2368      FcLangSetDestroy (ls);
    2369      FcCharSetDestroy (cs);
    2370      if (face)
    2371  	FT_Done_Face (face);
    2372      FT_Done_FreeType (ftLibrary);
    2373      if (nm)
    2374  	free (nm);
    2375  
    2376      return ret;
    2377  }
    2378  
    2379  
    2380  static const FT_Encoding fcFontEncodings[] = {
    2381      FT_ENCODING_UNICODE,
    2382      FT_ENCODING_MS_SYMBOL
    2383  };
    2384  
    2385  #define NUM_DECODE  (int) (sizeof (fcFontEncodings) / sizeof (fcFontEncodings[0]))
    2386  
    2387  /*
    2388   * Map a UCS4 glyph to a glyph index.  Use all available encoding
    2389   * tables to try and find one that works.  This information is expected
    2390   * to be cached by higher levels, so performance isn't critical
    2391   */
    2392  
    2393  FT_UInt
    2394  FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
    2395  {
    2396      int		    initial, offset, decode;
    2397      FT_UInt	    glyphindex;
    2398  
    2399      initial = 0;
    2400  
    2401      if (!face)
    2402          return 0;
    2403  
    2404      /*
    2405       * Find the current encoding
    2406       */
    2407      if (face->charmap)
    2408      {
    2409  	for (; initial < NUM_DECODE; initial++)
    2410  	    if (fcFontEncodings[initial] == face->charmap->encoding)
    2411  		break;
    2412  	if (initial == NUM_DECODE)
    2413  	    initial = 0;
    2414      }
    2415      /*
    2416       * Check each encoding for the glyph, starting with the current one
    2417       */
    2418      for (offset = 0; offset < NUM_DECODE; offset++)
    2419      {
    2420  	decode = (initial + offset) % NUM_DECODE;
    2421  	if (!face->charmap || face->charmap->encoding != fcFontEncodings[decode])
    2422  	    if (FT_Select_Charmap (face, fcFontEncodings[decode]) != 0)
    2423  		continue;
    2424  	glyphindex = FT_Get_Char_Index (face, (FT_ULong) ucs4);
    2425  	if (glyphindex)
    2426  	    return glyphindex;
    2427  	if (ucs4 < 0x100 && face->charmap &&
    2428  	    face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
    2429  	{
    2430  	    /* For symbol-encoded OpenType fonts, we duplicate the
    2431  	     * U+F000..F0FF range at U+0000..U+00FF.  That's what
    2432  	     * Windows seems to do, and that's hinted about at:
    2433  	     * http://www.microsoft.com/typography/otspec/recom.htm
    2434  	     * under "Non-Standard (Symbol) Fonts".
    2435  	     *
    2436  	     * See thread with subject "Webdings and other MS symbol
    2437  	     * fonts don't display" on mailing list from May 2015.
    2438  	     */
    2439  	    glyphindex = FT_Get_Char_Index (face, (FT_ULong) ucs4 + 0xF000);
    2440  	    if (glyphindex)
    2441  		return glyphindex;
    2442  	}
    2443      }
    2444      return 0;
    2445  }
    2446  
    2447  static inline int fc_min (int a, int b) { return a <= b ? a : b; }
    2448  static inline int fc_max (int a, int b) { return a >= b ? a : b; }
    2449  static inline FcBool fc_approximately_equal (int x, int y)
    2450  { return abs (x - y) * 33 <= fc_max (abs (x), abs (y)); }
    2451  
    2452  static int
    2453  FcFreeTypeSpacing (FT_Face face)
    2454  {
    2455      FT_Int	    load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
    2456      FT_Pos	    advances[3] = {0};
    2457      unsigned int    num_advances = 0;
    2458      int		    o;
    2459  
    2460      /* When using scalable fonts, only report those glyphs
    2461       * which can be scaled; otherwise those fonts will
    2462       * only be available at some sizes, and never when
    2463       * transformed.  Avoid this by simply reporting bitmap-only
    2464       * glyphs as missing
    2465       */
    2466      if (face->face_flags & FT_FACE_FLAG_SCALABLE)
    2467  	load_flags |= FT_LOAD_NO_BITMAP;
    2468  
    2469      if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
    2470  	face->num_fixed_sizes > 0 &&
    2471  	FT_Get_Sfnt_Table (face, ft_sfnt_head))
    2472      {
    2473  	FT_Int strike_index = 0, i;
    2474  	/* Select the face closest to 16 pixels tall */
    2475  	for (i = 1; i < face->num_fixed_sizes; i++)
    2476  	{
    2477  	    if (abs (face->available_sizes[i].height - 16) <
    2478  		abs (face->available_sizes[strike_index].height - 16))
    2479  		strike_index = i;
    2480  	}
    2481  
    2482  	FT_Select_Size (face, strike_index);
    2483      }
    2484  
    2485      for (o = 0; o < NUM_DECODE; o++)
    2486      {
    2487  	FcChar32        ucs4;
    2488  	FT_UInt	 	glyph;
    2489  
    2490  	if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
    2491  	    continue;
    2492  
    2493  	ucs4 = FT_Get_First_Char (face, &glyph);
    2494  	while (glyph != 0 && num_advances < 3)
    2495  	{
    2496  	    FT_Pos advance = 0;
    2497  	    if (!FT_Get_Advance (face, glyph, load_flags, &advance) && advance)
    2498  	    {
    2499  		unsigned int j;
    2500  		for (j = 0; j < num_advances; j++)
    2501  		  if (fc_approximately_equal (advance, advances[j]))
    2502  		    break;
    2503  		if (j == num_advances)
    2504  		  advances[num_advances++] = advance;
    2505  	    }
    2506  
    2507  	    ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
    2508  	}
    2509  	break;
    2510      }
    2511  
    2512      if (num_advances <= 1)
    2513  	return FC_MONO;
    2514      else if (num_advances == 2 &&
    2515  	     fc_approximately_equal (fc_min (advances[0], advances[1]) * 2,
    2516  				     fc_max (advances[0], advances[1])))
    2517  	return FC_DUAL;
    2518      else
    2519  	return FC_PROPORTIONAL;
    2520  }
    2521  
    2522  FcCharSet *
    2523  FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED)
    2524  {
    2525      const FT_Int    load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
    2526      FcCharSet	    *fcs;
    2527      int		    o;
    2528  
    2529      fcs = FcCharSetCreate ();
    2530      if (!fcs)
    2531  	goto bail;
    2532  
    2533  #ifdef CHECK
    2534      printf ("Family %s style %s\n", face->family_name, face->style_name);
    2535  #endif
    2536      for (o = 0; o < NUM_DECODE; o++)
    2537      {
    2538  	FcChar32        page, off, ucs4;
    2539  	FcCharLeaf      *leaf;
    2540  	FT_UInt	 	glyph;
    2541  
    2542  	if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
    2543  	    continue;
    2544  
    2545  	page = ~0;
    2546  	leaf = NULL;
    2547  	ucs4 = FT_Get_First_Char (face, &glyph);
    2548  	while (glyph != 0)
    2549  	{
    2550  	    FcBool good = FcTrue;
    2551  
    2552  	    /* CID fonts built by Adobe used to make ASCII control chars to cid1
    2553  	     * (space glyph). As such, always check contour for those characters. */
    2554  	    if (ucs4 <= 0x001F)
    2555  	    {
    2556  		if (FT_Load_Glyph (face, glyph, load_flags) ||
    2557  		    (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
    2558  		     face->glyph->outline.n_contours == 0))
    2559  		    good = FcFalse;
    2560  	    }
    2561  
    2562  	    if (good)
    2563  	    {
    2564  		FcCharSetAddChar (fcs, ucs4);
    2565  		if ((ucs4 >> 8) != page)
    2566  		{
    2567  		    page = (ucs4 >> 8);
    2568  		    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
    2569  		    if (!leaf)
    2570  			goto bail;
    2571  		}
    2572  		off = ucs4 & 0xff;
    2573  		leaf->map[off >> 5] |= (1U << (off & 0x1f));
    2574  	    }
    2575  
    2576  	    ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
    2577  	}
    2578  	if (fcFontEncodings[o] == FT_ENCODING_MS_SYMBOL)
    2579  	{
    2580  	    /* For symbol-encoded OpenType fonts, we duplicate the
    2581  	     * U+F000..F0FF range at U+0000..U+00FF.  That's what
    2582  	     * Windows seems to do, and that's hinted about at:
    2583  	     * http://www.microsoft.com/typography/otspec/recom.htm
    2584  	     * under "Non-Standard (Symbol) Fonts".
    2585  	     *
    2586  	     * See thread with subject "Webdings and other MS symbol
    2587  	     * fonts don't display" on mailing list from May 2015.
    2588  	     */
    2589  	    for (ucs4 = 0xF000; ucs4 < 0xF100; ucs4++)
    2590  	    {
    2591  		if (FcCharSetHasChar (fcs, ucs4))
    2592  		    FcCharSetAddChar (fcs, ucs4 - 0xF000);
    2593  	    }
    2594  	}
    2595  #ifdef CHECK
    2596  	for (ucs4 = 0x0020; ucs4 < 0x10000; ucs4++)
    2597  	{
    2598  	    FcBool	    FT_Has, FC_Has;
    2599  
    2600  	    FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
    2601  	    FC_Has = FcCharSetHasChar (fcs, ucs4);
    2602  	    if (FT_Has != FC_Has)
    2603  	    {
    2604  		printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
    2605  	    }
    2606  	}
    2607  #endif
    2608  	break;
    2609      }
    2610  
    2611      return fcs;
    2612  bail:
    2613      FcCharSetDestroy (fcs);
    2614      return 0;
    2615  }
    2616  
    2617  FcCharSet *
    2618  FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing)
    2619  {
    2620  
    2621      if (spacing)
    2622  	*spacing = FcFreeTypeSpacing (face);
    2623  
    2624      return FcFreeTypeCharSet (face, blanks);
    2625  }
    2626  
    2627  
    2628  #define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
    2629  #define TTAG_GSUB  FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
    2630  #define TTAG_SILF  FT_MAKE_TAG( 'S', 'i', 'l', 'f')
    2631  #define TTAG_prep  FT_MAKE_TAG( 'p', 'r', 'e', 'p' )
    2632  
    2633  #define OTLAYOUT_HEAD	    "otlayout:"
    2634  #define OTLAYOUT_HEAD_LEN   9
    2635  #define OTLAYOUT_ID_LEN	    4
    2636  /* space + head + id */
    2637  #define OTLAYOUT_LEN	    (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
    2638  
    2639  /*
    2640   * This is a bit generous; the registry has only lower case and space
    2641   * except for 'DFLT'.
    2642   */
    2643  #define FcIsSpace(x)	    (040 == (x))
    2644  #define FcIsDigit(c)	    (('0' <= (c) && (c) <= '9'))
    2645  #define FcIsValidScript(x)  (FcIsLower(x) || FcIsUpper (x) || FcIsDigit(x) || FcIsSpace(x))
    2646  			
    2647  static void
    2648  addtag(FcChar8 *complex_, FT_ULong tag)
    2649  {
    2650      FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
    2651  
    2652      tagstring[0] = (FcChar8)(tag >> 24),
    2653      tagstring[1] = (FcChar8)(tag >> 16),
    2654      tagstring[2] = (FcChar8)(tag >> 8),
    2655      tagstring[3] = (FcChar8)(tag);
    2656      tagstring[4] = '\0';
    2657  
    2658      /* skip tags which aren't alphanumeric, under the assumption that
    2659       * they're probably broken
    2660       */
    2661      if (!FcIsValidScript(tagstring[0]) ||
    2662  	!FcIsValidScript(tagstring[1]) ||
    2663  	!FcIsValidScript(tagstring[2]) ||
    2664  	!FcIsValidScript(tagstring[3]))
    2665  	return;
    2666  
    2667      if (*complex_ != '\0')
    2668  	strcat ((char *) complex_, " ");
    2669      strcat ((char *) complex_, OTLAYOUT_HEAD);
    2670      strcat ((char *) complex_, (char *) tagstring);
    2671  }
    2672  
    2673  static int
    2674  compareulong (const void *a, const void *b)
    2675  {
    2676      const FT_ULong *ua = (const FT_ULong *) a;
    2677      const FT_ULong *ub = (const FT_ULong *) b;
    2678      return *ua - *ub;
    2679  }
    2680  
    2681  static FcBool
    2682  FindTable (FT_Face face, FT_ULong tabletag)
    2683  {
    2684      FT_Stream  stream = face->stream;
    2685      FT_Error   error;
    2686  
    2687      if (!stream)
    2688          return FcFalse;
    2689  
    2690      if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
    2691  	return FcFalse;
    2692  
    2693      return FcTrue;
    2694  }
    2695  
    2696  static int
    2697  GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
    2698  {
    2699      FT_ULong   cur_offset, new_offset, base_offset;
    2700      FT_Stream  stream = face->stream;
    2701      FT_Error   error;
    2702      FT_UShort  n, p;
    2703      int        script_count;
    2704  
    2705      if (!stream)
    2706          return 0;
    2707  
    2708      if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
    2709  	return 0;
    2710  
    2711      base_offset = ftglue_stream_pos ( stream );
    2712  
    2713      /* skip version */
    2714  
    2715      if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
    2716  	return 0;
    2717  
    2718      new_offset = GET_UShort() + base_offset;
    2719  
    2720      ftglue_stream_frame_exit( stream );
    2721  
    2722      cur_offset = ftglue_stream_pos( stream );
    2723  
    2724      if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
    2725  	return 0;
    2726  
    2727      base_offset = ftglue_stream_pos( stream );
    2728  
    2729      if ( ftglue_stream_frame_enter( stream, 2L ) )
    2730  	return 0;
    2731  
    2732      script_count = GET_UShort ();
    2733  
    2734      ftglue_stream_frame_exit( stream );
    2735  
    2736      *stags = malloc(script_count * sizeof (FT_ULong));
    2737      if (!*stags)
    2738  	return 0;
    2739  
    2740      p = 0;
    2741      for ( n = 0; n < script_count; n++ )
    2742      {
    2743          if ( ftglue_stream_frame_enter( stream, 6L ) )
    2744  	    goto Fail;
    2745  
    2746  	(*stags)[p] = GET_ULong ();
    2747  	new_offset = GET_UShort () + base_offset;
    2748  
    2749          ftglue_stream_frame_exit( stream );
    2750  
    2751  	cur_offset = ftglue_stream_pos( stream );
    2752  
    2753  	error = ftglue_stream_seek( stream, new_offset );
    2754  
    2755  	if ( error == FT_Err_Ok )
    2756  	    p++;
    2757  
    2758  	(void)ftglue_stream_seek( stream, cur_offset );
    2759      }
    2760  
    2761      if (!p)
    2762  	goto Fail;
    2763  
    2764      /* sort the tag list before returning it */
    2765      qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
    2766  
    2767      return script_count;
    2768  
    2769  Fail:
    2770      free(*stags);
    2771      *stags = NULL;
    2772      return 0;
    2773  }
    2774  
    2775  static FcChar8 *
    2776  FcFontCapabilities(FT_Face face)
    2777  {
    2778      FcBool issilgraphitefont = 0;
    2779      FT_Error err;
    2780      FT_ULong len = 0;
    2781      FT_ULong *gsubtags=NULL, *gpostags=NULL;
    2782      FT_UShort gsub_count=0, gpos_count=0;
    2783      FT_ULong maxsize;
    2784      FcChar8 *complex_ = NULL;
    2785      int indx1 = 0, indx2 = 0;
    2786  
    2787      err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
    2788      issilgraphitefont = ( err == FT_Err_Ok);
    2789  
    2790      gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
    2791      gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
    2792  
    2793      if (!issilgraphitefont && !gsub_count && !gpos_count)
    2794      	goto bail;
    2795  
    2796      maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
    2797  	       (issilgraphitefont ? 13 : 0));
    2798      complex_ = malloc (sizeof (FcChar8) * maxsize);
    2799      if (!complex_)
    2800  	goto bail;
    2801  
    2802      complex_[0] = '\0';
    2803      if (issilgraphitefont)
    2804          strcpy((char *) complex_, "ttable:Silf ");
    2805  
    2806      while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
    2807  	if (indx1 == gsub_count) {
    2808  	    addtag(complex_, gpostags[indx2]);
    2809  	    indx2++;
    2810  	} else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
    2811  	    addtag(complex_, gsubtags[indx1]);
    2812  	    indx1++;
    2813  	} else if (gsubtags[indx1] == gpostags[indx2]) {
    2814  	    addtag(complex_, gsubtags[indx1]);
    2815  	    indx1++;
    2816  	    indx2++;
    2817  	} else {
    2818  	    addtag(complex_, gpostags[indx2]);
    2819  	    indx2++;
    2820  	}
    2821      }
    2822      if (FcDebug () & FC_DBG_SCANV)
    2823  	printf("complex_ features in this font: %s\n", complex_);
    2824  bail:
    2825      free(gsubtags);
    2826      free(gpostags);
    2827      return complex_;
    2828  }
    2829  
    2830  static FcBool
    2831  FcFontHasHint (FT_Face face)
    2832  {
    2833      return FindTable (face, TTAG_prep);
    2834  }
    2835  
    2836  
    2837  #define __fcfreetype__
    2838  #include "fcaliastail.h"
    2839  #include "fcftaliastail.h"
    2840  #undef __fcfreetype__