[HarfBuzz] harfbuzz-ng: Branch 'master' - 8 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Thu Aug 2 11:27:00 PDT 2012


 src/hb-ot-map-private.hh                 |   26 -
 src/hb-ot-map.cc                         |   28 -
 src/hb-ot-shape-complex-arabic.cc        |   27 -
 src/hb-ot-shape-complex-indic-machine.rl |    4 
 src/hb-ot-shape-complex-indic-private.hh |   16 
 src/hb-ot-shape-complex-indic.cc         |  637 ++++++++++++++++---------------
 src/hb-ot-shape-complex-misc.cc          |   24 -
 src/hb-ot-shape-complex-private.hh       |   48 +-
 src/hb-ot-shape-private.hh               |   45 ++
 src/hb-ot-shape.cc                       |   82 +--
 src/hb-shape-plan.cc                     |    2 
 src/hb-shape.cc                          |    2 
 12 files changed, 504 insertions(+), 437 deletions(-)

New commits:
commit 11b0e20ba42bf0b17133c3e1087732802bb4f230
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 14:21:40 2012 -0400

    [Indic] Add per-script configuration tables
    
    This concludes the Indic shape_plan work.  May do for Arabic also...

diff --git a/src/hb-ot-shape-complex-indic-private.hh b/src/hb-ot-shape-complex-indic-private.hh
index d4cfe0d..719d287 100644
--- a/src/hb-ot-shape-complex-indic-private.hh
+++ b/src/hb-ot-shape-complex-indic-private.hh
@@ -157,8 +157,8 @@ enum indic_matra_category_t {
 
 #define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900))
 #define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980))
-#define IS_GURM(u) (IN_HALF_BLOCK (u, 0x0A00))
-#define IS_GUJA(u) (IN_HALF_BLOCK (u, 0x0A80))
+#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00))
+#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80))
 #define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00))
 #define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80))
 #define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00))
@@ -172,8 +172,8 @@ enum indic_matra_category_t {
 #define MATRA_POS_RIGHT(u)	( \
 				  IS_DEVA(u) ? POS_AFTER_SUB  : \
 				  IS_BENG(u) ? POS_AFTER_POST : \
-				  IS_GURM(u) ? POS_AFTER_POST : \
-				  IS_GUJA(u) ? POS_AFTER_POST : \
+				  IS_GURU(u) ? POS_AFTER_POST : \
+				  IS_GUJR(u) ? POS_AFTER_POST : \
 				  IS_ORYA(u) ? POS_AFTER_POST : \
 				  IS_TAML(u) ? POS_AFTER_POST : \
 				  IS_TELU(u) ? (u <= 0x0C42 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
@@ -185,8 +185,8 @@ enum indic_matra_category_t {
 				)
 #define MATRA_POS_TOP(u)	( /* BENG and MLYM don't have top matras. */ \
 				  IS_DEVA(u) ? POS_AFTER_SUB  : \
-				  IS_GURM(u) ? POS_AFTER_POST : /* Deviate from spec */ \
-				  IS_GUJA(u) ? POS_AFTER_SUB  : \
+				  IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \
+				  IS_GUJR(u) ? POS_AFTER_SUB  : \
 				  IS_ORYA(u) ? POS_AFTER_MAIN : \
 				  IS_TAML(u) ? POS_AFTER_SUB  : \
 				  IS_TELU(u) ? POS_BEFORE_SUB : \
@@ -198,8 +198,8 @@ enum indic_matra_category_t {
 #define MATRA_POS_BOTTOM(u)	( \
 				  IS_DEVA(u) ? POS_AFTER_SUB  : \
 				  IS_BENG(u) ? POS_AFTER_SUB  : \
-				  IS_GURM(u) ? POS_AFTER_POST : \
-				  IS_GUJA(u) ? POS_AFTER_POST : \
+				  IS_GURU(u) ? POS_AFTER_POST : \
+				  IS_GUJR(u) ? POS_AFTER_POST : \
 				  IS_ORYA(u) ? POS_AFTER_SUB  : \
 				  IS_TAML(u) ? POS_AFTER_POST : \
 				  IS_TELU(u) ? POS_BEFORE_SUB : \
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index f48abf4..7dde77d 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -25,23 +25,12 @@
  */
 
 #include "hb-ot-shape-complex-indic-private.hh"
-#include "hb-ot-shape-private.hh"
 #include "hb-ot-layout-private.hh"
 
 
-#define OLD_INDIC_TAG(script) (((hb_tag_t) script) | 0x20000000)
-#define IS_OLD_INDIC_TAG(tag) ( \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_BENGALI)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_DEVANAGARI)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_GUJARATI)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_GURMUKHI)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_KANNADA)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_MALAYALAM)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_ORIYA)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_TAMIL)	|| \
-				(tag) == OLD_INDIC_TAG (HB_SCRIPT_TELUGU)	|| \
-			      0)
-
+/*
+ * Global Indic shaper options.
+ */
 
 struct indic_options_t
 {
@@ -82,6 +71,65 @@ indic_options (void)
 }
 
 
+/*
+ * Indic configurations.  Note that we do not want to keep every single script-specific
+ * behavior in these tables necessarily.  This should mainly be used for per-script
+ * properties that are cheaper keeping here, than in the code.  Ie. if, say, one and
+ * only one script has an exception, that one script can be if'ed directly in the code,
+ * instead of adding a new flag in these structs.
+ */
+
+enum base_position_t {
+  BASE_POS_FIRST,
+  BASE_POS_LAST
+};
+enum reph_position_t {
+  REPH_POS_DEFAULT     = POS_BEFORE_POST,
+
+  REPH_POS_AFTER_MAIN  = POS_AFTER_MAIN,
+  REPH_POS_BEFORE_SUB  = POS_BEFORE_SUB,
+  REPH_POS_AFTER_SUB   = POS_AFTER_SUB,
+  REPH_POS_BEFORE_POST = POS_BEFORE_POST,
+  REPH_POS_AFTER_POST  = POS_AFTER_POST
+};
+enum reph_mode_t {
+  REPH_MODE_IMPLICIT,  /* Reph formed out of initial Ra,H sequence. */
+  REPH_MODE_EXPLICIT,  /* Reph formed out of initial Ra,H,ZWJ sequence. */
+  REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
+  REPH_MODE_LOG_REPHA  /* Encoded Repha character, needs reordering. */
+};
+struct indic_config_t
+{
+  hb_script_t     script;
+  bool            has_old_spec;
+  hb_codepoint_t  virama;
+  base_position_t base_pos;
+  reph_position_t reph_pos;
+  reph_mode_t     reph_mode;
+};
+
+static const indic_config_t indic_configs[] =
+{
+  /* Default.  Should be first. */
+  {HB_SCRIPT_INVALID,	false,     0,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_BENGALI,	true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_GURMUKHI,	true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_GUJARATI,	true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_ORIYA,	true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_TAMIL,	true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_TELUGU,	true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT},
+  {HB_SCRIPT_KANNADA,	true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA},
+  {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT},
+  {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT,    REPH_MODE_VIS_REPHA},
+};
+
+
+
+/*
+ * Indic shaper.
+ */
 
 struct feature_list_t {
   hb_tag_t tag;
@@ -228,7 +276,7 @@ struct indic_shape_plan_t
     hb_codepoint_t glyph = virama_glyph;
     if (unlikely (virama_glyph == (hb_codepoint_t) -1))
     {
-      if (!font->get_glyph (virama, 0, &glyph))
+      if (!config->virama || !font->get_glyph (config->virama, 0, &glyph))
 	glyph = 0;
       /* Technically speaking, the spec says we should apply 'locl' to virama too.
        * Maybe one day... */
@@ -242,10 +290,9 @@ struct indic_shape_plan_t
     return glyph != 0;
   }
 
+  const indic_config_t *config;
 
   bool is_old_spec;
-
-  hb_codepoint_t virama;
   hb_codepoint_t virama_glyph;
 
   would_substitute_feature_t pref;
@@ -262,26 +309,15 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
   if (unlikely (!indic_plan))
     return NULL;
 
-  indic_plan->is_old_spec = IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0));
-  {
-    hb_codepoint_t virama;
-    switch ((int) plan->props.script) {
-      case HB_SCRIPT_DEVANAGARI:virama = 0x094D; break;
-      case HB_SCRIPT_BENGALI:	virama = 0x09CD; break;
-      case HB_SCRIPT_GURMUKHI:	virama = 0x0A4D; break;
-      case HB_SCRIPT_GUJARATI:	virama = 0x0ACD; break;
-      case HB_SCRIPT_ORIYA:	virama = 0x0B4D; break;
-      case HB_SCRIPT_TAMIL:	virama = 0x0BCD; break;
-      case HB_SCRIPT_TELUGU:	virama = 0x0C4D; break;
-      case HB_SCRIPT_KANNADA:	virama = 0x0CCD; break;
-      case HB_SCRIPT_MALAYALAM:	virama = 0x0D4D; break;
-      case HB_SCRIPT_SINHALA:	virama = 0x0DCA; break;
-      case HB_SCRIPT_KHMER:	virama = 0x17D2; break;
-      default:			virama = 0;      break;
+  indic_plan->config = &indic_configs[0];
+  for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
+    if (plan->props.script == indic_configs[i].script) {
+      indic_plan->config = &indic_configs[i];
+      break;
     }
-    indic_plan->virama = virama;
-  }
-  indic_plan->virama_glyph = indic_plan->virama ? (hb_codepoint_t) -1 : 0;
+
+  indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2');
+  indic_plan->virama_glyph = (hb_codepoint_t) -1;
 
   indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'));
   indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'));
@@ -397,9 +433,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
 	start + 3 <= end &&
 	info[start].indic_category() == OT_Ra &&
 	info[start + 1].indic_category() == OT_H &&
-	(unlikely (buffer->props.script == HB_SCRIPT_SINHALA || buffer->props.script == HB_SCRIPT_TELUGU) ?
-	 info[start + 2].indic_category() == OT_ZWJ /* In Sinhala & Telugu, form Reph only if ZWJ is present */:
-	 !is_joiner (info[start + 2] /* In other scripts, any joiner blocks Reph formation */ )
+	(/* TODO Handle other Reph modes. */
+	 (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
+	 (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
 	))
     {
       limit += 2;
@@ -409,92 +445,84 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
       has_reph = true;
     };
 
-     enum base_position_t {
-       BASE_FIRST,
-       BASE_LAST
-     } base_pos;
-
-    switch ((hb_tag_t) buffer->props.script)
-    {
-      case HB_SCRIPT_SINHALA:
-      case HB_SCRIPT_KHMER:
-	base_pos = BASE_FIRST;
-	break;
-
-      default:
-	base_pos = BASE_LAST;
-	break;
-    }
-
-    if (base_pos == BASE_LAST)
+    switch (indic_plan->config->base_pos == BASE_POS_LAST)
     {
-      /* -> starting from the end of the syllable, move backwards */
-      unsigned int i = end;
-      bool seen_below = false;
-      do {
-	i--;
-	/* -> until a consonant is found */
-	if (is_consonant (info[i]))
-	{
-	  /* -> that does not have a below-base or post-base form
-	   * (post-base forms have to follow below-base forms), */
-	  if (info[i].indic_position() != POS_BELOW_C &&
-	      (info[i].indic_position() != POS_POST_C || seen_below))
+      case BASE_POS_LAST:
+      {
+	/* -> starting from the end of the syllable, move backwards */
+	unsigned int i = end;
+	bool seen_below = false;
+	do {
+	  i--;
+	  /* -> until a consonant is found */
+	  if (is_consonant (info[i]))
 	  {
+	    /* -> that does not have a below-base or post-base form
+	     * (post-base forms have to follow below-base forms), */
+	    if (info[i].indic_position() != POS_BELOW_C &&
+		(info[i].indic_position() != POS_POST_C || seen_below))
+	    {
+	      base = i;
+	      break;
+	    }
+	    if (info[i].indic_position() == POS_BELOW_C)
+	      seen_below = true;
+
+	    /* -> or that is not a pre-base reordering Ra,
+	     *
+	     * IMPLEMENTATION NOTES:
+	     *
+	     * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped
+	     * by the logic above already.
+	     */
+
+	    /* -> or arrive at the first consonant. The consonant stopped at will
+	     * be the base. */
 	    base = i;
-	    break;
 	  }
-	  if (info[i].indic_position() == POS_BELOW_C)
-	    seen_below = true;
+	  else
+	  {
+	    /* A ZWJ after a Halant stops the base search, and requests an explicit
+	     * half form.
+	     * A ZWJ before a Halant, requests a subjoined form instead, and hence
+	     * search continues.  This is particularly important for Bengali
+	     * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */
+	    if (start < i &&
+		info[i].indic_category() == OT_ZWJ &&
+		info[i - 1].indic_category() == OT_H)
+	      break;
+	  }
+	} while (i > limit);
+      }
+      break;
 
-	  /* -> or that is not a pre-base reordering Ra,
-	   *
-	   * IMPLEMENTATION NOTES:
-	   *
-	   * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped
-	   * by the logic above already.
-	   */
+      case BASE_POS_FIRST:
+      {
+	/* In scripts without half forms (eg. Khmer), the first consonant is always the base. */
 
-	  /* -> or arrive at the first consonant. The consonant stopped at will
-	   * be the base. */
-	  base = i;
-	}
-	else
-	{
-	  /* A ZWJ after a Halant stops the base search, and requests an explicit
-	   * half form.
-	   * A ZWJ before a Halant, requests a subjoined form instead, and hence
-	   * search continues.  This is particularly important for Bengali
-	   * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */
-	  if (start < i &&
-	      info[i].indic_category() == OT_ZWJ &&
-	      info[i - 1].indic_category() == OT_H)
-	    break;
-	}
-      } while (i > limit);
-    }
-    else
-    {
-      /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */
+	if (!has_reph)
+	  base = limit;
 
-      if (!has_reph)
-	base = limit;
+	/* Find the last base consonant that is not blocked by ZWJ.  If there is
+	 * a ZWJ right before a base consonant, that would request a subjoined form. */
+	for (unsigned int i = limit; i < end; i++)
+	  if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
+	  {
+	    if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
+	      break;
+	    else
+	      base = i;
+	  }
 
-      /* Find the last base consonant that is not blocked by ZWJ.  If there is
-       * a ZWJ right before a base consonant, that would request a subjoined form. */
-      for (unsigned int i = limit; i < end; i++)
-        if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
-	{
-	  if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
-	    break;
-          else
-	    base = i;
-	}
+	/* Mark all subsequent consonants as below. */
+	for (unsigned int i = base + 1; i < end; i++)
+	  if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
+	    info[i].indic_position() = POS_BELOW_C;
+      }
+      break;
 
-      /* Mark all subsequent consonants as below. */
-      for (unsigned int i = base + 1; i < end; i++)
-        if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
-	  info[i].indic_position() = POS_BELOW_C;
+      default:
+      abort ();
     }
 
     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
@@ -864,50 +892,15 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
       info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
       info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH)
   {
-      unsigned int new_reph_pos;
-
-     enum reph_position_t {
-       REPH_AFTER_MAIN,
-       REPH_BEFORE_SUBSCRIPT,
-       REPH_AFTER_SUBSCRIPT,
-       REPH_BEFORE_POSTSCRIPT,
-       REPH_AFTER_POSTSCRIPT
-     } reph_pos;
-
-     /* XXX Figure out old behavior too */
-     switch ((hb_tag_t) buffer->props.script)
-     {
-       case HB_SCRIPT_MALAYALAM:
-       case HB_SCRIPT_ORIYA:
-       case HB_SCRIPT_SINHALA:
-	 reph_pos = REPH_AFTER_MAIN;
-	 break;
-
-       case HB_SCRIPT_GURMUKHI:
-	 reph_pos = REPH_BEFORE_SUBSCRIPT;
-	 break;
-
-       case HB_SCRIPT_BENGALI:
-	 reph_pos = REPH_AFTER_SUBSCRIPT;
-	 break;
-
-       default:
-       case HB_SCRIPT_DEVANAGARI:
-       case HB_SCRIPT_GUJARATI:
-	 reph_pos = REPH_BEFORE_POSTSCRIPT;
-	 break;
-
-       case HB_SCRIPT_KANNADA:
-       case HB_SCRIPT_TAMIL:
-       case HB_SCRIPT_TELUGU:
-	 reph_pos = REPH_AFTER_POSTSCRIPT;
-	 break;
-     }
+    unsigned int new_reph_pos;
+    reph_position_t reph_pos = indic_plan->config->reph_pos;
+
+    /* XXX Figure out old behavior too */
 
     /*       1. If reph should be positioned after post-base consonant forms,
      *          proceed to step 5.
      */
-    if (reph_pos == REPH_AFTER_POSTSCRIPT)
+    if (reph_pos == REPH_POS_AFTER_POST)
     {
       goto reph_step_5;
     }
@@ -940,7 +933,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
      *          first consonant not ligated with main, or find the first
      *          consonant that is not a potential pre-base reordering Ra.
      */
-    if (reph_pos == REPH_AFTER_MAIN)
+    if (reph_pos == REPH_POS_AFTER_MAIN)
     {
       new_reph_pos = base;
       /* XXX Skip potential pre-base reordering Ra. */
@@ -956,7 +949,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
      *          first matra, syllable modifier sign or vedic sign.
      */
     /* This is our take on what step 4 is trying to say (and failing, BADLY). */
-    if (reph_pos == REPH_AFTER_SUBSCRIPT)
+    if (reph_pos == REPH_POS_AFTER_SUB)
     {
       new_reph_pos = base;
       while (new_reph_pos < end &&
commit 85fc6c483f6d734febbe39270e84701a651f01f1
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 12:21:44 2012 -0400

    [Indic] Move more stuff to the shape_plan
    
    Almost done.  Need to add per-script static tables.

diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index 25c0e65..b6a372e 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -92,14 +92,14 @@ main := |*
     if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); \
     for (unsigned int i = last; i < p+1; i++) \
       info[i].syllable() = syllable_serial; \
-    PASTE (initial_reordering_, func) (plan, buffer, mask_array, last, p+1); \
+    PASTE (initial_reordering_, func) (plan, buffer, last, p+1); \
     last = p+1; \
     syllable_serial++; \
     if (unlikely (!syllable_serial)) syllable_serial++; \
   } HB_STMT_END
 
 static void
-find_syllables (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_mask_t *mask_array)
+find_syllables (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 57f3340..f48abf4 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -88,10 +88,13 @@ struct feature_list_t {
   hb_bool_t is_global;
 };
 
-/* These features are applied one at a time, given the order in this table. */
 static const feature_list_t
-indic_basic_features[] =
+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},
@@ -104,9 +107,25 @@ indic_basic_features[] =
   {HB_TAG('c','f','a','r'), false},
   {HB_TAG('c','j','c','t'), true},
   {HB_TAG('v','a','t','u'), true},
+  /*
+   * 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},
+  /* 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},
 };
 
-/* Same order as the indic_basic_features array */
+/*
+ * Must be in the same order as the indic_features array.
+ */
 enum {
   _NUKT,
   _AKHN,
@@ -119,26 +138,22 @@ enum {
   PSTF,
   CFAR,
   _CJCT,
-  VATU
+  _VATU,
+
+  INIT,
+  _PRES,
+  _ABVS,
+  _BLWS,
+  _PSTS,
+  _HALN,
+  _DIST,
+  _ABVM,
+  _BLWM,
+
+  INDIC_NUM_FEATURES,
+  INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
 };
 
-/* These features are applied all at once. */
-static const feature_list_t
-indic_other_features[] =
-{
-  {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('d','i','s','t'), true},
-  {HB_TAG('a','b','v','m'), true},
-  {HB_TAG('b','l','w','m'), true},
-};
-
-
 static void
 initial_reordering (const hb_ot_shape_plan_t *plan,
 		    hb_font_t *font,
@@ -158,17 +173,17 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
    * there is a use of it, it's typically at the beginning. */
   map->add_bool_feature (HB_TAG('c','c','m','p'));
 
-  map->add_gsub_pause (initial_reordering);
 
-  for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) {
-    map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global);
+  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_gsub_pause (NULL);
   }
-
   map->add_gsub_pause (final_reordering);
-
-  for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++)
-    map->add_bool_feature (indic_other_features[i].tag, indic_other_features[i].is_global);
+  for (; i < INDIC_NUM_FEATURES; i++) {
+    map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global);
+  }
 }
 
 static void
@@ -180,9 +195,9 @@ override_features_indic (hb_ot_shape_planner_t *plan)
 }
 
 
-struct would_apply_feature_t
+struct would_substitute_feature_t
 {
-  would_apply_feature_t (const hb_ot_map_t *map, hb_tag_t feature_tag)
+  inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag)
   {
     map->get_stage_lookups (0/*GSUB*/,
 			    map->get_feature_stage (0/*GSUB*/, feature_tag),
@@ -206,35 +221,7 @@ struct would_apply_feature_t
 
 struct indic_shape_plan_t
 {
-  indic_shape_plan_t (const hb_ot_shape_plan_t *plan) :
-		      pref (&plan->map, HB_TAG('p','r','e','f')),
-		      blwf (&plan->map, HB_TAG('b','l','w','f')),
-		      pstf (&plan->map, HB_TAG('p','s','t','f')),
-		      is_old_spec (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))),
-		      virama_glyph ((hb_codepoint_t) -1)
-  {
-    switch ((int) plan->props.script) {
-      case HB_SCRIPT_DEVANAGARI:virama = 0x094D; break;
-      case HB_SCRIPT_BENGALI:	virama = 0x09CD; break;
-      case HB_SCRIPT_GURMUKHI:	virama = 0x0A4D; break;
-      case HB_SCRIPT_GUJARATI:	virama = 0x0ACD; break;
-      case HB_SCRIPT_ORIYA:	virama = 0x0B4D; break;
-      case HB_SCRIPT_TAMIL:	virama = 0x0BCD; break;
-      case HB_SCRIPT_TELUGU:	virama = 0x0C4D; break;
-      case HB_SCRIPT_KANNADA:	virama = 0x0CCD; break;
-      case HB_SCRIPT_MALAYALAM:	virama = 0x0D4D; break;
-      case HB_SCRIPT_SINHALA:	virama = 0x0DCA; break;
-      case HB_SCRIPT_KHMER:	virama = 0x17D2; break;
-      default:			virama = 0;      break;
-    }
-  }
-
-  would_apply_feature_t pref;
-  would_apply_feature_t blwf;
-  would_apply_feature_t pstf;
-  bool is_old_spec;
-  hb_codepoint_t virama;
-  hb_codepoint_t virama_glyph;
+  ASSERT_POD ();
 
   inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
   {
@@ -254,20 +241,56 @@ struct indic_shape_plan_t
     *pglyph = glyph;
     return glyph != 0;
   }
+
+
+  bool is_old_spec;
+
+  hb_codepoint_t virama;
+  hb_codepoint_t virama_glyph;
+
+  would_substitute_feature_t pref;
+  would_substitute_feature_t blwf;
+  would_substitute_feature_t pstf;
+
+  hb_mask_t mask_array[INDIC_NUM_FEATURES];
 };
 
 static void *
 data_create_indic (const hb_ot_shape_plan_t *plan)
 {
-  indic_shape_plan_t *data = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
-  if (unlikely (!data))
+  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
+  if (unlikely (!indic_plan))
     return NULL;
 
-  /* Mixing C++ and C, oh well... */
-  indic_shape_plan_t indic_plan (plan);
+  indic_plan->is_old_spec = IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0));
+  {
+    hb_codepoint_t virama;
+    switch ((int) plan->props.script) {
+      case HB_SCRIPT_DEVANAGARI:virama = 0x094D; break;
+      case HB_SCRIPT_BENGALI:	virama = 0x09CD; break;
+      case HB_SCRIPT_GURMUKHI:	virama = 0x0A4D; break;
+      case HB_SCRIPT_GUJARATI:	virama = 0x0ACD; break;
+      case HB_SCRIPT_ORIYA:	virama = 0x0B4D; break;
+      case HB_SCRIPT_TAMIL:	virama = 0x0BCD; break;
+      case HB_SCRIPT_TELUGU:	virama = 0x0C4D; break;
+      case HB_SCRIPT_KANNADA:	virama = 0x0CCD; break;
+      case HB_SCRIPT_MALAYALAM:	virama = 0x0D4D; break;
+      case HB_SCRIPT_SINHALA:	virama = 0x0DCA; break;
+      case HB_SCRIPT_KHMER:	virama = 0x17D2; break;
+      default:			virama = 0;      break;
+    }
+    indic_plan->virama = virama;
+  }
+  indic_plan->virama_glyph = indic_plan->virama ? (hb_codepoint_t) -1 : 0;
+
+  indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'));
+  indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'));
+  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);
 
