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 #include <X11/Xatom.h>
32 #include <X11/Intrinsic.h>
33 #include <X11/StringDefs.h>
34 #include <X11/Shell.h>
35 #include <X11/Xaw/Command.h>
36 #include <X11/Xaw/Toggle.h>
37 #include <X11/Xaw/Box.h>
38 #include <X11/Xaw/Form.h>
39 #include <X11/Xaw/Viewport.h>
42 #include FT_FREETYPE_H
46 #define DEFAULT_PIXEL_SIZE 30
49 #define DEFAULT_FONT_NAME "6x13"
51 #define FONT_HEIGHT (font->ascent + font->descent)
52 #define FONT_ASCENT (font->ascent)
53 #define FONT_DESCENT (font->descent)
54 #define FONT_WIDTH (font->max_bounds.width)
58 +--- frame (form) -------------------------+
59 | +--- command_area (box) ---------------+ |
60 | | quit dump charmap ... | |
61 | +--------------------------------------+ |
62 | +---- navi_area (box) -----------------+ |
63 | | FIRST PREV prev range next NEXT LAST | |
64 | +--------------------------------------+ |
65 | +--- glyph_area (form) ----------------+ |
66 | | idxh[0] glyph[0] ... glyph[15] | |
68 | | idxh[7] glyph[112] ... glyph[127]| |
69 | | idxl[0] ... idxl[15] | |
70 | +--------------------------------------+ |
71 | +--- render_area (form) ---------------+ |
72 | | clear del bidi | |
73 | | +--- raw (box) --------------------+ | |
74 | | | raw_label raw_image | | |
75 | | +----------------------------------+ | |
76 | | GSUB all none features... | |
77 | | GPOS all none features... | |
78 | | +--- seq (box) --------------------+ | |
79 | | | seq_label seq_image | | |
80 | | +----------------------------------+ | |
81 | +--------------------------------------+ |
82 +------------------------------------------+ */
84 Widget command_area, quit, dump, *charmap;
85 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
86 Widget glyph_area, glyph[128], index_label[8];
87 Widget render_area, clear, del, bidi, raw, seq;
88 Widget raw_label, raw_image, seq_label, seq_image;
89 unsigned long foreground, background;
91 #define MAX_FEATURE_COUNT 16
96 OTF_GSUB_GPOS *gsub_gpos;
102 } features[MAX_FEATURE_COUNT];
105 FeatureRec gsub, gpos;
112 GC gc, gc_set, gc_or, gc_inv;
116 unsigned width, height;
121 BitmapRec bitmap[0x10000];
123 int render_width, render_height;
124 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
138 unsigned glyph_width, glyph_height;
139 int glyph_x, glyph_y;
152 create_pixmap (int index)
154 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
160 bitmap[index].pixmap = none_pixmap;
163 ximage.height = face->glyph->bitmap.rows;
164 ximage.width = face->glyph->bitmap.width;
166 ximage.bits_per_pixel = 1;
168 ximage.format = XYPixmap;
169 ximage.data = (char *) face->glyph->bitmap.buffer;
170 ximage.byte_order = MSBFirst;
171 ximage.bitmap_unit = 8;
172 ximage.bitmap_bit_order = MSBFirst;
173 ximage.bitmap_pad = 8;
174 ximage.bytes_per_line = face->glyph->bitmap.pitch;
175 XInitImage (&ximage);
176 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
177 glyph_width, glyph_height, 1);
178 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
179 XPutImage (display, pixmap, gc, &ximage, 0, 0,
180 glyph_x + face->glyph->bitmap_left,
181 glyph_y - face->glyph->bitmap_top,
182 ximage.width, ximage.height);
183 bitmap[index].pixmap = pixmap;
184 bitmap[index].width = ximage.width;
185 bitmap[index].height = ximage.height;
186 bitmap[index].x = face->glyph->bitmap_left;
187 bitmap[index].y = - face->glyph->bitmap_top;
188 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
199 for (i = 0; i < 128; i++)
201 int index = glyph_index + i;
203 if (charmap_index >= 0)
204 index = FT_Get_Char_Index (face, (FT_ULong) index);
205 if (! bitmap[index].pixmap)
206 create_pixmap (index);
207 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
208 XtSetValues (glyph[i], arg, 1);
211 msb = (glyph_index >> 7) % 2 ? 8 : 0;
212 for (i = 0; i < 8; i++)
216 sprintf (str, "%XX", i | msb );
217 XtSetArg (arg[0], XtNheight, glyph_height + 5);
218 XtSetArg (arg[1], XtNlabel, str);
219 XtSetValues (index_label[i], arg, 2);
222 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
223 XtSetArg (arg[0], XtNlabel, buf);
224 XtSetValues (range, arg, 1);
228 get_features (OTF_FeatureList *list, FeatureRec *rec)
233 if (! rec->features[0].on)
235 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
237 if (rec->features[i].on)
242 if (i == rec->langsys->FeatureCount)
248 str = malloc (n * 5);
249 for (i = 0, p = str; i < n; i++, p += 5)
251 OTF_tag_name (rec->features[i].tag, p);
259 #define DEVICE_DELTA(table, size) \
260 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
261 ? (table).DeltaValue[(size) >= (table).StartSize] \
265 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
266 OTF_Glyph *g, int *x, int *y)
268 if (anchor->AnchorFormat == 2)
271 int ap = anchor->f.f1.AnchorPoint;
273 FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
274 outline = &ft_face->glyph->outline;
275 if (ap < outline->n_points)
277 *x = outline->points[ap].x;
278 *y = outline->points[ap].y;
281 else if (anchor->AnchorFormat == 3)
283 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
284 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
292 OTF_GlyphString gstring;
293 OTF_Glyph *g, *prev, *base, *mark;
295 int len = glyph_rec.n_glyphs;
297 int unitsPerEm = face->units_per_EM;
299 gstring.size = gstring.used = len;
300 gstring.glyphs = alloca (sizeof (OTF_Glyph) * len);
301 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
302 for (i = 0; i < len; i++)
303 gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
304 OTF_drive_gdef (otf, &gstring);
306 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
307 XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
314 str = get_features (&otf->gsub->FeatureList, &gsub);
317 OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
323 str = get_features (&otf->gpos->FeatureList, &gpos);
326 OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
337 for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
338 prev < g; prev++, g--)
339 temp = *prev, *prev = *g, *g = temp;
340 for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
341 if (g->GlyphClass == 3)
345 while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
347 for (g0 = g; prev < g0; prev++, g0--)
348 temp = *prev, *prev = *g, *g = temp;
354 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
355 i < gstring.used; i++, prev = g++)
357 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
358 int xoff = 0, yoff = 0;
360 int advance = bmp->advance;
364 create_pixmap (gstring.glyphs[i].glyph_id);
368 switch (g->positioning_type)
375 int format = g->f.f1.format;
377 if (format & OTF_XPlacement)
378 xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
379 if (format & OTF_XPlaDevice)
380 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
381 if (format & OTF_YPlacement)
382 yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
383 if (format & OTF_YPlaDevice)
384 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
385 if (format & OTF_XAdvance)
386 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
387 if (format & OTF_XAdvDevice)
388 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice, pixel_size);
393 /* Not yet supported. */
399 prev_width = base_width;
400 goto label_adjust_anchor;
401 default: /* i.e. case 6 */
408 int base_x, base_y, mark_x, mark_y;
410 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
411 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
412 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
413 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
415 if (g->f.f4.base_anchor->AnchorFormat != 1)
416 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
417 if (g->f.f4.mark_anchor->AnchorFormat != 1)
418 adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
419 xoff = (base_x - prev_width) - mark_x;
420 yoff = base_y - mark_y;
424 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
425 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
426 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
429 if (g->GlyphClass == OTF_GlyphClass0)
430 base = mark = g, base_width = advance;
431 else if (g->GlyphClass == OTF_GlyphClassMark)
434 base = g, base_width = advance;
436 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
437 XtSetValues (seq_image, arg, 1);
442 update_render_area ()
448 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
449 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
451 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
454 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
455 0, 0, glyph_width, glyph_height,
456 (glyph_width + 4) * i + 1, 1);
457 XDrawRectangle (display, raw_pixmap, gc_set,
458 (glyph_width + 4) * i, 0,
459 glyph_width + 1, glyph_height + 1);
460 XDrawLine (display, raw_pixmap, gc_set,
461 (glyph_width + 4) * i + 1 + glyph_x, 1,
462 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
463 XDrawLine (display, raw_pixmap, gc_set,
464 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
465 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
468 sprintf (buf, "%04X", glyph_rec.codes[i]);
469 XDrawString (display, raw_pixmap, gc_inv,
470 (glyph_width + 1) * i + 1
471 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
472 glyph_height + 2 + FONT_HEIGHT, buf, 4);
474 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
475 XtSetValues (raw_image, arg, 1);
480 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
482 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
486 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
488 int g_width, g_height, g_x, g_y, pix_width, pix_height;
489 int margin = 20 * 300 / 25.4;
490 int a4_width = 210 * 300 / 25.4 - margin * 2;
491 int a4_height = 297 * 300 / 25.4 - margin * 2;
494 XImage ximage, *image;
499 FT_Set_Pixel_Sizes (face, 0, size);
500 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
501 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
502 pix_width = (g_width + 1) * 16 + margin + 1;
503 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
504 while (pix_width > a4_width || pix_height > a4_height)
507 FT_Set_Pixel_Sizes (face, 0, size);
508 g_width = ((face->bbox.xMax - face->bbox.xMin)
509 * size / face->units_per_EM);
510 g_height = ((face->bbox.yMax - face->bbox.yMin)
511 * size / face->units_per_EM);
512 pix_width = (g_width + 1) * 16 + margin + 1;
513 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
516 g_x = - (face->bbox.xMin * size / face->units_per_EM);
517 g_y = face->bbox.yMax * size / face->units_per_EM;
518 for (i = 0; i < 0xFF; i++)
522 if (charmap_index >= 0)
523 idx = FT_Get_Char_Index (face, (FT_ULong) i);
526 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
528 if (g_x < - face->glyph->bitmap_left)
529 g_x = - face->glyph->bitmap_left;
530 if (g_y < face->glyph->bitmap_top)
531 g_y = face->glyph->bitmap_top;
533 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
535 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
537 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
539 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
542 pix_width = (g_width + 1) * 16 + margin + 1;
543 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
544 pixmap = XCreatePixmap (display,
545 RootWindow (display, DefaultScreen (display)),
546 pix_width, pix_height, 1);
547 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
549 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
550 XDrawLine (display, pixmap, gc_set, x, margin,
551 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
552 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
553 XDrawLine (display, pixmap, gc_set, margin, y,
554 margin + (g_width + 1) * 16, y);
555 for (i = 0; i < 256; i++)
560 if (charmap_index >= 0)
561 idx = FT_Get_Char_Index (face, (FT_ULong) i);
564 x = margin + (g_width + 1) * (i % 16);
565 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
566 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
568 ximage.height = face->glyph->bitmap.rows;
569 ximage.width = face->glyph->bitmap.width;
571 ximage.bits_per_pixel = 1;
573 ximage.format = XYPixmap;
574 ximage.data = (char *) face->glyph->bitmap.buffer;
575 ximage.byte_order = MSBFirst;
576 ximage.bitmap_unit = 8;
577 ximage.bitmap_bit_order = MSBFirst;
578 ximage.bitmap_pad = 8;
579 ximage.bytes_per_line = face->glyph->bitmap.pitch;
580 XInitImage (&ximage);
581 XPutImage (display, pixmap, gc, &ximage, 0, 0,
582 x + g_x + face->glyph->bitmap_left,
583 y + g_y - face->glyph->bitmap_top,
584 ximage.width, ximage.height);
586 sprintf (str, "0x%02X", i);
587 XDrawString (display, pixmap, gc_inv,
588 x + (g_width - XTextWidth (font, str, 4))/ 2,
589 y + g_height + FONT_ASCENT, str, 4);
592 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
593 AllPlanes, XYPixmap);
596 char *name = alloca (strlen (filename) + 5);
599 sprintf (name, "%s.pbm", filename);
600 printf ("Writing %s ...", name);
601 fp = fopen (name, "w");
602 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
603 bytes_per_line = (image->width + 7) / 8;
605 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
606 fwrite (data, 1, bytes_per_line, fp);
610 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
615 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
617 int old_glyph_index = glyph_index;
619 if ((int) client_data == -3 && glyph_index > 0)
621 else if ((int) client_data == -2 && glyph_index > 0)
622 glyph_index = (glyph_index - 1) & 0xF000;
623 else if ((int) client_data == -1 && glyph_index > 0)
625 else if ((int) client_data == 1 && glyph_index < 0xFF80)
627 else if ((int) client_data == 2 && glyph_index < 0xF000)
628 glyph_index = (glyph_index + 0x1000) & 0xF000;
629 else if ((int) client_data == 3 && glyph_index < 0xF000)
630 glyph_index = 0xFF80;
631 if (glyph_index != old_glyph_index)
632 update_glyph_area ();
636 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
638 if (charmap_index == (int) client_data)
640 charmap_index = (int) client_data;
641 if (charmap_index >= 0)
642 FT_Set_Charmap (face, face->charmaps[charmap_index]);
643 update_glyph_area ();
647 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
649 if ((int) client_data < 0)
651 if (glyph_rec.n_glyphs > 0)
653 if ((int) client_data == -2)
654 glyph_rec.n_glyphs--;
656 glyph_rec.n_glyphs = 0;
657 update_render_area ();
660 else if (glyph_rec.n_glyphs < 64)
662 int index = glyph_index + (int) client_data;
664 if (charmap_index >= 0)
665 index = FT_Get_Char_Index (face, (FT_ULong) index);
666 if (bitmap[index].pixmap)
668 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
669 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
670 update_render_area ();
676 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
680 reversed = ! reversed;
682 XtSetArg (arg[0], XtNlabel, "L<-R");
684 XtSetArg (arg[0], XtNlabel, "L->R");
685 XtSetValues (w, arg, 1);
690 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
692 FeatureRec *rec = (FeatureRec *) client_data;
699 XtSetArg (arg[0], XtNlabel, &label);
700 XtGetValues (w, arg, 1);
701 if (! strcmp (label, "all"))
703 else if (! strcmp (label, "none"))
707 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
708 if (rec->features[idx].w == w)
710 if (idx == rec->langsys->FeatureCount)
717 for (i = j = 0; j < rec->langsys->FeatureCount; j++)
719 int index = rec->langsys->FeatureIndex[j];
722 = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
723 rec->features[j].on = on;
728 OTF_Tag tag = rec->features[idx].tag;
731 if (rec->features[i].on)
734 j < rec->langsys->FeatureCount && rec->features[j].on; j++)
735 rec->features[j - 1].tag = rec->features[j].tag;
736 rec->features[j - 1].tag = tag;
737 rec->features[j - 1].on = 0;
741 for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
742 rec->features[i].tag = rec->features[i - 1].tag;
743 rec->features[i].tag = tag;
744 rec->features[i].on = 1;
751 unsigned fore = foreground, back = background;
755 fore = background, back = foreground;
757 if (rec->features[i].on)
759 XtSetArg (arg[0], XtNforeground, back);
760 XtSetArg (arg[1], XtNbackground, fore);
764 XtSetArg (arg[0], XtNforeground, fore);
765 XtSetArg (arg[1], XtNbackground, back);
767 OTF_tag_name (rec->features[i].tag, str);
768 XtSetArg (arg[2], XtNlabel, str);
769 XtSetValues (rec->features[i].w, arg, 3);
775 setup_feature_rec (FeatureRec *rec)
781 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
782 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
784 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
792 XtSetArg (arg[0], XtNborderWidth, 1);
793 XtSetArg (arg[1], XtNborderColor, foreground);
794 XtSetArg (arg[2], XtNsensitive, True);
795 XtSetArg (arg[3], XtNforeground, foreground);
796 XtSetArg (arg[4], XtNbackground, background);
797 for (i = 0; i < rec->langsys->FeatureCount && i < MAX_FEATURE_COUNT; i++)
799 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
800 int index = rec->langsys->FeatureIndex[i];
803 rec->features[i].tag = feature[index].FeatureTag;
804 rec->features[i].on = 0;
805 OTF_tag_name (rec->features[i].tag, label);
806 XtSetArg (arg[5], XtNlabel, label);
807 XtSetValues (rec->features[i].w, arg, 6);
810 XtSetArg (arg[0], XtNborderWidth, 1);
811 XtSetArg (arg[1], XtNborderColor, background);
812 XtSetArg (arg[2], XtNsensitive, False);
813 XtSetArg (arg[3], XtNforeground, foreground);
814 XtSetArg (arg[4], XtNbackground, background);
815 XtSetArg (arg[5], XtNlabel, " ");
816 for (; i < MAX_FEATURE_COUNT; i++)
817 XtSetValues (rec->features[i].w, arg, 6);
821 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
823 if (script_tag == (OTF_Tag) client_data)
825 script_tag = (OTF_Tag) client_data;
826 setup_feature_rec (&gsub);
827 setup_feature_rec (&gpos);
832 create_otf_script_widgets (Widget prev)
840 XtSetArg (arg[0], XtNborderWidth, 0);
841 XtSetArg (arg[1], XtNleft, XawChainLeft);
842 XtSetArg (arg[2], XtNright, XawChainLeft);
843 XtSetArg (arg[3], XtNtop, XawChainTop);
844 XtSetArg (arg[4], XtNbottom, XawChainTop);
845 XtSetArg (arg[5], XtNfromVert, prev);
846 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
847 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
848 XtCreateManagedWidget ("script", labelWidgetClass, prev, arg, 1);
852 n = otf->gsub->ScriptList.ScriptCount;
854 n += otf->gpos->ScriptList.ScriptCount;
855 scripts = alloca (sizeof (OTF_Tag) * n);
858 for (; i < otf->gsub->ScriptList.ScriptCount; i++)
859 scripts[i] = otf->gsub->ScriptList.Script[i].ScriptTag;
862 for (; i < otf->gpos->ScriptList.ScriptCount; i++)
864 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
867 for (j = 0; j < i; j++)
868 if (tag == scripts[j])
877 script_tag = scripts[0];
878 OTF_tag_name (scripts[0], script_name);
881 XtSetArg (arg[0], XtNforeground, background);
882 XtSetArg (arg[1], XtNbackground, foreground);
883 XtCreateManagedWidget (script_name, labelWidgetClass, prev, arg, 2);
889 XtSetArg (arg[0], XtNstate, True);
890 w = XtCreateManagedWidget (script_name, toggleWidgetClass, prev, arg, 1);
891 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[0]);
892 XtSetArg (arg[0], XtNradioGroup, w);
893 for (i = 1; i < n; i++)
895 OTF_tag_name (scripts[i], name);
896 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
897 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[i]);
905 create_otf_widgets (Widget prev, FeatureRec *rec)
911 XtSetArg (arg[0], XtNborderWidth, 0);
912 XtSetArg (arg[1], XtNleft, XawChainLeft);
913 XtSetArg (arg[2], XtNright, XawChainLeft);
914 XtSetArg (arg[3], XtNtop, XawChainTop);
915 XtSetArg (arg[4], XtNbottom, XawChainTop);
916 XtSetArg (arg[5], XtNfromVert, prev);
917 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
918 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
920 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
921 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, NULL, 0);
922 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
923 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, NULL, 0);
924 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
926 for (i = 0; i < MAX_FEATURE_COUNT; i++)
928 w = XtCreateManagedWidget ("", commandWidgetClass, prev, arg, 1);
929 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
930 rec->features[i].w = w;
933 setup_feature_rec (rec);
940 String quit_action = "<KeyPress>q: set() notify() unset()";
941 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
942 <KeyPress>Home: set() notify() unset()";
943 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
944 <KeyPress>Up: set() notify() unset()";
945 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
946 <KeyPress>Left: set() notify() unset()";
947 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
948 <KeyPress>Right: set() notify() unset()";
949 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
950 <KeyPress>Down: set() notify() unset()";
951 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
952 <KeyPress>End: set() notify() unset()";
956 String trans = "<Expose>: Expose()";
958 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
959 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
961 XtSetArg (arg[0], XtNleft, XawChainLeft);
962 XtSetArg (arg[1], XtNright, XawChainLeft);
963 XtSetArg (arg[2], XtNtop, XawChainTop);
964 XtSetArg (arg[3], XtNbottom, XawChainTop);
965 XtSetArg (arg[4], XtNborderWidth, 0);
966 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
967 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
969 XtSetArg (arg[6], XtNfromVert, command_area);
970 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
972 XtSetArg (arg[4], XtNborderWidth, 0);
973 XtSetArg (arg[5], XtNfromVert, navi_area);
974 XtSetArg (arg[6], XtNdefaultDistance, 0);
975 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
977 XtSetArg (arg[5], XtNfromVert, glyph_area);
978 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
981 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
982 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
983 command_area, arg, 1);
984 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
986 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
987 command_area, arg, 1);
988 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
990 XtSetArg (arg[0], XtNborderWidth, 0);
991 XtSetArg (arg[1], XtNwidth, 10);
992 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
994 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
995 XtSetArg (arg[0], XtNstate, True);
996 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
997 command_area, arg, 1);
998 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
999 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1000 for (i = 0; i < face->num_charmaps; i++)
1002 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1004 command_area, arg, 1);
1005 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
1008 XtSetArg (arg[0], XtNlabel, " |< (f)");
1009 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1010 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1012 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1013 XtSetArg (arg[0], XtNlabel, "<< (P)");
1014 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1015 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1017 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1018 XtSetArg (arg[0], XtNlabel, "< (p)");
1019 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1020 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1022 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1023 XtSetArg (arg[0], XtNlabel, " 0000 ");
1024 range = XtCreateManagedWidget ("range", labelWidgetClass,
1026 XtSetArg (arg[0], XtNforeground, &foreground);
1027 XtSetArg (arg[1], XtNbackground, &background);
1028 XtGetValues (range, arg, 2);
1030 XtSetArg (arg[0], XtNlabel, "> (n)");
1031 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1032 next = XtCreateManagedWidget ("next", commandWidgetClass,
1034 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1035 XtSetArg (arg[0], XtNlabel, ">> (N)");
1036 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1037 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1039 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1040 XtSetArg (arg[0], XtNlabel, ">| (l)");
1041 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1042 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1044 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1046 XtSetArg (arg[0], XtNleft, XawChainLeft);
1047 XtSetArg (arg[1], XtNright, XawChainLeft);
1048 XtSetArg (arg[2], XtNtop, XawChainTop);
1049 XtSetArg (arg[3], XtNbottom, XawChainTop);
1051 for (i = 0; i < 8; i++)
1057 sprintf (str, "%XX", i);
1058 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1059 XtSetArg (arg[n], XtNlabel, str), n++;
1060 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1062 XtSetArg (arg[n], XtNfromVert, w), n++;
1063 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1064 index_label[i] = head;
1065 for (j = 0; j < 16; j++)
1071 XtSetArg (arg[n], XtNfromVert, w), n++;
1073 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1075 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1076 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1077 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1078 glyph_area, arg, n);
1079 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1083 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1084 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1085 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1086 XtSetArg (arg[6], XtNfromHoriz, w);
1087 XtSetArg (arg[7], XtNborderWidth, 0);
1089 for (j = 0; j < 16; j++)
1093 sprintf (str, "X%X", j);
1094 XtSetArg (arg[8], XtNlabel, str);
1095 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1096 XtSetArg (arg[6], XtNfromHoriz, w);
1099 XtSetArg (arg[0], XtNleft, XawChainLeft);
1100 XtSetArg (arg[1], XtNright, XawChainLeft);
1101 XtSetArg (arg[2], XtNtop, XawChainTop);
1102 XtSetArg (arg[3], XtNbottom, XawChainTop);
1103 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1104 XtSetArg (arg[5], XtNborderWidth, 0);
1105 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1106 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1107 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1108 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1109 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1110 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1111 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1113 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1114 XtSetArg (arg[5], XtNborderWidth, 0);
1115 XtSetArg (arg[6], XtNfromVert, w);
1116 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1118 XtSetArg (arg[0], XtNborderWidth, 0);
1119 XtSetArg (arg[1], XtNlabel, "raw: ");
1120 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1122 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1123 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1128 OTF_get_table (otf, "GSUB");
1129 OTF_get_table (otf, "GPOS");
1130 w = create_otf_script_widgets (w);
1133 gsub.label = "GSUB";
1134 gsub.gsub_gpos = otf->gsub;
1135 w = create_otf_widgets (w, &gsub);
1139 gpos.label = "GPOS";
1140 gpos.gsub_gpos = otf->gpos;
1141 w = create_otf_widgets (w, &gpos);
1145 XtSetArg (arg[6], XtNfromVert, w);
1146 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1147 XtSetArg (arg[0], XtNborderWidth, 0);
1148 XtSetArg (arg[1], XtNlabel, "seq: ");
1149 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1151 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1152 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1154 XtInstallAllAccelerators (shell, shell);
1158 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1160 XTextProperty text_prop;
1161 char *pname = "otfview";
1162 char *fname = basename (filename);
1163 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1165 sprintf (name, "%s - %s", pname, fname);
1166 text_prop.value = (unsigned char *) name;
1167 text_prop.encoding = XA_STRING;
1168 text_prop.format = 8;
1169 text_prop.nitems = strlen (name);
1170 XSetWMName (display, XtWindow (shell), &text_prop);
1173 /* Format MSG by FMT and print the result to the stderr, and exit. */
1175 #define FATAL_ERROR(fmt, arg) \
1177 fprintf (stderr, fmt, arg); \
1182 x_error_handler (Display *display, XErrorEvent *error)
1189 main (int argc, char **argv)
1191 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1195 OTF_GlyphString gstring;
1200 int fixed_pixel_size = 0;
1203 pixel_size = DEFAULT_PIXEL_SIZE;
1205 char *str = getenv ("PIXEL_SIZE");
1207 if (str && (i = atoi (str)) > 0)
1210 fixed_pixel_size = 1;
1214 gstring.size = gstring.used = 256;
1215 g = calloc (256, sizeof (OTF_Glyph));
1218 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1219 shellWidgetClass, arg, 0);
1220 display = XtDisplay (shell);
1221 /*XSynchronize (display, True);*/
1222 XSetErrorHandler (x_error_handler);
1223 display_width = DisplayWidth (display,
1224 XScreenNumberOfScreen (XtScreen (shell)));
1225 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1227 font = XLoadQueryFont (display, "fixed");
1229 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1231 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
1232 basename (argv[0]));
1236 if (strstr (filename, ".ttf")
1237 || strstr (filename, ".TTF")
1238 || strstr (filename, ".otf")
1239 || strstr (filename, ".OTF"))
1241 otf = OTF_open (filename);
1243 || OTF_get_table (otf, "head") < 0
1244 || OTF_get_table (otf, "cmap") < 0
1245 || (OTF_check_table (otf, "GSUB") < 0
1246 && OTF_check_table (otf, "GPOS") < 0))
1250 if ((err = FT_Init_FreeType (&library)))
1251 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1252 err = FT_New_Face (library, filename, 0, &face);
1253 if (err == FT_Err_Unknown_File_Format)
1254 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1256 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
1257 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1258 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1264 filename = basename (filename);
1265 sprintf (title, "%s family:%s style:%s",
1266 filename, face->family_name, face->style_name);
1267 XtSetArg (arg[0], XtNtitle, title);
1268 XtSetValues (shell, arg, 1);
1271 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1272 * pixel_size / face->units_per_EM);
1273 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1275 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1276 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1277 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1278 * pixel_size / face->units_per_EM);
1280 if (glyph_width < FONT_WIDTH * 4)
1281 glyph_width = FONT_WIDTH * 4;
1283 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1284 * pixel_size / face->units_per_EM);
1286 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1287 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1288 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1289 glyph_width, glyph_height, 1);
1292 unsigned long valuemask = GCFunction | GCLineWidth;
1295 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1296 values.function = GXset;
1297 values.line_width = 1;
1298 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1299 values.function = GXor;
1300 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1301 values.function = GXcopyInverted;
1302 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1305 XFillRectangle (display, none_pixmap, gc, 0, 0,
1306 glyph_width, glyph_height);
1307 XDrawString (display, none_pixmap, gc_inv,
1308 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1309 glyph_height / 2, "none", 4);
1311 render_width = (glyph_width + 4) * 15 + 1;
1312 render_height = glyph_height + 2;
1314 charmap_rec[0].platform_id = -1;
1315 charmap_rec[0].encoding_id = -1;
1316 strcpy (charmap_rec[0].name, "no charmap");
1318 for (i = 0; i < face->num_charmaps; i++)
1320 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1321 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1322 sprintf (charmap_rec[i + 1].name, "%d-%d",
1323 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1324 if (face->charmaps[i]->platform_id == 0
1325 || (face->charmaps[i]->platform_id == 3
1326 && face->charmaps[i]->encoding_id == 1))
1327 strcat (charmap_rec[i + 1].name, " (unicode)");
1328 else if (face->charmaps[i]->platform_id == 1
1329 && face->charmaps[i]->encoding_id == 0)
1330 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1333 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1334 render_width, render_height, 1);
1335 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1336 render_width, render_height, 1);
1338 memset (bitmap, 0, sizeof (bitmap));
1342 update_glyph_area ();
1343 update_render_area ();
1345 XtAppAddActions (context, actions, XtNumber (actions));
1346 XtRealizeWidget (shell);
1347 XtAppMainLoop (context);