1 /* otfview.c -- View glyphs of OpenType fonts.
3 Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010
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. */
36 #ifdef HAVE_X11_XAW_COMMAND_H
38 #include <X11/Xatom.h>
39 #include <X11/Intrinsic.h>
40 #include <X11/StringDefs.h>
41 #include <X11/Shell.h>
42 #include <X11/Xaw/Command.h>
43 #include <X11/Xaw/Toggle.h>
44 #include <X11/Xaw/Box.h>
45 #include <X11/Xaw/Form.h>
46 #include <X11/Xaw/Viewport.h>
49 #include FT_FREETYPE_H
53 #define CAST_FROM_XTPOINTER(TYPE, DATA, VAR) \
55 long TYPE temp = (long TYPE) (DATA); \
59 #define XtAddCallbackWithCast(TYPE, W, PROC, VAR) \
61 long TYPE temp = (long TYPE) (VAR); \
62 XtAddCallback (W, XtNcallback, PROC, (XtPointer) temp); \
66 #define DEFAULT_PIXEL_SIZE 30
69 #define DEFAULT_FONT_NAME "6x13"
71 #define FONT_HEIGHT (font->ascent + font->descent)
72 #define FONT_ASCENT (font->ascent)
73 #define FONT_DESCENT (font->descent)
74 #define FONT_WIDTH (font->max_bounds.width)
78 +--- frame (form) -------------------------+
79 | +--- command_area (box) ---------------+ |
80 | | quit dump charmap ... | |
81 | +--------------------------------------+ |
82 | +---- navi_area (box) -----------------+ |
83 | | FIRST PREV prev range next NEXT LAST | |
84 | +--------------------------------------+ |
85 | +--- glyph_area (form) ----------------+ |
86 | | idxh[0] glyph[0] ... glyph[15] | |
88 | | idxh[7] glyph[112] ... glyph[127]| |
89 | | idxl[0] ... idxl[15] | |
90 | +--------------------------------------+ |
91 | +--- script_area (box) ----------------+ |
92 | | script(langsys) DFLT ... | |
93 | +--------------------------------------+ |
94 | +---- uvs_area (box) (optional) -------+ |
96 | +--------------------------------------+ |
97 | +--- render_area (form) ---------------+ |
98 | | clear del bidi alt_subst | |
99 | | +--- raw (box) --------------------+ | |
100 | | | raw_label raw_image | | |
101 | | +----------------------------------+ | |
102 | | GSUB all none features... | |
103 | | GPOS all none features... | |
104 | | +--- seq (box) --------------------+ | |
105 | | | seq_label seq_image | | |
106 | | +----------------------------------+ | |
107 | | +--- code (box) -------------------+ | |
108 | | | code_label code_list ... | | |
109 | | +----------------------------------+ | |
110 | +--------------------------------------+ |
111 +------------------------------------------+ */
113 Widget command_area, quit, dump, *charmap;
114 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
115 Widget glyph_area, glyph[128], index_label[8];
116 Widget uvs_area, uvs_label;
117 Widget render_area, clear, del, bidi, alt_subst, raw, seq, code;
118 Widget raw_label, raw_image, seq_label, seq_image, code_label, code_list;
119 unsigned long foreground, background;
131 OTF_GSUB_GPOS *gsub_gpos;
132 OTF_LangSys *langsys;
134 FeatureElement *features;
138 FeatureRec gsub, gpos;
140 /* Currently selected script and langsys. */
141 OTF_Tag script_tag, langsys_tag;
146 GC gc, gc_set, gc_or, gc_inv;
150 unsigned width, height;
155 BitmapRec bitmap[0x110000];
157 int render_width, render_height;
158 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
172 int do_alternate_subst;
173 unsigned glyph_width, glyph_height;
174 int glyph_x, glyph_y;
183 OTF_EncodingSubtable14 *sub14 = NULL;
195 create_pixmap (int index)
197 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
203 bitmap[index].pixmap = none_pixmap;
206 ximage.height = face->glyph->bitmap.rows;
207 ximage.width = face->glyph->bitmap.width;
209 ximage.bits_per_pixel = 1;
211 ximage.format = XYPixmap;
212 ximage.data = (char *) face->glyph->bitmap.buffer;
213 ximage.byte_order = MSBFirst;
214 ximage.bitmap_unit = 8;
215 ximage.bitmap_bit_order = MSBFirst;
216 ximage.bitmap_pad = 8;
217 ximage.bytes_per_line = face->glyph->bitmap.pitch;
218 XInitImage (&ximage);
219 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
220 glyph_width, glyph_height, 1);
221 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
222 XPutImage (display, pixmap, gc, &ximage, 0, 0,
223 glyph_x + face->glyph->bitmap_left,
224 glyph_y - face->glyph->bitmap_top,
225 ximage.width, ximage.height);
226 bitmap[index].pixmap = pixmap;
227 bitmap[index].width = ximage.width;
228 bitmap[index].height = ximage.height;
229 bitmap[index].x = face->glyph->bitmap_left;
230 bitmap[index].y = - face->glyph->bitmap_top;
231 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
242 for (i = 0; i < 128; i++)
244 int index = glyph_index + i;
246 if (charmap_index >= 0)
247 index = FT_Get_Char_Index (face, (FT_ULong) index);
248 if (charmap_index >= 0 && ! index)
249 XtSetArg (arg[0], XtNbitmap, none_pixmap);
252 if (! bitmap[index].pixmap)
253 create_pixmap (index);
254 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
256 XtSetValues (glyph[i], arg, 1);
259 msb = (glyph_index >> 7) % 2 ? 8 : 0;
260 for (i = 0; i < 8; i++)
264 sprintf (str, "%XX", i | msb );
265 XtSetArg (arg[0], XtNheight, glyph_height + 5);
266 XtSetArg (arg[1], XtNlabel, str);
267 XtSetValues (index_label[i], arg, 2);
270 if (glyph_index < 0x10000)
271 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
273 sprintf (buf, "%06X-%06X", glyph_index, glyph_index + 0x7F);
274 XtSetArg (arg[0], XtNlabel, buf);
275 XtSetValues (range, arg, 1);
279 update_uvs_area (int c)
281 OTF_GlyphID code[256];
285 OTF_get_variation_glyphs (otf, c, code);
287 for (i = 0; i < 256; i++)
291 XtSetArg (arg[0], XtNsensitive, True);
293 XtSetArg (arg[0], XtNsensitive, False);
294 XtSetValues (uvs[i].w, arg, 1);
300 get_features (OTF_FeatureList *list, FeatureRec *rec)
305 if (! rec->langsys || ! rec->features)
307 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
308 if (rec->features[i].on)
312 str = malloc (n * 5);
313 for (i = 0, p = str; i < rec->langsys->FeatureCount; i++)
314 if (rec->features[i].on)
316 OTF_tag_name (rec->features[i].tag, p);
325 #define DEVICE_DELTA(table, size) \
326 (((table).DeltaValue \
327 && ((size) >= (table).StartSize && (size) <= (table).EndSize)) \
328 ? (table).DeltaValue[(size) >= (table).StartSize] \
332 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
333 OTF_Glyph *g, int *x, int *y)
335 if (anchor->AnchorFormat == 2)
338 int ap = anchor->f.f1.AnchorPoint;
340 FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
341 outline = &ft_face->glyph->outline;
342 if (ap < outline->n_points)
344 *x = outline->points[ap].x;
345 *y = outline->points[ap].y;
348 else if (anchor->AnchorFormat == 3)
350 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
351 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
359 OTF_GlyphString gstring;
360 OTF_Glyph *g, *prev, *base, *mark;
362 int len = glyph_rec.n_glyphs;
364 int unitsPerEm = face->units_per_EM;
368 gstring.size = gstring.used = len;
369 gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
370 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
371 for (i = 0; i < len; i++)
373 gstring.glyphs[i].c = glyph_rec.codes[i];
374 if (charmap_index < 0)
375 gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
378 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
379 XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
382 char *script_name = NULL, *langsys_name = NULL, buf[10];
388 OTF_tag_name (script_tag, script_name);
392 langsys_name = buf + 5;
393 OTF_tag_name (langsys_tag, langsys_name);
396 OTF_drive_cmap (otf, &gstring);
397 OTF_drive_gdef (otf, &gstring);
400 str = get_features (&otf->gsub->FeatureList, &gsub);
403 if (do_alternate_subst)
404 OTF_drive_gsub_alternate (otf, &gstring,
405 script_name, langsys_name, str);
408 OTF_drive_gsub_with_log (otf, &gstring,
409 script_name, langsys_name, str);
410 logsize = gstring.used * 2;
411 log = alloca (sizeof (OTF_Tag) * logsize);
412 for (i = 0; i < gstring.used; i++)
414 int idx = gstring.glyphs[i].positioning_type >> 4;
416 log[i] = otf->gsub->FeatureList.Feature[idx - 1].FeatureTag;
426 str = get_features (&otf->gpos->FeatureList, &gpos);
429 OTF_drive_gpos_with_log (otf, &gstring,
430 script_name, langsys_name, str);
433 if (logsize < gstring.used)
435 OTF_Tag *log2 = alloca (sizeof (OTF_Tag) * gstring.used);
436 memset (log2, 0, sizeof (OTF_Tag) * gstring.used);
437 memcpy (log2, log, sizeof (OTF_Tag) * logsize);
438 logsize = gstring.used;
444 logsize = gstring.used;
445 log = alloca (sizeof (OTF_Tag) * logsize);
446 memset (log, 0, sizeof (OTF_Tag) * logsize);
448 for (i = 0; i < gstring.used; i++)
450 int idx = gstring.glyphs[i].positioning_type >> 4;
452 log[i] = otf->gpos->FeatureList.Feature[idx - 1].FeatureTag;
465 for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
466 prev < g; prev++, g--)
467 temp = *prev, *prev = *g, *g = temp;
468 for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
469 if (g->GlyphClass == 3)
473 while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
475 for (g0 = g; prev < g0; prev++, g0--)
476 temp = *prev, *prev = *g, *g = temp;
482 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
483 i < gstring.used; i++, prev = g++)
485 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
486 int xoff = 0, yoff = 0;
488 int advance = bmp->advance;
490 if (gstring.glyphs[i].glyph_id && ! bmp->pixmap)
492 create_pixmap (gstring.glyphs[i].glyph_id);
495 advance = bmp->advance;
497 if (g->positioning_type & 0xF)
501 switch (g->positioning_type & 0xF)
505 int format = g->f.f1.format;
507 if (format & OTF_XPlacement)
508 xoff += g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
509 if (format & OTF_XPlaDevice)
510 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
511 if (format & OTF_YPlacement)
512 yoff += g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
513 if (format & OTF_YPlaDevice)
514 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
515 if (format & OTF_XAdvance)
516 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
517 if (format & OTF_XAdvDevice)
518 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice,
524 /* Not yet supported. */
530 prev_width = base_width;
531 goto label_adjust_anchor;
532 default: /* i.e. case 6 */
539 int base_x, base_y, mark_x, mark_y;
541 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
542 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
543 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
544 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
546 if (g->f.f4.base_anchor->AnchorFormat != 1)
547 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
548 if (g->f.f4.mark_anchor->AnchorFormat != 1)
549 adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
550 xoff = (base_x - prev_width) - mark_x;
551 yoff = base_y - mark_y;
554 if (i + 1 == gstring.used
555 || gstring.glyphs[i + 1].glyph_id
556 || ! (gstring.glyphs[i + 1].positioning_type & 0xF))
562 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
563 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
564 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
567 if (g->GlyphClass == OTF_GlyphClass0)
568 base = mark = g, base_width = advance;
569 else if (g->GlyphClass == OTF_GlyphClassMark)
572 base = g, base_width = advance;
575 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
576 XtSetValues (seq_image, arg, 1);
578 if (gstring.used > 0)
580 int size = render_width / FONT_WIDTH;
581 char *buf = alloca (size + 1);
584 sprintf (buf, "%04X", gstring.glyphs[0].glyph_id);
587 OTF_tag_name (log[0], name);
588 sprintf (buf + 4, " (%s)", name);
593 for (i = 1; i < gstring.used && x + 5 < size; i++, x += 5)
595 sprintf (buf + x, " %04X", gstring.glyphs[i].glyph_id);
596 if (log && log[i] && x + 11 < size)
598 OTF_tag_name (log[i], name);
599 sprintf (buf + x + 5, "(%s)", name);
606 XtSetArg (arg[0], XtNlabel, buf);
607 XtSetValues (code_list, arg, 1);
610 free (gstring.glyphs);
615 update_render_area ()
621 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
622 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
624 if (glyph_rec.glyphs[i] >= 0)
626 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
629 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
630 0, 0, glyph_width, glyph_height,
631 (glyph_width + 4) * i + 1, 1);
632 XDrawRectangle (display, raw_pixmap, gc_set,
633 (glyph_width + 4) * i, 0,
634 glyph_width + 1, glyph_height + 1);
635 XDrawLine (display, raw_pixmap, gc_set,
636 (glyph_width + 4) * i + 1 + glyph_x, 1,
637 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
638 XDrawLine (display, raw_pixmap, gc_set,
639 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
640 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
643 sprintf (buf, "%04X", glyph_rec.codes[i]);
644 XDrawString (display, raw_pixmap, gc_inv,
645 (glyph_width + 4) * i + 1
646 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
647 glyph_height + 2 + FONT_HEIGHT, buf, 4);
651 /* Variation Selector */
652 int idx = - glyph_rec.glyphs[i];
655 sprintf (buf, "%03d", idx);
656 XDrawRectangle (display, raw_pixmap, gc_set,
657 (glyph_width + 4) * i, 0,
658 glyph_width + 1, glyph_height + 1);
659 XDrawString (display, raw_pixmap, gc_set,
660 (glyph_width + 4) * i + 1
661 + (glyph_width - XTextWidth (font, "VS", 2)) / 2,
662 1 + glyph_height / 2, "VS", 2);
663 XDrawString (display, raw_pixmap, gc_set,
664 (glyph_width + 4) * i + 1
665 + (glyph_width - XTextWidth (font, buf, 3)) / 2,
666 1 + glyph_height / 2 + FONT_ASCENT, buf, 3);
669 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
670 XtSetValues (raw_image, arg, 1);
675 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
677 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
681 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
683 int g_width, g_height;
685 /* unit in points (1/72 inch); to fit in both US-letter and A4 */
686 static int xoff = 30, yoff = 30;
687 static int unit = 30;
688 static int margin = 2;
689 static int title_height = 20, label_height = 10;
690 int total_width = (unit + margin * 2) * 16;
691 int total_height = (unit + margin * 2 + label_height) * 16 + title_height;
692 /* pixel size (dots) */
695 char *name = alloca (strlen (filename) + 10);
697 int index = (glyph_index / 0x100) * 0x100;
700 g_width = face->bbox.xMax - face->bbox.xMin;
701 g_height = face->bbox.yMax - face->bbox.yMin;
702 if (g_width > g_height)
704 scale = g_width * size;
705 g_x = face->bbox.xMin * unit / g_width;
706 g_y = face->bbox.yMin * unit / g_width;
710 scale = g_height * size;
711 g_x = face->bbox.xMin * unit / g_height;
712 g_y = face->bbox.yMin * unit / g_height;
714 scale /= face->units_per_EM;
716 FT_Set_Pixel_Sizes (face, 0, size);
718 sprintf (name, "%s-%04X.ps", face->family_name, index);
719 printf ("Writing %s ... ", name);
721 fp = fopen (name, "w");
723 fprintf (fp, "%s\n", "%!PS-Adobe-2.0 EPSF-2.0");
724 fprintf (fp, "%s\n", "%%Creater: otfview");
725 fprintf (fp, "%s %s(%s)-%04X\n", "%%Title:",
726 face->family_name, face->style_name, index);
727 fprintf (fp, "%s\n", "%%Pages: 1");
728 fprintf (fp, "%s %d %d %d %d\n", "%%BoundingBox:",
729 xoff, yoff, xoff + total_width, yoff + total_height);
730 fprintf (fp, "%s\n", "%%EndComments");
731 fprintf (fp, "%s\n", "%%BeginProlog");
732 fprintf (fp, "/W %d def\n", unit + margin * 2);
733 fprintf (fp, "/H %d def\n", unit + margin * 2 + label_height);
734 fprintf (fp, "/STR 10 string def\n");
735 fprintf (fp, "/DrawIndex {\n");
736 fprintf (fp, " I 16 lt { (000) show } { I 256 lt { (00) show } { I 4096 lt { (0) show} if } ifelse } ifelse I 16 STR cvrs show\n");
737 fprintf (fp, "} def\n");
738 fprintf (fp, "/DrawTitle {\n");
739 fprintf (fp, " /Courier findfont 20 scalefont setfont\n");
740 fprintf (fp, " %d %d 4 add moveto\n", xoff + total_width / 2,
741 yoff + total_height - title_height + 2);
742 fprintf (fp, " (%s(%s)-%04X) dup stringwidth pop 2 div neg 0 rmoveto show\n",
743 face->family_name, face->style_name, index);
744 fprintf (fp, "} def\n");
745 fprintf (fp, "/DrawFrame { gsave %d %d translate 0 setlinewidth\n",
747 fprintf (fp, " /Courier findfont 10 scalefont setfont\n");
748 fprintf (fp, " /I %d def\n", index);
749 fprintf (fp, " 0 1 16 { W mul 0 moveto 0 H 16 mul rlineto stroke } for\n");
750 fprintf (fp, " 0 1 16 { H mul 0 exch moveto W 16 mul 0 rlineto stroke } for\n");
751 fprintf (fp, " 0 1 15 { H mul %d add 0 exch moveto W 16 mul 0 rlineto stroke } for\n", label_height);
752 fprintf (fp, " 15 -1 0 { gsave H mul 0 exch translate 0 0 moveto\n");
753 fprintf (fp, " 0 1 15 { gsave W mul 0 moveto\n");
754 fprintf (fp, " 4 2 rmoveto DrawIndex /I I 1 add def grestore} for\n");
755 fprintf (fp, " grestore } for grestore } def\n");
756 fprintf (fp, "%s\n", "%%EndProlog");
757 fprintf (fp, "DrawTitle DrawFrame\n");
759 for (i = 0; i < 16; i++)
760 for (j = 0; j < 16; j++, index++)
764 if (charmap_index >= 0)
765 idx = FT_Get_Char_Index (face, (FT_ULong) index);
769 && FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0
770 && face->glyph->bitmap.rows > 0
771 && face->glyph->bitmap.width > 0)
773 unsigned char *p = face->glyph->bitmap.buffer;
774 int width = (face->glyph->bitmap.width - 1) / 8 + 1;
776 fprintf (fp, "gsave %f %f translate %d %d scale 0 0 moveto\n",
777 xoff + (unit + margin * 2) * j + margin - g_x,
778 yoff + (unit + label_height + margin * 2) * (15 - i) + label_height + margin - g_y,
780 fprintf (fp, "%d %d true [%f 0 0 %f %d %d]\n",
781 width * 8, face->glyph->bitmap.rows,
782 scale, -scale, -face->glyph->bitmap_left,
783 face->glyph->bitmap_top);
785 for (k = 0; k < face->glyph->bitmap.rows;
786 k++, p += face->glyph->bitmap.pitch)
788 for (l = 0; l < width; l++)
789 fprintf (fp, "%02X", p[l]);
792 fprintf (fp, ">} imagemask grestore\n");
796 int boxsize = unit + margin * 2;
798 fprintf (fp, "gsave 0 setlinewidth %d %d translate\n",
800 yoff + (boxsize + label_height) * (15 - i) + label_height);
801 fprintf (fp, "0 0 moveto %d %d lineto stroke\n",
803 fprintf (fp, "0 %d moveto %d 0 lineto stroke grestore\n",
807 fprintf (fp, "showpage\n");
811 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
816 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
818 int old_glyph_index = glyph_index;
821 CAST_FROM_XTPOINTER (int, client_data, data);
823 if (data == -3 && glyph_index > 0)
825 else if (data == -2 && glyph_index > 0)
826 glyph_index = (glyph_index - 1) & 0x1FF000;
827 else if (data == -1 && glyph_index > 0)
829 else if (data == 1 && glyph_index < 0x10FF80)
831 else if (data == 2 && glyph_index < 0x10F000)
832 glyph_index = (glyph_index + 0x1000) & 0x1FF000;
833 else if (data == 3 && glyph_index < 0x10F000)
834 glyph_index = 0x10FF80;
835 if (glyph_index != old_glyph_index)
836 update_glyph_area ();
840 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
844 CAST_FROM_XTPOINTER (int, client_data, data);
846 if (charmap_index == data)
848 charmap_index = data;
849 if (charmap_index >= 0)
850 FT_Set_Charmap (face, face->charmaps[charmap_index]);
851 update_glyph_area ();
855 UVSProc (Widget w, XtPointer client_data, XtPointer call_data)
859 OTF_VariationSelectorRecord *record;
862 CAST_FROM_XTPOINTER (unsigned, client_data, idx);
863 selector = uvs[idx].c;
865 if (glyph_rec.n_glyphs >= 64)
867 for (i = 0; i < sub14->nRecords; i++)
869 record = sub14->Records + i;
870 if (record->varSelector == selector)
873 if (i < sub14->nRecords)
875 if (glyph_rec.n_glyphs > 0
876 && glyph_rec.glyphs[glyph_rec.n_glyphs - 1] < 0)
877 glyph_rec.n_glyphs--;
878 glyph_rec.codes[glyph_rec.n_glyphs] = selector;
879 glyph_rec.glyphs[glyph_rec.n_glyphs++] = - idx - 1;
880 update_render_area ();
885 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
889 CAST_FROM_XTPOINTER (int, client_data, data);
893 if (glyph_rec.n_glyphs > 0)
896 glyph_rec.n_glyphs--;
898 glyph_rec.n_glyphs = 0;
899 update_render_area ();
902 else if (glyph_rec.n_glyphs < 64)
904 int index = glyph_index + data;
906 if (charmap_index >= 0)
907 index = FT_Get_Char_Index (face, (FT_ULong) index);
908 if (bitmap[index].pixmap)
910 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + data;
911 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
913 update_uvs_area (glyph_index + data);
914 update_render_area ();
920 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
924 reversed = ! reversed;
926 XtSetArg (arg[0], XtNlabel, "L<-R");
928 XtSetArg (arg[0], XtNlabel, "L->R");
929 XtSetValues (w, arg, 1);
934 AltSubstProc (Widget w, XtPointer client_data, XtPointer call_data)
936 do_alternate_subst = ! do_alternate_subst;
941 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
943 FeatureRec *rec = (FeatureRec *) client_data;
950 XtSetArg (arg[0], XtNlabel, &label);
951 XtGetValues (w, arg, 1);
952 if (! strcmp (label, "all"))
954 else if (! strcmp (label, "none"))
958 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
959 if (rec->features[idx].w == w)
961 if (idx == rec->langsys->FeatureCount)
969 for (i = 0; i < rec->langsys->FeatureCount; i++)
970 if (rec->features[i].on != on)
972 rec->features[i].on = on;
975 XtSetArg (arg[0], XtNborderWidth, 3);
976 XtSetArg (arg[1], XtNinternalHeight, 2);
977 XtSetArg (arg[2], XtNinternalWidth, 2);
981 XtSetArg (arg[0], XtNborderWidth, 1);
982 XtSetArg (arg[1], XtNinternalHeight, 4);
983 XtSetArg (arg[2], XtNinternalWidth, 4);
985 OTF_tag_name (rec->features[i].tag, str);
986 XtSetArg (arg[3], XtNlabel, str);
987 XtSetValues (rec->features[i].w, arg, 4);
994 rec->features[idx].on = ! rec->features[idx].on;
995 if (rec->features[idx].on)
997 XtSetArg (arg[0], XtNborderWidth, 3);
998 XtSetArg (arg[1], XtNinternalHeight, 2);
999 XtSetArg (arg[2], XtNinternalWidth, 2);
1003 XtSetArg (arg[0], XtNborderWidth, 1);
1004 XtSetArg (arg[1], XtNinternalHeight, 4);
1005 XtSetArg (arg[2], XtNinternalWidth, 4);
1007 OTF_tag_name (rec->features[idx].tag, str);
1008 XtSetArg (arg[3], XtNlabel, str);
1009 XtSetValues (rec->features[idx].w, arg, 4);
1015 setup_feature_rec (FeatureRec *rec)
1020 rec->langsys = NULL;
1021 if (! rec->gsub_gpos)
1023 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
1024 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
1026 OTF_Script *script = rec->gsub_gpos->ScriptList.Script + i;
1030 for (j = 0; j < script->LangSysCount; j++)
1031 if (script->LangSysRecord[j].LangSysTag == langsys_tag)
1033 rec->langsys = script->LangSys + j;
1038 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
1046 XtSetArg (arg[0], XtNborderWidth, 1);
1047 XtSetArg (arg[1], XtNinternalHeight, 4);
1048 XtSetArg (arg[2], XtNinternalWidth, 4);
1049 XtSetArg (arg[3], XtNborderColor, foreground);
1050 XtSetArg (arg[4], XtNsensitive, True);
1051 for (i = 0; i < rec->langsys->FeatureCount; i++)
1053 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
1054 int index = rec->langsys->FeatureIndex[i];
1057 if (! rec->features[i].w)
1059 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
1060 rec->parent, arg, 0);
1061 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1062 rec->features[i].w = w;
1065 rec->features[i].tag = feature[index].FeatureTag;
1066 rec->features[i].on = 0;
1067 OTF_tag_name (rec->features[i].tag, label);
1068 XtSetArg (arg[5], XtNlabel, label);
1069 XtSetValues (rec->features[i].w, arg, 6);
1072 XtSetArg (arg[0], XtNborderColor, background);
1073 XtSetArg (arg[1], XtNsensitive, False);
1074 XtSetArg (arg[2], XtNlabel, " ");
1075 for (; i < rec->num_features; i++)
1077 if (! rec->features[i].w)
1079 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
1080 rec->parent, arg, 0);
1081 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1082 rec->features[i].w = w;
1084 XtSetValues (rec->features[i].w, arg, 3);
1089 compose_script_langsys (OTF_Tag script, OTF_Tag langsys, char *name)
1091 OTF_tag_name (script, name);
1095 OTF_tag_name (langsys, name + 5);
1102 decompose_script_langsys (OTF_Tag *script, OTF_Tag *langsys, char *name)
1104 *script = OTF_tag (name);
1106 *langsys = OTF_tag (name + 5);
1112 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
1115 OTF_Tag script, langsys;
1118 XtSetArg (arg[0], XtNlabel, &name);
1119 XtGetValues (w, arg, 1);
1120 decompose_script_langsys (&script, &langsys, name);
1121 if (script_tag == script && langsys_tag == langsys)
1123 script_tag = script;
1124 langsys_tag = langsys;
1125 setup_feature_rec (&gsub);
1126 setup_feature_rec (&gpos);
1131 create_otf_script_widgets (Widget prev)
1135 int n, prev_n, i, j;
1143 XtSetArg (arg[0], XtNborderWidth, 0);
1144 XtSetArg (arg[1], XtNleft, XawChainLeft);
1145 XtSetArg (arg[2], XtNright, XawChainLeft);
1146 XtSetArg (arg[3], XtNtop, XawChainTop);
1147 XtSetArg (arg[4], XtNbottom, XawChainTop);
1148 XtSetArg (arg[5], XtNfromVert, prev);
1149 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1150 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
1151 XtCreateManagedWidget ("script(langsys)", labelWidgetClass, prev, arg, 1);
1155 for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1156 n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
1158 for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1159 n += otf->gpos->ScriptList.Script[i].LangSysCount + 1;
1160 script_langsys = alloca ((sizeof script_langsys[0]) * n);
1164 for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1166 OTF_Tag tag = otf->gsub->ScriptList.Script[i].ScriptTag;
1168 script_langsys[n].script = tag;
1169 script_langsys[n++].langsys = 0;
1171 < otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1173 = otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1174 for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
1176 script_langsys[n].script = tag;
1177 script_langsys[n++].langsys
1178 = otf->gsub->ScriptList.Script[i].LangSysRecord[j].LangSysTag;
1180 < otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount)
1182 = otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount;
1185 gsub.num_features = nfeatures;
1188 gsub.num_features = nfeatures;
1189 gsub.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1190 memset (gsub.features, 0, (sizeof (FeatureElement)) * nfeatures);
1195 for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1197 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
1201 < otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1203 = otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1204 for (k = 0; k < prev_n; k++)
1205 if (tag == script_langsys[k].script)
1209 script_langsys[n].script = tag;
1210 script_langsys[n++].langsys = 0;
1212 for (j = 0; j < otf->gpos->ScriptList.Script[i].LangSysCount; j++)
1218 OTF_Script *script = otf->gpos->ScriptList.Script + i;
1220 for (l = k; l < prev_n && tag == script_langsys[l].script; l++)
1221 if (script->LangSysRecord[j].LangSysTag
1222 == script_langsys[l].langsys)
1229 script_langsys[n].script = tag;
1230 script_langsys[n++].langsys = 0;
1233 < otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount)
1235 = otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount;
1241 gpos.num_features = nfeatures;
1242 gpos.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1243 memset (gpos.features, 0, (sizeof (FeatureElement)) * nfeatures);
1249 script_tag = script_langsys[0].script;
1250 langsys_tag = script_langsys[0].langsys;
1251 compose_script_langsys (script_tag, langsys_tag, name);
1255 XtSetArg (arg[0], XtNforeground, background);
1256 XtSetArg (arg[1], XtNbackground, foreground);
1257 XtCreateManagedWidget (name, labelWidgetClass, prev, arg, 2);
1262 XtSetArg (arg[0], XtNborderWidth, 0);
1263 XtSetArg (arg[1], XtNwidth, render_width - (FONT_WIDTH * 15));
1264 XtSetArg (arg[2], XtNorientation, XtorientHorizontal);
1265 box = XtCreateManagedWidget ("scritp-list", boxWidgetClass, prev, arg, 2);
1266 XtSetArg (arg[0], XtNstate, True);
1267 w = XtCreateManagedWidget (name, toggleWidgetClass, box, arg, 1);
1268 XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1269 XtSetArg (arg[0], XtNradioGroup, w);
1270 for (i = 1; i < n; i++)
1272 compose_script_langsys (script_langsys[i].script,
1273 script_langsys[i].langsys, name);
1274 w = XtCreateManagedWidget (name, toggleWidgetClass, box, arg, 1);
1275 XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1283 create_otf_widgets (Widget prev, FeatureRec *rec)
1288 XtSetArg (arg[0], XtNborderWidth, 0);
1289 XtSetArg (arg[1], XtNleft, XawChainLeft);
1290 XtSetArg (arg[2], XtNright, XawChainLeft);
1291 XtSetArg (arg[3], XtNtop, XawChainTop);
1292 XtSetArg (arg[4], XtNbottom, XawChainTop);
1293 XtSetArg (arg[5], XtNfromVert, prev);
1294 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1295 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
1297 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
1298 XtSetArg (arg[0], XtNborderWidth, 1);
1299 XtSetArg (arg[1], XtNinternalHeight, 4);
1300 XtSetArg (arg[2], XtNinternalWidth, 4);
1301 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
1302 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1303 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
1304 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1307 setup_feature_rec (rec);
1314 String quit_action = "<KeyPress>q: set() notify() unset()";
1315 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
1316 <KeyPress>Home: set() notify() unset()";
1317 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
1318 <KeyPress>Up: set() notify() unset()";
1319 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
1320 <KeyPress>Left: set() notify() unset()";
1321 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
1322 <KeyPress>Right: set() notify() unset()";
1323 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
1324 <KeyPress>Down: set() notify() unset()";
1325 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
1326 <KeyPress>End: set() notify() unset()";
1330 String trans = "<Expose>: Expose()";
1332 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
1333 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
1335 XtSetArg (arg[0], XtNleft, XawChainLeft);
1336 XtSetArg (arg[1], XtNright, XawChainLeft);
1337 XtSetArg (arg[2], XtNtop, XawChainTop);
1338 XtSetArg (arg[3], XtNbottom, XawChainTop);
1339 XtSetArg (arg[4], XtNborderWidth, 0);
1340 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
1341 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
1343 XtSetArg (arg[6], XtNfromVert, command_area);
1344 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
1346 XtSetArg (arg[4], XtNborderWidth, 0);
1347 XtSetArg (arg[5], XtNfromVert, navi_area);
1348 XtSetArg (arg[6], XtNdefaultDistance, 0);
1349 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
1352 XtSetArg (arg[5], XtNfromVert, glyph_area);
1357 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1358 uvs_area = XtCreateManagedWidget ("uvs-area", boxWidgetClass,
1360 XtSetArg (arg2[0], XtNborderWidth, 0);
1361 XtSetArg (arg2[1], XtNlabel, "Variation Selector: ");
1362 uvs_label = XtCreateManagedWidget ("uvs-label", labelWidgetClass,
1364 XtSetArg (arg2[0], XtNborderWidth, 1);
1365 for (i = 0; i < sub14->nRecords; i++)
1367 OTF_VariationSelectorRecord *record = sub14->Records + i;
1368 unsigned selector = record->varSelector;
1372 idx = (selector <= 0xFE0F ? selector - 0xFE00
1373 : selector - 0xE0100 + 16);
1376 uvs[idx].c = selector;
1377 sprintf (lbl, "%03d", idx + 1);
1378 XtSetArg (arg2[1], XtNlabel, lbl);
1379 XtSetArg (arg2[2], XtNsensitive, False);
1380 uvs[idx].w = XtCreateManagedWidget ("lbl", commandWidgetClass,
1382 XtAddCallbackWithCast (unsigned, uvs[idx].w, UVSProc, idx);
1384 XtSetArg (arg[5], XtNfromVert, uvs_area);
1386 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
1389 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
1390 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
1391 command_area, arg, 1);
1392 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
1394 dump = XtCreateManagedWidget ("DumpImage", commandWidgetClass,
1395 command_area, arg, 1);
1396 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
1398 XtSetArg (arg[0], XtNborderWidth, 0);
1399 XtSetArg (arg[1], XtNwidth, 10);
1400 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
1402 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
1403 XtSetArg (arg[0], XtNstate, True);
1404 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
1405 command_area, arg, 1);
1406 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1407 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1408 for (i = 0; i < face->num_charmaps; i++)
1410 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1412 command_area, arg, 1);
1413 XtAddCallbackWithCast (int, charmap[i + 1], CharmapProc, i);
1416 XtSetArg (arg[0], XtNlabel, " |< (f)");
1417 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1418 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1420 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1421 XtSetArg (arg[0], XtNlabel, "<< (P)");
1422 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1423 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1425 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1426 XtSetArg (arg[0], XtNlabel, "< (p)");
1427 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1428 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1430 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1431 XtSetArg (arg[0], XtNlabel, " 0000 ");
1432 range = XtCreateManagedWidget ("range", labelWidgetClass,
1434 XtSetArg (arg[0], XtNforeground, &foreground);
1435 XtSetArg (arg[1], XtNbackground, &background);
1436 XtGetValues (range, arg, 2);
1438 XtSetArg (arg[0], XtNlabel, "> (n)");
1439 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1440 next = XtCreateManagedWidget ("next", commandWidgetClass,
1442 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1443 XtSetArg (arg[0], XtNlabel, ">> (N)");
1444 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1445 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1447 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1448 XtSetArg (arg[0], XtNlabel, ">| (l)");
1449 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1450 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1452 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1454 XtSetArg (arg[0], XtNleft, XawChainLeft);
1455 XtSetArg (arg[1], XtNright, XawChainLeft);
1456 XtSetArg (arg[2], XtNtop, XawChainTop);
1457 XtSetArg (arg[3], XtNbottom, XawChainTop);
1459 for (i = 0; i < 8; i++)
1465 sprintf (str, "%XX", i);
1466 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1467 XtSetArg (arg[n], XtNlabel, str), n++;
1468 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1470 XtSetArg (arg[n], XtNfromVert, w), n++;
1471 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1472 index_label[i] = head;
1473 for (j = 0; j < 16; j++)
1479 XtSetArg (arg[n], XtNfromVert, w), n++;
1481 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1483 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1484 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1485 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1486 glyph_area, arg, n);
1487 XtAddCallbackWithCast (int, glyph[k], RenderProc, k);
1491 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1492 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1493 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1494 XtSetArg (arg[6], XtNfromHoriz, w);
1495 XtSetArg (arg[7], XtNborderWidth, 0);
1497 for (j = 0; j < 16; j++)
1501 sprintf (str, "X%X", j);
1502 XtSetArg (arg[8], XtNlabel, str);
1503 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1504 XtSetArg (arg[6], XtNfromHoriz, w);
1507 XtSetArg (arg[0], XtNleft, XawChainLeft);
1508 XtSetArg (arg[1], XtNright, XawChainLeft);
1509 XtSetArg (arg[2], XtNtop, XawChainTop);
1510 XtSetArg (arg[3], XtNbottom, XawChainTop);
1511 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1512 XtSetArg (arg[5], XtNborderWidth, 0);
1513 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1514 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1515 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1516 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1517 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1518 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1519 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1520 alt_subst = XtCreateManagedWidget ("AltSubst", toggleWidgetClass, w, arg, 0);
1521 XtAddCallback (alt_subst, XtNcallback, AltSubstProc, NULL);
1523 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1524 XtSetArg (arg[5], XtNborderWidth, 0);
1525 XtSetArg (arg[6], XtNfromVert, w);
1526 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1528 XtSetArg (arg[0], XtNborderWidth, 0);
1529 XtSetArg (arg[1], XtNlabel, "raw: ");
1530 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1532 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1533 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1538 OTF_get_table (otf, "GSUB");
1539 OTF_get_table (otf, "GPOS");
1540 w = create_otf_script_widgets (w);
1543 gsub.label = "GSUB";
1544 gsub.gsub_gpos = otf->gsub;
1545 w = create_otf_widgets (w, &gsub);
1549 gpos.label = "GPOS";
1550 gpos.gsub_gpos = otf->gpos;
1551 w = create_otf_widgets (w, &gpos);
1555 XtSetArg (arg[6], XtNfromVert, w);
1556 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1557 XtSetArg (arg[0], XtNborderWidth, 0);
1558 XtSetArg (arg[1], XtNlabel, "seq: ");
1559 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1561 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1562 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1564 XtSetArg (arg[6], XtNfromVert, seq);
1565 code = XtCreateManagedWidget ("code", boxWidgetClass, render_area, arg, 7);
1566 XtSetArg (arg[0], XtNborderWidth, 0);
1567 XtSetArg (arg[1], XtNlabel, "code:");
1568 code_label = XtCreateManagedWidget ("code-label", labelWidgetClass,
1570 XtSetArg (arg[1], XtNlabel, "");
1571 XtSetArg (arg[2], XtNwidth, render_width);
1572 code_list = XtCreateManagedWidget ("code-list", labelWidgetClass,
1574 XtInstallAllAccelerators (shell, shell);
1578 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1580 XTextProperty text_prop;
1581 char *pname = "otfview";
1582 char *fname = basename (filename);
1583 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1585 sprintf (name, "%s - %s", pname, fname);
1586 text_prop.value = (unsigned char *) name;
1587 text_prop.encoding = XA_STRING;
1588 text_prop.format = 8;
1589 text_prop.nitems = strlen (name);
1590 XSetWMName (display, XtWindow (shell), &text_prop);
1593 /* Format MSG by FMT and print the result to the stderr, and exit. */
1595 #define FATAL_ERROR(fmt, arg) \
1597 fprintf (stderr, fmt, arg); \
1602 x_error_handler (Display *display, XErrorEvent *error)
1608 help (char **argv, int err)
1610 FILE *fp = err ? stderr : stdout;
1612 fprintf (fp, "Usage: %s [ X-OPTION ... ] OTF-FILE [INDEX]\n",
1613 basename (argv[0]));
1614 fprintf (fp, " Environment variable PIXEL_SIZE specifies the pixel size.\n");
1615 fprintf (fp, " The default pixel size is %d, but is reduced\n",
1616 DEFAULT_PIXEL_SIZE);
1617 fprintf (fp, " if your screen is not that wide.\n");
1622 main (int argc, char **argv)
1624 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1628 OTF_GlyphString gstring;
1633 int fixed_pixel_size = 0;
1636 pixel_size = DEFAULT_PIXEL_SIZE;
1638 char *str = getenv ("PIXEL_SIZE");
1640 if (str && (i = atoi (str)) > 0)
1643 fixed_pixel_size = 1;
1647 gstring.size = gstring.used = 256;
1648 g = calloc (256, sizeof (OTF_Glyph));
1651 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1652 shellWidgetClass, arg, 0);
1653 display = XtDisplay (shell);
1654 /*XSynchronize (display, True);*/
1655 XSetErrorHandler (x_error_handler);
1656 display_width = DisplayWidth (display,
1657 XScreenNumberOfScreen (XtScreen (shell)));
1658 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1660 font = XLoadQueryFont (display, "fixed");
1664 if (!strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1669 fontindex = atoi (argv[2]);
1671 FATAL_ERROR ("Invalid font index: %d\n", fontindex);
1674 if ((err = FT_Init_FreeType (&library)))
1675 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1676 err = FT_New_Face (library, filename, fontindex, &face);
1677 if (err == FT_Err_Unknown_File_Format)
1678 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1680 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error (invalid face index?)");
1681 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1682 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1684 if (strstr (filename, ".ttf")
1685 || strstr (filename, ".TTF")
1686 || strstr (filename, ".otf")
1687 || strstr (filename, ".OTF"))
1689 otf = OTF_open_ft_face (face);
1692 if (OTF_get_table (otf, "head") < 0
1693 || OTF_get_table (otf, "cmap") < 0
1694 || (OTF_check_table (otf, "GSUB") < 0
1695 && OTF_check_table (otf, "GPOS") < 0))
1702 for (i = 0; i < otf->cmap->numTables; i++)
1703 if (otf->cmap->EncodingRecord[i].subtable.format == 14)
1705 sub14 = otf->cmap->EncodingRecord[i].subtable.f.f14;
1714 filename = basename (filename);
1715 sprintf (title, "%s family:%s style:%s",
1716 filename, face->family_name, face->style_name);
1717 XtSetArg (arg[0], XtNtitle, title);
1718 XtSetValues (shell, arg, 1);
1721 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1722 * pixel_size / face->units_per_EM);
1723 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1725 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1726 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1727 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1728 * pixel_size / face->units_per_EM);
1730 if (glyph_width < FONT_WIDTH * 4)
1731 glyph_width = FONT_WIDTH * 4;
1733 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1734 * pixel_size / face->units_per_EM);
1736 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1737 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1738 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1739 glyph_width, glyph_height, 1);
1742 unsigned long valuemask = GCFunction | GCLineWidth;
1745 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1746 XSetFont (display, gc, font->fid);
1747 values.function = GXset;
1748 values.line_width = 1;
1749 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1750 XSetFont (display, gc_set, font->fid);
1751 values.function = GXor;
1752 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1753 values.function = GXcopyInverted;
1754 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1757 XFillRectangle (display, none_pixmap, gc, 0, 0,
1758 glyph_width, glyph_height);
1759 XDrawString (display, none_pixmap, gc_inv,
1760 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1761 glyph_height / 2, "none", 4);
1763 render_width = (glyph_width + 4) * 15 + 1;
1764 render_height = glyph_height + 2;
1766 charmap_rec[0].platform_id = -1;
1767 charmap_rec[0].encoding_id = -1;
1768 strcpy (charmap_rec[0].name, "no charmap");
1770 for (i = 0; i < face->num_charmaps; i++)
1772 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1773 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1774 sprintf (charmap_rec[i + 1].name, "%d-%d",
1775 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1776 if (face->charmaps[i]->platform_id == 0
1777 || (face->charmaps[i]->platform_id == 3
1778 && face->charmaps[i]->encoding_id == 1))
1779 strcat (charmap_rec[i + 1].name, " (unicode)");
1780 else if (face->charmaps[i]->platform_id == 1
1781 && face->charmaps[i]->encoding_id == 0)
1782 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1785 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1786 render_width, render_height, 1);
1787 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1788 render_width, render_height, 1);
1790 memset (bitmap, 0, sizeof (bitmap));
1794 update_glyph_area ();
1795 update_render_area ();
1797 XtAppAddActions (context, actions, XtNumber (actions));
1798 XtRealizeWidget (shell);
1799 XtAppMainLoop (context);
1804 #else /* not HAVE_X11_XAW_COMMAND_H */
1807 main (int argc, char **argv)
1810 "Building of this program failed (lack of some header files)\n");