bug 382542. Deal with different style variations of fonts containing different character maps. r=vlad

This commit is contained in:
pavlov@pavlov.net 2008-03-18 17:06:55 -07:00
Родитель 42c381d824
Коммит 605d1a5e15
4 изменённых файлов: 375 добавлений и 281 удалений

Просмотреть файл

@ -51,24 +51,45 @@
#include <usp10.h>
#include <cairo-win32.h>
/**
* FontEntry is a class that describes one of the fonts on the users system
* It contains information such as the name, font type, charset table and unicode ranges.
* It may be extended to also keep basic metrics of the fonts so that we can better
* compare one FontEntry to another.
* FontFamily is a class that describes one of the fonts on the users system. It holds
* each FontEntry (maps more directly to a font face) which holds font type, charset info
* and character map info.
*/
class FontEntry;
class FontFamily
{
public:
THEBES_INLINE_DECL_REFCOUNTING(FontFamily)
FontFamily(const nsAString& aName) :
mName(aName)
{
}
nsTArray<nsRefPtr<FontEntry> > mVariations;
nsString mName;
};
class FontEntry
{
public:
THEBES_INLINE_DECL_REFCOUNTING(FontEntry)
FontEntry(const nsAString& aName) :
mName(aName), mDefaultWeight(0),
mUnicodeFont(PR_FALSE), mSymbolFont(PR_FALSE), mIsType1(PR_FALSE),
FontEntry(FontFamily *aFontFamily) :
mFamily(aFontFamily), mUnicodeFont(PR_FALSE), mSymbolFont(PR_FALSE),
mTrueType(PR_FALSE), mIsType1(PR_FALSE),
mIsBadUnderlineFont(PR_FALSE), mCharset(0), mUnicodeRanges(0)
{
}
const nsString& GetName() const {
return mFamily->mName;
}
PRBool IsCrappyFont() const {
/* return if it is a bitmap not a unicode font */
return (!mUnicodeFont || mSymbolFont || mIsType1);
@ -80,18 +101,18 @@ public:
// Japanese 'Mincho' fonts do not belong to FF_MODERN even if
// they are fixed pitch because they have variable stroke width.
if (mFamily == FF_ROMAN && mPitch & FIXED_PITCH) {
if (mWindowsFamily == FF_ROMAN && mWindowsPitch & FIXED_PITCH) {
return aGeneric.EqualsLiteral("monospace");
}
// Japanese 'Gothic' fonts do not belong to FF_SWISS even if
// they are variable pitch because they have constant stroke width.
if (mFamily == FF_MODERN && mPitch & VARIABLE_PITCH) {
if (mWindowsFamily == FF_MODERN && mWindowsPitch & VARIABLE_PITCH) {
return aGeneric.EqualsLiteral("sans-serif");
}
// All other fonts will be grouped correctly using family...
switch (mFamily) {
switch (mWindowsFamily) {
case FF_DONTCARE:
return PR_TRUE;
case FF_ROMAN:
@ -158,52 +179,29 @@ public:
return mUnicodeRanges[range];
}
class WeightTable
{
public:
THEBES_INLINE_DECL_REFCOUNTING(WeightTable)
WeightTable() : mWeights(0) {}
~WeightTable() {}
PRBool TriedWeight(PRUint8 aWeight) {
return mWeights[aWeight - 1 + 10];
}
PRBool HasWeight(PRUint8 aWeight) {
return mWeights[aWeight - 1];
}
void SetWeight(PRUint8 aWeight, PRBool aValue) {
mWeights[aWeight - 1] = aValue;
mWeights[aWeight - 1 + 10] = PR_TRUE;
}
private:
std::bitset<20> mWeights;
};
// whether this font family is in "bad" underline offset blacklist.
PRBool IsBadUnderlineFont() { return mIsBadUnderlineFont != 0; }
// The family name of the font
nsString mName;
/* needs to be a weak pointer to avoid a cycle */
FontFamily *mFamily;
PRUint16 mDefaultWeight;
PRUint8 mFamily;
PRUint8 mPitch;
PRUint8 mWindowsFamily;
PRUint8 mWindowsPitch;
PRPackedBool mUnicodeFont;
PRPackedBool mSymbolFont;
PRPackedBool mTrueType;
PRPackedBool mIsType1;
PRPackedBool mIsBadUnderlineFont;
PRPackedBool mItalic;
PRUint16 mWeight;
std::bitset<256> mCharset;
std::bitset<128> mUnicodeRanges;
WeightTable mWeightTable;
gfxSparseBitSet mCharacterMap;
};
/**********************************************************************
*
* class gfxWindowsFont
@ -238,7 +236,7 @@ public:
protected:
HFONT MakeHFONT();
void FillLogFont(gfxFloat aSize, PRInt16 aWeight);
void FillLogFont(gfxFloat aSize);
HFONT mFont;
gfxFloat mAdjustedSize;
@ -297,6 +295,11 @@ public:
virtual gfxWindowsFont *GetFontAt(PRInt32 i);
void GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list);
void FamilyListToArrayList(const nsString& aFamilies,
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *list);
protected:
void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const char *aString, PRUint32 aLength);
void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
@ -304,6 +307,7 @@ protected:
void InitTextRunUniscribe(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
private:
nsCString mGenericFamily;
nsTArray<nsRefPtr<FontEntry> > mFontEntries;
};

Просмотреть файл

@ -83,11 +83,14 @@ public:
*/
FontEntry *FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont);
/* Find a FontEntry object that represents a font on your system given a name */
FontEntry *FindFontEntry(const nsAString& aName);
/* Find a FontFamily/FontEntry object that represents a font on your system given a name */
FontFamily *FindFontFamily(const nsAString& aName);
FontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle *aFontStyle);
PRBool GetPrefFontEntries(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array);
void SetPrefFontEntries(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
private:
void Init();
@ -98,8 +101,12 @@ private:
const NEWTEXTMETRICEXW *metrics,
DWORD fontType, LPARAM data);
static PLDHashOperator PR_CALLBACK FontGetStylesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg);
static PLDHashOperator PR_CALLBACK FontGetCMapDataProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontEntry>& aFontEntry,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg);
static int CALLBACK FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
@ -107,20 +114,20 @@ private:
DWORD fontType, LPARAM data);
static PLDHashOperator PR_CALLBACK HashEnumFunc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontEntry>& aData,
nsRefPtr<FontFamily>& aData,
void* userArg);
static PLDHashOperator PR_CALLBACK FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontEntry>& aFontEntry,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg);
virtual cmsHPROFILE GetPlatformCMSOutputProfile();
static int PR_CALLBACK PrefChangedCallback(const char*, void*);
nsDataHashtable<nsStringHashKey, nsRefPtr<FontEntry> > mFonts;
nsDataHashtable<nsStringHashKey, nsRefPtr<FontEntry> > mFontAliases;
nsDataHashtable<nsStringHashKey, nsRefPtr<FontEntry> > mFontSubstitutes;
FontTable mFonts;
FontTable mFontAliases;
FontTable mFontSubstitutes;
nsStringArray mNonExistingFonts;
// when system-wide font lookup fails for a character, cache it to skip future searches

