*** empty log message ***
[m17n/m17n-test.git] / mimdaemon.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <ctype.h>
9
10 #include <gd.h>
11
12 #include <m17n-gui.h>
13 #include <m17n-misc.h>
14
15 #define PIPE_IN "/tmp/mimdemo-in"
16 #define PIPE_OUT "/tmp/mimdemo-out"
17
18 /* Format MSG by FMT and print the result to the stderr, and exit.  */
19
20 #define FATAL_ERROR(fmt, arg)   \
21   do {                          \
22     fprintf (out, "0\n");       \
23     fprintf (out, fmt, arg);    \
24     fprintf (out, "\n");        \
25     goto err;                   \
26   } while (0)
27
28 char base64_encode_table[] =
29   { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
30     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
31     'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
32     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
33     'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
34     'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
35     '8', '9', '+', '/' };
36
37 void
38 base64_encode (const unsigned char *src, int length, FILE *fp)
39 {
40   int i = 0;
41   int c;
42   unsigned int value;
43
44   while (i < length)
45     {
46       c = src[i++];
47       putc (base64_encode_table[0x3f & c >> 2], fp);
48       value = (0x03 & c) << 4;
49       if (i == length)
50         {
51           putc (base64_encode_table[value], fp);
52           putc ('=', fp);
53           putc ('=', fp);
54           break;
55         }
56       c = src[i++];
57       putc (base64_encode_table[value | (0x0f & c >> 4)], fp);
58       value = (0x0f & c) << 2;
59       if (i == length)
60         {
61           putc (base64_encode_table[value], fp);
62           putc ('=', fp);
63           break;
64         }
65       c = src[i++];
66       putc (base64_encode_table[value | (0x03 & c >> 6)], fp);
67       putc (base64_encode_table[0x3f & c], fp);
68     }
69 }
70   
71 int
72 main (int argc, char **argv)
73 {
74   FILE *in, *out;
75   mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
76   int c;
77
78   int fontsize = 240;
79   int dpi = 100;
80
81   MText *mt;
82   int i;
83   MSymbol lang, name;
84   MInputMethod *im;
85   MInputContext *ic;
86
87   int len, from, to;
88   MConverter *converter;
89   MFrame *frame;
90   MDrawControl control;
91   MDrawMetric ink, logical;
92   int ascent, descent, height, width;
93 #if 0
94   int indent = 0;
95   int left_adjust;
96 #endif
97   gdImagePtr work;
98   int work_white;
99
100   umask (0);
101   if (mkfifo (PIPE_IN, mode) < 0 && errno != EEXIST)
102     {
103       fprintf (stderr, "Failed to make a named pipe.\n");
104       exit (1);
105     }
106
107   if (mkfifo (PIPE_OUT, mode) < 0 && errno != EEXIST)
108     {
109       fprintf (stderr, "Failed to make a named pipe.\n");
110       exit (1);
111     }
112
113   M17N_INIT ();
114   if (merror_code != MERROR_NONE)
115     {
116       fprintf (stderr, "Failed to initialize the m17n library.\n");
117       exit (1);
118     }
119
120   {
121     MPlist *plist = mplist (), *p;
122     MFontset *fontset = mfontset ("generic");
123     MFace *face = mface ();
124
125     mface_put_prop (face, Mfontset, fontset);
126     mface_put_prop (face, Msize, (void *) (fontsize * dpi / 100));
127     p = mplist_add (plist, Mdevice, msymbol ("gd"));
128     p = mplist_add (p, Mface, face);
129     m17n_object_unref (face);
130     frame = mframe (plist);
131     m17n_object_unref (plist);
132     if (! frame)
133       {
134         fprintf (stderr, "Failed to open a frame.\n");
135         exit (1);
136       }
137   }
138
139   while (1)
140     {
141       char langname[256], imname[256];
142       
143       printf ("accepting...");
144       fflush (stdout);
145       in = fopen (PIPE_IN, "r");
146       printf ("\nconnecting...");
147       fflush (stdout);
148       out = fopen (PIPE_OUT, "w");
149       if (! in || ! out)
150         {
151           fprintf (stderr, "Failed to open a named pipe.\n");
152           exit (1);
153         }
154       printf ("done\nreading...");
155       fflush (stdout);
156
157       memset (langname, 0, 256);
158       memset (imname, 0, 256);
159
160       i = 0;
161       while ((c = getc (in)) != EOF && c != '-')
162         {
163           if (i == 255)
164             FATAL_ERROR ("Too long lang name: %s.", langname);
165           langname[i++] = c;
166         }
167       if (c != '-')
168         FATAL_ERROR ("No input method name for %s.", langname);
169       i = 0;
170       while ((c = getc (in)) != EOF && c != ' ')
171         {
172           if (i == 255)
173             FATAL_ERROR ("Too long input method name: %s", imname);
174           imname[i++] = c;
175         }
176       if (c != ' ')
177         FATAL_ERROR ("%s", "No key sequence");
178
179       lang = msymbol (langname);
180       name = msymbol (imname);
181
182       im = minput_open_im (lang, name, NULL);
183       if (! im)
184         FATAL_ERROR ("Failed to open input method \"%s\".", imname);
185       ic = minput_create_ic (im, NULL);
186       if (! im)
187         FATAL_ERROR ("%s", "Failed to create the input context.");
188       mt = mtext ();
189       while ((c = getc (in)) != EOF)
190         {
191           char keybuf[2];
192           MSymbol key;
193
194           keybuf[0] = c;
195           keybuf[1] = '\0';
196           key = msymbol (keybuf);
197           if (minput_filter (ic, key, NULL) == 1)
198             continue;
199           if (minput_lookup (ic, key, NULL, mt) < 0)
200             {
201               mtext_cat_char (mt, c);
202             }
203         }
204       if (ic->preedit)
205         mtext_cat (mt, ic->preedit);
206       minput_destroy_ic (ic);
207       minput_close_im (im);
208
209       len = mtext_len (mt);
210       if (len == 0)
211         {
212           m17n_object_unref (mt);
213           goto err;
214         }
215
216       mtext_put_prop (mt, 0, len, Mlanguage, lang);
217
218       memset (&control, 0, sizeof control);
219       control.enable_bidi = 1;
220
221       mdraw_text_extents (frame, mt, 0, len, &control, &ink, &logical, NULL);
222       ascent = - logical.y;
223       if (ascent < - ink.y)
224         ascent = -ink.y;
225       descent = logical.height + logical.y;
226       if (descent < ink.height + ink.y)
227         descent = ink.height + ink.y;
228       height = ascent + descent;
229       width = logical.width;
230       if (height == 0 || width == 0)
231         {
232           m17n_object_unref (mt);
233           goto err;
234         }
235
236       work = gdImageCreate (width, height);
237       work_white = gdImageColorAllocate (work, 255, 255, 255); 
238       gdImageColorTransparent (work, work_white);
239       gdImageFilledRectangle (work, 0, 0, width - 1, height - 1, work_white);
240       mdraw_text_with_control (frame, work, 0, ascent, mt, 0, len, &control);
241
242       converter = mconv_stream_converter (msymbol ("utf-8"), out);
243
244       fprintf (out, "1\n");
245       from = 0;
246       {
247         MDrawMetric *ink_array, *logical_array;
248         int array_size = len * 2;
249         int num_chars;
250         unsigned char *buf;
251         int size;
252     
253         ink_array = malloc (sizeof (MDrawMetric) * array_size);
254         logical_array = malloc (sizeof (MDrawMetric) * array_size);
255
256         if (mdraw_text_per_char_extents (frame, mt, 0, len, &control,
257                                          ink_array, logical_array,
258                                          array_size, &num_chars, NULL, NULL) < 0)
259           {
260             ink_array = realloc (ink_array, sizeof (MDrawMetric) * num_chars);
261             logical_array = realloc (logical_array, sizeof (MDrawMetric) * num_chars);
262             mdraw_text_per_char_extents (frame, mt, 0, len, &control,
263                                          ink_array, logical_array,
264                                          num_chars, &num_chars, NULL, NULL);
265           }
266
267         for (from = 0, i = 0; i < num_chars;)
268           {
269             gdImagePtr image;
270             int white;
271             int x = logical_array[i].x;
272
273             image = gdImageCreate (logical_array[i].width, height);
274             white = gdImageColorAllocate (image, 255, 255, 255); 
275             gdImageColorTransparent (image, white);
276             gdImageCopy (image, work, 0, 0,
277                          logical_array[i].x, 0, logical_array[i].width, height);
278             fprintf (out, "<img src=\"data:image/png;base64,");
279             buf = gdImagePngPtr (image, &size);
280             base64_encode (buf, size, out);
281             gdFree (buf);
282             gdImageDestroy (image);
283
284             while (++i < num_chars && logical_array[i].x == x);
285             if (i == num_chars)
286               to = len;
287             else
288               to = mdraw_coordinates_position (frame, mt, 0, len,
289                                                logical_array[i].x, 0, &control);
290             fprintf (out, "\" alt=\"");
291             mconv_encode_range (converter, mt, from, to);
292             fprintf (out, "\">");
293             from = to;
294           }
295         free (ink_array);
296         free (logical_array);
297       }
298       fprintf (out, "\n");
299       gdImageDestroy (work);
300       m17n_object_unref (mt);
301
302     err:
303       fclose (in);
304       fclose (out);
305     }
306
307   M17N_FINI ();
308   unlink (PIPE_IN);
309   unlink (PIPE_OUT);
310   exit (0);
311 }
312