*** empty log message ***
[m17n/libotf.git] / example / otfview.c
index 2b021da..626bce8 100644 (file)
@@ -1,20 +1,28 @@
 #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;
@@ -26,72 +34,44 @@ XGCValues values;
 
 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);
@@ -100,35 +80,102 @@ quit (char *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");
@@ -137,10 +184,11 @@ main (int argc, char **argv)
     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++)
     {
@@ -152,7 +200,7 @@ main (int argc, char **argv)
          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;
@@ -172,25 +220,49 @@ main (int argc, char **argv)
        }
     }
 
-  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);
@@ -227,88 +299,182 @@ main (int argc, char **argv)
            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);
 }