Merge harfbuzz-ng
authorBehdad Esfahbod <behdad@behdad.org>
Mon, 2 Nov 2009 19:35:51 +0000 (14:35 -0500)
committerBehdad Esfahbod <behdad@behdad.org>
Mon, 2 Nov 2009 19:38:33 +0000 (14:38 -0500)
14 files changed:
1  2 
src/Makefile.am
src/harfbuzz-buffer-private.h
src/harfbuzz-global.h
src/harfbuzz-gpos.c
src/harfbuzz-gpos.h
src/harfbuzz-gsub.c
src/harfbuzz-gsub.h
src/harfbuzz-impl.h
src/harfbuzz-open.c
src/harfbuzz.h
src/hb-ot-layout-gsub-private.h
src/hb-ot-layout-open-private.h
src/hb-ot-layout.cc
src/main.cc

diff --cc src/Makefile.am
index 5c0b18e,0000000..40644c1
mode 100644,000000..100644
--- /dev/null
@@@ -1,64 -1,0 +1,68 @@@
-       $(FREETYPE_CFLAGS)
 +## Process this file with automake to produce Makefile.in
 +
 +INCLUDES =                                    \
 +      -I $(srcdir)                            \
-       harfbuzz.c
++      $(FREETYPE_CFLAGS)                      \
++      $(GLIB_CFLAGS)
++CXX = gcc $(GCCOPTS) -fno-rtti -fno-exceptions -Wabi -Wpadded -Wcast-align
 +
 +noinst_LTLIBRARIES = libharfbuzz-1.la
 +
 +MAINSOURCES =  \
-       harfbuzz-gdef.c \
++      $(INCLUDEDSOURCES) \
++      hb-ot-layout.cc
++#     harfbuzz.c
 +
 +# included from harfbuzz.c
 +INCLUDEDSOURCES = \
 +      harfbuzz-buffer.c \
-       harfbuzz-gdef.h \
 +      harfbuzz-gpos.c \
 +      harfbuzz-gsub.c \
 +      harfbuzz-impl.c \
 +      harfbuzz-open.c \
 +      harfbuzz-stream.c
 +
 +PUBLICHEADERS = \
 +      harfbuzz.h \
 +      harfbuzz-global.h \
 +      harfbuzz-buffer.h \
-       harfbuzz-gdef-private.h \
 +      harfbuzz-gpos.h \
 +      harfbuzz-gsub.h \
 +      harfbuzz-open.h
 +
 +PRIVATEHEADERS = \
 +      harfbuzz-impl.h \
 +      harfbuzz-buffer-private.h \
- noinst_PROGRAMS = harfbuzz-dump
 +      harfbuzz-gpos-private.h \
 +      harfbuzz-gsub-private.h \
 +      harfbuzz-open-private.h \
 +      harfbuzz-stream-private.h
 +
 +libharfbuzz_1_la_SOURCES = \
 +      $(MAINSOURCES) \
 +      $(PUBLICHEADERS) \
 +      $(PRIVATEHEADERS)
 +
 +libharfbuzz_1_la_LIBADD = \
 +      $(FREETYPE_LIBS)
 +
++noinst_PROGRAMS = harfbuzz-dump main
 +
 +harfbuzz_dump_SOURCES =       \
 +      harfbuzz-dump.c \
 +      harfbuzz-dump.h \
 +      harfbuzz-dump-main.c
 +
 +harfbuzz_dump_LDADD = \
 +      $(libharfbuzz_1_la_LIBADD) \
 +      libharfbuzz-1.la
 +
++main_LDADD = \
++      $(GLIB_LIBS)
++
 +EXTRA_DIST =          \
 +      README          \
 +      COPYING         \
 +      $(INCLUDEDSOURCES)
 +
 +-include $(top_srcdir)/git.mk
index 5065f2e,0000000..02ae336
mode 100644,000000..100644
--- /dev/null
@@@ -1,107 -1,0 +1,107 @@@
- #define CHECK_Property( gdef, index, flags, property )                                        \
-           ( ( error = _HB_GDEF_Check_Property( (gdef), (index), (flags),              \
-                                       (property) ) ) != HB_Err_Ok )
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2004,2007  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): Owen Taylor, Behdad Esfahbod
 + */
 +
 +#ifndef HARFBUZZ_BUFFER_PRIVATE_H
 +#define HARFBUZZ_BUFFER_PRIVATE_H
 +
 +#include "harfbuzz-impl.h"
 +#include "harfbuzz-buffer.h"
 +
 +HB_BEGIN_HEADER
 +
 +#define HB_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
 +
 +HB_INTERNAL void
 +_hb_buffer_swap( HB_Buffer buffer );
 +
 +HB_INTERNAL void
 +_hb_buffer_clear_output( HB_Buffer buffer );
 +
 +HB_INTERNAL HB_Error
 +_hb_buffer_clear_positions( HB_Buffer buffer );
 +
 +HB_INTERNAL HB_Error
 +_hb_buffer_add_output_glyphs( HB_Buffer  buffer,
 +                            HB_UShort  num_in,
 +                            HB_UShort  num_out,
 +                            HB_UShort *glyph_data,
 +                            HB_UShort  component,
 +                            HB_UShort  ligID );
 +
 +HB_INTERNAL HB_Error
 +_hb_buffer_add_output_glyph ( HB_Buffer buffer,
 +                            HB_UInt   glyph_index,
 +                            HB_UShort component,
 +                            HB_UShort ligID );
 +
 +HB_INTERNAL HB_Error
 +_hb_buffer_copy_output_glyph ( HB_Buffer buffer );
 +
 +HB_INTERNAL HB_Error
 +_hb_buffer_replace_output_glyph ( HB_Buffer buffer,
 +                                HB_UInt   glyph_index,
 +                                HB_Bool   inplace );
 +
 +HB_INTERNAL HB_UShort
 +_hb_buffer_allocate_ligid( HB_Buffer buffer );
 +
 +
 +/* convenience macros */
 +
 +#define IN_GLYPH( pos )        (buffer->in_string[(pos)].gindex)
 +#define IN_ITEM( pos )         (&buffer->in_string[(pos)])
 +#define IN_CURGLYPH()          (buffer->in_string[buffer->in_pos].gindex)
 +#define IN_CURITEM()           (&buffer->in_string[buffer->in_pos])
 +#define IN_PROPERTIES( pos )   (buffer->in_string[(pos)].properties)
 +#define IN_LIGID( pos )        (buffer->in_string[(pos)].ligID)
 +#define IN_COMPONENT( pos )    (buffer->in_string[(pos)].component)
 +#define POSITION( pos )        (&buffer->positions[(pos)])
 +#define OUT_GLYPH( pos )       (buffer->out_string[(pos)].gindex)
 +#define OUT_ITEM( pos )        (&buffer->out_string[(pos)])
 +
++#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),                            \
 +                                                  (num_in), (num_out),                \
 +                                                    (glyph_data), (component), (ligID)  \
 +                                                  ) ) != HB_Err_Ok )
 +#define ADD_Glyph( buffer, glyph_index, component, ligID )                            \
 +          ( ( error = _hb_buffer_add_output_glyph( (buffer),                             \
 +                                                    (glyph_index), (component), (ligID) \
 +                                                  ) ) != HB_Err_Ok )
 +#define REPLACE_Glyph( buffer, glyph_index, nesting_level )                           \
 +          ( ( error = _hb_buffer_replace_output_glyph( (buffer), (glyph_index),               \
 +                                                    (nesting_level) == 1 ) ) != HB_Err_Ok )
 +#define COPY_Glyph( buffer )                                                          \
 +        ( (error = _hb_buffer_copy_output_glyph ( buffer ) ) != HB_Err_Ok )
 +
 +HB_END_HEADER
 +
 +#endif /* HARFBUZZ_BUFFER_PRIVATE_H */
index dab20b5,0000000..7b8a0f2
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,84 @@@
 +/*
 + * Copyright (C) 2007  Trolltech ASA
 + * Copyright (C) 2007  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 HARFBUZZ_GLOBAL_H
 +#define HARFBUZZ_GLOBAL_H
 +
++/* XXX */
++#include "hb-ot-layout.h"
++
 +#include <ft2build.h>
 +#include FT_FREETYPE_H
 +
 +#ifdef __cplusplus
 +#define HB_BEGIN_HEADER  extern "C" {
 +#define HB_END_HEADER  }
 +#else
 +#define HB_BEGIN_HEADER  /* nothing */
 +#define HB_END_HEADER  /* nothing */
 +#endif
 +
 +HB_BEGIN_HEADER
 +
 +#define HB_MAKE_TAG(a,b,c,d) FT_MAKE_TAG(a,b,c,d)
 +typedef FT_Pos                HB_Fixed;       /* 26.6 */
 +typedef FT_Fixed      HB_16Dot16;     /* 16.6 */
 +typedef FT_Face               HB_Font;
 +
 +typedef unsigned char HB_Byte;
 +typedef signed char   HB_Char;
 +typedef unsigned short        HB_UShort;
 +typedef signed short  HB_Short;
 +typedef unsigned int  HB_UInt;
 +typedef signed int    HB_Int;
 +typedef int           HB_Bool;
 +typedef void *                HB_Pointer;
 +
 +
 +typedef enum {
 +  /* no error */
 +  HB_Err_Ok                           = 0x0000,
 +  HB_Err_Not_Covered                  = 0xFFFF,
 +
 +  /* _hb_err() is called whenever returning the following errors,
 +   * and in a couple places for HB_Err_Not_Covered too. */
 +
 +  /* programmer error */
 +  HB_Err_Invalid_Argument             = 0x1A66,
 +
 +  /* font error */
 +  HB_Err_Invalid_SubTable_Format      = 0x157F,
 +  HB_Err_Invalid_SubTable             = 0x1570,
 +  HB_Err_Read_Error                   = 0x6EAD,
 +
 +  /* system error */
 +  HB_Err_Out_Of_Memory                = 0xDEAD
 +} HB_Error;
 +
 +HB_END_HEADER
 +
 +#endif
index c78dcba,0000000..560a291
mode 100644,000000..100644
--- /dev/null
@@@ -1,6082 -1,0 +1,6071 @@@
-                             HB_GDEFHeader*  gdef )
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2006  Behdad Esfahbod
 + * Copyright (C) 2007  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
 + */
 +
 +#include "harfbuzz-impl.h"
 +#include "harfbuzz-gpos-private.h"
 +#include "harfbuzz-open-private.h"
 +#include "harfbuzz-gdef-private.h"
 +
 +struct  GPOS_Instance_
 +{
 +  HB_GPOSHeader*  gpos;
 +  HB_Font          font;
 +  HB_Bool          dvi;
 +  HB_UShort        load_flags;  /* how the glyph should be loaded */
 +  HB_Bool          r2l;
 +
 +  HB_UShort        last;        /* the last valid glyph -- used
 +                                 with cursive positioning     */
 +  HB_Fixed           anchor_x;    /* the coordinates of the anchor point */
 +  HB_Fixed           anchor_y;    /* of the last valid glyph             */
 +};
 +
 +typedef struct GPOS_Instance_  GPOS_Instance;
 +
 +
 +static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
 +                                     HB_UShort         lookup_index,
 +                                     HB_Buffer        buffer,
 +                                     HB_UShort         context_length,
 +                                     int               nesting_level );
 +
 +
 +
 +/* the client application must replace this with something more
 +   meaningful if multiple master fonts are to be supported.     */
 +
 +static HB_Error  default_mmfunc( HB_Font      font,
 +                               HB_UShort    metric_id,
 +                               HB_Fixed*      metric_value,
 +                               void*        data )
 +{
 +  HB_UNUSED(font);
 +  HB_UNUSED(metric_id);
 +  HB_UNUSED(metric_value);
 +  HB_UNUSED(data);
 +  return ERR(HB_Err_Not_Covered); /* ERR() call intended */
 +}
 +
 +
 +
 +HB_Error  HB_Load_GPOS_Table( HB_Font          font,
 +                            HB_GPOSHeader** retptr,
-   if ( !retptr )
++                            hb_ot_layout_t    *layout )
 +{
 +  HB_UInt         cur_offset, new_offset, base_offset;
 +
 +  HB_GPOSHeader*  gpos;
 +
 +  HB_Stream  stream = font->stream;
 +  HB_Error   error;
 +
 +
-   gpos->gdef = gdef;      /* can be NULL */
-   if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream,
-                                                                    gpos->LookupList.Lookup,
-                                                                    gpos->LookupList.LookupCount ) ) )
-         goto Fail1;
++  if ( !retptr || !layout )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  if ( GOTO_Table( TTAG_GPOS ) )
 +    return error;
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ALLOC ( gpos, sizeof( *gpos ) ) )
 +    return error;
 +
 +  gpos->gfunc = (HB_GlyphFunction) FT_Load_Glyph;
 +  gpos->mmfunc = default_mmfunc;
 +
 +  /* skip version */
 +
 +  if ( FILE_Seek( base_offset + 4L ) ||
 +       ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
 +                                stream ) ) != HB_Err_Ok )
 +    goto Fail4;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
 +                                 stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
 +                                stream, HB_Type_GPOS ) ) != HB_Err_Ok )
 +    goto Fail2;
 +
- Fail1:
-   _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
++  gpos->layout = layout;      /* can be NULL */
 +
 +  *retptr = gpos;
 +
 +  return HB_Err_Ok;
 +
