(Mgenerator, Mend): New variables.
authorhanda <handa>
Mon, 29 Oct 2007 02:33:25 +0000 (02:33 +0000)
committerhanda <handa>
Mon, 29 Oct 2007 02:33:25 +0000 (02:33 +0000)
(flt_min_coverage, flt_max_coverage): New variables.
(GCPY): New macro.
(GDUP): Use it.
(Mfont_has): Renamed from Mexist.  Referrers chagned.
(gen_otf_tag): Handle the trailing whitespaces.
(otf_count_features, otf_store_features): Fix for negative features.
(parse_otf_command): Adjusted for the change of MFLTOtfSpec.
(load_otf_command): Likewise.
(free_flt_command): Adjusted for the change of MFLTOtfSpec.
(load_flt): Argument changed.  Caller changed.
(free_flt_list): New function.
(run_rule): Adjusted for the change of FontLayoutContext.
(mflt_run): Adjusted for the change of FontLayoutContext.

src/m17n-flt.c

index 80795ea..dcc610f 100644 (file)
@@ -242,7 +242,10 @@ static int mdebug_flag = MDEBUG_FONT_FLT;
 
 MSymbol Mfont, Mlayouter;
 
+static MSymbol Mgenerator, Mend;
+
 static MPlist *flt_list;
+static int flt_min_coverage, flt_max_coverage;
 
 enum GlyphInfoMask
 {
@@ -269,16 +272,13 @@ enum GlyphInfoMask
 #define GET_MEASURED(g) ((g)->measured)
 #define SET_MEASURED(g, flag) ((g)->measured = (flag))
 
-#define GINIT(gstring, n)                                              \
-  do {                                                                 \
-    if (! (gstring)->glyph_size)                                       \
-      (gstring)->glyph_size = sizeof (MFLTGlyph);                      \
-    if ((n) > 0)                                                       \
-      {                                                                        \
-       (gstring)->glyphs = alloca ((gstring)->glyph_size * (n));       \
-       (gstring)->allocated = (n);                                     \
-       (gstring)->used = 0;                                            \
-      }                                                                        \
+#define GINIT(gstring, n)                                      \
+  do {                                                         \
+    if (! (gstring)->glyph_size)                               \
+      (gstring)->glyph_size = sizeof (MFLTGlyph);              \
+    (gstring)->glyphs = alloca ((gstring)->glyph_size * (n));  \
+    (gstring)->allocated = (n);                                        \
+    (gstring)->used = 0;                                       \
   } while (0)
 
 #define GALLOCA (gstring)      \
@@ -287,16 +287,21 @@ enum GlyphInfoMask
 #define GREF(gstring, idx)     \
   ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
 
-#define GDUP(ctx, idx)                                                 \
+#define GCPY(src, src_idx, n, tgt, tgt_idx)                            \
   do {                                                                 \
-    MFLTGlyphString *src = ctx->in;                                    \
-    MFLTGlyphString *tgt = ctx->out;                                   \
-    if ((tgt)->allocated <= (tgt)->used)                               \
-      return -2;                                                       \
-    memcpy ((char *) (tgt->glyphs) + tgt->glyph_size * tgt->used,      \
-           (char *) (src->glyphs) + src->glyph_size * (idx),           \
-           (src)->glyph_size);                                         \
-    tgt->used++;                                                       \
+    memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx),  \
+           (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx),   \
+           (src)->glyph_size * (n));                                   \
+  } while (0)
+
+#define GDUP(ctx, idx)                         \
+  do {                                         \
+    MFLTGlyphString *src = (ctx)->in;          \
+    MFLTGlyphString *tgt = (ctx)->out;         \
+    if (tgt->allocated <= tgt->used)           \
+      return -2;                               \
+    GCPY (src, (idx), 1, tgt, tgt->used);      \
+    tgt->used++;                               \
   } while (0)
 
 static int
@@ -350,7 +355,7 @@ GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
 
-static MSymbol Mcond, Mrange, Mexist;
+static MSymbol Mcond, Mrange, Mfont_has;
 
 #define GLYPH_CODE_P(code)     \
   ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
@@ -442,6 +447,7 @@ struct _MFLT
 {
   MSymbol name;
   MSymbol family;
+  MSymbol registry;
   MFLTOtfSpec otf;
   MDatabase *mdb;
   MCharTable *coverage;
@@ -452,70 +458,6 @@ struct _MFLT
 
 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
 
-static int
-list_flt ()
-{
-  MPlist *plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil);
-  MPlist *pl;
-
-  flt_list = mplist ();
-  MPLIST_DO (pl, plist)
-    {
-      MDatabase *mdb = MPLIST_VAL (pl);
-      MSymbol *tags = mdatabase_tag (mdb);
-      MPlist *properties = mdatabase__props (mdb), *p;
-      MFLT *flt;
-
-      if (! MSTRUCT_CALLOC_SAFE (flt))
-       goto memfull;
-      flt->name = tags[2];
-      flt->mdb = mdb;
-      mplist_push (flt_list, flt->name, flt);
-      if (properties)
-       MPLIST_DO (properties, properties)
-         {
-           MSymbol sym = Mnil;
-           char *otf_spec;
-
-           if (! MPLIST_PLIST_P (properties))
-             continue;
-           p = MPLIST_PLIST (properties);
-           if (! MPLIST_SYMBOL_P (p))
-             continue;
-           if (MPLIST_SYMBOL (p) != Mfont)
-             continue;
-           p = MPLIST_NEXT (p);
-           if (! MPLIST_PLIST_P (p))
-             continue;
-           p = MPLIST_PLIST (p);
-           if (! MPLIST_SYMBOL_P (p))
-             continue;
-           p = MPLIST_NEXT (p);
-           if (! MPLIST_SYMBOL_P (p))
-             continue;
-           flt->family = MPLIST_SYMBOL (p);
-           MPLIST_DO (p, MPLIST_NEXT (p))
-             if (MPLIST_SYMBOL_P (p))
-               sym = MPLIST_SYMBOL (p);
-           if (sym
-               && (otf_spec = MSYMBOL_NAME (sym))
-               && otf_spec[0] == ':' && otf_spec[1] == 'o'
-               && otf_spec[2] == 't' && otf_spec[3] == 'f')
-             {
-               if (parse_otf_command (sym, &flt->otf) == -2)
-                 goto memfull;
-             }
-         }
-    }
-  M17N_OBJECT_UNREF (plist);
-  return 0;
-
- memfull:
-  M17N_OBJECT_UNREF (plist);  
-  M17N_OBJECT_UNREF (flt_list);
-  MERROR (MERROR_MEMORY, -1);
-}
-
 /* Load a category table from PLIST.  PLIST has this form:
       PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
 */
