(lookup_gpos): Ignore mark glyphs while
[m17n/libotf.git] / example / otfview.c
index ab6ddda..79428da 100644 (file)
@@ -1,6 +1,6 @@
 /* otfview.c -- View glyphs of OpenType fonts.
 
-Copyright (C) 2003, 2004, 2005
+Copyright (C) 2003, 2004, 2005, 2006
   National Institute of Advanced Industrial Science and Technology (AIST)
   Registration Number H15PRO167
 
@@ -126,7 +126,7 @@ typedef struct {
   int advance;
 } BitmapRec;
 
-BitmapRec bitmap[0x10000];
+BitmapRec bitmap[0x110000];
 
 int render_width, render_height;
 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
@@ -156,6 +156,7 @@ struct {
 
 OTF *otf;
 char *filename;
+int fontindex;
 
 void
 create_pixmap (int index)
@@ -211,7 +212,7 @@ update_glyph_area ()
 
       if (charmap_index >= 0)
        index = FT_Get_Char_Index (face, (FT_ULong) index);
-      if (! index)
+      if (charmap_index >= 0 && ! index)
        XtSetArg (arg[0], XtNbitmap, none_pixmap);
       else
        {
@@ -233,7 +234,10 @@ update_glyph_area ()
       XtSetValues (index_label[i], arg, 2);
     }
 
-  sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
+  if (glyph_index < 0x10000)
+    sprintf (buf, "  %04X-%04X  ", glyph_index, glyph_index + 0x7F);
+  else
+    sprintf (buf, "%06X-%06X", glyph_index, glyph_index + 0x7F);
   XtSetArg (arg[0], XtNlabel, buf);
   XtSetValues (range, arg, 1);
 }
@@ -499,128 +503,134 @@ QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
 void
 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
 {
-  int g_width, g_height, g_x, g_y, pix_width, pix_height;
-  int margin = 20 * 300 / 25.4;
-  int a4_width = 210 * 300 / 25.4 - margin * 2;
-  int a4_height = 297 * 300 / 25.4 - margin * 2;
-  int size = 100;
-  Pixmap pixmap;
-  XImage ximage, *image;
-  int i, x, y;
-  char *data;
-  int bytes_per_line;
-
-  FT_Set_Pixel_Sizes (face, 0, size);
-  g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
-  g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
-  pix_width = (g_width + 1) * 16 + margin + 1;
-  pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
-  while (pix_width > a4_width || pix_height > a4_height)
+  int g_width, g_height;
+  float g_x, g_y;
+  /* unit in points (1/72 inch); to fit in both US-letter and A4 */
+  static int xoff = 30, yoff = 30;
+  static int unit = 30;
+  static int margin = 2;
+  static int title_height = 20, label_height = 10;
+  int total_width = (unit + margin * 2) * 16;
+  int total_height = (unit + margin * 2 + label_height) * 16 + title_height;
+  /* pixel size (dots) */
+  int size = 128;
+  int i, j, k, l;
+  char *name = alloca (strlen (filename) + 10);
+  FILE *fp;
+  int index = (glyph_index / 0x100) * 0x100;
+  float scale;
+
+  g_width = face->bbox.xMax - face->bbox.xMin;
+  g_height = face->bbox.yMax - face->bbox.yMin;
+  if (g_width > g_height)
     {
-      size--;
-      FT_Set_Pixel_Sizes (face, 0, size);
-      g_width = ((face->bbox.xMax - face->bbox.xMin)
-                * size / face->units_per_EM);
-      g_height = ((face->bbox.yMax - face->bbox.yMin)
-                 * size / face->units_per_EM);
-      pix_width = (g_width + 1) * 16 + margin + 1;
-      pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
+      scale = g_width * size;
+      g_x = face->bbox.xMin * unit / g_width;
+      g_y = face->bbox.yMin * unit / g_width;
     }
