bug 424018. make character map loading lazy to fix ts regression. r=vlad a=beltzner

This commit is contained in:
pavlov%pavlov.net 2008-03-26 18:02:57 +00:00
Родитель fec8ae0b9e
Коммит c1e34c0aff
8 изменённых файлов: 317 добавлений и 299 удалений

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

@ -307,14 +307,14 @@ public:
} }
static nsresult static nsresult
ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges); ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap);
static nsresult static nsresult
ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges); ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap);
static nsresult static nsresult
ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges, PRPackedBool& aUnicodeFont, ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRPackedBool& aSymbolFont); PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
static inline bool IsJoiner(PRUint32 ch) { static inline bool IsJoiner(PRUint32 ch) {
return (ch == 0x200C || return (ch == 0x200C ||

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

@ -64,12 +64,22 @@ public:
THEBES_INLINE_DECL_REFCOUNTING(FontFamily) THEBES_INLINE_DECL_REFCOUNTING(FontFamily)
FontFamily(const nsAString& aName) : FontFamily(const nsAString& aName) :
mName(aName) mName(aName), mHasStyles(PR_FALSE) { }
{
}
FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
private:
static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data);
void FindStyleVariations();
public:
nsTArray<nsRefPtr<FontEntry> > mVariations; nsTArray<nsRefPtr<FontEntry> > mVariations;
nsString mName; nsString mName;
private:
PRBool mHasStyles;
}; };
class FontEntry class FontEntry

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

@ -85,8 +85,7 @@ public:
/* Find a FontFamily/FontEntry object that represents a font on your system given a name */ /* Find a FontFamily/FontEntry object that represents a font on your system given a name */
FontFamily *FindFontFamily(const nsAString& aName); FontFamily *FindFontFamily(const nsAString& aName);
FontEntry *FindFontEntry(FontFamily *aFontFamily, const gfxFontStyle *aFontStyle); FontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle);
FontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle *aFontStyle);
PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array); PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array); void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
@ -101,6 +100,9 @@ private:
static int CALLBACK FontEnumProc(const ENUMLOGFONTEXW *lpelfe, static int CALLBACK FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *metrics, const NEWTEXTMETRICEXW *metrics,
DWORD fontType, LPARAM data); DWORD fontType, LPARAM data);
static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data);
static PLDHashOperator PR_CALLBACK FontGetStylesProc(nsStringHashKey::KeyType aKey, static PLDHashOperator PR_CALLBACK FontGetStylesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily, nsRefPtr<FontFamily>& aFontFamily,

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

@ -220,7 +220,7 @@ static const struct UnicodeRangeTableEntry gUnicodeRanges[] = {
nsresult nsresult
gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges) gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap)
{ {
enum { enum {
OffsetFormat = 0, OffsetFormat = 0,
@ -260,7 +260,7 @@ gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBit
} }
nsresult nsresult
gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges) gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap)
{ {
enum { enum {
OffsetFormat = 0, OffsetFormat = 0,
@ -340,8 +340,8 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitS
(platformID == PlatformIDUnicode && encodingID == EncodingIDUCS4ForUnicodePlatform)) (platformID == PlatformIDUnicode && encodingID == EncodingIDUCS4ForUnicodePlatform))
nsresult nsresult
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges, gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont) PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
{ {
enum { enum {
OffsetVersion = 0, OffsetVersion = 0,
@ -395,9 +395,13 @@ gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCha
keepOffset = offset; keepOffset = offset;
break; break;
} else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) { } else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
keepFormat = format; keepFormat = format;
keepOffset = offset; keepOffset = offset;
} else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID)) { } else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID)) {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
keepFormat = format; keepFormat = format;
keepOffset = offset; keepOffset = offset;
break; // we don't want to try anything else when this format is available. break; // we don't want to try anything else when this format is available.
@ -407,9 +411,9 @@ gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCha
nsresult rv = NS_ERROR_FAILURE; nsresult rv = NS_ERROR_FAILURE;
if (keepFormat == 12) if (keepFormat == 12)
rv = ReadCMAPTableFormat12(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap, aUnicodeRanges); rv = ReadCMAPTableFormat12(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap);
else if (keepFormat == 4) else if (keepFormat == 4)
rv = ReadCMAPTableFormat4(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap, aUnicodeRanges); rv = ReadCMAPTableFormat4(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap);
return rv; return rv;
} }

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

