Versions changed to 0.9.12.
[m17n/libotf.git] / src / otfdrive.c
index 44cca1c..97e1974 100644 (file)
@@ -1,6 +1,6 @@
 /* otfdrive.c -- OpenType font driver.
 
-Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   National Institute of Advanced Industrial Science and Technology (AIST)
   Registration Number H15PRO167
 
@@ -27,10 +27,15 @@ write to the Free Software Foundation, Inc., 59 Temple Place, Suite
 #include <config.h>
 
 #include "otf.h"
-#include "otferror.h"
+#include "internal.h"
 
 extern int debug_flag;
 
+#ifdef USHORT
+#undef USHORT
+#endif
+#define USHORT unsigned short
+
 /* Return nonzero (-1 if ID is zero, 1 otherwise) if OTF_Glyph *G
    should be ignored according to LookupFlag FLAG.  */
 #define IGNORED_GLYPH(g, flag)                         \
@@ -107,14 +112,17 @@ gstring_subst (OTF *otf, OTF_GlyphString *gstring, int from, int to, int flag,
       if (gstring->glyphs[from + i].glyph_id != ids[i])
        {
          gstring->glyphs[from + i].c = 0;
-         if (otf->gdef)
+         if (otf->gdef && otf->gdef->glyph_class_def.offset)
            gstring->glyphs[from + i].GlyphClass
              = get_class_def (&otf->gdef->glyph_class_def, ids[i]);
          else
            gstring->glyphs[from + i].GlyphClass = 0;
+         if (otf->gdef && otf->gdef->mark_attach_class_def.offset)
+           gstring->glyphs[from + i].MarkAttachClass
+             = get_class_def (&otf->gdef->mark_attach_class_def, ids[i]);
        }
       gstring->glyphs[from + i].glyph_id = ids[i];
-      gstring->glyphs[from + i].positioning_type = 0;
+      gstring->glyphs[from + i].positioning_type = 1;
       gstring->glyphs[from + i].f.index.from = from_idx;
       gstring->glyphs[from + i].f.index.to = to_idx;
     }
