*** empty log message ***
[m17n/libotf.git] / example / otfviewx.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6
7 #include <X11/Intrinsic.h>
8 #include <X11/StringDefs.h>
9 #include <X11/Shell.h>
10 #include <X11/Xaw/Box.h>
11 #include <X11/Xaw/Form.h>
12 #include <X11/Xaw/Command.h>
13 #include <X11/Xaw/Viewport.h>
14
15 #include <ft2build.h>
16 #include FT_FREETYPE_H
17
18 #include <otf.h>
19
20 #define DEFAULT_PIXEL_SIZE 30
21 #define DEFAULT_FONT_NAME "6x13"
22 XFontStruct *font;
23 #define FONT_HEIGHT (font->ascent + font->descent)
24
25 XtAppContext context;
26 /* Widget structure.
27    +---form----------------------------+
28    | +--- command_area --------------+ |
29    | | charmap ...               quit| |
30    | | PREV prev label next NEXT     | |
31    | +-------------------------------+ |
32    | +--- glyph_area ----------------+ |
33    | |                               | |
34    | |                               | |
35    | |                               | |
36    | +-------------------------------+ |
37    | +--- render_area ---------------+ |
38    | | cmap: ...                clear| |
39    | | GSUB: ...                     | |
40    | | GPOS: ...                     | |
41    | +-------------------------------+ |
42    +-----------------------------------+ */
43 Widget shell, form, command_area, glyph_area, render_area;
44 Widget PREV, prev, label, next, NEXT, *charmap, quit, glyph[128], clear;
45
46 unsigned char glyph_exist[0x10000];
47 Pixmap pixmap[0x10000];
48
49 FT_Face face;
50
51 struct
52 {
53   int platform_id;
54   int encoding_id;
55   char name[20];
56 } charmap_rec[10];
57
58 int charmap_index;
59
60 unsigned glyph_width, glyph_height;
61 int glyph_x, glyph_y;
62 int glyph_index;
63
64 Pixmap
65 create_pixmap (int index, Display *display)
66 {
67   int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
68   XImage ximage;
69   Pixmap pixmap;
70   GC gc;
71   
72   if (err)
73     return (Pixmap) 0;
74   ximage.height = face->glyph->bitmap.rows;
75   ximage.width = face->glyph->bitmap.width;
76   ximage.depth = 1;
77   ximage.bits_per_pixel = 1;
78   ximage.xoffset = 0;
79   ximage.format = XYPixmap;
80   ximage.data = (char *) face->glyph->bitmap.buffer;
81   ximage.byte_order = MSBFirst;
82   ximage.bitmap_unit = 8;
83   ximage.bitmap_bit_order = MSBFirst;
84   ximage.bitmap_pad = 8;
85   ximage.bytes_per_line = face->glyph->bitmap.pitch;
86   XInitImage (&ximage);
87   pixmap = XCreatePixmap (display, DefaultRootWindow (display),
88                           glyph_width, glyph_height, 1);
89   gc = XCreateGC(display, pixmap, (unsigned long) 0, (XGCValues *) 0);
90   XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
91   XPutImage (display, pixmap, gc, &ximage, 0, 0,
92              glyph_x + face->glyph->bitmap_left,
93              glyph_y - face->glyph->bitmap_top,
94              ximage.width, ximage.height);
95   XFreeGC (display, gc);
96   return pixmap;
97 }
98
99 void
100 update_glyph_area ()
101 {
102   int i;
103   Arg arg[2];
104   char buf[16];
105
106   for (i = 0; i < 128; i++)
107     {
108       int index = glyph_index + i;
109       int num_args = 0;
110
111       if (charmap_index >= 0)
112         index = FT_Get_Char_Index (face, (FT_ULong) index);
113       XtSetArg (arg[num_args], XtNbitmap, pixmap[index]), num_args++;
114       if (! pixmap[index])
115         XtSetArg (arg[num_args], XtNlabel, "none"), num_args++;
116       XtSetValues (glyph[i], arg, num_args);
117     }
118
119   sprintf (buf, " %04X ", glyph_index);
120   XtSetArg (arg[0], XtNlabel, buf);
121   XtSetValues (label, arg, 1);
122 }
123
124 void
125 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
126 {
127   XtAppSetExitFlag (XtWidgetToApplicationContext (w));
128 }
129
130 void
131 ChangeProc (Widget w, XtPointer client_data, XtPointer call_data)
132 {
133   int old_glyph_index = glyph_index;
134
135   if ((int) client_data == -2 && glyph_index > 0)
136     glyph_index = (glyph_index - 1) & 0xF000;
137   else if ((int) client_data == -1 && glyph_index > 0)
138     glyph_index -= 0x80;
139   else if ((int) client_data == 1 && glyph_index < 0xFF80)
140     glyph_index += 0x80;
141   else if ((int) client_data == 2 && glyph_index < 0xF000)
142     glyph_index = (glyph_index + 0x1000) & 0xF000;
143   if (glyph_index != old_glyph_index)
144     update_glyph_area ();
145 }
146
147 void
148 EncodingProc (Widget w, XtPointer client_data, XtPointer call_data)
149 {
150   if (charmap_index == (int) client_data)
151     return;
152   charmap_index = (int) client_data;
153   if (charmap_index >= 0)
154     FT_Set_Charmap (face, face->charmaps[charmap_index]);
155   update_glyph_area ();
156 }
157
158
159 void
160 create_widgets ()
161 {
162   String PREV_action = "Shift<KeyPress>p: set() notify() unset()";
163   String prev_action = "~Shift<KeyPress>p: set() notify() unset()";
164   String next_action = "~Shift<KeyPress>n: set() notify() unset()";
165   String NEXT_action = "Shift<KeyPress>n: set() notify() unset()";
166   String quit_action = "<KeyPress>q: set() notify() unset()";
167   Arg arg[10];
168   int i, j;
169
170   form = XtCreateManagedWidget ("form", formWidgetClass, shell, NULL, 0);
171   XtSetArg (arg[0], XtNborderWidth, 0);
172   command_area = XtCreateManagedWidget ("command-area", formWidgetClass,
173                                         form, arg, 1);
174   XtSetArg (arg[0], XtNborderWidth, 1);
175   XtSetArg (arg[1], XtNfromVert, command_area);
176   XtSetArg (arg[2], XtNdefaultDistance, 0);
177   glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
178                                       form, arg, 3);
179   XtSetArg (arg[0], XtNborderWidth, 0);
180   XtSetArg (arg[1], XtNfromVert, glyph_area);
181   render_area = XtCreateManagedWidget ("render", formWidgetClass,
182                                        form, arg, 2);
183
184   charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
185   XtSetArg (arg[0], XtNleft, XawChainLeft);
186   XtSetArg (arg[1], XtNright, XawChainLeft);
187   XtSetArg (arg[2], XtNtop, XawChainTop);
188   XtSetArg (arg[3], XtNbottom, XawChainTop);
189   charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, commandWidgetClass,
190                                       command_area, arg, 4);
191   XtAddCallback (charmap[0], XtNcallback, EncodingProc, (XtPointer) -1);
192   for (i = 1; i <= face->num_charmaps; i++)
193     {
194       XtSetArg (arg[4], XtNfromHoriz, charmap[i - 1]);
195       charmap[i] = XtCreateManagedWidget (charmap_rec[i].name,
196                                           commandWidgetClass,
197                                           command_area, arg, 5);
198       XtAddCallback (charmap[i], XtNcallback, EncodingProc,
199                      (XtPointer) (i - 1));
200     }
201   XtSetArg (arg[0], XtNleft, XawChainRight);
202   XtSetArg (arg[1], XtNright, XawChainRight);
203   XtSetArg (arg[4], XtNfromHoriz, charmap[i - 1]);
204   XtSetArg (arg[5], XtNaccelerators, XtParseAcceleratorTable (quit_action));
205   quit = XtCreateManagedWidget ("quit", commandWidgetClass,
206                                 command_area, arg, 6);
207   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
208
209   XtSetArg (arg[4], XtNfromVert, charmap[0]);
210   XtSetArg (arg[5], XtNlabel, "<< (P)");
211   XtSetArg (arg[6], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
212   PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
213                                 command_area, arg, 7);
214   XtAddCallback (PREV, XtNcallback, ChangeProc, (XtPointer) -2);
215   XtSetArg (arg[5], XtNfromHoriz, PREV);
216   XtSetArg (arg[6], XtNlabel, "< (p)");
217   XtSetArg (arg[7], XtNaccelerators, XtParseAcceleratorTable (prev_action));
218   prev = XtCreateManagedWidget ("prev", commandWidgetClass,
219                                 command_area, arg, 8);
220   XtAddCallback (prev, XtNcallback, ChangeProc, (XtPointer) -1);
221   XtSetArg (arg[5], XtNfromHoriz, prev);
222   XtSetArg (arg[6], XtNlabel, " 0000 ");
223   label = XtCreateManagedWidget ("label", labelWidgetClass,
224                                 command_area, arg, 7);
225   XtSetArg (arg[5], XtNfromHoriz, label);
226   XtSetArg (arg[6], XtNlabel, "(n) >");
227   XtSetArg (arg[7], XtNaccelerators, XtParseAcceleratorTable (next_action));
228   next = XtCreateManagedWidget ("next", commandWidgetClass,
229                                 command_area, arg, 8);
230   XtAddCallback (next, XtNcallback, ChangeProc, (XtPointer) 1);
231   XtSetArg (arg[5], XtNfromHoriz, next);
232   XtSetArg (arg[6], XtNlabel, "(N) >>");
233   XtSetArg (arg[7], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
234   NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
235                                 command_area, arg, 8);
236   XtAddCallback (NEXT, XtNcallback, ChangeProc, (XtPointer) 2);
237
238   for (i = 0; i < 8; i++)
239     for (j = 0; j < 16; j++)
240       {
241         int k = i * 16 + j;
242         int num_args = 0;
243
244         XtSetArg (arg[num_args], XtNwidth, glyph_width), num_args++;
245         XtSetArg (arg[num_args], XtNheight, glyph_height), num_args++;
246         if (j > 0)
247           XtSetArg (arg[num_args], XtNfromHoriz, glyph[k - 1]), num_args++;
248         if (i > 0)
249           XtSetArg (arg[num_args], XtNfromVert, glyph[k - 16]), num_args++;
250         glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
251                                           glyph_area, arg, num_args);
252       }
253
254   clear = XtCreateManagedWidget ("clear", commandWidgetClass,
255                                  render_area, NULL, 0);
256
257   XtInstallAllAccelerators (form, form);
258 }
259
260 /* Format MSG by FMT and print the result to the stderr, and exit.  */
261
262 #define FATAL_ERROR(fmt, arg)   \
263   do {                          \
264     fprintf (stderr, fmt, arg); \
265     exit (1);                   \
266   } while (0)
267
268 int
269 main (int argc, char **argv)
270 {
271   Display *display;
272
273   FT_Library library;
274
275   OTF *otf = NULL;
276   OTF_GlyphString gstring;
277   OTF_Glyph *g;
278
279   int err;
280   int i;
281   int pixel_size = DEFAULT_PIXEL_SIZE;
282
283   gstring.size = gstring.used = 256;
284   g = calloc (256, sizeof (OTF_Glyph));
285   gstring.glyphs = g;
286
287   shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
288                              shellWidgetClass, NULL, 0);
289   display = XtDisplay (shell);
290
291   if (argc != 2)
292     FATAL_ERROR ("%s\n", "Usage: otfview [ X-OPTION ... ]  OTF-FILE");
293   
294   if (strstr (argv[1], ".ttf")
295       || strstr (argv[1], ".TTF")
296       || strstr (argv[1], ".otf")
297       || strstr (argv[1], ".OTF"))
298     {
299       otf = OTF_open (argv[1]);
300       if (! otf
301           || OTF_get_table (otf, "head") < 0
302           || OTF_get_table (otf, "cmap") < 0)
303         otf = NULL;
304     }
305
306   if ((err = FT_Init_FreeType (&library)))
307     FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
308   err = FT_New_Face (library, argv[1], 0, &face);
309   if (err == FT_Err_Unknown_File_Format)
310     FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
311   else if (err)
312     FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
313   if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
314     FATAL_ERROR ("%s\n", "FT_Set_Char_Size: error");
315
316   glyph_width = ((face->bbox.xMax - face->bbox.xMin)
317                  * pixel_size / face->units_per_EM);
318   glyph_height = ((face->bbox.yMax - face->bbox.yMin)
319                   *  pixel_size / face->units_per_EM);
320   glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
321   glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
322
323   charmap_rec[0].platform_id = -1;
324   charmap_rec[0].encoding_id = -1;
325   strcpy (charmap_rec[0].name, "bypass charmap");
326
327   for (i = 0; i < face->num_charmaps; i++)
328     {
329       charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
330       charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
331       sprintf (charmap_rec[i + 1].name, "%d-%d",
332                charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
333       if (face->charmaps[i]->platform_id == 0
334           || (face->charmaps[i]->platform_id == 3
335               && face->charmaps[i]->encoding_id == 1))
336         strcat (charmap_rec[i + 1].name, " (unicode)");
337       else if (face->charmaps[i]->platform_id == 1
338                && face->charmaps[i]->encoding_id == 0)
339         strcat (charmap_rec[i + 1].name, " (apple-roman)");
340     }
341
342   for (i = 0; i < 0x10000; i++)
343     pixmap[i] = create_pixmap (i, display);
344
345   create_widgets ();
346
347   glyph_index = 0;
348   charmap_index = -1;
349   update_glyph_area ();
350
351   XtRealizeWidget (shell);
352   XtAppMainLoop (context);
353
354   exit (0);
355 }