shithub: freetype+ttf2subf

Download patch

ref: adff5b0c210d90eb6da88ee2fe8376e0d3a70a77
parent: 80ed03e2bbb1c890869f5c8e53571cd091518e96
author: Werner Lemberg <[email protected]>
date: Sat Aug 14 03:20:43 EDT 2004

* src/otlayout/otljstf.c (otl_jstf_gsub_mods_validate): Removed.
(otl_jstf_gpos_mods_validate): Renamed to...
(otl_jstf_gsubgpos_mods_validate): This.
Test whether lookup_count is zero.
(otl_jstf_priority_validate): Use otl_jstf_gsubgpos_mods_validate.
(otl_jstf_validate): Initialize gsub_lookup_count and
gpos_lookup_count if gsub or gpos is zero.

* src/otlayout/otlgsub.c: Rename counting variables to be more
meaningful.
Add copyright.
(otl_gsub_lookup1_validate): Simplify code.
(otl_gsub_lookup2_validate, otl_gsub_lookup3_validate,
otl_gsub_lookup4_validate, otl_gsub_lookup7_validate): Remove unused
variables.
(otl_gsub_lookup5_validate): Remove unused variable.
Fix call to otl_sub_rule_set_validate and
otl_sub_class_rule_set_validate.
(otl_chain_sub_class_rule_validate,
otl_chain_sub_class_set_validate): Removed.
(otl_gsub_lookup6_validate): Remove unused variable.
Fix call to otl_chain_sub_rule_set_validate.
(otl_gsub_lookup7_validate): Handle lookup type 8 also.
(otl_gsub_lookup8_validate: New function.
(otl_gsub_lookup1_apply, otl_gsub_lookup2_apply,
otl_gsub_lookup3_apply): Commented out.
(otl_gsub_validate_funcs): Add otl_gsub_lookup7_validate and
otl_gsub_lookup8_validate.
(otl_gsub_validate): Updated.

* src/otlayout/otlgsub.h: Add copyright.

* src/otlayout/otlcommn.c, src/otlayout/otlcommn.h
(otl_coverage_get_index): Comment out.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2004-08-14  Werner Lemberg  <[email protected]>
+
+	* src/otlayout/otljstf.c (otl_jstf_gsub_mods_validate): Removed.
+	(otl_jstf_gpos_mods_validate): Renamed to...
+	(otl_jstf_gsubgpos_mods_validate): This.
+	Test whether lookup_count is zero.
+	(otl_jstf_priority_validate): Use otl_jstf_gsubgpos_mods_validate.
+	(otl_jstf_validate): Initialize gsub_lookup_count and
+	gpos_lookup_count if gsub or gpos is zero.
+
+	* src/otlayout/otlgsub.c: Rename counting variables to be more
+	meaningful.
+	Add copyright.
+	(otl_gsub_lookup1_validate): Simplify code.
+	(otl_gsub_lookup2_validate, otl_gsub_lookup3_validate,
+	otl_gsub_lookup4_validate, otl_gsub_lookup7_validate): Remove unused
+	variables.
+	(otl_gsub_lookup5_validate): Remove unused variable.
+	Fix call to otl_sub_rule_set_validate and
+	otl_sub_class_rule_set_validate.
+	(otl_chain_sub_class_rule_validate,
+	otl_chain_sub_class_set_validate): Removed.
+	(otl_gsub_lookup6_validate): Remove unused variable.
+	Fix call to otl_chain_sub_rule_set_validate.
+	(otl_gsub_lookup7_validate): Handle lookup type 8 also.
+	(otl_gsub_lookup8_validate: New function.
+	(otl_gsub_lookup1_apply, otl_gsub_lookup2_apply,
+	otl_gsub_lookup3_apply): Commented out.
+	(otl_gsub_validate_funcs): Add otl_gsub_lookup7_validate and
+	otl_gsub_lookup8_validate.
+	(otl_gsub_validate): Updated.
+
+	* src/otlayout/otlgsub.h: Add copyright.
+
+	* src/otlayout/otlcommn.c, src/otlayout/otlcommn.h
+	(otl_coverage_get_index): Comment out.
+
 2004-08-13  Werner Lemberg  <[email protected]>
 
 	* src/otlayout/otlcommn.c (otl_gsubgpos_get_lookup_count): New
--- a/src/otlayout/otlcommn.c
+++ b/src/otlayout/otlcommn.c
@@ -47,7 +47,6 @@
 
         OTL_CHECK( num_glyphs * 2 );
 
-        /* XXX: check glyph indices */
       }
       break;
 
@@ -81,6 +80,9 @@
     default:
       OTL_INVALID_FORMAT;
     }
+
+    /* no need to check glyph indices used as input to coverage tables */
+    /* since even invalid glyph indices return a meaningful result     */
   }
 
 
@@ -122,6 +124,7 @@
   }
 
 
+#if 0
   OTL_LOCALDEF( OTL_Long )
   otl_coverage_get_index( OTL_Bytes  table,
                           OTL_UInt   glyph_index )
@@ -186,6 +189,7 @@
 
     return -1;
   }
+#endif
 
 
   /*************************************************************************/
@@ -219,7 +223,6 @@
 
         OTL_CHECK( num_glyphs * 2 );
 
-        /* XXX: check glyph indices */
       }
       break;
 
@@ -249,6 +252,9 @@
     default:
       OTL_INVALID_FORMAT;
     }
+
+    /* no need to check glyph indices used as input to class definition   */
+    /* tables since even invalid glyph indices return a meaningful result */
   }
 
 
--- a/src/otlayout/otlcommn.h
+++ b/src/otlayout/otlcommn.h
@@ -41,11 +41,13 @@
   OTL_LOCAL( OTL_UInt )
   otl_coverage_get_count( OTL_Bytes  table );
 
