[pango/harfbuzz-ng: 1/17] Merge harfbuzz-ng



commit 23fe8a3b2aa15ea135704d8c25321a016a6972ae
Author: Behdad Esfahbod <behdad behdad org>
Date:   Wed Apr 15 20:14:24 2009 -0400

    Merge harfbuzz-ng
---
 pango/opentype/Makefile.am                 |   16 +-
 pango/opentype/harfbuzz-buffer-private.h   |    6 +-
 pango/opentype/harfbuzz-global.h           |    3 +
 pango/opentype/harfbuzz-gpos.c             |  121 ++--
 pango/opentype/harfbuzz-gpos.h             |    6 +-
 pango/opentype/harfbuzz-gsub.c             |  145 ++---
 pango/opentype/harfbuzz-gsub.h             |    4 +-
 pango/opentype/harfbuzz-impl.h             |   11 +-
 pango/opentype/harfbuzz-open.c             |    9 -
 pango/opentype/harfbuzz.h                  |    1 -
 pango/opentype/hb-ot-layout-gdef-private.h |  276 ++++++++
 pango/opentype/hb-ot-layout-gsub-private.h |  583 ++++++++++++++++
 pango/opentype/hb-ot-layout-open-private.h |  993 ++++++++++++++++++++++++++++
 pango/opentype/hb-ot-layout-private.h      |   66 ++
 pango/opentype/hb-ot-layout.cc             |  565 ++++++++++++++++
 pango/opentype/hb-ot-layout.h              |  229 +++++++
 pango/opentype/main.cc                     |  174 +++++
 pango/pango-ot-buffer.c                    |   12 +-
 pango/pango-ot-info.c                      |  397 +++---------
 pango/pango-ot-private.h                   |    4 +-
 20 files changed, 3127 insertions(+), 494 deletions(-)

diff --git a/pango/opentype/Makefile.am b/pango/opentype/Makefile.am
index 5c0b18e..40644c1 100644
--- a/pango/opentype/Makefile.am
+++ b/pango/opentype/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 @@ PUBLICHEADERS = \
 	harfbuzz.h \
 	harfbuzz-global.h \
 	harfbuzz-buffer.h \
-	harfbuzz-gdef.h \
 	harfbuzz-gpos.h \
 	harfbuzz-gsub.h \
 	harfbuzz-open.h
@@ -31,7 +33,6 @@ PUBLICHEADERS = \
 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_SOURCES = \
 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 @@ harfbuzz_dump_LDADD = \
 	$(libharfbuzz_1_la_LIBADD) \
 	libharfbuzz-1.la
 
+main_LDADD = \
+	$(GLIB_LIBS)
+
 EXTRA_DIST = 		\
 	README		\
 	COPYING		\
diff --git a/pango/opentype/harfbuzz-buffer-private.h b/pango/opentype/harfbuzz-buffer-private.h
index 5065f2e..02ae336 100644
--- a/pango/opentype/harfbuzz-buffer-private.h
+++ b/pango/opentype/harfbuzz-buffer-private.h
@@ -83,9 +83,9 @@ _hb_buffer_allocate_ligid( HB_Buffer buffer );
 #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/pango/opentype/harfbuzz-global.h b/pango/opentype/harfbuzz-global.h
