1 /* otfview.c -- View glyphs of OpenType fonts.
3 Copyright (C) 2003, 2004
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H15PRO167
7 This file is part of libotf.
9 Libotf is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 Libotf is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library, in a file named COPYING; if not,
21 write to the Free Software Foundation, Inc., 59 Temple Place, Suite
22 330, Boston, MA 02111-1307, USA. */
31 #ifdef HAVE_X11_XAW_COMMAND_H
33 #include <X11/Xatom.h>
34 #include <X11/Intrinsic.h>
35 #include <X11/StringDefs.h>
36 #include <X11/Shell.h>
37 #include <X11/Xaw/Command.h>
38 #include <X11/Xaw/Toggle.h>
39 #include <X11/Xaw/Box.h>
40 #include <X11/Xaw/Form.h>
41 #include <X11/Xaw/Viewport.h>
44 #include FT_FREETYPE_H
48 #define DEFAULT_PIXEL_SIZE 30
51 #define DEFAULT_FONT_NAME "6x13"
53 #define FONT_HEIGHT (font->ascent + font->descent)
54 #define FONT_ASCENT (font->ascent)
55 #define FONT_DESCENT (font->descent)
56 #define FONT_WIDTH (font->max_bounds.width)
60 +--- frame (form) -------------------------+
61 | +--- command_area (box) ---------------+ |
62 | | quit dump charmap ... | |
63 | +--------------------------------------+ |
64 | +---- navi_area (box) -----------------+ |
65 | | FIRST PREV prev range next NEXT LAST | |
66 | +--------------------------------------+ |
67 | +--- glyph_area (form) ----------------+ |
68 | | idxh[0] glyph[0] ... glyph[15] | |
70 | | idxh[7] glyph[112] ... glyph[127]| |
71 | | idxl[0] ... idxl[15] | |
72 | +--------------------------------------+ |
73 | +--- render_area (form) ---------------+ |
74 | | clear del bidi | |
75 | | +--- raw (box) --------------------+ | |
76 | | | raw_label raw_image | | |
77 | | +----------------------------------+ | |
78 | | GSUB all none features... | |
79 | | GPOS all none features... | |
80 | | +--- seq (box) --------------------+ | |
81 | | | seq_label seq_image | | |
82 | | +----------------------------------+ | |
83 | +--------------------------------------+ |
84 +------------------------------------------+ */
86 Widget command_area, quit, dump, *charmap;
87 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
88 Widget glyph_area, glyph[128], index_label[8];
89 Widget render_area, clear, del, bidi, raw, seq;
90 Widget raw_label, raw_image, seq_label, seq_image;
91 unsigned long foreground, background;
93 #define MAX_FEATURE_COUNT 16
98 OTF_GSUB_GPOS *gsub_gpos;
104 } features[MAX_FEATURE_COUNT];
107 FeatureRec gsub, gpos;
114 GC gc, gc_set, gc_or, gc_inv;
118 unsigned width, height;
123 BitmapRec bitmap[0x10000];
125 int render_width, render_height;
126 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
140 unsigned glyph_width, glyph_height;
141 int glyph_x, glyph_y;
154 create_pixmap (int index)
156 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
162 bitmap[index].pixmap = none_pixmap;
165 ximage.height = face->glyph->bitmap.rows;
166 ximage.width = face->glyph->bitmap.width;
168 ximage.bits_per_pixel = 1;
170 ximage.format = XYPixmap;
171 ximage.data = (char *) face->glyph->bitmap.buffer;
172 ximage.byte_order = MSBFirst;
173 ximage.bitmap_unit = 8;
174 ximage.bitmap_bit_order = MSBFirst;
175 ximage.bitmap_pad = 8;
176 ximage.bytes_per_line = face->glyph->bitmap.pitch;
177 XInitImage (&ximage);
178 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
179 glyph_width, glyph_height, 1);
180 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
181 XPutImage (display, pixmap, gc, &ximage, 0, 0,
182 glyph_x + face->glyph->bitmap_left,
183 glyph_y - face->glyph->bitmap_top,
184 ximage.width, ximage.height);
185 bitmap[index].pixmap = pixmap;
186 bitmap[index].width = ximage.width;
187 bitmap[index].height = ximage.height;
188 bitmap[index].x = face->glyph->bitmap_left;
189 bitmap[index].y = - face->glyph->bitmap_top;
190 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
201 for (i = 0; i < 128; i++)
203 int index = glyph_index + i;
205 if (charmap_index >= 0)
206 index = FT_Get_Char_Index (face, (FT_ULong) index);
207 if (! bitmap[index].pixmap)
208 create_pixmap (index);
209 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
210 XtSetValues (glyph[i], arg, 1);
213 msb = (glyph_index >> 7) % 2 ? 8 : 0;
214 for (i = 0; i < 8; i++)
218 sprintf (str, "%XX", i | msb );
219 XtSetArg (arg[0], XtNheight, glyph_height + 5);
220 XtSetArg (arg[1], XtNlabel, str);
221 XtSetValues (index_label[i], arg, 2);
224 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
225 XtSetArg (arg[0], XtNlabel, buf);
226 XtSetValues (range, arg, 1);
230 get_features (OTF_FeatureList *list, FeatureRec *rec)
235 if (! rec->features[0].on)
237 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
239 if (rec->features[i].on)
244 if (i == rec->langsys->FeatureCount)
250 str = malloc (n * 5);
251 for (i = 0, p = str; i < n; i++, p += 5)
253 OTF_tag_name (rec->features[i].tag, p);
261 #define DEVICE_DELTA(table, size) \
262 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
263 ? (table).DeltaValue[(size) >= (table).StartSize] \
267 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
268 OTF_Glyph *g, int *x, int *y)
270 if (anchor->AnchorFormat == 2)
273 int ap = anchor->f.f1.AnchorPoint;
275 FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
276 outline = &ft_face->glyph->outline;
277 if (ap < outline->n_points)
279 *x = outline->points[ap].x;
280 *y = outline->points[ap].y;
283 else if (anchor->AnchorFormat == 3)
285 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
286 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
294 OTF_GlyphString gstring;
295 OTF_Glyph *g, *prev, *base, *mark;
297 int len = glyph_rec.n_glyphs;
299 int unitsPerEm = face->units_per_EM;
301 gstring.size = gstring.used = len;
302 gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
303 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
304 for (i = 0; i < len; i++)
305 gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
307 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
308 XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
313 OTF_drive_gdef (otf, &gstring);
316 str = get_features (&otf->gsub->FeatureList, &gsub);
319 OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
325 str = get_features (&otf->gpos->FeatureList, &gpos);
328 OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
339 for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
340 prev < g; prev++, g--)
341 temp = *prev, *prev = *g, *g = temp;
342 for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
343 if (g->GlyphClass == 3)
347 while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
349 for (g0 = g; prev < g0; prev++, g0--)
350 temp = *prev, *prev = *g, *g = temp;
356 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
357 i < gstring.used; i++, prev = g++)
359 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
360 int xoff = 0, yoff = 0;
362 int advance = bmp->advance;
366 create_pixmap (gstring.glyphs[i].glyph_id);
370 switch (g->positioning_type)
377 int format = g->f.f1.format;
379 if (format & OTF_XPlacement)
380 xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
381 if (format & OTF_XPlaDevice)
382 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
383 if (format & OTF_YPlacement)
384 yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
385 if (format & OTF_YPlaDevice)
386 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
387 if (format & OTF_XAdvance)
388 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
389 if (format & OTF_XAdvDevice)
390 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice, pixel_size);
395 /* Not yet supported. */
401 prev_width = base_width;
402 goto label_adjust_anchor;
403 default: /* i.e. case 6 */
410 int base_x, base_y, mark_x, mark_y;
412 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
413 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
414 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
415 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
417 if (g->f.f4.base_anchor->AnchorFormat != 1)
418 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
419 if (g->f.f4.mark_anchor->AnchorFormat != 1)
420 adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
421 xoff = (base_x - prev_width) - mark_x;
422 yoff = base_y - mark_y;
426 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
427 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
428 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
431 if (g->GlyphClass == OTF_GlyphClass0)
432 base = mark = g, base_width = advance;
433 else if (g->GlyphClass == OTF_GlyphClassMark)
436 base = g, base_width = advance;
438 free (gstring.glyphs);
440 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
441 XtSetValues (seq_image, arg, 1);
446 update_render_area ()
452 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
453 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
455 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
458 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
459 0, 0, glyph_width, glyph_height,
460 (glyph_width + 4) * i + 1, 1);
461 XDrawRectangle (display, raw_pixmap, gc_set,
462 (glyph_width + 4) * i, 0,
463 glyph_width + 1, glyph_height + 1);
464 XDrawLine (display, raw_pixmap, gc_set,
465 (glyph_width + 4) * i + 1 + glyph_x, 1,
466 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
467 XDrawLine (display, raw_pixmap, gc_set,
468 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
469 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
472 sprintf (buf, "%04X", glyph_rec.codes[i]);
473 XDrawString (display, raw_pixmap, gc_inv,
474 (glyph_width + 1) * i + 1
475 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
476 glyph_height + 2 + FONT_HEIGHT, buf, 4);
478 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
479 XtSetValues (raw_image, arg, 1);
484 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
486 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
490 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
492 int g_width, g_height, g_x, g_y, pix_width, pix_height;
493 int margin = 20 * 300 / 25.4;
494 int a4_width = 210 * 300 / 25.4 - margin * 2;
495 int a4_height = 297 * 300 / 25.4 - margin * 2;
498 XImage ximage, *image;
503 FT_Set_Pixel_Sizes (face, 0, size);
504 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
505 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
506 pix_width = (g_width + 1) * 16 + margin + 1;
507 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
508 while (pix_width > a4_width || pix_height > a4_height)
511 FT_Set_Pixel_Sizes (face, 0, size);
512 g_width = ((face->bbox.xMax - face->bbox.xMin)
513 * size / face->units_per_EM);
514 g_height = ((face->bbox.yMax - face->bbox.yMin)
515 * size / face->units_per_EM);
516 pix_width = (g_width + 1) * 16 + margin + 1;
517 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
520 g_x = - (face->bbox.xMin * size / face->units_per_EM);
521 g_y = face->bbox.yMax * size / face->units_per_EM;
522 for (i = 0; i < 0xFF; i++)
526 if (charmap_index >= 0)
527 idx = FT_Get_Char_Index (face, (FT_ULong) i);
530 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
532 if (g_x < - face->glyph->bitmap_left)
533 g_x = - face->glyph->bitmap_left;
534 if (g_y < face->glyph->bitmap_top)
535 g_y = face->glyph->bitmap_top;
537 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
539 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
541 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
543 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
546 pix_width = (g_width + 1) * 16 + margin + 1;
547 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
548 pixmap = XCreatePixmap (display,
549 RootWindow (display, DefaultScreen (display)),
550 pix_width, pix_height, 1);
551 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
553 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
554 XDrawLine (display, pixmap, gc_set, x, margin,
555 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
556 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
557 XDrawLine (display, pixmap, gc_set, margin, y,
558 margin + (g_width + 1) * 16, y);
559 for (i = 0; i < 256; i++)
564 if (charmap_index >= 0)
565 idx = FT_Get_Char_Index (face, (FT_ULong) i);
568 x = margin + (g_width + 1) * (i % 16);
569 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
570 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
572 ximage.height = face->glyph->bitmap.rows;
573 ximage.width = face->glyph->bitmap.width;
575 ximage.bits_per_pixel = 1;
577 ximage.format = XYPixmap;
578 ximage.data = (char *) face->glyph->bitmap.buffer;
579 ximage.byte_order = MSBFirst;
580 ximage.bitmap_unit = 8;
581 ximage.bitmap_bit_order = MSBFirst;
582 ximage.bitmap_pad = 8;
583 ximage.bytes_per_line = face->glyph->bitmap.pitch;
584 XInitImage (&ximage);
585 XPutImage (display, pixmap, gc, &ximage, 0, 0,
586 x + g_x + face->glyph->bitmap_left,
587 y + g_y - face->glyph->bitmap_top,
588 ximage.width, ximage.height);
590 sprintf (str, "0x%02X", i);
591 XDrawString (display, pixmap, gc_inv,
592 x + (g_width - XTextWidth (font, str, 4))/ 2,
593 y + g_height + FONT_ASCENT, str, 4);
596 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
597 AllPlanes, XYPixmap);
600 char *name = alloca (strlen (filename) + 5);
603 sprintf (name, "%s.pbm", filename);
604 printf ("Writing %s ...", name);
605 fp = fopen (name, "w");
606 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
607 bytes_per_line = (image->width + 7) / 8;
609 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
610 fwrite (data, 1, bytes_per_line, fp);
614 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
619 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
621 int old_glyph_index = glyph_index;
623 if ((int) client_data == -3 && glyph_index > 0)
625 else if ((int) client_data == -2 && glyph_index > 0)
626 glyph_index = (glyph_index - 1) & 0xF000;
627 else if ((int) client_data == -1 && glyph_index > 0)
629 else if ((int) client_data == 1 && glyph_index < 0xFF80)
631 else if ((int) client_data == 2 && glyph_index < 0xF000)
632 glyph_index = (glyph_index + 0x1000) & 0xF000;
633 else if ((int) client_data == 3 && glyph_index < 0xF000)
634 glyph_index = 0xFF80;
635 if (glyph_index != old_glyph_index)
636 update_glyph_area ();
640 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
642 if (charmap_index == (int) client_data)
644 charmap_index = (int) client_data;
645 if (charmap_index >= 0)
646 FT_Set_Charmap (face, face->charmaps[charmap_index]);
647 update_glyph_area ();
651 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
653 if ((int) client_data < 0)
655 if (glyph_rec.n_glyphs > 0)
657 if ((int) client_data == -2)
658 glyph_rec.n_glyphs--;
660 glyph_rec.n_glyphs = 0;
661 update_render_area ();
664 else if (glyph_rec.n_glyphs < 64)
666 int index = glyph_index + (int) client_data;
668 if (charmap_index >= 0)
669 index = FT_Get_Char_Index (face, (FT_ULong) index);
670 if (bitmap[index].pixmap)
672 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
673 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
674 update_render_area ();
680 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
684 reversed = ! reversed;
686 XtSetArg (arg[0], XtNlabel, "L<-R");
688 XtSetArg (arg[0], XtNlabel, "L->R");
689 XtSetValues (w, arg, 1);
694 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
696 FeatureRec *rec = (FeatureRec *) client_data;
703 XtSetArg (arg[0], XtNlabel, &label);
704 XtGetValues (w, arg, 1);
705 if (! strcmp (label, "all"))
707 else if (! strcmp (label, "none"))
711 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
712 if (rec->features[idx].w == w)
714 if (idx == rec->langsys->FeatureCount)
721 for (i = j = 0; j < rec->langsys->FeatureCount; j++)
723 int index = rec->langsys->FeatureIndex[j];
726 = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
727 rec->features[j].on = on;
732 OTF_Tag tag = rec->features[idx].tag;
735 if (rec->features[i].on)
738 j < rec->langsys->FeatureCount && rec->features[j].on; j++)
739 rec->features[j - 1].tag = rec->features[j].tag;
740 rec->features[j - 1].tag = tag;
741 rec->features[j - 1].on = 0;
745 for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
746 rec->features[i].tag = rec->features[i - 1].tag;
747 rec->features[i].tag = tag;
748 rec->features[i].on = 1;
756 if (rec->features[i].on)
758 XtSetArg (arg[0], XtNborderWidth, 3);
759 XtSetArg (arg[1], XtNinternalHeight, 2);
760 XtSetArg (arg[2], XtNinternalWidth, 2);
764 XtSetArg (arg[0], XtNborderWidth, 1);
765 XtSetArg (arg[1], XtNinternalHeight, 4);
766 XtSetArg (arg[2], XtNinternalWidth, 4);
768 OTF_tag_name (rec->features[i].tag, str);
769 XtSetArg (arg[3], XtNlabel, str);
770 XtSetValues (rec->features[i].w, arg, 4);
776 setup_feature_rec (FeatureRec *rec)
782 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
783 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
785 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
793 XtSetArg (arg[0], XtNborderWidth, 1);
794 XtSetArg (arg[1], XtNinternalHeight, 4);
795 XtSetArg (arg[2], XtNinternalWidth, 4);
796 XtSetArg (arg[3], XtNborderColor, foreground);
797 XtSetArg (arg[4], XtNsensitive, True);
798 for (i = 0; i < rec->langsys->FeatureCount && i < MAX_FEATURE_COUNT; i++)
800 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
801 int index = rec->langsys->FeatureIndex[i];
804 rec->features[i].tag = feature[index].FeatureTag;
805 rec->features[i].on = 0;
806 OTF_tag_name (rec->features[i].tag, label);
807 XtSetArg (arg[5], XtNlabel, label);
808 XtSetValues (rec->features[i].w, arg, 6);
811 XtSetArg (arg[0], XtNborderColor, background);
812 XtSetArg (arg[1], XtNsensitive, False);
813 XtSetArg (arg[2], XtNlabel, " ");
814 for (; i < MAX_FEATURE_COUNT; i++)
815 XtSetValues (rec->features[i].w, arg, 3);
819 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
821 if (script_tag == (OTF_Tag) client_data)
823 script_tag = (OTF_Tag) client_data;
824 setup_feature_rec (&gsub);
825 setup_feature_rec (&gpos);
830 create_otf_script_widgets (Widget prev)
838 XtSetArg (arg[0], XtNborderWidth, 0);
839 XtSetArg (arg[1], XtNleft, XawChainLeft);
840 XtSetArg (arg[2], XtNright, XawChainLeft);
841 XtSetArg (arg[3], XtNtop, XawChainTop);
842 XtSetArg (arg[4], XtNbottom, XawChainTop);
843 XtSetArg (arg[5], XtNfromVert, prev);
844 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
845 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
846 XtCreateManagedWidget ("script", labelWidgetClass, prev, arg, 1);
850 n = otf->gsub->ScriptList.ScriptCount;
852 n += otf->gpos->ScriptList.ScriptCount;
853 scripts = alloca (sizeof (OTF_Tag) * n);
856 for (; i < otf->gsub->ScriptList.ScriptCount; i++)
857 scripts[i] = otf->gsub->ScriptList.Script[i].ScriptTag;
860 for (; i < otf->gpos->ScriptList.ScriptCount; i++)
862 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
865 for (j = 0; j < i; j++)
866 if (tag == scripts[j])
875 script_tag = scripts[0];
876 OTF_tag_name (scripts[0], script_name);
879 XtSetArg (arg[0], XtNforeground, background);
880 XtSetArg (arg[1], XtNbackground, foreground);
881 XtCreateManagedWidget (script_name, labelWidgetClass, prev, arg, 2);
887 XtSetArg (arg[0], XtNstate, True);
888 w = XtCreateManagedWidget (script_name, toggleWidgetClass, prev, arg, 1);
889 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[0]);
890 XtSetArg (arg[0], XtNradioGroup, w);
891 for (i = 1; i < n; i++)
893 OTF_tag_name (scripts[i], name);
894 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
895 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[i]);
903 create_otf_widgets (Widget prev, FeatureRec *rec)
909 XtSetArg (arg[0], XtNborderWidth, 0);
910 XtSetArg (arg[1], XtNleft, XawChainLeft);
911 XtSetArg (arg[2], XtNright, XawChainLeft);
912 XtSetArg (arg[3], XtNtop, XawChainTop);
913 XtSetArg (arg[4], XtNbottom, XawChainTop);
914 XtSetArg (arg[5], XtNfromVert, prev);
915 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
916 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
918 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
919 XtSetArg (arg[0], XtNborderWidth, 1);
920 XtSetArg (arg[1], XtNinternalHeight, 4);
921 XtSetArg (arg[2], XtNinternalWidth, 4);
922 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
923 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
924 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
925 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
927 for (i = 0; i < MAX_FEATURE_COUNT; i++)
929 w = XtCreateManagedWidget ("", commandWidgetClass, prev, arg, 0);
930 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
931 rec->features[i].w = w;
934 setup_feature_rec (rec);
941 String quit_action = "<KeyPress>q: set() notify() unset()";
942 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
943 <KeyPress>Home: set() notify() unset()";
944 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
945 <KeyPress>Up: set() notify() unset()";
946 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
947 <KeyPress>Left: set() notify() unset()";
948 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
949 <KeyPress>Right: set() notify() unset()";
950 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
951 <KeyPress>Down: set() notify() unset()";
952 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
953 <KeyPress>End: set() notify() unset()";
957 String trans = "<Expose>: Expose()";
959 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
960 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
962 XtSetArg (arg[0], XtNleft, XawChainLeft);
963 XtSetArg (arg[1], XtNright, XawChainLeft);
964 XtSetArg (arg[2], XtNtop, XawChainTop);
965 XtSetArg (arg[3], XtNbottom, XawChainTop);
966 XtSetArg (arg[4], XtNborderWidth, 0);
967 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
968 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
970 XtSetArg (arg[6], XtNfromVert, command_area);
971 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
973 XtSetArg (arg[4], XtNborderWidth, 0);
974 XtSetArg (arg[5], XtNfromVert, navi_area);
975 XtSetArg (arg[6], XtNdefaultDistance, 0);
976 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
978 XtSetArg (arg[5], XtNfromVert, glyph_area);
979 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
982 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
983 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
984 command_area, arg, 1);
985 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
987 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
988 command_area, arg, 1);
989 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
991 XtSetArg (arg[0], XtNborderWidth, 0);
992 XtSetArg (arg[1], XtNwidth, 10);
993 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
995 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
996 XtSetArg (arg[0], XtNstate, True);
997 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
998 command_area, arg, 1);
999 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1000 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1001 for (i = 0; i < face->num_charmaps; i++)
1003 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1005 command_area, arg, 1);
1006 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
1009 XtSetArg (arg[0], XtNlabel, " |< (f)");
1010 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1011 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1013 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1014 XtSetArg (arg[0], XtNlabel, "<< (P)");
1015 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1016 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1018 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1019 XtSetArg (arg[0], XtNlabel, "< (p)");
1020 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1021 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1023 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1024 XtSetArg (arg[0], XtNlabel, " 0000 ");
1025 range = XtCreateManagedWidget ("range", labelWidgetClass,
1027 XtSetArg (arg[0], XtNforeground, &foreground);
1028 XtSetArg (arg[1], XtNbackground, &background);
1029 XtGetValues (range, arg, 2);
1031 XtSetArg (arg[0], XtNlabel, "> (n)");
1032 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1033 next = XtCreateManagedWidget ("next", commandWidgetClass,
1035 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1036 XtSetArg (arg[0], XtNlabel, ">> (N)");
1037 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1038 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1040 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1041 XtSetArg (arg[0], XtNlabel, ">| (l)");
1042 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1043 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1045 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1047 XtSetArg (arg[0], XtNleft, XawChainLeft);
1048 XtSetArg (arg[1], XtNright, XawChainLeft);
1049 XtSetArg (arg[2], XtNtop, XawChainTop);
1050 XtSetArg (arg[3], XtNbottom, XawChainTop);
1052 for (i = 0; i < 8; i++)
1058 sprintf (str, "%XX", i);
1059 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1060 XtSetArg (arg[n], XtNlabel, str), n++;
1061 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1063 XtSetArg (arg[n], XtNfromVert, w), n++;
1064 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1065 index_label[i] = head;
1066 for (j = 0; j < 16; j++)
1072 XtSetArg (arg[n], XtNfromVert, w), n++;
1074 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1076 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1077 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1078 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1079 glyph_area, arg, n);
1080 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1084 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1085 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1086 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1087 XtSetArg (arg[6], XtNfromHoriz, w);
1088 XtSetArg (arg[7], XtNborderWidth, 0);
1090 for (j = 0; j < 16; j++)
1094 sprintf (str, "X%X", j);
1095 XtSetArg (arg[8], XtNlabel, str);
1096 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1097 XtSetArg (arg[6], XtNfromHoriz, w);
1100 XtSetArg (arg[0], XtNleft, XawChainLeft);
1101 XtSetArg (arg[1], XtNright, XawChainLeft);
1102 XtSetArg (arg[2], XtNtop, XawChainTop);
1103 XtSetArg (arg[3], XtNbottom, XawChainTop);
1104 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1105 XtSetArg (arg[5], XtNborderWidth, 0);
1106 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1107 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1108 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1109 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1110 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1111 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1112 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1114 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1115 XtSetArg (arg[5], XtNborderWidth, 0);
1116 XtSetArg (arg[6], XtNfromVert, w);
1117 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1119 XtSetArg (arg[0], XtNborderWidth, 0);
1120 XtSetArg (arg[1], XtNlabel, "raw: ");
1121 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1123 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1124 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1129 OTF_get_table (otf, "GSUB");
1130 OTF_get_table (otf, "GPOS");
1131 w = create_otf_script_widgets (w);
1134 gsub.label = "GSUB";
1135 gsub.gsub_gpos = otf->gsub;
1136 w = create_otf_widgets (w, &gsub);
1140 gpos.label = "GPOS";
1141 gpos.gsub_gpos = otf->gpos;
1142 w = create_otf_widgets (w, &gpos);
1146 XtSetArg (arg[6], XtNfromVert, w);
1147 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1148 XtSetArg (arg[0], XtNborderWidth, 0);
1149 XtSetArg (arg[1], XtNlabel, "seq: ");
1150 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1152 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1153 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1155 XtInstallAllAccelerators (shell, shell);
1159 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1161 XTextProperty text_prop;
1162 char *pname = "otfview";
1163 char *fname = basename (filename);
1164 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1166 sprintf (name, "%s - %s", pname, fname);
1167 text_prop.value = (unsigned char *) name;
1168 text_prop.encoding = XA_STRING;
1169 text_prop.format = 8;
1170 text_prop.nitems = strlen (name);
1171 XSetWMName (display, XtWindow (shell), &text_prop);
1174 /* Format MSG by FMT and print the result to the stderr, and exit. */
1176 #define FATAL_ERROR(fmt, arg) \
1178 fprintf (stderr, fmt, arg); \
1183 x_error_handler (Display *display, XErrorEvent *error)
1190 main (int argc, char **argv)
1192 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1196 OTF_GlyphString gstring;
1201 int fixed_pixel_size = 0;
1204 pixel_size = DEFAULT_PIXEL_SIZE;
1206 char *str = getenv ("PIXEL_SIZE");
1208 if (str && (i = atoi (str)) > 0)
1211 fixed_pixel_size = 1;
1215 gstring.size = gstring.used = 256;
1216 g = calloc (256, sizeof (OTF_Glyph));
1219 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1220 shellWidgetClass, arg, 0);
1221 display = XtDisplay (shell);
1222 /*XSynchronize (display, True);*/
1223 XSetErrorHandler (x_error_handler);
1224 display_width = DisplayWidth (display,
1225 XScreenNumberOfScreen (XtScreen (shell)));
1226 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1228 font = XLoadQueryFont (display, "fixed");
1230 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1232 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
1233 basename (argv[0]));
1235 " Pixel size is decided by the environment variable PIXEL_SIZE ((default %d).\n", DEFAULT_PIXEL_SIZE);
1239 if (strstr (filename, ".ttf")
1240 || strstr (filename, ".TTF")
1241 || strstr (filename, ".otf")
1242 || strstr (filename, ".OTF"))
1244 otf = OTF_open (filename);
1246 || OTF_get_table (otf, "head") < 0
1247 || OTF_get_table (otf, "cmap") < 0
1248 || (OTF_check_table (otf, "GSUB") < 0
1249 && OTF_check_table (otf, "GPOS") < 0))
1253 if ((err = FT_Init_FreeType (&library)))
1254 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1255 err = FT_New_Face (library, filename, 0, &face);
1256 if (err == FT_Err_Unknown_File_Format)
1257 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1259 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
1260 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1261 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1267 filename = basename (filename);
1268 sprintf (title, "%s family:%s style:%s",
1269 filename, face->family_name, face->style_name);
1270 XtSetArg (arg[0], XtNtitle, title);
1271 XtSetValues (shell, arg, 1);
1274 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1275 * pixel_size / face->units_per_EM);
1276 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1278 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1279 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1280 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1281 * pixel_size / face->units_per_EM);
1283 if (glyph_width < FONT_WIDTH * 4)
1284 glyph_width = FONT_WIDTH * 4;
1286 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1287 * pixel_size / face->units_per_EM);
1289 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1290 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1291 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1292 glyph_width, glyph_height, 1);
1295 unsigned long valuemask = GCFunction | GCLineWidth;
1298 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1299 values.function = GXset;
1300 values.line_width = 1;
1301 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1302 values.function = GXor;
1303 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1304 values.function = GXcopyInverted;
1305 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1308 XFillRectangle (display, none_pixmap, gc, 0, 0,
1309 glyph_width, glyph_height);
1310 XDrawString (display, none_pixmap, gc_inv,
1311 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1312 glyph_height / 2, "none", 4);
1314 render_width = (glyph_width + 4) * 15 + 1;
1315 render_height = glyph_height + 2;
1317 charmap_rec[0].platform_id = -1;
1318 charmap_rec[0].encoding_id = -1;
1319 strcpy (charmap_rec[0].name, "no charmap");
1321 for (i = 0; i < face->num_charmaps; i++)
1323 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1324 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1325 sprintf (charmap_rec[i + 1].name, "%d-%d",
1326 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1327 if (face->charmaps[i]->platform_id == 0
1328 || (face->charmaps[i]->platform_id == 3
1329 && face->charmaps[i]->encoding_id == 1))
1330 strcat (charmap_rec[i + 1].name, " (unicode)");
1331 else if (face->charmaps[i]->platform_id == 1
1332 && face->charmaps[i]->encoding_id == 0)
1333 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1336 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1337 render_width, render_height, 1);
1338 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1339 render_width, render_height, 1);
1341 memset (bitmap, 0, sizeof (bitmap));
1345 update_glyph_area ();
1346 update_render_area ();
1348 XtAppAddActions (context, actions, XtNumber (actions));
1349 XtRealizeWidget (shell);
1350 XtAppMainLoop (context);
1355 #else /* not HAVE_X11_XAW_COMMAND_H */
1358 main (int argc, char **argv)
1361 "Building of this program failed (lack of some header files)\n",