-  *data = indic_plan;
-  return data;
+  return indic_plan;
 }
 
 static void
@@ -317,8 +340,8 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
 
 static void
 update_consonant_positions (const hb_ot_shape_plan_t *plan,
-			    hb_buffer_t       *buffer,
-			    hb_font_t         *font)
+			    hb_font_t         *font,
+			    hb_buffer_t       *buffer)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
@@ -341,7 +364,7 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
 
 static void
-initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_mask_t *basic_mask_array,
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer,
 				       unsigned int start, unsigned int end)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
@@ -370,7 +393,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
      *    and has more than one consonant, Ra is excluded from candidates for
      *    base consonants. */
     unsigned int limit = start;
-    if (basic_mask_array[RPHF] &&
+    if (indic_plan->mask_array[RPHF] &&
 	start + 3 <= end &&
 	info[start].indic_category() == OT_Ra &&
 	info[start + 1].indic_category() == OT_H &&
@@ -627,10 +650,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
 
     /* Reph */
     for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
-      info[i].mask |= basic_mask_array[RPHF];
+      info[i].mask |= indic_plan->mask_array[RPHF];
 
     /* Pre-base */
-    mask = basic_mask_array[HALF];
+    mask = indic_plan->mask_array[HALF];
     for (unsigned int i = start; i < base; i++)
       info[i].mask  |= mask;
     /* Base */
@@ -638,21 +661,21 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
     if (base < end)
       info[base].mask |= mask;
     /* Post-base */
-    mask = basic_mask_array[BLWF] | basic_mask_array[ABVF] | basic_mask_array[PSTF];
+    mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
     for (unsigned int i = base + 1; i < end; i++)
       info[i].mask  |= mask;
   }
 
   /* XXX This will not match for old-Indic spec since the Halant-Ra order is reversed already. */
-  if (basic_mask_array[PREF] && base + 2 < end)
+  if (indic_plan->mask_array[PREF] && base + 2 < end)
   {
     /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
     for (unsigned int i = base + 1; i + 1 < end; i++)
       if (is_halant_or_coeng (info[i]) &&
 	  info[i + 1].indic_category() == OT_Ra)
       {
-	info[i++].mask |= basic_mask_array[PREF];
-	info[i++].mask |= basic_mask_array[PREF];
+	info[i++].mask |= indic_plan->mask_array[PREF];
+	info[i++].mask |= indic_plan->mask_array[PREF];
 
 	/* Mark the subsequent stuff with 'cfar'.  Used in Khmer.
 	 * Read the feature spec.
@@ -661,7 +684,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
 	 * U+1784,U+17D2,U+1782,U+17D2,U+179A
 	 */
 	for (; i < end; i++)
-	  info[i].mask |= basic_mask_array[CFAR];
+	  info[i].mask |= indic_plan->mask_array[CFAR];
 
 	break;
       }
@@ -681,7 +704,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
 
 	/* A ZWNJ disables HALF. */
 	if (non_joiner)
-	  info[j].mask &= ~basic_mask_array[HALF];
+	  info[j].mask &= ~indic_plan->mask_array[HALF];
 
       } while (j > start && !is_consonant (info[j]));
     }