@@ -207,7 +215,7 @@ get_langsys (OTF_ScriptList *script_list,
 static int
 setup_lookup_flags (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
                    OTF_LangSys *LangSys,
-                   const char *features, char *lookup_flags)
+                   const char *features, USHORT *lookup_flags)
 {
   int i, j, n = 0;
   OTF_Feature *feature;
@@ -217,7 +225,7 @@ setup_lookup_flags (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
     return -1;
   for (i = 0; i < FeatureList->FeatureCount; i++)
     feature_table[i] = 0;
-  memset (lookup_flags, 0, LookupList->LookupCount);
+  memset (lookup_flags, 0, sizeof (USHORT) * LookupList->LookupCount);
 
   while (*features)
     {
@@ -236,7 +244,7 @@ setup_lookup_flags (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
                {
                  feature = FeatureList->Feature + index;
                  for (j = 0; j < feature->LookupCount; j++)
-                   lookup_flags[feature->LookupListIndex[j]] = 1;
+                   lookup_flags[feature->LookupListIndex[j]] = index + 1;
                }
            }
          break;
@@ -254,14 +262,16 @@ setup_lookup_flags (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
       tag = OTF_tag (tagname);
       for (i = 0; i < LangSys->FeatureCount; i++)
        {
-         feature = FeatureList->Feature + LangSys->FeatureIndex[i];
+         int index = LangSys->FeatureIndex[i];
+
+         feature = FeatureList->Feature + index;
          if (tag == feature->FeatureTag)
            {
              if (feature_table[i])
                break;
              if (use_it > 0)
                for (j = 0; j < feature->LookupCount; j++)
-                 lookup_flags[feature->LookupListIndex[j]] = 1;
+                 lookup_flags[feature->LookupListIndex[j]] = index + 1;
              feature_table[i] = use_it;
              break;
            }
@@ -278,7 +288,7 @@ match_ids (OTF_GlyphString *gstring, int gidx, int flag,
   OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : -1);
   int i, j;
 
-  for (i = j = 0; i < count && g != gend; g += direction)
+  for (i = j = 0; i < count && g != gend; j++, g += direction)
     if (! IGNORED_GLYPH (g, flag)
        && g->glyph_id != ids[i++])
       return -1;
@@ -316,7 +326,7 @@ match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
   OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : -1);
   int i, j;
 
-  for (i = j = 0; i < count && g != gend; g += direction)
+  for (i = j = 0; i < count && g != gend; j++, g += direction)
     if (! IGNORED_GLYPH (g, flag)
        && get_class_def (class_def, g->glyph_id) != classes[i++])
       return -1;
@@ -359,7 +369,7 @@ match_coverages (OTF_GlyphString *gstring, int gidx, int flag, int count,
   OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : - 1);
   int i, j;
 
-  for (i = j = 0; i < count && g != gend; g += direction, j++)
+  for (i = j = 0; i < count && g != gend; j++, g += direction)
     if (! IGNORED_GLYPH (g, flag)
        && get_coverage_index (coverages + i++, g->glyph_id) < 0)
       return -1;
@@ -392,6 +402,12 @@ match_chain_coverages (OTF_GlyphString *gstring, int gidx, int flag,
   return 0;
 }
 
+/* Apply the lookup indexed by LOOKUP_LIST_INDEX in LOOKUP_LIST to the
+   glyphs indexed by GIDX in GSTRING and the followings.  If
+   successfully applied, return the index of the next glyph to apply
+   the lookup.  If not applied, return GIDX.  If error happened,
+   return -1.  */
+
 static int
 lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
             OTF_GlyphString *gstring, int gidx, int alternate_subst)
@@ -406,7 +422,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
   int i;
 
   if (IGNORED_GLYPH (g, flag))
-    return (gidx + 1);
+    return gidx;
 
   /* Try all subtables until one of them handles the current glyph.  */
   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
@@ -424,7 +440,8 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
        }
 
       if (alternate_subst
-         ? (lookup_type != 3 && lookup_type != 5 && lookup_type != 6)
+         ? (alternate_subst == 1
+            && lookup_type != 3 && lookup_type != 5 && lookup_type != 6)
          : (lookup_type == 3))
        continue;
 
@@ -443,6 +460,15 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
            g->glyph_id += subtable->u.single1.DeltaGlyphID;
          else
            g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
+         if (otf->gdef && otf->gdef->glyph_class_def.offset)
+           g->GlyphClass
+             = get_class_def (&otf->gdef->glyph_class_def, g->glyph_id);
+         else
+           g->GlyphClass = 0;
+         if (otf->gdef && otf->gdef->mark_attach_class_def.offset)
+           g->MarkAttachClass
+             = get_class_def (&otf->gdef->mark_attach_class_def, g->glyph_id);
+         g->positioning_type = 1;
          gidx++;
          break;
 
@@ -466,8 +492,12 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
              OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
              OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
 
-             gstring_subst (otf, gstring, gidx, gidx + 1, flag,
-                            altset->Alternate, altset->GlyphCount);
+             if (alternate_subst == 1)
+               gstring_subst (otf, gstring, gidx, gidx + 1, flag,
+                              altset->Alternate, altset->GlyphCount);
+             else
+               gstring_subst (otf, gstring, gidx, gidx + 1, flag,
+                              altset->Alternate, 1);
              gidx += altset->GlyphCount;;
            }
          else
@@ -522,7 +552,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
                                 rule->LookupRecord[k].LookupListIndex,
                                 gstring,
                                 gidx + rule->LookupRecord[k].SequenceIndex,
-                                alternate_subst);
+                                alternate_subst ? alternate_subst : 2);
                  gidx += rule->GlyphCount + (gstring->used - orig_used);
                  break;
                }
@@ -553,7 +583,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
                                   rule->LookupRecord[k].LookupListIndex,
                                   gstring,
                                   gidx + rule->LookupRecord[k].SequenceIndex,
-                                  alternate_subst);
+                                  alternate_subst ? alternate_subst : 2);
                    gidx += rule->GlyphCount + (gstring->used - orig_used);
                    break;
                  }
@@ -574,7 +604,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
                             context3->LookupRecord[j].LookupListIndex,
                             gstring,
                             gidx + context3->LookupRecord[j].SequenceIndex,
-                            alternate_subst);
+                            alternate_subst ? alternate_subst : 2);
              gidx += context3->GlyphCount + (gstring->used - orig_used);
            }
          break;
