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