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