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

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Apr 20 00:17:25 PDT 2011


 src/Makefile.am           |    8 -
 src/hb-blob-private.h     |    2 
 src/hb-blob.c             |   16 +-
 src/hb-blob.h             |    4 
 src/hb-buffer-private.hh  |    2 
 src/hb-common.c           |    5 
 src/hb-font-private.h     |    4 
 src/hb-font.cc            |   30 ++--
 src/hb-font.h             |   12 -
 src/hb-ft.c               |    8 -
 src/hb-glib.c             |   64 ---------
 src/hb-glib.cc            |  241 ++++++++++++++++++++++++++++++++++++
 src/hb-glib.h             |    8 +
 src/hb-icu.c              |  260 ---------------------------------------
 src/hb-icu.cc             |  300 ++++++++++++++++++++++++++++++++++++++++++++++
 src/hb-icu.h              |    9 +
 src/hb-ot-shape.cc        |   11 -
 src/hb-shape.cc           |    4 
 src/hb-unicode-private.h  |   60 ---------
 src/hb-unicode-private.hh |   96 ++++++++++++++
 src/hb-unicode.c          |  237 ------------------------------------
 src/hb-unicode.cc         |  223 ++++++++++++++++++++++++++++++++++
 src/hb-unicode.h          |   97 +++++++-------
 test/Makefile.am          |   20 ++-
 test/test-c.c             |   49 +++++++
 test/test-common.c        |  166 +++++++++++++++++++++++++
 test/test-cplusplus.cc    |   29 ++++
 test/test-types.c         |  166 -------------------------
 test/test-unicode.c       |  227 ++++++++++++++++++++++++++++++++++
 29 files changed, 1468 insertions(+), 890 deletions(-)

New commits:
commit fb6291d9c9224bedf207bf0077ad9f0a2690f867
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 03:15:31 2011 -0400

    [test] Add test for headers included from C and C++

diff --git a/test/Makefile.am b/test/Makefile.am
index 499d00b..e4fdb20 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,6 +15,23 @@ TEST_PROGS += \
 	$(NULL)
 
 
+# Tests for header compilation
+TEST_PROGS += \
+	test-c \
+	test-cplusplus \
+	$(NULL)
+test_cplusplus_SOURCES = test-cplusplus.cc
+test_c_CPPFLAGS = $(AM_CPPFLAGS)
+test_cplusplus_CPPFLAGS = $(AM_CPPFLAGS)
+if HAVE_ICU
+test_c_CPPFLAGS += $(ICU_CFLAGS)
+test_cplusplus_CPPFLAGS += $(ICU_CFLAGS)
+endif
+if HAVE_FREETYPE
+test_c_CPPFLAGS += $(FREETYPE_CFLAGS)
+test_cplusplus_CPPFLAGS += $(FREETYPE_CFLAGS)
+endif
+
 
 else
 check-am:
diff --git a/test/test-c.c b/test/test-c.c
new file mode 100644
index 0000000..37f02ff
--- /dev/null
+++ b/test/test-c.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+/* This file tests that all headers can be included from .c files */
+
+#include <config.h>
+
+#include <hb.h>
+
+#if HAVE_GLIB
+#include <hb-glib.h>
+#endif
+
+#if HAVE_ICU
+#include <hb-icu.h>
+#endif
+
+#if HAVE_FREETYPE
+#include <hb-ft.h>
+#endif
+
+int
+main (int argc, char **argv)
+{
+  return 0;
+}
diff --git a/test/test-cplusplus.cc b/test/test-cplusplus.cc
new file mode 100644
index 0000000..3488b78
--- /dev/null
+++ b/test/test-cplusplus.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+/* This file tests that all headers can be included from .cc files */
+
+#include "test-c.c"
commit 107a50581ccab7df7c390d5b927fdab1bbe8e713
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 03:04:56 2011 -0400

    [test] Add todo items

diff --git a/test/test-unicode.c b/test/test-unicode.c
index c210d54..923c250 100644
--- a/test/test-unicode.c
+++ b/test/test-unicode.c
@@ -220,5 +220,8 @@ main (int argc, char **argv)
   g_test_add_func ("/unicode/subclassing/glib", test_subclassing_glib);
   g_test_add_func ("/unicode/subclassing/deep", test_subclassing_deep);
 
+  /* XXX test all methods for their defaults and various (glib, icu) implementations. */
+  /* XXX test glib & icu two-way script conversion */
+
   return g_test_run ();
 }
commit 5668189c12c264e8d2caf0d12dac918363ef6f80
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 03:03:32 2011 -0400

    [API] font: move user_data before destroy()
    
    This is the common convention for language binding tools.

diff --git a/src/hb-font-private.h b/src/hb-font-private.h
index b147bce..46686b7 100644
--- a/src/hb-font-private.h
+++ b/src/hb-font-private.h
@@ -63,8 +63,8 @@ struct _hb_face_t {
   hb_reference_count_t ref_count;
 
   hb_get_table_func_t  get_table;
-  hb_destroy_func_t    destroy;
   void                *user_data;
+  hb_destroy_func_t    destroy;
 
   hb_blob_t *head_blob;
   const struct head *head_table;
@@ -87,8 +87,8 @@ struct _hb_font_t {
   unsigned int y_ppem;
 
   hb_font_funcs_t   *klass;
-  hb_destroy_func_t  destroy;
   void              *user_data;
+  hb_destroy_func_t  destroy;
 };
 
 
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 63631a9..43112c1 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -296,8 +296,8 @@ static hb_face_t _hb_face_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
 
   NULL, /* get_table */
-  NULL, /* destroy */
   NULL, /* user_data */
+  NULL, /* destroy */
 
   NULL, /* head_blob */
   NULL, /* head_table */
@@ -308,8 +308,8 @@ static hb_face_t _hb_face_nil = {
 
 hb_face_t *
 hb_face_create_for_tables (hb_get_table_func_t  get_table,
-			   hb_destroy_func_t    destroy,
-			   void                *user_data)
+			   void                *user_data,
+			   hb_destroy_func_t    destroy)
 {
   hb_face_t *face;
 
@@ -320,8 +320,8 @@ hb_face_create_for_tables (hb_get_table_func_t  get_table,
   }
 
   face->get_table = get_table;
-  face->destroy = destroy;
   face->user_data = user_data;
+  face->destroy = destroy;
 
   face->ot_layout = _hb_ot_layout_new (face);
 
@@ -386,8 +386,8 @@ hb_face_create_for_data (hb_blob_t    *blob,
     return &_hb_face_nil;
 
   return hb_face_create_for_tables (_hb_face_for_data_get_table,
-				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy,
-				    closure);
+				    closure,
+				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
 }
 
 
@@ -454,8 +454,8 @@ static hb_font_t _hb_font_nil = {
   0, /* y_ppem */
 
   NULL, /* klass */
-  NULL, /* destroy */
-  NULL  /* user_data */
+  NULL, /* user_data */
+  NULL  /* destroy */
 };
 
 hb_font_t *
@@ -498,8 +498,8 @@ hb_font_destroy (hb_font_t *font)
 void
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
-		   hb_destroy_func_t  destroy,
-		   void              *user_data)
+		   void              *user_data,
+		   hb_destroy_func_t  destroy)
 {
   if (HB_OBJECT_IS_INERT (font))
     return;
@@ -513,28 +513,28 @@ hb_font_set_funcs (hb_font_t         *font,
   hb_font_funcs_reference (klass);
   hb_font_funcs_destroy (font->klass);
   font->klass = klass;
-  font->destroy = destroy;
   font->user_data = user_data;
+  font->destroy = destroy;
 }
 
 void
 hb_font_unset_funcs (hb_font_t          *font,
 		     hb_font_funcs_t   **klass,
-		     hb_destroy_func_t  *destroy,
-		     void              **user_data)
+		     void              **user_data,
+		     hb_destroy_func_t  *destroy)
 {
   /* None of the input arguments can be NULL. */
 
   *klass = font->klass;
-  *destroy = font->destroy;
   *user_data = font->user_data;
+  *destroy = font->destroy;
 
   if (HB_OBJECT_IS_INERT (font))
     return;
 
   font->klass = NULL;
-  font->destroy = NULL;
   font->user_data = NULL;
+  font->destroy = NULL;
 }
 
 void
diff --git a/src/hb-font.h b/src/hb-font.h
index f33e56f..4b9540b 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -49,8 +49,8 @@ typedef hb_blob_t * (*hb_get_table_func_t)  (hb_tag_t tag, void *user_data);
 /* calls destroy() when not needing user_data anymore */
 hb_face_t *
 hb_face_create_for_tables (hb_get_table_func_t  get_table,
-			   hb_destroy_func_t    destroy,
-			   void                *user_data);
+			   void                *user_data,
+			   hb_destroy_func_t    destroy);
 
 hb_face_t *
 hb_face_reference (hb_face_t *face);
@@ -218,8 +218,8 @@ hb_font_destroy (hb_font_t *font);
 void
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
-		   hb_destroy_func_t  destroy,
-		   void              *user_data);
+		   void              *user_data,
+		   hb_destroy_func_t  destroy);
 
 /* Returns what was set and unsets it, but doesn't destroy(user_data).
  * This is useful for wrapping / chaining font_funcs_t's.
@@ -234,8 +234,8 @@ hb_font_set_funcs (hb_font_t         *font,
 void
 hb_font_unset_funcs (hb_font_t          *font,
 		     hb_font_funcs_t   **klass,
-		     hb_destroy_func_t  *destroy,
-		     void              **user_data);
+		     void              **user_data,
+		     hb_destroy_func_t  *destroy);
 
 
 /*
diff --git a/src/hb-ft.c b/src/hb-ft.c
index e696fe8..96c035a 100644
--- a/src/hb-ft.c
+++ b/src/hb-ft.c
@@ -189,7 +189,7 @@ get_table  (hb_tag_t tag, void *user_data)
 
   return hb_blob_create ((const char *) buffer, length,
 			 HB_MEMORY_MODE_WRITABLE,
-			 free, buffer);
+			 buffer, free);
 }
 
 
@@ -206,11 +206,11 @@ hb_ft_face_create (FT_Face           ft_face,
 			   (unsigned int) ft_face->stream->size,
 			   /* TODO: Check FT_FACE_FLAG_EXTERNAL_STREAM? */
 			   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
-			   destroy, ft_face);
+			   ft_face, destroy);
     face = hb_face_create_for_data (blob, ft_face->face_index);
     hb_blob_destroy (blob);
   } else {
-    face = hb_face_create_for_tables (get_table, destroy, ft_face);
+    face = hb_face_create_for_tables (get_table, ft_face, destroy);
   }
 
   return face;
@@ -247,7 +247,7 @@ hb_ft_font_create (FT_Face           ft_face,
   font = hb_font_create ();
   hb_font_set_funcs (font,
 		     hb_ft_get_font_funcs (),
-		     destroy, ft_face);
+		     ft_face, destroy);
   hb_font_set_scale (font,
 		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
 		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
commit e5847f75fb7bd25c5db6061d8e20d61fa469f9fe
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 02:59:28 2011 -0400

    [API] blob: move user_data before destroy()
    
    This is the common convention for language binding tools.

diff --git a/src/hb-blob-private.h b/src/hb-blob-private.h
index 92109ed..cdc9b2f 100644
--- a/src/hb-blob-private.h
+++ b/src/hb-blob-private.h
@@ -47,8 +47,8 @@ struct _hb_blob_t {
 
   const char *data;
 
-  hb_destroy_func_t destroy;
   void *user_data;
+  hb_destroy_func_t destroy;
 };
 
 extern HB_INTERNAL hb_blob_t _hb_blob_nil;
diff --git a/src/hb-blob.c b/src/hb-blob.c
index 37e7787..97ffd99 100644
--- a/src/hb-blob.c
+++ b/src/hb-blob.c
@@ -57,8 +57,8 @@ hb_blob_t _hb_blob_nil = {
 
   NULL, /* data */
 
-  NULL, /* destroy */
-  NULL /* user_data */
+  NULL, /* user_data */
+  NULL  /* destroy */
 };
 
 static void
@@ -66,8 +66,8 @@ _hb_blob_destroy_user_data (hb_blob_t *blob)
 {
   if (blob->destroy) {
     blob->destroy (blob->user_data);
-    blob->destroy = NULL;
     blob->user_data = NULL;
+    blob->destroy = NULL;
   }
 }
 
@@ -82,8 +82,8 @@ hb_blob_t *
 hb_blob_create (const char        *data,
 		unsigned int       length,
 		hb_memory_mode_t   mode,
-		hb_destroy_func_t  destroy,
-		void              *user_data)
+		void              *user_data,
+		hb_destroy_func_t  destroy)
 {
   hb_blob_t *blob;
 
@@ -100,8 +100,8 @@ hb_blob_create (const char        *data,
   blob->length = length;
   blob->mode = mode;
 
-  blob->destroy = destroy;
   blob->user_data = user_data;
+  blob->destroy = destroy;
 
   if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
     blob->mode = HB_MEMORY_MODE_READONLY;
@@ -134,8 +134,8 @@ hb_blob_create_sub_blob (hb_blob_t    *parent,
   blob->mode = parent->mode;
   hb_mutex_unlock (parent->lock);
 
-  blob->destroy = (hb_destroy_func_t) _hb_blob_unlock_and_destroy;
   blob->user_data = hb_blob_reference (parent);
+  blob->destroy = (hb_destroy_func_t) _hb_blob_unlock_and_destroy;
 
   return blob;
 }
@@ -345,8 +345,8 @@ hb_blob_try_writable (hb_blob_t *blob)
       _hb_blob_destroy_user_data (blob);
       blob->mode = HB_MEMORY_MODE_WRITABLE;
       blob->data = new_data;
-      blob->destroy = free;
       blob->user_data = new_data;
+      blob->destroy = free;
     }
   }
 
diff --git a/src/hb-blob.h b/src/hb-blob.h
index dbbfc90..b6080f1 100644
--- a/src/hb-blob.h
+++ b/src/hb-blob.h
@@ -45,8 +45,8 @@ hb_blob_t *
 hb_blob_create (const char        *data,
 		unsigned int       length,
 		hb_memory_mode_t   mode,
-		hb_destroy_func_t  destroy,
-		void              *user_data);
+		void              *user_data,
+		hb_destroy_func_t  destroy);
 
 hb_blob_t *
 hb_blob_create_sub_blob (hb_blob_t    *parent,
commit 1fd73b594d611624ccb73f614c61298debf48994
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 02:56:39 2011 -0400

    [test] Rename test-types to test-common

diff --git a/test/Makefile.am b/test/Makefile.am
index 37cfed2..499d00b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -10,7 +10,7 @@ check_PROGRAMS = $(TEST_PROGS)
 
 TEST_PROGS += \
 	test-buffer \
-	test-types \
+	test-common \
 	test-unicode \
 	$(NULL)
 
diff --git a/test/test-common.c b/test/test-common.c
new file mode 100644
index 0000000..daf2754
--- /dev/null
+++ b/test/test-common.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-test.h"
+
+/* This file tests types defined in hb-common.h */
+
+static void
+test_types_int (void)
+{
+  /* We already ASSERT_STATIC these in hb-private.h, but anyway */
+  g_assert_cmpint (sizeof (int8_t), ==, 1);
+  g_assert_cmpint (sizeof (uint8_t), ==, 1);
+  g_assert_cmpint (sizeof (int16_t), ==, 2);
+  g_assert_cmpint (sizeof (uint16_t), ==, 2);
+  g_assert_cmpint (sizeof (int32_t), ==, 4);
+  g_assert_cmpint (sizeof (uint32_t), ==, 4);
+  g_assert_cmpint (sizeof (int64_t), ==, 8);
+  g_assert_cmpint (sizeof (uint64_t), ==, 8);
+
+  g_assert_cmpint (sizeof (hb_codepoint_t), ==, 4);
+  g_assert_cmpint (sizeof (hb_position_t), ==, 4);
+  g_assert_cmpint (sizeof (hb_mask_t), ==, 4);
+  g_assert_cmpint (sizeof (hb_var_int_t), ==, 4);
+}
+
+static void
+test_types_direction (void)
+{
+  g_assert_cmpint ((signed) HB_DIRECTION_INVALID, ==, -1);
+  g_assert_cmpint (HB_DIRECTION_LTR, ==, 0);
+
+  g_assert (HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_LTR));
+  g_assert (HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_RTL));
+  g_assert (!HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_TTB));
+  g_assert (!HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_BTT));
+
+  g_assert (!HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_LTR));
+  g_assert (!HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_RTL));
+  g_assert (HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_TTB));
+  g_assert (HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_BTT));
+
+  g_assert (HB_DIRECTION_IS_FORWARD (HB_DIRECTION_LTR));
+  g_assert (HB_DIRECTION_IS_FORWARD (HB_DIRECTION_TTB));
+  g_assert (!HB_DIRECTION_IS_FORWARD (HB_DIRECTION_RTL));
+  g_assert (!HB_DIRECTION_IS_FORWARD (HB_DIRECTION_BTT));
+
+  g_assert (!HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_LTR));
+  g_assert (!HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_TTB));
+  g_assert (HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_RTL));
+  g_assert (HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_BTT));
+
+  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_LTR), ==, HB_DIRECTION_RTL);
+  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_RTL), ==, HB_DIRECTION_LTR);
+  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_TTB), ==, HB_DIRECTION_BTT);
+  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_BTT), ==, HB_DIRECTION_TTB);
+}
+
+static void
+test_types_tag (void)
+{
+  g_assert_cmphex (HB_TAG_NONE, ==, 0);
+
+  g_assert_cmphex (HB_TAG ('a','B','c','D'), ==, 0x61426344);
+
+  g_assert_cmphex (hb_tag_from_string ("aBcDe"), ==, 0x61426344);
+  g_assert_cmphex (hb_tag_from_string ("aBcD"),  ==, 0x61426344);
+  g_assert_cmphex (hb_tag_from_string ("aBc"),   ==, 0x61426320);
+  g_assert_cmphex (hb_tag_from_string ("aB"),    ==, 0x61422020);
+  g_assert_cmphex (hb_tag_from_string ("a"),     ==, 0x61202020);
+
+  g_assert_cmphex (hb_tag_from_string (""),      ==, HB_TAG_NONE);
+  g_assert_cmphex (hb_tag_from_string (NULL),    ==, HB_TAG_NONE);
+}
+
+static void
+test_types_script (void)
+{
+  hb_tag_t arab = HB_TAG_CHAR4 ("arab");
+  hb_tag_t Arab = HB_TAG_CHAR4 ("Arab");
+  hb_tag_t ARAB = HB_TAG_CHAR4 ("ARAB");
+
+  hb_tag_t wWyZ = HB_TAG_CHAR4 ("wWyZ");
+  hb_tag_t Wwyz = HB_TAG_CHAR4 ("Wwyz");
+
+  hb_tag_t x123 = HB_TAG_CHAR4 ("x123");
+
+  g_assert_cmpint ((hb_tag_t) HB_SCRIPT_INVALID, ==, HB_TAG_NONE);
+  g_assert_cmphex (HB_SCRIPT_ARABIC, !=, HB_SCRIPT_LATIN);
+
+  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (arab));
+  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (Arab));
+  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (ARAB));
+
+  /* Arbitrary tags that look like may be valid ISO 15924 should be preserved. */
+  g_assert_cmphex (HB_SCRIPT_UNKNOWN, !=, hb_script_from_iso15924_tag (wWyZ));
+  /* Otherwise, UNKNOWN should be returned. */
+  g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_iso15924_tag (x123));
+
+  g_assert_cmphex (hb_script_to_iso15924_tag (HB_SCRIPT_ARABIC), ==, Arab);
+  g_assert_cmphex (hb_script_to_iso15924_tag (hb_script_from_iso15924_tag (wWyZ)), ==, Wwyz);
+
+  g_assert_cmpint (hb_script_get_horizontal_direction (HB_SCRIPT_LATIN), ==, HB_DIRECTION_LTR);
+  g_assert_cmpint (hb_script_get_horizontal_direction (HB_SCRIPT_ARABIC), ==, HB_DIRECTION_RTL);
+  g_assert_cmpint (hb_script_get_horizontal_direction (hb_script_from_iso15924_tag (wWyZ)), ==, HB_DIRECTION_LTR);
+}
+
+static void
+test_types_language (void)
+{
+  hb_language_t fa = hb_language_from_string ("fa");
+  hb_language_t fa_IR = hb_language_from_string ("fa_IR");
+  hb_language_t fa_ir = hb_language_from_string ("fa-ir");
+  hb_language_t en = hb_language_from_string ("en");
+
+  g_assert (fa != NULL);
+  g_assert (fa_IR != NULL);
+  g_assert (fa_IR == fa_ir);
+
+  g_assert (en != NULL);
+  g_assert (en != fa);
+
+  /* Test recall */
+  g_assert (en == hb_language_from_string ("en"));
+  g_assert (en == hb_language_from_string ("eN"));
+
+  g_assert (NULL == hb_language_from_string (NULL));
+  g_assert (NULL == hb_language_from_string (""));
+}
+
+int
+main (int argc, char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/types/int", test_types_int);
+  g_test_add_func ("/types/direction", test_types_direction);
+  g_test_add_func ("/types/tag", test_types_tag);
+  g_test_add_func ("/types/script", test_types_script);
+  g_test_add_func ("/types/language", test_types_language);
+
+  return g_test_run();
+}
diff --git a/test/test-types.c b/test/test-types.c
deleted file mode 100644
index daf2754..0000000
--- a/test/test-types.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2010  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb-test.h"
-
-/* This file tests types defined in hb-common.h */
-
-static void
-test_types_int (void)
-{
-  /* We already ASSERT_STATIC these in hb-private.h, but anyway */
-  g_assert_cmpint (sizeof (int8_t), ==, 1);
-  g_assert_cmpint (sizeof (uint8_t), ==, 1);
-  g_assert_cmpint (sizeof (int16_t), ==, 2);
-  g_assert_cmpint (sizeof (uint16_t), ==, 2);
-  g_assert_cmpint (sizeof (int32_t), ==, 4);
-  g_assert_cmpint (sizeof (uint32_t), ==, 4);
-  g_assert_cmpint (sizeof (int64_t), ==, 8);
-  g_assert_cmpint (sizeof (uint64_t), ==, 8);
-
-  g_assert_cmpint (sizeof (hb_codepoint_t), ==, 4);
-  g_assert_cmpint (sizeof (hb_position_t), ==, 4);
-  g_assert_cmpint (sizeof (hb_mask_t), ==, 4);
-  g_assert_cmpint (sizeof (hb_var_int_t), ==, 4);
-}
-
-static void
-test_types_direction (void)
-{
-  g_assert_cmpint ((signed) HB_DIRECTION_INVALID, ==, -1);
-  g_assert_cmpint (HB_DIRECTION_LTR, ==, 0);
-
-  g_assert (HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_LTR));
-  g_assert (HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_RTL));
-  g_assert (!HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_TTB));
-  g_assert (!HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_BTT));
-
-  g_assert (!HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_LTR));
-  g_assert (!HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_RTL));
-  g_assert (HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_TTB));
-  g_assert (HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_BTT));
-
-  g_assert (HB_DIRECTION_IS_FORWARD (HB_DIRECTION_LTR));
-  g_assert (HB_DIRECTION_IS_FORWARD (HB_DIRECTION_TTB));
-  g_assert (!HB_DIRECTION_IS_FORWARD (HB_DIRECTION_RTL));
-  g_assert (!HB_DIRECTION_IS_FORWARD (HB_DIRECTION_BTT));
-
-  g_assert (!HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_LTR));
-  g_assert (!HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_TTB));
-  g_assert (HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_RTL));
-  g_assert (HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_BTT));
-
-  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_LTR), ==, HB_DIRECTION_RTL);
-  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_RTL), ==, HB_DIRECTION_LTR);
-  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_TTB), ==, HB_DIRECTION_BTT);
-  g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_BTT), ==, HB_DIRECTION_TTB);
-}
-
-static void
-test_types_tag (void)
-{
-  g_assert_cmphex (HB_TAG_NONE, ==, 0);
-
-  g_assert_cmphex (HB_TAG ('a','B','c','D'), ==, 0x61426344);
-
-  g_assert_cmphex (hb_tag_from_string ("aBcDe"), ==, 0x61426344);
-  g_assert_cmphex (hb_tag_from_string ("aBcD"),  ==, 0x61426344);
-  g_assert_cmphex (hb_tag_from_string ("aBc"),   ==, 0x61426320);
-  g_assert_cmphex (hb_tag_from_string ("aB"),    ==, 0x61422020);
-  g_assert_cmphex (hb_tag_from_string ("a"),     ==, 0x61202020);
-
-  g_assert_cmphex (hb_tag_from_string (""),      ==, HB_TAG_NONE);
-  g_assert_cmphex (hb_tag_from_string (NULL),    ==, HB_TAG_NONE);
-}
-
-static void
-test_types_script (void)
-{
-  hb_tag_t arab = HB_TAG_CHAR4 ("arab");
-  hb_tag_t Arab = HB_TAG_CHAR4 ("Arab");
-  hb_tag_t ARAB = HB_TAG_CHAR4 ("ARAB");
-
-  hb_tag_t wWyZ = HB_TAG_CHAR4 ("wWyZ");
-  hb_tag_t Wwyz = HB_TAG_CHAR4 ("Wwyz");
-
-  hb_tag_t x123 = HB_TAG_CHAR4 ("x123");
-
-  g_assert_cmpint ((hb_tag_t) HB_SCRIPT_INVALID, ==, HB_TAG_NONE);
-  g_assert_cmphex (HB_SCRIPT_ARABIC, !=, HB_SCRIPT_LATIN);
-
-  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (arab));
-  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (Arab));
-  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (ARAB));
-
-  /* Arbitrary tags that look like may be valid ISO 15924 should be preserved. */
-  g_assert_cmphex (HB_SCRIPT_UNKNOWN, !=, hb_script_from_iso15924_tag (wWyZ));
-  /* Otherwise, UNKNOWN should be returned. */
-  g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_iso15924_tag (x123));
-
-  g_assert_cmphex (hb_script_to_iso15924_tag (HB_SCRIPT_ARABIC), ==, Arab);
-  g_assert_cmphex (hb_script_to_iso15924_tag (hb_script_from_iso15924_tag (wWyZ)), ==, Wwyz);
-
-  g_assert_cmpint (hb_script_get_horizontal_direction (HB_SCRIPT_LATIN), ==, HB_DIRECTION_LTR);
-  g_assert_cmpint (hb_script_get_horizontal_direction (HB_SCRIPT_ARABIC), ==, HB_DIRECTION_RTL);
-  g_assert_cmpint (hb_script_get_horizontal_direction (hb_script_from_iso15924_tag (wWyZ)), ==, HB_DIRECTION_LTR);
-}
-
-static void
-test_types_language (void)
-{
-  hb_language_t fa = hb_language_from_string ("fa");
-  hb_language_t fa_IR = hb_language_from_string ("fa_IR");
-  hb_language_t fa_ir = hb_language_from_string ("fa-ir");
-  hb_language_t en = hb_language_from_string ("en");
-
-  g_assert (fa != NULL);
-  g_assert (fa_IR != NULL);
-  g_assert (fa_IR == fa_ir);
-
-  g_assert (en != NULL);
-  g_assert (en != fa);
-
-  /* Test recall */
-  g_assert (en == hb_language_from_string ("en"));
-  g_assert (en == hb_language_from_string ("eN"));
-
-  g_assert (NULL == hb_language_from_string (NULL));
-  g_assert (NULL == hb_language_from_string (""));
-}
-
-int
-main (int argc, char **argv)
-{
-  g_test_init (&argc, &argv, NULL);
-
-  g_test_add_func ("/types/int", test_types_int);
-  g_test_add_func ("/types/direction", test_types_direction);
-  g_test_add_func ("/types/tag", test_types_tag);
-  g_test_add_func ("/types/script", test_types_script);
-  g_test_add_func ("/types/language", test_types_language);
-
-  return g_test_run();
-}
commit f144a8ea840c6452c1fece2fd988b42a8ea7c5a6
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 02:54:42 2011 -0400

    [icu] Add two-way script conversion functions
    
    Also optimizes the common-direction script lookup.

