From 5c893157721fee4cf2786feee501839d4822a532 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 9 Jan 2011 04:10:13 +0000 Subject: [PATCH] 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 --- src/servers/app/FontCacheEntry.cpp | 89 +++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/src/servers/app/FontCacheEntry.cpp b/src/servers/app/FontCacheEntry.cpp index b06d550876..a22a90a01e 100644 --- a/src/servers/app/FontCacheEntry.cpp +++ b/src/servers/app/FontCacheEntry.cpp @@ -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; }