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/Xatom.h>
32 #include <X11/Intrinsic.h>
33 #include <X11/StringDefs.h>
34 #include <X11/Shell.h>
35 #include <X11/Xaw/Command.h>
36 #include <X11/Xaw/Toggle.h>
37 #include <X11/Xaw/Box.h>
38 #include <X11/Xaw/Form.h>
39 #include <X11/Xaw/Viewport.h>
42 #include FT_FREETYPE_H
46 #define DEFAULT_PIXEL_SIZE 30
49 #define DEFAULT_FONT_NAME "6x13"
51 #define FONT_HEIGHT (font->ascent + font->descent)
52 #define FONT_ASCENT (font->ascent)
53 #define FONT_DESCENT (font->descent)
54 #define FONT_WIDTH (font->max_bounds.width)
58 +--- frame (form) -------------------------+
59 | +--- command_area (box) ---------------+ |
60 | | quit dump charmap ... | |
61 | +--------------------------------------+ |
62 | +---- navi_area (box) -----------------+ |
63 | | FIRST PREV prev range next NEXT LAST | |
64 | +--------------------------------------+ |
65 | +--- glyph_area (form) ----------------+ |
66 | | idxh[0] glyph[0] ... glyph[15] | |
68 | | idxh[7] glyph[112] ... glyph[127]| |
69 | | idxl[0] ... idxl[15] | |
70 | +--------------------------------------+ |
71 | +--- render_area (form) ---------------+ |
73 | | +--- raw (box) --------------------+ | |
74 | | | raw_label raw_image | | |
75 | | +----------------------------------+ | |
76 | | GSUB all none features... | |
77 | | GPOS all none features... | |
78 | | +--- seq (box) --------------------+ | |
79 | | | seq_label seq_image | | |
80 | | +----------------------------------+ | |
81 | +--------------------------------------+ |
82 +------------------------------------------+ */
84 Widget command_area, quit, dump, *charmap;
85 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
86 Widget glyph_area, glyph[128], index_label[8];
87 Widget render_area, clear, del, raw, seq;
88 Widget raw_label, raw_image, seq_label, seq_image;
89 unsigned long foreground, background;
91 #define MAX_FEATURE_COUNT 16
96 OTF_GSUB_GPOS *gsub_gpos;
102 } features[MAX_FEATURE_COUNT];
105 FeatureRec gsub, gpos;
112 GC gc, gc_set, gc_or, gc_inv;
116 unsigned width, height;
121 BitmapRec bitmap[0x10000];
123 int render_width, render_height;
124 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
137 unsigned glyph_width, glyph_height;
138 int glyph_x, glyph_y;
151 create_pixmap (int index)
153 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
159 bitmap[index].pixmap = none_pixmap;
162 ximage.height = face->glyph->bitmap.rows;
163 ximage.width = face->glyph->bitmap.width;
165 ximage.bits_per_pixel = 1;
167 ximage.format = XYPixmap;
168 ximage.data = (char *) face->glyph->bitmap.buffer;
169 ximage.byte_order = MSBFirst;
170 ximage.bitmap_unit = 8;
171 ximage.bitmap_bit_order = MSBFirst;
172 ximage.bitmap_pad = 8;
173 ximage.bytes_per_line = face->glyph->bitmap.pitch;
174 XInitImage (&ximage);
175 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
176 glyph_width, glyph_height, 1);
177 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
178 XPutImage (display, pixmap, gc, &ximage, 0, 0,
179 glyph_x + face->glyph->bitmap_left,
180 glyph_y - face->glyph->bitmap_top,
181 ximage.width, ximage.height);
182 bitmap[index].pixmap = pixmap;
183 bitmap[index].width = ximage.width;
184 bitmap[index].height = ximage.height;
185 bitmap[index].x = face->glyph->bitmap_left;
186 bitmap[index].y = - face->glyph->bitmap_top;
187 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
198 for (i = 0; i < 128; i++)
200 int index = glyph_index + i;
202 if (charmap_index >= 0)
203 index = FT_Get_Char_Index (face, (FT_ULong) index);
204 if (! bitmap[index].pixmap)
205 create_pixmap (index);
206 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
207 XtSetValues (glyph[i], arg, 1);
210 msb = (glyph_index >> 7) % 2 ? 8 : 0;
211 for (i = 0; i < 8; i++)
215 sprintf (str, "%XX", i | msb );
216 XtSetArg (arg[0], XtNheight, glyph_height + 5);
217 XtSetArg (arg[1], XtNlabel, str);
218 XtSetValues (index_label[i], arg, 2);
221 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
222 XtSetArg (arg[0], XtNlabel, buf);
223 XtSetValues (range, arg, 1);
227 get_features (OTF_FeatureList *list, FeatureRec *rec)
232 if (! rec->features[0].on)
234 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
236 if (rec->features[i].on)
241 if (i == rec->langsys->FeatureCount)
247 str = malloc (n * 5);
248 for (i = 0, p = str; i < n; i++, p += 5)
250 OTF_tag_name (rec->features[i].tag, p);
258 #define DEVICE_DELTA(table, size) \
259 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
260 ? (table).DeltaValue[(size) >= (table).StartSize] \
264 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
265 OTF_Glyph *prev, int *x, int *y)
267 if (anchor->AnchorFormat == 2 && prev)
270 int ap = anchor->f.f1.AnchorPoint;
272 FT_Load_Glyph (ft_face, (FT_UInt) prev->glyph_id, FT_LOAD_MONOCHROME);
273 outline = &ft_face->glyph->outline;
274 if (ap < outline->n_points)
276 *x = outline->points[ap].x;
277 *y = outline->points[ap].y;
280 else if (anchor->AnchorFormat == 3)
282 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
283 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
291 OTF_GlyphString gstring;
294 int len = glyph_rec.n_glyphs;
296 int unitsPerEm = face->units_per_EM;
298 gstring.size = gstring.used = len;
299 gstring.glyphs = alloca (sizeof (OTF_Glyph) * len);
300 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
301 for (i = 0; i < len; i++)
302 gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
304 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
311 str = get_features (&otf->gsub->FeatureList, &gsub);
314 OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
320 str = get_features (&otf->gpos->FeatureList, &gpos);
323 OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
330 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
331 i < gstring.used; i++, prev = g++)
333 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
334 int xoff = 0, yoff = 0;
336 switch (g->positioning_type)
343 int format = g->f.f1.format;
345 if (format & OTF_XPlacement)
346 xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
347 if (format & OTF_XPlaDevice)
348 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
349 if (format & OTF_YPlacement)
350 yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
351 if (format & OTF_YPlaDevice)
352 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
356 /* Not yet supported. */
360 int base_x, base_y, mark_x, mark_y;
362 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
363 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
364 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
365 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
367 if (g->f.f4.base_anchor->AnchorFormat != 1)
368 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
369 if (g->f.f4.mark_anchor->AnchorFormat != 1)
370 adjust_anchor (g->f.f4.mark_anchor, face, prev, &mark_x, &mark_y);
371 xoff = (base_x - prev_width) - mark_x;
372 yoff = base_y - mark_y;
376 /* Not yet supported. */
378 default: /* i.e case 6 */
379 /* Not yet supported. */
383 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
384 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
385 x + bmp->x + xoff, glyph_y + bmp->y + yoff);
386 x += prev_width = bmp->advance;
388 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
389 XtSetValues (seq_image, arg, 1);
394 update_render_area ()
400 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
401 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
403 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
406 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
407 0, 0, glyph_width, glyph_height,
408 (glyph_width + 4) * i + 1, 1);
409 XDrawRectangle (display, raw_pixmap, gc_set,
410 (glyph_width + 4) * i, 0,
411 glyph_width + 1, glyph_height + 1);
412 XDrawLine (display, raw_pixmap, gc_set,
413 (glyph_width + 4) * i + 1 + glyph_x, 1,
414 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
415 XDrawLine (display, raw_pixmap, gc_set,
416 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
417 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
420 sprintf (buf, "%04X", glyph_rec.codes[i]);
421 XDrawString (display, raw_pixmap, gc_inv,
422 (glyph_width + 1) * i + 1
423 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
424 glyph_height + 2 + FONT_HEIGHT, buf, 4);
426 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
427 XtSetValues (raw_image, arg, 1);
432 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
434 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
438 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
440 int g_width, g_height, g_x, g_y, pix_width, pix_height;
441 int margin = 20 * 300 / 25.4;
442 int a4_width = 210 * 300 / 25.4 - margin * 2;
443 int a4_height = 297 * 300 / 25.4 - margin * 2;
446 XImage ximage, *image;
451 FT_Set_Pixel_Sizes (face, 0, size);
452 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
453 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
454 pix_width = (g_width + 1) * 16 + margin + 1;
455 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
456 while (pix_width > a4_width || pix_height > a4_height)
459 FT_Set_Pixel_Sizes (face, 0, size);
460 g_width = ((face->bbox.xMax - face->bbox.xMin)
461 * size / face->units_per_EM);
462 g_height = ((face->bbox.yMax - face->bbox.yMin)
463 * size / face->units_per_EM);
464 pix_width = (g_width + 1) * 16 + margin + 1;
465 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
468 g_x = - (face->bbox.xMin * size / face->units_per_EM);
469 g_y = face->bbox.yMax * size / face->units_per_EM;
470 for (i = 0; i < 0xFF; i++)
474 if (charmap_index >= 0)
475 idx = FT_Get_Char_Index (face, (FT_ULong) i);
478 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
480 if (g_x < - face->glyph->bitmap_left)
481 g_x = - face->glyph->bitmap_left;
482 if (g_y < face->glyph->bitmap_top)
483 g_y = face->glyph->bitmap_top;
485 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
487 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
489 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
491 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
494 pix_width = (g_width + 1) * 16 + margin + 1;
495 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
496 pixmap = XCreatePixmap (display,
497 RootWindow (display, DefaultScreen (display)),
498 pix_width, pix_height, 1);
499 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
501 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
502 XDrawLine (display, pixmap, gc_set, x, margin,
503 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
504 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
505 XDrawLine (display, pixmap, gc_set, margin, y,
506 margin + (g_width + 1) * 16, y);
507 for (i = 0; i < 256; i++)
512 if (charmap_index >= 0)
513 idx = FT_Get_Char_Index (face, (FT_ULong) i);
516 x = margin + (g_width + 1) * (i % 16);
517 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
518 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
520 ximage.height = face->glyph->bitmap.rows;
521 ximage.width = face->glyph->bitmap.width;
523 ximage.bits_per_pixel = 1;
525 ximage.format = XYPixmap;
526 ximage.data = (char *) face->glyph->bitmap.buffer;
527 ximage.byte_order = MSBFirst;
528 ximage.bitmap_unit = 8;
529 ximage.bitmap_bit_order = MSBFirst;
530 ximage.bitmap_pad = 8;
531 ximage.bytes_per_line = face->glyph->bitmap.pitch;
532 XInitImage (&ximage);
533 XPutImage (display, pixmap, gc, &ximage, 0, 0,
534 x + g_x + face->glyph->bitmap_left,
535 y + g_y - face->glyph->bitmap_top,
536 ximage.width, ximage.height);
538 sprintf (str, "0x%02X", i);
539 XDrawString (display, pixmap, gc_inv,
540 x + (g_width - XTextWidth (font, str, 4))/ 2,
541 y + g_height + FONT_ASCENT, str, 4);
544 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
545 AllPlanes, XYPixmap);
548 char *name = alloca (strlen (filename) + 5);
551 sprintf (name, "%s.pbm", filename);
552 printf ("Writing %s ...", name);
553 fp = fopen (name, "w");
554 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
555 bytes_per_line = (image->width + 7) / 8;
557 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
558 fwrite (data, 1, bytes_per_line, fp);
562 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
567 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
569 int old_glyph_index = glyph_index;
571 if ((int) client_data == -3 && glyph_index > 0)
573 else if ((int) client_data == -2 && glyph_index > 0)
574 glyph_index = (glyph_index - 1) & 0xF000;
575 else if ((int) client_data == -1 && glyph_index > 0)
577 else if ((int) client_data == 1 && glyph_index < 0xFF80)
579 else if ((int) client_data == 2 && glyph_index < 0xF000)
580 glyph_index = (glyph_index + 0x1000) & 0xF000;
581 else if ((int) client_data == 3 && glyph_index < 0xF000)
582 glyph_index = 0xFF80;
583 if (glyph_index != old_glyph_index)
584 update_glyph_area ();
588 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
590 if (charmap_index == (int) client_data)
592 charmap_index = (int) client_data;
593 if (charmap_index >= 0)
594 FT_Set_Charmap (face, face->charmaps[charmap_index]);
595 update_glyph_area ();
599 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
601 if ((int) client_data < 0)
603 if (glyph_rec.n_glyphs > 0)
605 if ((int) client_data == -2)
606 glyph_rec.n_glyphs--;
608 glyph_rec.n_glyphs = 0;
609 update_render_area ();
612 else if (glyph_rec.n_glyphs < 64)
614 int index = glyph_index + (int) client_data;
616 if (charmap_index >= 0)
617 index = FT_Get_Char_Index (face, (FT_ULong) index);
618 if (bitmap[index].pixmap)
620 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
621 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
622 update_render_area ();
628 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
630 FeatureRec *rec = (FeatureRec *) client_data;
637 XtSetArg (arg[0], XtNlabel, &label);
638 XtGetValues (w, arg, 1);
639 if (! strcmp (label, "all"))
641 else if (! strcmp (label, "none"))
645 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
646 if (rec->features[idx].w == w)
648 if (idx == rec->langsys->FeatureCount)
655 for (i = j = 0; j < rec->langsys->FeatureCount; j++)
657 int index = rec->langsys->FeatureIndex[j];
660 = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
661 rec->features[j].on = on;
666 OTF_Tag tag = rec->features[idx].tag;
669 if (rec->features[i].on)
672 j < rec->langsys->FeatureCount && rec->features[j].on; j++)
673 rec->features[j - 1].tag = rec->features[j].tag;
674 rec->features[j - 1].tag = tag;
675 rec->features[j - 1].on = 0;
679 for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
680 rec->features[i].tag = rec->features[i - 1].tag;
681 rec->features[i].tag = tag;
682 rec->features[i].on = 1;
689 unsigned fore = foreground, back = background;
693 fore = background, back = foreground;
695 if (rec->features[i].on)
697 XtSetArg (arg[0], XtNforeground, back);
698 XtSetArg (arg[1], XtNbackground, fore);
702 XtSetArg (arg[0], XtNforeground, fore);
703 XtSetArg (arg[1], XtNbackground, back);
705 OTF_tag_name (rec->features[i].tag, str);
706 XtSetArg (arg[2], XtNlabel, str);
707 XtSetValues (rec->features[i].w, arg, 3);
713 setup_feature_rec (FeatureRec *rec)
719 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
720 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
722 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
730 XtSetArg (arg[0], XtNborderWidth, 1);
731 XtSetArg (arg[1], XtNborderColor, foreground);
732 XtSetArg (arg[2], XtNsensitive, True);
733 XtSetArg (arg[3], XtNforeground, foreground);
734 XtSetArg (arg[4], XtNbackground, background);
735 for (i = 0; i < rec->langsys->FeatureCount && i < MAX_FEATURE_COUNT; i++)
737 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
738 int index = rec->langsys->FeatureIndex[i];
741 rec->features[i].tag = feature[index].FeatureTag;
742 rec->features[i].on = 0;
743 OTF_tag_name (rec->features[i].tag, label);
744 XtSetArg (arg[5], XtNlabel, label);
745 XtSetValues (rec->features[i].w, arg, 6);
748 XtSetArg (arg[0], XtNborderWidth, 1);
749 XtSetArg (arg[1], XtNborderColor, background);
750 XtSetArg (arg[2], XtNsensitive, False);
751 XtSetArg (arg[3], XtNforeground, foreground);
752 XtSetArg (arg[4], XtNbackground, background);
753 XtSetArg (arg[5], XtNlabel, " ");
754 for (; i < MAX_FEATURE_COUNT; i++)
755 XtSetValues (rec->features[i].w, arg, 6);
759 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
761 if (script_tag == (OTF_Tag) client_data)
763 script_tag = (OTF_Tag) client_data;
764 setup_feature_rec (&gsub);
765 setup_feature_rec (&gpos);
770 create_otf_script_widgets (Widget prev)
778 XtSetArg (arg[0], XtNborderWidth, 0);
779 XtSetArg (arg[1], XtNleft, XawChainLeft);
780 XtSetArg (arg[2], XtNright, XawChainLeft);
781 XtSetArg (arg[3], XtNtop, XawChainTop);
782 XtSetArg (arg[4], XtNbottom, XawChainTop);
783 XtSetArg (arg[5], XtNfromVert, prev);
784 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
785 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
786 XtCreateManagedWidget ("script", labelWidgetClass, prev, arg, 1);
790 n = otf->gsub->ScriptList.ScriptCount;
792 n += otf->gpos->ScriptList.ScriptCount;
793 scripts = alloca (sizeof (OTF_Tag) * n);
796 for (; i < otf->gsub->ScriptList.ScriptCount; i++)
797 scripts[i] = otf->gsub->ScriptList.Script[i].ScriptTag;
800 for (; i < otf->gpos->ScriptList.ScriptCount; i++)
802 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
805 for (j = 0; j < i; j++)
806 if (tag == scripts[j])
815 script_tag = scripts[0];
816 OTF_tag_name (scripts[0], script_name);
819 XtSetArg (arg[0], XtNforeground, background);
820 XtSetArg (arg[1], XtNbackground, foreground);
821 XtCreateManagedWidget (script_name, labelWidgetClass, prev, arg, 2);
827 XtSetArg (arg[0], XtNstate, True);
828 w = XtCreateManagedWidget (script_name, toggleWidgetClass, prev, arg, 1);
829 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[0]);
830 XtSetArg (arg[0], XtNradioGroup, w);
831 for (i = 1; i < n; i++)
833 OTF_tag_name (scripts[i], name);
834 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
835 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[i]);
843 create_otf_widgets (Widget prev, FeatureRec *rec)
849 XtSetArg (arg[0], XtNborderWidth, 0);
850 XtSetArg (arg[1], XtNleft, XawChainLeft);
851 XtSetArg (arg[2], XtNright, XawChainLeft);
852 XtSetArg (arg[3], XtNtop, XawChainTop);
853 XtSetArg (arg[4], XtNbottom, XawChainTop);
854 XtSetArg (arg[5], XtNfromVert, prev);
855 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
856 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
858 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
859 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, NULL, 0);
860 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
861 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, NULL, 0);
862 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
864 for (i = 0; i < MAX_FEATURE_COUNT; i++)
866 w = XtCreateManagedWidget ("", commandWidgetClass, prev, arg, 1);
867 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
868 rec->features[i].w = w;
871 setup_feature_rec (rec);
878 String quit_action = "<KeyPress>q: set() notify() unset()";
879 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
880 <KeyPress>Home: set() notify() unset()";
881 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
882 <KeyPress>Up: set() notify() unset()";
883 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
884 <KeyPress>Left: set() notify() unset()";
885 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
886 <KeyPress>Right: set() notify() unset()";
887 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
888 <KeyPress>Down: set() notify() unset()";
889 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
890 <KeyPress>End: set() notify() unset()";
894 String trans = "<Expose>: Expose()";
896 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
897 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
899 XtSetArg (arg[0], XtNleft, XawChainLeft);
900 XtSetArg (arg[1], XtNright, XawChainLeft);
901 XtSetArg (arg[2], XtNtop, XawChainTop);
902 XtSetArg (arg[3], XtNbottom, XawChainTop);
903 XtSetArg (arg[4], XtNborderWidth, 0);
904 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
905 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
907 XtSetArg (arg[6], XtNfromVert, command_area);
908 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
910 XtSetArg (arg[4], XtNborderWidth, 0);
911 XtSetArg (arg[5], XtNfromVert, navi_area);
912 XtSetArg (arg[6], XtNdefaultDistance, 0);
913 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
915 XtSetArg (arg[5], XtNfromVert, glyph_area);
916 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
919 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
920 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
921 command_area, arg, 1);
922 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
924 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
925 command_area, arg, 1);
926 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
928 XtSetArg (arg[0], XtNborderWidth, 0);
929 XtSetArg (arg[1], XtNwidth, 10);
930 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
932 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
933 XtSetArg (arg[0], XtNstate, True);
934 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
935 command_area, arg, 1);
936 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
937 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
938 for (i = 0; i < face->num_charmaps; i++)
940 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
942 command_area, arg, 1);
943 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
946 XtSetArg (arg[0], XtNlabel, " |< (f)");
947 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
948 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
950 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
951 XtSetArg (arg[0], XtNlabel, "<< (P)");
952 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
953 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
955 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
956 XtSetArg (arg[0], XtNlabel, "< (p)");
957 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
958 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
960 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
961 XtSetArg (arg[0], XtNlabel, " 0000 ");
962 range = XtCreateManagedWidget ("range", labelWidgetClass,
964 XtSetArg (arg[0], XtNforeground, &foreground);
965 XtSetArg (arg[1], XtNbackground, &background);
966 XtGetValues (range, arg, 2);
968 XtSetArg (arg[0], XtNlabel, "> (n)");
969 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
970 next = XtCreateManagedWidget ("next", commandWidgetClass,
972 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
973 XtSetArg (arg[0], XtNlabel, ">> (N)");
974 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
975 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
977 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
978 XtSetArg (arg[0], XtNlabel, ">| (l)");
979 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
980 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
982 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
984 XtSetArg (arg[0], XtNleft, XawChainLeft);
985 XtSetArg (arg[1], XtNright, XawChainLeft);
986 XtSetArg (arg[2], XtNtop, XawChainTop);
987 XtSetArg (arg[3], XtNbottom, XawChainTop);
989 for (i = 0; i < 8; i++)
995 sprintf (str, "%XX", i);
996 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
997 XtSetArg (arg[n], XtNlabel, str), n++;
998 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1000 XtSetArg (arg[n], XtNfromVert, w), n++;
1001 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1002 index_label[i] = head;
1003 for (j = 0; j < 16; j++)
1009 XtSetArg (arg[n], XtNfromVert, w), n++;
1011 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1013 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1014 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1015 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1016 glyph_area, arg, n);
1017 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1021 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1022 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1023 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1024 XtSetArg (arg[6], XtNfromHoriz, w);
1025 XtSetArg (arg[7], XtNborderWidth, 0);
1027 for (j = 0; j < 16; j++)
1031 sprintf (str, "X%X", j);
1032 XtSetArg (arg[8], XtNlabel, str);
1033 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1034 XtSetArg (arg[6], XtNfromHoriz, w);
1037 XtSetArg (arg[0], XtNleft, XawChainLeft);
1038 XtSetArg (arg[1], XtNright, XawChainLeft);
1039 XtSetArg (arg[2], XtNtop, XawChainTop);
1040 XtSetArg (arg[3], XtNbottom, XawChainTop);
1041 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1042 XtSetArg (arg[5], XtNborderWidth, 0);
1043 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1044 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1045 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1046 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1047 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1049 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1050 XtSetArg (arg[5], XtNborderWidth, 0);
1051 XtSetArg (arg[6], XtNfromVert, w);
1052 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1054 XtSetArg (arg[0], XtNborderWidth, 0);
1055 XtSetArg (arg[1], XtNlabel, "raw: ");
1056 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1058 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1059 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1064 OTF_get_table (otf, "GSUB");
1065 OTF_get_table (otf, "GPOS");
1066 w = create_otf_script_widgets (w);
1069 gsub.label = "GSUB";
1070 gsub.gsub_gpos = otf->gsub;
1071 w = create_otf_widgets (w, &gsub);
1075 gpos.label = "GPOS";
1076 gpos.gsub_gpos = otf->gpos;
1077 w = create_otf_widgets (w, &gpos);
1081 XtSetArg (arg[6], XtNfromVert, w);
1082 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1083 XtSetArg (arg[0], XtNborderWidth, 0);
1084 XtSetArg (arg[1], XtNlabel, "seq: ");
1085 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1087 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1088 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1090 XtInstallAllAccelerators (shell, shell);
1094 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1096 XTextProperty text_prop;
1097 char *pname = "otfview";
1098 char *fname = basename (filename);
1099 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1101 sprintf (name, "%s - %s", pname, fname);
1102 text_prop.value = (unsigned char *) name;
1103 text_prop.encoding = XA_STRING;
1104 text_prop.format = 8;
1105 text_prop.nitems = strlen (name);
1106 XSetWMName (display, XtWindow (shell), &text_prop);
1109 /* Format MSG by FMT and print the result to the stderr, and exit. */
1111 #define FATAL_ERROR(fmt, arg) \
1113 fprintf (stderr, fmt, arg); \
1118 x_error_handler (Display *display, XErrorEvent *error)
1125 main (int argc, char **argv)
1127 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1131 OTF_GlyphString gstring;
1136 int fixed_pixel_size = 0;
1139 pixel_size = DEFAULT_PIXEL_SIZE;
1141 char *str = getenv ("PIXEL_SIZE");
1143 if (str && (i = atoi (str)) > 0)
1146 fixed_pixel_size = 1;
1150 gstring.size = gstring.used = 256;
1151 g = calloc (256, sizeof (OTF_Glyph));
1154 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1155 shellWidgetClass, arg, 0);
1156 display = XtDisplay (shell);
1157 /*XSynchronize (display, True);*/
1158 XSetErrorHandler (x_error_handler);
1159 display_width = DisplayWidth (display,
1160 XScreenNumberOfScreen (XtScreen (shell)));
1161 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1163 font = XLoadQueryFont (display, "fixed");
1165 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1167 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
1168 basename (argv[0]));
1172 if (strstr (filename, ".ttf")
1173 || strstr (filename, ".TTF")
1174 || strstr (filename, ".otf")
1175 || strstr (filename, ".OTF"))
1177 otf = OTF_open (filename);
1179 || OTF_get_table (otf, "head") < 0
1180 || OTF_get_table (otf, "cmap") < 0
1181 || (OTF_check_table (otf, "GSUB") < 0
1182 && OTF_check_table (otf, "GPOS") < 0))
1186 if ((err = FT_Init_FreeType (&library)))
1187 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1188 err = FT_New_Face (library, filename, 0, &face);
1189 if (err == FT_Err_Unknown_File_Format)
1190 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1192 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
1193 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1194 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1200 filename = basename (filename);
1201 sprintf (title, "%s family:%s style:%s",
1202 filename, face->family_name, face->style_name);
1203 XtSetArg (arg[0], XtNtitle, title);
1204 XtSetValues (shell, arg, 1);
1207 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1208 * pixel_size / face->units_per_EM);
1209 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1211 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1212 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1213 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1214 * pixel_size / face->units_per_EM);
1216 if (glyph_width < FONT_WIDTH * 4)
1217 glyph_width = FONT_WIDTH * 4;
1219 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1220 * pixel_size / face->units_per_EM);
1222 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1223 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1224 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1225 glyph_width, glyph_height, 1);
1228 unsigned long valuemask = GCFunction | GCLineWidth;
1231 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1232 values.function = GXset;
1233 values.line_width = 1;
1234 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1235 values.function = GXor;
1236 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1237 values.function = GXcopyInverted;
1238 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1241 XFillRectangle (display, none_pixmap, gc, 0, 0,
1242 glyph_width, glyph_height);
1243 XDrawString (display, none_pixmap, gc_inv,
1244 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1245 glyph_height / 2, "none", 4);
1247 render_width = (glyph_width + 4) * 15 + 1;
1248 render_height = glyph_height + 2;
1250 charmap_rec[0].platform_id = -1;
1251 charmap_rec[0].encoding_id = -1;
1252 strcpy (charmap_rec[0].name, "no charmap");
1254 for (i = 0; i < face->num_charmaps; i++)
1256 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1257 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1258 sprintf (charmap_rec[i + 1].name, "%d-%d",
1259 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1260 if (face->charmaps[i]->platform_id == 0
1261 || (face->charmaps[i]->platform_id == 3
1262 && face->charmaps[i]->encoding_id == 1))
1263 strcat (charmap_rec[i + 1].name, " (unicode)");
1264 else if (face->charmaps[i]->platform_id == 1
1265 && face->charmaps[i]->encoding_id == 0)
1266 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1269 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1270 render_width, render_height, 1);
1271 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1272 render_width, render_height, 1);
1274 memset (bitmap, 0, sizeof (bitmap));
1278 update_glyph_area ();
1279 update_render_area ();
1281 XtAppAddActions (context, actions, XtNumber (actions));
1282 XtRealizeWidget (shell);
1283 XtAppMainLoop (context);