diff --git a/src/hb-common.c b/src/hb-common.c
index 56537e4..c1c4c54 100644
--- a/src/hb-common.c
+++ b/src/hb-common.c
@@ -37,7 +37,7 @@ hb_tag_from_string (const char *s)
   char tag[4];
   unsigned int i;
 
-  if (!s)
+  if (!s || !*s)
     return HB_TAG_NONE;
 
   for (i = 0; i < 4 && s[i]; i++)
@@ -146,6 +146,9 @@ hb_language_to_string (hb_language_t language)
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag)
 {
+  if (unlikely (tag == HB_TAG_NONE))
+    return HB_SCRIPT_INVALID;
+
   /* Be lenient, adjust case (one capital letter followed by three small letters) */
   tag = (tag & 0xDFDFDFDF) | 0x00202020;
 
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index dcfbade..8fc8c81 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -33,111 +33,27 @@
 
 #include <unicode/uversion.h>
 #include <unicode/uchar.h>
-#include <unicode/uscript.h>
 
 HB_BEGIN_DECLS
 
 
-static unsigned int
-hb_icu_get_combining_class (hb_unicode_funcs_t *ufuncs,
-			    hb_codepoint_t      unicode,
-			    void               *user_data)
-
-{
-  return u_getCombiningClass (unicode);
-}
-
-static unsigned int
-hb_icu_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
-			    hb_codepoint_t      unicode,
-			    void               *user_data)
+hb_script_t
+hb_icu_script_to_script (UScriptCode script)
 {
-  switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
-  {
-  case U_EA_WIDE:
-  case U_EA_FULLWIDTH:
-    return 2;
-  case U_EA_NEUTRAL:
-  case U_EA_AMBIGUOUS:
-  case U_EA_HALFWIDTH:
-  case U_EA_NARROW:
-    return 1;
-  }
-  return 1;
+  return hb_script_from_string (uscript_getShortName (script));
 }
 
-static hb_unicode_general_category_t
-hb_icu_get_general_category (hb_unicode_funcs_t *ufuncs,
-			     hb_codepoint_t      unicode,
-			     void               *user_data)
+UScriptCode
+hb_icu_script_from_script (hb_script_t script)
 {
-  switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
-  {
-  case U_UNASSIGNED:			return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
-
-  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
-  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
-  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
-  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
-  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
-
-  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
-  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
-  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_COMBINING_MARK;
-
-  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
-  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
-  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
-
-  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
-  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
-  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
-
-  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
-  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
-  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
-  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
-
-
-  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
-  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
-  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
-  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
-  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
-
-  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
-  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
-  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
-  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
-
-  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
-  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
-  }
-
-  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
-}
-
-static hb_codepoint_t
-hb_icu_get_mirroring (hb_unicode_funcs_t *ufuncs,
-		      hb_codepoint_t      unicode,
-		      void               *user_data)
-{
-  return u_charMirror(unicode);
-}
-
-static hb_script_t
-hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
-		   hb_codepoint_t      unicode,
-		   void               *user_data)
-{
-  UErrorCode status = U_ZERO_ERROR;
-  UScriptCode scriptCode = uscript_getScript(unicode, &status);
-  switch ((int) scriptCode)
+  switch ((int) script)
   {
 #define CHECK_ICU_VERSION(major, minor) \
 	U_ICU_VERSION_MAJOR_NUM > (major) || (U_ICU_VERSION_MAJOR_NUM == (major) && U_ICU_VERSION_MINOR_NUM >= (minor))
-#define MATCH_SCRIPT(C) case USCRIPT_##C: return HB_SCRIPT_##C
-#define MATCH_SCRIPT2(C1, C2) case USCRIPT_##C1: return HB_SCRIPT_##C2
+#define MATCH_SCRIPT(C) case HB_SCRIPT_##C: return USCRIPT_##C
+#define MATCH_SCRIPT2(C1, C2) case HB_SCRIPT_##C2: return USCRIPT_##C1
+
+  MATCH_SCRIPT2(INVALID_CODE, INVALID);
 
   MATCH_SCRIPT (COMMON);
   MATCH_SCRIPT (INHERITED);
@@ -259,7 +175,106 @@ hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
 #undef MATCH_SCRIPT2
   }
 
-  return HB_SCRIPT_UNKNOWN;
+  return USCRIPT_UNKNOWN;
+}
+
+
+static unsigned int
+hb_icu_get_combining_class (hb_unicode_funcs_t *ufuncs,
+			    hb_codepoint_t      unicode,
+			    void               *user_data)
+
+{
+  return u_getCombiningClass (unicode);
+}
+
+static unsigned int
+hb_icu_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
+			    hb_codepoint_t      unicode,
+			    void               *user_data)
+{
+  switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
+  {
+  case U_EA_WIDE:
+  case U_EA_FULLWIDTH:
+    return 2;
+  case U_EA_NEUTRAL:
+  case U_EA_AMBIGUOUS:
+  case U_EA_HALFWIDTH:
+  case U_EA_NARROW:
+    return 1;
+  }
+  return 1;
+}
+
+static hb_unicode_general_category_t
+hb_icu_get_general_category (hb_unicode_funcs_t *ufuncs,
+			     hb_codepoint_t      unicode,
+			     void               *user_data)
+{
+  switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
+  {
+  case U_UNASSIGNED:			return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+
+  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
+  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
+  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
+  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
+  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
+
+  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
+  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_COMBINING_MARK;
+
+  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
+  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
+  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
+
+  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
+  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
+  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
+
+  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
+  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
+  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
+  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
+
+
+  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
+  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
+  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
+  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
+  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
+
+  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
+  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
+  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
+  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
+
+  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
+  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
+  }
+
+  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+}
+
+static hb_codepoint_t
+hb_icu_get_mirroring (hb_unicode_funcs_t *ufuncs,
+		      hb_codepoint_t      unicode,
+		      void               *user_data)
+{
+  return u_charMirror(unicode);
+}
+
+static hb_script_t
+hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
+		   hb_codepoint_t      unicode,
+		   void               *user_data)
+{
+  UErrorCode status = U_ZERO_ERROR;
+  UScriptCode scriptCode = uscript_getScript(unicode, &status);
+
+  return hb_icu_script_to_script (scriptCode);
 }
 
 static hb_unicode_funcs_t icu_ufuncs = {
diff --git a/src/hb-icu.h b/src/hb-icu.h
index cc17af8..2e7f146 100644
--- a/src/hb-icu.h
+++ b/src/hb-icu.h
@@ -28,10 +28,19 @@
 #define HB_ICU_H
 
 #include "hb.h"
+#include <unicode/uscript.h>
+
 
 HB_BEGIN_DECLS
 
 
+hb_script_t
+hb_icu_script_to_script (UScriptCode script);
+
+UScriptCode
+hb_icu_script_from_script (hb_script_t script);
+
+
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void);
 
diff --git a/test/test-types.c b/test/test-types.c
index 5d7043e..daf2754 100644
--- a/test/test-types.c
+++ b/test/test-types.c
@@ -91,8 +91,8 @@ test_types_tag (void)
   g_assert_cmphex (hb_tag_from_string ("aBc"),   ==, 0x61426320);
   g_assert_cmphex (hb_tag_from_string ("aB"),    ==, 0x61422020);
   g_assert_cmphex (hb_tag_from_string ("a"),     ==, 0x61202020);
-  g_assert_cmphex (hb_tag_from_string (""),      ==, 0x20202020);
 
+  g_assert_cmphex (hb_tag_from_string (""),      ==, HB_TAG_NONE);
   g_assert_cmphex (hb_tag_from_string (NULL),    ==, HB_TAG_NONE);
 }
 
commit 0809aadd4bbd5d0f256407def7cc10b79772a824
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 02:44:29 2011 -0400

    [glib] Add two-way script conversion functions
    
    Also optimizes the common-direction script lookup to be an array lookup.

diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index a87031b..158a210 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -34,6 +34,145 @@
 
 HB_BEGIN_DECLS
 