-
-  g_x = - (face->bbox.xMin * size / face->units_per_EM);
-  g_y = face->bbox.yMax * size / face->units_per_EM;
-  for (i = 0; i < 0xFF; i++)
+  else
     {
-      int idx;
-
-      if (charmap_index >= 0)
-       idx = FT_Get_Char_Index (face, (FT_ULong) i);
-      else
-       idx = i;
-      if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
-       {
-         if (g_x < - face->glyph->bitmap_left)
-           g_x = - face->glyph->bitmap_left;
-         if (g_y < face->glyph->bitmap_top)
-           g_y = face->glyph->bitmap_top;
-         if (g_width
-             < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
-           g_width
-             = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
-         if (g_height
-             < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
-           g_height
-             = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
-       }
+      scale = g_height * size;
+      g_x = face->bbox.xMin * unit / g_height;
+      g_y = face->bbox.yMin * unit / g_height;
     }
-  pix_width = (g_width + 1) * 16 + margin + 1;
-  pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
-  pixmap = XCreatePixmap (display,
-                         RootWindow (display, DefaultScreen (display)),
-                         pix_width, pix_height, 1);
-  XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
-
-  for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
-    XDrawLine (display, pixmap, gc_set, x, margin,
-              x, margin + (g_height + FONT_HEIGHT + 1) * 16);
-  for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
-    XDrawLine (display, pixmap, gc_set, margin, y,
-              margin + (g_width + 1) * 16, y);
-  for (i = 0; i < 256; i++)
-    {
-      char str[5];
-      int idx;
+  scale /= face->units_per_EM;
 
-      if (charmap_index >= 0)
-       idx = FT_Get_Char_Index (face, (FT_ULong) i);
-      else
-       idx = i;
-      x = margin + (g_width + 1) * (i % 16);
-      y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
-      if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
-       {
-         ximage.height = face->glyph->bitmap.rows;
-         ximage.width = face->glyph->bitmap.width;
-         ximage.depth = 1;
-         ximage.bits_per_pixel = 1;
-         ximage.xoffset = 0;
-         ximage.format = XYPixmap;
-         ximage.data = (char *) face->glyph->bitmap.buffer;
-         ximage.byte_order = MSBFirst;
-         ximage.bitmap_unit = 8;
-         ximage.bitmap_bit_order = MSBFirst;
-         ximage.bitmap_pad = 8;
-         ximage.bytes_per_line = face->glyph->bitmap.pitch;
-         XInitImage (&ximage);
-         XPutImage (display, pixmap, gc, &ximage, 0, 0,
-                    x + g_x + face->glyph->bitmap_left,
-                    y + g_y - face->glyph->bitmap_top, 
-                    ximage.width, ximage.height);
-       }
-      sprintf (str, "0x%02X", i);
-      XDrawString (display, pixmap, gc_inv,
-                  x + (g_width - XTextWidth (font, str, 4))/ 2,
-                  y + g_height + FONT_ASCENT, str, 4);
-    }
+  FT_Set_Pixel_Sizes (face, 0, size);
+
+  sprintf (name, "%s-%04X.ps", face->family_name, index);
+  printf ("Writing %s ... ", name);
+  fflush (stdout);
+  fp = fopen (name, "w");
+
+  fprintf (fp, "%s\n", "%!PS-Adobe-2.0 EPSF-2.0");
+  fprintf (fp, "%s\n", "%%Creater: otfview");
+  fprintf (fp, "%s %s(%s)-%04X\n", "%%Title:",
+          face->family_name, face->style_name, index);
+  fprintf (fp, "%s\n", "%%Pages: 1");
+  fprintf (fp, "%s %d %d %d %d\n", "%%BoundingBox:",
+          xoff, yoff, xoff + total_width, yoff + total_height);
+  fprintf (fp, "%s\n", "%%EndComments");
+  fprintf (fp, "%s\n", "%%BeginProlog");
+  fprintf (fp, "/W %d def\n", unit + margin * 2);
+  fprintf (fp, "/H %d def\n", unit + margin * 2 + label_height);
+  fprintf (fp, "/STR 10 string def\n");
+  fprintf (fp, "/DrawIndex {\n");
+  fprintf (fp, "  I 16 lt { (000) show } { I 256 lt { (00) show } { I 4096 lt { (0) show} if } ifelse } ifelse I 16 STR cvrs show\n");
+  fprintf (fp, "} def\n");
+  fprintf (fp, "/DrawTitle {\n");
+  fprintf (fp, "  /Courier findfont 20 scalefont setfont\n");
+  fprintf (fp, "  %d %d 4 add moveto\n", xoff + total_width / 2,
+          yoff + total_height - title_height + 2);
+  fprintf (fp, "  (%s(%s)-%04X) dup stringwidth pop 2 div neg 0 rmoveto show\n",
+          face->family_name, face->style_name, index);
+  fprintf (fp, "} def\n");
+  fprintf (fp, "/DrawFrame { gsave %d %d translate 0 setlinewidth\n",
+          xoff, yoff);
+  fprintf (fp, "  /Courier findfont 10 scalefont setfont\n");
+  fprintf (fp, "  /I %d def\n", index);
+  fprintf (fp, "  0 1 16 { W mul 0 moveto 0 H 16 mul rlineto stroke } for\n");
+  fprintf (fp, "  0 1 16 { H mul 0 exch moveto W 16 mul 0 rlineto stroke } for\n");
+  fprintf (fp, "  0 1 15 { H mul %d add 0 exch moveto W 16 mul 0 rlineto stroke } for\n", label_height);
+  fprintf (fp, "  15 -1 0 { gsave H mul 0 exch translate 0 0 moveto\n");
+  fprintf (fp, "    0 1 15 { gsave W mul 0 moveto\n");
+  fprintf (fp, "      4 2 rmoveto DrawIndex /I I 1 add def grestore} for\n");
+  fprintf (fp, "    grestore } for grestore } def\n");
+  fprintf (fp, "%s\n", "%%EndProlog");
+  fprintf (fp, "DrawTitle DrawFrame\n");
+
+  for (i = 0; i < 16; i++)
+    for (j = 0; j < 16; j++, index++)
+      {
+       int idx;
+
+       if (charmap_index >= 0) 
+         idx = FT_Get_Char_Index (face, (FT_ULong) index);
+       else
+         idx = index;
+       if (idx > 0
+           && FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0
+           && face->glyph->bitmap.rows > 0
+           && face->glyph->bitmap.width > 0)
+         {
+           unsigned char *p = face->glyph->bitmap.buffer;
+           int width = (face->glyph->bitmap.width - 1) / 8 + 1;
+
+           fprintf (fp, "gsave %f %f translate %d %d scale 0 0 moveto\n",
+                    xoff + (unit + margin * 2) * j + margin - g_x,
+                    yoff + (unit + label_height + margin * 2) * (15 - i) + label_height + margin - g_y,
+                    unit, unit);
+           fprintf (fp, "%d %d true [%f 0 0 %f %d %d]\n",
+                    width * 8, face->glyph->bitmap.rows,
+                    scale, -scale, -face->glyph->bitmap_left,
+                    face->glyph->bitmap_top);
+           fprintf (fp, "{< ");
+           for (k = 0; k < face->glyph->bitmap.rows;
+                k++, p += face->glyph->bitmap.pitch)
+             {
+               for (l = 0; l < width; l++)
+                 fprintf (fp, "%02X", p[l]);
+               fprintf (fp, "\n");
+             }
+           fprintf (fp, ">} imagemask grestore\n");
+         }
+       else
+         {
+           int boxsize = unit + margin * 2;
+
+           fprintf (fp, "gsave 0 setlinewidth %d %d translate\n",
+                    xoff + boxsize * j,
+                    yoff + (boxsize + label_height) * (15 - i) + label_height);
+           fprintf (fp, "0 0 moveto %d %d lineto stroke\n",
+                    boxsize, boxsize);
+           fprintf (fp, "0 %d moveto %d 0 lineto stroke grestore\n",
+                    boxsize, boxsize);
+         }
+      }
+  fprintf (fp, "showpage\n");
+  fclose (fp);
+  printf ("done\n");
 
-  image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
-                    AllPlanes, XYPixmap);
-  XInitImage (image);
-  {
-    char *name = alloca (strlen (filename) + 5);
-    FILE *fp;
-
-    sprintf (name, "%s.pbm", filename);
-    printf ("Writing %s ...", name);
-    fp = fopen (name, "w");
-    fprintf (fp, "P4\n%d %d\n", image->width, image->height);
-    bytes_per_line = (image->width + 7) / 8;
-    data = image->data;
-    for (y = 0; y < image->height; y++, data += image->bytes_per_line)
-      fwrite (data, 1, bytes_per_line, fp);
-    fclose (fp);
-    printf ("done\n");
-  }
   FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
 }
 
