bug 424018. make character map loading lazy to fix ts regression. r=vlad a=beltzner
This commit is contained in:
Родитель
fec8ae0b9e
Коммит
c1e34c0aff
|
@ -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 ||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ protected:
|
|||
MacOSFamilyEntry *mFamily;
|
||||
|
||||
ATSUFontID mATSUFontID;
|
||||
std::bitset<128> mUnicodeRanges;
|
||||
gfxSparseBitSet mCharacterMap;
|
||||
|
||||
PRPackedBool mCmapInitialized;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче