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