1 /* otfview.c -- View glyphs of OpenType fonts.
3 Copyright (C) 2003, 2004
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H15PRO167
7 This file is part of libotf.
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.
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.
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. */
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>
41 #include FT_FREETYPE_H
45 #define DEFAULT_PIXEL_SIZE 30
46 #define DEFAULT_FONT_NAME "6x13"
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)
55 +--- frame (form) -------------------------+
56 | +--- command_area (box) ---------------+ |
57 | | quit dump charmap ... | |
58 | +--------------------------------------+ |
59 | +---- navi_area (box) -----------------+ |
60 | | FIRST PREV prev range next NEXT LAST | |
61 | +--------------------------------------+ |
62 | +--- glyph_area (form) ----------------+ |
63 | | idxh[0] glyph[0] ... glyph[15] | |
65 | | idxh[7] glyph[112] ... glyph[127]| |
66 | | idxl[0] ... idxl[15] | |
67 | +--------------------------------------+ |
68 | +--- render_area (form) ---------------+ |
70 | | +--- raw (box) --------------------+ | |
71 | | | raw_label raw_image | | |
72 | | +----------------------------------+ | |
73 | | GSUB all none features... | |
74 | | GPOS all none features... | |
75 | | +--- seq (box) --------------------+ | |
76 | | | seq_label seq_image | | |
77 | | +----------------------------------+ | |
78 | +--------------------------------------+ |
79 +------------------------------------------+ */
81 Widget command_area, quit, dump, *charmap;
82 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
83 Widget glyph_area, glyph[128], index_label[8];
84 Widget render_area, clear, del, raw, seq;
85 Widget raw_label, raw_image, seq_label, seq_image;
86 unsigned long foreground, background;
95 FeatureRec gsub[64], gpos[64];
100 GC gc, gc_set, gc_or, gc_inv;
104 unsigned width, height;
109 BitmapRec bitmap[0x10000];
111 int render_width, render_height;
112 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
125 unsigned glyph_width, glyph_height;
126 int glyph_x, glyph_y;
139 create_pixmap (int pixel_size, int index)
141 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
147 bitmap[index].pixmap = (Pixmap) 0;
150 ximage.height = face->glyph->bitmap.rows;
151 ximage.width = face->glyph->bitmap.width;
153 ximage.bits_per_pixel = 1;
155 ximage.format = XYPixmap;
156 ximage.data = (char *) face->glyph->bitmap.buffer;
157 ximage.byte_order = MSBFirst;
158 ximage.bitmap_unit = 8;
159 ximage.bitmap_bit_order = MSBFirst;
160 ximage.bitmap_pad = 8;
161 ximage.bytes_per_line = face->glyph->bitmap.pitch;
162 XInitImage (&ximage);
163 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
164 glyph_width, glyph_height, 1);
165 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
166 XPutImage (display, pixmap, gc, &ximage, 0, 0,
167 glyph_x + face->glyph->bitmap_left,
168 glyph_y - face->glyph->bitmap_top,
169 ximage.width, ximage.height);
170 bitmap[index].pixmap = pixmap;
171 bitmap[index].width = ximage.width;
172 bitmap[index].height = ximage.height;
173 bitmap[index].x = face->glyph->bitmap_left;
174 bitmap[index].y = - face->glyph->bitmap_top;
175 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
186 for (i = 0; i < 128; i++)
188 int index = glyph_index + i;
190 if (charmap_index >= 0)
191 index = FT_Get_Char_Index (face, (FT_ULong) index);
192 if (bitmap[index].pixmap)
193 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
195 XtSetArg (arg[0], XtNbitmap, none_pixmap);
196 XtSetValues (glyph[i], arg, 1);
199 msb = (glyph_index >> 7) % 2 ? 8 : 0;
200 for (i = 0; i < 8; i++)
204 sprintf (str, "%XX", i | msb );
205 XtSetArg (arg[0], XtNheight, glyph_height + 5);
206 XtSetArg (arg[1], XtNlabel, str);
207 XtSetValues (index_label[i], arg, 2);
210 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
211 XtSetArg (arg[0], XtNlabel, buf);
212 XtSetValues (range, arg, 1);
216 get_features (OTF_FeatureList *list, FeatureRec *features)
218 int len = list->FeatureCount;
222 if (! features[0].on)
224 for (i = n = 0; i < len; i++)
237 str = malloc (n * 5);
238 for (i = 0, p = str; i < len ; i++, p += 5)
241 OTF_tag_name (list->Feature[features[i].idx].FeatureTag, p);
253 OTF_GlyphString gstring;
254 int len = glyph_rec.n_glyphs;
257 gstring.size = gstring.used = len;
258 gstring.glyphs = alloca (sizeof (OTF_Glyph) * len);
259 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
260 for (i = 0; i < len; i++)
261 gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
263 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
270 str = get_features (&otf->gsub->FeatureList, gsub);
273 OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
279 str = get_features (&otf->gpos->FeatureList, gpos);
282 OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
288 for (i = 0, x = glyph_x; i < gstring.used; i++)
290 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
292 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
293 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
294 x + bmp->x, glyph_y + bmp->y);
297 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
298 XtSetValues (seq_image, arg, 1);
303 update_render_area ()
309 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
310 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
312 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
315 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
316 0, 0, glyph_width, glyph_height,
317 (glyph_width + 4) * i + 1, 1);
318 XDrawRectangle (display, raw_pixmap, gc_set,
319 (glyph_width + 4) * i, 0,
320 glyph_width + 1, glyph_height + 1);
321 XDrawLine (display, raw_pixmap, gc_set,
322 (glyph_width + 4) * i + 1 + glyph_x, 1,
323 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
324 XDrawLine (display, raw_pixmap, gc_set,
325 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
326 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
329 sprintf (buf, "%04X", glyph_rec.codes[i]);
330 XDrawString (display, raw_pixmap, gc_inv,
331 (glyph_width + 1) * i + 1
332 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
333 glyph_height + 2 + FONT_HEIGHT, buf, 4);
335 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
336 XtSetValues (raw_image, arg, 1);
341 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
343 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
347 DumpProc (Widget w, XtPointer client_data, XtPointer pixel_size)
349 int g_width, g_height, g_x, g_y, pix_width, pix_height;
350 int margin = 20 * 300 / 25.4;
351 int a4_width = 210 * 300 / 25.4 - margin * 2;
352 int a4_height = 297 * 300 / 25.4 - margin * 2;
355 XImage ximage, *image;
360 FT_Set_Pixel_Sizes (face, 0, size);
361 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
362 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
363 pix_width = (g_width + 1) * 16 + margin + 1;
364 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
365 while (pix_width > a4_width || pix_height > a4_height)
368 FT_Set_Pixel_Sizes (face, 0, size);
369 g_width = ((face->bbox.xMax - face->bbox.xMin)
370 * size / face->units_per_EM);
371 g_height = ((face->bbox.yMax - face->bbox.yMin)
372 * size / face->units_per_EM);
373 pix_width = (g_width + 1) * 16 + margin + 1;
374 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
377 g_x = - (face->bbox.xMin * size / face->units_per_EM);
378 g_y = face->bbox.yMax * size / face->units_per_EM;
379 for (i = 0; i < 0xFF; i++)
383 if (charmap_index >= 0)
384 idx = FT_Get_Char_Index (face, (FT_ULong) i);
387 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
389 if (g_x < - face->glyph->bitmap_left)
390 g_x = - face->glyph->bitmap_left;
391 if (g_y < face->glyph->bitmap_top)
392 g_y = face->glyph->bitmap_top;
394 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
396 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
398 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
400 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
403 pix_width = (g_width + 1) * 16 + margin + 1;
404 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
405 pixmap = XCreatePixmap (display,
406 RootWindow (display, DefaultScreen (display)),
407 pix_width, pix_height, 1);
408 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
410 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
411 XDrawLine (display, pixmap, gc_set, x, margin,
412 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
413 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
414 XDrawLine (display, pixmap, gc_set, margin, y,
415 margin + (g_width + 1) * 16, y);
416 for (i = 0; i < 256; i++)
421 if (charmap_index >= 0)
422 idx = FT_Get_Char_Index (face, (FT_ULong) i);
425 x = margin + (g_width + 1) * (i % 16);
426 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
427 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
429 ximage.height = face->glyph->bitmap.rows;
430 ximage.width = face->glyph->bitmap.width;
432 ximage.bits_per_pixel = 1;
434 ximage.format = XYPixmap;
435 ximage.data = (char *) face->glyph->bitmap.buffer;
436 ximage.byte_order = MSBFirst;
437 ximage.bitmap_unit = 8;
438 ximage.bitmap_bit_order = MSBFirst;
439 ximage.bitmap_pad = 8;
440 ximage.bytes_per_line = face->glyph->bitmap.pitch;
441 XInitImage (&ximage);
442 XPutImage (display, pixmap, gc, &ximage, 0, 0,
443 x + g_x + face->glyph->bitmap_left,
444 y + g_y - face->glyph->bitmap_top,
445 ximage.width, ximage.height);
447 sprintf (str, "0x%02X", i);
448 XDrawString (display, pixmap, gc_inv,
449 x + (g_width - XTextWidth (font, str, 4))/ 2,
450 y + g_height + FONT_ASCENT, str, 4);
453 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
454 AllPlanes, XYPixmap);
457 char *name = alloca (strlen (filename) + 5);
460 sprintf (name, "%s.pbm", filename);
461 printf ("Writing %s ...", name);
462 fp = fopen (name, "w");
463 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
464 bytes_per_line = (image->width + 7) / 8;
466 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
467 fwrite (data, 1, bytes_per_line, fp);
471 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
476 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
478 int old_glyph_index = glyph_index;
480 if ((int) client_data == -3 && glyph_index > 0)
482 else if ((int) client_data == -2 && glyph_index > 0)
483 glyph_index = (glyph_index - 1) & 0xF000;
484 else if ((int) client_data == -1 && glyph_index > 0)
486 else if ((int) client_data == 1 && glyph_index < 0xFF80)
488 else if ((int) client_data == 2 && glyph_index < 0xF000)
489 glyph_index = (glyph_index + 0x1000) & 0xF000;
490 else if ((int) client_data == 3 && glyph_index < 0xF000)
491 glyph_index = 0xFF80;
492 if (glyph_index != old_glyph_index)
493 update_glyph_area ();
497 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
499 if (charmap_index == (int) client_data)
501 charmap_index = (int) client_data;
502 if (charmap_index >= 0)
503 FT_Set_Charmap (face, face->charmaps[charmap_index]);
504 update_glyph_area ();
508 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
510 if ((int) client_data < 0)
512 if (glyph_rec.n_glyphs > 0)
514 if ((int) client_data == -2)
515 glyph_rec.n_glyphs--;
517 glyph_rec.n_glyphs = 0;
518 update_render_area ();
521 else if (glyph_rec.n_glyphs < 64)
523 int index = glyph_index + (int) client_data;
525 if (charmap_index >= 0)
526 index = FT_Get_Char_Index (face, (FT_ULong) index);
527 if (bitmap[index].pixmap)
529 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
530 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
531 update_render_area ();
537 FeatureProc (OTF_FeatureList *list, FeatureRec *features, int idx)
546 for (idx = 0; idx < list->FeatureCount; idx++)
548 features[idx].idx = idx;
549 features[idx].on = on;
551 i = 0, j = list->FeatureCount - 1;
556 idx = features[i].idx;
560 for (j = i; j + 1 < list->FeatureCount && features[j + 1].on; j++)
561 features[j].idx = features[j + 1].idx;
562 features[j].idx = idx;
567 for (j = i; i > 0 && ! features[i - 1].on; i--)
568 features[i].idx = features[i - 1].idx;
569 features[i].idx = idx;
578 OTF_tag_name (list->Feature[features[i].idx].FeatureTag, str);
579 XtSetArg (arg[0], XtNlabel, str);
582 XtSetArg (arg[1], XtNforeground, background);
583 XtSetArg (arg[2], XtNbackground, foreground);
587 XtSetArg (arg[1], XtNforeground, foreground);
588 XtSetArg (arg[2], XtNbackground, background);
590 XtSetValues (features[i].w, arg, 3);
596 GsubProc (Widget w, XtPointer client_data, XtPointer call_data)
598 FeatureProc (&otf->gsub->FeatureList, gsub, (int) client_data);
602 GposProc (Widget w, XtPointer client_data, XtPointer call_data)
604 FeatureProc (&otf->gpos->FeatureList, gpos, (int) client_data);
608 create_otf_widgets (int flag, Widget prev)
611 OTF_FeatureList *list;
613 FeatureRec *features;
616 char *box_label, feature_label[5];
622 list = &otf->gsub->FeatureList;
629 list = &otf->gpos->FeatureList;
633 box_label = alloca (strlen (label) + 4);
635 strcpy (box_label, label);
636 strcat (box_label, "box");
638 XtSetArg (arg[0], XtNborderWidth, 0);
639 XtSetArg (arg[1], XtNleft, XawChainLeft);
640 XtSetArg (arg[2], XtNright, XawChainLeft);
641 XtSetArg (arg[3], XtNtop, XawChainTop);
642 XtSetArg (arg[4], XtNbottom, XawChainTop);
643 XtSetArg (arg[5], XtNfromVert, prev);
644 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
645 prev = XtCreateManagedWidget (box_label, boxWidgetClass, render_area, arg, 7);
646 XtCreateManagedWidget (label, labelWidgetClass, prev, arg, 1);
647 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, NULL, 0);
648 XtAddCallback (w, XtNcallback, proc, (XtPointer) -2);
649 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, NULL, 0);
650 XtAddCallback (w, XtNcallback, proc, (XtPointer) -1);
651 for (i = 0; i < list->FeatureCount; i++)
653 OTF_tag_name (list->Feature[i].FeatureTag, feature_label);
655 w = XtCreateManagedWidget (feature_label, commandWidgetClass, prev,
657 XtAddCallback (w, XtNcallback, proc, (XtPointer) i);
665 create_widgets (int pixel_size)
667 String quit_action = "<KeyPress>q: set() notify() unset()";
668 String FIRST_action = "~Shift<KeyPress>f: set() notify() unset()";
669 String PREV_action = "Shift<KeyPress>p: set() notify() unset()";
670 String prev_action = "~Shift<KeyPress>p: set() notify() unset()";
671 String next_action = "~Shift<KeyPress>n: set() notify() unset()";
672 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()";
673 String LAST_action = "~Shift<KeyPress>l: set() notify() unset()";
678 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, NULL, 0);
679 XtSetArg (arg[0], XtNleft, XawChainLeft);
680 XtSetArg (arg[1], XtNright, XawChainLeft);
681 XtSetArg (arg[2], XtNtop, XawChainTop);
682 XtSetArg (arg[3], XtNbottom, XawChainTop);
683 XtSetArg (arg[4], XtNborderWidth, 0);
684 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
685 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
687 XtSetArg (arg[6], XtNfromVert, command_area);
688 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
690 XtSetArg (arg[4], XtNborderWidth, 0);
691 XtSetArg (arg[5], XtNfromVert, navi_area);
692 XtSetArg (arg[6], XtNdefaultDistance, 0);
693 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
695 XtSetArg (arg[5], XtNfromVert, glyph_area);
696 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
699 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
700 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
701 command_area, arg, 1);
702 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
704 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
705 command_area, arg, 1);
706 XtAddCallback (dump, XtNcallback, DumpProc, (XtPointer) pixel_size);
708 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
709 XtSetArg (arg[0], XtNstate, True);
710 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
711 command_area, arg, 1);
712 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
713 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
714 for (i = 0; i < face->num_charmaps; i++)
716 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
718 command_area, arg, 1);
719 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
722 XtSetArg (arg[0], XtNlabel, " |< (f)");
723 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
724 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
726 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
727 XtSetArg (arg[0], XtNlabel, "<< (P)");
728 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
729 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
731 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
732 XtSetArg (arg[0], XtNlabel, "< (p)");
733 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
734 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
736 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
737 XtSetArg (arg[0], XtNlabel, " 0000 ");
738 range = XtCreateManagedWidget ("range", labelWidgetClass,
740 XtSetArg (arg[0], XtNforeground, &foreground);
741 XtSetArg (arg[1], XtNbackground, &background);
742 XtGetValues (range, arg, 2);
744 XtSetArg (arg[0], XtNlabel, "> (n)");
745 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
746 next = XtCreateManagedWidget ("next", commandWidgetClass,
748 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
749 XtSetArg (arg[0], XtNlabel, ">> (N)");
750 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
751 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
753 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
754 XtSetArg (arg[0], XtNlabel, ">| (l)");
755 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
756 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
758 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
760 XtSetArg (arg[0], XtNleft, XawChainLeft);
761 XtSetArg (arg[1], XtNright, XawChainLeft);
762 XtSetArg (arg[2], XtNtop, XawChainTop);
763 XtSetArg (arg[3], XtNbottom, XawChainTop);
765 for (i = 0; i < 8; i++)
771 sprintf (str, "%XX", i);
772 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
773 XtSetArg (arg[n], XtNlabel, str), n++;
774 XtSetArg (arg[n], XtNborderWidth, 0), n++;
776 XtSetArg (arg[n], XtNfromVert, w), n++;
777 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
778 index_label[i] = head;
779 for (j = 0; j < 16; j++)
784 XtSetArg (arg[n], XtNheight, glyph_height), n++;
785 XtSetArg (arg[n], XtNwidth, glyph_width), n++;
787 XtSetArg (arg[n], XtNfromVert, w), n++;
789 XtSetArg (arg[n], XtNfromHoriz, head), n++;
791 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
792 XtSetArg (arg[n], XtNinternalWidth, 0), n++;
793 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
795 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
799 XtSetArg(arg[4], XtNwidth, glyph_width + 2);
800 XtSetArg (arg[5], XtNfromVert, glyph[112]);
801 XtSetArg (arg[6], XtNfromHoriz, w);
802 XtSetArg (arg[7], XtNborderWidth, 0);
804 for (j = 0; j < 16; j++)
808 sprintf (str, "X%X", j);
809 XtSetArg (arg[8], XtNlabel, str);
810 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
811 XtSetArg (arg[6], XtNfromHoriz, w);
814 XtSetArg (arg[0], XtNleft, XawChainLeft);
815 XtSetArg (arg[1], XtNright, XawChainLeft);
816 XtSetArg (arg[2], XtNtop, XawChainTop);
817 XtSetArg (arg[3], XtNbottom, XawChainTop);
818 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
819 XtSetArg (arg[5], XtNborderWidth, 0);
820 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
821 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
822 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
823 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
824 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
826 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
827 XtSetArg (arg[5], XtNborderWidth, 0);
828 XtSetArg (arg[6], XtNfromVert, w);
829 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
831 XtSetArg (arg[0], XtNborderWidth, 0);
832 XtSetArg (arg[1], XtNlabel, "raw: ");
833 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
835 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
836 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
841 if (OTF_get_table (otf, "GSUB") >= 0)
842 w = create_otf_widgets (1, w);
843 if (OTF_get_table (otf, "GPOS") >= 0)
844 w = create_otf_widgets (0, w);
847 XtSetArg (arg[6], XtNfromVert, w);
848 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
849 XtSetArg (arg[0], XtNborderWidth, 0);
850 XtSetArg (arg[1], XtNlabel, "seq: ");
851 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
853 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
854 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
856 XtInstallAllAccelerators (shell, shell);
860 /* Format MSG by FMT and print the result to the stderr, and exit. */
862 #define FATAL_ERROR(fmt, arg) \
864 fprintf (stderr, fmt, arg); \
869 x_error_handler (Display *display, XErrorEvent *error)
876 main (int argc, char **argv)
880 OTF_GlyphString gstring;
885 int pixel_size = DEFAULT_PIXEL_SIZE;
886 int fixed_pixel_size = 0;
890 char *str = getenv ("PIXEL_SIZE");
892 if (str && (i = atoi (str)) > 0)
895 fixed_pixel_size = 1;
899 gstring.size = gstring.used = 256;
900 g = calloc (256, sizeof (OTF_Glyph));
903 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
904 shellWidgetClass, NULL, 0);
905 display = XtDisplay (shell);
906 /*XSynchronize (display, True);*/
907 XSetErrorHandler (x_error_handler);
908 display_width = DisplayWidth (display,
909 XScreenNumberOfScreen (XtScreen (shell)));
910 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
912 font = XLoadQueryFont (display, "fixed");
914 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
916 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
921 if (strstr (filename, ".ttf")
922 || strstr (filename, ".TTF")
923 || strstr (filename, ".otf")
924 || strstr (filename, ".OTF"))
926 otf = OTF_open (filename);
928 || OTF_get_table (otf, "head") < 0
929 || OTF_get_table (otf, "cmap") < 0
930 || (OTF_check_table (otf, "GSUB") < 0
931 && OTF_check_table (otf, "GPOS") < 0))
937 memset (gsub, 0, sizeof gsub);
938 memset (gpos, 0, sizeof gpos);
940 if ((err = FT_Init_FreeType (&library)))
941 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
942 err = FT_New_Face (library, filename, 0, &face);
943 if (err == FT_Err_Unknown_File_Format)
944 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
946 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
947 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
948 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
954 filename = basename (filename);
955 sprintf (title, "%s family:%s style:%s",
956 filename, face->family_name, face->style_name);
957 XtSetArg (arg[0], XtNtitle, title);
958 XtSetValues (shell, arg, 1);
961 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
962 * pixel_size / face->units_per_EM);
963 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
965 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
966 FT_Set_Pixel_Sizes (face, 0, pixel_size);
967 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
968 * pixel_size / face->units_per_EM);
970 if (glyph_width < FONT_WIDTH * 4)
971 glyph_width = FONT_WIDTH * 4;
973 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
974 * pixel_size / face->units_per_EM);
976 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
977 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
979 for (i = 0; i < 0x10000; i++)
980 if (FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
982 if (glyph_x < - face->glyph->bitmap_left)
983 glyph_x = - face->glyph->bitmap_left;
984 if (glyph_y < face->glyph->bitmap_top)
985 glyph_y = face->glyph->bitmap_top;
987 < glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
989 = glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
991 < glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
993 = glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
996 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
997 glyph_width, glyph_height + 1 + FONT_HEIGHT, 1);
1000 unsigned long valuemask = GCFunction | GCLineWidth;
1003 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1004 values.function = GXset;
1005 values.line_width = 1;
1006 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1007 values.function = GXor;
1008 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1009 values.function = GXcopyInverted;
1010 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1013 XFillRectangle (display, none_pixmap, gc, 0, 0,
1014 glyph_width, glyph_height + 1 + FONT_HEIGHT);
1015 XDrawString (display, none_pixmap, gc_inv,
1016 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1017 glyph_height / 2, "none", 4);
1019 render_width = (glyph_width + 4) * 15 + 1;
1020 render_height = glyph_height + 2;
1022 charmap_rec[0].platform_id = -1;
1023 charmap_rec[0].encoding_id = -1;
1024 strcpy (charmap_rec[0].name, "no charmap");
1026 for (i = 0; i < face->num_charmaps; i++)
1028 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1029 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1030 sprintf (charmap_rec[i + 1].name, "%d-%d",
1031 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1032 if (face->charmaps[i]->platform_id == 0
1033 || (face->charmaps[i]->platform_id == 3
1034 && face->charmaps[i]->encoding_id == 1))
1035 strcat (charmap_rec[i + 1].name, " (unicode)");
1036 else if (face->charmaps[i]->platform_id == 1
1037 && face->charmaps[i]->encoding_id == 0)
1038 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1041 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1042 render_width, render_height, 1);
1043 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1044 render_width, render_height, 1);
1046 for (i = 0; i < 0x10000; i++)
1047 create_pixmap (pixel_size, i);
1048 create_widgets (pixel_size);
1051 update_glyph_area ();
1052 update_render_area ();
1054 XtRealizeWidget (shell);
1055 XtAppMainLoop (context);