@@ -633,15 +643,15 @@ GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
   if ((int) client_data == -3 && glyph_index > 0)
     glyph_index = 0;
   else if ((int) client_data == -2 && glyph_index > 0)
-    glyph_index = (glyph_index - 1) & 0xF000;
+    glyph_index = (glyph_index - 1) & 0x1FF000;
   else if ((int) client_data == -1 && glyph_index > 0)
     glyph_index -= 0x80;
-  else if ((int) client_data == 1 && glyph_index < 0xFF80)
+  else if ((int) client_data == 1 && glyph_index < 0x10FF80)
     glyph_index += 0x80;
-  else if ((int) client_data == 2 && glyph_index < 0xF000)
-    glyph_index = (glyph_index + 0x1000) & 0xF000;
-  else if ((int) client_data == 3 && glyph_index < 0xF000)
-    glyph_index = 0xFF80;
+  else if ((int) client_data == 2 && glyph_index < 0x10F000)
+    glyph_index = (glyph_index + 0x1000) & 0x1FF000;
+  else if ((int) client_data == 3 && glyph_index < 0x10F000)
+    glyph_index = 0x10FF80;
   if (glyph_index != old_glyph_index)
     update_glyph_area ();
 }
@@ -934,7 +944,7 @@ create_otf_script_widgets (Widget prev)
       n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
   if (otf->gpos)
     for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