-   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
 +Fail2:
 +  _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
 +
 +Fail3:
 +  _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
 +
 +Fail4:
 +  FREE( gpos );
 +
 +  return error;
 +}
 +
 +
 +HB_Error  HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
 +{
 +  _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
 +  _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
 +  _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
 +
 +  FREE( gpos );
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/*****************************
 + * SubTable related functions
 + *****************************/
 +
 +/* shared tables */
 +
 +/* ValueRecord */
 +
 +/* There is a subtle difference in the specs between a `table' and a
 +   `record' -- offsets for device tables in ValueRecords are taken from
 +   the parent table and not the parent record.                          */
 +
 +static HB_Error  Load_ValueRecord( HB_ValueRecord*  vr,
 +                                 HB_UShort         format,
 +                                 HB_UInt          base_offset,
 +                                 HB_Stream         stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UInt cur_offset, new_offset;
 +
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      return error;
 +
 +    vr->XPlacement = GET_Short();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->XPlacement = 0;
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      return error;
 +
 +    vr->YPlacement = GET_Short();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->YPlacement = 0;
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      return error;
 +
 +    vr->XAdvance = GET_Short();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->XAdvance = 0;
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      return error;
 +
 +    vr->YAdvance = GET_Short();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->YAdvance = 0;
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      return error;
 +
 +    new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = _HB_OPEN_Load_Device( &vr->XPlacementDevice,
 +                                stream ) ) != HB_Err_Ok )
 +      return error;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +      goto empty1;
 +  }
 +  else
 +  {
 +  empty1:
 +    vr->XPlacementDevice.StartSize  = 0;
 +    vr->XPlacementDevice.EndSize    = 0;
 +    vr->XPlacementDevice.DeltaValue = NULL;
 +  }
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail3;
 +
 +    new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice,
 +                                stream ) ) != HB_Err_Ok )
 +      goto Fail3;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +      goto empty2;
 +  }
 +  else
 +  {
 +  empty2:
 +    vr->YPlacementDevice.StartSize  = 0;
 +    vr->YPlacementDevice.EndSize    = 0;
 +    vr->YPlacementDevice.DeltaValue = NULL;
 +  }
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = _HB_OPEN_Load_Device( &vr->XAdvanceDevice,
 +                                stream ) ) != HB_Err_Ok )
 +      goto Fail2;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +      goto empty3;
 +  }
 +  else
 +  {
 +  empty3:
 +    vr->XAdvanceDevice.StartSize  = 0;
 +    vr->XAdvanceDevice.EndSize    = 0;
 +    vr->XAdvanceDevice.DeltaValue = NULL;
 +  }
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice,
 +                                stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +      goto empty4;
 +  }
 +  else
 +  {
 +  empty4:
 +    vr->YAdvanceDevice.StartSize  = 0;
 +    vr->YAdvanceDevice.EndSize    = 0;
 +    vr->YAdvanceDevice.DeltaValue = NULL;
 +  }
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    vr->XIdPlacement = GET_UShort();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->XIdPlacement = 0;
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    vr->YIdPlacement = GET_UShort();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->YIdPlacement = 0;
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    vr->XIdAdvance = GET_UShort();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->XIdAdvance = 0;
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    vr->YIdAdvance = GET_UShort();
 +
 +    FORGET_Frame();
 +  }
 +  else
 +    vr->YIdAdvance = 0;
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
 +
 +Fail2:
 +  _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
 +
 +Fail3:
 +  _HB_OPEN_Free_Device( &vr->YPlacementDevice );
 +  return error;
 +}
 +
 +
 +static void  Free_ValueRecord( HB_ValueRecord*  vr,
 +                             HB_UShort         format )
 +{
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
 +    _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
 +    _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
 +    _HB_OPEN_Free_Device( &vr->YPlacementDevice );
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
 +    _HB_OPEN_Free_Device( &vr->XPlacementDevice );
 +}
 +
 +
 +static HB_Error  Get_ValueRecord( GPOS_Instance*    gpi,
 +                                HB_ValueRecord*  vr,
 +                                HB_UShort         format,
 +                                HB_Position      gd )
 +{
 +  HB_Fixed           value;
 +  HB_Short         pixel_value;
 +  HB_Error         error = HB_Err_Ok;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +
 +  HB_UShort  x_ppem, y_ppem;
 +  HB_16Dot16   x_scale, y_scale;
 +
 +
 +  if ( !format )
 +    return HB_Err_Ok;
 +
 +  x_ppem  = gpi->font->size->metrics.x_ppem;
 +  y_ppem  = gpi->font->size->metrics.y_ppem;
 +  x_scale = gpi->font->size->metrics.x_scale;
 +  y_scale = gpi->font->size->metrics.y_scale;
 +
 +  /* design units -> fractional pixel */
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
 +    gd->x_pos += x_scale * vr->XPlacement / 0x10000;
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
 +    gd->y_pos += y_scale * vr->YPlacement / 0x10000;
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
 +    gd->x_advance += x_scale * vr->XAdvance / 0x10000;
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
 +    gd->y_advance += y_scale * vr->YAdvance / 0x10000;
 +
 +  if ( !gpi->dvi )
 +  {
 +    /* pixel -> fractional pixel */
 +
 +    if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
 +    {
 +      _HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
 +      gd->x_pos += pixel_value << 6;
 +    }
 +    if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
 +    {
 +      _HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
 +      gd->y_pos += pixel_value << 6;
 +    }
 +    if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
 +    {
 +      _HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
 +      gd->x_advance += pixel_value << 6;
 +    }
 +    if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
 +    {
 +      _HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
 +      gd->y_advance += pixel_value << 6;
 +    }
 +  }
 +
 +  /* values returned from mmfunc() are already in fractional pixels */
 +
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
 +  {
 +    error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
 +                          &value, gpos->data );
 +    if ( error )
 +      return error;
 +    gd->x_pos += value;
 +  }
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
 +  {
 +    error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
 +                          &value, gpos->data );
 +    if ( error )
 +      return error;
 +    gd->y_pos += value;
 +  }
 +  if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
 +  {
 +    error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
 +                          &value, gpos->data );
 +    if ( error )
 +      return error;
 +    gd->x_advance += value;
 +  }
 +  if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
 +  {
 +    error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
 +                          &value, gpos->data );
 +    if ( error )
 +      return error;
 +    gd->y_advance += value;
 +  }
 +
 +  return error;
 +}
 +
 +
 +/* AnchorFormat1 */
 +/* AnchorFormat2 */
 +/* AnchorFormat3 */
 +/* AnchorFormat4 */
 +
 +static HB_Error  Load_Anchor( HB_Anchor*  an,
 +                            HB_Stream    stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UInt cur_offset, new_offset, base_offset;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  an->PosFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  switch ( an->PosFormat )
 +  {
 +  case 1:
 +    if ( ACCESS_Frame( 4L ) )
 +      return error;
 +
 +    an->af.af1.XCoordinate = GET_Short();
 +    an->af.af1.YCoordinate = GET_Short();
 +
 +    FORGET_Frame();
 +    break;
 +
 +  case 2:
 +    if ( ACCESS_Frame( 6L ) )
 +      return error;
 +
 +    an->af.af2.XCoordinate = GET_Short();
 +    an->af.af2.YCoordinate = GET_Short();
 +    an->af.af2.AnchorPoint = GET_UShort();
 +
 +    FORGET_Frame();
 +    break;
 +
 +  case 3:
 +    if ( ACCESS_Frame( 6L ) )
 +      return error;
 +
 +    an->af.af3.XCoordinate = GET_Short();
 +    an->af.af3.YCoordinate = GET_Short();
 +
 +    new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable,
 +                                stream ) ) != HB_Err_Ok )
 +      return error;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +    {
 +      an->af.af3.XDeviceTable.StartSize  = 0;
 +      an->af.af3.XDeviceTable.EndSize    = 0;
 +      an->af.af3.XDeviceTable.DeltaValue = NULL;
 +    }
 +
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable,
 +                                stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +    {
 +      an->af.af3.YDeviceTable.StartSize  = 0;
 +      an->af.af3.YDeviceTable.EndSize    = 0;
 +      an->af.af3.YDeviceTable.DeltaValue = NULL;
 +    }
 +    break;
 +
 +  case 4:
 +    if ( ACCESS_Frame( 4L ) )
 +      return error;
 +
 +    an->af.af4.XIdAnchor = GET_UShort();
 +    an->af.af4.YIdAnchor = GET_UShort();
 +
 +    FORGET_Frame();
 +    break;
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
 +  return error;
 +}
 +
 +
 +static void  Free_Anchor( HB_Anchor*  an )
 +{
 +  if ( an->PosFormat == 3 )
 +  {
 +    _HB_OPEN_Free_Device( &an->af.af3.YDeviceTable );
 +    _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
 +  }
 +}
 +
 +
 +static HB_Error  Get_Anchor( GPOS_Instance*   gpi,
 +                           HB_Anchor*      an,
 +                           HB_UShort        glyph_index,
 +                           HB_Fixed*          x_value,
 +                           HB_Fixed*          y_value )
 +{
 +  HB_Error  error = HB_Err_Ok;
 +
 +  FT_Outline       outline;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +  HB_UShort        ap;
 +
 +  HB_Short         pixel_value;
 +  HB_UShort        load_flags;
 +
 +  HB_UShort        x_ppem, y_ppem;
 +  HB_16Dot16         x_scale, y_scale;
 +
 +
 +  x_ppem  = gpi->font->size->metrics.x_ppem;
 +  y_ppem  = gpi->font->size->metrics.y_ppem;
 +  x_scale = gpi->font->size->metrics.x_scale;
 +  y_scale = gpi->font->size->metrics.y_scale;
 +
 +  switch ( an->PosFormat )
 +  {
 +  case 0:
 +    /* The special case of an empty AnchorTable */
 +  default:
 +
 +    return HB_Err_Not_Covered;
 +
 +  case 1:
 +    *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
 +    *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
 +    break;
 +
 +  case 2:
 +    /* glyphs must be scaled */
 +
 +    load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE;
 +
 +    if ( !gpi->dvi )
 +    {
 +      error = (gpos->gfunc)( gpi->font, glyph_index, load_flags );
 +      if ( error )
 +      return error;
 +
 +      if ( gpi->font->glyph->format != ft_glyph_format_outline )
 +      return ERR(HB_Err_Invalid_SubTable);
 +
 +      ap = an->af.af2.AnchorPoint;
 +
 +      outline = gpi->font->glyph->outline;
 +
 +      /* if n_points is set to zero, we use the design coordinate value pair.
 +       * This can happen e.g. for sbit glyphs. */ 
 +      if ( !outline.n_points )
 +      goto no_contour_point;
 +
 +      if ( ap >= outline.n_points )
 +      return ERR(HB_Err_Invalid_SubTable);
 +
 +      *x_value = outline.points[ap].x;
 +      *y_value = outline.points[ap].y;
 +    }
 +    else
 +    {
 +    no_contour_point:
 +      *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
 +      *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
 +    }
 +    break;
 +
 +  case 3:
 +    if ( !gpi->dvi )
 +    {
 +      _HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
 +      *x_value = pixel_value << 6;
 +      _HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
 +      *y_value = pixel_value << 6;
 +    }
 +    else
 +      *x_value = *y_value = 0;
 +
 +    *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
 +    *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
 +    break;
 +
 +  case 4:
 +    error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
 +                          x_value, gpos->data );
 +    if ( error )
 +      return error;
 +
 +    error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
 +                          y_value, gpos->data );
 +    if ( error )
 +      return error;
 +    break;
 +  }
 +
 +  return error;
 +}
 +
 +
 +/* MarkArray */
 +
 +static HB_Error  Load_MarkArray ( HB_MarkArray*  ma,
 +                                HB_Stream       stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort        n, m, count;
 +  HB_UInt         cur_offset, new_offset, base_offset;
 +
 +  HB_MarkRecord*  mr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = ma->MarkCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ma->MarkRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
 +    return error;
 +
 +  mr = ma->MarkRecord;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 4L ) )
 +      goto Fail;
 +
 +    mr[n].Class = GET_UShort();
 +    new_offset  = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_Anchor( &mr[m].MarkAnchor );
 +
 +  FREE( mr );
 +  return error;
 +}
 +
 +
 +static void  Free_MarkArray( HB_MarkArray*  ma )
 +{
 +  HB_UShort        n, count;
 +
 +  HB_MarkRecord*  mr;
 +
 +
 +  if ( ma->MarkRecord )
 +  {
 +    count = ma->MarkCount;
 +    mr    = ma->MarkRecord;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_Anchor( &mr[n].MarkAnchor );
 +
 +    FREE( mr );
 +  }
 +}
 +
 +
 +/* LookupType 1 */
 +
 +/* SinglePosFormat1 */
 +/* SinglePosFormat2 */
 +
 +static HB_Error  Load_SinglePos( HB_GPOS_SubTable* st,
 +                               HB_Stream       stream )
 +{
 +  HB_Error  error;
 +  HB_SinglePos*   sp = &st->single;
 +
 +  HB_UShort         n, m, count, format;
 +  HB_UInt          cur_offset, new_offset, base_offset;
 +
 +  HB_ValueRecord*  vr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 6L ) )
 +    return error;
 +
 +  sp->PosFormat = GET_UShort();
 +  new_offset    = GET_UShort() + base_offset;
 +
 +  format = sp->ValueFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( !format )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  switch ( sp->PosFormat )
 +  {
 +  case 1:
 +    error = Load_ValueRecord( &sp->spf.spf1.Value, format,
 +                            base_offset, stream );
 +    if ( error )
 +      goto Fail2;
 +    break;
 +
 +  case 2:
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    count = sp->spf.spf2.ValueCount = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    sp->spf.spf2.Value = NULL;
 +
 +    if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
 +      goto Fail2;
 +
 +    vr = sp->spf.spf2.Value;
 +
 +    for ( n = 0; n < count; n++ )
 +    {
 +      error = Load_ValueRecord( &vr[n], format, base_offset, stream );
 +      if ( error )
 +      goto Fail1;
 +    }
 +    break;
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_ValueRecord( &vr[m], format );
 +
 +  FREE( vr );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &sp->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_SinglePos( HB_GPOS_SubTable* st )
 +{
 +  HB_UShort         n, count, format;
 +  HB_SinglePos*   sp = &st->single;
 +
 +  HB_ValueRecord*  v;
 +
 +
 +  format = sp->ValueFormat;
 +
 +  switch ( sp->PosFormat )
 +  {
 +  case 1:
 +    Free_ValueRecord( &sp->spf.spf1.Value, format );
 +    break;
 +
 +  case 2:
 +    if ( sp->spf.spf2.Value )
 +    {
 +      count = sp->spf.spf2.ValueCount;
 +      v     = sp->spf.spf2.Value;
 +
 +      for ( n = 0; n < count; n++ )
 +      Free_ValueRecord( &v[n], format );
 +
 +      FREE( v );
 +    }
 +    break;
 +  default:
 +    break;
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &sp->Coverage );
 +}
 +
 +static HB_Error  Lookup_SinglePos( GPOS_Instance*    gpi,
 +                                 HB_GPOS_SubTable* st,
 +                                 HB_Buffer        buffer,
 +                                 HB_UShort         flags,
 +                                 HB_UShort         context_length,
 +                                 int               nesting_level )
 +{
 +  HB_UShort        index, property;
 +  HB_Error         error;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +  HB_SinglePos*   sp = &st->single;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  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 );
 +  if ( error )
 +    return error;
 +
 +  switch ( sp->PosFormat )
 +  {
 +  case 1:
 +    error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
 +                           sp->ValueFormat, POSITION( buffer->in_pos ) );
 +    if ( error )
 +      return error;
 +    break;
 +
 +  case 2:
 +    if ( index >= sp->spf.spf2.ValueCount )
 +      return ERR(HB_Err_Invalid_SubTable);
 +    error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
 +                           sp->ValueFormat, POSITION( buffer->in_pos ) );
 +    if ( error )
 +      return error;
 +    break;
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable);
 +  }
 +
 +  (buffer->in_pos)++;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 2 */
 +
 +/* PairSet */
 +
 +static HB_Error  Load_PairSet ( HB_PairSet*  ps,
 +                              HB_UShort     format1,
 +                              HB_UShort     format2,
 +                              HB_Stream     stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, m, count;
 +  HB_UInt              base_offset;
 +
 +  HB_PairValueRecord*  pvr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = ps->PairValueCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ps->PairValueRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
 +    return error;
 +
 +  pvr = ps->PairValueRecord;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    pvr[n].SecondGlyph = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( format1 )
 +    {
 +      error = Load_ValueRecord( &pvr[n].Value1, format1,
 +                              base_offset, stream );
 +      if ( error )
 +      goto Fail;
 +    }
 +    if ( format2 )
 +    {
 +      error = Load_ValueRecord( &pvr[n].Value2, format2,
 +                              base_offset, stream );
 +      if ( error )
 +      {
 +      if ( format1 )
 +        Free_ValueRecord( &pvr[n].Value1, format1 );
 +      goto Fail;
 +      }
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +  {
 +    if ( format1 )
 +      Free_ValueRecord( &pvr[m].Value1, format1 );
 +    if ( format2 )
 +      Free_ValueRecord( &pvr[m].Value2, format2 );
 +  }
 +
 +  FREE( pvr );
 +  return error;
 +}
 +
 +
 +static void  Free_PairSet( HB_PairSet*  ps,
 +                         HB_UShort     format1,
 +                         HB_UShort     format2 )
 +{
 +  HB_UShort             n, count;
 +
 +  HB_PairValueRecord*  pvr;
 +
 +
 +  if ( ps->PairValueRecord )
 +  {
 +    count = ps->PairValueCount;
 +    pvr   = ps->PairValueRecord;
 +
 +    for ( n = 0; n < count; n++ )
 +    {
 +      if ( format1 )
 +      Free_ValueRecord( &pvr[n].Value1, format1 );
 +      if ( format2 )
 +      Free_ValueRecord( &pvr[n].Value2, format2 );
 +    }
 +
 +    FREE( pvr );
 +  }
 +}
 +
 +
 +/* PairPosFormat1 */
 +
 +static HB_Error  Load_PairPos1( HB_PairPosFormat1*  ppf1,
 +                              HB_UShort            format1,
 +                              HB_UShort            format2,
 +                              HB_Stream            stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort     n, m, count;
 +  HB_UInt      cur_offset, new_offset, base_offset;
 +
 +  HB_PairSet*  ps;
 +
 +
 +  base_offset = FILE_Pos() - 8L;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = ppf1->PairSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ppf1->PairSet = NULL;
 +
 +  if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
 +    return error;
 +
 +  ps = ppf1->PairSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_PairSet( &ps[n], format1,
 +                               format2, stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_PairSet( &ps[m], format1, format2 );
 +
 +  FREE( ps );
 +  return error;
 +}
 +
 +
 +static void  Free_PairPos1( HB_PairPosFormat1*  ppf1,
 +                          HB_UShort            format1,
 +                          HB_UShort            format2 )
 +{
 +  HB_UShort     n, count;
 +
 +  HB_PairSet*  ps;
 +
 +
 +  if ( ppf1->PairSet )
 +  {
 +    count = ppf1->PairSetCount;
 +    ps    = ppf1->PairSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_PairSet( &ps[n], format1, format2 );
 +
 +    FREE( ps );
 +  }
 +}
 +
 +
 +/* PairPosFormat2 */
 +
 +static HB_Error  Load_PairPos2( HB_PairPosFormat2*  ppf2,
 +                              HB_UShort            format1,
 +                              HB_UShort            format2,
 +                              HB_Stream            stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort          m, n, k, count1, count2;
 +  HB_UInt           cur_offset, new_offset1, new_offset2, base_offset;
 +
 +  HB_Class1Record*  c1r;
 +  HB_Class2Record*  c2r;
 +
 +
 +  base_offset = FILE_Pos() - 8L;
 +
 +  if ( ACCESS_Frame( 8L ) )
 +    return error;
 +
 +  new_offset1 = GET_UShort() + base_offset;
 +  new_offset2 = GET_UShort() + base_offset;
 +
 +  /* `Class1Count' and `Class2Count' are the upper limits for class
 +     values, thus we read it now to make additional safety checks.  */
 +
 +  count1 = ppf2->Class1Count = GET_UShort();
 +  count2 = ppf2->Class2Count = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset1 ) ||
 +       ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
 +                                     stream ) ) != HB_Err_Ok )
 +    return error;
 +  if ( FILE_Seek( new_offset2 ) ||
 +       ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
 +                                     stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  ppf2->Class1Record = NULL;
 +
 +  if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
 +    goto Fail2;
 +
 +  c1r = ppf2->Class1Record;
 +
 +  for ( m = 0; m < count1; m++ )
 +  {
 +    c1r[m].Class2Record = NULL;
 +
 +    if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
 +      goto Fail1;
 +
 +    c2r = c1r[m].Class2Record;
 +
 +    for ( n = 0; n < count2; n++ )
 +    {
 +      if ( format1 )
 +      {
 +      error = Load_ValueRecord( &c2r[n].Value1, format1,
 +                                base_offset, stream );
 +      if ( error )
 +        goto Fail0;
 +      }
 +      if ( format2 )
 +      {
 +      error = Load_ValueRecord( &c2r[n].Value2, format2,
 +                                base_offset, stream );
 +      if ( error )
 +      {
 +        if ( format1 )
 +          Free_ValueRecord( &c2r[n].Value1, format1 );
 +        goto Fail0;
 +      }
 +      }
 +    }
 +
 +    continue;
 +
 +  Fail0:
 +    for ( k = 0; k < n; k++ )
 +    {
 +      if ( format1 )
 +      Free_ValueRecord( &c2r[k].Value1, format1 );
 +      if ( format2 )
 +      Free_ValueRecord( &c2r[k].Value2, format2 );
 +    }
 +    goto Fail1;
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( k = 0; k < m; k++ )
 +  {
 +    c2r = c1r[k].Class2Record;
 +
 +    for ( n = 0; n < count2; n++ )
 +    {
 +      if ( format1 )
 +      Free_ValueRecord( &c2r[n].Value1, format1 );
 +      if ( format2 )
 +      Free_ValueRecord( &c2r[n].Value2, format2 );
 +    }
 +
 +    FREE( c2r );
 +  }
 +
 +  FREE( c1r );
 +Fail2:
 +
 +  _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
 +
 +Fail3:
 +  _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
 +  return error;
 +}
 +
 +
 +static void  Free_PairPos2( HB_PairPosFormat2*  ppf2,
 +                          HB_UShort            format1,
 +                          HB_UShort            format2 )
 +{
 +  HB_UShort          m, n, count1, count2;
 +
 +  HB_Class1Record*  c1r;
 +  HB_Class2Record*  c2r;
 +
 +
 +  if ( ppf2->Class1Record )
 +  {
 +    c1r    = ppf2->Class1Record;
 +    count1 = ppf2->Class1Count;
 +    count2 = ppf2->Class2Count;
 +
 +    for ( m = 0; m < count1; m++ )
 +    {
 +      c2r = c1r[m].Class2Record;
 +
 +      for ( n = 0; n < count2; n++ )
 +      {
 +      if ( format1 )
 +        Free_ValueRecord( &c2r[n].Value1, format1 );
 +      if ( format2 )
 +        Free_ValueRecord( &c2r[n].Value2, format2 );
 +      }
 +
 +      FREE( c2r );
 +    }
 +
 +    FREE( c1r );
 +
 +    _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
 +    _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
 +  }
 +}
 +
 +
 +static HB_Error  Load_PairPos( HB_GPOS_SubTable* st,
 +                             HB_Stream     stream )
 +{
 +  HB_Error  error;
 +  HB_PairPos*     pp = &st->pair;
 +
 +  HB_UShort         format1, format2;
 +  HB_UInt          cur_offset, new_offset, base_offset;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 8L ) )
 +    return error;
 +
 +  pp->PosFormat = GET_UShort();
 +  new_offset    = GET_UShort() + base_offset;
 +
 +  format1 = pp->ValueFormat1 = GET_UShort();
 +  format2 = pp->ValueFormat2 = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  switch ( pp->PosFormat )
 +  {
 +  case 1:
 +    error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
 +    if ( error )
 +      goto Fail;
 +    break;
 +
 +  case 2:
 +    error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
 +    if ( error )
 +      goto Fail;
 +    break;
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  _HB_OPEN_Free_Coverage( &pp->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_PairPos( HB_GPOS_SubTable* st )
 +{
 +  HB_UShort  format1, format2;
 +  HB_PairPos*     pp = &st->pair;
 +
 +
 +  format1 = pp->ValueFormat1;
 +  format2 = pp->ValueFormat2;
 +
 +  switch ( pp->PosFormat )
 +  {
 +  case 1:
 +    Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
 +    break;
 +
 +  case 2:
 +    Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
 +    break;
 +
 +  default:
 +    break;
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &pp->Coverage );
 +}
 +
 +
 +static HB_Error  Lookup_PairPos1( GPOS_Instance*       gpi,
 +                                HB_PairPosFormat1*  ppf1,
 +                                HB_Buffer           buffer,
 +                                HB_UInt             first_pos,
 +                                HB_UShort            index,
 +                                HB_UShort            format1,
 +                                HB_UShort            format2 )
 +{
 +  HB_Error              error;
 +  HB_UShort             numpvr, glyph2;
 +
 +  HB_PairValueRecord*  pvr;
 +
 +
 +  if ( index >= ppf1->PairSetCount )
 +     return ERR(HB_Err_Invalid_SubTable);
 +
 +  pvr = ppf1->PairSet[index].PairValueRecord;
 +  if ( !pvr )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  glyph2 = IN_CURGLYPH();
 +
 +  for ( numpvr = ppf1->PairSet[index].PairValueCount;
 +      numpvr;
 +      numpvr--, pvr++ )
 +  {
 +    if ( glyph2 == pvr->SecondGlyph )
 +    {
 +      error = Get_ValueRecord( gpi, &pvr->Value1, format1,
 +                             POSITION( first_pos ) );
 +      if ( error )
 +      return error;
 +      return Get_ValueRecord( gpi, &pvr->Value2, format2,
 +                            POSITION( buffer->in_pos ) );
 +    }
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +static HB_Error  Lookup_PairPos2( GPOS_Instance*       gpi,
 +                                HB_PairPosFormat2*  ppf2,
 +                                HB_Buffer           buffer,
 +                                HB_UInt             first_pos,
 +                                HB_UShort            format1,
 +                                HB_UShort            format2 )
 +{
 +  HB_Error           error;
 +  HB_UShort          cl1 = 0, cl2 = 0; /* shut compiler up */
 +
 +  HB_Class1Record*  c1r;
 +  HB_Class2Record*  c2r;
 +
 +
 +  error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
 +                   &cl1, NULL );
 +  if ( error && error != HB_Err_Not_Covered )
 +    return error;
 +  error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
 +                   &cl2, NULL );
 +  if ( error && error != HB_Err_Not_Covered )
 +    return error;
 +
 +  c1r = &ppf2->Class1Record[cl1];
 +  if ( !c1r )
 +    return ERR(HB_Err_Invalid_SubTable);
 +  c2r = &c1r->Class2Record[cl2];
 +
 +  error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
 +  if ( error )
 +    return error;
 +  return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
 +}
 +
 +
 +static HB_Error  Lookup_PairPos( GPOS_Instance*    gpi,
 +                               HB_GPOS_SubTable* st,
 +                               HB_Buffer        buffer,
 +                               HB_UShort         flags,
 +                               HB_UShort         context_length,
 +                               int               nesting_level )
 +{
 +  HB_Error         error;
 +  HB_UShort        index, property;
 +  HB_UInt         first_pos;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +  HB_PairPos*     pp = &st->pair;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( buffer->in_pos >= buffer->in_length - 1 )
 +    return HB_Err_Not_Covered;           /* Not enough glyphs in stream */
 +
 +  if ( context_length != 0xFFFF && context_length < 2 )
 +    return HB_Err_Not_Covered;
 +
-   while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
++  if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  /* second glyph */
 +
 +  first_pos = buffer->in_pos;
 +  (buffer->in_pos)++;
 +
-   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
++  while ( CHECK_Property( gpos->layout, IN_CURITEM(),
 +                        flags, &property ) )
 +  {
 +    if ( error && error != HB_Err_Not_Covered )
 +      return error;
 +
 +    if ( buffer->in_pos == buffer->in_length )
 +      {
 +      buffer->in_pos = first_pos;
 +        return HB_Err_Not_Covered;
 +      }
 +    (buffer->in_pos)++;
 +
 +  }
 +
 +  switch ( pp->PosFormat )
 +  {
 +  case 1:
 +    error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
 +                           first_pos, index,
 +                           pp->ValueFormat1, pp->ValueFormat2 );
 +    break;
 +
 +  case 2:
 +    error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
 +                           pp->ValueFormat1, pp->ValueFormat2 );
 +    break;
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  /* if we don't have coverage for the second glyph don't skip it for
 +     further lookups but reset in_pos back to the first_glyph and let
 +     the caller in Do_String_Lookup increment in_pos */
 +  if ( error == HB_Err_Not_Covered )
 +      buffer->in_pos = first_pos;
 +
 +  /* adjusting the `next' glyph */
 +
 +  if ( pp->ValueFormat2 )
 +    (buffer->in_pos)++;
 +
 +  return error;
 +}
 +
 +
 +/* LookupType 3 */
 +
 +/* CursivePosFormat1 */
 +
 +static HB_Error  Load_CursivePos( HB_GPOS_SubTable* st,
 +                                HB_Stream        stream )
 +{
 +  HB_Error  error;
 +  HB_CursivePos*  cp = &st->cursive;
 +
 +  HB_UShort             n, m, count;
 +  HB_UInt              cur_offset, new_offset, base_offset;
 +
 +  HB_EntryExitRecord*  eer;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  cp->PosFormat = GET_UShort();
 +  new_offset    = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = cp->EntryExitCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cp->EntryExitRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
 +    goto Fail2;
 +
 +  eer = cp->EntryExitRecord;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    HB_UInt entry_offset;
 +
 +    if ( ACCESS_Frame( 2L ) )
 +      return error;
 +
 +    entry_offset = new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_Anchor( &eer[n].EntryAnchor,
 +                                stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +      eer[n].EntryAnchor.PosFormat   = 0;
 +
 +    if ( ACCESS_Frame( 2L ) )
 +      return error;
 +
 +    new_offset = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset )
 +    {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_Anchor( &eer[n].ExitAnchor,
 +                                stream ) ) != HB_Err_Ok )
 +      {
 +      if ( entry_offset )
 +        Free_Anchor( &eer[n].EntryAnchor );
 +      goto Fail1;
 +      }
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +      eer[n].ExitAnchor.PosFormat   = 0;
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +  {
 +    Free_Anchor( &eer[m].EntryAnchor );
 +    Free_Anchor( &eer[m].ExitAnchor );
 +  }
 +
 +  FREE( eer );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &cp->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_CursivePos( HB_GPOS_SubTable* st )
 +{
 +  HB_UShort             n, count;
 +  HB_CursivePos*  cp = &st->cursive;
 +
 +  HB_EntryExitRecord*  eer;
 +
 +
 +  if ( cp->EntryExitRecord )
 +  {
 +    count = cp->EntryExitCount;
 +    eer   = cp->EntryExitRecord;
 +
 +    for ( n = 0; n < count; n++ )
 +    {
 +      Free_Anchor( &eer[n].EntryAnchor );
 +      Free_Anchor( &eer[n].ExitAnchor );
 +    }
 +
 +    FREE( eer );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &cp->Coverage );
 +}
 +
 +
 +static HB_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
 +                                  HB_GPOS_SubTable* st,
 +                                  HB_Buffer        buffer,
 +                                  HB_UShort         flags,
 +                                  HB_UShort         context_length,
 +                                  int               nesting_level )
 +{
 +  HB_UShort        index, property;
 +  HB_Error         error;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +  HB_CursivePos*  cp = &st->cursive;
 +
 +  HB_EntryExitRecord*  eer;
 +  HB_Fixed                entry_x, entry_y;
 +  HB_Fixed                exit_x, exit_y;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( context_length != 0xFFFF && context_length < 1 )
 +  {
 +    gpi->last = 0xFFFF;
 +    return HB_Err_Not_Covered;
 +  }
 +
 +  /* Glyphs not having the right GDEF properties will be ignored, i.e.,
 +     gpi->last won't be reset (contrary to user defined properties). */
 +
-   if ( property == HB_GDEF_MARK )
++  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 ( CHECK_Property( gpos->gdef, IN_CURITEM(),
++  if ( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK )
 +  {
 +    gpi->last = 0xFFFF;
 +    return HB_Err_Not_Covered;
 +  }
 +
 +  error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +  {
 +    gpi->last = 0xFFFF;
 +    return error;
 +  }
 +
 +  if ( index >= cp->EntryExitCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  eer = &cp->EntryExitRecord[index];
 +
 +  /* Now comes the messiest part of the whole OpenType
 +     specification.  At first glance, cursive connections seem easy
 +     to understand, but there are pitfalls!  The reason is that
 +     the specs don't mention how to compute the advance values
 +     resp. glyph offsets.  I was told it would be an omission, to
 +     be fixed in the next OpenType version...  Again many thanks to
 +     Andrei Burago <andreib@microsoft.com> for clarifications.
 +
 +     Consider the following example:
 +
 +                    |  xadv1    |
 +                     +---------+
 +                     |         |
 +               +-----+--+ 1    |
 +               |     | .|      |
 +               |    0+--+------+
 +               |   2    |
 +               |        |
 +              0+--------+
 +              |  xadv2   |
 +
 +       glyph1: advance width = 12
 +             anchor point = (3,1)
 +
 +       glyph2: advance width = 11
 +             anchor point = (9,4)
 +
 +       LSB is 1 for both glyphs (so the boxes drawn above are glyph
 +       bboxes).  Writing direction is R2L; `0' denotes the glyph's
 +       coordinate origin.
 +
 +     Now the surprising part: The advance width of the *left* glyph
 +     (resp. of the *bottom* glyph) will be modified, no matter
 +     whether the writing direction is L2R or R2L (resp. T2B or
 +     B2T)!  This assymetry is caused by the fact that the glyph's
 +     coordinate origin is always the lower left corner for all
 +     writing directions.
 +
 +     Continuing the above example, we can compute the new
 +     (horizontal) advance width of glyph2 as
 +
 +       9 - 3 = 6  ,
 +
 +     and the new vertical offset of glyph2 as
 +
 +       1 - 4 = -3  .
 +
 +
 +     Vertical writing direction is far more complicated:
 +
 +     a) Assuming that we recompute the advance height of the lower glyph:
 +
 +                                --
 +                     +---------+
 +            --       |         |
 +               +-----+--+ 1    | yadv1
 +               |     | .|      |
 +         yadv2 |    0+--+------+        -- BSB1  --
 +               |   2    |       --      --        y_offset
 +               |        |
 +   BSB2 --      0+--------+                        --
 +      --    --
 +
 +       glyph1: advance height = 6
 +             anchor point = (3,1)
 +
 +       glyph2: advance height = 7
 +             anchor point = (9,4)
 +
 +       TSB is 1 for both glyphs; writing direction is T2B.
 +
 +
 +       BSB1     = yadv1 - (TSB1 + ymax1)
 +       BSB2     = yadv2 - (TSB2 + ymax2)
 +       y_offset = y2 - y1
 +
 +       vertical advance width of glyph2
 +       = y_offset + BSB2 - BSB1
 +       = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
 +       = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
 +       = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
 +
 +
 +     b) Assuming that we recompute the advance height of the upper glyph:
 +
 +                                --      --
 +                     +---------+        -- TSB1
 +      --    --       |         |
 +   TSB2 --       +-----+--+ 1    | yadv1   ymax1
 +               |     | .|      |
 +         yadv2 |    0+--+------+        --       --
 +    ymax2        |   2    |       --                y_offset
 +               |        |
 +      --      0+--------+                        --
 +            --
 +
 +       glyph1: advance height = 6
 +             anchor point = (3,1)
 +
 +       glyph2: advance height = 7
 +             anchor point = (9,4)
 +
 +       TSB is 1 for both glyphs; writing direction is T2B.
 +
 +       y_offset = y2 - y1
 +
 +       vertical advance width of glyph2
 +       = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
 +       = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
 +
 +
 +     Comparing a) with b) shows that b) is easier to compute.  I'll wait
 +     for a reply from Andrei to see what should really be implemented...
 +
 +     Since horizontal advance widths or vertical advance heights
 +     can be used alone but not together, no ambiguity occurs.        */
 +
 +  if ( gpi->last == 0xFFFF )
 +    goto end;
 +
 +  /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
 +     table.                                                         */
 +
 +  error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
 +                    &entry_x, &entry_y );
 +  if ( error == HB_Err_Not_Covered )
 +    goto end;
 +  if ( error )
 +    return error;
 +
 +  if ( gpi->r2l )
 +  {
 +    POSITION( buffer->in_pos )->x_advance   = entry_x - gpi->anchor_x;
 +    POSITION( buffer->in_pos )->new_advance = TRUE;
 +  }
 +  else
 +  {
 +    POSITION( gpi->last )->x_advance   = gpi->anchor_x - entry_x;
 +    POSITION( gpi->last )->new_advance = TRUE;
 +  }
 +
 +  if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
 +  {
 +    POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
 +    POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
 +  }
 +  else
 +  {
 +    POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
 +    POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
 +  }
 +
 +end:
 +  error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
 +                    &exit_x, &exit_y );
 +  if ( error == HB_Err_Not_Covered )
 +    gpi->last = 0xFFFF;
 +  else
 +  {
 +    gpi->last     = buffer->in_pos;
 +    gpi->anchor_x = exit_x;
 +    gpi->anchor_y = exit_y;
 +  }
 +  if ( error )
 +    return error;
 +
 +  (buffer->in_pos)++;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 4 */
 +
 +/* BaseArray */
 +
 +static HB_Error  Load_BaseArray( HB_BaseArray*  ba,
 +                               HB_UShort       num_classes,
 +                               HB_Stream       stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort       m, n, count;
 +  HB_UInt         cur_offset, new_offset, base_offset;
 +
 +  HB_BaseRecord  *br;
 +  HB_Anchor      *ban, *bans;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = ba->BaseCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ba->BaseRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
 +    return error;
 +
 +  br = ba->BaseRecord;
 +
 +  bans = NULL;
 +
 +  if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
 +    goto Fail;
 +
 +  for ( m = 0; m < count; m++ )
 +  {
 +    br[m].BaseAnchor = NULL;
 +
 +    ban = br[m].BaseAnchor = bans + m * num_classes;
 +
 +    for ( n = 0; n < num_classes; n++ )
 +    {
 +      if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +      new_offset = GET_UShort() + base_offset;
 +
 +      FORGET_Frame();
 +
 +      if (new_offset == base_offset) {
 +      /* XXX
 +       * Doulos SIL Regular is buggy and has zero offsets here.
 +       * Skip it
 +       */
 +      ban[n].PosFormat = 0;
 +      continue;
 +      }
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  FREE( bans );
 +  FREE( br );
 +  return error;
 +}
 +
 +
 +static void  Free_BaseArray( HB_BaseArray*  ba,
 +                           HB_UShort       num_classes )
 +{
 +  HB_BaseRecord  *br;
 +  HB_Anchor      *bans;
 +
 +  HB_UNUSED(num_classes);
 +
 +  if ( ba->BaseRecord )
 +  {
 +    br    = ba->BaseRecord;
 +
 +    if ( ba->BaseCount )
 +    {
 +      bans = br[0].BaseAnchor;
 +      FREE( bans );
 +    }
 +
 +    FREE( br );
 +  }
 +}
 +
 +
 +/* MarkBasePosFormat1 */
 +
 +static HB_Error  Load_MarkBasePos( HB_GPOS_SubTable* st,
 +                                 HB_Stream         stream )
 +{
 +  HB_Error  error;
 +  HB_MarkBasePos* mbp = &st->markbase;
 +
 +  HB_UInt  cur_offset, new_offset, base_offset;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  mbp->PosFormat = GET_UShort();
 +  new_offset     = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  if (mbp->PosFormat != 1)
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    goto Fail2;
 +
 +  mbp->ClassCount = GET_UShort();
 +  new_offset      = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
 +    goto Fail2;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail1;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
 +                               stream ) ) != HB_Err_Ok )
 +    goto Fail1;
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  Free_MarkArray( &mbp->MarkArray );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
 +
 +Fail3:
 +  _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
 +  return error;
 +}
 +
 +
 +static void  Free_MarkBasePos( HB_GPOS_SubTable* st )
 +{
 +  HB_MarkBasePos* mbp = &st->markbase;
 +
 +  Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
 +  Free_MarkArray( &mbp->MarkArray );
 +  _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
 +  _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
 +}
 +
 +
 +static HB_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
 +                                   HB_GPOS_SubTable* st,
 +                                   HB_Buffer        buffer,
 +                                   HB_UShort         flags,
 +                                   HB_UShort         context_length,
 +                                   int               nesting_level )
 +{
 +  HB_UShort        i, j, mark_index, base_index, property, class;
 +  HB_Fixed           x_mark_value, y_mark_value, x_base_value, y_base_value;
 +  HB_Error         error;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +  HB_MarkBasePos* mbp = &st->markbase;
 +
 +  HB_MarkArray*   ma;
 +  HB_BaseArray*   ba;
 +  HB_BaseRecord*  br;
 +  HB_Anchor*      mark_anchor;
 +  HB_Anchor*      base_anchor;
 +
 +  HB_Position     o;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( context_length != 0xFFFF && context_length < 1 )
 +    return HB_Err_Not_Covered;
 +
 +  if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
 +    return HB_Err_Not_Covered;
 +
-     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-                                       &property );
-     if ( error )
-       return error;
++  if ( CHECK_Property( gpos->layout, IN_CURITEM(),
 +                     flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
 +                        &mark_index );
 +  if ( error )
 +    return error;
 +
 +  /* now we search backwards for a non-mark glyph */
 +
 +  i = 1;
 +  j = buffer->in_pos - 1;
 +
 +  while ( i <= buffer->in_pos )
 +  {
-     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++    property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
++    if ( !property )
++      return HB_Err_Not_Covered;
 +
-   if ( property != HB_GDEF_BASE_GLYPH )
++    if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
 +      break;
 +
 +    i++;
 +    j--;
 +  }
 +
 +  /* The following assertion is too strong -- at least for mangal.ttf. */
 +#if 0
-   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
++  if ( property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH )
 +    return HB_Err_Not_Covered;
 +#endif
 +
 +  if ( i > buffer->in_pos )
 +    return HB_Err_Not_Covered;
 +
 +  error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
 +                        &base_index );
 +  if ( error )
 +    return error;
 +
 +  ma = &mbp->MarkArray;
 +
 +  if ( mark_index >= ma->MarkCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  class       = ma->MarkRecord[mark_index].Class;
 +  mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
 +
 +  if ( class >= mbp->ClassCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  ba = &mbp->BaseArray;
 +
 +  if ( base_index >= ba->BaseCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  br          = &ba->BaseRecord[base_index];
 +  base_anchor = &br->BaseAnchor[class];
 +
 +  error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
 +                    &x_mark_value, &y_mark_value );
 +  if ( error )
 +    return error;
 +
 +  error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
 +                    &x_base_value, &y_base_value );
 +  if ( error )
 +    return error;
 +
 +  /* anchor points are not cumulative */
 +
 +  o = POSITION( buffer->in_pos );
 +
 +  o->x_pos     = x_base_value - x_mark_value;
 +  o->y_pos     = y_base_value - y_mark_value;
 +  o->x_advance = 0;
 +  o->y_advance = 0;
 +  o->back      = i;
 +
 +  (buffer->in_pos)++;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 5 */
 +
 +/* LigatureAttach */
 +
 +static HB_Error  Load_LigatureAttach( HB_LigatureAttach*  lat,
 +                                    HB_UShort            num_classes,
 +                                    HB_Stream            stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             m, n, k, count;
 +  HB_UInt              cur_offset, new_offset, base_offset;
 +
 +  HB_ComponentRecord*  cr;
 +  HB_Anchor*           lan;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = lat->ComponentCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  lat->ComponentRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
 +    return error;
 +
 +  cr = lat->ComponentRecord;
 +
 +  for ( m = 0; m < count; m++ )
 +  {
 +    cr[m].LigatureAnchor = NULL;
 +
 +    if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
 +      goto Fail;
 +
 +    lan = cr[m].LigatureAnchor;
 +
 +    for ( n = 0; n < num_classes; n++ )
 +    {
 +      if ( ACCESS_Frame( 2L ) )
 +      goto Fail0;
 +
 +      new_offset = GET_UShort();
 +
 +      FORGET_Frame();
 +
 +      if ( new_offset )
 +      {
 +      new_offset += base_offset;
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +           ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
 +        goto Fail0;
 +      (void)FILE_Seek( cur_offset );
 +      }
 +      else
 +      lan[n].PosFormat = 0;
 +    }
 +
 +    continue;
 +  Fail0:
 +    for ( k = 0; k < n; k++ )
 +      Free_Anchor( &lan[k] );
 +    goto Fail;
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( k = 0; k < m; k++ )
 +  {
 +    lan = cr[k].LigatureAnchor;
 +
 +    for ( n = 0; n < num_classes; n++ )
 +      Free_Anchor( &lan[n] );
 +
 +    FREE( lan );
 +  }
 +
 +  FREE( cr );
 +  return error;
 +}
 +
 +
 +static void  Free_LigatureAttach( HB_LigatureAttach*  lat,
 +                                HB_UShort            num_classes )
 +{
 +  HB_UShort        m, n, count;
 +
 +  HB_ComponentRecord*  cr;
 +  HB_Anchor*           lan;
 +
 +
 +  if ( lat->ComponentRecord )
 +  {
 +    count = lat->ComponentCount;
 +    cr    = lat->ComponentRecord;
 +
 +    for ( m = 0; m < count; m++ )
 +    {
 +      lan = cr[m].LigatureAnchor;
 +
 +      for ( n = 0; n < num_classes; n++ )
 +      Free_Anchor( &lan[n] );
 +
 +      FREE( lan );
 +    }
 +
 +    FREE( cr );
 +  }
 +}
 +
 +
 +/* LigatureArray */
 +
 +static HB_Error  Load_LigatureArray( HB_LigatureArray*  la,
 +                                   HB_UShort           num_classes,
 +                                   HB_Stream           stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort            n, m, count;
 +  HB_UInt             cur_offset, new_offset, base_offset;
 +
 +  HB_LigatureAttach*  lat;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = la->LigatureCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  la->LigatureAttach = NULL;
 +
 +  if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
 +    return error;
 +
 +  lat = la->LigatureAttach;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_LigatureAttach( &lat[n], num_classes,
 +                                      stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_LigatureAttach( &lat[m], num_classes );
 +
 +  FREE( lat );
 +  return error;
 +}
 +
 +
 +static void  Free_LigatureArray( HB_LigatureArray*  la,
 +                               HB_UShort          num_classes )
 +{
 +  HB_UShort            n, count;
 +
 +  HB_LigatureAttach*  lat;
 +
 +
 +  if ( la->LigatureAttach )
 +  {
 +    count = la->LigatureCount;
 +    lat   = la->LigatureAttach;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_LigatureAttach( &lat[n], num_classes );
 +
 +    FREE( lat );
 +  }
 +}
 +
 +
 +/* MarkLigPosFormat1 */
 +
 +static HB_Error  Load_MarkLigPos( HB_GPOS_SubTable* st,
 +                                HB_Stream        stream )
 +{
 +  HB_Error  error;
 +  HB_MarkLigPos*  mlp = &st->marklig;
 +
 +  HB_UInt  cur_offset, new_offset, base_offset;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  mlp->PosFormat = GET_UShort();
 +  new_offset     = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
 +                              stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    goto Fail2;
 +
 +  mlp->ClassCount = GET_UShort();
 +  new_offset      = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
 +    goto Fail2;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail1;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
 +                                   stream ) ) != HB_Err_Ok )
 +    goto Fail1;
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  Free_MarkArray( &mlp->MarkArray );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
 +
 +Fail3:
 +  _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
 +  return error;
 +}
 +
 +
 +static void  Free_MarkLigPos( HB_GPOS_SubTable* st )
 +{
 +  HB_MarkLigPos*  mlp = &st->marklig;
 +
 +  Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
 +  Free_MarkArray( &mlp->MarkArray );
 +  _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
 +  _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
 +}
 +
 +
 +static HB_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
 +                                  HB_GPOS_SubTable* st,
 +                                  HB_Buffer        buffer,
 +                                  HB_UShort         flags,
 +                                  HB_UShort         context_length,
 +                                  int               nesting_level )
 +{
 +  HB_UShort        i, j, mark_index, lig_index, property, class;
 +  HB_UShort        mark_glyph;
 +  HB_Fixed           x_mark_value, y_mark_value, x_lig_value, y_lig_value;
 +  HB_Error         error;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +  HB_MarkLigPos*  mlp = &st->marklig;
 +
 +  HB_MarkArray*        ma;
 +  HB_LigatureArray*    la;
 +  HB_LigatureAttach*   lat;
 +  HB_ComponentRecord*  cr;
 +  HB_UShort             comp_index;
 +  HB_Anchor*           mark_anchor;
 +  HB_Anchor*           lig_anchor;
 +
 +  HB_Position    o;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( context_length != 0xFFFF && context_length < 1 )
 +    return HB_Err_Not_Covered;
 +
 +  if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
 +    return HB_Err_Not_Covered;
 +
 +  mark_glyph = IN_CURGLYPH();
 +
-     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-                                       &property );
-     if ( error )
-       return error;
++  if ( CHECK_Property( gpos->layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
 +  if ( error )
 +    return error;
 +
 +  /* now we search backwards for a non-mark glyph */
 +
 +  i = 1;
 +  j = buffer->in_pos - 1;
 +
 +  while ( i <= buffer->in_pos )
 +  {
-     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++    property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
++    if ( !property )
++      return HB_Err_Not_Covered;
 +
-   if ( property != HB_GDEF_LIGATURE )
++    if ( !( property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
 +      break;
 +
 +    i++;
 +    j--;
 +  }
 +
 +  /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
 +     too strong, thus it is commented out.                             */
 +#if 0
-   if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
++  if ( property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
 +    return HB_Err_Not_Covered;
 +#endif
 +
 +  if ( i > buffer->in_pos )
 +    return HB_Err_Not_Covered;
 +
 +  error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
 +                        &lig_index );
 +  if ( error )
 +    return error;
 +
 +  ma = &mlp->MarkArray;
 +
 +  if ( mark_index >= ma->MarkCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  class       = ma->MarkRecord[mark_index].Class;
 +  mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
 +
 +  if ( class >= mlp->ClassCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  la = &mlp->LigatureArray;
 +
 +  if ( lig_index >= la->LigatureCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  lat = &la->LigatureAttach[lig_index];
 +
 +  /* We must now check whether the ligature ID of the current mark glyph
 +     is identical to the ligature ID of the found ligature.  If yes, we
 +     can directly use the component index.  If not, we attach the mark
 +     glyph to the last component of the ligature.                        */
 +
 +  if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
 +  {
 +    comp_index = IN_COMPONENT( buffer->in_pos );
 +    if ( comp_index >= lat->ComponentCount )
 +      return HB_Err_Not_Covered;
 +  }
 +  else
 +    comp_index = lat->ComponentCount - 1;
 +
 +  cr         = &lat->ComponentRecord[comp_index];
 +  lig_anchor = &cr->LigatureAnchor[class];
 +
 +  error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
 +                    &x_mark_value, &y_mark_value );
 +  if ( error )
 +    return error;
 +  error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
 +                    &x_lig_value, &y_lig_value );
 +  if ( error )
 +    return error;
 +
 +  /* anchor points are not cumulative */
 +
 +  o = POSITION( buffer->in_pos );
 +
 +  o->x_pos     = x_lig_value - x_mark_value;
 +  o->y_pos     = y_lig_value - y_mark_value;
 +  o->x_advance = 0;
 +  o->y_advance = 0;
 +  o->back      = i;
 +
 +  (buffer->in_pos)++;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 6 */
 +
 +/* Mark2Array */
 +
 +static HB_Error  Load_Mark2Array( HB_Mark2Array*  m2a,
 +                                HB_UShort        num_classes,
 +                                HB_Stream        stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort        k, m, n, count;
 +  HB_UInt          cur_offset, new_offset, base_offset;
 +
 +  HB_Mark2Record  *m2r;
 +  HB_Anchor       *m2an, *m2ans;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = m2a->Mark2Count = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  m2a->Mark2Record = NULL;
 +
 +  if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
 +    return error;
 +
 +  m2r = m2a->Mark2Record;
 +
 +  m2ans = NULL;
 +
 +  if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
 +    goto Fail;
 +
 +  for ( m = 0; m < count; m++ )
 +  {
 +    m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
 +
 +    for ( n = 0; n < num_classes; n++ )
 +    {
 +      if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +      new_offset = GET_UShort() + base_offset;
 +
 +      FORGET_Frame();
 +
 +      if (new_offset == base_offset) {
 +        /* Anchor table not provided.  Skip loading.
 +       * Some versions of FreeSans hit this. */
 +        m2an[n].PosFormat = 0;
 +      continue;
 +      }
 +
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  FREE( m2ans );
 +  FREE( m2r );
 +  return error;
 +}
 +
 +
 +static void  Free_Mark2Array( HB_Mark2Array*  m2a,
 +                            HB_UShort        num_classes )
 +{
 +  HB_Mark2Record  *m2r;
 +  HB_Anchor       *m2ans;
 +
 +  HB_UNUSED(num_classes);
 +
 +  if ( m2a->Mark2Record )
 +  {
 +    m2r   = m2a->Mark2Record;
 +
 +    if ( m2a->Mark2Count )
 +    {
 +      m2ans = m2r[0].Mark2Anchor;
 +      FREE( m2ans );
 +    }
 +
 +    FREE( m2r );
 +  }
 +}
 +
 +
 +/* MarkMarkPosFormat1 */
 +
 +static HB_Error  Load_MarkMarkPos( HB_GPOS_SubTable* st,
 +                                 HB_Stream         stream )
 +{
 +  HB_Error  error;
 +  HB_MarkMarkPos* mmp = &st->markmark;
 +
 +  HB_UInt  cur_offset, new_offset, base_offset;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  mmp->PosFormat = GET_UShort();
 +  new_offset     = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
 +                              stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
 +                              stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    goto Fail2;
 +
 +  mmp->ClassCount = GET_UShort();
 +  new_offset      = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
 +    goto Fail2;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail1;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
 +                                stream ) ) != HB_Err_Ok )
 +    goto Fail1;
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  Free_MarkArray( &mmp->Mark1Array );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
 +
 +Fail3:
 +  _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_MarkMarkPos( HB_GPOS_SubTable* st )
 +{
 +  HB_MarkMarkPos* mmp = &st->markmark;
 +
 +  Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
 +  Free_MarkArray( &mmp->Mark1Array );
 +  _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
 +  _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
 +}
 +
 +
 +static HB_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
 +                                   HB_GPOS_SubTable* st,
 +                                   HB_Buffer        buffer,
 +                                   HB_UShort         flags,
 +                                   HB_UShort         context_length,
 +                                   int               nesting_level )
 +{
 +  HB_UShort        i, j, mark1_index, mark2_index, property, class;
 +  HB_Fixed           x_mark1_value, y_mark1_value,
 +                 x_mark2_value, y_mark2_value;
 +  HB_Error         error;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +  HB_MarkMarkPos* mmp = &st->markmark;
 +
 +  HB_MarkArray*    ma1;
 +  HB_Mark2Array*   ma2;
 +  HB_Mark2Record*  m2r;
 +  HB_Anchor*       mark1_anchor;
 +  HB_Anchor*       mark2_anchor;
 +
 +  HB_Position    o;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( context_length != 0xFFFF && context_length < 1 )
 +    return HB_Err_Not_Covered;
 +
 +  if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
 +    return HB_Err_Not_Covered;
 +
-     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-                                       &property );
-     if ( error )
-       return error;
++  if ( CHECK_Property( gpos->layout, IN_CURITEM(),
 +                     flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
 +                        &mark1_index );
 +  if ( error )
 +    return error;
 +
 +  /* now we search backwards for a suitable mark glyph until a non-mark
 +     glyph                                                */
 +
 +  if ( buffer->in_pos == 0 )
 +    return HB_Err_Not_Covered;
 +
 +  i = 1;
 +  j = buffer->in_pos - 1;
 +  while ( i <= buffer->in_pos )
 +  {
-     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++    property = _hb_ot_layout_get_glyph_properties (gpos->layout, IN_GLYPH(j));
++    if ( !property )
++      return HB_Err_Not_Covered;
 +
-   HB_GDEFHeader*  gdef;
++    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 )
 +    {
 +      if ( property == (flags & 0xFF00) )
 +        break;
 +    }
 +    else
 +      break;
 +
 +    i++;
 +    j--;
 +  }
 +
 +  error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
 +                        &mark2_index );
 +  if ( error )
 +    return error;
 +
 +  ma1 = &mmp->Mark1Array;
 +
 +  if ( mark1_index >= ma1->MarkCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  class        = ma1->MarkRecord[mark1_index].Class;
 +  mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
 +
 +  if ( class >= mmp->ClassCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  ma2 = &mmp->Mark2Array;
 +
 +  if ( mark2_index >= ma2->Mark2Count )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  m2r          = &ma2->Mark2Record[mark2_index];
 +  mark2_anchor = &m2r->Mark2Anchor[class];
 +
 +  error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
 +                    &x_mark1_value, &y_mark1_value );
 +  if ( error )
 +    return error;
 +  error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
 +                    &x_mark2_value, &y_mark2_value );
 +  if ( error )
 +    return error;
 +
 +  /* anchor points are not cumulative */
 +
 +  o = POSITION( buffer->in_pos );
 +
 +  o->x_pos     = x_mark2_value - x_mark1_value;
 +  o->y_pos     = y_mark2_value - y_mark1_value;
 +  o->x_advance = 0;
 +  o->y_advance = 0;
 +  o->back      = 1;
 +
 +  (buffer->in_pos)++;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* Do the actual positioning for a context positioning (either format
 +   7 or 8).  This is only called after we've determined that the stream
 +   matches the subrule.                                                 */
 +
 +static HB_Error  Do_ContextPos( GPOS_Instance*        gpi,
 +                              HB_UShort             GlyphCount,
 +                              HB_UShort             PosCount,
 +                              HB_PosLookupRecord*  pos,
 +                              HB_Buffer            buffer,
 +                              int                   nesting_level )
 +{
 +  HB_Error  error;
 +  HB_UInt i, old_pos;
 +
 +
 +  i = 0;
 +
 +  while ( i < GlyphCount )
 +  {
 +    if ( PosCount && i == pos->SequenceIndex )
 +    {
 +      old_pos = buffer->in_pos;
 +
 +      /* Do a positioning */
 +
 +      error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
 +                                  GlyphCount, nesting_level );
 +
 +      if ( error )
 +      return error;
 +
 +      pos++;
 +      PosCount--;
 +      i += buffer->in_pos - old_pos;
 +    }
 +    else
 +    {
 +      i++;
 +      (buffer->in_pos)++;
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 7 */
 +
 +/* PosRule */
 +
 +static HB_Error  Load_PosRule( HB_PosRule*  pr,
 +                             HB_Stream     stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, count;
 +  HB_UShort*            i;
 +
 +  HB_PosLookupRecord*  plr;
 +
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  pr->GlyphCount = GET_UShort();
 +  pr->PosCount   = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  pr->Input = NULL;
 +
 +  count = pr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
 +    return error;
 +
 +  i = pr->Input;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    i[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  pr->PosLookupRecord = NULL;
 +
 +  count = pr->PosCount;
 +
 +  if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
 +    goto Fail2;
 +
 +  plr = pr->PosLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    plr[n].SequenceIndex   = GET_UShort();
 +    plr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( plr );
 +
 +Fail2:
 +  FREE( i );
 +  return error;
 +}
 +
 +
 +static void  Free_PosRule( HB_PosRule*  pr )
 +{
 +  FREE( pr->PosLookupRecord );
 +  FREE( pr->Input );
 +}
 +
 +
 +/* PosRuleSet */
 +
 +static HB_Error  Load_PosRuleSet( HB_PosRuleSet*  prs,
 +                                HB_Stream        stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort     n, m, count;
 +  HB_UInt      cur_offset, new_offset, base_offset;
 +
 +  HB_PosRule*  pr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = prs->PosRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  prs->PosRule = NULL;
 +
 +  if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
 +    return error;
 +
 +  pr = prs->PosRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_PosRule( &pr[m] );
 +
 +  FREE( pr );
 +  return error;
 +}
 +
 +
 +static void  Free_PosRuleSet( HB_PosRuleSet*  prs )
 +{
 +  HB_UShort     n, count;
 +
 +  HB_PosRule*  pr;
 +
 +
 +  if ( prs->PosRule )
 +  {
 +    count = prs->PosRuleCount;
 +    pr    = prs->PosRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_PosRule( &pr[n] );
 +
 +    FREE( pr );
 +  }
 +}
 +
 +
 +/* ContextPosFormat1 */
 +
 +static HB_Error  Load_ContextPos1( HB_ContextPosFormat1*  cpf1,
 +                                 HB_Stream               stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort        n, m, count;
 +  HB_UInt         cur_offset, new_offset, base_offset;
 +
 +  HB_PosRuleSet*  prs;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = cpf1->PosRuleSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpf1->PosRuleSet = NULL;
 +
 +  if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
 +    goto Fail2;
 +
 +  prs = cpf1->PosRuleSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_PosRuleSet( &prs[m] );
 +
 +  FREE( prs );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &cpf1->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ContextPos1( HB_ContextPosFormat1*  cpf1 )
 +{
 +  HB_UShort        n, count;
 +
 +  HB_PosRuleSet*  prs;
 +
 +
 +  if ( cpf1->PosRuleSet )
 +  {
 +    count = cpf1->PosRuleSetCount;
 +    prs   = cpf1->PosRuleSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_PosRuleSet( &prs[n] );
 +
 +    FREE( prs );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &cpf1->Coverage );
 +}
 +
 +
 +/* PosClassRule */
 +
 +static HB_Error  Load_PosClassRule( HB_ContextPosFormat2*  cpf2,
 +                                  HB_PosClassRule*       pcr,
 +                                  HB_Stream               stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, count;
 +
 +  HB_UShort*            c;
 +  HB_PosLookupRecord*  plr;
 +
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  pcr->GlyphCount = GET_UShort();
 +  pcr->PosCount   = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( pcr->GlyphCount > cpf2->MaxContextLength )
 +    cpf2->MaxContextLength = pcr->GlyphCount;
 +
 +  pcr->Class = NULL;
 +
 +  count = pcr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
 +    return error;
 +
 +  c = pcr->Class;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    c[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  pcr->PosLookupRecord = NULL;
 +
 +  count = pcr->PosCount;
 +
 +  if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
 +    goto Fail2;
 +
 +  plr = pcr->PosLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    plr[n].SequenceIndex   = GET_UShort();
 +    plr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( plr );
 +
 +Fail2:
 +  FREE( c );
 +  return error;
 +}
 +
 +
 +static void  Free_PosClassRule( HB_PosClassRule*  pcr )
 +{
 +  FREE( pcr->PosLookupRecord );
 +  FREE( pcr->Class );
 +}
 +
 +
 +/* PosClassSet */
 +
 +static HB_Error  Load_PosClassSet( HB_ContextPosFormat2*  cpf2,
 +                                 HB_PosClassSet*        pcs,
 +                                 HB_Stream               stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort          n, m, count;
 +  HB_UInt           cur_offset, new_offset, base_offset;
 +
 +  HB_PosClassRule*  pcr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = pcs->PosClassRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  pcs->PosClassRule = NULL;
 +
 +  if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
 +    return error;
 +
 +  pcr = pcs->PosClassRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_PosClassRule( cpf2, &pcr[n],
 +                                    stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_PosClassRule( &pcr[m] );
 +
 +  FREE( pcr );
 +  return error;
 +}
 +
 +
 +static void  Free_PosClassSet( HB_PosClassSet*  pcs )
 +{
 +  HB_UShort          n, count;
 +
 +  HB_PosClassRule*  pcr;
 +
 +
 +  if ( pcs->PosClassRule )
 +  {
 +    count = pcs->PosClassRuleCount;
 +    pcr   = pcs->PosClassRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_PosClassRule( &pcr[n] );
 +
 +    FREE( pcr );
 +  }
 +}
 +
 +
 +/* ContextPosFormat2 */
 +
 +static HB_Error  Load_ContextPos2( HB_ContextPosFormat2*  cpf2,
 +                                 HB_Stream               stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort         n, m, count;
 +  HB_UInt          cur_offset, new_offset, base_offset;
 +
 +  HB_PosClassSet*  pcs;
 +
 +
 +  base_offset = FILE_Pos() - 2;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    goto Fail3;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  /* `PosClassSetCount' is the upper limit for class values, thus we
 +     read it now to make an additional safety check.                 */
 +
 +  count = cpf2->PosClassSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
 +                                     stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  cpf2->PosClassSet      = NULL;
 +  cpf2->MaxContextLength = 0;
 +
 +  if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
 +    goto Fail2;
 +
 +  pcs = cpf2->PosClassSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset != base_offset )      /* not a NULL offset */
 +    {
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_PosClassSet( cpf2, &pcs[n],
 +                                     stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +    {
 +      /* we create a PosClassSet table with no entries */
 +
 +      cpf2->PosClassSet[n].PosClassRuleCount = 0;
 +      cpf2->PosClassSet[n].PosClassRule      = NULL;
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; n++ )
 +    Free_PosClassSet( &pcs[m] );
 +
 +  FREE( pcs );
 +
 +Fail2:
 +  _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
 +
 +Fail3:
 +  _HB_OPEN_Free_Coverage( &cpf2->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ContextPos2( HB_ContextPosFormat2*  cpf2 )
 +{
 +  HB_UShort         n, count;
 +
 +  HB_PosClassSet*  pcs;
 +
 +
 +  if ( cpf2->PosClassSet )
 +  {
 +    count = cpf2->PosClassSetCount;
 +    pcs   = cpf2->PosClassSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_PosClassSet( &pcs[n] );
 +
 +    FREE( pcs );
 +  }
 +
 +  _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
 +  _HB_OPEN_Free_Coverage( &cpf2->Coverage );
 +}
 +
 +
 +/* ContextPosFormat3 */
 +
 +static HB_Error  Load_ContextPos3( HB_ContextPosFormat3*  cpf3,
 +                                 HB_Stream               stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, count;
 +  HB_UInt              cur_offset, new_offset, base_offset;
 +
 +  HB_Coverage*         c;
 +  HB_PosLookupRecord*  plr;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  cpf3->GlyphCount = GET_UShort();
 +  cpf3->PosCount   = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpf3->Coverage = NULL;
 +
 +  count = cpf3->GlyphCount;
 +
 +  if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
 +    return error;
 +
 +  c = cpf3->Coverage;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
 +      goto Fail2;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  cpf3->PosLookupRecord = NULL;
 +
 +  count = cpf3->PosCount;
 +
 +  if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
 +    goto Fail2;
 +
 +  plr = cpf3->PosLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    plr[n].SequenceIndex   = GET_UShort();
 +    plr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( plr );
 +
 +Fail2:
 +  for ( n = 0; n < count; n++ )
 +    _HB_OPEN_Free_Coverage( &c[n] );
 +
 +  FREE( c );
 +  return error;
 +}
 +
 +
 +static void  Free_ContextPos3( HB_ContextPosFormat3*  cpf3 )
 +{
 +  HB_UShort      n, count;
 +
 +  HB_Coverage*  c;
 +
 +
 +  FREE( cpf3->PosLookupRecord );
 +
 +  if ( cpf3->Coverage )
 +  {
 +    count = cpf3->GlyphCount;
 +    c     = cpf3->Coverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +}
 +
 +
 +/* ContextPos */
 +
 +static HB_Error  Load_ContextPos( HB_GPOS_SubTable* st,
 +                                HB_Stream        stream )
 +{
 +  HB_Error  error;
 +  HB_ContextPos*   cp = &st->context;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  cp->PosFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  switch ( cp->PosFormat )
 +  {
 +  case 1:
 +    return Load_ContextPos1( &cp->cpf.cpf1, stream );
 +
 +  case 2:
 +    return Load_ContextPos2( &cp->cpf.cpf2, stream );
 +
 +  case 3:
 +    return Load_ContextPos3( &cp->cpf.cpf3, stream );
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +static void  Free_ContextPos( HB_GPOS_SubTable* st )
 +{
 +  HB_ContextPos*   cp = &st->context;
 +
 +  switch ( cp->PosFormat )
 +  {
 +  case 1:  Free_ContextPos1( &cp->cpf.cpf1 ); break;
 +  case 2:  Free_ContextPos2( &cp->cpf.cpf2 ); break;
 +  case 3:  Free_ContextPos3( &cp->cpf.cpf3 ); break;
 +  default:                                          break;
 +  }
 +}
 +
 +
 +static HB_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
 +                                   HB_ContextPosFormat1*  cpf1,
 +                                   HB_Buffer              buffer,
 +                                   HB_UShort               flags,
 +                                   HB_UShort               context_length,
 +                                   int                     nesting_level )
 +{
 +  HB_UShort        index, property;
 +  HB_UShort        i, j, k, numpr;
 +  HB_Error         error;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +
 +  HB_PosRule*     pr;
-   gdef = gpos->gdef;
++  hb_ot_layout_t*  layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gpos->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  pr    = cpf1->PosRuleSet[index].PosRule;
 +  numpr = cpf1->PosRuleSet[index].PosRuleCount;
 +
 +  for ( k = 0; k < numpr; k++ )
 +  {
 +    if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
 +      goto next_posrule;
 +
 +    if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
 +      goto next_posrule;                       /* context is too long */
 +
 +    for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
 +    {
-   HB_GDEFHeader*    gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        return error;
 +
 +      if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
 +        goto next_posrule;
 +      j++;
 +      }
 +
 +      if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
 +      goto next_posrule;
 +    }
 +
 +    return Do_ContextPos( gpi, pr[k].GlyphCount,
 +                        pr[k].PosCount, pr[k].PosLookupRecord,
 +                        buffer,
 +                        nesting_level );
 +
 +    next_posrule:
 +      ;
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +static HB_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
 +                                   HB_ContextPosFormat2*  cpf2,
 +                                   HB_Buffer              buffer,
 +                                   HB_UShort               flags,
 +                                   HB_UShort               context_length,
 +                                   int                     nesting_level )
 +{
 +  HB_UShort          index, property;
 +  HB_Error           error;
 +  HB_UShort          i, j, k, known_classes;
 +
 +  HB_UShort*         classes;
 +  HB_UShort*         cl;
 +  HB_GPOSHeader*    gpos = gpi->gpos;
 +
 +  HB_PosClassSet*   pcs;
 +  HB_PosClassRule*  pr;
-   gdef = gpos->gdef;
++  hb_ot_layout_t*    layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gpos->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), 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
 +         anything.  It just lets us know whether or not we need to
 +         do any lookup at all.                                     */
 +
 +  error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  if (cpf2->MaxContextLength < 1)
 +    return HB_Err_Not_Covered;
 +
 +  if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
 +    return error;
 +
 +  error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
 +                   &classes[0], NULL );
 +  if ( error && error != HB_Err_Not_Covered )
 +    goto End;
 +  known_classes = 0;
 +
 +  pcs = &cpf2->PosClassSet[classes[0]];
 +  if ( !pcs )
 +  {
 +    error = ERR(HB_Err_Invalid_SubTable);
 +    goto End;
 +  }
 +
 +  for ( k = 0; k < pcs->PosClassRuleCount; k++ )
 +  {
 +    pr = &pcs->PosClassRule[k];
 +
 +    if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
 +      goto next_posclassrule;
 +
 +    if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
 +      goto next_posclassrule;                /* context is too long */
 +
 +    cl   = pr->Class;
 +
 +    /* Start at 1 because [0] is implied */
 +
 +    for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
 +    {
-   HB_GDEFHeader*  gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End;
 +
 +      if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
 +        goto next_posclassrule;
 +      j++;
 +      }
 +
 +      if ( i > known_classes )
 +      {
 +      /* Keeps us from having to do this for each rule */
 +
 +      error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End;
 +      known_classes = i;
 +      }
 +
 +      if ( cl[i - 1] != classes[i] )
 +      goto next_posclassrule;
 +    }
 +
 +    error = Do_ContextPos( gpi, pr->GlyphCount,
 +                         pr->PosCount, pr->PosLookupRecord,
 +                         buffer,
 +                         nesting_level );
 +    goto End;
 +
 +  next_posclassrule:
 +    ;
 +  }
 +
 +  error = HB_Err_Not_Covered;
 +
 +End:
 +  FREE( classes );
 +  return error;
 +}
 +
 +
 +static HB_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
 +                                   HB_ContextPosFormat3*  cpf3,
 +                                   HB_Buffer              buffer,
 +                                   HB_UShort               flags,
 +                                   HB_UShort               context_length,
 +                                   int                     nesting_level )
 +{
 +  HB_Error         error;
 +  HB_UShort        index, i, j, property;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +
 +  HB_Coverage*    c;
-   gdef = gpos->gdef;
++  hb_ot_layout_t*  layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gpos->layout;
 +
-     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
 +    return HB_Err_Not_Covered;
 +
 +  if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
 +    return HB_Err_Not_Covered;         /* context is too long */
 +
 +  c    = cpf3->Coverage;
 +
 +  for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
 +  {
-   HB_GDEFHeader*    gdef;
++    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +    {
 +      if ( error && error != HB_Err_Not_Covered )
 +      return error;
 +
 +      if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
 +      return HB_Err_Not_Covered;
 +      j++;
 +    }
 +
 +    error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
 +    if ( error )
 +      return error;
 +  }
 +
 +  return Do_ContextPos( gpi, cpf3->GlyphCount,
 +                      cpf3->PosCount, cpf3->PosLookupRecord,
 +                      buffer,
 +                      nesting_level );
 +}
 +
 +
 +static HB_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
 +                                  HB_GPOS_SubTable* st,
 +                                  HB_Buffer        buffer,
 +                                  HB_UShort         flags,
 +                                  HB_UShort         context_length,
 +                                  int               nesting_level )
 +{
 +  HB_ContextPos*   cp = &st->context;
 +
 +  switch ( cp->PosFormat )
 +  {
 +  case 1:
 +    return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
 +                             flags, context_length, nesting_level );
 +
 +  case 2:
 +    return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
 +                             flags, context_length, nesting_level );
 +
 +  case 3:
 +    return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
 +                             flags, context_length, nesting_level );
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +/* LookupType 8 */
 +
 +/* ChainPosRule */
 +
 +static HB_Error  Load_ChainPosRule( HB_ChainPosRule*  cpr,
 +                                  HB_Stream          stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, count;
 +  HB_UShort*            b;
 +  HB_UShort*            i;
 +  HB_UShort*            l;
 +
 +  HB_PosLookupRecord*  plr;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  cpr->BacktrackGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpr->Backtrack = NULL;
 +
 +  count = cpr->BacktrackGlyphCount;
 +
 +  if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
 +    return error;
 +
 +  b = cpr->Backtrack;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail4;
 +
 +  for ( n = 0; n < count; n++ )
 +    b[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  cpr->InputGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpr->Input = NULL;
 +
 +  count = cpr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
 +    goto Fail4;
 +
 +  i = cpr->Input;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail3;
 +
 +  for ( n = 0; n < count; n++ )
 +    i[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  cpr->LookaheadGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpr->Lookahead = NULL;
 +
 +  count = cpr->LookaheadGlyphCount;
 +
 +  if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
 +    goto Fail3;
 +
 +  l = cpr->Lookahead;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    l[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  cpr->PosCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpr->PosLookupRecord = NULL;
 +
 +  count = cpr->PosCount;
 +
 +  if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
 +    goto Fail2;
 +
 +  plr = cpr->PosLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    plr[n].SequenceIndex   = GET_UShort();
 +    plr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( plr );
 +
 +Fail2:
 +  FREE( l );
 +
 +Fail3:
 +  FREE( i );
 +
 +Fail4:
 +  FREE( b );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainPosRule( HB_ChainPosRule*  cpr )
 +{
 +  FREE( cpr->PosLookupRecord );
 +  FREE( cpr->Lookahead );
 +  FREE( cpr->Input );
 +  FREE( cpr->Backtrack );
 +}
 +
 +
 +/* ChainPosRuleSet */
 +
 +static HB_Error  Load_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs,
 +                                     HB_Stream             stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort          n, m, count;
 +  HB_UInt           cur_offset, new_offset, base_offset;
 +
 +  HB_ChainPosRule*  cpr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = cprs->ChainPosRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cprs->ChainPosRule = NULL;
 +
 +  if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
 +    return error;
 +
 +  cpr = cprs->ChainPosRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainPosRule( &cpr[m] );
 +
 +  FREE( cpr );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs )
 +{
 +  HB_UShort          n, count;
 +
 +  HB_ChainPosRule*  cpr;
 +
 +
 +  if ( cprs->ChainPosRule )
 +  {
 +    count = cprs->ChainPosRuleCount;
 +    cpr   = cprs->ChainPosRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainPosRule( &cpr[n] );
 +
 +    FREE( cpr );
 +  }
 +}
 +
 +
 +/* ChainContextPosFormat1 */
 +
 +static HB_Error  Load_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1,
 +                                      HB_Stream                    stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, m, count;
 +  HB_UInt              cur_offset, new_offset, base_offset;
 +
 +  HB_ChainPosRuleSet*  cprs;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = ccpf1->ChainPosRuleSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccpf1->ChainPosRuleSet = NULL;
 +
 +  if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
 +    goto Fail2;
 +
 +  cprs = ccpf1->ChainPosRuleSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainPosRuleSet( &cprs[m] );
 +
 +  FREE( cprs );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1 )
 +{
 +  HB_UShort             n, count;
 +
 +  HB_ChainPosRuleSet*  cprs;
 +
 +
 +  if ( ccpf1->ChainPosRuleSet )
 +  {
 +    count = ccpf1->ChainPosRuleSetCount;
 +    cprs  = ccpf1->ChainPosRuleSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainPosRuleSet( &cprs[n] );
 +
 +    FREE( cprs );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
 +}
 +
 +
 +/* ChainPosClassRule */
 +
 +static HB_Error  Load_ChainPosClassRule(
 +                 HB_ChainContextPosFormat2*  ccpf2,
 +                 HB_ChainPosClassRule*       cpcr,
 +                 HB_Stream                    stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, count;
 +
 +  HB_UShort*            b;
 +  HB_UShort*            i;
 +  HB_UShort*            l;
 +  HB_PosLookupRecord*  plr;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  cpcr->BacktrackGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
 +    ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
 +
 +  cpcr->Backtrack = NULL;
 +
 +  count = cpcr->BacktrackGlyphCount;
 +
 +  if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
 +    return error;
 +
 +  b = cpcr->Backtrack;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail4;
 +
 +  for ( n = 0; n < count; n++ )
 +    b[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  cpcr->InputGlyphCount = GET_UShort();
 +
 +  if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
 +    ccpf2->MaxInputLength = cpcr->InputGlyphCount;
 +
 +  FORGET_Frame();
 +
 +  cpcr->Input = NULL;
 +
 +  count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
 +    goto Fail4;
 +
 +  i = cpcr->Input;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail3;
 +
 +  for ( n = 0; n < count; n++ )
 +    i[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  cpcr->LookaheadGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
 +    ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
 +
 +  cpcr->Lookahead = NULL;
 +
 +  count = cpcr->LookaheadGlyphCount;
 +
 +  if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
 +    goto Fail3;
 +
 +  l = cpcr->Lookahead;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    l[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  cpcr->PosCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpcr->PosLookupRecord = NULL;
 +
 +  count = cpcr->PosCount;
 +
 +  if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
 +    goto Fail2;
 +
 +  plr = cpcr->PosLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    plr[n].SequenceIndex   = GET_UShort();
 +    plr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( plr );
 +
 +Fail2:
 +  FREE( l );
 +
 +Fail3:
 +  FREE( i );
 +
 +Fail4:
 +  FREE( b );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainPosClassRule( HB_ChainPosClassRule*  cpcr )
 +{
 +  FREE( cpcr->PosLookupRecord );
 +  FREE( cpcr->Lookahead );
 +  FREE( cpcr->Input );
 +  FREE( cpcr->Backtrack );
 +}
 +
 +
 +/* PosClassSet */
 +
 +static HB_Error  Load_ChainPosClassSet(
 +                 HB_ChainContextPosFormat2*  ccpf2,
 +                 HB_ChainPosClassSet*        cpcs,
 +                 HB_Stream                    stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort               n, m, count;
 +  HB_UInt                cur_offset, new_offset, base_offset;
 +
 +  HB_ChainPosClassRule*  cpcr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = cpcs->ChainPosClassRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cpcs->ChainPosClassRule = NULL;
 +
 +  if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
 +                  HB_ChainPosClassRule ) )
 +    return error;
 +
 +  cpcr = cpcs->ChainPosClassRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
 +                                         stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainPosClassRule( &cpcr[m] );
 +
 +  FREE( cpcr );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainPosClassSet( HB_ChainPosClassSet*  cpcs )
 +{
 +  HB_UShort               n, count;
 +
 +  HB_ChainPosClassRule*  cpcr;
 +
 +
 +  if ( cpcs->ChainPosClassRule )
 +  {
 +    count = cpcs->ChainPosClassRuleCount;
 +    cpcr  = cpcs->ChainPosClassRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainPosClassRule( &cpcr[n] );
 +
 +    FREE( cpcr );
 +  }
 +}
 +
 +
 +/* ChainContextPosFormat2 */
 +
 +static HB_Error  Load_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2,
 +                                      HB_Stream                    stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort              n, m, count;
 +  HB_UInt               cur_offset, new_offset, base_offset;
 +  HB_UInt               backtrack_offset, input_offset, lookahead_offset;
 +
 +  HB_ChainPosClassSet*  cpcs;
 +
 +
 +  base_offset = FILE_Pos() - 2;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 8L ) )
 +    goto Fail5;
 +
 +  backtrack_offset = GET_UShort();
 +  input_offset     = GET_UShort();
 +  lookahead_offset = GET_UShort();
 +
 +  /* `ChainPosClassSetCount' is the upper limit for input class values,
 +     thus we read it now to make an additional safety check. No limit
 +     is known or needed for the other two class definitions          */
 +
 +  count = ccpf2->ChainPosClassSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
 +                                                     backtrack_offset, base_offset,
 +                                                     stream ) ) != HB_Err_Ok )
 +    goto Fail5;
 +  if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
 +                                                     input_offset, base_offset,
 +                                                     stream ) ) != HB_Err_Ok )
 +    goto Fail4;
 +  if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
 +                                                     lookahead_offset, base_offset,
 +                                                     stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +
 +  ccpf2->ChainPosClassSet   = NULL;
 +  ccpf2->MaxBacktrackLength = 0;
 +  ccpf2->MaxInputLength     = 0;
 +  ccpf2->MaxLookaheadLength = 0;
 +
 +  if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
 +    goto Fail2;
 +
 +  cpcs = ccpf2->ChainPosClassSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset != base_offset )      /* not a NULL offset */
 +    {
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
 +                                          stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +    {
 +      /* we create a ChainPosClassSet table with no entries */
 +
 +      ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
 +      ccpf2->ChainPosClassSet[n].ChainPosClassRule      = NULL;
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainPosClassSet( &cpcs[m] );
 +
 +  FREE( cpcs );
 +
 +Fail2:
 +  _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
 +
 +Fail3:
 +  _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
 +
 +Fail4:
 +  _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
 +
 +Fail5:
 +  _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2 )
 +{
 +  HB_UShort              n, count;
 +
 +  HB_ChainPosClassSet*  cpcs;
 +
 +
 +  if ( ccpf2->ChainPosClassSet )
 +  {
 +    count = ccpf2->ChainPosClassSetCount;
 +    cpcs  = ccpf2->ChainPosClassSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainPosClassSet( &cpcs[n] );
 +
 +    FREE( cpcs );
 +  }
 +
 +  _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
 +  _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
 +  _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
 +
 +  _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
 +}
 +
 +
 +/* ChainContextPosFormat3 */
 +
 +static HB_Error  Load_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3,
 +                                      HB_Stream                    stream )
 +{
 +  HB_Error  error;
 +
 +  HB_UShort             n, nb, ni, nl, m, count;
 +  HB_UShort             backtrack_count, input_count, lookahead_count;
 +  HB_UInt              cur_offset, new_offset, base_offset;
 +
 +  HB_Coverage*         b;
 +  HB_Coverage*         i;
 +  HB_Coverage*         l;
 +  HB_PosLookupRecord*  plr;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  ccpf3->BacktrackGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccpf3->BacktrackCoverage = NULL;
 +
 +  backtrack_count = ccpf3->BacktrackGlyphCount;
 +
 +  if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
 +                  HB_Coverage ) )
 +    return error;
 +
 +  b = ccpf3->BacktrackCoverage;
 +
 +  for ( nb = 0; nb < backtrack_count; nb++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail4;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
 +      goto Fail4;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  ccpf3->InputGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccpf3->InputCoverage = NULL;
 +
 +  input_count = ccpf3->InputGlyphCount;
 +
 +  if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
 +    goto Fail4;
 +
 +  i = ccpf3->InputCoverage;
 +
 +  for ( ni = 0; ni < input_count; ni++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail3;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
 +      goto Fail3;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  ccpf3->LookaheadGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccpf3->LookaheadCoverage = NULL;
 +
 +  lookahead_count = ccpf3->LookaheadGlyphCount;
 +
 +  if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
 +                  HB_Coverage ) )
 +    goto Fail3;
 +
 +  l = ccpf3->LookaheadCoverage;
 +
 +  for ( nl = 0; nl < lookahead_count; nl++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
 +      goto Fail2;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  ccpf3->PosCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccpf3->PosLookupRecord = NULL;
 +
 +  count = ccpf3->PosCount;
 +
 +  if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
 +    goto Fail2;
 +
 +  plr = ccpf3->PosLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    plr[n].SequenceIndex   = GET_UShort();
 +    plr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( plr );
 +
 +Fail2:
 +  for ( m = 0; m < nl; m++ )
 +    _HB_OPEN_Free_Coverage( &l[m] );
 +
 +  FREE( l );
 +
 +Fail3:
 +  for ( m = 0; m < ni; m++ )
 +    _HB_OPEN_Free_Coverage( &i[m] );
 +
 +  FREE( i );
 +
 +Fail4:
 +  for ( m = 0; m < nb; m++ )
 +    _HB_OPEN_Free_Coverage( &b[m] );
 +
 +  FREE( b );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3 )
 +{
 +  HB_UShort      n, count;
 +
 +  HB_Coverage*  c;
 +
 +
 +  FREE( ccpf3->PosLookupRecord );
 +
 +  if ( ccpf3->LookaheadCoverage )
 +  {
 +    count = ccpf3->LookaheadGlyphCount;
 +    c     = ccpf3->LookaheadCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +
 +  if ( ccpf3->InputCoverage )
 +  {
 +    count = ccpf3->InputGlyphCount;
 +    c     = ccpf3->InputCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +
 +  if ( ccpf3->BacktrackCoverage )
 +  {
 +    count = ccpf3->BacktrackGlyphCount;
 +    c     = ccpf3->BacktrackCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +}
 +
 +
 +/* ChainContextPos */
 +
 +static HB_Error  Load_ChainContextPos( HB_GPOS_SubTable* st,
 +                                     HB_Stream             stream )
 +{
 +  HB_Error  error;
 +  HB_ChainContextPos*  ccp = &st->chain;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  ccp->PosFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  switch ( ccp->PosFormat )
 +  {
 +  case 1:
 +    return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
 +
 +  case 2:
 +    return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
 +
 +  case 3:
 +    return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +static void  Free_ChainContextPos( HB_GPOS_SubTable* st )
 +{
 +  HB_ChainContextPos*  ccp = &st->chain;
 +
 +  switch ( ccp->PosFormat )
 +  {
 +  case 1:  Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
 +  case 2:  Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
 +  case 3:  Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
 +  default:                                                  break;
 +  }
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextPos1(
 +                 GPOS_Instance*               gpi,
 +                 HB_ChainContextPosFormat1*  ccpf1,
 +                 HB_Buffer                   buffer,
 +                 HB_UShort                    flags,
 +                 HB_UShort                    context_length,
 +                 int                          nesting_level )
 +{
 +  HB_UShort          index, property;
 +  HB_UShort          i, j, k, num_cpr;
 +  HB_UShort          bgc, igc, lgc;
 +  HB_Error           error;
 +  HB_GPOSHeader*    gpos = gpi->gpos;
 +
 +  HB_ChainPosRule*  cpr;
 +  HB_ChainPosRule   curr_cpr;
-   gdef = gpos->gdef;
++  hb_ot_layout_t*    layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gpos->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  cpr     = ccpf1->ChainPosRuleSet[index].ChainPosRule;
 +  num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
 +
 +  for ( k = 0; k < num_cpr; k++ )
 +  {
 +    curr_cpr = cpr[k];
 +    bgc      = curr_cpr.BacktrackGlyphCount;
 +    igc      = curr_cpr.InputGlyphCount;
 +    lgc      = curr_cpr.LookaheadGlyphCount;
 +
 +    if ( context_length != 0xFFFF && context_length < igc )
 +      goto next_chainposrule;
 +
 +    /* check whether context is too long; it is a first guess only */
 +
 +    if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
 +      goto next_chainposrule;
 +
 +    if ( bgc )
 +    {
 +      /* Since we don't know in advance the number of glyphs to inspect,
 +       we search backwards for matches in the backtrack glyph array    */
 +
 +      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;
 +
 +        if ( j + 1 == bgc - i )
 +          goto next_chainposrule;
 +        j--;
 +      }
 +
 +      /* In OpenType 1.3, it is undefined whether the offsets of
 +         backtrack glyphs is in logical order or not.  Version 1.4
 +         will clarify this:
 +
 +           Logical order -      a  b  c  d  e  f  g  h  i  j
 +                                            i
 +           Input offsets -                  0  1
 +           Backtrack offsets -  3  2  1  0
 +           Lookahead offsets -                    0  1  2  3           */
 +
 +      if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
 +        goto next_chainposrule;
 +      }
 +    }
 +
 +    /* Start at 1 because [0] is implied */
 +
 +    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;
 +
 +      if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
 +        goto next_chainposrule;
 +      j++;
 +      }
 +
 +      if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
 +      goto next_chainposrule;
 +    }
 +
 +    /* we are starting to check for lookahead glyphs right after the
 +       last context glyph                                            */
 +
 +    for ( i = 0; i < lgc; i++, j++ )
 +    {
-   HB_GDEFHeader*        gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        return error;
 +
 +      if ( j + lgc - i == (HB_Int)buffer->in_length )
 +        goto next_chainposrule;
 +      j++;
 +      }
 +
 +      if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
 +      goto next_chainposrule;
 +    }
 +
 +    return Do_ContextPos( gpi, igc,
 +                        curr_cpr.PosCount,
 +                        curr_cpr.PosLookupRecord,
 +                        buffer,
 +                        nesting_level );
 +
 +  next_chainposrule:
 +    ;
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextPos2(
 +                 GPOS_Instance*               gpi,
 +                 HB_ChainContextPosFormat2*  ccpf2,
 +                 HB_Buffer                   buffer,
 +                 HB_UShort                    flags,
 +                 HB_UShort                    context_length,
 +                 int                          nesting_level )
 +{
 +  HB_UShort              index, property;
 +  HB_Error               error;
 +  HB_UShort              i, j, k;
 +  HB_UShort              bgc, igc, lgc;
 +  HB_UShort              known_backtrack_classes,
 +                       known_input_classes,
 +                       known_lookahead_classes;
 +
 +  HB_UShort*             backtrack_classes;
 +  HB_UShort*             input_classes;
 +  HB_UShort*             lookahead_classes;
 +
 +  HB_UShort*             bc;
 +  HB_UShort*             ic;
 +  HB_UShort*             lc;
 +  HB_GPOSHeader*        gpos = gpi->gpos;
 +
 +  HB_ChainPosClassSet*  cpcs;
 +  HB_ChainPosClassRule  cpcr;
-   gdef = gpos->gdef;
++  hb_ot_layout_t*        layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gpos->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), 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
 +         anything.  It just lets us know whether or not we need to
 +         do any lookup at all.                                     */
 +
 +  error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
 +    return error;
 +  known_backtrack_classes = 0;
 +
 +  if (ccpf2->MaxInputLength < 1)
 +    return HB_Err_Not_Covered;
 +
 +  if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
 +    goto End3;
 +  known_input_classes = 1;
 +
 +  if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
 +    goto End2;
 +  known_lookahead_classes = 0;
 +
 +  error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
 +                   &input_classes[0], NULL );
 +  if ( error && error != HB_Err_Not_Covered )
 +    goto End1;
 +
 +  cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
 +  if ( !cpcs )
 +  {
 +    error = ERR(HB_Err_Invalid_SubTable);
 +    goto End1;
 +  }
 +
 +  for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
 +  {
 +    cpcr = cpcs->ChainPosClassRule[k];
 +    bgc  = cpcr.BacktrackGlyphCount;
 +    igc  = cpcr.InputGlyphCount;
 +    lgc  = cpcr.LookaheadGlyphCount;
 +
 +    if ( context_length != 0xFFFF && context_length < igc )
 +      goto next_chainposclassrule;
 +
 +    /* check whether context is too long; it is a first guess only */
 +
 +    if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
 +      goto next_chainposclassrule;
 +
 +    if ( bgc )
 +    {
 +      /* Since we don't know in advance the number of glyphs to inspect,
 +       we search backwards for matches in the backtrack glyph array.
 +       Note that `known_backtrack_classes' starts at index 0.         */
 +
 +      bc       = cpcr.Backtrack;
 +
 +      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;
 +
 +        if ( j + 1 == bgc - i )
 +          goto next_chainposclassrule;
 +        j++;
 +      }
 +
 +      if ( i >= known_backtrack_classes )
 +      {
 +        /* Keeps us from having to do this for each rule */
 +
 +        error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
 +                           &backtrack_classes[i], NULL );
 +        if ( error && error != HB_Err_Not_Covered )
 +          goto End1;
 +        known_backtrack_classes = i;
 +      }
 +
 +      if ( bc[i] != backtrack_classes[i] )
 +        goto next_chainposclassrule;
 +      }
 +    }
 +
 +    ic       = cpcr.Input;
 +
 +    /* Start at 1 because [0] is implied */
 +
 +    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;
 +
 +      if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
 +        goto next_chainposclassrule;
 +      j++;
 +      }
 +
 +      if ( i >= known_input_classes )
 +      {
 +      error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
 +                         &input_classes[i], NULL );
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End1;
 +      known_input_classes = i;
 +      }
 +
 +      if ( ic[i - 1] != input_classes[i] )
 +      goto next_chainposclassrule;
 +    }
 +
 +    /* we are starting to check for lookahead glyphs right after the
 +       last context glyph                                            */
 +
 +    lc       = cpcr.Lookahead;
 +
 +    for ( i = 0; i < lgc; i++, j++ )
 +    {
-   HB_GDEFHeader*  gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End1;
 +
 +      if ( j + lgc - i == (HB_Int)buffer->in_length )
 +        goto next_chainposclassrule;
 +      j++;
 +      }
 +
 +      if ( i >= known_lookahead_classes )
 +      {
 +      error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
 +                         &lookahead_classes[i], NULL );
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End1;
 +      known_lookahead_classes = i;
 +      }
 +
 +      if ( lc[i] != lookahead_classes[i] )
 +      goto next_chainposclassrule;
 +    }
 +
 +    error = Do_ContextPos( gpi, igc,
 +                         cpcr.PosCount,
 +                         cpcr.PosLookupRecord,
 +                         buffer,
 +                         nesting_level );
 +    goto End1;
 +
 +  next_chainposclassrule:
 +    ;
 +  }
 +
 +  error = HB_Err_Not_Covered;
 +
 +End1:
 +  FREE( lookahead_classes );
 +
 +End2:
 +  FREE( input_classes );
 +
 +End3:
 +  FREE( backtrack_classes );
 +  return error;
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextPos3(
 +                 GPOS_Instance*               gpi,
 +                 HB_ChainContextPosFormat3*  ccpf3,
 +                 HB_Buffer                   buffer,
 +                 HB_UShort                    flags,
 +                 HB_UShort                    context_length,
 +                 int                          nesting_level )
 +{
 +  HB_UShort        index, i, j, property;
 +  HB_UShort        bgc, igc, lgc;
 +  HB_Error         error;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +
 +  HB_Coverage*    bc;
 +  HB_Coverage*    ic;
 +  HB_Coverage*    lc;
-   gdef = gpos->gdef;
++  hb_ot_layout_t*  layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gpos->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  bgc = ccpf3->BacktrackGlyphCount;
 +  igc = ccpf3->InputGlyphCount;
 +  lgc = ccpf3->LookaheadGlyphCount;
 +
 +  if ( context_length != 0xFFFF && context_length < igc )
 +    return HB_Err_Not_Covered;
 +
 +  /* check whether context is too long; it is a first guess only */
 +
 +  if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
 +    return HB_Err_Not_Covered;
 +
 +  if ( bgc )
 +  {
 +    /* Since we don't know in advance the number of glyphs to inspect,
 +       we search backwards for matches in the backtrack glyph array    */
 +
 +    bc       = ccpf3->BacktrackCoverage;
 +
 +    for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
 +    {
-     while ( j > buffer->in_pos && 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;
 +
 +      if ( j + 1 == bgc - i )
 +        return HB_Err_Not_Covered;
 +      j--;
 +      }
 +
 +      error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
 +      if ( error )
 +      return error;
 +    }
 +  }
 +
 +  ic       = ccpf3->InputCoverage;
 +
 +  for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
 +  {
 +    /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
-     while ( 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;
 +
 +      if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
 +      return HB_Err_Not_Covered;
 +      j++;
 +    }
 +
 +    error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
 +    if ( error )
 +      return error;
 +  }
 +
 +  /* we are starting to check for lookahead glyphs right after the
 +     last context glyph                                            */
 +
 +  lc       = ccpf3->LookaheadCoverage;
 +
 +  for ( i = 0; i < lgc; i++, j++ )
 +  {
++    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +    {
 +      if ( error && error != HB_Err_Not_Covered )
 +      return error;
 +
 +      if ( j + lgc - i == (HB_Int)buffer->in_length )
 +      return HB_Err_Not_Covered;
 +      j++;
 +    }
 +
 +    error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
 +    if ( error )
 +      return error;
 +  }
 +
 +  return Do_ContextPos( gpi, igc,
 +                      ccpf3->PosCount,
 +                      ccpf3->PosLookupRecord,
 +                      buffer,
 +                      nesting_level );
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextPos(
 +                 GPOS_Instance*        gpi,
 +                 HB_GPOS_SubTable* st,
 +                 HB_Buffer            buffer,
 +                 HB_UShort             flags,
 +                 HB_UShort             context_length,
 +                 int                   nesting_level )
 +{
 +  HB_ChainContextPos*  ccp = &st->chain;
 +
 +  switch ( ccp->PosFormat )
 +  {
 +  case 1:
 +    return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
 +                                  flags, context_length,
 +                                  nesting_level );
 +
 +  case 2:
 +    return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
 +                                  flags, context_length,
 +                                  nesting_level );
 +
 +  case 3:
 +    return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
 +                                  flags, context_length,
 +                                  nesting_level );
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +
 +/***********
 + * GPOS API
 + ***********/
 +
 +
 +
 +HB_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
 +                               HB_UInt         script_tag,
 +                               HB_UShort*       script_index )
 +{
 +  HB_UShort          n;
 +
 +  HB_ScriptList*    sl;
 +  HB_ScriptRecord*  sr;
 +
 +
 +  if ( !gpos || !script_index )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gpos->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  for ( n = 0; n < sl->ScriptCount; n++ )
 +    if ( script_tag == sr[n].ScriptTag )
 +    {
 +      *script_index = n;
 +
 +      return HB_Err_Ok;
 +    }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +
 +HB_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
 +                                 HB_UInt         language_tag,
 +                                 HB_UShort        script_index,
 +                                 HB_UShort*       language_index,
 +                                 HB_UShort*       req_feature_index )
 +{
 +  HB_UShort           n;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +
 +
 +  if ( !gpos || !language_index || !req_feature_index )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gpos->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  for ( n = 0; n < s->LangSysCount; n++ )
 +    if ( language_tag == lsr[n].LangSysTag )
 +    {
 +      *language_index = n;
 +      *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
 +
 +      return HB_Err_Ok;
 +    }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +/* selecting 0xFFFF for language_index asks for the values of the
 +   default language (DefaultLangSys)                              */
 +
 +
 +HB_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
 +                                HB_UInt         feature_tag,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UShort*       feature_index )
 +{
 +  HB_UShort           n;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +  HB_LangSys*        ls;
 +  HB_UShort*          fi;
 +
 +  HB_FeatureList*    fl;
 +  HB_FeatureRecord*  fr;
 +
 +
 +  if ( !gpos || !feature_index )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gpos->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  fl = &gpos->FeatureList;
 +  fr = fl->FeatureRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  if ( language_index == 0xFFFF )
 +    ls = &s->DefaultLangSys;
 +  else
 +  {
 +    if ( language_index >= s->LangSysCount )
 +      return ERR(HB_Err_Invalid_Argument);
 +
 +    ls = &lsr[language_index].LangSys;
 +  }
 +
 +  fi = ls->FeatureIndex;
 +
 +  for ( n = 0; n < ls->FeatureCount; n++ )
 +  {
 +    if ( fi[n] >= fl->FeatureCount )
 +      return ERR(HB_Err_Invalid_SubTable_Format);
 +
 +    if ( feature_tag == fr[fi[n]].FeatureTag )
 +    {
 +      *feature_index = fi[n];
 +
 +      return HB_Err_Ok;
 +    }
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +/* The next three functions return a null-terminated list */
 +
 +
 +HB_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
 +                               HB_UInt**       script_tag_list )
 +{
 +  HB_Error           error;
 +  HB_UShort          n;
 +  HB_UInt*          stl;
 +
 +  HB_ScriptList*    sl;
 +  HB_ScriptRecord*  sr;
 +
 +
 +  if ( !gpos || !script_tag_list )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gpos->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
 +    return error;
 +
 +  for ( n = 0; n < sl->ScriptCount; n++ )
 +    stl[n] = sr[n].ScriptTag;
 +  stl[n] = 0;
 +
 +  *script_tag_list = stl;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +
 +HB_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
 +                                 HB_UShort        script_index,
 +                                 HB_UInt**       language_tag_list )
 +{
 +  HB_Error            error;
 +  HB_UShort           n;
 +  HB_UInt*           ltl;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +
 +
 +  if ( !gpos || !language_tag_list )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gpos->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
 +    return error;
 +
 +  for ( n = 0; n < s->LangSysCount; n++ )
 +    ltl[n] = lsr[n].LangSysTag;
 +  ltl[n] = 0;
 +
 +  *language_tag_list = ltl;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* selecting 0xFFFF for language_index asks for the values of the
 +   default language (DefaultLangSys)                              */
 +
 +
 +HB_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UInt**       feature_tag_list )
 +{
 +  HB_UShort           n;
 +  HB_Error            error;
 +  HB_UInt*           ftl;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +  HB_LangSys*        ls;
 +  HB_UShort*          fi;
 +
 +  HB_FeatureList*    fl;
 +  HB_FeatureRecord*  fr;
 +
 +
 +  if ( !gpos || !feature_tag_list )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gpos->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  fl = &gpos->FeatureList;
 +  fr = fl->FeatureRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  if ( language_index == 0xFFFF )
 +    ls = &s->DefaultLangSys;
 +  else
 +  {
 +    if ( language_index >= s->LangSysCount )
 +      return ERR(HB_Err_Invalid_Argument);
 +
 +    ls = &lsr[language_index].LangSys;
 +  }
 +
 +  fi = ls->FeatureIndex;
 +
 +  if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
 +    return error;
 +
 +  for ( n = 0; n < ls->FeatureCount; n++ )
 +  {
 +    if ( fi[n] >= fl->FeatureCount )
 +    {
 +      FREE( ftl );
 +      return ERR(HB_Err_Invalid_SubTable_Format);
 +    }
 +    ftl[n] = fr[fi[n]].FeatureTag;
 +  }
 +  ftl[n] = 0;
 +
 +  *feature_tag_list = ftl;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* Do an individual subtable lookup.  Returns HB_Err_Ok if positioning
 +   has been done, or HB_Err_Not_Covered if not.                        */
 +static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
 +                                     HB_UShort         lookup_index,
 +                                     HB_Buffer        buffer,
 +                                     HB_UShort         context_length,
 +                                     int               nesting_level )
 +{
 +  HB_Error             error = HB_Err_Not_Covered;
 +  HB_UShort            i, flags, lookup_count;
 +  HB_GPOSHeader*       gpos = gpi->gpos;
 +  HB_Lookup*           lo;
 +  int                lookup_type;
 +
 +
 +  nesting_level++;
 +
 +  if ( nesting_level > HB_MAX_NESTING_LEVEL )
 +    return ERR(HB_Err_Not_Covered); /* ERR() call intended */
 +
 +  lookup_count = gpos->LookupList.LookupCount;
 +  if (lookup_index >= lookup_count)
 +    return error;
 +
 +  lo    = &gpos->LookupList.Lookup[lookup_index];
 +  flags = lo->LookupFlag;
 +  lookup_type = lo->LookupType;
 +
 +  for ( i = 0; i < lo->SubTableCount; i++ )
 +  {
 +    HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
 +
 +    switch (lookup_type) {
 +      case HB_GPOS_LOOKUP_SINGLE:
 +        error = Lookup_SinglePos      ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GPOS_LOOKUP_PAIR:
 +      error = Lookup_PairPos          ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GPOS_LOOKUP_CURSIVE:
 +      error = Lookup_CursivePos       ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GPOS_LOOKUP_MARKBASE:
 +      error = Lookup_MarkBasePos      ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GPOS_LOOKUP_MARKLIG:
 +      error = Lookup_MarkLigPos       ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GPOS_LOOKUP_MARKMARK:
 +      error = Lookup_MarkMarkPos      ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GPOS_LOOKUP_CONTEXT:
 +      error = Lookup_ContextPos       ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GPOS_LOOKUP_CHAIN:
 +      error = Lookup_ChainContextPos  ( gpi, st, buffer, flags, context_length, nesting_level ); break;
 +    /*case HB_GPOS_LOOKUP_EXTENSION:
 +      error = Lookup_ExtensionPos     ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
 +      default:
 +      error = HB_Err_Not_Covered;
 +    }
 +
 +    /* Check whether we have a successful positioning or an error other
 +       than HB_Err_Not_Covered                                         */
 +    if ( error != HB_Err_Not_Covered )
 +      return error;
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +HB_INTERNAL HB_Error
 +_HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
 +                      HB_Stream         stream,
 +                      HB_UShort         lookup_type )
 +{
 +  switch ( lookup_type ) {
 +    case HB_GPOS_LOOKUP_SINGLE:               return Load_SinglePos           ( st, stream );
 +    case HB_GPOS_LOOKUP_PAIR:         return Load_PairPos             ( st, stream );
 +    case HB_GPOS_LOOKUP_CURSIVE:      return Load_CursivePos          ( st, stream );
 +    case HB_GPOS_LOOKUP_MARKBASE:     return Load_MarkBasePos         ( st, stream );
 +    case HB_GPOS_LOOKUP_MARKLIG:      return Load_MarkLigPos          ( st, stream );
 +    case HB_GPOS_LOOKUP_MARKMARK:     return Load_MarkMarkPos         ( st, stream );
 +    case HB_GPOS_LOOKUP_CONTEXT:      return Load_ContextPos          ( st, stream );
 +    case HB_GPOS_LOOKUP_CHAIN:                return Load_ChainContextPos     ( st, stream );
 +  /*case HB_GPOS_LOOKUP_EXTENSION:    return Load_ExtensionPos        ( st, stream );*/
 +    default:                          return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +}
 +
 +
 +HB_INTERNAL void
 +_HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
 +                      HB_UShort         lookup_type )
 +{
 +  switch ( lookup_type ) {
 +    case HB_GPOS_LOOKUP_SINGLE:               Free_SinglePos          ( st ); return;
 +    case HB_GPOS_LOOKUP_PAIR:         Free_PairPos            ( st ); return;
 +    case HB_GPOS_LOOKUP_CURSIVE:      Free_CursivePos         ( st ); return;
 +    case HB_GPOS_LOOKUP_MARKBASE:     Free_MarkBasePos        ( st ); return;
 +    case HB_GPOS_LOOKUP_MARKLIG:      Free_MarkLigPos         ( st ); return;
 +    case HB_GPOS_LOOKUP_MARKMARK:     Free_MarkMarkPos        ( st ); return;
 +    case HB_GPOS_LOOKUP_CONTEXT:      Free_ContextPos         ( st ); return;
 +    case HB_GPOS_LOOKUP_CHAIN:                Free_ChainContextPos    ( st ); return;
 +  /*case HB_GPOS_LOOKUP_EXTENSION:    Free_ExtensionPos       ( st ); return;*/
 +    default:                                                                  return;
 +  }
 +}
 +
 +
 +/* apply one lookup to the input string object */
 +
 +static HB_Error  GPOS_Do_String_Lookup( GPOS_Instance*    gpi,
 +                                 HB_UShort         lookup_index,
 +                                 HB_Buffer        buffer )
 +{
 +  HB_Error         error, retError = HB_Err_Not_Covered;
 +  HB_GPOSHeader*  gpos = gpi->gpos;
 +
 +  HB_UInt*  properties = gpos->LookupList.Properties;
 +
 +  const int       nesting_level = 0;
 +  /* 0xFFFF indicates that we don't have a context length yet */
 +  const HB_UShort context_length = 0xFFFF;
 +
 +
 +  gpi->last  = 0xFFFF;     /* no last valid glyph for cursive pos. */
 +
 +  buffer->in_pos = 0;
 +  while ( buffer->in_pos < buffer->in_length )
 +  {
 +    if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
 +    {
 +      /* Note that the connection between mark and base glyphs hold
 +       exactly one (string) lookup.  For example, it would be possible
 +       that in the first lookup, mark glyph X is attached to base
 +       glyph A, and in the next lookup it is attached to base glyph B.
 +       It is up to the font designer to provide meaningful lookups and
 +       lookup order.                                                   */
 +
 +      error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
 +      if ( error && error != HB_Err_Not_Covered )
 +      return error;
 +    }
 +    else
 +    {
 +      /* Contrary to properties defined in GDEF, user-defined properties
 +       will always stop a possible cursive positioning.                */
 +      gpi->last = 0xFFFF;
 +
 +      error = HB_Err_Not_Covered;
 +    }
 +
 +    if ( error == HB_Err_Not_Covered )
 +      (buffer->in_pos)++;
 +    else
 +      retError = error;
 +  }
 +
 +  return retError;
 +}
 +
 +
 +static HB_Error  Position_CursiveChain ( HB_Buffer     buffer )
 +{
 +  HB_UInt   i, j;
 +  HB_Position positions = buffer->positions;
 +
 +  /* First handle all left-to-right connections */
 +  for (j = 0; j < buffer->in_length; j++)
 +  {
 +    if (positions[j].cursive_chain > 0)
 +      positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
 +  }
 +
 +  /* Then handle all right-to-left connections */
 +  for (i = buffer->in_length; i > 0; i--)
 +  {
 +    j = i - 1;
 +
 +    if (positions[j].cursive_chain < 0)
 +      positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +HB_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
 +                             HB_UShort        feature_index,
 +                             HB_UInt          property )
 +{
 +  HB_UShort    i;
 +
 +  HB_Feature  feature;
 +  HB_UInt*     properties;
 +  HB_UShort*   index;
 +  HB_UShort    lookup_count;
 +
 +  /* Each feature can only be added once */
 +
 +  if ( !gpos ||
 +       feature_index >= gpos->FeatureList.FeatureCount ||
 +       gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
 +
 +  properties = gpos->LookupList.Properties;
 +
 +  feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
 +  index   = feature.LookupListIndex;
 +  lookup_count = gpos->LookupList.LookupCount;
 +
 +  for ( i = 0; i < feature.LookupListCount; i++ )
 +  {
 +    HB_UShort lookup_index = index[i];
 +    if (lookup_index < lookup_count)
 +      properties[lookup_index] |= property;
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +
 +HB_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos )
 +{
 +  HB_UShort i;
 +
 +  HB_UInt*  properties;
 +
 +
 +  if ( !gpos )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  gpos->FeatureList.ApplyCount = 0;
 +
 +  properties = gpos->LookupList.Properties;
 +
 +  for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
 +    properties[i] = 0;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +
 +HB_Error  HB_GPOS_Register_Glyph_Function( HB_GPOSHeader*    gpos,
 +                                         HB_GlyphFunction  gfunc )
 +{
 +  if ( !gpos )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  gpos->gfunc = gfunc;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +
 +HB_Error  HB_GPOS_Register_MM_Function( HB_GPOSHeader*  gpos,
 +                                      HB_MMFunction   mmfunc,
 +                                      void*            data )
 +{
 +  if ( !gpos )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  gpos->mmfunc = mmfunc;
 +  gpos->data   = data;
 +
 +  return HB_Err_Ok;
 +}
 +
 +/* If `dvi' is TRUE, glyph contour points for anchor points and device
 +   tables are ignored -- you will get device independent values.         */
 +
 +
 +HB_Error  HB_GPOS_Apply_String( HB_Font           font,
 +                              HB_GPOSHeader*    gpos,
 +                              HB_UShort         load_flags,
 +                              HB_Buffer         buffer,
 +                              HB_Bool           dvi,
 +                              HB_Bool           r2l )
 +{
 +  HB_Error       error, retError = HB_Err_Not_Covered;
 +  GPOS_Instance  gpi;
 +  int            i, j, lookup_count, num_features;
 +
 +  if ( !font || !gpos || !buffer )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  if ( buffer->in_length == 0 )
 +    return HB_Err_Not_Covered;
 +
 +  gpi.font       = font;
 +  gpi.gpos       = gpos;
 +  gpi.load_flags = load_flags;
 +  gpi.r2l        = r2l;
 +  gpi.dvi        = dvi;
 +
 +  lookup_count = gpos->LookupList.LookupCount;
 +  num_features = gpos->FeatureList.ApplyCount;
 +
 +  if ( num_features )
 +    {
 +      error = _hb_buffer_clear_positions( buffer );
 +      if ( error )
 +      return error;
 +    }
 +
 +  for ( i = 0; i < num_features; i++ )
 +  {
 +    HB_UShort  feature_index = gpos->FeatureList.ApplyOrder[i];
 +    HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
 +
 +    for ( j = 0; j < feature.LookupListCount; j++ )
 +    {
 +      HB_UShort lookup_index = feature.LookupListIndex[j];
 +
 +      /* Skip nonexistant lookups */
 +      if (lookup_index >= lookup_count)
 +       continue;
 +
 +      error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
 +      if ( error )
 +      {
 +      if ( error != HB_Err_Not_Covered )
 +        return error;
 +      }
 +      else
 +      retError = error;
 +    }
 +  }
 +
 +  if ( num_features )
 +    {
 +      error = Position_CursiveChain ( buffer );
 +      if ( error )
 +      return error;
 +    }
 +
 +  return retError;
 +}
 +
 +/* END */
index 8638cf1,0000000..b1aa135
mode 100644,000000..100644
--- /dev/null
@@@ -1,174 -1,0 +1,174 @@@
- #include "harfbuzz-gdef.h"
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2006  Behdad Esfahbod
 + *
 + *  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.
 + */
 +
 +#ifndef HARFBUZZ_GPOS_H
 +#define HARFBUZZ_GPOS_H
 +
-   HB_GDEFHeader*    gdef;
++#include "harfbuzz-open.h"
 +#include "harfbuzz-buffer.h"
 +
 +HB_BEGIN_HEADER
 +
 +
 +/* Lookup types for glyph positioning */
 +
 +#define HB_GPOS_LOOKUP_SINGLE     1
 +#define HB_GPOS_LOOKUP_PAIR       2
 +#define HB_GPOS_LOOKUP_CURSIVE    3
 +#define HB_GPOS_LOOKUP_MARKBASE   4
 +#define HB_GPOS_LOOKUP_MARKLIG    5
 +#define HB_GPOS_LOOKUP_MARKMARK   6
 +#define HB_GPOS_LOOKUP_CONTEXT    7
 +#define HB_GPOS_LOOKUP_CHAIN      8
 +#define HB_GPOS_LOOKUP_EXTENSION  9
 +
 +
 +/* A pointer to a function which loads a glyph.  Its parameters are
 +   the same as in a call to Load_Glyph() -- if no glyph loading
 +   function will be registered with HB_GPOS_Register_Glyph_Function(),
 +   Load_Glyph() will be called indeed.  The purpose of this function
 +   pointer is to provide a hook for caching glyph outlines and sbits
 +   (using the instance's generic pointer to hold the data).
 +
 +   If for some reason no outline data is available (e.g. for an
 +   embedded bitmap glyph), _glyph->outline.n_points should be set to
 +   zero.                                                                */
 +
 +typedef HB_Error  (*HB_GlyphFunction)(HB_Font      font,
 +                                     HB_UInt      glyphIndex,
 +                                     HB_Int       loadFlags );
 +
 +
 +/* A pointer to a function which accesses the PostScript interpreter.
 +   Multiple Master fonts need this interface to convert a metric ID
 +   (as stored in an OpenType font version 1.2 or higher) `metric_id'
 +   into a metric value (returned in `metric_value').
 +
 +   `data' points to the user-defined structure specified during a
 +   call to HB_GPOS_Register_MM_Function().
 +
 +   `metric_value' must be returned as a scaled value (but shouldn't
 +   be rounded).                                                       */
 +
 +typedef HB_Error  (*HB_MMFunction)(HB_Font      font,
 +                                  HB_UShort    metric_id,
 +                                  HB_Fixed*      metric_value,
 +                                  void*        data );
 +
 +
 +struct  HB_GPOSHeader_
 +{
 +  HB_16Dot16           Version;
 +
 +  HB_ScriptList     ScriptList;
 +  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.                                            */
 +
 +  HB_GlyphFunction  gfunc;
 +
 +  /* this is OpenType 1.2 -- Multiple Master fonts need this
 +     callback function to get various metric values from the
 +     PostScript interpreter.                                 */
 +
 +  HB_MMFunction     mmfunc;
 +  void*              data;
 +};
 +
 +typedef struct HB_GPOSHeader_  HB_GPOSHeader;
 +typedef HB_GPOSHeader* HB_GPOS;
 +
 +
 +HB_Error  HB_Load_GPOS_Table( HB_Font          font,
 +                            HB_GPOSHeader** gpos,
++                            hb_ot_layout_t   *layout );
 +
 +
 +HB_Error  HB_Done_GPOS_Table( HB_GPOSHeader* gpos );
 +
 +
 +HB_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
 +                               HB_UInt         script_tag,
 +                               HB_UShort*       script_index );
 +
 +HB_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
 +                                 HB_UInt         language_tag,
 +                                 HB_UShort        script_index,
 +                                 HB_UShort*       language_index,
 +                                 HB_UShort*       req_feature_index );
 +
 +HB_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
 +                                HB_UInt         feature_tag,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UShort*       feature_index );
 +
 +
 +HB_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
 +                               HB_UInt**       script_tag_list );
 +
 +HB_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
 +                                 HB_UShort        script_index,
 +                                 HB_UInt**       language_tag_list );
 +
 +HB_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UInt**       feature_tag_list );
 +
 +
 +HB_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
 +                             HB_UShort        feature_index,
 +                             HB_UInt          property );
 +
 +HB_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos );
 +
 +
 +HB_Error  HB_GPOS_Register_Glyph_Function( HB_GPOSHeader*    gpos,
 +                                         HB_GlyphFunction  gfunc );
 +
 +
 +HB_Error  HB_GPOS_Register_MM_Function( HB_GPOSHeader*  gpos,
 +                                      HB_MMFunction   mmfunc,
 +                                      void*            data );
 +
 +/* If `dvi' is TRUE, glyph contour points for anchor points and device
 +   tables are ignored -- you will get device independent values.         */
 +
 +
 +HB_Error  HB_GPOS_Apply_String( HB_Font           font,
 +                              HB_GPOSHeader*   gpos,
 +                              HB_UShort         load_flags,
 +                              HB_Buffer        buffer,
 +                              HB_Bool           dvi,
 +                              HB_Bool           r2l );
 +
 +HB_END_HEADER
 +
 +#endif /* HARFBUZZ_GPOS_H */
