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