@@ -603,7 +633,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
                                 rule->LookupRecord[k].LookupListIndex,
                                 gstring,
                                 gidx + rule->LookupRecord[k].SequenceIndex,
-                                alternate_subst);
+                                alternate_subst ? alternate_subst : 2);
                  gidx += rule->InputGlyphCount + (gstring->used - orig_used);
                  break;
                }
@@ -639,7 +669,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
                                 rule->LookupRecord[k].LookupListIndex,
                                 gstring,
                                 gidx + rule->LookupRecord[k].SequenceIndex,
-                                alternate_subst);
+                                alternate_subst ? alternate_subst : 2);
                  gidx += rule->InputGlyphCount + (gstring->used - orig_used);
                  break;
                }
@@ -662,7 +692,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
                             context3->LookupRecord[j].LookupListIndex,
                             gstring,
                             gidx + context3->LookupRecord[j].SequenceIndex,
-                            alternate_subst);
+                            alternate_subst ? alternate_subst : 2);
              gidx += context3->InputGlyphCount + (gstring->used - orig_used);
            }
          break;
@@ -692,6 +722,7 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
            if (j < reverse->LookaheadGlyphCount)
              continue;
            g->glyph_id = reverse->Substitute[coverage_idx];
+           g->positioning_type = 1;
            gidx--;
          }
 
@@ -699,8 +730,6 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
          continue;
        }
     }
-  if (gidx == orig_gidx)
-    gidx++;
   return gidx;
 }
 
@@ -716,7 +745,7 @@ gstring_insert_for_gpos (OTF_GlyphString *gstring, int gidx)
 
   while (gidx < gstring->used
         && ! gstring->glyphs[gidx].glyph_id
-        && gstring->glyphs[gidx].positioning_type)
+        && (gstring->glyphs[gidx].positioning_type & 0xF))
     gidx++;
   GSTRING_INSERT (gstring, gidx, 1);
   gstring->glyphs[gidx] = gstring->glyphs[orig_gidx];
@@ -744,7 +773,7 @@ print_glyph_positioning (OTF_Glyph *g, int type)
 {
   if (type)
     fprintf (stderr, " %0X=", g->glyph_id);
-  switch (g->positioning_type)
+  switch (g->positioning_type & 0xF)
     {
     case 1: case 2:
       {
@@ -783,6 +812,8 @@ print_glyph_positioning (OTF_Glyph *g, int type)
     }
 }
 
+/* See the comment of lookup_gsub.  */
+
 static int
 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
             OTF_GlyphString *gstring, int gidx, int accumulate)
@@ -803,7 +834,7 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
     {
       if (debug_flag)
        fprintf (stderr, " glyph ignored\n");
-      return (gidx + 1);
+      return gidx;
     }
 
   /* Try all subtables until one of them handles the current glyph.  */
