part of -Wsign-compare
[alioth/magicpoint.git] / draw.c
1 /*
2  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "mgp.h"
30 #include <Imlib2.h>
31
32 /* state associated with the window - how should we treat this? */
33 static struct ctrl *bg_ctl, *bg_ctl_last, *bg_ctl_cache;
34 static int bgindex = 0;
35 struct render_state cache_state;
36
37 static struct pcache {
38         u_int flag;
39         u_int page;
40         u_int mgpflag;
41         u_int mode;
42         u_int effect;
43         u_int value;
44 } pcache;
45
46 #define COMPLEX_BGIMAGE (bg_ctl && \
47         ((bg_ctl->ct_op == CTL_BIMAGE) || bg_ctl->ct_op == CTL_BGRAD))
48
49 #define COMPLEX_BGIMAGE2 (0)
50
51 #define POSY(size)      (-(int)((size)/2))
52
53 static void process_direc(struct render_state *, int *);
54
55 static int set_position(struct render_state *);
56 static void draw_line_output(struct render_state *, char *);
57 static void cutin(struct render_state *, int, int, int);
58
59 static void draw_string(struct render_state *, char *);
60 static u_char *draw_fragment(struct render_state *, u_char *, u_int, const char *, int);
61 static struct render_object *obj_alloc(struct render_state *state);
62 static void obj_free(struct render_state *, struct render_object *);
63 static int obj_new_xfont(struct render_state *, int, int, int,
64         u_int, const char *);
65 static int obj_new_image2(struct render_state *, int, int, Image *, int, int, Imlib_Image *, int);
66 static int obj_new_icon(struct render_state *, int, int, u_int, u_int, u_long, u_int, XPoint *);
67 static Pixel obj_image_color(Image *, Image *, Pixel, int *);
68 static Image *obj_image_trans(Image *, u_int, u_int);
69 static void obj_draw_image(Drawable, u_int, u_int, struct render_object *, int);
70 static void obj_draw(struct render_state *, Drawable, u_int, u_int);
71 static char *x_fontname(char *, int, const char *, int, const char *);
72 static int x_parsefont(char *, int *, int*);
73 static XFontStruct *x_setfont(const char *, u_int, const char *, int *);
74 static u_int draw_onechar_x(struct render_state *, u_int, int, int, int,
75         const char *, int);
76
77 static void back_gradation(struct render_state *, struct ctrl_grad *);
78 static void image_load(struct render_state *, char *, int, int, int, int, int, int, int, int, int);
79 static void image_load_ps(struct render_state *, char *, int, int, int, int, int, int, int, int, int);
80 static void process_icon(struct render_state *, struct ctrl *);
81 static void draw_bar(struct render_state *, struct ctrl *);
82 static void process_system(struct render_state *, struct ctrl *);
83 static void process_xsystem(struct render_state *, struct ctrl *);
84 static void process_tsystem(struct render_state *, struct ctrl *);
85 static Window search_child_window(void);
86 static Window tsearch_child_window(const char *name);
87 static Window getNamedWindow(const char *name, Window top);
88 static void reparent_child_window(Window, int, int);
89 static char *epstoimage(const char *, int, int, int, int, int, int);
90 static void image_setcolor(struct render_state *);
91 static void x_registerseed(struct render_state *, char *, const char *);
92 static const char *x_findseed(struct render_state *, const char *);
93 static int get_regid(const char *);
94
95 static void XClearPixmap(Display *, Drawable);
96 static void cache_page(struct render_state *, int);
97 static void cache_effect1(void);
98 static void cache_effect2(void);
99 static void set_from_cache(struct render_state *);
100 static void pcache_process(int);
101 static void predraw(struct render_state *);
102 static void set_background_pixmap(struct ctrl *);
103 static void get_background_pixmap(struct ctrl *, struct render_state *);
104 static void regist_background_pixmap(XImageInfo *, Image *);
105 static int valign = VL_BOTTOM;
106
107 #define CHECK_CACHE     do {if (caching) {caching = -1; return; }} while (0)
108
109 static void set_xrender_color(long, int);
110 static XftDraw * xft_getdraw(Drawable);
111 static u_char *xft_draw_fragment(struct render_state *,
112     u_char *, u_int, const char *, int);
113 static int obj_new_xftfont(struct render_state *, int, int, u_char *,
114     int, const char *, const char *, int, int, XftFont *);
115 static XftFont * xft_setfont(const char *, int, const char *);
116 XftFont *xft_font;
117 XftDraw *xft_draw[2];
118 Drawable xft_xdraw[2];
119 XftColor xft_forecolor;
120 XRenderColor xft_render_color;
121
122 static void regist_zimage_position(struct render_object *, int, int, int, int, int);
123 static void clear_zimage(int);
124 static void clear_region(int, int, int, int);
125 #define ZIMAGENUM 100
126 static Imlib_Image *zimage[ZIMAGENUM];
127 static int zonzoom[ZIMAGENUM];
128 static int zpage[ZIMAGENUM];
129 static int zx[ZIMAGENUM];
130 static int zy[ZIMAGENUM];
131 static int zwidth[ZIMAGENUM];
132 static int zheight[ZIMAGENUM];
133
134 static int
135 ispsfilename(char *p0)
136 {
137         char *p;
138
139         p = p0;
140         while (*p)
141                 p++;
142         if (4 < p - p0 && strcasecmp(p - 4, ".eps") == 0)
143                 return 1;
144         if (3 < p - p0 && strcasecmp(p - 3, ".ps") == 0)
145                 return 1;
146         if (6 < p - p0 && strcasecmp(p - 6, ".idraw") == 0)
147                 return 1;
148         return 0;
149 }
150
151 /*
152  * state management.
153  */
154 void
155 state_goto(struct render_state *state, u_int page, int repaint)
156 {
157         if (!repaint) {
158                 purgechild(state->page);
159                 clear_zimage(state->page);
160         }
161
162         state->page = page;
163         state->line = 0;
164         state->cp = NULL;
165         state->phase = P_NONE;
166         free_alloc_colors(&image_clr);
167         free_alloc_colors(&font_clr);
168
169         colormap = XCopyColormapAndFree(display, colormap);
170         predraw(state);
171 }
172
173 void
174 state_next(struct render_state *state)
175 {
176
177         switch (state->phase) {
178         case P_NONE:
179                 fprintf(stderr, "internal error\n");
180                 break;
181         case P_DEFAULT:
182                 if (state->cp)
183                         state->cp = state->cp->ct_next;
184                 if (!state->cp) {
185                         state->cp = page_control[state->page][state->line];
186                         state->phase = P_PAGE;
187                 }
188                 break;
189         case P_PAGE:
190                 if (state->cp)
191                         state->cp = state->cp->ct_next;
192                 if (!state->cp) {
193                         state->line++;
194                         state->cp = NULL;
195                         state->phase = P_NONE;
196                         state_init(state);
197                 }
198                 break;
199
200         case P_END:
201                 /*nothing*/
202                 break;
203         }
204
205         /* next page */
206         if (page_attribute[state->page].pg_linenum < state->line) {
207                 if (state->page < maxpage) {
208                         purgechild(state->page);
209                         clear_zimage(state->page);
210                         if (mgp_flag & FL_FRDCACHE &&
211                                 cached_page == state->page + 1) {
212                                         /* Hit cache */
213                                         set_from_cache(state);
214                                         pcache_process(state->page);
215                                         cache_hit = 1;
216                         } else {
217                                 state->phase = P_NONE;
218                                 state->page++;
219                                 state->line = 0;
220                                 state_newpage(state);
221                                 state_init(state);
222                         }
223                 } else
224                         state->phase = P_END;
225         }
226 }
227
228 void
229 state_init(struct render_state *state)
230 {
231         assert(state);
232
233         if (state->phase == P_NONE || !state->cp) {
234                 state->cp = page_control[state->page][state->line];
235                 state->phase = P_PAGE;
236         }
237 }
238
239 void
240 state_newpage(struct render_state *state)
241 {
242         state->ypos = 0;
243         state->have_mark = 0;
244         state->charoff = 0;
245         char_size[caching] = nonscaled_size[caching];
246         free_alloc_colors(&image_clr);
247         free_alloc_colors(&font_clr);
248
249         colormap = XCopyColormapAndFree(display, colormap);
250         predraw(state);
251 }
252
253 /*
254  * page management.
255  */
256 void
257 draw_page(struct render_state *state, struct ctrl *lastcp)
258 {
259         int pause2;
260
261         assert(state);
262
263         /* initialize the state, if required. */
264         if (state->phase != P_END && (state->phase == P_NONE || !state->cp)) {
265                 state_newpage(state);
266                 state_init(state);
267         }
268
269         while (1) {
270                 switch (state->phase) {
271                 case P_NONE:
272                         fprintf(stderr, "internal error\n");
273                         cleanup(-1);
274                         /* NOTREACHED */
275                 case P_DEFAULT:
276                 case P_PAGE:
277                         pause2 = 0;
278                         if (state->cp)
279                                 process_direc(state, &pause2);
280                         if (caching == -1) {
281                                 /* caching failed */
282                                 caching = 0;
283                                 return;
284                         }
285                         if (lastcp && state->cp == lastcp)
286                                 goto done;
287                         if (pause2) {
288                                 if (state->cp
289                                  && state->cp->ct_op == CTL_PAUSE
290                                  && state->cp->cti_value) {
291                                         goto done;
292                                 }
293                         }
294                         break;
295                 case P_END:
296                         goto done;
297                 }
298                 state_next(state);
299         }
300 done:
301         XFlush(display);
302 }
303
304 Bool
305 draw_one(struct render_state *state, XEvent *e)
306 {
307         int pause2;
308         fd_set fds;
309         int xfd;
310         struct timeval tout;
311         long emask;
312 #ifdef TTY_KEYINPUT
313         KeySym ks;
314         char c;
315 #endif
316
317         assert(state);
318
319         /* initialize the state, if required. */
320         if (state->phase != P_END && (state->phase == P_NONE || !state->cp)) {
321                 state_newpage(state);
322                 state_init(state);
323         }
324
325         switch (state->phase) {
326         case P_DEFAULT:
327         case P_PAGE:
328                 pause2 = 0;
329                 if (state->cp)
330                         process_direc(state, &pause2);
331                 break;
332         case P_END:
333                 break;
334         case P_NONE:
335         default:
336                 fprintf(stderr, "internal error\n");
337                 cleanup(-1);
338         }
339         xfd = ConnectionNumber(display);
340         if (state->phase != P_END && !pause2)
341                 emask = xeventmask;
342         else
343                 emask = ~NoEventMask;
344         for (;;) {
345                 if (XCheckMaskEvent(display, emask, e) == True) {
346                         /* we got some event in the queue*/
347                         if (2 <= parse_debug) {
348                                 fprintf(stderr,
349                                         "interrupted and "
350                                         "got X11 event type=%d\n",
351                                         e->type);
352                         }
353   got_event:
354                         if (state->phase == P_END)
355                                 XFlush(display);
356                         else if (!pause2)
357                                 state_next(state);
358                         return True;
359                 }
360 #ifdef TTY_KEYINPUT
361                 if (ttykey_enable) {
362                         FD_ZERO(&fds);
363                         FD_SET(0, &fds);
364                         tout.tv_sec = tout.tv_usec = 0;
365                         if (select(1, &fds, NULL, NULL, &tout) > 0
366                         &&  read(0, &c, sizeof(c)) == sizeof(c)) {
367                                 if (c > 0 && c < ' ')
368                                         ks = 0xff00 | c;
369                                 else if (c >= ' ' && c < '\177')
370                                         ks = c;
371                                 else if (c == '\177')
372                                         ks = XK_Delete;
373                                 else
374                                         continue;
375                                 e->xkey.display = display;
376                                 e->xkey.type = KeyPress;
377                                 e->xkey.keycode = XKeysymToKeycode(display, ks);
378                                 if (e->xkey.keycode == 0)
379                                         continue;
380                                 goto got_event;
381                         }
382                 }
383 #endif
384                 if (state->phase != P_END && !pause2) {
385                         state_next(state);
386                         return False;
387                 }
388                 FD_ZERO(&fds);
389                 FD_SET(xfd, &fds);
390 #ifdef TTY_KEYINPUT
391                 if (ttykey_enable)
392                         FD_SET(0, &fds);
393 #endif
394                 remapchild();
395                 /* always cache next page */
396                 if ((mgp_flag & FL_FRDCACHE) && cache_mode) {
397                         if (XCheckMaskEvent(display, emask, e) == True)
398                                 goto got_event;
399                         cache_page(&cache_state, state->page +1);
400                         /* check if we got some events during caching */
401                         if (XCheckMaskEvent(display, emask, e) == True)
402                                 goto got_event;
403                 }
404
405                 /* wait for something */
406                 tout.tv_sec = 2;
407                 tout.tv_usec = 0;
408                 (void)select(xfd + 1, &fds, NULL, NULL, &tout);
409
410 #ifdef TTY_KEYINPUT
411                 if (!(mgp_flag & FL_NOSTDIN) && !ttykey_enable)
412                         try_enable_ttykey();
413 #endif
414                 /* we have no event in 2sec, so..*/
415                 if (!FD_ISSET(xfd, &fds)) {
416                         if ((mgp_flag & FL_FRDCACHE) && !cache_mode)
417                                 cache_page(&cache_state, state->page +1);
418                         timebar(state);
419                         e->type = 0;
420                         return True;
421                 }
422         }
423         /*NOTREACHED*/
424 }
425
426 static void
427 process_direc(struct render_state *state, int *seenpause)
428 {
429         struct ctrl *cp;
430
431         if (seenpause)
432                 *seenpause = 0;
433         cp = state->cp;
434
435         if (2 <= parse_debug) {
436                 fprintf(stderr, "p%d/l%d: ", state->page, state->line);
437                 debug0(cp);
438         }
439
440         switch(cp->ct_op) {
441         case CTL_SUP:
442                 if (sup_scale > 1.0 || sup_scale < 0.1) {
443                         sup_scale = DEFAULT_SUPSCALE;
444                 }
445                 if (sup_off > 1.0 || sup_scale < 0.1) {
446                         sup_off = DEFAULT_SUPOFF;
447                 }
448                 state->charoff = -sup_off * nonscaled_size[caching];
449                 char_size[caching] = (int)(nonscaled_size[caching] * sup_scale);
450                 break;
451         case CTL_SUB:
452                 if (sup_scale > 1.0 || sup_scale < 0.1) {
453                         sup_scale = DEFAULT_SUPSCALE;
454                 }
455                 if (sub_off > 1.0 || sub_off < 0.1){
456                         sub_off = DEFAULT_SUBOFF;
457                 }
458                 state->charoff = sub_off * nonscaled_size[caching];
459                 char_size[caching] = (int)(nonscaled_size[caching] * sup_scale);
460                 break;
461         case CTL_SETSUP:
462                 if (cp->cti3_value1 > 100 || cp->cti3_value1 < 10){
463                         sup_off = DEFAULT_SUPOFF;
464                 } else {
465                         sup_off = cp->cti3_value1 / 100.;
466                 }
467                 if (cp->cti3_value2 > 100 || cp->cti3_value2 < 10){
468                         sub_off = DEFAULT_SUBOFF;
469                 } else {
470                         sub_off = cp->cti3_value2 / 100.;
471                 }
472                 if (cp->cti3_value3 > 100 || cp->cti3_value3 < 10){
473                      sup_scale = DEFAULT_SUPSCALE;
474                 } else {
475                      sup_scale = cp->cti3_value3 / 100.;
476                 }
477                 break;
478         case CTL_SIZE:
479                 nonscaled_size[caching] = state->height * cp->ctf_value / 100;
480                 char_size[caching] = nonscaled_size[caching];
481                 break;
482
483         case CTL_VGAP:
484                 vert_gap[caching] = cp->cti_value;
485                 break;
486
487         case CTL_HGAP:
488                 horiz_gap[caching] = cp->cti_value;
489                 break;
490
491         case CTL_GAP:
492                 vert_gap[caching] = horiz_gap[caching] = cp->cti_value;
493                 break;
494
495         case CTL_QUALITY:
496                 if (!quality_flag)
497                         b_quality[caching] = cp->cti_value;
498                 break;
499
500         case CTL_PAUSE:
501                 CHECK_CACHE;
502                 if (seenpause)
503                         *seenpause = 1;
504                 break;
505
506         case CTL_AGAIN:
507                 CHECK_CACHE;
508                 if (state->have_mark)
509                         state->ypos = state->mark_ypos;
510                 state->have_mark = 0;
511                 break;
512
513         case CTL_FORE:
514                 fore_color[caching] = cp->ctl_value;
515                 XSetForeground(display, gcfore, fore_color[caching]);
516                 break;
517
518         case CTL_BACK:
519                 if (state->line){
520                         fprintf(stderr, "warning: %%back directive should be put in the first line of the page. ignored.\n");
521                         break;
522                 }
523                 back_color[caching] = cp->ctl_value;
524                 bg_ctl = cp;    /*update later*/
525                 break;
526
527         case CTL_CCOLOR:
528                 ctrl_color[caching] = cp->ctl_value;
529                 break;
530
531         case CTL_CENTER:
532                 state->align = AL_CENTER;
533                 break;
534
535         case CTL_LEFT:
536                 state->align = AL_LEFT;
537                 break;
538
539         case CTL_LEFTFILL:
540                 state->align = AL_LEFTFILL0;
541                 break;
542
543         case CTL_RIGHT:
544                 state->align = AL_RIGHT;
545                 break;
546
547         case CTL_CONT:
548                 state->charoff = 0;
549                 char_size[caching] = nonscaled_size[caching];
550                 break;
551
552         case CTL_XFONT2:
553                 x_registerseed(state, cp->ctc2_value1, cp->ctc2_value2);
554                 break;
555
556         case CTL_BAR:
557                 draw_bar(state, cp);
558                 break;
559
560         case CTL_IMAGE:
561             {
562                 if (state->align == AL_LEFTFILL0) {
563                         state->align = AL_LEFTFILL1;
564                         state->leftfillpos = state->linewidth;
565                 }
566
567                 /* quickhack for postscript */
568                 if (ispsfilename(cp->ctm_fname)) {
569                         image_load_ps(state, cp->ctm_fname, cp->ctm_numcolor,
570                                 cp->ctm_ximagesize, cp->ctm_yimagesize, 0,
571                                 cp->ctm_zoomflag, 0, cp->ctm_raise, cp->ctm_rotate, cp->ctm_zoomonclk);
572                 } else {
573                         image_load(state, cp->ctm_fname, cp->ctm_numcolor,
574                                 cp->ctm_ximagesize, cp->ctm_yimagesize, 0,
575                                 cp->ctm_zoomflag, 0, cp->ctm_raise, cp->ctm_rotate, cp->ctm_zoomonclk);
576                 }
577                 state->brankline = 0;
578             }
579                 break;
580
581         case CTL_BIMAGE:
582                 if (mgp_flag & FL_BIMAGE)
583                         break;
584                 bg_ctl = cp;    /*update later*/
585                 break;
586
587         case CTL_BGRAD:
588                 if (mgp_flag & FL_BIMAGE)
589                         break;
590                 bg_ctl = cp;    /*update later*/
591                 break;
592
593         case CTL_LCUTIN:
594                 CHECK_CACHE;
595                 state->special = SP_LCUTIN;
596                 break;
597
598         case CTL_RCUTIN:
599                 CHECK_CACHE;
600                 state->special = SP_RCUTIN;
601                 break;
602
603         case CTL_SHRINK:
604                 CHECK_CACHE;
605                 state->special = SP_SHRINK;
606                 break;
607
608         case CTL_PREFIX:
609                 state->curprefix = cp->ctc_value;
610                 break;
611
612         case CTL_PREFIXN:
613                 state->xprefix = state->width * cp->ctf_value / 100;
614                 break;
615
616         case CTL_TABPREFIX:
617                 state->tabprefix = cp->ctc_value;
618                 break;
619
620         case CTL_TABPREFIXN:
621                 state->tabxprefix = state->width * cp->ctf_value / 100;
622                 break;
623
624         case CTL_PREFIXPOS:
625             {
626                 char *p;
627
628                 p = (state->tabprefix) ? state->tabprefix : state->curprefix;
629                 if (p)
630                         draw_line_output(state, p);
631                 break;
632             }
633
634         case CTL_TEXT:
635                 if (!cp->ctc_value)
636                         break;
637                 if (state->align == AL_LEFTFILL0) {
638                         state->align = AL_LEFTFILL1;
639                         state->leftfillpos = state->linewidth;
640                 }
641                 draw_line_output(state, cp->ctc_value);
642                 break;
643
644         case CTL_LINESTART:
645                 state->charoff = 0;
646                 char_size[caching] = nonscaled_size[caching];
647                 if (state->line == 0) {
648                         /*
649                          * set background of target
650                          */
651                         if (bg_ctl) {
652                                 if (!caching){
653                                         /* target is window, so we need care bg_ctl_last */
654                                         if (bg_ctl_last && !ctlcmp(bg_ctl, bg_ctl_last)){
655                                                 /* same as last time, we do nothing  */
656                                                 ;
657                                         } else {
658                                                 /* we have to change background */
659                                                 get_background_pixmap(bg_ctl, state);
660
661                                                 /* set window background */
662                                                 set_background_pixmap(bg_ctl);
663
664                                                 bg_ctl_last = bg_ctl;
665                                         }
666                                         XClearWindow(display, state->target);
667                                 } else {
668                                         get_background_pixmap(bg_ctl, state);
669                                         bg_ctl_cache = bg_ctl;
670
671                                         XClearPixmap(display, state->target);
672                                 }
673                         } else {
674                                 if (!caching)
675                                         XClearWindow(display, state->target);
676                                 else
677                                         XClearPixmap(display, state->target);
678                         }
679
680                         if (t_fin)
681                                 timebar(state);
682                 }
683                 draw_line_start(state);
684                 break;
685
686         case CTL_LINEEND:
687                 /* blank lines */
688                 if (state->brankline) { /*XXX*/
689                         state->max_lineascent = char_size[caching];
690                         state->maxascent = char_size[caching];
691                         state->maxdescent = VERT_GAP(char_size[caching]);
692                 }
693                 draw_line_end(state);
694                 /* reset single-line oriented state */
695                 state->tabprefix = NULL;
696                 state->tabxprefix = 0;
697                 state->special = 0;
698                 if (state->align == AL_LEFTFILL1) {
699                         state->align = AL_LEFTFILL0;
700                         state->leftfillpos = 0;
701                 }
702                 break;
703
704         case CTL_MARK:
705                 state->have_mark = 1;
706                 state->mark_ypos = state->ypos;
707                 break;
708
709         case CTL_SYSTEM:
710                 CHECK_CACHE;
711                 process_system(state, cp);
712                 break;
713
714         case CTL_XSYSTEM:
715                 CHECK_CACHE;
716                 process_xsystem(state, cp);
717                 break;
718
719         case CTL_TSYSTEM:
720                 CHECK_CACHE;
721                 process_tsystem(state, cp);
722                 break;
723
724         case CTL_ICON:
725                 process_icon(state, cp);
726                 break;
727
728         case CTL_NOOP:
729         case CTL_NODEF:
730         case CTL_TITLE:
731                 break;
732
733         case CTL_XFONT:
734                 /* obsolete directives */
735                 fprintf(stderr, "internal error: obsolete directive "
736                         "\"%s\"\n", ctl_words[cp->ct_op].ctl_string);
737                 exit(1);
738                 /*NOTREACHED*/
739
740         case CTL_PCACHE:
741                 if (!caching) {
742                         if (cp->ctch_flag)
743                                 mgp_flag |= FL_FRDCACHE;
744                         else
745                                 mgp_flag ^= FL_FRDCACHE;
746                         cache_mode   = cp->ctch_mode;
747                         cache_effect = cp->ctch_effect;
748                         cache_value  = cp->ctch_value;
749                 } else {
750                         pcache.flag = 1;
751                         pcache.page = state->page;
752                         pcache.mgpflag = cp->ctch_flag;
753                         pcache.mode = cp->ctch_mode;
754                         pcache.effect = cp->ctch_effect;
755                         pcache.value = cp->ctch_value;
756                 }
757                 break;
758
759         case CTL_CHARSET:
760                 if (get_regid(cp->ctc_value) < 0){
761                         fprintf(stderr, "invalid charset \"%s\". ignored\n",
762                                 cp->ctc_value);
763                         break;
764                 }
765                 strlcpy(mgp_charset, cp->ctc_value, sizeof(mgp_charset));
766                 break;
767
768         case CTL_VALIGN:
769                 valign = cp->cti_value;
770                 break;
771
772         case CTL_AREA:
773                 state->width = window_width * cp->ctar_width / 100;
774                 state->height = window_height * cp->ctar_height / 100;
775                 state->xoff = window_width * cp->ctar_xoff / 100;
776                 state->yoff = window_height * cp->ctar_yoff / 100;
777                 state->ypos = 0;
778                 break;
779
780         case CTL_OPAQUE:
781                 if (cp->cti_value > 100){
782                         fprintf(stderr, "%%opaque: value should be 0-100\n");
783                         cp->cti_value = 100;
784                 }
785                 state->opaque = cp->cti_value;
786                 if (mgp_flag & FL_NOXFT && verbose){
787                         fprintf(stderr, "ignored %%opaque.\n");
788                 }
789                 break;
790         case CTL_PSFONT:
791                 break;
792         default:
793                 fprintf(stderr,
794                         "undefined directive %d at page %d line %d:\n\t",
795                         cp->ct_op, state->page, state->line);
796                 debug0(cp);
797                 break;
798         }
799 }
800
801 /*
802  * line management.
803  */
804 static int
805 set_position(struct render_state *state)
806 {
807         int x;
808
809         x = 0;
810         switch (state->align) {
811         case AL_CENTER:
812                 x = (state->width - state->linewidth)/ 2;
813                 break;
814
815         case AL_LEFT:
816         case AL_LEFTFILL0:
817         case AL_LEFTFILL1:
818                 x = 0;
819                 break;
820
821         case AL_RIGHT:
822                 x = state->width - state->linewidth;
823                 break;
824         }
825
826         return x;
827 }
828
829 void
830 draw_line_start(struct render_state *state)
831 {
832         struct render_object *obj;
833
834         state->max_lineascent = 0;
835         state->max_linedescent = 0;
836         state->maxascent = 0;
837         state->maxdescent = 0;
838         state->linewidth = 0;
839         state->brankline = 1;
840         while ((obj = state->obj))
841                 obj_free(state, obj);
842 }
843
844 void
845 draw_line_itemsize(struct render_state *state,
846     int ascent, int descent, int flheight)
847 {
848         ascent -= state->charoff;
849         descent += state->charoff;
850         if (ascent > state->maxascent)
851                 state->maxascent = ascent;
852         if (descent > state->maxdescent)
853                 state->maxdescent = descent;
854
855         /*
856          * calculation for the height of a line should ignore
857          * character offset
858          */
859         if (state->charoff == 0) {
860                 if (ascent > state->max_lineascent)
861                         state->max_lineascent = ascent;
862                 if (descent > state->max_linedescent)
863                         state->max_linedescent = descent;
864         }
865
866         if (flheight > state->maxflheight)
867                 state->maxflheight = flheight;
868 }
869
870 static void
871 draw_line_output(struct render_state *state, char *data)
872 {
873         draw_string(state, data);
874 }
875
876 void
877 draw_line_end(struct render_state *state)
878 {
879         int xpos;
880
881         xpos = set_position(state);
882
883         /* process the special attribute. */
884         switch (state->special) {
885         case SP_LCUTIN:
886                 cutin(state, xpos, state->ypos, 1);
887                 break;
888         case SP_RCUTIN:
889                 cutin(state, xpos, state->ypos, -1);
890                 break;
891         default:
892                 break;
893         }
894         if (state->obj) {
895                 obj_draw(state, state->target, xpos, state->ypos);
896                 while (state->obj)
897                         obj_free(state, state->obj);
898         }
899
900         state->ypos += state->max_lineascent;
901
902         /*
903          * we should ignore height of images to calculate line gap.
904          * suggested by Toru Terao
905          */
906         if (VERT_GAP(char_size[caching]) < state->max_linedescent)
907                 state->ypos += state->max_linedescent;
908         else
909                 state->ypos += VERT_GAP(char_size[caching]);
910
911         state->ypos += 2;
912 }
913
914 #undef min
915 #define min(x, y) (x < y ? x: y)
916 static void
917 cutin(struct render_state *state, int lx, int ly, int dir)
918 {
919         u_int x, xoff, yoff;
920         int i, sx, round2;
921         int root_x, root_y, use_copy;
922         Window cutinWin = 0, junkwin;
923         XImage *copywin;
924         static XWindowAttributes xa;
925         XWindowAttributes wa;
926         Pixmap ghostWin;
927         GC saveGC = gc_cache;
928
929         XGetWindowAttributes(display, window, &wa);
930         ghostWin = XCreatePixmap(display, window, wa.width, wa.height, wa.depth);
931         /* all drawing should be done on the image */
932         gc_cache = XCreateGC(display, ghostWin, 0, 0);
933         XCopyArea(display, state->target, ghostWin, gc_cache,
934                         0, 0, wa.width, wa.height, 0, 0);
935
936         if (state->repaint)
937                 return;
938
939         if (!state->linewidth)
940                 return;
941
942         if (!xa.width)
943                 XGetWindowAttributes(display, DefaultRootWindow(display), &xa);
944         XTranslateCoordinates(display, window, DefaultRootWindow(display),
945                 0, 0, &root_x ,&root_y, &junkwin);
946         use_copy = 1;
947         if ((root_x + window_width > xa.width) || (root_y + window_height > xa.height) ||
948                         (root_x < 0 || root_y < 0)) use_copy = 1;
949
950         sx = (0 < dir) ? 0 : state->width - state->linewidth;
951         round2 = 20;    /*XXX*/
952 #ifndef abs
953 #define abs(a)  (((a) < 0) ? -(a) : (a))
954 #endif
955         if (abs(lx - sx) < round2){
956                 round2 = abs(lx - sx);
957                 if (!round2) round2 = 1;
958         }
959
960         if (!use_copy){
961                 cutinWin = XCreateSimpleWindow(display, state->target,
962                         sx, ly, state->linewidth, state->maxascent + state->maxdescent,
963                         0, fore_color[caching], back_color[caching]);
964                 XSetWindowBackgroundPixmap(display, cutinWin, None);
965                 XMapSubwindows(display, state->target);
966         } else {
967                 copywin = XGetImage(display, window, state->xoff + min(sx, lx), ly + state->yoff, state->linewidth + abs(lx - sx),
968                                         state->maxascent + state->maxdescent, AllPlanes, ZPixmap);
969         }
970
971         xoff = state->xoff;
972         yoff = state->yoff;
973         state->xoff = state->yoff = 0;
974         if (state->obj && !use_copy) {
975                 obj_draw(state, cutinWin, 0, 0);
976         }
977         XFlush(display);
978
979         x = sx;
980         for (i = 0; i < round2; i++) {
981                 if (use_copy && state->obj) {
982                                 obj_draw(state, ghostWin, x + xoff, ly + yoff);
983                                 XCopyArea(display, ghostWin, state->target,
984                                     saveGC,
985                                     xoff + min(sx, lx),
986                                     ly + yoff,
987                                     state->linewidth + abs(lx - sx),
988                                     state->maxascent + state->maxdescent,
989                                     xoff + min(sx, lx),
990                                     ly + yoff);
991                 } else
992                         XMoveWindow(display, cutinWin, x + xoff, ly + yoff);
993
994                 XFlush(display);
995                 usleep(CUTIN_DELAY);
996                 if (use_copy && state->obj) {
997                         XPutImage(display, ghostWin, gc_cache, copywin,
998                                 x - min(sx, lx) , 0, x + xoff, ly + yoff,
999                                 state->linewidth, state->maxascent + state->maxdescent);
1000                 }
1001                 x = sx + ((i+1)*(lx - sx)) / round2;
1002         }
1003         XCopyArea(display, ghostWin, state->target, saveGC,
1004                 0, 0, wa.width, wa.height, 0, 0);
1005
1006         if (!use_copy) XDestroyWindow(display, cutinWin);
1007         state->xoff = xoff;
1008         state->yoff = yoff;
1009
1010         /* freeing images */
1011         if(use_copy) XFree(copywin);
1012
1013         /* restoring tho old GC */
1014         XFreeGC(display, gc_cache);
1015         XFreePixmap(display, ghostWin);
1016         gc_cache = saveGC;
1017 }
1018
1019 /*
1020  * render characters.
1021  */
1022 static void
1023 draw_string(struct render_state *state, char *data)
1024 {
1025         u_char *p, *q;
1026         const char *registry = NULL;
1027         u_int code2;
1028         static const char *rtab96[] = {
1029                 NULL,                   /* ESC - @ */
1030                 "iso8859-1",            /* ESC - A */
1031                 "iso8859-2",            /* ESC - B */
1032                 "iso8859-3",            /* ESC - C */
1033                 "iso8859-4",            /* ESC - D */
1034         };
1035 #define RTAB96_MAX      (sizeof(rtab96)/sizeof(rtab96[0]))
1036         static const char *rtab9494[] = {
1037                 "jisx0208.1978-*",      /* ESC $ @ or ESC $ ( @ */
1038                 "gb2312.1980-*",        /* ESC $ A or ESC $ ( A */
1039                 "jisx0208.1983-*",      /* ESC $ B or ESC $ ( B */
1040                 "ksc5601.1987-*",       /* ESC $ ( C */
1041                 NULL,                   /* D */
1042                 NULL,                   /* E */
1043                 NULL,                   /* F */
1044                 NULL,                   /* G */
1045                 NULL,                   /* H */
1046                 NULL,                   /* I */
1047                 NULL,                   /* J */
1048                 NULL,                   /* K */
1049                 NULL,                   /* L */
1050                 NULL,                   /* M */
1051                 NULL,                   /* N */
1052                 "jisx0213.2000-1",      /* ESC $ ( O */
1053                 "jisx0213.2000-2",      /* ESC $ ( P */
1054         };
1055 #define RTAB9494_MAX    (sizeof(rtab9494)/sizeof(rtab9494[0]))
1056         int charset16 = 0;
1057
1058         p = (u_char *)data;
1059         while (*p && *p != '\n') {
1060                 /* 94x94 charset */
1061                 if (p[0] == 0x1b && p[1] == '$' &&
1062                     '@' <= p[2] && p[2] < 'C' && rtab9494[p[2] - '@']) {
1063                         registry = rtab9494[p[2] - '@'];
1064                         charset16 = 1;
1065                         p += 3;
1066                         continue;
1067                 }
1068                 if (p[0] == 0x1b && p[1] == '$' && p[2] == '(' &&
1069                     '@' <= p[3] && p[3] < '@' + RTAB9494_MAX &&
1070                     rtab9494[p[3] - '@']) {
1071                         registry = rtab9494[p[3] - '@'];
1072                         charset16 = 1;
1073                         p += 4;
1074                         continue;
1075                 }
1076                 /* ascii (or JIS roman) */
1077                 if (p[0] == 0x1b && p[1] == '(' &&
1078                     (p[2] == 'B' || p[2] == 'J')) {
1079                         registry = NULL;
1080                         charset16 = 0;
1081                         p += 3;
1082                         continue;
1083                 }
1084                 /* 96 charset */
1085                 if (p[0] == 0x1b && p[1] == '-' &&
1086                     '@' < p[2] && p[2] < '@' + RTAB96_MAX &&
1087                     rtab96[p[2] - '@']) {
1088                         registry = rtab96[p[2] - '@'];
1089                         charset16 = 0;
1090                         p += 3;
1091                         continue;
1092                 }
1093
1094                 if (!registry && isspace(p[0])) {
1095                         draw_fragment(state, p, 1, registry, 0);
1096                         p++;
1097                         continue;
1098                 }
1099
1100                 if (charset16) {
1101                         for (q = p + 2; 0x21 <= *q && *q <= 0x7e; q += 2) {
1102                                 code2 = q[0] * 256 + q[1];
1103                                 if (strncmp(registry, "jisx0208", 8) == 0
1104                                  && !iskinsokuchar(code2)) {
1105                                         break;
1106                                 }
1107                         }
1108                 } else {
1109                         q = p;
1110                         while (*q && isprint(*q) && !isspace(*q))
1111                                 q++;
1112                         if (q == p)
1113                                 q++;
1114                         else {
1115                                 /*
1116                                  * append spaces to the end of the word.
1117                                  * fragments in the following line:
1118                                  *      "this is test"
1119                                  * are:
1120                                  *      "this_" "is_" "test"
1121                                  */
1122                                 while (*q && isspace(*q))
1123                                         q++;
1124                         }
1125                 }
1126
1127                 q = draw_fragment(state, p, q - p, registry, charset16);
1128
1129                 p = q;
1130         }
1131 }
1132
1133 static u_char *
1134 draw_fragment(struct render_state *state, u_char *p, u_int len,
1135     const char *registry, /* 2-octet charset? */ int charset16)
1136 {
1137         u_int char_len, i;
1138         u_short code;
1139         struct render_object *tail;
1140         struct render_object *thisline;
1141         struct render_object *thislineend;
1142         u_int startwidth;
1143         struct render_state backup0, backup;
1144         enum { MODE_UNKNOWN, MODE_X }
1145                 mode = MODE_UNKNOWN;
1146
1147         if (!(mgp_flag & FL_NOXFT)){
1148                 u_char *p0 = xft_draw_fragment(state, p, len, registry, charset16);
1149                 if (p0) return p0;
1150         }
1151
1152         if (state->obj)
1153                 tail = state->objlast;
1154         else
1155                 tail = NULL;
1156         startwidth = state->linewidth;
1157
1158         while (len) {
1159                 code = charset16 ? p[0] * 256 + p[1] : p[0];
1160                 if (code != ' ')
1161                         state->brankline = 0; /* This isn't brankline */
1162
1163                 if (code == '\t') {
1164                         char_len = char_size[caching] / 2;
1165                         p++;
1166                         len--;
1167
1168                         char_len = HORIZ_STEP(char_size[caching], char_len) * 8;/*XXX*/
1169                         state->linewidth = (state->linewidth + char_len) / char_len * char_len;
1170                         continue;
1171                 }
1172
1173                 /*
1174                  * decide which font to use.
1175                  * Japanese font:
1176                  *      VFlib - optional
1177                  *      then X.
1178                  * Western font:
1179                  *      X if truely scalable.
1180                  *      otherwise, X.
1181                  */
1182                 mode = MODE_UNKNOWN;
1183                 if (charset16) {
1184                         if (mode == MODE_UNKNOWN)
1185                                 mode = MODE_X;
1186                 } else {
1187                         if (mode == MODE_UNKNOWN) {
1188                                 /*
1189                                  * if we can have X font that is exactly
1190                                  * matches the required size, we use that.
1191                                  */
1192                                 int ts;
1193
1194                                 x_setfont(x_findseed(state, registry),
1195                                     char_size[caching], registry, &ts);
1196                                 if (ts)
1197                                         mode = MODE_X;
1198                         }
1199
1200                         /* last resort: use X font. */
1201                         if (mode == MODE_UNKNOWN)
1202                                 mode = MODE_X;
1203                 }
1204
1205                 /* back it up before drawing anything */
1206                 memcpy(&backup0, state, sizeof(struct render_state));
1207
1208                 switch (mode) {
1209                 default:
1210                         fprintf(stderr, "invalid drawing mode %d for %04x "
1211                                 "- fallback to X11\n", mode, code);
1212                         /* fall through */
1213                 case MODE_UNKNOWN:
1214                 case MODE_X:
1215                         char_len = draw_onechar_x(state, code,
1216                                 state->linewidth, state->charoff, char_size[caching],
1217                                 registry, (len == (charset16 ? 2 : 1)) ? 1 : 0);
1218                         if (char_len == 0) {
1219                                 fprintf(stderr, "can't load font size %d "
1220                                         "(nor font in similar size) for "
1221                                         "font <%s:%d:%s>, glyph 0x%04x\n",
1222                                         char_size[caching], x_findseed(state, registry),
1223                                         char_size[caching], registry?registry:"NULL", code);
1224                         }
1225                         break;
1226                 }
1227
1228                 p += (charset16 ? 2 : 1);
1229                 len -= (charset16 ? 2 : 1);
1230
1231                 state->linewidth += HORIZ_STEP(char_size[caching], char_len);
1232                 /* ukai */
1233                 if (!charset16 && state->linewidth + HORIZ_STEP(char_size[caching],
1234                                 char_len) > state->width) {
1235                         if (len >= 20) break; /* too long word */
1236                         for (i = 0; i < len; i ++){
1237                                 if (isspace(*(p +i))) break;
1238                         }
1239                         if (i == len) break;
1240                 }
1241         }
1242
1243         if (state->width - state->leftfillpos / 2 < state->linewidth) {
1244                 memcpy(&backup, state, sizeof(struct render_state));
1245
1246                 /* strip off the last fragment we wrote. */
1247                 if (tail) {
1248                         thisline = tail->next;
1249                         thislineend = state->objlast;
1250                         tail->next = NULL;
1251                         state->objlast = tail;
1252                         state->maxascent = backup0.maxascent;
1253                         state->maxdescent = backup0.maxdescent;
1254                 } else {
1255                         thisline = state->obj;
1256                         thislineend = state->objlast;
1257                         state->obj = state->objlast = NULL;
1258                         state->maxascent = backup0.maxascent;
1259                         state->maxdescent = backup0.maxdescent;
1260                 }
1261                 state->linewidth = startwidth;
1262                 draw_line_end(state);   /* flush the line. */
1263
1264                 /* start the new line with the last fragment we wrote. */
1265                 draw_line_start(state);
1266                 state->linewidth = state->leftfillpos;
1267                 state->linewidth += (backup.linewidth - startwidth);
1268                 if (state->obj && state->objlast)
1269                         state->objlast->next = thisline;
1270                 else
1271                         state->obj = thisline;
1272                 state->objlast = thislineend;
1273                 state->align = backup.align;
1274                 /* fix up x position and maxascent. */
1275                 for (tail = state->obj; tail; tail = tail->next) {
1276                         tail->x -= startwidth;
1277                         tail->x += state->leftfillpos;
1278                         draw_line_itemsize(state, tail->ascent, tail->descent, 0);
1279                 }
1280         }
1281         return p;
1282 }
1283
1284 static struct render_object *
1285 obj_alloc(struct render_state *state)
1286 {
1287         struct render_object *obj;
1288
1289         obj = malloc(sizeof(*obj));
1290         if (obj == NULL)
1291                 return NULL;
1292         obj->next = NULL;
1293         if (state->obj == NULL)
1294                 state->obj = obj;
1295         else
1296                 state->objlast->next = obj;
1297         state->objlast = obj;
1298         return obj;
1299 }
1300
1301 static void
1302 obj_free(struct render_state *state, struct render_object *obj)
1303 {
1304         struct render_object *o;
1305
1306         if (state->obj == obj)
1307                 state->obj = obj->next;
1308         else {
1309                 for (o = state->obj; o; o = o->next)
1310                         if (o->next == obj)
1311                                 break;
1312                 /* ASSERT(o != NULL); */
1313                 o->next = obj->next;
1314         }
1315         if (state->objlast == obj)
1316                 state->objlast = obj->next;
1317         switch (obj->type) {
1318         case O_IMAGE:
1319                 freeImage(obj->data.image.image);
1320                 break;
1321         case O_XFONT:
1322                 free(obj->data.xfont.xfont);
1323                 break;
1324         case O_ICON:
1325                 if (obj->data.icon.xpoint)
1326                         free(obj->data.icon.xpoint);
1327                 break;
1328         case O_XTFONT:
1329                 if (obj->data.xftfont.data)
1330                         free(obj->data.xftfont.data);
1331                 if (obj->data.xftfont.fontname)
1332                         free(obj->data.xftfont.fontname);
1333                 if (obj->data.xftfont.registry)
1334                         free(obj->data.xftfont.registry);
1335                 break;
1336         }
1337         free(obj);
1338 }
1339
1340 static int
1341 obj_new_xfont(struct render_state *state,
1342     int x, int y, int size, u_int code, const char *registry)
1343 {
1344         struct render_object *obj;
1345
1346         obj = obj_alloc(state);
1347         if (obj == NULL)
1348                 return 0;
1349         obj->x = x;
1350         obj->y = y;
1351         obj->fore = fore_color[caching];
1352         obj->type = O_XFONT;
1353         obj->data.xfont.xfont = strdup(x_findseed(state, registry));
1354         obj->data.xfont.csize = size;
1355         obj->data.xfont.code = code;
1356         obj->data.xfont.registry = registry;
1357         obj->ascent = size - y; /*XXX*/
1358         obj->descent = -y;      /*XXX*/
1359         obj->vertloc = VL_BASE;
1360         return 1;
1361 }
1362
1363 static int
1364 obj_new_image2(struct render_state *state,
1365     int x, int y, Image *image, int xzoom, int yzoom,
1366     Imlib_Image *imimage, int zoomonclk)
1367 {
1368         struct render_object *obj;
1369
1370         obj = obj_alloc(state);
1371         if (obj == NULL)
1372                 return 0;
1373         obj->x = x;
1374         obj->y = y;
1375         obj->type = O_IMAGE;
1376         obj->data.image.image = image;
1377         obj->data.image.xzoom = xzoom;
1378         obj->data.image.yzoom = yzoom;
1379         obj->ascent = 0;        /*XXX*/
1380         obj->descent = image->height * yzoom / 100;     /*XXX*/
1381         obj->vertloc = VL_TOP;
1382         obj->data.image.imimage = imimage;
1383         obj->data.image.zoomonclk = zoomonclk;
1384         return 1;
1385 }
1386
1387 static int
1388 obj_new_icon(struct render_state *state, int x, int y,
1389     u_int itype, u_int isize, u_long color, u_int npoint, XPoint *xpoint)
1390 {
1391         struct render_object *obj;
1392         int i;
1393
1394         obj = obj_alloc(state);
1395         if (obj == NULL)
1396                 return 0;
1397         obj->x = x;
1398         obj->y = y;
1399         obj->fore = color;
1400         obj->type = O_ICON;
1401         obj->data.icon.itype = itype;
1402         obj->data.icon.isize = isize;
1403         obj->data.icon.npoint = npoint;
1404         if (npoint) {
1405                 obj->data.icon.xpoint = malloc(sizeof(XPoint) * npoint);
1406                 if (obj->data.icon.xpoint == NULL) {
1407                         obj_free(state, obj);
1408                         return 0;
1409                 }
1410                 for (i = 0; i < npoint; i++)
1411                         obj->data.icon.xpoint[i] = xpoint[i];
1412         } else
1413                 obj->data.icon.xpoint = NULL;
1414         obj->ascent = 0;        /*XXX*/
1415         obj->descent = isize;   /*XXX*/
1416         obj->vertloc = VL_CENTER;
1417         return 1;
1418 }
1419
1420 static Pixel
1421 obj_image_color(Image *image, Image *bimage, Pixel d, int *inithist)
1422 {
1423         int i, j;
1424         RGBMap rgb;
1425         int r, g, b;
1426         static char hist[256];
1427         byte *p;
1428
1429         switch (bimage->type) {
1430         case IBITMAP:
1431                 r = g = b = d ? 0xffff : 0;
1432                 break;
1433         case IRGB:
1434                 r = bimage->rgb.red[d];
1435                 g = bimage->rgb.green[d];
1436                 b = bimage->rgb.blue[d];
1437                 break;
1438         case ITRUE:
1439                 r = TRUE_RED(d) << 8;
1440                 g = TRUE_GREEN(d) << 8;
1441                 b = TRUE_BLUE(d) << 8;
1442                 break;
1443         default:
1444                 return 0;
1445         }
1446         if (image->type == ITRUE)
1447                 return RGB_TO_TRUE(r, g, b);
1448
1449         for (i = 0; i < image->rgb.used; i++) {
1450                 if (image->rgb.red[i] == r &&
1451                     image->rgb.green[i] == g &&
1452                     image->rgb.blue[i] == b)
1453                         return i;
1454         }
1455         if (i >= image->rgb.size) {
1456                 if (i >= 256) {
1457                         /* search a free slot */
1458                         if (image->rgb.size == 256) {
1459                                 if (!*inithist) {
1460                                         *inithist = 1;
1461                                         memset(hist, 0, sizeof(hist));
1462                                         p = image->data;
1463                                         for (j = 0; j < image->height; j++)
1464                                                 for (i = 0; i < image->width; i++)
1465                                                         hist[*p++] = 1;
1466                                 }
1467                                 for (i = 0; i < 256; i++) {
1468                                         if (hist[i] == 0) {
1469                                                 hist[i] = 1;
1470                                                 goto freeslot;
1471                                         }
1472                                 }
1473                         }
1474                         return -1;
1475                 }
1476                 image->depth = 8;
1477                 newRGBMapData(&rgb, depthToColors(image->depth));
1478                 for (i = 0; i < image->rgb.used; i++) {
1479                         rgb.red[i] = image->rgb.red[i];
1480                         rgb.green[i] = image->rgb.green[i];
1481                         rgb.blue[i] = image->rgb.blue[i];
1482                 }
1483                 rgb.used = i;
1484                 freeRGBMapData(&image->rgb);
1485                 image->rgb = rgb;
1486         }
1487   freeslot:
1488         image->rgb.red[i] = r;
1489         image->rgb.green[i] = g;
1490         image->rgb.blue[i] = b;
1491         if (image->rgb.used < i + 1)
1492                 image->rgb.used = i + 1;
1493         return i;
1494 }
1495
1496 static Image *
1497 obj_image_trans(Image *image, u_int x, u_int y)
1498 {
1499         Image *timage;
1500         int i, j;
1501         byte *p, *b;
1502         Pixel d, n, pd;
1503         static XColor xcol;
1504         int pl, bpl;
1505         int trans;
1506         u_int bw, bh, bx, by;
1507         int inithist;
1508
1509         if (!COMPLEX_BGIMAGE) {
1510                 if (back_color[caching] != xcol.pixel) {
1511                         xcol.pixel = back_color[caching];
1512                         xcol.flags = DoRed|DoGreen|DoBlue;
1513                         XQueryColor(display, colormap, &xcol);
1514                 }
1515                 switch (image->type) {
1516                 case IBITMAP:
1517                 case IRGB:
1518                         image->rgb.red[image->trans] = xcol.red;
1519                         image->rgb.green[image->trans] = xcol.green;
1520                         image->rgb.blue[image->trans] = xcol.blue;
1521                         break;
1522                 case ITRUE:
1523                         d = image->trans;
1524                         n = RGB_TO_TRUE(xcol.red, xcol.green, xcol.blue);
1525                         pl = image->pixlen;
1526                         p = image->data;
1527                         for (j = 0; j < image->height; j++) {
1528                                 for (i = 0; i < image->width; i++, p += pl) {
1529                                         if (memToVal(p, pl) == d)
1530                                                 valToMem(n, p, pl);
1531                                 }
1532                         }
1533                         break;
1534                 }
1535                 bw = bh = 0;    /* for lint */
1536                 goto end;
1537         }
1538         bh = bgpixmap[bgindex].image->height;
1539         bw = bgpixmap[bgindex].image->width;
1540         j = 0;
1541         if (image->type == IBITMAP) {
1542   expand:
1543                 timage = image;
1544                 if (verbose)
1545                         fprintf(stderr, "obj_image_trans: expanding image\n");
1546                 image = expand(image);
1547                 if (image != timage)
1548                         freeImage(timage);
1549         }
1550         pl = image->pixlen;
1551         p = image->data + image->width * j * pl;
1552         bpl = bgpixmap[bgindex].image->pixlen;
1553         pd = -1;
1554         n = 0;  /* for lint */
1555         trans = image->trans;
1556         inithist = 0;
1557         for ( ; j < image->height; j++) {
1558                 by = (y + j) % bh;
1559                 bx = x % bw;
1560                 b = bgpixmap[bgindex].image->data +
1561                         (bgpixmap[bgindex].image->width * by + bx) * bpl;
1562                 for (i = 0; i < image->width; i++, p += pl, b += bpl, bx++) {
1563                         if (bx == bw) {
1564                                 bx = 0;
1565                                 b = bgpixmap[bgindex].image->data +
1566                                         bgpixmap[bgindex].image->width * by * bpl;
1567                         }
1568                         if (memToVal(p, pl) != trans)
1569                                 continue;
1570                         d = memToVal(b, bpl);
1571                         if (d != pd) {
1572                                 pd = d;
1573                                 n = obj_image_color(image,
1574                                                 bgpixmap[bgindex].image, d, &inithist);
1575                                 if (n == -1)
1576                                         goto expand;
1577                         }
1578                         valToMem(n, p, pl);
1579                 }
1580         }
1581   end:
1582         if (verbose) {
1583                 const char *p2;
1584
1585                 switch (image->type) {
1586                 case IBITMAP:   p2 = "bitmap"; break;
1587                 case IRGB:      p2 = "rgb"; break;
1588                 default:        p2 = "true"; break;
1589                 }
1590                 fprintf(stderr, "obj_image_trans: %s: "
1591                         "trans=%d, rgb_used=%d, rgb_size=%d\n",
1592                         p2, image->trans, image->rgb.used, image->rgb.size);
1593                 fprintf(stderr, "  image=%dx%d+%d+%d",
1594                         image->width, image->height, x, y);
1595                 if (COMPLEX_BGIMAGE)
1596                         fprintf(stderr, "  bgpixmap[bgindex].image=%dx%d", bw, bh);
1597                 fprintf(stderr, "\n");
1598         }
1599         image->trans = -1;      /* XXX: need recalculation to redraw? */
1600         return image;
1601 }
1602
1603 static void
1604 obj_draw_image(Drawable target, u_int x, u_int y,
1605     struct render_object *obj, int page)
1606 {
1607         Image *image, *timage;
1608         XImageInfo *ximageinfo;
1609         XImage *xim;
1610         int private = mgp_flag & FL_PRIVATE;
1611
1612         image = obj->data.image.image;
1613         if (obj->data.image.xzoom != 100.0 || obj->data.image.yzoom != 100.0) {
1614                 timage = image;
1615                 image = zoom(image,
1616                         obj->data.image.xzoom, obj->data.image.yzoom, verbose);
1617                 if (!image) {
1618                         fprintf(stderr, "image zoom (%0.2fx%0.2f) failed in obj_draw_image\n",
1619                                 obj->data.image.xzoom, obj->data.image.yzoom);
1620                         exit(1);
1621                 }
1622                 freeImage(timage);
1623         }
1624         if (image->trans >= 0)
1625                 image = obj_image_trans(image, x, y);
1626         obj->data.image.image = image;  /* to free later */
1627         ximageinfo= imageToXImage(display, screen, visual, depth, image,
1628                                 private, 0,0, verbose);
1629         if (ximageinfo == NULL) {
1630                 fprintf(stderr, "Cannot convert Image to XImage\n");
1631                 cleanup(-1);
1632         }
1633         xim = ximageinfo->ximage;
1634         if (xim->format == XYBitmap)
1635                 XSetBackground(display, gcfore, back_color[caching]);
1636         XPutImage(display, target, gcfore, xim, 0, 0,
1637                 x, y, xim->width, xim->height);
1638
1639         if (obj->data.image.zoomonclk) {
1640                 regist_zimage_position(obj, x, y, xim->width, xim->height, page);
1641         }
1642         freeXImage(ximageinfo);
1643 }
1644
1645 static void
1646 obj_draw(struct render_state *state, Drawable target, u_int xpos, u_int ypos)
1647 {
1648         struct render_object *obj;
1649         int x = 0, y = 0;
1650         u_long fore;
1651         u_int code;
1652         const char *registry;
1653         XChar2b kch[2];
1654         u_int isize;
1655         int i;
1656         int lineoff;   /* ypos correction for lines with superscripts */
1657         XftDraw *dummy;
1658
1659         /*
1660          * very complicated...
1661          *
1662          *      xpos, ypos      x/y position of the target,
1663          *                      leftmost and uppermost dot.
1664          *      state->ypos     absolute y position in main window.
1665          */
1666         xpos += state->tabxprefix ? state->tabxprefix : state->xprefix;
1667         xpos += state->xoff;
1668         ypos += state->yoff;
1669         fore = fore_color[caching];
1670
1671         /*
1672          * only used with superscript offset for calculating the
1673          * exact line position (ypos correction)
1674          */
1675         lineoff = state->maxascent - state->max_lineascent;
1676
1677         for (obj = state->obj; obj; obj = obj->next) {
1678 #if 0
1679                 x = obj->x + offx;
1680                 y = obj->y + offy;
1681 #else
1682                 x = obj->x;
1683                 switch (obj->vertloc) {
1684                 case VL_BASE:
1685                         y = state->maxascent;
1686                         break;
1687                 case VL_ICENTER:
1688                         if (state->maxflheight){
1689                                 y = (state->maxascent + state->maxflheight) / 2;
1690                         } else
1691                                 y = (state->maxascent + state->maxdescent) / 2;
1692                         y += (obj->ascent - obj->descent) / 2;
1693                         break;
1694                 case VL_CENTER:
1695                         y = (state->maxascent + state->maxdescent) / 2;
1696                         y += (obj->ascent - obj->descent) / 2;
1697                         break;
1698                 case VL_TOP:
1699                         y = obj->ascent;
1700                         break;
1701                 case VL_BOTTOM:
1702                         y = state->maxascent + state->maxdescent;
1703                         y -= obj->descent;
1704                         break;
1705                 }
1706                 x += xpos;
1707                 y += ypos;
1708 #endif
1709                 switch (obj->type) {
1710                 case O_IMAGE:
1711                         obj_draw_image(target, x, y, obj, state->page);
1712                         break;
1713                 case O_XTFONT:
1714                         y += obj->y;
1715                         set_xrender_color(obj->fore, state->opaque);
1716                         xft_font = xft_setfont(obj->data.xftfont.fontname,
1717                                                 obj->data.xftfont.size,
1718                                                 obj->data.xftfont.registry);
1719
1720                         dummy = xft_getdraw(target);
1721                         if (obj->data.xftfont.charset16){
1722                                 XftDrawStringUtf8(dummy,
1723                                                 &xft_forecolor, xft_font,
1724                                                 x, y - lineoff,
1725                                                 obj->data.xftfont.data,
1726                                                 obj->data.xftfont.len);
1727                         } else
1728                                 XftDrawString8(dummy,
1729                                                 &xft_forecolor, xft_font,
1730                                                 x, y - lineoff,
1731                                                 obj->data.xftfont.data,
1732                                                 obj->data.xftfont.len);
1733                         XftDrawDestroy(dummy);
1734                         break;
1735                 case O_XFONT:
1736                         y += obj->y;
1737                         code = obj->data.xfont.code;
1738                         registry = obj->data.xfont.registry;
1739                         (void)x_setfont(obj->data.xfont.xfont,
1740                                 obj->data.xfont.csize,
1741                                 registry, NULL);
1742                         if (obj->fore != fore) {
1743                                 fore = obj->fore;
1744                                 XSetForeground(display, gcfore, fore);
1745                         }
1746
1747 #if 1
1748                         /* is it always okay? */
1749                         kch[0].byte1 = (code >> 8) & 0xff;
1750                         kch[0].byte2 = code & 0xff;
1751                         XDrawString16(display, target, gcfore,
1752                                         x, y - lineoff, kch, 1);
1753 #else
1754                         if (registry) {
1755                                 kch[0].byte1 = (code >> 8) & 0xff;
1756                                 kch[0].byte2 = code & 0xff;
1757                                 XDrawString16(display, target, gcfore,
1758                                         x, y - lineoff, kch, 1);
1759                         } else {
1760                                 ch[0] = code & 0xff;
1761                                 XDrawString(display, target, gcfore,
1762                                         x, y - lineoff, ch, 1);
1763                         }
1764 #endif
1765                         break;
1766                 case O_ICON:
1767                         if (obj->fore != fore) {
1768                                 fore = obj->fore;
1769                                 XSetForeground(display, gcfore, fore);
1770                         }
1771                         isize = obj->data.icon.isize;
1772                         switch (obj->data.icon.itype) {
1773                         case 1: /* this is box */
1774                                 XFillRectangle(display, target, gcfore, x, y,
1775                                         isize, isize);
1776                                 break;
1777                         case 2: /* this is arc */
1778                                 XFillArc(display, target, gcfore, x, y,
1779                                         isize, isize, 0, 360 * 64);
1780                                 break;
1781                         case 3: case 4: case 5: case 6:
1782                         case 7:
1783                                 for (i = 0; i < obj->data.icon.npoint; i++) {
1784                                         obj->data.icon.xpoint[i].x += x;
1785                                         obj->data.icon.xpoint[i].y += y;
1786                                 }
1787                                 XFillPolygon(display, target, gcfore,
1788                                         obj->data.icon.xpoint,
1789                                         obj->data.icon.npoint,
1790                                         Convex, CoordModeOrigin);
1791                                 break;
1792                         }
1793                         break;
1794                 default:
1795                         break;
1796                 }
1797         }
1798         if (fore != fore_color[caching]){
1799                 XSetForeground(display, gcfore, fore_color[caching]);
1800         }
1801         /* ASSERT(state->obj == NULL); */
1802         /* ASSERT(state->objlast == NULL); */
1803 }
1804
1805 static char *
1806 x_fontname(char *buf, int bufsiz, const char *seed, int siz,
1807     /* already canonicalised */ const char *registry)
1808 {
1809         int hyphen;
1810         const char *p;
1811         char tmp[BUFSIZ];
1812         char tmp2[BUFSIZ];
1813         char **fontlist;
1814         int count;
1815
1816         if (!registry)
1817                 registry = "iso8859-1";
1818
1819         if (siz < 0)
1820                 strlcpy(tmp2, "*", sizeof(tmp2));
1821         else
1822                 sprintf(tmp2, "%d", siz);
1823
1824         hyphen = 0;
1825         for (p = seed; *p; p++) {
1826                 if (*p == '-')
1827                         hyphen++;
1828         }
1829         switch (hyphen) {
1830         case 0:
1831                 /* for "a14", "5x8", or such an short names */
1832                 if ((fontlist = XListFonts(display, seed, 1, &count))) {
1833                         XFreeFontNames(fontlist);
1834                         strlcpy(buf, seed, bufsiz);
1835                         break;
1836                 }
1837                 sprintf(tmp, "%s-*-*", seed);
1838                 sprintf(buf, FONT_FORMAT, tmp, tmp2, registry);
1839                 break;
1840         case 2:
1841                 sprintf(buf, FONT_FORMAT, seed, tmp2, registry);
1842                 break;
1843         case XLFD_HYPHEN:
1844                 /* as is */
1845                 strlcpy(buf, seed, bufsiz);
1846                 break;
1847         case 1: /* should not happen */
1848                 fprintf(stderr, "internal error: invalid seed <%s>\n", seed);
1849                 exit(1);
1850         }
1851         if (mgp_flag & FL_VERBOSE) {
1852                 fprintf(stderr, "fontname: seed=<%s> siz=<%d> reg=<%s> "
1853                         "result=<%s>\n",
1854                         seed, siz, registry, buf);
1855         }
1856         return buf;
1857 }
1858
1859 static int
1860 x_parsefont(char *xfont, int *pixel, int *truescalable)
1861 {
1862         char *p;
1863         int fsize;
1864         int i;
1865
1866         /* go toward pixel size */
1867         p = xfont;
1868         for (i = 0; *p && i < 7; i++) {
1869                 /* go toward minus sign */
1870                 while (*p && *p != '-')
1871                         p++;
1872                 /* skip minus sign */
1873                 if (*p)
1874                         p++;
1875         }
1876
1877         if (!*p)
1878                 return -1;
1879         fsize = atoi(p);
1880         if (pixel)
1881                 *pixel = fsize;
1882
1883         /* skip pixel size */
1884         while (*p && (isdigit(*p) || *p == '*'))
1885                 p++;
1886         if (*p == '-')
1887                 p++;
1888         else
1889                 return -1;
1890
1891         /* skip point size */
1892         while (*p && (isdigit(*p) || *p == '*'))
1893                 p++;
1894         if (*p == '-')
1895                 p++;
1896         else
1897                 return -1;
1898
1899         if (truescalable) {
1900                 if (fsize == 0 && (p[0] == '0' || p[0] == '*') && p[1] == '-')
1901                         *truescalable = 1;
1902                 else
1903                         *truescalable = 0;
1904         }
1905         return 0;
1906 }
1907
1908 static XFontStruct *
1909 x_setfont(const char *xfont, u_int csize, const char *registry, int *truescalable)
1910 {
1911         static XFontStruct *xfontstruct;
1912         int i, fsize;
1913         char fontstring[BUFSIZ];
1914 #define FONTTYPEMAX     10      /* number of used fontlist type (in cache) */
1915 #define FONTLISTMAX     20      /* number of list for specified font type */
1916 #define FONTALLOWMAX    105     /* % of desired font */
1917 #define FONTALLOWMIN    90      /* % of desired font */
1918         char **fontlist, **font;
1919         u_int error;
1920         int best, freeindex, count;
1921         int maxsize, minsize;
1922         int scalable, tscalable, tsflag;
1923         static struct {
1924                 char *xlfd;
1925                 char **list;
1926                 int count;
1927         } fontnames[FONTTYPEMAX];
1928 #define FONTCACHEMAX    200     /* number of used font type (in cache) */
1929         static struct {
1930                 char *xfont;
1931                 u_int csize;
1932                 const char *registry;
1933                 char *xlfd;
1934                 XFontStruct *xfontstruct;
1935         } fonts[FONTCACHEMAX];
1936
1937         /*
1938          * Check font cache first.
1939          */
1940         for (i = 0; i < FONTCACHEMAX; i++) {
1941                 if (!fonts[i].xfontstruct)
1942                         continue;
1943                 if (fonts[i].csize != csize || fonts[i].registry != registry
1944                  || strcmp(fonts[i].xfont, xfont) != 0) {
1945                         continue;
1946                 }
1947
1948                 XSetFont(display, gcfore, fonts[i].xfontstruct->fid);
1949                 return fonts[i].xfontstruct;
1950         }
1951
1952         /*
1953          * load new font.
1954          */
1955         if (csize < 5) {
1956                 xfontstruct = XLoadQueryFont(display, "nil2");
1957                 goto gotfont;
1958         }
1959
1960         if (verbose) {
1961                 fprintf(stderr, "need font <%s:%d:%s>\n",
1962                         xfont, csize, registry?registry:"NULL");
1963         }
1964
1965         /*
1966          * Look for the best font possible.
1967          * 1. Check for a font that is smaller than the required one.
1968          *    By using smaller font, we won't make the screen garbled.
1969          * 2. If 1. is impossible, look for slightly larger font than
1970          *    the required one.
1971          */
1972         fontlist = NULL;
1973         freeindex = -1;
1974         x_fontname(fontstring, sizeof(fontstring), xfont, -1, registry);
1975         if (verbose)
1976                 fprintf(stderr, "fontstring <%s>\n", fontstring);
1977         for (i = 0; i < FONTTYPEMAX; i++) {
1978                 if (fontnames[i].xlfd == NULL) {
1979                         if (freeindex < 0)
1980                                 freeindex = i;
1981                         continue;
1982                 }
1983                 if (strcmp(fontnames[i].xlfd, fontstring) == 0) {
1984                         fontlist = fontnames[i].list;
1985                         count = fontnames[i].count;
1986                         freeindex = i;
1987                         break;
1988                 }
1989         }
1990         if (fontlist == NULL) {
1991                 fontlist = XListFonts(display, fontstring, FONTLISTMAX, &count);
1992                 if (fontlist == NULL)
1993                         return NULL;
1994                 if (freeindex >= 0) {
1995                         if (fontnames[freeindex].xlfd)
1996                                 free(fontnames[freeindex].xlfd);
1997                         fontnames[freeindex].xlfd = strdup(fontstring);
1998                         fontnames[freeindex].list = fontlist;
1999                         fontnames[freeindex].count = count;
2000                 }
2001         }
2002         error = (u_int)-1;
2003         best = -1;
2004         maxsize = csize * FONTALLOWMAX / 100;           /* truncate */
2005         minsize = (csize * FONTALLOWMIN + 99) / 100;    /* roundup */
2006         if (verbose)
2007                 fprintf(stderr, "checking %d to %d\n", minsize, maxsize);
2008         scalable = tscalable = -1;
2009         if (truescalable)
2010                 *truescalable = 0;
2011         for (i = 0, font = fontlist; i < count; i++, font++) {
2012                 if (x_parsefont(*font, &fsize, &tsflag) < 0) {
2013                         if (verbose) {
2014                                 fprintf(stderr, " [%d] <%s>: nosize\n",
2015                                         i, *font);
2016                         }
2017                         continue;
2018                 }
2019                 if (fsize == 0) {
2020                         if (scalable < 0)
2021                                 scalable = i;
2022                         if (tsflag) {
2023                                 tscalable = i;
2024                                 if (truescalable)
2025                                         *truescalable = 1;
2026                         }
2027                         if (verbose) {
2028                                 fprintf(stderr, " [%d] <%s>: scalable (%d)\n",
2029                                         i, *font, tsflag);
2030                         }
2031                         continue;
2032                 } else if (fsize > maxsize || fsize < minsize) {
2033                         continue;
2034                 }
2035                 if (fsize > csize) {
2036                         fsize = fsize - csize + 100;
2037                                         /* penalty for larger font */
2038                 } else
2039                         fsize = csize - fsize;
2040                 if (error > fsize) {
2041                         error = fsize;
2042                         best = i;
2043                         if (verbose) {
2044                                 fprintf(stderr, " [%d] <%s>: score %d best\n",
2045                                         i, *font, error);
2046                         }
2047                 } else {
2048                         if (verbose) {
2049                                 fprintf(stderr, " [%d] <%s>: score %d\n",
2050                                         i, *font, error);
2051                         }
2052                 }
2053         }
2054         if (best >= 0) {
2055                 if (verbose) {
2056                         fprintf(stderr, "using best [%d] <%s>\n",
2057                                 best, fontlist[best]);
2058                 }
2059                 strlcpy(fontstring, fontlist[best], sizeof(fontstring));
2060         } else if (scalable >= 0 || tscalable >= 0) {
2061                 x_fontname(fontstring, sizeof(fontstring), xfont, csize,
2062                     registry);
2063                 if (verbose) {
2064                         fprintf(stderr, "using %sscalable <%s>\n",
2065                                 tscalable >= 0 ? "true" : "", fontstring);
2066                 }
2067         }
2068         xfontstruct = XLoadQueryFont(display, fontstring);
2069
2070         if (freeindex < 0)
2071                 XFreeFontNames(fontlist);
2072
2073         /*
2074          * Fill font cache.
2075          */
2076         for (i = 0; i < FONTCACHEMAX; i++) {
2077                 if (!fonts[i].xfontstruct)
2078                         break;
2079         }
2080         if (FONTTYPEMAX <= i) {
2081                 /* last resort.  always cache the font recently used */
2082                 i = FONTTYPEMAX - 1;
2083                 XFreeFont(display, fonts[i].xfontstruct);
2084                 free(fonts[i].xfont);
2085                 free(fonts[i].xlfd);
2086         }
2087         fonts[i].csize = csize;
2088         fonts[i].registry = registry;
2089         fonts[i].xfont = strdup(xfont);
2090         fonts[i].xlfd = strdup(fontstring);
2091         fonts[i].xfontstruct = xfontstruct;
2092
2093   gotfont:
2094         if (xfontstruct == NULL)
2095                 return NULL;
2096         XSetFont(display, gcfore, xfontstruct->fid);
2097         return xfontstruct;
2098 }
2099
2100 static u_int
2101 draw_onechar_x(struct render_state *state, u_int code,
2102     int x, int y, int size, const char *argregistry, int lastchar)
2103 {
2104         u_int charlen;
2105         static XFontStruct *xfontstruct;
2106         int coffset;
2107         XCharStruct *cs;
2108         const char *metricsource;
2109         const char *seed;
2110         const char *registry;
2111
2112         if (code >= 0xa0 && ((!argregistry || !argregistry[0]) && *mgp_charset))
2113                 registry = mgp_charset;
2114         else
2115                 registry = argregistry;
2116         seed = x_findseed(state, registry);
2117         xfontstruct = x_setfont(seed, char_size[caching], registry, NULL);
2118
2119         if (xfontstruct == NULL)
2120                 return 0;
2121
2122         if (!xfontstruct->per_char) {
2123                 metricsource = "max_bounds";
2124                 coffset = 0;
2125                 cs = &xfontstruct->max_bounds;
2126         } else if (!xfontstruct->min_byte1 && !xfontstruct->max_byte1) {
2127                 metricsource = "bytewise offset";
2128                 coffset = (code & 0xff) - xfontstruct->min_char_or_byte2;
2129                 cs = &xfontstruct->per_char[coffset];
2130         } else {
2131                 metricsource = "wordwise offset";
2132                 coffset = (code & 0xff) - xfontstruct->min_char_or_byte2;
2133                 coffset += (((code >> 8) & 0xff) - xfontstruct->min_byte1)
2134                     * (xfontstruct->max_char_or_byte2 - xfontstruct->min_char_or_byte2);
2135                 cs = &xfontstruct->per_char[coffset];
2136         }
2137
2138         /*
2139          * It looks that there are some Japanese X11 fonts with bogus
2140          * font metric (cs->width == 0).  This is a workaround for that.
2141          * (or is there any mistake in above "coffset" computation?)
2142          *
2143          * TODO: report the X/Open group, or some other guys, about this.
2144          */
2145         if (!cs->width) {
2146                 if (verbose) {
2147                         fprintf(stderr, "X11 font %s:%d:%s has bogus "
2148                                 "font metric for glyph 0x%04x\n"
2149                                 "\tcs->width=%d, source=%s, coffset=0x%04x\n",
2150                                 seed, char_size[caching], registry?registry:"NULL",
2151                                 code, cs->width, metricsource, coffset);
2152                 }
2153                 cs = &xfontstruct->max_bounds;
2154         }
2155
2156         draw_line_itemsize(state, cs->ascent, cs->descent, 0);
2157
2158         /* usually */
2159         charlen = cs->width;
2160
2161         /*
2162          * for the very first char on the line, the char may goes over the
2163          * edge at the lefthand side.  offset the image to the right so that
2164          * whole part of the bitmap appears on the screen.
2165          * beware the sign-ness of cs->lbearing.
2166          */
2167         if (x + cs->lbearing < 0) {
2168                 x -= cs->lbearing;
2169                 charlen -= cs->lbearing;
2170         }
2171
2172         /*
2173          * For the last char, make sure that the whole part of the bitmap
2174          * appears on the screen.
2175          */
2176         if (lastchar && cs->width < cs->rbearing)
2177                 charlen += cs->rbearing - cs->width;
2178
2179         obj_new_xfont(state, x, y, size, code, registry);
2180
2181         return charlen;
2182 }
2183
2184 /*
2185  * render misc items.
2186  */
2187 static void
2188 back_gradation(struct render_state *state, struct ctrl_grad *cg0)
2189 {
2190         struct ctrl_grad cg1;
2191         struct ctrl_grad *cg;
2192         int srcwidth, srcheight;
2193         int dstwidth, dstheight;
2194         int dir, numcolor;
2195         float xzoomrate, yzoomrate;
2196         int hquality, vquality;
2197
2198         Image *myimage, *image;
2199         XImageInfo *ximageinfo;
2200         byte *pic;
2201         int private = mgp_flag & FL_PRIVATE;
2202         static Cursor curs;
2203
2204         /* okay, please wait for a while... */
2205         if (!curs)
2206                 curs = XCreateFontCursor(display, XC_watch);
2207         XDefineCursor(display, window, curs);
2208         XFlush(display);
2209
2210         /* just for safety */
2211         memcpy(&cg1, cg0, sizeof(struct ctrl_grad));
2212         cg = &cg1;
2213
2214         /* grab parameters */
2215         dir = cg->ct_direction;
2216         numcolor = cg->ct_numcolor;
2217         hquality = b_quality[caching];
2218         vquality = b_quality[caching];
2219
2220         /*
2221          * XXX zoomflag is too complex to understand.
2222          */
2223         if (!cg->ct_zoomflag) {
2224                 int t;
2225                 int i;
2226
2227                 dstwidth = window_width * cg->ct_width / 100;
2228                 dstheight = window_height * cg->ct_height / 100;
2229                 srcwidth = dstwidth;
2230                 srcheight = dstheight;
2231
2232                 /*
2233                  * apply quality factor if srcwidth/height are large enough.
2234                  */
2235 #define TOOSMALLFACTOR 8
2236                 t = srcwidth;
2237                 for (i = 100; hquality < i; i--) {
2238                         t = srcwidth * i / 100;
2239                         if (t < cg->ct_g_colors * TOOSMALLFACTOR)
2240                                 break;
2241                 }
2242                 srcwidth = t;
2243
2244                 t = srcheight;
2245                 for (i = 100; vquality < i; i--) {
2246                         t = srcheight * i / 100;
2247                         if (t < cg->ct_g_colors * TOOSMALLFACTOR)
2248                                 break;
2249                 }
2250                 srcheight = t;
2251 #undef TOOSMALLFACTOR
2252         } else {
2253                 dstwidth = window_width;
2254                 dstheight = window_height;
2255                 srcwidth = state->width * cg->ct_width / 100;
2256                 srcheight = state->height * cg->ct_height / 100;
2257
2258                 /*
2259                  * we don't apply quality factor here, since srcwidth/height
2260                  * is already smaller than dstwidth/height.
2261                  */
2262         }
2263
2264         xzoomrate = 100.0 * dstwidth / srcwidth;
2265         yzoomrate = 100.0 * dstheight / srcheight;
2266
2267         /* performace enhance hack for special case */
2268         if (dir % 90 == 0) {
2269                 float *q;
2270                 int *p, *r;
2271
2272                 /*
2273                  * 0 or 180: reduce width
2274                  * 90 or 270: reduce height
2275                  */
2276                 p = (dir % 180 == 0) ? &srcwidth : &srcheight;
2277                 q = (dir % 180 == 0) ? &xzoomrate : &yzoomrate;
2278                 r = (dir % 180 == 0) ? &dstwidth : &dstheight;
2279
2280                 /* rely upon use X11 background image tiling. */
2281                 *q = (float) 100.0;
2282                 *p = 3;
2283                 *r = 3;
2284         }
2285
2286         if (verbose) {
2287                 fprintf(stderr, "raw: %d,%d qu: %d,%d "
2288                         "dst: %d,%d src: %d,%d zoom: %0.2f,%0.2f\n",
2289                         cg->ct_width, cg->ct_height,
2290                         hquality, vquality,
2291                         dstwidth, dstheight, srcwidth, srcheight,
2292                         xzoomrate, yzoomrate);
2293         }
2294
2295         screen = DefaultScreen(display);
2296
2297         /* make gradation image */
2298         pic = draw_gradation(srcwidth, srcheight, cg);
2299         myimage = make_XImage(pic, srcwidth, srcheight);
2300
2301         if (numcolor < 64)
2302                 myimage = reduce(myimage, numcolor, verbose);
2303
2304         if (verbose) {
2305                 fprintf(stderr, "background zoomrate: (%0.2f,%0.2f)\n",
2306                         xzoomrate, yzoomrate);
2307                 fprintf(stderr, "background zoom mode %d: "
2308                         "(%d, %d)->(%d, %d)[%d]\n", cg->ct_zoomflag,
2309                         srcwidth, srcheight, dstwidth, dstheight, b_quality[caching]);
2310         }
2311
2312         if (xzoomrate != 100.0 || yzoomrate != 100.0) {
2313                 image = myimage;
2314                 myimage = zoom(image, xzoomrate, yzoomrate, verbose);
2315                 if (!image) {
2316                         fprintf(stderr, "image zoom (%0.2fx%0.2f) failed in back_gradataion\n",
2317                                 xzoomrate, yzoomrate);
2318                         exit(1);
2319                 }
2320                 freeImage(image);
2321         }
2322
2323         ximageinfo = imageToXImage(display, screen, visual, depth, myimage,
2324                 private, 0, 1, verbose);
2325         if (!ximageinfo) {
2326                 fprintf(stderr, "Cannot convert Image to XImage\n");
2327                 cleanup(-1);
2328         }
2329
2330         regist_background_pixmap(ximageinfo, myimage);
2331
2332         XUndefineCursor(display, window);
2333         XFlush(display);
2334 }
2335
2336 /* !TODO: move rotation code into some library */
2337 /* rotate image by 90 degrees (counter clockwise) */
2338 static void
2339 rotate_image_p90(Image *image)
2340 {
2341         unsigned int row, column, pl = image->pixlen;
2342         unsigned int new_height = image->width, new_width = image->height, new_linelen = new_width * pl;
2343         byte *src, *tgt, *col_head;
2344         Pixel d;
2345         /* allocate buffer for new image */
2346         byte *rot_data = lmalloc(new_linelen * new_height);
2347
2348         /* do the rotation */
2349         for (row = 0, src = image->data, col_head = rot_data + (new_height - 1) * new_linelen;
2350                         row < image->height;
2351                         row++, col_head += pl) {
2352                 for (column = 0, tgt = col_head;
2353                                 column < image->width;
2354                                 column++, src += pl, tgt -= new_linelen) {
2355                         d = memToVal(src, pl);
2356                         valToMem(d, tgt, pl);
2357                 }
2358         }
2359
2360         /* swap to rotated image, exchange height and width
2361            and point to rotated data */
2362         image->height = new_height;
2363         image->width = new_width;
2364         lfree(image->data);
2365         image->data = rot_data;
2366 }
2367
2368 /* rotate image by -90 degrees (clockwise) */
2369 static void
2370 rotate_image_m90(Image *image)
2371 {
2372         unsigned int row, column, pl = image->pixlen;
2373         unsigned int new_height = image->width, new_width = image->height, new_linelen = new_width * pl;
2374         byte *src, *tgt;
2375         Pixel d;
2376         /* allocate buffer for new image */
2377         byte *rot_data = lmalloc(new_linelen * new_height);
2378
2379         /* do the rotation */
2380         for (row = 0, src = image->data; row < image->height; row++) {
2381                 for (column = 0, tgt = rot_data + new_linelen - (row + 1) * pl;
2382                                 column < image->width;
2383                                 column++, src += pl, tgt += new_linelen) {
2384                         d = memToVal(src, pl);
2385                         valToMem(d, tgt, pl);
2386                 }
2387         }
2388
2389         /* swap to rotated image, exchange height and width
2390            and point to rotated data */
2391         image->height = new_height;
2392         image->width = new_width;
2393         lfree(image->data);
2394         image->data = rot_data;
2395
2396         return;
2397 }
2398
2399 /* rotate image by 180 degrees */
2400 static void
2401 rotate_image_180(Image *image)
2402 {
2403         unsigned int row, column, pl = image->pixlen;
2404         unsigned int new_height = image->height, new_width = image->width, new_linelen = new_width * pl;
2405         byte *src, *tgt;
2406         Pixel d;
2407         /* allocate buffer for new image */
2408         byte *rot_data = lmalloc(new_linelen * new_height);
2409
2410         /* do the rotation */
2411         for (row = 0, src = image->data; row < image->height; row++) {
2412                 for (column = 0, tgt = rot_data + (new_height - row) * new_linelen - pl;
2413                                 column < image->width;
2414                                 column++, src += pl, tgt -= pl) {
2415                         d = memToVal(src, pl);
2416                         valToMem(d, tgt, pl);
2417                 }
2418         }
2419
2420         /* swap to rotated image, exchange height and width
2421            and point to rotated data */
2422         image->height = new_height;
2423         image->width = new_width;
2424         lfree(image->data);
2425         image->data = rot_data;
2426
2427         return;
2428 }
2429
2430 static void
2431 image_load(struct render_state *state, char *filename,
2432     int numcolor, int ximagesize, int yimagesize,
2433     int backflag, int zoomflag, int centerflag,
2434     int raise2, int rotate, int zoomonclk)
2435 {
2436         Image *image, *myimage;
2437         XImageInfo *ximageinfo;
2438         u_int image_posx;
2439         int width, height;
2440         float xzoomrate, yzoomrate;
2441         int     private = mgp_flag & FL_PRIVATE;
2442         static Cursor curs;
2443         Imlib_Image *imimage;
2444
2445         if (!caching){
2446                 if (!curs)
2447                         curs = XCreateFontCursor(display, XC_watch);
2448                 XDefineCursor(display, state->target, curs);
2449                 XFlush(display);
2450         }
2451
2452         if ((myimage = loadImage(filename)) == NULL) {
2453                 fprintf(stderr, "failed to load image file\n");
2454                 cleanup(-1);
2455         }
2456         switch (rotate) {
2457                 case 0:
2458                         /* Do nothing */
2459                         break;
2460
2461                 case -90:
2462                 case 270:
2463                         rotate_image_m90(myimage);
2464                         break;
2465
2466                 case 90:
2467                         rotate_image_p90(myimage);
2468                         break;
2469
2470                 case -180:
2471                 case 180:
2472                         rotate_image_180(myimage);
2473                         break;
2474
2475                 default:
2476                         fprintf(stderr, "rotation by %d degrees not supported.\n", rotate);
2477                         cleanup(-1);
2478         }
2479         width = myimage->width;
2480         height = myimage->height;
2481
2482         if (myimage->depth == 1 && myimage->trans < 0) {
2483                 XColor xc;
2484
2485                 xc.flags = DoRed | DoGreen | DoBlue;
2486                 xc.pixel = fore_color[caching];
2487                 XQueryColor(display, colormap, &xc);
2488                 *(myimage->rgb.red + 1) = xc.red;
2489                 *(myimage->rgb.green + 1) = xc.green;
2490                 *(myimage->rgb.blue + 1) = xc.blue;
2491                 myimage->trans = 0;     /* call obj_image_trans() later */
2492         }
2493
2494         if (numcolor)
2495                 myimage = reduce(myimage, numcolor, verbose);
2496
2497         if (!ximagesize) ximagesize = 100;
2498         if (!yimagesize) yimagesize = 100;
2499         xzoomrate = (float) ximagesize;
2500         yzoomrate = (float) yimagesize;
2501         image_zoomratio(state, &xzoomrate, &yzoomrate, zoomflag, width, height);
2502
2503         if (backflag) {
2504                 if (xzoomrate != 100 || yzoomrate != 100) {
2505                         image = myimage;
2506                         myimage = zoom(image, xzoomrate, yzoomrate, verbose);
2507                         if (!image) {
2508                                 fprintf(stderr, "image zoom (%fx%f) failed in image_load\n",
2509                                         xzoomrate, yzoomrate);
2510                                 exit(1);
2511                         }
2512                         freeImage(image);
2513                 }
2514
2515                 ximageinfo= imageToXImage(display, screen, visual, depth,
2516                                 myimage, private, 0, 1, verbose);
2517                 if (ximageinfo == NULL) {
2518                         fprintf(stderr, "Cannot convert Image to XImage\n");
2519                         cleanup(-1);
2520                 }
2521                 regist_background_pixmap(ximageinfo, myimage);
2522                 goto end;
2523         }
2524
2525 #if 1  /* by h.kakugawa@computer.org */
2526         switch(valign){
2527         case VL_TOP:
2528                 draw_line_itemsize(state,
2529                                    (height * raise2) * yzoomrate / 10000,
2530                                    height * (100 + raise2) * yzoomrate / 10000, 0);
2531                 break;
2532         case VL_BOTTOM:
2533                 draw_line_itemsize(state,
2534                                    height * (100 + raise2) * yzoomrate / 10000,
2535                                    (height * raise2) * yzoomrate / 10000, 0);
2536                 break;
2537         case VL_CENTER:
2538                 draw_line_itemsize(state,
2539                                    height * (100 + raise2) * yzoomrate / 20000,
2540                                    height * (100 + raise2) * yzoomrate / 20000, 0);
2541                 break;
2542         }
2543 #else
2544         switch(valign){
2545         case VL_TOP:
2546                 draw_line_itemsize(state, 0, height * yzoomrate / 100, 0);
2547                 break;
2548         case VL_BOTTOM:
2549                 draw_line_itemsize(state, height * yzoomrate / 100, 0, 0);
2550                 break;
2551         case VL_CENTER:
2552                 draw_line_itemsize(state, height * yzoomrate / 200,
2553                         height * yzoomrate / 200, 0);
2554                 break;
2555         }
2556 #endif
2557
2558         if (centerflag)
2559                 image_posx = char_size[caching] / 2 - (width * xzoomrate / 100) / 2;
2560         else
2561                 image_posx = 0;
2562
2563         imimage = search_imdata(filename);
2564         obj_new_image2(state, state->linewidth + image_posx,
2565                 - height * yzoomrate / 100 / 2,
2566                 myimage, xzoomrate, yzoomrate, imimage, zoomonclk);
2567
2568         state->linewidth += (width * xzoomrate / 100);
2569 end:
2570         if (!caching){
2571                 XUndefineCursor(display, state->target);
2572                 XFlush(display);
2573         }
2574 }
2575
2576 static void
2577 image_load_ps(struct render_state *state, char *filename,
2578     int numcolor, int ximagesize, int yimagesize,
2579     int backflag, int zoomflag, int centerflag,
2580     int raise2, int rotate, int zoomonclk)
2581 {
2582         int x1, y1v, x2, y2;
2583         static Cursor curs;
2584         char fullname[MAXPATHLEN];
2585         char *imagefile;
2586         int width, height;
2587         float xzoom, yzoom, zratio;
2588         char *p;
2589
2590         /* wait for a while, please. */
2591         if (!curs)
2592                 curs = XCreateFontCursor(display, XC_watch);
2593         XDefineCursor(display, window, curs);
2594         XFlush(display);
2595
2596         if (findImage(filename, fullname) < 0) {
2597                 fprintf(stderr, "image file %s not found in path\n", filename);
2598                 cleanup(-1);
2599         }
2600         if (ps_boundingbox(fullname, &x1, &y1v, &x2, &y2) < 0) {
2601                 /* error message generated in ps_boundingbox() */
2602                 cleanup(-1);
2603         }
2604
2605         width = x2 - x1 + 1;
2606         height = y2 - y1v + 1;
2607         xzoom = (float) ximagesize;
2608         yzoom = (float) yimagesize;
2609         image_zoomratio(state, &xzoom, &yzoom, zoomflag, width, height);
2610         width = width * xzoom / 100;
2611         height = height * yzoom / 100;
2612
2613         if (zoomonclk)
2614                 zratio = (float) zoomonclk / 100.0 * window_width / width;
2615         else
2616                 zratio = 1.0;
2617         imagefile = epstoimage(fullname, x1, y1v,
2618                 width * zratio, height * zratio, xzoom * zratio, yzoom * zratio);
2619         if (imagefile == NULL) {
2620                 fprintf(stderr, "WARN: cannot generate %s file from %s\n",
2621                         gsdevice, filename);
2622                 XUndefineCursor(display, window);
2623                 XFlush(display);
2624                 return;
2625         }
2626
2627         if (mgp_flag & FL_VERBOSE) {
2628                 fprintf(stderr, "image_load_ps: %s: %s file = %s\n",
2629                         filename, gsdevice, imagefile);
2630         }
2631         image_load(state, imagefile, numcolor, 100.0 /zratio, 100.0/zratio, backflag,
2632                 Z_NORMAL | (Z_NORMAL << Z_YSHIFT), centerflag, raise2, rotate, zoomonclk);
2633         /* XXX: unlink imagefile in /tmp */
2634         if ((p = strrchr(imagefile, '/')) != NULL)
2635                 p++;
2636         else
2637                 p = imagefile;
2638         if (strncmp(p, ".gscache", sizeof(".gscache") - 1) != 0)
2639                 unlink(imagefile);
2640
2641         if (!backflag && numcolor >= 0)
2642                 image_setcolor(state);
2643 }
2644
2645 void
2646 timebar(struct render_state *state)
2647 {
2648         int pos, n, p, barlen;
2649         GC pgc;
2650
2651         if (t_start == 0 || tbar_mode == 0 || caching)
2652                 return;
2653
2654         pos = (window_width - 2) * (state->page - 1) / (maxpage - 1);
2655         p = time(NULL) - t_start;
2656         barlen = window_width - window_width * p / t_fin / 60;
2657
2658         if (window_width / 2 < barlen)
2659                 pgc = gcgreen;
2660         else if (window_width / 3 < barlen)
2661                 pgc = gcyellow;
2662         else
2663                 pgc = gcred;
2664         if (barlen > 0) {
2665                 XClearArea(display, state->target, 0, window_height - 2,
2666                         window_width, 2, 0);
2667                 XFillRectangle(display, state->target, pgc,
2668                         window_width - barlen, window_height - 1, barlen, 1);
2669                 XFillRectangle(display, state->target, pgc,
2670                         pos, window_height - 5, 2, 5);
2671         } else if (barlen < 0) {
2672                 barlen = - barlen;
2673                 n = p / t_fin / 60;
2674                 if (n > window_height - 1)
2675                         n = window_height - 1;
2676                 if (n)
2677                         XFillRectangle(display, state->target, gcred,
2678                                 0, window_height - n,
2679                                 barlen, n);
2680                 XClearArea(display, state->target, 0, window_height - (n + 2),
2681                         window_width, n + 2, 0);
2682                 XFillRectangle(display, state->target, gcred,
2683                         0, window_height - (n + 1),
2684                         barlen % window_width, n + 1);
2685                 XFillRectangle(display, state->target, gcred,
2686                         pos, window_height - (n + 1 + 4),
2687                         2, 5);
2688         }
2689 }
2690
2691 static const struct icon_point {
2692         XPoint xpoint[4];
2693         int     point_num;
2694 } icon_point[] = {{ {{1, 0}, {0, 2}, {2, 2}, {0, 0}}, 3 },
2695                   { {{0, 0}, {2, 0}, {1, 2}, {0, 0}}, 3 },
2696                   { {{0, 0}, {0, 2}, {2, 1}, {0, 0}}, 3 },
2697                   { {{2, 0}, {2, 2}, {0, 1}, {0, 0}}, 3 },
2698                   { {{1, 0}, {0, 1}, {1, 2}, {2, 1}}, 4 }};
2699
2700 static void
2701 process_icon(struct render_state *state, struct ctrl *cp)
2702 {
2703         u_int i, icon_type, icon_size, icon_x, icon_y, index2;
2704         u_long tmp_color;
2705         XPoint xpoint[4];
2706
2707         for (i = 0; icon_words[i].ctl_strlen != 0; i++) {
2708                 if (!strncasecmp(cp->ctic_value, icon_words[i].ctl_string,
2709                         strlen(cp->ctic_value))) {
2710                                 break;
2711                 }
2712         }
2713
2714         icon_type = icon_words[i].ctl_type; /* may be 0 */
2715         icon_size = char_size[caching] * cp->ctic_size / 100;
2716
2717         switch(icon_type){
2718         case 0:
2719                 /* this is image */
2720                 icon_x = icon_size * 100 / state->width;
2721                 icon_y = icon_size * 100 / state->height;
2722                 if (icon_x == 0) icon_x = 1;
2723                 if (icon_y == 0) icon_y = 1;
2724                 tmp_color = fore_color[caching];
2725                 fore_color[caching] = cp->ctic_color;
2726                 image_load(state, cp->ctic_value, 0, icon_x, icon_y, 0, 0, 1, 0, 0, 0);
2727                 fore_color[caching] = tmp_color;
2728                 break;
2729
2730         case 1:
2731                 /* this is box */
2732                 obj_new_icon(state,
2733                         state->linewidth + char_size[caching]/2 - icon_size/2,
2734                         POSY(icon_size), icon_type, icon_size,
2735                         cp->ctic_color, 0, NULL);
2736                 state->linewidth += char_size[caching];
2737                 break;
2738
2739         case 2:
2740                 /* this is arc */
2741                 obj_new_icon(state,
2742                         state->linewidth + char_size[caching]/2 - icon_size/2,
2743                         POSY(icon_size), icon_type, icon_size,
2744                         cp->ctic_color, 0, NULL);
2745                 state->linewidth += char_size[caching];
2746                 break;
2747
2748         case 3:
2749         case 4:
2750         case 5:
2751         case 6:
2752         case 7:
2753                 index2 = icon_type - 3;
2754                 icon_x = state->linewidth + (char_size[caching] - icon_size) / 2;
2755 #if 0
2756                 icon_y = POSY(icon_size);
2757 #else
2758                 icon_y = 0;
2759 #endif
2760                 for (i = 0; i < icon_point[index2].point_num; i ++){
2761                         xpoint[i].x = icon_x +
2762                                 icon_point[index2].xpoint[i].x * icon_size / 2;
2763                         xpoint[i].y = icon_y +
2764                                 icon_point[index2].xpoint[i].y * icon_size / 2;
2765                 }
2766                 obj_new_icon(state, 0, 0, icon_type, icon_size,
2767                         cp->ctic_color, icon_point[index2].point_num, xpoint);
2768                 state->linewidth += char_size[caching];
2769                 break;
2770
2771         default:
2772                 break;
2773         }
2774
2775         cp = NULL;
2776         state->brankline = 0;
2777 }
2778
2779 static void
2780 draw_bar(struct render_state *state, struct ctrl *cp)
2781 {
2782         u_int width, swidth, st, len;
2783         XColor col, scol;
2784         static GC gcbar, gcsbar;
2785         static u_long prevcolor = -1;
2786
2787         if (!gcbar) {
2788                 gcbar = XCreateGC(display, state->target, 0, 0);
2789                 XSetFunction(display, gcbar, GXcopy);
2790                 gcsbar = XCreateGC(display, state->target, 0, 0);
2791                 XSetFunction(display, gcsbar, GXcopy);
2792         }
2793         col.pixel = cp->ctb_color;
2794         if (col.pixel == -1)
2795                 col.pixel = fore_color[caching];
2796         if (col.pixel != prevcolor) {
2797                 prevcolor = col.pixel;
2798                 col.flags = DoRed|DoGreen|DoBlue;
2799                 XQueryColor(display, colormap, &col);
2800                 scol.red   = col.red   / 2;
2801                 scol.green = col.green / 2;
2802                 scol.blue  = col.blue  / 2;
2803                 if (!XAllocColor(display, colormap, &scol))
2804                         scol.pixel = col.pixel;
2805                 XSetForeground(display, gcbar, col.pixel);
2806                 XSetForeground(display, gcsbar, scol.pixel);
2807         }
2808         width = cp->ctb_width * state->height / 1000;
2809         swidth = width / 2;
2810         width -= swidth;
2811         st = cp->ctb_start * state->width / 100 + state->xoff;
2812         len = cp->ctb_length * state->width / 100;
2813         XFillRectangle(display, state->target, gcbar, st, state->ypos + state->yoff, len, width);
2814         XFillRectangle(display, state->target, gcsbar, st, state->ypos + state->yoff + width, len, swidth);
2815
2816         state->ypos += width + swidth + VERT_GAP(char_size[caching]) / 2;
2817         if (state->maxascent < width + swidth)
2818                 state->maxascent = width + swidth;
2819         state->brankline = 0;
2820 }
2821
2822 static void
2823 process_system(struct render_state *state, struct ctrl *cp)
2824 {
2825         pid_t pid;
2826         int i;
2827         char **argv;
2828         char buf[BUFSIZ];
2829
2830         if (state->repaint) {
2831                 if (mgp_flag & FL_VERBOSE) {
2832                         fprintf(stderr, "WARN: %%system directive skipping during repaint of same page\n");
2833                 }
2834                 return; /* don't relaunch on repaint */
2835         }
2836
2837         if (mgp_flag & FL_NOFORK) {
2838                 if (mgp_flag & FL_VERBOSE) {
2839                         fprintf(stderr, "WARN: %%system ");
2840                         for (i = 0; i < cp->cta_argc; i++) {
2841                                 fprintf(stderr, "%c%s", (i == 0) ? '"' : ' ',
2842                                         cp->cta_argv[i]);
2843                         }
2844                         fprintf(stderr, "\": directive skipped\n");
2845                 }
2846                 return;
2847         }
2848
2849         if (checkchild(cp) != (pid_t)-1)
2850                 return; /*already running*/
2851
2852         /*
2853          * edit argument.
2854          * if we have X11 geometry string
2855          */
2856         argv = (char **)cp->cta_argv;
2857         for (i = 0; i < cp->cta_argc; i++) {
2858                 if (*(argv[i]) == '%')
2859                         break;
2860         }
2861         if (i < cp->cta_argc) {
2862                 char *p;
2863                 char *q;
2864                 int myxpos, myypos;
2865                 u_int rootxsiz, rootysiz;
2866                 u_int xsiz, ysiz;
2867                 int xloc, yloc;
2868                 int mode;
2869
2870             {
2871                 XWindowAttributes wa;
2872                 Window junkwin;
2873                 int junk;
2874
2875                 XGetWindowAttributes(display, window, &wa);
2876                 XTranslateCoordinates(display, window, wa.root,
2877                         -wa.border_width, -wa.border_width,
2878                         &myxpos, &myypos, &junkwin);
2879                 XGetGeometry(display, wa.root, &junkwin, &junk, &junk,
2880                         &rootxsiz, &rootysiz, (void *)&junk, (void *)&junk);
2881              }
2882
2883                 argv = (char **)malloc((cp->cta_argc + 1) * sizeof(char *));
2884                 memcpy(argv, cp->cta_argv, (cp->cta_argc + 1) * sizeof(char *));
2885                 p = argv[i];
2886                 p++;    /*drop percent char*/
2887                 q = buf;
2888                 *q = '\0';
2889
2890                 mode = XParseGeometry(p, &xloc, &yloc, &xsiz, &ysiz);
2891                 if (mode == 0)
2892                         goto fail;
2893                 if ((mode & WidthValue) && (mode & HeightValue)) {
2894                         sprintf(q, "%dx%d", xsiz * state->width / 100,
2895                                 ysiz * state->height / 100);
2896                         q += strlen(q);
2897                 }
2898                 if ((mode & XValue) && (mode & YValue)) {
2899                         xloc = xloc * state->width / 100;
2900                         yloc = yloc * state->height / 100;
2901                         if (mode & XNegative)
2902                                 xloc = rootxsiz - myxpos + state->width - xloc;
2903                         else
2904                                 xloc += myxpos;
2905                         if (mode & YNegative)
2906                                 yloc = rootysiz - myypos + state->height - yloc;
2907                         else
2908                                 yloc += myypos;
2909                         sprintf(q, "+%d+%d", xloc + state->xoff, yloc + state->yoff);
2910                 }
2911
2912                 if (mgp_flag & FL_VERBOSE) {
2913                         fprintf(stderr, "relative geometry: "
2914                                 "%s (presentation %dx%d+%d+%d)\n",
2915                                 argv[i], state->width, state->height,
2916                                 myxpos, myypos);
2917                         fprintf(stderr, "\t-> %s\n", buf);
2918                 }
2919                 argv[i] = buf;
2920
2921                 if (0) {
2922 fail:
2923                         if (mgp_flag & FL_VERBOSE) {
2924                                 fprintf(stderr,
2925                                         "relative geometry: %s failed\n",
2926                                         argv[i]);
2927                         }
2928                 }
2929         }
2930         pid = fork();
2931         if (pid < 0) {
2932                 perror("fork");
2933                 cleanup(-1);
2934         } else if (pid == 0) {
2935                 execvp(argv[0], argv);
2936                 perror(argv[0]);
2937                 _exit(1);
2938         }
2939
2940         if (!cp->cta_flag)      /*will be purged at the end of page*/
2941                 regchild(pid, cp, -1, state->page);
2942         else
2943                 regchild(pid, cp, -1, cp->cta_flag);
2944 }
2945
2946 static void
2947 process_xsystem(struct render_state *state, struct ctrl *cp)
2948 {
2949         pid_t pid;
2950         int i;
2951         u_int dumint;
2952         int xloc, yloc;
2953         u_int xsiz, ysiz;
2954         char **argv;
2955         char buf[BUFSIZ];
2956         Window window_id, dumwin;
2957
2958         if (state->repaint) {
2959                 if (mgp_flag & FL_VERBOSE) {
2960                         fprintf(stderr, "WARN: %%system directive skipping during repaint of same page\n");
2961                 }
2962                 return; /* don't relaunch on repaint */
2963         }
2964
2965         if (mgp_flag & FL_NOFORK) {
2966                 if (mgp_flag & FL_VERBOSE) {
2967                         fprintf(stderr, "WARN: %%system ");
2968                         for (i = 0; i < cp->cta_argc; i++) {
2969                                 fprintf(stderr, "%c%s", (i == 0) ? '"' : ' ',
2970                                         cp->cta_argv[i]);