@@ -691,17 +714,15 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
 static void
 initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
 				   hb_buffer_t *buffer,
-				   hb_mask_t *basic_mask_array,
 				   unsigned int start, unsigned int end)
 {
   /* We made the vowels look like consonants.  So let's call the consonant logic! */
-  initial_reordering_consonant_syllable (plan, buffer, basic_mask_array, start, end);
+  initial_reordering_consonant_syllable (plan, buffer, start, end);
 }
 
 static void
 initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
 				       hb_buffer_t *buffer,
-				       hb_mask_t *basic_mask_array,
 				       unsigned int start, unsigned int end)
 {
   /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain.
@@ -716,13 +737,12 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
       return;
   }
 
-  initial_reordering_consonant_syllable (plan, buffer, basic_mask_array, start, end);
+  initial_reordering_consonant_syllable (plan, buffer, start, end);
 }
 
 static void
 initial_reordering_non_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
 			      hb_buffer_t *buffer HB_UNUSED,
-			      hb_mask_t *basic_mask_array HB_UNUSED,
 			      unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
 {
   /* Nothing to do right now.  If we ever switch to using the output
@@ -736,21 +756,16 @@ initial_reordering (const hb_ot_shape_plan_t *plan,
 		    hb_font_t *font,
 		    hb_buffer_t *buffer)
 {
-  update_consonant_positions (plan, buffer, font);
-
-  hb_mask_t basic_mask_array[ARRAY_LENGTH (indic_basic_features)] = {0};
-  unsigned int num_masks = ARRAY_LENGTH (indic_basic_features);
-  for (unsigned int i = 0; i < num_masks; i++)
-    basic_mask_array[i] = plan->map.get_1_mask (indic_basic_features[i].tag);
-
-  find_syllables (plan, buffer, basic_mask_array);
+  update_consonant_positions (plan, font, buffer);
+  find_syllables (plan, buffer);
 }
 
 static void
-final_reordering_syllable (hb_buffer_t *buffer,
-			   hb_mask_t init_mask, hb_mask_t pref_mask,
+final_reordering_syllable (const hb_ot_shape_plan_t *plan,
+			   hb_buffer_t *buffer,
 			   unsigned int start, unsigned int end)
 {
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
 
   /* 4. Final reordering:
@@ -1017,16 +1032,16 @@ final_reordering_syllable (hb_buffer_t *buffer,
    *     the following rules:
    */
 
-  if (pref_mask && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
+  if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
   {
     for (unsigned int i = base + 1; i < end; i++)
-      if ((info[i].mask & pref_mask) != 0)
+      if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
       {
 	/*       1. Only reorder a glyph produced by substitution during application
 	 *          of the <pref> feature. (Note that a font may shape a Ra consonant with
 	 *          the feature generally but block it in certain contexts.)
 	 */
-	if (i + 1 == end || (info[i + 1].mask & pref_mask) == 0)
+	if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0)
 	{
 	  /*
 	   *       2. Try to find a target position the same way as for pre-base matra.
@@ -1078,7 +1093,7 @@ final_reordering_syllable (hb_buffer_t *buffer,
       (!start ||
        !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) &
 	 FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
-    info[start].mask |= init_mask;
+    info[start].mask |= indic_plan->mask_array[INIT];
 
 
   /*
@@ -1097,25 +1112,22 @@ final_reordering_syllable (hb_buffer_t *buffer,
 
 static void
 final_reordering (const hb_ot_shape_plan_t *plan,
-		  hb_font_t *font HB_UNUSED,
+		  hb_font_t *font,
 		  hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   if (!count) return;
 
-  hb_mask_t init_mask = plan->map.get_1_mask (HB_TAG('i','n','i','t'));
-  hb_mask_t pref_mask = plan->map.get_1_mask (HB_TAG('p','r','e','f'));
-
   hb_glyph_info_t *info = buffer->info;
   unsigned int last = 0;
   unsigned int last_syllable = info[0].syllable();
   for (unsigned int i = 1; i < count; i++)
     if (last_syllable != info[i].syllable()) {
-      final_reordering_syllable (buffer, init_mask, pref_mask, last, i);
+      final_reordering_syllable (plan, buffer, last, i);
       last = i;
       last_syllable = info[last].syllable();
     }
-  final_reordering_syllable (buffer, init_mask, pref_mask, last, count);
+  final_reordering_syllable (plan, buffer, last, count);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
commit 914ffaa40fcca020f65bacdd709421e9047afd83
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 11:03:39 2012 -0400

    [Indic] Move more repeated work into shape_plan

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index cdfd5b9..57f3340 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -210,12 +210,50 @@ struct indic_shape_plan_t
 		      pref (&plan->map, HB_TAG('p','r','e','f')),
 		      blwf (&plan->map, HB_TAG('b','l','w','f')),
 		      pstf (&plan->map, HB_TAG('p','s','t','f')),
-		      is_old_spec (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))) {}
+		      is_old_spec (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))),
+		      virama_glyph ((hb_codepoint_t) -1)
+  {
+    switch ((int) plan->props.script) {
+      case HB_SCRIPT_DEVANAGARI:virama = 0x094D; break;
+      case HB_SCRIPT_BENGALI:	virama = 0x09CD; break;
+      case HB_SCRIPT_GURMUKHI:	virama = 0x0A4D; break;
+      case HB_SCRIPT_GUJARATI:	virama = 0x0ACD; break;
+      case HB_SCRIPT_ORIYA:	virama = 0x0B4D; break;
+      case HB_SCRIPT_TAMIL:	virama = 0x0BCD; break;
+      case HB_SCRIPT_TELUGU:	virama = 0x0C4D; break;
+      case HB_SCRIPT_KANNADA:	virama = 0x0CCD; break;
+      case HB_SCRIPT_MALAYALAM:	virama = 0x0D4D; break;
+      case HB_SCRIPT_SINHALA:	virama = 0x0DCA; break;
+      case HB_SCRIPT_KHMER:	virama = 0x17D2; break;
+      default:			virama = 0;      break;
+    }
+  }
 
   would_apply_feature_t pref;
   would_apply_feature_t blwf;
   would_apply_feature_t pstf;
   bool is_old_spec;
+  hb_codepoint_t virama;
+  hb_codepoint_t virama_glyph;
+
+  inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
+  {
+    hb_codepoint_t glyph = virama_glyph;
+    if (unlikely (virama_glyph == (hb_codepoint_t) -1))
+    {
+      if (!font->get_glyph (virama, 0, &glyph))
+	glyph = 0;
+      /* Technically speaking, the spec says we should apply 'locl' to virama too.
+       * Maybe one day... */
+
+      /* Our get_glyph() function needs a font, so we can't get the virama glyph
+       * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
+      (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
+    }
+
+    *pglyph = glyph;
+    return glyph != 0;
+  }
 };
 
 static void *
@@ -282,30 +320,12 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
 			    hb_buffer_t       *buffer,
 			    hb_font_t         *font)
 {
-  hb_codepoint_t virama;
-  switch ((int) buffer->props.script) {
-    case HB_SCRIPT_DEVANAGARI:	virama = 0x094D; break;
-    case HB_SCRIPT_BENGALI:	virama = 0x09CD; break;
-    case HB_SCRIPT_GURMUKHI:	virama = 0x0A4D; break;
-    case HB_SCRIPT_GUJARATI:	virama = 0x0ACD; break;
-    case HB_SCRIPT_ORIYA:	virama = 0x0B4D; break;
-    case HB_SCRIPT_TAMIL:	virama = 0x0BCD; break;
-    case HB_SCRIPT_TELUGU:	virama = 0x0C4D; break;
-    case HB_SCRIPT_KANNADA:	virama = 0x0CCD; break;
-    case HB_SCRIPT_MALAYALAM:	virama = 0x0D4D; break;
-    case HB_SCRIPT_SINHALA:	virama = 0x0DCA; break;
-    case HB_SCRIPT_KHMER:	virama = 0x17D2; break;
-    default:			virama = 0;      break;
-  }
-
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
   unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1;
   hb_codepoint_t glyphs[2];
-  if (virama && font->get_glyph (virama, 0, &glyphs[1 - consonant_pos]))
+  if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos]))
   {
-    /* Technically speaking, the spec says we should apply 'locl' to virama too.
-     * Maybe one day... */
     hb_face_t *face = font->face;
     unsigned int count = buffer->len;
     for (unsigned int i = 0; i < count; i++)
@@ -324,6 +344,7 @@ static void
 initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_mask_t *basic_mask_array,
 				       unsigned int start, unsigned int end)
 {
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
 
 
@@ -526,7 +547,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
 
   /* For old-style Indic script tags, move the first post-base Halant after
    * last consonant. */
-  if (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))) {
+  if (indic_plan->is_old_spec) {
     for (unsigned int i = base + 1; i < end; i++)
       if (info[i].indic_category() == OT_H) {
         unsigned int j;
commit a8c6da90f4c6e8d27a3a1b758a55476776d9f750
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 10:46:34 2012 -0400

    [OT] Add per-complex-shaper shape_plan data
    
    Hookup some Indic data to it.  More to come.

diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index d08d364..b014c74 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -296,6 +296,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
   "arabic",
   collect_features_arabic,
   NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
   NULL, /* normalization_preference */
   setup_masks_arabic,
   true, /* zero_width_attached_marks */
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index be37cdd..cdfd5b9 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -82,56 +82,6 @@ indic_options (void)
 }
 
 
-struct indic_shape_plan_t
-{
-  struct would_apply_feature_t
-  {
-    would_apply_feature_t (const hb_ot_map_t *map, hb_tag_t feature_tag)
-    {
-      map->get_stage_lookups (0/*GSUB*/,
-			      map->get_feature_stage (0/*GSUB*/, feature_tag),
-			      &lookups, &count);
-    }
-
-    inline bool would_substitute (hb_codepoint_t    *glyphs,
-				  unsigned int       glyphs_count,
-				  hb_face_t         *face) const
-    {
-      for (unsigned int i = 0; i < count; i++)
-	if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookups[i].index))
-	  return true;
-      return false;
-    }
-
-    private:
-    const hb_ot_map_t::lookup_map_t *lookups;
-    unsigned int count;
-  };
-
-  indic_shape_plan_t (const hb_ot_shape_plan_t *plan) :
-		      pref (&plan->map, HB_TAG('p','r','e','f')),
-		      blwf (&plan->map, HB_TAG('b','l','w','f')),
-		      pstf (&plan->map, HB_TAG('p','s','t','f')),
-		      is_old_spec (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))) {}
-
-  would_apply_feature_t pref;
-  would_apply_feature_t blwf;
-  would_apply_feature_t pstf;
-  bool is_old_spec;
-};
-
-static indic_position_t
-consonant_position_from_font (const indic_shape_plan_t *indic_plan,
-			      hb_codepoint_t *glyphs, unsigned int glyphs_len,
-			      hb_face_t      *face)
-{
-  if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C;
-  if (indic_plan->blwf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C;
-  if (indic_plan->pstf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_POST_C;
-  return POS_BASE_C;
-}
-
-
 
 struct feature_list_t {
   hb_tag_t tag;
@@ -230,6 +180,76 @@ override_features_indic (hb_ot_shape_planner_t *plan)
 }
 
 
+struct would_apply_feature_t
+{
+  would_apply_feature_t (const hb_ot_map_t *map, hb_tag_t feature_tag)
+  {
+    map->get_stage_lookups (0/*GSUB*/,
+			    map->get_feature_stage (0/*GSUB*/, feature_tag),
+			    &lookups, &count);
+  }
+
+  inline bool would_substitute (hb_codepoint_t    *glyphs,
+				unsigned int       glyphs_count,
+				hb_face_t         *face) const
+  {
+    for (unsigned int i = 0; i < count; i++)
+      if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookups[i].index))
+	return true;
+    return false;
+  }
+
+  private:
+  const hb_ot_map_t::lookup_map_t *lookups;
+  unsigned int count;
+};
+
+struct indic_shape_plan_t
+{
+  indic_shape_plan_t (const hb_ot_shape_plan_t *plan) :
+		      pref (&plan->map, HB_TAG('p','r','e','f')),
+		      blwf (&plan->map, HB_TAG('b','l','w','f')),
+		      pstf (&plan->map, HB_TAG('p','s','t','f')),
+		      is_old_spec (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))) {}
+
+  would_apply_feature_t pref;
+  would_apply_feature_t blwf;
+  would_apply_feature_t pstf;
+  bool is_old_spec;
+};
+
+static void *
+data_create_indic (const hb_ot_shape_plan_t *plan)
+{
+  indic_shape_plan_t *data = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
+  if (unlikely (!data))
+    return NULL;
+
+  /* Mixing C++ and C, oh well... */
+  indic_shape_plan_t indic_plan (plan);
+
+  *data = indic_plan;
+  return data;
+}
+
+static void
+data_destroy_indic (void *data)
+{
+  free (data);
+}
+
+static indic_position_t
+consonant_position_from_face (const indic_shape_plan_t *indic_plan,
+			      hb_codepoint_t *glyphs, unsigned int glyphs_len,
+			      hb_face_t      *face)
+{
+  if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C;
+  if (indic_plan->blwf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C;
+  if (indic_plan->pstf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_POST_C;
+  return POS_BASE_C;
+}
+
+
 static void
 setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
 		   hb_buffer_t              *buffer,
@@ -278,9 +298,9 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
     default:			virama = 0;      break;
   }
 
-  indic_shape_plan_t indic_plan (plan);
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
-  unsigned int consonant_pos = indic_plan.is_old_spec ? 0 : 1;
+  unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1;
   hb_codepoint_t glyphs[2];
   if (virama && font->get_glyph (virama, 0, &glyphs[1 - consonant_pos]))
   {
@@ -291,7 +311,7 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
     for (unsigned int i = 0; i < count; i++)
       if (buffer->info[i].indic_position() == POS_BASE_C) {
 	glyphs[consonant_pos] = buffer->info[i].codepoint;
-	buffer->info[i].indic_position() = consonant_position_from_font (&indic_plan, glyphs, 2, face);
+	buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face);
       }
   }
 }