@@ -838,7 +869,6 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
       switch (lookup_type)
        {
        case 1:
-         positioning_type = lookup_type;
          if (subtable->Format == 1)
            {
              OTF_GPOS_Single1 *single1 = &subtable->u.single1;
@@ -853,12 +883,13 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              format = single2->ValueFormat;
              value = single2->Value + coverage_idx;
            }
-         if (accumulate && g->positioning_type)
+         if (accumulate && (g->positioning_type & 0xF))
            {
              gidx = gstring_insert_for_gpos (gstring, gidx);
              g = gstring->glyphs + gidx;
            }
-         g->positioning_type = positioning_type;
+         g->positioning_type
+           = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
          g->f.f1.format = format;
          g->f.f1.value = value;
          if (debug_flag)
@@ -888,14 +919,15 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
                    {
                      if (pair1->ValueFormat1)
                        {
-                         if (accumulate && g->positioning_type)
+                         if (accumulate && (g->positioning_type & 0xF))
                            {
                              gidx = gstring_insert_for_gpos (gstring, gidx);
                              g = gstring->glyphs + gidx;
                              next_gidx += gidx - orig_gidx;
                              nextg = gstring->glyphs + next_gidx;
                            }
-                         g->positioning_type = lookup_type;
+                         g->positioning_type
+                           = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
                          g->f.f2.format = pair1->ValueFormat1;
                          g->f.f2.value = &set->PairValueRecord[j].Value1;
                          if (debug_flag)
@@ -905,12 +937,13 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
                      g = nextg;
                      if (pair1->ValueFormat2)
                        {
-                         if (accumulate && g->positioning_type)
+                         if (accumulate && (g->positioning_type & 0xF))
                            {
                              gidx = gstring_insert_for_gpos (gstring, gidx);
                              g = gstring->glyphs + gidx;
                            }
-                         g->positioning_type = lookup_type;
+                         g->positioning_type
+                           = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
                          g->f.f2.format = pair1->ValueFormat2;
                          g->f.f2.value = &set->PairValueRecord[j].Value2;
                          if (debug_flag)
@@ -928,14 +961,15 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
                class2 = get_class_def (&pair2->ClassDef2, nextg->glyph_id);
                if (pair2->ValueFormat1)
                  {
-                   if (accumulate && g->positioning_type)
+                   if (accumulate && (g->positioning_type & 0xF))
                      {
                        gidx = gstring_insert_for_gpos (gstring, gidx);
                        g = gstring->glyphs + gidx;
                        next_gidx += gidx - orig_gidx;
                        nextg = gstring->glyphs + next_gidx;
                      }
-                   g->positioning_type = lookup_type;
+                   g->positioning_type
+                   = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
                    g->f.f2.format = pair2->ValueFormat1;
                    g->f.f2.value
                      = &pair2->Class1Record[class1].Class2Record[class2].Value1;
@@ -946,12 +980,13 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
                g = nextg;
                if (pair2->ValueFormat2)
                  {
-                   if (accumulate && g->positioning_type)
+                   if (accumulate && (g->positioning_type & 0xF))
                      {
                        gidx = gstring_insert_for_gpos (gstring, gidx);
                        g = gstring->glyphs + gidx;
                      }
-                   g->positioning_type = lookup_type;
+                   g->positioning_type
+                     = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
                    g->f.f2.format = pair2->ValueFormat2;
                    g->f.f2.value
                      = &pair2->Class1Record[class1].Class2Record[class2].Value2;
@@ -966,7 +1001,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
          {
            OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1;
 
-           g->positioning_type = lookup_type;
+           g->positioning_type
+             = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
            g->f.f3.entry_anchor
              = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor;
            g->f.f3.exit_anchor
@@ -1005,7 +1041,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              g->f.f4.mark_anchor = &mark_record->MarkAnchor;
              g->f.f4.base_anchor
                = &base_record->Anchor[mark_record->Class];
-             g->positioning_type = lookup_type;
+             g->positioning_type
+               = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
              if (debug_flag)
                print_glyph_positioning (g, 0);
              gidx++;
@@ -1033,7 +1070,7 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
                    && (IGNORED_GLYPH (ligg, flag)
                        || ligg->GlyphClass > OTF_GlyphClassLigature));
                   ligg--)
-               if (ligg->positioning_type == 5
+               if ((ligg->positioning_type & 0xF) == 5
                    && ligg->MarkAttachClass < mark_lig1->ClassCount)
                  num_class[ligg->MarkAttachClass]++;
              if (ligg < gstring->glyphs)
@@ -1055,7 +1092,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
                  if (lig_anchor[mark_record->Class].AnchorFormat
                      && num_class[mark_record->Class]-- == 0)
                    {
-                     g->positioning_type = lookup_type;
+                     g->positioning_type
+                       = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
                      g->f.f5.mark_anchor = &mark_record->MarkAnchor;
                      g->f.f5.ligature_anchor = lig_anchor + mark_record->Class;
                      if (debug_flag)
@@ -1094,7 +1132,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
              g->f.f6.mark2_anchor
                = &mark2_record->Anchor[mark1_record->Class];
-             g->positioning_type = lookup_type;
+             g->positioning_type
+               = (g->positioning_type & 0xFFFFFFF0) | lookup_type;
              if (debug_flag)
                print_glyph_positioning (g, 0);
              gidx++;
@@ -1274,14 +1313,13 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
          continue;
        }
     }
-  if (gidx == orig_gidx)
+  if (debug_flag)
     {
-      if (debug_flag)
+      if (gidx == orig_gidx)
        fprintf (stderr, " no match\n");
-      gidx++;
+      else
+       fprintf (stderr, "\n");
     }
-  else if (debug_flag)
-    fprintf (stderr, "\n");
   return gidx;
 }
 
@@ -1670,19 +1708,17 @@ OTF_get_variation_glyphs (OTF *otf, int c, OTF_GlyphID code[256])
   return n;
 }
 
-
 int
 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
 {
   OTF_GDEF *gdef;
   int i;
 
-  if (! otf->gdef
-      && OTF_get_table (otf, "GDEF") < 0)
-    return -1;
+  if (! otf->gdef)
+    OTF_get_table (otf, "GDEF");
   gdef = otf->gdef;
 
-  if (gdef->glyph_class_def.offset)
+  if (gdef && gdef->glyph_class_def.offset)
     for (i = 0; i < gstring->used; i++)
       gstring->glyphs[i].GlyphClass
        = get_class_def (&gdef->glyph_class_def,
@@ -1705,19 +1741,20 @@ static int
 OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
                         const char *script, const char *language,
                         const char *features,
-                        int alternate_subst)
+                        int alternate_subst, int with_log)
 {
   char *errfmt = "GSUB driving%s";
   int errret = -1;
   OTF_GSUB *gsub;
   OTF_LangSys *LangSys;
-  char *lookup_flags;
+  USHORT *lookup_flags;
   int i;
-
+  USHORT *log;
+  
   for (i = 0; i < gstring->used; i++)
     {
-      gstring->glyphs[i].positioning_type = 0;
       gstring->glyphs[i].f.index.from = gstring->glyphs[i].f.index.to = i;
+      gstring->glyphs[i].positioning_type = 0;
     }
 
   if (OTF_get_table (otf, "GSUB") < 0)
@@ -1731,7 +1768,7 @@ OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
   if (! LangSys)
     return errret;
 
-  lookup_flags = alloca (gsub->LookupList.LookupCount);
+  lookup_flags = alloca (sizeof (USHORT) * gsub->LookupList.LookupCount);
   if (! lookup_flags
       || setup_lookup_flags (&gsub->LookupList, &gsub->FeatureList, LangSys,
                             features, lookup_flags) < 0)
@@ -1748,10 +1785,17 @@ OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
          gidx = 0;
          while (gidx < gstring->used)
            {
-             gidx = lookup_gsub (otf, &gsub->LookupList, i, gstring, gidx,
-                                 alternate_subst);
-             if (gidx < 0)
+             int result = lookup_gsub (otf, &gsub->LookupList, i, gstring,
+                                       gidx, alternate_subst);
+             if (result < 0)
                return errret;
+             if (gidx < result)
+               for (; gidx < result; gidx++)
+                 gstring->glyphs[gidx].positioning_type
+                   = ((with_log && gstring->glyphs[gidx].positioning_type)
+                      ? (lookup_flags[i] << 4) : 0);
+             else
+               gidx++;
            }
        }
       else
@@ -1759,10 +1803,17 @@ OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
          gidx = gstring->used - 1;
          while (gidx >= 0)
            {
-             gidx = lookup_gsub (otf, &gsub->LookupList, i, gstring, gidx,
-                                 alternate_subst);
-             if (gidx < 0)
+             int result = lookup_gsub (otf, &gsub->LookupList, i, gstring,
+                                       gidx, alternate_subst);
+             if (result < 0)
                return errret;
+             if (gidx > result)
+               for (; gidx > result; gidx--)
+                 gstring->glyphs[gidx].positioning_type
+                   = ((with_log && gstring->glyphs[gidx].positioning_type)
+                      ? (lookup_flags[i] << 4) : 0);
+             else
+               gidx--;
            }
        }
     }
@@ -1776,20 +1827,32 @@ OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
 {
   if (! otf->cmap)
     OTF_get_table (otf, "cmap");
-  return OTF_drive_gsub_internal (otf, gstring, script, language, features, 0);
+  return OTF_drive_gsub_internal (otf, gstring, script, language, features,
+                                 0, 0);
 }
 
 int
+OTF_drive_gsub_with_log (OTF *otf, OTF_GlyphString *gstring,
+                        const char *script, const char *language,
+                        const char *features)
+{
+  if (! otf->cmap)
+    OTF_get_table (otf, "cmap");
+  return OTF_drive_gsub_internal (otf, gstring, script, language, features,
+                                 0, 1);
+}
+
+static int
 OTF_drive_gpos_internal (OTF *otf, OTF_GlyphString *gstring,
                         const char *script, const char *language,
                         const char *features,
-                        int accumulate)
+                        int accumulate, int with_log)
 {
   char *errfmt = "GPOS driving%s";
   int errret = -1;
   OTF_GPOS *gpos;
   OTF_LangSys *LangSys;
-  char *lookup_flags;
+  USHORT *lookup_flags;
   int i, n;
 
   for (i = 0; i < gstring->used; i++)
@@ -1806,7 +1869,7 @@ OTF_drive_gpos_internal (OTF *otf, OTF_GlyphString *gstring,
   if (! LangSys)
     return errret;
 
-  lookup_flags = alloca (gpos->LookupList.LookupCount);
+  lookup_flags = alloca (sizeof (USHORT) * gpos->LookupList.LookupCount);
   if (! lookup_flags
       || setup_lookup_flags (&gpos->LookupList, &gpos->FeatureList, LangSys,
                             features, lookup_flags) < 0)
@@ -1820,9 +1883,22 @@ OTF_drive_gpos_internal (OTF *otf, OTF_GlyphString *gstring,
 
       while (gidx < gstring->used)
        {
-         gidx = lookup_gpos (&gpos->LookupList, i, gstring, gidx, accumulate);
-         if (gidx < 0)
+         int result = lookup_gpos (&gpos->LookupList, i, gstring, gidx,
+                                   accumulate);
+         if (result < 0)
            return errret;
+         if (gidx < result)
+           for (; gidx < result; gidx++)
+             {
+               int positioning_type
+                 = gstring->glyphs[gidx].positioning_type & 0xF;
+
+               if (with_log && positioning_type)
+                 gstring->glyphs[gidx].positioning_type
+                   = positioning_type | (lookup_flags[i] << 4);
+             }
+         else
+           gidx++;
        }
     }
 
@@ -1835,7 +1911,8 @@ OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
 {
   if (! otf->cmap)
     OTF_get_table (otf, "cmap");
-  return OTF_drive_gpos_internal (otf, gstring, script, language, features, 0);
+  return OTF_drive_gpos_internal (otf, gstring, script, language, features,
+                                 0, 0);
 }
 
 int
@@ -1844,7 +1921,19 @@ OTF_drive_gpos2 (OTF *otf, OTF_GlyphString *gstring,
 {
   if (! otf->cmap)
     OTF_get_table (otf, "cmap");
-  return OTF_drive_gpos_internal (otf, gstring, script, language, features, 1);
+  return OTF_drive_gpos_internal (otf, gstring, script, language, features,
+                                 1, 0);
+}
+
+int
+OTF_drive_gpos_with_log (OTF *otf, OTF_GlyphString *gstring,
+                        const char *script, const char *language,
+                        const char *features)
+{
+  if (! otf->cmap)
+    OTF_get_table (otf, "cmap");
+  return OTF_drive_gpos_internal (otf, gstring, script, language, features,
+                                 1, 1);
 }
 
 int
@@ -1870,7 +1959,8 @@ OTF_drive_gsub_alternate (OTF *otf, OTF_GlyphString *gstring,
                          const char *script, const char *language,
                          const char *features)
 {
-  return OTF_drive_gsub_internal (otf, gstring, script, language, features, 1);
+  return OTF_drive_gsub_internal (otf, gstring, script, language, features,
+                                 1, 0);
 }
 
 static int
@@ -2021,7 +2111,7 @@ OTF_iterate_gsub_feature (OTF *otf, OTF_Feature_Callback callback,
 
   OTF_GSUB *gsub;
   OTF_LangSys *langsys;
-  char *lookup_flags;
+  USHORT *lookup_flags;
 
   if (OTF_get_table (otf, "GSUB") < 0)
     return errret;
@@ -2032,7 +2122,7 @@ OTF_iterate_gsub_feature (OTF *otf, OTF_Feature_Callback callback,
   langsys = get_langsys (&gsub->ScriptList, script, language);
   if (! langsys)
     return errret;
-  lookup_flags = alloca (gsub->LookupList.LookupCount);
+  lookup_flags = alloca (sizeof (USHORT) * gsub->LookupList.LookupCount);
   if (! lookup_flags
       || setup_lookup_flags (&gsub->LookupList, &gsub->FeatureList, langsys,
                             feature, lookup_flags) < 0)