index c05f20d,0000000..38879a8
mode 100644,000000..100644
--- /dev/null
@@@ -1,4329 -1,0 +1,4304 @@@
-                             HB_GDEFHeader*  gdef )
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2006  Behdad Esfahbod
 + * Copyright (C) 2007  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
 + */
 +
 +#include "harfbuzz-impl.h"
 +#include "harfbuzz-gsub-private.h"
 +#include "harfbuzz-open-private.h"
 +#include "harfbuzz-gdef-private.h"
 +
 +static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader*   gsub,
 +                                     HB_UShort         lookup_index,
 +                                     HB_Buffer        buffer,
 +                                     HB_UShort         context_length,
 +                                     int               nesting_level );
 +
 +
 +
 +/**********************
 + * Auxiliary functions
 + **********************/
 +
 +
 +
 +HB_Error  HB_Load_GSUB_Table( HB_Font          font,
 +                            HB_GSUBHeader** retptr,
-   if ( !retptr )
++                            hb_ot_layout_t    *layout )
 +{
 +  HB_Stream        stream = font->stream;
 +  HB_Error         error;
 +  HB_UInt         cur_offset, new_offset, base_offset;
 +
 +  HB_GSUBHeader*  gsub;
 +
-   gsub->gdef = gdef;      /* can be NULL */
-   if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream,
-                                                                    gsub->LookupList.Lookup,
-                                                                    gsub->LookupList.LookupCount ) ) )
-         goto Fail1;
++  if ( !retptr || !layout )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  if ( GOTO_Table( TTAG_GSUB ) )
 +    return error;
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ALLOC ( gsub, sizeof( *gsub ) ) )
 +    return error;
 +
 +
 +  /* skip version */
 +
 +  if ( FILE_Seek( base_offset + 4L ) ||
 +       ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_ScriptList( &gsub->ScriptList,
 +                                stream ) ) != HB_Err_Ok )
 +    goto Fail4;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_FeatureList( &gsub->FeatureList,
 +                                 stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_LookupList( &gsub->LookupList,
 +                                stream, HB_Type_GSUB ) ) != HB_Err_Ok )
 +    goto Fail2;
 +
