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");
660 if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
662 fprintf (stderr, "Usage: %s [ X-OPTION ... ] OTF-FILE\n",
667 if (strstr (filename, ".ttf")
668 || strstr (filename, ".TTF")
669 || strstr (filename, ".otf")
670 || strstr (filename, ".OTF"))
672 otf = OTF_open (filename);
674 || OTF_get_table (otf, "head") < 0
675 || OTF_get_table (otf, "cmap") < 0
676 || (OTF_get_table (otf, "gsub") < 0
677 && OTF_get_table (otf, "gpos") < 0))
681 if ((err = FT_Init_FreeType (&library)))
682 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
683 err = FT_New_Face (library, filename, 0, &face);
684 if (err == FT_Err_Unknown_File_Format)
685 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
687 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
688 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
689 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
695 filename = basename (filename);
696 sprintf (title, "%s family:%s style:%s",
697 filename, face->family_name, face->style_name);
698 XtSetArg (arg[0], XtNtitle, title);
699 XtSetValues (shell, arg, 1);
702 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
703 * pixel_size / face->units_per_EM);
704 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
706 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
707 FT_Set_Pixel_Sizes (face, 0, pixel_size);
708 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
709 * pixel_size / face->units_per_EM);
711 if (glyph_width < FONT_WIDTH * 4)
712 glyph_width = FONT_WIDTH * 4;
714 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
715 * pixel_size / face->units_per_EM);
717 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
718 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
720 for (i = 0; i < 0x10000; i++)
721 if (FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
723 if (glyph_x < - face->glyph->bitmap_left)
724 glyph_x = - face->glyph->bitmap_left;
725 if (glyph_y < face->glyph->bitmap_top)
726 glyph_y = face->glyph->bitmap_top;
728 < glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
730 = glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
732 < glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
734 = glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
737 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
738 glyph_width, glyph_height + 1 + FONT_HEIGHT, 1);
741 unsigned long valuemask = GCFunction | GCLineWidth;
744 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
745 values.function = GXset;
746 values.line_width = 1;
747 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
748 values.function = GXor;
749 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
750 values.function = GXcopyInverted;
751 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
754 XFillRectangle (display, none_pixmap, gc, 0, 0,
755 glyph_width, glyph_height + 1 + FONT_HEIGHT);
756 XDrawString (display, none_pixmap, gc_inv,
757 (glyph_width - XTextWidth (font, "none", 4)) / 2,
758 glyph_height / 2, "none", 4);
760 render_width = (glyph_width + 1) * 15 + 1;
761 render_height = glyph_height + FONT_HEIGHT + 2;
763 charmap_rec[0].platform_id = -1;
764 charmap_rec[0].encoding_id = -1;
765 strcpy (charmap_rec[0].name, "no charmap");
767 for (i = 0; i < face->num_charmaps; i++)
769 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
770 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
771 sprintf (charmap_rec[i + 1].name, "%d-%d",
772 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
773 if (face->charmaps[i]->platform_id == 0
774 || (face->charmaps[i]->platform_id == 3
775 && face->charmaps[i]->encoding_id == 1))
776 strcat (charmap_rec[i + 1].name, " (unicode)");
777 else if (face->charmaps[i]->platform_id == 1
778 && face->charmaps[i]->encoding_id == 0)
779 strcat (charmap_rec[i + 1].name, " (apple-roman)");
782 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
783 render_width, render_height, 1);
784 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
785 render_width, render_height, 1);
786 gsub_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
787 render_width, render_height, 1);
788 gpos_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
789 render_width, render_height, 1);
791 for (i = 0; i < 0x10000; i++)
792 create_pixmap (pixel_size, i);
793 create_widgets (pixel_size);
796 update_glyph_area ();
797 update_render_area ();
799 XtRealizeWidget (shell);
800 XtAppMainLoop (context);