Bug 427411. Handle GetTextMetrics failing when we create a gfxWindowsFont (can happen if we're out of GDI resources or Windows' font catalog is stale). r=pavlov,a=damon

This commit is contained in:
roc+@cs.cmu.edu 2008-04-28 15:30:22 -07:00
parent 47fa543841
commit b243289a8d
4 changed files with 85 additions and 39 deletions

View File

@ -265,8 +265,12 @@ public:
return mSpaceGlyph;
};
PRBool IsValid() { GetMetrics(); return mIsValid; }
FontEntry *GetFontEntry() { return mFontEntry; }
static already_AddRefed<gfxWindowsFont>
GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle);
protected:
HFONT MakeHFONT();
void FillLogFont(gfxFloat aSize);
@ -288,6 +292,7 @@ private:
LOGFONTW mLogFont;
nsRefPtr<FontEntry> mFontEntry;
PRPackedBool mIsValid;
virtual PRBool SetupCairoFont(gfxContext *aContext);
};

View File

@ -84,7 +84,7 @@ public:
* code points they support as well as looking at things like the font
* family, style, weight, etc.
*/
FontEntry *FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont);
already_AddRefed<gfxWindowsFont> FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont);
/* Find a FontFamily/FontEntry object that represents a font on your system given a name */
FontFamily *FindFontFamily(const nsAString& aName);

View File

