[HarfBuzz] harfbuzz: Branch 'master' - 18 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Thu Feb 14 10:12:27 PST 2013


 src/hb-ot-layout-gpos-table.hh                                                   |   25 
 src/hb-ot-layout-gsub-table.hh                                                   |    9 
 src/hb-ot-layout-gsubgpos-private.hh                                             |  378 ++++++----
 src/hb-ot-layout-private.hh                                                      |   58 +
 src/hb-ot-layout.cc                                                              |   10 
 src/hb-ot-map-private.hh                                                         |   41 -
 src/hb-ot-map.cc                                                                 |   56 -
 src/hb-ot-shape-complex-arabic-fallback.hh                                       |    2 
 src/hb-ot-shape-complex-arabic.cc                                                |   16 
 src/hb-ot-shape-complex-default.cc                                               |    2 
 src/hb-ot-shape-complex-indic-machine.rl                                         |    2 
 src/hb-ot-shape-complex-indic.cc                                                 |   79 +-
 src/hb-ot-shape-complex-myanmar-machine.rl                                       |    2 
 src/hb-ot-shape-complex-myanmar.cc                                               |   12 
 src/hb-ot-shape-complex-sea-machine.rl                                           |    2 
 src/hb-ot-shape-complex-sea.cc                                                   |   10 
 src/hb-ot-shape-private.hh                                                       |   37 
 src/hb-ot-shape.cc                                                               |   14 
 test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt |   10 
 19 files changed, 491 insertions(+), 274 deletions(-)

New commits:
commit cfc507c5432e6327e8484b07b9e091212653bc92
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 10:40:12 2013 -0500

    [Indic-like] Disable automatic joiner handling for basic shaping features
    
    Not for Arabic, but for Indic-like scripts.  ZWJ/ZWNJ have special
    meanings in those scripts, so let font lookups take full control.
    
    This undoes the regression caused by automatic-joiners handling
    introduced two commits ago.
    
    We only disable automatic joiner handling for the "basic shaping
    features" of Indic, Myanmar, and SEAsian shapers.  The "presentation
    forms" and other features are still applied with automatic-joiner
    handling.
    
    This change also changes the test suite failure statistics, such that
    a few scripts show more "failures".  The most affected is Kannada.
    However, upon inspection, we believe that in most, if not all, of the
    new failures, we are producing results superior to Uniscribe.  Hard to
    count those!
    
    Here's an example of what is fixed by the recent joiner-handling
    changes:
    
      https://bugs.freedesktop.org/show_bug.cgi?id=58714
    
    New numbers, for future reference:
    
    BENGALI: 353892 out of 354188 tests passed. 296 failed (0.0835714%)
    DEVANAGARI: 707336 out of 707394 tests passed. 58 failed (0.00819911%)
    GUJARATI: 366262 out of 366457 tests passed. 195 failed (0.0532122%)
    GURMUKHI: 60706 out of 60747 tests passed. 41 failed (0.067493%)
    KANNADA: 950680 out of 951913 tests passed. 1233 failed (0.129529%)
    KHMER: 299074 out of 299124 tests passed. 50 failed (0.0167155%)
    LAO: 53611 out of 53644 tests passed. 33 failed (0.0615167%)
    MALAYALAM: 1047983 out of 1048334 tests passed. 351 failed (0.0334817%)
    ORIYA: 42320 out of 42329 tests passed. 9 failed (0.021262%)
    SINHALA: 271539 out of 271847 tests passed. 308 failed (0.113299%)
    TAMIL: 1091753 out of 1091754 tests passed. 1 failed (9.15957e-05%)
    TELUGU: 970555 out of 970573 tests passed. 18 failed (0.00185457%)
    TIBETAN: 208469 out of 208469 tests passed. 0 failed (0%)

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 4a6c9c5..a709c32 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -261,6 +261,7 @@ struct hb_apply_context_t
   hb_buffer_t *buffer;
   hb_direction_t direction;
   hb_mask_t lookup_mask;
+  bool auto_joiners;
   recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int lookup_props;
@@ -272,11 +273,13 @@ struct hb_apply_context_t
   hb_apply_context_t (unsigned int table_index_,
 		      hb_font_t *font_,
 		      hb_buffer_t *buffer_,
-		      hb_mask_t lookup_mask_) :
+		      hb_mask_t lookup_mask_,
+		      bool auto_joiners_) :
 			table_index (table_index_),
 			font (font_), face (font->face), buffer (buffer_),
 			direction (buffer_->props.direction),
 			lookup_mask (lookup_mask_),
+			auto_joiners (auto_joiners_),
 			recurse_func (NULL),
 			nesting_level_left (MAX_NESTING_LEVEL),
 			lookup_props (0),
@@ -292,8 +295,8 @@ struct hb_apply_context_t
   {
     inline matcher_t (void) :
 	     lookup_props (0),
-	     ignore_zwnj (true),
-	     ignore_zwj (true),
+	     ignore_zwnj (false),
+	     ignore_zwj (false),
 	     mask (-1),
 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
 	     syllable arg1(0),
@@ -369,13 +372,16 @@ struct hb_apply_context_t
 					 end (c->buffer->len)
     {
       matcher.set_lookup_props (c->lookup_props);
-      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
-      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
-      matcher.set_ignore_zwj (true);
+      if (c->auto_joiners)
+      {
+	/* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+	matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+	matcher.set_ignore_zwj (true);
+      }
       if (!context_match)
       {
-        matcher.set_mask (c->lookup_mask);
-        matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+	matcher.set_mask (c->lookup_mask);
+	matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
       }
     }
     inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
@@ -439,13 +445,16 @@ struct hb_apply_context_t
 					  num_items (num_items_)
     {
       matcher.set_lookup_props (c->lookup_props);
-      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
-      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
-      matcher.set_ignore_zwj (true);
+      if (c->auto_joiners)
+      {
+	/* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+	matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+	matcher.set_ignore_zwj (true);
+      }
       if (!context_match)
       {
-        matcher.set_mask (c->lookup_mask);
-        matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+	matcher.set_mask (c->lookup_mask);
+	matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
       }
     }
     inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 21a79d6..3c5a1e8 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -206,7 +206,8 @@ HB_INTERNAL hb_bool_t
 hb_ot_layout_substitute_lookup (hb_font_t    *font,
 				hb_buffer_t  *buffer,
 				unsigned int  lookup_index,
-				hb_mask_t     mask);
+				hb_mask_t     mask,
+				hb_bool_t     auto_joiners);
 
 /* Should be called after all the substitute_lookup's are done */
 HB_INTERNAL void
@@ -223,7 +224,8 @@ HB_INTERNAL hb_bool_t
 hb_ot_layout_position_lookup (hb_font_t    *font,
 			      hb_buffer_t  *buffer,
 			      unsigned int  lookup_index,
-			      hb_mask_t     mask);
+			      hb_mask_t     mask,
+			      hb_bool_t     auto_joiners);
 
 /* Should be called after all the position_lookup's are done */
 HB_INTERNAL void
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 62988ab..0349b32 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -666,11 +666,12 @@ hb_bool_t
 hb_ot_layout_substitute_lookup (hb_font_t    *font,
 				hb_buffer_t  *buffer,
 				unsigned int  lookup_index,
-				hb_mask_t     mask)
+				hb_mask_t     mask,
+				hb_bool_t     auto_joiners)
 {
   if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
 
-  OT::hb_apply_context_t c (0, font, buffer, mask);
+  OT::hb_apply_context_t c (0, font, buffer, mask, auto_joiners);
 
   const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);
 
@@ -715,11 +716,12 @@ hb_bool_t
 hb_ot_layout_position_lookup (hb_font_t    *font,
 			      hb_buffer_t  *buffer,
 			      unsigned int  lookup_index,
-			      hb_mask_t     mask)
+			      hb_mask_t     mask,
+			      hb_bool_t     auto_joiners)
 {
   if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
 
-  OT::hb_apply_context_t c (1, font, buffer, mask);
+  OT::hb_apply_context_t c (1, font, buffer, mask, auto_joiners);
 
   const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);
 
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 663b7d1..942e9f4 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -49,14 +49,16 @@ struct hb_ot_map_t
     unsigned int shift;
     hb_mask_t mask;
     hb_mask_t _1_mask; /* mask for value=1, for quick access */
-    hb_bool_t needs_fallback;
+    unsigned int needs_fallback : 1;
+    unsigned int auto_joiners : 1;
 
     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;
+    unsigned short index;
+    unsigned short auto_joiners : 1;
     hb_mask_t mask;
 
     static int cmp (const lookup_map_t *a, const lookup_map_t *b)
@@ -136,7 +138,8 @@ struct hb_ot_map_t
   HB_INTERNAL void add_lookups (hb_face_t    *face,
 				unsigned int  table_index,
 				unsigned int  feature_index,
-				hb_mask_t     mask);
+				hb_mask_t     mask,
+				bool          auto_joiners);
 
   hb_mask_t global_mask;
 
