*** empty log message ***
[m17n/m17n-test.git] / flt.c
diff --git a/flt.c b/flt.c
index 1590ed2..884782a 100644 (file)
--- a/flt.c
+++ b/flt.c
@@ -20,7 +20,7 @@
 #elif defined (FLT_HB)
 
 #include <m17n-flt.h>
-#include <harfbuzz.h>
+#include <hb.h>
 #define PROGNAME "flt-hb"
 
 #else  /* (defined (FLT_PANGO)) */
 #include <m17n-flt.h>
 #define PANGO_ENABLE_ENGINE
 #define PANGO_ENABLE_BACKEND
-#include <pango/pango.h>
+#include <pango/pangcairo.h>
 #include <pango/pango-ot.h>
-#include <pango/pangoft2.h>
-#include <pango/pangofc-font.h>
+
 #endif
 
+#include <m17n-misc.h>
+
 static FT_Library ft_library;
 
 int
@@ -113,11 +114,23 @@ new_face (char *fontname, char **err)
 
 #ifdef FLT_GUI
 
-typedef struct
+typedef struct _MFLTFont MFLTFont;
+
+struct _MFLTFont
 {
+  int x_ppem, y_ppem;
+  void (*get_glyph_id) (void);
+  void (*get_metrics) (void);
+  void (*suitable_p) (void);
+  void (*drive_otf) (void);
   MFont *font;
   FT_Face face;
-} MFLTFont;
+};
+
+void get_glyph_id (void) {}
+void get_metrics (void) {}
+void suitable_p (void) {}
+void drive_otf (void) {}
 
 MFrame *frame;
 
@@ -157,21 +170,6 @@ close_font (MFLTFont *font)
   m17n_object_unref (frame);
 }
 
