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