*** empty log message ***
[m17n/m17n-lib.git] / src / font-flt.c
index b93c5c4..668ff6f 100644 (file)
@@ -263,6 +263,17 @@ static MSymbol Mcond, Mrange;
 
 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
 
+#define UPDATE_CLUSTER_RANGE(ctx, g)           \
+  do {                                         \
+    if ((ctx)->cluster_begin_idx)              \
+      {                                                \
+       if (ctx->cluster_begin_pos > (g).pos)   \
+         ctx->cluster_begin_pos = (g).pos;     \
+       if (ctx->cluster_end_pos < (g).to)      \
+         ctx->cluster_end_pos = (g).to;        \
+      }                                                \
+  } while (0);
+
 enum FontLayoutCmdRuleSrcType
   {
     SRC_REGEX,
@@ -295,18 +306,15 @@ typedef struct
 
 typedef struct
 {
+  /* Beginning and end indices of series of SEQ commands.  */
+  int seq_beg, seq_end;
+  /* Range of the first character appears in the above series.  */
+  int seq_from, seq_to;
+
   int n_cmds;
   int *cmd_ids;
 } FontLayoutCmdCond;
 
-typedef struct
-{
-  MSymbol script;
-  MSymbol langsys;
-  MSymbol gsub_features;
-  MSymbol gpos_features;
-} FontLayoutCmdOTF;
-
 enum FontLayoutCmdType
   {
     FontLayoutCmdTypeRule,
@@ -321,7 +329,7 @@ typedef struct
   union {
     FontLayoutCmdRule rule;
     FontLayoutCmdCond cond;
-    FontLayoutCmdOTF otf;
+    MFontCapability *otf;
   } body;
 } FontLayoutCmd;
 
@@ -394,49 +402,31 @@ load_category_table (MPlist *plist)
        [FEATURE[,FEATURE]*] | ' '  */
 
 static int
-load_otf_command (FontLayoutCmd *cmd, char *name)
+load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
 {
-  char *p = name, *beg;
+  char *name = MSYMBOL_NAME (sym);
 
-  cmd->type = FontLayoutCmdTypeOTF;
-  cmd->body.otf.script = cmd->body.otf.langsys = Mnil;
-  cmd->body.otf.gsub_features = cmd->body.otf.gpos_features = Mt;
-
-  while (*p)
+  if (name[0] != ':')
     {
-      if (*p == ':')
-       {
-         for (beg = ++p; *p && *p != '/' && *p != '=' && *p != '+'; p++);
-         if (beg < p)
-           cmd->body.otf.script = msymbol__with_len (beg, p - beg);
-       }
-      else if (*p == '/')
-       {
-         for (beg = ++p; *p && *p != '=' && *p != '+'; p++);
-         if (beg < p)
-           cmd->body.otf.langsys = msymbol__with_len (beg, p - beg);
-       }
-      else if (*p == '=')
-       {
-         for (beg = ++p; *p && *p != '+'; p++);
-         if (beg < p)
-           cmd->body.otf.gsub_features = msymbol__with_len (beg, p - beg);
-         else
-           cmd->body.otf.gsub_features = Mnil;
-       }
-      else if (*p == '+')
-       {
-         for (beg = ++p; *p && *p != '+'; p++);
-         if (beg < p)
-           cmd->body.otf.gpos_features = msymbol__with_len (beg, p - beg);
-         else
-           cmd->body.otf.gpos_features = Mnil;
-       }
-      else
-       p++;
+      /* This is old format of "otf:...".  Change it to ":otf=...".  */
+      char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
+
+      sprintf (str, ":otf=");
+      strcat (str, name + 4);
+      sym = msymbol (str);
     }
 
-  return (cmd->body.otf.script == Mnil ? -1 : 0);
+  cmd->body.otf = mfont__get_capability (sym);
+  if (! cmd->body.otf)
+    return -1;
+  if (cmd->body.otf->script == Mnil)
+    {
+      cmd->body.otf = NULL;
+      return -1;
+    }
+  M17N_OBJECT_REF (cmd->body.otf);
+  cmd->type = FontLayoutCmdTypeOTF;
+  return 0;
 }
 
 
@@ -574,12 +564,17 @@ load_command (FontLayoutStage *stage, MPlist *plist,
 
       if (MPLIST_SYMBOL_P (elt))
        {
+         FontLayoutCmdCond *cond;
+
          if (MPLIST_SYMBOL (elt) != Mcond)
            MERROR (MERROR_DRAW, INVALID_CMD_ID);
          elt = MPLIST_NEXT (elt);
          cmd->type = FontLayoutCmdTypeCond;
-         cmd->body.cond.n_cmds = len;
-         MTABLE_CALLOC (cmd->body.cond.cmd_ids, len, MERROR_DRAW);
+         cond = &cmd->body.cond;
+         cond->seq_beg = cond->seq_end = -1;
+         cond->seq_from = cond->seq_to = 0;
+         cond->n_cmds = len;
+         MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
          for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
            {
              int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
@@ -588,8 +583,50 @@ load_command (FontLayoutStage *stage, MPlist *plist,
                MERROR (MERROR_DRAW, INVALID_CMD_ID);
              /* The above load_command may relocate stage->cmds.  */
              cmd = stage->cmds + CMD_ID_TO_INDEX (id);
-             cmd->body.cond.cmd_ids[i] = this_id;
+             cond = &cmd->body.cond;
+             cond->cmd_ids[i] = this_id;
+             if (this_id <= CMD_ID_OFFSET_INDEX)
+               {
+                 FontLayoutCmd *this_cmd
+                   = stage->cmds + CMD_ID_TO_INDEX (this_id);
+
+                 if (this_cmd->type == FontLayoutCmdTypeRule
+                     && this_cmd->body.rule.src_type == SRC_SEQ)
+                   {
+                     int first_char = this_cmd->body.rule.src.seq.codes[0];
+
+                     if (cond->seq_beg < 0)
+                       {
+                         /* The first SEQ command.  */
+                         cond->seq_beg = i;
+                         cond->seq_from = cond->seq_to = first_char;
+                       }
+                     else if (cond->seq_end < 0)
+                       {
+                         /* The following SEQ command.  */
+                         if (cond->seq_from > first_char)
+                           cond->seq_from = first_char;
+                         else if (cond->seq_to < first_char)
+                           cond->seq_to = first_char;
+                       }
+                   }
+                 else
+                   {
+                     if (cond->seq_beg >= 0 && cond->seq_end < 0)
+                       /* The previous one is the last SEQ command.  */
+                       cond->seq_end = i;
+                   }
+               }
+             else
+               {
+                 if (cond->seq_beg >= 0 && cond->seq_end < 0)
+                   /* The previous one is the last SEQ command.  */
+                   cond->seq_end = i;
+               }
            }
+         if (cond->seq_beg >= 0 && cond->seq_end < 0)
+           /* The previous one is the last SEQ command.  */
+           cond->seq_end = i;
        }
       else
        {
@@ -673,8 +710,11 @@ load_command (FontLayoutStage *stage, MPlist *plist,
       FontLayoutCmd cmd;
 
       if (len > 4
-         && ! strncmp (name, "otf:", 4)
-         && load_otf_command (&cmd, name + 3) >= 0)
+         && ((name[0] == 'o' && name[1] == 't'
+              && name[2] == 'f' && name[3] == ':')
+             || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
+                 && name[3] == 'f' && name[4] == '='))
+         && load_otf_command (&cmd, sym) >= 0)
        {
          if (id == INVALID_CMD_ID)
            {
@@ -751,6 +791,8 @@ free_flt_command (FontLayoutCmd *cmd)
     }
   else if (cmd->type == FontLayoutCmdTypeCond)
     free (cmd->body.cond.cmd_ids);
+  else if (cmd->type == FontLayoutCmdTypeOTF)
+    M17N_OBJECT_UNREF (cmd->body.otf);
 }
 
 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
@@ -804,6 +846,7 @@ load_flt (MSymbol layouter_name)
   MPlist *top = NULL, *plist;
   MSymbol Mcategory = msymbol ("category");
   MSymbol Mgenerator = msymbol ("generator");
+  MSymbol Mend = msymbol ("end");
   MFontLayoutTable *layouter = NULL;
   MCharTable *category = NULL;
 
@@ -819,6 +862,9 @@ load_flt (MSymbol layouter_name)
       MSymbol sym;
       MPlist *elt;
 
+      if (MPLIST_SYMBOL_P (plist)
+         && MPLIST_SYMBOL (plist) == Mend)
+       break;
       if (! MPLIST_PLIST (plist))
        MERROR_GOTO (MERROR_FONT, finish);
       elt = MPLIST_PLIST (plist);
@@ -930,14 +976,6 @@ run_rule (int depth,
   int i;
   int orig_from = from;
 
-  if (ctx->cluster_begin_idx)
-    {
-      if (ctx->cluster_begin_pos > MGLYPH (from)->pos)
-       ctx->cluster_begin_pos = MGLYPH (from)->pos;
-      if (ctx->cluster_end_pos < MGLYPH (to)->pos)
-       ctx->cluster_end_pos = MGLYPH (to)->pos;
-    }
-
   if (rule->src_type == SRC_SEQ)
     {
       int len;
@@ -951,7 +989,8 @@ run_rule (int depth,
       if (i < len)
        return 0;
       to = from + len;
-      MDEBUG_PRINT1 (" (SEQ 0x%X", rule->src.seq.codes[0]);
+      MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
+                    rule->src.seq.codes[0]);
     }
   else if (rule->src_type == SRC_RANGE)
     {
@@ -964,7 +1003,7 @@ run_rule (int depth,
        return 0;
       ctx->code_offset = head - rule->src.range.from;
       to = from + 1;
-      MDEBUG_PRINT2 (" (RANGE 0x%X-0x%X",
+      MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
                     rule->src.range.from, rule->src.range.to);
     }
   else if (rule->src_type == SRC_REGEX)
@@ -982,7 +1021,7 @@ run_rule (int depth,
                        NMATCH, pmatch, 0);
       if (result == 0 && pmatch[0].rm_so == 0)
        {
-         MDEBUG_PRINT3 (" (REGEX \"%s\" \"%s\" %d",
+         MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
                         rule->src.re.pattern,
                         ctx->encoded + from - ctx->encoded_offset,
                         pmatch[0].rm_eo);
@@ -1014,7 +1053,7 @@ run_rule (int depth,
       if (from < 0)
        return 0;
       to = ctx->match_indices[rule->src.match_idx * 2 + 1];
-      MDEBUG_PRINT1 (" (INDEX %d", rule->src.match_idx);
+      MDEBUG_PRINT3 ("\n [FLT] %*s(INDEX %d", depth, "", rule->src.match_idx);
     }
 
   consumed = 0;
@@ -1052,9 +1091,13 @@ run_cond (int depth,
   MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
   depth++;
   for (i = 0; i < cond->n_cmds; i++)
-    if ((pos = run_command (depth, cond->cmd_ids[i], gstring, from, to, ctx))
-       != 0)
-      break;
+    {
+      /* TODO: Write a code for optimization utilizaing the info
+        cond->seq_XXX.  */
+      if ((pos = run_command (depth, cond->cmd_ids[i], gstring, from, to, ctx))
+         != 0)
+       break;
+    }
   if (pos < 0)
     MERROR (MERROR_DRAW, -1);
   MDEBUG_PRINT (")");
@@ -1063,21 +1106,27 @@ run_cond (int depth,
 
 static int
 run_otf (int depth,
-        FontLayoutCmdOTF *otf_cmd, MGlyphString *gstring, int from, int to,
+        MFontCapability *otf_cmd, MGlyphString *gstring, int from, int to,
         FontLayoutContext *ctx)
 {
 #ifdef HAVE_OTF
-  int gidx = gstring->used;
-
-  to = mfont__ft_drive_otf (gstring, from, to,
-                           otf_cmd->script, otf_cmd->langsys,
-                           otf_cmd->gsub_features, otf_cmd->gpos_features);
-  if (gidx < gstring->used)
-    MGLYPH (gidx)->left_padding = ctx->left_padding;
+  int from_idx = gstring->used;
+
+  MDEBUG_PRINT4 ("\n [FLT] %*s(OTF %s,%s)", depth, "",
+                (! otf_cmd->features[MFONT_OTT_GSUB].str ? ""
+                 : otf_cmd->features[MFONT_OTT_GSUB].str),
+                (! otf_cmd->features[MFONT_OTT_GPOS].str ? ""
+                 : otf_cmd->features[MFONT_OTT_GPOS].str));
+  to = mfont__ft_drive_otf (gstring, from, to, otf_cmd);
+  if (ctx->cluster_begin_idx)
+    for (; from_idx < gstring->used; from_idx++)
+      UPDATE_CLUSTER_RANGE (ctx, gstring->glyphs[from_idx]);
 #endif
   return to;
 }
 
+extern char *dump_combining_code (int code);
+
 static int
 run_command (int depth, int id, MGlyphString *gstring, int from, int to,
             FontLayoutContext *ctx)
@@ -1096,7 +1145,7 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
        g = *(MGLYPH (from - 1));
       g.type = GLYPH_CHAR;
       g.code = ctx->code_offset + id;
-      MDEBUG_PRINT1 (" (DIRECT 0x%X", g.code);
+      MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "", g.code);
       if (ctx->combining_code)
        g.combining_code = ctx->combining_code;
       if (ctx->left_padding)
@@ -1111,6 +1160,7 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
            g.to = tmp->to;
        }
       APPEND_GLYPH (gstring, g);
+      UPDATE_CLUSTER_RANGE (ctx, g);
       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
       MDEBUG_PRINT (")");
       return (from);
@@ -1129,7 +1179,7 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
       else if (cmd->type == FontLayoutCmdTypeCond)
        to = run_cond (depth, &cmd->body.cond, gstring, from, to, ctx);
       else if (cmd->type == FontLayoutCmdTypeOTF)
-       to = run_otf (depth, &cmd->body.otf, gstring, from, to, ctx);
+       to = run_otf (depth, cmd->body.otf, gstring, from, to, ctx);
 
       if (to < 0)
        return -1;
@@ -1139,6 +1189,8 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
   if (id <= CMD_ID_OFFSET_COMBINING)
     {
       ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
+      MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
+                    dump_combining_code (ctx->combining_code));
       return from;
     }
 
@@ -1154,6 +1206,8 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
        if (ctx->left_padding)
          g.left_padding = ctx->left_padding;
        APPEND_GLYPH (gstring, g);
+       UPDATE_CLUSTER_RANGE (ctx, g);
+       MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g.code);
        ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
        return (from + 1);
       }
@@ -1161,7 +1215,7 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
     case CMD_ID_CLUSTER_BEGIN:
       if (! ctx->cluster_begin_idx)
        {
-         MDEBUG_PRINT1 (" <%d", MGLYPH (from)->pos);
+         MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "", MGLYPH (from)->pos);
          ctx->cluster_begin_idx = gstring->used;
          ctx->cluster_begin_pos = MGLYPH (from)->pos;
          ctx->cluster_end_pos = MGLYPH (from)->to;
@@ -1197,12 +1251,16 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
       }
 
     case CMD_ID_LEFT_PADDING:
+      MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
       ctx->left_padding = 1;
       return from;
 
     case CMD_ID_RIGHT_PADDING:
       if (gstring->used > 0)
-       gstring->glyphs[gstring->used - 1].right_padding = 1;
+       {
+         MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
+         gstring->glyphs[gstring->used - 1].right_padding = 1;
+       }
       return from;
     }
 
@@ -1256,8 +1314,7 @@ mfont__flt_encode_char (MSymbol layouter_name, int c)
 }
 
 int
