Merge harfbuzz-ng
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..ba2906d
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1 @@
+main
diff --git a/src/Makefile.am b/src/Makefile.am
index 5c0b18e..40644c1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,17 +2,20 @@
 
 INCLUDES = 					\
 	-I $(srcdir)				\
-	$(FREETYPE_CFLAGS)
+	$(FREETYPE_CFLAGS)			\
+	$(GLIB_CFLAGS)
+CXX = gcc $(GCCOPTS) -fno-rtti -fno-exceptions -Wabi -Wpadded -Wcast-align
 
 noinst_LTLIBRARIES = libharfbuzz-1.la
 
 MAINSOURCES =  \
-	harfbuzz.c
+	$(INCLUDEDSOURCES) \
+	hb-ot-layout.cc
+#	harfbuzz.c
 
 # included from harfbuzz.c
 INCLUDEDSOURCES = \
 	harfbuzz-buffer.c \
-	harfbuzz-gdef.c \
 	harfbuzz-gpos.c \
 	harfbuzz-gsub.c \
 	harfbuzz-impl.c \
@@ -23,7 +26,6 @@
 	harfbuzz.h \
 	harfbuzz-global.h \
 	harfbuzz-buffer.h \
-	harfbuzz-gdef.h \
 	harfbuzz-gpos.h \
 	harfbuzz-gsub.h \
 	harfbuzz-open.h
@@ -31,7 +33,6 @@
 PRIVATEHEADERS = \
 	harfbuzz-impl.h \
 	harfbuzz-buffer-private.h \
-	harfbuzz-gdef-private.h \
 	harfbuzz-gpos-private.h \
 	harfbuzz-gsub-private.h \
 	harfbuzz-open-private.h \
@@ -45,7 +46,7 @@
 libharfbuzz_1_la_LIBADD = \
 	$(FREETYPE_LIBS)
 
-noinst_PROGRAMS = harfbuzz-dump
+noinst_PROGRAMS = harfbuzz-dump main
 
 harfbuzz_dump_SOURCES =	\
 	harfbuzz-dump.c \
@@ -56,6 +57,9 @@
 	$(libharfbuzz_1_la_LIBADD) \
 	libharfbuzz-1.la
 
+main_LDADD = \
+	$(GLIB_LIBS)
+
 EXTRA_DIST = 		\
 	README		\
 	COPYING		\
diff --git a/src/Makefile.ng b/src/Makefile.ng
new file mode 100644
index 0000000..816269b
--- /dev/null
+++ b/src/Makefile.ng
@@ -0,0 +1,11 @@
+all: main
+
+CPPFLAGS = -Wall -Wextra  `pkg-config --cflags glib-2.0`
+LDFLAGS = `pkg-config --libs glib-2.0`
+CXX = gcc $(GCCOPTS) -fno-rtti -fno-exceptions -Wabi -Wpadded -Wcast-align
+
+main: main.cc *.h
+	$(CXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+	rm -f main main.o
diff --git a/src/harfbuzz-buffer-private.h b/src/harfbuzz-buffer-private.h
index 5065f2e..02ae336 100644
--- a/src/harfbuzz-buffer-private.h
+++ b/src/harfbuzz-buffer-private.h
@@ -83,9 +83,9 @@
 #define OUT_GLYPH( pos )       (buffer->out_string[(pos)].gindex)
 #define OUT_ITEM( pos )        (&buffer->out_string[(pos)])
 
-#define CHECK_Property( gdef, index, flags, property )					\
-          ( ( error = _HB_GDEF_Check_Property( (gdef), (index), (flags),		\
-                                      (property) ) ) != HB_Err_Ok )
+#define CHECK_Property( layout, index, flags, property )					\
+          (error = _hb_ot_layout_check_glyph_properties((layout), (index), (flags), (property)) \
+	         ? HB_Err_Ok : HB_Err_Not_Covered)
 
 #define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID )             \
           ( ( error = _hb_buffer_add_output_glyphs( (buffer),                            \
diff --git a/src/harfbuzz-global.h b/src/harfbuzz-global.h
index dab20b5..7b8a0f2 100644
--- a/src/harfbuzz-global.h
+++ b/src/harfbuzz-global.h
@@ -28,6 +28,9 @@
 #ifndef HARFBUZZ_GLOBAL_H
 #define HARFBUZZ_GLOBAL_H
 
+/* XXX */
+#include "hb-ot-layout.h"
+
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
diff --git a/src/harfbuzz-gpos.c b/src/harfbuzz-gpos.c
index c78dcba..560a291 100644
--- a/src/harfbuzz-gpos.c
+++ b/src/harfbuzz-gpos.c
@@ -75,7 +75,7 @@
 
 HB_Error  HB_Load_GPOS_Table( HB_Font          font,
 			      HB_GPOSHeader** retptr,
-			      HB_GDEFHeader*  gdef )
+			      hb_ot_layout_t    *layout )
 {
   HB_UInt         cur_offset, new_offset, base_offset;
 
@@ -85,7 +85,7 @@
   HB_Error   error;
 
 
-  if ( !retptr )
+  if ( !retptr || !layout )
     return ERR(HB_Err_Invalid_Argument);
 
   if ( GOTO_Table( TTAG_GPOS ) )
@@ -143,20 +143,12 @@
 				  stream, HB_Type_GPOS ) ) != HB_Err_Ok )
     goto Fail2;
 
-  gpos->gdef = gdef;      /* can be NULL */
-
-  if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream,
-								     gpos->LookupList.Lookup,
-								     gpos->LookupList.LookupCount ) ) )
-	  goto Fail1;
+  gpos->layout = layout;      /* can be NULL */
 
   *retptr = gpos;
 
   return HB_Err_Ok;
 
-Fail1:
-  _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
-
 Fail2:
   _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
 
@@ -1005,7 +997,7 @@
   if ( context_length != 0xFFFF && context_length < 1 )
     return HB_Err_Not_Covered;
 
-  if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
@@ -1568,7 +1560,7 @@
   if ( context_length != 0xFFFF && context_length < 2 )
     return HB_Err_Not_Covered;
 
-  if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
@@ -1580,7 +1572,7 @@
   first_pos = buffer->in_pos;
   (buffer->in_pos)++;
 
-  while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+  while ( CHECK_Property( gpos->layout, IN_CURITEM(),
 			  flags, &property ) )
   {
     if ( error && error != HB_Err_Not_Covered )
@@ -1794,13 +1786,13 @@
   /* Glyphs not having the right GDEF properties will be ignored, i.e.,
      gpi->last won't be reset (contrary to user defined properties). */
 
-  if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   /* We don't handle mark glyphs here.  According to Andrei, this isn't
      possible, but who knows...                                         */
 
-  if ( property == HB_GDEF_MARK )
+  if ( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK )
   {
     gpi->last = 0xFFFF;
     return HB_Err_Not_Covered;
@@ -2216,7 +2208,7 @@
   if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
     return HB_Err_Not_Covered;
 
-  if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+  if ( CHECK_Property( gpos->layout, IN_CURITEM(),
 		       flags, &property ) )
     return error;
 
@@ -2232,12 +2224,11 @@
 
   while ( i <= buffer->in_pos )
   {
-    error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-					&property );
-    if ( error )
-      return error;
+    property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
+    if ( !property )
+      return HB_Err_Not_Covered;
 
-    if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+    if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
       break;
 
     i++;
@@ -2246,7 +2237,7 @@
 
   /* The following assertion is too strong -- at least for mangal.ttf. */
 #if 0
-  if ( property != HB_GDEF_BASE_GLYPH )
+  if ( property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH )
     return HB_Err_Not_Covered;
 #endif
 
@@ -2628,7 +2619,7 @@
 
   mark_glyph = IN_CURGLYPH();
 
-  if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
@@ -2642,12 +2633,11 @@
 
   while ( i <= buffer->in_pos )
   {
-    error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-					&property );
-    if ( error )
-      return error;
+    property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
+    if ( !property )
+      return HB_Err_Not_Covered;
 
-    if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+    if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
       break;
 
     i++;
@@ -2657,7 +2647,7 @@
   /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
      too strong, thus it is commented out.                             */
 #if 0
-  if ( property != HB_GDEF_LIGATURE )
+  if ( property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
     return HB_Err_Not_Covered;
 #endif
 
@@ -2951,7 +2941,7 @@
   if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
     return HB_Err_Not_Covered;
 
-  if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+  if ( CHECK_Property( gpos->layout, IN_CURITEM(),
 		       flags, &property ) )
     return error;
 
@@ -2970,12 +2960,11 @@
   j = buffer->in_pos - 1;
   while ( i <= buffer->in_pos )
   {
-    error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-					&property );
-    if ( error )
-      return error;
+    property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
+    if ( !property )
+      return HB_Err_Not_Covered;
 
-    if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+    if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
       return HB_Err_Not_Covered;
 
     if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
@@ -3780,12 +3769,12 @@
   HB_GPOSHeader*  gpos = gpi->gpos;
 
   HB_PosRule*     pr;
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t*  layout;
 
 
-  gdef = gpos->gdef;
+  layout = gpos->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
@@ -3805,7 +3794,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -3849,12 +3838,12 @@
 
   HB_PosClassSet*   pcs;
   HB_PosClassRule*  pr;
-  HB_GDEFHeader*    gdef;
+  hb_ot_layout_t*    layout;
 
 
-  gdef = gpos->gdef;
+  layout = gpos->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   /* Note: The coverage table in format 2 doesn't give an index into
@@ -3900,7 +3889,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  goto End;
@@ -3954,12 +3943,12 @@
   HB_GPOSHeader*  gpos = gpi->gpos;
 
   HB_Coverage*    c;
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t*  layout;
 
 
-  gdef = gpos->gdef;
+  layout = gpos->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
@@ -3972,7 +3961,7 @@
 
   for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
   {
-    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
     {
       if ( error && error != HB_Err_Not_Covered )
 	return error;
@@ -4990,12 +4979,12 @@
 
   HB_ChainPosRule*  cpr;
   HB_ChainPosRule   curr_cpr;
-  HB_GDEFHeader*    gdef;
+  hb_ot_layout_t*    layout;
 
 
-  gdef = gpos->gdef;
+  layout = gpos->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
@@ -5027,7 +5016,7 @@
 
       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
       {
-	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+	while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 	{
 	  if ( error && error != HB_Err_Not_Covered )
 	    return error;
@@ -5056,7 +5045,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -5075,7 +5064,7 @@
 
     for ( i = 0; i < lgc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -5130,12 +5119,12 @@
 
   HB_ChainPosClassSet*  cpcs;
   HB_ChainPosClassRule  cpcr;
-  HB_GDEFHeader*        gdef;
+  hb_ot_layout_t*        layout;
 
 
-  gdef = gpos->gdef;
+  layout = gpos->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   /* Note: The coverage table in format 2 doesn't give an index into
@@ -5198,7 +5187,7 @@
 
       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
       {
-	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+	while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 	{
 	  if ( error && error != HB_Err_Not_Covered )
 	    goto End1;
@@ -5230,7 +5219,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  goto End1;
@@ -5260,7 +5249,7 @@
 
     for ( i = 0; i < lgc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  goto End1;
@@ -5324,12 +5313,12 @@
   HB_Coverage*    bc;
   HB_Coverage*    ic;
   HB_Coverage*    lc;
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t*  layout;
 
 
-  gdef = gpos->gdef;
+  layout = gpos->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   bgc = ccpf3->BacktrackGlyphCount;
@@ -5353,7 +5342,7 @@
 
     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -5374,7 +5363,7 @@
   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
   {
     /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
-    while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    while ( j > buffer->in_pos && CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
     {
       if ( error && error != HB_Err_Not_Covered )
 	return error;
@@ -5396,7 +5385,7 @@
 
   for ( i = 0; i < lgc; i++, j++ )
   {
-    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
     {
       if ( error && error != HB_Err_Not_Covered )
 	return error;
diff --git a/src/harfbuzz-gpos.h b/src/harfbuzz-gpos.h
index 8638cf1..b1aa135 100644
--- a/src/harfbuzz-gpos.h
+++ b/src/harfbuzz-gpos.h
@@ -26,7 +26,7 @@
 #ifndef HARFBUZZ_GPOS_H
 #define HARFBUZZ_GPOS_H
 
-#include "harfbuzz-gdef.h"
+#include "harfbuzz-open.h"
 #include "harfbuzz-buffer.h"
 
 HB_BEGIN_HEADER
@@ -86,7 +86,7 @@
   HB_FeatureList    FeatureList;
   HB_LookupList     LookupList;
 
-  HB_GDEFHeader*    gdef;
+  hb_ot_layout_t     *layout;
 
   /* the next field is used for a callback function to get the
      glyph outline.                                            */
@@ -107,7 +107,7 @@
 
 HB_Error  HB_Load_GPOS_Table( HB_Font          font,
 			      HB_GPOSHeader** gpos,
-			      HB_GDEFHeader*  gdef );
+			      hb_ot_layout_t   *layout );
 
 
 HB_Error  HB_Done_GPOS_Table( HB_GPOSHeader* gpos );
diff --git a/src/harfbuzz-gsub.c b/src/harfbuzz-gsub.c
index c05f20d..38879a8 100644
--- a/src/harfbuzz-gsub.c
+++ b/src/harfbuzz-gsub.c
@@ -47,7 +47,7 @@
 
 HB_Error  HB_Load_GSUB_Table( HB_Font          font,
 			      HB_GSUBHeader** retptr,
-			      HB_GDEFHeader*  gdef )
+			      hb_ot_layout_t    *layout )
 {
   HB_Stream        stream = font->stream;
   HB_Error         error;
@@ -55,7 +55,7 @@
 
   HB_GSUBHeader*  gsub;
 
-  if ( !retptr )
+  if ( !retptr || !layout )
     return ERR(HB_Err_Invalid_Argument);
 
   if ( GOTO_Table( TTAG_GSUB ) )
@@ -111,20 +111,12 @@
 				  stream, HB_Type_GSUB ) ) != HB_Err_Ok )
     goto Fail2;
 
-  gsub->gdef = gdef;      /* can be NULL */
-
-  if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream,
-								     gsub->LookupList.Lookup,
-								     gsub->LookupList.LookupCount ) ) )
-	  goto Fail1;
+  gsub->layout = layout;      /* can be NULL */
 
   *retptr = gsub;
 
   return HB_Err_Ok;
 
-Fail1:
-  _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
-
 Fail2:
   _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
 
@@ -271,14 +263,14 @@
   HB_UShort index, value, property;
   HB_Error  error;
   HB_SingleSubst*  ss = &st->single;
-  HB_GDEFHeader*   gdef = gsub->gdef;
+  hb_ot_layout_t*   layout = gsub->layout;
 
   HB_UNUSED(nesting_level);
 
   if ( context_length != 0xFFFF && context_length < 1 )
     return HB_Err_Not_Covered;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index );
@@ -305,13 +297,11 @@
     return ERR(HB_Err_Invalid_SubTable);
   }
 
-  if ( gdef && gdef->NewGlyphClasses )
+  if ( _hb_ot_layout_has_new_glyph_classes (layout) )
   {
     /* we inherit the old glyph class to the substituted glyph */
 
-    error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
-    if ( error && error != HB_Err_Not_Covered )
-      return error;
+    hb_ot_layout_set_glyph_class (layout, value, property);
   }
 
   return HB_Err_Ok;
@@ -477,14 +467,14 @@
   HB_UShort index, property, n, count;
   HB_UShort*s;
   HB_MultipleSubst*  ms = &st->multiple;
