diff --git a/mozilla/gfx/thebes/public/gfxAtsuiFonts.h b/mozilla/gfx/thebes/public/gfxAtsuiFonts.h index 446a6b5e468..1e9c9999b4c 100644 --- a/mozilla/gfx/thebes/public/gfxAtsuiFonts.h +++ b/mozilla/gfx/thebes/public/gfxAtsuiFonts.h @@ -144,6 +144,9 @@ public: return nsnull; } + // search through pref fonts for a character, return nsnull if no matching pref font + already_AddRefed WhichPrefFontSupportsChar(PRUint32 aCh); + already_AddRefed FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNextCh, gfxAtsuiFont* aPrevMatchedFont); protected: diff --git a/mozilla/gfx/thebes/public/gfxPlatform.h b/mozilla/gfx/thebes/public/gfxPlatform.h index 82e995e1c76..716004d2f5a 100644 --- a/mozilla/gfx/thebes/public/gfxPlatform.h +++ b/mozilla/gfx/thebes/public/gfxPlatform.h @@ -56,6 +56,48 @@ class gfxImageSurface; class gfxFontGroup; struct gfxFontStyle; +// pref lang id's for font prefs +// !!! needs to match the list of pref font.default.xx entries listed in all.js !!! + +enum eFontPrefLang { + eFontPrefLang_Western = 0, + eFontPrefLang_CentEuro = 1, + eFontPrefLang_Japanese = 2, + eFontPrefLang_ChineseTW = 3, + eFontPrefLang_ChineseCN = 4, + eFontPrefLang_ChineseHK = 5, + eFontPrefLang_Korean = 6, + eFontPrefLang_Cyrillic = 7, + eFontPrefLang_Baltic = 8, + eFontPrefLang_Greek = 9, + eFontPrefLang_Turkish = 10, + eFontPrefLang_Thai = 11, + eFontPrefLang_Hebrew = 12, + eFontPrefLang_Arabic = 13, + eFontPrefLang_Devanagari = 14, + eFontPrefLang_Tamil = 15, + eFontPrefLang_Armenian = 16, + eFontPrefLang_Bengali = 17, + eFontPrefLang_Canadian = 18, + eFontPrefLang_Ethiopic = 19, + eFontPrefLang_Georgian = 20, + eFontPrefLang_Gujarati = 21, + eFontPrefLang_Gurmukhi = 22, + eFontPrefLang_Khmer = 23, + eFontPrefLang_Malayalam = 24, + + eFontPrefLang_LangCount = 25, // except Others and UserDefined. + + eFontPrefLang_Others = 25, // x-unicode + eFontPrefLang_UserDefined = 26, + + eFontPrefLang_CJKSet = 27, // special code for CJK set + eFontPrefLang_AllCount = 28 +}; + +// when searching through pref langs, max number of pref langs +const PRUint32 kMaxLenPrefLangList = 30; + class THEBES_API gfxPlatform { public: /** @@ -135,6 +177,29 @@ public: void GetPrefFonts(const char *aLangGroup, nsString& array, PRBool aAppendUnicode = PR_TRUE); + /** + * Iterate over pref fonts given a list of lang groups. For a single lang + * group, multiple pref fonts are possible. If error occurs, returns PR_FALSE, + * PR_TRUE otherwise. Callback returns PR_FALSE to abort process. + */ + typedef PRBool (*PrefFontCallback) (eFontPrefLang aLang, const nsAString& aName, + void *aClosure); + static PRBool ForEachPrefFont(eFontPrefLang aLangArray[], PRUint32 aLangArrayLen, + PrefFontCallback aCallback, + void *aClosure); + + // convert a lang group string to enum constant (i.e. "zh-TW" ==> eFontPrefLang_ChineseTW) + static eFontPrefLang GetFontPrefLangFor(const char* aLang); + + // convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW ==> "zh-TW") + static const char* GetPrefLangName(eFontPrefLang aLang); + + // returns true if a pref lang is CJK + static PRBool IsLangCJK(eFontPrefLang aLang); + + // helper method to add a pref lang to an array, if not already in array + static void AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPrefLang aAddLang); + /** * Are we going to try color management? */ diff --git a/mozilla/gfx/thebes/public/gfxPlatformMac.h b/mozilla/gfx/thebes/public/gfxPlatformMac.h index ea725c95a09..bd3e4803d56 100644 --- a/mozilla/gfx/thebes/public/gfxPlatformMac.h +++ b/mozilla/gfx/thebes/public/gfxPlatformMac.h @@ -39,6 +39,7 @@ #ifndef GFX_PLATFORM_MAC_H #define GFX_PLATFORM_MAC_H +#include "nsTArray.h" #include "gfxPlatform.h" class THEBES_API gfxPlatformMac : public gfxPlatform { @@ -64,8 +65,16 @@ public: nsStringArray& aListOfFonts); nsresult UpdateFontList(); + // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs + void GetLangPrefs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang); + private: + void gfxPlatformMac::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, + eFontPrefLang aCharLang, eFontPrefLang aPageLang); + virtual cmsHPROFILE GetPlatformCMSOutputProfile(); + + nsTArray mCJKPrefLangs; }; #endif /* GFX_PLATFORM_MAC_H */ diff --git a/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp b/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp index 78d19760c95..de364c86690 100644 --- a/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp +++ b/mozilla/gfx/thebes/src/gfxAtsuiFonts.cpp @@ -48,6 +48,7 @@ #include "gfxContext.h" #include "gfxPlatform.h" +#include "gfxPlatformMac.h" #include "gfxAtsuiFonts.h" #include "gfxFontTest.h" @@ -58,16 +59,15 @@ #include "gfxQuartzSurface.h" #include "gfxQuartzFontCache.h" -#include "nsIPrefBranch.h" -#include "nsIPrefService.h" -#include "nsIPrefLocalizedString.h" -#include "nsServiceManagerUtils.h" #include "nsUnicodeRange.h" -#include "nsCRT.h" // Uncomment this to dump all text runs created to stdout // #define DUMP_TEXT_RUNS +#ifdef DUMP_TEXT_RUNS +static PRLogModuleInfo *gAtsuiTextRunLog = PR_NewLogModule("atsuiTextRun"); +#endif + #define ROUND(x) (floor((x) + 0.5)) /* 10.5 SDK includes a funky new definition of FloatToFixed, so reset to old-style definition */ @@ -88,80 +88,6 @@ OSStatus ATSInitializeGlyphVector(int size, void *glyphVectorPtr); OSStatus ATSClearGlyphVector(void *glyphVectorPtr); #endif -// The lang names for eFontPrefLang -// this needs to match the list of pref font.default.xx entries listed in all.js! -static const char *gPrefLangNames[] = { - "x-western", - "x-central-euro", - "ja", - "zh-TW", - "zh-CN", - "zh-HK", - "ko", - "x-cyrillic", - "x-baltic", - "el", - "tr", - "th", - "he", - "ar", - "x-devanagari", - "x-tamil", - "x-armn", - "x-beng", - "x-cans", - "x-ethi", - "x-geor", - "x-gujr", - "x-guru", - "x-khmr", - "x-mlym", - "x-unicode", - "x-user-def" -}; - -// The lang IDs for font prefs -// this needs to match the list of pref font.default.xx entries listed in all.js! -enum eFontPrefLang { - eFontPrefLang_Western = 0, - eFontPrefLang_CentEuro = 1, - eFontPrefLang_Japanese = 2, - eFontPrefLang_ChineseTW = 3, - eFontPrefLang_ChineseCN = 4, - eFontPrefLang_ChineseHK = 5, - eFontPrefLang_Korean = 6, - eFontPrefLang_Cyrillic = 7, - eFontPrefLang_Baltic = 8, - eFontPrefLang_Greek = 9, - eFontPrefLang_Turkish = 10, - eFontPrefLang_Thai = 11, - eFontPrefLang_Hebrew = 12, - eFontPrefLang_Arabic = 13, - eFontPrefLang_Devanagari = 14, - eFontPrefLang_Tamil = 15, - eFontPrefLang_Armenian = 16, - eFontPrefLang_Bengali = 17, - eFontPrefLang_Canadian = 18, - eFontPrefLang_Ethiopic = 19, - eFontPrefLang_Georgian = 20, - eFontPrefLang_Gujarati = 21, - eFontPrefLang_Gurmukhi = 22, - eFontPrefLang_Khmer = 23, - eFontPrefLang_Malayalam = 24, - - eFontPrefLang_LangCount = 25, // except Others and UserDefined. - - eFontPrefLang_Others = 25, // x-unicode - eFontPrefLang_UserDefined = 26, - - eFontPrefLang_CJKSet = 27, // special code for CJK set - eFontPrefLang_AllCount = 28 -}; - -static nsresult AppendAllPrefFonts(nsTArray > *aFonts, - eFontPrefLang aLang, PRUint32& didAppendBits, const gfxFontStyle *aStyle); - -static eFontPrefLang GetFontPrefLangFor(const char* aLang); eFontPrefLang GetFontPrefLangFor(PRUint8 aUnicodeRange); gfxAtsuiFont::gfxAtsuiFont(MacOSFontEntry *aFontEntry, @@ -735,6 +661,78 @@ gfxAtsuiFontGroup::HasFont(ATSUFontID fid) return PR_FALSE; } +struct PrefFontCallbackData { + PrefFontCallbackData(nsTArray >& aFamiliesArray) + : mPrefFamilies(aFamiliesArray) + {} + + nsTArray >& mPrefFamilies; + + static PRBool AddFontFamilyEntry(eFontPrefLang aLang, const nsAString& aName, void *aClosure) + { + PrefFontCallbackData *prefFontData = (PrefFontCallbackData*) aClosure; + + MacOSFamilyEntry *family = gfxQuartzFontCache::SharedFontCache()->FindFamily(aName); + if (family) { + prefFontData->mPrefFamilies.AppendElement(family); + } + return PR_TRUE; + } +}; + + +already_AddRefed +gfxAtsuiFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) +{ + // FindCharUnicodeRange only supports BMP character points and there are no non-BMP fonts in prefs + if (aCh > 0xFFFF) + return nsnull; + + // get the pref font list if it hasn't been set up already + PRUint32 unicodeRange = FindCharUnicodeRange(aCh); + eFontPrefLang charLang = GetFontPrefLangFor(unicodeRange); + eFontPrefLang pageLang = gfxPlatform::GetFontPrefLangFor(mStyle.langGroup.get()); + + // based on char lang and page lang, set up list of pref lang fonts to check + eFontPrefLang prefLangs[kMaxLenPrefLangList]; + PRUint32 i, numLangs = 0; + + gfxPlatformMac *macPlatform = gfxPlatformMac::GetPlatform(); + macPlatform->GetLangPrefs(prefLangs, numLangs, charLang, pageLang); + + for (i = 0; i < numLangs; i++) { + nsAutoTArray, 5> families; + + gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache(); + + // get the pref families for a single pref lang + if (!fc->GetPrefFontFamilyEntries(charLang, &families)) { + eFontPrefLang prefLangs[1] = { charLang }; + PrefFontCallbackData prefFontData(families); + gfxPlatform::ForEachPrefFont(prefLangs, 1, PrefFontCallbackData::AddFontFamilyEntry, + &prefFontData); + fc->SetPrefFontFamilyEntries(charLang, families); + } + + // find the first pref font that includes the character + PRUint32 i, numPrefs; + numPrefs = families.Length(); + for (i = 0; i < numPrefs; i++) { + // look up the appropriate face + MacOSFamilyEntry *family = families[i]; + if (family) { + MacOSFontEntry *fe = family->FindFont(&mStyle); + // if ch in cmap, create and return a gfxFont + if (fe && fe->TestCharacterMap(aCh)) { + return GetOrMakeFont(fe, &mStyle); + } + } + } + } + + return nsnull; +} + already_AddRefed gfxAtsuiFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNextCh, gfxAtsuiFont* aPrevMatchedFont) { @@ -760,23 +758,9 @@ gfxAtsuiFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNex return selectedFont.forget(); // 2. search pref fonts if none of the font group fonts match - if (aCh <= 0xFFFF) { // FindCharUnicodeRange only supports BMP character points and there are no non-BMP fonts in prefs - nsresult rv; - PRUint32 unicodeRange = FindCharUnicodeRange(aCh); - PRUint32 didAppendFonts = 0; - - nsAutoTArray, 15> prefFonts; - - // xxx - god this sucks to be doing this per-character in the fallback case - eFontPrefLang prefLang = GetFontPrefLangFor(unicodeRange); - - rv = AppendAllPrefFonts(&prefFonts, prefLang, didAppendFonts, GetStyle()); - if (!NS_FAILED(rv)) { - selectedFont = WhichFontSupportsChar(prefFonts, aCh); - if (selectedFont) { - return selectedFont.forget(); - } - } + // FindCharUnicodeRange only supports BMP character points and there are no non-BMP fonts in prefs + if ((selectedFont = WhichPrefFontSupportsChar(aCh))) { + return selectedFont.forget(); } // 3. use fallback fonts @@ -1140,22 +1124,13 @@ PostLayoutOperationCallback(ATSULayoutOperationSelector iCurrentOperation, return noErr; } -static eFontPrefLang -GetFontPrefLangFor(const char* aLang) -{ - if (!aLang || aLang[0]) - return eFontPrefLang_Others; - for (PRUint32 i = 0; i < PRUint32(eFontPrefLang_LangCount); ++i) { - if (!PL_strcasecmp(gPrefLangNames[i], aLang)) - return eFontPrefLang(i); - } - return eFontPrefLang_Others; -} +// xxx - leaving this here for now, probably belongs in platform code somewhere eFontPrefLang GetFontPrefLangFor(PRUint8 aUnicodeRange) { switch (aUnicodeRange) { + case kRangeSetLatin: return eFontPrefLang_Western; case kRangeCyrillic: return eFontPrefLang_Cyrillic; case kRangeGreek: return eFontPrefLang_Greek; case kRangeTurkish: return eFontPrefLang_Turkish; @@ -1183,169 +1158,6 @@ GetFontPrefLangFor(PRUint8 aUnicodeRange) } } -static const char* -GetPrefLangName(eFontPrefLang aLang) -{ - if (PRUint32(aLang) < PRUint32(eFontPrefLang_AllCount)) - return gPrefLangNames[PRUint32(aLang)]; - return nsnull; -} - -struct AFLClosure { - const gfxFontStyle *style; - nsTArray > *fontArray; -}; - -// xxx - this is almost identical to the static method FindATSUFont, -// except for the closure struct used, we should merge these -PRBool -AppendFontToList(const nsAString& aName, - const nsACString& aGenericName, - void *closure) -{ - struct AFLClosure *afl = (struct AFLClosure *) closure; - - gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache(); - - MacOSFontEntry *fe = fc->FindFontForFamily(aName, afl->style); - - if (fe) { - nsRefPtr font = GetOrMakeFont(fe, afl->style); - if (font) { - afl->fontArray->AppendElement(font); - } - } - - return PR_TRUE; -} - -static nsresult -AppendPrefFonts(nsTArray > *aFonts, - eFontPrefLang aLang, - PRUint32& didAppendBits, - const gfxFontStyle *aStyle) -{ - if (didAppendBits & (1 << aLang)) - return NS_OK; - - didAppendBits |= (1 << aLang); - - const char* langGroup = GetPrefLangName(aLang); - if (!langGroup || !langGroup[0]) { - NS_ERROR("The langGroup is null"); - return NS_ERROR_FAILURE; - } - gfxPlatform *platform = gfxPlatform::GetPlatform(); - NS_ENSURE_TRUE(platform, NS_ERROR_OUT_OF_MEMORY); - nsString fonts; - platform->GetPrefFonts(langGroup, fonts, PR_FALSE); - if (fonts.IsEmpty()) - return NS_OK; - - struct AFLClosure afl = { aStyle, aFonts }; - gfxFontGroup::ForEachFont(fonts, nsDependentCString(langGroup), - AppendFontToList, &afl); - return NS_OK; -} - -static nsresult -AppendCJKPrefFonts(nsTArray > *aFonts, - PRUint32& didAppendBits, - const gfxFontStyle *aStyle) -{ - nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); - - // Add the CJK pref fonts from accept languages, the order should be same order - nsCAutoString list; - nsresult rv; - if (prefs) { - nsCOMPtr prefString; - rv = prefs->GetComplexValue("intl.accept_languages", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(prefString)); - if (prefString) { - nsAutoString temp; - prefString->ToString(getter_Copies(temp)); - LossyCopyUTF16toASCII(temp, list); - } - } - - if (NS_SUCCEEDED(rv) && !list.IsEmpty()) { - const char kComma = ','; - const char *p, *p_end; - list.BeginReading(p); - list.EndReading(p_end); - while (p < p_end) { - while (nsCRT::IsAsciiSpace(*p)) { - if (++p == p_end) - break; - } - if (p == p_end) - break; - const char *start = p; - while (++p != p_end && *p != kComma) - /* nothing */ ; - nsCAutoString lang(Substring(start, p)); - lang.CompressWhitespace(PR_FALSE, PR_TRUE); - eFontPrefLang fpl = GetFontPrefLangFor(lang.get()); - switch (fpl) { - case eFontPrefLang_Japanese: - case eFontPrefLang_Korean: - case eFontPrefLang_ChineseCN: - case eFontPrefLang_ChineseHK: - case eFontPrefLang_ChineseTW: - rv = AppendPrefFonts(aFonts, fpl, didAppendBits, aStyle); - NS_ENSURE_SUCCESS(rv, rv); - break; - default: - break; - } - p++; - } - } - - // Prefer the system locale if it is CJK. - ScriptCode sysScript = ::GetScriptManagerVariable(smSysScript); - // XXX Is not there the HK locale? - switch (sysScript) { - case smJapanese: rv = AppendPrefFonts(aFonts, eFontPrefLang_Japanese, didAppendBits, aStyle); break; - case smTradChinese: rv = AppendPrefFonts(aFonts, eFontPrefLang_ChineseTW, didAppendBits, aStyle); break; - case smKorean: rv = AppendPrefFonts(aFonts, eFontPrefLang_Korean, didAppendBits, aStyle); break; - case smSimpChinese: rv = AppendPrefFonts(aFonts, eFontPrefLang_ChineseCN, didAppendBits, aStyle); break; - default: rv = NS_OK; - } - NS_ENSURE_SUCCESS(rv, rv); - - // last resort... (the order is same as old gfx.) - rv = AppendPrefFonts(aFonts, eFontPrefLang_Japanese, didAppendBits, aStyle); - NS_ENSURE_SUCCESS(rv, rv); - rv = AppendPrefFonts(aFonts, eFontPrefLang_Korean, didAppendBits, aStyle); - NS_ENSURE_SUCCESS(rv, rv); - rv = AppendPrefFonts(aFonts, eFontPrefLang_ChineseCN, didAppendBits, aStyle); - NS_ENSURE_SUCCESS(rv, rv); - rv = AppendPrefFonts(aFonts, eFontPrefLang_ChineseHK, didAppendBits, aStyle); - NS_ENSURE_SUCCESS(rv, rv); - rv = AppendPrefFonts(aFonts, eFontPrefLang_ChineseTW, didAppendBits, aStyle); - return rv; -} - -static nsresult -AppendAllPrefFonts(nsTArray > *aFonts, - eFontPrefLang aLang, - PRUint32& didAppendBits, - const gfxFontStyle *aStyle) -{ - nsresult rv; - - if (aLang == eFontPrefLang_CJKSet) - rv = AppendCJKPrefFonts(aFonts, didAppendBits, aStyle); - else - rv = AppendPrefFonts(aFonts, aLang, didAppendBits, aStyle); - - if (NS_FAILED(rv)) return rv; - - rv = AppendPrefFonts(aFonts, eFontPrefLang_Others, didAppendBits, aStyle); - return rv; -} - static void DisableOptionalLigaturesInStyle(ATSUStyle aStyle) { @@ -1510,10 +1322,6 @@ SetLayoutRangeToFont(ATSUTextLayout layout, ATSUStyle mainStyle, UniCharArrayOff return subStyle; } -#ifdef DUMP_TEXT_RUNS -static PRLogModuleInfo *gAtsuiTextRunLog = PR_NewLogModule("atsuiTextRun"); -#endif - PRBool gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength, @@ -1532,7 +1340,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun, #ifdef DUMP_TEXT_RUNS NS_ConvertUTF16toUTF8 str(realString, aSegmentLength); NS_ConvertUTF16toUTF8 families(mFamilies); - PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun %p fontgroup %p (%s) len %d TEXTRUN \"%s\" ENDTEXTRUN\n", aRun, this, families.get(), aSegmentLength, str.get()) ); + PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun %p fontgroup %p (%s) lang: %s len %d TEXTRUN \"%s\" ENDTEXTRUN\n", aRun, this, families.get(), mStyle.langGroup.get(), aSegmentLength, str.get()) ); PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG, ("InitTextRun font: %s\n", NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get()) ); #endif diff --git a/mozilla/gfx/thebes/src/gfxPlatform.cpp b/mozilla/gfx/thebes/src/gfxPlatform.cpp index 2875bf4bf29..d5f2b2767a1 100644 --- a/mozilla/gfx/thebes/src/gfxPlatform.cpp +++ b/mozilla/gfx/thebes/src/gfxPlatform.cpp @@ -65,6 +65,7 @@ #include "cairo.h" #include "lcms.h" +#include "plstr.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" @@ -75,6 +76,39 @@ static cmsHTRANSFORM gCMSRGBTransform = nsnull; static cmsHTRANSFORM gCMSInverseRGBTransform = nsnull; static cmsHTRANSFORM gCMSRGBATransform = nsnull; +// this needs to match the list of pref font.default.xx entries listed in all.js! +// the order *must* match the order in eFontPrefLang +static const char *gPrefLangNames[] = { + "x-western", + "x-central-euro", + "ja", + "zh-TW", + "zh-CN", + "zh-HK", + "ko", + "x-cyrillic", + "x-baltic", + "el", + "tr", + "th", + "he", + "ar", + "x-devanagari", + "x-tamil", + "x-armn", + "x-beng", + "x-cans", + "x-ethi", + "x-geor", + "x-gujr", + "x-guru", + "x-khmr", + "x-mlym", + "x-unicode", + "x-user-def" +}; + + gfxPlatform* gfxPlatform::GetPlatform() { @@ -285,6 +319,102 @@ gfxPlatform::GetPrefFonts(const char *aLangGroup, nsString& aFonts, PRBool aAppe AppendGenericFontFromPref(aFonts, "x-unicode", nsnull); } +PRBool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], PRUint32 aLangArrayLen, PrefFontCallback aCallback, + void *aClosure) +{ + nsresult rv; + + nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); + if (!prefs) + return PR_FALSE; + + PRUint32 i; + + for (i = 0; i < aLangArrayLen; i++) { + eFontPrefLang prefLang = aLangArray[i]; + const char *langGroup = GetPrefLangName(prefLang); + + nsCAutoString prefName; + nsXPIDLString nameValue, nameListValue; + + nsXPIDLString genericName; + prefName.AssignLiteral("font.default."); + prefName.Append(langGroup); + prefs->CopyUnicharPref(prefName.get(), getter_Copies(genericName)); + + nsCAutoString genericDotLang; + genericDotLang.Assign(NS_ConvertUTF16toUTF8(genericName)); + genericDotLang.AppendLiteral("."); + genericDotLang.Append(langGroup); + + // fetch font.name.xxx value + prefName.AssignLiteral("font.name."); + prefName.Append(genericDotLang); + rv = prefs->CopyUnicharPref(prefName.get(), getter_Copies(nameValue)); + if (NS_SUCCEEDED(rv)) { + if (!aCallback(prefLang, nameValue, aClosure)) + return PR_FALSE; + } + + // fetch font.name-list.xxx value + prefName.AssignLiteral("font.name-list."); + prefName.Append(genericDotLang); + rv = prefs->CopyUnicharPref(prefName.get(), getter_Copies(nameListValue)); + if (NS_SUCCEEDED(rv) && !nameListValue.Equals(nameValue)) { + if (!aCallback(prefLang, nameListValue, aClosure)) + return PR_FALSE; + } + } + + return PR_TRUE; +} + +eFontPrefLang +gfxPlatform::GetFontPrefLangFor(const char* aLang) +{ + if (!aLang || !aLang[0]) + return eFontPrefLang_Others; + for (PRUint32 i = 0; i < PRUint32(eFontPrefLang_LangCount); ++i) { + if (!PL_strcasecmp(gPrefLangNames[i], aLang)) + return eFontPrefLang(i); + } + return eFontPrefLang_Others; +} + +const char* +gfxPlatform::GetPrefLangName(eFontPrefLang aLang) +{ + if (PRUint32(aLang) < PRUint32(eFontPrefLang_AllCount)) + return gPrefLangNames[PRUint32(aLang)]; + return nsnull; +} + +const PRUint32 kFontPrefLangCJKMask = (1 << (PRUint32) eFontPrefLang_Japanese) | (1 << (PRUint32) eFontPrefLang_ChineseTW) + | (1 << (PRUint32) eFontPrefLang_ChineseCN) | (1 << (PRUint32) eFontPrefLang_ChineseHK) + | (1 << (PRUint32) eFontPrefLang_Korean); +PRBool +gfxPlatform::IsLangCJK(eFontPrefLang aLang) +{ + return kFontPrefLangCJKMask & (1 << (PRUint32) aLang); +} + +void +gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPrefLang aAddLang) +{ + if (aLen >= kMaxLenPrefLangList) return; + + // make sure + PRUint32 i = 0; + while (i < aLen && aPrefLangs[i] != aAddLang) { + i++; + } + + if (i == aLen) { + aPrefLangs[aLen] = aAddLang; + aLen++; + } +} + PRBool gfxPlatform::IsCMSEnabled() { diff --git a/mozilla/gfx/thebes/src/gfxPlatformMac.cpp b/mozilla/gfx/thebes/src/gfxPlatformMac.cpp index 6c76425f2e7..3f00032f327 100644 --- a/mozilla/gfx/thebes/src/gfxPlatformMac.cpp +++ b/mozilla/gfx/thebes/src/gfxPlatformMac.cpp @@ -44,6 +44,12 @@ #include "gfxQuartzFontCache.h" #include "gfxAtsuiFonts.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsIPrefLocalizedString.h" +#include "nsServiceManagerUtils.h" +#include "nsCRT.h" + #ifdef MOZ_ENABLE_GLITZ #include "gfxGlitzSurface.h" #include "glitz-agl.h" @@ -177,6 +183,116 @@ gfxPlatformMac::UpdateFontList() return NS_OK; } +void +gfxPlatformMac::GetLangPrefs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) +{ + if (IsLangCJK(aCharLang)) { + AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang); + } else { + AppendPrefLang(aPrefLangs, aLen, aCharLang); + } + + AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others); +} + +void +gfxPlatformMac::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) +{ + nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + + // prefer the lang specified by the page *if* CJK + if (IsLangCJK(aPageLang)) { + AppendPrefLang(aPrefLangs, aLen, aPageLang); + } + + // if not set up, set up the default CJK order, based on accept lang settings and system script + if (mCJKPrefLangs.Length() == 0) { + + // temp array + eFontPrefLang tempPrefLangs[kMaxLenPrefLangList]; + PRUint32 tempLen = 0; + + // Add the CJK pref fonts from accept languages, the order should be same order + nsCAutoString list; + nsresult rv; + if (prefs) { + nsCOMPtr prefString; + rv = prefs->GetComplexValue("intl.accept_languages", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(prefString)); + if (prefString) { + nsAutoString temp; + prefString->ToString(getter_Copies(temp)); + LossyCopyUTF16toASCII(temp, list); + } + } + + if (NS_SUCCEEDED(rv) && !list.IsEmpty()) { + const char kComma = ','; + const char *p, *p_end; + list.BeginReading(p); + list.EndReading(p_end); + while (p < p_end) { + while (nsCRT::IsAsciiSpace(*p)) { + if (++p == p_end) + break; + } + if (p == p_end) + break; + const char *start = p; + while (++p != p_end && *p != kComma) + /* nothing */ ; + nsCAutoString lang(Substring(start, p)); + lang.CompressWhitespace(PR_FALSE, PR_TRUE); + eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get()); + switch (fpl) { + case eFontPrefLang_Japanese: + case eFontPrefLang_Korean: + case eFontPrefLang_ChineseCN: + case eFontPrefLang_ChineseHK: + case eFontPrefLang_ChineseTW: + AppendPrefLang(tempPrefLangs, tempLen, fpl); + break; + default: + break; + } + p++; + } + } + + // Prefer the system locale if it is CJK. + ScriptCode sysScript = ::GetScriptManagerVariable(smSysScript); + // XXX Is not there the HK locale? + switch (sysScript) { + case smJapanese: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); break; + case smTradChinese: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); break; + case smKorean: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); break; + case smSimpChinese: AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); break; + default: break; + } + + // last resort... (the order is same as old gfx.) + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); + + // copy into the cached array + PRUint32 j; + for (j = 0; j < tempLen; j++) { + mCJKPrefLangs.AppendElement(tempPrefLangs[j]); + } + } + + // append in cached CJK langs + PRUint32 i, numCJKlangs = mCJKPrefLangs.Length(); + + for (i = 0; i < numCJKlangs; i++) { + AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i])); + } + +} + + cmsHPROFILE gfxPlatformMac::GetPlatformCMSOutputProfile() { diff --git a/mozilla/gfx/thebes/src/gfxQuartzFontCache.h b/mozilla/gfx/thebes/src/gfxQuartzFontCache.h index 0350ef6bdac..877a39a89c0 100644 --- a/mozilla/gfx/thebes/src/gfxQuartzFontCache.h +++ b/mozilla/gfx/thebes/src/gfxQuartzFontCache.h @@ -44,6 +44,7 @@ #include "gfxFontUtils.h" #include "gfxAtsuiFonts.h" +#include "gfxPlatform.h" #include @@ -173,12 +174,17 @@ public: MacOSFontEntry* FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont); + MacOSFamilyEntry* FindFamily(const nsAString& aFamily); + MacOSFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle); MacOSFontEntry* GetDefaultFont(const gfxFontStyle* aStyle); static PRInt32 AppleWeightToCSSWeight(PRInt32 aAppleWeight); + PRBool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray > *array); + void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray >& array); + private: static PLDHashOperator PR_CALLBACK FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr& aFamilyEntry, @@ -191,6 +197,7 @@ private: void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult); static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg); + static int PR_CALLBACK PrefChangedCallback(const char *aPrefName, void *closure); static PLDHashOperator PR_CALLBACK HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey, @@ -204,6 +211,10 @@ private: // family entry, only names *other* than the canonical names are stored here) nsDataHashtable > mLocalizedFamilies; + // cached pref font lists + // maps list of family names ==> array of family entries, one per lang group + nsDataHashtable > > mPrefFonts; + }; #endif /* GFXQUARTZFONTCACHE_H_ */ diff --git a/mozilla/gfx/thebes/src/gfxQuartzFontCache.mm b/mozilla/gfx/thebes/src/gfxQuartzFontCache.mm index fdc1f0387a9..e34c5d01eeb 100644 --- a/mozilla/gfx/thebes/src/gfxQuartzFontCache.mm +++ b/mozilla/gfx/thebes/src/gfxQuartzFontCache.mm @@ -45,6 +45,9 @@ #include "gfxQuartzFontCache.h" #include "gfxAtsuiFonts.h" +#include "nsIPref.h" // for pref changes callback notification +#include "nsServiceManagerUtils.h" + // _atsFontID is private; add it in our new category to NSFont @interface NSFont (MozillaCategory) - (ATSUFontID)_atsFontID; @@ -98,6 +101,7 @@ gfxQuartzFontCache::GenerateFontListKey(const nsAString& aKeyName, nsAString& aR } /* MacOSFontEntry */ +#pragma mark- MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, PRInt32 aAppleWeight, PRUint32 aTraits, MacOSFamilyEntry *aFamily) @@ -169,6 +173,7 @@ MacOSFontEntry::ReadCMAP() /* MacOSFamilyEntry */ +#pragma mark- static const PRUint32 kTraits_NonNormalWidthMask = NSNarrowFontMask | NSExpandedFontMask | NSCondensedFontMask | NSCompressedFontMask | NSFixedPitchFontMask; @@ -396,6 +401,7 @@ MacOSFamilyEntry::FindFontWeight(MacOSFontEntry* aFontsForWeights[], const gfxFo } /* gfxQuartzFontCache */ +#pragma mark- gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull; @@ -403,11 +409,19 @@ gfxQuartzFontCache::gfxQuartzFontCache() { mFontFamilies.Init(100); mLocalizedFamilies.Init(30); + mPrefFonts.Init(10); InitFontList(); ::ATSFontNotificationSubscribe(ATSNotification, kATSFontNotifyOptionDefault, (void*)this, nsnull); + + // pref changes notification setup + nsCOMPtr pref = do_GetService(NS_PREF_CONTRACTID); + pref->RegisterCallback("font.", PrefChangedCallback, this); + pref->RegisterCallback("font.name-list.", PrefChangedCallback, this); + pref->RegisterCallback("intl.accept_languages", PrefChangedCallback, this); // hmmmm... + } static NSString* CreateNameFromBuffer(const UInt8 *aBuf, ByteCount aLength, @@ -517,6 +531,7 @@ gfxQuartzFontCache::InitFontList() { mFontFamilies.Clear(); mLocalizedFamilies.Clear(); + mPrefFonts.Clear(); // iterate over available families NSFontManager *fontManager = [NSFontManager sharedFontManager]; @@ -629,6 +644,16 @@ gfxQuartzFontCache::ATSNotification(ATSFontNotificationInfoRef aInfo, qfc->UpdateFontList(); } +int PR_CALLBACK +gfxQuartzFontCache::PrefChangedCallback(const char *aPrefName, void *closure) +{ + // XXX this could be made to only clear out the cache for the prefs that were changed + // but it probably isn't that big a deal. + gfxQuartzFontCache *qfc = static_cast(closure); + qfc->mPrefFonts.Clear(); + return 0; +} + MacOSFontEntry* gfxQuartzFontCache::GetDefaultFont(const gfxFontStyle* aStyle) { @@ -695,18 +720,29 @@ gfxQuartzFontCache::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr< return PL_DHASH_NEXT; } -MacOSFontEntry* -gfxQuartzFontCache::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle) +MacOSFamilyEntry* +gfxQuartzFontCache::FindFamily(const nsAString& aFamily) { nsAutoString key; nsRefPtr familyEntry; GenerateFontListKey(aFamily, key); if (mFontFamilies.Get(key, &familyEntry) || mLocalizedFamilies.Get(key, &familyEntry)) { - return familyEntry->FindFont(aStyle); + return familyEntry; } return nsnull; } + +MacOSFontEntry* +gfxQuartzFontCache::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle) +{ + MacOSFamilyEntry *familyEntry = FindFamily(aFamily); + + if (familyEntry) + return familyEntry->FindFont(aStyle); + + return nsnull; +} PRInt32 gfxQuartzFontCache::AppleWeightToCSSWeight(PRInt32 aAppleWeight) @@ -718,3 +754,15 @@ gfxQuartzFontCache::AppleWeightToCSSWeight(PRInt32 aAppleWeight) return gAppleWeightToCSSWeight[aAppleWeight]; } +PRBool +gfxQuartzFontCache::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray > *array) +{ + return mPrefFonts.Get(PRUint32(aLangGroup), array); +} + +void +gfxQuartzFontCache::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray >& array) +{ + mPrefFonts.Put(PRUint32(aLangGroup), array); +} +