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

Behdad Esfahbod behdad at kemper.freedesktop.org
Thu Oct 17 10:53:16 PDT 2013


 src/hb-ot-layout-common-private.hh   |    2 
 src/hb-ot-layout-gsub-table.hh       |   20 +--
 src/hb-ot-layout-gsubgpos-private.hh |   85 +++++++--------
 src/hb-ot-layout.cc                  |    4 
 src/hb-ot-shape-complex-indic.cc     |  191 +++++++++++++++++++++--------------
 src/hb-ot-shape-complex-private.hh   |    4 
 src/hb-ot-shape-complex-sea.cc       |    2 
 7 files changed, 176 insertions(+), 132 deletions(-)

New commits:
commit 8f9ec92dfce5c469fb85ad301296b5dde1b2ab0a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 19:52:47 2013 +0200

    [indic] Adjust Javanese base algorithm

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 587977b..bc79025 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -323,7 +323,7 @@ static const indic_config_t indic_configs[] =
   {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_LAST_SINHALA,
 						    REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
   {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
-  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
 };
 
 
commit 49901862e36e1c153835877a9f1183729333bbbe
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 19:48:51 2013 +0200

    [otlayout] Guard against use of ReverseChain through Context

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index a595a4b..28ba3b9 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1037,7 +1037,9 @@ struct ReverseChainSingleSubstFormat1
 			 1))
     {
       c->replace_glyph_inplace (substitute[index]);
-      c->buffer->idx--; /* Reverse! */
+      /* Note: We DON'T decrease buffer->idx.  The main loop does it
+       * for us.  This is useful for preventing surprises if someone
+       * calls us through a Context lookup. */
       return TRACE_RETURN (true);
     }
 
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 5f3eb57..06c98d2 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -867,8 +867,8 @@ apply_string (OT::hb_apply_context_t *c,
 	  (c->buffer->cur().mask & c->lookup_mask) &&
 	  apply_once (c, lookup))
 	ret = true;
-      else
-	c->buffer->idx--;
+      /* The reverse lookup doesn't "advance" cursor (for good reason). */
+      c->buffer->idx--;
 
     }
     while ((int) c->buffer->idx >= 0);