+#if 0
   /* Return the coverage index corresponding to a glyph glyph index. */
   /* Return -1 if the glyph isn't covered.                           */
   OTL_LOCAL( OTL_Long )
   otl_coverage_get_index( OTL_Bytes  table,
                           OTL_UInt   glyph_index );
+#endif
 
 
   /*************************************************************************/
--- a/src/otlayout/otlgsub.c
+++ b/src/otlayout/otlgsub.c
@@ -1,40 +1,59 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otlgsub.c                                                              */
+/*                                                                         */
+/*    OpenType layout support, GSUB table (body).                          */
+/*                                                                         */
+/*  Copyright 2002, 2004 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 "otlgsub.h"
 #include "otlcommn.h"
 #include "otlparse.h"
 
- /* forward declaration */
+
+  /* forward declaration */
   static OTL_ValidateFunc  otl_gsub_validate_funcs[];
 
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                 GSUB LOOKUP TYPE 1                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  GSUB LOOKUP TYPE 1                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
- /*
-  *  1: Single Substitution - Table format(s)
-  *
-  *  This table is used to substiture individual glyph indices
-  *  with another one. There are only two sub-formats:
-  *
-  *   Name         Offset    Size       Description
-  *   ------------------------------------------
-  *   format       0         2          sub-table format (1)
-  *   offset       2         2          offset to coverage table
-  *   delta        4         2          16-bit delta to apply on all
-  *                                     covered glyph indices
-  *
-  *   Name         Offset    Size       Description
-  *   ------------------------------------------
-  *   format       0         2          sub-table format (2)
-  *   offset       2         2          offset to coverage table
-  *   count        4         2          coverage table count
-  *   substs[]     6         2*count    substituted glyph indices,
-  *
-  */
+  /*
+   * 1: Single Substitution - Table format(s)
+   *
+   * This table is used to substitute individual glyph indices
+   * with another one.  There are only two sub-formats:
+   *
+   *   Name         Offset    Size       Description
+   *   --------------------------------------------------------------
+   *   format       0         2          sub-table format (1)
+   *   offset       2         2          offset to coverage table
+   *   delta        4         2          16-bit delta to apply on all
+   *                                     covered glyph indices
+   *
+   *   Name         Offset    Size       Description
+   *   --------------------------------------------------------------
+   *   format       0         2          sub-table format (2)
+   *   offset       2         2          offset to coverage table
+   *   count        4         2          coverage table count
+   *   substs[]     6         2*count    substituted glyph indices,
+   *
+   */
 
   static void
   otl_gsub_lookup1_validate( OTL_Bytes      table,
@@ -43,45 +62,47 @@
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
+
     switch ( format )
     {
-      case 1:
-        {
-          OTL_UInt  coverage;
+    case 1:
+      OTL_CHECK( 4 );
 
-          OTL_CHECK( 4 );
-          coverage = OTL_NEXT_USHORT( p );
+      otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-          otl_coverage_validate( table + coverage, valid );
-        }
-        break;
+      /* skip delta glyph ID */
 
-      case 2:
-        {
-          OTL_UInt  coverage, count;
+      break;
 
-          OTL_CHECK( 4 );
-          coverage = OTL_NEXT_USHORT( p );
-          count    = OTL_NEXT_USHORT( p );
+    case 2:
+      {
+        OTL_UInt  coverage, num_glyphs;
 
-          otl_coverage_validate( table + coverage, valid );
 
-          OTL_CHECK( 2*count );
+        OTL_CHECK( 4 );
+        coverage   = OTL_NEXT_USHORT( p );
+        num_glyphs = OTL_NEXT_USHORT( p );
 
-          /* NB: we don't check that there are at most 'count'   */
-          /*     elements in the coverage table. This is delayed */
-          /*     to the lookup function...                       */
-        }
-        break;
+        otl_coverage_validate( table + coverage, valid );
 
-      default:
-        OTL_INVALID_DATA;
+        OTL_CHECK( 2 * num_glyphs );
+
+        /* We don't check that there are at most `num_glyphs' */
+        /* elements in the coverage table.  This is delayed   */
+        /* to the lookup function.                            */
+      }
+      break;
+
+    default:
+      OTL_INVALID_DATA;
     }
   }
 
 
+#if 0
   static OTL_Bool
   otl_gsub_lookup1_apply( OTL_Bytes   table,
                           OTL_Parser  parser )
@@ -92,6 +113,7 @@
     OTL_Long   index;
     OTL_Bool   subst = 0;
 
+
     if ( parser->context_len != 0xFFFFU && parser->context_len < 1 )
       goto Exit;
 
@@ -142,51 +164,55 @@
   Exit:
     return subst;
   }
+#endif
 
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                 GSUB LOOKUP TYPE 2                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  GSUB LOOKUP TYPE 2                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
- /*
-  *  2: Multiple Substitution - Table format(s)
-  *
-  *  Replaces a single glyph with one or more glyphs.
-  *
-  *   Name         Offset    Size       Description
-  *   -----------------------------------------------------------
-  *   format       0         2          sub-table format (1)
-  *   offset       2         2          offset to coverage table
-  *   count        4         2          coverage table count
-  *   sequencess[] 6         2*count    offsets to sequence items
-  *
-  *   each sequence item has the following format:
-  *
-  *   Name         Offset    Size       Description
-  *   -----------------------------------------------------------
-  *   count        0         2          number of replacement glyphs
-  *   gindices[]   2         2*count    string of glyph indices
-  */
+  /*
+   * 2: Multiple Substitution - Table format(s)
+   *
+   * Replaces a single glyph with one or more glyphs.
+   *
+   *   Name         Offset    Size       Description
+   *   --------------------------------------------------------------
+   *   format       0         2          sub-table format (1)
+   *   offset       2         2          offset to coverage table
+   *   count        4         2          coverage table count
+   *   sequencess[] 6         2*count    offsets to sequence items
+   *
+   * each sequence item has the following format:
+   *
+   *   Name         Offset    Size       Description
+   *   --------------------------------------------------------------
+   *   count        0         2          number of replacement glyphs
+   *   gindices[]   2         2*count    string of glyph indices
+   *
+   */
 
   static void
