Print debug information to mdebug__output instead of stderr.
[m17n/m17n-lib.git] / src / m17n-flt.c
index 14d8a54..7423026 100644 (file)
@@ -1,5 +1,5 @@
 /* m17n-flt.c -- Font Layout Table sub-module.
-   Copyright (C) 2003, 2004, 2007, 2008, 2009
+   Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -257,9 +257,9 @@ enum GlyphInfoMask
 {
   CategoryCodeMask = 0x7F,
   CombiningCodeMask = 0xFFFFFF,
-  CombinedMask = 1 << 27,
-  LeftPaddingMask = 1 << 28,
-  RightPaddingMask = 1 << 29
+  CombinedMask = 1 << 28,
+  LeftPaddingMask = 1 << 29,
+  RightPaddingMask = 1 << 30
 };
 
 #define SET_GLYPH_INFO(g, mask, ctx, info)                     \
@@ -543,7 +543,14 @@ load_category_table (MPlist *plist, MFLTFont *font)
       elt = MPLIST_PLIST (p);
       if (MPLIST_SYMBOL_P (elt))
        {
-         MPlist *next = MPLIST_NEXT (elt);
+         MPlist *next;
+
+         if (! mflt_enable_new_feature)
+           {
+             M17N_OBJECT_UNREF (table);
+             return NULL;
+           }
+         next = MPLIST_NEXT (elt);
          if (! MPLIST_INTEGER_P (next))
            MERROR_GOTO (MERROR_FLT, end);
          if (! feature_table_head)
@@ -566,6 +573,11 @@ load_category_table (MPlist *plist, MFLTFont *font)
        }
       else if (MPLIST_SYMBOL_P (elt))
        {
+         if (! mflt_enable_new_feature)
+           {
+             M17N_OBJECT_UNREF (table);
+             return NULL;
+           }
          if (font)
            {
              MFLTOtfSpec spec;
@@ -743,7 +755,16 @@ parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
   memset (spec, 0, sizeof (MFLTOtfSpec));
 
   spec->sym = symbol;
-  str += 5;                    /* skip the heading ":otf=" */
+  str += 5;                    /* skip the heading ":otf=" or ":otf?" */
+  if (str[-1] == '?')
+    {
+      if (! mflt_enable_new_feature)
+       /* The client can't use this command.  */
+       return -1;
+      if (! *str)
+       /* This is a spec to reset category codes.  */
+       return 0;
+    }
   script = gen_otf_tag (str, 8);
   str += 4;
   if (*str == '/')
@@ -818,7 +839,7 @@ load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
   char *name = MSYMBOL_NAME (sym);
   int result;
 
-  if (name[0] != ':' && name[0] != '?')
+  if (name[0] != ':')
     {
       /* This is old format of "otf:...".  Change it to ":otf=...".  */
       char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
@@ -831,7 +852,7 @@ load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
   result = parse_otf_command (sym, &cmd->body.otf);
   if (result == -2)
     return result;
-  cmd->type = (name[0] == '?' ? FontLayoutCmdTypeOTFCategory
+  cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
               : FontLayoutCmdTypeOTF);
   return 0;
 }
