*** empty log message ***
[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 <X11/Intrinsic.h>
32 #include <X11/StringDefs.h>
33 #include <X11/Shell.h>
34 #include <X11/Xaw/Command.h>
35 #include <X11/Xaw/Toggle.h>
36 #include <X11/Xaw/Box.h>
37 #include <X11/Xaw/Form.h>
38 #include <X11/Xaw/Viewport.h>
39
40 #include <ft2build.h>
41 #include FT_FREETYPE_H
42
43 #include <otf.h>
44
45 #define DEFAULT_PIXEL_SIZE 30
46 #define DEFAULT_FONT_NAME "6x13"
47 XFontStruct *font;
48 #define FONT_HEIGHT (font->ascent + font->descent)
49 #define FONT_DESCENT (font->descent)
50 #define FONT_WIDTH (font->max_bounds.width)
51
52 XtAppContext context;
53 /* Widget structure.
54    +--- frame (form) -------------------------+
55    | +--- command_area (box) ---------------+ |
56    | | quit charmap ...                     | |
57    | +--------------------------------------+ |
58    | +---- navi_area (box) -----------------+ |
59    | | FIRST PREV prev label next NEXT LAST | |
60    | +--------------------------------------+ |
61    | +--- glyph_area (form) ----------------+ |
62    | | glyph[0]        ...        glyph[15] | |
63    | |   ...                        ...     | |
64    | | glyph[112]      ...        glyph[127]| |
65    | +--------------------------------------+ |
66    | +--- render_area (form) ---------------+ |
67    | | clear                                | |
68    | | +--- raw (box) --------------------+ | |
69    | | | raw_label raw_image              | | |
70    | | +--- seq (box) --------------------+ | |
71    | | | seq_label seq_image              | | |
72    | | +--- gsub (box) -------------------+ | |
73    | | | gsub_label gsub_image            | | |
74    | | +--- gpos (box) -------------------+ | |
75    | | | gpos_label gpos_image            | | |
76    | | +----------------------------------+ | |
77    | +--------------------------------------+ |
78    +------------------------------------------+ */
79 Widget shell, frame;
80 Widget command_area, quit, *charmap;
81 Widget navi_area, FIRST, PREV, prev, label, next, NEXT, LAST;
82 Widget glyph_area, glyph[128];
83 Widget render_area, clear, raw, seq, gsub, gpos;
84 Widget raw_label, raw_image, seq_label, seq_image;
85 Widget gsub_label, gsub_image, gpos_label, gpos_image;
86
87 int glyph_char[128];
88
89 Display *display;
90 GC gc, gc_set, gc_or, gc_inv;
91
92 typedef struct {
93   Pixmap pixmap;
94   unsigned width, height;
95   int x, y;
96   int advance;
97 } BitmapRec;
98
99 BitmapRec bitmap[0x10000];
100
101 int render_width, render_height;
102 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
103 Pixmap none_pixmap;
104
105 FT_Face face;
106
107 struct {
108   int platform_id;
109   int encoding_id;
110   char name[20];
111 } charmap_rec[10];
112
113 int charmap_index;
114
115 unsigned glyph_width, glyph_height;
116 int glyph_x, glyph_y;
117 int glyph_index;
118
119 struct {
120   int n_glyphs;
121   int glyphs[64];
122   int codes[64];
123 } glyph_rec;
124
125 OTF *otf;
126
127 void
128 create_pixmap (int pixel_size, int index)
129 {
130   int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
131   XImage ximage;
132   Pixmap pixmap;
133   int height = glyph_height + 1 + FONT_HEIGHT;
134   char index_buf[5];
135   
136   if (err)
137     {
138       bitmap[index].pixmap = (Pixmap) 0;
139       return;
140     }
141   ximage.height = face->glyph->bitmap.rows;
142   ximage.width = face->glyph->bitmap.width;
143   ximage.depth = 1;
144   ximage.bits_per_pixel = 1;
145   ximage.xoffset = 0;
146   ximage.format = XYPixmap;
147   ximage.data = (char *) face->glyph->bitmap.buffer;
148   ximage.byte_order = MSBFirst;
149   ximage.bitmap_unit = 8;
150   ximage.bitmap_bit_order = MSBFirst;
151   ximage.bitmap_pad = 8;
152   ximage.bytes_per_line = face->glyph->bitmap.pitch;
153   XInitImage (&ximage);
154   pixmap = XCreatePixmap (display, DefaultRootWindow (display),
155                           glyph_width, height, 1);
156   XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, height);
157   XPutImage (display, pixmap, gc, &ximage, 0, 0,
158              glyph_x + face->glyph->bitmap_left,
159              glyph_y - face->glyph->bitmap_top,
160              ximage.width, ximage.height);
161   sprintf (index_buf, "%04X", index);
162   XDrawLine (display, pixmap, gc_inv,
163              0, glyph_height + 1, glyph_width, glyph_height + 1);
164   XDrawString (display, pixmap, gc_inv,
165                (glyph_width - XTextWidth (font, index_buf, 4)) / 2,
166                height - FONT_DESCENT, index_buf, 4);
167   bitmap[index].pixmap = pixmap;
168   bitmap[index].width = ximage.width;
169   bitmap[index].height = ximage.height;
170   bitmap[index].x = face->glyph->bitmap_left;
171   bitmap[index].y = - face->glyph->bitmap_top;
172   bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
173 }
174
175 void
176 update_glyph_area ()
177 {
178   int i;
179   Arg arg[2];
180   char buf[16];
181
182   for (i = 0; i < 128; i++)
183     {
184       int index = glyph_index + i;
185
186       if (charmap_index >= 0)
187         index = FT_Get_Char_Index (face, (FT_ULong) index);
188       if (bitmap[index].pixmap)
189         XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
190       else
191         XtSetArg (arg[0], XtNbitmap, none_pixmap);
192       XtSetValues (glyph[i], arg, 1);
193     }
194
195   sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
196   XtSetArg (arg[0], XtNlabel, buf);
197   XtSetValues (label, arg, 1);
198 }
199
200 void
201 update_render_area ()
202 {
203   int i;
204   int x;
205   Arg arg[1];
206
207   XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
208   XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
209   for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
210     {
211       BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
212       char buf[5];
213
214       XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
215                  0, 0, glyph_width, glyph_height,
216                  (glyph_width + 1) * i + 1, 1);
217       XDrawRectangle (display, raw_pixmap, gc_set,
218                       (glyph_width + 1) * i, 0,
219                       glyph_width + 1, glyph_height + 1);
220       XDrawLine (display, raw_pixmap, gc_set,
221                  (glyph_width + 1) * i + 1 + glyph_x, 1,
222                  (glyph_width + 1) * i + 1 + glyph_x, glyph_height + 1);
223       XDrawLine (display, raw_pixmap, gc_set,
224                  (glyph_width + 1) * i + 1 + glyph_x + bmp->advance, 1,
225                  (glyph_width + 1) * i + 1 + glyph_x + bmp->advance,
226                  glyph_height + 1);
227
228       sprintf (buf, "%04X", glyph_rec.codes[i]);
229       XDrawString (display, raw_pixmap, gc_inv, 
230                    (glyph_width + 1) * i + 1
231                    + (glyph_width - XTextWidth (font, buf, 4)) / 2,
232                    glyph_height + 2 + FONT_HEIGHT, buf, 4);
233       XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
234                  glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
235                  x + bmp->x, glyph_y + bmp->y);
236       x += bmp->advance;
237     }
238   XtSetArg (arg[0], XtNbitmap, raw_pixmap);
239   XtSetValues (raw_image, arg, 1);
240   XtSetArg (arg[0], XtNbitmap, seq_pixmap);
241   XtSetValues (seq_image, arg, 1);
242   if (! otf)
243     return;
244   XFillRectangle (display, gsub_pixmap, gc, 0, 0, render_width, render_height);
245   XFillRectangle (display, gpos_pixmap, gc, 0, 0, render_width, render_height);
246   XtSetArg (arg[0], XtNbitmap, gsub_pixmap);
247   XtSetValues (gsub_image, arg, 1);
248   XtSetArg (arg[0], XtNbitmap, gpos_pixmap);
249   XtSetValues (gpos_image, arg, 1);
250 }
251
252 void
253 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
254 {
255   XtAppSetExitFlag (XtWidgetToApplicationContext (w));
256 }
257
258 void
259 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
260 {
261   int old_glyph_index = glyph_index;
262
263   if ((int) client_data == -3 && glyph_index > 0)
264     glyph_index = 0;
265   else if ((int) client_data == -2 && glyph_index > 0)
266     glyph_index = (glyph_index - 1) & 0xF000;
267   else if ((int) client_data == -1 && glyph_index > 0)
268     glyph_index -= 0x80;
269   else if ((int) client_data == 1 && glyph_index < 0xFF80)
270     glyph_index += 0x80;
271   else if ((int) client_data == 2 && glyph_index < 0xF000)
272     glyph_index = (glyph_index + 0x1000) & 0xF000;
273   else if ((int) client_data == 3 && glyph_index < 0xF000)
274     glyph_index = 0xFF80;
275   if (glyph_index != old_glyph_index)
276     update_glyph_area ();
277 }
278
279 void
280 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
281 {
282   if (charmap_index == (int) client_data)
283     return;
284   charmap_index = (int) client_data;
285   if (charmap_index >= 0)
286     FT_Set_Charmap (face, face->charmaps[charmap_index]);
287   update_glyph_area ();
288 }
289
290 void
291 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
292 {
293   if ((int) client_data < 0)
294     {
295       glyph_rec.n_glyphs = 0;
296       update_render_area ();
297     }
298   else if (glyph_rec.n_glyphs < 64)
299     {
300       int index = glyph_index + (int) client_data;
301
302       if (charmap_index >= 0)
303         index = FT_Get_Char_Index (face, (FT_ULong) index);
304       if (bitmap[index].pixmap)
305         {
306           glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
307           glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
308           update_render_area ();
309         }
310     }
311 }
312
313 void
314 create_widgets ()
315 {
316   String quit_action = "<KeyPress>q: set() notify() unset()";
317   String FIRST_action = "~Shift<KeyPress>f: set() notify() unset()";
318   String PREV_action = "Shift<KeyPress>p: set() notify() unset()";
319   String prev_action = "~Shift<KeyPress>p: set() notify() unset()";
320   String next_action = "~Shift<KeyPress>n: set() notify() unset()";
321   String NEXT_action = "Shift<KeyPress>n: set() notify() unset()";
322   String LAST_action = "~Shift<KeyPress>l: set() notify() unset()";
323   Arg arg[10];
324   int i, j;
325   int glyph_widget_height;
326
327   frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, NULL, 0);
328   XtSetArg (arg[0], XtNleft, XawChainLeft);
329   XtSetArg (arg[1], XtNright, XawChainLeft);
330   XtSetArg (arg[2], XtNtop, XawChainTop);
331   XtSetArg (arg[3], XtNbottom, XawChainTop);
332   XtSetArg (arg[4], XtNborderWidth, 0);
333   XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
334   command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
335                                         frame, arg, 6);
336   XtSetArg (arg[6], XtNfromVert, command_area);
337   navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
338                                      frame, arg, 7);
339   XtSetArg (arg[4], XtNborderWidth, 1);
340   XtSetArg (arg[5], XtNfromVert, navi_area);
341   XtSetArg (arg[6], XtNdefaultDistance, 0);
342   glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
343                                       frame, arg, 7);
344   XtSetArg (arg[4], XtNborderWidth, 0);
345   XtSetArg (arg[5], XtNfromVert, glyph_area);
346   render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
347                                        frame, arg, 6);
348
349   XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
350   quit = XtCreateManagedWidget ("quit", commandWidgetClass,
351                                 command_area, arg, 1);
352   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
353
354   charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
355   XtSetArg (arg[0], XtNstate, True);
356   charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
357                                       command_area, arg, 1);
358   XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
359   XtSetArg (arg[0], XtNradioGroup, charmap[0]);
360   for (i = 0; i < face->num_charmaps; i++)
361     {
362       charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
363                                               toggleWidgetClass,
364                                               command_area, arg, 1);
365       XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
366     }
367
368   XtSetArg (arg[0], XtNlabel, " |< (f)");
369   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
370   FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
371                                  navi_area, arg, 2);
372   XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
373   XtSetArg (arg[0], XtNlabel, "<< (P)");
374   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
375   PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
376                                 navi_area, arg, 2);
377   XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
378   XtSetArg (arg[0], XtNlabel, "< (p)");
379   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
380   prev = XtCreateManagedWidget ("prev", commandWidgetClass,
381                                 navi_area, arg, 2);
382   XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
383   XtSetArg (arg[0], XtNlabel, " 0000 ");
384   label = XtCreateManagedWidget ("label", labelWidgetClass,
385                                  navi_area, arg, 1);
386   XtSetArg (arg[0], XtNlabel, "> (n)");
387   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
388   next = XtCreateManagedWidget ("next", commandWidgetClass,
389                                 navi_area, arg, 2);
390   XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
391   XtSetArg (arg[0], XtNlabel, ">> (N)");
392   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
393   NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
394                                 navi_area, arg, 2);
395   XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
396   XtSetArg (arg[0], XtNlabel, ">| (l)");
397   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
398   LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
399                                 navi_area, arg, 2);
400   XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
401
402   glyph_widget_height = glyph_height + 1 + FONT_HEIGHT;
403   XtSetArg (arg[0], XtNleft, XawChainLeft);
404   XtSetArg (arg[1], XtNright, XawChainLeft);
405   XtSetArg (arg[2], XtNtop, XawChainTop);
406   XtSetArg (arg[3], XtNbottom, XawChainTop);
407   for (i = 0; i < 8; i++)
408     for (j = 0; j < 16; j++)
409       {
410         int k = i * 16 + j;
411         int num_args = 4;
412
413         XtSetArg (arg[num_args], XtNwidth, glyph_width), num_args++;
414         XtSetArg (arg[num_args], XtNheight, glyph_widget_height), num_args++;
415         if (j > 0)
416           XtSetArg (arg[num_args], XtNfromHoriz, glyph[k - 1]), num_args++;
417         if (i > 0)
418           XtSetArg (arg[num_args], XtNfromVert, glyph[k - 16]), num_args++;
419         XtSetArg (arg[num_args], XtNinternalWidth, 0), num_args++;
420         glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
421                                           glyph_area, arg, num_args);
422         XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
423       }
424
425   XtSetArg (arg[0], XtNleft, XawChainLeft);
426   XtSetArg (arg[1], XtNright, XawChainLeft);
427   XtSetArg (arg[2], XtNtop, XawChainTop);
428   XtSetArg (arg[3], XtNbottom, XawChainTop);
429   clear = XtCreateManagedWidget ("clear", commandWidgetClass,
430                                  render_area, arg, 4);
431   XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
432   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
433   XtSetArg (arg[5], XtNborderWidth, 0);
434   XtSetArg (arg[6], XtNfromVert, clear);
435   raw = XtCreateManagedWidget ("raw", boxWidgetClass,
436                                 render_area, arg, 7);
437   XtSetArg (arg[0], XtNborderWidth, 0);
438   XtSetArg (arg[1], XtNlabel, "raw: ");
439   raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
440                                       raw, arg, 2);
441   XtSetArg (arg[1], XtNbitmap, raw_pixmap);
442   raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
443                                       raw, arg, 2);
444   XtSetArg (arg[6], XtNfromVert, raw);
445   seq = XtCreateManagedWidget ("seq", boxWidgetClass,
446                                 render_area, arg, 7);
447   XtSetArg (arg[0], XtNborderWidth, 0);
448   XtSetArg (arg[1], XtNlabel, "seq: ");
449   seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
450                                       seq, arg, 2);
451   XtSetArg (arg[1], XtNbitmap, seq_pixmap);
452   seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
453                                       seq, arg, 2);
454   if (otf)
455     {
456       XtSetArg (arg[6], XtNfromVert, seq);
457       gsub = XtCreateManagedWidget ("gsub", boxWidgetClass,
458                                     render_area, arg, 7);
459       XtSetArg (arg[0], XtNborderWidth, 0);
460       XtSetArg (arg[1], XtNlabel, "gsub: ");
461       gsub_label = XtCreateManagedWidget ("gsub-label", labelWidgetClass,
462                                           gsub, arg, 2);
463       gsub_image = XtCreateManagedWidget ("gsub-image", labelWidgetClass,
464                                           gsub, arg, 1);
465       XtSetArg (arg[6], XtNfromVert, gsub);
466       gpos = XtCreateManagedWidget ("gpos", boxWidgetClass,
467                                     render_area, arg, 7);
468       XtSetArg (arg[0], XtNborderWidth, 0);
469       XtSetArg (arg[1], XtNlabel, "gpos: ");
470       gpos_label = XtCreateManagedWidget ("gpos-label", labelWidgetClass,
471                                           gpos, arg, 2);
472       gpos_image = XtCreateManagedWidget ("gpos-image", labelWidgetClass,
473                                           gpos, arg, 1);
474     }
475
476   XtInstallAllAccelerators (shell, shell);
477 }
478
479
480 /* Format MSG by FMT and print the result to the stderr, and exit.  */
481
482 #define FATAL_ERROR(fmt, arg)   \
483   do {                          \
484     fprintf (stderr, fmt, arg); \
485     exit (1);                   \
486   } while (0)
487
488 int
489 main (int argc, char **argv)
490 {
491   FT_Library library;
492
493   OTF_GlyphString gstring;
494   OTF_Glyph *g;
495
496   int err;
497   int i;
498   int pixel_size = DEFAULT_PIXEL_SIZE;
499   int display_width;
500
501   {
502     char *str = getenv ("PIXEL_SIZE");
503
504     if (str && (i = atoi (str)) > 0)
505       pixel_size = i;
506   }
507
508   gstring.size = gstring.used = 256;
509   g = calloc (256, sizeof (OTF_Glyph));
510   gstring.glyphs = g;
511
512   shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
513                              shellWidgetClass, NULL, 0);
514   display = XtDisplay (shell);
515   display_width = DisplayWidth (display,
516                                 XScreenNumberOfScreen (XtScreen (shell)));
517   font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
518   if (! font)
519     font = XLoadQueryFont (display, "fixed");
520
521   if (argc != 2)
522     FATAL_ERROR ("%s\n", "Usage: otfview [ X-OPTION ... ]  OTF-FILE");
523   
524   if (strstr (argv[1], ".ttf")
525       || strstr (argv[1], ".TTF")
526       || strstr (argv[1], ".otf")
527       || strstr (argv[1], ".OTF"))
528     {
529       otf = OTF_open (argv[1]);
530       if (! otf
531           || OTF_get_table (otf, "head") < 0
532           || OTF_get_table (otf, "cmap") < 0
533           || (OTF_get_table (otf, "gsub") < 0
534               && OTF_get_table (otf, "gpos") < 0))
535         otf = NULL;
536     }
537
538   if ((err = FT_Init_FreeType (&library)))
539     FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
540   err = FT_New_Face (library, argv[1], 0, &face);
541   if (err == FT_Err_Unknown_File_Format)
542     FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
543   else if (err)
544     FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
545   if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
546     FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
547
548   {
549     char title[256];
550     Arg arg[1];
551
552     sprintf (title, "%s family:%s style:%s",
553              basename (argv[1]), face->family_name, face->style_name);
554     XtSetArg (arg[0], XtNtitle, title);
555     XtSetValues (shell, arg, 1);
556   }
557
558   glyph_width = ((face->bbox.xMax - face->bbox.xMin)
559                  * pixel_size / face->units_per_EM);
560   if (glyph_width * 16 > display_width * 0.8)
561     {
562       pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
563       FT_Set_Pixel_Sizes (face, 0, pixel_size);
564       glyph_width = ((face->bbox.xMax - face->bbox.xMin)
565                      * pixel_size / face->units_per_EM);
566     }
567   if (glyph_width < FONT_WIDTH * 4)
568     glyph_width = FONT_WIDTH * 4;
569
570   glyph_height = ((face->bbox.yMax - face->bbox.yMin)
571                   *  pixel_size / face->units_per_EM);
572
573   glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
574   glyph_y = face->ascender * pixel_size / face->units_per_EM;
575
576   for (i = 0; i < 0x10000; i++)
577     if (FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
578       {
579         if (glyph_x < - face->glyph->bitmap_left)
580           glyph_x = - face->glyph->bitmap_left;
581         if (glyph_y < face->glyph->bitmap_top)
582           glyph_y = face->glyph->bitmap_top;
583         if (glyph_width
584             < glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
585           glyph_width
586             = glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
587         if (glyph_height
588             < glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
589           glyph_height
590             = glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
591       }
592
593   none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
594                                glyph_width, glyph_height + 1 + FONT_HEIGHT, 1);
595
596   {
597     unsigned long valuemask =  GCFunction | GCLineWidth;
598     XGCValues values;
599
600     gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
601     values.function = GXset;
602     values.line_width = 1;
603     gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
604     values.function = GXor;
605     gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
606     values.function = GXcopyInverted;
607     gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
608   }
609
610   XFillRectangle (display, none_pixmap, gc, 0, 0,
611                   glyph_width, glyph_height + 1 + FONT_HEIGHT);
612   XDrawString (display, none_pixmap, gc_inv,
613                (glyph_width - XTextWidth (font, "none", 4)) / 2,
614                glyph_height / 2, "none", 4);
615
616   render_width = (glyph_width + 1) * 15 + 1;
617   render_height = glyph_height + FONT_HEIGHT + 2;
618
619   charmap_rec[0].platform_id = -1;
620   charmap_rec[0].encoding_id = -1;
621   strcpy (charmap_rec[0].name, "no charmap");
622
623   for (i = 0; i < face->num_charmaps; i++)
624     {
625       charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
626       charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
627       sprintf (charmap_rec[i + 1].name, "%d-%d",
628                charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
629       if (face->charmaps[i]->platform_id == 0
630           || (face->charmaps[i]->platform_id == 3
631               && face->charmaps[i]->encoding_id == 1))
632         strcat (charmap_rec[i + 1].name, " (unicode)");
633       else if (face->charmaps[i]->platform_id == 1
634                && face->charmaps[i]->encoding_id == 0)
635         strcat (charmap_rec[i + 1].name, " (apple-roman)");
636     }
637
638   raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
639                               render_width, render_height, 1);
640   seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
641                               render_width, render_height, 1);
642   gsub_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
643                                render_width, render_height, 1);
644   gpos_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
645                                render_width, render_height, 1);
646
647   for (i = 0; i < 0x10000; i++)
648     create_pixmap (pixel_size, i);
649   create_widgets ();
650   glyph_index = 0;
651   charmap_index = -1;
652   update_glyph_area ();
653   update_render_area ();
654
655   XtRealizeWidget (shell);
656   XtAppMainLoop (context);
657
658   exit (0);
659 }