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 11:02:57 -07:00
parent da94aa6085
commit 8dd5ec194a
8 changed files with 317 additions and 299 deletions

View File

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

View File

@ -64,12 +64,22 @@ public:
THEBES_INLINE_DECL_REFCOUNTING(FontFamily)
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;
nsString mName;
private:
PRBool mHasStyles;
};
class FontEntry

View File

@ -85,8 +85,7 @@ public:
/* Find a FontFamily/FontEntry object that represents a font on your system given a name */
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);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
@ -101,6 +100,9 @@ private:
static int CALLBACK FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *metrics,
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,
nsRefPtr<FontFamily>& aFontFamily,

View File

@ -220,7 +220,7 @@ static const struct UnicodeRangeTableEntry gUnicodeRanges[] = {
nsresult
gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges)
gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap)
{
enum {
OffsetFormat = 0,
@ -260,7 +260,7 @@ gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBit
}
nsresult
gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges)
gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap)
{
enum {
OffsetFormat = 0,
@ -340,8 +340,8 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitS
(platformID == PlatformIDUnicode && encodingID == EncodingIDUCS4ForUnicodePlatform))
nsresult
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap, std::bitset<128>& aUnicodeRanges,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
{
enum {
OffsetVersion = 0,
@ -395,9 +395,13 @@ gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCha
keepOffset = offset;
break;
} else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
keepFormat = format;
keepOffset = offset;
} else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID)) {
aUnicodeFont = PR_TRUE;
aSymbolFont = PR_FALSE;
keepFormat = format;
keepOffset = offset;
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;
if (keepFormat == 12)
rv = ReadCMAPTableFormat12(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap, aUnicodeRanges);
rv = ReadCMAPTableFormat12(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap);
else if (keepFormat == 4)
rv = ReadCMAPTableFormat4(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap, aUnicodeRanges);
rv = ReadCMAPTableFormat4(aBuf + keepOffset, aBufLength - keepOffset, aCharacterMap);
return rv;
}

View File

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

View File

@ -190,7 +190,7 @@ MacOSFontEntry::ReadCMAP()
nsresult rv = NS_ERROR_FAILURE;
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
PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;

View File

@ -109,6 +109,260 @@ struct DCFromContext {
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
@ -442,7 +696,7 @@ gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *
PRUint32 len = fonts.Length();
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);
}
}
@ -458,7 +712,7 @@ gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies,
PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++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);
}
}
@ -477,7 +731,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), aStyle);
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(nsDependentString(logFont.lfFaceName), *aStyle);
mFontEntries.AppendElement(fe);
}
@ -737,7 +991,7 @@ struct ScriptPropertyEntry {
static const struct ScriptPropertyEntry gScriptToText[] =
{
{ nsnull, nsnull },
{ "LANG_ARABIC", "ara" },
{ "LANG_ARABIC", "ar" }, // ara
{ "LANG_BULGARIAN", "bul" },
{ "LANG_CATALAN", "cat" },
{ "LANG_CHINESE", "zh-CN" }, //XXX right lang code?
@ -1304,6 +1558,13 @@ public:
(ch >= 0xF0000 && ch <= 0x10FFFD))
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
if (!selectedFont) {
/* first check with the script properties to see what they think */

View File

@ -58,7 +58,13 @@
//#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
gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName, void *closure)
@ -107,23 +113,14 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
FontTable *ht = reinterpret_cast<FontTable*>(data);
const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
LOGFONTW logFont = lpelfe->elfLogFont;
const LOGFONTW& logFont = lpelfe->elfLogFont;
// Ignore vertical fonts
if (logFont.lfFaceName[0] == L'@') {
if (logFont.lfFaceName[0] == L'@')
return 1;
}
// 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);
#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);
nsAutoString name(logFont.lfFaceName);
BuildKeyNameFromFontName(name);
nsRefPtr<FontFamily> ff;
if (!ht->Get(name, &ff)) {
@ -131,176 +128,12 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
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;
}
// 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 {
FontListData(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsStringArray& aListOfFonts) :
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
@ -355,14 +188,6 @@ RemoveCharsetFromFontSubstitute(nsAString &aName)
aName.Truncate(comma);
}
static void
BuildKeyNameFromFontName(nsAString &aName)
{
if (aName.Length() >= LF_FACESIZE)
aName.Truncate(LF_FACESIZE - 1);
ToLowerCase(aName);
}
nsresult
gfxWindowsPlatform::UpdateFontList()
{
@ -386,9 +211,6 @@ gfxWindowsPlatform::UpdateFontList()
EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0);
::ReleaseDC(nsnull, dc);
// 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");
if (!regKey)
@ -441,7 +263,7 @@ gfxWindowsPlatform::UpdateFontList()
static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
{
nsString* result = static_cast<nsString*>(aClosure);
nsString *result = static_cast<nsString*>(aClosure);
result->Assign(aName);
return PR_FALSE;
}
@ -591,7 +413,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
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
// the code point we're looking for
@ -613,7 +435,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
rank += 3;
/* 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)
rank += 3;
@ -652,7 +474,7 @@ gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont)
if (!data.bestMatch) {
mCodepointsWithNoFonts.set(aCh);
}
return data.bestMatch;
}
@ -666,8 +488,8 @@ gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
FontFamily *
gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
{
nsString name(aName);
ToLowerCase(name);
nsAutoString name(aName);
BuildKeyNameFromFontName(name);
nsRefPtr<FontFamily> ff;
if (!mFonts.Get(name, &ff) &&
@ -679,93 +501,13 @@ gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
}
FontEntry *
gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle *aFontStyle)
gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
{
nsRefPtr<FontFamily> ff = FindFontFamily(aName);
if (!ff)
return nsnull;
return FindFontEntry(ff, 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;
return ff->FindFontEntry(aFontStyle);
}
cmsHPROFILE