@@ -1169,9 +1190,8 @@ load_command (FontLayoutStage *stage, MPlist *plist,
       if (len > 4
          && ((name[0] == 'o' && name[1] == 't'
               && name[2] == 'f' && name[3] == ':')
-             || ((name[0] == ':' || name[0] == '?')
-                 && name[1] == 'o' && name[2] == 't'
-                 && name[3] == 'f' && name[4] == '=')))
+             || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
+                 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
        {
          result = load_otf_command (&cmd, sym);
          if (result < 0)
@@ -1395,6 +1415,8 @@ load_flt (MFLT *flt, MPlist *key_list)
              continue;
            }
          category = load_category_table (pl, NULL);
+         if (! category)
+           goto err;
          if (! flt->coverage)
            {
              flt->coverage = category;
@@ -1421,7 +1443,7 @@ load_flt (MFLT *flt, MPlist *key_list)
     }
   if (category)
     unref_category_table (category);
-
+ err:
   if (! MPLIST_TAIL_P (plist))
     {
       M17N_OBJECT_UNREF (top);
@@ -1570,7 +1592,7 @@ typedef struct
 
 static int run_command (int, int, int, int, FontLayoutContext *);
 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
-static int run_otf_category (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
+static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
 
 #define NMATCH 20
 
@@ -1704,12 +1726,12 @@ run_rule (int depth,
            {
              if (MPLIST_INTEGER_P (p))
                {
-                 GREF (&gstring, i)->code = MPLIST_INTEGER (p);
+                 GREF (&gstring, i)->c = MPLIST_INTEGER (p);
                  GREF (&gstring, i)->encoded = 0;
                }
              else
                {
-                 GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
+                 GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
                  GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
                  idx++;
                }
@@ -1844,8 +1866,8 @@ run_cond (int depth,
 }
 
 static void
-decode_packed_otf_tag (MFLTGlyphString *gstring, int from, int to,
-                      FontLayoutCategory *category)
+decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
+                      int from, int to, FontLayoutCategory *category)
 {
   for (; from < to; from++)
     {
@@ -1853,6 +1875,8 @@ decode_packed_otf_tag (MFLTGlyphString *gstring, int from, int to,
       unsigned int tag = g->internal & 0xFFFFFFF;
       char enc;
 
+      if (GET_COMBINED (g))
+       continue;
       if (! category)
        {
          SET_CATEGORY_CODE (g, 0);
@@ -1862,16 +1886,19 @@ decode_packed_otf_tag (MFLTGlyphString *gstring, int from, int to,
        {
          int i;
 
-         g->internal &= 0x30000000;
+         /* Clear the feature tag code.  */
+         g->internal &= ~0xFFFFFFF;
          for (i = 0, enc = '\0'; i < category->feature_table.size; i++)
            if (category->feature_table.tag[i] == tag)
              {
                enc = category->feature_table.code[i];
+               if (ctx->in == gstring)
+                 ctx->encoded[from - ctx->encoded_offset] = enc;
                break;
              }
        }
       else
-       enc = GET_COMBINED (g) ? '\0' : GET_CATEGORY_CODE (g);
+       enc = '\0';
       if (! enc)
        enc = g->c > 0 ? (int) mchartable_lookup (category->table, g->c) : 1;
       SET_CATEGORY_CODE (g, enc);
@@ -1913,7 +1940,8 @@ run_otf (int depth,
                            adjustment);
       if (to < 0)
        return to;
-      decode_packed_otf_tag (ctx->out, from_idx, ctx->out->used, ctx->category);
+      decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
+                            ctx->category);
       out_len = ctx->out->used - from_idx;
       if (otf_spec->features[1])
        {
@@ -1986,28 +2014,49 @@ run_otf (int depth,
 }
 
 static int
-run_otf_category (int depth, MFLTOtfSpec *otf_spec, int from, int to,
-                 FontLayoutContext *ctx)
+try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
+        FontLayoutContext *ctx)
 {
   MFLTFont *font = ctx->font;
-  int from_idx = ctx->out->used;
-
-  if (! ctx->category || ctx->category->feature_table.size == 0)
-    return from;
 
   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);
-  if (font->drive_otf)
+  if (! otf_spec->features[0] && ! otf_spec->features[1])
     {
-      int out_len;
+      /* Reset categories.  */
+      MCharTable *table = ctx->category->table;
       int i;
 
-      to = font->drive_otf (font, otf_spec, ctx->in, from, to, NULL, NULL);
+      for (i = from; i < to; i++)
+       {
+         MFLTGlyph *g = GREF (ctx->in, i);
+
+         if (! GET_COMBINED (g))
+           {
+             char enc = (GET_ENCODED (g)
+                         ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
+                            : 1)
+                         : g->code
+                         ? (int) mchartable_lookup (table, g->code)
+                         : ' ');
+             SET_CATEGORY_CODE (g, enc);
+             ctx->encoded[i - ctx->encoded_offset] = enc;
+           }
+       }
+      return from;
+    }
+
+  if (ctx->stage->category->feature_table.size == 0)
+    return from;
+
+  font->get_glyph_id (font, ctx->in, from, to);
+  if (mflt_try_otf)
+    {
+      to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
       if (to < 0)
        return from;
-      decode_packed_otf_tag (ctx->in, from, to, ctx->category);
+      decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
     }
   return from;
 }
@@ -2113,7 +2162,7 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
       else if (cmd->type == FontLayoutCmdTypeOTF)
        to = run_otf (depth, &cmd->body.otf, from, to, ctx);
       else if (cmd->type == FontLayoutCmdTypeOTFCategory)
-       to = run_otf_category (depth, &cmd->body.otf, from, to, ctx);
+       to = try_otf (depth, &cmd->body.otf, from, to, ctx);
       return to;
     }
 
@@ -2136,17 +2185,6 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
        g = GREF (ctx->out, ctx->out->used - 1);
        if (ctx->combining_code)
          SET_COMBINING_CODE (g, ctx, ctx->combining_code);
-       else if (! GET_COMBINED (g) && ctx->category)
-         {
-           MCharTable *table = ctx->category->table;
-           char enc = (GET_ENCODED (g)
-                       ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
-                          : 1)
-                       : g->code
-                       ? (int) mchartable_lookup (table, g->code)
-                       : ' ');
-           SET_CATEGORY_CODE (g, enc);
-         }
        if (ctx->left_padding)
          SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
        if (ctx->cluster_begin_idx >= 0)
@@ -2200,8 +2238,8 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
        g = GREF (ctx->out, ctx->out->used - 1);
        g->c = -1, g->code = 0;
        g->xadv = g->yadv = 0;
-       SET_ENCODED (g, 1);
-       SET_MEASURED (g, 1);
+       SET_ENCODED (g, 0);
+       SET_MEASURED (g, 0);
        SET_CATEGORY_CODE (g, ' ');
        return from;
       }
@@ -2237,6 +2275,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
   int i, j;
   MFLTGlyph *g;
   MPlist *stages = flt->stages;
+  FontLayoutCategory *prev_category = NULL;
 
   from_pos = GREF (ctx->in, from)->from;
   to_pos = GREF (ctx->in, to - 1)->to;
@@ -2268,12 +2307,17 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
          MFLTGlyph *g = GREF (ctx->in, i);
          char enc;
 
-         if (GET_COMBINED (g))
-           enc = (GET_ENCODED (g)
-                  ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
-                  : g->code
-                  ? (int) mchartable_lookup (table, g->code)
-                  : ' ');
+         if (GET_COMBINED (g)
+             || (prev_category && prev_category != ctx->stage->category))
+           {
+             enc = (GET_ENCODED (g)
+                    ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
+                    : g->code
+                    ? (int) mchartable_lookup (table, g->code)
+                    : ' ');
+             if (! GET_COMBINED (g))
+               SET_CATEGORY_CODE (g, enc);
+           }
          else
            enc = GET_CATEGORY_CODE (g);
          ctx->encoded[i - from] = enc;
@@ -2315,6 +2359,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to,
        break;
 
       /* Otherwise, prepare for the next stage.   */
+      prev_category = ctx->stage->category;
       temp = ctx->in;
       ctx->in = ctx->out;
       if (buf.glyphs)
@@ -2622,10 +2667,12 @@ m17n_init_flt (void)
   Mgenerator = msymbol ("generator");
   Mend = msymbol ("end");
 
+  mflt_enable_new_feature = 0;
   mflt_iterate_otf_feature = NULL;
   mflt_font_id = NULL;
+  mflt_try_otf = NULL;
 
-  MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
+  MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
   MDEBUG_POP_TIME ();
 }
 
@@ -2640,7 +2687,7 @@ m17n_fini_flt (void)
 
   MDEBUG_PUSH_TIME ();
   free_flt_list ();
-  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
+  MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
   MDEBUG_POP_TIME ();
   m17n_fini_core ();
 }
@@ -2766,6 +2813,8 @@ mflt_find (int c, MFLTFont *font)
            }
          best = flt;
        }
