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. */
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 DEFAULT_PIXEL_SIZE 30
53 #define DEFAULT_FONT_NAME "6x13"
55 #define FONT_HEIGHT (font->ascent + font->descent)
56 #define FONT_ASCENT (font->ascent)
57 #define FONT_DESCENT (font->descent)
58 #define FONT_WIDTH (font->max_bounds.width)
62 +--- frame (form) -------------------------+
63 | +--- command_area (box) ---------------+ |
64 | | quit dump charmap ... | |
65 | +--------------------------------------+ |
66 | +---- navi_area (box) -----------------+ |
67 | | FIRST PREV prev range next NEXT LAST | |
68 | +--------------------------------------+ |
69 | +--- glyph_area (form) ----------------+ |
70 | | idxh[0] glyph[0] ... glyph[15] | |
72 | | idxh[7] glyph[112] ... glyph[127]| |
73 | | idxl[0] ... idxl[15] | |
74 | +--------------------------------------+ |
75 | +--- render_area (form) ---------------+ |
76 | | clear del bidi alt_subst | |
77 | | +--- raw (box) --------------------+ | |
78 | | | raw_label raw_image | | |
79 | | +----------------------------------+ | |
80 | | GSUB all none features... | |
81 | | GPOS all none features... | |
82 | | +--- seq (box) --------------------+ | |
83 | | | seq_label seq_image | | |
84 | | +----------------------------------+ | |
85 | +--------------------------------------+ |
86 +------------------------------------------+ */
88 Widget command_area, quit, dump, *charmap;
89 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
90 Widget glyph_area, glyph[128], index_label[8];
91 Widget render_area, clear, del, bidi, alt_subst, raw, seq;
92 Widget raw_label, raw_image, seq_label, seq_image;
93 unsigned long foreground, background;
105 OTF_GSUB_GPOS *gsub_gpos;
106 OTF_LangSys *langsys;
108 FeatureElement *features;
112 FeatureRec gsub, gpos;
119 GC gc, gc_set, gc_or, gc_inv;
123 unsigned width, height;
128 BitmapRec bitmap[0x10000];
130 int render_width, render_height;
131 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
145 int do_alternate_subst;
146 unsigned glyph_width, glyph_height;
147 int glyph_x, glyph_y;
160 create_pixmap (int index)
162 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
168 bitmap[index].pixmap = none_pixmap;
171 ximage.height = face->glyph->bitmap.rows;
172 ximage.width = face->glyph->bitmap.width;
174 ximage.bits_per_pixel = 1;
176 ximage.format = XYPixmap;
177 ximage.data = (char *) face->glyph->bitmap.buffer;
178 ximage.byte_order = MSBFirst;
179 ximage.bitmap_unit = 8;
180 ximage.bitmap_bit_order = MSBFirst;
181 ximage.bitmap_pad = 8;
182 ximage.bytes_per_line = face->glyph->bitmap.pitch;
183 XInitImage (&ximage);
184 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
185 glyph_width, glyph_height, 1);
186 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
187 XPutImage (display, pixmap, gc, &ximage, 0, 0,
188 glyph_x + face->glyph->bitmap_left,
189 glyph_y - face->glyph->bitmap_top,
190 ximage.width, ximage.height);
191 bitmap[index].pixmap = pixmap;
192 bitmap[index].width = ximage.width;
193 bitmap[index].height = ximage.height;
194 bitmap[index].x = face->glyph->bitmap_left;
195 bitmap[index].y = - face->glyph->bitmap_top;
196 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
207 for (i = 0; i < 128; i++)
209 int index = glyph_index + i;
211 if (charmap_index >= 0)
212 index = FT_Get_Char_Index (face, (FT_ULong) index);
213 if (! bitmap[index].pixmap)
214 create_pixmap (index);
215 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
216 XtSetValues (glyph[i], arg, 1);
219 msb = (glyph_index >> 7) % 2 ? 8 : 0;
220 for (i = 0; i < 8; i++)
224 sprintf (str, "%XX", i | msb );
225 XtSetArg (arg[0], XtNheight, glyph_height + 5);
226 XtSetArg (arg[1], XtNlabel, str);
227 XtSetValues (index_label[i], arg, 2);
230 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
231 XtSetArg (arg[0], XtNlabel, buf);
232 XtSetValues (range, arg, 1);
236 get_features (OTF_FeatureList *list, FeatureRec *rec)
241 if (! rec->features[0].on)
243 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
245 if (rec->features[i].on)
250 if (i == rec->langsys->FeatureCount)
256 str = malloc (n * 5);
257 for (i = 0, p = str; i < n; i++, p += 5)
259 OTF_tag_name (rec->features[i].tag, p);
267 #define DEVICE_DELTA(table, size) \
268 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
269 ? (table).DeltaValue[(size) >= (table).StartSize] \
273 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
274 OTF_Glyph *g, int *x, int *y)
276 if (anchor->AnchorFormat == 2)
279 int ap = anchor->f.f1.AnchorPoint;
281 FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
282 outline = &ft_face->glyph->outline;
283 if (ap < outline->n_points)
285 *x = outline->points[ap].x;
286 *y = outline->points[ap].y;
289 else if (anchor->AnchorFormat == 3)
291 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
292 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
300 OTF_GlyphString gstring;
301 OTF_Glyph *g, *prev, *base, *mark;
303 int len = glyph_rec.n_glyphs;
305 int unitsPerEm = face->units_per_EM;
307 gstring.size = gstring.used = len;
308 gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
309 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
310 for (i = 0; i < len; i++)
311 gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
313 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
314 XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
319 OTF_drive_gdef (otf, &gstring);
322 str = get_features (&otf->gsub->FeatureList, &gsub);
325 if (do_alternate_subst)
326 OTF_drive_gsub_alternate (otf, &gstring, NULL, NULL, str);
328 OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
334 str = get_features (&otf->gpos->FeatureList, &gpos);
337 OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
348 for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
349 prev < g; prev++, g--)
350 temp = *prev, *prev = *g, *g = temp;
351 for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
352 if (g->GlyphClass == 3)
356 while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
358 for (g0 = g; prev < g0; prev++, g0--)
359 temp = *prev, *prev = *g, *g = temp;
365 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
366 i < gstring.used; i++, prev = g++)
368 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
369 int xoff = 0, yoff = 0;
371 int advance = bmp->advance;
376 create_pixmap (gstring.glyphs[i].glyph_id);
379 advance = bmp->advance;
381 switch (g->positioning_type)
388 int format = g->f.f1.format;
390 if (format & OTF_XPlacement)
391 xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
392 if (format & OTF_XPlaDevice)
393 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
394 if (format & OTF_YPlacement)
395 yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
396 if (format & OTF_YPlaDevice)
397 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
398 if (format & OTF_XAdvance)
399 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
400 if (format & OTF_XAdvDevice)
401 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice, pixel_size);
406 /* Not yet supported. */
412 prev_width = base_width;
413 goto label_adjust_anchor;
414 default: /* i.e. case 6 */
421 int base_x, base_y, mark_x, mark_y;
423 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
424 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
425 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
426 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
428 if (g->f.f4.base_anchor->AnchorFormat != 1)
429 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
430 if (g->f.f4.mark_anchor->AnchorFormat != 1)
431 adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
432 xoff = (base_x - prev_width) - mark_x;
433 yoff = base_y - mark_y;
437 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
438 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
439 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
442 if (g->GlyphClass == OTF_GlyphClass0)
443 base = mark = g, base_width = advance;
444 else if (g->GlyphClass == OTF_GlyphClassMark)
447 base = g, base_width = advance;
449 free (gstring.glyphs);
451 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
452 XtSetValues (seq_image, arg, 1);
457 update_render_area ()
463 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
464 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
466 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
469 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
470 0, 0, glyph_width, glyph_height,
471 (glyph_width + 4) * i + 1, 1);
472 XDrawRectangle (display, raw_pixmap, gc_set,
473 (glyph_width + 4) * i, 0,
474 glyph_width + 1, glyph_height + 1);
475 XDrawLine (display, raw_pixmap, gc_set,
476 (glyph_width + 4) * i + 1 + glyph_x, 1,
477 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
478 XDrawLine (display, raw_pixmap, gc_set,
479 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
480 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
483 sprintf (buf, "%04X", glyph_rec.codes[i]);
484 XDrawString (display, raw_pixmap, gc_inv,
485 (glyph_width + 1) * i + 1
486 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
487 glyph_height + 2 + FONT_HEIGHT, buf, 4);
489 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
490 XtSetValues (raw_image, arg, 1);
495 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
497 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
501 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
503 int g_width, g_height, g_x, g_y, pix_width, pix_height;
504 int margin = 20 * 300 / 25.4;
505 int a4_width = 210 * 300 / 25.4 - margin * 2;
506 int a4_height = 297 * 300 / 25.4 - margin * 2;
509 XImage ximage, *image;
514 FT_Set_Pixel_Sizes (face, 0, size);
515 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
516 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
517 pix_width = (g_width + 1) * 16 + margin + 1;
518 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
519 while (pix_width > a4_width || pix_height > a4_height)
522 FT_Set_Pixel_Sizes (face, 0, size);
523 g_width = ((face->bbox.xMax - face->bbox.xMin)
524 * size / face->units_per_EM);
525 g_height = ((face->bbox.yMax - face->bbox.yMin)
526 * size / face->units_per_EM);
527 pix_width = (g_width + 1) * 16 + margin + 1;
528 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
531 g_x = - (face->bbox.xMin * size / face->units_per_EM);
532 g_y = face->bbox.yMax * size / face->units_per_EM;
533 for (i = 0; i < 0xFF; i++)
537 if (charmap_index >= 0)
538 idx = FT_Get_Char_Index (face, (FT_ULong) i);
541 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
543 if (g_x < - face->glyph->bitmap_left)
544 g_x = - face->glyph->bitmap_left;
545 if (g_y < face->glyph->bitmap_top)
546 g_y = face->glyph->bitmap_top;
548 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
550 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
552 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
554 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
557 pix_width = (g_width + 1) * 16 + margin + 1;
558 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
559 pixmap = XCreatePixmap (display,
560 RootWindow (display, DefaultScreen (display)),
561 pix_width, pix_height, 1);
562 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
564 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
565 XDrawLine (display, pixmap, gc_set, x, margin,
566 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
567 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
568 XDrawLine (display, pixmap, gc_set, margin, y,
569 margin + (g_width + 1) * 16, y);
570 for (i = 0; i < 256; i++)
575 if (charmap_index >= 0)
576 idx = FT_Get_Char_Index (face, (FT_ULong) i);
579 x = margin + (g_width + 1) * (i % 16);
580 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
581 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
583 ximage.height = face->glyph->bitmap.rows;
584 ximage.width = face->glyph->bitmap.width;
586 ximage.bits_per_pixel = 1;
588 ximage.format = XYPixmap;
589 ximage.data = (char *) face->glyph->bitmap.buffer;
590 ximage.byte_order = MSBFirst;
591 ximage.bitmap_unit = 8;
592 ximage.bitmap_bit_order = MSBFirst;
593 ximage.bitmap_pad = 8;
594 ximage.bytes_per_line = face->glyph->bitmap.pitch;
595 XInitImage (&ximage);
596 XPutImage (display, pixmap, gc, &ximage, 0, 0,
597 x + g_x + face->glyph->bitmap_left,
598 y + g_y - face->glyph->bitmap_top,
599 ximage.width, ximage.height);
601 sprintf (str, "0x%02X", i);
602 XDrawString (display, pixmap, gc_inv,
603 x + (g_width - XTextWidth (font, str, 4))/ 2,
604 y + g_height + FONT_ASCENT, str, 4);
607 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
608 AllPlanes, XYPixmap);
611 char *name = alloca (strlen (filename) + 5);
614 sprintf (name, "%s.pbm", filename);
615 printf ("Writing %s ...", name);
616 fp = fopen (name, "w");
617 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
618 bytes_per_line = (image->width + 7) / 8;
620 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
621 fwrite (data, 1, bytes_per_line, fp);
625 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
630 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
632 int old_glyph_index = glyph_index;
634 if ((int) client_data == -3 && glyph_index > 0)
636 else if ((int) client_data == -2 && glyph_index > 0)
637 glyph_index = (glyph_index - 1) & 0xF000;
638 else if ((int) client_data == -1 && glyph_index > 0)
640 else if ((int) client_data == 1 && glyph_index < 0xFF80)
642 else if ((int) client_data == 2 && glyph_index < 0xF000)
643 glyph_index = (glyph_index + 0x1000) & 0xF000;
644 else if ((int) client_data == 3 && glyph_index < 0xF000)
645 glyph_index = 0xFF80;
646 if (glyph_index != old_glyph_index)
647 update_glyph_area ();
651 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
653 if (charmap_index == (int) client_data)
655 charmap_index = (int) client_data;
656 if (charmap_index >= 0)
657 FT_Set_Charmap (face, face->charmaps[charmap_index]);
658 update_glyph_area ();
662 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
664 if ((int) client_data < 0)
666 if (glyph_rec.n_glyphs > 0)
668 if ((int) client_data == -2)
669 glyph_rec.n_glyphs--;
671 glyph_rec.n_glyphs = 0;
672 update_render_area ();
675 else if (glyph_rec.n_glyphs < 64)
677 int index = glyph_index + (int) client_data;
679 if (charmap_index >= 0)
680 index = FT_Get_Char_Index (face, (FT_ULong) index);
681 if (bitmap[index].pixmap)
683 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
684 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
685 update_render_area ();
691 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
695 reversed = ! reversed;
697 XtSetArg (arg[0], XtNlabel, "L<-R");
699 XtSetArg (arg[0], XtNlabel, "L->R");
700 XtSetValues (w, arg, 1);
705 AltSubstProc (Widget w, XtPointer client_data, XtPointer call_data)
707 do_alternate_subst = ! do_alternate_subst;
712 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
714 FeatureRec *rec = (FeatureRec *) client_data;
721 XtSetArg (arg[0], XtNlabel, &label);
722 XtGetValues (w, arg, 1);
723 if (! strcmp (label, "all"))
725 else if (! strcmp (label, "none"))
729 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
730 if (rec->features[idx].w == w)
732 if (idx == rec->langsys->FeatureCount)
739 for (i = j = 0; j < rec->langsys->FeatureCount; j++)
741 int index = rec->langsys->FeatureIndex[j];
744 = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
745 rec->features[j].on = on;
750 OTF_Tag tag = rec->features[idx].tag;
753 if (rec->features[i].on)
756 j < rec->langsys->FeatureCount && rec->features[j].on; j++)
757 rec->features[j - 1].tag = rec->features[j].tag;
758 rec->features[j - 1].tag = tag;
759 rec->features[j - 1].on = 0;
763 for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
764 rec->features[i].tag = rec->features[i - 1].tag;
765 rec->features[i].tag = tag;
766 rec->features[i].on = 1;
774 if (rec->features[i].on)
776 XtSetArg (arg[0], XtNborderWidth, 3);
777 XtSetArg (arg[1], XtNinternalHeight, 2);
778 XtSetArg (arg[2], XtNinternalWidth, 2);
782 XtSetArg (arg[0], XtNborderWidth, 1);
783 XtSetArg (arg[1], XtNinternalHeight, 4);
784 XtSetArg (arg[2], XtNinternalWidth, 4);
786 OTF_tag_name (rec->features[i].tag, str);
787 XtSetArg (arg[3], XtNlabel, str);
788 XtSetValues (rec->features[i].w, arg, 4);
794 setup_feature_rec (FeatureRec *rec)
800 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
801 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
803 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
809 rec->num_features = rec->langsys->FeatureCount;
810 rec->features = malloc ((sizeof (FeatureElement)) * rec->num_features);
811 memset (rec->features, 0, (sizeof (FeatureElement)) * rec->num_features);
813 else if (rec->num_features < rec->langsys->FeatureCount)
815 rec->features = realloc (rec->features,
816 (sizeof (FeatureElement))
817 * rec->langsys->FeatureCount);
818 memset (rec->features + rec->num_features, 0,
819 (sizeof (FeatureElement))
820 * (rec->langsys->FeatureCount - rec->num_features));
821 rec->num_features = rec->langsys->FeatureCount;
828 XtSetArg (arg[0], XtNborderWidth, 1);
829 XtSetArg (arg[1], XtNinternalHeight, 4);
830 XtSetArg (arg[2], XtNinternalWidth, 4);
831 XtSetArg (arg[3], XtNborderColor, foreground);
832 XtSetArg (arg[4], XtNsensitive, True);
833 for (i = 0; i < rec->langsys->FeatureCount; i++)
835 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
836 int index = rec->langsys->FeatureIndex[i];
839 if (! rec->features[i].w)
841 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
842 rec->parent, arg, 0);
843 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
844 rec->features[i].w = w;
847 rec->features[i].tag = feature[index].FeatureTag;
848 rec->features[i].on = 0;
849 OTF_tag_name (rec->features[i].tag, label);
850 XtSetArg (arg[5], XtNlabel, label);
851 XtSetValues (rec->features[i].w, arg, 6);
854 XtSetArg (arg[0], XtNborderColor, background);
855 XtSetArg (arg[1], XtNsensitive, False);
856 XtSetArg (arg[2], XtNlabel, " ");
857 for (; i < rec->langsys->FeatureCount; i++)
859 if (! rec->features[i].w)
861 Widget w = XtCreateManagedWidget ("", commandWidgetClass,
862 rec->parent, arg, 0);
863 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
864 rec->features[i].w = w;
866 XtSetValues (rec->features[i].w, arg, 3);
871 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
873 if (script_tag == (OTF_Tag) client_data)
875 script_tag = (OTF_Tag) client_data;
876 setup_feature_rec (&gsub);
877 setup_feature_rec (&gpos);
882 create_otf_script_widgets (Widget prev)
890 XtSetArg (arg[0], XtNborderWidth, 0);
891 XtSetArg (arg[1], XtNleft, XawChainLeft);
892 XtSetArg (arg[2], XtNright, XawChainLeft);
893 XtSetArg (arg[3], XtNtop, XawChainTop);
894 XtSetArg (arg[4], XtNbottom, XawChainTop);
895 XtSetArg (arg[5], XtNfromVert, prev);
896 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
897 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
898 XtCreateManagedWidget ("script", labelWidgetClass, prev, arg, 1);
902 n = otf->gsub->ScriptList.ScriptCount;
904 n += otf->gpos->ScriptList.ScriptCount;
905 scripts = alloca (sizeof (OTF_Tag) * n);
908 for (; i < otf->gsub->ScriptList.ScriptCount; i++)
909 scripts[i] = otf->gsub->ScriptList.Script[i].ScriptTag;
912 for (; i < otf->gpos->ScriptList.ScriptCount; i++)
914 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
917 for (j = 0; j < i; j++)
918 if (tag == scripts[j])
927 script_tag = scripts[0];
928 OTF_tag_name (scripts[0], script_name);
931 XtSetArg (arg[0], XtNforeground, background);
932 XtSetArg (arg[1], XtNbackground, foreground);
933 XtCreateManagedWidget (script_name, labelWidgetClass, prev, arg, 2);
939 XtSetArg (arg[0], XtNstate, True);
940 w = XtCreateManagedWidget (script_name, toggleWidgetClass, prev, arg, 1);
941 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[0]);
942 XtSetArg (arg[0], XtNradioGroup, w);
943 for (i = 1; i < n; i++)
945 OTF_tag_name (scripts[i], name);
946 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
947 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[i]);
955 create_otf_widgets (Widget prev, FeatureRec *rec)
961 XtSetArg (arg[0], XtNborderWidth, 0);
962 XtSetArg (arg[1], XtNleft, XawChainLeft);
963 XtSetArg (arg[2], XtNright, XawChainLeft);
964 XtSetArg (arg[3], XtNtop, XawChainTop);
965 XtSetArg (arg[4], XtNbottom, XawChainTop);
966 XtSetArg (arg[5], XtNfromVert, prev);
967 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
968 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
970 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
971 XtSetArg (arg[0], XtNborderWidth, 1);
972 XtSetArg (arg[1], XtNinternalHeight, 4);
973 XtSetArg (arg[2], XtNinternalWidth, 4);
974 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
975 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
976 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
977 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
980 setup_feature_rec (rec);
987 String quit_action = "<KeyPress>q: set() notify() unset()";
988 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
989 <KeyPress>Home: set() notify() unset()";
990 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
991 <KeyPress>Up: set() notify() unset()";
992 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
993 <KeyPress>Left: set() notify() unset()";
994 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
995 <KeyPress>Right: set() notify() unset()";
996 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
997 <KeyPress>Down: set() notify() unset()";
998 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
999 <KeyPress>End: set() notify() unset()";
1003 String trans = "<Expose>: Expose()";
1005 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
1006 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
1008 XtSetArg (arg[0], XtNleft, XawChainLeft);
1009 XtSetArg (arg[1], XtNright, XawChainLeft);
1010 XtSetArg (arg[2], XtNtop, XawChainTop);
1011 XtSetArg (arg[3], XtNbottom, XawChainTop);
1012 XtSetArg (arg[4], XtNborderWidth, 0);
1013 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
1014 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
1016 XtSetArg (arg[6], XtNfromVert, command_area);
1017 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
1019 XtSetArg (arg[4], XtNborderWidth, 0);
1020 XtSetArg (arg[5], XtNfromVert, navi_area);
1021 XtSetArg (arg[6], XtNdefaultDistance, 0);
1022 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
1024 XtSetArg (arg[5], XtNfromVert, glyph_area);
1025 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
1028 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
1029 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
1030 command_area, arg, 1);
1031 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
1033 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
1034 command_area, arg, 1);
1035 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
1037 XtSetArg (arg[0], XtNborderWidth, 0);
1038 XtSetArg (arg[1], XtNwidth, 10);
1039 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
1041 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
1042 XtSetArg (arg[0], XtNstate, True);
1043 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
1044 command_area, arg, 1);
1045 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1046 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1047 for (i = 0; i < face->num_charmaps; i++)
1049 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1051 command_area, arg, 1);
1052 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
1055 XtSetArg (arg[0], XtNlabel, " |< (f)");
1056 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1057 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1059 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1060 XtSetArg (arg[0], XtNlabel, "<< (P)");
1061 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1062 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1064 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1065 XtSetArg (arg[0], XtNlabel, "< (p)");
1066 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1067 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1069 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1070 XtSetArg (arg[0], XtNlabel, " 0000 ");
1071 range = XtCreateManagedWidget ("range", labelWidgetClass,
1073 XtSetArg (arg[0], XtNforeground, &foreground);
1074 XtSetArg (arg[1], XtNbackground, &background);
1075 XtGetValues (range, arg, 2);
1077 XtSetArg (arg[0], XtNlabel, "> (n)");
1078 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1079 next = XtCreateManagedWidget ("next", commandWidgetClass,
1081 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1082 XtSetArg (arg[0], XtNlabel, ">> (N)");
1083 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1084 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1086 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1087 XtSetArg (arg[0], XtNlabel, ">| (l)");
1088 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1089 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1091 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1093 XtSetArg (arg[0], XtNleft, XawChainLeft);
1094 XtSetArg (arg[1], XtNright, XawChainLeft);
1095 XtSetArg (arg[2], XtNtop, XawChainTop);
1096 XtSetArg (arg[3], XtNbottom, XawChainTop);
1098 for (i = 0; i < 8; i++)
1104 sprintf (str, "%XX", i);
1105 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1106 XtSetArg (arg[n], XtNlabel, str), n++;
1107 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1109 XtSetArg (arg[n], XtNfromVert, w), n++;
1110 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1111 index_label[i] = head;
1112 for (j = 0; j < 16; j++)
1118 XtSetArg (arg[n], XtNfromVert, w), n++;
1120 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1122 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1123 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1124 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1125 glyph_area, arg, n);
1126 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1130 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1131 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1132 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1133 XtSetArg (arg[6], XtNfromHoriz, w);
1134 XtSetArg (arg[7], XtNborderWidth, 0);
1136 for (j = 0; j < 16; j++)
1140 sprintf (str, "X%X", j);
1141 XtSetArg (arg[8], XtNlabel, str);
1142 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1143 XtSetArg (arg[6], XtNfromHoriz, w);
1146 XtSetArg (arg[0], XtNleft, XawChainLeft);
1147 XtSetArg (arg[1], XtNright, XawChainLeft);
1148 XtSetArg (arg[2], XtNtop, XawChainTop);
1149 XtSetArg (arg[3], XtNbottom, XawChainTop);
1150 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1151 XtSetArg (arg[5], XtNborderWidth, 0);
1152 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1153 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1154 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1155 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1156 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1157 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1158 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1159 alt_subst = XtCreateManagedWidget ("AltSubst", toggleWidgetClass, w, arg, 0);
1160 XtAddCallback (alt_subst, XtNcallback, AltSubstProc, NULL);
1162 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1163 XtSetArg (arg[5], XtNborderWidth, 0);
1164 XtSetArg (arg[6], XtNfromVert, w);
1165 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1167 XtSetArg (arg[0], XtNborderWidth, 0);
1168 XtSetArg (arg[1], XtNlabel, "raw: ");
1169 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1171 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1172 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1177 OTF_get_table (otf, "GSUB");
1178 OTF_get_table (otf, "GPOS");
1179 w = create_otf_script_widgets (w);
1182 gsub.label = "GSUB";
1183 gsub.gsub_gpos = otf->gsub;
1184 w = create_otf_widgets (w, &gsub);
1188 gpos.label = "GPOS";
1189 gpos.gsub_gpos = otf->gpos;
1190 w = create_otf_widgets (w, &gpos);
1194 XtSetArg (arg[6], XtNfromVert, w);
1195 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1196 XtSetArg (arg[0], XtNborderWidth, 0);
1197 XtSetArg (arg[1], XtNlabel, "seq: ");
1198 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1200 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1201 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1203 XtInstallAllAccelerators (shell, shell);
1207 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1209 XTextProperty text_prop;
1210 char *pname = "otfview";
1211 char *fname = basename (filename);
1212 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1214 sprintf (name, "%s - %s", pname, fname);
1215 text_prop.value = (unsigned char *) name;
1216 text_prop.encoding = XA_STRING;
1217 text_prop.format = 8;
1218 text_prop.nitems = strlen (name);
1219 XSetWMName (display, XtWindow (shell), &text_prop);
1222 /* Format MSG by FMT and print the result to the stderr, and exit. */
1224 #define FATAL_ERROR(fmt, arg) \
1226 fprintf (stderr, fmt, arg); \
1231 x_error_handler (Display *display, XErrorEvent *error)
1238 main (int argc, char **argv)
1240 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1244 OTF_GlyphString gstring;
1249 int fixed_pixel_size = 0;
1252 pixel_size = DEFAULT_PIXEL_SIZE;
1254 char *str = getenv ("PIXEL_SIZE");
1256 if (str && (i = atoi (str)) > 0)
1259 fixed_pixel_size = 1;
1263 gstring.size = gstring.used = 256;
1264 g = calloc (256, sizeof (OTF_Glyph));
1267 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1268 shellWidgetClass, arg, 0);
1269 display = XtDisplay (shell);
1270 /*XSynchronize (display, True);*/
1271 XSetErrorHandler (x_error_handler);
1272 display_width = DisplayWidth (display,
1273 XScreenNumberOfScreen (XtScreen (shell)));
1274 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1276 font = XLoadQueryFont (display, "fixed");
1278 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1280 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
1281 basename (argv[0]));
1283 " Pixel size is decided by the environment variable PIXEL_SIZE ((default %d).\n", DEFAULT_PIXEL_SIZE);
1287 if (strstr (filename, ".ttf")
1288 || strstr (filename, ".TTF")
1289 || strstr (filename, ".otf")
1290 || strstr (filename, ".OTF"))
1292 otf = OTF_open (filename);
1294 || OTF_get_table (otf, "head") < 0
1295 || OTF_get_table (otf, "cmap") < 0
1296 || (OTF_check_table (otf, "GSUB") < 0
1297 && OTF_check_table (otf, "GPOS") < 0))
1301 if ((err = FT_Init_FreeType (&library)))
1302 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1303 err = FT_New_Face (library, filename, 0, &face);
1304 if (err == FT_Err_Unknown_File_Format)
1305 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1307 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
1308 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1309 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1315 filename = basename (filename);
1316 sprintf (title, "%s family:%s style:%s",
1317 filename, face->family_name, face->style_name);
1318 XtSetArg (arg[0], XtNtitle, title);
1319 XtSetValues (shell, arg, 1);
1322 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1323 * pixel_size / face->units_per_EM);
1324 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1326 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1327 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1328 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1329 * pixel_size / face->units_per_EM);
1331 if (glyph_width < FONT_WIDTH * 4)
1332 glyph_width = FONT_WIDTH * 4;
1334 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1335 * pixel_size / face->units_per_EM);
1337 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1338 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1339 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1340 glyph_width, glyph_height, 1);
1343 unsigned long valuemask = GCFunction | GCLineWidth;
1346 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1347 values.function = GXset;
1348 values.line_width = 1;
1349 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1350 values.function = GXor;
1351 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1352 values.function = GXcopyInverted;
1353 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1356 XFillRectangle (display, none_pixmap, gc, 0, 0,
1357 glyph_width, glyph_height);
1358 XDrawString (display, none_pixmap, gc_inv,
1359 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1360 glyph_height / 2, "none", 4);
1362 render_width = (glyph_width + 4) * 15 + 1;
1363 render_height = glyph_height + 2;
1365 charmap_rec[0].platform_id = -1;
1366 charmap_rec[0].encoding_id = -1;
1367 strcpy (charmap_rec[0].name, "no charmap");
1369 for (i = 0; i < face->num_charmaps; i++)
1371 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1372 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1373 sprintf (charmap_rec[i + 1].name, "%d-%d",
1374 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1375 if (face->charmaps[i]->platform_id == 0
1376 || (face->charmaps[i]->platform_id == 3
1377 && face->charmaps[i]->encoding_id == 1))
1378 strcat (charmap_rec[i + 1].name, " (unicode)");
1379 else if (face->charmaps[i]->platform_id == 1
1380 && face->charmaps[i]->encoding_id == 0)
1381 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1384 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1385 render_width, render_height, 1);
1386 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1387 render_width, render_height, 1);
1389 memset (bitmap, 0, sizeof (bitmap));
1393 update_glyph_area ();
1394 update_render_area ();
1396 XtAppAddActions (context, actions, XtNumber (actions));
1397 XtRealizeWidget (shell);
1398 XtAppMainLoop (context);
1403 #else /* not HAVE_X11_XAW_COMMAND_H */
1406 main (int argc, char **argv)
1409 "Building of this program failed (lack of some header files)\n",