[HarfBuzz] improving hb_ot_hide_default_ignorables
Jonathan Kew
jfkthame at googlemail.com
Fri Sep 27 08:22:14 PDT 2013
Hi Behdad,
With the change in variation selector handling, stray (unsupported) VS
codes are no longer consumed by the get_glyph callback; they remain in
the buffer and are individually mapped to glyphs. That's all very well;
but in most cases they'll just map to .notdef.
Eventually, hb_ot_hide_default_ignorables() will run across these
.notdef glyphs and replace them with zero-width space glyphs. All's good...
...except in the (unlikely) case where the font does not actually
support the <space> character. This will be almost vanishingly rare, of
course - but unfortunately it happens with the "MarkA" font that's used
for a variety of rendering tests.
This prompted me to look into patching hb_ot_hide_default_ignorables()
so that it will work even if there's no <space> in the font. ISTM we can
fix this by simply deleting the ignorable altogether in this case. It'll
be a bit less performant than the current replace-with-zero-width-space
implementation, because it requires shifting all the following glyphs up
in the buffer, so I've retained the existing implementation for the
(usual) case where <space> is available.
Suggested patch is attached.
JK
-------------- next part --------------
From: Jonathan Kew <jkew at mozilla.com>
diff --git a/gfx/harfbuzz/src/hb-ot-shape.cc b/gfx/harfbuzz/src/hb-ot-shape.cc
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -531,28 +531,40 @@ static void
hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
return;
hb_codepoint_t space = 0;
unsigned int count = c->buffer->len;
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
for (unsigned int i = 0; i < count; i++)
- if (unlikely (!is_a_ligature (c->buffer->info[i]) &&
- _hb_glyph_info_is_default_ignorable (&c->buffer->info[i])))
+ if (unlikely (!is_a_ligature (info[i]) &&
+ _hb_glyph_info_is_default_ignorable (&info[i])))
{
if (!space) {
/* We assume that the space glyph is not gid0. */
- if (unlikely (!c->font->get_glyph (' ', 0, &space)) || !space)
- return; /* No point! */
+ if (unlikely (!c->font->get_glyph (' ', 0, &space)) || !space) {
+ /*
+ * Failed to find a space glyph(!), so delete the ignorable entirely
+ * by shortening the buffer and shifting everything up.
+ */
+ c->buffer->len = --count;
+ for (unsigned int j = i; j < count; j++) {
+ info[j] = info[j + 1];
+ pos[j] = pos[j + 1];
+ }
+ continue;
+ }
}
- c->buffer->info[i].codepoint = space;
- c->buffer->pos[i].x_advance = 0;
- c->buffer->pos[i].y_advance = 0;
+ info[i].codepoint = space;
+ pos[i].x_advance = 0;
+ pos[i].y_advance = 0;
}
}
/* Pull it all together! */
static void
hb_ot_shape_internal (hb_ot_shape_context_t *c)
More information about the HarfBuzz
mailing list