@@ -148,7 +151,8 @@ struct hb_ot_map_t
 enum hb_ot_map_feature_flags_t {
   F_NONE		= 0x0000,
   F_GLOBAL		= 0x0001,
-  F_HAS_FALLBACK	= 0x0002
+  F_HAS_FALLBACK	= 0x0002,
+  F_MANUAL_JOINERS	= 0x0004
 };
 inline hb_ot_map_feature_flags_t
 operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 7848186..2fbb6ce 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -33,7 +33,8 @@ void
 hb_ot_map_t::add_lookups (hb_face_t    *face,
 			  unsigned int  table_index,
 			  unsigned int  feature_index,
-			  hb_mask_t     mask)
+			  hb_mask_t     mask,
+			  bool          auto_joiners)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
@@ -53,6 +54,7 @@ hb_ot_map_t::add_lookups (hb_face_t    *face,
         return;
       lookup->mask = mask;
       lookup->index = lookup_indices[i];
+      lookup->auto_joiners = auto_joiners;
     }
 
     offset += len;
@@ -108,7 +110,10 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h
   for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
     const pause_map_t *pause = &pauses[table_index][pause_index];
     for (; i < pause->num_lookups; i++)
-      hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
+      hb_ot_layout_substitute_lookup (font, buffer,
+				      lookups[table_index][i].index,
+				      lookups[table_index][i].mask,
+				      lookups[table_index][i].auto_joiners);
 
     buffer->clear_output ();
 
@@ -117,7 +122,9 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h
   }
 
   for (; i < lookups[table_index].len; i++)
-    hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
+    hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index,
+				    lookups[table_index][i].mask,
+				    lookups[table_index][i].auto_joiners);
 }
 
 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
@@ -128,14 +135,18 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_
   for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
     const pause_map_t *pause = &pauses[table_index][pause_index];
     for (; i < pause->num_lookups; i++)
-      hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
+      hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index,
+				    lookups[table_index][i].mask,
+				    lookups[table_index][i].auto_joiners);
 
     if (pause->callback)
       pause->callback (plan, font, buffer);
   }
 
   for (; i < lookups[table_index].len; i++)
-    hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
+    hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index,
+				  lookups[table_index][i].mask,
+				  lookups[table_index][i].auto_joiners);
 }
 
 void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
@@ -232,6 +243,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
     map->index[1] = feature_index[1];
     map->stage[0] = info->stage[0];
     map->stage[1] = info->stage[1];
+    map->auto_joiners = !(info->flags & F_MANUAL_JOINERS);
     if ((info->flags & F_GLOBAL) && info->max_value == 1) {
       /* Uses the global bit */
       map->shift = 0;
@@ -264,7 +276,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 							  script_index[table_index],
 							  language_index[table_index],
 							  &required_feature_index))
-      m.add_lookups (face, table_index, required_feature_index, 1);
+      m.add_lookups (face, table_index, required_feature_index, 1, true);
 
     unsigned int pause_index = 0;
     unsigned int last_num_lookups = 0;
@@ -272,7 +284,10 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
     {
       for (unsigned i = 0; i < m.features.len; i++)
         if (m.features[i].stage[table_index] == stage)
-	  m.add_lookups (face, table_index, m.features[i].index[table_index], m.features[i].mask);
+	  m.add_lookups (face, table_index,
+			 m.features[i].index[table_index],
+			 m.features[i].mask,
+			 m.features[i].auto_joiners);
 
       /* Sort lookups and merge duplicates */
       if (last_num_lookups < m.lookups[table_index].len)
@@ -284,7 +299,10 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 	  if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
 	    m.lookups[table_index][++j] = m.lookups[table_index][i];
 	  else
+	  {
 	    m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
+	    m.lookups[table_index][j].auto_joiners &= m.lookups[table_index][i].auto_joiners;
+	  }
 	m.lookups[table_index].shrink (j + 1);
       }
 
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index c0dbff0..6f8e951 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -244,7 +244,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
 {
   for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
     if (fallback_plan->lookup_array[i]) {
-      OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i]);
+      OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i], true/*auto_joiners*/);
       fallback_plan->lookup_array[i]->apply_string (&c, &fallback_plan->digest_array[i]);
     }
 }
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index b60e310..0beddc8 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -339,18 +339,18 @@ indic_features[] =
    * Basic features.
    * These features are applied in order, one at a time, after initial_reordering.
    */
-  {HB_TAG('n','u','k','t'), F_GLOBAL},
-  {HB_TAG('a','k','h','n'), F_GLOBAL},
-  {HB_TAG('r','p','h','f'), F_NONE},
-  {HB_TAG('r','k','r','f'), F_GLOBAL},
-  {HB_TAG('p','r','e','f'), F_NONE},
-  {HB_TAG('b','l','w','f'), F_NONE},
-  {HB_TAG('h','a','l','f'), F_NONE},
-  {HB_TAG('a','b','v','f'), F_NONE},
-  {HB_TAG('p','s','t','f'), F_NONE},
-  {HB_TAG('c','f','a','r'), F_NONE},
-  {HB_TAG('v','a','t','u'), F_GLOBAL},
-  {HB_TAG('c','j','c','t'), F_GLOBAL},
+  {HB_TAG('n','u','k','t'), F_MANUAL_JOINERS | F_GLOBAL},
+  {HB_TAG('a','k','h','n'), F_MANUAL_JOINERS | F_GLOBAL},
+  {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS},
+  {HB_TAG('r','k','r','f'), F_MANUAL_JOINERS | F_GLOBAL},
+  {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
+  {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
+  {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS},
+  {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
+  {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
+  {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS},
+  {HB_TAG('v','a','t','u'), F_MANUAL_JOINERS | F_GLOBAL},
+  {HB_TAG('c','j','c','t'), F_MANUAL_JOINERS | F_GLOBAL},
   /*
    * Other features.
    * These features are applied all at once, after final_reordering.
@@ -1003,8 +1003,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
       do {
 	j--;
 
-	/* A ZWJ disables CJCT, however, it's mere presence is enough
-	 * to disable ligation.  No explicit action needed. */
+	/* ZWJ/ZWNJ should disable CJCT.  They do that by simply
+	 * being there, since we don't skip them for the CJCT
+	 * feature (ie. F_MANUAL_JOINERS) */
 
 	/* A ZWNJ disables HALF. */
 	if (non_joiner)
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index 53a9ab4..e766973 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -107,12 +107,12 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < MYANMAR_BASIC_FEATURES; i++) {
-    map->add_global_bool_feature (myanmar_features[i]);
+    map->add_feature (myanmar_features[i], 1, F_GLOBAL | F_MANUAL_JOINERS);
     map->add_gsub_pause (NULL);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < MYANMAR_NUM_FEATURES; i++) {
-    map->add_global_bool_feature (myanmar_features[i]);
+    map->add_feature (myanmar_features[i], 1, F_GLOBAL);
   }
 }
 
diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc
index 387a4a1..c06612e 100644
--- a/src/hb-ot-shape-complex-sea.cc
+++ b/src/hb-ot-shape-complex-sea.cc
@@ -109,12 +109,12 @@ collect_features_sea (hb_ot_shape_planner_t *plan)
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < SEA_BASIC_FEATURES; i++) {
-    map->add_global_bool_feature (sea_features[i]);
+    map->add_feature (sea_features[i], 1, F_GLOBAL | F_MANUAL_JOINERS);
     map->add_gsub_pause (NULL);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < SEA_NUM_FEATURES; i++) {
-    map->add_global_bool_feature (sea_features[i]);
+    map->add_feature (sea_features[i], 1, F_GLOBAL | F_MANUAL_JOINERS);
   }
 }
 
commit 0b45479198d61d5135dad771e9c68408eb13f930
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 10:46:52 2013 -0500

    [OTLayout] Add fine-grained control over ZWJ matching
    
    Not used yet.  Next commit...

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index fe10589..4a6c9c5 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -293,6 +293,7 @@ struct hb_apply_context_t
     inline matcher_t (void) :
 	     lookup_props (0),
 	     ignore_zwnj (true),
+	     ignore_zwj (true),
 	     mask (-1),
 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
 	     syllable arg1(0),
@@ -303,6 +304,7 @@ struct hb_apply_context_t
     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
 
     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
+    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
     inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
     inline void set_mask (hb_mask_t mask_) { mask = mask_; }
     inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
@@ -335,8 +337,9 @@ struct hb_apply_context_t
       if (!c->match_properties (info.codepoint, property, lookup_props))
 	return SKIP_YES;
 
-      if (unlikely ((_hb_glyph_info_is_default_ignorable (&info) &&
-		     (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info))) &&
+      if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
+		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
+		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
 		    !is_a_ligature (info)))
 	return SKIP_MAYBE;
 
@@ -346,6 +349,7 @@ struct hb_apply_context_t
     protected:
     unsigned int lookup_props;
     bool ignore_zwnj;
+    bool ignore_zwj;
     hb_mask_t mask;
     uint8_t syllable;
     match_func_t match_func;
@@ -367,6 +371,7 @@ struct hb_apply_context_t
       matcher.set_lookup_props (c->lookup_props);
       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      matcher.set_ignore_zwj (true);
       if (!context_match)
       {
         matcher.set_mask (c->lookup_mask);
@@ -436,6 +441,7 @@ struct hb_apply_context_t
       matcher.set_lookup_props (c->lookup_props);
       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      matcher.set_ignore_zwj (true);
       if (!context_match)
       {
         matcher.set_mask (c->lookup_mask);
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index cc4b590..21a79d6 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -53,14 +53,15 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *uni
 {
   info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
 			   (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0) |
-			   (info->codepoint == 0x200C ? 0x40 : 0);
+			   (info->codepoint == 0x200C ? 0x40 : 0) |
+			   (info->codepoint == 0x200D ? 0x20 : 0);
   info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 }
 
 inline hb_unicode_general_category_t
 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 {
-  return (hb_unicode_general_category_t) (info->unicode_props0() & 0x3F);
+  return (hb_unicode_general_category_t) (info->unicode_props0() & 0x1F);
 }
 
 inline void
@@ -87,6 +88,12 @@ _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
   return !!(info->unicode_props0() & 0x40);
 }
 
+inline hb_bool_t
+_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & 0x20);
+}
+
 
 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 
