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

Behdad Esfahbod behdad at kemper.freedesktop.org
Tue Oct 12 14:39:38 PDT 2010


 src/Makefile.am                    |    3 
 src/hb-buffer-private.hh           |   11 
 src/hb-buffer.cc                   |    5 
 src/hb-ot-map-private.hh           |   43 --
 src/hb-ot-map.cc                   |   47 +-
 src/hb-ot-shape-arabic.cc          |  706 ------------------------------------
 src/hb-ot-shape-complex-arabic.cc  |  716 +++++++++++++++++++++++++++++++++++++
 src/hb-ot-shape-complex-private.hh |   95 ++++
 src/hb-ot-shape-private.hh         |   24 -
 src/hb-ot-shape.cc                 |  103 +++--
 src/hb-ot-shape.h                  |   10 
 11 files changed, 953 insertions(+), 810 deletions(-)

New commits:
commit 758f68b860b44b5a04eb3dde5cb40b1b04cf634a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 17:37:44 2010 -0400

    Fix Arabic shaper
    
    It's tested now.  It works!

diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index d1f9f4a..74d7125 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -684,14 +684,15 @@ _hb_ot_shape_complex_setup_masks_arabic	(hb_ot_shape_context_t *c)
   unsigned int count = c->buffer->len;
   unsigned int prev = 0, state = 0;
 
-  for (unsigned int i = 0; i < count; i++) {
+  for (unsigned int i = 0; i < count; i++)
+  {
 
     unsigned int this_type = get_joining_type (c->buffer->info[i].codepoint, c->buffer->unicode->v.get_general_category (c->buffer->info[i].codepoint));
 
     if (unlikely (this_type == JOINING_TYPE_T))
       continue;
 
-    const arabic_state_table_entry *entry = arabic_state_table[state];
+    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
 
     if (entry->prev_action != NONE)
       c->buffer->info[prev].gproperty = entry->prev_action;
@@ -702,7 +703,7 @@ _hb_ot_shape_complex_setup_masks_arabic	(hb_ot_shape_context_t *c)
     state = entry->next_state;
   }
 
-  hb_mask_t mask_array[TOTAL_NUM_FEATURES] = {0};
+  hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0};
   unsigned int num_masks = c->buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
   for (unsigned int i = 0; i < num_masks; i++)
     mask_array[i] = c->plan->map.get_mask (arabic_syriac_features[i]);
commit 13403bc67a01e0d4908fb964093fd02ddd11c580
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 17:23:54 2010 -0400

    Hookup Arabic shaper!
    
    Not tested yet.

diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 5e6ce05..d1f9f4a 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-complex-private.hh"
 
 HB_BEGIN_DECLS
 
@@ -679,7 +679,7 @@ _hb_ot_shape_complex_collect_features_arabic	(hb_ot_shape_plan_t *plan, const hb
 }
 
 void
-_hb_ot_analyze_complex_arabic (hb_ot_shape_context_t *c)
+_hb_ot_shape_complex_setup_masks_arabic	(hb_ot_shape_context_t *c)
 {
   unsigned int count = c->buffer->len;
   unsigned int prev = 0, state = 0;
@@ -705,7 +705,7 @@ _hb_ot_analyze_complex_arabic (hb_ot_shape_context_t *c)
   hb_mask_t mask_array[TOTAL_NUM_FEATURES] = {0};
   unsigned int num_masks = c->buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
   for (unsigned int i = 0; i < num_masks; i++)
-    mask_array[i] = 0 /* XXX find_mask */;
+    mask_array[i] = c->plan->map.get_mask (arabic_syriac_features[i]);
 
   for (unsigned int i = 0; i < count; i++)
     c->buffer->info[i].mask |= mask_array[c->buffer->info[i].gproperty];
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index 1c605bb..a3796b4 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -29,24 +29,11 @@
 
 #include "hb-private.h"
 
-#include "hb-ot-map-private.hh"
+#include "hb-ot-shape-private.hh"
 
 HB_BEGIN_DECLS
 
 
-enum hb_ot_complex_shaper_t {
-  hb_ot_complex_shaper_none,
-  hb_ot_complex_shaper_arabic
-};
-
-
-struct hb_ot_shape_plan_t
-{
-  hb_ot_map_t map;
-  hb_ot_complex_shaper_t shaper;
-};
-
-
 static inline hb_ot_complex_shaper_t
 hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
 {
@@ -66,7 +53,9 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
 /*
  * collect_features()
  *
- * Called during planning.  Shapers should call plan->map.add_feature().
+ * Called during shape_plan().
+ *
+ * Shapers should use plan->map to add their features.
  */
 
 HB_INTERNAL void _hb_ot_shape_complex_collect_features_arabic	(hb_ot_shape_plan_t *plan, const hb_segment_properties_t  *props);
@@ -82,6 +71,24 @@ hb_ot_shape_complex_collect_features (hb_ot_shape_plan_t *plan,
 }
 
 
+/* setup_masks()
+ *
+ * Called during shape_execute().
+ *
+ * Shapers should use c->plan.map to get feature masks and set on buffer.
+ */
+
+HB_INTERNAL void _hb_ot_shape_complex_setup_masks_arabic	(hb_ot_shape_context_t *c);
+
+static inline void
+hb_ot_shape_complex_setup_masks (hb_ot_shape_context_t *c)
+{
+  switch (c->plan->shaper) {
+    case hb_ot_complex_shaper_arabic:	_hb_ot_shape_complex_setup_masks_arabic (c);	return;
+    case hb_ot_complex_shaper_none:	default:					return;
+  }
+}
+
 
 HB_END_DECLS
 
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 772b0cd..0794fbf 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -31,11 +31,23 @@
 
 #include "hb-ot-shape.h"
 
-#include "hb-ot-shape-complex-private.hh"
 #include "hb-ot-map-private.hh"
 
 HB_BEGIN_DECLS
 
+enum hb_ot_complex_shaper_t {
+  hb_ot_complex_shaper_none,
+  hb_ot_complex_shaper_arabic
+};
+
+
+struct hb_ot_shape_plan_t
+{
+  hb_ot_map_t map;
+  hb_ot_complex_shaper_t shaper;
+};
+
+
 struct hb_ot_shape_context_t
 {
   /* Input to hb_ot_shape_execute() */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 9eda177..0ce3896 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -27,6 +27,7 @@
  */
 
 #include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-complex-private.hh"
 
 HB_BEGIN_DECLS
 
@@ -95,7 +96,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
     }
   }
 
-  /* complex */
+  hb_ot_shape_complex_setup_masks (c);
 }
 
 
commit 57ac0ecb7843533b2e6e6d6c8a12b2a44437cc1c
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 17:07:02 2010 -0400

    Merge clearing masks and setting global masks

diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index d9f3d4d..8154b17 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -102,10 +102,11 @@ _hb_buffer_next_glyph (hb_buffer_t *buffer);
 
 
 HB_INTERNAL void
-_hb_buffer_clear_masks (hb_buffer_t *buffer);
+_hb_buffer_reset_masks (hb_buffer_t *buffer,
+			hb_mask_t    mask);
 
 HB_INTERNAL void
