From 4f27c1c0a383e891890ab27c74226957ed7067aa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 4 Dec 2004 19:41:10 +0000 Subject: [PATCH] Move existing fonts.conf to fonts.conf.bak Add detection of iconv Document new selectfont elements Switch to UTF-8 in comment Add fullname, and family/style/fullname language entries Respect selectfont/*/glob Add support for selectfont Add multi-lingual family/style/fullname support Expose FcListPatternMatchAny (which selectfont/*/pattern uses) Add new FcPatternRemove/FcPatternAppend. FcObjectStaticName stores computed pattern element names which are required to be static. --- ChangeLog | 47 ++ Makefile.am | 13 +- configure.in | 6 +- doc/fcpattern.fncs | 11 + doc/fontconfig-devel.sgml | 13 +- doc/fontconfig-user.sgml | 43 +- fc-lang/nb.orth | 2 +- fontconfig/fontconfig.h | 7 + fonts.dtd | 19 + src/fccache.c | 2 +- src/fccfg.c | 55 +- src/fcdir.c | 2 +- src/fcfreetype.c | 1085 +++++++++++++++++++++++++++---------- src/fcint.h | 21 + src/fclist.c | 6 +- src/fcname.c | 4 + src/fcpat.c | 73 +++ src/fcxml.c | 162 ++++++ 18 files changed, 1282 insertions(+), 289 deletions(-) diff --git a/ChangeLog b/ChangeLog index b9c22c2..3d98cab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,50 @@ +2004-12-04 Keith Packard + + * Makefile.am: + Move existing fonts.conf to fonts.conf.bak + + * configure.in: + Add detection of iconv + + * doc/fcpattern.fncs: + * doc/fontconfig-devel.sgml: + * doc/fontconfig-user.sgml: + * fonts.dtd: + Document new selectfont elements + + * fc-lang/nb.orth: + Switch to UTF-8 in comment + + * fontconfig/fontconfig.h: + * src/fcname.c: + Add fullname, and family/style/fullname language entries + + * src/fccache.c: (FcCacheFontSetAdd): + * src/fcdir.c: (FcFileScanConfig): + Respect selectfont/*/glob + + * src/fcint.h: + * src/fccfg.c: (FcConfigCreate), (FcConfigDestroy), + (FcConfigCompareValue), (FcConfigPatternsAdd), + (FcConfigPatternsMatch), (FcConfigAcceptFont): + * src/fcxml.c: (FcElementMap), (FcVStackDestroy), + (FcVStackPushPattern), (FcPopExpr), (FcParseAcceptRejectFont), + (FcPopValue), (FcParsePatelt), (FcParsePattern), (FcEndElement): + Add support for selectfont + + * src/fcfreetype.c: (FcSfntNameTranscode), (FcSfntNameLanguage), + (FcStringInPatternElement), (FcFreeTypeQuery): + Add multi-lingual family/style/fullname support + + * src/fclist.c: (FcListPatternMatchAny): + Expose FcListPatternMatchAny (which selectfont/*/pattern uses) + + * src/fcpat.c: (FcPatternRemove), (FcPatternAppend), + (FcObjectStaticName): + Add new FcPatternRemove/FcPatternAppend. + FcObjectStaticName stores computed pattern element names which + are required to be static. + 2004-09-09 "NAKAMURA Ken'ichi" reviewed by: keithp diff --git a/Makefile.am b/Makefile.am index 8de5069..c1e48a1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,10 +37,21 @@ pkgconfigdir=$(libdir)/pkgconfig pkgconfig_DATA = fontconfig.pc configdir=$(CONFDIR) -config_DATA=fonts.conf fonts.dtd +config_DATA=fonts.dtd install-data-local: $(mkinstalldirs) $(DESTDIR)$(configdir) + if [ -f $(DESTDIR)$(configdir)/fonts.conf ]; then \ + echo "backing up existing $(DESTDIR)$(configdir)/fonts.conf"; \ + mv $(DESTDIR)$(configdir)/fonts.conf $(DESTDIR)$(configdir)/fonts.conf.bak; \ + fi + if [ -f $(srcdir)/fonts.conf ]; then \ + echo " $(INSTALL_DATA) $(srcdir)/fonts.conf $(DESTDIR)$(configdir)/fonts.conf"; \ + $(INSTALL_DATA) $(srcdir)/fonts.conf $(DESTDIR)$(configdir)/fonts.conf; \ + else if [ -f fonts.conf ]; then \ + echo " $(INSTALL_DATA) fonts.conf $(DESTDIR)$(configdir)/fonts.conf"; \ + $(INSTALL_DATA) fonts.conf $(DESTDIR)$(configdir)/fonts.conf; \ + fi; fi if [ -f $(DESTDIR)$(configdir)/local.conf ]; then \ echo "not overwriting existing $(DESTDIR)$(configdir)/local.conf"; \ else if [ -f $(srcdir)/local.conf ]; then \ diff --git a/configure.in b/configure.in index 604d56e..71f6742 100644 --- a/configure.in +++ b/configure.in @@ -91,7 +91,7 @@ dnl ========================================================================== # Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC -AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) +AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h iconv.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -99,7 +99,7 @@ AC_TYPE_PID_T # Checks for library functions. AC_FUNC_VPRINTF -AC_CHECK_FUNCS([geteuid getuid link memmove memset mkstemp strchr strrchr strtol getopt getopt_long]) +AC_CHECK_FUNCS([geteuid getuid link memmove memset mkstemp strchr strrchr strtol getopt getopt_long iconv]) # # Checks for FreeType @@ -324,7 +324,7 @@ esac AC_SUBST(FC_FONTPATH) -FC_FONTDATE=`date` +FC_FONTDATE=`LC_ALL=C date` AC_SUBST(FC_FONTDATE) diff --git a/doc/fcpattern.fncs b/doc/fcpattern.fncs index 4011a26..177bd9b 100644 --- a/doc/fcpattern.fncs +++ b/doc/fcpattern.fncs @@ -262,6 +262,17 @@ Deletes all values associated with the property `object', returning whether the property existed or not. @@ +@RET@ FcBool +@FUNC@ FcPatternRemove +@TYPE1@ FcPattern * @ARG1@ p +@TYPE2@ const char * @ARG2@ object +@TYPE3@ int @ARG3@ id +@PURPOSE@ Remove one object of the specified type from the pattern +@DESC@ +Removes the value associated with the property `object' at position `id', returning +whether the property existed and had a value at that position or not. +@@ + @RET@ void @FUNC@ FcPatternPrint @TYPE1@ const FcPattern * @ARG1@ p diff --git a/doc/fontconfig-devel.sgml b/doc/fontconfig-devel.sgml index b2fd21c..a989388 100644 --- a/doc/fontconfig-devel.sgml +++ b/doc/fontconfig-devel.sgml @@ -127,11 +127,20 @@ convenience for the applications rendering mechanism. Property Definitions - Property CPP Symbol Type Description + Property CPP Symbol Type Description ---------------------------------------------------- - family FC_FAMILY String Font family name + family FC_FAMILY String Font family names + familylang FC_FAMILYLANG String Language cooresponding to + each family name style FC_STYLE String Font style. Overrides weight and slant + stylelang FC_STYLELANG String Language cooresponding to + each style name + fullname FC_FULLNAME String Font face full name where + different from family and + family + style + fullnamelang FC_FULLNAMELANG String Language cooresponding to + each fullname slant FC_SLANT Int Italic, oblique or roman weight FC_WEIGHT Int Light, medium, demibold, bold or black diff --git a/doc/fontconfig-user.sgml b/doc/fontconfig-user.sgml index 60dc31d..ca0f9b7 100644 --- a/doc/fontconfig-user.sgml +++ b/doc/fontconfig-user.sgml @@ -91,8 +91,12 @@ convenience for the applications rendering mechanism. Property Type Description -------------------------------------------------------------- - family String Font family name + family String Font family names + familylang String Languages cooresponding to each family style String Font style. Overrides weight and slant + stylelang String Languages cooresponding to each style + fullname String Font full names (often includes style) + fullnamelang String Languages cooresponding to each fullname slant Int Italic, oblique or roman weight Int Light, medium, demibold, bold or black size Double Point size @@ -283,6 +287,43 @@ The rescan element holds an int element which indicates interval between automatic checks for font configuration changes. Fontconfig will validate all of the configuration files and directories and automatically rebuild the internal datastructures when this interval passes. + + <sgmltag>selectfont</> +This element is used to black/white list fonts from being listed or matched +against. It holds acceptfont and rejectfont elements. + + <sgmltag>acceptfont</> +Fonts matched by an acceptfont element are "whitelisted"; such fonts are +explicitly included in the set of fonts used to resolve list and match +requests; including them in this list protects them from being "blacklisted" +by a rejectfont element. Acceptfont elements include glob and pattern +elements which are used to match fonts. + + <sgmltag>rejectfont</> +Fonts matched by an rejectfont element are "blacklisted"; such fonts are +excluded from the set of fonts used to resolve list and match requests as if +they didn't exist in the system. Rejectfont elements include glob and +pattern elements which are used to match fonts. + + <sgmltag>glob</> +Glob elements hold shell-style filename matching patterns (including ? and +*) which match fonts based on their complete pathnames. This can be used to +exclude a set of directories (/usr/share/fonts/uglyfont*), or particular +font file types (*.pcf.gz), but the latter mechanism relies rather heavily +on filenaming conventions which can't be relied upon. + + <sgmltag>pattern</> +Pattern elements perform list-style matching on incoming fonts; that is, +they hold a list of elements and associated values. If all of those +elements have a matching value, then the pattern matches the font. This can +be used to select fonts based on attributes of the font (scalable, bold, +etc), which is a more reliable mechanism than using file extensions. +Pattern elements include patelt elements. + <sgmltag>patelt name="property"</> +Patelt elements hold a single pattern element and list of values. They must +have a 'name' attribute which indicates the pattern element name. Patelt +elements include int, double, string, matrix, bool, charset and const +elements. <sgmltag>match target="pattern"</> This element holds first a (possibly empty) list of test elements and then diff --git a/fc-lang/nb.orth b/fc-lang/nb.orth index 72d6d05..d867b81 100644 --- a/fc-lang/nb.orth +++ b/fc-lang/nb.orth @@ -21,5 +21,5 @@ # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # -# Norwegian Bokmål (NB) +# Norwegian Bokmäl (NB) include no.orth diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index 2e667cb..645aebb 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -89,6 +89,10 @@ typedef int FcBool; #define FC_CHARSET "charset" /* CharSet */ #define FC_LANG "lang" /* String RFC 3066 langs */ #define FC_FONTVERSION "fontversion" /* Int from 'head' table */ +#define FC_FULLNAME "fullname" /* String */ +#define FC_FAMILYLANG "familylang" /* String RFC 3066 langs */ +#define FC_STYLELANG "stylelang" /* String RFC 3066 langs */ +#define FC_FULLNAMELANG "fullnamelang" /* String RFC 3066 langs */ #define FC_DIR_CACHE_FILE "fonts.cache-"FC_CACHE_VERSION #define FC_USER_CACHE_FILE ".fonts.cache-"FC_CACHE_VERSION @@ -683,6 +687,9 @@ FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v); FcBool FcPatternDel (FcPattern *p, const char *object); +FcBool +FcPatternRemove (FcPattern *p, const char *object, int id); + FcBool FcPatternAddInteger (FcPattern *p, const char *object, int i); diff --git a/fonts.dtd b/fonts.dtd index 6fcfe09..6c9a33d 100644 --- a/fonts.dtd +++ b/fonts.dtd @@ -3,6 +3,7 @@ cache | include | config | + selectfont | match | alias)* > @@ -80,6 +81,24 @@ --> + + + + + + + + + + + + + + + diff --git a/src/fccache.c b/src/fccache.c index beb9ae5..ab6bec0 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -297,7 +297,7 @@ FcCacheFontSetAdd (FcFontSet *set, if (FcDebug () & FC_DBG_CACHEV) printf (" dir cache file \"%s\"\n", file); ret = FcPatternAddString (font, FC_FILE, path); - if (ret) + if (ret && (!config || FcConfigAcceptFont (config, font))) { frozen = FcPatternFreeze (font); ret = (frozen != 0); diff --git a/src/fccfg.c b/src/fccfg.c index 5612949..b0bc06e 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -67,10 +67,18 @@ FcConfigCreate (void) if (!config->rejectGlobs) goto bail5; + config->acceptPatterns = FcFontSetCreate (); + if (!config->acceptPatterns) + goto bail6; + + config->rejectPatterns = FcFontSetCreate (); + if (!config->rejectPatterns) + goto bail7; + config->cache = 0; if (FcConfigHome()) if (!FcConfigSetCache (config, (FcChar8 *) ("~/" FC_USER_CACHE_FILE))) - goto bail6; + goto bail8; #ifdef _WIN32 if (config->cache == 0) @@ -110,6 +118,10 @@ FcConfigCreate (void) return config; +bail8: + FcFontSetDestroy (config->rejectPatterns); +bail7: + FcFontSetDestroy (config->acceptPatterns); bail6: FcStrSetDestroy (config->rejectGlobs); bail5: @@ -207,6 +219,8 @@ FcConfigDestroy (FcConfig *config) FcStrSetDestroy (config->configFiles); FcStrSetDestroy (config->acceptGlobs); FcStrSetDestroy (config->rejectGlobs); + FcFontSetDestroy (config->acceptPatterns); + FcFontSetDestroy (config->rejectPatterns); if (config->blanks) FcBlanksDestroy (config->blanks); @@ -665,7 +679,7 @@ FcConfigCompareValue (const FcValue left_o, ret = FcLangSetContains (left.u.l, right.u.l); break; case FcOpNotContains: - ret = FcLangSetContains (left.u.l, right.u.l); + ret = !FcLangSetContains (left.u.l, right.u.l); break; case FcOpEqual: ret = FcLangSetEqual (left.u.l, right.u.l); @@ -1837,3 +1851,40 @@ FcConfigAcceptFilename (FcConfig *config, return FcFalse; return FcTrue; } + +/* + * Manage font-pattern based font source selectors + */ + +FcBool +FcConfigPatternsAdd (FcConfig *config, + FcPattern *pattern, + FcBool accept) +{ + FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; + + return FcFontSetAdd (set, pattern); +} + +static FcBool +FcConfigPatternsMatch (const FcFontSet *patterns, + const FcPattern *font) +{ + int i; + + for (i = 0; i < patterns->nfont; i++) + if (FcListPatternMatchAny (patterns->fonts[i], font)) + return FcTrue; + return FcFalse; +} + +FcBool +FcConfigAcceptFont (FcConfig *config, + const FcPattern *font) +{ + if (FcConfigPatternsMatch (config->acceptPatterns, font)) + return FcTrue; + if (FcConfigPatternsMatch (config->rejectPatterns, font)) + return FcFalse; + return FcTrue; +} diff --git a/src/fcdir.c b/src/fcdir.c index 6ae7052..9ce22da 100644 --- a/src/fcdir.c +++ b/src/fcdir.c @@ -141,7 +141,7 @@ FcFileScanConfig (FcFontSet *set, /* * Add the font */ - if (font) + if (font && (!config || FcConfigAcceptFont (config, font))) { if (!FcFontSetAdd (set, font)) { diff --git a/src/fcfreetype.c b/src/fcfreetype.c index daaba28..9c2c385 100644 --- a/src/fcfreetype.c +++ b/src/fcfreetype.c @@ -104,54 +104,639 @@ FcFreeTypeIsExclusiveLang (const FcChar8 *lang) return FcFalse; } -#define FC_NAME_PRIO_LANG 0x0f00 -#define FC_NAME_PRIO_LANG_ENGLISH 0x0200 -#define FC_NAME_PRIO_LANG_LATIN 0x0100 -#define FC_NAME_PRIO_LANG_NONE 0x0000 +typedef struct { + FT_UShort platform_id; + FT_UShort encoding_id; + char *fromcode; +} FcFtEncoding; + +#define TT_ENCODING_DONT_CARE 0xffff +#define FC_ENCODING_MAC_ROMAN "MACINTOSH" + +static const FcFtEncoding fcFtEncoding[] = { + { TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UCS-2BE" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, "GB3212" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johap" }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UCS4" }, + { TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" }, + { TT_PLATFORM_ISO, TT_ISO_ID_10646, "UCS-2BE" }, + { TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" }, +}; -#define FC_NAME_PRIO_ENC 0x00f0 -#define FC_NAME_PRIO_ENC_UNICODE 0x0010 -#define FC_NAME_PRIO_ENC_NONE 0x0000 +#define NUM_FC_FT_ENCODING (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0])) + +typedef struct { + FT_UShort platform_id; + FT_UShort language_id; + char *lang; +} FcFtLanguage; + +#define TT_LANGUAGE_DONT_CARE 0xffff + +static const FcFtLanguage fcFtLanguage[] = { + { TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, 0 }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" }, +/* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */ + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" }, + +#if 0 /* these seem to be errors that have been dropped */ -#define FC_NAME_PRIO_NAME 0x000f -#define FC_NAME_PRIO_NAME_FAMILY 0x0002 -#define FC_NAME_PRIO_NAME_PS 0x0001 -#define FC_NAME_PRIO_NAME_NONE 0x0000 + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC }, -static FcBool -FcUcs4IsLatin (FcChar32 ucs4) -{ - FcChar32 page = ucs4 >> 8; +#endif - if (page <= 2) - return FcTrue; - if (page == 0x1e) - return FcTrue; - if (0x20 <= page && page <= 0x23) - return FcTrue; - if (page == 0xfb) - return FcTrue; - /* halfwidth forms, don't include kana or white parens */ - if (0xff01 <= ucs4 && ucs4 <= 0xff5e) - return FcTrue; - return FcFalse; -} + /* The following codes are new as of 2000-03-10 */ + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" }, + { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" }, + +#ifdef TT_MS_LANGID_MAORI_NEW_ZELAND + /* this seems to be an error that have been dropped */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" }, +#endif -static FcBool -FcUtf8IsLatin (FcChar8 *str, int len) + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" }, + + /* new as of 2001-01-01 */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" }, + + /* the following seems to be inconsistent; + here is the current "official" way: */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" }, + /* and here is what is used by Passport SDK */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" }, + /* end of inconsistency */ + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" }, + /* the following one is only encountered in Microsoft RTF specification */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" }, + /* the following one is not in the Passport list, looks like an omission */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" }, + + /* new as of 2001-03-01 (from Office Xp) */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" }, +#if 0 + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN }, +#endif + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" }, + + /* New additions from Windows Xp/Passport SDK 2001-11-10. */ + + /* don't ask what this one means... It is commented out currently. */ +#if 0 + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 }, +#endif + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" }, + /* The following two IDs blatantly violate MS specs by using a */ + /* sublanguage >,. */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" }, + + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" }, +#if 0 + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA }, +#endif + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" }, + /* language codes from, to, are (still) unknown. */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" }, + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" }, +#if 0 + /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */ + /* not written (but OTOH the peculiar writing system is worth */ + /* studying). */ + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA }, +#endif + { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" }, +}; + +#define NUM_FC_FT_LANGUAGE (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0])) + +typedef struct { + FT_UShort language_id; + char *fromcode; +} FcMacRomanFake; + +static const FcMacRomanFake fcMacRomanFake[] = { + { TT_MS_LANGID_JAPANESE_JAPAN, "SJIS-WIN" }, + { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" }, +}; + +#define NUM_FC_MAC_ROMAN_FAKE (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0])) + +#if HAVE_ICONV && HAVE_ICONV_H +#define USE_ICONV 1 +#include +#endif + +static FcChar8 * +FcSfntNameTranscode (FT_SfntName *sname) { - while (len) + int i; + char *fromcode; +#if USE_ICONV + iconv_t cd; +#endif + FcChar8 *utf8; + + for (i = 0; i < NUM_FC_FT_ENCODING; i++) + if (fcFtEncoding[i].platform_id == sname->platform_id && + (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE || + fcFtEncoding[i].encoding_id == sname->encoding_id)) + break; + if (i == NUM_FC_FT_ENCODING) + return 0; + fromcode = fcFtEncoding[i].fromcode; + + /* + * "real" Mac language IDs are all less than 150. + * Names using one of the MS language IDs are assumed + * to use an associated encoding (Yes, this is a kludge) + */ + if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN) && + sname->language_id >= 0x100) + { + int f; + + fromcode = 0; + for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++) + if (fcMacRomanFake[f].language_id == sname->language_id) + { + fromcode = fcMacRomanFake[f].fromcode; + break; + } + if (!fromcode) + return 0; + } +#if USE_ICONV + cd = iconv_open ("UTF-8", fromcode); + if (cd) + { + size_t in_bytes_left = sname->string_len; + size_t out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN; + char *inbuf, *outbuf; + + utf8 = malloc (out_bytes_left + 1); + if (!utf8) + return 0; + + outbuf = (char *) utf8; + inbuf = (char *) sname->string; + + while (in_bytes_left) + { + size_t did = iconv (cd, + &inbuf, &in_bytes_left, + &outbuf, &out_bytes_left); + if (did == (size_t) (-1)) + { + free (utf8); + return 0; + } + } + *outbuf = '\0'; + goto done; + } +#endif + if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE")) + { + FcChar8 *src = sname->string; + int src_len = sname->string_len; + int len; + int wchar; + int ilen, olen; + FcChar8 *u8; + FcChar32 ucs4; + + /* + * Convert Utf16 to Utf8 + */ + + if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar)) + return 0; + + /* + * Allocate plenty of space. Freed below + */ + utf8 = malloc (len * FC_UTF8_MAX_LEN + 1); + if (!utf8) + return 0; + + u8 = utf8; + + while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0) + { + src_len -= ilen; + src += ilen; + olen = FcUcs4ToUtf8 (ucs4, u8); + u8 += olen; + } + *u8 = '\0'; + goto done; + } + if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1")) { + FcChar8 *src = sname->string; + int src_len = sname->string_len; + int olen; + FcChar8 *u8; FcChar32 ucs4; - int clen = FcUtf8ToUcs4 (str, &ucs4, len); - if (clen <= 0) - return FcFalse; - if (!FcUcs4IsLatin (ucs4)) - return FcFalse; - len -= clen; - str += clen; + + /* + * Convert Latin1 to Utf8. Freed below + */ + utf8 = malloc (src_len * 2 + 1); + if (!utf8) + return 0; + + u8 = utf8; + while (src_len > 0) + { + ucs4 = *src++; + src_len--; + olen = FcUcs4ToUtf8 (ucs4, u8); + u8 += olen; + } + *u8 = '\0'; + goto done; } - return FcTrue; + if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN)) + { + FcChar8 *u8; + const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman); + FcChar8 *src = (FcChar8 *) sname->string; + int src_len = sname->string_len; + + /* + * Convert AppleRoman to Utf8 + */ + if (!map) + return 0; + + utf8 = malloc (sname->string_len * 3 + 1); + if (!utf8) + return 0; + + u8 = utf8; + while (src_len > 0) + { + FcChar32 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map); + int olen = FcUcs4ToUtf8 (ucs4, u8); + src_len--; + u8 += olen; + } + *u8 = '\0'; + goto done; + } + return 0; +done: + if (FcStrCmpIgnoreBlanksAndCase (utf8, "") == 0) + { + free (utf8); + return 0; + } + return utf8; +} + +static FcChar8 * +FcSfntNameLanguage (FT_SfntName *sname) +{ + int i; + for (i = 0; i < NUM_FC_FT_LANGUAGE; i++) + if (fcFtLanguage[i].platform_id == sname->platform_id && + (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE || + fcFtLanguage[i].language_id == sname->language_id)) + return fcFtLanguage[i].lang; + return 0; } /* Order is significant. For example, some B&H fonts are hinted by @@ -368,6 +953,20 @@ FcGetPixelSize (FT_Face face, int i) #endif } +static FcBool +FcStringInPatternElement (FcPattern *pat, char *elt, FcChar8 *string) +{ + int e; + FcChar8 *old; + for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++) + if (!FcStrCmpIgnoreBlanksAndCase (old, string)) + { + return FcTrue; + break; + } + return FcFalse; +} + FcPattern * FcFreeTypeQuery (const FcChar8 *file, int id, @@ -383,8 +982,9 @@ FcFreeTypeQuery (const FcChar8 *file, FcCharSet *cs; FcLangSet *ls; FT_Library ftLibrary; +#if 0 FcChar8 *family = 0; - FcChar8 *style = 0; +#endif const FcChar8 *foundry = 0; int spacing; TT_OS2 *os2; @@ -398,11 +998,17 @@ FcFreeTypeQuery (const FcChar8 *file, const FcChar8 *exclusiveLang = 0; FT_SfntName sname; FT_UInt snamei, snamec; - FcBool family_allocated = FcFalse; - FcBool style_allocated = FcFalse; - int family_prio = 0; - int style_prio = 0; + + int nfamily = 0; + int nfamily_lang = 0; + int nstyle = 0; + int nstyle_lang = 0; + int nfullname = 0; + int nfullname_lang = 0; + FcChar8 *style = 0; + int st; + if (FT_Init_FreeType (&ftLibrary)) return 0; @@ -440,6 +1046,8 @@ FcFreeTypeQuery (const FcChar8 *file, if (os2 && os2->version >= 0x0001 && os2->version != 0xffff) foundry = FcVendorFoundry(os2->achVendID); + if (FcDebug () & FC_DBG_SCANV) + printf ("\n"); /* * Grub through the name table looking for family * and style names. FreeType makes quite a hash @@ -449,225 +1057,60 @@ FcFreeTypeQuery (const FcChar8 *file, for (snamei = 0; snamei < snamec; snamei++) { FcChar8 *utf8; - int len; - int wchar; - FcChar8 *src; - int src_len; - FcChar8 *u8; - FcChar32 ucs4; - int ilen, olen; - int prio = 0; - - const FcCharMap *map; - enum { - FcNameEncodingUtf16, - FcNameEncodingAppleRoman, - FcNameEncodingLatin1 - } encoding; - - + FcChar8 *lang; + char *elt = 0, *eltlang = 0; + int *np = 0, *nlangp = 0; + if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0) - break; + continue; - /* - * Look for Unicode strings - */ - switch (sname.platform_id) { - case TT_PLATFORM_APPLE_UNICODE: - /* - * All APPLE_UNICODE encodings are Utf16 BE - * - * Because there's no language id for Unicode, - * assume it's English - */ - prio |= FC_NAME_PRIO_LANG_ENGLISH; - prio |= FC_NAME_PRIO_ENC_UNICODE; - encoding = FcNameEncodingUtf16; - break; - case TT_PLATFORM_MACINTOSH: - switch (sname.encoding_id) { - case TT_MAC_ID_ROMAN: - encoding = FcNameEncodingAppleRoman; - break; - default: - continue; - } - switch (sname.language_id) { - case TT_MAC_LANGID_ENGLISH: - prio |= FC_NAME_PRIO_LANG_ENGLISH; - break; - default: - /* - * Sometimes Microsoft language ids - * end up in the macintosh table. This - * is often accompanied by data in - * some mystic encoding. Ignore these names - */ - if (sname.language_id >= 0x100) - continue; - break; - } - break; - case TT_PLATFORM_MICROSOFT: - switch (sname.encoding_id) { - case TT_MS_ID_UNICODE_CS: - encoding = FcNameEncodingUtf16; - prio |= FC_NAME_PRIO_ENC_UNICODE; - break; - default: - continue; - } - switch (sname.language_id & 0xff) { - case 0x09: - prio |= FC_NAME_PRIO_LANG_ENGLISH; - break; - default: - break; - } - break; - case TT_PLATFORM_ISO: - switch (sname.encoding_id) { - case TT_ISO_ID_10646: - encoding = FcNameEncodingUtf16; - prio |= FC_NAME_PRIO_ENC_UNICODE; - break; - case TT_ISO_ID_7BIT_ASCII: - case TT_ISO_ID_8859_1: - encoding = FcNameEncodingLatin1; - break; - default: - continue; - } - break; - default: + utf8 = FcSfntNameTranscode (&sname); + lang = FcSfntNameLanguage (&sname); + + if (!utf8) continue; - } - /* - * Look for family and style names - */ switch (sname.name_id) { case TT_NAME_ID_FONT_FAMILY: - prio |= FC_NAME_PRIO_NAME_FAMILY; - break; +#if 0 case TT_NAME_ID_PS_NAME: - prio |= FC_NAME_PRIO_NAME_PS; - break; - case TT_NAME_ID_FONT_SUBFAMILY: - case TT_NAME_ID_TRADEMARK: - case TT_NAME_ID_MANUFACTURER: - break; - default: - continue; - } - - src = (FcChar8 *) sname.string; - src_len = sname.string_len; - - switch (encoding) { - case FcNameEncodingUtf16: - /* - * Convert Utf16 to Utf8 - */ - - if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar)) - continue; + case TT_NAME_ID_UNIQUE_ID: +#endif + if (FcDebug () & FC_DBG_SCANV) + printf ("found family (n %2d p %d e %d l 0x%04x) %s\n", + sname.name_id, sname.platform_id, + sname.encoding_id, sname.language_id, + utf8); - /* - * Allocate plenty of space. Freed below - */ - utf8 = malloc (len * FC_UTF8_MAX_LEN + 1); - if (!utf8) - continue; - - u8 = utf8; - - while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0) - { - src_len -= ilen; - src += ilen; - olen = FcUcs4ToUtf8 (ucs4, u8); - u8 += olen; - } - *u8 = '\0'; - break; - case FcNameEncodingLatin1: - /* - * Convert Latin1 to Utf8. Freed below - */ - utf8 = malloc (src_len * 2 + 1); - if (!utf8) - continue; - - u8 = utf8; - while (src_len > 0) - { - ucs4 = *src++; - src_len--; - olen = FcUcs4ToUtf8 (ucs4, u8); - u8 += olen; - } - *u8 = '\0'; + elt = FC_FAMILY; + eltlang = FC_FAMILYLANG; + np = &nfamily; + nlangp = &nfamily_lang; break; - case FcNameEncodingAppleRoman: - /* - * Convert AppleRoman to Utf8 - */ - map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman); - if (!map) - continue; - - /* freed below */ - utf8 = malloc (src_len * 3 + 1); - if (!utf8) - continue; - - u8 = utf8; - while (src_len > 0) - { - ucs4 = FcFreeTypePrivateToUcs4 (*src++, map); - src_len--; - olen = FcUcs4ToUtf8 (ucs4, u8); - u8 += olen; - } - *u8 = '\0'; - break; - default: - continue; - } - if ((prio & FC_NAME_PRIO_LANG) == FC_NAME_PRIO_LANG_NONE) - if (FcUtf8IsLatin (utf8, strlen ((char *) utf8))) - prio |= FC_NAME_PRIO_LANG_LATIN; - - if (FcDebug () & FC_DBG_SCANV) - printf ("\nfound name (name %d platform %d encoding %d language 0x%x prio 0x%x) %s\n", + case TT_NAME_ID_FULL_NAME: + case TT_NAME_ID_MAC_FULL_NAME: + if (FcDebug () & FC_DBG_SCANV) + printf ("found full (n %2d p %d e %d l 0x%04x) %s\n", sname.name_id, sname.platform_id, sname.encoding_id, sname.language_id, - prio, utf8); + utf8); - switch (sname.name_id) { - case TT_NAME_ID_FONT_FAMILY: - case TT_NAME_ID_PS_NAME: - if (!family || prio > family_prio) - { - if (family) - free (family); - family = utf8; - utf8 = 0; - family_allocated = FcTrue; - family_prio = prio; - } + elt = FC_FULLNAME; + eltlang = FC_FULLNAMELANG; + np = &nfullname; + nlangp = &nfullname_lang; break; case TT_NAME_ID_FONT_SUBFAMILY: - if (!style || prio > style_prio) - { - if (style) - free (style); - style = utf8; - utf8 = 0; - style_allocated = FcTrue; - style_prio = prio; - } + if (FcDebug () & FC_DBG_SCANV) + printf ("found style (n %2d p %d e %d l 0x%04x) %s\n", + sname.name_id, sname.platform_id, + sname.encoding_id, sname.language_id, + utf8); + + elt = FC_STYLE; + eltlang = FC_STYLELANG; + np = &nstyle; + nlangp = &nstyle_lang; break; case TT_NAME_ID_TRADEMARK: case TT_NAME_ID_MANUFACTURER: @@ -676,19 +1119,62 @@ FcFreeTypeQuery (const FcChar8 *file, foundry = FcNoticeFoundry((FT_String *) utf8); break; } - if (utf8) + if (elt) + { + if (FcStringInPatternElement (pat, elt, utf8)) + { + free (utf8); + continue; + } + + /* add new element */ + if (!FcPatternAddString (pat, elt, utf8)) + { + free (utf8); + goto bail1; + } + free (utf8); + if (lang) + { + /* pad lang list with 'xx' to line up with elt */ + while (*nlangp < *np) + { + if (!FcPatternAddString (pat, eltlang, "xx")) + goto bail1; + ++*nlangp; + } + if (!FcPatternAddString (pat, eltlang, lang)) + goto bail1; + ++*nlangp; + } + ++*np; + } + else free (utf8); } - if (!family) - family = (FcChar8 *) face->family_name; + if (!nfamily && face->family_name) + { + if (FcDebug () & FC_DBG_SCANV) + printf ("using FreeType family %s", face->family_name); + if (!FcPatternAddString (pat, FC_FAMILY, face->family_name)) + goto bail1; + ++nfamily; + } - if (!style) - style = (FcChar8 *) face->style_name; + if (!nstyle && face->style_name) + { + if (FcDebug () & FC_DBG_SCANV) + printf ("using FreeType style %s", face->family_name); + if (!FcPatternAddString (pat, FC_STYLE, face->style_name)) + goto bail1; + ++nstyle; + } - if (!family) + if (!nfamily) { FcChar8 *start, *end; + FcChar8 *family; start = (FcChar8 *) strrchr ((char *) file, '/'); if (start) @@ -702,19 +1188,79 @@ FcFreeTypeQuery (const FcChar8 *file, family = malloc (end - start + 1); strncpy ((char *) family, (char *) start, end - start); family[end - start] = '\0'; - family_allocated = FcTrue; + if (FcDebug () & FC_DBG_SCANV) + printf ("using filename for family %s", family); + if (!FcPatternAddString (pat, FC_FAMILY, family)) + { + free (family); + goto bail1; + } + free (family); + ++nfamily; } - if (FcDebug() & FC_DBG_SCAN) - printf ("\n\"%s\" \"%s\"\n", family, style ? style : (FcChar8 *) ""); + /* + * Walk through FC_FULLNAME entries eliding those in FC_FAMILY + * or which are simply a FC_FAMILY and FC_STYLE glued together + */ + { + int fn, fa, st; + FcChar8 *full; + FcChar8 *fam; + FcChar8 *style; - if (!FcPatternAddString (pat, FC_FAMILY, family)) - goto bail1; + for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++) + { + FcBool remove = FcFalse; + /* + * Check each family + */ + for (fa = 0; !remove && + FcPatternGetString (pat, FC_FAMILY, + fa, &fam) == FcResultMatch; + fa++) + { + /* + * for exact match + */ + if (!FcStrCmpIgnoreBlanksAndCase (full, fam)) + { + remove = FcTrue; + break; + } + /* + * If the family is in the full name, check the + * combination of this family with every style + */ + if (!FcStrContainsIgnoreBlanksAndCase (full, fam)) + continue; + for (st = 0; !remove && + FcPatternGetString (pat, FC_STYLE, + st, &style) == FcResultMatch; + st++) + { + FcChar8 *both = FcStrPlus (fam, style); - if (style) - { - if (!FcPatternAddString (pat, FC_STYLE, style)) - goto bail1; + if (both) + { + if (FcStrCmpIgnoreBlanksAndCase (full, both) == 0) + remove = FcTrue; + free (both); + } + } + } + if (remove) + { + FcPatternRemove (pat, FC_FULLNAME, fn); + FcPatternRemove (pat, FC_FULLNAMELANG, fn); + fn--; + nfullname--; + nfullname_lang--; + } + } + if (FcDebug () & FC_DBG_SCANV) + for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++) + printf ("Saving unique fullname %s\n", full); } if (!FcPatternAddString (pat, FC_FILE, file)) @@ -906,7 +1452,7 @@ FcFreeTypeQuery (const FcChar8 *file, /* * Look for weight, width and slant names in the style value */ - if (style) + for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++) { if (weight == -1) { @@ -1062,11 +1608,6 @@ FcFreeTypeQuery (const FcChar8 *file, * Deallocate family/style values */ - if (family_allocated) - free (family); - if (style_allocated) - free (style); - FT_Done_Face (face); FT_Done_FreeType (ftLibrary); return pat; @@ -1075,10 +1616,6 @@ bail2: FcCharSetDestroy (cs); bail1: FcPatternDestroy (pat); - if (family_allocated) - free (family); - if (style_allocated) - free (style); bail0: FT_Done_Face (face); bail: diff --git a/src/fcint.h b/src/fcint.h index 036da9e..cf86ad4 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -329,6 +329,8 @@ struct _FcConfig { */ FcStrSet *acceptGlobs; FcStrSet *rejectGlobs; + FcFontSet *acceptPatterns; + FcFontSet *rejectPatterns; /* * The set of fonts loaded from the listed directories; the * order within the set does not determine the font selection, @@ -465,6 +467,15 @@ FcBool FcConfigAcceptFilename (FcConfig *config, const FcChar8 *filename); +FcBool +FcConfigPatternsAdd (FcConfig *config, + FcPattern *pattern, + FcBool accept); + +FcBool +FcConfigAcceptFont (FcConfig *config, + const FcPattern *font); + /* fccharset.c */ FcCharSet * FcCharSetFreeze (FcCharSet *cs); @@ -639,6 +650,10 @@ FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls); /* fclist.c */ +FcBool +FcListPatternMatchAny (const FcPattern *p, + const FcPattern *font); + /* fcmatch.c */ /* fcname.c */ @@ -669,6 +684,12 @@ FcPatternFreeze (FcPattern *p); void FcPatternThawAll (void); +FcBool +FcPatternAppend (FcPattern *p, FcPattern *s); + +const char * +FcObjectStaticName (const char *name); + /* fcrender.c */ /* fcmatrix.c */ diff --git a/src/fclist.c b/src/fclist.c index 0885c93..3474d99 100644 --- a/src/fclist.c +++ b/src/fclist.c @@ -200,9 +200,9 @@ FcListPatternEqual (FcPattern *p1, * FcTrue iff all objects in "p" match "font" */ -static FcBool -FcListPatternMatchAny (FcPattern *p, - FcPattern *font) +FcBool +FcListPatternMatchAny (const FcPattern *p, + const FcPattern *font) { int i; FcPatternElt *e; diff --git a/src/fcname.c b/src/fcname.c index c1df41b..f40bf64 100644 --- a/src/fcname.c +++ b/src/fcname.c @@ -30,7 +30,11 @@ static const FcObjectType _FcBaseObjectTypes[] = { { FC_FAMILY, FcTypeString, }, + { FC_FAMILYLANG, FcTypeString, }, { FC_STYLE, FcTypeString, }, + { FC_STYLELANG, FcTypeString, }, + { FC_FULLNAME, FcTypeString, }, + { FC_FULLNAMELANG, FcTypeString, }, { FC_SLANT, FcTypeInteger, }, { FC_WEIGHT, FcTypeInteger, }, { FC_WIDTH, FcTypeInteger, }, diff --git a/src/fcpat.c b/src/fcpat.c index ddc16f8..421211f 100644 --- a/src/fcpat.c +++ b/src/fcpat.c @@ -849,6 +849,31 @@ FcPatternDel (FcPattern *p, const char *object) return FcTrue; } +FcBool +FcPatternRemove (FcPattern *p, const char *object, int id) +{ + FcPatternElt *e; + FcValueList **prev, *l; + + e = FcPatternFindElt (p, object); + if (!e) + return FcFalse; + for (prev = &e->values; (l = *prev); prev = &l->next) + { + if (!id) + { + *prev = l->next; + l->next = 0; + FcValueListDestroy (l); + if (!e->values) + FcPatternDel (p, object); + return FcTrue; + } + id--; + } + return FcFalse; +} + FcBool FcPatternAddInteger (FcPattern *p, const char *object, int i) { @@ -1139,3 +1164,51 @@ FcPatternBuild (FcPattern *orig, ...) va_end (va); return orig; } + +/* + * Add all of the elements in 's' to 'p' + */ +FcBool +FcPatternAppend (FcPattern *p, FcPattern *s) +{ + int i; + FcPatternElt *e; + FcValueList *v; + + for (i = 0; i < s->num; i++) + { + e = &s->elts[i]; + for (v = e->values; v; v = v->next) + { + if (!FcPatternAddWithBinding (p, e->object, + v->value, v->binding, FcTrue)) + return FcFalse; + } + } + return FcTrue; +} + +const char * +FcObjectStaticName (const char *name) +{ +#define OBJECT_HASH_SIZE 31 + static struct objectBucket { + struct objectBucket *next; + FcChar32 hash; + } *buckets[OBJECT_HASH_SIZE]; + FcChar32 hash = FcStringHash ((const FcChar8 *) name); + struct objectBucket **p; + struct objectBucket *b; + + for (p = &buckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) + if (b->hash == hash && !strcmp (name, (char *) (b + 1))) + return (char *) (b + 1); + b = malloc (sizeof (struct objectBucket) + strlen (name) + 1); + if (!b) + return NULL; + b->next = 0; + b->hash = hash; + strcpy ((char *) (b + 1), name); + *p = b; + return (char *) (b + 1); +} diff --git a/src/fcxml.c b/src/fcxml.c index 70aeb03..52172b2 100644 --- a/src/fcxml.c +++ b/src/fcxml.c @@ -323,6 +323,8 @@ typedef enum _FcElement { FcElementAcceptfont, FcElementRejectfont, FcElementGlob, + FcElementPattern, + FcElementPatelt, FcElementTest, FcElementEdit, @@ -384,6 +386,8 @@ FcElementMap (const XML_Char *name) { "acceptfont", FcElementAcceptfont }, { "rejectfont", FcElementRejectfont }, { "glob", FcElementGlob }, + { "pattern", FcElementPattern }, + { "patelt", FcElementPatelt }, { "test", FcElementTest }, { "edit", FcElementEdit }, @@ -441,6 +445,7 @@ typedef enum _FcVStackTag { FcVStackField, FcVStackConstant, FcVStackGlob, + FcVStackPattern, FcVStackPrefer, FcVStackAccept, @@ -473,6 +478,8 @@ typedef struct _FcVStack { FcOp op; FcExpr *expr; FcEdit *edit; + + FcPattern *pattern; } u; } FcVStack; @@ -560,6 +567,9 @@ FcVStackDestroy (FcVStack *vstack) case FcVStackGlob: FcStrFree (vstack->u.string); break; + case FcVStackPattern: + FcPatternDestroy (vstack->u.pattern); + break; case FcVStackInteger: case FcVStackDouble: break; @@ -688,6 +698,18 @@ FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) return FcTrue; } +static FcBool +FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.pattern = pattern; + vstack->tag = FcVStackPattern; + FcVStackPush (parse, vstack); + return FcTrue; +} + static FcVStack * FcVStackFetch (FcConfigParse *parse, int off) { @@ -1321,6 +1343,8 @@ FcPopExpr (FcConfigParse *parse) break; case FcVStackEdit: break; + default: + break; } FcVStackDestroy (vstack); return expr; @@ -1675,6 +1699,16 @@ FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) FcConfigMessage (parse, FcSevereError, "out of memory"); } break; + case FcVStackPattern: + if (!FcConfigPatternsAdd (parse->config, + vstack->u.pattern, + element == FcElementAcceptfont)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + else + vstack->tag = FcVStackNone; + break; default: FcConfigMessage (parse, FcSevereWarning, "bad font selector"); break; @@ -1683,6 +1717,128 @@ FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) } } + +static FcValue +FcPopValue (FcConfigParse *parse) +{ + FcVStack *vstack = FcVStackPop (parse); + FcValue value; + + value.type = FcTypeVoid; + + if (!vstack) + return value; + + switch (vstack->tag) { + case FcVStackString: + value.u.s = FcStrCopy (vstack->u.string); + if (value.u.s) + value.type = FcTypeString; + break; + case FcVStackConstant: + if (FcNameConstant (vstack->u.string, &value.u.i)) + value.type = FcTypeInteger; + break; + case FcVStackInteger: + value.u.i = vstack->u.integer; + value.type = FcTypeInteger; + break; + case FcVStackDouble: + value.u.d = vstack->u._double; + value.type = FcTypeInteger; + break; + case FcVStackMatrix: + value.u.m = FcMatrixCopy (vstack->u.matrix); + if (value.u.m) + value.type = FcTypeMatrix; + break; + case FcVStackBool: + value.u.b = vstack->u.bool; + value.type = FcTypeBool; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", + vstack->tag); + break; + } + FcVStackDestroy (vstack); + + return value; +} + +static void +FcParsePatelt (FcConfigParse *parse) +{ + FcValue value; + FcPattern *pattern = FcPatternCreate (); + const char *name; + + if (!pattern) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + name = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); + return; + } + name = FcObjectStaticName (name); + if (!name) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + for (;;) + { + value = FcPopValue (parse); + if (value.type == FcTypeVoid) + break; + if (!FcPatternAdd (pattern, name, value, FcTrue)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + } + + FcVStackPushPattern (parse, pattern); +} + +static void +FcParsePattern (FcConfigParse *parse) +{ + FcVStack *vstack; + FcPattern *pattern = FcPatternCreate (); + + if (!pattern) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + while ((vstack = FcVStackPop (parse))) + { + switch (vstack->tag) { + case FcVStackPattern: + if (!FcPatternAppend (pattern, vstack->u.pattern)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + break; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); + break; + } + FcVStackDestroy (vstack); + } + + FcVStackPushPattern (parse, pattern); +} + static void FcEndElement(void *userData, const XML_Char *name) { @@ -1814,6 +1970,12 @@ FcEndElement(void *userData, const XML_Char *name) case FcElementGlob: FcParseString (parse, FcVStackGlob); break; + case FcElementPattern: + FcParsePattern (parse); + break; + case FcElementPatelt: + FcParsePatelt (parse); + break; case FcElementName: FcParseString (parse, FcVStackField); break; -- 2.39.2