index dab20b5..7b8a0f2 100644
--- a/pango/opentype/harfbuzz-global.h
+++ b/pango/opentype/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/pango/opentype/harfbuzz-gpos.c b/pango/opentype/harfbuzz-gpos.c
index c78dcba..560a291 100644
--- a/pango/opentype/harfbuzz-gpos.c
+++ b/pango/opentype/harfbuzz-gpos.c
@@ -75,7 +75,7 @@ static HB_Error  default_mmfunc( HB_Font      font,
 
 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  HB_Load_GPOS_Table( HB_Font          font,
   HB_Error   error;
 
 
-  if ( !retptr )
+  if ( !retptr || !layout )
     return ERR(HB_Err_Invalid_Argument);
 
   if ( GOTO_Table( TTAG_GPOS ) )
@@ -143,20 +143,12 @@ HB_Error  HB_Load_GPOS_Table( HB_Font          font,
 				  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 @@ static HB_Error  Lookup_SinglePos( GPOS_Instance*    gpi,
   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 @@ static HB_Error  Lookup_PairPos( GPOS_Instance*    gpi,
   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 @@ static HB_Error  Lookup_PairPos( GPOS_Instance*    gpi,
   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 @@ static HB_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
   /* 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 @@ static HB_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
   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 @@ static HB_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
 
   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 @@ static HB_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
 
   /* 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 @@ static HB_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
 
   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 @@ static HB_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
 
   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 @@ static HB_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
   /* 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 @@ static HB_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
   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 @@ static HB_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
   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 @@ static HB_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
   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 @@ static HB_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
 
     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 @@ static HB_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
 
   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 @@ static HB_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
 
     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 @@ static HB_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
   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 @@ static HB_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
 
   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 @@ static HB_Error  Lookup_ChainContextPos1(
 
   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 @@ static HB_Error  Lookup_ChainContextPos1(
 
       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 @@ static HB_Error  Lookup_ChainContextPos1(
 
     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 @@ static HB_Error  Lookup_ChainContextPos1(
 
     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 @@ static HB_Error  Lookup_ChainContextPos2(
 
   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 @@ static HB_Error  Lookup_ChainContextPos2(
 
       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 @@ static HB_Error  Lookup_ChainContextPos2(
 
     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 @@ static HB_Error  Lookup_ChainContextPos2(
 
     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 @@ static HB_Error  Lookup_ChainContextPos3(
   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 @@ static HB_Error  Lookup_ChainContextPos3(
 
     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 @@ static HB_Error  Lookup_ChainContextPos3(
   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 @@ static HB_Error  Lookup_ChainContextPos3(
 
   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/pango/opentype/harfbuzz-gpos.h b/pango/opentype/harfbuzz-gpos.h
index 8638cf1..b1aa135 100644
--- a/pango/opentype/harfbuzz-gpos.h
+++ b/pango/opentype/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 @@ struct  HB_GPOSHeader_
   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 @@ typedef HB_GPOSHeader* HB_GPOS;
 
 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/pango/opentype/harfbuzz-gsub.c b/pango/opentype/harfbuzz-gsub.c
index c05f20d..38879a8 100644
--- a/pango/opentype/harfbuzz-gsub.c
+++ b/pango/opentype/harfbuzz-gsub.c
@@ -47,7 +47,7 @@ static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader*   gsub,
 
 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_Error  HB_Load_GSUB_Table( HB_Font          font,
 
   HB_GSUBHeader*  gsub;
 
-  if ( !retptr )
+  if ( !retptr || !layout )
     return ERR(HB_Err_Invalid_Argument);
 
   if ( GOTO_Table( TTAG_GSUB ) )
@@ -111,20 +111,12 @@ HB_Error  HB_Load_GSUB_Table( HB_Font          font,
 				  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 @@ static HB_Error  Lookup_SingleSubst( HB_GSUBHeader*   gsub,
   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 @@ static HB_Error  Lookup_SingleSubst( HB_GSUBHeader*   gsub,
     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 @@ static HB_Error  Lookup_MultipleSubst( HB_GSUBHeader*    gsub,
   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 @@ static HB_Error  Lookup_MultipleSubst( HB_GSUBHeader*    gsub,
   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 @@ static HB_Error  Lookup_AlternateSubst( HB_GSUBHeader*    gsub,
   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 @@ static HB_Error  Lookup_AlternateSubst( HB_GSUBHeader*    gsub,
   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 @@ static HB_Error  Lookup_AlternateSubst( HB_GSUBHeader*    gsub,
   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 @@ static HB_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
   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 @@ static HB_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
 
     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 @@ static HB_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
 	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 @@ static HB_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
 
       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 @@ static HB_Error  Lookup_ContextSubst1( HB_GSUBHeader*          gsub,
   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 @@ static HB_Error  Lookup_ContextSubst1( HB_GSUBHeader*          gsub,
 
     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 @@ static HB_Error  Lookup_ContextSubst2( HB_GSUBHeader*          gsub,
 
   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 @@ static HB_Error  Lookup_ContextSubst2( HB_GSUBHeader*          gsub,
 
     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 @@ static HB_Error  Lookup_ContextSubst3( HB_GSUBHeader*          gsub,
   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 @@ static HB_Error  Lookup_ContextSubst3( HB_GSUBHeader*          gsub,
 
   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 @@ static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
 
   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 @@ static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
 
       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 @@ static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
 
     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 @@ static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
 
     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 @@ static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
 
   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 @@ static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
 
       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 @@ static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
 
     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 @@ static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
 
     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 @@ static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
   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 @@ static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
 
     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 @@ static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
   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 @@ static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
 
   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 @@ static HB_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
   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 @@ static HB_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
 
     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 @@ static HB_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
 
   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/pango/opentype/harfbuzz-gsub.h b/pango/opentype/harfbuzz-gsub.h
index 3d6cfa1..b1e78ce 100644
--- a/pango/opentype/harfbuzz-gsub.h
+++ b/pango/opentype/harfbuzz-gsub.h
@@ -68,7 +68,7 @@ struct  HB_GSUBHeader_
   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 @@ typedef HB_GSUBHeader*  HB_GSUB;
 
 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/pango/opentype/harfbuzz-impl.h b/pango/opentype/harfbuzz-impl.h
index f886e67..29101f8 100644
--- a/pango/opentype/harfbuzz-impl.h
+++ b/pango/opentype/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 @@ HB_BEGIN_HEADER
 # 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/pango/opentype/harfbuzz-open.c b/pango/opentype/harfbuzz-open.c
index e187916..68b27d4 100644
--- a/pango/opentype/harfbuzz-open.c
+++ b/pango/opentype/harfbuzz-open.c
@@ -124,15 +124,6 @@ static HB_Error  Load_Script( HB_ScriptTable*  s,
 
   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/pango/opentype/harfbuzz.h b/pango/opentype/harfbuzz.h
index 10d4f74..d23b6bc 100644
--- a/pango/opentype/harfbuzz.h
+++ b/pango/opentype/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/pango/opentype/hb-ot-layout-gdef-private.h b/pango/opentype/hb-ot-layout-gdef-private.h
new file mode 100644
index 0000000..5418d8b
--- /dev/null
+++ b/pango/opentype/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/pango/opentype/hb-ot-layout-gsub-private.h b/pango/opentype/hb-ot-layout-gsub-private.h
new file mode 100644
index 0000000..c8d5405
--- /dev/null
+++ b/pango/opentype/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/pango/opentype/hb-ot-layout-open-private.h b/pango/opentype/hb-ot-layout-open-private.h
new file mode 100644
index 0000000..d5ca810
--- /dev/null
+++ b/pango/opentype/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/pango/opentype/hb-ot-layout-private.h b/pango/opentype/hb-ot-layout-private.h
new file mode 100644
index 0000000..a1be8aa
--- /dev/null
+++ b/pango/opentype/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/pango/opentype/hb-ot-layout.cc b/pango/opentype/hb-ot-layout.cc
new file mode 100644
index 0000000..01923db
--- /dev/null
+++ b/pango/opentype/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/pango/opentype/hb-ot-layout.h b/pango/opentype/hb-ot-layout.h
new file mode 100644
index 0000000..c29485c
--- /dev/null
+++ b/pango/opentype/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/pango/opentype/main.cc b/pango/opentype/main.cc
new file mode 100644
index 0000000..ffd13b4
--- /dev/null
+++ b/pango/opentype/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;
+}
diff --git a/pango/pango-ot-buffer.c b/pango/pango-ot-buffer.c
index 7795b27..5feb5a0 100644
--- a/pango/pango-ot-buffer.c
+++ b/pango/pango-ot-buffer.c
@@ -325,8 +325,7 @@ pango_ot_buffer_output (const PangoOTBuffer *buffer,
 			PangoGlyphString    *glyphs)
 {
   FT_Face face;
-  PangoOTInfo *info;
-  HB_GDEF gdef = NULL;
+  hb_ot_layout_t *layout;
   unsigned int i;
   int last_cluster;
 
@@ -352,8 +351,7 @@ pango_ot_buffer_output (const PangoOTBuffer *buffer,
       last_cluster = glyphs->log_clusters[i];
     }
 
-  info = pango_ot_info_get (face);
-  gdef = pango_ot_info_get_gdef (info);
+  layout = _pango_ot_info_get_layout (pango_ot_info_get (face));
 
   /* Apply default positioning */
   for (i = 0; i < (unsigned int)glyphs->num_glyphs; i++)
@@ -362,12 +360,8 @@ pango_ot_buffer_output (const PangoOTBuffer *buffer,
 	{
 	  PangoRectangle logical_rect;
 
-	  HB_UShort property;
-
 	  if (buffer->zero_width_marks &&
-	      gdef &&
-	      HB_GDEF_Get_Glyph_Property (gdef, glyphs->glyphs[i].glyph, &property) == HB_Err_Ok &&
-	      (property == HB_GDEF_MARK || (property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS) != 0))
+	      hb_ot_layout_get_glyph_class (layout, glyphs->glyphs[i].glyph) == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
 	    {
 	      glyphs->glyphs[i].geometry.width = 0;
 	    }
diff --git a/pango/pango-ot-info.c b/pango/pango-ot-info.c
index 51a8d44..b1a5dfd 100644
--- a/pango/pango-ot-info.c
+++ b/pango/pango-ot-info.c
@@ -28,11 +28,12 @@
 static void pango_ot_info_class_init (GObjectClass *object_class);
 static void pango_ot_info_finalize   (GObject *object);
 
+static void synthesize_class_def (PangoOTInfo *info);
+
 static GObjectClass *parent_class;
 
 enum
 {
-  INFO_LOADED_GDEF = 1 << 0,
   INFO_LOADED_GSUB = 1 << 1,
   INFO_LOADED_GPOS = 1 << 2
 };
@@ -79,11 +80,9 @@ pango_ot_info_finalize (GObject *object)
 {
   PangoOTInfo *info = PANGO_OT_INFO (object);
 
-  if (info->gdef)
-    {
-      HB_Done_GDEF_Table (info->gdef);
-      info->gdef = NULL;
-    }
+  if (info->layout)
+    hb_ot_layout_destroy (info->layout);
+
   if (info->gsub)
     {
       HB_Done_GSUB_Table (info->gsub);
@@ -132,17 +131,26 @@ pango_ot_info_get (FT_Face face)
       face->generic.finalizer = pango_ot_info_finalizer;
 
       info->face = face;
+
+      if (FT_IS_SFNT (face))
+        {
+	  /* XXX handle face->stream->base == NULL better */
+	  info->layout = hb_ot_layout_create_for_data ((const char *) face->stream->base, face->face_index);
+
+	  if (!hb_ot_layout_has_font_glyph_classes (info->layout))
+	    synthesize_class_def (info);
+	}
+      else
+        info->layout = hb_ot_layout_create ();
     }
 
   return info;
 }
 
-/* There must be be a better way to do this
- */
-static gboolean
-is_truetype (FT_Face face)
+hb_ot_layout_t *
+_pango_ot_info_get_layout (PangoOTInfo *info)
 {
-  return FT_IS_SFNT(face);
+  return info->layout;
 }
 
 typedef struct _GlyphInfo GlyphInfo;
@@ -217,10 +225,10 @@ static void
 synthesize_class_def (PangoOTInfo *info)
 {
   GArray *glyph_infos;
-  HB_UShort *glyph_indices;
-  HB_UShort *classes;
-  HB_UInt charcode;
-  HB_UInt glyph;
+  hb_codepoint_t *glyph_indices;
+  unsigned char *classes;
+  gunichar charcode;
+  FT_UInt glyph;
   unsigned int i, j;
   FT_CharMap old_charmap;
 
@@ -254,8 +262,8 @@ synthesize_class_def (PangoOTInfo *info)
    */
   g_array_sort (glyph_infos, compare_glyph_info);
 
-  glyph_indices = g_new (HB_UShort, glyph_infos->len);
-  classes = g_new (HB_UShort, glyph_infos->len);
+  glyph_indices = g_new (hb_codepoint_t, glyph_infos->len);
+  classes = g_new (unsigned char, glyph_infos->len);
 
   for (i = 0, j = 0; i < glyph_infos->len; i++)
     {
@@ -272,8 +280,8 @@ synthesize_class_def (PangoOTInfo *info)
 
   g_array_free (glyph_infos, TRUE);
 
-  HB_GDEF_Build_ClassDefinition (info->gdef, info->face->num_glyphs, j,
-				 glyph_indices, classes);
+  hb_ot_layout_build_glyph_classes (info->layout, info->face->num_glyphs,
+				    glyph_indices, classes, j);
 
   g_free (glyph_indices);
   g_free (classes);
@@ -282,35 +290,6 @@ synthesize_class_def (PangoOTInfo *info)
     FT_Set_Charmap (info->face, old_charmap);
 }
 
-HB_GDEF
-pango_ot_info_get_gdef (PangoOTInfo *info)
-{
-  g_return_val_if_fail (PANGO_IS_OT_INFO (info), NULL);
-
-  if (!(info->loaded & INFO_LOADED_GDEF))
-    {
-      HB_Error error;
-
-      info->loaded |= INFO_LOADED_GDEF;
-
-      if (is_truetype (info->face))
-	{
-	  error = HB_Load_GDEF_Table (info->face, &info->gdef);
-
-	  if (error && error != HB_Err_Not_Covered)
-	    g_warning ("Error loading GDEF table 0x%04X", error);
-
-	  if (!info->gdef)
-	    error = HB_New_GDEF_Table (&info->gdef);
-
-	  if (info->gdef && !info->gdef->GlyphClassDef.loaded)
-	    synthesize_class_def (info);
-	}
-    }
-
-  return info->gdef;
-}
-
 HB_GSUB
 pango_ot_info_get_gsub (PangoOTInfo *info)
 {
@@ -319,13 +298,12 @@ pango_ot_info_get_gsub (PangoOTInfo *info)
   if (!(info->loaded & INFO_LOADED_GSUB))
     {
       HB_Error error;
-      HB_GDEF gdef = pango_ot_info_get_gdef (info);
 
       info->loaded |= INFO_LOADED_GSUB;
 
-      if (is_truetype (info->face))
+      if (FT_IS_SFNT (info->face))
 	{
-	  error = HB_Load_GSUB_Table (info->face, &info->gsub, gdef);
+	  error = HB_Load_GSUB_Table (info->face, &info->gsub, _pango_ot_info_get_layout (info));
 
 	  if (error && error != HB_Err_Not_Covered)
 	    g_warning ("Error loading GSUB table 0x%04X", error);
@@ -343,13 +321,12 @@ pango_ot_info_get_gpos (PangoOTInfo *info)
   if (!(info->loaded & INFO_LOADED_GPOS))
     {
       HB_Error error;
-      HB_GDEF gdef = pango_ot_info_get_gdef (info);
 
       info->loaded |= INFO_LOADED_GPOS;
 
-      if (is_truetype (info->face))
+      if (FT_IS_SFNT (info->face))
 	{
-	  error = HB_Load_GPOS_Table (info->face, &info->gpos, gdef);
+	  error = HB_Load_GPOS_Table (info->face, &info->gpos, _pango_ot_info_get_layout (info));
 
 	  if (error && error != HB_Err_Not_Covered)
 	    g_warning ("Error loading GPOS table 0x%04X", error);
@@ -359,42 +336,14 @@ pango_ot_info_get_gpos (PangoOTInfo *info)
   return info->gpos;
 }
 
-static gboolean
-get_tables (PangoOTInfo      *info,
-	    PangoOTTableType  table_type,
-	    HB_ScriptList  **script_list,
-	    HB_FeatureList **feature_list)
+static hb_ot_layout_table_type_t
+get_hb_table_type (PangoOTTableType table_type)
 {
-  if (table_type == PANGO_OT_TABLE_GSUB)
-    {
-      HB_GSUB gsub = pango_ot_info_get_gsub (info);
-
-      if (!gsub)
-	return FALSE;
-      else
-	{
-	  if (script_list)
-	    *script_list = &gsub->ScriptList;
-	  if (feature_list)
-	    *feature_list = &gsub->FeatureList;
-	  return TRUE;
-	}
-    }
-  else
-    {
-      HB_GPOS gpos = pango_ot_info_get_gpos (info);
-
-      if (!gpos)
-	return FALSE;
-      else
-	{
-	  if (script_list)
-	    *script_list = &gpos->ScriptList;
-	  if (feature_list)
-	    *feature_list = &gpos->FeatureList;
-	  return TRUE;
-	}
-    }
+  switch (table_type) {
+    case PANGO_OT_TABLE_GSUB: return HB_OT_LAYOUT_TABLE_TYPE_GSUB;
+    case PANGO_OT_TABLE_GPOS: return HB_OT_LAYOUT_TABLE_TYPE_GPOS;
+    default:                  return (hb_ot_layout_table_type_t) -1;
+  }
 }
 
 /**
@@ -422,57 +371,11 @@ pango_ot_info_find_script (PangoOTInfo      *info,
 			   PangoOTTag        script_tag,
 			   guint            *script_index)
 {
-  HB_ScriptList *script_list;
-  int i;
-
-  if (script_index)
-    *script_index = PANGO_OT_NO_SCRIPT;
-
-  g_return_val_if_fail (PANGO_IS_OT_INFO (info), FALSE);
-
-  if (!get_tables (info, table_type, &script_list, NULL))
-    return FALSE;
-
-  for (i=0; i < script_list->ScriptCount; i++)
-    {
-      if (script_list->ScriptRecord[i].ScriptTag == script_tag)
-	{
-	  if (script_index)
-	    *script_index = i;
-
-	  return TRUE;
-	}
-    }
-
-  /* try finding 'DFLT' */
-  script_tag = PANGO_OT_TAG_DEFAULT_SCRIPT;
-
-  for (i=0; i < script_list->ScriptCount; i++)
-    {
-      if (script_list->ScriptRecord[i].ScriptTag == script_tag)
-	{
-	  if (script_index)
-	    *script_index = i;
-
-	  return FALSE;
-	}
-    }
+  hb_ot_layout_table_type_t tt = get_hb_table_type (table_type);
 
-  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
-  script_tag = PANGO_OT_TAG_MAKE ('d', 'f', 'l', 't');
-
-  for (i=0; i < script_list->ScriptCount; i++)
-    {
-      if (script_list->ScriptRecord[i].ScriptTag == script_tag)
-	{
-	  if (script_index)
-	    *script_index = i;
-
-	  return FALSE;
-	}
-    }
-
-  return FALSE;
+  return hb_ot_layout_table_find_script (info->layout, tt,
+					 script_tag,
+					 script_index);
 }
 
 /**
@@ -504,60 +407,22 @@ pango_ot_info_find_language (PangoOTInfo      *info,
 			     guint            *language_index,
 			     guint            *required_feature_index)
 {
-  HB_ScriptList *script_list;
-  HB_ScriptTable *script;
-  int i;
-
-  if (language_index)
-    *language_index = PANGO_OT_DEFAULT_LANGUAGE;
-  if (required_feature_index)
-    *required_feature_index = PANGO_OT_NO_FEATURE;
-
-  g_return_val_if_fail (PANGO_IS_OT_INFO (info), FALSE);
-
-  if (script_index == PANGO_OT_NO_SCRIPT)
-    return FALSE;
-
-  if (!get_tables (info, table_type, &script_list, NULL))
-    return FALSE;
-
-  g_return_val_if_fail (script_index < script_list->ScriptCount, FALSE);
-  script = &script_list->ScriptRecord[script_index].Script;
-
-  for (i = 0; i < script->LangSysCount; i++)
-    {
-      if (script->LangSysRecord[i].LangSysTag == language_tag)
-	{
-	  if (language_index)
-	    *language_index = i;
-	  if (required_feature_index)
-	    *required_feature_index = script->LangSysRecord[i].LangSys.ReqFeatureIndex;
-	  return TRUE;
-	}
-    }
-
-  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
-  language_tag = PANGO_OT_TAG_MAKE ('d', 'f', 'l', 't');
-
-  for (i = 0; i < script->LangSysCount; i++)
-    {
-      if (script->LangSysRecord[i].LangSysTag == language_tag)
-	{
-	  if (language_index)
-	    *language_index = i;
-	  if (required_feature_index)
-	    *required_feature_index = script->LangSysRecord[i].LangSys.ReqFeatureIndex;
-	  return FALSE;
-	}
-    }
-
-  /* DefaultLangSys */
-  if (language_index)
-    *language_index = PANGO_OT_DEFAULT_LANGUAGE;
-  if (required_feature_index)
-    *required_feature_index = script->DefaultLangSys.ReqFeatureIndex;
-
-  return FALSE;
+  gboolean ret;
+  unsigned l_index;
+  hb_ot_layout_table_type_t tt = get_hb_table_type (table_type);
+
+  ret = hb_ot_layout_script_find_language (info->layout, tt,
+					   script_index,
+					   language_tag,
+					   &l_index);
+  if (language_index) *language_index = l_index;
+
+  hb_ot_layout_language_get_required_feature_index (info->layout, tt,
+						    script_index,
+						    l_index,
+						    required_feature_index);
+
+  return ret;
 }
 
 /**
@@ -590,50 +455,13 @@ pango_ot_info_find_feature  (PangoOTInfo      *info,
 			     guint             language_index,
 			     guint            *feature_index)
 {
-  HB_ScriptList *script_list;
-  HB_FeatureList *feature_list;
-  HB_ScriptTable *script;
-  HB_LangSys *lang_sys;
-
-  int i;
-
-  if (feature_index)
-    *feature_index = PANGO_OT_NO_FEATURE;
-
-  g_return_val_if_fail (PANGO_IS_OT_INFO (info), FALSE);
-
-  if (script_index == PANGO_OT_NO_SCRIPT)
-    return FALSE;
+  hb_ot_layout_table_type_t tt = get_hb_table_type (table_type);
 
-  if (!get_tables (info, table_type, &script_list, &feature_list))
-    return FALSE;
-
-  g_return_val_if_fail (script_index < script_list->ScriptCount, FALSE);
-  script = &script_list->ScriptRecord[script_index].Script;
-
-  if (language_index == PANGO_OT_DEFAULT_LANGUAGE)
-    lang_sys = &script->DefaultLangSys;
-  else
-    {
-      g_return_val_if_fail (language_index < script->LangSysCount, FALSE);
-      lang_sys = &script->LangSysRecord[language_index].LangSys;
-    }
-
-  for (i = 0; i < lang_sys->FeatureCount; i++)
-    {
-      HB_UShort index = lang_sys->FeatureIndex[i];
-
-      if (index < feature_list->FeatureCount &&
-	  feature_list->FeatureRecord[index].FeatureTag == feature_tag)
-	{
-	  if (feature_index)
-	    *feature_index = index;
-
-	  return TRUE;
-	}
-    }
-
-  return FALSE;
+  return hb_ot_layout_language_find_feature (info->layout, tt,
+					     script_index,
+					     language_index,
+					     feature_tag,
+					     feature_index);
 }
 
 /**
@@ -650,19 +478,16 @@ PangoOTTag *
 pango_ot_info_list_scripts (PangoOTInfo      *info,
 			    PangoOTTableType  table_type)
 {
+  hb_ot_layout_table_type_t tt = get_hb_table_type (table_type);
   PangoOTTag *result;
-  HB_ScriptList *script_list;
-  int i;
-
-  g_return_val_if_fail (PANGO_IS_OT_INFO (info), NULL);
+  unsigned int count, i;
 
-  if (!get_tables (info, table_type, &script_list, NULL))
-    return NULL;
+  count = hb_ot_layout_table_get_script_count (info->layout, tt);
 
-  result = g_new (PangoOTTag, script_list->ScriptCount + 1);
+  result = g_new (PangoOTTag, count + 1);
 
-  for (i=0; i < script_list->ScriptCount; i++)
-    result[i] = script_list->ScriptRecord[i].ScriptTag;
+  for (i = 0; i < count; i++)
+    result[i] = hb_ot_layout_table_get_script_tag (info->layout, tt, i);
 
   result[i] = 0;
 
@@ -687,30 +512,19 @@ pango_ot_info_list_languages (PangoOTInfo      *info,
 			      guint             script_index,
 			      PangoOTTag        language_tag G_GNUC_UNUSED)
 {
+  hb_ot_layout_table_type_t tt = get_hb_table_type (table_type);
   PangoOTTag *result;
-  HB_ScriptList *script_list;
-  HB_ScriptTable *script;
-  int i;
+  unsigned int count, i;
 
-  g_return_val_if_fail (PANGO_IS_OT_INFO (info), NULL);
-
-  if (script_index == PANGO_OT_NO_SCRIPT)
-    {
-      result = g_new (PangoOTTag, 0+1);
-      result[0] = 0;
-      return result;
-    }
+  count = hb_ot_layout_script_get_language_count (info->layout, tt,
+						  script_index);
 
-  if (!get_tables (info, table_type, &script_list, NULL))
-    return NULL;
+  result = g_new (PangoOTTag, count + 1);
 
-  g_return_val_if_fail (script_index < script_list->ScriptCount, NULL);
-  script = &script_list->ScriptRecord[script_index].Script;
-
-  result = g_new (PangoOTTag, script->LangSysCount + 1);
-
-  for (i = 0; i < script->LangSysCount; i++)
-    result[i] = script->LangSysRecord[i].LangSysTag;
+  for (i = 0; i < count; i++)
+    result[i] = hb_ot_layout_script_get_language_tag (info->layout, tt,
+						      script_index,
+						      i);
 
   result[i] = 0;
 
@@ -739,52 +553,23 @@ pango_ot_info_list_features  (PangoOTInfo      *info,
 			      guint             script_index,
 			      guint             language_index)
 {
+  hb_ot_layout_table_type_t tt = get_hb_table_type (table_type);
   PangoOTTag *result;
+  unsigned int count, i;
 
-  HB_ScriptList *script_list;
-  HB_FeatureList *feature_list;
-  HB_ScriptTable *script;
-  HB_LangSys *lang_sys;
+  count = hb_ot_layout_language_get_feature_count (info->layout, tt,
+						   script_index,
+						   language_index);
 
-  int i, j;
+  result = g_new (PangoOTTag, count + 1);
 
-  g_return_val_if_fail (PANGO_IS_OT_INFO (info), NULL);
+  for (i = 0; i < count; i++)
+    result[i] = hb_ot_layout_language_get_feature_tag (info->layout, tt,
+						       script_index,
+						       language_index,
+						       i);
 
-  if (script_index == PANGO_OT_NO_SCRIPT)
-    {
-      result = g_new (PangoOTTag, 0+1);
-      result[0] = 0;
-      return result;
-    }
-
-  if (!get_tables (info, table_type, &script_list, &feature_list))
-    return NULL;
-
-  g_return_val_if_fail (script_index < script_list->ScriptCount, NULL);
-  script = &script_list->ScriptRecord[script_index].Script;
-
-  if (language_index == PANGO_OT_DEFAULT_LANGUAGE)
-    lang_sys = &script->DefaultLangSys;
-  else
-    {
-      g_return_val_if_fail (language_index < script->LangSysCount, NULL);
-      lang_sys = &script->LangSysRecord[language_index].LangSys;
-    }
-
-  result = g_new (PangoOTTag, lang_sys->FeatureCount + 1);
-
-  j = 0;
-  for (i = 0; i < lang_sys->FeatureCount; i++)
-    {
-      HB_UShort index = lang_sys->FeatureIndex[i];
-
-      if (index < feature_list->FeatureCount)
-	result[j++] = feature_list->FeatureRecord[index].FeatureTag;
-    }
-
-  result[j] = 0;
+  result[i] = 0;
 
   return result;
 }
-
-
diff --git a/pango/pango-ot-private.h b/pango/pango-ot-private.h
index 2103194..0ba3984 100644
--- a/pango/pango-ot-private.h
+++ b/pango/pango-ot-private.h
@@ -39,8 +39,8 @@ struct _PangoOTInfo
 
   FT_Face face;
 
+  hb_ot_layout_t *layout;
   HB_GSUB gsub;
-  HB_GDEF gdef;
   HB_GPOS gpos;
 };
 
@@ -80,7 +80,7 @@ struct _PangoOTBuffer
   guint applied_gpos : 1;
 };
 
-HB_GDEF pango_ot_info_get_gdef (PangoOTInfo *info);
+hb_ot_layout_t *_pango_ot_info_get_layout (PangoOTInfo *info);
 HB_GSUB pango_ot_info_get_gsub (PangoOTInfo *info);
 HB_GPOS pango_ot_info_get_gpos (PangoOTInfo *info);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]