From 0dbd19de2653173f5b04e63ac9e720ce27b4f484 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Fri, 26 Sep 2008 16:40:28 +1200 Subject: [PATCH] b=456545 Unify pseudo-inversion of langGrouping r=roc --- gfx/thebes/src/Makefile.in | 5 +- gfx/thebes/src/gfxFontconfigUtils.cpp | 191 ++++++++++++++----- gfx/thebes/src/gfxFontconfigUtils.h | 13 +- gfx/thebes/src/gfxPangoFonts.cpp | 265 +------------------------- 4 files changed, 159 insertions(+), 315 deletions(-) diff --git a/gfx/thebes/src/Makefile.in b/gfx/thebes/src/Makefile.in index 0c2ef3a4ba5..affd5f1a48a 100644 --- a/gfx/thebes/src/Makefile.in +++ b/gfx/thebes/src/Makefile.in @@ -77,7 +77,7 @@ CPPSRCS += gfxOS2Fonts.cpp \ $(NULL) CPPSRCS += gfxPDFSurface.cpp EXTRA_DSO_LDOPTS += $(MOZ_CAIRO_LIBS) -REQUIRES += uconv +REQUIRES += uconv locale endif ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) @@ -92,6 +92,7 @@ ifdef MOZ_X11 CPPSRCS += gfxXlibSurface.cpp endif +REQUIRES += locale CPPSRCS += gfxPlatformGtk.cpp gfxGdkNativeRenderer.cpp CPPSRCS += gfxPDFSurface.cpp gfxPSSurface.cpp CPPSRCS += gfxFontconfigUtils.cpp @@ -113,6 +114,7 @@ CPPSRCS += gfxDirectFBSurface.cpp endif ifeq ($(MOZ_WIDGET_TOOLKIT),qt) +REQUIRES += locale CPPSRCS += gfxQtPlatform.cpp gfxQPainterSurface.cpp CPPSRCS += gfxXlibSurface.cpp gfxQtNativeRenderer.cpp CPPSRCS += gfxFT2Fonts.cpp @@ -123,6 +125,7 @@ EXTRA_DSO_LDOPTS += $(ZLIB_LIBS) $(XLDFLAGS) $(XLIBS) $(CAIRO_FT_LIBS) endif ifeq ($(MOZ_WIDGET_TOOLKIT),beos) +REQUIRES += locale CPPSRCS += gfxBeOSSurface.cpp gfxBeOSPlatform.cpp CPPSRCS += gfxPangoFonts.cpp #CPPSRCS += gfxPDFSurface.cpp diff --git a/gfx/thebes/src/gfxFontconfigUtils.cpp b/gfx/thebes/src/gfxFontconfigUtils.cpp index 9d80e924526..bdea7660d9e 100644 --- a/gfx/thebes/src/gfxFontconfigUtils.cpp +++ b/gfx/thebes/src/gfxFontconfigUtils.cpp @@ -21,6 +21,7 @@ * Contributor(s): * Masayuki Nakano * Vladimir Vukicevic + * Karl Tomlinson , Mozilla Corporation * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -39,16 +40,28 @@ #include "gfxFontconfigUtils.h" #include "gfxFont.h" +#include #include #include "nsIPrefBranch.h" #include "nsIPrefService.h" #include "nsServiceManagerUtils.h" +#include "nsILanguageAtomService.h" #include "nsIAtom.h" #include "nsCRT.h" /* static */ gfxFontconfigUtils* gfxFontconfigUtils::sUtils = nsnull; +static nsILanguageAtomService* gLangService = nsnull; + +/* static */ void +gfxFontconfigUtils::Shutdown() { + if (sUtils) { + delete sUtils; + sUtils = nsnull; + } + NS_IF_RELEASE(gLangService); +} /* static */ PRUint8 gfxFontconfigUtils::GetThebesStyle(FcPattern *aPattern) @@ -169,69 +182,146 @@ gfxFontconfigUtils::GetFontList(const nsACString& aLangGroup, return NS_OK; } -struct MozGtkLangGroup { - const char *mozLangGroup; - const FcChar8 *Lang; +struct MozLangGroupData { + const char *mozLangGroup; + const char *defaultLang; }; -const MozGtkLangGroup MozGtkLangGroups[] = { - { "x-western", (const FcChar8 *)"en" }, - { "x-central-euro", (const FcChar8 *)"pl" }, - { "x-cyrillic", (const FcChar8 *)"ru" }, - { "x-baltic", (const FcChar8 *)"lv" }, - { "x-devanagari", (const FcChar8 *)"hi" }, - { "x-tamil", (const FcChar8 *)"ta" }, - { "x-armn", (const FcChar8 *)"hy" }, - { "x-beng", (const FcChar8 *)"bn" }, - { "x-cans", (const FcChar8 *)"iu" }, - { "x-ethi", (const FcChar8 *)"am" }, - { "x-geor", (const FcChar8 *)"ka" }, - { "x-gujr", (const FcChar8 *)"gu" }, - { "x-guru", (const FcChar8 *)"pa" }, - { "x-khmr", (const FcChar8 *)"km" }, - { "x-mlym", (const FcChar8 *)"ml" }, - { "x-orya", (const FcChar8 *)"or" }, - { "x-telu", (const FcChar8 *)"te" }, - { "x-knda", (const FcChar8 *)"kn" }, - { "x-sinh", (const FcChar8 *)"si" }, - { "x-unicode", 0 }, - { "x-user-def", 0 } +const MozLangGroupData MozLangGroups[] = { + { "x-western", "en" }, + { "x-central-euro", "pl" }, + { "x-cyrillic", "ru" }, + { "x-baltic", "lv" }, + { "x-devanagari", "hi" }, + { "x-tamil", "ta" }, + { "x-armn", "hy" }, + { "x-beng", "bn" }, + { "x-cans", "iu" }, + { "x-ethi", "am" }, + { "x-geor", "ka" }, + { "x-gujr", "gu" }, + { "x-guru", "pa" }, + { "x-khmr", "km" }, + { "x-knda", "kn" }, + { "x-mlym", "ml" }, + { "x-orya", "or" }, + { "x-sinh", "si" }, + { "x-telu", "te" }, + { "x-unicode", 0 }, + { "x-user-def", 0 } }; -static const MozGtkLangGroup* -NS_FindFCLangGroup (nsACString &aLangGroup) +static PRBool +TryLangForGroup(const nsACString& aOSLang, nsIAtom *aLangGroup, + nsACString *aFcLang) { - for (unsigned int i=0; i < NS_ARRAY_LENGTH(MozGtkLangGroups); ++i) { - if (aLangGroup.Equals(MozGtkLangGroups[i].mozLangGroup, + // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'. + // aOSLang is in the form "language[_territory][.codeset][@modifier]". + // fontconfig takes languages in the form "language-territory". + // nsILanguageAtomService takes languages in the form language-subtag, + // where subtag may be a territory. fontconfig and nsILanguageAtomService + // handle case-conversion for us. + const char *pos, *end; + aOSLang.BeginReading(pos); + aOSLang.EndReading(end); + aFcLang->Truncate(); + while (pos < end) { + switch (*pos) { + case '.': + case '@': + end = pos; + break; + case '_': + aFcLang->Append('-'); + break; + default: + aFcLang->Append(*pos); + } + ++pos; + } + + nsIAtom *atom = + gLangService->LookupLanguage(NS_ConvertUTF8toUTF16(*aFcLang)); + + return atom == aLangGroup; +} + +/* static */ void +gfxFontconfigUtils::GetSampleLangForGroup(const nsACString& aLangGroup, + nsACString *aFcLang) +{ + NS_PRECONDITION(aFcLang != nsnull, "aFcLang must not be NULL"); + + const MozLangGroupData *langGroup = nsnull; + + for (unsigned int i=0; i < NS_ARRAY_LENGTH(MozLangGroups); ++i) { + if (aLangGroup.Equals(MozLangGroups[i].mozLangGroup, nsCaseInsensitiveCStringComparator())) { - return &MozGtkLangGroups[i]; + langGroup = &MozLangGroups[i]; + break; } } - return nsnull; + if (!langGroup) { + // Not a special mozilla language group. + // Use aLangGroup as a language code. + aFcLang->Assign(aLangGroup); + return; + } + + // Check the environment for the users preferred language that corresponds + // to this langGroup. + if (!gLangService) { + CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); + } + + if (gLangService) { + nsRefPtr langGroupAtom = do_GetAtom(langGroup->mozLangGroup); + + const char *languages = getenv("LANGUAGE"); + if (languages) { + const char separator = ':'; + + for (const char *pos = languages; PR_TRUE; ++pos) { + if (*pos == '\0' || *pos == separator) { + if (languages < pos && + TryLangForGroup(Substring(languages, pos), + langGroupAtom, aFcLang)) + return; + + if (*pos == '\0') + break; + + languages = pos + 1; + } + } + } + const char *ctype = setlocale(LC_CTYPE, NULL); + if (ctype && + TryLangForGroup(nsDependentCString(ctype), langGroupAtom, aFcLang)) + return; + } + + if (langGroup->defaultLang) { + aFcLang->Assign(langGroup->defaultLang); + } else { + aFcLang->Truncate(); + } } static void -NS_AddLangGroup(FcPattern *aPattern, nsIAtom *aLangGroup) +AddLangGroup(FcPattern *aPattern, const nsACString& aLangGroup) { - // Find the FC lang group for this lang group - nsCAutoString cname; - aLangGroup->ToUTF8String(cname); + // Translate from mozilla's internal mapping into fontconfig's + nsCAutoString lang; + gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang); - // see if the lang group needs to be translated from mozilla's - // internal mapping into fontconfig's - const struct MozGtkLangGroup *langGroup; - langGroup = NS_FindFCLangGroup(cname); - - // if there's no lang group, just use the lang group as it was - // passed to us - // - // we're casting away the const here for the strings - should be - // safe. - if (!langGroup) - FcPatternAddString(aPattern, FC_LANG, (FcChar8 *)cname.get()); - else if (langGroup->Lang) - FcPatternAddString(aPattern, FC_LANG, (FcChar8 *)langGroup->Lang); + if (!lang.IsEmpty()) { + // cast from signed chars used in nsString to unsigned in fontconfig + const FcChar8 *fcString = reinterpret_cast(lang.get()); + // and cast away the const for fontconfig, that will merely make a copy. + FcPatternAddString(aPattern, FC_LANG, const_cast(fcString)); + } } @@ -256,8 +346,7 @@ gfxFontconfigUtils::GetFontListInternal(nsCStringArray& aListOfFonts, // take the pattern and add the lang group to it if (aLangGroup && !aLangGroup->IsEmpty()) { - nsCOMPtr langAtom = do_GetAtom(*aLangGroup); - NS_AddLangGroup(pat, langAtom); + AddLangGroup(pat, *aLangGroup); } fs = FcFontList(NULL, pat, os); diff --git a/gfx/thebes/src/gfxFontconfigUtils.h b/gfx/thebes/src/gfxFontconfigUtils.h index 310d36fd3a8..6684ea2a50e 100644 --- a/gfx/thebes/src/gfxFontconfigUtils.h +++ b/gfx/thebes/src/gfxFontconfigUtils.h @@ -62,10 +62,7 @@ public: return sUtils; } - static void Shutdown() { - delete sUtils; - sUtils = nsnull; - } + static void Shutdown(); nsresult GetFontList(const nsACString& aLangGroup, const nsACString& aGenericFamily, @@ -82,6 +79,14 @@ public: static PRUint8 GetThebesStyle(FcPattern *aPattern); // slant static PRUint16 GetThebesWeight(FcPattern *aPattern); + /** + * @param aLangGroup [in] a Mozilla langGroup. + * @param aFcLang [out] returns a language suitable for fontconfig + * matching |aLangGroup| or an empty string if no match is found. + */ + static void GetSampleLangForGroup(const nsACString& aLangGroup, + nsACString *aFcLang); + protected: static gfxFontconfigUtils* sUtils; diff --git a/gfx/thebes/src/gfxPangoFonts.cpp b/gfx/thebes/src/gfxPangoFonts.cpp index 773e703757f..185931e4270 100644 --- a/gfx/thebes/src/gfxPangoFonts.cpp +++ b/gfx/thebes/src/gfxPangoFonts.cpp @@ -48,24 +48,12 @@ #include "prlink.h" #include "gfxTypes.h" -#include "nsUnicodeRange.h" - -#include "nsIPref.h" -#include "nsIPrefBranch.h" -#include "nsIPrefService.h" -#include "nsServiceManagerUtils.h" #include "nsMathUtils.h" -#include "nsVoidArray.h" -#include "nsPromiseFlatString.h" - #include "gfxContext.h" #include "gfxPlatformGtk.h" #include "gfxPangoFonts.h" -#include "nsCRT.h" - -#include #include #include @@ -1714,262 +1702,21 @@ out: g_object_unref(context); } - - -/** - ** language group helpers - **/ - -struct MozPangoLangGroup { - const char *mozLangGroup; - const char *PangoLang; -}; - -static const MozPangoLangGroup MozPangoLangGroups[] = { - { "x-western", "en" }, - { "x-central-euro", "pl" }, - { "ja", "ja" }, - { "zh-TW", "zh-tw" }, - { "zh-CN", "zh-cn" }, - { "zh-HK", "zh-hk" }, - { "ko", "ko" }, - { "x-cyrillic", "ru" }, - { "x-baltic", "lv" }, - { "el", "el" }, - { "tr", "tr" }, - { "th", "th" }, - { "he", "he" }, - { "ar", "ar" }, - { "x-devanagari", "hi" }, - { "x-tamil", "ta" }, - { "x-armn", "ar" }, - { "x-beng", "bn" }, - { "x-ethi", "et" }, - { "x-geor", "ka" }, - { "x-gujr", "gu" }, - { "x-guru", "pa" }, - { "x-khmr", "km" }, - { "x-mlym", "ml" }, - { "x-cans", "iu" }, - { "x-unicode", 0 }, - { "x-user-def", 0 }, -}; - -#define NUM_PANGO_LANG_GROUPS (sizeof (MozPangoLangGroups) / \ - sizeof (MozPangoLangGroups[0])) - /* static */ PangoLanguage * -GetPangoLanguage(const nsACString& cname) +GetPangoLanguage(const nsACString& aLangGroup) { // see if the lang group needs to be translated from mozilla's // internal mapping into fontconfig's - const struct MozPangoLangGroup *langGroup = nsnull; + nsCAutoString lang; + gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang); - for (unsigned int i=0; i < NUM_PANGO_LANG_GROUPS; ++i) { - if (cname.Equals(MozPangoLangGroups[i].mozLangGroup, - nsCaseInsensitiveCStringComparator())) { - langGroup = &MozPangoLangGroups[i]; - break; - } - } + if (lang.IsEmpty()) + return NULL; - // if there's no lang group, just use the lang group as it was - // passed to us - // - // we're casting away the const here for the strings - should be - // safe. - if (!langGroup) - return pango_language_from_string(nsPromiseFlatCString(cname).get()); - else if (langGroup->PangoLang) - return pango_language_from_string(langGroup->PangoLang); - - return nsnull; + return pango_language_from_string(lang.get()); } -// See pango-script-lang-table.h in pango. -static const MozPangoLangGroup PangoAllLangGroup[] = { - { "x-western", "aa" }, - { "x-cyrillic", "ab" }, - { "x-western", "af" }, - { "x-ethi", "am" }, - { "ar", "ar" }, - { "x-western", "ast" }, - { "x-cyrillic", "ava" }, - { "x-western", "ay" }, - { "x-western", "az" }, - { "x-cyrillic", "ba" }, - { "x-western", "bam" }, - { "x-cyrillic", "be" }, - { "x-cyrillic", "bg" }, - { "x-devanagari", "bh" }, - { "x-devanagari", "bho" }, - { "x-western", "bi" }, - { "x-western", "bin" }, - { "x-beng", "bn" }, - { 0, "bo" }, // PANGO_SCRIPT_TIBETAN - { "x-western", "br" }, - { "x-western", "bs" }, - { "x-cyrillic", "bua" }, - { "x-western", "ca" }, - { "x-cyrillic", "ce" }, - { "x-western", "ch" }, - { "x-cyrillic", "chm" }, - { 0, "chr" }, // PANGO_SCRIPT_CHEROKEE - { "x-western", "co" }, - { "x-central-euro", "cs" }, // PANGO_SCRIPT_LATIN - { "x-cyrillic", "cu" }, - { "x-cyrillic", "cv" }, - { "x-western", "cy" }, - { "x-western", "da" }, - { "x-central-euro", "de" }, // PANGO_SCRIPT_LATIN - { 0, "dz" }, // PANGO_SCRIPT_TIBETAN - { "el", "el" }, - { "x-western", "en" }, - { "x-western", "eo" }, - { "x-western", "es" }, - { "x-western", "et" }, - { "x-western", "eu" }, - { "ar", "fa" }, - { "x-western", "fi" }, - { "x-western", "fj" }, - { "x-western", "fo" }, - { "x-western", "fr" }, - { "x-western", "ful" }, - { "x-western", "fur" }, - { "x-western", "fy" }, - { "x-western", "ga" }, - { "x-western", "gd" }, - { "x-ethi", "gez" }, - { "x-western", "gl" }, - { "x-western", "gn" }, - { "x-gujr", "gu" }, - { "x-western", "gv" }, - { "x-western", "ha" }, - { "x-western", "haw" }, - { "he", "he" }, - { "x-devanagari", "hi" }, - { "x-western", "ho" }, - { "x-central-euro", "hr" }, // PANGO_SCRIPT_LATIN - { "x-western", "hu" }, - { "x-armn", "hy" }, - { "x-western", "ia" }, - { "x-western", "ibo" }, - { "x-western", "id" }, - { "x-western", "ie" }, - { "x-cyrillic", "ik" }, - { "x-western", "io" }, - { "x-western", "is" }, - { "x-western", "it" }, - { "x-cans", "iu" }, - { "ja", "ja" }, - { "x-geor", "ka" }, - { "x-cyrillic", "kaa" }, - { "x-western", "ki" }, - { "x-cyrillic", "kk" }, - { "x-western", "kl" }, - { "x-khmr", "km" }, - { 0, "kn" }, // PANGO_SCRIPT_KANNADA - { "ko", "ko" }, - { "x-devanagari", "kok" }, - { "x-devanagari", "ks" }, - { "x-cyrillic", "ku" }, - { "x-cyrillic", "kum" }, - { "x-cyrillic", "kv" }, - { "x-western", "kw" }, - { "x-cyrillic", "ky" }, - { "x-western", "la" }, - { "x-western", "lb" }, - { "x-cyrillic", "lez" }, - { 0, "lo" }, // PANGO_SCRIPT_LAO - { "x-western", "lt" }, - { "x-western", "lv" }, - { "x-western", "mg" }, - { "x-western", "mh" }, - { "x-western", "mi" }, - { "x-cyrillic", "mk" }, - { "x-mlym", "ml" }, - { 0, "mn" }, // PANGO_SCRIPT_MONGOLIAN - { "x-western", "mo" }, - { "x-devanagari", "mr" }, - { "x-western", "mt" }, - { 0, "my" }, // PANGO_SCRIPT_MYANMAR - { "x-western", "nb" }, - { "x-devanagari", "ne" }, - { "x-western", "nl" }, - { "x-western", "nn" }, - { "x-western", "no" }, - { "x-western", "ny" }, - { "x-western", "oc" }, - { "x-western", "om" }, - { 0, "or" }, // PANGO_SCRIPT_ORIYA - { "x-cyrillic", "os" }, - { "x-central-euro", "pl" }, // PANGO_SCRIPT_LATIN - { "x-western", "pt" }, - { "x-western", "rm" }, - { "x-western", "ro" }, - { "x-cyrillic", "ru" }, - { "x-devanagari", "sa" }, - { "x-cyrillic", "sah" }, - { "x-western", "sco" }, - { "x-western", "se" }, - { "x-cyrillic", "sel" }, - { "x-cyrillic", "sh" }, - { 0, "si" }, // PANGO_SCRIPT_SINHALA - { "x-central-euro", "sk" }, // PANGO_SCRIPT_LATIN - { "x-central-euro", "sl" }, // PANGO_SCRIPT_LATIN - { "x-western", "sm" }, - { "x-western", "sma" }, - { "x-western", "smj" }, - { "x-western", "smn" }, - { "x-western", "sms" }, - { "x-western", "so" }, - { "x-western", "sq" }, - { "x-cyrillic", "sr" }, - { "x-western", "sv" }, - { "x-western", "sw" }, - { 0, "syr" }, // PANGO_SCRIPT_SYRIAC - { "x-tamil", "ta" }, - { 0, "te" }, // PANGO_SCRIPT_TELUGU - { "x-cyrillic", "tg" }, - { "th", "th" }, - { "x-ethi", "ti-er" }, - { "x-ethi", "ti-et" }, - { "x-ethi", "tig" }, - { "x-cyrillic", "tk" }, - { 0, "tl" }, // PANGO_SCRIPT_TAGALOG - { "x-western", "tn" }, - { "x-western", "to" }, - { "x-western", "tr" }, - { "x-western", "ts" }, - { "x-cyrillic", "tt" }, - { "x-western", "tw" }, - { "x-cyrillic", "tyv" }, - { "ar", "ug" }, - { "x-cyrillic", "uk" }, - { "ar", "ur" }, - { "x-cyrillic", "uz" }, - { "x-western", "ven" }, - { "x-western", "vi" }, - { "x-western", "vo" }, - { "x-western", "vot" }, - { "x-western", "wa" }, - { "x-western", "wen" }, - { "x-western", "wo" }, - { "x-western", "xh" }, - { "x-western", "yap" }, - { "he", "yi" }, - { "x-western", "yo" }, - { "zh-CN", "zh-cn" }, - { "zh-HK", "zh-hk" }, - { "zh-HK", "zh-mo" }, - { "zh-CN", "zh-sg" }, - { "zh-TW", "zh-tw" }, - { "x-western", "zu" }, -}; - -#define NUM_PANGO_ALL_LANG_GROUPS (G_N_ELEMENTS (PangoAllLangGroup)) - gfxPangoFontCache::gfxPangoFontCache() { mPangoFonts.Init(500);