@@ -574,12 +516,16 @@ gen_otf_tag (char *p)
 
   for (i = 0; i < 4 && *p; i++, p++)
     tag = (tag << 8) | *p;
-  return (i < 4 ? 0 : tag);
+  for (; i < 4; i++)
+    tag = (tag << 8) | 0x20;
+  return tag;
 }
 
 static char *
 otf_count_features (char *p, char *end, char stopper, int *count)
 {
+  int negative = 0;
+
   *count = 0;
   if (*p != stopper && *p != '\0')
     while (1)
@@ -593,7 +539,11 @@ otf_count_features (char *p, char *end, char stopper, int *count)
            return NULL;
          }
        if (*p == '~')
-         p += 5;
+         {
+           if (negative++ == 0)
+             (*count)++;
+           p += 5;
+         }
        else 
          p += 4;
        if (p > end)
@@ -610,19 +560,25 @@ otf_count_features (char *p, char *end, char stopper, int *count)
 }
 
 static void
-otf_store_features (char *p, char *end, int count, unsigned *buf)
+otf_store_features (char *p, char *end, unsigned *buf)
 {
+  int negative = 0;
   int i;
 
   for (i = 0; p < end;)
     {
       if (*p == '*')
-       buf[i++] = 0, p += 2;
+       buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
       else if (*p == '~')
-       buf[--count] = gen_otf_tag (p + 1), p += 6;
+       {
+         if (negative++ == 0)
+           buf[i++] = 0xFFFFFFFF;
+         buf[i++] = gen_otf_tag (p + 1), p += 6;
+       }
       else
        buf[i++] = gen_otf_tag (p), p += 5;
     }
+  buf[i] = 0;
 }
 
 static int
@@ -631,81 +587,71 @@ parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
   char *str = MSYMBOL_NAME (symbol);
   char *end = str + MSYMBOL_NAMELEN (symbol);
   unsigned int script, langsys;
-  unsigned int *gsub, *gpos;
+  char *gsub, *gpos;
   int gsub_count = 0, gpos_count = 0;
   char *p;
 
+  memset (spec, 0, sizeof (MFLTOtfSpec));
+
   spec->sym = symbol;
   str += 5;                    /* skip the heading ":otf=" */
   script = gen_otf_tag (str);
-  if (! script)
-    return 0;
   str += 4;
   if (*str == '/')
     {
       langsys = gen_otf_tag (str);
-      if (! langsys)
-       MERROR (MERROR_FLT, -1);
       str += 4;
     }
   else
     langsys = 0;
+  gsub = str;
   if (*str != '=')
-    {
-      /* Apply all GSUB features.  */
+    /* Apply all GSUB features.  */
       gsub_count = 1;
-      gsub = alloca (sizeof *gsub);
-      *gsub = 0;
-    }
   else
     {
       p = str + 1;
       str = otf_count_features (p, end, '+', &gsub_count);
       if (! str)
        MERROR (MERROR_FLT, -1);
-      if (gsub_count > 0)
-       {
-         gsub = alloca (sizeof (unsigned int) * gsub_count);
-         otf_store_features (p, str, gsub_count, gsub);
-       }
     }
+  gpos = str;
   if (*str != '+')
-    {
-      /* Apply all GPOS features.  */
-      gpos_count = 1;
-      gpos = alloca (sizeof *gpos);
-      *gpos = 0;
-    }
+    /* Apply all GPOS features.  */
+    gpos_count = 1;
   else
     {
       p = str + 1;
       str = otf_count_features (p, end, '\0', &gpos_count);
       if (! str)
        MERROR (MERROR_FLT, -1);
-      if (gpos_count > 0)
-       {
-         gpos = alloca (sizeof (unsigned int) * gpos_count);
-         otf_store_features (p, str, gpos_count, gpos);
-       }
     }
 
   spec->script = script;
   spec->langsys = langsys;
-  spec->gsub_gpos[0].count = gsub_count;
   if (gsub_count > 0)
     {
-      spec->gsub_gpos[0].tags = malloc (sizeof (int) * gsub_count);
-      if (! spec->gsub_gpos[0].tags)
-       MERROR (MERROR_FLT, -2);
-      memcpy (spec->gsub_gpos[0].tags, gsub, sizeof (int) * gsub_count);
+      spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
+      if (! spec->features[0])
+       return -2;
+      if (*gsub == '=')
+       otf_store_features (gsub + 1, gpos, spec->features[0]);
+      else
+       spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
     }
