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