Bug 490267 - implement pref font and system font fallback for gfxFT2Fonts. r=jtd,jfkthame sr=roc

This commit is contained in:
Takuro Ashie 2009-09-09 16:35:08 +01:00
parent 54ee98bc91
commit 8ffb33380a
7 changed files with 429 additions and 171 deletions

View File

@ -65,9 +65,6 @@ public:
protected: protected:
virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
PRBool anItalic, PRInt16 aStretch); PRBool anItalic, PRInt16 aStretch);
public:
nsString mName;
}; };
class FontEntry : public gfxFontEntry class FontEntry : public gfxFontEntry
@ -76,6 +73,7 @@ public:
FontEntry(const nsAString& aFaceName) : FontEntry(const nsAString& aFaceName) :
gfxFontEntry(aFaceName) gfxFontEntry(aFaceName)
{ {
mFTFace = nsnull;
mFontFace = nsnull; mFontFace = nsnull;
mFTFontIndex = 0; mFTFontIndex = 0;
} }
@ -95,7 +93,9 @@ public:
CreateFontEntryFromFace(FT_Face aFace); CreateFontEntryFromFace(FT_Face aFace);
cairo_font_face_t *CairoFontFace(); cairo_font_face_t *CairoFontFace();
nsresult ReadCMAP();
FT_Face mFTFace;
cairo_font_face_t *mFontFace; cairo_font_face_t *mFontFace;
nsString mFaceName; nsString mFaceName;
@ -124,6 +124,8 @@ public: // new functions
static already_AddRefed<gfxFT2Font> static already_AddRefed<gfxFT2Font>
GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle); GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle);
static already_AddRefed<gfxFT2Font>
GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle);
private: private:
cairo_scaled_font_t *mScaledFont; cairo_scaled_font_t *mScaledFont;
@ -180,17 +182,18 @@ protected: // new functions
void *closure); void *closure);
PRBool mEnableKerning; PRBool mEnableKerning;
gfxFT2Font *FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRUint32 nextCh, gfxFT2Font *aFont); void GetPrefFonts(const char *aLangGroup,
PRUint32 ComputeRanges(); nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
void GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
void FamilyListToArrayList(const nsString& aFamilies,
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *aFontEntryList);
already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& aFontEntryList,
PRUint32 aCh);
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
struct TextRange { nsTArray<gfxTextRange> mRanges;
TextRange(PRUint32 aStart, PRUint32 aEnd) : start(aStart), end(aEnd) { }
PRUint32 Length() const { return end - start; }
nsRefPtr<gfxFT2Font> font;
PRUint32 start, end;
};
nsTArray<TextRange> mRanges;
nsString mString; nsString mString;
}; };

View File

