8 #include <X11/Intrinsic.h>
9 #include <X11/StringDefs.h>
10 #include <X11/Shell.h>
11 #include <X11/Xaw/Command.h>
12 #include <X11/Xaw/Toggle.h>
13 #include <X11/Xaw/Box.h>
14 #include <X11/Xaw/Form.h>
15 #include <X11/Xaw/Viewport.h>
18 #include FT_FREETYPE_H
22 #define DEFAULT_PIXEL_SIZE 30
23 #define DEFAULT_FONT_NAME "6x13"
25 #define FONT_HEIGHT (font->ascent + font->descent)
29 +--- frame (form) ------------------+
30 | +--- command_area (box) --------+ |
31 | | quit charmap ... | |
32 | +-------------------------------+ |
33 | +---- navi_area (box) ----------+ |
34 | | PREV prev label next NEXT | |
35 | +-------------------------------+ |
36 | +--- glyph_area (form) ---------+ |
37 | | glyph[0] ... glyph[15] | |
39 | | glyph[112] ... glyph[127]| |
40 | +-------------------------------+ |
41 | +--- render_area (form) --------+ |
43 | | +--- raw (box) -------------+ | |
44 | | | raw_label raw_image | | |
45 | | +--- seq (box) -------------+ | |
46 | | | seq_label seq_image | | |
47 | | +--- gsub (box) ------------+ | |
48 | | | gsub_label gsub_image | | |
49 | | +--- gpos (box) ------------+ | |
50 | | | gpos_label gpos_image | | |
51 | | +---------------------------+ | |
52 | +-------------------------------+ |
53 +-----------------------------------+ */
55 Widget command_area, quit, *charmap;
56 Widget navi_area, PREV, prev, label, next, NEXT;
57 Widget glyph_area, glyph[128];
58 Widget render_area, clear, raw, seq, gsub, gpos;
59 Widget raw_label, raw_image, seq_label, seq_image;
60 Widget gsub_label, gsub_image, gpos_label, gpos_image;
69 unsigned width, height;
74 BitmapRec bitmap[0x10000];
76 int render_width, render_height;
77 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
89 unsigned glyph_width, glyph_height;
101 create_pixmap (int pixel_size, int index)
103 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
109 bitmap[index].pixmap = (Pixmap) 0;
112 ximage.height = face->glyph->bitmap.rows;
113 ximage.width = face->glyph->bitmap.width;
115 ximage.bits_per_pixel = 1;
117 ximage.format = XYPixmap;
118 ximage.data = (char *) face->glyph->bitmap.buffer;
119 ximage.byte_order = MSBFirst;
120 ximage.bitmap_unit = 8;
121 ximage.bitmap_bit_order = MSBFirst;
122 ximage.bitmap_pad = 8;
123 ximage.bytes_per_line = face->glyph->bitmap.pitch;
124 XInitImage (&ximage);
125 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
126 glyph_width, glyph_height, 1);
127 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
128 XPutImage (display, pixmap, gc, &ximage, 0, 0,
129 glyph_x + face->glyph->bitmap_left,
130 glyph_y - face->glyph->bitmap_top,
131 ximage.width, ximage.height);
132 bitmap[index].pixmap = pixmap;
133 bitmap[index].width = ximage.width;
134 bitmap[index].height = ximage.height;
135 bitmap[index].x = face->glyph->bitmap_left;
136 bitmap[index].y = - face->glyph->bitmap_top;
137 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
147 for (i = 0; i < 128; i++)
149 int index = glyph_index + i;
152 if (charmap_index >= 0)
153 index = FT_Get_Char_Index (face, (FT_ULong) index);
154 XtSetArg (arg[num_args], XtNbitmap, bitmap[index].pixmap), num_args++;
155 if (! bitmap[index].pixmap)
156 XtSetArg (arg[num_args], XtNlabel, "none"), num_args++;
157 XtSetValues (glyph[i], arg, num_args);
160 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
161 XtSetArg (arg[0], XtNlabel, buf);
162 XtSetValues (label, arg, 1);
166 update_render_area ()
172 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
173 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
174 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
176 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
178 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
179 0, 0, glyph_width, glyph_height,
180 (glyph_width + 1) * i + 1, 1);
181 XDrawRectangle (display, raw_pixmap, gc_set,
182 (glyph_width + 1) * i, 0,
183 glyph_width + 1, glyph_height + 1);
184 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
185 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
186 x + bmp->x, glyph_y + bmp->y);
189 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
190 XtSetValues (raw_image, arg, 1);
191 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
192 XtSetValues (seq_image, arg, 1);
195 XFillRectangle (display, gsub_pixmap, gc, 0, 0, render_width, render_height);
196 XFillRectangle (display, gpos_pixmap, gc, 0, 0, render_width, render_height);
197 XtSetArg (arg[0], XtNbitmap, gsub_pixmap);
198 XtSetValues (gsub_image, arg, 1);
199 XtSetArg (arg[0], XtNbitmap, gpos_pixmap);
200 XtSetValues (gpos_image, arg, 1);
204 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
206 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
210 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
212 int old_glyph_index = glyph_index;
214 if ((int) client_data == -2 && glyph_index > 0)
215 glyph_index = (glyph_index - 1) & 0xF000;
216 else if ((int) client_data == -1 && glyph_index > 0)
218 else if ((int) client_data == 1 && glyph_index < 0xFF80)
220 else if ((int) client_data == 2 && glyph_index < 0xF000)
221 glyph_index = (glyph_index + 0x1000) & 0xF000;
222 if (glyph_index != old_glyph_index)
223 update_glyph_area ();
227 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
229 if (charmap_index == (int) client_data)
231 charmap_index = (int) client_data;
232 if (charmap_index >= 0)
233 FT_Set_Charmap (face, face->charmaps[charmap_index]);
234 update_glyph_area ();
238 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
240 if ((int) client_data < 0)
242 glyph_rec.n_glyphs = 0;
243 update_render_area ();
245 else if (glyph_rec.n_glyphs < 64)
247 int index = glyph_index + (int) client_data;
249 if (bitmap[index].pixmap)
251 if (charmap_index >= 0)
252 index = FT_Get_Char_Index (face, (FT_ULong) index);
253 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
254 update_render_area ();
262 String quit_action = "<KeyPress>q: set() notify() unset()";
263 String PREV_action = "Shift<KeyPress>p: set() notify() unset()";
264 String prev_action = "~Shift<KeyPress>p: set() notify() unset()";
265 String next_action = "~Shift<KeyPress>n: set() notify() unset()";
266 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()";
270 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, NULL, 0);
271 XtSetArg (arg[0], XtNleft, XawChainLeft);
272 XtSetArg (arg[1], XtNright, XawChainLeft);
273 XtSetArg (arg[2], XtNtop, XawChainTop);
274 XtSetArg (arg[3], XtNbottom, XawChainTop);
275 XtSetArg (arg[4], XtNborderWidth, 0);
276 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
277 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
279 XtSetArg (arg[6], XtNfromVert, command_area);
280 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
282 XtSetArg (arg[4], XtNborderWidth, 1);
283 XtSetArg (arg[5], XtNfromVert, navi_area);
284 XtSetArg (arg[6], XtNdefaultDistance, 0);
285 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
287 XtSetArg (arg[4], XtNborderWidth, 0);
288 XtSetArg (arg[5], XtNfromVert, glyph_area);
289 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
292 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
293 quit = XtCreateManagedWidget ("quit", commandWidgetClass,
294 command_area, arg, 1);
295 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
297 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
298 XtSetArg (arg[0], XtNstate, True);
299 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
300 command_area, arg, 1);
301 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
302 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
303 for (i = 0; i < face->num_charmaps; i++)
305 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
307 command_area, arg, 1);
308 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
311 XtSetArg (arg[0], XtNlabel, "-0x1000 (P)");
312 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
313 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
315 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
316 XtSetArg (arg[0], XtNlabel, "-0x80 (p)");
317 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
318 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
320 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
321 XtSetArg (arg[0], XtNlabel, " 0000 ");
322 label = XtCreateManagedWidget ("label", labelWidgetClass,
324 XtSetArg (arg[0], XtNlabel, "+0x80 (n)");
325 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
326 next = XtCreateManagedWidget ("next", commandWidgetClass,
328 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
329 XtSetArg (arg[0], XtNlabel, "+0x1000 (N)");
330 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
331 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
333 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
335 XtSetArg (arg[0], XtNleft, XawChainLeft);
336 XtSetArg (arg[1], XtNright, XawChainLeft);
337 XtSetArg (arg[2], XtNtop, XawChainTop);
338 XtSetArg (arg[3], XtNbottom, XawChainTop);
339 for (i = 0; i < 8; i++)
340 for (j = 0; j < 16; j++)
345 XtSetArg (arg[num_args], XtNwidth, glyph_width), num_args++;
346 XtSetArg (arg[num_args], XtNheight, glyph_height), num_args++;
348 XtSetArg (arg[num_args], XtNfromHoriz, glyph[k - 1]), num_args++;
350 XtSetArg (arg[num_args], XtNfromVert, glyph[k - 16]), num_args++;
351 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
352 glyph_area, arg, num_args);
353 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
356 XtSetArg (arg[0], XtNleft, XawChainLeft);
357 XtSetArg (arg[1], XtNright, XawChainLeft);
358 XtSetArg (arg[2], XtNtop, XawChainTop);
359 XtSetArg (arg[3], XtNbottom, XawChainTop);
360 clear = XtCreateManagedWidget ("clear", commandWidgetClass,
361 render_area, arg, 4);
362 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
363 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
364 XtSetArg (arg[5], XtNborderWidth, 0);
365 XtSetArg (arg[6], XtNfromVert, clear);
366 raw = XtCreateManagedWidget ("raw", boxWidgetClass,
367 render_area, arg, 7);
368 XtSetArg (arg[0], XtNborderWidth, 0);
369 XtSetArg (arg[1], XtNlabel, "raw: ");
370 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
372 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
373 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
375 XtSetArg (arg[6], XtNfromVert, raw);
376 seq = XtCreateManagedWidget ("seq", boxWidgetClass,
377 render_area, arg, 7);
378 XtSetArg (arg[0], XtNborderWidth, 0);
379 XtSetArg (arg[1], XtNlabel, "seq: ");
380 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
382 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
383 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
387 XtSetArg (arg[6], XtNfromVert, seq);
388 gsub = XtCreateManagedWidget ("gsub", boxWidgetClass,
389 render_area, arg, 7);
390 XtSetArg (arg[0], XtNborderWidth, 0);
391 XtSetArg (arg[1], XtNlabel, "gsub: ");
392 gsub_label = XtCreateManagedWidget ("gsub-label", labelWidgetClass,
394 gsub_image = XtCreateManagedWidget ("gsub-image", labelWidgetClass,
396 XtSetArg (arg[6], XtNfromVert, gsub);
397 gpos = XtCreateManagedWidget ("gpos", boxWidgetClass,
398 render_area, arg, 7);
399 XtSetArg (arg[0], XtNborderWidth, 0);
400 XtSetArg (arg[1], XtNlabel, "gpos: ");
401 gpos_label = XtCreateManagedWidget ("gpos-label", labelWidgetClass,
403 gpos_image = XtCreateManagedWidget ("gpos-image", labelWidgetClass,
407 XtInstallAllAccelerators (shell, shell);
411 /* Format MSG by FMT and print the result to the stderr, and exit. */
413 #define FATAL_ERROR(fmt, arg) \
415 fprintf (stderr, fmt, arg); \
420 main (int argc, char **argv)
424 OTF_GlyphString gstring;
429 int pixel_size = DEFAULT_PIXEL_SIZE;
433 char *str = getenv ("PIXEL_SIZE");
435 if (str && (i = atoi (str)) > 0)
439 gstring.size = gstring.used = 256;
440 g = calloc (256, sizeof (OTF_Glyph));
443 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
444 shellWidgetClass, NULL, 0);
445 display = XtDisplay (shell);
446 display_width = DisplayWidth (display,
447 XScreenNumberOfScreen (XtScreen (shell)));
450 FATAL_ERROR ("%s\n", "Usage: otfview [ X-OPTION ... ] OTF-FILE");
452 if (strstr (argv[1], ".ttf")
453 || strstr (argv[1], ".TTF")
454 || strstr (argv[1], ".otf")
455 || strstr (argv[1], ".OTF"))
457 otf = OTF_open (argv[1]);
459 || OTF_get_table (otf, "head") < 0
460 || OTF_get_table (otf, "cmap") < 0
461 || (OTF_get_table (otf, "gsub") < 0
462 && OTF_get_table (otf, "gpos") < 0))
466 if ((err = FT_Init_FreeType (&library)))
467 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
468 err = FT_New_Face (library, argv[1], 0, &face);
469 if (err == FT_Err_Unknown_File_Format)
470 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
472 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
473 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
474 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
480 sprintf (title, "%s family:%s style:%s",
481 basename (argv[1]), face->family_name, face->style_name);
482 XtSetArg (arg[0], XtNtitle, title);
483 XtSetValues (shell, arg, 1);
486 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
487 * pixel_size / face->units_per_EM);
488 if (glyph_width * 16 > display_width * 0.8)
490 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
491 FT_Set_Pixel_Sizes (face, 0, pixel_size);
492 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
493 * pixel_size / face->units_per_EM);
495 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
496 * pixel_size / face->units_per_EM);
498 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
499 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
501 render_width = (glyph_width + 1) * 15 + 1;
502 render_height = glyph_height + 2;
504 charmap_rec[0].platform_id = -1;
505 charmap_rec[0].encoding_id = -1;
506 strcpy (charmap_rec[0].name, "no charmap");
508 for (i = 0; i < face->num_charmaps; i++)
510 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
511 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
512 sprintf (charmap_rec[i + 1].name, "%d-%d",
513 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
514 if (face->charmaps[i]->platform_id == 0
515 || (face->charmaps[i]->platform_id == 3
516 && face->charmaps[i]->encoding_id == 1))
517 strcat (charmap_rec[i + 1].name, " (unicode)");
518 else if (face->charmaps[i]->platform_id == 1
519 && face->charmaps[i]->encoding_id == 0)
520 strcat (charmap_rec[i + 1].name, " (apple-roman)");
523 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
524 render_width, render_height, 1);
525 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
526 render_width, render_height, 1);
527 gsub_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
528 render_width, render_height, 1);
529 gpos_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
530 render_width, render_height, 1);
532 unsigned long valuemask = GCFunction | GCLineWidth;
535 gc = XCreateGC (display, raw_pixmap, (unsigned long) 0, NULL);
536 values.function = GXset;
537 values.line_width = 1;
538 gc_set = XCreateGC (display, raw_pixmap, valuemask, &values);
539 values.function = GXor;
540 gc_or = XCreateGC (display, raw_pixmap, valuemask, &values);
543 for (i = 0; i < 0x10000; i++)
544 create_pixmap (pixel_size, i);
548 update_glyph_area ();
549 update_render_area ();
551 XtRealizeWidget (shell);
552 XtAppMainLoop (context);