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. */
33 #ifdef HAVE_X11_XAW_COMMAND_H
35 #include <X11/Xatom.h>
36 #include <X11/Intrinsic.h>
37 #include <X11/StringDefs.h>
38 #include <X11/Shell.h>
39 #include <X11/Xaw/Command.h>
40 #include <X11/Xaw/Toggle.h>
41 #include <X11/Xaw/Box.h>
42 #include <X11/Xaw/Form.h>
43 #include <X11/Xaw/Viewport.h>
46 #include FT_FREETYPE_H
50 #define CAST_FROM_XTPOINTER(TYPE, DATA, VAR) \
52 long TYPE temp = (long TYPE) (DATA); \
56 #define XtAddCallbackWithCast(TYPE, W, PROC, VAR) \
58 long TYPE temp = (long TYPE) (VAR); \
59 XtAddCallback (W, XtNcallback, PROC, (XtPointer) temp); \
63 #define DEFAULT_PIXEL_SIZE 30
66 #define DEFAULT_FONT_NAME "6x13"
68 #define FONT_HEIGHT (font->ascent + font->descent)
69 #define FONT_ASCENT (font->ascent)
70 #define FONT_DESCENT (font->descent)
71 #define FONT_WIDTH (font->max_bounds.width)
75 +--- frame (form) -------------------------+
76 | +--- command_area (box) ---------------+ |
77 | | quit dump charmap ... | |
78 | +--------------------------------------+ |
79 | +---- navi_area (box) -----------------+ |
80 | | FIRST PREV prev range next NEXT LAST | |
81 | +--------------------------------------+ |
82 | +--- glyph_area (form) ----------------+ |
83 | | idxh[0] glyph[0] ... glyph[15] | |
85 | | idxh[7] glyph[112] ... glyph[127]| |
86 | | idxl[0] ... idxl[15] | |
87 | +--------------------------------------+ |
88 | +--- script_area (box) ----------------+ |
89 | | script(langsys) DFLT ... | |
90 | +--------------------------------------+ |
91 | +---- uvs_area (box) (optional) -------+ |
93 | +--------------------------------------+ |
94 | +--- render_area (form) ---------------+ |
95 | | clear del bidi alt_subst | |
96 | | +--- raw (box) --------------------+ | |
97 | | | raw_label raw_image | | |
98 | | +----------------------------------+ | |
99 | | GSUB all none features... | |
100 | | GPOS all none features... | |
101 | | +--- seq (box) --------------------+ | |
102 | | | seq_label seq_image | | |
103 | | +----------------------------------+ | |
104 | | +--- code (box) -------------------+ | |
105 | | | code_label code_list ... | | |
106 | | +----------------------------------+ | |
107 | +--------------------------------------+ |
108 +------------------------------------------+ */
110 Widget command_area, quit, dump, *charmap;
111 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
112 Widget glyph_area, glyph[128], index_label[8];
113 Widget uvs_area, uvs_label;
114 Widget render_area, clear, del, bidi, alt_subst, raw, seq, code;
115 Widget raw_label, raw_image, seq_label, seq_image, code_label, code_list;
116 unsigned long foreground, background;
128 OTF_GSUB_GPOS *gsub_gpos;
129 OTF_LangSys *langsys;
131 FeatureElement *features;
135 FeatureRec gsub, gpos;
137 /* Currently selected script and langsys. */
138 OTF_Tag script_tag, langsys_tag;
143 GC gc, gc_set, gc_or, gc_inv;
147 unsigned width, height;
152 BitmapRec bitmap[0x110000];
154 int render_width, render_height;
155 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
169 int do_alternate_subst;
170 unsigned glyph_width, glyph_height;
171 int glyph_x, glyph_y;
180 OTF_EncodingSubtable14 *sub14 = NULL;
192 create_pixmap (int index)
194 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
200 bitmap[index].pixmap = none_pixmap;
203 ximage.height = face->glyph->bitmap.rows;
204 ximage.width = face->glyph->bitmap.width;
206 ximage.bits_per_pixel = 1;
208 ximage.format = XYPixmap;
209 ximage.data = (char *) face->glyph->bitmap.buffer;
210 ximage.byte_order = MSBFirst;
211 ximage.bitmap_unit = 8;
212 ximage.bitmap_bit_order = MSBFirst;
213 ximage.bitmap_pad = 8;
214 ximage.bytes_per_line = face->glyph->bitmap.pitch;
215 XInitImage (&ximage);
216 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
217 glyph_width, glyph_height, 1);
218 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
219 XPutImage (display, pixmap, gc, &ximage, 0, 0,
220 glyph_x + face->glyph->bitmap_left,
221 glyph_y - face->glyph->bitmap_top,
222 ximage.width, ximage.height);
223 bitmap[index].pixmap = pixmap;
224 bitmap[index].width = ximage.width;
225 bitmap[index].height = ximage.height;
226 bitmap[index].x = face->glyph->bitmap_left;
227 bitmap[index].y = - face->glyph->bitmap_top;
228 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
239 for (i = 0; i < 128; i++)
241 int index = glyph_index + i;
243 if (charmap_index >= 0)
244 index = FT_Get_Char_Index (face, (FT_ULong) index);
245 if (charmap_index >= 0 && ! index)
246 XtSetArg (arg[0], XtNbitmap, none_pixmap);
249 if (! bitmap[index].pixmap)
250 create_pixmap (index);
251 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
253 XtSetValues (glyph[i], arg, 1);
256 msb = (glyph_index >> 7) % 2 ? 8 : 0;
257 for (i = 0; i < 8; i++)
261 sprintf (str, "%XX", i | msb );
262 XtSetArg (arg[0], XtNheight, glyph_height + 5);
263 XtSetArg (arg[1], XtNlabel, str);
264 XtSetValues (index_label[i], arg, 2);
267 if (glyph_index < 0x10000)
268 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
270 sprintf (buf, "%06X-%06X", glyph_index, glyph_index + 0x7F);
271 XtSetArg (arg[0], XtNlabel, buf);
272 XtSetValues (range, arg, 1);
276 update_uvs_area (int c)
278 OTF_GlyphID code[256];
282 OTF_get_variation_glyphs (otf, c, code);
284 for (i = 0; i < 256; i++)
288 XtSetArg (arg[0], XtNsensitive, True);
290 XtSetArg (arg[0], XtNsensitive, False);
291 XtSetValues (uvs[i].w, arg, 1);
297 get_features (OTF_FeatureList *list, FeatureRec *rec)
302 if (! rec->langsys || ! rec->features)
304 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
305 if (rec->features[i].on)
309 str = malloc (n * 5);
310 for (i = 0, p = str; i < rec->langsys->FeatureCount; i++)
311 if (rec->features[i].on)
313 OTF_tag_name (rec->features[i].tag, p);
322 #define DEVICE_DELTA(table, size) \
323 (((table).DeltaValue \
324 && ((size) >= (table).StartSize && (size) <= (table).EndSize)) \
325 ? (table).DeltaValue[(size) >= (table).StartSize] \
329 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
330 OTF_Glyph *g, int *x, int *y)
332 if (anchor->AnchorFormat == 2)
335 int ap = anchor->f.f1.AnchorPoint;
337 FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
338 outline = &ft_face->glyph->outline;
339 if (ap < outline->n_points)
341 *x = outline->points[ap].x;
342 *y = outline->points[ap].y;
345 else if (anchor->AnchorFormat == 3)
347 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
348 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
356 OTF_GlyphString gstring;
357 OTF_Glyph *g, *prev, *base, *mark;
359 int len = glyph_rec.n_glyphs;
361 int unitsPerEm = face->units_per_EM;
365 gstring.size = gstring.used = len;
366 gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
367 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
368 for (i = 0; i < len; i++)
370 gstring.glyphs[i].c = glyph_rec.codes[i];
371 if (charmap_index < 0)
372 gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
375 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
376 XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
379 char *script_name = NULL, *langsys_name = NULL, buf[10];
385 OTF_tag_name (script_tag, script_name);
389 langsys_name = buf + 5;
390 OTF_tag_name (langsys_tag, langsys_name);
393 OTF_drive_cmap (otf, &gstring);
394 OTF_drive_gdef (otf, &gstring);
397 str = get_features (&otf->gsub->FeatureList, &gsub);
400 if (do_alternate_subst)
401 OTF_drive_gsub_alternate (otf, &gstring,
402 script_name, langsys_name, str);
405 OTF_drive_gsub_with_log (otf, &gstring,
406 script_name, langsys_name, str);
407 logsize = gstring.used * 2;
408 log = alloca (sizeof (OTF_Tag) * logsize);
409 for (i = 0; i < gstring.used; i++)
411 int idx = gstring.glyphs[i].positioning_type >> 4;
413 log[i] = otf->gsub->FeatureList.Feature[idx - 1].FeatureTag;
423 str = get_features (&otf->gpos->FeatureList, &gpos);
426 OTF_drive_gpos_with_log (otf, &gstring,
427 script_name, langsys_name, str);
430 if (logsize < gstring.used)
432 OTF_Tag *log2 = alloca (sizeof (OTF_Tag) * gstring.used);
433 memset (log2, 0, sizeof (OTF_Tag) * gstring.used);
434 memcpy (log2, log, sizeof (OTF_Tag) * logsize);
435 logsize = gstring.used;
441 logsize = gstring.used;
442 log = alloca (sizeof (OTF_Tag) * logsize);
443 memset (log, 0, sizeof (OTF_Tag) * logsize);
445 for (i = 0; i < gstring.used; i++)
447 int idx = gstring.glyphs[i].positioning_type >> 4;
449 log[i] = otf->gpos->FeatureList.Feature[idx - 1].FeatureTag;
462 for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
463 prev < g; prev++, g--)
464 temp = *prev, *prev = *g, *g = temp;
465 for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
466 if (g->GlyphClass == 3)
470 while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
472 for (g0 = g; prev < g0; prev++, g0--)
473 temp = *prev, *prev = *g, *g = temp;
479 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
480 i < gstring.used; i++, prev = g++)
482 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
483 int xoff = 0, yoff = 0;
485 int advance = bmp->advance;
487 if (gstring.glyphs[i].glyph_id && ! bmp->pixmap)
489 create_pixmap (gstring.glyphs[i].glyph_id);
492 advance = bmp->advance;
494 if (g->positioning_type & 0xF)
498 switch (g->positioning_type & 0xF)
502 int format = g->f.f1.format;
504 if (format & OTF_XPlacement)
505 xoff += g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
506 if (format & OTF_XPlaDevice)
507 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
508 if (format & OTF_YPlacement)
509 yoff += g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
510 if (format & OTF_YPlaDevice)
511 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
512 if (format & OTF_XAdvance)
513 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
514 if (format & OTF_XAdvDevice)
515 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice,
521 /* Not yet supported. */
527 prev_width = base_width;
528 goto label_adjust_anchor;
529 default: /* i.e. case 6 */
536 int base_x, base_y, mark_x, mark_y;
538 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
539 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
540 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
541 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
543 if (g->f.f4.base_anchor->AnchorFormat != 1)
544 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
545 if (g->f.f4.mark_anchor->AnchorFormat != 1)
546 adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
547 xoff = (base_x - prev_width) - mark_x;
548 yoff = base_y - mark_y;
551 if (i + 1 == gstring.used
552 || gstring.glyphs[i + 1].glyph_id
553 || ! (gstring.glyphs[i + 1].positioning_type & 0xF))
559 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
560 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
561 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
564 if (g->GlyphClass == OTF_GlyphClass0)
565 base = mark = g, base_width = advance;
566 else if (g->GlyphClass == OTF_GlyphClassMark)
569 base = g, base_width = advance;
572 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
573 XtSetValues (seq_image, arg, 1);
575 if (gstring.used > 0)
577 int size = render_width / FONT_WIDTH;
578 char *buf = alloca (size + 1);
581 sprintf (buf, "%04X", gstring.glyphs[0].glyph_id);
584 OTF_tag_name (log[0], name);
585 sprintf (buf + 4, " (%s)", name);
590 for (i = 1; i < gstring.used && x + 5 < size; i++, x += 5)
592 sprintf (buf + x, " %04X", gstring.glyphs[i].glyph_id);
593 if (log && log[i] && x + 11 < size)
595 OTF_tag_name (log[i], name);
596 sprintf (buf + x + 5, "(%s)", name);
603 XtSetArg (arg[0], XtNlabel, buf);
604 XtSetValues (code_list, arg, 1);
607 free (gstring.glyphs);
612 update_render_area ()
618 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
619 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
621 if (glyph_rec.glyphs[i] >= 0)
623 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
626 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
627 0, 0, glyph_width, glyph_height,
628 (glyph_width + 4) * i + 1, 1);
629 XDrawRectangle (display, raw_pixmap, gc_set,
630 (glyph_width + 4) * i, 0,
631 glyph_width + 1, glyph_height + 1);
632 XDrawLine (display, raw_pixmap, gc_set,
633 (glyph_width + 4) * i + 1 + glyph_x, 1,
634 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
635 XDrawLine (display, raw_pixmap, gc_set,
636 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
637 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
640 sprintf (buf, "%04X", glyph_rec.codes[i]);
641 XDrawString (display, raw_pixmap, gc_inv,
642 (glyph_width + 4) * i + 1
643 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
644 glyph_height + 2 + FONT_HEIGHT, buf, 4);
648 /* Variation Selector */
649 int idx = - glyph_rec.glyphs[i];
652 sprintf (buf, "%03d", idx);
653 XDrawRectangle (display, raw_pixmap, gc_set,
654 (glyph_width + 4) * i, 0,
655 glyph_width + 1, glyph_height + 1);
656 XDrawString (display, raw_pixmap, gc_set,
657 (glyph_width + 4) * i + 1
658 + (glyph_width - XTextWidth (font, "VS", 2)) / 2,
659 1 + glyph_height / 2, "VS", 2);
660 XDrawString (display, raw_pixmap, gc_set,
661 (glyph_width + 4) * i + 1
662 + (glyph_width - XTextWidth (font, buf, 3)) / 2,
663 1 + glyph_height / 2 + FONT_ASCENT, buf, 3);
666 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
667 XtSetValues (raw_image, arg, 1);
672 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
674 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
678 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
680 int g_width, g_height;
682 /* unit in points (1/72 inch); to fit in both US-letter and A4 */
683 static int xoff = 30, yoff = 30;
684 static int unit = 30;
685 static int margin = 2;
686 static int title_height = 20, label_height = 10;
687 int total_width = (unit + margin * 2) * 16;
688 int total_height = (unit + margin * 2 + label_height) * 16 + title_height;
689 /* pixel size (dots) */
692 char *name = alloca (strlen (filename) + 10);
694 int index = (glyph_index / 0x100) * 0x100;
697 g_width = face->bbox.xMax - face->bbox.xMin;
698 g_height = face->bbox.yMax - face->bbox.yMin;
699 if (g_width > g_height)
701 scale = g_width * size;
702 g_x = face->bbox.xMin * unit / g_width;
703 g_y = face->bbox.yMin * unit / g_width;
707 scale = g_height * size;
708 g_x = face->bbox.xMin * unit / g_height;
709 g_y = face->bbox.yMin * unit / g_height;
711 scale /= face->units_per_EM;
713 FT_Set_Pixel_Sizes (face, 0, size);
715 sprintf (name, "%s-%04X.ps", face->family_name, index);
716 printf ("Writing %s ... ", name);
718 fp = fopen (name, "w");
720 fprintf (fp, "%s\n", "%!PS-Adobe-2.0 EPSF-2.0");
721 fprintf (fp, "%s\n", "%%Creater: otfview");
722 fprintf (fp, "%s %s(%s)-%04X\n", "%%Title:",
723 face->family_name, face->style_name, index);
724 fprintf (fp, "%s\n", "%%Pages: 1");
725 fprintf (fp, "%s %d %d %d %d\n", "%%BoundingBox:",
726 xoff, yoff, xoff + total_width, yoff + total_height);
727 fprintf (fp, "%s\n", "%%EndComments");
728 fprintf (fp, "%s\n", "%%BeginProlog");
729 fprintf (fp, "/W %d def\n", unit + margin * 2);
730 fprintf (fp, "/H %d def\n", unit + margin * 2 + label_height);
731 fprintf (fp, "/STR 10 string def\n");
732 fprintf (fp, "/DrawIndex {\n");
733 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");
734 fprintf (fp, "} def\n");
735 fprintf (fp, "/DrawTitle {\n");
736 fprintf (fp, " /Courier findfont 20 scalefont setfont\n");
737 fprintf (fp, " %d %d 4 add moveto\n", xoff + total_width / 2,
738 yoff + total_height - title_height + 2);
739 fprintf (fp, " (%s(%s)-%04X) dup stringwidth pop 2 div neg 0 rmoveto show\n",
740 face->family_name, face->style_name, index);
741 fprintf (fp, "} def\n");
742 fprintf (fp, "/DrawFrame { gsave %d %d translate 0 setlinewidth\n",
744 fprintf (fp, " /Courier findfont 10 scalefont setfont\n");
745 fprintf (fp, " /I %d def\n", index);
746 fprintf (fp, " 0 1 16 { W mul 0 moveto 0 H 16 mul rlineto stroke } for\n");
747 fprintf (fp, " 0 1 16 { H mul 0 exch moveto W 16 mul 0 rlineto stroke } for\n");
748 fprintf (fp, " 0 1 15 { H mul %d add 0 exch moveto W 16 mul 0 rlineto stroke } for\n", label_height);
749 fprintf (fp, " 15 -1 0 { gsave H mul 0 exch translate 0 0 moveto\n");
750 fprintf (fp, " 0 1 15 { gsave W mul 0 moveto\n");
751 fprintf (fp, " 4 2 rmoveto DrawIndex /I I 1 add def grestore} for\n");
752 fprintf (fp, " grestore } for grestore } def\n");
753 fprintf (fp, "%s\n", "%%EndProlog");
754 fprintf (fp, "DrawTitle DrawFrame\n");
756 for (i = 0; i < 16; i++)
757 for (j = 0; j < 16; j++, index++)
761 if (charmap_index >= 0)
762 idx = FT_Get_Char_Index (face, (FT_ULong) index);
766 && FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0
767 && face->glyph->bitmap.rows > 0
768 && face->glyph->bitmap.width > 0)
770 unsigned char *p = face->glyph->bitmap.buffer;
771 int width = (face->glyph->bitmap.width - 1) / 8 + 1;
773 fprintf (fp, "gsave %f %f translate %d %d scale 0 0 moveto\n",
774 xoff + (unit + margin * 2) * j + margin - g_x,
775 yoff + (unit + label_height + margin * 2) * (15 - i) + label_height + margin - g_y,
777 fprintf (fp, "%d %d true [%f 0 0 %f %d %d]\n",
778 width * 8, face->glyph->bitmap.rows,
779 scale, -scale, -face->glyph->bitmap_left,
780 face->glyph->bitmap_top);
782 for (k = 0; k < face->glyph->bitmap.rows;
783 k++, p += face->glyph->bitmap.pitch)
785 for (l = 0; l < width; l++)
786 fprintf (fp, "%02X", p[l]);
789 fprintf (fp, ">} imagemask grestore\n");
793 int boxsize = unit + margin * 2;
795 fprintf (fp, "gsave 0 setlinewidth %d %d translate\n",
797 yoff + (boxsize + label_height) * (15 - i) + label_height);
798 fprintf (fp, "0 0 moveto %d %d lineto stroke\n",
800 fprintf (fp, "0 %d moveto %d 0 lineto stroke grestore\n",
804 fprintf (fp, "showpage\n");
808 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
813 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
815 int old_glyph_index = glyph_index;
818 CAST_FROM_XTPOINTER (int, client_data, data);
820 if (data == -3 && glyph_index > 0)
822 else if (data == -2 && glyph_index > 0)
823 glyph_index = (glyph_index - 1) & 0x1FF000;
824 else if (data == -1 && glyph_index > 0)
826 else if (data == 1 && glyph_index < 0x10FF80)
828 else if (data == 2 && glyph_index < 0x10F000)
829 glyph_index = (glyph_index + 0x1000) & 0x1FF000;
830 else if (data == 3 && glyph_index < 0x10F000)
831 glyph_index = 0x10FF80;
832 if (glyph_index != old_glyph_index)
833 update_glyph_area ();
837 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
841 CAST_FROM_XTPOINTER (int, client_data, data);
843 if (charmap_index == data)
845 charmap_index = data;
846 if (charmap_index >= 0)
847 FT_Set_Charmap (face, face->charmaps[charmap_index]);
848 update_glyph_area ();
852 UVSProc (Widget w, XtPointer client_data, XtPointer call_data)
856 OTF_VariationSelectorRecord *record;
859 CAST_FROM_XTPOINTER (unsigned, client_data, idx);
860 selector = uvs[idx].c;
862 if (glyph_rec.n_glyphs >= 64)
864 for (i = 0; i < sub14->nRecords; i++)
866 record = sub14->Records + i;
867 if (record->varSelector == selector)
870 if (i < sub14->nRecords)
872 if (glyph_rec.n_glyphs > 0
873 && glyph_rec.glyphs[glyph_rec.n_glyphs - 1] < 0)
874 glyph_rec.n_glyphs--;
875 glyph_rec.codes[glyph_rec.n_glyphs] = selector;
876 glyph_rec.glyphs[glyph_rec.n_glyphs++] = - idx - 1;
877 update_render_area ();
882 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
886 CAST_FROM_XTPOINTER (int, client_data, data);
890 if (glyph_rec.n_glyphs > 0)
893 glyph_rec.n_glyphs--;
895 glyph_rec.n_glyphs = 0;
896 update_render_area ();
899 else if (glyph_rec.n_glyphs < 64)
901 int index = glyph_index + data;
903 if (charmap_index >= 0)
904 index = FT_Get_Char_Index (face, (FT_ULong) index);
905 if (bitmap[index].pixmap)
907 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + data;
908 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
910 update_uvs_area (glyph_index + data);
911 update_render_area ();
917 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
921 reversed = ! reversed;
923 XtSetArg (arg[0], XtNlabel, "L<-R");
925 XtSetArg (arg[0], XtNlabel, "L->R");
926 XtSetValues (w, arg, 1);
931 AltSubstProc (Widget w, XtPointer client_data, XtPointer call_data)
933 do_alternate_subst = ! do_alternate_subst;
938 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
940 FeatureRec *rec = (FeatureRec *) client_data;
947 XtSetArg (arg[0], XtNlabel, &label);
948 XtGetValues (w, arg, 1);
949 if (! strcmp (label, "all"))
951 else if (! strcmp (label, "none"))
955 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
956 if (rec->features[idx].w == w)
958 if (idx == rec->langsys->FeatureCount)
966 for (i = 0; i < rec->langsys->FeatureCount; i++)
967 if (rec->features[i].on != on)
969 rec->features[i].on = on;
972 XtSetArg (arg[0], XtNborderWidth, 3);
973 XtSetArg (arg[1], XtNinternalHeight, 2);
974 XtSetArg (arg[2], XtNinternalWidth, 2);
978 XtSetArg (arg[0], XtNborderWidth, 1);
979 XtSetArg (arg[1], XtNinternalHeight, 4);
980 XtSetArg (arg[2], XtNinternalWidth, 4);
982 OTF_tag_name (rec->features[i].tag, str);
983 XtSetArg (arg[3], XtNlabel, str);
984 XtSetValues (rec->features[i].w, arg, 4);
991 rec->features[idx].on = ! rec->features[idx].on;
992 if (rec->features[idx].on)
994 XtSetArg (arg[0], XtNborderWidth, 3);
995 XtSetArg (arg[1], XtNinternalHeight, 2);
996 XtSetArg (arg[2], XtNinternalWidth, 2);
1000 XtSetArg (arg[0], XtNborderWidth, 1);
1001 XtSetArg (arg[1], XtNinternalHeight, 4);
1002 XtSetArg (arg[2], XtNinternalWidth, 4);
1004 OTF_tag_name (rec->features[idx].tag, str);
1005 XtSetArg (arg[3], XtNlabel, str);
1006 XtSetValues (rec->features[idx].w, arg, 4);
1012 setup_feature_rec (FeatureRec *rec)
1017 rec->langsys = NULL;
1018 if (! rec->gsub_gpos)
1020 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
1021 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
1023 OTF_Script *script = rec->gsub_gpos->ScriptList.Script + i;
1027 for (j = 0; j < script->LangSysCount; j++)
1028 if (script->LangSysRecord[j].LangSysTag == langsys_tag)
1030 rec->langsys = script->LangSys + j;
1035 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
1043 XtSetArg (arg[0], XtNborderWidth, 1);
1044 XtSetArg (arg[1], XtNinternalHeight, 4);
1045 XtSetArg (arg[2], XtNinternalWidth, 4);
1046 XtSetArg (arg[3], XtNborderColor, foreground);
1047 XtSetArg (arg[4], XtNsensitive, True);
1048 for (i = 0; i < rec->langsys->FeatureCount; i++)
1050 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
1051 int index = rec->langsys->FeatureIndex[i];
1054 if (! rec->features[i].w)
1056 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
1057 rec->parent, arg, 0);
1058 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1059 rec->features[i].w = w;
1062 rec->features[i].tag = feature[index].FeatureTag;
1063 rec->features[i].on = 0;
1064 OTF_tag_name (rec->features[i].tag, label);
1065 XtSetArg (arg[5], XtNlabel, label);
1066 XtSetValues (rec->features[i].w, arg, 6);
1069 XtSetArg (arg[0], XtNborderColor, background);
1070 XtSetArg (arg[1], XtNsensitive, False);
1071 XtSetArg (arg[2], XtNlabel, " ");
1072 for (; i < rec->num_features; i++)
1074 if (! rec->features[i].w)
1076 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
1077 rec->parent, arg, 0);
1078 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1079 rec->features[i].w = w;
1081 XtSetValues (rec->features[i].w, arg, 3);
1086 compose_script_langsys (OTF_Tag script, OTF_Tag langsys, char *name)
1088 OTF_tag_name (script, name);
1092 OTF_tag_name (langsys, name + 5);
1099 decompose_script_langsys (OTF_Tag *script, OTF_Tag *langsys, char *name)
1101 *script = OTF_tag (name);
1103 *langsys = OTF_tag (name + 5);
1109 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
1112 OTF_Tag script, langsys;
1115 XtSetArg (arg[0], XtNlabel, &name);
1116 XtGetValues (w, arg, 1);
1117 decompose_script_langsys (&script, &langsys, name);
1118 if (script_tag == script && langsys_tag == langsys)
1120 script_tag = script;
1121 langsys_tag = langsys;
1122 setup_feature_rec (&gsub);
1123 setup_feature_rec (&gpos);
1128 create_otf_script_widgets (Widget prev)
1132 int n, prev_n, i, j;
1140 XtSetArg (arg[0], XtNborderWidth, 0);
1141 XtSetArg (arg[1], XtNleft, XawChainLeft);
1142 XtSetArg (arg[2], XtNright, XawChainLeft);
1143 XtSetArg (arg[3], XtNtop, XawChainTop);
1144 XtSetArg (arg[4], XtNbottom, XawChainTop);
1145 XtSetArg (arg[5], XtNfromVert, prev);
1146 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1147 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
1148 XtCreateManagedWidget ("script(langsys)", labelWidgetClass, prev, arg, 1);
1152 for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1153 n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
1155 for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1156 n += otf->gpos->ScriptList.Script[i].LangSysCount + 1;
1157 script_langsys = alloca ((sizeof script_langsys[0]) * n);
1161 for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1163 OTF_Tag tag = otf->gsub->ScriptList.Script[i].ScriptTag;
1165 script_langsys[n].script = tag;
1166 script_langsys[n++].langsys = 0;
1168 < otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1170 = otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1171 for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
1173 script_langsys[n].script = tag;
1174 script_langsys[n++].langsys
1175 = otf->gsub->ScriptList.Script[i].LangSysRecord[j].LangSysTag;
1177 < otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount)
1179 = otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount;
1182 gsub.num_features = nfeatures;
1185 gsub.num_features = nfeatures;
1186 gsub.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1187 memset (gsub.features, 0, (sizeof (FeatureElement)) * nfeatures);
1192 for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1194 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
1198 < otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1200 = otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1201 for (k = 0; k < prev_n; k++)
1202 if (tag == script_langsys[k].script)
1206 script_langsys[n].script = tag;
1207 script_langsys[n++].langsys = 0;
1209 for (j = 0; j < otf->gpos->ScriptList.Script[i].LangSysCount; j++)
1215 OTF_Script *script = otf->gpos->ScriptList.Script + i;
1217 for (l = k; l < prev_n && tag == script_langsys[l].script; l++)
1218 if (script->LangSysRecord[j].LangSysTag
1219 == script_langsys[l].langsys)
1226 script_langsys[n].script = tag;
1227 script_langsys[n++].langsys = 0;
1230 < otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount)
1232 = otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount;
1238 gpos.num_features = nfeatures;
1239 gpos.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1240 memset (gpos.features, 0, (sizeof (FeatureElement)) * nfeatures);
1246 script_tag = script_langsys[0].script;
1247 langsys_tag = script_langsys[0].langsys;
1248 compose_script_langsys (script_tag, langsys_tag, name);
1252 XtSetArg (arg[0], XtNforeground, background);
1253 XtSetArg (arg[1], XtNbackground, foreground);
1254 XtCreateManagedWidget (name, labelWidgetClass, prev, arg, 2);
1259 XtSetArg (arg[0], XtNborderWidth, 0);
1260 XtSetArg (arg[1], XtNwidth, render_width - (FONT_WIDTH * 15));
1261 XtSetArg (arg[2], XtNorientation, XtorientHorizontal);
1262 box = XtCreateManagedWidget ("scritp-list", boxWidgetClass, prev, arg, 2);
1263 XtSetArg (arg[0], XtNstate, True);
1264 w = XtCreateManagedWidget (name, toggleWidgetClass, box, arg, 1);
1265 XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1266 XtSetArg (arg[0], XtNradioGroup, w);
1267 for (i = 1; i < n; i++)
1269 compose_script_langsys (script_langsys[i].script,
1270 script_langsys[i].langsys, name);
1271 w = XtCreateManagedWidget (name, toggleWidgetClass, box, arg, 1);
1272 XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1280 create_otf_widgets (Widget prev, FeatureRec *rec)
1285 XtSetArg (arg[0], XtNborderWidth, 0);
1286 XtSetArg (arg[1], XtNleft, XawChainLeft);
1287 XtSetArg (arg[2], XtNright, XawChainLeft);
1288 XtSetArg (arg[3], XtNtop, XawChainTop);
1289 XtSetArg (arg[4], XtNbottom, XawChainTop);
1290 XtSetArg (arg[5], XtNfromVert, prev);
1291 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1292 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
1294 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
1295 XtSetArg (arg[0], XtNborderWidth, 1);
1296 XtSetArg (arg[1], XtNinternalHeight, 4);
1297 XtSetArg (arg[2], XtNinternalWidth, 4);
1298 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
1299 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1300 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
1301 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1304 setup_feature_rec (rec);
1311 String quit_action = "<KeyPress>q: set() notify() unset()";
1312 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
1313 <KeyPress>Home: set() notify() unset()";
1314 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
1315 <KeyPress>Up: set() notify() unset()";
1316 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
1317 <KeyPress>Left: set() notify() unset()";
1318 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
1319 <KeyPress>Right: set() notify() unset()";
1320 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
1321 <KeyPress>Down: set() notify() unset()";
1322 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
1323 <KeyPress>End: set() notify() unset()";
1327 String trans = "<Expose>: Expose()";
1329 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
1330 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
1332 XtSetArg (arg[0], XtNleft, XawChainLeft);
1333 XtSetArg (arg[1], XtNright, XawChainLeft);
1334 XtSetArg (arg[2], XtNtop, XawChainTop);
1335 XtSetArg (arg[3], XtNbottom, XawChainTop);
1336 XtSetArg (arg[4], XtNborderWidth, 0);
1337 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
1338 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
1340 XtSetArg (arg[6], XtNfromVert, command_area);
1341 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
1343 XtSetArg (arg[4], XtNborderWidth, 0);
1344 XtSetArg (arg[5], XtNfromVert, navi_area);
1345 XtSetArg (arg[6], XtNdefaultDistance, 0);
1346 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
1349 XtSetArg (arg[5], XtNfromVert, glyph_area);
1354 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1355 uvs_area = XtCreateManagedWidget ("uvs-area", boxWidgetClass,
1357 XtSetArg (arg2[0], XtNborderWidth, 0);
1358 XtSetArg (arg2[1], XtNlabel, "Variation Selector: ");
1359 uvs_label = XtCreateManagedWidget ("uvs-label", labelWidgetClass,
1361 XtSetArg (arg2[0], XtNborderWidth, 1);
1362 for (i = 0; i < sub14->nRecords; i++)
1364 OTF_VariationSelectorRecord *record = sub14->Records + i;
1365 unsigned selector = record->varSelector;
1369 idx = (selector <= 0xFE0F ? selector - 0xFE00
1370 : selector - 0xE0100 + 16);
1373 uvs[idx].c = selector;
1374 sprintf (lbl, "%03d", idx + 1);
1375 XtSetArg (arg2[1], XtNlabel, lbl);
1376 XtSetArg (arg2[2], XtNsensitive, False);
1377 uvs[idx].w = XtCreateManagedWidget ("lbl", commandWidgetClass,
1379 XtAddCallbackWithCast (unsigned, uvs[idx].w, UVSProc, idx);
1381 XtSetArg (arg[5], XtNfromVert, uvs_area);
1383 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
1386 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
1387 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
1388 command_area, arg, 1);
1389 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
1391 dump = XtCreateManagedWidget ("DumpImage", commandWidgetClass,
1392 command_area, arg, 1);
1393 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
1395 XtSetArg (arg[0], XtNborderWidth, 0);
1396 XtSetArg (arg[1], XtNwidth, 10);
1397 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
1399 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
1400 XtSetArg (arg[0], XtNstate, True);
1401 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
1402 command_area, arg, 1);
1403 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1404 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1405 for (i = 0; i < face->num_charmaps; i++)
1407 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1409 command_area, arg, 1);
1410 XtAddCallbackWithCast (int, charmap[i + 1], CharmapProc, i);
1413 XtSetArg (arg[0], XtNlabel, " |< (f)");
1414 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1415 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1417 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1418 XtSetArg (arg[0], XtNlabel, "<< (P)");
1419 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1420 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1422 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1423 XtSetArg (arg[0], XtNlabel, "< (p)");
1424 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1425 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1427 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1428 XtSetArg (arg[0], XtNlabel, " 0000 ");
1429 range = XtCreateManagedWidget ("range", labelWidgetClass,
1431 XtSetArg (arg[0], XtNforeground, &foreground);
1432 XtSetArg (arg[1], XtNbackground, &background);
1433 XtGetValues (range, arg, 2);
1435 XtSetArg (arg[0], XtNlabel, "> (n)");
1436 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1437 next = XtCreateManagedWidget ("next", commandWidgetClass,
1439 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1440 XtSetArg (arg[0], XtNlabel, ">> (N)");
1441 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1442 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1444 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1445 XtSetArg (arg[0], XtNlabel, ">| (l)");
1446 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1447 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1449 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1451 XtSetArg (arg[0], XtNleft, XawChainLeft);
1452 XtSetArg (arg[1], XtNright, XawChainLeft);
1453 XtSetArg (arg[2], XtNtop, XawChainTop);
1454 XtSetArg (arg[3], XtNbottom, XawChainTop);
1456 for (i = 0; i < 8; i++)
1462 sprintf (str, "%XX", i);
1463 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1464 XtSetArg (arg[n], XtNlabel, str), n++;
1465 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1467 XtSetArg (arg[n], XtNfromVert, w), n++;
1468 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1469 index_label[i] = head;
1470 for (j = 0; j < 16; j++)
1476 XtSetArg (arg[n], XtNfromVert, w), n++;
1478 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1480 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1481 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1482 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1483 glyph_area, arg, n);
1484 XtAddCallbackWithCast (int, glyph[k], RenderProc, k);
1488 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1489 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1490 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1491 XtSetArg (arg[6], XtNfromHoriz, w);
1492 XtSetArg (arg[7], XtNborderWidth, 0);
1494 for (j = 0; j < 16; j++)
1498 sprintf (str, "X%X", j);
1499 XtSetArg (arg[8], XtNlabel, str);
1500 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1501 XtSetArg (arg[6], XtNfromHoriz, w);
1504 XtSetArg (arg[0], XtNleft, XawChainLeft);
1505 XtSetArg (arg[1], XtNright, XawChainLeft);
1506 XtSetArg (arg[2], XtNtop, XawChainTop);
1507 XtSetArg (arg[3], XtNbottom, XawChainTop);
1508 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1509 XtSetArg (arg[5], XtNborderWidth, 0);
1510 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1511 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1512 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1513 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1514 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1515 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1516 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1517 alt_subst = XtCreateManagedWidget ("AltSubst", toggleWidgetClass, w, arg, 0);
1518 XtAddCallback (alt_subst, XtNcallback, AltSubstProc, NULL);
1520 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1521 XtSetArg (arg[5], XtNborderWidth, 0);
1522 XtSetArg (arg[6], XtNfromVert, w);
1523 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1525 XtSetArg (arg[0], XtNborderWidth, 0);
1526 XtSetArg (arg[1], XtNlabel, "raw: ");
1527 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1529 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1530 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1535 OTF_get_table (otf, "GSUB");
1536 OTF_get_table (otf, "GPOS");
1537 w = create_otf_script_widgets (w);
1540 gsub.label = "GSUB";
1541 gsub.gsub_gpos = otf->gsub;
1542 w = create_otf_widgets (w, &gsub);
1546 gpos.label = "GPOS";
1547 gpos.gsub_gpos = otf->gpos;
1548 w = create_otf_widgets (w, &gpos);
1552 XtSetArg (arg[6], XtNfromVert, w);
1553 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1554 XtSetArg (arg[0], XtNborderWidth, 0);
1555 XtSetArg (arg[1], XtNlabel, "seq: ");
1556 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1558 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1559 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1561 XtSetArg (arg[6], XtNfromVert, seq);
1562 code = XtCreateManagedWidget ("code", boxWidgetClass, render_area, arg, 7);
1563 XtSetArg (arg[0], XtNborderWidth, 0);
1564 XtSetArg (arg[1], XtNlabel, "code:");
1565 code_label = XtCreateManagedWidget ("code-label", labelWidgetClass,
1567 XtSetArg (arg[1], XtNlabel, "");
1568 XtSetArg (arg[2], XtNwidth, render_width);
1569 code_list = XtCreateManagedWidget ("code-list", labelWidgetClass,
1571 XtInstallAllAccelerators (shell, shell);
1575 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1577 XTextProperty text_prop;
1578 char *pname = "otfview";
1579 char *fname = basename (filename);
1580 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1582 sprintf (name, "%s - %s", pname, fname);
1583 text_prop.value = (unsigned char *) name;
1584 text_prop.encoding = XA_STRING;
1585 text_prop.format = 8;
1586 text_prop.nitems = strlen (name);
1587 XSetWMName (display, XtWindow (shell), &text_prop);
1590 /* Format MSG by FMT and print the result to the stderr, and exit. */
1592 #define FATAL_ERROR(fmt, arg) \
1594 fprintf (stderr, fmt, arg); \
1599 x_error_handler (Display *display, XErrorEvent *error)
1605 help (char **argv, int err)
1607 FILE *fp = err ? stderr : stdout;
1609 fprintf (fp, "Usage: %s [ X-OPTION ... ] OTF-FILE [INDEX]\n",
1610 basename (argv[0]));
1611 fprintf (fp, " Environment variable PIXEL_SIZE specifies the pixel size.\n");
1612 fprintf (fp, " The default pixel size is %d, but is reduced\n",
1613 DEFAULT_PIXEL_SIZE);
1614 fprintf (fp, " if your screen is not that wide.\n");
1619 main (int argc, char **argv)
1621 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1625 OTF_GlyphString gstring;
1630 int fixed_pixel_size = 0;
1633 pixel_size = DEFAULT_PIXEL_SIZE;
1635 char *str = getenv ("PIXEL_SIZE");
1637 if (str && (i = atoi (str)) > 0)
1640 fixed_pixel_size = 1;
1644 gstring.size = gstring.used = 256;
1645 g = calloc (256, sizeof (OTF_Glyph));
1648 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1649 shellWidgetClass, arg, 0);
1650 display = XtDisplay (shell);
1651 /*XSynchronize (display, True);*/
1652 XSetErrorHandler (x_error_handler);
1653 display_width = DisplayWidth (display,
1654 XScreenNumberOfScreen (XtScreen (shell)));
1655 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1657 font = XLoadQueryFont (display, "fixed");
1661 if (!strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1666 fontindex = atoi (argv[2]);
1668 FATAL_ERROR ("Invalid font index: %d\n", fontindex);
1671 if ((err = FT_Init_FreeType (&library)))
1672 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1673 err = FT_New_Face (library, filename, fontindex, &face);
1674 if (err == FT_Err_Unknown_File_Format)
1675 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1677 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error (invalid face index?)");
1678 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1679 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1681 if (strstr (filename, ".ttf")
1682 || strstr (filename, ".TTF")
1683 || strstr (filename, ".otf")
1684 || strstr (filename, ".OTF"))
1686 otf = OTF_open_ft_face (face);
1689 if (OTF_get_table (otf, "head") < 0
1690 || OTF_get_table (otf, "cmap") < 0
1691 || (OTF_check_table (otf, "GSUB") < 0
1692 && OTF_check_table (otf, "GPOS") < 0))
1699 for (i = 0; i < otf->cmap->numTables; i++)
1700 if (otf->cmap->EncodingRecord[i].subtable.format == 14)
1702 sub14 = otf->cmap->EncodingRecord[i].subtable.f.f14;
1711 filename = basename (filename);
1712 sprintf (title, "%s family:%s style:%s",
1713 filename, face->family_name, face->style_name);
1714 XtSetArg (arg[0], XtNtitle, title);
1715 XtSetValues (shell, arg, 1);
1718 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1719 * pixel_size / face->units_per_EM);
1720 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1722 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1723 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1724 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1725 * pixel_size / face->units_per_EM);
1727 if (glyph_width < FONT_WIDTH * 4)
1728 glyph_width = FONT_WIDTH * 4;
1730 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1731 * pixel_size / face->units_per_EM);
1733 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1734 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1735 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1736 glyph_width, glyph_height, 1);
1739 unsigned long valuemask = GCFunction | GCLineWidth;
1742 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1743 XSetFont (display, gc, font->fid);
1744 values.function = GXset;
1745 values.line_width = 1;
1746 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1747 XSetFont (display, gc_set, font->fid);
1748 values.function = GXor;
1749 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1750 values.function = GXcopyInverted;
1751 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1754 XFillRectangle (display, none_pixmap, gc, 0, 0,
1755 glyph_width, glyph_height);
1756 XDrawString (display, none_pixmap, gc_inv,
1757 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1758 glyph_height / 2, "none", 4);
1760 render_width = (glyph_width + 4) * 15 + 1;
1761 render_height = glyph_height + 2;
1763 charmap_rec[0].platform_id = -1;
1764 charmap_rec[0].encoding_id = -1;
1765 strcpy (charmap_rec[0].name, "no charmap");
1767 for (i = 0; i < face->num_charmaps; i++)
1769 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1770 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1771 sprintf (charmap_rec[i + 1].name, "%d-%d",
1772 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1773 if (face->charmaps[i]->platform_id == 0
1774 || (face->charmaps[i]->platform_id == 3
1775 && face->charmaps[i]->encoding_id == 1))
1776 strcat (charmap_rec[i + 1].name, " (unicode)");
1777 else if (face->charmaps[i]->platform_id == 1
1778 && face->charmaps[i]->encoding_id == 0)
1779 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1782 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1783 render_width, render_height, 1);
1784 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1785 render_width, render_height, 1);
1787 memset (bitmap, 0, sizeof (bitmap));
1791 update_glyph_area ();
1792 update_render_area ();
1794 XtAppAddActions (context, actions, XtNumber (actions));
1795 XtRealizeWidget (shell);
1796 XtAppMainLoop (context);
1801 #else /* not HAVE_X11_XAW_COMMAND_H */
1804 main (int argc, char **argv)
1807 "Building of this program failed (lack of some header files)\n");