[OT] Avoid calling get_glyph() twice

Essentially move the glyph mapping to normalization process.
The effect on Devanagari is small (but observable).  Should be more
observable in simple text, like ASCII.
This commit is contained in:
Behdad Esfahbod 2012-08-09 22:33:32 -04:00
parent 12c0875eaf
commit b00321ea78
3 changed files with 77 additions and 45 deletions

View File

@ -32,6 +32,8 @@
#include "hb-font.h" #include "hb-font.h"
#include "hb-buffer.h" #include "hb-buffer.h"
/* buffer var allocations, used during the normalization process */
#define glyph_index() var1.u32
enum hb_ot_shape_normalization_mode_t { enum hb_ot_shape_normalization_mode_t {
HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED, HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,

View File

@ -258,16 +258,25 @@ compose_func (hb_unicode_funcs_t *unicode,
return found; return found;
} }
static inline void static inline void
output_char (hb_buffer_t *buffer, hb_codepoint_t unichar) set_glyph (hb_glyph_info_t &info, hb_font_t *font)
{ {
hb_font_get_glyph (font, info.codepoint, 0, &info.glyph_index());
}
static inline void
output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
{
buffer->cur().glyph_index() = glyph;
buffer->output_glyph (unichar); buffer->output_glyph (unichar);
_hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode); _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
} }
static inline void static inline void
next_char (hb_buffer_t *buffer) next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
{ {
buffer->cur().glyph_index() = glyph;
buffer->next_glyph (); buffer->next_glyph ();
} }
@ -282,31 +291,31 @@ decompose (hb_font_t *font, hb_buffer_t *buffer,
bool shortest, bool shortest,
hb_codepoint_t ab) hb_codepoint_t ab)
{ {
hb_codepoint_t a, b, glyph; hb_codepoint_t a, b, a_glyph, b_glyph;
if (!decompose_func (buffer->unicode, ab, &a, &b) || if (!decompose_func (buffer->unicode, ab, &a, &b) ||
(b && !font->get_glyph (b, 0, &glyph))) (b && !font->get_glyph (b, 0, &b_glyph)))
return false; return false;
bool has_a = font->get_glyph (a, 0, &glyph); bool has_a = font->get_glyph (a, 0, &a_glyph);
if (shortest && has_a) { if (shortest && has_a) {
/* Output a and b */ /* Output a and b */
output_char (buffer, a); output_char (buffer, a, a_glyph);
if (b) if (b)
output_char (buffer, b); output_char (buffer, b, b_glyph);
return true; return true;
} }
if (decompose (font, buffer, shortest, a)) { if (decompose (font, buffer, shortest, a)) {
if (b) if (b)
output_char (buffer, b); output_char (buffer, b, b_glyph);
return true; return true;
} }
if (has_a) { if (has_a) {
output_char (buffer, a); output_char (buffer, a, a_glyph);
if (b) if (b)
output_char (buffer, b); output_char (buffer, b, b_glyph);
return true; return true;
} }
@ -319,18 +328,18 @@ decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer,
{ {
unsigned int len, i; unsigned int len, i;
hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN]; hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN];
len = buffer->unicode->decompose_compatibility (u, decomposed); len = buffer->unicode->decompose_compatibility (u, decomposed);
if (!len) if (!len)
return false; return false;
hb_codepoint_t glyph;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
if (!font->get_glyph (decomposed[i], 0, &glyph)) if (!font->get_glyph (decomposed[i], 0, &glyphs[i]))
return false; return false;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
output_char (buffer, decomposed[i]); output_char (buffer, decomposed[i], glyphs[i]);
return true; return true;
} }
@ -343,15 +352,38 @@ decompose_current_character (hb_font_t *font, hb_buffer_t *buffer,
/* Kind of a cute waterfall here... */ /* Kind of a cute waterfall here... */
if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
next_char (buffer); next_char (buffer, glyph);
else if (decompose (font, buffer, shortest, buffer->cur().codepoint)) else if (decompose (font, buffer, shortest, buffer->cur().codepoint))
skip_char (buffer); skip_char (buffer);
else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
next_char (buffer); next_char (buffer, glyph);
else if (decompose_compatibility (font, buffer, buffer->cur().codepoint)) else if (decompose_compatibility (font, buffer, buffer->cur().codepoint))
skip_char (buffer); skip_char (buffer);
else else {
next_char (buffer); /* A glyph-not-found case... */
font->get_glyph (buffer->cur().codepoint, 0, &glyph);
next_char (buffer, glyph);
}
}
static inline void
handle_variation_selector_cluster (hb_font_t *font, hb_buffer_t *buffer,
unsigned int end)
{
for (; buffer->idx < end - 1;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
/* The next two lines are some ugly lines... But work. */
font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index());
buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
} else {
set_glyph (buffer->cur(), font);
buffer->next_glyph ();
}
}
if (likely (buffer->idx < end)) {
set_glyph (buffer->cur(), font);
buffer->next_glyph ();
}
} }
static void static void
@ -361,8 +393,7 @@ decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
for (unsigned int i = buffer->idx; i < end; i++) for (unsigned int i = buffer->idx; i < end; i++)
if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) { if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
while (buffer->idx < end) handle_variation_selector_cluster (font, buffer, end);
next_char (buffer);
return; return;
} }
@ -457,7 +488,7 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
buffer->clear_output (); buffer->clear_output ();
count = buffer->len; count = buffer->len;
unsigned int starter = 0; unsigned int starter = 0;
next_char (buffer); buffer->next_glyph ();
while (buffer->idx < count) while (buffer->idx < count)
{ {
hb_codepoint_t composed, glyph; hb_codepoint_t composed, glyph;
@ -478,19 +509,20 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
font->get_glyph (composed, 0, &glyph)) font->get_glyph (composed, 0, &glyph))
{ {
/* Composes. */ /* Composes. */
next_char (buffer); /* Copy to out-buffer. */ buffer->next_glyph (); /* Copy to out-buffer. */
if (unlikely (buffer->in_error)) if (unlikely (buffer->in_error))
return; return;
buffer->merge_out_clusters (starter, buffer->out_len); buffer->merge_out_clusters (starter, buffer->out_len);
buffer->out_len--; /* Remove the second composable. */ buffer->out_len--; /* Remove the second composable. */
buffer->out_info[starter].codepoint = composed; /* Modify starter and carry on. */ buffer->out_info[starter].codepoint = composed; /* Modify starter and carry on. */
set_glyph (buffer->out_info[starter], font);
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode); _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
continue; continue;
} }
/* Blocked, or doesn't compose. */ /* Blocked, or doesn't compose. */
next_char (buffer); buffer->next_glyph ();
if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0) if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0)
starter = buffer->out_len - 1; starter = buffer->out_len - 1;

