[OT] Avoid calling get_glyph() twice
authorBehdad Esfahbod <behdad@behdad.org>
Fri, 10 Aug 2012 02:33:32 +0000 (22:33 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Fri, 10 Aug 2012 02:33:32 +0000 (22:33 -0400)
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.

src/hb-ot-shape-normalize-private.hh
src/hb-ot-shape-normalize.cc
src/hb-ot-shape.cc

index f222c07..462b87d 100644 (file)
@@ -32,6 +32,8 @@
 #include "hb-font.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 {
   HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
index ccaf1d7..e6092d6 100644 (file)
@@ -258,16 +258,25 @@ compose_func (hb_unicode_funcs_t *unicode,
   return found;
 }
 
+
+static inline void
+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)
+output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 {
+  buffer->cur().glyph_index() = glyph;
   buffer->output_glyph (unichar);
   _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
 }
 
 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 ();
 }
 
@@ -282,31 +291,31 @@ decompose (hb_font_t *font, hb_buffer_t *buffer,
           bool shortest,
           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) ||
-      (b && !font->get_glyph (b, 0, &glyph)))
+      (b && !font->get_glyph (b, 0, &b_glyph)))
     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) {
     /* Output a and b */
-    output_char (buffer, a);
+    output_char (buffer, a, a_glyph);
     if (b)
-      output_char (buffer, b);
+      output_char (buffer, b, b_glyph);
     return true;
   }
 
   if (decompose (font, buffer, shortest, a)) {
     if (b)
-      output_char (buffer, b);
+      output_char (buffer, b, b_glyph);
     return true;
   }
 
   if (has_a) {
-    output_char (buffer, a);
+    output_char (buffer, a, a_glyph);
     if (b)
-      output_char (buffer, b);
+      output_char (buffer, b, b_glyph);
     return true;
   }
 
@@ -319,18 +328,18 @@ decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer,
 {
   unsigned int len, i;
   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);
   if (!len)
     return false;
 
-  hb_codepoint_t glyph;
   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;
 
   for (i = 0; i < len; i++)
-    output_char (buffer, decomposed[i]);
+    output_char (buffer, decomposed[i], glyphs[i]);
 
   return true;
 }
@@ -343,15 +352,38 @@ decompose_current_character (hb_font_t *font, hb_buffer_t *buffer,
 
   /* Kind of a cute waterfall here... */
   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))
     skip_char (buffer);
   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))
     skip_char (buffer);
-  else
-    next_char (buffer);
+  else {
+    /* 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
@@ -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. */
   for (unsigned int i = buffer->idx; i < end; i++)
     if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
-      while (buffer->idx < end)
-       next_char (buffer);
+      handle_variation_selector_cluster (font, buffer, end);
       return;
     }
 
@@ -457,7 +488,7 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
   buffer->clear_output ();
   count = buffer->len;
   unsigned int starter = 0;
-  next_char (buffer);
+  buffer->next_glyph ();
   while (buffer->idx < count)
   {
     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))
     {
       /* Composes. */
-      next_char (buffer); /* Copy to out-buffer. */
+      buffer->next_glyph (); /* Copy to out-buffer. */
       if (unlikely (buffer->in_error))
         return;
       buffer->merge_out_clusters (starter, buffer->out_len);
       buffer->out_len--; /* Remove the second composable. */
       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);
 
       continue;
     }
 
     /* Blocked, or doesn't compose. */
-    next_char (buffer);
+    buffer->next_glyph ();
 
     if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0)
       starter = buffer->out_len - 1;
index b4745c5..2062102 100644 (file)
@@ -308,28 +308,12 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 }
 
 static inline void
-hb_ot_map_glyphs (hb_font_t    *font,
-                 hb_buffer_t  *buffer)
+hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
 {
-  hb_codepoint_t glyph;
-
-  buffer->clear_output ();
-
-  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 ();
+  /* Normalization process sets up glyph_index(), we just copy it. */
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    buffer->info[i].codepoint = buffer->info[i].glyph_index();
 }
 
 static inline void
@@ -337,6 +321,8 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
 {
   hb_ot_mirror_chars (c);
 
+  HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index);
+
   _hb_ot_shape_normalize (c->font, c->buffer,
                          c->plan->shaper->normalization_preference ?
                          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_map_glyphs (c->font, c->buffer);
+  hb_ot_map_glyphs_fast (c->buffer);
+
+  HB_BUFFER_DEALLOCATE_VAR (c->buffer, glyph_index);
 }
 
 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
 hb_ot_shape_glyphs_closure (hb_font_t          *font,
                            hb_buffer_t        *buffer,
@@ -574,7 +572,7 @@ hb_ot_shape_glyphs_closure (hb_font_t          *font,
 
   /* TODO: normalization? have shapers do closure()? */
   /* 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
    * if that's what they desire. */