@ -117,6 +117,9 @@ public:
#ifndef MOZ_PANGO #ifndef MOZ_PANGO
FontFamily *FindFontFamily(const nsAString& aName); FontFamily *FindFontFamily(const nsAString& aName);
FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle); FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle);
already_AddRefed<gfxFont> FindFontForChar(PRUint32 aCh, gfxFont *aFont);
PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *aFontEntryList);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
#endif #endif
static double DPI() { static double DPI() {

View File

@ -79,6 +79,9 @@ public:
FontFamily *FindFontFamily(const nsAString& aName); FontFamily *FindFontFamily(const nsAString& aName);
FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle); FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle);
already_AddRefed<gfxFont> FindFontForChar(PRUint32 aCh, gfxFont *aFont);
PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *aFontEntryList);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
static PRInt32 DPI() { static PRInt32 DPI() {
if (sDPI == -1) { if (sDPI == -1) {

View File

@ -52,9 +52,34 @@
#include "gfxFT2Fonts.h" #include "gfxFT2Fonts.h"
#include <locale.h> #include <locale.h>
#include "cairo-ft.h" #include "cairo-ft.h"
#include <freetype/tttables.h> #include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_TABLES_H
#include "gfxFontUtils.h" #include "gfxFontUtils.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "nsUnicodeRange.h"
#include "nsIPrefService.h"
#include "nsIPrefLocalizedString.h"
#include "nsServiceManagerUtils.h"
#include "nsCRT.h"
#include "prlog.h"
#include "prinit.h"
static PRLogModuleInfo *gFontLog = PR_NewLogModule("ft2fonts");
static const char *sCJKLangGroup[] = {
"ja",
"ko",
"zh-CN",
"zh-HK",
"zh-TW"
};
#define COUNT_OF_CJK_LANG_GROUP 5
#define CJK_LANG_JA sCJKLangGroup[0]
#define CJK_LANG_KO sCJKLangGroup[1]
#define CJK_LANG_ZH_CN sCJKLangGroup[2]
#define CJK_LANG_ZH_HK sCJKLangGroup[3]
#define CJK_LANG_ZH_TW sCJKLangGroup[4]
/** /**
* FontEntry * FontEntry
@ -63,6 +88,7 @@
FontEntry::FontEntry(const FontEntry& aFontEntry) : FontEntry::FontEntry(const FontEntry& aFontEntry) :
gfxFontEntry(aFontEntry) gfxFontEntry(aFontEntry)
{ {
mFTFace = aFontEntry.mFTFace;
if (aFontEntry.mFontFace) if (aFontEntry.mFontFace)
mFontFace = cairo_font_face_reference(aFontEntry.mFontFace); mFontFace = cairo_font_face_reference(aFontEntry.mFontFace);
else else
@ -71,6 +97,9 @@ FontEntry::FontEntry(const FontEntry& aFontEntry) :
FontEntry::~FontEntry() FontEntry::~FontEntry()
{ {
// Do nothing for mFTFace here since FTFontDestroyFunc is called by cairo.
mFTFace = nsnull;
if (mFontFace) { if (mFontFace) {
cairo_font_face_destroy(mFontFace); cairo_font_face_destroy(mFontFace);
mFontFace = nsnull; mFontFace = nsnull;
@ -122,6 +151,7 @@ FontEntry::CreateFontEntryFromFace(FT_Face aFace) {
} }
FontEntry *fe = new FontEntry(fontName); FontEntry *fe = new FontEntry(fontName);
fe->mItalic = aFace->style_flags & FT_STYLE_FLAG_ITALIC; fe->mItalic = aFace->style_flags & FT_STYLE_FLAG_ITALIC;
fe->mFTFace = aFace;
fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, 0); fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, 0);
cairo_font_face_set_user_data(fe->mFontFace, &key, cairo_font_face_set_user_data(fe->mFontFace, &key,
aFace, FTFontDestroyFunc); aFace, FTFontDestroyFunc);
@ -165,12 +195,45 @@ FontEntry::CairoFontFace()
if (!mFontFace) { if (!mFontFace) {
FT_Face face; FT_Face face;
FT_New_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(), mFilename.get(), mFTFontIndex, &face); FT_New_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(), mFilename.get(), mFTFontIndex, &face);
mFTFace = face;
mFontFace = cairo_ft_font_face_create_for_ft_face(face, 0); mFontFace = cairo_ft_font_face_create_for_ft_face(face, 0);
cairo_font_face_set_user_data(mFontFace, &key, face, FTFontDestroyFunc); cairo_font_face_set_user_data(mFontFace, &key, face, FTFontDestroyFunc);
} }
return mFontFace; return mFontFace;
} }
nsresult
FontEntry::ReadCMAP()
{
if (mCmapInitialized) return NS_OK;
// attempt this once, if errors occur leave a blank cmap
mCmapInitialized = PR_TRUE;
// Ensure existence of mFTFace
CairoFontFace();
NS_ENSURE_TRUE(mFTFace, NS_ERROR_FAILURE);
FT_Error status;
FT_ULong len = 0;
status = FT_Load_Sfnt_Table(mFTFace, TTAG_cmap, 0, nsnull, &len);
NS_ENSURE_TRUE(status == 0, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(len != 0, NS_ERROR_FAILURE);
nsAutoTArray<PRUint8,16384> buffer;
if (!buffer.AppendElements(len))
return NS_ERROR_FAILURE;
PRUint8 *buf = buffer.Elements();
status = FT_Load_Sfnt_Table(mFTFace, TTAG_cmap, 0, buf, &len);
NS_ENSURE_TRUE(status == 0, NS_ERROR_FAILURE);
PRPackedBool unicodeFont;
PRPackedBool symbolFont;
return gfxFontUtils::ReadCMAP(buf, len, mCharacterMap,
unicodeFont, symbolFont);
}
FontEntry * FontEntry *
FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle) FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
{ {
@ -367,184 +430,240 @@ PRUint32 getUTF8CharAndNext(const PRUint8 *aString, PRUint8 *aLength)
} }
static PRBool
AddFontNameToArray(const nsAString& aName,
const nsACString& aGenericName,
void *aClosure)
PRBool
HasCharacter(gfxFT2Font *aFont, PRUint32 ch)
{ {
if (aFont->GetFontEntry()->mCharacterMap.test(ch)) if (!aName.IsEmpty()) {
return PR_TRUE; nsTArray<nsString> *list = static_cast<nsTArray<nsString> *>(aClosure);
// XXX move this lock way way out if (list->IndexOf(aName) == list->NoIndex)
FT_Face face = cairo_ft_scaled_font_lock_face(aFont->CairoScaledFont()); list->AppendElement(aName);
FT_UInt gid = FT_Get_Char_Index(face, ch); }
cairo_ft_scaled_font_unlock_face(aFont->CairoScaledFont());
return PR_TRUE;
if (gid != 0) { }
aFont->GetFontEntry()->mCharacterMap.set(ch);
return PR_TRUE; void
gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies,
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *aFontEntryList)
{
nsAutoTArray<nsString, 15> fonts;
ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts);
PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++i) {
const nsString& str = fonts[i];
nsRefPtr<FontEntry> fe = gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle);
aFontEntryList->AppendElement(fe);
} }
return PR_FALSE;
} }
#if 0 void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList) {
inline FontEntry * NS_ASSERTION(aLangGroup, "aLangGroup is null");
gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<>& foo, PRUint32 ch) gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
{ nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
for (int i = 0; i < aGroup->FontListLength(); i++) { /* this lookup has to depend on weight and style */
nsRefPtr<gfxFT2Font> font = aGroup->GetFontAt(i); nsCAutoString key(aLangGroup);
if (HasCharacter(font, ch)) key.Append("-");
return font; key.AppendInt(GetStyle()->style);
key.Append("-");
key.AppendInt(GetStyle()->weight);
if (!platform->GetPrefFontEntries(key, &fonts)) {
nsString fontString;
platform->GetPrefFonts(aLangGroup, fontString);
if (fontString.IsEmpty())
return;
FamilyListToArrayList(fontString, nsDependentCString(aLangGroup),
&fonts);
platform->SetPrefFontEntries(key, fonts);
} }
return nsnull; aFontEntryList.AppendElements(fonts);
} }
static PRInt32 GetCJKLangGroupIndex(const char *aLangGroup) {
PRInt32 i;
for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) {
if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i]))
return i;
}
return -1;
}
// this function assigns to the array passed in.
void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& aFontEntryList) {
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
nsCAutoString key("x-internal-cjk-");
key.AppendInt(mStyle.style);
key.Append("-");
key.AppendInt(mStyle.weight);
if (!platform->GetPrefFontEntries(key, &aFontEntryList)) {
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (!prefs)
return;
nsCOMPtr<nsIPrefBranch> prefBranch;
prefs->GetBranch(0, getter_AddRefs(prefBranch));
if (!prefBranch)
return;
// Add the CJK pref fonts from accept languages, the order should be same order
nsCAutoString list;
nsCOMPtr<nsIPrefLocalizedString> val;
nsresult rv = prefBranch->GetComplexValue("intl.accept_languages", NS_GET_IID(nsIPrefLocalizedString),
getter_AddRefs(val));
if (NS_SUCCEEDED(rv) && val) {
nsAutoString temp;
val->ToString(getter_Copies(temp));
LossyCopyUTF16toASCII(temp, list);
}
if (!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);
PRInt32 index = GetCJKLangGroupIndex(lang.get());
if (index >= 0)
GetPrefFonts(sCJKLangGroup[index], aFontEntryList);
p++;
}
}
// Add the system locale
#ifdef XP_WIN
switch (::GetACP()) {
case 932: GetPrefFonts(CJK_LANG_JA, aFontEntryList); break;
case 936: GetPrefFonts(CJK_LANG_ZH_CN, aFontEntryList); break;
case 949: GetPrefFonts(CJK_LANG_KO, aFontEntryList); break;
// XXX Don't we need to append CJK_LANG_ZH_HK if the codepage is 950?
case 950: GetPrefFonts(CJK_LANG_ZH_TW, aFontEntryList); break;
}
#else
const char *ctype = setlocale(LC_CTYPE, NULL);
if (ctype) {
if (!PL_strncasecmp(ctype, "ja", 2)) {
GetPrefFonts(CJK_LANG_JA, aFontEntryList);
} else if (!PL_strncasecmp(ctype, "zh_cn", 5)) {
GetPrefFonts(CJK_LANG_ZH_CN, aFontEntryList);
} else if (!PL_strncasecmp(ctype, "zh_hk", 5)) {
GetPrefFonts(CJK_LANG_ZH_HK, aFontEntryList);
} else if (!PL_strncasecmp(ctype, "zh_tw", 5)) {
GetPrefFonts(CJK_LANG_ZH_TW, aFontEntryList);
} else if (!PL_strncasecmp(ctype, "ko", 2)) {
GetPrefFonts(CJK_LANG_KO, aFontEntryList);
}
}
#endif #endif
inline gfxFT2Font * // last resort...
gfxFT2FontGroup::FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRUint32 nextCh, gfxFT2Font *aFont) GetPrefFonts(CJK_LANG_JA, aFontEntryList);
{ GetPrefFonts(CJK_LANG_KO, aFontEntryList);
gfxFT2Font *selectedFont; GetPrefFonts(CJK_LANG_ZH_CN, aFontEntryList);
GetPrefFonts(CJK_LANG_ZH_HK, aFontEntryList);
GetPrefFonts(CJK_LANG_ZH_TW, aFontEntryList);
// if this character or the next one is a joiner use the platform->SetPrefFontEntries(key, aFontEntryList);
// same font as the previous range if we can
if (gfxFontUtils::IsJoiner(ch) || gfxFontUtils::IsJoiner(prevCh) || gfxFontUtils::IsJoiner(nextCh)) {
if (aFont && HasCharacter(aFont, ch))
return aFont;
} }
}
for (PRUint32 i = 0; i < FontListLength(); i++) { already_AddRefed<gfxFT2Font>
nsRefPtr<gfxFT2Font> font = GetFontAt(i); gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& aFontEntryList, PRUint32 aCh)
if (HasCharacter(font, ch)) {
return font; for (PRUint32 i = 0; i < aFontEntryList.Length(); i++) {
nsRefPtr<FontEntry> fe = aFontEntryList[i];
if (fe->HasCharacter(aCh)) {
nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(fe, &mStyle);
return font.forget();
}
} }
return nsnull; return nsnull;
}
#if 0 already_AddRefed<gfxFont>
// check the list of fonts gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
selectedFont = WhichFontSupportsChar(mGroup->GetFontList(), ch); {
if (aCh > 0xFFFF)
return nsnull;
nsRefPtr<gfxFT2Font> selectedFont;
// don't look in other fonts if the character is in a Private Use Area
if ((ch >= 0xE000 && ch <= 0xF8FF) ||
(ch >= 0xF0000 && ch <= 0x10FFFD))
return selectedFont;
// check out the style's language group // check out the style's language group
if (!selectedFont) { nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts; GetPrefFonts(mStyle.langGroup.get(), fonts);
this->GetPrefFonts(mGroup->GetStyle()->langGroup.get(), fonts); selectedFont = WhichFontSupportsChar(fonts, aCh);
selectedFont = WhichFontSupportsChar(fonts, ch);
}
// otherwise search prefs // otherwise search prefs
if (!selectedFont) { if (!selectedFont) {
/* first check with the script properties to see what they think */ PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
if (ch <= 0xFFFF) {
PRUint32 unicodeRange = FindCharUnicodeRange(ch);
/* special case CJK */
if (unicodeRange == kRangeSetCJK) {
if (PR_LOG_TEST(gFontLog, PR_LOG_DEBUG))
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: CJK"));
nsAutoTArray<nsRefPtr<FontEntry>, 15> fonts; /* special case CJK */
this->GetCJKPrefFonts(fonts); if (unicodeRange == kRangeSetCJK) {
selectedFont = WhichFontSupportsChar(fonts, ch); if (PR_LOG_TEST(gFontLog, PR_LOG_DEBUG))
} else { PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: CJK"));
const char *langGroup = LangGroupFromUnicodeRange(unicodeRange);
if (langGroup) {
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroup));
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts; nsAutoTArray<nsRefPtr<FontEntry>, 15> fonts;
this->GetPrefFonts(langGroup, fonts); GetCJKPrefFonts(fonts);
selectedFont = WhichFontSupportsChar(fonts, ch); selectedFont = WhichFontSupportsChar(fonts, aCh);
} } else {
const char *langGroup = LangGroupFromUnicodeRange(unicodeRange);
if (langGroup) {
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroup));
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
GetPrefFonts(langGroup, fonts);
selectedFont = WhichFontSupportsChar(fonts, aCh);
} }
} }
} }
// before searching for something else check the font used for the previous character if (selectedFont) {
if (!selectedFont && aFont && HasCharacter(aFont, ch)) nsRefPtr<gfxFont> f = static_cast<gfxFont*>(selectedFont.get());
selectedFont = aFont; return f.forget();
// otherwise look for other stuff
if (!selectedFont) {
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Looking for best match"));
nsRefPtr<gfxWindowsFont> refFont = mGroup->GetFontAt(0);
gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform();
selectedFont = platform->FindFontForChar(ch, refFont);
} }
return selectedFont; return nsnull;
#endif
} }
PRUint32 already_AddRefed<gfxFont>
gfxFT2FontGroup::ComputeRanges() gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
{ {
const PRUnichar *str = mString.get(); nsRefPtr<gfxFont> selectedFont;
PRUint32 len = mString.Length(); nsRefPtr<gfxFT2Font> refFont = GetFontAt(0);
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
mRanges.Clear(); selectedFont = platform->FindFontForChar(aCh, refFont);
if (selectedFont)
PRUint32 prevCh = 0; return selectedFont.forget();
for (PRUint32 i = 0; i < len; i++) { return nsnull;
const PRUint32 origI = i; // save off incase we increase for surrogate
PRUint32 ch = str[i];
if ((i+1 < len) && NS_IS_HIGH_SURROGATE(ch) && NS_IS_LOW_SURROGATE(str[i+1])) {
i++;
ch = SURROGATE_TO_UCS4(ch, str[i]);
}
PRUint32 nextCh = 0;
if (i+1 < len) {
nextCh = str[i+1];
if ((i+2 < len) && NS_IS_HIGH_SURROGATE(ch) && NS_IS_LOW_SURROGATE(str[i+2]))
nextCh = SURROGATE_TO_UCS4(nextCh, str[i+2]);
}
gfxFT2Font *fe = FindFontForChar(ch,
prevCh,
nextCh,
(mRanges.Length() == 0) ? nsnull : mRanges[mRanges.Length() - 1].font);
prevCh = ch;
if (mRanges.Length() == 0) {
TextRange r(0,1);
r.font = fe;
mRanges.AppendElement(r);
} else {
TextRange& prevRange = mRanges[mRanges.Length() - 1];
if (prevRange.font != fe) {
// close out the previous range
prevRange.end = origI;
TextRange r(origI, i+1);
r.font = fe;
mRanges.AppendElement(r);
}
}
}
mRanges[mRanges.Length()-1].end = len;
PRUint32 nranges = mRanges.Length();
return nranges;
} }
void gfxFT2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun) void gfxFT2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun)
{ {
ComputeRanges(); ComputeRanges(mRanges, mString.get(), 0, mString.Length());
PRUint32 offset = 0; PRUint32 offset = 0;
for (PRUint32 i = 0; i < mRanges.Length(); ++i) { for (PRUint32 i = 0; i < mRanges.Length(); ++i) {
const TextRange& range = mRanges[i]; const gfxTextRange& range = mRanges[i];
PRUint32 rangeLength = range.Length(); PRUint32 rangeLength = range.Length();
gfxFT2Font *font = range.font ? range.font.get() : GetFontAt(0); gfxFT2Font *font = static_cast<gfxFT2Font *>(range.font ? range.font.get() : GetFontAt(0));
AddRange(aTextRun, font, mString.get(), offset, rangeLength); AddRange(aTextRun, font, mString.get(), offset, rangeLength);
offset += rangeLength; offset += rangeLength;
} }
@ -908,9 +1027,16 @@ gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle)
return nsnull; return nsnull;
} }
nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(fe->Name(), aStyle); nsRefPtr<gfxFT2Font> font = GetOrMakeFont(fe, aStyle);
return font.forget();
}
already_AddRefed<gfxFT2Font>
gfxFT2Font::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry->Name(), aStyle);
if (!font) { if (!font) {
font = new gfxFT2Font(fe, aStyle); font = new gfxFT2Font(aFontEntry, aStyle);
if (!font) if (!font)
return nsnull; return nsnull;
gfxFontCache::GetCache()->AddNew(font); gfxFontCache::GetCache()->AddNew(font);

View File

@ -44,6 +44,7 @@
#include "gfxPlatformGtk.h" #include "gfxPlatformGtk.h"
#include "nsUnicharUtils.h"
#include "gfxFontconfigUtils.h" #include "gfxFontconfigUtils.h"
#ifdef MOZ_PANGO #ifdef MOZ_PANGO
#include "gfxPangoFonts.h" #include "gfxPangoFonts.h"
@ -95,8 +96,11 @@ gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
#ifndef MOZ_PANGO #ifndef MOZ_PANGO
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable; typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
typedef nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > PrefFontTable;
static FontTable *gPlatformFonts = NULL; static FontTable *gPlatformFonts = NULL;
static FontTable *gPlatformFontAliases = NULL; static FontTable *gPlatformFontAliases = NULL;
static PrefFontTable *gPrefFonts = NULL;
static gfxSparseBitSet *gCodepointsWithNoFonts = NULL;
static FT_Library gPlatformFTLibrary = NULL; static FT_Library gPlatformFTLibrary = NULL;
#endif #endif
@ -119,6 +123,9 @@ gfxPlatformGtk::gfxPlatformGtk()
gPlatformFonts->Init(100); gPlatformFonts->Init(100);
gPlatformFontAliases = new FontTable(); gPlatformFontAliases = new FontTable();
gPlatformFontAliases->Init(100); gPlatformFontAliases->Init(100);
gPrefFonts = new PrefFontTable();
gPrefFonts->Init(100);
gCodepointsWithNoFonts = new gfxSparseBitSet();
UpdateFontList(); UpdateFontList();
#endif #endif
@ -137,6 +144,10 @@ gfxPlatformGtk::~gfxPlatformGtk()
gPlatformFonts = NULL; gPlatformFonts = NULL;
delete gPlatformFontAliases; delete gPlatformFontAliases;
gPlatformFontAliases = NULL; gPlatformFontAliases = NULL;
delete gPrefFonts;
gPrefFonts = NULL;
delete gCodepointsWithNoFonts;
gCodepointsWithNoFonts = NULL;
FT_Done_FreeType(gPlatformFTLibrary); FT_Done_FreeType(gPlatformFTLibrary);
gPlatformFTLibrary = NULL; gPlatformFTLibrary = NULL;
@ -369,15 +380,14 @@ gfxPlatformGtk::UpdateFontList()
nsAutoString name(NS_ConvertUTF8toUTF16(nsDependentCString(str)).get()); nsAutoString name(NS_ConvertUTF8toUTF16(nsDependentCString(str)).get());
nsAutoString key(name); nsAutoString key(name);
/* FIXME DFB */ ToLowerCase(key);
//ToLowerCase(key);
nsRefPtr<FontFamily> ff; nsRefPtr<FontFamily> ff;
if (!gPlatformFonts->Get(key, &ff)) { if (!gPlatformFonts->Get(key, &ff)) {
ff = new FontFamily(name); ff = new FontFamily(name);
gPlatformFonts->Put(key, ff); gPlatformFonts->Put(key, ff);
} }
FontEntry *fe = new FontEntry(ff->mName); FontEntry *fe = new FontEntry(ff->Name());
ff->AddFontEntry(fe); ff->AddFontEntry(fe);
if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, (FcChar8 **) &str) == FcResultMatch) { if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, (FcChar8 **) &str) == FcResultMatch) {
@ -429,13 +439,12 @@ gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
{ {
nsAutoString name(aFontName); nsAutoString name(aFontName);
/* FIXME: DFB */ ToLowerCase(name);
//ToLowerCase(name);
nsRefPtr<FontFamily> ff; nsRefPtr<FontFamily> ff;
if (gPlatformFonts->Get(name, &ff) || if (gPlatformFonts->Get(name, &ff) ||
gPlatformFontAliases->Get(name, &ff)) { gPlatformFontAliases->Get(name, &ff)) {
aAborted = !(*aCallback)(ff->mName, aClosure); aAborted = !(*aCallback)(ff->Name(), aClosure);
return NS_OK; return NS_OK;
} }
@ -451,8 +460,7 @@ gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
continue; continue;
nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str))); nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
/* FIXME: DFB */ ToLowerCase(altName);
//ToLowerCase(altName);
if (gPlatformFonts->Get(altName, &ff)) { if (gPlatformFonts->Get(altName, &ff)) {
//printf("Adding alias: %s -> %s\n", utf8Name.get(), str); //printf("Adding alias: %s -> %s\n", utf8Name.get(), str);
gPlatformFontAliases->Put(name, ff); gPlatformFontAliases->Put(name, ff);
@ -486,8 +494,7 @@ gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
continue; continue;
nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str))); nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
/* FIXME: DFB */ ToLowerCase(altName);
//ToLowerCase(altName);
if (gPlatformFonts->Get(altName, &ff)) { if (gPlatformFonts->Get(altName, &ff)) {
//printf("Adding alias: %s -> %s\n", utf8Name.get(), str); //printf("Adding alias: %s -> %s\n", utf8Name.get(), str);
gPlatformFontAliases->Put(name, ff); gPlatformFontAliases->Put(name, ff);
@ -668,8 +675,7 @@ FontFamily *
gfxPlatformGtk::FindFontFamily(const nsAString& aName) gfxPlatformGtk::FindFontFamily(const nsAString& aName)
{ {
nsAutoString name(aName); nsAutoString name(aName);
/* FIXME: DFB */ ToLowerCase(name);
//ToLowerCase(name);
nsRefPtr<FontFamily> ff; nsRefPtr<FontFamily> ff;
if (!gPlatformFonts->Get(name, &ff)) { if (!gPlatformFonts->Get(name, &ff)) {
@ -687,6 +693,58 @@ gfxPlatformGtk::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontS
return ff->FindFontEntry(aFontStyle); return ff->FindFontEntry(aFontStyle);
} }
static PLDHashOperator
FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* aUserArg)
{
FontSearch *data = (FontSearch*)aUserArg;
aFontFamily->FindFontForChar(data);
return PL_DHASH_NEXT;
}
already_AddRefed<gfxFont>
gfxPlatformGtk::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
{
if (!gPlatformFonts || !gCodepointsWithNoFonts)
return nsnull;
// is codepoint with no matching font? return null immediately
if (gCodepointsWithNoFonts->test(aCh)) {
return nsnull;
}
FontSearch data(aCh, aFont);
// find fonts that support the character
gPlatformFonts->Enumerate(FindFontForCharProc, &data);
if (data.mBestMatch) {
nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
aFont->GetStyle());
gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret);
}
// no match? add to set of non-matching codepoints
gCodepointsWithNoFonts->set(aCh);
return nsnull;
}
PRBool
gfxPlatformGtk::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> > *aFontEntryList)
{
return gPrefFonts->Get(aKey, aFontEntryList);
}
void
gfxPlatformGtk::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList)
{
gPrefFonts->Put(aKey, aFontEntryList);
}
#endif #endif