@@ -1086,6 +1106,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
   "indic",
   collect_features_indic,
   override_features_indic,
+  data_create_indic,
+  data_destroy_indic,
   NULL, /* normalization_preference */
   setup_masks_indic,
   false, /* zero_width_attached_marks */
diff --git a/src/hb-ot-shape-complex-misc.cc b/src/hb-ot-shape-complex-misc.cc
index 6ae9f50..4f1dd5b 100644
--- a/src/hb-ot-shape-complex-misc.cc
+++ b/src/hb-ot-shape-complex-misc.cc
@@ -88,6 +88,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
   "default",
   collect_features_default,
   NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
   normalization_preference_default,
   NULL, /* setup_masks */
   true, /* zero_width_attached_marks */
@@ -196,6 +198,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
   "thai",
   NULL, /* collect_features */
   NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
   NULL, /* normalization_preference */
   setup_masks_thai,
   true, /* zero_width_attached_marks */
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index e7f9697..baece32 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -69,13 +69,27 @@ struct hb_ot_complex_shaper_t
    */
   void (*override_features) (hb_ot_shape_planner_t *plan);
 
+
+  /* data_create()
+   * Called at the end of shape_plan().
+   * Whatever shapers return will be accessible through plan->data later.
+   * If NULL is returned, means a plan failure.
+   * May be NULL. */
+  void *(*data_create) (const hb_ot_shape_plan_t *plan);
+
+  /* data_destroy()
+   * Called when the shape_plan is being destroyed.
+   * plan->data is passed here for destruction.
+   * If NULL is returned, means a plan failure.
+   * May be NULL. */
+  void (*data_destroy) (void *data);
+
   /* normalization_preference()
    * Called during shape().
    */
   hb_ot_shape_normalization_mode_t
   (*normalization_preference) (const hb_ot_shape_plan_t *plan);
 