commit 607feb7cff0e50f8738d2e49ca463fc9d7d494de
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 07:43:13 2013 -0500

    [OTLayout] Ignore default-ignorables when matching GSUB/GPOS
    
    When matching lookups, be smart about default-ignorable characters.
    In particular:
    
    Do nothing specific about ZWNJ, but for the other default-ignorables:
    
    If the lookup in question uses the ignorable character in a sequence,
    then match it as we used to do.  However, if the sequence match will
    fail because the default-ignorable blocked it, try skipping the
    ignorable character and continue.
    
    The most immediate thing it means is that if Lam-Alef forms a ligature,
    then Lam-ZWJ-Alef will do to.  Finally!
    
    One exception: when matching for GPOS, or for backtrack/lookahead of
    GSUB, we ignore ZWNJ too.  That's the right thing to do.
    
    It certainly is possible to build fonts that this feature will result
    in undesirable glyphs, but it's hard to think of a real-world case
    that that would happen.
    
    This *does* break Indic shaping right now, since Indic Unicode has
    specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
    those rules.  That will be fixed in upcoming commits.

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 71e0aee..44f1c64 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -596,6 +596,7 @@ struct PairSet
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
     {
+      /* TODO bsearch */
       if (c->buffer->info[pos].codepoint == record->secondGlyph)
       {
 	valueFormats[0].apply_value (c->font, c->direction, this,
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index ec549a8..40ee5f2 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -638,9 +638,9 @@ struct Ligature
     ligate_input (c,
 		  count,
 		  &component[1],
-		  ligGlyph,
 		  match_glyph,
 		  NULL,
+		  ligGlyph,
 		  is_mark_ligature,
 		  total_component_count);
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 07989fa..fe10589 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -288,53 +288,137 @@ struct hb_apply_context_t
   inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
   inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
 
+  struct matcher_t
+  {
+    inline matcher_t (void) :
+	     lookup_props (0),
+	     ignore_zwnj (true),
+	     mask (-1),
+#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
+	     syllable arg1(0),
+#undef arg1
+	     match_func (NULL),
+	     match_data (NULL) {};
+
+    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+
+    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
+    inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+    inline void set_mask (hb_mask_t mask_) { mask = mask_; }
+    inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
+    inline void set_match_func (match_func_t match_func_,
+				const void *match_data_)
+    { match_func = match_func_; match_data = match_data_; }
+
+    inline bool matches (const hb_glyph_info_t &info,
+			 const USHORT          *glyph_data) const
+    {
+      return (info.mask & mask) &&
+	     (!syllable || syllable == info.syllable ()) &&
+	     (!match_func || match_func (info.codepoint, *glyph_data, match_data));
+    }
+
+    enum may_skip_t {
+      SKIP_NO,
+      SKIP_YES,
+      SKIP_MAYBE
+    };
+
+    inline may_skip_t
+    may_skip (const hb_apply_context_t *c,
+	      const hb_glyph_info_t    &info) const
+    {
+      unsigned int property;
+
+      property = info.glyph_props();
+
+      if (!c->match_properties (info.codepoint, property, lookup_props))
+	return SKIP_YES;
+
+      if (unlikely ((_hb_glyph_info_is_default_ignorable (&info) &&
+		     (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info))) &&
+		    !is_a_ligature (info)))
+	return SKIP_MAYBE;
+
+      return SKIP_NO;
+    }
+
+    protected:
+    unsigned int lookup_props;
+    bool ignore_zwnj;
+    hb_mask_t mask;
+    uint8_t syllable;
+    match_func_t match_func;
+    const void *match_data;
+  };
+
   struct skipping_forward_iterator_t
   {
     inline skipping_forward_iterator_t (hb_apply_context_t *c_,
 					unsigned int start_index_,
 					unsigned int num_items_,
-					bool context_match = false)
+					bool context_match = false) :
+					 idx (start_index_),
+					 c (c_),
+					 match_glyph_data (NULL),
+					 num_items (num_items_),
+					 end (c->buffer->len)
     {
-      c = c_;
-      lookup_props = c->lookup_props;
-      idx = start_index_;
-      num_items = num_items_;
-      mask = context_match ? -1 : c->lookup_mask;
-      syllable = context_match ? 0 : c->buffer->cur().syllable ();
-      end = c->buffer->len;
-    }
-    inline void set_lookup_props (unsigned int lookup_props_)
-    {
-      lookup_props = lookup_props_;
-    }
-    inline bool has_no_chance (void) const
-    {
-      return unlikely (num_items && idx + num_items >= end);
+      matcher.set_lookup_props (c->lookup_props);
+      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      if (!context_match)
+      {
+        matcher.set_mask (c->lookup_mask);
+        matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+      }
     }
-    inline void reject (void)
+    inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
+    inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
+    inline void set_match_func (matcher_t::match_func_t match_func,
+				const void *match_data,
+				const USHORT glyph_data[])
     {
-      num_items++;
+      matcher.set_match_func (match_func, match_data);
+      match_glyph_data = glyph_data;
     }
+
+    inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
+    inline void reject (void) { num_items++; match_glyph_data--; }
     inline bool next (void)
     {
       assert (num_items > 0);
-      do
+      matcher_t::may_skip_t skip;
+      while (!has_no_chance ())
       {
-	if (has_no_chance ())
-	  return false;
 	idx++;
-      } while (c->should_skip (&c->buffer->info[idx], lookup_props));
-      num_items--;
-      return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
+	const hb_glyph_info_t &info = c->buffer->info[idx];
+
+	skip = matcher.may_skip (c, info);
+
+	if (unlikely (skip == matcher_t::SKIP_YES))
+	  continue;
+
+	if (matcher.matches (info, match_glyph_data))
+	{
+	  num_items--;
+	  match_glyph_data++;
+	  return true;
+	}
+
+	if (skip == matcher_t::SKIP_NO)
+	  return false;
+      }
+      return false;
     }
 
     unsigned int idx;
     protected:
     hb_apply_context_t *c;
-    unsigned int lookup_props;
+    matcher_t matcher;
+    const USHORT *match_glyph_data;
+
     unsigned int num_items;
-    hb_mask_t mask;
-    uint8_t syllable;
     unsigned int end;
   };
 
@@ -343,47 +427,67 @@ struct hb_apply_context_t
     inline skipping_backward_iterator_t (hb_apply_context_t *c_,
 					 unsigned int start_index_,
 					 unsigned int num_items_,
-					 bool context_match = false)
+					 bool context_match = false) :
+					  idx (start_index_),
+					  c (c_),
+					  match_glyph_data (NULL),
+					  num_items (num_items_)
     {
-      c = c_;
-      lookup_props = c->lookup_props;
-      idx = start_index_;
-      num_items = num_items_;
-      mask = context_match ? -1 : c->lookup_mask;
-      syllable = context_match ? 0 : c->buffer->cur().syllable ();
-    }
-    inline void set_lookup_props (unsigned int lookup_props_)
-    {
-      lookup_props = lookup_props_;
-    }
-    inline bool has_no_chance (void) const
-    {
-      return unlikely (idx < num_items);
+      matcher.set_lookup_props (c->lookup_props);
+      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      if (!context_match)
+      {
+        matcher.set_mask (c->lookup_mask);
+        matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+      }
     }
-    inline void reject (void)
+    inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
+    inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
+    inline void set_match_func (matcher_t::match_func_t match_func,
+				const void *match_data,
+				const USHORT glyph_data[])
     {
-      num_items++;
+      matcher.set_match_func (match_func, match_data);
+      match_glyph_data = glyph_data;
     }
+
+    inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
+    inline void reject (void) { num_items++; }
     inline bool prev (void)
     {
       assert (num_items > 0);
-      do
+      matcher_t::may_skip_t skip;
+      while (!has_no_chance ())
       {
-	if (has_no_chance ())
-	  return false;
 	idx--;
-      } while (c->should_skip (&c->buffer->out_info[idx], lookup_props));
-      num_items--;
-      return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
+	const hb_glyph_info_t &info = c->buffer->out_info[idx];
+
+	skip = matcher.may_skip (c, info);
+
+	if (unlikely (skip == matcher_t::SKIP_YES))
+	  continue;
+
+	if (matcher.matches (info, match_glyph_data))
+	{
+	  num_items--;
+	  match_glyph_data++;
+	  return true;
+	}
+
+	if (skip == matcher_t::SKIP_NO)
+	  return false;
+      }
+      return false;
     }
 
     unsigned int idx;
     protected:
     hb_apply_context_t *c;
-    unsigned int lookup_props;
+    matcher_t matcher;
+    const USHORT *match_glyph_data;
+
     unsigned int num_items;
-    hb_mask_t mask;
-    uint8_t syllable;
   };
 
   inline bool
@@ -435,18 +539,6 @@ struct hb_apply_context_t
     return match_properties (info->codepoint, property, lookup_props);
   }
 