+      if (best == NULL)
+       return NULL;
       flt = best;
       goto found;
     }
@@ -3040,6 +3089,8 @@ mflt_run (MFLTGlyphString *gstring, int from, int to,
   return to;
 }
 
+int mflt_enable_new_feature;
+
 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
                                 MFLTOtfSpec *spec,
                                 int from, int to,
@@ -3047,6 +3098,9 @@ int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
 
 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
 
+int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
+                    MFLTGlyphString *gstring, int from, int to);
+
 \f
 /* for debugging... */
 
@@ -3059,7 +3113,7 @@ dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
   prefix[indent] = 0;
 
   if (id >= 0)
-    fprintf (stderr, "0x%02X", id);
+    fprintf (mdebug__output, "0x%02X", id);
   else if (id <= CMD_ID_OFFSET_INDEX)
     {
       int idx = CMD_ID_TO_INDEX (id);
@@ -3070,57 +3124,58 @@ dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
          FontLayoutCmdRule *rule = &cmd->body.rule;
          int i;
 
-         fprintf (stderr, "(rule ");
+         fprintf (mdebug__output, "(rule ");
          if (rule->src_type == SRC_REGEX)
-           fprintf (stderr, "\"%s\"", rule->src.re.pattern);
+           fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
          else if (rule->src_type == SRC_INDEX)
-           fprintf (stderr, "%d", rule->src.match_idx);
+           fprintf (mdebug__output, "%d", rule->src.match_idx);
          else if (rule->src_type == SRC_SEQ)
-           fprintf (stderr, "(seq)");
+           fprintf (mdebug__output, "(seq)");
          else if (rule->src_type == SRC_RANGE)
-           fprintf (stderr, "(range)");
+           fprintf (mdebug__output, "(range)");
          else
-           fprintf (stderr, "(invalid src)");
+           fprintf (mdebug__output, "(invalid src)");
 
          for (i = 0; i < rule->n_cmds; i++)
            {
-             fprintf (stderr, "\n%s  ", prefix);
+             fprintf (mdebug__output, "\n%s  ", prefix);
              dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
            }
-         fprintf (stderr, ")");
+         fprintf (mdebug__output, ")");
        }
       else if (cmd->type == FontLayoutCmdTypeCond)
        {
          FontLayoutCmdCond *cond = &cmd->body.cond;
          int i;
 
-         fprintf (stderr, "(cond");
+         fprintf (mdebug__output, "(cond");
          for (i = 0; i < cond->n_cmds; i++)
            {
-             fprintf (stderr, "\n%s  ", prefix);
+             fprintf (mdebug__output, "\n%s  ", prefix);
              dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
            }
-         fprintf (stderr, ")");
+         fprintf (mdebug__output, ")");
        }
       else if (cmd->type == FontLayoutCmdTypeOTF)
        {
-         fprintf (stderr, "(otf)");
+         fprintf (mdebug__output, "(otf)");
        }
       else
