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