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 *prev, int *x, int *y)
268 if (anchor->AnchorFormat == 2 && prev)
271 int ap = anchor->f.f1.AnchorPoint;
273 FT_Load_Glyph (ft_face, (FT_UInt) prev->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;
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);
313 str = get_features (&otf->gsub->FeatureList, &gsub);
316 OTF_drive_gsub (otf, &gstring, NULL, NULL, str);
322 str = get_features (&otf->gpos->FeatureList, &gpos);
325 OTF_drive_gpos (otf, &gstring, NULL, NULL, str);
336 for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
337 prev < g; prev++, g--)
338 temp = *prev, *prev = *g, *g = temp;
339 for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
340 if (g->GlyphClass == 3)
344 while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
346 for (g0 = g; prev < g0; prev++, g0--)
347 temp = *prev, *prev = *g, *g = temp;
352 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
353 i < gstring.used; i++, prev = g++)
355 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
356 int xoff = 0, yoff = 0;
357 int advance = bmp->advance;
361 create_pixmap (gstring.glyphs[i].glyph_id);
365 switch (g->positioning_type)
372 int format = g->f.f1.format;
374 if (format & OTF_XPlacement)
375 xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
376 if (format & OTF_XPlaDevice)
377 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
378 if (format & OTF_YPlacement)
379 yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
380 if (format & OTF_YPlaDevice)
381 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
382 if (format & OTF_XAdvance)
383 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
384 if (format & OTF_XAdvDevice)
385 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice, pixel_size);
389 /* Not yet supported. */
393 int base_x, base_y, mark_x, mark_y;
395 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
396 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
397 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
398 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
400 if (g->f.f4.base_anchor->AnchorFormat != 1)
401 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
402 if (g->f.f4.mark_anchor->AnchorFormat != 1)
403 adjust_anchor (g->f.f4.mark_anchor, face, prev, &mark_x, &mark_y);
404 xoff = (base_x - prev_width) - mark_x;
405 yoff = base_y - mark_y;
409 /* Not yet supported. */
411 default: /* i.e case 6 */
412 /* Not yet supported. */
416 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
417 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
418 x + bmp->x + xoff, glyph_y + bmp->y + yoff);
419 x += prev_width = advance;
421 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
422 XtSetValues (seq_image, arg, 1);
427 update_render_area ()
433 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
434 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
436 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
439 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
440 0, 0, glyph_width, glyph_height,
441 (glyph_width + 4) * i + 1, 1);
442 XDrawRectangle (display, raw_pixmap, gc_set,
443 (glyph_width + 4) * i, 0,
444 glyph_width + 1, glyph_height + 1);
445 XDrawLine (display, raw_pixmap, gc_set,
446 (glyph_width + 4) * i + 1 + glyph_x, 1,
447 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
448 XDrawLine (display, raw_pixmap, gc_set,
449 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
450 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
453 sprintf (buf, "%04X", glyph_rec.codes[i]);
454 XDrawString (display, raw_pixmap, gc_inv,
455 (glyph_width + 1) * i + 1
456 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
457 glyph_height + 2 + FONT_HEIGHT, buf, 4);
459 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
460 XtSetValues (raw_image, arg, 1);
465 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
467 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
471 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
473 int g_width, g_height, g_x, g_y, pix_width, pix_height;
474 int margin = 20 * 300 / 25.4;
475 int a4_width = 210 * 300 / 25.4 - margin * 2;
476 int a4_height = 297 * 300 / 25.4 - margin * 2;
479 XImage ximage, *image;
484 FT_Set_Pixel_Sizes (face, 0, size);
485 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
486 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
487 pix_width = (g_width + 1) * 16 + margin + 1;
488 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
489 while (pix_width > a4_width || pix_height > a4_height)
492 FT_Set_Pixel_Sizes (face, 0, size);
493 g_width = ((face->bbox.xMax - face->bbox.xMin)
494 * size / face->units_per_EM);
495 g_height = ((face->bbox.yMax - face->bbox.yMin)
496 * size / face->units_per_EM);
497 pix_width = (g_width + 1) * 16 + margin + 1;
498 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
501 g_x = - (face->bbox.xMin * size / face->units_per_EM);
502 g_y = face->bbox.yMax * size / face->units_per_EM;
503 for (i = 0; i < 0xFF; i++)
507 if (charmap_index >= 0)
508 idx = FT_Get_Char_Index (face, (FT_ULong) i);
511 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
513 if (g_x < - face->glyph->bitmap_left)
514 g_x = - face->glyph->bitmap_left;
515 if (g_y < face->glyph->bitmap_top)
516 g_y = face->glyph->bitmap_top;
518 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
520 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
522 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
524 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
527 pix_width = (g_width + 1) * 16 + margin + 1;
528 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
529 pixmap = XCreatePixmap (display,
530 RootWindow (display, DefaultScreen (display)),
531 pix_width, pix_height, 1);
532 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
534 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
535 XDrawLine (display, pixmap, gc_set, x, margin,
536 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
537 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
538 XDrawLine (display, pixmap, gc_set, margin, y,
539 margin + (g_width + 1) * 16, y);
540 for (i = 0; i < 256; i++)
545 if (charmap_index >= 0)
546 idx = FT_Get_Char_Index (face, (FT_ULong) i);
549 x = margin + (g_width + 1) * (i % 16);
550 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
551 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
553 ximage.height = face->glyph->bitmap.rows;
554 ximage.width = face->glyph->bitmap.width;
556 ximage.bits_per_pixel = 1;
558 ximage.format = XYPixmap;
559 ximage.data = (char *) face->glyph->bitmap.buffer;
560 ximage.byte_order = MSBFirst;
561 ximage.bitmap_unit = 8;
562 ximage.bitmap_bit_order = MSBFirst;
563 ximage.bitmap_pad = 8;
564 ximage.bytes_per_line = face->glyph->bitmap.pitch;
565 XInitImage (&ximage);
566 XPutImage (display, pixmap, gc, &ximage, 0, 0,
567 x + g_x + face->glyph->bitmap_left,
568 y + g_y - face->glyph->bitmap_top,
569 ximage.width, ximage.height);
571 sprintf (str, "0x%02X", i);
572 XDrawString (display, pixmap, gc_inv,
573 x + (g_width - XTextWidth (font, str, 4))/ 2,
574 y + g_height + FONT_ASCENT, str, 4);
577 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
578 AllPlanes, XYPixmap);
581 char *name = alloca (strlen (filename) + 5);
584 sprintf (name, "%s.pbm", filename);
585 printf ("Writing %s ...", name);
586 fp = fopen (name, "w");
587 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
588 bytes_per_line = (image->width + 7) / 8;
590 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
591 fwrite (data, 1, bytes_per_line, fp);
595 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
600 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
602 int old_glyph_index = glyph_index;
604 if ((int) client_data == -3 && glyph_index > 0)
606 else if ((int) client_data == -2 && glyph_index > 0)
607 glyph_index = (glyph_index - 1) & 0xF000;
608 else if ((int) client_data == -1 && glyph_index > 0)
610 else if ((int) client_data == 1 && glyph_index < 0xFF80)
612 else if ((int) client_data == 2 && glyph_index < 0xF000)
613 glyph_index = (glyph_index + 0x1000) & 0xF000;
614 else if ((int) client_data == 3 && glyph_index < 0xF000)
615 glyph_index = 0xFF80;
616 if (glyph_index != old_glyph_index)
617 update_glyph_area ();
621 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
623 if (charmap_index == (int) client_data)
625 charmap_index = (int) client_data;
626 if (charmap_index >= 0)
627 FT_Set_Charmap (face, face->charmaps[charmap_index]);
628 update_glyph_area ();
632 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
634 if ((int) client_data < 0)
636 if (glyph_rec.n_glyphs > 0)
638 if ((int) client_data == -2)
639 glyph_rec.n_glyphs--;
641 glyph_rec.n_glyphs = 0;
642 update_render_area ();
645 else if (glyph_rec.n_glyphs < 64)
647 int index = glyph_index + (int) client_data;
649 if (charmap_index >= 0)
650 index = FT_Get_Char_Index (face, (FT_ULong) index);
651 if (bitmap[index].pixmap)
653 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
654 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
655 update_render_area ();
661 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
665 reversed = ! reversed;
667 XtSetArg (arg[0], XtNlabel, "L<-R");
669 XtSetArg (arg[0], XtNlabel, "L->R");
670 XtSetValues (w, arg, 1);
675 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
677 FeatureRec *rec = (FeatureRec *) client_data;
684 XtSetArg (arg[0], XtNlabel, &label);
685 XtGetValues (w, arg, 1);
686 if (! strcmp (label, "all"))
688 else if (! strcmp (label, "none"))
692 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
693 if (rec->features[idx].w == w)
695 if (idx == rec->langsys->FeatureCount)
702 for (i = j = 0; j < rec->langsys->FeatureCount; j++)
704 int index = rec->langsys->FeatureIndex[j];
707 = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
708 rec->features[j].on = on;
713 OTF_Tag tag = rec->features[idx].tag;
716 if (rec->features[i].on)
719 j < rec->langsys->FeatureCount && rec->features[j].on; j++)
720 rec->features[j - 1].tag = rec->features[j].tag;
721 rec->features[j - 1].tag = tag;
722 rec->features[j - 1].on = 0;
726 for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
727 rec->features[i].tag = rec->features[i - 1].tag;
728 rec->features[i].tag = tag;
729 rec->features[i].on = 1;
736 unsigned fore = foreground, back = background;
740 fore = background, back = foreground;
742 if (rec->features[i].on)
744 XtSetArg (arg[0], XtNforeground, back);
745 XtSetArg (arg[1], XtNbackground, fore);
749 XtSetArg (arg[0], XtNforeground, fore);
750 XtSetArg (arg[1], XtNbackground, back);
752 OTF_tag_name (rec->features[i].tag, str);
753 XtSetArg (arg[2], XtNlabel, str);
754 XtSetValues (rec->features[i].w, arg, 3);
760 setup_feature_rec (FeatureRec *rec)
766 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
767 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
769 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
777 XtSetArg (arg[0], XtNborderWidth, 1);
778 XtSetArg (arg[1], XtNborderColor, foreground);
779 XtSetArg (arg[2], XtNsensitive, True);
780 XtSetArg (arg[3], XtNforeground, foreground);
781 XtSetArg (arg[4], XtNbackground, background);
782 for (i = 0; i < rec->langsys->FeatureCount && i < MAX_FEATURE_COUNT; i++)
784 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
785 int index = rec->langsys->FeatureIndex[i];
788 rec->features[i].tag = feature[index].FeatureTag;
789 rec->features[i].on = 0;
790 OTF_tag_name (rec->features[i].tag, label);
791 XtSetArg (arg[5], XtNlabel, label);
792 XtSetValues (rec->features[i].w, arg, 6);
795 XtSetArg (arg[0], XtNborderWidth, 1);
796 XtSetArg (arg[1], XtNborderColor, background);
797 XtSetArg (arg[2], XtNsensitive, False);
798 XtSetArg (arg[3], XtNforeground, foreground);
799 XtSetArg (arg[4], XtNbackground, background);
800 XtSetArg (arg[5], XtNlabel, " ");
801 for (; i < MAX_FEATURE_COUNT; i++)
802 XtSetValues (rec->features[i].w, arg, 6);
806 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
808 if (script_tag == (OTF_Tag) client_data)
810 script_tag = (OTF_Tag) client_data;
811 setup_feature_rec (&gsub);
812 setup_feature_rec (&gpos);
817 create_otf_script_widgets (Widget prev)
825 XtSetArg (arg[0], XtNborderWidth, 0);
826 XtSetArg (arg[1], XtNleft, XawChainLeft);
827 XtSetArg (arg[2], XtNright, XawChainLeft);
828 XtSetArg (arg[3], XtNtop, XawChainTop);
829 XtSetArg (arg[4], XtNbottom, XawChainTop);
830 XtSetArg (arg[5], XtNfromVert, prev);
831 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
832 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
833 XtCreateManagedWidget ("script", labelWidgetClass, prev, arg, 1);
837 n = otf->gsub->ScriptList.ScriptCount;
839 n += otf->gpos->ScriptList.ScriptCount;
840 scripts = alloca (sizeof (OTF_Tag) * n);
843 for (; i < otf->gsub->ScriptList.ScriptCount; i++)
844 scripts[i] = otf->gsub->ScriptList.Script[i].ScriptTag;
847 for (; i < otf->gpos->ScriptList.ScriptCount; i++)
849 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
852 for (j = 0; j < i; j++)
853 if (tag == scripts[j])
862 script_tag = scripts[0];
863 OTF_tag_name (scripts[0], script_name);
866 XtSetArg (arg[0], XtNforeground, background);
867 XtSetArg (arg[1], XtNbackground, foreground);
868 XtCreateManagedWidget (script_name, labelWidgetClass, prev, arg, 2);
874 XtSetArg (arg[0], XtNstate, True);
875 w = XtCreateManagedWidget (script_name, toggleWidgetClass, prev, arg, 1);
876 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[0]);
877 XtSetArg (arg[0], XtNradioGroup, w);
878 for (i = 1; i < n; i++)
880 OTF_tag_name (scripts[i], name);
881 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
882 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[i]);
890 create_otf_widgets (Widget prev, FeatureRec *rec)
896 XtSetArg (arg[0], XtNborderWidth, 0);
897 XtSetArg (arg[1], XtNleft, XawChainLeft);
898 XtSetArg (arg[2], XtNright, XawChainLeft);
899 XtSetArg (arg[3], XtNtop, XawChainTop);
900 XtSetArg (arg[4], XtNbottom, XawChainTop);
901 XtSetArg (arg[5], XtNfromVert, prev);
902 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
903 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
905 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
906 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, NULL, 0);
907 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
908 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, NULL, 0);
909 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
911 for (i = 0; i < MAX_FEATURE_COUNT; i++)
913 w = XtCreateManagedWidget ("", commandWidgetClass, prev, arg, 1);
914 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
915 rec->features[i].w = w;
918 setup_feature_rec (rec);
925 String quit_action = "<KeyPress>q: set() notify() unset()";
926 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
927 <KeyPress>Home: set() notify() unset()";
928 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
929 <KeyPress>Up: set() notify() unset()";
930 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
931 <KeyPress>Left: set() notify() unset()";
932 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
933 <KeyPress>Right: set() notify() unset()";
934 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
935 <KeyPress>Down: set() notify() unset()";
936 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
937 <KeyPress>End: set() notify() unset()";
941 String trans = "<Expose>: Expose()";
943 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
944 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
946 XtSetArg (arg[0], XtNleft, XawChainLeft);
947 XtSetArg (arg[1], XtNright, XawChainLeft);
948 XtSetArg (arg[2], XtNtop, XawChainTop);
949 XtSetArg (arg[3], XtNbottom, XawChainTop);
950 XtSetArg (arg[4], XtNborderWidth, 0);
951 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
952 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
954 XtSetArg (arg[6], XtNfromVert, command_area);
955 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
957 XtSetArg (arg[4], XtNborderWidth, 0);
958 XtSetArg (arg[5], XtNfromVert, navi_area);
959 XtSetArg (arg[6], XtNdefaultDistance, 0);
960 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
962 XtSetArg (arg[5], XtNfromVert, glyph_area);
963 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
966 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
967 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
968 command_area, arg, 1);
969 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
971 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
972 command_area, arg, 1);
973 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
975 XtSetArg (arg[0], XtNborderWidth, 0);
976 XtSetArg (arg[1], XtNwidth, 10);
977 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
979 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
980 XtSetArg (arg[0], XtNstate, True);
981 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
982 command_area, arg, 1);
983 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
984 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
985 for (i = 0; i < face->num_charmaps; i++)
987 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
989 command_area, arg, 1);
990 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
993 XtSetArg (arg[0], XtNlabel, " |< (f)");
994 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
995 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
997 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
998 XtSetArg (arg[0], XtNlabel, "<< (P)");
999 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1000 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1002 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1003 XtSetArg (arg[0], XtNlabel, "< (p)");
1004 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1005 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1007 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1008 XtSetArg (arg[0], XtNlabel, " 0000 ");
1009 range = XtCreateManagedWidget ("range", labelWidgetClass,
1011 XtSetArg (arg[0], XtNforeground, &foreground);
1012 XtSetArg (arg[1], XtNbackground, &background);
1013 XtGetValues (range, arg, 2);
1015 XtSetArg (arg[0], XtNlabel, "> (n)");
1016 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1017 next = XtCreateManagedWidget ("next", commandWidgetClass,
1019 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1020 XtSetArg (arg[0], XtNlabel, ">> (N)");
1021 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1022 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1024 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1025 XtSetArg (arg[0], XtNlabel, ">| (l)");
1026 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1027 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1029 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1031 XtSetArg (arg[0], XtNleft, XawChainLeft);
1032 XtSetArg (arg[1], XtNright, XawChainLeft);
1033 XtSetArg (arg[2], XtNtop, XawChainTop);
1034 XtSetArg (arg[3], XtNbottom, XawChainTop);
1036 for (i = 0; i < 8; i++)
1042 sprintf (str, "%XX", i);
1043 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1044 XtSetArg (arg[n], XtNlabel, str), n++;
1045 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1047 XtSetArg (arg[n], XtNfromVert, w), n++;
1048 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1049 index_label[i] = head;
1050 for (j = 0; j < 16; j++)
1056 XtSetArg (arg[n], XtNfromVert, w), n++;
1058 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1060 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1061 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1062 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1063 glyph_area, arg, n);
1064 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1068 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1069 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1070 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1071 XtSetArg (arg[6], XtNfromHoriz, w);
1072 XtSetArg (arg[7], XtNborderWidth, 0);
1074 for (j = 0; j < 16; j++)
1078 sprintf (str, "X%X", j);
1079 XtSetArg (arg[8], XtNlabel, str);
1080 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1081 XtSetArg (arg[6], XtNfromHoriz, w);
1084 XtSetArg (arg[0], XtNleft, XawChainLeft);
1085 XtSetArg (arg[1], XtNright, XawChainLeft);
1086 XtSetArg (arg[2], XtNtop, XawChainTop);
1087 XtSetArg (arg[3], XtNbottom, XawChainTop);
1088 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1089 XtSetArg (arg[5], XtNborderWidth, 0);
1090 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1091 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1092 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1093 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1094 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1095 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1096 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1098 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1099 XtSetArg (arg[5], XtNborderWidth, 0);
1100 XtSetArg (arg[6], XtNfromVert, w);
1101 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1103 XtSetArg (arg[0], XtNborderWidth, 0);
1104 XtSetArg (arg[1], XtNlabel, "raw: ");
1105 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1107 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1108 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1113 OTF_get_table (otf, "GSUB");
1114 OTF_get_table (otf, "GPOS");
1115 w = create_otf_script_widgets (w);
1118 gsub.label = "GSUB";
1119 gsub.gsub_gpos = otf->gsub;
1120 w = create_otf_widgets (w, &gsub);
1124 gpos.label = "GPOS";
1125 gpos.gsub_gpos = otf->gpos;
1126 w = create_otf_widgets (w, &gpos);
1130 XtSetArg (arg[6], XtNfromVert, w);
1131 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1132 XtSetArg (arg[0], XtNborderWidth, 0);
1133 XtSetArg (arg[1], XtNlabel, "seq: ");
1134 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1136 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1137 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1139 XtInstallAllAccelerators (shell, shell);
1143 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1145 XTextProperty text_prop;
1146 char *pname = "otfview";
1147 char *fname = basename (filename);
1148 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1150 sprintf (name, "%s - %s", pname, fname);
1151 text_prop.value = (unsigned char *) name;
1152 text_prop.encoding = XA_STRING;
1153 text_prop.format = 8;
1154 text_prop.nitems = strlen (name);
1155 XSetWMName (display, XtWindow (shell), &text_prop);
1158 /* Format MSG by FMT and print the result to the stderr, and exit. */
1160 #define FATAL_ERROR(fmt, arg) \
1162 fprintf (stderr, fmt, arg); \
1167 x_error_handler (Display *display, XErrorEvent *error)
1174 main (int argc, char **argv)
1176 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1180 OTF_GlyphString gstring;
1185 int fixed_pixel_size = 0;
1188 pixel_size = DEFAULT_PIXEL_SIZE;
1190 char *str = getenv ("PIXEL_SIZE");
1192 if (str && (i = atoi (str)) > 0)
1195 fixed_pixel_size = 1;
1199 gstring.size = gstring.used = 256;
1200 g = calloc (256, sizeof (OTF_Glyph));
1203 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1204 shellWidgetClass, arg, 0);
1205 display = XtDisplay (shell);
1206 /*XSynchronize (display, True);*/
1207 XSetErrorHandler (x_error_handler);
1208 display_width = DisplayWidth (display,
1209 XScreenNumberOfScreen (XtScreen (shell)));
1210 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1212 font = XLoadQueryFont (display, "fixed");
1214 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1216 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
1217 basename (argv[0]));
1221 if (strstr (filename, ".ttf")
1222 || strstr (filename, ".TTF")
1223 || strstr (filename, ".otf")
1224 || strstr (filename, ".OTF"))
1226 otf = OTF_open (filename);
1228 || OTF_get_table (otf, "head") < 0
1229 || OTF_get_table (otf, "cmap") < 0
1230 || (OTF_check_table (otf, "GSUB") < 0
1231 && OTF_check_table (otf, "GPOS") < 0))
1235 if ((err = FT_Init_FreeType (&library)))
1236 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1237 err = FT_New_Face (library, filename, 0, &face);
1238 if (err == FT_Err_Unknown_File_Format)
1239 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1241 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
1242 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1243 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1249 filename = basename (filename);
1250 sprintf (title, "%s family:%s style:%s",
1251 filename, face->family_name, face->style_name);
1252 XtSetArg (arg[0], XtNtitle, title);
1253 XtSetValues (shell, arg, 1);
1256 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1257 * pixel_size / face->units_per_EM);
1258 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1260 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1261 FT_Set_Pixel_Sizes (face, 0, pixel_size);
1262 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1263 * pixel_size / face->units_per_EM);
1265 if (glyph_width < FONT_WIDTH * 4)
1266 glyph_width = FONT_WIDTH * 4;
1268 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1269 * pixel_size / face->units_per_EM);
1271 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1272 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1273 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1274 glyph_width, glyph_height, 1);
1277 unsigned long valuemask = GCFunction | GCLineWidth;
1280 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1281 values.function = GXset;
1282 values.line_width = 1;
1283 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1284 values.function = GXor;
1285 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1286 values.function = GXcopyInverted;
1287 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1290 XFillRectangle (display, none_pixmap, gc, 0, 0,
1291 glyph_width, glyph_height);
1292 XDrawString (display, none_pixmap, gc_inv,
1293 (glyph_width - XTextWidth (font, "none", 4)) / 2,
1294 glyph_height / 2, "none", 4);
1296 render_width = (glyph_width + 4) * 15 + 1;
1297 render_height = glyph_height + 2;
1299 charmap_rec[0].platform_id = -1;
1300 charmap_rec[0].encoding_id = -1;
1301 strcpy (charmap_rec[0].name, "no charmap");
1303 for (i = 0; i < face->num_charmaps; i++)
1305 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1306 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1307 sprintf (charmap_rec[i + 1].name, "%d-%d",
1308 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1309 if (face->charmaps[i]->platform_id == 0
1310 || (face->charmaps[i]->platform_id == 3
1311 && face->charmaps[i]->encoding_id == 1))
1312 strcat (charmap_rec[i + 1].name, " (unicode)");
1313 else if (face->charmaps[i]->platform_id == 1
1314 && face->charmaps[i]->encoding_id == 0)
1315 strcat (charmap_rec[i + 1].name, " (apple-roman)");
1318 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1319 render_width, render_height, 1);
1320 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1321 render_width, render_height, 1);
1323 memset (bitmap, 0, sizeof (bitmap));
1327 update_glyph_area ();
1328 update_render_area ();
1330 XtAppAddActions (context, actions, XtNumber (actions));
1331 XtRealizeWidget (shell);
1332 XtAppMainLoop (context);