-int
-flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
-{
-  MDrawControl control;
-
-  memset (&control, 0, sizeof (MDrawControl));
-  control.two_dimensional = 1;
-  control.enable_bidi = 1;
-  control.anti_alias = 1;
-  /*control.disable_caching = 1;*/
-  mtext_put_prop (mt, from, to, Mfont, font->font);
-  mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL);
-  return 0;
-}
-
 #elif defined (FLT_OTF) || defined (FLT_HB)
 
 typedef struct {
@@ -180,55 +178,50 @@ typedef struct {
 } FontInfo;
 
 int
-get_glyph_id (MFLTFont *font, MFLTGlyph *g)
+get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
 {
   FT_Face face = ((FontInfo *) font)->face;
 
-  g->code = FT_Get_Char_Index (face, g->code);
+  for (; from < to; from++)
+    {
+      MFLTGlyph *g = gstring->glyphs + from;
 
-  return (g->code ? 0 : -1);
+      if (! g->encoded
+         && ! (g->code = FT_Get_Char_Index (face, g->code)))
+       return -1;
+      g->encoded = 1;
+    }
+  return 0;
 }
 
 int 
-get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
+get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
 {
   FT_Face face = ((FontInfo *) font)->face;
 
   for (; from < to; from++)
     {
       MFLTGlyph *g = gstring->glyphs + from;
-      FT_Glyph_Metrics *metrics;
 
-      if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
-       return -1;
-      metrics = &face->glyph->metrics;
-      g->lbearing = metrics->horiBearingX;
-      g->rbearing = metrics->horiBearingX + metrics->width;
-      g->xadv = metrics->horiAdvance;
-      g->yadv = metrics->vertAdvance;
-      g->ascent = metrics->horiBearingY;
-      g->descent = metrics->height - metrics->horiBearingY;
+      if (! g->measured)
+       {
+         FT_Glyph_Metrics *metrics;
+
+         if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
+           return -1;
+         metrics = &face->glyph->metrics;
+         g->lbearing = metrics->horiBearingX;
+         g->rbearing = metrics->horiBearingX + metrics->width;
+         g->xadv = metrics->horiAdvance;
+         g->yadv = metrics->vertAdvance;
+         g->ascent = metrics->horiBearingY;
+         g->descent = metrics->height - metrics->horiBearingY;
+         g->measured = 1;
+       }
     }
   return 0;
 }
 
-int
-flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
-{
-  MFLTGlyphString gstring;
-  int len = to - from;
-  int i;
-
-  memset (&gstring, 0, sizeof (MFLTGlyphString));
-  gstring.glyph_size = sizeof (MFLTGlyph);
-  gstring.allocated = len * 2;
-  gstring.glyphs = alloca (sizeof (MFLTGlyph) * gstring.allocated);
-  for (i = 0; i < len; i++)
-    gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
-  gstring.used = len;
-  return mflt_run (&gstring, 0, len, font, msymbol (flt_name));
-}
-
 #ifdef FLT_OTF
 
 typedef struct {
@@ -308,61 +301,74 @@ encode_features (char *str, int count, unsigned *features)
   *str = '\0';
 }
 
+static OTF_GlyphString otf_gstring;
+
+static void
+setup_otf_gstring (int size)
+{
+  if (otf_gstring.size == 0)
+    {
+      otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
+      otf_gstring.size = size;
+    }
+  else if (otf_gstring.size < size)
+    {
+      otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
+                                    sizeof (OTF_Glyph) * size);
+      otf_gstring.size = size;
+    }
+  otf_gstring.used = size;
+  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
+}
+
 int
 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
           MFLTGlyphString *in, int from, int to,
           MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
 {
-  int len = to - from;
-  int i, gidx;
   OTF *otf = ((FontInfoOTF *) font)->otf;
-  OTF_GlyphString otf_gstring;
+  int len = to - from;
+  int i, j, gidx;
   OTF_Glyph *otfg;
-  char script[4], langsys[4];
+  char script[5], *langsys = NULL;
   char *gsub_features = NULL, *gpos_features = NULL;
 
   if (len == 0)
     return from;
 
-  if (! otf)
-    goto simple_copy;
-  otf_gstring.glyphs = NULL;
-  if (OTF_get_table (otf, "head") < 0)
+  OTF_tag_name (spec->script, script);
+  if (spec->langsys)
     {
-      OTF_close (otf);
-      ((FontInfoOTF *) font)->otf = NULL;
-      goto simple_copy;
+      langsys = alloca (5);
+      OTF_tag_name (spec->langsys, langsys);
     }
-
-  tag_name (script, spec->script);
-  tag_name (langsys, spec->langsys);
-
-  if (spec->gsub_count > 0)
+  for (i = 0; i < 2; i++)
     {
-      gsub_features = alloca (6 * spec->gsub_count);
-      if (gsub_features)
-       {
-         if (OTF_check_table (otf, "GSUB") < 0)
-           gsub_features = NULL;
-         else
-           encode_features (gsub_features, spec->gsub_count, spec->gsub);
-       }
-    }
-  if (spec->gpos_count)
-    {
-      gpos_features = alloca (6 * spec->gpos_count);
-      if (gpos_features)
+      char *p;
+
+      if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
        {
-         if (OTF_check_table (otf, "GPOS") < 0)
-           gpos_features = NULL;
+         for (j = 0; spec->features[i][j]; j++);
+         if (i == 0)
+           p = gsub_features = alloca (6 * j);
          else
-           encode_features (gpos_features, spec->gpos_count, spec->gpos);
+           p = gpos_features = alloca (6 * j);
+         for (j = 0; spec->features[i][j]; j++)
+           {
+             if (spec->features[i][j] == 0xFFFFFFFF)
+               *p++ = '*', *p++ = ',';
+             else
+               {
+                 OTF_tag_name (spec->features[i][j], p);
+                 p[4] = ',';
+                 p += 5;
+               }
+           }
+         *--p = '\0';
        }
     }
 
-  otf_gstring.size = otf_gstring.used = len;
-  otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
-  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
+  setup_otf_gstring (len);
   for (i = 0; i < len; i++)
     {
       otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
@@ -392,7 +398,11 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
                g->c = in->glyphs[j].c;
                break;
              }
-         g->code = otfg->glyph_id;
+         if (g->code != otfg->glyph_id)
+           {
+             g->code = otfg->glyph_id;
+             g->measured = 0;
+           }
          out->used++;
        }
     }
@@ -404,8 +414,6 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
        out->glyphs[out->used++] = in->glyphs[from + i];
     }
 