View File

@ -74,8 +74,11 @@ static void do_qt_pixmap_unref (void *data)
} }
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable; typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
typedef nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > PrefFontTable;
static FontTable *gPlatformFonts = NULL; static FontTable *gPlatformFonts = NULL;
static FontTable *gPlatformFontAliases = NULL; static FontTable *gPlatformFontAliases = NULL;
static PrefFontTable *gPrefFonts = NULL;
static gfxSparseBitSet *gCodepointsWithNoFonts = NULL;
static FT_Library gPlatformFTLibrary = NULL; static FT_Library gPlatformFTLibrary = NULL;
@ -91,6 +94,9 @@ gfxQtPlatform::gfxQtPlatform()
gPlatformFonts->Init(100); gPlatformFonts->Init(100);
gPlatformFontAliases = new FontTable(); gPlatformFontAliases = new FontTable();
gPlatformFontAliases->Init(100); gPlatformFontAliases->Init(100);
gPrefFonts = new PrefFontTable();
gPrefFonts->Init(100);
gCodepointsWithNoFonts = new gfxSparseBitSet();
UpdateFontList(); UpdateFontList();
InitDPI(); InitDPI();
@ -105,6 +111,10 @@ gfxQtPlatform::~gfxQtPlatform()
gPlatformFonts = NULL; gPlatformFonts = NULL;
delete gPlatformFontAliases; delete gPlatformFontAliases;
gPlatformFontAliases = NULL; gPlatformFontAliases = NULL;
delete gPrefFonts;
gPrefFonts = NULL;
delete gCodepointsWithNoFonts;
gCodepointsWithNoFonts = NULL;
cairo_debug_reset_static_data(); cairo_debug_reset_static_data();
@ -389,3 +399,55 @@ gfxQtPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontSt
return ff->FindFontEntry(aFontStyle); return ff->FindFontEntry(aFontStyle);
} }
static PLDHashOperator
FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* aUserArg)
{
FontSearch *data = (FontSearch*)aUserArg;
aFontFamily->FindFontForChar(data);
return PL_DHASH_NEXT;
}
already_AddRefed<gfxFont>
gfxQtPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
{
if (!gPlatformFonts || !gCodepointsWithNoFonts)
return nsnull;
// is codepoint with no matching font? return null immediately
if (gCodepointsWithNoFonts->test(aCh)) {
return nsnull;
}
FontSearch data(aCh, aFont);
// find fonts that support the character
gPlatformFonts->Enumerate(FindFontForCharProc, &data);
if (data.mBestMatch) {
nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
aFont->GetStyle());
gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret);
}
// no match? add to set of non-matching codepoints
gCodepointsWithNoFonts->set(aCh);
return nsnull;
}
PRBool
gfxQtPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> > *aFontEntryList)
{
return gPrefFonts->Get(aKey, aFontEntryList);
}
void
gfxQtPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList)
{
gPrefFonts->Put(aKey, aFontEntryList);
}

