(main): If ! otf, don't setup sub14.
[m17n/libotf.git] / example / otfview.c
index 87b67c9..919c8f3 100644 (file)
@@ -1,6 +1,6 @@
 /* otfview.c -- View glyphs of OpenType fonts.
 
-Copyright (C) 2003, 2004, 2005
+Copyright (C) 2003, 2004, 2005, 2006, 2008
   National Institute of Advanced Industrial Science and Technology (AIST)
   Registration Number H15PRO167
 
@@ -72,6 +72,9 @@ XtAppContext context;
    | | idxh[7] glyph[112]  ...    glyph[127]| |
    | |         idxl[0]     ...    idxl[15]  | |
    | +--------------------------------------+ |
+   | +---- uvs_area (box) (optional) -------+ |
+   | | uvs[?].w ...                         | |
+   | +--------------------------------------+ |
    | +--- render_area (form) ---------------+ |
    | | clear del bidi alt_subst             | |
    | | +--- raw (box) --------------------+ | |
@@ -88,6 +91,7 @@ Widget shell, frame;
 Widget command_area, quit, dump, *charmap;
 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
 Widget glyph_area, glyph[128], index_label[8];
+Widget uvs_area, uvs_label;
 Widget render_area, clear, del, bidi, alt_subst, raw, seq;
 Widget raw_label, raw_image, seq_label, seq_image;
 unsigned long foreground, background;
@@ -126,7 +130,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;
@@ -154,8 +158,16 @@ struct {
   int codes[64];
 } glyph_rec;
 
+OTF_EncodingSubtable14 *sub14 = NULL;
+
+struct {
+  Widget w;
+  int c;
+} uvs[256];
+
 OTF *otf;
 char *filename;
+int fontindex;
 
 void
 create_pixmap (int index)
@@ -211,7 +223,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,11 +245,35 @@ 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);
 }
 
+void
+update_uvs_area (int c)
+{
+  OTF_GlyphID code[256];
+  Arg arg[1];
+  int i;
+
+  OTF_get_variation_glyphs (otf, c, code);
+
+  for (i = 0; i < 256; i++)
+    if (uvs[i].w)
+      {
+       if (code[i])
+         XtSetArg (arg[0], XtNsensitive, True);
+       else
+         XtSetArg (arg[0], XtNsensitive, False);
+       XtSetValues (uvs[i].w, arg, 1);
+      }
+}
+
+
 char *
 get_features (OTF_FeatureList *list, FeatureRec *rec)
 {
@@ -264,9 +300,10 @@ get_features (OTF_FeatureList *list, FeatureRec *rec)
 }
 
 
-#define DEVICE_DELTA(table, size)                              \
-  (((size) >= (table).StartSize && (size) <= (table).EndSize)  \
-   ? (table).DeltaValue[(size) >= (table).StartSize]           \
+#define DEVICE_DELTA(table, size)                                      \
+  (((table).DeltaValue                                                 \
+    && ((size) >= (table).StartSize && (size) <= (table).EndSize))     \
+   ? (table).DeltaValue[(size) >= (table).StartSize]                   \
    : 0)
 
 void
@@ -308,7 +345,11 @@ update_seq_area ()
   gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
   memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
   for (i = 0; i < len; i++)
-    gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
+    {
+      gstring.glyphs[i].c = glyph_rec.codes[i];
+      if (charmap_index < 0)
+       gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
+    }
 
   XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
   XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
@@ -317,6 +358,7 @@ update_seq_area ()
       char *str;
 
       OTF_drive_gdef (otf, &gstring);
+      OTF_drive_cmap (otf, &gstring);
       if (otf->gsub)
        {
          str = get_features (&otf->gsub->FeatureList, &gsub);
@@ -334,7 +376,7 @@ update_seq_area ()
          str = get_features (&otf->gpos->FeatureList, &gpos);
          if (str)
            {
-             OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
+             OTF_drive_gpos2 (otf, &gstring, NULL, NULL, str);
              free (str);
            }
        }
@@ -370,69 +412,78 @@ update_seq_area ()
       int prev_width;
       int advance = bmp->advance;
 
-      if (! bmp->pixmap)
+      if (gstring.glyphs[i].glyph_id && ! bmp->pixmap)
        {
          create_pixmap (gstring.glyphs[i].glyph_id);
          if (! bmp->pixmap)
            continue;
          advance = bmp->advance;
        }
-      switch (g->positioning_type)
+      if (g->positioning_type)
        {
-       case 0:
-         break;
-
-       case 1: case 2:
-         {
-           int format = g->f.f1.format;
-
-           if (format & OTF_XPlacement)
-             xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
-           if (format & OTF_XPlaDevice)
-             xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
-           if (format & OTF_YPlacement)
-             yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
-           if (format & OTF_YPlaDevice)
-             yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
-           if (format & OTF_XAdvance)
-             advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
-           if (format & OTF_XAdvDevice)
-             advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice, pixel_size);
-         }
-         break;
+         while (1)
+           {
+             switch (g->positioning_type)
+               {
+               case 1: case 2:
+                 {
+                   int format = g->f.f1.format;
+
+                   if (format & OTF_XPlacement)
+                     xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
+                   if (format & OTF_XPlaDevice)
+                     xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
+                   if (format & OTF_YPlacement)
+                     yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
+                   if (format & OTF_YPlaDevice)
+                     yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
+                   if (format & OTF_XAdvance)
+                     advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
+                   if (format & OTF_XAdvDevice)
+                     advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice,
+                                              pixel_size);
+                 }
+                 break;
 
-       case 3:
-         /* Not yet supported.  */
-         break;
-       case 4: case 5:
-         if (! base)
-           break;
-         prev = base;
-         prev_width = base_width;
-         goto label_adjust_anchor;
-       default:                /* i.e. case 6 */
-         if (! mark)
-           break;
-         prev = mark;
-         prev_width = 0;
-       label_adjust_anchor:
-         {
-           int base_x, base_y, mark_x, mark_y;
-
-           base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
-           base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
-           mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
-           mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
-
-           if (g->f.f4.base_anchor->AnchorFormat != 1)
-             adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
-           if (g->f.f4.mark_anchor->AnchorFormat != 1)
-             adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
-           xoff = (base_x - prev_width) - mark_x;
-           yoff = base_y - mark_y;
-         }
+               case 3:
+                 /* Not yet supported.  */
+                 break;
+               case 4: case 5:
+                 if (! base)
+                   break;
+                 prev = base;
+                 prev_width = base_width;
+                 goto label_adjust_anchor;
+               default:                /* i.e. case 6 */
+                 if (! mark)
+                   break;
+                 prev = mark;
+                 prev_width = 0;
+               label_adjust_anchor:
+                 {
+                   int base_x, base_y, mark_x, mark_y;
+
+                   base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
+                   base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
+                   mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
+                   mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
+
+                   if (g->f.f4.base_anchor->AnchorFormat != 1)
+                     adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
+                   if (g->f.f4.mark_anchor->AnchorFormat != 1)
+                     adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
+                   xoff = (base_x - prev_width) - mark_x;
+                   yoff = base_y - mark_y;
+                 }
+               }
+             if (i + 1 == gstring.used
+                 || gstring.glyphs[i + 1].glyph_id
+                 || ! gstring.glyphs[i + 1].positioning_type)
+               break;
+             i++, g++;
+           }
        }