-mfont__flt_run (MGlyphString *gstring, int from, int to,
-               MSymbol layouter_name, MRealizedFace *ascii_rface)
+mfont__flt_run (MGlyphString *gstring, int from, int to, MRealizedFace *rface)
 {
   int stage_idx = 0;
   int gidx;
@@ -1266,7 +1323,9 @@ mfont__flt_run (MGlyphString *gstring, int from, int to,
   MCharTable *table;
   int encoded_len;
   int match_indices[NMATCH];
+  MSymbol layouter_name = rface->layouter;
   MFontLayoutTable *layouter = get_font_layout_table (layouter_name);
+  MRealizedFace *ascii_rface = rface->ascii_rface;
   FontLayoutStage *stage;
   int from_pos, to_pos;
   MGlyph dummy;
@@ -1325,11 +1384,29 @@ mfont__flt_run (MGlyphString *gstring, int from, int to,
       int len = to - from;
       int result;
 
-      MDEBUG_PRINT1 ("\n [FLT]   (STAGE %d", stage_idx);
+      ctx.code_offset = ctx.combining_code = ctx.left_padding = 0;
+      MDEBUG_PRINT2 ("\n [FLT]   (STAGE %d \"%s\"", stage_idx, ctx.encoded);
+      if (mdebug__flag & mdebug_mask
+         && ctx.encoded_offset < to)
+       {
+         if (gstring->glyphs[ctx.encoded_offset].type == GLYPH_PAD)
+           fprintf (stderr, " (|");
+         else
+           fprintf (stderr, " (%X", gstring->glyphs[ctx.encoded_offset].code);
+         for (i = ctx.encoded_offset + 1; i < to; i++)
+           {
+             if (gstring->glyphs[i].type == GLYPH_PAD)
+               fprintf (stderr, " |");
+             else
+               fprintf (stderr, " %X", gstring->glyphs[i].code);
+           }
+         fprintf (stderr, ")");
+       }
+
       gidx = gstring->used;
       ctx.stage = stage;
 
-      result = run_command (2, INDEX_TO_CMD_ID (0), gstring,
+      result = run_command (4, INDEX_TO_CMD_ID (0), gstring,
                            ctx.encoded_offset, to, &ctx);
       MDEBUG_PRINT (")");
       if (result < 0)
@@ -1359,7 +1436,7 @@ mfont__flt_run (MGlyphString *gstring, int from, int to,
            ctx.encoded[i - from] = ' ';
          else if (! g->otf_encoded)
            ctx.encoded[i - from] = (int) mchartable_lookup (table, g->code);
-#ifdef HAVE_FREETYPE
+#if defined (HAVE_FREETYPE) && defined (HAVE_OTF)
          else
            {
              int c = mfont__ft_decode_otf (g);
@@ -1372,7 +1449,7 @@ mfont__flt_run (MGlyphString *gstring, int from, int to,
                }
              ctx.encoded[i - from] = (c >= 0 ? c : 1);
            }
-#endif /* HAVE_FREETYPE */
+#endif /* HAVE_FREETYPE && HAVE_OTF */
        }
       ctx.encoded[i - from] = '\0';
       ctx.encoded_offset = from;
@@ -1380,8 +1457,6 @@ mfont__flt_run (MGlyphString *gstring, int from, int to,
       ctx.match_indices[1] = to;
     }
 
-  MDEBUG_PRINT (")\n");
-
   if (from == to)
     {
       /* Somehow there's no glyph contributing to characters between
@@ -1398,15 +1473,19 @@ mfont__flt_run (MGlyphString *gstring, int from, int to,
     }
   else
     {
-      /* Here we must check if all characters in the range is covered
-        by some glyph(s).  If not, change <pos> and <to> of glyphs to
-        cover uncovered characters.  */
+      /* Get actual glyph IDs of glyphs.  Also check if all characters
+        in the range is covered by some glyph(s).  If not, change
+        <pos> and <to> of glyphs to cover uncovered characters.  */
       int len = to_pos - from_pos;
       int pos;
       MGlyph **glyphs = alloca (sizeof (MGlyph) * len);
       MGlyph *g, *gend = MGLYPH (to);
       MGlyph *latest = gend;
 
+      for (g = MGLYPH (from); g != gend; g++)
+       if (g->type == GLYPH_CHAR && ! g->otf_encoded)
+         g->code = ((rface->rfont->driver->encode_char)
+                    (NULL, (MFont *) rface->rfont, NULL, g->code));
       for (i = 0; i < len; i++)
        glyphs[i] = NULL;
       for (g = MGLYPH (from); g != gend; g++)
@@ -1438,6 +1517,25 @@ mfont__flt_run (MGlyphString *gstring, int from, int to,
            latest = glyphs[i];
        }
     }
+  MDEBUG_PRINT ("\n [FLT]   (RESULT (");
+  if (mdebug__flag & mdebug_mask
+      && ctx.encoded_offset < to)
+    {
+      if (gstring->glyphs[from].type == GLYPH_PAD)
+       fprintf (stderr, "|");
+      else
+       fprintf (stderr, "%X", gstring->glyphs[from].code);
+      for (from++; from < to; from++)
+       {
+         if (gstring->glyphs[from].type == GLYPH_PAD)
+           fprintf (stderr, " |");
+         else
+           fprintf (stderr, " %X", gstring->glyphs[from].code);
+       }
+      fprintf (stderr, "))");
+    }
+  MDEBUG_PRINT (")\n");
+
   return to;
 }