- Fail1:
-   _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
++  gsub->layout = layout;      /* can be NULL */
 +
 +  *retptr = gsub;
 +
 +  return HB_Err_Ok;
 +
-   HB_GDEFHeader*   gdef = gsub->gdef;
 +Fail2:
 +  _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
 +
 +Fail3:
 +  _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
 +
 +Fail4:
 +  FREE ( gsub );
 +
 +
 +  return error;
 +}
 +
 +
 +HB_Error   HB_Done_GSUB_Table( HB_GSUBHeader* gsub )
 +{
 +  _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
 +  _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
 +  _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
 +
 +  FREE( gsub );
 +
 +  return HB_Err_Ok;
 +}
 +
 +/*****************************
 + * SubTable related functions
 + *****************************/
 +
 +
 +/* LookupType 1 */
 +
 +/* SingleSubstFormat1 */
 +/* SingleSubstFormat2 */
 +
 +static HB_Error  Load_SingleSubst( HB_GSUB_SubTable* st,
 +                                 HB_Stream         stream )
 +{
 +  HB_Error error;
 +  HB_SingleSubst*  ss = &st->single;
 +
 +  HB_UShort n, count;
 +  HB_UInt cur_offset, new_offset, base_offset;
 +
 +  HB_UShort*  s;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  ss->SubstFormat = GET_UShort();
 +  new_offset      = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  switch ( ss->SubstFormat )
 +  {
 +  case 1:
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    break;
 +
 +  case 2:
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    count = ss->ssf.ssf2.GlyphCount = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    ss->ssf.ssf2.Substitute = NULL;
 +
 +    if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, HB_UShort ) )
 +      goto Fail2;
 +
 +    s = ss->ssf.ssf2.Substitute;
 +
 +    if ( ACCESS_Frame( count * 2L ) )
 +      goto Fail1;
 +
 +    for ( n = 0; n < count; n++ )
 +      s[n] = GET_UShort();
 +
 +    FORGET_Frame();
 +
 +    break;
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( s );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &ss->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_SingleSubst( HB_GSUB_SubTable* st )
 +{
 +  HB_SingleSubst*  ss = &st->single;
 +
 +  switch ( ss->SubstFormat )
 +  {
 +  case 1:
 +    break;
 +
 +  case 2:
 +    FREE( ss->ssf.ssf2.Substitute );
 +    break;
 +
 +  default:
 +    break;
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &ss->Coverage );
 +}
 +
 +
 +static HB_Error  Lookup_SingleSubst( HB_GSUBHeader*   gsub,
 +                                   HB_GSUB_SubTable* st,
 +                                   HB_Buffer        buffer,
 +                                   HB_UShort         flags,
 +                                   HB_UShort         context_length,
 +                                   int               nesting_level )
 +{
 +  HB_UShort index, value, property;
 +  HB_Error  error;
 +  HB_SingleSubst*  ss = &st->single;
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  hb_ot_layout_t*   layout = gsub->layout;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( context_length != 0xFFFF && context_length < 1 )
 +    return HB_Err_Not_Covered;
 +
-   if ( gdef && gdef->NewGlyphClasses )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  switch ( ss->SubstFormat )
 +  {
 +  case 1:
 +    value = (IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
 +    if ( REPLACE_Glyph( buffer, value, nesting_level ) )
 +      return error;
 +    break;
 +
 +  case 2:
 +    if ( index >= ss->ssf.ssf2.GlyphCount )
 +      return ERR(HB_Err_Invalid_SubTable);
 +    value = ss->ssf.ssf2.Substitute[index];
 +    if ( REPLACE_Glyph( buffer, value, nesting_level ) )
 +      return error;
 +    break;
 +
 +  default:
 +    return ERR(HB_Err_Invalid_SubTable);
 +  }
 +
-     error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
-     if ( error && error != HB_Err_Not_Covered )
-       return error;
++  if ( _hb_ot_layout_has_new_glyph_classes (layout) )
 +  {
 +    /* we inherit the old glyph class to the substituted glyph */
 +
-   HB_GDEFHeader*     gdef = gsub->gdef;
++    hb_ot_layout_set_glyph_class (layout, value, property);
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 2 */
 +
 +/* Sequence */
 +
 +static HB_Error  Load_Sequence( HB_Sequence*  s,
 +                              HB_Stream      stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort n, count;
 +  HB_UShort*  sub;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = s->GlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  s->Substitute = NULL;
 +
 +  if ( count )
 +  {
 +    if ( ALLOC_ARRAY( s->Substitute, count, HB_UShort ) )
 +      return error;
 +
 +    sub = s->Substitute;
 +
 +    if ( ACCESS_Frame( count * 2L ) )
 +    {
 +      FREE( sub );
 +      return error;
 +    }
 +
 +    for ( n = 0; n < count; n++ )
 +      sub[n] = GET_UShort();
 +
 +    FORGET_Frame();
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +static void  Free_Sequence( HB_Sequence*  s )
 +{
 +  FREE( s->Substitute );
 +}
 +
 +
 +/* MultipleSubstFormat1 */
 +
 +static HB_Error  Load_MultipleSubst( HB_GSUB_SubTable* st,
 +                                   HB_Stream         stream )
 +{
 +  HB_Error error;
 +  HB_MultipleSubst*  ms = &st->multiple;
 +
 +  HB_UShort      n = 0, m, count;
 +  HB_UInt       cur_offset, new_offset, base_offset;
 +
 +  HB_Sequence*  s;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  ms->SubstFormat = GET_UShort();             /* should be 1 */
 +  new_offset      = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = ms->SequenceCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ms->Sequence = NULL;
 +
 +  if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) )
 +    goto Fail2;
 +
 +  s = ms->Sequence;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_Sequence( &s[n], stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_Sequence( &s[m] );
 +
 +  FREE( s );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &ms->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_MultipleSubst( HB_GSUB_SubTable* st )
 +{
 +  HB_UShort      n, count;
 +  HB_MultipleSubst*  ms = &st->multiple;
 +
 +  HB_Sequence*  s;
 +
 +
 +  if ( ms->Sequence )
 +  {
 +    count = ms->SequenceCount;
 +    s     = ms->Sequence;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_Sequence( &s[n] );
 +
 +    FREE( s );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &ms->Coverage );
 +}
 +
 +
 +static HB_Error  Lookup_MultipleSubst( HB_GSUBHeader*    gsub,
 +                                     HB_GSUB_SubTable* st,
 +                                     HB_Buffer         buffer,
 +                                     HB_UShort          flags,
 +                                     HB_UShort          context_length,
 +                                     int                nesting_level )
 +{
 +  HB_Error  error;
 +  HB_UShort index, property, n, count;
 +  HB_UShort*s;
 +  HB_MultipleSubst*  ms = &st->multiple;
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  hb_ot_layout_t*     layout = gsub->layout;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( context_length != 0xFFFF && context_length < 1 )
 +    return HB_Err_Not_Covered;
 +
-   if ( gdef && gdef->NewGlyphClasses )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  if ( index >= ms->SequenceCount )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  count = ms->Sequence[index].GlyphCount;
 +  s     = ms->Sequence[index].Substitute;
 +
 +  if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
 +    return error;
 +
-     if ( property == HB_GDEF_LIGATURE )
-       property = HB_GDEF_BASE_GLYPH;
++  if ( _hb_ot_layout_has_new_glyph_classes (layout) )
 +  {
 +    /* this is a guess only ... */
 +
-     {
-       error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
-       if ( error && error != HB_Err_Not_Covered )
-       return error;
-     }
++    if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
++      property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
 +
 +    for ( n = 0; n < count; n++ )
-   HB_GDEFHeader*     gdef = gsub->gdef;
++      hb_ot_layout_set_glyph_class (layout, s[n], property);
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 3 */
 +
 +/* AlternateSet */
 +
 +static HB_Error  Load_AlternateSet( HB_AlternateSet*  as,
 +                                  HB_Stream          stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort n, count;
 +  HB_UShort*  a;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = as->GlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  as->Alternate = NULL;
 +
 +  if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) )
 +    return error;
 +
 +  a = as->Alternate;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +  {
 +    FREE( a );
 +    return error;
 +  }
 +
 +  for ( n = 0; n < count; n++ )
 +    a[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +static void  Free_AlternateSet( HB_AlternateSet*  as )
 +{
 +  FREE( as->Alternate );
 +}
 +
 +
 +/* AlternateSubstFormat1 */
 +
 +static HB_Error  Load_AlternateSubst( HB_GSUB_SubTable* st,
 +                                    HB_Stream         stream )
 +{
 +  HB_Error error;
 +  HB_AlternateSubst* as = &st->alternate;
 +
 +  HB_UShort          n = 0, m, count;
 +  HB_UInt           cur_offset, new_offset, base_offset;
 +
 +  HB_AlternateSet*  aset;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  as->SubstFormat = GET_UShort();             /* should be 1 */
 +  new_offset      = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = as->AlternateSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  as->AlternateSet = NULL;
 +
 +  if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) )
 +    goto Fail2;
 +
 +  aset = as->AlternateSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_AlternateSet( &aset[n], stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_AlternateSet( &aset[m] );
 +
 +  FREE( aset );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &as->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_AlternateSubst( HB_GSUB_SubTable* st )
 +{
 +  HB_UShort          n, count;
 +  HB_AlternateSubst* as = &st->alternate;
 +
 +  HB_AlternateSet*  aset;
 +
 +
 +  if ( as->AlternateSet )
 +  {
 +    count = as->AlternateSetCount;
 +    aset  = as->AlternateSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_AlternateSet( &aset[n] );
 +
 +    FREE( aset );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &as->Coverage );
 +}
 +
 +
 +static HB_Error  Lookup_AlternateSubst( HB_GSUBHeader*    gsub,
 +                                      HB_GSUB_SubTable* st,
 +                                      HB_Buffer         buffer,
 +                                      HB_UShort          flags,
 +                                      HB_UShort          context_length,
 +                                      int                nesting_level )
 +{
 +  HB_Error          error;
 +  HB_UShort         index, value, alt_index, property;
 +  HB_AlternateSubst* as = &st->alternate;
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  hb_ot_layout_t*     layout = gsub->layout;
 +  HB_AlternateSet  aset;
 +
 +  HB_UNUSED(nesting_level);
 +
 +  if ( context_length != 0xFFFF && context_length < 1 )
 +    return HB_Err_Not_Covered;
 +
-   if ( gdef && gdef->NewGlyphClasses )
-   {
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  aset = as->AlternateSet[index];
 +
 +  /* we use a user-defined callback function to get the alternate index */
 +
 +  if ( gsub->altfunc )
 +    alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(),
 +                               aset.GlyphCount, aset.Alternate,
 +                               gsub->data );
 +  else
 +    alt_index = 0;
 +
 +  value = aset.Alternate[alt_index];
 +  if ( REPLACE_Glyph( buffer, value, nesting_level ) )
 +    return error;
 +
-     error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
-     if ( error && error != HB_Err_Not_Covered )
-       return error;
-   }
++  if ( _hb_ot_layout_has_new_glyph_classes (layout) )
 +    /* we inherit the old glyph class to the substituted glyph */
-   HB_GDEFHeader*     gdef = gsub->gdef;
++    hb_ot_layout_set_glyph_class (layout, value, property);
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 4 */
 +
 +/* Ligature */
 +
 +static HB_Error  Load_Ligature( HB_Ligature*  l,
 +                              HB_Stream      stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort n, count;
 +  HB_UShort*  c;
 +
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  l->LigGlyph       = GET_UShort();
 +  l->ComponentCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  l->Component = NULL;
 +
 +  count = l->ComponentCount - 1;      /* only ComponentCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( l->Component, count, HB_UShort ) )
 +    return error;
 +
 +  c = l->Component;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +  {
 +    FREE( c );
 +    return error;
 +  }
 +
 +  for ( n = 0; n < count; n++ )
 +    c[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +static void  Free_Ligature( HB_Ligature*  l )
 +{
 +  FREE( l->Component );
 +}
 +
 +
 +/* LigatureSet */
 +
 +static HB_Error  Load_LigatureSet( HB_LigatureSet*  ls,
 +                                 HB_Stream         stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort      n = 0, m, count;
 +  HB_UInt       cur_offset, new_offset, base_offset;
 +
 +  HB_Ligature*  l;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = ls->LigatureCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ls->Ligature = NULL;
 +
 +  if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) )
 +    return error;
 +
 +  l = ls->Ligature;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_Ligature( &l[n], stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_Ligature( &l[m] );
 +
 +  FREE( l );
 +  return error;
 +}
 +
 +
 +static void  Free_LigatureSet( HB_LigatureSet*  ls )
 +{
 +  HB_UShort      n, count;
 +
 +  HB_Ligature*  l;
 +
 +
 +  if ( ls->Ligature )
 +  {
 +    count = ls->LigatureCount;
 +    l     = ls->Ligature;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_Ligature( &l[n] );
 +
 +    FREE( l );
 +  }
 +}
 +
 +
 +/* LigatureSubstFormat1 */
 +
 +static HB_Error  Load_LigatureSubst( HB_GSUB_SubTable* st,
 +                                   HB_Stream         stream )
 +{
 +  HB_Error error;
 +  HB_LigatureSubst*  ls = &st->ligature;
 +
 +  HB_UShort         n = 0, m, count;
 +  HB_UInt          cur_offset, new_offset, base_offset;
 +
 +  HB_LigatureSet*  lset;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  ls->SubstFormat = GET_UShort();             /* should be 1 */
 +  new_offset      = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = ls->LigatureSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ls->LigatureSet = NULL;
 +
 +  if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) )
 +    goto Fail2;
 +
 +  lset = ls->LigatureSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_LigatureSet( &lset[n], stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_LigatureSet( &lset[m] );
 +
 +  FREE( lset );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &ls->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_LigatureSubst( HB_GSUB_SubTable* st )
 +{
 +  HB_UShort         n, count;
 +  HB_LigatureSubst*  ls = &st->ligature;
 +
 +  HB_LigatureSet*  lset;
 +
 +
 +  if ( ls->LigatureSet )
 +  {
 +    count = ls->LigatureSetCount;
 +    lset  = ls->LigatureSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_LigatureSet( &lset[n] );
 +
 +    FREE( lset );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &ls->Coverage );
 +}
 +
 +
 +static HB_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
 +                                     HB_GSUB_SubTable* st,
 +                                     HB_Buffer         buffer,
 +                                     HB_UShort          flags,
 +                                     HB_UShort          context_length,
 +                                     int                nesting_level )
 +{
 +  HB_UShort      index, property;
 +  HB_Error       error;
 +  HB_UShort      numlig, i, j, is_mark, first_is_mark = FALSE;
 +  HB_UShort*     c;
 +  HB_LigatureSubst*  ls = &st->ligature;
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  hb_ot_layout_t*     layout = gsub->layout;
 +
 +  HB_Ligature*  lig;
 +
 +  HB_UNUSED(nesting_level);
 +
-   if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  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 );
 +  if ( error )
 +    return error;
 +
 +  if ( index >= ls->LigatureSetCount )
 +     return ERR(HB_Err_Invalid_SubTable);
 +
 +  lig = ls->LigatureSet[index].Ligature;
 +
 +  for ( numlig = ls->LigatureSet[index].LigatureCount;
 +      numlig;
 +      numlig--, lig++ )
 +  {
 +    if ( buffer->in_pos + lig->ComponentCount > buffer->in_length )
 +      goto next_ligature;               /* Not enough glyphs in input */
 +
 +    c    = lig->Component;
 +
 +    is_mark = first_is_mark;
 +
 +    if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
 +      break;
 +
 +    for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ )
 +    {
-       if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        return error;
 +
 +      if ( j + lig->ComponentCount - i == (HB_Int)buffer->in_length )
 +        goto next_ligature;
 +      j++;
 +      }
 +
-     if ( gdef && gdef->NewGlyphClasses )
-     {
++      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;
 +    }
 +
-       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;
-     }
++    if ( _hb_ot_layout_has_new_glyph_classes (layout) )
 +      /* this is just a guess ... */
-       while ( CHECK_Property( gdef, IN_CURITEM(),
++      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 */
 +    {
 +      /* We don't use a new ligature ID if there are no skipped
 +       glyphs and the ligature already has an ID.             */
 +
 +      if ( IN_LIGID( buffer->in_pos ) )
 +      {
 +      if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
 +                      0xFFFF, 0xFFFF ) )
 +        return error;
 +      }
 +      else
 +      {
 +      HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
 +      if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
 +                      0xFFFF, ligID ) )
 +        return error;
 +      }
 +    }
 +    else
 +    {
 +      HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
 +      if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) )
 +      return error;
 +
 +      /* Now we must do a second loop to copy the skipped glyphs to
 +       `out' and assign component values to it.  We start with the
 +       glyph after the first component.  Glyphs between component
 +       i and i+1 belong to component i.  Together with the ligID
 +       value it is later possible to check whether a specific
 +       component value really belongs to a given ligature.         */
 +
 +      for ( i = 0; i < lig->ComponentCount - 1; i++ )
 +      {
-   HB_GDEFHeader*  gdef;
++      while ( CHECK_Property( layout, IN_CURITEM(),
 +                              flags, &property ) )
 +        if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) )
 +          return error;
 +
 +      (buffer->in_pos)++;
 +      }
 +    }
 +
 +    return HB_Err_Ok;
 +
 +  next_ligature:
 +    ;
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +/* Do the actual substitution for a context substitution (either format
 +   5 or 6).  This is only called after we've determined that the input
 +   matches the subrule.                                                 */
 +
 +static HB_Error  Do_ContextSubst( HB_GSUBHeader*        gsub,
 +                                HB_UShort              GlyphCount,
 +                                HB_UShort              SubstCount,
 +                                HB_SubstLookupRecord* subst,
 +                                HB_Buffer             buffer,
 +                                int                    nesting_level )
 +{
 +  HB_Error  error;
 +  HB_UInt i, old_pos;
 +
 +
 +  i = 0;
 +
 +  while ( i < GlyphCount )
 +  {
 +    if ( SubstCount && i == subst->SequenceIndex )
 +    {
 +      old_pos = buffer->in_pos;
 +
 +      /* Do a substitution */
 +
 +      error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer,
 +                                  GlyphCount, nesting_level );
 +
 +      subst++;
 +      SubstCount--;
 +      i += buffer->in_pos - old_pos;
 +
 +      if ( error == HB_Err_Not_Covered )
 +      {
 +      if ( COPY_Glyph( buffer ) )
 +        return error;
 +      i++;
 +      }
 +      else if ( error )
 +      return error;
 +    }
 +    else
 +    {
 +      /* No substitution for this index */
 +
 +      if ( COPY_Glyph( buffer ) )
 +      return error;
 +      i++;
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* LookupType 5 */
 +
 +/* SubRule */
 +
 +static HB_Error  Load_SubRule( HB_SubRule*  sr,
 +                             HB_Stream     stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort               n, count;
 +  HB_UShort*              i;
 +
 +  HB_SubstLookupRecord*  slr;
 +
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  sr->GlyphCount = GET_UShort();
 +  sr->SubstCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  sr->Input = NULL;
 +
 +  count = sr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( sr->Input, count, HB_UShort ) )
 +    return error;
 +
 +  i = sr->Input;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    i[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  sr->SubstLookupRecord = NULL;
 +
 +  count = sr->SubstCount;
 +
 +  if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
 +    goto Fail2;
 +
 +  slr = sr->SubstLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    slr[n].SequenceIndex   = GET_UShort();
 +    slr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( slr );
 +
 +Fail2:
 +  FREE( i );
 +  return error;
 +}
 +
 +
 +static void  Free_SubRule( HB_SubRule*  sr )
 +{
 +  FREE( sr->SubstLookupRecord );
 +  FREE( sr->Input );
 +}
 +
 +
 +/* SubRuleSet */
 +
 +static HB_Error  Load_SubRuleSet( HB_SubRuleSet*  srs,
 +                                HB_Stream        stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort     n = 0, m, count;
 +  HB_UInt      cur_offset, new_offset, base_offset;
 +
 +  HB_SubRule*  sr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = srs->SubRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  srs->SubRule = NULL;
 +
 +  if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) )
 +    return error;
 +
 +  sr = srs->SubRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_SubRule( &sr[n], stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_SubRule( &sr[m] );
 +
 +  FREE( sr );
 +  return error;
 +}
 +
 +
 +static void  Free_SubRuleSet( HB_SubRuleSet*  srs )
 +{
 +  HB_UShort     n, count;
 +
 +  HB_SubRule*  sr;
 +
 +
 +  if ( srs->SubRule )
 +  {
 +    count = srs->SubRuleCount;
 +    sr    = srs->SubRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_SubRule( &sr[n] );
 +
 +    FREE( sr );
 +  }
 +}
 +
 +
 +/* ContextSubstFormat1 */
 +
 +static HB_Error  Load_ContextSubst1( HB_ContextSubstFormat1*  csf1,
 +                                   HB_Stream                 stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort        n = 0, m, count;
 +  HB_UInt         cur_offset, new_offset, base_offset;
 +
 +  HB_SubRuleSet*  srs;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &csf1->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = csf1->SubRuleSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  csf1->SubRuleSet = NULL;
 +
 +  if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) )
 +    goto Fail2;
 +
 +  srs = csf1->SubRuleSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_SubRuleSet( &srs[n], stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_SubRuleSet( &srs[m] );
 +
 +  FREE( srs );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &csf1->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ContextSubst1( HB_ContextSubstFormat1* csf1 )
 +{
 +  HB_UShort        n, count;
 +
 +  HB_SubRuleSet*  srs;
 +
 +
 +  if ( csf1->SubRuleSet )
 +  {
 +    count = csf1->SubRuleSetCount;
 +    srs   = csf1->SubRuleSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_SubRuleSet( &srs[n] );
 +
 +    FREE( srs );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &csf1->Coverage );
 +}
 +
 +
 +/* SubClassRule */
 +
 +static HB_Error  Load_SubClassRule( HB_ContextSubstFormat2*  csf2,
 +                                  HB_SubClassRule*         scr,
 +                                  HB_Stream                 stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort               n, count;
 +
 +  HB_UShort*              c;
 +  HB_SubstLookupRecord*  slr;
 +
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  scr->GlyphCount = GET_UShort();
 +  scr->SubstCount = GET_UShort();
 +
 +  if ( scr->GlyphCount > csf2->MaxContextLength )
 +    csf2->MaxContextLength = scr->GlyphCount;
 +
 +  FORGET_Frame();
 +
 +  scr->Class = NULL;
 +
 +  count = scr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) )
 +    return error;
 +
 +  c = scr->Class;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    c[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  scr->SubstLookupRecord = NULL;
 +
 +  count = scr->SubstCount;
 +
 +  if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
 +    goto Fail2;
 +
 +  slr = scr->SubstLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    slr[n].SequenceIndex   = GET_UShort();
 +    slr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( slr );
 +
 +Fail2:
 +  FREE( c );
 +  return error;
 +}
 +
 +
 +static void  Free_SubClassRule( HB_SubClassRule*  scr )
 +{
 +  FREE( scr->SubstLookupRecord );
 +  FREE( scr->Class );
 +}
 +
 +
 +/* SubClassSet */
 +
 +static HB_Error  Load_SubClassSet( HB_ContextSubstFormat2*  csf2,
 +                                 HB_SubClassSet*          scs,
 +                                 HB_Stream                 stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort          n = 0, m, count;
 +  HB_UInt           cur_offset, new_offset, base_offset;
 +
 +  HB_SubClassRule*  scr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = scs->SubClassRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  scs->SubClassRule = NULL;
 +
 +  if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) )
 +    return error;
 +
 +  scr = scs->SubClassRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_SubClassRule( csf2, &scr[n],
 +                                    stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_SubClassRule( &scr[m] );
 +
 +  FREE( scr );
 +  return error;
 +}
 +
 +
 +static void  Free_SubClassSet( HB_SubClassSet*  scs )
 +{
 +  HB_UShort          n, count;
 +
 +  HB_SubClassRule*  scr;
 +
 +
 +  if ( scs->SubClassRule )
 +  {
 +    count = scs->SubClassRuleCount;
 +    scr   = scs->SubClassRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_SubClassRule( &scr[n] );
 +
 +    FREE( scr );
 +  }
 +}
 +
 +
 +/* ContextSubstFormat2 */
 +
 +static HB_Error  Load_ContextSubst2( HB_ContextSubstFormat2*  csf2,
 +                                   HB_Stream                 stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort         n = 0, m, count;
 +  HB_UInt          cur_offset, new_offset, base_offset;
 +
 +  HB_SubClassSet*  scs;
 +
 +
 +  base_offset = FILE_Pos() - 2;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    goto Fail3;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  /* `SubClassSetCount' is the upper limit for class values, thus we
 +     read it now to make an additional safety check.                 */
 +
 +  count = csf2->SubClassSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count,
 +                                     stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +  (void)FILE_Seek( cur_offset );
 +
 +  csf2->SubClassSet      = NULL;
 +  csf2->MaxContextLength = 0;
 +
 +  if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) )
 +    goto Fail2;
 +
 +  scs = csf2->SubClassSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset != base_offset )      /* not a NULL offset */
 +    {
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_SubClassSet( csf2, &scs[n],
 +                                     stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +    {
 +      /* we create a SubClassSet table with no entries */
 +
 +      csf2->SubClassSet[n].SubClassRuleCount = 0;
 +      csf2->SubClassSet[n].SubClassRule      = NULL;
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_SubClassSet( &scs[m] );
 +
 +  FREE( scs );
 +
 +Fail2:
 +  _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
 +
 +Fail3:
 +  _HB_OPEN_Free_Coverage( &csf2->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ContextSubst2( HB_ContextSubstFormat2*  csf2 )
 +{
 +  HB_UShort         n, count;
 +
 +  HB_SubClassSet*  scs;
 +
 +
 +  if ( csf2->SubClassSet )
 +  {
 +    count = csf2->SubClassSetCount;
 +    scs   = csf2->SubClassSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_SubClassSet( &scs[n] );
 +
 +    FREE( scs );
 +  }
 +
 +  _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
 +  _HB_OPEN_Free_Coverage( &csf2->Coverage );
 +}
 +
 +
 +/* ContextSubstFormat3 */
 +
 +static HB_Error  Load_ContextSubst3( HB_ContextSubstFormat3*  csf3,
 +                                   HB_Stream                 stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort               n = 0, m, count;
 +  HB_UInt                cur_offset, new_offset, base_offset;
 +
 +  HB_Coverage*           c;
 +  HB_SubstLookupRecord*  slr;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  csf3->GlyphCount = GET_UShort();
 +  csf3->SubstCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  csf3->Coverage = NULL;
 +
 +  count = csf3->GlyphCount;
 +
 +  if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) )
 +    return error;
 +
 +  c = csf3->Coverage;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
 +      goto Fail2;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  csf3->SubstLookupRecord = NULL;
 +
 +  count = csf3->SubstCount;
 +
 +  if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
 +                  HB_SubstLookupRecord ) )
 +    goto Fail2;
 +
 +  slr = csf3->SubstLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    slr[n].SequenceIndex   = GET_UShort();
 +    slr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( slr );
 +
 +Fail2:
 +  for ( m = 0; m < n; m++ )
 +    _HB_OPEN_Free_Coverage( &c[m] );
 +
 +  FREE( c );
 +  return error;
 +}
 +
 +
 +static void  Free_ContextSubst3( HB_ContextSubstFormat3*  csf3 )
 +{
 +  HB_UShort      n, count;
 +
 +  HB_Coverage*  c;
 +
 +
 +  FREE( csf3->SubstLookupRecord );
 +
 +  if ( csf3->Coverage )
 +  {
 +    count = csf3->GlyphCount;
 +    c     = csf3->Coverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +}
 +
 +
 +/* ContextSubst */
 +
 +static HB_Error  Load_ContextSubst( HB_GSUB_SubTable* st,
 +                                  HB_Stream         stream )
 +{
 +  HB_Error error;
 +  HB_ContextSubst*  cs = &st->context;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  cs->SubstFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  switch ( cs->SubstFormat )
 +  {
 +  case 1:  return Load_ContextSubst1( &cs->csf.csf1, stream );
 +  case 2:  return Load_ContextSubst2( &cs->csf.csf2, stream );
 +  case 3:  return Load_ContextSubst3( &cs->csf.csf3, stream );
 +  default: return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +static void  Free_ContextSubst( HB_GSUB_SubTable* st )
 +{
 +  HB_ContextSubst*  cs = &st->context;
 +
 +  switch ( cs->SubstFormat )
 +  {
 +  case 1:  Free_ContextSubst1( &cs->csf.csf1 ); break;
 +  case 2:  Free_ContextSubst2( &cs->csf.csf2 ); break;
 +  case 3:  Free_ContextSubst3( &cs->csf.csf3 ); break;
 +  default:                                            break;
 +  }
 +}
 +
 +
 +static HB_Error  Lookup_ContextSubst1( HB_GSUBHeader*          gsub,
 +                                     HB_ContextSubstFormat1* csf1,
 +                                     HB_Buffer               buffer,
 +                                     HB_UShort                flags,
 +                                     HB_UShort                context_length,
 +                                     int                      nesting_level )
 +{
 +  HB_UShort        index, property;
 +  HB_UShort        i, j, k, numsr;
 +  HB_Error         error;
 +
 +  HB_SubRule*     sr;
-   gdef = gsub->gdef;
++  hb_ot_layout_t*  layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gsub->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  sr    = csf1->SubRuleSet[index].SubRule;
 +  numsr = csf1->SubRuleSet[index].SubRuleCount;
 +
 +  for ( k = 0; k < numsr; k++ )
 +  {
 +    if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
 +      goto next_subrule;
 +
 +    if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length )
 +      goto next_subrule;                        /* context is too long */
 +
 +    for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
 +    {
-   HB_GDEFHeader*    gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        return error;
 +
 +      if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length )
 +        goto next_subrule;
 +      j++;
 +      }
 +
 +      if ( IN_GLYPH( j ) != sr[k].Input[i - 1] )
 +      goto next_subrule;
 +    }
 +
 +    return Do_ContextSubst( gsub, sr[k].GlyphCount,
 +                          sr[k].SubstCount, sr[k].SubstLookupRecord,
 +                          buffer,
 +                          nesting_level );
 +  next_subrule:
 +    ;
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +static HB_Error  Lookup_ContextSubst2( HB_GSUBHeader*          gsub,
 +                                     HB_ContextSubstFormat2* csf2,
 +                                     HB_Buffer               buffer,
 +                                     HB_UShort                flags,
 +                                     HB_UShort                context_length,
 +                                     int                      nesting_level )
 +{
 +  HB_UShort          index, property;
 +  HB_Error           error;
 +  HB_UShort          i, j, k, known_classes;
 +
 +  HB_UShort*         classes;
 +  HB_UShort*         cl;
 +
 +  HB_SubClassSet*   scs;
 +  HB_SubClassRule*  sr;
-   gdef = gsub->gdef;
++  hb_ot_layout_t*    layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gsub->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), 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
 +         anything.  It just lets us know whether or not we need to
 +         do any lookup at all.                                     */
 +
 +  error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  if (csf2->MaxContextLength < 1)
 +    return HB_Err_Not_Covered;
 +
 +  if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
 +    return error;
 +
 +  error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
 +                   &classes[0], NULL );
 +  if ( error && error != HB_Err_Not_Covered )
 +    goto End;
 +  known_classes = 0;
 +
 +  scs = &csf2->SubClassSet[classes[0]];
 +  if ( !scs )
 +  {
 +    error = ERR(HB_Err_Invalid_SubTable);
 +    goto End;
 +  }
 +
 +  for ( k = 0; k < scs->SubClassRuleCount; k++ )
 +  {
 +    sr  = &scs->SubClassRule[k];
 +
 +    if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
 +      goto next_subclassrule;
 +
 +    if ( buffer->in_pos + sr->GlyphCount > buffer->in_length )
 +      goto next_subclassrule;                      /* context is too long */
 +
 +    cl   = sr->Class;
 +
 +    /* Start at 1 because [0] is implied */
 +
 +    for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
 +    {
-   HB_GDEFHeader*  gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End;
 +
 +      if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length )
 +        goto next_subclassrule;
 +      j++;
 +      }
 +
 +      if ( i > known_classes )
 +      {
 +      /* Keeps us from having to do this for each rule */
 +
 +      error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End;
 +      known_classes = i;
 +      }
 +
 +      if ( cl[i - 1] != classes[i] )
 +      goto next_subclassrule;
 +    }
 +
 +    error = Do_ContextSubst( gsub, sr->GlyphCount,
 +                           sr->SubstCount, sr->SubstLookupRecord,
 +                           buffer,
 +                           nesting_level );
 +    goto End;
 +
 +  next_subclassrule:
 +    ;
 +  }
 +
 +  error = HB_Err_Not_Covered;
 +
 +End:
 +  FREE( classes );
 +  return error;
 +}
 +
 +
 +static HB_Error  Lookup_ContextSubst3( HB_GSUBHeader*          gsub,
 +                                     HB_ContextSubstFormat3* csf3,
 +                                     HB_Buffer               buffer,
 +                                     HB_UShort                flags,
 +                                     HB_UShort                context_length,
 +                                     int                      nesting_level )
 +{
 +  HB_Error         error;
 +  HB_UShort        index, i, j, property;
 +
 +  HB_Coverage*    c;
-   gdef = gsub->gdef;
++  hb_ot_layout_t*  layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gsub->layout;
 +
-     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
 +    return HB_Err_Not_Covered;
 +
 +  if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
 +    return HB_Err_Not_Covered;         /* context is too long */
 +
 +  c    = csf3->Coverage;
 +
 +  for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
 +  {
-   HB_GDEFHeader*    gdef;
++    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +    {
 +      if ( error && error != HB_Err_Not_Covered )
 +      return error;
 +
 +      if ( j + csf3->GlyphCount - i == (HB_Int)buffer->in_length )
 +      return HB_Err_Not_Covered;
 +      j++;
 +    }
 +
 +    error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
 +    if ( error )
 +      return error;
 +  }
 +
 +  return Do_ContextSubst( gsub, csf3->GlyphCount,
 +                        csf3->SubstCount, csf3->SubstLookupRecord,
 +                        buffer,
 +                        nesting_level );
 +}
 +
 +
 +static HB_Error  Lookup_ContextSubst( HB_GSUBHeader*    gsub,
 +                                    HB_GSUB_SubTable* st,
 +                                    HB_Buffer         buffer,
 +                                    HB_UShort          flags,
 +                                    HB_UShort          context_length,
 +                                    int                nesting_level )
 +{
 +  HB_ContextSubst*  cs = &st->context;
 +
 +  switch ( cs->SubstFormat )
 +  {
 +  case 1:  return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level );
 +  case 2:  return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level );
 +  case 3:  return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level );
 +  default: return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +/* LookupType 6 */
 +
 +/* ChainSubRule */
 +
 +static HB_Error  Load_ChainSubRule( HB_ChainSubRule*  csr,
 +                                  HB_Stream          stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort               n, count;
 +  HB_UShort*              b;
 +  HB_UShort*              i;
 +  HB_UShort*              l;
 +
 +  HB_SubstLookupRecord*  slr;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  csr->BacktrackGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  csr->Backtrack = NULL;
 +
 +  count = csr->BacktrackGlyphCount;
 +
 +  if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) )
 +    return error;
 +
 +  b = csr->Backtrack;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail4;
 +
 +  for ( n = 0; n < count; n++ )
 +    b[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  csr->InputGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  csr->Input = NULL;
 +
 +  count = csr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) )
 +    goto Fail4;
 +
 +  i = csr->Input;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail3;
 +
 +  for ( n = 0; n < count; n++ )
 +    i[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  csr->LookaheadGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  csr->Lookahead = NULL;
 +
 +  count = csr->LookaheadGlyphCount;
 +
 +  if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) )
 +    goto Fail3;
 +
 +  l = csr->Lookahead;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    l[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  csr->SubstCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  csr->SubstLookupRecord = NULL;
 +
 +  count = csr->SubstCount;
 +
 +  if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
 +    goto Fail2;
 +
 +  slr = csr->SubstLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    slr[n].SequenceIndex   = GET_UShort();
 +    slr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( slr );
 +
 +Fail2:
 +  FREE( l );
 +
 +Fail3:
 +  FREE( i );
 +
 +Fail4:
 +  FREE( b );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainSubRule( HB_ChainSubRule*  csr )
 +{
 +  FREE( csr->SubstLookupRecord );
 +  FREE( csr->Lookahead );
 +  FREE( csr->Input );
 +  FREE( csr->Backtrack );
 +}
 +
 +
 +/* ChainSubRuleSet */
 +
 +static HB_Error  Load_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs,
 +                                     HB_Stream             stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort          n = 0, m, count;
 +  HB_UInt           cur_offset, new_offset, base_offset;
 +
 +  HB_ChainSubRule*  csr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = csrs->ChainSubRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  csrs->ChainSubRule = NULL;
 +
 +  if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) )
 +    return error;
 +
 +  csr = csrs->ChainSubRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainSubRule( &csr[m] );
 +
 +  FREE( csr );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs )
 +{
 +  HB_UShort          n, count;
 +
 +  HB_ChainSubRule*  csr;
 +
 +
 +  if ( csrs->ChainSubRule )
 +  {
 +    count = csrs->ChainSubRuleCount;
 +    csr   = csrs->ChainSubRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainSubRule( &csr[n] );
 +
 +    FREE( csr );
 +  }
 +}
 +
 +
 +/* ChainContextSubstFormat1 */
 +
 +static HB_Error  Load_ChainContextSubst1(
 +                 HB_ChainContextSubstFormat1*  ccsf1,
 +                 HB_Stream                      stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort             n = 0, m, count;
 +  HB_UInt              cur_offset, new_offset, base_offset;
 +
 +  HB_ChainSubRuleSet*  csrs;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = ccsf1->ChainSubRuleSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccsf1->ChainSubRuleSet = NULL;
 +
 +  if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) )
 +    goto Fail2;
 +
 +  csrs = ccsf1->ChainSubRuleSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainSubRuleSet( &csrs[m] );
 +
 +  FREE( csrs );
 +
 +Fail2:
 +  _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainContextSubst1( HB_ChainContextSubstFormat1*  ccsf1 )
 +{
 +  HB_UShort             n, count;
 +
 +  HB_ChainSubRuleSet*  csrs;
 +
 +
 +  if ( ccsf1->ChainSubRuleSet )
 +  {
 +    count = ccsf1->ChainSubRuleSetCount;
 +    csrs  = ccsf1->ChainSubRuleSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainSubRuleSet( &csrs[n] );
 +
 +    FREE( csrs );
 +  }
 +
 +  _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
 +}
 +
 +
 +/* ChainSubClassRule */
 +
 +static HB_Error  Load_ChainSubClassRule(
 +                 HB_ChainContextSubstFormat2*  ccsf2,
 +                 HB_ChainSubClassRule*         cscr,
 +                 HB_Stream                      stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort               n, count;
 +
 +  HB_UShort*              b;
 +  HB_UShort*              i;
 +  HB_UShort*              l;
 +  HB_SubstLookupRecord*  slr;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  cscr->BacktrackGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
 +    ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
 +
 +  cscr->Backtrack = NULL;
 +
 +  count = cscr->BacktrackGlyphCount;
 +
 +  if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) )
 +    return error;
 +
 +  b = cscr->Backtrack;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail4;
 +
 +  for ( n = 0; n < count; n++ )
 +    b[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  cscr->InputGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
 +    ccsf2->MaxInputLength = cscr->InputGlyphCount;
 +
 +  cscr->Input = NULL;
 +
 +  count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
 +
 +  if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) )
 +    goto Fail4;
 +
 +  i = cscr->Input;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail3;
 +
 +  for ( n = 0; n < count; n++ )
 +    i[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  cscr->LookaheadGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
 +    ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
 +
 +  cscr->Lookahead = NULL;
 +
 +  count = cscr->LookaheadGlyphCount;
 +
 +  if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) )
 +    goto Fail3;
 +
 +  l = cscr->Lookahead;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail2;
 +
 +  for ( n = 0; n < count; n++ )
 +    l[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  cscr->SubstCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cscr->SubstLookupRecord = NULL;
 +
 +  count = cscr->SubstCount;
 +
 +  if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
 +                  HB_SubstLookupRecord ) )
 +    goto Fail2;
 +
 +  slr = cscr->SubstLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    slr[n].SequenceIndex   = GET_UShort();
 +    slr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( slr );
 +
 +Fail2:
 +  FREE( l );
 +
 +Fail3:
 +  FREE( i );
 +
 +Fail4:
 +  FREE( b );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainSubClassRule( HB_ChainSubClassRule*  cscr )
 +{
 +  FREE( cscr->SubstLookupRecord );
 +  FREE( cscr->Lookahead );
 +  FREE( cscr->Input );
 +  FREE( cscr->Backtrack );
 +}
 +
 +
 +/* SubClassSet */
 +
 +static HB_Error  Load_ChainSubClassSet(
 +                 HB_ChainContextSubstFormat2*  ccsf2,
 +                 HB_ChainSubClassSet*          cscs,
 +                 HB_Stream                      stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort               n = 0, m, count;
 +  HB_UInt                cur_offset, new_offset, base_offset;
 +
 +  HB_ChainSubClassRule*  cscr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = cscs->ChainSubClassRuleCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cscs->ChainSubClassRule = NULL;
 +
 +  if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
 +                  HB_ChainSubClassRule ) )
 +    return error;
 +
 +  cscr = cscs->ChainSubClassRule;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
 +                                         stream ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainSubClassRule( &cscr[m] );
 +
 +  FREE( cscr );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainSubClassSet( HB_ChainSubClassSet*  cscs )
 +{
 +  HB_UShort               n, count;
 +
 +  HB_ChainSubClassRule*  cscr;
 +
 +
 +  if ( cscs->ChainSubClassRule )
 +  {
 +    count = cscs->ChainSubClassRuleCount;
 +    cscr  = cscs->ChainSubClassRule;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainSubClassRule( &cscr[n] );
 +
 +    FREE( cscr );
 +  }
 +}
 +
 +
 +/* ChainContextSubstFormat2 */
 +
 +static HB_Error  Load_ChainContextSubst2(
 +                 HB_ChainContextSubstFormat2*  ccsf2,
 +                 HB_Stream                      stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort              n = 0, m, count;
 +  HB_UInt               cur_offset, new_offset, base_offset;
 +  HB_UInt               backtrack_offset, input_offset, lookahead_offset;
 +
 +  HB_ChainSubClassSet*  cscs;
 +
 +
 +  base_offset = FILE_Pos() - 2;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +  if ( ACCESS_Frame( 8L ) )
 +    goto Fail5;
 +
 +  backtrack_offset = GET_UShort();
 +  input_offset     = GET_UShort();
 +  lookahead_offset = GET_UShort();
 +
 +  /* `ChainSubClassSetCount' is the upper limit for input class values,
 +     thus we read it now to make an additional safety check. No limit
 +     is known or needed for the other two class definitions          */
 +
 +  count = ccsf2->ChainSubClassSetCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
 +                                                     backtrack_offset, base_offset,
 +                                                     stream ) ) != HB_Err_Ok )
 +      goto Fail5;
 +
 +  if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
 +                                                     input_offset, base_offset,
 +                                                     stream ) ) != HB_Err_Ok )
 +      goto Fail4;
 +  if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
 +                                                     lookahead_offset, base_offset,
 +                                                     stream ) ) != HB_Err_Ok )
 +    goto Fail3;
 +
 +  ccsf2->ChainSubClassSet   = NULL;
 +  ccsf2->MaxBacktrackLength = 0;
 +  ccsf2->MaxInputLength     = 0;
 +  ccsf2->MaxLookaheadLength = 0;
 +
 +  if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) )
 +    goto Fail2;
 +
 +  cscs = ccsf2->ChainSubClassSet;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    if ( new_offset != base_offset )      /* not a NULL offset */
 +    {
 +      cur_offset = FILE_Pos();
 +      if ( FILE_Seek( new_offset ) ||
 +         ( error = Load_ChainSubClassSet( ccsf2, &cscs[n],
 +                                          stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +      (void)FILE_Seek( cur_offset );
 +    }
 +    else
 +    {
 +      /* we create a ChainSubClassSet table with no entries */
 +
 +      ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
 +      ccsf2->ChainSubClassSet[n].ChainSubClassRule      = NULL;
 +    }
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_ChainSubClassSet( &cscs[m] );
 +
 +  FREE( cscs );
 +
 +Fail2:
 +  _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
 +
 +Fail3:
 +  _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
 +
 +Fail4:
 +  _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
 +
 +Fail5:
 +  _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainContextSubst2( HB_ChainContextSubstFormat2*  ccsf2 )
 +{
 +  HB_UShort              n, count;
 +
 +  HB_ChainSubClassSet*  cscs;
 +
 +
 +  if ( ccsf2->ChainSubClassSet )
 +  {
 +    count = ccsf2->ChainSubClassSetCount;
 +    cscs  = ccsf2->ChainSubClassSet;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_ChainSubClassSet( &cscs[n] );
 +
 +    FREE( cscs );
 +  }
 +
 +  _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
 +  _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
 +  _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
 +
 +  _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
 +}
 +
 +
 +/* ChainContextSubstFormat3 */
 +
 +static HB_Error  Load_ChainContextSubst3(
 +                 HB_ChainContextSubstFormat3*  ccsf3,
 +                 HB_Stream                      stream )
 +{
 +  HB_Error error;
 +
 +  HB_UShort               n, nb = 0, ni =0, nl = 0, m, count;
 +  HB_UShort               backtrack_count, input_count, lookahead_count;
 +  HB_UInt                cur_offset, new_offset, base_offset;
 +
 +  HB_Coverage*           b;
 +  HB_Coverage*           i;
 +  HB_Coverage*           l;
 +  HB_SubstLookupRecord*  slr;
 +
 +
 +  base_offset = FILE_Pos() - 2L;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  ccsf3->BacktrackGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccsf3->BacktrackCoverage = NULL;
 +
 +  backtrack_count = ccsf3->BacktrackGlyphCount;
 +
 +  if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
 +                  HB_Coverage ) )
 +    return error;
 +
 +  b = ccsf3->BacktrackCoverage;
 +
 +  for ( nb = 0; nb < backtrack_count; nb++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail4;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
 +      goto Fail4;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  ccsf3->InputGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccsf3->InputCoverage = NULL;
 +
 +  input_count = ccsf3->InputGlyphCount;
 +
 +  if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) )
 +    goto Fail4;
 +
 +  i = ccsf3->InputCoverage;
 +
 +  for ( ni = 0; ni < input_count; ni++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail3;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
 +      goto Fail3;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  ccsf3->LookaheadGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccsf3->LookaheadCoverage = NULL;
 +
 +  lookahead_count = ccsf3->LookaheadGlyphCount;
 +
 +  if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
 +                  HB_Coverage ) )
 +    goto Fail3;
 +
 +  l = ccsf3->LookaheadCoverage;
 +
 +  for ( nl = 0; nl < lookahead_count; nl++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
 +      goto Fail2;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  ccsf3->SubstCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ccsf3->SubstLookupRecord = NULL;
 +
 +  count = ccsf3->SubstCount;
 +
 +  if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
 +                  HB_SubstLookupRecord ) )
 +    goto Fail2;
 +
 +  slr = ccsf3->SubstLookupRecord;
 +
 +  if ( ACCESS_Frame( count * 4L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    slr[n].SequenceIndex   = GET_UShort();
 +    slr[n].LookupListIndex = GET_UShort();
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( slr );
 +
 +Fail2:
 +  for ( m = 0; m < nl; m++ )
 +    _HB_OPEN_Free_Coverage( &l[m] );
 +
 +  FREE( l );
 +
 +Fail3:
 +  for ( m = 0; m < ni; m++ )
 +    _HB_OPEN_Free_Coverage( &i[m] );
 +
 +  FREE( i );
 +
 +Fail4:
 +  for ( m = 0; m < nb; m++ )
 +    _HB_OPEN_Free_Coverage( &b[m] );
 +
 +  FREE( b );
 +  return error;
 +}
 +
 +
 +static void  Free_ChainContextSubst3( HB_ChainContextSubstFormat3*  ccsf3 )
 +{
 +  HB_UShort      n, count;
 +
 +  HB_Coverage*  c;
 +
 +
 +  FREE( ccsf3->SubstLookupRecord );
 +
 +  if ( ccsf3->LookaheadCoverage )
 +  {
 +    count = ccsf3->LookaheadGlyphCount;
 +    c     = ccsf3->LookaheadCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +
 +  if ( ccsf3->InputCoverage )
 +  {
 +    count = ccsf3->InputGlyphCount;
 +    c     = ccsf3->InputCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +
 +  if ( ccsf3->BacktrackCoverage )
 +  {
 +    count = ccsf3->BacktrackGlyphCount;
 +    c     = ccsf3->BacktrackCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +}
 +
 +
 +/* ChainContextSubst */
 +
 +static HB_Error  Load_ChainContextSubst( HB_GSUB_SubTable* st,
 +                                       HB_Stream         stream )
 +{
 +  HB_Error error;
 +  HB_ChainContextSubst*  ccs = &st->chain;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  ccs->SubstFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  switch ( ccs->SubstFormat ) {
 +    case 1:  return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream );
 +    case 2:  return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream );
 +    case 3:  return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream );
 +    default: return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +static void  Free_ChainContextSubst( HB_GSUB_SubTable* st )
 +{
 +  HB_ChainContextSubst*  ccs = &st->chain;
 +
 +  switch ( ccs->SubstFormat ) {
 +    case 1:  Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break;
 +    case 2:  Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break;
 +    case 3:  Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break;
 +    default:                                                    break;
 +  }
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
 +                                          HB_ChainContextSubstFormat1* ccsf1,
 +                                          HB_Buffer                    buffer,
 +                                          HB_UShort                     flags,
 +                                          HB_UShort                     context_length,
 +                                          int                           nesting_level )
 +{
 +  HB_UShort          index, property;
 +  HB_UShort          i, j, k, num_csr;
 +  HB_UShort          bgc, igc, lgc;
 +  HB_Error           error;
 +
 +  HB_ChainSubRule*  csr;
 +  HB_ChainSubRule   curr_csr;
-   gdef = gsub->gdef;
++  hb_ot_layout_t*    layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gsub->layout;
 +
-       while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  csr     = ccsf1->ChainSubRuleSet[index].ChainSubRule;
 +  num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
 +
 +  for ( k = 0; k < num_csr; k++ )
 +  {
 +    curr_csr = csr[k];
 +    bgc      = curr_csr.BacktrackGlyphCount;
 +    igc      = curr_csr.InputGlyphCount;
 +    lgc      = curr_csr.LookaheadGlyphCount;
 +
 +    if ( context_length != 0xFFFF && context_length < igc )
 +      goto next_chainsubrule;
 +
 +    /* check whether context is too long; it is a first guess only */
 +
 +    if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
 +      goto next_chainsubrule;
 +
 +    if ( bgc )
 +    {
 +      /* since we don't know in advance the number of glyphs to inspect,
 +       we search backwards for matches in the backtrack glyph array    */
 +
 +      for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
 +      {
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++      while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
 +      {
 +        if ( error && error != HB_Err_Not_Covered )
 +          return error;
 +
 +        if ( j + 1 == bgc - i )
 +          goto next_chainsubrule;
 +        j--;
 +      }
 +
 +      /* In OpenType 1.3, it is undefined whether the offsets of
 +         backtrack glyphs is in logical order or not.  Version 1.4
 +         will clarify this:
 +
 +           Logical order -      a  b  c  d  e  f  g  h  i  j
 +                                            i
 +           Input offsets -                  0  1
 +           Backtrack offsets -  3  2  1  0
 +           Lookahead offsets -                    0  1  2  3           */
 +
 +      if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] )
 +        goto next_chainsubrule;
 +      }
 +    }
 +
 +    /* Start at 1 because [0] is implied */
 +
 +    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;
 +
 +      if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
 +        goto next_chainsubrule;
 +      j++;
 +      }
 +
 +      if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] )
 +        goto next_chainsubrule;
 +    }
 +
 +    /* we are starting to check for lookahead glyphs right after the
 +       last context glyph                                            */
 +
 +    for ( i = 0; i < lgc; i++, j++ )
 +    {
-   HB_GDEFHeader*        gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        return error;
 +
 +      if ( j + lgc - i == (HB_Int)buffer->in_length )
 +        goto next_chainsubrule;
 +      j++;
 +      }
 +
 +      if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] )
 +      goto next_chainsubrule;
 +    }
 +
 +    return Do_ContextSubst( gsub, igc,
 +                          curr_csr.SubstCount,
 +                          curr_csr.SubstLookupRecord,
 +                          buffer,
 +                          nesting_level );
 +
 +  next_chainsubrule:
 +    ;
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
 +                                          HB_ChainContextSubstFormat2* ccsf2,
 +                                          HB_Buffer                    buffer,
 +                                          HB_UShort                     flags,
 +                                          HB_UShort                     context_length,
 +                                          int                           nesting_level )
 +{
 +  HB_UShort              index, property;
 +  HB_Error               error;
 +  HB_UShort              i, j, k;
 +  HB_UShort              bgc, igc, lgc;
 +  HB_UShort              known_backtrack_classes,
 +                       known_input_classes,
 +                       known_lookahead_classes;
 +
 +  HB_UShort*             backtrack_classes;
 +  HB_UShort*             input_classes;
 +  HB_UShort*             lookahead_classes;
 +
 +  HB_UShort*             bc;
 +  HB_UShort*             ic;
 +  HB_UShort*             lc;
 +
 +  HB_ChainSubClassSet*  cscs;
 +  HB_ChainSubClassRule  ccsr;
-   gdef = gsub->gdef;
++  hb_ot_layout_t*        layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gsub->layout;
 +
-       while ( CHECK_Property( gdef, OUT_ITEM( j ), 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
 +         anything.  It just lets us know whether or not we need to
 +         do any lookup at all.                                     */
 +
 +  error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index );
 +  if ( error )
 +    return error;
 +
 +  if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) )
 +    return error;
 +  known_backtrack_classes = 0;
 +
 +  if (ccsf2->MaxInputLength < 1)
 +    return HB_Err_Not_Covered;
 +
 +  if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
 +    goto End3;
 +  known_input_classes = 1;
 +
 +  if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) )
 +    goto End2;
 +  known_lookahead_classes = 0;
 +
 +  error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
 +                   &input_classes[0], NULL );
 +  if ( error && error != HB_Err_Not_Covered )
 +    goto End1;
 +
 +  cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
 +  if ( !cscs )
 +  {
 +    error = ERR(HB_Err_Invalid_SubTable);
 +    goto End1;
 +  }
 +
 +  for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
 +  {
 +    ccsr = cscs->ChainSubClassRule[k];
 +    bgc  = ccsr.BacktrackGlyphCount;
 +    igc  = ccsr.InputGlyphCount;
 +    lgc  = ccsr.LookaheadGlyphCount;
 +
 +    if ( context_length != 0xFFFF && context_length < igc )
 +      goto next_chainsubclassrule;
 +
 +    /* check whether context is too long; it is a first guess only */
 +
 +    if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
 +      goto next_chainsubclassrule;
 +
 +    if ( bgc )
 +    {
 +      /* Since we don't know in advance the number of glyphs to inspect,
 +       we search backwards for matches in the backtrack glyph array.
 +       Note that `known_backtrack_classes' starts at index 0.         */
 +
 +      bc       = ccsr.Backtrack;
 +
 +      for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
 +      {
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++      while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
 +      {
 +        if ( error && error != HB_Err_Not_Covered )
 +          goto End1;
 +
 +        if ( j + 1 == bgc - i )
 +          goto next_chainsubclassrule;
 +        j--;
 +      }
 +
 +      if ( i >= known_backtrack_classes )
 +      {
 +        /* Keeps us from having to do this for each rule */
 +
 +        error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ),
 +                           &backtrack_classes[i], NULL );
 +        if ( error && error != HB_Err_Not_Covered )
 +          goto End1;
 +        known_backtrack_classes = i;
 +      }
 +
 +      if ( bc[i] != backtrack_classes[i] )
 +        goto next_chainsubclassrule;
 +      }
 +    }
 +
 +    ic       = ccsr.Input;
 +
 +    /* Start at 1 because [0] is implied */
 +
 +    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;
 +
 +      if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
 +        goto next_chainsubclassrule;
 +      j++;
 +      }
 +
 +      if ( i >= known_input_classes )
 +      {
 +      error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ),
 +                         &input_classes[i], NULL );
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End1;
 +      known_input_classes = i;
 +      }
 +
 +      if ( ic[i - 1] != input_classes[i] )
 +      goto next_chainsubclassrule;
 +    }
 +
 +    /* we are starting to check for lookahead glyphs right after the
 +       last context glyph                                            */
 +
 +    lc       = ccsr.Lookahead;
 +
 +    for ( i = 0; i < lgc; i++, j++ )
 +    {
-   HB_GDEFHeader*  gdef;
++      while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End1;
 +
 +      if ( j + lgc - i == (HB_Int)buffer->in_length )
 +        goto next_chainsubclassrule;
 +      j++;
 +      }
 +
 +      if ( i >= known_lookahead_classes )
 +      {
 +      error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ),
 +                         &lookahead_classes[i], NULL );
 +      if ( error && error != HB_Err_Not_Covered )
 +        goto End1;
 +      known_lookahead_classes = i;
 +      }
 +
 +      if ( lc[i] != lookahead_classes[i] )
 +      goto next_chainsubclassrule;
 +    }
 +
 +    error = Do_ContextSubst( gsub, igc,
 +                           ccsr.SubstCount,
 +                           ccsr.SubstLookupRecord,
 +                           buffer,
 +                           nesting_level );
 +    goto End1;
 +
 +  next_chainsubclassrule:
 +    ;
 +  }
 +
 +  error = HB_Err_Not_Covered;
 +
 +End1:
 +  FREE( lookahead_classes );
 +
 +End2:
 +  FREE( input_classes );
 +
 +End3:
 +  FREE( backtrack_classes );
 +  return error;
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
 +                                          HB_ChainContextSubstFormat3* ccsf3,
 +                                          HB_Buffer                    buffer,
 +                                          HB_UShort                     flags,
 +                                          HB_UShort                     context_length,
 +                                          int                           nesting_level )
 +{
 +  HB_UShort        index, i, j, property;
 +  HB_UShort        bgc, igc, lgc;
 +  HB_Error         error;
 +
 +  HB_Coverage*    bc;
 +  HB_Coverage*    ic;
 +  HB_Coverage*    lc;
-   gdef = gsub->gdef;
++  hb_ot_layout_t*  layout;
 +
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gsub->layout;
 +
-       while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  bgc = ccsf3->BacktrackGlyphCount;
 +  igc = ccsf3->InputGlyphCount;
 +  lgc = ccsf3->LookaheadGlyphCount;
 +
 +  if ( context_length != 0xFFFF && context_length < igc )
 +    return HB_Err_Not_Covered;
 +
 +  /* check whether context is too long; it is a first guess only */
 +
 +  if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
 +    return HB_Err_Not_Covered;
 +
 +  if ( bgc )
 +  {
 +    /* Since we don't know in advance the number of glyphs to inspect,
 +       we search backwards for matches in the backtrack glyph array    */
 +
 +    bc       = ccsf3->BacktrackCoverage;
 +
 +    for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
 +    {
-     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++      while ( CHECK_Property( layout, OUT_ITEM( j ), flags, &property ) )
 +      {
 +      if ( error && error != HB_Err_Not_Covered )
 +        return error;
 +
 +      if ( j + 1 == bgc - i )
 +        return HB_Err_Not_Covered;
 +      j--;
 +      }
 +
 +      error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index );
 +      if ( error )
 +      return error;
 +    }
 +  }
 +
 +  ic       = ccsf3->InputCoverage;
 +
 +  for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
 +  {
 +    /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
-     while ( 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;
 +
 +      if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
 +      return HB_Err_Not_Covered;
 +      j++;
 +    }
 +
 +    error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
 +    if ( error )
 +      return error;
 +  }
 +
 +  /* we are starting for lookahead glyphs right after the last context
 +     glyph                                                             */
 +
 +  lc       = ccsf3->LookaheadCoverage;
 +
 +  for ( i = 0; i < lgc; i++, j++ )
 +  {
-   HB_GDEFHeader*  gdef;
++    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +    {
 +      if ( error && error != HB_Err_Not_Covered )
 +      return error;
 +
 +      if ( j + lgc - i == (HB_Int)buffer->in_length )
 +      return HB_Err_Not_Covered;
 +      j++;
 +    }
 +
 +    error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
 +    if ( error )
 +      return error;
 +  }
 +
 +  return Do_ContextSubst( gsub, igc,
 +                        ccsf3->SubstCount,
 +                        ccsf3->SubstLookupRecord,
 +                        buffer,
 +                        nesting_level );
 +}
 +
 +
 +static HB_Error  Lookup_ChainContextSubst( HB_GSUBHeader*    gsub,
 +                                         HB_GSUB_SubTable* st,
 +                                         HB_Buffer         buffer,
 +                                         HB_UShort          flags,
 +                                         HB_UShort          context_length,
 +                                         int                nesting_level )
 +{
 +  HB_ChainContextSubst*  ccs = &st->chain;
 +
 +  switch ( ccs->SubstFormat ) {
 +    case 1:  return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level );
 +    case 2:  return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level );
 +    case 3:  return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level );
 +    default: return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +}
 +
 +
 +static HB_Error  Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
 +                                              HB_Stream         stream )
 +{
 +  HB_Error error;
 +  HB_ReverseChainContextSubst*  rccs = &st->reverse;
 +
 +  HB_UShort               m, count;
 +
 +  HB_UShort               nb = 0, nl = 0, n;
 +  HB_UShort               backtrack_count, lookahead_count;
 +  HB_UInt                cur_offset, new_offset, base_offset;
 +
 +  HB_Coverage*           b;
 +  HB_Coverage*           l;
 +  HB_UShort*              sub;
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  rccs->SubstFormat = GET_UShort();
 +
 +  if ( rccs->SubstFormat != 1 )
 +    return ERR(HB_Err_Invalid_SubTable_Format);
 +
 +  FORGET_Frame();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  cur_offset = FILE_Pos();
 +  if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != HB_Err_Ok )
 +    return error;
 +  (void)FILE_Seek( cur_offset );
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail4;
 +
 +  rccs->BacktrackGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  rccs->BacktrackCoverage = NULL;
 +
 +  backtrack_count = rccs->BacktrackGlyphCount;
 +
 +  if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count,
 +                  HB_Coverage ) )
 +    goto Fail4;
 +
 +  b = rccs->BacktrackCoverage;
 +
 +  for ( nb = 0; nb < backtrack_count; nb++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail3;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
 +      goto Fail3;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail3;
 +
 +  rccs->LookaheadGlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  rccs->LookaheadCoverage = NULL;
 +
 +  lookahead_count = rccs->LookaheadGlyphCount;
 +
 +  if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count,
 +                  HB_Coverage ) )
 +    goto Fail3;
 +
 +  l = rccs->LookaheadCoverage;
 +
 +  for ( nl = 0; nl < lookahead_count; nl++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail2;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
 +      goto Fail2;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  rccs->GlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  rccs->Substitute = NULL;
 +
 +  count = rccs->GlyphCount;
 +
 +  if ( ALLOC_ARRAY( rccs->Substitute, count,
 +                  HB_UShort ) )
 +    goto Fail2;
 +
 +  sub = rccs->Substitute;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail1;
 +
 +  for ( n = 0; n < count; n++ )
 +    sub[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( sub );
 +
 +Fail2:
 +  for ( m = 0; m < nl; m++ )
 +    _HB_OPEN_Free_Coverage( &l[m] );
 +
 +  FREE( l );
 +
 +Fail3:
 +  for ( m = 0; m < nb; m++ )
 +    _HB_OPEN_Free_Coverage( &b[m] );
 +
 +  FREE( b );
 +
 +Fail4:
 +  _HB_OPEN_Free_Coverage( &rccs->Coverage );
 +  return error;
 +}
 +
 +
 +static void  Free_ReverseChainContextSubst( HB_GSUB_SubTable* st )
 +{
 +  HB_UShort      n, count;
 +  HB_ReverseChainContextSubst*  rccs = &st->reverse;
 +
 +  HB_Coverage*  c;
 +
 +  _HB_OPEN_Free_Coverage( &rccs->Coverage );
 +
 +  if ( rccs->LookaheadCoverage )
 +  {
 +    count = rccs->LookaheadGlyphCount;
 +    c     = rccs->LookaheadCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +
 +  if ( rccs->BacktrackCoverage )
 +  {
 +    count = rccs->BacktrackGlyphCount;
 +    c     = rccs->BacktrackCoverage;
 +
 +    for ( n = 0; n < count; n++ )
 +      _HB_OPEN_Free_Coverage( &c[n] );
 +
 +    FREE( c );
 +  }
 +
 +  FREE ( rccs->Substitute );
 +}
 +
 +
 +static HB_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
 +                                                HB_GSUB_SubTable* st,
 +                                                HB_Buffer         buffer,
 +                                                HB_UShort         flags,
 +                                                HB_UShort         context_length,
 +                                                int               nesting_level )
 +{
 +  HB_UShort        index, input_index, i, j, property;
 +  HB_UShort        bgc, lgc;
 +  HB_Error         error;
 +
 +  HB_ReverseChainContextSubst*  rccs = &st->reverse;
 +  HB_Coverage*    bc;
 +  HB_Coverage*    lc;
-   gdef = gsub->gdef;
++  hb_ot_layout_t*  layout;
 +
 +  if ( nesting_level != 1 || context_length != 0xFFFF )
 +    return HB_Err_Not_Covered;
 +
-   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
++  layout = gsub->layout;
 +
-       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
++  if ( CHECK_Property( layout, IN_CURITEM(), flags, &property ) )
 +    return error;
 +
 +  bgc = rccs->BacktrackGlyphCount;
 +  lgc = rccs->LookaheadGlyphCount;
 +
 +  /* check whether context is too long; it is a first guess only */
 +
 +  if ( bgc > buffer->in_pos || buffer->in_pos + 1 + lgc > buffer->in_length )
 +    return HB_Err_Not_Covered;
 +
 +  if ( bgc )
 +  {
 +    /* Since we don't know in advance the number of glyphs to inspect,
 +       we search backwards for matches in the backtrack glyph array    */
 +
 +    bc       = rccs->BacktrackCoverage;
 +
 +    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;
 +
 +      if ( j + 1 == bgc - i )
 +        return HB_Err_Not_Covered;
 +      j--;
 +      }
 +
 +      error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
 +      if ( error )
 +      return error;
 +    }
 +  }
 +
 +  j = buffer->in_pos;
 +
 +  error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
 +  if ( error )
 +      return error;
 +
 +  lc       = rccs->LookaheadCoverage;
 +
 +  for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ )
 +  {
++    while ( CHECK_Property( layout, IN_ITEM( j ), flags, &property ) )
 +    {
 +      if ( error && error != HB_Err_Not_Covered )
 +      return error;
 +
 +      if ( j + lgc - i == (HB_Int)buffer->in_length )
 +      return HB_Err_Not_Covered;
 +      j++;
 +    }
 +
 +    error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
 +    if ( error )
 +      return error;
 +  }
 +
 +  IN_CURGLYPH() = rccs->Substitute[input_index];
 +  buffer->in_pos--; /* Reverse! */
 +
 +  return error;
 +}
 +
 +
 +
 +/***********
 + * GSUB API
 + ***********/
 +
 +
 +
 +HB_Error  HB_GSUB_Select_Script( HB_GSUBHeader*  gsub,
 +                               HB_UInt         script_tag,
 +                               HB_UShort*       script_index )
 +{
 +  HB_UShort          n;
 +
 +  HB_ScriptList*    sl;
 +  HB_ScriptRecord*  sr;
 +
 +
 +  if ( !gsub || !script_index )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gsub->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  for ( n = 0; n < sl->ScriptCount; n++ )
 +    if ( script_tag == sr[n].ScriptTag )
 +    {
 +      *script_index = n;
 +
 +      return HB_Err_Ok;
 +    }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +
 +HB_Error  HB_GSUB_Select_Language( HB_GSUBHeader*  gsub,
 +                                 HB_UInt         language_tag,
 +                                 HB_UShort        script_index,
 +                                 HB_UShort*       language_index,
 +                                 HB_UShort*       req_feature_index )
 +{
 +  HB_UShort           n;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +
 +
 +  if ( !gsub || !language_index || !req_feature_index )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gsub->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  for ( n = 0; n < s->LangSysCount; n++ )
 +    if ( language_tag == lsr[n].LangSysTag )
 +    {
 +      *language_index = n;
 +      *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
 +
 +      return HB_Err_Ok;
 +    }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +/* selecting 0xFFFF for language_index asks for the values of the
 +   default language (DefaultLangSys)                              */
 +
 +
 +HB_Error  HB_GSUB_Select_Feature( HB_GSUBHeader*  gsub,
 +                                HB_UInt         feature_tag,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UShort*       feature_index )
 +{
 +  HB_UShort           n;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +  HB_LangSys*        ls;
 +  HB_UShort*          fi;
 +
 +  HB_FeatureList*    fl;
 +  HB_FeatureRecord*  fr;
 +
 +
 +  if ( !gsub || !feature_index )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gsub->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  fl = &gsub->FeatureList;
 +  fr = fl->FeatureRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  if ( language_index == 0xFFFF )
 +    ls = &s->DefaultLangSys;
 +  else
 +  {
 +    if ( language_index >= s->LangSysCount )
 +      return ERR(HB_Err_Invalid_Argument);
 +
 +    ls = &lsr[language_index].LangSys;
 +  }
 +
 +  fi = ls->FeatureIndex;
 +
 +  for ( n = 0; n < ls->FeatureCount; n++ )
 +  {
 +    if ( fi[n] >= fl->FeatureCount )
 +      return ERR(HB_Err_Invalid_SubTable_Format);
 +
 +    if ( feature_tag == fr[fi[n]].FeatureTag )
 +    {
 +      *feature_index = fi[n];
 +
 +      return HB_Err_Ok;
 +    }
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +/* The next three functions return a null-terminated list */
 +
 +
 +HB_Error  HB_GSUB_Query_Scripts( HB_GSUBHeader*  gsub,
 +                               HB_UInt**       script_tag_list )
 +{
 +  HB_UShort          n;
 +  HB_Error           error;
 +  HB_UInt*          stl;
 +
 +  HB_ScriptList*    sl;
 +  HB_ScriptRecord*  sr;
 +
 +
 +  if ( !gsub || !script_tag_list )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gsub->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
 +    return error;
 +
 +  for ( n = 0; n < sl->ScriptCount; n++ )
 +    stl[n] = sr[n].ScriptTag;
 +  stl[n] = 0;
 +
 +  *script_tag_list = stl;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +
 +HB_Error  HB_GSUB_Query_Languages( HB_GSUBHeader*  gsub,
 +                                 HB_UShort        script_index,
 +                                 HB_UInt**       language_tag_list )
 +{
 +  HB_UShort           n;
 +  HB_Error            error;
 +  HB_UInt*           ltl;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +
 +
 +  if ( !gsub || !language_tag_list )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gsub->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
 +    return error;
 +
 +  for ( n = 0; n < s->LangSysCount; n++ )
 +    ltl[n] = lsr[n].LangSysTag;
 +  ltl[n] = 0;
 +
 +  *language_tag_list = ltl;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* selecting 0xFFFF for language_index asks for the values of the
 +   default language (DefaultLangSys)                              */
 +
 +
 +HB_Error  HB_GSUB_Query_Features( HB_GSUBHeader*  gsub,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UInt**       feature_tag_list )
 +{
 +  HB_UShort           n;
 +  HB_Error            error;
 +  HB_UInt*           ftl;
 +
 +  HB_ScriptList*     sl;
 +  HB_ScriptRecord*   sr;
 +  HB_ScriptTable*         s;
 +  HB_LangSysRecord*  lsr;
 +  HB_LangSys*        ls;
 +  HB_UShort*          fi;
 +
 +  HB_FeatureList*    fl;
 +  HB_FeatureRecord*  fr;
 +
 +
 +  if ( !gsub || !feature_tag_list )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  sl = &gsub->ScriptList;
 +  sr = sl->ScriptRecord;
 +
 +  fl = &gsub->FeatureList;
 +  fr = fl->FeatureRecord;
 +
 +  if ( script_index >= sl->ScriptCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  s   = &sr[script_index].Script;
 +  lsr = s->LangSysRecord;
 +
 +  if ( language_index == 0xFFFF )
 +    ls = &s->DefaultLangSys;
 +  else
 +  {
 +    if ( language_index >= s->LangSysCount )
 +      return ERR(HB_Err_Invalid_Argument);
 +
 +    ls = &lsr[language_index].LangSys;
 +  }
 +
 +  fi = ls->FeatureIndex;
 +
 +  if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
 +    return error;
 +
 +  for ( n = 0; n < ls->FeatureCount; n++ )
 +  {
 +    if ( fi[n] >= fl->FeatureCount )
 +    {
 +      FREE( ftl );
 +      return ERR(HB_Err_Invalid_SubTable_Format);
 +    }
 +    ftl[n] = fr[fi[n]].FeatureTag;
 +  }
 +  ftl[n] = 0;
 +
 +  *feature_tag_list = ftl;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +/* Do an individual subtable lookup.  Returns HB_Err_Ok if substitution
 +   has been done, or HB_Err_Not_Covered if not.                        */
 +static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
 +                                     HB_UShort      lookup_index,
 +                                     HB_Buffer      buffer,
 +                                     HB_UShort      context_length,
 +                                     int            nesting_level )
 +{
 +  HB_Error               error = HB_Err_Not_Covered;
 +  HB_UShort              i, flags, lookup_count;
 +  HB_Lookup*             lo;
 +  int                    lookup_type;
 +
 +  nesting_level++;
 +
 +  if ( nesting_level > HB_MAX_NESTING_LEVEL )
 +    return ERR(HB_Err_Not_Covered); /* ERR() call intended */
 +
 +  lookup_count = gsub->LookupList.LookupCount;
 +  if (lookup_index >= lookup_count)
 +    return error;
 +
 +  lo    = &gsub->LookupList.Lookup[lookup_index];
 +  flags = lo->LookupFlag;
 +  lookup_type = lo->LookupType;
 +
 +  for ( i = 0; i < lo->SubTableCount; i++ )
 +  {
 +    HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub;
 +
 +    switch (lookup_type) {
 +      case HB_GSUB_LOOKUP_SINGLE:
 +      error = Lookup_SingleSubst              ( gsub, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GSUB_LOOKUP_MULTIPLE:
 +      error = Lookup_MultipleSubst            ( gsub, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GSUB_LOOKUP_ALTERNATE:
 +      error = Lookup_AlternateSubst           ( gsub, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GSUB_LOOKUP_LIGATURE:
 +      error = Lookup_LigatureSubst            ( gsub, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GSUB_LOOKUP_CONTEXT:
 +      error = Lookup_ContextSubst             ( gsub, st, buffer, flags, context_length, nesting_level ); break;
 +      case HB_GSUB_LOOKUP_CHAIN:
 +      error = Lookup_ChainContextSubst        ( gsub, st, buffer, flags, context_length, nesting_level ); break;
 +    /*case HB_GSUB_LOOKUP_EXTENSION:
 +      error = Lookup_ExtensionSubst           ( gsub, st, buffer, flags, context_length, nesting_level ); break;*/
 +      case HB_GSUB_LOOKUP_REVERSE_CHAIN:
 +      error = Lookup_ReverseChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
 +      default:
 +      error = HB_Err_Not_Covered;
 +    };
 +
 +    /* Check whether we have a successful substitution or an error other
 +       than HB_Err_Not_Covered                                          */
 +    if ( error != HB_Err_Not_Covered )
 +      return error;
 +  }
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +HB_INTERNAL HB_Error
 +_HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
 +                      HB_Stream         stream,
 +                      HB_UShort         lookup_type )
 +{
 +  switch (lookup_type) {
 +    case HB_GSUB_LOOKUP_SINGLE:               return Load_SingleSubst                 ( st, stream );
 +    case HB_GSUB_LOOKUP_MULTIPLE:     return Load_MultipleSubst               ( st, stream );
 +    case HB_GSUB_LOOKUP_ALTERNATE:    return Load_AlternateSubst              ( st, stream );
 +    case HB_GSUB_LOOKUP_LIGATURE:     return Load_LigatureSubst               ( st, stream );
 +    case HB_GSUB_LOOKUP_CONTEXT:      return Load_ContextSubst                ( st, stream );
 +    case HB_GSUB_LOOKUP_CHAIN:                return Load_ChainContextSubst           ( st, stream );
 +  /*case HB_GSUB_LOOKUP_EXTENSION:    return Load_ExtensionSubst              ( st, stream );*/
 +    case HB_GSUB_LOOKUP_REVERSE_CHAIN:        return Load_ReverseChainContextSubst    ( st, stream );
 +    default:                          return ERR(HB_Err_Invalid_SubTable_Format);
 +  };
 +}
 +
 +
 +HB_INTERNAL void
 +_HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
 +                      HB_UShort         lookup_type )
 +{
 +  switch ( lookup_type ) {
 +    case HB_GSUB_LOOKUP_SINGLE:               Free_SingleSubst                ( st ); return;
 +    case HB_GSUB_LOOKUP_MULTIPLE:     Free_MultipleSubst              ( st ); return;
 +    case HB_GSUB_LOOKUP_ALTERNATE:    Free_AlternateSubst             ( st ); return;
 +    case HB_GSUB_LOOKUP_LIGATURE:     Free_LigatureSubst              ( st ); return;
 +    case HB_GSUB_LOOKUP_CONTEXT:      Free_ContextSubst               ( st ); return;
 +    case HB_GSUB_LOOKUP_CHAIN:                Free_ChainContextSubst          ( st ); return;
 +  /*case HB_GSUB_LOOKUP_EXTENSION:    Free_ExtensionSubst             ( st ); return;*/
 +    case HB_GSUB_LOOKUP_REVERSE_CHAIN:        Free_ReverseChainContextSubst   ( st ); return;
 +    default:                                                                  return;
 +  };
 +}
 +
 +
 +
 +/* apply one lookup to the input string object */
 +
 +static HB_Error  GSUB_Do_String_Lookup( HB_GSUBHeader* gsub,
 +                                      HB_UShort      lookup_index,
 +                                      HB_Buffer      buffer )
 +{
 +  HB_Error  error, retError = HB_Err_Not_Covered;
 +
 +  HB_UInt*  properties  = gsub->LookupList.Properties;
 +  int       lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType;
 +
 +  const int       nesting_level = 0;
 +  /* 0xFFFF indicates that we don't have a context length yet */
 +  const HB_UShort context_length = 0xFFFF;
 +
 +  switch (lookup_type) {
 +
 +    case HB_GSUB_LOOKUP_SINGLE:
 +    case HB_GSUB_LOOKUP_MULTIPLE:
 +    case HB_GSUB_LOOKUP_ALTERNATE:
 +    case HB_GSUB_LOOKUP_LIGATURE:
 +    case HB_GSUB_LOOKUP_CONTEXT:
 +    case HB_GSUB_LOOKUP_CHAIN:
 +      /* in/out forward substitution (implemented lazy) */
 +
 +      _hb_buffer_clear_output ( buffer );
 +      buffer->in_pos = 0;
 +      while ( buffer->in_pos < buffer->in_length )
 +      {
 +      if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
 +      {
 +        error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
 +        if ( error )
 +        {
 +          if ( error != HB_Err_Not_Covered )
 +            return error;
 +        }
 +        else
 +          retError = error;
 +      }
 +      else
 +        error = HB_Err_Not_Covered;
 +
 +      if ( error == HB_Err_Not_Covered )
 +        if ( COPY_Glyph ( buffer ) )
 +          return error;
 +      }
 +      /* we shouldn't swap if error occurred.
 +       *
 +       * also don't swap if nothing changed (ie HB_Err_Not_Covered).
 +       * shouldn't matter in that case though.
 +       */
 +      if ( retError == HB_Err_Ok )
 +      _hb_buffer_swap( buffer );
 +
 +      return retError;
 +
 +    case HB_GSUB_LOOKUP_REVERSE_CHAIN:
 +      /* in-place backward substitution */
 +
 +      buffer->in_pos = buffer->in_length - 1;
 +      do
 +      {
 +      if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
 +      {
 +        error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
 +        if ( error )
 +        {
 +          if ( error != HB_Err_Not_Covered )
 +            return error;
 +        }
 +        else
 +          retError = error;
 +      }
 +      else
 +        error = HB_Err_Not_Covered;
 +
 +      if ( error == HB_Err_Not_Covered )
 +        buffer->in_pos--;
 +      }
 +      while ((HB_Int) buffer->in_pos >= 0);
 +
 +      return retError;
 +
 +  /*case HB_GSUB_LOOKUP_EXTENSION:*/
 +    default:
 +      return retError;
 +  };
 +}
 +
 +
 +HB_Error  HB_GSUB_Add_Feature( HB_GSUBHeader*  gsub,
 +                             HB_UShort        feature_index,
 +                             HB_UInt          property )
 +{
 +  HB_UShort    i;
 +
 +  HB_Feature  feature;
 +  HB_UInt*     properties;
 +  HB_UShort*   index;
 +  HB_UShort    lookup_count;
 +
 +  /* Each feature can only be added once */
 +
 +  if ( !gsub ||
 +       feature_index >= gsub->FeatureList.FeatureCount ||
 +       gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index;
 +
 +  properties = gsub->LookupList.Properties;
 +
 +  feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
 +  index   = feature.LookupListIndex;
 +  lookup_count = gsub->LookupList.LookupCount;
 +
 +  for ( i = 0; i < feature.LookupListCount; i++ )
 +  {
 +    HB_UShort lookup_index = index[i];
 +    if (lookup_index < lookup_count)
 +      properties[lookup_index] |= property;
 +  }
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +
 +HB_Error  HB_GSUB_Clear_Features( HB_GSUBHeader*  gsub )
 +{
 +  HB_UShort i;
 +
 +  HB_UInt*  properties;
 +
 +
 +  if ( !gsub )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  gsub->FeatureList.ApplyCount = 0;
 +
 +  properties = gsub->LookupList.Properties;
 +
 +  for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
 +    properties[i] = 0;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +
 +HB_Error  HB_GSUB_Register_Alternate_Function( HB_GSUBHeader*  gsub,
 +                                             HB_AltFunction  altfunc,
 +                                             void*            data )
 +{
 +  if ( !gsub )
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  gsub->altfunc = altfunc;
 +  gsub->data    = data;
 +
 +  return HB_Err_Ok;
 +}
 +
 +/* returns error if one happened, otherwise returns HB_Err_Not_Covered if no
 + * feature were applied, or HB_Err_Ok otherwise.
 + */
 +HB_Error  HB_GSUB_Apply_String( HB_GSUBHeader*   gsub,
 +                              HB_Buffer        buffer )
 +{
 +  HB_Error          error, retError = HB_Err_Not_Covered;
 +  int               i, j, lookup_count, num_features;
 +
 +  if ( !gsub ||
 +       !buffer)
 +    return ERR(HB_Err_Invalid_Argument);
 +
 +  if ( buffer->in_length == 0 )
 +    return retError;
 +
 +  lookup_count = gsub->LookupList.LookupCount;
 +  num_features = gsub->FeatureList.ApplyCount;
 +
 +  for ( i = 0; i < num_features; i++)
 +  {
 +    HB_UShort  feature_index = gsub->FeatureList.ApplyOrder[i];
 +    HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
 +
 +    for ( j = 0; j < feature.LookupListCount; j++ )
 +    {
 +      HB_UShort         lookup_index = feature.LookupListIndex[j];
 +
 +      /* Skip nonexistant lookups */
 +      if (lookup_index >= lookup_count)
 +       continue;
 +
 +      error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
 +      if ( error )
 +      {
 +      if ( error != HB_Err_Not_Covered )
 +        return error;
 +      }
 +      else
 +      retError = error;
 +    }
 +  }
 +
 +  error = retError;
 +
 +  return error;
 +}
 +
 +
 +/* END */
index 3d6cfa1,0000000..b1e78ce
mode 100644,000000..100644
--- /dev/null
@@@ -1,140 -1,0 +1,140 @@@
-   HB_GDEFHeader*  gdef;
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2006  Behdad Esfahbod
 + *
 + *  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.
 + */
 +
 +#ifndef HARFBUZZ_GSUB_H
 +#define HARFBUZZ_GSUB_H
 +
 +#include "harfbuzz-gdef.h"
 +#include "harfbuzz-buffer.h"
 +
 +HB_BEGIN_HEADER
 +
 +
 +/* Lookup types for glyph substitution */
 +
 +#define HB_GSUB_LOOKUP_SINGLE        1
 +#define HB_GSUB_LOOKUP_MULTIPLE      2
 +#define HB_GSUB_LOOKUP_ALTERNATE     3
 +#define HB_GSUB_LOOKUP_LIGATURE      4
 +#define HB_GSUB_LOOKUP_CONTEXT       5
 +#define HB_GSUB_LOOKUP_CHAIN         6
 +#define HB_GSUB_LOOKUP_EXTENSION     7
 +#define HB_GSUB_LOOKUP_REVERSE_CHAIN 8
 +
 +
 +/* A pointer to a function which selects the alternate glyph.  `pos' is
 +   the position of the glyph with index `glyphID', `num_alternates'
 +   gives the number of alternates in the `alternates' array.  `data'
 +   points to the user-defined structure specified during a call to
 +   HB_GSUB_Register_Alternate_Function().  The function must return an
 +   index into the `alternates' array.                                   */
 +
 +typedef HB_UShort  (*HB_AltFunction)(HB_UInt    pos,
 +                                    HB_UShort   glyphID,
 +                                    HB_UShort   num_alternates,
 +                                    HB_UShort*  alternates,
 +                                    void*       data );
 +
 +
 +struct  HB_GSUBHeader_
 +{
 +  HB_UInt         offset;
 +
 +  HB_16Dot16         Version;
 +
 +  HB_ScriptList   ScriptList;
 +  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.                      */
 +
 +  HB_AltFunction  altfunc;
 +  void*            data;
 +};
 +
 +typedef struct HB_GSUBHeader_   HB_GSUBHeader;
 +typedef HB_GSUBHeader*  HB_GSUB;
 +
 +
 +HB_Error  HB_Load_GSUB_Table( HB_Font          font,
 +                            HB_GSUBHeader** gsub,
++                            hb_ot_layout_t   *layout );
 +
 +
 +HB_Error  HB_Done_GSUB_Table( HB_GSUBHeader*  gsub );
 +
 +
 +HB_Error  HB_GSUB_Select_Script( HB_GSUBHeader*  gsub,
 +                               HB_UInt         script_tag,
 +                               HB_UShort*       script_index );
 +
 +HB_Error  HB_GSUB_Select_Language( HB_GSUBHeader*  gsub,
 +                                 HB_UInt         language_tag,
 +                                 HB_UShort        script_index,
 +                                 HB_UShort*       language_index,
 +                                 HB_UShort*       req_feature_index );
 +
 +HB_Error  HB_GSUB_Select_Feature( HB_GSUBHeader*  gsub,
 +                                HB_UInt         feature_tag,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UShort*       feature_index );
 +
 +
 +HB_Error  HB_GSUB_Query_Scripts( HB_GSUBHeader*  gsub,
 +                               HB_UInt**       script_tag_list );
 +
 +HB_Error  HB_GSUB_Query_Languages( HB_GSUBHeader*  gsub,
 +                                 HB_UShort        script_index,
 +                                 HB_UInt**       language_tag_list );
 +
 +HB_Error  HB_GSUB_Query_Features( HB_GSUBHeader*  gsub,
 +                                HB_UShort        script_index,
 +                                HB_UShort        language_index,
 +                                HB_UInt**       feature_tag_list );
 +
 +
 +HB_Error  HB_GSUB_Add_Feature( HB_GSUBHeader*  gsub,
 +                             HB_UShort        feature_index,
 +                             HB_UInt          property );
 +
 +HB_Error  HB_GSUB_Clear_Features( HB_GSUBHeader*  gsub );
 +
 +
 +HB_Error  HB_GSUB_Register_Alternate_Function( HB_GSUBHeader*  gsub,
 +                                             HB_AltFunction  altfunc,
 +                                             void*            data );
 +
 +
 +HB_Error  HB_GSUB_Apply_String( HB_GSUBHeader*   gsub,
 +                              HB_Buffer        buffer );
 +
 +
 +HB_END_HEADER
 +
 +#endif /* HARFBUZZ_GSUB_H */
index f886e67,0000000..29101f8
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,126 @@@
- #define HB_LIKELY(cond) (cond)
- #define HB_UNLIKELY(cond) (cond)
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2006  Behdad Esfahbod
 + *
 + *  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.
 + */
 +
 +#ifndef HARFBUZZ_IMPL_H
 +#define HARFBUZZ_IMPL_H
 +
 +#include <ft2build.h>
 +#include FT_FREETYPE_H
 +#include FT_TRUETYPE_TAGS_H
 +
 +#include "harfbuzz-global.h"
 +
 +#include <stdlib.h>
 +
++/* XXX */
++#include "hb-ot-layout-private.h"
++
 +HB_BEGIN_HEADER
 +
 +#ifndef HB_INTERNAL
 +# define HB_INTERNAL
 +#endif
 +
 +#ifndef NULL
 +# define NULL ((void *)0)
 +#endif
 +
 +#ifndef FALSE
 +# define FALSE 0
 +#endif
 +
 +#ifndef TRUE
 +# define TRUE 1
 +#endif
 +
 +#ifndef TTAG_GDEF
 +# define TTAG_GDEF  HB_MAKE_TAG( 'G', 'D', 'E', 'F' )
 +#endif
 +#ifndef TTAG_GPOS
 +# define TTAG_GPOS  HB_MAKE_TAG( 'G', 'P', 'O', 'S' )
 +#endif
 +#ifndef TTAG_GSUB
 +# define TTAG_GSUB  HB_MAKE_TAG( 'G', 'S', 'U', 'B' )
 +#endif
 +
 +#ifndef HB_UNUSED
 +# define HB_UNUSED(arg) ((arg) = (arg))
 +#endif
 +
++#ifndef HB_LIKELY
++# define HB_LIKELY(cond) (cond)
++#endif
++#ifndef HB_UNLIKELY
++# define HB_UNLIKELY(cond) (cond)
++#endif
 +
 +
 +#define  ALLOC(_ptr,_size)   \
 +           ( (_ptr) = _hb_alloc( _size, &error ), error != 0 )
 +
 +#define  REALLOC(_ptr,_newsz)  \
 +           ( (_ptr) = _hb_realloc( (_ptr), (_newsz), &error ), error != 0 )
 +
 +#define  FREE(_ptr)                    \
 +  do {                                 \
 +    if ( (_ptr) )                      \
 +    {                                  \
 +      _hb_free( _ptr );                \
 +      _ptr = NULL;                     \
 +    }                                  \
 +  } while (0)
 +
 +#define  ALLOC_ARRAY(_ptr,_count,_type)   \
 +           ALLOC(_ptr,(_count)*sizeof(_type))
 +
 +#define  REALLOC_ARRAY(_ptr,_newcnt,_type) \
 +           REALLOC(_ptr,(_newcnt)*sizeof(_type))
 +
 +#define  MEM_Copy(dest,source,count)   memcpy( (char*)(dest), (const char*)(source), (size_t)(count) )
 +
 +#define ERR(err)   _hb_err (err)
 +
 +
 +HB_INTERNAL HB_Pointer
 +_hb_alloc( size_t    size,
 +         HB_Error *perror_ );
 +
 +HB_INTERNAL HB_Pointer
 +_hb_realloc( HB_Pointer block,
 +           size_t     new_size,
 +           HB_Error  *perror_ );
 +
 +HB_INTERNAL void
 +_hb_free( HB_Pointer block );
 +
 +
 +/* helper func to set a breakpoint on */
 +HB_INTERNAL HB_Error
 +_hb_err (HB_Error code);
 +
 +
 +HB_END_HEADER
 +
 +#endif /* HARFBUZZ_IMPL_H */
index e187916,0000000..68b27d4
mode 100644,000000..100644
--- /dev/null
@@@ -1,1414 -1,0 +1,1405 @@@
-   /* 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;
-   }
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2006  Behdad Esfahbod
 + *
 + *  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.
 + */
 +
 +#include "harfbuzz-impl.h"
 +#include "harfbuzz-open-private.h"
 +
 +
 +/***************************
 + * Script related functions
 + ***************************/
 +
 +
 +/* LangSys */
 +
 +static HB_Error  Load_LangSys( HB_LangSys*  ls,
 +                             HB_Stream     stream )
 +{
 +  HB_Error   error;
 +  HB_UShort  n, count;
 +  HB_UShort* fi;
 +
 +
 +  if ( ACCESS_Frame( 6L ) )
 +    return error;
 +
 +  ls->LookupOrderOffset    = GET_UShort();    /* should be 0 */
 +  ls->ReqFeatureIndex      = GET_UShort();
 +  count = ls->FeatureCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ls->FeatureIndex = NULL;
 +
 +  if ( ALLOC_ARRAY( ls->FeatureIndex, count, HB_UShort ) )
 +    return error;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +  {
 +    FREE( ls->FeatureIndex );
 +    return error;
 +  }
 +
 +  fi = ls->FeatureIndex;
 +
 +  for ( n = 0; n < count; n++ )
 +    fi[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +static void  Free_LangSys( HB_LangSys*  ls )
 +{
 +  FREE( ls->FeatureIndex );
 +}
 +
 +
 +/* Script */
 +
 +static HB_Error  Load_Script( HB_ScriptTable*  s,
 +                            HB_Stream    stream )
 +{
 +  HB_Error   error;
 +  HB_UShort  n, m, count;
 +  HB_UInt   cur_offset, new_offset, base_offset;
 +
 +  HB_LangSysRecord*  lsr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  new_offset = GET_UShort() + base_offset;
 +
 +  FORGET_Frame();
 +
 +  if ( new_offset != base_offset )        /* not a NULL offset */
 +  {
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_LangSys( &s->DefaultLangSys,
 +                               stream ) ) != HB_Err_Ok )
 +      return error;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +  else
 +  {
 +    /* we create a DefaultLangSys table with no entries */
 +
 +    s->DefaultLangSys.LookupOrderOffset = 0;
 +    s->DefaultLangSys.ReqFeatureIndex   = 0xFFFF;
 +    s->DefaultLangSys.FeatureCount      = 0;
 +    s->DefaultLangSys.FeatureIndex      = NULL;
 +  }
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    goto Fail2;
 +
 +  count = s->LangSysCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  s->LangSysRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) )
 +    goto Fail2;
 +
 +  lsr = s->LangSysRecord;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 6L ) )
 +      goto Fail1;
 +
 +    lsr[n].LangSysTag = GET_ULong();
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_LangSys( &lsr[m].LangSys );
 +
 +  FREE( s->LangSysRecord );
 +
 +Fail2:
 +  Free_LangSys( &s->DefaultLangSys );
 +  return error;
 +}
 +
 +
 +static void  Free_Script( HB_ScriptTable*  s )
 +{
 +  HB_UShort           n, count;
 +
 +  HB_LangSysRecord*  lsr;
 +
 +
 +  Free_LangSys( &s->DefaultLangSys );
 +
 +  if ( s->LangSysRecord )
 +  {
 +    count = s->LangSysCount;
 +    lsr   = s->LangSysRecord;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_LangSys( &lsr[n].LangSys );
 +
 +    FREE( lsr );
 +  }
 +}
 +
 +
 +/* ScriptList */
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Load_ScriptList( HB_ScriptList* sl,
 +                        HB_Stream      stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort          n, script_count;
 +  HB_UInt           cur_offset, new_offset, base_offset;
 +
 +  HB_ScriptRecord*  sr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  script_count = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  sl->ScriptRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) )
 +    return error;
 +
 +  sr = sl->ScriptRecord;
 +
 +  sl->ScriptCount= 0;
 +  for ( n = 0; n < script_count; n++ )
 +  {
 +    if ( ACCESS_Frame( 6L ) )
 +      goto Fail;
 +
 +    sr[sl->ScriptCount].ScriptTag = GET_ULong();
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +
 +    if ( FILE_Seek( new_offset ) )
 +      goto Fail;
 +
 +    error = Load_Script( &sr[sl->ScriptCount].Script, stream );
 +    if ( error == HB_Err_Ok )
 +      sl->ScriptCount += 1;
 +    else if ( error != HB_Err_Not_Covered )
 +      goto Fail;
 +
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  /* Empty tables are harmless and generated by fontforge.
 +   * See http://bugzilla.gnome.org/show_bug.cgi?id=347073
 +   */
 +#if 0
 +  if ( sl->ScriptCount == 0 )
 +  {
 +    error = ERR(HB_Err_Invalid_SubTable);
 +    goto Fail;
 +  }
 +#endif
 +  
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( n = 0; n < sl->ScriptCount; n++ )
 +    Free_Script( &sr[n].Script );
 +
 +  FREE( sl->ScriptRecord );
 +  return error;
 +}
 +
 +
 +HB_INTERNAL void
 +_HB_OPEN_Free_ScriptList( HB_ScriptList* sl )
 +{
 +  HB_UShort          n, count;
 +
 +  HB_ScriptRecord*  sr;
 +
 +
 +  if ( sl->ScriptRecord )
 +  {
 +    count = sl->ScriptCount;
 +    sr    = sl->ScriptRecord;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_Script( &sr[n].Script );
 +
 +    FREE( sr );
 +  }
 +}
 +
 +
 +
 +/*********************************
 + * Feature List related functions
 + *********************************/
 +
 +
 +/* Feature */
 +
 +static HB_Error  Load_Feature( HB_Feature*  f,
 +                             HB_Stream     stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort   n, count;
 +
 +  HB_UShort*  lli;
 +
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  f->FeatureParams           = GET_UShort();    /* should be 0 */
 +  count = f->LookupListCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  f->LookupListIndex = NULL;
 +
 +  if ( ALLOC_ARRAY( f->LookupListIndex, count, HB_UShort ) )
 +    return error;
 +
 +  lli = f->LookupListIndex;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +  {
 +    FREE( f->LookupListIndex );
 +    return error;
 +  }
 +
 +  for ( n = 0; n < count; n++ )
 +    lli[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +static void  Free_Feature( HB_Feature*  f )
 +{
 +  FREE( f->LookupListIndex );
 +}
 +
 +
 +/* FeatureList */
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Load_FeatureList( HB_FeatureList* fl,
 +                         HB_Stream       stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort           n, m, count;
 +  HB_UInt            cur_offset, new_offset, base_offset;
 +
 +  HB_FeatureRecord*  fr;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = fl->FeatureCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  fl->FeatureRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) )
 +    return error;
 +  if ( ALLOC_ARRAY( fl->ApplyOrder, count, HB_UShort ) )
 +    goto Fail2;
 +  
 +  fl->ApplyCount = 0;
 +
 +  fr = fl->FeatureRecord;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 6L ) )
 +      goto Fail1;
 +
 +    fr[n].FeatureTag = GET_ULong();
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_Feature( &fr[n].Feature, stream ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  for ( m = 0; m < n; m++ )
 +    Free_Feature( &fr[m].Feature );
 +
 +  FREE( fl->ApplyOrder );
 +
 +Fail2:
 +  FREE( fl->FeatureRecord );
 +
 +  return error;
 +}
 +
 +
 +HB_INTERNAL void
 +_HB_OPEN_Free_FeatureList( HB_FeatureList*  fl )
 +{
 +  HB_UShort           n, count;
 +
 +  HB_FeatureRecord*  fr;
 +
 +
 +  if ( fl->FeatureRecord )
 +  {
 +    count = fl->FeatureCount;
 +    fr    = fl->FeatureRecord;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_Feature( &fr[n].Feature );
 +
 +    FREE( fr );
 +  }
 +  
 +  FREE( fl->ApplyOrder );
 +}
 +
 +
 +
 +/********************************
 + * Lookup List related functions
 + ********************************/
 +
 +/* the subroutines of the following two functions are defined in
 +   ftxgsub.c and ftxgpos.c respectively                          */
 +
 +
 +/* SubTable */
 +
 +static HB_Error  Load_SubTable( HB_SubTable*  st,
 +                              HB_Stream     stream,
 +                              HB_Type       table_type,
 +                              HB_UShort     lookup_type )
 +{
 +  if ( table_type == HB_Type_GSUB )
 +    return _HB_GSUB_Load_SubTable ( &st->st.gsub, stream, lookup_type );
 +  else
 +    return _HB_GPOS_Load_SubTable ( &st->st.gpos, stream, lookup_type );
 +}
 +
 +
 +static void  Free_SubTable( HB_SubTable*  st,
 +                          HB_Type       table_type,
 +                          HB_UShort     lookup_type )
 +{
 +  if ( table_type == HB_Type_GSUB )
 +    _HB_GSUB_Free_SubTable ( &st->st.gsub, lookup_type );
 +  else
 +    _HB_GPOS_Free_SubTable ( &st->st.gpos, lookup_type );
 +}
 +
 +
 +/* Lookup */
 +
 +static HB_Error  Load_Lookup( HB_Lookup*   l,
 +                            HB_Stream     stream,
 +                            HB_Type      type )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort      n, m, count;
 +  HB_UInt       cur_offset, new_offset, base_offset;
 +
 +  HB_SubTable*  st;
 +
 +  HB_Bool        is_extension = FALSE;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 6L ) )
 +    return error;
 +
 +  l->LookupType            = GET_UShort();
 +  l->LookupFlag            = GET_UShort();
 +  count = l->SubTableCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  l->SubTable = NULL;
 +
 +  if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) )
 +    return error;
 +
 +  st = l->SubTable;
 +
 +  if ( ( type == HB_Type_GSUB && l->LookupType == HB_GSUB_LOOKUP_EXTENSION ) ||
 +       ( type == HB_Type_GPOS && l->LookupType == HB_GPOS_LOOKUP_EXTENSION ) )
 +    is_extension = TRUE;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +
 +    if ( is_extension )
 +    {
 +      if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) )
 +      goto Fail;
 +
 +      if (GET_UShort() != 1) /* format should be 1 */
 +      goto Fail;
 +
 +      l->LookupType = GET_UShort();
 +      new_offset += GET_ULong();
 +
 +      FORGET_Frame();
 +    }
 +
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_SubTable( &st[n], stream,
 +                                type, l->LookupType ) ) != HB_Err_Ok )
 +      goto Fail;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  for ( m = 0; m < n; m++ )
 +    Free_SubTable( &st[m], type, l->LookupType );
 +
 +  FREE( l->SubTable );
 +  return error;
 +}
 +
 +
 +static void  Free_Lookup( HB_Lookup*   l,
 +                        HB_Type      type )
 +{
 +  HB_UShort      n, count;
 +
 +  HB_SubTable*  st;
 +
 +
 +  if ( l->SubTable )
 +  {
 +    count = l->SubTableCount;
 +    st    = l->SubTable;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_SubTable( &st[n], type, l->LookupType );
 +
 +    FREE( st );
 +  }
 +}
 +
 +
 +/* LookupList */
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Load_LookupList( HB_LookupList* ll,
 +                        HB_Stream      stream,
 +                        HB_Type        type )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort    n, m, count;
 +  HB_UInt     cur_offset, new_offset, base_offset;
 +
 +  HB_Lookup*  l;
 +
 +
 +  base_offset = FILE_Pos();
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = ll->LookupCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  ll->Lookup = NULL;
 +
 +  if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) )
 +    return error;
 +  if ( ALLOC_ARRAY( ll->Properties, count, HB_UInt ) )
 +    goto Fail2;
 +
 +  l = ll->Lookup;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    if ( ACCESS_Frame( 2L ) )
 +      goto Fail1;
 +
 +    new_offset = GET_UShort() + base_offset;
 +
 +    FORGET_Frame();
 +
 +    cur_offset = FILE_Pos();
 +    if ( FILE_Seek( new_offset ) ||
 +       ( error = Load_Lookup( &l[n], stream, type ) ) != HB_Err_Ok )
 +      goto Fail1;
 +    (void)FILE_Seek( cur_offset );
 +  }
 +
 +  return HB_Err_Ok;
 +
 +Fail1:
 +  FREE( ll->Properties );
 +
 +  for ( m = 0; m < n; m++ )
 +    Free_Lookup( &l[m], type );
 +
 +Fail2:
 +  FREE( ll->Lookup );
 +  return error;
 +}
 +
 +
 +HB_INTERNAL void
 +_HB_OPEN_Free_LookupList( HB_LookupList* ll,
 +                        HB_Type        type )
 +{
 +  HB_UShort    n, count;
 +
 +  HB_Lookup*  l;
 +
 +
 +  FREE( ll->Properties );
 +
 +  if ( ll->Lookup )
 +  {
 +    count = ll->LookupCount;
 +    l     = ll->Lookup;
 +
 +    for ( n = 0; n < count; n++ )
 +      Free_Lookup( &l[n], type );
 +
 +    FREE( l );
 +  }
 +}
 +
 +
 +
 +/*****************************
 + * Coverage related functions
 + *****************************/
 +
 +
 +/* CoverageFormat1 */
 +
 +static HB_Error  Load_Coverage1( HB_CoverageFormat1*  cf1,
 +                               HB_Stream             stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort  n, count;
 +
 +  HB_UShort* ga;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = cf1->GlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cf1->GlyphArray = NULL;
 +
 +  if ( ALLOC_ARRAY( cf1->GlyphArray, count, HB_UShort ) )
 +    return error;
 +
 +  ga = cf1->GlyphArray;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +  {
 +    FREE( cf1->GlyphArray );
 +    return error;
 +  }
 +
 +  for ( n = 0; n < count; n++ )
 +    ga[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +static void  Free_Coverage1( HB_CoverageFormat1*  cf1 )
 +{
 +  FREE( cf1->GlyphArray );
 +}
 +
 +
 +/* CoverageFormat2 */
 +
 +static HB_Error  Load_Coverage2( HB_CoverageFormat2*  cf2,
 +                               HB_Stream             stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort         n, count;
 +
 +  HB_RangeRecord*  rr;
 +
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = cf2->RangeCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  cf2->RangeRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) )
 +    return error;
 +
 +  rr = cf2->RangeRecord;
 +
 +  if ( ACCESS_Frame( count * 6L ) )
 +    goto Fail;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    rr[n].Start              = GET_UShort();
 +    rr[n].End                = GET_UShort();
 +    rr[n].StartCoverageIndex = GET_UShort();
 +
 +    /* sanity check; we are limited to 16bit integers */
 +    if ( rr[n].Start > rr[n].End ||
 +       ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >=
 +         0x10000L )
 +    {
 +      error = ERR(HB_Err_Invalid_SubTable);
 +      goto Fail;
 +    }
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  FREE( cf2->RangeRecord );
 +  return error;
 +}
 +
 +
 +static void  Free_Coverage2( HB_CoverageFormat2*  cf2 )
 +{
 +  FREE( cf2->RangeRecord );
 +}
 +
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Load_Coverage( HB_Coverage* c,
 +                      HB_Stream    stream )
 +{
 +  HB_Error   error;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  c->CoverageFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  switch ( c->CoverageFormat )
 +  {
 +  case 1:  return Load_Coverage1( &c->cf.cf1, stream );
 +  case 2:  return Load_Coverage2( &c->cf.cf2, stream );
 +  default: return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +HB_INTERNAL void
 +_HB_OPEN_Free_Coverage( HB_Coverage* c )
 +{
 +  switch ( c->CoverageFormat )
 +  {
 +  case 1:  Free_Coverage1( &c->cf.cf1 ); break;
 +  case 2:  Free_Coverage2( &c->cf.cf2 ); break;
 +  default:                                     break;
 +  }
 +}
 +
 +
 +static HB_Error  Coverage_Index1( HB_CoverageFormat1*  cf1,
 +                                HB_UShort             glyphID,
 +                                HB_UShort*            index )
 +{
 +  HB_UShort min, max, new_min, new_max, middle;
 +
 +  HB_UShort*  array = cf1->GlyphArray;
 +
 +
 +  /* binary search */
 +
 +  if ( cf1->GlyphCount == 0 )
 +    return HB_Err_Not_Covered;
 +
 +  new_min = 0;
 +  new_max = cf1->GlyphCount - 1;
 +
 +  do
 +  {
 +    min = new_min;
 +    max = new_max;
 +
 +    /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
 +       overflow and rounding errors                             */
 +
 +    middle = max - ( ( max - min ) >> 1 );
 +
 +    if ( glyphID == array[middle] )
 +    {
 +      *index = middle;
 +      return HB_Err_Ok;
 +    }
 +    else if ( glyphID < array[middle] )
 +    {
 +      if ( middle == min )
 +      break;
 +      new_max = middle - 1;
 +    }
 +    else
 +    {
 +      if ( middle == max )
 +      break;
 +      new_min = middle + 1;
 +    }
 +  } while ( min < max );
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +static HB_Error  Coverage_Index2( HB_CoverageFormat2*  cf2,
 +                                HB_UShort             glyphID,
 +                                HB_UShort*            index )
 +{
 +  HB_UShort         min, max, new_min, new_max, middle;
 +
 +  HB_RangeRecord*  rr = cf2->RangeRecord;
 +
 +
 +  /* binary search */
 +
 +  if ( cf2->RangeCount == 0 )
 +    return HB_Err_Not_Covered;
 +
 +  new_min = 0;
 +  new_max = cf2->RangeCount - 1;
 +
 +  do
 +  {
 +    min = new_min;
 +    max = new_max;
 +
 +    /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
 +       overflow and rounding errors                             */
 +
 +    middle = max - ( ( max - min ) >> 1 );
 +
 +    if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End )
 +    {
 +      *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start;
 +      return HB_Err_Ok;
 +    }
 +    else if ( glyphID < rr[middle].Start )
 +    {
 +      if ( middle == min )
 +      break;
 +      new_max = middle - 1;
 +    }
 +    else
 +    {
 +      if ( middle == max )
 +      break;
 +      new_min = middle + 1;
 +    }
 +  } while ( min < max );
 +
 +  return HB_Err_Not_Covered;
 +}
 +
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Coverage_Index( HB_Coverage* c,
 +                       HB_UShort    glyphID,
 +                       HB_UShort*   index )
 +{
 +  switch ( c->CoverageFormat )
 +  {
 +  case 1:  return Coverage_Index1( &c->cf.cf1, glyphID, index );
 +  case 2:  return Coverage_Index2( &c->cf.cf2, glyphID, index );
 +  default: return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +
 +/*************************************
 + * Class Definition related functions
 + *************************************/
 +
 +
 +/* ClassDefFormat1 */
 +
 +static HB_Error  Load_ClassDef1( HB_ClassDefinition*  cd,
 +                               HB_UShort             limit,
 +                               HB_Stream             stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort             n, count;
 +
 +  HB_UShort*            cva;
 +
 +  HB_ClassDefFormat1*  cdf1;
 +
 +
 +  cdf1 = &cd->cd.cd1;
 +
 +  if ( ACCESS_Frame( 4L ) )
 +    return error;
 +
 +  cdf1->StartGlyph         = GET_UShort();
 +  count = cdf1->GlyphCount = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  /* sanity check; we are limited to 16bit integers */
 +
 +  if ( cdf1->StartGlyph + (long)count >= 0x10000L )
 +    return ERR(HB_Err_Invalid_SubTable);
 +
 +  cdf1->ClassValueArray = NULL;
 +
 +  if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, HB_UShort ) )
 +    return error;
 +
 +  cva = cdf1->ClassValueArray;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +    goto Fail;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    cva[n] = GET_UShort();
 +    if ( cva[n] >= limit )
 +    {
 +      error = ERR(HB_Err_Invalid_SubTable);
 +      goto Fail;
 +    }
 +  }
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  FREE( cva );
 +
 +  return error;
 +}
 +
 +
 +static void  Free_ClassDef1( HB_ClassDefFormat1*  cdf1 )
 +{
 +  FREE( cdf1->ClassValueArray );
 +}
 +
 +
 +/* ClassDefFormat2 */
 +
 +static HB_Error  Load_ClassDef2( HB_ClassDefinition*  cd,
 +                               HB_UShort             limit,
 +                               HB_Stream             stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort              n, count;
 +
 +  HB_ClassRangeRecord*  crr;
 +
 +  HB_ClassDefFormat2*   cdf2;
 +
 +
 +  cdf2 = &cd->cd.cd2;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  count = GET_UShort();
 +  cdf2->ClassRangeCount = 0; /* zero for now.  we fill with the number of good entries later */
 +
 +  FORGET_Frame();
 +
 +  cdf2->ClassRangeRecord = NULL;
 +
 +  if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) )
 +    return error;
 +
 +  crr = cdf2->ClassRangeRecord;
 +
 +  if ( ACCESS_Frame( count * 6L ) )
 +    goto Fail;
 +
 +  for ( n = 0; n < count; n++ )
 +  {
 +    crr[n].Start = GET_UShort();
 +    crr[n].End   = GET_UShort();
 +    crr[n].Class = GET_UShort();
 +
 +    /* sanity check */
 +
 +    if ( crr[n].Start > crr[n].End ||
 +       crr[n].Class >= limit )
 +    {
 +      /* XXX
 +       * Corrupt entry.  Skip it.
 +       * This is hit by Nafees Nastaliq font for example
 +       */
 +       n--;
 +       count--;
 +    }
 +  }
 +
 +  FORGET_Frame();
 +
 +  cdf2->ClassRangeCount = count;
 +
 +  return HB_Err_Ok;
 +
 +Fail:
 +  FREE( crr );
 +
 +  return error;
 +}
 +
 +
 +static void  Free_ClassDef2( HB_ClassDefFormat2*  cdf2 )
 +{
 +  FREE( cdf2->ClassRangeRecord );
 +}
 +
 +
 +/* ClassDefinition */
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd,
 +                             HB_UShort           limit,
 +                             HB_Stream           stream )
 +{
 +  HB_Error   error;
 +
 +  if ( ACCESS_Frame( 2L ) )
 +    return error;
 +
 +  cd->ClassFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  switch ( cd->ClassFormat )
 +  {
 +  case 1:  error = Load_ClassDef1( cd, limit, stream ); break;
 +  case 2:  error = Load_ClassDef2( cd, limit, stream ); break;
 +  default: error = ERR(HB_Err_Invalid_SubTable_Format);       break;
 +  }
 +
 +  if ( error )
 +    return error;
 +
 +  cd->loaded = TRUE;
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +static HB_Error
 +_HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition*  cd )
 +{
 +  HB_Error   error;
 +
 +  cd->ClassFormat = 1; /* Meaningless */
 +
 +  if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, HB_UShort ) )
 +    return error;
 +
 +  return HB_Err_Ok;
 +}
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd,
 +                                    HB_UShort           limit,
 +                                    HB_UInt            class_offset,
 +                                    HB_UInt            base_offset,
 +                                    HB_Stream           stream )
 +{
 +  HB_Error error;
 +  HB_UInt               cur_offset;
 +
 +  cur_offset = FILE_Pos();
 +
 +  if ( class_offset )
 +    {
 +      if ( !FILE_Seek( class_offset + base_offset ) )
 +      error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream );
 +    }
 +  else
 +     error = _HB_OPEN_Load_EmptyClassDefinition ( cd );
 +
 +  if (error == HB_Err_Ok)
 +    (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
 +
 +  return error;
 +}
 +
 +HB_INTERNAL void
 +_HB_OPEN_Free_ClassDefinition( HB_ClassDefinition*  cd )
 +{
 +  if ( !cd->loaded )
 +    return;
 +
 +  switch ( cd->ClassFormat )
 +  {
 +  case 1:  Free_ClassDef1( &cd->cd.cd1 ); break;
 +  case 2:  Free_ClassDef2( &cd->cd.cd2 ); break;
 +  default:                              break;
 +  }
 +}
 +
 +
 +static HB_Error  Get_Class1( HB_ClassDefFormat1*  cdf1,
 +                           HB_UShort             glyphID,
 +                           HB_UShort*            klass,
 +                           HB_UShort*            index )
 +{
 +  HB_UShort*  cva = cdf1->ClassValueArray;
 +
 +
 +  if ( index )
 +    *index = 0;
 +
 +  if ( glyphID >= cdf1->StartGlyph &&
 +       glyphID < cdf1->StartGlyph + cdf1->GlyphCount )
 +  {
 +    *klass = cva[glyphID - cdf1->StartGlyph];
 +    return HB_Err_Ok;
 +  }
 +  else
 +  {
 +    *klass = 0;
 +    return HB_Err_Not_Covered;
 +  }
 +}
 +
 +
 +/* we need the index value of the last searched class range record
 +   in case of failure for constructed GDEF tables                  */
 +
 +static HB_Error  Get_Class2( HB_ClassDefFormat2*  cdf2,
 +                           HB_UShort             glyphID,
 +                           HB_UShort*            klass,
 +                           HB_UShort*            index )
 +{
 +  HB_Error               error = HB_Err_Ok;
 +  HB_UShort              min, max, new_min, new_max, middle;
 +
 +  HB_ClassRangeRecord*  crr = cdf2->ClassRangeRecord;
 +
 +
 +  /* binary search */
 +
 +  if ( cdf2->ClassRangeCount == 0 )
 +    {
 +      *klass = 0;
 +      if ( index )
 +      *index = 0;
 +      
 +      return HB_Err_Not_Covered;
 +    }
 +
 +  new_min = 0;
 +  new_max = cdf2->ClassRangeCount - 1;
 +
 +  do
 +  {
 +    min = new_min;
 +    max = new_max;
 +
 +    /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
 +       overflow and rounding errors                             */
 +
 +    middle = max - ( ( max - min ) >> 1 );
 +
 +    if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End )
 +    {
 +      *klass = crr[middle].Class;
 +      error  = HB_Err_Ok;
 +      break;
 +    }
 +    else if ( glyphID < crr[middle].Start )
 +    {
 +      if ( middle == min )
 +      {
 +      *klass = 0;
 +      error  = HB_Err_Not_Covered;
 +      break;
 +      }
 +      new_max = middle - 1;
 +    }
 +    else
 +    {
 +      if ( middle == max )
 +      {
 +      *klass = 0;
 +      error  = HB_Err_Not_Covered;
 +      break;
 +      }
 +      new_min = middle + 1;
 +    }
 +  } while ( min < max );
 +
 +  if ( index )
 +    *index = middle;
 +
 +  return error;
 +}
 +
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Get_Class( HB_ClassDefinition* cd,
 +                  HB_UShort           glyphID,
 +                  HB_UShort*          klass,
 +                  HB_UShort*          index )
 +{
 +  switch ( cd->ClassFormat )
 +  {
 +  case 1:  return Get_Class1( &cd->cd.cd1, glyphID, klass, index );
 +  case 2:  return Get_Class2( &cd->cd.cd2, glyphID, klass, index );
 +  default: return ERR(HB_Err_Invalid_SubTable_Format);
 +  }
 +
 +  return HB_Err_Ok;               /* never reached */
 +}
 +
 +
 +
 +/***************************
 + * Device related functions
 + ***************************/
 +
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Load_Device( HB_Device* d,
 +                    HB_Stream  stream )
 +{
 +  HB_Error   error;
 +
 +  HB_UShort   n, count;
 +
 +  HB_UShort*  dv;
 +
 +
 +  if ( ACCESS_Frame( 6L ) )
 +    return error;
 +
 +  d->StartSize   = GET_UShort();
 +  d->EndSize     = GET_UShort();
 +  d->DeltaFormat = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  d->DeltaValue = NULL;
 +
 +  if ( d->StartSize > d->EndSize ||
 +       d->DeltaFormat == 0 || d->DeltaFormat > 3 )
 +    {
 +      /* XXX
 +       * I've seen fontforge generate DeltaFormat == 0.
 +       * Just return Ok and let the NULL DeltaValue disable
 +       * this table.
 +       */
 +      return HB_Err_Ok;
 +    }
 +
 +  count = ( ( d->EndSize - d->StartSize + 1 ) >>
 +            ( 4 - d->DeltaFormat ) ) + 1;
 +
 +  if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) )
 +    return error;
 +
 +  if ( ACCESS_Frame( count * 2L ) )
 +  {
 +    FREE( d->DeltaValue );
 +    return error;
 +  }
 +
 +  dv = d->DeltaValue;
 +
 +  for ( n = 0; n < count; n++ )
 +    dv[n] = GET_UShort();
 +
 +  FORGET_Frame();
 +
 +  return HB_Err_Ok;
 +}
 +
 +
 +HB_INTERNAL void
 +_HB_OPEN_Free_Device( HB_Device* d )
 +{
 +  FREE( d->DeltaValue );
 +}
 +
 +
 +/* Since we have the delta values stored in compressed form, we must
 +   uncompress it now.  To simplify the interface, the function always
 +   returns a meaningful value in `value'; the error is just for
 +   information.
 +                             |                |
 +   format = 1: 0011223344556677|8899101112131415|...
 +                             |                |
 +                  byte 1           byte 2
 +
 +     00: (byte >> 14) & mask
 +     11: (byte >> 12) & mask
 +     ...
 +
 +     mask = 0x0003
 +                             |                |
 +   format = 2: 0000111122223333|4444555566667777|...
 +                             |                |
 +                  byte 1           byte 2
 +
 +     0000: (byte >> 12) & mask
 +     1111: (byte >>  8) & mask
 +     ...
 +
 +     mask = 0x000F
 +                             |                |
 +   format = 3: 0000000011111111|2222222233333333|...
 +                             |                |
 +                  byte 1           byte 2
 +
 +     00000000: (byte >> 8) & mask
 +     11111111: (byte >> 0) & mask
 +     ....
 +
 +     mask = 0x00FF                                    */
 +
 +HB_INTERNAL HB_Error
 +_HB_OPEN_Get_Device( HB_Device* d,
 +                   HB_UShort  size,
 +                   HB_Short*  value )
 +{
 +  HB_UShort  byte, bits, mask, f, s;
 +
 +
 +  f = d->DeltaFormat;
 +
 +  if ( d->DeltaValue && size >= d->StartSize && size <= d->EndSize )
 +  {
 +    s    = size - d->StartSize;
 +    byte = d->DeltaValue[s >> ( 4 - f )];
 +    bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) );
 +    mask = 0xFFFF >> ( 16 - ( 1 << f ) );
 +
 +    *value = (HB_Short)( bits & mask );
 +
 +    /* conversion to a signed value */
 +
 +    if ( *value >= ( ( mask + 1 ) >> 1 ) )
 +      *value -= mask + 1;
 +
 +    return HB_Err_Ok;
 +  }
 +  else
 +  {
 +    *value = 0;
 +    return HB_Err_Not_Covered;
 +  }
 +}
 +
 +
 +/* END */
diff --cc src/harfbuzz.h
index 10d4f74,0000000..d23b6bc
mode 100644,000000..100644
--- /dev/null
@@@ -1,36 -1,0 +1,35 @@@
- #include "harfbuzz-gdef.h"
 +/*
 + * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 + * Copyright (C) 2006  Behdad Esfahbod
 + *
 + *  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.
 + */
 +
 +#ifndef HARFBUZZ_H
 +#define HARFBUZZ_H
 +
 +#include "harfbuzz-global.h"
 +#include "harfbuzz-buffer.h"
 +#include "harfbuzz-gsub.h"
 +#include "harfbuzz-gpos.h"
 +#include "harfbuzz-open.h"
 +
 +#endif /* HARFBUZZ_OPEN_H */
index 0000000,ae41090..c8d5405
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,583 +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 */
index 0000000,66fd55e..d5ca810
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,993 +1,993 @@@
 -                               * to the beginning of the Feature Table; = Null 
+ /*
+  * 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 */
index 0000000,68fd3e5..01923db
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,565 +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 --cc src/main.cc
index 0000000,4c24ff4..ffd13b4
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,174 +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;
+ }