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

Behdad Esfahbod behdad at kemper.freedesktop.org
Fri Jul 27 09:56:02 PDT 2012


 TODO                             |    4 
 src/Makefile.am                  |   16 +-
 src/hb-buffer-private.hh         |   31 ++++
 src/hb-buffer.cc                 |    1 
 src/hb-coretext-private.hh       |   42 -----
 src/hb-coretext.cc               |    6 
 src/hb-fallback-shape-private.hh |   41 -----
 src/hb-fallback-shape.cc         |   67 ++++++++-
 src/hb-font-private.hh           |   24 +++
 src/hb-font.cc                   |   48 +++++-
 src/hb-graphite2-private.hh      |   42 -----
 src/hb-old-private.hh            |   40 -----
 src/hb-old.cc                    |  128 ++++++++---------
 src/hb-ot-layout-gpos-table.hh   |    2 
 src/hb-ot-layout-gsub-table.hh   |    4 
 src/hb-ot-layout-private.hh      |    1 
 src/hb-ot-layout.cc              |   16 +-
 src/hb-ot-layout.h               |    6 
 src/hb-ot-shape-private.hh       |   14 -
 src/hb-ot-shape.cc               |  131 ++++++++++++------
 src/hb-shape-plan-private.hh     |   60 ++++++++
 src/hb-shape-plan.cc             |  281 +++++++++++++++++++++++++++++++++++++++
 src/hb-shape-plan.h              |   75 ++++++++++
 src/hb-shape.cc                  |  156 ++-------------------
 src/hb-shaper-impl-private.hh    |   43 +++++
 src/hb-shaper-list.hh            |   50 ++++++
 src/hb-shaper-private.hh         |  108 ++++++++++++++
 src/hb-shaper.cc                 |  109 +++++++++++++++
 src/hb-uniscribe-private.hh      |   42 -----
 src/hb-uniscribe.cc              |  224 +++++++++++++++----------------
 src/hb-uniscribe.h               |    4 
 31 files changed, 1206 insertions(+), 610 deletions(-)

New commits:
commit 2f87cebe1062c7007021ebd05c1664e60da80825
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 04:02:38 2012 -0400

    Implement shape_plan caching
    
    Should give us some performance boost.

diff --git a/TODO b/TODO
index 0521b85..be381e3 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,10 @@
 General fixes:
 =============
 
+- mask propagation (when ligation, "or" the masks).
+
+- fail_shaper that always fails.
+
 - Make map in setup_masks() const, etc.
 
 - Warn at compile time (and runtime with HB_DEBUG?) if no Unicode / font
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index b800aeb..d6189d2 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -40,14 +40,44 @@
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
 
+
+/*
+ * hb_segment_properties_t
+ */
+
 typedef struct hb_segment_properties_t {
     hb_direction_t      direction;
     hb_script_t         script;
     hb_language_t       language;
     ASSERT_POD ();
 } hb_segment_properties_t;
+
 #define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
 
+static inline hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+			     const hb_segment_properties_t *b)
+{
+  return a->direction == b->direction &&
+	 a->script    == b->script    &&
+	 a->language  == b->language;
+}
+
+
+static inline long
+hb_segment_properties_hash (const hb_segment_properties_t *p)
+{
+  /* TODO improve */
+  return (long) p->direction +
+	 (long) p->script +
+	 (long) p->language;
+}
+
+
+
+/*
+ * hb_buffer_t
+ */
 
 struct hb_buffer_t {
   hb_object_header_t header;
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index f1b43c0..892fd7c 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -34,6 +34,7 @@
 #include "hb-font.h"
 #include "hb-object-private.hh"
 #include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
 
 
 
@@ -101,6 +102,11 @@ struct hb_face_t {
   unsigned int upem;
 
   struct hb_shaper_data_t shaper_data;
+
+  struct plan_node_t {
+    hb_shape_plan_t *shape_plan;
+    plan_node_t *next;
+  } *shape_plans;
 };
 
 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 5a3219a..83c349e 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -596,7 +596,9 @@ static const hb_face_t _hb_face_nil = {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
-  }
+  },
+
+  NULL, /* shape_plans */
 };
 
 
@@ -709,6 +711,17 @@ hb_face_destroy (hb_face_t *face)
 {
   if (!hb_object_destroy (face)) return;
 
+  /* The cached shape_plans think they have a reference on us, and
+   * try to release it.  Make sure that doesn't mess up. */
+  face->header.ref_count.ref_count = HB_REFERENCE_COUNT_INVALID_VALUE;
+  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
+  {
+    hb_face_t::plan_node_t *next = node->next;
+    hb_shape_plan_destroy (node->shape_plan);
+    free (node);
+    node = next;
+  }
+
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 663cb34..af3c18d 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -179,3 +179,103 @@ hb_shape_plan_execute (hb_shape_plan      *shape_plan,
 
   return false;
 }
+
+
+/*
+ * caching
+ */
+
+#if 0
+static long
+hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
+{
+  return hb_segment_properties_hash (&shape_plan->props) +
+	 shape_plan->default_shaper_list ? 0 : (long) shape_plan->shaper_func;
+}
+#endif
+
+/* TODO no user-feature caching for now. */
+struct hb_shape_plan_proposal_t
+{
+  const hb_segment_properties_t  props;
+  const char * const            *shaper_list;
+  hb_shape_func_t               *shaper_func;
+};
+
+static hb_bool_t
+hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
+		       const hb_shape_plan_proposal_t *proposal)
+{
+  return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
+	 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
+	  (shape_plan->shaper_func == proposal->shaper_func));
+}
+
+hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t                     *face,
+			     const hb_segment_properties_t *props,
+			     const hb_feature_t            *user_features,
+			     unsigned int                   num_user_features,
+			     const char * const            *shaper_list)
+{
+  if (num_user_features)
+    return hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+
+  hb_shape_plan_proposal_t proposal = {
+    *props,
+    shaper_list,
+    NULL
+  };
+
+  if (shaper_list) {
+    /* Choose shaper.  Adapted from hb_shape_plan_plan(). */
+#define HB_SHAPER_PLAN(shaper) \
+	  HB_STMT_START { \
+	    if (hb_##shaper##_shaper_face_data_ensure (face)) \
+	      proposal.shaper_func = _hb_##shaper##_shape; \
+	  } HB_STMT_END
+
+    for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
+      if (0)
+	;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (0 == strcmp (*shaper_item, #shaper)) \
+	HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+#undef HB_SHAPER_PLAN
+
+    if (unlikely (!proposal.shaper_list))
+      return hb_shape_plan_get_empty ();
+  }
+
+
+retry:
+  hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
+  for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
+    if (hb_shape_plan_matches (node->shape_plan, &proposal))
+      return hb_shape_plan_reference (node->shape_plan);
+
+  /* Not found. */
+
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+
+  hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
+  if (unlikely (!node))
+    return shape_plan;
+
+  node->shape_plan = shape_plan;
+  node->next = cached_plan_nodes;
+
+  if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
+    hb_shape_plan_destroy (shape_plan);
+    free (node);
+    goto retry;
+  }
+
+  /* Release our reference on face. */
+  hb_face_destroy (face);
+
+  return hb_shape_plan_reference (shape_plan);
+}
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
index a4786a8..fbce5dd 100644
--- a/src/hb-shape-plan.h
+++ b/src/hb-shape-plan.h
@@ -47,6 +47,13 @@ hb_shape_plan_create (hb_face_t                     *face,
 		      unsigned int                   num_user_features,
 		      const char * const            *shaper_list);
 
+hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t                     *face,
+			     const hb_segment_properties_t *props,
+			     const hb_feature_t            *user_features,
+			     unsigned int                   num_user_features,
+			     const char * const            *shaper_list);
+
 HB_INTERNAL hb_shape_plan_t *
 hb_shape_plan_get_empty (void);
 
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index fde9cf2..5aa587b 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -87,7 +87,7 @@ hb_shape_full (hb_font_t          *font,
 
   buffer->guess_properties ();
 
-  hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, shaper_list);
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
   return res;
commit e9eb9503e97044222f843daacfa47e26e51312b7
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 03:16:22 2012 -0400

    Add default_shaper_list to shape_plan

diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
index 1b3c3b2..d6a57d6 100644
--- a/src/hb-shape-plan-private.hh
+++ b/src/hb-shape-plan-private.hh
@@ -39,6 +39,7 @@ struct hb_shape_plan_t
   hb_object_header_t header;
   ASSERT_POD ();
 
+  hb_bool_t default_shaper_list;
   hb_face_t *face;
   hb_segment_properties_t props;
 
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 83de1f6..663cb34 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -100,6 +100,7 @@ hb_shape_plan_create (hb_face_t                     *face,
     return hb_shape_plan_get_empty ();
 
   hb_face_make_immutable (face);
+  shape_plan->default_shaper_list = shaper_list == NULL;
   shape_plan->face = hb_face_reference (face);
   shape_plan->props = *props;
 
@@ -114,6 +115,7 @@ hb_shape_plan_get_empty (void)
   static const hb_shape_plan_t _hb_shape_plan_nil = {
     HB_OBJECT_HEADER_STATIC,
 
+    TRUE, /* default_shaper_list */
     NULL, /* face */
     _HB_BUFFER_PROPS_DEFAULT, /* props */
 
commit 3b7c4e270694ed962e2a2839e44f2a59c26b326c
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 03:12:23 2012 -0400

    Don't fail choosing shaper on planning failure
    
    Shapers have a chance to reject a font in face shaper_data creation.
    No need to allow failing during planning.

diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index b0a8937..83de1f6 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -48,13 +48,10 @@ hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 #define HB_SHAPER_PLAN(shaper) \
 	HB_STMT_START { \
 	  if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face)) { \
-	    HB_SHAPER_DATA_TYPE (shaper, shape_plan) *data= \
+	    HB_SHAPER_DATA (shaper, shape_plan) = \
 	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
-	    if (data) { \
-	      HB_SHAPER_DATA (shaper, shape_plan) = data; \
-	      shape_plan->shaper_func = _hb_##shaper##_shape; \
-	      return; \
-	    } \
+	    shape_plan->shaper_func = _hb_##shaper##_shape; \
+	    return; \
 	  } \
 	} HB_STMT_END
 
@@ -163,11 +160,9 @@ hb_shape_plan_execute (hb_shape_plan      *shape_plan,
 
 #define HB_SHAPER_EXECUTE(shaper) \
 	HB_STMT_START { \
-	  if (hb_##shaper##_shaper_font_data_ensure (font) && \
-	      _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features)) \
-	    return true; \
-	  else \
-	    return false; \
+	  return HB_SHAPER_DATA (shaper, shape_plan) && \
+		 hb_##shaper##_shaper_font_data_ensure (font) && \
+		 _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
 	} HB_STMT_END
 
   if (0)
commit cfe9882610489e1b917e09a74dfbf6bbba2e4a57
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 03:06:30 2012 -0400

    Add hb_ot_layout_ensure() and hb_uniscribe_font_ensure()

diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index dff3673..eb39c65 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -38,6 +38,13 @@
 #include <string.h>
 
 
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+hb_bool_t
+hb_ot_layout_ensure (hb_face_t *face)
+{
+  return hb_ot_shaper_face_data_ensure (face);
+}
+
 
 hb_ot_layout_t *
 _hb_ot_layout_create (hb_face_t *face)
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index cf178b7..af23478 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -42,6 +42,12 @@ HB_BEGIN_DECLS
 #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
 #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
 
+
+/* Must call before all other funtions in this file.  Idempotent. */
+hb_bool_t
+hb_ot_layout_ensure (hb_face_t *face);
+
+
 /*
  * GDEF
  */
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 1820f61..b0a8937 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -30,24 +30,6 @@
 #include "hb-shaper-private.hh"
 #include "hb-font-private.hh"
 
-#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
-static inline bool \
-hb_##shaper##_##object##_data_ensure (hb_##object##_t *object) \
-{\
-  retry: \
-  HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
-  if (unlikely (!data)) { \
-    data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
-    if (unlikely (!data)) \
-      data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
-    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
-      HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
-      goto retry; \
-    } \
-  } \
-  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
-}
-
 #define HB_SHAPER_IMPLEMENT(shaper) \
 	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
 	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
