*** 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, g_x, g_y, pix_width, pix_height;
503   int margin = 20 * 300 / 25.4;
504   int a4_width = 210 * 300 / 25.4 - margin * 2;
505   int a4_height = 297 * 300 / 25.4 - margin * 2;
506   int size = 100;
507   Pixmap pixmap;
508   XImage ximage, *image;
509   int i, x, y;
510   char *data;
511   int bytes_per_line;
512
513   FT_Set_Pixel_Sizes (face, 0, size);
514   g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
515   g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
516   pix_width = (g_width + 1) * 16 + margin + 1;
517   pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
518   while (pix_width > a4_width || pix_height > a4_height)
519     {
520       size--;
521       FT_Set_Pixel_Sizes (face, 0, size);
522       g_width = ((face->bbox.xMax - face->bbox.xMin)
523                  * size / face->units_per_EM);
524       g_height = ((face->bbox.yMax - face->bbox.yMin)
525                   * size / face->units_per_EM);
526       pix_width = (g_width + 1) * 16 + margin + 1;
527       pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
528     }
529
530   g_x = - (face->bbox.xMin * size / face->units_per_EM);
531   g_y = face->bbox.yMax * size / face->units_per_EM;
532   for (i = 0; i < 0xFF; i++)
533     {
534       int idx;
535
536       if (charmap_index >= 0)
537         idx = FT_Get_Char_Index (face, (FT_ULong) i);
538       else
539         idx = i;
540       if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
541         {
542           if (g_x < - face->glyph->bitmap_left)
543             g_x = - face->glyph->bitmap_left;
544           if (g_y < face->glyph->bitmap_top)
545             g_y = face->glyph->bitmap_top;
546           if (g_width
547               < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
548             g_width
549               = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
550           if (g_height
551               < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
552             g_height
553               = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
554         }
555     }
556   pix_width = (g_width + 1) * 16 + margin + 1;
557   pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
558   pixmap = XCreatePixmap (display,
559                           RootWindow (display, DefaultScreen (display)),
560                           pix_width, pix_height, 1);
561   XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
562
563   for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
564     XDrawLine (display, pixmap, gc_set, x, margin,
565                x, margin + (g_height + FONT_HEIGHT + 1) * 16);
566   for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
567     XDrawLine (display, pixmap, gc_set, margin, y,
568                margin + (g_width + 1) * 16, y);
569   for (i = 0; i < 256; i++)
570     {
571       char str[5];
572       int idx;
573
574       if (charmap_index >= 0)
575         idx = FT_Get_Char_Index (face, (FT_ULong) i);
576       else
577         idx = i;
578       x = margin + (g_width + 1) * (i % 16);
579       y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
580       if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
581         {
582           ximage.height = face->glyph->bitmap.rows;
583           ximage.width = face->glyph->bitmap.width;
584           ximage.depth = 1;
585           ximage.bits_per_pixel = 1;
586           ximage.xoffset = 0;
587           ximage.format = XYPixmap;
588           ximage.data = (char *) face->glyph->bitmap.buffer;
589           ximage.byte_order = MSBFirst;
590           ximage.bitmap_unit = 8;
591           ximage.bitmap_bit_order = MSBFirst;
592           ximage.bitmap_pad = 8;
593           ximage.bytes_per_line = face->glyph->bitmap.pitch;
594           XInitImage (&ximage);
595           XPutImage (display, pixmap, gc, &ximage, 0, 0,
596                      x + g_x + face->glyph->bitmap_left,
597                      y + g_y - face->glyph->bitmap_top, 
598                      ximage.width, ximage.height);
599         }
600       sprintf (str, "0x%02X", i);
601       XDrawString (display, pixmap, gc_inv,
602                    x + (g_width - XTextWidth (font, str, 4))/ 2,
603                    y + g_height + FONT_ASCENT, str, 4);
604     }
605
606   image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
607                      AllPlanes, XYPixmap);
608   XInitImage (image);
609   {
610     char *name = alloca (strlen (filename) + 5);
611     FILE *fp;
612
613     sprintf (name, "%s.pbm", filename);
614     printf ("Writing %s ...", name);
615     fp = fopen (name, "w");
616     fprintf (fp, "P4\n%d %d\n", image->width, image->height);
617     bytes_per_line = (image->width + 7) / 8;
618     data = image->data;
619     for (y = 0; y < image->height; y++, data += image->bytes_per_line)
620       fwrite (data, 1, bytes_per_line, fp);
621     fclose (fp);
622     printf ("done\n");
623   }
624   FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
625 }
626
627
628 void
629 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
630 {
631   int old_glyph_index = glyph_index;
632
633   if ((int) client_data == -3 && glyph_index > 0)
634     glyph_index = 0;
635   else if ((int) client_data == -2 && glyph_index > 0)
636     glyph_index = (glyph_index - 1) & 0xF000;
637   else if ((int) client_data == -1 && glyph_index > 0)
638     glyph_index -= 0x80;
639   else if ((int) client_data == 1 && glyph_index < 0xFF80)
640     glyph_index += 0x80;
641   else if ((int) client_data == 2 && glyph_index < 0xF000)
642     glyph_index = (glyph_index + 0x1000) & 0xF000;
643   else if ((int) client_data == 3 && glyph_index < 0xF000)
644     glyph_index = 0xFF80;
645   if (glyph_index != old_glyph_index)
646     update_glyph_area ();
647 }
648
649 void
650 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
651 {
652   if (charmap_index == (int) client_data)
653     return;
654   charmap_index = (int) client_data;
655   if (charmap_index >= 0)
656     FT_Set_Charmap (face, face->charmaps[charmap_index]);
657   update_glyph_area ();
658 }
659
660 void
661 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
662 {
663   if ((int) client_data < 0)
664     {
665       if (glyph_rec.n_glyphs > 0)
666         {
667           if ((int) client_data == -2)
668             glyph_rec.n_glyphs--;
669           else
670             glyph_rec.n_glyphs = 0;
671           update_render_area ();
672         }
673     }
674   else if (glyph_rec.n_glyphs < 64)
675     {
676       int index = glyph_index + (int) client_data;
677
678       if (charmap_index >= 0)
679         index = FT_Get_Char_Index (face, (FT_ULong) index);
680       if (bitmap[index].pixmap)
681         {
682           glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
683           glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
684           update_render_area ();
685         }
686     }
687 }
688
689 void
690 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
691 {
692   Arg arg[1];
693
694   reversed = ! reversed;
695   if (reversed)
696     XtSetArg (arg[0], XtNlabel, "L<-R");
697   else
698     XtSetArg (arg[0], XtNlabel, "L->R");
699   XtSetValues (w, arg, 1);
700   update_seq_area ();
701 }
702
703 void
704 AltSubstProc (Widget w, XtPointer client_data, XtPointer call_data)
705 {
706   do_alternate_subst = ! do_alternate_subst;
707   update_seq_area ();
708 }
709
710 void
711 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
712 {
713   FeatureRec *rec = (FeatureRec *) client_data;
714   int idx, i, j;
715   Arg arg[4];
716   char *label;
717
718   if (! rec->langsys)
719     return;
720   XtSetArg (arg[0], XtNlabel, &label);
721   XtGetValues (w, arg, 1);
722   if (! strcmp (label, "all"))
723     idx = -2;
724   else if (! strcmp (label, "none"))
725     idx = -1;
726   else
727     {
728       for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
729         if (rec->features[idx].w == w)
730           break;
731       if (idx == rec->langsys->FeatureCount)
732         idx = -1;
733     }
734   if (idx < 0)
735     {
736       int on = idx == -2;
737
738       for (i = j = 0; j < rec->langsys->FeatureCount; j++)
739         {
740           int index  = rec->langsys->FeatureIndex[j];
741
742           rec->features[j].tag
743             = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
744           rec->features[j].on = on;
745         }
746     }
747   else
748     {
749       OTF_Tag tag = rec->features[idx].tag;
750
751       i = idx;
752       if (rec->features[i].on)
753         {
754           for (j = i + 1;
755                j < rec->langsys->FeatureCount && rec->features[j].on; j++)
756             rec->features[j - 1].tag = rec->features[j].tag;
757           rec->features[j - 1].tag = tag;
758           rec->features[j - 1].on = 0;
759         }
760       else
761         {
762           for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
763             rec->features[i].tag = rec->features[i - 1].tag;
764           rec->features[i].tag = tag;
765           rec->features[i].on = 1;
766         }
767     }
768
769   for (; i < j; i++)
770     {
771       char str[5];
772
773       if (rec->features[i].on)
774         {
775           XtSetArg (arg[0], XtNborderWidth, 3);
776           XtSetArg (arg[1], XtNinternalHeight, 2);
777           XtSetArg (arg[2], XtNinternalWidth, 2);
778         }
779       else
780         {
781           XtSetArg (arg[0], XtNborderWidth, 1);
782           XtSetArg (arg[1], XtNinternalHeight, 4);
783           XtSetArg (arg[2], XtNinternalWidth, 4);
784         }
785       OTF_tag_name (rec->features[i].tag, str);
786       XtSetArg (arg[3], XtNlabel, str);
787       XtSetValues (rec->features[i].w, arg, 4);
788     }
789   update_seq_area ();
790 }
791
792 void
793 setup_feature_rec (FeatureRec *rec)
794 {
795   int i, j;
796   Arg arg[10];
797
798   rec->langsys = NULL;
799   if (! rec->gsub_gpos)
800     return;
801   for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
802     if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
803       {
804         OTF_Script *script = rec->gsub_gpos->ScriptList.Script + i;
805
806         if (langsys_tag)
807           {
808             for (j = 0; j < script->LangSysCount; j++)
809               if (script->LangSysRecord[j].LangSysTag == langsys_tag)
810                 {
811                   rec->langsys = script->LangSys + j;
812                   break;
813                 }
814           }
815         if (! rec->langsys)
816           rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
817         break;
818       }
819
820   if (! rec->langsys)
821     i = 0;
822   else
823     {
824       XtSetArg (arg[0], XtNborderWidth, 1);
825       XtSetArg (arg[1], XtNinternalHeight, 4);
826       XtSetArg (arg[2], XtNinternalWidth, 4);
827       XtSetArg (arg[3], XtNborderColor, foreground);
828       XtSetArg (arg[4], XtNsensitive, True);
829       for (i = 0; i < rec->langsys->FeatureCount; i++)
830         {
831           OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
832           int index = rec->langsys->FeatureIndex[i];
833           char label[5];
834
835           if (! rec->features[i].w)
836             {
837               Widget w = XtCreateManagedWidget ("", commandWidgetClass,
838                                                 rec->parent, arg, 0);
839               XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
840               rec->features[i].w = w;
841             }
842
843           rec->features[i].tag = feature[index].FeatureTag;
844           rec->features[i].on = 0;
845           OTF_tag_name (rec->features[i].tag, label);
846           XtSetArg (arg[5], XtNlabel, label);
847           XtSetValues (rec->features[i].w, arg, 6);
848         }
849     }
850   XtSetArg (arg[0], XtNborderColor, background);
851   XtSetArg (arg[1], XtNsensitive, False);
852   XtSetArg (arg[2], XtNlabel, "    ");
853   for (; i < rec->num_features; i++)
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       XtSetValues (rec->features[i].w, arg, 3);
863     }
864 }
865
866 void
867 compose_script_langsys (OTF_Tag script, OTF_Tag langsys, char *name)
868 {
869   OTF_tag_name (script, name);
870   if (langsys)
871     {
872       name[4] = '(';
873       OTF_tag_name (langsys, name + 5);
874       name[9] = ')';
875       name[10] = '\0';
876     }
877 }
878
879 void
880 decompose_script_langsys (OTF_Tag *script, OTF_Tag *langsys, char *name)
881 {
882   *script = OTF_tag (name);
883   if (name[4])
884     *langsys = OTF_tag (name + 5);
885   else
886     *langsys = 0;
887 }
888
889 void
890 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
891 {
892   char *name;
893   OTF_Tag script, langsys;
894   Arg arg[1];
895
896   XtSetArg (arg[0], XtNlabel, &name);
897   XtGetValues (w, arg, 1);
898   decompose_script_langsys (&script, &langsys, name);
899   if (script_tag == script && langsys_tag == langsys)
900     return;
901   script_tag = script;
902   langsys_tag = langsys;
903   setup_feature_rec (&gsub);
904   setup_feature_rec (&gpos);
905   update_seq_area ();
906 }
907
908 Widget
909 create_otf_script_widgets (Widget prev)
910 {
911   Widget w;
912   Arg arg[10];
913   int n, prev_n, i, j;
914   struct {
915     OTF_Tag script;
916     OTF_Tag langsys;
917   } *script_langsys;
918   char name[11];
919   int nfeatures;
920
921   XtSetArg (arg[0], XtNborderWidth, 0);
922   XtSetArg (arg[1], XtNleft, XawChainLeft);
923   XtSetArg (arg[2], XtNright, XawChainLeft);
924   XtSetArg (arg[3], XtNtop, XawChainTop);
925   XtSetArg (arg[4], XtNbottom, XawChainTop);
926   XtSetArg (arg[5], XtNfromVert, prev);
927   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
928   prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
929   XtCreateManagedWidget ("script(langsys)", labelWidgetClass, prev, arg, 1);
930
931   n = 0;
932   if (otf->gsub)
933     for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
934       n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
935   if (otf->gpos)
936     for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
937       n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
938   script_langsys = alloca ((sizeof script_langsys[0]) * n);
939   n = 0;
940   nfeatures = 0;
941   if (otf->gsub)
942     for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
943       {
944         OTF_Tag tag = otf->gsub->ScriptList.Script[i].ScriptTag;
945
946         script_langsys[n].script = tag;
947         script_langsys[n++].langsys = 0;
948         if (nfeatures
949             < otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount)
950           nfeatures
951             = otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount;
952         for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
953           {
954             script_langsys[n].script = tag;
955             script_langsys[n++].langsys
956               = otf->gsub->ScriptList.Script[i].LangSysRecord[j].LangSysTag;
957             if (nfeatures
958                 < otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount)
959               nfeatures
960                 = otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount;
961           }
962       }
963   gsub.num_features = nfeatures;
964   if (nfeatures > 0)
965     {
966       gsub.num_features = nfeatures;
967       gsub.features = malloc ((sizeof (FeatureElement)) * nfeatures);
968       memset (gsub.features, 0, (sizeof (FeatureElement)) * nfeatures);
969     }
970   prev_n = n;
971   nfeatures = 0;
972   if (otf->gpos)
973     for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
974       {
975         OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
976         int k;
977
978         if (nfeatures
979             < otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount)
980           nfeatures
981             = otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount;
982         for (k = 0; k < prev_n; k++)
983           if (tag == script_langsys[k].script)
984             break;
985         if (k == prev_n)
986           {
987             script_langsys[n].script = tag;
988             script_langsys[n++].langsys = 0;
989           }
990         for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
991           {
992             int l;
993
994             if (k < prev_n)
995               {
996                 OTF_Script *script = otf->gsub->ScriptList.Script + i;
997
998                 for (l = k; l < prev_n && tag == script_langsys[l].script; l++)
999                   if (script->LangSysRecord[j].LangSysTag
1000                       == script_langsys[l].langsys)
1001                     break;
1002               }
1003             else
1004               l = prev_n;
1005             if (l == prev_n)
1006               {
1007                 script_langsys[n].script = tag;
1008                 script_langsys[n++].langsys = 0;
1009               }
1010             if (nfeatures
1011                 < otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount)
1012               nfeatures
1013                 = otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount;
1014           }
1015       }
1016
1017   if (nfeatures > 0)
1018     {
1019       gpos.num_features = nfeatures;
1020       gpos.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1021       memset (gpos.features, 0, (sizeof (FeatureElement)) * nfeatures);
1022     }
1023
1024   if (n == 0)
1025     return prev;
1026
1027   script_tag = script_langsys[0].script;
1028   langsys_tag = script_langsys[0].langsys;
1029   compose_script_langsys (script_tag, langsys_tag, name);
1030
1031   if (n == 1)
1032     {
1033       XtSetArg (arg[0], XtNforeground, background);
1034       XtSetArg (arg[1], XtNbackground, foreground);
1035       XtCreateManagedWidget (name, labelWidgetClass, prev, arg, 2);
1036     }
1037   else
1038     {
1039       XtSetArg (arg[0], XtNstate, True);
1040       w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
1041       XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1042       XtSetArg (arg[0], XtNradioGroup, w);
1043       for (i = 1; i < n; i++)
1044         {
1045           compose_script_langsys (script_langsys[i].script,
1046                                   script_langsys[i].langsys, name);
1047           w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
1048           XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1049         }         
1050     }
1051   return prev;
1052 }
1053
1054
1055 Widget
1056 create_otf_widgets (Widget prev, FeatureRec *rec)
1057 {
1058   Arg arg[10];
1059   Widget w;
1060
1061   XtSetArg (arg[0], XtNborderWidth, 0);
1062   XtSetArg (arg[1], XtNleft, XawChainLeft);
1063   XtSetArg (arg[2], XtNright, XawChainLeft);
1064   XtSetArg (arg[3], XtNtop, XawChainTop);
1065   XtSetArg (arg[4], XtNbottom, XawChainTop);
1066   XtSetArg (arg[5], XtNfromVert, prev);
1067   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1068   prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
1069                                 arg, 7);
1070   XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
1071   XtSetArg (arg[0], XtNborderWidth, 1);
1072   XtSetArg (arg[1], XtNinternalHeight, 4);
1073   XtSetArg (arg[2], XtNinternalWidth, 4);
1074   w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
1075   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1076   w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
1077   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1078
1079   rec->parent = prev;
1080   setup_feature_rec (rec);
1081   return prev;
1082 }
1083
1084 void
1085 create_widgets ()
1086 {
1087   String quit_action = "<KeyPress>q: set() notify() unset()";
1088   String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
1089                          <KeyPress>Home: set() notify() unset()";
1090   String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
1091                          <KeyPress>Up: set() notify() unset()";
1092   String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
1093                          <KeyPress>Left: set() notify() unset()";
1094   String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
1095                          <KeyPress>Right: set() notify() unset()";
1096   String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
1097                          <KeyPress>Down: set() notify() unset()";
1098   String LAST_action = "<KeyPress>l: set() notify() unset()\n\
1099                          <KeyPress>End: set() notify() unset()";
1100   Arg arg[10];
1101   int i, j;
1102   Widget prev, w;
1103   String trans = "<Expose>: Expose()";
1104
1105   XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
1106   frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
1107
1108   XtSetArg (arg[0], XtNleft, XawChainLeft);
1109   XtSetArg (arg[1], XtNright, XawChainLeft);
1110   XtSetArg (arg[2], XtNtop, XawChainTop);
1111   XtSetArg (arg[3], XtNbottom, XawChainTop);
1112   XtSetArg (arg[4], XtNborderWidth, 0);
1113   XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
1114   command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
1115                                         frame, arg, 6);
1116   XtSetArg (arg[6], XtNfromVert, command_area);
1117   navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
1118                                      frame, arg, 7);
1119   XtSetArg (arg[4], XtNborderWidth, 0);
1120   XtSetArg (arg[5], XtNfromVert, navi_area);
1121   XtSetArg (arg[6], XtNdefaultDistance, 0);
1122   glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
1123                                       frame, arg, 7);
1124   XtSetArg (arg[5], XtNfromVert, glyph_area);
1125   render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
1126                                        frame, arg, 6);
1127
1128   XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
1129   quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
1130                                 command_area, arg, 1);
1131   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
1132
1133   dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
1134                                 command_area, arg, 1);
1135   XtAddCallback (dump, XtNcallback, DumpProc, NULL);
1136
1137   XtSetArg (arg[0], XtNborderWidth, 0);
1138   XtSetArg (arg[1], XtNwidth, 10);
1139   XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
1140
1141   charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
1142   XtSetArg (arg[0], XtNstate, True);
1143   charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
1144                                       command_area, arg, 1);
1145   XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1146   XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1147   for (i = 0; i < face->num_charmaps; i++)
1148     {
1149       charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1150                                               toggleWidgetClass,
1151                                               command_area, arg, 1);
1152       XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
1153     }
1154
1155   XtSetArg (arg[0], XtNlabel, " |< (f)");
1156   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1157   FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1158                                  navi_area, arg, 2);
1159   XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1160   XtSetArg (arg[0], XtNlabel, "<< (P)");
1161   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1162   PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1163                                 navi_area, arg, 2);
1164   XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1165   XtSetArg (arg[0], XtNlabel, "< (p)");
1166   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1167   prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1168                                 navi_area, arg, 2);
1169   XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1170   XtSetArg (arg[0], XtNlabel, " 0000 ");
1171   range = XtCreateManagedWidget ("range", labelWidgetClass,
1172                                  navi_area, arg, 1);
1173   XtSetArg (arg[0], XtNforeground, &foreground);
1174   XtSetArg (arg[1], XtNbackground, &background);
1175   XtGetValues (range, arg, 2);
1176
1177   XtSetArg (arg[0], XtNlabel, "> (n)");
1178   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1179   next = XtCreateManagedWidget ("next", commandWidgetClass,
1180                                 navi_area, arg, 2);
1181   XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1182   XtSetArg (arg[0], XtNlabel, ">> (N)");
1183   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1184   NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1185                                 navi_area, arg, 2);
1186   XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1187   XtSetArg (arg[0], XtNlabel, ">| (l)");
1188   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1189   LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1190                                 navi_area, arg, 2);
1191   XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1192
1193   XtSetArg (arg[0], XtNleft, XawChainLeft);
1194   XtSetArg (arg[1], XtNright, XawChainLeft);
1195   XtSetArg (arg[2], XtNtop, XawChainTop);
1196   XtSetArg (arg[3], XtNbottom, XawChainTop);
1197
1198   for (i = 0; i < 8; i++)
1199     {
1200       char str[3];
1201       int n = 4;
1202       Widget head;
1203
1204       sprintf (str, "%XX", i);
1205       XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1206       XtSetArg (arg[n], XtNlabel, str), n++;
1207       XtSetArg (arg[n], XtNborderWidth, 0), n++;
1208       if (i > 0)
1209         XtSetArg (arg[n], XtNfromVert, w), n++;
1210       head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1211       index_label[i] = head;
1212       for (j = 0; j < 16; j++)
1213         {
1214           int k = i * 16 + j;
1215
1216           n = 4;
1217           if (i > 0)
1218             XtSetArg (arg[n], XtNfromVert, w), n++;
1219           if (j == 0)
1220             XtSetArg (arg[n], XtNfromHoriz, head), n++;
1221           else
1222             XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1223           XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1224           glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1225                                             glyph_area, arg, n);
1226           XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1227         }
1228       w = head;
1229     }
1230   /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1231   XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1232   XtSetArg (arg[5], XtNfromVert, glyph[112]);
1233   XtSetArg (arg[6], XtNfromHoriz, w);
1234   XtSetArg (arg[7], XtNborderWidth, 0);
1235
1236   for (j = 0; j < 16; j++)
1237     {
1238       char str[3];
1239
1240       sprintf (str, "X%X", j);
1241       XtSetArg (arg[8], XtNlabel, str);
1242       w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1243       XtSetArg (arg[6], XtNfromHoriz, w);
1244     }
1245
1246   XtSetArg (arg[0], XtNleft, XawChainLeft);
1247   XtSetArg (arg[1], XtNright, XawChainLeft);
1248   XtSetArg (arg[2], XtNtop, XawChainTop);
1249   XtSetArg (arg[3], XtNbottom, XawChainTop);
1250   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1251   XtSetArg (arg[5], XtNborderWidth, 0);
1252   w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1253   clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1254   XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1255   del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1256   XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1257   bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1258   XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1259   alt_subst = XtCreateManagedWidget ("AltSubst", toggleWidgetClass, w, arg, 0);
1260   XtAddCallback (alt_subst, XtNcallback, AltSubstProc, NULL);
1261
1262   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1263   XtSetArg (arg[5], XtNborderWidth, 0);
1264   XtSetArg (arg[6], XtNfromVert, w);
1265   raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1266
1267   XtSetArg (arg[0], XtNborderWidth, 0);
1268   XtSetArg (arg[1], XtNlabel, "raw: ");
1269   raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1270                                       raw, arg, 2);
1271   XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1272   raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1273                                       raw, arg, 2);
1274   w = raw;
1275   if (otf)
1276     {
1277       OTF_get_table (otf, "GSUB");
1278       OTF_get_table (otf, "GPOS");
1279       w = create_otf_script_widgets (w);
1280       if (otf->gsub)
1281         {
1282           gsub.label = "GSUB";
1283           gsub.gsub_gpos = otf->gsub;
1284           w = create_otf_widgets (w, &gsub);
1285         }
1286       if (otf->gpos)
1287         {
1288           gpos.label = "GPOS";
1289           gpos.gsub_gpos = otf->gpos;
1290           w = create_otf_widgets (w, &gpos);
1291         }
1292     }
1293
1294   XtSetArg (arg[6], XtNfromVert, w);
1295   seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1296   XtSetArg (arg[0], XtNborderWidth, 0);
1297   XtSetArg (arg[1], XtNlabel, "seq: ");
1298   seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1299                                      seq, arg, 2);
1300   XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1301   seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1302                                      seq, arg, 2);
1303   XtInstallAllAccelerators (shell, shell);
1304 }
1305
1306 static void
1307 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1308 {
1309   XTextProperty text_prop;
1310   char *pname = "otfview";
1311   char *fname = basename (filename);
1312   char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1313
1314   sprintf (name, "%s - %s", pname, fname);
1315   text_prop.value = (unsigned char *) name;
1316   text_prop.encoding = XA_STRING;
1317   text_prop.format = 8;
1318   text_prop.nitems = strlen (name);
1319   XSetWMName (display, XtWindow (shell), &text_prop);
1320 }
1321
1322 /* Format MSG by FMT and print the result to the stderr, and exit.  */
1323
1324 #define FATAL_ERROR(fmt, arg)   \
1325   do {                          \
1326     fprintf (stderr, fmt, arg); \
1327     exit (1);                   \
1328   } while (0)
1329
1330 static int
1331 x_error_handler (Display *display, XErrorEvent *error)
1332 {
1333   return 0;
1334 }
1335
1336
1337 int
1338 main (int argc, char **argv)
1339 {
1340   XtActionsRec actions[] = { {"Expose", ExposeProc} };
1341   Arg arg[10];
1342
1343   FT_Library library;
1344   OTF_GlyphString gstring;
1345   OTF_Glyph *g;
1346
1347   int err;
1348   int i;
1349   int fixed_pixel_size = 0;
1350   int display_width;
1351
1352   pixel_size = DEFAULT_PIXEL_SIZE;
1353   {
1354     char *str = getenv ("PIXEL_SIZE");
1355
1356     if (str && (i = atoi (str)) > 0)
1357       {
1358         pixel_size = i;
1359         fixed_pixel_size = 1;
1360       }
1361   }
1362
1363   gstring.size = gstring.used = 256;
1364   g = calloc (256, sizeof (OTF_Glyph));
1365   gstring.glyphs = g;
1366
1367   shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1368                              shellWidgetClass, arg, 0);
1369   display = XtDisplay (shell);
1370   /*XSynchronize (display, True);*/
1371   XSetErrorHandler (x_error_handler);
1372   display_width = DisplayWidth (display,
1373                                 XScreenNumberOfScreen (XtScreen (shell)));
1374   font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1375   if (! font)
1376     font = XLoadQueryFont (display, "fixed");
1377
1378   if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1379     {
1380       fprintf (stderr, "Usage: %s [ X-OPTION ... ]  OTF-FILE\n",
1381                basename (argv[0]));
1382       fprintf (stderr,
1383                "  Pixel size is decided by the environment variable PIXEL_SIZE ((default %d).\n", DEFAULT_PIXEL_SIZE);
1384       exit (argc != 2);
1385     }
1386   filename = argv[1];
1387   if (strstr (filename, ".ttf")
1388       || strstr (filename, ".TTF")
1389       || strstr (filename, ".otf")
1390       || strstr (filename, ".OTF"))
1391     {
1392       otf = OTF_open (filename);
1393       if (! otf
1394           || OTF_get_table (otf, "head") < 0
1395           || OTF_get_table (otf, "cmap") < 0
1396           || (OTF_check_table (otf, "GSUB") < 0
1397               && OTF_check_table (otf, "GPOS") < 0))
1398         otf = NULL;
1399     }
1400
1401   if ((err = FT_Init_FreeType (&library)))
1402     FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1403   err = FT_New_Face (library, filename, 0, &face);
1404   if (err == FT_Err_Unknown_File_Format)
1405     FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1406   else if (err)
1407     FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
1408   if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1409     FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1410
1411   {
1412     char title[256];
1413     Arg arg[1];
1414
1415     filename = basename (filename);
1416     sprintf (title, "%s family:%s style:%s",
1417              filename, face->family_name, face->style_name);
1418     XtSetArg (arg[0], XtNtitle, title);
1419     XtSetValues (shell, arg, 1);
1420   }
1421
1422   glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1423                  * pixel_size / face->units_per_EM);
1424   if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1425     {
1426       pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1427       FT_Set_Pixel_Sizes (face, 0, pixel_size);
1428       glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1429                      * pixel_size / face->units_per_EM);
1430     }
1431   if (glyph_width < FONT_WIDTH * 4)
1432     glyph_width = FONT_WIDTH * 4;
1433
1434   glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1435                   *  pixel_size / face->units_per_EM);
1436
1437   glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1438   glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1439   none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1440                                glyph_width, glyph_height, 1);
1441
1442   {
1443     unsigned long valuemask =  GCFunction | GCLineWidth;
1444     XGCValues values;
1445
1446     gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1447     values.function = GXset;
1448     values.line_width = 1;
1449     gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1450     values.function = GXor;
1451     gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1452     values.function = GXcopyInverted;
1453     gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1454   }
1455
1456   XFillRectangle (display, none_pixmap, gc, 0, 0,
1457                   glyph_width, glyph_height);
1458   XDrawString (display, none_pixmap, gc_inv,
1459                (glyph_width - XTextWidth (font, "none", 4)) / 2,
1460                glyph_height / 2, "none", 4);
1461
1462   render_width = (glyph_width + 4) * 15 + 1;
1463   render_height = glyph_height + 2;
1464
1465   charmap_rec[0].platform_id = -1;
1466   charmap_rec[0].encoding_id = -1;
1467   strcpy (charmap_rec[0].name, "no charmap");
1468
1469   for (i = 0; i < face->num_charmaps; i++)
1470     {
1471       charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1472       charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1473       sprintf (charmap_rec[i + 1].name, "%d-%d",
1474                charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1475       if (face->charmaps[i]->platform_id == 0
1476           || (face->charmaps[i]->platform_id == 3
1477               && face->charmaps[i]->encoding_id == 1))
1478         strcat (charmap_rec[i + 1].name, " (unicode)");
1479       else if (face->charmaps[i]->platform_id == 1
1480                && face->charmaps[i]->encoding_id == 0)
1481         strcat (charmap_rec[i + 1].name, " (apple-roman)");
1482     }
1483
1484   raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1485                               render_width, render_height, 1);
1486   seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1487                               render_width, render_height, 1);
1488
1489   memset (bitmap, 0, sizeof (bitmap));
1490   create_widgets ();
1491   glyph_index = 0;
1492   charmap_index = -1;
1493   update_glyph_area ();
1494   update_render_area ();
1495
1496   XtAppAddActions (context, actions, XtNumber (actions));
1497   XtRealizeWidget (shell);
1498   XtAppMainLoop (context);
1499
1500   exit (0);
1501 }
1502
1503 #else /* not HAVE_X11_XAW_COMMAND_H */
1504
1505 int
1506 main (int argc, char **argv)
1507 {
1508   fprintf (stderr, 
1509            "Building of this program failed (lack of some header files)\n");
1510   exit (1);
1511 }
1512
1513 #endif