-
   /* setup_masks()
    * Called during shape().
    * Shapers should use map to get feature masks and set on buffer.
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index da8a6db..975665e 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -44,6 +44,7 @@ struct hb_ot_shape_plan_t
   hb_segment_properties_t props;
   const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
+  const void *data;
 
   inline void substitute_closure (hb_face_t *face, hb_set_t *glyphs) const { map.substitute_closure (this, face, glyphs); }
   inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 67330b4..28bb1f9 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -167,8 +167,8 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
 				      const hb_feature_t *user_features,
 				      unsigned int        num_user_features)
 {
-  hb_ot_shape_plan_t *data = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
-  if (unlikely (!data))
+  hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
+  if (unlikely (!plan))
     return NULL;
 
   hb_ot_shape_planner_t planner (shape_plan);
@@ -177,17 +177,26 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
 
   hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
 
-  planner.compile (*data);
+  planner.compile (*plan);
 
-  return data;
+  if (plan->shaper->data_create) {
+    plan->data = plan->shaper->data_create (plan);
+    if (unlikely (!plan->data))
+      return NULL;
+  }
+
+  return plan;
 }
 
 void
-_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *data)
+_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
 {
-  data->finish ();
+  if (plan->shaper->data_destroy)
+    plan->shaper->data_destroy (const_cast<void *> (plan->data));
+
+  plan->finish ();
 
-  free (data);
+  free (plan);
 }
 
 
commit 8bb5deba9630d35878eb6edb4643ecfabf99f15f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 10:07:58 2012 -0400

    [OT] Pipe shape_plan down to pause_callbacks

diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 18517c4..b9c6736 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -62,7 +62,7 @@ struct hb_ot_map_t
     { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
   };
 
-  typedef void (*pause_func_t) (const hb_ot_map_t *map, hb_font_t *font, hb_buffer_t *buffer);
+  typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
 
   struct pause_map_t {
     unsigned int num_lookups; /* Cumulative */
@@ -112,9 +112,9 @@ struct hb_ot_map_t
   inline hb_tag_t get_chosen_script (unsigned int table_index) const
   { return chosen_script[table_index]; }
 
-  HB_INTERNAL void substitute_closure (hb_face_t *face, hb_set_t *glyphs) const;
-  HB_INTERNAL void substitute (hb_font_t *font, hb_buffer_t *buffer) const;
-  HB_INTERNAL void position (hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void substitute_closure (const struct hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const;
+  HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 
   inline void finish (void) {
     features.finish ();
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 62afdef..7eed624 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -75,7 +75,7 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool gl
 
 /* Keep the next two functions in sync. */
 
-void hb_ot_map_t::substitute (hb_font_t *font, hb_buffer_t *buffer) const
+void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
   const unsigned int table_index = 0;
   unsigned int i = 0;
@@ -88,14 +88,14 @@ void hb_ot_map_t::substitute (hb_font_t *font, hb_buffer_t *buffer) const
     buffer->clear_output ();
 
     if (pause->callback)
-      pause->callback (this, font, buffer);
+      pause->callback (plan, font, buffer);
   }
 
   for (; i < lookups[table_index].len; i++)
     hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
 }
 
-void hb_ot_map_t::position (hb_font_t *font, hb_buffer_t *buffer) const
+void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
   const unsigned int table_index = 1;
   unsigned int i = 0;
@@ -106,15 +106,14 @@ void hb_ot_map_t::position (hb_font_t *font, hb_buffer_t *buffer) const
       hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
 
     if (pause->callback)
-      pause->callback (this, font, buffer);
+      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);
 }
 
-void hb_ot_map_t::substitute_closure (hb_face_t *face,
-				      hb_set_t *glyphs) const
+void hb_ot_map_t::substitute_closure (const hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const
 {
   unsigned int table_index = 0;
   unsigned int i = 0;
diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index 25e308d..25c0e65 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -92,14 +92,14 @@ main := |*
     if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); \
     for (unsigned int i = last; i < p+1; i++) \
       info[i].syllable() = syllable_serial; \
-    PASTE (initial_reordering_, func) (map, buffer, mask_array, last, p+1); \
+    PASTE (initial_reordering_, func) (plan, buffer, mask_array, last, p+1); \
     last = p+1; \
     syllable_serial++; \
     if (unlikely (!syllable_serial)) syllable_serial++; \
   } HB_STMT_END
 
 static void
-find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array)
+find_syllables (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_mask_t *mask_array)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 6b55fb7..be37cdd 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -108,14 +108,12 @@ struct indic_shape_plan_t
     unsigned int count;
   };
 
-  indic_shape_plan_t (const hb_ot_map_t *map_) :
-		      map (map_),
-		      pref (map_, HB_TAG('p','r','e','f')),
-		      blwf (map_, HB_TAG('b','l','w','f')),
-		      pstf (map_, HB_TAG('p','s','t','f')),
-		      is_old_spec (IS_OLD_INDIC_TAG (map->get_chosen_script (0))) {}
-
-  const hb_ot_map_t *map;
+  indic_shape_plan_t (const hb_ot_shape_plan_t *plan) :
+		      pref (&plan->map, HB_TAG('p','r','e','f')),
+		      blwf (&plan->map, HB_TAG('b','l','w','f')),
+		      pstf (&plan->map, HB_TAG('p','s','t','f')),
+		      is_old_spec (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))) {}
+
   would_apply_feature_t pref;
   would_apply_feature_t blwf;
   would_apply_feature_t pstf;