commit 74f4bbf0560a5fd2d295e100e96f0c6c7033e852
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 19:07:53 2013 +0200

    [indic] Towards supporting atomicly-encoded prebase-reorderings

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index e1f64d1..587977b 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -273,12 +273,12 @@ enum base_position_t {
   BASE_POS_LAST
 };
 enum reph_position_t {
-  REPH_POS_DONT_CARE   = POS_RA_TO_BECOME_REPH,
   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
+  REPH_POS_AFTER_POST  = POS_AFTER_POST,
+  REPH_POS_DONT_CARE   = POS_RA_TO_BECOME_REPH
 };
 enum reph_mode_t {
   REPH_MODE_IMPLICIT,  /* Reph formed out of initial Ra,H sequence. */
@@ -290,6 +290,11 @@ enum blwf_mode_t {
   BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
   BLWF_MODE_POST_ONLY     /* Below-forms feature applied to post-base only. */
 };
+enum pref_len_t {
+  PREF_LEN_1 = 1,
+  PREF_LEN_2 = 2,
+  PREF_LEN_DONT_CARE = PREF_LEN_2
+};
 struct indic_config_t
 {
   hb_script_t     script;
@@ -299,25 +304,26 @@ struct indic_config_t
   reph_position_t reph_pos;
   reph_mode_t     reph_mode;
   blwf_mode_t     blwf_mode;
+  pref_len_t      pref_len;
 };
 
 static const indic_config_t indic_configs[] =
 {
   /* Default.  Should be first. */
-  {HB_SCRIPT_INVALID,	false,     0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_BENGALI,	true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_GURMUKHI,	true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_GUJARATI,	true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_ORIYA,	true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_TAMIL,	true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_TELUGU,	true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
-  {HB_SCRIPT_KANNADA,	true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
-  {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_INVALID,	false,     0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+  {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_BENGALI,	true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_GURMUKHI,	true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_GUJARATI,	true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_ORIYA,	true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_TAMIL,	true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_TELUGU,	true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY,    PREF_LEN_2},
+  {HB_SCRIPT_KANNADA,	true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY,    PREF_LEN_2},
+  {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
   {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_LAST_SINHALA,
-						    REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
+						    REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
 };
 
 
@@ -588,8 +594,12 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
   if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
       indic_plan->pstf.would_substitute (glyphs+1, 2, face))
     return POS_POST_C;
-  if (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
-      indic_plan->pref.would_substitute (glyphs+1, 2, face))
+  unsigned int pref_len = indic_plan->config->pref_len;
+  if ((pref_len == PREF_LEN_2 &&
+       (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
+        indic_plan->pref.would_substitute (glyphs+1, 2, face)))
+   || (pref_len == PREF_LEN_1 &&
+       indic_plan->pref.would_substitute (glyphs+1, 1, face)))
     return POS_POST_C;
   return POS_BASE_C;
 }
@@ -1068,15 +1078,19 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
       }
   }
 
-  if (indic_plan->mask_array[PREF] && base + 2 < end)
+  unsigned int pref_len = indic_plan->config->pref_len;
+  if (indic_plan->mask_array[PREF] && base + pref_len < end)
   {
+    assert (1 <= pref_len && pref_len <= 2);
     /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
-    for (unsigned int i = base + 1; i + 1 < end; i++) {
-      hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint};
-      if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face))
+    for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
+      hb_codepoint_t glyphs[2];
+      for (unsigned int j = 0; j < pref_len; j++)
+        glyphs[j] = info[i + j].codepoint;
+      if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
       {
-	info[i++].mask |= indic_plan->mask_array[PREF];
-	info[i++].mask |= indic_plan->mask_array[PREF];
+	for (unsigned int j = 0; j < pref_len; j++)
+	  info[i++].mask |= indic_plan->mask_array[PREF];
 
 	/* Mark the subsequent stuff with 'cfar'.  Used in Khmer.
 	 * Read the feature spec.
@@ -1084,8 +1098,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 	 * U+1784,U+17D2,U+179A,U+17D2,U+1782
 	 * U+1784,U+17D2,U+1782,U+17D2,U+179A
 	 */
-	for (; i < end; i++)
-	  info[i].mask |= indic_plan->mask_array[CFAR];
+	if (indic_plan->mask_array[CFAR])
+	  for (; i < end; i++)
+	    info[i].mask |= indic_plan->mask_array[CFAR];
 
 	break;
       }
commit efed40b975110d78c9c505441e7e17a8c13e85c8
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 18:50:11 2013 +0200

    [indic] Minor refactoring of reph handling

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 8c3e1e0..e1f64d1 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -273,8 +273,7 @@ enum base_position_t {
   BASE_POS_LAST
 };
 enum reph_position_t {
-  REPH_POS_DEFAULT     = POS_BEFORE_POST,
-
+  REPH_POS_DONT_CARE   = POS_RA_TO_BECOME_REPH,
   REPH_POS_AFTER_MAIN  = POS_AFTER_MAIN,
   REPH_POS_BEFORE_SUB  = POS_BEFORE_SUB,
   REPH_POS_AFTER_SUB   = POS_AFTER_SUB,
@@ -305,7 +304,7 @@ struct indic_config_t
 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, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_INVALID,	false,     0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
   {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
   {HB_SCRIPT_BENGALI,	true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
   {HB_SCRIPT_GURMUKHI,	true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
@@ -317,8 +316,8 @@ static const indic_config_t indic_configs[] =
   {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
   {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_LAST_SINHALA,
 						    REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT,    REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
 };
 
 
@@ -702,7 +701,8 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
      *    and has more than one consonant, Ra is excluded from candidates for
      *    base consonants. */
     unsigned int limit = start;
-    if (indic_plan->mask_array[RPHF] &&
+    if (indic_plan->config->reph_pos != POS_RA_TO_BECOME_REPH &&
+	indic_plan->mask_array[RPHF] &&
 	start + 3 <= end &&
 	(
 	 (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
@@ -816,6 +816,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 	/* The first consonant is always the base. */
 
 	assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
+	assert (!has_reph);
 
 	base = start;
 
@@ -1394,6 +1395,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
     unsigned int new_reph_pos;
     reph_position_t reph_pos = indic_plan->config->reph_pos;
 
+    assert (reph_pos != POS_RA_TO_BECOME_REPH);
 
     /*       1. If reph should be positioned after post-base consonant forms,
      *          proceed to step 5.
diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc
index 9c0c303..da687ed 100644
--- a/src/hb-ot-shape-complex-sea.cc
+++ b/src/hb-ot-shape-complex-sea.cc
@@ -266,7 +266,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
   switch (syllable_type) {
   case consonant_syllable:	initial_reordering_consonant_syllable  (plan, face, buffer, start, end); return;
   case broken_cluster:		initial_reordering_broken_cluster      (plan, face, buffer, start, end); return;
-  case non_sea_cluster:	initial_reordering_non_sea_cluster (plan, face, buffer, start, end); return;
+  case non_sea_cluster:		initial_reordering_non_sea_cluster     (plan, face, buffer, start, end); return;
   }
 }
 
commit 684fe59ff858a0ecba71b3ed80378afb0b8bbb48
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 18:30:06 2013 +0200

    [indic] Minor refactoring of would_substitute()

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 81079bc..8c3e1e0 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -568,7 +568,8 @@ data_destroy_indic (void *data)
 
 static indic_position_t
 consonant_position_from_face (const indic_shape_plan_t *indic_plan,
-			      const hb_codepoint_t glyphs[2],
+			      const hb_codepoint_t consonant,
+			      const hb_codepoint_t virama,
 			      hb_face_t *face)
 {
   /* For old-spec, the order of glyphs is Consonant,Virama,
@@ -581,15 +582,15 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
    * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
    * table).  As such, we simply match both sequences.  Seems
    * to work. */
-  hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]};
+  hb_codepoint_t glyphs[3] = {virama, consonant, virama};
   if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
-      indic_plan->blwf.would_substitute (glyphs_r, 2, face))
+      indic_plan->blwf.would_substitute (glyphs+1, 2, face))
     return POS_BELOW_C;
   if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
-      indic_plan->pstf.would_substitute (glyphs_r, 2, face))
+      indic_plan->pstf.would_substitute (glyphs+1, 2, face))
     return POS_POST_C;
   if (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
-      indic_plan->pref.would_substitute (glyphs_r, 2, face))
+      indic_plan->pref.would_substitute (glyphs+1, 2, face))
     return POS_POST_C;
   return POS_BASE_C;
 }
@@ -652,15 +653,15 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
   if (indic_plan->config->base_pos != BASE_POS_LAST)
     return;
 
-  hb_codepoint_t glyphs[2];
-  if (indic_plan->get_virama_glyph (font, &glyphs[0]))
+  hb_codepoint_t virama;
+  if (indic_plan->get_virama_glyph (font, &virama))
   {
     hb_face_t *face = font->face;
     unsigned int count = buffer->len;
     for (unsigned int i = 0; i < count; i++)
       if (buffer->info[i].indic_position() == POS_BASE_C) {
-	glyphs[1] = buffer->info[i].codepoint;
-	buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, face);
+	hb_codepoint_t consonant = buffer->info[i].codepoint;
+	buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
       }
   }
 }