-  HB_GDEFHeader*     gdef = gsub->gdef;
+  hb_ot_layout_t*     layout = gsub->layout;
 
   HB_UNUSED(nesting_level);
 
   if ( context_length != 0xFFFF && context_length < 1 )
     return HB_Err_Not_Covered;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
@@ -500,19 +490,15 @@
   if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
     return error;
 
-  if ( gdef && gdef->NewGlyphClasses )
+  if ( _hb_ot_layout_has_new_glyph_classes (layout) )
   {
     /* this is a guess only ... */
 
-    if ( property == HB_GDEF_LIGATURE )
-      property = HB_GDEF_BASE_GLYPH;
+    if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
+      property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
 
     for ( n = 0; n < count; n++ )
-    {
-      error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
-      if ( error && error != HB_Err_Not_Covered )
-	return error;
-    }
+      hb_ot_layout_set_glyph_class (layout, s[n], property);
   }
 
   return HB_Err_Ok;
@@ -674,7 +660,7 @@
   HB_Error          error;
   HB_UShort         index, value, alt_index, property;
   HB_AlternateSubst* as = &st->alternate;
-  HB_GDEFHeader*     gdef = gsub->gdef;
+  hb_ot_layout_t*     layout = gsub->layout;
   HB_AlternateSet  aset;
 
   HB_UNUSED(nesting_level);
@@ -682,7 +668,7 @@
   if ( context_length != 0xFFFF && context_length < 1 )
     return HB_Err_Not_Covered;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index );
@@ -704,14 +690,9 @@
   if ( REPLACE_Glyph( buffer, value, nesting_level ) )
     return error;
 
-  if ( gdef && gdef->NewGlyphClasses )
-  {
+  if ( _hb_ot_layout_has_new_glyph_classes (layout) )
     /* we inherit the old glyph class to the substituted glyph */
-
-    error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
-    if ( error && error != HB_Err_Not_Covered )
-      return error;
-  }
+    hb_ot_layout_set_glyph_class (layout, value, property);
 
   return HB_Err_Ok;
 }
@@ -953,16 +934,16 @@
   HB_UShort      numlig, i, j, is_mark, first_is_mark = FALSE;
   HB_UShort*     c;
   HB_LigatureSubst*  ls = &st->ligature;
-  HB_GDEFHeader*     gdef = gsub->gdef;
+  hb_ot_layout_t*     layout = gsub->layout;
 
   HB_Ligature*  lig;
 
   HB_UNUSED(nesting_level);
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
-  if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+  if ( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
     first_is_mark = TRUE;
 
   error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index );
@@ -990,7 +971,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -1000,22 +981,16 @@
 	j++;
       }
 
-      if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+      if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
 	is_mark = FALSE;
 
       if ( IN_GLYPH( j ) != c[i - 1] )
 	goto next_ligature;
     }
 