+static const hb_script_t
+glib_script_to_script[] =
+{
+  HB_SCRIPT_COMMON,
+  HB_SCRIPT_INHERITED,
+  HB_SCRIPT_ARABIC,
+  HB_SCRIPT_ARMENIAN,
+  HB_SCRIPT_BENGALI,
+  HB_SCRIPT_BOPOMOFO,
+  HB_SCRIPT_CHEROKEE,
+  HB_SCRIPT_COPTIC,
+  HB_SCRIPT_CYRILLIC,
+  HB_SCRIPT_DESERET,
+  HB_SCRIPT_DEVANAGARI,
+  HB_SCRIPT_ETHIOPIC,
+  HB_SCRIPT_GEORGIAN,
+  HB_SCRIPT_GOTHIC,
+  HB_SCRIPT_GREEK,
+  HB_SCRIPT_GUJARATI,
+  HB_SCRIPT_GURMUKHI,
+  HB_SCRIPT_HAN,
+  HB_SCRIPT_HANGUL,
+  HB_SCRIPT_HEBREW,
+  HB_SCRIPT_HIRAGANA,
+  HB_SCRIPT_KANNADA,
+  HB_SCRIPT_KATAKANA,
+  HB_SCRIPT_KHMER,
+  HB_SCRIPT_LAO,
+  HB_SCRIPT_LATIN,
+  HB_SCRIPT_MALAYALAM,
+  HB_SCRIPT_MONGOLIAN,
+  HB_SCRIPT_MYANMAR,
+  HB_SCRIPT_OGHAM,
+  HB_SCRIPT_OLD_ITALIC,
+  HB_SCRIPT_ORIYA,
+  HB_SCRIPT_RUNIC,
+  HB_SCRIPT_SINHALA,
+  HB_SCRIPT_SYRIAC,
+  HB_SCRIPT_TAMIL,
+  HB_SCRIPT_TELUGU,
+  HB_SCRIPT_THAANA,
+  HB_SCRIPT_THAI,
+  HB_SCRIPT_TIBETAN,
+  HB_SCRIPT_CANADIAN_ABORIGINAL,
+  HB_SCRIPT_YI,
+  HB_SCRIPT_TAGALOG,
+  HB_SCRIPT_HANUNOO,
+  HB_SCRIPT_BUHID,
+  HB_SCRIPT_TAGBANWA,
+
+  /* Unicode-4.0 additions */
+  HB_SCRIPT_BRAILLE,
+  HB_SCRIPT_CYPRIOT,
+  HB_SCRIPT_LIMBU,
+  HB_SCRIPT_OSMANYA,
+  HB_SCRIPT_SHAVIAN,
+  HB_SCRIPT_LINEAR_B,
+  HB_SCRIPT_TAI_LE,
+  HB_SCRIPT_UGARITIC,
+
+  /* Unicode-4.1 additions */
+  HB_SCRIPT_NEW_TAI_LUE,
+  HB_SCRIPT_BUGINESE,
+  HB_SCRIPT_GLAGOLITIC,
+  HB_SCRIPT_TIFINAGH,
+  HB_SCRIPT_SYLOTI_NAGRI,
+  HB_SCRIPT_OLD_PERSIAN,
+  HB_SCRIPT_KHAROSHTHI,
+
+  /* Unicode-5.0 additions */
+  HB_SCRIPT_UNKNOWN,
+  HB_SCRIPT_BALINESE,
+  HB_SCRIPT_CUNEIFORM,
+  HB_SCRIPT_PHOENICIAN,
+  HB_SCRIPT_PHAGS_PA,
+  HB_SCRIPT_NKO,
+
+  /* Unicode-5.1 additions */
+  HB_SCRIPT_KAYAH_LI,
+  HB_SCRIPT_LEPCHA,
+  HB_SCRIPT_REJANG,
+  HB_SCRIPT_SUNDANESE,
+  HB_SCRIPT_SAURASHTRA,
+  HB_SCRIPT_CHAM,
+  HB_SCRIPT_OL_CHIKI,
+  HB_SCRIPT_VAI,
+  HB_SCRIPT_CARIAN,
+  HB_SCRIPT_LYCIAN,
+  HB_SCRIPT_LYDIAN,
+
+  /* Unicode-5.2 additions */
+  HB_SCRIPT_AVESTAN,
+  HB_SCRIPT_BAMUM,
+  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
+  HB_SCRIPT_IMPERIAL_ARAMAIC,
+  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
+  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
+  HB_SCRIPT_JAVANESE,
+  HB_SCRIPT_KAITHI,
+  HB_SCRIPT_TAI_THAM,
+  HB_SCRIPT_LISU,
+  HB_SCRIPT_MEETEI_MAYEK,
+  HB_SCRIPT_OLD_SOUTH_ARABIAN,
+  HB_SCRIPT_OLD_TURKIC,
+  HB_SCRIPT_SAMARITAN,
+  HB_SCRIPT_TAI_VIET,
+
+  /* Unicode-6.0 additions */
+  HB_SCRIPT_BATAK,
+  HB_SCRIPT_BRAHMI,
+  HB_SCRIPT_MANDAIC
+};
+
+hb_script_t
+hb_glib_script_to_script (GUnicodeScript script)
+{
+  if (likely ((unsigned int) script < ARRAY_LENGTH (glib_script_to_script)))
+    return glib_script_to_script[script];
+
+  if (unlikely (script == G_UNICODE_SCRIPT_INVALID_CODE))
+    return HB_SCRIPT_INVALID;
+
+  return HB_SCRIPT_UNKNOWN;
+}
+
+GUnicodeScript
+hb_glib_script_from_script (hb_script_t script)
+{
+  unsigned int count = ARRAY_LENGTH (glib_script_to_script);
+  for (unsigned int i = 0; i < count; i++)
+    if (glib_script_to_script[i] == script)
+      return (GUnicodeScript) i;
+
+  if (unlikely (script == HB_SCRIPT_INVALID))
+    return G_UNICODE_SCRIPT_INVALID_CODE;
+
+  return G_UNICODE_SCRIPT_UNKNOWN;
+}
+
 
 static unsigned int
 hb_glib_get_combining_class (hb_unicode_funcs_t *ufuncs,
@@ -76,136 +215,7 @@ hb_glib_get_script (hb_unicode_funcs_t *ufuncs,
                     hb_codepoint_t      unicode,
                     void               *user_data)
 {
-  GUnicodeScript script = g_unichar_get_script (unicode);
-  switch (script)
-  {
-#define MATCH_SCRIPT(C) case G_UNICODE_SCRIPT_##C: return HB_SCRIPT_##C
-#define MATCH_SCRIPT2(C1, C2) case G_UNICODE_SCRIPT_##C1: return HB_SCRIPT_##C2
-
-  MATCH_SCRIPT2(INVALID_CODE, INVALID);
-
-  MATCH_SCRIPT (COMMON);
-  MATCH_SCRIPT (INHERITED);
-  MATCH_SCRIPT (ARABIC);
-  MATCH_SCRIPT (ARMENIAN);
-  MATCH_SCRIPT (BENGALI);
-  MATCH_SCRIPT (BOPOMOFO);
-  MATCH_SCRIPT (CHEROKEE);
-  MATCH_SCRIPT (COPTIC);
-  MATCH_SCRIPT (CYRILLIC);
-  MATCH_SCRIPT (DESERET);
-  MATCH_SCRIPT (DEVANAGARI);
-  MATCH_SCRIPT (ETHIOPIC);
-  MATCH_SCRIPT (GEORGIAN);
-  MATCH_SCRIPT (GOTHIC);
-  MATCH_SCRIPT (GREEK);
-  MATCH_SCRIPT (GUJARATI);
-  MATCH_SCRIPT (GURMUKHI);
-  MATCH_SCRIPT (HAN);
-  MATCH_SCRIPT (HANGUL);
-  MATCH_SCRIPT (HEBREW);
-  MATCH_SCRIPT (HIRAGANA);
-  MATCH_SCRIPT (KANNADA);
-  MATCH_SCRIPT (KATAKANA);
-  MATCH_SCRIPT (KHMER);
-  MATCH_SCRIPT (LAO);
-  MATCH_SCRIPT (LATIN);
-  MATCH_SCRIPT (MALAYALAM);
-  MATCH_SCRIPT (MONGOLIAN);
-  MATCH_SCRIPT (MYANMAR);
-  MATCH_SCRIPT (OGHAM);
-  MATCH_SCRIPT (OLD_ITALIC);
-  MATCH_SCRIPT (ORIYA);
-  MATCH_SCRIPT (RUNIC);
-  MATCH_SCRIPT (SINHALA);
-  MATCH_SCRIPT (SYRIAC);
-  MATCH_SCRIPT (TAMIL);
-  MATCH_SCRIPT (TELUGU);
-  MATCH_SCRIPT (THAANA);
-  MATCH_SCRIPT (THAI);
-  MATCH_SCRIPT (TIBETAN);
-  MATCH_SCRIPT (CANADIAN_ABORIGINAL);
-  MATCH_SCRIPT (YI);
-  MATCH_SCRIPT (TAGALOG);
-  MATCH_SCRIPT (HANUNOO);
-  MATCH_SCRIPT (BUHID);
-  MATCH_SCRIPT (TAGBANWA);
-
-  /* Unicode-4.0 additions */
-  MATCH_SCRIPT (BRAILLE);
-  MATCH_SCRIPT (CYPRIOT);
-  MATCH_SCRIPT (LIMBU);
-  MATCH_SCRIPT (OSMANYA);
-  MATCH_SCRIPT (SHAVIAN);
-  MATCH_SCRIPT (LINEAR_B);
-  MATCH_SCRIPT (TAI_LE);
-  MATCH_SCRIPT (UGARITIC);
-
-  /* Unicode-4.1 additions */
-  MATCH_SCRIPT (NEW_TAI_LUE);
-  MATCH_SCRIPT (BUGINESE);
-  MATCH_SCRIPT (GLAGOLITIC);
-  MATCH_SCRIPT (TIFINAGH);
-  MATCH_SCRIPT (SYLOTI_NAGRI);
-  MATCH_SCRIPT (OLD_PERSIAN);
-  MATCH_SCRIPT (KHAROSHTHI);
-
-  /* Unicode-5.0 additions */
-  MATCH_SCRIPT (UNKNOWN);
-  MATCH_SCRIPT (BALINESE);
-  MATCH_SCRIPT (CUNEIFORM);
-  MATCH_SCRIPT (PHOENICIAN);
-  MATCH_SCRIPT (PHAGS_PA);
-  MATCH_SCRIPT (NKO);
-
-  /* Unicode-5.1 additions */
-  MATCH_SCRIPT (KAYAH_LI);
-  MATCH_SCRIPT (LEPCHA);
-  MATCH_SCRIPT (REJANG);
-  MATCH_SCRIPT (SUNDANESE);
-  MATCH_SCRIPT (SAURASHTRA);
-  MATCH_SCRIPT (CHAM);
-  MATCH_SCRIPT (OL_CHIKI);
-  MATCH_SCRIPT (VAI);
-  MATCH_SCRIPT (CARIAN);
-  MATCH_SCRIPT (LYCIAN);
-  MATCH_SCRIPT (LYDIAN);
-
-  /* Unicode-5.2 additions */
-#if GLIB_CHECK_VERSION(2,26,0)
-  MATCH_SCRIPT (AVESTAN);
-  MATCH_SCRIPT (BAMUM);
-  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);
-  MATCH_SCRIPT (IMPERIAL_ARAMAIC);
-  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);
-  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN);
-  MATCH_SCRIPT (JAVANESE);
-  MATCH_SCRIPT (KAITHI);
-  MATCH_SCRIPT (TAI_THAM);
-  MATCH_SCRIPT (LISU);
-  MATCH_SCRIPT (MEETEI_MAYEK);
-  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);
-#if GLIB_CHECK_VERSION(2,27,92)
-  MATCH_SCRIPT (OLD_TURKIC);
-#else
-  MATCH_SCRIPT2(OLD_TURKISH, OLD_TURKIC);
-#endif
-  MATCH_SCRIPT (SAMARITAN);
-  MATCH_SCRIPT (TAI_VIET);
-#endif
-
-  /* Unicode-6.0 additions */
-#if GLIB_CHECK_VERSION(2,28,0)
-  MATCH_SCRIPT (BATAK);
-  MATCH_SCRIPT (BRAHMI);
-  MATCH_SCRIPT (MANDAIC);
-#endif
-
-#undef MATCH_SCRIPT
-#undef MATCH_SCRIPT2
-  }
-
-  return HB_SCRIPT_UNKNOWN;
+  return hb_glib_script_to_script (g_unichar_get_script (unicode));
 }
 
 static hb_unicode_funcs_t glib_ufuncs = {
diff --git a/src/hb-glib.h b/src/hb-glib.h
index 81ab15d..abec2d2 100644
--- a/src/hb-glib.h
+++ b/src/hb-glib.h
@@ -28,10 +28,18 @@
 #define HB_GLIB_H
 
 #include "hb.h"
+#include <glib.h>
 
 HB_BEGIN_DECLS
 
 
+hb_script_t
+hb_glib_script_to_script (GUnicodeScript script);
+
+GUnicodeScript
+hb_glib_script_from_script (hb_script_t script);
+
+
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void);
 
commit 5c8c1b680c4fa23c8574b9aebd21113e276f57a3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 02:29:22 2011 -0400

    Remove verbose comments

diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 5bebf5e..a87031b 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -84,121 +84,121 @@ hb_glib_get_script (hb_unicode_funcs_t *ufuncs,
 
   MATCH_SCRIPT2(INVALID_CODE, INVALID);
 
-  MATCH_SCRIPT (COMMON);             /* Zyyy */
-  MATCH_SCRIPT (INHERITED);          /* Qaai */
-  MATCH_SCRIPT (ARABIC);             /* Arab */
-  MATCH_SCRIPT (ARMENIAN);           /* Armn */
-  MATCH_SCRIPT (BENGALI);            /* Beng */
-  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
-  MATCH_SCRIPT (CHEROKEE);           /* Cher */
-  MATCH_SCRIPT (COPTIC);             /* Qaac */
-  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
-  MATCH_SCRIPT (DESERET);            /* Dsrt */
-  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
-  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
-  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
-  MATCH_SCRIPT (GOTHIC);             /* Goth */
-  MATCH_SCRIPT (GREEK);              /* Grek */
-  MATCH_SCRIPT (GUJARATI);           /* Gujr */
-  MATCH_SCRIPT (GURMUKHI);           /* Guru */
-  MATCH_SCRIPT (HAN);                /* Hani */
-  MATCH_SCRIPT (HANGUL);             /* Hang */
-  MATCH_SCRIPT (HEBREW);             /* Hebr */
-  MATCH_SCRIPT (HIRAGANA);           /* Hira */
-  MATCH_SCRIPT (KANNADA);            /* Knda */
-  MATCH_SCRIPT (KATAKANA);           /* Kana */
-  MATCH_SCRIPT (KHMER);              /* Khmr */
-  MATCH_SCRIPT (LAO);                /* Laoo */
-  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
-  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
-  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
-  MATCH_SCRIPT (MYANMAR);            /* Mymr */
-  MATCH_SCRIPT (OGHAM);              /* Ogam */
-  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
-  MATCH_SCRIPT (ORIYA);              /* Orya */
-  MATCH_SCRIPT (RUNIC);              /* Runr */
-  MATCH_SCRIPT (SINHALA);            /* Sinh */
-  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
-  MATCH_SCRIPT (TAMIL);              /* Taml */
-  MATCH_SCRIPT (TELUGU);             /* Telu */
-  MATCH_SCRIPT (THAANA);             /* Thaa */
-  MATCH_SCRIPT (THAI);               /* Thai */
-  MATCH_SCRIPT (TIBETAN);            /* Tibt */
-  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
-  MATCH_SCRIPT (YI);                 /* Yiii */
-  MATCH_SCRIPT (TAGALOG);            /* Tglg */
-  MATCH_SCRIPT (HANUNOO);            /* Hano */
-  MATCH_SCRIPT (BUHID);              /* Buhd */
-  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
+  MATCH_SCRIPT (COMMON);
+  MATCH_SCRIPT (INHERITED);
+  MATCH_SCRIPT (ARABIC);
+  MATCH_SCRIPT (ARMENIAN);
+  MATCH_SCRIPT (BENGALI);
+  MATCH_SCRIPT (BOPOMOFO);
+  MATCH_SCRIPT (CHEROKEE);
+  MATCH_SCRIPT (COPTIC);
+  MATCH_SCRIPT (CYRILLIC);
+  MATCH_SCRIPT (DESERET);
+  MATCH_SCRIPT (DEVANAGARI);
+  MATCH_SCRIPT (ETHIOPIC);
+  MATCH_SCRIPT (GEORGIAN);
+  MATCH_SCRIPT (GOTHIC);
+  MATCH_SCRIPT (GREEK);
+  MATCH_SCRIPT (GUJARATI);
+  MATCH_SCRIPT (GURMUKHI);
+  MATCH_SCRIPT (HAN);
+  MATCH_SCRIPT (HANGUL);
+  MATCH_SCRIPT (HEBREW);
+  MATCH_SCRIPT (HIRAGANA);
+  MATCH_SCRIPT (KANNADA);
+  MATCH_SCRIPT (KATAKANA);
+  MATCH_SCRIPT (KHMER);
+  MATCH_SCRIPT (LAO);
+  MATCH_SCRIPT (LATIN);
+  MATCH_SCRIPT (MALAYALAM);
+  MATCH_SCRIPT (MONGOLIAN);
+  MATCH_SCRIPT (MYANMAR);
+  MATCH_SCRIPT (OGHAM);
+  MATCH_SCRIPT (OLD_ITALIC);
+  MATCH_SCRIPT (ORIYA);
+  MATCH_SCRIPT (RUNIC);
+  MATCH_SCRIPT (SINHALA);
+  MATCH_SCRIPT (SYRIAC);
+  MATCH_SCRIPT (TAMIL);
+  MATCH_SCRIPT (TELUGU);
+  MATCH_SCRIPT (THAANA);
+  MATCH_SCRIPT (THAI);
+  MATCH_SCRIPT (TIBETAN);
+  MATCH_SCRIPT (CANADIAN_ABORIGINAL);
+  MATCH_SCRIPT (YI);
+  MATCH_SCRIPT (TAGALOG);
+  MATCH_SCRIPT (HANUNOO);
+  MATCH_SCRIPT (BUHID);
+  MATCH_SCRIPT (TAGBANWA);
 
   /* Unicode-4.0 additions */
-  MATCH_SCRIPT (BRAILLE);            /* Brai */
-  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
-  MATCH_SCRIPT (LIMBU);              /* Limb */
-  MATCH_SCRIPT (OSMANYA);            /* Osma */
-  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
-  MATCH_SCRIPT (LINEAR_B);           /* Linb */
-  MATCH_SCRIPT (TAI_LE);             /* Tale */
-  MATCH_SCRIPT (UGARITIC);           /* Ugar */
+  MATCH_SCRIPT (BRAILLE);
+  MATCH_SCRIPT (CYPRIOT);
+  MATCH_SCRIPT (LIMBU);
+  MATCH_SCRIPT (OSMANYA);
+  MATCH_SCRIPT (SHAVIAN);
+  MATCH_SCRIPT (LINEAR_B);
+  MATCH_SCRIPT (TAI_LE);
+  MATCH_SCRIPT (UGARITIC);
 
   /* Unicode-4.1 additions */
-  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
-  MATCH_SCRIPT (BUGINESE);           /* Bugi */
-  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
-  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
-  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
-  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
-  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
+  MATCH_SCRIPT (NEW_TAI_LUE);
+  MATCH_SCRIPT (BUGINESE);
+  MATCH_SCRIPT (GLAGOLITIC);
+  MATCH_SCRIPT (TIFINAGH);
+  MATCH_SCRIPT (SYLOTI_NAGRI);
+  MATCH_SCRIPT (OLD_PERSIAN);
+  MATCH_SCRIPT (KHAROSHTHI);
 
   /* Unicode-5.0 additions */
-  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
-  MATCH_SCRIPT (BALINESE);           /* Bali */
-  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
-  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
-  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
-  MATCH_SCRIPT (NKO);                /* Nkoo */
+  MATCH_SCRIPT (UNKNOWN);
+  MATCH_SCRIPT (BALINESE);
+  MATCH_SCRIPT (CUNEIFORM);
+  MATCH_SCRIPT (PHOENICIAN);
+  MATCH_SCRIPT (PHAGS_PA);
+  MATCH_SCRIPT (NKO);
 
   /* Unicode-5.1 additions */
-  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
-  MATCH_SCRIPT (LEPCHA);             /* Lepc */
-  MATCH_SCRIPT (REJANG);             /* Rjng */
-  MATCH_SCRIPT (SUNDANESE);          /* Sund */
-  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
-  MATCH_SCRIPT (CHAM);               /* Cham */
-  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
-  MATCH_SCRIPT (VAI);                /* Vaii */
-  MATCH_SCRIPT (CARIAN);             /* Cari */
-  MATCH_SCRIPT (LYCIAN);             /* Lyci */
-  MATCH_SCRIPT (LYDIAN);             /* Lydi */
+  MATCH_SCRIPT (KAYAH_LI);
+  MATCH_SCRIPT (LEPCHA);
+  MATCH_SCRIPT (REJANG);
+  MATCH_SCRIPT (SUNDANESE);
+  MATCH_SCRIPT (SAURASHTRA);
+  MATCH_SCRIPT (CHAM);
+  MATCH_SCRIPT (OL_CHIKI);
+  MATCH_SCRIPT (VAI);
+  MATCH_SCRIPT (CARIAN);
+  MATCH_SCRIPT (LYCIAN);
+  MATCH_SCRIPT (LYDIAN);
 
   /* Unicode-5.2 additions */
 #if GLIB_CHECK_VERSION(2,26,0)
-  MATCH_SCRIPT (AVESTAN);                /* Avst */
-  MATCH_SCRIPT (BAMUM);                  /* Bamu */
-  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
-  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
-  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
-  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
-  MATCH_SCRIPT (JAVANESE);               /* Java */
-  MATCH_SCRIPT (KAITHI);                 /* Kthi */
-  MATCH_SCRIPT (TAI_THAM);               /* Lana */
-  MATCH_SCRIPT (LISU);                   /* Lisu */
-  MATCH_SCRIPT (MEETEI_MAYEK);           /* Mtei */
-  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
+  MATCH_SCRIPT (AVESTAN);
+  MATCH_SCRIPT (BAMUM);
+  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);
+  MATCH_SCRIPT (IMPERIAL_ARAMAIC);
+  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);
+  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN);
+  MATCH_SCRIPT (JAVANESE);
+  MATCH_SCRIPT (KAITHI);
+  MATCH_SCRIPT (TAI_THAM);
+  MATCH_SCRIPT (LISU);
+  MATCH_SCRIPT (MEETEI_MAYEK);
+  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);
 #if GLIB_CHECK_VERSION(2,27,92)
-  MATCH_SCRIPT (OLD_TURKIC);             /* Orkh */
+  MATCH_SCRIPT (OLD_TURKIC);
 #else
-  MATCH_SCRIPT2(OLD_TURKISH, OLD_TURKIC);/* Orkh */
+  MATCH_SCRIPT2(OLD_TURKISH, OLD_TURKIC);
 #endif
-  MATCH_SCRIPT (SAMARITAN);              /* Samr */
-  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
+  MATCH_SCRIPT (SAMARITAN);
+  MATCH_SCRIPT (TAI_VIET);
 #endif
 
   /* Unicode-6.0 additions */
 #if GLIB_CHECK_VERSION(2,28,0)
