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. */
30 #include <X11/Xatom.h>
31 #include <X11/Intrinsic.h>
32 #include <X11/StringDefs.h>
33 #include <X11/Shell.h>
34 #include <X11/Xaw/Command.h>
35 #include <X11/Xaw/Toggle.h>
36 #include <X11/Xaw/Box.h>
37 #include <X11/Xaw/Form.h>
38 #include <X11/Xaw/Viewport.h>
41 #include FT_FREETYPE_H
45 #define DEFAULT_PIXEL_SIZE 30
48 #define DEFAULT_FONT_NAME "6x13"
50 #define FONT_HEIGHT (font->ascent + font->descent)
51 #define FONT_ASCENT (font->ascent)
52 #define FONT_DESCENT (font->descent)
53 #define FONT_WIDTH (font->max_bounds.width)
57 +--- frame (form) -------------------------+
58 | +--- command_area (box) ---------------+ |
59 | | quit dump charmap ... | |
60 | +--------------------------------------+ |
61 | +---- navi_area (box) -----------------+ |
62 | | FIRST PREV prev range next NEXT LAST | |
63 | +--------------------------------------+ |
64 | +--- glyph_area (form) ----------------+ |
65 | | idxh[0] glyph[0] ... glyph[15] | |
67 | | idxh[7] glyph[112] ... glyph[127]| |
68 | | idxl[0] ... idxl[15] | |
69 | +--------------------------------------+ |
70 | +--- render_area (form) ---------------+ |
71 | | clear del bidi | |
72 | | +--- raw (box) --------------------+ | |
73 | | | raw_label raw_image | | |
74 | | +----------------------------------+ | |
75 | | GSUB all none features... | |
76 | | GPOS all none features... | |
77 | | +--- seq (box) --------------------+ | |
78 | | | seq_label seq_image | | |
79 | | +----------------------------------+ | |
80 | +--------------------------------------+ |
81 +------------------------------------------+ */
83 Widget command_area, quit, dump, *charmap;
84 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
85 Widget glyph_area, glyph[128], index_label[8];
86 Widget render_area, clear, del, bidi, raw, seq;
87 Widget raw_label, raw_image, seq_label, seq_image;
88 unsigned long foreground, background;
90 #define MAX_FEATURE_COUNT 16
95 OTF_GSUB_GPOS *gsub_gpos;
101 } features[MAX_FEATURE_COUNT];
104 FeatureRec gsub, gpos;
111 GC gc, gc_set, gc_or, gc_inv;
115 unsigned width, height;
120 BitmapRec bitmap[0x10000];
122 int render_width, render_height;
123 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
137 unsigned glyph_width, glyph_height;
138 int glyph_x, glyph_y;
151 create_pixmap (int index)
153 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
159 bitmap[index].pixmap = none_pixmap;
162 ximage.height = face->glyph->bitmap.rows;
163 ximage.width = face->glyph->bitmap.width;
165 ximage.bits_per_pixel = 1;
167 ximage.format = XYPixmap;
168 ximage.data = (char *) face->glyph->bitmap.buffer;
169 ximage.byte_order = MSBFirst;
170 ximage.bitmap_unit = 8;
171 ximage.bitmap_bit_order = MSBFirst;
172 ximage.bitmap_pad = 8;
173 ximage.bytes_per_line = face->glyph->bitmap.pitch;
174 XInitImage (&ximage);
175 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
176 glyph_width, glyph_height, 1);
177 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
178 XPutImage (display, pixmap, gc, &ximage, 0, 0,
179 glyph_x + face->glyph->bitmap_left,
180 glyph_y - face->glyph->bitmap_top,
181 ximage.width, ximage.height);
182 bitmap[index].pixmap = pixmap;
183 bitmap[index].width = ximage.width;
184 bitmap[index].height = ximage.height;
185 bitmap[index].x = face->glyph->bitmap_left;
186 bitmap[index].y = - face->glyph->bitmap_top;
187 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
198 for (i = 0; i < 128; i++)
200 int index = glyph_index + i;
202 if (charmap_index >= 0)
203 index = FT_Get_Char_Index (face, (FT_ULong) index);
204 if (! bitmap[index].pixmap)
205 create_pixmap (index);
206 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
207 XtSetValues (glyph[i], arg, 1);
210 msb = (glyph_index >> 7) % 2 ? 8 : 0;
211 for (i = 0; i < 8; i++)
215 sprintf (str, "%XX", i | msb );
216 XtSetArg (arg[0], XtNheight, glyph_height + 5);
217 XtSetArg (arg[1], XtNlabel, str);
218 XtSetValues (index_label[i], arg, 2);
221 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
222 XtSetArg (arg[0], XtNlabel, buf);
223 XtSetValues (range, arg, 1);
227 get_features (OTF_FeatureList *list, FeatureRec *rec)
232 if (! rec->features[0].on)
234 for (i = n = 0; i < rec->langsys->FeatureCount; i++)
236 if (rec->features[i].on)
241 if (i == rec->langsys->FeatureCount)
247 str = malloc (n * 5);
248 for (i = 0, p = str; i < n; i++, p += 5)
250 OTF_tag_name (rec->features[i].tag, p);
258 #define DEVICE_DELTA(table, size) \
259 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
260 ? (table).DeltaValue[(size) >= (table).StartSize] \
264 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
265 OTF_Glyph *g, int *x, int *y)
267 if (anchor->AnchorFormat == 2)
270 int ap = anchor->f.f1.AnchorPoint;
272 FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
273 outline = &ft_face->glyph->outline;
274 if (ap < outline->n_points)
276 *x = outline->points[ap].x;
277 *y = outline->points[ap].y;
280 else if (anchor->AnchorFormat == 3)
282 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
283 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
291 OTF_GlyphString gstring;
292 OTF_Glyph *g, *prev, *base, *mark;
294 int len = glyph_rec.n_glyphs;
296 int unitsPerEm = face->units_per_EM;
298 gstring.size = gstring.used = len;
299 gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
300 memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
301 for (i = 0; i < len; i++)
302 gstring.glyphs[i].c = gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
304 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
305 XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
310 OTF_drive_gdef (otf, &gstring);
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;
353 for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
354 i < gstring.used; i++, prev = g++)
356 BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
357 int xoff = 0, yoff = 0;
359 int advance = bmp->advance;
363 create_pixmap (gstring.glyphs[i].glyph_id);
367 switch (g->positioning_type)
374 int format = g->f.f1.format;
376 if (format & OTF_XPlacement)
377 xoff = g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
378 if (format & OTF_XPlaDevice)
379 xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
380 if (format & OTF_YPlacement)
381 yoff = g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
382 if (format & OTF_YPlaDevice)
383 yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
384 if (format & OTF_XAdvance)
385 advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
386 if (format & OTF_XAdvDevice)
387 advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice, pixel_size);
392 /* Not yet supported. */
398 prev_width = base_width;
399 goto label_adjust_anchor;
400 default: /* i.e. case 6 */
407 int base_x, base_y, mark_x, mark_y;
409 base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
410 base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
411 mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
412 mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
414 if (g->f.f4.base_anchor->AnchorFormat != 1)
415 adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
416 if (g->f.f4.mark_anchor->AnchorFormat != 1)
417 adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
418 xoff = (base_x - prev_width) - mark_x;
419 yoff = base_y - mark_y;
423 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
424 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
425 x + bmp->x + xoff, glyph_y + bmp->y - yoff);
428 if (g->GlyphClass == OTF_GlyphClass0)
429 base = mark = g, base_width = advance;
430 else if (g->GlyphClass == OTF_GlyphClassMark)
433 base = g, base_width = advance;
435 free (gstring.glyphs);
437 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
438 XtSetValues (seq_image, arg, 1);
443 update_render_area ()
449 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
450 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
452 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
455 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
456 0, 0, glyph_width, glyph_height,
457 (glyph_width + 4) * i + 1, 1);
458 XDrawRectangle (display, raw_pixmap, gc_set,
459 (glyph_width + 4) * i, 0,
460 glyph_width + 1, glyph_height + 1);
461 XDrawLine (display, raw_pixmap, gc_set,
462 (glyph_width + 4) * i + 1 + glyph_x, 1,
463 (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
464 XDrawLine (display, raw_pixmap, gc_set,
465 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
466 (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
469 sprintf (buf, "%04X", glyph_rec.codes[i]);
470 XDrawString (display, raw_pixmap, gc_inv,
471 (glyph_width + 1) * i + 1
472 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
473 glyph_height + 2 + FONT_HEIGHT, buf, 4);
475 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
476 XtSetValues (raw_image, arg, 1);
481 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
483 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
487 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
489 int g_width, g_height, g_x, g_y, pix_width, pix_height;
490 int margin = 20 * 300 / 25.4;
491 int a4_width = 210 * 300 / 25.4 - margin * 2;
492 int a4_height = 297 * 300 / 25.4 - margin * 2;
495 XImage ximage, *image;
500 FT_Set_Pixel_Sizes (face, 0, size);
501 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
502 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
503 pix_width = (g_width + 1) * 16 + margin + 1;
504 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
505 while (pix_width > a4_width || pix_height > a4_height)
508 FT_Set_Pixel_Sizes (face, 0, size);
509 g_width = ((face->bbox.xMax - face->bbox.xMin)
510 * size / face->units_per_EM);
511 g_height = ((face->bbox.yMax - face->bbox.yMin)
512 * size / face->units_per_EM);
513 pix_width = (g_width + 1) * 16 + margin + 1;
514 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
517 g_x = - (face->bbox.xMin * size / face->units_per_EM);
518 g_y = face->bbox.yMax * size / face->units_per_EM;
519 for (i = 0; i < 0xFF; i++)
523 if (charmap_index >= 0)
524 idx = FT_Get_Char_Index (face, (FT_ULong) i);
527 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
529 if (g_x < - face->glyph->bitmap_left)
530 g_x = - face->glyph->bitmap_left;
531 if (g_y < face->glyph->bitmap_top)
532 g_y = face->glyph->bitmap_top;
534 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
536 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
538 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
540 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
543 pix_width = (g_width + 1) * 16 + margin + 1;
544 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
545 pixmap = XCreatePixmap (display,
546 RootWindow (display, DefaultScreen (display)),
547 pix_width, pix_height, 1);
548 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
550 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
551 XDrawLine (display, pixmap, gc_set, x, margin,
552 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
553 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
554 XDrawLine (display, pixmap, gc_set, margin, y,
555 margin + (g_width + 1) * 16, y);
556 for (i = 0; i < 256; i++)
561 if (charmap_index >= 0)
562 idx = FT_Get_Char_Index (face, (FT_ULong) i);
565 x = margin + (g_width + 1) * (i % 16);
566 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
567 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
569 ximage.height = face->glyph->bitmap.rows;
570 ximage.width = face->glyph->bitmap.width;
572 ximage.bits_per_pixel = 1;
574 ximage.format = XYPixmap;
575 ximage.data = (char *) face->glyph->bitmap.buffer;
576 ximage.byte_order = MSBFirst;
577 ximage.bitmap_unit = 8;
578 ximage.bitmap_bit_order = MSBFirst;
579 ximage.bitmap_pad = 8;
580 ximage.bytes_per_line = face->glyph->bitmap.pitch;
581 XInitImage (&ximage);
582 XPutImage (display, pixmap, gc, &ximage, 0, 0,
583 x + g_x + face->glyph->bitmap_left,
584 y + g_y - face->glyph->bitmap_top,
585 ximage.width, ximage.height);
587 sprintf (str, "0x%02X", i);
588 XDrawString (display, pixmap, gc_inv,
589 x + (g_width - XTextWidth (font, str, 4))/ 2,
590 y + g_height + FONT_ASCENT, str, 4);
593 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
594 AllPlanes, XYPixmap);
597 char *name = alloca (strlen (filename) + 5);
600 sprintf (name, "%s.pbm", filename);
601 printf ("Writing %s ...", name);
602 fp = fopen (name, "w");
603 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
604 bytes_per_line = (image->width + 7) / 8;
606 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
607 fwrite (data, 1, bytes_per_line, fp);
611 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
616 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
618 int old_glyph_index = glyph_index;
620 if ((int) client_data == -3 && glyph_index > 0)
622 else if ((int) client_data == -2 && glyph_index > 0)
623 glyph_index = (glyph_index - 1) & 0xF000;
624 else if ((int) client_data == -1 && glyph_index > 0)
626 else if ((int) client_data == 1 && glyph_index < 0xFF80)
628 else if ((int) client_data == 2 && glyph_index < 0xF000)
629 glyph_index = (glyph_index + 0x1000) & 0xF000;
630 else if ((int) client_data == 3 && glyph_index < 0xF000)
631 glyph_index = 0xFF80;
632 if (glyph_index != old_glyph_index)
633 update_glyph_area ();
637 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
639 if (charmap_index == (int) client_data)
641 charmap_index = (int) client_data;
642 if (charmap_index >= 0)
643 FT_Set_Charmap (face, face->charmaps[charmap_index]);
644 update_glyph_area ();
648 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
650 if ((int) client_data < 0)
652 if (glyph_rec.n_glyphs > 0)
654 if ((int) client_data == -2)
655 glyph_rec.n_glyphs--;
657 glyph_rec.n_glyphs = 0;
658 update_render_area ();
661 else if (glyph_rec.n_glyphs < 64)
663 int index = glyph_index + (int) client_data;
665 if (charmap_index >= 0)
666 index = FT_Get_Char_Index (face, (FT_ULong) index);
667 if (bitmap[index].pixmap)
669 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
670 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
671 update_render_area ();
677 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
681 reversed = ! reversed;
683 XtSetArg (arg[0], XtNlabel, "L<-R");
685 XtSetArg (arg[0], XtNlabel, "L->R");
686 XtSetValues (w, arg, 1);
691 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
693 FeatureRec *rec = (FeatureRec *) client_data;
700 XtSetArg (arg[0], XtNlabel, &label);
701 XtGetValues (w, arg, 1);
702 if (! strcmp (label, "all"))
704 else if (! strcmp (label, "none"))
708 for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
709 if (rec->features[idx].w == w)
711 if (idx == rec->langsys->FeatureCount)
718 for (i = j = 0; j < rec->langsys->FeatureCount; j++)
720 int index = rec->langsys->FeatureIndex[j];
723 = rec->gsub_gpos->FeatureList.Feature[index].FeatureTag;
724 rec->features[j].on = on;
729 OTF_Tag tag = rec->features[idx].tag;
732 if (rec->features[i].on)
735 j < rec->langsys->FeatureCount && rec->features[j].on; j++)
736 rec->features[j - 1].tag = rec->features[j].tag;
737 rec->features[j - 1].tag = tag;
738 rec->features[j - 1].on = 0;
742 for (j = i + 1; i > 0 && ! rec->features[i - 1].on; i--)
743 rec->features[i].tag = rec->features[i - 1].tag;
744 rec->features[i].tag = tag;
745 rec->features[i].on = 1;
753 if (rec->features[i].on)
755 XtSetArg (arg[0], XtNborderWidth, 3);
756 XtSetArg (arg[1], XtNinternalHeight, 2);
757 XtSetArg (arg[2], XtNinternalWidth, 2);
761 XtSetArg (arg[0], XtNborderWidth, 1);
762 XtSetArg (arg[1], XtNinternalHeight, 4);
763 XtSetArg (arg[2], XtNinternalWidth, 4);
765 OTF_tag_name (rec->features[i].tag, str);
766 XtSetArg (arg[3], XtNlabel, str);
767 XtSetValues (rec->features[i].w, arg, 4);
773 setup_feature_rec (FeatureRec *rec)
779 for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
780 if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
782 rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
790 XtSetArg (arg[0], XtNborderWidth, 1);
791 XtSetArg (arg[1], XtNinternalHeight, 4);
792 XtSetArg (arg[2], XtNinternalWidth, 4);
793 XtSetArg (arg[3], XtNborderColor, foreground);
794 XtSetArg (arg[4], XtNsensitive, True);
795 for (i = 0; i < rec->langsys->FeatureCount && i < MAX_FEATURE_COUNT; i++)
797 OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
798 int index = rec->langsys->FeatureIndex[i];
801 rec->features[i].tag = feature[index].FeatureTag;
802 rec->features[i].on = 0;
803 OTF_tag_name (rec->features[i].tag, label);
804 XtSetArg (arg[5], XtNlabel, label);
805 XtSetValues (rec->features[i].w, arg, 6);
808 XtSetArg (arg[0], XtNborderColor, background);
809 XtSetArg (arg[1], XtNsensitive, False);
810 XtSetArg (arg[2], XtNlabel, " ");
811 for (; i < MAX_FEATURE_COUNT; i++)
812 XtSetValues (rec->features[i].w, arg, 3);
816 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
818 if (script_tag == (OTF_Tag) client_data)
820 script_tag = (OTF_Tag) client_data;
821 setup_feature_rec (&gsub);
822 setup_feature_rec (&gpos);
827 create_otf_script_widgets (Widget prev)
835 XtSetArg (arg[0], XtNborderWidth, 0);
836 XtSetArg (arg[1], XtNleft, XawChainLeft);
837 XtSetArg (arg[2], XtNright, XawChainLeft);
838 XtSetArg (arg[3], XtNtop, XawChainTop);
839 XtSetArg (arg[4], XtNbottom, XawChainTop);
840 XtSetArg (arg[5], XtNfromVert, prev);
841 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
842 prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
843 XtCreateManagedWidget ("script", labelWidgetClass, prev, arg, 1);
847 n = otf->gsub->ScriptList.ScriptCount;
849 n += otf->gpos->ScriptList.ScriptCount;
850 scripts = alloca (sizeof (OTF_Tag) * n);
853 for (; i < otf->gsub->ScriptList.ScriptCount; i++)
854 scripts[i] = otf->gsub->ScriptList.Script[i].ScriptTag;
857 for (; i < otf->gpos->ScriptList.ScriptCount; i++)
859 OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
862 for (j = 0; j < i; j++)
863 if (tag == scripts[j])
872 script_tag = scripts[0];
873 OTF_tag_name (scripts[0], script_name);
876 XtSetArg (arg[0], XtNforeground, background);
877 XtSetArg (arg[1], XtNbackground, foreground);
878 XtCreateManagedWidget (script_name, labelWidgetClass, prev, arg, 2);
884 XtSetArg (arg[0], XtNstate, True);
885 w = XtCreateManagedWidget (script_name, toggleWidgetClass, prev, arg, 1);
886 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[0]);
887 XtSetArg (arg[0], XtNradioGroup, w);
888 for (i = 1; i < n; i++)
890 OTF_tag_name (scripts[i], name);
891 w = XtCreateManagedWidget (name, toggleWidgetClass, prev, arg, 1);
892 XtAddCallback (w, XtNcallback, ScriptProc, (XtPointer) scripts[i]);
900 create_otf_widgets (Widget prev, FeatureRec *rec)
906 XtSetArg (arg[0], XtNborderWidth, 0);
907 XtSetArg (arg[1], XtNleft, XawChainLeft);
908 XtSetArg (arg[2], XtNright, XawChainLeft);
909 XtSetArg (arg[3], XtNtop, XawChainTop);
910 XtSetArg (arg[4], XtNbottom, XawChainTop);
911 XtSetArg (arg[5], XtNfromVert, prev);
912 XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
913 prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
915 XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
916 XtSetArg (arg[0], XtNborderWidth, 1);
917 XtSetArg (arg[1], XtNinternalHeight, 4);
918 XtSetArg (arg[2], XtNinternalWidth, 4);
919 w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
920 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
921 w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
922 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
924 for (i = 0; i < MAX_FEATURE_COUNT; i++)
926 w = XtCreateManagedWidget ("", commandWidgetClass, prev, arg, 0);
927 XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
928 rec->features[i].w = w;
931 setup_feature_rec (rec);
938 String quit_action = "<KeyPress>q: set() notify() unset()";
939 String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
940 <KeyPress>Home: set() notify() unset()";
941 String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
942 <KeyPress>Up: set() notify() unset()";
943 String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
944 <KeyPress>Left: set() notify() unset()";
945 String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
946 <KeyPress>Right: set() notify() unset()";
947 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
948 <KeyPress>Down: set() notify() unset()";
949 String LAST_action = "<KeyPress>l: set() notify() unset()\n\
950 <KeyPress>End: set() notify() unset()";
954 String trans = "<Expose>: Expose()";
956 XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
957 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
959 XtSetArg (arg[0], XtNleft, XawChainLeft);
960 XtSetArg (arg[1], XtNright, XawChainLeft);
961 XtSetArg (arg[2], XtNtop, XawChainTop);
962 XtSetArg (arg[3], XtNbottom, XawChainTop);
963 XtSetArg (arg[4], XtNborderWidth, 0);
964 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
965 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
967 XtSetArg (arg[6], XtNfromVert, command_area);
968 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
970 XtSetArg (arg[4], XtNborderWidth, 0);
971 XtSetArg (arg[5], XtNfromVert, navi_area);
972 XtSetArg (arg[6], XtNdefaultDistance, 0);
973 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
975 XtSetArg (arg[5], XtNfromVert, glyph_area);
976 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
979 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
980 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
981 command_area, arg, 1);
982 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
984 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
985 command_area, arg, 1);
986 XtAddCallback (dump, XtNcallback, DumpProc, NULL);
988 XtSetArg (arg[0], XtNborderWidth, 0);
989 XtSetArg (arg[1], XtNwidth, 10);
990 XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
992 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
993 XtSetArg (arg[0], XtNstate, True);
994 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
995 command_area, arg, 1);
996 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
997 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
998 for (i = 0; i < face->num_charmaps; i++)
1000 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1002 command_area, arg, 1);
1003 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
1006 XtSetArg (arg[0], XtNlabel, " |< (f)");
1007 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1008 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1010 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1011 XtSetArg (arg[0], XtNlabel, "<< (P)");
1012 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1013 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1015 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1016 XtSetArg (arg[0], XtNlabel, "< (p)");
1017 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1018 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1020 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1021 XtSetArg (arg[0], XtNlabel, " 0000 ");
1022 range = XtCreateManagedWidget ("range", labelWidgetClass,
1024 XtSetArg (arg[0], XtNforeground, &foreground);
1025 XtSetArg (arg[1], XtNbackground, &background);
1026 XtGetValues (range, arg, 2);
1028 XtSetArg (arg[0], XtNlabel, "> (n)");
1029 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1030 next = XtCreateManagedWidget ("next", commandWidgetClass,
1032 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1033 XtSetArg (arg[0], XtNlabel, ">> (N)");
1034 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1035 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1037 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1038 XtSetArg (arg[0], XtNlabel, ">| (l)");
1039 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1040 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1042 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1044 XtSetArg (arg[0], XtNleft, XawChainLeft);
1045 XtSetArg (arg[1], XtNright, XawChainLeft);
1046 XtSetArg (arg[2], XtNtop, XawChainTop);
1047 XtSetArg (arg[3], XtNbottom, XawChainTop);
1049 for (i = 0; i < 8; i++)
1055 sprintf (str, "%XX", i);
1056 XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1057 XtSetArg (arg[n], XtNlabel, str), n++;
1058 XtSetArg (arg[n], XtNborderWidth, 0), n++;
1060 XtSetArg (arg[n], XtNfromVert, w), n++;
1061 head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1062 index_label[i] = head;
1063 for (j = 0; j < 16; j++)
1069 XtSetArg (arg[n], XtNfromVert, w), n++;
1071 XtSetArg (arg[n], XtNfromHoriz, head), n++;
1073 XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1074 XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1075 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1076 glyph_area, arg, n);
1077 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
1081 /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1082 XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1083 XtSetArg (arg[5], XtNfromVert, glyph[112]);
1084 XtSetArg (arg[6], XtNfromHoriz, w);
1085 XtSetArg (arg[7], XtNborderWidth, 0);
1087 for (j = 0; j < 16; j++)
1091 sprintf (str, "X%X", j);
1092 XtSetArg (arg[8], XtNlabel, str);
1093 w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1094 XtSetArg (arg[6], XtNfromHoriz, w);
1097 XtSetArg (arg[0], XtNleft, XawChainLeft);
1098 XtSetArg (arg[1], XtNright, XawChainLeft);
1099 XtSetArg (arg[2], XtNtop, XawChainTop);
1100 XtSetArg (arg[3], XtNbottom, XawChainTop);
1101 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1102 XtSetArg (arg[5], XtNborderWidth, 0);
1103 w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1104 clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1105 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1106 del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1107 XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1108 bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1109 XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1111 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1112 XtSetArg (arg[5], XtNborderWidth, 0);
1113 XtSetArg (arg[6], XtNfromVert, w);
1114 raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1116 XtSetArg (arg[0], XtNborderWidth, 0);
1117 XtSetArg (arg[1], XtNlabel, "raw: ");
1118 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1120 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1121 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1126 OTF_get_table (otf, "GSUB");
1127 OTF_get_table (otf, "GPOS");
1128 w = create_otf_script_widgets (w);
1131 gsub.label = "GSUB";
1132 gsub.gsub_gpos = otf->gsub;
1133 w = create_otf_widgets (w, &gsub);
1137 gpos.label = "GPOS";
1138 gpos.gsub_gpos = otf->gpos;
1139 w = create_otf_widgets (w, &gpos);
1143 XtSetArg (arg[6], XtNfromVert, w);
1144 seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1145 XtSetArg (arg[0], XtNborderWidth, 0);
1146 XtSetArg (arg[1], XtNlabel, "seq: ");
1147 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1149 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1150 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1152 XtInstallAllAccelerators (shell, shell);
1156 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1158 XTextProperty text_prop;
1159 char *pname = "otfview";
1160 char *fname = basename (filename);
1161 char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1163 sprintf (name, "%s - %s", pname, fname);
1164 text_prop.value = (unsigned char *) name;
1165 text_prop.encoding = XA_STRING;
1166 text_prop.format = 8;
1167 text_prop.nitems = strlen (name);
1168 XSetWMName (display, XtWindow (shell), &text_prop);
1171 /* Format MSG by FMT and print the result to the stderr, and exit. */
1173 #define FATAL_ERROR(fmt, arg) \
1175 fprintf (stderr, fmt, arg); \
1180 x_error_handler (Display *display, XErrorEvent *error)
1187 main (int argc, char **argv)
1189 XtActionsRec actions[] = { {"Expose", ExposeProc} };
1193 OTF_GlyphString gstring;
1198 int fixed_pixel_size = 0;
1201 pixel_size = DEFAULT_PIXEL_SIZE;
1203 char *str = getenv ("PIXEL_SIZE");
1205 if (str && (i = atoi (str)) > 0)
1208 fixed_pixel_size = 1;
1212 gstring.size = gstring.used = 256;
1213 g = calloc (256, sizeof (OTF_Glyph));
1216 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1217 shellWidgetClass, arg, 0);
1218 display = XtDisplay (shell);
1219 /*XSynchronize (display, True);*/
1220 XSetErrorHandler (x_error_handler);
1221 display_width = DisplayWidth (display,
1222 XScreenNumberOfScreen (XtScreen (shell)));
1223 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1225 font = XLoadQueryFont (display, "fixed");
1227 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1229 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
1230 basename (argv[0]));
1232 " Pixel size is decided by the environment variable PIXEL_SIZE ((default %d).\n", DEFAULT_PIXEL_SIZE);
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);