10 #include FT_FREETYPE_H
13 #include <X11/keysym.h>
14 #include <X11/Xutil.h>
18 #define FONT_NAME "6x13"
19 #define FONT_HEIGHT 14
21 int font_height, font_width;
30 GC gc_norm, gc_rev, gc_xor;
31 unsigned long valuemask;
32 unsigned long foreground, background;
46 Bitmap bitmap[0x10000];
48 /* Unicode to glyph index mapping table. */
52 draw_bitmap (int index, int x, int y)
54 Bitmap *bmp = bitmap + index;
55 unsigned char *buf = bmp->buf;
62 for (i = 0; i < bmp->rows; i++, buf += bmp->pitch)
63 for (j = 0; j < bmp->width; j++)
64 if (buf[j / 8] & (1 << (7 - (j % 8))))
65 XDrawPoint (display, win, gc_norm, x + j, y + i);
72 fprintf (stderr, "Error by %s\n", msg);
78 read_unicode_seq (char *filename, int *code)
80 FILE *fp = fopen (filename, "r");
85 fprintf (stderr, "File \"%s\" can't be opened.\n", filename);
89 && fscanf (fp, "%x", code + i) == 1)
105 main (int argc, char **argv)
112 #define UPDATE_RENDERING 1
113 #define UPDATE_CHARMAP 2
114 #define UPDATE_BITMAP 3
115 OTF_GlyphString gstring;
117 int unicode_seq[256];
119 int pixel_size = PIXEL_SIZE;
120 CharmapRec *charmap_rec;
121 int charmap_index = -1;
122 char charmap_line[256];
126 +-------------------------+
127 | +--- rendering area --+ |
132 | +---------------------+ |
133 | +--- charmap area ----+ |
135 | +---------------------+ |
136 | +--- bitmap area -----+ |
140 | +---------------------+ |
141 +-------------------------+
144 int win_width, win_height;
145 int cols = 16, rows = 8;
146 int max_glyph_width, max_glyph_height;
147 int inner_width, rendering_area_height;
148 int charmap_area_height, bitmap_area_height;
149 int x, y, x0, y0, x1, y1;
152 gstring.size = gstring.used = 256;
153 g = calloc (256, sizeof (OTF_Glyph));
156 if (argc != 2 && argc != 3)
158 fprintf (stderr, "Usage, otfview OTF-FILE [CODE-FILE]\n");
162 if (strstr (argv[1], ".ttf")
163 || strstr (argv[1], ".TTF")
164 || strstr (argv[1], ".otf")
165 || strstr (argv[1], ".OTF"))
167 otf = OTF_open (argv[1]);
169 || OTF_get_table (otf, "head") < 0
170 || OTF_get_table (otf, "cmap") < 0)
172 OTF_perror ("otfview");
178 char *p = getenv ("PIXEL_SIZE");
181 if (p && sscanf (p, "%d", &n) == 1)
185 err = FT_Init_FreeType (&library);
187 quit ("FT_Init_FreeType");
188 err = FT_New_Face (library, argv[1], 0, &face);
189 if (err == FT_Err_Unknown_File_Format)
190 quit ("FT_New_Face: unknown file format");
192 quit ("FT_New_Face: unknown error");
193 err = FT_Set_Pixel_Sizes (face, 0, pixel_size);
195 quit ("FT_Set_Char_Size");
196 charmap_rec = alloca (sizeof (CharmapRec) * face->num_charmaps);
197 strcpy (charmap_line, "raw");
198 for (i = 0; i < face->num_charmaps; i++)
200 strcat (charmap_line, " ");
201 charmap_rec[i].index = strlen (charmap_line);
202 charmap_rec[i].platform_id = face->charmaps[i]->platform_id;
203 charmap_rec[i].encoding_id = face->charmaps[i]->encoding_id;
204 sprintf (charmap_rec[i].name, "%d-%d",
205 charmap_rec[i].platform_id, charmap_rec[i].encoding_id);
206 if (face->charmaps[i]->platform_id == 0
207 || (face->charmaps[i]->platform_id == 3
208 && face->charmaps[i]->encoding_id == 1))
209 strcat (charmap_rec[i].name, " (unicode)");
210 else if (face->charmaps[i]->platform_id == 1
211 && face->charmaps[i]->encoding_id == 0)
212 strcat (charmap_rec[i].name, " (apple-roman)");
213 strcat (charmap_line, charmap_rec[i].name);
215 strcat (charmap_line, " ");
217 memset (utog, 0, sizeof (utog));
218 x0 = x1 = y0 = y1 = 0;
219 for (i = 0; i < 0x10000; i++)
221 err = FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
223 bitmap[i].buf = NULL;
226 Bitmap *bmp = bitmap + i;
229 bmp->advance = face->glyph->metrics.horiAdvance >> 6;
230 bmp->left = face->glyph->bitmap_left;
231 bmp->top = face->glyph->bitmap_top;
232 bmp->rows = face->glyph->bitmap.rows;
233 bmp->width = face->glyph->bitmap.width;
234 bmp->pitch = face->glyph->bitmap.pitch;
235 bmpsize = bmp->rows * bmp->pitch;
236 bmp->buf = malloc (bmpsize);
237 memcpy (bmp->buf, face->glyph->bitmap.buffer, bmpsize);
242 if (x1 < bmp->left + bmp->width)
243 x1 = bmp->left + bmp->width;
244 if (y1 < bmp->rows - bmp->top)
245 y1 = bmp->rows - bmp->top;
249 max_glyph_height = y1 - y0;
250 max_glyph_width = x1 - x0;
252 for (i = 0; i < 0x10000; i++)
254 if (i >= 0xD800 && i < 0xE000)
256 gstring.glyphs[i & 0xFF].c = i;
257 if ((i & 0xFF) == 0xFF)
259 OTF_drive_cmap (otf, &gstring);
260 for (j = 0; j < 0x100; j++)
262 utog[(i & 0xFF00) + j] = gstring.glyphs[j].glyph_id;
263 if (gstring.glyphs[j].glyph_id > 0
264 && gstring.glyphs[j].glyph_id < 0x10000)
265 bitmap[gstring.glyphs[j].glyph_id].unicode = (i & 0xFF00) + j;
271 n_codes = read_unicode_seq (argv[2], unicode_seq);
273 display = XOpenDisplay (NULL);
274 screen = DefaultScreen (display);
275 font = XLoadQueryFont (display, FONT_NAME);
277 font = XLoadQueryFont (display, "fixed");
278 font_height = font->ascent + font->descent;
279 font_width = font->max_bounds.width;
281 inner_width = (max_glyph_width + 1) * cols + font_width * 4 + 2;
282 rendering_area_height= (max_glyph_height + 1) * 3 + font_height;
283 charmap_area_height = font_height + 2;
284 bitmap_area_height = (max_glyph_height + 1) * rows + font_height + 2;
285 win_width = inner_width + margin * 2;
286 win_height = (rendering_area_height
287 + charmap_area_height
290 win = XCreateSimpleWindow (display, RootWindow (display, screen),
291 0, 0, win_width, win_height, 1,
292 BlackPixel (display, screen),
293 WhitePixel (display, screen));
295 valuemask = GCForeground | GCBackground | GCFunction | GCFont;
297 values.foreground = BlackPixel (display, screen);
298 values.background = WhitePixel (display, screen);
299 values.function = GXcopy;
300 values.font = font->fid;
301 gc_norm = XCreateGC (display, win, valuemask, &values);
303 values.foreground = WhitePixel (display, screen);
304 values.background = BlackPixel (display, screen);
305 values.function = GXcopy;
306 gc_rev = XCreateGC (display, win, valuemask, &values);
308 values.foreground = BlackPixel (display, screen);
309 values.background = WhitePixel (display, screen);
310 values.function = values.foreground ? GXxor : GXequiv;
311 gc_xor = XCreateGC (display, win, valuemask, &values);
313 XMapWindow (display, win);
314 XSelectInput (display, win, ExposureMask | KeyPressMask | ButtonPressMask);
322 XNextEvent (display, &event);
328 int x = event.xbutton.x;
329 int y = event.xbutton.y;
331 if (x < margin || x >= margin + inner_width)
333 if (margin + rendering_area_height + 3 <= y
334 && y < margin + rendering_area_height + 3 + font_height)
337 if (charmap_index >= face->num_charmaps)
339 update_mask = UPDATE_CHARMAP | UPDATE_BITMAP;
342 if (margin + 1 <= y && y < margin + 1 + font_height)
344 n_codes = read_unicode_seq (argv[2], unicode_seq);
357 n = XLookupString ((XKeyEvent *) &event, buf, 512, &keysym, NULL);
362 if (buf[0] == 'n' || buf[0] == ' ')
364 if (first_idx + cols * rows < 0x10000)
366 first_idx += cols * rows;
367 update_mask |= UPDATE_BITMAP;
371 else if (buf[0] == 'p'
372 || keysym == XK_BackSpace || keysym == XK_Delete)
376 first_idx -= cols * rows;
377 update_mask |= UPDATE_BITMAP;
385 update_mask = UPDATE_RENDERING | UPDATE_BITMAP;
391 if (update_mask == (UPDATE_RENDERING | UPDATE_CHARMAP | UPDATE_BITMAP))
393 XClearWindow (display, win);
395 y = margin + font->ascent;
396 XDrawImageString (display, win, gc_norm, x, y, "Unicode: ", 9);
397 y += font_height + (max_glyph_height - font_height) / 2;
398 XDrawImageString (display, win, gc_norm, x, y, " cmap: ", 9);
399 y += max_glyph_height + 1;
400 XDrawImageString (display, win, gc_norm, x, y, " GSUB: ", 9);
401 y += max_glyph_height + 1;
402 XDrawImageString (display, win, gc_norm, x, y, " GPOS: ", 9);
404 y = margin * 3 + rendering_area_height + charmap_area_height;
405 XDrawLine (display, win, gc_norm, x, y, x + inner_width - 1, y);
406 y += font_height + 1;
407 for (i = 0; i <= rows; i++, y += max_glyph_height + 1)
408 XDrawLine (display, win, gc_norm, x, y, x + inner_width - 1, y);
409 y = margin * 3 + rendering_area_height + charmap_area_height;
410 XDrawLine (display, win, gc_norm, x, y,
411 x, y + bitmap_area_height - 1);
412 x += font_width * 4 + 1;
413 for (i = 0; i <= cols; i++, x += max_glyph_width + 1)
414 XDrawLine (display, win, gc_norm, x, y,
415 x, y + bitmap_area_height - 1);
416 y += font->ascent + 1;
417 x = (margin + font_width * 4 + 2
418 + (max_glyph_width - font_width * 4) / 2);
419 for (i = 0; i < cols; i++, x += max_glyph_width + 1)
421 sprintf (buf, "xxx%X", i);
422 XDrawImageString (display, win, gc_norm, x, y, buf, 4);
426 if (otf && update_mask & UPDATE_RENDERING)
428 x = margin + font_width * 9;
429 y = margin + font->ascent;
430 for (i = 0; i < n_codes; i++)
432 sprintf (buf + i * 5, "%04X ", unicode_seq[i]);
433 gstring.glyphs[i].c = unicode_seq[i];
435 gstring.used = n_codes;
436 XDrawImageString (display, win, gc_norm, x, y, buf, n_codes * 5);
438 OTF_drive_cmap (otf, &gstring);
439 y = margin + font_height + 1;
440 for (i = 0; i < n_codes; i++, x += max_glyph_width)
441 draw_bitmap (gstring.glyphs[i].glyph_id, x - x0, y - y0);
443 OTF_drive_gsub (otf, &gstring, "deva", NULL, NULL);
444 x = margin + font_width * 9;
445 y += max_glyph_height;
446 for (i = 0; i < gstring.used; i++, x += max_glyph_width)
447 draw_bitmap (gstring.glyphs[i].glyph_id, x - x0, y - y0);
449 OTF_drive_gpos (otf, &gstring, "deva", NULL, NULL);
450 x = margin + font_width * 9 - x0;
451 y += max_glyph_height - y0;
452 for (i = 0; i < gstring.used; i++)
454 int xoff = 0, yoff = 0;
455 OTF_Glyph *g = gstring.glyphs + i;
457 switch (g->positioning_type)
460 if (g->f.f1.format & OTF_XPlacement)
461 xoff = pixel_size * ((double) (g->f.f1.value->XPlacement)
462 * 100 / otf->head->unitsPerEm);
463 if (g->f.f1.format & OTF_YPlacement)
464 yoff = pixel_size * ((double) (g->f.f1.value->YPlacement)
465 * 100 / otf->head->unitsPerEm);
470 * ((double) (g->f.f4.base_anchor->XCoordinate
471 - g->f.f4.mark_anchor->XCoordinate)
472 * 100 / otf->head->unitsPerEm));
474 * ((double) (g->f.f4.base_anchor->YCoordinate
475 - g->f.f4.mark_anchor->YCoordinate)
476 * 100 / otf->head->unitsPerEm));
480 draw_bitmap (gstring.glyphs[i].glyph_id, x + xoff, y + yoff);
481 x += bitmap[gstring.glyphs[i].glyph_id].advance;
485 if (update_mask & UPDATE_CHARMAP)
487 char *p = charmap_line, *pend;
490 y = margin * 3 + rendering_area_height + font->ascent + 1;
491 XDrawImageString (display, win, gc_norm, x, y, charmap_line,
492 strlen (charmap_line));
493 if (charmap_index == -1)
497 p += charmap_rec[charmap_index].index;
498 pend = p + strlen (charmap_rec[charmap_index].name);
499 FT_Set_Charmap (face, face->charmaps[charmap_index]);
501 x += font_width * (p - charmap_line);
503 XDrawImageString (display, win, gc_rev, x, y, p, strlen (p));
507 if (update_mask & UPDATE_BITMAP)
510 y = (margin * 2 + rendering_area_height + font_height + 2
511 + (max_glyph_height - font_height) / 2 + font->ascent);
512 for (i = 0; i < rows; i++, y += max_glyph_height + 1)
514 sprintf (buf, "%03Xx", (first_idx + i * cols) / 16);
515 XDrawImageString (display, win, gc_norm, x, y, buf, 4);
517 x += font_width * 4 + 1;
518 y = (margin * 3 + rendering_area_height + charmap_area_height
520 for (i = 0; i < rows; i++)
521 for (j = 0; j < cols; j++)
523 unsigned index = first_idx + i * cols + j;
525 XClearArea (display, win, x + (max_glyph_width + 1) * j,
526 y + (max_glyph_height + 1) * i,
527 max_glyph_width, max_glyph_height, False);
528 if (charmap_index >= 0)
529 index = FT_Get_Char_Index (face, (FT_ULong) index);
532 x + (max_glyph_width + 1) * j - x0,
533 y + (max_glyph_height + 1) * i - y0);