-  MATCH_SCRIPT (BATAK);                  /* Batk */
-  MATCH_SCRIPT (BRAHMI);                 /* Brah */
-  MATCH_SCRIPT (MANDAIC);                /* Mand */
+  MATCH_SCRIPT (BATAK);
+  MATCH_SCRIPT (BRAHMI);
+  MATCH_SCRIPT (MANDAIC);
 #endif
 
 #undef MATCH_SCRIPT
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 4978bf5..dcfbade 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -75,43 +75,43 @@ hb_icu_get_general_category (hb_unicode_funcs_t *ufuncs,
   {
   case U_UNASSIGNED:			return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
 
-  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;	/* Lu */
-  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;	/* Ll */
-  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;	/* Lt */
-  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;	/* Lm */
-  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;	/* Lo */
-
-  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;	/* Mn */
-  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;	/* Me */
-  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_COMBINING_MARK;	/* Mc */
-
-  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;	/* Nd */
-  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;	/* Nl */
-  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;	/* No */
-
-  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;	/* Zs */
-  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;	/* Zl */
-  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;	/* Zp */
-
-  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;		/* Cc */
-  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;		/* Cf */
-  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;		/* Co */
-  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;		/* Cs */
-
-
-  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;	/* Pd */
-  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;	/* Ps */
-  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;	/* Pe */
-  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;	/* Pc */
-  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;	/* Po */
-
-  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;		/* Sm */
-  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;	/* Sc */
-  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;	/* Sk */
-  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;	/* So */
-
-  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;	/* Pi */
-  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;	/* Pf */
+  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
+  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
+  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
+  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
+  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
+
+  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
+  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_COMBINING_MARK;
+
+  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
+  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
+  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
+
+  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
+  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
+  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
+
+  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
+  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
+  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
+  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
+
+
+  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
+  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
+  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
+  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
+  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
+
+  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
+  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
+  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
+  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
+
+  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
+  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
   }
 
   return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
@@ -139,120 +139,120 @@ hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
 #define MATCH_SCRIPT(C) case USCRIPT_##C: return HB_SCRIPT_##C
 #define MATCH_SCRIPT2(C1, C2) case USCRIPT_##C1: return HB_SCRIPT_##C2
 
-  MATCH_SCRIPT (COMMON);             /* Zyyy */
-  MATCH_SCRIPT (INHERITED);          /* Qaai */
-  MATCH_SCRIPT (ARABIC);             /* Arab */
-  MATCH_SCRIPT (ARMENIAN);           /* Armn */
-  MATCH_SCRIPT (BENGALI);            /* Beng */
-  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
-  MATCH_SCRIPT (CHEROKEE);           /* Cher */
-  MATCH_SCRIPT (COPTIC);             /* Qaac */
-  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
-  MATCH_SCRIPT (DESERET);            /* Dsrt */
-  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
-  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
-  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
-  MATCH_SCRIPT (GOTHIC);             /* Goth */
-  MATCH_SCRIPT (GREEK);              /* Grek */
-  MATCH_SCRIPT (GUJARATI);           /* Gujr */
-  MATCH_SCRIPT (GURMUKHI);           /* Guru */
-  MATCH_SCRIPT (HAN);                /* Hani */
-  MATCH_SCRIPT (HANGUL);             /* Hang */
-  MATCH_SCRIPT (HEBREW);             /* Hebr */
-  MATCH_SCRIPT (HIRAGANA);           /* Hira */
-  MATCH_SCRIPT (KANNADA);            /* Knda */
-  MATCH_SCRIPT (KATAKANA);           /* Kana */
-  MATCH_SCRIPT (KHMER);              /* Khmr */
-  MATCH_SCRIPT (LAO);                /* Laoo */
-  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
-  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
-  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
-  MATCH_SCRIPT (MYANMAR);            /* Mymr */
-  MATCH_SCRIPT (OGHAM);              /* Ogam */
-  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
-  MATCH_SCRIPT (ORIYA);              /* Orya */
-  MATCH_SCRIPT (RUNIC);              /* Runr */
-  MATCH_SCRIPT (SINHALA);            /* Sinh */
-  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
-  MATCH_SCRIPT (TAMIL);              /* Taml */
-  MATCH_SCRIPT (TELUGU);             /* Telu */
-  MATCH_SCRIPT (THAANA);             /* Thaa */
-  MATCH_SCRIPT (THAI);               /* Thai */
-  MATCH_SCRIPT (TIBETAN);            /* Tibt */
-  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
-  MATCH_SCRIPT (YI);                 /* Yiii */
-  MATCH_SCRIPT (TAGALOG);            /* Tglg */
-  MATCH_SCRIPT (HANUNOO);            /* Hano */
-  MATCH_SCRIPT (BUHID);              /* Buhd */
-  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
+  MATCH_SCRIPT (COMMON);
+  MATCH_SCRIPT (INHERITED);
+  MATCH_SCRIPT (ARABIC);
+  MATCH_SCRIPT (ARMENIAN);
+  MATCH_SCRIPT (BENGALI);
+  MATCH_SCRIPT (BOPOMOFO);
+  MATCH_SCRIPT (CHEROKEE);
+  MATCH_SCRIPT (COPTIC);
+  MATCH_SCRIPT (CYRILLIC);
+  MATCH_SCRIPT (DESERET);
+  MATCH_SCRIPT (DEVANAGARI);
+  MATCH_SCRIPT (ETHIOPIC);
+  MATCH_SCRIPT (GEORGIAN);
+  MATCH_SCRIPT (GOTHIC);
+  MATCH_SCRIPT (GREEK);
+  MATCH_SCRIPT (GUJARATI);
+  MATCH_SCRIPT (GURMUKHI);
+  MATCH_SCRIPT (HAN);
+  MATCH_SCRIPT (HANGUL);
+  MATCH_SCRIPT (HEBREW);
+  MATCH_SCRIPT (HIRAGANA);
+  MATCH_SCRIPT (KANNADA);
+  MATCH_SCRIPT (KATAKANA);
+  MATCH_SCRIPT (KHMER);
+  MATCH_SCRIPT (LAO);
+  MATCH_SCRIPT (LATIN);
+  MATCH_SCRIPT (MALAYALAM);
+  MATCH_SCRIPT (MONGOLIAN);
+  MATCH_SCRIPT (MYANMAR);
+  MATCH_SCRIPT (OGHAM);
+  MATCH_SCRIPT (OLD_ITALIC);
+  MATCH_SCRIPT (ORIYA);
+  MATCH_SCRIPT (RUNIC);
+  MATCH_SCRIPT (SINHALA);
+  MATCH_SCRIPT (SYRIAC);
+  MATCH_SCRIPT (TAMIL);
+  MATCH_SCRIPT (TELUGU);
+  MATCH_SCRIPT (THAANA);
+  MATCH_SCRIPT (THAI);
+  MATCH_SCRIPT (TIBETAN);
+  MATCH_SCRIPT (CANADIAN_ABORIGINAL);
+  MATCH_SCRIPT (YI);
+  MATCH_SCRIPT (TAGALOG);
+  MATCH_SCRIPT (HANUNOO);
+  MATCH_SCRIPT (BUHID);
+  MATCH_SCRIPT (TAGBANWA);
 
   /* Unicode-4.0 additions */
-  MATCH_SCRIPT (BRAILLE);            /* Brai */
-  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
-  MATCH_SCRIPT (LIMBU);              /* Limb */
-  MATCH_SCRIPT (OSMANYA);            /* Osma */
-  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
-  MATCH_SCRIPT (LINEAR_B);           /* Linb */
-  MATCH_SCRIPT (TAI_LE);             /* Tale */
-  MATCH_SCRIPT (UGARITIC);           /* Ugar */
+  MATCH_SCRIPT (BRAILLE);
+  MATCH_SCRIPT (CYPRIOT);
+  MATCH_SCRIPT (LIMBU);
+  MATCH_SCRIPT (OSMANYA);
+  MATCH_SCRIPT (SHAVIAN);
+  MATCH_SCRIPT (LINEAR_B);
+  MATCH_SCRIPT (TAI_LE);
+  MATCH_SCRIPT (UGARITIC);
 
   /* Unicode-4.1 additions */
-  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
-  MATCH_SCRIPT (BUGINESE);           /* Bugi */
-  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
-  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
-  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
-  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
-  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
+  MATCH_SCRIPT (NEW_TAI_LUE);
+  MATCH_SCRIPT (BUGINESE);
+  MATCH_SCRIPT (GLAGOLITIC);
+  MATCH_SCRIPT (TIFINAGH);
+  MATCH_SCRIPT (SYLOTI_NAGRI);
+  MATCH_SCRIPT (OLD_PERSIAN);
+  MATCH_SCRIPT (KHAROSHTHI);
 
   /* Unicode-5.0 additions */
-  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
-  MATCH_SCRIPT (BALINESE);           /* Bali */
-  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
-  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
-  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
-  MATCH_SCRIPT (NKO);                /* Nkoo */
+  MATCH_SCRIPT (UNKNOWN);
+  MATCH_SCRIPT (BALINESE);
+  MATCH_SCRIPT (CUNEIFORM);
+  MATCH_SCRIPT (PHOENICIAN);
+  MATCH_SCRIPT (PHAGS_PA);
+  MATCH_SCRIPT (NKO);
 
   /* Unicode-5.1 additions */
-  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
-  MATCH_SCRIPT (LEPCHA);             /* Lepc */
-  MATCH_SCRIPT (REJANG);             /* Rjng */
-  MATCH_SCRIPT (SUNDANESE);          /* Sund */
-  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
-  MATCH_SCRIPT (CHAM);               /* Cham */
-  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
-  MATCH_SCRIPT (VAI);                /* Vaii */
-  MATCH_SCRIPT (CARIAN);             /* Cari */
-  MATCH_SCRIPT (LYCIAN);             /* Lyci */
-  MATCH_SCRIPT (LYDIAN);             /* Lydi */
+  MATCH_SCRIPT (KAYAH_LI);
+  MATCH_SCRIPT (LEPCHA);
+  MATCH_SCRIPT (REJANG);
+  MATCH_SCRIPT (SUNDANESE);
+  MATCH_SCRIPT (SAURASHTRA);
+  MATCH_SCRIPT (CHAM);
+  MATCH_SCRIPT (OL_CHIKI);
+  MATCH_SCRIPT (VAI);
+  MATCH_SCRIPT (CARIAN);
+  MATCH_SCRIPT (LYCIAN);
+  MATCH_SCRIPT (LYDIAN);
 
   /* Unicode-5.2 additions */
-  MATCH_SCRIPT (AVESTAN);                /* Avst */
+  MATCH_SCRIPT (AVESTAN);
 #if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (BAMUM);                  /* Bamu */
+  MATCH_SCRIPT (BAMUM);
 #endif
-  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
-  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
-  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
-  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
-  MATCH_SCRIPT (JAVANESE);               /* Java */
-  MATCH_SCRIPT (KAITHI);                 /* Kthi */
-  MATCH_SCRIPT2(LANNA, TAI_THAM);        /* Lana */
+  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);
+  MATCH_SCRIPT (IMPERIAL_ARAMAIC);
+  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);
+  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN);
+  MATCH_SCRIPT (JAVANESE);
+  MATCH_SCRIPT (KAITHI);
+  MATCH_SCRIPT2(LANNA, TAI_THAM);
 #if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (LISU);                   /* Lisu */
+  MATCH_SCRIPT (LISU);
 #endif
-  MATCH_SCRIPT2(MEITEI_MAYEK, MEETEI_MAYEK);/* Mtei */
+  MATCH_SCRIPT2(MEITEI_MAYEK, MEETEI_MAYEK);
 #if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
+  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);
 #endif
-  MATCH_SCRIPT2(ORKHON, OLD_TURKIC);     /* Orkh */
-  MATCH_SCRIPT (SAMARITAN);              /* Samr */
-  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
+  MATCH_SCRIPT2(ORKHON, OLD_TURKIC);
+  MATCH_SCRIPT (SAMARITAN);
+  MATCH_SCRIPT (TAI_VIET);
 
   /* Unicode-6.0 additions */
-  MATCH_SCRIPT (BATAK);                  /* Batk */
-  MATCH_SCRIPT (BRAHMI);                 /* Brah */
-  MATCH_SCRIPT2(MANDAEAN, MANDAIC);      /* Mand */
+  MATCH_SCRIPT (BATAK);
+  MATCH_SCRIPT (BRAHMI);
+  MATCH_SCRIPT2(MANDAEAN, MANDAIC);
 
 #undef CHECK_ICU_VERSION
 #undef MATCH_SCRIPT
commit fb194b8794898f51eb596fa4092c26606889d376
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 02:00:47 2011 -0400

    unicode: Cleanup implementation

diff --git a/src/Makefile.am b/src/Makefile.am
index 2fbf278..70c51d1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,8 +24,8 @@ HBSOURCES =  \
 	hb-ot-head-private.hh \
 	hb-private.h \
 	hb-shape.cc \
-	hb-unicode.c \
-	hb-unicode-private.h \
+	hb-unicode.cc \
+	hb-unicode-private.hh \
 	$(NULL)
 HBHEADERS = \
 	hb.h \
@@ -65,7 +65,7 @@ if HAVE_GLIB
 HBCFLAGS += $(GLIB_CFLAGS)
 HBLIBS   += $(GLIB_LIBS)
 HBSOURCES += \
-	hb-glib.c \
+	hb-glib.cc \
 	$(NULL)
 HBHEADERS += \
 	hb-glib.h \
@@ -76,7 +76,7 @@ if HAVE_ICU
 HBCFLAGS += $(ICU_CFLAGS)
 HBLIBS   += $(ICU_LIBS)
 HBSOURCES += \
-	hb-icu.c \
+	hb-icu.cc \
 	$(NULL)
 HBHEADERS += \
 	hb-icu.h \
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index 2b063b7..dfcc45d 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -30,7 +30,7 @@
 
 #include "hb-private.h"
 #include "hb-buffer.h"
-#include "hb-unicode-private.h"
+#include "hb-unicode-private.hh"
 
 HB_BEGIN_DECLS
 
