*** empty log message ***
[m17n/libotf.git] / example / otfview.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "otf.h"
6
7 #include <ft2build.h>
8 #include FT_FREETYPE_H
9
10 FT_Library library;
11 FT_Face face;
12
13 #include <X11/Xlib.h>
14
15 #define FONT_NAME "-adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1"
16 #define FONT_HEIGHT 14
17
18 Display *display;
19 int screen;
20 Window win;
21 XFontStruct *font;
22 GC gc_norm, gc_rev, gc_xor;
23 unsigned long valuemask;
24 unsigned long foreground, background;
25 XGCValues values;
26
27 typedef struct
28 {
29   int left, top;
30   int rows;
31   int width;
32   int pitch;
33   unsigned char* buf;
34 } Bitmap;
35
36 Bitmap bitmap[0x10000];
37
38 void
39 draw_bitmap (int index, int x, int xoff, int width,
40              int y, int yoff, int height, int rev)
41 {
42   Bitmap *bmp = bitmap + index;
43   unsigned char *buf = bmp->buf;
44   int i, j;
45   char str[256];
46   int w;
47
48   if (rev)
49     XFillRectangle (display, win, gc_norm, x, y, width, height);
50   XFillRectangle (display, win, gc_xor, x, y + height - FONT_HEIGHT,
51                   width, FONT_HEIGHT);
52   XDrawLine (display, win, gc_xor, x, y, x, y + height - 1);
53   sprintf (str, "%04X", index);
54   w = XTextWidth (font, str, 4);
55   XDrawString (display, win, gc_xor, x + (width - w) / 2, y + height - 2,
56                str, 4);
57
58   if (buf)
59     {
60       x += xoff + bmp->left;
61       y += yoff - bmp->top;
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_xor, x + j, y + i);
66     }
67 }
68
69 void
70 draw_big_bitmat (int index,
71                  int x, int xoff, int width,
72                  int y, int yoff, int height)
73 {
74   FT_Bitmap *bmp;
75   unsigned char *buf;
76   int i, j;
77
78   FT_Set_Pixel_Sizes (face, 0, 120);
79   if (FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME))
80     return;
81   
82   bmp = &face->glyph->bitmap;
83   buf = bmp->buffer;
84   XFillRectangle (display, win, gc_rev, x, y, width, height);
85   XDrawRectangle (display, win, gc_norm, x - 1, y - 1, width + 1, height + 1);
86   x += xoff + face->glyph->bitmap_left;
87   y += yoff - face->glyph->bitmap_top;
88   for (i = 0; i < bmp->rows; i++, buf += bmp->pitch)
89     for (j = 0; j < bmp->width; j++)
90       if (buf[j / 8] & (1 << (7 - (j % 8))))
91         XDrawPoint (display, win, gc_norm, x + j, y + i);
92 }
93
94 void
95 quit (char *msg)
96 {
97   fprintf (stderr, "Error by %s\n", msg);
98   exit (1);
99 }
100
101
102 int
103 main (int argc, char **argv)
104 {
105   OTF *otf;
106   int err;
107   int i, max_i, j;
108   int width, height, max_width, max_height;
109   int cols = 16, rows = 8;
110   int x0, y0, x1, y1;
111   int big_height;
112   int first_idx;
113   int left_idx = -1, right_idx = -1;
114   int update_mask;
115 #define UPDATE_LEFT 1
116 #define UPDATE_RIGHT 2
117 #define UPDATE_MAIN 4
118
119   if (argc != 2)
120     {
121       fprintf (stderr, "Usage, otfview OTF-FILE");
122       exit (1);
123     }
124   
125   otf = otf_open (argv[1]);
126   if (! otf)
127     {
128       otf_perror ("otfview");
129       exit (1);
130     }
131
132   err = FT_Init_FreeType (&library);
133   if (err)
134     quit ("FT_Init_FreeType");
135   err = FT_New_Face (library, argv[1], 0, &face);
136   if (err == FT_Err_Unknown_File_Format)
137     quit ("FT_New_Face: unknown file format");
138   else if (err)
139     quit ("FT_New_Face: unknown error");
140   err = FT_Set_Pixel_Sizes (face, 0, 24);
141   if (err)
142     quit ("FT_Set_Char_Size");
143
144   x0 = x1 = y0 = y1 = 0;
145   for (i = 0; i < 0x10000; i++)
146     {
147       err = FT_Load_Glyph (face, i, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
148       if (err)
149         bitmap[i].buf = NULL;
150       else
151         {
152           Bitmap *bmp = bitmap + i;
153           int bmpsize;
154
155           max_i = i;
156           bmp->left = face->glyph->bitmap_left;
157           bmp->top = face->glyph->bitmap_top;
158           bmp->rows = face->glyph->bitmap.rows;
159           bmp->width = face->glyph->bitmap.width;
160           bmp->pitch = face->glyph->bitmap.pitch;
161           bmpsize = bmp->rows * bmp->pitch;
162           bmp->buf = malloc (bmpsize);
163           memcpy (bmp->buf, face->glyph->bitmap.buffer, bmpsize);
164           if (x0 > bmp->left)
165             x0 = bmp->left;
166           if (y0 > - bmp->top)
167             y0 = - bmp->top;
168           if (x1 < bmp->left + bmp->width)
169             x1 = bmp->left + bmp->width;
170           if (y1 < bmp->rows - bmp->top)
171             y1 = bmp->rows - bmp->top;
172         }
173     }
174
175   max_height = y1 - y0;
176   max_width = x1 - x0;
177
178   display = XOpenDisplay (NULL);
179   screen = DefaultScreen (display);
180
181   big_height = max_height * 5 + 10;
182   
183   width = max_width * cols;
184   height = big_height + (max_height + FONT_HEIGHT) * rows;
185
186   win = XCreateSimpleWindow (display, RootWindow (display, screen),
187                              0, 0, width, height, 1,
188                              BlackPixel (display, screen),
189                              WhitePixel (display, screen));
190
191   font = XLoadQueryFont (display, FONT_NAME);
192   if (! font)
193     font = XLoadQueryFont (display, "fixed");
194   valuemask = GCForeground | GCBackground | GCFunction | GCFont;
195
196   values.foreground = BlackPixel (display, screen);
197   values.background = WhitePixel (display, screen);
198   values.function = GXcopy;
199   values.font = font->fid;
200   gc_norm = XCreateGC (display, win, valuemask, &values);
201
202   values.foreground = WhitePixel (display, screen);
203   values.background = BlackPixel (display, screen);
204   values.function = GXcopy;
205   gc_rev = XCreateGC (display, win, valuemask, &values);
206
207   values.foreground = BlackPixel (display, screen);
208   values.background = WhitePixel (display, screen);
209   values.function = values.foreground ? GXxor : GXequiv;
210   gc_xor = XCreateGC (display, win, valuemask, &values);
211
212   XMapWindow (display, win);
213   XSelectInput (display, win, ExposureMask | KeyPressMask | ButtonPressMask);
214
215   first_idx = 0;
216   update_mask = 0;
217   while (1)
218     {
219       XEvent event;
220
221       XNextEvent (display, &event);
222
223       switch (event.type)
224         {
225         case ButtonPress:
226           {
227             int x = event.xbutton.x;
228             int y = event.xbutton.y;
229
230             if (y < big_height)
231               {
232                 if (x < width / 2)
233                   {
234                     if (first_idx > 0)
235                       {
236                         first_idx -= cols * rows;
237                         update_mask |= UPDATE_MAIN;
238                         goto redraw;
239                       }
240                   }
241                 else
242                   {
243                     if (first_idx + cols * rows <= max_i)
244                       {
245                         first_idx += cols * rows;
246                         update_mask |= UPDATE_MAIN;
247                         goto redraw;
248                       }
249                   }
250               }
251             else
252               {
253                 if (event.xbutton.button == Button1)
254                   {
255                     left_idx = (first_idx
256                                 + ((y - big_height)
257                                    / (max_height + FONT_HEIGHT)
258                                    * cols)
259                                 + x / max_width);
260                     update_mask |= UPDATE_LEFT;
261                   }
262                 else
263                   {
264                     right_idx = (first_idx
265                                  + ((y - big_height)
266                                     / (max_height + FONT_HEIGHT)
267                                     * cols)
268                                  + x / max_width);
269                     update_mask |= UPDATE_RIGHT;
270                   }
271                 goto redraw;
272               }
273           }
274           break;
275
276         case KeyPress:
277           break;
278
279         default:
280           update_mask = UPDATE_LEFT | UPDATE_RIGHT | UPDATE_MAIN;
281           goto redraw;
282         }
283       continue;
284
285     redraw:
286       if (update_mask == (UPDATE_LEFT | UPDATE_RIGHT | UPDATE_MAIN))
287         {
288           XClearWindow (display, win);
289           XDrawLine (display, win, gc_norm, 0, big_height - 1,
290                      width, big_height - 1);
291         }
292
293       if (update_mask & UPDATE_MAIN)
294         {
295           XFillRectangle (display, win, gc_rev, 0, big_height, width, height);
296           for (i = 0; i < rows; i++)
297             for (j = 0; j < cols; j++)
298               draw_bitmap (first_idx + i * cols + j,
299                            max_width * j, -x0, max_width,
300                            big_height + (max_height + FONT_HEIGHT) * i,
301                            -y0, max_height + FONT_HEIGHT,  0);
302         }
303       if (update_mask & UPDATE_LEFT)      
304         draw_big_bitmat (left_idx, max_width * 2, -x0 * 5, max_width * 5,
305                          5, -y0 * 5, max_height * 5);
306       if (update_mask & UPDATE_RIGHT)      
307         draw_big_bitmat (right_idx, max_width * 9, -x0 * 5, max_width * 5,
308                          5, -y0 * 5, max_height * 5);
309       update_mask = 0;
310     }
311
312   otf_close (otf);
313   exit (0);
314 }