Bug 409342. Cache pref font lists per lang group during font matching. r+sr=pavlov

This commit is contained in:
jdaggett@mozilla.com 2008-01-30 16:23:36 -08:00
parent 82f3afa0ed
commit efccb7f6b0
8 changed files with 468 additions and 278 deletions

View File

@ -144,6 +144,9 @@ public:
return nsnull;
}
// search through pref fonts for a character, return nsnull if no matching pref font
already_AddRefed<gfxAtsuiFont> WhichPrefFontSupportsChar(PRUint32 aCh);
already_AddRefed<gfxAtsuiFont> FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNextCh, gfxAtsuiFont* aPrevMatchedFont);
protected:

View File

@ -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?
*/

View File

@ -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<PRUint32> mCJKPrefLangs;
};
#endif /* GFX_PLATFORM_MAC_H */

View File

@ -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<nsRefPtr<gfxFont> > *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<nsRefPtr<MacOSFamilyEntry> >& aFamiliesArray)
: mPrefFamilies(aFamiliesArray)
{}
nsTArray<nsRefPtr<MacOSFamilyEntry> >& 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<gfxAtsuiFont>
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<nsRefPtr<MacOSFamilyEntry>, 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<gfxAtsuiFont>
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<nsRefPtr<gfxFont>, 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<nsRefPtr<gfxFont> > *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<gfxAtsuiFont> font = GetOrMakeFont(fe, afl->style);
if (font) {
afl->fontArray->AppendElement(font);
}
}
return PR_TRUE;
}
static nsresult
AppendPrefFonts(nsTArray<nsRefPtr<gfxFont> > *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<nsRefPtr<gfxFont> > *aFonts,
PRUint32& didAppendBits,
const gfxFontStyle *aStyle)
{
nsCOMPtr<nsIPrefBranch> 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<nsIPrefLocalizedString> 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<nsRefPtr<gfxFont> > *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

View File

@ -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<nsIPref> 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()
{

View File

@ -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<nsIPrefBranch> 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<nsIPrefLocalizedString> 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()
{

View File

@ -44,6 +44,7 @@
#include "gfxFontUtils.h"
#include "gfxAtsuiFonts.h"
#include "gfxPlatform.h"
#include <Carbon/Carbon.h>
@ -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<nsRefPtr<MacOSFamilyEntry> > *array);
void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array);
private:
static PLDHashOperator PR_CALLBACK FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<MacOSFamilyEntry>& 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<nsStringHashKey, nsRefPtr<MacOSFamilyEntry> > mLocalizedFamilies;
// cached pref font lists
// maps list of family names ==> array of family entries, one per lang group
nsDataHashtable<nsUint32HashKey, nsTArray<nsRefPtr<MacOSFamilyEntry> > > mPrefFonts;
};
#endif /* GFXQUARTZFONTCACHE_H_ */

View File

@ -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<nsIPref> 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<gfxQuartzFontCache *>(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<MacOSFamilyEntry> 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<nsRefPtr<MacOSFamilyEntry> > *array)
{
return mPrefFonts.Get(PRUint32(aLangGroup), array);
}
void
gfxQuartzFontCache::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array)
{
mPrefFonts.Put(PRUint32(aLangGroup), array);
}