@ -102,7 +102,6 @@ protected:
MacOSFamilyEntry *mFamily; MacOSFamilyEntry *mFamily;
ATSUFontID mATSUFontID; ATSUFontID mATSUFontID;
std::bitset<128> mUnicodeRanges;
gfxSparseBitSet mCharacterMap; gfxSparseBitSet mCharacterMap;
PRPackedBool mCmapInitialized; PRPackedBool mCmapInitialized;

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

@ -190,7 +190,7 @@ MacOSFontEntry::ReadCMAP()
nsresult rv = NS_ERROR_FAILURE; nsresult rv = NS_ERROR_FAILURE;
PRPackedBool unicodeFont, symbolFont; // currently ignored PRPackedBool unicodeFont, symbolFont; // currently ignored
rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, mUnicodeRanges, unicodeFont, symbolFont); rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, unicodeFont, symbolFont);
// for complex scripts, check for the presence of mort/morx // for complex scripts, check for the presence of mort/morx
PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE; PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;

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

@ -109,6 +109,260 @@ struct DCFromContext {
PRBool needsRelease; PRBool needsRelease;
}; };
/**********************************************************************
*
* class FontFamily
*
**********************************************************************/
static nsresult
ReadCMAP(HDC hdc, FontEntry *aFontEntry)
{
const PRUint32 kCMAP = (('c') | ('m' << 8) | ('a' << 16) | ('p' << 24));
DWORD len = GetFontData(hdc, kCMAP, 0, nsnull, 0);
if (len == GDI_ERROR || len == 0) // not a truetype font --
return NS_ERROR_FAILURE; // we'll treat it as a symbol font
nsAutoTArray<PRUint8,16384> buffer;
if (!buffer.AppendElements(len))
return NS_ERROR_OUT_OF_MEMORY;
PRUint8 *buf = buffer.Elements();
DWORD newLen = GetFontData(hdc, kCMAP, 0, buf, len);
NS_ENSURE_TRUE(newLen == len, NS_ERROR_FAILURE);
return gfxFontUtils::ReadCMAP(buf, len, aFontEntry->mCharacterMap,
aFontEntry->mUnicodeFont, aFontEntry->mSymbolFont);
}
struct FamilyAddStyleProcData {
HDC dc;
FontFamily *ff;
};
int CALLBACK
FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data)
{
const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
LOGFONTW logFont = lpelfe->elfLogFont;
FamilyAddStyleProcData *faspd = reinterpret_cast<FamilyAddStyleProcData*>(data);
FontFamily *ff = faspd->ff;
HDC hdc = faspd->dc;
// Some fonts claim to support things > 900, but we don't so clamp the sizes
logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
FontEntry *fe = nsnull;
for (PRUint32 i = 0; i < ff->mVariations.Length(); ++i) {
fe = ff->mVariations[i];
// check if we already know about this face
if (fe->mWeight == logFont.lfWeight &&
fe->mItalic == (logFont.lfItalic == 0xFF)) {
// update the charset bit here since this could be different
fe->mCharset[metrics.tmCharSet] = 1;
return 1;
}
}
fe = new FontEntry(ff->mName);
ff->mVariations.AppendElement(fe);
fe->mItalic = (logFont.lfItalic == 0xFF);
fe->mWeight = logFont.lfWeight;
if (metrics.ntmFlags & NTM_TYPE1)
fe->mIsType1 = fe->mForceGDI = PR_TRUE;
// fontType == TRUETYPE_FONTTYPE when (metrics.ntmFlags & NTM_TT_OPENTYPE)
if (fontType == TRUETYPE_FONTTYPE || metrics.ntmFlags & (NTM_PS_OPENTYPE))
fe->mTrueType = PR_TRUE;
// mark the charset bit
fe->mCharset[metrics.tmCharSet] = 1;
fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[3] != 0x00000000) {
// set the unicode ranges
PRUint32 x = 0;
for (PRUint32 i = 0; i < 4; ++i) {
DWORD range = nmetrics->ntmFontSig.fsUsb[i];
for (PRUint32 k = 0; k < 32; ++k) {
fe->mUnicodeRanges[x++] = (range & (1 << k)) != 0;
}
}
}
// read in the character map
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);
// ReadCMAP may change the values of mUnicodeFont and mSymbolFont
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;
// For fonts where we failed to read the character map,
// we should use GDI to slowly determine their cmap lazily
fe->mForceGDI = PR_TRUE;
//printf("%d, %s failed to get cmap\n", aFontEntry->mIsType1, NS_ConvertUTF16toUTF8(aFontEntry->mName).get());
}
SelectObject(hdc, oldFont);
DeleteObject(font);
}
return 1;
}
// general cmap reading routines moved to gfxFontUtils.cpp
void
FontFamily::FindStyleVariations()
{
mHasStyles = PR_TRUE;
HDC hdc = GetDC(nsnull);
LOGFONTW logFont;
memset(&logFont, 0, sizeof(LOGFONTW));
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfPitchAndFamily = 0;
PRUint32 l = PR_MIN(mName.Length(), LF_FACESIZE - 1);
memcpy(logFont.lfFaceName,
nsPromiseFlatString(mName).get(),
l * sizeof(PRUnichar));
logFont.lfFaceName[l] = 0;
FamilyAddStyleProcData faspd;
faspd.dc = hdc;
faspd.ff = this;
EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FontFamily::FamilyAddStylesProc, (LPARAM)&faspd, 0);
ReleaseDC(nsnull, hdc);
// Look for font families without bold variations and add a FontEntry
// with synthetic bold (weight 600) for them.
FontEntry *darkestItalic = nsnull;
FontEntry *darkestNonItalic = nsnull;
PRUint8 highestItalic = 0, highestNonItalic = 0;
for (PRUint32 i = 0; i < mVariations.Length(); i++) {
FontEntry *fe = mVariations[i];
if (fe->mItalic) {
if (!darkestItalic || fe->mWeight > darkestItalic->mWeight)
darkestItalic = fe;
} else {
if (!darkestNonItalic || fe->mWeight > darkestNonItalic->mWeight)
darkestNonItalic = fe;
}
}
if (darkestItalic && darkestItalic->mWeight < 600) {
FontEntry *newEntry = new FontEntry(*darkestItalic);
newEntry->mWeight = 600;
mVariations.AppendElement(newEntry);
}
if (darkestNonItalic && darkestNonItalic->mWeight < 600) {
FontEntry *newEntry = new FontEntry(*darkestNonItalic);
newEntry->mWeight = 600;
mVariations.AppendElement(newEntry);
}
}
FontEntry *
FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle)
{
if (!mHasStyles)
FindStyleVariations();
PRUint8 bestMatch = 0;
PRBool italic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
FontEntry *weightList[10] = { 0 };
for (PRUint32 j = 0; j < 2; j++) {
PRBool matchesSomething = PR_FALSE;
// build up an array of weights that match the italicness we're looking for
for (PRUint32 i = 0; i < mVariations.Length(); i++) {
FontEntry *fe = mVariations[i];
const PRUint8 weight = (fe->mWeight / 100);
if (fe->mItalic == italic) {
weightList[weight] = fe;
matchesSomething = PR_TRUE;
}
}
if (matchesSomething)
break;
italic = !italic;
}
PRInt8 baseWeight, weightDistance;
aFontStyle.ComputeWeightAndOffset(&baseWeight, &weightDistance);
// 500 isn't quite bold so we want to treat it as 400 if we don't
// have a 500 weight
if (baseWeight == 5 && weightDistance == 0) {
// If we have a 500 weight then use it
if (weightList[5])
return weightList[5];
// Otherwise treat as 400
baseWeight = 4;
}
PRInt8 matchBaseWeight = 0;
PRInt8 direction = (baseWeight > 5) ? 1 : -1;
for (PRInt8 i = baseWeight; ; i += direction) {
if (weightList[i]) {
matchBaseWeight = i;
break;
}
// if we've reached one side without finding a font,
// go the other direction until we find a match
if (i == 1 || i == 9)
direction = -direction;
}
FontEntry *matchFE;
const PRInt8 absDistance = abs(weightDistance);
direction = (weightDistance >= 0) ? 1 : -1;
for (PRInt8 i = matchBaseWeight, k = 0; i < 10 && i > 0; i += direction) {
if (weightList[i]) {
matchFE = weightList[i];
k++;
}
if (k > absDistance)
break;
}
if (!matchFE)
matchFE = weightList[matchBaseWeight];
NS_ASSERTION(matchFE, "we should always be able to return something here");
return matchFE;
}
/********************************************************************** /**********************************************************************
* *
* class gfxWindowsFont * class gfxWindowsFont
@ -442,7 +696,7 @@ gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *
PRUint32 len = fonts.Length(); PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++i) { for (PRUint32 i = 0; i < len; ++i) {
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], &mStyle); nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], mStyle);
list->AppendElement(fe); list->AppendElement(fe);
} }
} }
@ -458,7 +712,7 @@ gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies,
PRUint32 len = fonts.Length(); PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++i) { for (PRUint32 i = 0; i < len; ++i) {
const nsAutoString& str = fonts[i]; const nsAutoString& str = fonts[i];
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, &mStyle); nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, mStyle);
list->AppendElement(fe); list->AppendElement(fe);
} }
} }
@ -477,7 +731,7 @@ gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFo
NS_ERROR("Failed to create font group"); NS_ERROR("Failed to create font group");
return; return;
} }
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(nsDependentString(logFont.lfFaceName), aStyle); nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(nsDependentString(logFont.lfFaceName), *aStyle);
mFontEntries.AppendElement(fe); mFontEntries.AppendElement(fe);
} }
@ -737,7 +991,7 @@ struct ScriptPropertyEntry {
static const struct ScriptPropertyEntry gScriptToText[] = static const struct ScriptPropertyEntry gScriptToText[] =
{ {
{ nsnull, nsnull }, { nsnull, nsnull },
{ "LANG_ARABIC", "ara" }, { "LANG_ARABIC", "ar" }, // ara
{ "LANG_BULGARIAN", "bul" }, { "LANG_BULGARIAN", "bul" },
{ "LANG_CATALAN", "cat" }, { "LANG_CATALAN", "cat" },
{ "LANG_CHINESE", "zh-CN" }, //XXX right lang code? { "LANG_CHINESE", "zh-CN" }, //XXX right lang code?
@ -1304,6 +1558,13 @@ public:
(ch >= 0xF0000 && ch <= 0x10FFFD)) (ch >= 0xF0000 && ch <= 0x10FFFD))
return selectedFont; return 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);
}
// otherwise search prefs // otherwise search prefs
if (!selectedFont) { if (!selectedFont) {
/* first check with the script properties to see what they think */ /* first check with the script properties to see what they think */

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