View File

@ -610,6 +610,9 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
{ {
FontSearch *data = (FontSearch*)userArg; FontSearch *data = (FontSearch*)userArg;
#ifdef MOZ_FT2_FONTS
aFontFamily->FindFontForChar(data);
#else
const PRUint32 ch = data->mCh; const PRUint32 ch = data->mCh;
nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->mFontToMatch->GetStyle()); nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->mFontToMatch->GetStyle());
@ -619,7 +622,6 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
PRInt32 rank = 0; PRInt32 rank = 0;
#ifndef MOZ_FT2_FONTS
// skip over non-unicode and bitmap fonts and fonts that don't have // skip over non-unicode and bitmap fonts and fonts that don't have
// the code point we're looking for // the code point we're looking for
if (fe->IsCrappyFont() || !fe->mCharacterMap.test(ch)) if (fe->IsCrappyFont() || !fe->mCharacterMap.test(ch))
@ -639,7 +641,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
rank += 3; rank += 3;
if (fe->mWindowsPitch == mfe->mWindowsPitch) if (fe->mWindowsPitch == mfe->mWindowsPitch)
rank += 3; rank += 3;
#endif
/* italic */ /* italic */
const PRBool italic = (data->mFontToMatch->GetStyle()->style != FONT_STYLE_NORMAL); const PRBool italic = (data->mFontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
if (fe->mItalic != italic) if (fe->mItalic != italic)
@ -658,6 +660,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
data->mBestMatch = fe; data->mBestMatch = fe;
data->mMatchRank = rank; data->mMatchRank = rank;
} }
#endif
return PL_DHASH_NEXT; return PL_DHASH_NEXT;
} }
@ -678,10 +681,10 @@ gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
if (data.mBestMatch) { if (data.mBestMatch) {
#ifdef MOZ_FT2_FONTS #ifdef MOZ_FT2_FONTS
nsRefPtr<gfxFT2Font> font = nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(data.mBestMatch->mName, gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
aFont->GetStyle()); aFont->GetStyle());
gfxFont* ret = font.forget().get(); gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret); return already_AddRefed<gfxFont>(ret);
#else #else
nsRefPtr<gfxWindowsFont> font = nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()), gfxWindowsFont::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),