-  spec->gsub_gpos[1].count = gpos_count;
   if (gpos_count > 0)
     {
-      spec->gsub_gpos[1].tags = malloc (sizeof (int) * gpos_count);
-      if (! spec->gsub_gpos[1].tags)
-       MERROR (MERROR_FLT, -2);
-      memcpy (spec->gsub_gpos[1].tags, gpos, sizeof (int) * gpos_count);
+      spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
+      if (! spec->features[1])
+       {
+         if (spec->features[0])
+           free (spec->features[0]);
+         return -2;
+       }
+      if (*gpos == '+')
+       otf_store_features (gpos + 1, str, spec->features[1]);
+      else
+       spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
     }
   return 0;
 }
@@ -736,8 +682,6 @@ load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
   result = parse_otf_command (sym, &cmd->body.otf);
   if (result == -2)
     return result;
-  if (result < 0)
-    cmd->body.otf.gsub_gpos[0].count = cmd->body.otf.gsub_gpos[1].count = 0;
   cmd->type = FontLayoutCmdTypeOTF;
   return 0;
 }
@@ -1005,7 +949,7 @@ load_command (FontLayoutStage *stage, MPlist *plist,
                }
              else if (MPLIST_SYMBOL_P (pl) && size <= 2)
                {
-                 if (MPLIST_SYMBOL (pl) != Mexist)
+                 if (MPLIST_SYMBOL (pl) != Mfont_has)
                    MERROR (MERROR_FLT, INVALID_CMD_ID);
                  cmd->body.rule.src_type = SRC_EXIST;
                  if (size == 1)
@@ -1133,10 +1077,10 @@ free_flt_command (FontLayoutCmd *cmd)
     free (cmd->body.cond.cmd_ids);
   else if (cmd->type == FontLayoutCmdTypeOTF)
     {
-      if (cmd->body.otf.gsub_gpos[0].count > 0)
-       free (cmd->body.otf.gsub_gpos[0].tags);
-      if (cmd->body.otf.gsub_gpos[1].count > 0)
-       free (cmd->body.otf.gsub_gpos[1].tags);
+      if (cmd->body.otf.features[0])
+       free (cmd->body.otf.features[0]);
+      if (cmd->body.otf.features[1])
+       free (cmd->body.otf.features[1]);
     }
 }
 
@@ -1186,42 +1130,68 @@ load_generator (MPlist *plist)
 /* Load stages of the font layout table FLT.  */
 
 static int
