b=456545 Unify pseudo-inversion of langGrouping r=roc

This commit is contained in:
Karl Tomlinson 2008-09-26 16:40:28 +12:00
parent c4f31bbd86
commit 0dbd19de26
4 changed files with 159 additions and 315 deletions

View File

@ -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

View File

@ -21,6 +21,7 @@
* Contributor(s):
* Masayuki Nakano <masayuki@d-toybox.com>
* Vladimir Vukicevic <vladimir@pobox.com>
* Karl Tomlinson <karlt+@karlt.net>, 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 <locale.h>
#include <fontconfig/fontconfig.h>
#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<nsIAtom> 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<const FcChar8*>(lang.get());
// and cast away the const for fontconfig, that will merely make a copy.
FcPatternAddString(aPattern, FC_LANG, const_cast<FcChar8*>(fcString));
}
}
@ -256,8 +346,7 @@ gfxFontconfigUtils::GetFontListInternal(nsCStringArray& aListOfFonts,
// take the pattern and add the lang group to it
if (aLangGroup && !aLangGroup->IsEmpty()) {
nsCOMPtr<nsIAtom> langAtom = do_GetAtom(*aLangGroup);
NS_AddLangGroup(pat, langAtom);
AddLangGroup(pat, *aLangGroup);
}
fs = FcFontList(NULL, pat, os);

View File

@ -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;

View File

@ -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 <locale.h>
#include <freetype/tttables.h>
#include <cairo.h>
@ -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);