[Indic] Streamline feature would_apply()
authorBehdad Esfahbod <behdad@behdad.org>
Thu, 2 Aug 2012 09:27:46 +0000 (05:27 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Thu, 2 Aug 2012 09:41:18 +0000 (05:41 -0400)
Comes with some 10% speedup for Devanagari even!

src/hb-ot-map-private.hh
src/hb-ot-map.cc
src/hb-ot-shape-complex-indic.cc

index 2ba0f76..5e3c967 100644 (file)
@@ -42,6 +42,38 @@ struct hb_ot_map_t
 
   public:
 
+  struct feature_map_t {
+    hb_tag_t tag; /* should be first for our bsearch to work */
+    unsigned int index[2]; /* GSUB/GPOS */
+    unsigned int stage[2]; /* GSUB/GPOS */
+    unsigned int shift;
+    hb_mask_t mask;
+    hb_mask_t _1_mask; /* mask for value=1, for quick access */
+
+    static int cmp (const feature_map_t *a, const feature_map_t *b)
+    { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
+  };
+
+  struct lookup_map_t {
+    unsigned int index;
+    hb_mask_t mask;
+
+    static int cmp (const lookup_map_t *a, const lookup_map_t *b)
+    { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
+  };
+
+  typedef void (*pause_func_t) (const hb_ot_map_t *map, void *face_or_font, hb_buffer_t *buffer, void *user_data);
+  typedef struct {
+    pause_func_t func;
+    void *user_data;
+  } pause_callback_t;
+
+  struct pause_map_t {
+    unsigned int num_lookups; /* Cumulative */
+    pause_callback_t callback;
+  };
+
+
   hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
 
   typedef void (*gsub_pause_func_t) (const hb_ot_map_t *map, hb_face_t *face, hb_buffer_t *buffer, void *user_data);
@@ -60,11 +92,30 @@ struct hb_ot_map_t
     return map ? map->_1_mask : 0;
   }
 
-  inline hb_mask_t get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
+  inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
     const feature_map_t *map = features.bsearch (&feature_tag);
     return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
   }
 
+  inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->stage[table_index] : (unsigned int) -1;
+  }
+
+  inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
+                                const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
+    if (unlikely (stage == (unsigned int) -1)) {
+      *plookups = NULL;
+      *lookup_count = 0;
+      return;
+    }
+    assert (stage <= pauses[table_index].len);
+    unsigned int start = stage ? pauses[table_index][stage - 1].num_lookups : 0;
+    unsigned int end   = stage < pauses[table_index].len ? pauses[table_index][stage].num_lookups : lookups[table_index].len;
+    *plookups = &lookups[table_index][start];
+    *lookup_count = end - start;
+  }
+
   inline hb_tag_t get_chosen_script (unsigned int table_index) const
   { return chosen_script[table_index]; }
 
@@ -80,38 +131,8 @@ struct hb_ot_map_t
     pauses[1].finish ();
   }
 