-  font->get_metric (font, out, gidx, out->used);
-
   if (gpos_features)
     {
       FT_Face face;
@@ -510,7 +518,7 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
   return to;
 
  simple_copy:
-  font->get_metric (font, in, from, to);
+  font->get_metrics (font, in, from, to);
   for (i = 0; i < len; i++)
     {
       MFLTGlyph *g = in->glyphs + (from + i);
@@ -533,6 +541,13 @@ open_font (char *fontname, char **err)
   font_info = malloc (sizeof (FontInfoOTF));
   font_info->face = face;
   font_info->otf = OTF_open_ft_face (face);
+  if (OTF_get_table (font_info->otf, "head") < 0)
+    {
+      OTF_close (font_info->otf);
+      FT_Done_Face (font_info->face);
+      free (font_info);
+      return NULL;
+    }
   return ((MFLTFont *) font_info);
 }
 
@@ -920,7 +935,11 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
       out->glyphs[out->used] = in->glyphs[hg->cluster];
       g = out->glyphs + out->used++;
       if (g->code != hg->gindex)
-       g->c = 0, g->code = hg->gindex;
+       {
+         g->c = 0;
+         g->code = hg->gindex;
+         g->measured = 0;
+       }
       adjustment[i].set = gpos_applied;
       if (gpos_applied)
        {
@@ -1017,18 +1036,27 @@ typedef struct {
 } FontInfoPango;
 
 int
-get_glyph_id (MFLTFont *font, MFLTGlyph *g)
+get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
 {
   FontInfoPango *font_info = (FontInfoPango *) font;
 
-  g->code = pango_fc_font_get_glyph (font_info->pango_font, g->c);
-  return (g->code ? 0 : -1);
+  for (; from < to; from++)
+    {
+      MFLTGlyph *g = gstring->glyphs + from;
+
+      if (! g->encoded
+         && ! (g->code = pango_fc_font_get_glyph (font_info->pango_font,
+                                                  g->code)))
+       return -1;
+      g->encoded = 1;
+    }
+  return 0;
 }
 
 #define PANGO_SCALE_TO_26_6 (PANGO_SCALE / (1<<6))
 
 int
-get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
+get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
 {
   FontInfoPango *font_info = (FontInfoPango *) font;
   int i;
@@ -1036,20 +1064,26 @@ get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
   for (i = from; i < to; i++)
     {
       MFLTGlyph *g = gstring->glyphs + from;
-      PangoRectangle inc, logical;
 
-      pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font),
-                                   gstring->glyphs[i].code, &inc, &logical);
-      g->lbearing = inc.x / PANGO_SCALE_TO_26_6;
-      g->rbearing = (inc.x + inc.width) / PANGO_SCALE_TO_26_6;
-      g->xadv = logical.width / PANGO_SCALE_TO_26_6;
-      g->yadv = 0;
-      g->ascent = - inc.y / PANGO_SCALE_TO_26_6;
-      g->descent = (inc.height + inc.y) / PANGO_SCALE_TO_26_6;
+      if (! g->measured)
+       {
+         PangoRectangle inc, logical;
+
+         pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font),
+                                       gstring->glyphs[i].code, &inc, &logical);
+         g->lbearing = inc.x / PANGO_SCALE_TO_26_6;
+         g->rbearing = (inc.x + inc.width) / PANGO_SCALE_TO_26_6;
+         g->xadv = logical.width / PANGO_SCALE_TO_26_6;
+         g->yadv = 0;
+         g->ascent = - inc.y / PANGO_SCALE_TO_26_6;
+         g->descent = (inc.height + inc.y) / PANGO_SCALE_TO_26_6;
+         g->measured = 1;
+       }
     }
   return 0;
 }
 
+
 #ifndef PANGO_OT_DEFAULT_LANGUAGE
 #define PANGO_OT_DEFAULT_LANGUAGE ((guint) 0xFFFF)
 #endif
@@ -1133,9 +1167,15 @@ setup_features (PangoOTTableType type, FontInfoPango *font_info,
       }
   info->count = i;
   info->ruleset = pango_ot_ruleset_new (ot_info);
+#if 1
   for (i = 0; i < info->count; i++)
     pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
                                  PANGO_OT_ALL_GLYPHS);
+#else
+  for (i = info->count - 1; i >= 0; i--)
+    pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
+                                 PANGO_OT_ALL_GLYPHS);
+#endif
 }
 
 GsubGposInfo *
@@ -1186,7 +1226,11 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
       out->glyphs[out->used] = in->glyphs[glyphs->log_clusters[i]];
       g = out->glyphs + out->used++;
       if (g->code != glyph_info->glyph)
