1 /* otfview.c -- View glyphs of OpenType fonts.
3 Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009
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 | +---- uvs_area (box) (optional) -------+ |
90 | +--------------------------------------+ |
91 | +--- render_area (form) ---------------+ |
92 | | clear del bidi alt_subst | |
93 | | +--- raw (box) --------------------+ | |
94 | | | raw_label raw_image | | |
95 | | +----------------------------------+ | |
96 | | GSUB all none features... | |
97 | | GPOS all none features... | |
98 | | +--- seq (box) --------------------+ | |
99 | | | seq_label seq_image | | |
100 | | +----------------------------------+ | |
101 | +--------------------------------------+ |
102 +------------------------------------------+ */
104 Widget command_area, quit, dump, *charmap;
105 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
106 Widget glyph_area, glyph[128], index_label[8];
107 Widget uvs_area, uvs_label;
108 Widget render_area, clear, del, bidi, alt_subst, raw, seq;
109 Widget raw_label, raw_image, seq_label, seq_image;
110 unsigned long foreground, background;
122 OTF_GSUB_GPOS *gsub_gpos;
123 OTF_LangSys *langsys;
125 FeatureElement *features;
129 FeatureRec gsub, gpos;
131 /* Currently selected script and langsys. */
132 OTF_Tag script_tag, langsys_tag;
137 GC gc, gc_set, gc_or, gc_inv;
141 unsigned width, height;
146 BitmapRec bitmap[0x110000];
148 int render_width, render_height;
149 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
163 int do_alternate_subst;
164 unsigned glyph_width, glyph_height;
165 int glyph_x, glyph_y;
174 OTF_EncodingSubtable14 *sub14 = NULL;
186 create_pixmap (int index)
188 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
194 bitmap[index].pixmap = none_pixmap;
197 ximage.height = face->glyph->bitmap.rows;
198 ximage.width = face->glyph->bitmap.width;
200 ximage.bits_per_pixel = 1;
202 ximage.format = XYPixmap;
203 ximage.data = (char *) face->glyph->bitmap.buffer;
204 ximage.byte_order = MSBFirst;
205 ximage.bitmap_unit = 8;
206 ximage.bitmap_bit_order = MSBFirst;
207 ximage.bitmap_pad = 8;
208 ximage.bytes_per_line = face->glyph->bitmap.pitch;
209 XInitImage (&ximage);
210 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
211 glyph_width, glyph_height, 1);
212 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
213 XPutImage (display, pixmap, gc, &ximage, 0, 0,
214 glyph_x + face->glyph->bitmap_left,
215 glyph_y - face->glyph->bitmap_top,
216 ximage.width, ximage.height);
217 bitmap[index].pixmap = pixmap;
218 bitmap[index].width = ximage.width;
219 bitmap[index].height = ximage.height;
220 bitmap[index].x = face->glyph->bitmap_left;
221 bitmap[index].y = - face->glyph->bitmap_top;
222 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
233 for (i = 0; i < 128; i++)
235 int index = glyph_index + i;
237 if (charmap_index >= 0)
238 index = FT_Get_Char_Index (face, (FT_ULong) index);
239 if (charmap_index >= 0 && ! index)
240 XtSetArg (arg[0], XtNbitmap, none_pixmap);
243 if (! bitmap[index].pixmap)
244 create_pixmap (index);
245 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
247 XtSetValues (glyph[i], arg, 1);
250 msb = (glyph_index >> 7) % 2 ? 8 : 0;
251 for (i = 0; i < 8; i++)
255 sprintf (str, "%XX", i | msb );
256 XtSetArg (arg[0], XtNheight, glyph_height + 5);
257 XtSetArg (arg[1], XtNlabel, str);
258 XtSetValues (index_label[i], arg, 2);
261 if (glyph_index < 0x10000)
262 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
264 sprintf (buf, "%06X-%06X", glyph_index, glyph_index + 0x7F);
265 XtSetArg (arg[0], XtNlabel, buf);
266 XtSetValues (range, arg, 1);
270 update_uvs_area (int c)
272 OTF_GlyphID code[256];
276 OTF_get_variation_glyphs (otf, c, code);
278 for (i = 0; i < 256; i++)
282 XtSetArg (arg[0], XtNsensitive, True);
284 XtSetArg (arg[0], XtNsensitive, False);
285 XtSetValues (uvs[i].w, arg, 1);
291 get_features (OTF_FeatureList *list, FeatureRec *rec)
296 if (! rec->langsys || ! rec->features || ! rec->features[0].on)
298 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
300 if (rec->features[i].on)
305 str = malloc (n * 5);
306 for (i = 0, p = str; i < n; i++, p += 5)
308 OTF_tag_name (rec->features[i].tag, p);
316 #define DEVICE_DELTA(table, size) \
317 (((table).DeltaValue \
318 && ((size) >= (table).StartSize && (size) <= (table).EndSize)) \
319 ? (table).DeltaValue[(size) >= (table).StartSize] \
323 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
324 OTF_Glyph *g, int *x, int *y)
326 if (anchor->AnchorFormat == 2)
329 int ap = anchor->f.f1.AnchorPoint;
331 FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
332 outline = &ft_face->glyph->outline;
333 if (ap < outline->n_points)
335 *x = outline->points[ap].x;
336 *y = outline->points[ap].y;
339 else if (anchor->AnchorFormat == 3)
341 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
342 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
350 OTF_GlyphString gstring;
351 OTF_Glyph *g, *prev, *base, *mark;
353 int len = glyph_rec.n_glyphs;
355 int unitsPerEm = face->units_per_EM;
357 gstring.size = gstring.used = len;
358 gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
359 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
360 for (i = 0; i < len; i++)
362 gstring.glyphs[i].c = glyph_rec.codes[i];
363 if (charmap_index < 0)
364 gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
367 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
368 XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
371 char *script_name = NULL, *langsys_name = NULL, buf[10];
377 OTF_tag_name (script_tag, script_name);
381 langsys_name = buf + 5;
382 OTF_tag_name (langsys_tag, langsys_name);
385 OTF_drive_cmap (otf, &gstring);
386 OTF_drive_gdef (otf, &gstring);
389 str = get_features (&otf->gsub->FeatureList, &gsub);
392 if (do_alternate_subst)
393 OTF_drive_gsub_alternate (otf, &gstring,
394 script_name, langsys_name, str);
396 OTF_drive_gsub (otf, &gstring, script_name, langsys_name, str);
402 str = get_features (&otf->gpos->FeatureList, &gpos);
405 OTF_drive_gpos2 (otf, &gstring, script_name, langsys_name, str);
416 for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
417 prev < g; prev++, g--)
418 temp = *prev, *prev = *g, *g = temp;
419 for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
420 if (g->GlyphClass == 3)
424 while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
426 for (g0 = g; prev < g0; prev++, g0--)
427 temp = *prev, *prev = *g, *g = temp;
433 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
434 i < gstring.used; i++, prev = g++)
436 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
437 int xoff = 0, yoff = 0;
439 int advance = bmp->advance;
441 if (gstring.glyphs[i].glyph_id && ! bmp->pixmap)
443 create_pixmap (gstring.glyphs[i].glyph_id);
446 advance = bmp->advance;
448 if (g->positioning_type)
452 switch (g->positioning_type)
456 int format = g->f.f1.format;
458 if (format & OTF_XPlacement)
459 xoff += g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
460 if (format & OTF_XPlaDevice)
461 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
462 if (format & OTF_YPlacement)
463 yoff += g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
464 if (format & OTF_YPlaDevice)
465 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
466 if (format & OTF_XAdvance)
467 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
468 if (format & OTF_XAdvDevice)
469 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice,
475 /* Not yet supported. */
481 prev_width = base_width;
482 goto label_adjust_anchor;
483 default: /* i.e. case 6 */
490 int base_x, base_y, mark_x, mark_y;
492 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
493 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
494 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
495 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
497 if (g->f.f4.base_anchor->AnchorFormat != 1)
498 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
499 if (g->f.f4.mark_anchor->AnchorFormat != 1)
500 adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
501 xoff = (base_x - prev_width) - mark_x;
502 yoff = base_y - mark_y;
505 if (i + 1 == gstring.used
506 || gstring.glyphs[i + 1].glyph_id
507 || ! gstring.glyphs[i + 1].positioning_type)
513 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
514 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
515 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
518 if (g->GlyphClass == OTF_GlyphClass0)
519 base = mark = g, base_width = advance;
520 else if (g->GlyphClass == OTF_GlyphClassMark)
523 base = g, base_width = advance;
525 free (gstring.glyphs);
527 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
528 XtSetValues (seq_image, arg, 1);
533 update_render_area ()
539 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
540 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
542 if (glyph_rec.glyphs[i] >= 0)
544 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
547 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
548 0, 0, glyph_width, glyph_height,
549 (glyph_width + 4) * i + 1, 1);
550 XDrawRectangle (display, raw_pixmap, gc_set,
551 (glyph_width + 4) * i, 0,
552 glyph_width + 1, glyph_height + 1);
553 XDrawLine (display, raw_pixmap, gc_set,
554 (glyph_width + 4) * i + 1 + glyph_x, 1,
555 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
556 XDrawLine (display, raw_pixmap, gc_set,
557 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
558 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
561 sprintf (buf, "%04X", glyph_rec.codes[i]);
562 XDrawString (display, raw_pixmap, gc_inv,
563 (glyph_width + 4) * i + 1
564 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
565 glyph_height + 2 + FONT_HEIGHT, buf, 4);
569 /* Variation Selector */
570 int idx = - glyph_rec.glyphs[i];
573 sprintf (buf, "%03d", idx);
574 XDrawRectangle (display, raw_pixmap, gc_set,
575 (glyph_width + 4) * i, 0,
576 glyph_width + 1, glyph_height + 1);
577 XDrawString (display, raw_pixmap, gc_set,
578 (glyph_width + 4) * i + 1
579 + (glyph_width - XTextWidth (font, "VS", 2)) / 2,
580 1 + glyph_height / 2, "VS", 2);
581 XDrawString (display, raw_pixmap, gc_set,
582 (glyph_width + 4) * i + 1
583 + (glyph_width - XTextWidth (font, buf, 3)) / 2,
584 1 + glyph_height / 2 + FONT_ASCENT, buf, 3);
587 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
588 XtSetValues (raw_image, arg, 1);
593 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
595 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
599 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
601 int g_width, g_height;
603 /* unit in points (1/72 inch); to fit in both US-letter and A4 */
604 static int xoff = 30, yoff = 30;
605 static int unit = 30;
606 static int margin = 2;
607 static int title_height = 20, label_height = 10;
608 int total_width = (unit + margin * 2) * 16;
609 int total_height = (unit + margin * 2 + label_height) * 16 + title_height;
610 /* pixel size (dots) */
613 char *name = alloca (strlen (filename) + 10);
615 int index = (glyph_index / 0x100) * 0x100;
618 g_width = face->bbox.xMax - face->bbox.xMin;
619 g_height = face->bbox.yMax - face->bbox.yMin;
620 if (g_width > g_height)
622 scale = g_width * size;
623 g_x = face->bbox.xMin * unit / g_width;
624 g_y = face->bbox.yMin * unit / g_width;
628 scale = g_height * size;
629 g_x = face->bbox.xMin * unit / g_height;
630 g_y = face->bbox.yMin * unit / g_height;
632 scale /= face->units_per_EM;
634 FT_Set_Pixel_Sizes (face, 0, size);
636 sprintf (name, "%s-%04X.ps", face->family_name, index);
637 printf ("Writing %s ... ", name);
639 fp = fopen (name, "w");
641 fprintf (fp, "%s\n", "%!PS-Adobe-2.0 EPSF-2.0");
642 fprintf (fp, "%s\n", "%%Creater: otfview");
643 fprintf (fp, "%s %s(%s)-%04X\n", "%%Title:",
644 face->family_name, face->style_name, index);
645 fprintf (fp, "%s\n", "%%Pages: 1");
646 fprintf (fp, "%s %d %d %d %d\n", "%%BoundingBox:",
647 xoff, yoff, xoff + total_width, yoff + total_height);
648 fprintf (fp, "%s\n", "%%EndComments");
649 fprintf (fp, "%s\n", "%%BeginProlog");
650 fprintf (fp, "/W %d def\n", unit + margin * 2);
651 fprintf (fp, "/H %d def\n", unit + margin * 2 + label_height);
652 fprintf (fp, "/STR 10 string def\n");
653 fprintf (fp, "/DrawIndex {\n");
654 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");
655 fprintf (fp, "} def\n");
656 fprintf (fp, "/DrawTitle {\n");
657 fprintf (fp, " /Courier findfont 20 scalefont setfont\n");
658 fprintf (fp, " %d %d 4 add moveto\n", xoff + total_width / 2,
659 yoff + total_height - title_height + 2);
660 fprintf (fp, " (%s(%s)-%04X) dup stringwidth pop 2 div neg 0 rmoveto show\n",
661 face->family_name, face->style_name, index);
662 fprintf (fp, "} def\n");
663 fprintf (fp, "/DrawFrame { gsave %d %d translate 0 setlinewidth\n",
665 fprintf (fp, " /Courier findfont 10 scalefont setfont\n");
666 fprintf (fp, " /I %d def\n", index);
667 fprintf (fp, " 0 1 16 { W mul 0 moveto 0 H 16 mul rlineto stroke } for\n");
668 fprintf (fp, " 0 1 16 { H mul 0 exch moveto W 16 mul 0 rlineto stroke } for\n");
669 fprintf (fp, " 0 1 15 { H mul %d add 0 exch moveto W 16 mul 0 rlineto stroke } for\n", label_height);
670 fprintf (fp, " 15 -1 0 { gsave H mul 0 exch translate 0 0 moveto\n");
671 fprintf (fp, " 0 1 15 { gsave W mul 0 moveto\n");
672 fprintf (fp, " 4 2 rmoveto DrawIndex /I I 1 add def grestore} for\n");
673 fprintf (fp, " grestore } for grestore } def\n");
674 fprintf (fp, "%s\n", "%%EndProlog");
675 fprintf (fp, "DrawTitle DrawFrame\n");
677 for (i = 0; i < 16; i++)
678 for (j = 0; j < 16; j++, index++)
682 if (charmap_index >= 0)
683 idx = FT_Get_Char_Index (face, (FT_ULong) index);
687 && FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0
688 && face->glyph->bitmap.rows > 0
689 && face->glyph->bitmap.width > 0)
691 unsigned char *p = face->glyph->bitmap.buffer;
692 int width = (face->glyph->bitmap.width - 1) / 8 + 1;
694 fprintf (fp, "gsave %f %f translate %d %d scale 0 0 moveto\n",
695 xoff + (unit + margin * 2) * j + margin - g_x,
696 yoff + (unit + label_height + margin * 2) * (15 - i) + label_height + margin - g_y,
698 fprintf (fp, "%d %d true [%f 0 0 %f %d %d]\n",
699 width * 8, face->glyph->bitmap.rows,
700 scale, -scale, -face->glyph->bitmap_left,
701 face->glyph->bitmap_top);
703 for (k = 0; k < face->glyph->bitmap.rows;
704 k++, p += face->glyph->bitmap.pitch)
706 for (l = 0; l < width; l++)
707 fprintf (fp, "%02X", p[l]);
710 fprintf (fp, ">} imagemask grestore\n");
714 int boxsize = unit + margin * 2;
716 fprintf (fp, "gsave 0 setlinewidth %d %d translate\n",
718 yoff + (boxsize + label_height) * (15 - i) + label_height);
719 fprintf (fp, "0 0 moveto %d %d lineto stroke\n",
721 fprintf (fp, "0 %d moveto %d 0 lineto stroke grestore\n",
725 fprintf (fp, "showpage\n");
729 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
734 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
736 int old_glyph_index = glyph_index;
739 CAST_FROM_XTPOINTER (int, client_data, data);
741 if (data == -3 && glyph_index > 0)
743 else if (data == -2 && glyph_index > 0)
744 glyph_index = (glyph_index - 1) & 0x1FF000;
745 else if (data == -1 && glyph_index > 0)
747 else if (data == 1 && glyph_index < 0x10FF80)
749 else if (data == 2 && glyph_index < 0x10F000)
750 glyph_index = (glyph_index + 0x1000) & 0x1FF000;
751 else if (data == 3 && glyph_index < 0x10F000)
752 glyph_index = 0x10FF80;
753 if (glyph_index != old_glyph_index)
754 update_glyph_area ();
758 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
762 CAST_FROM_XTPOINTER (int, client_data, data);
764 if (charmap_index == data)
766 charmap_index = data;
767 if (charmap_index >= 0)
768 FT_Set_Charmap (face, face->charmaps[charmap_index]);
769 update_glyph_area ();
773 UVSProc (Widget w, XtPointer client_data, XtPointer call_data)
777 OTF_VariationSelectorRecord *record;
780 CAST_FROM_XTPOINTER (unsigned, client_data, idx);
781 selector = uvs[idx].c;
783 if (glyph_rec.n_glyphs >= 64)
785 for (i = 0; i < sub14->nRecords; i++)
787 record = sub14->Records + i;
788 if (record->varSelector == selector)
791 if (i < sub14->nRecords)
793 if (glyph_rec.n_glyphs > 0
794 && glyph_rec.glyphs[glyph_rec.n_glyphs - 1] < 0)
795 glyph_rec.n_glyphs--;
796 glyph_rec.codes[glyph_rec.n_glyphs] = selector;
797 glyph_rec.glyphs[glyph_rec.n_glyphs++] = - idx - 1;
798 update_render_area ();
803 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
807 CAST_FROM_XTPOINTER (int, client_data, data);
811 if (glyph_rec.n_glyphs > 0)
814 glyph_rec.n_glyphs--;
816 glyph_rec.n_glyphs = 0;
817 update_render_area ();
820 else if (glyph_rec.n_glyphs < 64)
822 int index = glyph_index + data;
824 if (charmap_index >= 0)
825 index = FT_Get_Char_Index (face, (FT_ULong) index);
826 if (bitmap[index].pixmap)
828 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + data;
829 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
831 update_uvs_area (glyph_index + data);
832 update_render_area ();
838 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
842 reversed = ! reversed;
844 XtSetArg (arg[0], XtNlabel, "L<-R");
846 XtSetArg (arg[0], XtNlabel, "L->R");
847 XtSetValues (w, arg, 1);
852 AltSubstProc (Widget w, XtPointer client_data, XtPointer call_data)
854 do_alternate_subst = ! do_alternate_subst;
859 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
861 FeatureRec *rec = (FeatureRec *) client_data;
868 XtSetArg (arg[0], XtNlabel, &label);
869 XtGetValues (w, arg, 1);
870 if (! strcmp (label, "all"))
872 else if (! strcmp (label, "none"))
876 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
877 if (rec->features[idx].w == w)
879 if (idx == rec->langsys->FeatureCount)
886 for (i = j = 0; j < rec->langsys->FeatureCount; j++)
888 int index = rec->langsys->FeatureIndex[j];
891 = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
892 rec->features[j].on = on;
897 OTF_Tag tag = rec->features[idx].tag;
900 if (rec->features[i].on)
903 j < rec->langsys->FeatureCount && rec->features[j].on; j++)
904 rec->features[j - 1].tag = rec->features[j].tag;
905 rec->features[j - 1].tag = tag;
906 rec->features[j - 1].on = 0;
910 for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
911 rec->features[i].tag = rec->features[i - 1].tag;
912 rec->features[i].tag = tag;
913 rec->features[i].on = 1;
921 if (rec->features[i].on)
923 XtSetArg (arg[0], XtNborderWidth, 3);
924 XtSetArg (arg[1], XtNinternalHeight, 2);
925 XtSetArg (arg[2], XtNinternalWidth, 2);
929 XtSetArg (arg[0], XtNborderWidth, 1);
930 XtSetArg (arg[1], XtNinternalHeight, 4);
931 XtSetArg (arg[2], XtNinternalWidth, 4);
933 OTF_tag_name (rec->features[i].tag, str);
934 XtSetArg (arg[3], XtNlabel, str);
935 XtSetValues (rec->features[i].w, arg, 4);
941 setup_feature_rec (FeatureRec *rec)
947 if (! rec->gsub_gpos)
949 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
950 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
952 OTF_Script *script = rec->gsub_gpos->ScriptList.Script + i;
956 for (j = 0; j < script->LangSysCount; j++)
957 if (script->LangSysRecord[j].LangSysTag == langsys_tag)
959 rec->langsys = script->LangSys + j;
964 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
972 XtSetArg (arg[0], XtNborderWidth, 1);
973 XtSetArg (arg[1], XtNinternalHeight, 4);
974 XtSetArg (arg[2], XtNinternalWidth, 4);
975 XtSetArg (arg[3], XtNborderColor, foreground);
976 XtSetArg (arg[4], XtNsensitive, True);
977 for (i = 0; i < rec->langsys->FeatureCount; i++)
979 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
980 int index = rec->langsys->FeatureIndex[i];
983 if (! rec->features[i].w)
985 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
986 rec->parent, arg, 0);
987 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
988 rec->features[i].w = w;
991 rec->features[i].tag = feature[index].FeatureTag;
992 rec->features[i].on = 0;
993 OTF_tag_name (rec->features[i].tag, label);
994 XtSetArg (arg[5], XtNlabel, label);
995 XtSetValues (rec->features[i].w, arg, 6);
998 XtSetArg (arg[0], XtNborderColor, background);
999 XtSetArg (arg[1], XtNsensitive, False);
1000 XtSetArg (arg[2], XtNlabel, " ");
1001 for (; i < rec->num_features; i++)
1003 if (! rec->features[i].w)
1005 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
1006 rec->parent, arg, 0);
1007 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1008 rec->features[i].w = w;
1010 XtSetValues (rec->features[i].w, arg, 3);
1015 compose_script_langsys (OTF_Tag script, OTF_Tag langsys, char *name)
1017 OTF_tag_name (script, name);
1021 OTF_tag_name (langsys, name + 5);
1028 decompose_script_langsys (OTF_Tag *script, OTF_Tag *langsys, char *name)
1030 *script = OTF_tag (name);
1032 *langsys = OTF_tag (name + 5);
1038 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
1041 OTF_Tag script, langsys;
1044 XtSetArg (arg[0], XtNlabel, &name);
1045 XtGetValues (w, arg, 1);
1046 decompose_script_langsys (&script, &langsys, name);
1047 if (script_tag == script && langsys_tag == langsys)
1049 script_tag = script;
1050 langsys_tag = langsys;
1051 setup_feature_rec (&gsub);
1052 setup_feature_rec (&gpos);
1057 create_otf_script_widgets (Widget prev)
1061 int n, prev_n, i, j;
1069 XtSetArg (arg[0], XtNborderWidth, 0);
1070 XtSetArg (arg[1], XtNleft, XawChainLeft);
1071 XtSetArg (arg[2], XtNright, XawChainLeft);
1072 XtSetArg (arg[3], XtNtop, XawChainTop);
1073 XtSetArg (arg[4], XtNbottom, XawChainTop);
1074 XtSetArg (arg[5], XtNfromVert, prev);
1075 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1076 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
1077 XtCreateManagedWidget ("script(langsys)", labelWidgetClass, prev, arg, 1);
1081 for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1082 n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
1084 for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1085 n += otf->gpos->ScriptList.Script[i].LangSysCount + 1;
1086 script_langsys = alloca ((sizeof script_langsys[0]) * n);
1090 for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1092 OTF_Tag tag = otf->gsub->ScriptList.Script[i].ScriptTag;
1094 script_langsys[n].script = tag;
1095 script_langsys[n++].langsys = 0;
1097 < otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1099 = otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1100 for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
1102 script_langsys[n].script = tag;
1103 script_langsys[n++].langsys
1104 = otf->gsub->ScriptList.Script[i].LangSysRecord[j].LangSysTag;
1106 < otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount)
1108 = otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount;
1111 gsub.num_features = nfeatures;
1114 gsub.num_features = nfeatures;
1115 gsub.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1116 memset (gsub.features, 0, (sizeof (FeatureElement)) * nfeatures);
1121 for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1123 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
1127 < otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1129 = otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1130 for (k = 0; k < prev_n; k++)
1131 if (tag == script_langsys[k].script)
1135 script_langsys[n].script = tag;
1136 script_langsys[n++].langsys = 0;
1138 for (j = 0; j < otf->gpos->ScriptList.Script[i].LangSysCount; j++)
1144 OTF_Script *script = otf->gpos->ScriptList.Script + i;
1146 for (l = k; l < prev_n && tag == script_langsys[l].script; l++)
1147 if (script->LangSysRecord[j].LangSysTag
1148 == script_langsys[l].langsys)
1155 script_langsys[n].script = tag;
1156 script_langsys[n++].langsys = 0;
1159 < otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount)
1161 = otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount;
1167 gpos.num_features = nfeatures;
1168 gpos.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1169 memset (gpos.features, 0, (sizeof (FeatureElement)) * nfeatures);
1175 script_tag = script_langsys[0].script;
1176 langsys_tag = script_langsys[0].langsys;
1177 compose_script_langsys (script_tag, langsys_tag, name);
1181 XtSetArg (arg[0], XtNforeground, background);
1182 XtSetArg (arg[1], XtNbackground, foreground);
1183 XtCreateManagedWidget (name, labelWidgetClass, prev, arg, 2);
1187 XtSetArg (arg[0], XtNstate, True);
1188 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
1189 XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1190 XtSetArg (arg[0], XtNradioGroup, w);
1191 for (i = 1; i < n; i++)
1193 compose_script_langsys (script_langsys[i].script,
1194 script_langsys[i].langsys, name);
1195 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
1196 XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1204 create_otf_widgets (Widget prev, FeatureRec *rec)
1209 XtSetArg (arg[0], XtNborderWidth, 0);
1210 XtSetArg (arg[1], XtNleft, XawChainLeft);
1211 XtSetArg (arg[2], XtNright, XawChainLeft);
1212 XtSetArg (arg[3], XtNtop, XawChainTop);
1213 XtSetArg (arg[4], XtNbottom, XawChainTop);
1214 XtSetArg (arg[5], XtNfromVert, prev);
1215 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1216 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
1218 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
1219 XtSetArg (arg[0], XtNborderWidth, 1);
1220 XtSetArg (arg[1], XtNinternalHeight, 4);
1221 XtSetArg (arg[2], XtNinternalWidth, 4);
1222 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
1223 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1224 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
1225 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1228 setup_feature_rec (rec);
1235 String quit_action = "<KeyPress>q: set() notify() unset()";
1236 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
1237 <KeyPress>Home: set() notify() unset()";
1238 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
1239 <KeyPress>Up: set() notify() unset()";
1240 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
1241 <KeyPress>Left: set() notify() unset()";
1242 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
1243 <KeyPress>Right: set() notify() unset()";
1244 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
1245 <KeyPress>Down: set() notify() unset()";
1246 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
1247 <KeyPress>End: set() notify() unset()";
1251 String trans = "<Expose>: Expose()";
1253 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
1254 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
1256 XtSetArg (arg[0], XtNleft, XawChainLeft);
1257 XtSetArg (arg[1], XtNright, XawChainLeft);
1258 XtSetArg (arg[2], XtNtop, XawChainTop);
1259 XtSetArg (arg[3], XtNbottom, XawChainTop);
1260 XtSetArg (arg[4], XtNborderWidth, 0);
1261 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
1262 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
1264 XtSetArg (arg[6], XtNfromVert, command_area);
1265 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
1267 XtSetArg (arg[4], XtNborderWidth, 0);
1268 XtSetArg (arg[5], XtNfromVert, navi_area);
1269 XtSetArg (arg[6], XtNdefaultDistance, 0);
1270 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
1273 XtSetArg (arg[5], XtNfromVert, glyph_area);
1278 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1279 uvs_area = XtCreateManagedWidget ("uvs-area", boxWidgetClass,
1281 XtSetArg (arg2[0], XtNborderWidth, 0);
1282 XtSetArg (arg2[1], XtNlabel, "Variation Selector: ");
1283 uvs_label = XtCreateManagedWidget ("uvs-label", labelWidgetClass,
1285 XtSetArg (arg2[0], XtNborderWidth, 1);
1286 for (i = 0; i < sub14->nRecords; i++)
1288 OTF_VariationSelectorRecord *record = sub14->Records + i;
1289 unsigned selector = record->varSelector;
1293 idx = (selector <= 0xFE0F ? selector - 0xFE00
1294 : selector - 0xE0100 + 16);
1297 uvs[idx].c = selector;
1298 sprintf (lbl, "%03d", idx + 1);
1299 XtSetArg (arg2[1], XtNlabel, lbl);
1300 XtSetArg (arg2[2], XtNsensitive, False);
1301 uvs[idx].w = XtCreateManagedWidget ("lbl", commandWidgetClass,
1303 XtAddCallbackWithCast (unsigned, uvs[idx].w, UVSProc, idx);
1305 XtSetArg (arg[5], XtNfromVert, uvs_area);
1307 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
1310 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
1311 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
1312 command_area, arg, 1);
1313 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
1315 dump = XtCreateManagedWidget ("DumpImage", commandWidgetClass,
1316 command_area, arg, 1);
1317 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
1319 XtSetArg (arg[0], XtNborderWidth, 0);
1320 XtSetArg (arg[1], XtNwidth, 10);
1321 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
1323 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
1324 XtSetArg (arg[0], XtNstate, True);
1325 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
1326 command_area, arg, 1);
1327 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1328 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1329 for (i = 0; i < face->num_charmaps; i++)
1331 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1333 command_area, arg, 1);
1334 XtAddCallbackWithCast (int, charmap[i + 1], CharmapProc, i);
1337 XtSetArg (arg[0], XtNlabel, " |< (f)");
1338 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1339 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1341 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1342 XtSetArg (arg[0], XtNlabel, "<< (P)");
1343 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1344 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1346 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1347 XtSetArg (arg[0], XtNlabel, "< (p)");
1348 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1349 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1351 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1352 XtSetArg (arg[0], XtNlabel, " 0000 ");
1353 range = XtCreateManagedWidget ("range", labelWidgetClass,
1355 XtSetArg (arg[0], XtNforeground, &foreground);
1356 XtSetArg (arg[1], XtNbackground, &background);
1357 XtGetValues (range, arg, 2);
1359 XtSetArg (arg[0], XtNlabel, "> (n)");
1360 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1361 next = XtCreateManagedWidget ("next", commandWidgetClass,
1363 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1364 XtSetArg (arg[0], XtNlabel, ">> (N)");
1365 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1366 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1368 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1369 XtSetArg (arg[0], XtNlabel, ">| (l)");
1370 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1371 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1373 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1375 XtSetArg (arg[0], XtNleft, XawChainLeft);
1376 XtSetArg (arg[1], XtNright, XawChainLeft);
1377 XtSetArg (arg[2], XtNtop, XawChainTop);
1378 XtSetArg (arg[3], XtNbottom, XawChainTop);
1380 for (i = 0; i < 8; i++)
1386 sprintf (str, "%XX", i);
1387 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1388 XtSetArg (arg[n], XtNlabel, str), n++;
1389 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1391 XtSetArg (arg[n], XtNfromVert, w), n++;
1392 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1393 index_label[i] = head;
1394 for (j = 0; j < 16; j++)
1400 XtSetArg (arg[n], XtNfromVert, w), n++;
1402 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1404 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1405 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1406 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1407 glyph_area, arg, n);
1408 XtAddCallbackWithCast (int, glyph[k], RenderProc, k);
1412 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1413 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1414 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1415 XtSetArg (arg[6], XtNfromHoriz, w);
1416 XtSetArg (arg[7], XtNborderWidth, 0);
1418 for (j = 0; j < 16; j++)
1422 sprintf (str, "X%X", j);
1423 XtSetArg (arg[8], XtNlabel, str);
1424 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1425 XtSetArg (arg[6], XtNfromHoriz, w);
1428 XtSetArg (arg[0], XtNleft, XawChainLeft);
1429 XtSetArg (arg[1], XtNright, XawChainLeft);
1430 XtSetArg (arg[2], XtNtop, XawChainTop);
1431 XtSetArg (arg[3], XtNbottom, XawChainTop);
1432 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1433 XtSetArg (arg[5], XtNborderWidth, 0);
1434 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1435 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1436 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1437 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1438 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1439 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1440 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1441 alt_subst = XtCreateManagedWidget ("AltSubst", toggleWidgetClass, w, arg, 0);
1442 XtAddCallback (alt_subst, XtNcallback, AltSubstProc, NULL);
1444 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1445 XtSetArg (arg[5], XtNborderWidth, 0);
1446 XtSetArg (arg[6], XtNfromVert, w);
1447 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1449 XtSetArg (arg[0], XtNborderWidth, 0);
1450 XtSetArg (arg[1], XtNlabel, "raw: ");
1451 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1453 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1454 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1459 OTF_get_table (otf, "GSUB");
1460 OTF_get_table (otf, "GPOS");
1461 w = create_otf_script_widgets (w);
1464 gsub.label = "GSUB";
1465 gsub.gsub_gpos = otf->gsub;
1466 w = create_otf_widgets (w, &gsub);
1470 gpos.label = "GPOS";
1471 gpos.gsub_gpos = otf->gpos;
1472 w = create_otf_widgets (w, &gpos);
1476 XtSetArg (arg[6], XtNfromVert, w);
1477 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1478 XtSetArg (arg[0], XtNborderWidth, 0);
1479 XtSetArg (arg[1], XtNlabel, "seq: ");
1480 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1482 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1483 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1485 XtInstallAllAccelerators (shell, shell);
1489 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1491 XTextProperty text_prop;
1492 char *pname = "otfview";
1493 char *fname = basename (filename);
1494 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1496 sprintf (name, "%s - %s", pname, fname);
1497 text_prop.value = (unsigned char *) name;
1498 text_prop.encoding = XA_STRING;
1499 text_prop.format = 8;
1500 text_prop.nitems = strlen (name);
1501 XSetWMName (display, XtWindow (shell), &text_prop);
1504 /* Format MSG by FMT and print the result to the stderr, and exit. */
1506 #define FATAL_ERROR(fmt, arg) \
1508 fprintf (stderr, fmt, arg); \
1513 x_error_handler (Display *display, XErrorEvent *error)
1519 help (char **argv, int err)
1521 FILE *fp = err ? stderr : stdout;
1523 fprintf (fp, "Usage: %s [ X-OPTION ... ] OTF-FILE [INDEX]\n",
1524 basename (argv[0]));
1525 fprintf (fp, " Environment variable PIXEL_SIZE specifies the pixel size.\n");
1526 fprintf (fp, " The default pixel size is %d, but is reduced\n",
1527 DEFAULT_PIXEL_SIZE);
1528 fprintf (fp, " if your screen is not that wide.\n");
1533 main (int argc, char **argv)
1535 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1539 OTF_GlyphString gstring;
1544 int fixed_pixel_size = 0;
1547 pixel_size = DEFAULT_PIXEL_SIZE;
1549 char *str = getenv ("PIXEL_SIZE");
1551 if (str && (i = atoi (str)) > 0)
1554 fixed_pixel_size = 1;
1558 gstring.size = gstring.used = 256;
1559 g = calloc (256, sizeof (OTF_Glyph));
1562 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1563 shellWidgetClass, arg, 0);
1564 display = XtDisplay (shell);
1565 /*XSynchronize (display, True);*/
1566 XSetErrorHandler (x_error_handler);
1567 display_width = DisplayWidth (display,
1568 XScreenNumberOfScreen (XtScreen (shell)));
1569 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1571 font = XLoadQueryFont (display, "fixed");
1575 if (!strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1580 fontindex = atoi (argv[2]);
1582 FATAL_ERROR ("Invalid font index: %d\n", fontindex);
1585 if ((err = FT_Init_FreeType (&library)))
1586 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1587 err = FT_New_Face (library, filename, fontindex, &face);
1588 if (err == FT_Err_Unknown_File_Format)
1589 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1591 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error (invalid face index?)");
1592 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1593 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1595 if (strstr (filename, ".ttf")
1596 || strstr (filename, ".TTF")
1597 || strstr (filename, ".otf")
1598 || strstr (filename, ".OTF"))
1600 otf = OTF_open_ft_face (face);
1603 if (OTF_get_table (otf, "head") < 0
1604 || OTF_get_table (otf, "cmap") < 0
1605 || (OTF_check_table (otf, "GSUB") < 0
1606 && OTF_check_table (otf, "GPOS") < 0))
1613 for (i = 0; i < otf->cmap->numTables; i++)
1614 if (otf->cmap->EncodingRecord[i].subtable.format == 14)
1616 sub14 = otf->cmap->EncodingRecord[i].subtable.f.f14;
1625 filename = basename (filename);
1626 sprintf (title, "%s family:%s style:%s",
1627 filename, face->family_name, face->style_name);
1628 XtSetArg (arg[0], XtNtitle, title);
1629 XtSetValues (shell, arg, 1);
1632 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1633 * pixel_size / face->units_per_EM);
1634 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1636 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1637 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1638 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1639 * pixel_size / face->units_per_EM);
1641 if (glyph_width < FONT_WIDTH * 4)
1642 glyph_width = FONT_WIDTH * 4;
1644 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1645 * pixel_size / face->units_per_EM);
1647 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1648 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1649 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1650 glyph_width, glyph_height, 1);
1653 unsigned long valuemask = GCFunction | GCLineWidth;
1656 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1657 XSetFont (display, gc, font->fid);
1658 values.function = GXset;
1659 values.line_width = 1;
1660 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1661 XSetFont (display, gc_set, font->fid);
1662 values.function = GXor;
1663 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1664 values.function = GXcopyInverted;
1665 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1668 XFillRectangle (display, none_pixmap, gc, 0, 0,
1669 glyph_width, glyph_height);
1670 XDrawString (display, none_pixmap, gc_inv,
1671 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1672 glyph_height / 2, "none", 4);
1674 render_width = (glyph_width + 4) * 15 + 1;
1675 render_height = glyph_height + 2;
1677 charmap_rec[0].platform_id = -1;
1678 charmap_rec[0].encoding_id = -1;
1679 strcpy (charmap_rec[0].name, "no charmap");
1681 for (i = 0; i < face->num_charmaps; i++)
1683 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1684 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1685 sprintf (charmap_rec[i + 1].name, "%d-%d",
1686 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1687 if (face->charmaps[i]->platform_id == 0
1688 || (face->charmaps[i]->platform_id == 3
1689 && face->charmaps[i]->encoding_id == 1))
1690 strcat (charmap_rec[i + 1].name, " (unicode)");
1691 else if (face->charmaps[i]->platform_id == 1
1692 && face->charmaps[i]->encoding_id == 0)
1693 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1696 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1697 render_width, render_height, 1);
1698 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1699 render_width, render_height, 1);
1701 memset (bitmap, 0, sizeof (bitmap));
1705 update_glyph_area ();
1706 update_render_area ();
1708 XtAppAddActions (context, actions, XtNumber (actions));
1709 XtRealizeWidget (shell);
1710 XtAppMainLoop (context);
1715 #else /* not HAVE_X11_XAW_COMMAND_H */
1718 main (int argc, char **argv)
1721 "Building of this program failed (lack of some header files)\n");