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