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