-  otl_seq_validate( OTL_Bytes      table,
-                    OTL_Validator  valid )
+  otl_sequence_validate( OTL_Bytes      table,
+                         OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   count;
+    OTL_UInt   num_glyphs;
 
+
     OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+    num_glyphs = OTL_NEXT_USHORT( p );
 
-    /* XXX: according to the spec, 'count' should be > 0     */
-    /*      we can deal with these cases pretty well however */
+    /* XXX: according to the spec, `num_glyphs' should be > 0; */
+    /*      we can deal with these cases pretty well, however  */
 
-    OTL_CHECK( 2*count );
-    /* check glyph indices */
+    OTL_CHECK( 2 * num_glyphs );
+
+    /* XXX: check glyph indices */
   }
 
 
@@ -195,34 +221,39 @@
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   format, coverage;
+    OTL_UInt   format;
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
     {
-      case 1:
-        {
-          OTL_UInt  coverage, seq_count;
+    case 1:
+      {
+        OTL_UInt  coverage, num_sequences;
 
-          OTL_CHECK( 4 );
-          coverage  = OTL_NEXT_USHORT( p );
-          seq_count = OTL_NEXT_USHORT( p );
 
-          otl_coverage_validate( table + coverage, valid );
+        OTL_CHECK( 4 );
+        coverage      = OTL_NEXT_USHORT( p );
+        num_sequences = OTL_NEXT_USHORT( p );
 
-          OTL_CHECK( seq_count*2 );
-          for ( ; seq_count > 0; seq_count-- )
-            otl_seq_validate( table + OTL_NEXT_USHORT( p ), valid );
-        }
-        break;
+        otl_coverage_validate( table + coverage, valid );
 
-      default:
-        OTL_INVALID_DATA;
+        OTL_CHECK( num_sequences * 2 );
+
+        /* scan sequence records */
+        for ( ; num_sequences > 0; num_sequences-- )
+          otl_sequence_validate( table + OTL_NEXT_USHORT( p ), valid );
+      }
+      break;
+
+    default:
+      OTL_INVALID_DATA;
     }
   }
 
 
+#if 0
   static OTL_Bool
   otl_gsub_lookup2_apply( OTL_Bytes    table,
                           OTL_Parser   parser )
@@ -233,6 +264,7 @@
     OTL_Long   index;
     OTL_Bool   subst = 0;
 
+
     if ( parser->context_len != 0xFFFFU && parser->context_len < 1 )
       goto Exit;
 
@@ -261,37 +293,39 @@
    Exit:
     return subst;
   }
+#endif
 
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                 GSUB LOOKUP TYPE 3                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 3                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
- /*
-  *  3: Alternate Substitution - Table format(s)
-  *
-  *  Replaces a single glyph by another one taken liberally
-  *  in a list of alternatives
-  *
-  *   Name         Offset    Size       Description
-  *   -----------------------------------------------------------
-  *   format       0         2          sub-table format (1)
-  *   offset       2         2          offset to coverage table
-  *   count        4         2          coverage table count
-  *   alternates[] 6         2*count    offsets to alternate items
-  *
-  *   each alternate item has the following format:
-  *
-  *   Name         Offset    Size       Description
-  *   -----------------------------------------------------------
-  *   count        0         2          number of replacement glyphs
-  *   gindices[]   2         2*count    string of glyph indices, each one
-  *                                     is a valid alternative
-  */
+  /*
+   * 3: Alternate Substitution - Table format(s)
+   *
+   * Replaces a single glyph by another one taken liberally
+   * in a list of alternatives.
+   *
+   *   Name         Offset    Size       Description
+   *   ---------------------------------------------------------------
+   *   format       0         2          sub-table format (1)
+   *   offset       2         2          offset to coverage table
+   *   count        4         2          coverage table count
+   *   alternates[] 6         2*count    offsets to alternate items
+   *
+   * each alternate item has the following format:
+   *
+   *   Name         Offset    Size       Description
+   *   ---------------------------------------------------------------
+   *   count        0         2          number of replacement glyphs
+   *   gindices[]   2         2*count    string of glyph indices, each
+   *                                     one is a valid alternative
+   *
+   */
 
   static void
   otl_alternate_set_validate( OTL_Bytes      table,
@@ -300,10 +334,12 @@
     OTL_Bytes  p = table;
     OTL_UInt   count;
 
+
     OTL_CHECK( 2 );
     count = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2*count );
+    OTL_CHECK( 2 * count );
+
     /* XXX: check glyph indices */
   }
 
@@ -313,34 +349,39 @@
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   format, coverage;
+    OTL_UInt   format;
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
     {
-      case 1:
-        {
-          OTL_UInt  coverage, count;
+    case 1:
+      {
+        OTL_UInt  coverage, num_alternate_sets;
 
-          OTL_CHECK( 4 );
-          coverage = OTL_NEXT_USHORT( p );
-          count    = OTL_NEXT_USHORT( p );
 
-          otl_coverage_validate( table + coverage, valid );
+        OTL_CHECK( 4 );
+        coverage           = OTL_NEXT_USHORT( p );
+        num_alternate_sets = OTL_NEXT_USHORT( p );
 
-          OTL_CHECK( 2*count );
-          for ( ; count > 0; count-- )
-            otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid );
-        }
-        break;
+        otl_coverage_validate( table + coverage, valid );
 
-      default:
-        OTL_INVALID_DATA;
+        OTL_CHECK( 2 * num_alternate_sets );
+
+        /* scan alternate set records */
+        for ( ; num_alternate_sets > 0; num_alternate_sets-- )
+          otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+      }
+      break;
+
+    default:
+      OTL_INVALID_DATA;
     }
   }
 
 
