Author: mmlr Date: 2011-01-09 05:10:13 +0100 (Sun, 09 Jan 2011) New Revision: 40174 Changeset: http://dev.haiku-os.org/changeset/40174 Ticket: http://dev.haiku-os.org/ticket/7077 Modified: haiku/trunk/src/servers/app/FontCacheEntry.cpp Log: 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. Modified: haiku/trunk/src/servers/app/FontCacheEntry.cpp =================================================================== --- haiku/trunk/src/servers/app/FontCacheEntry.cpp 2011-01-08 23:37:54 UTC (rev 40173) +++ haiku/trunk/src/servers/app/FontCacheEntry.cpp 2011-01-09 04:10:13 UTC (rev 40174) @@ -187,6 +187,74 @@ } +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 @@ 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 @@ if (glyph != NULL) engine->WriteGlyphTo(glyph->data); + } - } return glyph; }