@ -58,7 +58,13 @@
//#define DEBUG_CMAP_SIZE 1 //#define DEBUG_CMAP_SIZE 1
static nsresult ReadCMAP(HDC hdc, FontEntry *aFontEntry); static __inline void
BuildKeyNameFromFontName(nsAString &aName)
{
if (aName.Length() >= LF_FACESIZE)
aName.Truncate(LF_FACESIZE - 1);
ToLowerCase(aName);
}
int PR_CALLBACK int PR_CALLBACK
gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName, void *closure) gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName, void *closure)
@ -107,23 +113,14 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
FontTable *ht = reinterpret_cast<FontTable*>(data); FontTable *ht = reinterpret_cast<FontTable*>(data);
const NEWTEXTMETRICW& metrics = nmetrics->ntmTm; const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
LOGFONTW logFont = lpelfe->elfLogFont; const LOGFONTW& logFont = lpelfe->elfLogFont;
// Ignore vertical fonts // Ignore vertical fonts
if (logFont.lfFaceName[0] == L'@') { if (logFont.lfFaceName[0] == L'@')
return 1; return 1;
}
// Some fonts claim to support things > 900, but we don't so clamp the sizes nsAutoString name(logFont.lfFaceName);
logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100); BuildKeyNameFromFontName(name);
#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<FontFamily> ff; nsRefPtr<FontFamily> ff;
if (!ht->Get(name, &ff)) { if (!ht->Get(name, &ff)) {
@ -131,176 +128,12 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
ht->Put(name, ff); 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->mName);
/* 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 = fe->mForceGDI = PR_TRUE;
if (metrics.ntmFlags & (NTM_PS_OPENTYPE | NTM_TT_OPENTYPE))
fe->mTrueType = PR_TRUE;
// mark the charset bit
fe->mCharset[metrics.tmCharSet] = 1;
fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
if (nmetrics->ntmFontSig.fsUsb[0] == 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[1] == 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[2] == 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[3] == 0x00000000) {
// no unicode ranges
fe->mUnicodeFont = PR_FALSE;
} else {
fe->mUnicodeFont = PR_TRUE;
// set the unicode ranges
PRUint32 x = 0;
for (PRUint32 i = 0; i < 4; ++i) {
DWORD range = nmetrics->ntmFontSig.fsUsb[i];
for (PRUint32 k = 0; k < 32; ++k) {
fe->mUnicodeRanges[x++] = (range & (1 << k)) != 0;
}
}
}
/* 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; return 1;
} }
// general cmap reading routines moved to gfxFontUtils.cpp // general cmap reading routines moved to gfxFontUtils.cpp
static nsresult
ReadCMAP(HDC hdc, FontEntry *aFontEntry)
{
const PRUint32 kCMAP = (('c') | ('m' << 8) | ('a' << 16) | ('p' << 24));
DWORD len = GetFontData(hdc, kCMAP, 0, nsnull, 0);
if (len == GDI_ERROR || len == 0) // not a truetype font --
return NS_ERROR_FAILURE; // we'll treat it as a symbol font
nsAutoTArray<PRUint8,16384> buffer;
if (!buffer.AppendElements(len))
return NS_ERROR_OUT_OF_MEMORY;
PRUint8 *buf = buffer.Elements();
DWORD newLen = GetFontData(hdc, kCMAP, 0, buf, len);
NS_ENSURE_TRUE(newLen == len, NS_ERROR_FAILURE);
return gfxFontUtils::ReadCMAP(buf, len, aFontEntry->mCharacterMap, aFontEntry->mUnicodeRanges,
aFontEntry->mUnicodeFont, aFontEntry->mSymbolFont);
}
PLDHashOperator PR_CALLBACK
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->GetName().Length(), LF_FACESIZE - 1);
memcpy(logFont.lfFaceName,
nsPromiseFlatString(aFontEntry->GetName()).get(),
l * sizeof(PRUnichar));
logFont.lfFaceName[l] = 0;
EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)userArg, 0);
ReleaseDC(nsnull, hdc);
// Look for font families without bold variations and add a FontEntry
// with synthetic bold (weight 600) for them.
nsRefPtr<FontEntry> darkestItalic;
nsRefPtr<FontEntry> darkestNonItalic;
PRUint8 highestItalic = 0, highestNonItalic = 0;
for (PRUint32 i = 0; i < aFontFamily->mVariations.Length(); i++) {
nsRefPtr<FontEntry> fe = aFontFamily->mVariations[i];
if (fe->mItalic) {
if (!darkestItalic || fe->mWeight > darkestItalic->mWeight)
darkestItalic = fe;
} else {
if (!darkestNonItalic || fe->mWeight > darkestNonItalic->mWeight)
darkestNonItalic = fe;
}
}
if (darkestItalic && darkestItalic->mWeight < 600) {
nsRefPtr<FontEntry> newEntry = new FontEntry(*darkestItalic.get());
newEntry->mWeight = 600;
aFontFamily->mVariations.AppendElement(newEntry);
}
if (darkestNonItalic && darkestNonItalic->mWeight < 600) {
nsRefPtr<FontEntry> newEntry = new FontEntry(*darkestNonItalic.get());
newEntry->mWeight = 600;
aFontFamily->mVariations.AppendElement(newEntry);
}
return PL_DHASH_NEXT;
}
struct FontListData { struct FontListData {
FontListData(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsStringArray& aListOfFonts) : FontListData(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsStringArray& aListOfFonts) :
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {} mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
@ -355,14 +188,6 @@ RemoveCharsetFromFontSubstitute(nsAString &aName)
aName.Truncate(comma); aName.Truncate(comma);
} }
static void
BuildKeyNameFromFontName(nsAString &aName)
{
if (aName.Length() >= LF_FACESIZE)
aName.Truncate(LF_FACESIZE - 1);
ToLowerCase(aName);
}
nsresult nsresult
gfxWindowsPlatform::UpdateFontList() gfxWindowsPlatform::UpdateFontList()
{ {
@ -386,9 +211,6 @@ gfxWindowsPlatform::UpdateFontList()
EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0); EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0);
::ReleaseDC(nsnull, dc); ::ReleaseDC(nsnull, dc);
// Look for additional styles
mFonts.Enumerate(gfxWindowsPlatform::FontGetStylesProc, &mFonts);
// Create the list of FontSubstitutes // Create the list of FontSubstitutes
nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1"); nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey) if (!regKey)
@ -441,7 +263,7 @@ gfxWindowsPlatform::UpdateFontList()
static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure) static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
{ {
nsString* result = static_cast<nsString*>(aClosure); nsString *result = static_cast<nsString*>(aClosure);
result->Assign(aName); result->Assign(aName);
return PR_FALSE; return PR_FALSE;
} }
@ -591,7 +413,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
const PRUint32 ch = data->ch; const PRUint32 ch = data->ch;
nsRefPtr<FontEntry> fe = GetPlatform()->FindFontEntry(aFontFamily, data->fontToMatch->GetStyle()); nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->fontToMatch->GetStyle());
// 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
@ -613,7 +435,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
rank += 3; rank += 3;
/* italic */ /* italic */
const PRBool italic = (data->fontToMatch->GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? PR_TRUE : PR_FALSE; const PRBool italic = (data->fontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
if (fe->mItalic != italic) if (fe->mItalic != italic)
rank += 3; rank += 3;
@ -652,7 +474,7 @@ gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont)
if (!data.bestMatch) { if (!data.bestMatch) {
mCodepointsWithNoFonts.set(aCh); mCodepointsWithNoFonts.set(aCh);
} }
return data.bestMatch; return data.bestMatch;
} }
@ -666,8 +488,8 @@ gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
FontFamily * FontFamily *
gfxWindowsPlatform::FindFontFamily(const nsAString& aName) gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
{ {
nsString name(aName); nsAutoString name(aName);
ToLowerCase(name); BuildKeyNameFromFontName(name);
nsRefPtr<FontFamily> ff; nsRefPtr<FontFamily> ff;
if (!mFonts.Get(name, &ff) && if (!mFonts.Get(name, &ff) &&
@ -679,93 +501,13 @@ gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
} }
FontEntry * FontEntry *
gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle *aFontStyle) gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
{ {
nsRefPtr<FontFamily> ff = FindFontFamily(aName); nsRefPtr<FontFamily> ff = FindFontFamily(aName);
if (!ff) if (!ff)
return nsnull; return nsnull;
return FindFontEntry(ff, aFontStyle); return ff->FindFontEntry(aFontStyle);
}
FontEntry *
gfxWindowsPlatform::FindFontEntry(FontFamily *aFontFamily, const gfxFontStyle *aFontStyle)
{
PRUint8 bestMatch = 0;
PRBool italic = (aFontStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
nsAutoTArray<nsRefPtr<FontEntry>, 10> weightList;
weightList.AppendElements(10);
for (PRUint32 j = 0; j < 2; j++) {
PRBool matchesSomething = PR_FALSE;
// build up an array of weights that match the italicness we're looking for
for (PRUint32 i = 0; i < aFontFamily->mVariations.Length(); i++) {
nsRefPtr<FontEntry> fe = aFontFamily->mVariations[i];
const PRUint8 weight = (fe->mWeight / 100);
if (fe->mItalic == italic) {
weightList[weight] = fe;
matchesSomething = PR_TRUE;
}
}
if (matchesSomething)
break;
italic = !italic;
}
PRInt8 baseWeight, weightDistance;
aFontStyle->ComputeWeightAndOffset(&baseWeight, &weightDistance);
// 500 isn't quite bold so we want to treat it as 400 if we don't
// have a 500 weight
if (baseWeight == 5 && weightDistance == 0) {
// If we have a 500 weight then use it
if (weightList[5])
return weightList[5];
// Otherwise treat as 400
baseWeight = 4;
}
PRInt8 matchBaseWeight = 0;
PRInt8 direction = (baseWeight > 5) ? 1 : -1;
for (PRInt8 i = baseWeight; ; i += direction) {
if (weightList[i]) {
matchBaseWeight = i;
break;
}
// if we've reached one side without finding a font,
// go the other direction until we find a match
if (i == 1 || i == 9)
direction = -direction;
}
nsRefPtr<FontEntry> matchFE;
const PRInt8 absDistance = abs(weightDistance);
direction = (weightDistance >= 0) ? 1 : -1;
for (PRInt8 i = matchBaseWeight, k = 0; i < 10 && i > 0; i += direction) {
if (weightList[i]) {
matchFE = weightList[i];
k++;
}
if (k > absDistance)
break;
}
if (!matchFE) {
/* if we still don't have a match, grab the closest thing in the other direction */
direction = -direction;
for (PRInt8 i = matchBaseWeight; i < 10 && i > 0; i += direction) {
if (weightList[i]) {
matchFE = weightList[i];
}
}
}
NS_ASSERTION(matchFE, "we should always be able to return something here");
return matchFE;
} }
cmsHPROFILE cmsHPROFILE