+#if 0
   static OTL_Bool
   otl_gsub_lookup3_apply( OTL_Bytes    table,
                           OTL_Parser   parser )
@@ -353,6 +394,7 @@
 
     OTL_GSUB_Alternate  alternate = parser->alternate;
 
+
     if ( parser->context_len != 0xFFFFU && parser->context_len < 1 )
       goto Exit;
 
@@ -387,30 +429,34 @@
    Exit:
     return subst;
   }
+#endif
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                 GSUB LOOKUP TYPE 4                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
 
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 4                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
   static void
   otl_ligature_validate( OTL_Bytes      table,
                          OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   glyph_id, count;
+    OTL_UInt   glyph_id, num_components;
 
+
     OTL_CHECK( 4 );
-    glyph_id = OTL_NEXT_USHORT( p );
-    count    = OTL_NEXT_USHORT( p );
+    glyph_id       = OTL_NEXT_USHORT( p );
+    num_components = OTL_NEXT_USHORT( p );
 
-    if ( count == 0 )
+    if ( num_components == 0 )
       OTL_INVALID_DATA;
 
-    OTL_CHECK( 2*(count-1) );
+    OTL_CHECK( 2 * ( num_components - 1 ) );
+
     /* XXX: check glyph indices */
   }
 
@@ -420,13 +466,16 @@
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   count;
+    OTL_UInt   num_ligatures;
 
+
     OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+    num_ligatures = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2*count );
-    for ( ; count > 0; count-- )
+    OTL_CHECK( 2 * num_ligatures );
+
+    /* scan ligature records */
+    for ( ; num_ligatures > 0; num_ligatures-- )
       otl_ligature_validate( table + OTL_NEXT_USHORT( p ), valid );
   }
 
@@ -436,58 +485,62 @@
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   format, coverage;
+    OTL_UInt   format;
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
     {
-      case 1:
-        {
-          OTL_UInt  coverage, count;
+    case 1:
+      {
+        OTL_UInt  coverage, num_ligsets;
 
-          OTL_CHECK( 4 );
-          coverage = OTL_NEXT_USHORT( p );
-          count    = OTL_NEXT_USHORT( p );
 
-          otl_coverage_validate( table + coverage, valid );
+        OTL_CHECK( 4 );
+        coverage    = OTL_NEXT_USHORT( p );
+        num_ligsets = OTL_NEXT_USHORT( p );
 
-          OTL_CHECK( 2*count );
-          for ( ; count > 0; count-- )
-            otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid );
-        }
-        break;
+        otl_coverage_validate( table + coverage, valid );
 
-      default:
-        OTL_INVALID_DATA;
+        OTL_CHECK( 2 * num_ligsets );
+
+        /* scan ligature set records */
+        for ( ; num_ligsets > 0; num_ligsets-- )
+          otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+      }
+      break;
+
+    default:
+      OTL_INVALID_DATA;
     }
   }
 
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                 GSUB LOOKUP TYPE 5                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  GSUB LOOKUP TYPE 5                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
-
   static void
   otl_sub_rule_validate( OTL_Bytes      table,
                          OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   glyph_count, subst_count;
+    OTL_UInt   num_glyphs, num_subst;
 
+
     OTL_CHECK( 4 );
-    glyph_count = OTL_NEXT_USHORT( p );
-    subst_count = OTL_NEXT_USHORT( p );
+    num_glyphs = OTL_NEXT_USHORT( p );
+    num_subst  = OTL_NEXT_USHORT( p );
 
-    if ( glyph_count == 0 )
+    if ( num_glyphs == 0 )
       OTL_INVALID_DATA;
 
-    OTL_CHECK( (glyph_count-1)*2 + subst_count*4 );
+    OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_subst * 4 );
 
     /* XXX: check glyph indices and subst lookups */
   }
@@ -498,13 +551,16 @@
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   count;
+    OTL_UInt   num_subrules;
 
+
     OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+    num_subrules = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2*count );
-    for ( ; count > 0; count-- )
+    OTL_CHECK( 2 * num_subrules );
+
+    /* scan sub rule records */
+    for ( ; num_subrules > 0; num_subrules-- )
       otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
   }
 
@@ -514,18 +570,22 @@
                                OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   glyph_count, subst_count;
+    OTL_UInt   num_glyphs, num_subst;
 
+
     OTL_CHECK( 4 );
-    glyph_count = OTL_NEXT_USHORT( p );
-    subst_count = OTL_NEXT_USHORT( p );
+    num_glyphs = OTL_NEXT_USHORT( p );
+    num_subst  = OTL_NEXT_USHORT( p );
 
-    if ( glyph_count == 0 )
+    if ( num_glyphs == 0 )
       OTL_INVALID_DATA;
 
-    OTL_CHECK( (glyph_count-1)*2 + subst_count*4 );
+    OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_subst * 4 );
 
-    /* XXX: check glyph indices and subst lookups */
+    /* XXX: check subst lookups */
+
+    /* no need to check glyph indices used as input for this context    */
+    /* rule since even invalid glyph indices return a meaningful result */
   }
 
 
@@ -534,13 +594,16 @@
                                    OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   count;
+    OTL_UInt   num_subrules;
 
+
     OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+    num_subrules = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2*count );
