[OS/2] Bug 381333: first cut at replacing glyphs missing from the primary font from secondary (unicode and user-defined) fonts

git-svn-id: svn://10.0.0.236/trunk@239595 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mozilla%weilbacher.org
2007-11-17 22:22:04 +00:00
parent e00c1b7768
commit 52eeabeb75

View File

@@ -394,14 +394,55 @@ gfxOS2FontGroup::gfxOS2FontGroup(const nsAString& aFamilies,
mFontCache.Init(15);
ForEachFont(FontCallback, &familyArray);
FindGenericFontFromStyle(FontCallback, &familyArray);
// To be able to easily search for glyphs in other fonts, append a few good
// replacement candidates to the list. The best ones are the Unicode fonts that
// are set up, and if the user was so clever to set up the User Defined fonts,
// then these are probable candidates, too.
nsString fontString;
gfxPlatform::GetPlatform()->GetPrefFonts("x-unicode", fontString, PR_FALSE);
ForEachFont(fontString, NS_LITERAL_CSTRING("x-unicode"), FontCallback, &familyArray);
gfxPlatform::GetPlatform()->GetPrefFonts("x-user-def", fontString, PR_FALSE);
ForEachFont(fontString, NS_LITERAL_CSTRING("x-user-def"), FontCallback, &familyArray);
if (familyArray.Count() == 0) {
// Should append default GUI font if there are no available fonts.
// We use WarpSans as in the default case in nsSystemFontsOS2.
familyArray.AppendString(NS_LITERAL_STRING("WarpSans"));
}
for (int i = 0; i < familyArray.Count(); i++) {
mFonts.AppendElement(new gfxOS2Font(*familyArray[i], &mStyle));
}
#ifdef REALLY_DESPERATE_FONT_MATCHING
// just continue to append all fonts known to the system
nsStringArray fontList;
nsCAutoString generic;
if (!gfxPlatform::GetPlatform()->GetFontList(mStyle.langGroup, generic, fontList)) {
// we don't want MARKSYM in the list (which always matches every glyph)
// nor MT Extra or the Math1* fonts which seem to have the same problem
fontList.RemoveString(NS_LITERAL_STRING("MARKSYM"));
fontList.RemoveString(NS_LITERAL_STRING("MT Extra"));
fontList.RemoveString(NS_LITERAL_STRING("Math1"));
fontList.RemoveString(NS_LITERAL_STRING("Math2"));
fontList.RemoveString(NS_LITERAL_STRING("Math3"));
fontList.RemoveString(NS_LITERAL_STRING("Math4"));
fontList.RemoveString(NS_LITERAL_STRING("Math5"));
fontList.RemoveString(NS_LITERAL_STRING("Math1Mono"));
fontList.RemoveString(NS_LITERAL_STRING("Math2Mono"));
fontList.RemoveString(NS_LITERAL_STRING("Math3Mono"));
fontList.RemoveString(NS_LITERAL_STRING("Math4Mono"));
fontList.RemoveString(NS_LITERAL_STRING("Math5Mono"));
// start at 3 to ignore the generic entries
for (int i = 3; i < fontList.Count(); i++) {
// check for duplicates that we already found through the familyArray
if (familyArray.IndexOf(*fontList[i]) == -1) {
mFonts.AppendElement(new gfxOS2Font(*fontList[i], &mStyle));
}
}
}
#endif
}
gfxOS2FontGroup::~gfxOS2FontGroup()
@@ -536,73 +577,113 @@ void gfxOS2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun, const PRUint8 *aUT
font->GetStyle()->size);
}
#endif
PRUint32 fontlistLast = FontListLength()-1;
gfxOS2Font *font0 = GetFontAt(0);
const PRUint8 *p = aUTF8;
gfxOS2Font *font = GetFontAt(0);
PRUint32 utf16Offset = 0;
gfxTextRun::CompressedGlyph g;
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
aTextRun->AddGlyphRun(font, 0);
// a textRun should have the same font, so we can lock it before the loop
FT_Face face = cairo_ft_scaled_font_lock_face(font->CairoScaledFont());
aTextRun->AddGlyphRun(font0, 0);
// a textRun likely has the same font for most of the characters, so we can
// lock it before the loop for efficiency
FT_Face face0 = cairo_ft_scaled_font_lock_face(font0->CairoScaledFont());
while (p < aUTF8 + aUTF8Length) {
PRBool glyphFound = PR_FALSE;
// convert UTF-8 character and step to the next one in line
PRUint8 chLen;
PRUint32 ch = getUTF8CharAndNext(p, &chLen);
p += chLen; // move to next char
#ifdef DEBUG_thebes_2
printf("\'%c\' (%d, %#x, %s):", (char)ch, ch, ch, ch >=0x10000 ? "non-BMP!" : "BMP");
printf("\'%c\' (%d, %#x, %s) [%#x %#x]:", (char)ch, ch, ch, ch >=0x10000 ? "non-BMP!" : "BMP", ch >=0x10000 ? H_SURROGATE(ch) : 0, ch >=0x10000 ? L_SURROGATE(ch) : 0);
#endif
if (ch == 0) {
// treat this null byte as a missing glyph, don't create a glyph for it
aTextRun->SetMissingGlyph(utf16Offset, 0);
} else {
NS_ASSERTION(!IsInvalidChar(ch), "Invalid char detected");
FT_UInt gid = FT_Get_Char_Index(face, ch); // find the glyph id
PRInt32 advance = 0;
if (gid == font->GetSpaceGlyph()) {
advance = (int)(font->GetMetrics().spaceWidth * appUnitsPerDevUnit);
} else if (gid == 0) {
advance = -1; // trigger the missing glyphs case below
} else {
FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT); // load glyph into the slot
advance = (face->glyph->advance.x >> 6) * appUnitsPerDevUnit;
}
// Try to get a glyph from all fonts available to us.
// Once we found it in one of the fonts we quit the loop early.
// If we don't find the glyph, we set the missing glyph symbol after
// trying the last font.
for (PRUint32 i = 0; i <= fontlistLast; i++) {
gfxOS2Font *font = font0;
FT_Face face = face0;
if (i > 0) {
font = GetFontAt(i);
face = cairo_ft_scaled_font_lock_face(font->CairoScaledFont());
#ifdef DEBUG_thebes_2
printf(" gid=%d, advance=%d (%s)\n", gid, advance,
NS_LossyConvertUTF16toASCII(font->GetName()).get());
if (i == fontlistLast) {
printf("Last font %d (%s) for ch=%#x (pos=%d)",
i, NS_LossyConvertUTF16toASCII(font->GetName()).get(), ch, utf16Offset);
}
#endif
}
// select the current font into the text run
aTextRun->AddGlyphRun(font, utf16Offset);
NS_ASSERTION(!IsInvalidChar(ch), "Invalid char detected");
FT_UInt gid = FT_Get_Char_Index(face, ch); // find the glyph id
PRInt32 advance = 0;
if (gid == font->GetSpaceGlyph()) {
advance = (int)(font->GetMetrics().spaceWidth * appUnitsPerDevUnit);
} else if (gid == 0) {
advance = -1; // trigger the missing glyphs case below
} else {
FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT); // load glyph into the slot
advance = (face->glyph->advance.x >> 6) * appUnitsPerDevUnit;
}
#ifdef DEBUG_thebes_2
printf(" gid=%d, advance=%d (%s)\n", gid, advance,
NS_LossyConvertUTF16toASCII(font->GetName()).get());
#endif
if (advance >= 0 &&
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(gid))
{
aTextRun->SetSimpleGlyph(utf16Offset,
g.SetSimpleGlyph(advance, gid));
} else if (gid == 0) {
// gid = 0 only happens when the glyph is missing from the font
aTextRun->SetMissingGlyph(utf16Offset, ch);
} else {
gfxTextRun::DetailedGlyph details;
details.mGlyphID = gid;
NS_ASSERTION(details.mGlyphID == gid, "Seriously weird glyph ID detected!");
details.mAdvance = advance;
details.mXOffset = 0;
details.mYOffset = 0;
g.SetComplex(aTextRun->IsClusterStart(utf16Offset), PR_TRUE, 1);
aTextRun->SetGlyphs(utf16Offset, g, &details);
}
if (advance >= 0 &&
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(gid))
{
aTextRun->SetSimpleGlyph(utf16Offset,
g.SetSimpleGlyph(advance, gid));
glyphFound = PR_TRUE;
} else if (gid == 0) {
// gid = 0 only happens when the glyph is missing from the font
if (i == fontlistLast) {
// set the missing glyph only when it's missing from the very
// last font
aTextRun->SetMissingGlyph(utf16Offset, ch);
}
glyphFound = PR_FALSE;
} else {
gfxTextRun::DetailedGlyph details;
details.mGlyphID = gid;
NS_ASSERTION(details.mGlyphID == gid, "Seriously weird glyph ID detected!");
details.mAdvance = advance;
details.mXOffset = 0;
details.mYOffset = 0;
g.SetComplex(aTextRun->IsClusterStart(utf16Offset), PR_TRUE, 1);
aTextRun->SetGlyphs(utf16Offset, g, &details);
glyphFound = PR_TRUE;
}
NS_ASSERTION(!IS_SURROGATE(ch), "Surrogates shouldn't appear in UTF8");
if (ch >= 0x10000) {
// This character is a surrogate pair in UTF16
++utf16Offset;
if (i > 0) {
cairo_ft_scaled_font_unlock_face(font->CairoScaledFont());
}
if (glyphFound) {
break;
}
}
} // for all fonts
NS_ASSERTION(!IS_SURROGATE(ch), "Surrogates shouldn't appear in UTF8");
if (ch >= 0x10000) {
// This character is a surrogate pair in UTF16
++utf16Offset;
}
++utf16Offset;
}
cairo_ft_scaled_font_unlock_face(font->CairoScaledFont());
cairo_ft_scaled_font_unlock_face(font0->CairoScaledFont());
}
PRBool gfxOS2FontGroup::FontCallback(const nsAString& aFontName,