@@ -65,7 +47,7 @@ hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 
 #define HB_SHAPER_PLAN(shaper) \
 	HB_STMT_START { \
-	  if (hb_##shaper##_face_data_ensure (shape_plan->face)) { \
+	  if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face)) { \
 	    HB_SHAPER_DATA_TYPE (shaper, shape_plan) *data= \
 	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
 	    if (data) { \
@@ -181,7 +163,7 @@ hb_shape_plan_execute (hb_shape_plan      *shape_plan,
 
 #define HB_SHAPER_EXECUTE(shaper) \
 	HB_STMT_START { \
-	  if (hb_##shaper##_font_data_ensure (font) && \
+	  if (hb_##shaper##_shaper_font_data_ensure (font) && \
 	      _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features)) \
 	    return true; \
 	  else \
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index e50d869..186318d 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -86,5 +86,23 @@ struct hb_shaper_data_t {
 	    object->shaper_data.shaper != HB_SHAPER_DATA_SUCCEEDED) \
 	  HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA (shaper, object));
 
+#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
+static inline bool \
+hb_##shaper##_shaper_##object##_data_ensure (hb_##object##_t *object) \
+{\
+  retry: \
+  HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
+  if (unlikely (!data)) { \
+    data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
+    if (unlikely (!data)) \
+      data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
+    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
+      HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
+      goto retry; \
+    } \
+  } \
+  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
+}
+
 
 #endif /* HB_SHAPER_PRIVATE_HH */
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 4368f68..7d06a6b 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -56,6 +56,17 @@ DWORD GetFontData(
 */
 
 
+HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
+hb_bool_t
+hb_uniscribe_font_ensure (hb_font_t *font)
+{
+  hb_face_t *face = font->face;
+  return hb_uniscribe_shaper_face_data_ensure (face) &&
+         hb_uniscribe_shaper_font_data_ensure (font);
+}
+
+
 /*
  * shaper face data
  */
diff --git a/src/hb-uniscribe.h b/src/hb-uniscribe.h
index bb99f39..2758dab 100644
--- a/src/hb-uniscribe.h
+++ b/src/hb-uniscribe.h
@@ -34,6 +34,10 @@
 
 HB_BEGIN_DECLS
 
+/* Must call before all other funtions in this file.  Idempotent. */
+hb_bool_t
+hb_uniscribe_font_ensure (hb_font_t *font);
+
 
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font);
commit c5b668fb9239c912d2448280a7176e331ebc9181
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 02:49:39 2012 -0400

    Choose one shaper per plan

diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
index c292f14..1b3c3b2 100644
--- a/src/hb-shape-plan-private.hh
+++ b/src/hb-shape-plan-private.hh
@@ -42,7 +42,7 @@ struct hb_shape_plan_t
   hb_face_t *face;
   hb_segment_properties_t props;
 
-  hb_shape_func_t *shapers[HB_SHAPERS_COUNT];
+  hb_shape_func_t *shaper_func;
 
   struct hb_shaper_data_t shaper_data;
 };
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 099d09c..1820f61 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -62,7 +62,6 @@ hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 		    const char * const *shaper_list)
 {
   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
-  unsigned num_shapers = 0;
 
 #define HB_SHAPER_PLAN(shaper) \
 	HB_STMT_START { \
@@ -71,10 +70,9 @@ hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
 	    if (data) { \
 	      HB_SHAPER_DATA (shaper, shape_plan) = data; \
-	      shape_plan->shapers[num_shapers++] = _hb_##shaper##_shape; \
-	    } \
-	    if (false /* shaper never fails */) \
+	      shape_plan->shaper_func = _hb_##shaper##_shape; \
 	      return; \
+	    } \
 	  } \
 	} HB_STMT_END
 
@@ -140,7 +138,7 @@ hb_shape_plan_get_empty (void)
     NULL, /* face */
     _HB_BUFFER_PROPS_DEFAULT, /* props */
 
-    {NULL}, /* shapers */
+    NULL, /* shaper_func */
 
     {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
@@ -186,14 +184,15 @@ hb_shape_plan_execute (hb_shape_plan      *shape_plan,
 	  if (hb_##shaper##_font_data_ensure (font) && \
 	      _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features)) \
 	    return true; \
+	  else \
+	    return false; \
 	} HB_STMT_END
 
-  for (hb_shape_func_t **shaper_func = shape_plan->shapers; *shaper_func; shaper_func++)
-    if (0)
-      ;
+  if (0)
+    ;
 #define HB_SHAPER_IMPLEMENT(shaper) \