@ -386,7 +386,7 @@ gfxWindowsFont::gfxWindowsFont(const nsAString& aName, const gfxFontStyle *aFont
: gfxFont(aName, aFontStyle),
mFont(nsnull), mAdjustedSize(0.0), mScriptCache(nsnull),
mFontFace(nsnull), mScaledFont(nsnull),
mMetrics(nsnull), mFontEntry(aFontEntry)
mMetrics(nsnull), mFontEntry(aFontEntry), mIsValid(PR_TRUE)
{
NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack.");
@ -528,7 +528,18 @@ gfxWindowsFont::ComputeMetrics()
} else {
// Make a best-effort guess at extended metrics
// this is based on general typographic guidelines
GetTextMetrics(dc, &metrics);
// GetTextMetrics can fail if the font file has been removed
// or corrupted recently.
BOOL result = GetTextMetrics(dc, &metrics);
if (!result) {
NS_WARNING("Missing or corrupt font data, fasten your seatbelt");
mIsValid = PR_FALSE;
memset(mMetrics, 0, sizeof(*mMetrics));
SelectObject(dc, oldFont);
ReleaseDC((HWND)nsnull, dc);
return;
}
mMetrics->xHeight = ROUND((float)metrics.tmAscent * 0.56f); // 56% of ascent, best guess for non-true type
mMetrics->superscriptOffset = mMetrics->xHeight;
@ -676,8 +687,8 @@ gfxWindowsFont::SetupCairoFont(gfxContext *aContext)
* In either case, add a ref, append it to the aFonts array, and return it ---
* except for OOM in which case we do nothing and return null.
*/
static already_AddRefed<gfxWindowsFont>
GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
already_AddRefed<gfxWindowsFont>
gfxWindowsFont::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
{
// because we know the FontEntry has the weight we really want, use it for matching
// things in the cache so we don't end up with things like 402 in there.
@ -748,6 +759,22 @@ gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFo
{
GroupFamilyListToArrayList(&mFontEntries);
mFonts.AppendElements(mFontEntries.Length());
// Ensure that the first font is usable. Precompute its metrics since
// we'll surely need them anyway.
while (mFontEntries.Length() > 0) {
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(mFontEntries[0], &mStyle);
if (!font->IsValid()) {
mFontEntries.RemoveElementAt(0);
mFonts.RemoveElementAt(0);
continue;
}
mFonts[0] = font;
break;
}
if (mFontEntries.Length() == 0) {
// Should append default GUI font if there are no available fonts.
HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
@ -761,8 +788,6 @@ gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFo
mFontEntries.AppendElement(fe);
}
mFonts.AppendElements(mFontEntries.Length());
if (!mStyle.systemFont) {
for (PRUint32 i = 0; i < mFontEntries.Length(); ++i) {
if (mFontEntries[i]->IsBadUnderlineFont()) {
@ -783,7 +808,8 @@ gfxWindowsFont *
gfxWindowsFontGroup::GetFontAt(PRInt32 i)
{
if (!mFonts[i]) {
nsRefPtr<gfxWindowsFont> font = GetOrMakeFont(mFontEntries[i], &mStyle);
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(mFontEntries[i], &mStyle);
mFonts[i] = font;
}
@ -1503,18 +1529,17 @@ public:
struct TextRange {
TextRange(PRUint32 aStart, PRUint32 aEnd) : start(aStart), end(aEnd) { }
PRUint32 Length() const { return end - start; }
nsRefPtr<FontEntry> font;
nsRefPtr<gfxWindowsFont> font;
PRUint32 start, end;
};
void SetRange(PRUint32 i) {
nsRefPtr<FontEntry> fe;
nsRefPtr<gfxWindowsFont> font;
if (mRanges[i].font)
fe = mRanges[i].font;
font = mRanges[i].font;
else
fe = mGroup->GetFontEntryAt(0);
font = mGroup->GetFontAt(0);
nsRefPtr<gfxWindowsFont> font = GetOrMakeFont(fe, mGroup->GetStyle());
SetCurrentFont(font);
mRangeString = mItemString + mRanges[i].start;
@ -1529,7 +1554,8 @@ public:
if (ch > 0xFFFF)
return PR_FALSE;
nsRefPtr<gfxWindowsFont> font = GetOrMakeFont(aFontEntry, mGroup->GetStyle());
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(aFontEntry, mGroup->GetStyle());
HDC dc = GetDC((HWND)nsnull);
HFONT hfont = font->GetHFONT();
@ -1563,32 +1589,42 @@ public:
return PR_FALSE;
}
inline FontEntry *WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& fonts, PRUint32 ch) {
inline already_AddRefed<gfxWindowsFont>
WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& fonts, PRUint32 ch) {
for (PRUint32 i = 0; i < fonts.Length(); i++) {
nsRefPtr<FontEntry> fe = fonts[i];
if (fe->mSymbolFont && !mGroup->GetStyle()->familyNameQuirks)
continue;
if (HasCharacter(fe, ch))
return fe;
if (HasCharacter(fe, ch)) {
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(fe, mGroup->GetStyle());
// Check that the font is still usable.
if (!font->IsValid())
continue;
return font.forget();
}
}
return nsnull;
}
static inline bool IsJoiner(PRUint32 ch) {
return (ch == 0x200C ||
ch == 0x200D ||
ch == 0x2060);
}
inline FontEntry *FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRUint32 nextCh, FontEntry *aFont) {
nsRefPtr<FontEntry> selectedFont;
inline already_AddRefed<gfxWindowsFont>
FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRUint32 nextCh,
gfxWindowsFont *aFont) {
nsRefPtr<gfxWindowsFont> selectedFont;
// if this character or the next one is a joiner use the
// same font as the previous range if we can
if (IsJoiner(ch) || IsJoiner(prevCh) || IsJoiner(nextCh)) {
if (aFont && HasCharacter(aFont, ch))
if (aFont && HasCharacter(aFont->GetFontEntry(), ch)) {
NS_ADDREF(aFont);
return aFont;
}
}
// check the list of fonts
@ -1597,7 +1633,7 @@ public:
// don't look in other fonts if the character is in a Private Use Area
if ((ch >= 0xE000 && ch <= 0xF8FF) ||
(ch >= 0xF0000 && ch <= 0x10FFFD))
return selectedFont;
return selectedFont.forget();
// check out the style's language group
if (!selectedFont) {
@ -1645,7 +1681,7 @@ public:
}
// before searching for something else check the font used for the previous character
if (!selectedFont && aFont && HasCharacter(aFont, ch))
if (!selectedFont && aFont && HasCharacter(aFont->GetFontEntry(), ch))
selectedFont = aFont;
// otherwise look for other stuff
@ -1657,7 +1693,7 @@ public:
selectedFont = platform->FindFontForChar(ch, refFont);
}
return selectedFont;
return selectedFont.forget();
}
PRUint32 ComputeRanges() {
@ -1682,31 +1718,32 @@ public:
if ((i+2 < mItemLength) && NS_IS_HIGH_SURROGATE(nextCh) && NS_IS_LOW_SURROGATE(mItemString[i+2]))
nextCh = SURROGATE_TO_UCS4(nextCh, mItemString[i+2]);
}
nsRefPtr<FontEntry> fe = FindFontForChar(ch,
prevCh,
nextCh,
(mRanges.Length() == 0) ? nsnull : mRanges[mRanges.Length() - 1].font);
nsRefPtr<gfxWindowsFont> font =
FindFontForChar(ch,
prevCh,
nextCh,
(mRanges.Length() == 0) ? nsnull : mRanges[mRanges.Length() - 1].font);
prevCh = ch;
if (mRanges.Length() == 0) {
TextRange r(0,1);
r.font = fe;
r.font = font;
mRanges.AppendElement(r);
} else {
TextRange& prevRange = mRanges[mRanges.Length() - 1];
if (prevRange.font != fe) {
if (prevRange.font != font) {
// close out the previous range
prevRange.end = origI;
TextRange r(origI, i+1);
r.font = fe;
r.font = font;
mRanges.AppendElement(r);
}
}
if (PR_LOG_TEST(gFontLog, PR_LOG_DEBUG)) {
if (fe)
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Using %s", NS_LossyConvertUTF16toASCII(fe->GetName()).get()));
if (font)
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Using %s", NS_LossyConvertUTF16toASCII(font->GetUniqueName()).get()));
else
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Unable to find font"));
}

View File

@ -489,8 +489,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
return PL_DHASH_NEXT;
}
FontEntry *
already_AddRefed<gfxWindowsFont>
gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont)
{
// is codepoint with no matching font? return null immediately
@ -503,12 +502,17 @@ gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont)
// find fonts that support the character
mFonts.Enumerate(gfxWindowsPlatform::FindFontForCharProc, &data);
// no match? add to set of non-matching codepoints
if (!data.bestMatch) {
mCodepointsWithNoFonts.set(aCh);
if (data.bestMatch) {
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(data.bestMatch, aFont->GetStyle());
if (font->IsValid())
return font.forget();
return nsnull;
}
return data.bestMatch;
// no match? add to set of non-matching codepoints
mCodepointsWithNoFonts.set(aCh);
return nsnull;
}
gfxFontGroup *