662d0b8ba34c7d1147dbba7ea82ef053d980d532
[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                            | |
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, 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 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 *prev, int *x, int *y)
266 {
267   if (anchor->AnchorFormat == 2 && prev)
268     {
269       FT_Outline *outline;
270       int ap = anchor->f.f1.AnchorPoint;
271
272       FT_Load_Glyph (ft_face, (FT_UInt) prev->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;
293   int prev_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 = alloca (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   if (otf)
306     {
307       char *str;
308
309       if (otf->gsub)
310         {
311           str = get_features (&otf->gsub->FeatureList, &gsub);
312           if (str)
313             {
314               OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
315               free (str);
316             }
317         }
318       if (otf->gpos)
319         {
320           str = get_features (&otf->gpos->FeatureList, &gpos);
321           if (str)
322             {
323               OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
324               free (str);
325             }
326         }
327     }
328
329   prev = NULL;
330   for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
331        i < gstring.used; i++, prev = g++)
332     {
333       BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
334       int xoff = 0, yoff = 0;
335
336       switch (g->positioning_type)
337         {
338         case 0:
339           break;
340
341         case 1: case 2:
342           {
343             int format = g->f.f1.format;
344
345             if (format & OTF_XPlacement)
346               xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
347             if (format & OTF_XPlaDevice)
348               xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
349             if (format & OTF_YPlacement)
350               yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
351             if (format & OTF_YPlaDevice)
352               yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
353           }
354         break;
355       case 3:
356         /* Not yet supported.  */
357         break;
358       case 4:
359         {
360           int base_x, base_y, mark_x, mark_y;
361
362           base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
363           base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
364           mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
365           mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
366
367           if (g->f.f4.base_anchor->AnchorFormat != 1)
368             adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
369           if (g->f.f4.mark_anchor->AnchorFormat != 1)
370             adjust_anchor (g->f.f4.mark_anchor, face, prev, &mark_x, &mark_y);
371           xoff = (base_x - prev_width) - mark_x;
372           yoff = base_y - mark_y;
373         }
374         break;
375       case 5:
376         /* Not yet supported.  */
377         break;
378       default:          /* i.e case 6 */
379         /* Not yet supported.  */
380         break;
381       }
382           
383       XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
384                  glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
385                  x + bmp->x + xoff, glyph_y + bmp->y + yoff);
386       x += prev_width = bmp->advance;
387     }
388   XtSetArg (arg[0], XtNbitmap, seq_pixmap);
389   XtSetValues (seq_image, arg, 1);
390 }
391
392
393 void
394 update_render_area ()
395 {
396   int i;
397   int x;
398   Arg arg[1];
399
400   XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
401   for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
402     {
403       BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
404       char buf[5];
405
406       XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
407                  0, 0, glyph_width, glyph_height,
408                  (glyph_width + 4) * i + 1, 1);
409       XDrawRectangle (display, raw_pixmap, gc_set,
410                       (glyph_width + 4) * i, 0,
411                       glyph_width + 1, glyph_height + 1);
412       XDrawLine (display, raw_pixmap, gc_set,
413                  (glyph_width + 4) * i + 1 + glyph_x, 1,
414                  (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
415       XDrawLine (display, raw_pixmap, gc_set,
416                  (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
417                  (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
418                  glyph_height + 1);
419
420       sprintf (buf, "%04X", glyph_rec.codes[i]);
421       XDrawString (display, raw_pixmap, gc_inv, 
422                    (glyph_width + 1) * i + 1
423                    + (glyph_width - XTextWidth (font, buf, 4)) / 2,
424                    glyph_height + 2 + FONT_HEIGHT, buf, 4);
425     }
426   XtSetArg (arg[0], XtNbitmap, raw_pixmap);
427   XtSetValues (raw_image, arg, 1);
428   update_seq_area ();
429 }
430
431 void
432 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
433 {
434   XtAppSetExitFlag (XtWidgetToApplicationContext (w));
435 }
436
437 void
438 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
439 {
440   int g_width, g_height, g_x, g_y, pix_width, pix_height;
441   int margin = 20 * 300 / 25.4;
442   int a4_width = 210 * 300 / 25.4 - margin * 2;
443   int a4_height = 297 * 300 / 25.4 - margin * 2;
444   int size = 100;
445   Pixmap pixmap;
446   XImage ximage, *image;
447   int i, x, y;
448   char *data;
449   int bytes_per_line;
450
451   FT_Set_Pixel_Sizes (face, 0, size);
452   g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
453   g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
454   pix_width = (g_width + 1) * 16 + margin + 1;
455   pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
456   while (pix_width > a4_width || pix_height > a4_height)
457     {
458       size--;
459       FT_Set_Pixel_Sizes (face, 0, size);
460       g_width = ((face->bbox.xMax - face->bbox.xMin)
461                  * size / face->units_per_EM);
462       g_height = ((face->bbox.yMax - face->bbox.yMin)
463                   * size / face->units_per_EM);
464       pix_width = (g_width + 1) * 16 + margin + 1;
465       pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
466     }
467
468   g_x = - (face->bbox.xMin * size / face->units_per_EM);
469   g_y = face->bbox.yMax * size / face->units_per_EM;
470   for (i = 0; i < 0xFF; i++)
471     {
472       int idx;
473
474       if (charmap_index >= 0)
475         idx = FT_Get_Char_Index (face, (FT_ULong) i);
476       else
477         idx = i;
478       if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
479         {
480           if (g_x < - face->glyph->bitmap_left)
481             g_x = - face->glyph->bitmap_left;
482           if (g_y < face->glyph->bitmap_top)
483             g_y = face->glyph->bitmap_top;
484           if (g_width
485               < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
486             g_width
487               = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
488           if (g_height
489               < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
490             g_height
491               = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
492         }
493     }
494   pix_width = (g_width + 1) * 16 + margin + 1;
495   pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
496   pixmap = XCreatePixmap (display,
497                           RootWindow (display, DefaultScreen (display)),
498                           pix_width, pix_height, 1);
499   XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
500
501   for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
502     XDrawLine (display, pixmap, gc_set, x, margin,
503                x, margin + (g_height + FONT_HEIGHT + 1) * 16);
504   for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
505     XDrawLine (display, pixmap, gc_set, margin, y,
506                margin + (g_width + 1) * 16, y);
507   for (i = 0; i < 256; i++)
508     {
509       char str[5];
510       int idx;
511
512       if (charmap_index >= 0)
513         idx = FT_Get_Char_Index (face, (FT_ULong) i);
514       else
515         idx = i;
516       x = margin + (g_width + 1) * (i % 16);
517       y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
518       if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
519         {
520           ximage.height = face->glyph->bitmap.rows;
521           ximage.width = face->glyph->bitmap.width;
522           ximage.depth = 1;
523           ximage.bits_per_pixel = 1;
524           ximage.xoffset = 0;
525           ximage.format = XYPixmap;
526           ximage.data = (char *) face->glyph->bitmap.buffer;
527           ximage.byte_order = MSBFirst;
528           ximage.bitmap_unit = 8;
529           ximage.bitmap_bit_order = MSBFirst;
530           ximage.bitmap_pad = 8;
531           ximage.bytes_per_line = face->glyph->bitmap.pitch;
532           XInitImage (&ximage);
533           XPutImage (display, pixmap, gc, &ximage, 0, 0,
534                      x + g_x + face->glyph->bitmap_left,
535                      y + g_y - face->glyph->bitmap_top, 
536                      ximage.width, ximage.height);
537         }
538       sprintf (str, "0x%02X", i);
539       XDrawString (display, pixmap, gc_inv,
540                    x + (g_width - XTextWidth (font, str, 4))/ 2,
541                    y + g_height + FONT_ASCENT, str, 4);
542     }
543
544   image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
545                      AllPlanes, XYPixmap);
546   XInitImage (image);
547   {
548     char *name = alloca (strlen (filename) + 5);
549     FILE *fp;
550
551     sprintf (name, "%s.pbm", filename);
552     printf ("Writing %s ...", name);
553     fp = fopen (name, "w");
554     fprintf (fp, "P4\n%d %d\n", image->width, image->height);
555     bytes_per_line = (image->width + 7) / 8;
556     data = image->data;
557     for (y = 0; y < image->height; y++, data += image->bytes_per_line)
558       fwrite (data, 1, bytes_per_line, fp);
559     fclose (fp);
560     printf ("done\n");
561   }
562   FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
563 }
564
565
566 void
567 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
568 {
569   int old_glyph_index = glyph_index;
570
571   if ((int) client_data == -3 && glyph_index > 0)
572     glyph_index = 0;
573   else if ((int) client_data == -2 && glyph_index > 0)
574     glyph_index = (glyph_index - 1) & 0xF000;
575   else if ((int) client_data == -1 && glyph_index > 0)
576     glyph_index -= 0x80;
577   else if ((int) client_data == 1 && glyph_index < 0xFF80)
578     glyph_index += 0x80;
579   else if ((int) client_data == 2 && glyph_index < 0xF000)
580     glyph_index = (glyph_index + 0x1000) & 0xF000;
581   else if ((int) client_data == 3 && glyph_index < 0xF000)
582     glyph_index = 0xFF80;
583   if (glyph_index != old_glyph_index)
584     update_glyph_area ();
585 }
586
587 void
588 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
589 {
590   if (charmap_index == (int) client_data)
591     return;
592   charmap_index = (int) client_data;
593   if (charmap_index >= 0)
594     FT_Set_Charmap (face, face->charmaps[charmap_index]);
595   update_glyph_area ();
596 }
597
598 void
599 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
600 {
601   if ((int) client_data < 0)
602     {
603       if (glyph_rec.n_glyphs > 0)
604         {
605           if ((int) client_data == -2)
606             glyph_rec.n_glyphs--;
607           else
608             glyph_rec.n_glyphs = 0;
609           update_render_area ();
610         }
611     }
612   else if (glyph_rec.n_glyphs < 64)
613     {
614       int index = glyph_index + (int) client_data;
615
616       if (charmap_index >= 0)
617         index = FT_Get_Char_Index (face, (FT_ULong) index);
618       if (bitmap[index].pixmap)
619         {
620           glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
621           glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
622           update_render_area ();
623         }
624     }
625 }
626
627 void
628 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
629 {
630   FeatureRec *rec = (FeatureRec *) client_data;
631   int idx, i, j;
632   Arg arg[3];
633   char *label;
634
635   if (! rec->langsys)
636     return;
637   XtSetArg (arg[0], XtNlabel, &label);
638   XtGetValues (w, arg, 1);
639   if (! strcmp (label, "all"))
640     idx = -2;
641   else if (! strcmp (label, "none"))
642     idx = -1;
643   else
644     {
645       for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
646         if (rec->features[idx].w == w)
647           break;
648       if (idx == rec->langsys->FeatureCount)
649         idx = -1;
650     }
651   if (idx < 0)
652     {
653       int on = idx == -2;
654
655       for (i = j = 0; j < rec->langsys->FeatureCount; j++)
656         {
657           int index  = rec->langsys->FeatureIndex[j];
658
659           rec->features[j].tag
660             = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
661           rec->features[j].on = on;
662         }
663     }
664   else
665     {
666       OTF_Tag tag = rec->features[idx].tag;
667
668       i = idx;
669       if (rec->features[i].on)
670         {
671           for (j = i + 1;
672                j < rec->langsys->FeatureCount && rec->features[j].on; j++)
673             rec->features[j - 1].tag = rec->features[j].tag;
674           rec->features[j - 1].tag = tag;
675           rec->features[j - 1].on = 0;
676         }
677       else
678         {
679           for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
680             rec->features[i].tag = rec->features[i - 1].tag;
681           rec->features[i].tag = tag;
682           rec->features[i].on = 1;
683         }
684     }
685
686   for (; i < j; i++)
687     {
688       char str[5];
689       unsigned fore = foreground, back = background;
690
691 #if 0
692       if (i == idx)
693         fore = background, back = foreground;
694 #endif
695       if (rec->features[i].on)
696         {
697           XtSetArg (arg[0], XtNforeground, back);
698           XtSetArg (arg[1], XtNbackground, fore);
699         }
700       else
701         {
702           XtSetArg (arg[0], XtNforeground, fore);
703           XtSetArg (arg[1], XtNbackground, back);
704         }
705       OTF_tag_name (rec->features[i].tag, str);
706       XtSetArg (arg[2], XtNlabel, str);
707       XtSetValues (rec->features[i].w, arg, 3);
708     }
709   update_seq_area ();
710 }
711
712 void
713 setup_feature_rec (FeatureRec *rec)
714 {
715   int i;
716   Arg arg[10];
717
718   rec->langsys = NULL;
719   for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
720     if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
721       {
722         rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
723         break;
724       }
725
726   if (! rec->langsys)
727     i = 0;
728   else
729     {
730       XtSetArg (arg[0], XtNborderWidth, 1);
731       XtSetArg (arg[1], XtNborderColor, foreground);
732       XtSetArg (arg[2], XtNsensitive, True);
733       XtSetArg (arg[3], XtNforeground, foreground);
734       XtSetArg (arg[4], XtNbackground, background);
735       for (i = 0; i < rec->langsys->FeatureCount && i < MAX_FEATURE_COUNT; i++)
736         {
737           OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
738           int index = rec->langsys->FeatureIndex[i];
739           char label[5];
740
741           rec->features[i].tag = feature[index].FeatureTag;
742           rec->features[i].on = 0;
743           OTF_tag_name (rec->features[i].tag, label);
744           XtSetArg (arg[5], XtNlabel, label);
745           XtSetValues (rec->features[i].w, arg, 6);
746         }
747     }
748   XtSetArg (arg[0], XtNborderWidth, 1);
749   XtSetArg (arg[1], XtNborderColor, background);
750   XtSetArg (arg[2], XtNsensitive, False);
751   XtSetArg (arg[3], XtNforeground, foreground);
752   XtSetArg (arg[4], XtNbackground, background);
753   XtSetArg (arg[5], XtNlabel, "    ");
754   for (; i < MAX_FEATURE_COUNT; i++)
755     XtSetValues (rec->features[i].w, arg, 6);
756 }
757
758 void
759 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
760 {
761   if (script_tag == (OTF_Tag) client_data)
762     return;
763   script_tag = (OTF_Tag) client_data;
764   setup_feature_rec (&gsub);
765   setup_feature_rec (&gpos);
766   update_seq_area ();
767 }
768
769 Widget
770 create_otf_script_widgets (Widget prev)
771 {
772   Widget w;
773   Arg arg[10];
774   int n, i;
775   OTF_Tag *scripts;
776   char script_name[5];
777
778   XtSetArg (arg[0], XtNborderWidth, 0);
779   XtSetArg (arg[1], XtNleft, XawChainLeft);
780   XtSetArg (arg[2], XtNright, XawChainLeft);
781   XtSetArg (arg[3], XtNtop, XawChainTop);
782   XtSetArg (arg[4], XtNbottom, XawChainTop);
783   XtSetArg (arg[5], XtNfromVert, prev);
784   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
785   prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
786   XtCreateManagedWidget ("script", labelWidgetClass, prev, arg, 1);
787
788   n = 0;
789   if (otf->gsub)
790     n = otf->gsub->ScriptList.ScriptCount;
791   if (otf->gpos)
792     n += otf->gpos->ScriptList.ScriptCount;
793   scripts = alloca (sizeof (OTF_Tag) * n);
794   i = 0;
795   if (otf->gsub)
796     for (; i < otf->gsub->ScriptList.ScriptCount; i++)
797       scripts[i] = otf->gsub->ScriptList.Script[i].ScriptTag;
798   n = i;
799   if (otf->gpos)
800     for (; i < otf->gpos->ScriptList.ScriptCount; i++)
801       {
802         OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
803         int j;
804
805         for (j = 0; j < i; j++)
806           if (tag == scripts[j])
807             break;
808         if (j == i)
809           scripts[n++] = tag;
810       }
811
812   if (n == 0)
813     return prev;
814
815   script_tag = scripts[0];
816   OTF_tag_name (scripts[0], script_name);
817   if (n == 1)
818     {
819       XtSetArg (arg[0], XtNforeground, background);
820       XtSetArg (arg[1], XtNbackground, foreground);
821       XtCreateManagedWidget (script_name, labelWidgetClass, prev, arg, 2);
822     }
823   else
824     {
825       char name[5];
826
827       XtSetArg (arg[0], XtNstate, True);
828       w = XtCreateManagedWidget (script_name, toggleWidgetClass, prev, arg, 1);
829       XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[0]);
830       XtSetArg (arg[0], XtNradioGroup, w);
831       for (i = 1; i < n; i++)
832         {
833           OTF_tag_name (scripts[i], name);
834           w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
835           XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[i]);
836         }         
837     }
838   return prev;
839 }
840
841
842 Widget
843 create_otf_widgets (Widget prev, FeatureRec *rec)
844 {
845   Arg arg[10];
846   Widget w;
847   int i;
848
849   XtSetArg (arg[0], XtNborderWidth, 0);
850   XtSetArg (arg[1], XtNleft, XawChainLeft);
851   XtSetArg (arg[2], XtNright, XawChainLeft);
852   XtSetArg (arg[3], XtNtop, XawChainTop);
853   XtSetArg (arg[4], XtNbottom, XawChainTop);
854   XtSetArg (arg[5], XtNfromVert, prev);
855   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
856   prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
857                                 arg, 7);
858   XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
859   w = XtCreateManagedWidget ("all", commandWidgetClass, prev, NULL, 0);
860   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
861   w = XtCreateManagedWidget ("none", commandWidgetClass, prev, NULL, 0);
862   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
863
864   for (i = 0; i < MAX_FEATURE_COUNT; i++)
865     {
866       w = XtCreateManagedWidget ("", commandWidgetClass, prev, arg, 1);
867       XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
868       rec->features[i].w = w;
869     }
870
871   setup_feature_rec (rec);
872   return prev;
873 }
874
875 void
876 create_widgets ()
877 {
878   String quit_action = "<KeyPress>q: set() notify() unset()";
879   String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
880                          <KeyPress>Home: set() notify() unset()";
881   String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
882                          <KeyPress>Up: set() notify() unset()";
883   String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
884                          <KeyPress>Left: set() notify() unset()";
885   String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
886                          <KeyPress>Right: set() notify() unset()";
887   String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
888                          <KeyPress>Down: set() notify() unset()";
889   String LAST_action = "<KeyPress>l: set() notify() unset()\n\
890                          <KeyPress>End: set() notify() unset()";
891   Arg arg[10];
892   int i, j;
893   Widget prev, w;
894   String trans = "<Expose>: Expose()";
895
896   XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
897   frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
898
899   XtSetArg (arg[0], XtNleft, XawChainLeft);
900   XtSetArg (arg[1], XtNright, XawChainLeft);
901   XtSetArg (arg[2], XtNtop, XawChainTop);
902   XtSetArg (arg[3], XtNbottom, XawChainTop);
903   XtSetArg (arg[4], XtNborderWidth, 0);
904   XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
905   command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
906                                         frame, arg, 6);
907   XtSetArg (arg[6], XtNfromVert, command_area);
908   navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
909                                      frame, arg, 7);
910   XtSetArg (arg[4], XtNborderWidth, 0);
911   XtSetArg (arg[5], XtNfromVert, navi_area);
912   XtSetArg (arg[6], XtNdefaultDistance, 0);
913   glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
914                                       frame, arg, 7);
915   XtSetArg (arg[5], XtNfromVert, glyph_area);
916   render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
917                                        frame, arg, 6);
918
919   XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
920   quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
921                                 command_area, arg, 1);
922   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
923
924   dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
925                                 command_area, arg, 1);
926   XtAddCallback (dump, XtNcallback, DumpProc, NULL);
927
928   XtSetArg (arg[0], XtNborderWidth, 0);
929   XtSetArg (arg[1], XtNwidth, 10);
930   XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
931
932   charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
933   XtSetArg (arg[0], XtNstate, True);
934   charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
935                                       command_area, arg, 1);
936   XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
937   XtSetArg (arg[0], XtNradioGroup, charmap[0]);
938   for (i = 0; i < face->num_charmaps; i++)
939     {
940       charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
941                                               toggleWidgetClass,
942                                               command_area, arg, 1);
943       XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
944     }
945
946   XtSetArg (arg[0], XtNlabel, " |< (f)");
947   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
948   FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
949                                  navi_area, arg, 2);
950   XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
951   XtSetArg (arg[0], XtNlabel, "<< (P)");
952   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
953   PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
954                                 navi_area, arg, 2);
955   XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
956   XtSetArg (arg[0], XtNlabel, "< (p)");
957   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
958   prev = XtCreateManagedWidget ("prev", commandWidgetClass,
959                                 navi_area, arg, 2);
960   XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
961   XtSetArg (arg[0], XtNlabel, " 0000 ");
962   range = XtCreateManagedWidget ("range", labelWidgetClass,
963                                  navi_area, arg, 1);
964   XtSetArg (arg[0], XtNforeground, &foreground);
965   XtSetArg (arg[1], XtNbackground, &background);
966   XtGetValues (range, arg, 2);
967
968   XtSetArg (arg[0], XtNlabel, "> (n)");
969   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
970   next = XtCreateManagedWidget ("next", commandWidgetClass,
971                                 navi_area, arg, 2);
972   XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
973   XtSetArg (arg[0], XtNlabel, ">> (N)");
974   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
975   NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
976                                 navi_area, arg, 2);
977   XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
978   XtSetArg (arg[0], XtNlabel, ">| (l)");
979   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
980   LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
981                                 navi_area, arg, 2);
982   XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
983
984   XtSetArg (arg[0], XtNleft, XawChainLeft);
985   XtSetArg (arg[1], XtNright, XawChainLeft);
986   XtSetArg (arg[2], XtNtop, XawChainTop);
987   XtSetArg (arg[3], XtNbottom, XawChainTop);
988
989   for (i = 0; i < 8; i++)
990     {
991       char str[3];
992       int n = 4;
993       Widget head;
994
995       sprintf (str, "%XX", i);
996       XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
997       XtSetArg (arg[n], XtNlabel, str), n++;
998       XtSetArg (arg[n], XtNborderWidth, 0), n++;
999       if (i > 0)
1000         XtSetArg (arg[n], XtNfromVert, w), n++;
1001       head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1002       index_label[i] = head;
1003       for (j = 0; j < 16; j++)
1004         {
1005           int k = i * 16 + j;
1006
1007           n = 4;
1008           if (i > 0)
1009             XtSetArg (arg[n], XtNfromVert, w), n++;
1010           if (j == 0)
1011             XtSetArg (arg[n], XtNfromHoriz, head), n++;
1012           else
1013             XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1014           XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1015           glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1016                                             glyph_area, arg, n);
1017           XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1018         }
1019       w = head;
1020     }
1021   /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1022   XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1023   XtSetArg (arg[5], XtNfromVert, glyph[112]);
1024   XtSetArg (arg[6], XtNfromHoriz, w);
1025   XtSetArg (arg[7], XtNborderWidth, 0);
1026
1027   for (j = 0; j < 16; j++)
1028     {
1029       char str[3];
1030
1031       sprintf (str, "X%X", j);
1032       XtSetArg (arg[8], XtNlabel, str);
1033       w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1034       XtSetArg (arg[6], XtNfromHoriz, w);
1035     }
1036
1037   XtSetArg (arg[0], XtNleft, XawChainLeft);
1038   XtSetArg (arg[1], XtNright, XawChainLeft);
1039   XtSetArg (arg[2], XtNtop, XawChainTop);
1040   XtSetArg (arg[3], XtNbottom, XawChainTop);
1041   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1042   XtSetArg (arg[5], XtNborderWidth, 0);
1043   w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1044   clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1045   XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1046   del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1047   XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1048
1049   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1050   XtSetArg (arg[5], XtNborderWidth, 0);
1051   XtSetArg (arg[6], XtNfromVert, w);
1052   raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1053
1054   XtSetArg (arg[0], XtNborderWidth, 0);
1055   XtSetArg (arg[1], XtNlabel, "raw: ");
1056   raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1057                                       raw, arg, 2);
1058   XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1059   raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1060                                       raw, arg, 2);
1061   w = raw;
1062   if (otf)
1063     {
1064       OTF_get_table (otf, "GSUB");
1065       OTF_get_table (otf, "GPOS");
1066       w = create_otf_script_widgets (w);
1067       if (otf->gsub)
1068         {
1069           gsub.label = "GSUB";
1070           gsub.gsub_gpos = otf->gsub;
1071           w = create_otf_widgets (w, &gsub);
1072         }
1073       if (otf->gpos)
1074         {
1075           gpos.label = "GPOS";
1076           gpos.gsub_gpos = otf->gpos;
1077           w = create_otf_widgets (w, &gpos);
1078         }
1079     }
1080
1081   XtSetArg (arg[6], XtNfromVert, w);
1082   seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1083   XtSetArg (arg[0], XtNborderWidth, 0);
1084   XtSetArg (arg[1], XtNlabel, "seq: ");
1085   seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1086                                      seq, arg, 2);
1087   XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1088   seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1089                                      seq, arg, 2);
1090   XtInstallAllAccelerators (shell, shell);
1091 }
1092
1093 static void
1094 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1095 {
1096   XTextProperty text_prop;
1097   char *pname = "otfview";
1098   char *fname = basename (filename);
1099   char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1100
1101   sprintf (name, "%s - %s", pname, fname);
1102   text_prop.value = (unsigned char *) name;
1103   text_prop.encoding = XA_STRING;
1104   text_prop.format = 8;
1105   text_prop.nitems = strlen (name);
1106   XSetWMName (display, XtWindow (shell), &text_prop);
1107 }
1108
1109 /* Format MSG by FMT and print the result to the stderr, and exit.  */
1110
1111 #define FATAL_ERROR(fmt, arg)   \
1112   do {                          \
1113     fprintf (stderr, fmt, arg); \
1114     exit (1);                   \
1115   } while (0)
1116
1117 static int
1118 x_error_handler (Display *display, XErrorEvent *error)
1119 {
1120   return 0;
1121 }
1122
1123
1124 int
1125 main (int argc, char **argv)
1126 {
1127   XtActionsRec actions[] = { {"Expose", ExposeProc} };
1128   Arg arg[10];
1129
1130   FT_Library library;
1131   OTF_GlyphString gstring;
1132   OTF_Glyph *g;
1133
1134   int err;
1135   int i;
1136   int fixed_pixel_size = 0;
1137   int display_width;
1138
1139   pixel_size = DEFAULT_PIXEL_SIZE;
1140   {
1141     char *str = getenv ("PIXEL_SIZE");
1142
1143     if (str && (i = atoi (str)) > 0)
1144       {
1145         pixel_size = i;
1146         fixed_pixel_size = 1;
1147       }
1148   }
1149
1150   gstring.size = gstring.used = 256;
1151   g = calloc (256, sizeof (OTF_Glyph));
1152   gstring.glyphs = g;
1153
1154   shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1155                              shellWidgetClass, arg, 0);
1156   display = XtDisplay (shell);
1157   /*XSynchronize (display, True);*/
1158   XSetErrorHandler (x_error_handler);
1159   display_width = DisplayWidth (display,
1160                                 XScreenNumberOfScreen (XtScreen (shell)));
1161   font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1162   if (! font)
1163     font = XLoadQueryFont (display, "fixed");
1164
1165   if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1166     {
1167       fprintf (stderr, "Usage: %s [ X-OPTION ... ]  OTF-FILE\n",
1168                basename (argv[0]));
1169       exit (argc != 2);
1170     }
1171   filename = argv[1];
1172   if (strstr (filename, ".ttf")
1173       || strstr (filename, ".TTF")
1174       || strstr (filename, ".otf")
1175       || strstr (filename, ".OTF"))
1176     {
1177       otf = OTF_open (filename);
1178       if (! otf
1179           || OTF_get_table (otf, "head") < 0
1180           || OTF_get_table (otf, "cmap") < 0
1181           || (OTF_check_table (otf, "GSUB") < 0
1182               && OTF_check_table (otf, "GPOS") < 0))
1183         otf = NULL;
1184     }
1185
1186   if ((err = FT_Init_FreeType (&library)))
1187     FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1188   err = FT_New_Face (library, filename, 0, &face);
1189   if (err == FT_Err_Unknown_File_Format)
1190     FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1191   else if (err)
1192     FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
1193   if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1194     FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1195
1196   {
1197     char title[256];
1198     Arg arg[1];
1199
1200     filename = basename (filename);
1201     sprintf (title, "%s family:%s style:%s",
1202              filename, face->family_name, face->style_name);
1203     XtSetArg (arg[0], XtNtitle, title);
1204     XtSetValues (shell, arg, 1);
1205   }
1206
1207   glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1208                  * pixel_size / face->units_per_EM);
1209   if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1210     {
1211       pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1212       FT_Set_Pixel_Sizes (face, 0, pixel_size);
1213       glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1214                      * pixel_size / face->units_per_EM);
1215     }
1216   if (glyph_width < FONT_WIDTH * 4)
1217     glyph_width = FONT_WIDTH * 4;
1218
1219   glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1220                   *  pixel_size / face->units_per_EM);
1221
1222   glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1223   glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1224   none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1225                                glyph_width, glyph_height, 1);
1226
1227   {
1228     unsigned long valuemask =  GCFunction | GCLineWidth;
1229     XGCValues values;
1230
1231     gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1232     values.function = GXset;
1233     values.line_width = 1;
1234     gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1235     values.function = GXor;
1236     gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1237     values.function = GXcopyInverted;
1238     gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1239   }
1240
1241   XFillRectangle (display, none_pixmap, gc, 0, 0,
1242                   glyph_width, glyph_height);
1243   XDrawString (display, none_pixmap, gc_inv,
1244                (glyph_width - XTextWidth (font, "none", 4)) / 2,
1245                glyph_height / 2, "none", 4);
1246
1247   render_width = (glyph_width + 4) * 15 + 1;
1248   render_height = glyph_height + 2;
1249
1250   charmap_rec[0].platform_id = -1;
1251   charmap_rec[0].encoding_id = -1;
1252   strcpy (charmap_rec[0].name, "no charmap");
1253
1254   for (i = 0; i < face->num_charmaps; i++)
1255     {
1256       charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1257       charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1258       sprintf (charmap_rec[i + 1].name, "%d-%d",
1259                charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1260       if (face->charmaps[i]->platform_id == 0
1261           || (face->charmaps[i]->platform_id == 3
1262               && face->charmaps[i]->encoding_id == 1))
1263         strcat (charmap_rec[i + 1].name, " (unicode)");
1264       else if (face->charmaps[i]->platform_id == 1
1265                && face->charmaps[i]->encoding_id == 0)
1266         strcat (charmap_rec[i + 1].name, " (apple-roman)");
1267     }
1268
1269   raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1270                               render_width, render_height, 1);
1271   seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1272                               render_width, render_height, 1);
1273
1274   memset (bitmap, 0, sizeof (bitmap));
1275   create_widgets ();
1276   glyph_index = 0;
1277   charmap_index = -1;
1278   update_glyph_area ();
1279   update_render_area ();
1280
1281   XtAppAddActions (context, actions, XtNumber (actions));
1282   XtRealizeWidget (shell);
1283   XtAppMainLoop (context);
1284
1285   exit (0);
1286 }