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