-load_flt (MFLT *flt, int full)
+load_flt (MFLT *flt, MPlist *key_list)
 {
-  static MSymbol Mcategory, Mgenerator, Mend;
-  MPlist *top, *plist;
+  MPlist *top, *plist, *pl, *p;
   MCharTable *category = NULL;
+  MSymbol sym;
 
-  if (! Mcategory)
-    {
-      Mcategory = msymbol ("category");
-      Mgenerator = msymbol ("generator");
-      Mend = msymbol ("end");
-    }
-
-  if (full)
-    {
-      top = (MPlist *) mdatabase_load (flt->mdb);
-    }
+  if (key_list)
+    top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
   else
+    top = (MPlist *) mdatabase_load (flt->mdb);
+  if (! top)
+    return -1;
+  if (! MPLIST_PLIST_P (top))
     {
-      plist = mplist ();
-      mplist_add (plist, Mcategory, Mt);
-      top = (MPlist *) mdatabase__load_for_keys (flt->mdb, plist);
-      M17N_OBJECT_UNREF (plist);
-    }
-  if (! top || ! MPLIST_PLIST_P (top))
-    {
-      if (top)
-       M17N_OBJECT_UNREF (top);
+      M17N_OBJECT_UNREF (top);
       MERROR (MERROR_FLT, -1);
     }
 
-  MPLIST_DO (plist, top)
+  if (key_list)
     {
-      MSymbol sym;
-      MPlist *elt;
+      plist = mdatabase__props (flt->mdb);
+      if (! plist)
+       MERROR (MERROR_FLT, -1);
+      MPLIST_DO (plist, plist)
+       if (MPLIST_PLIST_P (plist))
+         {
+           pl = MPLIST_PLIST (plist);
+           if (! MPLIST_SYMBOL_P (pl)
+               || MPLIST_SYMBOL (pl) != Mfont)
+             continue;
+           pl = MPLIST_NEXT (pl);
+           if (! MPLIST_PLIST_P (pl))
+             continue;
+           p = MPLIST_PLIST (pl);
+           if (! MPLIST_SYMBOL_P (p))
+             continue;
+           p = MPLIST_NEXT (p);
+           if (! MPLIST_SYMBOL_P (p))
+             continue;
+           flt->family = MPLIST_SYMBOL (p);
+           MPLIST_DO (p, MPLIST_NEXT (p))
+             if (MPLIST_SYMBOL_P (p))
+               {
+                 sym = MPLIST_SYMBOL (p);
+                 if (MSYMBOL_NAME (sym)[0] != ':')
+                   flt->registry = sym, sym = Mnil;
+                 else
+                   break;
+               }
+           if (sym)
+             {
+               char *otf_spec = MSYMBOL_NAME (sym);
 
+               if (otf_spec[0] == ':' && otf_spec[1] == 'o'
+                   && otf_spec[2] == 't' && otf_spec[3] == 'f')
+                 parse_otf_command (sym, &flt->otf);
+             }
+           break;
+         }
+    }
+  MPLIST_DO (plist, top)
+    {
       if (MPLIST_SYMBOL_P (plist)
          && MPLIST_SYMBOL (plist) == Mend)
        {
@@ -1229,19 +1199,24 @@ load_flt (MFLT *flt, int full)
          break;
        }
       if (! MPLIST_PLIST (plist))
-       break;
-      elt = MPLIST_PLIST (plist);
-      if (! MPLIST_SYMBOL_P (elt))
-       break;
-      sym = MPLIST_SYMBOL (elt);
-      elt = MPLIST_NEXT (elt);
-      if (! elt)
-       break;
+       continue;
+      pl = MPLIST_PLIST (plist);
+      if (! MPLIST_SYMBOL_P (pl))
+       continue;
+      sym = MPLIST_SYMBOL (pl);
+      pl = MPLIST_NEXT (pl);
+      if (! pl)
+       continue;
       if (sym == Mcategory)
        {
          if (category)
            M17N_OBJECT_UNREF (category);
-         category = load_category_table (elt);
+         else if (flt->coverage)
+           {
+             category = flt->coverage;
+             continue;
+           }
+         category = load_category_table (pl);
          if (! flt->coverage)
            {
              flt->coverage = category;
@@ -1254,7 +1229,7 @@ load_flt (MFLT *flt, int full)
 
          if (! category)
            break;
-         stage = load_generator (elt);
+         stage = load_generator (pl);
          if (! stage)
            break;
          stage->category = category;
@@ -1288,6 +1263,91 @@ free_flt_stage (FontLayoutStage *stage)
   free (stage);
 }
 
+static void
+free_flt_list ()
+{
+  if (flt_list)
+    {
+      MPlist *plist, *pl;
+
+      MPLIST_DO (plist, flt_list)
+       {
+         MFLT *flt = MPLIST_VAL (plist);
+
+         if (flt->coverage)
+           M17N_OBJECT_UNREF (flt->coverage);
+         if (flt->stages)
+           {
+             MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
+               free_flt_stage (MPLIST_VAL (pl));
+             M17N_OBJECT_UNREF (flt->stages);
+           }
+       }
+      M17N_OBJECT_UNREF (flt_list);
+    }
+}
+
+static int
+list_flt ()
+{
+  MPlist *plist, *key_list = NULL;
+  MPlist *pl;
+  int result = 0;
+
+  if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
+    return -1;
+  if (! (flt_list = mplist ()))
+    goto err;
+  if (! (key_list = mplist ()))
+    goto err;
+  if (! mplist_add (key_list, Mcategory, Mt))
+    goto err;
+
+  MPLIST_DO (pl, plist)
+    {
+      MDatabase *mdb = MPLIST_VAL (pl);
+      MSymbol *tags = mdatabase_tag (mdb);
+      MFLT *flt;
+
+      if (! MSTRUCT_CALLOC_SAFE (flt))
+       goto err;
+      flt->name = tags[2];
+      flt->mdb = mdb;
+      if (load_flt (flt, key_list) < 0)
+       free (flt);
+      else
+       {
+         if (MPLIST_TAIL_P (flt_list))
+           {
+             flt_min_coverage = mchartable_min_char (flt->coverage);
+             flt_max_coverage = mchartable_max_char (flt->coverage);
+           }
+         else
+           {
+             int c;
+
+             c = mchartable_min_char (flt->coverage);
+             if (flt_min_coverage > c)
+               flt_min_coverage = c;
+             c = mchartable_max_char (flt->coverage);
+             if (flt_max_coverage < c)
+               flt_max_coverage = c;
+           }
+         if (! mplist_push (flt_list, flt->name, flt))
+           goto err;
+       }
+    }
+  goto end;
+
+ err:
+  free_flt_list ();
+  result = -1;
+ end:
+  M17N_OBJECT_UNREF (plist);  
+  M17N_OBJECT_UNREF (key_list);
+  return result;
+}
+
 /* FLS (Font Layout Service) */
 
 /* Structure to hold information about a context of FLS.  */
@@ -1307,11 +1367,7 @@ typedef struct
      table into this array.  An element is a category letter used for
      a regular expression matching.  */
   char *encoded;
-  /* <encoded>[GIDX - <encoded_offset>] gives a category for the glyph
-     index GIDX.  */
-  int encoded_offset;
   int *match_indices;
-  int gstring_size;
   int code_offset;
   int cluster_begin_idx;
   int cluster_begin_pos;
@@ -1375,19 +1431,18 @@ run_rule (int depth,
 
       if (from > to)
        return 0;
-      saved_code = ctx->encoded[to - ctx->encoded_offset];
-      ctx->encoded[to - ctx->encoded_offset] = '\0';
+      saved_code = ctx->encoded[to];
+      ctx->encoded[to] = '\0';
       result = regexec (&(rule->src.re.preg),
-                       ctx->encoded + from - ctx->encoded_offset,
-                       NMATCH, pmatch, 0);
+                       ctx->encoded + from, NMATCH, pmatch, 0);
       if (result == 0 && pmatch[0].rm_so == 0)
        {
          if (MDEBUG_FLAG () > 2)
            MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
                           rule->src.re.pattern,
-                          ctx->encoded + from - ctx->encoded_offset,
+                          ctx->encoded + from,
                           pmatch[0].rm_eo);
-         ctx->encoded[to - ctx->encoded_offset] = saved_code;
+         ctx->encoded[to] = saved_code;
          for (i = 0; i < NMATCH; i++)
            {
              if (pmatch[i].rm_so < 0)
@@ -1403,7 +1458,7 @@ run_rule (int depth,
        }
       else
        {
-         ctx->encoded[to - ctx->encoded_offset] = saved_code;
+         ctx->encoded[to] = saved_code;
          return 0;
        }
     }
@@ -1511,67 +1566,80 @@ run_otf (int depth,
 {
   MFLTFont *font = ctx->font;
   int from_idx = ctx->out->used;
-  MFLTGlyphAdjustment *adjustment;
-  int out_len;
-  int i;
 
   if (MDEBUG_FLAG () > 2)
     MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
 
   font->get_glyph_id (font, ctx->in, from, to);
-  adjustment = alloca ((sizeof *adjustment)
-                      * (ctx->out->allocated - ctx->out->used));
-  if (! adjustment)
-    MERROR (MERROR_FLT, -1);
-  memset (adjustment, 0,
-         (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
-  to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out, adjustment);
-  if (to < 0)
-    return to;
-  out_len = ctx->out->used - from_idx;
-  if (otf_spec->gsub_gpos[1].count > 0)
+  if (! font->drive_otf)
     {
-      MFLTGlyphAdjustment *a;
+      if (ctx->out->used + (to - from) > ctx->out->allocated)
+       return -2;
+      font->get_metrics (font, ctx->in, from, to);
+      GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
+      ctx->out->used += to - from;
+    }
+  else
+    {
+      MFLTGlyphAdjustment *adjustment;
+      int out_len;
+      int i;
 
-      for (i = 0, a = adjustment; i < out_len; i++, a++)
-       if (a->set)
-         break;
-      if (i < out_len)
+      adjustment = alloca ((sizeof *adjustment)
+                          * (ctx->out->allocated - ctx->out->used));
+      if (! adjustment)
+       MERROR (MERROR_FLT, -1);
+      memset (adjustment, 0,
+             (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
+      to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
+                           adjustment);
+      if (to < 0)
+       return to;
+      out_len = ctx->out->used - from_idx;
+      if (otf_spec->features[1])
        {
-         font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
+         MFLTGlyphAdjustment *a;
+
          for (i = 0, a = adjustment; i < out_len; i++, a++)
+           if (a->set)
+             break;
+         if (i < out_len)
            {
-             MFLTGlyph *g = GREF (ctx->out, from_idx + i);
-
-             SET_MEASURED (g, 1);
-             if (a->xadv || a->yadv)
+             font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
+             for (i = 0, a = adjustment; i < out_len; i++, a++)
                {
-                 if (a->advance_is_absolute)
+                 MFLTGlyph *g = GREF (ctx->out, from_idx + i);
+
+                 SET_MEASURED (g, 1);
+                 if (a->xadv || a->yadv)
                    {
-                     g->xadv = a->xadv;
-                     g->yadv = a->yadv;
+                     if (a->advance_is_absolute)
+                       {
+                         g->xadv = a->xadv;
+                         g->yadv = a->yadv;
+                       }
+                     else
+                       {
+                         g->xadv += a->xadv;
+                         g->yadv += a->yadv;
+                       }
                    }
-                 else
+                 if (a->xoff || a->yoff)
                    {
-                     g->xadv += a->xadv;
-                     g->yadv += a->yadv;
-                   }
-               }
-             if (a->xoff || a->yoff)
-               {
-                 int j;
-                 MFLTGlyph *gg = g;
-                 MFLTGlyphAdjustment *aa = a;
+                     int j;
+                     MFLTGlyph *gg = g;
+                     MFLTGlyphAdjustment *aa = a;
 
-                 g->xoff = a->xoff;
-                 g->yoff = a->yoff;
-                 while (aa->back > 0)
-                   {
-                     for (j = 0, gg--; j < aa->back; j++, gg--)
-                       g->xoff -= gg->xadv;
-                     aa = aa - aa->back;
-                     g->xoff += aa->xoff;
-                     g->yoff += aa->yoff;
+                     g->xoff = a->xoff;
+                     g->yoff = a->yoff;
+                     while (aa->back > 0)
+                       {
+                         for (j = 0, gg--; j < aa->back; j++, gg--)
+                           g->xoff -= gg->xadv;
+                         aa = aa - aa->back;
+                         g->xoff += aa->xoff;
+                         g->yoff += aa->yoff;
+                       }
                    }
                }
            }
@@ -1807,13 +1875,6 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
       ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
       table = ctx->stage->category;
       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
-      if (ctx->encoded_offset < from)
-       {
-         for (i = ctx->encoded_offset; i < from; i++)
-           ctx->encoded[i]
-             = (int) mchartable_lookup (table, GREF (ctx->in, i)->c);
-         ctx->encoded[i++] = ' ';
-       }
       for (i = from; i < to; i++)
        {
          MFLTGlyph *g = GREF (ctx->in, i);
@@ -1823,14 +1884,14 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
                      ? (int) mchartable_lookup (table, g->code)
                      : ' ');
 
-         ctx->encoded[i - ctx->encoded_offset] = enc;
+         ctx->encoded[i] = enc;
          if (! enc && stage_idx == 0)
            {
              to = i;
              break;
            }
        }
-      ctx->encoded[i - ctx->encoded_offset] = '\0';
+      ctx->encoded[i] = '\0';
       ctx->match_indices[0] = from;
       ctx->match_indices[1] = to;
       for (i = 2; i < NMATCH; i++)
@@ -1839,7 +1900,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
       if (MDEBUG_FLAG () > 2)
        {
          MDEBUG_PRINT2 ("\n [FLT]   (STAGE %d \"%s\"", stage_idx,
-                        ctx->encoded);
+                        ctx->encoded + from);
          MDEBUG_PRINT (" (");
          for (i = from; i < to; i++)
            {
@@ -1874,7 +1935,6 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
        }
       ctx->out->used = 0;
 
-      ctx->encoded_offset = 0;
       from = 0;
       to = ctx->in->used;
     }
@@ -1882,7 +1942,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
   if (ctx->out->used > 0)
     {
       int *g_indices;
-      int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
+      int x_ppem = ctx->font->x_ppem, y_ppem = ctx->font->y_ppem;
 
       /* Remove separator glyphs.  */
       for (i = 0; i < ctx->out->used;)
@@ -2030,25 +2090,63 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
   return to;
 }
 
-#define CHECK_FLT_COVERAGE(flt) ((flt)->coverage || load_flt (flt, 0) == 0)
-#define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, 1) == 0)
+static int
+combining_code_from_class (int class)
+{
+  int code;
+
+  if (class < 200)
+    code = MAKE_COMBINING_CODE (3, 1, 3, 1, 128, 128);
+  else if (class == 200)       /* below left attached */
+    code = MAKE_COMBINING_CODE (2, 0, 0, 1, 128, 128);
+  else if (class == 202)       /* below attached*/
+    code = MAKE_COMBINING_CODE (2, 1, 0, 1, 128, 128);
+  else if (class == 204)       /* below right attached */
+    code = MAKE_COMBINING_CODE (2, 2, 0, 1, 128, 128);
+  else if (class == 208)       /* left attached */
+    code = MAKE_COMBINING_CODE (3, 0, 3, 2, 128, 128);
+  else if (class == 210)       /* right attached */
+    code = MAKE_COMBINING_CODE (3, 2, 3, 0, 128, 128);
+  else if (class == 212)       /* above left attached */
+    code = MAKE_COMBINING_CODE (0, 0, 2, 1, 128, 128);
+  else if (class == 214)       /* above attached */
+    code = MAKE_COMBINING_CODE (0, 1, 2, 1, 128, 128);
+  else if (class == 216)       /* above right attached */
+    code = MAKE_COMBINING_CODE (0, 2, 2, 1, 128, 128);
+  else if (class == 218)       /* below left */
+    code = MAKE_COMBINING_CODE (2, 0, 0, 1, 122, 128);
+  else if (class == 220)       /* below */
+    code = MAKE_COMBINING_CODE (2, 1, 0, 1, 122, 128);
+  else if (class == 222)       /* below right */
+    code = MAKE_COMBINING_CODE (2, 2, 0, 1, 122, 128);
+  else if (class == 224)       /* left */
+    code = MAKE_COMBINING_CODE (3, 0, 3, 2, 128, 122);
+  else if (class == 226)       /* right */
+    code = MAKE_COMBINING_CODE (3, 2, 3, 0, 128, 133);
+  else if (class == 228)       /* above left */
+    code = MAKE_COMBINING_CODE (0, 0, 2, 1, 133, 128);
+  else if (class == 230)       /* above */
+    code = MAKE_COMBINING_CODE (0, 1, 2, 1, 133, 128);
+  else if (class == 232)       /* above right */
+    code = MAKE_COMBINING_CODE (0, 2, 2, 1, 133, 128);
+  else if (class == 233)       /* double below */
+    code = MAKE_COMBINING_CODE (2, 2, 0, 2, 122, 128);
+  else if (class == 234)       /* double above */
+    code = MAKE_COMBINING_CODE (0, 2, 2, 2, 133, 128);
+  else if (class == 240)       /* iota subscript */
+    code = MAKE_COMBINING_CODE (2, 1, 0, 1, 122, 128);
+  else                         /* unknown */
+    code = MAKE_COMBINING_CODE (3, 1, 3, 1, 128, 128);
+  return code;
+}
+
+#define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
 
 \f
 /* Internal API */
 
 int m17n__flt_initialized;
 
-unsigned
-mfont__flt_encode_char (MFLT *flt, int c)
-{
-  unsigned code;
-
-  if (! CHECK_FLT_STAGES (flt))
-    return MCHAR_INVALID_CODE;
-  code = (unsigned) mchartable_lookup (flt->coverage, c);
-  return (code ? code : MCHAR_INVALID_CODE);
-}
-
 \f
 /* External API */
 
@@ -2071,15 +2169,15 @@ m17n_init_flt (void)
     }
 
   MDEBUG_PUSH_TIME ();
-  MDEBUG_PUSH_TIME ();
 
   Mcond = msymbol ("cond");
   Mrange = msymbol ("range");
   Mfont = msymbol ("font");
   Mlayouter = msymbol ("layouter");
-  Mexist = msymbol ("exist");
+  Mfont_has = msymbol ("font-has");
+  Mgenerator = msymbol ("generator");
+  Mend = msymbol ("end");
 
-  MDEBUG_POP_TIME ();
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
   MDEBUG_POP_TIME ();
 }
@@ -2088,35 +2186,13 @@ void
 m17n_fini_flt (void)
 {
   int mdebug_flag = MDEBUG_FINI;
-  MPlist *plist, *pl;
 
   if (m17n__flt_initialized == 0
       || --m17n__flt_initialized > 0)
     return;
 
   MDEBUG_PUSH_TIME ();
-  MDEBUG_PUSH_TIME ();
-  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize database module."));
-
-  if (flt_list)
-    {
-      MPLIST_DO (plist, flt_list)
-       {
-         MFLT *flt = MPLIST_VAL (plist);
-
-         if (flt->coverage)
-           M17N_OBJECT_UNREF (flt->coverage);
-         if (flt->stages)
-           {
-             MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
-               free_flt_stage (MPLIST_VAL (pl));
-             M17N_OBJECT_UNREF (flt->stages);
-           }
-       }
-      M17N_OBJECT_UNREF (flt_list);
-    }
-
-  MDEBUG_POP_TIME ();
+  free_flt_list ();
   MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
   MDEBUG_POP_TIME ();
   m17n_fini_core ();
@@ -2125,106 +2201,170 @@ m17n_fini_flt (void)
 /*** @} */ 
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
+/*** @addtogroup m17nFLT */
+/*** @{ */
+/*=*/
+
+/*=*/
+/***en
+    @brief Return a FLT object whose name is NAME.
+
+    The mflt_get () function returns a FLT object whose name is $NAME.
+
+    @return
+    If the operation was successfully, mflt_get () returns a pointer
+    to a FLT object.  Otherwise, it returns @c NULL.  */
+
 MFLT *
-mflt_get (char *name)
+mflt_get (MSymbol name)
 {
-  MSymbol sym = msymbol (name);
   MFLT *flt;
 
-  if (! flt_list
-      && list_flt () < 0)
+  if (! flt_list && list_flt () < 0)
     return NULL;
-  flt = mplist_get (flt_list, sym);
+  flt = mplist_get (flt_list, name);
   if (flt && ! CHECK_FLT_STAGES (flt))
     return NULL;
   return flt;
 }
 
+/*=*/
+/***en
+    @brief Find a FLT suitable for a specified character and font.
+
+    The mflt_find () function returns the most appropriate FLT for
+    rendering the character $C by font $FONT.
+
+    @return
+    If the operation was successfully, mflt_find () returns a pointer
+    to a FLT object.  Otherwise, it returns @c NULL.  */
+
 MFLT *
 mflt_find (int c, MFLTFont *font)
 {
   MPlist *plist;
   MFLT *flt;
+  static MSymbol unicode_bmp = NULL, unicode_full = NULL;
+
+  if (! unicode_bmp)
+    {
+      unicode_bmp = msymbol ("unicode-bmp");
+      unicode_full = msymbol ("unicode-full");
+    }
 
   if (! flt_list && list_flt () < 0)
     return NULL;
   if (font)
     {
+      MFLT *best = NULL;
+
       MPLIST_DO (plist, flt_list)
        {
          flt = MPLIST_VAL (plist);
-         if (flt->family && flt->family != font->family)
+         if (flt->registry != unicode_bmp
+             && flt->registry != unicode_full)
            continue;
-         if (flt->otf.sym
-             && (! font->check_otf (font, &flt->otf)))
+         if (flt->family && flt->family != font->family)
            continue;
          if (c >= 0
-             && (! CHECK_FLT_COVERAGE (flt)
-                 || ! mchartable_lookup (flt->coverage, c)))
+             && ! mchartable_lookup (flt->coverage, c))
            continue;
-         return flt;
+         if (flt->otf.sym)
+           {
+             MFLTOtfSpec *spec = &flt->otf;
+
+             if (! font->check_otf)
+               {
+                 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
+                     || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
+                   continue;
+               }
+             else if (! font->check_otf (font, &flt->otf))
+               continue;
+             return flt;
+           }
+         best = flt;
        }
-      return NULL;
+      return best;
     }
   if (c >= 0)
     {
       MPLIST_DO (plist, flt_list)
        {
          flt = MPLIST_VAL (plist);
-         if (CHECK_FLT_COVERAGE (flt)
-             && mchartable_lookup (flt->coverage, c))
+         if (mchartable_lookup (flt->coverage, c))
            return flt;
        }
     }
   return NULL;
 }
 
-char *
+/*=*/
+/***en
+    @brief Return a name of a FLT.
+
+    The mflt_name () function returns the name of $FLT.  */
+
+const char *
 mflt_name (MFLT *flt)
 {
   return MSYMBOL_NAME (flt->name);
 }
 
+/*=*/
+/***en
+    @brief Return a coverage of a FLT.
+
+    The mflt_coverage () function returns a char-table that contains
+    nonzero value for characters supported by $FLT.  */
+
 MCharTable *
 mflt_coverage (MFLT *flt)
 {
-  if (! CHECK_FLT_COVERAGE (flt))
-    MERROR (MERROR_FLT, NULL);
   return flt->coverage;
 }
 
+/*=*/
+/***en
+    @brief Layout characters by Font Layout Table.
+
+    The mflt_run () function layout characters in $GSTRING between
+    $FROM (inclusive) and $TO (exclusive) by $FONT.  If $FLT is
+    nonzero, it is used for all the charaters.  Otherwise, appropriate
+    FLTs are automatically chosen.
+
+    @retval >=0
+    The operation was successful.  The value is an index to the
+    $GSTRING->glyphs which was previously indexed by $TO.
+
+    @retval -2
+    $GSTRING->glyphs is too short to store the result.  A caller can
+    call this fucntion again with the larger $GSTRING->glyphs.
+
+    @retval -1
+    Some other error occurred.  */
+
 int
 mflt_run (MFLTGlyphString *gstring, int from, int to,
          MFLTFont *font, MFLT *flt)
 {
-  int i, j;
   FontLayoutContext ctx;
   int match_indices[NMATCH];
   MFLTGlyph *g;
   MFLTGlyphString out;
+  int auto_flt = ! flt;
+  int c, i, j, k;
+  int this_from, this_to;
 
-  if (! CHECK_FLT_STAGES (flt))
-    {
-      GREPLACE (NULL, 0, 0, gstring, from, to);
-      return from;
-    }
+  out = *gstring;
+  out.glyphs = NULL;
+  /* This is usually sufficient, but if not, we retry with the larger
+     values at most 3 times.  This value is also used for the
+     allocating size of ctx.encoded.  */
+  out.allocated = (to - from) * 4;
 
-  MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
-
-  /* Setup CTX.  */
-  memset (&ctx, 0, sizeof ctx);
-  ctx.cluster_begin_idx = -1;
-  /* Find previous glyphs that are also supported by the layouter.  */
-  for (i = from;
-       i > 0 && (g = GREF (gstring, i - 1))
-        && g->c && mchartable_lookup (flt->coverage, g->c);
-       i--)
-    g->code = g->c;
-  ctx.encoded_offset = i;
   for (i = from; i < to; i++)
     {
-      int c;
-
       g = GREF (gstring, i);
       c = g->c;
       memset (g, 0, sizeof (MFLTGlyph));
@@ -2232,73 +2372,136 @@ mflt_run (MFLTGlyphString *gstring, int from, int to,
       g->from = g->to = i;
     }
 
-  ctx.match_indices = match_indices;
+  for (this_from = from; this_from < to;)
+    {
+      if (! auto_flt)
+       {
+         for (this_to = this_from; this_to < to; i++)
+           if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
+             break;
+       }
+      else
+       {
+         if (! flt_list && list_flt () < 0)
+           {
+             font->get_glyph_id (font, gstring, this_from, to);
+             font->get_metrics (font, gstring, this_from, to);
+             this_from = to;
+             break;
+           }
+         for (this_to = this_from; this_to < to; this_to++)
+           {
+             c = GREF (gstring, this_to)->c;
+             if (c >= flt_min_coverage && c <= flt_max_coverage)
+               break;
+           }
+         for (; this_to < to; this_to++)
+           {
+             c = GREF (gstring, this_to)->c;
+             if (font->internal
+                 && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
+               {
+                 flt = font->internal;
+                 break;
+               }
+             flt = mflt_find (c, font);
+             if (flt)
+               {
+                 if (CHECK_FLT_STAGES (flt))
+                   {
+                     font->internal = flt;
+                     break;
+                   }
+               }
+           }
+       }
+
+      if (this_from < this_to)
+       {
+         font->get_glyph_id (font, gstring, this_from, this_to);
+         font->get_metrics (font, gstring, this_from, this_to);
+         this_from = this_to;
+       }
+      if (this_to == to)
+       break;
 
-  ctx.font = font;
-  ctx.in = gstring;
-  out = *gstring;
-  out.glyphs = NULL;
-  /* This is usually sufficient, but if not, we retry with the larger
-     values at most 3 times.  This value is also used for the
-     allocating size of ctx.encoded.  */
-  out.allocated = (to - ctx.encoded_offset + 2) * 4;
-  ctx.out = &out;
+      MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
 
-  if (MDEBUG_FLAG ())
-    {
-      MDEBUG_PRINT ("\n [FLT]   (SOURCE");
-      for (i = from, j = 0; i < to; i++, j++)
+      for (; this_to < to; this_to++)
+       if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
+         break;
+
+      if (MDEBUG_FLAG ())
        {
-         if (j > 0 && j % 8 == 0)
-           MDEBUG_PRINT ("\n [FLT]          ");
-         MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
+         MDEBUG_PRINT ("\n [FLT]   (SOURCE");
+         for (i = this_from, j = 0; i < this_to; i++, j++)
+           {
+             if (j > 0 && j % 8 == 0)
+               MDEBUG_PRINT ("\n [FLT]          ");
+             MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
+           }
+         MDEBUG_PRINT (")");
        }
-      MDEBUG_PRINT (")");
-    }
 
-  for (i = 0; (i < 3 &&
-              (to = run_stages (gstring, from, to, flt, &ctx)) == -2);
-       i++)
-    {
-      ctx.out = &out;
-      ctx.out->allocated *= 2;
-    }
+      for (i = 0; i < 3; i++)
+       {
+         /* Setup CTX.  */
+         memset (&ctx, 0, sizeof ctx);
+         ctx.match_indices = match_indices;
+         ctx.font = font;
+         ctx.cluster_begin_idx = -1;
+         ctx.in = gstring;
+         ctx.out = &out;
+         j = run_stages (gstring, this_from, this_to, flt, &ctx);
+         if (j != -2)
+           break;
+         out.allocated *= 2;
+       }
 
-#if 0
-  for (i = from; i < to; i++)
-    {
-      MFLTGlyph *g = GREF (gstring, i);
-
-      g->ascent >>= 6;
-      g->descent >>= 6;
-      g->lbearing >>= 6;
-      g->rbearing >>= 6;
-      g->xadv >>= 6;
-      g->yadv >>= 6;
-      g->xoff >>= 6;
-      g->yoff >>= 6;
+      if (j < 0)
+       return j;
+
+      to += j - this_to;
+      this_to = j;
+
+      if (MDEBUG_FLAG ())
+       {
+         MDEBUG_PRINT ("\n [FLT]   (RESULT");
+         if (MDEBUG_FLAG () > 1)
+           for (i = 0; this_from < this_to; this_from++, i++)
+             {
+               if (i > 0 && i % 4 == 0)
+                 MDEBUG_PRINT ("\n [FLT]          ");
+               g = GREF (gstring, this_from);
+               MDEBUG_PRINT4 (" (%04X %d %d %d)",
+                              g->code, g->xadv, g->xoff, g->yoff);
+             }
+         else
+           for (; this_from < this_to; this_from++)
+             MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
+         MDEBUG_PRINT ("))\n");
+       }
+      this_from = this_to;
     }
-#endif
 
-  if (MDEBUG_FLAG ())
+  if (gstring->r2l)
     {
-      MDEBUG_PRINT ("\n [FLT]   (RESULT");
-      if (MDEBUG_FLAG () > 1)
-       for (i = 0; from < to; from++, i++)
-         {
-           if (i > 0 && i % 4 == 0)
-             MDEBUG_PRINT ("\n [FLT]          ");
-           g = GREF (gstring, from);
-           MDEBUG_PRINT4 (" (%04X %d %d %d)",
-                          g->code, g->xadv, g->xoff, g->yoff);
-         }
-      else
-       for (; from < to; from++)
-         MDEBUG_PRINT1 (" %04X", GREF (gstring, from)->code);
-      MDEBUG_PRINT ("))\n");
+      int len = to - from;
+
+      GINIT (&out, len);
+      memcpy (((char *) out.glyphs),
+             ((char *) gstring->glyphs) + gstring->glyph_size * from,
+             gstring->glyph_size * len);
+      for (i = from, j = to; i < to;)
+       {
+         for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
+              k++, j--);
+         GCPY (&out, i, (k - i), gstring, j);
+         i = k;
+       }
     }
 
-  return (to < 0 ? -1 : to);
+  return to;
 }
 
 \f
@@ -2395,3 +2598,11 @@ mdebug_dump_flt (MFLT *flt, int indent)
     }
   fprintf (stderr, ")");
 }
+
+/*** @} */
+
+/*
+ Local Variables:
+ coding: euc-japan
+ End:
+*/