-    for ( ; count > 0; count-- )
+    OTL_CHECK( 2 * num_subrules );
+
+    /* scan subrule records */
+    for ( ; num_subrules > 0; num_subrules-- )
       otl_sub_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
   }
 
@@ -550,298 +613,342 @@
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   format, coverage;
+    OTL_UInt   format;
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
     {
-      case 1:
-        {
-          OTL_UInt  coverage, count;
+    case 1:
+      {
+        OTL_UInt  coverage, num_subrulesets;
 
-          OTL_CHECK( 4 );
-          coverage = OTL_NEXT_USHORT( p );
-          count    = OTL_NEXT_USHORT( p );
 
-          otl_coverage_validate( table + coverage, valid );
+        OTL_CHECK( 4 );
+        coverage        = OTL_NEXT_USHORT( p );
+        num_subrulesets = OTL_NEXT_USHORT( p );
 
-          OTL_CHECK( 2*count );
-          for ( ; count > 0; count-- )
-            otl_sub_rule_set_validate( table + coverage, valid );
-        }
-        break;
+        otl_coverage_validate( table + coverage, valid );
 
-      case 2:
-        {
-          OTL_UInt  coverage, class_def, count;
+        OTL_CHECK( 2 * num_subrulesets );
 
-          OTL_CHECK( 6 );
-          coverage  = OTL_NEXT_USHORT( p );
-          class_def = OTL_NEXT_USHORT( p );
-          count     = OTL_NEXT_USHORT( p );
+        /* scan subrule set records */
+        for ( ; num_subrulesets > 0; num_subrulesets-- )
+          otl_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+      }
+      break;
 
-          otl_coverage_validate        ( table + coverage, valid );
-          otl_class_definition_validate( table + class_def, valid );
+    case 2:
+      {
+        OTL_UInt  coverage, class_def, num_subclass_sets;
 
-          OTL_CHECK( 2*count );
-          for ( ; count > 0; count-- )
-            otl_sub_class_rule_set_validate( table + coverage, valid );
-        }
-        break;
 
-      case 3:
-        {
-          OTL_UInt  glyph_count, subst_count, count;
+        OTL_CHECK( 6 );
+        coverage          = OTL_NEXT_USHORT( p );
+        class_def         = OTL_NEXT_USHORT( p );
+        num_subclass_sets = OTL_NEXT_USHORT( p );
 
-          OTL_CHECK( 4 );
-          glyph_count = OTL_NEXT_USHORT( p );
-          subst_count = OTL_NEXT_USHORT( p );
+        otl_coverage_validate( table + coverage, valid );
+        otl_class_definition_validate( table + class_def, valid );
 
-          OTL_CHECK( 2*glyph_count + 4*subst_count );
-          for ( count = glyph_count; count > 0; count-- )
-            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
-        }
-        break;
+        OTL_CHECK( 2 * num_subclass_sets );
 
-      default:
-        OTL_INVALID_DATA;
+        /* scan subclass set records */
+        for ( ; num_subclass_sets > 0; num_subclass_sets-- )
+          otl_sub_class_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+                                           valid );
+      }
+      break;
+
+    case 3:
+      {
+        OTL_UInt  num_glyphs, num_subst;
+
+
+        OTL_CHECK( 4 );
+        num_glyphs = OTL_NEXT_USHORT( p );
+        num_subst  = OTL_NEXT_USHORT( p );
+
+        OTL_CHECK( 2 * num_glyphs + 4 * num_subst );
+
+        for ( ; num_glyphs > 0; num_glyphs-- )
+          otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+        /* XXX: check subst lookups */
+      }
+      break;
+
+    default:
+      OTL_INVALID_DATA;
     }
   }
 
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                 GSUB LOOKUP TYPE 6                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 6                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
-
+  /* used for both format 1 and 2 */
   static void
   otl_chain_sub_rule_validate( OTL_Bytes      table,
                                OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   back_count, input_count, ahead_count, subst_count, count;
+    OTL_UInt   num_backtrack_glyphs, num_input_glyphs, num_lookahead_glyphs;
+    OTL_UInt   num_subst;
 
+
     OTL_CHECK( 2 );
-    back_count = OTL_NEXT_USHORT( p );
+    num_backtrack_glyphs = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2*back_count+2 );
-    p += 2*back_count;
+    OTL_CHECK( 2 * num_backtrack_glyphs + 2 );
+    p += 2 * num_backtrack_glyphs;
 
-    input_count = OTL_NEXT_USHORT( p );
-    if ( input_count == 0 )
+    num_input_glyphs = OTL_NEXT_USHORT( p );
+    if ( num_input_glyphs == 0 )
       OTL_INVALID_DATA;
 
-    OTL_CHECK( 2*input_count );
-    p += 2*(input_count-1);
+    OTL_CHECK( 2 * num_input_glyphs );
+    p += 2 * ( num_input_glyphs - 1 );
 
-    ahead_count = OTL_NEXT_USHORT( p );
-    OTL_CHECK( 2*ahead_count + 2 );
-    p += 2*ahead_count;
+    num_lookahead_glyphs = OTL_NEXT_USHORT( p );
+    OTL_CHECK( 2 * num_lookahead_glyphs + 2 );
+    p += 2 * num_lookahead_glyphs;
 
-    count = OTL_NEXT_USHORT( p );
-    OTL_CHECK( 4*count );
+    num_subst = OTL_NEXT_USHORT( p );
+    OTL_CHECK( 4 * num_subst );
 
-    /* XXX: check glyph indices and subst lookups */
+    /* XXX: check subst lookups */
+
+    /* no need to check glyph indices used as input for this context    */
+    /* rule since even invalid glyph indices return a meaningful result */
   }
 
 