@@ -192,11 +190,11 @@ indic_other_features[] =
 
 
 static void
-initial_reordering (const hb_ot_map_t *map,
+initial_reordering (const hb_ot_shape_plan_t *plan,
 		    hb_font_t *font,
 		    hb_buffer_t *buffer);
 static void
-final_reordering (const hb_ot_map_t *map,
+final_reordering (const hb_ot_shape_plan_t *plan,
 		  hb_font_t *font,
 		  hb_buffer_t *buffer);
 
@@ -260,7 +258,7 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
 
 
 static void
-update_consonant_positions (const hb_ot_map_t *map,
+update_consonant_positions (const hb_ot_shape_plan_t *plan,
 			    hb_buffer_t       *buffer,
 			    hb_font_t         *font)
 {
@@ -280,7 +278,7 @@ update_consonant_positions (const hb_ot_map_t *map,
     default:			virama = 0;      break;
   }
 
-  indic_shape_plan_t indic_plan (map);
+  indic_shape_plan_t indic_plan (plan);
 
   unsigned int consonant_pos = indic_plan.is_old_spec ? 0 : 1;
   hb_codepoint_t glyphs[2];
@@ -303,7 +301,7 @@ update_consonant_positions (const hb_ot_map_t *map,
  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
 
 static void
-initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *basic_mask_array,
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_mask_t *basic_mask_array,
 				       unsigned int start, unsigned int end)
 {
   hb_glyph_info_t *info = buffer->info;
@@ -508,7 +506,7 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
 
   /* For old-style Indic script tags, move the first post-base Halant after
    * last consonant. */
-  if (IS_OLD_INDIC_TAG (map->get_chosen_script (0))) {
+  if (IS_OLD_INDIC_TAG (plan->map.get_chosen_script (0))) {
     for (unsigned int i = base + 1; i < end; i++)
       if (info[i].indic_category() == OT_H) {
         unsigned int j;
@@ -650,17 +648,17 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
 
 
 static void
-initial_reordering_vowel_syllable (const hb_ot_map_t *map,
+initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
 				   hb_buffer_t *buffer,
 				   hb_mask_t *basic_mask_array,
 				   unsigned int start, unsigned int end)
 {
   /* We made the vowels look like consonants.  So let's call the consonant logic! */
-  initial_reordering_consonant_syllable (map, buffer, basic_mask_array, start, end);
+  initial_reordering_consonant_syllable (plan, buffer, basic_mask_array, start, end);
 }
 
 static void
-initial_reordering_standalone_cluster (const hb_ot_map_t *map,
+initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
 				       hb_buffer_t *buffer,
 				       hb_mask_t *basic_mask_array,
 				       unsigned int start, unsigned int end)
@@ -677,11 +675,11 @@ initial_reordering_standalone_cluster (const hb_ot_map_t *map,
       return;
   }
 
-  initial_reordering_consonant_syllable (map, buffer, basic_mask_array, start, end);
+  initial_reordering_consonant_syllable (plan, buffer, basic_mask_array, start, end);
 }
 
 static void
-initial_reordering_non_indic (const hb_ot_map_t *map HB_UNUSED,
+initial_reordering_non_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
 			      hb_buffer_t *buffer HB_UNUSED,
 			      hb_mask_t *basic_mask_array HB_UNUSED,
 			      unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
@@ -693,18 +691,18 @@ initial_reordering_non_indic (const hb_ot_map_t *map HB_UNUSED,
 #include "hb-ot-shape-complex-indic-machine.hh"
 
 static void
-initial_reordering (const hb_ot_map_t *map,
+initial_reordering (const hb_ot_shape_plan_t *plan,
 		    hb_font_t *font,
 		    hb_buffer_t *buffer)
 {
-  update_consonant_positions (map, buffer, font);
+  update_consonant_positions (plan, buffer, font);
 
   hb_mask_t basic_mask_array[ARRAY_LENGTH (indic_basic_features)] = {0};
   unsigned int num_masks = ARRAY_LENGTH (indic_basic_features);
   for (unsigned int i = 0; i < num_masks; i++)
-    basic_mask_array[i] = map->get_1_mask (indic_basic_features[i].tag);
+    basic_mask_array[i] = plan->map.get_1_mask (indic_basic_features[i].tag);
 
-  find_syllables (map, buffer, basic_mask_array);
+  find_syllables (plan, buffer, basic_mask_array);
 }
 
 static void
@@ -1057,15 +1055,15 @@ final_reordering_syllable (hb_buffer_t *buffer,
 
 
 static void
-final_reordering (const hb_ot_map_t *map,
+final_reordering (const hb_ot_shape_plan_t *plan,
 		  hb_font_t *font HB_UNUSED,
 		  hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   if (!count) return;
 
-  hb_mask_t init_mask = map->get_1_mask (HB_TAG('i','n','i','t'));
-  hb_mask_t pref_mask = map->get_1_mask (HB_TAG('p','r','e','f'));
+  hb_mask_t init_mask = plan->map.get_1_mask (HB_TAG('i','n','i','t'));
+  hb_mask_t pref_mask = plan->map.get_1_mask (HB_TAG('p','r','e','f'));
 
   hb_glyph_info_t *info = buffer->info;
   unsigned int last = 0;
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 0c26528..da8a6db 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -44,6 +44,12 @@ struct hb_ot_shape_plan_t
   hb_segment_properties_t props;
   const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
+
+  inline void substitute_closure (hb_face_t *face, hb_set_t *glyphs) const { map.substitute_closure (this, face, glyphs); }
+  inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
+  inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); }
+
+  void finish (void) { map.finish (); }
 };
 
 struct hb_ot_shape_planner_t
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index c874fb5..67330b4 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -77,14 +77,16 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      const hb_feature_t             *user_features,
 			      unsigned int                    num_user_features)
 {
+  hb_ot_map_builder_t *map = &planner->map;
+
   switch (props->direction) {
     case HB_DIRECTION_LTR:
-      planner->map.add_bool_feature (HB_TAG ('l','t','r','a'));
-      planner->map.add_bool_feature (HB_TAG ('l','t','r','m'));
+      map->add_bool_feature (HB_TAG ('l','t','r','a'));
+      map->add_bool_feature (HB_TAG ('l','t','r','m'));
       break;
     case HB_DIRECTION_RTL:
-      planner->map.add_bool_feature (HB_TAG ('r','t','l','a'));
-      planner->map.add_bool_feature (HB_TAG ('r','t','l','m'), false);
+      map->add_bool_feature (HB_TAG ('r','t','l','a'));
+      map->add_bool_feature (HB_TAG ('r','t','l','m'), false);
       break;
     case HB_DIRECTION_TTB:
     case HB_DIRECTION_BTT:
@@ -96,7 +98,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++) \
-      planner->map.add_bool_feature (array[i]); \
+      map->add_bool_feature (array[i]); \
   } HB_STMT_END
 
   if (planner->shaper->collect_features)
@@ -116,7 +118,7 @@ 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];
-    planner->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));
   }
 }
 
@@ -183,7 +185,7 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
 void
 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *data)
 {
-  data->map.finish ();
+  data->finish ();
 
   free (data);
 }
@@ -211,7 +213,9 @@ struct hb_ot_shape_context_t
 static void
 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 {
-  hb_mask_t global_mask = c->plan->map.get_global_mask ();
+  hb_ot_map_t *map = &c->plan->map;
+
+  hb_mask_t global_mask = map->get_global_mask ();
   c->buffer->reset_masks (global_mask);
 
   if (c->plan->shaper->setup_masks)
@@ -222,7 +226,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
     const hb_feature_t *feature = &c->user_features[i];
     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
       unsigned int shift;
-      hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
+      hb_mask_t mask = map->get_mask (feature->tag, &shift);
       c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
     }
   }
@@ -352,7 +356,7 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
     hb_synthesize_glyph_classes (c);
 
   if (hb_ot_layout_has_substitution (c->face))
-    c->plan->map.substitute (c->font, c->buffer);
+    c->plan->substitute (c->font, c->buffer);
 
   hb_ot_layout_substitute_finish (c->font, c->buffer);
 
@@ -408,7 +412,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
 					       &c->buffer->pos[i].y_offset);
     }
 
-    c->plan->map.position (c->font, c->buffer);
+    c->plan->position (c->font, c->buffer);
 
     for (unsigned int i = 0; i < count; i++) {
       c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint,
@@ -588,7 +592,7 @@ hb_ot_shape_glyphs_closure (hb_font_t          *font,
 
   do {
     copy.set (glyphs);
-    HB_SHAPER_DATA_GET (shape_plan)->map.substitute_closure (font->face, glyphs);
+    HB_SHAPER_DATA_GET (shape_plan)->substitute_closure (font->face, glyphs);
   } while (!copy.equal (glyphs));
 
   hb_shape_plan_destroy (shape_plan);
commit 3e38c0f2886c38d2f0a9d80a97a36edf2479d2c7
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 09:44:18 2012 -0400

    More massaging

diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 648e5df..18517c4 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -62,15 +62,11 @@ struct hb_ot_map_t
     { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
   };
 
-  typedef void (*pause_func_t) (const hb_ot_map_t *map, hb_font_t *font, hb_buffer_t *buffer, void *user_data);
-  typedef struct {
-    pause_func_t func;
-    void *user_data;
-  } pause_callback_t;
+  typedef void (*pause_func_t) (const hb_ot_map_t *map, hb_font_t *font, hb_buffer_t *buffer);
 
   struct pause_map_t {
     unsigned int num_lookups; /* Cumulative */
-    pause_callback_t callback;
+    pause_func_t callback;
   };
 
 
@@ -156,10 +152,10 @@ struct hb_ot_map_builder_t
   inline void add_bool_feature (hb_tag_t tag, bool global = true)
   { add_feature (tag, 1, global); }
 
-  inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func, void *user_data)
-  { add_pause (0, pause_func, user_data); }
-  inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func, void *user_data)
-  { add_pause (1, pause_func, user_data); }
+  inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
+  { add_pause (0, pause_func); }
+  inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
+  { add_pause (1, pause_func); }
 
   HB_INTERNAL void compile (hb_face_t *face,
 			    const hb_segment_properties_t *props,
@@ -187,10 +183,10 @@ struct hb_ot_map_builder_t
 
   struct pause_info_t {
     unsigned int stage;
-    hb_ot_map_t::pause_callback_t callback;
+    hb_ot_map_t::pause_func_t callback;
   };
 
-  HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data);
+  HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
 
   unsigned int current_stage[2]; /* GSUB/GPOS */
   hb_prealloced_array_t<feature_info_t,16> feature_infos;
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 7192c2b..62afdef 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -87,8 +87,8 @@ void hb_ot_map_t::substitute (hb_font_t *font, hb_buffer_t *buffer) const
 
     buffer->clear_output ();
 
