[ot] Hide default-ignorables before finishing off positioning

For example, fixes the following sequence with Arial XP:
628 25cc 651 25cc 64e 3a 20 628 651 34f 64e
628 25cc 64e 25cc 651 3a 20 628 64e 34f 651

Discovered as part of:
https://bugs.freedesktop.org/show_bug.cgi?id=85873
This commit is contained in:
Behdad Esfahbod 2015-07-22 17:36:23 +01:00
parent 376d587f36
commit f0010dfd01
1 changed files with 63 additions and 62 deletions

View File

@ -411,6 +411,65 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
}
}
static void
hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
return;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
unsigned int i = 0;
for (i = 0; i < count; i++)
{
if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_is_default_ignorable (&info[i])))
break;
}
/* No default-ignorables found; return. */
if (i == count)
return;
hb_codepoint_t space;
if (c->font->get_glyph (' ', 0, &space))
{
/* Replace default-ignorables with a zero-advance space glyph. */
for (/*continue*/; i < count; i++)
{
if (!_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_is_default_ignorable (&info[i]))
{
info[i].codepoint = space;
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
}
}
else
{
/* Merge clusters and delete default-ignorables. */
buffer->clear_output ();
buffer->idx = 0;
buffer->next_glyphs (i);
while (buffer->idx < buffer->len)
{
if (!_hb_glyph_info_ligated (&info[buffer->idx]) &&
_hb_glyph_info_is_default_ignorable (&info[buffer->idx]))
{
buffer->delete_glyph ();
continue;
}
buffer->next_glyph ();
}
buffer->swap_buffers ();
}
}
static inline void
hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
{
@ -656,6 +715,10 @@ hb_ot_position (hb_ot_shape_context_t *c)
hb_bool_t fallback = !hb_ot_position_complex (c);
/* Need to do this here, since position_finish and fallback positioning
* might be affected by width of default_ignorables. */
hb_ot_hide_default_ignorables (c);
hb_ot_layout_position_finish (c->font, c->buffer);
if (fallback && c->plan->shaper->fallback_position)
@ -673,66 +736,6 @@ hb_ot_position (hb_ot_shape_context_t *c)
}
/* Post-process */
static void
hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
return;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
unsigned int i = 0;
for (i = 0; i < count; i++)
{
if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_is_default_ignorable (&info[i])))
break;
}
/* No default-ignorables found; return. */
if (i == count)
return;
hb_codepoint_t space;
if (c->font->get_glyph (' ', 0, &space))
{
/* Replace default-ignorables with a zero-advance space glyph. */
for (/*continue*/; i < count; i++)
{
if (!_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_is_default_ignorable (&info[i]))
{
info[i].codepoint = space;
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
}
}
else
{
/* Merge clusters and delete default-ignorables. */
buffer->clear_output ();
buffer->idx = 0;
buffer->next_glyphs (i);
while (buffer->idx < buffer->len)
{
if (!_hb_glyph_info_ligated (&info[buffer->idx]) &&
_hb_glyph_info_is_default_ignorable (&info[buffer->idx]))
{
buffer->delete_glyph ();
continue;
}
buffer->next_glyph ();
}
buffer->swap_buffers ();
}
}
/* Pull it all together! */
static void
@ -756,8 +759,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
hb_ot_substitute (c);
hb_ot_position (c);
hb_ot_hide_default_ignorables (c);
_hb_buffer_deallocate_unicode_vars (c->buffer);
c->buffer->props.direction = c->target_direction;