(USHORT): New macro for "unsigned short".
[m17n/libotf.git] / src / otfdrive.c
index aca83bc..0139011 100644 (file)
@@ -31,6 +31,11 @@ write to the Free Software Foundation, Inc., 59 Temple Place, Suite
 
 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)                         \
@@ -121,27 +126,6 @@ gstring_subst (OTF *otf, OTF_GlyphString *gstring, int from, int to, int flag,
   return 0;
 }
 
-static int
-prepare_drive_log (OTF_DriveLog *log, int size)
-{
-  if (size > log->allocated)
-    {
-      OTF_Tag *tags;
-      int allocated = log->allocated;
-
-      while (size > allocated)
-       allocated <<= 1;
-      tags = realloc (log->tags, sizeof (OTF_Tag) * log->allocated);
-      if (! tags)
-       return -1;
-      log->allocated = allocated;
-      log->tags = tags;
-    }
-  log->size = 0;
-  return 0;
-}
-
-
 \f
 static int
 get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id)
@@ -228,7 +212,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;
@@ -238,7 +222,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)
     {
@@ -257,7 +241,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]] = i + 1;
                }
            }
          break;
@@ -282,7 +266,7 @@ setup_lookup_flags (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
                break;
              if (use_it > 0)
                for (j = 0; j < feature->LookupCount; j++)
-                 lookup_flags[feature->LookupListIndex[j]] = 1;
+                 lookup_flags[feature->LookupListIndex[j]] = j + 1;
              feature_table[i] = use_it;
              break;
            }
@@ -413,6 +397,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)
@@ -427,7 +417,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++)
@@ -720,8 +710,6 @@ lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
          continue;
        }
     }
-  if (gidx == orig_gidx)
-    gidx++;
   return gidx;
 }
 
@@ -737,7 +725,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];
@@ -765,7 +753,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:
       {
@@ -804,6 +792,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)
@@ -824,7 +814,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.  */
@@ -879,7 +869,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              gidx = gstring_insert_for_gpos (gstring, gidx);
              g = gstring->glyphs + gidx;
            }
-         g->positioning_type = positioning_type;
+         g->positioning_type
+           = (g->positioning_type & 0xFFFFFFF0) | positioning_type;
          g->f.f1.format = format;
          g->f.f1.value = value;
          if (debug_flag)
@@ -909,14 +900,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)
@@ -926,12 +918,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)
@@ -949,14 +942,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;
@@ -967,12 +961,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;
@@ -987,7 +982,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
@@ -1026,7 +1022,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++;
@@ -1054,7 +1051,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)
@@ -1076,7 +1073,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)
@@ -1115,7 +1113,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++;
@@ -1295,14 +1294,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;
 }
 
@@ -1726,19 +1724,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)
@@ -1752,7 +1751,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)
@@ -1761,6 +1760,7 @@ OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
   for (i = 0; i < gsub->LookupList.LookupCount; i++)
     {
       int gidx;
+      int j;
 
       if (! lookup_flags[i]) continue;
 
@@ -1769,10 +1769,21 @@ 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)
+               {
+                 if (with_log)
+                   for (j = gidx; j < result; j++)
+                     gstring->glyphs[j].positioning_type
+                       = ((gstring->glyphs[j].positioning_type & 0xF)
+                          | (lookup_flags[i] << 4));
+                 gidx = result;
+               }
+             else
+               gidx++;
            }
        }
       else
@@ -1780,10 +1791,21 @@ 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)
+               {
+                 if (with_log)
+                   for (j = gidx; j > result; j--)
+                     gstring->glyphs[j].positioning_type
+                       = ((gstring->glyphs[j].positioning_type & 0xF)
+                          | (lookup_flags[i] << 4));
+                 gidx = result;
+               }
+             else
+               gidx--;
            }
        }
     }
@@ -1797,20 +1819,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++)
@@ -1827,7 +1861,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)
@@ -1836,14 +1870,27 @@ OTF_drive_gpos_internal (OTF *otf, OTF_GlyphString *gstring,
   for (i = 0; i < gpos->LookupList.LookupCount; i++)
     {
       int gidx = 0;
+      int j;
 
       if (! lookup_flags[i]) continue;
 
       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)
+           {
+             if (with_log)
+               for (j = gidx; j < result; j++)
+                 gstring->glyphs[j].positioning_type
+                   = ((gstring->glyphs[j].positioning_type & 0xF)
+                      | (lookup_flags[i] << 4));
+             gidx = result;
+           }
+         else
+           gidx++;
        }
     }
 
@@ -1856,7 +1903,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
@@ -1865,7 +1913,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
@@ -1891,7 +1951,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
@@ -2042,7 +2103,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;
@@ -2053,7 +2114,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)
@@ -2066,12 +2127,3 @@ OTF_iterate_gsub_feature (OTF *otf, OTF_Feature_Callback callback,
        return -1;
   return 0;
 }
-
-OTF_Tag *
-OTF_get_drive_log (OTF *otf)
-{
-  OTF_DriveLog *log = get_drive_log (otf);
-
-  return (log ? log->tags : NULL);
-}
-