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