+  /* used for both format 1 and 2 */
   static void
   otl_chain_sub_rule_set_validate( OTL_Bytes      table,
                                    OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   count;
+    OTL_UInt   num_chain_subrules;
 
+
     OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+    num_chain_subrules = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2*count );
-    for ( ; count > 0; count-- )
+    OTL_CHECK( 2 * num_chain_subrules );
+
+    /* scan chain subrule records */
+    for ( ; num_chain_subrules > 0; num_chain_subrules-- )
       otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
   }
 
 
   static void
-  otl_chain_sub_class_rule_validate( OTL_Bytes      table,
-                                     OTL_Validator  valid )
+  otl_gsub_lookup6_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   back_count, input_count, ahead_count, subst_count, count;
+    OTL_UInt   format;
 
+
     OTL_CHECK( 2 );
-    back_count = OTL_NEXT_USHORT( p );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+    case 1:
+      {
+        OTL_UInt  coverage, num_chain_subrulesets;
 
-    OTL_CHECK( 2*back_count+2 );
-    p += 2*back_count;
 
-    input_count = OTL_NEXT_USHORT( p );
-    if ( input_count == 0 )
-      OTL_INVALID_DATA;
+        OTL_CHECK( 4 );
+        coverage              = OTL_NEXT_USHORT( p );
+        num_chain_subrulesets = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2*input_count );
-    p += 2*(input_count-1);
+        otl_coverage_validate( table + coverage, valid );
 
-    ahead_count = OTL_NEXT_USHORT( p );
-    OTL_CHECK( 2*ahead_count + 2 );
-    p += 2*ahead_count;
+        OTL_CHECK( 2 * num_chain_subrulesets );
 
-    count = OTL_NEXT_USHORT( p );
-    OTL_CHECK( 4*count );
+        /* scan chain subrule set records */
+        for ( ; num_chain_subrulesets > 0; num_chain_subrulesets-- )
+          otl_chain_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+                                           valid );
+      }
+      break;
 
-    /* XXX: check class indices and subst lookups */
-  }
+    case 2:
+      {
+        OTL_UInt  coverage, back_class, input_class, ahead_class;
+        OTL_UInt  num_chain_subclass_sets;
 
 
+        OTL_CHECK( 10 );
+        coverage                = OTL_NEXT_USHORT( p );
+        back_class              = OTL_NEXT_USHORT( p );
+        input_class             = OTL_NEXT_USHORT( p );
+        ahead_class             = OTL_NEXT_USHORT( p );
+        num_chain_subclass_sets = OTL_NEXT_USHORT( p );
 
-  static void
-  otl_chain_sub_class_set_validate( OTL_Bytes      table,
-                                    OTL_Validator  valid )
-  {
-    OTL_Bytes  p = table;
-    OTL_UInt   count;
+        otl_coverage_validate( table + coverage, valid );
 
-    OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+        otl_class_definition_validate( table + back_class,  valid );
+        otl_class_definition_validate( table + input_class, valid );
+        otl_class_definition_validate( table + ahead_class, valid );
 
-    OTL_CHECK( 2*count );
-    for ( ; count > 0; count-- )
-      otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
-  }
+        OTL_CHECK( 2 * num_chain_subclass_sets );
 
+        /* scan chain subclass set records */
+        for ( ; num_chain_subclass_sets > 0; num_chain_subclass_sets-- )
+          otl_chain_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+                                           valid );
+      }
+      break;
 
-  static void
-  otl_gsub_lookup6_validate( OTL_Bytes      table,
-                             OTL_Validator  valid )
-  {
-    OTL_Bytes  p = table;
-    OTL_UInt   format, coverage;
+    case 3:
+      {
+        OTL_UInt  num_backtrack_glyphs, num_input_glyphs;
+        OTL_UInt  num_lookahead_glyphs, num_subst;
 
-    OTL_CHECK( 2 );
-    format = OTL_NEXT_USHORT( p );
-    switch ( format )
-    {
-      case 1:
-        {
-          OTL_UInt  coverage, count;
 
-          OTL_CHECK( 4 );
-          coverage = OTL_NEXT_USHORT( p );
-          count    = OTL_NEXT_USHORT( p );
+        OTL_CHECK( 2 );
 
-          otl_coverage_validate( table + coverage, valid );
+        num_backtrack_glyphs = OTL_NEXT_USHORT( p );
+        OTL_CHECK( 2 * num_backtrack_glyphs + 2 );
 
-          OTL_CHECK( 2*count );
-          for ( ; count > 0; count-- )
-            otl_chain_sub_rule_set_validate( table + coverage, valid );
-        }
-        break;
+        for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- )
+          otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-      case 2:
-        {
-          OTL_UInt  coverage, back_class, input_class, ahead_class, count;
+        num_input_glyphs = OTL_NEXT_USHORT( p );
+        OTL_CHECK( 2 * num_input_glyphs + 2 );
 
-          OTL_CHECK( 10 );
-          coverage    = OTL_NEXT_USHORT( p );
-          back_class  = OTL_NEXT_USHORT( p );
-          input_class = OTL_NEXT_USHORT( p );
-          ahead_class = OTL_NEXT_USHORT( p );
-          count       = OTL_NEXT_USHORT( p );
+        for ( ; num_input_glyphs > 0; num_input_glyphs-- )
+          otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-          otl_coverage_validate( table + coverage, valid );
+        num_lookahead_glyphs = OTL_NEXT_USHORT( p );
+        OTL_CHECK( 2 * num_lookahead_glyphs + 2 );
 
-          otl_class_definition_validate( table + back_class,  valid );
-          otl_class_definition_validate( table + input_class, valid );
-          otl_class_definition_validate( table + ahead_class, valid );
+        for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- )
+          otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-          OTL_CHECK( 2*count );
-          for ( ; count > 0; count-- )
-            otl_chain_sub_class_set_validate( table + OTL_NEXT_USHORT( p ),
-                                              valid );
-        }
-        break;
+        num_subst = OTL_NEXT_USHORT( p );
+        OTL_CHECK( num_subst * 4 );
 
-      case 3:
-        {
-          OTL_UInt  back_count, input_count, ahead_count, subst_count, count;
+        /* XXX: check subst lookups */
+      }
+      break;
 
-          OTL_CHECK( 2 );
-          back_count = OTL_NEXT_USHORT( p );
+    default:
+      OTL_INVALID_DATA;
+    }
+  }
 
