[Fontconfig] fontconfig: Branch 'master' - 4 commits

Akira TAGOH tagoh at kemper.freedesktop.org
Fri Jun 8 00:05:23 PDT 2012


 doc/fclangset.fncs      |    9 ++
 fc-lang/fc-lang.c       |    6 +
 fontconfig/fontconfig.h |    3 
 src/fccfg.c             |   18 +++++
 src/fcdefault.c         |  106 +++++++++-----------------------
 src/fcint.h             |    6 +
 src/fclang.c            |  159 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/fcstr.c             |   44 +++++++++++++
 8 files changed, 278 insertions(+), 73 deletions(-)

New commits:
commit 07e52eeb097a4e3c147e00ed7a6eb7652a611751
Author: Akira TAGOH <akira at tagoh.org>
Date:   Fri Jun 8 15:54:48 2012 +0900

    fcdefault: no need to set FC_LANG in FcDefaultSubstitute() anymore

diff --git a/src/fcdefault.c b/src/fcdefault.c
index ce90a88..c6b5669 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -126,10 +126,6 @@ FcDefaultSubstitute (FcPattern *pattern)
 	FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, size);
     }
 
-    if (FcPatternObjectGet (pattern, FC_LANG_OBJECT, 0, &v) == FcResultNoMatch)
-    {
- 	FcPatternObjectAddString (pattern, FC_LANG_OBJECT, FcGetDefaultLang ());
-    }
     if (FcPatternObjectGet (pattern, FC_FONTVERSION_OBJECT, 0, &v) == FcResultNoMatch)
     {
 	FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff);
commit 550fd49d4fb8efab33d1fa1687b1b9bd352202fe
Author: Akira TAGOH <akira at tagoh.org>
Date:   Tue May 22 14:17:10 2012 +0900

    Add the default language to the pattern prior to do build the substitution
    
    the default language is referred from the FC_LANG environment variable
    or the current locale

