diff --git a/gfx/thebes/public/gfxWindowsFonts.h b/gfx/thebes/public/gfxWindowsFonts.h index 4bb240d8655..ba604a83388 100644 --- a/gfx/thebes/public/gfxWindowsFonts.h +++ b/gfx/thebes/public/gfxWindowsFonts.h @@ -265,8 +265,12 @@ public: return mSpaceGlyph; }; + PRBool IsValid() { GetMetrics(); return mIsValid; } FontEntry *GetFontEntry() { return mFontEntry; } + static already_AddRefed + GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle); + protected: HFONT MakeHFONT(); void FillLogFont(gfxFloat aSize); @@ -288,6 +292,7 @@ private: LOGFONTW mLogFont; nsRefPtr mFontEntry; + PRPackedBool mIsValid; virtual PRBool SetupCairoFont(gfxContext *aContext); }; diff --git a/gfx/thebes/public/gfxWindowsPlatform.h b/gfx/thebes/public/gfxWindowsPlatform.h index a9172899c4a..5048dbd3eeb 100644 --- a/gfx/thebes/public/gfxWindowsPlatform.h +++ b/gfx/thebes/public/gfxWindowsPlatform.h @@ -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 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); diff --git a/gfx/thebes/src/gfxWindowsFonts.cpp b/gfx/thebes/src/gfxWindowsFonts.cpp index 20d9d51346d..29daa9e87c1 100644 --- a/gfx/thebes/src/gfxWindowsFonts.cpp +++ b/gfx/thebes/src/gfxWindowsFonts.cpp @@ -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 -GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle) +already_AddRefed +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 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 font = GetOrMakeFont(mFontEntries[i], &mStyle); + nsRefPtr 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 font; + nsRefPtr font; PRUint32 start, end; }; void SetRange(PRUint32 i) { - nsRefPtr fe; + nsRefPtr font; if (mRanges[i].font) - fe = mRanges[i].font; + font = mRanges[i].font; else - fe = mGroup->GetFontEntryAt(0); + font = mGroup->GetFontAt(0); - nsRefPtr font = GetOrMakeFont(fe, mGroup->GetStyle()); SetCurrentFont(font); mRangeString = mItemString + mRanges[i].start; @@ -1529,7 +1554,8 @@ public: if (ch > 0xFFFF) return PR_FALSE; - nsRefPtr font = GetOrMakeFont(aFontEntry, mGroup->GetStyle()); + nsRefPtr 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 >& fonts, PRUint32 ch) { + inline already_AddRefed + WhichFontSupportsChar(const nsTArray >& fonts, PRUint32 ch) { for (PRUint32 i = 0; i < fonts.Length(); i++) { nsRefPtr fe = fonts[i]; if (fe->mSymbolFont && !mGroup->GetStyle()->familyNameQuirks) continue; - if (HasCharacter(fe, ch)) - return fe; + if (HasCharacter(fe, ch)) { + nsRefPtr 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 selectedFont; + inline already_AddRefed + FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRUint32 nextCh, + gfxWindowsFont *aFont) { + nsRefPtr 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 fe = FindFontForChar(ch, - prevCh, - nextCh, - (mRanges.Length() == 0) ? nsnull : mRanges[mRanges.Length() - 1].font); + nsRefPtr 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")); } diff --git a/gfx/thebes/src/gfxWindowsPlatform.cpp b/gfx/thebes/src/gfxWindowsPlatform.cpp index b865784d681..706bfe9e7e4 100644 --- a/gfx/thebes/src/gfxWindowsPlatform.cpp +++ b/gfx/thebes/src/gfxWindowsPlatform.cpp @@ -489,8 +489,7 @@ gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey, return PL_DHASH_NEXT; } - -FontEntry * +already_AddRefed 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 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 *