Просмотреть файл

@ -122,7 +122,7 @@ gfxWindowsFont::gfxWindowsFont(const nsAString& aName, const gfxFontStyle *aFont
mMetrics(nsnull)
{
// XXX we should work to get this passed in rather than having to find it again.
mFontEntry = gfxWindowsPlatform::GetPlatform()->FindFontEntry(aName);
mFontEntry = gfxWindowsPlatform::GetPlatform()->FindFontEntry(aName, aFontStyle);
NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack.");
mFont = MakeHFONT(); // create the HFONT, compute metrics, etc
@ -194,87 +194,10 @@ gfxWindowsFont::MakeHFONT()
if (mFont)
return mFont;
PRInt8 baseWeight, weightDistance;
GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
HDC dc = nsnull;
PRUint32 chosenWeight = 0;
PRUint8 direction = (weightDistance >= 0) ? 1 : -1;
/* Special case 500 and adjust it to 400 if we don't have it so that
we don't pick a bolder font */
if (baseWeight == 5 && weightDistance == 0) {
if (!mFontEntry->mWeightTable.TriedWeight(5)) {
if (!dc)
dc = GetDC((HWND)nsnull);
FillLogFont(GetStyle()->size, 500);
mFont = CreateFontIndirectW(&mLogFont);
HGDIOBJ oldFont = SelectObject(dc, mFont);
TEXTMETRIC metrics;
GetTextMetrics(dc, &metrics);
PRBool hasWeight = (metrics.tmWeight == 500);
mFontEntry->mWeightTable.SetWeight(5, hasWeight);
if (hasWeight)
chosenWeight = 500;
SelectObject(dc, oldFont);
}
if (!mFontEntry->mWeightTable.HasWeight(5)) {
baseWeight--; /* move the base weight to 400 */
}
}
if (chosenWeight == 0) {
for (PRUint8 i = baseWeight, k = 0; i < 10 && i >= 1; i+=direction) {
if (mFontEntry->mWeightTable.HasWeight(i)) {
k++;
chosenWeight = i * 100;
} else if (mFontEntry->mWeightTable.TriedWeight(i)) {
continue;
} else {
const PRUint32 tryWeight = i * 100;
if (!dc)
dc = GetDC((HWND)nsnull);
FillLogFont(GetStyle()->size, tryWeight);
mFont = CreateFontIndirectW(&mLogFont);
HGDIOBJ oldFont = SelectObject(dc, mFont);
TEXTMETRIC metrics;
GetTextMetrics(dc, &metrics);
PRBool hasWeight = (metrics.tmWeight == tryWeight);
mFontEntry->mWeightTable.SetWeight(i, hasWeight);
if (hasWeight) {
chosenWeight = i * 100;
k++;
}
SelectObject(dc, oldFont);
if (k <= abs(weightDistance)) {
DeleteObject(mFont);
mFont = nsnull;
}
}
if (k > abs(weightDistance)) {
chosenWeight = i * 100;
break;
}
}
}
if (chosenWeight == 0)
chosenWeight = baseWeight * 100;
mAdjustedSize = GetStyle()->size;
if (GetStyle()->sizeAdjust > 0.0) {
if (!mFont) {
FillLogFont(mAdjustedSize, chosenWeight);
FillLogFont(mAdjustedSize);
mFont = CreateFontIndirectW(&mLogFont);
}
@ -292,13 +215,10 @@ gfxWindowsFont::MakeHFONT()
}
if (!mFont) {
FillLogFont(mAdjustedSize, chosenWeight);
FillLogFont(mAdjustedSize);
mFont = CreateFontIndirectW(&mLogFont);
}
if (dc)
ReleaseDC((HWND)nsnull, dc);
return mFont;
}
@ -388,7 +308,7 @@ gfxWindowsFont::ComputeMetrics()
}
void
gfxWindowsFont::FillLogFont(gfxFloat aSize, PRInt16 aWeight)
gfxWindowsFont::FillLogFont(gfxFloat aSize)
{
#define CLIP_TURNOFF_FONTASSOCIATION 0x40
@ -412,8 +332,20 @@ gfxWindowsFont::FillLogFont(gfxFloat aSize, PRInt16 aWeight)
mLogFont.lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION;
mLogFont.lfQuality = DEFAULT_QUALITY;
mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
// always force lfItalic if we want it. Font selection code will
// do its best to give us an italic font entry, but if no face exists
// it may give us a regular one based on weight. Windows should
// do fake italic for us in that case.
mLogFont.lfItalic = (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? TRUE : FALSE;
mLogFont.lfWeight = aWeight;
// for truetype fonts we want to use the entry's weight.
// for bitmap fonts we want to force our boldness.
if (mFontEntry->mTrueType) {
mLogFont.lfWeight = mFontEntry->mWeight;
} else {
PRInt8 baseWeight, weightDistance;
GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
mLogFont.lfWeight = (baseWeight * 100) + (weightDistance * 100);
}
int len = PR_MIN(mName.Length(), LF_FACESIZE - 1);
memcpy(mLogFont.lfFaceName, nsPromiseFlatString(mName).get(), len * 2);
@ -485,9 +417,9 @@ gfxWindowsFont::SetupCairoFont(gfxContext *aContext)
static already_AddRefed<gfxWindowsFont>
GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry->mName, aStyle);
nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry->GetName(), aStyle);
if (!font) {
font = new gfxWindowsFont(aFontEntry->mName, aStyle);
font = new gfxWindowsFont(aFontEntry->GetName(), aStyle);
if (!font)
return nsnull;
gfxFontCache::GetCache()->AddNew(font);
@ -498,25 +430,53 @@ GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
}
static PRBool
AddFontEntryToArray(const nsAString& aName,
AddFontNameToArray(const nsAString& aName,
const nsACString& aGenericName,
void *closure)
{
if (!aName.IsEmpty()) {
nsTArray<nsRefPtr<FontEntry> > *list = static_cast<nsTArray<nsRefPtr<FontEntry> >*>(closure);
nsTArray<nsAutoString> *list = static_cast<nsTArray<nsAutoString> *>(closure);
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(aName);
if (list->IndexOf(fe) == list->NoIndex)
list->AppendElement(fe);
if (list->IndexOf(aName) == list->NoIndex)
list->AppendElement(aName);
}
return PR_TRUE;
}
void
gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list)
{
nsAutoTArray<nsAutoString, 15> fonts;
ForEachFont(AddFontNameToArray, &fonts);
PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++i) {
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], &mStyle);
list->AppendElement(fe);
}
}
void
gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies,
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *list)
{
nsAutoTArray<nsAutoString, 15> fonts;
ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts);
PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++i) {
const nsAutoString& str = fonts[i];
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, &mStyle);
list->AppendElement(fe);
}
}
gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
: gfxFontGroup(aFamilies, aStyle)
{
ForEachFont(AddFontEntryToArray, &mFontEntries);
GroupFamilyListToArrayList(&mFontEntries);
if (mFontEntries.Length() == 0) {
// Should append default GUI font if there are no available fonts.
@ -527,7 +487,7 @@ gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFo
NS_ERROR("Failed to create font group");
return;
}
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(nsDependentString(logFont.lfFaceName));
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(nsDependentString(logFont.lfFaceName), aStyle);
mFontEntries.AppendElement(fe);
}
@ -1463,7 +1423,7 @@ public:
}
if (PR_LOG_TEST(gFontLog, PR_LOG_DEBUG)) {
if (fe)
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Using %s", NS_LossyConvertUTF16toASCII(fe->mName).get()));
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Using %s", NS_LossyConvertUTF16toASCII(fe->GetName()).get()));
else
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Unable to find font"));
}
@ -1490,15 +1450,22 @@ private:
NS_ASSERTION(aLangGroup, "aLangGroup is null");
gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform();
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
if (!platform->GetPrefFontEntries(aLangGroup, &fonts)) {
/* this lookup has to depend on weight and style */
nsCAutoString key(aLangGroup);
key.Append("-");
key.AppendInt(mGroup->GetStyle()->style);
key.Append("-");
key.AppendInt(mGroup->GetStyle()->weight);
if (!platform->GetPrefFontEntries(key, &fonts)) {
nsString fontString;
platform->GetPrefFonts(aLangGroup, fontString);
if (fontString.IsEmpty())
return;
gfxFontGroup::ForEachFont(fontString, nsDependentCString(aLangGroup),
AddFontEntryToArray, &fonts);
platform->SetPrefFontEntries(aLangGroup, fonts);
mGroup->FamilyListToArrayList(fontString, nsDependentCString(aLangGroup),
&fonts);
platform->SetPrefFontEntries(key, fonts);
}
array.AppendElements(fonts);
}
@ -1506,7 +1473,13 @@ private:
// this function assigns to the array passed in.
void GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& array) {
gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform();
if (!platform->GetPrefFontEntries("x-internal-cjk", &array)) {
nsCAutoString key("x-internal-cjk-");
key.AppendInt(mGroup->GetStyle()->style);
key.Append("-");
key.AppendInt(mGroup->GetStyle()->weight);
if (!platform->GetPrefFontEntries(key, &array)) {
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (!prefs)
return;
@ -1566,7 +1539,7 @@ private:
GetPrefFonts(CJK_LANG_ZH_HK, array);
GetPrefFonts(CJK_LANG_ZH_TW, array);
platform->SetPrefFontEntries("x-internal-cjk", array);
platform->SetPrefFontEntries(key, array);
}
}

Просмотреть файл

@ -58,6 +58,8 @@
//#define DEBUG_CMAP_SIZE 1
static nsresult ReadCMAP(HDC hdc, FontEntry *aFontEntry);
int PR_CALLBACK
gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName, void *closure)
{
@ -102,44 +104,53 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data)
{
gfxWindowsPlatform *thisp = reinterpret_cast<gfxWindowsPlatform*>(data);
FontTable *ht = reinterpret_cast<FontTable*>(data);
const LOGFONTW& logFont = lpelfe->elfLogFont;
const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
#ifdef DEBUG_pavlov
printf("%s %d %d %d\n", NS_ConvertUTF16toUTF8(nsDependentString(logFont.lfFaceName)).get(),
logFont.lfCharSet, logFont.lfItalic, logFont.lfWeight);
#endif
LOGFONTW logFont = lpelfe->elfLogFont;
// Ignore vertical fonts
if (logFont.lfFaceName[0] == L'@') {
return 1;
}
#ifdef DEBUG_pavlov
printf("%s %d %d %d\n", NS_ConvertUTF16toUTF8(nsDependentString(logFont.lfFaceName)).get(),
logFont.lfCharSet, logFont.lfItalic, logFont.lfWeight);
#endif
nsString name(logFont.lfFaceName);
ToLowerCase(name);
nsRefPtr<FontEntry> fe;
if (!thisp->mFonts.Get(name, &fe)) {
fe = new FontEntry(nsDependentString(logFont.lfFaceName));
thisp->mFonts.Put(name, fe);
nsRefPtr<FontFamily> ff;
if (!ht->Get(name, &ff)) {
ff = new FontFamily(nsDependentString(logFont.lfFaceName));
ht->Put(name, ff);
}
nsRefPtr<FontEntry> fe;
for (PRUint32 i = 0; i < ff->mVariations.Length(); ++i) {
fe = ff->mVariations[i];
if (fe->mWeight == logFont.lfWeight &&
fe->mItalic == (logFont.lfItalic == 0xFF)) {
return 1; /* we already know about this font */
}
}
fe = new FontEntry(ff);
/* don't append it until the end in case of error */
fe->mItalic = (logFont.lfItalic == 0xFF);
fe->mWeight = logFont.lfWeight;
if (metrics.ntmFlags & NTM_TYPE1)
fe->mIsType1 = PR_TRUE;
// mark the charset bit
fe->mCharset[metrics.tmCharSet] = 1;
// put the default weight in the weight table
fe->mWeightTable.SetWeight(PR_MAX(1, PR_MIN(9, metrics.tmWeight / 100)), PR_TRUE);
// store the default font weight
fe->mDefaultWeight = metrics.tmWeight;
fe->mFamily = logFont.lfPitchAndFamily & 0xF0;
fe->mPitch = logFont.lfPitchAndFamily & 0x0F;
fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
if (nmetrics->ntmFontSig.fsUsb[0] == 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[1] == 0x00000000 &&
@ -160,6 +171,51 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
}
}
/* read in the character map */
HDC hdc = GetDC(nsnull);
logFont.lfCharSet = DEFAULT_CHARSET;
HFONT font = CreateFontIndirectW(&logFont);
NS_ASSERTION(font, "This font creation should never ever ever fail");
if (font) {
HFONT oldFont = (HFONT)SelectObject(hdc, font);
TEXTMETRIC metrics;
GetTextMetrics(hdc, &metrics);
if (metrics.tmPitchAndFamily & TMPF_TRUETYPE)
fe->mTrueType = PR_TRUE;
if (NS_FAILED(ReadCMAP(hdc, fe))) {
// Type1 fonts aren't necessarily Unicode but
// this is the best guess we can make here
if (fe->mIsType1)
fe->mUnicodeFont = PR_TRUE;
else
fe->mUnicodeFont = PR_FALSE;
//printf("%d, %s failed to get cmap\n", aFontEntry->mIsType1, NS_ConvertUTF16toUTF8(aFontEntry->mName).get());
}
SelectObject(hdc, oldFont);
DeleteObject(font);
}
ReleaseDC(nsnull, hdc);
if (!fe->mUnicodeFont) {
/* non-unicode fonts.. boy lets just set all code points
between 0x20 and 0xFF. All the ones on my system do...
If we really wanted to test which characters in this
range were supported we could just generate a string with
each codepoint and do GetGlyphIndicies or similar to determine
what is there.
*/
fe->mCharacterMap.SetRange(0x20, 0xFF);
}
/* append the variation to the font family */
ff->mVariations.AppendElement(fe);
return 1;
}
@ -187,62 +243,32 @@ ReadCMAP(HDC hdc, FontEntry *aFontEntry)
}
PLDHashOperator PR_CALLBACK
gfxWindowsPlatform::FontGetCMapDataProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontEntry>& aFontEntry,
gfxWindowsPlatform::FontGetStylesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg)
{
NS_ASSERTION(aFontFamily->mVariations.Length() == 1, "We should only have 1 variation here");
nsRefPtr<FontEntry> aFontEntry = aFontFamily->mVariations[0];
HDC hdc = GetDC(nsnull);
LOGFONTW logFont;
memset(&logFont, 0, sizeof(LOGFONTW));
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfPitchAndFamily = 0;
PRUint32 l = PR_MIN(aFontEntry->mName.Length(), LF_FACESIZE - 1);
PRUint32 l = PR_MIN(aFontEntry->GetName().Length(), LF_FACESIZE - 1);
memcpy(logFont.lfFaceName,
nsPromiseFlatString(aFontEntry->mName).get(),
nsPromiseFlatString(aFontEntry->GetName()).get(),
l * sizeof(PRUnichar));
logFont.lfFaceName[l] = 0;
HFONT font = CreateFontIndirectW(&logFont);
if (font) {
HFONT oldFont = (HFONT)SelectObject(hdc, font);
nsresult rv = ReadCMAP(hdc, aFontEntry);
if (NS_FAILED(rv)) {
// Type1 fonts aren't necessarily Unicode but
// this is the best guess we can make here
if (aFontEntry->mIsType1)
aFontEntry->mUnicodeFont = PR_TRUE;
else
aFontEntry->mUnicodeFont = PR_FALSE;
//printf("%d, %s failed to get cmap\n", aFontEntry->mIsType1, NS_ConvertUTF16toUTF8(aFontEntry->mName).get());
}
SelectObject(hdc, oldFont);
DeleteObject(font);
}
EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)userArg, 0);
ReleaseDC(nsnull, hdc);
if (!aFontEntry->mUnicodeFont) {
/* non-unicode fonts.. boy lets just set all code points
between 0x20 and 0xFF. All the ones on my system do...
If we really wanted to test which characters in this
range were supported we could just generate a string with
each codepoint and do GetGlyphIndicies or similar to determine
what is there.
*/
aFontEntry->mCharacterMap.SetRange(0x20, 0xFF);
return PL_DHASH_NEXT;
}
return PL_DHASH_NEXT;
}
struct FontListData {
FontListData(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsStringArray& aListOfFonts) :
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
@ -253,18 +279,23 @@ struct FontListData {
PLDHashOperator PR_CALLBACK
gfxWindowsPlatform::HashEnumFunc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontEntry>& aFontEntry,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg)
{
FontListData *data = (FontListData*)userArg;
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
nsRefPtr<FontEntry> aFontEntry = aFontFamily->mVariations[0];
/* skip symbol fonts */
if (aFontEntry->mSymbolFont)
return PL_DHASH_NEXT;
if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
aFontEntry->MatchesGenericFamily(data->mGenericFamily))
data->mStringArray.AppendString(aFontEntry->mName);
data->mStringArray.AppendString(aFontFamily->mName);
return PL_DHASH_NEXT;
}
@ -317,11 +348,11 @@ gfxWindowsPlatform::UpdateFontList()
// Use the screen DC here.. should we use something else for printing?
HDC dc = ::GetDC(nsnull);
EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)this, 0);
EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0);
::ReleaseDC(nsnull, dc);
// Update all the fonts cmaps
mFonts.Enumerate(gfxWindowsPlatform::FontGetCMapDataProc, nsnull);
// Look for additional styles
mFonts.Enumerate(gfxWindowsPlatform::FontGetStylesProc, &mFonts);
// Create the list of FontSubstitutes
nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
@ -357,9 +388,9 @@ gfxWindowsPlatform::UpdateFontList()
BuildKeyNameFromFontName(substituteName);
RemoveCharsetFromFontSubstitute(actualFontName);
BuildKeyNameFromFontName(actualFontName);
nsRefPtr<FontEntry> fe;
if (!actualFontName.IsEmpty() && mFonts.Get(actualFontName, &fe))
mFontSubstitutes.Put(substituteName, fe);
nsRefPtr<FontFamily> ff;
if (!actualFontName.IsEmpty() && mFonts.Get(actualFontName, &ff))
mFontSubstitutes.Put(substituteName, ff);
else
mNonExistingFonts.AppendString(substituteName);
}
@ -392,12 +423,15 @@ gfxWindowsPlatform::InitBadUnderlineList()
ResolveFontName(blacklist[i], SimpleResolverCallback, &resolved, aborted);
if (resolved.IsEmpty())
continue;
FontEntry* fe = FindFontEntry(resolved);
if (!fe)
FontFamily *ff = FindFontFamily(resolved);
if (!ff)
continue;
for (PRUint32 j = 0; j < ff->mVariations.Length(); ++j) {
nsRefPtr<FontEntry> fe = ff->mVariations[j];
fe->mIsBadUnderlineFont = 1;
}
}
}
nsresult
gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
@ -432,11 +466,11 @@ gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName,
nsAutoString keyName(aFontName);
BuildKeyNameFromFontName(keyName);
nsRefPtr<FontEntry> fe;
if (mFonts.Get(keyName, &fe) ||
mFontSubstitutes.Get(keyName, &fe) ||
mFontAliases.Get(keyName, &fe)) {
aAborted = !(*aCallback)(fe->mName, aClosure);
nsRefPtr<FontFamily> ff;
if (mFonts.Get(keyName, &ff) ||
mFontSubstitutes.Get(keyName, &ff) ||
mFontAliases.Get(keyName, &ff)) {
aAborted = !(*aCallback)(ff->mName, aClosure);
// XXX If the font has font link, we should add the linked font.
return NS_OK;
}
@ -458,8 +492,7 @@ gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName,
HDC dc = ::GetDC(nsnull);
ResolveData data(aCallback, this, &keyName, aClosure);
aAborted =
!EnumFontFamiliesExW(dc, &logFont,
aAborted = !EnumFontFamiliesExW(dc, &logFont,
(FONTENUMPROCW)gfxWindowsPlatform::FontResolveProc,
(LPARAM)&data, 0);
if (data.mFoundCount == 0)
@ -484,10 +517,10 @@ gfxWindowsPlatform::FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
nsAutoString name(logFont.lfFaceName);
// Save the alias name to cache
nsRefPtr<FontEntry> fe;
nsRefPtr<FontFamily> ff;
nsAutoString keyName(name);
BuildKeyNameFromFontName(keyName);
if (!rData->mCaller->mFonts.Get(keyName, &fe)) {
if (!rData->mCaller->mFonts.Get(keyName, &ff)) {
// This case only occurs on failing to build
// the list of font substitue. In this case, the user should
// reboot the Windows. Probably, we don't have the good way for
@ -497,7 +530,7 @@ gfxWindowsPlatform::FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
}
rData->mFoundCount++;
rData->mCaller->mFontAliases.Put(*(rData->mFontName), fe);
rData->mCaller->mFontAliases.Put(*(rData->mFontName), ff);
return (rData->mCallback)(name, rData->mClosure);
@ -516,53 +549,61 @@ struct FontSearch {
PLDHashOperator PR_CALLBACK
gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontEntry>& aFontEntry,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg)
{
// XXX Improve this to look at the variations to find a better font
nsRefPtr<FontEntry> aFontEntry = aFontFamily->mVariations[0];
// bitmap fonts suck
if (aFontEntry->IsCrappyFont())
return PL_DHASH_NEXT;
FontSearch *data = (FontSearch*)userArg;
PRInt32 rank = 0;
PRUint32 ch = data->ch;
if (aFontEntry->mCharacterMap.test(ch)) {
rank += 20;
for (PRUint32 i = 0; i < aFontFamily->mVariations.Length(); ++i) {
PRInt32 rank = 0;
nsRefPtr<FontEntry> fe = aFontFamily->mVariations[i];
if (fe->mCharacterMap.test(ch)) {
// fonts that claim to support the range are more
// likely to be "better fonts" than ones that don't... (in theory)
if (aFontEntry->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
if (fe->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
rank += 1;
} else {
// if we didn't match any characters don't bother wasting more time.
continue;
}
// if we didn't match any characters don't bother wasting more time.
if (rank == 0)
return PL_DHASH_NEXT;
if (aFontEntry->SupportsLangGroup(data->fontToMatch->GetStyle()->langGroup))
if (fe->SupportsLangGroup(data->fontToMatch->GetStyle()->langGroup))
rank += 10;
if (data->fontToMatch->GetFontEntry()->mFamily == aFontEntry->mFamily)
if (fe->mWindowsFamily == data->fontToMatch->GetFontEntry()->mWindowsFamily)
rank += 5;
if (data->fontToMatch->GetFontEntry()->mFamily == aFontEntry->mPitch)
if (fe->mWindowsPitch == data->fontToMatch->GetFontEntry()->mWindowsFamily)
rank += 5;
/* italic */
const PRBool italic = (data->fontToMatch->GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? PR_TRUE : PR_FALSE;
if (fe->mItalic == italic)
rank += 55;
/* weight */
PRInt8 baseWeight, weightDistance;
data->fontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
PRUint16 targetWeight = (baseWeight * 100) + (weightDistance * 100);
if (targetWeight == aFontEntry->mDefaultWeight)
rank += 5;
if (fe->mWeight == targetWeight)
rank += 50;
if (rank > data->matchRank ||
(rank == data->matchRank && Compare(aFontEntry->mName, data->bestMatch->mName) > 0)) {
data->bestMatch = aFontEntry;
(rank == data->matchRank && Compare(fe->GetName(), data->bestMatch->GetName()) > 0)) {
data->bestMatch = fe;
data->matchRank = rank;
}
}
return PL_DHASH_NEXT;
}
@ -596,19 +637,90 @@ gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
return new gfxWindowsFontGroup(aFamilies, aStyle);
}
FontEntry *
gfxWindowsPlatform::FindFontEntry(const nsAString& aName)
FontFamily *
gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
{
nsString name(aName);
ToLowerCase(name);
nsRefPtr<FontEntry> fe;
if (!mFonts.Get(name, &fe) &&
!mFontSubstitutes.Get(name, &fe) &&
!mFontAliases.Get(name, &fe)) {
nsRefPtr<FontFamily> ff;
if (!mFonts.Get(name, &ff) &&
!mFontSubstitutes.Get(name, &ff) &&
!mFontAliases.Get(name, &ff)) {
return nsnull;
}
return fe.get();
return ff.get();
}
FontEntry *
gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle *aFontStyle)
{
nsRefPtr<FontFamily> ff = FindFontFamily(aName);
if (!ff)
return nsnull;
PRUint8 bestMatch = 0;
nsRefPtr<FontEntry> matchFE;
const PRBool italic = (aFontStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? PR_TRUE : PR_FALSE;
// build up an array of weights that match the italicness we're looking for
nsAutoTArray<nsRefPtr<FontEntry>, 10> weightList;
weightList.AppendElements(10);
for (PRInt32 i = 0; i < ff->mVariations.Length(); i++) {
nsRefPtr<FontEntry> fe = ff->mVariations[i];
const PRUint8 weight = (fe->mWeight / 100) - 1;
if (italic == fe->mItalic)
weightList[weight] = fe;
}
PRInt8 baseWeight, weightDistance;
aFontStyle->ComputeWeightAndOffset(&baseWeight, &weightDistance);
PRUint32 chosenWeight = 0;
PRUint8 direction = (weightDistance >= 0) ? 1 : -1;
WEIGHT_SELECTION:
for (PRUint8 i = baseWeight, k = 0; i < 10 && i >= 1; i+=direction) {
if (weightList[i - 1]) {
k++;
chosenWeight = i * 100;
}
if (k > abs(weightDistance)) {
chosenWeight = i * 100;
break;
}
}
// 500 isn't quite bold, so if we don't have a 500 weight
// lets pretend to be 400 and look again
if (baseWeight == 5 && weightDistance == 0 && chosenWeight > 500) {
baseWeight = 4;
goto WEIGHT_SELECTION;
}
// If we still don't have a chosen weight, just pick one
if (chosenWeight == 0)
chosenWeight = baseWeight * 100;
// If we end up with something like 900 here but only have 600,
// search backwards until we find a match
const PRUint32 index = (chosenWeight / 100) - 1;
for (PRInt32 j = index; j >= 0; --j) {
if (matchFE = weightList[j])
break;
}
if (!matchFE) {
NS_ASSERTION(italic, "Italic isn't set. This is bad");
// We should only ever hit this code in the case where we're looking for an
// italic font and there is no face for one, so ask for a match for a normal one.
// The font rendering code can still specify italic and Windows will
// do synthetic italic
gfxFontStyle style(*aFontStyle);
style.style = FONT_STYLE_NORMAL;
matchFE = FindFontEntry(aName, &style);
}
return matchFE;
}
cmsHPROFILE
@ -633,15 +745,13 @@ gfxWindowsPlatform::GetPlatformCMSOutputProfile()
}
PRBool
gfxWindowsPlatform::GetPrefFontEntries(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array)
gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> > *array)
{
nsCAutoString keyName(aLangGroup);
return mPrefFonts.Get(keyName, array);
return mPrefFonts.Get(aKey, array);
}
void
gfxWindowsPlatform::SetPrefFontEntries(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array)
gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& array)
{
nsCAutoString keyName(aLangGroup);
mPrefFonts.Put(keyName, array);
mPrefFonts.Put(aKey, array);
}