-    else if (*shaper_func == _hb_##shaper##_shape) \
-      HB_SHAPER_EXECUTE (shaper);
+  else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
+    HB_SHAPER_EXECUTE (shaper);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 
commit e82061e8db922f0ddbefd5a184ee2f9f967b9a05
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 02:29:32 2012 -0400

    Move ot shaper completely to shape_plan

diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 8c8876a..e1f6a69 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -37,12 +37,6 @@ struct hb_ot_shape_plan_t
 {
   hb_ot_map_t map;
   hb_ot_complex_shaper_t shaper;
-
-  hb_ot_shape_plan_t (void) : map () {}
-  ~hb_ot_shape_plan_t (void) { map.finish (); }
-
-  private:
-  NO_COPY (hb_ot_shape_plan_t);
 };
 
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 22dea07..e04e700 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -28,6 +28,7 @@
 
 #define HB_SHAPER ot
 #define hb_ot_shaper_face_data_t hb_ot_layout_t
+#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
 #include "hb-shaper-impl-private.hh"
 
 #include "hb-ot-shape-private.hh"
@@ -37,65 +38,6 @@
 #include "hb-set-private.hh"
 
 
-/*
- * shaper face data
- */
-
-hb_ot_shaper_face_data_t *
-_hb_ot_shaper_face_data_create (hb_face_t *face)
-{
-  return _hb_ot_layout_create (face);
-}
-
-void
-_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
-{
-  _hb_ot_layout_destroy (data);
-}
-
-
-/*
- * shaper font data
- */
-
-struct hb_ot_shaper_font_data_t {};
-
-hb_ot_shaper_font_data_t *
-_hb_ot_shaper_font_data_create (hb_font_t *font)
-{
-  return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
-}
-
-void
-_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
-{
-}
-
-
-/*
- * shaper shape_plan data
- */
-
-struct hb_ot_shaper_shape_plan_data_t {};
-
-hb_ot_shaper_shape_plan_data_t *
-_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
-				      const hb_feature_t *user_features,
-				      unsigned int        num_user_features)
-{
-  return (hb_ot_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
-}
-
-void
-_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *data)
-{
-}
-
-
-/*
- * shaper
- */
-
 hb_tag_t common_features[] = {
   HB_TAG('c','c','m','p'),
   HB_TAG('l','i','g','a'),
@@ -138,7 +80,7 @@ struct hb_ot_shape_planner_t
 
   inline void compile (hb_face_t *face,
 		       const hb_segment_properties_t *props,
-		       struct hb_ot_shape_plan_t &plan)
+		       hb_ot_shape_plan_t &plan)
   {
     plan.shaper = shaper;
     map.compile (face, props, plan.map);
@@ -196,9 +138,81 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 }
 
 
+/*
+ * shaper face data
+ */
+
+hb_ot_shaper_face_data_t *
+_hb_ot_shaper_face_data_create (hb_face_t *face)
+{
+  return _hb_ot_layout_create (face);
+}
+
+void
+_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
+{
+  _hb_ot_layout_destroy (data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_ot_shaper_font_data_t {};
+
+hb_ot_shaper_font_data_t *
+_hb_ot_shaper_font_data_create (hb_font_t *font)
+{
+  return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+hb_ot_shaper_shape_plan_data_t *
+_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+				      const hb_feature_t *user_features,
+				      unsigned int        num_user_features)
+{
+  hb_ot_shape_plan_t *data = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
+  if (unlikely (!data))
+    return NULL;
+
+  hb_ot_shape_planner_t planner;
+
+  assert (HB_DIRECTION_IS_VALID (shape_plan->props.direction));
+
+  planner.shaper = hb_ot_shape_complex_categorize (&shape_plan->props);
+
+  hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
+
+  planner.compile (shape_plan->face, &shape_plan->props, *data);
+
+  return data;
+}
+
+void
+_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *data)
+{
+  data->map.finish ();
+}
+
+
+/*
+ * shaper
+ */
+
 struct hb_ot_shape_context_t
 {
-  /* Input to hb_ot_shape_execute() */
+  /* Input to hb_ot_shape_internal() */
   hb_ot_shape_plan_t *plan;
   hb_font_t *font;
   hb_face_t *face;
@@ -458,7 +472,7 @@ hb_hide_zerowidth (hb_ot_shape_context_t *c)
 /* Do it! */
 
 static void
-hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
+hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
   c->buffer->deallocate_var_all ();
 
@@ -514,34 +528,6 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
   c->buffer->deallocate_var_all ();
 }
 
-static void
-hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
-			   hb_face_t                *face,
-			   const hb_segment_properties_t  *props,
-			   const hb_feature_t       *user_features,
-			   unsigned int              num_user_features)
-{
-  hb_ot_shape_planner_t planner;
-
-  assert (HB_DIRECTION_IS_VALID (props->direction));
-
-  planner.shaper = hb_ot_shape_complex_categorize (props);
-
-  hb_ot_shape_collect_features (&planner, props, user_features, num_user_features);
-
-  planner.compile (face, props, *plan);
-}
-
-static void
-hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
-		     hb_font_t          *font,
-		     hb_buffer_t        *buffer,
-		     const hb_feature_t *user_features,
-		     unsigned int        num_user_features)
-{
-  hb_ot_shape_context_t c = {plan, font, font->face, buffer, user_features, num_user_features};
-  hb_ot_shape_execute_internal (&c);
-}
 
 hb_bool_t
 _hb_ot_shape (hb_shape_plan_t    *shape_plan,
@@ -550,12 +536,8 @@ _hb_ot_shape (hb_shape_plan_t    *shape_plan,
 	      const hb_feature_t *features,
 	      unsigned int        num_features)
 {
-  hb_ot_shape_plan_t plan;
-
-  buffer->guess_properties ();
-
-  hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
-  hb_ot_shape_execute (&plan, font, buffer, features, num_features);
+  hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
+  hb_ot_shape_internal (&c);
 
   return true;
 }
@@ -572,7 +554,8 @@ hb_ot_shape_glyphs_closure (hb_font_t          *font,
 
   buffer->guess_properties ();
 
-  hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
+  /* TODO cache / ensure correct backend, etc. */
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, NULL);
 
   /* TODO: normalization? have shapers do closure()? */
   /* TODO: Deal with mirrored chars? */
@@ -590,6 +573,8 @@ hb_ot_shape_glyphs_closure (hb_font_t          *font,
 
   do {
     copy.set (glyphs);
-    plan.map.substitute_closure (font->face, glyphs);
+    HB_SHAPER_DATA_GET (shape_plan)->map.substitute_closure (font->face, glyphs);
   } while (!copy.equal (glyphs));
+
+  hb_shape_plan_destroy (shape_plan);
 }
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 67e245c..4368f68 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -144,7 +144,7 @@ populate_log_font (LOGFONTW  *lf,
 hb_uniscribe_shaper_font_data_t *
 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
 {
-  hb_uniscribe_shaper_font_data_t * data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
+  hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
   if (unlikely (!data))
     return NULL;
 
commit ea278d3895fe0c92801d692cd71d8d9f1de7c048
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 02:12:28 2012 -0400

    Partially switch ot shaper to shape_plan

diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index e06a7fa..b800aeb 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -46,6 +46,7 @@ typedef struct hb_segment_properties_t {
     hb_language_t       language;
     ASSERT_POD ();
 } hb_segment_properties_t;
+#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
 
 
 struct hb_buffer_t {
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 2b4acff..f8c62ac 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -38,7 +38,6 @@
 #endif
 
 #define _HB_BUFFER_UNICODE_FUNCS_DEFAULT (const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default))
-#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
 
 /* Here is how the buffer works internally:
  *
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 2540dd6..f1b43c0 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -97,8 +97,6 @@ struct hb_face_t {
   void                      *user_data;
   hb_destroy_func_t          destroy;
 
-  struct hb_ot_layout_t *ot_layout;
-
   unsigned int index;
   unsigned int upem;
 
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 1261077..5a3219a 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -589,10 +589,14 @@ static const hb_face_t _hb_face_nil = {
   NULL, /* user_data */
   NULL, /* destroy */
 
-  NULL, /* ot_layout */
-
   0,    /* index */
-  1000  /* upem */
+  1000, /* upem */
+
+  {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  }
 };
 
 
@@ -613,8 +617,6 @@ hb_face_create_for_tables (hb_reference_table_func_t  reference_table,
   face->user_data = user_data;
   face->destroy = destroy;
 
-  face->ot_layout = _hb_ot_layout_create (face);
-
   face->upem = 0;
 
   return face;
@@ -707,8 +709,6 @@ hb_face_destroy (hb_face_t *face)
 {
   if (!hb_object_destroy (face)) return;
 
-  _hb_ot_layout_destroy (face->ot_layout);
-
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
@@ -877,7 +877,13 @@ hb_font_get_empty (void)
 
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
     NULL, /* user_data */
-    NULL  /* destroy */
+    NULL, /* destroy */
+
+    {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+    }
   };
 
   return const_cast<hb_font_t *> (&_hb_font_nil);
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 5b71407..a35f633 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1553,7 +1553,7 @@ inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
 
 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
 {
-  const GPOS &gpos = *(c->face->ot_layout->gpos);
+  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
 
   if (unlikely (c->nesting_level_left == 0))
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 600a92a..038cb93 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1241,7 +1241,7 @@ inline bool ExtensionSubst::is_reverse (void) const
 
 static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
 {
-  const GSUB &gsub = *(c->face->ot_layout->gsub);
+  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
 
   if (unlikely (c->nesting_level_left == 0))
@@ -1254,7 +1254,7 @@ static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_
 
 static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
 {
-  const GSUB &gsub = *(c->face->ot_layout->gsub);
+  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
 
   if (unlikely (c->nesting_level_left == 0))
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index ba375aa..294c359 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -36,6 +36,7 @@
 #include "hb-ot-shape-complex-private.hh"
 
 
+#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 
 /*
  * GDEF
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index c6de75c..dff3673 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -70,17 +70,20 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
 static inline const GDEF&
 _get_gdef (hb_face_t *face)
 {
-  return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
+  /* XXX ensure ot_layout, and speed up */
+  return *hb_ot_layout_from_face (face)->gdef;
 }
 static inline const GSUB&
 _get_gsub (hb_face_t *face)
 {
-  return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
+  /* XXX ensure ot_layout, and speed up */
+  return *hb_ot_layout_from_face (face)->gsub;
 }
 static inline const GPOS&
 _get_gpos (hb_face_t *face)
 {
-  return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
+  /* XXX ensure ot_layout, and speed up */
+  return *hb_ot_layout_from_face (face)->gpos;
 }
 
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 639748e..22dea07 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -44,12 +44,13 @@
 hb_ot_shaper_face_data_t *
 _hb_ot_shaper_face_data_create (hb_face_t *face)
 {
-  return (hb_ot_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+  return _hb_ot_layout_create (face);
 }
 
 void
 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
 {
+  _hb_ot_layout_destroy (data);
 }
 
 
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index db21e88..099d09c 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -136,6 +136,17 @@ hb_shape_plan_get_empty (void)
 {
   static const hb_shape_plan_t _hb_shape_plan_nil = {
     HB_OBJECT_HEADER_STATIC,
+
+    NULL, /* face */
+    _HB_BUFFER_PROPS_DEFAULT, /* props */
+
+    {NULL}, /* shapers */
+
+    {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+    }
   };
 
   return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index 1cf7c5b..e50d869 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -68,7 +68,8 @@ struct hb_shaper_data_t {
 #define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
 
 #define HB_SHAPER_DATA_TYPE(shaper, object)		struct hb_##shaper##_shaper_##object##_data_t
-#define HB_SHAPER_DATA(shaper, object)			(* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(object)->shaper_data.shaper)
+#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance)	(* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
+#define HB_SHAPER_DATA(shaper, object)			HB_SHAPER_DATA_INSTANCE (shaper, object, object)
 #define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create
 #define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_destroy
 
commit b6b7ba1313bf686e6ed567183466104c90504a67
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 01:26:11 2012 -0400

    Switch old and uniscribe backends to shape_plan

diff --git a/src/hb-old.cc b/src/hb-old.cc
index 77761e8..f938a9b 100644
--- a/src/hb-old.cc
+++ b/src/hb-old.cc
@@ -248,61 +248,6 @@ _hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data)
  * shaper
  */
 
-
-static hb_user_data_key_t hb_old_data_key;
-
-static HB_Face
-_hb_old_face_get (hb_face_t *face)
-{
-  HB_Face data = (HB_Face) hb_face_get_user_data (face, &hb_old_data_key);
-  if (likely (data)) return data;
-
-  data = _hb_old_shaper_face_data_create (face);
-
-  if (unlikely (!data)) {
-    DEBUG_MSG (OLD, face, "HB_NewFace failed");
-    return NULL;
-  }
-
-  if (unlikely (!hb_face_set_user_data (face, &hb_old_data_key, data,
-                                        (hb_destroy_func_t) _hb_old_shaper_face_data_destroy,
-                                        false)))
-  {
-    _hb_old_shaper_face_data_destroy (data);
-    data = (HB_Face) hb_face_get_user_data (face, &hb_old_data_key);
-    if (data)
-      return data;
-    else
-      return NULL;
-  }
-
-  return data;
-}
-
-
-static HB_Font
-_hb_old_font_get (hb_font_t *font)
-{
-  /* Ouch, check user_data! */
-  HB_Font data = _hb_old_shaper_font_data_create (font);
-  if (!data)
-    return NULL;
-
-  if (unlikely (!hb_font_set_user_data (font, &hb_old_data_key, data,
-                                        (hb_destroy_func_t) _hb_old_shaper_font_data_destroy,
-                                        false)))
-  {
-    _hb_old_shaper_font_data_destroy (data);
-    data = (HB_Font) hb_font_get_user_data (font, &hb_old_data_key);
-    if (data)
-      return data;
-    else
-      return NULL;
-  }
-
-  return data;
-}
-
 hb_bool_t
 _hb_old_shape (hb_shape_plan_t    *shape_plan,
 	       hb_font_t          *font,
@@ -310,27 +255,12 @@ _hb_old_shape (hb_shape_plan_t    *shape_plan,
 	       const hb_feature_t *features,
 	       unsigned int        num_features)
 {
-  if (unlikely (!buffer->len))
-    return true;
-
-  buffer->guess_properties ();
+  hb_face_t *face = font->face;
+  HB_Face old_face = HB_SHAPER_DATA_GET (face);
+  HB_Font old_font = HB_SHAPER_DATA_GET (font);
 
   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
-#define FAIL(...) \
-  HB_STMT_START { \
-    DEBUG_MSG (OLD, NULL, __VA_ARGS__); \
-    return false; \
-  } HB_STMT_END;
-
-  HB_Face old_face = _hb_old_face_get (font->face);
-  if (unlikely (!old_face))
-    FAIL ("Couldn't get old face");
-
-  HB_Font old_font = _hb_old_font_get (font);
-  if (unlikely (!old_font))
-    FAIL ("Couldn't get old font");
-
 retry:
 
   unsigned int scratch_size;
@@ -398,7 +328,7 @@ retry:
     {
       buffer->ensure (buffer->allocated * 2);
       if (buffer->in_error)
-	FAIL ("Buffer resize failed");
+        return false;
       goto retry;
     }
     return false;
@@ -429,7 +359,7 @@ retry:
 
   buffer->ensure (num_glyphs);
   if (buffer->in_error)
-    FAIL ("Buffer in error");
+    return false;
 
 
   buffer->len = num_glyphs;
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 0087618..fde9cf2 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -82,6 +82,11 @@ hb_shape_full (hb_font_t          *font,
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
+  if (unlikely (!buffer->len))
+    return true;
+
+  buffer->guess_properties ();
+
   hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, shaper_list);
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
diff --git a/src/hb-shaper-impl-private.hh b/src/hb-shaper-impl-private.hh
index 91ee14f..7844081 100644
--- a/src/hb-shaper-impl-private.hh
+++ b/src/hb-shaper-impl-private.hh
@@ -36,8 +36,7 @@
 
 
 #ifdef HB_SHAPER
-/* For use in things like font->shaper_data() in the shaper implementations. */
-#define shaper_data() shaper_data.HB_SHAPER
+#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object)
 #endif
 
 
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index 9e35ef8..1cf7c5b 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -69,15 +69,11 @@ struct hb_shaper_data_t {
 
 #define HB_SHAPER_DATA_TYPE(shaper, object)		struct hb_##shaper##_shaper_##object##_data_t
 #define HB_SHAPER_DATA(shaper, object)			(* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(object)->shaper_data.shaper)
-#define HB_SHAPER_DATA_GET_FUNC(shaper, object)		_hb_##shaper##_shaper_get_##object##_data
 #define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create
 #define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_destroy
 
 #define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
 	HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
-	static inline HB_SHAPER_DATA_TYPE (shaper, object) * \
-	HB_SHAPER_DATA_GET_FUNC (shaper, object) (hb_##object##_t *object) \
-	{ return HB_SHAPER_DATA (shaper, object); } \
 	extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
 	HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
 	extern "C" HB_INTERNAL void \
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index a7aa163..67e245c 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -55,38 +55,6 @@ DWORD GetFontData(
 );
 */
 
-static bool
-populate_log_font (LOGFONTW  *lf,
-		   hb_font_t *font)
-{
-  memset (lf, 0, sizeof (*lf));
-  lf->lfHeight = -font->y_scale;
-  lf->lfCharSet = DEFAULT_CHARSET;
-
-  hb_blob_t *blob = Sanitizer<name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e')));
-  const name *name_table = Sanitizer<name>::lock_instance (blob);
-  unsigned int len = name_table->get_name (3, 1, 0x409, 4,
-					   lf->lfFaceName,
-					   sizeof (lf->lfFaceName[0]) * LF_FACESIZE)
-					  / sizeof (lf->lfFaceName[0]);
-  hb_blob_destroy (blob);
-
-  if (unlikely (!len)) {
-    DEBUG_MSG (UNISCRIBE, NULL, "Didn't find English name table entry");
-    return false;
-  }
-  if (unlikely (len >= LF_FACESIZE)) {
-    DEBUG_MSG (UNISCRIBE, NULL, "Font name too long");
-    return false;
-  }
-
-  for (unsigned int i = 0; i < len; i++)
-    lf->lfFaceName[i] = hb_be_uint16 (lf->lfFaceName[i]);
-  lf->lfFaceName[len] = 0;
-
-  return true;
-}
-
 
 /*
  * shaper face data
@@ -141,6 +109,38 @@ struct hb_uniscribe_shaper_font_data_t {
   SCRIPT_CACHE script_cache;
 };
 
+static bool
+populate_log_font (LOGFONTW  *lf,
+		   hb_font_t *font)
+{
+  memset (lf, 0, sizeof (*lf));
+  lf->lfHeight = -font->y_scale;
+  lf->lfCharSet = DEFAULT_CHARSET;
+
+  hb_blob_t *blob = Sanitizer<name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e')));
+  const name *name_table = Sanitizer<name>::lock_instance (blob);
+  unsigned int len = name_table->get_name (3, 1, 0x409, 4,
+					   lf->lfFaceName,
+					   sizeof (lf->lfFaceName[0]) * LF_FACESIZE)
+					  / sizeof (lf->lfFaceName[0]);
+  hb_blob_destroy (blob);
+
+  if (unlikely (!len)) {
+    DEBUG_MSG (UNISCRIBE, NULL, "Didn't find English name table entry");
+    return false;
+  }
+  if (unlikely (len >= LF_FACESIZE)) {
+    DEBUG_MSG (UNISCRIBE, NULL, "Font name too long");
+    return false;
+  }
+
+  for (unsigned int i = 0; i < len; i++)
+    lf->lfFaceName[i] = hb_be_uint16 (lf->lfFaceName[i]);
+  lf->lfFaceName[len] = 0;
+
+  return true;
+}
+
 hb_uniscribe_shaper_font_data_t *
 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
 {
@@ -208,65 +208,18 @@ _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_dat
 /*
  * shaper
  */
-static hb_user_data_key_t hb_uniscribe_data_key;
-
-static hb_uniscribe_shaper_face_data_t *
-_hb_uniscribe_face_get_data (hb_face_t *face)
-{
-  hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
-  if (likely (data)) return data;
-
-  data = _hb_uniscribe_shaper_face_data_create (face);
-  if (!data) return NULL;
-
-  if (unlikely (!hb_face_set_user_data (face, &hb_uniscribe_data_key, data,
-					(hb_destroy_func_t) _hb_uniscribe_shaper_face_data_destroy,
-					false)))
-  {
-    _hb_uniscribe_shaper_face_data_destroy (data);
-    data = (hb_uniscribe_shaper_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
-  }
-
-  return data;
-}
-
-
-static hb_uniscribe_shaper_font_data_t *
-_hb_uniscribe_font_get_data (hb_font_t *font)
-{
-  hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
-  if (likely (data)) return data;
-
-  data = _hb_uniscribe_shaper_font_data_create (font);
-  if (unlikely (!data))
-    return NULL;
-
-  if (unlikely (!hb_font_set_user_data (font, &hb_uniscribe_data_key, data,
-					(hb_destroy_func_t) _hb_uniscribe_shaper_font_data_destroy,
-					false)))
-  {
-    _hb_uniscribe_shaper_font_data_destroy (data);
-    data = (hb_uniscribe_shaper_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
-  }
-
-  return data;
-}
 
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font)
 {
-  hb_uniscribe_shaper_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
-  if (unlikely (!font_data))
-    return NULL;
+  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return &font_data->log_font;
 }
 
 HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font)
 {
-  hb_uniscribe_shaper_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
-  if (unlikely (!font_data))
-    return 0;
+  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return font_data->hfont;
 }
 
@@ -278,7 +231,9 @@ _hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
 		     const hb_feature_t *features,
 		     unsigned int        num_features)
 {
-  buffer->guess_properties ();
+  hb_face_t *face = font->face;
+  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
 
 #define FAIL(...) \
   HB_STMT_START { \
@@ -286,17 +241,6 @@ _hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
     return false; \
   } HB_STMT_END;
 
-  hb_uniscribe_shaper_face_data_t *face_data = _hb_uniscribe_face_get_data (font->face);
-  if (unlikely (!face_data->fh))
-    FAIL ("Couldn't get face data");
-
-  hb_uniscribe_shaper_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
-  if (unlikely (!font_data->hfont))
-    FAIL ("Couldn't get font font");
-
-  if (unlikely (!buffer->len))
-    return true;
-
   HRESULT hr;
 
 retry:
commit c32c096a429da3e64896cf42ff5ab8c775d3c2ec
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 27 01:13:53 2012 -0400

    Switch to shape_plan
    
    Not optimized yet.  Eats babies.  And no shaper uses the shape_plan.

diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 372543b..db21e88 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -48,7 +48,9 @@ hb_##shaper##_##object##_data_ensure (hb_##object##_t *object) \
   return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
 }
 
-#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face)
+#define HB_SHAPER_IMPLEMENT(shaper) \
+	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
+	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 
@@ -65,7 +67,6 @@ hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 #define HB_SHAPER_PLAN(shaper) \
 	HB_STMT_START { \
 	  if (hb_##shaper##_face_data_ensure (shape_plan->face)) { \
-	    /* TODO Ensure face shaper data. */ \
 	    HB_SHAPER_DATA_TYPE (shaper, shape_plan) *data= \
 	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
 	    if (data) { \
@@ -157,3 +158,35 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 
   free (shape_plan);
 }
+
+
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan      *shape_plan,
+		       hb_font_t          *font,
+		       hb_buffer_t        *buffer,
+		       const hb_feature_t *features,
+		       unsigned int        num_features)
+{
+  if (unlikely (shape_plan->face != font->face))
+    return false;
+
+#define HB_SHAPER_EXECUTE(shaper) \
+	HB_STMT_START { \
+	  if (hb_##shaper##_font_data_ensure (font) && \
+	      _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features)) \
+	    return true; \
+	} HB_STMT_END
+
+  for (hb_shape_func_t **shaper_func = shape_plan->shapers; *shaper_func; shaper_func++)
+    if (0)
+      ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+    else if (*shaper_func == _hb_##shaper##_shape) \
+      HB_SHAPER_EXECUTE (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+#undef HB_SHAPER_EXECUTE
+
+  return false;
+}
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
index 5160b95..a4786a8 100644
--- a/src/hb-shape-plan.h
+++ b/src/hb-shape-plan.h
@@ -57,4 +57,12 @@ HB_INTERNAL void
 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
 
 
+HB_INTERNAL hb_bool_t
+hb_shape_plan_execute (hb_shape_plan      *shape_plan,
+		       hb_font_t          *font,
+		       hb_buffer_t        *buffer,
+		       const hb_feature_t *features,
+		       unsigned int        num_features);
+
+
 #endif /* HB_SHAPE_PLAN_H */
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index d017425..0087618 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -32,7 +32,6 @@
 #include "hb-font-private.hh"
 
 
-
 static const char **static_shaper_list;
 
 static
@@ -83,28 +82,10 @@ hb_shape_full (hb_font_t          *font,
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
-//  hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, shaper_list);
-
-  const hb_shaper_pair_t *shapers = _hb_shapers_get ();
-
-  hb_font_make_immutable (font); /* So we can safely cache stuff on it */
-
-  if (likely (!shaper_list)) {
-    for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
-      if (likely (shapers[i].func (NULL, font, buffer, features, num_features)))
-        return true;
-  } else {
-    while (*shaper_list) {
-      for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
-	if (0 == strcmp (*shaper_list, shapers[i].name)) {
-	  if (likely (shapers[i].func (NULL, font, buffer, features, num_features)))
-	    return true;
-	  break;
-	}
-      shaper_list++;
-    }
-  }
-  return false;
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, shaper_list);
+  hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
+  hb_shape_plan_destroy (shape_plan);
+  return res;
 }
 
 void
commit 5b95c148cc485f79fd7018bc4520b4cb5f728a18
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jul 26 23:46:53 2012 -0400

    Start implementing shape_plan

diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index 48aba73..52b46b1 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -71,7 +71,9 @@ _hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data)
 struct hb_fallback_shaper_shape_plan_data_t {};
 
 hb_fallback_shaper_shape_plan_data_t *
-_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
+_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+					    const hb_feature_t *user_features,
+					    unsigned int        num_user_features)
 {
   return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 97a86d5..2540dd6 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -105,9 +105,11 @@ struct hb_face_t {
   struct hb_shaper_data_t shaper_data;
 };
 
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 
 
 /*
@@ -172,9 +174,11 @@ struct hb_font_t {
   inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); }
 };
 
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 
 
 #endif /* HB_FONT_PRIVATE_HH */
diff --git a/src/hb-old.cc b/src/hb-old.cc
index 879ee70..77761e8 100644
--- a/src/hb-old.cc
+++ b/src/hb-old.cc
@@ -231,7 +231,9 @@ _hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t *data)
 struct hb_old_shaper_shape_plan_data_t {};
 
 hb_old_shaper_shape_plan_data_t *
-_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
+_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+				       const hb_feature_t *user_features,
+				       unsigned int        num_user_features)
 {
   return (hb_old_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index a3c4153..639748e 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -78,7 +78,9 @@ _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
 struct hb_ot_shaper_shape_plan_data_t {};
 
 hb_ot_shaper_shape_plan_data_t *
-_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
+_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+				      const hb_feature_t *user_features,
+				      unsigned int        num_user_features)
 {
   return (hb_ot_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
index 68246f4..c292f14 100644
--- a/src/hb-shape-plan-private.hh
+++ b/src/hb-shape-plan-private.hh
@@ -39,14 +39,21 @@ struct hb_shape_plan_t
   hb_object_header_t header;
   ASSERT_POD ();
 
+  hb_face_t *face;
+  hb_segment_properties_t props;
+
   hb_shape_func_t *shapers[HB_SHAPERS_COUNT];
 
   struct hb_shaper_data_t shaper_data;
 };
 
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
+	, const hb_feature_t            *user_features \
+	, unsigned int                   num_user_features
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 
 
 #endif /* HB_SHAPE_PLAN_PRIVATE_HH */
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index e76847d..372543b 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -27,9 +27,79 @@
 #include "hb-private.hh"
 
 #include "hb-shape-plan-private.hh"
-
+#include "hb-shaper-private.hh"
 #include "hb-font-private.hh"
 
+#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
+static inline bool \
+hb_##shaper##_##object##_data_ensure (hb_##object##_t *object) \
+{\
+  retry: \
+  HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
+  if (unlikely (!data)) { \
+    data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
+    if (unlikely (!data)) \
+      data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
+    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
+      HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
+      goto retry; \
+    } \
+  } \
+  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
+}
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face)
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+
+void
+hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
+		    const hb_feature_t *user_features,
+		    unsigned int        num_user_features,
+		    const char * const *shaper_list)
+{
+  const hb_shaper_pair_t *shapers = _hb_shapers_get ();
+  unsigned num_shapers = 0;
+
+#define HB_SHAPER_PLAN(shaper) \
+	HB_STMT_START { \
+	  if (hb_##shaper##_face_data_ensure (shape_plan->face)) { \
+	    /* TODO Ensure face shaper data. */ \
+	    HB_SHAPER_DATA_TYPE (shaper, shape_plan) *data= \
+	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
+	    if (data) { \
+	      HB_SHAPER_DATA (shaper, shape_plan) = data; \
+	      shape_plan->shapers[num_shapers++] = _hb_##shaper##_shape; \
+	    } \
+	    if (false /* shaper never fails */) \
+	      return; \
+	  } \
+	} HB_STMT_END
+
+  if (likely (!shaper_list)) {
+    for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
+      if (0)
+	;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (shapers[i].func == _hb_##shaper##_shape) \
+	HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  } else {
+    for (; *shaper_list; shaper_list++)
+      if (0)
+	;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (0 == strcmp (*shaper_list, #shaper)) \
+	HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  }
+
+#undef HB_SHAPER_PLAN
+}
+
 
 /*
  * hb_shape_plan_t
@@ -52,8 +122,10 @@ hb_shape_plan_create (hb_face_t                     *face,
     return hb_shape_plan_get_empty ();
 
   hb_face_make_immutable (face);
+  shape_plan->face = hb_face_reference (face);
+  shape_plan->props = *props;
 
-  /* Plan! */
+  hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
 
   return shape_plan;
 }
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 3915de7..d017425 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -27,7 +27,9 @@
 #include "hb-private.hh"
 
 #include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
 #include "hb-buffer-private.hh"
+#include "hb-font-private.hh"
 
 
 
@@ -81,6 +83,8 @@ hb_shape_full (hb_font_t          *font,
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
+//  hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, shaper_list);
+
   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
 
   hb_font_make_immutable (font); /* So we can safely cache stuff on it */
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index fa279bc..9e35ef8 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -68,7 +68,7 @@ struct hb_shaper_data_t {
 #define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
 
 #define HB_SHAPER_DATA_TYPE(shaper, object)		struct hb_##shaper##_shaper_##object##_data_t
-#define HB_SHAPER_DATA(shaper, object)			((HB_SHAPER_DATA_TYPE(shaper, object) *) (object)->shaper_data.shaper)
+#define HB_SHAPER_DATA(shaper, object)			(* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(object)->shaper_data.shaper)
 #define HB_SHAPER_DATA_GET_FUNC(shaper, object)		_hb_##shaper##_shaper_get_##object##_data
 #define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create
 #define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_destroy
@@ -79,7 +79,7 @@ struct hb_shaper_data_t {
 	HB_SHAPER_DATA_GET_FUNC (shaper, object) (hb_##object##_t *object) \
 	{ return HB_SHAPER_DATA (shaper, object); } \
 	extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
-	HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object); \
+	HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
 	extern "C" HB_INTERNAL void \
 	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
 
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index faba587..a7aa163 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -192,7 +192,9 @@ _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
 struct hb_uniscribe_shaper_shape_plan_data_t {};
 
 hb_uniscribe_shaper_shape_plan_data_t *
-_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
+_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+					     const hb_feature_t *user_features,
+					     unsigned int        num_user_features)
 {
   return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
commit bd26b4d21f59312805d294f46f15182adbcc47da
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jul 26 22:05:39 2012 -0400

    Minor

diff --git a/src/Makefile.am b/src/Makefile.am
index 847c9e7..9b583fd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,6 +47,7 @@ HBSOURCES =  \
 	hb-shaper-list.hh \
 	hb-shaper-impl-private.hh \
 	hb-shaper-private.hh \
+	hb-shaper.cc \
 	hb-tt-font.cc \
 	hb-unicode-private.hh \
 	hb-unicode.cc \
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index 4c9a3b3..48aba73 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -87,7 +87,8 @@ _hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_
  */
 
 hb_bool_t
-_hb_fallback_shape (hb_font_t          *font,
+_hb_fallback_shape (hb_shape_plan_t    *shape_plan,
+		    hb_font_t          *font,
 		    hb_buffer_t        *buffer,
 		    const hb_feature_t *features HB_UNUSED,
 		    unsigned int        num_features HB_UNUSED)
diff --git a/src/hb-old.cc b/src/hb-old.cc
index b898b3f..879ee70 100644
--- a/src/hb-old.cc
+++ b/src/hb-old.cc
@@ -302,7 +302,8 @@ _hb_old_font_get (hb_font_t *font)
 }
 
 hb_bool_t
-_hb_old_shape (hb_font_t          *font,
+_hb_old_shape (hb_shape_plan_t    *shape_plan,
+	       hb_font_t          *font,
 	       hb_buffer_t        *buffer,
 	       const hb_feature_t *features,
 	       unsigned int        num_features)
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 512ffa5..a3c4153 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -541,7 +541,8 @@ hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
 }
 
 hb_bool_t
-_hb_ot_shape (hb_font_t          *font,
+_hb_ot_shape (hb_shape_plan_t    *shape_plan,
+	      hb_font_t          *font,
 	      hb_buffer_t        *buffer,
 	      const hb_feature_t *features,
 	      unsigned int        num_features)
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
index 1f54608..68246f4 100644
--- a/src/hb-shape-plan-private.hh
+++ b/src/hb-shape-plan-private.hh
@@ -39,7 +39,7 @@ struct hb_shape_plan_t
   hb_object_header_t header;
   ASSERT_POD ();
 
-  hb_shape_func_t *shapers[HB_NUM_SHAPERS];
+  hb_shape_func_t *shapers[HB_SHAPERS_COUNT];
 
   struct hb_shaper_data_t shaper_data;
 };
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index b96d5f2..e76847d 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -53,6 +53,8 @@ hb_shape_plan_create (hb_face_t                     *face,
 
   hb_face_make_immutable (face);
 
+  /* Plan! */
+
   return shape_plan;
 }
 
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index a1f3402..3915de7 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -30,85 +30,6 @@
 #include "hb-buffer-private.hh"
 
 
-static const struct hb_shaper_pair_t {
-  char name[16];
-  hb_shape_func_t *func;
-} all_shapers[] = {
-#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
-#include "hb-shaper-list.hh"
-#undef HB_SHAPER_IMPLEMENT
-};
-
-
-/* Thread-safe, lock-free, shapers */
-
-static const hb_shaper_pair_t *static_shapers;
-
-static
-void free_static_shapers (void)
-{
-  if (unlikely (static_shapers != all_shapers))
-    free ((void *) static_shapers);
-}
-
-static const hb_shaper_pair_t *
-get_shapers (void)
-{
-retry:
-  hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
-
-  if (unlikely (!shapers))
-  {
-    char *env = getenv ("HB_SHAPER_LIST");
-    if (!env || !*env) {
-      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
-      return (const hb_shaper_pair_t *) all_shapers;
-    }
-
-    /* Not found; allocate one. */
-    shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
-    if (unlikely (!shapers))
-      return (const hb_shaper_pair_t *) all_shapers;
-     memcpy (shapers, all_shapers, sizeof (all_shapers));
-
-     /* Reorder shaper list to prefer requested shapers. */
-    unsigned int i = 0;
-    char *end, *p = env;
-    for (;;) {
-      end = strchr (p, ',');
-      if (!end)
-	end = p + strlen (p);
-
-      for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
-	if (end - p == (int) strlen (shapers[j].name) &&
-	    0 == strncmp (shapers[j].name, p, end - p))
-	{
-	  /* Reorder this shaper to position i */
-	 struct hb_shaper_pair_t t = shapers[j];
-	 memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
-	 shapers[i] = t;
-	 i++;
-	}
-
-      if (!*end)
-	break;
-      else
-	p = end + 1;
-    }
-
-    if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
-      free (shapers);
-      goto retry;
-    }
-
-#ifdef HAVE_ATEXIT
-    atexit (free_static_shapers); /* First person registers atexit() callback. */
-#endif
-  }
-
-  return shapers;
-}
-
 
 static const char **static_shaper_list;
 
@@ -127,15 +48,15 @@ retry:
   if (unlikely (!shaper_list))
   {
     /* Not found; allocate one. */
-    shaper_list = (const char **) calloc (1 + ARRAY_LENGTH (all_shapers), sizeof (const char *));
+    shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
     if (unlikely (!shaper_list)) {
       static const char *nil_shaper_list[] = {NULL};
       return nil_shaper_list;
     }
 
-    const hb_shaper_pair_t *shapers = get_shapers ();
+    const hb_shaper_pair_t *shapers = _hb_shapers_get ();
     unsigned int i;
-    for (i = 0; i < ARRAY_LENGTH (all_shapers); i++)
+    for (i = 0; i < HB_SHAPERS_COUNT; i++)
       shaper_list[i] = shapers[i].name;
     shaper_list[i] = NULL;
 
@@ -160,18 +81,19 @@ hb_shape_full (hb_font_t          *font,
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
+  const hb_shaper_pair_t *shapers = _hb_shapers_get ();
+
   hb_font_make_immutable (font); /* So we can safely cache stuff on it */
 
   if (likely (!shaper_list)) {
-    const hb_shaper_pair_t *shapers = get_shapers ();
-    for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
-      if (likely (shapers[i].func (font, buffer, features, num_features)))
+    for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
+      if (likely (shapers[i].func (NULL, font, buffer, features, num_features)))
         return true;
   } else {
     while (*shaper_list) {
-      for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
-	if (0 == strcmp (*shaper_list, all_shapers[i].name)) {
-	  if (likely (all_shapers[i].func (font, buffer, features, num_features)))
+      for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
+	if (0 == strcmp (*shaper_list, shapers[i].name)) {
+	  if (likely (shapers[i].func (NULL, font, buffer, features, num_features)))
 	    return true;
 	  break;
 	}
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index 88be96c..fa279bc 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -29,7 +29,10 @@
 
 #include "hb-private.hh"
 
-typedef hb_bool_t hb_shape_func_t (hb_font_t          *font,
+#include "hb-shape-plan.h" /* TODO remove */
+
+typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t    *shape_plan,
+				   hb_font_t          *font,
 				   hb_buffer_t        *buffer,
 				   const hb_feature_t *features,
 				   unsigned int        num_features);
@@ -39,6 +42,15 @@ typedef hb_bool_t hb_shape_func_t (hb_font_t          *font,
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 
+struct hb_shaper_pair_t {
+  char name[16];
+  hb_shape_func_t *func;
+};
+
+HB_INTERNAL const hb_shaper_pair_t *
+_hb_shapers_get (void);
+
+
 /* For embedding in face / font / ... */
 struct hb_shaper_data_t {
 #define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
@@ -46,7 +58,7 @@ struct hb_shaper_data_t {
 #undef HB_SHAPER_IMPLEMENT
 };
 
-#define HB_NUM_SHAPERS (sizeof (hb_shaper_data_t) / sizeof (void *))
+#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
 
 /* Means: succeeded, but don't need to keep any data. */
 #define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
new file mode 100644
index 0000000..a16ffc8
--- /dev/null
+++ b/src/hb-shaper.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2012  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-private.hh"
+
+#include "hb-shaper-private.hh"
+
+
+static const hb_shaper_pair_t all_shapers[] = {
+#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+
+/* Thread-safe, lock-free, shapers */
+
+static const hb_shaper_pair_t *static_shapers;
+
+static
+void free_static_shapers (void)
+{
+  if (unlikely (static_shapers != all_shapers))
+    free ((void *) static_shapers);
+}
+
+const hb_shaper_pair_t *
+_hb_shapers_get (void)
+{
+retry:
+  hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
+
+  if (unlikely (!shapers))
+  {
+    char *env = getenv ("HB_SHAPER_LIST");
+    if (!env || !*env) {
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      return (const hb_shaper_pair_t *) all_shapers;
+    }
+
+    /* Not found; allocate one. */
+    shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
+    if (unlikely (!shapers)) {
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      return (const hb_shaper_pair_t *) all_shapers;
+    }
+
+    memcpy (shapers, all_shapers, sizeof (all_shapers));
+
+     /* Reorder shaper list to prefer requested shapers. */
+    unsigned int i = 0;
+    char *end, *p = env;
+    for (;;) {
+      end = strchr (p, ',');
+      if (!end)
+	end = p + strlen (p);
+
+      for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
+	if (end - p == (int) strlen (shapers[j].name) &&
+	    0 == strncmp (shapers[j].name, p, end - p))
+	{
+	  /* Reorder this shaper to position i */
+	 struct hb_shaper_pair_t t = shapers[j];
+	 memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
+	 shapers[i] = t;
+	 i++;
+	}
+
+      if (!*end)
+	break;
+      else
+	p = end + 1;
+    }
+
+    if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
+      free (shapers);
+      goto retry;
+    }
+
+#ifdef HAVE_ATEXIT
+    atexit (free_static_shapers); /* First person registers atexit() callback. */
+#endif
+  }
+
+  return shapers;
+}
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index fe7be70..faba587 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -270,7 +270,8 @@ hb_uniscribe_font_get_hfont (hb_font_t *font)
 
 
 hb_bool_t
-_hb_uniscribe_shape (hb_font_t          *font,
+_hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
+		     hb_font_t          *font,
 		     hb_buffer_t        *buffer,
 		     const hb_feature_t *features,
 		     unsigned int        num_features)
commit 027857d0412477fb4427dcb8a8c45287c272e143
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jul 26 17:34:25 2012 -0400

    Start adding a unified shaper access infrastructure
    
    Add global shape_plan.  Unused so far.

diff --git a/src/Makefile.am b/src/Makefile.am
index b1255fa..847c9e7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,6 @@ HBSOURCES =  \
 	hb-buffer.cc \
 	hb-cache-private.hh \
 	hb-common.cc \
-	hb-fallback-shape-private.hh \
 	hb-fallback-shape.cc \
 	hb-font-private.hh \
 	hb-font.cc \
@@ -42,6 +41,12 @@ HBSOURCES =  \
 	hb-set-private.hh \
 	hb-set.cc \
 	hb-shape.cc \
+	hb-shape-plan-private.hh \
+	hb-shape-plan.cc \
+	hb-shape-plan.h \
+	hb-shaper-list.hh \
+	hb-shaper-impl-private.hh \
+	hb-shaper-private.hh \
 	hb-tt-font.cc \
 	hb-unicode-private.hh \
 	hb-unicode.cc \
@@ -129,21 +134,21 @@ endif
 if HAVE_GRAPHITE2
 HBCFLAGS += $(GRAPHITE2_CFLAGS)
 HBLIBS   += $(GRAPHITE2_LIBS)
-HBSOURCES += hb-graphite2.cc hb-graphite2-private.hh
+HBSOURCES += hb-graphite2.cc
 HBHEADERS += hb-graphite2.h
 endif
 
 if HAVE_UNISCRIBE
 HBCFLAGS += $(UNISCRIBE_CFLAGS)
 HBLIBS   += $(UNISCRIBE_LIBS)
-HBSOURCES += hb-uniscribe.cc hb-uniscribe-private.hh
+HBSOURCES += hb-uniscribe.cc
 HBHEADERS += hb-uniscribe.h
 endif
 
 if HAVE_CORETEXT
 HBCFLAGS += $(CORETEXT_CFLAGS)
 HBLIBS   += $(CORETEXT_LIBS)
-HBSOURCES += hb-coretext.cc hb-coretext-private.hh
+HBSOURCES += hb-coretext.cc
 HBHEADERS += hb-coretext.h
 endif
 
@@ -151,7 +156,7 @@ if HAVE_HB_OLD
 SUBDIRS += hb-old
 HBCFLAGS += -I$(srcdir)/hb-old
 HBLIBS   += hb-old/libhb-old.la
-HBSOURCES += hb-old.cc hb-old-private.hh
+HBSOURCES += hb-old.cc
 endif
 DIST_SUBDIRS += hb-old
 
diff --git a/src/hb-coretext-private.hh b/src/hb-coretext-private.hh
deleted file mode 100644
index 153106c..0000000
--- a/src/hb-coretext-private.hh
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright © 2012  Mozilla Foundation.
- *
- *  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.
- *
- * Mozilla Author(s): Jonathan Kew
- */
-
-#ifndef HB_CORETEXT_PRIVATE_HH
-#define HB_CORETEXT_PRIVATE_HH
-
-#include "hb-private.hh"
-
-#include "hb-coretext.h"
-
-
-HB_INTERNAL hb_bool_t
-_hb_coretext_shape (hb_font_t          *font,
-		     hb_buffer_t        *buffer,
-		     const hb_feature_t *features,
-		     unsigned int        num_features);
-
-
-#endif /* HB_CORETEXT_PRIVATE_HH */
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index c99ffc4..6e09c5e 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -24,7 +24,8 @@
  * Mozilla Author(s): Jonathan Kew
  */
 
-#include "hb-private.hh"
+#define HB_SHAPER coretext
+#include "hb-shaper-private.hh"
 
 #define GlyphID GlyphID_mac
 #include <ApplicationServices/ApplicationServices.h>
@@ -32,9 +33,6 @@
 
 #include "hb-coretext.h"
 
-#include "hb-ot-name-table.hh"
-#include "hb-ot-tag.h"
-
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
 
diff --git a/src/hb-fallback-shape-private.hh b/src/hb-fallback-shape-private.hh
deleted file mode 100644
index 0ef155c..0000000
--- a/src/hb-fallback-shape-private.hh
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright © 2011  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_FALLBACK_SHAPE_PRIVATE_HH
-#define HB_FALLBACK_SHAPE_PRIVATE_HH
-
-#include "hb-private.hh"
-
-#include "hb-shape.h"
-
-
-HB_INTERNAL hb_bool_t
-_hb_fallback_shape (hb_font_t          *font,
-		    hb_buffer_t        *buffer,
-		    const hb_feature_t *features,
-		    unsigned int        num_features);
-
-#endif /* HB_FALLBACK_SHAPE_PRIVATE_HH */
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index b9480e6..4c9a3b3 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -24,9 +24,67 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-fallback-shape-private.hh"
+#define HB_SHAPER fallback
+#include "hb-shaper-impl-private.hh"
 
-#include "hb-buffer-private.hh"
+
+/*
+ * shaper face data
+ */
+
+struct hb_fallback_shaper_face_data_t {};
+
+hb_fallback_shaper_face_data_t *
+_hb_fallback_shaper_face_data_create (hb_face_t *face)
+{
+  return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_fallback_shaper_font_data_t {};
+
+hb_fallback_shaper_font_data_t *
+_hb_fallback_shaper_font_data_create (hb_font_t *font)
+{
+  return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_fallback_shaper_shape_plan_data_t {};
+
+hb_fallback_shaper_shape_plan_data_t *
+_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
+{
+  return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data)
+{
+}
+
+
+/*
+ * shaper
+ */
 
 hb_bool_t
 _hb_fallback_shape (hb_font_t          *font,
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 2f74cfa..97a86d5 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -33,6 +33,7 @@
 
 #include "hb-font.h"
 #include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
 
 
 
@@ -100,8 +101,14 @@ struct hb_face_t {
 
   unsigned int index;
   unsigned int upem;
+
+  struct hb_shaper_data_t shaper_data;
 };
 
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
 
 /*
  * hb_font_t
@@ -126,6 +133,8 @@ struct hb_font_t {
   void              *user_data;
   hb_destroy_func_t  destroy;
 
+  struct hb_shaper_data_t shaper_data;
+
 
   /* Convert from font-space to user-space */
   inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
@@ -163,6 +172,9 @@ struct hb_font_t {
   inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); }
 };
 
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
 
 
 #endif /* HB_FONT_PRIVATE_HH */
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 7c62fbe..1261077 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,6 +23,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
@@ -707,6 +709,10 @@ hb_face_destroy (hb_face_t *face)
 
   _hb_ot_layout_destroy (face->ot_layout);
 
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
   if (face->destroy)
     face->destroy (face->user_data);
 
@@ -888,11 +894,16 @@ hb_font_destroy (hb_font_t *font)
 {
   if (!hb_object_destroy (font)) return;
 
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  if (font->destroy)
+    font->destroy (font->user_data);
+
   hb_font_destroy (font->parent);
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
-  if (font->destroy)
-    font->destroy (font->user_data);
 
   free (font);
 }
diff --git a/src/hb-graphite2-private.hh b/src/hb-graphite2-private.hh
deleted file mode 100644
index 644ea75..0000000
--- a/src/hb-graphite2-private.hh
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright © 2012  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_GRAPHITE2_PRIVATE_HH
-#define HB_GRAPHITE2_PRIVATE_HH
-
-#include "hb-private.hh"
-
-#include "hb-graphite2.h"
-
-
-HB_INTERNAL hb_bool_t
-_hb_graphite2_shape (hb_font_t          *font,
-		     hb_buffer_t        *buffer,
-		     const hb_feature_t *features,
-		     unsigned int        num_features);
-
-
-#endif /* HB_GRAPHITE2_PRIVATE_HH */
diff --git a/src/hb-old-private.hh b/src/hb-old-private.hh
deleted file mode 100644
index 7c51321..0000000
--- a/src/hb-old-private.hh
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright © 2012  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_OLD_PRIVATE_HH
-#define HB_OLD_PRIVATE_HH
-
-#include "hb-private.hh"
-
-
-HB_INTERNAL hb_bool_t
-_hb_old_shape (hb_font_t          *font,
-	       hb_buffer_t        *buffer,
-	       const hb_feature_t *features,
-	       unsigned int        num_features);
-
-
-#endif /* HB_OLD_PRIVATE_HH */
diff --git a/src/hb-old.cc b/src/hb-old.cc
index be0187f..b898b3f 100644
--- a/src/hb-old.cc
+++ b/src/hb-old.cc
@@ -24,12 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-private.hh"
-
-#include "hb-old-private.hh"
-
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
+#define HB_SHAPER old
+#define hb_old_shaper_face_data_t HB_FaceRec_
+#define hb_old_shaper_font_data_t HB_Font_
+#include "hb-shaper-impl-private.hh"
 
 #include <harfbuzz.h>
 
@@ -166,8 +164,6 @@ static const HB_FontClass hb_old_font_class = {
 
 
 
-static hb_user_data_key_t hb_old_data_key;
-
 static HB_Error
 table_func (void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length)
 {
@@ -180,13 +176,86 @@ table_func (void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length)
  return HB_Err_Ok;
 }
 
+
+/*
+ * shaper face data
+ */
+
+hb_old_shaper_face_data_t *
+_hb_old_shaper_face_data_create (hb_face_t *face)
+{
+  return HB_NewFace (face, table_func);
+}
+
+void
+_hb_old_shaper_face_data_destroy (hb_old_shaper_face_data_t *data)
+{
+  HB_FreeFace (data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+hb_old_shaper_font_data_t *
+_hb_old_shaper_font_data_create (hb_font_t *font)
+{
+  HB_FontRec *data = (HB_FontRec *) calloc (1, sizeof (HB_FontRec));
+  if (unlikely (!data)) {
+    DEBUG_MSG (OLD, font, "malloc()ing HB_Font failed");
+    return NULL;
+  }
+
+  data->klass = &hb_old_font_class;
+  data->x_ppem = font->x_ppem;
+  data->y_ppem = font->y_ppem;
+  data->x_scale = font->x_scale; // XXX
+  data->y_scale = font->y_scale; // XXX
+  data->userData = font;
+
+  return data;
+}
+
+void
+_hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t *data)
+{
+  free (data);
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_old_shaper_shape_plan_data_t {};
+
+hb_old_shaper_shape_plan_data_t *
+_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
+{
+  return (hb_old_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+
+static hb_user_data_key_t hb_old_data_key;
+
 static HB_Face
 _hb_old_face_get (hb_face_t *face)
 {
   HB_Face data = (HB_Face) hb_face_get_user_data (face, &hb_old_data_key);
   if (likely (data)) return data;
 
-  data = HB_NewFace (face, table_func);
+  data = _hb_old_shaper_face_data_create (face);
 
   if (unlikely (!data)) {
     DEBUG_MSG (OLD, face, "HB_NewFace failed");
@@ -194,10 +263,10 @@ _hb_old_face_get (hb_face_t *face)
   }
 
   if (unlikely (!hb_face_set_user_data (face, &hb_old_data_key, data,
-                                        (hb_destroy_func_t) HB_FreeFace,
+                                        (hb_destroy_func_t) _hb_old_shaper_face_data_destroy,
                                         false)))
   {
-    HB_FreeFace (data);
+    _hb_old_shaper_face_data_destroy (data);
     data = (HB_Face) hb_face_get_user_data (face, &hb_old_data_key);
     if (data)
       return data;
@@ -212,24 +281,16 @@ _hb_old_face_get (hb_face_t *face)
 static HB_Font
 _hb_old_font_get (hb_font_t *font)
 {
-  HB_Font data = (HB_Font) calloc (1, sizeof (HB_FontRec));
-  if (unlikely (!data)) {
-    DEBUG_MSG (OLD, font, "malloc()ing HB_Font failed");
+  /* Ouch, check user_data! */
+  HB_Font data = _hb_old_shaper_font_data_create (font);
+  if (!data)
     return NULL;
-  }
-
-  data->klass = &hb_old_font_class;
-  data->x_ppem = font->x_ppem;
-  data->y_ppem = font->y_ppem;
-  data->x_scale = font->x_scale; // XXX
-  data->y_scale = font->y_scale; // XXX
-  data->userData = font;
 
   if (unlikely (!hb_font_set_user_data (font, &hb_old_data_key, data,
-                                        (hb_destroy_func_t) free,
+                                        (hb_destroy_func_t) _hb_old_shaper_font_data_destroy,
                                         false)))
   {
-    free (data);
+    _hb_old_shaper_font_data_destroy (data);
     data = (HB_Font) hb_font_get_user_data (font, &hb_old_data_key);
     if (data)
       return data;
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index df0c705..8c8876a 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -46,14 +46,6 @@ struct hb_ot_shape_plan_t
 };
 
 
-
-HB_INTERNAL hb_bool_t
-_hb_ot_shape (hb_font_t          *font,
-	      hb_buffer_t        *buffer,
-	      const hb_feature_t *features,
-	      unsigned int        num_features);
-
-
 inline void
 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 {
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 3b1c1d7..512ffa5 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -26,14 +26,72 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#define HB_SHAPER ot
+#define hb_ot_shaper_face_data_t hb_ot_layout_t
+#include "hb-shaper-impl-private.hh"
+
 #include "hb-ot-shape-private.hh"
 #include "hb-ot-shape-normalize-private.hh"
 
 #include "hb-ot-layout-private.hh"
-#include "hb-font-private.hh"
 #include "hb-set-private.hh"
 
 
+/*
+ * shaper face data
+ */
+
+hb_ot_shaper_face_data_t *
+_hb_ot_shaper_face_data_create (hb_face_t *face)
+{
+  return (hb_ot_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_ot_shaper_font_data_t {};
+
+hb_ot_shaper_font_data_t *
+_hb_ot_shaper_font_data_create (hb_font_t *font)
+{
+  return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_ot_shaper_shape_plan_data_t {};
+
+hb_ot_shaper_shape_plan_data_t *
+_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
+{
+  return (hb_ot_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *data)
+{
+}
+
+
+/*
+ * shaper
+ */
 
 hb_tag_t common_features[] = {
   HB_TAG('c','c','m','p'),
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
new file mode 100644
index 0000000..1f54608
--- /dev/null
+++ b/src/hb-shape-plan-private.hh
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2012  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_SHAPE_PLAN_PRIVATE_HH
+#define HB_SHAPE_PLAN_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-shape-plan.h"
+
+#include "hb-shaper-private.hh"
+
+
+struct hb_shape_plan_t
+{
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_shape_func_t *shapers[HB_NUM_SHAPERS];
+
+  struct hb_shaper_data_t shaper_data;
+};
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+
+#endif /* HB_SHAPE_PLAN_PRIVATE_HH */
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
new file mode 100644
index 0000000..b96d5f2
--- /dev/null
+++ b/src/hb-shape-plan.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2012  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-private.hh"
+
+#include "hb-shape-plan-private.hh"
+
+#include "hb-font-private.hh"
+
+
+/*
+ * hb_shape_plan_t
+ */
+
+hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t                     *face,
+		      const hb_segment_properties_t *props,
+		      const hb_feature_t            *user_features,
+		      unsigned int                   num_user_features,
+		      const char * const            *shaper_list)
+{
+  hb_shape_plan_t *shape_plan;
+
+  if (unlikely (!face))
+    face = hb_face_get_empty ();
+  if (unlikely (!props || hb_object_is_inert (face)))
+    return hb_shape_plan_get_empty ();
+  if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
+    return hb_shape_plan_get_empty ();
+
+  hb_face_make_immutable (face);
+
+  return shape_plan;
+}
+
+hb_shape_plan_t *
+hb_shape_plan_get_empty (void)
+{
+  static const hb_shape_plan_t _hb_shape_plan_nil = {
+    HB_OBJECT_HEADER_STATIC,
+  };
+
+  return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
+}
+
+hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
+{
+  return hb_object_reference (shape_plan);
+}
+
+void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
+{
+  if (!hb_object_destroy (shape_plan)) return;
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  free (shape_plan);
+}
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
new file mode 100644
index 0000000..5160b95
--- /dev/null
+++ b/src/hb-shape-plan.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2012  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_SHAPE_PLAN_H
+#define HB_SHAPE_PLAN_H
+
+/* TODO To become public one day */
+
+#include "hb-private.hh"
+
+#include "hb-buffer-private.hh"
+
+
+typedef struct hb_shape_plan_t hb_shape_plan;
+
+/*
+ * hb_shape_plan_t
+ */
+
+HB_INTERNAL hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t                     *face,
+		      const hb_segment_properties_t *props,
+		      const hb_feature_t            *user_features,
+		      unsigned int                   num_user_features,
+		      const char * const            *shaper_list);
+
+HB_INTERNAL hb_shape_plan_t *
+hb_shape_plan_get_empty (void);
+
+HB_INTERNAL hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
+
+HB_INTERNAL void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
+
+
+#endif /* HB_SHAPE_PLAN_H */
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index da7d9e0..a1f3402 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -26,56 +26,18 @@
 
 #include "hb-private.hh"
 
-#include "hb-shape.h"
-
+#include "hb-shaper-private.hh"
 #include "hb-buffer-private.hh"
 
-#ifdef HAVE_GRAPHITE
-#include "hb-graphite2-private.hh"
-#endif
-#ifdef HAVE_UNISCRIBE
-# include "hb-uniscribe-private.hh"
-#endif
-#ifdef HAVE_CORETEXT
-# include "hb-coretext-private.hh"
-#endif
-#ifdef HAVE_HB_OLD
-# include "hb-old-private.hh"
-#endif
-#ifdef HAVE_OT
-# include "hb-ot-shape-private.hh"
-#endif
-#include "hb-fallback-shape-private.hh"
-
-typedef hb_bool_t (*hb_shape_func_t) (hb_font_t          *font,
-				      hb_buffer_t        *buffer,
-				      const hb_feature_t *features,
-				      unsigned int        num_features);
 
-#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}
 static const struct hb_shaper_pair_t {
   char name[16];
-  hb_shape_func_t func;
+  hb_shape_func_t *func;
 } all_shapers[] = {
-  /* v--- Add new shapers in the right place here */
-#ifdef HAVE_GRAPHITE
-  HB_SHAPER_IMPLEMENT (graphite2),
-#endif
-#ifdef HAVE_UNISCRIBE
-  HB_SHAPER_IMPLEMENT (uniscribe),
-#endif
-#ifdef HAVE_CORETEXT
-  HB_SHAPER_IMPLEMENT (coretext),
-#endif
-#ifdef HAVE_OT
-  HB_SHAPER_IMPLEMENT (ot),
-#endif
-#ifdef HAVE_HB_OLD
-  HB_SHAPER_IMPLEMENT (old),
-#endif
-  HB_SHAPER_IMPLEMENT (fallback), /* This should be last. */
-};
+#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
+#include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
+};
 
 
 /* Thread-safe, lock-free, shapers */
diff --git a/src/hb-shaper-impl-private.hh b/src/hb-shaper-impl-private.hh
new file mode 100644
index 0000000..91ee14f
--- /dev/null
+++ b/src/hb-shaper-impl-private.hh
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2012  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_SHAPER_IMPL_PRIVATE_HH
+#define HB_SHAPER_IMPL_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
+
+
+#ifdef HB_SHAPER
+/* For use in things like font->shaper_data() in the shaper implementations. */
+#define shaper_data() shaper_data.HB_SHAPER
+#endif
+
+
+#endif /* HB_SHAPER_IMPL_PRIVATE_HH */
diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh
new file mode 100644
index 0000000..ff1fdfd
--- /dev/null
+++ b/src/hb-shaper-list.hh
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2012  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_SHAPER_LIST_HH
+#define HB_SHAPER_LIST_HH
+#endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
+
+/* v--- Add new shapers in the right place here. */
+#ifdef HAVE_GRAPHITE
+HB_SHAPER_IMPLEMENT (graphite2)
+#endif
+#ifdef HAVE_UNISCRIBE
+HB_SHAPER_IMPLEMENT (uniscribe)
+#endif
+#ifdef HAVE_CORETEXT
+HB_SHAPER_IMPLEMENT (coretext)
+#endif
+
+#ifdef HAVE_OT
+HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+#endif
+
+#ifdef HAVE_HB_OLD
+HB_SHAPER_IMPLEMENT (old)
+#endif
+
+HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
new file mode 100644
index 0000000..88be96c
--- /dev/null
+++ b/src/hb-shaper-private.hh
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2012  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_SHAPER_PRIVATE_HH
+#define HB_SHAPER_PRIVATE_HH
+
+#include "hb-private.hh"
+
+typedef hb_bool_t hb_shape_func_t (hb_font_t          *font,
+				   hb_buffer_t        *buffer,
+				   const hb_feature_t *features,
+				   unsigned int        num_features);
+
+#define HB_SHAPER_IMPLEMENT(name) \
+	extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+/* For embedding in face / font / ... */
+struct hb_shaper_data_t {
+#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+#define HB_NUM_SHAPERS (sizeof (hb_shaper_data_t) / sizeof (void *))
+
+/* Means: succeeded, but don't need to keep any data. */
+#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
+
+/* Means: tried but failed to create. */
+#define HB_SHAPER_DATA_INVALID ((void *) -1)
+#define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
+
+#define HB_SHAPER_DATA_TYPE(shaper, object)		struct hb_##shaper##_shaper_##object##_data_t
+#define HB_SHAPER_DATA(shaper, object)			((HB_SHAPER_DATA_TYPE(shaper, object) *) (object)->shaper_data.shaper)
+#define HB_SHAPER_DATA_GET_FUNC(shaper, object)		_hb_##shaper##_shaper_get_##object##_data
+#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create
+#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_destroy
+
+#define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
+	HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
+	static inline HB_SHAPER_DATA_TYPE (shaper, object) * \
+	HB_SHAPER_DATA_GET_FUNC (shaper, object) (hb_##object##_t *object) \
+	{ return HB_SHAPER_DATA (shaper, object); } \
+	extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
+	HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object); \
+	extern "C" HB_INTERNAL void \
+	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
+
+#define HB_SHAPER_DATA_DESTROY(shaper, object) \
+	if (object->shaper_data.shaper && \
+	    object->shaper_data.shaper != HB_SHAPER_DATA_INVALID && \
+	    object->shaper_data.shaper != HB_SHAPER_DATA_SUCCEEDED) \
+	  HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA (shaper, object));
+
+
+#endif /* HB_SHAPER_PRIVATE_HH */
diff --git a/src/hb-uniscribe-private.hh b/src/hb-uniscribe-private.hh
deleted file mode 100644
index 239ab0c..0000000
--- a/src/hb-uniscribe-private.hh
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright © 2012  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_UNISCRIBE_PRIVATE_HH
-#define HB_UNISCRIBE_PRIVATE_HH
-
-#include "hb-private.hh"
-
-#include "hb-uniscribe.h"
-
-
-HB_INTERNAL hb_bool_t
-_hb_uniscribe_shape (hb_font_t          *font,
-		     hb_buffer_t        *buffer,
-		     const hb_feature_t *features,
-		     unsigned int        num_features);
-
-
-#endif /* HB_UNISCRIBE_PRIVATE_HH */
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 6b9a261..fe7be70 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -26,7 +26,8 @@
 
 #define _WIN32_WINNT 0x0600
 
-#include "hb-private.hh"
+#define HB_SHAPER uniscribe
+#include "hb-shaper-impl-private.hh"
 
 #include <windows.h>
 #include <usp10.h>
@@ -38,10 +39,6 @@ typedef ULONG WIN_ULONG;
 #include "hb-ot-name-table.hh"
 #include "hb-ot-tag.h"
 
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
-
-
 
 #ifndef HB_DEBUG_UNISCRIBE
 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
@@ -91,31 +88,20 @@ populate_log_font (LOGFONTW  *lf,
 }
 
 
-static hb_user_data_key_t hb_uniscribe_data_key;
-
+/*
+ * shaper face data
+ */
 
-static struct hb_uniscribe_face_data_t {
+struct hb_uniscribe_shaper_face_data_t {
   HANDLE fh;
-} _hb_uniscribe_face_data_nil = {0};
-
-static void
-_hb_uniscribe_face_data_destroy (hb_uniscribe_face_data_t *data)
-{
-  if (data->fh)
-    RemoveFontMemResourceEx (data->fh);
-  free (data);
-}
+};
 
-static hb_uniscribe_face_data_t *
-_hb_uniscribe_face_get_data (hb_face_t *face)
+hb_uniscribe_shaper_face_data_t *
+_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
 {
-  hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
-  if (likely (data)) return data;
-
-  data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t));
+  hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
   if (unlikely (!data))
-    return &_hb_uniscribe_face_data_nil;
-
+    return NULL;
 
   hb_blob_t *blob = hb_face_reference_blob (face);
   unsigned int blob_length;
@@ -126,35 +112,68 @@ _hb_uniscribe_face_get_data (hb_face_t *face)
   DWORD num_fonts_installed;
   data->fh = AddFontMemResourceEx ((void *) blob_data, blob_length, 0, &num_fonts_installed);
   hb_blob_destroy (blob);
-  if (unlikely (!data->fh))
+  if (unlikely (!data->fh)) {
     DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
-
-
-  if (unlikely (!hb_face_set_user_data (face, &hb_uniscribe_data_key, data,
-					(hb_destroy_func_t) _hb_uniscribe_face_data_destroy,
-					false)))
-  {
-    _hb_uniscribe_face_data_destroy (data);
-    data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
-    if (data)
-      return data;
-    else
-      return &_hb_uniscribe_face_data_nil;
+    free (data);
+    return NULL;
   }
 
   return data;
 }
 
+void
+_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
+{
+  if (data->fh)
+    RemoveFontMemResourceEx (data->fh);
+  free (data);
+}
 
-static struct hb_uniscribe_font_data_t {
+
+/*
+ * shaper font data
+ */
+
+struct hb_uniscribe_shaper_font_data_t {
   HDC hdc;
   LOGFONTW log_font;
   HFONT hfont;
   SCRIPT_CACHE script_cache;
-} _hb_uniscribe_font_data_nil = {NULL, NULL, NULL};
+};
 
-static void
-_hb_uniscribe_font_data_destroy (hb_uniscribe_font_data_t *data)
+hb_uniscribe_shaper_font_data_t *
+_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
+{
+  hb_uniscribe_shaper_font_data_t * data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  data->hdc = GetDC (NULL);
+
+  if (unlikely (!populate_log_font (&data->log_font, font))) {
+    DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
+    _hb_uniscribe_shaper_font_data_destroy (data);
+    return NULL;
+  }
+
+  data->hfont = CreateFontIndirectW (&data->log_font);
+  if (unlikely (!data->hfont)) {
+    DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
+    _hb_uniscribe_shaper_font_data_destroy (data);
+     return NULL;
+  }
+
+  if (!SelectObject (data->hdc, data->hfont)) {
+    DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
+    _hb_uniscribe_shaper_font_data_destroy (data);
+     return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
 {
   if (data->hdc)
     ReleaseDC (NULL, data->hdc);
@@ -165,38 +184,67 @@ _hb_uniscribe_font_data_destroy (hb_uniscribe_font_data_t *data)
   free (data);
 }
 
-static hb_uniscribe_font_data_t *
-_hb_uniscribe_font_get_data (hb_font_t *font)
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_uniscribe_shaper_shape_plan_data_t {};
+
+hb_uniscribe_shaper_shape_plan_data_t *
+_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan)
 {
-  hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
-  if (likely (data)) return data;
+  return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
 
-  data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t));
-  if (unlikely (!data))
-    return &_hb_uniscribe_font_data_nil;
+void
+_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data)
+{
+}
 
-  data->hdc = GetDC (NULL);
 
-  if (unlikely (!populate_log_font (&data->log_font, font)))
-    DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
-  else {
-    data->hfont = CreateFontIndirectW (&data->log_font);
-    if (unlikely (!data->hfont))
-      DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
-    if (!SelectObject (data->hdc, data->hfont))
-      DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
+/*
+ * shaper
+ */
+static hb_user_data_key_t hb_uniscribe_data_key;
+
+static hb_uniscribe_shaper_face_data_t *
+_hb_uniscribe_face_get_data (hb_face_t *face)
+{
+  hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
+  if (likely (data)) return data;
+
+  data = _hb_uniscribe_shaper_face_data_create (face);
+  if (!data) return NULL;
+
+  if (unlikely (!hb_face_set_user_data (face, &hb_uniscribe_data_key, data,
+					(hb_destroy_func_t) _hb_uniscribe_shaper_face_data_destroy,
+					false)))
+  {
+    _hb_uniscribe_shaper_face_data_destroy (data);
+    data = (hb_uniscribe_shaper_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
   }
 
+  return data;
+}
+
+
+static hb_uniscribe_shaper_font_data_t *
+_hb_uniscribe_font_get_data (hb_font_t *font)
+{
+  hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
+  if (likely (data)) return data;
+
+  data = _hb_uniscribe_shaper_font_data_create (font);
+  if (unlikely (!data))
+    return NULL;
+
   if (unlikely (!hb_font_set_user_data (font, &hb_uniscribe_data_key, data,
-					(hb_destroy_func_t) _hb_uniscribe_font_data_destroy,
+					(hb_destroy_func_t) _hb_uniscribe_shaper_font_data_destroy,
 					false)))
   {
-    _hb_uniscribe_font_data_destroy (data);
-    data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
-    if (data)
-      return data;
-    else
-      return &_hb_uniscribe_font_data_nil;
+    _hb_uniscribe_shaper_font_data_destroy (data);
+    data = (hb_uniscribe_shaper_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
   }
 
   return data;
@@ -205,7 +253,7 @@ _hb_uniscribe_font_get_data (hb_font_t *font)
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font)
 {
-  hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
+  hb_uniscribe_shaper_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
   if (unlikely (!font_data))
     return NULL;
   return &font_data->log_font;
@@ -214,7 +262,7 @@ hb_uniscribe_font_get_logfontw (hb_font_t *font)
 HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font)
 {
-  hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
+  hb_uniscribe_shaper_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
   if (unlikely (!font_data))
     return 0;
   return font_data->hfont;
@@ -235,11 +283,11 @@ _hb_uniscribe_shape (hb_font_t          *font,
     return false; \
   } HB_STMT_END;
 
-  hb_uniscribe_face_data_t *face_data = _hb_uniscribe_face_get_data (font->face);
+  hb_uniscribe_shaper_face_data_t *face_data = _hb_uniscribe_face_get_data (font->face);
   if (unlikely (!face_data->fh))
     FAIL ("Couldn't get face data");
 
-  hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
+  hb_uniscribe_shaper_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
   if (unlikely (!font_data->hfont))
     FAIL ("Couldn't get font font");
 



More information about the HarfBuzz mailing list