commit 321df83fb4f0b8a5310888129cb70bfda8ae0c96
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 18:16:14 2013 +0200

    Route Buginese through the SEA shaper
    
    Both Indic and SEA seem to do it just fine, but SEA is much
    simpler.

diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index a099e05..ac0072b 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -279,9 +279,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
     /* Unicode-3.0 additions */
     case HB_SCRIPT_SINHALA:
 
-    /* Unicode-4.1 additions */
-    case HB_SCRIPT_BUGINESE:
-
     /* Unicode-5.0 additions */
     case HB_SCRIPT_BALINESE:
 
@@ -336,6 +333,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
 	return &_hb_ot_complex_shaper_default;
 
     /* Unicode-4.1 additions */
+    case HB_SCRIPT_BUGINESE:
     case HB_SCRIPT_NEW_TAI_LUE:
 
     /* Unicode-5.1 additions */
commit b5a0f69e47ace468b06e21cf069a18ddcfcf6064
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 18:04:23 2013 +0200

    [indic] Pass zero-context=false to would_substitute for newer scripts
    
    For scripts without an old/new spec distinction, use zero-context=false.
    This changes behavior in Sinhala / Khmer, but doesn't seem to regress.
    This will be useful and used in Javanese.

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 42549ed..81079bc 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -468,8 +468,9 @@ override_features_indic (hb_ot_shape_planner_t *plan)
 
 struct would_substitute_feature_t
 {
-  inline void init (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, bool zero_context_)
   {
+    zero_context = zero_context_;
     map->get_stage_lookups (0/*GSUB*/,
 			    map->get_feature_stage (0/*GSUB*/, feature_tag),
 			    &lookups, &count);
@@ -477,7 +478,6 @@ struct would_substitute_feature_t
 
   inline bool would_substitute (const hb_codepoint_t *glyphs,
 				unsigned int          glyphs_count,
-				bool                  zero_context,
 				hb_face_t            *face) const
   {
     for (unsigned int i = 0; i < count; i++)
@@ -489,6 +489,7 @@ struct would_substitute_feature_t
   private:
   const hb_ot_map_t::lookup_map_t *lookups;
   unsigned int count;
+  bool zero_context;
 };
 
 struct indic_shape_plan_t
@@ -544,10 +545,13 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
   indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2');
   indic_plan->virama_glyph = (hb_codepoint_t) -1;
 
-  indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'));
-  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'));
+  /* Use zero-context would_substitute() matching for new-spec of the main
+   * Indic scripts, but not for old-spec or scripts with one spec only. */
+  bool zero_context = indic_plan->config->has_old_spec || !indic_plan->is_old_spec;
+  indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
+  indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
+  indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
+  indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
     indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
@@ -577,16 +581,15 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
    * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
    * table).  As such, we simply match both sequences.  Seems
    * to work. */
-  bool zero_context = indic_plan->is_old_spec ? false : true;
   hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]};