-  inline bool
-  should_skip (hb_glyph_info_t *info,
-	       unsigned int  lookup_props) const
-  {
-    unsigned int property;
-
-    property = info->glyph_props();
-
-    return !match_properties (info->codepoint, property, lookup_props);
-  }
-
-
   inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
   {
     if (likely (has_glyph_classes))
@@ -591,6 +683,7 @@ static inline bool match_input (hb_apply_context_t *c,
   TRACE_APPLY (NULL);
 
   hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
+  skippy_iter.set_match_func (match_func, match_data, input);
   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
   /*
@@ -623,8 +716,6 @@ static inline bool match_input (hb_apply_context_t *c,
   {
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
-    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return TRACE_RETURN (false);
-
     unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
     unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
 
@@ -659,13 +750,17 @@ static inline bool match_input (hb_apply_context_t *c,
 }
 static inline void ligate_input (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph (not matched) */
-				 const USHORT input[] HB_UNUSED, /* Array of input values--start with second glyph */
+				 const USHORT input[], /* Array of input values--start with second glyph */
+				 match_func_t match_func,
+				 const void *match_data,
 				 hb_codepoint_t lig_glyph,
-				 match_func_t match_func HB_UNUSED,
-				 const void *match_data HB_UNUSED,
 				 bool is_mark_ligature,
 				 unsigned int total_component_count)
 {
+  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
+  skippy_iter.set_match_func (match_func, match_data, input);
+  if (skippy_iter.has_no_chance ()) return;
+
   /*
    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
    *   the ligature to keep its old ligature id.  This will allow it to attach to
@@ -700,8 +795,6 @@ static inline void ligate_input (hb_apply_context_t *c,
   unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
   unsigned int components_so_far = last_num_components;
 
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
-
   if (!is_mark_ligature)
     set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
   c->replace_glyph (lig_glyph, klass);
@@ -709,6 +802,7 @@ static inline void ligate_input (hb_apply_context_t *c,
   for (unsigned int i = 1; i < count; i++)
   {
     if (!skippy_iter.next ()) return;
+
     while (c->buffer->idx < skippy_iter.idx)
     {
       if (!is_mark_ligature) {
@@ -749,18 +843,13 @@ static inline bool match_backtrack (hb_apply_context_t *c,
   TRACE_APPLY (NULL);
 
   hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
-  if (skippy_iter.has_no_chance ())
-    return TRACE_RETURN (false);
+  skippy_iter.set_match_func (match_func, match_data, backtrack);
+  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
   for (unsigned int i = 0; i < count; i++)
-  {
     if (!skippy_iter.prev ())
       return TRACE_RETURN (false);
 
-    if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
-      return TRACE_RETURN (false);
-  }
-
   return TRACE_RETURN (true);
 }
 
@@ -774,18 +863,13 @@ static inline bool match_lookahead (hb_apply_context_t *c,
   TRACE_APPLY (NULL);
 
   hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
-  if (skippy_iter.has_no_chance ())
-    return TRACE_RETURN (false);
+  skippy_iter.set_match_func (match_func, match_data, lookahead);
+  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
   for (unsigned int i = 0; i < count; i++)
-  {
     if (!skippy_iter.next ())
       return TRACE_RETURN (false);
 
-    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
-      return TRACE_RETURN (false);
-  }
-
   return TRACE_RETURN (true);
 }
 
@@ -818,6 +902,9 @@ static inline void recurse_lookups (context_t *c,
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
+				 const USHORT input[], /* Array of input values--start with second glyph */
+				 match_func_t match_func,
+				 const void *match_data,
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
@@ -834,6 +921,11 @@ static inline bool apply_lookup (hb_apply_context_t *c,
    * and we jump out of it.  Not entirely disastrous.  So we don't check
    * for reverse lookup here.
    */
+
+  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
+  skippy_iter.set_match_func (match_func, match_data, input);
+  uint8_t syllable = c->buffer->cur().syllable();
+
   unsigned int i = 0;
   if (lookupCount && 0 == lookupRecord->sequenceIndex)
   {
@@ -849,6 +941,13 @@ static inline bool apply_lookup (hb_apply_context_t *c,
 
     if (!done)
       goto not_applied;
+    else
+    {
+      /* Reinitialize iterator. */
+      hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
+      tmp.set_syllable (syllable);
+      skippy_iter = tmp;
+    }
   }
   else
   {
@@ -857,7 +956,6 @@ static inline bool apply_lookup (hb_apply_context_t *c,
     c->buffer->next_glyph ();
     i++;
   }
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx - 1, count - i);
   while (i < count)
   {
     if (!skippy_iter.next ()) return TRACE_RETURN (true);
@@ -882,6 +980,7 @@ static inline bool apply_lookup (hb_apply_context_t *c,
       {
         /* Reinitialize iterator. */
 	hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
+	tmp.set_syllable (syllable);
 	skippy_iter = tmp;
       }
     }
@@ -969,7 +1068,8 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data)
       && apply_lookup (c,
-		       inputCount,
+		       inputCount, input,
+		       lookup_context.funcs.match, lookup_context.match_data,
 		       lookupCount, lookupRecord);
 }
 
@@ -1505,7 +1605,8 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
 			  lookup_context.funcs.match, lookup_context.match_data[2],
 			  lookahead_offset)
       && apply_lookup (c,
-		       inputCount,
+		       inputCount, input,
+		       lookup_context.funcs.match, lookup_context.match_data[1],
 		       lookupCount, lookupRecord);
 }
 
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index b550fa8..cc4b590 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -43,6 +43,51 @@
 #define syllable()		var1.u8[2] /* GSUB/GPOS shaping boundaries */
 #define lig_props()		var1.u8[3] /* GSUB/GPOS ligature tracking */
 
+/* buffer var allocations, used during the entire shaping process */
+#define unicode_props0()	var2.u8[0]
+#define unicode_props1()	var2.u8[1]
+
+
+inline void
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+{
+  info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
+			   (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0) |
+			   (info->codepoint == 0x200C ? 0x40 : 0);
+  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
+}
+
+inline hb_unicode_general_category_t
+_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
+{
+  return (hb_unicode_general_category_t) (info->unicode_props0() & 0x3F);
+}
+
+inline void
+_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class)
+{
+  info->unicode_props1() = modified_class;
+}
+
+inline unsigned int
+_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
+{
+  return info->unicode_props1();
+}
+
+inline hb_bool_t
+_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & 0x80);
+}
+
+inline hb_bool_t
+_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & 0x40);
+}
+
+
 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 
 /*
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 74c5b19..9599f8e 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -33,10 +33,6 @@
 
 
 
-/* buffer var allocations, used during the entire shaping process */
-#define unicode_props0()	var2.u8[0]
-#define unicode_props1()	var2.u8[1]
-
 
 
 struct hb_ot_shape_plan_t
@@ -89,44 +85,4 @@ struct hb_ot_shape_planner_t
 };
 
 
-
-inline void
-_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
-{
-  info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
-			   (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0) |
-			   (info->codepoint == 0x200C ? 0x40 : 0);
-  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
-}
-
-inline hb_unicode_general_category_t
-_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
-{
-  return (hb_unicode_general_category_t) (info->unicode_props0() & 0x3F);
-}
-
-inline void
-_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class)
-{
-  info->unicode_props1() = modified_class;
-}
-
-inline unsigned int
-_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
-{
-  return info->unicode_props1();
-}
-
-inline hb_bool_t
-_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
-{
-  return !!(info->unicode_props0() & 0x80);
-}
-
-inline hb_bool_t
-_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
-{
-  return !!(info->unicode_props0() & 0x40);
-}
-
 #endif /* HB_OT_SHAPE_PRIVATE_HH */
commit ec5448667b30ad662401c2b4f5fc0da524c013fd
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 11:25:10 2013 -0500

    Add hb_ot_map_feature_flags_t
    
    Code cleanup.  No (intended) functional change.

diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 344e914..663b7d1 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -145,6 +145,27 @@ struct hb_ot_map_t
   hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */
 };
 
+enum hb_ot_map_feature_flags_t {
+  F_NONE		= 0x0000,
+  F_GLOBAL		= 0x0001,
+  F_HAS_FALLBACK	= 0x0002
+};
+inline hb_ot_map_feature_flags_t
+operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
+inline hb_ot_map_feature_flags_t
+operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
+inline hb_ot_map_feature_flags_t
+operator ~ (hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
+inline hb_ot_map_feature_flags_t&
+operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
+{ l = l | r; return l; }
+inline hb_ot_map_feature_flags_t&
+operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
+{ l = l & r; return l; }
+
 
 struct hb_ot_map_builder_t
 {
@@ -153,10 +174,11 @@ struct hb_ot_map_builder_t
   HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
 				   const hb_segment_properties_t *props_);
 
-  HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback = false);
+  HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value,
+				hb_ot_map_feature_flags_t flags);
 
   inline void add_global_bool_feature (hb_tag_t tag)
-  { add_feature (tag, 1, true, false); }
+  { add_feature (tag, 1, F_GLOBAL); }
 
   inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
   { add_pause (0, pause_func); }
@@ -177,8 +199,7 @@ struct hb_ot_map_builder_t
     hb_tag_t tag;
     unsigned int seq; /* sequence#, used for stable sorting only */
     unsigned int max_value;