-      n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
+      n += otf->gpos->ScriptList.Script[i].LangSysCount + 1;
   script_langsys = alloca ((sizeof script_langsys[0]) * n);
   n = 0;
   nfeatures = 0;
@@ -987,13 +997,13 @@ create_otf_script_widgets (Widget prev)
            script_langsys[n].script = tag;
            script_langsys[n++].langsys = 0;
          }
-       for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
+       for (j = 0; j < otf->gpos->ScriptList.Script[i].LangSysCount; j++)
          {
            int l;
 
            if (k < prev_n)
              {
-               OTF_Script *script = otf->gsub->ScriptList.Script + i;
+               OTF_Script *script = otf->gpos->ScriptList.Script + i;
 
                for (l = k; l < prev_n && tag == script_langsys[l].script; l++)
                  if (script->LangSysRecord[j].LangSysTag
@@ -1130,7 +1140,7 @@ create_widgets ()
                                command_area, arg, 1);
   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
 
-  dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
+  dump = XtCreateManagedWidget ("DumpImage", commandWidgetClass,
                                command_area, arg, 1);
   XtAddCallback (dump, XtNcallback, DumpProc, NULL);
 
@@ -1333,6 +1343,19 @@ x_error_handler (Display *display, XErrorEvent *error)
   return 0;
 }
 
+void
+help (char **argv, int err)
+{
+  FILE *fp = err ? stderr : stdout;
+
+  fprintf (fp, "Usage: %s [ X-OPTION ... ]  OTF-FILE [INDEX]\n",
+          basename (argv[0]));
+  fprintf (fp, "  Environment variable PIXEL_SIZE specifies the pixel size.\n");
+  fprintf (fp, "  The default pixel size is %d, but is reduced\n",
+          DEFAULT_PIXEL_SIZE);
+  fprintf (fp, "  if your screen is not that wide.\n");
+  exit (err);
+}
 
 int
 main (int argc, char **argv)
@@ -1375,21 +1398,34 @@ main (int argc, char **argv)
   if (! font)
     font = XLoadQueryFont (display, "fixed");
 
-  if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
+  if (argc < 2)
+    help (argv, 1);
+  if (!strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
+    help (argv, 0);
+  filename = argv[1];
+  if (argc > 2)
     {
-      fprintf (stderr, "Usage: %s [ X-OPTION ... ]  OTF-FILE\n",
-              basename (argv[0]));
-      fprintf (stderr,
-              "  Pixel size is decided by the environment variable PIXEL_SIZE ((default %d).\n", DEFAULT_PIXEL_SIZE);
-      exit (argc != 2);
+      fontindex = atoi (argv[2]);
+      if (fontindex < 0)
+       FATAL_ERROR ("Invalid font index: %d\n", fontindex);
     }
-  filename = argv[1];
+
+  if ((err = FT_Init_FreeType (&library)))
+    FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
+  err = FT_New_Face (library, filename, fontindex, &face);
+  if (err == FT_Err_Unknown_File_Format)
+    FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
+  else if (err)
+    FATAL_ERROR ("%s\n", "FT_New_Face: unknown error (invalid face index?)");
+  if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
+    FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
+
   if (strstr (filename, ".ttf")
       || strstr (filename, ".TTF")
       || strstr (filename, ".otf")
       || strstr (filename, ".OTF"))
     {
-      otf = OTF_open (filename);
+      otf = OTF_open_ft_face (face);
       if (! otf
          || OTF_get_table (otf, "head") < 0
          || OTF_get_table (otf, "cmap") < 0
@@ -1398,16 +1434,6 @@ main (int argc, char **argv)
        otf = NULL;
     }
 
-  if ((err = FT_Init_FreeType (&library)))
-    FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
-  err = FT_New_Face (library, filename, 0, &face);
-  if (err == FT_Err_Unknown_File_Format)
-    FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
-  else if (err)
-    FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
-  if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
-    FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
-
   {
     char title[256];
     Arg arg[1];