diff --git a/src/hb-glib.c b/src/hb-glib.c
deleted file mode 100644
index 1905637..0000000
--- a/src/hb-glib.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, 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.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-glib.h"
-
-#include "hb-unicode-private.h"
-
-#include <glib.h>
-
-HB_BEGIN_DECLS
-
-
-static hb_codepoint_t
-hb_glib_get_mirroring (hb_unicode_funcs_t *ufuncs,
-                       hb_codepoint_t      unicode,
-                       void               *user_data)
-{
-  g_unichar_get_mirror_char (unicode, &unicode);
-  return unicode;
-}
-
-static hb_unicode_general_category_t
-hb_glib_get_general_category (hb_unicode_funcs_t *ufuncs,
-                              hb_codepoint_t      unicode,
-                              void               *user_data)
-
-{
-  return g_unichar_type (unicode);
-}
-
-static hb_script_t
-hb_glib_get_script (hb_unicode_funcs_t *ufuncs,
-                    hb_codepoint_t      unicode,
-                    void               *user_data)
-{
-  GUnicodeScript script = g_unichar_get_script (unicode);
-  switch (script)
-  {
-#define MATCH_SCRIPT(C) case G_UNICODE_SCRIPT_##C: return HB_SCRIPT_##C
-#define MATCH_SCRIPT2(C1, C2) case G_UNICODE_SCRIPT_##C1: return HB_SCRIPT_##C2
-
-  MATCH_SCRIPT2(INVALID_CODE, INVALID);
-
-  MATCH_SCRIPT (COMMON);             /* Zyyy */
-  MATCH_SCRIPT (INHERITED);          /* Qaai */
-  MATCH_SCRIPT (ARABIC);             /* Arab */
-  MATCH_SCRIPT (ARMENIAN);           /* Armn */
-  MATCH_SCRIPT (BENGALI);            /* Beng */
-  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
-  MATCH_SCRIPT (CHEROKEE);           /* Cher */
-  MATCH_SCRIPT (COPTIC);             /* Qaac */
-  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
-  MATCH_SCRIPT (DESERET);            /* Dsrt */
-  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
-  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
-  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
-  MATCH_SCRIPT (GOTHIC);             /* Goth */
-  MATCH_SCRIPT (GREEK);              /* Grek */
-  MATCH_SCRIPT (GUJARATI);           /* Gujr */
-  MATCH_SCRIPT (GURMUKHI);           /* Guru */
-  MATCH_SCRIPT (HAN);                /* Hani */
-  MATCH_SCRIPT (HANGUL);             /* Hang */
-  MATCH_SCRIPT (HEBREW);             /* Hebr */
-  MATCH_SCRIPT (HIRAGANA);           /* Hira */
-  MATCH_SCRIPT (KANNADA);            /* Knda */
-  MATCH_SCRIPT (KATAKANA);           /* Kana */
-  MATCH_SCRIPT (KHMER);              /* Khmr */
-  MATCH_SCRIPT (LAO);                /* Laoo */
-  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
-  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
-  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
-  MATCH_SCRIPT (MYANMAR);            /* Mymr */
-  MATCH_SCRIPT (OGHAM);              /* Ogam */
-  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
-  MATCH_SCRIPT (ORIYA);              /* Orya */
-  MATCH_SCRIPT (RUNIC);              /* Runr */
-  MATCH_SCRIPT (SINHALA);            /* Sinh */
-  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
-  MATCH_SCRIPT (TAMIL);              /* Taml */
-  MATCH_SCRIPT (TELUGU);             /* Telu */
-  MATCH_SCRIPT (THAANA);             /* Thaa */
-  MATCH_SCRIPT (THAI);               /* Thai */
-  MATCH_SCRIPT (TIBETAN);            /* Tibt */
-  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
-  MATCH_SCRIPT (YI);                 /* Yiii */
-  MATCH_SCRIPT (TAGALOG);            /* Tglg */
-  MATCH_SCRIPT (HANUNOO);            /* Hano */
-  MATCH_SCRIPT (BUHID);              /* Buhd */
-  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
-
-  /* Unicode-4.0 additions */
-  MATCH_SCRIPT (BRAILLE);            /* Brai */
-  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
-  MATCH_SCRIPT (LIMBU);              /* Limb */
-  MATCH_SCRIPT (OSMANYA);            /* Osma */
-  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
-  MATCH_SCRIPT (LINEAR_B);           /* Linb */
-  MATCH_SCRIPT (TAI_LE);             /* Tale */
-  MATCH_SCRIPT (UGARITIC);           /* Ugar */
-
-  /* Unicode-4.1 additions */
-  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
-  MATCH_SCRIPT (BUGINESE);           /* Bugi */
-  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
-  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
-  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
-  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
-  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
-
-  /* Unicode-5.0 additions */
-  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
-  MATCH_SCRIPT (BALINESE);           /* Bali */
-  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
-  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
-  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
-  MATCH_SCRIPT (NKO);                /* Nkoo */
-
-  /* Unicode-5.1 additions */
-  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
-  MATCH_SCRIPT (LEPCHA);             /* Lepc */
-  MATCH_SCRIPT (REJANG);             /* Rjng */
-  MATCH_SCRIPT (SUNDANESE);          /* Sund */
-  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
-  MATCH_SCRIPT (CHAM);               /* Cham */
-  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
-  MATCH_SCRIPT (VAI);                /* Vaii */
-  MATCH_SCRIPT (CARIAN);             /* Cari */
-  MATCH_SCRIPT (LYCIAN);             /* Lyci */
-  MATCH_SCRIPT (LYDIAN);             /* Lydi */
-
-  /* Unicode-5.2 additions */
-#if GLIB_CHECK_VERSION(2,26,0)
-  MATCH_SCRIPT (AVESTAN);                /* Avst */
-  MATCH_SCRIPT (BAMUM);                  /* Bamu */
-  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
-  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
-  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
-  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
-  MATCH_SCRIPT (JAVANESE);               /* Java */
-  MATCH_SCRIPT (KAITHI);                 /* Kthi */
-  MATCH_SCRIPT (TAI_THAM);               /* Lana */
-  MATCH_SCRIPT (LISU);                   /* Lisu */
-  MATCH_SCRIPT (MEETEI_MAYEK);           /* Mtei */
-  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
-#if GLIB_CHECK_VERSION(2,28,0)
-  MATCH_SCRIPT (OLD_TURKIC);             /* Orkh */
-#else
-  MATCH_SCRIPT2(OLD_TURKISH, OLD_TURKIC);/* Orkh */
-#endif
-  MATCH_SCRIPT (SAMARITAN);              /* Samr */
-  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
-#endif
-
-  /* Unicode-6.0 additions */
-#if GLIB_CHECK_VERSION(2,28,0)
-  MATCH_SCRIPT (BATAK);                  /* Batk */
-  MATCH_SCRIPT (BRAHMI);                 /* Brah */
-  MATCH_SCRIPT (MANDAIC);                /* Mand */
-#endif
-
-#undef MATCH_SCRIPT
-#undef MATCH_SCRIPT2
-  }
-
-  return HB_SCRIPT_UNKNOWN;
-}
-
-static unsigned int
-hb_glib_get_combining_class (hb_unicode_funcs_t *ufuncs,
-                             hb_codepoint_t      unicode,
-                             void               *user_data)
-
-{
-  return g_unichar_combining_class (unicode);
-}
-
-static unsigned int
-hb_glib_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
-                             hb_codepoint_t      unicode,
-                             void               *user_data)
-{
-  return g_unichar_iswide (unicode) ? 2 : 1;
-}
-
-static hb_unicode_funcs_t glib_ufuncs = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  NULL,
-  TRUE, /* immutable */
-  {
-    hb_glib_get_general_category, NULL, NULL,
-    hb_glib_get_combining_class, NULL, NULL,
-    hb_glib_get_mirroring, NULL, NULL,
-    hb_glib_get_script, NULL, NULL,
-    hb_glib_get_eastasian_width, NULL, NULL
-  }
-};
-
-hb_unicode_funcs_t *
-hb_glib_get_unicode_funcs (void)
-{
-  return &glib_ufuncs;
-}
-
-
-HB_END_DECLS
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
new file mode 100644
index 0000000..5bebf5e
--- /dev/null
+++ b/src/hb-glib.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2009  Red Hat, 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.h"
+
+#include "hb-glib.h"
+
+#include "hb-unicode-private.hh"
+
+#include <glib.h>
+
+HB_BEGIN_DECLS
+
+
+static unsigned int
+hb_glib_get_combining_class (hb_unicode_funcs_t *ufuncs,
+                             hb_codepoint_t      unicode,
+                             void               *user_data)
+
+{
+  return g_unichar_combining_class (unicode);
+}
+
+static unsigned int
+hb_glib_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
+                             hb_codepoint_t      unicode,
+                             void               *user_data)
+{
+  return g_unichar_iswide (unicode) ? 2 : 1;
+}
+
+static hb_unicode_general_category_t
+hb_glib_get_general_category (hb_unicode_funcs_t *ufuncs,
+                              hb_codepoint_t      unicode,
+                              void               *user_data)
+
+{
+  /* hb_unicode_general_category_t and GUnicodeType are identical */
+  return (hb_unicode_general_category_t) g_unichar_type (unicode);
+}
+
+static hb_codepoint_t
+hb_glib_get_mirroring (hb_unicode_funcs_t *ufuncs,
+                       hb_codepoint_t      unicode,
+                       void               *user_data)
+{
+  g_unichar_get_mirror_char (unicode, &unicode);
+  return unicode;
+}
+
+static hb_script_t
+hb_glib_get_script (hb_unicode_funcs_t *ufuncs,
+                    hb_codepoint_t      unicode,
+                    void               *user_data)
+{
+  GUnicodeScript script = g_unichar_get_script (unicode);
+  switch (script)
+  {
+#define MATCH_SCRIPT(C) case G_UNICODE_SCRIPT_##C: return HB_SCRIPT_##C
+#define MATCH_SCRIPT2(C1, C2) case G_UNICODE_SCRIPT_##C1: return HB_SCRIPT_##C2
+
+  MATCH_SCRIPT2(INVALID_CODE, INVALID);
+
+  MATCH_SCRIPT (COMMON);             /* Zyyy */
+  MATCH_SCRIPT (INHERITED);          /* Qaai */
+  MATCH_SCRIPT (ARABIC);             /* Arab */
+  MATCH_SCRIPT (ARMENIAN);           /* Armn */
+  MATCH_SCRIPT (BENGALI);            /* Beng */
+  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
+  MATCH_SCRIPT (CHEROKEE);           /* Cher */
+  MATCH_SCRIPT (COPTIC);             /* Qaac */
+  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
+  MATCH_SCRIPT (DESERET);            /* Dsrt */
+  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
+  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
+  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
+  MATCH_SCRIPT (GOTHIC);             /* Goth */
+  MATCH_SCRIPT (GREEK);              /* Grek */
+  MATCH_SCRIPT (GUJARATI);           /* Gujr */
+  MATCH_SCRIPT (GURMUKHI);           /* Guru */
+  MATCH_SCRIPT (HAN);                /* Hani */
+  MATCH_SCRIPT (HANGUL);             /* Hang */
+  MATCH_SCRIPT (HEBREW);             /* Hebr */
+  MATCH_SCRIPT (HIRAGANA);           /* Hira */
+  MATCH_SCRIPT (KANNADA);            /* Knda */
+  MATCH_SCRIPT (KATAKANA);           /* Kana */
+  MATCH_SCRIPT (KHMER);              /* Khmr */
+  MATCH_SCRIPT (LAO);                /* Laoo */
+  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
+  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
+  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
+  MATCH_SCRIPT (MYANMAR);            /* Mymr */
+  MATCH_SCRIPT (OGHAM);              /* Ogam */
+  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
+  MATCH_SCRIPT (ORIYA);              /* Orya */
+  MATCH_SCRIPT (RUNIC);              /* Runr */
+  MATCH_SCRIPT (SINHALA);            /* Sinh */
+  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
+  MATCH_SCRIPT (TAMIL);              /* Taml */
+  MATCH_SCRIPT (TELUGU);             /* Telu */
+  MATCH_SCRIPT (THAANA);             /* Thaa */
+  MATCH_SCRIPT (THAI);               /* Thai */
+  MATCH_SCRIPT (TIBETAN);            /* Tibt */
+  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
+  MATCH_SCRIPT (YI);                 /* Yiii */
+  MATCH_SCRIPT (TAGALOG);            /* Tglg */
+  MATCH_SCRIPT (HANUNOO);            /* Hano */
+  MATCH_SCRIPT (BUHID);              /* Buhd */
+  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
+
+  /* Unicode-4.0 additions */
+  MATCH_SCRIPT (BRAILLE);            /* Brai */
+  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
+  MATCH_SCRIPT (LIMBU);              /* Limb */
+  MATCH_SCRIPT (OSMANYA);            /* Osma */
+  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
+  MATCH_SCRIPT (LINEAR_B);           /* Linb */
+  MATCH_SCRIPT (TAI_LE);             /* Tale */
+  MATCH_SCRIPT (UGARITIC);           /* Ugar */
+
+  /* Unicode-4.1 additions */
+  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
+  MATCH_SCRIPT (BUGINESE);           /* Bugi */
+  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
+  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
+  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
+  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
+  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
+
+  /* Unicode-5.0 additions */
+  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
+  MATCH_SCRIPT (BALINESE);           /* Bali */
+  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
+  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
+  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
+  MATCH_SCRIPT (NKO);                /* Nkoo */
+
+  /* Unicode-5.1 additions */
+  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
+  MATCH_SCRIPT (LEPCHA);             /* Lepc */
+  MATCH_SCRIPT (REJANG);             /* Rjng */
+  MATCH_SCRIPT (SUNDANESE);          /* Sund */
+  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
+  MATCH_SCRIPT (CHAM);               /* Cham */
+  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
+  MATCH_SCRIPT (VAI);                /* Vaii */
+  MATCH_SCRIPT (CARIAN);             /* Cari */
+  MATCH_SCRIPT (LYCIAN);             /* Lyci */
+  MATCH_SCRIPT (LYDIAN);             /* Lydi */
+
+  /* Unicode-5.2 additions */
+#if GLIB_CHECK_VERSION(2,26,0)
+  MATCH_SCRIPT (AVESTAN);                /* Avst */
+  MATCH_SCRIPT (BAMUM);                  /* Bamu */
+  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
+  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
+  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
+  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
+  MATCH_SCRIPT (JAVANESE);               /* Java */
+  MATCH_SCRIPT (KAITHI);                 /* Kthi */
+  MATCH_SCRIPT (TAI_THAM);               /* Lana */
+  MATCH_SCRIPT (LISU);                   /* Lisu */
+  MATCH_SCRIPT (MEETEI_MAYEK);           /* Mtei */
+  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
+#if GLIB_CHECK_VERSION(2,27,92)
+  MATCH_SCRIPT (OLD_TURKIC);             /* Orkh */
+#else
+  MATCH_SCRIPT2(OLD_TURKISH, OLD_TURKIC);/* Orkh */
+#endif
+  MATCH_SCRIPT (SAMARITAN);              /* Samr */
+  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
+#endif
+
+  /* Unicode-6.0 additions */
+#if GLIB_CHECK_VERSION(2,28,0)
+  MATCH_SCRIPT (BATAK);                  /* Batk */
+  MATCH_SCRIPT (BRAHMI);                 /* Brah */
+  MATCH_SCRIPT (MANDAIC);                /* Mand */
+#endif
+
+#undef MATCH_SCRIPT
+#undef MATCH_SCRIPT2
+  }
+
+  return HB_SCRIPT_UNKNOWN;
+}
+
+static hb_unicode_funcs_t glib_ufuncs = {
+  HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  NULL, /* parent */
+  TRUE, /* immutable */
+  {
+    hb_glib_get_combining_class,
+    hb_glib_get_eastasian_width,
+    hb_glib_get_general_category,
+    hb_glib_get_mirroring,
+    hb_glib_get_script
+  }
+};
+
+hb_unicode_funcs_t *
+hb_glib_get_unicode_funcs (void)
+{
+  return &glib_ufuncs;
+}
+
+
+HB_END_DECLS
diff --git a/src/hb-icu.c b/src/hb-icu.c
deleted file mode 100644
index 6bc3339..0000000
--- a/src/hb-icu.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- * Copyright (C) 2009  Keith Stribley
- *
- *  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.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-icu.h"
-
-#include "hb-unicode-private.h"
-
-#include <unicode/uversion.h>
-#include <unicode/uchar.h>
-#include <unicode/uscript.h>
-
-HB_BEGIN_DECLS
-
-
-static hb_codepoint_t
-hb_icu_get_mirroring (hb_unicode_funcs_t *ufuncs,
-		      hb_codepoint_t      unicode,
-		      void               *user_data)
-{
-  return u_charMirror(unicode);
-}
-
-static unsigned int
-hb_icu_get_combining_class (hb_unicode_funcs_t *ufuncs,
-			    hb_codepoint_t      unicode,
-			    void               *user_data)
-
-{
-  return u_getCombiningClass (unicode);
-}
-
-static unsigned int
-hb_icu_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
-			    hb_codepoint_t      unicode,
-			    void               *user_data)
-{
-  switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
-  {
-  case U_EA_WIDE:
-  case U_EA_FULLWIDTH:
-    return 2;
-  case U_EA_NEUTRAL:
-  case U_EA_AMBIGUOUS:
-  case U_EA_HALFWIDTH:
-  case U_EA_NARROW:
-    return 1;
-  }
-  return 1;
-}
-
-static hb_unicode_general_category_t
-hb_icu_get_general_category (hb_unicode_funcs_t *ufuncs,
-			     hb_codepoint_t      unicode,
-			     void               *user_data)
-{
-  switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
-  {
-  case U_UNASSIGNED:			return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
-
-  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;	/* Lu */
-  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;	/* Ll */
-  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;	/* Lt */
-  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;	/* Lm */
-  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;	/* Lo */
-
-  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;	/* Mn */
-  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;	/* Me */
-  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_COMBINING_MARK;	/* Mc */
-
-  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;	/* Nd */
-  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;	/* Nl */
-  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;	/* No */
-
-  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;	/* Zs */
-  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;	/* Zl */
-  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;	/* Zp */
-
-  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;		/* Cc */
-  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;		/* Cf */
-  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;		/* Co */
-  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;		/* Cs */
-
-
-  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;	/* Pd */
-  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;	/* Ps */
-  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;	/* Pe */
-  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;	/* Pc */
-  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;	/* Po */
-
-  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;		/* Sm */
-  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;	/* Sc */
-  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;	/* Sk */
-  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;	/* So */
-
-  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;	/* Pi */
-  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;	/* Pf */
-  }
-
-  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
-}
-
-static hb_script_t
-hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
-		   hb_codepoint_t      unicode,
-		   void               *user_data)
-{
-  UErrorCode status = U_ZERO_ERROR;
-  UScriptCode scriptCode = uscript_getScript(unicode, &status);
-  switch ((int) scriptCode)
-  {
-#define CHECK_ICU_VERSION(major, minor) \
-	U_ICU_VERSION_MAJOR_NUM > (major) || (U_ICU_VERSION_MAJOR_NUM == (major) && U_ICU_VERSION_MINOR_NUM >= (minor))
-#define MATCH_SCRIPT(C) case USCRIPT_##C: return HB_SCRIPT_##C
-#define MATCH_SCRIPT2(C1, C2) case USCRIPT_##C1: return HB_SCRIPT_##C2
-
-  MATCH_SCRIPT (COMMON);             /* Zyyy */
-  MATCH_SCRIPT (INHERITED);          /* Qaai */
-  MATCH_SCRIPT (ARABIC);             /* Arab */
-  MATCH_SCRIPT (ARMENIAN);           /* Armn */
-  MATCH_SCRIPT (BENGALI);            /* Beng */
-  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
-  MATCH_SCRIPT (CHEROKEE);           /* Cher */
-  MATCH_SCRIPT (COPTIC);             /* Qaac */
-  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
-  MATCH_SCRIPT (DESERET);            /* Dsrt */
-  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
-  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
-  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
-  MATCH_SCRIPT (GOTHIC);             /* Goth */
-  MATCH_SCRIPT (GREEK);              /* Grek */
-  MATCH_SCRIPT (GUJARATI);           /* Gujr */
-  MATCH_SCRIPT (GURMUKHI);           /* Guru */
-  MATCH_SCRIPT (HAN);                /* Hani */
-  MATCH_SCRIPT (HANGUL);             /* Hang */
-  MATCH_SCRIPT (HEBREW);             /* Hebr */
-  MATCH_SCRIPT (HIRAGANA);           /* Hira */
-  MATCH_SCRIPT (KANNADA);            /* Knda */
-  MATCH_SCRIPT (KATAKANA);           /* Kana */
-  MATCH_SCRIPT (KHMER);              /* Khmr */
-  MATCH_SCRIPT (LAO);                /* Laoo */
-  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
-  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
-  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
-  MATCH_SCRIPT (MYANMAR);            /* Mymr */
-  MATCH_SCRIPT (OGHAM);              /* Ogam */
-  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
-  MATCH_SCRIPT (ORIYA);              /* Orya */
-  MATCH_SCRIPT (RUNIC);              /* Runr */
-  MATCH_SCRIPT (SINHALA);            /* Sinh */
-  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
-  MATCH_SCRIPT (TAMIL);              /* Taml */
-  MATCH_SCRIPT (TELUGU);             /* Telu */
-  MATCH_SCRIPT (THAANA);             /* Thaa */
-  MATCH_SCRIPT (THAI);               /* Thai */
-  MATCH_SCRIPT (TIBETAN);            /* Tibt */
-  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
-  MATCH_SCRIPT (YI);                 /* Yiii */
-  MATCH_SCRIPT (TAGALOG);            /* Tglg */
-  MATCH_SCRIPT (HANUNOO);            /* Hano */
-  MATCH_SCRIPT (BUHID);              /* Buhd */
-  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
-
-  /* Unicode-4.0 additions */
-  MATCH_SCRIPT (BRAILLE);            /* Brai */
-  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
-  MATCH_SCRIPT (LIMBU);              /* Limb */
-  MATCH_SCRIPT (OSMANYA);            /* Osma */
-  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
-  MATCH_SCRIPT (LINEAR_B);           /* Linb */
-  MATCH_SCRIPT (TAI_LE);             /* Tale */
-  MATCH_SCRIPT (UGARITIC);           /* Ugar */
-
-  /* Unicode-4.1 additions */
-  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
-  MATCH_SCRIPT (BUGINESE);           /* Bugi */
-  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
-  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
-  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
-  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
-  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
-
-  /* Unicode-5.0 additions */
-  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
-  MATCH_SCRIPT (BALINESE);           /* Bali */
-  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
-  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
-  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
-  MATCH_SCRIPT (NKO);                /* Nkoo */
-
-  /* Unicode-5.1 additions */
-  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
-  MATCH_SCRIPT (LEPCHA);             /* Lepc */
-  MATCH_SCRIPT (REJANG);             /* Rjng */
-  MATCH_SCRIPT (SUNDANESE);          /* Sund */
-  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
-  MATCH_SCRIPT (CHAM);               /* Cham */
-  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
-  MATCH_SCRIPT (VAI);                /* Vaii */
-  MATCH_SCRIPT (CARIAN);             /* Cari */
-  MATCH_SCRIPT (LYCIAN);             /* Lyci */
-  MATCH_SCRIPT (LYDIAN);             /* Lydi */
-
-  /* Unicode-5.2 additions */
-  MATCH_SCRIPT (AVESTAN);                /* Avst */
-#if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (BAMUM);                  /* Bamu */
-#endif
-  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
-  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
-  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
-  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
-  MATCH_SCRIPT (JAVANESE);               /* Java */
-  MATCH_SCRIPT (KAITHI);                 /* Kthi */
-  MATCH_SCRIPT2(LANNA, TAI_THAM);        /* Lana */
-#if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (LISU);                   /* Lisu */
-#endif
-  MATCH_SCRIPT2(MEITEI_MAYEK, MEETEI_MAYEK);/* Mtei */
-#if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
-#endif
-  MATCH_SCRIPT2(ORKHON, OLD_TURKIC);     /* Orkh */
-  MATCH_SCRIPT (SAMARITAN);              /* Samr */
-  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
-
-  /* Unicode-6.0 additions */
-  MATCH_SCRIPT (BATAK);                  /* Batk */
-  MATCH_SCRIPT (BRAHMI);                 /* Brah */
-  MATCH_SCRIPT2(MANDAEAN, MANDAIC);      /* Mand */
-
-#undef CHECK_ICU_VERSION
-#undef MATCH_SCRIPT
-#undef MATCH_SCRIPT2
-  }
-
-  return HB_SCRIPT_UNKNOWN;
-}
-
-static hb_unicode_funcs_t icu_ufuncs = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  NULL,
-  TRUE, /* immutable */
-  {
-    hb_icu_get_general_category, NULL, NULL,
-    hb_icu_get_combining_class, NULL, NULL,
-    hb_icu_get_mirroring, NULL, NULL,
-    hb_icu_get_script, NULL, NULL,
-    hb_icu_get_eastasian_width, NULL, NULL
-  }
-};
-
-hb_unicode_funcs_t *
-hb_icu_get_unicode_funcs (void)
-{
-  return &icu_ufuncs;
-}
-
-
-HB_END_DECLS
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
new file mode 100644
index 0000000..4978bf5
--- /dev/null
+++ b/src/hb-icu.cc
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2009  Red Hat, Inc.
+ * Copyright (C) 2009  Keith Stribley
+ *
+ *  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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.h"
+
+#include "hb-icu.h"
+
+#include "hb-unicode-private.hh"
+
+#include <unicode/uversion.h>
+#include <unicode/uchar.h>
+#include <unicode/uscript.h>
+
+HB_BEGIN_DECLS
+
+
+static unsigned int
+hb_icu_get_combining_class (hb_unicode_funcs_t *ufuncs,
+			    hb_codepoint_t      unicode,
+			    void               *user_data)
+
+{
+  return u_getCombiningClass (unicode);
+}
+
+static unsigned int
+hb_icu_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
+			    hb_codepoint_t      unicode,
+			    void               *user_data)
+{
+  switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
+  {
+  case U_EA_WIDE:
+  case U_EA_FULLWIDTH:
+    return 2;
+  case U_EA_NEUTRAL:
+  case U_EA_AMBIGUOUS:
+  case U_EA_HALFWIDTH:
+  case U_EA_NARROW:
+    return 1;
+  }
+  return 1;
+}
+
+static hb_unicode_general_category_t
+hb_icu_get_general_category (hb_unicode_funcs_t *ufuncs,
+			     hb_codepoint_t      unicode,
+			     void               *user_data)
+{
+  switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
+  {
+  case U_UNASSIGNED:			return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+
+  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;	/* Lu */
+  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;	/* Ll */
+  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;	/* Lt */
+  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;	/* Lm */
+  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;	/* Lo */
+
+  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;	/* Mn */
+  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;	/* Me */
+  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_COMBINING_MARK;	/* Mc */
+
+  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;	/* Nd */
+  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;	/* Nl */
+  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;	/* No */
+
+  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;	/* Zs */
+  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;	/* Zl */
+  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;	/* Zp */
+
+  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;		/* Cc */
+  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;		/* Cf */
+  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;		/* Co */
+  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;		/* Cs */
+
+
+  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;	/* Pd */
+  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;	/* Ps */
+  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;	/* Pe */
+  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;	/* Pc */
+  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;	/* Po */
+
+  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;		/* Sm */
+  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;	/* Sc */
+  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;	/* Sk */
+  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;	/* So */
+
+  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;	/* Pi */
+  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;	/* Pf */
+  }
+
+  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+}
+
+static hb_codepoint_t
+hb_icu_get_mirroring (hb_unicode_funcs_t *ufuncs,
+		      hb_codepoint_t      unicode,
+		      void               *user_data)
+{
+  return u_charMirror(unicode);
+}
+
+static hb_script_t
+hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
+		   hb_codepoint_t      unicode,
+		   void               *user_data)
+{
+  UErrorCode status = U_ZERO_ERROR;
+  UScriptCode scriptCode = uscript_getScript(unicode, &status);
+  switch ((int) scriptCode)
+  {
+#define CHECK_ICU_VERSION(major, minor) \
+	U_ICU_VERSION_MAJOR_NUM > (major) || (U_ICU_VERSION_MAJOR_NUM == (major) && U_ICU_VERSION_MINOR_NUM >= (minor))
+#define MATCH_SCRIPT(C) case USCRIPT_##C: return HB_SCRIPT_##C
+#define MATCH_SCRIPT2(C1, C2) case USCRIPT_##C1: return HB_SCRIPT_##C2
+
+  MATCH_SCRIPT (COMMON);             /* Zyyy */
+  MATCH_SCRIPT (INHERITED);          /* Qaai */
+  MATCH_SCRIPT (ARABIC);             /* Arab */
+  MATCH_SCRIPT (ARMENIAN);           /* Armn */
+  MATCH_SCRIPT (BENGALI);            /* Beng */
+  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
+  MATCH_SCRIPT (CHEROKEE);           /* Cher */
+  MATCH_SCRIPT (COPTIC);             /* Qaac */
+  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
+  MATCH_SCRIPT (DESERET);            /* Dsrt */
+  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
+  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
+  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
+  MATCH_SCRIPT (GOTHIC);             /* Goth */
+  MATCH_SCRIPT (GREEK);              /* Grek */
+  MATCH_SCRIPT (GUJARATI);           /* Gujr */
+  MATCH_SCRIPT (GURMUKHI);           /* Guru */
+  MATCH_SCRIPT (HAN);                /* Hani */
+  MATCH_SCRIPT (HANGUL);             /* Hang */
+  MATCH_SCRIPT (HEBREW);             /* Hebr */
+  MATCH_SCRIPT (HIRAGANA);           /* Hira */
+  MATCH_SCRIPT (KANNADA);            /* Knda */
+  MATCH_SCRIPT (KATAKANA);           /* Kana */
+  MATCH_SCRIPT (KHMER);              /* Khmr */
+  MATCH_SCRIPT (LAO);                /* Laoo */
+  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
+  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
+  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
+  MATCH_SCRIPT (MYANMAR);            /* Mymr */
+  MATCH_SCRIPT (OGHAM);              /* Ogam */
+  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
+  MATCH_SCRIPT (ORIYA);              /* Orya */
+  MATCH_SCRIPT (RUNIC);              /* Runr */
+  MATCH_SCRIPT (SINHALA);            /* Sinh */
+  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
+  MATCH_SCRIPT (TAMIL);              /* Taml */
+  MATCH_SCRIPT (TELUGU);             /* Telu */
+  MATCH_SCRIPT (THAANA);             /* Thaa */
+  MATCH_SCRIPT (THAI);               /* Thai */
+  MATCH_SCRIPT (TIBETAN);            /* Tibt */
+  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
+  MATCH_SCRIPT (YI);                 /* Yiii */
+  MATCH_SCRIPT (TAGALOG);            /* Tglg */
+  MATCH_SCRIPT (HANUNOO);            /* Hano */
+  MATCH_SCRIPT (BUHID);              /* Buhd */
+  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
+
+  /* Unicode-4.0 additions */
+  MATCH_SCRIPT (BRAILLE);            /* Brai */
+  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
+  MATCH_SCRIPT (LIMBU);              /* Limb */
+  MATCH_SCRIPT (OSMANYA);            /* Osma */
+  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
+  MATCH_SCRIPT (LINEAR_B);           /* Linb */
+  MATCH_SCRIPT (TAI_LE);             /* Tale */
+  MATCH_SCRIPT (UGARITIC);           /* Ugar */
+
+  /* Unicode-4.1 additions */
+  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
+  MATCH_SCRIPT (BUGINESE);           /* Bugi */
+  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
+  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
+  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
+  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
+  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
+
+  /* Unicode-5.0 additions */
+  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
+  MATCH_SCRIPT (BALINESE);           /* Bali */
+  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
+  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
+  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
+  MATCH_SCRIPT (NKO);                /* Nkoo */
+
+  /* Unicode-5.1 additions */
+  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
+  MATCH_SCRIPT (LEPCHA);             /* Lepc */
+  MATCH_SCRIPT (REJANG);             /* Rjng */
+  MATCH_SCRIPT (SUNDANESE);          /* Sund */
+  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
+  MATCH_SCRIPT (CHAM);               /* Cham */
+  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
+  MATCH_SCRIPT (VAI);                /* Vaii */
+  MATCH_SCRIPT (CARIAN);             /* Cari */
+  MATCH_SCRIPT (LYCIAN);             /* Lyci */
+  MATCH_SCRIPT (LYDIAN);             /* Lydi */
+
+  /* Unicode-5.2 additions */
+  MATCH_SCRIPT (AVESTAN);                /* Avst */
+#if CHECK_ICU_VERSION (4, 4)
+  MATCH_SCRIPT (BAMUM);                  /* Bamu */
+#endif
+  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
+  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
+  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
+  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
+  MATCH_SCRIPT (JAVANESE);               /* Java */
+  MATCH_SCRIPT (KAITHI);                 /* Kthi */
+  MATCH_SCRIPT2(LANNA, TAI_THAM);        /* Lana */
+#if CHECK_ICU_VERSION (4, 4)
+  MATCH_SCRIPT (LISU);                   /* Lisu */
+#endif
+  MATCH_SCRIPT2(MEITEI_MAYEK, MEETEI_MAYEK);/* Mtei */
+#if CHECK_ICU_VERSION (4, 4)
+  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
+#endif
+  MATCH_SCRIPT2(ORKHON, OLD_TURKIC);     /* Orkh */
+  MATCH_SCRIPT (SAMARITAN);              /* Samr */
+  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
+
+  /* Unicode-6.0 additions */
+  MATCH_SCRIPT (BATAK);                  /* Batk */
+  MATCH_SCRIPT (BRAHMI);                 /* Brah */
+  MATCH_SCRIPT2(MANDAEAN, MANDAIC);      /* Mand */
+
+#undef CHECK_ICU_VERSION
+#undef MATCH_SCRIPT
+#undef MATCH_SCRIPT2
+  }
+
+  return HB_SCRIPT_UNKNOWN;
+}
+
+static hb_unicode_funcs_t icu_ufuncs = {
+  HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  NULL, /* parent */
+  TRUE, /* immutable */
+  {
+    hb_icu_get_combining_class,
+    hb_icu_get_eastasian_width,
+    hb_icu_get_general_category,
+    hb_icu_get_mirroring,
+    hb_icu_get_script
+  }
+};
+
+hb_unicode_funcs_t *
+hb_icu_get_unicode_funcs (void)
+{
+  return &icu_ufuncs;
+}
+
+
+HB_END_DECLS
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 2ffb076..589dee3 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -143,16 +143,13 @@ is_variation_selector (hb_codepoint_t unicode)
 static void
 hb_set_unicode_props (hb_ot_shape_context_t *c)
 {
-  hb_unicode_get_general_category_func_t get_general_category = c->buffer->unicode->v.get_general_category;
-  hb_unicode_get_combining_class_func_t get_combining_class = c->buffer->unicode->v.get_combining_class;
+  hb_unicode_funcs_t *unicode = c->buffer->unicode;
   hb_glyph_info_t *info = c->buffer->info;
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 1; i < count; i++) {
-    info[i].general_category() = get_general_category (c->buffer->unicode, info[i].codepoint,
-                                                       c->buffer->unicode->v.get_general_category_data);
-    info[i].combining_class() = get_combining_class (c->buffer->unicode, info[i].codepoint,
-                                                     c->buffer->unicode->v.get_combining_class_data);
+    info[i].general_category() = unicode->get_general_category (info[i].codepoint);
+    info[i].combining_class() = unicode->get_combining_class (info[i].codepoint);
   }
 }
 