-    bool global; /* whether the feature applies value to every glyph in the buffer */
-    bool has_fallback; /* whether to allocate bits even if feature not found */
+    hb_ot_map_feature_flags_t flags;
     unsigned int default_value; /* for non-global features, what should the unset glyphs take */
     unsigned int stage[2]; /* GSUB/GPOS */
 
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 62f7904..7848186 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -84,16 +84,16 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
   }
 }
 
-void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback)
+void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
+				       hb_ot_map_feature_flags_t flags)
 {
   feature_info_t *info = feature_infos.push();
   if (unlikely (!info)) return;
   info->tag = tag;
   info->seq = feature_infos.len;
   info->max_value = value;
-  info->global = global;
-  info->has_fallback = has_fallback;
-  info->default_value = global ? value : 0;
+  info->flags = flags;
+  info->default_value = (flags & F_GLOBAL) ? value : 0;
   info->stage[0] = current_stage[0];
   info->stage[1] = current_stage[1];
 }
@@ -176,15 +176,15 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
       if (feature_infos[i].tag != feature_infos[j].tag)
 	feature_infos[++j] = feature_infos[i];
       else {
-	if (feature_infos[i].global) {
-	  feature_infos[j].global = true;
+	if (feature_infos[i].flags & F_GLOBAL) {
+	  feature_infos[j].flags |= F_GLOBAL;
 	  feature_infos[j].max_value = feature_infos[i].max_value;
 	  feature_infos[j].default_value = feature_infos[i].default_value;
 	} else {
-	  feature_infos[j].global = false;
+	  feature_infos[j].flags &= ~F_GLOBAL;
 	  feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
 	}
-	feature_infos[j].has_fallback = feature_infos[j].has_fallback || feature_infos[i].has_fallback;
+	feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
 	feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
 	feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
 	/* Inherit default_value from j */
@@ -200,7 +200,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 
     unsigned int bits_needed;
 
-    if (info->global && info->max_value == 1)
+    if ((info->flags & F_GLOBAL) && info->max_value == 1)
       /* Uses the global bit */
       bits_needed = 0;
     else
@@ -219,7 +219,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 						   language_index[table_index],
 						   info->tag,
 						   &feature_index[table_index]);
-    if (!found && !info->has_fallback)
+    if (!found && !(info->flags & F_HAS_FALLBACK))
       continue;
 
 
@@ -232,7 +232,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
     map->index[1] = feature_index[1];
     map->stage[0] = info->stage[0];
     map->stage[1] = info->stage[1];
-    if (info->global && info->max_value == 1) {
+    if ((info->flags & F_GLOBAL) && info->max_value == 1) {
       /* Uses the global bit */
       map->shift = 0;
       map->mask = 1;
@@ -240,7 +240,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
       map->shift = next_bit;
       map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
       next_bit += bits_needed;
-      if (info->global)
+      if ((info->flags & F_GLOBAL))
 	m.global_mask |= (info->default_value << map->shift) & map->mask;
     }
     map->_1_mask = (1 << map->shift) & map->mask;
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 2c23da5..3a69f06 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -184,11 +184,11 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
   map->add_gsub_pause (NULL);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
-    map->add_feature (arabic_features[i], 1, false, i < 4); /* The first four features have fallback. */
+    map->add_feature (arabic_features[i], 1, i < 4 ? F_HAS_FALLBACK : F_NONE); /* The first four features have fallback. */
 
   map->add_gsub_pause (NULL);
 
-  map->add_feature (HB_TAG('r','l','i','g'), 1, true, true);
+  map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
   map->add_gsub_pause (arabic_fallback_shape);
 
   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index bf82615..b60e310 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -329,7 +329,7 @@ static const indic_config_t indic_configs[] =
 
 struct feature_list_t {
   hb_tag_t tag;
-  hb_bool_t is_global;
+  hb_ot_map_feature_flags_t flags;
 };
 
 static const feature_list_t
@@ -339,32 +339,32 @@ indic_features[] =
    * Basic features.
    * These features are applied in order, one at a time, after initial_reordering.
    */
-  {HB_TAG('n','u','k','t'), true},
-  {HB_TAG('a','k','h','n'), true},
-  {HB_TAG('r','p','h','f'), false},
-  {HB_TAG('r','k','r','f'), true},
-  {HB_TAG('p','r','e','f'), false},
-  {HB_TAG('b','l','w','f'), false},
-  {HB_TAG('h','a','l','f'), false},
-  {HB_TAG('a','b','v','f'), false},
-  {HB_TAG('p','s','t','f'), false},
-  {HB_TAG('c','f','a','r'), false},
-  {HB_TAG('v','a','t','u'), true},
-  {HB_TAG('c','j','c','t'), true},
+  {HB_TAG('n','u','k','t'), F_GLOBAL},
+  {HB_TAG('a','k','h','n'), F_GLOBAL},
+  {HB_TAG('r','p','h','f'), F_NONE},
+  {HB_TAG('r','k','r','f'), F_GLOBAL},
+  {HB_TAG('p','r','e','f'), F_NONE},
+  {HB_TAG('b','l','w','f'), F_NONE},
+  {HB_TAG('h','a','l','f'), F_NONE},
+  {HB_TAG('a','b','v','f'), F_NONE},
+  {HB_TAG('p','s','t','f'), F_NONE},
+  {HB_TAG('c','f','a','r'), F_NONE},
+  {HB_TAG('v','a','t','u'), F_GLOBAL},
+  {HB_TAG('c','j','c','t'), F_GLOBAL},
   /*
    * Other features.
    * These features are applied all at once, after final_reordering.
    */
-  {HB_TAG('i','n','i','t'), false},
-  {HB_TAG('p','r','e','s'), true},
-  {HB_TAG('a','b','v','s'), true},
-  {HB_TAG('b','l','w','s'), true},
-  {HB_TAG('p','s','t','s'), true},
-  {HB_TAG('h','a','l','n'), true},
+  {HB_TAG('i','n','i','t'), F_NONE},
+  {HB_TAG('p','r','e','s'), F_GLOBAL},
+  {HB_TAG('a','b','v','s'), F_GLOBAL},
+  {HB_TAG('b','l','w','s'), F_GLOBAL},
+  {HB_TAG('p','s','t','s'), F_GLOBAL},
+  {HB_TAG('h','a','l','n'), F_GLOBAL},
   /* Positioning features, though we don't care about the types. */
-  {HB_TAG('d','i','s','t'), true},
-  {HB_TAG('a','b','v','m'), true},
-  {HB_TAG('b','l','w','m'), true},
+  {HB_TAG('d','i','s','t'), F_GLOBAL},
+  {HB_TAG('a','b','v','m'), F_GLOBAL},
+  {HB_TAG('b','l','w','m'), F_GLOBAL},
 };
 
 /*
@@ -428,12 +428,12 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < INDIC_BASIC_FEATURES; i++) {
-    map->add_feature (indic_features[i].tag, 1, indic_features[i].is_global);
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags);
     map->add_gsub_pause (NULL);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < INDIC_NUM_FEATURES; i++) {
-    map->add_feature (indic_features[i].tag, 1, indic_features[i].is_global);
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags);
   }
 }
 
@@ -442,9 +442,9 @@ override_features_indic (hb_ot_shape_planner_t *plan)
 {
   /* Uniscribe does not apply 'kern'. */
   if (hb_options ().uniscribe_bug_compatible)
-    plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true);
+    plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
 
-  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true);
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
 }
 
 
@@ -532,7 +532,8 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
   indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'));
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
-    indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag);
+    indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
+				 0 : plan->map.get_1_mask (indic_features[i].tag);
 
   return indic_plan;
 }
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index 3f63770..53a9ab4 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -119,7 +119,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
 static void
 override_features_myanmar (hb_ot_shape_planner_t *plan)
 {
-  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true);
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
 
   /*
    * Note:
@@ -130,7 +130,7 @@ override_features_myanmar (hb_ot_shape_planner_t *plan)
    * 'mkmk' however.
    */
   if (hb_options ().uniscribe_bug_compatible)
-    plan->map.add_feature (HB_TAG('m','a','r','k'), 0, true);
+    plan->map.add_feature (HB_TAG('m','a','r','k'), 0, F_GLOBAL);
 }
 
 
diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc
index c9bce6c..387a4a1 100644
--- a/src/hb-ot-shape-complex-sea.cc
+++ b/src/hb-ot-shape-complex-sea.cc
@@ -121,7 +121,7 @@ collect_features_sea (hb_ot_shape_planner_t *plan)
 static void
 override_features_sea (hb_ot_shape_planner_t *plan)
 {
-  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true);
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
 }
 
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 2a1bfb7..2d78a18 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -88,7 +88,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
       break;
     case HB_DIRECTION_RTL:
       map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
-      map->add_feature (HB_TAG ('r','t','l','m'), 1, false);
+      map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
       break;
     case HB_DIRECTION_TTB:
     case HB_DIRECTION_BTT:
@@ -120,7 +120,9 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 
   for (unsigned int i = 0; i < num_user_features; i++) {
     const hb_feature_t *feature = &user_features[i];
-    map->add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
+    map->add_feature (feature->tag, feature->value,
+		      (feature->start == 0 && feature->end == (unsigned int) -1) ?
+		       F_GLOBAL : F_NONE);
   }
 }
 
commit e7ffcfafb1108801ac504f18f820e497226bf07f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 11:05:56 2013 -0500

    Clean-up add_bool_feature

diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index b140207..344e914 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -155,8 +155,8 @@ struct hb_ot_map_builder_t
 
   HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback = false);
 