-    if (pause->callback.func)
-      pause->callback.func (this, font, buffer, pause->callback.user_data);
+    if (pause->callback)
+      pause->callback (this, font, buffer);
   }
 
   for (; i < lookups[table_index].len; i++)
@@ -105,8 +105,8 @@ void hb_ot_map_t::position (hb_font_t *font, hb_buffer_t *buffer) const
     for (; i < pause->num_lookups; i++)
       hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
 
-    if (pause->callback.func)
-      pause->callback.func (this, font, buffer, pause->callback.user_data);
+    if (pause->callback)
+      pause->callback (this, font, buffer);
   }
 
   for (; i < lookups[table_index].len; i++)
@@ -129,13 +129,12 @@ void hb_ot_map_t::substitute_closure (hb_face_t *face,
     hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index);
 }
 
-void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data)
+void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
 {
   pause_info_t *p = pauses[table_index].push ();
   if (likely (p)) {
     p->stage = current_stage[table_index];
-    p->callback.func = pause_func;
-    p->callback.user_data = user_data;
+    p->callback = pause_func;
   }
 
   current_stage[table_index]++;
@@ -249,8 +248,8 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
   feature_infos.shrink (0); /* Done with these */
 
 
-  add_gsub_pause (NULL, NULL);
-  add_gpos_pause (NULL, NULL);
+  add_gsub_pause (NULL);
+  add_gpos_pause (NULL);
 
   for (unsigned int table_index = 0; table_index < 2; table_index++) {
     hb_tag_t table_tag = table_tags[table_index];
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 3290ee1..d08d364 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -182,19 +182,19 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
   map->add_bool_feature (HB_TAG('c','c','m','p'));
   map->add_bool_feature (HB_TAG('l','o','c','l'));
 
-  map->add_gsub_pause (NULL, NULL);
+  map->add_gsub_pause (NULL);
 
   unsigned int num_features = plan->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
   for (unsigned int i = 0; i < num_features; i++)
     map->add_bool_feature (arabic_syriac_features[i], false);
 
-  map->add_gsub_pause (NULL, NULL);
+  map->add_gsub_pause (NULL);
 
   map->add_bool_feature (HB_TAG('r','l','i','g'));
-  map->add_gsub_pause (NULL, NULL);
+  map->add_gsub_pause (NULL);
 
   map->add_bool_feature (HB_TAG('c','a','l','t'));
-  map->add_gsub_pause (NULL, NULL);
+  map->add_gsub_pause (NULL);
 
   /* ArabicOT spec enables 'cswh' for Arabic where as for basic shaper it's disabled by default. */
   map->add_bool_feature (HB_TAG('c','s','w','h'));
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 652e4e6..6b55fb7 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -194,13 +194,11 @@ indic_other_features[] =
 static void
 initial_reordering (const hb_ot_map_t *map,
 		    hb_font_t *font,
-		    hb_buffer_t *buffer,
-		    void *user_data HB_UNUSED);
+		    hb_buffer_t *buffer);
 static void
 final_reordering (const hb_ot_map_t *map,
 		  hb_font_t *font,
-		  hb_buffer_t *buffer,
-		  void *user_data HB_UNUSED);
+		  hb_buffer_t *buffer);
 
 static void
 collect_features_indic (hb_ot_shape_planner_t *plan)
@@ -212,14 +210,14 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
    * there is a use of it, it's typically at the beginning. */
   map->add_bool_feature (HB_TAG('c','c','m','p'));
 
-  map->add_gsub_pause (initial_reordering, NULL);
+  map->add_gsub_pause (initial_reordering);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) {
     map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global);
-    map->add_gsub_pause (NULL, NULL);
+    map->add_gsub_pause (NULL);
   }
 
-  map->add_gsub_pause (final_reordering, NULL);
+  map->add_gsub_pause (final_reordering);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++)
     map->add_bool_feature (indic_other_features[i].tag, indic_other_features[i].is_global);