@@ -193,7 +190,7 @@ hb_reset_glyph_infos (hb_ot_shape_context_t *c)
 static void
 hb_mirror_chars (hb_ot_shape_context_t *c)
 {
-  hb_unicode_get_mirroring_func_t get_mirroring = c->buffer->unicode->v.get_mirroring;
+  hb_unicode_funcs_t *unicode = c->buffer->unicode;
 
   if (HB_DIRECTION_IS_FORWARD (c->target_direction))
     return;
@@ -202,8 +199,7 @@ hb_mirror_chars (hb_ot_shape_context_t *c)
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t codepoint = get_mirroring (c->buffer->unicode, c->buffer->info[i].codepoint,
-                                              c->buffer->unicode->v.get_mirroring_data);
+    hb_codepoint_t codepoint = unicode->get_mirroring (c->buffer->info[i].codepoint);
     if (likely (codepoint == c->buffer->info[i].codepoint))
       c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
     else
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 9d9bf25..2b536fa 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -74,10 +74,10 @@ hb_shape (hb_font_t          *font,
 
   /* If script is set to INVALID, guess from buffer contents */
   if (buffer->props.script == HB_SCRIPT_INVALID) {
-    hb_unicode_get_script_func_t get_script = buffer->unicode->v.get_script;
+    hb_unicode_funcs_t *unicode = buffer->unicode;
     unsigned int count = buffer->len;
     for (unsigned int i = 0; i < count; i++) {
-      hb_script_t script = get_script (buffer->unicode, buffer->info[i].codepoint, buffer->unicode->v.get_script_data);
+      hb_script_t script = unicode->get_script (buffer->info[i].codepoint);
       if (likely (script != HB_SCRIPT_COMMON &&
 		  script != HB_SCRIPT_INHERITED &&
 		  script != HB_SCRIPT_UNKNOWN)) {
diff --git a/src/hb-unicode-private.h b/src/hb-unicode-private.h
deleted file mode 100644
index 456d8de..0000000
--- a/src/hb-unicode-private.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- * Copyright © 2011 Codethink Limited
- *
- *  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.
- *
- * Red Hat Author(s): Behdad Esfahbod
- * Codethink Author(s): Ryan Lortie
- */
-
-#ifndef HB_UNICODE_PRIVATE_H
-#define HB_UNICODE_PRIVATE_H
-
-#include "hb-private.h"
-
-#include "hb-unicode.h"
-
-HB_BEGIN_DECLS
-
-
-/*
- * hb_unicode_funcs_t
- */
-
-struct _hb_unicode_funcs_t {
-  hb_reference_count_t ref_count;
-  hb_unicode_funcs_t *parent;
-
-  hb_bool_t immutable;
-
-  struct {
-    hb_unicode_get_general_category_func_t	get_general_category;
-    void                                       *get_general_category_data;
-    hb_destroy_func_t                           get_general_category_destroy;
-
-    hb_unicode_get_combining_class_func_t	get_combining_class;
-    void                                       *get_combining_class_data;
-    hb_destroy_func_t                           get_combining_class_destroy;
-
-    hb_unicode_get_mirroring_func_t		get_mirroring;
-    void                                       *get_mirroring_data;
-    hb_destroy_func_t                           get_mirroring_destroy;
-
-    hb_unicode_get_script_func_t		get_script;
-    void                                       *get_script_data;
-    hb_destroy_func_t                           get_script_destroy;
-
-    hb_unicode_get_eastasian_width_func_t	get_eastasian_width;
-    void                                       *get_eastasian_width_data;
-    hb_destroy_func_t                           get_eastasian_width_destroy;
-  } v;
-};
-
-extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_nil;
-
-
-HB_END_DECLS
-
-#endif /* HB_UNICODE_PRIVATE_H */
diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
new file mode 100644
index 0000000..67a60f5
--- /dev/null
+++ b/src/hb-unicode-private.hh
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009  Red Hat, Inc.
+ * Copyright © 2011 Codethink Limited
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Codethink Author(s): Ryan Lortie
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_UNICODE_PRIVATE_HH
+#define HB_UNICODE_PRIVATE_HH
+
+#include "hb-private.h"
+
+#include "hb-unicode.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * hb_unicode_funcs_t
+ */
+
+struct _hb_unicode_funcs_t {
+  hb_reference_count_t ref_count;
+  hb_unicode_funcs_t *parent;
+
+  hb_bool_t immutable;
+
+#define IMPLEMENT(return_type, name) \
+  inline return_type \
+  get_##name (hb_codepoint_t unicode) \
+  { return this->get.name (this, unicode, this->user_data.name); }
+
+  IMPLEMENT (unsigned int, combining_class)
+  IMPLEMENT (unsigned int, eastasian_width)
+  IMPLEMENT (hb_unicode_general_category_t, general_category)
+  IMPLEMENT (hb_codepoint_t, mirroring)
+  IMPLEMENT (hb_script_t, script)
+
+#undef IMPLEMENT
+
+  /* Don't access these directly.  Call get_*() instead. */
+
+  struct {
+    hb_unicode_get_combining_class_func_t	combining_class;
+    hb_unicode_get_eastasian_width_func_t	eastasian_width;
+    hb_unicode_get_general_category_func_t	general_category;
+    hb_unicode_get_mirroring_func_t		mirroring;
+    hb_unicode_get_script_func_t		script;
+  } get;
+
+  struct {
+    void 					*combining_class;
+    void 					*eastasian_width;
+    void 					*general_category;
+    void 					*mirroring;
+    void 					*script;
+  } user_data;
+
+  struct {
+    hb_destroy_func_t				combining_class;
+    hb_destroy_func_t				eastasian_width;
+    hb_destroy_func_t				general_category;
+    hb_destroy_func_t				mirroring;
+    hb_destroy_func_t				script;
+  } destroy;
+};
+
+extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_nil;
+
+
+HB_END_DECLS
+
+#endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/src/hb-unicode.c b/src/hb-unicode.c
deleted file mode 100644
index e047ef7..0000000
--- a/src/hb-unicode.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- * Copyright © 2011 Codethink Limited
- *
- *  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.
- *
- * Red Hat Author(s): Behdad Esfahbod
- * Codethink Author(s): Ryan Lortie
- */
-
-#include "hb-private.h"
-
-#include "hb-unicode-private.h"
-
-HB_BEGIN_DECLS
-
-
-/*
- * hb_unicode_funcs_t
- */
-
-static hb_codepoint_t
-hb_unicode_get_mirroring_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
-                              hb_codepoint_t      unicode   HB_UNUSED,
-                              void               *user_data HB_UNUSED)
-{
-  return unicode;
-}
-
-static hb_unicode_general_category_t
-hb_unicode_get_general_category_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
-                                     hb_codepoint_t      unicode   HB_UNUSED,
-                                     void               *user_data HB_UNUSED)
-{
-  return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
-}
-
-static hb_script_t
-hb_unicode_get_script_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
-                           hb_codepoint_t      unicode   HB_UNUSED,
-                           void               *user_data HB_UNUSED)
-{
-  return HB_SCRIPT_UNKNOWN;
-}
-
-static unsigned int
-hb_unicode_get_combining_class_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
-                                    hb_codepoint_t      unicode   HB_UNUSED,
-                                    void               *user_data HB_UNUSED)
-{
-  return 0;
-}
-
-static unsigned int
-hb_unicode_get_eastasian_width_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
-                                    hb_codepoint_t      unicode   HB_UNUSED,
-                                    void               *user_data HB_UNUSED)
-{
-  return 1;
-}
-
-hb_unicode_funcs_t _hb_unicode_funcs_nil = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  NULL, /* parent */
-  TRUE, /* immutable */
-  {
-    hb_unicode_get_general_category_nil, NULL, NULL,
-    hb_unicode_get_combining_class_nil, NULL, NULL,
-    hb_unicode_get_mirroring_nil, NULL, NULL,
-    hb_unicode_get_script_nil, NULL, NULL,
-    hb_unicode_get_eastasian_width_nil, NULL, NULL
-  }
-};
-
-hb_unicode_funcs_t *
-hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
-{
-  hb_unicode_funcs_t *ufuncs;
-
-  if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
-    return &_hb_unicode_funcs_nil;
-
-  if (parent != NULL) {
-    ufuncs->parent = hb_unicode_funcs_reference (parent);
-    hb_unicode_funcs_make_immutable (parent);
-    ufuncs->v = parent->v;
-
-    /* Clear out the destroy notifies from our parent.
-     *
-     * We don't want to destroy the user_data twice and since we hold a
-     * reference on our parent then we know that the user_data will
-     * survive for at least as long as we do anyway.
-     */
-    ufuncs->v.get_general_category_destroy = NULL;
-    ufuncs->v.get_combining_class_destroy = NULL;
-    ufuncs->v.get_mirroring_destroy = NULL;
-    ufuncs->v.get_script_destroy = NULL;
-    ufuncs->v.get_eastasian_width_destroy = NULL;
-  } else {
-    ufuncs->v = _hb_unicode_funcs_nil.v;
-  }
-
-  return ufuncs;
-}
-
-hb_unicode_funcs_t *
-hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
-{
-  HB_OBJECT_DO_REFERENCE (ufuncs);
-}
-
-unsigned int
-hb_unicode_funcs_get_reference_count (hb_unicode_funcs_t *ufuncs)
-{
-  HB_OBJECT_DO_GET_REFERENCE_COUNT (ufuncs);
-}
-
-void
-hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
-{
-  HB_OBJECT_DO_DESTROY (ufuncs);
-
-  if (ufuncs->parent != NULL)
-    hb_unicode_funcs_destroy (ufuncs->parent);
-
-  if (ufuncs->v.get_general_category_destroy != NULL)
-    ufuncs->v.get_general_category_destroy (ufuncs->v.get_general_category_data);
-
-  if (ufuncs->v.get_combining_class_destroy != NULL)
-    ufuncs->v.get_combining_class_destroy (ufuncs->v.get_combining_class_data);
-
-  if (ufuncs->v.get_mirroring_destroy != NULL)
-    ufuncs->v.get_mirroring_destroy (ufuncs->v.get_mirroring_data);
-
-  if (ufuncs->v.get_script_destroy != NULL)
-    ufuncs->v.get_script_destroy (ufuncs->v.get_script_data);
-
-  if (ufuncs->v.get_eastasian_width_destroy != NULL)
-    ufuncs->v.get_eastasian_width_destroy (ufuncs->v.get_eastasian_width_data);
-
-  free (ufuncs);
-}
-
-hb_unicode_funcs_t *
-hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
-{
-  return ufuncs->parent;
-}
-
-void
-hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
-{
-  if (HB_OBJECT_IS_INERT (ufuncs))
-    return;
-
-  ufuncs->immutable = TRUE;
-}
-
-hb_bool_t
-hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
-{
-  return ufuncs->immutable;
-}
-
-
-#define SETTER(name) \
-void                                                                           \
-hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t             *ufuncs,    \
-                                    hb_unicode_get_##name##_func_t  func,      \
-                                    void                           *user_data, \
-                                    hb_destroy_func_t               destroy)   \
-{                                                                              \
-  if (ufuncs->immutable)                                                       \
-    return;                                                                    \
-                                                                               \
-  if (func != NULL) {                                                          \
-    ufuncs->v.get_##name = func;                                               \
-    ufuncs->v.get_##name##_data = user_data;                                   \
-    ufuncs->v.get_##name##_destroy = destroy;                                  \
-  } else if (ufuncs->parent != NULL) {                                         \
-    ufuncs->v.get_##name = ufuncs->parent->v.get_##name;                       \
-    ufuncs->v.get_##name##_data = ufuncs->parent->v.get_##name##_data;;        \
-    ufuncs->v.get_##name##_destroy = NULL;                                     \
-  } else {                                                                     \
-    ufuncs->v.get_##name = hb_unicode_get_##name##_nil;                        \
-    ufuncs->v.get_##name##_data = NULL;                                        \
-    ufuncs->v.get_##name##_destroy = NULL;                                     \
-  }                                                                            \
-}
-
-SETTER(mirroring)
-SETTER(general_category)
-SETTER(script)
-SETTER(combining_class)
-SETTER(eastasian_width)
-
-hb_codepoint_t
-hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
-			  hb_codepoint_t unicode)
-{
-  return ufuncs->v.get_mirroring (ufuncs, unicode,
-				  ufuncs->v.get_mirroring_data);
-}
-
-hb_unicode_general_category_t
-hb_unicode_get_general_category (hb_unicode_funcs_t *ufuncs,
-				 hb_codepoint_t unicode)
-{
-  return ufuncs->v.get_general_category (ufuncs, unicode,
-					 ufuncs->v.get_general_category_data);
-}
-
-hb_script_t
-hb_unicode_get_script (hb_unicode_funcs_t *ufuncs,
-		       hb_codepoint_t unicode)
-{
-  return ufuncs->v.get_script (ufuncs, unicode,
-			       ufuncs->v.get_script_data);
-}
-
-unsigned int
-hb_unicode_get_combining_class (hb_unicode_funcs_t *ufuncs,
-				hb_codepoint_t unicode)
-{
-  return ufuncs->v.get_combining_class (ufuncs, unicode,
-					ufuncs->v.get_combining_class_data);
-}
-
-unsigned int
-hb_unicode_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
-				hb_codepoint_t unicode)
-{
-  return ufuncs->v.get_eastasian_width (ufuncs, unicode,
-					ufuncs->v.get_eastasian_width_data);
-}
-
-
-HB_END_DECLS
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
new file mode 100644
index 0000000..ddad884
--- /dev/null
+++ b/src/hb-unicode.cc
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2009  Red Hat, Inc.
+ * Copyright © 2011 Codethink Limited
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Codethink Author(s): Ryan Lortie
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.h"
+
+#include "hb-unicode-private.hh"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * hb_unicode_funcs_t
+ */
+
+static unsigned int
+hb_unicode_get_combining_class_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+				    hb_codepoint_t      unicode   HB_UNUSED,
+				    void               *user_data HB_UNUSED)
+{
+  return 0;
+}
+
+static unsigned int
+hb_unicode_get_eastasian_width_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+				    hb_codepoint_t      unicode   HB_UNUSED,
+				    void               *user_data HB_UNUSED)
+{
+  return 1;
+}
+
+static hb_unicode_general_category_t
+hb_unicode_get_general_category_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+				     hb_codepoint_t      unicode   HB_UNUSED,
+				     void               *user_data HB_UNUSED)
+{
+  return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
+}
+
+static hb_codepoint_t
+hb_unicode_get_mirroring_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+			      hb_codepoint_t      unicode   HB_UNUSED,
+			      void               *user_data HB_UNUSED)
+{
+  return unicode;
+}
+
+static hb_script_t
+hb_unicode_get_script_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+			   hb_codepoint_t      unicode   HB_UNUSED,
+			   void               *user_data HB_UNUSED)
+{
+  return HB_SCRIPT_UNKNOWN;
+}
+
+
+hb_unicode_funcs_t _hb_unicode_funcs_nil = {
+  HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  NULL, /* parent */
+  TRUE, /* immutable */
+  {
+    hb_unicode_get_combining_class_nil,
+    hb_unicode_get_eastasian_width_nil,
+    hb_unicode_get_general_category_nil,
+    hb_unicode_get_mirroring_nil,
+    hb_unicode_get_script_nil,
+  }
+};
+
+
+hb_unicode_funcs_t *
+hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
+{
+  hb_unicode_funcs_t *ufuncs;
+
+  if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
+    return &_hb_unicode_funcs_nil;
+
+  if (parent != NULL)
+  {
+    hb_unicode_funcs_make_immutable (parent);
+    ufuncs->parent = hb_unicode_funcs_reference (parent);
+
+    ufuncs->get = parent->get;
+
+    /* We can safely copy user_data from parent since we hold a reference
+     * onto it and it's immutable.  We should not copy the destroy notifiers
+     * though. */
+    ufuncs->user_data = parent->user_data;
+  }
+  else
+  {
+    ufuncs->get = _hb_unicode_funcs_nil.get;
+  }
+
+  return ufuncs;
+}
+
+hb_unicode_funcs_t *
+hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
+{
+  HB_OBJECT_DO_REFERENCE (ufuncs);
+}
+
+unsigned int
+hb_unicode_funcs_get_reference_count (hb_unicode_funcs_t *ufuncs)
+{
+  HB_OBJECT_DO_GET_REFERENCE_COUNT (ufuncs);
+}
+
+void
+hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
+{
+  HB_OBJECT_DO_DESTROY (ufuncs);
+
+#define DESTROY(name) if (ufuncs->destroy.name) ufuncs->destroy.name (ufuncs->user_data.name)
+  DESTROY (combining_class);
+  DESTROY (eastasian_width);
+  DESTROY (general_category);
+  DESTROY (mirroring);
+  DESTROY (script);
+#undef DESTROY
+
+  if (ufuncs->parent != NULL)
+    hb_unicode_funcs_destroy (ufuncs->parent);
+
+  free (ufuncs);
+}
+
+void
+hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
+{
+  if (HB_OBJECT_IS_INERT (ufuncs))
+    return;
+
+  ufuncs->immutable = TRUE;
+}
+
+hb_bool_t
+hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->immutable;
+}
+
+hb_unicode_funcs_t *
+hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->parent;
+}
+
+
+#define IMPLEMENT(return_type, name)                                           \
+                                                                               \
+void                                                                           \
+hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t             *ufuncs,    \
+                                    hb_unicode_get_##name##_func_t  func,      \
+                                    void                           *user_data, \
+                                    hb_destroy_func_t               destroy)   \
+{                                                                              \
+  if (ufuncs->immutable)                                                       \
+    return;                                                                    \
+                                                                               \
+  if (ufuncs->destroy.name)                                                    \
+    ufuncs->destroy.name (ufuncs->user_data.name);                             \
+                                                                               \
+  if (func) {                                                                  \
+    ufuncs->get.name = func;                                                   \
+    ufuncs->user_data.name = user_data;                                        \
+    ufuncs->destroy.name = destroy;                                            \
+  } else if (ufuncs->parent != NULL) {                                         \
+    ufuncs->get.name = ufuncs->parent->get.name;                               \
+    ufuncs->user_data.name = ufuncs->parent->user_data.name;                   \
+    ufuncs->destroy.name = NULL;                                               \
+  } else {                                                                     \
+    ufuncs->get.name = hb_unicode_get_##name##_nil;                            \
+    ufuncs->user_data.name = NULL;                                             \
+    ufuncs->destroy.name = NULL;                                               \
+  }                                                                            \
+}                                                                              \
+                                                                               \
+return_type                                                                    \
+hb_unicode_get_##name (hb_unicode_funcs_t *ufuncs,                             \
+		       hb_codepoint_t      unicode)                            \
+{                                                                              \
+  return ufuncs->get.name (ufuncs, unicode, ufuncs->user_data.name);           \
+}
+
+IMPLEMENT (unsigned int, combining_class)
+IMPLEMENT (unsigned int, eastasian_width)
+IMPLEMENT (hb_unicode_general_category_t, general_category)
+IMPLEMENT (hb_codepoint_t, mirroring)
+IMPLEMENT (hb_script_t, script)
+
+#undef IMPLEMENT
+
+
+HB_END_DECLS
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 9785f3e..0b94aa3 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -68,28 +68,33 @@ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
 
 /* typedefs */
 