-         
+
       XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
                 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
                 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
@@ -462,28 +513,50 @@ update_render_area ()
   XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
   for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
     {
-      BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
-      char buf[5];
-
-      XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
-                0, 0, glyph_width, glyph_height,
-                (glyph_width + 4) * i + 1, 1);
-      XDrawRectangle (display, raw_pixmap, gc_set,
-                     (glyph_width + 4) * i, 0,
-                     glyph_width + 1, glyph_height + 1);
-      XDrawLine (display, raw_pixmap, gc_set,
-                (glyph_width + 4) * i + 1 + glyph_x, 1,
-                (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
-      XDrawLine (display, raw_pixmap, gc_set,
-                (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
-                (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
-                glyph_height + 1);
-
-      sprintf (buf, "%04X", glyph_rec.codes[i]);
-      XDrawString (display, raw_pixmap, gc_inv, 
-                  (glyph_width + 1) * i + 1
-                  + (glyph_width - XTextWidth (font, buf, 4)) / 2,
-                  glyph_height + 2 + FONT_HEIGHT, buf, 4);
+      if (glyph_rec.glyphs[i] >= 0)
+       {
+         BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
+         char buf[5];
+
+         XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
+                    0, 0, glyph_width, glyph_height,
+                    (glyph_width + 4) * i + 1, 1);
+         XDrawRectangle (display, raw_pixmap, gc_set,
+                         (glyph_width + 4) * i, 0,
+                         glyph_width + 1, glyph_height + 1);
+         XDrawLine (display, raw_pixmap, gc_set,
+                    (glyph_width + 4) * i + 1 + glyph_x, 1,
+                    (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
+         XDrawLine (display, raw_pixmap, gc_set,
+                    (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
+                    (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
+                    glyph_height + 1);
+
+         sprintf (buf, "%04X", glyph_rec.codes[i]);
+         XDrawString (display, raw_pixmap, gc_inv, 
+                      (glyph_width + 4) * i + 1
+                      + (glyph_width - XTextWidth (font, buf, 4)) / 2,
+                      glyph_height + 2 + FONT_HEIGHT, buf, 4);
+       }
+      else
+       {
+         /* Variation Selector */
+         int idx = - glyph_rec.glyphs[i];
+         char buf[4];
+
+         sprintf (buf, "%03d", idx);
+         XDrawRectangle (display, raw_pixmap, gc_set,
+                         (glyph_width + 4) * i, 0,
+                         glyph_width + 1, glyph_height + 1);
+         XDrawString (display, raw_pixmap, gc_set,
+                      (glyph_width + 4) * i + 1
+                      + (glyph_width - XTextWidth (font, "VS", 2)) / 2,
+                      1 + glyph_height / 2, "VS", 2);
+         XDrawString (display, raw_pixmap, gc_set,
+                      (glyph_width + 4) * i + 1
+                      + (glyph_width - XTextWidth (font, buf, 3)) / 2,
+                      1 + glyph_height / 2 + FONT_ASCENT, buf, 3);
+       }
     }
   XtSetArg (arg[0], XtNbitmap, raw_pixmap);
   XtSetValues (raw_image, arg, 1);
@@ -516,6 +589,24 @@ DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
   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)
+    {
+      scale = g_width * size;
+      g_x = face->bbox.xMin * unit / g_width;
+      g_y = face->bbox.yMin * unit / g_width;
+    }
+  else
+    {
+      scale = g_height * size;
+      g_x = face->bbox.xMin * unit / g_height;
+      g_y = face->bbox.yMin * unit / g_height;
+    }
+  scale /= face->units_per_EM;
+
+  FT_Set_Pixel_Sizes (face, 0, size);
+
   sprintf (name, "%s-%04X.ps", face->family_name, index);
   printf ("Writing %s ... ", name);
   fflush (stdout);
@@ -557,14 +648,6 @@ DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
   fprintf (fp, "%s\n", "%%EndProlog");
   fprintf (fp, "DrawTitle DrawFrame\n");
 
-  g_width = face->bbox.xMax - face->bbox.xMin;
-  g_height = face->bbox.yMax - face->bbox.yMin;
-  scale = ((g_width > g_height) ? g_width : g_height) * size;
-  scale /= face->units_per_EM;
-  g_x = face->bbox.xMin * scale / unit / face->units_per_EM;
-  g_y = face->bbox.yMin * scale / unit / face->units_per_EM;
-
-  FT_Set_Pixel_Sizes (face, 0, size);
   for (i = 0; i < 16; i++)
     for (j = 0; j < 16; j++, index++)
       {
@@ -574,44 +657,43 @@ DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
          idx = FT_Get_Char_Index (face, (FT_ULong) index);
        else
          idx = index;
-       if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
+       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)
          {
-           if (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)
              {
-               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);
+               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");
@@ -630,15 +712,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 ();
 }
@@ -655,6 +737,33 @@ CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
 }
 
 void
+UVSProc (Widget w, XtPointer client_data, XtPointer call_data)
+{
+  unsigned idx = (unsigned) client_data;
+  int selector = uvs[idx].c;
+  OTF_VariationSelectorRecord *record;
+  int i;
+
+  if (glyph_rec.n_glyphs >= 64)
+    return;
+  for (i = 0; i < sub14->nRecords; i++)
+    {
+      record = sub14->Records + i;
+      if (record->varSelector == selector)
+       break;
+    }
+  if (i < sub14->nRecords)
+    {
+      if (glyph_rec.n_glyphs > 0
+         && glyph_rec.glyphs[glyph_rec.n_glyphs - 1] < 0)
+       glyph_rec.n_glyphs--;
+      glyph_rec.codes[glyph_rec.n_glyphs] = selector;
+      glyph_rec.glyphs[glyph_rec.n_glyphs++] = - idx - 1;
+      update_render_area ();
+    }
+}
+
+void
 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
 {
   if ((int) client_data < 0)
@@ -678,6 +787,8 @@ RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
        {
          glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
          glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
+         if (otf)
+           update_uvs_area (glyph_index + (int) client_data);
          update_render_area ();
        }
     }
@@ -931,7 +1042,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;
@@ -984,13 +1095,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
@@ -1118,7 +1229,41 @@ create_widgets ()
   XtSetArg (arg[6], XtNdefaultDistance, 0);
   glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
                                      frame, arg, 7);
+
   XtSetArg (arg[5], XtNfromVert, glyph_area);
+  if (sub14)
+    {
+      Arg arg2[3];
+
+      XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
+      uvs_area = XtCreateManagedWidget ("uvs-area", boxWidgetClass,
+                                       frame, arg, 7);
+      XtSetArg (arg2[0], XtNborderWidth, 0);
+      XtSetArg (arg2[1], XtNlabel, "Variation Selector: ");
+      uvs_label = XtCreateManagedWidget ("uvs-label", labelWidgetClass,
+                                        uvs_area, arg2, 2);
+      XtSetArg (arg2[0], XtNborderWidth, 1);
+      for (i = 0; i < sub14->nRecords; i++)
+       {
+         OTF_VariationSelectorRecord *record = sub14->Records + i;;
+         unsigned selector = record->varSelector;
+         unsigned idx;
+         char lbl[4];
+         
+         idx = (selector <= 0xFE0F ? selector - 0xFE00
+                : selector - 0xE0100 + 16);
+         if (uvs[idx].c)
+           continue;
+         uvs[idx].c = selector;
+         sprintf (lbl, "%03d", idx + 1);
+         XtSetArg (arg2[1], XtNlabel, lbl);
+         XtSetArg (arg2[2], XtNsensitive, False);
+         uvs[idx].w = XtCreateManagedWidget ("lbl", commandWidgetClass,
+                                                  uvs_area, arg2, 3);
+         XtAddCallback (uvs[idx].w, XtNcallback, UVSProc, (XtPointer) idx);
+       }
+      XtSetArg (arg[5], XtNfromVert, uvs_area);
+    }
   render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
                                       frame, arg, 6);
 
@@ -1330,6 +1475,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)
@@ -1372,39 +1530,49 @@ 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
          || (OTF_check_table (otf, "GSUB") < 0
              && OTF_check_table (otf, "GPOS") < 0))
        otf = NULL;
+      else
+       for (i = 0; i < otf->cmap->numTables; i++)
+         if (otf->cmap->EncodingRecord[i].subtable.format == 14)
+           {
+             sub14 = otf->cmap->EncodingRecord[i].subtable.f.f14;
+             break;
+           }
     }
 
-  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];
@@ -1441,9 +1609,11 @@ main (int argc, char **argv)
     XGCValues values;
 
     gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
+    XSetFont (display, gc, font->fid);
     values.function = GXset;
     values.line_width = 1;
     gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
+    XSetFont (display, gc_set, font->fid);
     values.function = GXor;
     gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
     values.function = GXcopyInverted;