View File

@ -308,28 +308,12 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
} }
static inline void static inline void
hb_ot_map_glyphs (hb_font_t *font, hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
hb_buffer_t *buffer)
{ {
hb_codepoint_t glyph; /* Normalization process sets up glyph_index(), we just copy it. */
unsigned int count = buffer->len;
buffer->clear_output (); for (unsigned int i = 0; i < count; i++)
buffer->info[i].codepoint = buffer->info[i].glyph_index();
unsigned int count = buffer->len - 1;
for (buffer->idx = 0; buffer->idx < count;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &glyph);
buffer->replace_glyphs (2, 1, &glyph);
} else {
font->get_glyph (buffer->cur().codepoint, 0, &glyph);
buffer->replace_glyph (glyph);
}
}
if (likely (buffer->idx < buffer->len)) {
font->get_glyph (buffer->cur().codepoint, 0, &glyph);
buffer->replace_glyph (glyph);
}
buffer->swap_buffers ();
} }
static inline void static inline void
@ -337,6 +321,8 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
{ {
hb_ot_mirror_chars (c); hb_ot_mirror_chars (c);
HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index);
_hb_ot_shape_normalize (c->font, c->buffer, _hb_ot_shape_normalize (c->font, c->buffer,
c->plan->shaper->normalization_preference ? c->plan->shaper->normalization_preference ?
c->plan->shaper->normalization_preference (c->plan) : c->plan->shaper->normalization_preference (c->plan) :
@ -344,7 +330,9 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
hb_ot_shape_setup_masks (c); hb_ot_shape_setup_masks (c);
hb_ot_map_glyphs (c->font, c->buffer); hb_ot_map_glyphs_fast (c->buffer);
HB_BUFFER_DEALLOCATE_VAR (c->buffer, glyph_index);
} }
static inline void static inline void
@ -558,6 +546,16 @@ _hb_ot_shape (hb_shape_plan_t *shape_plan,
} }
static inline void
hb_ot_map_glyphs_dumb (hb_font_t *font,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
font->get_glyph (buffer->cur().codepoint, 0, &buffer->cur().codepoint);
}
void void
hb_ot_shape_glyphs_closure (hb_font_t *font, hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer, hb_buffer_t *buffer,
@ -574,7 +572,7 @@ hb_ot_shape_glyphs_closure (hb_font_t *font,
/* TODO: normalization? have shapers do closure()? */ /* TODO: normalization? have shapers do closure()? */
/* TODO: Deal with mirrored chars? */ /* TODO: Deal with mirrored chars? */
hb_ot_map_glyphs (font, buffer); hb_ot_map_glyphs_dumb (font, buffer);
/* Seed it. It's user's responsibility to have cleard glyphs /* Seed it. It's user's responsibility to have cleard glyphs
* if that's what they desire. */ * if that's what they desire. */