зеркало из https://github.com/mozilla/pjs.git
Bug 427411. Handle bogus fonts being returned by Windows due to the font catalog being stale or out of GDI objects. r=pavlov,a=damon
This commit is contained in:
Родитель
99776ebdd3
Коммит
0503319868
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -759,10 +786,16 @@ gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFo
|
|||
}
|
||||
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(nsDependentString(logFont.lfFaceName), *aStyle);
|
||||
mFontEntries.AppendElement(fe);
|
||||
// Keep length of mFonts in sync with length of mFontEntries.
|
||||
// Maybe we should eagerly set up mFonts[0] like we do above,
|
||||
// but if the resulting gfxWindowsFont is invalid then we can't
|
||||
// do much anyway. In that case the font will return zero metrics,
|
||||
// its mUnknownCMAP will be set to true, and HasCharacter will
|
||||
// just report false for all characters, so the fact that the font
|
||||
// is bogus should not cause problems.
|
||||
mFonts.AppendElements(1);
|
||||
}
|
||||
|
||||
mFonts.AppendElements(mFontEntries.Length());
|
||||
|
||||
if (!mStyle.systemFont) {
|
||||
for (PRUint32 i = 0; i < mFontEntries.Length(); ++i) {
|
||||
if (mFontEntries[i]->IsBadUnderlineFont()) {
|
||||
|
@ -783,7 +816,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 +1537,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 +1562,10 @@ public:
|
|||
if (ch > 0xFFFF)
|
||||
return PR_FALSE;
|
||||
|
||||
nsRefPtr<gfxWindowsFont> font = GetOrMakeFont(aFontEntry, mGroup->GetStyle());
|
||||
nsRefPtr<gfxWindowsFont> font =
|
||||
gfxWindowsFont::GetOrMakeFont(aFontEntry, mGroup->GetStyle());
|
||||
if (!font->IsValid())
|
||||
return PR_FALSE;
|
||||
|
||||
HDC dc = GetDC((HWND)nsnull);
|
||||
HFONT hfont = font->GetHFONT();
|
||||
|
@ -1563,32 +1599,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 +1643,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 +1691,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 +1703,7 @@ public:
|
|||
selectedFont = platform->FindFontForChar(ch, refFont);
|
||||
}
|
||||
|
||||
return selectedFont;
|
||||
return selectedFont.forget();
|
||||
}
|
||||
|
||||
PRUint32 ComputeRanges() {
|
||||
|
@ -1682,31 +1728,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"));
|
||||
}
|
||||
|
|
|
@ -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 *
|
||||
|
|
Загрузка…
Ссылка в новой задаче