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

View File

@ -117,6 +117,9 @@ public:
#ifndef MOZ_PANGO
FontFamily *FindFontFamily(const nsAString& aName);
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
static double DPI() {

View File

@ -79,6 +79,9 @@ public:
FontFamily *FindFontFamily(const nsAString& aName);
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() {
if (sDPI == -1) {

View File

@ -52,9 +52,34 @@
#include "gfxFT2Fonts.h"
#include <locale.h>
#include "cairo-ft.h"
#include <freetype/tttables.h>
#include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_TABLES_H
#include "gfxFontUtils.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
@ -63,6 +88,7 @@
FontEntry::FontEntry(const FontEntry& aFontEntry) :
gfxFontEntry(aFontEntry)
{
mFTFace = aFontEntry.mFTFace;
if (aFontEntry.mFontFace)
mFontFace = cairo_font_face_reference(aFontEntry.mFontFace);
else
@ -71,6 +97,9 @@ FontEntry::FontEntry(const FontEntry& aFontEntry) :
FontEntry::~FontEntry()
{
// Do nothing for mFTFace here since FTFontDestroyFunc is called by cairo.
mFTFace = nsnull;
if (mFontFace) {
cairo_font_face_destroy(mFontFace);
mFontFace = nsnull;
@ -122,6 +151,7 @@ FontEntry::CreateFontEntryFromFace(FT_Face aFace) {
}
FontEntry *fe = new FontEntry(fontName);
fe->mItalic = aFace->style_flags & FT_STYLE_FLAG_ITALIC;
fe->mFTFace = aFace;
fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, 0);
cairo_font_face_set_user_data(fe->mFontFace, &key,
aFace, FTFontDestroyFunc);
@ -165,12 +195,45 @@ FontEntry::CairoFontFace()
if (!mFontFace) {
FT_Face face;
FT_New_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(), mFilename.get(), mFTFontIndex, &face);
mFTFace = face;
mFontFace = cairo_ft_font_face_create_for_ft_face(face, 0);
cairo_font_face_set_user_data(mFontFace, &key, face, FTFontDestroyFunc);
}
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 *
FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
{
@ -367,184 +430,240 @@ PRUint32 getUTF8CharAndNext(const PRUint8 *aString, PRUint8 *aLength)
}
PRBool
HasCharacter(gfxFT2Font *aFont, PRUint32 ch)
static PRBool
AddFontNameToArray(const nsAString& aName,
const nsACString& aGenericName,
void *aClosure)
{
if (aFont->GetFontEntry()->mCharacterMap.test(ch))
return PR_TRUE;
if (!aName.IsEmpty()) {
nsTArray<nsString> *list = static_cast<nsTArray<nsString> *>(aClosure);
// XXX move this lock way way out
FT_Face face = cairo_ft_scaled_font_lock_face(aFont->CairoScaledFont());
FT_UInt gid = FT_Get_Char_Index(face, ch);
cairo_ft_scaled_font_unlock_face(aFont->CairoScaledFont());
if (gid != 0) {
aFont->GetFontEntry()->mCharacterMap.set(ch);
return PR_TRUE;
if (list->IndexOf(aName) == list->NoIndex)
list->AppendElement(aName);
}
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
inline FontEntry *
gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<>& foo, PRUint32 ch)
{
for (int i = 0; i < aGroup->FontListLength(); i++) {
nsRefPtr<gfxFT2Font> font = aGroup->GetFontAt(i);
if (HasCharacter(font, ch))
return font;
void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList) {
NS_ASSERTION(aLangGroup, "aLangGroup is null");
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
/* this lookup has to depend on weight and style */
nsCAutoString key(aLangGroup);
key.Append("-");
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
inline gfxFT2Font *
gfxFT2FontGroup::FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRUint32 nextCh, gfxFT2Font *aFont)
{
gfxFT2Font *selectedFont;
// last resort...
GetPrefFonts(CJK_LANG_JA, aFontEntryList);
GetPrefFonts(CJK_LANG_KO, aFontEntryList);
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
// 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;
platform->SetPrefFontEntries(key, aFontEntryList);
}
}
for (PRUint32 i = 0; i < FontListLength(); i++) {
nsRefPtr<gfxFT2Font> font = GetFontAt(i);
if (HasCharacter(font, ch))
return font;
already_AddRefed<gfxFT2Font>
gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& aFontEntryList, PRUint32 aCh)
{
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;
}
#if 0
// check the list of fonts
selectedFont = WhichFontSupportsChar(mGroup->GetFontList(), ch);
already_AddRefed<gfxFont>
gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
{
if (aCh > 0xFFFF)
return nsnull;
// 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;
nsRefPtr<gfxFT2Font> selectedFont;
// check out the style's language group
if (!selectedFont) {
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
this->GetPrefFonts(mGroup->GetStyle()->langGroup.get(), fonts);
selectedFont = WhichFontSupportsChar(fonts, ch);
}
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
GetPrefFonts(mStyle.langGroup.get(), fonts);
selectedFont = WhichFontSupportsChar(fonts, aCh);
// otherwise search prefs
if (!selectedFont) {
/* first check with the script properties to see what they think */
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"));
PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
nsAutoTArray<nsRefPtr<FontEntry>, 15> fonts;
this->GetCJKPrefFonts(fonts);
selectedFont = WhichFontSupportsChar(fonts, ch);
} else {
const char *langGroup = LangGroupFromUnicodeRange(unicodeRange);
if (langGroup) {
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroup));
/* 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>, 5> fonts;
this->GetPrefFonts(langGroup, fonts);
selectedFont = WhichFontSupportsChar(fonts, ch);
}
nsAutoTArray<nsRefPtr<FontEntry>, 15> fonts;
GetCJKPrefFonts(fonts);
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 && aFont && HasCharacter(aFont, ch))
selectedFont = aFont;
// 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);
if (selectedFont) {
nsRefPtr<gfxFont> f = static_cast<gfxFont*>(selectedFont.get());
return f.forget();
}
return selectedFont;
#endif
return nsnull;
}
PRUint32
gfxFT2FontGroup::ComputeRanges()
already_AddRefed<gfxFont>
gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
{
const PRUnichar *str = mString.get();
PRUint32 len = mString.Length();
mRanges.Clear();
PRUint32 prevCh = 0;
for (PRUint32 i = 0; i < len; i++) {
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;
nsRefPtr<gfxFont> selectedFont;
nsRefPtr<gfxFT2Font> refFont = GetFontAt(0);
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
selectedFont = platform->FindFontForChar(aCh, refFont);
if (selectedFont)
return selectedFont.forget();
return nsnull;
}
void gfxFT2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun)
{
ComputeRanges();
ComputeRanges(mRanges, mString.get(), 0, mString.Length());
PRUint32 offset = 0;
for (PRUint32 i = 0; i < mRanges.Length(); ++i) {
const TextRange& range = mRanges[i];
const gfxTextRange& range = mRanges[i];
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);
offset += rangeLength;
}
@ -908,9 +1027,16 @@ gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle)
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) {
font = new gfxFT2Font(fe, aStyle);
font = new gfxFT2Font(aFontEntry, aStyle);
if (!font)
return nsnull;
gfxFontCache::GetCache()->AddNew(font);

View File

@ -44,6 +44,7 @@
#include "gfxPlatformGtk.h"
#include "nsUnicharUtils.h"
#include "gfxFontconfigUtils.h"
#ifdef MOZ_PANGO
#include "gfxPangoFonts.h"
@ -95,8 +96,11 @@ gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
#ifndef MOZ_PANGO
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
typedef nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > PrefFontTable;
static FontTable *gPlatformFonts = NULL;
static FontTable *gPlatformFontAliases = NULL;
static PrefFontTable *gPrefFonts = NULL;
static gfxSparseBitSet *gCodepointsWithNoFonts = NULL;
static FT_Library gPlatformFTLibrary = NULL;
#endif
@ -119,6 +123,9 @@ gfxPlatformGtk::gfxPlatformGtk()
gPlatformFonts->Init(100);
gPlatformFontAliases = new FontTable();
gPlatformFontAliases->Init(100);
gPrefFonts = new PrefFontTable();
gPrefFonts->Init(100);
gCodepointsWithNoFonts = new gfxSparseBitSet();
UpdateFontList();
#endif
@ -137,6 +144,10 @@ gfxPlatformGtk::~gfxPlatformGtk()
gPlatformFonts = NULL;
delete gPlatformFontAliases;
gPlatformFontAliases = NULL;
delete gPrefFonts;
gPrefFonts = NULL;
delete gCodepointsWithNoFonts;
gCodepointsWithNoFonts = NULL;
FT_Done_FreeType(gPlatformFTLibrary);
gPlatformFTLibrary = NULL;
@ -369,15 +380,14 @@ gfxPlatformGtk::UpdateFontList()
nsAutoString name(NS_ConvertUTF8toUTF16(nsDependentCString(str)).get());
nsAutoString key(name);
/* FIXME DFB */
//ToLowerCase(key);
ToLowerCase(key);
nsRefPtr<FontFamily> ff;
if (!gPlatformFonts->Get(key, &ff)) {
ff = new FontFamily(name);
gPlatformFonts->Put(key, ff);
}
FontEntry *fe = new FontEntry(ff->mName);
FontEntry *fe = new FontEntry(ff->Name());
ff->AddFontEntry(fe);
if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, (FcChar8 **) &str) == FcResultMatch) {
@ -429,13 +439,12 @@ gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
{
nsAutoString name(aFontName);
/* FIXME: DFB */
//ToLowerCase(name);
ToLowerCase(name);
nsRefPtr<FontFamily> ff;
if (gPlatformFonts->Get(name, &ff) ||
gPlatformFontAliases->Get(name, &ff)) {
aAborted = !(*aCallback)(ff->mName, aClosure);
aAborted = !(*aCallback)(ff->Name(), aClosure);
return NS_OK;
}
@ -451,8 +460,7 @@ gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
continue;
nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
/* FIXME: DFB */
//ToLowerCase(altName);
ToLowerCase(altName);
if (gPlatformFonts->Get(altName, &ff)) {
//printf("Adding alias: %s -> %s\n", utf8Name.get(), str);
gPlatformFontAliases->Put(name, ff);
@ -486,8 +494,7 @@ gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
continue;
nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
/* FIXME: DFB */
//ToLowerCase(altName);
ToLowerCase(altName);
if (gPlatformFonts->Get(altName, &ff)) {
//printf("Adding alias: %s -> %s\n", utf8Name.get(), str);
gPlatformFontAliases->Put(name, ff);
@ -668,8 +675,7 @@ FontFamily *
gfxPlatformGtk::FindFontFamily(const nsAString& aName)
{
nsAutoString name(aName);
/* FIXME: DFB */
//ToLowerCase(name);
ToLowerCase(name);
nsRefPtr<FontFamily> ff;
if (!gPlatformFonts->Get(name, &ff)) {
@ -687,6 +693,58 @@ gfxPlatformGtk::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontS
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

View File

@ -74,8 +74,11 @@ static void do_qt_pixmap_unref (void *data)
}
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
typedef nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > PrefFontTable;
static FontTable *gPlatformFonts = NULL;
static FontTable *gPlatformFontAliases = NULL;
static PrefFontTable *gPrefFonts = NULL;
static gfxSparseBitSet *gCodepointsWithNoFonts = NULL;
static FT_Library gPlatformFTLibrary = NULL;
@ -91,6 +94,9 @@ gfxQtPlatform::gfxQtPlatform()
gPlatformFonts->Init(100);
gPlatformFontAliases = new FontTable();
gPlatformFontAliases->Init(100);
gPrefFonts = new PrefFontTable();
gPrefFonts->Init(100);
gCodepointsWithNoFonts = new gfxSparseBitSet();
UpdateFontList();
InitDPI();
@ -105,6 +111,10 @@ gfxQtPlatform::~gfxQtPlatform()
gPlatformFonts = NULL;
delete gPlatformFontAliases;
gPlatformFontAliases = NULL;
delete gPrefFonts;
gPrefFonts = NULL;
delete gCodepointsWithNoFonts;
gCodepointsWithNoFonts = NULL;
cairo_debug_reset_static_data();
@ -389,3 +399,55 @@ gfxQtPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontSt
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;
#ifdef MOZ_FT2_FONTS
aFontFamily->FindFontForChar(data);
#else
const PRUint32 ch = data->mCh;
nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->mFontToMatch->GetStyle());
@ -619,7 +622,6 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
PRInt32 rank = 0;
#ifndef MOZ_FT2_FONTS
// skip over non-unicode and bitmap fonts and fonts that don't have
// the code point we're looking for
if (fe->IsCrappyFont() || !fe->mCharacterMap.test(ch))
@ -639,7 +641,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
rank += 3;
if (fe->mWindowsPitch == mfe->mWindowsPitch)
rank += 3;
#endif
/* italic */
const PRBool italic = (data->mFontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
if (fe->mItalic != italic)
@ -658,6 +660,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
data->mBestMatch = fe;
data->mMatchRank = rank;
}
#endif
return PL_DHASH_NEXT;
}
@ -678,10 +681,10 @@ gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
if (data.mBestMatch) {
#ifdef MOZ_FT2_FONTS
nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(data.mBestMatch->mName,
gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
aFont->GetStyle());
gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret);
gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret);
#else
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),