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 < 0x10000; i++)
294 if (FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
296 if (g_x < - face->glyph->bitmap_left)
297 g_x = - face->glyph->bitmap_left;
298 if (g_y < face->glyph->bitmap_top)
299 g_y = face->glyph->bitmap_top;
301 < g_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
303 = g_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
305 < g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
307 = g_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
309 pix_width = (g_width + 1) * 16 + margin + 1;
310 pix_height = (g_height + FONT_HEIGHT + 1) * 16 + margin + 1;
311 pixmap = XCreatePixmap (display,
312 RootWindow (display, DefaultScreen (display)),
313 pix_width, pix_height, 1);
314 XFillRectangle (display, pixmap, gc, 0, 0, pix_width, pix_height);
316 for (i = 0, x = margin; i <= 16; i++, x += g_width + 1)
317 XDrawLine (display, pixmap, gc_set, x, margin,
318 x, margin + (g_height + FONT_HEIGHT + 1) * 16);
319 for (i = 0, y = margin; i <= 16; i++, y += g_height + FONT_HEIGHT + 1)
320 XDrawLine (display, pixmap, gc_set, margin, y,
321 margin + (g_width + 1) * 16, y);
322 for (i = 0; i < 256; i++)
327 if (charmap_index >= 0)
328 idx = FT_Get_Char_Index (face, (FT_ULong) i);
331 x = margin + (g_width + 1) * (i % 16);
332 y = margin + (g_height + FONT_HEIGHT + 1) * (i / 16);
333 if (FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
335 ximage.height = face->glyph->bitmap.rows;
336 ximage.width = face->glyph->bitmap.width;
338 ximage.bits_per_pixel = 1;
340 ximage.format = XYPixmap;
341 ximage.data = (char *) face->glyph->bitmap.buffer;
342 ximage.byte_order = MSBFirst;
343 ximage.bitmap_unit = 8;
344 ximage.bitmap_bit_order = MSBFirst;
345 ximage.bitmap_pad = 8;
346 ximage.bytes_per_line = face->glyph->bitmap.pitch;
347 XInitImage (&ximage);
348 XPutImage (display, pixmap, gc, &ximage, 0, 0,
349 x + g_x + face->glyph->bitmap_left,
350 y + g_y - face->glyph->bitmap_top,
351 ximage.width, ximage.height);
353 sprintf (str, "0x%02X", i);
354 XDrawString (display, pixmap, gc_inv,
355 x + (g_width - XTextWidth (font, str, 4))/ 2,
356 y + g_height + FONT_ASCENT, str, 4);
359 image = XGetImage (display, pixmap, 0, 0, pix_width, pix_height,
360 AllPlanes, XYPixmap);
363 char *name = alloca (strlen (filename) + 5);
366 sprintf (name, "%s.pbm", filename);
368 fp = fopen (name, "w");
369 fprintf (fp, "P4\n%d %d\n", image->width, image->height);
370 bytes_per_line = (image->width + 7) / 8;
372 for (y = 0; y < image->height; y++, data += image->bytes_per_line)
373 fwrite (data, 1, bytes_per_line, fp);
376 XWriteBitmapFile (display, name, pixmap, pix_width, pix_height, 0, 0);
379 FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
384 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
386 int old_glyph_index = glyph_index;
388 if ((int) client_data == -3 && glyph_index > 0)
390 else if ((int) client_data == -2 && glyph_index > 0)
391 glyph_index = (glyph_index - 1) & 0xF000;
392 else if ((int) client_data == -1 && glyph_index > 0)
394 else if ((int) client_data == 1 && glyph_index < 0xFF80)
396 else if ((int) client_data == 2 && glyph_index < 0xF000)
397 glyph_index = (glyph_index + 0x1000) & 0xF000;
398 else if ((int) client_data == 3 && glyph_index < 0xF000)
399 glyph_index = 0xFF80;
400 if (glyph_index != old_glyph_index)
401 update_glyph_area ();
405 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
407 if (charmap_index == (int) client_data)
409 charmap_index = (int) client_data;
410 if (charmap_index >= 0)
411 FT_Set_Charmap (face, face->charmaps[charmap_index]);
412 update_glyph_area ();
416 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
418 if ((int) client_data < 0)
420 glyph_rec.n_glyphs = 0;
421 update_render_area ();
423 else if (glyph_rec.n_glyphs < 64)
425 int index = glyph_index + (int) client_data;
427 if (charmap_index >= 0)
428 index = FT_Get_Char_Index (face, (FT_ULong) index);
429 if (bitmap[index].pixmap)
431 glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + (int) client_data;
432 glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
433 update_render_area ();
439 create_widgets (int pixel_size)
441 String quit_action = "<KeyPress>q: set() notify() unset()";
442 String FIRST_action = "~Shift<KeyPress>f: set() notify() unset()";
443 String PREV_action = "Shift<KeyPress>p: set() notify() unset()";
444 String prev_action = "~Shift<KeyPress>p: set() notify() unset()";
445 String next_action = "~Shift<KeyPress>n: set() notify() unset()";
446 String NEXT_action = "Shift<KeyPress>n: set() notify() unset()";
447 String LAST_action = "~Shift<KeyPress>l: set() notify() unset()";
450 int glyph_widget_height;
452 frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, NULL, 0);
453 XtSetArg (arg[0], XtNleft, XawChainLeft);
454 XtSetArg (arg[1], XtNright, XawChainLeft);
455 XtSetArg (arg[2], XtNtop, XawChainTop);
456 XtSetArg (arg[3], XtNbottom, XawChainTop);
457 XtSetArg (arg[4], XtNborderWidth, 0);
458 XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
459 command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
461 XtSetArg (arg[6], XtNfromVert, command_area);
462 navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
464 XtSetArg (arg[4], XtNborderWidth, 1);
465 XtSetArg (arg[5], XtNfromVert, navi_area);
466 XtSetArg (arg[6], XtNdefaultDistance, 0);
467 glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
469 XtSetArg (arg[4], XtNborderWidth, 0);
470 XtSetArg (arg[5], XtNfromVert, glyph_area);
471 render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
474 XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
475 quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
476 command_area, arg, 1);
477 XtAddCallback (quit, XtNcallback, QuitProc, NULL);
479 dump = XtCreateManagedWidget ("Dump Image", commandWidgetClass,
480 command_area, arg, 1);
481 XtAddCallback (dump, XtNcallback, DumpProc, (XtPointer) pixel_size);
483 charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
484 XtSetArg (arg[0], XtNstate, True);
485 charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
486 command_area, arg, 1);
487 XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
488 XtSetArg (arg[0], XtNradioGroup, charmap[0]);
489 for (i = 0; i < face->num_charmaps; i++)
491 charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
493 command_area, arg, 1);
494 XtAddCallback (charmap[i + 1], XtNcallback, CharmapProc, (XtPointer) i);
497 XtSetArg (arg[0], XtNlabel, " |< (f)");
498 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
499 FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
501 XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
502 XtSetArg (arg[0], XtNlabel, "<< (P)");
503 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
504 PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
506 XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
507 XtSetArg (arg[0], XtNlabel, "< (p)");
508 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
509 prev = XtCreateManagedWidget ("prev", commandWidgetClass,
511 XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
512 XtSetArg (arg[0], XtNlabel, " 0000 ");
513 label = XtCreateManagedWidget ("label", labelWidgetClass,
515 XtSetArg (arg[0], XtNlabel, "> (n)");
516 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
517 next = XtCreateManagedWidget ("next", commandWidgetClass,
519 XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
520 XtSetArg (arg[0], XtNlabel, ">> (N)");
521 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
522 NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
524 XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
525 XtSetArg (arg[0], XtNlabel, ">| (l)");
526 XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
527 LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
529 XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
531 glyph_widget_height = glyph_height + 1 + FONT_HEIGHT;
532 XtSetArg (arg[0], XtNleft, XawChainLeft);
533 XtSetArg (arg[1], XtNright, XawChainLeft);
534 XtSetArg (arg[2], XtNtop, XawChainTop);
535 XtSetArg (arg[3], XtNbottom, XawChainTop);
536 for (i = 0; i < 8; i++)
537 for (j = 0; j < 16; j++)
542 XtSetArg (arg[num_args], XtNwidth, glyph_width), num_args++;
543 XtSetArg (arg[num_args], XtNheight, glyph_widget_height), num_args++;
545 XtSetArg (arg[num_args], XtNfromHoriz, glyph[k - 1]), num_args++;
547 XtSetArg (arg[num_args], XtNfromVert, glyph[k - 16]), num_args++;
548 XtSetArg (arg[num_args], XtNinternalWidth, 0), num_args++;
549 glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
550 glyph_area, arg, num_args);
551 XtAddCallback (glyph[k], XtNcallback, RenderProc, (XtPointer) k);
554 XtSetArg (arg[0], XtNleft, XawChainLeft);
555 XtSetArg (arg[1], XtNright, XawChainLeft);
556 XtSetArg (arg[2], XtNtop, XawChainTop);
557 XtSetArg (arg[3], XtNbottom, XawChainTop);
558 clear = XtCreateManagedWidget ("clear", commandWidgetClass,
559 render_area, arg, 4);
560 XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
561 XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
562 XtSetArg (arg[5], XtNborderWidth, 0);
563 XtSetArg (arg[6], XtNfromVert, clear);
564 raw = XtCreateManagedWidget ("raw", boxWidgetClass,
565 render_area, arg, 7);
566 XtSetArg (arg[0], XtNborderWidth, 0);
567 XtSetArg (arg[1], XtNlabel, "raw: ");
568 raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
570 XtSetArg (arg[1], XtNbitmap, raw_pixmap);
571 raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
573 XtSetArg (arg[6], XtNfromVert, raw);
574 seq = XtCreateManagedWidget ("seq", boxWidgetClass,
575 render_area, arg, 7);
576 XtSetArg (arg[0], XtNborderWidth, 0);
577 XtSetArg (arg[1], XtNlabel, "seq: ");
578 seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
580 XtSetArg (arg[1], XtNbitmap, seq_pixmap);
581 seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
585 XtSetArg (arg[6], XtNfromVert, seq);
586 gsub = XtCreateManagedWidget ("gsub", boxWidgetClass,
587 render_area, arg, 7);
588 XtSetArg (arg[0], XtNborderWidth, 0);
589 XtSetArg (arg[1], XtNlabel, "gsub: ");
590 gsub_label = XtCreateManagedWidget ("gsub-label", labelWidgetClass,
592 gsub_image = XtCreateManagedWidget ("gsub-image", labelWidgetClass,
594 XtSetArg (arg[6], XtNfromVert, gsub);
595 gpos = XtCreateManagedWidget ("gpos", boxWidgetClass,
596 render_area, arg, 7);
597 XtSetArg (arg[0], XtNborderWidth, 0);
598 XtSetArg (arg[1], XtNlabel, "gpos: ");
599 gpos_label = XtCreateManagedWidget ("gpos-label", labelWidgetClass,
601 gpos_image = XtCreateManagedWidget ("gpos-image", labelWidgetClass,
605 XtInstallAllAccelerators (shell, shell);
609 /* Format MSG by FMT and print the result to the stderr, and exit. */
611 #define FATAL_ERROR(fmt, arg) \
613 fprintf (stderr, fmt, arg); \
618 main (int argc, char **argv)
622 OTF_GlyphString gstring;
627 int pixel_size = DEFAULT_PIXEL_SIZE;
628 int fixed_pixel_size = 0;
632 char *str = getenv ("PIXEL_SIZE");
634 if (str && (i = atoi (str)) > 0)
637 fixed_pixel_size = 1;
641 gstring.size = gstring.used = 256;
642 g = calloc (256, sizeof (OTF_Glyph));
645 shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
646 shellWidgetClass, NULL, 0);
647 display = XtDisplay (shell);
648 display_width = DisplayWidth (display,
649 XScreenNumberOfScreen (XtScreen (shell)));
650 font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
652 font = XLoadQueryFont (display, "fixed");
655 FATAL_ERROR ("%s\n", "Usage: otfview [ X-OPTION ... ] OTF-FILE");
658 if (strstr (filename, ".ttf")
659 || strstr (filename, ".TTF")
660 || strstr (filename, ".otf")
661 || strstr (filename, ".OTF"))
663 otf = OTF_open (filename);
665 || OTF_get_table (otf, "head") < 0
666 || OTF_get_table (otf, "cmap") < 0
667 || (OTF_get_table (otf, "gsub") < 0
668 && OTF_get_table (otf, "gpos") < 0))
672 if ((err = FT_Init_FreeType (&library)))
673 FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
674 err = FT_New_Face (library, filename, 0, &face);
675 if (err == FT_Err_Unknown_File_Format)
676 FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
678 FATAL_ERROR ("%s\n", "FT_New_Face: unknown error");
679 if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
680 FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
686 filename = basename (filename);
687 sprintf (title, "%s family:%s style:%s",
688 filename, face->family_name, face->style_name);
689 XtSetArg (arg[0], XtNtitle, title);
690 XtSetValues (shell, arg, 1);
693 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
694 * pixel_size / face->units_per_EM);
695 if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
697 pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
698 FT_Set_Pixel_Sizes (face, 0, pixel_size);
699 glyph_width = ((face->bbox.xMax - face->bbox.xMin)
700 * pixel_size / face->units_per_EM);
702 if (glyph_width < FONT_WIDTH * 4)
703 glyph_width = FONT_WIDTH * 4;
705 glyph_height = ((face->bbox.yMax - face->bbox.yMin)
706 * pixel_size / face->units_per_EM);
708 glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
709 glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
711 for (i = 0; i < 0x10000; i++)
712 if (FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0)
714 if (glyph_x < - face->glyph->bitmap_left)
715 glyph_x = - face->glyph->bitmap_left;
716 if (glyph_y < face->glyph->bitmap_top)
717 glyph_y = face->glyph->bitmap_top;
719 < glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width)
721 = glyph_x + face->glyph->bitmap_left + face->glyph->bitmap.width;
723 < glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows)
725 = glyph_y - face->glyph->bitmap_top + face->glyph->bitmap.rows;
728 none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
729 glyph_width, glyph_height + 1 + FONT_HEIGHT, 1);
732 unsigned long valuemask = GCFunction | GCLineWidth;
735 gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
736 values.function = GXset;
737 values.line_width = 1;
738 gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
739 values.function = GXor;
740 gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
741 values.function = GXcopyInverted;
742 gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
745 XFillRectangle (display, none_pixmap, gc, 0, 0,
746 glyph_width, glyph_height + 1 + FONT_HEIGHT);
747 XDrawString (display, none_pixmap, gc_inv,
748 (glyph_width - XTextWidth (font, "none", 4)) / 2,
749 glyph_height / 2, "none", 4);
751 render_width = (glyph_width + 1) * 15 + 1;
752 render_height = glyph_height + FONT_HEIGHT + 2;
754 charmap_rec[0].platform_id = -1;
755 charmap_rec[0].encoding_id = -1;
756 strcpy (charmap_rec[0].name, "no charmap");
758 for (i = 0; i < face->num_charmaps; i++)
760 charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
761 charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
762 sprintf (charmap_rec[i + 1].name, "%d-%d",
763 charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
764 if (face->charmaps[i]->platform_id == 0
765 || (face->charmaps[i]->platform_id == 3
766 && face->charmaps[i]->encoding_id == 1))
767 strcat (charmap_rec[i + 1].name, " (unicode)");
768 else if (face->charmaps[i]->platform_id == 1
769 && face->charmaps[i]->encoding_id == 0)
770 strcat (charmap_rec[i + 1].name, " (apple-roman)");
773 raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
774 render_width, render_height, 1);
775 seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
776 render_width, render_height, 1);
777 gsub_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
778 render_width, render_height, 1);
779 gpos_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
780 render_width, render_height, 1);
782 for (i = 0; i < 0x10000; i++)
783 create_pixmap (pixel_size, i);
784 create_widgets (pixel_size);
787 update_glyph_area ();
788 update_render_area ();
790 XtRealizeWidget (shell);
791 XtAppMainLoop (context);