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