From c1e34c0aff0d04a71758a10afbcf7f2d4fdd9300 Mon Sep 17 00:00:00 2001 From: "pavlov%pavlov.net" Date: Wed, 26 Mar 2008 18:02:57 +0000 Subject: [PATCH] bug 424018. make character map loading lazy to fix ts regression. r=vlad a=beltzner --- gfx/thebes/public/gfxFontUtils.h | 8 +- gfx/thebes/public/gfxWindowsFonts.h | 16 +- gfx/thebes/public/gfxWindowsPlatform.h | 6 +- gfx/thebes/src/gfxFontUtils.cpp | 16 +- gfx/thebes/src/gfxQuartzFontCache.h | 1 - gfx/thebes/src/gfxQuartzFontCache.mm | 2 +- gfx/thebes/src/gfxWindowsFonts.cpp | 269 +++++++++++++++++++++- gfx/thebes/src/gfxWindowsPlatform.cpp | 298 ++----------------------- 8 files changed, 317 insertions(+), 299 deletions(-) diff --git a/gfx/thebes/public/gfxFontUtils.h b/gfx/thebes/public/gfxFontUtils.h index c716ac11f97..ec7485aae24 100644 --- a/gfx/thebes/public/gfxFontUtils.h +++ b/gfx/thebes/public/gfxFontUtils.h @@ -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 || diff --git a/gfx/thebes/public/gfxWindowsFonts.h b/gfx/thebes/public/gfxWindowsFonts.h index 14f4516d671..9f75f1c2ecc 100644 --- a/gfx/thebes/public/gfxWindowsFonts.h +++ b/gfx/thebes/public/gfxWindowsFonts.h @@ -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 > mVariations; nsString mName; + +private: + PRBool mHasStyles; }; class FontEntry diff --git a/gfx/thebes/public/gfxWindowsPlatform.h b/gfx/thebes/public/gfxWindowsPlatform.h index 83392414915..3ef1c2eb6e9 100644 --- a/gfx/thebes/public/gfxWindowsPlatform.h +++ b/gfx/thebes/public/gfxWindowsPlatform.h @@ -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 > *array); void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray >& 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& aFontFamily, diff --git a/gfx/thebes/src/gfxFontUtils.cpp b/gfx/thebes/src/gfxFontUtils.cpp index 48a3c499117..0aa1192587f 100644 --- a/gfx/thebes/src/gfxFontUtils.cpp +++ b/gfx/thebes/src/gfxFontUtils.cpp @@ -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; } diff --git a/gfx/thebes/src/gfxQuartzFontCache.h b/gfx/thebes/src/gfxQuartzFontCache.h index 5c6f8588d92..ccf0ebd5e24 100644 --- a/gfx/thebes/src/gfxQuartzFontCache.h +++ b/gfx/thebes/src/gfxQuartzFontCache.h @@ -102,7 +102,6 @@ protected: MacOSFamilyEntry *mFamily; ATSUFontID mATSUFontID; - std::bitset<128> mUnicodeRanges; gfxSparseBitSet mCharacterMap; PRPackedBool mCmapInitialized; diff --git a/gfx/thebes/src/gfxQuartzFontCache.mm b/gfx/thebes/src/gfxQuartzFontCache.mm index 7bfd664832c..f134804828d 100644 --- a/gfx/thebes/src/gfxQuartzFontCache.mm +++ b/gfx/thebes/src/gfxQuartzFontCache.mm @@ -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; diff --git a/gfx/thebes/src/gfxWindowsFonts.cpp b/gfx/thebes/src/gfxWindowsFonts.cpp index 9e6d145f969..bcd8f471c51 100644 --- a/gfx/thebes/src/gfxWindowsFonts.cpp +++ b/gfx/thebes/src/gfxWindowsFonts.cpp @@ -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 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(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 > * PRUint32 len = fonts.Length(); for (PRUint32 i = 0; i < len; ++i) { - nsRefPtr fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], &mStyle); + nsRefPtr 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 fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, &mStyle); + nsRefPtr 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 fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(nsDependentString(logFont.lfFaceName), aStyle); + nsRefPtr 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, 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 */ diff --git a/gfx/thebes/src/gfxWindowsPlatform.cpp b/gfx/thebes/src/gfxWindowsPlatform.cpp index 88109cc6b12..be6d4c9b7b2 100644 --- a/gfx/thebes/src/gfxWindowsPlatform.cpp +++ b/gfx/thebes/src/gfxWindowsPlatform.cpp @@ -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(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 ff; if (!ht->Get(name, &ff)) { @@ -131,176 +128,12 @@ gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe, ht->Put(name, ff); } - nsRefPtr 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 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& aFontFamily, - void* userArg) -{ - NS_ASSERTION(aFontFamily->mVariations.Length() == 1, "We should only have 1 variation here"); - nsRefPtr 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 darkestItalic; - nsRefPtr darkestNonItalic; - PRUint8 highestItalic = 0, highestNonItalic = 0; - for (PRUint32 i = 0; i < aFontFamily->mVariations.Length(); i++) { - nsRefPtr 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 newEntry = new FontEntry(*darkestItalic.get()); - newEntry->mWeight = 600; - aFontFamily->mVariations.AppendElement(newEntry); - } - if (darkestNonItalic && darkestNonItalic->mWeight < 600) { - nsRefPtr 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 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(aClosure); + nsString *result = static_cast(aClosure); result->Assign(aName); return PR_FALSE; } @@ -591,7 +413,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey, const PRUint32 ch = data->ch; - nsRefPtr fe = GetPlatform()->FindFontEntry(aFontFamily, data->fontToMatch->GetStyle()); + nsRefPtr 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 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 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, 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 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 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