@@ -697,8 +695,7 @@ initial_reordering_non_indic (const hb_ot_map_t *map HB_UNUSED,
 static void
 initial_reordering (const hb_ot_map_t *map,
 		    hb_font_t *font,
-		    hb_buffer_t *buffer,
-		    void *user_data HB_UNUSED)
+		    hb_buffer_t *buffer)
 {
   update_consonant_positions (map, buffer, font);
 
@@ -1062,8 +1059,7 @@ final_reordering_syllable (hb_buffer_t *buffer,
 static void
 final_reordering (const hb_ot_map_t *map,
 		  hb_font_t *font HB_UNUSED,
-		  hb_buffer_t *buffer,
-		  void *user_data HB_UNUSED)
+		  hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   if (!count) return;
commit 16c6a27b4bffc19026944c7bea9cf0a3a8ff1d8f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 09:38:28 2012 -0400

    [OT] Port complex_shaper to planner/plan

diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 4ce09a8..3290ee1 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -165,10 +165,10 @@ static const struct arabic_state_table_entry {
 
 
 static void
-collect_features_arabic (const hb_ot_complex_shaper_t  *shaper,
-			 hb_ot_map_builder_t           *map,
-			 const hb_segment_properties_t *props)
+collect_features_arabic (hb_ot_shape_planner_t *plan)
 {
+  hb_ot_map_builder_t *map = &plan->map;
+
   /* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together,
    * then rlig and calt each in their own stage.  This makes IranNastaliq's ALLAH
    * ligature work correctly. It's unfortunate though...
@@ -184,7 +184,7 @@ collect_features_arabic (const hb_ot_complex_shaper_t  *shaper,
 
   map->add_gsub_pause (NULL, NULL);
 
-  unsigned int num_features = props->script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
+  unsigned int num_features = plan->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
   for (unsigned int i = 0; i < num_features; i++)
     map->add_bool_feature (arabic_syriac_features[i], false);
 
@@ -236,10 +236,9 @@ arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
 }
 
 static void
-setup_masks_arabic (const hb_ot_complex_shaper_t *shaper,
-		    const hb_ot_map_t            *map,
-		    hb_buffer_t                  *buffer,
-		    hb_font_t                    *font)
+setup_masks_arabic (const hb_ot_shape_plan_t *plan,
+		    hb_buffer_t              *buffer,
+		    hb_font_t                *font)
 {
   unsigned int count = buffer->len;
   unsigned int prev = 0, state = 0;
@@ -270,7 +269,7 @@ setup_masks_arabic (const hb_ot_complex_shaper_t *shaper,
   hb_mask_t total_masks = 0;
   unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
   for (unsigned int i = 0; i < num_masks; i++) {
-    mask_array[i] = map->get_1_mask (arabic_syriac_features[i]);
+    mask_array[i] = plan->map.get_1_mask (arabic_syriac_features[i]);
     total_masks |= mask_array[i];
   }
 
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 19ff048..652e4e6 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -203,10 +203,10 @@ final_reordering (const hb_ot_map_t *map,
 		  void *user_data HB_UNUSED);
 
 static void
-collect_features_indic (const hb_ot_complex_shaper_t  *shaper,
-			hb_ot_map_builder_t           *map,
-			const hb_segment_properties_t *props)
+collect_features_indic (hb_ot_shape_planner_t *plan)
 {
+  hb_ot_map_builder_t *map = &plan->map;
+
   map->add_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. */
@@ -226,21 +226,18 @@ collect_features_indic (const hb_ot_complex_shaper_t  *shaper,
 }
 
 static void
-override_features_indic (const hb_ot_complex_shaper_t  *shaper,
-			 hb_ot_map_builder_t           *map,
-			 const hb_segment_properties_t *props)
+override_features_indic (hb_ot_shape_planner_t *plan)
 {
   /* Uniscribe does not apply 'kern'. */
   if (indic_options ().uniscribe_bug_compatible)
-    map->add_feature (HB_TAG('k','e','r','n'), 0, true);
+    plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true);
 }
 
 
 static void
-setup_masks_indic (const hb_ot_complex_shaper_t *shaper,
-		   const hb_ot_map_t            *map,
-		   hb_buffer_t                  *buffer,
-		   hb_font_t                    *font HB_UNUSED)
+setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		   hb_buffer_t              *buffer,
+		   hb_font_t                *font HB_UNUSED)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
diff --git a/src/hb-ot-shape-complex-misc.cc b/src/hb-ot-shape-complex-misc.cc
index 06b873a..6ae9f50 100644
--- a/src/hb-ot-shape-complex-misc.cc
+++ b/src/hb-ot-shape-complex-misc.cc
@@ -50,13 +50,11 @@ static const hb_tag_t tibetan_features[] =
 };
 
 static void
-collect_features_default (const hb_ot_complex_shaper_t  *shaper,
-			  hb_ot_map_builder_t           *map,
-			  const hb_segment_properties_t *props)
+collect_features_default (hb_ot_shape_planner_t *plan)
 {
   const hb_tag_t *script_features = NULL;
 
-  switch ((hb_tag_t) props->script)
+  switch ((hb_tag_t) plan->props.script)
   {
     /* Unicode-1.1 additions */
     case HB_SCRIPT_HANGUL:
@@ -70,14 +68,13 @@ collect_features_default (const hb_ot_complex_shaper_t  *shaper,
   }
 
   for (; script_features && *script_features; script_features++)
-    map->add_bool_feature (*script_features);
+    plan->map.add_bool_feature (*script_features);
 }
 
 static hb_ot_shape_normalization_mode_t
-normalization_preference_default (const hb_ot_complex_shaper_t  *shaper,
-				  const hb_segment_properties_t *props)
+normalization_preference_default (const hb_ot_shape_plan_t *plan)
 {
-  switch ((hb_tag_t) props->script)
+  switch ((hb_tag_t) plan->props.script)
   {
     /* Unicode-1.1 additions */
     case HB_SCRIPT_HANGUL:
@@ -100,10 +97,9 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
 /* Thai / Lao shaper */
 
 static void
-setup_masks_thai (const hb_ot_complex_shaper_t *shaper,
-		  const hb_ot_map_t            *map,
-		  hb_buffer_t                  *buffer,
-		  hb_font_t                    *font)
+setup_masks_thai (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		  hb_buffer_t              *buffer,
+		  hb_font_t                *font HB_UNUSED)
 {
   /* The following is NOT specified in the MS OT Thai spec, however, it seems
    * to be what Uniscribe and other engines implement.  According to Eric Muller:
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index 9cdafff..e7f9697 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -29,15 +29,11 @@
 
 #include "hb-private.hh"
 
-#include "hb-ot-map-private.hh"
+#include "hb-ot-shape-private.hh"
 #include "hb-ot-shape-normalize-private.hh"
 
 
 
-/* buffer var allocations, used during the entire shaping process */
-#define unicode_props0()	var1.u8[0]
-#define unicode_props1()	var1.u8[1]
-
 /* buffer var allocations, used by complex shapers */
 #define complex_var_persistent_u8_0()	var2.u8[2]
 #define complex_var_persistent_u8_1()	var2.u8[3]
@@ -60,39 +56,33 @@ struct hb_ot_complex_shaper_t
 
   /* collect_features()
    * Called during shape_plan().
-   * Shapers should use map to add their features and callbacks.
+   * Shapers should use plan->map to add their features and callbacks.
    * May be NULL.
    */
-  void (*collect_features) (const hb_ot_complex_shaper_t  *shaper,
-			    hb_ot_map_builder_t           *map,
-			    const hb_segment_properties_t *props);
+  void (*collect_features) (hb_ot_shape_planner_t *plan);
 
   /* override_features()
    * Called during shape_plan().
-   * Shapers should use map to override features and add callbacks after
+   * Shapers should use plan->map to override features and add callbacks after
    * common features are added.
    * May be NULL.
    */
-  void (*override_features) (const hb_ot_complex_shaper_t  *shaper,
-			     hb_ot_map_builder_t           *map,
-			     const hb_segment_properties_t *props);
+  void (*override_features) (hb_ot_shape_planner_t *plan);
 
   /* normalization_preference()
-   * Called during shape_execute().
+   * Called during shape().
    */
   hb_ot_shape_normalization_mode_t
-  (*normalization_preference) (const hb_ot_complex_shaper_t  *shaper,
-			       const hb_segment_properties_t *props);
+  (*normalization_preference) (const hb_ot_shape_plan_t *plan);
 
 
   /* setup_masks()
-   * Called during shape_execute().
+   * Called during shape().
    * Shapers should use map to get feature masks and set on buffer.
    */
-  void (*setup_masks) (const hb_ot_complex_shaper_t *shaper,
-		       const hb_ot_map_t            *map,
-		       hb_buffer_t                  *buffer,
-		       hb_font_t                    *font);
+  void (*setup_masks) (const hb_ot_shape_plan_t *plan,
+		       hb_buffer_t              *buffer,
+		       hb_font_t                *font);
 
   bool zero_width_attached_marks;
 };
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 89f15be..0c26528 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -30,12 +30,19 @@
 #include "hb-private.hh"
 
 #include "hb-ot-map-private.hh"
-#include "hb-ot-shape-complex-private.hh"
+
+
+
+/* buffer var allocations, used during the entire shaping process */
+#define unicode_props0()	var1.u8[0]
+#define unicode_props1()	var1.u8[1]
+
 
 
 struct hb_ot_shape_plan_t
 {
-  const hb_ot_complex_shaper_t *shaper;
+  hb_segment_properties_t props;
+  const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
 };
 
@@ -44,7 +51,7 @@ struct hb_ot_shape_planner_t
   /* In the order that they are filled in. */
   hb_face_t *face;
   hb_segment_properties_t props;
-  const hb_ot_complex_shaper_t *shaper;
+  const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_builder_t map;
 
   hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
@@ -56,6 +63,7 @@ struct hb_ot_shape_planner_t
 
   inline void compile (hb_ot_shape_plan_t &plan)
   {
+    plan.props = props;
     plan.shaper = shaper;
     map.compile (face, &props, plan.map);
   }
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index f6d7a83..c874fb5 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -33,6 +33,7 @@
 
 #include "hb-ot-shape-private.hh"
 #include "hb-ot-shape-normalize-private.hh"
+#include "hb-ot-shape-complex-private.hh"
 
 #include "hb-ot-layout-private.hh"
 #include "hb-set-private.hh"
@@ -99,7 +100,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
   } HB_STMT_END
 
   if (planner->shaper->collect_features)
-    planner->shaper->collect_features (planner->shaper, &planner->map, props);
+    planner->shaper->collect_features (planner);
 
   ADD_FEATURES (common_features);
 
@@ -109,7 +110,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
     ADD_FEATURES (vertical_features);
 
   if (planner->shaper->override_features)
-    planner->shaper->override_features (planner->shaper, &planner->map, props);
+    planner->shaper->override_features (planner);
 
 #undef ADD_FEATURES
 
@@ -214,7 +215,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
   c->buffer->reset_masks (global_mask);
 
   if (c->plan->shaper->setup_masks)
-    c->plan->shaper->setup_masks (c->plan->shaper, &c->plan->map, c->buffer, c->font);
+    c->plan->shaper->setup_masks (c->plan, c->buffer, c->font);
 
   for (unsigned int i = 0; i < c->num_user_features; i++)
   {
@@ -503,7 +504,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
 
   _hb_ot_shape_normalize (c->font, c->buffer,
 			  c->plan->shaper->normalization_preference ?
-			  c->plan->shaper->normalization_preference (c->plan->shaper, &c->buffer->props) :
+			  c->plan->shaper->normalization_preference (c->plan) :
 			  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT);
 
   hb_ot_shape_setup_masks (c);
commit 5393e3a62ba09fd7bcf3767b36225c8f49badb9d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Aug 2 09:24:35 2012 -0400

    [OT] Minor refactoring

diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 03c9ba1..7192c2b 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -28,8 +28,6 @@
 
 #include "hb-ot-map-private.hh"
 
-#include "hb-ot-shape-private.hh"
-
 
 void
 hb_ot_map_t::add_lookups (hb_face_t    *face,
@@ -303,5 +301,3 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
     }
   }
 }
-
-
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index fd45e2d..89f15be 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -35,11 +35,37 @@
 
 struct hb_ot_shape_plan_t
 {
+  const hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
+};
+
+struct hb_ot_shape_planner_t
+{
+  /* In the order that they are filled in. */
+  hb_face_t *face;
+  hb_segment_properties_t props;
   const hb_ot_complex_shaper_t *shaper;
+  hb_ot_map_builder_t map;
+
+  hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
+			 face (master_plan->face),
+			 props (master_plan->props),
+			 shaper (NULL),
+			 map () {}
+  ~hb_ot_shape_planner_t (void) { map.finish (); }
+
+  inline void compile (hb_ot_shape_plan_t &plan)
+  {
+    plan.shaper = shaper;
+    map.compile (face, &props, plan.map);
+  }
+
+  private:
+  NO_COPY (hb_ot_shape_planner_t);
 };
 
 
+
 inline void
 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 {
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 66664c5..f6d7a83 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -70,26 +70,6 @@ hb_tag_t vertical_features[] = {
 
 
 
-struct hb_ot_shape_planner_t
-{
-  hb_ot_map_builder_t map;
-  const hb_ot_complex_shaper_t *shaper;
-
-  hb_ot_shape_planner_t (void) : map () {}
-  ~hb_ot_shape_planner_t (void) { map.finish (); }
-
-  inline void compile (hb_face_t *face,
-		       const hb_segment_properties_t *props,
-		       hb_ot_shape_plan_t &plan)
-  {
-    plan.shaper = shaper;
-    map.compile (face, props, plan.map);
-  }
-
-  private:
-  NO_COPY (hb_ot_shape_planner_t);
-};
-
 static void
 hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      const hb_segment_properties_t  *props,
@@ -188,15 +168,13 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
   if (unlikely (!data))
     return NULL;
 
-  hb_ot_shape_planner_t planner;
-
-  assert (HB_DIRECTION_IS_VALID (shape_plan->props.direction));
+  hb_ot_shape_planner_t planner (shape_plan);
 
   planner.shaper = hb_ot_shape_complex_categorize (&shape_plan->props);
 
   hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
 
-  planner.compile (shape_plan->face, &shape_plan->props, *data);
+  planner.compile (*data);
 
   return data;
 }
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index a478ba5..974c370 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -90,6 +90,8 @@ hb_shape_plan_create (hb_face_t                     *face,
 		      unsigned int                   num_user_features,
 		      const char * const            *shaper_list)
 {
+  assert (props->direction != HB_DIRECTION_INVALID);
+
   hb_shape_plan_t *shape_plan;
 
   if (unlikely (!face))
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index b3d373b..5aa587b 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -87,8 +87,6 @@ hb_shape_full (hb_font_t          *font,
 
   buffer->guess_properties ();
 
-  assert (buffer->props.direction != HB_DIRECTION_INVALID);
-
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);



More information about the HarfBuzz mailing list