Implement missing glyph handling, making the glyph retrieval the following:

1. If the glyph is cached, return it, as before.
2. Try to find a glyph in the fallback font, as before.
3. Check for ignorable characters as per Unicode and cache and return a zero
   width glyph (rendering as completely invisible).
4. Reset to the original font.
5. Check for whitespace as per Unicode and cache and return the normal space
   glyph.
6. If there still is no valid glyphIndex, continue with index 0 which caches
   and returns the usual "missing glyph box".

This implements the Unicode suggestions on how to handle missing glyphs and
closes #7077.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40174 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2011-01-09 04:10:13 +00:00
parent ea4b7aebf3
commit 5c89315772
+87 -2
View File
@@ -187,6 +187,74 @@ FontCacheEntry::HasGlyphs(const char* utf8String, ssize_t length) const
}
inline bool
render_as_space(uint32 glyphCode)
{
// whitespace: render as space
// as per Unicode PropList.txt: White_Space
return (glyphCode >= 0x0009 && glyphCode <= 0x000d)
// control characters
|| (glyphCode == 0x0085)
// another control
|| (glyphCode == 0x00a0)
// no-break space
|| (glyphCode == 0x1680)
// ogham space mark
|| (glyphCode == 0x180e)
// mongolian vowel separator
|| (glyphCode >= 0x2000 && glyphCode <= 0x200a)
// en quand, hair space
|| (glyphCode >= 0x2028 && glyphCode <= 0x2029)
// line and paragraph separators
|| (glyphCode == 0x202f)
// narrow no-break space
|| (glyphCode == 0x205f)
// medium math space
|| (glyphCode == 0x3000)
// ideographic space
;
}
inline bool
render_as_zero_width(uint32 glyphCode)
{
// ignorable chars: render as invisible
// as per Unicode DerivedCoreProperties.txt: Default_Ignorable_Code_Point
return (glyphCode == 0x00ad)
// soft hyphen
|| (glyphCode == 0x034f)
// combining grapheme joiner
|| (glyphCode >= 0x115f && glyphCode <= 0x1160)
// hangul fillers
|| (glyphCode >= 0x17b4 && glyphCode <= 0x17b5)
// ignorable khmer vowels
|| (glyphCode >= 0x180b && glyphCode <= 0x180d)
// variation selectors
|| (glyphCode >= 0x200b && glyphCode <= 0x200f)
// zero width space, cursive joiners, ltr marks
|| (glyphCode >= 0x202a && glyphCode <= 0x202e)
// left to right embed, override
|| (glyphCode >= 0x2060 && glyphCode <= 0x206f)
// word joiner, invisible math operators, reserved
|| (glyphCode == 0x3164)
// hangul filler
|| (glyphCode >= 0xfe00 && glyphCode <= 0xfe0f)
// variation selectors
|| (glyphCode == 0xfeff)
// zero width no-break space
|| (glyphCode == 0xffa0)
// halfwidth hangul filler
|| (glyphCode >= 0xfff0 && glyphCode <= 0xfff8)
// reserved
|| (glyphCode >= 0x1d173 && glyphCode <= 0x1d17a)
// musical symbols
|| (glyphCode >= 0xe0000 && glyphCode <= 0xe01ef)
// variation selectors, tag space, reserved
;
}
const GlyphCache*
FontCacheEntry::Glyph(uint32 glyphCode, FontCacheEntry* fallbackEntry)
{
@@ -212,7 +280,24 @@ FontCacheEntry::Glyph(uint32 glyphCode, FontCacheEntry* fallbackEntry)
glyphIndex = engine->GlyphIndexForGlyphCode(glyphCode);
}
if (glyphIndex != 0 && engine->PrepareGlyph(glyphIndex)) {
if (glyphIndex == 0) {
if (render_as_zero_width(glyphCode)) {
// cache and return a zero width glyph
return fGlyphCache->CacheGlyph(glyphCode, 0, glyph_data_invalid,
agg::rect_i(0, 0, -1, -1), 0, 0, 0, 0);
}
// reset to our engine
engine = &fEngine;
if (render_as_space(glyphCode)) {
// get the normal space glyph
glyphIndex = engine->GlyphIndexForGlyphCode(0x20 /* space */);
} else {
// render the "missing glyph box" (by simply keeping glyphIndex 0)
}
}
if (engine->PrepareGlyph(glyphIndex)) {
glyph = fGlyphCache->CacheGlyph(glyphCode,
engine->DataSize(), engine->DataType(), engine->Bounds(),
engine->AdvanceX(), engine->AdvanceY(),
@@ -220,8 +305,8 @@ FontCacheEntry::Glyph(uint32 glyphCode, FontCacheEntry* fallbackEntry)
if (glyph != NULL)
engine->WriteGlyphTo(glyph->data);
}
return glyph;
}