-  inline void add_bool_feature (hb_tag_t tag, bool global = true, bool has_fallback = false)
-  { add_feature (tag, 1, global, has_fallback); }
+  inline void add_global_bool_feature (hb_tag_t tag)
+  { add_feature (tag, 1, true, false); }
 
   inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
   { add_pause (0, pause_func); }
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 3374cfc..2c23da5 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -178,25 +178,25 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
    * TODO: Add test cases for these two.
    */
 
-  map->add_bool_feature (HB_TAG('c','c','m','p'));
-  map->add_bool_feature (HB_TAG('l','o','c','l'));
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
 
   map->add_gsub_pause (NULL);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
-    map->add_bool_feature (arabic_features[i], false, i < 4); /* The first four features have fallback. */
+    map->add_feature (arabic_features[i], 1, false, i < 4); /* The first four features have fallback. */
 
   map->add_gsub_pause (NULL);
 
-  map->add_bool_feature (HB_TAG('r','l','i','g'), true, true);
+  map->add_feature (HB_TAG('r','l','i','g'), 1, true, true);
   map->add_gsub_pause (arabic_fallback_shape);
 
-  map->add_bool_feature (HB_TAG('c','a','l','t'));
+  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
   map->add_gsub_pause (NULL);
 
-  map->add_bool_feature (HB_TAG('c','s','w','h'));
-  map->add_bool_feature (HB_TAG('d','l','i','g'));
-  map->add_bool_feature (HB_TAG('m','s','e','t'));
+  map->add_global_bool_feature (HB_TAG('c','s','w','h'));
+  map->add_global_bool_feature (HB_TAG('d','l','i','g'));
+  map->add_global_bool_feature (HB_TAG('m','s','e','t'));
 }
 
 #include "hb-ot-shape-complex-arabic-fallback.hh"
diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc
index d406f8c..fad57f6 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/src/hb-ot-shape-complex-default.cc
@@ -68,7 +68,7 @@ collect_features_default (hb_ot_shape_planner_t *plan)
   }
 
   for (; script_features && *script_features; script_features++)
-    plan->map.add_bool_feature (*script_features);
+    plan->map.add_global_bool_feature (*script_features);
 }
 
 static hb_ot_shape_normalization_mode_t
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 4491daa..bf82615 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -419,21 +419,21 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables);
 
-  map->add_bool_feature (HB_TAG('l','o','c','l'));
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
   /* The Indic specs do not require ccmp, but we apply it here since if
    * there is a use of it, it's typically at the beginning. */
-  map->add_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
 
 
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < INDIC_BASIC_FEATURES; i++) {
-    map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global);
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].is_global);
     map->add_gsub_pause (NULL);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < INDIC_NUM_FEATURES; i++) {
-    map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global);
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].is_global);
   }
 }
 
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index a115064..3f63770 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -98,21 +98,21 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables);
 
-  map->add_bool_feature (HB_TAG('l','o','c','l'));
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
   /* The Indic specs do not require ccmp, but we apply it here since if
    * there is a use of it, it's typically at the beginning. */
-  map->add_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
 
 
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < MYANMAR_BASIC_FEATURES; i++) {
-    map->add_bool_feature (myanmar_features[i]);
+    map->add_global_bool_feature (myanmar_features[i]);
     map->add_gsub_pause (NULL);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < MYANMAR_NUM_FEATURES; i++) {
-    map->add_bool_feature (myanmar_features[i]);
+    map->add_global_bool_feature (myanmar_features[i]);
   }
 }
 
diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc
index cfd0baa..c9bce6c 100644
--- a/src/hb-ot-shape-complex-sea.cc
+++ b/src/hb-ot-shape-complex-sea.cc
@@ -100,21 +100,21 @@ collect_features_sea (hb_ot_shape_planner_t *plan)
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables);
 
-  map->add_bool_feature (HB_TAG('l','o','c','l'));
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
   /* The Indic specs do not require ccmp, but we apply it here since if
    * there is a use of it, it's typically at the beginning. */
