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/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
46 #define DEFAULT_FONT_NAME "6x13"
48 #define FONT_HEIGHT (font->ascent + font->descent)
49 #define FONT_ASCENT (font->ascent)
50 #define FONT_DESCENT (font->descent)
51 #define FONT_WIDTH (font->max_bounds.width)
55 +--- frame (form) -------------------------+
56 | +--- command_area (box) ---------------+ |
57 | | quit dump charmap ... | |
58 | +--------------------------------------+ |
59 | +---- navi_area (box) -----------------+ |
60 | | FIRST PREV prev label next NEXT LAST | |
61 | +--------------------------------------+ |
62 | +--- glyph_area (form) ----------------+ |
63 | | glyph[0] ... glyph[15] | |
65 | | glyph[112] ... glyph[127]| |
66 | +--------------------------------------+ |
67 | +--- render_area (form) ---------------+ |
69 | | +--- raw (box) --------------------+ | |
70 | | | raw_label raw_image | | |
71 | | +--- seq (box) --------------------+ | |
72 | | | seq_label seq_image | | |
73 | | +--- gsub (box) -------------------+ | |
74 | | | gsub_label gsub_image | | |
75 | | +--- gpos (box) -------------------+ | |
76 | | | gpos_label gpos_image | | |
77 | | +----------------------------------+ | |
78 | +--------------------------------------+ |
79 +------------------------------------------+ */
81 Widget command_area, quit, dump, *charmap;
82 Widget navi_area, FIRST, PREV, prev, label, next, NEXT, LAST;
83 Widget glyph_area, glyph[128];
84 Widget render_area, clear, raw, seq, gsub, gpos;
85 Widget raw_label, raw_image, seq_label, seq_image;
86 Widget gsub_label, gsub_image, gpos_label, gpos_image;
91 GC gc, gc_set, gc_or, gc_inv;
95 unsigned width, height;
100 BitmapRec bitmap[0x10000];
102 int render_width, render_height;
103 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
116 unsigned glyph_width, glyph_height;
117 int glyph_x, glyph_y;
130 create_pixmap (int pixel_size, int index)
132 int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
135 int height = glyph_height + 1 + FONT_HEIGHT;
140 bitmap[index].pixmap = (Pixmap) 0;
143 ximage.height = face->glyph->bitmap.rows;
144 ximage.width = face->glyph->bitmap.width;
146 ximage.bits_per_pixel = 1;
148 ximage.format = XYPixmap;
149 ximage.data = (char *) face->glyph->bitmap.buffer;
150 ximage.byte_order = MSBFirst;
151 ximage.bitmap_unit = 8;
152 ximage.bitmap_bit_order = MSBFirst;
153 ximage.bitmap_pad = 8;
154 ximage.bytes_per_line = face->glyph->bitmap.pitch;
155 XInitImage (&ximage);
156 pixmap = XCreatePixmap (display, DefaultRootWindow (display),
157 glyph_width, height, 1);
158 XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, height);
159 XPutImage (display, pixmap, gc, &ximage, 0, 0,
160 glyph_x + face->glyph->bitmap_left,
161 glyph_y - face->glyph->bitmap_top,
162 ximage.width, ximage.height);
163 sprintf (index_buf, "%04X", index);
164 XDrawLine (display, pixmap, gc_inv,
165 0, glyph_height + 1, glyph_width, glyph_height + 1);
166 XDrawString (display, pixmap, gc_inv,
167 (glyph_width - XTextWidth (font, index_buf, 4)) / 2,
168 height - FONT_DESCENT, index_buf, 4);
169 bitmap[index].pixmap = pixmap;
170 bitmap[index].width = ximage.width;
171 bitmap[index].height = ximage.height;
172 bitmap[index].x = face->glyph->bitmap_left;
173 bitmap[index].y = - face->glyph->bitmap_top;
174 bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
184 for (i = 0; i < 128; i++)
186 int index = glyph_index + i;
188 if (charmap_index >= 0)
189 index = FT_Get_Char_Index (face, (FT_ULong) index);
190 if (bitmap[index].pixmap)
191 XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
193 XtSetArg (arg[0], XtNbitmap, none_pixmap);
194 XtSetValues (glyph[i], arg, 1);
197 sprintf (buf, " %04X-%04X ", glyph_index, glyph_index + 0x7F);
198 XtSetArg (arg[0], XtNlabel, buf);
199 XtSetValues (label, arg, 1);
203 update_render_area ()
209 XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
210 XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
211 for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
213 BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
216 XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
217 0, 0, glyph_width, glyph_height,
218 (glyph_width + 1) * i + 1, 1);
219 XDrawRectangle (display, raw_pixmap, gc_set,
220 (glyph_width + 1) * i, 0,
221 glyph_width + 1, glyph_height + 1);
222 XDrawLine (display, raw_pixmap, gc_set,
223 (glyph_width + 1) * i + 1 + glyph_x, 1,
224 (glyph_width + 1) * i + 1 + glyph_x, glyph_height + 1);
225 XDrawLine (display, raw_pixmap, gc_set,
226 (glyph_width + 1) * i + 1 + glyph_x + bmp->advance, 1,
227 (glyph_width + 1) * i + 1 + glyph_x + bmp->advance,
230 sprintf (buf, "%04X", glyph_rec.codes[i]);
231 XDrawString (display, raw_pixmap, gc_inv,
232 (glyph_width + 1) * i + 1
233 + (glyph_width - XTextWidth (font, buf, 4)) / 2,
234 glyph_height + 2 + FONT_HEIGHT, buf, 4);
235 XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
236 glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
237 x + bmp->x, glyph_y + bmp->y);
240 XtSetArg (arg[0], XtNbitmap, raw_pixmap);
241 XtSetValues (raw_image, arg, 1);
242 XtSetArg (arg[0], XtNbitmap, seq_pixmap);
243 XtSetValues (seq_image, arg, 1);
246 XFillRectangle (display, gsub_pixmap, gc, 0, 0, render_width, render_height);
247 XFillRectangle (display, gpos_pixmap, gc, 0, 0, render_width, render_height);
248 XtSetArg (arg[0], XtNbitmap, gsub_pixmap);
249 XtSetValues (gsub_image, arg, 1);
250 XtSetArg (arg[0], XtNbitmap, gpos_pixmap);
251 XtSetValues (gpos_image, arg, 1);
255 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
257 XtAppSetExitFlag (XtWidgetToApplicationContext (w));
261 DumpProc (Widget w, XtPointer client_data, XtPointer pixel_size)
263 int g_width, g_height, g_x, g_y, pix_width, pix_height;
264 int margin = 20 * 300 / 25.4;
265 int a4_width = 210 * 300 / 25.4 - margin * 2;
266 int a4_height = 297 * 300 / 25.4 - margin * 2;
269 XImage ximage, *image;
274 FT_Set_Pixel_Sizes (face, 0, size);
275 g_width = ((face->bbox.xMax - face->bbox.xMin) * size / face->units_per_EM);
276 g_height = ((face->bbox.yMax - face->bbox.yMin) * size / face->units_per_EM);
277 pix_width = (g_width + 1) * 16 + margin + 1;
278 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
279 while (pix_width > a4_width || pix_height > a4_height)
282 FT_Set_Pixel_Sizes (face, 0, size);
283 g_width = ((face->bbox.xMax - face->bbox.xMin)
284 * size / face->units_per_EM);
285 g_height = ((face->bbox.yMax - face->bbox.yMin)
286 * size / face->units_per_EM);
287 pix_width = (g_width + 1) * 16 + margin + 1;
288 pix_height = (g_height + 1 + FONT_HEIGHT) * 16 + margin + 1;
291 g_x = - (face->bbox.xMin * size / face->units_per_EM);
292 g_y = face->bbox.yMax * size / face->units_per_EM;
293 for (i = 0; i < 0xFF; i++)
297 if (charmap_index >= 0)
298 idx = FT_Get_Char_Index (face, (FT_ULong) i);
301 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
303 if (g_x < - face->glyph->bitmap_left)
304 g_x = - face->glyph->bitmap_left;
305 if (g_y < face->glyph->bitmap_top)
306 g_y = face->glyph->bitmap_top;
308 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
310 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
312 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
314 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
317 pix_width = (g_width + 1) * 16 + margin + 1;
318 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
319 pixmap = XCreatePixmap (display,
320 RootWindow (display, DefaultScreen (display)),
321 pix_width, pix_height, 1);
322 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
324 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
325 XDrawLine (display, pixmap, gc_set, x, margin,
326 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
327 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
328 XDrawLine (display, pixmap, gc_set, margin, y,
329 margin + (g_width + 1) * 16, y);
330 for (i = 0; i < 256; i++)
335 if (charmap_index >= 0)
336 idx = FT_Get_Char_Index (face, (FT_ULong) i);
339 x = margin + (g_width + 1) * (i % 16);
340 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
341 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
343 ximage.height = face->glyph->bitmap.rows;
344 ximage.width = face->glyph->bitmap.width;
346 ximage.bits_per_pixel = 1;
348 ximage.format = XYPixmap;
349 ximage.data = (char *) face->glyph->bitmap.buffer;
350 ximage.byte_order = MSBFirst;
351 ximage.bitmap_unit = 8;
352 ximage.bitmap_bit_order = MSBFirst;
353 ximage.bitmap_pad = 8;
354 ximage.bytes_per_line = face->glyph->bitmap.pitch;
355 XInitImage (&ximage);
356 XPutImage (display, pixmap, gc, &ximage, 0, 0,
357 x + g_x + face->glyph->bitmap_left,
358 y + g_y - face->glyph->bitmap_top,
359 ximage.width, ximage.height);
361 sprintf (str, "0x%02X", i);
362 XDrawString (display, pixmap, gc_inv,
363 x + (g_width - XTextWidth (font, str, 4))/ 2,
364 y + g_height + FONT_ASCENT, str, 4);
367 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
368 AllPlanes, XYPixmap);
371 char *name = alloca (strlen (filename) + 5);
374 sprintf (name, "%s.pbm", filename);
375 printf ("Writing %s ...", name);
376 fp = fopen (name, "w");
377 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
378 bytes_per_line = (image->width + 7) / 8;
380 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
381 fwrite (data, 1, bytes_per_line, fp);
385 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
390 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
392 int old_glyph_index = glyph_index;
394 if ((int) client_data == -3 && glyph_index > 0)
396 else if ((int) client_data == -2 && glyph_index > 0)
397 glyph_index = (glyph_index - 1) & 0xF000;
398 else if ((int) client_data == -1 && glyph_index > 0)
400 else if ((int) client_data == 1 && glyph_index < 0xFF80)
402 else if ((int) client_data == 2 && glyph_index < 0xF000)
403 glyph_index = (glyph_index + 0x1000) & 0xF000;
404 else if ((int) client_data == 3 && glyph_index < 0xF000)
405 glyph_index = 0xFF80;
406 if (glyph_index != old_glyph_index)
407 update_glyph_area ();
411 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
413 if (charmap_index == (int) client_data)
415 charmap_index = (int) client_data;
416 if (charmap_index >= 0)
417 FT_Set_Charmap (face, face->charmaps[charmap_index]);
418 update_glyph_area ();
422 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
424 if ((int) client_data < 0)
426 glyph_rec.n_glyphs = 0;
427 update_render_area ();
429 else if (glyph_rec.n_glyphs < 64)
431 int index = glyph_index + (int) client_data;
433 if (charmap_index >= 0)
434 index = FT_Get_Char_Index (face, (FT_ULong) index);
435 if (bitmap[index].pixmap)
437 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
438 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
439 update_render_area ();
445 create_widgets (int pixel_size)
447 String quit_action = "<KeyPress>q: set() notify() unset()";
448 String FIRST_action = "~Shift<KeyPress>f: set() notify() unset()";
449 String PREV_action = "Shift<KeyPress>p: set() notify() unset()";
450 String prev_action = "~Shift<KeyPress>p: set() notify() unset()";
451 String next_action = "~Shift<KeyPress>n: set() notify() unset()";
452 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()";
453 String LAST_action = "~Shift<KeyPress>l: set() notify() unset()";
456 int glyph_widget_height;
458 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, NULL, 0);
459 XtSetArg (arg[0], XtNleft, XawChainLeft);
460 XtSetArg (arg[1], XtNright, XawChainLeft);
461 XtSetArg (arg[2], XtNtop, XawChainTop);
462 XtSetArg (arg[3], XtNbottom, XawChainTop);
463 XtSetArg (arg[4], XtNborderWidth, 0);
464 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
465 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
467 XtSetArg (arg[6], XtNfromVert, command_area);
468 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
470 XtSetArg (arg[4], XtNborderWidth, 1);
471 XtSetArg (arg[5], XtNfromVert, navi_area);
472 XtSetArg (arg[6], XtNdefaultDistance, 0);
473 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
475 XtSetArg (arg[4], XtNborderWidth, 0);
476 XtSetArg (arg[5], XtNfromVert, glyph_area);
477 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
480 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
481 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
482 command_area, arg, 1);
483 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
485 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
486 command_area, arg, 1);
487 XtAddCallback (dump, XtNcallback, DumpProc, (XtPointer) pixel_size);
489 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
490 XtSetArg (arg[0], XtNstate, True);
491 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
492 command_area, arg, 1);
493 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
494 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
495 for (i = 0; i < face->num_charmaps; i++)
497 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
499 command_area, arg, 1);
500 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
503 XtSetArg (arg[0], XtNlabel, " |< (f)");
504 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
505 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
507 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
508 XtSetArg (arg[0], XtNlabel, "<< (P)");
509 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
510 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
512 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
513 XtSetArg (arg[0], XtNlabel, "< (p)");
514 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
515 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
517 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
518 XtSetArg (arg[0], XtNlabel, " 0000 ");
519 label = XtCreateManagedWidget ("label", labelWidgetClass,
521 XtSetArg (arg[0], XtNlabel, "> (n)");
522 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
523 next = XtCreateManagedWidget ("next", commandWidgetClass,
525 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
526 XtSetArg (arg[0], XtNlabel, ">> (N)");
527 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
528 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
530 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
531 XtSetArg (arg[0], XtNlabel, ">| (l)");
532 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
533 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
535 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
537 glyph_widget_height = glyph_height + 1 + FONT_HEIGHT;
538 XtSetArg (arg[0], XtNleft, XawChainLeft);
539 XtSetArg (arg[1], XtNright, XawChainLeft);
540 XtSetArg (arg[2], XtNtop, XawChainTop);
541 XtSetArg (arg[3], XtNbottom, XawChainTop);
542 for (i = 0; i < 8; i++)
543 for (j = 0; j < 16; j++)
548 XtSetArg (arg[num_args], XtNwidth, glyph_width), num_args++;
549 XtSetArg (arg[num_args], XtNheight, glyph_widget_height), num_args++;
551 XtSetArg (arg[num_args], XtNfromHoriz, glyph[k - 1]), num_args++;
553 XtSetArg (arg[num_args], XtNfromVert, glyph[k - 16]), num_args++;
554 XtSetArg (arg[num_args], XtNinternalWidth, 0), num_args++;
555 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
556 glyph_area, arg, num_args);
557 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
560 XtSetArg (arg[0], XtNleft, XawChainLeft);
561 XtSetArg (arg[1], XtNright, XawChainLeft);
562 XtSetArg (arg[2], XtNtop, XawChainTop);
563 XtSetArg (arg[3], XtNbottom, XawChainTop);
564 clear = XtCreateManagedWidget ("clear", commandWidgetClass,
565 render_area, arg, 4);
566 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
567 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
568 XtSetArg (arg[5], XtNborderWidth, 0);
569 XtSetArg (arg[6], XtNfromVert, clear);
570 raw = XtCreateManagedWidget ("raw", boxWidgetClass,
571 render_area, arg, 7);
572 XtSetArg (arg[0], XtNborderWidth, 0);
573 XtSetArg (arg[1], XtNlabel, "raw: ");
574 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
576 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
577 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
579 XtSetArg (arg[6], XtNfromVert, raw);
580 seq = XtCreateManagedWidget ("seq", boxWidgetClass,
581 render_area, arg, 7);
582 XtSetArg (arg[0], XtNborderWidth, 0);
583 XtSetArg (arg[1], XtNlabel, "seq: ");
584 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
586 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
587 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
591 XtSetArg (arg[6], XtNfromVert, seq);
592 gsub = XtCreateManagedWidget ("gsub", boxWidgetClass,
593 render_area, arg, 7);
594 XtSetArg (arg[0], XtNborderWidth, 0);
595 XtSetArg (arg[1], XtNlabel, "gsub: ");
596 gsub_label = XtCreateManagedWidget ("gsub-label", labelWidgetClass,
598 gsub_image = XtCreateManagedWidget ("gsub-image", labelWidgetClass,
600 XtSetArg (arg[6], XtNfromVert, gsub);
601 gpos = XtCreateManagedWidget ("gpos", boxWidgetClass,
602 render_area, arg, 7);
603 XtSetArg (arg[0], XtNborderWidth, 0);
604 XtSetArg (arg[1], XtNlabel, "gpos: ");
605 gpos_label = XtCreateManagedWidget ("gpos-label", labelWidgetClass,
607 gpos_image = XtCreateManagedWidget ("gpos-image", labelWidgetClass,
611 XtInstallAllAccelerators (shell, shell);
615 /* Format MSG by FMT and print the result to the stderr, and exit. */
617 #define FATAL_ERROR(fmt, arg) \
619 fprintf (stderr, fmt, arg); \
624 main (int argc, char **argv)
628 OTF_GlyphString gstring;
633 int pixel_size = DEFAULT_PIXEL_SIZE;
634 int fixed_pixel_size = 0;
638 char *str = getenv ("PIXEL_SIZE");
640 if (str && (i = atoi (str)) > 0)
643 fixed_pixel_size = 1;
647 gstring.size = gstring.used = 256;
648 g = calloc (256, sizeof (OTF_Glyph));
651 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
652 shellWidgetClass, NULL, 0);
653 display = XtDisplay (shell);
654 display_width = DisplayWidth (display,
655 XScreenNumberOfScreen (XtScreen (shell)));
656 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
658 font = XLoadQueryFont (display, "fixed");
661 FATAL_ERROR ("%s\n", "Usage: otfview [ X-OPTION ... ] OTF-FILE");
664 if (strstr (filename, ".ttf")
665 || strstr (filename, ".TTF")
666 || strstr (filename, ".otf")
667 || strstr (filename, ".OTF"))
669 otf = OTF_open (filename);
671 || OTF_get_table (otf, "head") < 0
672 || OTF_get_table (otf, "cmap") < 0
673 || (OTF_get_table (otf, "gsub") < 0
674 && OTF_get_table (otf, "gpos") < 0))
678 if ((err = FT_Init_FreeType (&library)))
679 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
680 err = FT_New_Face (library, filename, 0, &face);
681 if (err == FT_Err_Unknown_File_Format)
682 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
684 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
685 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
686 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
692 filename = basename (filename);
693 sprintf (title, "%s family:%s style:%s",
694 filename, face->family_name, face->style_name);
695 XtSetArg (arg[0], XtNtitle, title);
696 XtSetValues (shell, arg, 1);
699 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
700 * pixel_size / face->units_per_EM);
701 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
703 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
704 FT_Set_Pixel_Sizes (face, 0, pixel_size);
705 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
706 * pixel_size / face->units_per_EM);
708 if (glyph_width < FONT_WIDTH * 4)
709 glyph_width = FONT_WIDTH * 4;
711 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
712 * pixel_size / face->units_per_EM);
714 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
715 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
717 for (i = 0; i < 0x10000; i++)
718 if (FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
720 if (glyph_x < - face->glyph->bitmap_left)
721 glyph_x = - face->glyph->bitmap_left;
722 if (glyph_y < face->glyph->bitmap_top)
723 glyph_y = face->glyph->bitmap_top;
725 < glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
727 = glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
729 < glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
731 = glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
734 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
735 glyph_width, glyph_height + 1 + FONT_HEIGHT, 1);
738 unsigned long valuemask = GCFunction | GCLineWidth;
741 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
742 values.function = GXset;
743 values.line_width = 1;
744 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
745 values.function = GXor;
746 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
747 values.function = GXcopyInverted;
748 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
751 XFillRectangle (display, none_pixmap, gc, 0, 0,
752 glyph_width, glyph_height + 1 + FONT_HEIGHT);
753 XDrawString (display, none_pixmap, gc_inv,
754 (glyph_width - XTextWidth (font, "none", 4)) / 2,
755 glyph_height / 2, "none", 4);
757 render_width = (glyph_width + 1) * 15 + 1;
758 render_height = glyph_height + FONT_HEIGHT + 2;
760 charmap_rec[0].platform_id = -1;
761 charmap_rec[0].encoding_id = -1;
762 strcpy (charmap_rec[0].name, "no charmap");
764 for (i = 0; i < face->num_charmaps; i++)
766 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
767 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
768 sprintf (charmap_rec[i + 1].name, "%d-%d",
769 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
770 if (face->charmaps[i]->platform_id == 0
771 || (face->charmaps[i]->platform_id == 3
772 && face->charmaps[i]->encoding_id == 1))
773 strcat (charmap_rec[i + 1].name, " (unicode)");
774 else if (face->charmaps[i]->platform_id == 1
775 && face->charmaps[i]->encoding_id == 0)
776 strcat (charmap_rec[i + 1].name, " (apple-roman)");
779 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
780 render_width, render_height, 1);
781 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
782 render_width, render_height, 1);
783 gsub_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
784 render_width, render_height, 1);
785 gpos_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
786 render_width, render_height, 1);
788 for (i = 0; i < 0x10000; i++)
789 create_pixmap (pixel_size, i);
790 create_widgets (pixel_size);
793 update_glyph_area ();
794 update_render_area ();
796 XtRealizeWidget (shell);
797 XtAppMainLoop (context);