#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
-#include "otf.h"
+#include <otf.h>
#include <ft2build.h>
#include FT_FREETYPE_H
-FT_Library library;
-FT_Face face;
-
#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
-#define FONT_NAME "-adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1"
+#define PIXEL_SIZE 40
+
+#define FONT_NAME "6x13"
#define FONT_HEIGHT 14
+int font_height, font_width;
+
+FT_Library library;
+FT_Face face;
+
Display *display;
int screen;
Window win;
typedef struct
{
+ int advance;
int left, top;
int rows;
int width;
int pitch;
+ int unicode;
unsigned char* buf;
} Bitmap;
Bitmap bitmap[0x10000];
+/* Unicode to glyph index mapping table. */
+int utog[0x10000];
+
void
-draw_bitmap (int index, int x, int xoff, int width,
- int y, int yoff, int height, int rev)
+draw_bitmap (int index, int x, int y)
{
- Bitmap *bmp = bitmap + index;
- unsigned char *buf = bmp->buf;
+ Bitmap *bmp;
+ unsigned char *buf;
int i, j;
- char str[256];
- int w;
-
- if (rev)
- XFillRectangle (display, win, gc_norm, x, y, width, height);
- XFillRectangle (display, win, gc_xor, x, y + height - FONT_HEIGHT,
- width, FONT_HEIGHT);
- XDrawLine (display, win, gc_xor, x, y, x, y + height - 1);
- sprintf (str, "%04X", index);
- w = XTextWidth (font, str, 4);
- XDrawString (display, win, gc_xor, x + (width - w) / 2, y + height - 2,
- str, 4);
+ unsigned code = FT_Get_Char_Index (face, (FT_ULong) index);
+ //unsigned code = index;
+
+ bmp = bitmap + code;
+ buf = bmp->buf;
if (buf)
{
- x += xoff + bmp->left;
- y += yoff - bmp->top;
+ x += bmp->left;
+ y -= bmp->top;
for (i = 0; i < bmp->rows; i++, buf += bmp->pitch)
for (j = 0; j < bmp->width; j++)
if (buf[j / 8] & (1 << (7 - (j % 8))))
- XDrawPoint (display, win, gc_xor, x + j, y + i);
+ XDrawPoint (display, win, gc_norm, x + j, y + i);
}
}
void
-draw_big_bitmat (int index,
- int x, int xoff, int width,
- int y, int yoff, int height)
-{
- FT_Bitmap *bmp;
- unsigned char *buf;
- int i, j;
-
- FT_Set_Pixel_Sizes (face, 0, 120);
- if (FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME))
- return;
-
- bmp = &face->glyph->bitmap;
- buf = bmp->buffer;
- XFillRectangle (display, win, gc_rev, x, y, width, height);
- XDrawRectangle (display, win, gc_norm, x - 1, y - 1, width + 1, height + 1);
- x += xoff + face->glyph->bitmap_left;
- y += yoff - face->glyph->bitmap_top;
- for (i = 0; i < bmp->rows; i++, buf += bmp->pitch)
- for (j = 0; j < bmp->width; j++)
- if (buf[j / 8] & (1 << (7 - (j % 8))))
- XDrawPoint (display, win, gc_norm, x + j, y + i);
-}
-
-void
quit (char *msg)
{
fprintf (stderr, "Error by %s\n", msg);
int
+read_unicode_seq (char *filename, int *code)
+{
+ FILE *fp = fopen (filename, "r");
+ int i = 0;
+
+ if (! fp)
+ {
+ fprintf (stderr, "File \"%s\" can't be opened.\n", filename);
+ exit (1);
+ }
+ while (i < 256
+ && fscanf (fp, "%x", code + i) == 1)
+ i++;
+ fclose (fp);
+ return i;
+}
+
+
+int
main (int argc, char **argv)
{
- OTF *otf;
+ OTF *otf = NULL;
int err;
- int i, max_i, j;
- int width, height, max_width, max_height;
- int cols = 16, rows = 8;
- int x0, y0, x1, y1;
- int big_height;
+ int i, j;
int first_idx;
- int left_idx = -1, right_idx = -1;
int update_mask;
-#define UPDATE_LEFT 1
-#define UPDATE_RIGHT 2
-#define UPDATE_MAIN 4
+#define UPDATE_RENDERING 1
+#define UPDATE_BITMAP 2
+ OTF_GlyphString gstring;
+ OTF_Glyph *g;
+ int unicode_seq[256];
+ int n_codes = 0;
+ int pixel_size = PIXEL_SIZE;
+ int raw_mode = 0;
+
+ /* Window structure.
+
+ +-------------------------+
+ | +--- rendering area --+ |
+ | |Unicode: ... | |
+ | | cmap: ... | |
+ | | GSUB: ... | |
+ | | GPOS: ... | |
+ | +---------------------+ |
+ | +--- bitmap area -----+ |
+ | | | |
+ | | | |
+ | | | |
+ | +---------------------+ |
+ +-------------------------+
+ */
+ int margin = 2;
+ int win_width, win_height;
+ int cols = 16, rows = 8;
+ int max_glyph_width, max_glyph_height;
+ int inner_width, rendering_area_height, bitmap_area_height;
+ int x, y, x0, y0, x1, y1;
+ char buf[1024];
+
+ gstring.size = gstring.used = 256;
+ g = calloc (256, sizeof (OTF_Glyph));
+ gstring.glyphs = g;
- if (argc != 2)
+ if (argc != 2 && argc != 3)
{
- fprintf (stderr, "Usage, otfview OTF-FILE");
+ fprintf (stderr, "Usage, otfview OTF-FILE [CODE-FILE]\n");
exit (1);
}
- otf = otf_open (argv[1]);
- if (! otf)
+ if (strstr (argv[1], ".ttf")
+ || strstr (argv[1], ".TTF")
+ || strstr (argv[1], ".otf")
+ || strstr (argv[1], ".OTF"))
{
- otf_perror ("otfview");
- exit (1);
+ otf = OTF_open (argv[1]);
+ if (! otf
+ || OTF_get_table (otf, "head") < 0
+ || OTF_get_table (otf, "cmap") < 0)
+ {
+ OTF_perror ("otfview");
+ otf = NULL;
+ }
}
+ {
+ char *p = getenv ("PIXEL_SIZE");
+ int n;
+
+ if (p && sscanf (p, "%d", &n) == 1)
+ pixel_size = n;
+
+ p = getenv ("RAW_MODE");
+ if (p)
+ raw_mode = 1;
+ }
+
err = FT_Init_FreeType (&library);
if (err)
quit ("FT_Init_FreeType");
quit ("FT_New_Face: unknown file format");
else if (err)
quit ("FT_New_Face: unknown error");
- err = FT_Set_Pixel_Sizes (face, 0, 24);
+ err = FT_Set_Pixel_Sizes (face, 0, pixel_size);
if (err)
quit ("FT_Set_Char_Size");
-
+ err = FT_Select_Charmap (face, FT_ENCODING_APPLE_ROMAN);
+ memset (utog, 0, sizeof (utog));
x0 = x1 = y0 = y1 = 0;
for (i = 0; i < 0x10000; i++)
{
Bitmap *bmp = bitmap + i;
int bmpsize;
- max_i = i;
+ bmp->advance = face->glyph->metrics.horiAdvance >> 6;
bmp->left = face->glyph->bitmap_left;
bmp->top = face->glyph->bitmap_top;
bmp->rows = face->glyph->bitmap.rows;
}
}
- max_height = y1 - y0;
- max_width = x1 - x0;
+ max_glyph_height = y1 - y0;
+ max_glyph_width = x1 - x0;
+
+ for (i = 0; i < 0x10000; i++)
+ {
+ if (i >= 0xD800 && i < 0xE000)
+ continue;
+ gstring.glyphs[i & 0xFF].c = i;
+ if ((i & 0xFF) == 0xFF)
+ {
+ OTF_drive_cmap (otf, &gstring);
+ for (j = 0; j < 0x100; j++)
+ {
+ utog[(i & 0xFF00) + j] = gstring.glyphs[j].glyph_id;
+ if (gstring.glyphs[j].glyph_id > 0
+ && gstring.glyphs[j].glyph_id < 0x10000)
+ bitmap[gstring.glyphs[j].glyph_id].unicode = (i & 0xFF00) + j;
+ }
+ }
+ }
+
+ if (argc == 3)
+ n_codes = read_unicode_seq (argv[2], unicode_seq);
display = XOpenDisplay (NULL);
screen = DefaultScreen (display);
+ font = XLoadQueryFont (display, FONT_NAME);
+ if (! font)
+ font = XLoadQueryFont (display, "fixed");
+ font_height = font->ascent + font->descent;
+ font_width = font->max_bounds.width;
- big_height = max_height * 5 + 10;
-
- width = max_width * cols;
- height = big_height + (max_height + FONT_HEIGHT) * rows;
+ inner_width = (max_glyph_width + 1) * cols + font_width * 4 + 2;
+ rendering_area_height= (max_glyph_height + 1) * 3 + font_height;
+ bitmap_area_height = (max_glyph_height + 1) * rows + font_height + 2;
+ win_width = inner_width + margin * 2;
+ win_height = rendering_area_height + bitmap_area_height + margin * 3;
win = XCreateSimpleWindow (display, RootWindow (display, screen),
- 0, 0, width, height, 1,
+ 0, 0, win_width, win_height, 1,
BlackPixel (display, screen),
WhitePixel (display, screen));
- font = XLoadQueryFont (display, FONT_NAME);
- if (! font)
- font = XLoadQueryFont (display, "fixed");
valuemask = GCForeground | GCBackground | GCFunction | GCFont;
values.foreground = BlackPixel (display, screen);
int x = event.xbutton.x;
int y = event.xbutton.y;
- if (y < big_height)
+ if (margin <= x && x < margin + inner_width
+ && margin + 1 <= y && y < margin + 1 + font_height)
{
- if (x < width / 2)
- {
- if (first_idx > 0)
- {
- first_idx -= cols * rows;
- update_mask |= UPDATE_MAIN;
- goto redraw;
- }
- }
- else
- {
- if (first_idx + cols * rows <= max_i)
- {
- first_idx += cols * rows;
- update_mask |= UPDATE_MAIN;
- goto redraw;
- }
- }
+ n_codes = read_unicode_seq (argv[2], unicode_seq);
+ update_mask = UPDATE_RENDERING;
+ goto redraw;
}
- else
+ }
+ break;
+
+ case KeyPress:
+ {
+ char buf[512];
+ KeySym keysym;
+ int n;
+
+ n = XLookupString ((XKeyEvent *) &event, buf, 512, &keysym, NULL);
+ if (! n)
+ break;
+ if (buf[0] == 'q')
+ goto finish;
+ if (buf[0] == 'n' || buf[0] == ' ')
{
- if (event.xbutton.button == Button1)
+ if (first_idx + cols * rows < 0x10000)
{
- left_idx = (first_idx
- + ((y - big_height)
- / (max_height + FONT_HEIGHT)
- * cols)
- + x / max_width);
- update_mask |= UPDATE_LEFT;
+ first_idx += cols * rows;
+ update_mask |= UPDATE_BITMAP;
+ goto redraw;
}
- else
+ }
+ else if (buf[0] == 'p'
+ || keysym == XK_BackSpace || keysym == XK_Delete)
+ {
+ if (first_idx > 0)
{
- right_idx = (first_idx
- + ((y - big_height)
- / (max_height + FONT_HEIGHT)
- * cols)
- + x / max_width);
- update_mask |= UPDATE_RIGHT;
+ first_idx -= cols * rows;
+ update_mask |= UPDATE_BITMAP;
+ goto redraw;
}
- goto redraw;
}
}
break;
- case KeyPress:
- break;
-
default:
- update_mask = UPDATE_LEFT | UPDATE_RIGHT | UPDATE_MAIN;
+ update_mask = UPDATE_RENDERING | UPDATE_BITMAP;
goto redraw;
}
continue;
redraw:
- if (update_mask == (UPDATE_LEFT | UPDATE_RIGHT | UPDATE_MAIN))
+ if (update_mask == (UPDATE_RENDERING | UPDATE_BITMAP))
{
XClearWindow (display, win);
- XDrawLine (display, win, gc_norm, 0, big_height - 1,
- width, big_height - 1);
+ x = margin;
+ y = margin + font->ascent;
+ XDrawImageString (display, win, gc_norm, x, y, "Unicode: ", 9);
+ y += font_height + (max_glyph_height - font_height) / 2;
+ XDrawImageString (display, win, gc_norm, x, y, " cmap: ", 9);
+ y += max_glyph_height + 1;
+ XDrawImageString (display, win, gc_norm, x, y, " GSUB: ", 9);
+ y += max_glyph_height + 1;
+ XDrawImageString (display, win, gc_norm, x, y, " GPOS: ", 9);
+
+ y = margin * 2 + rendering_area_height;
+ XDrawLine (display, win, gc_norm, x, y, x + inner_width - 1, y);
+ y += font_height + 1;
+ for (i = 0; i <= rows; i++, y += max_glyph_height + 1)
+ XDrawLine (display, win, gc_norm, x, y, x + inner_width - 1, y);
+ y = margin * 2 + rendering_area_height;
+ XDrawLine (display, win, gc_norm, x, y,
+ x, y + bitmap_area_height - 1);
+ x += font_width * 4 + 1;
+ for (i = 0; i <= cols; i++, x += max_glyph_width + 1)
+ XDrawLine (display, win, gc_norm, x, y,
+ x, y + bitmap_area_height - 1);
+ y += font->ascent + 1;
+ x = (margin + font_width * 4 + 2
+ + (max_glyph_width - font_width * 4) / 2);
+ for (i = 0; i < cols; i++, x += max_glyph_width + 1)
+ {
+ sprintf (buf, "xxx%X", i);
+ XDrawImageString (display, win, gc_norm, x, y, buf, 4);
+ }
+ }
+
+ if (otf && update_mask & UPDATE_RENDERING)
+ {
+ x = margin + font_width * 9;
+ y = margin + font->ascent;
+ for (i = 0; i < n_codes; i++)
+ {
+ sprintf (buf + i * 5, "%04X ", unicode_seq[i]);
+ gstring.glyphs[i].c = unicode_seq[i];
+ }
+ gstring.used = n_codes;
+ XDrawImageString (display, win, gc_norm, x, y, buf, n_codes * 5);
+
+ OTF_drive_cmap (otf, &gstring);
+ y = margin + font_height + 1;
+ for (i = 0; i < n_codes; i++, x += max_glyph_width)
+ draw_bitmap (gstring.glyphs[i].glyph_id, x - x0, y - y0);
+
+ OTF_drive_gsub (otf, &gstring, "deva", NULL, NULL);
+ x = margin + font_width * 9;
+ y += max_glyph_height;
+ for (i = 0; i < gstring.used; i++, x += max_glyph_width)
+ draw_bitmap (gstring.glyphs[i].glyph_id, x - x0, y - y0);
+
+ OTF_drive_gpos (otf, &gstring, "deva", NULL, NULL);
+ x = margin + font_width * 9 - x0;
+ y += max_glyph_height - y0;
+ for (i = 0; i < gstring.used; i++)
+ {
+ int xoff = 0, yoff = 0;
+ OTF_Glyph *g = gstring.glyphs + i;
+
+ switch (g->positioning_type)
+ {
+ case 1: case 2:
+ if (g->f.f1.format & OTF_XPlacement)
+ xoff = pixel_size * ((double) (g->f.f1.value->XPlacement)
+ * 100 / otf->head->unitsPerEm);
+ if (g->f.f1.format & OTF_YPlacement)
+ yoff = pixel_size * ((double) (g->f.f1.value->YPlacement)
+ * 100 / otf->head->unitsPerEm);
+ break;
+
+ case 4:
+ xoff = (pixel_size
+ * ((double) (g->f.f4.base_anchor->XCoordinate
+ - g->f.f4.mark_anchor->XCoordinate)
+ * 100 / otf->head->unitsPerEm));
+ yoff = (pixel_size
+ * ((double) (g->f.f4.base_anchor->YCoordinate
+ - g->f.f4.mark_anchor->YCoordinate)
+ * 100 / otf->head->unitsPerEm));
+ break;
+ }
+
+ draw_bitmap (gstring.glyphs[i].glyph_id, x + xoff, y + yoff);
+ x += bitmap[gstring.glyphs[i].glyph_id].advance;
+ }
}
- if (update_mask & UPDATE_MAIN)
+ if (update_mask & UPDATE_BITMAP)
{
- XFillRectangle (display, win, gc_rev, 0, big_height, width, height);
+ x = margin + 1;
+ y = (margin * 2 + rendering_area_height + font_height + 2
+ + (max_glyph_height - font_height) / 2 + font->ascent);
+ for (i = 0; i < rows; i++, y += max_glyph_height + 1)
+ {
+ sprintf (buf, "%03Xx", (first_idx + i * cols) / 16);
+ XDrawImageString (display, win, gc_norm, x, y, buf, 4);
+ }
+ x += font_width * 4 + 1;
+ y = margin * 2 + rendering_area_height + font_height + 2;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
- draw_bitmap (first_idx + i * cols + j,
- max_width * j, -x0, max_width,
- big_height + (max_height + FONT_HEIGHT) * i,
- -y0, max_height + FONT_HEIGHT, 0);
+ {
+ unsigned index = first_idx + i * cols + j;
+
+ XClearArea (display, win, x + (max_glyph_width + 1) * j,
+ y + (max_glyph_height + 1) * i,
+ max_glyph_width, max_glyph_height, False);
+ if (! raw_mode)
+ index = FT_Get_Char_Index (face, (FT_ULong) index);
+
+ draw_bitmap (index,
+ x + (max_glyph_width + 1) * j - x0,
+ y + (max_glyph_height + 1) * i - y0);
+ }
}
- if (update_mask & UPDATE_LEFT)
- draw_big_bitmat (left_idx, max_width * 2, -x0 * 5, max_width * 5,
- 5, -y0 * 5, max_height * 5);
- if (update_mask & UPDATE_RIGHT)
- draw_big_bitmat (right_idx, max_width * 9, -x0 * 5, max_width * 5,
- 5, -y0 * 5, max_height * 5);
update_mask = 0;
}
- otf_close (otf);
+ finish:
+ OTF_close (otf);
exit (0);
}