-_hb_buffer_set_masks (hb_buffer_t *buffer,
+_hb_buffer_add_masks (hb_buffer_t *buffer,
 		      hb_mask_t    value,
 		      hb_mask_t    mask,
 		      unsigned int cluster_start,
@@ -164,12 +165,12 @@ struct _hb_buffer_t {
   { _hb_buffer_add_output_glyph (this, glyph_index, component, ligID); }
   inline void replace_glyph (hb_codepoint_t glyph_index) { add_output_glyph (glyph_index); }
 
-  inline void clear_masks (void) { _hb_buffer_clear_masks (this); }
-  inline void set_masks (hb_mask_t    value,
+  inline void reset_masks (hb_mask_t mask) { _hb_buffer_reset_masks (this, mask); }
+  inline void add_masks (hb_mask_t value,
 			 hb_mask_t mask,
 			 unsigned int cluster_start,
 			 unsigned int cluster_end)
-  { _hb_buffer_set_masks (this, value, mask, cluster_start, cluster_end); }
+  { _hb_buffer_add_masks (this, value, mask, cluster_start, cluster_end); }
 
 };
 
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 047dafd..800a34d 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -460,7 +460,8 @@ _hb_buffer_next_glyph (hb_buffer_t *buffer)
 }
 
 void
-_hb_buffer_clear_masks (hb_buffer_t *buffer)
+_hb_buffer_reset_masks (hb_buffer_t *buffer,
+			hb_mask_t    mask)
 {
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
@@ -468,7 +469,7 @@ _hb_buffer_clear_masks (hb_buffer_t *buffer)
 }
 
 void
-_hb_buffer_set_masks (hb_buffer_t *buffer,
+_hb_buffer_add_masks (hb_buffer_t *buffer,
 		      hb_mask_t    value,
 		      hb_mask_t    mask,
 		      unsigned int cluster_start,
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index ea11faf..94be14f 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -63,7 +63,7 @@ void
 hb_ot_map_t::compile (hb_face_t *face,
 		      const hb_segment_properties_t *props)
 {
- global_mask = 0;
+ global_mask = 1;
  lookup_count[0] = lookup_count[1] = 0;
 
   if (!feature_count)
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index a729c3f..9eda177 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -82,11 +82,8 @@ hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan,
 static void
 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 {
-  c->buffer->clear_masks ();
-
   hb_mask_t global_mask = c->plan->map.get_global_mask ();
-  if (global_mask)
-    c->buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
+  c->buffer->reset_masks (global_mask);
 
   for (unsigned int i = 0; i < c->num_user_features; i++)
   {
@@ -94,7 +91,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
       unsigned int shift;
       hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
-      c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
+      c->buffer->add_masks (feature->value << shift, mask, feature->start, feature->end);
     }
   }
 
commit fc96596b7c1c4e62491e951a3c256fb00dcde550
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 17:00:25 2010 -0400

    Form clusters before setting masks

diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 36155df..a729c3f 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -277,10 +277,10 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
   /* Save the original direction, we use it later. */
   c->original_direction = c->buffer->props.direction;
 
-  hb_ot_shape_setup_masks (c);
-
   hb_form_clusters (c);
 
+  hb_ot_shape_setup_masks (c);
+
   /* SUBSTITUTE */
   {
     /* Mirroring needs to see the original direction */
commit 1e80782244cdb1dedae9d1e61079d0508e57ca72
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 17:00:07 2010 -0400

    Clear masks before setting them up, not after!

diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index efa71ba..36155df 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -82,6 +82,8 @@ hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan,
 static void
 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 {
+  c->buffer->clear_masks ();
+
   hb_mask_t global_mask = c->plan->map.get_global_mask ();
   if (global_mask)
     c->buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
@@ -281,8 +283,6 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
 
   /* SUBSTITUTE */
   {
-    c->buffer->clear_masks ();
-
     /* Mirroring needs to see the original direction */
     hb_mirror_chars (c);
 
@@ -298,8 +298,6 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
 
   /* POSITION */
   {
-    c->buffer->clear_masks ();
-
     hb_position_default (c);
 
     hb_ot_position_complex (c);
commit fd3d32d31cb6d74a9994b6850d539fd0b707d941
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 16:57:47 2010 -0400

    Add hb_ot_shape_execute()
    
    Not public yet.

diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index aea52af..772b0cd 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -38,7 +38,8 @@ HB_BEGIN_DECLS
 
 struct hb_ot_shape_context_t
 {
-  /* Input to hb_ot_shape() */
+  /* Input to hb_ot_shape_execute() */
+  hb_ot_shape_plan_t *plan;
   hb_font_t *font;
   hb_face_t *face;
   hb_buffer_t  *buffer;
@@ -49,8 +50,6 @@ struct hb_ot_shape_context_t
   hb_direction_t original_direction;
   hb_bool_t applied_substitute_complex;
   hb_bool_t applied_position_complex;
-
-  hb_ot_shape_plan_t *plan;
 };
 
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index b6acb22..efa71ba 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -270,7 +270,7 @@ hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
 /* Do it! */
 
 static void
-hb_ot_shape_internal (hb_ot_shape_context_t *c)
+hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
 {
   /* Save the original direction, we use it later. */
   c->original_direction = c->buffer->props.direction;
@@ -333,6 +333,18 @@ hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
 }
 
 void
+hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
+		     hb_font_t          *font,
+		     hb_face_t          *face,
+		     hb_buffer_t        *buffer,
+		     const hb_feature_t *user_features,
+		     unsigned int        num_user_features)
+{
+  hb_ot_shape_context_t c = {plan, font, face, buffer, user_features, num_user_features};
+  hb_ot_shape_execute_internal (&c);
+}
+
+void
 hb_ot_shape (hb_font_t    *font,
 	     hb_face_t    *face,
 	     hb_buffer_t  *buffer,
@@ -342,10 +354,7 @@ hb_ot_shape (hb_font_t    *font,
   hb_ot_shape_plan_t plan;
 
   hb_ot_shape_plan_internal (&plan, face, &buffer->props, user_features, num_user_features);
-
-  hb_ot_shape_context_t c = {font, face, buffer, user_features, num_user_features};
-  c.plan = &plan;
-  hb_ot_shape_internal (&c);
+  hb_ot_shape_execute (&plan, font, face, buffer, user_features, num_user_features);
 }
 
 
commit 49baa1f69efb0e3c62e45bd59dd88459a84bf390
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 16:50:36 2010 -0400

    Add hb_ot_complex_shaper_t stuff and start hooking Arabic shaper up

diff --git a/src/Makefile.am b/src/Makefile.am
index 4908876..a542ee7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,8 +50,9 @@ HBSOURCES += \
 	hb-ot-map.cc \
 	hb-ot-map-private.hh \
 	hb-ot-shape.cc \
+	hb-ot-shape-complex-arabic.cc \
+	hb-ot-shape-complex-private.hh \
 	hb-ot-shape-private.hh \
-	hb-ot-shape-arabic.cc \
 	hb-ot-tag.c \
 	$(NULL)
 HBHEADERS += \
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 0c05742..8e65f49 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -96,7 +96,7 @@ struct hb_ot_map_t {
   { add_feature (tag, 1, global); }
 
   HB_INTERNAL void compile (hb_face_t *face,
-			    hb_segment_properties_t *props);
+			    const hb_segment_properties_t *props);
 
   hb_mask_t get_global_mask (void) const { return global_mask; }
 
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 2205624..ea11faf 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -61,7 +61,7 @@ hb_ot_map_t::add_lookups (hb_face_t    *face,
 
 void
 hb_ot_map_t::compile (hb_face_t *face,
-		      hb_segment_properties_t *props)
+		      const hb_segment_properties_t *props)
 {
  global_mask = 0;
  lookup_count[0] = lookup_count[1] = 0;
diff --git a/src/hb-ot-shape-arabic.cc b/src/hb-ot-shape-arabic.cc
deleted file mode 100644
index fb5182b..0000000
--- a/src/hb-ot-shape-arabic.cc
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * Copyright (C) 2010  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb-ot-shape-private.hh"
-
-HB_BEGIN_DECLS
-
-/*
- * Bits used in the joining tables
- */
-enum {
-  JOINING_TYPE_U		= 0,
-  JOINING_TYPE_R		= 1,
-  JOINING_TYPE_D		= 2,
-  JOINING_TYPE_C		= JOINING_TYPE_D,
-  JOINING_GROUP_ALAPH		= 3,
-  JOINING_GROUP_DALATH_RISH	= 4,
-  NUM_STATE_MACHINE_COLS	= 5,
-
-  /* We deliberately don't have a JOINING_TYPE_L since that's unused in Unicode. */
-
-  JOINING_TYPE_T = 6,
-  JOINING_TYPE_X = 7, /* means: use general-category to choose between U or T. */
-};
-
-/*
- * Joining types:
- */
-
-
-/*
- * Main joining-type table, covering U+0600..U+07FF.
- * Includes Arabic, Syriac, and N'ko.
- */
-static const uint8_t arabic_syriac_nko_joining_types[0x0800 - 0x0600 + 1] =
-{
-  /*
-   * The following table is generated by running:
-   *
-   *   ./gen-arabic-joining-table.py < ArabicShaping.txt
-   *
-   * on the ArabicShaping.txt file with the header:
-   *
-   * # ArabicShaping-6.0.0.txt
-   * # Date: 2010-04-30, 13:47:00 PDT [KW]
-   */
-  /* == Start of generated table == */
-  JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0601; ARABIC SIGN SANAH; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0602; ARABIC FOOTNOTE MARKER; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0603; ARABIC SIGN SAFHA; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 0604 */
-  JOINING_TYPE_X, /* 0605 */
-  JOINING_TYPE_X, /* 0606 */
-  JOINING_TYPE_X, /* 0607 */
-  JOINING_TYPE_U, /* 0608; ARABIC RAY; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 0609 */
-  JOINING_TYPE_X, /* 060A */
-  JOINING_TYPE_U, /* 060B; AFGHANI SIGN; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 060C */
-  JOINING_TYPE_X, /* 060D */
-  JOINING_TYPE_X, /* 060E */
-  JOINING_TYPE_X, /* 060F */
-  JOINING_TYPE_X, /* 0610 */
-  JOINING_TYPE_X, /* 0611 */
-  JOINING_TYPE_X, /* 0612 */
-  JOINING_TYPE_X, /* 0613 */
-  JOINING_TYPE_X, /* 0614 */
-  JOINING_TYPE_X, /* 0615 */
-  JOINING_TYPE_X, /* 0616 */
-  JOINING_TYPE_X, /* 0617 */
-  JOINING_TYPE_X, /* 0618 */
-  JOINING_TYPE_X, /* 0619 */
-  JOINING_TYPE_X, /* 061A */
-  JOINING_TYPE_X, /* 061B */
-  JOINING_TYPE_X, /* 061C */
-  JOINING_TYPE_X, /* 061D */
-  JOINING_TYPE_X, /* 061E */
-  JOINING_TYPE_X, /* 061F */
-  JOINING_TYPE_D, /* 0620; YEH WITH RING; D; YEH */
-  JOINING_TYPE_U, /* 0621; HAMZA; U; No_Joining_Group */
-  JOINING_TYPE_R, /* 0622; MADDA ON ALEF; R; ALEF */
-  JOINING_TYPE_R, /* 0623; HAMZA ON ALEF; R; ALEF */
-  JOINING_TYPE_R, /* 0624; HAMZA ON WAW; R; WAW */
-  JOINING_TYPE_R, /* 0625; HAMZA UNDER ALEF; R; ALEF */
-  JOINING_TYPE_D, /* 0626; HAMZA ON YEH; D; YEH */
-  JOINING_TYPE_R, /* 0627; ALEF; R; ALEF */
-  JOINING_TYPE_D, /* 0628; BEH; D; BEH */
-  JOINING_TYPE_R, /* 0629; TEH MARBUTA; R; TEH MARBUTA */
-  JOINING_TYPE_D, /* 062A; TEH; D; BEH */
-  JOINING_TYPE_D, /* 062B; THEH; D; BEH */
-  JOINING_TYPE_D, /* 062C; JEEM; D; HAH */
-  JOINING_TYPE_D, /* 062D; HAH; D; HAH */
-  JOINING_TYPE_D, /* 062E; KHAH; D; HAH */
-  JOINING_TYPE_R, /* 062F; DAL; R; DAL */
-  JOINING_TYPE_R, /* 0630; THAL; R; DAL */
-  JOINING_TYPE_R, /* 0631; REH; R; REH */
-  JOINING_TYPE_R, /* 0632; ZAIN; R; REH */
-  JOINING_TYPE_D, /* 0633; SEEN; D; SEEN */
-  JOINING_TYPE_D, /* 0634; SHEEN; D; SEEN */
-  JOINING_TYPE_D, /* 0635; SAD; D; SAD */
-  JOINING_TYPE_D, /* 0636; DAD; D; SAD */
-  JOINING_TYPE_D, /* 0637; TAH; D; TAH */
-  JOINING_TYPE_D, /* 0638; ZAH; D; TAH */
-  JOINING_TYPE_D, /* 0639; AIN; D; AIN */
-  JOINING_TYPE_D, /* 063A; GHAIN; D; AIN */
-  JOINING_TYPE_D, /* 063B; KEHEH WITH 2 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 063C; KEHEH WITH 3 DOTS BELOW; D; GAF */
-  JOINING_TYPE_D, /* 063D; FARSI YEH WITH INVERTED V; D; FARSI YEH */
-  JOINING_TYPE_D, /* 063E; FARSI YEH WITH 2 DOTS ABOVE; D; FARSI YEH */
-  JOINING_TYPE_D, /* 063F; FARSI YEH WITH 3 DOTS ABOVE; D; FARSI YEH */
-  JOINING_TYPE_C, /* 0640; TATWEEL; C; No_Joining_Group */
-  JOINING_TYPE_D, /* 0641; FEH; D; FEH */
-  JOINING_TYPE_D, /* 0642; QAF; D; QAF */
-  JOINING_TYPE_D, /* 0643; KAF; D; KAF */
-  JOINING_TYPE_D, /* 0644; LAM; D; LAM */
-  JOINING_TYPE_D, /* 0645; MEEM; D; MEEM */
-  JOINING_TYPE_D, /* 0646; NOON; D; NOON */
-  JOINING_TYPE_D, /* 0647; HEH; D; HEH */
-  JOINING_TYPE_R, /* 0648; WAW; R; WAW */
-  JOINING_TYPE_D, /* 0649; ALEF MAKSURA; D; YEH */
-  JOINING_TYPE_D, /* 064A; YEH; D; YEH */
-  JOINING_TYPE_X, /* 064B */
-  JOINING_TYPE_X, /* 064C */
-  JOINING_TYPE_X, /* 064D */
-  JOINING_TYPE_X, /* 064E */
-  JOINING_TYPE_X, /* 064F */
-  JOINING_TYPE_X, /* 0650 */
-  JOINING_TYPE_X, /* 0651 */
-  JOINING_TYPE_X, /* 0652 */
-  JOINING_TYPE_X, /* 0653 */
-  JOINING_TYPE_X, /* 0654 */
-  JOINING_TYPE_X, /* 0655 */
-  JOINING_TYPE_X, /* 0656 */
-  JOINING_TYPE_X, /* 0657 */
-  JOINING_TYPE_X, /* 0658 */
-  JOINING_TYPE_X, /* 0659 */
-  JOINING_TYPE_X, /* 065A */
-  JOINING_TYPE_X, /* 065B */
-  JOINING_TYPE_X, /* 065C */
-  JOINING_TYPE_X, /* 065D */
-  JOINING_TYPE_X, /* 065E */
-  JOINING_TYPE_X, /* 065F */
-  JOINING_TYPE_X, /* 0660 */
-  JOINING_TYPE_X, /* 0661 */
-  JOINING_TYPE_X, /* 0662 */
-  JOINING_TYPE_X, /* 0663 */
-  JOINING_TYPE_X, /* 0664 */
-  JOINING_TYPE_X, /* 0665 */
-  JOINING_TYPE_X, /* 0666 */
-  JOINING_TYPE_X, /* 0667 */
-  JOINING_TYPE_X, /* 0668 */
-  JOINING_TYPE_X, /* 0669 */
-  JOINING_TYPE_X, /* 066A */
-  JOINING_TYPE_X, /* 066B */
-  JOINING_TYPE_X, /* 066C */
-  JOINING_TYPE_X, /* 066D */
-  JOINING_TYPE_D, /* 066E; DOTLESS BEH; D; BEH */
-  JOINING_TYPE_D, /* 066F; DOTLESS QAF; D; QAF */
-  JOINING_TYPE_X, /* 0670 */
-  JOINING_TYPE_R, /* 0671; HAMZAT WASL ON ALEF; R; ALEF */
-  JOINING_TYPE_R, /* 0672; WAVY HAMZA ON ALEF; R; ALEF */
-  JOINING_TYPE_R, /* 0673; WAVY HAMZA UNDER ALEF; R; ALEF */
-  JOINING_TYPE_U, /* 0674; HIGH HAMZA; U; No_Joining_Group */
-  JOINING_TYPE_R, /* 0675; HIGH HAMZA ALEF; R; ALEF */
-  JOINING_TYPE_R, /* 0676; HIGH HAMZA WAW; R; WAW */
-  JOINING_TYPE_R, /* 0677; HIGH HAMZA WAW WITH DAMMA; R; WAW */
-  JOINING_TYPE_D, /* 0678; HIGH HAMZA YEH; D; YEH */
-  JOINING_TYPE_D, /* 0679; TEH WITH SMALL TAH; D; BEH */
-  JOINING_TYPE_D, /* 067A; TEH WITH 2 DOTS VERTICAL ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 067B; BEH WITH 2 DOTS VERTICAL BELOW; D; BEH */
-  JOINING_TYPE_D, /* 067C; TEH WITH RING; D; BEH */
-  JOINING_TYPE_D, /* 067D; TEH WITH 3 DOTS ABOVE DOWNWARD; D; BEH */
-  JOINING_TYPE_D, /* 067E; TEH WITH 3 DOTS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 067F; TEH WITH 4 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0680; BEH WITH 4 DOTS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0681; HAMZA ON HAH; D; HAH */
-  JOINING_TYPE_D, /* 0682; HAH WITH 2 DOTS VERTICAL ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 0683; HAH WITH MIDDLE 2 DOTS; D; HAH */
-  JOINING_TYPE_D, /* 0684; HAH WITH MIDDLE 2 DOTS VERTICAL; D; HAH */
-  JOINING_TYPE_D, /* 0685; HAH WITH 3 DOTS ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 0686; HAH WITH MIDDLE 3 DOTS DOWNWARD; D; HAH */
-  JOINING_TYPE_D, /* 0687; HAH WITH MIDDLE 4 DOTS; D; HAH */
-  JOINING_TYPE_R, /* 0688; DAL WITH SMALL TAH; R; DAL */
-  JOINING_TYPE_R, /* 0689; DAL WITH RING; R; DAL */
-  JOINING_TYPE_R, /* 068A; DAL WITH DOT BELOW; R; DAL */
-  JOINING_TYPE_R, /* 068B; DAL WITH DOT BELOW AND SMALL TAH; R; DAL */
-  JOINING_TYPE_R, /* 068C; DAL WITH 2 DOTS ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 068D; DAL WITH 2 DOTS BELOW; R; DAL */
-  JOINING_TYPE_R, /* 068E; DAL WITH 3 DOTS ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 068F; DAL WITH 3 DOTS ABOVE DOWNWARD; R; DAL */
-  JOINING_TYPE_R, /* 0690; DAL WITH 4 DOTS ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 0691; REH WITH SMALL TAH; R; REH */
-  JOINING_TYPE_R, /* 0692; REH WITH SMALL V; R; REH */
-  JOINING_TYPE_R, /* 0693; REH WITH RING; R; REH */
-  JOINING_TYPE_R, /* 0694; REH WITH DOT BELOW; R; REH */
-  JOINING_TYPE_R, /* 0695; REH WITH SMALL V BELOW; R; REH */
-  JOINING_TYPE_R, /* 0696; REH WITH DOT BELOW AND DOT ABOVE; R; REH */
-  JOINING_TYPE_R, /* 0697; REH WITH 2 DOTS ABOVE; R; REH */
-  JOINING_TYPE_R, /* 0698; REH WITH 3 DOTS ABOVE; R; REH */
-  JOINING_TYPE_R, /* 0699; REH WITH 4 DOTS ABOVE; R; REH */
-  JOINING_TYPE_D, /* 069A; SEEN WITH DOT BELOW AND DOT ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 069B; SEEN WITH 3 DOTS BELOW; D; SEEN */
-  JOINING_TYPE_D, /* 069C; SEEN WITH 3 DOTS BELOW AND 3 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 069D; SAD WITH 2 DOTS BELOW; D; SAD */
-  JOINING_TYPE_D, /* 069E; SAD WITH 3 DOTS ABOVE; D; SAD */
-  JOINING_TYPE_D, /* 069F; TAH WITH 3 DOTS ABOVE; D; TAH */
-  JOINING_TYPE_D, /* 06A0; AIN WITH 3 DOTS ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 06A1; DOTLESS FEH; D; FEH */
-  JOINING_TYPE_D, /* 06A2; FEH WITH DOT MOVED BELOW; D; FEH */
-  JOINING_TYPE_D, /* 06A3; FEH WITH DOT BELOW; D; FEH */
-  JOINING_TYPE_D, /* 06A4; FEH WITH 3 DOTS ABOVE; D; FEH */
-  JOINING_TYPE_D, /* 06A5; FEH WITH 3 DOTS BELOW; D; FEH */
-  JOINING_TYPE_D, /* 06A6; FEH WITH 4 DOTS ABOVE; D; FEH */
-  JOINING_TYPE_D, /* 06A7; QAF WITH DOT ABOVE; D; QAF */
-  JOINING_TYPE_D, /* 06A8; QAF WITH 3 DOTS ABOVE; D; QAF */
-  JOINING_TYPE_D, /* 06A9; KEHEH; D; GAF */
-  JOINING_TYPE_D, /* 06AA; SWASH KAF; D; SWASH KAF */
-  JOINING_TYPE_D, /* 06AB; KAF WITH RING; D; GAF */
-  JOINING_TYPE_D, /* 06AC; KAF WITH DOT ABOVE; D; KAF */
-  JOINING_TYPE_D, /* 06AD; KAF WITH 3 DOTS ABOVE; D; KAF */
-  JOINING_TYPE_D, /* 06AE; KAF WITH 3 DOTS BELOW; D; KAF */
-  JOINING_TYPE_D, /* 06AF; GAF; D; GAF */
-  JOINING_TYPE_D, /* 06B0; GAF WITH RING; D; GAF */
-  JOINING_TYPE_D, /* 06B1; GAF WITH 2 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 06B2; GAF WITH 2 DOTS BELOW; D; GAF */
-  JOINING_TYPE_D, /* 06B3; GAF WITH 2 DOTS VERTICAL BELOW; D; GAF */
-  JOINING_TYPE_D, /* 06B4; GAF WITH 3 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 06B5; LAM WITH SMALL V; D; LAM */
-  JOINING_TYPE_D, /* 06B6; LAM WITH DOT ABOVE; D; LAM */
-  JOINING_TYPE_D, /* 06B7; LAM WITH 3 DOTS ABOVE; D; LAM */
-  JOINING_TYPE_D, /* 06B8; LAM WITH 3 DOTS BELOW; D; LAM */
-  JOINING_TYPE_D, /* 06B9; NOON WITH DOT BELOW; D; NOON */
-  JOINING_TYPE_D, /* 06BA; DOTLESS NOON; D; NOON */
-  JOINING_TYPE_D, /* 06BB; DOTLESS NOON WITH SMALL TAH; D; NOON */
-  JOINING_TYPE_D, /* 06BC; NOON WITH RING; D; NOON */
-  JOINING_TYPE_D, /* 06BD; NYA; D; NYA */
-  JOINING_TYPE_D, /* 06BE; KNOTTED HEH; D; KNOTTED HEH */
-  JOINING_TYPE_D, /* 06BF; HAH WITH MIDDLE 3 DOTS DOWNWARD AND DOT ABOVE; D; HAH */
-  JOINING_TYPE_R, /* 06C0; HAMZA ON HEH; R; TEH MARBUTA */
-  JOINING_TYPE_D, /* 06C1; HEH GOAL; D; HEH GOAL */
-  JOINING_TYPE_D, /* 06C2; HAMZA ON HEH GOAL; D; HEH GOAL */
-  JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL */
-  JOINING_TYPE_R, /* 06C4; WAW WITH RING; R; WAW */
-  JOINING_TYPE_R, /* 06C5; WAW WITH BAR; R; WAW */
-  JOINING_TYPE_R, /* 06C6; WAW WITH SMALL V; R; WAW */
-  JOINING_TYPE_R, /* 06C7; WAW WITH DAMMA; R; WAW */
-  JOINING_TYPE_R, /* 06C8; WAW WITH ALEF ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 06C9; WAW WITH INVERTED SMALL V; R; WAW */
-  JOINING_TYPE_R, /* 06CA; WAW WITH 2 DOTS ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 06CB; WAW WITH 3 DOTS ABOVE; R; WAW */
-  JOINING_TYPE_D, /* 06CC; FARSI YEH; D; FARSI YEH */
-  JOINING_TYPE_R, /* 06CD; YEH WITH TAIL; R; YEH WITH TAIL */
-  JOINING_TYPE_D, /* 06CE; FARSI YEH WITH SMALL V; D; FARSI YEH */
-  JOINING_TYPE_R, /* 06CF; WAW WITH DOT ABOVE; R; WAW */
-  JOINING_TYPE_D, /* 06D0; YEH WITH 2 DOTS VERTICAL BELOW; D; YEH */
-  JOINING_TYPE_D, /* 06D1; YEH WITH 3 DOTS BELOW; D; YEH */
-  JOINING_TYPE_R, /* 06D2; YEH BARREE; R; YEH BARREE */
-  JOINING_TYPE_R, /* 06D3; HAMZA ON YEH BARREE; R; YEH BARREE */
-  JOINING_TYPE_X, /* 06D4 */
-  JOINING_TYPE_R, /* 06D5; AE; R; TEH MARBUTA */
-  JOINING_TYPE_X, /* 06D6 */
-  JOINING_TYPE_X, /* 06D7 */
-  JOINING_TYPE_X, /* 06D8 */
-  JOINING_TYPE_X, /* 06D9 */
-  JOINING_TYPE_X, /* 06DA */
-  JOINING_TYPE_X, /* 06DB */
-  JOINING_TYPE_X, /* 06DC */
-  JOINING_TYPE_U, /* 06DD; ARABIC END OF AYAH; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 06DE */
-  JOINING_TYPE_X, /* 06DF */
-  JOINING_TYPE_X, /* 06E0 */
-  JOINING_TYPE_X, /* 06E1 */
-  JOINING_TYPE_X, /* 06E2 */
-  JOINING_TYPE_X, /* 06E3 */
-  JOINING_TYPE_X, /* 06E4 */
-  JOINING_TYPE_X, /* 06E5 */
-  JOINING_TYPE_X, /* 06E6 */
-  JOINING_TYPE_X, /* 06E7 */
-  JOINING_TYPE_X, /* 06E8 */
-  JOINING_TYPE_X, /* 06E9 */
-  JOINING_TYPE_X, /* 06EA */
-  JOINING_TYPE_X, /* 06EB */
-  JOINING_TYPE_X, /* 06EC */
-  JOINING_TYPE_X, /* 06ED */
-  JOINING_TYPE_R, /* 06EE; DAL WITH INVERTED V; R; DAL */
-  JOINING_TYPE_R, /* 06EF; REH WITH INVERTED V; R; REH */
-  JOINING_TYPE_X, /* 06F0 */
-  JOINING_TYPE_X, /* 06F1 */
-  JOINING_TYPE_X, /* 06F2 */
-  JOINING_TYPE_X, /* 06F3 */
-  JOINING_TYPE_X, /* 06F4 */
-  JOINING_TYPE_X, /* 06F5 */
-  JOINING_TYPE_X, /* 06F6 */
-  JOINING_TYPE_X, /* 06F7 */
-  JOINING_TYPE_X, /* 06F8 */
-  JOINING_TYPE_X, /* 06F9 */
-  JOINING_TYPE_D, /* 06FA; SEEN WITH DOT BELOW AND 3 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 06FB; DAD WITH DOT BELOW; D; SAD */
-  JOINING_TYPE_D, /* 06FC; GHAIN WITH DOT BELOW; D; AIN */
-  JOINING_TYPE_X, /* 06FD */
-  JOINING_TYPE_X, /* 06FE */
-  JOINING_TYPE_D, /* 06FF; HEH WITH INVERTED V; D; KNOTTED HEH */
-  JOINING_TYPE_X, /* 0700 */
-  JOINING_TYPE_X, /* 0701 */
-  JOINING_TYPE_X, /* 0702 */
-  JOINING_TYPE_X, /* 0703 */
-  JOINING_TYPE_X, /* 0704 */
-  JOINING_TYPE_X, /* 0705 */
-  JOINING_TYPE_X, /* 0706 */
-  JOINING_TYPE_X, /* 0707 */
-  JOINING_TYPE_X, /* 0708 */
-  JOINING_TYPE_X, /* 0709 */
-  JOINING_TYPE_X, /* 070A */
-  JOINING_TYPE_X, /* 070B */
-  JOINING_TYPE_X, /* 070C */
-  JOINING_TYPE_X, /* 070D */
-  JOINING_TYPE_X, /* 070E */
-  JOINING_TYPE_X, /* 070F */
-  JOINING_GROUP_ALAPH, /* 0710; ALAPH; R; ALAPH */
-  JOINING_TYPE_X, /* 0711 */
-  JOINING_TYPE_D, /* 0712; BETH; D; BETH */
-  JOINING_TYPE_D, /* 0713; GAMAL; D; GAMAL */
-  JOINING_TYPE_D, /* 0714; GAMAL GARSHUNI; D; GAMAL */
-  JOINING_GROUP_DALATH_RISH, /* 0715; DALATH; R; DALATH RISH */
-  JOINING_GROUP_DALATH_RISH, /* 0716; DOTLESS DALATH RISH; R; DALATH RISH */
-  JOINING_TYPE_R, /* 0717; HE; R; HE */
-  JOINING_TYPE_R, /* 0718; WAW; R; SYRIAC WAW */
-  JOINING_TYPE_R, /* 0719; ZAIN; R; ZAIN */
-  JOINING_TYPE_D, /* 071A; HETH; D; HETH */
-  JOINING_TYPE_D, /* 071B; TETH; D; TETH */
-  JOINING_TYPE_D, /* 071C; TETH GARSHUNI; D; TETH */
-  JOINING_TYPE_D, /* 071D; YUDH; D; YUDH */
-  JOINING_TYPE_R, /* 071E; YUDH HE; R; YUDH HE */
-  JOINING_TYPE_D, /* 071F; KAPH; D; KAPH */
-  JOINING_TYPE_D, /* 0720; LAMADH; D; LAMADH */
-  JOINING_TYPE_D, /* 0721; MIM; D; MIM */
-  JOINING_TYPE_D, /* 0722; NUN; D; NUN */
-  JOINING_TYPE_D, /* 0723; SEMKATH; D; SEMKATH */
-  JOINING_TYPE_D, /* 0724; FINAL SEMKATH; D; FINAL SEMKATH */
-  JOINING_TYPE_D, /* 0725; E; D; E */
-  JOINING_TYPE_D, /* 0726; PE; D; PE */
-  JOINING_TYPE_D, /* 0727; REVERSED PE; D; REVERSED PE */
-  JOINING_TYPE_R, /* 0728; SADHE; R; SADHE */
-  JOINING_TYPE_D, /* 0729; QAPH; D; QAPH */
-  JOINING_GROUP_DALATH_RISH, /* 072A; RISH; R; DALATH RISH */
-  JOINING_TYPE_D, /* 072B; SHIN; D; SHIN */
-  JOINING_TYPE_R, /* 072C; TAW; R; TAW */
-  JOINING_TYPE_D, /* 072D; PERSIAN BHETH; D; BETH */
-  JOINING_TYPE_D, /* 072E; PERSIAN GHAMAL; D; GAMAL */
-  JOINING_GROUP_DALATH_RISH, /* 072F; PERSIAN DHALATH; R; DALATH RISH */
-  JOINING_TYPE_X, /* 0730 */
-  JOINING_TYPE_X, /* 0731 */
-  JOINING_TYPE_X, /* 0732 */
-  JOINING_TYPE_X, /* 0733 */
-  JOINING_TYPE_X, /* 0734 */
-  JOINING_TYPE_X, /* 0735 */
-  JOINING_TYPE_X, /* 0736 */
-  JOINING_TYPE_X, /* 0737 */
-  JOINING_TYPE_X, /* 0738 */
-  JOINING_TYPE_X, /* 0739 */
-  JOINING_TYPE_X, /* 073A */
-  JOINING_TYPE_X, /* 073B */
-  JOINING_TYPE_X, /* 073C */
-  JOINING_TYPE_X, /* 073D */
-  JOINING_TYPE_X, /* 073E */
-  JOINING_TYPE_X, /* 073F */
-  JOINING_TYPE_X, /* 0740 */
-  JOINING_TYPE_X, /* 0741 */
-  JOINING_TYPE_X, /* 0742 */
-  JOINING_TYPE_X, /* 0743 */
-  JOINING_TYPE_X, /* 0744 */
-  JOINING_TYPE_X, /* 0745 */
-  JOINING_TYPE_X, /* 0746 */
-  JOINING_TYPE_X, /* 0747 */
-  JOINING_TYPE_X, /* 0748 */
-  JOINING_TYPE_X, /* 0749 */
-  JOINING_TYPE_X, /* 074A */
-  JOINING_TYPE_X, /* 074B */
-  JOINING_TYPE_X, /* 074C */
-  JOINING_TYPE_R, /* 074D; SOGDIAN ZHAIN; R; ZHAIN */
-  JOINING_TYPE_D, /* 074E; SOGDIAN KHAPH; D; KHAPH */
-  JOINING_TYPE_D, /* 074F; SOGDIAN FE; D; FE */
-  JOINING_TYPE_D, /* 0750; BEH WITH 3 DOTS HORIZONTALLY BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0751; BEH WITH DOT BELOW AND 3 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0752; BEH WITH 3 DOTS POINTING UPWARDS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0753; BEH WITH 3 DOTS POINTING UPWARDS BELOW AND 2 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0754; BEH WITH 2 DOTS BELOW AND DOT ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0755; BEH WITH INVERTED SMALL V BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0756; BEH WITH SMALL V; D; BEH */
-  JOINING_TYPE_D, /* 0757; HAH WITH 2 DOTS ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 0758; HAH WITH 3 DOTS POINTING UPWARDS BELOW; D; HAH */
-  JOINING_TYPE_R, /* 0759; DAL WITH 2 DOTS VERTICALLY BELOW AND SMALL TAH; R; DAL */
-  JOINING_TYPE_R, /* 075A; DAL WITH INVERTED SMALL V BELOW; R; DAL */
-  JOINING_TYPE_R, /* 075B; REH WITH STROKE; R; REH */
-  JOINING_TYPE_D, /* 075C; SEEN WITH 4 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 075D; AIN WITH 2 DOTS ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 075E; AIN WITH 3 DOTS POINTING DOWNWARDS ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 075F; AIN WITH 2 DOTS VERTICALLY ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 0760; FEH WITH 2 DOTS BELOW; D; FEH */
-  JOINING_TYPE_D, /* 0761; FEH WITH 3 DOTS POINTING UPWARDS BELOW; D; FEH */
-  JOINING_TYPE_D, /* 0762; KEHEH WITH DOT ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 0763; KEHEH WITH 3 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 0764; KEHEH WITH 3 DOTS POINTING UPWARDS BELOW; D; GAF */
-  JOINING_TYPE_D, /* 0765; MEEM WITH DOT ABOVE; D; MEEM */
-  JOINING_TYPE_D, /* 0766; MEEM WITH DOT BELOW; D; MEEM */
-  JOINING_TYPE_D, /* 0767; NOON WITH 2 DOTS BELOW; D; NOON */
-  JOINING_TYPE_D, /* 0768; NOON WITH SMALL TAH; D; NOON */
-  JOINING_TYPE_D, /* 0769; NOON WITH SMALL V; D; NOON */
-  JOINING_TYPE_D, /* 076A; LAM WITH BAR; D; LAM */
-  JOINING_TYPE_R, /* 076B; REH WITH 2 DOTS VERTICALLY ABOVE; R; REH */
-  JOINING_TYPE_R, /* 076C; REH WITH HAMZA ABOVE; R; REH */
-  JOINING_TYPE_D, /* 076D; SEEN WITH 2 DOTS VERTICALLY ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 076E; HAH WITH SMALL TAH BELOW; D; HAH */
-  JOINING_TYPE_D, /* 076F; HAH WITH SMALL TAH AND 2 DOTS; D; HAH */
-  JOINING_TYPE_D, /* 0770; SEEN WITH SMALL TAH AND 2 DOTS; D; SEEN */
-  JOINING_TYPE_R, /* 0771; REH WITH SMALL TAH AND 2 DOTS; R; REH */
-  JOINING_TYPE_D, /* 0772; HAH WITH SMALL TAH ABOVE; D; HAH */
-  JOINING_TYPE_R, /* 0773; ALEF WITH DIGIT TWO ABOVE; R; ALEF */
-  JOINING_TYPE_R, /* 0774; ALEF WITH DIGIT THREE ABOVE; R; ALEF */
-  JOINING_TYPE_D, /* 0775; FARSI YEH WITH DIGIT TWO ABOVE; D; FARSI YEH */
-  JOINING_TYPE_D, /* 0776; FARSI YEH WITH DIGIT THREE ABOVE; D; FARSI YEH */
-  JOINING_TYPE_D, /* 0777; YEH WITH DIGIT FOUR BELOW; D; YEH */
-  JOINING_TYPE_R, /* 0778; WAW WITH DIGIT TWO ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 0779; WAW WITH DIGIT THREE ABOVE; R; WAW */
-  JOINING_TYPE_D, /* 077A; YEH BARREE WITH DIGIT TWO ABOVE; D; BURUSHASKI YEH BARREE */
-  JOINING_TYPE_D, /* 077B; YEH BARREE WITH DIGIT THREE ABOVE; D; BURUSHASKI YEH BARREE */
-  JOINING_TYPE_D, /* 077C; HAH WITH DIGIT FOUR BELOW; D; HAH */
-  JOINING_TYPE_D, /* 077D; SEEN WITH DIGIT FOUR ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 077E; SEEN WITH INVERTED V; D; SEEN */
-  JOINING_TYPE_D, /* 077F; KAF WITH 2 DOTS ABOVE; D; KAF */
-  JOINING_TYPE_X, /* 0780 */
-  JOINING_TYPE_X, /* 0781 */
-  JOINING_TYPE_X, /* 0782 */
-  JOINING_TYPE_X, /* 0783 */
-  JOINING_TYPE_X, /* 0784 */
-  JOINING_TYPE_X, /* 0785 */
-  JOINING_TYPE_X, /* 0786 */
-  JOINING_TYPE_X, /* 0787 */
-  JOINING_TYPE_X, /* 0788 */
-  JOINING_TYPE_X, /* 0789 */
-  JOINING_TYPE_X, /* 078A */
-  JOINING_TYPE_X, /* 078B */
-  JOINING_TYPE_X, /* 078C */
-  JOINING_TYPE_X, /* 078D */
-  JOINING_TYPE_X, /* 078E */
-  JOINING_TYPE_X, /* 078F */
-  JOINING_TYPE_X, /* 0790 */
-  JOINING_TYPE_X, /* 0791 */
-  JOINING_TYPE_X, /* 0792 */
-  JOINING_TYPE_X, /* 0793 */
-  JOINING_TYPE_X, /* 0794 */
-  JOINING_TYPE_X, /* 0795 */
-  JOINING_TYPE_X, /* 0796 */
-  JOINING_TYPE_X, /* 0797 */
-  JOINING_TYPE_X, /* 0798 */
-  JOINING_TYPE_X, /* 0799 */
-  JOINING_TYPE_X, /* 079A */
-  JOINING_TYPE_X, /* 079B */
-  JOINING_TYPE_X, /* 079C */
-  JOINING_TYPE_X, /* 079D */
-  JOINING_TYPE_X, /* 079E */
-  JOINING_TYPE_X, /* 079F */
-  JOINING_TYPE_X, /* 07A0 */
-  JOINING_TYPE_X, /* 07A1 */
-  JOINING_TYPE_X, /* 07A2 */
-  JOINING_TYPE_X, /* 07A3 */
-  JOINING_TYPE_X, /* 07A4 */
-  JOINING_TYPE_X, /* 07A5 */
-  JOINING_TYPE_X, /* 07A6 */
-  JOINING_TYPE_X, /* 07A7 */
-  JOINING_TYPE_X, /* 07A8 */
-  JOINING_TYPE_X, /* 07A9 */
-  JOINING_TYPE_X, /* 07AA */
-  JOINING_TYPE_X, /* 07AB */
-  JOINING_TYPE_X, /* 07AC */
-  JOINING_TYPE_X, /* 07AD */
-  JOINING_TYPE_X, /* 07AE */
-  JOINING_TYPE_X, /* 07AF */
-  JOINING_TYPE_X, /* 07B0 */
-  JOINING_TYPE_X, /* 07B1 */
-  JOINING_TYPE_X, /* 07B2 */
-  JOINING_TYPE_X, /* 07B3 */
-  JOINING_TYPE_X, /* 07B4 */
-  JOINING_TYPE_X, /* 07B5 */
-  JOINING_TYPE_X, /* 07B6 */
-  JOINING_TYPE_X, /* 07B7 */
-  JOINING_TYPE_X, /* 07B8 */
-  JOINING_TYPE_X, /* 07B9 */
-  JOINING_TYPE_X, /* 07BA */
-  JOINING_TYPE_X, /* 07BB */
-  JOINING_TYPE_X, /* 07BC */
-  JOINING_TYPE_X, /* 07BD */
-  JOINING_TYPE_X, /* 07BE */
-  JOINING_TYPE_X, /* 07BF */
-  JOINING_TYPE_X, /* 07C0 */
-  JOINING_TYPE_X, /* 07C1 */
-  JOINING_TYPE_X, /* 07C2 */
-  JOINING_TYPE_X, /* 07C3 */
-  JOINING_TYPE_X, /* 07C4 */
-  JOINING_TYPE_X, /* 07C5 */
-  JOINING_TYPE_X, /* 07C6 */
-  JOINING_TYPE_X, /* 07C7 */
-  JOINING_TYPE_X, /* 07C8 */
-  JOINING_TYPE_X, /* 07C9 */
-  JOINING_TYPE_D, /* 07CA; NKO A; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CB; NKO EE; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CC; NKO I; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CD; NKO E; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CE; NKO U; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CF; NKO OO; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D0; NKO O; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D1; NKO DAGBASINNA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D2; NKO N; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D3; NKO BA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D4; NKO PA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D5; NKO TA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D6; NKO JA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D7; NKO CHA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D8; NKO DA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D9; NKO RA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DA; NKO RRA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DB; NKO SA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DC; NKO GBA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DD; NKO FA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DE; NKO KA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DF; NKO LA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E0; NKO NA WOLOSO; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E1; NKO MA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E2; NKO NYA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E3; NKO NA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E4; NKO HA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E5; NKO WA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E6; NKO YA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E7; NKO NYA WOLOSO; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E8; NKO JONA JA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E9; NKO JONA CHA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07EA; NKO JONA RA; D; No_Joining_Group */
-  JOINING_TYPE_X, /* 07EB */
-  JOINING_TYPE_X, /* 07EC */
-  JOINING_TYPE_X, /* 07ED */
-  JOINING_TYPE_X, /* 07EE */
-  JOINING_TYPE_X, /* 07EF */
-  JOINING_TYPE_X, /* 07F0 */
-  JOINING_TYPE_X, /* 07F1 */
-  JOINING_TYPE_X, /* 07F2 */
-  JOINING_TYPE_X, /* 07F3 */
-  JOINING_TYPE_X, /* 07F4 */
-  JOINING_TYPE_X, /* 07F5 */
-  JOINING_TYPE_X, /* 07F6 */
-  JOINING_TYPE_X, /* 07F7 */
-  JOINING_TYPE_X, /* 07F8 */
-  JOINING_TYPE_X, /* 07F9 */
-  JOINING_TYPE_C, /* 07FA; NKO LAJANYALAN; C; No_Joining_Group */
-  JOINING_TYPE_X, /* 07FB */
-  JOINING_TYPE_X, /* 07FC */
-  JOINING_TYPE_X, /* 07FD */
-  JOINING_TYPE_X, /* 07FE */
-  JOINING_TYPE_X, /* 07FF */
-  /* == End of generated table == */
-  JOINING_TYPE_X
-};
-
-static unsigned int get_joining_type (hb_codepoint_t u, hb_category_t gen_cat)
-{
-  /* TODO Macroize the magic bit operations */
-
-  if (likely ((u & ~(0x0600^0x07FF)) == 0x0600)) {
-    unsigned int j_type = arabic_syriac_nko_joining_types[u - 0x0600];
-    if (likely (j_type != JOINING_TYPE_X))
-      return j_type;
-  }
-
-  if (unlikely ((u & ~(0x200C^0x200D)) == 0x200C)) {
-    return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
-  }
-
-  return ((1<<gen_cat) & ((1<<HB_CATEGORY_NON_SPACING_MARK)|(1<<HB_CATEGORY_ENCLOSING_MARK)|(1<<HB_CATEGORY_FORMAT))) ?
-	 JOINING_TYPE_T : JOINING_TYPE_U;
-}
-
-
-
-static const hb_tag_t arabic_syriac_features[] =
-{
-  HB_TAG('i','n','i','t'),
-  HB_TAG('m','e','d','i'),
-  HB_TAG('f','i','n','a'),
-  HB_TAG('i','s','o','l'),
-  /* Syriac */
-  HB_TAG('m','e','d','2'),
-  HB_TAG('f','i','n','2'),
-  HB_TAG('f','i','n','3'),
-  HB_TAG_NONE
-};
-
-
-/* Same order as the feature array */
-enum {
-  INIT,
-  MEDI,
-  FINA,
-  ISOL,
-
-  /* Syriac */
-  MED2,
-  FIN2,
-  FIN3,
-
-  NONE,
-
-  COMMON_NUM_FEATURES = 4,
-  SYRIAC_NUM_FEATURES = 7,
-  TOTAL_NUM_FEATURES = NONE
-};
-
-static const struct arabic_state_table_entry {
-	uint8_t prev_action;
-	uint8_t curr_action;
-	uint8_t next_state;
-	uint8_t padding;
-} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
-{
-  /*   jt_U,          jt_R,          jt_D,          jg_ALAPH,      jg_DALATH_RISH */
-
-  /* State 0: prev was U, not willing to join. */
-  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
-
-  /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
-  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
-
-  /* State 2: prev was D/ISOL, willing to join. */
-  { {NONE,NONE,0}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
-
-  /* State 3: prev was D/FINA, willing to join. */
-  { {NONE,NONE,0}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
-
-  /* State 4: prev was FINA ALAPH, not willing to join. */
-  { {NONE,NONE,0}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
-
-  /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
-  { {NONE,NONE,0}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
-
-  /* State 6: prev was DALATH/RISH, not willing to join. */
-  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
-};
-
-
-void
-_hb_ot_analyze_complex_arabic (hb_ot_shape_context_t *c)
-{
-  unsigned int count = c->buffer->len;
-  unsigned int prev = 0, state = 0;
-
-  for (unsigned int i = 0; i < count; i++) {
-
-    unsigned int this_type = get_joining_type (c->buffer->info[i].codepoint, c->buffer->unicode->v.get_general_category (c->buffer->info[i].codepoint));
-
-    if (unlikely (this_type == JOINING_TYPE_T))
-      continue;
-
-    const arabic_state_table_entry *entry = arabic_state_table[state];
-
-    if (entry->prev_action != NONE)
-      c->buffer->info[prev].gproperty = entry->prev_action;
-
-    c->buffer->info[i].gproperty = entry->curr_action;
-
-    prev = i;
-    state = entry->next_state;
-  }
-
-  hb_mask_t mask_array[TOTAL_NUM_FEATURES] = {0};
-  unsigned int num_masks = c->buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
-  for (unsigned int i = 0; i < num_masks; i++)
-    mask_array[i] = 0 /* XXX find_mask */;
-
-  for (unsigned int i = 0; i < count; i++)
-    c->buffer->info[i].mask |= mask_array[c->buffer->info[i].gproperty];
-}
-
-
-HB_END_DECLS
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
new file mode 100644
index 0000000..5e6ce05
--- /dev/null
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-private.hh"
+
+HB_BEGIN_DECLS
+
+/*
+ * Bits used in the joining tables
+ */
+enum {
+  JOINING_TYPE_U		= 0,
+  JOINING_TYPE_R		= 1,
+  JOINING_TYPE_D		= 2,
+  JOINING_TYPE_C		= JOINING_TYPE_D,
+  JOINING_GROUP_ALAPH		= 3,
+  JOINING_GROUP_DALATH_RISH	= 4,
+  NUM_STATE_MACHINE_COLS	= 5,
+
+  /* We deliberately don't have a JOINING_TYPE_L since that's unused in Unicode. */
+
+  JOINING_TYPE_T = 6,
+  JOINING_TYPE_X = 7, /* means: use general-category to choose between U or T. */
+};
+
+/*
+ * Joining types:
+ */
+
+
+/*
+ * Main joining-type table, covering U+0600..U+07FF.
+ * Includes Arabic, Syriac, and N'ko.
+ */
+static const uint8_t arabic_syriac_nko_joining_types[0x0800 - 0x0600 + 1] =
+{
+  /*
+   * The following table is generated by running:
+   *
+   *   ./gen-arabic-joining-table.py < ArabicShaping.txt
+   *
+   * on the ArabicShaping.txt file with the header:
+   *
+   * # ArabicShaping-6.0.0.txt
+   * # Date: 2010-04-30, 13:47:00 PDT [KW]
+   */
+  /* == Start of generated table == */
+  JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0601; ARABIC SIGN SANAH; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0602; ARABIC FOOTNOTE MARKER; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0603; ARABIC SIGN SAFHA; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 0604 */
+  JOINING_TYPE_X, /* 0605 */
+  JOINING_TYPE_X, /* 0606 */
+  JOINING_TYPE_X, /* 0607 */
+  JOINING_TYPE_U, /* 0608; ARABIC RAY; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 0609 */
+  JOINING_TYPE_X, /* 060A */
+  JOINING_TYPE_U, /* 060B; AFGHANI SIGN; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 060C */
+  JOINING_TYPE_X, /* 060D */
+  JOINING_TYPE_X, /* 060E */
+  JOINING_TYPE_X, /* 060F */
+  JOINING_TYPE_X, /* 0610 */
+  JOINING_TYPE_X, /* 0611 */
+  JOINING_TYPE_X, /* 0612 */
+  JOINING_TYPE_X, /* 0613 */
+  JOINING_TYPE_X, /* 0614 */
+  JOINING_TYPE_X, /* 0615 */
+  JOINING_TYPE_X, /* 0616 */
+  JOINING_TYPE_X, /* 0617 */
+  JOINING_TYPE_X, /* 0618 */
+  JOINING_TYPE_X, /* 0619 */
+  JOINING_TYPE_X, /* 061A */
+  JOINING_TYPE_X, /* 061B */
+  JOINING_TYPE_X, /* 061C */
+  JOINING_TYPE_X, /* 061D */
+  JOINING_TYPE_X, /* 061E */
+  JOINING_TYPE_X, /* 061F */
+  JOINING_TYPE_D, /* 0620; YEH WITH RING; D; YEH */
+  JOINING_TYPE_U, /* 0621; HAMZA; U; No_Joining_Group */
+  JOINING_TYPE_R, /* 0622; MADDA ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0623; HAMZA ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0624; HAMZA ON WAW; R; WAW */
+  JOINING_TYPE_R, /* 0625; HAMZA UNDER ALEF; R; ALEF */
+  JOINING_TYPE_D, /* 0626; HAMZA ON YEH; D; YEH */
+  JOINING_TYPE_R, /* 0627; ALEF; R; ALEF */
+  JOINING_TYPE_D, /* 0628; BEH; D; BEH */
+  JOINING_TYPE_R, /* 0629; TEH MARBUTA; R; TEH MARBUTA */
+  JOINING_TYPE_D, /* 062A; TEH; D; BEH */
+  JOINING_TYPE_D, /* 062B; THEH; D; BEH */
+  JOINING_TYPE_D, /* 062C; JEEM; D; HAH */
+  JOINING_TYPE_D, /* 062D; HAH; D; HAH */
+  JOINING_TYPE_D, /* 062E; KHAH; D; HAH */
+  JOINING_TYPE_R, /* 062F; DAL; R; DAL */
+  JOINING_TYPE_R, /* 0630; THAL; R; DAL */
+  JOINING_TYPE_R, /* 0631; REH; R; REH */
+  JOINING_TYPE_R, /* 0632; ZAIN; R; REH */
+  JOINING_TYPE_D, /* 0633; SEEN; D; SEEN */
+  JOINING_TYPE_D, /* 0634; SHEEN; D; SEEN */
+  JOINING_TYPE_D, /* 0635; SAD; D; SAD */
+  JOINING_TYPE_D, /* 0636; DAD; D; SAD */
+  JOINING_TYPE_D, /* 0637; TAH; D; TAH */
+  JOINING_TYPE_D, /* 0638; ZAH; D; TAH */
+  JOINING_TYPE_D, /* 0639; AIN; D; AIN */
+  JOINING_TYPE_D, /* 063A; GHAIN; D; AIN */
+  JOINING_TYPE_D, /* 063B; KEHEH WITH 2 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 063C; KEHEH WITH 3 DOTS BELOW; D; GAF */
+  JOINING_TYPE_D, /* 063D; FARSI YEH WITH INVERTED V; D; FARSI YEH */
+  JOINING_TYPE_D, /* 063E; FARSI YEH WITH 2 DOTS ABOVE; D; FARSI YEH */
+  JOINING_TYPE_D, /* 063F; FARSI YEH WITH 3 DOTS ABOVE; D; FARSI YEH */
+  JOINING_TYPE_C, /* 0640; TATWEEL; C; No_Joining_Group */
+  JOINING_TYPE_D, /* 0641; FEH; D; FEH */
+  JOINING_TYPE_D, /* 0642; QAF; D; QAF */
+  JOINING_TYPE_D, /* 0643; KAF; D; KAF */
+  JOINING_TYPE_D, /* 0644; LAM; D; LAM */
+  JOINING_TYPE_D, /* 0645; MEEM; D; MEEM */
+  JOINING_TYPE_D, /* 0646; NOON; D; NOON */
+  JOINING_TYPE_D, /* 0647; HEH; D; HEH */
+  JOINING_TYPE_R, /* 0648; WAW; R; WAW */
+  JOINING_TYPE_D, /* 0649; ALEF MAKSURA; D; YEH */
+  JOINING_TYPE_D, /* 064A; YEH; D; YEH */
+  JOINING_TYPE_X, /* 064B */
+  JOINING_TYPE_X, /* 064C */
+  JOINING_TYPE_X, /* 064D */
+  JOINING_TYPE_X, /* 064E */
+  JOINING_TYPE_X, /* 064F */
+  JOINING_TYPE_X, /* 0650 */
+  JOINING_TYPE_X, /* 0651 */
+  JOINING_TYPE_X, /* 0652 */
+  JOINING_TYPE_X, /* 0653 */
+  JOINING_TYPE_X, /* 0654 */
+  JOINING_TYPE_X, /* 0655 */
+  JOINING_TYPE_X, /* 0656 */
+  JOINING_TYPE_X, /* 0657 */
+  JOINING_TYPE_X, /* 0658 */
+  JOINING_TYPE_X, /* 0659 */
+  JOINING_TYPE_X, /* 065A */
+  JOINING_TYPE_X, /* 065B */
+  JOINING_TYPE_X, /* 065C */
+  JOINING_TYPE_X, /* 065D */
+  JOINING_TYPE_X, /* 065E */
+  JOINING_TYPE_X, /* 065F */
+  JOINING_TYPE_X, /* 0660 */
+  JOINING_TYPE_X, /* 0661 */
+  JOINING_TYPE_X, /* 0662 */
+  JOINING_TYPE_X, /* 0663 */
+  JOINING_TYPE_X, /* 0664 */
+  JOINING_TYPE_X, /* 0665 */
+  JOINING_TYPE_X, /* 0666 */
+  JOINING_TYPE_X, /* 0667 */
+  JOINING_TYPE_X, /* 0668 */
+  JOINING_TYPE_X, /* 0669 */
+  JOINING_TYPE_X, /* 066A */
+  JOINING_TYPE_X, /* 066B */
+  JOINING_TYPE_X, /* 066C */
+  JOINING_TYPE_X, /* 066D */
+  JOINING_TYPE_D, /* 066E; DOTLESS BEH; D; BEH */
+  JOINING_TYPE_D, /* 066F; DOTLESS QAF; D; QAF */
+  JOINING_TYPE_X, /* 0670 */
+  JOINING_TYPE_R, /* 0671; HAMZAT WASL ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0672; WAVY HAMZA ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0673; WAVY HAMZA UNDER ALEF; R; ALEF */
+  JOINING_TYPE_U, /* 0674; HIGH HAMZA; U; No_Joining_Group */
+  JOINING_TYPE_R, /* 0675; HIGH HAMZA ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0676; HIGH HAMZA WAW; R; WAW */
+  JOINING_TYPE_R, /* 0677; HIGH HAMZA WAW WITH DAMMA; R; WAW */
+  JOINING_TYPE_D, /* 0678; HIGH HAMZA YEH; D; YEH */
+  JOINING_TYPE_D, /* 0679; TEH WITH SMALL TAH; D; BEH */
+  JOINING_TYPE_D, /* 067A; TEH WITH 2 DOTS VERTICAL ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 067B; BEH WITH 2 DOTS VERTICAL BELOW; D; BEH */
+  JOINING_TYPE_D, /* 067C; TEH WITH RING; D; BEH */
+  JOINING_TYPE_D, /* 067D; TEH WITH 3 DOTS ABOVE DOWNWARD; D; BEH */
+  JOINING_TYPE_D, /* 067E; TEH WITH 3 DOTS BELOW; D; BEH */
+  JOINING_TYPE_D, /* 067F; TEH WITH 4 DOTS ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0680; BEH WITH 4 DOTS BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0681; HAMZA ON HAH; D; HAH */
+  JOINING_TYPE_D, /* 0682; HAH WITH 2 DOTS VERTICAL ABOVE; D; HAH */
+  JOINING_TYPE_D, /* 0683; HAH WITH MIDDLE 2 DOTS; D; HAH */
+  JOINING_TYPE_D, /* 0684; HAH WITH MIDDLE 2 DOTS VERTICAL; D; HAH */
+  JOINING_TYPE_D, /* 0685; HAH WITH 3 DOTS ABOVE; D; HAH */
+  JOINING_TYPE_D, /* 0686; HAH WITH MIDDLE 3 DOTS DOWNWARD; D; HAH */
+  JOINING_TYPE_D, /* 0687; HAH WITH MIDDLE 4 DOTS; D; HAH */
+  JOINING_TYPE_R, /* 0688; DAL WITH SMALL TAH; R; DAL */
+  JOINING_TYPE_R, /* 0689; DAL WITH RING; R; DAL */
+  JOINING_TYPE_R, /* 068A; DAL WITH DOT BELOW; R; DAL */
+  JOINING_TYPE_R, /* 068B; DAL WITH DOT BELOW AND SMALL TAH; R; DAL */
+  JOINING_TYPE_R, /* 068C; DAL WITH 2 DOTS ABOVE; R; DAL */
+  JOINING_TYPE_R, /* 068D; DAL WITH 2 DOTS BELOW; R; DAL */
+  JOINING_TYPE_R, /* 068E; DAL WITH 3 DOTS ABOVE; R; DAL */
+  JOINING_TYPE_R, /* 068F; DAL WITH 3 DOTS ABOVE DOWNWARD; R; DAL */
+  JOINING_TYPE_R, /* 0690; DAL WITH 4 DOTS ABOVE; R; DAL */
+  JOINING_TYPE_R, /* 0691; REH WITH SMALL TAH; R; REH */
+  JOINING_TYPE_R, /* 0692; REH WITH SMALL V; R; REH */
+  JOINING_TYPE_R, /* 0693; REH WITH RING; R; REH */
+  JOINING_TYPE_R, /* 0694; REH WITH DOT BELOW; R; REH */
+  JOINING_TYPE_R, /* 0695; REH WITH SMALL V BELOW; R; REH */
+  JOINING_TYPE_R, /* 0696; REH WITH DOT BELOW AND DOT ABOVE; R; REH */
+  JOINING_TYPE_R, /* 0697; REH WITH 2 DOTS ABOVE; R; REH */
+  JOINING_TYPE_R, /* 0698; REH WITH 3 DOTS ABOVE; R; REH */
+  JOINING_TYPE_R, /* 0699; REH WITH 4 DOTS ABOVE; R; REH */
+  JOINING_TYPE_D, /* 069A; SEEN WITH DOT BELOW AND DOT ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 069B; SEEN WITH 3 DOTS BELOW; D; SEEN */
+  JOINING_TYPE_D, /* 069C; SEEN WITH 3 DOTS BELOW AND 3 DOTS ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 069D; SAD WITH 2 DOTS BELOW; D; SAD */
+  JOINING_TYPE_D, /* 069E; SAD WITH 3 DOTS ABOVE; D; SAD */
+  JOINING_TYPE_D, /* 069F; TAH WITH 3 DOTS ABOVE; D; TAH */
+  JOINING_TYPE_D, /* 06A0; AIN WITH 3 DOTS ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 06A1; DOTLESS FEH; D; FEH */
+  JOINING_TYPE_D, /* 06A2; FEH WITH DOT MOVED BELOW; D; FEH */
+  JOINING_TYPE_D, /* 06A3; FEH WITH DOT BELOW; D; FEH */
+  JOINING_TYPE_D, /* 06A4; FEH WITH 3 DOTS ABOVE; D; FEH */
+  JOINING_TYPE_D, /* 06A5; FEH WITH 3 DOTS BELOW; D; FEH */
+  JOINING_TYPE_D, /* 06A6; FEH WITH 4 DOTS ABOVE; D; FEH */
+  JOINING_TYPE_D, /* 06A7; QAF WITH DOT ABOVE; D; QAF */
+  JOINING_TYPE_D, /* 06A8; QAF WITH 3 DOTS ABOVE; D; QAF */
+  JOINING_TYPE_D, /* 06A9; KEHEH; D; GAF */
+  JOINING_TYPE_D, /* 06AA; SWASH KAF; D; SWASH KAF */
+  JOINING_TYPE_D, /* 06AB; KAF WITH RING; D; GAF */
+  JOINING_TYPE_D, /* 06AC; KAF WITH DOT ABOVE; D; KAF */
+  JOINING_TYPE_D, /* 06AD; KAF WITH 3 DOTS ABOVE; D; KAF */
+  JOINING_TYPE_D, /* 06AE; KAF WITH 3 DOTS BELOW; D; KAF */
+  JOINING_TYPE_D, /* 06AF; GAF; D; GAF */
+  JOINING_TYPE_D, /* 06B0; GAF WITH RING; D; GAF */
+  JOINING_TYPE_D, /* 06B1; GAF WITH 2 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 06B2; GAF WITH 2 DOTS BELOW; D; GAF */
+  JOINING_TYPE_D, /* 06B3; GAF WITH 2 DOTS VERTICAL BELOW; D; GAF */
+  JOINING_TYPE_D, /* 06B4; GAF WITH 3 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 06B5; LAM WITH SMALL V; D; LAM */
+  JOINING_TYPE_D, /* 06B6; LAM WITH DOT ABOVE; D; LAM */
+  JOINING_TYPE_D, /* 06B7; LAM WITH 3 DOTS ABOVE; D; LAM */
+  JOINING_TYPE_D, /* 06B8; LAM WITH 3 DOTS BELOW; D; LAM */
+  JOINING_TYPE_D, /* 06B9; NOON WITH DOT BELOW; D; NOON */
+  JOINING_TYPE_D, /* 06BA; DOTLESS NOON; D; NOON */
+  JOINING_TYPE_D, /* 06BB; DOTLESS NOON WITH SMALL TAH; D; NOON */
+  JOINING_TYPE_D, /* 06BC; NOON WITH RING; D; NOON */
+  JOINING_TYPE_D, /* 06BD; NYA; D; NYA */
+  JOINING_TYPE_D, /* 06BE; KNOTTED HEH; D; KNOTTED HEH */
+  JOINING_TYPE_D, /* 06BF; HAH WITH MIDDLE 3 DOTS DOWNWARD AND DOT ABOVE; D; HAH */
+  JOINING_TYPE_R, /* 06C0; HAMZA ON HEH; R; TEH MARBUTA */
+  JOINING_TYPE_D, /* 06C1; HEH GOAL; D; HEH GOAL */
+  JOINING_TYPE_D, /* 06C2; HAMZA ON HEH GOAL; D; HEH GOAL */
+  JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL */
+  JOINING_TYPE_R, /* 06C4; WAW WITH RING; R; WAW */
+  JOINING_TYPE_R, /* 06C5; WAW WITH BAR; R; WAW */
+  JOINING_TYPE_R, /* 06C6; WAW WITH SMALL V; R; WAW */
+  JOINING_TYPE_R, /* 06C7; WAW WITH DAMMA; R; WAW */
+  JOINING_TYPE_R, /* 06C8; WAW WITH ALEF ABOVE; R; WAW */
+  JOINING_TYPE_R, /* 06C9; WAW WITH INVERTED SMALL V; R; WAW */
+  JOINING_TYPE_R, /* 06CA; WAW WITH 2 DOTS ABOVE; R; WAW */
+  JOINING_TYPE_R, /* 06CB; WAW WITH 3 DOTS ABOVE; R; WAW */
+  JOINING_TYPE_D, /* 06CC; FARSI YEH; D; FARSI YEH */
+  JOINING_TYPE_R, /* 06CD; YEH WITH TAIL; R; YEH WITH TAIL */
+  JOINING_TYPE_D, /* 06CE; FARSI YEH WITH SMALL V; D; FARSI YEH */
+  JOINING_TYPE_R, /* 06CF; WAW WITH DOT ABOVE; R; WAW */
+  JOINING_TYPE_D, /* 06D0; YEH WITH 2 DOTS VERTICAL BELOW; D; YEH */
+  JOINING_TYPE_D, /* 06D1; YEH WITH 3 DOTS BELOW; D; YEH */
+  JOINING_TYPE_R, /* 06D2; YEH BARREE; R; YEH BARREE */
+  JOINING_TYPE_R, /* 06D3; HAMZA ON YEH BARREE; R; YEH BARREE */
+  JOINING_TYPE_X, /* 06D4 */
+  JOINING_TYPE_R, /* 06D5; AE; R; TEH MARBUTA */
+  JOINING_TYPE_X, /* 06D6 */
+  JOINING_TYPE_X, /* 06D7 */
+  JOINING_TYPE_X, /* 06D8 */
+  JOINING_TYPE_X, /* 06D9 */
+  JOINING_TYPE_X, /* 06DA */
+  JOINING_TYPE_X, /* 06DB */
+  JOINING_TYPE_X, /* 06DC */
+  JOINING_TYPE_U, /* 06DD; ARABIC END OF AYAH; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 06DE */
+  JOINING_TYPE_X, /* 06DF */
+  JOINING_TYPE_X, /* 06E0 */
+  JOINING_TYPE_X, /* 06E1 */
+  JOINING_TYPE_X, /* 06E2 */
+  JOINING_TYPE_X, /* 06E3 */
+  JOINING_TYPE_X, /* 06E4 */
+  JOINING_TYPE_X, /* 06E5 */
+  JOINING_TYPE_X, /* 06E6 */
+  JOINING_TYPE_X, /* 06E7 */
+  JOINING_TYPE_X, /* 06E8 */
+  JOINING_TYPE_X, /* 06E9 */
+  JOINING_TYPE_X, /* 06EA */
+  JOINING_TYPE_X, /* 06EB */
+  JOINING_TYPE_X, /* 06EC */
+  JOINING_TYPE_X, /* 06ED */
+  JOINING_TYPE_R, /* 06EE; DAL WITH INVERTED V; R; DAL */
+  JOINING_TYPE_R, /* 06EF; REH WITH INVERTED V; R; REH */
+  JOINING_TYPE_X, /* 06F0 */
+  JOINING_TYPE_X, /* 06F1 */
+  JOINING_TYPE_X, /* 06F2 */
+  JOINING_TYPE_X, /* 06F3 */
+  JOINING_TYPE_X, /* 06F4 */
+  JOINING_TYPE_X, /* 06F5 */
+  JOINING_TYPE_X, /* 06F6 */
+  JOINING_TYPE_X, /* 06F7 */
+  JOINING_TYPE_X, /* 06F8 */
+  JOINING_TYPE_X, /* 06F9 */
+  JOINING_TYPE_D, /* 06FA; SEEN WITH DOT BELOW AND 3 DOTS ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 06FB; DAD WITH DOT BELOW; D; SAD */
+  JOINING_TYPE_D, /* 06FC; GHAIN WITH DOT BELOW; D; AIN */
+  JOINING_TYPE_X, /* 06FD */
+  JOINING_TYPE_X, /* 06FE */
+  JOINING_TYPE_D, /* 06FF; HEH WITH INVERTED V; D; KNOTTED HEH */
+  JOINING_TYPE_X, /* 0700 */
+  JOINING_TYPE_X, /* 0701 */
+  JOINING_TYPE_X, /* 0702 */
+  JOINING_TYPE_X, /* 0703 */
+  JOINING_TYPE_X, /* 0704 */
+  JOINING_TYPE_X, /* 0705 */
+  JOINING_TYPE_X, /* 0706 */
+  JOINING_TYPE_X, /* 0707 */
+  JOINING_TYPE_X, /* 0708 */
+  JOINING_TYPE_X, /* 0709 */
+  JOINING_TYPE_X, /* 070A */
+  JOINING_TYPE_X, /* 070B */
+  JOINING_TYPE_X, /* 070C */
+  JOINING_TYPE_X, /* 070D */
+  JOINING_TYPE_X, /* 070E */
+  JOINING_TYPE_X, /* 070F */
+  JOINING_GROUP_ALAPH, /* 0710; ALAPH; R; ALAPH */
+  JOINING_TYPE_X, /* 0711 */
+  JOINING_TYPE_D, /* 0712; BETH; D; BETH */
+  JOINING_TYPE_D, /* 0713; GAMAL; D; GAMAL */
+  JOINING_TYPE_D, /* 0714; GAMAL GARSHUNI; D; GAMAL */
+  JOINING_GROUP_DALATH_RISH, /* 0715; DALATH; R; DALATH RISH */
+  JOINING_GROUP_DALATH_RISH, /* 0716; DOTLESS DALATH RISH; R; DALATH RISH */
+  JOINING_TYPE_R, /* 0717; HE; R; HE */
+  JOINING_TYPE_R, /* 0718; WAW; R; SYRIAC WAW */
+  JOINING_TYPE_R, /* 0719; ZAIN; R; ZAIN */
+  JOINING_TYPE_D, /* 071A; HETH; D; HETH */
+  JOINING_TYPE_D, /* 071B; TETH; D; TETH */
+  JOINING_TYPE_D, /* 071C; TETH GARSHUNI; D; TETH */
+  JOINING_TYPE_D, /* 071D; YUDH; D; YUDH */
+  JOINING_TYPE_R, /* 071E; YUDH HE; R; YUDH HE */
+  JOINING_TYPE_D, /* 071F; KAPH; D; KAPH */
+  JOINING_TYPE_D, /* 0720; LAMADH; D; LAMADH */
+  JOINING_TYPE_D, /* 0721; MIM; D; MIM */
+  JOINING_TYPE_D, /* 0722; NUN; D; NUN */
+  JOINING_TYPE_D, /* 0723; SEMKATH; D; SEMKATH */
+  JOINING_TYPE_D, /* 0724; FINAL SEMKATH; D; FINAL SEMKATH */
+  JOINING_TYPE_D, /* 0725; E; D; E */
+  JOINING_TYPE_D, /* 0726; PE; D; PE */
+  JOINING_TYPE_D, /* 0727; REVERSED PE; D; REVERSED PE */
+  JOINING_TYPE_R, /* 0728; SADHE; R; SADHE */
+  JOINING_TYPE_D, /* 0729; QAPH; D; QAPH */
+  JOINING_GROUP_DALATH_RISH, /* 072A; RISH; R; DALATH RISH */
+  JOINING_TYPE_D, /* 072B; SHIN; D; SHIN */
+  JOINING_TYPE_R, /* 072C; TAW; R; TAW */
+  JOINING_TYPE_D, /* 072D; PERSIAN BHETH; D; BETH */
+  JOINING_TYPE_D, /* 072E; PERSIAN GHAMAL; D; GAMAL */
+  JOINING_GROUP_DALATH_RISH, /* 072F; PERSIAN DHALATH; R; DALATH RISH */
+  JOINING_TYPE_X, /* 0730 */
+  JOINING_TYPE_X, /* 0731 */
+  JOINING_TYPE_X, /* 0732 */
+  JOINING_TYPE_X, /* 0733 */
+  JOINING_TYPE_X, /* 0734 */
+  JOINING_TYPE_X, /* 0735 */
+  JOINING_TYPE_X, /* 0736 */
+  JOINING_TYPE_X, /* 0737 */
+  JOINING_TYPE_X, /* 0738 */
+  JOINING_TYPE_X, /* 0739 */
+  JOINING_TYPE_X, /* 073A */
+  JOINING_TYPE_X, /* 073B */
+  JOINING_TYPE_X, /* 073C */
+  JOINING_TYPE_X, /* 073D */
+  JOINING_TYPE_X, /* 073E */
+  JOINING_TYPE_X, /* 073F */
+  JOINING_TYPE_X, /* 0740 */
+  JOINING_TYPE_X, /* 0741 */
+  JOINING_TYPE_X, /* 0742 */
+  JOINING_TYPE_X, /* 0743 */
+  JOINING_TYPE_X, /* 0744 */
+  JOINING_TYPE_X, /* 0745 */
+  JOINING_TYPE_X, /* 0746 */
+  JOINING_TYPE_X, /* 0747 */
+  JOINING_TYPE_X, /* 0748 */
+  JOINING_TYPE_X, /* 0749 */
+  JOINING_TYPE_X, /* 074A */
+  JOINING_TYPE_X, /* 074B */
+  JOINING_TYPE_X, /* 074C */
+  JOINING_TYPE_R, /* 074D; SOGDIAN ZHAIN; R; ZHAIN */
+  JOINING_TYPE_D, /* 074E; SOGDIAN KHAPH; D; KHAPH */
+  JOINING_TYPE_D, /* 074F; SOGDIAN FE; D; FE */
+  JOINING_TYPE_D, /* 0750; BEH WITH 3 DOTS HORIZONTALLY BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0751; BEH WITH DOT BELOW AND 3 DOTS ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0752; BEH WITH 3 DOTS POINTING UPWARDS BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0753; BEH WITH 3 DOTS POINTING UPWARDS BELOW AND 2 DOTS ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0754; BEH WITH 2 DOTS BELOW AND DOT ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0755; BEH WITH INVERTED SMALL V BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0756; BEH WITH SMALL V; D; BEH */
+  JOINING_TYPE_D, /* 0757; HAH WITH 2 DOTS ABOVE; D; HAH */
+  JOINING_TYPE_D, /* 0758; HAH WITH 3 DOTS POINTING UPWARDS BELOW; D; HAH */
+  JOINING_TYPE_R, /* 0759; DAL WITH 2 DOTS VERTICALLY BELOW AND SMALL TAH; R; DAL */
+  JOINING_TYPE_R, /* 075A; DAL WITH INVERTED SMALL V BELOW; R; DAL */
+  JOINING_TYPE_R, /* 075B; REH WITH STROKE; R; REH */
+  JOINING_TYPE_D, /* 075C; SEEN WITH 4 DOTS ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 075D; AIN WITH 2 DOTS ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 075E; AIN WITH 3 DOTS POINTING DOWNWARDS ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 075F; AIN WITH 2 DOTS VERTICALLY ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 0760; FEH WITH 2 DOTS BELOW; D; FEH */
+  JOINING_TYPE_D, /* 0761; FEH WITH 3 DOTS POINTING UPWARDS BELOW; D; FEH */
+  JOINING_TYPE_D, /* 0762; KEHEH WITH DOT ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 0763; KEHEH WITH 3 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 0764; KEHEH WITH 3 DOTS POINTING UPWARDS BELOW; D; GAF */
+  JOINING_TYPE_D, /* 0765; MEEM WITH DOT ABOVE; D; MEEM */
+  JOINING_TYPE_D, /* 0766; MEEM WITH DOT BELOW; D; MEEM */
+  JOINING_TYPE_D, /* 0767; NOON WITH 2 DOTS BELOW; D; NOON */
+  JOINING_TYPE_D, /* 0768; NOON WITH SMALL TAH; D; NOON */
+  JOINING_TYPE_D, /* 0769; NOON WITH SMALL V; D; NOON */
+  JOINING_TYPE_D, /* 076A; LAM WITH BAR; D; LAM */
+  JOINING_TYPE_R, /* 076B; REH WITH 2 DOTS VERTICALLY ABOVE; R; REH */
+  JOINING_TYPE_R, /* 076C; REH WITH HAMZA ABOVE; R; REH */
+  JOINING_TYPE_D, /* 076D; SEEN WITH 2 DOTS VERTICALLY ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 076E; HAH WITH SMALL TAH BELOW; D; HAH */
+  JOINING_TYPE_D, /* 076F; HAH WITH SMALL TAH AND 2 DOTS; D; HAH */
+  JOINING_TYPE_D, /* 0770; SEEN WITH SMALL TAH AND 2 DOTS; D; SEEN */
+  JOINING_TYPE_R, /* 0771; REH WITH SMALL TAH AND 2 DOTS; R; REH */
+  JOINING_TYPE_D, /* 0772; HAH WITH SMALL TAH ABOVE; D; HAH */
+  JOINING_TYPE_R, /* 0773; ALEF WITH DIGIT TWO ABOVE; R; ALEF */
+  JOINING_TYPE_R, /* 0774; ALEF WITH DIGIT THREE ABOVE; R; ALEF */
+  JOINING_TYPE_D, /* 0775; FARSI YEH WITH DIGIT TWO ABOVE; D; FARSI YEH */
+  JOINING_TYPE_D, /* 0776; FARSI YEH WITH DIGIT THREE ABOVE; D; FARSI YEH */
+  JOINING_TYPE_D, /* 0777; YEH WITH DIGIT FOUR BELOW; D; YEH */
+  JOINING_TYPE_R, /* 0778; WAW WITH DIGIT TWO ABOVE; R; WAW */
+  JOINING_TYPE_R, /* 0779; WAW WITH DIGIT THREE ABOVE; R; WAW */
+  JOINING_TYPE_D, /* 077A; YEH BARREE WITH DIGIT TWO ABOVE; D; BURUSHASKI YEH BARREE */
+  JOINING_TYPE_D, /* 077B; YEH BARREE WITH DIGIT THREE ABOVE; D; BURUSHASKI YEH BARREE */
+  JOINING_TYPE_D, /* 077C; HAH WITH DIGIT FOUR BELOW; D; HAH */
+  JOINING_TYPE_D, /* 077D; SEEN WITH DIGIT FOUR ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 077E; SEEN WITH INVERTED V; D; SEEN */
+  JOINING_TYPE_D, /* 077F; KAF WITH 2 DOTS ABOVE; D; KAF */
+  JOINING_TYPE_X, /* 0780 */
+  JOINING_TYPE_X, /* 0781 */
+  JOINING_TYPE_X, /* 0782 */
+  JOINING_TYPE_X, /* 0783 */
+  JOINING_TYPE_X, /* 0784 */
+  JOINING_TYPE_X, /* 0785 */
+  JOINING_TYPE_X, /* 0786 */
+  JOINING_TYPE_X, /* 0787 */
+  JOINING_TYPE_X, /* 0788 */
+  JOINING_TYPE_X, /* 0789 */
+  JOINING_TYPE_X, /* 078A */
+  JOINING_TYPE_X, /* 078B */
+  JOINING_TYPE_X, /* 078C */
+  JOINING_TYPE_X, /* 078D */
+  JOINING_TYPE_X, /* 078E */
+  JOINING_TYPE_X, /* 078F */
+  JOINING_TYPE_X, /* 0790 */
+  JOINING_TYPE_X, /* 0791 */
+  JOINING_TYPE_X, /* 0792 */
+  JOINING_TYPE_X, /* 0793 */
+  JOINING_TYPE_X, /* 0794 */
+  JOINING_TYPE_X, /* 0795 */
+  JOINING_TYPE_X, /* 0796 */
+  JOINING_TYPE_X, /* 0797 */
+  JOINING_TYPE_X, /* 0798 */
+  JOINING_TYPE_X, /* 0799 */
+  JOINING_TYPE_X, /* 079A */
+  JOINING_TYPE_X, /* 079B */
+  JOINING_TYPE_X, /* 079C */
+  JOINING_TYPE_X, /* 079D */
+  JOINING_TYPE_X, /* 079E */
+  JOINING_TYPE_X, /* 079F */
+  JOINING_TYPE_X, /* 07A0 */
+  JOINING_TYPE_X, /* 07A1 */
+  JOINING_TYPE_X, /* 07A2 */
+  JOINING_TYPE_X, /* 07A3 */
+  JOINING_TYPE_X, /* 07A4 */
+  JOINING_TYPE_X, /* 07A5 */
+  JOINING_TYPE_X, /* 07A6 */
+  JOINING_TYPE_X, /* 07A7 */
+  JOINING_TYPE_X, /* 07A8 */
+  JOINING_TYPE_X, /* 07A9 */
+  JOINING_TYPE_X, /* 07AA */
+  JOINING_TYPE_X, /* 07AB */
+  JOINING_TYPE_X, /* 07AC */
+  JOINING_TYPE_X, /* 07AD */
+  JOINING_TYPE_X, /* 07AE */
+  JOINING_TYPE_X, /* 07AF */
+  JOINING_TYPE_X, /* 07B0 */
+  JOINING_TYPE_X, /* 07B1 */
+  JOINING_TYPE_X, /* 07B2 */
+  JOINING_TYPE_X, /* 07B3 */
+  JOINING_TYPE_X, /* 07B4 */
+  JOINING_TYPE_X, /* 07B5 */
+  JOINING_TYPE_X, /* 07B6 */
+  JOINING_TYPE_X, /* 07B7 */
+  JOINING_TYPE_X, /* 07B8 */
+  JOINING_TYPE_X, /* 07B9 */
+  JOINING_TYPE_X, /* 07BA */
+  JOINING_TYPE_X, /* 07BB */
+  JOINING_TYPE_X, /* 07BC */
+  JOINING_TYPE_X, /* 07BD */
+  JOINING_TYPE_X, /* 07BE */
+  JOINING_TYPE_X, /* 07BF */
+  JOINING_TYPE_X, /* 07C0 */
+  JOINING_TYPE_X, /* 07C1 */
+  JOINING_TYPE_X, /* 07C2 */
+  JOINING_TYPE_X, /* 07C3 */
+  JOINING_TYPE_X, /* 07C4 */
+  JOINING_TYPE_X, /* 07C5 */
+  JOINING_TYPE_X, /* 07C6 */
+  JOINING_TYPE_X, /* 07C7 */
+  JOINING_TYPE_X, /* 07C8 */
+  JOINING_TYPE_X, /* 07C9 */
+  JOINING_TYPE_D, /* 07CA; NKO A; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CB; NKO EE; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CC; NKO I; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CD; NKO E; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CE; NKO U; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CF; NKO OO; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D0; NKO O; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D1; NKO DAGBASINNA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D2; NKO N; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D3; NKO BA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D4; NKO PA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D5; NKO TA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D6; NKO JA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D7; NKO CHA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D8; NKO DA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D9; NKO RA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DA; NKO RRA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DB; NKO SA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DC; NKO GBA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DD; NKO FA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DE; NKO KA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DF; NKO LA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E0; NKO NA WOLOSO; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E1; NKO MA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E2; NKO NYA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E3; NKO NA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E4; NKO HA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E5; NKO WA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E6; NKO YA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E7; NKO NYA WOLOSO; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E8; NKO JONA JA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E9; NKO JONA CHA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07EA; NKO JONA RA; D; No_Joining_Group */
+  JOINING_TYPE_X, /* 07EB */
+  JOINING_TYPE_X, /* 07EC */
+  JOINING_TYPE_X, /* 07ED */
+  JOINING_TYPE_X, /* 07EE */
+  JOINING_TYPE_X, /* 07EF */
+  JOINING_TYPE_X, /* 07F0 */
+  JOINING_TYPE_X, /* 07F1 */
+  JOINING_TYPE_X, /* 07F2 */
+  JOINING_TYPE_X, /* 07F3 */
+  JOINING_TYPE_X, /* 07F4 */
+  JOINING_TYPE_X, /* 07F5 */
+  JOINING_TYPE_X, /* 07F6 */
+  JOINING_TYPE_X, /* 07F7 */
+  JOINING_TYPE_X, /* 07F8 */
+  JOINING_TYPE_X, /* 07F9 */
+  JOINING_TYPE_C, /* 07FA; NKO LAJANYALAN; C; No_Joining_Group */
+  JOINING_TYPE_X, /* 07FB */
+  JOINING_TYPE_X, /* 07FC */
+  JOINING_TYPE_X, /* 07FD */
+  JOINING_TYPE_X, /* 07FE */
+  JOINING_TYPE_X, /* 07FF */
+  /* == End of generated table == */
+  JOINING_TYPE_X
+};
+
+static unsigned int get_joining_type (hb_codepoint_t u, hb_category_t gen_cat)
+{
+  /* TODO Macroize the magic bit operations */
+
+  if (likely ((u & ~(0x0600^0x07FF)) == 0x0600)) {
+    unsigned int j_type = arabic_syriac_nko_joining_types[u - 0x0600];
+    if (likely (j_type != JOINING_TYPE_X))
+      return j_type;
+  }
+
+  if (unlikely ((u & ~(0x200C^0x200D)) == 0x200C)) {
+    return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
+  }
+
+  return ((1<<gen_cat) & ((1<<HB_CATEGORY_NON_SPACING_MARK)|(1<<HB_CATEGORY_ENCLOSING_MARK)|(1<<HB_CATEGORY_FORMAT))) ?
+	 JOINING_TYPE_T : JOINING_TYPE_U;
+}
+
+
+
+static const hb_tag_t arabic_syriac_features[] =
+{
+  HB_TAG('i','n','i','t'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('f','i','n','a'),
+  HB_TAG('i','s','o','l'),
+  /* Syriac */
+  HB_TAG('m','e','d','2'),
+  HB_TAG('f','i','n','2'),
+  HB_TAG('f','i','n','3'),
+  HB_TAG_NONE
+};
+
+
+/* Same order as the feature array */
+enum {
+  INIT,
+  MEDI,
+  FINA,
+  ISOL,
+
+  /* Syriac */
+  MED2,
+  FIN2,
+  FIN3,
+
+  NONE,
+
+  COMMON_NUM_FEATURES = 4,
+  SYRIAC_NUM_FEATURES = 7,
+  TOTAL_NUM_FEATURES = NONE
+};
+
+static const struct arabic_state_table_entry {
+	uint8_t prev_action;
+	uint8_t curr_action;
+	uint8_t next_state;
+	uint8_t padding;
+} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
+{
+  /*   jt_U,          jt_R,          jt_D,          jg_ALAPH,      jg_DALATH_RISH */
+
+  /* State 0: prev was U, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
+
+  /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
+
+  /* State 2: prev was D/ISOL, willing to join. */
+  { {NONE,NONE,0}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
+
+  /* State 3: prev was D/FINA, willing to join. */
+  { {NONE,NONE,0}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
+
+  /* State 4: prev was FINA ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
+
+  /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
+
+  /* State 6: prev was DALATH/RISH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
+};
+
+
+
+void
+_hb_ot_shape_complex_collect_features_arabic	(hb_ot_shape_plan_t *plan, const hb_segment_properties_t  *props)
+{
+  unsigned int num_features = props->script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
+  for (unsigned int i = 0; i < num_features; i++)
+    plan->map.add_bool_feature (arabic_syriac_features[i], false);
+}
+
+void
+_hb_ot_analyze_complex_arabic (hb_ot_shape_context_t *c)
+{
+  unsigned int count = c->buffer->len;
+  unsigned int prev = 0, state = 0;
+
+  for (unsigned int i = 0; i < count; i++) {
+
+    unsigned int this_type = get_joining_type (c->buffer->info[i].codepoint, c->buffer->unicode->v.get_general_category (c->buffer->info[i].codepoint));
+
+    if (unlikely (this_type == JOINING_TYPE_T))
+      continue;
+
+    const arabic_state_table_entry *entry = arabic_state_table[state];
+
+    if (entry->prev_action != NONE)
+      c->buffer->info[prev].gproperty = entry->prev_action;
+
+    c->buffer->info[i].gproperty = entry->curr_action;
+
+    prev = i;
+    state = entry->next_state;
+  }
+
+  hb_mask_t mask_array[TOTAL_NUM_FEATURES] = {0};
+  unsigned int num_masks = c->buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
+  for (unsigned int i = 0; i < num_masks; i++)
+    mask_array[i] = 0 /* XXX find_mask */;
+
+  for (unsigned int i = 0; i < count; i++)
+    c->buffer->info[i].mask |= mask_array[c->buffer->info[i].gproperty];
+}
+
+
+HB_END_DECLS
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
new file mode 100644
index 0000000..1c605bb
--- /dev/null
+++ b/src/hb-ot-shape-complex-private.hh
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_PRIVATE_HH
+
+#include "hb-private.h"
+
+#include "hb-ot-map-private.hh"
+
+HB_BEGIN_DECLS
+
+
+enum hb_ot_complex_shaper_t {
+  hb_ot_complex_shaper_none,
+  hb_ot_complex_shaper_arabic
+};
+
+
+struct hb_ot_shape_plan_t
+{
+  hb_ot_map_t map;
+  hb_ot_complex_shaper_t shaper;
+};
+
+
+static inline hb_ot_complex_shaper_t
+hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
+{
+  switch ((int) props->script) {
+    case HB_SCRIPT_ARABIC:
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_SYRIAC:
+      return hb_ot_complex_shaper_arabic;
+
+    default:
+      return hb_ot_complex_shaper_none;
+  }
+}
+
+
+
+/*
+ * collect_features()
+ *
+ * Called during planning.  Shapers should call plan->map.add_feature().
+ */
+
+HB_INTERNAL void _hb_ot_shape_complex_collect_features_arabic	(hb_ot_shape_plan_t *plan, const hb_segment_properties_t  *props);
+
+static inline void
+hb_ot_shape_complex_collect_features (hb_ot_shape_plan_t *plan,
+				      const hb_segment_properties_t  *props)
+{
+  switch (plan->shaper) {
+    case hb_ot_complex_shaper_arabic:	_hb_ot_shape_complex_collect_features_arabic (plan, props);	return;
+    case hb_ot_complex_shaper_none:	default:							return;
+  }
+}
+
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index de1cb3b..aea52af 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -31,21 +31,11 @@
 
 #include "hb-ot-shape.h"
 
+#include "hb-ot-shape-complex-private.hh"
 #include "hb-ot-map-private.hh"
 
 HB_BEGIN_DECLS
 
-enum hb_ot_complex_shaper_t {
-  hb_ot_complex_shaper_none,
-  hb_ot_complex_shaper_arabic
-};
-
-struct hb_ot_shape_plan_t
-{
-  hb_ot_map_t map;
-  hb_ot_complex_shaper_t shaper;
-};
-
 struct hb_ot_shape_context_t
 {
   /* Input to hb_ot_shape() */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 061c203..b6acb22 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -48,7 +48,7 @@ hb_tag_t default_features[] = {
 
 static void
 hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan,
-			      hb_segment_properties_t  *props,
+			      const hb_segment_properties_t  *props,
 			      const hb_feature_t       *user_features,
 			      unsigned int              num_user_features)
 {
@@ -70,7 +70,7 @@ hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan,
   for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++)
     plan->map.add_bool_feature (default_features[i]);
 
-  /* complex */
+  hb_ot_shape_complex_collect_features (plan, props);
 
   for (unsigned int i = 0; i < num_user_features; i++) {
     const hb_feature_t *feature = &user_features[i];
@@ -321,10 +321,12 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
 void
 hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
 			   hb_face_t                *face,
-			   hb_segment_properties_t  *props,
+			   const hb_segment_properties_t  *props,
 			   const hb_feature_t       *user_features,
 			   unsigned int              num_user_features)
 {
+  plan->shaper = hb_ot_shape_complex_categorize (props);
+
   hb_ot_shape_collect_features (plan, props, user_features, num_user_features);
 
   plan->map.compile (face, props);
commit 605ed468f380f86d642031f6451447d270cb6de1
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 16:19:29 2010 -0400

    Add hb_ot_shape_plan_t
    
    This is the object that a separate plan/execute shaping API will use in
    between the two stages.

diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 3f47fa2..de1cb3b 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -35,8 +35,16 @@
 
 HB_BEGIN_DECLS
 
-struct hb_ot_map_t;
+enum hb_ot_complex_shaper_t {
+  hb_ot_complex_shaper_none,
+  hb_ot_complex_shaper_arabic
+};
 
+struct hb_ot_shape_plan_t
+{
+  hb_ot_map_t map;
+  hb_ot_complex_shaper_t shaper;
+};
 
 struct hb_ot_shape_context_t
 {
@@ -52,7 +60,7 @@ struct hb_ot_shape_context_t
   hb_bool_t applied_substitute_complex;
   hb_bool_t applied_position_complex;
 
-  struct hb_ot_map_t *map;
+  hb_ot_shape_plan_t *plan;
 };
 
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index f2bf848..061c203 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -28,8 +28,6 @@
 
 #include "hb-ot-shape-private.hh"
 
-#include "hb-ot-map-private.hh"
-
 HB_BEGIN_DECLS
 
 
@@ -49,19 +47,19 @@ hb_tag_t default_features[] = {
 };
 
 static void
-hb_ot_shape_collect_features (hb_ot_map_t              *map,
+hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan,
 			      hb_segment_properties_t  *props,
 			      const hb_feature_t       *user_features,
 			      unsigned int              num_user_features)
 {
   switch (props->direction) {
     case HB_DIRECTION_LTR:
-      map->add_bool_feature (HB_TAG ('l','t','r','a'));
-      map->add_bool_feature (HB_TAG ('l','t','r','m'));
+      plan->map.add_bool_feature (HB_TAG ('l','t','r','a'));
+      plan->map.add_bool_feature (HB_TAG ('l','t','r','m'));
       break;
     case HB_DIRECTION_RTL:
-      map->add_bool_feature (HB_TAG ('r','t','l','a'));
-      map->add_bool_feature (HB_TAG ('r','t','l','m'), false);
+      plan->map.add_bool_feature (HB_TAG ('r','t','l','a'));
+      plan->map.add_bool_feature (HB_TAG ('r','t','l','m'), false);
       break;
     case HB_DIRECTION_TTB:
     case HB_DIRECTION_BTT:
@@ -70,13 +68,13 @@ hb_ot_shape_collect_features (hb_ot_map_t              *map,
   }
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++)
-    map->add_bool_feature (default_features[i]);
+    plan->map.add_bool_feature (default_features[i]);
 
   /* complex */
 
   for (unsigned int i = 0; i < num_user_features; i++) {
     const hb_feature_t *feature = &user_features[i];
-    map->add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
+    plan->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
   }
 }
 
@@ -84,7 +82,7 @@ hb_ot_shape_collect_features (hb_ot_map_t              *map,
 static void
 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 {
-  hb_mask_t global_mask = c->map->get_global_mask ();
+  hb_mask_t global_mask = c->plan->map.get_global_mask ();
   if (global_mask)
     c->buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
 
@@ -93,7 +91,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->map->get_mask (feature->tag, &shift);
+      hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
       c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
     }
   }
@@ -108,7 +106,7 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
   if (!hb_ot_layout_has_substitution (c->face))
     return;
 
-  c->map->substitute (c->face, c->buffer);
+  c->plan->map.substitute (c->face, c->buffer);
 
   c->applied_substitute_complex = TRUE;
   return;
@@ -121,7 +119,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
   if (!hb_ot_layout_has_positioning (c->face))
     return;
 
-  c->map->position (c->font, c->face, c->buffer);
+  c->plan->map.position (c->font, c->face, c->buffer);
 
   hb_ot_layout_position_finish (c->font, c->face, c->buffer);
 
@@ -176,7 +174,7 @@ hb_mirror_chars (hb_ot_shape_context_t *c)
   if (HB_DIRECTION_IS_FORWARD (c->buffer->props.direction))
     return;
 
-  hb_mask_t rtlm_mask = c->map->get_mask (HB_TAG ('r','t','l','m'));
+  hb_mask_t rtlm_mask = c->plan->map.get_mask (HB_TAG ('r','t','l','m'));
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++) {
@@ -321,15 +319,15 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
 }
 
 void
-hb_ot_shape_plan_internal (hb_ot_map_t              *map,
+hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
 			   hb_face_t                *face,
 			   hb_segment_properties_t  *props,
 			   const hb_feature_t       *user_features,
 			   unsigned int              num_user_features)
 {
-  hb_ot_shape_collect_features (map, props, user_features, num_user_features);
+  hb_ot_shape_collect_features (plan, props, user_features, num_user_features);
 
-  map->compile (face, props);
+  plan->map.compile (face, props);
 }
 
 void
@@ -339,12 +337,12 @@ hb_ot_shape (hb_font_t    *font,
 	     const hb_feature_t *user_features,
 	     unsigned int        num_user_features)
 {
-  hb_ot_map_t map;
+  hb_ot_shape_plan_t plan;
 
-  hb_ot_shape_plan_internal (&map, face, &buffer->props, user_features, num_user_features);
+  hb_ot_shape_plan_internal (&plan, face, &buffer->props, user_features, num_user_features);
 
   hb_ot_shape_context_t c = {font, face, buffer, user_features, num_user_features};
-  c.map = ↦
+  c.plan = &plan;
   hb_ot_shape_internal (&c);
 }
 
commit 895fb5d364e7ae5d9d2e34b9f68b8651804369ef
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 16:00:21 2010 -0400

    Refactor, in a different direction

diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index abf96f2..0c05742 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -29,7 +29,7 @@
 #ifndef HB_OT_MAP_PRIVATE_HH
 #define HB_OT_MAP_PRIVATE_HH
 
-#include "hb-ot-shape-private.hh"
+#include "hb-buffer-private.hh"
 
 #include "hb-ot-layout.h"
 
@@ -73,7 +73,7 @@ struct hb_ot_map_t {
     { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
   };
 
-  HB_INTERNAL void add_lookups (hb_ot_shape_plan_context_t *c,
+  HB_INTERNAL void add_lookups (hb_face_t    *face,
 				unsigned int  table_index,
 				unsigned int  feature_index,
 				hb_mask_t     mask);
@@ -95,7 +95,8 @@ struct hb_ot_map_t {
   inline void add_bool_feature (hb_tag_t tag, bool global = true)
   { add_feature (tag, 1, global); }
 
-  HB_INTERNAL void compile (hb_ot_shape_plan_context_t *c);
+  HB_INTERNAL void compile (hb_face_t *face,
+			    hb_segment_properties_t *props);
 
   hb_mask_t get_global_mask (void) const { return global_mask; }
 
@@ -105,14 +106,14 @@ struct hb_ot_map_t {
     return map ? map->mask : 0;
   }
 
-  inline void substitute (hb_ot_shape_context_t *c) const {
+  inline void substitute (hb_face_t *face, hb_buffer_t *buffer) const {
     for (unsigned int i = 0; i < lookup_count[0]; i++)
-      hb_ot_layout_substitute_lookup (c->face, c->buffer, lookup_maps[0][i].index, lookup_maps[0][i].mask);
+      hb_ot_layout_substitute_lookup (face, buffer, lookup_maps[0][i].index, lookup_maps[0][i].mask);
   }
 
-  inline void position (hb_ot_shape_context_t *c) const {
+  inline void position (hb_font_t *font, hb_face_t *face, hb_buffer_t *buffer) const {
     for (unsigned int i = 0; i < lookup_count[1]; i++)
-      hb_ot_layout_position_lookup (c->font, c->face, c->buffer, lookup_maps[1][i].index, lookup_maps[1][i].mask);
+      hb_ot_layout_position_lookup (font, face, buffer, lookup_maps[1][i].index, lookup_maps[1][i].mask);
   }
 
   private:
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 84149b8..2205624 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -34,7 +34,7 @@ HB_BEGIN_DECLS
 
 
 void
-hb_ot_map_t::add_lookups (hb_ot_shape_plan_context_t *c,
+hb_ot_map_t::add_lookups (hb_face_t    *face,
 			  unsigned int  table_index,
 			  unsigned int  feature_index,
 			  hb_mask_t     mask)
@@ -44,7 +44,7 @@ hb_ot_map_t::add_lookups (hb_ot_shape_plan_context_t *c,
 
   unsigned int *lookup_indices = (unsigned int *) lookups;
 
-  hb_ot_layout_feature_get_lookup_indexes (c->face,
+  hb_ot_layout_feature_get_lookup_indexes (face,
 					   table_tags[table_index],
 					   feature_index,
 					   0, &i,
@@ -60,7 +60,8 @@ hb_ot_map_t::add_lookups (hb_ot_shape_plan_context_t *c,
 
 
 void
-hb_ot_map_t::compile (hb_ot_shape_plan_context_t *c)
+hb_ot_map_t::compile (hb_face_t *face,
+		      hb_segment_properties_t *props)
 {
  global_mask = 0;
  lookup_count[0] = lookup_count[1] = 0;
@@ -75,14 +76,14 @@ hb_ot_map_t::compile (hb_ot_shape_plan_context_t *c)
   const hb_tag_t *script_tags;
   hb_tag_t language_tag;
 
-  script_tags = hb_ot_tags_from_script (c->props->script);
-  language_tag = hb_ot_tag_from_language (c->props->language);
+  script_tags = hb_ot_tags_from_script (props->script);
+  language_tag = hb_ot_tag_from_language (props->language);
 
   unsigned int script_index[2], language_index[2];
   for (unsigned int table_index = 0; table_index < 2; table_index++) {
     hb_tag_t table_tag = table_tags[table_index];
-    hb_ot_layout_table_choose_script (c->face, table_tag, script_tags, &script_index[table_index]);
-    hb_ot_layout_script_find_language (c->face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+    hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index]);
+    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
   }
 
 
@@ -124,7 +125,7 @@ hb_ot_map_t::compile (hb_ot_shape_plan_context_t *c)
     bool found = false;
     unsigned int feature_index[2];
     for (unsigned int table_index = 0; table_index < 2; table_index++)
-      found |= hb_ot_layout_language_find_feature (c->face,
+      found |= hb_ot_layout_language_find_feature (face,
 						   table_tags[table_index],
 						   script_index[table_index],
 						   language_index[table_index],
@@ -161,15 +162,15 @@ hb_ot_map_t::compile (hb_ot_shape_plan_context_t *c)
     /* Collect lookup indices for features */
 
     unsigned int required_feature_index;
-    if (hb_ot_layout_language_get_required_feature_index (c->face,
+    if (hb_ot_layout_language_get_required_feature_index (face,
 							  table_tag,
 							  script_index[table_index],
 							  language_index[table_index],
 							  &required_feature_index))
-      add_lookups (c, table_index, required_feature_index, 1);
+      add_lookups (face, table_index, required_feature_index, 1);
 
     for (unsigned i = 0; i < feature_count; i++)
-      add_lookups (c, table_index, feature_maps[i].index[table_index], feature_maps[i].mask);
+      add_lookups (face, table_index, feature_maps[i].index[table_index], feature_maps[i].mask);
 
     /* Sort lookups and merge duplicates */
     qsort (lookup_maps[table_index], lookup_count[table_index], sizeof (lookup_maps[table_index][0]), (hb_compare_func_t) lookup_map_t::cmp);
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 0d21e88..3f47fa2 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -31,23 +31,12 @@
 
 #include "hb-ot-shape.h"
 
-#include "hb-buffer-private.hh"
+#include "hb-ot-map-private.hh"
 
 HB_BEGIN_DECLS
 
 struct hb_ot_map_t;
 
-struct hb_ot_shape_plan_context_t
-{
-  struct hb_ot_map_t *map;
-
-  hb_face_t *face;
-  hb_segment_properties_t *props;
-
-  const hb_feature_t *user_features;
-  unsigned int  num_user_features;
-};
-
 
 struct hb_ot_shape_context_t
 {
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index b0494c7..f2bf848 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -49,16 +49,19 @@ hb_tag_t default_features[] = {
 };
 
 static void
-hb_ot_shape_collect_features (hb_ot_shape_plan_context_t *c)
+hb_ot_shape_collect_features (hb_ot_map_t              *map,
+			      hb_segment_properties_t  *props,
+			      const hb_feature_t       *user_features,
+			      unsigned int              num_user_features)
 {
-  switch (c->props->direction) {
+  switch (props->direction) {
     case HB_DIRECTION_LTR:
-      c->map->add_bool_feature (HB_TAG ('l','t','r','a'));
-      c->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:
-      c->map->add_bool_feature (HB_TAG ('r','t','l','a'));
-      c->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:
@@ -67,13 +70,13 @@ hb_ot_shape_collect_features (hb_ot_shape_plan_context_t *c)
   }
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++)
-    c->map->add_bool_feature (default_features[i]);
+    map->add_bool_feature (default_features[i]);
 
   /* complex */
 
-  for (unsigned int i = 0; i < c->num_user_features; i++) {
-    const hb_feature_t *feature = &c->user_features[i];
-    c->map->add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
+  for (unsigned int i = 0; i < num_user_features; i++) {
+    const hb_feature_t *feature = &user_features[i];
+    map->add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
   }
 }
 
@@ -105,7 +108,7 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
   if (!hb_ot_layout_has_substitution (c->face))
     return;
 
-  c->map->substitute (c);
+  c->map->substitute (c->face, c->buffer);
 
   c->applied_substitute_complex = TRUE;
   return;
@@ -118,7 +121,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
   if (!hb_ot_layout_has_positioning (c->face))
     return;
 
-  c->map->position (c);
+  c->map->position (c->font, c->face, c->buffer);
 
   hb_ot_layout_position_finish (c->font, c->face, c->buffer);
 
@@ -324,11 +327,9 @@ hb_ot_shape_plan_internal (hb_ot_map_t              *map,
 			   const hb_feature_t       *user_features,
 			   unsigned int              num_user_features)
 {
-  hb_ot_shape_plan_context_t c = {map, face, props, user_features, num_user_features};
-
-  hb_ot_shape_collect_features (&c);
+  hb_ot_shape_collect_features (map, props, user_features, num_user_features);
 
-  map->compile (&c);
+  map->compile (face, props);
 }
 
 void
commit d2ba016ca1ba7489537768b619980d5159b5870c
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 15:35:45 2010 -0400

    More refactoring

diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 816ce4f..abf96f2 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -73,32 +73,10 @@ struct hb_ot_map_t {
     { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
   };
 
-
-  void
-  add_lookups (hb_ot_shape_context_t *c,
-	       unsigned int  table_index,
-	       unsigned int  feature_index,
-	       hb_mask_t     mask)
-  {
-    unsigned int i = MAX_LOOKUPS - lookup_count[table_index];
-    lookup_map_t *lookups = lookup_maps[table_index] + lookup_count[table_index];
-
-    unsigned int *lookup_indices = (unsigned int *) lookups;
-
-    hb_ot_layout_feature_get_lookup_indexes (c->face,
-					     table_tags[table_index],
-					     feature_index,
-					     0, &i,
-					     lookup_indices);
-
-    lookup_count[table_index] += i;
-
-    while (i--) {
-      lookups[i].mask = mask;
-      lookups[i].index = lookup_indices[i];
-    }
-  }
-
+  HB_INTERNAL void add_lookups (hb_ot_shape_plan_context_t *c,
+				unsigned int  table_index,
+				unsigned int  feature_index,
+				hb_mask_t     mask);
 
 
   public:
@@ -117,7 +95,7 @@ struct hb_ot_map_t {
   inline void add_bool_feature (hb_tag_t tag, bool global = true)
   { add_feature (tag, 1, global); }
 
-  HB_INTERNAL void compile (hb_ot_shape_context_t *c);
+  HB_INTERNAL void compile (hb_ot_shape_plan_context_t *c);
 
   hb_mask_t get_global_mask (void) const { return global_mask; }
 
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 8cf21b4..84149b8 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -34,7 +34,33 @@ HB_BEGIN_DECLS
 
 
 void
-hb_ot_map_t::compile (hb_ot_shape_context_t *c)
+hb_ot_map_t::add_lookups (hb_ot_shape_plan_context_t *c,
+			  unsigned int  table_index,
+			  unsigned int  feature_index,
+			  hb_mask_t     mask)
+{
+  unsigned int i = MAX_LOOKUPS - lookup_count[table_index];
+  lookup_map_t *lookups = lookup_maps[table_index] + lookup_count[table_index];
+
+  unsigned int *lookup_indices = (unsigned int *) lookups;
+
+  hb_ot_layout_feature_get_lookup_indexes (c->face,
+					   table_tags[table_index],
+					   feature_index,
+					   0, &i,
+					   lookup_indices);
+
+  lookup_count[table_index] += i;
+
+  while (i--) {
+    lookups[i].mask = mask;
+    lookups[i].index = lookup_indices[i];
+  }
+}
+
+
+void
+hb_ot_map_t::compile (hb_ot_shape_plan_context_t *c)
 {
  global_mask = 0;
  lookup_count[0] = lookup_count[1] = 0;
@@ -49,8 +75,8 @@ hb_ot_map_t::compile (hb_ot_shape_context_t *c)
   const hb_tag_t *script_tags;
   hb_tag_t language_tag;
 
-  script_tags = hb_ot_tags_from_script (c->buffer->props.script);
-  language_tag = hb_ot_tag_from_language (c->buffer->props.language);
+  script_tags = hb_ot_tags_from_script (c->props->script);
+  language_tag = hb_ot_tag_from_language (c->props->language);
 
   unsigned int script_index[2], language_index[2];
   for (unsigned int table_index = 0; table_index < 2; table_index++) {
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index b00be33..0d21e88 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -37,14 +37,26 @@ HB_BEGIN_DECLS
 
 struct hb_ot_map_t;
 
+struct hb_ot_shape_plan_context_t
+{
+  struct hb_ot_map_t *map;
+
+  hb_face_t *face;
+  hb_segment_properties_t *props;
+
+  const hb_feature_t *user_features;
+  unsigned int  num_user_features;
+};
+
+
 struct hb_ot_shape_context_t
 {
   /* Input to hb_ot_shape() */
   hb_font_t *font;
   hb_face_t *face;
   hb_buffer_t  *buffer;
-  hb_feature_t *features;
-  unsigned int  num_features;
+  const hb_feature_t *user_features;
+  unsigned int        num_user_features;
 
   /* Transient stuff */
   hb_direction_t original_direction;
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 8fc9c4f..b0494c7 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -49,9 +49,9 @@ hb_tag_t default_features[] = {
 };
 
 static void
-hb_ot_shape_collect_features (hb_ot_shape_context_t *c)
+hb_ot_shape_collect_features (hb_ot_shape_plan_context_t *c)
 {
-  switch (c->original_direction) {
+  switch (c->props->direction) {
     case HB_DIRECTION_LTR:
       c->map->add_bool_feature (HB_TAG ('l','t','r','a'));
       c->map->add_bool_feature (HB_TAG ('l','t','r','m'));
@@ -71,8 +71,8 @@ hb_ot_shape_collect_features (hb_ot_shape_context_t *c)
 
   /* complex */
 
-  for (unsigned int i = 0; i < c->num_features; i++) {
-    const hb_feature_t *feature = &c->features[i];
+  for (unsigned int i = 0; i < c->num_user_features; i++) {
+    const hb_feature_t *feature = &c->user_features[i];
     c->map->add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
   }
 }
@@ -85,9 +85,9 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
   if (global_mask)
     c->buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
 
-  for (unsigned int i = 0; i < c->num_features; i++)
+  for (unsigned int i = 0; i < c->num_user_features; i++)
   {
-    hb_feature_t *feature = &c->features[i];
+    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->map->get_mask (feature->tag, &shift);
@@ -271,6 +271,9 @@ hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
 static void
 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
+  /* Save the original direction, we use it later. */
+  c->original_direction = c->buffer->props.direction;
+
   hb_ot_shape_setup_masks (c);
 
   hb_form_clusters (c);
@@ -315,22 +318,32 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
 }
 
 void
+hb_ot_shape_plan_internal (hb_ot_map_t              *map,
+			   hb_face_t                *face,
+			   hb_segment_properties_t  *props,
+			   const hb_feature_t       *user_features,
+			   unsigned int              num_user_features)
+{
+  hb_ot_shape_plan_context_t c = {map, face, props, user_features, num_user_features};
+
+  hb_ot_shape_collect_features (&c);
+
+  map->compile (&c);
+}
+
+void
 hb_ot_shape (hb_font_t    *font,
 	     hb_face_t    *face,
 	     hb_buffer_t  *buffer,
-	     hb_feature_t *features,
-	     unsigned int  num_features)
+	     const hb_feature_t *user_features,
+	     unsigned int        num_user_features)
 {
-  hb_ot_shape_context_t c = {font, face, buffer, features, num_features};
   hb_ot_map_t map;
 
-  /* Setup transient context members */
-  c.original_direction = buffer->props.direction;
-  c.map = ↦
-
-  hb_ot_shape_collect_features (&c);
-  c.map->compile (&c);
+  hb_ot_shape_plan_internal (&map, face, &buffer->props, user_features, num_user_features);
 
+  hb_ot_shape_context_t c = {font, face, buffer, user_features, num_user_features};
+  c.map = ↦
   hb_ot_shape_internal (&c);
 }
 
diff --git a/src/hb-ot-shape.h b/src/hb-ot-shape.h
index 182d951..c90e0fe 100644
--- a/src/hb-ot-shape.h
+++ b/src/hb-ot-shape.h
@@ -34,11 +34,11 @@ HB_BEGIN_DECLS
 
 
 void
-hb_ot_shape (hb_font_t    *font,
-	     hb_face_t    *face,
-	     hb_buffer_t  *buffer,
-	     hb_feature_t *features,
-	     unsigned int  num_features);
+hb_ot_shape (hb_font_t          *font,
+	     hb_face_t          *face,
+	     hb_buffer_t        *buffer,
+	     const hb_feature_t *user_features,
+	     unsigned int        num_user_features);
 
 
 HB_END_DECLS
commit 66e487dfbfdccd0c4be8cd11661d412ca27c3425
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 12 13:51:19 2010 -0400

    Update Arabic shaping table to Unicode 6.0.0.

diff --git a/src/hb-ot-shape-arabic.cc b/src/hb-ot-shape-arabic.cc
index 7729be1..fb5182b 100644
--- a/src/hb-ot-shape-arabic.cc
+++ b/src/hb-ot-shape-arabic.cc
@@ -64,8 +64,8 @@ static const uint8_t arabic_syriac_nko_joining_types[0x0800 - 0x0600 + 1] =
    *
    * on the ArabicShaping.txt file with the header:
    *
-   * # ArabicShaping-5.2.0.txt
-   * # Date: 2009-08-17, 11:11:00 PDT [KW]
+   * # ArabicShaping-6.0.0.txt
+   * # Date: 2010-04-30, 13:47:00 PDT [KW]
    */
   /* == Start of generated table == */
   JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */
@@ -100,7 +100,7 @@ static const uint8_t arabic_syriac_nko_joining_types[0x0800 - 0x0600 + 1] =
   JOINING_TYPE_X, /* 061D */
   JOINING_TYPE_X, /* 061E */
   JOINING_TYPE_X, /* 061F */
-  JOINING_TYPE_X, /* 0620 */
+  JOINING_TYPE_D, /* 0620; YEH WITH RING; D; YEH */
   JOINING_TYPE_U, /* 0621; HAMZA; U; No_Joining_Group */
   JOINING_TYPE_R, /* 0622; MADDA ON ALEF; R; ALEF */
   JOINING_TYPE_R, /* 0623; HAMZA ON ALEF; R; ALEF */
@@ -263,7 +263,7 @@ static const uint8_t arabic_syriac_nko_joining_types[0x0800 - 0x0600 + 1] =
   JOINING_TYPE_R, /* 06C0; HAMZA ON HEH; R; TEH MARBUTA */
   JOINING_TYPE_D, /* 06C1; HEH GOAL; D; HEH GOAL */
   JOINING_TYPE_D, /* 06C2; HAMZA ON HEH GOAL; D; HEH GOAL */
-  JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; HAMZA ON HEH GOAL */
+  JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL */
   JOINING_TYPE_R, /* 06C4; WAW WITH RING; R; WAW */
   JOINING_TYPE_R, /* 06C5; WAW WITH BAR; R; WAW */
   JOINING_TYPE_R, /* 06C6; WAW WITH SMALL V; R; WAW */



More information about the HarfBuzz mailing list