-typedef hb_codepoint_t                (*hb_unicode_get_mirroring_func_t)        (hb_unicode_funcs_t *ufuncs,
+typedef unsigned int                  (*hb_unicode_get_combining_class_func_t)  (hb_unicode_funcs_t *ufuncs,
                                                                                  hb_codepoint_t      unicode,
                                                                                  void               *user_data);
-typedef hb_unicode_general_category_t (*hb_unicode_get_general_category_func_t) (hb_unicode_funcs_t *ufuncs,
+typedef unsigned int                  (*hb_unicode_get_eastasian_width_func_t)  (hb_unicode_funcs_t *ufuncs,
                                                                                  hb_codepoint_t      unicode,
                                                                                  void               *user_data);
-typedef hb_script_t                   (*hb_unicode_get_script_func_t)           (hb_unicode_funcs_t *ufuncs,
+typedef hb_unicode_general_category_t (*hb_unicode_get_general_category_func_t) (hb_unicode_funcs_t *ufuncs,
                                                                                  hb_codepoint_t      unicode,
                                                                                  void               *user_data);
-typedef unsigned int                  (*hb_unicode_get_combining_class_func_t)  (hb_unicode_funcs_t *ufuncs,
+typedef hb_codepoint_t                (*hb_unicode_get_mirroring_func_t)        (hb_unicode_funcs_t *ufuncs,
                                                                                  hb_codepoint_t      unicode,
                                                                                  void               *user_data);
-typedef unsigned int                  (*hb_unicode_get_eastasian_width_func_t)  (hb_unicode_funcs_t *ufuncs,
+typedef hb_script_t                   (*hb_unicode_get_script_func_t)           (hb_unicode_funcs_t *ufuncs,
                                                                                  hb_codepoint_t      unicode,
                                                                                  void               *user_data);
 
 /* setters */
 
 void
-hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
-				     hb_unicode_get_mirroring_func_t mirroring_func,
-                                     void *user_data, hb_destroy_func_t destroy);
+hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
+					   hb_unicode_get_combining_class_func_t combining_class_func,
+                                           void *user_data, hb_destroy_func_t destroy);
+
+void
+hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
+					   hb_unicode_get_eastasian_width_func_t eastasian_width_func,
+                                           void *user_data, hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
@@ -97,43 +102,39 @@ hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
                                             void *user_data, hb_destroy_func_t destroy);
 
 void
+hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
+				     hb_unicode_get_mirroring_func_t mirroring_func,
+                                     void *user_data, hb_destroy_func_t destroy);
+
+void
 hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
 				  hb_unicode_get_script_func_t script_func,
                                   void *user_data, hb_destroy_func_t destroy);
 
-void
-hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_get_combining_class_func_t combining_class_func,
-                                           void *user_data, hb_destroy_func_t destroy);
-
-void
-hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_get_eastasian_width_func_t eastasian_width_func,
-                                           void *user_data, hb_destroy_func_t destroy);
 
 
 /* accessors */
 
-hb_codepoint_t
-hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
-			  hb_codepoint_t unicode);
+unsigned int
+hb_unicode_get_combining_class (hb_unicode_funcs_t *ufuncs,
+				hb_codepoint_t unicode);
+
+unsigned int
+hb_unicode_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
+				hb_codepoint_t unicode);
 
 hb_unicode_general_category_t
 hb_unicode_get_general_category (hb_unicode_funcs_t *ufuncs,
 				 hb_codepoint_t unicode);
 
+hb_codepoint_t
+hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
+			  hb_codepoint_t unicode);
+
 hb_script_t
 hb_unicode_get_script (hb_unicode_funcs_t *ufuncs,
 		       hb_codepoint_t unicode);
 
-unsigned int
-hb_unicode_get_combining_class (hb_unicode_funcs_t *ufuncs,
-				hb_codepoint_t unicode);
-
-unsigned int
-hb_unicode_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
-				hb_codepoint_t unicode);
-
 
 HB_END_DECLS
 
diff --git a/test/test-unicode.c b/test/test-unicode.c
index f610c1d..c210d54 100644
--- a/test/test-unicode.c
+++ b/test/test-unicode.c
@@ -120,10 +120,14 @@ a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs,
 static void
 test_subclassing_nil (void)
 {
-  hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+  hb_unicode_funcs_t *uf, *aa;
+
+  uf = hb_unicode_funcs_create (NULL);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
-  hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
+
+  aa = hb_unicode_funcs_create (uf);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 2);
+
   hb_unicode_funcs_destroy (uf);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
 
@@ -133,7 +137,6 @@ test_subclassing_nil (void)
   g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
   g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
 
-
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
   g_assert (!freed0 && !freed1);
@@ -145,10 +148,14 @@ test_subclassing_nil (void)
 static void
 test_subclassing_glib (void)
 {
-  hb_unicode_funcs_t *uf = hb_glib_get_unicode_funcs ();
+  hb_unicode_funcs_t *uf, *aa;
+
+  uf = hb_glib_get_unicode_funcs ();
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
-  hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
+
+  aa = hb_unicode_funcs_create (uf);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
+
   hb_unicode_funcs_destroy (uf);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
 
@@ -168,13 +175,15 @@ test_subclassing_glib (void)
 static void
 test_subclassing_deep (void)
 {
-  hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+  hb_unicode_funcs_t *uf, *aa;
+
+  uf = hb_unicode_funcs_create (NULL);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
 
   hb_unicode_funcs_set_script_func (uf, simple_get_script,
                                     unique_pointer0, free_up);
 
-  hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
+  aa = hb_unicode_funcs_create (uf);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
   g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 2);
 
commit ecfb773829a5d98a4f5456a992f3e5ecd6731435
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Apr 20 01:34:51 2011 -0400

    Cosmetic

diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 792ad54..9785f3e 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -52,15 +52,16 @@ hb_unicode_funcs_get_reference_count (hb_unicode_funcs_t *ufuncs);
 void
 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
 
-hb_unicode_funcs_t *
-hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
-
 void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
 
 hb_bool_t
 hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
 
+hb_unicode_funcs_t *
+hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
+
+
 /*
  * funcs
  */
@@ -88,32 +89,27 @@ typedef unsigned int                  (*hb_unicode_get_eastasian_width_func_t)
 void
 hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
 				     hb_unicode_get_mirroring_func_t mirroring_func,
-                                     void *user_data,
-                                     hb_destroy_func_t destroy);
+                                     void *user_data, hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
 					    hb_unicode_get_general_category_func_t general_category_func,
-                                            void *user_data,
-                                            hb_destroy_func_t destroy);
+                                            void *user_data, hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
 				  hb_unicode_get_script_func_t script_func,
-                                  void *user_data,
-                                  hb_destroy_func_t destroy);
+                                  void *user_data, hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
 					   hb_unicode_get_combining_class_func_t combining_class_func,
-                                           void *user_data,
-                                           hb_destroy_func_t destroy);
+                                           void *user_data, hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
 					   hb_unicode_get_eastasian_width_func_t eastasian_width_func,
-                                           void *user_data,
-                                           hb_destroy_func_t destroy);
+                                           void *user_data, hb_destroy_func_t destroy);
 
 
 /* accessors */
commit 2fd0c577e322ccbf762927bc4600b3ea31db4c80
Author: Ryan Lortie <desrt at desrt.ca>
Date:   Wed Apr 20 00:19:20 2011 -0400

    [API] unicode: rework virtual functions for subclassing
    
    Unicode data providers can now be subclassed, including support for
    chain-up.  The interface should now be nicely bindable, as well.
    
    Also fix glib unicode funcs that where broken after hb_script_t
    changes.  Nicely caught by the test-unicode.c added in this commit.

diff --git a/src/hb-glib.c b/src/hb-glib.c
index 56123f3..1905637 100644
--- a/src/hb-glib.c
+++ b/src/hb-glib.c
@@ -35,22 +35,188 @@
 HB_BEGIN_DECLS
 
 
-static hb_codepoint_t hb_glib_get_mirroring (hb_codepoint_t unicode) { g_unichar_get_mirror_char (unicode, &unicode); return unicode; }
-static hb_unicode_general_category_t hb_glib_get_general_category (hb_codepoint_t unicode) { return g_unichar_type (unicode); }
-static hb_script_t hb_glib_get_script (hb_codepoint_t unicode) { return g_unichar_get_script (unicode); }
-static unsigned int hb_glib_get_combining_class (hb_codepoint_t unicode) { return g_unichar_combining_class (unicode); }
-static unsigned int hb_glib_get_eastasian_width (hb_codepoint_t unicode) { return g_unichar_iswide (unicode); }
+static hb_codepoint_t
+hb_glib_get_mirroring (hb_unicode_funcs_t *ufuncs,
+                       hb_codepoint_t      unicode,
+                       void               *user_data)
+{
+  g_unichar_get_mirror_char (unicode, &unicode);
+  return unicode;
+}
+
+static hb_unicode_general_category_t
+hb_glib_get_general_category (hb_unicode_funcs_t *ufuncs,
+                              hb_codepoint_t      unicode,
+                              void               *user_data)
+
+{
+  return g_unichar_type (unicode);
+}
+
+static hb_script_t
+hb_glib_get_script (hb_unicode_funcs_t *ufuncs,
+                    hb_codepoint_t      unicode,
+                    void               *user_data)
+{
+  GUnicodeScript script = g_unichar_get_script (unicode);
+  switch (script)
+  {
+#define MATCH_SCRIPT(C) case G_UNICODE_SCRIPT_##C: return HB_SCRIPT_##C
+#define MATCH_SCRIPT2(C1, C2) case G_UNICODE_SCRIPT_##C1: return HB_SCRIPT_##C2
+
+  MATCH_SCRIPT2(INVALID_CODE, INVALID);
+
+  MATCH_SCRIPT (COMMON);             /* Zyyy */
+  MATCH_SCRIPT (INHERITED);          /* Qaai */
+  MATCH_SCRIPT (ARABIC);             /* Arab */
+  MATCH_SCRIPT (ARMENIAN);           /* Armn */
+  MATCH_SCRIPT (BENGALI);            /* Beng */
+  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
+  MATCH_SCRIPT (CHEROKEE);           /* Cher */
+  MATCH_SCRIPT (COPTIC);             /* Qaac */
+  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
+  MATCH_SCRIPT (DESERET);            /* Dsrt */
+  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
+  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
+  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
+  MATCH_SCRIPT (GOTHIC);             /* Goth */
+  MATCH_SCRIPT (GREEK);              /* Grek */
+  MATCH_SCRIPT (GUJARATI);           /* Gujr */
+  MATCH_SCRIPT (GURMUKHI);           /* Guru */
+  MATCH_SCRIPT (HAN);                /* Hani */
+  MATCH_SCRIPT (HANGUL);             /* Hang */
+  MATCH_SCRIPT (HEBREW);             /* Hebr */
+  MATCH_SCRIPT (HIRAGANA);           /* Hira */
+  MATCH_SCRIPT (KANNADA);            /* Knda */
+  MATCH_SCRIPT (KATAKANA);           /* Kana */
+  MATCH_SCRIPT (KHMER);              /* Khmr */
+  MATCH_SCRIPT (LAO);                /* Laoo */
+  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
+  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
+  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
+  MATCH_SCRIPT (MYANMAR);            /* Mymr */
+  MATCH_SCRIPT (OGHAM);              /* Ogam */
+  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
+  MATCH_SCRIPT (ORIYA);              /* Orya */
+  MATCH_SCRIPT (RUNIC);              /* Runr */
+  MATCH_SCRIPT (SINHALA);            /* Sinh */
+  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
+  MATCH_SCRIPT (TAMIL);              /* Taml */
+  MATCH_SCRIPT (TELUGU);             /* Telu */
+  MATCH_SCRIPT (THAANA);             /* Thaa */
+  MATCH_SCRIPT (THAI);               /* Thai */
+  MATCH_SCRIPT (TIBETAN);            /* Tibt */
+  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
+  MATCH_SCRIPT (YI);                 /* Yiii */
+  MATCH_SCRIPT (TAGALOG);            /* Tglg */
+  MATCH_SCRIPT (HANUNOO);            /* Hano */
+  MATCH_SCRIPT (BUHID);              /* Buhd */
+  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
+
+  /* Unicode-4.0 additions */
+  MATCH_SCRIPT (BRAILLE);            /* Brai */
+  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
+  MATCH_SCRIPT (LIMBU);              /* Limb */
+  MATCH_SCRIPT (OSMANYA);            /* Osma */
+  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
+  MATCH_SCRIPT (LINEAR_B);           /* Linb */
+  MATCH_SCRIPT (TAI_LE);             /* Tale */
+  MATCH_SCRIPT (UGARITIC);           /* Ugar */
+
+  /* Unicode-4.1 additions */
+  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
+  MATCH_SCRIPT (BUGINESE);           /* Bugi */
+  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
+  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
+  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
+  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
+  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
+
+  /* Unicode-5.0 additions */
+  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
+  MATCH_SCRIPT (BALINESE);           /* Bali */
+  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
+  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
+  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
+  MATCH_SCRIPT (NKO);                /* Nkoo */
 
+  /* Unicode-5.1 additions */
+  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
+  MATCH_SCRIPT (LEPCHA);             /* Lepc */
+  MATCH_SCRIPT (REJANG);             /* Rjng */
+  MATCH_SCRIPT (SUNDANESE);          /* Sund */
+  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
+  MATCH_SCRIPT (CHAM);               /* Cham */
+  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
+  MATCH_SCRIPT (VAI);                /* Vaii */
+  MATCH_SCRIPT (CARIAN);             /* Cari */
+  MATCH_SCRIPT (LYCIAN);             /* Lyci */
+  MATCH_SCRIPT (LYDIAN);             /* Lydi */
+
+  /* Unicode-5.2 additions */
+#if GLIB_CHECK_VERSION(2,26,0)
+  MATCH_SCRIPT (AVESTAN);                /* Avst */
+  MATCH_SCRIPT (BAMUM);                  /* Bamu */
+  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
+  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
+  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
+  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
+  MATCH_SCRIPT (JAVANESE);               /* Java */
+  MATCH_SCRIPT (KAITHI);                 /* Kthi */
+  MATCH_SCRIPT (TAI_THAM);               /* Lana */
+  MATCH_SCRIPT (LISU);                   /* Lisu */
+  MATCH_SCRIPT (MEETEI_MAYEK);           /* Mtei */
+  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
+#if GLIB_CHECK_VERSION(2,28,0)
+  MATCH_SCRIPT (OLD_TURKIC);             /* Orkh */
+#else
+  MATCH_SCRIPT2(OLD_TURKISH, OLD_TURKIC);/* Orkh */
+#endif
+  MATCH_SCRIPT (SAMARITAN);              /* Samr */
+  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
+#endif
+
+  /* Unicode-6.0 additions */
+#if GLIB_CHECK_VERSION(2,28,0)
+  MATCH_SCRIPT (BATAK);                  /* Batk */
+  MATCH_SCRIPT (BRAHMI);                 /* Brah */
+  MATCH_SCRIPT (MANDAIC);                /* Mand */
+#endif
+
+#undef MATCH_SCRIPT
+#undef MATCH_SCRIPT2
+  }
+
+  return HB_SCRIPT_UNKNOWN;
+}
+
+static unsigned int
+hb_glib_get_combining_class (hb_unicode_funcs_t *ufuncs,
+                             hb_codepoint_t      unicode,
+                             void               *user_data)
+
+{
+  return g_unichar_combining_class (unicode);
+}
+
+static unsigned int
+hb_glib_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
+                             hb_codepoint_t      unicode,
+                             void               *user_data)
+{
+  return g_unichar_iswide (unicode) ? 2 : 1;
+}
 
 static hb_unicode_funcs_t glib_ufuncs = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  NULL,
   TRUE, /* immutable */
   {
-    hb_glib_get_general_category,
-    hb_glib_get_combining_class,
-    hb_glib_get_mirroring,
-    hb_glib_get_script,
-    hb_glib_get_eastasian_width
+    hb_glib_get_general_category, NULL, NULL,
+    hb_glib_get_combining_class, NULL, NULL,
+    hb_glib_get_mirroring, NULL, NULL,
+    hb_glib_get_script, NULL, NULL,
+    hb_glib_get_eastasian_width, NULL, NULL
   }
 };
 
diff --git a/src/hb-icu.c b/src/hb-icu.c
index 0ebc9c5..6bc3339 100644
--- a/src/hb-icu.c
+++ b/src/hb-icu.c
@@ -38,11 +38,27 @@
 HB_BEGIN_DECLS
 
 
-static hb_codepoint_t hb_icu_get_mirroring (hb_codepoint_t unicode) { return u_charMirror(unicode); }
-static unsigned int hb_icu_get_combining_class (hb_codepoint_t unicode) { return u_getCombiningClass (unicode); }
+static hb_codepoint_t
+hb_icu_get_mirroring (hb_unicode_funcs_t *ufuncs,
+		      hb_codepoint_t      unicode,
+		      void               *user_data)
+{
+  return u_charMirror(unicode);
+}
+
+static unsigned int
+hb_icu_get_combining_class (hb_unicode_funcs_t *ufuncs,
+			    hb_codepoint_t      unicode,
+			    void               *user_data)
+
+{
+  return u_getCombiningClass (unicode);
+}
 
 static unsigned int
-hb_icu_get_eastasian_width (hb_codepoint_t unicode)
+hb_icu_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
+			    hb_codepoint_t      unicode,
+			    void               *user_data)
 {
   switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
   {
@@ -59,7 +75,9 @@ hb_icu_get_eastasian_width (hb_codepoint_t unicode)
 }
 
 static hb_unicode_general_category_t
-hb_icu_get_general_category (hb_codepoint_t unicode)
+hb_icu_get_general_category (hb_unicode_funcs_t *ufuncs,
+			     hb_codepoint_t      unicode,
+			     void               *user_data)
 {
   switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
   {
@@ -108,7 +126,9 @@ hb_icu_get_general_category (hb_codepoint_t unicode)
 }
 
 static hb_script_t
-hb_icu_get_script (hb_codepoint_t unicode)
+hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
+		   hb_codepoint_t      unicode,
+		   void               *user_data)
 {
   UErrorCode status = U_ZERO_ERROR;
   UScriptCode scriptCode = uscript_getScript(unicode, &status);
@@ -234,19 +254,24 @@ hb_icu_get_script (hb_codepoint_t unicode)
   MATCH_SCRIPT (BRAHMI);                 /* Brah */
   MATCH_SCRIPT2(MANDAEAN, MANDAIC);      /* Mand */
 
+#undef CHECK_ICU_VERSION
+#undef MATCH_SCRIPT
+#undef MATCH_SCRIPT2
   }
+
   return HB_SCRIPT_UNKNOWN;
 }
 
 static hb_unicode_funcs_t icu_ufuncs = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  NULL,
   TRUE, /* immutable */
   {
-    hb_icu_get_general_category,
-    hb_icu_get_combining_class,
-    hb_icu_get_mirroring,
-    hb_icu_get_script,
-    hb_icu_get_eastasian_width
+    hb_icu_get_general_category, NULL, NULL,
+    hb_icu_get_combining_class, NULL, NULL,
+    hb_icu_get_mirroring, NULL, NULL,
+    hb_icu_get_script, NULL, NULL,
+    hb_icu_get_eastasian_width, NULL, NULL
   }
 };
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 2364d3c..2ffb076 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -149,8 +149,10 @@ hb_set_unicode_props (hb_ot_shape_context_t *c)
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 1; i < count; i++) {
-    info[i].general_category() = get_general_category (info[i].codepoint);
-    info[i].combining_class() = get_combining_class (info[i].codepoint);
+    info[i].general_category() = get_general_category (c->buffer->unicode, info[i].codepoint,
+                                                       c->buffer->unicode->v.get_general_category_data);
+    info[i].combining_class() = get_combining_class (c->buffer->unicode, info[i].codepoint,
+                                                     c->buffer->unicode->v.get_combining_class_data);
   }
 }
 
