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