-          OTL_CHECK( 2*back_count+2 );
-          for ( count = back_count; count > 0; count-- )
-            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-          input_count = OTL_NEXT_USHORT( p );
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 7                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
-          OTL_CHECK( 2*input_count+2 );
-          for ( count = input_count; count > 0; count-- )
-            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+  static void
+  otl_gsub_lookup7_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
 
-          ahead_count = OTL_NEXT_USHORT( p );
 
-          OTL_CHECK( 2*ahead_count+2 );
-          for ( count = ahead_count; count > 0; count-- )
-            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+    case 1:
+      {
+        OTL_UInt          lookup_type, lookup_offset;
+        OTL_ValidateFunc  validate;
 
-          subst_count = OTL_NEXT_USHORT( p );
-          OTL_CHECK( subst_count*4 );
-        }
-        break;
 
-      default:
-        OTL_INVALID_DATA;
+        OTL_CHECK( 6 );
+        lookup_type   = OTL_NEXT_USHORT( p );
+        lookup_offset = OTL_NEXT_ULONG( p );
+
+        if ( lookup_type == 0 || lookup_type == 7 || lookup_type > 8 )
+          OTL_INVALID_DATA;
+
+        validate = otl_gsub_validate_funcs[lookup_type - 1];
+        validate( table + lookup_offset, valid );
+      }
+      break;
+
+    default:
+      OTL_INVALID_DATA;
     }
   }
 
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                 GSUB LOOKUP TYPE 7                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 8                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
   static void
-  otl_gsub_lookup7_validate( OTL_Bytes      table,
+  otl_gsub_lookup8_validate( OTL_Bytes      table,
                              OTL_Validator  valid )
   {
-    OTL_Bytes  p = table;
-    OTL_UInt   format, coverage;
+    OTL_Bytes  p = table, coverage;
+    OTL_UInt   format;
+    OTL_UInt   num_backtrack_glyphs, num_lookahead_glyphs, num_glyphs;
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
     {
-      case 1:
-        {
-          OTL_UInt          lookup_type, lookup_offset;
-          OTL_ValidateFunc  validate;
+    case 1:
+      OTL_CHECK( 4 );
 
-          OTL_CHECK( 6 );
-          lookup_type   = OTL_NEXT_USHORT( p );
-          lookup_offset = OTL_NEXT_ULONG( p );
+      coverage = table + OTL_NEXT_USHORT( p );
+      num_backtrack_glyphs = OTL_NEXT_USHORT( p );
 
-          if ( lookup_type == 0 || lookup_type >= 7 )
-            OTL_INVALID_DATA;
+      otl_coverage_validate( coverage, valid );
 
-          validate = otl_gsub_validate_funcs[ lookup_type-1 ];
-          validate( table + lookup_offset, valid );
-        }
-        break;
+      OTL_CHECK( 2 * num_backtrack_glyphs + 2 );
 
-      default:
+      for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- )
+        otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+      num_lookahead_glyphs = OTL_NEXT_USHORT( p );
+      OTL_CHECK( 2 * num_lookahead_glyphs + 2 );
+
+      for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- )
+        otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+      num_glyphs = OTL_NEXT_USHORT( p );
+      if ( num_glyphs != otl_coverage_get_count( coverage ) )
         OTL_INVALID_DATA;
+
+      OTL_CHECK( 2 * num_glyphs );
+
+      /* XXX: check glyph indices */
+      break;
+
+    default:
+      OTL_INVALID_DATA;
     }
   }
 
 
-  static OTL_ValidateFunc  otl_gsub_validate_funcs[ 7 ] =
+  static OTL_ValidateFunc  otl_gsub_validate_funcs[8] =
   {
     otl_gsub_lookup1_validate,
     otl_gsub_lookup2_validate,
@@ -848,19 +955,20 @@
     otl_gsub_lookup3_validate,
     otl_gsub_lookup4_validate,
     otl_gsub_lookup5_validate,
-    otl_gsub_lookup6_validate
+    otl_gsub_lookup6_validate,
+    otl_gsub_lookup7_validate,
+    otl_gsub_lookup8_validate
   };
 
 
