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