-       fprintf (stderr, "(error-command)");
+       fprintf (mdebug__output, "(error-command)");
     }
   else if (id <= CMD_ID_OFFSET_COMBINING)
-    fprintf (stderr, "cominging-code");
+    fprintf (mdebug__output, "cominging-code");
   else
-    fprintf (stderr, "(predefiend %d)", id);
+    fprintf (mdebug__output, "(predefiend %d)", id);
 }
 
 /***en
     @brief Dump a Font Layout Table.
 
     The mdebug_dump_flt () function prints the Font Layout Table $FLT
-    in a human readable way to the stderr.  $INDENT specifies how many
-    columns to indent the lines but the first one.
+    in a human readable way to the stderr or to what specified by the
+    environment variable MDEBUG_OUTPUT_FILE.  $INDENT specifies how
+    many columns to indent the lines but the first one.
 
     @return
     This function returns $FLT.  */
@@ -3134,22 +3189,22 @@ mdebug_dump_flt (MFLT *flt, int indent)
 
   memset (prefix, 32, indent);
   prefix[indent] = 0;
-  fprintf (stderr, "(flt");
+  fprintf (mdebug__output, "(flt");
   MPLIST_DO (plist, flt->stages)
     {
       FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
       int i;
 
-      fprintf (stderr, "\n%s  (stage %d", prefix, stage_idx);
+      fprintf (mdebug__output, "\n%s  (stage %d", prefix, stage_idx);
       for (i = 0; i < stage->used; i++)
        {
-         fprintf (stderr, "\n%s    ", prefix);
+         fprintf (mdebug__output, "\n%s    ", prefix);
          dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
        }
-      fprintf (stderr, ")");
+      fprintf (mdebug__output, ")");
       stage_idx++;
     }
-  fprintf (stderr, ")");
+  fprintf (mdebug__output, ")");
   return flt;
 }
 
@@ -3158,14 +3213,14 @@ mflt_dump_gstring (MFLTGlyphString *gstring)
 {
   int i;
 
-  fprintf (stderr, "(flt-gstring");
+  fprintf (mdebug__output, "(flt-gstring");
   for (i = 0; i < gstring->used; i++)
     {
       MFLTGlyph *g = GREF (gstring, i);
-      fprintf (stderr, "\n  (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
+      fprintf (mdebug__output, "\n  (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
               i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
     }
-  fprintf (stderr, ")\n");
+  fprintf (mdebug__output, ")\n");
 }
 
 /*** @} */