-       g->c = 0, g->code = glyph_info->glyph;
+       {
+         g->c = 0;
+         g->code = glyph_info->glyph;
+         g->measured = 0;
+       }
       g->xoff = glyph_info->geometry.x_offset / PANGO_SCALE_TO_26_6;
       g->yoff = glyph_info->geometry.y_offset / PANGO_SCALE_TO_26_6;
       g->xadv = glyph_info->geometry.width / PANGO_SCALE_TO_26_6;
@@ -1255,25 +1299,77 @@ close_font (MFLTFont *font)
   g_object_unref (font_info->fontmap);
 }
 
+#endif
+
+#ifdef FLT_GUI
+
 int
-flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
+run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
 {
-  MFLTGlyphString gstring;
-  int len = to - from;
-  int i;
+  MDrawControl control;
 
-  memset (&gstring, 0, sizeof (MFLTGlyphString));
-  gstring.glyph_size = sizeof (MFLTGlyph);
-  gstring.allocated = len * 2;
-  gstring.glyphs = alloca (sizeof (MFLTGlyph) * gstring.allocated);
-  for (i = 0; i < len; i++)
-    gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
-  gstring.used = len;
-  return mflt_run (&gstring, 0, len, font, msymbol (flt_name));
+  memset (&control, 0, sizeof (MDrawControl));
+  control.two_dimensional = 1;
+  control.enable_bidi = 1;
+  control.anti_alias = 1;
+  /*control.disable_caching = 1;*/
+  mtext_put_prop (mt, from, to, Mfont, font->font);
+  mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL);
+  return 0;
 }
 
+#else
+
+int
+run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
+{
+  static MFLT *flt = NULL;
+  MCharTable *coverage;
+  static MFLTGlyphString gstring;
+
+  if (! flt
+      && ! (flt = mflt_get (flt_name)))
+    {
+      fprintf (stderr, "Invalid FLT name: %s\n", flt_name);
+      exit (1);
+    }
+  coverage = mflt_coverage (flt);
+  while (from < to)
+    {
+      int len = 0, i;
+
+      for (; from < to; from++)
+       if (mchartable_lookup (coverage, mtext_ref_char (mt, from)))
+         {
+           for (i = from + 1; i < to; i++)
+             if (! mchartable_lookup (coverage, mtext_ref_char (mt, i)))
+               break;
+           len = i - from;
+           break;
+         }
+      if (len > 0)
+       {
+         if (gstring.allocated < len)
+           {
+             gstring.allocated = len * 2;
+             gstring.glyphs = realloc (gstring.glyphs,
+                                       sizeof (MFLTGlyph) * len * 2);
+           }
+         gstring.glyph_size = sizeof (MFLTGlyph);
+         for (i = 0; i < len; i++)
+           gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
+         gstring.used = len;
+         i = mflt_run (&gstring, 0, len, font, flt);
+         if (i < 0)
+           return i;
+         from += len;
+       }
+    }
+  return to;
+}
 #endif
 
+
 int
 main (int argc, char **argv)
 {
@@ -1282,6 +1378,7 @@ main (int argc, char **argv)
   MText *mt;
   MFLTFont *font;
   int len, i, j;
+  unsigned char *buf;
 
   if (argc < 3)
     {
@@ -1301,10 +1398,17 @@ main (int argc, char **argv)
       exit (1);
     }
   font->get_glyph_id = get_glyph_id;
-  font->get_metric = get_metric;
+  font->get_metrics = get_metrics;
   font->drive_otf = drive_otf;
 
-  mt = mconv_decode_stream (msymbol ("utf-8"), stdin);
+  i = 0;
+  buf = malloc (4096);
+  while ((j = fread (buf + i, 1, 4096, stdin)) == 4096)
+    {
+      i += 4096;
+      buf = realloc (buf, i + 4096);
+    }
+  mt = mtext_from_data (buf, i, MTEXT_FORMAT_UTF_8);
   len = mtext_len (mt);
   for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
        i = j + 1, j = mtext_character (mt, i, len, '\n'))
@@ -1313,16 +1417,16 @@ main (int argc, char **argv)
 
       if (j < 0)
        j = len;
-      to = flt (mt, i, j, font, flt_name);
+      to = run_flt (mt, i, j, font, flt_name);
       if (to < 0)
        {
          fprintf (stderr, "Error in FLT processing.\n");
          exit (1);
        }
-      while (to < j
-
+      i = j;
     }
   m17n_object_unref (mt);
+  free (buf);
   close_font (font);
   M17N_FINI ();
   return 0;