-    if ( gdef && gdef->NewGlyphClasses )
-    {
+    if ( _hb_ot_layout_has_new_glyph_classes (layout) )
       /* this is just a guess ... */
-
-      error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph,
-				  is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE );
-      if ( error && error != HB_Err_Not_Covered )
-	return error;
-    }
+      hb_ot_layout_set_glyph_class (layout, lig->LigGlyph, is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
 
     if ( j == buffer->in_pos + i ) /* No input glyphs skipped */
     {
@@ -1051,7 +1026,7 @@
 
       for ( i = 0; i < lig->ComponentCount - 1; i++ )
       {
-	while ( CHECK_Property( gdef, IN_CURITEM(),
+	while ( CHECK_Property( layout, IN_CURITEM(),
 				flags, &property ) )
 	  if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) )
 	    return error;
@@ -1813,12 +1788,12 @@
   HB_Error         error;
 
   HB_SubRule*     sr;
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t*  layout;
 
 
-  gdef = gsub->gdef;
+  layout = gsub->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
@@ -1838,7 +1813,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -1880,12 +1855,12 @@
 
   HB_SubClassSet*   scs;
   HB_SubClassRule*  sr;
-  HB_GDEFHeader*    gdef;
+  hb_ot_layout_t*    layout;
 
 
-  gdef = gsub->gdef;
+  layout = gsub->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   /* Note: The coverage table in format 2 doesn't give an index into
@@ -1931,7 +1906,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  goto End;
@@ -1984,12 +1959,12 @@
   HB_UShort        index, i, j, property;
 
   HB_Coverage*    c;
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t*  layout;
 
 
-  gdef = gsub->gdef;
+  layout = gsub->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
@@ -2002,7 +1977,7 @@
 
   for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
   {
-    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
     {
       if ( error && error != HB_Err_Not_Covered )
 	return error;
@@ -3004,12 +2979,12 @@
 
   HB_ChainSubRule*  csr;
   HB_ChainSubRule   curr_csr;
-  HB_GDEFHeader*    gdef;
+  hb_ot_layout_t*    layout;
 
 
-  gdef = gsub->gdef;
+  layout = gsub->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
@@ -3041,7 +3016,7 @@
 
       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
       {
-	while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
+	while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
 	{
 	  if ( error && error != HB_Err_Not_Covered )
 	    return error;
@@ -3070,7 +3045,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -3089,7 +3064,7 @@
 
     for ( i = 0; i < lgc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -3142,12 +3117,12 @@
 
   HB_ChainSubClassSet*  cscs;
   HB_ChainSubClassRule  ccsr;
-  HB_GDEFHeader*        gdef;
+  hb_ot_layout_t*        layout;
 
 
-  gdef = gsub->gdef;
+  layout = gsub->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   /* Note: The coverage table in format 2 doesn't give an index into
@@ -3210,7 +3185,7 @@
 
       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
       {
-	while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
+	while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
 	{
 	  if ( error && error != HB_Err_Not_Covered )
 	    goto End1;
@@ -3242,7 +3217,7 @@
 
     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  goto End1;
@@ -3272,7 +3247,7 @@
 
     for ( i = 0; i < lgc; i++, j++ )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  goto End1;
@@ -3334,12 +3309,12 @@
   HB_Coverage*    bc;
   HB_Coverage*    ic;
   HB_Coverage*    lc;
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t*  layout;
 
 
-  gdef = gsub->gdef;
+  layout = gsub->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   bgc = ccsf3->BacktrackGlyphCount;
@@ -3363,7 +3338,7 @@
 
     for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
     {
-      while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -3384,7 +3359,7 @@
   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
   {
     /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
-    while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    while ( j > buffer->in_pos && CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
     {
       if ( error && error != HB_Err_Not_Covered )
 	return error;
@@ -3406,7 +3381,7 @@
 
   for ( i = 0; i < lgc; i++, j++ )
   {
-    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
     {
       if ( error && error != HB_Err_Not_Covered )
 	return error;
@@ -3653,14 +3628,14 @@
   HB_ReverseChainContextSubst*  rccs = &st->reverse;
   HB_Coverage*    bc;
   HB_Coverage*    lc;
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t*  layout;
 
   if ( nesting_level != 1 || context_length != 0xFFFF )
     return HB_Err_Not_Covered;
 
-  gdef = gsub->gdef;
+  layout = gsub->layout;
 
-  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
     return error;
 
   bgc = rccs->BacktrackGlyphCount;
@@ -3680,7 +3655,7 @@
 
     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
     {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
       {
 	if ( error && error != HB_Err_Not_Covered )
 	  return error;
@@ -3706,7 +3681,7 @@
 
   for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ )
   {
-    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
     {
       if ( error && error != HB_Err_Not_Covered )
 	return error;
diff --git a/src/harfbuzz-gsub.h b/src/harfbuzz-gsub.h
index 3d6cfa1..b1e78ce 100644
--- a/src/harfbuzz-gsub.h
+++ b/src/harfbuzz-gsub.h
@@ -68,7 +68,7 @@
   HB_FeatureList  FeatureList;
   HB_LookupList   LookupList;
 
-  HB_GDEFHeader*  gdef;
+  hb_ot_layout_t   *layout;
 
   /* the next two fields are used for an alternate substitution callback
      function to select the proper alternate glyph.                      */
@@ -83,7 +83,7 @@
 
 HB_Error  HB_Load_GSUB_Table( HB_Font          font,
 			      HB_GSUBHeader** gsub,
-			      HB_GDEFHeader*  gdef );
+			      hb_ot_layout_t   *layout );
 
 
 HB_Error  HB_Done_GSUB_Table( HB_GSUBHeader*  gsub );
diff --git a/src/harfbuzz-impl.h b/src/harfbuzz-impl.h
index f886e67..29101f8 100644
--- a/src/harfbuzz-impl.h
+++ b/src/harfbuzz-impl.h
@@ -34,6 +34,9 @@
 
 #include <stdlib.h>
 
+/* XXX */
+#include "hb-ot-layout-private.h"
+
 HB_BEGIN_HEADER
 
 #ifndef HB_INTERNAL
@@ -66,8 +69,12 @@
 # define HB_UNUSED(arg) ((arg) = (arg))
 #endif
 
-#define HB_LIKELY(cond) (cond)
-#define HB_UNLIKELY(cond) (cond)
+#ifndef HB_LIKELY
+# define HB_LIKELY(cond) (cond)
+#endif
+#ifndef HB_UNLIKELY
+# define HB_UNLIKELY(cond) (cond)
+#endif
 
 
 #define  ALLOC(_ptr,_size)   \
diff --git a/src/harfbuzz-open.c b/src/harfbuzz-open.c
index e187916..68b27d4 100644
--- a/src/harfbuzz-open.c
+++ b/src/harfbuzz-open.c
@@ -124,15 +124,6 @@
 
   count = s->LangSysCount = GET_UShort();
 
-  /* safety check; otherwise the official handling of TrueType Open
-     fonts won't work */
-
-  if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
-  {
-    error = HB_Err_Not_Covered;
-    goto Fail2;
-  }
-
   FORGET_Frame();
 
   s->LangSysRecord = NULL;
diff --git a/src/harfbuzz.h b/src/harfbuzz.h
index 10d4f74..d23b6bc 100644
--- a/src/harfbuzz.h
+++ b/src/harfbuzz.h
@@ -28,7 +28,6 @@
 
 #include "harfbuzz-global.h"
 #include "harfbuzz-buffer.h"
-#include "harfbuzz-gdef.h"
 #include "harfbuzz-gsub.h"
 #include "harfbuzz-gpos.h"
 #include "harfbuzz-open.h"
diff --git a/src/hb-common.h b/src/hb-common.h
new file mode 100644
index 0000000..d404353
--- /dev/null
+++ b/src/hb-common.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#ifndef HB_COMMON_H
+#define HB_COMMON_H
+
+#include <stdint.h>
+
+# ifdef __cplusplus
+#  define HB_BEGIN_DECLS() extern "C" { extern int hb_dummy_prototype (int)
+#  define HB_END_DECLS() } extern "C" int hb_dummy_prototype (int)
+# else /* !__cplusplus */
+#  define HB_BEGIN_DECLS()   extern int hb_dummy_prototype (int)
+#  define HB_END_DECLS()     extern int hb_dummy_prototype (int)
+# endif /* !__cplusplus */
+
+typedef int hb_bool_t;
+
+typedef uint32_t hb_tag_t;
+#define HB_TAG(a,b,c,d) ((hb_tag_t)(((uint8_t)a<<24)|((uint8_t)b<<16)|((uint8_t)c<<8)|(uint8_t)d))
+#define HB_TAG_STR(s)   (HB_TAG(((const char *) s)[0], \
+				((const char *) s)[1], \
+				((const char *) s)[2], \
+				((const char *) s)[3]))
+
+typedef uint32_t hb_codepoint_t;
+
+/* XXX */
+typedef struct HB_BufferRec_ hb_buffer_t;
+
+#endif /* HB_COMMON_H */
diff --git a/src/hb-ot-layout-gdef-private.h b/src/hb-ot-layout-gdef-private.h
new file mode 100644
index 0000000..5418d8b
--- /dev/null
+++ b/src/hb-ot-layout-gdef-private.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#ifndef HB_OT_LAYOUT_GDEF_PRIVATE_H
+#define HB_OT_LAYOUT_GDEF_PRIVATE_H
+
+#include "hb-ot-layout-private.h"
+
+#include "hb-ot-layout-open-private.h"
+
+
+#define DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP(Type, name) \
+  inline const Type& name (hb_codepoint_t glyph) { \
+    const Coverage &c = get_coverage (); \
+    hb_ot_layout_coverage_t c_index = c.get_coverage (glyph); \
+    return (*this)[c_index]; \
+  }
+
+
+struct GlyphClassDef : ClassDef {
+  static const unsigned int BaseGlyph		= 0x0001u;
+  static const unsigned int LigatureGlyph	= 0x0002u;
+  static const unsigned int MarkGlyph		= 0x0003u;
+  static const unsigned int ComponentGlyph	= 0x0004u;
+};
+
+/*
+ * Attachment List Table
+ */
+
+struct AttachPoint {
+
+  friend struct AttachList;
+
+  private:
+  /* countour point indices, in increasing numerical order */
+  DEFINE_ARRAY_TYPE (USHORT, pointIndex, pointCount);
+
+  private:
+  USHORT	pointCount;		/* Number of attachment points on
+					 * this glyph */
+  USHORT	pointIndex[];		/* Array of contour point indices--in
+					 * increasing numerical order */
+};
+DEFINE_NULL_ASSERT_SIZE (AttachPoint, 2);
+
+struct AttachList {
+
+  friend struct GDEF;
+
+  private:
+  /* const AttachPoint& get_attach_points (hb_codepoint_t glyph); */
+  DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP (AttachPoint, get_attach_points);
+
+  private:
+  /* AttachPoint tables, in Coverage Index order */
+  DEFINE_OFFSET_ARRAY_TYPE (AttachPoint, attachPoint, glyphCount);
+  DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
+
+ private:
+  Offset	coverage;		/* Offset to Coverage table -- from
+					 * beginning of AttachList table */
+  USHORT	glyphCount;		/* Number of glyphs with attachment
+					 * points */
+  Offset	attachPoint[];		/* Array of offsets to AttachPoint
+					 * tables--from beginning of AttachList
+					 * table--in Coverage Index order */
+};
+DEFINE_NULL_ASSERT_SIZE (AttachList, 4);
+
+/*
+ * Ligature Caret Table
+ */
+
+struct CaretValueFormat1 {
+
+  friend struct CaretValue;
+
+  private:
+  inline int get_caret_value (int ppem) const {
+    return /* TODO garbage */ coordinate / ppem;
+  }
+
+  private:
+  USHORT	caretValueFormat;	/* Format identifier--format = 1 */
+  SHORT		coordinate;		/* X or Y value, in design units */
+};
+ASSERT_SIZE (CaretValueFormat1, 4);
+
+struct CaretValueFormat2 {
+
+  friend struct CaretValue;
+
+  private:
+  inline int get_caret_value (int ppem) const {
+    return /* TODO garbage */ 0 / ppem;
+  }
+
+  private:
+  USHORT	caretValueFormat;	/* Format identifier--format = 2 */
+  USHORT	caretValuePoint;	/* Contour point index on glyph */
+};
+ASSERT_SIZE (CaretValueFormat2, 4);
+
+struct CaretValueFormat3 {
+
+  friend struct CaretValue;
+
+  private:
+  inline const Device& get_device (void) const {
+    if (HB_UNLIKELY (!deviceTable)) return NullDevice;
+    return *(const Device*)((const char*)this + deviceTable);
+  }
+
+  inline int get_caret_value (int ppem) const {
+    return /* TODO garbage */ (coordinate + get_device().get_delta (ppem)) / ppem;
+  }
+
+  private:
+  USHORT	caretValueFormat;	/* Format identifier--format = 3 */
+  SHORT		coordinate;		/* X or Y value, in design units */
+  Offset	deviceTable;		/* Offset to Device table for X or Y
+					 * value--from beginning of CaretValue
+					 * table */
+};
+ASSERT_SIZE (CaretValueFormat3, 6);
+
+struct CaretValue {
+  DEFINE_NON_INSTANTIABLE(CaretValue);
+
+  unsigned int get_size (void) const {
+    switch (u.caretValueFormat) {
+    case 1: return sizeof (u.format1);
+    case 2: return sizeof (u.format2);
+    case 3: return sizeof (u.format3);
+    default:return sizeof (u.caretValueFormat);
+    }
+  }
+
+  /* XXX  we need access to a load-contour-point vfunc here */
+  int get_caret_value (int ppem) const {
+    switch (u.caretValueFormat) {
+    case 1: return u.format1.get_caret_value(ppem);
+    case 2: return u.format2.get_caret_value(ppem);
+    case 3: return u.format3.get_caret_value(ppem);
+    default:return 0;
+    }
+  }
+
+  private:
+  union {
+  USHORT	caretValueFormat;	/* Format identifier */
+  CaretValueFormat1	format1;
+  CaretValueFormat2	format2;
+  CaretValueFormat3	format3;
+  /* FIXME old HarfBuzz code has a format 4 here! */
+  } u;
+};
+DEFINE_NULL (CaretValue, 2);
+
+struct LigGlyph {
+
+  friend struct LigCaretList;
+
+  private:
+  /* Caret value tables, in increasing coordinate order */
+  DEFINE_OFFSET_ARRAY_TYPE (CaretValue, caretValue, caretCount);
+  /* TODO */
+
+  private:
+  USHORT	caretCount;		/* Number of CaretValues for this
+					 * ligature (components - 1) */
+  Offset	caretValue[];		/* Array of offsets to CaretValue
+					 * tables--from beginning of LigGlyph
+					 * table--in increasing coordinate
+					 * order */
+};
+DEFINE_NULL_ASSERT_SIZE (LigGlyph, 2);
+
+struct LigCaretList {
+
+  friend struct GDEF;
+
+  private:
+  /* const LigGlyph& get_lig_glyph (hb_codepoint_t glyph); */
+  DEFINE_INDIRECT_GLYPH_ARRAY_LOOKUP (LigGlyph, get_lig_glyph);
+
+  private:
+  /* AttachPoint tables, in Coverage Index order */
+  DEFINE_OFFSET_ARRAY_TYPE (LigGlyph, ligGlyph, ligGlyphCount);
+  DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
+
+  private:
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of LigCaretList table */
+  USHORT	ligGlyphCount;		/* Number of ligature glyphs */
+  Offset	ligGlyph[];		/* Array of offsets to LigGlyph
+					 * tables--from beginning of
+					 * LigCaretList table--in Coverage
+					 * Index order */
+};
+DEFINE_NULL_ASSERT_SIZE (LigCaretList, 4);
+
+/*
+ * GDEF
+ */
+
+struct GDEF {
+  static const hb_tag_t Tag		= HB_TAG ('G','D','E','F');
+
+  static const hb_ot_layout_class_t UnclassifiedGlyph	= 0;
+  static const hb_ot_layout_class_t BaseGlyph		= 1;
+  static const hb_ot_layout_class_t LigatureGlyph	= 2;
+  static const hb_ot_layout_class_t MarkGlyph		= 3;
+  static const hb_ot_layout_class_t ComponentGlyph	= 4;
+
+  STATIC_DEFINE_GET_FOR_DATA (GDEF);
+  /* XXX check version here? */
+
+  DEFINE_GET_HAS_ACCESSOR (ClassDef, glyph_classes, glyphClassDef);
+  DEFINE_GET_HAS_ACCESSOR (AttachList, attach_list, attachList);
+  DEFINE_GET_HAS_ACCESSOR (LigCaretList, lig_caret_list, ligCaretList);
+  DEFINE_GET_HAS_ACCESSOR (ClassDef, mark_attachment_types, markAttachClassDef);
+
+  inline hb_ot_layout_class_t get_glyph_class (hb_codepoint_t glyph) const {
+    return get_glyph_classes ().get_class (glyph);
+  }
+
+  inline hb_ot_layout_class_t get_mark_attachment_type (hb_codepoint_t glyph) const {
+    return get_mark_attachment_types ().get_class (glyph);
+  }
+
+  /* TODO get_attach and get_lig_caret */
+
+  private:
+  Fixed		version;		/* Version of the GDEF table--initially
+					 * 0x00010000 */
+  Offset	glyphClassDef;		/* Offset to class definition table
+					 * for glyph type--from beginning of
+					 * GDEF header (may be Null) */
+  Offset	attachList;		/* Offset to list of glyphs with
+					 * attachment points--from beginning
+					 * of GDEF header (may be Null) */
+  Offset	ligCaretList;		/* Offset to list of positioning points
+					 * for ligature carets--from beginning
+					 * of GDEF header (may be Null) */
+  Offset	markAttachClassDef;	/* Offset to class definition table for
+					 * mark attachment type--from beginning
+					 * of GDEF header (may be Null) */
+};
+DEFINE_NULL_ASSERT_SIZE (GDEF, 12);
+
+#endif /* HB_OT_LAYOUT_GDEF_PRIVATE_H */
diff --git a/src/hb-ot-layout-gsub-private.h b/src/hb-ot-layout-gsub-private.h
new file mode 100644
index 0000000..c8d5405
--- /dev/null
+++ b/src/hb-ot-layout-gsub-private.h
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#ifndef HB_OT_LAYOUT_GSUB_PRIVATE_H
+#define HB_OT_LAYOUT_GSUB_PRIVATE_H
+
+#include "hb-ot-layout-private.h"
+
+#include "hb-ot-layout-open-private.h"
+#include "hb-ot-layout-gdef-private.h"
+
+
+struct SingleSubstFormat1 {
+
+  friend struct SingleSubst;
+
+  private:
+  inline bool substitute (hb_ot_layout_t *layout,
+			  hb_buffer_t    *buffer,
+			  unsigned int    context_length,
+			  unsigned int    nesting_level_left) const {
+//    if (get_coverage (IN_CURGLYPH()))
+//      return ;
+  }
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 1 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
+					 * substitute GlyphID */
+};
+ASSERT_SIZE (SingleSubstFormat1, 6);
+
+struct SingleSubstFormat2 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 2 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  USHORT	glyphCount;		/* Number of GlyphIDs in the Substitute
+					 * array */
+  GlyphID	substitute[];		/* Array of substitute
+					 * GlyphIDs--ordered by Coverage  Index */
+};
+ASSERT_SIZE (SingleSubstFormat2, 6);
+
+struct MultipleSubstFormat1 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 1 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  USHORT	sequenceCount;		/* Number of Sequence table offsets in
+					 * the Sequence array */
+  Offset	sequence[];		/* Array of offsets to Sequence
+					 * tables--from beginning of
+					 * Substitution table--ordered by
+					 * Coverage Index */
+};
+ASSERT_SIZE (MultipleSubstFormat1, 6);
+
+struct Sequence {
+  /* TODO */
+
+  private:
+  USHORT	glyphCount;		/* Number of GlyphIDs in the Substitute
+					 * array. This should always  be
+					 * greater than 0. */
+  GlyphID	substitute[];		/* String of GlyphIDs to substitute */
+};
+DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
+
+struct AlternateSubstFormat1 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 1 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  USHORT	alternateSetCount;	/* Number of AlternateSet tables */
+  Offset	alternateSet[];		/* Array of offsets to AlternateSet
+					 * tables--from beginning of
+					 * Substitution table--ordered by
+					 * Coverage Index */
+};
+ASSERT_SIZE (AlternateSubstFormat1, 6);
+
+struct AlternateSet {
+  /* TODO */
+
+  private:
+  USHORT	glyphCount;		/* Number of GlyphIDs in the Alternate
+					 * array */
+  GlyphID	alternate[];		/* Array of alternate GlyphIDs--in
+					 * arbitrary order */
+};
+DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
+
+struct LigatureSubstFormat1 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 1 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  USHORT	ligSetCount;		/* Number of LigatureSet tables */
+  Offset	ligatureSet[];		/* Array of offsets to LigatureSet
+					 * tables--from beginning of
+					 * Substitution table--ordered by
+					 * Coverage Index */
+};
+ASSERT_SIZE (LigatureSubstFormat1, 6);
+
+struct LigatureSet {
+  /* TODO */
+
+  private:
+  USHORT	ligatureCount;		/* Number of Ligature tables */
+  Offset	ligature[];		/* Array of offsets to Ligature
+					 * tables--from beginning of
+					 * LigatureSet table--ordered by
+					 * preference */
+};
+DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
+
+struct Ligature {
+  /* TODO */
+
+  private:
+  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
+  USHORT	compCount;		/* Number of components in the ligature */
+  GlyphID	component[];		/* Array of component GlyphIDs--start
+					 * with the second  component--ordered
+					 * in writing direction */
+};
+DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
+
+struct SubstLookupRecord {
+  /* TODO */
+
+  private:
+  USHORT	sequenceIndex;		/* Index into current glyph
+					 * sequence--first glyph = 0 */
+  USHORT	lookupListIndex;	/* Lookup to apply to that
+					 * position--zero--based */
+};
+DEFINE_NULL_ASSERT_SIZE (SubstLookupRecord, 4);
+
+struct ContextSubstFormat1 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 1 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  USHORT	subRuleSetCount;	/* Number of SubRuleSet tables--must
+					 * equal GlyphCount in Coverage  table */
+  Offset	subRuleSet[];		/* Array of offsets to SubRuleSet
+					 * tables--from beginning of
+					 * Substitution table--ordered by
+					 * Coverage Index */
+};
+ASSERT_SIZE (ContextSubstFormat1, 6);
+
+struct SubRuleSet {
+  /* TODO */
+
+  private:
+  USHORT	subRuleCount;		/* Number of SubRule tables */
+  Offset	subRule[];		/* Array of offsets to SubRule
+					 * tables--from beginning of SubRuleSet
+					 * table--ordered by preference */
+};
+DEFINE_NULL_ASSERT_SIZE (SubRuleSet, 2);
+
+struct SubRule {
+  /* TODO */
+
+  private:
+  USHORT	glyphCount;		/* Total number of glyphs in input
+					 * glyph sequence--includes the  first
+					 * glyph */
+  USHORT	substCount;		/* Number of SubstLookupRecords */
+  GlyphID	input[];		/* Array of input GlyphIDs--start with
+					 * second glyph */
+  SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+					 * design order */
+};
+DEFINE_NULL_ASSERT_SIZE (SubRule, 4);
+
+struct ContextSubstFormat2 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 2 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  Offset	classDef;		/* Offset to glyph ClassDef table--from
+					 * beginning of Substitution  table */
+  USHORT	subClassSetCnt;		/* Number of SubClassSet tables */
+  Offset	subClassSet[];		/* Array of offsets to SubClassSet
+					 * tables--from beginning of
+					 * Substitution table--ordered by
+					 * class--may be NULL */
+};
+ASSERT_SIZE (ContextSubstFormat2, 8);
+
+struct SubClassSet {
+  /* TODO */
+
+  private:
+  USHORT	subClassRuleCnt;	/* Number of SubClassRule tables */
+  Offset	subClassRule[];		/* Array of offsets to SubClassRule
+					 * tables--from beginning of
+					 * SubClassSet--ordered by preference */
+};
+DEFINE_NULL_ASSERT_SIZE (SubClassSet, 2);
+
+struct SubClassRule {
+  /* TODO */
+
+  private:
+  USHORT	glyphCount;		/* Total number of classes
+					 * specified for the context in the
+					 * rule--includes the first class */
+  USHORT	substCount;		/* Number of SubstLookupRecords */
+  USHORT	klass[];		/* Array of classes--beginning with the
+					 * second class--to be matched  to the
+					 * input glyph class sequence */
+  SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+					 * design order */
+};
+DEFINE_NULL_ASSERT_SIZE (SubClassRule, 4);
+
+struct ContextSubstFormat3 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 3 */
+  USHORT	glyphCount;		/* Number of glyphs in the input glyph
+					 * sequence */
+  USHORT	substCount;		/* Number of SubstLookupRecords */
+  Offset	coverage[];		/* Array of offsets to Coverage
+					 * table--from beginning of
+					 * Substitution table--in glyph
+					 * sequence order */
+  SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+					 * design order */
+};
+ASSERT_SIZE (ContextSubstFormat3, 6);
+
+struct ChainContextSubstFormat1 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 1 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  USHORT	chainSubRuleSetCount;	/* Number of ChainSubRuleSet
+					 * tables--must equal GlyphCount in
+					 * Coverage table */
+  Offset	chainSubRuleSet[];	/* Array of offsets to ChainSubRuleSet
+					 * tables--from beginning of
+					 * Substitution table--ordered by
+					 * Coverage Index */
+};
+ASSERT_SIZE (ChainContextSubstFormat1, 6);
+
+struct ChainSubRuleSet {
+  /* TODO */
+
+  private:
+  USHORT	chainSubRuleCount;	/* Number of ChainSubRule tables */
+  Offset	chainSubRule[];		/* Array of offsets to ChainSubRule
+					 * tables--from beginning of
+					 * ChainSubRuleSet table--ordered
+					 * by preference */
+};
+DEFINE_NULL_ASSERT_SIZE (ChainSubRuleSet, 2);
+
+struct ChainSubRule {
+  /* TODO */
+
+  private:
+  USHORT	backtrackGlyphCount;	/* Total number of glyphs in the
+					 * backtrack sequence (number of
+					 * glyphs to be matched before the
+					 * first glyph) */
+  GlyphID	backtrack[];		/* Array of backtracking GlyphID's
+					 * (to be matched before the input
+					 * sequence) */
+  USHORT	inputGlyphCount;	/* Total number of glyphs in the input
+					 * sequence (includes the first  glyph) */
+  GlyphID	input[];		/* Array of input GlyphIDs (start with
+					 * second glyph) */
+  USHORT	lookaheadGlyphCount;	/* Total number of glyphs in the look
+					 * ahead sequence (number of  glyphs to
+					 * be matched after the input sequence) */
+  GlyphID	lookAhead[];		/* Array of lookahead GlyphID's (to be
+					 * matched after  the input sequence) */
+  USHORT	substCount;		/* Number of SubstLookupRecords */
+  SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+					 * design order) */
+};
+DEFINE_NULL_ASSERT_SIZE (ChainSubRule, 8);
+
+struct ChainContextSubstFormat2 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 2 */
+  Offset	coverage;		/* Offset to Coverage table--from
+					 * beginning of Substitution table */
+  Offset	backtrackClassDef;	/* Offset to glyph ClassDef table
+					 * containing backtrack sequence
+					 * data--from beginning of Substitution
+					 * table */
+  Offset	inputClassDef;		/* Offset to glyph ClassDef
+					 * table containing input sequence
+					 * data--from beginning of Substitution
+					 * table */
+  Offset	lookaheadClassDef;	/* Offset to glyph ClassDef table
+					 * containing lookahead sequence
+					 * data--from beginning of Substitution
+					 * table */
+  USHORT	chainSubClassSetCnt;	/* Number of ChainSubClassSet tables */
+  Offset	chainSubClassSet[];	/* Array of offsets to ChainSubClassSet
+					 * tables--from beginning of
+					 * Substitution table--ordered by input
+					 * class--may be NULL */
+};
+ASSERT_SIZE (ChainContextSubstFormat2, 12);
+
+struct ChainSubClassSet {
+  /* TODO */
+
+  private:
+  USHORT	chainSubClassRuleCnt;	/* Number of ChainSubClassRule tables */
+  Offset	chainSubClassRule[];	/* Array of offsets
+					 * to ChainSubClassRule
+					 * tables--from beginning of
+					 * ChainSubClassSet--ordered by
+					 * preference */
+};
+DEFINE_NULL_ASSERT_SIZE (ChainSubClassSet, 2);
+
+struct ChainSubClassRule {
+  /* TODO */
+
+  private:
+  USHORT	backtrackGlyphCount;	/* Total number of glyphs in the
+					 * backtrack sequence (number of
+					 * glyphs to be matched before the
+					 * first glyph) */
+  USHORT	backtrack[];		/* Array of backtracking classes(to be
+					 * matched before the input  sequence) */
+  USHORT	inputGlyphCount;	/* Total number of classes in the input
+					 * sequence (includes the  first class) */
+  USHORT	input[];		/* Array of input classes(start with
+					 * second class; to  be matched with
+					 * the input glyph sequence) */
+  USHORT	lookaheadGlyphCount;	/* Total number of classes in the
+					 * look ahead sequence (number of
+					 * classes to be matched after the
+					 * input sequence) */
+  USHORT	lookAhead[];		/* Array of lookahead classes(to be
+					 * matched after the  input sequence) */
+  USHORT	substCount;		/* Number of SubstLookupRecords */
+  SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+					 * design order) */
+};
+DEFINE_NULL_ASSERT_SIZE (ChainSubClassRule, 8);
+
+struct ChainContextSubstFormat3 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 3 */
+  USHORT	backtrackGlyphCount;	/* Number of glyphs in the backtracking
+					 * sequence */
+  Offset	backtrackCoverage[];	/* Array of offsets to coverage tables
+					 * in backtracking sequence, in  glyph
+					 * sequence order */
+  USHORT	inputGlyphCount;	/* Number of glyphs in input sequence */
+  Offset	inputCoverage[];	/* Array of offsets to coverage
+					 * tables in input sequence, in glyph
+					 * sequence order */
+  USHORT	lookaheadGlyphCount;	/* Number of glyphs in lookahead
+					 * sequence */
+  Offset	lookaheadCoverage[];	/* Array of offsets to coverage tables
+					 * in lookahead sequence, in  glyph
+					 * sequence order */
+  USHORT	substCount;		/* Number of SubstLookupRecords */
+  SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
+					 * design order */
+};
+ASSERT_SIZE (ChainContextSubstFormat3, 10);
+
+struct ExtensionSubstFormat1 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier. Set to 1. */
+  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
+					 * by ExtensionOffset (i.e. the
+					 * extension subtable). */
+  ULONG		extensionOffset;	/* Offset to the extension subtable,
+					 * of lookup type  subtable. */
+};
+ASSERT_SIZE (ExtensionSubstFormat1, 8);
+
+struct ReverseChainSingleSubstFormat1 {
+  /* TODO */
+
+  private:
+  USHORT	substFormat;		/* Format identifier--format = 1 */
+  Offset	coverage;		/* Offset to Coverage table -- from
+					 * beginning of Substitution table */
+  USHORT	backtrackGlyphCount;	/* Number of glyphs in the backtracking
+					 * sequence */
+  Offset	backtrackCoverage[];	/* Array of offsets to coverage tables
+					 * in backtracking sequence, in  glyph
+					 * sequence order */
+  USHORT	lookaheadGlyphCount;	/* Number of glyphs in lookahead
+					 * sequence */
+  Offset	lookaheadCoverage[];	/* Array of offsets to coverage tables
+					 * in lookahead sequence, in  glyph
+					 * sequence order */
+  USHORT	glyphCount;		/* Number of GlyphIDs in the Substitute
+					 * array */
+  GlyphID	substitute[];		/* Array of substitute
+					 * GlyphIDs--ordered by Coverage  Index */
+};
+ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
+
+/*
+ * SubstLookup
+ */
+
+struct SubstLookupSubTable {
+  DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
+
+  friend struct SubstLookup;
+
+  unsigned int get_size (unsigned int lookup_type) const {
+    switch (lookup_type) {
+//    case 1: return u.format1.get_size ();
+//    case 2: return u.format2.get_size ();
+    /*
+    case Single:
+    case Multiple:
+    case Alternate:
+    case Ligature:
+    case Context:
+    case ChainingContext:
+    case Extension:
+    case ReverseChainingContextSingle:
+    */
+    default:return sizeof (LookupSubTable);
+    }
+  }
+
+  inline bool substitute (hb_ot_layout_t *layout,
+			  hb_buffer_t    *buffer,
+			  unsigned int    context_length,
+			  unsigned int    nesting_level_left,
+			  unsigned int    lookup_type) const {
+  }
+
+  private:
+  union {
+  USHORT		substFormat;
+  CoverageFormat1	format1;
+  CoverageFormat2	format2;
+  } u;
+};
+
+struct SubstLookup : Lookup {
+
+  DEFINE_NON_INSTANTIABLE(SubstLookup);
+
+  static const unsigned int Single				= 1;
+  static const unsigned int Multiple				= 2;
+  static const unsigned int Alternate				= 3;
+  static const unsigned int Ligature				= 4;
+  static const unsigned int Context				= 5;
+  static const unsigned int ChainingContext			= 6;
+  static const unsigned int Extension				= 7;
+  static const unsigned int ReverseChainingContextSingle	= 8;
+
+  inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
+    return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
+  }
+
+  /* Like get_type(), but looks through extension lookups.
+   * Never returns SubstLookup::Extension */
+  inline unsigned int get_effective_type (void) const {
+    unsigned int type = get_type ();
+
+    if (HB_UNLIKELY (type == Extension)) {
+      /* Return lookup type of first extension subtable.
+       * The spec says all of them should have the same type.
+       * XXX check for that somehow */
+//XXX      type = get_subtable(0).v.extension.get_type ();
+    }
+
+    return type;
+  }
+
+  inline bool is_reverse (void) const {
+    switch (get_effective_type ()) {
+    case ReverseChainingContextSingle:	return true;
+    default:				return false;
+    }
+  }
+
+  inline bool substitute (hb_ot_layout_t *layout,
+			  hb_buffer_t    *buffer,
+			  unsigned int    context_length,
+			  unsigned int    nesting_level_left) const {
+    unsigned int lookup_type = get_type ();
+
+    if (HB_UNLIKELY (nesting_level_left == 0))
+      return false;
+    nesting_level_left--;
+
+    for (unsigned int i = 0; i < get_subtable_count (); i++)
+      if (get_subtable (i).substitute (layout, buffer,
+				       context_length, nesting_level_left,
+				       lookup_type))
+	return true;
+
+    return false;
+  }
+};
+DEFINE_NULL_ALIAS (SubstLookup, Lookup);
+
+/*
+ * GSUB
+ */
+
+struct GSUB : GSUBGPOS {
+  static const hb_tag_t Tag		= HB_TAG ('G','S','U','B');
+
+  STATIC_DEFINE_GET_FOR_DATA (GSUB);
+  /* XXX check version here? */
+
+  inline const SubstLookup& get_lookup (unsigned int i) const {
+    return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i));
+  }
+
+
+};
+DEFINE_NULL_ALIAS (GSUB, GSUBGPOS);
+
+
+#endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */
diff --git a/src/hb-ot-layout-open-private.h b/src/hb-ot-layout-open-private.h
new file mode 100644
index 0000000..d5ca810
--- /dev/null
+++ b/src/hb-ot-layout-open-private.h
@@ -0,0 +1,993 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#ifndef HB_OT_LAYOUT_OPEN_PRIVATE_H
+#define HB_OT_LAYOUT_OPEN_PRIVATE_H
+
+#ifndef HB_OT_LAYOUT_CC
+#error "This file should only be included from hb-ot-layout.c"
+#endif
+
+#include "hb-ot-layout-private.h"
+
+
+#define NO_INDEX		((unsigned int) 0xFFFF)
+#define NO_CONTEXT		((unsigned int) -1)
+
+/*
+ * Int types
+ */
+
+/* XXX define these as structs of chars on machines that do not allow
+ * unaligned access */
+#define DEFINE_INT_TYPE1(NAME, TYPE, BIG_ENDIAN) \
+  inline NAME& operator = (TYPE i) { v = BIG_ENDIAN(i); return *this; } \
+  inline operator TYPE(void) const { return BIG_ENDIAN(v); } \
+  inline bool operator== (NAME o) const { return v == o.v; } \
+  private: TYPE v; \
+  public:
+#define DEFINE_INT_TYPE0(NAME, type) DEFINE_INT_TYPE1 (NAME, type, hb_be_##type)
+#define DEFINE_INT_TYPE(NAME, u, w)  DEFINE_INT_TYPE0 (NAME, u##int##w##_t)
+#define DEFINE_INT_TYPE_STRUCT(NAME, u, w) \
+  struct NAME { \
+    DEFINE_INT_TYPE(NAME, u, w) \
+  }
+
+/*
+ * Array types
+ */
+
+/* get_len() is a method returning the number of items in an array-like object */
+#define DEFINE_LEN(Type, array, num) \
+  inline unsigned int get_len(void) const { return num; } \
+
+/* get_size() is a method returning the size in bytes of an array-like object */
+#define DEFINE_SIZE(Type, array, num) \
+  inline unsigned int get_size(void) const { return sizeof (*this) + sizeof (Type) * num; }
+
+#define DEFINE_LEN_AND_SIZE(Type, array, num) \
+  DEFINE_LEN(Type, array, num) \
+  DEFINE_SIZE(Type, array, num)
+
+/* An array type is one that contains a variable number of objects
+ * as its last item.  An array object is extended with len() and size()
+ * methods, as well as overloaded [] operator. */
+#define DEFINE_ARRAY_TYPE(Type, array, num) \
+  DEFINE_INDEX_OPERATOR(Type, array, num) \
+  DEFINE_LEN_AND_SIZE(Type, array, num)
+#define DEFINE_INDEX_OPERATOR(Type, array, num) \
+  inline const Type& operator[] (unsigned int i) const { \
+    if (HB_UNLIKELY (i >= num)) return Null##Type; \
+    return array[i]; \
+  }
+
+/* An offset array type is like an array type, but it contains a table
+ * of offsets to the objects, relative to the beginning of the current
+ * object. */
+#define DEFINE_OFFSET_ARRAY_TYPE(Type, array, num) \
+  DEFINE_OFFSET_INDEX_OPERATOR(Type, array, num) \
+  DEFINE_LEN_AND_SIZE(Offset, array, num)
+#define DEFINE_OFFSET_INDEX_OPERATOR(Type, array, num) \
+  inline const Type& operator[] (unsigned int i) const { \
+    if (HB_UNLIKELY (i >= num)) return Null##Type; \
+    if (HB_UNLIKELY (!array[i])) return Null##Type; \
+    return *(const Type *)((const char*)this + array[i]); \
+  }
+
+/* A record array type is like an array type, but it contains a table
+ * of records to the objects.  Each record has a tag, and an offset
+ * relative to the beginning of the current object. */
+#define DEFINE_RECORD_ARRAY_TYPE(Type, array, num) \
+  DEFINE_RECORD_ACCESSOR(Type, array, num) \
+  DEFINE_LEN_AND_SIZE(Record, array, num)
+#define DEFINE_RECORD_ACCESSOR(Type, array, num) \
+  inline const Type& operator[] (unsigned int i) const { \
+    if (HB_UNLIKELY (i >= num)) return Null##Type; \
+    if (HB_UNLIKELY (!array[i].offset)) return Null##Type; \
+    return *(const Type *)((const char*)this + array[i].offset); \
+  } \
+  inline const Tag& get_tag (unsigned int i) const { \
+    if (HB_UNLIKELY (i >= num)) return NullTag; \
+    return array[i].tag; \
+  }
+
+
+#define DEFINE_ARRAY_INTERFACE(Type, name) \
+  inline const Type& get_##name (unsigned int i) const { \
+    return (*this)[i]; \
+  } \
+  inline unsigned int get_##name##_count (void) const { \
+    return this->get_len (); \
+  }
+#define DEFINE_INDEX_ARRAY_INTERFACE(name) \
+  inline unsigned int get_##name##_index (unsigned int i) const { \
+    if (HB_UNLIKELY (i >= get_len ())) return NO_INDEX; \
+    return (*this)[i]; \
+  } \
+  inline unsigned int get_##name##_count (void) const { \
+    return get_len (); \
+  }
+
+
+/*
+ * List types
+ */
+
+#define DEFINE_LIST_ARRAY(Type, name) \
+  inline const Type##List& get_##name##_list (void) const { \
+    if (HB_UNLIKELY (!name##List)) return Null##Type##List; \
+    return *(const Type##List *)((const char*)this + name##List); \
+  }
+
+#define DEFINE_LIST_INTERFACE(Type, name) \
+  inline const Type& get_##name (unsigned int i) const { \
+    return get_##name##_list ()[i]; \
+  } \
+  inline unsigned int get_##name##_count (void) const { \
+    return get_##name##_list ().get_len (); \
+  }
+
+/*
+ * Tag types
+ */
+
+#define DEFINE_TAG_ARRAY_INTERFACE(Type, name) \
+  DEFINE_ARRAY_INTERFACE (Type, name); \
+  inline const Tag& get_##name##_tag (unsigned int i) const { \
+    return (*this)[i].tag; \
+  }
+#define DEFINE_TAG_LIST_INTERFACE(Type, name) \
+  DEFINE_LIST_INTERFACE (Type, name); \
+  inline const Tag& get_##name##_tag (unsigned int i) const { \
+    return get_##name##_list ().get_tag (i); \
+  }
+
+#define DEFINE_TAG_FIND_INTERFACE(Type, name) \
+  inline bool find_##name##_index (hb_tag_t tag, unsigned int *name##_index) const { \
+    const Tag t = tag; \
+    for (unsigned int i = 0; i < get_##name##_count (); i++) { \
+      if (t == get_##name##_tag (i)) { \
+        if (name##_index) *name##_index = i; \
+        return true; \
+      } \
+    } \
+    if (name##_index) *name##_index = NO_INDEX; \
+    return false; \
+  } \
+  inline const Type& get_##name##_by_tag (hb_tag_t tag) const { \
+    unsigned int i; \
+    if (find_##name##_index (tag, &i)) \
+      return get_##name (i); \
+    else \
+      return Null##Type; \
+  }
+
+/*
+ * Class features
+ */
+
+/* makes class uninstantiable.  should be used for union classes that don't
+ * contain any complete type */
+#define DEFINE_NON_INSTANTIABLE(Type) \
+  protected: inline Type() {} /* cannot be instantiated */ \
+  public:
+
+// TODO use a global nul-array for most Null's
+/* defines Null##Type as a safe nil instance of Type */
+#define DEFINE_NULL_DATA(Type, size, data) \
+  static const unsigned char Null##Type##Data[size] = data; \
+  DEFINE_NULL_ALIAS (Type, Type)
+#define DEFINE_NULL(Type, size) \
+	DEFINE_NULL_DATA(Type, size, "")
+#define DEFINE_NULL_ASSERT_SIZE(Type, size) \
+	DEFINE_NULL_ASSERT_SIZE_DATA(Type, size, "")
+#define DEFINE_NULL_ASSERT_SIZE_DATA(Type, size, data) \
+  ASSERT_SIZE (Type, size); \
+  DEFINE_NULL_DATA (Type, size, data)
+#define DEFINE_NULL_ALIAS(NewType, OldType) \
+  /* XXX static */ const NewType &Null##NewType = *(NewType *)Null##OldType##Data
+
+/* get_for_data() is a static class method returning a reference to an
+ * instance of Type located at the input data location.  It's just a
+ * fancy, NULL-safe, cast! */
+#define STATIC_DEFINE_GET_FOR_DATA(Type) \
+  static inline const Type& get_for_data (const char *data) { \
+    extern const Type &Null##Type; \
+    if (HB_UNLIKELY (data == NULL)) return Null##Type; \
+    return *(const Type*)data; \
+  } \
+  static inline Type& get_for_data (char *data) { \
+    return *(Type*)data; \
+  }
+
+
+#define DEFINE_GET_ACCESSOR(Type, name, Name) \
+  inline const Type& get_##name (void) const { \
+    if (HB_UNLIKELY (!Name)) return Null##Type; \
+    return *(const Type*)((const char*)this + Name); \
+  }
+#define DEFINE_GET_HAS_ACCESSOR(Type, name, Name) \
+  DEFINE_GET_ACCESSOR (Type, name, Name); \
+  inline bool has_##name (void) const { \
+    return Name != 0; \
+  }
+
+
+
+
+/*
+ *
+ * The OpenType Font File
+ *
+ */
+
+
+
+/*
+ * Data Types
+ */
+
+
+/* "The following data types are used in the OpenType font file.
+ *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
+
+
+DEFINE_INT_TYPE_STRUCT (BYTE,	 u,  8);	/*  8-bit unsigned integer. */
+DEFINE_NULL_ASSERT_SIZE (BYTE, 1);
+DEFINE_INT_TYPE_STRUCT (CHAR,	  ,  8);	/*  8-bit signed integer. */
+DEFINE_NULL_ASSERT_SIZE (CHAR, 1);
+DEFINE_INT_TYPE_STRUCT (USHORT,  u, 16);	/* 16-bit unsigned integer. */
+DEFINE_NULL_ASSERT_SIZE (USHORT, 2);
+DEFINE_INT_TYPE_STRUCT (SHORT,	  , 16);	/* 16-bit signed integer. */
+DEFINE_NULL_ASSERT_SIZE (SHORT, 2);
+DEFINE_INT_TYPE_STRUCT (ULONG,	 u, 32);	/* 32-bit unsigned integer. */
+DEFINE_NULL_ASSERT_SIZE (ULONG, 4);
+DEFINE_INT_TYPE_STRUCT (LONG,	  , 32);	/* 32-bit signed integer. */
+DEFINE_NULL_ASSERT_SIZE (LONG, 4);
+
+/* Date represented in number of seconds since 12:00 midnight, January 1,
+ * 1904. The value is represented as a signed 64-bit integer. */
+DEFINE_INT_TYPE_STRUCT (LONGDATETIME, , 64);
+
+/* 32-bit signed fixed-point number (16.16) */
+struct Fixed {
+  inline Fixed& operator = (int32_t v) { i = (int16_t) (v >> 16); f = (uint16_t) v; return *this; } \
+  inline operator int32_t(void) const { return (((int32_t) i) << 16) + (uint16_t) f; } \
+  inline bool operator== (Fixed o) const { return i == o.i && f == o.f; } \
+
+  inline operator double(void) const { return (uint32_t) this / 65536.; }
+  inline int16_t int_part (void) const { return i; }
+  inline uint16_t frac_part (void) const { return f; }
+
+  private:
+  SHORT i;
+  USHORT f;
+};
+DEFINE_NULL_ASSERT_SIZE (Fixed, 4);
+
+/* Smallest measurable distance in the em space. */
+struct FUNIT;
+
+/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
+struct FWORD : SHORT {
+};
+DEFINE_NULL_ASSERT_SIZE (FWORD, 2);
+
+/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
+struct UFWORD : USHORT {
+};
+DEFINE_NULL_ASSERT_SIZE (UFWORD, 2);
+
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+struct F2DOT14 : SHORT {
+  inline operator double() const { return (uint32_t) this / 16384.; }
+};
+DEFINE_NULL_ASSERT_SIZE (F2DOT14, 2);
+
+/* Array of four uint8s (length = 32 bits) used to identify a script, language
+ * system, feature, or baseline */
+struct Tag {
+  inline Tag (void) { v[0] = v[1] = v[2] = v[3] = 0; }
+  inline Tag (uint32_t v) { (ULONG&)(*this) = v; }
+  inline Tag (const char *c) { v[0] = c[0]; v[1] = c[1]; v[2] = c[2]; v[3] = c[3]; }
+  inline bool operator== (Tag o) const { return v[0]==o.v[0]&&v[1]==o.v[1]&&v[2]==o.v[2]&&v[3]==o.v[3]; }
+  inline bool operator== (const char *c) const { return v[0]==c[0]&&v[1]==c[1]&&v[2]==c[2]&&v[3]==c[3]; }
+  inline bool operator== (uint32_t i) const { return i == (uint32_t) *this; }
+  inline operator uint32_t(void) const { return (v[0]<<24)+(v[1]<<16) +(v[2]<<8)+v[3]; }
+  /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
+  inline operator const char* (void) const { return (const char *)this; }
+  inline operator char* (void) { return (char *)this; }
+
+  private:
+  char v[4];
+};
+ASSERT_SIZE (Tag, 4);
+DEFINE_NULL_DATA (Tag, 5, "    ");
+
+/* Glyph index number, same as uint16 (length = 16 bits) */
+DEFINE_INT_TYPE_STRUCT (GlyphID, u, 16);
+DEFINE_NULL_ASSERT_SIZE (GlyphID, 2);
+
+/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
+DEFINE_INT_TYPE_STRUCT (Offset, u, 16);
+DEFINE_NULL_ASSERT_SIZE (Offset, 2);
+
+/* CheckSum */
+struct CheckSum : ULONG {
+  static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length) {
+    uint32_t Sum = 0L;
+    ULONG *EndPtr = Table+((Length+3) & ~3) / sizeof(ULONG);
+
+    while (Table < EndPtr)
+      Sum += *Table++;
+    return Sum;
+  }
+};
+DEFINE_NULL_ASSERT_SIZE (CheckSum, 4);
+
+
+/*
+ * Version Numbers
+ */
+
+struct USHORT_Version : USHORT {
+};
+DEFINE_NULL_ASSERT_SIZE (USHORT_Version, 2);
+
+struct Fixed_Version : Fixed {
+  inline int16_t major (void) const { return this->int_part(); }
+  inline int16_t minor (void) const { return this->frac_part(); }
+};
+DEFINE_NULL_ASSERT_SIZE (Fixed_Version, 4);
+
+
+/*
+ * Organization of an OpenType Font
+ */
+
+struct OpenTypeFontFile;
+struct OffsetTable;
+struct TTCHeader;
+
+typedef struct TableDirectory {
+
+  friend struct OpenTypeFontFile;
+  friend struct OffsetTable;
+
+  inline bool is_null (void) const { return length == 0; }
+  inline const Tag& get_tag (void) const { return tag; }
+  inline unsigned long get_checksum (void) const { return checkSum; }
+  inline unsigned long get_offset (void) const { return offset; }
+  inline unsigned long get_length (void) const { return length; }
+
+  private:
+  Tag		tag;		/* 4-byte identifier. */
+  CheckSum	checkSum;	/* CheckSum for this table. */
+  ULONG		offset;		/* Offset from beginning of TrueType font
+				 * file. */
+  ULONG		length;		/* Length of this table. */
+} OpenTypeTable;
+DEFINE_NULL_ASSERT_SIZE (TableDirectory, 16);
+DEFINE_NULL_ALIAS (OpenTypeTable, TableDirectory);
+
+typedef struct OffsetTable {
+
+  friend struct OpenTypeFontFile;
+  friend struct TTCHeader;
+
+  DEFINE_TAG_ARRAY_INTERFACE (OpenTypeTable, table);	/* get_table_count(), get_table(i), get_table_tag(i) */
+  DEFINE_TAG_FIND_INTERFACE  (OpenTypeTable, table);	/* find_table_index(tag), get_table_by_tag(tag) */
+
+  private:
+  /* OpenTypeTables, in no particular order */
+  DEFINE_ARRAY_TYPE (TableDirectory, tableDir, numTables);
+
+  private:
+  Tag		sfnt_version;	/* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
+  USHORT	numTables;	/* Number of tables. */
+  USHORT	searchRange;	/* (Maximum power of 2 <= numTables) x 16 */
+  USHORT	entrySelector;	/* Log2(maximum power of 2 <= numTables). */
+  USHORT	rangeShift;	/* NumTables x 16-searchRange. */
+  TableDirectory tableDir[];	/* TableDirectory entries. numTables items */
+} OpenTypeFontFace;
+DEFINE_NULL_ASSERT_SIZE (OffsetTable, 12);
+DEFINE_NULL_ALIAS (OpenTypeFontFace, OffsetTable);
+
+/*
+ * TrueType Collections
+ */
+
+struct TTCHeader {
+
+  friend struct OpenTypeFontFile;
+
+  private:
+  /* OpenTypeFontFaces, in no particular order */
+  DEFINE_OFFSET_ARRAY_TYPE (OffsetTable, offsetTable, numFonts);
+  /* XXX check version here? */
+
+  private:
+  Tag	ttcTag;		/* TrueType Collection ID string: 'ttcf' */
+  ULONG	version;	/* Version of the TTC Header (1.0 or 2.0),
+			 * 0x00010000 or 0x00020000 */
+  ULONG	numFonts;	/* Number of fonts in TTC */
+  ULONG	offsetTable[];	/* Array of offsets to the OffsetTable for each font
+			 * from the beginning of the file */
+};
+DEFINE_NULL_ASSERT_SIZE (TTCHeader, 12);
+
+
+/*
+ * OpenType Font File
+ */
+
+struct OpenTypeFontFile {
+  DEFINE_NON_INSTANTIABLE(OpenTypeFontFile);
+  static const hb_tag_t TrueTypeTag	= HB_TAG ( 0 , 1 , 0 , 0 );
+  static const hb_tag_t CFFTag		= HB_TAG ('O','T','T','O');
+  static const hb_tag_t TTCTag		= HB_TAG ('t','t','c','f');
+
+  STATIC_DEFINE_GET_FOR_DATA (OpenTypeFontFile);
+
+  DEFINE_ARRAY_INTERFACE (OpenTypeFontFace, face);	/* get_face_count(), get_face(i) */
+
+  inline const Tag& get_tag (void) const { return tag; }
+
+  /* This is how you get a table */
+  inline const char* get_table_data (const OpenTypeTable& table) const {
+    return (*this)[table];
+  }
+  inline char* get_table_data (const OpenTypeTable& table) {
+    return (*this)[table];
+  }
+
+  private:
+  inline const char* operator[] (const OpenTypeTable& table) const {
+    if (G_UNLIKELY (table.offset == 0)) return NULL;
+    return ((const char*)this) + table.offset;
+  }
+  inline char* operator[] (const OpenTypeTable& table) {
+    if (G_UNLIKELY (table.offset == 0)) return NULL;
+    return ((char*)this) + table.offset;
+  }
+
+  /* Array interface sans get_size() */
+  unsigned int get_len (void) const {
+    switch (tag) {
+    default: return 0;
+    case TrueTypeTag: case CFFTag: return 1;
+    case TTCTag: return ((const TTCHeader&)*this).get_len();
+    }
+  }
+  const OpenTypeFontFace& operator[] (unsigned int i) const {
+    if (HB_UNLIKELY (i >= get_len ())) return NullOpenTypeFontFace;
+    switch (tag) {
+    default: case TrueTypeTag: case CFFTag: return (const OffsetTable&)*this;
+    case TTCTag: return ((const TTCHeader&)*this)[i];
+    }
+  }
+
+  private:
+  Tag		tag;		/* 4-byte identifier. */
+};
+DEFINE_NULL_ASSERT_SIZE (OpenTypeFontFile, 4);
+
+
+
+/*
+ *
+ * OpenType Layout Common Table Formats
+ *
+ */
+
+/*
+ * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
+ */
+
+typedef struct Record {
+  Tag		tag;		/* 4-byte Tag identifier */
+  Offset	offset;		/* Offset from beginning of object holding
+				 * the Record */
+} ScriptRecord, LangSysRecord, FeatureRecord;
+DEFINE_NULL_ASSERT_SIZE (Record, 6);
+
+struct LangSys {
+
+  DEFINE_INDEX_ARRAY_INTERFACE (feature);
+
+  inline const bool has_required_feature (void) const {
+    return reqFeatureIndex != 0xffff;
+  }
+  /* Returns NO_INDEX if none */
+  inline int get_required_feature_index (void) const {
+    if (reqFeatureIndex == 0xffff)
+      return NO_INDEX;
+    return reqFeatureIndex;;
+  }
+
+  private:
+  /* Feature indices, in no particular order */
+  DEFINE_ARRAY_TYPE (USHORT, featureIndex, featureCount);
+
+  private:
+  Offset	lookupOrder;	/* = Null (reserved for an offset to a
+				 * reordering table) */
+  USHORT	reqFeatureIndex;/* Index of a feature required for this
+				 * language system--if no required features
+				 * = 0xFFFF */
+  USHORT	featureCount;	/* Number of FeatureIndex values for this
+				 * language system--excludes the required
+				 * feature */
+  USHORT	featureIndex[];	/* Array of indices into the FeatureList--in
+				 * arbitrary order. featureCount entires long */
+};
+DEFINE_NULL_ASSERT_SIZE_DATA (LangSys, 6, "\0\0\xFF\xFF");
+
+struct Script {
+
+  /* DEFINE_ARRAY_INTERFACE (LangSys, lang_sys) but handling defaultLangSys */
+
+  inline const LangSys& get_lang_sys (unsigned int i) const {
+    if (i == NO_INDEX) return get_default_lang_sys ();
+    return (*this)[i];
+  }
+  inline unsigned int get_lang_sys_count (void) const {
+    return this->get_len ();
+  }
+
+  inline const Tag& get_lang_sys_tag (unsigned int i) const {
+    return get_tag (i);
+  }
+
+  // LONGTERMTODO bsearch
+  DEFINE_TAG_FIND_INTERFACE (LangSys, lang_sys);	/* find_lang_sys_index (), get_lang_sys_by_tag (tag) */
+
+  inline const bool has_default_lang_sys (void) const {
+    return defaultLangSys != 0;
+  }
+  inline const LangSys& get_default_lang_sys (void) const {
+    if (HB_UNLIKELY (!defaultLangSys))
+      return NullLangSys;
+    return *(LangSys*)((const char*)this + defaultLangSys);
+  }
+
+  private:
+  /* LangSys', in sorted alphabetical tag order */
+  DEFINE_RECORD_ARRAY_TYPE (LangSys, langSysRecord, langSysCount);
+
+  private:
+  Offset	defaultLangSys;	/* Offset to DefaultLangSys table--from
+				 * beginning of Script table--may be Null */
+  USHORT	langSysCount;	/* Number of LangSysRecords for this script--
+				 * excluding the DefaultLangSys */
+  LangSysRecord	langSysRecord[];/* Array of LangSysRecords--listed
+				 * alphabetically by LangSysTag */
+};
+DEFINE_NULL_ASSERT_SIZE (Script, 4);
+
+struct ScriptList {
+
+  friend struct GSUBGPOS;
+
+private:
+  /* Scripts, in sorted alphabetical tag order */
+  DEFINE_RECORD_ARRAY_TYPE (Script, scriptRecord, scriptCount);
+
+private:
+  USHORT	scriptCount;	/* Number of ScriptRecords */
+  ScriptRecord	scriptRecord[]; /* Array of ScriptRecords--listed alphabetically
+				 * by ScriptTag */
+};
+DEFINE_NULL_ASSERT_SIZE (ScriptList, 2);
+
+struct Feature {
+
+  DEFINE_INDEX_ARRAY_INTERFACE (lookup);	/* get_lookup_count(), get_lookup_index(i) */
+
+  private:
+  /* LookupList indices, in no particular order */
+  DEFINE_ARRAY_TYPE (USHORT, lookupIndex, lookupCount);
+
+  /* TODO: implement get_feature_parameters() */
+  /* TODO: implement FeatureSize and other special features? */
+
+  private:
+  Offset	featureParams;	/* Offset to Feature Parameters table (if one
+				 * has been defined for the feature), relative
+				 * to the beginning of the Feature Table; = Null
+				 * if not required */
+  USHORT	lookupCount;	/* Number of LookupList indices for this
+				 * feature */
+  USHORT	lookupIndex[];	/* Array of LookupList indices for this
+				 * feature--zero-based (first lookup is
+				 * LookupListIndex = 0) */
+};
+DEFINE_NULL_ASSERT_SIZE (Feature, 4);
+
+struct FeatureList {
+
+  friend struct GSUBGPOS;
+
+  private:
+  /* Feature indices, in sorted alphabetical tag order */
+  DEFINE_RECORD_ARRAY_TYPE (Feature, featureRecord, featureCount);
+
+  private:
+  USHORT	featureCount;	/* Number of FeatureRecords in this table */
+  FeatureRecord	featureRecord[];/* Array of FeatureRecords--zero-based (first
+				 * feature has FeatureIndex = 0)--listed
+				 * alphabetically by FeatureTag */
+};
+DEFINE_NULL_ASSERT_SIZE (FeatureList, 2);
+
+struct LookupFlag : USHORT {
+  static const unsigned int RightToLeft		= 0x0001u;
+  static const unsigned int IgnoreBaseGlyphs	= 0x0002u;
+  static const unsigned int IgnoreLigatures	= 0x0004u;
+  static const unsigned int IgnoreMarks		= 0x0008u;
+  static const unsigned int Reserved		= 0x00F0u;
+  static const unsigned int MarkAttachmentType	= 0xFF00u;
+};
+DEFINE_NULL_ASSERT_SIZE (LookupFlag, 2);
+
+struct LookupSubTable {
+  DEFINE_NON_INSTANTIABLE(LookupSubTable);
+
+  private:
+  USHORT	format;		/* Subtable format.  Different for GSUB and GPOS */
+};
+DEFINE_NULL_ASSERT_SIZE (LookupSubTable, 2);
+
+
+struct Lookup {
+  DEFINE_NON_INSTANTIABLE(Lookup);
+
+  DEFINE_ARRAY_INTERFACE (LookupSubTable, subtable);	/* get_subtable_count(), get_subtable(i) */
+
+  inline bool is_right_to_left	(void) const { return lookupFlag & LookupFlag::RightToLeft; }
+  inline bool ignore_base_glyphs(void) const { return lookupFlag & LookupFlag::IgnoreBaseGlyphs; }
+  inline bool ignore_ligatures	(void) const { return lookupFlag & LookupFlag::IgnoreLigatures; }
+  inline bool ignore_marks	(void) const { return lookupFlag & LookupFlag::IgnoreMarks; }
+  inline bool get_mark_attachment_type (void) const { return lookupFlag & LookupFlag::MarkAttachmentType; }
+
+  inline unsigned int get_type (void) const { return lookupType; }
+  inline unsigned int get_flag (void) const { return lookupFlag; }
+
+  private:
+  /* SubTables, in the desired order */
+  DEFINE_OFFSET_ARRAY_TYPE (LookupSubTable, subTableOffset, subTableCount);
+
+  protected:
+  USHORT	lookupType;	/* Different enumerations for GSUB and GPOS */
+  USHORT	lookupFlag;	/* Lookup qualifiers */
+  USHORT	subTableCount;	/* Number of SubTables for this lookup */
+  Offset	subTableOffset[];/* Array of offsets to SubTables-from
+				  * beginning of Lookup table */
+};
+DEFINE_NULL_ASSERT_SIZE (Lookup, 6);
+
+struct LookupList {
+
+  friend struct GSUBGPOS;
+
+  private:
+  /* Lookup indices, in sorted alphabetical tag order */
+  DEFINE_OFFSET_ARRAY_TYPE (Lookup, lookupOffset, lookupCount);
+
+  private:
+  USHORT	lookupCount;	/* Number of lookups in this table */
+  Offset	lookupOffset[];	/* Array of offsets to Lookup tables--from
+				 * beginning of LookupList--zero based (first
+				 * lookup is Lookup index = 0) */
+};
+DEFINE_NULL_ASSERT_SIZE (LookupList, 2);
+
+/*
+ * Coverage Table
+ */
+
+struct CoverageFormat1 {
+
+  friend struct Coverage;
+
+  private:
+  /* GlyphIDs, in sorted numerical order */
+  DEFINE_ARRAY_TYPE (GlyphID, glyphArray, glyphCount);
+
+  inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+    GlyphID gid;
+    if (HB_UNLIKELY (glyph_id > 65535))
+      return -1;
+    gid = glyph_id;
+    // TODO: bsearch
+    for (unsigned int i = 0; i < glyphCount; i++)
+      if (gid == glyphArray[i])
+        return i;
+    return -1;
+  }
+
+  private:
+  USHORT	coverageFormat;	/* Format identifier--format = 1 */
+  USHORT	glyphCount;	/* Number of glyphs in the GlyphArray */
+  GlyphID	glyphArray[];	/* Array of GlyphIDs--in numerical order */
+};
+ASSERT_SIZE (CoverageFormat1, 4);
+
+struct CoverageRangeRecord {
+
+  friend struct CoverageFormat2;
+
+  private:
+  inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+    if (glyph_id >= start && glyph_id <= end)
+      return startCoverageIndex + (glyph_id - start);
+    return -1;
+  }
+
+  private:
+  GlyphID	start;			/* First GlyphID in the range */
+  GlyphID	end;			/* Last GlyphID in the range */
+  USHORT	startCoverageIndex;	/* Coverage Index of first GlyphID in
+					 * range */
+};
+DEFINE_NULL_ASSERT_SIZE_DATA (CoverageRangeRecord, 6, "\001");
+
+struct CoverageFormat2 {
+
+  friend struct Coverage;
+
+  private:
+  /* CoverageRangeRecords, in sorted numerical start order */
+  DEFINE_ARRAY_TYPE (CoverageRangeRecord, rangeRecord, rangeCount);
+
+  inline hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+    // TODO: bsearch
+    for (unsigned int i = 0; i < rangeCount; i++) {
+      int coverage = rangeRecord[i].get_coverage (glyph_id);
+      if (coverage >= 0)
+        return coverage;
+    }
+    return -1;
+  }
+
+  private:
+  USHORT		coverageFormat;	/* Format identifier--format = 2 */
+  USHORT		rangeCount;	/* Number of CoverageRangeRecords */
+  CoverageRangeRecord	rangeRecord[];	/* Array of glyph ranges--ordered by
+					 * Start GlyphID. rangeCount entries
+					 * long */
+};
+ASSERT_SIZE (CoverageFormat2, 4);
+
+struct Coverage {
+  DEFINE_NON_INSTANTIABLE(Coverage);
+
+  unsigned int get_size (void) const {
+    switch (u.coverageFormat) {
+    case 1: return u.format1.get_size ();
+    case 2: return u.format2.get_size ();
+    default:return sizeof (u.coverageFormat);
+    }
+  }
+
+  hb_ot_layout_coverage_t get_coverage (hb_codepoint_t glyph_id) const {
+    switch (u.coverageFormat) {
+    case 1: return u.format1.get_coverage(glyph_id);
+    case 2: return u.format2.get_coverage(glyph_id);
+    default:return -1;
+    }
+  }
+
+  private:
+  union {
+  USHORT		coverageFormat;	/* Format identifier */
+  CoverageFormat1	format1;
+  CoverageFormat2	format2;
+  } u;
+};
+DEFINE_NULL (Coverage, 2);
+
+/*
+ * Class Definition Table
+ */
+
+struct ClassDefFormat1 {
+
+  friend struct ClassDef;
+
+  private:
+  /* GlyphIDs, in sorted numerical order */
+  DEFINE_ARRAY_TYPE (USHORT, classValueArray, glyphCount);
+
+  inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+    if (glyph_id >= startGlyph && glyph_id - startGlyph < glyphCount)
+      return classValueArray[glyph_id - startGlyph];
+    return 0;
+  }
+
+  private:
+  USHORT	classFormat;		/* Format identifier--format = 1 */
+  GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
+  USHORT	glyphCount;		/* Size of the classValueArray */
+  USHORT	classValueArray[];	/* Array of Class Values--one per GlyphID */
+};
+ASSERT_SIZE (ClassDefFormat1, 6);
+
+struct ClassRangeRecord {
+
+  friend struct ClassDefFormat2;
+
+  private:
+  inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+    if (glyph_id >= start && glyph_id <= end)
+      return classValue;
+    return 0;
+  }
+
+  private:
+  GlyphID	start;		/* First GlyphID in the range */
+  GlyphID	end;		/* Last GlyphID in the range */
+  USHORT	classValue;	/* Applied to all glyphs in the range */
+};
+DEFINE_NULL_ASSERT_SIZE_DATA (ClassRangeRecord, 6, "\001");
+
+struct ClassDefFormat2 {
+
+  friend struct ClassDef;
+
+  private:
+  /* ClassRangeRecords, in sorted numerical start order */
+  DEFINE_ARRAY_TYPE (ClassRangeRecord, rangeRecord, rangeCount);
+
+  inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+    // TODO: bsearch
+    for (unsigned int i = 0; i < rangeCount; i++) {
+      int classValue = rangeRecord[i].get_class (glyph_id);
+      if (classValue > 0)
+        return classValue;
+    }
+    return 0;
+  }
+
+  private:
+  USHORT		classFormat;	/* Format identifier--format = 2 */
+  USHORT		rangeCount;	/* Number of Number of ClassRangeRecords */
+  ClassRangeRecord	rangeRecord[];	/* Array of glyph ranges--ordered by
+					 * Start GlyphID */
+};
+ASSERT_SIZE (ClassDefFormat2, 4);
+
+struct ClassDef {
+  DEFINE_NON_INSTANTIABLE(ClassDef);
+
+  unsigned int get_size (void) const {
+    switch (u.classFormat) {
+    case 1: return u.format1.get_size ();
+    case 2: return u.format2.get_size ();
+    default:return sizeof (u.classFormat);
+    }
+  }
+
+  hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const {
+    switch (u.classFormat) {
+    case 1: return u.format1.get_class(glyph_id);
+    case 2: return u.format2.get_class(glyph_id);
+    default:return 0;
+    }
+  }
+
+  private:
+  union {
+  USHORT		classFormat;	/* Format identifier */
+  ClassDefFormat1	format1;
+  ClassDefFormat2	format2;
+  } u;
+};
+DEFINE_NULL (ClassDef, 2);
+
+/*
+ * Device Tables
+ */
+
+struct Device {
+  DEFINE_NON_INSTANTIABLE(Device);
+
+   unsigned int get_size (void) const {
+    int count = endSize - startSize + 1;
+    if (count < 0) count = 0;
+    switch (deltaFormat) {
+    case 1: return sizeof (Device) + sizeof (USHORT) * ((count+7)/8);
+    case 2: return sizeof (Device) + sizeof (USHORT) * ((count+3)/4);
+    case 3: return sizeof (Device) + sizeof (USHORT) * ((count+1)/2);
+    default:return sizeof (Device);
+    }
+  }
+
+  int get_delta (int ppem_size) const {
+    if (ppem_size >= startSize && ppem_size <= endSize &&
+        deltaFormat >= 1 && deltaFormat <= 3) {
+      int s = ppem_size - startSize;
+      int f = deltaFormat;
+
+      uint16_t byte = deltaValue[s >> (4 - f)];
+      uint16_t bits = byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f));
+      uint16_t mask = 0xFFFF >> (16 - (1 << f));
+
+      int delta = bits & mask;
+
+      if (delta >= ((mask + 1) >> 1))
+        delta -= mask + 1;
+
+      return delta;
+    }
+    return 0;
+  }
+
+  private:
+  USHORT	startSize;	/* Smallest size to correct--in ppem */
+  USHORT	endSize;	/* Largest size to correct--in ppem */
+  USHORT	deltaFormat;	/* Format of DeltaValue array data: 1, 2, or 3 */
+  USHORT	deltaValue[];	/* Array of compressed data */
+};
+DEFINE_NULL_ASSERT_SIZE (Device, 6);
+
+/*
+ * GSUB/GPOS Common
+ */
+
+struct GSUBGPOS {
+  static const hb_tag_t GSUBTag		= HB_TAG ('G','S','U','B');
+  static const hb_tag_t GPOSTag		= HB_TAG ('G','P','O','S');
+
+  STATIC_DEFINE_GET_FOR_DATA (GSUBGPOS);
+  /* XXX check version here? */
+
+  DEFINE_TAG_LIST_INTERFACE (Script,  script );	/* get_script_count (), get_script (i), get_script_tag (i) */
+  DEFINE_TAG_LIST_INTERFACE (Feature, feature);	/* get_feature_count(), get_feature(i), get_feature_tag(i) */
+  DEFINE_LIST_INTERFACE     (Lookup,  lookup );	/* get_lookup_count (), get_lookup (i) */
+
+  // LONGTERMTODO bsearch
+  DEFINE_TAG_FIND_INTERFACE (Script,  script );	/* find_script_index (), get_script_by_tag (tag) */
+  DEFINE_TAG_FIND_INTERFACE (Feature, feature);	/* find_feature_index(), get_feature_by_tag(tag) */
+
+  private:
+  DEFINE_LIST_ARRAY(Script,  script);
+  DEFINE_LIST_ARRAY(Feature, feature);
+  DEFINE_LIST_ARRAY(Lookup,  lookup);
+
+  private:
+  Fixed_Version	version;	/* Version of the GSUB/GPOS table--initially set
+				 * to 0x00010000 */
+  Offset	scriptList;  	/* Offset to ScriptList table--from beginning of
+				 * GSUB/GPOS table */
+  Offset	featureList; 	/* Offset to FeatureList table--from beginning of
+				 * GSUB/GPOS table */
+  Offset	lookupList; 	/* Offset to LookupList table--from beginning of
+				 * GSUB/GPOS table */
+};
+DEFINE_NULL_ASSERT_SIZE (GSUBGPOS, 10);
+
+#endif /* HB_OT_LAYOUT_OPEN_PRIVATE_H */
diff --git a/src/hb-ot-layout-private.h b/src/hb-ot-layout-private.h
new file mode 100644
index 0000000..a1be8aa
--- /dev/null
+++ b/src/hb-ot-layout-private.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#ifndef HB_OT_LAYOUT_PRIVATE_H
+#define HB_OT_LAYOUT_PRIVATE_H
+
+#include "hb-private.h"
+#include "hb-ot-layout.h"
+
+/* XXX */
+#include "harfbuzz-buffer.h"
+
+
+typedef uint16_t hb_ot_layout_class_t;
+typedef uint16_t hb_ot_layout_glyph_properties_t;
+typedef uint16_t hb_ot_layout_lookup_flags_t;
+typedef int hb_ot_layout_coverage_t;	/* -1 is not covered, >= 0 otherwise */
+
+/* XXX #define HB_OT_LAYOUT_INTERNAL static */
+#define HB_OT_LAYOUT_INTERNAL
+
+HB_BEGIN_DECLS();
+
+/*
+ * GDEF
+ */
+
+HB_OT_LAYOUT_INTERNAL hb_bool_t
+_hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout);
+
+HB_OT_LAYOUT_INTERNAL hb_ot_layout_glyph_properties_t
+_hb_ot_layout_get_glyph_properties (hb_ot_layout_t *layout,
+				    hb_codepoint_t  glyph);
+
+HB_OT_LAYOUT_INTERNAL hb_bool_t
+_hb_ot_layout_check_glyph_properties (hb_ot_layout_t                  *layout,
+				      HB_GlyphItem                     gitem,
+				      hb_ot_layout_lookup_flags_t      lookup_flags,
+				      hb_ot_layout_glyph_properties_t *property);
+
+HB_END_DECLS();
+
+#endif /* HB_OT_LAYOUT_PRIVATE_H */
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
new file mode 100644
index 0000000..01923db
--- /dev/null
+++ b/src/hb-ot-layout.cc
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 1998-2004  David Turner and Werner Lemberg
+ * Copyright (C) 2006  Behdad Esfahbod
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#define HB_OT_LAYOUT_CC
+
+#include "hb-ot-layout.h"
+#include "hb-ot-layout-private.h"
+
+#include "hb-ot-layout-open-private.h"
+#include "hb-ot-layout-gdef-private.h"
+#include "hb-ot-layout-gsub-private.h"
+
+/* XXX */
+#include "harfbuzz-buffer-private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+struct _hb_ot_layout_t {
+  const GDEF *gdef;
+  const GSUB *gsub;
+  const /*XXX*/GSUBGPOS *gpos;
+
+  struct {
+    unsigned char *klasses;
+    unsigned int len;
+  } new_gdef;
+
+  /* TODO add max-nesting-level here? */
+};
+
+hb_ot_layout_t *
+hb_ot_layout_create (void)
+{
+  hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
+
+  layout->gdef = &NullGDEF;
+  layout->gsub = &NullGSUB;
+  layout->gpos = &/*XXX*/NullGSUBGPOS;
+
+  return layout;
+}
+
+hb_ot_layout_t *
+hb_ot_layout_create_for_data (const char *font_data,
+			      int         face_index)
+{
+  hb_ot_layout_t *layout;
+
+  if (HB_UNLIKELY (font_data == NULL))
+    return hb_ot_layout_create ();
+
+  layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
+
+  const OpenTypeFontFile &font = OpenTypeFontFile::get_for_data (font_data);
+  const OpenTypeFontFace &face = font.get_face (face_index);
+
+  layout->gdef = &GDEF::get_for_data (font.get_table_data (face.get_table_by_tag (GDEF::Tag)));
+  layout->gsub = &GSUB::get_for_data (font.get_table_data (face.get_table_by_tag (GSUB::Tag)));
+  layout->gpos = &/*XXX*/GSUBGPOS::get_for_data (font.get_table_data (face.get_table_by_tag (/*XXX*/GSUBGPOS::GPOSTag)));
+
+  return layout;
+}
+
+void
+hb_ot_layout_destroy (hb_ot_layout_t *layout)
+{
+  free (layout);
+}
+
+/*
+ * GDEF
+ */
+
+hb_bool_t
+hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout)
+{
+  return layout->gdef->has_glyph_classes ();
+}
+
+HB_OT_LAYOUT_INTERNAL hb_bool_t
+_hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout)
+{
+  return layout->new_gdef.len > 0;
+}
+
+HB_OT_LAYOUT_INTERNAL hb_ot_layout_glyph_properties_t
+_hb_ot_layout_get_glyph_properties (hb_ot_layout_t *layout,
+				    hb_codepoint_t  glyph)
+{
+  hb_ot_layout_class_t klass;
+
+  /* TODO old harfbuzz doesn't always parse mark attachments as it says it was
+   * introduced without a version bump, so it may not be safe */
+  klass = layout->gdef->get_mark_attachment_type (glyph);
+  if (klass)
+    return klass << 8;
+
+  klass = layout->gdef->get_glyph_class (glyph);
+
+  if (!klass && glyph < layout->new_gdef.len)
+    klass = layout->new_gdef.klasses[glyph];
+
+  switch (klass) {
+  default:
+  case GDEF::UnclassifiedGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
+  case GDEF::BaseGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
+  case GDEF::LigatureGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
+  case GDEF::MarkGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
+  case GDEF::ComponentGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
+  }
+}
+
+HB_OT_LAYOUT_INTERNAL hb_bool_t
+_hb_ot_layout_check_glyph_properties (hb_ot_layout_t                  *layout,
+				      HB_GlyphItem                     gitem,
+				      hb_ot_layout_lookup_flags_t      lookup_flags,
+				      hb_ot_layout_glyph_properties_t *property)
+{
+  hb_ot_layout_glyph_class_t basic_glyph_class;
+  hb_ot_layout_glyph_properties_t desired_attachment_class;
+
+  if (gitem->gproperties == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
+  {
+    gitem->gproperties = *property = _hb_ot_layout_get_glyph_properties (layout, gitem->gindex);
+    if (gitem->gproperties == HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED)
+      return false;
+  }
+
+  *property = gitem->gproperties;
+
+  /* If the glyph was found in the MarkAttachmentClass table,
+   * then that class value is the high byte of the result,
+   * otherwise the low byte contains the basic type of the glyph
+   * as defined by the GlyphClassDef table.
+   */
+  if (*property & LookupFlag::MarkAttachmentType)
+    basic_glyph_class = HB_OT_LAYOUT_GLYPH_CLASS_MARK;
+  else
+    basic_glyph_class = (hb_ot_layout_glyph_class_t) *property;
+
+  /* Not covered, if, for example, basic_glyph_class
+   * is HB_GDEF_LIGATURE and lookup_flags includes LookupFlags::IgnoreLigatures
+   */
+  if (lookup_flags & basic_glyph_class)
+    return false;
+
+  /* The high byte of lookup_flags has the meaning
+   * "ignore marks of attachment type different than
+   * the attachment type specified."
+   */
+  desired_attachment_class = lookup_flags & LookupFlag::MarkAttachmentType;
+  if (desired_attachment_class)
+  {
+    if (basic_glyph_class == HB_OT_LAYOUT_GLYPH_CLASS_MARK &&
+        *property != desired_attachment_class )
+      return false;
+  }
+
+  return true;
+}
+
+
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout,
+			      hb_codepoint_t  glyph)
+{
+  hb_ot_layout_glyph_properties_t properties;
+  hb_ot_layout_class_t klass;
+
+  properties = _hb_ot_layout_get_glyph_properties (layout, glyph);
+
+  if (properties & 0xFF00)
+    return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
+
+  return (hb_ot_layout_glyph_class_t) properties;
+}
+
+void
+hb_ot_layout_set_glyph_class (hb_ot_layout_t             *layout,
+			      hb_codepoint_t              glyph,
+			      hb_ot_layout_glyph_class_t  klass)
+{
+  /* TODO optimize this, similar to old harfbuzz code for example */
+
+  hb_ot_layout_class_t gdef_klass;
+  int len = layout->new_gdef.len;
+
+  if (glyph >= len) {
+    int new_len;
+    unsigned char *new_klasses;
+
+    new_len = len == 0 ? 120 : 2 * len;
+    if (new_len > 65535)
+      new_len = 65535;
+    new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
+
+    if (G_UNLIKELY (!new_klasses))
+      return;
+
+    memset (new_klasses + len, 0, new_len - len);
+
+    layout->new_gdef.klasses = new_klasses;
+    layout->new_gdef.len = new_len;
+  }
+
+  switch (klass) {
+  default:
+  case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED:	gdef_klass = GDEF::UnclassifiedGlyph;	break;
+  case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH:	gdef_klass = GDEF::BaseGlyph;		break;
+  case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE:	gdef_klass = GDEF::LigatureGlyph;	break;
+  case HB_OT_LAYOUT_GLYPH_CLASS_MARK:		gdef_klass = GDEF::MarkGlyph;		break;
+  case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT:	gdef_klass = GDEF::ComponentGlyph;	break;
+  }
+
+  layout->new_gdef.klasses[glyph] = gdef_klass;
+  return;
+}
+
+void
+hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout,
+				  uint16_t        num_total_glyphs,
+				  hb_codepoint_t *glyphs,
+				  unsigned char  *klasses,
+				  uint16_t        count)
+{
+  int i;
+
+  if (G_UNLIKELY (!count || !glyphs || !klasses))
+    return;
+
+  if (layout->new_gdef.len == 0) {
+    layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
+    layout->new_gdef.len = count;
+  }
+
+  for (i = 0; i < count; i++)
+    hb_ot_layout_set_glyph_class (layout, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
+}
+
+/*
+ * GSUB/GPOS
+ */
+
+static const GSUBGPOS&
+get_gsubgpos_table (hb_ot_layout_t            *layout,
+		    hb_ot_layout_table_type_t  table_type)
+{
+  switch (table_type) {
+    case HB_OT_LAYOUT_TABLE_TYPE_GSUB: return *(layout->gsub);
+    case HB_OT_LAYOUT_TABLE_TYPE_GPOS: return *(layout->gpos);
+    default:                           return NullGSUBGPOS;
+  }
+}
+
+
+unsigned int
+hb_ot_layout_table_get_script_count (hb_ot_layout_t            *layout,
+				     hb_ot_layout_table_type_t  table_type)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+  return g.get_script_count ();
+}
+
+hb_tag_t
+hb_ot_layout_table_get_script_tag (hb_ot_layout_t            *layout,
+				   hb_ot_layout_table_type_t  table_type,
+				   unsigned int               script_index)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+  return g.get_script_tag (script_index);
+}
+
+hb_bool_t
+hb_ot_layout_table_find_script (hb_ot_layout_t            *layout,
+				hb_ot_layout_table_type_t  table_type,
+				hb_tag_t                   script_tag,
+				unsigned int              *script_index)
+{
+  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+  if (g.find_script_index (script_tag, script_index))
+    return TRUE;
+
+  /* try finding 'DFLT' */
+  if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index))
+    return FALSE;
+
+  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+  if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index))
+    return FALSE;
+
+  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
+  return FALSE;
+}
+
+unsigned int
+hb_ot_layout_table_get_feature_count (hb_ot_layout_t            *layout,
+				      hb_ot_layout_table_type_t  table_type)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+  return g.get_feature_count ();
+}
+
+hb_tag_t
+hb_ot_layout_table_get_feature_tag (hb_ot_layout_t            *layout,
+				    hb_ot_layout_table_type_t  table_type,
+				    unsigned int               feature_index)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+  return g.get_feature_tag (feature_index);
+}
+
+hb_bool_t
+hb_ot_layout_table_find_feature (hb_ot_layout_t            *layout,
+				 hb_ot_layout_table_type_t  table_type,
+				 hb_tag_t                   feature_tag,
+				 unsigned int              *feature_index)
+{
+  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+  if (g.find_feature_index (feature_tag, feature_index))
+    return TRUE;
+
+  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+  return FALSE;
+}
+
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_ot_layout_t            *layout,
+				     hb_ot_layout_table_type_t  table_type)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+
+  return g.get_lookup_count ();
+}
+
+
+unsigned int
+hb_ot_layout_script_get_language_count (hb_ot_layout_t            *layout,
+					hb_ot_layout_table_type_t  table_type,
+					unsigned int               script_index)
+{
+  const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
+
+  return s.get_lang_sys_count ();
+}
+
+hb_tag_t
+hb_ot_layout_script_get_language_tag (hb_ot_layout_t            *layout,
+				      hb_ot_layout_table_type_t  table_type,
+				      unsigned int               script_index,
+				      unsigned int               language_index)
+{
+  const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
+
+  return s.get_lang_sys_tag (language_index);
+}
+
+hb_bool_t
+hb_ot_layout_script_find_language (hb_ot_layout_t            *layout,
+				   hb_ot_layout_table_type_t  table_type,
+				   unsigned int               script_index,
+				   hb_tag_t                   language_tag,
+				   unsigned int              *language_index)
+{
+  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+  const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
+
+  if (s.find_lang_sys_index (language_tag, language_index))
+    return TRUE;
+
+  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+  if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index))
+    return FALSE;
+
+  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
+  return FALSE;
+}
+
+hb_bool_t
+hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t            *layout,
+						  hb_ot_layout_table_type_t  table_type,
+						  unsigned int               script_index,
+						  unsigned int               language_index,
+						  unsigned int              *feature_index)
+{
+  const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
+
+  if (feature_index) *feature_index = l.get_required_feature_index ();
+
+  return l.has_required_feature ();
+}
+
+unsigned int
+hb_ot_layout_language_get_feature_count (hb_ot_layout_t            *layout,
+					 hb_ot_layout_table_type_t  table_type,
+					 unsigned int               script_index,
+					 unsigned int               language_index)
+{
+  const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
+
+  return l.get_feature_count ();
+}
+
+unsigned int
+hb_ot_layout_language_get_feature_index (hb_ot_layout_t            *layout,
+					 hb_ot_layout_table_type_t  table_type,
+					 unsigned int               script_index,
+					 unsigned int               language_index,
+					 unsigned int               num_feature)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+  return l.get_feature_index (num_feature);
+}
+
+hb_tag_t
+hb_ot_layout_language_get_feature_tag (hb_ot_layout_t            *layout,
+				       hb_ot_layout_table_type_t  table_type,
+				       unsigned int               script_index,
+				       unsigned int               language_index,
+				       unsigned int               num_feature)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+  unsigned int feature_index = l.get_feature_index (num_feature);
+
+  return g.get_feature_tag (feature_index);
+}
+
+
+hb_bool_t
+hb_ot_layout_language_find_feature (hb_ot_layout_t            *layout,
+				    hb_ot_layout_table_type_t  table_type,
+				    unsigned int               script_index,
+				    unsigned int               language_index,
+				    hb_tag_t                   feature_tag,
+				    unsigned int              *feature_index)
+{
+  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+  unsigned int i;
+
+  for (i = 0; i < l.get_feature_count (); i++) {
+    unsigned int f_index = l.get_feature_index (i);
+
+    if (feature_tag == g.get_feature_tag (f_index)) {
+      if (feature_index) *feature_index = f_index;
+      return TRUE;
+    }
+  }
+
+  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+  return FALSE;
+}
+
+unsigned int
+hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t            *layout,
+				       hb_ot_layout_table_type_t  table_type,
+				       unsigned int               feature_index)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+  const Feature &f = g.get_feature (feature_index);
+
+  return f.get_lookup_count ();
+}
+
+unsigned int
+hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t            *layout,
+				       hb_ot_layout_table_type_t  table_type,
+				       unsigned int               feature_index,
+				       unsigned int               num_lookup)
+{
+  const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
+  const Feature &f = g.get_feature (feature_index);
+
+  return f.get_lookup_index (num_lookup);
+}
+
+/*
+ * GSUB
+ */
+
+hb_bool_t
+hb_ot_layout_substitute_lookup (hb_ot_layout_t              *layout,
+				hb_buffer_t                 *buffer,
+			        unsigned int                 lookup_index,
+				hb_ot_layout_feature_mask_t  mask)
+{
+  const GSUB &gsub = *(layout->gsub);
+  const SubstLookup &l = gsub.get_lookup (lookup_index);
+  unsigned int lookup_type = l.get_type ();
+  unsigned int nesting_level_left = HB_OT_LAYOUT_MAX_NESTING_LEVEL;
+  unsigned int context_length = NO_CONTEXT;
+  bool handled, ret = false;
+
+  if (!l.is_reverse ()) {
+
+      /* in/out forward substitution */
+      _hb_buffer_clear_output (buffer);
+      buffer->in_pos = 0;
+      while (buffer->in_pos < buffer->in_length) {
+
+	if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
+	    l.substitute (layout, buffer, context_length, nesting_level_left))
+	  ret = true;
+	else
+	  _hb_buffer_copy_output_glyph (buffer);
+
+      }
+      _hb_buffer_swap (buffer);
+
+  } else {
+
+      /* in-place backward substitution */
+      buffer->in_pos = buffer->in_length - 1;
+      do {
+
+	if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
+	    l.substitute (layout, buffer, context_length, nesting_level_left))
+	  ret = true;
+	else
+	  buffer->in_pos--;
+
+      } while (buffer->in_pos);
+
+  }
+
+  return ret;
+}
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
new file mode 100644
index 0000000..c29485c
--- /dev/null
+++ b/src/hb-ot-layout.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#ifndef HB_OT_LAYOUT_H
+#define HB_OT_LAYOUT_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS();
+
+/*
+ * hb_ot_layout_t
+ */
+
+typedef struct _hb_ot_layout_t hb_ot_layout_t;
+
+hb_ot_layout_t *
+hb_ot_layout_create (void);
+
+hb_ot_layout_t *
+hb_ot_layout_create_for_data (const char *font_data,
+			      int         face_index);
+
+void
+hb_ot_layout_destroy (hb_ot_layout_t *layout);
+
+/* TODO sanitizing API/constructor (make_wrieable_func_t) */
+/* TODO get_table_func_t constructor */
+
+/*
+ * GDEF
+ */
+
+typedef enum {
+  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0x0000,
+  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 0x0002,
+  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE	= 0x0004,
+  HB_OT_LAYOUT_GLYPH_CLASS_MARK		= 0x0008,
+  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 0x0010
+} hb_ot_layout_glyph_class_t;
+
+hb_bool_t
+hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout);
+
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout,
+			      hb_codepoint_t  glyph);
+
+void
+hb_ot_layout_set_glyph_class (hb_ot_layout_t            *layout,
+			      hb_codepoint_t             glyph,
+			      hb_ot_layout_glyph_class_t klass);
+
+void
+hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout,
+				  uint16_t        num_total_glyphs,
+				  hb_codepoint_t *glyphs,
+				  unsigned char  *klasses,
+				  uint16_t        count);
+
+/*
+ * GSUB/GPOS
+ */
+
+typedef enum {
+  HB_OT_LAYOUT_TABLE_TYPE_GSUB,
+  HB_OT_LAYOUT_TABLE_TYPE_GPOS,
+  HB_OT_LAYOUT_TABLE_TYPE_NONE
+} hb_ot_layout_table_type_t;
+
+typedef uint16_t hb_ot_layout_feature_mask_t;
+
+#define HB_OT_LAYOUT_MAX_NESTING_LEVEL		100
+
+#define HB_OT_LAYOUT_NO_SCRIPT_INDEX		((unsigned int) 0xFFFF)
+#define HB_OT_LAYOUT_NO_FEATURE_INDEX		((unsigned int) 0xFFFF)
+#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX	((unsigned int) 0xFFFF)
+#define HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT		HB_TAG ('D', 'F', 'L', 'T')
+#define HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE	HB_TAG ('d', 'f', 'l', 't')
+
+unsigned int
+hb_ot_layout_table_get_script_count (hb_ot_layout_t            *layout,
+				     hb_ot_layout_table_type_t  table_type);
+
+hb_tag_t
+hb_ot_layout_table_get_script_tag (hb_ot_layout_t            *layout,
+				   hb_ot_layout_table_type_t  table_type,
+				   unsigned int               script_index);
+
+hb_bool_t
+hb_ot_layout_table_find_script (hb_ot_layout_t            *layout,
+				hb_ot_layout_table_type_t  table_type,
+				hb_tag_t                   script_tag,
+				unsigned int              *script_index);
+
+unsigned int
+hb_ot_layout_table_get_feature_count (hb_ot_layout_t            *layout,
+				      hb_ot_layout_table_type_t  table_type);
+
+hb_tag_t
+hb_ot_layout_table_get_feature_tag (hb_ot_layout_t            *layout,
+				    hb_ot_layout_table_type_t  table_type,
+				    unsigned int               feature_index);
+
+hb_bool_t
+hb_ot_layout_table_find_script (hb_ot_layout_t            *layout,
+				hb_ot_layout_table_type_t  table_type,
+				hb_tag_t                   feature_tag,
+				unsigned int              *feature_index);
+
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_ot_layout_t            *layout,
+				     hb_ot_layout_table_type_t  table_type);
+
+unsigned int
+hb_ot_layout_script_get_language_count (hb_ot_layout_t            *layout,
+					hb_ot_layout_table_type_t  table_type,
+					unsigned int               script_index);
+
+hb_tag_t
+hb_ot_layout_script_get_language_tag (hb_ot_layout_t            *layout,
+				      hb_ot_layout_table_type_t  table_type,
+				      unsigned int               script_index,
+				      unsigned int               language_index);
+
+hb_bool_t
+hb_ot_layout_script_find_language (hb_ot_layout_t            *layout,
+				   hb_ot_layout_table_type_t  table_type,
+				   unsigned int               script_index,
+				   hb_tag_t                   language_tag,
+				   unsigned int              *language_index);
+
+hb_bool_t
+hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t            *layout,
+						  hb_ot_layout_table_type_t  table_type,
+						  unsigned int               script_index,
+						  unsigned int               language_index,
+						  unsigned int              *feature_index);
+
+unsigned int
+hb_ot_layout_language_get_feature_count (hb_ot_layout_t            *layout,
+					 hb_ot_layout_table_type_t  table_type,
+					 unsigned int               script_index,
+					 unsigned int               language_index);
+
+unsigned int
+hb_ot_layout_language_get_feature_index (hb_ot_layout_t            *layout,
+				         hb_ot_layout_table_type_t  table_type,
+				         unsigned int               script_index,
+				         unsigned int               language_index,
+				         unsigned int               num_feature);
+
+hb_tag_t
+hb_ot_layout_language_get_feature_tag (hb_ot_layout_t            *layout,
+				       hb_ot_layout_table_type_t  table_type,
+				       unsigned int               script_index,
+				       unsigned int               language_index,
+				       unsigned int               num_feature);
+
+hb_bool_t
+hb_ot_layout_language_find_feature (hb_ot_layout_t            *layout,
+				    hb_ot_layout_table_type_t  table_type,
+				    unsigned int               script_index,
+				    unsigned int               language_index,
+				    hb_tag_t                   feature_tag,
+				    unsigned int              *feature_index);
+
+unsigned int
+hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t            *layout,
+				       hb_ot_layout_table_type_t  table_type,
+				       unsigned int               feature_index);
+
+unsigned int
+hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t            *layout,
+				       hb_ot_layout_table_type_t  table_type,
+				       unsigned int               feature_index,
+				       unsigned int               num_lookup);
+
+/*
+ * GSUB
+ */
+
+hb_bool_t
+hb_ot_layout_substitute_lookup (hb_ot_layout_t              *layout,
+				hb_buffer_t                 *buffer,
+			        unsigned int                 lookup_index,
+				hb_ot_layout_feature_mask_t  mask);
+
+
+
+
+
+
+
+
+
+
+
+/*
+#define PANGO_OT_ALL_GLYPHS			((guint) 0xFFFF)
+
+*/
+
+HB_END_DECLS();
+
+#endif /* HB_OT_LAYOUT_H */
diff --git a/src/hb-private.h b/src/hb-private.h
new file mode 100644
index 0000000..3dca049
--- /dev/null
+++ b/src/hb-private.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#ifndef HB_PRIVATE_H
+#define HB_PRIVATE_H
+
+#include <glib.h>
+
+/* Macros to convert to/from BigEndian */
+#define hb_be_uint8_t
+#define hb_be_int8_t
+#define hb_be_uint16_t	GUINT16_TO_BE
+#define hb_be_int16_t	GINT16_TO_BE
+#define hb_be_uint32_t	GUINT32_TO_BE
+#define hb_be_int32_t	GINT32_TO_BE
+#define hb_be_uint64_t	GUINT64_TO_BE
+#define hb_be_int64_t	GINT64_TO_BE
+
+#define HB_LIKELY	G_LIKEYLY
+#define HB_UNLIKELY	G_UNLIKELY
+#define HB_UNUSED(arg) ((arg) = (arg))
+
+
+#include <assert.h>
+
+#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
+#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
+
+#define ASSERT_SIZE(_type, _size) ASSERT_STATIC (sizeof (_type) == (_size))
+
+/*
+ * buffer
+ */
+
+/* XXX */
+#define HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
+
+#endif /* HB_PRIVATE_H */
diff --git a/src/main.cc b/src/main.cc
new file mode 100644
index 0000000..ffd13b4
--- /dev/null
+++ b/src/main.cc
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2007,2008  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine 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
+ */
+
+#define HB_OT_LAYOUT_CC
+#include "hb-ot-layout-open-private.h"
+#include "hb-ot-layout-gdef-private.h"
+#include "hb-ot-layout-gsub-private.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+    exit (1);
+  }
+
+  GMappedFile *mf = g_mapped_file_new (argv[1], FALSE, NULL);
+  const char *font_data = g_mapped_file_get_contents (mf);
+  int len = g_mapped_file_get_length (mf);
+
+  printf ("Opened font file %s: %d bytes long\n", argv[1], len);
+
+  const OpenTypeFontFile &ot = OpenTypeFontFile::get_for_data (font_data);
+
+  switch (ot.get_tag()) {
+  case OpenTypeFontFile::TrueTypeTag:
+    printf ("OpenType font with TrueType outlines\n");
+    break;
+  case OpenTypeFontFile::CFFTag:
+    printf ("OpenType font with CFF (Type1) outlines\n");
+    break;
+  case OpenTypeFontFile::TTCTag:
+    printf ("TrueType Collection of OpenType fonts\n");
+    break;
+  default:
+    printf ("Unknown font format\n");
+    break;
+  }
+
+  int num_fonts = ot.get_face_count ();
+  printf ("%d font(s) found in file\n", num_fonts);
+  for (int n_font = 0; n_font < num_fonts; n_font++) {
+    const OpenTypeFontFace &font = ot.get_face (n_font);
+    printf ("Font %d of %d:\n", n_font, num_fonts);
+
+    int num_tables = font.get_table_count ();
+    printf ("  %d table(s) found in font\n", num_tables);
+    for (int n_table = 0; n_table < num_tables; n_table++) {
+      const OpenTypeTable &table = font.get_table (n_table);
+      printf ("  Table %2d of %2d: %.4s (0x%08lx+0x%08lx)\n", n_table, num_tables,
+	      (const char *)table.get_tag(), table.get_offset(), table.get_length());
+
+      switch (table.get_tag ()) {
+
+      case GSUBGPOS::GSUBTag:
+      case GSUBGPOS::GPOSTag:
+	{
+
+	const GSUBGPOS &g = GSUBGPOS::get_for_data (ot.get_table_data (table));
+
+	int num_scripts = g.get_script_count ();
+	printf ("    %d script(s) found in table\n", num_scripts);
+	for (int n_script = 0; n_script < num_scripts; n_script++) {
+	  const Script &script = g.get_script (n_script);
+	  printf ("    Script %2d of %2d: %.4s\n", n_script, num_scripts,
+	          (const char *)g.get_script_tag(n_script));
+
+	  if (!script.has_default_lang_sys())
+	    printf ("      No default language system\n");
+	  int num_langsys = script.get_lang_sys_count ();
+	  printf ("      %d language system(s) found in script\n", num_langsys);
+	  for (int n_langsys = script.has_default_lang_sys() ? -1 : 0; n_langsys < num_langsys; n_langsys++) {
+	    const LangSys &langsys = n_langsys == -1
+				   ? script.get_default_lang_sys ()
+				   : script.get_lang_sys (n_langsys);
+	    printf (n_langsys == -1
+		   ? "      Default Language System\n"
+		   : "      Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
+	            (const char *)script.get_lang_sys_tag (n_langsys));
+	    if (langsys.get_required_feature_index () == NO_INDEX)
+	      printf ("        No required feature\n");
+
+	    int num_features = langsys.get_feature_count ();
+	    printf ("        %d feature(s) found in language system\n", num_features);
+	    for (int n_feature = 0; n_feature < num_features; n_feature++) {
+	      unsigned int feature_index = langsys.get_feature_index (n_feature);
+	      printf ("        Feature index %2d of %2d: %d\n", n_feature, num_features,
+	              langsys.get_feature_index (n_feature));
+	    }
+	  }
+	}
+
+	int num_features = g.get_feature_count ();
+	printf ("    %d feature(s) found in table\n", num_features);
+	for (int n_feature = 0; n_feature < num_features; n_feature++) {
+	  const Feature &feature = g.get_feature (n_feature);
+	  printf ("    Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features,
+	          (const char *)g.get_feature_tag(n_feature),
+		  feature.get_lookup_count());
+
+	  int num_lookups = feature.get_lookup_count ();
+	  printf ("        %d lookup(s) found in feature\n", num_lookups);
+	  for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
+	    unsigned int lookup_index = feature.get_lookup_index (n_lookup);
+	    printf ("        Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
+	            feature.get_lookup_index (n_lookup));
+	  }
+	}
+
+	int num_lookups = g.get_lookup_count ();
+	printf ("    %d lookup(s) found in table\n", num_lookups);
+	for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
+	  const Lookup &lookup = g.get_lookup (n_lookup);
+	  printf ("    Lookup %2d of %2d: type %d, flags 0x%04X\n", n_lookup, num_lookups,
+	          lookup.get_type(), lookup.get_flag());
+	}
+
+	}
+	break;
+
+      case GDEF::Tag:
+	{
+
+	const GDEF &gdef = GDEF::get_for_data (ot.get_table_data (table));
+
+	printf ("    Has %sglyph classes\n",
+		  gdef.has_glyph_classes () ? "" : "no ");
+	printf ("    Has %smark attachment types\n",
+		  gdef.has_mark_attachment_types () ? "" : "no ");
+	printf ("    Has %sattach list\n",
+		  gdef.has_attach_list () ? "" : "no ");
+	printf ("    Has %slig caret list\n",
+		  gdef.has_lig_caret_list () ? "" : "no ");
+
+	for (int glyph = 0; glyph < 1; glyph++)
+	  printf ("    glyph %d has class %d and mark attachment type %d\n",
+		  glyph,
+		  gdef.get_glyph_class (glyph),
+		  gdef.get_mark_attachment_type (glyph));
+
+	}
+	break;
+      }
+    }
+  }
+
+  return 0;
+}