LayoutGlyphs() was broken in various ways when encountering missing glyphs:

* The code used continue to restart the loop when encountering a missing glyph,
  but in that case the index wouldn't be incremented, meaning the consumers
  would received the same index for ConsumeEmptyGlphy() and ConsumeGlyph() and
  at the end there was not necessarily a call for every index, resulting in
  uninitialized array elements for GetHasGlyphs, GetEdges, GetEscapements and
  GetBoundingBoxes.
* Since the advance values were not reset in case of a missing glyph but still
  added for the next char, the coordinates the consumers would get were advanced
  by the advance values of the glyph preceeding the missing glyph(s). This made
  StringWidth return wrong widths.
* The loop end condition was skipped by the continue as well, which would have
  resulted in overruns when there were problematic chars at the end of a string.

Fixes #7075 where the uninitialized array elements caused random truncation
errors. The problematic character in this case is a tab, that has no glyph as
it is a dynamic spacer. Previously this was resolved to the "missing glyph"
(the box) which had a width.

I find it highly problematic not to fall back to such a glyph, because there is
no real way to see that you're using a font that has missing glyphs. Instead
those are simply collapsed to nothing with this change (instead of being
random). This whole problem is only brought up by not guaranteeing that there
always is a glyph as was the case before where a missing glyph was replaced by
the box.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40172 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2011-01-08 23:17:18 +00:00
parent 89f0e174b0
commit 2004d8c100

View File

@ -55,7 +55,7 @@ public:
fCacheEntry->WriteUnlock();
else
fCacheEntry->ReadUnlock();
FontCache::Default()->Recycle(fCacheEntry);
}
@ -275,22 +275,22 @@ GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
const GlyphCache* glyph = entry->Glyph(charCode, fallbackEntry);
if (glyph == NULL) {
consumer.ConsumeEmptyGlyph(index, charCode, x, y);
continue;
consumer.ConsumeEmptyGlyph(index++, charCode, x, y);
advanceX = 0;
advanceY = 0;
} else {
if (!consumer.ConsumeGlyph(index, charCode, glyph, entry, x, y)) {
if (!consumer.ConsumeGlyph(index++, charCode, glyph, entry, x, y)) {
advanceX = 0;
advanceY = 0;
break;
}
// get next increment for pen position
advanceX = glyph->advance_x;
advanceY = glyph->advance_y;
}
// get next increment for pen position
advanceX = glyph->advance_x;
advanceY = glyph->advance_y;
lastCharCode = charCode;
index++;
if (utf8String - start + 1 > length)
break;
}