@@ -200,7 +202,8 @@ hb_mirror_chars (hb_ot_shape_context_t *c)
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t codepoint = get_mirroring (c->buffer->info[i].codepoint);
+    hb_codepoint_t codepoint = get_mirroring (c->buffer->unicode, c->buffer->info[i].codepoint,
+                                              c->buffer->unicode->v.get_mirroring_data);
     if (likely (codepoint == c->buffer->info[i].codepoint))
       c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
     else
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 368abfc..9d9bf25 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -77,7 +77,7 @@ hb_shape (hb_font_t          *font,
     hb_unicode_get_script_func_t get_script = buffer->unicode->v.get_script;
     unsigned int count = buffer->len;
     for (unsigned int i = 0; i < count; i++) {
-      hb_script_t script = get_script (buffer->info[i].codepoint);
+      hb_script_t script = get_script (buffer->unicode, buffer->info[i].codepoint, buffer->unicode->v.get_script_data);
       if (likely (script != HB_SCRIPT_COMMON &&
 		  script != HB_SCRIPT_INHERITED &&
 		  script != HB_SCRIPT_UNKNOWN)) {
diff --git a/src/hb-unicode-private.h b/src/hb-unicode-private.h
index 52d1b9b..456d8de 100644
--- a/src/hb-unicode-private.h
+++ b/src/hb-unicode-private.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009  Red Hat, Inc.
+ * Copyright © 2011 Codethink Limited
  *
  *  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
+ * Codethink Author(s): Ryan Lortie
  */
 
 #ifndef HB_UNICODE_PRIVATE_H
@@ -40,15 +42,30 @@ HB_BEGIN_DECLS
 
 struct _hb_unicode_funcs_t {
   hb_reference_count_t ref_count;
+  hb_unicode_funcs_t *parent;
 
   hb_bool_t immutable;
 
   struct {
     hb_unicode_get_general_category_func_t	get_general_category;
+    void                                       *get_general_category_data;
+    hb_destroy_func_t                           get_general_category_destroy;
+
     hb_unicode_get_combining_class_func_t	get_combining_class;
+    void                                       *get_combining_class_data;
+    hb_destroy_func_t                           get_combining_class_destroy;
+
     hb_unicode_get_mirroring_func_t		get_mirroring;
+    void                                       *get_mirroring_data;
+    hb_destroy_func_t                           get_mirroring_destroy;
+
     hb_unicode_get_script_func_t		get_script;
+    void                                       *get_script_data;
+    hb_destroy_func_t                           get_script_destroy;
+
     hb_unicode_get_eastasian_width_func_t	get_eastasian_width;
+    void                                       *get_eastasian_width_data;
+    hb_destroy_func_t                           get_eastasian_width_destroy;
   } v;
 };
 
diff --git a/src/hb-unicode.c b/src/hb-unicode.c
index 9bb3524..e047ef7 100644
--- a/src/hb-unicode.c
+++ b/src/hb-unicode.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009  Red Hat, Inc.
+ * Copyright © 2011 Codethink Limited
  *
  *  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
+ * Codethink Author(s): Ryan Lortie
  */
 
 #include "hb-private.h"
@@ -35,33 +37,86 @@ HB_BEGIN_DECLS
  * hb_unicode_funcs_t
  */
 
-static hb_codepoint_t hb_unicode_get_mirroring_nil (hb_codepoint_t unicode) { return unicode; }
-static hb_unicode_general_category_t hb_unicode_get_general_category_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER; }
-static hb_script_t hb_unicode_get_script_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_SCRIPT_UNKNOWN; }
-static unsigned int hb_unicode_get_combining_class_nil (hb_codepoint_t unicode HB_UNUSED) { return 0; }
-static unsigned int hb_unicode_get_eastasian_width_nil (hb_codepoint_t unicode HB_UNUSED) { return 1; }
+static hb_codepoint_t
+hb_unicode_get_mirroring_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                              hb_codepoint_t      unicode   HB_UNUSED,
+                              void               *user_data HB_UNUSED)
+{
+  return unicode;
+}
+
+static hb_unicode_general_category_t
+hb_unicode_get_general_category_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                                     hb_codepoint_t      unicode   HB_UNUSED,
+                                     void               *user_data HB_UNUSED)
+{
+  return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
+}
+
+static hb_script_t
+hb_unicode_get_script_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                           hb_codepoint_t      unicode   HB_UNUSED,
+                           void               *user_data HB_UNUSED)
+{
+  return HB_SCRIPT_UNKNOWN;
+}
+
+static unsigned int
+hb_unicode_get_combining_class_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                                    hb_codepoint_t      unicode   HB_UNUSED,
+                                    void               *user_data HB_UNUSED)
+{
+  return 0;
+}
+
+static unsigned int
+hb_unicode_get_eastasian_width_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                                    hb_codepoint_t      unicode   HB_UNUSED,
+                                    void               *user_data HB_UNUSED)
+{
+  return 1;
+}
 
 hb_unicode_funcs_t _hb_unicode_funcs_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  NULL, /* parent */
   TRUE, /* immutable */
   {
-    hb_unicode_get_general_category_nil,
-    hb_unicode_get_combining_class_nil,
-    hb_unicode_get_mirroring_nil,
-    hb_unicode_get_script_nil,
-    hb_unicode_get_eastasian_width_nil
+    hb_unicode_get_general_category_nil, NULL, NULL,
+    hb_unicode_get_combining_class_nil, NULL, NULL,
+    hb_unicode_get_mirroring_nil, NULL, NULL,
+    hb_unicode_get_script_nil, NULL, NULL,
+    hb_unicode_get_eastasian_width_nil, NULL, NULL
   }
 };
 
 hb_unicode_funcs_t *
-hb_unicode_funcs_create (void)
+hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
 {
   hb_unicode_funcs_t *ufuncs;
 
   if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
     return &_hb_unicode_funcs_nil;
 
-  ufuncs->v = _hb_unicode_funcs_nil.v;
+  if (parent != NULL) {
+    ufuncs->parent = hb_unicode_funcs_reference (parent);
+    hb_unicode_funcs_make_immutable (parent);
+    ufuncs->v = parent->v;
+
+    /* Clear out the destroy notifies from our parent.
+     *
+     * We don't want to destroy the user_data twice and since we hold a
+     * reference on our parent then we know that the user_data will
+     * survive for at least as long as we do anyway.
+     */
+    ufuncs->v.get_general_category_destroy = NULL;
+    ufuncs->v.get_combining_class_destroy = NULL;
+    ufuncs->v.get_mirroring_destroy = NULL;
+    ufuncs->v.get_script_destroy = NULL;
+    ufuncs->v.get_eastasian_width_destroy = NULL;
+  } else {
+    ufuncs->v = _hb_unicode_funcs_nil.v;
+  }
 
   return ufuncs;
 }
@@ -83,20 +138,31 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
 {
   HB_OBJECT_DO_DESTROY (ufuncs);
 
+  if (ufuncs->parent != NULL)
+    hb_unicode_funcs_destroy (ufuncs->parent);
+
+  if (ufuncs->v.get_general_category_destroy != NULL)
+    ufuncs->v.get_general_category_destroy (ufuncs->v.get_general_category_data);
+
+  if (ufuncs->v.get_combining_class_destroy != NULL)
+    ufuncs->v.get_combining_class_destroy (ufuncs->v.get_combining_class_data);
+
+  if (ufuncs->v.get_mirroring_destroy != NULL)
+    ufuncs->v.get_mirroring_destroy (ufuncs->v.get_mirroring_data);
+
+  if (ufuncs->v.get_script_destroy != NULL)
+    ufuncs->v.get_script_destroy (ufuncs->v.get_script_data);
+
+  if (ufuncs->v.get_eastasian_width_destroy != NULL)
+    ufuncs->v.get_eastasian_width_destroy (ufuncs->v.get_eastasian_width_data);
+
   free (ufuncs);
 }
 
 hb_unicode_funcs_t *
-hb_unicode_funcs_copy (hb_unicode_funcs_t *other_ufuncs)
+hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
 {
-  hb_unicode_funcs_t *ufuncs;
-
-  if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
-    return &_hb_unicode_funcs_nil;
-
-  ufuncs->v = other_ufuncs->v;
-
-  return ufuncs;
+  return ufuncs->parent;
 }
 
 void
@@ -115,122 +181,75 @@ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
 }
 
 
-void
-hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
-				     hb_unicode_get_mirroring_func_t mirroring_func)
-{
-  if (ufuncs->immutable)
-    return;
-
-  ufuncs->v.get_mirroring = mirroring_func ? mirroring_func : hb_unicode_get_mirroring_nil;
+#define SETTER(name) \
+void                                                                           \
+hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t             *ufuncs,    \
+                                    hb_unicode_get_##name##_func_t  func,      \
+                                    void                           *user_data, \
+                                    hb_destroy_func_t               destroy)   \
+{                                                                              \
+  if (ufuncs->immutable)                                                       \
+    return;                                                                    \
+                                                                               \
+  if (func != NULL) {                                                          \
+    ufuncs->v.get_##name = func;                                               \
+    ufuncs->v.get_##name##_data = user_data;                                   \
+    ufuncs->v.get_##name##_destroy = destroy;                                  \
+  } else if (ufuncs->parent != NULL) {                                         \
+    ufuncs->v.get_##name = ufuncs->parent->v.get_##name;                       \
+    ufuncs->v.get_##name##_data = ufuncs->parent->v.get_##name##_data;;        \
+    ufuncs->v.get_##name##_destroy = NULL;                                     \
+  } else {                                                                     \
+    ufuncs->v.get_##name = hb_unicode_get_##name##_nil;                        \
+    ufuncs->v.get_##name##_data = NULL;                                        \
+    ufuncs->v.get_##name##_destroy = NULL;                                     \
+  }                                                                            \
 }
 
-void
-hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
-					    hb_unicode_get_general_category_func_t general_category_func)
-{
-  if (ufuncs->immutable)
-    return;
-
-  ufuncs->v.get_general_category = general_category_func ? general_category_func : hb_unicode_get_general_category_nil;
-}
-
-void
-hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
-				  hb_unicode_get_script_func_t script_func)
-{
-  if (ufuncs->immutable)
-    return;
-
-  ufuncs->v.get_script = script_func ? script_func : hb_unicode_get_script_nil;
-}
-
-void
-hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_get_combining_class_func_t combining_class_func)
-{
-  if (ufuncs->immutable)
-    return;
-
-  ufuncs->v.get_combining_class = combining_class_func ? combining_class_func : hb_unicode_get_combining_class_nil;
-}
-
-void
-hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_get_eastasian_width_func_t eastasian_width_func)
-{
-  if (ufuncs->immutable)
-    return;
-
-  ufuncs->v.get_eastasian_width = eastasian_width_func ? eastasian_width_func : hb_unicode_get_eastasian_width_nil;
-}
-
-
-hb_unicode_get_mirroring_func_t
-hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs)
-{
-  return ufuncs->v.get_mirroring;
-}
-
-hb_unicode_get_general_category_func_t
-hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs)
-{
-  return ufuncs->v.get_general_category;
-}
-
-hb_unicode_get_script_func_t
-hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs)
-{
-  return ufuncs->v.get_script;
-}
-
-hb_unicode_get_combining_class_func_t
-hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs)
-{
-  return ufuncs->v.get_combining_class;
-}
-
-hb_unicode_get_eastasian_width_func_t
-hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs)
-{
-  return ufuncs->v.get_eastasian_width;
-}
-
-
+SETTER(mirroring)
+SETTER(general_category)
+SETTER(script)
+SETTER(combining_class)
+SETTER(eastasian_width)
 
 hb_codepoint_t
 hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
 			  hb_codepoint_t unicode)
 {
-  return ufuncs->v.get_mirroring (unicode);
+  return ufuncs->v.get_mirroring (ufuncs, unicode,
+				  ufuncs->v.get_mirroring_data);
 }
 
 hb_unicode_general_category_t
 hb_unicode_get_general_category (hb_unicode_funcs_t *ufuncs,
 				 hb_codepoint_t unicode)
 {
-  return ufuncs->v.get_general_category (unicode);
+  return ufuncs->v.get_general_category (ufuncs, unicode,
+					 ufuncs->v.get_general_category_data);
 }
 
 hb_script_t
 hb_unicode_get_script (hb_unicode_funcs_t *ufuncs,
 		       hb_codepoint_t unicode)
 {
-  return ufuncs->v.get_script (unicode);
+  return ufuncs->v.get_script (ufuncs, unicode,
+			       ufuncs->v.get_script_data);
 }
 
 unsigned int
 hb_unicode_get_combining_class (hb_unicode_funcs_t *ufuncs,
 				hb_codepoint_t unicode)
 {
-  return ufuncs->v.get_combining_class (unicode);
+  return ufuncs->v.get_combining_class (ufuncs, unicode,
+					ufuncs->v.get_combining_class_data);
 }
 
 unsigned int
 hb_unicode_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
 				hb_codepoint_t unicode)
 {
-  return ufuncs->v.get_eastasian_width (unicode);
+  return ufuncs->v.get_eastasian_width (ufuncs, unicode,
+					ufuncs->v.get_eastasian_width_data);
 }
 
 
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index fb8fe97..792ad54 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009  Red Hat, Inc.
+ * Copyright © 2011 Codethink Limited
  *
  *  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
+ * Codethink Author(s): Ryan Lortie
  */
 
 #ifndef HB_UNICODE_H
@@ -39,7 +41,7 @@ HB_BEGIN_DECLS
 typedef struct _hb_unicode_funcs_t hb_unicode_funcs_t;
 
 hb_unicode_funcs_t *
-hb_unicode_funcs_create (void);
+hb_unicode_funcs_create (hb_unicode_funcs_t *parent_funcs);
 
 hb_unicode_funcs_t *
 hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
@@ -51,7 +53,7 @@ void
 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
 
 hb_unicode_funcs_t *
-hb_unicode_funcs_copy (hb_unicode_funcs_t *ufuncs);
+hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
 
 void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
@@ -63,57 +65,55 @@ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
  * funcs
  */
 
-
 /* typedefs */
 
-typedef hb_codepoint_t (*hb_unicode_get_mirroring_func_t) (hb_codepoint_t unicode);
-typedef hb_unicode_general_category_t (*hb_unicode_get_general_category_func_t) (hb_codepoint_t unicode);
-typedef hb_script_t (*hb_unicode_get_script_func_t) (hb_codepoint_t unicode);
-typedef unsigned int (*hb_unicode_get_combining_class_func_t) (hb_codepoint_t unicode);
-typedef unsigned int (*hb_unicode_get_eastasian_width_func_t) (hb_codepoint_t unicode);
-
+typedef hb_codepoint_t                (*hb_unicode_get_mirroring_func_t)        (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef hb_unicode_general_category_t (*hb_unicode_get_general_category_func_t) (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef hb_script_t                   (*hb_unicode_get_script_func_t)           (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef unsigned int                  (*hb_unicode_get_combining_class_func_t)  (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef unsigned int                  (*hb_unicode_get_eastasian_width_func_t)  (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
 
 /* setters */
 
 void
 hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
-				     hb_unicode_get_mirroring_func_t mirroring_func);
+				     hb_unicode_get_mirroring_func_t mirroring_func,
+                                     void *user_data,
+                                     hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
-					    hb_unicode_get_general_category_func_t general_category_func);
+					    hb_unicode_get_general_category_func_t general_category_func,
+                                            void *user_data,
+                                            hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
-				  hb_unicode_get_script_func_t script_func);
+				  hb_unicode_get_script_func_t script_func,
+                                  void *user_data,
+                                  hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_get_combining_class_func_t combining_class_func);
+					   hb_unicode_get_combining_class_func_t combining_class_func,
+                                           void *user_data,
+                                           hb_destroy_func_t destroy);
 
 void
 hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_get_eastasian_width_func_t eastasian_width_func);
-
-
-/* getters */
-
-/* These never return NULL.  Return fallback defaults instead. */
-
-hb_unicode_get_mirroring_func_t
-hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs);
-
-hb_unicode_get_general_category_func_t
-hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs);
-
-hb_unicode_get_script_func_t
-hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs);
-
-hb_unicode_get_combining_class_func_t
-hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs);
-
-hb_unicode_get_eastasian_width_func_t
-hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs);
+					   hb_unicode_get_eastasian_width_func_t eastasian_width_func,
+                                           void *user_data,
+                                           hb_destroy_func_t destroy);
 
 
 /* accessors */
diff --git a/test/Makefile.am b/test/Makefile.am
index 2056b39..37cfed2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -11,6 +11,7 @@ check_PROGRAMS = $(TEST_PROGS)
 TEST_PROGS += \
 	test-buffer \
 	test-types \
+	test-unicode \
 	$(NULL)
 
 
diff --git a/test/test-unicode.c b/test/test-unicode.c
new file mode 100644
index 0000000..f610c1d
--- /dev/null
+++ b/test/test-unicode.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 Codethink Limited
+ *
+ *  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.
+ *
+ * Codethink Author(s): Ryan Lortie
+ */
+
+#include "hb-test.h"
+
+/* This file tests the unicode virtual functions interface */
+
+static void
+test_nil (void)
+{
+  hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+
+  g_assert_cmpint (hb_unicode_get_script (uf, 'd'), ==, HB_SCRIPT_UNKNOWN);
+
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+  hb_unicode_funcs_destroy (uf);
+}
+
+static void
+test_glib (void)
+{
+  hb_unicode_funcs_t *uf = hb_glib_get_unicode_funcs ();
+
+  g_assert_cmpint (hb_unicode_get_script (uf, 'd'), ==, HB_SCRIPT_LATIN);
+
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
+  hb_unicode_funcs_destroy (uf);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
+}
+
+static gboolean freed0, freed1;
+static int unique_pointer0[1];
+static int unique_pointer1[1];
+static void free_up (void *up)
+{
+  if (up == unique_pointer0) {
+    g_assert (!freed0);
+    freed0 = TRUE;
+  } else if (up == unique_pointer1) {
+    g_assert (!freed1);
+    freed1 = TRUE;
+  } else {
+    g_assert_not_reached ();
+  }
+}
+
+static hb_script_t
+simple_get_script (hb_unicode_funcs_t *ufuncs,
+                   hb_codepoint_t      codepoint,
+                   void               *user_data)
+{
+  g_assert (hb_unicode_funcs_get_parent (ufuncs) == NULL);
+  g_assert (unique_pointer0 == user_data);
+
+  if ('a' <= codepoint && codepoint <= 'z')
+    return HB_SCRIPT_LATIN;
+  else
+    return HB_SCRIPT_UNKNOWN;
+}
+
+static void
+test_custom (void)
+{
+  hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+
+  hb_unicode_funcs_set_script_func (uf, simple_get_script,
+                                    unique_pointer0, free_up);
+
+  g_assert_cmpint (hb_unicode_get_script (uf, 'a'), ==, HB_SCRIPT_LATIN);
+  g_assert_cmpint (hb_unicode_get_script (uf, '0'), ==, HB_SCRIPT_UNKNOWN);
+
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+  g_assert (!freed0 && !freed1);
+  hb_unicode_funcs_destroy (uf);
+  g_assert (freed0 && !freed1);
+  freed0 = FALSE;
+}
+
+
+static hb_script_t
+a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs,
+                            hb_codepoint_t      codepoint,
+                            void               *user_data)
+{
+  g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
+  g_assert (user_data == unique_pointer1);
+
+  if (codepoint == 'a') {
+    return HB_SCRIPT_ARABIC;
+  } else {
+    hb_unicode_funcs_t *parent = hb_unicode_funcs_get_parent (ufuncs);
+
+    return hb_unicode_get_script (parent, codepoint);
+  }
+}
+
+static void
+test_subclassing_nil (void)
+{
+  hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+  hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 2);
+  hb_unicode_funcs_destroy (uf);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+
+  hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
+                                    unique_pointer1, free_up);
+
+  g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
+  g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
+
+
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+  g_assert (!freed0 && !freed1);
+  hb_unicode_funcs_destroy (aa);
+  g_assert (!freed0 && freed1);
+  freed1 = FALSE;
+}
+
+static void
+test_subclassing_glib (void)
+{
+  hb_unicode_funcs_t *uf = hb_glib_get_unicode_funcs ();
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
+  hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
+  hb_unicode_funcs_destroy (uf);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
+
+  hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
+                                    unique_pointer1, free_up);
+
+  g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
+  g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
+
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
+  g_assert (!freed0 && !freed1);
+  hb_unicode_funcs_destroy (aa);
+  g_assert (!freed0 && freed1);
+  freed1 = FALSE;
+}
+
+static void
+test_subclassing_deep (void)
+{
+  hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+
+  hb_unicode_funcs_set_script_func (uf, simple_get_script,
+                                    unique_pointer0, free_up);
+
+  hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 2);
+
+  hb_unicode_funcs_destroy (uf);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+
+  /* make sure the 'uf' didn't get freed, since 'aa' holds a ref */
+  g_assert (!freed0);
+
+  hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
+                                    unique_pointer1, free_up);
+
+  g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
+  g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
+  g_assert_cmpint (hb_unicode_get_script (aa, '0'), ==, HB_SCRIPT_UNKNOWN);
+
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
+  g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
+  g_assert (!freed0 && !freed1);
+  hb_unicode_funcs_destroy (aa);
+  g_assert (freed0 && freed1);
+  freed0 = freed1 = FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/unicode/nil", test_nil);
+  g_test_add_func ("/unicode/glib", test_glib);
+  g_test_add_func ("/unicode/custom", test_custom);
+  g_test_add_func ("/unicode/subclassing/nil", test_subclassing_nil);
+  g_test_add_func ("/unicode/subclassing/glib", test_subclassing_glib);
+  g_test_add_func ("/unicode/subclassing/deep", test_subclassing_deep);
+
+  return g_test_run ();
+}



More information about the HarfBuzz mailing list