-  if (indic_plan->blwf.would_substitute (glyphs  , 2, zero_context, face) ||
-      indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face))
+  if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->blwf.would_substitute (glyphs_r, 2, face))
     return POS_BELOW_C;
-  if (indic_plan->pstf.would_substitute (glyphs  , 2, zero_context, face) ||
-      indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face))
+  if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->pstf.would_substitute (glyphs_r, 2, face))
     return POS_POST_C;
-  if (indic_plan->pref.would_substitute (glyphs  , 2, zero_context, face) ||
-      indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face))
+  if (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
+      indic_plan->pref.would_substitute (glyphs_r, 2, face))
     return POS_POST_C;
   return POS_BASE_C;
 }
@@ -707,7 +710,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
     {
       /* See if it matches the 'rphf' feature. */
       hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint};
-      if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face))
+      if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face))
       {
 	limit += 2;
 	while (limit < end && is_joiner (info[limit]))
@@ -1068,7 +1071,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
     /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
     for (unsigned int i = base + 1; i + 1 < end; i++) {
       hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint};
-      if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face))
+      if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face))
       {
 	info[i++].mask |= indic_plan->mask_array[PREF];
 	info[i++].mask |= indic_plan->mask_array[PREF];
@@ -1734,7 +1737,7 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
 
     if (hb_options ().uniscribe_bug_compatible ||
 	(c->font->get_glyph (ab, 0, &glyph) &&
-	 indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face)))
+	 indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
     {
       /* Ok, safe to use Uniscribe-style decomposition. */
       *a = 0x0DD9;
commit c4e71ff36d1f86a6ea56539728a964d97217e2b6
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 17:04:47 2013 +0200

    [indic] Clean up Khmer and Sinhala base finding algorithm

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index b120a61..42549ed 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -128,14 +128,6 @@ static const hb_codepoint_t ra_chars[] = {
   0x179A, /* Khmer */		/* No Reph, Visual Repha */
 };
 
-static inline indic_position_t
-consonant_position (hb_codepoint_t  u)
-{
-  if ((u & ~0x007F) == 0x1780)
-    return POS_BELOW_C; /* In Khmer coeng model, post and below forms should not be reordered. */
-  return POS_BASE_C; /* Will recategorize later based on font lookups. */
-}
-
 static inline bool
 is_ra (hb_codepoint_t u)
 {
@@ -241,7 +233,7 @@ set_indic_properties (hb_glyph_info_t &info)
 
   if ((FLAG (cat) & CONSONANT_FLAGS))
   {
-    pos = consonant_position (u);
+    pos = POS_BASE_C;
     if (is_ra (u))
       cat = OT_Ra;
   }
@@ -654,6 +646,9 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
+  if (indic_plan->config->base_pos != BASE_POS_LAST)
+    return;
+
   hb_codepoint_t glyphs[2];
   if (indic_plan->get_virama_glyph (font, &glyphs[0]))
   {
@@ -786,7 +781,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 
       case BASE_POS_LAST_SINHALA:
       {
-	/* In scripts without half forms (eg. Khmer), the first consonant is always the base. */
+        /* Sinhala base positioning is slightly different from main Indic, in that:
+	 * 1. It's ZWJ behavior is different,
+	 * 2. We don't need to look into the font for consonant positions.
+	 */
 
 	if (!has_reph)
 	  base = limit;
@@ -794,7 +792,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 	/* 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 (is_consonant (info[i]))
 	  {
 	    if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
 	      break;
@@ -804,7 +802,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 
 	/* 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)
+	  if (is_consonant (info[i]))
 	    info[i].indic_position() = POS_BELOW_C;
       }
       break;
@@ -819,7 +817,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 
 	/* 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)
+	  if (is_consonant (info[i]))
 	    info[i].indic_position() = POS_BELOW_C;
       }
       break;
commit e10453e6fb2544724ccd7ddfdbb9de90ef9274ce
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 16:49:06 2013 +0200

    [indic] Add BASE_POS_LAST_SINHALA
    
    Previously we planted this into the mode used for Khmer.  There's not
    really much in common between the two, so separate again.

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index a0ebfef..b120a61 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -277,6 +277,7 @@ set_indic_properties (hb_glyph_info_t &info)
 
 enum base_position_t {
   BASE_POS_FIRST,
+  BASE_POS_LAST_SINHALA,
   BASE_POS_LAST
 };
 enum reph_position_t {
@@ -322,7 +323,8 @@ static const indic_config_t indic_configs[] =
   {HB_SCRIPT_TELUGU,	true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
   {HB_SCRIPT_KANNADA,	true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
   {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
-  {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_LAST_SINHALA,
+						    REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
   {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT,    REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
   {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
 };
@@ -782,7 +784,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
       }
       break;
 
-      case BASE_POS_FIRST:
+      case BASE_POS_LAST_SINHALA:
       {
 	/* In scripts without half forms (eg. Khmer), the first consonant is always the base. */
 
@@ -806,6 +808,21 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 	    info[i].indic_position() = POS_BELOW_C;
       }
       break;
+
+      case BASE_POS_FIRST:
+      {
+	/* The first consonant is always the base. */
+
+	assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
+
+	base = start;
+
+	/* 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;
     }
 
     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
commit 9ac6b01e0cd8e2d66dfc727157f45b615bc77109
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 16:27:38 2013 +0200

    [indic] Adjust Sinhala cluster merging under uniscribe
    
    Similar to 190c8f2b60af0851bf692f653c1604cfbf0561a5 but for
    Sinhala.

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 3471aa6..a0ebfef 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -463,7 +463,7 @@ override_features_indic (hb_ot_shape_planner_t *plan)
     switch ((hb_tag_t) plan->props.script)
     {
       case HB_SCRIPT_KHMER:
-	  plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
+	plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
 	break;
     }
   }
@@ -1584,13 +1584,22 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
   /*
    * Finish off the clusters and go home!
    */
-  if (hb_options ().uniscribe_bug_compatible && buffer->props.script != HB_SCRIPT_TAMIL)
+  if (hb_options ().uniscribe_bug_compatible)
   {
-    /* Uniscribe merges the entire cluster... Except for Tamil.
-     * This means, half forms are submerged into the main consonants cluster.
-     * This is unnecessary, and makes cursor positioning harder, but that's what
-     * Uniscribe does. */
-    buffer->merge_clusters (start, end);
+    switch ((hb_tag_t) plan->props.script)
+    {
+      case HB_SCRIPT_TAMIL:
+      case HB_SCRIPT_SINHALA:
+        break;
+
+      default:
+	/* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
+	 * This means, half forms are submerged into the main consonants cluster.
+	 * This is unnecessary, and makes cursor positioning harder, but that's what
+	 * Uniscribe does. */
+	buffer->merge_clusters (start, end);
+	break;
+    }
   }
 }
 
commit 3c3df9cba13fec2c35e0e7ae587d9699ac0c37f5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 13:58:31 2013 +0200

    [otlayout] Minor

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 2ba9978..f156b98 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -761,7 +761,9 @@ static inline bool match_input (hb_apply_context_t *c,
 
   if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
 
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (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);
 
@@ -783,23 +785,23 @@ static inline bool match_input (hb_apply_context_t *c,
    *   ligate with a conjunct...)
    */
 
-  bool is_mark_ligature = !!(c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+  bool is_mark_ligature = !!(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());
+  total_component_count += get_lig_num_comps (buffer->cur());
 
-  unsigned int first_lig_id = get_lig_id (c->buffer->cur());
-  unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
+  unsigned int first_lig_id = get_lig_id (buffer->cur());
+  unsigned int first_lig_comp = get_lig_comp (buffer->cur());
 
-  match_positions[0] = c->buffer->idx;
+  match_positions[0] = buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     match_positions[i] = skippy_iter.idx;
 
-    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]);
+    unsigned int this_lig_id = get_lig_id (buffer->info[skippy_iter.idx]);
+    unsigned int this_lig_comp = get_lig_comp (buffer->info[skippy_iter.idx]);
 
     if (first_lig_id && first_lig_comp) {
       /* If first component was attached to a previous ligature component,
@@ -815,11 +817,11 @@ static inline bool match_input (hb_apply_context_t *c,
 	return TRACE_RETURN (false);
     }
 
-    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]);
+    is_mark_ligature = is_mark_ligature && (buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+    total_component_count += get_lig_num_comps (buffer->info[skippy_iter.idx]);
   }
 
-  *end_offset = skippy_iter.idx - c->buffer->idx + 1;
+  *end_offset = skippy_iter.idx - buffer->idx + 1;
 
   if (p_is_mark_ligature)
     *p_is_mark_ligature = is_mark_ligature;
@@ -839,7 +841,9 @@ static inline void ligate_input (hb_apply_context_t *c,
 {
   TRACE_APPLY (NULL);
 
-  c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + match_length);
+  hb_buffer_t *buffer = c->buffer;
+
+  buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
 
   /*
    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
@@ -870,46 +874,46 @@ static inline void ligate_input (hb_apply_context_t *c,
    */
 
   unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
-  unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
-  unsigned int last_lig_id = get_lig_id (c->buffer->cur());
-  unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
+  unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (buffer);
+  unsigned int last_lig_id = get_lig_id (buffer->cur());
+  unsigned int last_num_components = get_lig_num_comps (buffer->cur());
   unsigned int components_so_far = last_num_components;
 
   if (!is_mark_ligature)
   {
-    set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
-    if (_hb_glyph_info_get_general_category (&c->buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
-      _hb_glyph_info_set_general_category (&c->buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+    set_lig_props_for_ligature (buffer->cur(), lig_id, total_component_count);
+    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
   }
   c->replace_glyph (lig_glyph, klass);
 
   for (unsigned int i = 1; i < count; i++)
   {
-    while (c->buffer->idx < match_positions[i])
+    while (buffer->idx < match_positions[i])
     {
       if (!is_mark_ligature) {
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
-	set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
+				    MIN (MAX (get_lig_comp (buffer->cur()), 1u), last_num_components);
+	set_lig_props_for_mark (buffer->cur(), lig_id, new_lig_comp);
       }
-      c->buffer->next_glyph ();
+      buffer->next_glyph ();
     }
 
-    last_lig_id = get_lig_id (c->buffer->cur());
-    last_num_components = get_lig_num_comps (c->buffer->cur());
+    last_lig_id = get_lig_id (buffer->cur());
+    last_num_components = get_lig_num_comps (buffer->cur());
     components_so_far += last_num_components;
 
     /* Skip the base glyph */
-    c->buffer->idx++;
+    buffer->idx++;
   }
 
   if (!is_mark_ligature && last_lig_id) {
     /* Re-adjust components for any marks following. */
-    for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
-      if (last_lig_id == get_lig_id (c->buffer->info[i])) {
+    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
+      if (last_lig_id == get_lig_id (buffer->info[i])) {
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
-	set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
+				    MIN (MAX (get_lig_comp (buffer->info[i]), 1u), last_num_components);
+	set_lig_props_for_mark (buffer->info[i], lig_id, new_lig_comp);
       } else
 	break;
     }
commit 6cc136f7531a45e71ea08a7dc8a2187172cb813d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 13:55:48 2013 +0200

    [otlayout] Minor

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index bc7616b..2ba9978 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -752,8 +752,8 @@ static inline bool match_input (hb_apply_context_t *c,
 				const USHORT input[], /* Array of input values--start with second glyph */
 				match_func_t match_func,
 				const void *match_data,
-				unsigned int *end_offset = NULL,
-				unsigned int match_positions[MAX_CONTEXT_LENGTH] = NULL,
+				unsigned int *end_offset,
+				unsigned int match_positions[MAX_CONTEXT_LENGTH],
 				bool *p_is_mark_ligature = NULL,
 				unsigned int *p_total_component_count = NULL)
 {
@@ -791,13 +791,12 @@ static inline bool match_input (hb_apply_context_t *c,
   unsigned int first_lig_id = get_lig_id (c->buffer->cur());
   unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
 
-  if (match_positions)
-    match_positions[0] = c->buffer->idx;
+  match_positions[0] = c->buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
-    if (match_positions)
-      match_positions[i] = skippy_iter.idx;
+
+    match_positions[i] = skippy_iter.idx;
 
     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]);
@@ -820,8 +819,7 @@ static inline bool match_input (hb_apply_context_t *c,
     total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
   }
 
-  if (end_offset)
-    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
+  *end_offset = skippy_iter.idx - c->buffer->idx + 1;
 
   if (p_is_mark_ligature)
     *p_is_mark_ligature = is_mark_ligature;
commit ba6ddc421e5e440231c2ece2db1363f8e6d2ecbf
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 13:52:51 2013 +0200

    [otlayout] Increase MAX_CONTEXT_LENGTH
    
    It's cheap.

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 8ef8424..1e75930 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -39,7 +39,7 @@ namespace OT {
 
 #define NOT_COVERED		((unsigned int) -1)
 #define MAX_NESTING_LEVEL	8
-#define MAX_CONTEXT_LENGTH	32
+#define MAX_CONTEXT_LENGTH	64
 
 
 
commit e714fe6d6a2633494cb1fa7170a32ca2638cbb51
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 13:49:51 2013 +0200

    [otlayout] Simplify ligate_input()
    
    Shouldn't change behavior at all, but is faster / more robust.

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 1588580..a595a4b 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -663,28 +663,26 @@ struct Ligature
     unsigned int count = component.len;
     if (unlikely (count < 1)) return TRACE_RETURN (false);
 
-    unsigned int end_offset = 0;
     bool is_mark_ligature = false;
     unsigned int total_component_count = 0;
 
+    unsigned int match_length = 0;
+    unsigned int match_positions[MAX_CONTEXT_LENGTH];
+
     if (likely (!match_input (c, count,
 			      &component[1],
 			      match_glyph,
 			      NULL,
-			      &end_offset,
-			      NULL,
+			      &match_length,
+			      match_positions,
 			      &is_mark_ligature,
 			      &total_component_count)))
       return TRACE_RETURN (false);
 
-    /* Deal, we are forming the ligature. */
-    c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
-
     ligate_input (c,
 		  count,
-		  &component[1],
-		  match_glyph,
-		  NULL,
+		  match_positions,
+		  match_length,
 		  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 fde6eae..bc7616b 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -832,17 +832,16 @@ static inline bool match_input (hb_apply_context_t *c,
   return TRACE_RETURN (true);
 }
 static inline void ligate_input (hb_apply_context_t *c,
-				 unsigned int count, /* Including the first glyph (not matched) */
-				 const USHORT input[], /* Array of input values--start with second glyph */
-				 match_func_t match_func,
-				 const void *match_data,
+				 unsigned int count, /* Including the first glyph */
+				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 unsigned int match_length,
 				 hb_codepoint_t lig_glyph,
 				 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;
+  TRACE_APPLY (NULL);
+
+  c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + match_length);
 
   /*
    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
@@ -888,9 +887,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)
+    while (c->buffer->idx < match_positions[i])
     {
       if (!is_mark_ligature) {
 	unsigned int new_lig_comp = components_so_far - last_num_components +
commit 6b2abdcd203204131f3017ca85c91de9d43959cd
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 13:15:43 2013 +0200

    [indic] Improve clusters in presence of reph

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 943d1f6..3471aa6 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -1375,7 +1375,6 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
     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.
@@ -1417,7 +1416,6 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
     if (reph_pos == REPH_POS_AFTER_MAIN)
     {
       new_reph_pos = base;
-      /* XXX Skip potential pre-base reordering Ra. */
       while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
 	new_reph_pos++;
       if (new_reph_pos < end)
@@ -1490,8 +1488,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
 
     reph_move:
     {
-      /* Yay, one big cluster! Merge before moving. */
-      buffer->merge_clusters (start, end);
+      buffer->merge_clusters (start, new_reph_pos + 1);
 
       /* Move */
       hb_glyph_info_t reph = info[start];
commit 42d0f55cbc68285e22d713df7062e520af708c82
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 13:05:05 2013 +0200

    [indic] Apply calt,clig in the same stage as presentation features
    
    Whic means these twp are applied per-syllable now.  Apparently
    in some Khmer fonts the clig interacts with presentation features.
    
    Test case: U+1781,U+17D2,U+1789,U+17BB,U+17C6 with Mondulkiri-R.ttf
    should produce one big ligature.

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 75d4cad..943d1f6 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -447,6 +447,10 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
   for (; i < INDIC_NUM_FEATURES; i++) {
     map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
   }
+
+  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+  map->add_global_bool_feature (HB_TAG('c','l','i','g'));
+
   map->add_gsub_pause (clear_syllables);
 }
 
commit ae9a5834df477006686421d494b55a1569789327
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 12:24:55 2013 +0200

    [indic] Fix pref vs blwf interaction
    
    If a glyph can be both blwf and pref, we were wrongly sorting it
    in the post position instead of below position.

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 07f231b..75d4cad 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -581,15 +581,15 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
    * to work. */
   bool zero_context = indic_plan->is_old_spec ? false : true;
   hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]};
-  if (indic_plan->pref.would_substitute (glyphs  , 2, zero_context, face) ||
-      indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face))
-    return POS_POST_C;
   if (indic_plan->blwf.would_substitute (glyphs  , 2, zero_context, face) ||
       indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face))
     return POS_BELOW_C;
   if (indic_plan->pstf.would_substitute (glyphs  , 2, zero_context, face) ||
       indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face))
     return POS_POST_C;
+  if (indic_plan->pref.would_substitute (glyphs  , 2, zero_context, face) ||
+      indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face))
+    return POS_POST_C;
   return POS_BASE_C;
 }
 
commit c7dacac02cfe8526eaf131ce6c5e7b6df7ca2ccd
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Oct 17 12:20:24 2013 +0200

    [indic] Don't apply blwf before base under old-spec mode
    
    Test case: U+09AC,U+09CD,U+09A6 with Lohit-Bengali 2.5.3.

diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index a98c540..07f231b 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -997,7 +997,8 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
 
     /* Pre-base */
     mask = indic_plan->mask_array[HALF];
-    if (indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
+    if (!indic_plan->is_old_spec &&
+	indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
       mask |= indic_plan->mask_array[BLWF];
     for (unsigned int i = start; i < base; i++)
       info[i].mask  |= mask;



More information about the HarfBuzz mailing list