--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Viewport.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include <otf.h>
+
+#define DEFAULT_PIXEL_SIZE 30
+#define DEFAULT_FONT_NAME "6x13"
+XFontStruct *font;
+#define FONT_HEIGHT (font->ascent + font->descent)
+
+XtAppContext context;
+/* Widget structure.
+ +---form----------------------------+
+ | +--- command_area --------------+ |
+ | | prev next charmap ... quit| |
+ | +-------------------------------+ |
+ | +--- glyph_area ----------------+ |
+ | | | |
+ | | | |
+ | | | |
+ | +-------------------------------+ |
+ | +--- render_area ---------------+ |
+ | | cmap: ... clear| |
+ | | GSUB: ... | |
+ | | GPOS: ... | |
+ | +-------------------------------+ |
+ +-----------------------------------+ */
+Widget shell, form, command_area, glyph_area, render_area;
+Widget prev, next, *charmap, quit, glyph[128], clear;
+
+unsigned char glyph_exist[0x10000];
+Pixmap pixmap[0x10000];
+
+FT_Face face;
+
+struct
+{
+ int platform_id;
+ int encoding_id;
+ char name[20];
+} charmap_rec[10];
+
+int charmap_index;
+
+unsigned glyph_width, glyph_height;
+int glyph_x, glyph_y;
+int glyph_index;
+
+Pixmap
+create_pixmap (int index, Display *display)
+{
+ int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
+ XImage ximage;
+ Pixmap pixmap;
+ GC gc;
+
+ if (err)
+ return (Pixmap) 0;
+ ximage.height = face->glyph->bitmap.rows;
+ ximage.width = face->glyph->bitmap.width;
+ ximage.depth = 1;
+ ximage.bits_per_pixel = 1;
+ ximage.xoffset = 0;
+ ximage.format = XYPixmap;
+ ximage.data = (char *) face->glyph->bitmap.buffer;
+ ximage.byte_order = MSBFirst;
+ ximage.bitmap_unit = 8;
+ ximage.bitmap_bit_order = MSBFirst;
+ ximage.bitmap_pad = 8;
+ ximage.bytes_per_line = face->glyph->bitmap.pitch;
+ XInitImage (&ximage);
+ pixmap = XCreatePixmap (display, DefaultRootWindow (display),
+ glyph_width, glyph_height, 1);
+ gc = XCreateGC(display, pixmap, (unsigned long) 0, (XGCValues *) 0);
+ XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
+ XPutImage (display, pixmap, gc, &ximage, 0, 0,
+ glyph_x + face->glyph->bitmap_left,
+ glyph_y - face->glyph->bitmap_top,
+ ximage.width, ximage.height);
+ XFreeGC (display, gc);
+ return pixmap;
+}
+
+void
+update_glyph_area ()
+{
+ int i;
+
+ for (i = 0; i < 128; i++)
+ {
+ int index = glyph_index + i;
+ Arg arg[2];
+ int num_args = 0;
+
+ if (charmap_index >= 0)
+ index = FT_Get_Char_Index (face, (FT_ULong) index);
+ XtSetArg (arg[num_args], XtNbitmap, pixmap[index]), num_args++;
+ if (! pixmap[index])
+ XtSetArg (arg[num_args], XtNlabel, "none"), num_args++;
+ XtSetValues (glyph[i], arg, num_args);
+ }
+}
+
+void
+QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
+{
+ XtAppSetExitFlag (XtWidgetToApplicationContext (w));
+}
+
+void
+ChangeProc (Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if ((int) client_data < 0 && glyph_index > 0)
+ {
+ glyph_index -= 128;
+ update_glyph_area ();
+ }
+ else if ((int) client_data > 0 && glyph_index <= 0xFF00)
+ {
+ glyph_index += 128;
+ update_glyph_area ();
+ }
+}
+
+void
+EncodingProc (Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if (charmap_index == (int) client_data)
+ return;
+ charmap_index = (int) client_data;
+ if (charmap_index >= 0)
+ FT_Set_Charmap (face, face->charmaps[charmap_index]);
+ update_glyph_area ();
+}
+
+static void
+ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
+{
+}
+
+static void
+KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
+{
+ fprintf (stderr, "key pressed\n");
+}
+
+/* Format MSG by FMT and print the result to the stderr, and exit. */
+
+#define FATAL_ERROR(fmt, arg) \
+ do { \
+ fprintf (stderr, fmt, arg); \
+ exit (1); \
+ } while (0)
+
+int
+main (int argc, char **argv)
+{
+ XtActionsRec actions[] = { {"Expose", ExposeProc},
+ {"Key", KeyProc} };
+ String prev_action = "<KeyPress><: set() notify() unset()\n\
+ <KeyPress>p: set() notify() unset()\n";
+ String next_action = "<KeyPress>>: set() notify() unset()\n\
+ <KeyPress>n: set() notify() unset()\n";
+ String quit_action = "<KeyPress>q: set() notify() unset()";
+ Arg arg[10];
+ Display *display;
+
+ FT_Library library;
+
+ OTF *otf = NULL;
+ OTF_GlyphString gstring;
+ OTF_Glyph *g;
+
+ int err;
+ int i, j;
+ int pixel_size = DEFAULT_PIXEL_SIZE;
+
+ gstring.size = gstring.used = 256;
+ g = calloc (256, sizeof (OTF_Glyph));
+ gstring.glyphs = g;
+
+ shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
+ shellWidgetClass, NULL, 0);
+ display = XtDisplay (shell);
+ XtAppAddActions (context, actions, XtNumber (actions));
+
+ if (argc != 2)
+ FATAL_ERROR ("%s\n", "Usage: otfview [ X-OPTION ... ] OTF-FILE");
+
+ if (strstr (argv[1], ".ttf")
+ || strstr (argv[1], ".TTF")
+ || strstr (argv[1], ".otf")
+ || strstr (argv[1], ".OTF"))
+ {
+ otf = OTF_open (argv[1]);
+ if (! otf
+ || OTF_get_table (otf, "head") < 0
+ || OTF_get_table (otf, "cmap") < 0)
+ otf = NULL;
+ }
+
+ if ((err = FT_Init_FreeType (&library)))
+ FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
+ err = FT_New_Face (library, argv[1], 0, &face);
+ if (err == FT_Err_Unknown_File_Format)
+ FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
+ else if (err)
+ FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
+ if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
+ FATAL_ERROR ("%s\n", "FT_Set_Char_Size: error");
+
+ glyph_width = ((face->bbox.xMax - face->bbox.xMin)
+ * pixel_size / face->units_per_EM);
+ glyph_height = ((face->bbox.yMax - face->bbox.yMin)
+ * pixel_size / face->units_per_EM);
+ glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
+ glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
+
+ charmap_rec[0].platform_id = -1;
+ charmap_rec[0].encoding_id = -1;
+ strcpy (charmap_rec[0].name, "bypass charmap");
+
+ for (i = 0; i < face->num_charmaps; i++)
+ {
+ charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
+ charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
+ sprintf (charmap_rec[i + 1].name, "%d-%d",
+ charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
+ if (face->charmaps[i]->platform_id == 0
+ || (face->charmaps[i]->platform_id == 3
+ && face->charmaps[i]->encoding_id == 1))
+ strcat (charmap_rec[i + 1].name, " (unicode)");
+ else if (face->charmaps[i]->platform_id == 1
+ && face->charmaps[i]->encoding_id == 0)
+ strcat (charmap_rec[i + 1].name, " (apple-roman)");
+ }
+
+ for (i = 0; i < 0x10000; i++)
+ pixmap[i] = create_pixmap (i, display);
+
+ form = XtCreateManagedWidget ("form", formWidgetClass, shell, NULL, 0);
+ XtSetArg (arg[0], XtNborderWidth, 0);
+ command_area = XtCreateManagedWidget ("command-area", formWidgetClass,
+ form, arg, 1);
+ XtSetArg (arg[0], XtNborderWidth, 1);
+ XtSetArg (arg[1], XtNfromVert, command_area);
+ XtSetArg (arg[2], XtNdefaultDistance, 0);
+ glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
+ form, arg, 3);
+ XtSetArg (arg[0], XtNborderWidth, 0);
+ XtSetArg (arg[1], XtNfromVert, glyph_area);
+ render_area = XtCreateManagedWidget ("render", formWidgetClass,
+ form, arg, 2);
+
+ charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
+ XtSetArg (arg[0], XtNleft, XawChainLeft);
+ XtSetArg (arg[1], XtNright, XawChainLeft);
+ XtSetArg (arg[2], XtNtop, XawChainTop);
+ XtSetArg (arg[3], XtNbottom, XawChainTop);
+ XtSetArg (arg[4], XtNaccelerators, XtParseAcceleratorTable (prev_action));
+ prev = XtCreateManagedWidget ("prev", commandWidgetClass,
+ command_area, arg, 5);
+ XtAddCallback (prev, XtNcallback, ChangeProc, (XtPointer) -1);
+ XtSetArg (arg[4], XtNaccelerators, XtParseAcceleratorTable (next_action));
+ XtSetArg (arg[5], XtNfromHoriz, prev);
+ next = XtCreateManagedWidget ("next", commandWidgetClass,
+ command_area, arg, 6);
+ XtAddCallback (next, XtNcallback, ChangeProc, (XtPointer) 1);
+ XtSetArg (arg[4], XtNfromHoriz, next);
+ charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, commandWidgetClass,
+ command_area, arg, 5);
+ XtAddCallback (charmap[0], XtNcallback, EncodingProc, (XtPointer) -1);
+ for (i = 1; i <= face->num_charmaps; i++)
+ {
+ XtSetArg (arg[4], XtNfromHoriz, charmap[i - 1]);
+ charmap[i] = XtCreateManagedWidget (charmap_rec[i].name,
+ commandWidgetClass,
+ command_area, arg, 5);
+ XtAddCallback (charmap[i], XtNcallback, EncodingProc,
+ (XtPointer) (i - 1));
+ }
+ XtSetArg (arg[4], XtNfromHoriz, charmap[i - 1]);
+ XtSetArg (arg[5], XtNaccelerators, XtParseAcceleratorTable (quit_action));
+ quit = XtCreateManagedWidget ("quit", commandWidgetClass,
+ command_area, arg, 6);
+ XtAddCallback (quit, XtNcallback, QuitProc, NULL);
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 16; j++)
+ {
+ int k = i * 16 + j;
+ int num_args = 0;
+
+ XtSetArg (arg[num_args], XtNwidth, glyph_width), num_args++;
+ XtSetArg (arg[num_args], XtNheight, glyph_height), num_args++;
+ if (j > 0)
+ XtSetArg (arg[num_args], XtNfromHoriz, glyph[k - 1]), num_args++;
+ if (i > 0)
+ XtSetArg (arg[num_args], XtNfromVert, glyph[k - 16]), num_args++;
+ glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
+ glyph_area, arg, num_args);
+ }
+
+ clear = XtCreateManagedWidget ("clear", commandWidgetClass,
+ render_area, NULL, 0);
+
+ glyph_index = 0;
+ charmap_index = -1;
+ update_glyph_area ();
+
+ XtInstallAllAccelerators (form, form);
+ XtRealizeWidget (shell);
+ XtAppMainLoop (context);
+
+ exit (0);
+}