(update_seq_area): Call OTF_drive_gpos2
[m17n/libotf.git] / example / otfview.c
1 /* otfview.c -- View glyphs of OpenType fonts.
2
3 Copyright (C) 2003, 2004, 2005, 2006, 2008
4   National Institute of Advanced Industrial Science and Technology (AIST)
5   Registration Number H15PRO167
6
7 This file is part of libotf.
8
9 Libotf is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 Libotf is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library, in a file named COPYING; if not,
21 write to the Free Software Foundation, Inc., 59 Temple Place, Suite
22 330, Boston, MA 02111-1307, USA.  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <libgen.h>
30
31 #include "config.h"
32
33 #ifdef HAVE_X11_XAW_COMMAND_H
34
35 #include <X11/Xatom.h>
36 #include <X11/Intrinsic.h>
37 #include <X11/StringDefs.h>
38 #include <X11/Shell.h>
39 #include <X11/Xaw/Command.h>
40 #include <X11/Xaw/Toggle.h>
41 #include <X11/Xaw/Box.h>
42 #include <X11/Xaw/Form.h>
43 #include <X11/Xaw/Viewport.h>
44
45 #include <ft2build.h>
46 #include FT_FREETYPE_H
47
48 #include <otf.h>
49
50 #define DEFAULT_PIXEL_SIZE 30
51 int pixel_size;
52
53 #define DEFAULT_FONT_NAME "6x13"
54 XFontStruct *font;
55 #define FONT_HEIGHT (font->ascent + font->descent)
56 #define FONT_ASCENT (font->ascent)
57 #define FONT_DESCENT (font->descent)
58 #define FONT_WIDTH (font->max_bounds.width)
59
60 XtAppContext context;
61 /* Widget structure.
62    +--- frame (form) -------------------------+
63    | +--- command_area (box) ---------------+ |
64    | | quit dump charmap ...                | |
65    | +--------------------------------------+ |
66    | +---- navi_area (box) -----------------+ |
67    | | FIRST PREV prev range next NEXT LAST | |
68    | +--------------------------------------+ |
69    | +--- glyph_area (form) ----------------+ |
70    | | idxh[0] glyph[0]    ...    glyph[15] | |
71    | |   ...                        ...     | |
72    | | idxh[7] glyph[112]  ...    glyph[127]| |
73    | |         idxl[0]     ...    idxl[15]  | |
74    | +--------------------------------------+ |
75    | +--- render_area (form) ---------------+ |
76    | | clear del bidi alt_subst             | |
77    | | +--- raw (box) --------------------+ | |
78    | | | raw_label raw_image              | | |
79    | | +----------------------------------+ | |
80    | | GSUB all none features...            | |
81    | | GPOS all none features...            | |
82    | | +--- seq (box) --------------------+ | |
83    | | | seq_label seq_image              | | |
84    | | +----------------------------------+ | |
85    | +--------------------------------------+ |
86    +------------------------------------------+ */
87 Widget shell, frame;
88 Widget command_area, quit, dump, *charmap;
89 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
90 Widget glyph_area, glyph[128], index_label[8];
91 Widget render_area, clear, del, bidi, alt_subst, raw, seq;
92 Widget raw_label, raw_image, seq_label, seq_image;
93 unsigned long foreground, background;
94
95 typedef struct
96 {
97   OTF_Tag tag;
98   int on;
99   Widget w;
100 } FeatureElement;
101
102 typedef struct
103 {
104   char *label;
105   OTF_GSUB_GPOS *gsub_gpos;
106   OTF_LangSys *langsys;
107   int num_features;
108   FeatureElement *features;
109   Widget parent;
110 } FeatureRec;
111
112 FeatureRec gsub, gpos;
113
114 /* Currently selected script and langsys.  */
115 OTF_Tag script_tag, langsys_tag;
116
117 int glyph_char[128];
118
119 Display *display;
120 GC gc, gc_set, gc_or, gc_inv;
121
122 typedef struct {
123   Pixmap pixmap;
124   unsigned width, height;
125   int x, y;
126   int advance;
127 } BitmapRec;
128
129 BitmapRec bitmap[0x110000];
130
131 int render_width, render_height;
132 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
133 Pixmap none_pixmap;
134
135 FT_Face face;
136
137 struct {
138   int platform_id;
139   int encoding_id;
140   char name[20];
141 } charmap_rec[10];
142
143 int charmap_index;
144
145 int reversed;
146 int do_alternate_subst;
147 unsigned glyph_width, glyph_height;
148 int glyph_x, glyph_y;
149 int glyph_index;
150
151 struct {
152   int n_glyphs;
153   int glyphs[64];
154   int codes[64];
155 } glyph_rec;
156
157 OTF *otf;
158 char *filename;
159 int fontindex;
160
161 void
162 create_pixmap (int index)
163 {
164   int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
165   XImage ximage;
166   Pixmap pixmap;
167   
168   if (err)
169     {
170       bitmap[index].pixmap = none_pixmap;
171       return;
172     }
173   ximage.height = face->glyph->bitmap.rows;
174   ximage.width = face->glyph->bitmap.width;
175   ximage.depth = 1;
176   ximage.bits_per_pixel = 1;
177   ximage.xoffset = 0;
178   ximage.format = XYPixmap;
179   ximage.data = (char *) face->glyph->bitmap.buffer;
180   ximage.byte_order = MSBFirst;
181   ximage.bitmap_unit = 8;
182   ximage.bitmap_bit_order = MSBFirst;
183   ximage.bitmap_pad = 8;
184   ximage.bytes_per_line = face->glyph->bitmap.pitch;
185   XInitImage (&ximage);
186   pixmap = XCreatePixmap (display, DefaultRootWindow (display),
187                           glyph_width, glyph_height, 1);
188   XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
189   XPutImage (display, pixmap, gc, &ximage, 0, 0,
190              glyph_x + face->glyph->bitmap_left,
191              glyph_y - face->glyph->bitmap_top,
192              ximage.width, ximage.height);
193   bitmap[index].pixmap = pixmap;
194   bitmap[index].width = ximage.width;
195   bitmap[index].height = ximage.height;
196   bitmap[index].x = face->glyph->bitmap_left;
197   bitmap[index].y = - face->glyph->bitmap_top;
198   bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
199 }
200
201 void
202 update_glyph_area ()
203 {
204   int i;
205   Arg arg[2];
206   char buf[16];
207   int msb;
208
209   for (i = 0; i < 128; i++)
210     {
211       int index = glyph_index + i;
212
213       if (charmap_index >= 0)
214         index = FT_Get_Char_Index (face, (FT_ULong) index);
215       if (charmap_index >= 0 && ! index)
216         XtSetArg (arg[0], XtNbitmap, none_pixmap);
217       else
218         {
219           if (! bitmap[index].pixmap)
220             create_pixmap (index);
221           XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
222         }
223       XtSetValues (glyph[i], arg, 1);
224     }
225
226   msb = (glyph_index >> 7) % 2 ? 8 : 0;
227   for (i = 0; i < 8; i++)
228     {
229       char str[3];
230
231       sprintf (str, "%XX", i | msb );
232       XtSetArg (arg[0], XtNheight, glyph_height + 5);
233       XtSetArg (arg[1], XtNlabel, str);
234       XtSetValues (index_label[i], arg, 2);
235     }
236
237   if (glyph_index < 0x10000)
238     sprintf (buf, "  %04X-%04X  ", glyph_index, glyph_index + 0x7F);
239   else
240     sprintf (buf, "%06X-%06X", glyph_index, glyph_index + 0x7F);
241   XtSetArg (arg[0], XtNlabel, buf);
242   XtSetValues (range, arg, 1);
243 }
244
245 char *
246 get_features (OTF_FeatureList *list, FeatureRec *rec)
247 {
248   int i, n;
249   char *str, *p;
250
251   if (! rec->langsys || ! rec->features || ! rec->features[0].on)
252     return NULL;
253   for (i = n = 0; i < rec->langsys->FeatureCount; i++)
254     {
255       if (rec->features[i].on)
256         n++;
257       else
258         break;
259     }
260   str = malloc (n * 5);
261   for (i = 0, p = str; i < n; i++, p += 5)
262     {
263       OTF_tag_name (rec->features[i].tag, p);
264       p[4] = ',';
265     }
266   p[-1] = '\0';
267   return str;
268 }
269
270
271 #define DEVICE_DELTA(table, size)                                       \
272   (((table).DeltaValue                                                  \
273     && ((size) >= (table).StartSize && (size) <= (table).EndSize))      \
274    ? (table).DeltaValue[(size) >= (table).StartSize]                    \
275    : 0)
276
277 void
278 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
279                OTF_Glyph *g, int *x, int *y)
280 {
281   if (anchor->AnchorFormat == 2)
282     {
283       FT_Outline *outline;
284       int ap = anchor->f.f1.AnchorPoint;
285
286       FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
287       outline = &ft_face->glyph->outline;
288       if (ap < outline->n_points)
289         {
290           *x = outline->points[ap].x;
291           *y = outline->points[ap].y;
292         }
293     }
294   else if (anchor->AnchorFormat == 3)
295     {
296       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
297       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
298     }
299 }
300
301 void
302 update_seq_area ()
303 {
304   int i, x;
305   OTF_GlyphString gstring;
306   OTF_Glyph *g, *prev, *base, *mark;
307   int base_width;
308   int len = glyph_rec.n_glyphs;
309   Arg arg[1];
310   int unitsPerEm = face->units_per_EM;
311
312   gstring.size = gstring.used = len;
313   gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
314   memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
315   for (i = 0; i < len; i++)
316     gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
317
318   XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
319   XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
320   if (otf)
321     {
322       char *str;
323
324       OTF_drive_gdef (otf, &gstring);
325       if (otf->gsub)
326         {
327           str = get_features (&otf->gsub->FeatureList, &gsub);
328           if (str)
329             {
330               if (do_alternate_subst)
331                 OTF_drive_gsub_alternate (otf, &gstring, NULL, NULL, str);
332               else
333                 OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
334               free (str);
335             }
336         }
337       if (otf->gpos)
338         {
339           str = get_features (&otf->gpos->FeatureList, &gpos);
340           if (str)
341             {
342               OTF_drive_gpos2 (otf, &gstring, NULL, NULL, str);
343               free (str);
344             }
345         }
346     }
347
348   prev = NULL;
349   if (reversed)
350     {
351       OTF_Glyph temp;
352
353       for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
354            prev < g; prev++, g--)
355         temp = *prev, *prev = *g, *g = temp;
356       for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
357         if (g->GlyphClass == 3)
358           {
359             OTF_Glyph *g0;
360             prev = g++;
361             while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
362               g++;
363             for (g0 = g; prev < g0; prev++, g0--)
364               temp = *prev, *prev = *g, *g = temp;
365           }
366     }
367
368
369   mark = base = NULL;
370   for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
371        i < gstring.used; i++, prev = g++)
372     {
373       BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
374       int xoff = 0, yoff = 0;
375       int prev_width;
376       int advance = bmp->advance;
377
378       if (gstring.glyphs[i].glyph_id && ! bmp->pixmap)
379         {
380           create_pixmap (gstring.glyphs[i].glyph_id);
381           if (! bmp->pixmap)
382             continue;
383           advance = bmp->advance;
384         }
385       if (g->positioning_type)
386         {
387           while (1)
388             {
389               switch (g->positioning_type)
390                 {
391                 case 1: case 2:
392                   {
393                     int format = g->f.f1.format;
394
395                     if (format & OTF_XPlacement)
396                       xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
397                     if (format & OTF_XPlaDevice)
398                       xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
399                     if (format & OTF_YPlacement)
400                       yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
401                     if (format & OTF_YPlaDevice)
402                       yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
403                     if (format & OTF_XAdvance)
404                       advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
405                     if (format & OTF_XAdvDevice)
406                       advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice,
407                                                pixel_size);
408                   }
409                   break;
410
411                 case 3:
412                   /* Not yet supported.  */
413                   break;
414                 case 4: case 5:
415                   if (! base)
416                     break;
417                   prev = base;
418                   prev_width = base_width;
419                   goto label_adjust_anchor;
420                 default:                /* i.e. case 6 */
421                   if (! mark)
422                     break;
423                   prev = mark;
424                   prev_width = 0;
425                 label_adjust_anchor:
426                   {
427                     int base_x, base_y, mark_x, mark_y;
428
429                     base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
430                     base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
431                     mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
432                     mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
433
434                     if (g->f.f4.base_anchor->AnchorFormat != 1)
435                       adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
436                     if (g->f.f4.mark_anchor->AnchorFormat != 1)
437                       adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
438                     xoff = (base_x - prev_width) - mark_x;
439                     yoff = base_y - mark_y;
440                   }
441                 }
442               if (i + 1 == gstring.used
443                   || gstring.glyphs[i + 1].glyph_id
444                   || ! gstring.glyphs[i + 1].positioning_type)
445                 break;
446               i++, g++;
447             }
448         }
449
450       XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
451                  glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
452                  x + bmp->x + xoff, glyph_y + bmp->y - yoff);
453       x += advance;
454
455       if (g->GlyphClass == OTF_GlyphClass0)
456         base = mark = g, base_width = advance;
457       else if (g->GlyphClass == OTF_GlyphClassMark)
458         mark = g;
459       else
460         base = g, base_width = advance;
461     }
462   free (gstring.glyphs);
463
464   XtSetArg (arg[0], XtNbitmap, seq_pixmap);
465   XtSetValues (seq_image, arg, 1);
466 }
467
468
469 void
470 update_render_area ()
471 {
472   int i;
473   int x;
474   Arg arg[1];
475
476   XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
477   for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
478     {
479       BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
480       char buf[5];
481
482       XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
483                  0, 0, glyph_width, glyph_height,
484                  (glyph_width + 4) * i + 1, 1);
485       XDrawRectangle (display, raw_pixmap, gc_set,
486                       (glyph_width + 4) * i, 0,
487                       glyph_width + 1, glyph_height + 1);
488       XDrawLine (display, raw_pixmap, gc_set,
489                  (glyph_width + 4) * i + 1 + glyph_x, 1,
490                  (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
491       XDrawLine (display, raw_pixmap, gc_set,
492                  (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
493                  (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
494                  glyph_height + 1);
495
496       sprintf (buf, "%04X", glyph_rec.codes[i]);
497       XDrawString (display, raw_pixmap, gc_inv, 
498                    (glyph_width + 1) * i + 1
499                    + (glyph_width - XTextWidth (font, buf, 4)) / 2,
500                    glyph_height + 2 + FONT_HEIGHT, buf, 4);
501     }
502   XtSetArg (arg[0], XtNbitmap, raw_pixmap);
503   XtSetValues (raw_image, arg, 1);
504   update_seq_area ();
505 }
506
507 void
508 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
509 {
510   XtAppSetExitFlag (XtWidgetToApplicationContext (w));
511 }
512
513 void
514 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
515 {
516   int g_width, g_height;
517   float g_x, g_y;
518   /* unit in points (1/72 inch); to fit in both US-letter and A4 */
519   static int xoff = 30, yoff = 30;
520   static int unit = 30;
521   static int margin = 2;
522   static int title_height = 20, label_height = 10;
523   int total_width = (unit + margin * 2) * 16;
524   int total_height = (unit + margin * 2 + label_height) * 16 + title_height;
525   /* pixel size (dots) */
526   int size = 128;
527   int i, j, k, l;
528   char *name = alloca (strlen (filename) + 10);
529   FILE *fp;
530   int index = (glyph_index / 0x100) * 0x100;
531   float scale;
532
533   g_width = face->bbox.xMax - face->bbox.xMin;
534   g_height = face->bbox.yMax - face->bbox.yMin;
535   if (g_width > g_height)
536     {
537       scale = g_width * size;
538       g_x = face->bbox.xMin * unit / g_width;
539       g_y = face->bbox.yMin * unit / g_width;
540     }
541   else
542     {
543       scale = g_height * size;
544       g_x = face->bbox.xMin * unit / g_height;
545       g_y = face->bbox.yMin * unit / g_height;
546     }
547   scale /= face->units_per_EM;
548
549   FT_Set_Pixel_Sizes (face, 0, size);
550
551   sprintf (name, "%s-%04X.ps", face->family_name, index);
552   printf ("Writing %s ... ", name);
553   fflush (stdout);
554   fp = fopen (name, "w");
555
556   fprintf (fp, "%s\n", "%!PS-Adobe-2.0 EPSF-2.0");
557   fprintf (fp, "%s\n", "%%Creater: otfview");
558   fprintf (fp, "%s %s(%s)-%04X\n", "%%Title:",
559            face->family_name, face->style_name, index);
560   fprintf (fp, "%s\n", "%%Pages: 1");
561   fprintf (fp, "%s %d %d %d %d\n", "%%BoundingBox:",
562            xoff, yoff, xoff + total_width, yoff + total_height);
563   fprintf (fp, "%s\n", "%%EndComments");
564   fprintf (fp, "%s\n", "%%BeginProlog");
565   fprintf (fp, "/W %d def\n", unit + margin * 2);
566   fprintf (fp, "/H %d def\n", unit + margin * 2 + label_height);
567   fprintf (fp, "/STR 10 string def\n");
568   fprintf (fp, "/DrawIndex {\n");
569   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");
570   fprintf (fp, "} def\n");
571   fprintf (fp, "/DrawTitle {\n");
572   fprintf (fp, "  /Courier findfont 20 scalefont setfont\n");
573   fprintf (fp, "  %d %d 4 add moveto\n", xoff + total_width / 2,
574            yoff + total_height - title_height + 2);
575   fprintf (fp, "  (%s(%s)-%04X) dup stringwidth pop 2 div neg 0 rmoveto show\n",
576            face->family_name, face->style_name, index);
577   fprintf (fp, "} def\n");
578   fprintf (fp, "/DrawFrame { gsave %d %d translate 0 setlinewidth\n",
579            xoff, yoff);
580   fprintf (fp, "  /Courier findfont 10 scalefont setfont\n");
581   fprintf (fp, "  /I %d def\n", index);
582   fprintf (fp, "  0 1 16 { W mul 0 moveto 0 H 16 mul rlineto stroke } for\n");
583   fprintf (fp, "  0 1 16 { H mul 0 exch moveto W 16 mul 0 rlineto stroke } for\n");
584   fprintf (fp, "  0 1 15 { H mul %d add 0 exch moveto W 16 mul 0 rlineto stroke } for\n", label_height);
585   fprintf (fp, "  15 -1 0 { gsave H mul 0 exch translate 0 0 moveto\n");
586   fprintf (fp, "    0 1 15 { gsave W mul 0 moveto\n");
587   fprintf (fp, "      4 2 rmoveto DrawIndex /I I 1 add def grestore} for\n");
588   fprintf (fp, "    grestore } for grestore } def\n");
589   fprintf (fp, "%s\n", "%%EndProlog");
590   fprintf (fp, "DrawTitle DrawFrame\n");
591
592   for (i = 0; i < 16; i++)
593     for (j = 0; j < 16; j++, index++)
594       {
595         int idx;
596
597         if (charmap_index >= 0) 
598           idx = FT_Get_Char_Index (face, (FT_ULong) index);
599         else
600           idx = index;
601         if (idx > 0
602             && FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0
603             && face->glyph->bitmap.rows > 0
604             && face->glyph->bitmap.width > 0)
605           {
606             unsigned char *p = face->glyph->bitmap.buffer;
607             int width = (face->glyph->bitmap.width - 1) / 8 + 1;
608
609             fprintf (fp, "gsave %f %f translate %d %d scale 0 0 moveto\n",
610                      xoff + (unit + margin * 2) * j + margin - g_x,
611                      yoff + (unit + label_height + margin * 2) * (15 - i) + label_height + margin - g_y,
612                      unit, unit);
613             fprintf (fp, "%d %d true [%f 0 0 %f %d %d]\n",
614                      width * 8, face->glyph->bitmap.rows,
615                      scale, -scale, -face->glyph->bitmap_left,
616                      face->glyph->bitmap_top);
617             fprintf (fp, "{< ");
618             for (k = 0; k < face->glyph->bitmap.rows;
619                  k++, p += face->glyph->bitmap.pitch)
620               {
621                 for (l = 0; l < width; l++)
622                   fprintf (fp, "%02X", p[l]);
623                 fprintf (fp, "\n");
624               }
625             fprintf (fp, ">} imagemask grestore\n");
626           }
627         else
628           {
629             int boxsize = unit + margin * 2;
630
631             fprintf (fp, "gsave 0 setlinewidth %d %d translate\n",
632                      xoff + boxsize * j,
633                      yoff + (boxsize + label_height) * (15 - i) + label_height);
634             fprintf (fp, "0 0 moveto %d %d lineto stroke\n",
635                      boxsize, boxsize);
636             fprintf (fp, "0 %d moveto %d 0 lineto stroke grestore\n",
637                      boxsize, boxsize);
638           }
639       }
640   fprintf (fp, "showpage\n");
641   fclose (fp);
642   printf ("done\n");
643
644   FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
645 }
646
647
648 void
649 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
650 {
651   int old_glyph_index = glyph_index;
652
653   if ((int) client_data == -3 && glyph_index > 0)
654     glyph_index = 0;
655   else if ((int) client_data == -2 && glyph_index > 0)
656     glyph_index = (glyph_index - 1) & 0x1FF000;
657   else if ((int) client_data == -1 && glyph_index > 0)
658     glyph_index -= 0x80;
659   else if ((int) client_data == 1 && glyph_index < 0x10FF80)
660     glyph_index += 0x80;
661   else if ((int) client_data == 2 && glyph_index < 0x10F000)
662     glyph_index = (glyph_index + 0x1000) & 0x1FF000;
663   else if ((int) client_data == 3 && glyph_index < 0x10F000)
664     glyph_index = 0x10FF80;
665   if (glyph_index != old_glyph_index)
666     update_glyph_area ();
667 }
668
669 void
670 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
671 {
672   if (charmap_index == (int) client_data)
673     return;
674   charmap_index = (int) client_data;
675   if (charmap_index >= 0)
676     FT_Set_Charmap (face, face->charmaps[charmap_index]);
677   update_glyph_area ();
678 }
679
680 void
681 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
682 {
683   if ((int) client_data < 0)
684     {
685       if (glyph_rec.n_glyphs > 0)
686         {
687           if ((int) client_data == -2)
688             glyph_rec.n_glyphs--;
689           else
690             glyph_rec.n_glyphs = 0;
691           update_render_area ();
692         }
693     }
694   else if (glyph_rec.n_glyphs < 64)
695     {
696       int index = glyph_index + (int) client_data;
697
698       if (charmap_index >= 0)
699         index = FT_Get_Char_Index (face, (FT_ULong) index);
700       if (bitmap[index].pixmap)
701         {
702           glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
703           glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
704           update_render_area ();
705         }
706     }
707 }
708
709 void
710 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
711 {
712   Arg arg[1];
713
714   reversed = ! reversed;
715   if (reversed)
716     XtSetArg (arg[0], XtNlabel, "L<-R");
717   else
718     XtSetArg (arg[0], XtNlabel, "L->R");
719   XtSetValues (w, arg, 1);
720   update_seq_area ();
721 }
722
723 void
724 AltSubstProc (Widget w, XtPointer client_data, XtPointer call_data)
725 {
726   do_alternate_subst = ! do_alternate_subst;
727   update_seq_area ();
728 }
729
730 void
731 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
732 {
733   FeatureRec *rec = (FeatureRec *) client_data;
734   int idx, i, j;
735   Arg arg[4];
736   char *label;
737
738   if (! rec->langsys)
739     return;
740   XtSetArg (arg[0], XtNlabel, &label);
741   XtGetValues (w, arg, 1);
742   if (! strcmp (label, "all"))
743     idx = -2;
744   else if (! strcmp (label, "none"))
745     idx = -1;
746   else
747     {
748       for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
749         if (rec->features[idx].w == w)
750           break;
751       if (idx == rec->langsys->FeatureCount)
752         idx = -1;
753     }
754   if (idx < 0)
755     {
756       int on = idx == -2;
757
758       for (i = j = 0; j < rec->langsys->FeatureCount; j++)
759         {
760           int index  = rec->langsys->FeatureIndex[j];
761
762           rec->features[j].tag
763             = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
764           rec->features[j].on = on;
765         }
766     }
767   else
768     {
769       OTF_Tag tag = rec->features[idx].tag;
770
771       i = idx;
772       if (rec->features[i].on)
773         {
774           for (j = i + 1;
775                j < rec->langsys->FeatureCount && rec->features[j].on; j++)
776             rec->features[j - 1].tag = rec->features[j].tag;
777           rec->features[j - 1].tag = tag;
778           rec->features[j - 1].on = 0;
779         }
780       else
781         {
782           for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
783             rec->features[i].tag = rec->features[i - 1].tag;
784           rec->features[i].tag = tag;
785           rec->features[i].on = 1;
786         }
787     }
788
789   for (; i < j; i++)
790     {
791       char str[5];
792
793       if (rec->features[i].on)
794         {
795           XtSetArg (arg[0], XtNborderWidth, 3);
796           XtSetArg (arg[1], XtNinternalHeight, 2);
797           XtSetArg (arg[2], XtNinternalWidth, 2);
798         }
799       else
800         {
801           XtSetArg (arg[0], XtNborderWidth, 1);
802           XtSetArg (arg[1], XtNinternalHeight, 4);
803           XtSetArg (arg[2], XtNinternalWidth, 4);
804         }
805       OTF_tag_name (rec->features[i].tag, str);
806       XtSetArg (arg[3], XtNlabel, str);
807       XtSetValues (rec->features[i].w, arg, 4);
808     }
809   update_seq_area ();
810 }
811
812 void
813 setup_feature_rec (FeatureRec *rec)
814 {
815   int i, j;
816   Arg arg[10];
817
818   rec->langsys = NULL;
819   if (! rec->gsub_gpos)
820     return;
821   for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
822     if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
823       {
824         OTF_Script *script = rec->gsub_gpos->ScriptList.Script + i;
825
826         if (langsys_tag)
827           {
828             for (j = 0; j < script->LangSysCount; j++)
829               if (script->LangSysRecord[j].LangSysTag == langsys_tag)
830                 {
831                   rec->langsys = script->LangSys + j;
832                   break;
833                 }
834           }
835         if (! rec->langsys)
836           rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
837         break;
838       }
839
840   if (! rec->langsys)
841     i = 0;
842   else
843     {
844       XtSetArg (arg[0], XtNborderWidth, 1);
845       XtSetArg (arg[1], XtNinternalHeight, 4);
846       XtSetArg (arg[2], XtNinternalWidth, 4);
847       XtSetArg (arg[3], XtNborderColor, foreground);
848       XtSetArg (arg[4], XtNsensitive, True);
849       for (i = 0; i < rec->langsys->FeatureCount; i++)
850         {
851           OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
852           int index = rec->langsys->FeatureIndex[i];
853           char label[5];
854
855           if (! rec->features[i].w)
856             {
857               Widget w = XtCreateManagedWidget ("", commandWidgetClass,
858                                                 rec->parent, arg, 0);
859               XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
860               rec->features[i].w = w;
861             }
862
863           rec->features[i].tag = feature[index].FeatureTag;
864           rec->features[i].on = 0;
865           OTF_tag_name (rec->features[i].tag, label);
866           XtSetArg (arg[5], XtNlabel, label);
867           XtSetValues (rec->features[i].w, arg, 6);
868         }
869     }
870   XtSetArg (arg[0], XtNborderColor, background);
871   XtSetArg (arg[1], XtNsensitive, False);
872   XtSetArg (arg[2], XtNlabel, "    ");
873   for (; i < rec->num_features; i++)
874     {
875       if (! rec->features[i].w)
876         {
877           Widget w = XtCreateManagedWidget ("", commandWidgetClass,
878                                             rec->parent, arg, 0);
879           XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
880           rec->features[i].w = w;
881         }
882       XtSetValues (rec->features[i].w, arg, 3);
883     }
884 }
885
886 void
887 compose_script_langsys (OTF_Tag script, OTF_Tag langsys, char *name)
888 {
889   OTF_tag_name (script, name);
890   if (langsys)
891     {
892       name[4] = '(';
893       OTF_tag_name (langsys, name + 5);
894       name[9] = ')';
895       name[10] = '\0';
896     }
897 }
898
899 void
900 decompose_script_langsys (OTF_Tag *script, OTF_Tag *langsys, char *name)
901 {
902   *script = OTF_tag (name);
903   if (name[4])
904     *langsys = OTF_tag (name + 5);
905   else
906     *langsys = 0;
907 }
908
909 void
910 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
911 {
912   char *name;
913   OTF_Tag script, langsys;
914   Arg arg[1];
915
916   XtSetArg (arg[0], XtNlabel, &name);
917   XtGetValues (w, arg, 1);
918   decompose_script_langsys (&script, &langsys, name);
919   if (script_tag == script && langsys_tag == langsys)
920     return;
921   script_tag = script;
922   langsys_tag = langsys;
923   setup_feature_rec (&gsub);
924   setup_feature_rec (&gpos);
925   update_seq_area ();
926 }
927
928 Widget
929 create_otf_script_widgets (Widget prev)
930 {
931   Widget w;
932   Arg arg[10];
933   int n, prev_n, i, j;
934   struct {
935     OTF_Tag script;
936     OTF_Tag langsys;
937   } *script_langsys;
938   char name[11];
939   int nfeatures;
940
941   XtSetArg (arg[0], XtNborderWidth, 0);
942   XtSetArg (arg[1], XtNleft, XawChainLeft);
943   XtSetArg (arg[2], XtNright, XawChainLeft);
944   XtSetArg (arg[3], XtNtop, XawChainTop);
945   XtSetArg (arg[4], XtNbottom, XawChainTop);
946   XtSetArg (arg[5], XtNfromVert, prev);
947   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
948   prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
949   XtCreateManagedWidget ("script(langsys)", labelWidgetClass, prev, arg, 1);
950
951   n = 0;
952   if (otf->gsub)
953     for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
954       n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
955   if (otf->gpos)
956     for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
957       n += otf->gpos->ScriptList.Script[i].LangSysCount + 1;
958   script_langsys = alloca ((sizeof script_langsys[0]) * n);
959   n = 0;
960   nfeatures = 0;
961   if (otf->gsub)
962     for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
963       {
964         OTF_Tag tag = otf->gsub->ScriptList.Script[i].ScriptTag;
965
966         script_langsys[n].script = tag;
967         script_langsys[n++].langsys = 0;
968         if (nfeatures
969             < otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount)
970           nfeatures
971             = otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount;
972         for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
973           {
974             script_langsys[n].script = tag;
975             script_langsys[n++].langsys
976               = otf->gsub->ScriptList.Script[i].LangSysRecord[j].LangSysTag;
977             if (nfeatures
978                 < otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount)
979               nfeatures
980                 = otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount;
981           }
982       }
983   gsub.num_features = nfeatures;
984   if (nfeatures > 0)
985     {
986       gsub.num_features = nfeatures;
987       gsub.features = malloc ((sizeof (FeatureElement)) * nfeatures);
988       memset (gsub.features, 0, (sizeof (FeatureElement)) * nfeatures);
989     }
990   prev_n = n;
991   nfeatures = 0;
992   if (otf->gpos)
993     for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
994       {
995         OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
996         int k;
997
998         if (nfeatures
999             < otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1000           nfeatures
1001             = otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1002         for (k = 0; k < prev_n; k++)
1003           if (tag == script_langsys[k].script)
1004             break;
1005         if (k == prev_n)
1006           {
1007             script_langsys[n].script = tag;
1008             script_langsys[n++].langsys = 0;
1009           }
1010         for (j = 0; j < otf->gpos->ScriptList.Script[i].LangSysCount; j++)
1011           {
1012             int l;
1013
1014             if (k < prev_n)
1015               {
1016                 OTF_Script *script = otf->gpos->ScriptList.Script + i;
1017
1018                 for (l = k; l < prev_n && tag == script_langsys[l].script; l++)
1019                   if (script->LangSysRecord[j].LangSysTag
1020                       == script_langsys[l].langsys)
1021                     break;
1022               }
1023             else
1024               l = prev_n;
1025             if (l == prev_n)
1026               {
1027                 script_langsys[n].script = tag;
1028                 script_langsys[n++].langsys = 0;
1029               }
1030             if (nfeatures
1031                 < otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount)
1032               nfeatures
1033                 = otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount;
1034           }
1035       }
1036
1037   if (nfeatures > 0)
1038     {
1039       gpos.num_features = nfeatures;
1040       gpos.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1041       memset (gpos.features, 0, (sizeof (FeatureElement)) * nfeatures);
1042     }
1043
1044   if (n == 0)
1045     return prev;
1046
1047   script_tag = script_langsys[0].script;
1048   langsys_tag = script_langsys[0].langsys;
1049   compose_script_langsys (script_tag, langsys_tag, name);
1050
1051   if (n == 1)
1052     {
1053       XtSetArg (arg[0], XtNforeground, background);
1054       XtSetArg (arg[1], XtNbackground, foreground);
1055       XtCreateManagedWidget (name, labelWidgetClass, prev, arg, 2);
1056     }
1057   else
1058     {
1059       XtSetArg (arg[0], XtNstate, True);
1060       w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
1061       XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1062       XtSetArg (arg[0], XtNradioGroup, w);
1063       for (i = 1; i < n; i++)
1064         {
1065           compose_script_langsys (script_langsys[i].script,
1066                                   script_langsys[i].langsys, name);
1067           w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
1068           XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1069         }         
1070     }
1071   return prev;
1072 }
1073
1074
1075 Widget
1076 create_otf_widgets (Widget prev, FeatureRec *rec)
1077 {
1078   Arg arg[10];
1079   Widget w;
1080
1081   XtSetArg (arg[0], XtNborderWidth, 0);
1082   XtSetArg (arg[1], XtNleft, XawChainLeft);
1083   XtSetArg (arg[2], XtNright, XawChainLeft);
1084   XtSetArg (arg[3], XtNtop, XawChainTop);
1085   XtSetArg (arg[4], XtNbottom, XawChainTop);
1086   XtSetArg (arg[5], XtNfromVert, prev);
1087   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1088   prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
1089                                 arg, 7);
1090   XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
1091   XtSetArg (arg[0], XtNborderWidth, 1);
1092   XtSetArg (arg[1], XtNinternalHeight, 4);
1093   XtSetArg (arg[2], XtNinternalWidth, 4);
1094   w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
1095   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1096   w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
1097   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1098
1099   rec->parent = prev;
1100   setup_feature_rec (rec);
1101   return prev;
1102 }
1103
1104 void
1105 create_widgets ()
1106 {
1107   String quit_action = "<KeyPress>q: set() notify() unset()";
1108   String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
1109                          <KeyPress>Home: set() notify() unset()";
1110   String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
1111                          <KeyPress>Up: set() notify() unset()";
1112   String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
1113                          <KeyPress>Left: set() notify() unset()";
1114   String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
1115                          <KeyPress>Right: set() notify() unset()";
1116   String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
1117                          <KeyPress>Down: set() notify() unset()";
1118   String LAST_action = "<KeyPress>l: set() notify() unset()\n\
1119                          <KeyPress>End: set() notify() unset()";
1120   Arg arg[10];
1121   int i, j;
1122   Widget prev, w;
1123   String trans = "<Expose>: Expose()";
1124
1125   XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
1126   frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
1127
1128   XtSetArg (arg[0], XtNleft, XawChainLeft);
1129   XtSetArg (arg[1], XtNright, XawChainLeft);
1130   XtSetArg (arg[2], XtNtop, XawChainTop);
1131   XtSetArg (arg[3], XtNbottom, XawChainTop);
1132   XtSetArg (arg[4], XtNborderWidth, 0);
1133   XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
1134   command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
1135                                         frame, arg, 6);
1136   XtSetArg (arg[6], XtNfromVert, command_area);
1137   navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
1138                                      frame, arg, 7);
1139   XtSetArg (arg[4], XtNborderWidth, 0);
1140   XtSetArg (arg[5], XtNfromVert, navi_area);
1141   XtSetArg (arg[6], XtNdefaultDistance, 0);
1142   glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
1143                                       frame, arg, 7);
1144   XtSetArg (arg[5], XtNfromVert, glyph_area);
1145   render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
1146                                        frame, arg, 6);
1147
1148   XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
1149   quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
1150                                 command_area, arg, 1);
1151   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
1152
1153   dump = XtCreateManagedWidget ("DumpImage", commandWidgetClass,
1154                                 command_area, arg, 1);
1155   XtAddCallback (dump, XtNcallback, DumpProc, NULL);
1156
1157   XtSetArg (arg[0], XtNborderWidth, 0);
1158   XtSetArg (arg[1], XtNwidth, 10);
1159   XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
1160
1161   charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
1162   XtSetArg (arg[0], XtNstate, True);
1163   charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
1164                                       command_area, arg, 1);
1165   XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1166   XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1167   for (i = 0; i < face->num_charmaps; i++)
1168     {
1169       charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1170                                               toggleWidgetClass,
1171                                               command_area, arg, 1);
1172       XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
1173     }
1174
1175   XtSetArg (arg[0], XtNlabel, " |< (f)");
1176   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1177   FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1178                                  navi_area, arg, 2);
1179   XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1180   XtSetArg (arg[0], XtNlabel, "<< (P)");
1181   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1182   PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1183                                 navi_area, arg, 2);
1184   XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1185   XtSetArg (arg[0], XtNlabel, "< (p)");
1186   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1187   prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1188                                 navi_area, arg, 2);
1189   XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1190   XtSetArg (arg[0], XtNlabel, " 0000 ");
1191   range = XtCreateManagedWidget ("range", labelWidgetClass,
1192                                  navi_area, arg, 1);
1193   XtSetArg (arg[0], XtNforeground, &foreground);
1194   XtSetArg (arg[1], XtNbackground, &background);
1195   XtGetValues (range, arg, 2);
1196
1197   XtSetArg (arg[0], XtNlabel, "> (n)");
1198   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1199   next = XtCreateManagedWidget ("next", commandWidgetClass,
1200                                 navi_area, arg, 2);
1201   XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1202   XtSetArg (arg[0], XtNlabel, ">> (N)");
1203   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1204   NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1205                                 navi_area, arg, 2);
1206   XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1207   XtSetArg (arg[0], XtNlabel, ">| (l)");
1208   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1209   LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1210                                 navi_area, arg, 2);
1211   XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1212
1213   XtSetArg (arg[0], XtNleft, XawChainLeft);
1214   XtSetArg (arg[1], XtNright, XawChainLeft);
1215   XtSetArg (arg[2], XtNtop, XawChainTop);
1216   XtSetArg (arg[3], XtNbottom, XawChainTop);
1217
1218   for (i = 0; i < 8; i++)
1219     {
1220       char str[3];
1221       int n = 4;
1222       Widget head;
1223
1224       sprintf (str, "%XX", i);
1225       XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1226       XtSetArg (arg[n], XtNlabel, str), n++;
1227       XtSetArg (arg[n], XtNborderWidth, 0), n++;
1228       if (i > 0)
1229         XtSetArg (arg[n], XtNfromVert, w), n++;
1230       head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1231       index_label[i] = head;
1232       for (j = 0; j < 16; j++)
1233         {
1234           int k = i * 16 + j;
1235
1236           n = 4;
1237           if (i > 0)
1238             XtSetArg (arg[n], XtNfromVert, w), n++;
1239           if (j == 0)
1240             XtSetArg (arg[n], XtNfromHoriz, head), n++;
1241           else
1242             XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1243           XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1244           glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1245                                             glyph_area, arg, n);
1246           XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1247         }
1248       w = head;
1249     }
1250   /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1251   XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1252   XtSetArg (arg[5], XtNfromVert, glyph[112]);
1253   XtSetArg (arg[6], XtNfromHoriz, w);
1254   XtSetArg (arg[7], XtNborderWidth, 0);
1255
1256   for (j = 0; j < 16; j++)
1257     {
1258       char str[3];
1259
1260       sprintf (str, "X%X", j);
1261       XtSetArg (arg[8], XtNlabel, str);
1262       w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1263       XtSetArg (arg[6], XtNfromHoriz, w);
1264     }
1265
1266   XtSetArg (arg[0], XtNleft, XawChainLeft);
1267   XtSetArg (arg[1], XtNright, XawChainLeft);
1268   XtSetArg (arg[2], XtNtop, XawChainTop);
1269   XtSetArg (arg[3], XtNbottom, XawChainTop);
1270   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1271   XtSetArg (arg[5], XtNborderWidth, 0);
1272   w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1273   clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1274   XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1275   del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1276   XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1277   bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1278   XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1279   alt_subst = XtCreateManagedWidget ("AltSubst", toggleWidgetClass, w, arg, 0);
1280   XtAddCallback (alt_subst, XtNcallback, AltSubstProc, NULL);
1281
1282   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1283   XtSetArg (arg[5], XtNborderWidth, 0);
1284   XtSetArg (arg[6], XtNfromVert, w);
1285   raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1286
1287   XtSetArg (arg[0], XtNborderWidth, 0);
1288   XtSetArg (arg[1], XtNlabel, "raw: ");
1289   raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1290                                       raw, arg, 2);
1291   XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1292   raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1293                                       raw, arg, 2);
1294   w = raw;
1295   if (otf)
1296     {
1297       OTF_get_table (otf, "GSUB");
1298       OTF_get_table (otf, "GPOS");
1299       w = create_otf_script_widgets (w);
1300       if (otf->gsub)
1301         {
1302           gsub.label = "GSUB";
1303           gsub.gsub_gpos = otf->gsub;
1304           w = create_otf_widgets (w, &gsub);
1305         }
1306       if (otf->gpos)
1307         {
1308           gpos.label = "GPOS";
1309           gpos.gsub_gpos = otf->gpos;
1310           w = create_otf_widgets (w, &gpos);
1311         }
1312     }
1313
1314   XtSetArg (arg[6], XtNfromVert, w);
1315   seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1316   XtSetArg (arg[0], XtNborderWidth, 0);
1317   XtSetArg (arg[1], XtNlabel, "seq: ");
1318   seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1319                                      seq, arg, 2);
1320   XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1321   seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1322                                      seq, arg, 2);
1323   XtInstallAllAccelerators (shell, shell);
1324 }
1325
1326 static void
1327 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1328 {
1329   XTextProperty text_prop;
1330   char *pname = "otfview";
1331   char *fname = basename (filename);
1332   char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1333
1334   sprintf (name, "%s - %s", pname, fname);
1335   text_prop.value = (unsigned char *) name;
1336   text_prop.encoding = XA_STRING;
1337   text_prop.format = 8;
1338   text_prop.nitems = strlen (name);
1339   XSetWMName (display, XtWindow (shell), &text_prop);
1340 }
1341
1342 /* Format MSG by FMT and print the result to the stderr, and exit.  */
1343
1344 #define FATAL_ERROR(fmt, arg)   \
1345   do {                          \
1346     fprintf (stderr, fmt, arg); \
1347     exit (1);                   \
1348   } while (0)
1349
1350 static int
1351 x_error_handler (Display *display, XErrorEvent *error)
1352 {
1353   return 0;
1354 }
1355
1356 void
1357 help (char **argv, int err)
1358 {
1359   FILE *fp = err ? stderr : stdout;
1360
1361   fprintf (fp, "Usage: %s [ X-OPTION ... ]  OTF-FILE [INDEX]\n",
1362            basename (argv[0]));
1363   fprintf (fp, "  Environment variable PIXEL_SIZE specifies the pixel size.\n");
1364   fprintf (fp, "  The default pixel size is %d, but is reduced\n",
1365            DEFAULT_PIXEL_SIZE);
1366   fprintf (fp, "  if your screen is not that wide.\n");
1367   exit (err);
1368 }
1369
1370 int
1371 main (int argc, char **argv)
1372 {
1373   XtActionsRec actions[] = { {"Expose", ExposeProc} };
1374   Arg arg[10];
1375
1376   FT_Library library;
1377   OTF_GlyphString gstring;
1378   OTF_Glyph *g;
1379
1380   int err;
1381   int i;
1382   int fixed_pixel_size = 0;
1383   int display_width;
1384
1385   pixel_size = DEFAULT_PIXEL_SIZE;
1386   {
1387     char *str = getenv ("PIXEL_SIZE");
1388
1389     if (str && (i = atoi (str)) > 0)
1390       {
1391         pixel_size = i;
1392         fixed_pixel_size = 1;
1393       }
1394   }
1395
1396   gstring.size = gstring.used = 256;
1397   g = calloc (256, sizeof (OTF_Glyph));
1398   gstring.glyphs = g;
1399
1400   shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1401                              shellWidgetClass, arg, 0);
1402   display = XtDisplay (shell);
1403   /*XSynchronize (display, True);*/
1404   XSetErrorHandler (x_error_handler);
1405   display_width = DisplayWidth (display,
1406                                 XScreenNumberOfScreen (XtScreen (shell)));
1407   font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1408   if (! font)
1409     font = XLoadQueryFont (display, "fixed");
1410
1411   if (argc < 2)
1412     help (argv, 1);
1413   if (!strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1414     help (argv, 0);
1415   filename = argv[1];
1416   if (argc > 2)
1417     {
1418       fontindex = atoi (argv[2]);
1419       if (fontindex < 0)
1420         FATAL_ERROR ("Invalid font index: %d\n", fontindex);
1421     }
1422
1423   if ((err = FT_Init_FreeType (&library)))
1424     FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1425   err = FT_New_Face (library, filename, fontindex, &face);
1426   if (err == FT_Err_Unknown_File_Format)
1427     FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1428   else if (err)
1429     FATAL_ERROR ("%s\n", "FT_New_Face: unknown error (invalid face index?)");
1430   if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1431     FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1432
1433   if (strstr (filename, ".ttf")
1434       || strstr (filename, ".TTF")
1435       || strstr (filename, ".otf")
1436       || strstr (filename, ".OTF"))
1437     {
1438       otf = OTF_open_ft_face (face);
1439       if (! otf
1440           || OTF_get_table (otf, "head") < 0
1441           || OTF_get_table (otf, "cmap") < 0
1442           || (OTF_check_table (otf, "GSUB") < 0
1443               && OTF_check_table (otf, "GPOS") < 0))
1444         otf = NULL;
1445     }
1446
1447   {
1448     char title[256];
1449     Arg arg[1];
1450
1451     filename = basename (filename);
1452     sprintf (title, "%s family:%s style:%s",
1453              filename, face->family_name, face->style_name);
1454     XtSetArg (arg[0], XtNtitle, title);
1455     XtSetValues (shell, arg, 1);
1456   }
1457
1458   glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1459                  * pixel_size / face->units_per_EM);
1460   if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1461     {
1462       pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1463       FT_Set_Pixel_Sizes (face, 0, pixel_size);
1464       glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1465                      * pixel_size / face->units_per_EM);
1466     }
1467   if (glyph_width < FONT_WIDTH * 4)
1468     glyph_width = FONT_WIDTH * 4;
1469
1470   glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1471                   *  pixel_size / face->units_per_EM);
1472
1473   glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1474   glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1475   none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1476                                glyph_width, glyph_height, 1);
1477
1478   {
1479     unsigned long valuemask =  GCFunction | GCLineWidth;
1480     XGCValues values;
1481
1482     gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1483     values.function = GXset;
1484     values.line_width = 1;
1485     gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1486     values.function = GXor;
1487     gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1488     values.function = GXcopyInverted;
1489     gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1490   }
1491
1492   XFillRectangle (display, none_pixmap, gc, 0, 0,
1493                   glyph_width, glyph_height);
1494   XDrawString (display, none_pixmap, gc_inv,
1495                (glyph_width - XTextWidth (font, "none", 4)) / 2,
1496                glyph_height / 2, "none", 4);
1497
1498   render_width = (glyph_width + 4) * 15 + 1;
1499   render_height = glyph_height + 2;
1500
1501   charmap_rec[0].platform_id = -1;
1502   charmap_rec[0].encoding_id = -1;
1503   strcpy (charmap_rec[0].name, "no charmap");
1504
1505   for (i = 0; i < face->num_charmaps; i++)
1506     {
1507       charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1508       charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1509       sprintf (charmap_rec[i + 1].name, "%d-%d",
1510                charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1511       if (face->charmaps[i]->platform_id == 0
1512           || (face->charmaps[i]->platform_id == 3
1513               && face->charmaps[i]->encoding_id == 1))
1514         strcat (charmap_rec[i + 1].name, " (unicode)");
1515       else if (face->charmaps[i]->platform_id == 1
1516                && face->charmaps[i]->encoding_id == 0)
1517         strcat (charmap_rec[i + 1].name, " (apple-roman)");
1518     }
1519
1520   raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1521                               render_width, render_height, 1);
1522   seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1523                               render_width, render_height, 1);
1524
1525   memset (bitmap, 0, sizeof (bitmap));
1526   create_widgets ();
1527   glyph_index = 0;
1528   charmap_index = -1;
1529   update_glyph_area ();
1530   update_render_area ();
1531
1532   XtAppAddActions (context, actions, XtNumber (actions));
1533   XtRealizeWidget (shell);
1534   XtAppMainLoop (context);
1535
1536   exit (0);
1537 }
1538
1539 #else /* not HAVE_X11_XAW_COMMAND_H */
1540
1541 int
1542 main (int argc, char **argv)
1543 {
1544   fprintf (stderr, 
1545            "Building of this program failed (lack of some header files)\n");
1546   exit (1);
1547 }
1548
1549 #endif