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;
555 int index = features[idx].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 = index;
567 for (j = i; i > 0 && ! features[i - 1].on; i--)
568 features[i].idx = features[i - 1].idx;
569 features[i].idx = index;
577 unsigned fore = foreground, back = background;
580 fore = background, back = foreground;
583 XtSetArg (arg[0], XtNforeground, back);
584 XtSetArg (arg[1], XtNbackground, fore);
588 XtSetArg (arg[0], XtNforeground, fore);
589 XtSetArg (arg[1], XtNbackground, back);
591 OTF_tag_name (list->Feature[features[i].idx].FeatureTag, str);
592 XtSetArg (arg[2], XtNlabel, str);
593 XtSetValues (features[i].w, arg, 3);
599 GsubProc (Widget w, XtPointer client_data, XtPointer call_data)
601 FeatureProc (&otf->gsub->FeatureList, gsub, (int) client_data);
605 GposProc (Widget w, XtPointer client_data, XtPointer call_data)
607 FeatureProc (&otf->gpos->FeatureList, gpos, (int) client_data);
611 create_otf_widgets (int flag, Widget prev)
614 OTF_FeatureList *list;
616 FeatureRec *features;
619 char *box_label, feature_label[5];
625 list = &otf->gsub->FeatureList;
632 list = &otf->gpos->FeatureList;
636 box_label = alloca (strlen (label) + 4);
638 strcpy (box_label, label);
639 strcat (box_label, "box");
641 XtSetArg (arg[0], XtNborderWidth, 0);
642 XtSetArg (arg[1], XtNleft, XawChainLeft);
643 XtSetArg (arg[2], XtNright, XawChainLeft);
644 XtSetArg (arg[3], XtNtop, XawChainTop);
645 XtSetArg (arg[4], XtNbottom, XawChainTop);
646 XtSetArg (arg[5], XtNfromVert, prev);
647 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
648 prev = XtCreateManagedWidget (box_label, boxWidgetClass, render_area, arg, 7);
649 XtCreateManagedWidget (label, labelWidgetClass, prev, arg, 1);
650 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, NULL, 0);
651 XtAddCallback (w, XtNcallback, proc, (XtPointer) -2);
652 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, NULL, 0);
653 XtAddCallback (w, XtNcallback, proc, (XtPointer) -1);
654 for (i = 0; i < list->FeatureCount; i++)
656 OTF_tag_name (list->Feature[i].FeatureTag, feature_label);
658 w = XtCreateManagedWidget (feature_label, commandWidgetClass, prev,
660 XtAddCallback (w, XtNcallback, proc, (XtPointer) i);
668 create_widgets (int pixel_size)
670 String quit_action = "<KeyPress>q: set() notify() unset()";
671 String FIRST_action = "~Shift<KeyPress>f: set() notify() unset()";
672 String PREV_action = "Shift<KeyPress>p: set() notify() unset()";
673 String prev_action = "~Shift<KeyPress>p: set() notify() unset()";
674 String next_action = "~Shift<KeyPress>n: set() notify() unset()";
675 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()";
676 String LAST_action = "~Shift<KeyPress>l: set() notify() unset()";
681 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, NULL, 0);
682 XtSetArg (arg[0], XtNleft, XawChainLeft);
683 XtSetArg (arg[1], XtNright, XawChainLeft);
684 XtSetArg (arg[2], XtNtop, XawChainTop);
685 XtSetArg (arg[3], XtNbottom, XawChainTop);
686 XtSetArg (arg[4], XtNborderWidth, 0);
687 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
688 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
690 XtSetArg (arg[6], XtNfromVert, command_area);
691 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
693 XtSetArg (arg[4], XtNborderWidth, 0);
694 XtSetArg (arg[5], XtNfromVert, navi_area);
695 XtSetArg (arg[6], XtNdefaultDistance, 0);
696 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
698 XtSetArg (arg[5], XtNfromVert, glyph_area);
699 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
702 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
703 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
704 command_area, arg, 1);
705 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
707 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
708 command_area, arg, 1);
709 XtAddCallback (dump, XtNcallback, DumpProc, (XtPointer) pixel_size);
711 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
712 XtSetArg (arg[0], XtNstate, True);
713 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
714 command_area, arg, 1);
715 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
716 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
717 for (i = 0; i < face->num_charmaps; i++)
719 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
721 command_area, arg, 1);
722 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
725 XtSetArg (arg[0], XtNlabel, " |< (f)");
726 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
727 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
729 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
730 XtSetArg (arg[0], XtNlabel, "<< (P)");
731 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
732 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
734 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
735 XtSetArg (arg[0], XtNlabel, "< (p)");
736 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
737 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
739 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
740 XtSetArg (arg[0], XtNlabel, " 0000 ");
741 range = XtCreateManagedWidget ("range", labelWidgetClass,
743 XtSetArg (arg[0], XtNforeground, &foreground);
744 XtSetArg (arg[1], XtNbackground, &background);
745 XtGetValues (range, arg, 2);
747 XtSetArg (arg[0], XtNlabel, "> (n)");
748 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
749 next = XtCreateManagedWidget ("next", commandWidgetClass,
751 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
752 XtSetArg (arg[0], XtNlabel, ">> (N)");
753 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
754 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
756 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
757 XtSetArg (arg[0], XtNlabel, ">| (l)");
758 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
759 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
761 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
763 XtSetArg (arg[0], XtNleft, XawChainLeft);
764 XtSetArg (arg[1], XtNright, XawChainLeft);
765 XtSetArg (arg[2], XtNtop, XawChainTop);
766 XtSetArg (arg[3], XtNbottom, XawChainTop);
768 for (i = 0; i < 8; i++)
774 sprintf (str, "%XX", i);
775 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
776 XtSetArg (arg[n], XtNlabel, str), n++;
777 XtSetArg (arg[n], XtNborderWidth, 0), n++;
779 XtSetArg (arg[n], XtNfromVert, w), n++;
780 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
781 index_label[i] = head;
782 for (j = 0; j < 16; j++)
787 XtSetArg (arg[n], XtNheight, glyph_height), n++;
788 XtSetArg (arg[n], XtNwidth, glyph_width), n++;
790 XtSetArg (arg[n], XtNfromVert, w), n++;
792 XtSetArg (arg[n], XtNfromHoriz, head), n++;
794 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
795 XtSetArg (arg[n], XtNinternalWidth, 0), n++;
796 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
798 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
802 XtSetArg(arg[4], XtNwidth, glyph_width + 2);
803 XtSetArg (arg[5], XtNfromVert, glyph[112]);
804 XtSetArg (arg[6], XtNfromHoriz, w);
805 XtSetArg (arg[7], XtNborderWidth, 0);
807 for (j = 0; j < 16; j++)
811 sprintf (str, "X%X", j);
812 XtSetArg (arg[8], XtNlabel, str);
813 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
814 XtSetArg (arg[6], XtNfromHoriz, w);
817 XtSetArg (arg[0], XtNleft, XawChainLeft);
818 XtSetArg (arg[1], XtNright, XawChainLeft);
819 XtSetArg (arg[2], XtNtop, XawChainTop);
820 XtSetArg (arg[3], XtNbottom, XawChainTop);
821 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
822 XtSetArg (arg[5], XtNborderWidth, 0);
823 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
824 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
825 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
826 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
827 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
829 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
830 XtSetArg (arg[5], XtNborderWidth, 0);
831 XtSetArg (arg[6], XtNfromVert, w);
832 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
834 XtSetArg (arg[0], XtNborderWidth, 0);
835 XtSetArg (arg[1], XtNlabel, "raw: ");
836 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
838 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
839 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
844 if (OTF_get_table (otf, "GSUB") >= 0)
845 w = create_otf_widgets (1, w);
846 if (OTF_get_table (otf, "GPOS") >= 0)
847 w = create_otf_widgets (0, w);
850 XtSetArg (arg[6], XtNfromVert, w);
851 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
852 XtSetArg (arg[0], XtNborderWidth, 0);
853 XtSetArg (arg[1], XtNlabel, "seq: ");
854 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
856 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
857 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
859 XtInstallAllAccelerators (shell, shell);
863 /* Format MSG by FMT and print the result to the stderr, and exit. */
865 #define FATAL_ERROR(fmt, arg) \
867 fprintf (stderr, fmt, arg); \
872 x_error_handler (Display *display, XErrorEvent *error)
879 main (int argc, char **argv)
883 OTF_GlyphString gstring;
888 int pixel_size = DEFAULT_PIXEL_SIZE;
889 int fixed_pixel_size = 0;
893 char *str = getenv ("PIXEL_SIZE");
895 if (str && (i = atoi (str)) > 0)
898 fixed_pixel_size = 1;
902 gstring.size = gstring.used = 256;
903 g = calloc (256, sizeof (OTF_Glyph));
906 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
907 shellWidgetClass, NULL, 0);
908 display = XtDisplay (shell);
909 /*XSynchronize (display, True);*/
910 XSetErrorHandler (x_error_handler);
911 display_width = DisplayWidth (display,
912 XScreenNumberOfScreen (XtScreen (shell)));
913 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
915 font = XLoadQueryFont (display, "fixed");
917 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
919 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
924 if (strstr (filename, ".ttf")
925 || strstr (filename, ".TTF")
926 || strstr (filename, ".otf")
927 || strstr (filename, ".OTF"))
929 otf = OTF_open (filename);
931 || OTF_get_table (otf, "head") < 0
932 || OTF_get_table (otf, "cmap") < 0
933 || (OTF_check_table (otf, "GSUB") < 0
934 && OTF_check_table (otf, "GPOS") < 0))
940 memset (gsub, 0, sizeof gsub);
941 memset (gpos, 0, sizeof gpos);
943 if ((err = FT_Init_FreeType (&library)))
944 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
945 err = FT_New_Face (library, filename, 0, &face);
946 if (err == FT_Err_Unknown_File_Format)
947 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
949 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
950 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
951 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
957 filename = basename (filename);
958 sprintf (title, "%s family:%s style:%s",
959 filename, face->family_name, face->style_name);
960 XtSetArg (arg[0], XtNtitle, title);
961 XtSetValues (shell, arg, 1);
964 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
965 * pixel_size / face->units_per_EM);
966 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
968 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
969 FT_Set_Pixel_Sizes (face, 0, pixel_size);
970 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
971 * pixel_size / face->units_per_EM);
973 if (glyph_width < FONT_WIDTH * 4)
974 glyph_width = FONT_WIDTH * 4;
976 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
977 * pixel_size / face->units_per_EM);
979 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
980 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
982 for (i = 0; i < 0x10000; i++)
983 if (FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
985 if (glyph_x < - face->glyph->bitmap_left)
986 glyph_x = - face->glyph->bitmap_left;
987 if (glyph_y < face->glyph->bitmap_top)
988 glyph_y = face->glyph->bitmap_top;
990 < glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
992 = glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
994 < glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
996 = glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
999 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1000 glyph_width, glyph_height + 1 + FONT_HEIGHT, 1);
1003 unsigned long valuemask = GCFunction | GCLineWidth;
1006 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1007 values.function = GXset;
1008 values.line_width = 1;
1009 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1010 values.function = GXor;
1011 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1012 values.function = GXcopyInverted;
1013 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1016 XFillRectangle (display, none_pixmap, gc, 0, 0,
1017 glyph_width, glyph_height + 1 + FONT_HEIGHT);
1018 XDrawString (display, none_pixmap, gc_inv,
1019 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1020 glyph_height / 2, "none", 4);
1022 render_width = (glyph_width + 4) * 15 + 1;
1023 render_height = glyph_height + 2;
1025 charmap_rec[0].platform_id = -1;
1026 charmap_rec[0].encoding_id = -1;
1027 strcpy (charmap_rec[0].name, "no charmap");
1029 for (i = 0; i < face->num_charmaps; i++)
1031 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1032 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1033 sprintf (charmap_rec[i + 1].name, "%d-%d",
1034 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1035 if (face->charmaps[i]->platform_id == 0
1036 || (face->charmaps[i]->platform_id == 3
1037 && face->charmaps[i]->encoding_id == 1))
1038 strcat (charmap_rec[i + 1].name, " (unicode)");
1039 else if (face->charmaps[i]->platform_id == 1
1040 && face->charmaps[i]->encoding_id == 0)
1041 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1044 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1045 render_width, render_height, 1);
1046 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1047 render_width, render_height, 1);
1049 for (i = 0; i < 0x10000; i++)
1050 create_pixmap (pixel_size, i);
1051 create_widgets (pixel_size);
1054 update_glyph_area ();
1055 update_render_area ();
1057 XtRealizeWidget (shell);
1058 XtAppMainLoop (context);