-  private:
-
-  struct feature_map_t {
-    hb_tag_t tag; /* should be first for our bsearch to work */
-    unsigned int index[2]; /* GSUB/GPOS */
-    unsigned int stage[2]; /* GSUB/GPOS */
-    unsigned int shift;
-    hb_mask_t mask;
-    hb_mask_t _1_mask; /* mask for value=1, for quick access */
-
-    static int cmp (const feature_map_t *a, const feature_map_t *b)
-    { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
-  };
-
-  struct lookup_map_t {
-    unsigned int index;
-    hb_mask_t mask;
-
-    static int cmp (const lookup_map_t *a, const lookup_map_t *b)
-    { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
-  };
 
-  typedef void (*pause_func_t) (const hb_ot_map_t *map, void *face_or_font, hb_buffer_t *buffer, void *user_data);
-  typedef struct {
-    pause_func_t func;
-    void *user_data;
-  } pause_callback_t;
-
-  struct pause_map_t {
-    unsigned int num_lookups; /* Cumulative */
-    pause_callback_t callback;
-  };
+  private:
 
   HB_INTERNAL void add_lookups (hb_face_t    *face,
                                unsigned int  table_index,
index 20e8e6f..ae0cb61 100644 (file)
@@ -89,7 +89,8 @@ void hb_ot_map_t::substitute (hb_face_t *face, hb_buffer_t *buffer) const
 
     buffer->clear_output ();
 
-    pause->callback.func (this, face, buffer, pause->callback.user_data);
+    if (pause->callback.func)
+      pause->callback.func (this, face, buffer, pause->callback.user_data);
   }
 
   for (; i < lookups[table_index].len; i++)
@@ -106,7 +107,8 @@ void hb_ot_map_t::position (hb_font_t *font, hb_buffer_t *buffer) const
     for (; i < pause->num_lookups; i++)
       hb_ot_layout_position_lookup_fast (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
 
-    pause->callback.func (this, font, buffer, pause->callback.user_data);
+    if (pause->callback.func)
+      pause->callback.func (this, font, buffer, pause->callback.user_data);
   }
 
   for (; i < lookups[table_index].len; i++)
@@ -131,13 +133,11 @@ void hb_ot_map_t::substitute_closure (hb_face_t *face,
 
 void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data)
 {
-  if (pause_func) {
-    pause_info_t *p = pauses[table_index].push ();
-    if (likely (p)) {
-      p->stage = current_stage[table_index];
-      p->callback.func = pause_func;
-      p->callback.user_data = user_data;
-    }
+  pause_info_t *p = pauses[table_index].push ();
+  if (likely (p)) {
+    p->stage = current_stage[table_index];
+    p->callback.func = pause_func;
+    p->callback.user_data = user_data;
   }
 
   current_stage[table_index]++;
index ba4fb4d..8e3f3e6 100644 (file)
@@ -106,39 +106,48 @@ compare_codepoint (const void *pa, const void *pb)
   return a < b ? -1 : a == b ? 0 : +1;
 }
 
-static bool
-would_substitute (hb_codepoint_t    *glyphs,
-                 unsigned int       glyphs_count,
-                 hb_tag_t           feature_tag,
-                 const hb_ot_map_t *map,
-                 hb_face_t         *face)
+struct consonant_position_closure_t
 {
-  unsigned int lookup_indices[32];
-  unsigned int offset, len;
-
-  offset = 0;
-  do {
-    len = ARRAY_LENGTH (lookup_indices);
-    hb_ot_layout_feature_get_lookup_indexes (face, HB_OT_TAG_GSUB,
-                                            map->get_feature_index (0/*GSUB*/, feature_tag),
-                                            offset,
-                                            &len,
-                                            lookup_indices);
-
-    for (unsigned int i = 0; i < len; i++)
-      if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookup_indices[i]))
-       return true;
-
-    offset += len;
-  } while (len == ARRAY_LENGTH (lookup_indices));
-
-  return false;
-}
+  struct feature_t
+  {
+    feature_t (const hb_ot_map_t *map, hb_tag_t feature_tag)
+    {
+      map->get_stage_lookups (0/*GSUB*/,
+                             map->get_feature_stage (0/*GSUB*/, feature_tag),
+                             &lookups, &count);
+    }
+
+    inline bool would_substitute (hb_codepoint_t    *glyphs,
+                                 unsigned int       glyphs_count,
+                                 hb_face_t         *face) const
+    {
+      for (unsigned int i = 0; i < count; i++)
+       if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookups[i].index))
+         return true;
+      return false;
+    }
+
+    private:
+    const hb_ot_map_t::lookup_map_t *lookups;
+    unsigned int count;
+  };
+
+  consonant_position_closure_t (const hb_ot_map_t *map_) :
+                                       map (map_),
+                                       pref (map_, HB_TAG('p','r','e','f')),
+                                       blwf (map_, HB_TAG('b','l','w','f')),
+                                       pstf (map_, HB_TAG('p','s','t','f')) {}
+
+  const hb_ot_map_t *map;
+  feature_t pref;
+  feature_t blwf;
+  feature_t pstf;
+};
 
 static indic_position_t
-consonant_position (hb_codepoint_t     u,
-                   const hb_ot_map_t *map,
-                   hb_font_t         *font)
+consonant_position (hb_codepoint_t  u,
+                   const consonant_position_closure_t *closure,
+                   hb_font_t      *font)
 {
   if ((u & ~0x007F) == 0x1780)
     return POS_BELOW_C; /* In Khmer coeng model, post and below forms should not be reordered. */
@@ -148,14 +157,14 @@ consonant_position (hb_codepoint_t     u,
   if ((u & ~0x007F) == 0x1780) virama = 0x17D2; /* Khmaer */
   hb_codepoint_t glyphs[2];
 
-  unsigned int virama_pos = IS_OLD_INDIC_TAG (map->get_chosen_script (0)) ? 1 : 0;
+  unsigned int virama_pos = IS_OLD_INDIC_TAG (closure->map->get_chosen_script (0)) ? 1 : 0;
   font->get_glyph (virama, 0, &glyphs[virama_pos]);
   font->get_glyph (u,      0, &glyphs[1-virama_pos]);
 
   hb_face_t *face = font->face;
-  if (would_substitute (glyphs, ARRAY_LENGTH (glyphs), HB_TAG('p','r','e','f'), map, face)) return POS_BELOW_C;
-  if (would_substitute (glyphs, ARRAY_LENGTH (glyphs), HB_TAG('b','l','w','f'), map, face)) return POS_BELOW_C;
-  if (would_substitute (glyphs, ARRAY_LENGTH (glyphs), HB_TAG('p','s','t','f'), map, face)) return POS_POST_C;
+  if (closure->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C;
+  if (closure->blwf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C;
+  if (closure->pstf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_POST_C;
   return POS_BASE_C;
 }
 
@@ -260,7 +269,7 @@ is_halant_or_coeng (const hb_glyph_info_t &info)
 
 static inline void
 set_indic_properties (hb_glyph_info_t   &info,
-                     const hb_ot_map_t *map,
+                     const consonant_position_closure_t *closure,
                      hb_font_t         *font)
 {
   hb_codepoint_t u = info.codepoint;
@@ -322,7 +331,7 @@ set_indic_properties (hb_glyph_info_t   &info,
 
   if ((FLAG (cat) & CONSONANT_FLAGS))
   {
-    pos = consonant_position (u, map, font);
+    pos = consonant_position (u, closure, font);
     if (is_ra (u))
       cat = OT_Ra;
   }
@@ -462,9 +471,11 @@ setup_masks_indic (const hb_ot_complex_shaper_t *shaper,
   /* We cannot setup masks here.  We save information about characters
    * and setup masks later on in a pause-callback. */
 
+  consonant_position_closure_t closure (map);
+
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    set_indic_properties (buffer->info[i], map, font);
+    set_indic_properties (buffer->info[i], &closure, font);
 }
 
 static int