Convert pango/opentype to the new project called HarfBuzz.

2006-03-31  Behdad Esfahbod  <behdad@gnome.org>

        Convert pango/opentype to the new project called HarfBuzz.

        * pango/opentype/*: Restructured.

        * pango/pango-ot-*: Updated to use HarfBuzz symbol names.
diff --git a/src/COPYING b/src/COPYING
new file mode 100644
index 0000000..cde9101
--- /dev/null
+++ b/src/COPYING
@@ -0,0 +1,15 @@
+HarfBuzz is distributed under two mutually exclusive open-source licenses.
+This means  that *you* must choose  *one* of the  two licenses  described
+below, then obey  all its  terms and conditions when  using  HarfBuzz  in
+any of your projects or products.
+
+  - The FreeType License, found in the file `COPYING.FTL', which is similar to
+    the original BSD license *with* an advertising clause that forces you  to
+    explicitly cite  the  FreeType  project  in your  product's documentation.
+    All  details are in the license  file.  This license is  suited  to
+    products  which  don't  use  the GNU  General  Public License.
+
+  - The GNU  General Public License  version 2, found in  `COPYING.GPL' (any
+    later version can be used  also), for programs which already use the GPL.
+    Note  that the  FTL is  incompatible with the  GPL due  to its
+    advertisement clause.
diff --git a/src/FTL.TXT b/src/COPYING.FTL
similarity index 100%
rename from src/FTL.TXT
rename to src/COPYING.FTL
diff --git a/src/COPYING.GPL b/src/COPYING.GPL
new file mode 100644
index 0000000..14db8fc
--- /dev/null
+++ b/src/COPYING.GPL
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/FT-license.txt b/src/FT-license.txt
deleted file mode 100644
index 102a03d..0000000
--- a/src/FT-license.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-
-The  FreeType 2  font  engine is  copyrighted  work and  cannot be  used
-legally  without a  software license.   In  order to  make this  project
-usable  to a vast  majority of  developers, we  distribute it  under two
-mutually exclusive open-source licenses.
-
-This means  that *you* must choose  *one* of the  two licenses described
-below, then obey  all its terms and conditions when  using FreeType 2 in
-any of your projects or products.
-
-  - The FreeType License, found in  the file `FTL.TXT', which is similar
-    to the original BSD license *with* an advertising clause that forces
-    you  to  explicitly cite  the  FreeType  project  in your  product's
-    documentation.  All  details are in the license  file.  This license
-    is  suited  to products  which  don't  use  the GNU  General  Public
-    License.
-
-  - The GNU  General Public License  version 2, found in  `GPL.TXT' (any
-    later version can be used  also), for programs which already use the
-    GPL.  Note  that the  FTL is  incompatible with the  GPL due  to its
-    advertisement clause.
-
-The contributed PCF driver comes with a license similar to that of the X
-Window System.   It is  compatible to the  above two licenses  (see file
-src/pcf/readme).
-
-
---- end of LICENSE.TXT ---
diff --git a/src/Makefile.am b/src/Makefile.am
index 7c0ba69..8d65294 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,51 +1,58 @@
 ## Process this file with automake to produce Makefile.in
 
 INCLUDES = 					\
-	-DSYSCONFDIR=\"$(sysconfdir)\" 		\
-	-DLIBDIR=\"$(libdir)\" 			\
-	$(PANGO_DEBUG_FLAGS)			\
-	-I$(top_srcdir)				\
-	$(GLIB_CFLAGS)				\
 	$(FREETYPE_CFLAGS)
 
-noinst_LTLIBRARIES = libmini-harfbuzz.la
+noinst_LTLIBRARIES = libharfbuzz-1.la
 
-libmini_harfbuzz_la_SOURCES =  	\
-	ftglue.h		\
-	ftglue.c		\
-	ftxopen.c	 	\
-	ftxopen.h	 	\
-	ftxopenf.h	 	\
-	ftxgdef.c		\
-	ftxgdef.h		\
-	ftxgpos.c 		\
-	ftxgpos.h		\
-	ftxgsub.c		\
-	ftxgsub.h		\
-	otlbuffer.c		\
-	otlbuffer.h
+SOURCES =  \
+	ftglue.c \
+	harfbuzz-buffer.c \
+	harfbuzz-dump.c \
+	harfbuzz-gdef.c \
+	harfbuzz-gpos.c \
+	harfbuzz-gsub.c \
+	harfbuzz-open.c
 
-libmini_harfbuzz_la_LIBADD = \
-	$(x_ldflags)	\
-	$(x_libs)	\
-	$(GLIB_LIBS)	\
-	-lm
+EXTRA_SOURCES = harfbuzz.c
 
-if BUILD_OT_TESTS
-noinst_PROGRAMS = ottest
-endif
+PUBLICHEADERS = \
+	harfbuzz.h \
+	harfbuzz-buffer.h \
+	harfbuzz-dump.h \
+	harfbuzz-gdef.h \
+	harfbuzz-gpos.h \
+	harfbuzz-gsub.h \
+	harfbuzz-open.h
 
-ottest_SOURCES = 	\
-	ottest.c	\
-	disasm.c	\
-	disasm.h
+PRIVATEHEADERS = \
+	ftglue.h \
+	harfbuzz-impl.h \
+	harfbuzz-gdef-private.h \
+	harfbuzz-gpos-private.h \
+	harfbuzz-gsub-private.h \
+	harfbuzz-open-private.h
 
-ottest_LDADD = 		\
-	libmini-harfbuzz.la	\
+libharfbuzz_1_la_SOURCES = \
+	$(SOURCES) \
+	$(PUBLICHEADERS) \
+	$(PRIVATEHEADERS)
+
+libharfbuzz_1_la_LIBADD = \
 	$(FREETYPE_LIBS)
 
+noinst_PROGRAMS = harfbuzz-dump
+
+harfbuzz_dump_SOURCES = 	\
+	harfbuzz-dump-main.c
+
+harfbuzz_dump_LDADD = 		\
+	libharfbuzz-1.la
+
 EXTRA_DIST = 		\
 	README		\
-	FTL.TXT		\
-	FT-license.txt
+	COPYING.FTL	\
+	COPYING.GPL	\
+	COPYING		\
+	$(EXTRA_SOURCES)
 
diff --git a/src/README b/src/README
index 2003564..f7746ef 100644
--- a/src/README
+++ b/src/README
@@ -1,36 +1,18 @@
-This directory includes code for using OpenType Layout tables from
-OpenType fonts with FreeType and 
+This is HarfBuzz, an OpenType Layout engine.
 
-The table reading code in:
+It was derived originally from the OpenType code in FreeType-1.x, ported to
+FreeType2.  (This code has been abandoned for FreeType2, but until something
+better comes along, should serve our purposes.) In addition to porting to
+FreeType-2, it has been modified in various other ways.
 
- ftxopen.[ch]
- ftxopenf.h
- ftxgdef.[ch]
- ftxgpos.[ch]
- ftxgdef.[ch]
+It also includes a partial XML dumper for OpenType Layout tables useful for
+figuring out what is going on. Please extend to cover additional parts of the
+tables as you encounter fonts using them.  The dumper is written by Owen Taylor.
 
-Is derived from the OpenType code in FreeType-1.x, ported to FreeType2. 
-(This code has been abandoned for FreeType2, but until something better
-comes along, should serve our purposes.)
+Bug reports on these files should be sent to the HarfBuzz mailing list as
+listed on http://freedesktop.org/wiki/Software/harfbuzz
 
-This code should be left following the FreeType indentation style and
-coding conventions.
+For license information, see the file COPYING. 
 
-In addition to porting to FreeType-2, it has been modified to
-add support for PangoGlyphString's log_clusters, and in various
-other ways. Bug reports on these files should be sent to 
-gtk-i18n-list@gtk.org, NOT to the freetype maintainers.
-
-The license for these files is in the file FT-license.txt. 
-
-
-Most of the additional files in this directory implement a high-level
-interface to this that follows Pango conventions and integrates with
-Pango.
-
-disasm.[ch] is a partial dumper for OpenType layout tables useful
-in figuring out what is going on. Please extend to cover additional
-parts of the tables as you encounter fonts using them.
-
-Owen Taylor
-17 December 2000
+Behdad Esfahbod
+April 1st, 2006
diff --git a/src/ftglue.c b/src/ftglue.c
index b3fd5b2..5bb7274 100644
--- a/src/ftglue.c
+++ b/src/ftglue.c
@@ -8,15 +8,14 @@
  * See ftglue.h for more information.
  */
 
-#include <config.h>
 #include "ftglue.h"
 
 #if 0
 #include <stdio.h>
-#define  LOG(x)  ftglue_log x
+#define  LOG(x)  _hb_ftglue_log x
 
 static void
-ftglue_log( const char*   format, ... )
+_hb_ftglue_log( const char*   format, ... )
 {
   va_list  ap;
  
@@ -31,7 +30,7 @@
 
 /* only used internally */
 static FT_Pointer
-ftglue_qalloc( FT_Memory  memory,
+_hb_ftglue_qalloc( FT_Memory  memory,
                FT_ULong   size,
                FT_Error  *perror )
 {
@@ -50,11 +49,11 @@
 }
 
 #undef   QALLOC  /* just in case */
-#define  QALLOC(ptr,size)    ( (ptr) = ftglue_qalloc( memory, (size), &error ), error != 0 )
+#define  QALLOC(ptr,size)    ( (ptr) = _hb_ftglue_qalloc( memory, (size), &error ), error != 0 )
 
 
 FTGLUE_APIDEF( FT_Pointer )
-ftglue_alloc( FT_Memory  memory,
+_hb_ftglue_alloc( FT_Memory  memory,
               FT_ULong   size,
               FT_Error  *perror )
 {
@@ -76,7 +75,7 @@
 
 
 FTGLUE_APIDEF( FT_Pointer )
-ftglue_realloc( FT_Memory   memory,
+_hb_ftglue_realloc( FT_Memory   memory,
                 FT_Pointer  block,
                 FT_ULong    old_size,
                 FT_ULong    new_size,
@@ -87,11 +86,11 @@
 
   if ( old_size == 0 || block == NULL )
   {
-    block2 = ftglue_alloc( memory, new_size, &error );
+    block2 = _hb_ftglue_alloc( memory, new_size, &error );
   }
   else if ( new_size == 0 )
   {
-    ftglue_free( memory, block );
+    _hb_ftglue_free( memory, block );
   }
   else
   {
@@ -111,7 +110,7 @@
 
 
 FTGLUE_APIDEF( void )
-ftglue_free( FT_Memory   memory,
+_hb_ftglue_free( FT_Memory   memory,
              FT_Pointer  block )
 {
   if ( block )
@@ -120,7 +119,7 @@
 
 
 FTGLUE_APIDEF( FT_Long )
-ftglue_stream_pos( FT_Stream   stream )
+_hb_ftglue_stream_pos( FT_Stream   stream )
 {
   LOG(( "ftglue:stream:pos() -> %ld\n", stream->pos ));
   return stream->pos;
@@ -128,7 +127,7 @@
 
 
 FTGLUE_APIDEF( FT_Error )
-ftglue_stream_seek( FT_Stream   stream,
+_hb_ftglue_stream_seek( FT_Stream   stream,
                     FT_Long     pos )
 {
   FT_Error  error = 0;
@@ -136,7 +135,7 @@
   stream->pos = pos;
   if ( stream->read )
   {
-    if ( stream->read( stream, pos, 0, 0 ) )
+    if ( stream->read( stream, pos, NULL, 0 ) )
       error = FT_Err_Invalid_Stream_Operation;
   }
   else if ( pos > (FT_Long)stream->size )
@@ -148,7 +147,7 @@
 
 
 FTGLUE_APIDEF( FT_Error )
-ftglue_stream_frame_enter( FT_Stream   stream,
+_hb_ftglue_stream_frame_enter( FT_Stream   stream,
                            FT_ULong    count )
 {
   FT_Error  error = FT_Err_Ok;
@@ -198,7 +197,7 @@
 
 
 FTGLUE_APIDEF( void )
-ftglue_stream_frame_exit( FT_Stream  stream )
+_hb_ftglue_stream_frame_exit( FT_Stream  stream )
 {
   if ( stream->read )
   {
@@ -206,68 +205,21 @@
 
     FREE( stream->base );
   }
-  stream->cursor = 0;
-  stream->limit  = 0;
+  stream->cursor = NULL;
+  stream->limit  = NULL;
 
   LOG(( "ftglue:stream:frame_exit()\n" ));
 }
 
 
-FTGLUE_APIDEF( FT_Byte )
-ftglue_stream_get_byte( FT_Stream  stream )
-{
-  FT_Byte  result = 0;
-
-  if ( stream->cursor < stream->limit )
-    result = *stream->cursor++;
-
-  return result;
-}
-
-
-FTGLUE_APIDEF( FT_Short )
-ftglue_stream_get_short( FT_Stream  stream )
-{
-  FT_Byte*  p;
-  FT_Short  result = 0;
-
-  p = stream->cursor;
-  if ( p + 2 <= stream->limit )
-  {
-    result         = (FT_Short)((p[0] << 8) | p[1]);
-    stream->cursor = p+2;
-  }
-  return result;
-}
-
-
-FTGLUE_APIDEF( FT_Long )
-ftglue_stream_get_long( FT_Stream   stream )
-{
-  FT_Byte*  p;
-  FT_Long   result = 0;
-
-  p = stream->cursor;
-  if ( p + 4 <= stream->limit )
-  {
-    result         = (FT_Long)(((FT_Long)p[0] << 24) |
-                               ((FT_Long)p[1] << 16) |
-                               ((FT_Long)p[2] << 8)  |
-                                         p[3]        );
-    stream->cursor = p+4;
-  }
-  return result;
-}
-
-
 FTGLUE_APIDEF( FT_Error )
-ftglue_face_goto_table( FT_Face    face,
+_hb_ftglue_face_goto_table( FT_Face    face,
                         FT_ULong   the_tag,
                         FT_Stream  stream )
 {
   FT_Error  error;
 
-  LOG(( "ftglue_face_goto_table( %p, %c%c%c%c, %p )\n",
+  LOG(( "_hb_ftglue_face_goto_table( %p, %c%c%c%c, %p )\n",
                 face, 
                 (int)((the_tag >> 24) & 0xFF), 
                 (int)((the_tag >> 16) & 0xFF), 
@@ -331,11 +283,11 @@
       if ( tag == the_tag )
       {
         LOG(( "TrueType table (start: %ld) (size: %ld)\n", start, size ));
-        error = ftglue_stream_seek( stream, offset+start );
+        error = _hb_ftglue_stream_seek( stream, offset+start );
         goto FoundIt;
       }
     }
-    error = TT_Err_Table_Missing;
+    error = FT_Err_Table_Missing;
 
   FoundIt:
     FORGET_Frame();
diff --git a/src/ftglue.h b/src/ftglue.h
index 57c5ebe..84de7f3 100644
--- a/src/ftglue.h
+++ b/src/ftglue.h
@@ -1,4 +1,4 @@
-/* ftglue.c: Glue code for compiling the OpenType code from
+/* ftglue.h: Glue code for compiling the OpenType code from
  *           FreeType 1 using only the public API of FreeType 2
  *
  * By David Turner, The FreeType Project (www.freetype.org)
@@ -40,8 +40,8 @@
  *
  * PS: This "glue" code is explicitely put in the public domain
  */
-#ifndef __OPENTYPE_FTGLUE_H__
-#define __OPENTYPE_FTGLUE_H__
+#ifndef FTGLUE_H
+#define FTGLUE_H
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
@@ -50,10 +50,6 @@
 
 
 /* utility macros */
-#define  TT_Err_Ok                   FT_Err_Ok
-#define  TT_Err_Invalid_Argument     FT_Err_Invalid_Argument
-#define  TT_Err_Invalid_Face_Handle  FT_Err_Invalid_Face_Handle
-#define  TT_Err_Table_Missing        FT_Err_Table_Missing
 
 #define  SET_ERR(c)   ( (error = (c)) != 0 )
 
@@ -66,14 +62,23 @@
 #endif
 
 /* stream macros used by the OpenType parser */
-#define  FILE_Pos()      ftglue_stream_pos( stream )
-#define  FILE_Seek(pos)  SET_ERR( ftglue_stream_seek( stream, pos ) )
-#define  ACCESS_Frame(size)  SET_ERR( ftglue_stream_frame_enter( stream, size ) )
-#define  FORGET_Frame()      ftglue_stream_frame_exit( stream )
+#define  FILE_Pos()      _hb_ftglue_stream_pos( stream )
+#define  FILE_Seek(pos)  SET_ERR( _hb_ftglue_stream_seek( stream, pos ) )
+#define  ACCESS_Frame(size)  SET_ERR( _hb_ftglue_stream_frame_enter( stream, size ) )
+#define  FORGET_Frame()      _hb_ftglue_stream_frame_exit( stream )
 
-#define  GET_Byte()      ftglue_stream_get_byte( stream )
-#define  GET_Short()     ftglue_stream_get_short( stream )
-#define  GET_Long()      ftglue_stream_get_long( stream )
+#define  GET_Byte()      (*stream->cursor++)
+#define  GET_Short()     (stream->cursor += 2, (FT_Short)( \
+				(*(((FT_Byte*)stream->cursor)-2) << 8) | \
+				 *(((FT_Byte*)stream->cursor)-1) \
+			 ))
+#define  GET_Long()      (stream->cursor += 4, (FT_Long)( \
+				(*(((FT_Byte*)stream->cursor)-4) << 24) | \
+				(*(((FT_Byte*)stream->cursor)-3) << 16) | \
+				(*(((FT_Byte*)stream->cursor)-2) << 8) | \
+				 *(((FT_Byte*)stream->cursor)-1) \
+			 ))
+
 
 #define  GET_Char()      ((FT_Char)GET_Byte())
 #define  GET_UShort()    ((FT_UShort)GET_Short())
@@ -81,45 +86,36 @@
 #define  GET_Tag4()      GET_ULong()
 
 FTGLUE_API( FT_Long )
-ftglue_stream_pos( FT_Stream   stream );
+_hb_ftglue_stream_pos( FT_Stream   stream );
 
 FTGLUE_API( FT_Error )
-ftglue_stream_seek( FT_Stream   stream,
+_hb_ftglue_stream_seek( FT_Stream   stream,
                     FT_Long     pos );
 
 FTGLUE_API( FT_Error )
-ftglue_stream_frame_enter( FT_Stream   stream,
+_hb_ftglue_stream_frame_enter( FT_Stream   stream,
                            FT_ULong    size );
 
 FTGLUE_API( void )
-ftglue_stream_frame_exit( FT_Stream  stream );
-
-FTGLUE_API( FT_Byte )
-ftglue_stream_get_byte( FT_Stream  stream );
-
-FTGLUE_API( FT_Short )
-ftglue_stream_get_short( FT_Stream  stream );
-
-FTGLUE_API( FT_Long )
-ftglue_stream_get_long( FT_Stream   stream );
+_hb_ftglue_stream_frame_exit( FT_Stream  stream );
 
 FTGLUE_API( FT_Error )
-ftglue_face_goto_table( FT_Face    face,
+_hb_ftglue_face_goto_table( FT_Face    face,
                         FT_ULong   tag,
                         FT_Stream  stream );
 
 /* memory macros used by the OpenType parser */
 #define  ALLOC(_ptr,_size)   \
-           ( (_ptr) = ftglue_alloc( memory, _size, &error ), error != 0 )
+           ( (_ptr) = _hb_ftglue_alloc( memory, _size, &error ), error != 0 )
 
 #define  REALLOC(_ptr,_oldsz,_newsz)  \
-           ( (_ptr) = ftglue_realloc( memory, (_ptr), (_oldsz), (_newsz), &error ), error != 0 )
+           ( (_ptr) = _hb_ftglue_realloc( memory, (_ptr), (_oldsz), (_newsz), &error ), error != 0 )
 
 #define  FREE(_ptr)                    \
   do {                                 \
     if ( (_ptr) )                      \
     {                                  \
-      ftglue_free( memory, _ptr );     \
+      _hb_ftglue_free( memory, _ptr );     \
       _ptr = NULL;                     \
     }                                  \
   } while (0)
@@ -134,23 +130,21 @@
 
 
 FTGLUE_API( FT_Pointer )
-ftglue_alloc( FT_Memory  memory,
+_hb_ftglue_alloc( FT_Memory  memory,
               FT_ULong   size,
               FT_Error  *perror_ );
 
 FTGLUE_API( FT_Pointer )
-ftglue_realloc( FT_Memory   memory,
+_hb_ftglue_realloc( FT_Memory   memory,
                 FT_Pointer  block,
                 FT_ULong    old_size,
                 FT_ULong    new_size,
                 FT_Error   *perror_ );
 
 FTGLUE_API( void )
-ftglue_free( FT_Memory   memory,
+_hb_ftglue_free( FT_Memory   memory,
              FT_Pointer  block );
 
-/* */
-
 FT_END_HEADER
 
-#endif /* __OPENTYPE_FTGLUE_H__ */
+#endif /* FTGLUE_H */
diff --git a/src/ftxgdef.c b/src/ftxgdef.c
deleted file mode 100644
index 8701b32..0000000
--- a/src/ftxgdef.c
+++ /dev/null
@@ -1,1225 +0,0 @@
-/*******************************************************************
- *
- *  ftxgdef.c
- *
- *    TrueType Open GDEF table support.
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#include <config.h>
-#include "ftxopen.h"
-#include "ftxopenf.h"
-
-#include "ftglue.h"
-
-#include FT_TRUETYPE_TAGS_H
-
-#define TTAG_GDEF  FT_MAKE_TAG( 'G', 'D', 'E', 'F' )
-
-  static FT_Error  Load_AttachList( TTO_AttachList*  al,
-                                    FT_Stream        stream );
-  static FT_Error  Load_LigCaretList( TTO_LigCaretList*  lcl,
-                                      FT_Stream          stream );
-
-  static void  Free_AttachList( TTO_AttachList*  al,
-				FT_Memory        memory );
-  static void  Free_LigCaretList( TTO_LigCaretList*  lcl,
-				  FT_Memory          memory );
-
-  static void  Free_NewGlyphClasses( TTO_GDEFHeader*  gdef,
-				     FT_Memory        memory );
-
-
-
-  /**********************
-   * Extension Functions
-   **********************/
-
-#if 0
-#define GDEF_ID  Build_Extension_ID( 'G', 'D', 'E', 'F' )
-
-
-  static FT_Error  GDEF_Create( void*  ext,
-                                PFace  face )
-  {
-    DEFINE_LOAD_LOCALS( face->stream );
-
-    TTO_GDEFHeader*  gdef = (TTO_GDEFHeader*)ext;
-    Long             table;
-
-
-    /* by convention */
-
-    if ( !gdef )
-      return TT_Err_Ok;
-
-    /* a null offset indicates that there is no GDEF table */
-
-    gdef->offset = 0;
-
-    /* we store the start offset and the size of the subtable */
-
-    table = TT_LookUp_Table( face, TTAG_GDEF );
-    if ( table < 0 )
-      return TT_Err_Ok;             /* The table is optional */
-
-    if ( FILE_Seek( face->dirTables[table].Offset ) ||
-         ACCESS_Frame( 4L ) )
-      return error;
-
-    gdef->offset  = FILE_Pos() - 4L;    /* undo ACCESS_Frame() */
-    gdef->Version = GET_ULong();
-
-    FORGET_Frame();
-
-    gdef->loaded = FALSE;
-
-    return TT_Err_Ok;
-  }
-
-
-  static FT_Error  GDEF_Destroy( void*  ext,
-                                 PFace  face )
-  {
-    TTO_GDEFHeader*  gdef = (TTO_GDEFHeader*)ext;
-
-
-    /* by convention */
-
-    if ( !gdef )
-      return TT_Err_Ok;
-
-    if ( gdef->loaded )
-    {
-      Free_LigCaretList( &gdef->LigCaretList, memory );
-      Free_AttachList( &gdef->AttachList, memory );
-      Free_ClassDefinition( &gdef->GlyphClassDef, memory );
-      Free_ClassDefinition( &gdef->MarkAttachClassDef, memory );
-
-      Free_NewGlyphClasses( gdef, memory );
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_Init_GDEF_Extension( TT_Engine  engine )
-  {
-    PEngine_Instance  _engine = HANDLE_Engine( engine );
-
-
-    if ( !_engine )
-      return TT_Err_Invalid_Engine;
-
-    return  TT_Register_Extension( _engine,
-                                   GDEF_ID,
-                                   sizeof ( TTO_GDEFHeader ),
-                                   GDEF_Create,
-                                   GDEF_Destroy );
-  }
-#endif
-
-  EXPORT_FUNC
-  FT_Error  TT_New_GDEF_Table( FT_Face          face,
-			       TTO_GDEFHeader** retptr )
-  {
-    FT_Error         error;
-    FT_Memory        memory = face->memory;
-
-    TTO_GDEFHeader*  gdef;
-
-    if ( !retptr )
-      return TT_Err_Invalid_Argument;
-
-    if ( ALLOC( gdef, sizeof( *gdef ) ) )
-      return error;
-
-    gdef->memory = face->memory;
-
-    gdef->GlyphClassDef.loaded = FALSE;
-    gdef->AttachList.loaded = FALSE;
-    gdef->LigCaretList.loaded = FALSE;
-    gdef->MarkAttachClassDef_offset = 0;
-    gdef->MarkAttachClassDef.loaded = FALSE;
-
-    gdef->LastGlyph = 0;
-    gdef->NewGlyphClasses = NULL;
-
-    *retptr = gdef;
-
-    return TT_Err_Ok;
-  }
-
-  EXPORT_FUNC
-  FT_Error  TT_Load_GDEF_Table( FT_Face          face,
-                                TTO_GDEFHeader** retptr )
-  {
-    FT_Error         error;
-    FT_Memory        memory = face->memory;
-    FT_Stream        stream = face->stream;
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    TTO_GDEFHeader*  gdef;
-
-
-    if ( !retptr )
-      return TT_Err_Invalid_Argument;
-
-    if (( error = ftglue_face_goto_table( face, TTAG_GDEF, stream ) ))
-      return error;
-
-    if (( error = TT_New_GDEF_Table ( face, &gdef ) ))
-      return error;
-
-    base_offset = FILE_Pos();
-
-    /* skip version */
-
-    if ( FILE_Seek( base_offset + 4L ) ||
-         ACCESS_Frame( 2L ) )
-      goto Fail0;
-
-    new_offset = GET_UShort();
-
-    FORGET_Frame();
-
-    /* all GDEF subtables are optional */
-
-    if ( new_offset )
-    {
-      new_offset += base_offset;
-
-      /* only classes 1-4 are allowed here */
-
-      cur_offset = FILE_Pos();
-      if ( FILE_Seek( new_offset ) ||
-           ( error = Load_ClassDefinition( &gdef->GlyphClassDef, 5,
-                                           stream ) ) != TT_Err_Ok )
-        goto Fail0;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    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 = Load_AttachList( &gdef->AttachList,
-                                      stream ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    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 = Load_LigCaretList( &gdef->LigCaretList,
-                                        stream ) ) != TT_Err_Ok )
-        goto Fail2;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    /* OpenType 1.2 has introduced the `MarkAttachClassDef' field.  We
-       first have to scan the LookupFlag values to find out whether we
-       must load it or not.  Here we only store the offset of the table. */
-
-    if ( ACCESS_Frame( 2L ) )
-      goto Fail3;
-
-    new_offset = GET_UShort();
-
-    FORGET_Frame();
-
-    if ( new_offset )
-      gdef->MarkAttachClassDef_offset = new_offset + base_offset;
-    else
-      gdef->MarkAttachClassDef_offset = 0;
-
-    *retptr = gdef;
-
-    return TT_Err_Ok;
-
-  Fail3:
-    Free_LigCaretList( &gdef->LigCaretList, memory );
-    
-  Fail2:
-    Free_AttachList( &gdef->AttachList, memory );
-
-  Fail1:
-    Free_ClassDefinition( &gdef->GlyphClassDef, memory );
-
-  Fail0:
-    FREE( gdef );
-
-    return error;
-  }
-
-  EXPORT_FUNC
-  FT_Error  TT_Done_GDEF_Table ( TTO_GDEFHeader* gdef ) 
-  {
-    FT_Memory memory = gdef->memory;
-    
-    Free_LigCaretList( &gdef->LigCaretList, memory );
-    Free_AttachList( &gdef->AttachList, memory );
-    Free_ClassDefinition( &gdef->GlyphClassDef, memory );
-    Free_ClassDefinition( &gdef->MarkAttachClassDef, memory );
-    
-    Free_NewGlyphClasses( gdef, memory );
-
-    FREE( gdef );
-
-    return TT_Err_Ok;
-  }
-
-
-
-
-  /*******************************
-   * AttachList related functions
-   *******************************/
-
-
-  /* AttachPoint */
-
-  static FT_Error  Load_AttachPoint( TTO_AttachPoint*  ap,
-                                     FT_Stream         stream )
-  {
-    FT_Memory memory = stream->memory;
-    FT_Error  error;
-
-    FT_UShort   n, count;
-    FT_UShort*  pi;
-
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    count = ap->PointCount = GET_UShort();
-
-    FORGET_Frame();
-
-    ap->PointIndex = NULL;
-
-    if ( count )
-    {
-      if ( ALLOC_ARRAY( ap->PointIndex, count, FT_UShort ) )
-        return error;
-
-      pi = ap->PointIndex;
-
-      if ( ACCESS_Frame( count * 2L ) )
-      {
-        FREE( pi );
-        return error;
-      }
-
-      for ( n = 0; n < count; n++ )
-        pi[n] = GET_UShort();
-
-      FORGET_Frame();
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  static void  Free_AttachPoint( TTO_AttachPoint*  ap,
-				 FT_Memory        memory )
-  {
-    FREE( ap->PointIndex );
-  }
-
-
-  /* AttachList */
-
-  static FT_Error  Load_AttachList( TTO_AttachList*  al,
-                                    FT_Stream        stream )
-  {
-    FT_Memory memory = stream->memory;
-    FT_Error  error;
-
-    FT_UShort         n, m, count;
-    FT_ULong          cur_offset, new_offset, base_offset;
-
-    TTO_AttachPoint*  ap;
-
-
-    base_offset = FILE_Pos();
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    new_offset = GET_UShort() + base_offset;
-
-    FORGET_Frame();
-
-    cur_offset = FILE_Pos();
-    if ( FILE_Seek( new_offset ) ||
-         ( error = Load_Coverage( &al->Coverage, stream ) ) != TT_Err_Ok )
-      return error;
-    (void)FILE_Seek( cur_offset );
-
-    if ( ACCESS_Frame( 2L ) )
-      goto Fail2;
-
-    count = al->GlyphCount = GET_UShort();
-
-    FORGET_Frame();
-
-    al->AttachPoint = NULL;
-
-    if ( ALLOC_ARRAY( al->AttachPoint, count, TTO_AttachPoint ) )
-      goto Fail2;
-
-    ap = al->AttachPoint;
-
-    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_AttachPoint( &ap[n], stream ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    al->loaded = TRUE;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_AttachPoint( &ap[m], memory );
-
-    FREE( ap );
-
-  Fail2:
-    Free_Coverage( &al->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_AttachList( TTO_AttachList*  al,
-				FT_Memory        memory )
-  {
-    FT_UShort         n, count;
-
-    TTO_AttachPoint*  ap;
-
-
-    if ( !al->loaded )
-      return;
-
-    if ( al->AttachPoint )
-    {
-      count = al->GlyphCount;
-      ap    = al->AttachPoint;
-
-      for ( n = 0; n < count; n++ )
-        Free_AttachPoint( &ap[n], memory );
-
-      FREE( ap );
-    }
-
-    Free_Coverage( &al->Coverage, memory );
-  }
-
-
-
-  /*********************************
-   * LigCaretList related functions
-   *********************************/
-
-
-  /* CaretValueFormat1 */
-  /* CaretValueFormat2 */
-  /* CaretValueFormat3 */
-  /* CaretValueFormat4 */
-
-  static FT_Error  Load_CaretValue( TTO_CaretValue*  cv,
-                                    FT_Stream        stream )
-  {
-    FT_Error  error;
-
-    FT_ULong cur_offset, new_offset, base_offset;
-
-
-    base_offset = FILE_Pos();
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    cv->CaretValueFormat = GET_UShort();
-
-    FORGET_Frame();
-
-    switch ( cv->CaretValueFormat )
-    {
-    case 1:
-      if ( ACCESS_Frame( 2L ) )
-        return error;
-
-      cv->cvf.cvf1.Coordinate = GET_Short();
-
-      FORGET_Frame();
-
-      break;
-
-    case 2:
-      if ( ACCESS_Frame( 2L ) )
-        return error;
-
-      cv->cvf.cvf2.CaretValuePoint = GET_UShort();
-
-      FORGET_Frame();
-
-      break;
-
-    case 3:
-      if ( ACCESS_Frame( 4L ) )
-        return error;
-
-      cv->cvf.cvf3.Coordinate = GET_Short();
-
-      new_offset = GET_UShort() + base_offset;
-
-      FORGET_Frame();
-
-      cur_offset = FILE_Pos();
-      if ( FILE_Seek( new_offset ) ||
-           ( error = Load_Device( &cv->cvf.cvf3.Device,
-                                  stream ) ) != TT_Err_Ok )
-        return error;
-      (void)FILE_Seek( cur_offset );
-
-      break;
-
-    case 4:
-      if ( ACCESS_Frame( 2L ) )
-        return error;
-
-      cv->cvf.cvf4.IdCaretValue = GET_UShort();
-
-      FORGET_Frame();
-      break;
-
-    default:
-      return TTO_Err_Invalid_GDEF_SubTable_Format;
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  static void  Free_CaretValue( TTO_CaretValue*  cv,
-				FT_Memory        memory )
-  {
-    if ( cv->CaretValueFormat == 3 )
-      Free_Device( &cv->cvf.cvf3.Device, memory );
-  }
-
-
-  /* LigGlyph */
-
-  static FT_Error  Load_LigGlyph( TTO_LigGlyph*  lg,
-                                  FT_Stream      stream )
-  {
-    FT_Memory memory = stream->memory;
-    FT_Error  error;
-
-    FT_UShort        n, m, count;
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    TTO_CaretValue*  cv;
-
-
-    base_offset = FILE_Pos();
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    count = lg->CaretCount = GET_UShort();
-
-    FORGET_Frame();
-
-    lg->CaretValue = NULL;
-
-    if ( ALLOC_ARRAY( lg->CaretValue, count, TTO_CaretValue ) )
-      return error;
-
-    cv = lg->CaretValue;
-
-    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_CaretValue( &cv[n], stream ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_CaretValue( &cv[m], memory );
-
-    FREE( cv );
-    return error;
-  }
-
-
-  static void  Free_LigGlyph( TTO_LigGlyph*  lg,
-			      FT_Memory      memory )
-  {
-    FT_UShort        n, count;
-
-    TTO_CaretValue*  cv;
-
-
-    if ( lg->CaretValue )
-    {
-      count = lg->CaretCount;
-      cv    = lg->CaretValue;
-
-      for ( n = 0; n < count; n++ )
-        Free_CaretValue( &cv[n], memory );
-
-      FREE( cv );
-    }
-  }
-
-
-  /* LigCaretList */
-
-  static FT_Error  Load_LigCaretList( TTO_LigCaretList*  lcl,
-                                      FT_Stream          stream )
-  {
-    FT_Memory memory = stream->memory;
-    FT_Error  error;
-
-    FT_UShort      m, n, count;
-    FT_ULong       cur_offset, new_offset, base_offset;
-
-    TTO_LigGlyph*  lg;
-
-
-    base_offset = FILE_Pos();
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    new_offset = GET_UShort() + base_offset;
-
-    FORGET_Frame();
-
-    cur_offset = FILE_Pos();
-    if ( FILE_Seek( new_offset ) ||
-         ( error = Load_Coverage( &lcl->Coverage, stream ) ) != TT_Err_Ok )
-      return error;
-    (void)FILE_Seek( cur_offset );
-
-    if ( ACCESS_Frame( 2L ) )
-      goto Fail2;
-
-    count = lcl->LigGlyphCount = GET_UShort();
-
-    FORGET_Frame();
-
-    lcl->LigGlyph = NULL;
-
-    if ( ALLOC_ARRAY( lcl->LigGlyph, count, TTO_LigGlyph ) )
-      goto Fail2;
-
-    lg = lcl->LigGlyph;
-
-    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_LigGlyph( &lg[n], stream ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    lcl->loaded = TRUE;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_LigGlyph( &lg[m], memory );
-
-    FREE( lg );
-
-  Fail2:
-    Free_Coverage( &lcl->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_LigCaretList( TTO_LigCaretList*  lcl,
-				  FT_Memory           memory )
-  {
-    FT_UShort      n, count;
-
-    TTO_LigGlyph*  lg;
-
-
-    if ( !lcl->loaded )
-      return;
-
-    if ( lcl->LigGlyph )
-    {
-      count = lcl->LigGlyphCount;
-      lg    = lcl->LigGlyph;
-
-      for ( n = 0; n < count; n++ )
-        Free_LigGlyph( &lg[n], memory );
-
-      FREE( lg );
-    }
-
-    Free_Coverage( &lcl->Coverage, memory );
-  }
-
-
-
-  /***********
-   * GDEF API
-   ***********/
-
-
-  static FT_UShort  Get_New_Class( TTO_GDEFHeader*  gdef,
-				   FT_UShort        glyphID,
-				   FT_UShort        index )
-  {
-    FT_UShort              glyph_index, array_index, count;
-    FT_UShort              byte, bits;
-    
-    TTO_ClassRangeRecord*  gcrr;
-    FT_UShort**            ngc;
-
-
-    if ( glyphID >= gdef->LastGlyph )
-      return 0;
-
-    count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
-    gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
-    ngc  = gdef->NewGlyphClasses;
-
-    if ( index < count && glyphID < gcrr[index].Start )
-    {
-      array_index = index;
-      if ( index == 0 )
-        glyph_index = glyphID;
-      else
-        glyph_index = glyphID - gcrr[index - 1].End - 1;
-    }
-    else
-    {
-      array_index = index + 1;
-      glyph_index = glyphID - gcrr[index].End - 1;
-    }
-
-    byte = ngc[array_index][glyph_index / 4];
-    bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
-
-    return bits & 0x000F;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader*  gdef,
-                                        FT_UShort        glyphID,
-                                        FT_UShort*       property )
-  {
-    FT_UShort class, index;
-
-    FT_Error  error;
-
-
-    if ( !gdef || !property )
-      return TT_Err_Invalid_Argument;
-
-    /* first, we check for mark attach classes */
-
-    if ( gdef->MarkAttachClassDef.loaded )
-    {
-      error = Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index );
-      if ( error && error != TTO_Err_Not_Covered )
-        return error;
-      if ( !error )
-      {
-        *property = class << 8;
-        return TT_Err_Ok;
-      }
-    }
-
-    error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
-    if ( error && error != TTO_Err_Not_Covered )
-      return error;
-
-    /* if we have a constructed class table, check whether additional
-       values have been assigned                                      */
-
-    if ( error == TTO_Err_Not_Covered && gdef->NewGlyphClasses )
-      class = Get_New_Class( gdef, glyphID, index );
-
-    switch ( class )
-    {
-    case UNCLASSIFIED_GLYPH:
-      *property = 0;
-      break;
-
-    case SIMPLE_GLYPH:
-      *property = TTO_BASE_GLYPH;
-      break;
-
-    case LIGATURE_GLYPH:
-      *property = TTO_LIGATURE;
-      break;
-
-    case MARK_GLYPH:
-      *property = TTO_MARK;
-      break;
-
-    case COMPONENT_GLYPH:
-      *property = TTO_COMPONENT;
-      break;
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  static FT_Error  Make_ClassRange( TTO_ClassDefinition*  cd,
-                                    FT_UShort             start,
-                                    FT_UShort             end,
-                                    FT_UShort             class,
-				    FT_Memory             memory )
-  {
-    FT_Error               error;
-    FT_UShort              index;
-
-    TTO_ClassDefFormat2*   cdf2;
-    TTO_ClassRangeRecord*  crr;
-
-
-    cdf2 = &cd->cd.cd2;
-
-    if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
-			cdf2->ClassRangeCount,
-			cdf2->ClassRangeCount + 1 ,
-                        TTO_ClassRangeRecord ) )
-      return error;
-
-    cdf2->ClassRangeCount++;
-
-    crr   = cdf2->ClassRangeRecord;
-    index = cdf2->ClassRangeCount - 1;
-
-    crr[index].Start = start;
-    crr[index].End   = end;
-    crr[index].Class = class;
-
-    cd->Defined[class] = TRUE;
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader*  gdef,
-                                           FT_UShort        num_glyphs,
-                                           FT_UShort        glyph_count,
-                                           FT_UShort*       glyph_array,
-                                           FT_UShort*       class_array )
-  {
-    FT_UShort              start, curr_glyph, curr_class;
-    FT_UShort              n, m, count;
-    FT_Error               error;
-    FT_Memory              memory = gdef->memory;
-
-    TTO_ClassDefinition*   gcd;
-    TTO_ClassRangeRecord*  gcrr;
-    FT_UShort**            ngc;
-
-
-    if ( !gdef || !glyph_array || !class_array )
-      return TT_Err_Invalid_Argument;
-
-    gcd = &gdef->GlyphClassDef;
-
-    /* We build a format 2 table */
-
-    gcd->ClassFormat = 2;
-
-    /* A GlyphClassDef table contains at most 5 different class values */
-
-    if ( ALLOC_ARRAY( gcd->Defined, 5, FT_Bool ) )
-      return error;
-
-    gcd->cd.cd2.ClassRangeCount  = 0;
-    gcd->cd.cd2.ClassRangeRecord = NULL;
-
-    start      = glyph_array[0];
-    curr_class = class_array[0];
-    curr_glyph = start;
-
-    if ( curr_class >= 5 )
-    {
-      error = TT_Err_Invalid_Argument;
-      goto Fail4;
-    }
-
-    glyph_count--;
-
-    for ( n = 0; n <= glyph_count; n++ )
-    {
-      if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
-      {
-        if ( n == glyph_count )
-        {
-          if ( ( error = Make_ClassRange( gcd, start,
-                                          curr_glyph,
-                                          curr_class,
-					  memory ) ) != TT_Err_Ok )
-            goto Fail3;
-        }
-        else
-        {
-          if ( curr_glyph == 0xFFFF )
-          {
-            error = TT_Err_Invalid_Argument;
-            goto Fail3;
-          }
-          else
-            curr_glyph++;
-        }
-      }
-      else
-      {
-        if ( ( error = Make_ClassRange( gcd, start,
-                                        curr_glyph - 1,
-                                        curr_class,
-					memory ) ) != TT_Err_Ok )
-          goto Fail3;
-
-        if ( curr_glyph > glyph_array[n] )
-        {
-          error = TT_Err_Invalid_Argument;
-          goto Fail3;
-        }
-
-        start      = glyph_array[n];
-        curr_class = class_array[n];
-        curr_glyph = start;
-
-        if ( curr_class >= 5 )
-        {
-          error = TT_Err_Invalid_Argument;
-          goto Fail3;
-        }
-
-        if ( n == glyph_count )
-        {
-          if ( ( error = Make_ClassRange( gcd, start,
-                                          curr_glyph,
-                                          curr_class,
-					  memory ) ) != TT_Err_Ok )
-            goto Fail3;
-        }
-        else
-        {
-          if ( curr_glyph == 0xFFFF )
-          {
-            error = TT_Err_Invalid_Argument;
-            goto Fail3;
-          }
-          else
-            curr_glyph++;
-        }
-      }
-    }
-
-    /* now prepare the arrays for class values assigned during the lookup
-       process                                                            */
-
-    if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
-                      gcd->cd.cd2.ClassRangeCount + 1, FT_UShort* ) )
-      goto Fail3;
-
-    count = gcd->cd.cd2.ClassRangeCount;
-    gcrr  = gcd->cd.cd2.ClassRangeRecord;
-    ngc   = gdef->NewGlyphClasses;
-
-    /* We allocate arrays for all glyphs not covered by the class range
-       records.  Each element holds four class values.                  */
-
-    if ( count > 0 )
-    {
-	if ( gcrr[0].Start )
-	{
-	  if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, FT_UShort ) )
-	    goto Fail2;
-	}
-
-	for ( n = 1; n < count; n++ )
-	{
-	  if ( gcrr[n].Start - gcrr[n - 1].End > 1 )
-	    if ( ALLOC_ARRAY( ngc[n],
-			      ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4,
-			      FT_UShort ) )
-	      goto Fail1;
-	}
-
-	if ( gcrr[count - 1].End != num_glyphs - 1 )
-	{
-	  if ( ALLOC_ARRAY( ngc[count],
-			    ( num_glyphs - gcrr[count - 1].End + 2 ) / 4,
-			    FT_UShort ) )
-	      goto Fail1;
-	}
-    }
-    else if ( num_glyphs > 0 )
-    {
-	if ( ALLOC_ARRAY( ngc[count],
-			  ( num_glyphs + 3 ) / 4,
-			  FT_UShort ) )
-	    goto Fail2;
-    }
-	
-    gdef->LastGlyph = num_glyphs - 1;
-
-    gdef->MarkAttachClassDef_offset = 0L;
-    gdef->MarkAttachClassDef.loaded = FALSE;
-
-    gcd->loaded = TRUE;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      FREE( ngc[m] );
-
-  Fail2:
-    FREE( gdef->NewGlyphClasses );
-
-  Fail3:
-    FREE( gcd->cd.cd2.ClassRangeRecord );
-
-  Fail4:
-    FREE( gcd->Defined );
-    return error;
-  }
-
-
-  static void  Free_NewGlyphClasses( TTO_GDEFHeader*  gdef,
-				     FT_Memory        memory )
-  {
-    FT_UShort**  ngc;
-    FT_UShort    n, count;
-
-
-    if ( gdef->NewGlyphClasses )
-    {
-      count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
-      ngc   = gdef->NewGlyphClasses;
-
-      for ( n = 0; n < count; n++ )
-        FREE( ngc[n] );
-
-      FREE( ngc );
-    }
-  }
-
-
-  FT_Error  Add_Glyph_Property( TTO_GDEFHeader*  gdef,
-                                FT_UShort        glyphID,
-                                FT_UShort        property )
-  {
-    FT_Error               error;
-    FT_UShort              class, new_class, index;
-    FT_UShort              byte, bits, mask;
-    FT_UShort              array_index, glyph_index, count;
-
-    TTO_ClassRangeRecord*  gcrr;
-    FT_UShort**            ngc;
-
-
-    error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
-    if ( error && error != TTO_Err_Not_Covered )
-      return error;
-
-    /* we don't accept glyphs covered in `GlyphClassDef' */
-
-    if ( !error )
-      return TTO_Err_Not_Covered;
-
-    switch ( property )
-    {
-    case 0:
-      new_class = UNCLASSIFIED_GLYPH;
-      break;
-
-    case TTO_BASE_GLYPH:
-      new_class = SIMPLE_GLYPH;
-      break;
-
-    case TTO_LIGATURE:
-      new_class = LIGATURE_GLYPH;
-      break;
-
-    case TTO_MARK:
-      new_class = MARK_GLYPH;
-      break;
-
-    case TTO_COMPONENT:
-      new_class = COMPONENT_GLYPH;
-      break;
-
-    default:
-      return TT_Err_Invalid_Argument;
-    }
-
-    count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
-    gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
-    ngc  = gdef->NewGlyphClasses;
-
-    if ( index < count && glyphID < gcrr[index].Start )
-    {
-      array_index = index;
-      if ( index == 0 )
-        glyph_index = glyphID;
-      else
-        glyph_index = glyphID - gcrr[index - 1].End - 1;
-    }
-    else
-    {
-      array_index = index + 1;
-      glyph_index = glyphID - gcrr[index].End - 1;
-    }
-
-    byte  = ngc[array_index][glyph_index / 4];
-    bits  = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
-    class = bits & 0x000F;
-
-    /* we don't overwrite existing entries */
-
-    if ( !class )
-    {
-      bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
-      mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
-
-      ngc[array_index][glyph_index / 4] &= mask;
-      ngc[array_index][glyph_index / 4] |= bits;
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  FT_Error  Check_Property( TTO_GDEFHeader*  gdef,
-			    OTL_GlyphItem    gitem,
-                            FT_UShort        flags,
-                            FT_UShort*       property )
-  {
-    FT_Error  error;
-
-    if ( gdef )
-    {
-      FT_UShort basic_glyph_class;
-      FT_UShort desired_attachment_class;
-
-      if ( gitem->gproperties == OTL_GLYPH_PROPERTIES_UNKNOWN )
-      {
-	error = TT_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
-	if ( error )
-	  return error;
-      }
-
-      *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 & IGNORE_SPECIAL_MARKS  )
-	basic_glyph_class = TTO_MARK;
-      else
-	basic_glyph_class = *property;
-
-      /* Return Not_Covered, if, for example, basic_glyph_class
-       * is TTO_LIGATURE and LookFlags includes IGNORE_LIGATURES
-       */
-      if ( flags & basic_glyph_class )
-	return TTO_Err_Not_Covered;
-      
-      /* The high byte of LookupFlags has the meaning
-       * "ignore marks of attachment type different than
-       * the attachment type specified."
-       */
-      desired_attachment_class = flags & IGNORE_SPECIAL_MARKS;
-      if ( desired_attachment_class )
-      {
-	if ( basic_glyph_class == TTO_MARK &&
-	     *property != desired_attachment_class )
-	  return TTO_Err_Not_Covered;
-      }
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-/* END */
diff --git a/src/ftxgdef.h b/src/ftxgdef.h
deleted file mode 100644
index f22438e..0000000
--- a/src/ftxgdef.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*******************************************************************
- *
- *  ftxgdef.h
- *
- *    TrueType Open GDEF table support
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#ifndef FTXOPEN_H
-#error "Don't include this file! Use ftxopen.h instead."
-#endif
-
-#ifndef FTXGDEF_H
-#define FTXGDEF_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define TTO_Err_Invalid_GDEF_SubTable_Format  0x1030
-#define TTO_Err_Invalid_GDEF_SubTable         0x1031
-
-
-/* GDEF glyph classes */
-
-#define UNCLASSIFIED_GLYPH  0
-#define SIMPLE_GLYPH        1
-#define LIGATURE_GLYPH      2
-#define MARK_GLYPH          3
-#define COMPONENT_GLYPH     4
-
-/* GDEF glyph properties, corresponding to class values 1-4.  Note that
-   TTO_COMPONENT has no corresponding flag in the LookupFlag field.     */
-
-#define TTO_BASE_GLYPH  0x0002
-#define TTO_LIGATURE    0x0004
-#define TTO_MARK        0x0008
-#define TTO_COMPONENT   0x0010
-
-
-  /* Attachment related structures */
-
-  struct  TTO_AttachPoint_
-  {
-    FT_UShort   PointCount;             /* size of the PointIndex array */
-    FT_UShort*  PointIndex;             /* array of contour points      */
-  };
-
-  typedef struct TTO_AttachPoint_  TTO_AttachPoint;
-
-
-  struct  TTO_AttachList_
-  {
-    FT_Bool           loaded;
-
-    TTO_Coverage      Coverage;         /* Coverage table              */
-    FT_UShort         GlyphCount;       /* number of glyphs with
-                                           attachments                 */
-    TTO_AttachPoint*  AttachPoint;      /* array of AttachPoint tables */
-  };
-
-  typedef struct TTO_AttachList_  TTO_AttachList;
-
-
-  /* Ligature Caret related structures */
-
-  struct  TTO_CaretValueFormat1_
-  {
-    FT_Short  Coordinate;               /* x or y value (in design units) */
-  };
-
-  typedef struct TTO_CaretValueFormat1_  TTO_CaretValueFormat1;
-
-
-  struct  TTO_CaretValueFormat2_
-  {
-    FT_UShort  CaretValuePoint;         /* contour point index on glyph */
-  };
-
-  typedef struct TTO_CaretValueFormat2_  TTO_CaretValueFormat2;
-
-
-  struct  TTO_CaretValueFormat3_
-  {
-    FT_Short    Coordinate;             /* x or y value (in design units) */
-    TTO_Device  Device;                 /* Device table for x or y value  */
-  };
-
-  typedef struct TTO_CaretValueFormat3_  TTO_CaretValueFormat3;
-
-
-  struct  TTO_CaretValueFormat4_
-  {
-    FT_UShort  IdCaretValue;            /* metric ID */
-  };
-
-  typedef struct TTO_CaretValueFormat4_  TTO_CaretValueFormat4;
-
-
-  struct  TTO_CaretValue_
-  {
-    FT_UShort  CaretValueFormat;        /* 1, 2, 3, or 4 */
-
-    union
-    {
-      TTO_CaretValueFormat1  cvf1;
-      TTO_CaretValueFormat2  cvf2;
-      TTO_CaretValueFormat3  cvf3;
-      TTO_CaretValueFormat4  cvf4;
-    } cvf;
-  };
-
-  typedef struct TTO_CaretValue_  TTO_CaretValue;
-
-
-  struct  TTO_LigGlyph_
-  {
-    FT_Bool          loaded;
-
-    FT_UShort        CaretCount;        /* number of caret values */
-    TTO_CaretValue*  CaretValue;        /* array of caret values  */
-  };
-
-  typedef struct TTO_LigGlyph_  TTO_LigGlyph;
-
-
-  struct  TTO_LigCaretList_
-  {
-    FT_Bool        loaded;
-
-    TTO_Coverage   Coverage;            /* Coverage table            */
-    FT_UShort      LigGlyphCount;       /* number of ligature glyphs */
-    TTO_LigGlyph*  LigGlyph;            /* array of LigGlyph tables  */
-  };
-
-  typedef struct TTO_LigCaretList_  TTO_LigCaretList;
-
-
-  /* The `NewGlyphClasses' field is not defined in the TTO specification.
-     We use it for fonts with a constructed `GlyphClassDef' structure
-     (i.e., which don't have a GDEF table) to collect glyph classes
-     assigned during the lookup process.  The number of arrays in this
-     pointer array is GlyphClassDef->cd.cd2.ClassRangeCount+1; the nth
-     array then contains the glyph class values of the glyphs not covered
-     by the ClassRangeRecords structures with index n-1 and n.  We store
-     glyph class values for four glyphs in a single array element.
-
-     `LastGlyph' is identical to the number of glyphs minus one in the
-     font; we need it only if `NewGlyphClasses' is not NULL (to have an
-     upper bound for the last array).
-
-     Note that we first store the file offset to the `MarkAttachClassDef'
-     field (which has been introduced in OpenType 1.2) -- since the
-     `Version' field value hasn't been increased to indicate that we have
-     one more field for some obscure reason, we must parse the GSUB table
-     to find out whether class values refer to this table.  Only then we
-     can finally load the MarkAttachClassDef structure if necessary.      */
-
-  struct  TTO_GDEFHeader_
-  {
-    FT_Memory            memory;
-    FT_ULong             offset;
-
-    FT_Fixed             Version;
-
-    TTO_ClassDefinition  GlyphClassDef;
-    TTO_AttachList       AttachList;
-    TTO_LigCaretList     LigCaretList;
-    FT_ULong             MarkAttachClassDef_offset;
-    TTO_ClassDefinition  MarkAttachClassDef;        /* new in OT 1.2 */
-
-    FT_UShort            LastGlyph;
-    FT_UShort**          NewGlyphClasses;
-  };
-
-  typedef struct TTO_GDEFHeader_   TTO_GDEFHeader;
-  typedef struct TTO_GDEFHeader_*  TTO_GDEF;
-
-
-  /* finally, the GDEF API */
-
-  /*  EXPORT_DEF
-      FT_Error  TT_Init_GDEF_Extension( TT_Engine  engine ); */
-
-  EXPORT_FUNC
-  FT_Error  TT_New_GDEF_Table( FT_Face          face,
-			       TTO_GDEFHeader** retptr );
-	
-  EXPORT_DEF
-  FT_Error  TT_Load_GDEF_Table( FT_Face          face,
-                                TTO_GDEFHeader** gdef );
-
-  EXPORT_DEF
-  FT_Error  TT_Done_GDEF_Table ( TTO_GDEFHeader* gdef );
-
-  EXPORT_DEF
-  FT_Error  TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader*  gdef,
-                                        FT_UShort        glyphID,
-                                        FT_UShort*       property );
-  EXPORT_DEF
-  FT_Error  TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader*  gdef,
-                                           FT_UShort        num_glyphs,
-                                           FT_UShort        glyph_count,
-                                           FT_UShort*       glyph_array,
-                                           FT_UShort*       class_array );
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FTXGDEF_H */
-
-
-/* END */
diff --git a/src/ftxgpos.c b/src/ftxgpos.c
deleted file mode 100644
index 69efd07..0000000
--- a/src/ftxgpos.c
+++ /dev/null
@@ -1,6199 +0,0 @@
-/*******************************************************************
- *
- *  ftxgpos.c
- *
- *    TrueType Open GPOS table support.
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#include <config.h>
-
-/* XXX There is *a lot* of duplicated code (cf. formats 7 and 8), but
-       I don't care currently.  I believe that it would be possible to
-       save about 50% of TTO code by carefully designing the structures,
-       sharing as much as possible with extensive use of macros.  This
-       is something for a volunteer :-)                                  */
-
-#include "ftxopen.h"
-#include "ftxopenf.h"
-
-#include "ftglue.h"
-
-#include FT_TRUETYPE_TAGS_H
-
-#define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
-
-  struct  GPOS_Instance_
-  {
-    TTO_GPOSHeader*  gpos;
-    FT_Face          face;
-    FT_Bool          dvi;
-    FT_UShort        load_flags;  /* how the glyph should be loaded */
-    FT_Bool          r2l;
-
-    FT_UShort        last;        /* the last valid glyph -- used
-                                     with cursive positioning     */
-    FT_Pos           anchor_x;    /* the coordinates of the anchor point */
-    FT_Pos           anchor_y;    /* of the last valid glyph             */
-  };
-
-  typedef struct GPOS_Instance_  GPOS_Instance;
-
-
-  static FT_Error  Do_Glyph_Lookup( GPOS_Instance*    gpi,
-                                    FT_UShort         lookup_index,
-				    OTL_Buffer        buffer,
-                                    FT_UShort         context_length,
-                                    int               nesting_level );
-
-
-#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)])
-
-/* the client application must replace this with something more
-     meaningful if multiple master fonts are to be supported.     */
-
-  static FT_Error  default_mmfunc( FT_Face      face,
-                                   FT_UShort    metric_id,
-                                   FT_Pos*      metric_value,
-                                   void*        data )
-  {
-    return TTO_Err_No_MM_Interpreter;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_Load_GPOS_Table( FT_Face          face,
-                                TTO_GPOSHeader** retptr,
-                                TTO_GDEFHeader*  gdef )
-  {
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    FT_UShort        i, num_lookups;
-    TTO_GPOSHeader*  gpos;
-    TTO_Lookup*      lo;
-
-    FT_Stream  stream = face->stream;
-    FT_Error   error;
-    FT_Memory  memory = face->memory;
-
-
-    if ( !retptr )
-      return TT_Err_Invalid_Argument;
-
-    if ( !stream )
-      return TT_Err_Invalid_Face_Handle;
-
-    if (( error = ftglue_face_goto_table( face, TTAG_GPOS, stream ) ))
-      return error;
-
-    base_offset = FILE_Pos();
-
-    if ( ALLOC ( gpos, sizeof( *gpos ) ) )
-      return error;
-
-    gpos->memory = memory;
-    gpos->gfunc = 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 = Load_ScriptList( &gpos->ScriptList,
-                                    stream ) ) != TT_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 = Load_FeatureList( &gpos->FeatureList,
-                                     stream ) ) != TT_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 = Load_LookupList( &gpos->LookupList,
-                                    stream, GPOS ) ) != TT_Err_Ok )
-      goto Fail2;
-
-    gpos->gdef = gdef;      /* can be NULL */
-
-    /* We now check the LookupFlags for values larger than 0xFF to find
-       out whether we need to load the `MarkAttachClassDef' field of the
-       GDEF table -- this hack is necessary for OpenType 1.2 tables since
-       the version field of the GDEF table hasn't been incremented.
-
-       For constructed GDEF tables, we only load it if
-       `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
-       a constructed mark attach table is not supported currently).       */
-
-    if ( gdef &&
-         gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
-    {
-      lo          = gpos->LookupList.Lookup;
-      num_lookups = gpos->LookupList.LookupCount;
-
-      for ( i = 0; i < num_lookups; i++ )
-      {
-        if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
-        {
-          if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
-               ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
-                                               256, stream ) ) != TT_Err_Ok )
-            goto Fail1;
-
-          break;
-        }
-      }
-    }
-
-    *retptr = gpos;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    Free_LookupList( &gpos->LookupList, GPOS, memory );
-
-  Fail2:
-    Free_FeatureList( &gpos->FeatureList, memory );
-
-  Fail3:
-    Free_ScriptList( &gpos->ScriptList, memory );
-
-  Fail4:
-    FREE( gpos );
-
-    return error;
-  }
-
-  EXPORT_FUNC
-  FT_Error  TT_Done_GPOS_Table( TTO_GPOSHeader* gpos )
-  {
-    FT_Memory memory = gpos->memory;
-    
-    Free_LookupList( &gpos->LookupList, GPOS, memory );
-    Free_FeatureList( &gpos->FeatureList, memory );
-    Free_ScriptList( &gpos->ScriptList, memory );
-
-    return FT_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 FT_Error  Load_ValueRecord( TTO_ValueRecord*  vr,
-                                     FT_UShort         format,
-                                     FT_ULong          base_offset,
-                                     FT_Stream         stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-    
-    FT_ULong cur_offset, new_offset;
-
-
-    if ( format & HAVE_X_PLACEMENT )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        return error;
-
-      vr->XPlacement = GET_Short();
-
-      FORGET_Frame();
-    }
-    else
-      vr->XPlacement = 0;
-
-    if ( format & HAVE_Y_PLACEMENT )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        return error;
-
-      vr->YPlacement = GET_Short();
-
-      FORGET_Frame();
-    }
-    else
-      vr->YPlacement = 0;
-
-    if ( format & HAVE_X_ADVANCE )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        return error;
-
-      vr->XAdvance = GET_Short();
-
-      FORGET_Frame();
-    }
-    else
-      vr->XAdvance = 0;
-
-    if ( format & HAVE_Y_ADVANCE )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        return error;
-
-      vr->YAdvance = GET_Short();
-
-      FORGET_Frame();
-    }
-    else
-      vr->YAdvance = 0;
-
-    if ( 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 = Load_Device( &vr->XPlacementDevice,
-                                    stream ) ) != TT_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 & 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 = Load_Device( &vr->YPlacementDevice,
-                                    stream ) ) != TT_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 & 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 = Load_Device( &vr->XAdvanceDevice,
-                                    stream ) ) != TT_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 & 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 = Load_Device( &vr->YAdvanceDevice,
-                                    stream ) ) != TT_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 & HAVE_X_ID_PLACEMENT )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        goto Fail1;
-
-      vr->XIdPlacement = GET_UShort();
-
-      FORGET_Frame();
-    }
-    else
-      vr->XIdPlacement = 0;
-
-    if ( format & HAVE_Y_ID_PLACEMENT )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        goto Fail1;
-
-      vr->YIdPlacement = GET_UShort();
-
-      FORGET_Frame();
-    }
-    else
-      vr->YIdPlacement = 0;
-
-    if ( format & HAVE_X_ID_ADVANCE )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        goto Fail1;
-
-      vr->XIdAdvance = GET_UShort();
-
-      FORGET_Frame();
-    }
-    else
-      vr->XIdAdvance = 0;
-
-    if ( format & HAVE_Y_ID_ADVANCE )
-    {
-      if ( ACCESS_Frame( 2L ) )
-        goto Fail1;
-
-      vr->YIdAdvance = GET_UShort();
-
-      FORGET_Frame();
-    }
-    else
-      vr->YIdAdvance = 0;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    Free_Device( &vr->YAdvanceDevice, memory );
-
-  Fail2:
-    Free_Device( &vr->XAdvanceDevice, memory );
-
-  Fail3:
-    Free_Device( &vr->YPlacementDevice, memory );
-    return error;
-  }
-
-
-  static void  Free_ValueRecord( TTO_ValueRecord*  vr,
-                                 FT_UShort         format,
-				 FT_Memory         memory )
-  {
-    if ( format & HAVE_Y_ADVANCE_DEVICE )
-      Free_Device( &vr->YAdvanceDevice, memory );
-    if ( format & HAVE_X_ADVANCE_DEVICE )
-      Free_Device( &vr->XAdvanceDevice, memory );
-    if ( format & HAVE_Y_PLACEMENT_DEVICE )
-      Free_Device( &vr->YPlacementDevice, memory );
-    if ( format & HAVE_X_PLACEMENT_DEVICE )
-      Free_Device( &vr->XPlacementDevice, memory );
-  }
-
-
-  static FT_Error  Get_ValueRecord( GPOS_Instance*    gpi,
-                                    TTO_ValueRecord*  vr,
-                                    FT_UShort         format,
-                                    OTL_Position      gd )
-  {
-    FT_Pos           value;
-    FT_Short         pixel_value;
-    FT_Error         error = TT_Err_Ok;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-
-    FT_UShort  x_ppem, y_ppem;
-    FT_Fixed   x_scale, y_scale;
-
-
-    if ( !format )
-      return TT_Err_Ok;
-
-    x_ppem  = gpi->face->size->metrics.x_ppem;
-    y_ppem  = gpi->face->size->metrics.y_ppem;
-    x_scale = gpi->face->size->metrics.x_scale;
-    y_scale = gpi->face->size->metrics.y_scale;
-
-    /* design units -> fractional pixel */
-
-    if ( format & HAVE_X_PLACEMENT )
-      gd->x_pos += x_scale * vr->XPlacement / 0x10000;
-    if ( format & HAVE_Y_PLACEMENT )
-      gd->y_pos += y_scale * vr->YPlacement / 0x10000;
-    if ( format & HAVE_X_ADVANCE )
-      gd->x_advance += x_scale * vr->XAdvance / 0x10000;
-    if ( format & HAVE_Y_ADVANCE )
-      gd->y_advance += y_scale * vr->YAdvance / 0x10000;
-
-    if ( !gpi->dvi )
-    {
-      /* pixel -> fractional pixel */
-
-      if ( format & HAVE_X_PLACEMENT_DEVICE )
-      {
-        Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
-        gd->x_pos += pixel_value << 6;
-      }
-      if ( format & HAVE_Y_PLACEMENT_DEVICE )
-      {
-        Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
-        gd->y_pos += pixel_value << 6;
-      }
-      if ( format & HAVE_X_ADVANCE_DEVICE )
-      {
-        Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
-        gd->x_advance += pixel_value << 6;
-      }
-      if ( format & HAVE_Y_ADVANCE_DEVICE )
-      {
-        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 & HAVE_X_ID_PLACEMENT )
-    {
-      error = (gpos->mmfunc)( gpi->face, vr->XIdPlacement,
-                              &value, gpos->data );
-      if ( error )
-        return error;
-      gd->x_pos += value;
-    }
-    if ( format & HAVE_Y_ID_PLACEMENT )
-    {
-      error = (gpos->mmfunc)( gpi->face, vr->YIdPlacement,
-                              &value, gpos->data );
-      if ( error )
-        return error;
-      gd->y_pos += value;
-    }
-    if ( format & HAVE_X_ID_ADVANCE )
-    {
-      error = (gpos->mmfunc)( gpi->face, vr->XIdAdvance,
-                              &value, gpos->data );
-      if ( error )
-        return error;
-      gd->x_advance += value;
-    }
-    if ( format & HAVE_Y_ID_ADVANCE )
-    {
-      error = (gpos->mmfunc)( gpi->face, vr->YIdAdvance,
-                              &value, gpos->data );
-      if ( error )
-        return error;
-      gd->y_advance += value;
-    }
-
-    return error;
-  }
-
-
-  /* AnchorFormat1 */
-  /* AnchorFormat2 */
-  /* AnchorFormat3 */
-  /* AnchorFormat4 */
-
-  static FT_Error  Load_Anchor( TTO_Anchor*  an,
-                                FT_Stream    stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_ULong 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 = Load_Device( &an->af.af3.XDeviceTable,
-                                    stream ) ) != TT_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 = Load_Device( &an->af.af3.YDeviceTable,
-                                    stream ) ) != TT_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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    Free_Device( &an->af.af3.XDeviceTable, memory );
-    return error;
-  }
-
-
-  static void  Free_Anchor( TTO_Anchor*  an,
-			    FT_Memory    memory)
-  {
-    if ( an->PosFormat == 3 )
-    {
-      Free_Device( &an->af.af3.YDeviceTable, memory );
-      Free_Device( &an->af.af3.XDeviceTable, memory );
-    }
-  }
-
-
-  static FT_Error  Get_Anchor( GPOS_Instance*   gpi,
-                               TTO_Anchor*      an,
-                               FT_UShort        glyph_index,
-                               FT_Pos*          x_value,
-                               FT_Pos*          y_value )
-  {
-    FT_Error  error = TT_Err_Ok;
-
-    FT_Outline       outline;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    FT_UShort        ap;
-
-    FT_Short         pixel_value;
-    FT_UShort        load_flags;
-
-    FT_UShort        x_ppem, y_ppem;
-    FT_Fixed         x_scale, y_scale;
-
-
-    x_ppem  = gpi->face->size->metrics.x_ppem;
-    y_ppem  = gpi->face->size->metrics.y_ppem;
-    x_scale = gpi->face->size->metrics.x_scale;
-    y_scale = gpi->face->size->metrics.y_scale;
-
-    switch ( an->PosFormat )
-    {
-    case 0:
-      /* The special case of an empty AnchorTable */
-
-      return TTO_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->face, glyph_index, load_flags );
-        if ( error )
-          return error;
-
-	if ( gpi->face->glyph->format != ft_glyph_format_outline )
-          return TTO_Err_Invalid_GPOS_SubTable;	  
-
-	ap = an->af.af2.AnchorPoint;
-	
-	outline = gpi->face->glyph->outline;
-
-        /* if outline.n_points is set to zero by gfunc(), 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 TTO_Err_Invalid_GPOS_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 )
-      {
-        Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
-        *x_value = pixel_value << 6;
-        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->face, an->af.af4.XIdAnchor,
-                              x_value, gpos->data );
-      if ( error )
-        return error;
-
-      error = (gpos->mmfunc)( gpi->face, an->af.af4.YIdAnchor,
-                              y_value, gpos->data );
-      if ( error )
-        return error;
-      break;
-    }
-
-    return error;
-  }
-
-
-  /* MarkArray */
-
-  static FT_Error  Load_MarkArray ( TTO_MarkArray*  ma,
-                                    FT_Stream       stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort        n, m, count;
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_Anchor( &mr[m].MarkAnchor, memory );
-
-    FREE( mr );
-    return error;
-  }
-
-
-  static void  Free_MarkArray( TTO_MarkArray*  ma,
-			       FT_Memory       memory )
-  {
-    FT_UShort        n, count;
-
-    TTO_MarkRecord*  mr;
-
-
-    if ( ma->MarkRecord )
-    {
-      count = ma->MarkCount;
-      mr    = ma->MarkRecord;
-
-      for ( n = 0; n < count; n++ )
-        Free_Anchor( &mr[n].MarkAnchor, memory );
-
-      FREE( mr );
-    }
-  }
-
-
-  /* LookupType 1 */
-
-  /* SinglePosFormat1 */
-  /* SinglePosFormat2 */
-
-  FT_Error  Load_SinglePos( TTO_SinglePos*  sp,
-                            FT_Stream       stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort         n, m, count, format;
-    FT_ULong          cur_offset, new_offset, base_offset;
-
-    TTO_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 TTO_Err_Invalid_GPOS_SubTable;
-
-    cur_offset = FILE_Pos();
-    if ( FILE_Seek( new_offset ) ||
-         ( error = Load_Coverage( &sp->Coverage, stream ) ) != TT_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, TTO_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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_ValueRecord( &vr[m], format, memory );
-
-    FREE( vr );
-
-  Fail2:
-    Free_Coverage( &sp->Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_SinglePos( TTO_SinglePos*  sp,
-			FT_Memory       memory )
-  {
-    FT_UShort         n, count, format;
-
-    TTO_ValueRecord*  v;
-
-
-    format = sp->ValueFormat;
-
-    switch ( sp->PosFormat )
-    {
-    case 1:
-      Free_ValueRecord( &sp->spf.spf1.Value, format, memory );
-      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, memory );
-
-        FREE( v );
-      }
-      break;
-    }
-
-    Free_Coverage( &sp->Coverage, memory );
-  }
-
-  static FT_Error  Lookup_DefaultPos(  GPOS_Instance*    gpi,
-				       TTO_GPOS_SubTable* st,
-				       OTL_Buffer        buffer,
-				       FT_UShort         flags,
-				       FT_UShort         context_length,
-				       int               nesting_level )
-  {
-    return TTO_Err_Not_Covered;
-  }
-
-  static FT_Error  Lookup_SinglePos( GPOS_Instance*    gpi,
-                                     TTO_GPOS_SubTable* st,
-				     OTL_Buffer        buffer,
-                                     FT_UShort         flags,
-                                     FT_UShort         context_length,
-                                     int               nesting_level )
-  {
-    FT_UShort        index, property;
-    FT_Error         error;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    TTO_SinglePos*   sp = &st->single;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-      return TTO_Err_Not_Covered;
-
-    if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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 TTO_Err_Invalid_GPOS_SubTable;
-      error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
-                               sp->ValueFormat, POSITION( buffer->in_pos ) );
-      if ( error )
-        return error;
-      break;
-
-    default:
-      return TTO_Err_Invalid_GPOS_SubTable;
-    }
-
-    (buffer->in_pos)++;
-
-    return TT_Err_Ok;
-  }
-
-
-  /* LookupType 2 */
-
-  /* PairSet */
-
-  static FT_Error  Load_PairSet ( TTO_PairSet*  ps,
-                                  FT_UShort     format1,
-                                  FT_UShort     format2,
-                                  FT_Stream     stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, m, count;
-    FT_ULong              base_offset;
-
-    TTO_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, TTO_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, memory );
-          goto Fail;
-	}
-      }
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-    {
-      if ( format1 )
-        Free_ValueRecord( &pvr[m].Value1, format1, memory );
-      if ( format2 )
-        Free_ValueRecord( &pvr[m].Value2, format2, memory );
-    }
-
-    FREE( pvr );
-    return error;
-  }
-
-
-  static void  Free_PairSet( TTO_PairSet*  ps,
-                             FT_UShort     format1,
-                             FT_UShort     format2,
-			     FT_Memory     memory )
-  {
-    FT_UShort             n, count;
-
-    TTO_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, memory );
-        if ( format2 )
-          Free_ValueRecord( &pvr[n].Value2, format2, memory );
-      }
-
-      FREE( pvr );
-    }
-  }
-
-
-  /* PairPosFormat1 */
-
-  static FT_Error  Load_PairPos1( TTO_PairPosFormat1*  ppf1,
-                                  FT_UShort            format1,
-                                  FT_UShort            format2,
-                                  FT_Stream            stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort     n, m, count;
-    FT_ULong      cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_PairSet( &ps[m], format1, format2, memory );
-
-    FREE( ps );
-    return error;
-  }
-
-
-  static void  Free_PairPos1( TTO_PairPosFormat1*  ppf1,
-                              FT_UShort            format1,
-                              FT_UShort            format2,
-			      FT_Memory            memory )
-  {
-    FT_UShort     n, count;
-
-    TTO_PairSet*  ps;
-
-
-    if ( ppf1->PairSet )
-    {
-      count = ppf1->PairSetCount;
-      ps    = ppf1->PairSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_PairSet( &ps[n], format1, format2, memory );
-
-      FREE( ps );
-    }
-  }
-
-
-  /* PairPosFormat2 */
-
-  static FT_Error  Load_PairPos2( TTO_PairPosFormat2*  ppf2,
-                                  FT_UShort            format1,
-                                  FT_UShort            format2,
-                                  FT_Stream            stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort          m, n, k, count1, count2;
-    FT_ULong           cur_offset, new_offset1, new_offset2, base_offset;
-
-    TTO_Class1Record*  c1r;
-    TTO_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 = Load_ClassDefinition( &ppf2->ClassDef1, count1,
-                                         stream ) ) != TT_Err_Ok )
-      return error;
-    if ( FILE_Seek( new_offset2 ) ||
-         ( error = Load_ClassDefinition( &ppf2->ClassDef2, count2,
-                                         stream ) ) != TT_Err_Ok )
-      goto Fail3;
-    (void)FILE_Seek( cur_offset );
-
-    ppf2->Class1Record = NULL;
-
-    if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) )
-      goto Fail2;
-
-    c1r = ppf2->Class1Record;
-
-    for ( m = 0; m < count1; m++ )
-    {
-      c1r[m].Class2Record = NULL;
-
-      if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_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, memory );	      
-            goto Fail0;
-	  }
-        }
-      }
-
-      continue;
-
-    Fail0:
-      for ( k = 0; k < n; k++ )
-      {
-        if ( format1 )
-          Free_ValueRecord( &c2r[k].Value1, format1, memory );
-        if ( format2 )
-          Free_ValueRecord( &c2r[k].Value2, format2, memory );
-      }
-      goto Fail1;
-    }
-
-    return TT_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, memory );
-        if ( format2 )
-          Free_ValueRecord( &c2r[n].Value2, format2, memory );
-      }
-
-      FREE( c2r );
-    }
-
-    FREE( c1r );
-  Fail2:
-
-    Free_ClassDefinition( &ppf2->ClassDef2, memory );
-
-  Fail3:
-    Free_ClassDefinition( &ppf2->ClassDef1, memory );
-    return error;
-  }
-
-
-  static void  Free_PairPos2( TTO_PairPosFormat2*  ppf2,
-                              FT_UShort            format1,
-                              FT_UShort            format2,
-			      FT_Memory            memory )
-  {
-    FT_UShort          m, n, count1, count2;
-
-    TTO_Class1Record*  c1r;
-    TTO_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, memory );
-          if ( format2 )
-            Free_ValueRecord( &c2r[n].Value2, format2, memory );
-        }
-
-        FREE( c2r );
-      }
-
-      FREE( c1r );
-
-      Free_ClassDefinition( &ppf2->ClassDef2, memory );
-      Free_ClassDefinition( &ppf2->ClassDef1, memory );
-    }
-  }
-
-
-  FT_Error  Load_PairPos( TTO_PairPos*  pp,
-                          FT_Stream     stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort         format1, format2;
-    FT_ULong          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 = Load_Coverage( &pp->Coverage, stream ) ) != TT_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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    Free_Coverage( &pp->Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_PairPos( TTO_PairPos*  pp,
-		      FT_Memory     memory )
-  {
-    FT_UShort  format1, format2;
-
-
-    format1 = pp->ValueFormat1;
-    format2 = pp->ValueFormat2;
-
-    switch ( pp->PosFormat )
-    {
-    case 1:
-      Free_PairPos1( &pp->ppf.ppf1, format1, format2, memory );
-      break;
-
-    case 2:
-      Free_PairPos2( &pp->ppf.ppf2, format1, format2, memory );
-      break;
-    }
-
-    Free_Coverage( &pp->Coverage, memory );
-  }
-
-
-  static FT_Error  Lookup_PairPos1( GPOS_Instance*       gpi,
-                                    TTO_PairPosFormat1*  ppf1,
-				    OTL_Buffer           buffer,
-                                    FT_UShort            first_pos,
-                                    FT_UShort            index,
-                                    FT_UShort            format1,
-                                    FT_UShort            format2 )
-  {
-    FT_Error              error;
-    FT_UShort             numpvr, glyph2;
-
-    TTO_PairValueRecord*  pvr;
-
-
-    if ( index >= ppf1->PairSetCount )
-       return TTO_Err_Invalid_GPOS_SubTable;
-
-    pvr = ppf1->PairSet[index].PairValueRecord;
-    if ( !pvr )
-      return TTO_Err_Invalid_GPOS_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 TTO_Err_Not_Covered;
-  }
-
-
-  static FT_Error  Lookup_PairPos2( GPOS_Instance*       gpi,
-                                    TTO_PairPosFormat2*  ppf2,
-				    OTL_Buffer           buffer,
-                                    FT_UShort            first_pos,
-                                    FT_UShort            format1,
-                                    FT_UShort            format2 )
-  {
-    FT_Error           error;
-    FT_UShort          cl1, cl2;
-
-    TTO_Class1Record*  c1r;
-    TTO_Class2Record*  c2r;
-
-
-    error = Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
-                       &cl1, NULL );
-    if ( error && error != TTO_Err_Not_Covered )
-      return error;
-    error = Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
-                       &cl2, NULL );
-    if ( error && error != TTO_Err_Not_Covered )
-      return error;
-
-    c1r = &ppf2->Class1Record[cl1];
-    if ( !c1r )
-      return TTO_Err_Invalid_GPOS_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 FT_Error  Lookup_PairPos( GPOS_Instance*    gpi,
-                                   TTO_GPOS_SubTable* st,
-				   OTL_Buffer        buffer,
-                                   FT_UShort         flags,
-                                   FT_UShort         context_length,
-                                   int               nesting_level )
-  {
-    FT_Error         error;
-    FT_UShort        index, property, first_pos;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    TTO_PairPos*     pp = &st->pair;
-
-
-    if ( buffer->in_pos >= buffer->in_length - 1 )
-      return TTO_Err_Not_Covered;           /* Not enough glyphs in stream */
-
-    if ( context_length != 0xFFFF && context_length < 2 )
-      return TTO_Err_Not_Covered;
-
-    if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-      return error;
-
-    /* second glyph */
-
-    first_pos = buffer->in_pos;
-    (buffer->in_pos)++;
-
-    while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
-                            flags, &property ) )
-    {
-      if ( error && error != TTO_Err_Not_Covered )
-        return error;
-
-      if ( buffer->in_pos == buffer->in_length )
-        return TTO_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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    /* adjusting the `next' glyph */
-
-    if ( pp->ValueFormat2 )
-      (buffer->in_pos)++;
-
-    return error;
-  }
-
-
-  /* LookupType 3 */
-
-  /* CursivePosFormat1 */
-
-  FT_Error  Load_CursivePos( TTO_CursivePos*  cp,
-                             FT_Stream        stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, m, count;
-    FT_ULong              cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &cp->Coverage, stream ) ) != TT_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, TTO_EntryExitRecord ) )
-      goto Fail2;
-
-    eer = cp->EntryExitRecord;
-
-    for ( n = 0; n < count; n++ )
-    {
-      FT_ULong 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 ) ) != TT_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 ) ) != TT_Err_Ok )
-	{
-	  if ( entry_offset )
-	    Free_Anchor( &eer[n].EntryAnchor, memory );
-          goto Fail1;
-	}
-        (void)FILE_Seek( cur_offset );
-      }
-      else
-        eer[n].ExitAnchor.PosFormat   = 0;
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-    {
-      Free_Anchor( &eer[m].EntryAnchor, memory );
-      Free_Anchor( &eer[m].ExitAnchor, memory );
-    }
-
-    FREE( eer );
-
-  Fail2:
-    Free_Coverage( &cp->Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_CursivePos( TTO_CursivePos*  cp,
-			 FT_Memory        memory )
-  {
-    FT_UShort             n, count;
-
-    TTO_EntryExitRecord*  eer;
-
-
-    if ( cp->EntryExitRecord )
-    {
-      count = cp->EntryExitCount;
-      eer   = cp->EntryExitRecord;
-
-      for ( n = 0; n < count; n++ )
-      {
-        Free_Anchor( &eer[n].EntryAnchor, memory );
-        Free_Anchor( &eer[n].ExitAnchor, memory );
-      }
-
-      FREE( eer );
-    }
-
-    Free_Coverage( &cp->Coverage, memory );
-  }
-
-
-  static FT_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
-                                      TTO_GPOS_SubTable* st,
-				      OTL_Buffer        buffer,
-                                      FT_UShort         flags,
-                                      FT_UShort         context_length,
-                                      int               nesting_level )
-  {
-    FT_UShort        index, property;
-    FT_Error         error;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    TTO_CursivePos*  cp = &st->cursive;
-
-    TTO_EntryExitRecord*  eer;
-    FT_Pos                entry_x, entry_y;
-    FT_Pos                exit_x, exit_y;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-    {
-      gpi->last = 0xFFFF;
-      return TTO_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 ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    /* We don't handle mark glyphs here.  According to Andrei, this isn't
-       possible, but who knows...                                         */
-
-    if ( property == MARK_GLYPH )
-    {
-      gpi->last = 0xFFFF;
-      return TTO_Err_Not_Covered;
-    }
-
-    error = Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-    {
-      gpi->last = 0xFFFF;
-      return error;
-    }
-
-    if ( index >= cp->EntryExitCount )
-      return TTO_Err_Invalid_GPOS_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 TTO_Err_Not_Covered if there is no anchor
-       table.                                                         */
-
-    error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
-                        &entry_x, &entry_y );
-    if ( error == TTO_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 & 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 == TTO_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 TT_Err_Ok;
-  }
-
-
-  /* LookupType 4 */
-
-  /* BaseArray */
-
-  static FT_Error  Load_BaseArray( TTO_BaseArray*  ba,
-                                   FT_UShort       num_classes,
-                                   FT_Stream       stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort        m, n, k, count;
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    TTO_BaseRecord*  br;
-    TTO_Anchor*      ban;
-
-
-    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, TTO_BaseRecord ) )
-      return error;
-
-    br = ba->BaseRecord;
-
-    for ( m = 0; m < count; m++ )
-    {
-      br[m].BaseAnchor = NULL;
-
-      if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) )
-        goto Fail;
-
-      ban = br[m].BaseAnchor;
-
-      for ( n = 0; n < num_classes; n++ )
-      {
-        if ( ACCESS_Frame( 2L ) )
-          goto Fail0;
-
-        new_offset = GET_UShort() + base_offset;
-
-        FORGET_Frame();
-
-	if (new_offset == base_offset) {
-	  /* Doulos SIL Regular is buggy and has zer offsets here.  Skip */
-	  ban[n].PosFormat = 0;
-	  continue;
-	}
-
-        cur_offset = FILE_Pos();
-        if ( FILE_Seek( new_offset ) ||
-             ( error = Load_Anchor( &ban[n], stream ) ) != TT_Err_Ok )
-          goto Fail0;
-        (void)FILE_Seek( cur_offset );
-      }
-
-      continue;
-    Fail0:
-      for ( k = 0; k < n; k++ )
-        Free_Anchor( &ban[k], memory );
-      goto Fail;
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( k = 0; k < m; k++ )
-    {
-      ban = br[k].BaseAnchor;
-      
-      for ( n = 0; n < num_classes; n++ )
-        Free_Anchor( &ban[n], memory );
-
-      FREE( ban );
-    }
-
-    FREE( br );
-    return error;
-  }
-
-
-  static void  Free_BaseArray( TTO_BaseArray*  ba,
-                               FT_UShort       num_classes,
-			       FT_Memory       memory )
-  {
-    FT_UShort        m, n, count;
-
-    TTO_BaseRecord*  br;
-    TTO_Anchor*      ban;
-
-
-    if ( ba->BaseRecord )
-    {
-      count = ba->BaseCount;
-      br    = ba->BaseRecord;
-
-      for ( m = 0; m < count; m++ )
-      {
-        ban = br[m].BaseAnchor;
-
-        for ( n = 0; n < num_classes; n++ )
-          Free_Anchor( &ban[n], memory );
-
-        FREE( ban );
-      }
-
-      FREE( br );
-    }
-  }
-
-
-  /* MarkBasePosFormat1 */
-
-  FT_Error  Load_MarkBasePos( TTO_MarkBasePos*  mbp,
-                              FT_Stream         stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_ULong  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 TTO_Err_Invalid_SubTable_Format;
-
-    cur_offset = FILE_Pos();
-    if ( FILE_Seek( new_offset ) ||
-         ( error = Load_Coverage( &mbp->MarkCoverage, stream ) ) != TT_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 = Load_Coverage( &mbp->BaseCoverage, stream ) ) != TT_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 ) ) != TT_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 ) ) != TT_Err_Ok )
-      goto Fail1;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    Free_MarkArray( &mbp->MarkArray, memory );
-
-  Fail2:
-    Free_Coverage( &mbp->BaseCoverage, memory );
-
-  Fail3:
-    Free_Coverage( &mbp->MarkCoverage, memory );
-    return error;
-  }
-
-
-  void  Free_MarkBasePos( TTO_MarkBasePos*  mbp,
-			  FT_Memory         memory )
-  {
-    Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory );
-    Free_MarkArray( &mbp->MarkArray, memory );
-    Free_Coverage( &mbp->BaseCoverage, memory );
-    Free_Coverage( &mbp->MarkCoverage, memory );
-  }
-
-
-  static FT_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
-                                       TTO_GPOS_SubTable* st,
-				       OTL_Buffer        buffer,
-                                       FT_UShort         flags,
-                                       FT_UShort         context_length,
-                                       int               nesting_level )
-  {
-    FT_UShort        i, j, mark_index, base_index, property, class;
-    FT_Pos           x_mark_value, y_mark_value, x_base_value, y_base_value;
-    FT_Error         error;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    TTO_MarkBasePos* mbp = &st->markbase;
-
-    TTO_MarkArray*   ma;
-    TTO_BaseArray*   ba;
-    TTO_BaseRecord*  br;
-    TTO_Anchor*      mark_anchor;
-    TTO_Anchor*      base_anchor;
-
-    OTL_Position     o;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-      return TTO_Err_Not_Covered;
-
-    if ( flags & IGNORE_BASE_GLYPHS )
-      return TTO_Err_Not_Covered;
-
-    if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
-                         flags, &property ) )
-      return error;
-
-    error = 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 )
-    {
-      error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-                                          &property );
-      if ( error )
-        return error;
-
-      if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) )
-        break;
-
-      i++;
-      j--;
-    }
-
-    /* The following assertion is too strong -- at least for mangal.ttf. */
-#if 0
-    if ( property != TTO_BASE_GLYPH )
-      return TTO_Err_Not_Covered;
-#endif
-
-    if ( i > buffer->in_pos )
-      return TTO_Err_Not_Covered;
-
-    error = Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
-                            &base_index );
-    if ( error )
-      return error;
-
-    ma = &mbp->MarkArray;
-
-    if ( mark_index >= ma->MarkCount )
-      return TTO_Err_Invalid_GPOS_SubTable;
-
-    class       = ma->MarkRecord[mark_index].Class;
-    mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
-
-    if ( class >= mbp->ClassCount )
-      return TTO_Err_Invalid_GPOS_SubTable;
-
-    ba = &mbp->BaseArray;
-
-    if ( base_index >= ba->BaseCount )
-      return TTO_Err_Invalid_GPOS_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 TT_Err_Ok;
-  }
-
-
-  /* LookupType 5 */
-
-  /* LigatureAttach */
-
-  static FT_Error  Load_LigatureAttach( TTO_LigatureAttach*  lat,
-                                        FT_UShort            num_classes,
-                                        FT_Stream            stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             m, n, k, count;
-    FT_ULong              cur_offset, new_offset, base_offset;
-
-    TTO_ComponentRecord*  cr;
-    TTO_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, TTO_ComponentRecord ) )
-      return error;
-
-    cr = lat->ComponentRecord;
-
-    for ( m = 0; m < count; m++ )
-    {
-      cr[m].LigatureAnchor = NULL;
-
-      if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_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 ) ) != TT_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], memory );
-      goto Fail;
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( k = 0; k < m; k++ )
-    {
-      lan = cr[k].LigatureAnchor;
-      
-      for ( n = 0; n < num_classes; n++ )
-        Free_Anchor( &lan[n], memory );
-
-      FREE( lan );
-    }
-
-    FREE( cr );
-    return error;
-  }
-
-
-  static void  Free_LigatureAttach( TTO_LigatureAttach*  lat,
-                                    FT_UShort            num_classes,
-				    FT_Memory            memory )
-  {
-    FT_UShort        m, n, count;
-
-    TTO_ComponentRecord*  cr;
-    TTO_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], memory );
-
-        FREE( lan );
-      }
-
-      FREE( cr );
-    }
-  }
-
-
-  /* LigatureArray */
-
-  static FT_Error  Load_LigatureArray( TTO_LigatureArray*  la,
-                                       FT_UShort           num_classes,
-                                       FT_Stream           stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort            n, m, count;
-    FT_ULong             cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_LigatureAttach( &lat[m], num_classes, memory );
-
-    FREE( lat );
-    return error;
-  }
-
-
-  static void  Free_LigatureArray( TTO_LigatureArray*  la,
-                                   FT_UShort           num_classes,
-				   FT_Memory           memory )
-  {
-    FT_UShort            n, count;
-
-    TTO_LigatureAttach*  lat;
-
-
-    if ( la->LigatureAttach )
-    {
-      count = la->LigatureCount;
-      lat   = la->LigatureAttach;
-
-      for ( n = 0; n < count; n++ )
-        Free_LigatureAttach( &lat[n], num_classes, memory );
-
-      FREE( lat );
-    }
-  }
-
-
-  /* MarkLigPosFormat1 */
-
-  FT_Error  Load_MarkLigPos( TTO_MarkLigPos*  mlp,
-                             FT_Stream        stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_ULong  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 = Load_Coverage( &mlp->MarkCoverage, stream ) ) != TT_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 = Load_Coverage( &mlp->LigatureCoverage,
-                                  stream ) ) != TT_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 ) ) != TT_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 ) ) != TT_Err_Ok )
-      goto Fail1;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    Free_MarkArray( &mlp->MarkArray, memory );
-
-  Fail2:
-    Free_Coverage( &mlp->LigatureCoverage, memory );
-
-  Fail3:
-    Free_Coverage( &mlp->MarkCoverage, memory );
-    return error;
-  }
-
-
-  void  Free_MarkLigPos( TTO_MarkLigPos*  mlp,
-			 FT_Memory        memory)
-  {
-    Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, memory );
-    Free_MarkArray( &mlp->MarkArray, memory );
-    Free_Coverage( &mlp->LigatureCoverage, memory );
-    Free_Coverage( &mlp->MarkCoverage, memory );
-  }
-
-
-  static FT_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
-                                      TTO_GPOS_SubTable* st,
-				      OTL_Buffer        buffer,
-                                      FT_UShort         flags,
-                                      FT_UShort         context_length,
-                                      int               nesting_level )
-  {
-    FT_UShort        i, j, mark_index, lig_index, property, class;
-    FT_UShort        mark_glyph;
-    FT_Pos           x_mark_value, y_mark_value, x_lig_value, y_lig_value;
-    FT_Error         error;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    TTO_MarkLigPos*  mlp = &st->marklig;
-
-    TTO_MarkArray*        ma;
-    TTO_LigatureArray*    la;
-    TTO_LigatureAttach*   lat;
-    TTO_ComponentRecord*  cr;
-    FT_UShort             comp_index;
-    TTO_Anchor*           mark_anchor;
-    TTO_Anchor*           lig_anchor;
-
-    OTL_Position    o;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-      return TTO_Err_Not_Covered;
-
-    if ( flags & IGNORE_LIGATURES )
-      return TTO_Err_Not_Covered;
-
-    mark_glyph = IN_CURGLYPH();
-
-    if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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 )
-    {
-      error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-                                          &property );
-      if ( error )
-        return error;
-
-      if ( !( property == TTO_MARK || property & 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 ( property != TTO_LIGATURE )
-      return TTO_Err_Not_Covered;
-#endif
-
-    if ( i > buffer->in_pos )
-      return TTO_Err_Not_Covered;
-
-    error = Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
-                            &lig_index );
-    if ( error )
-      return error;
-
-    ma = &mlp->MarkArray;
-
-    if ( mark_index >= ma->MarkCount )
-      return TTO_Err_Invalid_GPOS_SubTable;
-
-    class       = ma->MarkRecord[mark_index].Class;
-    mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
-
-    if ( class >= mlp->ClassCount )
-      return TTO_Err_Invalid_GPOS_SubTable;
-
-    la = &mlp->LigatureArray;
-
-    if ( lig_index >= la->LigatureCount )
-      return TTO_Err_Invalid_GPOS_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 TTO_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 TT_Err_Ok;
-  }
-
-
-  /* LookupType 6 */
-
-  /* Mark2Array */
-
-  static FT_Error  Load_Mark2Array( TTO_Mark2Array*  m2a,
-                                    FT_UShort        num_classes,
-                                    FT_Stream        stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort         k, m, n, count;
-    FT_ULong          cur_offset, new_offset, base_offset;
-
-    TTO_Mark2Record*  m2r;
-    TTO_Anchor*       m2an;
-
-
-    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, TTO_Mark2Record ) )
-      return error;
-
-    m2r = m2a->Mark2Record;
-
-    for ( m = 0; m < count; m++ )
-    {
-      m2r[m].Mark2Anchor = NULL;
-
-      if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) )
-        goto Fail;
-
-      m2an = m2r[m].Mark2Anchor;
-
-      for ( n = 0; n < num_classes; n++ )
-      {
-        if ( ACCESS_Frame( 2L ) )
-          goto Fail0;
-
-        new_offset = GET_UShort() + base_offset;
-
-        FORGET_Frame();
-
-        cur_offset = FILE_Pos();
-        if ( FILE_Seek( new_offset ) ||
-             ( error = Load_Anchor( &m2an[n], stream ) ) != TT_Err_Ok )
-          goto Fail0;
-        (void)FILE_Seek( cur_offset );
-      }
-
-      continue;
-    Fail0:
-      for ( k = 0; k < n; k++ )
-        Free_Anchor( &m2an[k], memory );
-      goto Fail;
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( k = 0; k < m; k++ )
-    {
-      m2an = m2r[k].Mark2Anchor;
-      
-      for ( n = 0; n < num_classes; n++ )
-        Free_Anchor( &m2an[n], memory );
-
-      FREE( m2an );
-    }
-
-    FREE( m2r );
-    return error;
-  }
-
-
-  static void  Free_Mark2Array( TTO_Mark2Array*  m2a,
-                                FT_UShort        num_classes,
-				FT_Memory        memory )
-  {
-    FT_UShort         m, n, count;
-
-    TTO_Mark2Record*  m2r;
-    TTO_Anchor*       m2an;
-
-
-    if ( m2a->Mark2Record )
-    {
-      count = m2a->Mark2Count;
-      m2r   = m2a->Mark2Record;
-
-      for ( m = 0; m < count; m++ )
-      {
-        m2an = m2r[m].Mark2Anchor;
-
-        for ( n = 0; n < num_classes; n++ )
-          Free_Anchor( &m2an[n], memory );
-
-        FREE( m2an );
-      }
-
-      FREE( m2r );
-    }
-  }
-
-
-  /* MarkMarkPosFormat1 */
-
-  FT_Error  Load_MarkMarkPos( TTO_MarkMarkPos*  mmp,
-                              FT_Stream         stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_ULong  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 = Load_Coverage( &mmp->Mark1Coverage,
-                                  stream ) ) != TT_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 = Load_Coverage( &mmp->Mark2Coverage,
-                                  stream ) ) != TT_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 ) ) != TT_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 ) ) != TT_Err_Ok )
-      goto Fail1;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    Free_MarkArray( &mmp->Mark1Array, memory );
-
-  Fail2:
-    Free_Coverage( &mmp->Mark2Coverage, memory );
-
-  Fail3:
-    Free_Coverage( &mmp->Mark1Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_MarkMarkPos( TTO_MarkMarkPos*  mmp,
-			  FT_Memory         memory)
-  {
-    Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, memory );
-    Free_MarkArray( &mmp->Mark1Array, memory );
-    Free_Coverage( &mmp->Mark2Coverage, memory );
-    Free_Coverage( &mmp->Mark1Coverage, memory );
-  }
-
-
-  static FT_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
-                                       TTO_GPOS_SubTable* st,
-				       OTL_Buffer        buffer,
-                                       FT_UShort         flags,
-                                       FT_UShort         context_length,
-                                       int               nesting_level )
-  {
-    FT_UShort        j, mark1_index, mark2_index, property, class;
-    FT_Pos           x_mark1_value, y_mark1_value,
-                     x_mark2_value, y_mark2_value;
-    FT_Error         error;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    TTO_MarkMarkPos* mmp = &st->markmark;
-
-    TTO_MarkArray*    ma1;
-    TTO_Mark2Array*   ma2;
-    TTO_Mark2Record*  m2r;
-    TTO_Anchor*       mark1_anchor;
-    TTO_Anchor*       mark2_anchor;
-
-    OTL_Position    o;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-      return TTO_Err_Not_Covered;
-
-    if ( flags & IGNORE_MARKS )
-      return TTO_Err_Not_Covered;
-
-    if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
-                         flags, &property ) )
-      return error;
-
-    error = Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
-                            &mark1_index );
-    if ( error )
-      return error;
-
-    /* now we check the preceding glyph whether it is a suitable
-       mark glyph                                                */
-
-    if ( buffer->in_pos == 0 )
-      return TTO_Err_Not_Covered;
-
-    j = buffer->in_pos - 1;
-    error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
-                                        &property );
-    if ( error )
-      return error;
-
-    if ( flags & IGNORE_SPECIAL_MARKS )
-    {
-      if ( property != (flags & 0xFF00) )
-        return TTO_Err_Not_Covered;
-    }
-    else
-    {
-      if ( property != TTO_MARK )
-        return TTO_Err_Not_Covered;
-    }
-
-    error = Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
-                            &mark2_index );
-    if ( error )
-      return error;
-
-    ma1 = &mmp->Mark1Array;
-
-    if ( mark1_index >= ma1->MarkCount )
-      return TTO_Err_Invalid_GPOS_SubTable;
-
-    class        = ma1->MarkRecord[mark1_index].Class;
-    mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
-
-    if ( class >= mmp->ClassCount )
-      return TTO_Err_Invalid_GPOS_SubTable;
-
-    ma2 = &mmp->Mark2Array;
-
-    if ( mark2_index >= ma2->Mark2Count )
-      return TTO_Err_Invalid_GPOS_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 TT_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 FT_Error  Do_ContextPos( GPOS_Instance*        gpi,
-                                  FT_UShort             GlyphCount,
-                                  FT_UShort             PosCount,
-                                  TTO_PosLookupRecord*  pos,
-				  OTL_Buffer            buffer,
-                                  int                   nesting_level )
-  {
-    FT_Error  error;
-    FT_UShort i, old_pos;
-
-
-    i = 0;
-
-    while ( i < GlyphCount )
-    {
-      if ( PosCount && i == pos->SequenceIndex )
-      {
-        old_pos = buffer->in_pos;
-
-        /* Do a positioning */
-
-        error = 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 TT_Err_Ok;
-  }
-
-
-  /* LookupType 7 */
-
-  /* PosRule */
-
-  static FT_Error  Load_PosRule( TTO_PosRule*  pr,
-                                 FT_Stream     stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, count;
-    FT_UShort*            i;
-
-    TTO_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, FT_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, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( plr );
-
-  Fail2:
-    FREE( i );
-    return error;
-  }
-
-
-  static void  Free_PosRule( TTO_PosRule*  pr,
-			     FT_Memory     memory )
-  {
-    FREE( pr->PosLookupRecord );
-    FREE( pr->Input );
-  }
-
-
-  /* PosRuleSet */
-
-  static FT_Error  Load_PosRuleSet( TTO_PosRuleSet*  prs,
-                                    FT_Stream        stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort     n, m, count;
-    FT_ULong      cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_PosRule( &pr[m], memory );
-
-    FREE( pr );
-    return error;
-  }
-
-
-  static void  Free_PosRuleSet( TTO_PosRuleSet*  prs,
-				FT_Memory        memory )
-  {
-    FT_UShort     n, count;
-
-    TTO_PosRule*  pr;
-
-
-    if ( prs->PosRule )
-    {
-      count = prs->PosRuleCount;
-      pr    = prs->PosRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_PosRule( &pr[n], memory );
-
-      FREE( pr );
-    }
-  }
-
-
-  /* ContextPosFormat1 */
-
-  static FT_Error  Load_ContextPos1( TTO_ContextPosFormat1*  cpf1,
-                                     FT_Stream               stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort        n, m, count;
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &cpf1->Coverage, stream ) ) != TT_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_PosRuleSet( &prs[m], memory );
-
-    FREE( prs );
-
-  Fail2:
-    Free_Coverage( &cpf1->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_Context1( TTO_ContextPosFormat1*  cpf1,
-			      FT_Memory               memory )
-  {
-    FT_UShort        n, count;
-
-    TTO_PosRuleSet*  prs;
-
-
-    if ( cpf1->PosRuleSet )
-    {
-      count = cpf1->PosRuleSetCount;
-      prs   = cpf1->PosRuleSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_PosRuleSet( &prs[n], memory );
-
-      FREE( prs );
-    }
-
-    Free_Coverage( &cpf1->Coverage, memory );
-  }
-
-
-  /* PosClassRule */
-
-  static FT_Error  Load_PosClassRule( TTO_ContextPosFormat2*  cpf2,
-                                      TTO_PosClassRule*       pcr,
-                                      FT_Stream               stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, count;
-
-    FT_UShort*            c;
-    TTO_PosLookupRecord*  plr;
-    FT_Bool*              d;
-
-
-    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, FT_UShort ) )
-      return error;
-
-    c = pcr->Class;
-    d = cpf2->ClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail2;
-
-    for ( n = 0; n < count; n++ )
-    {
-      c[n] = GET_UShort();
-
-      /* We check whether the specific class is used at all.  If not,
-         class 0 is used instead.                                     */
-
-      if ( !d[c[n]] )
-        c[n] = 0;
-    }
-
-    FORGET_Frame();
-
-    pcr->PosLookupRecord = NULL;
-
-    count = pcr->PosCount;
-
-    if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( plr );
-
-  Fail2:
-    FREE( c );
-    return error;
-  }
-
-
-  static void  Free_PosClassRule( TTO_PosClassRule*  pcr,
-				  FT_Memory          memory )
-  {
-    FREE( pcr->PosLookupRecord );
-    FREE( pcr->Class );
-  }
-
-
-  /* PosClassSet */
-
-  static FT_Error  Load_PosClassSet( TTO_ContextPosFormat2*  cpf2,
-                                     TTO_PosClassSet*        pcs,
-                                     FT_Stream               stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort          n, m, count;
-    FT_ULong           cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_PosClassRule( &pcr[m], memory );
-
-    FREE( pcr );
-    return error;
-  }
-
-
-  static void  Free_PosClassSet( TTO_PosClassSet*  pcs,
-				 FT_Memory         memory )
-  {
-    FT_UShort          n, count;
-
-    TTO_PosClassRule*  pcr;
-
-
-    if ( pcs->PosClassRule )
-    {
-      count = pcs->PosClassRuleCount;
-      pcr   = pcs->PosClassRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_PosClassRule( &pcr[n], memory );
-
-      FREE( pcr );
-    }
-  }
-
-
-  /* ContextPosFormat2 */
-
-  static FT_Error  Load_ContextPos2( TTO_ContextPosFormat2*  cpf2,
-                                     FT_Stream               stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort         n, m, count;
-    FT_ULong          cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &cpf2->Coverage, stream ) ) != TT_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 = Load_ClassDefinition( &cpf2->ClassDef, count,
-                                         stream ) ) != TT_Err_Ok )
-      goto Fail3;
-    (void)FILE_Seek( cur_offset );
-
-    cpf2->PosClassSet      = NULL;
-    cpf2->MaxContextLength = 0;
-
-    if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_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 ) ) != TT_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 TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; n++ )
-      Free_PosClassSet( &pcs[m], memory );
-
-    FREE( pcs );
-
-  Fail2:
-    Free_ClassDefinition( &cpf2->ClassDef, memory );
-
-  Fail3:
-    Free_Coverage( &cpf2->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_Context2( TTO_ContextPosFormat2*  cpf2,
-			      FT_Memory               memory )
-  {
-    FT_UShort         n, count;
-
-    TTO_PosClassSet*  pcs;
-
-
-    if ( cpf2->PosClassSet )
-    {
-      count = cpf2->PosClassSetCount;
-      pcs   = cpf2->PosClassSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_PosClassSet( &pcs[n], memory );
-
-      FREE( pcs );
-    }
-
-    Free_ClassDefinition( &cpf2->ClassDef, memory );
-    Free_Coverage( &cpf2->Coverage, memory );
-  }
-
-
-  /* ContextPosFormat3 */
-
-  static FT_Error  Load_ContextPos3( TTO_ContextPosFormat3*  cpf3,
-                                     FT_Stream               stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, count;
-    FT_ULong              cur_offset, new_offset, base_offset;
-
-    TTO_Coverage*         c;
-    TTO_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, TTO_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 = Load_Coverage( &c[n], stream ) ) != TT_Err_Ok )
-        goto Fail2;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    cpf3->PosLookupRecord = NULL;
-
-    count = cpf3->PosCount;
-
-    if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( plr );
-
-  Fail2:
-    for ( n = 0; n < count; n++ )
-      Free_Coverage( &c[n], memory );
-
-    FREE( c );
-    return error;
-  }
-
-
-  static void  Free_Context3( TTO_ContextPosFormat3*  cpf3,
-			      FT_Memory               memory )
-  {
-    FT_UShort      n, count;
-
-    TTO_Coverage*  c;
-
-
-    FREE( cpf3->PosLookupRecord );
-
-    if ( cpf3->Coverage )
-    {
-      count = cpf3->GlyphCount;
-      c     = cpf3->Coverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-  }
-
-
-  /* ContextPos */
-
-  FT_Error  Load_ContextPos( TTO_ContextPos*  cp,
-                             FT_Stream        stream )
-  {
-    FT_Error  error;
-
-
-    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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  void  Free_ContextPos( TTO_ContextPos*  cp,
-			 FT_Memory        memory )
-  {
-    switch ( cp->PosFormat )
-    {
-    case 1:
-      Free_Context1( &cp->cpf.cpf1, memory );
-      break;
-
-    case 2:
-      Free_Context2( &cp->cpf.cpf2, memory );
-      break;
-
-    case 3:
-      Free_Context3( &cp->cpf.cpf3, memory );
-      break;
-    }
-  }
-
-
-  static FT_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
-                                       TTO_ContextPosFormat1*  cpf1,
-				       OTL_Buffer              buffer,
-                                       FT_UShort               flags,
-                                       FT_UShort               context_length,
-                                       int                     nesting_level )
-  {
-    FT_UShort        index, property;
-    FT_UShort        i, j, k, numpr;
-    FT_Error         error;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-
-    TTO_PosRule*     pr;
-    TTO_GDEFHeader*  gdef;
-
-
-    gdef = gpos->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-          if ( j + pr[k].GlyphCount - i == 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 TTO_Err_Not_Covered;
-  }
-
-
-  static FT_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
-                                       TTO_ContextPosFormat2*  cpf2,
-				       OTL_Buffer              buffer,
-                                       FT_UShort               flags,
-                                       FT_UShort               context_length,
-                                       int                     nesting_level )
-  {
-    FT_UShort          index, property;
-    FT_Error           error;
-    FT_Memory          memory = gpi->face->memory;
-    FT_UShort          i, j, k, known_classes;
-
-    FT_UShort*         classes;
-    FT_UShort*         cl;
-    TTO_GPOSHeader*    gpos = gpi->gpos;
-
-    TTO_PosClassSet*   pcs;
-    TTO_PosClassRule*  pr;
-    TTO_GDEFHeader*    gdef;
-
-
-    gdef = gpos->gdef;
-
-    if ( CHECK_Property( gdef, 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 = Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-      return error;
-
-    if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_UShort ) )
-      return error;
-
-    error = Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
-                       &classes[0], NULL );
-    if ( error && error != TTO_Err_Not_Covered )
-      goto End;
-    known_classes = 0;
-
-    pcs = &cpf2->PosClassSet[classes[0]];
-    if ( !pcs )
-    {
-      error = TTO_Err_Invalid_GPOS_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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            goto End;
-
-          if ( j + pr->GlyphCount - i == buffer->in_length )
-            goto next_posclassrule;
-          j++;
-        }
-
-        if ( i > known_classes )
-        {
-          /* Keeps us from having to do this for each rule */
-
-          error = Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
-          if ( error && error != TTO_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 = TTO_Err_Not_Covered;
-
-  End:
-    FREE( classes );
-    return error;
-  }
-
-
-  static FT_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
-                                       TTO_ContextPosFormat3*  cpf3,
-				       OTL_Buffer              buffer,
-                                       FT_UShort               flags,
-                                       FT_UShort               context_length,
-                                       int                     nesting_level )
-  {
-    FT_Error         error;
-    FT_UShort        index, i, j, property;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-
-    TTO_Coverage*    c;
-    TTO_GDEFHeader*  gdef;
-
-
-    gdef = gpos->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
-      return TTO_Err_Not_Covered;
-
-    if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
-      return TTO_Err_Not_Covered;         /* context is too long */
-
-    c    = cpf3->Coverage;
-
-    for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
-    {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-      {
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-
-        if ( j + cpf3->GlyphCount - i == buffer->in_length )
-          return TTO_Err_Not_Covered;
-        j++;
-      }
-
-      error = 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 FT_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
-                                      TTO_GPOS_SubTable* st,
-				      OTL_Buffer        buffer,
-                                      FT_UShort         flags,
-                                      FT_UShort         context_length,
-                                      int               nesting_level )
-  {
-    TTO_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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  /* LookupType 8 */
-
-  /* ChainPosRule */
-
-  static FT_Error  Load_ChainPosRule( TTO_ChainPosRule*  cpr,
-                                      FT_Stream          stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, count;
-    FT_UShort*            b;
-    FT_UShort*            i;
-    FT_UShort*            l;
-
-    TTO_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, FT_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, FT_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, FT_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, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( plr );
-
-  Fail2:
-    FREE( l );
-
-  Fail3:
-    FREE( i );
-
-  Fail4:
-    FREE( b );
-    return error;
-  }
-
-
-  static void  Free_ChainPosRule( TTO_ChainPosRule*  cpr,
-				  FT_Memory          memory )
-  {
-    FREE( cpr->PosLookupRecord );
-    FREE( cpr->Lookahead );
-    FREE( cpr->Input );
-    FREE( cpr->Backtrack );
-  }
-
-
-  /* ChainPosRuleSet */
-
-  static FT_Error  Load_ChainPosRuleSet( TTO_ChainPosRuleSet*  cprs,
-                                         FT_Stream             stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort          n, m, count;
-    FT_ULong           cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_ChainPosRule( &cpr[m], memory );
-
-    FREE( cpr );
-    return error;
-  }
-
-
-  static void  Free_ChainPosRuleSet( TTO_ChainPosRuleSet*  cprs,
-				     FT_Memory             memory )
-  {
-    FT_UShort          n, count;
-
-    TTO_ChainPosRule*  cpr;
-
-
-    if ( cprs->ChainPosRule )
-    {
-      count = cprs->ChainPosRuleCount;
-      cpr   = cprs->ChainPosRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainPosRule( &cpr[n], memory );
-
-      FREE( cpr );
-    }
-  }
-
-
-  /* ChainContextPosFormat1 */
-
-  static FT_Error  Load_ChainContextPos1( TTO_ChainContextPosFormat1*  ccpf1,
-                                          FT_Stream                    stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, m, count;
-    FT_ULong              cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &ccpf1->Coverage, stream ) ) != TT_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_ChainPosRuleSet( &cprs[m], memory );
-
-    FREE( cprs );
-
-  Fail2:
-    Free_Coverage( &ccpf1->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_ChainContext1( TTO_ChainContextPosFormat1*  ccpf1,
-				   FT_Memory                    memory )
-  {
-    FT_UShort             n, count;
-
-    TTO_ChainPosRuleSet*  cprs;
-
-
-    if ( ccpf1->ChainPosRuleSet )
-    {
-      count = ccpf1->ChainPosRuleSetCount;
-      cprs  = ccpf1->ChainPosRuleSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainPosRuleSet( &cprs[n], memory );
-
-      FREE( cprs );
-    }
-
-    Free_Coverage( &ccpf1->Coverage, memory );
-  }
-
-
-  /* ChainPosClassRule */
-
-  static FT_Error  Load_ChainPosClassRule(
-                     TTO_ChainContextPosFormat2*  ccpf2,
-                     TTO_ChainPosClassRule*       cpcr,
-                     FT_Stream                    stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, count;
-
-    FT_UShort*            b;
-    FT_UShort*            i;
-    FT_UShort*            l;
-    TTO_PosLookupRecord*  plr;
-    FT_Bool*              d;
-
-
-    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, FT_UShort ) )
-      return error;
-
-    b = cpcr->Backtrack;
-    d = ccpf2->BacktrackClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail4;
-
-    for ( n = 0; n < count; n++ )
-    {
-      b[n] = GET_UShort();
-
-      /* We check whether the specific class is used at all.  If not,
-         class 0 is used instead.                                     */
-
-      if ( !d[b[n]] )
-        b[n] = 0;
-    }
-
-    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, FT_UShort ) )
-      goto Fail4;
-
-    i = cpcr->Input;
-    d = ccpf2->InputClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail3;
-
-    for ( n = 0; n < count; n++ )
-    {
-      i[n] = GET_UShort();
-
-      if ( !d[i[n]] )
-        i[n] = 0;
-    }
-
-    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, FT_UShort ) )
-      goto Fail3;
-
-    l = cpcr->Lookahead;
-    d = ccpf2->LookaheadClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail2;
-
-    for ( n = 0; n < count; n++ )
-    {
-      l[n] = GET_UShort();
-
-      if ( !d[l[n]] )
-        l[n] = 0;
-    }
-
-    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, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( plr );
-
-  Fail2:
-    FREE( l );
-
-  Fail3:
-    FREE( i );
-
-  Fail4:
-    FREE( b );
-    return error;
-  }
-
-
-  static void  Free_ChainPosClassRule( TTO_ChainPosClassRule*  cpcr,
-				       FT_Memory               memory )
-  {
-    FREE( cpcr->PosLookupRecord );
-    FREE( cpcr->Lookahead );
-    FREE( cpcr->Input );
-    FREE( cpcr->Backtrack );
-  }
-
-
-  /* PosClassSet */
-
-  static FT_Error  Load_ChainPosClassSet(
-                     TTO_ChainContextPosFormat2*  ccpf2,
-                     TTO_ChainPosClassSet*        cpcs,
-                     FT_Stream                    stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n, m, count;
-    FT_ULong                cur_offset, new_offset, base_offset;
-
-    TTO_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,
-                      TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_ChainPosClassRule( &cpcr[m], memory );
-
-    FREE( cpcr );
-    return error;
-  }
-
-
-  static void  Free_ChainPosClassSet( TTO_ChainPosClassSet*  cpcs,
-				      FT_Memory              memory )
-  {
-    FT_UShort               n, count;
-
-    TTO_ChainPosClassRule*  cpcr;
-
-
-    if ( cpcs->ChainPosClassRule )
-    {
-      count = cpcs->ChainPosClassRuleCount;
-      cpcr  = cpcs->ChainPosClassRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainPosClassRule( &cpcr[n], memory );
-
-      FREE( cpcr );
-    }
-  }
-
-
-  static FT_Error Load_EmptyOrClassDefinition( TTO_ClassDefinition*  cd,
-                                               FT_UShort             limit,
-					       FT_ULong              class_offset,
-					       FT_ULong              base_offset,
-				               FT_Stream             stream )
-  {
-    FT_Error error;
-    FT_ULong               cur_offset;
-
-    cur_offset = FILE_Pos();
-
-    if ( class_offset )
-      {
-        if ( !FILE_Seek( class_offset + base_offset ) )
-          error = Load_ClassDefinition( cd, limit, stream );
-      }
-    else
-       error = Load_EmptyClassDefinition ( cd, stream );
-
-    if (error == TT_Err_Ok)
-      (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
-
-    return error;
-  }
-
-  /* ChainContextPosFormat2 */
-
-  static FT_Error  Load_ChainContextPos2( TTO_ChainContextPosFormat2*  ccpf2,
-                                          FT_Stream                    stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort              n, m, count;
-    FT_ULong               cur_offset, new_offset, base_offset;
-    FT_ULong               backtrack_offset, input_offset, lookahead_offset;
-
-    TTO_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 = Load_Coverage( &ccpf2->Coverage, stream ) ) != TT_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 = Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
-						backtrack_offset, base_offset,
-						stream ) ) != TT_Err_Ok )
-      goto Fail5;
-    if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
-						input_offset, base_offset,
-						stream ) ) != TT_Err_Ok )
-      goto Fail4;
-    if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
-						lookahead_offset, base_offset,
-						stream ) ) != TT_Err_Ok )
-      goto Fail3;
-
-    ccpf2->ChainPosClassSet   = NULL;
-    ccpf2->MaxBacktrackLength = 0;
-    ccpf2->MaxInputLength     = 0;
-    ccpf2->MaxLookaheadLength = 0;
-
-    if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_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 ) ) != TT_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 TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_ChainPosClassSet( &cpcs[m], memory );
-
-    FREE( cpcs );
-
-  Fail2:
-    Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
-
-  Fail3:
-    Free_ClassDefinition( &ccpf2->InputClassDef, memory );
-
-  Fail4:
-    Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
-
-  Fail5:
-    Free_Coverage( &ccpf2->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_ChainContext2( TTO_ChainContextPosFormat2*  ccpf2,
-				   FT_Memory                    memory )
-  {
-    FT_UShort              n, count;
-
-    TTO_ChainPosClassSet*  cpcs;
-
-
-    if ( ccpf2->ChainPosClassSet )
-    {
-      count = ccpf2->ChainPosClassSetCount;
-      cpcs  = ccpf2->ChainPosClassSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainPosClassSet( &cpcs[n], memory );
-
-      FREE( cpcs );
-    }
-
-    Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
-    Free_ClassDefinition( &ccpf2->InputClassDef, memory );
-    Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
-
-    Free_Coverage( &ccpf2->Coverage, memory );
-  }
-
-
-  /* ChainContextPosFormat3 */
-
-  static FT_Error  Load_ChainContextPos3( TTO_ChainContextPosFormat3*  ccpf3,
-                                          FT_Stream                    stream )
-  {
-    FT_Error  error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n, nb, ni, nl, m, count;
-    FT_UShort             backtrack_count, input_count, lookahead_count;
-    FT_ULong              cur_offset, new_offset, base_offset;
-
-    TTO_Coverage*         b;
-    TTO_Coverage*         i;
-    TTO_Coverage*         l;
-    TTO_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,
-                      TTO_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 = Load_Coverage( &b[nb], stream ) ) != TT_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, TTO_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 = Load_Coverage( &i[ni], stream ) ) != TT_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,
-                      TTO_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 = Load_Coverage( &l[nl], stream ) ) != TT_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, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( plr );
-
-  Fail2:
-    for ( m = 0; m < nl; nl++ )
-      Free_Coverage( &l[m], memory );
-
-    FREE( l );
-
-  Fail3:
-    for ( m = 0; m < ni; n++ )
-      Free_Coverage( &i[m], memory );
-
-    FREE( i );
-
-  Fail4:
-    for ( m = 0; m < nb; n++ )
-      Free_Coverage( &b[m], memory );
-
-    FREE( b );
-    return error;
-  }
-
-
-  static void  Free_ChainContext3( TTO_ChainContextPosFormat3*  ccpf3,
-				   FT_Memory                    memory )
-  {
-    FT_UShort      n, count;
-
-    TTO_Coverage*  c;
-
-
-    FREE( ccpf3->PosLookupRecord );
-
-    if ( ccpf3->LookaheadCoverage )
-    {
-      count = ccpf3->LookaheadGlyphCount;
-      c     = ccpf3->LookaheadCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-
-    if ( ccpf3->InputCoverage )
-    {
-      count = ccpf3->InputGlyphCount;
-      c     = ccpf3->InputCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-
-    if ( ccpf3->BacktrackCoverage )
-    {
-      count = ccpf3->BacktrackGlyphCount;
-      c     = ccpf3->BacktrackCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-  }
-
-
-  /* ChainContextPos */
-
-  FT_Error  Load_ChainContextPos( TTO_ChainContextPos*  ccp,
-                                  FT_Stream             stream )
-  {
-    FT_Error  error;
-
-
-    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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  void  Free_ChainContextPos( TTO_ChainContextPos*  ccp,
-			      FT_Memory             memory )
-  {
-    switch ( ccp->PosFormat )
-    {
-    case 1:
-      Free_ChainContext1( &ccp->ccpf.ccpf1, memory );
-      break;
-
-    case 2:
-      Free_ChainContext2( &ccp->ccpf.ccpf2, memory );
-      break;
-
-    case 3:
-      Free_ChainContext3( &ccp->ccpf.ccpf3, memory );
-      break;
-    }
-  }
-
-
-  static FT_Error  Lookup_ChainContextPos1(
-                     GPOS_Instance*               gpi,
-                     TTO_ChainContextPosFormat1*  ccpf1,
-		     OTL_Buffer                   buffer,
-                     FT_UShort                    flags,
-                     FT_UShort                    context_length,
-                     int                          nesting_level )
-  {
-    FT_UShort          index, property;
-    FT_UShort          i, j, k, num_cpr;
-    FT_UShort          bgc, igc, lgc;
-    FT_Error           error;
-    TTO_GPOSHeader*    gpos = gpi->gpos;
-
-    TTO_ChainPosRule*  cpr;
-    TTO_ChainPosRule   curr_cpr;
-    TTO_GDEFHeader*    gdef;
-
-
-    gdef = gpos->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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 ) )
-          {
-            if ( error && error != TTO_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 ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-          if ( j + igc - i + lgc == 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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-          if ( j + lgc - i == 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 TTO_Err_Not_Covered;
-  }
-
-
-  static FT_Error  Lookup_ChainContextPos2(
-                     GPOS_Instance*               gpi,
-                     TTO_ChainContextPosFormat2*  ccpf2,
-		     OTL_Buffer                   buffer,
-                     FT_UShort                    flags,
-                     FT_UShort                    context_length,
-                     int                          nesting_level )
-  {
-    FT_UShort              index, property;
-    FT_Memory              memory = gpi->face->memory;
-    FT_Error               error;
-    FT_UShort              i, j, k;
-    FT_UShort              bgc, igc, lgc;
-    FT_UShort              known_backtrack_classes,
-                           known_input_classes,
-                           known_lookahead_classes;
-
-    FT_UShort*             backtrack_classes;
-    FT_UShort*             input_classes;
-    FT_UShort*             lookahead_classes;
-
-    FT_UShort*             bc;
-    FT_UShort*             ic;
-    FT_UShort*             lc;
-    TTO_GPOSHeader*        gpos = gpi->gpos;
-
-    TTO_ChainPosClassSet*  cpcs;
-    TTO_ChainPosClassRule  cpcr;
-    TTO_GDEFHeader*        gdef;
-
-
-    gdef = gpos->gdef;
-
-    if ( CHECK_Property( gdef, 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 = Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-      return error;
-
-    if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, FT_UShort ) )
-      return error;
-    known_backtrack_classes = 0;
-
-    if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, FT_UShort ) )
-      goto End3;
-    known_input_classes = 1;
-
-    if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, FT_UShort ) )
-      goto End2;
-    known_lookahead_classes = 0;
-
-    error = Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
-                       &input_classes[0], NULL );
-    if ( error && error != TTO_Err_Not_Covered )
-      goto End1;
-
-    cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
-    if ( !cpcs )
-    {
-      error = TTO_Err_Invalid_GPOS_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 ) )
-          {
-            if ( error && error != TTO_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 = Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
-                               &backtrack_classes[i], NULL );
-            if ( error && error != TTO_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 ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            goto End1;
-
-          if ( j + igc - i + lgc == buffer->in_length )
-            goto next_chainposclassrule;
-          j++;
-        }
-
-        if ( i >= known_input_classes )
-        {
-          error = Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
-                             &input_classes[i], NULL );
-          if ( error && error != TTO_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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            goto End1;
-
-          if ( j + lgc - i == buffer->in_length )
-            goto next_chainposclassrule;
-          j++;
-        }
-
-        if ( i >= known_lookahead_classes )
-        {
-          error = Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
-                             &lookahead_classes[i], NULL );
-          if ( error && error != TTO_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 = TTO_Err_Not_Covered;
-
-  End1:
-    FREE( lookahead_classes );
-
-  End2:
-    FREE( input_classes );
-
-  End3:
-    FREE( backtrack_classes );
-    return error;
-  }
-
-
-  static FT_Error  Lookup_ChainContextPos3(
-                     GPOS_Instance*               gpi,
-                     TTO_ChainContextPosFormat3*  ccpf3,
-		     OTL_Buffer                   buffer,
-                     FT_UShort                    flags,
-                     FT_UShort                    context_length,
-                     int                          nesting_level )
-  {
-    FT_UShort        index, i, j, property;
-    FT_UShort        bgc, igc, lgc;
-    FT_Error         error;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-
-    TTO_Coverage*    bc;
-    TTO_Coverage*    ic;
-    TTO_Coverage*    lc;
-    TTO_GDEFHeader*  gdef;
-
-
-    gdef = gpos->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    bgc = ccpf3->BacktrackGlyphCount;
-    igc = ccpf3->InputGlyphCount;
-    lgc = ccpf3->LookaheadGlyphCount;
-
-    if ( context_length != 0xFFFF && context_length < igc )
-      return TTO_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 TTO_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 ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-          if ( j + 1 == bgc - i )
-            return TTO_Err_Not_Covered;
-          j--;
-        }
-
-        error = 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 ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-      {
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-
-        if ( j + igc - i + lgc == buffer->in_length )
-          return TTO_Err_Not_Covered;
-        j++;
-      }
-
-      error = 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( gdef, IN_ITEM( j ), flags, &property ) )
-      {
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-
-        if ( j + lgc - i == buffer->in_length )
-          return TTO_Err_Not_Covered;
-        j++;
-      }
-
-      error = 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 FT_Error  Lookup_ChainContextPos(
-                     GPOS_Instance*        gpi,
-		     TTO_GPOS_SubTable* st,
-		     OTL_Buffer            buffer,
-                     FT_UShort             flags,
-                     FT_UShort             context_length,
-                     int                   nesting_level )
-  {
-    TTO_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 TTO_Err_Invalid_GPOS_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-
-  /***********
-   * GPOS API
-   ***********/
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Select_Script( TTO_GPOSHeader*  gpos,
-                                   FT_ULong         script_tag,
-                                   FT_UShort*       script_index )
-  {
-    FT_UShort          n;
-
-    TTO_ScriptList*    sl;
-    TTO_ScriptRecord*  sr;
-
-
-    if ( !gpos || !script_index )
-      return TT_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 TT_Err_Ok;
-      }
-
-    return TTO_Err_Not_Covered;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Select_Language( TTO_GPOSHeader*  gpos,
-                                     FT_ULong         language_tag,
-                                     FT_UShort        script_index,
-                                     FT_UShort*       language_index,
-                                     FT_UShort*       req_feature_index )
-  {
-    FT_UShort           n;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-
-
-    if ( !gpos || !language_index || !req_feature_index )
-      return TT_Err_Invalid_Argument;
-
-    sl = &gpos->ScriptList;
-    sr = sl->ScriptRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_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 TT_Err_Ok;
-      }
-
-    return TTO_Err_Not_Covered;
-  }
-
-
-  /* selecting 0xFFFF for language_index asks for the values of the
-     default language (DefaultLangSys)                              */
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Select_Feature( TTO_GPOSHeader*  gpos,
-                                    FT_ULong         feature_tag,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_UShort*       feature_index )
-  {
-    FT_UShort           n;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-    TTO_LangSys*        ls;
-    FT_UShort*          fi;
-
-    TTO_FeatureList*    fl;
-    TTO_FeatureRecord*  fr;
-
-
-    if ( !gpos || !feature_index )
-      return TT_Err_Invalid_Argument;
-
-    sl = &gpos->ScriptList;
-    sr = sl->ScriptRecord;
-
-    fl = &gpos->FeatureList;
-    fr = fl->FeatureRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_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 TT_Err_Invalid_Argument;
-
-      ls = &lsr[language_index].LangSys;
-    }
-
-    fi = ls->FeatureIndex;
-
-    for ( n = 0; n < ls->FeatureCount; n++ )
-    {
-      if ( fi[n] >= fl->FeatureCount )
-        return TTO_Err_Invalid_GPOS_SubTable_Format;
-
-      if ( feature_tag == fr[fi[n]].FeatureTag )
-      {
-        *feature_index = fi[n];
-
-        return TT_Err_Ok;
-      }
-    }
-
-    return TTO_Err_Not_Covered;
-  }
-
-
-  /* The next three functions return a null-terminated list */
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Query_Scripts( TTO_GPOSHeader*  gpos,
-                                   FT_ULong**       script_tag_list )
-  {
-    FT_Error           error;
-    FT_Memory          memory = gpos->memory;
-    FT_UShort          n;
-    FT_ULong*          stl;
-
-    TTO_ScriptList*    sl;
-    TTO_ScriptRecord*  sr;
-
-
-    if ( !gpos || !script_tag_list )
-      return TT_Err_Invalid_Argument;
-
-    sl = &gpos->ScriptList;
-    sr = sl->ScriptRecord;
-
-    if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) )
-      return error;
-
-    for ( n = 0; n < sl->ScriptCount; n++ )
-      stl[n] = sr[n].ScriptTag;
-    stl[n] = 0;
-
-    *script_tag_list = stl;
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Query_Languages( TTO_GPOSHeader*  gpos,
-                                     FT_UShort        script_index,
-                                     FT_ULong**       language_tag_list )
-  {
-    FT_Error            error;
-    FT_Memory           memory = gpos->memory;
-    FT_UShort           n;
-    FT_ULong*           ltl;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-
-
-    if ( !gpos || !language_tag_list )
-      return TT_Err_Invalid_Argument;
-
-    sl = &gpos->ScriptList;
-    sr = sl->ScriptRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_Err_Invalid_Argument;
-
-    s   = &sr[script_index].Script;
-    lsr = s->LangSysRecord;
-
-    if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) )
-      return error;
-
-    for ( n = 0; n < s->LangSysCount; n++ )
-      ltl[n] = lsr[n].LangSysTag;
-    ltl[n] = 0;
-
-    *language_tag_list = ltl;
-
-    return TT_Err_Ok;
-  }
-
-
-  /* selecting 0xFFFF for language_index asks for the values of the
-     default language (DefaultLangSys)                              */
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Query_Features( TTO_GPOSHeader*  gpos,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_ULong**       feature_tag_list )
-  {
-    FT_UShort           n;
-    FT_Error            error;
-    FT_Memory           memory = gpos->memory;
-    FT_ULong*           ftl;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-    TTO_LangSys*        ls;
-    FT_UShort*          fi;
-
-    TTO_FeatureList*    fl;
-    TTO_FeatureRecord*  fr;
-
-
-    if ( !gpos || !feature_tag_list )
-      return TT_Err_Invalid_Argument;
-
-    sl = &gpos->ScriptList;
-    sr = sl->ScriptRecord;
-
-    fl = &gpos->FeatureList;
-    fr = fl->FeatureRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_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 TT_Err_Invalid_Argument;
-
-      ls = &lsr[language_index].LangSys;
-    }
-
-    fi = ls->FeatureIndex;
-
-    if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) )
-      return error;
-
-    for ( n = 0; n < ls->FeatureCount; n++ )
-    {
-      if ( fi[n] >= fl->FeatureCount )
-      {
-        FREE( ftl );
-        return TTO_Err_Invalid_GPOS_SubTable_Format;
-      }
-      ftl[n] = fr[fi[n]].FeatureTag;
-    }
-    ftl[n] = 0;
-
-    *feature_tag_list = ftl;
-
-    return TT_Err_Ok;
-  }
-
-
-  typedef FT_Error  (*Lookup_Func_Type)  ( GPOS_Instance*    gpi,
-					   TTO_GPOS_SubTable* st,
-					   OTL_Buffer        buffer,
-					   FT_UShort         flags,
-					   FT_UShort         context_length,
-					   int               nesting_level );
-  static const Lookup_Func_Type Lookup_Call_Table[] = {
-    Lookup_DefaultPos,
-    Lookup_SinglePos,		/* GPOS_LOOKUP_SINGLE     1 */
-    Lookup_PairPos,		/* GPOS_LOOKUP_PAIR       2 */
-    Lookup_CursivePos,		/* GPOS_LOOKUP_CURSIVE    3 */
-    Lookup_MarkBasePos,		/* GPOS_LOOKUP_MARKBASE   4 */
-    Lookup_MarkLigPos,		/* GPOS_LOOKUP_MARKLIG    5 */
-    Lookup_MarkMarkPos,		/* GPOS_LOOKUP_MARKMARK   6 */
-    Lookup_ContextPos,		/* GPOS_LOOKUP_CONTEXT    7 */
-    Lookup_ChainContextPos,	/* GPOS_LOOKUP_CHAIN      8 */
-    Lookup_DefaultPos,		/* GPOS_LOOKUP_EXTENSION  9 */
-  };
-
-  /* Do an individual subtable lookup.  Returns TT_Err_Ok if positioning
-     has been done, or TTO_Err_Not_Covered if not.                        */
-
-  static FT_Error  Do_Glyph_Lookup( GPOS_Instance*    gpi,
-                                    FT_UShort         lookup_index,
-				    OTL_Buffer        buffer,
-                                    FT_UShort         context_length,
-                                    int               nesting_level )
-  {
-    FT_Error         error = TTO_Err_Not_Covered;
-    FT_UShort        i, flags, lookup_count;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-    TTO_Lookup*      lo;
-    int		     lt;
-    Lookup_Func_Type Lookup_Func;
-
-
-    nesting_level++;
-
-    if ( nesting_level > TTO_MAX_NESTING_LEVEL )
-      return TTO_Err_Too_Many_Nested_Contexts;
-
-    lookup_count = gpos->LookupList.LookupCount;
-    if (lookup_index >= lookup_count)
-      return error;
-
-    lo    = &gpos->LookupList.Lookup[lookup_index];
-    flags = lo->LookupFlag;
-    lt = lo->LookupType;
-    if (lt >= sizeof Lookup_Call_Table / sizeof Lookup_Call_Table[0])
-      lt = 0;
-    Lookup_Func = Lookup_Call_Table[lt];
-
-    for ( i = 0; i < lo->SubTableCount; i++ )
-    {
-      error = Lookup_Func ( gpi,
-			    &lo->SubTable[i].st.gpos,
-			    buffer,
-			    flags, context_length,
-			    nesting_level );
-
-      /* Check whether we have a successful positioning or an error other
-         than TTO_Err_Not_Covered                                         */
-
-      if ( error != TTO_Err_Not_Covered )
-        return error;
-    }
-
-    return TTO_Err_Not_Covered;
-  }
-
-
-  /* apply one lookup to the input string object */
-
-  static FT_Error  Do_String_Lookup( GPOS_Instance*    gpi,
-                                     FT_UShort         lookup_index,
-				     OTL_Buffer        buffer )
-  {
-    FT_Error         error, retError = TTO_Err_Not_Covered;
-    TTO_GPOSHeader*  gpos = gpi->gpos;
-
-    FT_UInt*  properties = gpos->LookupList.Properties;
-
-    int       nesting_level = 0;
-
-
-    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] )
-      {
-        /* 0xFFFF indicates that we don't have a context length yet. */
-
-        /* 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 = Do_Glyph_Lookup( gpi, lookup_index, buffer,
-                                 0xFFFF, nesting_level );
-        if ( error && error != TTO_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 = TTO_Err_Not_Covered;
-      }
-
-      if ( error == TTO_Err_Not_Covered )
-        (buffer->in_pos)++;
-      else
-	retError = error;
-    }
-
-    return retError;
-  }
-
-
-  static FT_Error  Position_CursiveChain ( OTL_Buffer     buffer )
-  {
-    FT_ULong   i, j;
-    OTL_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 TT_Err_Ok;
-  }
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Add_Feature( TTO_GPOSHeader*  gpos,
-                                 FT_UShort        feature_index,
-                                 FT_UInt          property )
-  {
-    FT_UShort    i;
-
-    TTO_Feature  feature;
-    FT_UInt*     properties;
-    FT_UShort*   index;
-    FT_UShort    lookup_count;
-
-    /* Each feature can only be added once */
-    
-    if ( !gpos ||
-         feature_index >= gpos->FeatureList.FeatureCount ||
-	 gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
-      return TT_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++ )
-    {
-      FT_UShort lookup_index = index[i];
-      if (lookup_index < lookup_count)
-	properties[lookup_index] |= property;
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Clear_Features( TTO_GPOSHeader*  gpos )
-  {
-    FT_UShort i;
-
-    FT_UInt*  properties;
-
-
-    if ( !gpos )
-      return TT_Err_Invalid_Argument;
-
-    gpos->FeatureList.ApplyCount = 0;
-
-    properties = gpos->LookupList.Properties;
-
-    for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
-      properties[i] = 0;
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Register_Glyph_Function( TTO_GPOSHeader*    gpos,
-                                             TTO_GlyphFunction  gfunc )
-  {
-    if ( !gpos )
-      return TT_Err_Invalid_Argument;
-
-    gpos->gfunc = gfunc;
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Register_MM_Function( TTO_GPOSHeader*  gpos,
-                                          TTO_MMFunction   mmfunc,
-                                          void*            data )
-  {
-    if ( !gpos )
-      return TT_Err_Invalid_Argument;
-
-    gpos->mmfunc = mmfunc;
-    gpos->data   = data;
-
-    return TT_Err_Ok;
-  }
-
-  /* If `dvi' is TRUE, glyph contour points for anchor points and device
-     tables are ignored -- you will get device independent values.         */
-
-  EXPORT_FUNC
-  FT_Error  TT_GPOS_Apply_String( FT_Face            face,
-                                  TTO_GPOSHeader*    gpos,
-                                  FT_UShort          load_flags,
-				  OTL_Buffer         buffer,
-                                  FT_Bool            dvi,
-                                  FT_Bool            r2l )
-  {
-    FT_Error       error, retError = TTO_Err_Not_Covered;
-    GPOS_Instance  gpi;
-    FT_UShort      i, j, feature_index, lookup_count;
-    TTO_Feature    feature;
-
-    if ( !face || !gpos ||
-         !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length )
-      return TT_Err_Invalid_Argument;
-
-    gpi.face       = face;
-    gpi.gpos       = gpos;
-    gpi.load_flags = load_flags;
-    gpi.r2l        = r2l;
-    gpi.dvi        = dvi;
-    
-    lookup_count = gpos->LookupList.LookupCount;
-
-    for ( i = 0; i < gpos->FeatureList.ApplyCount; i++ )
-    { 
-      /* index of i'th feature */
-      feature_index = gpos->FeatureList.ApplyOrder[i];
-      feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
-
-      for ( j = 0; j < feature.LookupListCount; j++ )
-      {
-	FT_UShort lookup_index = feature.LookupListIndex[j];
-
-	/* Skip nonexistant lookups */
-        if (lookup_index >= lookup_count)
-	 continue;
-
-	error = Do_String_Lookup( &gpi, lookup_index, buffer );
-	if ( error )
-	{
-	  if ( error != TTO_Err_Not_Covered )
-	    return error;
-	}
-	else
-	  retError = error;
-      }
-    }
-    
-    error = Position_CursiveChain ( buffer );
-    if ( error )
-      return error;
-
-    return retError;
-  }
-
-/* END */
diff --git a/src/ftxgpos.h b/src/ftxgpos.h
deleted file mode 100644
index 28d1bae..0000000
--- a/src/ftxgpos.h
+++ /dev/null
@@ -1,838 +0,0 @@
-/*******************************************************************
- *
- *  ftxgpos.h
- *
- *    TrueType Open GPOS table support
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#ifndef FTXOPEN_H
-#error "Don't include this file! Use ftxopen.h instead."
-#endif
-
-#ifndef FTXGPOS_H
-#define FTXGPOS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define TTO_Err_Invalid_GPOS_SubTable_Format  0x1020
-#define TTO_Err_Invalid_GPOS_SubTable         0x1021
-
-
-/* Lookup types for glyph positioning */
-
-#define GPOS_LOOKUP_SINGLE     1
-#define GPOS_LOOKUP_PAIR       2
-#define GPOS_LOOKUP_CURSIVE    3
-#define GPOS_LOOKUP_MARKBASE   4
-#define GPOS_LOOKUP_MARKLIG    5
-#define GPOS_LOOKUP_MARKMARK   6
-#define GPOS_LOOKUP_CONTEXT    7
-#define GPOS_LOOKUP_CHAIN      8
-#define GPOS_LOOKUP_EXTENSION  9
-
-
-  /* A pointer to a function which loads a glyph.  Its parameters are
-     the same as in a call to TT_Load_Glyph() -- if no glyph loading
-     function will be registered with TTO_GPOS_Register_Glyph_Function(),
-     TT_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.  _glyph can be computed with
-
-        _glyph = HANDLE_Glyph( glyph )                                    */
-
-  typedef FT_Error  (*TTO_GlyphFunction)(FT_Face      face,
-					 FT_UInt      glyphIndex,
-					 FT_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 TT_GPOS_Register_MM_Function().
-
-     `metric_value' must be returned as a scaled value (but shouldn't
-     be rounded).                                                       */
-
-  typedef FT_Error  (*TTO_MMFunction)(FT_Face      face,
-				      FT_UShort    metric_id,
-                                      FT_Pos*      metric_value,
-                                      void*        data );
-                                          
-
-  struct  TTO_GPOSHeader_
-  {
-    FT_Memory          memory;
-    
-    FT_Fixed           Version;
-
-    TTO_ScriptList     ScriptList;
-    TTO_FeatureList    FeatureList;
-    TTO_LookupList     LookupList;
-
-    TTO_GDEFHeader*    gdef;
-
-    /* the next field is used for a callback function to get the
-       glyph outline.                                            */
-
-    TTO_GlyphFunction  gfunc;
-
-    /* this is OpenType 1.2 -- Multiple Master fonts need this
-       callback function to get various metric values from the
-       PostScript interpreter.                                 */
-
-    TTO_MMFunction     mmfunc;
-    void*              data;
-  };
-
-  typedef struct TTO_GPOSHeader_  TTO_GPOSHeader;
-  typedef struct TTO_GPOSHeader_* TTO_GPOS;
-
-
-  /* shared tables */
-
-  struct  TTO_ValueRecord_
-  {
-    FT_Short    XPlacement;             /* horizontal adjustment for
-                                           placement                      */
-    FT_Short    YPlacement;             /* vertical adjustment for
-                                           placement                      */
-    FT_Short    XAdvance;               /* horizontal adjustment for
-                                           advance                        */
-    FT_Short    YAdvance;               /* vertical adjustment for
-                                           advance                        */
-    TTO_Device  XPlacementDevice;       /* device table for horizontal
-                                           placement                      */
-    TTO_Device  YPlacementDevice;       /* device table for vertical
-                                           placement                      */
-    TTO_Device  XAdvanceDevice;         /* device table for horizontal
-                                           advance                        */
-    TTO_Device  YAdvanceDevice;         /* device table for vertical
-                                           advance                        */
-    FT_UShort   XIdPlacement;           /* horizontal placement metric ID */
-    FT_UShort   YIdPlacement;           /* vertical placement metric ID   */
-    FT_UShort   XIdAdvance;             /* horizontal advance metric ID   */
-    FT_UShort   YIdAdvance;             /* vertical advance metric ID     */
-  };
-
-  typedef struct TTO_ValueRecord_  TTO_ValueRecord;
-
-
-/* Mask values to scan the value format of the ValueRecord structure.
-   We always expand compressed ValueRecords of the font.              */
-
-#define HAVE_X_PLACEMENT         0x0001
-#define HAVE_Y_PLACEMENT         0x0002
-#define HAVE_X_ADVANCE           0x0004
-#define HAVE_Y_ADVANCE           0x0008
-#define HAVE_X_PLACEMENT_DEVICE  0x0010
-#define HAVE_Y_PLACEMENT_DEVICE  0x0020
-#define HAVE_X_ADVANCE_DEVICE    0x0040
-#define HAVE_Y_ADVANCE_DEVICE    0x0080
-#define HAVE_X_ID_PLACEMENT      0x0100
-#define HAVE_Y_ID_PLACEMENT      0x0200
-#define HAVE_X_ID_ADVANCE        0x0400
-#define HAVE_Y_ID_ADVANCE        0x0800
-
-
-  struct  TTO_AnchorFormat1_
-  {
-    FT_Short   XCoordinate;             /* horizontal value */
-    FT_Short   YCoordinate;             /* vertical value   */
-  };
-
-  typedef struct TTO_AnchorFormat1_  TTO_AnchorFormat1;
-
-
-  struct  TTO_AnchorFormat2_
-  {
-    FT_Short   XCoordinate;             /* horizontal value             */
-    FT_Short   YCoordinate;             /* vertical value               */
-    FT_UShort  AnchorPoint;             /* index to glyph contour point */
-  };
-
-  typedef struct TTO_AnchorFormat2_  TTO_AnchorFormat2;
-
-
-  struct  TTO_AnchorFormat3_
-  {
-    FT_Short    XCoordinate;            /* horizontal value              */
-    FT_Short    YCoordinate;            /* vertical value                */
-    TTO_Device  XDeviceTable;           /* device table for X coordinate */
-    TTO_Device  YDeviceTable;           /* device table for Y coordinate */
-  };
-
-  typedef struct TTO_AnchorFormat3_  TTO_AnchorFormat3;
-
-
-  struct  TTO_AnchorFormat4_
-  {
-    FT_UShort  XIdAnchor;               /* horizontal metric ID */
-    FT_UShort  YIdAnchor;               /* vertical metric ID   */
-  };
-
-  typedef struct TTO_AnchorFormat4_  TTO_AnchorFormat4;
-
-
-  struct  TTO_Anchor_
-  {
-    FT_UShort  PosFormat;               /* 1, 2, 3, or 4 -- 0 indicates
-                                           that there is no Anchor table */
-
-    union
-    {
-      TTO_AnchorFormat1  af1;
-      TTO_AnchorFormat2  af2;
-      TTO_AnchorFormat3  af3;
-      TTO_AnchorFormat4  af4;
-    } af;
-  };
-
-  typedef struct TTO_Anchor_  TTO_Anchor;
-
-
-  struct  TTO_MarkRecord_
-  {
-    FT_UShort   Class;                  /* mark class   */
-    TTO_Anchor  MarkAnchor;             /* anchor table */
-  };
-
-  typedef struct TTO_MarkRecord_  TTO_MarkRecord;
-
-
-  struct  TTO_MarkArray_
-  {
-    FT_UShort        MarkCount;         /* number of MarkRecord tables */
-    TTO_MarkRecord*  MarkRecord;        /* array of MarkRecord tables  */
-  };
-
-  typedef struct TTO_MarkArray_  TTO_MarkArray;
-
-
-  /* LookupType 1 */
-
-  struct  TTO_SinglePosFormat1_
-  {
-    TTO_ValueRecord  Value;             /* ValueRecord for all covered
-                                           glyphs                      */
-  };
-
-  typedef struct TTO_SinglePosFormat1_  TTO_SinglePosFormat1;
-
-
-  struct  TTO_SinglePosFormat2_
-  {
-    FT_UShort         ValueCount;       /* number of ValueRecord tables */
-    TTO_ValueRecord*  Value;            /* array of ValueRecord tables  */
-  };
-
-  typedef struct TTO_SinglePosFormat2_  TTO_SinglePosFormat2;
-
-
-  struct  TTO_SinglePos_
-  {
-    FT_UShort     PosFormat;            /* 1 or 2         */
-    TTO_Coverage  Coverage;             /* Coverage table */
-
-    FT_UShort     ValueFormat;          /* format of ValueRecord table */
-
-    union
-    {
-      TTO_SinglePosFormat1  spf1;
-      TTO_SinglePosFormat2  spf2;
-    } spf;
-  };
-
-  typedef struct TTO_SinglePos_  TTO_SinglePos;
-
-
-  /* LookupType 2 */
-
-  struct  TTO_PairValueRecord_
-  {
-    FT_UShort        SecondGlyph;       /* glyph ID for second glyph  */
-    TTO_ValueRecord  Value1;            /* pos. data for first glyph  */
-    TTO_ValueRecord  Value2;            /* pos. data for second glyph */
-  };
-
-  typedef struct TTO_PairValueRecord_  TTO_PairValueRecord;
-
-
-  struct  TTO_PairSet_
-  {
-    FT_UShort             PairValueCount;
-                                        /* number of PairValueRecord tables */
-    TTO_PairValueRecord*  PairValueRecord;
-                                        /* array of PairValueRecord tables  */
-  };
-
-  typedef struct TTO_PairSet_  TTO_PairSet;
-
-
-  struct  TTO_PairPosFormat1_
-  {
-    FT_UShort     PairSetCount;         /* number of PairSet tables    */
-    TTO_PairSet*  PairSet;              /* array of PairSet tables     */
-  };
-
-  typedef struct TTO_PairPosFormat1_  TTO_PairPosFormat1;
-
-
-  struct  TTO_Class2Record_
-  {
-    TTO_ValueRecord  Value1;            /* pos. data for first glyph  */
-    TTO_ValueRecord  Value2;            /* pos. data for second glyph */
-  };
-
-  typedef struct TTO_Class2Record_  TTO_Class2Record;
-
-
-  struct  TTO_Class1Record_
-  {
-    TTO_Class2Record*  Class2Record;    /* array of Class2Record tables */
-  };
-
-  typedef struct TTO_Class1Record_  TTO_Class1Record;
-
-
-  struct  TTO_PairPosFormat2_
-  {
-    TTO_ClassDefinition  ClassDef1;     /* class def. for first glyph     */
-    TTO_ClassDefinition  ClassDef2;     /* class def. for second glyph    */
-    FT_UShort            Class1Count;   /* number of classes in ClassDef1
-                                           table                          */
-    FT_UShort            Class2Count;   /* number of classes in ClassDef2
-                                           table                          */
-    TTO_Class1Record*    Class1Record;  /* array of Class1Record tables   */
-  };
-
-  typedef struct TTO_PairPosFormat2_  TTO_PairPosFormat2;
-
-
-  struct  TTO_PairPos_
-  {
-    FT_UShort     PosFormat;            /* 1 or 2         */
-    TTO_Coverage  Coverage;             /* Coverage table */
-    FT_UShort     ValueFormat1;         /* format of ValueRecord table
-                                           for first glyph             */
-    FT_UShort     ValueFormat2;         /* format of ValueRecord table
-                                           for second glyph            */
-
-    union
-    {
-      TTO_PairPosFormat1  ppf1;
-      TTO_PairPosFormat2  ppf2;
-    } ppf;
-  };
-
-  typedef struct TTO_PairPos_  TTO_PairPos;
-
-
-  /* LookupType 3 */
-
-  struct  TTO_EntryExitRecord_
-  {
-    TTO_Anchor  EntryAnchor;            /* entry Anchor table */
-    TTO_Anchor  ExitAnchor;             /* exit Anchor table  */
-  };
-
-
-  typedef struct TTO_EntryExitRecord_  TTO_EntryExitRecord;
-
-  struct  TTO_CursivePos_
-  {
-    FT_UShort             PosFormat;    /* always 1                         */
-    TTO_Coverage          Coverage;     /* Coverage table                   */
-    FT_UShort             EntryExitCount;
-                                        /* number of EntryExitRecord tables */
-    TTO_EntryExitRecord*  EntryExitRecord;
-                                        /* array of EntryExitRecord tables  */
-  };
-
-  typedef struct TTO_CursivePos_  TTO_CursivePos;
-
-
-  /* LookupType 4 */
-
-  struct  TTO_BaseRecord_
-  {
-    TTO_Anchor*  BaseAnchor;            /* array of base glyph anchor
-                                           tables                     */
-  };
-
-  typedef struct TTO_BaseRecord_  TTO_BaseRecord;
-
-
-  struct  TTO_BaseArray_
-  {
-    FT_UShort        BaseCount;         /* number of BaseRecord tables */
-    TTO_BaseRecord*  BaseRecord;        /* array of BaseRecord tables  */
-  };
-
-  typedef struct TTO_BaseArray_  TTO_BaseArray;
-
-
-  struct  TTO_MarkBasePos_
-  {
-    FT_UShort      PosFormat;           /* always 1                  */
-    TTO_Coverage   MarkCoverage;        /* mark glyph coverage table */
-    TTO_Coverage   BaseCoverage;        /* base glyph coverage table */
-    FT_UShort      ClassCount;          /* number of mark classes    */
-    TTO_MarkArray  MarkArray;           /* mark array table          */
-    TTO_BaseArray  BaseArray;           /* base array table          */
-  };
-
-  typedef struct TTO_MarkBasePos_  TTO_MarkBasePos;
-
-
-  /* LookupType 5 */
-
-  struct  TTO_ComponentRecord_
-  {
-    TTO_Anchor*  LigatureAnchor;        /* array of ligature glyph anchor
-                                           tables                         */
-  };
-
-  typedef struct TTO_ComponentRecord_  TTO_ComponentRecord;
-
-
-  struct  TTO_LigatureAttach_
-  {
-    FT_UShort             ComponentCount;
-                                        /* number of ComponentRecord tables */
-    TTO_ComponentRecord*  ComponentRecord;
-                                        /* array of ComponentRecord tables  */
-  };
-
-  typedef struct TTO_LigatureAttach_  TTO_LigatureAttach;
-
-
-  struct  TTO_LigatureArray_
-  {
-    FT_UShort            LigatureCount; /* number of LigatureAttach tables */
-    TTO_LigatureAttach*  LigatureAttach;
-                                        /* array of LigatureAttach tables  */
-  };
-
-  typedef struct TTO_LigatureArray_  TTO_LigatureArray;
-
-
-  struct  TTO_MarkLigPos_
-  {
-    FT_UShort          PosFormat;       /* always 1                      */
-    TTO_Coverage       MarkCoverage;    /* mark glyph coverage table     */
-    TTO_Coverage       LigatureCoverage;
-                                        /* ligature glyph coverage table */
-    FT_UShort          ClassCount;      /* number of mark classes        */
-    TTO_MarkArray      MarkArray;       /* mark array table              */
-    TTO_LigatureArray  LigatureArray;   /* ligature array table          */
-  };
-
-  typedef struct TTO_MarkLigPos_  TTO_MarkLigPos;
-
-
-  /* LookupType 6 */
-
-  struct  TTO_Mark2Record_
-  {
-    TTO_Anchor*  Mark2Anchor;           /* array of mark glyph anchor
-                                           tables                     */
-  };
-
-  typedef struct TTO_Mark2Record_  TTO_Mark2Record;
-
-
-  struct  TTO_Mark2Array_
-  {
-    FT_UShort         Mark2Count;       /* number of Mark2Record tables */
-    TTO_Mark2Record*  Mark2Record;      /* array of Mark2Record tables  */
-  };
-
-  typedef struct TTO_Mark2Array_  TTO_Mark2Array;
-
-
-  struct  TTO_MarkMarkPos_
-  {
-    FT_UShort       PosFormat;          /* always 1                         */
-    TTO_Coverage    Mark1Coverage;      /* first mark glyph coverage table  */
-    TTO_Coverage    Mark2Coverage;      /* second mark glyph coverave table */
-    FT_UShort       ClassCount;         /* number of combining mark classes */
-    TTO_MarkArray   Mark1Array;         /* MarkArray table for first mark   */
-    TTO_Mark2Array  Mark2Array;         /* MarkArray table for second mark  */
-  };
-
-  typedef struct TTO_MarkMarkPos_  TTO_MarkMarkPos;
-
-
-  /* needed by both lookup type 7 and 8 */
-
-  struct  TTO_PosLookupRecord_
-  {
-    FT_UShort  SequenceIndex;           /* index into current
-                                           glyph sequence               */
-    FT_UShort  LookupListIndex;         /* Lookup to apply to that pos. */
-  };
-
-  typedef struct TTO_PosLookupRecord_  TTO_PosLookupRecord;
-
-
-  /* LookupType 7 */
-
-  struct  TTO_PosRule_
-  {
-    FT_UShort             GlyphCount;   /* total number of input glyphs     */
-    FT_UShort             PosCount;     /* number of PosLookupRecord tables */
-    FT_UShort*            Input;        /* array of input glyph IDs         */
-    TTO_PosLookupRecord*  PosLookupRecord;
-                                        /* array of PosLookupRecord tables  */
-  };
-
-  typedef struct TTO_PosRule_  TTO_PosRule;
-
-
-  struct  TTO_PosRuleSet_
-  {
-    FT_UShort     PosRuleCount;         /* number of PosRule tables */
-    TTO_PosRule*  PosRule;              /* array of PosRule tables  */
-  };
-
-  typedef struct TTO_PosRuleSet_  TTO_PosRuleSet;
-
-
-  struct  TTO_ContextPosFormat1_
-  {
-    TTO_Coverage     Coverage;          /* Coverage table              */
-    FT_UShort        PosRuleSetCount;   /* number of PosRuleSet tables */
-    TTO_PosRuleSet*  PosRuleSet;        /* array of PosRuleSet tables  */
-  };
-
-  typedef struct TTO_ContextPosFormat1_  TTO_ContextPosFormat1;
-
-
-  struct  TTO_PosClassRule_
-  {
-    FT_UShort             GlyphCount;   /* total number of context classes  */
-    FT_UShort             PosCount;     /* number of PosLookupRecord tables */
-    FT_UShort*            Class;        /* array of classes                 */
-    TTO_PosLookupRecord*  PosLookupRecord;
-                                        /* array of PosLookupRecord tables  */
-  };
-
-  typedef struct TTO_PosClassRule_  TTO_PosClassRule;
-
-
-  struct  TTO_PosClassSet_
-  {
-    FT_UShort          PosClassRuleCount;
-                                        /* number of PosClassRule tables */
-    TTO_PosClassRule*  PosClassRule;    /* array of PosClassRule tables  */
-  };
-
-  typedef struct TTO_PosClassSet_  TTO_PosClassSet;
-
-
-  /* The `MaxContextLength' field is not defined in the TTO specification
-     but simplifies the implementation of this format.  It holds the
-     maximal context length used in the context rules.                    */
-
-  struct  TTO_ContextPosFormat2_
-  {
-    FT_UShort            MaxContextLength;
-                                        /* maximal context length       */
-    TTO_Coverage         Coverage;      /* Coverage table               */
-    TTO_ClassDefinition  ClassDef;      /* ClassDef table               */
-    FT_UShort            PosClassSetCount;
-                                        /* number of PosClassSet tables */
-    TTO_PosClassSet*     PosClassSet;   /* array of PosClassSet tables  */
-  };
-
-  typedef struct TTO_ContextPosFormat2_  TTO_ContextPosFormat2;
-
-
-  struct  TTO_ContextPosFormat3_
-  {
-    FT_UShort             GlyphCount;   /* number of input glyphs           */
-    FT_UShort             PosCount;     /* number of PosLookupRecord tables */
-    TTO_Coverage*         Coverage;     /* array of Coverage tables         */
-    TTO_PosLookupRecord*  PosLookupRecord;
-                                        /* array of PosLookupRecord tables  */
-  };
-
-  typedef struct TTO_ContextPosFormat3_  TTO_ContextPosFormat3;
-
-
-  struct  TTO_ContextPos_
-  {
-    FT_UShort  PosFormat;               /* 1, 2, or 3     */
-
-    union
-    {
-      TTO_ContextPosFormat1  cpf1;
-      TTO_ContextPosFormat2  cpf2;
-      TTO_ContextPosFormat3  cpf3;
-    } cpf;
-  };
-
-  typedef struct TTO_ContextPos_  TTO_ContextPos;
-
-
-  /* LookupType 8 */
-
-  struct  TTO_ChainPosRule_
-  {
-    FT_UShort             BacktrackGlyphCount;
-                                        /* total number of backtrack glyphs */
-    FT_UShort*            Backtrack;    /* array of backtrack glyph IDs     */
-    FT_UShort             InputGlyphCount;
-                                        /* total number of input glyphs     */
-    FT_UShort*            Input;        /* array of input glyph IDs         */
-    FT_UShort             LookaheadGlyphCount;
-                                        /* total number of lookahead glyphs */
-    FT_UShort*            Lookahead;    /* array of lookahead glyph IDs     */
-    FT_UShort             PosCount;     /* number of PosLookupRecords       */
-    TTO_PosLookupRecord*  PosLookupRecord;
-                                        /* array of PosLookupRecords       */
-  };
-
-  typedef struct TTO_ChainPosRule_  TTO_ChainPosRule;
-
-
-  struct  TTO_ChainPosRuleSet_
-  {
-    FT_UShort          ChainPosRuleCount;
-                                        /* number of ChainPosRule tables */
-    TTO_ChainPosRule*  ChainPosRule;    /* array of ChainPosRule tables  */
-  };
-
-  typedef struct TTO_ChainPosRuleSet_  TTO_ChainPosRuleSet;
-
-
-  struct  TTO_ChainContextPosFormat1_
-  {
-    TTO_Coverage          Coverage;     /* Coverage table                   */
-    FT_UShort             ChainPosRuleSetCount;
-                                        /* number of ChainPosRuleSet tables */
-    TTO_ChainPosRuleSet*  ChainPosRuleSet;
-                                        /* array of ChainPosRuleSet tables  */
-  };
-
-  typedef struct TTO_ChainContextPosFormat1_  TTO_ChainContextPosFormat1;
-
-
-  struct  TTO_ChainPosClassRule_
-  {
-    FT_UShort             BacktrackGlyphCount;
-                                        /* total number of backtrack
-                                           classes                         */
-    FT_UShort*            Backtrack;    /* array of backtrack classes      */
-    FT_UShort             InputGlyphCount;
-                                        /* total number of context classes */
-    FT_UShort*            Input;        /* array of context classes        */
-    FT_UShort             LookaheadGlyphCount;
-                                        /* total number of lookahead
-                                           classes                         */
-    FT_UShort*            Lookahead;    /* array of lookahead classes      */
-    FT_UShort             PosCount;     /* number of PosLookupRecords      */
-    TTO_PosLookupRecord*  PosLookupRecord;
-                                        /* array of substitution lookups   */
-  };
-
-  typedef struct TTO_ChainPosClassRule_  TTO_ChainPosClassRule;
-
-
-  struct  TTO_ChainPosClassSet_
-  {
-    FT_UShort               ChainPosClassRuleCount;
-                                        /* number of ChainPosClassRule
-                                           tables                      */
-    TTO_ChainPosClassRule*  ChainPosClassRule;
-                                        /* array of ChainPosClassRule
-                                           tables                      */
-  };
-
-  typedef struct TTO_ChainPosClassSet_  TTO_ChainPosClassSet;
-
-
-  /* The `MaxXXXLength' fields are not defined in the TTO specification
-     but simplifies the implementation of this format.  It holds the
-     maximal context length used in the specific context rules.         */
-
-  struct  TTO_ChainContextPosFormat2_
-  {
-    TTO_Coverage           Coverage;    /* Coverage table             */
-
-    FT_UShort              MaxBacktrackLength;
-                                        /* maximal backtrack length   */
-    TTO_ClassDefinition    BacktrackClassDef;
-                                        /* BacktrackClassDef table    */
-    FT_UShort              MaxInputLength;
-                                        /* maximal input length       */
-    TTO_ClassDefinition    InputClassDef;
-                                        /* InputClassDef table        */
-    FT_UShort              MaxLookaheadLength;
-                                        /* maximal lookahead length   */
-    TTO_ClassDefinition    LookaheadClassDef;
-                                        /* LookaheadClassDef table    */
-
-    FT_UShort              ChainPosClassSetCount;
-                                        /* number of ChainPosClassSet
-                                           tables                     */
-    TTO_ChainPosClassSet*  ChainPosClassSet;
-                                        /* array of ChainPosClassSet
-                                           tables                     */
-  };
-
-  typedef struct TTO_ChainContextPosFormat2_  TTO_ChainContextPosFormat2;
-
-
-  struct  TTO_ChainContextPosFormat3_
-  {
-    FT_UShort             BacktrackGlyphCount;
-                                        /* number of backtrack glyphs    */
-    TTO_Coverage*         BacktrackCoverage;
-                                        /* array of backtrack Coverage
-                                           tables                        */
-    FT_UShort             InputGlyphCount;
-                                        /* number of input glyphs        */
-    TTO_Coverage*         InputCoverage;
-                                        /* array of input coverage
-                                           tables                        */
-    FT_UShort             LookaheadGlyphCount;
-                                        /* number of lookahead glyphs    */
-    TTO_Coverage*         LookaheadCoverage;
-                                        /* array of lookahead coverage
-                                           tables                        */
-    FT_UShort             PosCount;     /* number of PosLookupRecords    */
-    TTO_PosLookupRecord*  PosLookupRecord;
-                                        /* array of substitution lookups */
-  };
-
-  typedef struct TTO_ChainContextPosFormat3_  TTO_ChainContextPosFormat3;
-
-
-  struct  TTO_ChainContextPos_
-  {
-    FT_UShort  PosFormat;             /* 1, 2, or 3 */
-
-    union
-    {
-      TTO_ChainContextPosFormat1  ccpf1;
-      TTO_ChainContextPosFormat2  ccpf2;
-      TTO_ChainContextPosFormat3  ccpf3;
-    } ccpf;
-  };
-
-  typedef struct TTO_ChainContextPos_  TTO_ChainContextPos;
-
-
-  union  TTO_GPOS_SubTable_
-  {
-    TTO_SinglePos        single;
-    TTO_PairPos          pair;
-    TTO_CursivePos       cursive;
-    TTO_MarkBasePos      markbase;
-    TTO_MarkLigPos       marklig;
-    TTO_MarkMarkPos      markmark;
-    TTO_ContextPos       context;
-    TTO_ChainContextPos  chain;
-  };
-
-  typedef union TTO_GPOS_SubTable_  TTO_GPOS_SubTable;
-
-
-  /* finally, the GPOS API */
-
-  /*  EXPORT_DEF
-      FT_Export ( FT_Error )  TT_Init_GPOS_Extension( TT_Engine  engine ); */
-
-  EXPORT_DEF
-  FT_Error  TT_Load_GPOS_Table( FT_Face          face,
-                                TTO_GPOSHeader** gpos,
-                                TTO_GDEFHeader*  gdef );
-
-  EXPORT_DEF
-  FT_Error  TT_Done_GPOS_Table( TTO_GPOSHeader* gpos );
-
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Select_Script( TTO_GPOSHeader*  gpos,
-                                   FT_ULong         script_tag,
-                                   FT_UShort*       script_index );
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Select_Language( TTO_GPOSHeader*  gpos,
-                                     FT_ULong         language_tag,
-                                     FT_UShort        script_index,
-                                     FT_UShort*       language_index,
-                                     FT_UShort*       req_feature_index );
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Select_Feature( TTO_GPOSHeader*  gpos,
-                                    FT_ULong         feature_tag,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_UShort*       feature_index );
-
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Query_Scripts( TTO_GPOSHeader*  gpos,
-                                   FT_ULong**       script_tag_list );
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Query_Languages( TTO_GPOSHeader*  gpos,
-                                     FT_UShort        script_index,
-                                     FT_ULong**       language_tag_list );
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Query_Features( TTO_GPOSHeader*  gpos,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_ULong**       feature_tag_list );
-
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Add_Feature( TTO_GPOSHeader*  gpos,
-                                 FT_UShort        feature_index,
-                                 FT_UInt          property );
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Clear_Features( TTO_GPOSHeader*  gpos );
-
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Register_Glyph_Function( TTO_GPOSHeader*    gpos,
-                                             TTO_GlyphFunction  gfunc );
-
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Register_MM_Function( TTO_GPOSHeader*  gpos,
-                                          TTO_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.         */
-
-  EXPORT_DEF
-  FT_Error  TT_GPOS_Apply_String( FT_Face           face,
-                                  TTO_GPOSHeader*   gpos,
-                                  FT_UShort         load_flags,
-				  OTL_Buffer        buffer,
-                                  FT_Bool           dvi,
-                                  FT_Bool           r2l );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FTXGPOS_H */
-
-
-/* END */
diff --git a/src/ftxgsub.c b/src/ftxgsub.c
deleted file mode 100644
index ce30697..0000000
--- a/src/ftxgsub.c
+++ /dev/null
@@ -1,4533 +0,0 @@
-/*******************************************************************
- *
- *  ftxgsub.c
- *
- *    TrueType Open GSUB table support.
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#include <config.h>
-
-/* XXX There is *a lot* of duplicated code (cf. formats 5 and 6), but
-       I don't care currently.  I believe that it would be possible to
-       save about 50% of TTO code by carefully designing the structures,
-       sharing as much as possible with extensive use of macros.  This
-       is something for a volunteer :-)                                  */
-
-#define EXPORT_FUNC
-
-#include "ftxopen.h"
-#include "ftxopenf.h"
-
-#include "ftglue.h"
-
-#include FT_TRUETYPE_TAGS_H
-
-#define GSUB_ID  Build_Extension_ID( 'G', 'S', 'U', 'B' )
-
-
-#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 OUT_GLYPH( pos )     buffer->out_string[(pos)].gindex
-#define OUT_ITEM( pos )      (&buffer->out_string[(pos)])
-
-#define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID )             \
-          ( ( error = otl_buffer_add_output_glyphs( (buffer),                           \
-						    (num_in), (num_out),                \
-                                                    (glyph_data), (component), (ligID)  \
-                                                  ) ) != TT_Err_Ok )
-#define ADD_Glyph( buffer, glyph_index, component, ligID )             		 	 \
-          ( ( error = otl_buffer_add_output_glyph( (buffer),                             \
-                                                    (glyph_index), (component), (ligID)  \
-                                                  ) ) != TT_Err_Ok )
-
-
-  static FT_Error  Do_Glyph_Lookup( TTO_GSUBHeader*   gsub,
-                                    FT_UShort         lookup_index,
-				    OTL_Buffer        buffer,
-                                    FT_UShort         context_length,
-                                    int               nesting_level );
-
-
-
-  /**********************
-   * Auxiliary functions
-   **********************/
-
-
-  EXPORT_FUNC
-  FT_Error  TT_Load_GSUB_Table( FT_Face          face,
-                                TTO_GSUBHeader** retptr,
-                                TTO_GDEFHeader*  gdef )
-  {
-    FT_Stream        stream = face->stream;
-    FT_Memory        memory = face->memory;
-    FT_Error         error;
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    FT_UShort        i, num_lookups;
-    TTO_GSUBHeader*  gsub;
-    TTO_Lookup*      lo;
-
-    if ( !retptr )
-      return TT_Err_Invalid_Argument;
-
-    if (( error = ftglue_face_goto_table( face, TTAG_GSUB, stream ) ))
-      return error;
-
-    base_offset = FILE_Pos();
-
-    if ( ALLOC ( gsub, sizeof( *gsub ) ) )
-      return error;
-
-    gsub->memory = memory;
-
-    /* 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 = Load_ScriptList( &gsub->ScriptList,
-                                    stream ) ) != TT_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 = Load_FeatureList( &gsub->FeatureList,
-                                     stream ) ) != TT_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 = Load_LookupList( &gsub->LookupList,
-                                    stream, GSUB ) ) != TT_Err_Ok )
-      goto Fail2;
-
-    gsub->gdef = gdef;      /* can be NULL */
-
-    /* We now check the LookupFlags for values larger than 0xFF to find
-       out whether we need to load the `MarkAttachClassDef' field of the
-       GDEF table -- this hack is necessary for OpenType 1.2 tables since
-       the version field of the GDEF table hasn't been incremented.
-
-       For constructed GDEF tables, we only load it if
-       `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
-       a constructed mark attach table is not supported currently).       */
-
-    if ( gdef &&
-         gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
-    {
-      lo          = gsub->LookupList.Lookup;
-      num_lookups = gsub->LookupList.LookupCount;
-
-      for ( i = 0; i < num_lookups; i++ )
-      {
-
-        if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
-        {
-          if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
-               ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
-                                               256, stream ) ) != TT_Err_Ok )
-            goto Fail1;
-
-          break;
-        }
-      }
-    }
-
-    *retptr = gsub;
-
-    return TT_Err_Ok;
-
-  Fail1:
-    Free_LookupList( &gsub->LookupList, GSUB, memory );
-
-  Fail2:
-    Free_FeatureList( &gsub->FeatureList, memory );
-
-  Fail3:
-    Free_ScriptList( &gsub->ScriptList, memory );
-
-  Fail4:
-    FREE ( gsub );
-
-
-    return error;
-  }
-
-  EXPORT_FUNC
-  FT_Error   TT_Done_GSUB_Table( TTO_GSUBHeader* gsub )
-  {
-    FT_Memory memory = gsub->memory;
-    
-    Free_LookupList( &gsub->LookupList, GSUB, memory );
-    Free_FeatureList( &gsub->FeatureList, memory );
-    Free_ScriptList( &gsub->ScriptList, memory );
-
-    FREE( gsub );
-
-    return TT_Err_Ok;
-  }
-
-  /*****************************
-   * SubTable related functions
-   *****************************/
-
-  static FT_Error  Lookup_DefaultSubst( TTO_GSUBHeader*    gsub,
-					TTO_GSUB_SubTable* st,
-					OTL_Buffer         buffer,
-					FT_UShort          flags,
-					FT_UShort          context_length,
-					int                nesting_level )
-  {
-    return TTO_Err_Not_Covered;
-  }
-
-
-  /* LookupType 1 */
-
-  /* SingleSubstFormat1 */
-  /* SingleSubstFormat2 */
-
-  FT_Error  Load_SingleSubst( TTO_SingleSubst*  ss,
-                              FT_Stream         stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort n, count;
-    FT_ULong cur_offset, new_offset, base_offset;
-
-    FT_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 = Load_Coverage( &ss->Coverage, stream ) ) != TT_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, FT_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 TTO_Err_Invalid_GSUB_SubTable_Format;
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    FREE( s );
-
-  Fail2:
-    Free_Coverage( &ss->Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_SingleSubst( TTO_SingleSubst*  ss,
-			  FT_Memory         memory )
-  {
-    switch ( ss->SubstFormat )
-    {
-    case 1:
-      break;
-
-    case 2:
-      FREE( ss->ssf.ssf2.Substitute );
-      break;
-    }
-
-    Free_Coverage( &ss->Coverage, memory );
-  }
-
-
-  static FT_Error  Lookup_SingleSubst( TTO_GSUBHeader*   gsub,
-				       TTO_GSUB_SubTable* st,
-				       OTL_Buffer        buffer,
-                                       FT_UShort         flags,
-                                       FT_UShort         context_length,
-				       int               nesting_level )
-  {
-    FT_UShort index, value, property;
-    FT_Error  error;
-    TTO_SingleSubst*  ss = &st->single;
-    TTO_GDEFHeader*   gdef = gsub->gdef;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-      return TTO_Err_Not_Covered;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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 ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) )
-        return error;
-      break;
-
-    case 2:
-      if ( index >= ss->ssf.ssf2.GlyphCount )
-        return TTO_Err_Invalid_GSUB_SubTable;
-      value = ss->ssf.ssf2.Substitute[index];
-      if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) )
-        return error;
-      break;
-
-    default:
-      return TTO_Err_Invalid_GSUB_SubTable;
-    }
-
-    if ( gdef && gdef->NewGlyphClasses )
-    {
-      /* we inherit the old glyph class to the substituted glyph */
-
-      error = Add_Glyph_Property( gdef, value, property );
-      if ( error && error != TTO_Err_Not_Covered )
-        return error;
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  /* LookupType 2 */
-
-  /* Sequence */
-
-  static FT_Error  Load_Sequence( TTO_Sequence*  s,
-                                  FT_Stream      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort n, count;
-    FT_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, FT_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 TT_Err_Ok;
-  }
-
-
-  static void  Free_Sequence( TTO_Sequence*  s,
-			      FT_Memory      memory )
-  {
-    FREE( s->Substitute );
-  }
-
-
-  /* MultipleSubstFormat1 */
-
-  FT_Error  Load_MultipleSubst( TTO_MultipleSubst*  ms,
-                                FT_Stream           stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort      n = 0, m, count;
-    FT_ULong       cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &ms->Coverage, stream ) ) != TT_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_Sequence( &s[m], memory );
-
-    FREE( s );
-
-  Fail2:
-    Free_Coverage( &ms->Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_MultipleSubst( TTO_MultipleSubst*  ms,
-			    FT_Memory           memory )
-  {
-    FT_UShort      n, count;
-
-    TTO_Sequence*  s;
-
-
-    if ( ms->Sequence )
-    {
-      count = ms->SequenceCount;
-      s     = ms->Sequence;
-
-      for ( n = 0; n < count; n++ )
-        Free_Sequence( &s[n], memory );
-
-      FREE( s );
-    }
-
-    Free_Coverage( &ms->Coverage, memory );
-  }
-
-
-  static FT_Error  Lookup_MultipleSubst( TTO_GSUBHeader*    gsub,
-					 TTO_GSUB_SubTable* st,
-					 OTL_Buffer         buffer,
-                                         FT_UShort          flags,
-                                         FT_UShort          context_length,
-					 int                nesting_level )
-  {
-    FT_Error  error;
-    FT_UShort index, property, n, count;
-    FT_UShort*s;
-    TTO_MultipleSubst*  ms = &st->multiple;
-    TTO_GDEFHeader*     gdef = gsub->gdef;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-      return TTO_Err_Not_Covered;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-      return error;
-
-    if ( index >= ms->SequenceCount )
-      return TTO_Err_Invalid_GSUB_SubTable;
-
-    count = ms->Sequence[index].GlyphCount;
-    s     = ms->Sequence[index].Substitute;
-
-    if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
-      return error;
-
-    if ( gdef && gdef->NewGlyphClasses )
-    {
-      /* this is a guess only ... */
-
-      if ( property == TTO_LIGATURE )
-        property = TTO_BASE_GLYPH;
-
-      for ( n = 0; n < count; n++ )
-      {
-        error = Add_Glyph_Property( gdef, s[n], property );
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-      }
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  /* LookupType 3 */
-
-  /* AlternateSet */
-
-  static FT_Error  Load_AlternateSet( TTO_AlternateSet*  as,
-                                      FT_Stream          stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort n, count;
-    FT_UShort*  a;
-
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    count = as->GlyphCount = GET_UShort();
-
-    FORGET_Frame();
-
-    as->Alternate = NULL;
-
-    if ( ALLOC_ARRAY( as->Alternate, count, FT_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 TT_Err_Ok;
-  }
-
-
-  static void  Free_AlternateSet( TTO_AlternateSet*  as,
-				  FT_Memory          memory )
-  {
-    FREE( as->Alternate );
-  }
-
-
-  /* AlternateSubstFormat1 */
-
-  FT_Error  Load_AlternateSubst( TTO_AlternateSubst*  as,
-                                 FT_Stream            stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort          n = 0, m, count;
-    FT_ULong           cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &as->Coverage, stream ) ) != TT_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_AlternateSet( &aset[m], memory );
-
-    FREE( aset );
-
-  Fail2:
-    Free_Coverage( &as->Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_AlternateSubst( TTO_AlternateSubst*  as,
-			     FT_Memory            memory )
-  {
-    FT_UShort          n, count;
-
-    TTO_AlternateSet*  aset;
-
-
-    if ( as->AlternateSet )
-    {
-      count = as->AlternateSetCount;
-      aset  = as->AlternateSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_AlternateSet( &aset[n], memory );
-
-      FREE( aset );
-    }
-
-    Free_Coverage( &as->Coverage, memory );
-  }
-
-
-  static FT_Error  Lookup_AlternateSubst( TTO_GSUBHeader*    gsub,
-					  TTO_GSUB_SubTable* st,
-					  OTL_Buffer         buffer,
-                                          FT_UShort          flags,
-                                          FT_UShort          context_length,
-					  int                nesting_level )
-  {
-    FT_Error          error;
-    FT_UShort         index, alt_index, property;
-    TTO_AlternateSubst*  as = &st->alternate;
-    TTO_GDEFHeader*     gdef = gsub->gdef;
-
-
-    TTO_AlternateSet  aset;
-
-
-    if ( context_length != 0xFFFF && context_length < 1 )
-      return TTO_Err_Not_Covered;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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;
-
-    if ( ADD_Glyph( buffer, aset.Alternate[alt_index],
-		    0xFFFF, 0xFFFF ) )
-      return error;
-
-    if ( gdef && gdef->NewGlyphClasses )
-    {
-      /* we inherit the old glyph class to the substituted glyph */
-
-      error = Add_Glyph_Property( gdef, aset.Alternate[alt_index],
-                                  property );
-      if ( error && error != TTO_Err_Not_Covered )
-        return error;
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  /* LookupType 4 */
-
-  /* Ligature */
-
-  static FT_Error  Load_Ligature( TTO_Ligature*  l,
-                                  FT_Stream      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort n, count;
-    FT_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, FT_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 TT_Err_Ok;
-  }
-
-
-  static void  Free_Ligature( TTO_Ligature*  l,
-			      FT_Memory      memory )
-  {
-    FREE( l->Component );
-  }
-
-
-  /* LigatureSet */
-
-  static FT_Error  Load_LigatureSet( TTO_LigatureSet*  ls,
-                                     FT_Stream         stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort      n = 0, m, count;
-    FT_ULong       cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_Ligature( &l[m], memory );
-
-    FREE( l );
-    return error;
-  }
-
-
-  static void  Free_LigatureSet( TTO_LigatureSet*  ls,
-				 FT_Memory         memory )
-  {
-    FT_UShort      n, count;
-
-    TTO_Ligature*  l;
-
-
-    if ( ls->Ligature )
-    {
-      count = ls->LigatureCount;
-      l     = ls->Ligature;
-
-      for ( n = 0; n < count; n++ )
-        Free_Ligature( &l[n], memory );
-
-      FREE( l );
-    }
-  }
-
-
-  /* LigatureSubstFormat1 */
-
-  FT_Error  Load_LigatureSubst( TTO_LigatureSubst*  ls,
-                                FT_Stream           stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort         n = 0, m, count;
-    FT_ULong          cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &ls->Coverage, stream ) ) != TT_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_LigatureSet( &lset[m], memory );
-
-    FREE( lset );
-
-  Fail2:
-    Free_Coverage( &ls->Coverage, memory );
-    return error;
-  }
-
-
-  void  Free_LigatureSubst( TTO_LigatureSubst*  ls,
-			    FT_Memory           memory )
-  {
-    FT_UShort         n, count;
-
-    TTO_LigatureSet*  lset;
-
-
-    if ( ls->LigatureSet )
-    {
-      count = ls->LigatureSetCount;
-      lset  = ls->LigatureSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_LigatureSet( &lset[n], memory );
-
-      FREE( lset );
-    }
-
-    Free_Coverage( &ls->Coverage, memory );
-  }
-
-
-  static FT_Error  Lookup_LigatureSubst( TTO_GSUBHeader*    gsub,
-					 TTO_GSUB_SubTable* st,
-					 OTL_Buffer         buffer,
-                                         FT_UShort          flags,
-                                         FT_UShort          context_length,
-					 int                nesting_level )
-  {
-    FT_UShort      index, property;
-    FT_Error       error;
-    FT_UShort      numlig, i, j, is_mark, first_is_mark = FALSE;
-    FT_UShort*     c;
-    TTO_LigatureSubst*  ls = &st->ligature;
-    TTO_GDEFHeader*     gdef = gsub->gdef;
-
-    TTO_Ligature*  lig;
-
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    if ( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS )
-      first_is_mark = TRUE;
-
-    error = Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-      return error;
-
-    if ( index >= ls->LigatureSetCount )
-       return TTO_Err_Invalid_GSUB_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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-          if ( j + lig->ComponentCount - i == buffer->in_length )
-	    goto next_ligature;
-	  j++;
-        }
-
-        if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) )
-          is_mark = FALSE;
-
-        if ( IN_GLYPH( j ) != c[i - 1] )
-	  goto next_ligature;
-      }
-
-      if ( gdef && gdef->NewGlyphClasses )
-      {
-	/* this is just a guess ... */
-
-	error = Add_Glyph_Property( gdef, lig->LigGlyph,
-				    is_mark ? TTO_MARK : TTO_LIGATURE );
-	if ( error && error != TTO_Err_Not_Covered )
-	  return error;
-      }
-
-      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
-	{
-	  FT_UShort ligID = otl_buffer_allocate_ligid( buffer );
-	  if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
-			  0xFFFF, ligID ) )
-	    return error;
-	}
-      }
-      else
-      {
-	FT_UShort ligID = otl_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++ )
-	{
-	  while ( CHECK_Property( gdef, IN_CURITEM(),
-				  flags, &property ) )
-	    if ( ADD_Glyph( buffer, IN_CURGLYPH(),
-			    i, ligID ) )
-	      return error;
-
-	  (buffer->in_pos)++;
-	}
-      }
-
-      return TT_Err_Ok;
-
-    next_ligature:
-      ;
-    }
-
-    return TTO_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 FT_Error  Do_ContextSubst( TTO_GSUBHeader*        gsub,
-                                    FT_UShort              GlyphCount,
-                                    FT_UShort              SubstCount,
-                                    TTO_SubstLookupRecord* subst,
-				    OTL_Buffer             buffer,
-                                    int                    nesting_level )
-  {
-    FT_Error  error;
-    FT_UShort i, old_pos;
-
-
-    i = 0;
-
-    while ( i < GlyphCount )
-    {
-      if ( SubstCount && i == subst->SequenceIndex )
-      {
-        old_pos = buffer->in_pos;
-
-        /* Do a substitution */
-
-        error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer,
-                                 GlyphCount, nesting_level );
-
-        subst++;
-        SubstCount--;
-        i += buffer->in_pos - old_pos;
-
-        if ( error == TTO_Err_Not_Covered )
-        {
-          /* XXX "can't happen" -- but don't count on it */
-
-          if ( ADD_Glyph( buffer, IN_CURGLYPH(),
-			  0xFFFF, 0xFFFF ) )
-            return error;
-          i++;
-        }
-        else if ( error )
-          return error;
-      }
-      else
-      {
-        /* No substitution for this index */
-
-        if ( ADD_Glyph( buffer, IN_CURGLYPH(),
-			0xFFFF, 0xFFFF ) )
-          return error;
-        i++;
-      }
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  /* LookupType 5 */
-
-  /* SubRule */
-
-  static FT_Error  Load_SubRule( TTO_SubRule*  sr,
-                                 FT_Stream     stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n, count;
-    FT_UShort*              i;
-
-    TTO_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, FT_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, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( slr );
-
-  Fail2:
-    FREE( i );
-    return error;
-  }
-
-
-  static void  Free_SubRule( TTO_SubRule*  sr,
-			     FT_Memory     memory )
-  {
-    FREE( sr->SubstLookupRecord );
-    FREE( sr->Input );
-  }
-
-
-  /* SubRuleSet */
-
-  static FT_Error  Load_SubRuleSet( TTO_SubRuleSet*  srs,
-                                    FT_Stream        stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort     n = 0, m, count;
-    FT_ULong      cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_SubRule( &sr[m], memory );
-
-    FREE( sr );
-    return error;
-  }
-
-
-  static void  Free_SubRuleSet( TTO_SubRuleSet*  srs,
-				FT_Memory        memory )
-  {
-    FT_UShort     n, count;
-
-    TTO_SubRule*  sr;
-
-
-    if ( srs->SubRule )
-    {
-      count = srs->SubRuleCount;
-      sr    = srs->SubRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_SubRule( &sr[n], memory );
-
-      FREE( sr );
-    }
-  }
-
-
-  /* ContextSubstFormat1 */
-
-  static FT_Error  Load_ContextSubst1( TTO_ContextSubstFormat1*  csf1,
-                                       FT_Stream                 stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort        n = 0, m, count;
-    FT_ULong         cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &csf1->Coverage, stream ) ) != TT_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_SubRuleSet( &srs[m], memory );
-
-    FREE( srs );
-
-  Fail2:
-    Free_Coverage( &csf1->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_Context1( TTO_ContextSubstFormat1* csf1,
-			      FT_Memory                memory )
-  {
-    FT_UShort        n, count;
-
-    TTO_SubRuleSet*  srs;
-
-
-    if ( csf1->SubRuleSet )
-    {
-      count = csf1->SubRuleSetCount;
-      srs   = csf1->SubRuleSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_SubRuleSet( &srs[n], memory );
-
-      FREE( srs );
-    }
-
-    Free_Coverage( &csf1->Coverage, memory );
-  }
-
-
-  /* SubClassRule */
-
-  static FT_Error  Load_SubClassRule( TTO_ContextSubstFormat2*  csf2,
-                                      TTO_SubClassRule*         scr,
-                                      FT_Stream                 stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n, count;
-
-    FT_UShort*              c;
-    TTO_SubstLookupRecord*  slr;
-    FT_Bool*                d;
-
-
-    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, FT_UShort ) )
-      return error;
-
-    c = scr->Class;
-    d = csf2->ClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail2;
-
-    for ( n = 0; n < count; n++ )
-    {
-      c[n] = GET_UShort();
-
-      /* We check whether the specific class is used at all.  If not,
-         class 0 is used instead.                                     */
-      if ( !d[c[n]] )
-        c[n] = 0;
-    }
-
-    FORGET_Frame();
-
-    scr->SubstLookupRecord = NULL;
-
-    count = scr->SubstCount;
-
-    if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( slr );
-
-  Fail2:
-    FREE( c );
-    return error;
-  }
-
-
-  static void  Free_SubClassRule( TTO_SubClassRule*  scr,
-				  FT_Memory          memory )
-  {
-    FREE( scr->SubstLookupRecord );
-    FREE( scr->Class );
-  }
-
-
-  /* SubClassSet */
-
-  static FT_Error  Load_SubClassSet( TTO_ContextSubstFormat2*  csf2,
-                                     TTO_SubClassSet*          scs,
-                                     FT_Stream                 stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort          n = 0, m, count;
-    FT_ULong           cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_SubClassRule( &scr[m], memory );
-
-    FREE( scr );
-    return error;
-  }
-
-
-  static void  Free_SubClassSet( TTO_SubClassSet*  scs,
-				 FT_Memory         memory )
-  {
-    FT_UShort          n, count;
-
-    TTO_SubClassRule*  scr;
-
-
-    if ( scs->SubClassRule )
-    {
-      count = scs->SubClassRuleCount;
-      scr   = scs->SubClassRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_SubClassRule( &scr[n], memory );
-
-      FREE( scr );
-    }
-  }
-
-
-  /* ContextSubstFormat2 */
-
-  static FT_Error  Load_ContextSubst2( TTO_ContextSubstFormat2*  csf2,
-                                       FT_Stream                 stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort         n = 0, m, count;
-    FT_ULong          cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &csf2->Coverage, stream ) ) != TT_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 = Load_ClassDefinition( &csf2->ClassDef, count,
-                                         stream ) ) != TT_Err_Ok )
-      goto Fail3;
-    (void)FILE_Seek( cur_offset );
-
-    csf2->SubClassSet      = NULL;
-    csf2->MaxContextLength = 0;
-
-    if ( ALLOC_ARRAY( csf2->SubClassSet, count, TTO_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 ) ) != TT_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 TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_SubClassSet( &scs[m], memory );
-
-    FREE( scs );
-
-  Fail2:
-    Free_ClassDefinition( &csf2->ClassDef, memory );
-
-  Fail3:
-    Free_Coverage( &csf2->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_Context2( TTO_ContextSubstFormat2*  csf2,
-			      FT_Memory                 memory )
-  {
-    FT_UShort         n, count;
-
-    TTO_SubClassSet*  scs;
-
-
-    if ( csf2->SubClassSet )
-    {
-      count = csf2->SubClassSetCount;
-      scs   = csf2->SubClassSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_SubClassSet( &scs[n], memory );
-
-      FREE( scs );
-    }
-
-    Free_ClassDefinition( &csf2->ClassDef, memory );
-    Free_Coverage( &csf2->Coverage, memory );
-  }
-
-
-  /* ContextSubstFormat3 */
-
-  static FT_Error  Load_ContextSubst3( TTO_ContextSubstFormat3*  csf3,
-                                       FT_Stream                 stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n = 0, m, count;
-    FT_ULong                cur_offset, new_offset, base_offset;
-
-    TTO_Coverage*           c;
-    TTO_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, TTO_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 = Load_Coverage( &c[n], stream ) ) != TT_Err_Ok )
-        goto Fail2;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    csf3->SubstLookupRecord = NULL;
-
-    count = csf3->SubstCount;
-
-    if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
-                      TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( slr );
-
-  Fail2:
-    for ( m = 0; m < n; m++ )
-      Free_Coverage( &c[m], memory );
-
-    FREE( c );
-    return error;
-  }
-
-
-  static void  Free_Context3( TTO_ContextSubstFormat3*  csf3,
-			      FT_Memory                 memory )
-  {
-    FT_UShort      n, count;
-
-    TTO_Coverage*  c;
-
-
-    FREE( csf3->SubstLookupRecord );
-
-    if ( csf3->Coverage )
-    {
-      count = csf3->GlyphCount;
-      c     = csf3->Coverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-  }
-
-
-  /* ContextSubst */
-
-  FT_Error  Load_ContextSubst( TTO_ContextSubst*  cs,
-                               FT_Stream          stream )
-  {
-    FT_Error error;
-
-
-    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 TTO_Err_Invalid_GSUB_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  void  Free_ContextSubst( TTO_ContextSubst*  cs,
-			   FT_Memory          memory )
-  {
-    switch ( cs->SubstFormat )
-    {
-    case 1:
-      Free_Context1( &cs->csf.csf1, memory );
-      break;
-
-    case 2:
-      Free_Context2( &cs->csf.csf2, memory );
-      break;
-
-    case 3:
-      Free_Context3( &cs->csf.csf3, memory );
-      break;
-    }
-  }
-
-
-  static FT_Error  Lookup_ContextSubst1( TTO_GSUBHeader*          gsub,
-					 TTO_ContextSubstFormat1* csf1,
-					 OTL_Buffer               buffer,
-					 FT_UShort                flags,
-					 FT_UShort                context_length,
-					 int                      nesting_level )
-  {
-    FT_UShort        index, property;
-    FT_UShort        i, j, k, numsr;
-    FT_Error         error;
-
-    TTO_SubRule*     sr;
-    TTO_GDEFHeader*  gdef;
-
-
-    gdef = gsub->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-          if ( j + sr[k].GlyphCount - i == 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 TTO_Err_Not_Covered;
-  }
-
-
-  static FT_Error  Lookup_ContextSubst2( TTO_GSUBHeader*          gsub,
-					 TTO_ContextSubstFormat2* csf2,
-					 OTL_Buffer               buffer,
-					 FT_UShort                flags,
-					 FT_UShort                context_length,
-					 int                      nesting_level )
-  {
-    FT_UShort          index, property;
-    FT_Error           error;
-    FT_Memory          memory = gsub->memory;
-    FT_UShort          i, j, k, known_classes;
-
-    FT_UShort*         classes;
-    FT_UShort*         cl;
-
-    TTO_SubClassSet*   scs;
-    TTO_SubClassRule*  sr;
-    TTO_GDEFHeader*    gdef;
-
-
-    gdef = gsub->gdef;
-
-    if ( CHECK_Property( gdef, 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 = Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-      return error;
-
-    if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, FT_UShort ) )
-      return error;
-
-    error = Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
-                       &classes[0], NULL );
-    if ( error && error != TTO_Err_Not_Covered )
-      goto End;
-    known_classes = 0;
-
-    scs = &csf2->SubClassSet[classes[0]];
-    if ( !scs )
-    {
-      error = TTO_Err_Invalid_GSUB_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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            goto End;
-
-          if ( j + sr->GlyphCount - i < buffer->in_length )
-	    goto next_subclassrule;
-	  j++;
-        }
-
-        if ( i > known_classes )
-        {
-          /* Keeps us from having to do this for each rule */
-
-          error = Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
-          if ( error && error != TTO_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 = TTO_Err_Not_Covered;
-
-  End:
-    FREE( classes );
-    return error;
-  }
-
-
-  static FT_Error  Lookup_ContextSubst3( TTO_GSUBHeader*          gsub,
-					 TTO_ContextSubstFormat3* csf3,
-					 OTL_Buffer               buffer,
-					 FT_UShort                flags,
-					 FT_UShort                context_length,
-					 int                      nesting_level )
-  {
-    FT_Error         error;
-    FT_UShort        index, i, j, property;
-
-    TTO_Coverage*    c;
-    TTO_GDEFHeader*  gdef;
-
-
-    gdef = gsub->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
-      return TTO_Err_Not_Covered;
-
-    if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
-      return TTO_Err_Not_Covered;         /* context is too long */
-
-    c    = csf3->Coverage;
-
-    for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
-    {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-      {
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-
-	if ( j + csf3->GlyphCount - i == buffer->in_length )
-          return TTO_Err_Not_Covered;
-	j++;
-      }
-
-      error = 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 FT_Error  Lookup_ContextSubst( TTO_GSUBHeader*    gsub,
-					TTO_GSUB_SubTable* st,
-					OTL_Buffer         buffer,
-                                        FT_UShort          flags,
-                                        FT_UShort          context_length,
-                                        int                nesting_level )
-  {
-    TTO_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 TTO_Err_Invalid_GSUB_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  /* LookupType 6 */
-
-  /* ChainSubRule */
-
-  static FT_Error  Load_ChainSubRule( TTO_ChainSubRule*  csr,
-                                      FT_Stream          stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n, count;
-    FT_UShort*              b;
-    FT_UShort*              i;
-    FT_UShort*              l;
-
-    TTO_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, FT_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, FT_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, FT_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, TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( slr );
-
-  Fail2:
-    FREE( l );
-
-  Fail3:
-    FREE( i );
-
-  Fail4:
-    FREE( b );
-    return error;
-  }
-
-
-  static void  Free_ChainSubRule( TTO_ChainSubRule*  csr,
-				  FT_Memory          memory )
-  {
-    FREE( csr->SubstLookupRecord );
-    FREE( csr->Lookahead );
-    FREE( csr->Input );
-    FREE( csr->Backtrack );
-  }
-
-
-  /* ChainSubRuleSet */
-
-  static FT_Error  Load_ChainSubRuleSet( TTO_ChainSubRuleSet*  csrs,
-                                         FT_Stream             stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort          n = 0, m, count;
-    FT_ULong           cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_ChainSubRule( &csr[m], memory );
-
-    FREE( csr );
-    return error;
-  }
-
-
-  static void  Free_ChainSubRuleSet( TTO_ChainSubRuleSet*  csrs,
-				     FT_Memory             memory )
-  {
-    FT_UShort          n, count;
-
-    TTO_ChainSubRule*  csr;
-
-
-    if ( csrs->ChainSubRule )
-    {
-      count = csrs->ChainSubRuleCount;
-      csr   = csrs->ChainSubRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainSubRule( &csr[n], memory );
-
-      FREE( csr );
-    }
-  }
-
-
-  /* ChainContextSubstFormat1 */
-
-  static FT_Error  Load_ChainContextSubst1(
-                     TTO_ChainContextSubstFormat1*  ccsf1,
-                     FT_Stream                      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort             n = 0, m, count;
-    FT_ULong              cur_offset, new_offset, base_offset;
-
-    TTO_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 = Load_Coverage( &ccsf1->Coverage, stream ) ) != TT_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, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_ChainSubRuleSet( &csrs[m], memory );
-
-    FREE( csrs );
-
-  Fail2:
-    Free_Coverage( &ccsf1->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_ChainContext1( TTO_ChainContextSubstFormat1*  ccsf1,
-				   FT_Memory                      memory )
-  {
-    FT_UShort             n, count;
-
-    TTO_ChainSubRuleSet*  csrs;
-
-
-    if ( ccsf1->ChainSubRuleSet )
-    {
-      count = ccsf1->ChainSubRuleSetCount;
-      csrs  = ccsf1->ChainSubRuleSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainSubRuleSet( &csrs[n], memory );
-
-      FREE( csrs );
-    }
-
-    Free_Coverage( &ccsf1->Coverage, memory );
-  }
-
-
-  /* ChainSubClassRule */
-
-  static FT_Error  Load_ChainSubClassRule(
-                     TTO_ChainContextSubstFormat2*  ccsf2,
-                     TTO_ChainSubClassRule*         cscr,
-                     FT_Stream                      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n, count;
-
-    FT_UShort*              b;
-    FT_UShort*              i;
-    FT_UShort*              l;
-    TTO_SubstLookupRecord*  slr;
-    FT_Bool*                d;
-
-
-    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, FT_UShort ) )
-      return error;
-
-    b = cscr->Backtrack;
-    d = ccsf2->BacktrackClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail4;
-
-    for ( n = 0; n < count; n++ )
-    {
-      b[n] = GET_UShort();
-
-      /* We check whether the specific class is used at all.  If not,
-         class 0 is used instead.                                     */
-
-      if ( !d[b[n]] )
-        b[n] = 0;
-    }
-
-    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, FT_UShort ) )
-      goto Fail4;
-
-    i = cscr->Input;
-    d = ccsf2->InputClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail3;
-
-    for ( n = 0; n < count; n++ )
-    {
-      i[n] = GET_UShort();
-
-      if ( !d[i[n]] )
-        i[n] = 0;
-    }
-
-    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, FT_UShort ) )
-      goto Fail3;
-
-    l = cscr->Lookahead;
-    d = ccsf2->LookaheadClassDef.Defined;
-
-    if ( ACCESS_Frame( count * 2L ) )
-      goto Fail2;
-
-    for ( n = 0; n < count; n++ )
-    {
-      l[n] = GET_UShort();
-
-      if ( !d[l[n]] )
-        l[n] = 0;
-    }
-
-    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,
-                      TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( slr );
-
-  Fail2:
-    FREE( l );
-
-  Fail3:
-    FREE( i );
-
-  Fail4:
-    FREE( b );
-    return error;
-  }
-
-
-  static void  Free_ChainSubClassRule( TTO_ChainSubClassRule*  cscr,
-				       FT_Memory               memory )
-  {
-    FREE( cscr->SubstLookupRecord );
-    FREE( cscr->Lookahead );
-    FREE( cscr->Input );
-    FREE( cscr->Backtrack );
-  }
-
-
-  /* SubClassSet */
-
-  static FT_Error  Load_ChainSubClassSet(
-                     TTO_ChainContextSubstFormat2*  ccsf2,
-                     TTO_ChainSubClassSet*          cscs,
-                     FT_Stream                      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n = 0, m, count;
-    FT_ULong                cur_offset, new_offset, base_offset;
-
-    TTO_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,
-                      TTO_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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_ChainSubClassRule( &cscr[m], memory );
-
-    FREE( cscr );
-    return error;
-  }
-
-
-  static void  Free_ChainSubClassSet( TTO_ChainSubClassSet*  cscs,
-				      FT_Memory              memory )
-  {
-    FT_UShort               n, count;
-
-    TTO_ChainSubClassRule*  cscr;
-
-
-    if ( cscs->ChainSubClassRule )
-    {
-      count = cscs->ChainSubClassRuleCount;
-      cscr  = cscs->ChainSubClassRule;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainSubClassRule( &cscr[n], memory );
-
-      FREE( cscr );
-    }
-  }
-
-  static FT_Error Load_EmptyOrClassDefinition( TTO_ClassDefinition*  cd,
-                                               FT_UShort             limit,
-					       FT_ULong              class_offset,
-					       FT_ULong              base_offset,
-				               FT_Stream             stream )
-  {
-    FT_Error error;
-    FT_ULong               cur_offset;
-
-    cur_offset = FILE_Pos();
-
-    if ( class_offset )
-      {
-        if ( !FILE_Seek( class_offset + base_offset ) )
-          error = Load_ClassDefinition( cd, limit, stream );
-      }
-    else
-       error = Load_EmptyClassDefinition ( cd, stream );
-
-    if (error == TT_Err_Ok)
-      (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
-
-    return error;
-  }
-
-
-  /* ChainContextSubstFormat2 */
-
-  static FT_Error  Load_ChainContextSubst2(
-                     TTO_ChainContextSubstFormat2*  ccsf2,
-                     FT_Stream                      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort              n = 0, m, count;
-    FT_ULong               cur_offset, new_offset, base_offset;
-    FT_ULong               backtrack_offset, input_offset, lookahead_offset;
-
-    TTO_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 = Load_Coverage( &ccsf2->Coverage, stream ) ) != TT_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 = Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
-                                                backtrack_offset, base_offset,
-					        stream ) ) != TT_Err_Ok )
-        goto Fail5;
-	       
-    if ( ( error = Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
-                                                input_offset, base_offset,
-                                                stream ) ) != TT_Err_Ok )
-        goto Fail4;
-    if ( ( error = Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
-                                                lookahead_offset, base_offset,
-                                                stream ) ) != TT_Err_Ok )
-      goto Fail3;
-
-    ccsf2->ChainSubClassSet   = NULL;
-    ccsf2->MaxBacktrackLength = 0;
-    ccsf2->MaxInputLength     = 0;
-    ccsf2->MaxLookaheadLength = 0;
-
-    if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, TTO_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 ) ) != TT_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 TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_ChainSubClassSet( &cscs[m], memory );
-
-    FREE( cscs );
-
-  Fail2:
-    Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory );
-
-  Fail3:
-    Free_ClassDefinition( &ccsf2->InputClassDef, memory );
-
-  Fail4:
-    Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory );
-
-  Fail5:
-    Free_Coverage( &ccsf2->Coverage, memory );
-    return error;
-  }
-
-
-  static void  Free_ChainContext2( TTO_ChainContextSubstFormat2*  ccsf2,
-				   FT_Memory                      memory )
-  {
-    FT_UShort              n, count;
-
-    TTO_ChainSubClassSet*  cscs;
-
-
-    if ( ccsf2->ChainSubClassSet )
-    {
-      count = ccsf2->ChainSubClassSetCount;
-      cscs  = ccsf2->ChainSubClassSet;
-
-      for ( n = 0; n < count; n++ )
-        Free_ChainSubClassSet( &cscs[n], memory );
-
-      FREE( cscs );
-    }
-
-    Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory );
-    Free_ClassDefinition( &ccsf2->InputClassDef, memory );
-    Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory );
-
-    Free_Coverage( &ccsf2->Coverage, memory );
-  }
-
-
-  /* ChainContextSubstFormat3 */
-
-  static FT_Error  Load_ChainContextSubst3(
-                     TTO_ChainContextSubstFormat3*  ccsf3,
-                     FT_Stream                      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               n, nb = 0, ni =0, nl = 0, m, count;
-    FT_UShort               backtrack_count, input_count, lookahead_count;
-    FT_ULong                cur_offset, new_offset, base_offset;
-
-    TTO_Coverage*           b;
-    TTO_Coverage*           i;
-    TTO_Coverage*           l;
-    TTO_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,
-                      TTO_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 = Load_Coverage( &b[nb], stream ) ) != TT_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, TTO_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 = Load_Coverage( &i[ni], stream ) ) != TT_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,
-                      TTO_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 = Load_Coverage( &l[nl], stream ) ) != TT_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,
-                      TTO_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( slr );
-
-  Fail2:
-    for ( m = 0; m < nl; m++ )
-      Free_Coverage( &l[m], memory );
-
-    FREE( l );
-
-  Fail3:
-    for ( m = 0; m < ni; m++ )
-      Free_Coverage( &i[m], memory );
-
-    FREE( i );
-
-  Fail4:
-    for ( m = 0; m < nb; m++ )
-      Free_Coverage( &b[m], memory );
-
-    FREE( b );
-    return error;
-  }
-
-
-  static void  Free_ChainContext3( TTO_ChainContextSubstFormat3*  ccsf3,
-				   FT_Memory                      memory )
-  {
-    FT_UShort      n, count;
-
-    TTO_Coverage*  c;
-
-
-    FREE( ccsf3->SubstLookupRecord );
-
-    if ( ccsf3->LookaheadCoverage )
-    {
-      count = ccsf3->LookaheadGlyphCount;
-      c     = ccsf3->LookaheadCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-
-    if ( ccsf3->InputCoverage )
-    {
-      count = ccsf3->InputGlyphCount;
-      c     = ccsf3->InputCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-
-    if ( ccsf3->BacktrackCoverage )
-    {
-      count = ccsf3->BacktrackGlyphCount;
-      c     = ccsf3->BacktrackCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-  }
-
-
-  /* ChainContextSubst */
-
-  FT_Error  Load_ChainContextSubst( TTO_ChainContextSubst*  ccs,
-                                    FT_Stream               stream )
-  {
-    FT_Error error;
-
-
-    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 TTO_Err_Invalid_GSUB_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  void  Free_ChainContextSubst( TTO_ChainContextSubst*  ccs,
-				FT_Memory               memory )
-  {
-    switch ( ccs->SubstFormat )
-    {
-    case 1:
-      Free_ChainContext1( &ccs->ccsf.ccsf1, memory );
-      break;
-
-    case 2:
-      Free_ChainContext2( &ccs->ccsf.ccsf2, memory );
-      break;
-
-    case 3:
-      Free_ChainContext3( &ccs->ccsf.ccsf3, memory );
-      break;
-    }
-  }
-
-
-  static FT_Error  Lookup_ChainContextSubst1( TTO_GSUBHeader*               gsub,
-					      TTO_ChainContextSubstFormat1* ccsf1,
-					      OTL_Buffer                    buffer,
-					      FT_UShort                     flags,
-					      FT_UShort                     context_length,
-					      int                           nesting_level )
-  {
-    FT_UShort          index, property;
-    FT_UShort          i, j, k, num_csr;
-    FT_UShort          bgc, igc, lgc;
-    FT_Error           error;
-
-    TTO_ChainSubRule*  csr;
-    TTO_ChainSubRule   curr_csr;
-    TTO_GDEFHeader*    gdef;
-
-
-    gdef = gsub->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    error = 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, OUT_ITEM( j ), flags, &property ) )
-          {
-            if ( error && error != TTO_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 ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-	  if ( j + igc - i + lgc == 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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-	  if ( j + lgc - i == 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 TTO_Err_Not_Covered;
-  }
-
-
-  static FT_Error  Lookup_ChainContextSubst2( TTO_GSUBHeader*               gsub,
-					      TTO_ChainContextSubstFormat2* ccsf2,
-					      OTL_Buffer                    buffer,
-					      FT_UShort                     flags,
-					      FT_UShort                     context_length,
-					      int                           nesting_level )
-  {
-    FT_UShort              index, property;
-    FT_Memory              memory;
-    FT_Error               error;
-    FT_UShort              i, j, k;
-    FT_UShort              bgc, igc, lgc;
-    FT_UShort              known_backtrack_classes,
-                           known_input_classes,
-                           known_lookahead_classes;
-
-    FT_UShort*             backtrack_classes;
-    FT_UShort*             input_classes;
-    FT_UShort*             lookahead_classes;
-
-    FT_UShort*             bc;
-    FT_UShort*             ic;
-    FT_UShort*             lc;
-
-    TTO_ChainSubClassSet*  cscs;
-    TTO_ChainSubClassRule  ccsr;
-    TTO_GDEFHeader*        gdef;
-
-
-    gdef = gsub->gdef;
-    memory = gsub->memory;
-
-    if ( CHECK_Property( gdef, 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 = Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index );
-    if ( error )
-      return error;
-
-    if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, FT_UShort ) )
-      return error;
-    known_backtrack_classes = 0;
-
-    if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, FT_UShort ) )
-      goto End3;
-    known_input_classes = 1;
-
-    if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, FT_UShort ) )
-      goto End2;
-    known_lookahead_classes = 0;
-
-    error = Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
-                       &input_classes[0], NULL );
-    if ( error && error != TTO_Err_Not_Covered )
-      goto End1;
-
-    cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
-    if ( !cscs )
-    {
-      error = TTO_Err_Invalid_GSUB_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, OUT_ITEM( j ), flags, &property ) )
-          {
-            if ( error && error != TTO_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 = Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ),
-                               &backtrack_classes[i], NULL );
-            if ( error && error != TTO_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 ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            goto End1;
-
-	  if ( j + igc - i + lgc == buffer->in_length )
-	    goto next_chainsubclassrule;
-	  j++;
-        }
-
-        if ( i >= known_input_classes )
-        {
-          error = Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ),
-                             &input_classes[i], NULL );
-          if ( error && error != TTO_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++ )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            goto End1;
-
-	  if ( j + lgc - i == buffer->in_length )
-	    goto next_chainsubclassrule;
-	  j++;
-        }
-
-        if ( i >= known_lookahead_classes )
-        {
-          error = Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ),
-                             &lookahead_classes[i], NULL );
-          if ( error && error != TTO_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 = TTO_Err_Not_Covered;
-
-  End1:
-    FREE( lookahead_classes );
-
-  End2:
-    FREE( input_classes );
-
-  End3:
-    FREE( backtrack_classes );
-    return error;
-  }
-
-
-  static FT_Error  Lookup_ChainContextSubst3( TTO_GSUBHeader*               gsub,
-					      TTO_ChainContextSubstFormat3* ccsf3,
-					      OTL_Buffer                    buffer,
-					      FT_UShort                     flags,
-					      FT_UShort                     context_length,
-					      int                           nesting_level )
-  {
-    FT_UShort        index, i, j, property;
-    FT_UShort        bgc, igc, lgc;
-    FT_Error         error;
-
-    TTO_Coverage*    bc;
-    TTO_Coverage*    ic;
-    TTO_Coverage*    lc;
-    TTO_GDEFHeader*  gdef;
-
-
-    gdef = gsub->gdef;
-
-    if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
-      return error;
-
-    bgc = ccsf3->BacktrackGlyphCount;
-    igc = ccsf3->InputGlyphCount;
-    lgc = ccsf3->LookaheadGlyphCount;
-
-    if ( context_length != 0xFFFF && context_length < igc )
-      return TTO_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 TTO_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 ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-	  if ( j + 1 == bgc - i )
-	    return TTO_Err_Not_Covered;
-	  j--;
-        }
-
-        error = 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 ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-      {
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-	
-	if ( j + igc - i + lgc == buffer->in_length )
-          return TTO_Err_Not_Covered;
-	j++;
-      }
-
-      error = 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++ )
-    {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-      {
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-
-	if ( j + lgc - i == buffer->in_length )
-	  return TTO_Err_Not_Covered;
-	j++;
-      }
-
-      error = 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 FT_Error  Lookup_ChainContextSubst( TTO_GSUBHeader*    gsub,
-					     TTO_GSUB_SubTable* st,
-					     OTL_Buffer         buffer,
-					     FT_UShort          flags,
-					     FT_UShort          context_length,
-					     int                nesting_level )
-  {
-    TTO_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 TTO_Err_Invalid_GSUB_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  FT_Error  Load_ReverseChainContextSubst( TTO_ReverseChainContextSubst*  rccs,
-					   FT_Stream                      stream )
-  {
-    FT_Error error;
-    FT_Memory memory = stream->memory;
-
-    FT_UShort               m, count;
-
-    FT_UShort               nb = 0, nl = 0, n;
-    FT_UShort               backtrack_count, lookahead_count;
-    FT_ULong                cur_offset, new_offset, base_offset;
-
-    TTO_Coverage*           b;
-    TTO_Coverage*           l;
-    FT_UShort*              sub;
-
-    base_offset = FILE_Pos();
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-    
-    rccs->SubstFormat = GET_UShort();
-    
-    if ( rccs->SubstFormat != 1 )
-      return TTO_Err_Invalid_GSUB_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 = Load_Coverage( &rccs->Coverage, stream ) ) != TT_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,
-                      TTO_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 = Load_Coverage( &b[nb], stream ) ) != TT_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,
-                      TTO_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 = Load_Coverage( &l[nl], stream ) ) != TT_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,
-                      FT_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 TT_Err_Ok;
-
-  Fail1:
-    FREE( sub );
-    
-  Fail2:
-    for ( m = 0; m < nl; m++ )
-      Free_Coverage( &l[m], memory );
-
-    FREE( l );
-
-  Fail3:
-    for ( m = 0; m < nb; m++ )
-      Free_Coverage( &b[m], memory );
-
-    FREE( b );
-
-  Fail4:
-    Free_Coverage( &rccs->Coverage, memory );    
-    return error;
-  }
-
-
-  void  Free_ReverseChainContextSubst( TTO_ReverseChainContextSubst*  rccs,
-	 			       FT_Memory                      memory )
-  {  
-    FT_UShort      n, count;
-
-    TTO_Coverage*  c;
-
-    Free_Coverage( &rccs->Coverage, memory );
-    
-    if ( rccs->LookaheadCoverage )
-    {
-      count = rccs->LookaheadGlyphCount;
-      c     = rccs->LookaheadCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-
-    if ( rccs->BacktrackCoverage )
-    {
-      count = rccs->BacktrackGlyphCount;
-      c     = rccs->BacktrackCoverage;
-
-      for ( n = 0; n < count; n++ )
-        Free_Coverage( &c[n], memory );
-
-      FREE( c );
-    }
-
-    FREE ( rccs->Substitute );
-  }
-  
- 
-  static FT_Error  Lookup_ReverseChainContextSubst( TTO_GSUBHeader*    gsub,
-						    TTO_GSUB_SubTable* st,
-						    OTL_Buffer         buffer,
-						    FT_UShort          flags,
-	/* note different signature here: */	    FT_ULong           string_index )
-  {
-    FT_UShort        index, input_index, i, j, property;
-    FT_UShort        bgc, lgc;
-    FT_Error         error;
-
-    TTO_ReverseChainContextSubst*  rccs = &st->reverse;
-    TTO_Coverage*    bc;
-    TTO_Coverage*    lc;
-    TTO_GDEFHeader*  gdef;
- 
-    gdef = gsub->gdef;
-
-    if ( CHECK_Property( gdef, IN_ITEM( string_index ), flags, &property ) )
-      return error;
-
-    bgc = rccs->BacktrackGlyphCount;
-    lgc = rccs->LookaheadGlyphCount;
-
-    /* check whether context is too long; it is a first guess only */
-    
-    if ( bgc > string_index || string_index + 1 + lgc > buffer->in_length )
-      return TTO_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 = string_index - 1; i < bgc; i++, j-- )
-      {
-        while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-        {
-          if ( error && error != TTO_Err_Not_Covered )
-            return error;
-
-	  if ( j + 1 == bgc - i )
-	    return TTO_Err_Not_Covered;
-	  j--;
-        }
-
-        error = Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
-        if ( error )
-          return error;
-      }
-    }
-
-    j = string_index;
-   
-    error = Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
-    if ( error )
-        return error;
-
-    /* we are starting for lookahead glyphs right after the last context
-       glyph                                                             */
-    
-    j += 1;
-
-    lc       = rccs->LookaheadCoverage;
-
-    for ( i = 0; i < lgc; i++, j++ )
-    {
-      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
-      {
-        if ( error && error != TTO_Err_Not_Covered )
-          return error;
-
-	if ( j + lgc - i == buffer->in_length )
-	  return TTO_Err_Not_Covered;
-	j++;
-      }
-
-      error = Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
-      if ( error )
-        return error;
-    }
-
-    IN_GLYPH( string_index ) = rccs->Substitute[input_index];
-	
-    return error;
-  }
-
-
- 
-  /***********
-   * GSUB API
-   ***********/
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Select_Script( TTO_GSUBHeader*  gsub,
-                                   FT_ULong         script_tag,
-                                   FT_UShort*       script_index )
-  {
-    FT_UShort          n;
-
-    TTO_ScriptList*    sl;
-    TTO_ScriptRecord*  sr;
-
-
-    if ( !gsub || !script_index )
-      return TT_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 TT_Err_Ok;
-      }
-
-    return TTO_Err_Not_Covered;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Select_Language( TTO_GSUBHeader*  gsub,
-                                     FT_ULong         language_tag,
-                                     FT_UShort        script_index,
-                                     FT_UShort*       language_index,
-                                     FT_UShort*       req_feature_index )
-  {
-    FT_UShort           n;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-
-
-    if ( !gsub || !language_index || !req_feature_index )
-      return TT_Err_Invalid_Argument;
-
-    sl = &gsub->ScriptList;
-    sr = sl->ScriptRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_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 TT_Err_Ok;
-      }
-
-    return TTO_Err_Not_Covered;
-  }
-
-
-  /* selecting 0xFFFF for language_index asks for the values of the
-     default language (DefaultLangSys)                              */
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Select_Feature( TTO_GSUBHeader*  gsub,
-                                    FT_ULong         feature_tag,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_UShort*       feature_index )
-  {
-    FT_UShort           n;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-    TTO_LangSys*        ls;
-    FT_UShort*          fi;
-
-    TTO_FeatureList*    fl;
-    TTO_FeatureRecord*  fr;
-
-
-    if ( !gsub || !feature_index )
-      return TT_Err_Invalid_Argument;
-
-    sl = &gsub->ScriptList;
-    sr = sl->ScriptRecord;
-
-    fl = &gsub->FeatureList;
-    fr = fl->FeatureRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_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 TT_Err_Invalid_Argument;
-
-      ls = &lsr[language_index].LangSys;
-    }
-
-    fi = ls->FeatureIndex;
-
-    for ( n = 0; n < ls->FeatureCount; n++ )
-    {
-      if ( fi[n] >= fl->FeatureCount )
-        return TTO_Err_Invalid_GSUB_SubTable_Format;
-
-      if ( feature_tag == fr[fi[n]].FeatureTag )
-      {
-        *feature_index = fi[n];
-
-        return TT_Err_Ok;
-      }
-    }
-
-    return TTO_Err_Not_Covered;
-  }
-
-
-  /* The next three functions return a null-terminated list */
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Query_Scripts( TTO_GSUBHeader*  gsub,
-                                   FT_ULong**       script_tag_list )
-  {
-    FT_UShort          n;
-    FT_Error           error;
-    FT_Memory          memory;
-    FT_ULong*          stl;
-
-    TTO_ScriptList*    sl;
-    TTO_ScriptRecord*  sr;
-
-
-    if ( !gsub || !script_tag_list )
-      return TT_Err_Invalid_Argument;
-
-    memory = gsub->memory;
-
-    sl = &gsub->ScriptList;
-    sr = sl->ScriptRecord;
-
-    if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) )
-      return error;
-
-    for ( n = 0; n < sl->ScriptCount; n++ )
-      stl[n] = sr[n].ScriptTag;
-    stl[n] = 0;
-
-    *script_tag_list = stl;
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Query_Languages( TTO_GSUBHeader*  gsub,
-                                     FT_UShort        script_index,
-                                     FT_ULong**       language_tag_list )
-  {
-    FT_UShort           n;
-    FT_Error            error;
-    FT_Memory           memory;
-    FT_ULong*           ltl;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-
-
-    if ( !gsub || !language_tag_list )
-      return TT_Err_Invalid_Argument;
-
-    memory = gsub->memory;
-    
-    sl = &gsub->ScriptList;
-    sr = sl->ScriptRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_Err_Invalid_Argument;
-
-    s   = &sr[script_index].Script;
-    lsr = s->LangSysRecord;
-
-    if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) )
-      return error;
-
-    for ( n = 0; n < s->LangSysCount; n++ )
-      ltl[n] = lsr[n].LangSysTag;
-    ltl[n] = 0;
-
-    *language_tag_list = ltl;
-
-    return TT_Err_Ok;
-  }
-
-
-  /* selecting 0xFFFF for language_index asks for the values of the
-     default language (DefaultLangSys)                              */
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Query_Features( TTO_GSUBHeader*  gsub,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_ULong**       feature_tag_list )
-  {
-    FT_UShort           n;
-    FT_Error            error;
-    FT_Memory           memory;
-    FT_ULong*           ftl;
-
-    TTO_ScriptList*     sl;
-    TTO_ScriptRecord*   sr;
-    TTO_Script*         s;
-    TTO_LangSysRecord*  lsr;
-    TTO_LangSys*        ls;
-    FT_UShort*          fi;
-
-    TTO_FeatureList*    fl;
-    TTO_FeatureRecord*  fr;
-
-
-    if ( !gsub || !feature_tag_list )
-      return TT_Err_Invalid_Argument;
-
-    memory = gsub->memory;
-    
-    sl = &gsub->ScriptList;
-    sr = sl->ScriptRecord;
-
-    fl = &gsub->FeatureList;
-    fr = fl->FeatureRecord;
-
-    if ( script_index >= sl->ScriptCount )
-      return TT_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 TT_Err_Invalid_Argument;
-
-      ls = &lsr[language_index].LangSys;
-    }
-
-    fi = ls->FeatureIndex;
-
-    if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) )
-      return error;
-
-    for ( n = 0; n < ls->FeatureCount; n++ )
-    {
-      if ( fi[n] >= fl->FeatureCount )
-      {
-        FREE( ftl );
-        return TTO_Err_Invalid_GSUB_SubTable_Format;
-      }
-      ftl[n] = fr[fi[n]].FeatureTag;
-    }
-    ftl[n] = 0;
-
-    *feature_tag_list = ftl;
-
-    return TT_Err_Ok;
-  }
-
-
-  typedef FT_Error  (*Lookup_Func_Type)( TTO_GSUBHeader*    gsub,
-					 TTO_GSUB_SubTable* st,
-					 OTL_Buffer         buffer,
-					 FT_UShort          flags,
-					 FT_UShort          context_length,
-					 int                nesting_level );
-  static const Lookup_Func_Type Lookup_Call_Table[] = {
-    Lookup_DefaultSubst,
-    Lookup_SingleSubst,			/* GSUB_LOOKUP_SINGLE        1 */
-    Lookup_MultipleSubst,		/* GSUB_LOOKUP_MULTIPLE      2 */
-    Lookup_AlternateSubst,		/* GSUB_LOOKUP_ALTERNATE     3 */
-    Lookup_LigatureSubst,		/* GSUB_LOOKUP_LIGATURE      4 */
-    Lookup_ContextSubst,		/* GSUB_LOOKUP_CONTEXT       5 */
-    Lookup_ChainContextSubst,		/* GSUB_LOOKUP_CHAIN         6 */
-    Lookup_DefaultSubst,		/* GSUB_LOOKUP_EXTENSION     7 */
-  };
-  /* Note that the following lookup does not belong to the table above:
-   * Lookup_ReverseChainContextSubst,	 GSUB_LOOKUP_REVERSE_CHAIN 8
-   * because it's invalid to happen where this table is used.  It's
-   * signature is different too...
-   */
-
-  /* Do an individual subtable lookup.  Returns TT_Err_Ok if substitution
-     has been done, or TTO_Err_Not_Covered if not.                        */
-
-  static FT_Error  Do_Glyph_Lookup( TTO_GSUBHeader* gsub,
-                                    FT_UShort       lookup_index,
-				    OTL_Buffer      buffer,
-                                    FT_UShort       context_length,
-                                    int             nesting_level )
-  {
-    FT_Error     error = TTO_Err_Not_Covered;
-    FT_UShort    i, flags, lookup_count;
-    TTO_Lookup*  lo;
-    int          lt;
-    Lookup_Func_Type Lookup_Func;
-
-
-    nesting_level++;
-
-    if ( nesting_level > TTO_MAX_NESTING_LEVEL )
-      return TTO_Err_Too_Many_Nested_Contexts;
-
-    lookup_count = gsub->LookupList.LookupCount;
-    if (lookup_index >= lookup_count)
-      return error;
-
-    lo    = &gsub->LookupList.Lookup[lookup_index];
-    flags = lo->LookupFlag;
-    lt = lo->LookupType;
-    if (lt >= sizeof Lookup_Call_Table / sizeof Lookup_Call_Table[0])
-      lt = 0;
-    Lookup_Func = Lookup_Call_Table[lt];
-
-    for ( i = 0; i < lo->SubTableCount; i++ )
-    {
-      error = Lookup_Func ( gsub,
-			    &lo->SubTable[i].st.gsub,
-			    buffer,
-			    flags, context_length,
-			    nesting_level );
-
-      /* Check whether we have a successful substitution or an error other
-         than TTO_Err_Not_Covered                                          */
-
-      if ( error != TTO_Err_Not_Covered )
-        return error;
-    }
-
-    return TTO_Err_Not_Covered;
-  }
-
-  /* apply one lookup to the input string object */
-
-  static FT_Error  Do_String_Lookup( TTO_GSUBHeader*   gsub,
-                                     FT_UShort         lookup_index,
-				     OTL_Buffer        buffer )
-  {
-    FT_Error  error, retError = TTO_Err_Not_Covered;
-
-    FT_UInt*  properties = gsub->LookupList.Properties;
-
-    int      nesting_level = 0;
-
-
-    while ( buffer->in_pos < buffer->in_length )
-    {
-      if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
-      {
-        /* 0xFFFF indicates that we don't have a context length yet */
-        error = Do_Glyph_Lookup( gsub, lookup_index, buffer,
-                                 0xFFFF, nesting_level );
-        if ( error )
-	{
-	  if ( error != TTO_Err_Not_Covered )
-	    return error;
-	}
-	else
-	  retError = error;
-      }
-      else
-        error = TTO_Err_Not_Covered;
-
-      if ( error == TTO_Err_Not_Covered )
-        if ( otl_buffer_copy_output_glyph ( buffer ) )
-          return error;
-    }
-
-    return retError;
-  }
-
-
-  static FT_Error  Apply_ReverseChainContextSubst( TTO_GSUBHeader*   gsub,
-						   FT_UShort         lookup_index,
-						   OTL_Buffer        buffer )
-  {
-    FT_UInt*     properties =  gsub->LookupList.Properties;
-    FT_Error     error, retError = TTO_Err_Not_Covered;
-    FT_ULong     subtable_Count, string_index;
-    FT_UShort    flags;
-    TTO_Lookup*  lo;      
-
-    if ( buffer->in_length == 0 )
-      return TTO_Err_Not_Covered;
-    
-    lo    = &gsub->LookupList.Lookup[lookup_index];
-    flags = lo->LookupFlag;      
-    
-    for ( subtable_Count = 0; subtable_Count < lo->SubTableCount; subtable_Count++ )
-    {
-      string_index  = buffer->in_length - 1;
-      do
-      {
-	if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
-	  {
-	    error = Lookup_ReverseChainContextSubst( gsub, &lo->SubTable[subtable_Count].st.gsub,
-						     buffer, flags, string_index );
-	    if ( error )
-	      {
-		if ( error != TTO_Err_Not_Covered )
-		  return error;
-	      }
-	    else
-	      retError = error;
-	  }
-      }
-      while (string_index--);
-    }
-    
-    return retError;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Add_Feature( TTO_GSUBHeader*  gsub,
-                                 FT_UShort        feature_index,
-                                 FT_UInt          property )
-  {
-    FT_UShort    i;
-
-    TTO_Feature  feature;
-    FT_UInt*     properties;
-    FT_UShort*   index;
-    FT_UShort    lookup_count;
-
-    /* Each feature can only be added once */
-    
-    if ( !gsub ||
-         feature_index >= gsub->FeatureList.FeatureCount ||
-	 gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
-      return TT_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++ )
-    {
-      FT_UShort lookup_index = index[i];
-      if (lookup_index < lookup_count)
-	properties[lookup_index] |= property;
-    }
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Clear_Features( TTO_GSUBHeader*  gsub )
-  {
-    FT_UShort i;
-
-    FT_UInt*  properties;
-
-
-    if ( !gsub )
-      return TT_Err_Invalid_Argument;
-
-    gsub->FeatureList.ApplyCount = 0;
-
-    properties = gsub->LookupList.Properties;
-
-    for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
-      properties[i] = 0;
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader*  gsub,
-                                                 TTO_AltFunction  altfunc,
-                                                 void*            data )
-  {
-    if ( !gsub )
-      return TT_Err_Invalid_Argument;
-
-    gsub->altfunc = altfunc;
-    gsub->data    = data;
-
-    return TT_Err_Ok;
-  }
-
-
-  EXPORT_FUNC
-  FT_Error  TT_GSUB_Apply_String( TTO_GSUBHeader*   gsub,
-				  OTL_Buffer        buffer )
-  {
-    FT_Error          error, retError = TTO_Err_Not_Covered;
-    FT_UShort         i, j, lookup_count;
-
-    if ( !gsub ||
-         !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length )
-      return TT_Err_Invalid_Argument;
-
-    lookup_count = gsub->LookupList.LookupCount;
-
-    for ( i = 0; i < gsub->FeatureList.ApplyCount; i++)
-    {
-      FT_UShort         feature_index;
-      TTO_Feature       feature;
-
-      feature_index = gsub->FeatureList.ApplyOrder[i];
-      feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
-
-      for ( j = 0; j < feature.LookupListCount; j++ )
-      {
-	FT_UShort         lookup_index;
-        TTO_Lookup*       lookup;
-        FT_Bool           need_swap;
-
-	lookup_index = feature.LookupListIndex[j];
-
-	/* Skip nonexistant lookups */
-        if (lookup_index >= lookup_count)
-	 continue;
-
-	lookup = &gsub->LookupList.Lookup[lookup_index];
-
-	if ( lookup->LookupType == GSUB_LOOKUP_REVERSE_CHAIN )
-	{
-	  error = Apply_ReverseChainContextSubst( gsub, lookup_index, buffer);
-	  need_swap = FALSE; /* We do ReverseChainContextSubst in-place */
-	}
-	else
-	{
-	  error = Do_String_Lookup( gsub, lookup_index, buffer );
-	  need_swap = TRUE;
-	}
-
-	if ( error )
-	{
-	  if ( error != TTO_Err_Not_Covered )
-	    goto End;
-	}
-	else
-	  retError = error;
-        
-	if ( need_swap )
-	{
-	  error = otl_buffer_swap( buffer );
-	  if ( error )
-	    goto End;
-	}
-      } 
-    }
-    
-    error = retError;
-
-  End:
-    return error;
-  }
-
-
-/* END */
diff --git a/src/ftxgsub.h b/src/ftxgsub.h
deleted file mode 100644
index 53409d6..0000000
--- a/src/ftxgsub.h
+++ /dev/null
@@ -1,594 +0,0 @@
-/*******************************************************************
- *
- *  ftxgsub.h
- *
- *    TrueType Open GSUB table support
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#ifndef FTXOPEN_H
-#error "Don't include this file! Use ftxopen.h instead."
-#endif
-
-#ifndef FTXGSUB_H
-#define FTXGSUB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define TTO_Err_Invalid_GSUB_SubTable_Format  0x1010
-#define TTO_Err_Invalid_GSUB_SubTable         0x1011
-
-
-/* Lookup types for glyph substitution */
-
-#define GSUB_LOOKUP_SINGLE        1
-#define GSUB_LOOKUP_MULTIPLE      2
-#define GSUB_LOOKUP_ALTERNATE     3
-#define GSUB_LOOKUP_LIGATURE      4
-#define GSUB_LOOKUP_CONTEXT       5
-#define GSUB_LOOKUP_CHAIN         6
-#define GSUB_LOOKUP_EXTENSION     7
-#define GSUB_LOOKUP_REVERSE_CHAIN 8
-
-/* Use this if a feature applies to all glyphs */
-
-#define ALL_GLYPHS  0xFFFF
-
-
-  /* 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
-     TT_GSUB_Register_Alternate_Function().  The function must return an
-     index into the `alternates' array.                                   */
-
-  typedef FT_UShort  (*TTO_AltFunction)(FT_ULong    pos,
-                                        FT_UShort   glyphID,
-                                        FT_UShort   num_alternates,
-                                        FT_UShort*  alternates,
-                                        void*       data );
-
-
-  struct  TTO_GSUBHeader_
-  {
-    FT_Memory        memory;
-    
-    FT_ULong         offset;
-
-    FT_Fixed         Version;
-
-    TTO_ScriptList   ScriptList;
-    TTO_FeatureList  FeatureList;
-    TTO_LookupList   LookupList;
-
-    TTO_GDEFHeader*  gdef;
-
-    /* the next two fields are used for an alternate substitution callback
-       function to select the proper alternate glyph.                      */
-
-    TTO_AltFunction  altfunc;
-    void*            data;
-  };
-
-  typedef struct TTO_GSUBHeader_   TTO_GSUBHeader;
-  typedef struct TTO_GSUBHeader_*  TTO_GSUB;
-
-
-  /* LookupType 1 */
-
-  struct  TTO_SingleSubstFormat1_
-  {
-    FT_Short  DeltaGlyphID;             /* constant added to get
-                                           substitution glyph index */
-  };
-
-  typedef struct TTO_SingleSubstFormat1_  TTO_SingleSubstFormat1;
-
-
-  struct  TTO_SingleSubstFormat2_
-  {
-    FT_UShort   GlyphCount;             /* number of glyph IDs in
-                                           Substitute array              */
-    FT_UShort*  Substitute;             /* array of substitute glyph IDs */
-  };
-
-  typedef struct TTO_SingleSubstFormat2_  TTO_SingleSubstFormat2;
-
-
-  struct  TTO_SingleSubst_
-  {
-    FT_UShort     SubstFormat;          /* 1 or 2         */
-    TTO_Coverage  Coverage;             /* Coverage table */
-
-    union
-    {
-      TTO_SingleSubstFormat1  ssf1;
-      TTO_SingleSubstFormat2  ssf2;
-    } ssf;
-  };
-
-  typedef struct TTO_SingleSubst_  TTO_SingleSubst;
-
-
-  /* LookupType 2 */
-
-  struct  TTO_Sequence_
-  {
-    FT_UShort   GlyphCount;             /* number of glyph IDs in the
-                                           Substitute array           */
-    FT_UShort*  Substitute;             /* string of glyph IDs to
-                                           substitute                 */
-  };
-
-  typedef struct TTO_Sequence_  TTO_Sequence;
-
-
-  struct  TTO_MultipleSubst_
-  {
-    FT_UShort      SubstFormat;         /* always 1                  */
-    TTO_Coverage   Coverage;            /* Coverage table            */
-    FT_UShort      SequenceCount;       /* number of Sequence tables */
-    TTO_Sequence*  Sequence;            /* array of Sequence tables  */
-  };
-
-  typedef struct TTO_MultipleSubst_  TTO_MultipleSubst;
-
-
-  /* LookupType 3 */
-
-  struct  TTO_AlternateSet_
-  {
-    FT_UShort   GlyphCount;             /* number of glyph IDs in the
-                                           Alternate array              */
-    FT_UShort*  Alternate;              /* array of alternate glyph IDs */
-  };
-
-  typedef struct TTO_AlternateSet_  TTO_AlternateSet;
-
-
-  struct  TTO_AlternateSubst_
-  {
-    FT_UShort          SubstFormat;     /* always 1                      */
-    TTO_Coverage       Coverage;        /* Coverage table                */
-    FT_UShort          AlternateSetCount;
-                                        /* number of AlternateSet tables */
-    TTO_AlternateSet*  AlternateSet;    /* array of AlternateSet tables  */
-  };
-
-  typedef struct TTO_AlternateSubst_  TTO_AlternateSubst;
-
-
-  /* LookupType 4 */
-
-  struct  TTO_Ligature_
-  {
-    FT_UShort   LigGlyph;               /* glyphID of ligature
-                                           to substitute                    */
-    FT_UShort   ComponentCount;         /* number of components in ligature */
-    FT_UShort*  Component;              /* array of component glyph IDs     */
-  };
-
-  typedef struct TTO_Ligature_  TTO_Ligature;
-
-
-  struct  TTO_LigatureSet_
-  {
-    FT_UShort      LigatureCount;       /* number of Ligature tables */
-    TTO_Ligature*  Ligature;            /* array of Ligature tables  */
-  };
-
-  typedef struct TTO_LigatureSet_  TTO_LigatureSet;
-
-
-  struct  TTO_LigatureSubst_
-  {
-    FT_UShort         SubstFormat;      /* always 1                     */
-    TTO_Coverage      Coverage;         /* Coverage table               */
-    FT_UShort         LigatureSetCount; /* number of LigatureSet tables */
-    TTO_LigatureSet*  LigatureSet;      /* array of LigatureSet tables  */
-  };
-
-  typedef struct TTO_LigatureSubst_  TTO_LigatureSubst;
-
-
-  /* needed by both lookup type 5 and 6 */
-
-  struct  TTO_SubstLookupRecord_
-  {
-    FT_UShort  SequenceIndex;           /* index into current
-                                           glyph sequence               */
-    FT_UShort  LookupListIndex;         /* Lookup to apply to that pos. */
-  };
-
-  typedef struct TTO_SubstLookupRecord_  TTO_SubstLookupRecord;
-
-
-  /* LookupType 5 */
-
-  struct  TTO_SubRule_
-  {
-    FT_UShort               GlyphCount; /* total number of input glyphs */
-    FT_UShort               SubstCount; /* number of SubstLookupRecord
-                                           tables                       */
-    FT_UShort*              Input;      /* array of input glyph IDs     */
-    TTO_SubstLookupRecord*  SubstLookupRecord;
-                                        /* array of SubstLookupRecord
-                                           tables                       */
-  };
-
-  typedef struct TTO_SubRule_  TTO_SubRule;
-
-
-  struct  TTO_SubRuleSet_
-  {
-    FT_UShort     SubRuleCount;         /* number of SubRule tables */
-    TTO_SubRule*  SubRule;              /* array of SubRule tables  */
-  };
-
-  typedef struct TTO_SubRuleSet_  TTO_SubRuleSet;
-
-
-  struct  TTO_ContextSubstFormat1_
-  {
-    TTO_Coverage     Coverage;          /* Coverage table              */
-    FT_UShort        SubRuleSetCount;   /* number of SubRuleSet tables */
-    TTO_SubRuleSet*  SubRuleSet;        /* array of SubRuleSet tables  */
-  };
-
-  typedef struct TTO_ContextSubstFormat1_  TTO_ContextSubstFormat1;
-
-
-  struct  TTO_SubClassRule_
-  {
-    FT_UShort               GlyphCount; /* total number of context classes */
-    FT_UShort               SubstCount; /* number of SubstLookupRecord
-                                           tables                          */
-    FT_UShort*              Class;      /* array of classes                */
-    TTO_SubstLookupRecord*  SubstLookupRecord;
-                                        /* array of SubstLookupRecord
-                                           tables                          */
-  };
-
-  typedef struct TTO_SubClassRule_  TTO_SubClassRule;
-
-
-  struct  TTO_SubClassSet_
-  {
-    FT_UShort          SubClassRuleCount;
-                                        /* number of SubClassRule tables */
-    TTO_SubClassRule*  SubClassRule;    /* array of SubClassRule tables  */
-  };
-
-  typedef struct TTO_SubClassSet_  TTO_SubClassSet;
-
-
-  /* The `MaxContextLength' field is not defined in the TTO specification
-     but simplifies the implementation of this format.  It holds the
-     maximal context length used in the context rules.                    */
-
-  struct  TTO_ContextSubstFormat2_
-  {
-    FT_UShort            MaxContextLength;
-                                        /* maximal context length       */
-    TTO_Coverage         Coverage;      /* Coverage table               */
-    TTO_ClassDefinition  ClassDef;      /* ClassDef table               */
-    FT_UShort            SubClassSetCount;
-                                        /* number of SubClassSet tables */
-    TTO_SubClassSet*     SubClassSet;   /* array of SubClassSet tables  */
-  };
-
-  typedef struct TTO_ContextSubstFormat2_  TTO_ContextSubstFormat2;
-
-
-  struct  TTO_ContextSubstFormat3_
-  {
-    FT_UShort               GlyphCount; /* number of input glyphs        */
-    FT_UShort               SubstCount; /* number of SubstLookupRecords  */
-    TTO_Coverage*           Coverage;   /* array of Coverage tables      */
-    TTO_SubstLookupRecord*  SubstLookupRecord;
-                                        /* array of substitution lookups */
-  };
-
-  typedef struct TTO_ContextSubstFormat3_  TTO_ContextSubstFormat3;
-
-
-  struct  TTO_ContextSubst_
-  {
-    FT_UShort  SubstFormat;             /* 1, 2, or 3 */
-
-    union
-    {
-      TTO_ContextSubstFormat1  csf1;
-      TTO_ContextSubstFormat2  csf2;
-      TTO_ContextSubstFormat3  csf3;
-    } csf;
-  };
-
-  typedef struct TTO_ContextSubst_  TTO_ContextSubst;
-
-
-  /* LookupType 6 */
-
-  struct  TTO_ChainSubRule_
-  {
-    FT_UShort               BacktrackGlyphCount;
-                                        /* total number of backtrack glyphs */
-    FT_UShort*              Backtrack;  /* array of backtrack glyph IDs     */
-    FT_UShort               InputGlyphCount;
-                                        /* total number of input glyphs     */
-    FT_UShort*              Input;      /* array of input glyph IDs         */
-    FT_UShort               LookaheadGlyphCount;
-                                        /* total number of lookahead glyphs */
-    FT_UShort*              Lookahead;  /* array of lookahead glyph IDs     */
-    FT_UShort               SubstCount; /* number of SubstLookupRecords     */
-    TTO_SubstLookupRecord*  SubstLookupRecord;
-                                        /* array of SubstLookupRecords      */
-  };
-
-  typedef struct TTO_ChainSubRule_  TTO_ChainSubRule;
-
-
-  struct  TTO_ChainSubRuleSet_
-  {
-    FT_UShort          ChainSubRuleCount;
-                                        /* number of ChainSubRule tables */
-    TTO_ChainSubRule*  ChainSubRule;    /* array of ChainSubRule tables  */
-  };
-
-  typedef struct TTO_ChainSubRuleSet_  TTO_ChainSubRuleSet;
-
-
-  struct  TTO_ChainContextSubstFormat1_
-  {
-    TTO_Coverage          Coverage;     /* Coverage table                   */
-    FT_UShort             ChainSubRuleSetCount;
-                                        /* number of ChainSubRuleSet tables */
-    TTO_ChainSubRuleSet*  ChainSubRuleSet;
-                                        /* array of ChainSubRuleSet tables  */
-  };
-
-  typedef struct TTO_ChainContextSubstFormat1_  TTO_ChainContextSubstFormat1;
-
-
-  struct  TTO_ChainSubClassRule_
-  {
-    FT_UShort               BacktrackGlyphCount;
-                                        /* total number of backtrack
-                                           classes                         */
-    FT_UShort*              Backtrack;  /* array of backtrack classes      */
-    FT_UShort               InputGlyphCount;
-                                        /* total number of context classes */
-    FT_UShort*              Input;      /* array of context classes        */
-    FT_UShort               LookaheadGlyphCount;
-                                        /* total number of lookahead
-                                           classes                         */
-    FT_UShort*              Lookahead;  /* array of lookahead classes      */
-    FT_UShort               SubstCount; /* number of SubstLookupRecords    */
-    TTO_SubstLookupRecord*  SubstLookupRecord;
-                                        /* array of substitution lookups   */
-  };
-
-  typedef struct TTO_ChainSubClassRule_  TTO_ChainSubClassRule;
-
-
-  struct  TTO_ChainSubClassSet_
-  {
-    FT_UShort               ChainSubClassRuleCount;
-                                        /* number of ChainSubClassRule
-                                           tables                      */
-    TTO_ChainSubClassRule*  ChainSubClassRule;
-                                        /* array of ChainSubClassRule
-                                           tables                      */
-  };
-
-  typedef struct TTO_ChainSubClassSet_  TTO_ChainSubClassSet;
-
-
-  /* The `MaxXXXLength' fields are not defined in the TTO specification
-     but simplifies the implementation of this format.  It holds the
-     maximal context length used in the specific context rules.         */
-
-  struct  TTO_ChainContextSubstFormat2_
-  {
-    TTO_Coverage           Coverage;    /* Coverage table             */
-
-    FT_UShort              MaxBacktrackLength;
-                                        /* maximal backtrack length   */
-    TTO_ClassDefinition    BacktrackClassDef;
-                                        /* BacktrackClassDef table    */
-    FT_UShort              MaxInputLength;
-                                        /* maximal input length       */
-    TTO_ClassDefinition    InputClassDef;
-                                        /* InputClassDef table        */
-    FT_UShort              MaxLookaheadLength;
-                                        /* maximal lookahead length   */
-    TTO_ClassDefinition    LookaheadClassDef;
-                                        /* LookaheadClassDef table    */
-
-    FT_UShort              ChainSubClassSetCount;
-                                        /* number of ChainSubClassSet
-                                           tables                     */
-    TTO_ChainSubClassSet*  ChainSubClassSet;
-                                        /* array of ChainSubClassSet
-                                           tables                     */
-  };
-
-  typedef struct TTO_ChainContextSubstFormat2_  TTO_ChainContextSubstFormat2;
-
-
-  struct  TTO_ChainContextSubstFormat3_
-  {
-    FT_UShort               BacktrackGlyphCount;
-                                        /* number of backtrack glyphs    */
-    TTO_Coverage*           BacktrackCoverage;
-                                        /* array of backtrack Coverage
-                                           tables                        */
-    FT_UShort               InputGlyphCount;
-                                        /* number of input glyphs        */
-    TTO_Coverage*           InputCoverage;
-                                        /* array of input coverage
-                                           tables                        */
-    FT_UShort               LookaheadGlyphCount;
-                                        /* number of lookahead glyphs    */
-    TTO_Coverage*           LookaheadCoverage;
-                                        /* array of lookahead coverage
-                                           tables                        */
-    FT_UShort               SubstCount; /* number of SubstLookupRecords  */
-    TTO_SubstLookupRecord*  SubstLookupRecord;
-                                        /* array of substitution lookups */
-  };
-
-  typedef struct TTO_ChainContextSubstFormat3_  TTO_ChainContextSubstFormat3;
-
-
-  struct  TTO_ChainContextSubst_
-  {
-    FT_UShort  SubstFormat;             /* 1, 2, or 3 */
-
-    union
-    {
-      TTO_ChainContextSubstFormat1  ccsf1;
-      TTO_ChainContextSubstFormat2  ccsf2;
-      TTO_ChainContextSubstFormat3  ccsf3;
-    } ccsf;
-  };
-
-  typedef struct TTO_ChainContextSubst_  TTO_ChainContextSubst;
-
-
-  /* LookupType 8 */
-  struct TTO_ReverseChainContextSubst_
-  {
-    FT_UShort      SubstFormat;         /* always 1 */
-    TTO_Coverage   Coverage;	        /* coverage table for input glyphs */
-    FT_UShort      BacktrackGlyphCount; /* number of backtrack glyphs      */
-    TTO_Coverage*  BacktrackCoverage;   /* array of backtrack Coverage
-                                           tables                          */
-    FT_UShort      LookaheadGlyphCount; /* number of lookahead glyphs      */
-    TTO_Coverage*  LookaheadCoverage;   /* array of lookahead Coverage
-                                           tables                          */
-    FT_UShort      GlyphCount;          /* number of Glyph IDs             */
-    FT_UShort*     Substitute;          /* array of substitute Glyph ID    */
-  };
-
-  typedef struct TTO_ReverseChainContextSubst_  TTO_ReverseChainContextSubst;
-
-
-  union  TTO_GSUB_SubTable_
-  {
-    TTO_SingleSubst              single;
-    TTO_MultipleSubst            multiple;
-    TTO_AlternateSubst           alternate;
-    TTO_LigatureSubst            ligature;
-    TTO_ContextSubst             context;
-    TTO_ChainContextSubst        chain;
-    TTO_ReverseChainContextSubst reverse;
-  };
-
-  typedef union TTO_GSUB_SubTable_  TTO_GSUB_SubTable;
-
-
-  /* A simple string object.  It can both `send' and `receive' data.
-     In case of sending, `length' and `pos' will be used.  In case of
-     receiving, `pos' points to the first free slot, and `allocated'
-     specifies the amount of allocated memory (and the `length' field
-     will be ignored).  The routine TT_Add_String() will increase the
-     amount of memory if necessary.  After end of receive, `length'
-     should be set to the value of `pos', and `pos' will be set to zero.
-
-     `properties' (which is treated as a bit field) gives the glyph's
-     properties: If a certain bit is set for a glyph, the feature which
-     has the same bit set in its property value is applied.
-
-     `components' is an internal array which tracks components of
-     ligatures.  We need this for MarkToLigature Attachment Positioning
-     Subtables (in GPOS) together with `ligIDs' (which is used to mark
-     ligatures and the skipped glyphs during a ligature lookup).
-     `max_ligID' is increased after a successful ligature lookup.
-
-     NEVER modify any elements of the structure!  You should rather copy
-     its contents if necessary.
-
-     TT_Add_String() will also handle allocation; you should use
-     free() in case you want to destroy the arrays in the object. */
-
-
-  /* finally, the GSUB API */
-
-  /*  EXPORT_DEF
-      TT_Error  TT_Init_GSUB_Extension( TT_Engine  engine ); */
-
-  EXPORT_DEF
-  FT_Error  TT_Load_GSUB_Table( FT_Face          face,
-                                TTO_GSUBHeader** gsub,
-                                TTO_GDEFHeader*  gdef );
-
-  EXPORT_DEF
-  FT_Error  TT_Done_GSUB_Table( TTO_GSUBHeader*  gsub );
-
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Select_Script( TTO_GSUBHeader*  gsub,
-                                   FT_ULong         script_tag,
-                                   FT_UShort*       script_index );
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Select_Language( TTO_GSUBHeader*  gsub,
-                                     FT_ULong         language_tag,
-                                     FT_UShort        script_index,
-                                     FT_UShort*       language_index,
-                                     FT_UShort*       req_feature_index );
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Select_Feature( TTO_GSUBHeader*  gsub,
-                                    FT_ULong         feature_tag,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_UShort*       feature_index );
-
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Query_Scripts( TTO_GSUBHeader*  gsub,
-                                   FT_ULong**       script_tag_list );
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Query_Languages( TTO_GSUBHeader*  gsub,
-                                     FT_UShort        script_index,
-                                     FT_ULong**       language_tag_list );
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Query_Features( TTO_GSUBHeader*  gsub,
-                                    FT_UShort        script_index,
-                                    FT_UShort        language_index,
-                                    FT_ULong**       feature_tag_list );
-
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Add_Feature( TTO_GSUBHeader*  gsub,
-                                 FT_UShort        feature_index,
-                                 FT_UInt          property );
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Clear_Features( TTO_GSUBHeader*  gsub );
-
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader*  gsub,
-                                                 TTO_AltFunction  altfunc,
-                                                 void*            data );
-  
-  EXPORT_DEF
-  FT_Error  TT_GSUB_Apply_String( TTO_GSUBHeader*   gsub,
-				  OTL_Buffer        buffer );
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FTXGSUB_H */
-
-
-/* END */
diff --git a/src/ftxopen.c b/src/ftxopen.c
deleted file mode 100644
index 8afb8f2..0000000
--- a/src/ftxopen.c
+++ /dev/null
@@ -1,1552 +0,0 @@
-/*******************************************************************
- *
- *  ftxopen.c
- *
- *    TrueType Open common table support.
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#include <config.h>
-
-#include "ftxopen.h"
-#include "ftxopenf.h"
-
-#include "ftglue.h"
-
-
-  /***************************
-   * Script related functions
-   ***************************/
-
-
-  /* LangSys */
-
-  static FT_Error  Load_LangSys( TTO_LangSys*  ls,
-				 FT_Stream     stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-    FT_UShort  n, count;
-    FT_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, FT_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 TT_Err_Ok;
-  }
-
-
-  static void  Free_LangSys( TTO_LangSys*  ls,
-   		             FT_Memory     memory )
-  {
-    FREE( ls->FeatureIndex );
-  }
-
-
-  /* Script */
-
-  static FT_Error  Load_Script( TTO_Script*  s,
-				FT_Stream    stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-    FT_UShort  n, m, count;
-    FT_ULong   cur_offset, new_offset, base_offset;
-
-    TTO_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 ) ) != TT_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();
-
-    /* safety check; otherwise the official handling of TrueType Open
-       fonts won't work */
-
-    if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
-    {
-      error = TTO_Err_Empty_Script;
-      goto Fail2;
-    }
-
-    FORGET_Frame();
-
-    s->LangSysRecord = NULL;
-
-    if ( ALLOC_ARRAY( s->LangSysRecord, count, TTO_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_LangSys( &lsr[m].LangSys, memory );
-
-    FREE( s->LangSysRecord );
-
-  Fail2:
-    Free_LangSys( &s->DefaultLangSys, memory );
-    return error;
-  }
-
-
-  static void  Free_Script( TTO_Script*  s,
-			    FT_Memory    memory )
-  {
-    FT_UShort           n, count;
-
-    TTO_LangSysRecord*  lsr;
-
-
-    Free_LangSys( &s->DefaultLangSys, memory );
-
-    if ( s->LangSysRecord )
-    {
-      count = s->LangSysCount;
-      lsr   = s->LangSysRecord;
-
-      for ( n = 0; n < count; n++ )
-        Free_LangSys( &lsr[n].LangSys, memory );
-
-      FREE( lsr );
-    }
-  }
-
-
-  /* ScriptList */
-
-  FT_Error  Load_ScriptList( TTO_ScriptList*  sl,
-   		   	     FT_Stream        stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort          n, script_count;
-    FT_ULong           cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_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 == TT_Err_Ok )
-	sl->ScriptCount += 1;
-      else if ( error != TTO_Err_Empty_Script )
-	goto Fail;
-
-      (void)FILE_Seek( cur_offset );
-    }
-
-    if ( sl->ScriptCount == 0 )
-    {
-      error = TTO_Err_Invalid_SubTable;
-      goto Fail;
-    }
-    
-    return TT_Err_Ok;
-
-  Fail:
-    for ( n = 0; n < sl->ScriptCount; n++ )
-      Free_Script( &sr[n].Script, memory );
-
-    FREE( sl->ScriptRecord );
-    return error;
-  }
-
-
-  void  Free_ScriptList( TTO_ScriptList*  sl,
-                         FT_Memory        memory )
-  {
-    FT_UShort          n, count;
-
-    TTO_ScriptRecord*  sr;
-
-
-    if ( sl->ScriptRecord )
-    {
-      count = sl->ScriptCount;
-      sr    = sl->ScriptRecord;
-
-      for ( n = 0; n < count; n++ )
-        Free_Script( &sr[n].Script, memory );
-
-      FREE( sr );
-    }
-  }
-
-
-
-  /*********************************
-   * Feature List related functions
-   *********************************/
-
-
-  /* Feature */
-
-  static FT_Error  Load_Feature( TTO_Feature*  f,
-				 FT_Stream     stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort   n, count;
-
-    FT_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, FT_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 TT_Err_Ok;
-  }
-
-
-  static void  Free_Feature( TTO_Feature*  f,
-			     FT_Memory     memory )
-  {
-    FREE( f->LookupListIndex );
-  }
-
-
-  /* FeatureList */
-
-  FT_Error  Load_FeatureList( TTO_FeatureList*  fl,
-			      FT_Stream         stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort           n, m, count;
-    FT_ULong            cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_FeatureRecord ) )
-      return error;
-    if ( ALLOC_ARRAY( fl->ApplyOrder, count, FT_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    for ( m = 0; m < n; m++ )
-      Free_Feature( &fr[m].Feature, memory );
-
-    FREE( fl->ApplyOrder );
-
-  Fail2:
-    FREE( fl->FeatureRecord );
-
-    return error;
-  }
-
-
-  void  Free_FeatureList( TTO_FeatureList*  fl,
-			  FT_Memory         memory)
-  {
-    FT_UShort           n, count;
-
-    TTO_FeatureRecord*  fr;
-
-
-    if ( fl->FeatureRecord )
-    {
-      count = fl->FeatureCount;
-      fr    = fl->FeatureRecord;
-
-      for ( n = 0; n < count; n++ )
-        Free_Feature( &fr[n].Feature, memory );
-
-      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 FT_Error  Load_SubTable( TTO_SubTable*  st,
-				  FT_Stream      stream,
-                                  TTO_Type       table_type,
-                                  FT_UShort      lookup_type )
-  {
-    if ( table_type == GSUB )
-      switch ( lookup_type )
-      {
-      case GSUB_LOOKUP_SINGLE:
-        return Load_SingleSubst( &st->st.gsub.single, stream );
-
-      case GSUB_LOOKUP_MULTIPLE:
-        return Load_MultipleSubst( &st->st.gsub.multiple, stream );
-
-      case GSUB_LOOKUP_ALTERNATE:
-        return Load_AlternateSubst( &st->st.gsub.alternate, stream );
-
-      case GSUB_LOOKUP_LIGATURE:
-        return Load_LigatureSubst( &st->st.gsub.ligature, stream );
-
-      case GSUB_LOOKUP_CONTEXT:
-        return Load_ContextSubst( &st->st.gsub.context, stream );
-
-      case GSUB_LOOKUP_CHAIN:
-        return Load_ChainContextSubst( &st->st.gsub.chain, stream );
-	
-      case GSUB_LOOKUP_REVERSE_CHAIN:
-        return Load_ReverseChainContextSubst( &st->st.gsub.reverse, stream );
-
-      default:
-        return TTO_Err_Invalid_GSUB_SubTable_Format;
-      }
-    else
-      switch ( lookup_type )
-      {
-        case GPOS_LOOKUP_SINGLE:
-          return Load_SinglePos( &st->st.gpos.single, stream );
-
-        case GPOS_LOOKUP_PAIR:
-          return Load_PairPos( &st->st.gpos.pair, stream );
-
-        case GPOS_LOOKUP_CURSIVE:
-          return Load_CursivePos( &st->st.gpos.cursive, stream );
-
-        case GPOS_LOOKUP_MARKBASE:
-          return Load_MarkBasePos( &st->st.gpos.markbase, stream );
-
-        case GPOS_LOOKUP_MARKLIG:
-          return Load_MarkLigPos( &st->st.gpos.marklig, stream );
-
-        case GPOS_LOOKUP_MARKMARK:
-          return Load_MarkMarkPos( &st->st.gpos.markmark, stream );
-
-        case GPOS_LOOKUP_CONTEXT:
-          return Load_ContextPos( &st->st.gpos.context, stream );
-
-        case GPOS_LOOKUP_CHAIN:
-          return Load_ChainContextPos( &st->st.gpos.chain, stream );
-
-        default:
-          return TTO_Err_Invalid_GPOS_SubTable_Format;
-      }
-
-    return TT_Err_Ok;           /* never reached */
-  }
-
-
-  static void  Free_SubTable( TTO_SubTable*  st,
-                              TTO_Type       table_type,
-                              FT_UShort      lookup_type,
-			      FT_Memory      memory )
-  {
-    if ( table_type == GSUB )
-      switch ( lookup_type )
-      {
-      case GSUB_LOOKUP_SINGLE:
-        Free_SingleSubst( &st->st.gsub.single, memory );
-        break;
-
-      case GSUB_LOOKUP_MULTIPLE:
-        Free_MultipleSubst( &st->st.gsub.multiple, memory );
-        break;
-
-      case GSUB_LOOKUP_ALTERNATE:
-        Free_AlternateSubst( &st->st.gsub.alternate, memory );
-        break;
-
-      case GSUB_LOOKUP_LIGATURE:
-        Free_LigatureSubst( &st->st.gsub.ligature, memory );
-        break;
-
-      case GSUB_LOOKUP_CONTEXT:
-        Free_ContextSubst( &st->st.gsub.context, memory );
-        break;
-
-      case GSUB_LOOKUP_REVERSE_CHAIN:
-        Free_ReverseChainContextSubst( &st->st.gsub.reverse, memory );
-        break;
-
-      case GSUB_LOOKUP_CHAIN:
-        Free_ChainContextSubst( &st->st.gsub.chain, memory );
-        break;
-      }
-    else
-      switch ( lookup_type )
-      {
-      case GPOS_LOOKUP_SINGLE:
-        Free_SinglePos( &st->st.gpos.single, memory );
-        break;
-
-      case GPOS_LOOKUP_PAIR:
-        Free_PairPos( &st->st.gpos.pair, memory );
-        break;
-
-      case GPOS_LOOKUP_CURSIVE:
-        Free_CursivePos( &st->st.gpos.cursive, memory );
-        break;
-
-      case GPOS_LOOKUP_MARKBASE:
-        Free_MarkBasePos( &st->st.gpos.markbase, memory );
-        break;
-
-      case GPOS_LOOKUP_MARKLIG:
-        Free_MarkLigPos( &st->st.gpos.marklig, memory );
-        break;
-
-      case GPOS_LOOKUP_MARKMARK:
-        Free_MarkMarkPos( &st->st.gpos.markmark, memory );
-        break;
-
-      case GPOS_LOOKUP_CONTEXT:
-        Free_ContextPos( &st->st.gpos.context, memory );
-        break;
-
-      case GPOS_LOOKUP_CHAIN:
-        Free_ChainContextPos ( &st->st.gpos.chain, memory );
-        break;
-      }
-  }
-
-
-  /* Lookup */
-
-  static FT_Error  Load_Lookup( TTO_Lookup*   l,
-				FT_Stream     stream,
-                                TTO_Type      type )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort      n, m, count;
-    FT_ULong       cur_offset, new_offset, base_offset;
-
-    TTO_SubTable*  st;
-
-    FT_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, TTO_SubTable ) )
-      return error;
-
-    st = l->SubTable;
-
-    if ( ( type == GSUB && l->LookupType == GSUB_LOOKUP_EXTENSION ) ||
-         ( type == GPOS && l->LookupType == 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 ) ) != TT_Err_Ok )
-        goto Fail;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail:
-    for ( m = 0; m < n; m++ )
-      Free_SubTable( &st[m], type, l->LookupType, memory );
-
-    FREE( l->SubTable );
-    return error;
-  }
-
-
-  static void  Free_Lookup( TTO_Lookup*   l,
-                            TTO_Type      type,
-			    FT_Memory     memory)
-  {
-    FT_UShort      n, count;
-
-    TTO_SubTable*  st;
-
-
-    if ( l->SubTable )
-    {
-      count = l->SubTableCount;
-      st    = l->SubTable;
-
-      for ( n = 0; n < count; n++ )
-        Free_SubTable( &st[n], type, l->LookupType, memory );
-
-      FREE( st );
-    }
-  }
-
-
-  /* LookupList */
-
-  FT_Error  Load_LookupList( TTO_LookupList*  ll,
-			     FT_Stream        stream,
-                             TTO_Type         type )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort    n, m, count;
-    FT_ULong     cur_offset, new_offset, base_offset;
-
-    TTO_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, TTO_Lookup ) )
-      return error;
-    if ( ALLOC_ARRAY( ll->Properties, count, FT_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 ) ) != TT_Err_Ok )
-        goto Fail1;
-      (void)FILE_Seek( cur_offset );
-    }
-
-    return TT_Err_Ok;
-
-  Fail1:
-    FREE( ll->Properties );
-
-    for ( m = 0; m < n; m++ )
-      Free_Lookup( &l[m], type, memory );
-
-  Fail2:
-    FREE( ll->Lookup );
-    return error;
-  }
-
-
-  void  Free_LookupList( TTO_LookupList*  ll,
-                         TTO_Type         type,
-			 FT_Memory        memory )
-  {
-    FT_UShort    n, count;
-
-    TTO_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, memory );
-
-      FREE( l );
-    }
-  }
-
-
-
-  /*****************************
-   * Coverage related functions
-   *****************************/
-
-
-  /* CoverageFormat1 */
-
-  static FT_Error  Load_Coverage1( TTO_CoverageFormat1*  cf1,
-				   FT_Stream             stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort  n, count;
-
-    FT_UShort* ga;
-
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    count = cf1->GlyphCount = GET_UShort();
-
-    FORGET_Frame();
-
-    cf1->GlyphArray = NULL;
-
-    if ( ALLOC_ARRAY( cf1->GlyphArray, count, FT_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 TT_Err_Ok;
-  }
-
-
-  static void  Free_Coverage1( TTO_CoverageFormat1*  cf1,
-			       FT_Memory             memory)
-  {
-    FREE( cf1->GlyphArray );
-  }
-
-
-  /* CoverageFormat2 */
-
-  static FT_Error  Load_Coverage2( TTO_CoverageFormat2*  cf2,
-				   FT_Stream             stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort         n, count;
-
-    TTO_RangeRecord*  rr;
-
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    count = cf2->RangeCount = GET_UShort();
-
-    FORGET_Frame();
-
-    cf2->RangeRecord = NULL;
-
-    if ( ALLOC_ARRAY( cf2->RangeRecord, count, TTO_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 = TTO_Err_Invalid_SubTable;
-        goto Fail;
-      }
-    }
-
-    FORGET_Frame();
-
-    return TT_Err_Ok;
-
-  Fail:
-    FREE( cf2->RangeRecord );
-    return error;
-  }
-
-
-  static void  Free_Coverage2( TTO_CoverageFormat2*  cf2,
-			       FT_Memory             memory )
-  {
-    FREE( cf2->RangeRecord );
-  }
-
-
-  FT_Error  Load_Coverage( TTO_Coverage*  c,
-			   FT_Stream      stream )
-  {
-    FT_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 TTO_Err_Invalid_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-  void  Free_Coverage( TTO_Coverage*  c,
-		       FT_Memory      memory )
-  {
-    switch ( c->CoverageFormat )
-    {
-    case 1:
-      Free_Coverage1( &c->cf.cf1, memory );
-      break;
-
-    case 2:
-      Free_Coverage2( &c->cf.cf2, memory );
-      break;
-    }
-  }
-
-
-  static FT_Error  Coverage_Index1( TTO_CoverageFormat1*  cf1,
-                                    FT_UShort             glyphID,
-                                    FT_UShort*            index )
-  {
-    FT_UShort min, max, new_min, new_max, middle;
-
-    FT_UShort*  array = cf1->GlyphArray;
-
-
-    /* binary search */
-
-    if ( cf1->GlyphCount == 0 )
-      return TTO_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 TT_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 TTO_Err_Not_Covered;
-  }
-
-
-  static FT_Error  Coverage_Index2( TTO_CoverageFormat2*  cf2,
-                                    FT_UShort             glyphID,
-                                    FT_UShort*            index )
-  {
-    FT_UShort         min, max, new_min, new_max, middle;
-
-    TTO_RangeRecord*  rr = cf2->RangeRecord;
-
-
-    /* binary search */
-
-    if ( cf2->RangeCount == 0 )
-      return TTO_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 TT_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 TTO_Err_Not_Covered;
-  }
-
-
-  FT_Error  Coverage_Index( TTO_Coverage*  c,
-                            FT_UShort      glyphID,
-                            FT_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 TTO_Err_Invalid_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-
-  /*************************************
-   * Class Definition related functions
-   *************************************/
-
-
-  /* ClassDefFormat1 */
-
-  static FT_Error  Load_ClassDef1( TTO_ClassDefinition*  cd,
-                                   FT_UShort             limit,
-				   FT_Stream             stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort             n, count;
-
-    FT_UShort*            cva;
-    FT_Bool*              d;
-
-    TTO_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 TTO_Err_Invalid_SubTable;
-
-    cdf1->ClassValueArray = NULL;
-
-    if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, FT_UShort ) )
-      return error;
-
-    d   = cd->Defined;
-    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 = TTO_Err_Invalid_SubTable;
-        goto Fail;
-      }
-      d[cva[n]] = TRUE;
-    }
-
-    FORGET_Frame();
-
-    return TT_Err_Ok;
-
-  Fail:
-    FREE( cva );
-
-    return error;
-  }
-
-
-  static void  Free_ClassDef1( TTO_ClassDefFormat1*  cdf1,
-			       FT_Memory             memory )
-  {
-    FREE( cdf1->ClassValueArray );
-  }
-
-
-  /* ClassDefFormat2 */
-
-  static FT_Error  Load_ClassDef2( TTO_ClassDefinition*  cd,
-                                   FT_UShort             limit,
-				   FT_Stream             stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort              n, count;
-
-    TTO_ClassRangeRecord*  crr;
-    FT_Bool*               d;
-
-    TTO_ClassDefFormat2*   cdf2;
-
-
-    cdf2 = &cd->cd.cd2;
-
-    if ( ACCESS_Frame( 2L ) )
-      return error;
-
-    count = cdf2->ClassRangeCount = GET_UShort();
-
-    FORGET_Frame();
-
-    cdf2->ClassRangeRecord = NULL;
-
-    if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, TTO_ClassRangeRecord ) )
-      return error;
-
-    d   = cd->Defined;
-    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 )
-      {
-        error = TTO_Err_Invalid_SubTable;
-        goto Fail;
-      }
-      d[crr[n].Class] = TRUE;
-    }
-
-    FORGET_Frame();
-
-    return TT_Err_Ok;
-
-  Fail:
-    FREE( crr );
-
-    return error;
-  }
-
-
-  static void  Free_ClassDef2( TTO_ClassDefFormat2*  cdf2,
-			       FT_Memory             memory )
-  {
-    FREE( cdf2->ClassRangeRecord );
-  }
-
-
-  /* ClassDefinition */
-
-  FT_Error  Load_ClassDefinition( TTO_ClassDefinition*  cd,
-                                  FT_UShort             limit,
-				  FT_Stream             stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-
-    if ( ALLOC_ARRAY( cd->Defined, limit, FT_Bool ) )
-      return error;
-
-    if ( ACCESS_Frame( 2L ) )
-      goto Fail;
-
-    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 = TTO_Err_Invalid_SubTable_Format;
-      break;
-    }
-
-    if ( error )
-      goto Fail;
-
-    cd->loaded = TRUE;
-
-    return TT_Err_Ok;
-
-  Fail:
-    FREE( cd->Defined );
-    return error;
-  }
-
-
-  FT_Error  Load_EmptyClassDefinition( TTO_ClassDefinition*  cd,
-				       FT_Stream             stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-
-    if ( ALLOC_ARRAY( cd->Defined, 1, FT_Bool ) )
-      return error;
-
-    cd->ClassFormat = 1; /* Meaningless */
-    cd->Defined[0] = FALSE;
-
-    if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, FT_UShort ) )
-      goto Fail;
-
-    return TT_Err_Ok;
-
-  Fail:
-    FREE( cd->Defined );
-    return error;
-  }
-
-  void  Free_ClassDefinition( TTO_ClassDefinition*  cd,
-			      FT_Memory             memory )
-  {
-    if ( !cd->loaded )
-      return;
-
-    FREE( cd->Defined );
-
-    switch ( cd->ClassFormat )
-    {
-    case 1:
-      Free_ClassDef1( &cd->cd.cd1, memory );
-      break;
-
-    case 2:
-      Free_ClassDef2( &cd->cd.cd2, memory );
-      break;
-    }
-  }
-
-
-  static FT_Error  Get_Class1( TTO_ClassDefFormat1*  cdf1,
-                               FT_UShort             glyphID,
-                               FT_UShort*            class,
-                               FT_UShort*            index )
-  {
-    FT_UShort*  cva = cdf1->ClassValueArray;
-
-
-    if ( index )
-      *index = 0;
-
-    if ( glyphID >= cdf1->StartGlyph &&
-         glyphID <= cdf1->StartGlyph + cdf1->GlyphCount )
-    {
-      *class = cva[glyphID - cdf1->StartGlyph];
-      return TT_Err_Ok;
-    }
-    else
-    {
-      *class = 0;
-      return TTO_Err_Not_Covered;
-    }
-  }
-
-
-  /* we need the index value of the last searched class range record
-     in case of failure for constructed GDEF tables                  */
-
-  static FT_Error  Get_Class2( TTO_ClassDefFormat2*  cdf2,
-                               FT_UShort             glyphID,
-                               FT_UShort*            class,
-                               FT_UShort*            index )
-  {
-    FT_Error               error = TT_Err_Ok;
-    FT_UShort              min, max, new_min, new_max, middle;
-
-    TTO_ClassRangeRecord*  crr = cdf2->ClassRangeRecord;
-
-
-    /* binary search */
-
-    if ( cdf2->ClassRangeCount == 0 )
-      {
-	*class = 0;
-	if ( index )
-	  *index = 0;
-	
-	return TTO_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 )
-      {
-        *class = crr[middle].Class;
-        error  = TT_Err_Ok;
-        break;
-      }
-      else if ( glyphID < crr[middle].Start )
-      {
-        if ( middle == min )
-        {
-          *class = 0;
-          error  = TTO_Err_Not_Covered;
-          break;
-        }
-        new_max = middle - 1;
-      }
-      else
-      {
-        if ( middle == max )
-        {
-          *class = 0;
-          error  = TTO_Err_Not_Covered;
-          break;
-        }
-        new_min = middle + 1;
-      }
-    } while ( min < max );
-
-    if ( index )
-      *index = middle;
-
-    return error;
-  }
-
-
-  FT_Error  Get_Class( TTO_ClassDefinition*  cd,
-                       FT_UShort             glyphID,
-                       FT_UShort*            class,
-                       FT_UShort*            index )
-  {
-    switch ( cd->ClassFormat )
-    {
-    case 1:
-      return Get_Class1( &cd->cd.cd1, glyphID, class, index );
-
-    case 2:
-      return Get_Class2( &cd->cd.cd2, glyphID, class, index );
-
-    default:
-      return TTO_Err_Invalid_SubTable_Format;
-    }
-
-    return TT_Err_Ok;               /* never reached */
-  }
-
-
-
-  /***************************
-   * Device related functions
-   ***************************/
-
-
-  FT_Error  Load_Device( TTO_Device*  d,
-			 FT_Stream    stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_UShort   n, count;
-
-    FT_UShort*  dv;
-
-
-    if ( ACCESS_Frame( 6L ) )
-      return error;
-
-    d->StartSize   = GET_UShort();
-    d->EndSize     = GET_UShort();
-    d->DeltaFormat = GET_UShort();
-
-    FORGET_Frame();
-
-    if ( d->StartSize > d->EndSize ||
-         d->DeltaFormat == 0 || d->DeltaFormat > 3 )
-      return TTO_Err_Invalid_SubTable;
-
-    d->DeltaValue = NULL;
-
-    count = ( ( d->EndSize - d->StartSize + 1 ) >>
-                ( 4 - d->DeltaFormat ) ) + 1;
-
-    if ( ALLOC_ARRAY( d->DeltaValue, count, FT_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 TT_Err_Ok;
-  }
-
-
-  void  Free_Device( TTO_Device*  d,
-		     FT_Memory    memory )
-  {
-    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                                    */
-
-  FT_Error  Get_Device( TTO_Device*  d,
-                        FT_UShort    size,
-                        FT_Short*    value )
-  {
-    FT_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 = (FT_Short)( bits & mask );
-
-      /* conversion to a signed value */
-
-      if ( *value >= ( ( mask + 1 ) >> 1 ) )
-        *value -= mask + 1;
-
-      return TT_Err_Ok;
-    }
-    else
-    {
-      *value = 0;
-      return TTO_Err_Not_Covered;
-    }
-  }
-
-
-/* END */
diff --git a/src/ftxopen.h b/src/ftxopen.h
deleted file mode 100644
index 64d2820..0000000
--- a/src/ftxopen.h
+++ /dev/null
@@ -1,317 +0,0 @@
-/*******************************************************************
- *
- *  ftxopen.h
- *
- *    TrueType Open support.
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- *  This file should be included by the application.  Nevertheless,
- *  the table specific APIs (and structures) are located in files like
- *  ftxgsub.h or ftxgpos.h; these header files are read by ftxopen.h .
- *
- ******************************************************************/
-
-#ifndef FTXOPEN_H
-#define FTXOPEN_H
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define EXPORT_DEF 
-#define EXPORT_FUNC
-
-#define TTO_MAX_NESTING_LEVEL  100
-
-#define TTO_Err_Invalid_SubTable_Format   0x1000
-#define TTO_Err_Invalid_SubTable          0x1001
-#define TTO_Err_Not_Covered               0x1002
-#define TTO_Err_Too_Many_Nested_Contexts  0x1003
-#define TTO_Err_No_MM_Interpreter         0x1004
-#define TTO_Err_Empty_Script              0x1005
-
-
-  /* Script list related structures */
-
-  struct  TTO_LangSys_
-  {
-    FT_UShort   LookupOrderOffset;      /* always 0 for TT Open 1.0  */
-    FT_UShort   ReqFeatureIndex;        /* required FeatureIndex     */
-    FT_UShort   FeatureCount;           /* number of Feature indices */
-    FT_UShort*  FeatureIndex;           /* array of Feature indices  */
-  };
-
-  typedef struct TTO_LangSys_  TTO_LangSys;
-
-
-  struct  TTO_LangSysRecord_
-  {
-    FT_ULong     LangSysTag;            /* LangSysTag identifier */
-    TTO_LangSys  LangSys;               /* LangSys table         */
-  };
-
-  typedef struct TTO_LangSysRecord_  TTO_LangSysRecord;
-
-
-  struct  TTO_Script_
-  {
-    TTO_LangSys         DefaultLangSys; /* DefaultLangSys table     */
-    FT_UShort           LangSysCount;   /* number of LangSysRecords */
-    TTO_LangSysRecord*  LangSysRecord;  /* array of LangSysRecords  */
-  };
-
-  typedef struct TTO_Script_  TTO_Script;
-
-
-  struct  TTO_ScriptRecord_
-  {
-    FT_ULong    ScriptTag;              /* ScriptTag identifier */
-    TTO_Script  Script;                 /* Script table         */
-  };
-
-  typedef struct TTO_ScriptRecord_  TTO_ScriptRecord;
-
-
-  struct  TTO_ScriptList_
-  {
-    FT_UShort          ScriptCount;     /* number of ScriptRecords */
-    TTO_ScriptRecord*  ScriptRecord;    /* array of ScriptRecords  */
-  };
-
-  typedef struct TTO_ScriptList_  TTO_ScriptList;
-
-
-  /* Feature list related structures */
-
-  struct TTO_Feature_
-  {
-    FT_UShort   FeatureParams;          /* always 0 for TT Open 1.0     */
-    FT_UShort   LookupListCount;        /* number of LookupList indices */
-    FT_UShort*  LookupListIndex;        /* array of LookupList indices  */
-  };
-
-  typedef struct TTO_Feature_  TTO_Feature;
-
-
-  struct  TTO_FeatureRecord_
-  {
-    FT_ULong     FeatureTag;            /* FeatureTag identifier */
-    TTO_Feature  Feature;               /* Feature table         */
-  };
-
-  typedef struct TTO_FeatureRecord_  TTO_FeatureRecord;
-
-
-  struct  TTO_FeatureList_
-  {
-    FT_UShort           FeatureCount;   /* number of FeatureRecords */
-    TTO_FeatureRecord*  FeatureRecord;  /* array of FeatureRecords  */
-    FT_UShort*		ApplyOrder;	/* order to apply features */
-    FT_UShort		ApplyCount;	/* number of elements in ApplyOrder */
-  };
-
-  typedef struct TTO_FeatureList_  TTO_FeatureList;
-
-
-  /* Lookup list related structures */
-
-  struct  TTO_SubTable_;                /* defined below after inclusion
-                                           of ftxgsub.h and ftxgpos.h    */
-  typedef struct TTO_SubTable_  TTO_SubTable;
-
-
-  struct  TTO_Lookup_
-  {
-    FT_UShort      LookupType;          /* Lookup type         */
-    FT_UShort      LookupFlag;          /* Lookup qualifiers   */
-    FT_UShort      SubTableCount;       /* number of SubTables */
-    TTO_SubTable*  SubTable;            /* array of SubTables  */
-  };
-
-  typedef struct TTO_Lookup_  TTO_Lookup;
-
-
-  /* The `Properties' field is not defined in the TTO specification but
-     is needed for processing lookups.  If properties[n] is > 0, the
-     functions TT_GSUB_Apply_String() resp. TT_GPOS_Apply_String() will
-     process Lookup[n] for glyphs which have the specific bit not set in
-     the `properties' field of the input string object.                  */
-
-  struct  TTO_LookupList_
-  {
-    FT_UShort    LookupCount;           /* number of Lookups       */
-    TTO_Lookup*  Lookup;                /* array of Lookup records */
-    FT_UInt*     Properties;            /* array of flags          */
-  };
-
-  typedef struct TTO_LookupList_  TTO_LookupList;
-
-
-  /* Possible LookupFlag bit masks.  `IGNORE_SPECIAL_MARKS' comes from the
-     OpenType 1.2 specification; RIGHT_TO_LEFT has been (re)introduced in
-     OpenType 1.3 -- if set, the last glyph in a cursive attachment
-     sequence has to be positioned on the baseline -- regardless of the
-     writing direction.                                                    */
-
-#define RIGHT_TO_LEFT         0x0001
-#define IGNORE_BASE_GLYPHS    0x0002
-#define IGNORE_LIGATURES      0x0004
-#define IGNORE_MARKS          0x0008
-#define IGNORE_SPECIAL_MARKS  0xFF00
-
-
-  struct  TTO_CoverageFormat1_
-  {
-    FT_UShort   GlyphCount;             /* number of glyphs in GlyphArray */
-    FT_UShort*  GlyphArray;             /* array of glyph IDs             */
-  };
-
-  typedef struct TTO_CoverageFormat1_  TTO_CoverageFormat1;
-
-
-  struct TTO_RangeRecord_
-  {
-    FT_UShort  Start;                   /* first glyph ID in the range */
-    FT_UShort  End;                     /* last glyph ID in the range  */
-    FT_UShort  StartCoverageIndex;      /* coverage index of first
-                                           glyph ID in the range       */
-  };
-
-  typedef struct TTO_RangeRecord_  TTO_RangeRecord;
-
-
-  struct  TTO_CoverageFormat2_
-  {
-    FT_UShort         RangeCount;       /* number of RangeRecords */
-    TTO_RangeRecord*  RangeRecord;      /* array of RangeRecords  */
-  };
-
-  typedef struct TTO_CoverageFormat2_  TTO_CoverageFormat2;
-
-
-  struct  TTO_Coverage_
-  {
-    FT_UShort  CoverageFormat;          /* 1 or 2 */
-
-    union
-    {
-      TTO_CoverageFormat1  cf1;
-      TTO_CoverageFormat2  cf2;
-    } cf;
-  };
-
-  typedef struct TTO_Coverage_  TTO_Coverage;
-
-
-  struct  TTO_ClassDefFormat1_
-  {
-    FT_UShort   StartGlyph;             /* first glyph ID of the
-                                           ClassValueArray             */
-    FT_UShort   GlyphCount;             /* size of the ClassValueArray */
-    FT_UShort*  ClassValueArray;        /* array of class values       */
-  };
-
-  typedef struct TTO_ClassDefFormat1_  TTO_ClassDefFormat1;
-
-
-  struct  TTO_ClassRangeRecord_
-  {
-    FT_UShort  Start;                   /* first glyph ID in the range    */
-    FT_UShort  End;                     /* last glyph ID in the range     */
-    FT_UShort  Class;                   /* applied to all glyphs in range */
-  };
-
-  typedef struct TTO_ClassRangeRecord_  TTO_ClassRangeRecord;
-
-
-  struct  TTO_ClassDefFormat2_
-  {
-    FT_UShort              ClassRangeCount;
-                                        /* number of ClassRangeRecords */
-    TTO_ClassRangeRecord*  ClassRangeRecord;
-                                        /* array of ClassRangeRecords  */
-  };
-
-  typedef struct TTO_ClassDefFormat2_  TTO_ClassDefFormat2;
-
-
-  /* The `Defined' field is not defined in the TTO specification but
-     apparently needed for processing fonts like trado.ttf: This font
-     refers to a class which contains not a single element.  We map such
-     classes to class 0.                                                 */
-
-  struct  TTO_ClassDefinition_
-  {
-    FT_Bool    loaded;
-
-    FT_Bool*   Defined;                 /* array of Booleans.
-                                           If Defined[n] is FALSE,
-                                           class n contains no glyphs. */
-    FT_UShort  ClassFormat;             /* 1 or 2                      */
-
-    union
-    {
-      TTO_ClassDefFormat1  cd1;
-      TTO_ClassDefFormat2  cd2;
-    } cd;
-  };
-
-  typedef struct TTO_ClassDefinition_  TTO_ClassDefinition;
-
-
-  struct TTO_Device_
-  {
-    FT_UShort   StartSize;              /* smallest size to correct      */
-    FT_UShort   EndSize;                /* largest size to correct       */
-    FT_UShort   DeltaFormat;            /* DeltaValue array data format:
-                                           1, 2, or 3                    */
-    FT_UShort*  DeltaValue;             /* array of compressed data      */
-  };
-
-  typedef struct TTO_Device_  TTO_Device;
-
-
-#include "otlbuffer.h"
-#include "ftxgdef.h"
-#include "ftxgsub.h"
-#include "ftxgpos.h"
-
-
-  struct  TTO_SubTable_
-  {
-    union
-    {
-      TTO_GSUB_SubTable  gsub;
-      TTO_GPOS_SubTable  gpos;
-    } st;
-  };
-
-
-  enum  TTO_Type_
-  {
-    GSUB,
-    GPOS
-  };
-
-  typedef enum TTO_Type_  TTO_Type;
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FTXOPEN_H */
-
-
-/* END */
diff --git a/src/ftxopenf.h b/src/ftxopenf.h
deleted file mode 100644
index 2c274c3..0000000
--- a/src/ftxopenf.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*******************************************************************
- *
- *  ftxopenf.h
- *
- *    internal TrueType Open functions
- *
- *  Copyright 1996-2000 by
- *  David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- *  This file is part of the FreeType project, and may only be used
- *  modified and distributed under the terms of the FreeType project
- *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
- *  this file you indicate that you have read the license and
- *  understand and accept it fully.
- *
- ******************************************************************/
-
-#ifndef FTXOPENF_H
-#define FTXOPENF_H
-
-#include "ftxopen.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-  /* functions from ftxopen.c */
-
-  FT_Error  Load_ScriptList( TTO_ScriptList*  sl,
-			     FT_Stream     stream );
-  FT_Error  Load_FeatureList( TTO_FeatureList*  fl,
-                              FT_Stream         input );
-  FT_Error  Load_LookupList( TTO_LookupList*  ll,
-                             FT_Stream        input,
-                             TTO_Type         type );
-
-  FT_Error  Load_Coverage( TTO_Coverage*  c,
-                           FT_Stream      input );
-  FT_Error  Load_ClassDefinition( TTO_ClassDefinition*  cd,
-                                  FT_UShort             limit,
-                                  FT_Stream             input );
-  FT_Error  Load_EmptyClassDefinition( TTO_ClassDefinition*  cd,
-                                       FT_Stream             input );
-  FT_Error  Load_Device( TTO_Device*  d,
-                         FT_Stream    input );
-
-  void  Free_ScriptList( TTO_ScriptList*  sl, 
-                         FT_Memory        memory );
-  void  Free_FeatureList( TTO_FeatureList*  fl,
-			  FT_Memory         memory );
-  void  Free_LookupList( TTO_LookupList*  ll,
-                         TTO_Type         type,
-			 FT_Memory        memory );
-
-  void  Free_Coverage( TTO_Coverage*  c,
-		       FT_Memory      memory );
-  void  Free_ClassDefinition( TTO_ClassDefinition*  cd,
-			      FT_Memory             memory );
-  void  Free_Device( TTO_Device*  d,
-		     FT_Memory    memory );
-
-
-  /* functions from ftxgsub.c */
-
-  FT_Error  Load_SingleSubst( TTO_SingleSubst*  ss,
-                              FT_Stream         input );
-  FT_Error  Load_MultipleSubst( TTO_MultipleSubst*  ms,
-                                FT_Stream           input );
-  FT_Error  Load_AlternateSubst( TTO_AlternateSubst*  as,
-                                 FT_Stream            input );
-  FT_Error  Load_LigatureSubst( TTO_LigatureSubst*  ls,
-                                FT_Stream           input );
-  FT_Error  Load_ContextSubst( TTO_ContextSubst*  cs,
-                               FT_Stream          input );
-  FT_Error  Load_ChainContextSubst( TTO_ChainContextSubst*  ccs,
-                                    FT_Stream               input );
-  FT_Error  Load_ReverseChainContextSubst( TTO_ReverseChainContextSubst*  rccs,
-					   FT_Stream                      input );
-
-  void  Free_SingleSubst( TTO_SingleSubst*  ss,
-			  FT_Memory         memory );
-  void  Free_MultipleSubst( TTO_MultipleSubst*  ms,
-			    FT_Memory         memory );
-  void  Free_AlternateSubst( TTO_AlternateSubst*  as,
-			     FT_Memory            memory );
-  void  Free_LigatureSubst( TTO_LigatureSubst*  ls,
-			    FT_Memory           memory );
-  void  Free_ContextSubst( TTO_ContextSubst*  cs,
-			   FT_Memory         memory );
-  void  Free_ChainContextSubst( TTO_ChainContextSubst*  ccs,
-				FT_Memory               memory );
-  void  Free_ReverseChainContextSubst( TTO_ReverseChainContextSubst*  rccs,
-				       FT_Memory                      memory );
-
-  /* functions from ftxgpos.c */
-
-  FT_Error  Load_SinglePos( TTO_SinglePos*  sp,
-                            FT_Stream       input );
-  FT_Error  Load_PairPos( TTO_PairPos*  pp,
-                          FT_Stream     input );
-  FT_Error  Load_CursivePos( TTO_CursivePos*  cp,
-                             FT_Stream        input );
-  FT_Error  Load_MarkBasePos( TTO_MarkBasePos*  mbp,
-                              FT_Stream         input );
-  FT_Error  Load_MarkLigPos( TTO_MarkLigPos*  mlp,
-                             FT_Stream        input );
-  FT_Error  Load_MarkMarkPos( TTO_MarkMarkPos*  mmp,
-                              FT_Stream         input );
-  FT_Error  Load_ContextPos( TTO_ContextPos*  cp,
-                             FT_Stream        input );
-  FT_Error  Load_ChainContextPos( TTO_ChainContextPos*  ccp,
-                                  FT_Stream             input );
-
-  void  Free_SinglePos( TTO_SinglePos*  sp,
-			FT_Memory       memory );
-  void  Free_PairPos( TTO_PairPos*  pp,
-		      FT_Memory     memory );
-  void  Free_CursivePos( TTO_CursivePos*  cp,
-   		         FT_Memory     memory );
-  void  Free_MarkBasePos( TTO_MarkBasePos*  mbp,
-			  FT_Memory         memory );
-  void  Free_MarkLigPos( TTO_MarkLigPos*  mlp,
-			 FT_Memory        memory );
-  void  Free_MarkMarkPos( TTO_MarkMarkPos*  mmp,
-			  FT_Memory         memory );
-  void  Free_ContextPos( TTO_ContextPos*  cp,
-			 FT_Memory         memory );
-  void  Free_ChainContextPos( TTO_ChainContextPos*  ccp,
-			      FT_Memory             memory );
-  /* query functions */
-
-  FT_Error  Coverage_Index( TTO_Coverage*  c,
-                            FT_UShort      glyphID,
-                            FT_UShort*     index );
-  FT_Error  Get_Class( TTO_ClassDefinition*  cd,
-                       FT_UShort             glyphID,
-                       FT_UShort*            class,
-                       FT_UShort*            index );
-  FT_Error  Get_Device( TTO_Device*  d,
-                        FT_UShort    size,
-                        FT_Short*    value );
-
-
-  /* functions from ftxgdef.c */
-
-  FT_Error  Add_Glyph_Property( TTO_GDEFHeader*  gdef,
-                                FT_UShort        glyphID,
-                                FT_UShort        property );
-
-  FT_Error  Check_Property( TTO_GDEFHeader*  gdef,
-                            OTL_GlyphItem    item,
-                            FT_UShort        flags,
-                            FT_UShort*       property );
-
-#define CHECK_Property( gdef, index, flags, property )              \
-          ( ( error = Check_Property( (gdef), (index), (flags),     \
-                                      (property) ) ) != TT_Err_Ok )
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FTXOPENF_H */
-
-
-/* END */
diff --git a/src/harfbuzz-buffer.c b/src/harfbuzz-buffer.c
new file mode 100644
index 0000000..3d233b4
--- /dev/null
+++ b/src/harfbuzz-buffer.c
@@ -0,0 +1,227 @@
+/* harfbuzz-buffer.c: Buffer of glyphs for substitution/positioning
+ *
+ * Copyright 2004 Red Hat Software
+ *
+ * Portions Copyright 1996-2000 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-buffer.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-gpos-private.h"
+
+static FT_Error
+hb_buffer_ensure( HB_Buffer buffer,
+		   FT_ULong   size )
+{
+  FT_Memory memory = buffer->memory;
+  FT_ULong new_allocated = buffer->allocated;
+
+  if (size > new_allocated)
+    {
+      FT_Error error;
+
+      while (size > new_allocated)
+	new_allocated += (new_allocated >> 1) + 8;
+      
+      if ( REALLOC_ARRAY( buffer->in_string, buffer->allocated, new_allocated, HB_GlyphItemRec ) )
+	return error;
+      if ( REALLOC_ARRAY( buffer->out_string, buffer->allocated, new_allocated, HB_GlyphItemRec ) )
+	return error;
+      if ( REALLOC_ARRAY( buffer->positions, buffer->allocated, new_allocated, HB_PositionRec ) )
+	return error;
+
+      buffer->allocated = new_allocated;
+    }
+
+  return FT_Err_Ok;
+}
+
+FT_Error
+hb_buffer_new( FT_Memory   memory,
+		HB_Buffer *buffer )
+{
+  FT_Error error;
+  
+  if ( ALLOC( *buffer, sizeof( HB_BufferRec ) ) )
+    return error;
+
+  (*buffer)->memory = memory;
+  (*buffer)->in_length = 0;
+  (*buffer)->out_length = 0;
+  (*buffer)->allocated = 0;
+  (*buffer)->in_pos = 0;
+  (*buffer)->out_pos = 0;
+
+  (*buffer)->in_string = NULL;
+  (*buffer)->out_string = NULL;
+  (*buffer)->positions = NULL;
+  (*buffer)->max_ligID = 0;
+
+  return FT_Err_Ok;
+}
+
+FT_Error
+hb_buffer_swap( HB_Buffer buffer )
+{
+  HB_GlyphItem tmp_string;
+
+  tmp_string = buffer->in_string;
+  buffer->in_string = buffer->out_string;
+  buffer->out_string = tmp_string;
+
+  buffer->in_length = buffer->out_length;
+  buffer->out_length = 0;
+  
+  buffer->in_pos = 0;
+  buffer->out_pos = 0;
+
+  return FT_Err_Ok;
+}
+
+FT_Error
+hb_buffer_free( HB_Buffer buffer )
+{
+  FT_Memory memory = buffer->memory;
+
+  FREE( buffer->in_string );
+  FREE( buffer->out_string );
+  FREE( buffer->positions );
+  FREE( buffer );
+
+  return FT_Err_Ok;
+}
+
+FT_Error
+hb_buffer_clear( HB_Buffer buffer )
+{
+  buffer->in_length = 0;
+  buffer->out_length = 0;
+  buffer->in_pos = 0;
+  buffer->out_pos = 0;
+  
+  return FT_Err_Ok;
+}
+
+FT_Error
+hb_buffer_add_glyph( HB_Buffer buffer,
+		      FT_UInt    glyph_index,
+		      FT_UInt    properties,
+		      FT_UInt    cluster )
+{
+  FT_Error error;
+  HB_GlyphItem glyph;
+  
+  error = hb_buffer_ensure( buffer, buffer->in_length + 1 );
+  if ( error )
+    return error;
+
+  glyph = &buffer->in_string[buffer->in_length];
+  glyph->gindex = glyph_index;
+  glyph->properties = properties;
+  glyph->cluster = cluster;
+  glyph->component = 0;
+  glyph->ligID = 0;
+  glyph->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN;
+  
+  buffer->in_length++;
+
+  return FT_Err_Ok;
+}
+
+/* The following function copies `num_out' elements from `glyph_data'
+   to `buffer->out_string', advancing the in array pointer in the structure
+   by `num_in' elements, and the out array pointer by `num_out' elements.
+   Finally, it sets the `length' field of `out' equal to
+   `pos' of the `out' structure.
+
+   If `component' is 0xFFFF, the component value from buffer->in_pos
+   will copied `num_out' times, otherwise `component' itself will
+   be used to fill the `component' fields.
+
+   If `ligID' is 0xFFFF, the ligID value from buffer->in_pos
+   will copied `num_out' times, otherwise `ligID' itself will
+   be used to fill the `ligID' fields.
+
+   The properties for all replacement glyphs are taken
+   from the glyph at position `buffer->in_pos'.
+
+   The cluster value for the glyph at position buffer->in_pos is used
+   for all replacement glyphs */
+FT_Error
+hb_buffer_add_output_glyphs( HB_Buffer buffer,
+			      FT_UShort  num_in,
+			      FT_UShort  num_out,
+			      FT_UShort *glyph_data,
+			      FT_UShort  component,
+			      FT_UShort  ligID )
+{
+  FT_Error  error;
+  FT_UShort i;
+  FT_UInt properties;
+  FT_UInt cluster;
+
+  error = hb_buffer_ensure( buffer, buffer->out_pos + num_out );
+  if ( error )
+    return error;
+
+  properties = buffer->in_string[buffer->in_pos].properties;
+  cluster = buffer->in_string[buffer->in_pos].cluster;
+  if ( component == 0xFFFF )
+    component = buffer->in_string[buffer->in_pos].component;
+  if ( ligID == 0xFFFF )
+    ligID = buffer->in_string[buffer->in_pos].ligID;
+
+  for ( i = 0; i < num_out; i++ )
+  {
+    HB_GlyphItem item = &buffer->out_string[buffer->out_pos + i];
+
+    item->gindex = glyph_data[i];
+    item->properties = properties;
+    item->cluster = cluster;
+    item->component = component;
+    item->ligID = ligID;
+    item->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN;
+  }
+
+  buffer->in_pos  += num_in;
+  buffer->out_pos += num_out;
+
+  buffer->out_length = buffer->out_pos;
+
+  return FT_Err_Ok;
+}
+
+FT_Error
+hb_buffer_add_output_glyph( HB_Buffer buffer,	
+			     FT_UInt    glyph_index,
+			     FT_UShort  component,
+			     FT_UShort  ligID )
+{
+  FT_UShort glyph_data =  glyph_index;
+
+  return hb_buffer_add_output_glyphs ( buffer, 1, 1,
+					&glyph_data, component, ligID );
+}
+
+FT_Error
+hb_buffer_copy_output_glyph ( HB_Buffer buffer )
+{  
+  FT_Error  error;
+
+  error = hb_buffer_ensure( buffer, buffer->out_pos + 1 );
+  if ( error )
+    return error;
+  
+  buffer->out_string[buffer->out_pos++] = buffer->in_string[buffer->in_pos++];
+  buffer->out_length = buffer->out_pos;
+
+  return FT_Err_Ok;
+}
+
+FT_UShort
+hb_buffer_allocate_ligid( HB_Buffer buffer )
+{
+  return buffer->max_ligID++;
+}
diff --git a/src/harfbuzz-buffer.h b/src/harfbuzz-buffer.h
new file mode 100644
index 0000000..c7478e3
--- /dev/null
+++ b/src/harfbuzz-buffer.h
@@ -0,0 +1,106 @@
+/* harfbuzz-buffer.h: Buffer of glyphs for substitution/positioning
+ *
+ * Copyrigh 2004 Red Hat Software
+ *
+ * Portions Copyright 1996-2000 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used
+ * modified and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ */
+#ifndef HARFBUZZ_BUFFER_H
+#define HARFBUZZ_BUFFER_H
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+FT_BEGIN_HEADER
+
+#define HB_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
+
+typedef struct HB_GlyphItemRec_ {
+  FT_UInt     gindex;
+  FT_UInt     properties;
+  FT_UInt     cluster;
+  FT_UShort   component;
+  FT_UShort   ligID;
+  FT_UShort   gproperties;
+} HB_GlyphItemRec, *HB_GlyphItem;
+
+typedef struct HB_PositionRec_ {
+  FT_Pos     x_pos;
+  FT_Pos     y_pos;
+  FT_Pos     x_advance;
+  FT_Pos     y_advance;
+  FT_UShort  back;            /* number of glyphs to go back
+				 for drawing current glyph   */
+  FT_Bool    new_advance;     /* if set, the advance width values are
+				 absolute, i.e., they won't be
+				 added to the original glyph's value
+				 but rather replace them.            */
+  FT_Short  cursive_chain;   /* character to which this connects,
+				 may be positive or negative; used
+				 only internally                     */
+} HB_PositionRec, *HB_Position;
+
+
+typedef struct HB_BufferRec_{ 
+  FT_Memory   memory;
+  FT_ULong    allocated;
+
+  FT_ULong    in_length;
+  FT_ULong    out_length;
+  FT_ULong    in_pos;
+  FT_ULong    out_pos;
+  
+  HB_GlyphItem  in_string;
+  HB_GlyphItem  out_string;
+  HB_Position   positions;
+  FT_UShort      max_ligID;
+} HB_BufferRec, *HB_Buffer;
+
+FT_Error
+hb_buffer_new( FT_Memory   memory,
+		HB_Buffer *buffer );
+
+FT_Error
+hb_buffer_swap( HB_Buffer buffer );
+
+FT_Error
+hb_buffer_free( HB_Buffer buffer );
+
+FT_Error
+hb_buffer_clear( HB_Buffer buffer );
+
+FT_Error
+hb_buffer_add_glyph( HB_Buffer buffer,
+		      FT_UInt    glyph_index,
+		      FT_UInt    properties,
+		      FT_UInt    cluster );
+
+FT_Error
+hb_buffer_add_output_glyphs( HB_Buffer buffer,
+			      FT_UShort  num_in,
+			      FT_UShort  num_out,
+			      FT_UShort *glyph_data,
+			      FT_UShort  component,
+			      FT_UShort  ligID );
+
+FT_Error
+hb_buffer_add_output_glyph ( HB_Buffer buffer,
+			      FT_UInt    glyph_index,
+			      FT_UShort  component,
+			      FT_UShort  ligID );
+
+FT_Error
+hb_buffer_copy_output_glyph ( HB_Buffer buffer );
+
+FT_UShort
+hb_buffer_allocate_ligid( HB_Buffer buffer );
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_BUFFER_H */
diff --git a/src/ottest.c b/src/harfbuzz-dump-main.c
similarity index 72%
rename from src/ottest.c
rename to src/harfbuzz-dump-main.c
index b0f4fd6..81fecf4 100644
--- a/src/ottest.c
+++ b/src/harfbuzz-dump-main.c
@@ -1,5 +1,4 @@
-/* Pango
- * otttest.c: Test program for OpenType
+/* harfbuzz-dump-main.c: Test program for OpenType
  *
  * Copyright (C) 2000 Red Hat Software
  *
@@ -19,13 +18,12 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "ftxopen.h"
+#include "harfbuzz-open.h"
 
-#include "disasm.h"
+#include "harfbuzz-dump.h"
 
 #define N_ELEMENTS(arr) (sizeof(arr)/ sizeof((arr)[0]))
 
@@ -56,7 +54,7 @@
 }
 
 static void
-maybe_add_feature (TTO_GSUB  gsub,
+maybe_add_feature (HB_GSUB  gsub,
 		   FT_UShort script_index,
 		   FT_ULong  tag,
 		   FT_UShort property)
@@ -65,22 +63,22 @@
   FT_UShort feature_index;
   
   /* 0xffff == default language system */
-  error = TT_GSUB_Select_Feature (gsub, tag, script_index, 0xffff, &feature_index);
+  error = HB_GSUB_Select_Feature (gsub, tag, script_index, 0xffff, &feature_index);
   
   if (error)
     {
-      if (error == TTO_Err_Not_Covered)
+      if (error == HB_Err_Not_Covered)
 	{
 	  print_tag (tag);
 	  fprintf (stderr, " not covered, ignored\n");
 	  return;
 	}
 
-      croak ("TT_GSUB_Select_Feature", error);
+      croak ("HB_GSUB_Select_Feature", error);
     }
 
-  if ((error = TT_GSUB_Add_Feature (gsub, feature_index, property)))
-    croak ("TT_GSUB_Add_Feature", error);
+  if ((error = HB_GSUB_Add_Feature (gsub, feature_index, property)))
+    croak ("HB_GSUB_Add_Feature", error);
 }
 
 static void
@@ -122,23 +120,23 @@
 }
 
 static void
-add_features (TTO_GSUB gsub)
+add_features (HB_GSUB gsub)
 {
   FT_Error error;
   FT_ULong tag = FT_MAKE_TAG ('a', 'r', 'a', 'b');
   FT_UShort script_index;
 
-  error = TT_GSUB_Select_Script (gsub, tag, &script_index);
+  error = HB_GSUB_Select_Script (gsub, tag, &script_index);
 
   if (error)
     {
-      if (error == TTO_Err_Not_Covered)
+      if (error == HB_Err_Not_Covered)
 	{
 	  fprintf (stderr, "Arabic not covered, no features used\n");
 	  return;
 	}
 
-      croak ("TT_GSUB_Select_Script", error);
+      croak ("HB_GSUB_Select_Script", error);
     }
 
   maybe_add_feature (gsub, script_index, FT_MAKE_TAG ('i', 'n', 'i', 't'), I);
@@ -150,7 +148,7 @@
 
 #if 0
 void 
-dump_string (TTO_GSUB_String *str)
+dump_string (HB_GSUB_String *str)
 {
   FT_ULong i;
 
@@ -173,20 +171,20 @@
 void
 try_string (FT_Library library,
 	    FT_Face    face,
-	    TTO_GSUB   gsub)
+	    HB_GSUB   gsub)
 {
   FT_Error error;
-  TTO_GSUB_String *in_str;
-  TTO_GSUB_String *out_str;
+  HB_GSUB_String *in_str;
+  HB_GSUB_String *out_str;
   FT_ULong i;
 
-  if ((error = TT_GSUB_String_New (face->memory, &in_str)))
-    croak ("TT_GSUB_String_New", error);
-  if ((error = TT_GSUB_String_New (face->memory, &out_str)))
-    croak ("TT_GSUB_String_New", error);
+  if ((error = HB_GSUB_String_New (face->memory, &in_str)))
+    croak ("HB_GSUB_String_New", error);
+  if ((error = HB_GSUB_String_New (face->memory, &out_str)))
+    croak ("HB_GSUB_String_New", error);
 
-  if ((error = TT_GSUB_String_Set_Length (in_str, N_ELEMENTS (arabic_str))))
-    croak ("TT_GSUB_String_Set_Length", error);
+  if ((error = HB_GSUB_String_Set_Length (in_str, N_ELEMENTS (arabic_str))))
+    croak ("HB_GSUB_String_Set_Length", error);
 
   for (i=0; i < N_ELEMENTS (arabic_str); i++)
     {
@@ -196,16 +194,16 @@
       in_str->ligIDs[i] = i;
     }
 
-  if ((error = TT_GSUB_Apply_String (gsub, in_str, out_str)))
-    croak ("TT_GSUB_Apply_String", error);
+  if ((error = HB_GSUB_Apply_String (gsub, in_str, out_str)))
+    croak ("HB_GSUB_Apply_String", error);
 
   dump_string (in_str);
   dump_string (out_str);
 
-  if ((error = TT_GSUB_String_Done (in_str)))
-    croak ("TT_GSUB_String_New", error);
-  if ((error = TT_GSUB_String_Done (out_str)))
-    croak ("TT_GSUB_String_New", error);
+  if ((error = HB_GSUB_String_Done (in_str)))
+    croak ("HB_GSUB_String_New", error);
+  if ((error = HB_GSUB_String_Done (out_str)))
+    croak ("HB_GSUB_String_New", error);
 }
 #endif
 
@@ -215,8 +213,8 @@
   FT_Error error;
   FT_Library library;
   FT_Face face;
-  TTO_GSUB gsub;
-  TTO_GPOS gpos;
+  HB_GSUB gsub;
+  HB_GPOS gpos;
 
   if (argc != 2)
     {
@@ -233,25 +231,25 @@
   printf ("<?xml version=\"1.0\"?>\n");
   printf ("<OpenType>\n");
 
-  if (!(error = TT_Load_GSUB_Table (face, &gsub, NULL)))
+  if (!(error = HB_Load_GSUB_Table (face, &gsub, NULL)))
     {
-      TT_Dump_GSUB_Table (gsub, stdout);
+      HB_Dump_GSUB_Table (gsub, stdout);
       
-      if ((error = TT_Done_GSUB_Table (gsub)))
-	croak ("FT_Done_GSUB_Table", error);
+      if ((error = HB_Done_GSUB_Table (gsub)))
+	croak ("HB_Done_GSUB_Table", error);
     }
   else if (error != FT_Err_Table_Missing)
-    fprintf (stderr, "TT_Load_GSUB_Table %x\n", error);
+    fprintf (stderr, "HB_Load_GSUB_Table %x\n", error);
 
-  if (!(error = TT_Load_GPOS_Table (face, &gpos, NULL)))
+  if (!(error = HB_Load_GPOS_Table (face, &gpos, NULL)))
     {
-      TT_Dump_GPOS_Table (gpos, stdout);
+      HB_Dump_GPOS_Table (gpos, stdout);
       
-      if ((error = TT_Done_GPOS_Table (gpos)))
-	croak ("FT_Done_GPOS_Table", error);
+      if ((error = HB_Done_GPOS_Table (gpos)))
+	croak ("HB_Done_GPOS_Table", error);
     }
   else if (error != FT_Err_Table_Missing)
-    fprintf (stderr, "TT_Load_GPOS_Table %x\n", error);
+    fprintf (stderr, "HB_Load_GPOS_Table %x\n", error);
 
   printf ("</OpenType>\n");
 
diff --git a/src/disasm.c b/src/harfbuzz-dump.c
similarity index 74%
rename from src/disasm.c
rename to src/harfbuzz-dump.c
index 50a0720..0500ff5 100644
--- a/src/disasm.c
+++ b/src/harfbuzz-dump.c
@@ -1,5 +1,4 @@
-/* Pango
- * disasm.c: Dump OpenType layout tables
+/* harfbuzz-dump.c: Dump OpenType layout tables
  *
  * Copyright (C) 2000 Red Hat Software
  *
@@ -19,28 +18,29 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include <config.h>
-
-#include <glib.h>		/* For G_HAVE_ISO_VARARGS */
+#include "harfbuzz-impl.h"
+#include "harfbuzz-dump.h"
+#include "harfbuzz-gdef-private.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-gpos-private.h"
+#include "harfbuzz-open-private.h"
 #include <stdarg.h>
 
-#include "disasm.h"
+#define DUMP(format) dump (stream, indent, format)
+#define DUMP1(format, arg1) dump (stream, indent, format, arg1)
+#define DUMP2(format, arg1, arg2) dump (stream, indent, format, arg1, arg2)
+#define DUMP3(format, arg1, arg2, arg3) dump (stream, indent, format, arg1, arg2, arg3)
 
-#ifdef G_HAVE_ISO_VARARGS
-#define DUMP(...) dump (stream, indent, __VA_ARGS__)
-#elif defined (G_HAVE_GNUC_VARARGS)
-#define DUMP(args...) dump (stream, indent, args)
-#endif
 #define DUMP_FINT(strct,fld) dump (stream, indent, "<" #fld ">%d</" #fld ">\n", (strct)->fld)
 #define DUMP_FUINT(strct,fld) dump (stream, indent, "<" #fld ">%u</" #fld ">\n", (strct)->fld)
 #define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x</" #fld ">\n", (strct)->fld)
 #define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x</" #fld ">\n", (strct)->fld)
 #define DUMP_USHORT_ARRAY(strct,fld,cnt) Dump_UShort_Array ((strct)->fld, cnt, #fld, stream, indent);
 
-#define DEF_DUMP(type) static void Dump_ ## type (TTO_ ## type *type, FILE *stream, int indent, FT_Bool G_GNUC_UNUSED is_gsub)
-#define RECURSE(name, type, val) do {  DUMP ("<" #name ">\n"); Dump_ ## type (val, stream, indent + 1, is_gsub); DUMP ("</" #name ">\n"); } while (0)
-#define RECURSE_NUM(name, i, type, val) do {  DUMP ("<" #name "> <!-- %d -->\n", i); Dump_ ## type (val, stream, indent + 1, is_gsub); DUMP ("</" #name ">\n"); } while (0)
-#define DUMP_VALUE_RECORD(val, frmt) do {  DUMP ("<ValueRecord>\n"); Dump_ValueRecord (val, stream, indent + 1, is_gsub, frmt); DUMP ("</ValueRecord>\n"); } while (0)
+#define DEF_DUMP(type) static void Dump_ ## type (HB_ ## type *type, FILE *stream, int indent, HB_Type hb_type)
+#define RECURSE(name, type, val) do {  DUMP ("<" #name ">\n"); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("</" #name ">\n"); } while (0)
+#define RECURSE_NUM(name, i, type, val) do {  DUMP1 ("<" #name "> <!-- %d -->\n", i); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("</" #name ">\n"); } while (0)
+#define DUMP_VALUE_RECORD(val, frmt) do {  DUMP ("<ValueRecord>\n"); Dump_ValueRecord (val, stream, indent + 1, hb_type, frmt); DUMP ("</ValueRecord>\n"); } while (0)
 
 static void
 do_indent (FILE *stream, int indent)
@@ -92,7 +92,7 @@
   DUMP_FUINT (LangSys, FeatureCount);
 
   for (i=0; i < LangSys->FeatureCount; i++)
-    DUMP("<FeatureIndex>%d</FeatureIndex>\n", LangSys->FeatureIndex[i]);
+    DUMP1("<FeatureIndex>%d</FeatureIndex>\n", LangSys->FeatureIndex[i]);
 }
 
 DEF_DUMP (Script)
@@ -137,13 +137,13 @@
   DUMP_FUINT (Feature, LookupListCount);
 
   for (i=0; i < Feature->LookupListCount; i++)
-    DUMP("<LookupIndex>%d</LookupIndex>\n", Feature->LookupListIndex[i]);
+    DUMP1("<LookupIndex>%d</LookupIndex>\n", Feature->LookupListIndex[i]);
 }
 
 DEF_DUMP (MarkRecord)
 {
   DUMP_FUINT (MarkRecord, Class);
-  DUMP("<Anchor>%d</Anchor>\n", MarkRecord->MarkAnchor.PosFormat );
+  DUMP1("<Anchor>%d</Anchor>\n", MarkRecord->MarkAnchor.PosFormat );
 }
 
 DEF_DUMP (MarkArray)
@@ -182,8 +182,8 @@
       DUMP_FUINT (&Coverage->cf.cf1, GlyphCount);
 
       for (i = 0; i < Coverage->cf.cf1.GlyphCount; i++)
-	DUMP("<Glyph>%#06x</Glyph> <!-- %d -->\n",
-	     Coverage->cf.cf1.GlyphArray[i], i);
+	DUMP2("<Glyph>%#06x</Glyph> <!-- %d -->\n",
+	      Coverage->cf.cf1.GlyphArray[i], i);
     }
   else
     {
@@ -191,9 +191,9 @@
       DUMP_FUINT (&Coverage->cf.cf2, RangeCount);
       
       for ( i = 0; i < Coverage->cf.cf2.RangeCount; i++ )
-	  DUMP("<Glyph>%#06x - %#06x</Glyph> <!-- %d -->\n",
-	       Coverage->cf.cf2.RangeRecord[i].Start,
-	       Coverage->cf.cf2.RangeRecord[i].End);
+	  DUMP3("<Glyph>%#06x - %#06x</Glyph> <!-- %d -->\n",
+	        Coverage->cf.cf2.RangeRecord[i].Start,
+	        Coverage->cf.cf2.RangeRecord[i].End, i);
     }
 }
 
@@ -212,18 +212,18 @@
   if (ClassDefinition->ClassFormat == 1)
     {
       int i;
-      TTO_ClassDefFormat1 *ClassDefFormat1 = &ClassDefinition->cd.cd1;
+      HB_ClassDefFormat1 *ClassDefFormat1 = &ClassDefinition->cd.cd1;
       DUMP("<ClassDefinition>\n");
       DUMP_FUINT (ClassDefFormat1, StartGlyph );
       DUMP_FUINT (ClassDefFormat1, GlyphCount );
       for (i = 0; i < ClassDefFormat1->GlyphCount; i++)
-	DUMP(" <Class>%d</Class> <!-- %#06x -->", ClassDefFormat1->ClassValueArray[i],
-	     ClassDefFormat1->StartGlyph+i );
+	DUMP2(" <Class>%d</Class> <!-- %#06x -->", ClassDefFormat1->ClassValueArray[i],
+	      ClassDefFormat1->StartGlyph+i );
     }
   else if (ClassDefinition->ClassFormat == 2)
     {
       int i;
-      TTO_ClassDefFormat2 *ClassDefFormat2 = &ClassDefinition->cd.cd2;
+      HB_ClassDefFormat2 *ClassDefFormat2 = &ClassDefinition->cd.cd2;
       DUMP_FUINT (ClassDefFormat2, ClassRangeCount);
       
       for (i = 0; i < ClassDefFormat2->ClassRangeCount; i++)
@@ -263,9 +263,9 @@
 }
 
 static void
-Dump_GSUB_Lookup_Single (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_GSUB_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
 {
-  TTO_SingleSubst *SingleSubst = &subtable->st.gsub.single;
+  HB_SingleSubst *SingleSubst = &subtable->st.gsub.single;
 
   DUMP_FUINT (SingleSubst, SubstFormat);
   RECURSE (Coverage, Coverage, &SingleSubst->Coverage);
@@ -280,7 +280,7 @@
       
       DUMP_FINT (&SingleSubst->ssf.ssf2, GlyphCount);
       for (i=0; i < SingleSubst->ssf.ssf2.GlyphCount; i++)
-	DUMP("<Substitute>%#06x</Substitute> <!-- %d -->\n", SingleSubst->ssf.ssf2.Substitute[i], i);
+	DUMP2("<Substitute>%#06x</Substitute> <!-- %d -->\n", SingleSubst->ssf.ssf2.Substitute[i], i);
     }
 }
 
@@ -292,7 +292,7 @@
   DUMP_FUINT (Ligature, ComponentCount);
 
   for (i=0; i < Ligature->ComponentCount - 1; i++)
-    DUMP("<Component>%#06x</Component>\n", Ligature->Component[i]);
+    DUMP1("<Component>%#06x</Component>\n", Ligature->Component[i]);
 }
 
 DEF_DUMP (LigatureSet)
@@ -306,10 +306,10 @@
 }
 
 static void
-Dump_GSUB_Lookup_Ligature (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_GSUB_Lookup_Ligature (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
 {
   int i;
-  TTO_LigatureSubst *LigatureSubst = &subtable->st.gsub.ligature;
+  HB_LigatureSubst *LigatureSubst = &subtable->st.gsub.ligature;
 
   DUMP_FUINT (LigatureSubst, SubstFormat);
   RECURSE (Coverage, Coverage, &LigatureSubst->Coverage);
@@ -338,21 +338,21 @@
 }
 
 static void
-Dump_GSUB_Lookup_Context (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_GSUB_Lookup_Context (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
 {
-  TTO_ContextSubst *ContextSubst = &subtable->st.gsub.context;
+  HB_ContextSubst *ContextSubst = &subtable->st.gsub.context;
 
   DUMP_FUINT (ContextSubst, SubstFormat);
   switch( ContextSubst->SubstFormat )
     {
     case 1:
-      Dump_ContextSubstFormat1 (&ContextSubst->csf.csf1, stream, indent+2, is_gsub);
+      Dump_ContextSubstFormat1 (&ContextSubst->csf.csf1, stream, indent+2, hb_type);
       break;
     case 2:
-      Dump_ContextSubstFormat2 (&ContextSubst->csf.csf2, stream, indent+2, is_gsub);
+      Dump_ContextSubstFormat2 (&ContextSubst->csf.csf2, stream, indent+2, hb_type);
       break;
     case 3:
-      Dump_ContextSubstFormat3 (&ContextSubst->csf.csf3, stream, indent+2, is_gsub);
+      Dump_ContextSubstFormat3 (&ContextSubst->csf.csf3, stream, indent+2, hb_type);
       break;
     default:
       fprintf(stderr, "invalid subformat!!!!!\n");
@@ -401,21 +401,21 @@
 }
 
 static void
-Dump_GSUB_Lookup_Chain (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_GSUB_Lookup_Chain (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
 {
-  TTO_ChainContextSubst *chain = &subtable->st.gsub.chain;
+  HB_ChainContextSubst *chain = &subtable->st.gsub.chain;
   
   DUMP_FUINT (chain, SubstFormat);
   switch (chain->SubstFormat)
     {
     case 1:
-      Dump_ChainContextSubstFormat1 (&chain->ccsf.ccsf1, stream, indent+2, is_gsub);
+      Dump_ChainContextSubstFormat1 (&chain->ccsf.ccsf1, stream, indent+2, hb_type);
       break;
     case 2:
-      Dump_ChainContextSubstFormat2 (&chain->ccsf.ccsf2, stream, indent+2, is_gsub);
+      Dump_ChainContextSubstFormat2 (&chain->ccsf.ccsf2, stream, indent+2, hb_type);
       break;
     case 3:
-      Dump_ChainContextSubstFormat3 (&chain->ccsf.ccsf3, stream, indent+2, is_gsub);
+      Dump_ChainContextSubstFormat3 (&chain->ccsf.ccsf3, stream, indent+2, hb_type);
       break;
     default:
       fprintf(stderr, "invalid subformat!!!!!\n");
@@ -423,7 +423,7 @@
 }
 
 static void
-Dump_Device (TTO_Device *Device, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_Device (HB_Device *Device, FILE *stream, int indent, HB_Type hb_type)
 {
   int i;
   int bits = 0;
@@ -471,38 +471,38 @@
 }
      
 static void
-Dump_ValueRecord (TTO_ValueRecord *ValueRecord, FILE *stream, int indent, FT_Bool is_gsub, FT_UShort value_format)
+Dump_ValueRecord (HB_ValueRecord *ValueRecord, FILE *stream, int indent, HB_Type hb_type, FT_UShort value_format)
 {
-  if (value_format & HAVE_X_PLACEMENT)
+  if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT)
     DUMP_FINT (ValueRecord, XPlacement);
-  if (value_format & HAVE_Y_PLACEMENT)
+  if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT)
     DUMP_FINT (ValueRecord, YPlacement);
-  if (value_format & HAVE_X_ADVANCE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE)
     DUMP_FINT (ValueRecord, XAdvance);
-  if (value_format & HAVE_Y_ADVANCE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE)
     DUMP_FINT (ValueRecord, XAdvance);
-  if (value_format & HAVE_X_PLACEMENT_DEVICE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE)
     RECURSE (Device, Device, &ValueRecord->XPlacementDevice);
-  if (value_format & HAVE_Y_PLACEMENT_DEVICE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE)
     RECURSE (Device, Device, &ValueRecord->YPlacementDevice);
-  if (value_format & HAVE_X_ADVANCE_DEVICE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE)
     RECURSE (Device, Device, &ValueRecord->XAdvanceDevice);
-  if (value_format & HAVE_Y_ADVANCE_DEVICE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE)
     RECURSE (Device, Device, &ValueRecord->YAdvanceDevice);
-  if (value_format & HAVE_X_ID_PLACEMENT)
+  if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT)
     DUMP_FUINT (ValueRecord, XIdPlacement);
-  if (value_format & HAVE_Y_ID_PLACEMENT)
+  if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT)
     DUMP_FUINT (ValueRecord, YIdPlacement);
-  if (value_format & HAVE_X_ID_ADVANCE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE)
     DUMP_FUINT (ValueRecord, XIdAdvance);
-  if (value_format & HAVE_Y_ID_ADVANCE)
+  if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE)
     DUMP_FUINT (ValueRecord, XIdAdvance);
 }
 
 static void
-Dump_GPOS_Lookup_Single (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_GPOS_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
 {
-  TTO_SinglePos *SinglePos = &subtable->st.gpos.single;
+  HB_SinglePos *SinglePos = &subtable->st.gpos.single;
 
   DUMP_FUINT (SinglePos, PosFormat);
   RECURSE (Coverage, Coverage, &SinglePos->Coverage);
@@ -524,7 +524,7 @@
 }
 
 static void
-Dump_PairValueRecord (TTO_PairValueRecord *PairValueRecord, FILE *stream, int indent, FT_Bool is_gsub, FT_UShort ValueFormat1, FT_UShort ValueFormat2)
+Dump_PairValueRecord (HB_PairValueRecord *PairValueRecord, FILE *stream, int indent, HB_Type hb_type, FT_UShort ValueFormat1, FT_UShort ValueFormat2)
 {
   DUMP_FUINT (PairValueRecord, SecondGlyph);
   DUMP_VALUE_RECORD (&PairValueRecord->Value1, ValueFormat1);
@@ -532,7 +532,7 @@
 }
 
 static void
-Dump_PairSet (TTO_PairSet *PairSet, FILE *stream, int indent, FT_Bool is_gsub, FT_UShort ValueFormat1, FT_UShort ValueFormat2)
+Dump_PairSet (HB_PairSet *PairSet, FILE *stream, int indent, HB_Type hb_type, FT_UShort ValueFormat1, FT_UShort ValueFormat2)
 {
   int i;
   DUMP_FUINT (PairSet, PairValueCount);
@@ -540,15 +540,15 @@
   for (i = 0; i < PairSet->PairValueCount; i++)
     {
       DUMP ("<PairValueRecord>\n");
-      Dump_PairValueRecord (&PairSet->PairValueRecord[i], stream, indent + 1, is_gsub, ValueFormat1, ValueFormat2);
+      Dump_PairValueRecord (&PairSet->PairValueRecord[i], stream, indent + 1, hb_type, ValueFormat1, ValueFormat2);
       DUMP ("</PairValueRecord>\n");
     }
 }
 
 static void
-Dump_GPOS_Lookup_Pair (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_GPOS_Lookup_Pair (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
 {
-  TTO_PairPos *PairPos = &subtable->st.gpos.pair;
+  HB_PairPos *PairPos = &subtable->st.gpos.pair;
 
   DUMP_FUINT (PairPos, PosFormat);
   RECURSE (Coverage, Coverage, &PairPos->Coverage);
@@ -564,7 +564,7 @@
       for (i = 0; i < PairPos->ppf.ppf1.PairSetCount; i++)
 	{
 	  DUMP ("<PairSet>\n");
-	  Dump_PairSet (&PairPos->ppf.ppf1.PairSet[i], stream, indent + 1, is_gsub, PairPos->ValueFormat1, PairPos->ValueFormat2);
+	  Dump_PairSet (&PairPos->ppf.ppf1.PairSet[i], stream, indent + 1, hb_type, PairPos->ValueFormat1, PairPos->ValueFormat2);
 	  DUMP ("</PairSet>\n");
 	}
     }
@@ -574,10 +574,10 @@
 }
 
 static void
-Dump_GPOS_Lookup_Markbase (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub)
+Dump_GPOS_Lookup_Markbase (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
 {
   int i;
-  TTO_MarkBasePos *markbase = &subtable->st.gpos.markbase;
+  HB_MarkBasePos *markbase = &subtable->st.gpos.markbase;
   
   DUMP_FUINT (markbase, PosFormat);
   RECURSE (Coverage, Coverage, &markbase->MarkCoverage);
@@ -592,10 +592,10 @@
   for (i = 0; i < markbase->BaseArray.BaseCount; i++)
     {
       int j;
-      TTO_BaseRecord *r = &markbase->BaseArray.BaseRecord[i];
-      DUMP ("<BaseRecord> <!-- %d -->\n",  i);
+      HB_BaseRecord *r = &markbase->BaseArray.BaseRecord[i];
+      DUMP1 ("<BaseRecord> <!-- %d -->\n",  i);
       for (j = 0; j < markbase->ClassCount; j++)
-	DUMP ("  <Anchor>%d</Anchor>\n", r->BaseAnchor->PosFormat);
+	DUMP1 ("  <Anchor>%d</Anchor>\n", r->BaseAnchor->PosFormat);
       DUMP ("<BaseRecord>\n");
     }
   
@@ -607,31 +607,31 @@
 {
   int i;
   const char *lookup_name = NULL;
-  void (*lookup_func) (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) = NULL;
+  void (*lookup_func) (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) = NULL;
 
-  if (is_gsub)
+  if (hb_type == HB_Type_GSUB)
     {
       switch (Lookup->LookupType)
 	{
-	case  GSUB_LOOKUP_SINGLE:
+	case  HB_GSUB_LOOKUP_SINGLE:
 	  lookup_name = "SINGLE";
 	  lookup_func = Dump_GSUB_Lookup_Single;
 	  break;
-	case  GSUB_LOOKUP_MULTIPLE:
+	case  HB_GSUB_LOOKUP_MULTIPLE:
 	  lookup_name = "MULTIPLE";
 	  break;
-	case  GSUB_LOOKUP_ALTERNATE:
+	case  HB_GSUB_LOOKUP_ALTERNATE:
 	  lookup_name = "ALTERNATE";
 	  break;
-	case  GSUB_LOOKUP_LIGATURE:
+	case  HB_GSUB_LOOKUP_LIGATURE:
 	  lookup_name = "LIGATURE";
 	  lookup_func = Dump_GSUB_Lookup_Ligature;
 	  break;
-	case  GSUB_LOOKUP_CONTEXT:
+	case  HB_GSUB_LOOKUP_CONTEXT:
 	  lookup_name = "CONTEXT";
 	  lookup_func = Dump_GSUB_Lookup_Context;
 	  break;
-	case  GSUB_LOOKUP_CHAIN:
+	case  HB_GSUB_LOOKUP_CHAIN:
 	  lookup_name = "CHAIN";
 	  lookup_func = Dump_GSUB_Lookup_Chain;
 	  break;
@@ -641,44 +641,44 @@
     {
       switch (Lookup->LookupType)
 	{
-	case GPOS_LOOKUP_SINGLE:
+	case HB_GPOS_LOOKUP_SINGLE:
 	  lookup_name = "SINGLE";
 	  lookup_func = Dump_GPOS_Lookup_Single;
 	  break;
-	case GPOS_LOOKUP_PAIR:
+	case HB_GPOS_LOOKUP_PAIR:
 	  lookup_name = "PAIR";
 	  lookup_func = Dump_GPOS_Lookup_Pair;
 	  break;
-	case GPOS_LOOKUP_CURSIVE:
+	case HB_GPOS_LOOKUP_CURSIVE:
 	  lookup_name = "CURSIVE";
 	  break;
-	case GPOS_LOOKUP_MARKBASE:
+	case HB_GPOS_LOOKUP_MARKBASE:
 	  lookup_name = "MARKBASE";
 	  lookup_func = Dump_GPOS_Lookup_Markbase;
 	  break;
-	case GPOS_LOOKUP_MARKLIG:
+	case HB_GPOS_LOOKUP_MARKLIG:
 	  lookup_name = "MARKLIG";
 	  break;
-	case GPOS_LOOKUP_MARKMARK:
+	case HB_GPOS_LOOKUP_MARKMARK:
 	  lookup_name = "MARKMARK";
 	  break;
-	case GPOS_LOOKUP_CONTEXT:
+	case HB_GPOS_LOOKUP_CONTEXT:
 	  lookup_name = "CONTEXT";
 	  break;
-	case GPOS_LOOKUP_CHAIN:
+	case HB_GPOS_LOOKUP_CHAIN:
 	  lookup_name = "CHAIN";
 	  break;
 	}
     }
 
-  DUMP("<LookupType>%s</LookupType> <!-- %d -->\n", lookup_name, Lookup->LookupType);
-  DUMP("<LookupFlag>%#06x</LookupFlag>\n", Lookup->LookupFlag);
+  DUMP2("<LookupType>%s</LookupType> <!-- %d -->\n", lookup_name, Lookup->LookupType);
+  DUMP1("<LookupFlag>%#06x</LookupFlag>\n", Lookup->LookupFlag);
 
   for (i=0; i < Lookup->SubTableCount; i++)
     {
       DUMP ("<Subtable>\n");
       if (lookup_func)
-	(*lookup_func) (&Lookup->SubTable[i], stream, indent + 1, is_gsub);
+	(*lookup_func) (&Lookup->SubTable[i], stream, indent + 1, hb_type);
       DUMP ("</Subtable>\n");
     }
 }
@@ -694,10 +694,10 @@
 }
 
 void
-TT_Dump_GSUB_Table (TTO_GSUB gsub, FILE *stream)
+HB_Dump_GSUB_Table (HB_GSUB gsub, FILE *stream)
 {
   int indent = 1;
-  FT_Bool is_gsub = 1;
+  HB_Type hb_type = HB_Type_GSUB;
 
   do_indent (stream, indent);
   fprintf(stream, "<!-- GSUB -->\n");
@@ -707,10 +707,10 @@
 }
 
 void
-TT_Dump_GPOS_Table (TTO_GPOS gpos, FILE *stream)
+HB_Dump_GPOS_Table (HB_GPOS gpos, FILE *stream)
 {
   int indent = 1;
-  FT_Bool is_gsub = 0;
+  HB_Type hb_type = HB_Type_GPOS;
 
   do_indent (stream, indent);
   fprintf(stream, "<!-- GPOS -->\n");
diff --git a/src/disasm.h b/src/harfbuzz-dump.h
similarity index 71%
rename from src/disasm.h
rename to src/harfbuzz-dump.h
index e7556d4..c41ca68 100644
--- a/src/disasm.h
+++ b/src/harfbuzz-dump.h
@@ -1,5 +1,4 @@
-/* Pango
- * disasm.h: Dump OpenType layout tables
+/* harfbuzz-dump.h: Dump OpenType layout tables
  *
  * Copyright (C) 2000 Red Hat Software
  *
@@ -18,9 +17,18 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+#ifndef HARFBUZZ_DUMP_H
+#define HARFBUZZ_DUMP_H
 
 #include <stdio.h>
-#include "ftxopen.h"
+#include "harfbuzz-gsub.h"
+#include "harfbuzz-gpos.h"
 
-void TT_Dump_GSUB_Table (TTO_GSUB gsub, FILE *stream);
-void TT_Dump_GPOS_Table (TTO_GPOS gpos, FILE *stream);
+FT_BEGIN_HEADER
+
+void HB_Dump_GSUB_Table (HB_GSUB gsub, FILE *stream);
+void HB_Dump_GPOS_Table (HB_GPOS gpos, FILE *stream);
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_DUMP_H */
diff --git a/src/harfbuzz-gdef-private.h b/src/harfbuzz-gdef-private.h
new file mode 100644
index 0000000..e07e236
--- /dev/null
+++ b/src/harfbuzz-gdef-private.h
@@ -0,0 +1,101 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_GDEF_PRIVATE_H
+#define HARFBUZZ_GDEF_PRIVATE_H
+
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-buffer.h"
+
+FT_BEGIN_HEADER
+
+
+/* Attachment related structures */
+
+struct  HB_AttachPoint_
+{
+  FT_UShort   PointCount;             /* size of the PointIndex array */
+  FT_UShort*  PointIndex;             /* array of contour points      */
+};
+
+/* Ligature Caret related structures */
+
+struct  HB_CaretValueFormat1_
+{
+  FT_Short  Coordinate;               /* x or y value (in design units) */
+};
+
+typedef struct HB_CaretValueFormat1_  HB_CaretValueFormat1;
+
+
+struct  HB_CaretValueFormat2_
+{
+  FT_UShort  CaretValuePoint;         /* contour point index on glyph */
+};
+
+typedef struct HB_CaretValueFormat2_  HB_CaretValueFormat2;
+
+
+struct  HB_CaretValueFormat3_
+{
+  FT_Short    Coordinate;             /* x or y value (in design units) */
+  HB_Device  Device;                 /* Device table for x or y value  */
+};
+
+typedef struct HB_CaretValueFormat3_  HB_CaretValueFormat3;
+
+
+struct  HB_CaretValueFormat4_
+{
+  FT_UShort  IdCaretValue;            /* metric ID */
+};
+
+typedef struct HB_CaretValueFormat4_  HB_CaretValueFormat4;
+
+
+struct  HB_CaretValue_
+{
+  FT_UShort  CaretValueFormat;        /* 1, 2, 3, or 4 */
+
+  union
+  {
+    HB_CaretValueFormat1  cvf1;
+    HB_CaretValueFormat2  cvf2;
+    HB_CaretValueFormat3  cvf3;
+    HB_CaretValueFormat4  cvf4;
+  } cvf;
+};
+
+typedef struct HB_CaretValue_  HB_CaretValue;
+
+
+struct  HB_LigGlyph_
+{
+  FT_Bool          loaded;
+
+  FT_UShort        CaretCount;        /* number of caret values */
+  HB_CaretValue*  CaretValue;        /* array of caret values  */
+};
+
+
+FT_Error  _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader*   gdef,
+				       FT_UShort        glyphID,
+				       FT_UShort        property );
+
+FT_Error  _HB_GDEF_Check_Property( HB_GDEFHeader*   gdef,
+				   HB_GlyphItem    item,
+				   FT_UShort        flags,
+				   FT_UShort*       property );
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_GDEF_PRIVATE_H */
diff --git a/src/harfbuzz-gdef.c b/src/harfbuzz-gdef.c
new file mode 100644
index 0000000..1564e88
--- /dev/null
+++ b/src/harfbuzz-gdef.c
@@ -0,0 +1,1228 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#include "harfbuzz-impl.h"
+#include "harfbuzz-gdef-private.h"
+#include "harfbuzz-open-private.h"
+
+#include FT_TRUETYPE_TAGS_H
+
+
+static FT_Error  Load_AttachList( HB_AttachList*  al,
+				  FT_Stream        stream );
+static FT_Error  Load_LigCaretList( HB_LigCaretList*  lcl,
+				    FT_Stream          stream );
+
+static void  Free_AttachList( HB_AttachList*  al,
+			      FT_Memory        memory );
+static void  Free_LigCaretList( HB_LigCaretList*  lcl,
+				FT_Memory          memory );
+
+static void  Free_NewGlyphClasses( HB_GDEFHeader*  gdef,
+				   FT_Memory        memory );
+
+
+
+/**********************
+ * Extension Functions
+ **********************/
+
+#if 0
+#define GDEF_ID  Build_Extension_ID( 'G', 'D', 'E', 'F' )
+
+
+static FT_Error  GDEF_Create( void*  ext,
+			      PFace  face )
+{
+  DEFINE_LOAD_LOCALS( face->stream );
+
+  HB_GDEFHeader*  gdef = (HB_GDEFHeader*)ext;
+  Long             table;
+
+
+  /* by convention */
+
+  if ( !gdef )
+    return FT_Err_Ok;
+
+  /* a null offset indicates that there is no GDEF table */
+
+  gdef->offset = 0;
+
+  /* we store the start offset and the size of the subtable */
+
+  table = HB_LookUp_Table( face, TTAG_GDEF );
+  if ( table < 0 )
+    return FT_Err_Ok;             /* The table is optional */
+
+  if ( FILE_Seek( face->dirTables[table].Offset ) ||
+       ACCESS_Frame( 4L ) )
+    return error;
+
+  gdef->offset  = FILE_Pos() - 4L;    /* undo ACCESS_Frame() */
+  gdef->Version = GET_ULong();
+
+  FORGET_Frame();
+
+  gdef->loaded = FALSE;
+
+  return FT_Err_Ok;
+}
+
+
+static FT_Error  GDEF_Destroy( void*  ext,
+			       PFace  face )
+{
+  HB_GDEFHeader*  gdef = (HB_GDEFHeader*)ext;
+
+
+  /* by convention */
+
+  if ( !gdef )
+    return FT_Err_Ok;
+
+  if ( gdef->loaded )
+  {
+    Free_LigCaretList( &gdef->LigCaretList, memory );
+    Free_AttachList( &gdef->AttachList, memory );
+    _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef, memory );
+    _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef, memory );
+
+    Free_NewGlyphClasses( gdef, memory );
+  }
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_Init_GDEF_Extension( HB_Engine  engine )
+{
+  PEngine_Instance  _engine = HANDLE_Engine( engine );
+
+
+  if ( !_engine )
+    return FT_Err_Invalid_Engine;
+
+  return  HB_Register_Extension( _engine,
+				 GDEF_ID,
+				 sizeof ( HB_GDEFHeader ),
+				 GDEF_Create,
+				 GDEF_Destroy );
+}
+#endif
+/* GDEF glyph classes */
+
+#define UNCLASSIFIED_GLYPH  0
+#define SIMPLE_GLYPH        1
+#define LIGATURE_GLYPH      2
+#define MARK_GLYPH          3
+#define COMPONENT_GLYPH     4
+
+
+
+
+
+
+FT_Error  HB_New_GDEF_Table( FT_Face          face,
+			     HB_GDEFHeader** retptr )
+{
+  FT_Error         error;
+  FT_Memory        memory = face->memory;
+
+  HB_GDEFHeader*  gdef;
+
+  if ( !retptr )
+    return FT_Err_Invalid_Argument;
+
+  if ( ALLOC( gdef, sizeof( *gdef ) ) )
+    return error;
+
+  gdef->memory = face->memory;
+
+  gdef->GlyphClassDef.loaded = FALSE;
+  gdef->AttachList.loaded = FALSE;
+  gdef->LigCaretList.loaded = FALSE;
+  gdef->MarkAttachClassDef_offset = 0;
+  gdef->MarkAttachClassDef.loaded = FALSE;
+
+  gdef->LastGlyph = 0;
+  gdef->NewGlyphClasses = NULL;
+
+  *retptr = gdef;
+
+  return FT_Err_Ok;
+}
+
+
+FT_Error  HB_Load_GDEF_Table( FT_Face          face,
+			      HB_GDEFHeader** retptr )
+{
+  FT_Error         error;
+  FT_Memory        memory = face->memory;
+  FT_Stream        stream = face->stream;
+  FT_ULong         cur_offset, new_offset, base_offset;
+
+  HB_GDEFHeader*  gdef;
+
+
+  if ( !retptr )
+    return FT_Err_Invalid_Argument;
+
+  if (( error = _hb_ftglue_face_goto_table( face, TTAG_GDEF, stream ) ))
+    return error;
+
+  if (( error = HB_New_GDEF_Table ( face, &gdef ) ))
+    return error;
+
+  base_offset = FILE_Pos();
+
+  /* skip version */
+
+  if ( FILE_Seek( base_offset + 4L ) ||
+       ACCESS_Frame( 2L ) )
+    goto Fail0;
+
+  new_offset = GET_UShort();
+
+  FORGET_Frame();
+
+  /* all GDEF subtables are optional */
+
+  if ( new_offset )
+  {
+    new_offset += base_offset;
+
+    /* only classes 1-4 are allowed here */
+
+    cur_offset = FILE_Pos();
+    if ( FILE_Seek( new_offset ) ||
+	 ( error = _HB_OPEN_Load_ClassDefinition( &gdef->GlyphClassDef, 5,
+					 stream ) ) != FT_Err_Ok )
+      goto Fail0;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  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 = Load_AttachList( &gdef->AttachList,
+				    stream ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  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 = Load_LigCaretList( &gdef->LigCaretList,
+				      stream ) ) != FT_Err_Ok )
+      goto Fail2;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  /* OpenType 1.2 has introduced the `MarkAttachClassDef' field.  We
+     first have to scan the LookupFlag values to find out whether we
+     must load it or not.  Here we only store the offset of the table. */
+
+  if ( ACCESS_Frame( 2L ) )
+    goto Fail3;
+
+  new_offset = GET_UShort();
+
+  FORGET_Frame();
+
+  if ( new_offset )
+    gdef->MarkAttachClassDef_offset = new_offset + base_offset;
+  else
+    gdef->MarkAttachClassDef_offset = 0;
+
+  *retptr = gdef;
+
+  return FT_Err_Ok;
+
+Fail3:
+  Free_LigCaretList( &gdef->LigCaretList, memory );
+  
+Fail2:
+  Free_AttachList( &gdef->AttachList, memory );
+
+Fail1:
+  _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef, memory );
+
+Fail0:
+  FREE( gdef );
+
+  return error;
+}
+
+
+FT_Error  HB_Done_GDEF_Table ( HB_GDEFHeader* gdef ) 
+{
+  FT_Memory memory = gdef->memory;
+  
+  Free_LigCaretList( &gdef->LigCaretList, memory );
+  Free_AttachList( &gdef->AttachList, memory );
+  _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef, memory );
+  _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef, memory );
+  
+  Free_NewGlyphClasses( gdef, memory );
+
+  FREE( gdef );
+
+  return FT_Err_Ok;
+}
+
+
+
+
+/*******************************
+ * AttachList related functions
+ *******************************/
+
+
+/* AttachPoint */
+
+static FT_Error  Load_AttachPoint( HB_AttachPoint*  ap,
+				   FT_Stream         stream )
+{
+  FT_Memory memory = stream->memory;
+  FT_Error  error;
+
+  FT_UShort   n, count;
+  FT_UShort*  pi;
+
+
+  if ( ACCESS_Frame( 2L ) )
+    return error;
+
+  count = ap->PointCount = GET_UShort();
+
+  FORGET_Frame();
+
+  ap->PointIndex = NULL;
+
+  if ( count )
+  {
+    if ( ALLOC_ARRAY( ap->PointIndex, count, FT_UShort ) )
+      return error;
+
+    pi = ap->PointIndex;
+
+    if ( ACCESS_Frame( count * 2L ) )
+    {
+      FREE( pi );
+      return error;
+    }
+
+    for ( n = 0; n < count; n++ )
+      pi[n] = GET_UShort();
+
+    FORGET_Frame();
+  }
+
+  return FT_Err_Ok;
+}
+
+
+static void  Free_AttachPoint( HB_AttachPoint*  ap,
+			       FT_Memory        memory )
+{
+  FREE( ap->PointIndex );
+}
+
+
+/* AttachList */
+
+static FT_Error  Load_AttachList( HB_AttachList*  al,
+				  FT_Stream        stream )
+{
+  FT_Memory memory = stream->memory;
+  FT_Error  error;
+
+  FT_UShort         n, m, count;
+  FT_ULong          cur_offset, new_offset, base_offset;
+
+  HB_AttachPoint*  ap;
+
+
+  base_offset = FILE_Pos();
+
+  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( &al->Coverage, stream ) ) != FT_Err_Ok )
+    return error;
+  (void)FILE_Seek( cur_offset );
+
+  if ( ACCESS_Frame( 2L ) )
+    goto Fail2;
+
+  count = al->GlyphCount = GET_UShort();
+
+  FORGET_Frame();
+
+  al->AttachPoint = NULL;
+
+  if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) )
+    goto Fail2;
+
+  ap = al->AttachPoint;
+
+  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_AttachPoint( &ap[n], stream ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  al->loaded = TRUE;
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_AttachPoint( &ap[m], memory );
+
+  FREE( ap );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &al->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_AttachList( HB_AttachList*  al,
+			      FT_Memory        memory )
+{
+  FT_UShort         n, count;
+
+  HB_AttachPoint*  ap;
+
+
+  if ( !al->loaded )
+    return;
+
+  if ( al->AttachPoint )
+  {
+    count = al->GlyphCount;
+    ap    = al->AttachPoint;
+
+    for ( n = 0; n < count; n++ )
+      Free_AttachPoint( &ap[n], memory );
+
+    FREE( ap );
+  }
+
+  _HB_OPEN_Free_Coverage( &al->Coverage, memory );
+}
+
+
+
+/*********************************
+ * LigCaretList related functions
+ *********************************/
+
+
+/* CaretValueFormat1 */
+/* CaretValueFormat2 */
+/* CaretValueFormat3 */
+/* CaretValueFormat4 */
+
+static FT_Error  Load_CaretValue( HB_CaretValue*  cv,
+				  FT_Stream        stream )
+{
+  FT_Error  error;
+
+  FT_ULong cur_offset, new_offset, base_offset;
+
+
+  base_offset = FILE_Pos();
+
+  if ( ACCESS_Frame( 2L ) )
+    return error;
+
+  cv->CaretValueFormat = GET_UShort();
+
+  FORGET_Frame();
+
+  switch ( cv->CaretValueFormat )
+  {
+  case 1:
+    if ( ACCESS_Frame( 2L ) )
+      return error;
+
+    cv->cvf.cvf1.Coordinate = GET_Short();
+
+    FORGET_Frame();
+
+    break;
+
+  case 2:
+    if ( ACCESS_Frame( 2L ) )
+      return error;
+
+    cv->cvf.cvf2.CaretValuePoint = GET_UShort();
+
+    FORGET_Frame();
+
+    break;
+
+  case 3:
+    if ( ACCESS_Frame( 4L ) )
+      return error;
+
+    cv->cvf.cvf3.Coordinate = GET_Short();
+
+    new_offset = GET_UShort() + base_offset;
+
+    FORGET_Frame();
+
+    cur_offset = FILE_Pos();
+    if ( FILE_Seek( new_offset ) ||
+	 ( error = _HB_OPEN_Load_Device( &cv->cvf.cvf3.Device,
+				stream ) ) != FT_Err_Ok )
+      return error;
+    (void)FILE_Seek( cur_offset );
+
+    break;
+
+  case 4:
+    if ( ACCESS_Frame( 2L ) )
+      return error;
+
+    cv->cvf.cvf4.IdCaretValue = GET_UShort();
+
+    FORGET_Frame();
+    break;
+
+  default:
+    return HB_Err_Invalid_GDEF_SubTable_Format;
+  }
+
+  return FT_Err_Ok;
+}
+
+
+static void  Free_CaretValue( HB_CaretValue*  cv,
+			      FT_Memory        memory )
+{
+  if ( cv->CaretValueFormat == 3 )
+    _HB_OPEN_Free_Device( &cv->cvf.cvf3.Device, memory );
+}
+
+
+/* LigGlyph */
+
+static FT_Error  Load_LigGlyph( HB_LigGlyph*  lg,
+				FT_Stream      stream )
+{
+  FT_Memory memory = stream->memory;
+  FT_Error  error;
+
+  FT_UShort        n, m, count;
+  FT_ULong         cur_offset, new_offset, base_offset;
+
+  HB_CaretValue*  cv;
+
+
+  base_offset = FILE_Pos();
+
+  if ( ACCESS_Frame( 2L ) )
+    return error;
+
+  count = lg->CaretCount = GET_UShort();
+
+  FORGET_Frame();
+
+  lg->CaretValue = NULL;
+
+  if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) )
+    return error;
+
+  cv = lg->CaretValue;
+
+  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_CaretValue( &cv[n], stream ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_CaretValue( &cv[m], memory );
+
+  FREE( cv );
+  return error;
+}
+
+
+static void  Free_LigGlyph( HB_LigGlyph*  lg,
+			    FT_Memory      memory )
+{
+  FT_UShort        n, count;
+
+  HB_CaretValue*  cv;
+
+
+  if ( lg->CaretValue )
+  {
+    count = lg->CaretCount;
+    cv    = lg->CaretValue;
+
+    for ( n = 0; n < count; n++ )
+      Free_CaretValue( &cv[n], memory );
+
+    FREE( cv );
+  }
+}
+
+
+/* LigCaretList */
+
+static FT_Error  Load_LigCaretList( HB_LigCaretList*  lcl,
+				    FT_Stream          stream )
+{
+  FT_Memory memory = stream->memory;
+  FT_Error  error;
+
+  FT_UShort      m, n, count;
+  FT_ULong       cur_offset, new_offset, base_offset;
+
+  HB_LigGlyph*  lg;
+
+
+  base_offset = FILE_Pos();
+
+  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( &lcl->Coverage, stream ) ) != FT_Err_Ok )
+    return error;
+  (void)FILE_Seek( cur_offset );
+
+  if ( ACCESS_Frame( 2L ) )
+    goto Fail2;
+
+  count = lcl->LigGlyphCount = GET_UShort();
+
+  FORGET_Frame();
+
+  lcl->LigGlyph = NULL;
+
+  if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) )
+    goto Fail2;
+
+  lg = lcl->LigGlyph;
+
+  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_LigGlyph( &lg[n], stream ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  lcl->loaded = TRUE;
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_LigGlyph( &lg[m], memory );
+
+  FREE( lg );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &lcl->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_LigCaretList( HB_LigCaretList*  lcl,
+				FT_Memory           memory )
+{
+  FT_UShort      n, count;
+
+  HB_LigGlyph*  lg;
+
+
+  if ( !lcl->loaded )
+    return;
+
+  if ( lcl->LigGlyph )
+  {
+    count = lcl->LigGlyphCount;
+    lg    = lcl->LigGlyph;
+
+    for ( n = 0; n < count; n++ )
+      Free_LigGlyph( &lg[n], memory );
+
+    FREE( lg );
+  }
+
+  _HB_OPEN_Free_Coverage( &lcl->Coverage, memory );
+}
+
+
+
+/***********
+ * GDEF API
+ ***********/
+
+
+static FT_UShort  Get_New_Class( HB_GDEFHeader*  gdef,
+				 FT_UShort        glyphID,
+				 FT_UShort        index )
+{
+  FT_UShort              glyph_index, array_index, count;
+  FT_UShort              byte, bits;
+  
+  HB_ClassRangeRecord*  gcrr;
+  FT_UShort**            ngc;
+
+
+  if ( glyphID >= gdef->LastGlyph )
+    return 0;
+
+  count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
+  gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
+  ngc  = gdef->NewGlyphClasses;
+
+  if ( index < count && glyphID < gcrr[index].Start )
+  {
+    array_index = index;
+    if ( index == 0 )
+      glyph_index = glyphID;
+    else
+      glyph_index = glyphID - gcrr[index - 1].End - 1;
+  }
+  else
+  {
+    array_index = index + 1;
+    glyph_index = glyphID - gcrr[index].End - 1;
+  }
+
+  byte = ngc[array_index][glyph_index / 4];
+  bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
+
+  return bits & 0x000F;
+}
+
+
+
+FT_Error  HB_GDEF_Get_Glyph_Property( HB_GDEFHeader*  gdef,
+				      FT_UShort        glyphID,
+				      FT_UShort*       property )
+{
+  FT_UShort class, index;
+
+  FT_Error  error;
+
+
+  if ( !gdef || !property )
+    return FT_Err_Invalid_Argument;
+
+  /* first, we check for mark attach classes */
+
+  if ( gdef->MarkAttachClassDef.loaded )
+  {
+    error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index );
+    if ( error && error != HB_Err_Not_Covered )
+      return error;
+    if ( !error )
+    {
+      *property = class << 8;
+      return FT_Err_Ok;
+    }
+  }
+
+  error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
+  if ( error && error != HB_Err_Not_Covered )
+    return error;
+
+  /* if we have a constructed class table, check whether additional
+     values have been assigned                                      */
+
+  if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses )
+    class = Get_New_Class( gdef, glyphID, index );
+
+  switch ( class )
+  {
+  case UNCLASSIFIED_GLYPH:
+    *property = 0;
+    break;
+
+  case SIMPLE_GLYPH:
+    *property = HB_GDEF_BASE_GLYPH;
+    break;
+
+  case LIGATURE_GLYPH:
+    *property = HB_GDEF_LIGATURE;
+    break;
+
+  case MARK_GLYPH:
+    *property = HB_GDEF_MARK;
+    break;
+
+  case COMPONENT_GLYPH:
+    *property = HB_GDEF_COMPONENT;
+    break;
+  }
+
+  return FT_Err_Ok;
+}
+
+
+static FT_Error  Make_ClassRange( HB_ClassDefinition*  cd,
+				  FT_UShort             start,
+				  FT_UShort             end,
+				  FT_UShort             class,
+				  FT_Memory             memory )
+{
+  FT_Error               error;
+  FT_UShort              index;
+
+  HB_ClassDefFormat2*   cdf2;
+  HB_ClassRangeRecord*  crr;
+
+
+  cdf2 = &cd->cd.cd2;
+
+  if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
+		      cdf2->ClassRangeCount,
+		      cdf2->ClassRangeCount + 1 ,
+		      HB_ClassRangeRecord ) )
+    return error;
+
+  cdf2->ClassRangeCount++;
+
+  crr   = cdf2->ClassRangeRecord;
+  index = cdf2->ClassRangeCount - 1;
+
+  crr[index].Start = start;
+  crr[index].End   = end;
+  crr[index].Class = class;
+
+  cd->Defined[class] = TRUE;
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GDEF_Build_ClassDefinition( HB_GDEFHeader*  gdef,
+					 FT_UShort        num_glyphs,
+					 FT_UShort        glyph_count,
+					 FT_UShort*       glyph_array,
+					 FT_UShort*       class_array )
+{
+  FT_UShort              start, curr_glyph, curr_class;
+  FT_UShort              n, m, count;
+  FT_Error               error;
+  FT_Memory              memory = gdef->memory;
+
+  HB_ClassDefinition*   gcd;
+  HB_ClassRangeRecord*  gcrr;
+  FT_UShort**            ngc;
+
+
+  if ( !gdef || !glyph_array || !class_array )
+    return FT_Err_Invalid_Argument;
+
+  gcd = &gdef->GlyphClassDef;
+
+  /* We build a format 2 table */
+
+  gcd->ClassFormat = 2;
+
+  /* A GlyphClassDef table contains at most 5 different class values */
+
+  if ( ALLOC_ARRAY( gcd->Defined, 5, FT_Bool ) )
+    return error;
+
+  gcd->cd.cd2.ClassRangeCount  = 0;
+  gcd->cd.cd2.ClassRangeRecord = NULL;
+
+  start      = glyph_array[0];
+  curr_class = class_array[0];
+  curr_glyph = start;
+
+  if ( curr_class >= 5 )
+  {
+    error = FT_Err_Invalid_Argument;
+    goto Fail4;
+  }
+
+  glyph_count--;
+
+  for ( n = 0; n <= glyph_count; n++ )
+  {
+    if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
+    {
+      if ( n == glyph_count )
+      {
+	if ( ( error = Make_ClassRange( gcd, start,
+					curr_glyph,
+					curr_class,
+					memory ) ) != FT_Err_Ok )
+	  goto Fail3;
+      }
+      else
+      {
+	if ( curr_glyph == 0xFFFF )
+	{
+	  error = FT_Err_Invalid_Argument;
+	  goto Fail3;
+	}
+	else
+	  curr_glyph++;
+      }
+    }
+    else
+    {
+      if ( ( error = Make_ClassRange( gcd, start,
+				      curr_glyph - 1,
+				      curr_class,
+				      memory ) ) != FT_Err_Ok )
+	goto Fail3;
+
+      if ( curr_glyph > glyph_array[n] )
+      {
+	error = FT_Err_Invalid_Argument;
+	goto Fail3;
+      }
+
+      start      = glyph_array[n];
+      curr_class = class_array[n];
+      curr_glyph = start;
+
+      if ( curr_class >= 5 )
+      {
+	error = FT_Err_Invalid_Argument;
+	goto Fail3;
+      }
+
+      if ( n == glyph_count )
+      {
+	if ( ( error = Make_ClassRange( gcd, start,
+					curr_glyph,
+					curr_class,
+					memory ) ) != FT_Err_Ok )
+	  goto Fail3;
+      }
+      else
+      {
+	if ( curr_glyph == 0xFFFF )
+	{
+	  error = FT_Err_Invalid_Argument;
+	  goto Fail3;
+	}
+	else
+	  curr_glyph++;
+      }
+    }
+  }
+
+  /* now prepare the arrays for class values assigned during the lookup
+     process                                                            */
+
+  if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
+		    gcd->cd.cd2.ClassRangeCount + 1, FT_UShort* ) )
+    goto Fail3;
+
+  count = gcd->cd.cd2.ClassRangeCount;
+  gcrr  = gcd->cd.cd2.ClassRangeRecord;
+  ngc   = gdef->NewGlyphClasses;
+
+  /* We allocate arrays for all glyphs not covered by the class range
+     records.  Each element holds four class values.                  */
+
+  if ( count > 0 )
+  {
+      if ( gcrr[0].Start )
+      {
+	if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, FT_UShort ) )
+	  goto Fail2;
+      }
+
+      for ( n = 1; n < count; n++ )
+      {
+	if ( gcrr[n].Start - gcrr[n - 1].End > 1 )
+	  if ( ALLOC_ARRAY( ngc[n],
+			    ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4,
+			    FT_UShort ) )
+	    goto Fail1;
+      }
+
+      if ( gcrr[count - 1].End != num_glyphs - 1 )
+      {
+	if ( ALLOC_ARRAY( ngc[count],
+			  ( num_glyphs - gcrr[count - 1].End + 2 ) / 4,
+			  FT_UShort ) )
+	    goto Fail1;
+      }
+  }
+  else if ( num_glyphs > 0 )
+  {
+      if ( ALLOC_ARRAY( ngc[count],
+			( num_glyphs + 3 ) / 4,
+			FT_UShort ) )
+	  goto Fail2;
+  }
+      
+  gdef->LastGlyph = num_glyphs - 1;
+
+  gdef->MarkAttachClassDef_offset = 0L;
+  gdef->MarkAttachClassDef.loaded = FALSE;
+
+  gcd->loaded = TRUE;
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    FREE( ngc[m] );
+
+Fail2:
+  FREE( gdef->NewGlyphClasses );
+
+Fail3:
+  FREE( gcd->cd.cd2.ClassRangeRecord );
+
+Fail4:
+  FREE( gcd->Defined );
+  return error;
+}
+
+
+static void  Free_NewGlyphClasses( HB_GDEFHeader*  gdef,
+				   FT_Memory        memory )
+{
+  FT_UShort**  ngc;
+  FT_UShort    n, count;
+
+
+  if ( gdef->NewGlyphClasses )
+  {
+    count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
+    ngc   = gdef->NewGlyphClasses;
+
+    for ( n = 0; n < count; n++ )
+      FREE( ngc[n] );
+
+    FREE( ngc );
+  }
+}
+
+
+FT_Error  _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader*  gdef,
+			      FT_UShort        glyphID,
+			      FT_UShort        property )
+{
+  FT_Error               error;
+  FT_UShort              class, new_class, index;
+  FT_UShort              byte, bits, mask;
+  FT_UShort              array_index, glyph_index, count;
+
+  HB_ClassRangeRecord*  gcrr;
+  FT_UShort**            ngc;
+
+
+  error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
+  if ( error && error != HB_Err_Not_Covered )
+    return error;
+
+  /* we don't accept glyphs covered in `GlyphClassDef' */
+
+  if ( !error )
+    return HB_Err_Not_Covered;
+
+  switch ( property )
+  {
+  case 0:
+    new_class = UNCLASSIFIED_GLYPH;
+    break;
+
+  case HB_GDEF_BASE_GLYPH:
+    new_class = SIMPLE_GLYPH;
+    break;
+
+  case HB_GDEF_LIGATURE:
+    new_class = LIGATURE_GLYPH;
+    break;
+
+  case HB_GDEF_MARK:
+    new_class = MARK_GLYPH;
+    break;
+
+  case HB_GDEF_COMPONENT:
+    new_class = COMPONENT_GLYPH;
+    break;
+
+  default:
+    return FT_Err_Invalid_Argument;
+  }
+
+  count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
+  gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
+  ngc  = gdef->NewGlyphClasses;
+
+  if ( index < count && glyphID < gcrr[index].Start )
+  {
+    array_index = index;
+    if ( index == 0 )
+      glyph_index = glyphID;
+    else
+      glyph_index = glyphID - gcrr[index - 1].End - 1;
+  }
+  else
+  {
+    array_index = index + 1;
+    glyph_index = glyphID - gcrr[index].End - 1;
+  }
+
+  byte  = ngc[array_index][glyph_index / 4];
+  bits  = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
+  class = bits & 0x000F;
+
+  /* we don't overwrite existing entries */
+
+  if ( !class )
+  {
+    bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
+    mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
+
+    ngc[array_index][glyph_index / 4] &= mask;
+    ngc[array_index][glyph_index / 4] |= bits;
+  }
+
+  return FT_Err_Ok;
+}
+
+
+FT_Error  _HB_GDEF_Check_Property( HB_GDEFHeader*  gdef,
+			  HB_GlyphItem    gitem,
+			  FT_UShort        flags,
+			  FT_UShort*       property )
+{
+  FT_Error  error;
+
+  if ( gdef )
+  {
+    FT_UShort basic_glyph_class;
+    FT_UShort desired_attachment_class;
+
+    if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN )
+    {
+      error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
+      if ( error )
+	return error;
+    }
+
+    *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 & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS  )
+      basic_glyph_class = HB_GDEF_MARK;
+    else
+      basic_glyph_class = *property;
+
+    /* Return Not_Covered, if, for example, basic_glyph_class
+     * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES
+     */
+    if ( flags & basic_glyph_class )
+      return HB_Err_Not_Covered;
+    
+    /* The high byte of LookupFlags has the meaning
+     * "ignore marks of attachment type different than
+     * the attachment type specified."
+     */
+    desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS;
+    if ( desired_attachment_class )
+    {
+      if ( basic_glyph_class == HB_GDEF_MARK &&
+	   *property != desired_attachment_class )
+	return HB_Err_Not_Covered;
+    }
+  }
+
+  return FT_Err_Ok;
+}
+
+
+/* END */
diff --git a/src/harfbuzz-gdef.h b/src/harfbuzz-gdef.h
new file mode 100644
index 0000000..e126e82
--- /dev/null
+++ b/src/harfbuzz-gdef.h
@@ -0,0 +1,127 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_GDEF_H
+#define HARFBUZZ_GDEF_H
+
+#include "harfbuzz-open.h"
+
+FT_BEGIN_HEADER
+
+#define HB_Err_Invalid_GDEF_SubTable_Format  0x1030
+#define HB_Err_Invalid_GDEF_SubTable         0x1031
+
+
+/* GDEF glyph properties.  Note that HB_GDEF_COMPONENT has no corresponding
+ * flag in the LookupFlag field.     */
+#define HB_GDEF_BASE_GLYPH  0x0002
+#define HB_GDEF_LIGATURE    0x0004
+#define HB_GDEF_MARK        0x0008
+#define HB_GDEF_COMPONENT   0x0010
+
+
+typedef struct HB_AttachPoint_  HB_AttachPoint;
+
+
+struct  HB_AttachList_
+{
+  FT_Bool           loaded;
+
+  HB_Coverage       Coverage;         /* Coverage table              */
+  FT_UShort         GlyphCount;       /* number of glyphs with
+					 attachments                 */
+  HB_AttachPoint*   AttachPoint;      /* array of AttachPoint tables */
+};
+
+typedef struct HB_AttachList_  HB_AttachList;
+
+typedef struct HB_LigGlyph_  HB_LigGlyph;
+
+struct  HB_LigCaretList_
+{
+  FT_Bool        loaded;
+
+  HB_Coverage    Coverage;            /* Coverage table            */
+  FT_UShort      LigGlyphCount;       /* number of ligature glyphs */
+  HB_LigGlyph*   LigGlyph;            /* array of LigGlyph tables  */
+};
+
+typedef struct HB_LigCaretList_  HB_LigCaretList;
+
+
+
+/* The `NewGlyphClasses' field is not defined in the TTO specification.
+   We use it for fonts with a constructed `GlyphClassDef' structure
+   (i.e., which don't have a GDEF table) to collect glyph classes
+   assigned during the lookup process.  The number of arrays in this
+   pointer array is GlyphClassDef->cd.cd2.ClassRangeCount+1; the nth
+   array then contains the glyph class values of the glyphs not covered
+   by the ClassRangeRecords structures with index n-1 and n.  We store
+   glyph class values for four glyphs in a single array element.
+
+   `LastGlyph' is identical to the number of glyphs minus one in the
+   font; we need it only if `NewGlyphClasses' is not NULL (to have an
+   upper bound for the last array).
+
+   Note that we first store the file offset to the `MarkAttachClassDef'
+   field (which has been introduced in OpenType 1.2) -- since the
+   `Version' field value hasn't been increased to indicate that we have
+   one more field for some obscure reason, we must parse the GSUB table
+   to find out whether class values refer to this table.  Only then we
+   can finally load the MarkAttachClassDef structure if necessary.      */
+
+struct  HB_GDEFHeader_
+{
+  FT_Memory            memory;
+  FT_ULong             offset;
+
+  FT_Fixed             Version;
+
+  HB_ClassDefinition   GlyphClassDef;
+  HB_AttachList        AttachList;
+  HB_LigCaretList      LigCaretList;
+  FT_ULong             MarkAttachClassDef_offset;
+  HB_ClassDefinition   MarkAttachClassDef;        /* new in OT 1.2 */
+
+  FT_UShort            LastGlyph;
+  FT_UShort**          NewGlyphClasses;
+};
+
+typedef struct HB_GDEFHeader_   HB_GDEFHeader;
+typedef struct HB_GDEFHeader_*  HB_GDEF;
+
+
+FT_Error  HB_New_GDEF_Table( FT_Face          face,
+			     HB_GDEFHeader** retptr );
+      
+
+FT_Error  HB_Load_GDEF_Table( FT_Face          face,
+			      HB_GDEFHeader** gdef );
+
+
+FT_Error  HB_Done_GDEF_Table ( HB_GDEFHeader* gdef );
+
+
+FT_Error  HB_GDEF_Get_Glyph_Property( HB_GDEFHeader*  gdef,
+				      FT_UShort        glyphID,
+				      FT_UShort*       property );
+
+FT_Error  HB_GDEF_Build_ClassDefinition( HB_GDEFHeader*  gdef,
+					 FT_UShort        num_glyphs,
+					 FT_UShort        glyph_count,
+					 FT_UShort*       glyph_array,
+					 FT_UShort*       class_array );
+
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_GDEF_H */
diff --git a/src/harfbuzz-gpos-private.h b/src/harfbuzz-gpos-private.h
new file mode 100644
index 0000000..a04416f
--- /dev/null
+++ b/src/harfbuzz-gpos-private.h
@@ -0,0 +1,683 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_GPOS_PRIVATE_H
+#define HARFBUZZ_GPOS_PRIVATE_H
+
+#include "harfbuzz-gpos.h"
+
+FT_BEGIN_HEADER
+
+
+/* shared tables */
+
+struct  HB_ValueRecord_
+{
+  FT_Short    XPlacement;             /* horizontal adjustment for
+					 placement                      */
+  FT_Short    YPlacement;             /* vertical adjustment for
+					 placement                      */
+  FT_Short    XAdvance;               /* horizontal adjustment for
+					 advance                        */
+  FT_Short    YAdvance;               /* vertical adjustment for
+					 advance                        */
+  HB_Device  XPlacementDevice;       /* device table for horizontal
+					 placement                      */
+  HB_Device  YPlacementDevice;       /* device table for vertical
+					 placement                      */
+  HB_Device  XAdvanceDevice;         /* device table for horizontal
+					 advance                        */
+  HB_Device  YAdvanceDevice;         /* device table for vertical
+					 advance                        */
+  FT_UShort   XIdPlacement;           /* horizontal placement metric ID */
+  FT_UShort   YIdPlacement;           /* vertical placement metric ID   */
+  FT_UShort   XIdAdvance;             /* horizontal advance metric ID   */
+  FT_UShort   YIdAdvance;             /* vertical advance metric ID     */
+};
+
+typedef struct HB_ValueRecord_  HB_ValueRecord;
+
+
+/* Mask values to scan the value format of the ValueRecord structure.
+ We always expand compressed ValueRecords of the font.              */
+
+#define HB_GPOS_FORMAT_HAVE_X_PLACEMENT         0x0001
+#define HB_GPOS_FORMAT_HAVE_Y_PLACEMENT         0x0002
+#define HB_GPOS_FORMAT_HAVE_X_ADVANCE           0x0004
+#define HB_GPOS_FORMAT_HAVE_Y_ADVANCE           0x0008
+#define HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE  0x0010
+#define HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE  0x0020
+#define HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE    0x0040
+#define HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE    0x0080
+#define HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT      0x0100
+#define HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT      0x0200
+#define HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE        0x0400
+#define HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE        0x0800
+
+
+struct  HB_AnchorFormat1_
+{
+  FT_Short   XCoordinate;             /* horizontal value */
+  FT_Short   YCoordinate;             /* vertical value   */
+};
+
+typedef struct HB_AnchorFormat1_  HB_AnchorFormat1;
+
+
+struct  HB_AnchorFormat2_
+{
+  FT_Short   XCoordinate;             /* horizontal value             */
+  FT_Short   YCoordinate;             /* vertical value               */
+  FT_UShort  AnchorPoint;             /* index to glyph contour point */
+};
+
+typedef struct HB_AnchorFormat2_  HB_AnchorFormat2;
+
+
+struct  HB_AnchorFormat3_
+{
+  FT_Short    XCoordinate;            /* horizontal value              */
+  FT_Short    YCoordinate;            /* vertical value                */
+  HB_Device  XDeviceTable;           /* device table for X coordinate */
+  HB_Device  YDeviceTable;           /* device table for Y coordinate */
+};
+
+typedef struct HB_AnchorFormat3_  HB_AnchorFormat3;
+
+
+struct  HB_AnchorFormat4_
+{
+  FT_UShort  XIdAnchor;               /* horizontal metric ID */
+  FT_UShort  YIdAnchor;               /* vertical metric ID   */
+};
+
+typedef struct HB_AnchorFormat4_  HB_AnchorFormat4;
+
+
+struct  HB_Anchor_
+{
+  FT_UShort  PosFormat;               /* 1, 2, 3, or 4 -- 0 indicates
+					 that there is no Anchor table */
+
+  union
+  {
+    HB_AnchorFormat1  af1;
+    HB_AnchorFormat2  af2;
+    HB_AnchorFormat3  af3;
+    HB_AnchorFormat4  af4;
+  } af;
+};
+
+typedef struct HB_Anchor_  HB_Anchor;
+
+
+struct  HB_MarkRecord_
+{
+  FT_UShort   Class;                  /* mark class   */
+  HB_Anchor  MarkAnchor;             /* anchor table */
+};
+
+typedef struct HB_MarkRecord_  HB_MarkRecord;
+
+
+struct  HB_MarkArray_
+{
+  FT_UShort        MarkCount;         /* number of MarkRecord tables */
+  HB_MarkRecord*  MarkRecord;        /* array of MarkRecord tables  */
+};
+
+typedef struct HB_MarkArray_  HB_MarkArray;
+
+
+/* LookupType 1 */
+
+struct  HB_SinglePosFormat1_
+{
+  HB_ValueRecord  Value;             /* ValueRecord for all covered
+					 glyphs                      */
+};
+
+typedef struct HB_SinglePosFormat1_  HB_SinglePosFormat1;
+
+
+struct  HB_SinglePosFormat2_
+{
+  FT_UShort         ValueCount;       /* number of ValueRecord tables */
+  HB_ValueRecord*  Value;            /* array of ValueRecord tables  */
+};
+
+typedef struct HB_SinglePosFormat2_  HB_SinglePosFormat2;
+
+
+struct  HB_SinglePos_
+{
+  FT_UShort     PosFormat;            /* 1 or 2         */
+  HB_Coverage  Coverage;             /* Coverage table */
+
+  FT_UShort     ValueFormat;          /* format of ValueRecord table */
+
+  union
+  {
+    HB_SinglePosFormat1  spf1;
+    HB_SinglePosFormat2  spf2;
+  } spf;
+};
+
+typedef struct HB_SinglePos_  HB_SinglePos;
+
+
+/* LookupType 2 */
+
+struct  HB_PairValueRecord_
+{
+  FT_UShort        SecondGlyph;       /* glyph ID for second glyph  */
+  HB_ValueRecord  Value1;            /* pos. data for first glyph  */
+  HB_ValueRecord  Value2;            /* pos. data for second glyph */
+};
+
+typedef struct HB_PairValueRecord_  HB_PairValueRecord;
+
+
+struct  HB_PairSet_
+{
+  FT_UShort             PairValueCount;
+				      /* number of PairValueRecord tables */
+  HB_PairValueRecord*  PairValueRecord;
+				      /* array of PairValueRecord tables  */
+};
+
+typedef struct HB_PairSet_  HB_PairSet;
+
+
+struct  HB_PairPosFormat1_
+{
+  FT_UShort     PairSetCount;         /* number of PairSet tables    */
+  HB_PairSet*  PairSet;              /* array of PairSet tables     */
+};
+
+typedef struct HB_PairPosFormat1_  HB_PairPosFormat1;
+
+
+struct  HB_Class2Record_
+{
+  HB_ValueRecord  Value1;            /* pos. data for first glyph  */
+  HB_ValueRecord  Value2;            /* pos. data for second glyph */
+};
+
+typedef struct HB_Class2Record_  HB_Class2Record;
+
+
+struct  HB_Class1Record_
+{
+  HB_Class2Record*  Class2Record;    /* array of Class2Record tables */
+};
+
+typedef struct HB_Class1Record_  HB_Class1Record;
+
+
+struct  HB_PairPosFormat2_
+{
+  HB_ClassDefinition  ClassDef1;     /* class def. for first glyph     */
+  HB_ClassDefinition  ClassDef2;     /* class def. for second glyph    */
+  FT_UShort            Class1Count;   /* number of classes in ClassDef1
+					 table                          */
+  FT_UShort            Class2Count;   /* number of classes in ClassDef2
+					 table                          */
+  HB_Class1Record*    Class1Record;  /* array of Class1Record tables   */
+};
+
+typedef struct HB_PairPosFormat2_  HB_PairPosFormat2;
+
+
+struct  HB_PairPos_
+{
+  FT_UShort     PosFormat;            /* 1 or 2         */
+  HB_Coverage  Coverage;             /* Coverage table */
+  FT_UShort     ValueFormat1;         /* format of ValueRecord table
+					 for first glyph             */
+  FT_UShort     ValueFormat2;         /* format of ValueRecord table
+					 for second glyph            */
+
+  union
+  {
+    HB_PairPosFormat1  ppf1;
+    HB_PairPosFormat2  ppf2;
+  } ppf;
+};
+
+typedef struct HB_PairPos_  HB_PairPos;
+
+
+/* LookupType 3 */
+
+struct  HB_EntryExitRecord_
+{
+  HB_Anchor  EntryAnchor;            /* entry Anchor table */
+  HB_Anchor  ExitAnchor;             /* exit Anchor table  */
+};
+
+
+typedef struct HB_EntryExitRecord_  HB_EntryExitRecord;
+
+struct  HB_CursivePos_
+{
+  FT_UShort             PosFormat;    /* always 1                         */
+  HB_Coverage          Coverage;     /* Coverage table                   */
+  FT_UShort             EntryExitCount;
+				      /* number of EntryExitRecord tables */
+  HB_EntryExitRecord*  EntryExitRecord;
+				      /* array of EntryExitRecord tables  */
+};
+
+typedef struct HB_CursivePos_  HB_CursivePos;
+
+
+/* LookupType 4 */
+
+struct  HB_BaseRecord_
+{
+  HB_Anchor*  BaseAnchor;            /* array of base glyph anchor
+					 tables                     */
+};
+
+typedef struct HB_BaseRecord_  HB_BaseRecord;
+
+
+struct  HB_BaseArray_
+{
+  FT_UShort        BaseCount;         /* number of BaseRecord tables */
+  HB_BaseRecord*  BaseRecord;        /* array of BaseRecord tables  */
+};
+
+typedef struct HB_BaseArray_  HB_BaseArray;
+
+
+struct  HB_MarkBasePos_
+{
+  FT_UShort      PosFormat;           /* always 1                  */
+  HB_Coverage   MarkCoverage;        /* mark glyph coverage table */
+  HB_Coverage   BaseCoverage;        /* base glyph coverage table */
+  FT_UShort      ClassCount;          /* number of mark classes    */
+  HB_MarkArray  MarkArray;           /* mark array table          */
+  HB_BaseArray  BaseArray;           /* base array table          */
+};
+
+typedef struct HB_MarkBasePos_  HB_MarkBasePos;
+
+
+/* LookupType 5 */
+
+struct  HB_ComponentRecord_
+{
+  HB_Anchor*  LigatureAnchor;        /* array of ligature glyph anchor
+					 tables                         */
+};
+
+typedef struct HB_ComponentRecord_  HB_ComponentRecord;
+
+
+struct  HB_LigatureAttach_
+{
+  FT_UShort             ComponentCount;
+				      /* number of ComponentRecord tables */
+  HB_ComponentRecord*  ComponentRecord;
+				      /* array of ComponentRecord tables  */
+};
+
+typedef struct HB_LigatureAttach_  HB_LigatureAttach;
+
+
+struct  HB_LigatureArray_
+{
+  FT_UShort            LigatureCount; /* number of LigatureAttach tables */
+  HB_LigatureAttach*  LigatureAttach;
+				      /* array of LigatureAttach tables  */
+};
+
+typedef struct HB_LigatureArray_  HB_LigatureArray;
+
+
+struct  HB_MarkLigPos_
+{
+  FT_UShort          PosFormat;       /* always 1                      */
+  HB_Coverage       MarkCoverage;    /* mark glyph coverage table     */
+  HB_Coverage       LigatureCoverage;
+				      /* ligature glyph coverage table */
+  FT_UShort          ClassCount;      /* number of mark classes        */
+  HB_MarkArray      MarkArray;       /* mark array table              */
+  HB_LigatureArray  LigatureArray;   /* ligature array table          */
+};
+
+typedef struct HB_MarkLigPos_  HB_MarkLigPos;
+
+
+/* LookupType 6 */
+
+struct  HB_Mark2Record_
+{
+  HB_Anchor*  Mark2Anchor;           /* array of mark glyph anchor
+					 tables                     */
+};
+
+typedef struct HB_Mark2Record_  HB_Mark2Record;
+
+
+struct  HB_Mark2Array_
+{
+  FT_UShort         Mark2Count;       /* number of Mark2Record tables */
+  HB_Mark2Record*  Mark2Record;      /* array of Mark2Record tables  */
+};
+
+typedef struct HB_Mark2Array_  HB_Mark2Array;
+
+
+struct  HB_MarkMarkPos_
+{
+  FT_UShort       PosFormat;          /* always 1                         */
+  HB_Coverage    Mark1Coverage;      /* first mark glyph coverage table  */
+  HB_Coverage    Mark2Coverage;      /* second mark glyph coverave table */
+  FT_UShort       ClassCount;         /* number of combining mark classes */
+  HB_MarkArray   Mark1Array;         /* MarkArray table for first mark   */
+  HB_Mark2Array  Mark2Array;         /* MarkArray table for second mark  */
+};
+
+typedef struct HB_MarkMarkPos_  HB_MarkMarkPos;
+
+
+/* needed by both lookup type 7 and 8 */
+
+struct  HB_PosLookupRecord_
+{
+  FT_UShort  SequenceIndex;           /* index into current
+					 glyph sequence               */
+  FT_UShort  LookupListIndex;         /* Lookup to apply to that pos. */
+};
+
+typedef struct HB_PosLookupRecord_  HB_PosLookupRecord;
+
+
+/* LookupType 7 */
+
+struct  HB_PosRule_
+{
+  FT_UShort             GlyphCount;   /* total number of input glyphs     */
+  FT_UShort             PosCount;     /* number of PosLookupRecord tables */
+  FT_UShort*            Input;        /* array of input glyph IDs         */
+  HB_PosLookupRecord*  PosLookupRecord;
+				      /* array of PosLookupRecord tables  */
+};
+
+typedef struct HB_PosRule_  HB_PosRule;
+
+
+struct  HB_PosRuleSet_
+{
+  FT_UShort     PosRuleCount;         /* number of PosRule tables */
+  HB_PosRule*  PosRule;              /* array of PosRule tables  */
+};
+
+typedef struct HB_PosRuleSet_  HB_PosRuleSet;
+
+
+struct  HB_ContextPosFormat1_
+{
+  HB_Coverage     Coverage;          /* Coverage table              */
+  FT_UShort        PosRuleSetCount;   /* number of PosRuleSet tables */
+  HB_PosRuleSet*  PosRuleSet;        /* array of PosRuleSet tables  */
+};
+
+typedef struct HB_ContextPosFormat1_  HB_ContextPosFormat1;
+
+
+struct  HB_PosClassRule_
+{
+  FT_UShort             GlyphCount;   /* total number of context classes  */
+  FT_UShort             PosCount;     /* number of PosLookupRecord tables */
+  FT_UShort*            Class;        /* array of classes                 */
+  HB_PosLookupRecord*  PosLookupRecord;
+				      /* array of PosLookupRecord tables  */
+};
+
+typedef struct HB_PosClassRule_  HB_PosClassRule;
+
+
+struct  HB_PosClassSet_
+{
+  FT_UShort          PosClassRuleCount;
+				      /* number of PosClassRule tables */
+  HB_PosClassRule*  PosClassRule;    /* array of PosClassRule tables  */
+};
+
+typedef struct HB_PosClassSet_  HB_PosClassSet;
+
+
+/* The `MaxContextLength' field is not defined in the TTO specification
+   but simplifies the implementation of this format.  It holds the
+   maximal context length used in the context rules.                    */
+
+struct  HB_ContextPosFormat2_
+{
+  FT_UShort            MaxContextLength;
+				      /* maximal context length       */
+  HB_Coverage         Coverage;      /* Coverage table               */
+  HB_ClassDefinition  ClassDef;      /* ClassDef table               */
+  FT_UShort            PosClassSetCount;
+				      /* number of PosClassSet tables */
+  HB_PosClassSet*     PosClassSet;   /* array of PosClassSet tables  */
+};
+
+typedef struct HB_ContextPosFormat2_  HB_ContextPosFormat2;
+
+
+struct  HB_ContextPosFormat3_
+{
+  FT_UShort             GlyphCount;   /* number of input glyphs           */
+  FT_UShort             PosCount;     /* number of PosLookupRecord tables */
+  HB_Coverage*         Coverage;     /* array of Coverage tables         */
+  HB_PosLookupRecord*  PosLookupRecord;
+				      /* array of PosLookupRecord tables  */
+};
+
+typedef struct HB_ContextPosFormat3_  HB_ContextPosFormat3;
+
+
+struct  HB_ContextPos_
+{
+  FT_UShort  PosFormat;               /* 1, 2, or 3     */
+
+  union
+  {
+    HB_ContextPosFormat1  cpf1;
+    HB_ContextPosFormat2  cpf2;
+    HB_ContextPosFormat3  cpf3;
+  } cpf;
+};
+
+typedef struct HB_ContextPos_  HB_ContextPos;
+
+
+/* LookupType 8 */
+
+struct  HB_ChainPosRule_
+{
+  FT_UShort             BacktrackGlyphCount;
+				      /* total number of backtrack glyphs */
+  FT_UShort*            Backtrack;    /* array of backtrack glyph IDs     */
+  FT_UShort             InputGlyphCount;
+				      /* total number of input glyphs     */
+  FT_UShort*            Input;        /* array of input glyph IDs         */
+  FT_UShort             LookaheadGlyphCount;
+				      /* total number of lookahead glyphs */
+  FT_UShort*            Lookahead;    /* array of lookahead glyph IDs     */
+  FT_UShort             PosCount;     /* number of PosLookupRecords       */
+  HB_PosLookupRecord*  PosLookupRecord;
+				      /* array of PosLookupRecords       */
+};
+
+typedef struct HB_ChainPosRule_  HB_ChainPosRule;
+
+
+struct  HB_ChainPosRuleSet_
+{
+  FT_UShort          ChainPosRuleCount;
+				      /* number of ChainPosRule tables */
+  HB_ChainPosRule*  ChainPosRule;    /* array of ChainPosRule tables  */
+};
+
+typedef struct HB_ChainPosRuleSet_  HB_ChainPosRuleSet;
+
+
+struct  HB_ChainContextPosFormat1_
+{
+  HB_Coverage          Coverage;     /* Coverage table                   */
+  FT_UShort             ChainPosRuleSetCount;
+				      /* number of ChainPosRuleSet tables */
+  HB_ChainPosRuleSet*  ChainPosRuleSet;
+				      /* array of ChainPosRuleSet tables  */
+};
+
+typedef struct HB_ChainContextPosFormat1_  HB_ChainContextPosFormat1;
+
+
+struct  HB_ChainPosClassRule_
+{
+  FT_UShort             BacktrackGlyphCount;
+				      /* total number of backtrack
+					 classes                         */
+  FT_UShort*            Backtrack;    /* array of backtrack classes      */
+  FT_UShort             InputGlyphCount;
+				      /* total number of context classes */
+  FT_UShort*            Input;        /* array of context classes        */
+  FT_UShort             LookaheadGlyphCount;
+				      /* total number of lookahead
+					 classes                         */
+  FT_UShort*            Lookahead;    /* array of lookahead classes      */
+  FT_UShort             PosCount;     /* number of PosLookupRecords      */
+  HB_PosLookupRecord*  PosLookupRecord;
+				      /* array of substitution lookups   */
+};
+
+typedef struct HB_ChainPosClassRule_  HB_ChainPosClassRule;
+
+
+struct  HB_ChainPosClassSet_
+{
+  FT_UShort               ChainPosClassRuleCount;
+				      /* number of ChainPosClassRule
+					 tables                      */
+  HB_ChainPosClassRule*  ChainPosClassRule;
+				      /* array of ChainPosClassRule
+					 tables                      */
+};
+
+typedef struct HB_ChainPosClassSet_  HB_ChainPosClassSet;
+
+
+/* The `MaxXXXLength' fields are not defined in the TTO specification
+   but simplifies the implementation of this format.  It holds the
+   maximal context length used in the specific context rules.         */
+
+struct  HB_ChainContextPosFormat2_
+{
+  HB_Coverage           Coverage;    /* Coverage table             */
+
+  FT_UShort              MaxBacktrackLength;
+				      /* maximal backtrack length   */
+  HB_ClassDefinition    BacktrackClassDef;
+				      /* BacktrackClassDef table    */
+  FT_UShort              MaxInputLength;
+				      /* maximal input length       */
+  HB_ClassDefinition    InputClassDef;
+				      /* InputClassDef table        */
+  FT_UShort              MaxLookaheadLength;
+				      /* maximal lookahead length   */
+  HB_ClassDefinition    LookaheadClassDef;
+				      /* LookaheadClassDef table    */
+
+  FT_UShort              ChainPosClassSetCount;
+				      /* number of ChainPosClassSet
+					 tables                     */
+  HB_ChainPosClassSet*  ChainPosClassSet;
+				      /* array of ChainPosClassSet
+					 tables                     */
+};
+
+typedef struct HB_ChainContextPosFormat2_  HB_ChainContextPosFormat2;
+
+
+struct  HB_ChainContextPosFormat3_
+{
+  FT_UShort             BacktrackGlyphCount;
+				      /* number of backtrack glyphs    */
+  HB_Coverage*         BacktrackCoverage;
+				      /* array of backtrack Coverage
+					 tables                        */
+  FT_UShort             InputGlyphCount;
+				      /* number of input glyphs        */
+  HB_Coverage*         InputCoverage;
+				      /* array of input coverage
+					 tables                        */
+  FT_UShort             LookaheadGlyphCount;
+				      /* number of lookahead glyphs    */
+  HB_Coverage*         LookaheadCoverage;
+				      /* array of lookahead coverage
+					 tables                        */
+  FT_UShort             PosCount;     /* number of PosLookupRecords    */
+  HB_PosLookupRecord*  PosLookupRecord;
+				      /* array of substitution lookups */
+};
+
+typedef struct HB_ChainContextPosFormat3_  HB_ChainContextPosFormat3;
+
+
+struct  HB_ChainContextPos_
+{
+  FT_UShort  PosFormat;             /* 1, 2, or 3 */
+
+  union
+  {
+    HB_ChainContextPosFormat1  ccpf1;
+    HB_ChainContextPosFormat2  ccpf2;
+    HB_ChainContextPosFormat3  ccpf3;
+  } ccpf;
+};
+
+typedef struct HB_ChainContextPos_  HB_ChainContextPos;
+
+
+union  HB_GPOS_SubTable_
+{
+  HB_SinglePos        single;
+  HB_PairPos          pair;
+  HB_CursivePos       cursive;
+  HB_MarkBasePos      markbase;
+  HB_MarkLigPos       marklig;
+  HB_MarkMarkPos      markmark;
+  HB_ContextPos       context;
+  HB_ChainContextPos  chain;
+};
+
+typedef union HB_GPOS_SubTable_  HB_GPOS_SubTable;
+
+
+
+FT_Error  _HB_GPOS_Load_SubTable( HB_GPOS_SubTable*  st,
+				  FT_Stream     stream,
+				  FT_UShort     lookup_type );
+
+void  _HB_GPOS_Free_SubTable( HB_GPOS_SubTable*  st,
+			      FT_Memory     memory,
+			      FT_UShort     lookup_type );
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_GPOS_PRIVATE_H */
diff --git a/src/harfbuzz-gpos.c b/src/harfbuzz-gpos.c
new file mode 100644
index 0000000..8143eac
--- /dev/null
+++ b/src/harfbuzz-gpos.c
@@ -0,0 +1,6269 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#include "harfbuzz-impl.h"
+#include "harfbuzz-gpos-private.h"
+#include "harfbuzz-open-private.h"
+#include "harfbuzz-gdef-private.h"
+
+#include FT_TRUETYPE_TAGS_H
+
+
+struct  GPOS_Instance_
+{
+  HB_GPOSHeader*  gpos;
+  FT_Face          face;
+  FT_Bool          dvi;
+  FT_UShort        load_flags;  /* how the glyph should be loaded */
+  FT_Bool          r2l;
+
+  FT_UShort        last;        /* the last valid glyph -- used
+				   with cursive positioning     */
+  FT_Pos           anchor_x;    /* the coordinates of the anchor point */
+  FT_Pos           anchor_y;    /* of the last valid glyph             */
+};
+
+typedef struct GPOS_Instance_  GPOS_Instance;
+
+
+static FT_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
+				       FT_UShort         lookup_index,
+				       HB_Buffer        buffer,
+				       FT_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 FT_Error  default_mmfunc( FT_Face      face,
+				 FT_UShort    metric_id,
+				 FT_Pos*      metric_value,
+				 void*        data )
+{
+  return HB_Err_No_MM_Interpreter;
+}
+
+
+
+FT_Error  HB_Load_GPOS_Table( FT_Face          face,
+			      HB_GPOSHeader** retptr,
+			      HB_GDEFHeader*  gdef )
+{
+  FT_ULong         cur_offset, new_offset, base_offset;
+
+  FT_UShort        i, num_lookups;
+  HB_GPOSHeader*  gpos;
+  HB_Lookup*      lo;
+
+  FT_Stream  stream = face->stream;
+  FT_Error   error;
+  FT_Memory  memory = face->memory;
+
+
+  if ( !retptr )
+    return FT_Err_Invalid_Argument;
+
+  if ( !stream )
+    return FT_Err_Invalid_Face_Handle;
+
+  if (( error = _hb_ftglue_face_goto_table( face, TTAG_GPOS, stream ) ))
+    return error;
+
+  base_offset = FILE_Pos();
+
+  if ( ALLOC ( gpos, sizeof( *gpos ) ) )
+    return error;
+
+  gpos->memory = memory;
+  gpos->gfunc = 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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_Err_Ok )
+    goto Fail2;
+
+  gpos->gdef = gdef;      /* can be NULL */
+
+  /* We now check the LookupFlags for values larger than 0xFF to find
+     out whether we need to load the `MarkAttachClassDef' field of the
+     GDEF table -- this hack is necessary for OpenType 1.2 tables since
+     the version field of the GDEF table hasn't been incremented.
+
+     For constructed GDEF tables, we only load it if
+     `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
+     a constructed mark attach table is not supported currently).       */
+
+  if ( gdef &&
+       gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
+  {
+    lo          = gpos->LookupList.Lookup;
+    num_lookups = gpos->LookupList.LookupCount;
+
+    for ( i = 0; i < num_lookups; i++ )
+    {
+      if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+      {
+	if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
+	     ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
+					     256, stream ) ) != FT_Err_Ok )
+	  goto Fail1;
+
+	break;
+      }
+    }
+  }
+
+  *retptr = gpos;
+
+  return FT_Err_Ok;
+
+Fail1:
+  _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS, memory );
+
+Fail2:
+  _HB_OPEN_Free_FeatureList( &gpos->FeatureList, memory );
+
+Fail3:
+  _HB_OPEN_Free_ScriptList( &gpos->ScriptList, memory );
+
+Fail4:
+  FREE( gpos );
+
+  return error;
+}
+
+
+FT_Error  HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
+{
+  FT_Memory memory = gpos->memory;
+  
+  _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS, memory );
+  _HB_OPEN_Free_FeatureList( &gpos->FeatureList, memory );
+  _HB_OPEN_Free_ScriptList( &gpos->ScriptList, memory );
+
+  return FT_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 FT_Error  Load_ValueRecord( HB_ValueRecord*  vr,
+				   FT_UShort         format,
+				   FT_ULong          base_offset,
+				   FT_Stream         stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+  
+  FT_ULong 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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  _HB_OPEN_Free_Device( &vr->YAdvanceDevice, memory );
+
+Fail2:
+  _HB_OPEN_Free_Device( &vr->XAdvanceDevice, memory );
+
+Fail3:
+  _HB_OPEN_Free_Device( &vr->YPlacementDevice, memory );
+  return error;
+}
+
+
+static void  Free_ValueRecord( HB_ValueRecord*  vr,
+			       FT_UShort         format,
+			       FT_Memory         memory )
+{
+  if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
+    _HB_OPEN_Free_Device( &vr->YAdvanceDevice, memory );
+  if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
+    _HB_OPEN_Free_Device( &vr->XAdvanceDevice, memory );
+  if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
+    _HB_OPEN_Free_Device( &vr->YPlacementDevice, memory );
+  if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
+    _HB_OPEN_Free_Device( &vr->XPlacementDevice, memory );
+}
+
+
+static FT_Error  Get_ValueRecord( GPOS_Instance*    gpi,
+				  HB_ValueRecord*  vr,
+				  FT_UShort         format,
+				  HB_Position      gd )
+{
+  FT_Pos           value;
+  FT_Short         pixel_value;
+  FT_Error         error = FT_Err_Ok;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+
+  FT_UShort  x_ppem, y_ppem;
+  FT_Fixed   x_scale, y_scale;
+
+
+  if ( !format )
+    return FT_Err_Ok;
+
+  x_ppem  = gpi->face->size->metrics.x_ppem;
+  y_ppem  = gpi->face->size->metrics.y_ppem;
+  x_scale = gpi->face->size->metrics.x_scale;
+  y_scale = gpi->face->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->face, 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->face, 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->face, 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->face, vr->YIdAdvance,
+			    &value, gpos->data );
+    if ( error )
+      return error;
+    gd->y_advance += value;
+  }
+
+  return error;
+}
+
+
+/* AnchorFormat1 */
+/* AnchorFormat2 */
+/* AnchorFormat3 */
+/* AnchorFormat4 */
+
+static FT_Error  Load_Anchor( HB_Anchor*  an,
+			      FT_Stream    stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_ULong 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 ) ) != FT_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 ) ) != FT_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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable, memory );
+  return error;
+}
+
+
+static void  Free_Anchor( HB_Anchor*  an,
+			  FT_Memory    memory)
+{
+  if ( an->PosFormat == 3 )
+  {
+    _HB_OPEN_Free_Device( &an->af.af3.YDeviceTable, memory );
+    _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable, memory );
+  }
+}
+
+
+static FT_Error  Get_Anchor( GPOS_Instance*   gpi,
+			     HB_Anchor*      an,
+			     FT_UShort        glyph_index,
+			     FT_Pos*          x_value,
+			     FT_Pos*          y_value )
+{
+  FT_Error  error = FT_Err_Ok;
+
+  FT_Outline       outline;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+  FT_UShort        ap;
+
+  FT_Short         pixel_value;
+  FT_UShort        load_flags;
+
+  FT_UShort        x_ppem, y_ppem;
+  FT_Fixed         x_scale, y_scale;
+
+
+  x_ppem  = gpi->face->size->metrics.x_ppem;
+  y_ppem  = gpi->face->size->metrics.y_ppem;
+  x_scale = gpi->face->size->metrics.x_scale;
+  y_scale = gpi->face->size->metrics.y_scale;
+
+  switch ( an->PosFormat )
+  {
+  case 0:
+    /* The special case of an empty AnchorTable */
+
+    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->face, glyph_index, load_flags );
+      if ( error )
+	return error;
+
+      if ( gpi->face->glyph->format != ft_glyph_format_outline )
+	return HB_Err_Invalid_GPOS_SubTable;	  
+
+      ap = an->af.af2.AnchorPoint;
+      
+      outline = gpi->face->glyph->outline;
+
+      /* if outline.n_points is set to zero by gfunc(), 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 HB_Err_Invalid_GPOS_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->face, an->af.af4.XIdAnchor,
+			    x_value, gpos->data );
+    if ( error )
+      return error;
+
+    error = (gpos->mmfunc)( gpi->face, an->af.af4.YIdAnchor,
+			    y_value, gpos->data );
+    if ( error )
+      return error;
+    break;
+  }
+
+  return error;
+}
+
+
+/* MarkArray */
+
+static FT_Error  Load_MarkArray ( HB_MarkArray*  ma,
+				  FT_Stream       stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort        n, m, count;
+  FT_ULong         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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_Anchor( &mr[m].MarkAnchor, memory );
+
+  FREE( mr );
+  return error;
+}
+
+
+static void  Free_MarkArray( HB_MarkArray*  ma,
+			     FT_Memory       memory )
+{
+  FT_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, memory );
+
+    FREE( mr );
+  }
+}
+
+
+/* LookupType 1 */
+
+/* SinglePosFormat1 */
+/* SinglePosFormat2 */
+
+static FT_Error  Load_SinglePos( HB_GPOS_SubTable* st,
+				 FT_Stream       stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+  HB_SinglePos*   sp = &st->single;
+
+  FT_UShort         n, m, count, format;
+  FT_ULong          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 HB_Err_Invalid_GPOS_SubTable;
+
+  cur_offset = FILE_Pos();
+  if ( FILE_Seek( new_offset ) ||
+       ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != FT_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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_ValueRecord( &vr[m], format, memory );
+
+  FREE( vr );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &sp->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_SinglePos( HB_GPOS_SubTable* st,
+			     FT_Memory       memory )
+{
+  FT_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, memory );
+    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, memory );
+
+      FREE( v );
+    }
+    break;
+  }
+
+  _HB_OPEN_Free_Coverage( &sp->Coverage, memory );
+}
+
+static FT_Error  Lookup_DefaultPos(  GPOS_Instance*    gpi,
+				     HB_GPOS_SubTable* st,
+				     HB_Buffer        buffer,
+				     FT_UShort         flags,
+				     FT_UShort         context_length,
+				     int               nesting_level )
+{
+  return HB_Err_Not_Covered;
+}
+
+static FT_Error  Lookup_SinglePos( GPOS_Instance*    gpi,
+				   HB_GPOS_SubTable* st,
+				   HB_Buffer        buffer,
+				   FT_UShort         flags,
+				   FT_UShort         context_length,
+				   int               nesting_level )
+{
+  FT_UShort        index, property;
+  FT_Error         error;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+  HB_SinglePos*   sp = &st->single;
+
+
+  if ( context_length != 0xFFFF && context_length < 1 )
+    return HB_Err_Not_Covered;
+
+  if ( CHECK_Property( gpos->gdef, 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 HB_Err_Invalid_GPOS_SubTable;
+    error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
+			     sp->ValueFormat, POSITION( buffer->in_pos ) );
+    if ( error )
+      return error;
+    break;
+
+  default:
+    return HB_Err_Invalid_GPOS_SubTable;
+  }
+
+  (buffer->in_pos)++;
+
+  return FT_Err_Ok;
+}
+
+
+/* LookupType 2 */
+
+/* PairSet */
+
+static FT_Error  Load_PairSet ( HB_PairSet*  ps,
+				FT_UShort     format1,
+				FT_UShort     format2,
+				FT_Stream     stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, m, count;
+  FT_ULong              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, memory );
+	goto Fail;
+      }
+    }
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+  {
+    if ( format1 )
+      Free_ValueRecord( &pvr[m].Value1, format1, memory );
+    if ( format2 )
+      Free_ValueRecord( &pvr[m].Value2, format2, memory );
+  }
+
+  FREE( pvr );
+  return error;
+}
+
+
+static void  Free_PairSet( HB_PairSet*  ps,
+			   FT_UShort     format1,
+			   FT_UShort     format2,
+			   FT_Memory     memory )
+{
+  FT_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, memory );
+      if ( format2 )
+	Free_ValueRecord( &pvr[n].Value2, format2, memory );
+    }
+
+    FREE( pvr );
+  }
+}
+
+
+/* PairPosFormat1 */
+
+static FT_Error  Load_PairPos1( HB_PairPosFormat1*  ppf1,
+				FT_UShort            format1,
+				FT_UShort            format2,
+				FT_Stream            stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort     n, m, count;
+  FT_ULong      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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_PairSet( &ps[m], format1, format2, memory );
+
+  FREE( ps );
+  return error;
+}
+
+
+static void  Free_PairPos1( HB_PairPosFormat1*  ppf1,
+			    FT_UShort            format1,
+			    FT_UShort            format2,
+			    FT_Memory            memory )
+{
+  FT_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, memory );
+
+    FREE( ps );
+  }
+}
+
+
+/* PairPosFormat2 */
+
+static FT_Error  Load_PairPos2( HB_PairPosFormat2*  ppf2,
+				FT_UShort            format1,
+				FT_UShort            format2,
+				FT_Stream            stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort          m, n, k, count1, count2;
+  FT_ULong           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 ) ) != FT_Err_Ok )
+    return error;
+  if ( FILE_Seek( new_offset2 ) ||
+       ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
+				       stream ) ) != FT_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, memory );	      
+	  goto Fail0;
+	}
+      }
+    }
+
+    continue;
+
+  Fail0:
+    for ( k = 0; k < n; k++ )
+    {
+      if ( format1 )
+	Free_ValueRecord( &c2r[k].Value1, format1, memory );
+      if ( format2 )
+	Free_ValueRecord( &c2r[k].Value2, format2, memory );
+    }
+    goto Fail1;
+  }
+
+  return FT_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, memory );
+      if ( format2 )
+	Free_ValueRecord( &c2r[n].Value2, format2, memory );
+    }
+
+    FREE( c2r );
+  }
+
+  FREE( c1r );
+Fail2:
+
+  _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2, memory );
+
+Fail3:
+  _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1, memory );
+  return error;
+}
+
+
+static void  Free_PairPos2( HB_PairPosFormat2*  ppf2,
+			    FT_UShort            format1,
+			    FT_UShort            format2,
+			    FT_Memory            memory )
+{
+  FT_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, memory );
+	if ( format2 )
+	  Free_ValueRecord( &c2r[n].Value2, format2, memory );
+      }
+
+      FREE( c2r );
+    }
+
+    FREE( c1r );
+
+    _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2, memory );
+    _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1, memory );
+  }
+}
+
+
+static FT_Error  Load_PairPos( HB_GPOS_SubTable* st,
+			       FT_Stream     stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+  HB_PairPos*     pp = &st->pair;
+
+  FT_UShort         format1, format2;
+  FT_ULong          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 ) ) != FT_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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  _HB_OPEN_Free_Coverage( &pp->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_PairPos( HB_GPOS_SubTable* st,
+			   FT_Memory     memory )
+{
+  FT_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, memory );
+    break;
+
+  case 2:
+    Free_PairPos2( &pp->ppf.ppf2, format1, format2, memory );
+    break;
+  }
+
+  _HB_OPEN_Free_Coverage( &pp->Coverage, memory );
+}
+
+
+static FT_Error  Lookup_PairPos1( GPOS_Instance*       gpi,
+				  HB_PairPosFormat1*  ppf1,
+				  HB_Buffer           buffer,
+				  FT_UShort            first_pos,
+				  FT_UShort            index,
+				  FT_UShort            format1,
+				  FT_UShort            format2 )
+{
+  FT_Error              error;
+  FT_UShort             numpvr, glyph2;
+
+  HB_PairValueRecord*  pvr;
+
+
+  if ( index >= ppf1->PairSetCount )
+     return HB_Err_Invalid_GPOS_SubTable;
+
+  pvr = ppf1->PairSet[index].PairValueRecord;
+  if ( !pvr )
+    return HB_Err_Invalid_GPOS_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 FT_Error  Lookup_PairPos2( GPOS_Instance*       gpi,
+				  HB_PairPosFormat2*  ppf2,
+				  HB_Buffer           buffer,
+				  FT_UShort            first_pos,
+				  FT_UShort            format1,
+				  FT_UShort            format2 )
+{
+  FT_Error           error;
+  FT_UShort          cl1, cl2;
+
+  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 HB_Err_Invalid_GPOS_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 FT_Error  Lookup_PairPos( GPOS_Instance*    gpi,
+				 HB_GPOS_SubTable* st,
+				 HB_Buffer        buffer,
+				 FT_UShort         flags,
+				 FT_UShort         context_length,
+				 int               nesting_level )
+{
+  FT_Error         error;
+  FT_UShort        index, property, first_pos;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+  HB_PairPos*     pp = &st->pair;
+
+
+  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;
+
+  if ( CHECK_Property( gpos->gdef, 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)++;
+
+  while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+			  flags, &property ) )
+  {
+    if ( error && error != HB_Err_Not_Covered )
+      return error;
+
+    if ( buffer->in_pos == buffer->in_length )
+      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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  /* adjusting the `next' glyph */
+
+  if ( pp->ValueFormat2 )
+    (buffer->in_pos)++;
+
+  return error;
+}
+
+
+/* LookupType 3 */
+
+/* CursivePosFormat1 */
+
+static FT_Error  Load_CursivePos( HB_GPOS_SubTable* st,
+				  FT_Stream        stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+  HB_CursivePos*  cp = &st->cursive;
+
+  FT_UShort             n, m, count;
+  FT_ULong              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 ) ) != FT_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++ )
+  {
+    FT_ULong 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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      {
+	if ( entry_offset )
+	  Free_Anchor( &eer[n].EntryAnchor, memory );
+	goto Fail1;
+      }
+      (void)FILE_Seek( cur_offset );
+    }
+    else
+      eer[n].ExitAnchor.PosFormat   = 0;
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+  {
+    Free_Anchor( &eer[m].EntryAnchor, memory );
+    Free_Anchor( &eer[m].ExitAnchor, memory );
+  }
+
+  FREE( eer );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &cp->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_CursivePos( HB_GPOS_SubTable* st,
+			      FT_Memory        memory )
+{
+  FT_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, memory );
+      Free_Anchor( &eer[n].ExitAnchor, memory );
+    }
+
+    FREE( eer );
+  }
+
+  _HB_OPEN_Free_Coverage( &cp->Coverage, memory );
+}
+
+
+static FT_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
+				    HB_GPOS_SubTable* st,
+				    HB_Buffer        buffer,
+				    FT_UShort         flags,
+				    FT_UShort         context_length,
+				    int               nesting_level )
+{
+  FT_UShort        index, property;
+  FT_Error         error;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+  HB_CursivePos*  cp = &st->cursive;
+
+  HB_EntryExitRecord*  eer;
+  FT_Pos                entry_x, entry_y;
+  FT_Pos                exit_x, exit_y;
+
+
+  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 ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+    return error;
+
+  /* We don't handle mark glyphs here.  According to Andrei, this isn't
+     possible, but who knows...                                         */
+
+  if ( property == HB_GDEF_MARK )
+  {
+    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 HB_Err_Invalid_GPOS_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 FT_Err_Ok;
+}
+
+
+/* LookupType 4 */
+
+/* BaseArray */
+
+static FT_Error  Load_BaseArray( HB_BaseArray*  ba,
+				 FT_UShort       num_classes,
+				 FT_Stream       stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort        m, n, k, count;
+  FT_ULong         cur_offset, new_offset, base_offset;
+
+  HB_BaseRecord*  br;
+  HB_Anchor*      ban;
+
+
+  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;
+
+  for ( m = 0; m < count; m++ )
+  {
+    br[m].BaseAnchor = NULL;
+
+    if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, HB_Anchor ) )
+      goto Fail;
+
+    ban = br[m].BaseAnchor;
+
+    for ( n = 0; n < num_classes; n++ )
+    {
+      if ( ACCESS_Frame( 2L ) )
+	goto Fail0;
+
+      new_offset = GET_UShort() + base_offset;
+
+      FORGET_Frame();
+
+      if (new_offset == base_offset) {
+	/* Doulos SIL Regular is buggy and has zer offsets here.  Skip */
+	ban[n].PosFormat = 0;
+	continue;
+      }
+
+      cur_offset = FILE_Pos();
+      if ( FILE_Seek( new_offset ) ||
+	   ( error = Load_Anchor( &ban[n], stream ) ) != FT_Err_Ok )
+	goto Fail0;
+      (void)FILE_Seek( cur_offset );
+    }
+
+    continue;
+  Fail0:
+    for ( k = 0; k < n; k++ )
+      Free_Anchor( &ban[k], memory );
+    goto Fail;
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( k = 0; k < m; k++ )
+  {
+    ban = br[k].BaseAnchor;
+    
+    for ( n = 0; n < num_classes; n++ )
+      Free_Anchor( &ban[n], memory );
+
+    FREE( ban );
+  }
+
+  FREE( br );
+  return error;
+}
+
+
+static void  Free_BaseArray( HB_BaseArray*  ba,
+			     FT_UShort       num_classes,
+			     FT_Memory       memory )
+{
+  FT_UShort        m, n, count;
+
+  HB_BaseRecord*  br;
+  HB_Anchor*      ban;
+
+
+  if ( ba->BaseRecord )
+  {
+    count = ba->BaseCount;
+    br    = ba->BaseRecord;
+
+    for ( m = 0; m < count; m++ )
+    {
+      ban = br[m].BaseAnchor;
+
+      for ( n = 0; n < num_classes; n++ )
+	Free_Anchor( &ban[n], memory );
+
+      FREE( ban );
+    }
+
+    FREE( br );
+  }
+}
+
+
+/* MarkBasePosFormat1 */
+
+static FT_Error  Load_MarkBasePos( HB_GPOS_SubTable* st,
+				   FT_Stream         stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+  HB_MarkBasePos* mbp = &st->markbase;
+
+  FT_ULong  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 HB_Err_Invalid_SubTable_Format;
+
+  cur_offset = FILE_Pos();
+  if ( FILE_Seek( new_offset ) ||
+       ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_Err_Ok )
+    goto Fail1;
+
+  return FT_Err_Ok;
+
+Fail1:
+  Free_MarkArray( &mbp->MarkArray, memory );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory );
+
+Fail3:
+  _HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory );
+  return error;
+}
+
+
+static void  Free_MarkBasePos( HB_GPOS_SubTable* st,
+			       FT_Memory         memory )
+{
+  HB_MarkBasePos* mbp = &st->markbase;
+
+  Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory );
+  Free_MarkArray( &mbp->MarkArray, memory );
+  _HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory );
+  _HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory );
+}
+
+
+static FT_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
+				     HB_GPOS_SubTable* st,
+				     HB_Buffer        buffer,
+				     FT_UShort         flags,
+				     FT_UShort         context_length,
+				     int               nesting_level )
+{
+  FT_UShort        i, j, mark_index, base_index, property, class;
+  FT_Pos           x_mark_value, y_mark_value, x_base_value, y_base_value;
+  FT_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;
+
+
+  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;
+
+  if ( CHECK_Property( gpos->gdef, 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 )
+  {
+    error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
+					&property );
+    if ( error )
+      return error;
+
+    if ( !( property == HB_GDEF_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 ( property != HB_GDEF_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 HB_Err_Invalid_GPOS_SubTable;
+
+  class       = ma->MarkRecord[mark_index].Class;
+  mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
+
+  if ( class >= mbp->ClassCount )
+    return HB_Err_Invalid_GPOS_SubTable;
+
+  ba = &mbp->BaseArray;
+
+  if ( base_index >= ba->BaseCount )
+    return HB_Err_Invalid_GPOS_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 FT_Err_Ok;
+}
+
+
+/* LookupType 5 */
+
+/* LigatureAttach */
+
+static FT_Error  Load_LigatureAttach( HB_LigatureAttach*  lat,
+				      FT_UShort            num_classes,
+				      FT_Stream            stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             m, n, k, count;
+  FT_ULong              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 ) ) != FT_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], memory );
+    goto Fail;
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( k = 0; k < m; k++ )
+  {
+    lan = cr[k].LigatureAnchor;
+    
+    for ( n = 0; n < num_classes; n++ )
+      Free_Anchor( &lan[n], memory );
+
+    FREE( lan );
+  }
+
+  FREE( cr );
+  return error;
+}
+
+
+static void  Free_LigatureAttach( HB_LigatureAttach*  lat,
+				  FT_UShort            num_classes,
+				  FT_Memory            memory )
+{
+  FT_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], memory );
+
+      FREE( lan );
+    }
+
+    FREE( cr );
+  }
+}
+
+
+/* LigatureArray */
+
+static FT_Error  Load_LigatureArray( HB_LigatureArray*  la,
+				     FT_UShort           num_classes,
+				     FT_Stream           stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort            n, m, count;
+  FT_ULong             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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_LigatureAttach( &lat[m], num_classes, memory );
+
+  FREE( lat );
+  return error;
+}
+
+
+static void  Free_LigatureArray( HB_LigatureArray*  la,
+				 FT_UShort           num_classes,
+				 FT_Memory           memory )
+{
+  FT_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, memory );
+
+    FREE( lat );
+  }
+}
+
+
+/* MarkLigPosFormat1 */
+
+static FT_Error  Load_MarkLigPos( HB_GPOS_SubTable* st,
+				  FT_Stream        stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+  HB_MarkLigPos*  mlp = &st->marklig;
+
+  FT_ULong  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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_Err_Ok )
+    goto Fail1;
+
+  return FT_Err_Ok;
+
+Fail1:
+  Free_MarkArray( &mlp->MarkArray, memory );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage, memory );
+
+Fail3:
+  _HB_OPEN_Free_Coverage( &mlp->MarkCoverage, memory );
+  return error;
+}
+
+
+static void  Free_MarkLigPos( HB_GPOS_SubTable* st,
+			      FT_Memory        memory)
+{
+  HB_MarkLigPos*  mlp = &st->marklig;
+
+  Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, memory );
+  Free_MarkArray( &mlp->MarkArray, memory );
+  _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage, memory );
+  _HB_OPEN_Free_Coverage( &mlp->MarkCoverage, memory );
+}
+
+
+static FT_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
+				    HB_GPOS_SubTable* st,
+				    HB_Buffer        buffer,
+				    FT_UShort         flags,
+				    FT_UShort         context_length,
+				    int               nesting_level )
+{
+  FT_UShort        i, j, mark_index, lig_index, property, class;
+  FT_UShort        mark_glyph;
+  FT_Pos           x_mark_value, y_mark_value, x_lig_value, y_lig_value;
+  FT_Error         error;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+  HB_MarkLigPos*  mlp = &st->marklig;
+
+  HB_MarkArray*        ma;
+  HB_LigatureArray*    la;
+  HB_LigatureAttach*   lat;
+  HB_ComponentRecord*  cr;
+  FT_UShort             comp_index;
+  HB_Anchor*           mark_anchor;
+  HB_Anchor*           lig_anchor;
+
+  HB_Position    o;
+
+
+  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();
+
+  if ( CHECK_Property( gpos->gdef, 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 )
+  {
+    error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
+					&property );
+    if ( error )
+      return error;
+
+    if ( !( property == HB_GDEF_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 ( property != HB_GDEF_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 HB_Err_Invalid_GPOS_SubTable;
+
+  class       = ma->MarkRecord[mark_index].Class;
+  mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
+
+  if ( class >= mlp->ClassCount )
+    return HB_Err_Invalid_GPOS_SubTable;
+
+  la = &mlp->LigatureArray;
+
+  if ( lig_index >= la->LigatureCount )
+    return HB_Err_Invalid_GPOS_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 FT_Err_Ok;
+}
+
+
+/* LookupType 6 */
+
+/* Mark2Array */
+
+static FT_Error  Load_Mark2Array( HB_Mark2Array*  m2a,
+				  FT_UShort        num_classes,
+				  FT_Stream        stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort         k, m, n, count;
+  FT_ULong          cur_offset, new_offset, base_offset;
+
+  HB_Mark2Record*  m2r;
+  HB_Anchor*       m2an;
+
+
+  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;
+
+  for ( m = 0; m < count; m++ )
+  {
+    m2r[m].Mark2Anchor = NULL;
+
+    if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, HB_Anchor ) )
+      goto Fail;
+
+    m2an = m2r[m].Mark2Anchor;
+
+    for ( n = 0; n < num_classes; n++ )
+    {
+      if ( ACCESS_Frame( 2L ) )
+	goto Fail0;
+
+      new_offset = GET_UShort() + base_offset;
+
+      FORGET_Frame();
+
+      cur_offset = FILE_Pos();
+      if ( FILE_Seek( new_offset ) ||
+	   ( error = Load_Anchor( &m2an[n], stream ) ) != FT_Err_Ok )
+	goto Fail0;
+      (void)FILE_Seek( cur_offset );
+    }
+
+    continue;
+  Fail0:
+    for ( k = 0; k < n; k++ )
+      Free_Anchor( &m2an[k], memory );
+    goto Fail;
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( k = 0; k < m; k++ )
+  {
+    m2an = m2r[k].Mark2Anchor;
+    
+    for ( n = 0; n < num_classes; n++ )
+      Free_Anchor( &m2an[n], memory );
+
+    FREE( m2an );
+  }
+
+  FREE( m2r );
+  return error;
+}
+
+
+static void  Free_Mark2Array( HB_Mark2Array*  m2a,
+			      FT_UShort        num_classes,
+			      FT_Memory        memory )
+{
+  FT_UShort         m, n, count;
+
+  HB_Mark2Record*  m2r;
+  HB_Anchor*       m2an;
+
+
+  if ( m2a->Mark2Record )
+  {
+    count = m2a->Mark2Count;
+    m2r   = m2a->Mark2Record;
+
+    for ( m = 0; m < count; m++ )
+    {
+      m2an = m2r[m].Mark2Anchor;
+
+      for ( n = 0; n < num_classes; n++ )
+	Free_Anchor( &m2an[n], memory );
+
+      FREE( m2an );
+    }
+
+    FREE( m2r );
+  }
+}
+
+
+/* MarkMarkPosFormat1 */
+
+static FT_Error  Load_MarkMarkPos( HB_GPOS_SubTable* st,
+				   FT_Stream         stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+  HB_MarkMarkPos* mmp = &st->markmark;
+
+  FT_ULong  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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_Err_Ok )
+    goto Fail1;
+
+  return FT_Err_Ok;
+
+Fail1:
+  Free_MarkArray( &mmp->Mark1Array, memory );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage, memory );
+
+Fail3:
+  _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage, memory );
+  return error;
+}
+
+
+static void  Free_MarkMarkPos( HB_GPOS_SubTable* st,
+			       FT_Memory         memory)
+{
+  HB_MarkMarkPos* mmp = &st->markmark;
+
+  Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, memory );
+  Free_MarkArray( &mmp->Mark1Array, memory );
+  _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage, memory );
+  _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage, memory );
+}
+
+
+static FT_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
+				     HB_GPOS_SubTable* st,
+				     HB_Buffer        buffer,
+				     FT_UShort         flags,
+				     FT_UShort         context_length,
+				     int               nesting_level )
+{
+  FT_UShort        j, mark1_index, mark2_index, property, class;
+  FT_Pos           x_mark1_value, y_mark1_value,
+		   x_mark2_value, y_mark2_value;
+  FT_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;
+
+
+  if ( context_length != 0xFFFF && context_length < 1 )
+    return HB_Err_Not_Covered;
+
+  if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
+    return HB_Err_Not_Covered;
+
+  if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+		       flags, &property ) )
+    return error;
+
+  error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
+			  &mark1_index );
+  if ( error )
+    return error;
+
+  /* now we check the preceding glyph whether it is a suitable
+     mark glyph                                                */
+
+  if ( buffer->in_pos == 0 )
+    return HB_Err_Not_Covered;
+
+  j = buffer->in_pos - 1;
+  error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
+				      &property );
+  if ( error )
+    return error;
+
+  if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+  {
+    if ( property != (flags & 0xFF00) )
+      return HB_Err_Not_Covered;
+  }
+  else
+  {
+    if ( property != HB_GDEF_MARK )
+      return HB_Err_Not_Covered;
+  }
+
+  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 HB_Err_Invalid_GPOS_SubTable;
+
+  class        = ma1->MarkRecord[mark1_index].Class;
+  mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
+
+  if ( class >= mmp->ClassCount )
+    return HB_Err_Invalid_GPOS_SubTable;
+
+  ma2 = &mmp->Mark2Array;
+
+  if ( mark2_index >= ma2->Mark2Count )
+    return HB_Err_Invalid_GPOS_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 FT_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 FT_Error  Do_ContextPos( GPOS_Instance*        gpi,
+				FT_UShort             GlyphCount,
+				FT_UShort             PosCount,
+				HB_PosLookupRecord*  pos,
+				HB_Buffer            buffer,
+				int                   nesting_level )
+{
+  FT_Error  error;
+  FT_UShort 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 FT_Err_Ok;
+}
+
+
+/* LookupType 7 */
+
+/* PosRule */
+
+static FT_Error  Load_PosRule( HB_PosRule*  pr,
+			       FT_Stream     stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, count;
+  FT_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, FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( plr );
+
+Fail2:
+  FREE( i );
+  return error;
+}
+
+
+static void  Free_PosRule( HB_PosRule*  pr,
+			   FT_Memory     memory )
+{
+  FREE( pr->PosLookupRecord );
+  FREE( pr->Input );
+}
+
+
+/* PosRuleSet */
+
+static FT_Error  Load_PosRuleSet( HB_PosRuleSet*  prs,
+				  FT_Stream        stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort     n, m, count;
+  FT_ULong      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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_PosRule( &pr[m], memory );
+
+  FREE( pr );
+  return error;
+}
+
+
+static void  Free_PosRuleSet( HB_PosRuleSet*  prs,
+			      FT_Memory        memory )
+{
+  FT_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], memory );
+
+    FREE( pr );
+  }
+}
+
+
+/* ContextPosFormat1 */
+
+static FT_Error  Load_ContextPos1( HB_ContextPosFormat1*  cpf1,
+				   FT_Stream               stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort        n, m, count;
+  FT_ULong         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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_PosRuleSet( &prs[m], memory );
+
+  FREE( prs );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &cpf1->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ContextPos1( HB_ContextPosFormat1*  cpf1,
+			    FT_Memory               memory )
+{
+  FT_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], memory );
+
+    FREE( prs );
+  }
+
+  _HB_OPEN_Free_Coverage( &cpf1->Coverage, memory );
+}
+
+
+/* PosClassRule */
+
+static FT_Error  Load_PosClassRule( HB_ContextPosFormat2*  cpf2,
+				    HB_PosClassRule*       pcr,
+				    FT_Stream               stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, count;
+
+  FT_UShort*            c;
+  HB_PosLookupRecord*  plr;
+  FT_Bool*              d;
+
+
+  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, FT_UShort ) )
+    return error;
+
+  c = pcr->Class;
+  d = cpf2->ClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail2;
+
+  for ( n = 0; n < count; n++ )
+  {
+    c[n] = GET_UShort();
+
+    /* We check whether the specific class is used at all.  If not,
+       class 0 is used instead.                                     */
+
+    if ( !d[c[n]] )
+      c[n] = 0;
+  }
+
+  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 FT_Err_Ok;
+
+Fail1:
+  FREE( plr );
+
+Fail2:
+  FREE( c );
+  return error;
+}
+
+
+static void  Free_PosClassRule( HB_PosClassRule*  pcr,
+				FT_Memory          memory )
+{
+  FREE( pcr->PosLookupRecord );
+  FREE( pcr->Class );
+}
+
+
+/* PosClassSet */
+
+static FT_Error  Load_PosClassSet( HB_ContextPosFormat2*  cpf2,
+				   HB_PosClassSet*        pcs,
+				   FT_Stream               stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort          n, m, count;
+  FT_ULong           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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_PosClassRule( &pcr[m], memory );
+
+  FREE( pcr );
+  return error;
+}
+
+
+static void  Free_PosClassSet( HB_PosClassSet*  pcs,
+			       FT_Memory         memory )
+{
+  FT_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], memory );
+
+    FREE( pcr );
+  }
+}
+
+
+/* ContextPosFormat2 */
+
+static FT_Error  Load_ContextPos2( HB_ContextPosFormat2*  cpf2,
+				   FT_Stream               stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort         n, m, count;
+  FT_ULong          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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; n++ )
+    Free_PosClassSet( &pcs[m], memory );
+
+  FREE( pcs );
+
+Fail2:
+  _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef, memory );
+
+Fail3:
+  _HB_OPEN_Free_Coverage( &cpf2->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ContextPos2( HB_ContextPosFormat2*  cpf2,
+			    FT_Memory               memory )
+{
+  FT_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], memory );
+
+    FREE( pcs );
+  }
+
+  _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef, memory );
+  _HB_OPEN_Free_Coverage( &cpf2->Coverage, memory );
+}
+
+
+/* ContextPosFormat3 */
+
+static FT_Error  Load_ContextPos3( HB_ContextPosFormat3*  cpf3,
+				   FT_Stream               stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, count;
+  FT_ULong              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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( plr );
+
+Fail2:
+  for ( n = 0; n < count; n++ )
+    _HB_OPEN_Free_Coverage( &c[n], memory );
+
+  FREE( c );
+  return error;
+}
+
+
+static void  Free_ContextPos3( HB_ContextPosFormat3*  cpf3,
+			    FT_Memory               memory )
+{
+  FT_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], memory );
+
+    FREE( c );
+  }
+}
+
+
+/* ContextPos */
+
+static FT_Error  Load_ContextPos( HB_GPOS_SubTable* st,
+				  FT_Stream        stream )
+{
+  FT_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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+static void  Free_ContextPos( HB_GPOS_SubTable* st,
+			      FT_Memory        memory )
+{
+  HB_ContextPos*   cp = &st->context;
+
+  switch ( cp->PosFormat )
+  {
+  case 1:
+    Free_ContextPos1( &cp->cpf.cpf1, memory );
+    break;
+
+  case 2:
+    Free_ContextPos2( &cp->cpf.cpf2, memory );
+    break;
+
+  case 3:
+    Free_ContextPos3( &cp->cpf.cpf3, memory );
+    break;
+  }
+}
+
+
+static FT_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
+				     HB_ContextPosFormat1*  cpf1,
+				     HB_Buffer              buffer,
+				     FT_UShort               flags,
+				     FT_UShort               context_length,
+				     int                     nesting_level )
+{
+  FT_UShort        index, property;
+  FT_UShort        i, j, k, numpr;
+  FT_Error         error;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+
+  HB_PosRule*     pr;
+  HB_GDEFHeader*  gdef;
+
+
+  gdef = gpos->gdef;
+
+  if ( CHECK_Property( gdef, 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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  return error;
+
+	if ( j + pr[k].GlyphCount - i == 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 FT_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
+				     HB_ContextPosFormat2*  cpf2,
+				     HB_Buffer              buffer,
+				     FT_UShort               flags,
+				     FT_UShort               context_length,
+				     int                     nesting_level )
+{
+  FT_UShort          index, property;
+  FT_Error           error;
+  FT_Memory          memory = gpi->face->memory;
+  FT_UShort          i, j, k, known_classes;
+
+  FT_UShort*         classes;
+  FT_UShort*         cl;
+  HB_GPOSHeader*    gpos = gpi->gpos;
+
+  HB_PosClassSet*   pcs;
+  HB_PosClassRule*  pr;
+  HB_GDEFHeader*    gdef;
+
+
+  gdef = gpos->gdef;
+
+  if ( CHECK_Property( gdef, 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 ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_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 = HB_Err_Invalid_GPOS_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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  goto End;
+
+	if ( j + pr->GlyphCount - i == 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 FT_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
+				     HB_ContextPosFormat3*  cpf3,
+				     HB_Buffer              buffer,
+				     FT_UShort               flags,
+				     FT_UShort               context_length,
+				     int                     nesting_level )
+{
+  FT_Error         error;
+  FT_UShort        index, i, j, property;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+
+  HB_Coverage*    c;
+  HB_GDEFHeader*  gdef;
+
+
+  gdef = gpos->gdef;
+
+  if ( CHECK_Property( gdef, 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++ )
+  {
+    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    {
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+
+      if ( j + cpf3->GlyphCount - i == 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 FT_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
+				    HB_GPOS_SubTable* st,
+				    HB_Buffer        buffer,
+				    FT_UShort         flags,
+				    FT_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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+/* LookupType 8 */
+
+/* ChainPosRule */
+
+static FT_Error  Load_ChainPosRule( HB_ChainPosRule*  cpr,
+				    FT_Stream          stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, count;
+  FT_UShort*            b;
+  FT_UShort*            i;
+  FT_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, FT_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, FT_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, FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( plr );
+
+Fail2:
+  FREE( l );
+
+Fail3:
+  FREE( i );
+
+Fail4:
+  FREE( b );
+  return error;
+}
+
+
+static void  Free_ChainPosRule( HB_ChainPosRule*  cpr,
+				FT_Memory          memory )
+{
+  FREE( cpr->PosLookupRecord );
+  FREE( cpr->Lookahead );
+  FREE( cpr->Input );
+  FREE( cpr->Backtrack );
+}
+
+
+/* ChainPosRuleSet */
+
+static FT_Error  Load_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs,
+				       FT_Stream             stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort          n, m, count;
+  FT_ULong           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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_ChainPosRule( &cpr[m], memory );
+
+  FREE( cpr );
+  return error;
+}
+
+
+static void  Free_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs,
+				   FT_Memory             memory )
+{
+  FT_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], memory );
+
+    FREE( cpr );
+  }
+}
+
+
+/* ChainContextPosFormat1 */
+
+static FT_Error  Load_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1,
+					FT_Stream                    stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, m, count;
+  FT_ULong              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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_ChainPosRuleSet( &cprs[m], memory );
+
+  FREE( cprs );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &ccpf1->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1,
+				 FT_Memory                    memory )
+{
+  FT_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], memory );
+
+    FREE( cprs );
+  }
+
+  _HB_OPEN_Free_Coverage( &ccpf1->Coverage, memory );
+}
+
+
+/* ChainPosClassRule */
+
+static FT_Error  Load_ChainPosClassRule(
+		   HB_ChainContextPosFormat2*  ccpf2,
+		   HB_ChainPosClassRule*       cpcr,
+		   FT_Stream                    stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, count;
+
+  FT_UShort*            b;
+  FT_UShort*            i;
+  FT_UShort*            l;
+  HB_PosLookupRecord*  plr;
+  FT_Bool*              d;
+
+
+  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, FT_UShort ) )
+    return error;
+
+  b = cpcr->Backtrack;
+  d = ccpf2->BacktrackClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail4;
+
+  for ( n = 0; n < count; n++ )
+  {
+    b[n] = GET_UShort();
+
+    /* We check whether the specific class is used at all.  If not,
+       class 0 is used instead.                                     */
+
+    if ( !d[b[n]] )
+      b[n] = 0;
+  }
+
+  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, FT_UShort ) )
+    goto Fail4;
+
+  i = cpcr->Input;
+  d = ccpf2->InputClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail3;
+
+  for ( n = 0; n < count; n++ )
+  {
+    i[n] = GET_UShort();
+
+    if ( !d[i[n]] )
+      i[n] = 0;
+  }
+
+  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, FT_UShort ) )
+    goto Fail3;
+
+  l = cpcr->Lookahead;
+  d = ccpf2->LookaheadClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail2;
+
+  for ( n = 0; n < count; n++ )
+  {
+    l[n] = GET_UShort();
+
+    if ( !d[l[n]] )
+      l[n] = 0;
+  }
+
+  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 FT_Err_Ok;
+
+Fail1:
+  FREE( plr );
+
+Fail2:
+  FREE( l );
+
+Fail3:
+  FREE( i );
+
+Fail4:
+  FREE( b );
+  return error;
+}
+
+
+static void  Free_ChainPosClassRule( HB_ChainPosClassRule*  cpcr,
+				     FT_Memory               memory )
+{
+  FREE( cpcr->PosLookupRecord );
+  FREE( cpcr->Lookahead );
+  FREE( cpcr->Input );
+  FREE( cpcr->Backtrack );
+}
+
+
+/* PosClassSet */
+
+static FT_Error  Load_ChainPosClassSet(
+		   HB_ChainContextPosFormat2*  ccpf2,
+		   HB_ChainPosClassSet*        cpcs,
+		   FT_Stream                    stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n, m, count;
+  FT_ULong                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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_ChainPosClassRule( &cpcr[m], memory );
+
+  FREE( cpcr );
+  return error;
+}
+
+
+static void  Free_ChainPosClassSet( HB_ChainPosClassSet*  cpcs,
+				    FT_Memory              memory )
+{
+  FT_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], memory );
+
+    FREE( cpcr );
+  }
+}
+
+
+static FT_Error GPOS_Load_EmptyOrClassDefinition( HB_ClassDefinition*  cd,
+					     FT_UShort             limit,
+					     FT_ULong              class_offset,
+					     FT_ULong              base_offset,
+					     FT_Stream             stream )
+{
+  FT_Error error;
+  FT_ULong               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, stream );
+
+  if (error == FT_Err_Ok)
+    (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
+
+  return error;
+}
+
+/* ChainContextPosFormat2 */
+
+static FT_Error  Load_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2,
+					FT_Stream                    stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort              n, m, count;
+  FT_ULong               cur_offset, new_offset, base_offset;
+  FT_ULong               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 ) ) != FT_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 = GPOS_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
+					      backtrack_offset, base_offset,
+					      stream ) ) != FT_Err_Ok )
+    goto Fail5;
+  if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
+					      input_offset, base_offset,
+					      stream ) ) != FT_Err_Ok )
+    goto Fail4;
+  if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
+					      lookahead_offset, base_offset,
+					      stream ) ) != FT_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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_ChainPosClassSet( &cpcs[m], memory );
+
+  FREE( cpcs );
+
+Fail2:
+  _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
+
+Fail3:
+  _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef, memory );
+
+Fail4:
+  _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
+
+Fail5:
+  _HB_OPEN_Free_Coverage( &ccpf2->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2,
+				 FT_Memory                    memory )
+{
+  FT_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], memory );
+
+    FREE( cpcs );
+  }
+
+  _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
+  _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef, memory );
+  _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
+
+  _HB_OPEN_Free_Coverage( &ccpf2->Coverage, memory );
+}
+
+
+/* ChainContextPosFormat3 */
+
+static FT_Error  Load_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3,
+					FT_Stream                    stream )
+{
+  FT_Error  error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n, nb, ni, nl, m, count;
+  FT_UShort             backtrack_count, input_count, lookahead_count;
+  FT_ULong              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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( plr );
+
+Fail2:
+  for ( m = 0; m < nl; nl++ )
+    _HB_OPEN_Free_Coverage( &l[m], memory );
+
+  FREE( l );
+
+Fail3:
+  for ( m = 0; m < ni; n++ )
+    _HB_OPEN_Free_Coverage( &i[m], memory );
+
+  FREE( i );
+
+Fail4:
+  for ( m = 0; m < nb; n++ )
+    _HB_OPEN_Free_Coverage( &b[m], memory );
+
+  FREE( b );
+  return error;
+}
+
+
+static void  Free_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3,
+				 FT_Memory                    memory )
+{
+  FT_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], memory );
+
+    FREE( c );
+  }
+
+  if ( ccpf3->InputCoverage )
+  {
+    count = ccpf3->InputGlyphCount;
+    c     = ccpf3->InputCoverage;
+
+    for ( n = 0; n < count; n++ )
+      _HB_OPEN_Free_Coverage( &c[n], memory );
+
+    FREE( c );
+  }
+
+  if ( ccpf3->BacktrackCoverage )
+  {
+    count = ccpf3->BacktrackGlyphCount;
+    c     = ccpf3->BacktrackCoverage;
+
+    for ( n = 0; n < count; n++ )
+      _HB_OPEN_Free_Coverage( &c[n], memory );
+
+    FREE( c );
+  }
+}
+
+
+/* ChainContextPos */
+
+static FT_Error  Load_ChainContextPos( HB_GPOS_SubTable* st,
+				       FT_Stream             stream )
+{
+  FT_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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+static void  Free_ChainContextPos( HB_GPOS_SubTable* st,
+				   FT_Memory             memory )
+{
+  HB_ChainContextPos*  ccp = &st->chain;
+
+  switch ( ccp->PosFormat )
+  {
+  case 1:
+    Free_ChainContextPos1( &ccp->ccpf.ccpf1, memory );
+    break;
+
+  case 2:
+    Free_ChainContextPos2( &ccp->ccpf.ccpf2, memory );
+    break;
+
+  case 3:
+    Free_ChainContextPos3( &ccp->ccpf.ccpf3, memory );
+    break;
+  }
+}
+
+
+static FT_Error  Lookup_ChainContextPos1(
+		   GPOS_Instance*               gpi,
+		   HB_ChainContextPosFormat1*  ccpf1,
+		   HB_Buffer                   buffer,
+		   FT_UShort                    flags,
+		   FT_UShort                    context_length,
+		   int                          nesting_level )
+{
+  FT_UShort          index, property;
+  FT_UShort          i, j, k, num_cpr;
+  FT_UShort          bgc, igc, lgc;
+  FT_Error           error;
+  HB_GPOSHeader*    gpos = gpi->gpos;
+
+  HB_ChainPosRule*  cpr;
+  HB_ChainPosRule   curr_cpr;
+  HB_GDEFHeader*    gdef;
+
+
+  gdef = gpos->gdef;
+
+  if ( CHECK_Property( gdef, 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 ) )
+	{
+	  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 ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  return error;
+
+	if ( j + igc - i + lgc == 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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  return error;
+
+	if ( j + lgc - i == 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 FT_Error  Lookup_ChainContextPos2(
+		   GPOS_Instance*               gpi,
+		   HB_ChainContextPosFormat2*  ccpf2,
+		   HB_Buffer                   buffer,
+		   FT_UShort                    flags,
+		   FT_UShort                    context_length,
+		   int                          nesting_level )
+{
+  FT_UShort              index, property;
+  FT_Memory              memory = gpi->face->memory;
+  FT_Error               error;
+  FT_UShort              i, j, k;
+  FT_UShort              bgc, igc, lgc;
+  FT_UShort              known_backtrack_classes,
+			 known_input_classes,
+			 known_lookahead_classes;
+
+  FT_UShort*             backtrack_classes;
+  FT_UShort*             input_classes;
+  FT_UShort*             lookahead_classes;
+
+  FT_UShort*             bc;
+  FT_UShort*             ic;
+  FT_UShort*             lc;
+  HB_GPOSHeader*        gpos = gpi->gpos;
+
+  HB_ChainPosClassSet*  cpcs;
+  HB_ChainPosClassRule  cpcr;
+  HB_GDEFHeader*        gdef;
+
+
+  gdef = gpos->gdef;
+
+  if ( CHECK_Property( gdef, 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, FT_UShort ) )
+    return error;
+  known_backtrack_classes = 0;
+
+  if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, FT_UShort ) )
+    goto End3;
+  known_input_classes = 1;
+
+  if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, FT_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 = HB_Err_Invalid_GPOS_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 ) )
+	{
+	  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 ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  goto End1;
+
+	if ( j + igc - i + lgc == 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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  goto End1;
+
+	if ( j + lgc - i == 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 FT_Error  Lookup_ChainContextPos3(
+		   GPOS_Instance*               gpi,
+		   HB_ChainContextPosFormat3*  ccpf3,
+		   HB_Buffer                   buffer,
+		   FT_UShort                    flags,
+		   FT_UShort                    context_length,
+		   int                          nesting_level )
+{
+  FT_UShort        index, i, j, property;
+  FT_UShort        bgc, igc, lgc;
+  FT_Error         error;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+
+  HB_Coverage*    bc;
+  HB_Coverage*    ic;
+  HB_Coverage*    lc;
+  HB_GDEFHeader*  gdef;
+
+
+  gdef = gpos->gdef;
+
+  if ( CHECK_Property( gdef, 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 ( CHECK_Property( gdef, 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 ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    {
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+
+      if ( j + igc - i + lgc == 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( gdef, IN_ITEM( j ), flags, &property ) )
+    {
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+
+      if ( j + lgc - i == 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 FT_Error  Lookup_ChainContextPos(
+		   GPOS_Instance*        gpi,
+		   HB_GPOS_SubTable* st,
+		   HB_Buffer            buffer,
+		   FT_UShort             flags,
+		   FT_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 HB_Err_Invalid_GPOS_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+
+/***********
+ * GPOS API
+ ***********/
+
+
+
+FT_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
+				 FT_ULong         script_tag,
+				 FT_UShort*       script_index )
+{
+  FT_UShort          n;
+
+  HB_ScriptList*    sl;
+  HB_ScriptRecord*  sr;
+
+
+  if ( !gpos || !script_index )
+    return FT_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 FT_Err_Ok;
+    }
+
+  return HB_Err_Not_Covered;
+}
+
+
+
+FT_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
+				   FT_ULong         language_tag,
+				   FT_UShort        script_index,
+				   FT_UShort*       language_index,
+				   FT_UShort*       req_feature_index )
+{
+  FT_UShort           n;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+
+
+  if ( !gpos || !language_index || !req_feature_index )
+    return FT_Err_Invalid_Argument;
+
+  sl = &gpos->ScriptList;
+  sr = sl->ScriptRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_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 FT_Err_Ok;
+    }
+
+  return HB_Err_Not_Covered;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+   default language (DefaultLangSys)                              */
+
+
+FT_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
+				  FT_ULong         feature_tag,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_UShort*       feature_index )
+{
+  FT_UShort           n;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+  HB_LangSys*        ls;
+  FT_UShort*          fi;
+
+  HB_FeatureList*    fl;
+  HB_FeatureRecord*  fr;
+
+
+  if ( !gpos || !feature_index )
+    return FT_Err_Invalid_Argument;
+
+  sl = &gpos->ScriptList;
+  sr = sl->ScriptRecord;
+
+  fl = &gpos->FeatureList;
+  fr = fl->FeatureRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_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 FT_Err_Invalid_Argument;
+
+    ls = &lsr[language_index].LangSys;
+  }
+
+  fi = ls->FeatureIndex;
+
+  for ( n = 0; n < ls->FeatureCount; n++ )
+  {
+    if ( fi[n] >= fl->FeatureCount )
+      return HB_Err_Invalid_GPOS_SubTable_Format;
+
+    if ( feature_tag == fr[fi[n]].FeatureTag )
+    {
+      *feature_index = fi[n];
+
+      return FT_Err_Ok;
+    }
+  }
+
+  return HB_Err_Not_Covered;
+}
+
+
+/* The next three functions return a null-terminated list */
+
+
+FT_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
+				 FT_ULong**       script_tag_list )
+{
+  FT_Error           error;
+  FT_Memory          memory = gpos->memory;
+  FT_UShort          n;
+  FT_ULong*          stl;
+
+  HB_ScriptList*    sl;
+  HB_ScriptRecord*  sr;
+
+
+  if ( !gpos || !script_tag_list )
+    return FT_Err_Invalid_Argument;
+
+  sl = &gpos->ScriptList;
+  sr = sl->ScriptRecord;
+
+  if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) )
+    return error;
+
+  for ( n = 0; n < sl->ScriptCount; n++ )
+    stl[n] = sr[n].ScriptTag;
+  stl[n] = 0;
+
+  *script_tag_list = stl;
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
+				   FT_UShort        script_index,
+				   FT_ULong**       language_tag_list )
+{
+  FT_Error            error;
+  FT_Memory           memory = gpos->memory;
+  FT_UShort           n;
+  FT_ULong*           ltl;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+
+
+  if ( !gpos || !language_tag_list )
+    return FT_Err_Invalid_Argument;
+
+  sl = &gpos->ScriptList;
+  sr = sl->ScriptRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_Err_Invalid_Argument;
+
+  s   = &sr[script_index].Script;
+  lsr = s->LangSysRecord;
+
+  if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) )
+    return error;
+
+  for ( n = 0; n < s->LangSysCount; n++ )
+    ltl[n] = lsr[n].LangSysTag;
+  ltl[n] = 0;
+
+  *language_tag_list = ltl;
+
+  return FT_Err_Ok;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+   default language (DefaultLangSys)                              */
+
+
+FT_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_ULong**       feature_tag_list )
+{
+  FT_UShort           n;
+  FT_Error            error;
+  FT_Memory           memory = gpos->memory;
+  FT_ULong*           ftl;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+  HB_LangSys*        ls;
+  FT_UShort*          fi;
+
+  HB_FeatureList*    fl;
+  HB_FeatureRecord*  fr;
+
+
+  if ( !gpos || !feature_tag_list )
+    return FT_Err_Invalid_Argument;
+
+  sl = &gpos->ScriptList;
+  sr = sl->ScriptRecord;
+
+  fl = &gpos->FeatureList;
+  fr = fl->FeatureRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_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 FT_Err_Invalid_Argument;
+
+    ls = &lsr[language_index].LangSys;
+  }
+
+  fi = ls->FeatureIndex;
+
+  if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) )
+    return error;
+
+  for ( n = 0; n < ls->FeatureCount; n++ )
+  {
+    if ( fi[n] >= fl->FeatureCount )
+    {
+      FREE( ftl );
+      return HB_Err_Invalid_GPOS_SubTable_Format;
+    }
+    ftl[n] = fr[fi[n]].FeatureTag;
+  }
+  ftl[n] = 0;
+
+  *feature_tag_list = ftl;
+
+  return FT_Err_Ok;
+}
+
+
+typedef FT_Error  (*Lookup_Pos_Func_Type)  ( GPOS_Instance*    gpi,
+					     HB_GPOS_SubTable* st,
+					     HB_Buffer        buffer,
+					     FT_UShort         flags,
+					     FT_UShort         context_length,
+					     int               nesting_level );
+static const Lookup_Pos_Func_Type Lookup_Pos_Call_Table[] = {
+  Lookup_DefaultPos,
+  Lookup_SinglePos,		/* HB_GPOS_LOOKUP_SINGLE     1 */
+  Lookup_PairPos,		/* HB_GPOS_LOOKUP_PAIR       2 */
+  Lookup_CursivePos,		/* HB_GPOS_LOOKUP_CURSIVE    3 */
+  Lookup_MarkBasePos,		/* HB_GPOS_LOOKUP_MARKBASE   4 */
+  Lookup_MarkLigPos,		/* HB_GPOS_LOOKUP_MARKLIG    5 */
+  Lookup_MarkMarkPos,		/* HB_GPOS_LOOKUP_MARKMARK   6 */
+  Lookup_ContextPos,		/* HB_GPOS_LOOKUP_CONTEXT    7 */
+  Lookup_ChainContextPos,	/* HB_GPOS_LOOKUP_CHAIN      8 */
+  Lookup_DefaultPos,		/* HB_GPOS_LOOKUP_EXTENSION  9 */
+};
+
+/* Do an individual subtable lookup.  Returns FT_Err_Ok if positioning
+   has been done, or HB_Err_Not_Covered if not.                        */
+static FT_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
+				       FT_UShort         lookup_index,
+				       HB_Buffer        buffer,
+				       FT_UShort         context_length,
+				       int               nesting_level )
+{
+  FT_Error             error = HB_Err_Not_Covered;
+  FT_UShort            i, flags, lookup_count;
+  HB_GPOSHeader*       gpos = gpi->gpos;
+  HB_Lookup*           lo;
+  int		       lookup_type;
+  Lookup_Pos_Func_Type Func;
+
+
+  nesting_level++;
+
+  if ( nesting_level > HB_MAX_NESTING_LEVEL )
+    return HB_Err_Too_Many_Nested_Contexts;
+
+  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;
+  if (lookup_type >= ARRAY_LEN (Lookup_Pos_Call_Table))
+    lookup_type = 0;
+  Func = Lookup_Pos_Call_Table[lookup_type];
+
+  for ( i = 0; i < lo->SubTableCount; i++ )
+  {
+    error = Func ( gpi,
+		   &lo->SubTable[i].st.gpos,
+		   buffer,
+		   flags, context_length,
+		   nesting_level );
+
+    /* 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;
+}
+
+
+static FT_Error  Load_DefaultPos( HB_GPOS_SubTable* st,
+				  FT_Stream         stream )
+{
+  return HB_Err_Invalid_GPOS_SubTable_Format;
+}
+
+typedef FT_Error  (*Load_Pos_Func_Type)( HB_GPOS_SubTable* st,
+					 FT_Stream         stream );
+static const Load_Pos_Func_Type Load_Pos_Call_Table[] = {
+  Load_DefaultPos,
+  Load_SinglePos,		/* HB_GPOS_LOOKUP_SINGLE     1 */
+  Load_PairPos,			/* HB_GPOS_LOOKUP_PAIR       2 */
+  Load_CursivePos,		/* HB_GPOS_LOOKUP_CURSIVE    3 */
+  Load_MarkBasePos,		/* HB_GPOS_LOOKUP_MARKBASE   4 */
+  Load_MarkLigPos,		/* HB_GPOS_LOOKUP_MARKLIG    5 */
+  Load_MarkMarkPos,		/* HB_GPOS_LOOKUP_MARKMARK   6 */
+  Load_ContextPos,		/* HB_GPOS_LOOKUP_CONTEXT    7 */
+  Load_ChainContextPos,		/* HB_GPOS_LOOKUP_CHAIN      8 */
+  Load_DefaultPos,		/* HB_GPOS_LOOKUP_EXTENSION  9 */
+};
+
+FT_Error  _HB_GPOS_Load_SubTable( HB_GPOS_SubTable*  st,
+				  FT_Stream     stream,
+				  FT_UShort     lookup_type )
+{
+  Load_Pos_Func_Type Func;
+
+  if (lookup_type >= ARRAY_LEN (Load_Pos_Call_Table))
+    lookup_type = 0;
+
+  Func = Load_Pos_Call_Table[lookup_type];
+
+  return Func ( st, stream );
+}
+
+
+static void  Free_DefaultPos( HB_GPOS_SubTable* st,
+			      FT_Memory         memory )
+{
+}
+
+typedef void (*Free_Pos_Func_Type)( HB_GPOS_SubTable* st,
+				    FT_Memory         memory );
+static const Free_Pos_Func_Type Free_Pos_Call_Table[] = {
+  Free_DefaultPos,
+  Free_SinglePos,		/* HB_GPOS_LOOKUP_SINGLE     1 */
+  Free_PairPos,			/* HB_GPOS_LOOKUP_PAIR       2 */
+  Free_CursivePos,		/* HB_GPOS_LOOKUP_CURSIVE    3 */
+  Free_MarkBasePos,		/* HB_GPOS_LOOKUP_MARKBASE   4 */
+  Free_MarkLigPos,		/* HB_GPOS_LOOKUP_MARKLIG    5 */
+  Free_MarkMarkPos,		/* HB_GPOS_LOOKUP_MARKMARK   6 */
+  Free_ContextPos,		/* HB_GPOS_LOOKUP_CONTEXT    7 */
+  Free_ChainContextPos,		/* HB_GPOS_LOOKUP_CHAIN      8 */
+  Free_DefaultPos,		/* HB_GPOS_LOOKUP_EXTENSION  9 */
+};
+
+void  _HB_GPOS_Free_SubTable( HB_GPOS_SubTable*  st,
+			      FT_Memory     memory,
+			      FT_UShort     lookup_type )
+{
+  Free_Pos_Func_Type Func;
+
+  if (lookup_type >= ARRAY_LEN (Free_Pos_Call_Table))
+    lookup_type = 0;
+
+  Func = Free_Pos_Call_Table[lookup_type];
+
+  Func ( st, memory );
+}
+
+
+
+/* apply one lookup to the input string object */
+
+static FT_Error  GPOS_Do_String_Lookup( GPOS_Instance*    gpi,
+				   FT_UShort         lookup_index,
+				   HB_Buffer        buffer )
+{
+  FT_Error         error, retError = HB_Err_Not_Covered;
+  HB_GPOSHeader*  gpos = gpi->gpos;
+
+  FT_UInt*  properties = gpos->LookupList.Properties;
+
+  int       nesting_level = 0;
+
+
+  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] )
+    {
+      /* 0xFFFF indicates that we don't have a context length yet. */
+
+      /* 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,
+				    0xFFFF, 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 FT_Error  Position_CursiveChain ( HB_Buffer     buffer )
+{
+  FT_ULong   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 FT_Err_Ok;
+}
+
+
+FT_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
+			       FT_UShort        feature_index,
+			       FT_UInt          property )
+{
+  FT_UShort    i;
+
+  HB_Feature  feature;
+  FT_UInt*     properties;
+  FT_UShort*   index;
+  FT_UShort    lookup_count;
+
+  /* Each feature can only be added once */
+  
+  if ( !gpos ||
+       feature_index >= gpos->FeatureList.FeatureCount ||
+       gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
+    return FT_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++ )
+  {
+    FT_UShort lookup_index = index[i];
+    if (lookup_index < lookup_count)
+      properties[lookup_index] |= property;
+  }
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos )
+{
+  FT_UShort i;
+
+  FT_UInt*  properties;
+
+
+  if ( !gpos )
+    return FT_Err_Invalid_Argument;
+
+  gpos->FeatureList.ApplyCount = 0;
+
+  properties = gpos->LookupList.Properties;
+
+  for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
+    properties[i] = 0;
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GPOS_Register_Glyph_Function( HB_GPOSHeader*    gpos,
+					   HB_GlyphFunction  gfunc )
+{
+  if ( !gpos )
+    return FT_Err_Invalid_Argument;
+
+  gpos->gfunc = gfunc;
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GPOS_Register_MM_Function( HB_GPOSHeader*  gpos,
+					HB_MMFunction   mmfunc,
+					void*            data )
+{
+  if ( !gpos )
+    return FT_Err_Invalid_Argument;
+
+  gpos->mmfunc = mmfunc;
+  gpos->data   = data;
+
+  return FT_Err_Ok;
+}
+
+/* If `dvi' is TRUE, glyph contour points for anchor points and device
+   tables are ignored -- you will get device independent values.         */
+
+
+FT_Error  HB_GPOS_Apply_String( FT_Face            face,
+				HB_GPOSHeader*    gpos,
+				FT_UShort          load_flags,
+				HB_Buffer         buffer,
+				FT_Bool            dvi,
+				FT_Bool            r2l )
+{
+  FT_Error       error, retError = HB_Err_Not_Covered;
+  GPOS_Instance  gpi;
+  FT_UShort      i, j, feature_index, lookup_count;
+  HB_Feature    feature;
+
+  if ( !face || !gpos ||
+       !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length )
+    return FT_Err_Invalid_Argument;
+
+  gpi.face       = face;
+  gpi.gpos       = gpos;
+  gpi.load_flags = load_flags;
+  gpi.r2l        = r2l;
+  gpi.dvi        = dvi;
+  
+  lookup_count = gpos->LookupList.LookupCount;
+
+  for ( i = 0; i < gpos->FeatureList.ApplyCount; i++ )
+  { 
+    /* index of i'th feature */
+    feature_index = gpos->FeatureList.ApplyOrder[i];
+    feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
+
+    for ( j = 0; j < feature.LookupListCount; j++ )
+    {
+      FT_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;
+    }
+  }
+  
+  error = Position_CursiveChain ( buffer );
+  if ( error )
+    return error;
+
+  return retError;
+}
+
+/* END */
diff --git a/src/harfbuzz-gpos.h b/src/harfbuzz-gpos.h
new file mode 100644
index 0000000..1c67027
--- /dev/null
+++ b/src/harfbuzz-gpos.h
@@ -0,0 +1,168 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_GPOS_H
+#define HARFBUZZ_GPOS_H
+
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-buffer.h"
+
+FT_BEGIN_HEADER
+
+#define HB_Err_Invalid_GPOS_SubTable_Format  0x1020
+#define HB_Err_Invalid_GPOS_SubTable         0x1021
+
+
+/* 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.  _glyph can be computed with
+
+      _glyph = HANDLE_Glyph( glyph )                                    */
+
+typedef FT_Error  (*HB_GlyphFunction)(FT_Face      face,
+				       FT_UInt      glyphIndex,
+				       FT_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 FT_Error  (*HB_MMFunction)(FT_Face      face,
+				    FT_UShort    metric_id,
+				    FT_Pos*      metric_value,
+				    void*        data );
+
+
+struct  HB_GPOSHeader_
+{
+  FT_Memory          memory;
+  
+  FT_Fixed           Version;
+
+  HB_ScriptList     ScriptList;
+  HB_FeatureList    FeatureList;
+  HB_LookupList     LookupList;
+
+  HB_GDEFHeader*    gdef;
+
+  /* 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;
+
+
+FT_Error  HB_Load_GPOS_Table( FT_Face          face,
+			      HB_GPOSHeader** gpos,
+			      HB_GDEFHeader*  gdef );
+
+
+FT_Error  HB_Done_GPOS_Table( HB_GPOSHeader* gpos );
+
+
+FT_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
+				 FT_ULong         script_tag,
+				 FT_UShort*       script_index );
+
+FT_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
+				   FT_ULong         language_tag,
+				   FT_UShort        script_index,
+				   FT_UShort*       language_index,
+				   FT_UShort*       req_feature_index );
+
+FT_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
+				  FT_ULong         feature_tag,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_UShort*       feature_index );
+
+
+FT_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
+				 FT_ULong**       script_tag_list );
+
+FT_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
+				   FT_UShort        script_index,
+				   FT_ULong**       language_tag_list );
+
+FT_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_ULong**       feature_tag_list );
+
+
+FT_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
+			       FT_UShort        feature_index,
+			       FT_UInt          property );
+
+FT_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos );
+
+
+FT_Error  HB_GPOS_Register_Glyph_Function( HB_GPOSHeader*    gpos,
+					   HB_GlyphFunction  gfunc );
+
+
+FT_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.         */
+
+
+FT_Error  HB_GPOS_Apply_String( FT_Face           face,
+				HB_GPOSHeader*   gpos,
+				FT_UShort         load_flags,
+				HB_Buffer        buffer,
+				FT_Bool           dvi,
+				FT_Bool           r2l );
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_GPOS_H */
diff --git a/src/harfbuzz-gsub-private.h b/src/harfbuzz-gsub-private.h
new file mode 100644
index 0000000..84c08df
--- /dev/null
+++ b/src/harfbuzz-gsub-private.h
@@ -0,0 +1,448 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_GSUB_PRIVATE_H
+#define HARFBUZZ_GSUB_PRIVATE_H
+
+#include "harfbuzz-gsub.h"
+
+FT_BEGIN_HEADER
+
+
+typedef union HB_GSUB_SubTable_  HB_GSUB_SubTable;
+
+/* LookupType 1 */
+
+struct  HB_SingleSubstFormat1_
+{
+  FT_Short  DeltaGlyphID;             /* constant added to get
+					 substitution glyph index */
+};
+
+typedef struct HB_SingleSubstFormat1_  HB_SingleSubstFormat1;
+
+
+struct  HB_SingleSubstFormat2_
+{
+  FT_UShort   GlyphCount;             /* number of glyph IDs in
+					 Substitute array              */
+  FT_UShort*  Substitute;             /* array of substitute glyph IDs */
+};
+
+typedef struct HB_SingleSubstFormat2_  HB_SingleSubstFormat2;
+
+
+struct  HB_SingleSubst_
+{
+  FT_UShort     SubstFormat;          /* 1 or 2         */
+  HB_Coverage  Coverage;             /* Coverage table */
+
+  union
+  {
+    HB_SingleSubstFormat1  ssf1;
+    HB_SingleSubstFormat2  ssf2;
+  } ssf;
+};
+
+typedef struct HB_SingleSubst_  HB_SingleSubst;
+
+
+/* LookupType 2 */
+
+struct  HB_Sequence_
+{
+  FT_UShort   GlyphCount;             /* number of glyph IDs in the
+					 Substitute array           */
+  FT_UShort*  Substitute;             /* string of glyph IDs to
+					 substitute                 */
+};
+
+typedef struct HB_Sequence_  HB_Sequence;
+
+
+struct  HB_MultipleSubst_
+{
+  FT_UShort      SubstFormat;         /* always 1                  */
+  HB_Coverage   Coverage;            /* Coverage table            */
+  FT_UShort      SequenceCount;       /* number of Sequence tables */
+  HB_Sequence*  Sequence;            /* array of Sequence tables  */
+};
+
+typedef struct HB_MultipleSubst_  HB_MultipleSubst;
+
+
+/* LookupType 3 */
+
+struct  HB_AlternateSet_
+{
+  FT_UShort   GlyphCount;             /* number of glyph IDs in the
+					 Alternate array              */
+  FT_UShort*  Alternate;              /* array of alternate glyph IDs */
+};
+
+typedef struct HB_AlternateSet_  HB_AlternateSet;
+
+
+struct  HB_AlternateSubst_
+{
+  FT_UShort          SubstFormat;     /* always 1                      */
+  HB_Coverage       Coverage;        /* Coverage table                */
+  FT_UShort          AlternateSetCount;
+				      /* number of AlternateSet tables */
+  HB_AlternateSet*  AlternateSet;    /* array of AlternateSet tables  */
+};
+
+typedef struct HB_AlternateSubst_  HB_AlternateSubst;
+
+
+/* LookupType 4 */
+
+struct  HB_Ligature_
+{
+  FT_UShort   LigGlyph;               /* glyphID of ligature
+					 to substitute                    */
+  FT_UShort   ComponentCount;         /* number of components in ligature */
+  FT_UShort*  Component;              /* array of component glyph IDs     */
+};
+
+typedef struct HB_Ligature_  HB_Ligature;
+
+
+struct  HB_LigatureSet_
+{
+  FT_UShort      LigatureCount;       /* number of Ligature tables */
+  HB_Ligature*  Ligature;            /* array of Ligature tables  */
+};
+
+typedef struct HB_LigatureSet_  HB_LigatureSet;
+
+
+struct  HB_LigatureSubst_
+{
+  FT_UShort         SubstFormat;      /* always 1                     */
+  HB_Coverage      Coverage;         /* Coverage table               */
+  FT_UShort         LigatureSetCount; /* number of LigatureSet tables */
+  HB_LigatureSet*  LigatureSet;      /* array of LigatureSet tables  */
+};
+
+typedef struct HB_LigatureSubst_  HB_LigatureSubst;
+
+
+/* needed by both lookup type 5 and 6 */
+
+struct  HB_SubstLookupRecord_
+{
+  FT_UShort  SequenceIndex;           /* index into current
+					 glyph sequence               */
+  FT_UShort  LookupListIndex;         /* Lookup to apply to that pos. */
+};
+
+typedef struct HB_SubstLookupRecord_  HB_SubstLookupRecord;
+
+
+/* LookupType 5 */
+
+struct  HB_SubRule_
+{
+  FT_UShort               GlyphCount; /* total number of input glyphs */
+  FT_UShort               SubstCount; /* number of SubstLookupRecord
+					 tables                       */
+  FT_UShort*              Input;      /* array of input glyph IDs     */
+  HB_SubstLookupRecord*  SubstLookupRecord;
+				      /* array of SubstLookupRecord
+					 tables                       */
+};
+
+typedef struct HB_SubRule_  HB_SubRule;
+
+
+struct  HB_SubRuleSet_
+{
+  FT_UShort     SubRuleCount;         /* number of SubRule tables */
+  HB_SubRule*  SubRule;              /* array of SubRule tables  */
+};
+
+typedef struct HB_SubRuleSet_  HB_SubRuleSet;
+
+
+struct  HB_ContextSubstFormat1_
+{
+  HB_Coverage     Coverage;          /* Coverage table              */
+  FT_UShort        SubRuleSetCount;   /* number of SubRuleSet tables */
+  HB_SubRuleSet*  SubRuleSet;        /* array of SubRuleSet tables  */
+};
+
+typedef struct HB_ContextSubstFormat1_  HB_ContextSubstFormat1;
+
+
+struct  HB_SubClassRule_
+{
+  FT_UShort               GlyphCount; /* total number of context classes */
+  FT_UShort               SubstCount; /* number of SubstLookupRecord
+					 tables                          */
+  FT_UShort*              Class;      /* array of classes                */
+  HB_SubstLookupRecord*  SubstLookupRecord;
+				      /* array of SubstLookupRecord
+					 tables                          */
+};
+
+typedef struct HB_SubClassRule_  HB_SubClassRule;
+
+
+struct  HB_SubClassSet_
+{
+  FT_UShort          SubClassRuleCount;
+				      /* number of SubClassRule tables */
+  HB_SubClassRule*  SubClassRule;    /* array of SubClassRule tables  */
+};
+
+typedef struct HB_SubClassSet_  HB_SubClassSet;
+
+
+/* The `MaxContextLength' field is not defined in the TTO specification
+   but simplifies the implementation of this format.  It holds the
+   maximal context length used in the context rules.                    */
+
+struct  HB_ContextSubstFormat2_
+{
+  FT_UShort            MaxContextLength;
+				      /* maximal context length       */
+  HB_Coverage         Coverage;      /* Coverage table               */
+  HB_ClassDefinition  ClassDef;      /* ClassDef table               */
+  FT_UShort            SubClassSetCount;
+				      /* number of SubClassSet tables */
+  HB_SubClassSet*     SubClassSet;   /* array of SubClassSet tables  */
+};
+
+typedef struct HB_ContextSubstFormat2_  HB_ContextSubstFormat2;
+
+
+struct  HB_ContextSubstFormat3_
+{
+  FT_UShort               GlyphCount; /* number of input glyphs        */
+  FT_UShort               SubstCount; /* number of SubstLookupRecords  */
+  HB_Coverage*           Coverage;   /* array of Coverage tables      */
+  HB_SubstLookupRecord*  SubstLookupRecord;
+				      /* array of substitution lookups */
+};
+
+typedef struct HB_ContextSubstFormat3_  HB_ContextSubstFormat3;
+
+
+struct  HB_ContextSubst_
+{
+  FT_UShort  SubstFormat;             /* 1, 2, or 3 */
+
+  union
+  {
+    HB_ContextSubstFormat1  csf1;
+    HB_ContextSubstFormat2  csf2;
+    HB_ContextSubstFormat3  csf3;
+  } csf;
+};
+
+typedef struct HB_ContextSubst_  HB_ContextSubst;
+
+
+/* LookupType 6 */
+
+struct  HB_ChainSubRule_
+{
+  FT_UShort               BacktrackGlyphCount;
+				      /* total number of backtrack glyphs */
+  FT_UShort*              Backtrack;  /* array of backtrack glyph IDs     */
+  FT_UShort               InputGlyphCount;
+				      /* total number of input glyphs     */
+  FT_UShort*              Input;      /* array of input glyph IDs         */
+  FT_UShort               LookaheadGlyphCount;
+				      /* total number of lookahead glyphs */
+  FT_UShort*              Lookahead;  /* array of lookahead glyph IDs     */
+  FT_UShort               SubstCount; /* number of SubstLookupRecords     */
+  HB_SubstLookupRecord*  SubstLookupRecord;
+				      /* array of SubstLookupRecords      */
+};
+
+typedef struct HB_ChainSubRule_  HB_ChainSubRule;
+
+
+struct  HB_ChainSubRuleSet_
+{
+  FT_UShort          ChainSubRuleCount;
+				      /* number of ChainSubRule tables */
+  HB_ChainSubRule*  ChainSubRule;    /* array of ChainSubRule tables  */
+};
+
+typedef struct HB_ChainSubRuleSet_  HB_ChainSubRuleSet;
+
+
+struct  HB_ChainContextSubstFormat1_
+{
+  HB_Coverage          Coverage;     /* Coverage table                   */
+  FT_UShort             ChainSubRuleSetCount;
+				      /* number of ChainSubRuleSet tables */
+  HB_ChainSubRuleSet*  ChainSubRuleSet;
+				      /* array of ChainSubRuleSet tables  */
+};
+
+typedef struct HB_ChainContextSubstFormat1_  HB_ChainContextSubstFormat1;
+
+
+struct  HB_ChainSubClassRule_
+{
+  FT_UShort               BacktrackGlyphCount;
+				      /* total number of backtrack
+					 classes                         */
+  FT_UShort*              Backtrack;  /* array of backtrack classes      */
+  FT_UShort               InputGlyphCount;
+				      /* total number of context classes */
+  FT_UShort*              Input;      /* array of context classes        */
+  FT_UShort               LookaheadGlyphCount;
+				      /* total number of lookahead
+					 classes                         */
+  FT_UShort*              Lookahead;  /* array of lookahead classes      */
+  FT_UShort               SubstCount; /* number of SubstLookupRecords    */
+  HB_SubstLookupRecord*  SubstLookupRecord;
+				      /* array of substitution lookups   */
+};
+
+typedef struct HB_ChainSubClassRule_  HB_ChainSubClassRule;
+
+
+struct  HB_ChainSubClassSet_
+{
+  FT_UShort               ChainSubClassRuleCount;
+				      /* number of ChainSubClassRule
+					 tables                      */
+  HB_ChainSubClassRule*  ChainSubClassRule;
+				      /* array of ChainSubClassRule
+					 tables                      */
+};
+
+typedef struct HB_ChainSubClassSet_  HB_ChainSubClassSet;
+
+
+/* The `MaxXXXLength' fields are not defined in the TTO specification
+   but simplifies the implementation of this format.  It holds the
+   maximal context length used in the specific context rules.         */
+
+struct  HB_ChainContextSubstFormat2_
+{
+  HB_Coverage           Coverage;    /* Coverage table             */
+
+  FT_UShort              MaxBacktrackLength;
+				      /* maximal backtrack length   */
+  HB_ClassDefinition    BacktrackClassDef;
+				      /* BacktrackClassDef table    */
+  FT_UShort              MaxInputLength;
+				      /* maximal input length       */
+  HB_ClassDefinition    InputClassDef;
+				      /* InputClassDef table        */
+  FT_UShort              MaxLookaheadLength;
+				      /* maximal lookahead length   */
+  HB_ClassDefinition    LookaheadClassDef;
+				      /* LookaheadClassDef table    */
+
+  FT_UShort              ChainSubClassSetCount;
+				      /* number of ChainSubClassSet
+					 tables                     */
+  HB_ChainSubClassSet*  ChainSubClassSet;
+				      /* array of ChainSubClassSet
+					 tables                     */
+};
+
+typedef struct HB_ChainContextSubstFormat2_  HB_ChainContextSubstFormat2;
+
+
+struct  HB_ChainContextSubstFormat3_
+{
+  FT_UShort               BacktrackGlyphCount;
+				      /* number of backtrack glyphs    */
+  HB_Coverage*           BacktrackCoverage;
+				      /* array of backtrack Coverage
+					 tables                        */
+  FT_UShort               InputGlyphCount;
+				      /* number of input glyphs        */
+  HB_Coverage*           InputCoverage;
+				      /* array of input coverage
+					 tables                        */
+  FT_UShort               LookaheadGlyphCount;
+				      /* number of lookahead glyphs    */
+  HB_Coverage*           LookaheadCoverage;
+				      /* array of lookahead coverage
+					 tables                        */
+  FT_UShort               SubstCount; /* number of SubstLookupRecords  */
+  HB_SubstLookupRecord*  SubstLookupRecord;
+				      /* array of substitution lookups */
+};
+
+typedef struct HB_ChainContextSubstFormat3_  HB_ChainContextSubstFormat3;
+
+
+struct  HB_ChainContextSubst_
+{
+  FT_UShort  SubstFormat;             /* 1, 2, or 3 */
+
+  union
+  {
+    HB_ChainContextSubstFormat1  ccsf1;
+    HB_ChainContextSubstFormat2  ccsf2;
+    HB_ChainContextSubstFormat3  ccsf3;
+  } ccsf;
+};
+
+typedef struct HB_ChainContextSubst_  HB_ChainContextSubst;
+
+
+/* LookupType 8 */
+struct HB_ReverseChainContextSubst_
+{
+  FT_UShort      SubstFormat;         /* always 1 */
+  HB_Coverage   Coverage;	        /* coverage table for input glyphs */
+  FT_UShort      BacktrackGlyphCount; /* number of backtrack glyphs      */
+  HB_Coverage*  BacktrackCoverage;   /* array of backtrack Coverage
+					 tables                          */
+  FT_UShort      LookaheadGlyphCount; /* number of lookahead glyphs      */
+  HB_Coverage*  LookaheadCoverage;   /* array of lookahead Coverage
+					 tables                          */
+  FT_UShort      GlyphCount;          /* number of Glyph IDs             */
+  FT_UShort*     Substitute;          /* array of substitute Glyph ID    */
+};
+
+typedef struct HB_ReverseChainContextSubst_  HB_ReverseChainContextSubst;
+
+
+union  HB_GSUB_SubTable_
+{
+  HB_SingleSubst              single;
+  HB_MultipleSubst            multiple;
+  HB_AlternateSubst           alternate;
+  HB_LigatureSubst            ligature;
+  HB_ContextSubst             context;
+  HB_ChainContextSubst        chain;
+  HB_ReverseChainContextSubst reverse;
+};
+
+
+
+
+
+FT_Error  _HB_GSUB_Load_SubTable( HB_GSUB_SubTable*  st,
+				  FT_Stream     stream,
+				  FT_UShort     lookup_type );
+
+void  _HB_GSUB_Free_SubTable( HB_GSUB_SubTable*  st,
+			      FT_Memory     memory,
+			      FT_UShort     lookup_type );
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_GSUB_PRIVATE_H */
diff --git a/src/harfbuzz-gsub.c b/src/harfbuzz-gsub.c
new file mode 100644
index 0000000..0a69fa6
--- /dev/null
+++ b/src/harfbuzz-gsub.c
@@ -0,0 +1,4581 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#include "harfbuzz-impl.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-open-private.h"
+#include "harfbuzz-gdef-private.h"
+
+#include FT_TRUETYPE_TAGS_H
+
+
+static FT_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader*   gsub,
+				       FT_UShort         lookup_index,
+				       HB_Buffer        buffer,
+				       FT_UShort         context_length,
+				       int               nesting_level );
+
+
+
+/**********************
+ * Auxiliary functions
+ **********************/
+
+
+
+FT_Error  HB_Load_GSUB_Table( FT_Face          face,
+			      HB_GSUBHeader** retptr,
+			      HB_GDEFHeader*  gdef )
+{
+  FT_Stream        stream = face->stream;
+  FT_Memory        memory = face->memory;
+  FT_Error         error;
+  FT_ULong         cur_offset, new_offset, base_offset;
+
+  FT_UShort        i, num_lookups;
+  HB_GSUBHeader*  gsub;
+  HB_Lookup*      lo;
+
+  if ( !retptr )
+    return FT_Err_Invalid_Argument;
+
+  if (( error = _hb_ftglue_face_goto_table( face, TTAG_GSUB, stream ) ))
+    return error;
+
+  base_offset = FILE_Pos();
+
+  if ( ALLOC ( gsub, sizeof( *gsub ) ) )
+    return error;
+
+  gsub->memory = memory;
+
+  /* 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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_Err_Ok )
+    goto Fail2;
+
+  gsub->gdef = gdef;      /* can be NULL */
+
+  /* We now check the LookupFlags for values larger than 0xFF to find
+     out whether we need to load the `MarkAttachClassDef' field of the
+     GDEF table -- this hack is necessary for OpenType 1.2 tables since
+     the version field of the GDEF table hasn't been incremented.
+
+     For constructed GDEF tables, we only load it if
+     `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
+     a constructed mark attach table is not supported currently).       */
+
+  if ( gdef &&
+       gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
+  {
+    lo          = gsub->LookupList.Lookup;
+    num_lookups = gsub->LookupList.LookupCount;
+
+    for ( i = 0; i < num_lookups; i++ )
+    {
+
+      if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+      {
+	if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
+	     ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
+					     256, stream ) ) != FT_Err_Ok )
+	  goto Fail1;
+
+	break;
+      }
+    }
+  }
+
+  *retptr = gsub;
+
+  return FT_Err_Ok;
+
+Fail1:
+  _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB, memory );
+
+Fail2:
+  _HB_OPEN_Free_FeatureList( &gsub->FeatureList, memory );
+
+Fail3:
+  _HB_OPEN_Free_ScriptList( &gsub->ScriptList, memory );
+
+Fail4:
+  FREE ( gsub );
+
+
+  return error;
+}
+
+
+FT_Error   HB_Done_GSUB_Table( HB_GSUBHeader* gsub )
+{
+  FT_Memory memory = gsub->memory;
+  
+  _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB, memory );
+  _HB_OPEN_Free_FeatureList( &gsub->FeatureList, memory );
+  _HB_OPEN_Free_ScriptList( &gsub->ScriptList, memory );
+
+  FREE( gsub );
+
+  return FT_Err_Ok;
+}
+
+/*****************************
+ * SubTable related functions
+ *****************************/
+
+static FT_Error  Lookup_DefaultSubst( HB_GSUBHeader*    gsub,
+				      HB_GSUB_SubTable* st,
+				      HB_Buffer         buffer,
+				      FT_UShort          flags,
+				      FT_UShort          context_length,
+				      int                nesting_level )
+{
+  return HB_Err_Not_Covered;
+}
+
+
+/* LookupType 1 */
+
+/* SingleSubstFormat1 */
+/* SingleSubstFormat2 */
+
+static FT_Error  Load_SingleSubst( HB_GSUB_SubTable* st,
+				   FT_Stream         stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+  HB_SingleSubst*  ss = &st->single;
+
+  FT_UShort n, count;
+  FT_ULong cur_offset, new_offset, base_offset;
+
+  FT_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 ) ) != FT_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, FT_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 HB_Err_Invalid_GSUB_SubTable_Format;
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  FREE( s );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &ss->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_SingleSubst( HB_GSUB_SubTable* st,
+			       FT_Memory         memory )
+{
+  HB_SingleSubst*  ss = &st->single;
+
+  switch ( ss->SubstFormat )
+  {
+  case 1:
+    break;
+
+  case 2:
+    FREE( ss->ssf.ssf2.Substitute );
+    break;
+  }
+
+  _HB_OPEN_Free_Coverage( &ss->Coverage, memory );
+}
+
+
+static FT_Error  Lookup_SingleSubst( HB_GSUBHeader*   gsub,
+				     HB_GSUB_SubTable* st,
+				     HB_Buffer        buffer,
+				     FT_UShort         flags,
+				     FT_UShort         context_length,
+				     int               nesting_level )
+{
+  FT_UShort index, value, property;
+  FT_Error  error;
+  HB_SingleSubst*  ss = &st->single;
+  HB_GDEFHeader*   gdef = gsub->gdef;
+
+
+  if ( context_length != 0xFFFF && context_length < 1 )
+    return HB_Err_Not_Covered;
+
+  if ( CHECK_Property( gdef, 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 ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) )
+      return error;
+    break;
+
+  case 2:
+    if ( index >= ss->ssf.ssf2.GlyphCount )
+      return HB_Err_Invalid_GSUB_SubTable;
+    value = ss->ssf.ssf2.Substitute[index];
+    if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) )
+      return error;
+    break;
+
+  default:
+    return HB_Err_Invalid_GSUB_SubTable;
+  }
+
+  if ( gdef && gdef->NewGlyphClasses )
+  {
+    /* we inherit the old glyph class to the substituted glyph */
+
+    error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
+    if ( error && error != HB_Err_Not_Covered )
+      return error;
+  }
+
+  return FT_Err_Ok;
+}
+
+
+/* LookupType 2 */
+
+/* Sequence */
+
+static FT_Error  Load_Sequence( HB_Sequence*  s,
+				FT_Stream      stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort n, count;
+  FT_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, FT_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 FT_Err_Ok;
+}
+
+
+static void  Free_Sequence( HB_Sequence*  s,
+			    FT_Memory      memory )
+{
+  FREE( s->Substitute );
+}
+
+
+/* MultipleSubstFormat1 */
+
+static FT_Error  Load_MultipleSubst( HB_GSUB_SubTable* st,
+				     FT_Stream         stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+  HB_MultipleSubst*  ms = &st->multiple;
+
+  FT_UShort      n = 0, m, count;
+  FT_ULong       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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_Sequence( &s[m], memory );
+
+  FREE( s );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &ms->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_MultipleSubst( HB_GSUB_SubTable* st,
+				 FT_Memory         memory )
+{
+  FT_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], memory );
+
+    FREE( s );
+  }
+
+  _HB_OPEN_Free_Coverage( &ms->Coverage, memory );
+}
+
+
+static FT_Error  Lookup_MultipleSubst( HB_GSUBHeader*    gsub,
+				       HB_GSUB_SubTable* st,
+				       HB_Buffer         buffer,
+				       FT_UShort          flags,
+				       FT_UShort          context_length,
+				       int                nesting_level )
+{
+  FT_Error  error;
+  FT_UShort index, property, n, count;
+  FT_UShort*s;
+  HB_MultipleSubst*  ms = &st->multiple;
+  HB_GDEFHeader*     gdef = gsub->gdef;
+
+
+  if ( context_length != 0xFFFF && context_length < 1 )
+    return HB_Err_Not_Covered;
+
+  if ( CHECK_Property( gdef, 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 HB_Err_Invalid_GSUB_SubTable;
+
+  count = ms->Sequence[index].GlyphCount;
+  s     = ms->Sequence[index].Substitute;
+
+  if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
+    return error;
+
+  if ( gdef && gdef->NewGlyphClasses )
+  {
+    /* this is a guess only ... */
+
+    if ( property == HB_GDEF_LIGATURE )
+      property = HB_GDEF_BASE_GLYPH;
+
+    for ( n = 0; n < count; n++ )
+    {
+      error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+    }
+  }
+
+  return FT_Err_Ok;
+}
+
+
+/* LookupType 3 */
+
+/* AlternateSet */
+
+static FT_Error  Load_AlternateSet( HB_AlternateSet*  as,
+				    FT_Stream          stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort n, count;
+  FT_UShort*  a;
+
+
+  if ( ACCESS_Frame( 2L ) )
+    return error;
+
+  count = as->GlyphCount = GET_UShort();
+
+  FORGET_Frame();
+
+  as->Alternate = NULL;
+
+  if ( ALLOC_ARRAY( as->Alternate, count, FT_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 FT_Err_Ok;
+}
+
+
+static void  Free_AlternateSet( HB_AlternateSet*  as,
+				FT_Memory          memory )
+{
+  FREE( as->Alternate );
+}
+
+
+/* AlternateSubstFormat1 */
+
+static FT_Error  Load_AlternateSubst( HB_GSUB_SubTable* st,
+				      FT_Stream         stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+  HB_AlternateSubst* as = &st->alternate;
+
+  FT_UShort          n = 0, m, count;
+  FT_ULong           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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_AlternateSet( &aset[m], memory );
+
+  FREE( aset );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &as->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_AlternateSubst( HB_GSUB_SubTable* st,
+				  FT_Memory         memory )
+{
+  FT_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], memory );
+
+    FREE( aset );
+  }
+
+  _HB_OPEN_Free_Coverage( &as->Coverage, memory );
+}
+
+
+static FT_Error  Lookup_AlternateSubst( HB_GSUBHeader*    gsub,
+					HB_GSUB_SubTable* st,
+					HB_Buffer         buffer,
+					FT_UShort          flags,
+					FT_UShort          context_length,
+					int                nesting_level )
+{
+  FT_Error          error;
+  FT_UShort         index, alt_index, property;
+  HB_AlternateSubst* as = &st->alternate;
+  HB_GDEFHeader*     gdef = gsub->gdef;
+
+
+  HB_AlternateSet  aset;
+
+
+  if ( context_length != 0xFFFF && context_length < 1 )
+    return HB_Err_Not_Covered;
+
+  if ( CHECK_Property( gdef, 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;
+
+  if ( ADD_Glyph( buffer, aset.Alternate[alt_index],
+		  0xFFFF, 0xFFFF ) )
+    return error;
+
+  if ( gdef && gdef->NewGlyphClasses )
+  {
+    /* we inherit the old glyph class to the substituted glyph */
+
+    error = _HB_GDEF_Add_Glyph_Property( gdef, aset.Alternate[alt_index],
+				property );
+    if ( error && error != HB_Err_Not_Covered )
+      return error;
+  }
+
+  return FT_Err_Ok;
+}
+
+
+/* LookupType 4 */
+
+/* Ligature */
+
+static FT_Error  Load_Ligature( HB_Ligature*  l,
+				FT_Stream      stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort n, count;
+  FT_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, FT_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 FT_Err_Ok;
+}
+
+
+static void  Free_Ligature( HB_Ligature*  l,
+			    FT_Memory      memory )
+{
+  FREE( l->Component );
+}
+
+
+/* LigatureSet */
+
+static FT_Error  Load_LigatureSet( HB_LigatureSet*  ls,
+				   FT_Stream         stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort      n = 0, m, count;
+  FT_ULong       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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_Ligature( &l[m], memory );
+
+  FREE( l );
+  return error;
+}
+
+
+static void  Free_LigatureSet( HB_LigatureSet*  ls,
+			       FT_Memory         memory )
+{
+  FT_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], memory );
+
+    FREE( l );
+  }
+}
+
+
+/* LigatureSubstFormat1 */
+
+static FT_Error  Load_LigatureSubst( HB_GSUB_SubTable* st,
+				     FT_Stream         stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+  HB_LigatureSubst*  ls = &st->ligature;
+
+  FT_UShort         n = 0, m, count;
+  FT_ULong          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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_LigatureSet( &lset[m], memory );
+
+  FREE( lset );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &ls->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_LigatureSubst( HB_GSUB_SubTable* st,
+				 FT_Memory         memory )
+{
+  FT_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], memory );
+
+    FREE( lset );
+  }
+
+  _HB_OPEN_Free_Coverage( &ls->Coverage, memory );
+}
+
+
+static FT_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
+				       HB_GSUB_SubTable* st,
+				       HB_Buffer         buffer,
+				       FT_UShort          flags,
+				       FT_UShort          context_length,
+				       int                nesting_level )
+{
+  FT_UShort      index, property;
+  FT_Error       error;
+  FT_UShort      numlig, i, j, is_mark, first_is_mark = FALSE;
+  FT_UShort*     c;
+  HB_LigatureSubst*  ls = &st->ligature;
+  HB_GDEFHeader*     gdef = gsub->gdef;
+
+  HB_Ligature*  lig;
+
+
+  if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+    return error;
+
+  if ( property == HB_GDEF_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 HB_Err_Invalid_GSUB_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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  return error;
+
+	if ( j + lig->ComponentCount - i == buffer->in_length )
+	  goto next_ligature;
+	j++;
+      }
+
+      if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+	is_mark = FALSE;
+
+      if ( IN_GLYPH( j ) != c[i - 1] )
+	goto next_ligature;
+    }
+
+    if ( gdef && gdef->NewGlyphClasses )
+    {
+      /* this is just a guess ... */
+
+      error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph,
+				  is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE );
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+    }
+
+    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
+      {
+	FT_UShort ligID = hb_buffer_allocate_ligid( buffer );
+	if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
+			0xFFFF, ligID ) )
+	  return error;
+      }
+    }
+    else
+    {
+      FT_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++ )
+      {
+	while ( CHECK_Property( gdef, IN_CURITEM(),
+				flags, &property ) )
+	  if ( ADD_Glyph( buffer, IN_CURGLYPH(),
+			  i, ligID ) )
+	    return error;
+
+	(buffer->in_pos)++;
+      }
+    }
+
+    return FT_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 FT_Error  Do_ContextSubst( HB_GSUBHeader*        gsub,
+				  FT_UShort              GlyphCount,
+				  FT_UShort              SubstCount,
+				  HB_SubstLookupRecord* subst,
+				  HB_Buffer             buffer,
+				  int                    nesting_level )
+{
+  FT_Error  error;
+  FT_UShort 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 )
+      {
+	/* XXX "can't happen" -- but don't count on it */
+
+	if ( ADD_Glyph( buffer, IN_CURGLYPH(),
+			0xFFFF, 0xFFFF ) )
+	  return error;
+	i++;
+      }
+      else if ( error )
+	return error;
+    }
+    else
+    {
+      /* No substitution for this index */
+
+      if ( ADD_Glyph( buffer, IN_CURGLYPH(),
+		      0xFFFF, 0xFFFF ) )
+	return error;
+      i++;
+    }
+  }
+
+  return FT_Err_Ok;
+}
+
+
+/* LookupType 5 */
+
+/* SubRule */
+
+static FT_Error  Load_SubRule( HB_SubRule*  sr,
+			       FT_Stream     stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n, count;
+  FT_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, FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( slr );
+
+Fail2:
+  FREE( i );
+  return error;
+}
+
+
+static void  Free_SubRule( HB_SubRule*  sr,
+			   FT_Memory     memory )
+{
+  FREE( sr->SubstLookupRecord );
+  FREE( sr->Input );
+}
+
+
+/* SubRuleSet */
+
+static FT_Error  Load_SubRuleSet( HB_SubRuleSet*  srs,
+				  FT_Stream        stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort     n = 0, m, count;
+  FT_ULong      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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_SubRule( &sr[m], memory );
+
+  FREE( sr );
+  return error;
+}
+
+
+static void  Free_SubRuleSet( HB_SubRuleSet*  srs,
+			      FT_Memory        memory )
+{
+  FT_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], memory );
+
+    FREE( sr );
+  }
+}
+
+
+/* ContextSubstFormat1 */
+
+static FT_Error  Load_ContextSubst1( HB_ContextSubstFormat1*  csf1,
+				     FT_Stream                 stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort        n = 0, m, count;
+  FT_ULong         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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_SubRuleSet( &srs[m], memory );
+
+  FREE( srs );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &csf1->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ContextSubst1( HB_ContextSubstFormat1* csf1,
+			    FT_Memory                memory )
+{
+  FT_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], memory );
+
+    FREE( srs );
+  }
+
+  _HB_OPEN_Free_Coverage( &csf1->Coverage, memory );
+}
+
+
+/* SubClassRule */
+
+static FT_Error  Load_SubClassRule( HB_ContextSubstFormat2*  csf2,
+				    HB_SubClassRule*         scr,
+				    FT_Stream                 stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n, count;
+
+  FT_UShort*              c;
+  HB_SubstLookupRecord*  slr;
+  FT_Bool*                d;
+
+
+  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, FT_UShort ) )
+    return error;
+
+  c = scr->Class;
+  d = csf2->ClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail2;
+
+  for ( n = 0; n < count; n++ )
+  {
+    c[n] = GET_UShort();
+
+    /* We check whether the specific class is used at all.  If not,
+       class 0 is used instead.                                     */
+    if ( !d[c[n]] )
+      c[n] = 0;
+  }
+
+  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 FT_Err_Ok;
+
+Fail1:
+  FREE( slr );
+
+Fail2:
+  FREE( c );
+  return error;
+}
+
+
+static void  Free_SubClassRule( HB_SubClassRule*  scr,
+				FT_Memory          memory )
+{
+  FREE( scr->SubstLookupRecord );
+  FREE( scr->Class );
+}
+
+
+/* SubClassSet */
+
+static FT_Error  Load_SubClassSet( HB_ContextSubstFormat2*  csf2,
+				   HB_SubClassSet*          scs,
+				   FT_Stream                 stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort          n = 0, m, count;
+  FT_ULong           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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_SubClassRule( &scr[m], memory );
+
+  FREE( scr );
+  return error;
+}
+
+
+static void  Free_SubClassSet( HB_SubClassSet*  scs,
+			       FT_Memory         memory )
+{
+  FT_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], memory );
+
+    FREE( scr );
+  }
+}
+
+
+/* ContextSubstFormat2 */
+
+static FT_Error  Load_ContextSubst2( HB_ContextSubstFormat2*  csf2,
+				     FT_Stream                 stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort         n = 0, m, count;
+  FT_ULong          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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_SubClassSet( &scs[m], memory );
+
+  FREE( scs );
+
+Fail2:
+  _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef, memory );
+
+Fail3:
+  _HB_OPEN_Free_Coverage( &csf2->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ContextSubst2( HB_ContextSubstFormat2*  csf2,
+			    FT_Memory                 memory )
+{
+  FT_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], memory );
+
+    FREE( scs );
+  }
+
+  _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef, memory );
+  _HB_OPEN_Free_Coverage( &csf2->Coverage, memory );
+}
+
+
+/* ContextSubstFormat3 */
+
+static FT_Error  Load_ContextSubst3( HB_ContextSubstFormat3*  csf3,
+				     FT_Stream                 stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n = 0, m, count;
+  FT_ULong                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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( slr );
+
+Fail2:
+  for ( m = 0; m < n; m++ )
+    _HB_OPEN_Free_Coverage( &c[m], memory );
+
+  FREE( c );
+  return error;
+}
+
+
+static void  Free_ContextSubst3( HB_ContextSubstFormat3*  csf3,
+			    FT_Memory                 memory )
+{
+  FT_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], memory );
+
+    FREE( c );
+  }
+}
+
+
+/* ContextSubst */
+
+static FT_Error  Load_ContextSubst( HB_GSUB_SubTable* st,
+				    FT_Stream         stream )
+{
+  FT_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 HB_Err_Invalid_GSUB_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+static void  Free_ContextSubst( HB_GSUB_SubTable* st,
+			        FT_Memory         memory )
+{
+  HB_ContextSubst*  cs = &st->context;
+
+  switch ( cs->SubstFormat )
+  {
+  case 1:
+    Free_ContextSubst1( &cs->csf.csf1, memory );
+    break;
+
+  case 2:
+    Free_ContextSubst2( &cs->csf.csf2, memory );
+    break;
+
+  case 3:
+    Free_ContextSubst3( &cs->csf.csf3, memory );
+    break;
+  }
+}
+
+
+static FT_Error  Lookup_ContextSubst1( HB_GSUBHeader*          gsub,
+				       HB_ContextSubstFormat1* csf1,
+				       HB_Buffer               buffer,
+				       FT_UShort                flags,
+				       FT_UShort                context_length,
+				       int                      nesting_level )
+{
+  FT_UShort        index, property;
+  FT_UShort        i, j, k, numsr;
+  FT_Error         error;
+
+  HB_SubRule*     sr;
+  HB_GDEFHeader*  gdef;
+
+
+  gdef = gsub->gdef;
+
+  if ( CHECK_Property( gdef, 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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  return error;
+
+	if ( j + sr[k].GlyphCount - i == 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 FT_Error  Lookup_ContextSubst2( HB_GSUBHeader*          gsub,
+				       HB_ContextSubstFormat2* csf2,
+				       HB_Buffer               buffer,
+				       FT_UShort                flags,
+				       FT_UShort                context_length,
+				       int                      nesting_level )
+{
+  FT_UShort          index, property;
+  FT_Error           error;
+  FT_Memory          memory = gsub->memory;
+  FT_UShort          i, j, k, known_classes;
+
+  FT_UShort*         classes;
+  FT_UShort*         cl;
+
+  HB_SubClassSet*   scs;
+  HB_SubClassRule*  sr;
+  HB_GDEFHeader*    gdef;
+
+
+  gdef = gsub->gdef;
+
+  if ( CHECK_Property( gdef, 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 ( ALLOC_ARRAY( classes, csf2->MaxContextLength, FT_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 = HB_Err_Invalid_GSUB_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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  goto End;
+
+	if ( j + sr->GlyphCount - i < 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 FT_Error  Lookup_ContextSubst3( HB_GSUBHeader*          gsub,
+				       HB_ContextSubstFormat3* csf3,
+				       HB_Buffer               buffer,
+				       FT_UShort                flags,
+				       FT_UShort                context_length,
+				       int                      nesting_level )
+{
+  FT_Error         error;
+  FT_UShort        index, i, j, property;
+
+  HB_Coverage*    c;
+  HB_GDEFHeader*  gdef;
+
+
+  gdef = gsub->gdef;
+
+  if ( CHECK_Property( gdef, 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++ )
+  {
+    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    {
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+
+      if ( j + csf3->GlyphCount - i == 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 FT_Error  Lookup_ContextSubst( HB_GSUBHeader*    gsub,
+				      HB_GSUB_SubTable* st,
+				      HB_Buffer         buffer,
+				      FT_UShort          flags,
+				      FT_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 HB_Err_Invalid_GSUB_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+/* LookupType 6 */
+
+/* ChainSubRule */
+
+static FT_Error  Load_ChainSubRule( HB_ChainSubRule*  csr,
+				    FT_Stream          stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n, count;
+  FT_UShort*              b;
+  FT_UShort*              i;
+  FT_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, FT_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, FT_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, FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( slr );
+
+Fail2:
+  FREE( l );
+
+Fail3:
+  FREE( i );
+
+Fail4:
+  FREE( b );
+  return error;
+}
+
+
+static void  Free_ChainSubRule( HB_ChainSubRule*  csr,
+				FT_Memory          memory )
+{
+  FREE( csr->SubstLookupRecord );
+  FREE( csr->Lookahead );
+  FREE( csr->Input );
+  FREE( csr->Backtrack );
+}
+
+
+/* ChainSubRuleSet */
+
+static FT_Error  Load_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs,
+				       FT_Stream             stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort          n = 0, m, count;
+  FT_ULong           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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_ChainSubRule( &csr[m], memory );
+
+  FREE( csr );
+  return error;
+}
+
+
+static void  Free_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs,
+				   FT_Memory             memory )
+{
+  FT_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], memory );
+
+    FREE( csr );
+  }
+}
+
+
+/* ChainContextSubstFormat1 */
+
+static FT_Error  Load_ChainContextSubst1(
+		   HB_ChainContextSubstFormat1*  ccsf1,
+		   FT_Stream                      stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort             n = 0, m, count;
+  FT_ULong              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 ) ) != FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_ChainSubRuleSet( &csrs[m], memory );
+
+  FREE( csrs );
+
+Fail2:
+  _HB_OPEN_Free_Coverage( &ccsf1->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ChainContextSubst1( HB_ChainContextSubstFormat1*  ccsf1,
+				 FT_Memory                      memory )
+{
+  FT_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], memory );
+
+    FREE( csrs );
+  }
+
+  _HB_OPEN_Free_Coverage( &ccsf1->Coverage, memory );
+}
+
+
+/* ChainSubClassRule */
+
+static FT_Error  Load_ChainSubClassRule(
+		   HB_ChainContextSubstFormat2*  ccsf2,
+		   HB_ChainSubClassRule*         cscr,
+		   FT_Stream                      stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n, count;
+
+  FT_UShort*              b;
+  FT_UShort*              i;
+  FT_UShort*              l;
+  HB_SubstLookupRecord*  slr;
+  FT_Bool*                d;
+
+
+  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, FT_UShort ) )
+    return error;
+
+  b = cscr->Backtrack;
+  d = ccsf2->BacktrackClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail4;
+
+  for ( n = 0; n < count; n++ )
+  {
+    b[n] = GET_UShort();
+
+    /* We check whether the specific class is used at all.  If not,
+       class 0 is used instead.                                     */
+
+    if ( !d[b[n]] )
+      b[n] = 0;
+  }
+
+  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, FT_UShort ) )
+    goto Fail4;
+
+  i = cscr->Input;
+  d = ccsf2->InputClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail3;
+
+  for ( n = 0; n < count; n++ )
+  {
+    i[n] = GET_UShort();
+
+    if ( !d[i[n]] )
+      i[n] = 0;
+  }
+
+  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, FT_UShort ) )
+    goto Fail3;
+
+  l = cscr->Lookahead;
+  d = ccsf2->LookaheadClassDef.Defined;
+
+  if ( ACCESS_Frame( count * 2L ) )
+    goto Fail2;
+
+  for ( n = 0; n < count; n++ )
+  {
+    l[n] = GET_UShort();
+
+    if ( !d[l[n]] )
+      l[n] = 0;
+  }
+
+  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 FT_Err_Ok;
+
+Fail1:
+  FREE( slr );
+
+Fail2:
+  FREE( l );
+
+Fail3:
+  FREE( i );
+
+Fail4:
+  FREE( b );
+  return error;
+}
+
+
+static void  Free_ChainSubClassRule( HB_ChainSubClassRule*  cscr,
+				     FT_Memory               memory )
+{
+  FREE( cscr->SubstLookupRecord );
+  FREE( cscr->Lookahead );
+  FREE( cscr->Input );
+  FREE( cscr->Backtrack );
+}
+
+
+/* SubClassSet */
+
+static FT_Error  Load_ChainSubClassSet(
+		   HB_ChainContextSubstFormat2*  ccsf2,
+		   HB_ChainSubClassSet*          cscs,
+		   FT_Stream                      stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n = 0, m, count;
+  FT_ULong                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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_ChainSubClassRule( &cscr[m], memory );
+
+  FREE( cscr );
+  return error;
+}
+
+
+static void  Free_ChainSubClassSet( HB_ChainSubClassSet*  cscs,
+				    FT_Memory              memory )
+{
+  FT_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], memory );
+
+    FREE( cscr );
+  }
+}
+
+static FT_Error GSUB_Load_EmptyOrClassDefinition( HB_ClassDefinition*  cd,
+					     FT_UShort             limit,
+					     FT_ULong              class_offset,
+					     FT_ULong              base_offset,
+					     FT_Stream             stream )
+{
+  FT_Error error;
+  FT_ULong               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, stream );
+
+  if (error == FT_Err_Ok)
+    (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
+
+  return error;
+}
+
+
+/* ChainContextSubstFormat2 */
+
+static FT_Error  Load_ChainContextSubst2(
+		   HB_ChainContextSubstFormat2*  ccsf2,
+		   FT_Stream                      stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort              n = 0, m, count;
+  FT_ULong               cur_offset, new_offset, base_offset;
+  FT_ULong               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 ) ) != FT_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 = GSUB_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
+					      backtrack_offset, base_offset,
+					      stream ) ) != FT_Err_Ok )
+      goto Fail5;
+	     
+  if ( ( error = GSUB_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
+					      input_offset, base_offset,
+					      stream ) ) != FT_Err_Ok )
+      goto Fail4;
+  if ( ( error = GSUB_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
+					      lookahead_offset, base_offset,
+					      stream ) ) != FT_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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_ChainSubClassSet( &cscs[m], memory );
+
+  FREE( cscs );
+
+Fail2:
+  _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory );
+
+Fail3:
+  _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef, memory );
+
+Fail4:
+  _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory );
+
+Fail5:
+  _HB_OPEN_Free_Coverage( &ccsf2->Coverage, memory );
+  return error;
+}
+
+
+static void  Free_ChainContextSubst2( HB_ChainContextSubstFormat2*  ccsf2,
+				 FT_Memory                      memory )
+{
+  FT_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], memory );
+
+    FREE( cscs );
+  }
+
+  _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory );
+  _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef, memory );
+  _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory );
+
+  _HB_OPEN_Free_Coverage( &ccsf2->Coverage, memory );
+}
+
+
+/* ChainContextSubstFormat3 */
+
+static FT_Error  Load_ChainContextSubst3(
+		   HB_ChainContextSubstFormat3*  ccsf3,
+		   FT_Stream                      stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+
+  FT_UShort               n, nb = 0, ni =0, nl = 0, m, count;
+  FT_UShort               backtrack_count, input_count, lookahead_count;
+  FT_ULong                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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( slr );
+
+Fail2:
+  for ( m = 0; m < nl; m++ )
+    _HB_OPEN_Free_Coverage( &l[m], memory );
+
+  FREE( l );
+
+Fail3:
+  for ( m = 0; m < ni; m++ )
+    _HB_OPEN_Free_Coverage( &i[m], memory );
+
+  FREE( i );
+
+Fail4:
+  for ( m = 0; m < nb; m++ )
+    _HB_OPEN_Free_Coverage( &b[m], memory );
+
+  FREE( b );
+  return error;
+}
+
+
+static void  Free_ChainContextSubst3( HB_ChainContextSubstFormat3*  ccsf3,
+				 FT_Memory                      memory )
+{
+  FT_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], memory );
+
+    FREE( c );
+  }
+
+  if ( ccsf3->InputCoverage )
+  {
+    count = ccsf3->InputGlyphCount;
+    c     = ccsf3->InputCoverage;
+
+    for ( n = 0; n < count; n++ )
+      _HB_OPEN_Free_Coverage( &c[n], memory );
+
+    FREE( c );
+  }
+
+  if ( ccsf3->BacktrackCoverage )
+  {
+    count = ccsf3->BacktrackGlyphCount;
+    c     = ccsf3->BacktrackCoverage;
+
+    for ( n = 0; n < count; n++ )
+      _HB_OPEN_Free_Coverage( &c[n], memory );
+
+    FREE( c );
+  }
+}
+
+
+/* ChainContextSubst */
+
+static FT_Error  Load_ChainContextSubst( HB_GSUB_SubTable* st,
+					 FT_Stream         stream )
+{
+  FT_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 HB_Err_Invalid_GSUB_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+static void  Free_ChainContextSubst( HB_GSUB_SubTable* st,
+				     FT_Memory         memory )
+{
+  HB_ChainContextSubst*  ccs = &st->chain;
+
+  switch ( ccs->SubstFormat )
+  {
+  case 1:
+    Free_ChainContextSubst1( &ccs->ccsf.ccsf1, memory );
+    break;
+
+  case 2:
+    Free_ChainContextSubst2( &ccs->ccsf.ccsf2, memory );
+    break;
+
+  case 3:
+    Free_ChainContextSubst3( &ccs->ccsf.ccsf3, memory );
+    break;
+  }
+}
+
+
+static FT_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
+					    HB_ChainContextSubstFormat1* ccsf1,
+					    HB_Buffer                    buffer,
+					    FT_UShort                     flags,
+					    FT_UShort                     context_length,
+					    int                           nesting_level )
+{
+  FT_UShort          index, property;
+  FT_UShort          i, j, k, num_csr;
+  FT_UShort          bgc, igc, lgc;
+  FT_Error           error;
+
+  HB_ChainSubRule*  csr;
+  HB_ChainSubRule   curr_csr;
+  HB_GDEFHeader*    gdef;
+
+
+  gdef = gsub->gdef;
+
+  if ( CHECK_Property( gdef, 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, 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 ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  return error;
+
+	if ( j + igc - i + lgc == 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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  return error;
+
+	if ( j + lgc - i == 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 FT_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
+					    HB_ChainContextSubstFormat2* ccsf2,
+					    HB_Buffer                    buffer,
+					    FT_UShort                     flags,
+					    FT_UShort                     context_length,
+					    int                           nesting_level )
+{
+  FT_UShort              index, property;
+  FT_Memory              memory;
+  FT_Error               error;
+  FT_UShort              i, j, k;
+  FT_UShort              bgc, igc, lgc;
+  FT_UShort              known_backtrack_classes,
+			 known_input_classes,
+			 known_lookahead_classes;
+
+  FT_UShort*             backtrack_classes;
+  FT_UShort*             input_classes;
+  FT_UShort*             lookahead_classes;
+
+  FT_UShort*             bc;
+  FT_UShort*             ic;
+  FT_UShort*             lc;
+
+  HB_ChainSubClassSet*  cscs;
+  HB_ChainSubClassRule  ccsr;
+  HB_GDEFHeader*        gdef;
+
+
+  gdef = gsub->gdef;
+  memory = gsub->memory;
+
+  if ( CHECK_Property( gdef, 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, FT_UShort ) )
+    return error;
+  known_backtrack_classes = 0;
+
+  if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, FT_UShort ) )
+    goto End3;
+  known_input_classes = 1;
+
+  if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, FT_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 = HB_Err_Invalid_GSUB_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, 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 ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  goto End1;
+
+	if ( j + igc - i + lgc == 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++ )
+    {
+      while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+      {
+	if ( error && error != HB_Err_Not_Covered )
+	  goto End1;
+
+	if ( j + lgc - i == 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 FT_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
+					    HB_ChainContextSubstFormat3* ccsf3,
+					    HB_Buffer                    buffer,
+					    FT_UShort                     flags,
+					    FT_UShort                     context_length,
+					    int                           nesting_level )
+{
+  FT_UShort        index, i, j, property;
+  FT_UShort        bgc, igc, lgc;
+  FT_Error         error;
+
+  HB_Coverage*    bc;
+  HB_Coverage*    ic;
+  HB_Coverage*    lc;
+  HB_GDEFHeader*  gdef;
+
+
+  gdef = gsub->gdef;
+
+  if ( CHECK_Property( gdef, 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 ( CHECK_Property( gdef, 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 ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    {
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+      
+      if ( j + igc - i + lgc == 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++ )
+  {
+    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    {
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+
+      if ( j + lgc - i == 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 FT_Error  Lookup_ChainContextSubst( HB_GSUBHeader*    gsub,
+					   HB_GSUB_SubTable* st,
+					   HB_Buffer         buffer,
+					   FT_UShort          flags,
+					   FT_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 HB_Err_Invalid_GSUB_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+static FT_Error  Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
+					        FT_Stream         stream )
+{
+  FT_Error error;
+  FT_Memory memory = stream->memory;
+  HB_ReverseChainContextSubst*  rccs = &st->reverse;
+
+  FT_UShort               m, count;
+
+  FT_UShort               nb = 0, nl = 0, n;
+  FT_UShort               backtrack_count, lookahead_count;
+  FT_ULong                cur_offset, new_offset, base_offset;
+
+  HB_Coverage*           b;
+  HB_Coverage*           l;
+  FT_UShort*              sub;
+
+  base_offset = FILE_Pos();
+
+  if ( ACCESS_Frame( 2L ) )
+    return error;
+  
+  rccs->SubstFormat = GET_UShort();
+  
+  if ( rccs->SubstFormat != 1 )
+    return HB_Err_Invalid_GSUB_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 ) ) != FT_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 ) ) != FT_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 ) ) != FT_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,
+		    FT_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 FT_Err_Ok;
+
+Fail1:
+  FREE( sub );
+  
+Fail2:
+  for ( m = 0; m < nl; m++ )
+    _HB_OPEN_Free_Coverage( &l[m], memory );
+
+  FREE( l );
+
+Fail3:
+  for ( m = 0; m < nb; m++ )
+    _HB_OPEN_Free_Coverage( &b[m], memory );
+
+  FREE( b );
+
+Fail4:
+  _HB_OPEN_Free_Coverage( &rccs->Coverage, memory );    
+  return error;
+}
+
+
+static void  Free_ReverseChainContextSubst( HB_GSUB_SubTable* st,
+					    FT_Memory         memory )
+{  
+  FT_UShort      n, count;
+  HB_ReverseChainContextSubst*  rccs = &st->reverse;
+
+  HB_Coverage*  c;
+
+  _HB_OPEN_Free_Coverage( &rccs->Coverage, memory );
+  
+  if ( rccs->LookaheadCoverage )
+  {
+    count = rccs->LookaheadGlyphCount;
+    c     = rccs->LookaheadCoverage;
+
+    for ( n = 0; n < count; n++ )
+      _HB_OPEN_Free_Coverage( &c[n], memory );
+
+    FREE( c );
+  }
+
+  if ( rccs->BacktrackCoverage )
+  {
+    count = rccs->BacktrackGlyphCount;
+    c     = rccs->BacktrackCoverage;
+
+    for ( n = 0; n < count; n++ )
+      _HB_OPEN_Free_Coverage( &c[n], memory );
+
+    FREE( c );
+  }
+
+  FREE ( rccs->Substitute );
+}
+
+
+static FT_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
+						  HB_GSUB_SubTable* st,
+						  HB_Buffer         buffer,
+						  FT_UShort          flags,
+      /* note different signature here: */	  FT_ULong           string_index )
+{
+  FT_UShort        index, input_index, i, j, property;
+  FT_UShort        bgc, lgc;
+  FT_Error         error;
+
+  HB_ReverseChainContextSubst*  rccs = &st->reverse;
+  HB_Coverage*    bc;
+  HB_Coverage*    lc;
+  HB_GDEFHeader*  gdef;
+
+  gdef = gsub->gdef;
+
+  if ( CHECK_Property( gdef, IN_ITEM( string_index ), flags, &property ) )
+    return error;
+
+  bgc = rccs->BacktrackGlyphCount;
+  lgc = rccs->LookaheadGlyphCount;
+
+  /* check whether context is too long; it is a first guess only */
+  
+  if ( bgc > string_index || string_index + 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 = string_index - 1; i < bgc; i++, j-- )
+    {
+      while ( CHECK_Property( gdef, 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 = string_index;
+ 
+  error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
+  if ( error )
+      return error;
+
+  /* we are starting for lookahead glyphs right after the last context
+     glyph                                                             */
+  
+  j += 1;
+
+  lc       = rccs->LookaheadCoverage;
+
+  for ( i = 0; i < lgc; i++, j++ )
+  {
+    while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+    {
+      if ( error && error != HB_Err_Not_Covered )
+	return error;
+
+      if ( j + lgc - i == 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_GLYPH( string_index ) = rccs->Substitute[input_index];
+      
+  return error;
+}
+
+
+
+/***********
+ * GSUB API
+ ***********/
+
+
+
+FT_Error  HB_GSUB_Select_Script( HB_GSUBHeader*  gsub,
+				 FT_ULong         script_tag,
+				 FT_UShort*       script_index )
+{
+  FT_UShort          n;
+
+  HB_ScriptList*    sl;
+  HB_ScriptRecord*  sr;
+
+
+  if ( !gsub || !script_index )
+    return FT_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 FT_Err_Ok;
+    }
+
+  return HB_Err_Not_Covered;
+}
+
+
+
+FT_Error  HB_GSUB_Select_Language( HB_GSUBHeader*  gsub,
+				   FT_ULong         language_tag,
+				   FT_UShort        script_index,
+				   FT_UShort*       language_index,
+				   FT_UShort*       req_feature_index )
+{
+  FT_UShort           n;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+
+
+  if ( !gsub || !language_index || !req_feature_index )
+    return FT_Err_Invalid_Argument;
+
+  sl = &gsub->ScriptList;
+  sr = sl->ScriptRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_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 FT_Err_Ok;
+    }
+
+  return HB_Err_Not_Covered;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+   default language (DefaultLangSys)                              */
+
+
+FT_Error  HB_GSUB_Select_Feature( HB_GSUBHeader*  gsub,
+				  FT_ULong         feature_tag,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_UShort*       feature_index )
+{
+  FT_UShort           n;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+  HB_LangSys*        ls;
+  FT_UShort*          fi;
+
+  HB_FeatureList*    fl;
+  HB_FeatureRecord*  fr;
+
+
+  if ( !gsub || !feature_index )
+    return FT_Err_Invalid_Argument;
+
+  sl = &gsub->ScriptList;
+  sr = sl->ScriptRecord;
+
+  fl = &gsub->FeatureList;
+  fr = fl->FeatureRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_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 FT_Err_Invalid_Argument;
+
+    ls = &lsr[language_index].LangSys;
+  }
+
+  fi = ls->FeatureIndex;
+
+  for ( n = 0; n < ls->FeatureCount; n++ )
+  {
+    if ( fi[n] >= fl->FeatureCount )
+      return HB_Err_Invalid_GSUB_SubTable_Format;
+
+    if ( feature_tag == fr[fi[n]].FeatureTag )
+    {
+      *feature_index = fi[n];
+
+      return FT_Err_Ok;
+    }
+  }
+
+  return HB_Err_Not_Covered;
+}
+
+
+/* The next three functions return a null-terminated list */
+
+
+FT_Error  HB_GSUB_Query_Scripts( HB_GSUBHeader*  gsub,
+				 FT_ULong**       script_tag_list )
+{
+  FT_UShort          n;
+  FT_Error           error;
+  FT_Memory          memory;
+  FT_ULong*          stl;
+
+  HB_ScriptList*    sl;
+  HB_ScriptRecord*  sr;
+
+
+  if ( !gsub || !script_tag_list )
+    return FT_Err_Invalid_Argument;
+
+  memory = gsub->memory;
+
+  sl = &gsub->ScriptList;
+  sr = sl->ScriptRecord;
+
+  if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) )
+    return error;
+
+  for ( n = 0; n < sl->ScriptCount; n++ )
+    stl[n] = sr[n].ScriptTag;
+  stl[n] = 0;
+
+  *script_tag_list = stl;
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GSUB_Query_Languages( HB_GSUBHeader*  gsub,
+				   FT_UShort        script_index,
+				   FT_ULong**       language_tag_list )
+{
+  FT_UShort           n;
+  FT_Error            error;
+  FT_Memory           memory;
+  FT_ULong*           ltl;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+
+
+  if ( !gsub || !language_tag_list )
+    return FT_Err_Invalid_Argument;
+
+  memory = gsub->memory;
+  
+  sl = &gsub->ScriptList;
+  sr = sl->ScriptRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_Err_Invalid_Argument;
+
+  s   = &sr[script_index].Script;
+  lsr = s->LangSysRecord;
+
+  if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) )
+    return error;
+
+  for ( n = 0; n < s->LangSysCount; n++ )
+    ltl[n] = lsr[n].LangSysTag;
+  ltl[n] = 0;
+
+  *language_tag_list = ltl;
+
+  return FT_Err_Ok;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+   default language (DefaultLangSys)                              */
+
+
+FT_Error  HB_GSUB_Query_Features( HB_GSUBHeader*  gsub,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_ULong**       feature_tag_list )
+{
+  FT_UShort           n;
+  FT_Error            error;
+  FT_Memory           memory;
+  FT_ULong*           ftl;
+
+  HB_ScriptList*     sl;
+  HB_ScriptRecord*   sr;
+  HB_Script*         s;
+  HB_LangSysRecord*  lsr;
+  HB_LangSys*        ls;
+  FT_UShort*          fi;
+
+  HB_FeatureList*    fl;
+  HB_FeatureRecord*  fr;
+
+
+  if ( !gsub || !feature_tag_list )
+    return FT_Err_Invalid_Argument;
+
+  memory = gsub->memory;
+  
+  sl = &gsub->ScriptList;
+  sr = sl->ScriptRecord;
+
+  fl = &gsub->FeatureList;
+  fr = fl->FeatureRecord;
+
+  if ( script_index >= sl->ScriptCount )
+    return FT_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 FT_Err_Invalid_Argument;
+
+    ls = &lsr[language_index].LangSys;
+  }
+
+  fi = ls->FeatureIndex;
+
+  if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) )
+    return error;
+
+  for ( n = 0; n < ls->FeatureCount; n++ )
+  {
+    if ( fi[n] >= fl->FeatureCount )
+    {
+      FREE( ftl );
+      return HB_Err_Invalid_GSUB_SubTable_Format;
+    }
+    ftl[n] = fr[fi[n]].FeatureTag;
+  }
+  ftl[n] = 0;
+
+  *feature_tag_list = ftl;
+
+  return FT_Err_Ok;
+}
+
+
+typedef FT_Error  (*Lookup_Subst_Func_Type)( HB_GSUBHeader*    gsub,
+					     HB_GSUB_SubTable* st,
+					     HB_Buffer         buffer,
+					     FT_UShort          flags,
+					     FT_UShort          context_length,
+					     int                nesting_level );
+static const Lookup_Subst_Func_Type Lookup_Subst_Call_Table[] = {
+  Lookup_DefaultSubst,
+  Lookup_SingleSubst,		/* HB_GSUB_LOOKUP_SINGLE        1 */
+  Lookup_MultipleSubst,		/* HB_GSUB_LOOKUP_MULTIPLE      2 */
+  Lookup_AlternateSubst,	/* HB_GSUB_LOOKUP_ALTERNATE     3 */
+  Lookup_LigatureSubst,		/* HB_GSUB_LOOKUP_LIGATURE      4 */
+  Lookup_ContextSubst,		/* HB_GSUB_LOOKUP_CONTEXT       5 */
+  Lookup_ChainContextSubst,	/* HB_GSUB_LOOKUP_CHAIN         6 */
+  Lookup_DefaultSubst		/* HB_GSUB_LOOKUP_EXTENSION     7 */
+};
+/* Note that the following lookup does not belong to the table above:
+ * Lookup_ReverseChainContextSubst,	 HB_GSUB_LOOKUP_REVERSE_CHAIN 8
+ * because it's invalid to happen where this table is used.  It's
+ * signature is different too...
+ */
+
+/* Do an individual subtable lookup.  Returns FT_Err_Ok if substitution
+   has been done, or HB_Err_Not_Covered if not.                        */
+static FT_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
+				       FT_UShort       lookup_index,
+				       HB_Buffer      buffer,
+				       FT_UShort       context_length,
+				       int             nesting_level )
+{
+  FT_Error               error = HB_Err_Not_Covered;
+  FT_UShort              i, flags, lookup_count;
+  HB_Lookup*             lo;
+  int                    lookup_type;
+  Lookup_Subst_Func_Type Func;
+
+
+  nesting_level++;
+
+  if ( nesting_level > HB_MAX_NESTING_LEVEL )
+    return HB_Err_Too_Many_Nested_Contexts;
+
+  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;
+
+  if (lookup_type >= ARRAY_LEN (Lookup_Subst_Call_Table))
+    lookup_type = 0;
+  Func = Lookup_Subst_Call_Table[lookup_type];
+
+  for ( i = 0; i < lo->SubTableCount; i++ )
+  {
+    error = Func ( gsub,
+		   &lo->SubTable[i].st.gsub,
+		   buffer,
+		   flags, context_length,
+		   nesting_level );
+
+    /* 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;
+}
+
+
+static FT_Error  Load_DefaultSubst( HB_GSUB_SubTable* st,
+				    FT_Stream         stream )
+{
+  return HB_Err_Invalid_GSUB_SubTable_Format;
+}
+
+typedef FT_Error  (*Load_Subst_Func_Type)( HB_GSUB_SubTable* st,
+					   FT_Stream         stream );
+static const Load_Subst_Func_Type Load_Subst_Call_Table[] = {
+  Load_DefaultSubst,
+  Load_SingleSubst,		/* HB_GSUB_LOOKUP_SINGLE        1 */
+  Load_MultipleSubst,		/* HB_GSUB_LOOKUP_MULTIPLE      2 */
+  Load_AlternateSubst,		/* HB_GSUB_LOOKUP_ALTERNATE     3 */
+  Load_LigatureSubst,		/* HB_GSUB_LOOKUP_LIGATURE      4 */
+  Load_ContextSubst,		/* HB_GSUB_LOOKUP_CONTEXT       5 */
+  Load_ChainContextSubst,	/* HB_GSUB_LOOKUP_CHAIN         6 */
+  Load_DefaultSubst,		/* HB_GSUB_LOOKUP_EXTENSION     7 */
+  Load_ReverseChainContextSubst /* HB_GSUB_LOOKUP_REVERSE_CHAIN 8 */
+};
+
+FT_Error  _HB_GSUB_Load_SubTable( HB_GSUB_SubTable*  st,
+				  FT_Stream     stream,
+				  FT_UShort     lookup_type )
+{
+  Load_Subst_Func_Type Func;
+
+  if (lookup_type >= ARRAY_LEN (Load_Subst_Call_Table))
+    lookup_type = 0;
+
+  Func = Load_Subst_Call_Table[lookup_type];
+
+  return Func ( st, stream );
+}
+
+
+static void  Free_DefaultSubst( HB_GSUB_SubTable* st,
+				FT_Memory         memory )
+{
+}
+
+typedef void  (*Free_Subst_Func_Type)( HB_GSUB_SubTable* st,
+				       FT_Memory         memory );
+static const Free_Subst_Func_Type Free_Subst_Call_Table[] = {
+  Free_DefaultSubst,
+  Free_SingleSubst,		/* HB_GSUB_LOOKUP_SINGLE        1 */
+  Free_MultipleSubst,		/* HB_GSUB_LOOKUP_MULTIPLE      2 */
+  Free_AlternateSubst,		/* HB_GSUB_LOOKUP_ALTERNATE     3 */
+  Free_LigatureSubst,		/* HB_GSUB_LOOKUP_LIGATURE      4 */
+  Free_ContextSubst,		/* HB_GSUB_LOOKUP_CONTEXT       5 */
+  Free_ChainContextSubst,	/* HB_GSUB_LOOKUP_CHAIN         6 */
+  Free_DefaultSubst,		/* HB_GSUB_LOOKUP_EXTENSION     7 */
+  Free_ReverseChainContextSubst /* HB_GSUB_LOOKUP_REVERSE_CHAIN 8 */
+};
+
+void  _HB_GSUB_Free_SubTable( HB_GSUB_SubTable*  st,
+			      FT_Memory     memory,
+			      FT_UShort     lookup_type )
+{
+  Free_Subst_Func_Type Func;
+
+  if (lookup_type >= ARRAY_LEN (Free_Subst_Call_Table))
+    lookup_type = 0;
+
+  Func = Free_Subst_Call_Table[lookup_type];
+
+  Func ( st, memory );
+}
+
+
+
+/* apply one lookup to the input string object */
+
+static FT_Error  GSUB_Do_String_Lookup( HB_GSUBHeader*   gsub,
+				   FT_UShort         lookup_index,
+				   HB_Buffer        buffer )
+{
+  FT_Error  error, retError = HB_Err_Not_Covered;
+
+  FT_UInt*  properties = gsub->LookupList.Properties;
+
+  int      nesting_level = 0;
+
+
+  while ( buffer->in_pos < buffer->in_length )
+  {
+    if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
+    {
+      /* 0xFFFF indicates that we don't have a context length yet */
+      error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer,
+				    0xFFFF, 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 ( hb_buffer_copy_output_glyph ( buffer ) )
+	return error;
+  }
+
+  return retError;
+}
+
+
+static FT_Error  Apply_ReverseChainContextSubst( HB_GSUBHeader*   gsub,
+						 FT_UShort         lookup_index,
+						 HB_Buffer        buffer )
+{
+  FT_UInt*     properties =  gsub->LookupList.Properties;
+  FT_Error     error, retError = HB_Err_Not_Covered;
+  FT_ULong     subtable_Count, string_index;
+  FT_UShort    flags;
+  HB_Lookup*  lo;      
+
+  if ( buffer->in_length == 0 )
+    return HB_Err_Not_Covered;
+  
+  lo    = &gsub->LookupList.Lookup[lookup_index];
+  flags = lo->LookupFlag;      
+  
+  for ( subtable_Count = 0; subtable_Count < lo->SubTableCount; subtable_Count++ )
+  {
+    string_index  = buffer->in_length - 1;
+    do
+    {
+      if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
+	{
+	  error = Lookup_ReverseChainContextSubst( gsub, &lo->SubTable[subtable_Count].st.gsub,
+						   buffer, flags, string_index );
+	  if ( error )
+	    {
+	      if ( error != HB_Err_Not_Covered )
+		return error;
+	    }
+	  else
+	    retError = error;
+	}
+    }
+    while (string_index--);
+  }
+  
+  return retError;
+}
+
+
+FT_Error  HB_GSUB_Add_Feature( HB_GSUBHeader*  gsub,
+			       FT_UShort        feature_index,
+			       FT_UInt          property )
+{
+  FT_UShort    i;
+
+  HB_Feature  feature;
+  FT_UInt*     properties;
+  FT_UShort*   index;
+  FT_UShort    lookup_count;
+
+  /* Each feature can only be added once */
+  
+  if ( !gsub ||
+       feature_index >= gsub->FeatureList.FeatureCount ||
+       gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
+    return FT_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++ )
+  {
+    FT_UShort lookup_index = index[i];
+    if (lookup_index < lookup_count)
+      properties[lookup_index] |= property;
+  }
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GSUB_Clear_Features( HB_GSUBHeader*  gsub )
+{
+  FT_UShort i;
+
+  FT_UInt*  properties;
+
+
+  if ( !gsub )
+    return FT_Err_Invalid_Argument;
+
+  gsub->FeatureList.ApplyCount = 0;
+
+  properties = gsub->LookupList.Properties;
+
+  for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
+    properties[i] = 0;
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GSUB_Register_Alternate_Function( HB_GSUBHeader*  gsub,
+					       HB_AltFunction  altfunc,
+					       void*            data )
+{
+  if ( !gsub )
+    return FT_Err_Invalid_Argument;
+
+  gsub->altfunc = altfunc;
+  gsub->data    = data;
+
+  return FT_Err_Ok;
+}
+
+
+
+FT_Error  HB_GSUB_Apply_String( HB_GSUBHeader*   gsub,
+				HB_Buffer        buffer )
+{
+  FT_Error          error, retError = HB_Err_Not_Covered;
+  FT_UShort         i, j, lookup_count;
+
+  if ( !gsub ||
+       !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length )
+    return FT_Err_Invalid_Argument;
+
+  lookup_count = gsub->LookupList.LookupCount;
+
+  for ( i = 0; i < gsub->FeatureList.ApplyCount; i++)
+  {
+    FT_UShort         feature_index;
+    HB_Feature       feature;
+
+    feature_index = gsub->FeatureList.ApplyOrder[i];
+    feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
+
+    for ( j = 0; j < feature.LookupListCount; j++ )
+    {
+      FT_UShort         lookup_index;
+      HB_Lookup*       lookup;
+      FT_Bool           need_swap;
+
+      lookup_index = feature.LookupListIndex[j];
+
+      /* Skip nonexistant lookups */
+      if (lookup_index >= lookup_count)
+       continue;
+
+      lookup = &gsub->LookupList.Lookup[lookup_index];
+
+      if ( lookup->LookupType == HB_GSUB_LOOKUP_REVERSE_CHAIN )
+      {
+	error = Apply_ReverseChainContextSubst( gsub, lookup_index, buffer);
+	need_swap = FALSE; /* We do ReverseChainContextSubst in-place */
+      }
+      else
+      {
+	error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
+	need_swap = TRUE;
+      }
+
+      if ( error )
+      {
+	if ( error != HB_Err_Not_Covered )
+	  goto End;
+      }
+      else
+	retError = error;
+      
+      if ( need_swap )
+      {
+	error = hb_buffer_swap( buffer );
+	if ( error )
+	  goto End;
+      }
+    } 
+  }
+  
+  error = retError;
+
+End:
+  return error;
+}
+
+
+/* END */
diff --git a/src/harfbuzz-gsub.h b/src/harfbuzz-gsub.h
new file mode 100644
index 0000000..09145ba
--- /dev/null
+++ b/src/harfbuzz-gsub.h
@@ -0,0 +1,132 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_GSUB_H
+#define HARFBUZZ_GSUB_H
+
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-buffer.h"
+
+FT_BEGIN_HEADER
+
+#define HB_Err_Invalid_GSUB_SubTable_Format  0x1010
+#define HB_Err_Invalid_GSUB_SubTable         0x1011
+
+
+/* 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 FT_UShort  (*HB_AltFunction)(FT_ULong    pos,
+				      FT_UShort   glyphID,
+				      FT_UShort   num_alternates,
+				      FT_UShort*  alternates,
+				      void*       data );
+
+
+struct  HB_GSUBHeader_
+{
+  FT_Memory        memory;
+  
+  FT_ULong         offset;
+
+  FT_Fixed         Version;
+
+  HB_ScriptList   ScriptList;
+  HB_FeatureList  FeatureList;
+  HB_LookupList   LookupList;
+
+  HB_GDEFHeader*  gdef;
+
+  /* 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;
+
+
+FT_Error  HB_Load_GSUB_Table( FT_Face          face,
+			      HB_GSUBHeader** gsub,
+			      HB_GDEFHeader*  gdef );
+
+
+FT_Error  HB_Done_GSUB_Table( HB_GSUBHeader*  gsub );
+
+
+FT_Error  HB_GSUB_Select_Script( HB_GSUBHeader*  gsub,
+				 FT_ULong         script_tag,
+				 FT_UShort*       script_index );
+
+FT_Error  HB_GSUB_Select_Language( HB_GSUBHeader*  gsub,
+				   FT_ULong         language_tag,
+				   FT_UShort        script_index,
+				   FT_UShort*       language_index,
+				   FT_UShort*       req_feature_index );
+
+FT_Error  HB_GSUB_Select_Feature( HB_GSUBHeader*  gsub,
+				  FT_ULong         feature_tag,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_UShort*       feature_index );
+
+
+FT_Error  HB_GSUB_Query_Scripts( HB_GSUBHeader*  gsub,
+				 FT_ULong**       script_tag_list );
+
+FT_Error  HB_GSUB_Query_Languages( HB_GSUBHeader*  gsub,
+				   FT_UShort        script_index,
+				   FT_ULong**       language_tag_list );
+
+FT_Error  HB_GSUB_Query_Features( HB_GSUBHeader*  gsub,
+				  FT_UShort        script_index,
+				  FT_UShort        language_index,
+				  FT_ULong**       feature_tag_list );
+
+
+FT_Error  HB_GSUB_Add_Feature( HB_GSUBHeader*  gsub,
+			       FT_UShort        feature_index,
+			       FT_UInt          property );
+
+FT_Error  HB_GSUB_Clear_Features( HB_GSUBHeader*  gsub );
+
+
+FT_Error  HB_GSUB_Register_Alternate_Function( HB_GSUBHeader*  gsub,
+					       HB_AltFunction  altfunc,
+					       void*            data );
+
+
+FT_Error  HB_GSUB_Apply_String( HB_GSUBHeader*   gsub,
+				HB_Buffer        buffer );
+
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_GSUB_H */
diff --git a/src/harfbuzz-impl.h b/src/harfbuzz-impl.h
new file mode 100644
index 0000000..2531014
--- /dev/null
+++ b/src/harfbuzz-impl.h
@@ -0,0 +1,64 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_IMPL_H
+#define HARFBUZZ_IMPL_H
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+FT_BEGIN_HEADER
+
+#include "ftglue.h"
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#define ARRAY_LEN(Array) ((int)(sizeof (Array) / sizeof (Array)[0]))
+
+
+
+
+#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( gdef, index, flags, property )              \
+          ( ( error = _HB_GDEF_Check_Property( (gdef), (index), (flags),     \
+                                      (property) ) ) != FT_Err_Ok )
+
+#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)  \
+                                                  ) ) != FT_Err_Ok )
+#define ADD_Glyph( buffer, glyph_index, component, ligID )             		 	 \
+          ( ( error = hb_buffer_add_output_glyph( (buffer),                             \
+                                                    (glyph_index), (component), (ligID)  \
+                                                  ) ) != FT_Err_Ok )
+
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_IMPL_H */
diff --git a/src/harfbuzz-open-private.h b/src/harfbuzz-open-private.h
new file mode 100644
index 0000000..be265af
--- /dev/null
+++ b/src/harfbuzz-open-private.h
@@ -0,0 +1,81 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_OPEN_PRIVATE_H
+#define HARFBUZZ_OPEN_PRIVATE_H
+
+#include "harfbuzz-open.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-gpos-private.h"
+
+FT_BEGIN_HEADER
+
+
+struct  HB_SubTable_
+{
+  union
+  {
+    HB_GSUB_SubTable  gsub;
+    HB_GPOS_SubTable  gpos;
+  } st;
+};
+
+
+FT_Error  _HB_OPEN_Load_ScriptList( HB_ScriptList*  sl,
+			   FT_Stream     stream );
+FT_Error  _HB_OPEN_Load_FeatureList( HB_FeatureList*  fl,
+			    FT_Stream         input );
+FT_Error  _HB_OPEN_Load_LookupList( HB_LookupList*  ll,
+			   FT_Stream        input,
+			   HB_Type         type );
+
+FT_Error  _HB_OPEN_Load_Coverage( HB_Coverage*  c,
+			 FT_Stream      input );
+FT_Error  _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition*  cd,
+				FT_UShort             limit,
+				FT_Stream             input );
+FT_Error  _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition*  cd,
+				     FT_Stream             input );
+FT_Error  _HB_OPEN_Load_Device( HB_Device*  d,
+		       FT_Stream    input );
+
+void  _HB_OPEN_Free_ScriptList( HB_ScriptList*  sl, 
+		       FT_Memory        memory );
+void  _HB_OPEN_Free_FeatureList( HB_FeatureList*  fl,
+			FT_Memory         memory );
+void  _HB_OPEN_Free_LookupList( HB_LookupList*  ll,
+		       HB_Type         type,
+		       FT_Memory        memory );
+
+void  _HB_OPEN_Free_Coverage( HB_Coverage*  c,
+		     FT_Memory      memory );
+void  _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition*  cd,
+			    FT_Memory             memory );
+void  _HB_OPEN_Free_Device( HB_Device*  d,
+		   FT_Memory    memory );
+
+
+
+FT_Error  _HB_OPEN_Coverage_Index( HB_Coverage*  c,
+			  FT_UShort      glyphID,
+			  FT_UShort*     index );
+FT_Error  _HB_OPEN_Get_Class( HB_ClassDefinition*  cd,
+		     FT_UShort             glyphID,
+		     FT_UShort*            class,
+		     FT_UShort*            index );
+FT_Error  _HB_OPEN_Get_Device( HB_Device*  d,
+		      FT_UShort    size,
+		      FT_Short*    value );
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_OPEN_PRIVATE_H */
diff --git a/src/harfbuzz-open.c b/src/harfbuzz-open.c
new file mode 100644
index 0000000..b3c1bcb
--- /dev/null
+++ b/src/harfbuzz-open.c
@@ -0,0 +1,1426 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#include "harfbuzz-impl.h"
+#include "harfbuzz-open-private.h"
+
+
+/***************************
+ * Script related functions
+ ***************************/
+
+
+/* LangSys */
+
+static FT_Error  Load_LangSys( HB_LangSys*  ls,
+			       FT_Stream     stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+  FT_UShort  n, count;
+  FT_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, FT_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 FT_Err_Ok;
+}
+
+
+static void  Free_LangSys( HB_LangSys*  ls,
+			   FT_Memory     memory )
+{
+  FREE( ls->FeatureIndex );
+}
+
+
+/* Script */
+
+static FT_Error  Load_Script( HB_Script*  s,
+			      FT_Stream    stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+  FT_UShort  n, m, count;
+  FT_ULong   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 ) ) != FT_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();
+
+  /* safety check; otherwise the official handling of TrueType Open
+     fonts won't work */
+
+  if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
+  {
+    error = HB_Err_Empty_Script;
+    goto Fail2;
+  }
+
+  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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_LangSys( &lsr[m].LangSys, memory );
+
+  FREE( s->LangSysRecord );
+
+Fail2:
+  Free_LangSys( &s->DefaultLangSys, memory );
+  return error;
+}
+
+
+static void  Free_Script( HB_Script*  s,
+			  FT_Memory    memory )
+{
+  FT_UShort           n, count;
+
+  HB_LangSysRecord*  lsr;
+
+
+  Free_LangSys( &s->DefaultLangSys, memory );
+
+  if ( s->LangSysRecord )
+  {
+    count = s->LangSysCount;
+    lsr   = s->LangSysRecord;
+
+    for ( n = 0; n < count; n++ )
+      Free_LangSys( &lsr[n].LangSys, memory );
+
+    FREE( lsr );
+  }
+}
+
+
+/* ScriptList */
+
+FT_Error  _HB_OPEN_Load_ScriptList( HB_ScriptList*  sl,
+			   FT_Stream        stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort          n, script_count;
+  FT_ULong           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 == FT_Err_Ok )
+      sl->ScriptCount += 1;
+    else if ( error != HB_Err_Empty_Script )
+      goto Fail;
+
+    (void)FILE_Seek( cur_offset );
+  }
+
+  if ( sl->ScriptCount == 0 )
+  {
+    error = HB_Err_Invalid_SubTable;
+    goto Fail;
+  }
+  
+  return FT_Err_Ok;
+
+Fail:
+  for ( n = 0; n < sl->ScriptCount; n++ )
+    Free_Script( &sr[n].Script, memory );
+
+  FREE( sl->ScriptRecord );
+  return error;
+}
+
+
+void  _HB_OPEN_Free_ScriptList( HB_ScriptList*  sl,
+		       FT_Memory        memory )
+{
+  FT_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, memory );
+
+    FREE( sr );
+  }
+}
+
+
+
+/*********************************
+ * Feature List related functions
+ *********************************/
+
+
+/* Feature */
+
+static FT_Error  Load_Feature( HB_Feature*  f,
+			       FT_Stream     stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort   n, count;
+
+  FT_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, FT_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 FT_Err_Ok;
+}
+
+
+static void  Free_Feature( HB_Feature*  f,
+			   FT_Memory     memory )
+{
+  FREE( f->LookupListIndex );
+}
+
+
+/* FeatureList */
+
+FT_Error  _HB_OPEN_Load_FeatureList( HB_FeatureList*  fl,
+			    FT_Stream         stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort           n, m, count;
+  FT_ULong            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, FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  for ( m = 0; m < n; m++ )
+    Free_Feature( &fr[m].Feature, memory );
+
+  FREE( fl->ApplyOrder );
+
+Fail2:
+  FREE( fl->FeatureRecord );
+
+  return error;
+}
+
+
+void  _HB_OPEN_Free_FeatureList( HB_FeatureList*  fl,
+			FT_Memory         memory)
+{
+  FT_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, memory );
+
+    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 FT_Error  Load_SubTable( HB_SubTable*  st,
+				FT_Stream     stream,
+				HB_Type       table_type,
+				FT_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,
+			    FT_UShort      lookup_type,
+			    FT_Memory      memory )
+{
+  if ( table_type == HB_Type_GSUB )
+    _HB_GSUB_Free_SubTable ( &st->st.gsub, memory, lookup_type );
+  else
+    _HB_GPOS_Free_SubTable ( &st->st.gpos, memory, lookup_type );
+}
+
+
+/* Lookup */
+
+static FT_Error  Load_Lookup( HB_Lookup*   l,
+			      FT_Stream     stream,
+			      HB_Type      type )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort      n, m, count;
+  FT_ULong       cur_offset, new_offset, base_offset;
+
+  HB_SubTable*  st;
+
+  FT_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 ) ) != FT_Err_Ok )
+      goto Fail;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail:
+  for ( m = 0; m < n; m++ )
+    Free_SubTable( &st[m], type, l->LookupType, memory );
+
+  FREE( l->SubTable );
+  return error;
+}
+
+
+static void  Free_Lookup( HB_Lookup*   l,
+			  HB_Type      type,
+			  FT_Memory     memory)
+{
+  FT_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, memory );
+
+    FREE( st );
+  }
+}
+
+
+/* LookupList */
+
+FT_Error  _HB_OPEN_Load_LookupList( HB_LookupList*  ll,
+			   FT_Stream        stream,
+			   HB_Type         type )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort    n, m, count;
+  FT_ULong     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, FT_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 ) ) != FT_Err_Ok )
+      goto Fail1;
+    (void)FILE_Seek( cur_offset );
+  }
+
+  return FT_Err_Ok;
+
+Fail1:
+  FREE( ll->Properties );
+
+  for ( m = 0; m < n; m++ )
+    Free_Lookup( &l[m], type, memory );
+
+Fail2:
+  FREE( ll->Lookup );
+  return error;
+}
+
+
+void  _HB_OPEN_Free_LookupList( HB_LookupList*  ll,
+		       HB_Type         type,
+		       FT_Memory        memory )
+{
+  FT_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, memory );
+
+    FREE( l );
+  }
+}
+
+
+
+/*****************************
+ * Coverage related functions
+ *****************************/
+
+
+/* CoverageFormat1 */
+
+static FT_Error  Load_Coverage1( HB_CoverageFormat1*  cf1,
+				 FT_Stream             stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort  n, count;
+
+  FT_UShort* ga;
+
+
+  if ( ACCESS_Frame( 2L ) )
+    return error;
+
+  count = cf1->GlyphCount = GET_UShort();
+
+  FORGET_Frame();
+
+  cf1->GlyphArray = NULL;
+
+  if ( ALLOC_ARRAY( cf1->GlyphArray, count, FT_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 FT_Err_Ok;
+}
+
+
+static void  Free_Coverage1( HB_CoverageFormat1*  cf1,
+			     FT_Memory             memory)
+{
+  FREE( cf1->GlyphArray );
+}
+
+
+/* CoverageFormat2 */
+
+static FT_Error  Load_Coverage2( HB_CoverageFormat2*  cf2,
+				 FT_Stream             stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_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 = HB_Err_Invalid_SubTable;
+      goto Fail;
+    }
+  }
+
+  FORGET_Frame();
+
+  return FT_Err_Ok;
+
+Fail:
+  FREE( cf2->RangeRecord );
+  return error;
+}
+
+
+static void  Free_Coverage2( HB_CoverageFormat2*  cf2,
+			     FT_Memory             memory )
+{
+  FREE( cf2->RangeRecord );
+}
+
+
+FT_Error  _HB_OPEN_Load_Coverage( HB_Coverage*  c,
+			 FT_Stream      stream )
+{
+  FT_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 HB_Err_Invalid_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+void  _HB_OPEN_Free_Coverage( HB_Coverage*  c,
+		     FT_Memory      memory )
+{
+  switch ( c->CoverageFormat )
+  {
+  case 1:
+    Free_Coverage1( &c->cf.cf1, memory );
+    break;
+
+  case 2:
+    Free_Coverage2( &c->cf.cf2, memory );
+    break;
+  }
+}
+
+
+static FT_Error  Coverage_Index1( HB_CoverageFormat1*  cf1,
+				  FT_UShort             glyphID,
+				  FT_UShort*            index )
+{
+  FT_UShort min, max, new_min, new_max, middle;
+
+  FT_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 FT_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 FT_Error  Coverage_Index2( HB_CoverageFormat2*  cf2,
+				  FT_UShort             glyphID,
+				  FT_UShort*            index )
+{
+  FT_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 FT_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;
+}
+
+
+FT_Error  _HB_OPEN_Coverage_Index( HB_Coverage*  c,
+			  FT_UShort      glyphID,
+			  FT_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 HB_Err_Invalid_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+
+/*************************************
+ * Class Definition related functions
+ *************************************/
+
+
+/* ClassDefFormat1 */
+
+static FT_Error  Load_ClassDef1( HB_ClassDefinition*  cd,
+				 FT_UShort             limit,
+				 FT_Stream             stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort             n, count;
+
+  FT_UShort*            cva;
+  FT_Bool*              d;
+
+  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 HB_Err_Invalid_SubTable;
+
+  cdf1->ClassValueArray = NULL;
+
+  if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, FT_UShort ) )
+    return error;
+
+  d   = cd->Defined;
+  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 = HB_Err_Invalid_SubTable;
+      goto Fail;
+    }
+    d[cva[n]] = TRUE;
+  }
+
+  FORGET_Frame();
+
+  return FT_Err_Ok;
+
+Fail:
+  FREE( cva );
+
+  return error;
+}
+
+
+static void  Free_ClassDef1( HB_ClassDefFormat1*  cdf1,
+			     FT_Memory             memory )
+{
+  FREE( cdf1->ClassValueArray );
+}
+
+
+/* ClassDefFormat2 */
+
+static FT_Error  Load_ClassDef2( HB_ClassDefinition*  cd,
+				 FT_UShort             limit,
+				 FT_Stream             stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort              n, count;
+
+  HB_ClassRangeRecord*  crr;
+  FT_Bool*               d;
+
+  HB_ClassDefFormat2*   cdf2;
+
+
+  cdf2 = &cd->cd.cd2;
+
+  if ( ACCESS_Frame( 2L ) )
+    return error;
+
+  count = cdf2->ClassRangeCount = GET_UShort();
+
+  FORGET_Frame();
+
+  cdf2->ClassRangeRecord = NULL;
+
+  if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) )
+    return error;
+
+  d   = cd->Defined;
+  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 )
+    {
+      error = HB_Err_Invalid_SubTable;
+      goto Fail;
+    }
+    d[crr[n].Class] = TRUE;
+  }
+
+  FORGET_Frame();
+
+  return FT_Err_Ok;
+
+Fail:
+  FREE( crr );
+
+  return error;
+}
+
+
+static void  Free_ClassDef2( HB_ClassDefFormat2*  cdf2,
+			     FT_Memory             memory )
+{
+  FREE( cdf2->ClassRangeRecord );
+}
+
+
+/* ClassDefinition */
+
+FT_Error  _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition*  cd,
+				FT_UShort             limit,
+				FT_Stream             stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+
+  if ( ALLOC_ARRAY( cd->Defined, limit, FT_Bool ) )
+    return error;
+
+  if ( ACCESS_Frame( 2L ) )
+    goto Fail;
+
+  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 = HB_Err_Invalid_SubTable_Format;
+    break;
+  }
+
+  if ( error )
+    goto Fail;
+
+  cd->loaded = TRUE;
+
+  return FT_Err_Ok;
+
+Fail:
+  FREE( cd->Defined );
+  return error;
+}
+
+
+FT_Error  _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition*  cd,
+				     FT_Stream             stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+
+  if ( ALLOC_ARRAY( cd->Defined, 1, FT_Bool ) )
+    return error;
+
+  cd->ClassFormat = 1; /* Meaningless */
+  cd->Defined[0] = FALSE;
+
+  if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, FT_UShort ) )
+    goto Fail;
+
+  return FT_Err_Ok;
+
+Fail:
+  FREE( cd->Defined );
+  return error;
+}
+
+void  _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition*  cd,
+			    FT_Memory             memory )
+{
+  if ( !cd->loaded )
+    return;
+
+  FREE( cd->Defined );
+
+  switch ( cd->ClassFormat )
+  {
+  case 1:
+    Free_ClassDef1( &cd->cd.cd1, memory );
+    break;
+
+  case 2:
+    Free_ClassDef2( &cd->cd.cd2, memory );
+    break;
+  }
+}
+
+
+static FT_Error  Get_Class1( HB_ClassDefFormat1*  cdf1,
+			     FT_UShort             glyphID,
+			     FT_UShort*            class,
+			     FT_UShort*            index )
+{
+  FT_UShort*  cva = cdf1->ClassValueArray;
+
+
+  if ( index )
+    *index = 0;
+
+  if ( glyphID >= cdf1->StartGlyph &&
+       glyphID <= cdf1->StartGlyph + cdf1->GlyphCount )
+  {
+    *class = cva[glyphID - cdf1->StartGlyph];
+    return FT_Err_Ok;
+  }
+  else
+  {
+    *class = 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 FT_Error  Get_Class2( HB_ClassDefFormat2*  cdf2,
+			     FT_UShort             glyphID,
+			     FT_UShort*            class,
+			     FT_UShort*            index )
+{
+  FT_Error               error = FT_Err_Ok;
+  FT_UShort              min, max, new_min, new_max, middle;
+
+  HB_ClassRangeRecord*  crr = cdf2->ClassRangeRecord;
+
+
+  /* binary search */
+
+  if ( cdf2->ClassRangeCount == 0 )
+    {
+      *class = 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 )
+    {
+      *class = crr[middle].Class;
+      error  = FT_Err_Ok;
+      break;
+    }
+    else if ( glyphID < crr[middle].Start )
+    {
+      if ( middle == min )
+      {
+	*class = 0;
+	error  = HB_Err_Not_Covered;
+	break;
+      }
+      new_max = middle - 1;
+    }
+    else
+    {
+      if ( middle == max )
+      {
+	*class = 0;
+	error  = HB_Err_Not_Covered;
+	break;
+      }
+      new_min = middle + 1;
+    }
+  } while ( min < max );
+
+  if ( index )
+    *index = middle;
+
+  return error;
+}
+
+
+FT_Error  _HB_OPEN_Get_Class( HB_ClassDefinition*  cd,
+		     FT_UShort             glyphID,
+		     FT_UShort*            class,
+		     FT_UShort*            index )
+{
+  switch ( cd->ClassFormat )
+  {
+  case 1:
+    return Get_Class1( &cd->cd.cd1, glyphID, class, index );
+
+  case 2:
+    return Get_Class2( &cd->cd.cd2, glyphID, class, index );
+
+  default:
+    return HB_Err_Invalid_SubTable_Format;
+  }
+
+  return FT_Err_Ok;               /* never reached */
+}
+
+
+
+/***************************
+ * Device related functions
+ ***************************/
+
+
+FT_Error  _HB_OPEN_Load_Device( HB_Device*  d,
+		       FT_Stream    stream )
+{
+  FT_Error   error;
+  FT_Memory  memory = stream->memory;
+
+  FT_UShort   n, count;
+
+  FT_UShort*  dv;
+
+
+  if ( ACCESS_Frame( 6L ) )
+    return error;
+
+  d->StartSize   = GET_UShort();
+  d->EndSize     = GET_UShort();
+  d->DeltaFormat = GET_UShort();
+
+  FORGET_Frame();
+
+  if ( d->StartSize > d->EndSize ||
+       d->DeltaFormat == 0 || d->DeltaFormat > 3 )
+    return HB_Err_Invalid_SubTable;
+
+  d->DeltaValue = NULL;
+
+  count = ( ( d->EndSize - d->StartSize + 1 ) >>
+	      ( 4 - d->DeltaFormat ) ) + 1;
+
+  if ( ALLOC_ARRAY( d->DeltaValue, count, FT_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 FT_Err_Ok;
+}
+
+
+void  _HB_OPEN_Free_Device( HB_Device*  d,
+		   FT_Memory    memory )
+{
+  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                                    */
+
+FT_Error  _HB_OPEN_Get_Device( HB_Device*  d,
+		      FT_UShort    size,
+		      FT_Short*    value )
+{
+  FT_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 = (FT_Short)( bits & mask );
+
+    /* conversion to a signed value */
+
+    if ( *value >= ( ( mask + 1 ) >> 1 ) )
+      *value -= mask + 1;
+
+    return FT_Err_Ok;
+  }
+  else
+  {
+    *value = 0;
+    return HB_Err_Not_Covered;
+  }
+}
+
+
+/* END */
diff --git a/src/harfbuzz-open.h b/src/harfbuzz-open.h
new file mode 100644
index 0000000..17e1f29
--- /dev/null
+++ b/src/harfbuzz-open.h
@@ -0,0 +1,285 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_OPEN_H
+#define HARFBUZZ_OPEN_H
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+FT_BEGIN_HEADER
+
+/* Use this if a feature applies to all glyphs */
+#define HB_ALL_GLYPHS                    0xFFFF
+
+#define HB_DEFAULT_LANGUAGE              0xFFFF
+
+#define HB_MAX_NESTING_LEVEL             100
+
+#define HB_Err_Invalid_SubTable_Format   0x1000
+#define HB_Err_Invalid_SubTable          0x1001
+#define HB_Err_Not_Covered               0x1002
+#define HB_Err_Too_Many_Nested_Contexts  0x1003
+#define HB_Err_No_MM_Interpreter         0x1004
+#define HB_Err_Empty_Script              0x1005
+
+
+/* Script list related structures */
+
+struct  HB_LangSys_
+{
+  FT_UShort   LookupOrderOffset;      /* always 0 for TT Open 1.0  */
+  FT_UShort   ReqFeatureIndex;        /* required FeatureIndex     */
+  FT_UShort   FeatureCount;           /* number of Feature indices */
+  FT_UShort*  FeatureIndex;           /* array of Feature indices  */
+};
+
+typedef struct HB_LangSys_  HB_LangSys;
+
+
+struct  HB_LangSysRecord_
+{
+  FT_ULong     LangSysTag;            /* LangSysTag identifier */
+  HB_LangSys  LangSys;               /* LangSys table         */
+};
+
+typedef struct HB_LangSysRecord_  HB_LangSysRecord;
+
+
+struct  HB_Script_
+{
+  HB_LangSys         DefaultLangSys; /* DefaultLangSys table     */
+  FT_UShort           LangSysCount;   /* number of LangSysRecords */
+  HB_LangSysRecord*  LangSysRecord;  /* array of LangSysRecords  */
+};
+
+typedef struct HB_Script_  HB_Script;
+
+
+struct  HB_ScriptRecord_
+{
+  FT_ULong    ScriptTag;              /* ScriptTag identifier */
+  HB_Script  Script;                 /* Script table         */
+};
+
+typedef struct HB_ScriptRecord_  HB_ScriptRecord;
+
+
+struct  HB_ScriptList_
+{
+  FT_UShort          ScriptCount;     /* number of ScriptRecords */
+  HB_ScriptRecord*  ScriptRecord;    /* array of ScriptRecords  */
+};
+
+typedef struct HB_ScriptList_  HB_ScriptList;
+
+
+/* Feature list related structures */
+
+struct HB_Feature_
+{
+  FT_UShort   FeatureParams;          /* always 0 for TT Open 1.0     */
+  FT_UShort   LookupListCount;        /* number of LookupList indices */
+  FT_UShort*  LookupListIndex;        /* array of LookupList indices  */
+};
+
+typedef struct HB_Feature_  HB_Feature;
+
+
+struct  HB_FeatureRecord_
+{
+  FT_ULong     FeatureTag;            /* FeatureTag identifier */
+  HB_Feature  Feature;               /* Feature table         */
+};
+
+typedef struct HB_FeatureRecord_  HB_FeatureRecord;
+
+
+struct  HB_FeatureList_
+{
+  FT_UShort           FeatureCount;   /* number of FeatureRecords */
+  HB_FeatureRecord*  FeatureRecord;  /* array of FeatureRecords  */
+  FT_UShort*		ApplyOrder;	/* order to apply features */
+  FT_UShort		ApplyCount;	/* number of elements in ApplyOrder */
+};
+
+typedef struct HB_FeatureList_  HB_FeatureList;
+
+
+/* Lookup list related structures */
+
+typedef struct HB_SubTable_  HB_SubTable;
+
+
+struct  HB_Lookup_
+{
+  FT_UShort      LookupType;          /* Lookup type         */
+  FT_UShort      LookupFlag;          /* Lookup qualifiers   */
+  FT_UShort      SubTableCount;       /* number of SubTables */
+  HB_SubTable*  SubTable;            /* array of SubTables  */
+};
+
+typedef struct HB_Lookup_  HB_Lookup;
+
+
+/* The `Properties' field is not defined in the OpenType specification but
+   is needed for processing lookups.  If properties[n] is > 0, the
+   functions HB_GSUB_Apply_String() resp. HB_GPOS_Apply_String() will
+   process Lookup[n] for glyphs which have the specific bit not set in
+   the `properties' field of the input string object.                  */
+
+struct  HB_LookupList_
+{
+  FT_UShort    LookupCount;           /* number of Lookups       */
+  HB_Lookup*  Lookup;                /* array of Lookup records */
+  FT_UInt*     Properties;            /* array of flags          */
+};
+
+typedef struct HB_LookupList_  HB_LookupList;
+
+
+/* Possible LookupFlag bit masks.  `HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS' comes from the
+   OpenType 1.2 specification; HB_LOOKUP_FLAG_RIGHT_TO_LEFT has been (re)introduced in
+   OpenType 1.3 -- if set, the last glyph in a cursive attachment
+   sequence has to be positioned on the baseline -- regardless of the
+   writing direction.                                                    */
+
+#define HB_LOOKUP_FLAG_RIGHT_TO_LEFT         0x0001
+#define HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS    0x0002
+#define HB_LOOKUP_FLAG_IGNORE_LIGATURES      0x0004
+#define HB_LOOKUP_FLAG_IGNORE_MARKS          0x0008
+#define HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS  0xFF00
+
+
+struct  HB_CoverageFormat1_
+{
+  FT_UShort   GlyphCount;             /* number of glyphs in GlyphArray */
+  FT_UShort*  GlyphArray;             /* array of glyph IDs             */
+};
+
+typedef struct HB_CoverageFormat1_  HB_CoverageFormat1;
+
+
+struct HB_RangeRecord_
+{
+  FT_UShort  Start;                   /* first glyph ID in the range */
+  FT_UShort  End;                     /* last glyph ID in the range  */
+  FT_UShort  StartCoverageIndex;      /* coverage index of first
+					 glyph ID in the range       */
+};
+
+typedef struct HB_RangeRecord_  HB_RangeRecord;
+
+
+struct  HB_CoverageFormat2_
+{
+  FT_UShort         RangeCount;       /* number of RangeRecords */
+  HB_RangeRecord*  RangeRecord;      /* array of RangeRecords  */
+};
+
+typedef struct HB_CoverageFormat2_  HB_CoverageFormat2;
+
+
+struct  HB_Coverage_
+{
+  FT_UShort  CoverageFormat;          /* 1 or 2 */
+
+  union
+  {
+    HB_CoverageFormat1  cf1;
+    HB_CoverageFormat2  cf2;
+  } cf;
+};
+
+typedef struct HB_Coverage_  HB_Coverage;
+
+
+struct  HB_ClassDefFormat1_
+{
+  FT_UShort   StartGlyph;             /* first glyph ID of the
+					 ClassValueArray             */
+  FT_UShort   GlyphCount;             /* size of the ClassValueArray */
+  FT_UShort*  ClassValueArray;        /* array of class values       */
+};
+
+typedef struct HB_ClassDefFormat1_  HB_ClassDefFormat1;
+
+
+struct  HB_ClassRangeRecord_
+{
+  FT_UShort  Start;                   /* first glyph ID in the range    */
+  FT_UShort  End;                     /* last glyph ID in the range     */
+  FT_UShort  Class;                   /* applied to all glyphs in range */
+};
+
+typedef struct HB_ClassRangeRecord_  HB_ClassRangeRecord;
+
+
+struct  HB_ClassDefFormat2_
+{
+  FT_UShort              ClassRangeCount;
+				      /* number of ClassRangeRecords */
+  HB_ClassRangeRecord*  ClassRangeRecord;
+				      /* array of ClassRangeRecords  */
+};
+
+typedef struct HB_ClassDefFormat2_  HB_ClassDefFormat2;
+
+
+/* The `Defined' field is not defined in the OpenType specification but
+   apparently needed for processing fonts like trado.ttf: This font
+   refers to a class which contains not a single element.  We map such
+   classes to class 0.                                                 */
+
+struct  HB_ClassDefinition_
+{
+  FT_Bool    loaded;
+
+  FT_Bool*   Defined;                 /* array of Booleans.
+					 If Defined[n] is FALSE,
+					 class n contains no glyphs. */
+  FT_UShort  ClassFormat;             /* 1 or 2                      */
+
+  union
+  {
+    HB_ClassDefFormat1  cd1;
+    HB_ClassDefFormat2  cd2;
+  } cd;
+};
+
+typedef struct HB_ClassDefinition_  HB_ClassDefinition;
+
+
+struct HB_Device_
+{
+  FT_UShort   StartSize;              /* smallest size to correct      */
+  FT_UShort   EndSize;                /* largest size to correct       */
+  FT_UShort   DeltaFormat;            /* DeltaValue array data format:
+					 1, 2, or 3                    */
+  FT_UShort*  DeltaValue;             /* array of compressed data      */
+};
+
+typedef struct HB_Device_  HB_Device;
+
+
+enum  HB_Type_
+{
+  HB_Type_GSUB,
+  HB_Type_GPOS
+};
+
+typedef enum HB_Type_  HB_Type;
+
+
+FT_END_HEADER
+
+#endif /* HARFBUZZ_OPEN_H */
diff --git a/src/harfbuzz.c b/src/harfbuzz.c
new file mode 100644
index 0000000..4fd8bf9
--- /dev/null
+++ b/src/harfbuzz.c
@@ -0,0 +1,19 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#include "ftglue.c"
+#include "harfbuzz-open.c"
+#include "harfbuzz-buffer.c"
+#include "harfbuzz-gdef.c"
+#include "harfbuzz-gsub.c"
+#include "harfbuzz-gpos.c"
+#include "harfbuzz-dump.c"
diff --git a/src/harfbuzz.h b/src/harfbuzz.h
new file mode 100644
index 0000000..e8e08a2
--- /dev/null
+++ b/src/harfbuzz.h
@@ -0,0 +1,23 @@
+/*******************************************************************
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Copyright 2006  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ *  See the file name COPYING for licensing information.
+ *
+ ******************************************************************/
+#ifndef HARFBUZZ_H
+#define HARFBUZZ_H
+
+#include "harfbuzz-open.h"
+#include "harfbuzz-buffer.h"
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-gsub.h"
+#include "harfbuzz-gpos.h"
+#include "harfbuzz-dump.h"
+
+#endif /* HARFBUZZ_OPEN_H */
diff --git a/src/otlbuffer.c b/src/otlbuffer.c
deleted file mode 100644
index 5578f8e..0000000
--- a/src/otlbuffer.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/* otlbuffer.c: Buffer of glyphs for substitution/positioning
- *
- * Copyright 2004 Red Hat Software
- *
- * Portions Copyright 1996-2000 by
- * David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- * This file is part of the FreeType project, and may only be used
- * modified and distributed under the terms of the FreeType project
- * license, LICENSE.TXT.  By continuing to use, modify, or distribute
- * this file you indicate that you have read the license and
- * understand and accept it fully.
- */
-
-#include <config.h>
-
-#include <otlbuffer.h>
-
-/* To get the gcc-3.3 strict-aliasing compatible versions
- * FREE/REALLOC_ARRAY/etc. rather than the FT_* versions
- * that
- */
-#include "ftglue.h"
-
-  static FT_Error
-  otl_buffer_ensure( OTL_Buffer buffer,
-		     FT_ULong   size )
-  {
-    FT_Memory memory = buffer->memory;
-    FT_ULong new_allocated = buffer->allocated;
-
-    if (size > new_allocated)
-      {
-	FT_Error error;
-
-	while (size > new_allocated)
-	  new_allocated += (new_allocated >> 1) + 8;
-	
-	if ( REALLOC_ARRAY( buffer->in_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) )
-	  return error;
-	if ( REALLOC_ARRAY( buffer->out_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) )
-	  return error;
-	if ( REALLOC_ARRAY( buffer->positions, buffer->allocated, new_allocated, OTL_PositionRec ) )
-	  return error;
-
-	buffer->allocated = new_allocated;
-      }
-
-    return FT_Err_Ok;
-  }
-
-  FT_Error
-  otl_buffer_new( FT_Memory   memory,
-		  OTL_Buffer *buffer )
-  {
-    FT_Error error;
-    
-    if ( ALLOC( *buffer, sizeof( OTL_BufferRec ) ) )
-      return error;
-
-    (*buffer)->memory = memory;
-    (*buffer)->in_length = 0;
-    (*buffer)->out_length = 0;
-    (*buffer)->allocated = 0;
-    (*buffer)->in_pos = 0;
-    (*buffer)->out_pos = 0;
-
-    (*buffer)->in_string = NULL;
-    (*buffer)->out_string = NULL;
-    (*buffer)->positions = NULL;
-    (*buffer)->max_ligID = 0;
-
-    return FT_Err_Ok;
-  }
-
-  FT_Error
-  otl_buffer_swap( OTL_Buffer buffer )
-  {
-    OTL_GlyphItem tmp_string;
-
-    tmp_string = buffer->in_string;
-    buffer->in_string = buffer->out_string;
-    buffer->out_string = tmp_string;
-
-    buffer->in_length = buffer->out_length;
-    buffer->out_length = 0;
-    
-    buffer->in_pos = 0;
-    buffer->out_pos = 0;
-
-    return FT_Err_Ok;
-  }
-
-  FT_Error
-  otl_buffer_free( OTL_Buffer buffer )
-  {
-    FT_Memory memory = buffer->memory;
-
-    FREE( buffer->in_string );
-    FREE( buffer->out_string );
-    FREE( buffer->positions );
-    FREE( buffer );
-
-    return FT_Err_Ok;
-  }
-
-  FT_Error
-  otl_buffer_clear( OTL_Buffer buffer )
-  {
-    buffer->in_length = 0;
-    buffer->out_length = 0;
-    buffer->in_pos = 0;
-    buffer->out_pos = 0;
-    
-    return FT_Err_Ok;
-  }
-
-  FT_Error
-  otl_buffer_add_glyph( OTL_Buffer buffer,
-			FT_UInt    glyph_index,
-			FT_UInt    properties,
-			FT_UInt    cluster )
-  {
-    FT_Error error;
-    OTL_GlyphItem glyph;
-    
-    error = otl_buffer_ensure( buffer, buffer->in_length + 1 );
-    if ( error )
-      return error;
-
-    glyph = &buffer->in_string[buffer->in_length];
-    glyph->gindex = glyph_index;
-    glyph->properties = properties;
-    glyph->cluster = cluster;
-    glyph->component = 0;
-    glyph->ligID = 0;
-    glyph->gproperties = OTL_GLYPH_PROPERTIES_UNKNOWN;
-    
-    buffer->in_length++;
-
-    return FT_Err_Ok;
-  }
-
-  /* The following function copies `num_out' elements from `glyph_data'
-     to `buffer->out_string', advancing the in array pointer in the structure
-     by `num_in' elements, and the out array pointer by `num_out' elements.
-     Finally, it sets the `length' field of `out' equal to
-     `pos' of the `out' structure.
-
-     If `component' is 0xFFFF, the component value from buffer->in_pos
-     will copied `num_out' times, otherwise `component' itself will
-     be used to fill the `component' fields.
-
-     If `ligID' is 0xFFFF, the ligID value from buffer->in_pos
-     will copied `num_out' times, otherwise `ligID' itself will
-     be used to fill the `ligID' fields.
-
-     The properties for all replacement glyphs are taken
-     from the glyph at position `buffer->in_pos'.
-
-     The cluster value for the glyph at position buffer->in_pos is used
-     for all replacement glyphs */
-  FT_Error
-  otl_buffer_add_output_glyphs( OTL_Buffer buffer,
-				FT_UShort  num_in,
-				FT_UShort  num_out,
-				FT_UShort *glyph_data,
-				FT_UShort  component,
-				FT_UShort  ligID )
-  {
-    FT_Error  error;
-    FT_UShort i;
-    FT_UInt properties;
-    FT_UInt cluster;
-
-    error = otl_buffer_ensure( buffer, buffer->out_pos + num_out );
-    if ( error )
-      return error;
-
-    properties = buffer->in_string[buffer->in_pos].properties;
-    cluster = buffer->in_string[buffer->in_pos].cluster;
-    if ( component == 0xFFFF )
-      component = buffer->in_string[buffer->in_pos].component;
-    if ( ligID == 0xFFFF )
-      ligID = buffer->in_string[buffer->in_pos].ligID;
-
-    for ( i = 0; i < num_out; i++ )
-    {
-      OTL_GlyphItem item = &buffer->out_string[buffer->out_pos + i];
-
-      item->gindex = glyph_data[i];
-      item->properties = properties;
-      item->cluster = cluster;
-      item->component = component;
-      item->ligID = ligID;
-      item->gproperties = OTL_GLYPH_PROPERTIES_UNKNOWN;
-    }
-
-    buffer->in_pos  += num_in;
-    buffer->out_pos += num_out;
-
-    buffer->out_length = buffer->out_pos;
-
-    return FT_Err_Ok;
-  }
-
-  FT_Error
-  otl_buffer_add_output_glyph( OTL_Buffer buffer,	
-			       FT_UInt    glyph_index,
-			       FT_UShort  component,
-			       FT_UShort  ligID )
-  {
-    FT_UShort glyph_data =  glyph_index;
-
-    return otl_buffer_add_output_glyphs ( buffer, 1, 1,
-					  &glyph_data, component, ligID );
-  }
-
-  FT_Error
-  otl_buffer_copy_output_glyph ( OTL_Buffer buffer )
-  {  
-    FT_Error  error;
-
-    error = otl_buffer_ensure( buffer, buffer->out_pos + 1 );
-    if ( error )
-      return error;
-    
-    buffer->out_string[buffer->out_pos++] = buffer->in_string[buffer->in_pos++];
-    buffer->out_length = buffer->out_pos;
-
-    return FT_Err_Ok;
-  }
-
-  FT_UShort
-  otl_buffer_allocate_ligid( OTL_Buffer buffer )
-  {
-    return buffer->max_ligID++;
-  }
diff --git a/src/otlbuffer.h b/src/otlbuffer.h
deleted file mode 100644
index bcb4e3e..0000000
--- a/src/otlbuffer.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* otlbuffer.h: Buffer of glyphs for substitution/positioning
- *
- * Copyrigh 2004 Red Hat Software
- *
- * Portions Copyright 1996-2000 by
- * David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- * This file is part of the FreeType project, and may only be used
- * modified and distributed under the terms of the FreeType project
- * license, LICENSE.TXT.  By continuing to use, modify, or distribute
- * this file you indicate that you have read the license and
- * understand and accept it fully.
- */
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-#define OTL_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
-
-  typedef struct OTL_GlyphItemRec_ {
-    FT_UInt     gindex;
-    FT_UInt     properties;
-    FT_UInt     cluster;
-    FT_UShort   component;
-    FT_UShort   ligID;
-    FT_UShort   gproperties;
-  } OTL_GlyphItemRec, *OTL_GlyphItem;
-
-  typedef struct OTL_PositionRec_ {
-    FT_Pos     x_pos;
-    FT_Pos     y_pos;
-    FT_Pos     x_advance;
-    FT_Pos     y_advance;
-    FT_UShort  back;            /* number of glyphs to go back
-                                   for drawing current glyph   */
-    FT_Bool    new_advance;     /* if set, the advance width values are
-                                   absolute, i.e., they won't be
-                                   added to the original glyph's value
-                                   but rather replace them.            */
-    FT_Short  cursive_chain;   /* character to which this connects,
- 				   may be positive or negative; used
- 				   only internally                     */
-  } OTL_PositionRec, *OTL_Position;
-
-
-  typedef struct OTL_BufferRec_{ 
-    FT_Memory   memory;
-    FT_ULong    allocated;
-
-    FT_ULong    in_length;
-    FT_ULong    out_length;
-    FT_ULong    in_pos;
-    FT_ULong    out_pos;
-    
-    OTL_GlyphItem  in_string;
-    OTL_GlyphItem  out_string;
-    OTL_Position   positions;
-    FT_UShort      max_ligID;
-  } OTL_BufferRec, *OTL_Buffer;
-
-  FT_Error
-  otl_buffer_new( FT_Memory   memory,
-		  OTL_Buffer *buffer );
-
-  FT_Error
-  otl_buffer_swap( OTL_Buffer buffer );
-
-  FT_Error
-  otl_buffer_free( OTL_Buffer buffer );
-
-  FT_Error
-  otl_buffer_clear( OTL_Buffer buffer );
-
-  FT_Error
-  otl_buffer_add_glyph( OTL_Buffer buffer,
-			FT_UInt    glyph_index,
-			FT_UInt    properties,
-			FT_UInt    cluster );
-
-  FT_Error
-  otl_buffer_add_output_glyphs( OTL_Buffer buffer,
-				FT_UShort  num_in,
-				FT_UShort  num_out,
-				FT_UShort *glyph_data,
-				FT_UShort  component,
-				FT_UShort  ligID );
-
-  FT_Error
-  otl_buffer_add_output_glyph ( OTL_Buffer buffer,
-			        FT_UInt    glyph_index,
-			        FT_UShort  component,
-			        FT_UShort  ligID );
-
-  FT_Error
-  otl_buffer_copy_output_glyph ( OTL_Buffer buffer );
-
-  FT_UShort
-  otl_buffer_allocate_ligid( OTL_Buffer buffer );
-
-G_END_DECLS