diff --git a/src/fccfg.c b/src/fccfg.c
index b45d74a..c3d95e8 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -1407,6 +1407,7 @@ FcConfigSubstituteWithPat (FcConfig    *config,
     FcEdit	    *e;
     FcValueList	    *l;
     FcPattern	    *m;
+    FcStrSet	    *strs;
 
     if (!config)
     {
@@ -1434,6 +1435,23 @@ FcConfigSubstituteWithPat (FcConfig    *config,
 	return FcFalse;
     FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
 
+    strs = FcGetDefaultLangs ();
+    if (strs)
+    {
+	FcStrList *l = FcStrListCreate (strs);
+	FcChar8 *lang;
+	FcValue v;
+
+	FcStrSetDestroy (strs);
+	while (l && (lang = FcStrListNext (l)))
+	{
+	    v.type = FcTypeString;
+	    v.u.s = lang;
+	    FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
+	}
+	FcStrListDone (l);
+    }
+
     if (FcDebug () & FC_DBG_EDIT)
     {
 	printf ("FcConfigSubstitute ");
commit 2261a64ce14d692f7c553f46e2158e70400dbc9c
Author: Akira TAGOH <akira at tagoh.org>
Date:   Fri Jun 8 15:47:52 2012 +0900

    fcdefault: fallback if the environment variables are empty
    
    try to fallback if FC_LANG, LC_ALL, LC_CTYPE and LANG is empty

diff --git a/src/fcdefault.c b/src/fcdefault.c
index 674374c..ce90a88 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -46,13 +46,13 @@ FcGetDefaultLangs (void)
     char *langs;
 
     langs = getenv ("FC_LANG");
-    if (!langs)
+    if (!langs || !langs[0])
 	langs = getenv ("LC_ALL");
-    if (!langs)
+    if (!langs || !langs[0])
 	langs = getenv ("LC_CTYPE");
-    if (!langs)
+    if (!langs || !langs[0])
 	langs = getenv ("LANG");
-    if (langs)
+    if (langs && langs[0])
     {
 	if (!FcStrSetAddLangs (result, langs))
 	    FcStrSetAdd (result, (const FcChar8 *) "en");
commit bbc8fb5ba705e5257693f3b266fce12d2f81b50c
Author: Akira TAGOH <akira at tagoh.org>
Date:   Thu Mar 29 20:25:20 2012 +0900

    Bug 32853 - Export API to get the default language
    
    Add a new API FcGetDefaultLangs() to export the string sets of the default
    languages.

diff --git a/doc/fclangset.fncs b/doc/fclangset.fncs
index 0a44b38..e2a40b8 100644
--- a/doc/fclangset.fncs
+++ b/doc/fclangset.fncs
@@ -154,6 +154,15 @@ has no matching language, this function returns FcLangDifferentLang.
 @@
 
 @RET@		FcStrSet *
+ at FUNC@		FcGetDefaultLangs
+ at TYPE1@		void
+ at PURPOSE@	Get the default languages list
+ at DESC@
+Returns a string set of the default languages according to the environment variables on the system.
+This function looks for them in order of FC_LANG, LC_ALL, LC_CTYPE and LANG then.
+If there are no valid values in those environment variables, "en" will be set as fallback.
+
+ at RET@		FcStrSet *
 @FUNC@		FcLangSetGetLangs
 @TYPE1@		const FcLangSet *		@ARG1@		ls
 @PURPOSE@	get the list of languages in the langset
diff --git a/fc-lang/fc-lang.c b/fc-lang/fc-lang.c
index 51717f9..93200c4 100644
--- a/fc-lang/fc-lang.c
+++ b/fc-lang/fc-lang.c
@@ -57,6 +57,12 @@ FcCacheObjectDereference (void *object)
 {
 }
 
+FcPrivate FcChar8 *
+FcLangNormalize (const FcChar8 *lang)
+{
+    return NULL;
+}
+
 int FcDebugVal;
 
 FcChar8 *
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
index 2671da7..21a476a 100644
--- a/fontconfig/fontconfig.h
+++ b/fontconfig/fontconfig.h
@@ -497,6 +497,9 @@ FcPublic void
 FcFontSetPrint (const FcFontSet *s);
 
 /* fcdefault.c */
+FcPublic FcStrSet *
+FcGetDefaultLangs (void);
+
 FcPublic void
 FcDefaultSubstitute (FcPattern *pattern);
 
diff --git a/src/fcdefault.c b/src/fcdefault.c
index 170a8a4..674374c 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -23,7 +23,7 @@
  */
 
 #include "fcint.h"
-#include <locale.h>
+#include <string.h>
 
 static const struct {
     FcObject	field;
@@ -39,81 +39,45 @@ static const struct {
 
 #define NUM_FC_BOOL_DEFAULTS	(int) (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
 
-FcChar8 *
-FcGetDefaultLang (void)
+FcStrSet *
+FcGetDefaultLangs (void)
 {
-    static char	lang_local [128] = {0};
-    char        *ctype;
-    char        *territory;
-    char        *after;
-    int         lang_len, territory_len;
-
-    if (lang_local [0])
-	return (FcChar8 *) lang_local;
-
-    ctype = setlocale (LC_CTYPE, NULL);
-
-    /*
-     * Check if setlocale (LC_ALL, "") has been called
-     */
-    if (!ctype || !strcmp (ctype, "C"))
+    FcStrSet *result = FcStrSetCreate ();
+    char *langs;
+
+    langs = getenv ("FC_LANG");
+    if (!langs)
+	langs = getenv ("LC_ALL");
+    if (!langs)
+	langs = getenv ("LC_CTYPE");
+    if (!langs)
+	langs = getenv ("LANG");
+    if (langs)
     {
-	ctype = getenv ("LC_ALL");
-	if (!ctype)
-	{
-	    ctype = getenv ("LC_CTYPE");
-	    if (!ctype)
-		ctype = getenv ("LANG");
-	}
+	if (!FcStrSetAddLangs (result, langs))
+	    FcStrSetAdd (result, (const FcChar8 *) "en");
     }
+    else
+	FcStrSetAdd (result, (const FcChar8 *) "en");
+
+    return result;
+}
 
-    /* ignore missing or empty ctype */
-    if (ctype && *ctype != '\0')
+FcChar8 *
+FcGetDefaultLang (void)
+{
+    static FcChar8 lang_local[128] = {0};
+    FcStrSet *langs;
+
+    if (!lang_local[0])
     {
-	territory = strchr (ctype, '_');
-	if (territory)
-	{
-	    lang_len = territory - ctype;
-	    territory = territory + 1;
-	    after = strchr (territory, '.');
-	    if (!after)
-	    {
-		after = strchr (territory, '@');
-		if (!after)
-		    after = territory + strlen (territory);
-	    }
-	    territory_len = after - territory;
-	    if (lang_len + 1 + territory_len + 1 <= (int) sizeof (lang_local))
-	    {
-		strncpy (lang_local, ctype, lang_len);
-		lang_local[lang_len] = '-';
-		strncpy (lang_local + lang_len + 1, territory, territory_len);
-		lang_local[lang_len + 1 + territory_len] = '\0';
-	    }
-	}
-	else
-	{
-	    after = strchr (ctype, '.');
-	    if (!after)
-	    {
-		after = strchr (ctype, '@');
-		if (!after)
-		    after = ctype + strlen (ctype);
-	    }
-	    lang_len = after - ctype;
-	    if (lang_len + 1 <= (int) sizeof (lang_local))
-	    {
-		strncpy (lang_local, ctype, lang_len);
-		lang_local[lang_len] = '\0';
-	    }
-	}
+	langs = FcGetDefaultLangs ();
+	strncpy ((char *)lang_local, (const char *)langs->strs[0], 127);
+	lang_local[127] = 0;
+	FcStrSetDestroy (langs);
     }
 
-    /* set default lang to en */
-    if (!lang_local [0])
-	strcpy (lang_local, "en");
-
-    return (FcChar8 *) lang_local;
+    return lang_local;
 }
 
 void
diff --git a/src/fcint.h b/src/fcint.h
index 3d06fc6..7cc4ed2 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -816,6 +816,9 @@ FcPrivate FcLangSet *
 FcFreeTypeLangSet (const FcCharSet  *charset,
 		   const FcChar8    *exclusiveLang);
 
+FcPrivate FcChar8 *
+FcLangNormalize (const FcChar8 *lang);
+
 FcPrivate FcLangResult
 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2);
 
@@ -1039,6 +1042,9 @@ FcPrivate FcBool
 FcIsFsMtimeBroken (const FcChar8 *dir);
 
 /* fcstr.c */
+FcPrivate FcBool
+FcStrSetAddLangs (FcStrSet *strs, const char *languages);
+
 FcPrivate void
 FcStrSetSort (FcStrSet * set);
 
diff --git a/src/fclang.c b/src/fclang.c
index be42b58..b7e70fc 100644
--- a/src/fclang.c
+++ b/src/fclang.c
@@ -22,6 +22,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <string.h>
 #include "fcint.h"
 #include "fcftint.h"
 
@@ -43,6 +44,9 @@ struct _FcLangSet {
     FcChar32	map[NUM_LANG_SET_MAP];
 };
 
+static int FcLangSetIndex (const FcChar8 *lang);
+
+
 static void
 FcLangSetBitSet (FcLangSet    *ls,
 		 unsigned int  id)
@@ -173,6 +177,161 @@ FcFreeTypeLangSet (const FcCharSet  *charset,
     return ls;
 }
 
+FcChar8 *
+FcLangNormalize (const FcChar8 *lang)
+{
+    FcChar8 *result = NULL, *s, *orig;
+    char *territory, *encoding, *modifier;
+    size_t llen, tlen = 0, mlen = 0;
+
+    if (!lang || !*lang)
+	return NULL;
+
+    if (FcStrCmpIgnoreCase (lang, (const FcChar8 *)"C") == 0 ||
+	FcStrCmpIgnoreCase (lang, (const FcChar8 *)"POSIX") == 0)
+    {
+	result = FcStrCopy ((const FcChar8 *)"en");
+	goto bail;
+    }
+
+    s = FcStrCopy (lang);
+    if (!s)
+	goto bail;
+
+    /* from the comments in glibc:
+     *
+     * LOCALE can consist of up to four recognized parts for the XPG syntax:
+     *
+     *            language[_territory[.codeset]][@modifier]
+     *
+     * Beside the first all of them are allowed to be missing.  If the
+     * full specified locale is not found, the less specific one are
+     * looked for.  The various part will be stripped off according to
+     * the following order:
+     *            (1) codeset
+     *            (2) normalized codeset
+     *            (3) territory
+     *            (4) modifier
+     *
+     * So since we don't take care of the codeset part here, what patterns
+     * we need to deal with is:
+     *
+     *   1. language_territory at modifier
+     *   2. language at modifier
+     *   3. language
+     *
+     * then. and maybe no need to try language_territory here.
+     */
+    modifier = strchr ((const char *) s, '@');
+    if (modifier)
+    {
+	*modifier = 0;
+	modifier++;
+	mlen = strlen (modifier);
+    }
+    encoding = strchr ((const char *) s, '.');
+    if (encoding)
+    {
+	*encoding = 0;
+	encoding++;
+	if (modifier)
+	{
+	    memmove (encoding, modifier, mlen + 1);
+	    modifier = encoding;
+	}
+    }
+    territory = strchr ((const char *) s, '_');
+    if (!territory)
+	territory = strchr ((const char *) s, '-');
+    if (territory)
+    {
+	*territory = 0;
+	territory++;
+	tlen = strlen (territory);
+    }
+    llen = strlen ((const char *) s);
+    if (llen < 2 || llen > 3)
+    {
+	fprintf (stderr, "Fontconfig warning: ignoring %s: not a valid language tag\n",
+		 lang);
+	goto bail0;
+    }
+    if (territory && (tlen < 2 || tlen > 3))
+    {
+	fprintf (stderr, "Fontconfig warning: ignoring %s: not a valid region tag\n",
+		 lang);
+	goto bail0;
+    }
+    if (territory)
+	territory[-1] = '-';
+    if (modifier)
+	modifier[-1] = '@';
+    orig = FcStrDowncase (s);
+    if (!orig)
+	goto bail0;
+    if (territory)
+    {
+	if (FcDebug () & FC_DBG_LANGSET)
+	    printf("Checking the existence of %s.orth\n", s);
+	if (FcLangSetIndex (s) < 0)
+	{
+	    memmove (territory - 1, territory + tlen, (mlen > 0 ? mlen + 1 : 0) + 1);
+	    if (modifier)
+		modifier = territory;
+	}
+	else
+	{
+	    result = s;
+	    s = NULL;
+	    goto bail1;
+	}
+    }
+    if (modifier)
+    {
+	if (FcDebug () & FC_DBG_LANGSET)
+	    printf("Checking the existence of %s.orth\n", s);
+	if (FcLangSetIndex (s) < 0)
+	    modifier[-1] = 0;
+	else
+	{
+	    result = s;
+	    s = NULL;
+	    goto bail1;
+	}
+    }
+    if (FcDebug () & FC_DBG_LANGSET)
+	printf("Checking the existence of %s.orth\n", s);
+    if (FcLangSetIndex (s) < 0)
+    {
+	/* there seems no languages matched in orth.
+	 * add the language as is for fallback.
+	 */
+	result = orig;
+	orig = NULL;
+    }
+    else
+    {
+	result = s;
+	s = NULL;
+    }
+  bail1:
+    if (orig)
+	free (orig);
+  bail0:
+    if (s)
+	free (s);
+  bail:
+    if (FcDebug () & FC_DBG_LANGSET)
+    {
+	if (result)
+	    printf ("normalized: %s -> %s\n", lang, result);
+	else
+	    printf ("Unable to normalize %s\n", lang);
+    }
+
+    return result;
+}
+
 #define FcLangEnd(c)	((c) == '-' || (c) == '\0')
 
 FcLangResult
diff --git a/src/fcstr.c b/src/fcstr.c
index e372af0..c446bcd 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -1177,6 +1177,50 @@ FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
 }
 
 FcBool
+FcStrSetAddLangs (FcStrSet *strs, const char *languages)
+{
+    const char *p = languages, *next;
+    FcChar8 lang[128] = {0}, *normalized_lang;
+    size_t len;
+    FcBool ret = FcFalse;
+
+    if (!languages)
+	return FcFalse;
+
+    while ((next = strchr (p, ':')))
+    {
+	len = next - p;
+	len = FC_MIN (len, 128);
+	strncpy ((char *) lang, p, len);
+	lang[len] = 0;
+	/* ignore an empty item */
+	if (*lang)
+	{
+	    normalized_lang = FcLangNormalize ((const FcChar8 *) lang);
+	    if (normalized_lang)
+	    {
+		FcStrSetAdd (strs, normalized_lang);
+		free (normalized_lang);
+		ret = FcTrue;
+	    }
+	}
+	p = next + 1;
+    }
+    if (*p)
+    {
+	normalized_lang = FcLangNormalize ((const FcChar8 *) p);
+	if (normalized_lang)
+	{
+	    FcStrSetAdd (strs, normalized_lang);
+	    free (normalized_lang);
+	    ret = FcTrue;
+	}
+    }
+
+    return ret;
+}
+
+FcBool
 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
 {
     int	i;


More information about the Fontconfig mailing list