-  map->add_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
 
 
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < SEA_BASIC_FEATURES; i++) {
-    map->add_bool_feature (sea_features[i]);
+    map->add_global_bool_feature (sea_features[i]);
     map->add_gsub_pause (NULL);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < SEA_NUM_FEATURES; i++) {
-    map->add_bool_feature (sea_features[i]);
+    map->add_global_bool_feature (sea_features[i]);
   }
 }
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index d529223..2a1bfb7 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -83,12 +83,12 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 
   switch (props->direction) {
     case HB_DIRECTION_LTR:
-      map->add_bool_feature (HB_TAG ('l','t','r','a'));
-      map->add_bool_feature (HB_TAG ('l','t','r','m'));
+      map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
+      map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
       break;
     case HB_DIRECTION_RTL:
-      map->add_bool_feature (HB_TAG ('r','t','l','a'));
-      map->add_bool_feature (HB_TAG ('r','t','l','m'), false);
+      map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
+      map->add_feature (HB_TAG ('r','t','l','m'), 1, false);
       break;
     case HB_DIRECTION_TTB:
     case HB_DIRECTION_BTT:
@@ -100,7 +100,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 #define ADD_FEATURES(array) \
   HB_STMT_START { \
     for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \
-      map->add_bool_feature (array[i]); \
+      map->add_global_bool_feature (array[i]); \
   } HB_STMT_END
 
   if (planner->shaper->collect_features)
commit e7562f53fe6a506d2c6d59d6688e4fa468bba462
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 11:05:36 2013 -0500

    Fix compile warnings for ragel-generated machines

diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index 11115c9..f9f07d8 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -103,7 +103,7 @@ main := |*
 static void
 find_syllables (hb_buffer_t *buffer)
 {
-  unsigned int p, pe, eof, ts HB_UNUSED, te, act;
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   %%{
diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl
index 949fde6..51d42dd 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.rl
+++ b/src/hb-ot-shape-complex-myanmar-machine.rl
@@ -102,7 +102,7 @@ main := |*
 static void
 find_syllables (hb_buffer_t *buffer)
 {
-  unsigned int p, pe, eof, ts HB_UNUSED, te, act;
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   %%{
diff --git a/src/hb-ot-shape-complex-sea-machine.rl b/src/hb-ot-shape-complex-sea-machine.rl
index 434be6b..46140fc 100644
--- a/src/hb-ot-shape-complex-sea-machine.rl
+++ b/src/hb-ot-shape-complex-sea-machine.rl
@@ -79,7 +79,7 @@ main := |*
 static void
 find_syllables (hb_buffer_t *buffer)
 {
-  unsigned int p, pe, eof, ts HB_UNUSED, te, act;
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   %%{
commit 4e51df73a337f7232a7dfa85df78a4f19b24771b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 07:42:42 2013 -0500

    [OTLayout] Remove unused function

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 61814ad..07989fa 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -447,11 +447,6 @@ struct hb_apply_context_t
   }
 
 
-  inline bool should_skip_current_glyph (void) const
-  {
-    return should_skip (&buffer->cur(), lookup_props);
-  }
-
   inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
   {
     if (likely (has_glyph_classes))
commit 8820bb235b1f63e4d93c8a2f5c08b44d89e06b78
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 07:41:03 2013 -0500

    [OTLayout] Port apply_lookup to skippy_iter

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 53be8f8..61814ad 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -839,19 +839,35 @@ static inline bool apply_lookup (hb_apply_context_t *c,
    * and we jump out of it.  Not entirely disastrous.  So we don't check
    * for reverse lookup here.
    */
-  for (unsigned int i = 0; i < count; /* NOP */)
+  unsigned int i = 0;
+  if (lookupCount && 0 == lookupRecord->sequenceIndex)
   {
-    if (unlikely (c->buffer->idx == end))
-      return TRACE_RETURN (true);
+    unsigned int old_pos = c->buffer->idx;
 
-    if (i)
-      while (c->should_skip_current_glyph ())
-      {
-	/* No lookup applied for this index */
-	c->buffer->next_glyph ();
-	if (unlikely (c->buffer->idx == end))
-	  return TRACE_RETURN (true);
-      }
+    /* Apply a lookup */
+    bool done = c->recurse (lookupRecord->lookupListIndex);
+
+    lookupRecord++;
+    lookupCount--;
+    /* Err, this is wrong if the lookup jumped over some glyphs */
+    i += c->buffer->idx - old_pos;
+
+    if (!done)
+      goto not_applied;
+  }
+  else
+  {
+  not_applied:
+    /* No lookup applied for this index */
+    c->buffer->next_glyph ();
+    i++;
+  }
+  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx - 1, count - i);
+  while (i < count)
+  {
+    if (!skippy_iter.next ()) return TRACE_RETURN (true);
+    while (c->buffer->idx < skippy_iter.idx)
+      c->buffer->next_glyph ();
 
     if (lookupCount && i == lookupRecord->sequenceIndex)
     {
@@ -864,15 +880,19 @@ static inline bool apply_lookup (hb_apply_context_t *c,
       lookupCount--;
       /* Err, this is wrong if the lookup jumped over some glyphs */
       i += c->buffer->idx - old_pos;
-      if (unlikely (c->buffer->idx == end))
-	return TRACE_RETURN (true);
 
       if (!done)
-	goto not_applied;
+	goto not_applied2;
+      else
+      {
+        /* Reinitialize iterator. */
+	hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
+	skippy_iter = tmp;
+      }
     }
     else
     {
-    not_applied:
+    not_applied2:
       /* No lookup applied for this index */
       c->buffer->next_glyph ();
       i++;
commit dfca269f069dae2f99990dac24da15d316eccb9f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 07:20:52 2013 -0500

    [OTLayout] Port ligate_input to skippy_iter

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index eabbe45..53be8f8 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -705,13 +705,16 @@ static inline void ligate_input (hb_apply_context_t *c,
   unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
   unsigned int components_so_far = last_num_components;
 
+  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
+
   if (!is_mark_ligature)
     set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
   c->replace_glyph (lig_glyph, klass);
 
   for (unsigned int i = 1; i < count; i++)
   {
-    while (c->should_skip_current_glyph ())
+    if (!skippy_iter.next ()) return;
+    while (c->buffer->idx < skippy_iter.idx)
     {
       if (!is_mark_ligature) {
 	unsigned int new_lig_comp = components_so_far - last_num_components +
commit 7e53415c2d8859e8b5948a2edb38c39a8f78b825
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Feb 14 06:24:30 2013 -0500

    [OTLayout] Minor fix for apply_lookup()
    
    Should NOT change behavior, since first glyph is a match.

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 752957b..eabbe45 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -840,13 +840,15 @@ static inline bool apply_lookup (hb_apply_context_t *c,
   {
     if (unlikely (c->buffer->idx == end))
       return TRACE_RETURN (true);
-    while (c->should_skip_current_glyph ())
-    {
-      /* No lookup applied for this index */
-      c->buffer->next_glyph ();
-      if (unlikely (c->buffer->idx == end))
-	return TRACE_RETURN (true);
-    }
+
+    if (i)
+      while (c->should_skip_current_glyph ())
+      {
+	/* No lookup applied for this index */
+	c->buffer->next_glyph ();
+	if (unlikely (c->buffer->idx == end))
+	  return TRACE_RETURN (true);
+      }
 
     if (lookupCount && i == lookupRecord->sequenceIndex)
     {
commit 6880f7e19d44c50e45ecb86d26381aad956d9acb
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 12:17:25 2013 -0500

    [OTLayout] Make table type known to apply context

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 04b29eb..752957b 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -255,6 +255,7 @@ struct hb_apply_context_t
     return ret;
   }
 
+  unsigned int table_index; /* GSUB/GPOS */
   hb_font_t *font;
   hb_face_t *face;
   hb_buffer_t *buffer;
@@ -268,9 +269,11 @@ struct hb_apply_context_t
   unsigned int debug_depth;
 
 
-  hb_apply_context_t (hb_font_t *font_,
+  hb_apply_context_t (unsigned int table_index_,
+		      hb_font_t *font_,
 		      hb_buffer_t *buffer_,
 		      hb_mask_t lookup_mask_) :
+			table_index (table_index_),
 			font (font_), face (font->face), buffer (buffer_),
 			direction (buffer_->props.direction),
 			lookup_mask (lookup_mask_),
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 291ff9a..62988ab 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -670,7 +670,7 @@ hb_ot_layout_substitute_lookup (hb_font_t    *font,
 {
   if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
 
-  OT::hb_apply_context_t c (font, buffer, mask);
+  OT::hb_apply_context_t c (0, font, buffer, mask);
 
   const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);
 
@@ -719,7 +719,7 @@ hb_ot_layout_position_lookup (hb_font_t    *font,
 {
   if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
 
-  OT::hb_apply_context_t c (font, buffer, mask);
+  OT::hb_apply_context_t c (1, font, buffer, mask);
 
   const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);
 
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index 4fcd0a2..c0dbff0 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -244,7 +244,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
 {
   for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
     if (fallback_plan->lookup_array[i]) {
-      OT::hb_apply_context_t c (font, buffer, fallback_plan->mask_array[i]);
+      OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i]);
       fallback_plan->lookup_array[i]->apply_string (&c, &fallback_plan->digest_array[i]);
     }
 }
commit 2c7d0b6b80d412de3fddd443ed1a485ea1cbb03c
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 12:10:08 2013 -0500

    [OTLayou] Unbreak backtrack matching
    
    Was introduced by 28b9d502bb69a8045818d5f6113ded9c59a56bd7.

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index a9824eb..04b29eb 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -340,15 +340,14 @@ struct hb_apply_context_t
     inline skipping_backward_iterator_t (hb_apply_context_t *c_,
 					 unsigned int start_index_,
 					 unsigned int num_items_,
-					 hb_mask_t mask_ = 0,
-					 bool match_syllable_ = true)
+					 bool context_match = false)
     {
       c = c_;
       lookup_props = c->lookup_props;
       idx = start_index_;
       num_items = num_items_;
-      mask = mask_ ? mask_ : c->lookup_mask;
-      syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
+      mask = context_match ? -1 : c->lookup_mask;
+      syllable = context_match ? 0 : c->buffer->cur().syllable ();
     }
     inline void set_lookup_props (unsigned int lookup_props_)
     {
commit c074ebc466dcc9bcc0d8a5dd7e942dea974ff718
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 11:22:42 2013 -0500

    [OTLayout] Minor refactoring

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 91bdcc4..71e0aee 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1029,8 +1029,9 @@ struct MarkBasePosFormat1
 
     /* now we search backwards for a non-mark glyph */
     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     do {
-      if (!skippy_iter.prev (LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
+      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
       if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break;
       skippy_iter.reject ();
@@ -1132,7 +1133,8 @@ struct MarkLigPosFormat1
 
     /* now we search backwards for a non-mark glyph */
     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (!skippy_iter.prev (LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
 
     /* The following assertion is too strong, so we've disabled it. */
     if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
@@ -1247,7 +1249,8 @@ struct MarkMarkPosFormat1
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (!skippy_iter.prev (c->lookup_props & ~LookupFlag::IgnoreFlags)) return TRACE_RETURN (false);
+    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
+    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
 
     if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) { return TRACE_RETURN (false); }
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index bbbb9c1..a9824eb 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -281,9 +281,9 @@ struct hb_apply_context_t
 			has_glyph_classes (gdef.has_glyph_classes ()),
 			debug_depth (0) {}
 
-  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
-  void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
-  void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
+  inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+  inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+  inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
 
   struct skipping_forward_iterator_t
   {
@@ -293,12 +293,17 @@ struct hb_apply_context_t
 					bool context_match = false)
     {
       c = c_;
+      lookup_props = c->lookup_props;
       idx = start_index_;
       num_items = num_items_;
       mask = context_match ? -1 : c->lookup_mask;
       syllable = context_match ? 0 : c->buffer->cur().syllable ();
       end = c->buffer->len;
     }
+    inline void set_lookup_props (unsigned int lookup_props_)
+    {
+      lookup_props = lookup_props_;
+    }
     inline bool has_no_chance (void) const
     {
       return unlikely (num_items && idx + num_items >= end);
@@ -307,7 +312,7 @@ struct hb_apply_context_t
     {
       num_items++;
     }
-    inline bool next (unsigned int  lookup_props)
+    inline bool next (void)
     {
       assert (num_items > 0);
       do
@@ -319,14 +324,11 @@ struct hb_apply_context_t
       num_items--;
       return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
     }
-    inline bool next (void)
-    {
-      return next (c->lookup_props);
-    }
 
     unsigned int idx;
     protected:
     hb_apply_context_t *c;
+    unsigned int lookup_props;
     unsigned int num_items;
     hb_mask_t mask;
     uint8_t syllable;
@@ -342,11 +344,16 @@ struct hb_apply_context_t
 					 bool match_syllable_ = true)
     {
       c = c_;
+      lookup_props = c->lookup_props;
       idx = start_index_;
       num_items = num_items_;
       mask = mask_ ? mask_ : c->lookup_mask;
       syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
     }
+    inline void set_lookup_props (unsigned int lookup_props_)
+    {
+      lookup_props = lookup_props_;
+    }
     inline bool has_no_chance (void) const
     {
       return unlikely (idx < num_items);
@@ -355,7 +362,7 @@ struct hb_apply_context_t
     {
       num_items++;
     }
-    inline bool prev (unsigned int  lookup_props)
+    inline bool prev (void)
     {
       assert (num_items > 0);
       do
@@ -367,14 +374,11 @@ struct hb_apply_context_t
       num_items--;
       return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
     }
-    inline bool prev (void)
-    {
-      return prev (c->lookup_props);
-    }
 
     unsigned int idx;
     protected:
     hb_apply_context_t *c;
+    unsigned int lookup_props;
     unsigned int num_items;
     hb_mask_t mask;
     uint8_t syllable;
commit 407fc12466ef460d0edf11b89f0d04c4d724875f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 11:13:06 2013 -0500

    [OTLayout] Remove bogus caching of glyph property

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 59d818e..91bdcc4 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -878,7 +878,7 @@ struct CursivePosFormat1
     TRACE_APPLY (this);
 
     /* We don't handle mark glyphs here. */
-    if (c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
+    if (c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
 
     hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
@@ -1028,17 +1028,16 @@ struct MarkBasePosFormat1
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
-    unsigned int property;
     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     do {
-      if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
+      if (!skippy_iter.prev (LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
       if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break;
       skippy_iter.reject ();
     } while (1);
 
     /* The following assertion is too strong, so we've disabled it. */
-    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
+    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
 
     unsigned int base_index = (this+baseCoverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint);
     if (base_index == NOT_COVERED) return TRACE_RETURN (false);
@@ -1132,12 +1131,11 @@ struct MarkLigPosFormat1
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
-    unsigned int property;
     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
+    if (!skippy_iter.prev (LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
 
     /* The following assertion is too strong, so we've disabled it. */
-    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
+    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
 
     unsigned int j = skippy_iter.idx;
     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (c->buffer->info[j].codepoint);
@@ -1248,11 +1246,10 @@ struct MarkMarkPosFormat1
     if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    unsigned int property;
     hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (!skippy_iter.prev (&property, c->lookup_props & ~LookupFlag::IgnoreFlags)) return TRACE_RETURN (false);
+    if (!skippy_iter.prev (c->lookup_props & ~LookupFlag::IgnoreFlags)) return TRACE_RETURN (false);
 
-    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) return TRACE_RETURN (false);
+    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) { return TRACE_RETURN (false); }
 
     unsigned int j = skippy_iter.idx;
 
@@ -1474,7 +1471,7 @@ struct PosLookup : Lookup
   inline bool apply_once (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
+    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
       return TRACE_RETURN (false);
     return TRACE_RETURN (process (c));
   }
@@ -1629,11 +1626,9 @@ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int l
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
-  unsigned int saved_property = c->property;
   c->set_lookup (l);
   bool ret = l.apply_once (c);
   c->lookup_props = saved_lookup_props;
-  c->property = saved_property;
   return ret;
 }
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 2642acb..ec549a8 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -272,7 +272,8 @@ struct Sequence
     TRACE_APPLY (this);
     if (unlikely (!substitute.len)) return TRACE_RETURN (false);
 
-    unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+    unsigned int klass = c->buffer->cur().glyph_props() &
+			 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++) {
       set_lig_props_for_component (c->buffer->cur(), i);
@@ -1193,7 +1194,7 @@ struct SubstLookup : Lookup
   inline bool apply_once (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
+    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
       return TRACE_RETURN (false);
     return TRACE_RETURN (process (c));
   }
@@ -1399,11 +1400,9 @@ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
-  unsigned int saved_property = c->property;
   c->set_lookup (l);
   bool ret = l.apply_once (c);
   c->lookup_props = saved_lookup_props;
-  c->property = saved_property;
   return ret;
 }
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index cb0eaa5..bbbb9c1 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -263,7 +263,6 @@ struct hb_apply_context_t
   recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int lookup_props;
-  unsigned int property; /* propety of first glyph */
   const GDEF &gdef;
   bool has_glyph_classes;
   unsigned int debug_depth;
@@ -277,7 +276,7 @@ struct hb_apply_context_t
 			lookup_mask (lookup_mask_),
 			recurse_func (NULL),
 			nesting_level_left (MAX_NESTING_LEVEL),
-			lookup_props (0), property (0),
+			lookup_props (0),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
 			has_glyph_classes (gdef.has_glyph_classes ()),
 			debug_depth (0) {}
@@ -308,8 +307,7 @@ struct hb_apply_context_t
     {
       num_items++;
     }
-    inline bool next (unsigned int *property_out,
-		      unsigned int  lookup_props)
+    inline bool next (unsigned int  lookup_props)
     {
       assert (num_items > 0);
       do
@@ -317,13 +315,13 @@ struct hb_apply_context_t
 	if (has_no_chance ())
 	  return false;
 	idx++;
-      } while (c->should_skip (&c->buffer->info[idx], lookup_props, property_out));
+      } while (c->should_skip (&c->buffer->info[idx], lookup_props));
       num_items--;
       return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
     }
-    inline bool next (unsigned int *property_out = NULL)
+    inline bool next (void)
     {
-      return next (property_out, c->lookup_props);
+      return next (c->lookup_props);
     }
 
     unsigned int idx;
@@ -357,8 +355,7 @@ struct hb_apply_context_t
     {
       num_items++;
     }
-    inline bool prev (unsigned int *property_out,
-		      unsigned int  lookup_props)
+    inline bool prev (unsigned int  lookup_props)
     {
       assert (num_items > 0);
       do
@@ -366,13 +363,13 @@ struct hb_apply_context_t
 	if (has_no_chance ())
 	  return false;
 	idx--;
-      } while (c->should_skip (&c->buffer->out_info[idx], lookup_props, property_out));
+      } while (c->should_skip (&c->buffer->out_info[idx], lookup_props));
       num_items--;
       return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
     }
-    inline bool prev (unsigned int *property_out = NULL)
+    inline bool prev (void)
     {
-      return prev (property_out, c->lookup_props);
+      return prev (c->lookup_props);
     }
 
     unsigned int idx;
@@ -423,27 +420,22 @@ struct hb_apply_context_t
 
   inline bool
   check_glyph_property (hb_glyph_info_t *info,
-			unsigned int  lookup_props,
-			unsigned int *property_out) const
+			unsigned int  lookup_props) const
   {
     unsigned int property;
 
     property = info->glyph_props();
-    *property_out = property;
 
     return match_properties (info->codepoint, property, lookup_props);
   }
 
   inline bool
   should_skip (hb_glyph_info_t *info,
-	       unsigned int  lookup_props,
-	       unsigned int *property_out) const
+	       unsigned int  lookup_props) const
   {
     unsigned int property;
 
     property = info->glyph_props();
-    if (property_out)
-      *property_out = property;
 
     return !match_properties (info->codepoint, property, lookup_props);
   }
@@ -451,7 +443,7 @@ struct hb_apply_context_t
 
   inline bool should_skip_current_glyph (void) const
   {
-    return should_skip (&buffer->cur(), lookup_props, NULL);
+    return should_skip (&buffer->cur(), lookup_props);
   }
 
   inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
@@ -618,7 +610,7 @@ static inline bool match_input (hb_apply_context_t *c,
    *   ligate with a conjunct...)
    */
 
-  bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+  bool is_mark_ligature = !!(c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
 
   unsigned int total_component_count = 0;
   total_component_count += get_lig_num_comps (c->buffer->cur());
@@ -628,9 +620,7 @@ static inline bool match_input (hb_apply_context_t *c,
 
   for (unsigned int i = 1; i < count; i++)
   {
-    unsigned int property;
-
-    if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
+    if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return TRACE_RETURN (false);
 
@@ -651,7 +641,7 @@ static inline bool match_input (hb_apply_context_t *c,
 	return TRACE_RETURN (false);
     }
 
-    is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+    is_mark_ligature = is_mark_ligature && (c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
     total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
   }
 
commit 6b1e3502e23c110dd810f854ba021f83baab1548
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 11:02:54 2013 -0500

    Remember ZWNJ
    
    To be used in upcoming changes.

diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 23e80b7..74c5b19 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -94,14 +94,15 @@ inline void
 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 {
   info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
-			   (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0);
+			   (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0) |
+			   (info->codepoint == 0x200C ? 0x40 : 0);
   info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 }
 
 inline hb_unicode_general_category_t
 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 {
-  return (hb_unicode_general_category_t) (info->unicode_props0() & 0x7F);
+  return (hb_unicode_general_category_t) (info->unicode_props0() & 0x3F);
 }
 
 inline void
@@ -122,4 +123,10 @@ _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
   return !!(info->unicode_props0() & 0x80);
 }
 
+inline hb_bool_t
+_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & 0x40);
+}
+
 #endif /* HB_OT_SHAPE_PRIVATE_HH */
commit 1f91c39677f840a1f630696d16d083060069abf5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 09:38:40 2013 -0500

    Indent

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 45b5825..4491daa 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -1304,7 +1304,8 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
       while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
 	new_reph_pos++;
 
-      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) {
+      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+      {
 	/* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
 	if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
 	  new_reph_pos++;
@@ -1356,7 +1357,8 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
       while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
 	new_reph_pos++;
 
-      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) {
+      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+      {
 	/* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
 	if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
 	  new_reph_pos++;
@@ -1455,9 +1457,11 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
 	  }
 
 	  if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
+	  {
 	    /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
 	    if (new_pos < end && is_joiner (info[new_pos]))
 	      new_pos++;
+	  }
 
 	  {
 	    unsigned int old_pos = i;
commit a0cb9f33ee064628debe8e848094dfd661334640
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 09:26:55 2013 -0500

    [Indic] Improve base finding in final_reordering
    
    Fixes 5 Malayalam failures!
    
    MALAYALAM: 1048016 out of 1048334 tests passed. 318 failed (0.0303338%)

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 9304dde..45b5825 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -1186,6 +1186,13 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
         base--;
       break;
     }
+  if (base == end && start < base &&
+      info[base - 1].indic_category() != OT_ZWJ)
+    base--;
+  while (start < base &&
+	 (info[base].indic_category() == OT_H ||
+	  info[base].indic_category() == OT_N))
+    base--;
 
 
   /*   o Reorder matras:
commit 126f39cd16cea87b2696f66467c83a585bd4c2cf
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Feb 13 08:29:21 2013 -0500

    Add more dot-reph tests

diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt
index 01b28dc..d158b8f 100644
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt
+++ b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt
@@ -1,2 +1,12 @@
 ൎക
 ൎക്ക്ര
+ൎന്ന
+ൎഗ്ഗ്രോ
+ൎഗ്രോ
+ൎഗോ
+ൎഗ
+ഗ്ഗ്രോ
+ഗ്ഗ്ര
+ഗ്ഗോ
+ഗ്ഗ
+ഗ്രോ



More information about the HarfBuzz mailing list