- /************************************************************************/
- /************************************************************************/
- /*****                                                              *****/
- /*****                         GSUB TABLE                           *****/
- /*****                                                              *****/
- /************************************************************************/
- /************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          GSUB TABLE                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
-
   OTL_LOCALDEF( void )
   otl_gsub_validate( OTL_Bytes      table,
                      OTL_Validator  valid )
@@ -868,6 +976,7 @@
     OTL_Bytes  p = table;
     OTL_UInt   scripts, features, lookups;
 
+
     OTL_CHECK( 10 );
 
     if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
@@ -877,7 +986,7 @@
     features = OTL_NEXT_USHORT( p );
     lookups  = OTL_NEXT_USHORT( p );
 
-    otl_lookup_list_validate( table + lookups, 7, otl_gsub_validate_funcs,
+    otl_lookup_list_validate( table + lookups, 8, otl_gsub_validate_funcs,
                               valid );
     otl_feature_list_validate( table + features, table + lookups, valid );
     otl_script_list_validate( table + scripts, table + features, valid );
--- a/src/otlayout/otlgsub.h
+++ b/src/otlayout/otlgsub.h
@@ -1,3 +1,21 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otlgsub.h                                                              */
+/*                                                                         */
+/*    OpenType layout support, GSUB table (specification).                 */
+/*                                                                         */
+/*  Copyright 2002, 2004 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 __OTLGSUB_H__
 #define __OTLGSUB_H__
 
@@ -5,11 +23,13 @@
 
 OTL_BEGIN_HEADER
 
-  typedef OTL_UInt  (*OTL_GSUB_AlternateFunc)( OTL_UInt     gindex,
-                                               OTL_UInt     count,
-                                               OTL_Bytes    alternates,
-                                               OTL_Pointer  data );
 
+  typedef OTL_UInt
+  (*OTL_GSUB_AlternateFunc)( OTL_UInt     gindex,
+                             OTL_UInt     count,
+                             OTL_Bytes    alternates,
+                             OTL_Pointer  data );
+
   typedef struct  OTL_GSUB_AlternateRec_
   {
     OTL_GSUB_AlternateFunc  handler_func;
@@ -26,3 +46,6 @@
 OTL_END_HEADER
 
 #endif /* __OTLGSUB_H__ */
+
+
+/* END */
--- a/src/otlayout/otljstf.c
+++ b/src/otlayout/otljstf.c
@@ -40,9 +40,9 @@
 
 
   static void
-  otl_jstf_gsub_mods_validate( OTL_Bytes      table,
-                               OTL_UInt       lookup_count,
-                               OTL_Validator  valid )
+  otl_jstf_gsubgpos_mods_validate( OTL_Bytes      table,
+                                   OTL_UInt       lookup_count,
+                                   OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   num_lookups;
@@ -52,32 +52,16 @@
     num_lookups = OTL_NEXT_USHORT( p );
     OTL_CHECK( num_lookups * 2 );
 
-    for ( ; num_lookups > 0; num_lookups-- )
-      if ( OTL_NEXT_USHORT( p ) >= lookup_count )
-        OTL_INVALID_DATA;
+    if ( lookup_count )
+    {
+      for ( ; num_lookups > 0; num_lookups-- )
+        if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+          OTL_INVALID_DATA;
+    }
   }
 
 
   static void
-  otl_jstf_gpos_mods_validate( OTL_Bytes      table,
-                               OTL_UInt       lookup_count,
-                               OTL_Validator  valid )
-  {
-    OTL_Bytes  p = table;
-    OTL_UInt   num_lookups;
-
-
-    OTL_CHECK( 2 );
-    num_lookups = OTL_NEXT_USHORT( p );
-    OTL_CHECK( num_lookups * 2 );
-
-    for ( ; num_lookups > 0; num_lookups-- )
-      if ( OTL_NEXT_USHORT( p ) >= lookup_count )
-        OTL_INVALID_DATA;
-  }
-
-
-  static void
   otl_jstf_max_validate( OTL_Bytes      table,
                          OTL_Validator  valid )
   {
@@ -111,20 +95,24 @@
     /* shrinkage GSUB enable/disable */
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gsub_mods_validate( table + val, gsub_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gsub_lookup_count,
+                                       valid );
 
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gsub_mods_validate( table + val, gsub_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gsub_lookup_count,
+                                       valid );
 
     /* shrinkage GPOS enable/disable */
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gpos_mods_validate( table + val, gpos_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gpos_lookup_count,
+                                       valid );
 
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gpos_mods_validate( table + val, gpos_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gpos_lookup_count,
+                                       valid );
 
     /* shrinkage JSTF max */
     val = OTL_NEXT_USHORT( p );
@@ -134,20 +122,24 @@
     /* extension GSUB enable/disable */
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gsub_mods_validate( table + val, gsub_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gsub_lookup_count,
+                                       valid );
 
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gsub_mods_validate( table + val, gsub_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gsub_lookup_count,
+                                       valid );
 
     /* extension GPOS enable/disable */
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gpos_mods_validate( table + val, gpos_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gpos_lookup_count,
+                                       valid );
 
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_gpos_mods_validate( table + val, gpos_lookup_count, valid );
+      otl_jstf_gsubgpos_mods_validate( table + val, gpos_lookup_count,
+                                       valid );
 
     /* extension JSTF max */
     val = OTL_NEXT_USHORT( p );
@@ -231,8 +223,15 @@
     num_scripts = OTL_NEXT_USHORT( p );
     OTL_CHECK( num_scripts * 6 );
 
-    gsub_lookup_count = otl_gsubgpos_get_lookup_count( gsub );
-    gpos_lookup_count = otl_gsubgpos_get_lookup_count( gpos );
+    if ( gsub )
+      gsub_lookup_count = otl_gsubgpos_get_lookup_count( gsub );
+    else
+      gsub_lookup_count = 0;
+
+    if ( gpos )
+      gpos_lookup_count = otl_gsubgpos_get_lookup_count( gpos );
+    else
+      gpos_lookup_count = 0;
 
     /* scan script records */
     for ( ; num_scripts > 0; num_scripts-- )
--- a/src/otlayout/otljstf.h
+++ b/src/otlayout/otljstf.h
@@ -25,8 +25,9 @@
 OTL_BEGIN_HEADER
 
 
-  /* validate JSTF table                            */
-  /* GSUB and GPOS tables must already be validated */
+  /* validate JSTF table                                         */
+  /* GSUB and GPOS tables must already be validated; if table is */
+  /* missing, set value to 0                                     */
   OTL_LOCAL( void )
   otl_jstf_validate( OTL_Bytes      table,
                      OTL_Bytes      gsub,