/* * Copyright (C) 1997 and 1998 WIDE Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: draw.c,v 1.232 2007/01/12 10:38:55 nishida Exp $ */ #include "mgp.h" /* state associated with the window - how should we treat this? */ static struct ctrl *bg_ctl, *bg_ctl_last, *bg_ctl_cache; static int bgindex = 0; struct render_state cache_state; static u_short kinsokutable[] = { 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212a, 0x212b, 0x212c, 0x212d, 0x212e, 0x212f, 0x2130, 0x2133, 0x2134, 0x2135, 0x2136, 0x213c, 0x2147, 0x2149, 0x214b, 0x214d, 0x214f, 0x2151, 0x2153, 0x2155, 0x2157, 0x2159, 0x216b, 0x2242, 0x2244, 0 }; static struct pcache { u_int flag; u_int page; u_int mgpflag; u_int mode; u_int effect; u_int value; } pcache; #define COMPLEX_BGIMAGE \ (bg_ctl \ && ((bg_ctl->ct_op == CTL_BIMAGE) \ || bg_ctl->ct_op == CTL_BGRAD)) #define COMPLEX_BGIMAGE2 (0) #define POSY(size) (-(int)((size)/2)) static void process_direc __P((struct render_state *, int *)); static int set_position __P((struct render_state *)); static void draw_line_output __P((struct render_state *, char *)); static void cutin __P((struct render_state *, int, int, int)); #if 0 static void shrink __P((char *, u_int)); #endif static void draw_string __P((struct render_state *, char *)); static char *draw_fragment __P((struct render_state *, u_char *, u_int, char *, int)); static int iskinsokuchar __P((u_int)); static struct render_object *obj_alloc __P((struct render_state *state)); static void obj_free __P((struct render_state *, struct render_object *)); static int obj_new_xfont __P((struct render_state *, int, int, int, u_int, char *)); static int obj_new_image __P((struct render_state *, int, int, Image *, int, int)); static int obj_new_icon __P((struct render_state *, int, int, u_int, u_int, u_long, u_int, XPoint *)); static Pixel obj_image_color __P((Image *, Image *, Pixel, int *)); static Image *obj_image_trans __P((Image *, u_int, u_int)); static void obj_draw_image __P((Drawable, u_int, u_int, struct render_object *)); static void obj_draw __P((struct render_state *, Drawable, u_int, u_int)); #ifdef VFLIB static int obj_new_vfont __P((struct render_state *, int, int, struct vfont *, int)); static u_int draw_onechar_vf __P((struct render_state *, u_int, int, int, u_int, u_int)); #endif #ifdef FREETYPE static u_int draw_onechar_tf __P((struct render_state *, u_int, int, int, u_int, char *, int, int)); #endif static char *x_fontname __P((char *, int, char *, int, char *)); static int x_parsefont __P((char *, int *, int*)); static XFontStruct *x_setfont __P((char *, u_int, char *, int *)); static u_int draw_onechar_x __P((struct render_state *, u_int, int, int, int, char *, int)); static void back_gradation __P((struct render_state *, struct ctrl_grad *)); #if 1 /* by h.kakugawa@computer.org */ static void image_load __P((struct render_state *, char *, int, int, int, int, int, int, int, int)); static void image_load_ps __P((struct render_state *, char *, int, int, int, int, int, int, int, int)); #else static void image_load __P((struct render_state *, char *, int, int, int, int, int, int)); static void image_load_ps __P((struct render_state *, char *, int, int, int, int, int, int)); #endif static void process_icon __P((struct render_state *, struct ctrl *)); static void draw_bar __P((struct render_state *, struct ctrl *)); static void process_system __P((struct render_state *, struct ctrl *)); static void process_xsystem __P((struct render_state *, struct ctrl *)); static void process_tsystem __P((struct render_state *, struct ctrl *)); static Window search_child_window __P(()); static Window tsearch_child_window __P((const char *name)); static Window getNamedWindow __P((const char *name, Window top)); static void reparent_child_window __P((Window, int, int)); static char *epstoimage __P((struct render_state *, char *, int, int, int, int, int, int)); static void image_setcolor __P((struct render_state *)); static void x_registerseed __P((struct render_state *, char *, char *)); static char *x_findseed __P((struct render_state *, char *)); static void XClearPixmap __P((Display *, Drawable)); static void cache_page __P((struct render_state *, int)); static void cache_effect1 __P((void)); static void cache_effect2 __P((void)); static void set_from_cache __P((struct render_state *)); static void pcache_process __P((int)); static void predraw __P((struct render_state *)); static void set_background_pixmap __P((struct ctrl *)); static void get_background_pixmap __P((struct ctrl *, struct render_state *)); static void regist_background_pixmap __P((XImageInfo *, Image *)); #ifdef MNG static void process_anim __P((struct render_state *, struct ctrl *)); static void obj_draw_anim __P((struct render_state *, u_int, u_int, struct render_object *)); #endif static int valign = VL_BOTTOM; #define CHECK_CACHE do {if (caching) {caching = -1; return; }} while (0) #ifdef USE_XFT2 static void set_xrender_color __P((long, int)); static XftDraw * xft_getdraw __P((Drawable)); static char *xft_draw_fragment __P((struct render_state *, u_char *, u_int, char *, int)); static int obj_new_xftfont __P((struct render_state *, int, int, char *, int, char *, char *, int, int, XftFont *)); static XftFont * xft_setfont __P((char *, int, char *)); XftFont *xft_font; XftDraw *xft_draw[2]; Drawable xft_xdraw[2]; XftColor xft_forecolor; XRenderColor xft_render_color; #endif static int ispsfilename(p0) char *p0; { char *p; p = p0; while (*p) p++; if (4 < p - p0 && strcasecmp(p - 4, ".eps") == 0) return 1; if (3 < p - p0 && strcasecmp(p - 3, ".ps") == 0) return 1; if (6 < p - p0 && strcasecmp(p - 6, ".idraw") == 0) return 1; return 0; } /* * state management. */ void state_goto(state, page, repaint) struct render_state *state; u_int page; int repaint; { if (!repaint) purgechild(state->page); state->page = page; state->line = 0; state->cp = NULL; state->phase = P_NONE; free_alloc_colors(&image_clr); free_alloc_colors(&font_clr); #ifdef COLOR_BUGFIX colormap = XCopyColormapAndFree(display, colormap); #endif predraw(state); } void state_next(state) struct render_state *state; { switch (state->phase) { case P_NONE: fprintf(stderr, "internal error\n"); break; case P_DEFAULT: if (state->cp) state->cp = state->cp->ct_next; if (!state->cp) { state->cp = page_control[state->page][state->line]; state->phase = P_PAGE; } break; case P_PAGE: if (state->cp) state->cp = state->cp->ct_next; if (!state->cp) { state->line++; state->cp = NULL; state->phase = P_NONE; state_init(state); } break; case P_END: /*nothing*/ break; } /* next page */ if (page_attribute[state->page].pg_linenum < state->line) { if (state->page < maxpage) { purgechild(state->page); if (mgp_flag & FL_FRDCACHE && cached_page == state->page + 1) { /* Hit cache */ set_from_cache(state); pcache_process(state->page); cache_hit = 1; } else { state->phase = P_NONE; state->page++; state->line = 0; state_newpage(state); state_init(state); } } else state->phase = P_END; } } void state_init(state) struct render_state *state; { assert(state); if (state->phase == P_NONE || !state->cp) { #if 0 if (!(page_attribute[state->page].pg_flag & PGFLAG_NODEF)) { state->cp = default_control[state->line]; state->phase = P_DEFAULT; } else #endif { state->cp = page_control[state->page][state->line]; state->phase = P_PAGE; } } } void state_newpage(state) struct render_state *state; { state->ypos = 0; state->have_mark = 0; state->charoff = 0; char_size[caching] = nonscaled_size[caching]; free_alloc_colors(&image_clr); free_alloc_colors(&font_clr); #ifdef COLOR_BUGFIX colormap = XCopyColormapAndFree(display, colormap); #endif predraw(state); } /* * page management. */ void draw_page(state, lastcp) struct render_state *state; struct ctrl *lastcp; { u_int end_line; int pause; assert(state); /* initialize the state, if required. */ if (state->phase != P_END && (state->phase == P_NONE || !state->cp)) { state_newpage(state); state_init(state); } end_line = page_attribute[state->page].pg_linenum; while (1) { switch (state->phase) { case P_NONE: fprintf(stderr, "internal error\n"); cleanup(-1); case P_DEFAULT: case P_PAGE: pause = 0; if (state->cp) process_direc(state, &pause); if (caching == -1) { /* caching failed */ caching = 0; return; } if (lastcp && state->cp == lastcp) goto done; if (pause) { if (state->cp && state->cp->ct_op == CTL_PAUSE && state->cp->cti_value) { goto done; } } break; case P_END: goto done; } #if 0 XFlush(display); #endif state_next(state); } done: XFlush(display); } Bool draw_one(state, e) struct render_state *state; XEvent *e; { u_int end_line; int pause; fd_set fds; int xfd; struct timeval tout; long emask; #ifdef TTY_KEYINPUT KeySym ks; char c; extern volatile int ttykey_enable; #endif assert(state); /* initialize the state, if required. */ if (state->phase != P_END && (state->phase == P_NONE || !state->cp)) { state_newpage(state); state_init(state); } end_line = page_attribute[state->page].pg_linenum; switch (state->phase) { case P_DEFAULT: case P_PAGE: pause = 0; if (state->cp) process_direc(state, &pause); break; case P_END: break; case P_NONE: default: fprintf(stderr, "internal error\n"); cleanup(-1); } xfd = ConnectionNumber(display); if (state->phase != P_END && !pause) emask = xeventmask; else emask = ~NoEventMask; for (;;) { if (XCheckMaskEvent(display, emask, e) == True) { /* we got some event in the queue*/ if (2 <= parse_debug) { fprintf(stderr, "interrupted and " "got X11 event type=%d\n", e->type); } got_event: if (state->phase == P_END) XFlush(display); else if (!pause) state_next(state); return True; } #ifdef TTY_KEYINPUT if (ttykey_enable) { FD_ZERO(&fds); FD_SET(0, &fds); tout.tv_sec = tout.tv_usec = 0; if (select(1, &fds, NULL, NULL, &tout) > 0 && read(0, &c, sizeof(c)) == sizeof(c)) { if (c > 0 && c < ' ') ks = 0xff00 | c; else if (c >= ' ' && c < '\177') ks = c; else if (c == '\177') ks = XK_Delete; else continue; e->xkey.display = display; e->xkey.type = KeyPress; e->xkey.keycode = XKeysymToKeycode(display, ks); if (e->xkey.keycode == 0) continue; goto got_event; } } #endif if (state->phase != P_END && !pause) { state_next(state); return False; } FD_ZERO(&fds); FD_SET(xfd, &fds); #ifdef TTY_KEYINPUT if (ttykey_enable) FD_SET(0, &fds); #endif remapchild(); /* always cache next page */ if ((mgp_flag & FL_FRDCACHE) && cache_mode) { #if 1/*ONOE*/ if (XCheckMaskEvent(display, emask, e) == True) goto got_event; #endif cache_page(&cache_state, state->page +1); /* check if we got some events during caching */ if (XCheckMaskEvent(display, emask, e) == True) goto got_event; } /* wait for something */ tout.tv_sec = 2; tout.tv_usec = 0; (void)select(xfd + 1, &fds, NULL, NULL, &tout); #ifdef TTY_KEYINPUT if (!(mgp_flag & FL_NOSTDIN) && !ttykey_enable) try_enable_ttykey(); #endif /* we have no event in 2sec, so..*/ if (!FD_ISSET(xfd, &fds)) { if ((mgp_flag & FL_FRDCACHE) && !cache_mode) cache_page(&cache_state, state->page +1); timebar(state); e->type = 0; return True; } } /*NOTREACHED*/ } static void process_direc(state, seenpause) struct render_state *state; int *seenpause; { struct ctrl *cp; if (seenpause) *seenpause = 0; cp = state->cp; if (2 <= parse_debug) { fprintf(stderr, "p%d/l%d: ", state->page, state->line); debug0(cp); } switch(cp->ct_op) { case CTL_SUP: if (sup_scale > 1.0 || sup_scale < 0.1) { sup_scale = DEFAULT_SUPSCALE; } if (sup_off > 1.0 || sup_scale < 0.1) { sup_off = DEFAULT_SUPOFF; } state->charoff = -sup_off * nonscaled_size[caching]; char_size[caching] = (int)(nonscaled_size[caching] * sup_scale); break; case CTL_SUB: if (sup_scale > 1.0 || sup_scale < 0.1) { sup_scale = DEFAULT_SUPSCALE; } if (sub_off > 1.0 || sub_off < 0.1){ sub_off = DEFAULT_SUBOFF; } state->charoff = sub_off * nonscaled_size[caching]; char_size[caching] = (int)(nonscaled_size[caching] * sup_scale); break; case CTL_SETSUP: if (cp->cti3_value1 > 100 || cp->cti3_value1 < 10){ sup_off = DEFAULT_SUPOFF; } else { sup_off = cp->cti3_value1 / 100.; } if (cp->cti3_value2 > 100 || cp->cti3_value2 < 10){ sub_off = DEFAULT_SUBOFF; } else { sub_off = cp->cti3_value2 / 100.; } if (cp->cti3_value3 > 100 || cp->cti3_value3 < 10){ sup_scale = DEFAULT_SUPSCALE; } else { sup_scale = cp->cti3_value3 / 100.; } break; case CTL_SIZE: nonscaled_size[caching] = state->height * cp->ctf_value / 100; char_size[caching] = nonscaled_size[caching]; #ifdef FREETYPE tfc_setsize(char_size[caching]); #endif break; case CTL_VGAP: vert_gap[caching] = cp->cti_value; break; case CTL_HGAP: horiz_gap[caching] = cp->cti_value; break; case CTL_GAP: vert_gap[caching] = horiz_gap[caching] = cp->cti_value; break; case CTL_QUALITY: if (!quality_flag) b_quality[caching] = cp->cti_value; break; case CTL_PAUSE: CHECK_CACHE; if (seenpause) *seenpause = 1; break; case CTL_AGAIN: CHECK_CACHE; if (state->have_mark) state->ypos = state->mark_ypos; state->have_mark = 0; break; case CTL_FORE: fore_color[caching] = cp->ctl_value; #ifdef USE_M17N if (! (mgp_flag & FL_NOM17N)) { M17N_set_color (cp->ctl_value); break; } #endif XSetForeground(display, gcfore, fore_color[caching]); break; case CTL_BACK: if (state->line){ fprintf(stderr, "warning: %%back directive should be put in the first line of the page. ignored.\n"); break; } back_color[caching] = cp->ctl_value; bg_ctl = cp; /*update later*/ break; case CTL_CCOLOR: ctrl_color[caching] = cp->ctl_value; break; case CTL_CENTER: state->align = AL_CENTER; break; case CTL_LEFT: state->align = AL_LEFT; break; case CTL_LEFTFILL: state->align = AL_LEFTFILL0; break; case CTL_RIGHT: state->align = AL_RIGHT; break; case CTL_CONT: state->charoff = 0; char_size[caching] = nonscaled_size[caching]; break; #ifdef VFLIB case CTL_VFONT: vfc_setfont(cp->ctc_value); break; #endif /*VFLIB*/ #ifdef FREETYPE case CTL_TFONT: tfc_setfont(cp->ctc2_value1, 0, cp->ctc2_value2); break; case CTL_TMFONT: tfc_setfont(cp->ctc_value, 1, NULL); break; #endif /*FREETYPE*/ case CTL_XFONT2: #ifdef USE_M17N if (! (mgp_flag & FL_NOM17N)) { M17N_set_font (cp->ctc2_value1, cp->ctc2_value2); break; } #endif x_registerseed(state, cp->ctc2_value1, cp->ctc2_value2); break; case CTL_BAR: draw_bar(state, cp); break; case CTL_IMAGE: { if (state->align == AL_LEFTFILL0) { state->align = AL_LEFTFILL1; state->leftfillpos = state->linewidth; } /* quickhack for postscript */ if (ispsfilename(cp->ctm_fname)) { #if 1 /* by h.kakugawa@computer.org */ image_load_ps(state, cp->ctm_fname, cp->ctm_numcolor, cp->ctm_ximagesize, cp->ctm_yimagesize, 0, cp->ctm_zoomflag, 0, cp->ctm_raise, cp->ctm_rotate); #else image_load_ps(state, cp->ctm_fname, cp->ctm_numcolor, cp->ctm_ximagesize, cp->ctm_yimagesize, 0, cp->ctm_zoomflag, 0); #endif } else { #if 1 /* by h.kakugawa@computer.org */ image_load(state, cp->ctm_fname, cp->ctm_numcolor, cp->ctm_ximagesize, cp->ctm_yimagesize, 0, cp->ctm_zoomflag, 0, cp->ctm_raise, cp->ctm_rotate); #else image_load(state, cp->ctm_fname, cp->ctm_numcolor, cp->ctm_ximagesize, cp->ctm_yimagesize, 0, cp->ctm_zoomflag, 0); #endif } state->brankline = 0; } break; case CTL_BIMAGE: if (mgp_flag & FL_BIMAGE) break; bg_ctl = cp; /*update later*/ break; case CTL_BGRAD: if (mgp_flag & FL_BIMAGE) break; bg_ctl = cp; /*update later*/ break; case CTL_LCUTIN: CHECK_CACHE; state->special = SP_LCUTIN; break; case CTL_RCUTIN: CHECK_CACHE; state->special = SP_RCUTIN; break; case CTL_SHRINK: CHECK_CACHE; state->special = SP_SHRINK; break; case CTL_PREFIX: state->curprefix = cp->ctc_value; break; case CTL_PREFIXN: state->xprefix = state->width * cp->ctf_value / 100; break; case CTL_TABPREFIX: state->tabprefix = cp->ctc_value; break; case CTL_TABPREFIXN: state->tabxprefix = state->width * cp->ctf_value / 100; break; case CTL_PREFIXPOS: { char *p; p = (state->tabprefix) ? state->tabprefix : state->curprefix; if (!p) break; #ifdef USE_M17N if (! (mgp_flag & FL_NOM17N)) { cp->ct_op = CTL_TEXT; cp->ctc_value = p; M17N_draw_string (state, cp); break; } #endif draw_line_output(state, p); break; } case CTL_TEXT: if (!cp->ctc_value) break; if (state->align == AL_LEFTFILL0) { state->align = AL_LEFTFILL1; state->leftfillpos = state->linewidth; } #ifdef USE_M17N if (! (mgp_flag & FL_NOM17N)) { M17N_draw_string (state, cp); break; } #endif draw_line_output(state, cp->ctc_value); break; case CTL_LINESTART: state->charoff = 0; char_size[caching] = nonscaled_size[caching]; if (state->line == 0) { /* * set background of target */ if (bg_ctl) { if (!caching){ /* target is window, so we need care bg_ctl_last */ if (bg_ctl_last && !ctlcmp(bg_ctl, bg_ctl_last)){ /* same as last time, we do nothing */ ; } else { /* we have to change background */ get_background_pixmap(bg_ctl, state); /* set window background */ set_background_pixmap(bg_ctl); bg_ctl_last = bg_ctl; } XClearWindow(display, state->target); } else { get_background_pixmap(bg_ctl, state); bg_ctl_cache = bg_ctl; XClearPixmap(display, state->target); } } else { if (!caching) XClearWindow(display, state->target); else XClearPixmap(display, state->target); } if (t_fin) timebar(state); } draw_line_start(state); break; case CTL_LINEEND: /* blank lines */ if (state->brankline) { /*XXX*/ state->max_lineascent = char_size[caching]; state->maxascent = char_size[caching]; state->maxdescent = VERT_GAP(char_size[caching]); } draw_line_end(state); /* reset single-line oriented state */ state->tabprefix = NULL; state->tabxprefix = 0; state->special = 0; if (state->align == AL_LEFTFILL1) { state->align = AL_LEFTFILL0; state->leftfillpos = 0; } break; case CTL_MARK: state->have_mark = 1; state->mark_ypos = state->ypos; break; case CTL_SYSTEM: CHECK_CACHE; process_system(state, cp); break; case CTL_XSYSTEM: CHECK_CACHE; process_xsystem(state, cp); break; case CTL_TSYSTEM: CHECK_CACHE; process_tsystem(state, cp); break; case CTL_ICON: process_icon(state, cp); break; #ifdef VFLIB case CTL_VFCAP: vfcap_name = cp->ctc_value; break; #endif #ifdef FREETYPE case CTL_TFDIR: freetypefontdir = cp->ctc_value; break; case CTL_TFONT0: freetypefont0 = cp->ctc_value; break; case CTL_TMFONT0: freetypemfont0 = cp->ctc_value; break; #endif case CTL_NOOP: case CTL_NODEF: break; case CTL_XFONT: /* obsolete directives */ fprintf(stderr, "internal error: obsolete directive " "\"%s\"\n", ctl_words[cp->ct_op].ctl_string); exit(1); /*NOTREACHED*/ case CTL_PCACHE: if (!caching) { if (cp->ctch_flag) mgp_flag |= FL_FRDCACHE; else mgp_flag ^= FL_FRDCACHE; cache_mode = cp->ctch_mode; cache_effect = cp->ctch_effect; cache_value = cp->ctch_value; } else { pcache.flag = 1; pcache.page = state->page; pcache.mgpflag = cp->ctch_flag; pcache.mode = cp->ctch_mode; pcache.effect = cp->ctch_effect; pcache.value = cp->ctch_value; } break; case CTL_CHARSET: if (get_regid(cp->ctc_value) < 0){ fprintf(stderr, "invalid charset \"%s\". ignored\n", cp->ctc_value); break; } strcpy(mgp_charset, cp->ctc_value); break; #ifdef MNG case CTL_ANIM: if (state->align == AL_LEFTFILL0) { state->align = AL_LEFTFILL1; state->leftfillpos = state->linewidth; } process_anim(state, cp); break; #endif case CTL_VALIGN: valign = cp->cti_value; break; case CTL_AREA: state->width = window_width * cp->ctar_width / 100; state->height = window_height * cp->ctar_height / 100; state->xoff = window_width * cp->ctar_xoff / 100; state->yoff = window_height * cp->ctar_yoff / 100; state->ypos = 0; break; case CTL_OPAQUE: #ifdef USE_XFT2 if (cp->cti_value > 100){ fprintf(stderr, "%%opaque: value should be 0-100\n"); cp->cti_value = 100; } state->opaque = cp->cti_value; if (mgp_flag & FL_NOXFT && verbose){ fprintf(stderr, "ignored %%opaque.\n"); } #else printf("this mgp cannot use %%opaque, needs to be built with xft2\n"); #endif break; case CTL_M17N: #ifdef USE_M17N M17N_process_direc(cp->ctc2_value1, cp->ctc2_value2); #else fprintf(stderr, "this mgp cannot use %%m17n, needs to be built with m17n-lib\n"); #endif break; default: fprintf(stderr, "undefined directive %d at page %d line %d:\n\t", cp->ct_op, state->page, state->line); debug0(cp); break; } } /* * line management. */ static int set_position(state) struct render_state *state; { int x; x = 0; switch (state->align) { case AL_CENTER: x = (state->width - state->linewidth)/ 2; break; case AL_LEFT: case AL_LEFTFILL0: case AL_LEFTFILL1: x = 0; break; case AL_RIGHT: x = state->width - state->linewidth; break; } return x; } void draw_line_start(state) struct render_state *state; { struct render_object *obj; state->max_lineascent = 0; state->max_linedescent = 0; state->maxascent = 0; state->maxdescent = 0; state->linewidth = 0; state->brankline = 1; while ((obj = state->obj)) obj_free(state, obj); } void draw_line_itemsize(state, ascent, descent, flheight) struct render_state *state; int ascent; int descent; int flheight; { ascent -= state->charoff; descent += state->charoff; if (ascent > state->maxascent) state->maxascent = ascent; if (descent > state->maxdescent) state->maxdescent = descent; /* * calculation for the height of a line should ignore * character offset */ if (state->charoff == 0) { if (ascent > state->max_lineascent) state->max_lineascent = ascent; if (descent > state->max_linedescent) state->max_linedescent = descent; } if (flheight > state->maxflheight) state->maxflheight = flheight; } static void draw_line_output(state, data) struct render_state *state; char *data; { draw_string(state, data); } void draw_line_end(state) struct render_state *state; { int xpos; xpos = set_position(state); /* process the special attribute. */ switch (state->special) { #if 0 case SP_SHRINK: shrink(data, page, xpos); break; #endif case SP_LCUTIN: cutin(state, xpos, state->ypos, 1); break; case SP_RCUTIN: cutin(state, xpos, state->ypos, -1); break; default: break; } if (state->obj) { obj_draw(state, state->target, xpos, state->ypos); while (state->obj) obj_free(state, state->obj); } state->ypos += state->max_lineascent; /* * we should ignore height of images to calculate line gap. * suggested by Toru Terao */ if (VERT_GAP(char_size[caching]) < state->max_linedescent) state->ypos += state->max_linedescent; else state->ypos += VERT_GAP(char_size[caching]); state->ypos += 2; } #define min(x, y) (x < y ? x: y) static void cutin(state, lx, ly, dir) struct render_state *state; int lx; int ly; int dir; { u_int step, x, xoff, yoff; int i, sx, round; int root_x, root_y, use_copy; Window cutinWin, junkwin; XImage *copywin; static XWindowAttributes xa; XWindowAttributes wa; Pixmap ghostWin; GC saveGC = gc_cache; XGetWindowAttributes(display, window, &wa); ghostWin = XCreatePixmap(display, window, wa.width, wa.height, wa.depth); /* all drawing should be done on the image */ gc_cache = XCreateGC(display, ghostWin, 0, 0); XCopyArea(display, state->target, ghostWin, gc_cache, 0, 0, wa.width, wa.height, 0, 0); if (state->repaint) return; if (!state->linewidth) return; if (!xa.width) XGetWindowAttributes(display, DefaultRootWindow(display), &xa); XTranslateCoordinates(display, window, DefaultRootWindow(display), 0, 0, &root_x ,&root_y, &junkwin); use_copy = 1; if ((root_x + window_width > xa.width) || (root_y + window_height > xa.height) || (root_x < 0 || root_y < 0)) use_copy = 1; sx = (0 < dir) ? 0 : state->width - state->linewidth; round = 20; /*XXX*/ #ifndef abs #define abs(a) (((a) < 0) ? -(a) : (a)) #endif if (abs(lx - sx) < round){ round = abs(lx - sx); if (!round) round = 1; } step = (lx - sx) / round; if (!use_copy){ cutinWin = XCreateSimpleWindow(display, state->target, sx, ly, state->linewidth, state->maxascent + state->maxdescent, 0, fore_color[caching], back_color[caching]); XSetWindowBackgroundPixmap(display, cutinWin, None); XMapSubwindows(display, state->target); } else { copywin = XGetImage(display, window, state->xoff + min(sx, lx), ly + state->yoff, state->linewidth + abs(lx - sx), state->maxascent + state->maxdescent, AllPlanes, ZPixmap); } xoff = state->xoff; yoff = state->yoff; state->xoff = state->yoff = 0; if (state->obj && !use_copy) { obj_draw(state, cutinWin, 0, 0); } XFlush(display); x = sx; for (i = 0; i < round; i++) { if (use_copy && state->obj) { obj_draw(state, ghostWin, x + xoff, ly + yoff); XCopyArea(display, ghostWin, state->target, saveGC, xoff + min(sx, lx), ly + yoff, state->linewidth + abs(lx - sx), state->maxascent + state->maxdescent, xoff + min(sx, lx), ly + yoff); } else XMoveWindow(display, cutinWin, x + xoff, ly + yoff); XFlush(display); usleep(CUTIN_DELAY); if (use_copy && state->obj) { XPutImage(display, ghostWin, gc_cache, copywin, x - min(sx, lx) , 0, x + xoff, ly + yoff, state->linewidth, state->maxascent + state->maxdescent); } x = sx + ((i+1)*(lx - sx)) / round; } XCopyArea(display, ghostWin, state->target, saveGC, 0, 0, wa.width, wa.height, 0, 0); if (!use_copy) XDestroyWindow(display, cutinWin); state->xoff = xoff; state->yoff = yoff; /* freeing images */ if(use_copy) XFree(copywin); /* restoring tho old GC */ XFreeGC(display, gc_cache); XFreePixmap(display, ghostWin); gc_cache = saveGC; } #if 0 static void shrink(data, page) char *data; u_int page; { u_int min_csize = char_size; u_int max_csize = state->height / 4; u_int csize, i, x; u_int step = (max_csize - min_csize) / 3; if (!step) step = 1; if (state->align != AL_CENTER) { fprintf(stderr, "align is not center: \n"); return; } csize = char_size; for (i = max_csize; i > min_csize; i -= step) { char_size = i; draw_string(state, data); x = (state->width - state->linewidth) / 2; XCopyArea(display, maskpix, state->target, gc, 0, 0, state->linewidth, char_size, x, state->ypos); XCopyArea(display, pixmap, state->target, gcor, 0, 0, state->linewidth, char_size, x, state->ypos); XFlush(display); usleep(SHRINK_DELAY); XFillRectangle(display, pixmap, gcall, 0, 0, state->width, char_size); XFillRectangle(display, maskpix, gcall, 0, 0, state->width, char_size); XClearArea(display, state->target, x, state->ypos, state->linewidth, char_size, 0); } char_size = csize; } #endif /* * render characters. */ static void draw_string(state, data) struct render_state *state; char *data; { u_char *p, *q; char *registry = NULL; u_int code2; static char *rtab96[] = { NULL, /* ESC - @ */ "iso8859-1", /* ESC - A */ "iso8859-2", /* ESC - B */ "iso8859-3", /* ESC - C */ "iso8859-4", /* ESC - D */ }; #define RTAB96_MAX (sizeof(rtab96)/sizeof(rtab96[0])) static char *rtab9494[] = { "jisx0208.1978-*", /* ESC $ @ or ESC $ ( @ */ "gb2312.1980-*", /* ESC $ A or ESC $ ( A */ "jisx0208.1983-*", /* ESC $ B or ESC $ ( B */ "ksc5601.1987-*", /* ESC $ ( C */ NULL, /* D */ NULL, /* E */ NULL, /* F */ NULL, /* G */ NULL, /* H */ NULL, /* I */ NULL, /* J */ NULL, /* K */ NULL, /* L */ NULL, /* M */ NULL, /* N */ "jisx0213.2000-1", /* ESC $ ( O */ "jisx0213.2000-2", /* ESC $ ( P */ }; #define RTAB9494_MAX (sizeof(rtab9494)/sizeof(rtab9494[0])) int charset16 = 0; p = (u_char *)data; while (*p && *p != '\n') { /* 94x94 charset */ if (p[0] == 0x1b && p[1] == '$' && '@' <= p[2] && p[2] < 'C' && rtab9494[p[2] - '@']) { registry = rtab9494[p[2] - '@']; charset16 = 1; p += 3; continue; } if (p[0] == 0x1b && p[1] == '$' && p[2] == '(' && '@' <= p[3] && p[3] < '@' + RTAB9494_MAX && rtab9494[p[3] - '@']) { registry = rtab9494[p[3] - '@']; charset16 = 1; p += 4; continue; } /* ascii (or JIS roman) */ if (p[0] == 0x1b && p[1] == '(' && (p[2] == 'B' || p[2] == 'J')) { registry = NULL; charset16 = 0; p += 3; continue; } /* 96 charset */ if (p[0] == 0x1b && p[1] == '-' && '@' < p[2] && p[2] < '@' + RTAB96_MAX && rtab96[p[2] - '@']) { registry = rtab96[p[2] - '@']; charset16 = 0; p += 3; continue; } if (!registry && isspace(p[0])) { draw_fragment(state, p, 1, registry, 0); p++; continue; } if (charset16) { for (q = p + 2; 0x21 <= *q && *q <= 0x7e; q += 2) { code2 = q[0] * 256 + q[1]; if (strncmp(registry, "jisx0208", 8) == 0 && !iskinsokuchar(code2)) { break; } } } else { q = p; while (*q && isprint(*q) && !isspace(*q)) q++; if (q == p) q++; else { /* * append spaces to the end of the word. * fragments in the following line: * "this is test" * are: * "this_" "is_" "test" */ while (*q && isspace(*q)) q++; } } q = draw_fragment(state, p, q - p, registry, charset16); p = q; } } static char * draw_fragment(state, p, len, registry, charset16) struct render_state *state; u_char *p; u_int len; char *registry; int charset16; /*2-octet charset?*/ { u_int char_len, i; u_short code; struct render_object *tail; struct render_object *thisline; struct render_object *thislineend; u_int startwidth; struct render_state backup0, backup; enum { MODE_UNKNOWN, MODE_X, MODE_VFLIB, MODE_FREETYPE } mode = MODE_UNKNOWN; char *p0; #ifdef USE_XFT2 if (!(mgp_flag & FL_NOXFT)){ p0 = xft_draw_fragment(state, p, len, registry, charset16); if (p0) return p0; } #endif if (state->obj) tail = state->objlast; else tail = NULL; startwidth = state->linewidth; while (len) { code = charset16 ? p[0] * 256 + p[1] : p[0]; if (code != ' ') state->brankline = 0; /* This isn't brankline */ #if 0 if (code == ' ') { char_len = char_size[caching] / 2; p++; len--; state->linewidth += HORIZ_STEP(char_size[caching], char_len); continue; } #endif if (code == '\t') { char_len = char_size[caching] / 2; p++; len--; char_len = HORIZ_STEP(char_size[caching], char_len) * 8;/*XXX*/ state->linewidth = (state->linewidth + char_len) / char_len * char_len; continue; } /* * decide which font to use. * Japanese font: * VFlib - optional * then X. * Western font: * If possible, freetype. (in the future) - optional * X if truely scalable. * VFlib if it is larger than some size - optional * otherwise, X. */ mode = MODE_UNKNOWN; if (charset16) { #ifdef VFLIB if (!(mgp_flag & FL_NOVFLIB) && strncmp(registry, "jisx0208.1983-", 14) == 0) mode = MODE_VFLIB; #endif #ifdef FREETYPE_CHARSET16 if (!(mgp_flag & FL_NOFREETYPE) && (strncmp(registry, "jisx0208.1983-", 14) == 0 || strncmp(registry, "jisx0213.2000-", 14) == 0)) { if (tfc_get(code, char_size[caching], 1, registry, charset16)){ mode = MODE_FREETYPE; } } #endif if (mode == MODE_UNKNOWN) mode = MODE_X; } else { #ifdef FREETYPE if (!(mgp_flag & FL_NOFREETYPE)) { if (tfc_get(code, char_size[caching], 1, registry, charset16)) { mode = MODE_FREETYPE; } } #endif if (mode == MODE_UNKNOWN) { /* * if we can have X font that is exactly * matches the required size, we use that. */ XFontStruct *xfontstruct; int ts; xfontstruct = x_setfont( x_findseed(state, registry), char_size[caching], registry, &ts); if (ts) mode = MODE_X; } #ifdef VFLIB # ifdef USE_XDRAWSTRING_ONLY_SMALL if (!(mgp_flag & FL_NOVFLIB) && mode == MODE_UNKNOWN) { if (25 < char_size) mode = MODE_VFLIB; } # endif /* USE_XDRAWSTRING_ONLY_SMALL */ #endif /* last resort: use X font. */ if (mode == MODE_UNKNOWN) mode = MODE_X; } /* back it up before drawing anything */ memcpy(&backup0, state, sizeof(struct render_state)); switch (mode) { #ifdef VFLIB case MODE_VFLIB: char_len = draw_onechar_vf(state, code, state->linewidth, state->charoff, registry ? char_size[caching] : (char_size[caching] * 4 / 5), /*XXX*/ char_size[caching]); break; #endif #ifdef FREETYPE case MODE_FREETYPE: /* * NOTE: width and height parameter (4th and 5th) * are meaningless for FreeType, since we use * metric info derived from TrueType font file. */ char_len = draw_onechar_tf(state, code, state->linewidth, state->charoff, char_size[caching], registry, (len == (charset16 ? 2 : 1)) ? 1 : 0, charset16); break; #endif default: fprintf(stderr, "invalid drawing mode %d for %04x " "- fallback to X11\n", mode, code); /* fall through */ case MODE_UNKNOWN: case MODE_X: char_len = draw_onechar_x(state, code, state->linewidth, state->charoff, char_size[caching], registry, (len == (charset16 ? 2 : 1)) ? 1 : 0); if (char_len == 0) { fprintf(stderr, "can't load font size %d " "(nor font in similar size) for " "font <%s:%d:%s>, glyph 0x%04x\n", char_size[caching], x_findseed(state, registry), char_size[caching], registry?registry:"NULL", code); } break; } p += (charset16 ? 2 : 1); len -= (charset16 ? 2 : 1); state->linewidth += HORIZ_STEP(char_size[caching], char_len); /* ukai */ if (!charset16 && state->linewidth + HORIZ_STEP(char_size[caching], char_len) > state->width) { if (len >= 20) break; /* too long word */ for (i = 0; i < len; i ++){ if (isspace(*(p +i))) break; } if (i == len) break; } } if (state->width - state->leftfillpos / 2 < state->linewidth #if 0 && state->align == AL_LEFTFILL1 #endif ) { memcpy(&backup, state, sizeof(struct render_state)); /* strip off the last fragment we wrote. */ if (tail) { thisline = tail->next; thislineend = state->objlast; tail->next = NULL; state->objlast = tail; state->maxascent = backup0.maxascent; state->maxdescent = backup0.maxdescent; } else { thisline = state->obj; thislineend = state->objlast; state->obj = state->objlast = NULL; state->maxascent = backup0.maxascent; state->maxdescent = backup0.maxdescent; } #if 0 state->align = AL_LEFT; #endif state->linewidth = startwidth; draw_line_end(state); /* flush the line. */ /* start the new line with the last fragment we wrote. */ draw_line_start(state); state->linewidth = state->leftfillpos; state->linewidth += (backup.linewidth - startwidth); if (state->obj && state->objlast) state->objlast->next = thisline; else state->obj = thisline; state->objlast = thislineend; state->align = backup.align; /* fix up x position and maxascent. */ for (tail = state->obj; tail; tail = tail->next) { tail->x -= startwidth; tail->x += state->leftfillpos; draw_line_itemsize(state, tail->ascent, tail->descent, 0); } } return p; } static int iskinsokuchar(code) u_int code; { u_short *kinsoku; for (kinsoku = kinsokutable; *kinsoku; kinsoku++) { if (code == *kinsoku) return 1; } return 0; } static struct render_object * obj_alloc(state) struct render_state *state; { struct render_object *obj; obj = malloc(sizeof(*obj)); if (obj == NULL) return NULL; obj->next = NULL; if (state->obj == NULL) state->obj = obj; else state->objlast->next = obj; state->objlast = obj; return obj; } static void obj_free(state, obj) struct render_state *state; struct render_object *obj; { struct render_object *o; if (state->obj == obj) state->obj = obj->next; else { for (o = state->obj; o; o = o->next) if (o->next == obj) break; /* ASSERT(o != NULL); */ o->next = obj->next; } if (state->objlast == obj) state->objlast = obj->next; switch (obj->type) { #ifdef VFLIB case O_VFONT: obj->data.vfc->ref--; break; #endif /* VFLIB */ #ifdef FREETYPE case O_TFONT: obj->data.tfc->ref--; break; #endif /* FREETYPE */ case O_IMAGE: freeImage(obj->data.image.image); break; case O_XFONT: free(obj->data.xfont.xfont); break; case O_ICON: if (obj->data.icon.xpoint) free(obj->data.icon.xpoint); break; #ifdef USE_XFT2 case O_XTFONT: if (obj->data.xftfont.data) free(obj->data.xftfont.data); if (obj->data.xftfont.fontname) free(obj->data.xftfont.fontname); if (obj->data.xftfont.registry) free(obj->data.xftfont.registry); break; #endif #ifdef USE_M17N case O_M17NTEXT: /* XXX we need to add free function for mtext data here! */ m17n_object_unref(obj->data.m17ntext.mt); break; #endif #ifdef MNG case O_ANIM: break; #endif /* MNG */ } free(obj); } #ifdef VFLIB static int obj_new_vfont(state, x, y, vfc, size) struct render_state *state; int x, y; struct vfont *vfc; int size; { struct render_object *obj; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->fore = fore_color[caching]; obj->type = O_VFONT; obj->data.vfc = vfc; obj->data.vfc->size = size; obj->ascent = obj->data.vfc->ascent - y; obj->descent = obj->data.vfc->descent + y; obj->vertloc = VL_BASE; vfc->ref++; return 1; } #endif /* VFLIB */ #ifdef FREETYPE static int obj_new_tfont(state, x, y, tfc) struct render_state *state; int x, y; struct tfont *tfc; { struct render_object *obj; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->fore = fore_color[caching]; obj->type = O_TFONT; obj->data.tfc = tfc; obj->ascent = obj->data.tfc->ascent - y; obj->descent = obj->data.tfc->descent + y; obj->vertloc = VL_BASE; tfc->ref++; return 1; } #endif /* FREETYPE */ static int obj_new_xfont(state, x, y, size, code, registry) struct render_state *state; int x, y; int size; u_int code; char *registry; { struct render_object *obj; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->fore = fore_color[caching]; obj->type = O_XFONT; obj->data.xfont.xfont = strdup(x_findseed(state, registry)); obj->data.xfont.csize = size; obj->data.xfont.code = code; obj->data.xfont.registry = registry; obj->ascent = size - y; /*XXX*/ obj->descent = -y; /*XXX*/ obj->vertloc = VL_BASE; return 1; } static int obj_new_image(state, x, y, image, xzoom, yzoom) struct render_state *state; int x, y; Image *image; int xzoom, yzoom; { struct render_object *obj; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->type = O_IMAGE; obj->data.image.image = image; obj->data.image.xzoom = xzoom; obj->data.image.yzoom = yzoom; obj->ascent = 0; /*XXX*/ obj->descent = image->height * yzoom / 100; /*XXX*/ obj->vertloc = VL_TOP; return 1; } static int obj_new_icon(state, x, y, itype, isize, color, npoint, xpoint) struct render_state *state; int x, y; u_int itype, isize; u_long color; u_int npoint; XPoint *xpoint; { struct render_object *obj; int i; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->fore = color; obj->type = O_ICON; obj->data.icon.itype = itype; obj->data.icon.isize = isize; obj->data.icon.npoint = npoint; if (npoint) { obj->data.icon.xpoint = malloc(sizeof(XPoint) * npoint); if (obj->data.icon.xpoint == NULL) { obj_free(state, obj); return 0; } for (i = 0; i < npoint; i++) obj->data.icon.xpoint[i] = xpoint[i]; } else obj->data.icon.xpoint = NULL; obj->ascent = 0; /*XXX*/ obj->descent = isize; /*XXX*/ obj->vertloc = VL_CENTER; #ifdef USE_M17N // Adjust icon position for line folding function if (mgp_flag & FL_NOM17N) obj->vertloc = VL_CENTER; else obj->vertloc = VL_ICENTER; #endif return 1; } static Pixel obj_image_color(image, bimage, d, inithist) Image *image, *bimage; Pixel d; int *inithist; { int i, j; RGBMap rgb; int r, g, b; static char hist[256]; byte *p; switch (bimage->type) { case IBITMAP: r = g = b = d ? 0xffff : 0; break; case IRGB: r = bimage->rgb.red[d]; g = bimage->rgb.green[d]; b = bimage->rgb.blue[d]; break; case ITRUE: r = TRUE_RED(d) << 8; g = TRUE_GREEN(d) << 8; b = TRUE_BLUE(d) << 8; break; default: return 0; } if (image->type == ITRUE) return RGB_TO_TRUE(r, g, b); for (i = 0; i < image->rgb.used; i++) { if (image->rgb.red[i] == r && image->rgb.green[i] == g && image->rgb.blue[i] == b) return i; } if (i >= image->rgb.size) { if (i >= 256) { /* search a free slot */ if (image->rgb.size == 256) { if (!*inithist) { *inithist = 1; memset(hist, 0, sizeof(hist)); p = image->data; for (j = 0; j < image->height; j++) for (i = 0; i < image->width; i++) hist[*p++] = 1; } for (i = 0; i < 256; i++) { if (hist[i] == 0) { hist[i] = 1; goto freeslot; } } } return -1; } image->depth = 8; newRGBMapData(&rgb, depthToColors(image->depth)); for (i = 0; i < image->rgb.used; i++) { rgb.red[i] = image->rgb.red[i]; rgb.green[i] = image->rgb.green[i]; rgb.blue[i] = image->rgb.blue[i]; } rgb.used = i; freeRGBMapData(&image->rgb); image->rgb = rgb; } freeslot: image->rgb.red[i] = r; image->rgb.green[i] = g; image->rgb.blue[i] = b; if (image->rgb.used < i + 1) image->rgb.used = i + 1; return i; } static Image * obj_image_trans(image, x, y) Image *image; u_int x, y; { Image *timage; int i, j; byte *p, *b; Pixel d, n, pd; static XColor xcol; int pl, bpl; int trans; u_int bw, bh, bx, by; int inithist; if (!COMPLEX_BGIMAGE) { if (back_color[caching] != xcol.pixel) { xcol.pixel = back_color[caching]; xcol.flags = DoRed|DoGreen|DoBlue; XQueryColor(display, colormap, &xcol); } switch (image->type) { case IBITMAP: case IRGB: image->rgb.red[image->trans] = xcol.red; image->rgb.green[image->trans] = xcol.green; image->rgb.blue[image->trans] = xcol.blue; break; case ITRUE: d = image->trans; n = RGB_TO_TRUE(xcol.red, xcol.green, xcol.blue); pl = image->pixlen; p = image->data; for (j = 0; j < image->height; j++) { for (i = 0; i < image->width; i++, p += pl) { if (memToVal(p, pl) == d) valToMem(n, p, pl); } } break; } bw = bh = 0; /* for lint */ goto end; } bh = bgpixmap[bgindex].image->height; bw = bgpixmap[bgindex].image->width; j = 0; if (image->type == IBITMAP) { expand: timage = image; if (verbose) fprintf(stderr, "obj_image_trans: expanding image\n"); image = expand(image); if (image != timage) freeImage(timage); } pl = image->pixlen; p = image->data + image->width * j * pl; bpl = bgpixmap[bgindex].image->pixlen; pd = -1; n = 0; /* for lint */ trans = image->trans; inithist = 0; for ( ; j < image->height; j++) { by = (y + j) % bh; bx = x % bw; b = bgpixmap[bgindex].image->data + (bgpixmap[bgindex].image->width * by + bx) * bpl; for (i = 0; i < image->width; i++, p += pl, b += bpl, bx++) { if (bx == bw) { bx = 0; b = bgpixmap[bgindex].image->data + bgpixmap[bgindex].image->width * by * bpl; } if (memToVal(p, pl) != trans) continue; d = memToVal(b, bpl); if (d != pd) { pd = d; n = obj_image_color(image, bgpixmap[bgindex].image, d, &inithist); if (n == -1) goto expand; } valToMem(n, p, pl); } } end: if (verbose) { char *p; switch (image->type) { case IBITMAP: p = "bitmap"; break; case IRGB: p = "rgb"; break; default: p = "true"; break; } fprintf(stderr, "obj_image_trans: %s: " "trans=%d, rgb_used=%d, rgb_size=%d\n", p, image->trans, image->rgb.used, image->rgb.size); fprintf(stderr, " image=%dx%d+%d+%d", image->width, image->height, x, y); if (COMPLEX_BGIMAGE) fprintf(stderr, " bgpixmap[bgindex].image=%dx%d", bw, bh); fprintf(stderr, "\n"); } image->trans = -1; /* XXX: need recalculation to redraw? */ return image; } static void obj_draw_image(target, x, y, obj) Drawable target; u_int x, y; struct render_object *obj; { Image *image, *timage; XImageInfo *ximageinfo; XImage *xim; int private = mgp_flag & FL_PRIVATE; image = obj->data.image.image; if (obj->data.image.xzoom != 100.0 || obj->data.image.yzoom != 100.0) { timage = image; image = zoom(image, obj->data.image.xzoom, obj->data.image.yzoom, verbose); if (!image) { fprintf(stderr, "image zoom (%0.2fx%0.2f) failed in obj_draw_image\n", obj->data.image.xzoom, obj->data.image.yzoom); exit(1); } freeImage(timage); } if (image->trans >= 0) image = obj_image_trans(image, x, y); obj->data.image.image = image; /* to free later */ ximageinfo= imageToXImage(display, screen, visual, depth, image, private, 0,0, verbose); if (ximageinfo == NULL) { fprintf(stderr, "Cannot convert Image to XImage\n"); cleanup(-1); } xim = ximageinfo->ximage; if (xim->format == XYBitmap) XSetBackground(display, gcfore, back_color[caching]); XPutImage(display, target, gcfore, xim, 0, 0, x, y, xim->width, xim->height); freeXImage(image, ximageinfo); } static void obj_draw(state, target, xpos, ypos) struct render_state *state; Drawable target; u_int xpos, ypos; { struct render_object *obj; int x = 0, y = 0; int width, height, xwidth, xheight; u_long fore; u_int code; char *registry; XChar2b kch[2]; #define MAXDRAWAREA 1024 struct { int x, y, width, height; } drawarea[MAXDRAWAREA]; int areaindex = 0; #define addarea(X) \ {\ if (areaindex == MAXDRAWAREA){\ fprintf(stderr, "too many drawarea (increase MAXDRAWAREA)\n");\ exit(1);\ }\ drawarea[areaindex].x = x;\ drawarea[areaindex].y = y - obj->data.X->ascent;\ drawarea[areaindex].width = obj->data.X->xmax+1;\ drawarea[areaindex].height = obj->data.X->height+1;\ areaindex ++;\ } #if 0 char ch[2]; #endif u_int isize; int i; int lineoff; /* ypos correction for lines with superscripts */ #ifdef RASTERLIB XImage *bim, *xim; u_long bcolor; #endif /* RASTERLIB */ /* * very complicated... * * xpos, ypos x/y position of the target, * leftmost and uppermost dot. * state->ypos absolute y position in main window. */ xpos += state->tabxprefix ? state->tabxprefix : state->xprefix; width = (state->linewidth <= state->width - xpos) ? state->linewidth : state->width - xpos; height = state->maxascent + state->maxdescent + 1; xpos += state->xoff; ypos += state->yoff; fore = fore_color[caching]; /* * only used with superscript offset for calculating the * exact line position (ypos correction) */ lineoff = state->maxascent - state->max_lineascent; #ifdef RASTERLIB bcolor = back_color[caching]; for (obj = state->obj; obj; obj = obj->next) { #ifdef VFLIB if (obj->type == O_VFONT){ xwidth = obj->data.vfc->width; xheight = obj->data.vfc->height; break; } #endif /* VFLIB */ #ifdef FREETYPE if (obj->type == O_TFONT){ xwidth = obj->data.tfc->width; xheight = obj->data.tfc->height; break; } #endif /* FREETYPE */ } if (obj != NULL) { /* VFONT exist */ xim = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, width, height, 8 << (depth - 1) / 8, 0); xim->data = malloc(xim->bytes_per_line * height); if (COMPLEX_BGIMAGE) { u_int bw, bh, bx, by, ox, oy; u_long p; u_long r, g, b; byte *bp; int bpl; XColor col; bim = bgpixmap[bgindex].ximageinfo->ximage; bw = bim->width; bh = bim->height; ox = xpos; oy = state->ypos + state->yoff; bcolor = (u_long)-1; /* tell vfc_image() to calculate */ by = oy % bh; if (bw == 1) { r = g = b = 0; bpl = bgpixmap[bgindex].image->pixlen; bp = bgpixmap[bgindex].image->data + by * bpl; for (y = 0; y < height; y++, by++, bp += bpl) { if (by == bh) by = 0; p = memToVal(bp, bpl); if (TRUEP(bgpixmap[bgindex].image)) { r += TRUE_RED(p) << 8; g += TRUE_GREEN(p) << 8; b += TRUE_BLUE(p) << 8; } else { r += bgpixmap[bgindex].image->rgb.red[p]; g += bgpixmap[bgindex].image->rgb.green[p]; b += bgpixmap[bgindex].image->rgb.blue[p]; } p = XGetPixel(bim, 0, by); for (x = 0; x < width; x++) XPutPixel(xim, x, y, p); } col.red = r / height; col.green = g / height; col.blue = b / height; col.flags = DoRed|DoGreen|DoBlue; /* XXX:actually we don't need to allocate. */ if (XAllocColor(display, colormap, &col)) { regist_alloc_colors(&font_clr, &col.pixel, 1); bcolor = col.pixel; } #if 0 fprintf(stderr, "bim=%dx%d, r=%x, g=%x, b=%x, " "bcolor=%x\n", bgpixmap[bgindex].image->width, bgpixmap[bgindex].image->height, col.red, col.green, col.blue, bcolor); #endif } else { for (y = 0; y < height; y++, by++) { if (by == bh) by = 0; for (x = 0, bx = ox % bw; x < width; x++, bx++) { if (bx == bw) bx = 0; p = XGetPixel(bim, bx, by); XPutPixel(xim, x, y, p); } } } } else { memset(xim->data, 0, xim->bytes_per_line * height); XAddPixel(xim, bcolor); } for ( ; obj; obj = obj->next) { x = obj->x; switch (obj->vertloc) { case VL_BASE: y = state->maxascent; break; case VL_CENTER: y = (state->maxascent + state->maxdescent) / 2; y += (obj->ascent - obj->descent) / 2; break; case VL_TOP: y = obj->ascent; break; case VL_BOTTOM: y = state->maxascent + state->maxdescent; y -= obj->descent; break; } y += obj->y; #ifdef VFLIB if (obj->type == O_VFONT) { (void)vfc_image(obj->data.vfc, obj->fore, bcolor, xim, x, y); addarea(vfc); } #endif /* VFLIB */ #ifdef FREETYPE if (obj->type == O_TFONT) { (void)tfc_image(obj->data.tfc, obj->fore, bcolor, xim, x, y); addarea(tfc); } #endif /* FREETYPE */ } #if 0 XPutImage(display, target, gcfore, xim, 0, 0, xpos, ypos, width, height); #else for (i = 0; i < areaindex; i ++) XPutImage(display, target, gcfore, xim, drawarea[i].x, drawarea[i].y, drawarea[i].x + xpos, ypos + drawarea[i].y - lineoff, drawarea[i].width, drawarea[i].height); #endif XDestroyImage(xim); if (mgp_flag & FL_GLYPHEDGE) { XDrawLine(display, target, gcfore, state->xoff, ypos, state->xoff + state->width - 1, ypos); XDrawLine(display, target, gcfore, state->xoff, ypos + state->maxascent, state->xoff + state->width - 1, ypos + state->maxascent); XDrawLine(display, target, gcgreen, state->xoff, ypos + state->maxascent + state->maxdescent, state->xoff + state->width - 1, ypos + state->maxascent + state->maxdescent); XDrawLine(display, target, gcred, state->xoff, ypos + height, state->xoff + state->width - 1, ypos + height); } } #endif /* RASTERLIB */ for (obj = state->obj; obj; obj = obj->next) { #if 0 x = obj->x + offx; y = obj->y + offy; #else x = obj->x; switch (obj->vertloc) { case VL_BASE: y = state->maxascent; break; case VL_ICENTER: if (state->maxflheight){ y = (state->maxascent + state->maxflheight) / 2; } else y = (state->maxascent + state->maxdescent) / 2; y += (obj->ascent - obj->descent) / 2; break; case VL_CENTER: y = (state->maxascent + state->maxdescent) / 2; y += (obj->ascent - obj->descent) / 2; break; case VL_TOP: y = obj->ascent; break; case VL_BOTTOM: y = state->maxascent + state->maxdescent; y -= obj->descent; break; } x += xpos; y += ypos; #endif switch (obj->type) { #ifdef MNG case O_ANIM: obj_draw_anim(state, x, y, obj); break; #endif /* MNG */ case O_IMAGE: obj_draw_image(target, x, y, obj); break; #ifdef USE_XFT2 case O_XTFONT: y += obj->y; set_xrender_color(obj->fore, state->opaque); xft_font = xft_setfont(obj->data.xftfont.fontname, obj->data.xftfont.size, obj->data.xftfont.registry); if (obj->data.xftfont.charset16){ XftDrawStringUtf8(xft_getdraw(target), &xft_forecolor, xft_font, x, y - lineoff, obj->data.xftfont.data, obj->data.xftfont.len); } else XftDrawString8(xft_getdraw(target), &xft_forecolor, xft_font, x, y - lineoff, obj->data.xftfont.data, obj->data.xftfont.len); break; #endif #ifdef USE_M17N case O_M17NTEXT: y += obj->y; M17N_draw_object(obj, target, x, y); break; #endif case O_XFONT: y += obj->y; code = obj->data.xfont.code; registry = obj->data.xfont.registry; (void)x_setfont(obj->data.xfont.xfont, obj->data.xfont.csize, registry, NULL); if (obj->fore != fore) { fore = obj->fore; XSetForeground(display, gcfore, fore); } #if 1 /* is it always okay? */ kch[0].byte1 = (code >> 8) & 0xff; kch[0].byte2 = code & 0xff; XDrawString16(display, target, gcfore, x, y - lineoff, kch, 1); #else if (registry) { kch[0].byte1 = (code >> 8) & 0xff; kch[0].byte2 = code & 0xff; XDrawString16(display, target, gcfore, x, y - lineoff, kch, 1); } else { ch[0] = code & 0xff; XDrawString(display, target, gcfore, x, y - lineoff, ch, 1); } #endif break; case O_ICON: if (obj->fore != fore) { fore = obj->fore; XSetForeground(display, gcfore, fore); } isize = obj->data.icon.isize; switch (obj->data.icon.itype) { case 1: /* this is box */ XFillRectangle(display, target, gcfore, x, y, isize, isize); break; case 2: /* this is arc */ XFillArc(display, target, gcfore, x, y, isize, isize, 0, 360 * 64); break; case 3: case 4: case 5: case 6: case 7: for (i = 0; i < obj->data.icon.npoint; i++) { obj->data.icon.xpoint[i].x += x; obj->data.icon.xpoint[i].y += y; } XFillPolygon(display, target, gcfore, obj->data.icon.xpoint, obj->data.icon.npoint, Convex, CoordModeOrigin); break; } break; default: break; } } if (fore != fore_color[caching]){ XSetForeground(display, gcfore, fore_color[caching]); } /* ASSERT(state->obj == NULL); */ /* ASSERT(state->objlast == NULL); */ } #ifdef VFLIB static u_int draw_onechar_vf(state, code, x, y, width, height) struct render_state *state; u_int code; int x, y; u_int width, height; { struct vfont *vfc; vfc = vfc_get(code, width, height, 1); draw_line_itemsize(state, vfc->ascent, vfc->descent, 0); obj_new_vfont(state, x, y, vfc, height); return vfc->charlen; } #endif /* VFLIB */ static char * x_fontname(buf, bufsiz, seed, siz, registry) char *buf; int bufsiz; char *seed; int siz; char *registry; /* already canonicalized */ { int hyphen; char *p; char tmp[BUFSIZ]; char tmp2[BUFSIZ]; char **fontlist; int count; if (!registry) registry = "iso8859-1"; if (siz < 0) strcpy(tmp2, "*"); else sprintf(tmp2, "%d", siz); hyphen = 0; for (p = seed; *p; p++) { if (*p == '-') hyphen++; } switch (hyphen) { case 0: /* for "a14", "5x8", or such an short names */ if ((fontlist = XListFonts(display, seed, 1, &count))) { XFreeFontNames(fontlist); strcpy(buf, seed); break; } sprintf(tmp, "%s-*-*", seed); sprintf(buf, FONT_FORMAT, tmp, tmp2, registry); break; case 2: sprintf(buf, FONT_FORMAT, seed, tmp2, registry); break; case XLFD_HYPHEN: /* as is */ strcpy(buf, seed); break; case 1: /* should not happen */ fprintf(stderr, "internal error: invalid seed <%s>\n", seed); exit(1); } if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "fontname: seed=<%s> siz=<%d> reg=<%s> " "result=<%s>\n", seed, siz, registry, buf); } return buf; } static int x_parsefont(xfont, pixel, truescalable) char *xfont; int *pixel; int *truescalable; { char *p; int fsize; int i; /* go toward pixel size */ p = xfont; for (i = 0; *p && i < 7; i++) { /* go toward minus sign */ while (*p && *p != '-') p++; /* skip minus sign */ if (*p) p++; } if (!*p) return -1; fsize = atoi(p); if (pixel) *pixel = fsize; /* skip pixel size */ while (*p && (isdigit(*p) || *p == '*')) p++; if (*p == '-') p++; else return -1; /* skip point size */ while (*p && (isdigit(*p) || *p == '*')) p++; if (*p == '-') p++; else return -1; if (truescalable) { if (fsize == 0 && (p[0] == '0' || p[0] == '*') && p[1] == '-') *truescalable = 1; else *truescalable = 0; } return 0; } static XFontStruct * x_setfont(xfont, csize, registry, truescalable) char *xfont; u_int csize; char *registry; int *truescalable; { static XFontStruct *xfontstruct; int i, fsize; char fontstring[BUFSIZ]; #define FONTTYPEMAX 10 /* number of used fontlist type (in cache) */ #define FONTLISTMAX 20 /* number of list for specified font type */ #define FONTALLOWMAX 105 /* % of desired font */ #define FONTALLOWMIN 90 /* % of desired font */ char **fontlist, **font; u_int error; int best, freeindex, count; int maxsize, minsize; int scalable, tscalable, tsflag; static struct { char *xlfd; char **list; int count; } fontnames[FONTTYPEMAX]; #define FONTCACHEMAX 200 /* number of used font type (in cache) */ static struct { char *xfont; u_int csize; char *registry; char *xlfd; XFontStruct *xfontstruct; } fonts[FONTCACHEMAX]; /* * Check font cache first. */ for (i = 0; i < FONTCACHEMAX; i++) { if (!fonts[i].xfontstruct) continue; if (fonts[i].csize != csize || fonts[i].registry != registry || strcmp(fonts[i].xfont, xfont) != 0) { continue; } #if 0 if (verbose) { fprintf(stderr, "font cache hit: entry %d <%s>\n", i, fonts[i].xlfd); } #endif XSetFont(display, gcfore, fonts[i].xfontstruct->fid); return fonts[i].xfontstruct; } /* * load new font. */ if (csize < 5) { xfontstruct = XLoadQueryFont(display, "nil2"); goto gotfont; } if (verbose) { fprintf(stderr, "need font <%s:%d:%s>\n", xfont, csize, registry?registry:"NULL"); } /* * Look for the best font possible. * 1. Check for a font that is smaller than the required one. * By using smaller font, we won't make the screen garbled. * 2. If 1. is impossible, look for slightly larger font than * the required one. */ fontlist = NULL; freeindex = -1; x_fontname(fontstring, sizeof(fontstring), xfont, -1, registry); if (verbose) fprintf(stderr, "fontstring <%s>\n", fontstring); for (i = 0; i < FONTTYPEMAX; i++) { if (fontnames[i].xlfd == NULL) { if (freeindex < 0) freeindex = i; continue; } if (strcmp(fontnames[i].xlfd, fontstring) == 0) { fontlist = fontnames[i].list; count = fontnames[i].count; freeindex = i; break; } } if (fontlist == NULL) { fontlist = XListFonts(display, fontstring, FONTLISTMAX, &count); if (fontlist == NULL) return NULL; if (freeindex >= 0) { if (fontnames[freeindex].xlfd) free(fontnames[freeindex].xlfd); fontnames[freeindex].xlfd = strdup(fontstring); fontnames[freeindex].list = fontlist; fontnames[freeindex].count = count; } } error = (u_int)-1; best = -1; maxsize = csize * FONTALLOWMAX / 100; /* truncate */ minsize = (csize * FONTALLOWMIN + 99) / 100; /* roundup */ if (verbose) fprintf(stderr, "checking %d to %d\n", minsize, maxsize); scalable = tscalable = -1; if (truescalable) *truescalable = 0; for (i = 0, font = fontlist; i < count; i++, font++) { if (x_parsefont(*font, &fsize, &tsflag) < 0) { #if 1 if (verbose) { fprintf(stderr, " [%d] <%s>: nosize\n", i, *font); } #endif continue; } if (fsize == 0) { if (scalable < 0) scalable = i; if (tsflag) { tscalable = i; if (truescalable) *truescalable = 1; } if (verbose) { fprintf(stderr, " [%d] <%s>: scalable (%d)\n", i, *font, tsflag); } continue; } else if (fsize > maxsize || fsize < minsize) { #if 0 if (verbose) { fprintf(stderr, " [%d] <%s>: reject\n", i, *font); } #endif continue; } if (fsize > csize) { fsize = fsize - csize + 100; /* penalty for larger font */ } else fsize = csize - fsize; if (error > fsize) { error = fsize; best = i; if (verbose) { fprintf(stderr, " [%d] <%s>: score %d best\n", i, *font, error); } } else { if (verbose) { fprintf(stderr, " [%d] <%s>: score %d\n", i, *font, error); } } } if (best >= 0) { if (verbose) { fprintf(stderr, "using best [%d] <%s>\n", best, fontlist[best]); } strlcpy(fontstring, fontlist[best], sizeof(fontstring)); } else if (scalable >= 0 || tscalable >= 0) { x_fontname(fontstring, sizeof(fontstring), xfont, csize, registry); if (verbose) { fprintf(stderr, "using %sscalable <%s>\n", tscalable >= 0 ? "true" : "", fontstring); } } xfontstruct = XLoadQueryFont(display, fontstring); if (freeindex < 0) XFreeFontNames(fontlist); /* * Fill font cache. */ for (i = 0; i < FONTCACHEMAX; i++) { if (!fonts[i].xfontstruct) break; } if (FONTTYPEMAX <= i) { /* last resort. always cache the font recently used */ i = FONTTYPEMAX - 1; XFreeFont(display, fonts[i].xfontstruct); free(fonts[i].xfont); free(fonts[i].xlfd); } #if 0 if (verbose) { fprintf(stderr, "fill font cache: entry %d <%s>\n", i, fontstring); } #endif fonts[i].csize = csize; fonts[i].registry = registry; fonts[i].xfont = strdup(xfont); fonts[i].xlfd = strdup(fontstring); fonts[i].xfontstruct = xfontstruct; gotfont: if (xfontstruct == NULL) return NULL; XSetFont(display, gcfore, xfontstruct->fid); return xfontstruct; } static u_int draw_onechar_x(state, code, x, y, size, argregistry, lastchar) struct render_state *state; u_int code; int x, y; int size; char *argregistry; int lastchar; { u_int charlen; static XFontStruct *xfontstruct; int coffset; XCharStruct *cs; char *metricsource; char *seed; char *registry; if (code >= 0xa0 && ((!argregistry || !argregistry[0]) && mgp_charset)) registry = mgp_charset; else registry = argregistry; seed = x_findseed(state, registry); xfontstruct = x_setfont(seed, char_size[caching], registry, NULL); if (xfontstruct == NULL) return 0; if (!xfontstruct->per_char) { metricsource = "max_bounds"; coffset = 0; cs = &xfontstruct->max_bounds; } else if (!xfontstruct->min_byte1 && !xfontstruct->max_byte1) { metricsource = "bytewise offset"; coffset = (code & 0xff) - xfontstruct->min_char_or_byte2; cs = &xfontstruct->per_char[coffset]; } else { metricsource = "wordwise offset"; coffset = (code & 0xff) - xfontstruct->min_char_or_byte2; coffset += (((code >> 8) & 0xff) - xfontstruct->min_byte1) * (xfontstruct->max_char_or_byte2 - xfontstruct->min_char_or_byte2); cs = &xfontstruct->per_char[coffset]; } /* * It looks that there are some Japanese X11 fonts with bogus * font metric (cs->width == 0). This is a workaround for that. * (or is there any mistake in above "coffset" computation?) * * TODO: report the X/Open group, or some other guys, about this. */ if (!cs->width) { if (verbose) { fprintf(stderr, "X11 font %s:%d:%s has bogus " "font metric for glyph 0x%04x\n" "\tcs->width=%d, source=%s, coffset=0x%04x\n", seed, char_size, registry?registry:"NULL", code, cs->width, metricsource, coffset); } cs = &xfontstruct->max_bounds; } draw_line_itemsize(state, cs->ascent, cs->descent, 0); /* usually */ charlen = cs->width; /* * for the very first char on the line, the char may goes over the * edge at the lefthand side. offset the image to the right so that * whole part of the bitmap appears on the screen. * beware the sign-ness of cs->lbearing. */ if (x + cs->lbearing < 0) { x -= cs->lbearing; charlen -= cs->lbearing; } /* * For the last char, make sure that the whole part of the bitmap * appears on the screen. */ if (lastchar && cs->width < cs->rbearing) charlen += cs->rbearing - cs->width; obj_new_xfont(state, x, y, size, code, registry); return charlen; } /* * render misc items. */ static void back_gradation(state, cg0) struct render_state *state; struct ctrl_grad *cg0; { struct ctrl_grad cg1; struct ctrl_grad *cg; int srcwidth, srcheight; int dstwidth, dstheight; int dir, numcolor; float xzoomrate, yzoomrate; int hquality, vquality; Image *myimage, *image; Pixmap mypixmap; XImageInfo *ximageinfo; byte *pic; int private = mgp_flag & FL_PRIVATE; static Cursor curs; /* okay, please wait for a while... */ if (!curs) curs = XCreateFontCursor(display, XC_watch); XDefineCursor(display, window, curs); XFlush(display); /* just for safety */ memcpy(&cg1, cg0, sizeof(struct ctrl_grad)); cg = &cg1; /* grab parameters */ dir = cg->ct_direction; numcolor = cg->ct_numcolor; hquality = b_quality[caching]; vquality = b_quality[caching]; /* * XXX zoomflag is too complex to understand. */ if (!cg->ct_zoomflag) { int t; int i; dstwidth = window_width * cg->ct_width / 100; dstheight = window_height * cg->ct_height / 100; srcwidth = dstwidth; srcheight = dstheight; /* * apply quality factor if srcwidth/height are large enough. */ #define TOOSMALLFACTOR 8 t = srcwidth; for (i = 100; hquality < i; i--) { t = srcwidth * i / 100; if (t < cg->ct_g_colors * TOOSMALLFACTOR) break; } srcwidth = t; t = srcheight; for (i = 100; vquality < i; i--) { t = srcheight * i / 100; if (t < cg->ct_g_colors * TOOSMALLFACTOR) break; } srcheight = t; #undef TOOSMALLFACTOR } else { dstwidth = window_width; dstheight = window_height; srcwidth = state->width * cg->ct_width / 100; srcheight = state->height * cg->ct_height / 100; /* * we don't apply quality factor here, since srcwidth/height * is already smaller than dstwidth/height. */ } #if 0 if (srcwidth * hquality / 100 < cg->ct_g_colors * TOOSMALLFACTOR || srcheight * vquality / 100 < cg->ct_g_colors * TOOSMALLFACTOR) { srcwidth = srcwidth * hquality / 100; srcheight = srcheight * vquality / 100; } #endif xzoomrate = 100.0 * dstwidth / srcwidth; yzoomrate = 100.0 * dstheight / srcheight; /* performace enhance hack for special case */ if (dir % 90 == 0) { float *q; int *p, *r; /* * 0 or 180: reduce width * 90 or 270: reduce height */ p = (dir % 180 == 0) ? &srcwidth : &srcheight; q = (dir % 180 == 0) ? &xzoomrate : &yzoomrate; r = (dir % 180 == 0) ? &dstwidth : &dstheight; /* rely upon use X11 background image tiling. */ *q = (float) 100.0; #ifndef DITHERED_BGRAD *p = 1; *r = 1; #else *p = 3; *r = 3; #endif } if (verbose) { fprintf(stderr, "raw: %d,%d qu: %d,%d " "dst: %d,%d src: %d,%d zoom: %0.2f,%0.2f\n", cg->ct_width, cg->ct_height, hquality, vquality, dstwidth, dstheight, srcwidth, srcheight, xzoomrate, yzoomrate); } screen = DefaultScreen(display); /* make gradation image */ pic = draw_gradation(srcwidth, srcheight, cg); myimage = make_XImage(pic, srcwidth, srcheight); if (numcolor < 64) myimage = reduce(myimage, numcolor, verbose); if (verbose) { fprintf(stderr, "background zoomrate: (%0.2f,%0.2f)\n", xzoomrate, yzoomrate); fprintf(stderr, "background zoom mode %d: " "(%d, %d)->(%d, %d)[%d]\n", cg->ct_zoomflag, srcwidth, srcheight, dstwidth, dstheight, b_quality); } if (xzoomrate != 100.0 || yzoomrate != 100.0) { image = myimage; myimage = zoom(image, xzoomrate, yzoomrate, verbose); if (!image) { fprintf(stderr, "image zoom (%0.2fx%0.2f) failed in back_gradataion\n", xzoomrate, yzoomrate); exit(1); } freeImage(image); } #ifndef COLOR_BUGFIX if (private) free_alloc_colors(&back_clr); #endif ximageinfo = imageToXImage(display, screen, visual, depth, myimage, private, 0, 1, verbose); if (!ximageinfo) { fprintf(stderr, "Cannot convert Image to XImage\n"); cleanup(-1); } regist_background_pixmap(ximageinfo, myimage); XUndefineCursor(display, window); XFlush(display); } /* !TODO: move rotation code into some library */ /* rotate image by 90 degrees (counter clockwise) */ static void rotate_image_p90(image) Image *image; { unsigned int row, column, pl = image->pixlen; unsigned int new_height = image->width, new_width = image->height, new_linelen = new_width * pl; byte *src, *tgt, *col_head; Pixel d; /* allocate buffer for new image */ byte *rot_data = lmalloc(new_linelen * new_height); /* do the rotation */ for (row = 0, src = image->data, col_head = rot_data + (new_height - 1) * new_linelen; row < image->height; row++, col_head += pl) { for (column = 0, tgt = col_head; column < image->width; column++, src += pl, tgt -= new_linelen) { d = memToVal(src, pl); valToMem(d, tgt, pl); } } /* swap to rotated image, exchange height and width and point to rotated data */ image->height = new_height; image->width = new_width; lfree(image->data); image->data = rot_data; } /* rotate image by -90 degrees (clockwise) */ static void rotate_image_m90(image) Image *image; { unsigned int row, column, pl = image->pixlen; unsigned int new_height = image->width, new_width = image->height, new_linelen = new_width * pl; byte *src, *tgt; Pixel d; /* allocate buffer for new image */ byte *rot_data = lmalloc(new_linelen * new_height); /* do the rotation */ for (row = 0, src = image->data; row < image->height; row++) { for (column = 0, tgt = rot_data + new_linelen - (row + 1) * pl; column < image->width; column++, src += pl, tgt += new_linelen) { d = memToVal(src, pl); valToMem(d, tgt, pl); } } /* swap to rotated image, exchange height and width and point to rotated data */ image->height = new_height; image->width = new_width; lfree(image->data); image->data = rot_data; return; } /* rotate image by 180 degrees */ static void rotate_image_180(image) Image *image; { unsigned int row, column, pl = image->pixlen; unsigned int new_height = image->height, new_width = image->width, new_linelen = new_width * pl; byte *src, *tgt; Pixel d; /* allocate buffer for new image */ byte *rot_data = lmalloc(new_linelen * new_height); /* do the rotation */ for (row = 0, src = image->data; row < image->height; row++) { for (column = 0, tgt = rot_data + (new_height - row) * new_linelen - pl; column < image->width; column++, src += pl, tgt -= pl) { d = memToVal(src, pl); valToMem(d, tgt, pl); } } /* swap to rotated image, exchange height and width and point to rotated data */ image->height = new_height; image->width = new_width; lfree(image->data); image->data = rot_data; return; } static void image_load(state, filename, numcolor, ximagesize, yimagesize, backflag, zoomflag, centerflag, raise, rotate) struct render_state *state; char *filename; int numcolor; int ximagesize; int yimagesize; int backflag; int zoomflag; int centerflag; int raise; int rotate; { Image *image, *myimage; Pixmap mypixmap; XImageInfo *ximageinfo; u_int image_posx; int width, height, yoffset; float xzoomrate, yzoomrate; int private = mgp_flag & FL_PRIVATE; static Cursor curs; static char backfile[MAXPATHLEN]; static int backzoom, backnumcolor, backx, backy; if (!caching){ if (!curs) curs = XCreateFontCursor(display, XC_watch); XDefineCursor(display, state->target, curs); XFlush(display); } if ((myimage = loadImage(filename, verbose)) == NULL) { fprintf(stderr, "failed to load image file\n"); cleanup(-1); } switch (rotate) { case 0: /* Do nothing */ break; case -90: case 270: rotate_image_m90(myimage); break; case 90: rotate_image_p90(myimage); break; case -180: case 180: rotate_image_180(myimage); break; default: fprintf(stderr, "rotation by %d degrees not supported.\n", rotate); cleanup(-1); } width = myimage->width; height = myimage->height; if (myimage->depth == 1 && myimage->trans < 0) { XColor xc; xc.flags = DoRed | DoGreen | DoBlue; xc.pixel = fore_color[caching]; XQueryColor(display, colormap, &xc); *(myimage->rgb.red + 1) = xc.red; *(myimage->rgb.green + 1) = xc.green; *(myimage->rgb.blue + 1) = xc.blue; myimage->trans = 0; /* call obj_image_trans() later */ } if (numcolor) myimage = reduce(myimage, numcolor, verbose); #if 0 if (zoomflag == 2) { /* * auto resize according to physical and desired screen size. * allow 5% error for '-o' option. */ if (ximagesize == 0 || ximagesize == state->width) ximagesize = 100; else ximagesize = state->width * 100 / ximagesize; if (yimagesize == 0 || yimagesize == state->height) yimagesize = 100; else yimagesize = state->height * 100 / yimagesize; if (ximagesize > 95 && ximagesize < 105 && yimagesize > 95 && yimagesize < 105) ximagesize = yimagesize = 0; } if (ximagesize != 0) { if (!zoomflag) xzoomrate = state->width * ximagesize / width; else xzoomrate = ximagesize; } else xzoomrate = 100.0; if (yimagesize != 0) { if (!zoomflag) yzoomrate = state->height * yimagesize / height; else yzoomrate = yimagesize; } else yzoomrate = 100.0; #else if (!ximagesize) ximagesize = 100; if (!yimagesize) yimagesize = 100; xzoomrate = (float) ximagesize; yzoomrate = (float) yimagesize; image_zoomratio(state, &xzoomrate, &yzoomrate, zoomflag, width, height); #endif if (backflag) { if (xzoomrate != 100 || yzoomrate != 100) { image = myimage; myimage = zoom(image, xzoomrate, yzoomrate, verbose); if (!image) { fprintf(stderr, "image zoom (%dx%d) failed in image_load\n", xzoomrate, yzoomrate); exit(1); } freeImage(image); } #ifndef COLOR_BUGFIX if (private) free_alloc_colors(&back_clr); #endif ximageinfo= imageToXImage(display, screen, visual, depth, myimage, private, 0, 1, verbose); if (ximageinfo == NULL) { fprintf(stderr, "Cannot convert Image to XImage\n"); cleanup(-1); } regist_background_pixmap(ximageinfo, myimage); goto end; } #if 1 /* by h.kakugawa@computer.org */ switch(valign){ case VL_TOP: draw_line_itemsize(state, (height * raise) * yzoomrate / 10000, height * (100 + raise) * yzoomrate / 10000, 0); break; case VL_BOTTOM: draw_line_itemsize(state, height * (100 + raise) * yzoomrate / 10000, (height * raise) * yzoomrate / 10000, 0); break; case VL_CENTER: draw_line_itemsize(state, height * (100 + raise) * yzoomrate / 20000, height * (100 + raise) * yzoomrate / 20000, 0); break; } #else switch(valign){ case VL_TOP: draw_line_itemsize(state, 0, height * yzoomrate / 100, 0); break; case VL_BOTTOM: draw_line_itemsize(state, height * yzoomrate / 100, 0, 0); break; case VL_CENTER: draw_line_itemsize(state, height * yzoomrate / 200, height * yzoomrate / 200, 0); break; } #endif if (centerflag) image_posx = char_size[caching] / 2 - (width * xzoomrate / 100) / 2; else image_posx = 0; obj_new_image(state, state->linewidth + image_posx, - height * yzoomrate / 100 / 2, myimage, xzoomrate, yzoomrate); state->linewidth += (width * xzoomrate / 100); end: if (!caching){ XUndefineCursor(display, state->target); XFlush(display); } } static void image_load_ps(state, filename, numcolor, ximagesize, yimagesize, backflag, zoomflag, centerflag, raise, rotate) struct render_state *state; char *filename; int numcolor; int ximagesize; int yimagesize; int backflag; int zoomflag; int centerflag; int raise; int rotate; { int x1, y1, x2, y2; static Cursor curs; char fullname[MAXPATHLEN]; char *imagefile; int width, height; float xzoom, yzoom; char *p; /* wait for a while, please. */ if (!curs) curs = XCreateFontCursor(display, XC_watch); XDefineCursor(display, window, curs); XFlush(display); if (findImage(filename, fullname) < 0) { fprintf(stderr, "image file %s not found in path\n", filename); cleanup(-1); } if (ps_boundingbox(fullname, &x1, &y1, &x2, &y2) < 0) { /* error message generated in ps_boundingbox() */ cleanup(-1); } width = x2 - x1 + 1; height = y2 - y1 + 1; #if 0 if (zoomflag == 2) { /* screen relative */ if (ximagesize == 0 || ximagesize == state->width) ximagesize = 100; else ximagesize = state->width * 100 / ximagesize; if (yimagesize == 0 || yimagesize == state->height) yimagesize = 100; else yimagesize = state->height * 100 / yimagesize; if (ximagesize > 95 && ximagesize < 105 && yimagesize > 95 && yimagesize < 105) ximagesize = yimagesize = 0; } if (ximagesize != 0) { if (!zoomflag) xzoom = ((float) state->width * ximagesize) / width; else xzoom = (float) ximagesize; width = width * xzoom / 100; } else xzoom = 100.0; if (yimagesize != 0) { if (!zoomflag) yzoom = ((float) state->height * yimagesize) / height; else yzoom = yimagesize; height = height * yzoom / 100; } else yzoom = 100.0; #else xzoom = (float) ximagesize; yzoom = (float) yimagesize; image_zoomratio(state, &xzoom, &yzoom, zoomflag, width, height); width = width * xzoom / 100; height = height * yzoom / 100; #endif imagefile = epstoimage(state, fullname, x1, y1, width, height, xzoom, yzoom); if (imagefile == NULL) { fprintf(stderr, "WARN: cannot generate %s file from %s\n", gsdevice, filename); XUndefineCursor(display, window); XFlush(display); return; } if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "image_load_ps: %s: %s file = %s\n", filename, gsdevice, imagefile); } image_load(state, imagefile, numcolor, 100, 100, backflag, Z_NORMAL | (Z_NORMAL << Z_YSHIFT), centerflag, raise, rotate); /* XXX: unlink imagefile in /tmp */ if ((p = strrchr(imagefile, '/')) != NULL) p++; else p = imagefile; if (strncmp(p, ".gscache", sizeof(".gscache") - 1) != 0) unlink(imagefile); if (!backflag) image_setcolor(state); } void timebar(state) struct render_state *state; { int pos, n, p, barlen; GC pgc; if (t_start == 0 || tbar_mode == 0 || caching) return; pos = (window_width - 2) * (state->page - 1) / (maxpage - 1); p = time(NULL) - t_start; barlen = window_width - window_width * p / t_fin / 60; if (window_width / 2 < barlen) pgc = gcgreen; else if (window_width / 3 < barlen) pgc = gcyellow; else pgc = gcred; if (barlen > 0) { XClearArea(display, state->target, 0, window_height - 2, window_width, 2, 0); XFillRectangle(display, state->target, pgc, window_width - barlen, window_height - 1, barlen, 1); XFillRectangle(display, state->target, pgc, pos, window_height - 5, 2, 5); } else if (barlen < 0) { barlen = - barlen; n = p / t_fin / 60; if (n > window_height - 1) n = window_height - 1; if (n) XFillRectangle(display, state->target, gcred, 0, window_height - n, barlen, n); XClearArea(display, state->target, 0, window_height - (n + 2), window_width, n + 2, 0); XFillRectangle(display, state->target, gcred, 0, window_height - (n + 1), barlen % window_width, n + 1); XFillRectangle(display, state->target, gcred, pos, window_height - (n + 1 + 4), 2, 5); } } static void process_icon(state, cp) struct render_state *state; struct ctrl *cp; { u_int i, icon_type, icon_size, icon_x, icon_y, index; u_long tmp_color; static struct ctl_words icon_words[] = { { 1, 'x', "box", 3 }, { 2, 'x', "arc", 3 }, { 3, 'x', "delta1", 6 }, { 4, 'x', "delta2", 6 }, { 5, 'x', "delta3", 6 }, { 6, 'x', "delta4", 6 }, { 7, 'x', "dia", 3 }, { 0, 'x', NULL, 0 } }; XPoint xpoint[4]; static struct icon_point { int point_num; XPoint xpoint[4]; } icon_point[] = {{ 3, {{1, 0}, {0, 2}, {2, 2}, {0, 0}}}, { 3, {{0, 0}, {2, 0}, {1, 2}, {0, 0}}}, { 3, {{0, 0}, {0, 2}, {2, 1}, {0, 0}}}, { 3, {{2, 0}, {2, 2}, {0, 1}, {0, 0}}}, { 4, {{1, 0}, {0, 1}, {1, 2}, {2, 1}}}}; for (i = 0; icon_words[i].ctl_strlen != 0; i++) { if (!strncasecmp(cp->ctic_value, icon_words[i].ctl_string, strlen(cp->ctic_value))) { break; } } icon_type = icon_words[i].ctl_type; /* may be 0 */ icon_size = char_size[caching] * cp->ctic_size / 100; switch(icon_type){ case 0: /* this is image */ icon_x = icon_size * 100 / state->width; icon_y = icon_size * 100 / state->height; if (icon_x == 0) icon_x = 1; if (icon_y == 0) icon_y = 1; tmp_color = fore_color[caching]; fore_color[caching] = cp->ctic_color; image_load(state, cp->ctic_value, 0, icon_x, icon_y, 0, 0, 1, 0, 0); fore_color[caching] = tmp_color; break; case 1: /* this is box */ obj_new_icon(state, state->linewidth + char_size[caching]/2 - icon_size/2, POSY(icon_size), icon_type, icon_size, cp->ctic_color, 0, NULL); state->linewidth += char_size[caching]; break; case 2: /* this is arc */ obj_new_icon(state, state->linewidth + char_size[caching]/2 - icon_size/2, POSY(icon_size), icon_type, icon_size, cp->ctic_color, 0, NULL); state->linewidth += char_size[caching]; break; case 3: case 4: case 5: case 6: case 7: index = icon_type - 3; icon_x = state->linewidth + (char_size[caching] - icon_size) / 2; #if 0 icon_y = POSY(icon_size); #else icon_y = 0; #endif for (i = 0; i < icon_point[index].point_num; i ++){ xpoint[i].x = icon_x + icon_point[index].xpoint[i].x * icon_size / 2; xpoint[i].y = icon_y + icon_point[index].xpoint[i].y * icon_size / 2; } obj_new_icon(state, 0, 0, icon_type, icon_size, cp->ctic_color, icon_point[index].point_num, xpoint); state->linewidth += char_size[caching]; break; default: break; } cp = NULL; state->brankline = 0; } static void draw_bar(state, cp) struct render_state *state; struct ctrl *cp; { u_int width, swidth, st, len; XColor col, scol; static GC gcbar, gcsbar; static u_long prevcolor = -1; if (!gcbar) { gcbar = XCreateGC(display, state->target, 0, 0); XSetFunction(display, gcbar, GXcopy); gcsbar = XCreateGC(display, state->target, 0, 0); XSetFunction(display, gcsbar, GXcopy); } col.pixel = cp->ctb_color; if (col.pixel == -1) col.pixel = fore_color[caching]; if (col.pixel != prevcolor) { prevcolor = col.pixel; col.flags = DoRed|DoGreen|DoBlue; XQueryColor(display, colormap, &col); scol.red = col.red / 2; scol.green = col.green / 2; scol.blue = col.blue / 2; if (!XAllocColor(display, colormap, &scol)) scol.pixel = col.pixel; XSetForeground(display, gcbar, col.pixel); XSetForeground(display, gcsbar, scol.pixel); } width = cp->ctb_width * state->height / 1000; swidth = width / 2; width -= swidth; st = cp->ctb_start * state->width / 100 + state->xoff; len = cp->ctb_length * state->width / 100; XFillRectangle(display, state->target, gcbar, st, state->ypos + state->yoff, len, width); XFillRectangle(display, state->target, gcsbar, st, state->ypos + state->yoff + width, len, swidth); state->ypos += width + swidth + VERT_GAP(char_size[caching]) / 2; if (state->maxascent < width + swidth) state->maxascent = width + swidth; state->brankline = 0; } static void process_system(state, cp) struct render_state *state; struct ctrl *cp; { pid_t pid; int i; char **argv; char buf[BUFSIZ]; if (state->repaint) { if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "WARN: %%system directive skipping during repaint of same page\n"); } return; /* don't relaunch on repaint */ } if (mgp_flag & FL_NOFORK) { if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "WARN: %%system "); for (i = 0; i < cp->cta_argc; i++) { fprintf(stderr, "%c%s", (i == 0) ? '"' : ' ', cp->cta_argv[i]); } fprintf(stderr, "\": directive skipped\n"); } return; } if (checkchild(cp) != (pid_t)-1) return; /*already running*/ /* * edit argument. * if we have X11 geometry string */ argv = (char **)cp->cta_argv; for (i = 0; i < cp->cta_argc; i++) { if (*(argv[i]) == '%') break; } if (i < cp->cta_argc) { char *p; char *q; int myxpos, myypos; int rootxsiz, rootysiz; int xsiz, ysiz; int xloc, yloc; int mode; { XWindowAttributes wa; Window junkwin; int junk; XGetWindowAttributes(display, window, &wa); XTranslateCoordinates(display, window, wa.root, -wa.border_width, -wa.border_width, &myxpos, &myypos, &junkwin); XGetGeometry(display, wa.root, &junkwin, &junk, &junk, &rootxsiz, &rootysiz, &junk, &junk); } argv = (char **)malloc((cp->cta_argc + 1) * sizeof(char *)); memcpy(argv, cp->cta_argv, (cp->cta_argc + 1) * sizeof(char *)); p = argv[i]; p++; /*drop percent char*/ q = buf; *q = '\0'; mode = XParseGeometry(p, &xloc, &yloc, &xsiz, &ysiz); if (mode == 0) goto fail; if ((mode & WidthValue) && (mode & HeightValue)) { sprintf(q, "%dx%d", xsiz * state->width / 100, ysiz * state->height / 100); q += strlen(q); } if ((mode & XValue) && (mode & YValue)) { xloc = xloc * state->width / 100; yloc = yloc * state->height / 100; if (mode & XNegative) xloc = rootxsiz - myxpos + state->width - xloc; else xloc += myxpos; if (mode & YNegative) yloc = rootysiz - myypos + state->height - yloc; else yloc += myypos; sprintf(q, "+%d+%d", xloc + state->xoff, yloc + state->yoff); } if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "relative geometry: " "%s (presentation %dx%d+%d+%d)\n", argv[i], state->width, state->height, myxpos, myypos); fprintf(stderr, "\t-> %s\n", buf); } argv[i] = buf; if (0) { fail: if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "relative geometry: %s failed\n", argv[i]); } } } pid = fork(); if (pid < 0) { perror("fork"); cleanup(-1); } else if (pid == 0) { execvp(argv[0], argv); perror(argv[0]); _exit(1); } if (!cp->cta_flag) /*will be purged at the end of page*/ regchild(pid, cp, -1, state->page); else regchild(pid, cp, -1, cp->cta_flag); } static void process_xsystem(state, cp) struct render_state *state; struct ctrl *cp; { pid_t pid; int i, dumint; int xloc, yloc; int xsiz, ysiz; char **argv; char buf[BUFSIZ]; Window window_id, dumwin; if (state->repaint) { if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "WARN: %%system directive skipping during repaint of same page\n"); } return; /* don't relaunch on repaint */ } if (mgp_flag & FL_NOFORK) { if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "WARN: %%system "); for (i = 0; i < cp->cta_argc; i++) { fprintf(stderr, "%c%s", (i == 0) ? '"' : ' ', cp->cta_argv[i]); } fprintf(stderr, "\": directive skipped\n"); } return; } /* * edit argument. * if we have X11 geometry string */ argv = (char **)cp->cta_argv; for (i = 0; i < cp->cta_argc; i++) { if (!strncmp(argv[i], "-geom", 5)) break; } i ++; if (i < cp->cta_argc) { char *p; char *q; int mode; argv = (char **)malloc((cp->cta_argc + 1) * sizeof(char *)); /* XXX seems to be never freed */ memcpy(argv, cp->cta_argv, (cp->cta_argc + 1) * sizeof(char *)); p = argv[i]; if (*p == '%') p++; /*drop percent char*/ q = buf; *q = '\0'; mode = XParseGeometry(p, &xloc, &yloc, &xsiz, &ysiz); if (mode == 0) goto fail; if ((mode & WidthValue) && (mode & HeightValue)) { xsiz = xsiz * state->width / 100; ysiz = ysiz * state->height / 100; sprintf(q, "%dx%d", xsiz, ysiz); q += strlen(q); } /* make window raise outside of display */ sprintf(q, "+%d+%d", DisplayWidth(display, DefaultScreen(display)), DisplayHeight(display, DefaultScreen(display))); if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "relative geometry: " "%s (presentation %dx%d+%d+%d)\n", argv[i], state->width, state->height, xloc, yloc); fprintf(stderr, "\t-> %s\n", buf); } argv[i] = buf; if (0) { fail: if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "relative geometry: %s failed\n", argv[i]); } } } else { char geom_arg1[] = {"-geometry"}; char geom_arg2[512]; sprintf(geom_arg2, "+%d+%d", DisplayWidth(display, DefaultScreen(display)), DisplayHeight(display, DefaultScreen(display))); argv[cp->cta_argc] = geom_arg1; argv[cp->cta_argc+1] = geom_arg2; /* ** XXX argv is now not generally NULL-terminated ** the maximal allowed size of argv is ganatied to be ** argc+2 so no NULL can appended */ } if ((window_id = checkchildwin(cp)) != (Window)-1) goto finish; /*already running*/ if (checkchild(cp) != (pid_t)-1) return; /*already running*/ pid = fork(); if (pid < 0) { perror("fork"); cleanup(-1); } else if (pid == 0){ usleep(EXEC_DELAY); execvp(argv[0], argv); perror(argv[0]); _exit(1); } window_id = search_child_window(); if (!cp->cta_flag) /*will be purged at the end of page*/ regchild(pid, cp, window_id, state->page); else regchild(pid, cp, window_id, cp->cta_flag); if (window_id != -1) reparent_child_window(window_id, window_width, window_height); else { if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "WARN: %%xsystem cannot find child window:"); for (i = 0; i < cp->cta_argc; i++) { fprintf(stderr, "%c%s", (i == 0) ? '"' : ' ', cp->cta_argv[i]); } fprintf(stderr, "\"\n"); } return; } finish: XGetGeometry(display, window_id, &dumwin, &xloc, &yloc, &xsiz, &ysiz, &dumint, &dumint); state->linewidth = xsiz; xloc = set_position(state) + state->xoff + (state->tabxprefix ? state->tabxprefix : state->xprefix); yloc = state->ypos + state->yoff; XMoveWindow(display, window_id, xloc, yloc); state->ypos += ysiz; #if 0 /* not implemented yet */ state->linewidth += xsiz; state->maxascent += ysiz; #endif } /* * tsystem does mostly the same like xsystem, but identifies the created * window by its name * * this hack is done because at some windowmanagers occures additional * xreparentevents, which cause xsystem to fail * * it is possible, that the title of some applications is reseted, than * tsystem will fail */ static void process_tsystem(state, cp) struct render_state *state; struct ctrl *cp; { pid_t pid; int i, dumint, argc; int xloc, yloc; int xsiz, ysiz; char **argv; char buf[BUFSIZ]; char title_arg1[] = "-title"; char title_arg2[BUFSIZ]; static unsigned int magicCnt=0; Window window_id, dumwin; if (mgp_flag & FL_NOFORK) { if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "WARN: %%system "); for (i = 0; i < cp->cta_argc; i++) { fprintf(stderr, "%c%s", (i == 0) ? '"' : ' ', cp->cta_argv[i]); } fprintf(stderr, "\": directive skipped\n"); } return; } /* * edit argument. * allways copy the argument vector, for adding -title magictitle * it's assumed, that there is not -title in the argument vector */ argc=cp->cta_argc; argv = (char **)malloc((argc + 5) * sizeof(char *)); /* +5 for NULL, title and potentally geometry */ memcpy(argv, cp->cta_argv, (argc + 1) * sizeof(char *)); /* * search for X11 geometry string */ for (i = 0; i < argc; i++) { if (!strncmp(argv[i], "-geom", 5)) break; } i ++; if (i < argc) { /* * we have X11 geometry string */ char *p; char *q; int mode; p = argv[i]; if (*p == '%') p++; /*drop percent char*/ q = buf; *q = '\0'; mode = XParseGeometry(p, &xloc, &yloc, &xsiz, &ysiz); if (mode == 0) goto fail; if ((mode & WidthValue) && (mode & HeightValue)) { xsiz = xsiz * state->width / 100; ysiz = ysiz * state->height / 100; sprintf(q, "%dx%d", xsiz, ysiz); q += strlen(q); } /* make window raise outside of display */ /* XXX potentially overflow, but BUFSIZ should be alway large enough*/ sprintf(q, "+%d+%d", DisplayWidth(display, DefaultScreen(display)), DisplayHeight(display, DefaultScreen(display))); if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "relative geometry: " "%s (presentation %dx%d+%d+%d)\n", argv[i], state->width, state->height, xloc, yloc); fprintf(stderr, "\t-> %s\n", buf); } argv[i] = buf; if (0) { fail: if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "relative geometry: %s failed\n", argv[i]); } } } else { /* * we do not have X11 geometry string */ char geom_arg1[] = "-geometry"; char geom_arg2[512]; sprintf(geom_arg2, "+%d+%d", DisplayWidth(display, DefaultScreen(display)), DisplayHeight(display, DefaultScreen(display))); argv[argc] = geom_arg1; argv[argc+1] = geom_arg2; argc += 2; } /* * adding magic title and incrementing magicCnt * guaranteeing the NULL-termination of argv */ snprintf(title_arg2, BUFSIZ, "magictitle %u", magicCnt++); argv[argc] = title_arg1; argv[argc+1] = title_arg2; argv[argc+2] = NULL; argc += 2; /* seems not to be nessesary */ if ((window_id = checkchildwin(cp)) != (Window)-1) goto finish; /*already running*/ if (checkchild(cp) != (pid_t)-1) { free(argv); return; /*already running*/ } /* * using vfork() to first run the child */ pid = vfork(); if (pid < 0) { perror("fork"); cleanup(-1); } else if (pid == 0){ execvp(argv[0], argv); perror(argv[0]); _exit(1); } window_id = tsearch_child_window(title_arg2); if (!cp->cta_flag) /*will be purged at the end of page*/ regchild(pid, cp, window_id, state->page); else regchild(pid, cp, window_id, cp->cta_flag); if (0 == window_id) { if (mgp_flag & FL_VERBOSE) { fprintf(stderr, "WARN: %%tsystem can not find child window:"); for (i = 0; i < cp->cta_argc; i++) { fprintf(stderr, "%c%s", (i == 0) ? '"' : ' ', cp->cta_argv[i]); } fprintf(stderr, "\"\n"); } return; } finish: { Window root, par, *child; int newxloc, newyloc; unsigned int nchild; XGetGeometry(display, window_id, &dumwin, &xloc, &yloc, &xsiz, &ysiz, &dumint, &dumint); XQueryTree(display, window_id, &root, &par, &child, &nchild); if(child) XFree(child); state->linewidth = xsiz; newxloc = set_position(state) + state->xoff + (state->tabxprefix ? state->tabxprefix : state->xprefix); newyloc = state->ypos + state->yoff; while((par!=window) || (xloc != newxloc)) { /* * this hack should correct not moved windows * if found, that XMoveWindow, XReparentWindow returns success, * but the window is sometimes not moved etc in ion */ XReparentWindow(display, window_id, window, newxloc, newyloc); XGetGeometry(display, window_id, &dumwin, &xloc, &yloc, &xsiz, &ysiz, &dumint, &dumint); XQueryTree(display, window_id, &root, &par, &child, &nchild); if(child) XFree(child); } } state->ypos += ysiz; free(argv); #if 0 /* not implemented yet */ state->linewidth += xsiz; state->maxascent += ysiz; #endif } Window search_child_window() { XEvent e; int fd, found = 0; fd_set fdset, dumfdset; struct timeval timeout; fd = ConnectionNumber(display); /* waiting for 2 second */ timeout.tv_sec = 2; timeout.tv_usec = 0; /* get all client's ReparentNotify event */ XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask); while (!found) { while (XEventsQueued(display, QueuedAfterFlush) > 0) { XNextEvent(display, &e); if (e.type == ReparentNotify){ found = 1; break; } } if (found) break; FD_ZERO(&fdset); FD_SET(fd, &fdset); FD_ZERO(&dumfdset); if (!select(fd+1, &fdset, &dumfdset, &dumfdset, &timeout)) break; } XSelectInput(display, DefaultRootWindow(display), NoEventMask); if (found == 1) return e.xreparent.window; else return (Window)-1; } /* ** looks for a window with the specified name ** return (Window)0 if not found */ Window tsearch_child_window(const char *name) { /* 100 ms between two searches for the specified window */ #define WAITTIME 100000 /* maximal wait time = 1 minute */ #define WAITCYCLES 60000000 / WAITTIME int maxWait=WAITCYCLES; Window w=0; while(maxWait--) { if((w = getNamedWindow(name, DefaultRootWindow(display)))) break; usleep(WAITTIME); } return w; #undef WAITCYCLES #undef WAITTIME } Window getNamedWindow(const char *name, Window top) { Window w=0; Window *child; Window dum; unsigned int nchild,i; char *w_name; if(XFetchName(display, top, &w_name) && (!strcmp(w_name, name))) return top; if(!XQueryTree(display, top, &dum, &dum, &child, &nchild)) return (Window)0; for(i=0; i 0) { if (verbose) { fprintf(stderr, "gs cache valid, " "using it \n"); } return imagefile; } } if (verbose) { fprintf(stderr, "gs cache looks older than source, " "generate again\n"); } } else { if (verbose) { fprintf(stderr, "gs cache not found, convert eps\n"); } } if (verbose) fprintf(stderr, "converting eps file...\n"); /* convert eps file into readable form. */ sprintf(device, "-sDEVICE=%s", gsdevice); /* * a suffix of +scale in the device tipe means produce a larger * image that can be scaled later for better antialiasing. */ if ((cp = strchr(device, '+')) != NULL) { *cp++ = '\0'; scale = atoi(cp); if (scale <= 0) scale = 2; xzoom *= scale; yzoom *= scale; width *= scale; height *= scale; } if (width == 0 || height == 0) { fprintf(stderr, "WARN: epstoimage: scale=%d, xzoom=%d, " "yzoom=%d, width=%d, height=%d\n", scale, xzoom, yzoom, width, height); return NULL; } if (scale != 1) sprintf(scalebuf, "%f", 1. / (double)scale); sprintf(geom, "-g%dx%d", width, height); /* generate cache file. */ fd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC, 0600); if (fd < 0) { /* last resort: generate output onto /tmp. */ if ((cp = getenv("TMPDIR")) == NULL) cp = "/tmp"; if (verbose) { fprintf(stderr, "could not write to \"%s\", using " "%s\n", imagefile, cp); } strcpy(imagefile, cp); strcat(imagefile, "/mgp.XXXXXXXX"); if ((fd = mkstemp(imagefile)) < 0) { perror(imagefile); return NULL; } } if (scale != 1) { if (pipe(pfd[2]) < 0) { perror("pipe"); goto error; } if ((pid = vfork()) == 0) { close(pfd[2][1]); dup2(pfd[2][0], 0); close(pfd[2][0]); dup2(fd, 1); close(fd); if (verbose) fprintf(stderr, "epstoimage: \"pnmdepth 256\"\n"); close(2); /* XXX suppress message */ execlp("pnmdepth", "pnmdepth", "255", NULL); perror("pnmdepth"); _exit(1); } if (pid < 0) { perror("vfork"); goto error; } close(pfd[2][0]); pfd[2][0] = -1; close(fd); fd = -1; if (pipe(pfd[1]) < 0) { perror("pipe"); goto error; } if ((gspid = vfork()) == 0) { close(pfd[1][1]); dup2(pfd[1][0], 0); close(pfd[1][0]); dup2(pfd[2][1], 1); close(pfd[2][1]); if (verbose) fprintf(stderr, "epstoimage: \"pnmscale %s\"\n", scalebuf); close(2); /* XXX suppress message */ execlp("pnmscale", "pnmscale", scalebuf, NULL); perror("pnmscale"); _exit(1); } if (gspid < 0) { perror("vfork"); goto error; } close(pfd[2][1]); pfd[2][1] = -1; close(pfd[1][0]); pfd[1][0] = -1; fd = pfd[1][1]; pfd[1][1] = -1; } if (pipe(pfd[0]) < 0) { perror("pipe"); goto error; } if ((gspid = vfork()) == 0) { close(pfd[0][1]); dup2(pfd[0][0], 0); close(pfd[0][0]); dup2(fd, 1); close(fd); if (verbose) fprintf(stderr, "epstoimage: \"gs %s %s -sOutputFile=- -q -\"\n", geom, device); execlp("gs", "gs", geom, device, "-sOutputFile=-", "-q", "-", NULL); perror("gs"); _exit(1); } close(fd); fd = -1; close(pfd[0][0]); pfd[0][0] = -1; if ((fp = fdopen(pfd[0][1], "w")) == NULL) { fprintf(stderr, "fdopen failed\n"); goto error; } sigpipe_handler = signal(SIGPIPE, SIG_IGN); /* XXX: avoid SIGPIPE */ pfd[0][1] = -1; fprintf(fp, "%f %f scale\n", (double)xzoom/100., (double)yzoom/100.); fprintf(fp, "%d %d translate\n", -1 * x, -1 * y); fprintf(fp, "(%s) run\n", epsfile); fprintf(fp, "showpage\n"); fprintf(fp, "quit\n"); fflush(fp); fclose(fp); signal(SIGPIPE, sigpipe_handler); if (!pid) pid = gspid; while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) break; } if (stat(imagefile, &stbuf) == 0 && stbuf.st_size > 0) return imagefile; error: if (fd >= 0) close(fd); for (i = 0; i < 3; i++) { for (j = 0; j < 2; j++) if (pfd[i][j] >= 0) close(pfd[i][j]); } if (imagefile[0]) unlink(imagefile); return NULL; } static void image_setcolor(state) struct render_state *state; { struct render_object *obj; Image *image; int i; Intensity *red, *green, *blue; XColor fore, back; obj = state->objlast; if (obj->type != O_IMAGE) return; image = obj->data.image.image; if (image->trans >= 0) return; switch (image->type) { case IBITMAP: /* * XXX: Actually, no one comes here. * This translation for IBITMAP was done by image_load(). */ fore.pixel = fore_color[caching]; fore.flags = DoRed | DoGreen | DoBlue; XQueryColor(display, colormap, &fore); image->rgb.red [1] = fore.red; image->rgb.green[1] = fore.green; image->rgb.blue [1] = fore.blue; image->trans = 0; break; case IRGB: red = image->rgb.red; green = image->rgb.green; blue = image->rgb.blue; for (i = 0; i < image->rgb.used; i++) { if (red[i] != green[i] || red[i] != blue[i]) return; } /* grayscale */ fore.pixel = fore_color[caching]; fore.flags = DoRed | DoGreen | DoBlue; XQueryColor(display, colormap, &fore); if (!COMPLEX_BGIMAGE) { back.pixel = back_color[caching]; back.flags = DoRed | DoGreen | DoBlue; XQueryColor(display, colormap, &back); } else { int x, y, bpl; byte *p; Pixel d; /* XXX: use background color of center position */ x = (obj->x + image->width/2) % bgpixmap[bgindex].image->width; y = (state->ypos + image->height/2) % bgpixmap[bgindex].image->height; bpl = bgpixmap[bgindex].image->pixlen; p = bgpixmap[bgindex].image->data + (bgpixmap[bgindex].image->width * y + x) * bpl; d = memToVal(p, bpl); if (bgpixmap[bgindex].image->type == ITRUE) { back.red = TRUE_RED(d) << 8; back.green = TRUE_GREEN(d) << 8; back.blue = TRUE_BLUE(d) << 8; } else { back.red = bgpixmap[bgindex].image->rgb.red [d]; back.green = bgpixmap[bgindex].image->rgb.green[d]; back.blue = bgpixmap[bgindex].image->rgb.blue [d]; } } for (i = 0; i < image->rgb.used; i++) { if (red[i] >= 65000) /*XXX*/ image->trans = i; red[i] = (back.red * red [i] + fore.red * (65535-red [i])) / 65535; green[i] = (back.green * green[i] + fore.green * (65535-green[i])) / 65535; blue[i] = (back.blue * blue [i] + fore.blue * (65535-blue [i])) / 65535; } break; case ITRUE: /* XXX: assume background color is on the left right corner */ image->trans = memToVal(image->data, image->pixlen); } } #ifdef FREETYPE static u_int draw_onechar_tf(state, code, x, y, size, registry, lastchar, charset16) struct render_state *state; u_int code; int x, y; u_int size; char *registry; int lastchar; int charset16; { struct tfont *tfc; int charlen; tfc = tfc_get(code, size, 1, registry, charset16); draw_line_itemsize(state, tfc->ascent, tfc->descent, 0); /* usually */ charlen = tfc->charlen; /* * for the very first char on the line, the char may goes over the * edge at the lefthand side. offset the image to the right so that * whole part of the bitmap appears on the screen. * beware the sign-ness of tfc->xoff. */ if (x + tfc->xoff < 0) { x -= tfc->xoff; charlen -= tfc->xoff; } /* * For the last char, make sure that the whole part of the bitmap * appears on the screen. */ if (lastchar && tfc->charlen < tfc->xoff + tfc->width) charlen += tfc->xoff + tfc->width - tfc->charlen; /* * (x, y): left side, baseline of the font (FreeType font origin) */ obj_new_tfont(state, x, y, tfc); return charlen; } #endif /* FREETYPE */ static void x_registerseed(state, seed, registry) struct render_state *state; char *seed; char *registry; { char tmp1[BUFSIZ], tmp2[BUFSIZ]; char *p; struct ctrl *cp; int hyphen; /* if both of arguments are NULL, initialize */ if (!seed && !registry) { if (state->xfont) ctlfree(state->xfont); state->xfont = NULL; return; } if (!registry) registry = "iso8859-1"; /* canonicalize seed */ hyphen = 0; for (p = seed; *p; p++) { if (*p == '-') hyphen++; if (*p == ':') { hyphen = 0; break; } } switch (hyphen) { case 0: /* maybe alias, don't canonicalize */ break; case 1: sprintf(tmp1, "%s-*", seed); seed = tmp1; break; case 2: case XLFD_HYPHEN: /* as is */ break; default: fprintf(stderr, "invalid XFONT seed <%s>\n", seed); break; } /* canonicalize registry */ if (!registry) registry = "iso8859-1"; hyphen = 0; for (p = registry; *p; p++) { if (*p == '-') hyphen++; } switch (hyphen) { case 0: sprintf(tmp2, "%s-*", registry); registry = tmp2; break; case 1: /* as is */ break; default: fprintf(stderr, "invalid XFONT registry <%s>\n", registry); exit(1); } cp = NULL; for (cp = state->xfont; cp; cp = cp->ct_next) { if (!cp->ctc2_value2) continue; if (strcmp(cp->ctc2_value2, registry) == 0) break; } if (cp) { if (!strcmp(cp->ctc2_value1, seed)) return; free(cp->ctc2_value1); cp->ctc2_value1 = strdup(seed); } else { cp = ctlalloc1(CTL_XFONT2); cp->ctc2_value1 = strdup(seed); cp->ctc2_value2 = strdup(registry); cp->ct_next = state->xfont; state->xfont = cp; } } static char * x_findseed(state, registry) struct render_state *state; char *registry; { struct ctrl *cp; if (!registry) registry = "iso8859-1"; for (cp = state->xfont; cp; cp = cp->ct_next) { if (strcmp(cp->ctc2_value2, registry) == 0) { return cp->ctc2_value1; } } return "*-*-*"; /*anything, canonicalized*/ } /* cache specified page */ static void cache_page(state, page) struct render_state *state; int page; { struct ctrl *tmp_bg_ctl; int tmp_bgindex; /* we don't need caching */ if (cached_page == page || page > maxpage || page <= 0) return; if (!page_attribute[page].pg_linenum) return; XFlush(display); memset(state, 0, sizeof(struct render_state)); state->target = cachewin; /*XXX*/ state->width = window_width; state->height = window_height; state->page = page; caching = 1; tmp_bg_ctl = bg_ctl; tmp_bgindex = bgindex; if (verbose){ printf("now caching %d page ...\n", page); fflush(stdout); } draw_page(state, NULL); if (verbose){ printf("caching done \n"); } caching = 0; cached_page = page; bg_ctl = tmp_bg_ctl; bgindex = tmp_bgindex; } static void set_from_cache(state) struct render_state *state; { int i; char_size[0] = char_size[1]; horiz_gap[0] = horiz_gap[1]; vert_gap[0] = vert_gap[1]; fore_color[0] = fore_color[1]; back_color[0] = back_color[1]; ctrl_color[0] = ctrl_color[1]; b_quality[0] = b_quality[1]; memcpy(state, &cache_state, sizeof(struct render_state)); state->target = window; XSetForeground(display, gcfore, fore_color[0]); XSetBackground(display, gcfore, back_color[0]); bg_ctl = bg_ctl_last = bg_ctl_cache; if (bg_ctl){ for (i = 0; i < MAXBGPIXMAP; i ++){ if (bgpixmap[i].ctl && ctlcmp(bg_ctl, bgpixmap[i].ctl) == 0) bgindex = i; } set_background_pixmap(bg_ctl); } switch(cache_effect){ case 1: cache_effect1(); break; case 2: cache_effect2(); break; default: break; } XCopyArea(display, cachewin, window, gc_cache, 0, 0, window_width, window_height, 0, 0); XFlush(display); } void reset_background_pixmap() { int i = 0; bg_ctl_last = NULL; bg_ctl_cache = NULL; for (i = 0; i < MAXBGPIXMAP; i ++) { if (bgpixmap[i].image){ XFreePixmap(display, bgpixmap[i].pixmap); freeXImage(bgpixmap[i].image, bgpixmap[i].ximageinfo); freeImage(bgpixmap[i].image); } bgpixmap[i].ctl = NULL; bgpixmap[i].image = NULL; bgpixmap[i].ximageinfo = NULL; } } static void cache_effect1() { int x, step; step = cache_value ? window_width / cache_value : 1; if (!step) step = 1; for (x = window_width; x > step; x -= step){ XCopyArea(display, window, window, gc_cache, step, 0, window_width - step, window_height, 0, 0); XCopyArea(display, cachewin, window, gc_cache, window_width - x, 0, step, window_height, window_width - step, 0); #if 1 XSync(display, False); #else XFlush(display); #endif #if 1/*ONOE*/ { XEvent e; if (XCheckMaskEvent(display, ~NoEventMask, &e) == True) { printf("event type=%d\n", e.type); XPutBackEvent(display, &e); break; } } #endif } } static void cache_effect2() { int x, step; step = cache_value ? window_width / (cache_value * 2) : 1; if (!step) step = 1; for (x = 0; x < window_width; x += step){ XCopyArea(display, window, window, gc_cache, x, 0, window_width - step -x , window_height, x + step, 0); XCopyArea(display, cachewin, window, gc_cache, x, 0, step, window_height, x, 0); XFlush(display); } } /* pcache directive process */ static void pcache_process(page) int page; { if (!pcache.flag) return; if (pcache.page != page) return; if (pcache.mgpflag) mgp_flag |= FL_FRDCACHE; else mgp_flag ^= FL_FRDCACHE; cache_mode = pcache.mode; cache_effect = pcache.effect; cache_value = pcache.value; pcache.flag = 0; } /* predraw: if this page contains texts only, draw page in pixmap once, then copy to window. */ static void predraw(state) struct render_state *state; { if (!caching && cached_page != state->page && page_attribute[state->page].pg_text && page_attribute[state->page].pg_linenum){ cache_page(&cache_state, state->page); set_from_cache(state); pcache_process(state->page); } } static void get_background_pixmap(ctl, state) struct ctrl *ctl; struct render_state *state; { int i; /* * check if background is already cached */ for (i = 0; i < MAXBGPIXMAP; i ++){ if (bgpixmap[i].ctl && ctlcmp(ctl, bgpixmap[i].ctl) == 0){ bgindex = i; return; } } if (i == MAXBGPIXMAP){ /* this background is not cached, we have to generate one */ switch(ctl->ct_op){ case CTL_BIMAGE: image_load(state, ctl->ctm_fname, ctl->ctm_numcolor, ctl->ctm_ximagesize, ctl->ctm_yimagesize, 1, ctl->ctm_zoomflag, 0, 0, ctl->ctm_rotate); break; case CTL_BGRAD: back_gradation(state, &ctl->ct_val.ctrl_grad); break; case CTL_BACK: break; default: fprintf(stderr, "fatal error in get_background_pixmap()\n"); cleanup(-1); break; } } } static void regist_background_pixmap(ximageinfo, image) XImageInfo *ximageinfo; Image *image; { Pixmap pixmap; int i, j; /* search empty slot */ for (i = 0; i < MAXBGPIXMAP; i ++){ if (bgpixmap[i].ctl == NULL) break; } if (i == MAXBGPIXMAP){ /* no empty slot, we need to make one */ XFreePixmap(display, bgpixmap[MAXBGPIXMAP -1].pixmap); freeXImage(bgpixmap[MAXBGPIXMAP -1].image, bgpixmap[MAXBGPIXMAP -1].ximageinfo); freeImage(bgpixmap[MAXBGPIXMAP -1].image); for (j = MAXBGPIXMAP -2; j >= 0; j --){ bgpixmap[j +1].ctl = bgpixmap[j].ctl; bgpixmap[j +1].pixmap = bgpixmap[j].pixmap; bgpixmap[j +1].image = bgpixmap[j].image; bgpixmap[j +1].ximageinfo = bgpixmap[j].ximageinfo; } bg_ctl_last = NULL; i = 0; } pixmap = ximageToPixmap(display, RootWindow(display, screen), ximageinfo); bgpixmap[i].ctl = bg_ctl; bgpixmap[i].pixmap = pixmap; bgpixmap[i].image = image; bgpixmap[i].ximageinfo = ximageinfo; bgindex = i; } static void set_background_pixmap(ctl) struct ctrl *ctl; { int i; switch(ctl->ct_op){ case CTL_BIMAGE: case CTL_BGRAD: for (i = 0; i < MAXBGPIXMAP; i ++){ if (bgpixmap[i].ctl && ctlcmp(ctl, bgpixmap[i].ctl) == 0) break; } if (i == MAXBGPIXMAP){ fprintf(stderr, "fatal error in set_background_pixmap()\n"); cleanup(-1); } XSetWindowBackgroundPixmap(display, window, bgpixmap[i].pixmap); break; case CTL_BACK: XSetWindowBackground(display, window, ctl->ctl_value); break; default: fprintf(stderr, "fatal error in set_background_pixmap() op=%d\n", ctl->ct_op); cleanup(-1); break; } } /* * Clear target pixmap */ static void XClearPixmap(display, target) Display *display; Drawable target; { int i; int x, y, width, height; XImage *xim; switch(bg_ctl->ct_op){ case CTL_BIMAGE: case CTL_BGRAD: for (i = 0; i < MAXBGPIXMAP; i ++){ if (bgpixmap[i].ctl && ctlcmp(bg_ctl, bgpixmap[i].ctl) == 0) break; } if (i == MAXBGPIXMAP){ fprintf(stderr, "fatal error in XClearPixmap()\n"); cleanup(-1); } xim = bgpixmap[i].ximageinfo->ximage; for (y = 0; y < window_height; y += xim->height) for (x = 0; x < window_width; x += xim->width) XPutImage(display, target, gc_cache, xim, 0, 0, x, y, xim->width, xim->height); break; case CTL_BACK: XSetForeground(display, gc_cache, bg_ctl->ctl_value); XFillRectangle(display, target, gc_cache, 0, 0, window_width, window_height); break; default: fprintf(stderr, "fatal error in XClearPixmap()\n"); cleanup(-1); break; } } int get_regid(registry) char *registry; { char *p; if (!registry || registry[0] == '\0') return 0; if (strlen(registry) == 9 && !strncmp("iso8859-", registry, 8) && registry[8] >= '1' && registry[8] <= '4') { p = registry + 8; return atoi(p) -1; } else return -1; } #ifdef MNG int obj_new_anim(state, x, y, width, height, filename, key) struct render_state *state; int x, y; int width, height; char *filename; void *key; { struct render_object *obj; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->type = O_ANIM; obj->data.anim.width = width; obj->data.anim.height = height; obj->data.anim.filename = strdup(filename); obj->data.anim.key = key; /* for regchild */ obj->ascent = 0; /*XXX*/ obj->descent = height; /*XXX*/ obj->vertloc = VL_CENTER; return 1; } static void obj_draw_anim(state, x, y, obj) struct render_state *state; u_int x, y; struct render_object *obj; { pid_t pid; if (!(pid = fork())){ mngload(obj->data.anim.filename, x, y, obj->data.anim.width, obj->data.anim.height); while(1) sleep(1); } regchild(pid, obj->data.anim.key, -1, state->page); } static void process_anim(state, cp) struct render_state *state; struct ctrl *cp; { int width, height; width = 200; height = 100; /* * we support only mng so far */ mngpreload(state, cp->ctc_value, &width, &height); obj_new_anim(state, state->linewidth, - height, width, height, cp->ctc_value, cp); switch(valign){ case VL_TOP: draw_line_itemsize(state, 0, height, 0); break; case VL_BOTTOM: draw_line_itemsize(state, height, 0, 0); break; case VL_CENTER: draw_line_itemsize(state, height /2 , height /2, 0); break; } state->linewidth += width; state->brankline = 0; } #endif #ifdef USE_XFT2 void set_xrender_color(value, opaque) long value; int opaque; { XColor xc; XRenderColor render_color; xft_forecolor.color.alpha = 65535 * opaque / 100; if (value == xft_forecolor.pixel) return; xc.flags = DoRed | DoGreen | DoBlue; xc.pixel = value; XQueryColor(display, colormap, &xc); xft_forecolor.pixel = value; xft_forecolor.color.red = xc.red; xft_forecolor.color.green = xc.green; xft_forecolor.color.blue = xc.blue; } static char * xft_draw_fragment(state, p, len, registry, charset16) struct render_state *state; u_char *p; u_int len; char *registry; int charset16; /*2-octet charset?*/ { XGlyphInfo extents; struct ctrl *cp; char *fontname = NULL; int i; static char etab[3][20] = { "iso-2022-jp", "gb2312", "ksc5601"}; static char rtab[3][20] = { "jisx208", "gb2312", "ksc5601"}; static char prefix[3][20] = { "\033$B", "\033$A", "\033$(C"}; char buf16[1024], *p16; char out16[1024], *o16; int ileft, oleft; #ifdef HAVE_ICONV static iconv_t icv[3]; #endif for (i = 0; i < len; i ++){ if (!isspace(*(p + i))) state->brankline = 0; /* This isn't brankline */ } if (!registry) registry = "iso8859-1"; for (cp = state->xfont; cp; cp = cp->ct_next) { if (!cp->ctc2_value2) continue; if (strcmp(cp->ctc2_value2, registry) == 0) { fontname = cp->ctc2_value1; break; } } if (!fontname) return NULL; if (!(xft_font = xft_setfont(fontname, char_size[caching], registry))) return NULL; if (charset16) { #ifdef HAVE_ICONV for (i = 0; i < 3; i ++) { if (!strncmp(registry, rtab[i], 3)) break; } if (i == 3) return NULL; /* cannot find codeset */ sprintf(buf16, "%s%s\0", prefix[i], p); if (icv[i] == (iconv_t)0) icv[i] = iconv_open("UTF-8", etab[i]); if (icv[i] == (iconv_t)-1) { fprintf(stderr, "your iconv doesn't support %s\n", etab[i]); return NULL; } p16 = buf16; o16 = out16; ileft = len + strlen(prefix[i]); oleft = sizeof(out16); if (iconv(icv[i], &p16, &ileft, &o16, &oleft) < 0) { perror("iconv"); return NULL; } /* measure drawing are */ XftTextExtentsUtf8(display, xft_font, (XftChar8 *)out16, sizeof(out16) - oleft, &extents); /* line folding check */ if (state->width - state->leftfillpos / 2 - state->linewidth < extents.xOff) { draw_line_end(state); draw_line_start(state); state->linewidth = state->leftfillpos; } draw_line_itemsize(state, xft_font->ascent, xft_font->descent, 0); if (obj_new_xftfont(state, state->linewidth, 0, out16, sizeof(out16) - oleft, fontname, registry, char_size[caching], charset16, xft_font)) { state->linewidth += extents.xOff; return p + len; } else #endif return NULL; } XftTextExtents8(display, xft_font, (XftChar8 *)p, len, &extents); /* line folding check */ if (state->width - state->leftfillpos / 2 - state->linewidth < extents.xOff) { if (isspace(*(p + len -1))) { XftTextExtents8(display, xft_font, (XftChar8 *)p, len -1, &extents); if (state->width - state->leftfillpos / 2 - state->linewidth >= extents.xOff) goto nofolding; } draw_line_end(state); draw_line_start(state); state->linewidth = state->leftfillpos; return p; } nofolding: #if 1 draw_line_itemsize(state, xft_font->ascent, xft_font->descent, 0); #else draw_line_itemsize(state, extents.y, extents.height - extents.y, 0); #endif if (obj_new_xftfont(state, state->linewidth, state->charoff, p, len, fontname, registry, char_size[caching], charset16, xft_font)) { state->linewidth += extents.xOff; return p + len; } else return NULL; } static int obj_new_xftfont(state, x, y, p, len, fontname, registry, size, charset16, xft_font) struct render_state *state; int x, y; char *p; int len; char *fontname; char *registry; int size; int charset16; XftFont *xft_font; { struct render_object *obj; char buf[65535], *p1; p1 = buf; bzero(buf, sizeof(buf)); if (sizeof(buf) > len) memcpy(buf, p, len); else return 0; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->fore = fore_color[caching]; obj->type = O_XTFONT; obj->data.xftfont.data = strdup(p1); obj->data.xftfont.fontname = strdup(fontname); obj->data.xftfont.registry = strdup(registry); obj->data.xftfont.len = len; obj->data.xftfont.size = size; obj->data.xftfont.charset16 = charset16; obj->ascent = xft_font->ascent; obj->descent = xft_font->descent; obj->vertloc = VL_BASE; return 1; } static XftDraw * xft_getdraw(Drawable drawable) { int i; for (i = 0; i < 2; i ++) { if (xft_xdraw[i] == drawable) return xft_draw[i]; } for (i = 0; i < 2; i ++) { if (!xft_xdraw[i]) xft_draw[i] = XftDrawCreate(display, drawable, visual, colormap); return xft_draw[i]; } return NULL; /* should not happen */ } static XftFont * xft_setfont(xfontarg, csize, registry) char *xfontarg; int csize; char *registry; { char *xfont; static XftFont *last_xftfont; static char lastfont[100]; static int lastsize = 0; XftFont *xftfont; char *p, *p2; char style[100]; char font[100]; int stlen; bzero(style, sizeof(style)); bzero(font, sizeof(font)); xfont = strdup(xfontarg); if (!xfont) return NULL; if (!strcmp(xfont, lastfont) && lastsize == csize) { free(xfont); return last_xftfont; } if ((p = strchr(xfont, ':')) != NULL) { /* * if xfont contsins ":", we believe this is a Xft font name * with the style expression. */ p2 = p + 1; /* allow to use ":style=" syntax */ if ((strstr(p2, "style=") != NULL) || (strstr(p2, "STYLE=") != NULL)) p2 += 6; *p = '\0'; strlcpy(font, xfont, sizeof(font)); strlcpy(style, p2, sizeof(style)); } else if ((p = strchr(xfont, '-')) != NULL) { /* * if xfont contains "-", we believe this is a conventional * xfont name and try to convert it for xft */ *p++ = 0; strlcpy(font, xfont, sizeof(font)); if (strncmp(p, "bold-i", 6) == 0) strlcpy(style, "Bold Italic", sizeof(style)); else if (strncmp(p, "bold-", 5) == 0) strlcpy(style, "Bold", sizeof(style)); else if ((p = strchr(p, '-')) != NULL && p[1] == 'i') strlcpy(style, "Italic", sizeof(style)); } else strlcpy(font, xfont, sizeof(font)); if (style[0]) { xftfont = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, font, XFT_ENCODING, XftTypeString, registry, XFT_STYLE, XftTypeString, style, XFT_PIXEL_SIZE, XftTypeDouble, (float)csize, 0); } else { xftfont = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, font, XFT_ENCODING, XftTypeString, registry, XFT_PIXEL_SIZE, XftTypeDouble, (float)csize, 0); } if (xftfont == 0) { free(xfont); return NULL; } if (style[0]) snprintf(lastfont, sizeof(lastfont), "%s:%s", font, style); else snprintf(lastfont, sizeof(lastfont), "%s", font); if (verbose) { fprintf(stderr, "using xftfont [%s] size: %d\n", lastfont, csize); } lastsize = csize; last_xftfont = xftfont; free(xfont); return last_xftfont; } #endif #ifdef USE_M17N obj_new_mtext(state, x, y, mt, from, to, drawframe, ascent, descent) struct render_state *state; int x, y; MText *mt; int from, to; MFrame *drawframe; int ascent, descent; { struct render_object *obj; obj = obj_alloc(state); if (obj == NULL) return 0; obj->x = x; obj->y = y; obj->fore = fore_color[caching]; /* we don't need this */ obj->type = O_M17NTEXT; obj->ascent = ascent; obj->descent = descent; obj->vertloc = VL_BASE; obj->data.m17ntext.mt = mt; m17n_object_ref (mt); obj->data.m17ntext.drawframe = drawframe; obj->data.m17ntext.from = from; obj->data.m17ntext.to = to; return 1; } #endif